1 /*
  2  * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved.
  3  * Copyright (c) 2020, 2021 SAP SE. All rights reserved.
  4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  5  *
  6  * This code is free software; you can redistribute it and/or modify it
  7  * under the terms of the GNU General Public License version 2 only, as
  8  * published by the Free Software Foundation.
  9  *
 10  * This code is distributed in the hope that it will be useful, but WITHOUT
 11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 13  * version 2 for more details (a copy is included in the LICENSE file that
 14  * accompanied this code).
 15  *
 16  * You should have received a copy of the GNU General Public License version
 17  * 2 along with this work; if not, write to the Free Software Foundation,
 18  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 19  *
 20  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 21  * or visit www.oracle.com if you need additional information or have any
 22  * questions.
 23  *
 24  */
 25 
 26 #include "precompiled.hpp"
 27 #include "memory/metaspace/chunkManager.hpp"
 28 #include "memory/metaspace/metaspaceArena.hpp"
 29 #include "memory/metaspace/metaspaceArenaGrowthPolicy.hpp"
 30 #include "memory/metaspace/metaspaceContext.hpp"
 31 #include "memory/metaspace/testHelpers.hpp"
 32 #include "runtime/mutexLocker.hpp"
 33 #include "runtime/os.hpp"
 34 #include "utilities/debug.hpp"
 35 #include "utilities/globalDefinitions.hpp"
 36 #include "utilities/ostream.hpp"
 37 
 38 namespace metaspace {
 39 
 40 ///// MetaspaceTestArena //////
 41 
 42 MetaspaceTestArena::MetaspaceTestArena(Mutex* lock, MetaspaceArena* arena) :
 43   _lock(lock),
 44   _arena(arena)
 45 {}
 46 
 47 MetaspaceTestArena::~MetaspaceTestArena() {
 48   {
 49     MutexLocker fcl(_lock, Mutex::_no_safepoint_check_flag);
 50     delete _arena;
 51   }
 52   delete _lock;
 53 }
 54 
 55 MetaWord* MetaspaceTestArena::allocate(size_t word_size) {
 56   MutexLocker fcl(_lock, Mutex::_no_safepoint_check_flag);
 57   MetaBlock result, wastage;
 58   result = _arena->allocate(word_size, wastage);
 59   if (wastage.is_nonempty()) {
 60     _arena->deallocate(wastage);
 61   }
 62   return result.base();
 63 }
 64 
 65 void MetaspaceTestArena::deallocate(MetaWord* p, size_t word_size) {
 66   MutexLocker fcl(_lock, Mutex::_no_safepoint_check_flag);
 67   _arena->deallocate(MetaBlock(p, word_size));
 68 }
 69 
 70 ///// MetaspaceTestArea //////
 71 
 72 MetaspaceTestContext::MetaspaceTestContext(const char* name, size_t commit_limit, size_t reserve_limit) :
 73   _name(name),
 74   _reserve_limit(reserve_limit),
 75   _commit_limit(commit_limit),
 76   _context(nullptr),
 77   _commit_limiter(commit_limit == 0 ? max_uintx : commit_limit), // commit_limit == 0 -> no limit
 78   _rs()
 79 {
 80   assert(is_aligned(reserve_limit, Metaspace::reserve_alignment_words()), "reserve_limit (" SIZE_FORMAT ") "
 81                     "not aligned to metaspace reserve alignment (" SIZE_FORMAT ")",
 82                     reserve_limit, Metaspace::reserve_alignment_words());
 83   if (reserve_limit > 0) {
 84     // have reserve limit -> non-expandable context
 85     _rs = ReservedSpace(reserve_limit * BytesPerWord, Metaspace::reserve_alignment(), os::vm_page_size());
 86     _context = MetaspaceContext::create_nonexpandable_context(name, _rs, &_commit_limiter);
 87   } else {
 88     // no reserve limit -> expandable vslist
 89     _context = MetaspaceContext::create_expandable_context(name, &_commit_limiter);
 90   }
 91 
 92 }
 93 
 94 MetaspaceTestContext::~MetaspaceTestContext() {
 95   DEBUG_ONLY(verify();)
 96   MutexLocker fcl(Metaspace_lock, Mutex::_no_safepoint_check_flag);
 97   delete _context;
 98   if (_rs.is_reserved()) {
 99     _rs.release();
100   }
101 }
102 
103 // Create an arena, feeding off this area.
104 MetaspaceTestArena* MetaspaceTestContext::create_arena(Metaspace::MetaspaceType type) {
105   const ArenaGrowthPolicy* growth_policy = ArenaGrowthPolicy::policy_for_space_type(type, false);
106   Mutex* lock = new Mutex(Monitor::nosafepoint, "MetaspaceTestArea_lock");
107   MetaspaceArena* arena = nullptr;
108   {
109     MutexLocker ml(lock,  Mutex::_no_safepoint_check_flag);
110     arena = new MetaspaceArena(_context, growth_policy, Metaspace::min_allocation_alignment_words, _name);
111   }
112   return new MetaspaceTestArena(lock, arena);
113 }
114 
115 void MetaspaceTestContext::purge_area() {
116   _context->cm()->purge();
117 }
118 
119 #ifdef ASSERT
120 void MetaspaceTestContext::verify() const {
121   if (_context != nullptr) {
122     _context->verify();
123   }
124 }
125 #endif
126 
127 void MetaspaceTestContext::print_on(outputStream* st) const {
128   _context->print_on(st);
129 }
130 
131 size_t MetaspaceTestContext::used_words() const {
132   return _context->used_words_counter()->get();
133 }
134 
135 size_t MetaspaceTestContext::committed_words() const {
136   assert(_commit_limiter.committed_words() == _context->committed_words(), "Sanity");
137   return _context->committed_words();
138 }
139 
140 size_t MetaspaceTestContext::reserved_words() const {
141   return _context->reserved_words();
142 }
143 
144 } // namespace metaspace
145