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 |