| File: | jdk/src/hotspot/share/memory/metaspace/rootChunkArea.cpp |
| Warning: | line 202, column 22 Value stored to 'starting_level' during its initialization is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* |
| 2 | * Copyright (c) 2020, 2021, 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 "logging/log.hpp" |
| 28 | #include "memory/allocation.hpp" |
| 29 | #include "memory/metaspace/chunkHeaderPool.hpp" |
| 30 | #include "memory/metaspace/chunkManager.hpp" |
| 31 | #include "memory/metaspace/freeChunkList.hpp" |
| 32 | #include "memory/metaspace/metachunk.hpp" |
| 33 | #include "memory/metaspace/metaspaceCommon.hpp" |
| 34 | #include "memory/metaspace/rootChunkArea.hpp" |
| 35 | #include "runtime/mutexLocker.hpp" |
| 36 | #include "utilities/debug.hpp" |
| 37 | #include "utilities/globalDefinitions.hpp" |
| 38 | |
| 39 | namespace metaspace { |
| 40 | |
| 41 | RootChunkArea::RootChunkArea(const MetaWord* base) : |
| 42 | _base(base), |
| 43 | _first_chunk(NULL__null) |
| 44 | {} |
| 45 | |
| 46 | RootChunkArea::~RootChunkArea() { |
| 47 | // This is called when a VirtualSpaceNode is destructed (purged). |
| 48 | // All chunks should be free of course. In fact, there should only |
| 49 | // be one chunk, since all free chunks should have been merged. |
| 50 | if (_first_chunk != NULL__null) { |
| 51 | assert(_first_chunk->is_root_chunk() && _first_chunk->is_free(),do { if (!(_first_chunk->is_root_chunk() && _first_chunk ->is_free())) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/memory/metaspace/rootChunkArea.cpp" , 52, "assert(" "_first_chunk->is_root_chunk() && _first_chunk->is_free()" ") failed", "Cannot delete root chunk area if not all chunks are free." ); ::breakpoint(); } } while (0) |
| 52 | "Cannot delete root chunk area if not all chunks are free.")do { if (!(_first_chunk->is_root_chunk() && _first_chunk ->is_free())) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/memory/metaspace/rootChunkArea.cpp" , 52, "assert(" "_first_chunk->is_root_chunk() && _first_chunk->is_free()" ") failed", "Cannot delete root chunk area if not all chunks are free." ); ::breakpoint(); } } while (0); |
| 53 | ChunkHeaderPool::pool()->return_chunk_header(_first_chunk); |
| 54 | } |
| 55 | } |
| 56 | |
| 57 | // Initialize: allocate a root node and a root chunk header; return the |
| 58 | // root chunk header. It will be partly initialized. |
| 59 | // Note: this just allocates a memory-less header; memory itself is allocated inside VirtualSpaceNode. |
| 60 | Metachunk* RootChunkArea::alloc_root_chunk_header(VirtualSpaceNode* node) { |
| 61 | assert(_first_chunk == 0, "already have a root")do { if (!(_first_chunk == 0)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/memory/metaspace/rootChunkArea.cpp" , 61, "assert(" "_first_chunk == 0" ") failed", "already have a root" ); ::breakpoint(); } } while (0); |
| 62 | Metachunk* c = ChunkHeaderPool::pool()->allocate_chunk_header(); |
| 63 | c->initialize(node, const_cast<MetaWord*>(_base), chunklevel::ROOT_CHUNK_LEVEL); |
| 64 | _first_chunk = c; |
| 65 | return c; |
| 66 | } |
| 67 | |
| 68 | // Given a chunk c, split it recursively until you get a chunk of the given target_level. |
| 69 | // |
| 70 | // The resulting target chunk resides at the same address as the original chunk. |
| 71 | // The resulting splinters are added to freelists. |
| 72 | // |
| 73 | // Returns pointer to the result chunk; the splitted-off chunks are added as |
| 74 | // free chunks to the freelists. |
| 75 | void RootChunkArea::split(chunklevel_t target_level, Metachunk* c, FreeChunkListVector* freelists) { |
| 76 | // Splitting a chunk once works like this: |
| 77 | // |
| 78 | // For a given chunk we want to split: |
| 79 | // - increase the chunk level (which halves its size) |
| 80 | // - (but leave base address as it is since it will be the leader of the newly |
| 81 | // created chunk pair) |
| 82 | // - then create a new chunk header of the same level, set its memory range |
| 83 | // to cover the second half of the old chunk. |
| 84 | // - wire them up (prev_in_vs/next_in_vs) |
| 85 | // - return the follower chunk as "splinter chunk" in the splinters array. |
| 86 | |
| 87 | // Doing this multiple times will create a new free splinter chunk for every |
| 88 | // level we split: |
| 89 | // |
| 90 | // A <- original chunk |
| 91 | // |
| 92 | // B B <- split into two halves |
| 93 | // |
| 94 | // C C B <- first half split again |
| 95 | // |
| 96 | // D D C B <- first half split again ... |
| 97 | // |
| 98 | |
| 99 | DEBUG_ONLY(check_pointer(c->base());)check_pointer(c->base()); |
| 100 | DEBUG_ONLY(c->verify();)c->verify(); |
| 101 | assert(c->is_free(), "Can only split free chunks.")do { if (!(c->is_free())) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/memory/metaspace/rootChunkArea.cpp" , 101, "assert(" "c->is_free()" ") failed", "Can only split free chunks." ); ::breakpoint(); } } while (0); |
| 102 | |
| 103 | DEBUG_ONLY(chunklevel::check_valid_level(target_level))chunklevel::check_valid_level(target_level); |
| 104 | assert(target_level > c->level(), "Wrong target level")do { if (!(target_level > c->level())) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/memory/metaspace/rootChunkArea.cpp" , 104, "assert(" "target_level > c->level()" ") failed" , "Wrong target level"); ::breakpoint(); } } while (0); |
| 105 | |
| 106 | const chunklevel_t starting_level = c->level(); |
| 107 | |
| 108 | while (c->level() < target_level) { |
| 109 | |
| 110 | log_trace(metaspace)(!(LogImpl<(LogTag::_metaspace), (LogTag::__NO_TAG), (LogTag ::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag:: __NO_TAG)>::is_level(LogLevel::Trace))) ? (void)0 : LogImpl <(LogTag::_metaspace), (LogTag::__NO_TAG), (LogTag::__NO_TAG ), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG) >::write<LogLevel::Trace>("Splitting chunk: " METACHUNK_FULL_FORMAT"@" "0x%016" "l" "x" ", %c, base " "0x%016" "l" "x" ", level " "lv%.2d" " (" "%" "l" "u" "), used: " "%" "l" "u" ", committed: " "%" "l" "u" ", committed-free: " "%" "l" "u" ".", METACHUNK_FULL_FORMAT_ARGS(c)p2i(c), c->get_state_char(), p2i(c->base()), c->level (), c->word_size(), c->used_words(), c->committed_words (), c->free_below_committed_words()); |
| 111 | |
| 112 | c->inc_level(); |
| 113 | Metachunk* splinter_chunk = ChunkHeaderPool::pool()->allocate_chunk_header(); |
| 114 | splinter_chunk->initialize(c->vsnode(), c->end(), c->level()); |
| 115 | |
| 116 | // Fix committed words info: If over the half of the original chunk was |
| 117 | // committed, committed area spills over into the follower chunk. |
| 118 | const size_t old_committed_words = c->committed_words(); |
| 119 | if (old_committed_words > c->word_size()) { |
| 120 | c->set_committed_words(c->word_size()); |
| 121 | splinter_chunk->set_committed_words(old_committed_words - c->word_size()); |
| 122 | } else { |
| 123 | splinter_chunk->set_committed_words(0); |
| 124 | } |
| 125 | |
| 126 | // Insert splinter chunk into vs list |
| 127 | if (c->next_in_vs() != NULL__null) { |
| 128 | c->next_in_vs()->set_prev_in_vs(splinter_chunk); |
| 129 | } |
| 130 | splinter_chunk->set_next_in_vs(c->next_in_vs()); |
| 131 | splinter_chunk->set_prev_in_vs(c); |
| 132 | c->set_next_in_vs(splinter_chunk); |
| 133 | |
| 134 | log_trace(metaspace)(!(LogImpl<(LogTag::_metaspace), (LogTag::__NO_TAG), (LogTag ::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag:: __NO_TAG)>::is_level(LogLevel::Trace))) ? (void)0 : LogImpl <(LogTag::_metaspace), (LogTag::__NO_TAG), (LogTag::__NO_TAG ), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG) >::write<LogLevel::Trace>(".. Result chunk: " METACHUNK_FULL_FORMAT"@" "0x%016" "l" "x" ", %c, base " "0x%016" "l" "x" ", level " "lv%.2d" " (" "%" "l" "u" "), used: " "%" "l" "u" ", committed: " "%" "l" "u" ", committed-free: " "%" "l" "u" ".", METACHUNK_FULL_FORMAT_ARGS(c)p2i(c), c->get_state_char(), p2i(c->base()), c->level (), c->word_size(), c->used_words(), c->committed_words (), c->free_below_committed_words()); |
| 135 | log_trace(metaspace)(!(LogImpl<(LogTag::_metaspace), (LogTag::__NO_TAG), (LogTag ::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag:: __NO_TAG)>::is_level(LogLevel::Trace))) ? (void)0 : LogImpl <(LogTag::_metaspace), (LogTag::__NO_TAG), (LogTag::__NO_TAG ), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG) >::write<LogLevel::Trace>(".. Splinter chunk: " METACHUNK_FULL_FORMAT"@" "0x%016" "l" "x" ", %c, base " "0x%016" "l" "x" ", level " "lv%.2d" " (" "%" "l" "u" "), used: " "%" "l" "u" ", committed: " "%" "l" "u" ", committed-free: " "%" "l" "u" ".", METACHUNK_FULL_FORMAT_ARGS(splinter_chunk)p2i(splinter_chunk), splinter_chunk->get_state_char(), p2i (splinter_chunk->base()), splinter_chunk->level(), splinter_chunk ->word_size(), splinter_chunk->used_words(), splinter_chunk ->committed_words(), splinter_chunk->free_below_committed_words ()); |
| 136 | |
| 137 | // Add splinter to free lists |
| 138 | freelists->add(splinter_chunk); |
| 139 | } |
| 140 | |
| 141 | assert(c->level() == target_level, "Sanity")do { if (!(c->level() == target_level)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/memory/metaspace/rootChunkArea.cpp" , 141, "assert(" "c->level() == target_level" ") failed", "Sanity" ); ::breakpoint(); } } while (0); |
| 142 | |
| 143 | DEBUG_ONLY(verify();)verify(); |
| 144 | DEBUG_ONLY(c->verify();)c->verify(); |
| 145 | } |
| 146 | |
| 147 | // Given a chunk, attempt to merge it recursively with its neighboring chunks. |
| 148 | // |
| 149 | // If successful (merged at least once), returns address of |
| 150 | // the merged chunk; NULL otherwise. |
| 151 | // |
| 152 | // The merged chunks are removed from the freelists. |
| 153 | // |
| 154 | // !!! Please note that if this method returns a non-NULL value, the |
| 155 | // original chunk will be invalid and should not be accessed anymore! !!! |
| 156 | Metachunk* RootChunkArea::merge(Metachunk* c, FreeChunkListVector* freelists) { |
| 157 | // Note rules: |
| 158 | // |
| 159 | // - a chunk always has a buddy, unless it is a root chunk. |
| 160 | // - In that buddy pair, a chunk is either leader or follower. |
| 161 | // - a chunk's base address is always aligned at its size. |
| 162 | // - if chunk is leader, its base address is also aligned to the size of the next |
| 163 | // lower level, at least. A follower chunk is not. |
| 164 | |
| 165 | // How we merge once: |
| 166 | // |
| 167 | // For a given chunk c, which has to be free and non-root, we do: |
| 168 | // - find out if we are the leader or the follower chunk |
| 169 | // - if we are leader, next_in_vs must be the follower; if we are follower, |
| 170 | // prev_in_vs must be the leader. Now we have the buddy chunk. |
| 171 | // - However, if the buddy chunk itself is split (of a level higher than us) |
| 172 | // we cannot merge. |
| 173 | // - we can only merge if the buddy is of the same level as we are and it is |
| 174 | // free. |
| 175 | // - Then we merge by simply removing the follower chunk from the address range |
| 176 | // linked list (returning the now useless header to the pool) and decreasing |
| 177 | // the leader chunk level by one. That makes it double the size. |
| 178 | |
| 179 | // Example: |
| 180 | // (lower case chunks are free, the * indicates the chunk we want to merge): |
| 181 | // |
| 182 | // ........................ |
| 183 | // d d*c b A <- we return the second (d*) chunk... |
| 184 | // |
| 185 | // c* c b A <- we merge it with its predecessor and decrease its level... |
| 186 | // |
| 187 | // b* b A <- we merge it again, since its new neighbor was free too... |
| 188 | // |
| 189 | // a* A <- we merge it again, since its new neighbor was free too... |
| 190 | // |
| 191 | // And we are done, since its new neighbor, (A), is not free. We would also be done |
| 192 | // if the new neighbor itself is splintered. |
| 193 | |
| 194 | DEBUG_ONLY(check_pointer(c->base());)check_pointer(c->base()); |
| 195 | assert(!c->is_root_chunk(), "Cannot be merged further.")do { if (!(!c->is_root_chunk())) { (*g_assert_poison) = 'X' ;; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/memory/metaspace/rootChunkArea.cpp" , 195, "assert(" "!c->is_root_chunk()" ") failed", "Cannot be merged further." ); ::breakpoint(); } } while (0); |
| 196 | assert(c->is_free(), "Can only merge free chunks.")do { if (!(c->is_free())) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/memory/metaspace/rootChunkArea.cpp" , 196, "assert(" "c->is_free()" ") failed", "Can only merge free chunks." ); ::breakpoint(); } } while (0); |
| 197 | |
| 198 | DEBUG_ONLY(c->verify();)c->verify(); |
| 199 | |
| 200 | log_trace(metaspace)(!(LogImpl<(LogTag::_metaspace), (LogTag::__NO_TAG), (LogTag ::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag:: __NO_TAG)>::is_level(LogLevel::Trace))) ? (void)0 : LogImpl <(LogTag::_metaspace), (LogTag::__NO_TAG), (LogTag::__NO_TAG ), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG) >::write<LogLevel::Trace>("Attempting to merge chunk " METACHUNK_FORMAT"@" "0x%016" "l" "x" ", %c, base " "0x%016" "l" "x" ", level " "lv%.2d" ".", METACHUNK_FORMAT_ARGS(c)p2i(c), c->get_state_char(), p2i(c->base()), c->level ()); |
| 201 | |
| 202 | const chunklevel_t starting_level = c->level(); |
Value stored to 'starting_level' during its initialization is never read | |
| 203 | |
| 204 | bool stop = false; |
| 205 | Metachunk* result = NULL__null; |
| 206 | |
| 207 | do { |
| 208 | |
| 209 | // First find out if this chunk is the leader of its pair |
| 210 | const bool is_leader = c->is_leader(); |
| 211 | |
| 212 | // Note: this is either our buddy or a splinter of the buddy. |
| 213 | Metachunk* const buddy = c->is_leader() ? c->next_in_vs() : c->prev_in_vs(); |
| 214 | DEBUG_ONLY(buddy->verify();)buddy->verify(); |
| 215 | |
| 216 | // A buddy chunk must be of the same or higher level (so, same size or smaller) |
| 217 | // never be larger. |
| 218 | assert(buddy->level() >= c->level(), "Sanity")do { if (!(buddy->level() >= c->level())) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/memory/metaspace/rootChunkArea.cpp" , 218, "assert(" "buddy->level() >= c->level()" ") failed" , "Sanity"); ::breakpoint(); } } while (0); |
| 219 | |
| 220 | // Is this really my buddy (same level) or a splinter of it (higher level)? |
| 221 | // Also, is it free? |
| 222 | if (buddy->level() != c->level() || buddy->is_free() == false) { |
| 223 | log_trace(metaspace)(!(LogImpl<(LogTag::_metaspace), (LogTag::__NO_TAG), (LogTag ::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag:: __NO_TAG)>::is_level(LogLevel::Trace))) ? (void)0 : LogImpl <(LogTag::_metaspace), (LogTag::__NO_TAG), (LogTag::__NO_TAG ), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG) >::write<LogLevel::Trace>("cannot merge with chunk " METACHUNK_FORMAT"@" "0x%016" "l" "x" ", %c, base " "0x%016" "l" "x" ", level " "lv%.2d" ".", METACHUNK_FORMAT_ARGS(buddy)p2i(buddy), buddy->get_state_char(), p2i(buddy->base()) , buddy->level()); |
| 224 | stop = true; |
| 225 | } else { |
| 226 | log_trace(metaspace)(!(LogImpl<(LogTag::_metaspace), (LogTag::__NO_TAG), (LogTag ::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag:: __NO_TAG)>::is_level(LogLevel::Trace))) ? (void)0 : LogImpl <(LogTag::_metaspace), (LogTag::__NO_TAG), (LogTag::__NO_TAG ), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG) >::write<LogLevel::Trace>("will merge with chunk " METACHUNK_FORMAT"@" "0x%016" "l" "x" ", %c, base " "0x%016" "l" "x" ", level " "lv%.2d" ".", METACHUNK_FORMAT_ARGS(buddy)p2i(buddy), buddy->get_state_char(), p2i(buddy->base()) , buddy->level()); |
| 227 | |
| 228 | // We can merge with the buddy. |
| 229 | // First, remove buddy from the chunk manager. |
| 230 | assert(buddy->is_free(), "Sanity")do { if (!(buddy->is_free())) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/memory/metaspace/rootChunkArea.cpp" , 230, "assert(" "buddy->is_free()" ") failed", "Sanity"); ::breakpoint(); } } while (0); |
| 231 | freelists->remove(buddy); |
| 232 | |
| 233 | // Determine current leader and follower |
| 234 | Metachunk* leader; |
| 235 | Metachunk* follower; |
| 236 | if (is_leader) { |
| 237 | leader = c; follower = buddy; |
| 238 | } else { |
| 239 | leader = buddy; follower = c; |
| 240 | } |
| 241 | |
| 242 | // Last checkpoint |
| 243 | assert(leader->end() == follower->base() &&do { if (!(leader->end() == follower->base() && leader->level() == follower->level() && leader ->is_free() && follower->is_free())) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/memory/metaspace/rootChunkArea.cpp" , 245, "assert(" "leader->end() == follower->base() && leader->level() == follower->level() && leader->is_free() && follower->is_free()" ") failed", "Sanity"); ::breakpoint(); } } while (0) |
| 244 | leader->level() == follower->level() &&do { if (!(leader->end() == follower->base() && leader->level() == follower->level() && leader ->is_free() && follower->is_free())) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/memory/metaspace/rootChunkArea.cpp" , 245, "assert(" "leader->end() == follower->base() && leader->level() == follower->level() && leader->is_free() && follower->is_free()" ") failed", "Sanity"); ::breakpoint(); } } while (0) |
| 245 | leader->is_free() && follower->is_free(), "Sanity")do { if (!(leader->end() == follower->base() && leader->level() == follower->level() && leader ->is_free() && follower->is_free())) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/memory/metaspace/rootChunkArea.cpp" , 245, "assert(" "leader->end() == follower->base() && leader->level() == follower->level() && leader->is_free() && follower->is_free()" ") failed", "Sanity"); ::breakpoint(); } } while (0); |
| 246 | |
| 247 | // The new merged chunk is as far committed as possible (if leader |
| 248 | // chunk is fully committed, as far as the follower chunk). |
| 249 | size_t merged_committed_words = leader->committed_words(); |
| 250 | if (merged_committed_words == leader->word_size()) { |
| 251 | merged_committed_words += follower->committed_words(); |
| 252 | } |
| 253 | |
| 254 | // Leader survives, follower chunk is freed. Remove follower from vslist .. |
| 255 | leader->set_next_in_vs(follower->next_in_vs()); |
| 256 | if (follower->next_in_vs() != NULL__null) { |
| 257 | follower->next_in_vs()->set_prev_in_vs(leader); |
| 258 | } |
| 259 | |
| 260 | // .. and return follower chunk header to pool for reuse. |
| 261 | ChunkHeaderPool::pool()->return_chunk_header(follower); |
| 262 | |
| 263 | // Leader level gets decreased (leader chunk doubles in size) but |
| 264 | // base address stays the same. |
| 265 | leader->dec_level(); |
| 266 | |
| 267 | // set commit boundary |
| 268 | leader->set_committed_words(merged_committed_words); |
| 269 | |
| 270 | // If the leader is now of root chunk size, stop merging |
| 271 | if (leader->is_root_chunk()) { |
| 272 | stop = true; |
| 273 | } |
| 274 | |
| 275 | result = c = leader; |
| 276 | DEBUG_ONLY(leader->verify();)leader->verify(); |
| 277 | } |
| 278 | } while (!stop); |
| 279 | |
| 280 | #ifdef ASSERT1 |
| 281 | verify(); |
| 282 | if (result != NULL__null) { |
| 283 | result->verify(); |
| 284 | } |
| 285 | #endif // ASSERT |
| 286 | return result; |
| 287 | } |
| 288 | |
| 289 | // Given a chunk c, which must be "in use" and must not be a root chunk, attempt to |
| 290 | // enlarge it in place by claiming its trailing buddy. |
| 291 | // |
| 292 | // This will only work if c is the leader of the buddy pair and the trailing buddy is free. |
| 293 | // |
| 294 | // If successful, the follower chunk will be removed from the freelists, the leader chunk c will |
| 295 | // double in size (level decreased by one). |
| 296 | // |
| 297 | // On success, true is returned, false otherwise. |
| 298 | bool RootChunkArea::attempt_enlarge_chunk(Metachunk* c, FreeChunkListVector* freelists) { |
| 299 | DEBUG_ONLY(check_pointer(c->base());)check_pointer(c->base()); |
| 300 | assert(!c->is_root_chunk(), "Cannot be merged further.")do { if (!(!c->is_root_chunk())) { (*g_assert_poison) = 'X' ;; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/memory/metaspace/rootChunkArea.cpp" , 300, "assert(" "!c->is_root_chunk()" ") failed", "Cannot be merged further." ); ::breakpoint(); } } while (0); |
| 301 | |
| 302 | // There is no real reason for this limitation other than it is not |
| 303 | // needed on free chunks since they should be merged already: |
| 304 | assert(c->is_in_use(), "Can only enlarge in use chunks.")do { if (!(c->is_in_use())) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/memory/metaspace/rootChunkArea.cpp" , 304, "assert(" "c->is_in_use()" ") failed", "Can only enlarge in use chunks." ); ::breakpoint(); } } while (0); |
| 305 | DEBUG_ONLY(c->verify();)c->verify(); |
| 306 | |
| 307 | if (!c->is_leader()) { |
| 308 | return false; |
| 309 | } |
| 310 | |
| 311 | // We are the leader, so the buddy must follow us. |
| 312 | Metachunk* const buddy = c->next_in_vs(); |
| 313 | DEBUG_ONLY(buddy->verify();)buddy->verify(); |
| 314 | |
| 315 | // Of course buddy cannot be larger than us. |
| 316 | assert(buddy->level() >= c->level(), "Sanity")do { if (!(buddy->level() >= c->level())) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/memory/metaspace/rootChunkArea.cpp" , 316, "assert(" "buddy->level() >= c->level()" ") failed" , "Sanity"); ::breakpoint(); } } while (0); |
| 317 | |
| 318 | // We cannot merge buddy in if it is not free... |
| 319 | if (!buddy->is_free()) { |
| 320 | return false; |
| 321 | } |
| 322 | // ... nor if it is splintered. |
| 323 | if (buddy->level() != c->level()) { |
| 324 | return false; |
| 325 | } |
| 326 | |
| 327 | // Okay, lets enlarge c. |
| 328 | log_trace(metaspace)(!(LogImpl<(LogTag::_metaspace), (LogTag::__NO_TAG), (LogTag ::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag:: __NO_TAG)>::is_level(LogLevel::Trace))) ? (void)0 : LogImpl <(LogTag::_metaspace), (LogTag::__NO_TAG), (LogTag::__NO_TAG ), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG) >::write<LogLevel::Trace>("Enlarging chunk " METACHUNK_FULL_FORMAT"@" "0x%016" "l" "x" ", %c, base " "0x%016" "l" "x" ", level " "lv%.2d" " (" "%" "l" "u" "), used: " "%" "l" "u" ", committed: " "%" "l" "u" ", committed-free: " "%" "l" "u" " by merging in follower " METACHUNK_FULL_FORMAT"@" "0x%016" "l" "x" ", %c, base " "0x%016" "l" "x" ", level " "lv%.2d" " (" "%" "l" "u" "), used: " "%" "l" "u" ", committed: " "%" "l" "u" ", committed-free: " "%" "l" "u" ".", |
| 329 | METACHUNK_FULL_FORMAT_ARGS(c)p2i(c), c->get_state_char(), p2i(c->base()), c->level (), c->word_size(), c->used_words(), c->committed_words (), c->free_below_committed_words(), METACHUNK_FULL_FORMAT_ARGS(buddy)p2i(buddy), buddy->get_state_char(), p2i(buddy->base()) , buddy->level(), buddy->word_size(), buddy->used_words (), buddy->committed_words(), buddy->free_below_committed_words ()); |
| 330 | |
| 331 | // the enlarged c is as far committed as possible: |
| 332 | size_t merged_committed_words = c->committed_words(); |
| 333 | if (merged_committed_words == c->word_size()) { |
| 334 | merged_committed_words += buddy->committed_words(); |
| 335 | } |
| 336 | |
| 337 | // Remove buddy from vs list... |
| 338 | Metachunk* successor = buddy->next_in_vs(); |
| 339 | if (successor != NULL__null) { |
| 340 | successor->set_prev_in_vs(c); |
| 341 | } |
| 342 | c->set_next_in_vs(successor); |
| 343 | |
| 344 | // .. and from freelist ... |
| 345 | freelists->remove(buddy); |
| 346 | |
| 347 | // .. and return its empty husk to the pool... |
| 348 | ChunkHeaderPool::pool()->return_chunk_header(buddy); |
| 349 | |
| 350 | // Then decrease level of c. |
| 351 | c->dec_level(); |
| 352 | |
| 353 | // and correct committed words if needed. |
| 354 | c->set_committed_words(merged_committed_words); |
| 355 | |
| 356 | log_debug(metaspace)(!(LogImpl<(LogTag::_metaspace), (LogTag::__NO_TAG), (LogTag ::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag:: __NO_TAG)>::is_level(LogLevel::Debug))) ? (void)0 : LogImpl <(LogTag::_metaspace), (LogTag::__NO_TAG), (LogTag::__NO_TAG ), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG) >::write<LogLevel::Debug>("Enlarged chunk " METACHUNK_FULL_FORMAT"@" "0x%016" "l" "x" ", %c, base " "0x%016" "l" "x" ", level " "lv%.2d" " (" "%" "l" "u" "), used: " "%" "l" "u" ", committed: " "%" "l" "u" ", committed-free: " "%" "l" "u" ".", METACHUNK_FULL_FORMAT_ARGS(c)p2i(c), c->get_state_char(), p2i(c->base()), c->level (), c->word_size(), c->used_words(), c->committed_words (), c->free_below_committed_words()); |
| 357 | |
| 358 | DEBUG_ONLY(verify())verify(); |
| 359 | return true; |
| 360 | } |
| 361 | |
| 362 | // Returns true if this root chunk area is completely free: |
| 363 | // In that case, it should only contain one chunk (maximally merged, so a root chunk) |
| 364 | // and it should be free. |
| 365 | bool RootChunkArea::is_free() const { |
| 366 | return _first_chunk == NULL__null || |
| 367 | (_first_chunk->is_root_chunk() && _first_chunk->is_free()); |
| 368 | } |
| 369 | |
| 370 | #ifdef ASSERT1 |
| 371 | |
| 372 | #define assrt_(cond, ...)if (!(cond)) { fdStream errst(2); this->print_on(&errst ); do { if (!(cond)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/memory/metaspace/rootChunkArea.cpp" , 372, "assert(" "cond" ") failed", ...); ::breakpoint(); } } while (0); } \ |
| 373 | if (!(cond)) { \ |
| 374 | fdStream errst(2); \ |
| 375 | this->print_on(&errst); \ |
| 376 | vmassert(cond, __VA_ARGS__)do { if (!(cond)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/memory/metaspace/rootChunkArea.cpp" , 376, "assert(" "cond" ") failed", __VA_ARGS__); ::breakpoint (); } } while (0); \ |
| 377 | } |
| 378 | |
| 379 | void RootChunkArea::verify() const { |
| 380 | assert_lock_strong(Metaspace_lock); |
| 381 | assert_is_aligned(_base, chunklevel::MAX_CHUNK_BYTE_SIZE)do { if (!(is_aligned((_base), (chunklevel::MAX_CHUNK_BYTE_SIZE )))) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/memory/metaspace/rootChunkArea.cpp" , 381, "assert(" "is_aligned((_base), (chunklevel::MAX_CHUNK_BYTE_SIZE))" ") failed", "0x%" "l" "x" " is not aligned to " "0x%" "l" "x" , (size_t)(uintptr_t)_base, (size_t)(chunklevel::MAX_CHUNK_BYTE_SIZE )); ::breakpoint(); } } while (0); |
| 382 | |
| 383 | // Iterate thru all chunks in this area. They must be ordered correctly, |
| 384 | // being adjacent to each other, and cover the complete area |
| 385 | int num_chunk = 0; |
| 386 | |
| 387 | if (_first_chunk != NULL__null) { |
| 388 | assrt_(_first_chunk->prev_in_vs() == NULL, "Sanity")if (!(_first_chunk->prev_in_vs() == __null)) { fdStream errst (2); this->print_on(&errst); do { if (!(_first_chunk-> prev_in_vs() == __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/memory/metaspace/rootChunkArea.cpp" , 388, "assert(" "_first_chunk->prev_in_vs() == __null" ") failed" , "Sanity"); ::breakpoint(); } } while (0); }; |
| 389 | |
| 390 | const Metachunk* c = _first_chunk; |
| 391 | const MetaWord* expected_next_base = _base; |
| 392 | const MetaWord* const area_end = _base + word_size(); |
| 393 | |
| 394 | while (c != NULL__null) { |
| 395 | assrt_(c->is_free() || c->is_in_use(),if (!(c->is_free() || c->is_in_use())) { fdStream errst (2); this->print_on(&errst); do { if (!(c->is_free( ) || c->is_in_use())) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/memory/metaspace/rootChunkArea.cpp" , 397, "assert(" "c->is_free() || c->is_in_use()" ") failed" , "Chunk No. %d " "@" "0x%016" "l" "x" ", %c, base " "0x%016" "l" "x" ", level " "lv%.2d" " - invalid state.", num_chunk, p2i (c), c->get_state_char(), p2i(c->base()), c->level() ); ::breakpoint(); } } while (0); } |
| 396 | "Chunk No. %d " METACHUNK_FORMAT " - invalid state.",if (!(c->is_free() || c->is_in_use())) { fdStream errst (2); this->print_on(&errst); do { if (!(c->is_free( ) || c->is_in_use())) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/memory/metaspace/rootChunkArea.cpp" , 397, "assert(" "c->is_free() || c->is_in_use()" ") failed" , "Chunk No. %d " "@" "0x%016" "l" "x" ", %c, base " "0x%016" "l" "x" ", level " "lv%.2d" " - invalid state.", num_chunk, p2i (c), c->get_state_char(), p2i(c->base()), c->level() ); ::breakpoint(); } } while (0); } |
| 397 | num_chunk, METACHUNK_FORMAT_ARGS(c))if (!(c->is_free() || c->is_in_use())) { fdStream errst (2); this->print_on(&errst); do { if (!(c->is_free( ) || c->is_in_use())) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/memory/metaspace/rootChunkArea.cpp" , 397, "assert(" "c->is_free() || c->is_in_use()" ") failed" , "Chunk No. %d " "@" "0x%016" "l" "x" ", %c, base " "0x%016" "l" "x" ", level " "lv%.2d" " - invalid state.", num_chunk, p2i (c), c->get_state_char(), p2i(c->base()), c->level() ); ::breakpoint(); } } while (0); }; |
| 398 | assrt_(c->base() == expected_next_base,if (!(c->base() == expected_next_base)) { fdStream errst(2 ); this->print_on(&errst); do { if (!(c->base() == expected_next_base )) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/memory/metaspace/rootChunkArea.cpp" , 400, "assert(" "c->base() == expected_next_base" ") failed" , "Chunk No. %d " "@" "0x%016" "l" "x" ", %c, base " "0x%016" "l" "x" ", level " "lv%.2d" " - unexpected base.", num_chunk , p2i(c), c->get_state_char(), p2i(c->base()), c->level ()); ::breakpoint(); } } while (0); } |
| 399 | "Chunk No. %d " METACHUNK_FORMAT " - unexpected base.",if (!(c->base() == expected_next_base)) { fdStream errst(2 ); this->print_on(&errst); do { if (!(c->base() == expected_next_base )) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/memory/metaspace/rootChunkArea.cpp" , 400, "assert(" "c->base() == expected_next_base" ") failed" , "Chunk No. %d " "@" "0x%016" "l" "x" ", %c, base " "0x%016" "l" "x" ", level " "lv%.2d" " - unexpected base.", num_chunk , p2i(c), c->get_state_char(), p2i(c->base()), c->level ()); ::breakpoint(); } } while (0); } |
| 400 | num_chunk, METACHUNK_FORMAT_ARGS(c))if (!(c->base() == expected_next_base)) { fdStream errst(2 ); this->print_on(&errst); do { if (!(c->base() == expected_next_base )) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/memory/metaspace/rootChunkArea.cpp" , 400, "assert(" "c->base() == expected_next_base" ") failed" , "Chunk No. %d " "@" "0x%016" "l" "x" ", %c, base " "0x%016" "l" "x" ", level " "lv%.2d" " - unexpected base.", num_chunk , p2i(c), c->get_state_char(), p2i(c->base()), c->level ()); ::breakpoint(); } } while (0); }; |
| 401 | assrt_(c->base() >= base() && c->end() <= end(),if (!(c->base() >= base() && c->end() <= end ())) { fdStream errst(2); this->print_on(&errst); do { if (!(c->base() >= base() && c->end() <= end())) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/memory/metaspace/rootChunkArea.cpp" , 403, "assert(" "c->base() >= base() && c->end() <= end()" ") failed", "chunk %d " "@" "0x%016" "l" "x" ", %c, base " "0x%016" "l" "x" ", level " "lv%.2d" " oob for this root area [" "0x%016" "l" "x" ".." "0x%016" "l" "x" ").", num_chunk, p2i(c), c-> get_state_char(), p2i(c->base()), c->level(), p2i(base( )), p2i(end())); ::breakpoint(); } } while (0); } |
| 402 | "chunk %d " METACHUNK_FORMAT " oob for this root area [" PTR_FORMAT ".." PTR_FORMAT ").",if (!(c->base() >= base() && c->end() <= end ())) { fdStream errst(2); this->print_on(&errst); do { if (!(c->base() >= base() && c->end() <= end())) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/memory/metaspace/rootChunkArea.cpp" , 403, "assert(" "c->base() >= base() && c->end() <= end()" ") failed", "chunk %d " "@" "0x%016" "l" "x" ", %c, base " "0x%016" "l" "x" ", level " "lv%.2d" " oob for this root area [" "0x%016" "l" "x" ".." "0x%016" "l" "x" ").", num_chunk, p2i(c), c-> get_state_char(), p2i(c->base()), c->level(), p2i(base( )), p2i(end())); ::breakpoint(); } } while (0); } |
| 403 | num_chunk, METACHUNK_FORMAT_ARGS(c), p2i(base()), p2i(end()))if (!(c->base() >= base() && c->end() <= end ())) { fdStream errst(2); this->print_on(&errst); do { if (!(c->base() >= base() && c->end() <= end())) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/memory/metaspace/rootChunkArea.cpp" , 403, "assert(" "c->base() >= base() && c->end() <= end()" ") failed", "chunk %d " "@" "0x%016" "l" "x" ", %c, base " "0x%016" "l" "x" ", level " "lv%.2d" " oob for this root area [" "0x%016" "l" "x" ".." "0x%016" "l" "x" ").", num_chunk, p2i(c), c-> get_state_char(), p2i(c->base()), c->level(), p2i(base( )), p2i(end())); ::breakpoint(); } } while (0); }; |
| 404 | assrt_(is_aligned(c->base(), c->word_size()),if (!(is_aligned(c->base(), c->word_size()))) { fdStream errst(2); this->print_on(&errst); do { if (!(is_aligned (c->base(), c->word_size()))) { (*g_assert_poison) = 'X' ;; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/memory/metaspace/rootChunkArea.cpp" , 405, "assert(" "is_aligned(c->base(), c->word_size())" ") failed", "misaligned chunk %d " "@" "0x%016" "l" "x" ", %c, base " "0x%016" "l" "x" ", level " "lv%.2d" ".", num_chunk, p2i(c), c->get_state_char(), p2i(c->base()), c->level()); :: breakpoint(); } } while (0); } |
| 405 | "misaligned chunk %d " METACHUNK_FORMAT ".", num_chunk, METACHUNK_FORMAT_ARGS(c))if (!(is_aligned(c->base(), c->word_size()))) { fdStream errst(2); this->print_on(&errst); do { if (!(is_aligned (c->base(), c->word_size()))) { (*g_assert_poison) = 'X' ;; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/memory/metaspace/rootChunkArea.cpp" , 405, "assert(" "is_aligned(c->base(), c->word_size())" ") failed", "misaligned chunk %d " "@" "0x%016" "l" "x" ", %c, base " "0x%016" "l" "x" ", level " "lv%.2d" ".", num_chunk, p2i(c), c->get_state_char(), p2i(c->base()), c->level()); :: breakpoint(); } } while (0); }; |
| 406 | |
| 407 | c->verify_neighborhood(); |
| 408 | c->verify(); |
| 409 | expected_next_base = c->end(); |
| 410 | num_chunk++; |
| 411 | c = c->next_in_vs(); |
| 412 | } |
| 413 | assrt_(expected_next_base == _base + word_size(), "Sanity")if (!(expected_next_base == _base + word_size())) { fdStream errst (2); this->print_on(&errst); do { if (!(expected_next_base == _base + word_size())) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/memory/metaspace/rootChunkArea.cpp" , 413, "assert(" "expected_next_base == _base + word_size()" ") failed" , "Sanity"); ::breakpoint(); } } while (0); }; |
| 414 | } |
| 415 | } |
| 416 | |
| 417 | void RootChunkArea::verify_area_is_ideally_merged() const { |
| 418 | SOMETIMES(assert_lock_strong(Metaspace_lock);){ static int counter_ = 0; if (VerifyMetaspaceInterval > 0 ) { counter_++; if (counter_ >= VerifyMetaspaceInterval) { counter_ = 0; { assert_lock_strong(Metaspace_lock); } } } } |
| 419 | int num_chunk = 0; |
| 420 | for (const Metachunk* c = _first_chunk; c != NULL__null; c = c->next_in_vs()) { |
| 421 | if (!c->is_root_chunk() && c->is_free()) { |
| 422 | // If a chunk is free, it must not have a buddy which is also free, because |
| 423 | // those chunks should have been merged. |
| 424 | // In other words, a buddy shall be either in-use or splintered |
| 425 | // (which in turn would mean part of it are in use). |
| 426 | Metachunk* const buddy = c->is_leader() ? c->next_in_vs() : c->prev_in_vs(); |
| 427 | assrt_(buddy->is_in_use() || buddy->level() > c->level(),if (!(buddy->is_in_use() || buddy->level() > c->level ())) { fdStream errst(2); this->print_on(&errst); do { if (!(buddy->is_in_use() || buddy->level() > c-> level())) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/memory/metaspace/rootChunkArea.cpp" , 429, "assert(" "buddy->is_in_use() || buddy->level() > c->level()" ") failed", "Chunk No. %d " "@" "0x%016" "l" "x" ", %c, base " "0x%016" "l" "x" ", level " "lv%.2d" " : missed merge opportunity with neighbor " "@" "0x%016" "l" "x" ", %c, base " "0x%016" "l" "x" ", level " "lv%.2d" ".", num_chunk, p2i(c), c->get_state_char(), p2i (c->base()), c->level(), p2i(buddy), buddy->get_state_char (), p2i(buddy->base()), buddy->level()); ::breakpoint() ; } } while (0); } |
| 428 | "Chunk No. %d " METACHUNK_FORMAT " : missed merge opportunity with neighbor " METACHUNK_FORMAT ".",if (!(buddy->is_in_use() || buddy->level() > c->level ())) { fdStream errst(2); this->print_on(&errst); do { if (!(buddy->is_in_use() || buddy->level() > c-> level())) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/memory/metaspace/rootChunkArea.cpp" , 429, "assert(" "buddy->is_in_use() || buddy->level() > c->level()" ") failed", "Chunk No. %d " "@" "0x%016" "l" "x" ", %c, base " "0x%016" "l" "x" ", level " "lv%.2d" " : missed merge opportunity with neighbor " "@" "0x%016" "l" "x" ", %c, base " "0x%016" "l" "x" ", level " "lv%.2d" ".", num_chunk, p2i(c), c->get_state_char(), p2i (c->base()), c->level(), p2i(buddy), buddy->get_state_char (), p2i(buddy->base()), buddy->level()); ::breakpoint() ; } } while (0); } |
| 429 | num_chunk, METACHUNK_FORMAT_ARGS(c), METACHUNK_FORMAT_ARGS(buddy))if (!(buddy->is_in_use() || buddy->level() > c->level ())) { fdStream errst(2); this->print_on(&errst); do { if (!(buddy->is_in_use() || buddy->level() > c-> level())) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/memory/metaspace/rootChunkArea.cpp" , 429, "assert(" "buddy->is_in_use() || buddy->level() > c->level()" ") failed", "Chunk No. %d " "@" "0x%016" "l" "x" ", %c, base " "0x%016" "l" "x" ", level " "lv%.2d" " : missed merge opportunity with neighbor " "@" "0x%016" "l" "x" ", %c, base " "0x%016" "l" "x" ", level " "lv%.2d" ".", num_chunk, p2i(c), c->get_state_char(), p2i (c->base()), c->level(), p2i(buddy), buddy->get_state_char (), p2i(buddy->base()), buddy->level()); ::breakpoint() ; } } while (0); }; |
| 430 | } |
| 431 | num_chunk++; |
| 432 | } |
| 433 | } |
| 434 | |
| 435 | #endif |
| 436 | |
| 437 | void RootChunkArea::print_on(outputStream* st) const { |
| 438 | st->print(PTR_FORMAT"0x%016" "l" "x" ": ", p2i(base())); |
| 439 | if (_first_chunk != NULL__null) { |
| 440 | const Metachunk* c = _first_chunk; |
| 441 | // 01234567890123 |
| 442 | const char* letters_for_levels_cap = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; |
| 443 | const char* letters_for_levels = "abcdefghijklmnopqrstuvwxyz"; |
| 444 | while (c != NULL__null) { |
| 445 | const chunklevel_t l = c->level(); |
| 446 | if (l >= 0 && (size_t)l < strlen(letters_for_levels)) { |
| 447 | st->print("%c", c->is_free() ? letters_for_levels[c->level()] : letters_for_levels_cap[c->level()]); |
| 448 | } else { |
| 449 | // Obviously garbage, but lets not crash. |
| 450 | st->print("?"); |
| 451 | } |
| 452 | c = c->next_in_vs(); |
| 453 | } |
| 454 | } else { |
| 455 | st->print(" (no chunks)"); |
| 456 | } |
| 457 | st->cr(); |
| 458 | } |
| 459 | |
| 460 | // Create an array of ChunkTree objects, all initialized to NULL, covering |
| 461 | // a given memory range. Memory range must be a multiple of root chunk size. |
| 462 | RootChunkAreaLUT::RootChunkAreaLUT(const MetaWord* base, size_t word_size) : |
| 463 | _base(base), |
| 464 | _num((int)(word_size / chunklevel::MAX_CHUNK_WORD_SIZE)), |
| 465 | _arr(NULL__null) |
| 466 | { |
| 467 | assert_is_aligned(word_size, chunklevel::MAX_CHUNK_WORD_SIZE)do { if (!(is_aligned((word_size), (chunklevel::MAX_CHUNK_WORD_SIZE )))) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/memory/metaspace/rootChunkArea.cpp" , 467, "assert(" "is_aligned((word_size), (chunklevel::MAX_CHUNK_WORD_SIZE))" ") failed", "0x%" "l" "x" " is not aligned to " "0x%" "l" "x" , (size_t)(uintptr_t)word_size, (size_t)(chunklevel::MAX_CHUNK_WORD_SIZE )); ::breakpoint(); } } while (0); |
| 468 | _arr = NEW_C_HEAP_ARRAY(RootChunkArea, _num, mtClass)(RootChunkArea*) (AllocateHeap((_num) * sizeof(RootChunkArea) , mtClass)); |
| 469 | const MetaWord* this_base = _base; |
| 470 | for (int i = 0; i < _num; i++) { |
| 471 | RootChunkArea* rca = new(_arr + i) RootChunkArea(this_base); |
| 472 | assert(rca == _arr + i, "Sanity")do { if (!(rca == _arr + i)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/memory/metaspace/rootChunkArea.cpp" , 472, "assert(" "rca == _arr + i" ") failed", "Sanity"); ::breakpoint (); } } while (0); |
| 473 | this_base += chunklevel::MAX_CHUNK_WORD_SIZE; |
| 474 | } |
| 475 | } |
| 476 | |
| 477 | RootChunkAreaLUT::~RootChunkAreaLUT() { |
| 478 | for (int i = 0; i < _num; i++) { |
| 479 | _arr[i].~RootChunkArea(); |
| 480 | } |
| 481 | FREE_C_HEAP_ARRAY(RootChunkArea, _arr)FreeHeap((char*)(_arr)); |
| 482 | } |
| 483 | |
| 484 | #ifdef ASSERT1 |
| 485 | |
| 486 | void RootChunkAreaLUT::verify() const { |
| 487 | for (int i = 0; i < _num; i++) { |
| 488 | check_pointer(_arr[i].base()); |
| 489 | _arr[i].verify(); |
| 490 | } |
| 491 | } |
| 492 | |
| 493 | #endif |
| 494 | |
| 495 | void RootChunkAreaLUT::print_on(outputStream* st) const { |
| 496 | for (int i = 0; i < _num; i++) { |
| 497 | st->print("%2d:", i); |
| 498 | _arr[i].print_on(st); |
| 499 | } |
| 500 | } |
| 501 | |
| 502 | } // end: namespace metaspace |