1 /* 2 * Copyright (c) 2020, 2023, 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 25 #ifndef SHARE_CLASSFILE_FIELDLAYOUTBUILDER_HPP 26 #define SHARE_CLASSFILE_FIELDLAYOUTBUILDER_HPP 27 28 #include "classfile/classFileParser.hpp" 29 #include "classfile/classLoaderData.hpp" 30 #include "memory/allocation.hpp" 31 #include "oops/fieldStreams.hpp" 32 #include "utilities/growableArray.hpp" 33 34 // Classes below are used to compute the field layout of classes. 35 36 // A LayoutRawBlock describes an element of a layout. 37 // Each field is represented by a LayoutRawBlock. 38 // LayoutRawBlocks can also represent elements injected by the JVM: 39 // padding, empty blocks, inherited fields, etc. 40 // All LayoutRawBlocks must have a size and an alignment. The size is the 41 // exact size of the field expressed in bytes. The alignment is 42 // the alignment constraint of the field (1 for byte, 2 for short, 43 // 4 for int, 8 for long, etc.) 44 // 45 // LayoutRawBlock are designed to be used in two data structures: 46 // - a linked list in a layout (using _next_block, _prev_block) 47 // - a GrowableArray in field group (the growable array contains pointers to LayoutRawBlocks) 48 // 49 // next/prev pointers are included in the LayoutRawBlock class to narrow 50 // the number of allocation required during the computation of a layout. 51 // 52 class LayoutRawBlock : public ResourceObj { 53 public: 54 // Some code relies on the order of values below. 55 enum Kind { 56 EMPTY, // empty slot, space is taken from this to allocate fields 57 RESERVED, // reserved for JVM usage (for instance object header) 58 PADDING, // padding (because of alignment constraints or @Contended) 59 REGULAR, // primitive or oop field (including not flat inline type fields) 60 FLAT, // flat field 61 INHERITED, // field(s) inherited from super classes 62 NULL_MARKER, // stores the null marker for a flat field 63 INHERITED_NULL_MARKER // a super-class used this slot to store a null marker 64 }; 65 66 private: 67 LayoutRawBlock* _next_block; 68 LayoutRawBlock* _prev_block; 69 InlineKlass* _inline_klass; 70 Kind _kind; 71 int _offset; 72 int _alignment; 73 int _size; 74 int _field_index; 75 int _null_marker_offset; 76 bool _is_reference; 77 bool _needs_null_marker; 78 79 public: 80 LayoutRawBlock(Kind kind, int size); 81 82 LayoutRawBlock(int index, Kind kind, int size, int alignment, bool is_reference = false); 83 LayoutRawBlock* next_block() const { return _next_block; } 84 void set_next_block(LayoutRawBlock* next) { _next_block = next; } 85 LayoutRawBlock* prev_block() const { return _prev_block; } 86 void set_prev_block(LayoutRawBlock* prev) { _prev_block = prev; } 87 Kind kind() const { return _kind; } 88 int offset() const { 89 assert(_offset >= 0, "Must be initialized"); 90 return _offset; 91 } 92 void set_offset(int offset) { _offset = offset; } 93 int alignment() const { return _alignment; } 94 int size() const { return _size; } 95 void set_size(int size) { _size = size; } 96 int field_index() const { 97 assert(_field_index != -1, "Must be initialized"); 98 return _field_index; 99 } 100 void set_field_index(int field_index) { 101 assert(_field_index == -1, "Must not be initialized"); 102 _field_index = field_index; 103 } 104 bool is_reference() const { return _is_reference; } 105 InlineKlass* inline_klass() const { 106 assert(_inline_klass != nullptr, "Must be initialized"); 107 return _inline_klass; 108 } 109 void set_inline_klass(InlineKlass* inline_klass) { _inline_klass = inline_klass; } 110 void set_needs_null_marker() { _needs_null_marker = true; } 111 bool needs_null_marker() const { return _needs_null_marker; } 112 void set_null_marker_offset(int offset) { 113 assert(_needs_null_marker, ""); 114 _null_marker_offset = offset; 115 _needs_null_marker = false; 116 } 117 int null_marker_offset() const { return _null_marker_offset; } 118 119 bool fit(int size, int alignment); 120 121 static int compare_offset(LayoutRawBlock** x, LayoutRawBlock** y) { return (*x)->offset() - (*y)->offset(); } 122 // compare_size_inverted() returns the opposite of a regular compare method in order to 123 // sort fields in decreasing order. 124 // Note: with line types, the comparison should include alignment constraint if sizes are equals 125 static int compare_size_inverted(LayoutRawBlock** x, LayoutRawBlock** y) { 126 #ifdef _WINDOWS 127 // qsort() on Windows reverse the order of fields with the same size 128 // the extension of the comparison function below preserves this order 129 int diff = (*y)->size() - (*x)->size(); 130 if (diff == 0) { 131 diff = (*x)->field_index() - (*y)->field_index(); 132 } 133 return diff; 134 #else 135 return (*y)->size() - (*x)->size(); 136 #endif // _WINDOWS 137 } 138 }; 139 140 // A Field group represents a set of fields that have to be allocated together, 141 // this is the way the @Contended annotation is supported. 142 // Inside a FieldGroup, fields are sorted based on their kind: primitive, 143 // oop, or flat. 144 // 145 class FieldGroup : public ResourceObj { 146 147 private: 148 FieldGroup* _next; 149 150 GrowableArray<LayoutRawBlock*>* _small_primitive_fields; 151 GrowableArray<LayoutRawBlock*>* _big_primitive_fields; 152 GrowableArray<LayoutRawBlock*>* _oop_fields; 153 int _contended_group; 154 int _oop_count; 155 static const int INITIAL_LIST_SIZE = 16; 156 157 public: 158 FieldGroup(int contended_group = -1); 159 160 FieldGroup* next() const { return _next; } 161 void set_next(FieldGroup* next) { _next = next; } 162 GrowableArray<LayoutRawBlock*>* small_primitive_fields() const { return _small_primitive_fields; } 163 GrowableArray<LayoutRawBlock*>* big_primitive_fields() const { return _big_primitive_fields; } 164 GrowableArray<LayoutRawBlock*>* oop_fields() const { return _oop_fields; } 165 int contended_group() const { return _contended_group; } 166 int oop_count() const { return _oop_count; } 167 168 void add_primitive_field(int idx, BasicType type); 169 void add_oop_field(int idx); 170 void add_flat_field(int idx, InlineKlass* vk, bool needs_null_marker); 171 void add_block(LayoutRawBlock** list, LayoutRawBlock* block); 172 void sort_by_size(); 173 private: 174 void add_to_small_primitive_list(LayoutRawBlock* block); 175 void add_to_big_primitive_list(LayoutRawBlock* block); 176 }; 177 178 // The FieldLayout class represents a set of fields organized 179 // in a layout. 180 // An instance of FieldLayout can either represent the layout 181 // of non-static fields (used in an instance object) or the 182 // layout of static fields (to be included in the class mirror). 183 // 184 // _block is a pointer to a list of LayoutRawBlock ordered by increasing 185 // offsets. 186 // _start points to the LayoutRawBlock with the first offset that can 187 // be used to allocate fields of the current class 188 // _last points to the last LayoutRawBlock of the list. In order to 189 // simplify the code, the LayoutRawBlock list always ends with an 190 // EMPTY block (the kind of LayoutRawBlock from which space is taken 191 // to allocate fields) with a size big enough to satisfy all 192 // field allocations. 193 // 194 class FieldLayout : public ResourceObj { 195 private: 196 GrowableArray<FieldInfo>* _field_info; 197 ConstantPool* _cp; 198 LayoutRawBlock* _blocks; // the layout being computed 199 LayoutRawBlock* _start; // points to the first block where a field can be inserted 200 LayoutRawBlock* _last; // points to the last block of the layout (big empty block) 201 int _super_first_field_offset; 202 int _super_alignment; 203 int _super_min_align_required; 204 bool _super_has_fields; 205 bool _has_missing_null_markers; 206 207 public: 208 FieldLayout(GrowableArray<FieldInfo>* field_info, ConstantPool* cp); 209 void initialize_static_layout(); 210 void initialize_instance_layout(const InstanceKlass* ik); 211 212 LayoutRawBlock* first_empty_block() { 213 LayoutRawBlock* block = _start; 214 while (block->kind() != LayoutRawBlock::EMPTY) { 215 block = block->next_block(); 216 } 217 return block; 218 } 219 220 LayoutRawBlock* blocks() const { return _blocks; } 221 222 LayoutRawBlock* start() const { return _start; } 223 void set_start(LayoutRawBlock* start) { _start = start; } 224 LayoutRawBlock* last_block() const { return _last; } 225 int super_first_field_offset() const { return _super_first_field_offset; } 226 int super_alignment() const { return _super_alignment; } 227 int super_min_align_required() const { return _super_min_align_required; } 228 bool super_has_fields() const { return _super_has_fields; } 229 bool has_missing_null_markers() const { return _has_missing_null_markers; } 230 231 LayoutRawBlock* first_field_block(); 232 void add(GrowableArray<LayoutRawBlock*>* list, LayoutRawBlock* start = nullptr); 233 void add_field_at_offset(LayoutRawBlock* blocks, int offset, LayoutRawBlock* start = nullptr); 234 void add_contiguously(GrowableArray<LayoutRawBlock*>* list, LayoutRawBlock* start = nullptr); 235 LayoutRawBlock* insert_field_block(LayoutRawBlock* slot, LayoutRawBlock* block); 236 bool reconstruct_layout(const InstanceKlass* ik); 237 void fill_holes(const InstanceKlass* ik); 238 LayoutRawBlock* insert(LayoutRawBlock* slot, LayoutRawBlock* block); 239 void remove(LayoutRawBlock* block); 240 void print(outputStream* output, bool is_static, const InstanceKlass* super, Array<InlineKlass*>* inline_fields); 241 }; 242 243 244 // FieldLayoutBuilder is the main entry point for layout computation. 245 // This class has two methods to generate layout: one for identity classes 246 // and one for inline classes. The rational for having two methods 247 // is that each kind of classes has a different set goals regarding 248 // its layout, so instead of mixing two layout strategies into a 249 // single method, each kind has its own method (see comments below 250 // for more details about the allocation strategies). 251 // 252 // Computing the layout of a class always goes through 4 steps: 253 // 1 - Prologue: preparation of data structure and gathering of 254 // layout information inherited from super classes 255 // 2 - Field sorting: fields are sorted according to their 256 // kind (oop, primitive, inline class) and their contention 257 // annotation (if any) 258 // 3 - Layout is computed from the set of lists generated during 259 // step 2 260 // 4 - Epilogue: oopmaps are generated, layout information is 261 // prepared so other VM components can use it (instance size, 262 // static field size, non-static field size, etc.) 263 // 264 // Steps 1 and 4 are common to all layout computations. Step 2 and 3 265 // differ for inline classes and identity classes. 266 // 267 class FieldLayoutBuilder : public ResourceObj { 268 private: 269 const Symbol* _classname; 270 ClassLoaderData* _loader_data; 271 const InstanceKlass* _super_klass; 272 ConstantPool* _constant_pool; 273 GrowableArray<FieldInfo>* _field_info; 274 FieldLayoutInfo* _info; 275 Array<InlineKlass*>* _inline_type_field_klasses; 276 FieldGroup* _root_group; 277 GrowableArray<FieldGroup*> _contended_groups; 278 FieldGroup* _static_fields; 279 FieldLayout* _layout; 280 FieldLayout* _static_layout; 281 int _nonstatic_oopmap_count; 282 int _alignment; 283 int _first_field_offset; 284 int _internal_null_marker_offset; // if any, -1 means no internal null marker 285 int _payload_size_in_bytes; 286 int _atomic_field_count; 287 int _fields_size_sum; 288 bool _has_nonstatic_fields; 289 bool _has_inline_type_fields; 290 bool _is_contended; 291 bool _is_inline_type; 292 bool _is_abstract_value; 293 bool _has_flattening_information; 294 bool _has_nonatomic_values; 295 bool _nullable_atomic_flat_candidate; 296 bool _has_null_markers; 297 298 FieldGroup* get_or_create_contended_group(int g); 299 300 public: 301 FieldLayoutBuilder(const Symbol* classname, ClassLoaderData* loader_data, const InstanceKlass* super_klass, ConstantPool* constant_pool, 302 GrowableArray<FieldInfo>* field_info, bool is_contended, bool is_inline_type, bool is_abstract_value, 303 FieldLayoutInfo* info, Array<InlineKlass*>* inline_type_field_klasses); 304 305 int get_alignment() { 306 assert(_alignment != -1, "Uninitialized"); 307 return _alignment; 308 } 309 310 int get_first_field_offset() { 311 assert(_first_field_offset != -1, "Uninitialized"); 312 return _first_field_offset; 313 } 314 315 int get_payload_size_in_byte() { 316 assert(_payload_size_in_bytes != -1, "Uninitialized"); 317 return _payload_size_in_bytes; 318 } 319 320 int get_internal_null_marker_offset() { 321 return _internal_null_marker_offset; 322 } 323 324 void build_layout(); 325 void compute_regular_layout(); 326 void compute_inline_class_layout(); 327 void insert_contended_padding(LayoutRawBlock* slot); 328 void insert_null_markers(); 329 330 protected: 331 void prologue(); 332 void epilogue(); 333 void regular_field_sorting(); 334 void inline_class_field_sorting(); 335 void add_flat_field_oopmap(OopMapBlocksBuilder* nonstatic_oop_map, InlineKlass* vk, int offset); 336 void register_embedded_oops_from_list(OopMapBlocksBuilder* nonstatic_oop_maps, GrowableArray<LayoutRawBlock*>* list); 337 void register_embedded_oops(OopMapBlocksBuilder* nonstatic_oop_maps, FieldGroup* group); 338 }; 339 340 #endif // SHARE_CLASSFILE_FIELDLAYOUTBUILDER_HPP