1 /*
   2  * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  *
  23  */
  24 #include "precompiled.hpp"
  25 
  26 #include "memory/metaspace/chunkAllocSequence.hpp"
  27 #include "memory/metaspace/chunkLevel.hpp"
  28 #include "utilities/globalDefinitions.hpp"
  29 
  30 namespace metaspace {
  31 
  32 
  33 // A chunk allocation sequence which can be encoded with a simple const array.
  34 class ConstantChunkAllocSequence : public ChunkAllocSequence {
  35 
  36   // integer array specifying chunk level allocation progression.
  37   // Last chunk is to be an endlessly repeated allocation.
  38   const chklvl_t* const _entries;
  39   const int _num_entries;
  40 
  41 public:
  42 
  43   ConstantChunkAllocSequence(const chklvl_t* array, int num_entries)
  44     : _entries(array)
  45     , _num_entries(num_entries)
  46   {
  47     assert(_num_entries > 0, "must not be empty.");
  48   }
  49 
  50   chklvl_t get_next_chunk_level(int num_allocated) const {
  51     if (num_allocated >= _num_entries) {
  52       // Caller shall repeat last allocation
  53       return _entries[_num_entries - 1];
  54     }
  55     return _entries[_num_entries];
  56   }
  57 
  58 };
  59 
  60 // hard-coded chunk allocation sequences for various space types
  61 
  62 ///////////////////////////
  63 // chunk allocation sequences for normal loaders:
  64 static const chklvl_t g_sequ_standard_nonclass[] = {
  65     CHUNK_LEVEL_4K, CHUNK_LEVEL_4K, CHUNK_LEVEL_4K, CHUNK_LEVEL_4K,
  66     CHUNK_LEVEL_64K,
  67     -1 // .. repeat last
  68 };
  69 
  70 static const chklvl_t g_sequ_standard_class[] = {
  71     CHUNK_LEVEL_4K, CHUNK_LEVEL_4K, CHUNK_LEVEL_4K, CHUNK_LEVEL_4K,
  72     CHUNK_LEVEL_32K,
  73     -1 // .. repeat last
  74 };
  75 
  76 ///////////////////////////
  77 // chunk allocation sequences for reflection/anonymous loaders:
  78 // We allocate four smallish chunks before progressing to bigger chunks.
  79 static const chklvl_t g_sequ_anon_nonclass[] = {
  80     CHUNK_LEVEL_1K, CHUNK_LEVEL_1K, CHUNK_LEVEL_1K, CHUNK_LEVEL_1K,
  81     CHUNK_LEVEL_4K,
  82     -1 // .. repeat last
  83 };
  84 
  85 static const chklvl_t g_sequ_anon_class[] = {
  86     CHUNK_LEVEL_1K, CHUNK_LEVEL_1K, CHUNK_LEVEL_1K, CHUNK_LEVEL_1K,
  87     CHUNK_LEVEL_4K,
  88     -1 // .. repeat last
  89 };
  90 
  91 #define DEFINE_CLASS_FOR_ARRAY(what) \
  92   static ConstantChunkAllocSequence g_chunk_alloc_sequence_##what (g_sequ_##what, sizeof(g_sequ_##what)/sizeof(int));
  93 
  94 DEFINE_CLASS_FOR_ARRAY(standard_nonclass)
  95 DEFINE_CLASS_FOR_ARRAY(standard_class)
  96 DEFINE_CLASS_FOR_ARRAY(anon_nonclass)
  97 DEFINE_CLASS_FOR_ARRAY(anon_class)
  98 
  99 
 100 class BootLoaderChunkAllocSequence : public ChunkAllocSequence {
 101 
 102   // For now, this mirrors what the old code did
 103   // (see SpaceManager::get_initial_chunk_size() and SpaceManager::calc_chunk_size).
 104 
 105   // Not sure how much sense this still makes, especially with CDS - by default we
 106   // now load JDK classes from CDS and therefore most of the boot loader
 107   // chunks remain unoccupied.
 108 
 109   // Also, InitialBootClassLoaderMetaspaceSize was/is confusing since it only applies
 110   // to the non-class chunk.
 111 
 112   const bool _is_class;
 113 
 114   static chklvl_t calc_initial_chunk_level(bool is_class) {
 115 
 116     size_t word_size = 0;
 117     if (is_class) {
 118       // In the old version first class space chunk for boot loader was always medium class chunk size * 6.
 119       word_size = 32 * K * 6;
 120 
 121     } else {
 122       assert(InitialBootClassLoaderMetaspaceSize < MAX_CHUNK_BYTE_SIZE,
 123              "InitialBootClassLoaderMetaspaceSize too large");
 124       word_size = InitialBootClassLoaderMetaspaceSize / BytesPerWord;
 125     }
 126     return level_fitting_word_size(word_size);
 127   }
 128 
 129 public:
 130 
 131   BootLoaderChunkAllocSequence(bool is_class)
 132     : _is_class(is_class)
 133   {}
 134 
 135   chklvl_t get_next_chunk_level(int num_allocated) const {
 136     if (num_allocated == 0) {
 137       return calc_initial_chunk_level(_is_class);
 138     }
 139     // bit arbitrary, but this is what the old code did. Can tweak later if needed.
 140     return CHUNK_LEVEL_64K;
 141   }
 142 
 143 };
 144 
 145 static BootLoaderChunkAllocSequence g_chunk_alloc_sequence_boot_non_class(false);
 146 static BootLoaderChunkAllocSequence g_chunk_alloc_sequence_boot_class(true);
 147 
 148 
 149 const ChunkAllocSequence* ChunkAllocSequence::alloc_sequence_by_space_type(Metaspace::MetaspaceType space_type, bool is_class) {
 150 
 151   if (is_class) {
 152     switch(space_type) {
 153     case Metaspace::StandardMetaspaceType: return &g_chunk_alloc_sequence_standard_class;
 154     case Metaspace::ReflectionMetaspaceType:
 155     case Metaspace::UnsafeAnonymousMetaspaceType: return &g_chunk_alloc_sequence_anon_class;
 156     case Metaspace::BootMetaspaceType: return &g_chunk_alloc_sequence_boot_non_class;
 157     default: ShouldNotReachHere();
 158     }
 159   } else {
 160     switch(space_type) {
 161     case Metaspace::StandardMetaspaceType: return &g_chunk_alloc_sequence_standard_class;
 162     case Metaspace::ReflectionMetaspaceType:
 163     case Metaspace::UnsafeAnonymousMetaspaceType: return &g_chunk_alloc_sequence_anon_class;
 164     case Metaspace::BootMetaspaceType: return &g_chunk_alloc_sequence_boot_class;
 165     default: ShouldNotReachHere();
 166     }
 167   }
 168 
 169   return NULL;
 170 
 171 }
 172 
 173 
 174 
 175 } // namespace metaspace
 176