1 /*
2  * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved.
3  * Copyright (c) 2018, 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 "logging/log.hpp"
28 #include "memory/metaspace.hpp"
29 #include "memory/metaspace/chunkManager.hpp"
30 #include "memory/metaspace/commitLimiter.hpp"
31 #include "memory/metaspace/counters.hpp"
32 #include "memory/metaspace/freeChunkList.hpp"
33 #include "memory/metaspace/metaspaceContext.hpp"
34 #include "memory/metaspace/metaspaceCommon.hpp"
35 #include "memory/metaspace/virtualSpaceList.hpp"
36 #include "memory/metaspace/virtualSpaceNode.hpp"
37 #include "runtime/mutexLocker.hpp"
38 
39 namespace metaspace {
40 
41 #define LOGFMT         "VsList @" PTR_FORMAT " (%s)"
42 #define LOGFMT_ARGS    p2i(this), this->_name
43 
44 // Create a new, empty, expandable list.
VirtualSpaceList(const char * name,CommitLimiter * commit_limiter)45 VirtualSpaceList::VirtualSpaceList(const char* name, CommitLimiter* commit_limiter) :
46   _name(name),
47   _first_node(NULL),
48   _can_expand(true),
49   _commit_limiter(commit_limiter),
50   _reserved_words_counter(),
51   _committed_words_counter()
52 {
53 }
54 
55 // Create a new list. The list will contain one node only, which uses the given ReservedSpace.
56 // It will be not expandable beyond that first node.
VirtualSpaceList(const char * name,ReservedSpace rs,CommitLimiter * commit_limiter)57 VirtualSpaceList::VirtualSpaceList(const char* name, ReservedSpace rs, CommitLimiter* commit_limiter) :
58   _name(name),
59   _first_node(NULL),
60   _can_expand(false),
61   _commit_limiter(commit_limiter),
62   _reserved_words_counter(),
63   _committed_words_counter()
64 {
65   // Create the first node spanning the existing ReservedSpace. This will be the only node created
66   // for this list since we cannot expand.
67   VirtualSpaceNode* vsn = VirtualSpaceNode::create_node(rs, _commit_limiter,
68                                                         &_reserved_words_counter, &_committed_words_counter);
69   assert(vsn != NULL, "node creation failed");
70   _first_node = vsn;
71   _first_node->set_next(NULL);
72   _nodes_counter.increment();
73 }
74 
~VirtualSpaceList()75 VirtualSpaceList::~VirtualSpaceList() {
76   assert_lock_strong(Metaspace_lock);
77   // Note: normally, there is no reason ever to delete a vslist since they are
78   // global objects, but for gtests it makes sense to allow this.
79   VirtualSpaceNode* vsn = _first_node;
80   VirtualSpaceNode* vsn2 = vsn;
81   while (vsn != NULL) {
82     vsn2 = vsn->next();
83     delete vsn;
84     vsn = vsn2;
85   }
86 }
87 
88 // Create a new node and append it to the list. After
89 // this function, _current_node shall point to a new empty node.
90 // List must be expandable for this to work.
create_new_node()91 void VirtualSpaceList::create_new_node() {
92   assert(_can_expand, "List is not expandable");
93   assert_lock_strong(Metaspace_lock);
94 
95   VirtualSpaceNode* vsn = VirtualSpaceNode::create_node(Settings::virtual_space_node_default_word_size(),
96                                                         _commit_limiter,
97                                                         &_reserved_words_counter, &_committed_words_counter);
98   vsn->set_next(_first_node);
99   _first_node = vsn;
100   _nodes_counter.increment();
101 }
102 
103 // Allocate a root chunk from this list.
104 // Note: this just returns a chunk whose memory is reserved; no memory is committed yet.
105 // Hence, before using this chunk, it must be committed.
106 // Also, no limits are checked, since no committing takes place.
allocate_root_chunk()107 Metachunk*  VirtualSpaceList::allocate_root_chunk() {
108   assert_lock_strong(Metaspace_lock);
109 
110   if (_first_node == NULL ||
111       _first_node->free_words() < chunklevel::MAX_CHUNK_WORD_SIZE) {
112 
113 #ifdef ASSERT
114     // Since all allocations from a VirtualSpaceNode happen in
115     // root-chunk-size units, and the node size must be root-chunk-size aligned,
116     // we should never have left-over space.
117     if (_first_node != NULL) {
118       assert(_first_node->free_words() == 0, "Sanity");
119     }
120 #endif
121 
122     if (_can_expand) {
123       create_new_node();
124       UL2(debug, "added new node (now: %d).", num_nodes());
125     } else {
126       UL(debug, "list cannot expand.");
127       return NULL; // We cannot expand this list.
128     }
129   }
130 
131   Metachunk* c = _first_node->allocate_root_chunk();
132   assert(c != NULL, "This should have worked");
133 
134   return c;
135 }
136 
137 // Attempts to purge nodes. This will remove and delete nodes which only contain free chunks.
138 // The free chunks are removed from the freelists before the nodes are deleted.
139 // Return number of purged nodes.
purge(FreeChunkListVector * freelists)140 int VirtualSpaceList::purge(FreeChunkListVector* freelists) {
141   assert_lock_strong(Metaspace_lock);
142   UL(debug, "purging.");
143 
144   VirtualSpaceNode* vsn = _first_node;
145   VirtualSpaceNode* prev_vsn = NULL;
146   int num = 0, num_purged = 0;
147   while (vsn != NULL) {
148     VirtualSpaceNode* next_vsn = vsn->next();
149     bool purged = vsn->attempt_purge(freelists);
150     if (purged) {
151       // Note: from now on do not dereference vsn!
152       UL2(debug, "purged node @" PTR_FORMAT ".", p2i(vsn));
153       if (_first_node == vsn) {
154         _first_node = next_vsn;
155       }
156       DEBUG_ONLY(vsn = (VirtualSpaceNode*)((uintptr_t)(0xdeadbeef));)
157       if (prev_vsn != NULL) {
158         prev_vsn->set_next(next_vsn);
159       }
160       num_purged++;
161       _nodes_counter.decrement();
162     } else {
163       prev_vsn = vsn;
164     }
165     vsn = next_vsn;
166     num ++;
167   }
168 
169   UL2(debug, "purged %d nodes (before: %d, now: %d)",
170       num_purged, num, num_nodes());
171   return num_purged;
172 }
173 
174 // Print all nodes in this space list.
print_on(outputStream * st) const175 void VirtualSpaceList::print_on(outputStream* st) const {
176   MutexLocker fcl(Metaspace_lock, Mutex::_no_safepoint_check_flag);
177 
178   st->print_cr("vsl %s:", _name);
179   const VirtualSpaceNode* vsn = _first_node;
180   int n = 0;
181   while (vsn != NULL) {
182     st->print("- node #%d: ", n);
183     vsn->print_on(st);
184     vsn = vsn->next();
185     n++;
186   }
187   st->print_cr("- total %d nodes, " SIZE_FORMAT " reserved words, " SIZE_FORMAT " committed words.",
188                n, reserved_words(), committed_words());
189 }
190 
191 #ifdef ASSERT
verify_locked() const192 void VirtualSpaceList::verify_locked() const {
193   assert_lock_strong(Metaspace_lock);
194   assert(_name != NULL, "Sanity");
195 
196   int n = 0;
197 
198   if (_first_node != NULL) {
199     size_t total_reserved_words = 0;
200     size_t total_committed_words = 0;
201     const VirtualSpaceNode* vsn = _first_node;
202     while (vsn != NULL) {
203       n++;
204       vsn->verify_locked();
205       total_reserved_words += vsn->word_size();
206       total_committed_words += vsn->committed_words();
207       vsn = vsn->next();
208     }
209     _nodes_counter.check(n);
210     _reserved_words_counter.check(total_reserved_words);
211     _committed_words_counter.check(total_committed_words);
212   } else {
213     _reserved_words_counter.check(0);
214     _committed_words_counter.check(0);
215   }
216 }
217 
verify() const218 void VirtualSpaceList::verify() const {
219   MutexLocker fcl(Metaspace_lock, Mutex::_no_safepoint_check_flag);
220   verify_locked();
221 }
222 #endif
223 
224 // Returns true if this pointer is contained in one of our nodes.
contains(const MetaWord * p) const225 bool VirtualSpaceList::contains(const MetaWord* p) const {
226   const VirtualSpaceNode* vsn = _first_node;
227   while (vsn != NULL) {
228     if (vsn->contains(p)) {
229       return true;
230     }
231     vsn = vsn->next();
232   }
233   return false;
234 }
235 
236 // Returns true if the vslist is not expandable and no more root chunks
237 // can be allocated.
is_full() const238 bool VirtualSpaceList::is_full() const {
239   if (!_can_expand && _first_node != NULL && _first_node->free_words() == 0) {
240     return true;
241   }
242   return false;
243 }
244 
245 // Convenience methods to return the global class-space chunkmanager
246 //  and non-class chunkmanager, respectively.
vslist_class()247 VirtualSpaceList* VirtualSpaceList::vslist_class() {
248   return MetaspaceContext::context_class() == NULL ? NULL : MetaspaceContext::context_class()->vslist();
249 }
250 
vslist_nonclass()251 VirtualSpaceList* VirtualSpaceList::vslist_nonclass() {
252   return MetaspaceContext::context_nonclass() == NULL ? NULL : MetaspaceContext::context_nonclass()->vslist();
253 }
254 
255 } // namespace metaspace
256