| File: | jdk/src/hotspot/share/classfile/fieldLayoutBuilder.cpp |
| Warning: | line 284, column 22 Division by zero |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* | ||||
| 2 | * Copyright (c) 2020, 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 | #include "precompiled.hpp" | ||||
| 26 | #include "jvm.h" | ||||
| 27 | #include "classfile/classFileParser.hpp" | ||||
| 28 | #include "classfile/fieldLayoutBuilder.hpp" | ||||
| 29 | #include "memory/resourceArea.hpp" | ||||
| 30 | #include "oops/array.hpp" | ||||
| 31 | #include "oops/fieldStreams.inline.hpp" | ||||
| 32 | #include "oops/instanceMirrorKlass.hpp" | ||||
| 33 | #include "oops/instanceKlass.inline.hpp" | ||||
| 34 | #include "oops/klass.inline.hpp" | ||||
| 35 | #include "runtime/fieldDescriptor.inline.hpp" | ||||
| 36 | |||||
| 37 | |||||
| 38 | LayoutRawBlock::LayoutRawBlock(Kind kind, int size) : | ||||
| 39 | _next_block(NULL__null), | ||||
| 40 | _prev_block(NULL__null), | ||||
| 41 | _kind(kind), | ||||
| 42 | _offset(-1), | ||||
| 43 | _alignment(1), | ||||
| 44 | _size(size), | ||||
| 45 | _field_index(-1), | ||||
| 46 | _is_reference(false) { | ||||
| 47 | assert(kind == EMPTY || kind == RESERVED || kind == PADDING || kind == INHERITED,do { if (!(kind == EMPTY || kind == RESERVED || kind == PADDING || kind == INHERITED)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/classfile/fieldLayoutBuilder.cpp" , 48, "assert(" "kind == EMPTY || kind == RESERVED || kind == PADDING || kind == INHERITED" ") failed", "Otherwise, should use the constructor with a field index argument" ); ::breakpoint(); } } while (0) | ||||
| 48 | "Otherwise, should use the constructor with a field index argument")do { if (!(kind == EMPTY || kind == RESERVED || kind == PADDING || kind == INHERITED)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/classfile/fieldLayoutBuilder.cpp" , 48, "assert(" "kind == EMPTY || kind == RESERVED || kind == PADDING || kind == INHERITED" ") failed", "Otherwise, should use the constructor with a field index argument" ); ::breakpoint(); } } while (0); | ||||
| 49 | assert(size > 0, "Sanity check")do { if (!(size > 0)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/classfile/fieldLayoutBuilder.cpp" , 49, "assert(" "size > 0" ") failed", "Sanity check"); :: breakpoint(); } } while (0); | ||||
| 50 | } | ||||
| 51 | |||||
| 52 | |||||
| 53 | LayoutRawBlock::LayoutRawBlock(int index, Kind kind, int size, int alignment, bool is_reference) : | ||||
| 54 | _next_block(NULL__null), | ||||
| 55 | _prev_block(NULL__null), | ||||
| 56 | _kind(kind), | ||||
| 57 | _offset(-1), | ||||
| 58 | _alignment(alignment), | ||||
| 59 | _size(size), | ||||
| 60 | _field_index(index), | ||||
| 61 | _is_reference(is_reference) { | ||||
| 62 | assert(kind == REGULAR || kind == FLATTENED || kind == INHERITED,do { if (!(kind == REGULAR || kind == FLATTENED || kind == INHERITED )) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/classfile/fieldLayoutBuilder.cpp" , 63, "assert(" "kind == REGULAR || kind == FLATTENED || kind == INHERITED" ") failed", "Other kind do not have a field index"); ::breakpoint (); } } while (0) | ||||
| 63 | "Other kind do not have a field index")do { if (!(kind == REGULAR || kind == FLATTENED || kind == INHERITED )) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/classfile/fieldLayoutBuilder.cpp" , 63, "assert(" "kind == REGULAR || kind == FLATTENED || kind == INHERITED" ") failed", "Other kind do not have a field index"); ::breakpoint (); } } while (0); | ||||
| 64 | assert(size > 0, "Sanity check")do { if (!(size > 0)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/classfile/fieldLayoutBuilder.cpp" , 64, "assert(" "size > 0" ") failed", "Sanity check"); :: breakpoint(); } } while (0); | ||||
| 65 | assert(alignment > 0, "Sanity check")do { if (!(alignment > 0)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/classfile/fieldLayoutBuilder.cpp" , 65, "assert(" "alignment > 0" ") failed", "Sanity check" ); ::breakpoint(); } } while (0); | ||||
| 66 | } | ||||
| 67 | |||||
| 68 | bool LayoutRawBlock::fit(int size, int alignment) { | ||||
| 69 | int adjustment = 0; | ||||
| 70 | if ((_offset % alignment) != 0) { | ||||
| 71 | adjustment = alignment - (_offset % alignment); | ||||
| 72 | } | ||||
| 73 | return _size >= size + adjustment; | ||||
| 74 | } | ||||
| 75 | |||||
| 76 | FieldGroup::FieldGroup(int contended_group) : | ||||
| 77 | _next(NULL__null), | ||||
| 78 | _primitive_fields(NULL__null), | ||||
| 79 | _oop_fields(NULL__null), | ||||
| 80 | _contended_group(contended_group), // -1 means no contended group, 0 means default contended group | ||||
| 81 | _oop_count(0) {} | ||||
| 82 | |||||
| 83 | void FieldGroup::add_primitive_field(AllFieldStream fs, BasicType type) { | ||||
| 84 | int size = type2aelembytes(type); | ||||
| 85 | LayoutRawBlock* block = new LayoutRawBlock(fs.index(), LayoutRawBlock::REGULAR, size, size /* alignment == size for primitive types */, false); | ||||
| 86 | if (_primitive_fields == NULL__null) { | ||||
| 87 | _primitive_fields = new(ResourceObj::RESOURCE_AREA, mtInternal) GrowableArray<LayoutRawBlock*>(INITIAL_LIST_SIZE); | ||||
| 88 | } | ||||
| 89 | _primitive_fields->append(block); | ||||
| 90 | } | ||||
| 91 | |||||
| 92 | void FieldGroup::add_oop_field(AllFieldStream fs) { | ||||
| 93 | int size = type2aelembytes(T_OBJECT); | ||||
| 94 | LayoutRawBlock* block = new LayoutRawBlock(fs.index(), LayoutRawBlock::REGULAR, size, size /* alignment == size for oops */, true); | ||||
| 95 | if (_oop_fields == NULL__null) { | ||||
| 96 | _oop_fields = new(ResourceObj::RESOURCE_AREA, mtInternal) GrowableArray<LayoutRawBlock*>(INITIAL_LIST_SIZE); | ||||
| 97 | } | ||||
| 98 | _oop_fields->append(block); | ||||
| 99 | _oop_count++; | ||||
| 100 | } | ||||
| 101 | |||||
| 102 | void FieldGroup::sort_by_size() { | ||||
| 103 | if (_primitive_fields != NULL__null) { | ||||
| 104 | _primitive_fields->sort(LayoutRawBlock::compare_size_inverted); | ||||
| 105 | } | ||||
| 106 | } | ||||
| 107 | |||||
| 108 | FieldLayout::FieldLayout(Array<u2>* fields, ConstantPool* cp) : | ||||
| 109 | _fields(fields), | ||||
| 110 | _cp(cp), | ||||
| 111 | _blocks(NULL__null), | ||||
| 112 | _start(_blocks), | ||||
| 113 | _last(_blocks) {} | ||||
| 114 | |||||
| 115 | void FieldLayout::initialize_static_layout() { | ||||
| 116 | _blocks = new LayoutRawBlock(LayoutRawBlock::EMPTY, INT_MAX2147483647); | ||||
| 117 | _blocks->set_offset(0); | ||||
| 118 | _last = _blocks; | ||||
| 119 | _start = _blocks; | ||||
| 120 | // Note: at this stage, InstanceMirrorKlass::offset_of_static_fields() could be zero, because | ||||
| 121 | // during bootstrapping, the size of the java.lang.Class is still not known when layout | ||||
| 122 | // of static field is computed. Field offsets are fixed later when the size is known | ||||
| 123 | // (see java_lang_Class::fixup_mirror()) | ||||
| 124 | if (InstanceMirrorKlass::offset_of_static_fields() > 0) { | ||||
| 125 | insert(first_empty_block(), new LayoutRawBlock(LayoutRawBlock::RESERVED, InstanceMirrorKlass::offset_of_static_fields())); | ||||
| 126 | _blocks->set_offset(0); | ||||
| 127 | } | ||||
| 128 | } | ||||
| 129 | |||||
| 130 | void FieldLayout::initialize_instance_layout(const InstanceKlass* super_klass) { | ||||
| 131 | if (super_klass == NULL__null) { | ||||
| 132 | _blocks = new LayoutRawBlock(LayoutRawBlock::EMPTY, INT_MAX2147483647); | ||||
| 133 | _blocks->set_offset(0); | ||||
| 134 | _last = _blocks; | ||||
| 135 | _start = _blocks; | ||||
| 136 | insert(first_empty_block(), new LayoutRawBlock(LayoutRawBlock::RESERVED, instanceOopDesc::base_offset_in_bytes())); | ||||
| 137 | } else { | ||||
| 138 | bool has_fields = reconstruct_layout(super_klass); | ||||
| 139 | fill_holes(super_klass); | ||||
| 140 | if ((UseEmptySlotsInSupers && !super_klass->has_contended_annotations()) || !has_fields) { | ||||
| 141 | _start = _blocks; // start allocating fields from the first empty block | ||||
| 142 | } else { | ||||
| 143 | _start = _last; // append fields at the end of the reconstructed layout | ||||
| 144 | } | ||||
| 145 | } | ||||
| 146 | } | ||||
| 147 | |||||
| 148 | LayoutRawBlock* FieldLayout::first_field_block() { | ||||
| 149 | LayoutRawBlock* block = _start; | ||||
| 150 | while (block->kind() != LayoutRawBlock::INHERITED && block->kind() != LayoutRawBlock::REGULAR | ||||
| 151 | && block->kind() != LayoutRawBlock::FLATTENED && block->kind() != LayoutRawBlock::PADDING) { | ||||
| 152 | block = block->next_block(); | ||||
| 153 | } | ||||
| 154 | return block; | ||||
| 155 | } | ||||
| 156 | |||||
| 157 | |||||
| 158 | // Insert a set of fields into a layout using a best-fit strategy. | ||||
| 159 | // For each field, search for the smallest empty slot able to fit the field | ||||
| 160 | // (satisfying both size and alignment requirements), if none is found, | ||||
| 161 | // add the field at the end of the layout. | ||||
| 162 | // Fields cannot be inserted before the block specified in the "start" argument | ||||
| 163 | void FieldLayout::add(GrowableArray<LayoutRawBlock*>* list, LayoutRawBlock* start) { | ||||
| 164 | if (list == NULL__null) return; | ||||
| 165 | if (start
| ||||
| 166 | bool last_search_success = false; | ||||
| 167 | int last_size = 0; | ||||
| 168 | int last_alignment = 0; | ||||
| 169 | for (int i = 0; i < list->length(); i ++) { | ||||
| 170 | LayoutRawBlock* b = list->at(i); | ||||
| 171 | LayoutRawBlock* cursor = NULL__null; | ||||
| 172 | LayoutRawBlock* candidate = NULL__null; | ||||
| 173 | |||||
| 174 | // if start is the last block, just append the field | ||||
| 175 | if (start == last_block()) { | ||||
| 176 | candidate = last_block(); | ||||
| 177 | } | ||||
| 178 | // Before iterating over the layout to find an empty slot fitting the field's requirements, | ||||
| 179 | // check if the previous field had the same requirements and if the search for a fitting slot | ||||
| 180 | // was successful. If the requirements were the same but the search failed, a new search will | ||||
| 181 | // fail the same way, so just append the field at the of the layout. | ||||
| 182 | else if (b->size() == last_size && b->alignment() == last_alignment && !last_search_success
| ||||
| 183 | candidate = last_block(); | ||||
| 184 | } else { | ||||
| 185 | // Iterate over the layout to find an empty slot fitting the field's requirements | ||||
| 186 | last_size = b->size(); | ||||
| 187 | last_alignment = b->alignment(); | ||||
| 188 | cursor = last_block()->prev_block(); | ||||
| 189 | assert(cursor != NULL, "Sanity check")do { if (!(cursor != __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/classfile/fieldLayoutBuilder.cpp" , 189, "assert(" "cursor != __null" ") failed", "Sanity check" ); ::breakpoint(); } } while (0); | ||||
| 190 | last_search_success = true; | ||||
| 191 | while (cursor != start) { | ||||
| 192 | if (cursor->kind() == LayoutRawBlock::EMPTY && cursor->fit(b->size(), b->alignment())) { | ||||
| 193 | if (candidate == NULL__null || cursor->size() < candidate->size()) { | ||||
| 194 | candidate = cursor; | ||||
| 195 | } | ||||
| 196 | } | ||||
| 197 | cursor = cursor->prev_block(); | ||||
| 198 | } | ||||
| 199 | if (candidate == NULL__null) { | ||||
| 200 | candidate = last_block(); | ||||
| 201 | last_search_success = false; | ||||
| 202 | } | ||||
| 203 | assert(candidate != NULL, "Candidate must not be null")do { if (!(candidate != __null)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/classfile/fieldLayoutBuilder.cpp" , 203, "assert(" "candidate != __null" ") failed", "Candidate must not be null" ); ::breakpoint(); } } while (0); | ||||
| 204 | assert(candidate->kind() == LayoutRawBlock::EMPTY, "Candidate must be an empty block")do { if (!(candidate->kind() == LayoutRawBlock::EMPTY)) { ( *g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/classfile/fieldLayoutBuilder.cpp" , 204, "assert(" "candidate->kind() == LayoutRawBlock::EMPTY" ") failed", "Candidate must be an empty block"); ::breakpoint (); } } while (0); | ||||
| 205 | assert(candidate->fit(b->size(), b->alignment()), "Candidate must be able to store the block")do { if (!(candidate->fit(b->size(), b->alignment()) )) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/classfile/fieldLayoutBuilder.cpp" , 205, "assert(" "candidate->fit(b->size(), b->alignment())" ") failed", "Candidate must be able to store the block"); :: breakpoint(); } } while (0); | ||||
| 206 | } | ||||
| 207 | |||||
| 208 | insert_field_block(candidate, b); | ||||
| 209 | } | ||||
| 210 | } | ||||
| 211 | |||||
| 212 | // Used for classes with hard coded field offsets, insert a field at the specified offset */ | ||||
| 213 | void FieldLayout::add_field_at_offset(LayoutRawBlock* block, int offset, LayoutRawBlock* start) { | ||||
| 214 | assert(block != NULL, "Sanity check")do { if (!(block != __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/classfile/fieldLayoutBuilder.cpp" , 214, "assert(" "block != __null" ") failed", "Sanity check" ); ::breakpoint(); } } while (0); | ||||
| 215 | block->set_offset(offset); | ||||
| 216 | if (start == NULL__null) { | ||||
| 217 | start = this->_start; | ||||
| 218 | } | ||||
| 219 | LayoutRawBlock* slot = start; | ||||
| 220 | while (slot != NULL__null) { | ||||
| 221 | if ((slot->offset() <= block->offset() && (slot->offset() + slot->size()) > block->offset()) || | ||||
| 222 | slot == _last){ | ||||
| 223 | assert(slot->kind() == LayoutRawBlock::EMPTY, "Matching slot must be an empty slot")do { if (!(slot->kind() == LayoutRawBlock::EMPTY)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/classfile/fieldLayoutBuilder.cpp" , 223, "assert(" "slot->kind() == LayoutRawBlock::EMPTY" ") failed" , "Matching slot must be an empty slot"); ::breakpoint(); } } while (0); | ||||
| 224 | assert(slot->size() >= block->offset() + block->size() ,"Matching slot must be big enough")do { if (!(slot->size() >= block->offset() + block-> size())) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/classfile/fieldLayoutBuilder.cpp" , 224, "assert(" "slot->size() >= block->offset() + block->size()" ") failed", "Matching slot must be big enough"); ::breakpoint (); } } while (0); | ||||
| 225 | if (slot->offset() < block->offset()) { | ||||
| 226 | int adjustment = block->offset() - slot->offset(); | ||||
| 227 | LayoutRawBlock* adj = new LayoutRawBlock(LayoutRawBlock::EMPTY, adjustment); | ||||
| 228 | insert(slot, adj); | ||||
| 229 | } | ||||
| 230 | insert(slot, block); | ||||
| 231 | if (slot->size() == 0) { | ||||
| 232 | remove(slot); | ||||
| 233 | } | ||||
| 234 | FieldInfo::from_field_array(_fields, block->field_index())->set_offset(block->offset()); | ||||
| 235 | return; | ||||
| 236 | } | ||||
| 237 | slot = slot->next_block(); | ||||
| 238 | } | ||||
| 239 | fatal("Should have found a matching slot above, corrupted layout or invalid offset")do { (*g_assert_poison) = 'X';; report_fatal(INTERNAL_ERROR, "/home/daniel/Projects/java/jdk/src/hotspot/share/classfile/fieldLayoutBuilder.cpp" , 239, "Should have found a matching slot above, corrupted layout or invalid offset" ); ::breakpoint(); } while (0); | ||||
| 240 | } | ||||
| 241 | |||||
| 242 | // The allocation logic uses a best fit strategy: the set of fields is allocated | ||||
| 243 | // in the first empty slot big enough to contain the whole set ((including padding | ||||
| 244 | // to fit alignment constraints). | ||||
| 245 | void FieldLayout::add_contiguously(GrowableArray<LayoutRawBlock*>* list, LayoutRawBlock* start) { | ||||
| 246 | if (list == NULL__null) return; | ||||
| 247 | if (start == NULL__null) { | ||||
| 248 | start = _start; | ||||
| 249 | } | ||||
| 250 | // This code assumes that if the first block is well aligned, the following | ||||
| 251 | // blocks would naturally be well aligned (no need for adjustment) | ||||
| 252 | int size = 0; | ||||
| 253 | for (int i = 0; i < list->length(); i++) { | ||||
| 254 | size += list->at(i)->size(); | ||||
| 255 | } | ||||
| 256 | |||||
| 257 | LayoutRawBlock* candidate = NULL__null; | ||||
| 258 | if (start == last_block()) { | ||||
| 259 | candidate = last_block(); | ||||
| 260 | } else { | ||||
| 261 | LayoutRawBlock* first = list->at(0); | ||||
| 262 | candidate = last_block()->prev_block(); | ||||
| 263 | while (candidate->kind() != LayoutRawBlock::EMPTY || !candidate->fit(size, first->alignment())) { | ||||
| 264 | if (candidate == start) { | ||||
| 265 | candidate = last_block(); | ||||
| 266 | break; | ||||
| 267 | } | ||||
| 268 | candidate = candidate->prev_block(); | ||||
| 269 | } | ||||
| 270 | assert(candidate != NULL, "Candidate must not be null")do { if (!(candidate != __null)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/classfile/fieldLayoutBuilder.cpp" , 270, "assert(" "candidate != __null" ") failed", "Candidate must not be null" ); ::breakpoint(); } } while (0); | ||||
| 271 | assert(candidate->kind() == LayoutRawBlock::EMPTY, "Candidate must be an empty block")do { if (!(candidate->kind() == LayoutRawBlock::EMPTY)) { ( *g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/classfile/fieldLayoutBuilder.cpp" , 271, "assert(" "candidate->kind() == LayoutRawBlock::EMPTY" ") failed", "Candidate must be an empty block"); ::breakpoint (); } } while (0); | ||||
| 272 | assert(candidate->fit(size, first->alignment()), "Candidate must be able to store the whole contiguous block")do { if (!(candidate->fit(size, first->alignment()))) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/classfile/fieldLayoutBuilder.cpp" , 272, "assert(" "candidate->fit(size, first->alignment())" ") failed", "Candidate must be able to store the whole contiguous block" ); ::breakpoint(); } } while (0); | ||||
| 273 | } | ||||
| 274 | |||||
| 275 | for (int i = 0; i < list->length(); i++) { | ||||
| 276 | LayoutRawBlock* b = list->at(i); | ||||
| 277 | insert_field_block(candidate, b); | ||||
| 278 | assert((candidate->offset() % b->alignment() == 0), "Contiguous blocks must be naturally well aligned")do { if (!((candidate->offset() % b->alignment() == 0)) ) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/classfile/fieldLayoutBuilder.cpp" , 278, "assert(" "(candidate->offset() % b->alignment() == 0)" ") failed", "Contiguous blocks must be naturally well aligned" ); ::breakpoint(); } } while (0); | ||||
| 279 | } | ||||
| 280 | } | ||||
| 281 | |||||
| 282 | LayoutRawBlock* FieldLayout::insert_field_block(LayoutRawBlock* slot, LayoutRawBlock* block) { | ||||
| 283 | assert(slot->kind() == LayoutRawBlock::EMPTY, "Blocks can only be inserted in empty blocks")do { if (!(slot->kind() == LayoutRawBlock::EMPTY)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/classfile/fieldLayoutBuilder.cpp" , 283, "assert(" "slot->kind() == LayoutRawBlock::EMPTY" ") failed" , "Blocks can only be inserted in empty blocks"); ::breakpoint (); } } while (0); | ||||
| 284 | if (slot->offset() % block->alignment() != 0) { | ||||
| |||||
| 285 | int adjustment = block->alignment() - (slot->offset() % block->alignment()); | ||||
| 286 | LayoutRawBlock* adj = new LayoutRawBlock(LayoutRawBlock::EMPTY, adjustment); | ||||
| 287 | insert(slot, adj); | ||||
| 288 | } | ||||
| 289 | insert(slot, block); | ||||
| 290 | if (slot->size() == 0) { | ||||
| 291 | remove(slot); | ||||
| 292 | } | ||||
| 293 | FieldInfo::from_field_array(_fields, block->field_index())->set_offset(block->offset()); | ||||
| 294 | return block; | ||||
| 295 | } | ||||
| 296 | |||||
| 297 | bool FieldLayout::reconstruct_layout(const InstanceKlass* ik) { | ||||
| 298 | bool has_instance_fields = false; | ||||
| 299 | GrowableArray<LayoutRawBlock*>* all_fields = new GrowableArray<LayoutRawBlock*>(32); | ||||
| 300 | while (ik != NULL__null) { | ||||
| 301 | for (AllFieldStream fs(ik->fields(), ik->constants()); !fs.done(); fs.next()) { | ||||
| 302 | BasicType type = Signature::basic_type(fs.signature()); | ||||
| 303 | // distinction between static and non-static fields is missing | ||||
| 304 | if (fs.access_flags().is_static()) continue; | ||||
| 305 | has_instance_fields = true; | ||||
| 306 | int size = type2aelembytes(type); | ||||
| 307 | // INHERITED blocks are marked as non-reference because oop_maps are handled by their holder class | ||||
| 308 | LayoutRawBlock* block = new LayoutRawBlock(fs.index(), LayoutRawBlock::INHERITED, size, size, false); | ||||
| 309 | block->set_offset(fs.offset()); | ||||
| 310 | all_fields->append(block); | ||||
| 311 | } | ||||
| 312 | ik = ik->super() == NULL__null ? NULL__null : InstanceKlass::cast(ik->super()); | ||||
| 313 | } | ||||
| 314 | |||||
| 315 | all_fields->sort(LayoutRawBlock::compare_offset); | ||||
| 316 | _blocks = new LayoutRawBlock(LayoutRawBlock::RESERVED, instanceOopDesc::base_offset_in_bytes()); | ||||
| 317 | _blocks->set_offset(0); | ||||
| 318 | _last = _blocks; | ||||
| 319 | |||||
| 320 | for(int i = 0; i < all_fields->length(); i++) { | ||||
| 321 | LayoutRawBlock* b = all_fields->at(i); | ||||
| 322 | _last->set_next_block(b); | ||||
| 323 | b->set_prev_block(_last); | ||||
| 324 | _last = b; | ||||
| 325 | } | ||||
| 326 | _start = _blocks; | ||||
| 327 | return has_instance_fields; | ||||
| 328 | } | ||||
| 329 | |||||
| 330 | // Called during the reconstruction of a layout, after fields from super | ||||
| 331 | // classes have been inserted. It fills unused slots between inserted fields | ||||
| 332 | // with EMPTY blocks, so the regular field insertion methods would work. | ||||
| 333 | // This method handles classes with @Contended annotations differently | ||||
| 334 | // by inserting PADDING blocks instead of EMPTY block to prevent subclasses' | ||||
| 335 | // fields to interfere with contended fields/classes. | ||||
| 336 | void FieldLayout::fill_holes(const InstanceKlass* super_klass) { | ||||
| 337 | assert(_blocks != NULL, "Sanity check")do { if (!(_blocks != __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/classfile/fieldLayoutBuilder.cpp" , 337, "assert(" "_blocks != __null" ") failed", "Sanity check" ); ::breakpoint(); } } while (0); | ||||
| 338 | assert(_blocks->offset() == 0, "first block must be at offset zero")do { if (!(_blocks->offset() == 0)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/classfile/fieldLayoutBuilder.cpp" , 338, "assert(" "_blocks->offset() == 0" ") failed", "first block must be at offset zero" ); ::breakpoint(); } } while (0); | ||||
| 339 | LayoutRawBlock::Kind filling_type = super_klass->has_contended_annotations() ? LayoutRawBlock::PADDING: LayoutRawBlock::EMPTY; | ||||
| 340 | LayoutRawBlock* b = _blocks; | ||||
| 341 | while (b->next_block() != NULL__null) { | ||||
| 342 | if (b->next_block()->offset() > (b->offset() + b->size())) { | ||||
| 343 | int size = b->next_block()->offset() - (b->offset() + b->size()); | ||||
| 344 | LayoutRawBlock* empty = new LayoutRawBlock(filling_type, size); | ||||
| 345 | empty->set_offset(b->offset() + b->size()); | ||||
| 346 | empty->set_next_block(b->next_block()); | ||||
| 347 | b->next_block()->set_prev_block(empty); | ||||
| 348 | b->set_next_block(empty); | ||||
| 349 | empty->set_prev_block(b); | ||||
| 350 | } | ||||
| 351 | b = b->next_block(); | ||||
| 352 | } | ||||
| 353 | assert(b->next_block() == NULL, "Invariant at this point")do { if (!(b->next_block() == __null)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/classfile/fieldLayoutBuilder.cpp" , 353, "assert(" "b->next_block() == __null" ") failed", "Invariant at this point" ); ::breakpoint(); } } while (0); | ||||
| 354 | assert(b->kind() != LayoutRawBlock::EMPTY, "Sanity check")do { if (!(b->kind() != LayoutRawBlock::EMPTY)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/classfile/fieldLayoutBuilder.cpp" , 354, "assert(" "b->kind() != LayoutRawBlock::EMPTY" ") failed" , "Sanity check"); ::breakpoint(); } } while (0); | ||||
| 355 | |||||
| 356 | // If the super class has @Contended annotation, a padding block is | ||||
| 357 | // inserted at the end to ensure that fields from the subclasses won't share | ||||
| 358 | // the cache line of the last field of the contended class | ||||
| 359 | if (super_klass->has_contended_annotations() && ContendedPaddingWidth > 0) { | ||||
| 360 | LayoutRawBlock* p = new LayoutRawBlock(LayoutRawBlock::PADDING, ContendedPaddingWidth); | ||||
| 361 | p->set_offset(b->offset() + b->size()); | ||||
| 362 | b->set_next_block(p); | ||||
| 363 | p->set_prev_block(b); | ||||
| 364 | b = p; | ||||
| 365 | } | ||||
| 366 | |||||
| 367 | if (!UseEmptySlotsInSupers) { | ||||
| 368 | // Add an empty slots to align fields of the subclass on a heapOopSize boundary | ||||
| 369 | // in order to emulate the behavior of the previous algorithm | ||||
| 370 | int align = (b->offset() + b->size()) % heapOopSize; | ||||
| 371 | if (align != 0) { | ||||
| 372 | int sz = heapOopSize - align; | ||||
| 373 | LayoutRawBlock* p = new LayoutRawBlock(LayoutRawBlock::EMPTY, sz); | ||||
| 374 | p->set_offset(b->offset() + b->size()); | ||||
| 375 | b->set_next_block(p); | ||||
| 376 | p->set_prev_block(b); | ||||
| 377 | b = p; | ||||
| 378 | } | ||||
| 379 | } | ||||
| 380 | |||||
| 381 | LayoutRawBlock* last = new LayoutRawBlock(LayoutRawBlock::EMPTY, INT_MAX2147483647); | ||||
| 382 | last->set_offset(b->offset() + b->size()); | ||||
| 383 | assert(last->offset() > 0, "Sanity check")do { if (!(last->offset() > 0)) { (*g_assert_poison) = 'X' ;; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/classfile/fieldLayoutBuilder.cpp" , 383, "assert(" "last->offset() > 0" ") failed", "Sanity check" ); ::breakpoint(); } } while (0); | ||||
| 384 | b->set_next_block(last); | ||||
| 385 | last->set_prev_block(b); | ||||
| 386 | _last = last; | ||||
| 387 | } | ||||
| 388 | |||||
| 389 | LayoutRawBlock* FieldLayout::insert(LayoutRawBlock* slot, LayoutRawBlock* block) { | ||||
| 390 | assert(slot->kind() == LayoutRawBlock::EMPTY, "Blocks can only be inserted in empty blocks")do { if (!(slot->kind() == LayoutRawBlock::EMPTY)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/classfile/fieldLayoutBuilder.cpp" , 390, "assert(" "slot->kind() == LayoutRawBlock::EMPTY" ") failed" , "Blocks can only be inserted in empty blocks"); ::breakpoint (); } } while (0); | ||||
| 391 | assert(slot->offset() % block->alignment() == 0, "Incompatible alignment")do { if (!(slot->offset() % block->alignment() == 0)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/classfile/fieldLayoutBuilder.cpp" , 391, "assert(" "slot->offset() % block->alignment() == 0" ") failed", "Incompatible alignment"); ::breakpoint(); } } while (0); | ||||
| 392 | block->set_offset(slot->offset()); | ||||
| 393 | slot->set_offset(slot->offset() + block->size()); | ||||
| 394 | assert((slot->size() - block->size()) < slot->size(), "underflow checking")do { if (!((slot->size() - block->size()) < slot-> size())) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/classfile/fieldLayoutBuilder.cpp" , 394, "assert(" "(slot->size() - block->size()) < slot->size()" ") failed", "underflow checking"); ::breakpoint(); } } while (0); | ||||
| 395 | assert(slot->size() - block->size() >= 0, "no negative size allowed")do { if (!(slot->size() - block->size() >= 0)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/classfile/fieldLayoutBuilder.cpp" , 395, "assert(" "slot->size() - block->size() >= 0" ") failed", "no negative size allowed"); ::breakpoint(); } } while (0); | ||||
| 396 | slot->set_size(slot->size() - block->size()); | ||||
| 397 | block->set_prev_block(slot->prev_block()); | ||||
| 398 | block->set_next_block(slot); | ||||
| 399 | slot->set_prev_block(block); | ||||
| 400 | if (block->prev_block() != NULL__null) { | ||||
| 401 | block->prev_block()->set_next_block(block); | ||||
| 402 | } | ||||
| 403 | if (_blocks == slot) { | ||||
| 404 | _blocks = block; | ||||
| 405 | } | ||||
| 406 | return block; | ||||
| 407 | } | ||||
| 408 | |||||
| 409 | void FieldLayout::remove(LayoutRawBlock* block) { | ||||
| 410 | assert(block != NULL, "Sanity check")do { if (!(block != __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/classfile/fieldLayoutBuilder.cpp" , 410, "assert(" "block != __null" ") failed", "Sanity check" ); ::breakpoint(); } } while (0); | ||||
| 411 | assert(block != _last, "Sanity check")do { if (!(block != _last)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/classfile/fieldLayoutBuilder.cpp" , 411, "assert(" "block != _last" ") failed", "Sanity check") ; ::breakpoint(); } } while (0); | ||||
| 412 | if (_blocks == block) { | ||||
| 413 | _blocks = block->next_block(); | ||||
| 414 | if (_blocks != NULL__null) { | ||||
| 415 | _blocks->set_prev_block(NULL__null); | ||||
| 416 | } | ||||
| 417 | } else { | ||||
| 418 | assert(block->prev_block() != NULL, "_prev should be set for non-head blocks")do { if (!(block->prev_block() != __null)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/classfile/fieldLayoutBuilder.cpp" , 418, "assert(" "block->prev_block() != __null" ") failed" , "_prev should be set for non-head blocks"); ::breakpoint(); } } while (0); | ||||
| 419 | block->prev_block()->set_next_block(block->next_block()); | ||||
| 420 | block->next_block()->set_prev_block(block->prev_block()); | ||||
| 421 | } | ||||
| 422 | if (block == _start) { | ||||
| 423 | _start = block->prev_block(); | ||||
| 424 | } | ||||
| 425 | } | ||||
| 426 | |||||
| 427 | void FieldLayout::print(outputStream* output, bool is_static, const InstanceKlass* super) { | ||||
| 428 | ResourceMark rm; | ||||
| 429 | LayoutRawBlock* b = _blocks; | ||||
| 430 | while(b != _last) { | ||||
| 431 | switch(b->kind()) { | ||||
| 432 | case LayoutRawBlock::REGULAR: { | ||||
| 433 | FieldInfo* fi = FieldInfo::from_field_array(_fields, b->field_index()); | ||||
| 434 | output->print_cr(" @%d \"%s\" %s %d/%d %s", | ||||
| 435 | b->offset(), | ||||
| 436 | fi->name(_cp)->as_C_string(), | ||||
| 437 | fi->signature(_cp)->as_C_string(), | ||||
| 438 | b->size(), | ||||
| 439 | b->alignment(), | ||||
| 440 | "REGULAR"); | ||||
| 441 | break; | ||||
| 442 | } | ||||
| 443 | case LayoutRawBlock::FLATTENED: { | ||||
| 444 | FieldInfo* fi = FieldInfo::from_field_array(_fields, b->field_index()); | ||||
| 445 | output->print_cr(" @%d \"%s\" %s %d/%d %s", | ||||
| 446 | b->offset(), | ||||
| 447 | fi->name(_cp)->as_C_string(), | ||||
| 448 | fi->signature(_cp)->as_C_string(), | ||||
| 449 | b->size(), | ||||
| 450 | b->alignment(), | ||||
| 451 | "FLATTENED"); | ||||
| 452 | break; | ||||
| 453 | } | ||||
| 454 | case LayoutRawBlock::RESERVED: { | ||||
| 455 | output->print_cr(" @%d %d/- %s", | ||||
| 456 | b->offset(), | ||||
| 457 | b->size(), | ||||
| 458 | "RESERVED"); | ||||
| 459 | break; | ||||
| 460 | } | ||||
| 461 | case LayoutRawBlock::INHERITED: { | ||||
| 462 | assert(!is_static, "Static fields are not inherited in layouts")do { if (!(!is_static)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/classfile/fieldLayoutBuilder.cpp" , 462, "assert(" "!is_static" ") failed", "Static fields are not inherited in layouts" ); ::breakpoint(); } } while (0); | ||||
| 463 | assert(super != NULL, "super klass must be provided to retrieve inherited fields info")do { if (!(super != __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/classfile/fieldLayoutBuilder.cpp" , 463, "assert(" "super != __null" ") failed", "super klass must be provided to retrieve inherited fields info" ); ::breakpoint(); } } while (0); | ||||
| 464 | bool found = false; | ||||
| 465 | const InstanceKlass* ik = super; | ||||
| 466 | while (!found && ik != NULL__null) { | ||||
| 467 | for (AllFieldStream fs(ik->fields(), ik->constants()); !fs.done(); fs.next()) { | ||||
| 468 | if (fs.offset() == b->offset()) { | ||||
| 469 | output->print_cr(" @%d \"%s\" %s %d/%d %s", | ||||
| 470 | b->offset(), | ||||
| 471 | fs.name()->as_C_string(), | ||||
| 472 | fs.signature()->as_C_string(), | ||||
| 473 | b->size(), | ||||
| 474 | b->size(), // so far, alignment constraint == size, will change with Valhalla | ||||
| 475 | "INHERITED"); | ||||
| 476 | found = true; | ||||
| 477 | break; | ||||
| 478 | } | ||||
| 479 | } | ||||
| 480 | ik = ik->java_super(); | ||||
| 481 | } | ||||
| 482 | break; | ||||
| 483 | } | ||||
| 484 | case LayoutRawBlock::EMPTY: | ||||
| 485 | output->print_cr(" @%d %d/1 %s", | ||||
| 486 | b->offset(), | ||||
| 487 | b->size(), | ||||
| 488 | "EMPTY"); | ||||
| 489 | break; | ||||
| 490 | case LayoutRawBlock::PADDING: | ||||
| 491 | output->print_cr(" @%d %d/1 %s", | ||||
| 492 | b->offset(), | ||||
| 493 | b->size(), | ||||
| 494 | "PADDING"); | ||||
| 495 | break; | ||||
| 496 | } | ||||
| 497 | b = b->next_block(); | ||||
| 498 | } | ||||
| 499 | } | ||||
| 500 | |||||
| 501 | FieldLayoutBuilder::FieldLayoutBuilder(const Symbol* classname, const InstanceKlass* super_klass, ConstantPool* constant_pool, | ||||
| 502 | Array<u2>* fields, bool is_contended, FieldLayoutInfo* info) : | ||||
| 503 | _classname(classname), | ||||
| 504 | _super_klass(super_klass), | ||||
| 505 | _constant_pool(constant_pool), | ||||
| 506 | _fields(fields), | ||||
| 507 | _info(info), | ||||
| 508 | _root_group(NULL__null), | ||||
| 509 | _contended_groups(GrowableArray<FieldGroup*>(8)), | ||||
| 510 | _static_fields(NULL__null), | ||||
| 511 | _layout(NULL__null), | ||||
| 512 | _static_layout(NULL__null), | ||||
| 513 | _nonstatic_oopmap_count(0), | ||||
| 514 | _alignment(-1), | ||||
| 515 | _has_nonstatic_fields(false), | ||||
| 516 | _is_contended(is_contended) {} | ||||
| 517 | |||||
| 518 | |||||
| 519 | FieldGroup* FieldLayoutBuilder::get_or_create_contended_group(int g) { | ||||
| 520 | assert(g > 0, "must only be called for named contended groups")do { if (!(g > 0)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/classfile/fieldLayoutBuilder.cpp" , 520, "assert(" "g > 0" ") failed", "must only be called for named contended groups" ); ::breakpoint(); } } while (0); | ||||
| 521 | FieldGroup* fg = NULL__null; | ||||
| 522 | for (int i = 0; i < _contended_groups.length(); i++) { | ||||
| 523 | fg = _contended_groups.at(i); | ||||
| 524 | if (fg->contended_group() == g) return fg; | ||||
| 525 | } | ||||
| 526 | fg = new FieldGroup(g); | ||||
| 527 | _contended_groups.append(fg); | ||||
| 528 | return fg; | ||||
| 529 | } | ||||
| 530 | |||||
| 531 | void FieldLayoutBuilder::prologue() { | ||||
| 532 | _layout = new FieldLayout(_fields, _constant_pool); | ||||
| 533 | const InstanceKlass* super_klass = _super_klass; | ||||
| 534 | _layout->initialize_instance_layout(super_klass); | ||||
| 535 | if (super_klass != NULL__null) { | ||||
| 536 | _has_nonstatic_fields = super_klass->has_nonstatic_fields(); | ||||
| 537 | } | ||||
| 538 | _static_layout = new FieldLayout(_fields, _constant_pool); | ||||
| 539 | _static_layout->initialize_static_layout(); | ||||
| 540 | _static_fields = new FieldGroup(); | ||||
| 541 | _root_group = new FieldGroup(); | ||||
| 542 | } | ||||
| 543 | |||||
| 544 | // Field sorting for regular classes: | ||||
| 545 | // - fields are sorted in static and non-static fields | ||||
| 546 | // - non-static fields are also sorted according to their contention group | ||||
| 547 | // (support of the @Contended annotation) | ||||
| 548 | // - @Contended annotation is ignored for static fields | ||||
| 549 | void FieldLayoutBuilder::regular_field_sorting() { | ||||
| 550 | for (AllFieldStream fs(_fields, _constant_pool); !fs.done(); fs.next()) { | ||||
| 551 | FieldGroup* group = NULL__null; | ||||
| 552 | if (fs.access_flags().is_static()) { | ||||
| 553 | group = _static_fields; | ||||
| 554 | } else { | ||||
| 555 | _has_nonstatic_fields = true; | ||||
| 556 | if (fs.is_contended()) { | ||||
| 557 | int g = fs.contended_group(); | ||||
| 558 | if (g == 0) { | ||||
| 559 | group = new FieldGroup(true); | ||||
| 560 | _contended_groups.append(group); | ||||
| 561 | } else { | ||||
| 562 | group = get_or_create_contended_group(g); | ||||
| 563 | } | ||||
| 564 | } else { | ||||
| 565 | group = _root_group; | ||||
| 566 | } | ||||
| 567 | } | ||||
| 568 | assert(group != NULL, "invariant")do { if (!(group != __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/classfile/fieldLayoutBuilder.cpp" , 568, "assert(" "group != __null" ") failed", "invariant"); :: breakpoint(); } } while (0); | ||||
| 569 | BasicType type = Signature::basic_type(fs.signature()); | ||||
| 570 | switch(type) { | ||||
| 571 | case T_BYTE: | ||||
| 572 | case T_CHAR: | ||||
| 573 | case T_DOUBLE: | ||||
| 574 | case T_FLOAT: | ||||
| 575 | case T_INT: | ||||
| 576 | case T_LONG: | ||||
| 577 | case T_SHORT: | ||||
| 578 | case T_BOOLEAN: | ||||
| 579 | group->add_primitive_field(fs, type); | ||||
| 580 | break; | ||||
| 581 | case T_OBJECT: | ||||
| 582 | case T_ARRAY: | ||||
| 583 | if (group != _static_fields) _nonstatic_oopmap_count++; | ||||
| 584 | group->add_oop_field(fs); | ||||
| 585 | break; | ||||
| 586 | default: | ||||
| 587 | fatal("Something wrong?")do { (*g_assert_poison) = 'X';; report_fatal(INTERNAL_ERROR, "/home/daniel/Projects/java/jdk/src/hotspot/share/classfile/fieldLayoutBuilder.cpp" , 587, "Something wrong?"); ::breakpoint(); } while (0); | ||||
| 588 | } | ||||
| 589 | } | ||||
| 590 | _root_group->sort_by_size(); | ||||
| 591 | _static_fields->sort_by_size(); | ||||
| 592 | if (!_contended_groups.is_empty()) { | ||||
| 593 | for (int i = 0; i < _contended_groups.length(); i++) { | ||||
| 594 | _contended_groups.at(i)->sort_by_size(); | ||||
| 595 | } | ||||
| 596 | } | ||||
| 597 | } | ||||
| 598 | |||||
| 599 | void FieldLayoutBuilder::insert_contended_padding(LayoutRawBlock* slot) { | ||||
| 600 | if (ContendedPaddingWidth > 0) { | ||||
| 601 | LayoutRawBlock* padding = new LayoutRawBlock(LayoutRawBlock::PADDING, ContendedPaddingWidth); | ||||
| 602 | _layout->insert(slot, padding); | ||||
| 603 | } | ||||
| 604 | } | ||||
| 605 | |||||
| 606 | // Computation of regular classes layout is an evolution of the previous default layout | ||||
| 607 | // (FieldAllocationStyle 1): | ||||
| 608 | // - primitive fields are allocated first (from the biggest to the smallest) | ||||
| 609 | // - then oop fields are allocated, either in existing gaps or at the end of | ||||
| 610 | // the layout | ||||
| 611 | void FieldLayoutBuilder::compute_regular_layout() { | ||||
| 612 | bool need_tail_padding = false; | ||||
| 613 | prologue(); | ||||
| 614 | regular_field_sorting(); | ||||
| 615 | |||||
| 616 | if (_is_contended) { | ||||
| 617 | _layout->set_start(_layout->last_block()); | ||||
| 618 | // insertion is currently easy because the current strategy doesn't try to fill holes | ||||
| 619 | // in super classes layouts => the _start block is by consequence the _last_block | ||||
| 620 | insert_contended_padding(_layout->start()); | ||||
| 621 | need_tail_padding = true; | ||||
| 622 | } | ||||
| 623 | _layout->add(_root_group->primitive_fields()); | ||||
| 624 | _layout->add(_root_group->oop_fields()); | ||||
| 625 | |||||
| 626 | if (!_contended_groups.is_empty()) { | ||||
| 627 | for (int i = 0; i < _contended_groups.length(); i++) { | ||||
| 628 | FieldGroup* cg = _contended_groups.at(i); | ||||
| 629 | LayoutRawBlock* start = _layout->last_block(); | ||||
| 630 | insert_contended_padding(start); | ||||
| 631 | _layout->add(cg->primitive_fields(), start); | ||||
| 632 | _layout->add(cg->oop_fields(), start); | ||||
| 633 | need_tail_padding = true; | ||||
| 634 | } | ||||
| 635 | } | ||||
| 636 | |||||
| 637 | if (need_tail_padding) { | ||||
| 638 | insert_contended_padding(_layout->last_block()); | ||||
| 639 | } | ||||
| 640 | |||||
| 641 | _static_layout->add_contiguously(this->_static_fields->oop_fields()); | ||||
| 642 | _static_layout->add(this->_static_fields->primitive_fields()); | ||||
| 643 | |||||
| 644 | epilogue(); | ||||
| 645 | } | ||||
| 646 | |||||
| 647 | void FieldLayoutBuilder::epilogue() { | ||||
| 648 | // Computing oopmaps | ||||
| 649 | int super_oop_map_count = (_super_klass == NULL__null) ? 0 :_super_klass->nonstatic_oop_map_count(); | ||||
| 650 | int max_oop_map_count = super_oop_map_count + _nonstatic_oopmap_count; | ||||
| 651 | |||||
| 652 | OopMapBlocksBuilder* nonstatic_oop_maps = | ||||
| 653 | new OopMapBlocksBuilder(max_oop_map_count); | ||||
| 654 | if (super_oop_map_count > 0) { | ||||
| 655 | nonstatic_oop_maps->initialize_inherited_blocks(_super_klass->start_of_nonstatic_oop_maps(), | ||||
| 656 | _super_klass->nonstatic_oop_map_count()); | ||||
| 657 | } | ||||
| 658 | |||||
| 659 | if (_root_group->oop_fields() != NULL__null) { | ||||
| 660 | for (int i = 0; i < _root_group->oop_fields()->length(); i++) { | ||||
| 661 | LayoutRawBlock* b = _root_group->oop_fields()->at(i); | ||||
| 662 | nonstatic_oop_maps->add(b->offset(), 1); | ||||
| 663 | } | ||||
| 664 | } | ||||
| 665 | |||||
| 666 | if (!_contended_groups.is_empty()) { | ||||
| 667 | for (int i = 0; i < _contended_groups.length(); i++) { | ||||
| 668 | FieldGroup* cg = _contended_groups.at(i); | ||||
| 669 | if (cg->oop_count() > 0) { | ||||
| 670 | assert(cg->oop_fields() != NULL && cg->oop_fields()->at(0) != NULL, "oop_count > 0 but no oop fields found")do { if (!(cg->oop_fields() != __null && cg->oop_fields ()->at(0) != __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/classfile/fieldLayoutBuilder.cpp" , 670, "assert(" "cg->oop_fields() != __null && cg->oop_fields()->at(0) != __null" ") failed", "oop_count > 0 but no oop fields found"); ::breakpoint (); } } while (0); | ||||
| 671 | nonstatic_oop_maps->add(cg->oop_fields()->at(0)->offset(), cg->oop_count()); | ||||
| 672 | } | ||||
| 673 | } | ||||
| 674 | } | ||||
| 675 | |||||
| 676 | nonstatic_oop_maps->compact(); | ||||
| 677 | |||||
| 678 | int instance_end = align_up(_layout->last_block()->offset(), wordSize); | ||||
| 679 | int static_fields_end = align_up(_static_layout->last_block()->offset(), wordSize); | ||||
| 680 | int static_fields_size = (static_fields_end - | ||||
| 681 | InstanceMirrorKlass::offset_of_static_fields()) / wordSize; | ||||
| 682 | int nonstatic_field_end = align_up(_layout->last_block()->offset(), heapOopSize); | ||||
| 683 | |||||
| 684 | // Pass back information needed for InstanceKlass creation | ||||
| 685 | |||||
| 686 | _info->oop_map_blocks = nonstatic_oop_maps; | ||||
| 687 | _info->_instance_size = align_object_size(instance_end / wordSize); | ||||
| 688 | _info->_static_field_size = static_fields_size; | ||||
| 689 | _info->_nonstatic_field_size = (nonstatic_field_end - instanceOopDesc::base_offset_in_bytes()) / heapOopSize; | ||||
| 690 | _info->_has_nonstatic_fields = _has_nonstatic_fields; | ||||
| 691 | |||||
| 692 | if (PrintFieldLayout) { | ||||
| 693 | ResourceMark rm; | ||||
| 694 | tty->print_cr("Layout of class %s", _classname->as_C_string()); | ||||
| 695 | tty->print_cr("Instance fields:"); | ||||
| 696 | _layout->print(tty, false, _super_klass); | ||||
| 697 | tty->print_cr("Static fields:"); | ||||
| 698 | _static_layout->print(tty, true, NULL__null); | ||||
| 699 | tty->print_cr("Instance size = %d bytes", _info->_instance_size * wordSize); | ||||
| 700 | tty->print_cr("---"); | ||||
| 701 | } | ||||
| 702 | } | ||||
| 703 | |||||
| 704 | void FieldLayoutBuilder::build_layout() { | ||||
| 705 | compute_regular_layout(); | ||||
| |||||
| 706 | } |
| 1 | /* |
| 2 | * Copyright (c) 2020, 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 | |
| 37 | // A LayoutRawBlock describes an element of a layout. |
| 38 | // Each field is represented by a LayoutRawBlock. |
| 39 | // LayoutRawBlocks can also represent elements injected by the JVM: |
| 40 | // padding, empty blocks, inherited fields, etc. |
| 41 | // All LayoutRawBlocks must have a size and an alignment. The size is the |
| 42 | // exact size of the field expressed in bytes. The alignment is |
| 43 | // the alignment constraint of the field (1 for byte, 2 for short, |
| 44 | // 4 for int, 8 for long, etc.) |
| 45 | // |
| 46 | // LayoutRawBlock are designed to be used in two data structures: |
| 47 | // - a linked list in a layout (using _next_block, _prev_block) |
| 48 | // - a GrowableArray in field group (the growable array contains pointers to LayoutRawBlocks) |
| 49 | // |
| 50 | // next/prev pointers are included in the LayoutRawBlock class to narrow |
| 51 | // the number of allocation required during the computation of a layout. |
| 52 | // |
| 53 | class LayoutRawBlock : public ResourceObj { |
| 54 | public: |
| 55 | // Some code relies on the order of values below. |
| 56 | enum Kind { |
| 57 | EMPTY, // empty slot, space is taken from this to allocate fields |
| 58 | RESERVED, // reserved for JVM usage (for instance object header) |
| 59 | PADDING, // padding (because of alignment constraints or @Contended) |
| 60 | REGULAR, // primitive or oop field (including non-flattened inline fields) |
| 61 | FLATTENED, // flattened field |
| 62 | INHERITED // field(s) inherited from super classes |
| 63 | }; |
| 64 | |
| 65 | private: |
| 66 | LayoutRawBlock* _next_block; |
| 67 | LayoutRawBlock* _prev_block; |
| 68 | Kind _kind; |
| 69 | int _offset; |
| 70 | int _alignment; |
| 71 | int _size; |
| 72 | int _field_index; |
| 73 | bool _is_reference; |
| 74 | |
| 75 | public: |
| 76 | LayoutRawBlock(Kind kind, int size); |
| 77 | LayoutRawBlock(int index, Kind kind, int size, int alignment, bool is_reference = false); |
| 78 | LayoutRawBlock* next_block() const { return _next_block; } |
| 79 | void set_next_block(LayoutRawBlock* next) { _next_block = next; } |
| 80 | LayoutRawBlock* prev_block() const { return _prev_block; } |
| 81 | void set_prev_block(LayoutRawBlock* prev) { _prev_block = prev; } |
| 82 | Kind kind() const { return _kind; } |
| 83 | int offset() const { |
| 84 | assert(_offset >= 0, "Must be initialized")do { if (!(_offset >= 0)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/classfile/fieldLayoutBuilder.hpp" , 84, "assert(" "_offset >= 0" ") failed", "Must be initialized" ); ::breakpoint(); } } while (0); |
| 85 | return _offset; |
| 86 | } |
| 87 | void set_offset(int offset) { _offset = offset; } |
| 88 | int alignment() const { return _alignment; } |
| 89 | int size() const { return _size; } |
| 90 | void set_size(int size) { _size = size; } |
| 91 | int field_index() const { |
| 92 | assert(_field_index != -1, "Must be initialized")do { if (!(_field_index != -1)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/classfile/fieldLayoutBuilder.hpp" , 92, "assert(" "_field_index != -1" ") failed", "Must be initialized" ); ::breakpoint(); } } while (0); |
| 93 | return _field_index; |
| 94 | } |
| 95 | bool is_reference() const { return _is_reference; } |
| 96 | |
| 97 | bool fit(int size, int alignment); |
| 98 | |
| 99 | static int compare_offset(LayoutRawBlock** x, LayoutRawBlock** y) { return (*x)->offset() - (*y)->offset(); } |
| 100 | // compare_size_inverted() returns the opposite of a regular compare method in order to |
| 101 | // sort fields in decreasing order. |
| 102 | // Note: with line types, the comparison should include alignment constraint if sizes are equals |
| 103 | static int compare_size_inverted(LayoutRawBlock** x, LayoutRawBlock** y) { |
| 104 | #ifdef _WINDOWS |
| 105 | // qsort() on Windows reverse the order of fields with the same size |
| 106 | // the extension of the comparison function below preserves this order |
| 107 | int diff = (*y)->size() - (*x)->size(); |
| 108 | if (diff == 0) { |
| 109 | diff = (*x)->field_index() - (*y)->field_index(); |
| 110 | } |
| 111 | return diff; |
| 112 | #else |
| 113 | return (*y)->size() - (*x)->size(); |
| 114 | #endif // _WINDOWS |
| 115 | } |
| 116 | |
| 117 | }; |
| 118 | |
| 119 | // A Field group represents a set of fields that have to be allocated together, |
| 120 | // this is the way the @Contended annotation is supported. |
| 121 | // Inside a FieldGroup, fields are sorted based on their kind: primitive, |
| 122 | // oop, or flattened. |
| 123 | // |
| 124 | class FieldGroup : public ResourceObj { |
| 125 | |
| 126 | private: |
| 127 | FieldGroup* _next; |
| 128 | GrowableArray<LayoutRawBlock*>* _primitive_fields; |
| 129 | GrowableArray<LayoutRawBlock*>* _oop_fields; |
| 130 | int _contended_group; |
| 131 | int _oop_count; |
| 132 | static const int INITIAL_LIST_SIZE = 16; |
| 133 | |
| 134 | public: |
| 135 | FieldGroup(int contended_group = -1); |
| 136 | |
| 137 | FieldGroup* next() const { return _next; } |
| 138 | void set_next(FieldGroup* next) { _next = next; } |
| 139 | GrowableArray<LayoutRawBlock*>* primitive_fields() const { return _primitive_fields; } |
| 140 | GrowableArray<LayoutRawBlock*>* oop_fields() const { return _oop_fields; } |
| 141 | int contended_group() const { return _contended_group; } |
| 142 | int oop_count() const { return _oop_count; } |
| 143 | |
| 144 | void add_primitive_field(AllFieldStream fs, BasicType type); |
| 145 | void add_oop_field(AllFieldStream fs); |
| 146 | void sort_by_size(); |
| 147 | }; |
| 148 | |
| 149 | // The FieldLayout class represents a set of fields organized |
| 150 | // in a layout. |
| 151 | // An instance of FieldLayout can either represent the layout |
| 152 | // of non-static fields (used in an instance object) or the |
| 153 | // layout of static fields (to be included in the class mirror). |
| 154 | // |
| 155 | // _block is a pointer to a list of LayoutRawBlock ordered by increasing |
| 156 | // offsets. |
| 157 | // _start points to the LayoutRawBlock with the first offset that can |
| 158 | // be used to allocate fields of the current class |
| 159 | // _last points to the last LayoutRawBlock of the list. In order to |
| 160 | // simplify the code, the LayoutRawBlock list always ends with an |
| 161 | // EMPTY block (the kind of LayoutRawBlock from which space is taken |
| 162 | // to allocate fields) with a size big enough to satisfy all |
| 163 | // field allocations. |
| 164 | // |
| 165 | class FieldLayout : public ResourceObj { |
| 166 | private: |
| 167 | Array<u2>* _fields; |
| 168 | ConstantPool* _cp; |
| 169 | LayoutRawBlock* _blocks; // the layout being computed |
| 170 | LayoutRawBlock* _start; // points to the first block where a field can be inserted |
| 171 | LayoutRawBlock* _last; // points to the last block of the layout (big empty block) |
| 172 | |
| 173 | public: |
| 174 | FieldLayout(Array<u2>* fields, ConstantPool* cp); |
| 175 | void initialize_static_layout(); |
| 176 | void initialize_instance_layout(const InstanceKlass* ik); |
| 177 | |
| 178 | LayoutRawBlock* first_empty_block() { |
| 179 | LayoutRawBlock* block = _start; |
| 180 | while (block->kind() != LayoutRawBlock::EMPTY) { |
| 181 | block = block->next_block(); |
| 182 | } |
| 183 | return block; |
| 184 | } |
| 185 | |
| 186 | LayoutRawBlock* start() { return _start; } |
| 187 | void set_start(LayoutRawBlock* start) { _start = start; } |
| 188 | LayoutRawBlock* last_block() { return _last; } |
| 189 | |
| 190 | LayoutRawBlock* first_field_block(); |
| 191 | void add(GrowableArray<LayoutRawBlock*>* list, LayoutRawBlock* start = NULL__null); |
| 192 | void add_field_at_offset(LayoutRawBlock* blocks, int offset, LayoutRawBlock* start = NULL__null); |
| 193 | void add_contiguously(GrowableArray<LayoutRawBlock*>* list, LayoutRawBlock* start = NULL__null); |
| 194 | LayoutRawBlock* insert_field_block(LayoutRawBlock* slot, LayoutRawBlock* block); |
| 195 | bool reconstruct_layout(const InstanceKlass* ik); |
| 196 | void fill_holes(const InstanceKlass* ik); |
| 197 | LayoutRawBlock* insert(LayoutRawBlock* slot, LayoutRawBlock* block); |
| 198 | void remove(LayoutRawBlock* block); |
| 199 | void print(outputStream* output, bool is_static, const InstanceKlass* super); |
| 200 | }; |
| 201 | |
| 202 | |
| 203 | // FieldLayoutBuilder is the main entry point for layout computation. |
| 204 | // This class has three methods to generate layout: one for regular classes |
| 205 | // and two for classes with hard coded offsets (java,lang.ref.Reference |
| 206 | // and the boxing classes). The rationale for having multiple methods |
| 207 | // is that each kind of class has a different set goals regarding |
| 208 | // its layout, so instead of mixing several layout strategies into a |
| 209 | // single method, each kind has its own method (see comments below |
| 210 | // for more details about the allocation strategies). |
| 211 | // |
| 212 | // Computing the layout of a class always goes through 4 steps: |
| 213 | // 1 - Prologue: preparation of data structure and gathering of |
| 214 | // layout information inherited from super classes |
| 215 | // 2 - Field sorting: fields are sorted according to their |
| 216 | // kind (oop, primitive, inline class) and their contention |
| 217 | // annotation (if any) |
| 218 | // 3 - Layout is computed from the set of lists generated during |
| 219 | // step 2 |
| 220 | // 4 - Epilogue: oopmaps are generated, layout information is |
| 221 | // prepared so other VM components can use it (instance size, |
| 222 | // static field size, non-static field size, etc.) |
| 223 | // |
| 224 | // Steps 1 and 4 are common to all layout computations. Step 2 and 3 |
| 225 | // can vary with the allocation strategy. |
| 226 | // |
| 227 | class FieldLayoutBuilder : public ResourceObj { |
| 228 | private: |
| 229 | |
| 230 | const Symbol* _classname; |
| 231 | const InstanceKlass* _super_klass; |
| 232 | ConstantPool* _constant_pool; |
| 233 | Array<u2>* _fields; |
| 234 | FieldLayoutInfo* _info; |
| 235 | FieldGroup* _root_group; |
| 236 | GrowableArray<FieldGroup*> _contended_groups; |
| 237 | FieldGroup* _static_fields; |
| 238 | FieldLayout* _layout; |
| 239 | FieldLayout* _static_layout; |
| 240 | int _nonstatic_oopmap_count; |
| 241 | int _alignment; |
| 242 | bool _has_nonstatic_fields; |
| 243 | bool _is_contended; // is a contended class? |
| 244 | |
| 245 | public: |
| 246 | FieldLayoutBuilder(const Symbol* classname, const InstanceKlass* super_klass, ConstantPool* constant_pool, |
| 247 | Array<u2>* fields, bool is_contended, FieldLayoutInfo* info); |
| 248 | |
| 249 | int get_alignment() { |
| 250 | assert(_alignment != -1, "Uninitialized")do { if (!(_alignment != -1)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/classfile/fieldLayoutBuilder.hpp" , 250, "assert(" "_alignment != -1" ") failed", "Uninitialized" ); ::breakpoint(); } } while (0); |
| 251 | return _alignment; |
| 252 | } |
| 253 | |
| 254 | void build_layout(); |
| 255 | void compute_regular_layout(); |
| 256 | void insert_contended_padding(LayoutRawBlock* slot); |
| 257 | |
| 258 | private: |
| 259 | void prologue(); |
| 260 | void epilogue(); |
| 261 | void regular_field_sorting(); |
| 262 | FieldGroup* get_or_create_contended_group(int g); |
| 263 | }; |
| 264 | |
| 265 | #endif // SHARE_CLASSFILE_FIELDLAYOUTBUILDER_HPP |