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