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