Skip to content

Commit 8f0e624

Browse files
Quan Anh MaiTobiHartmann
authored andcommitted
8356963: [lworld] MemNode::optimize_simple_memory_chain fails with "sanity check for basic cases"
Reviewed-by: thartmann
1 parent 7739c43 commit 8f0e624

20 files changed

+178
-120
lines changed

src/hotspot/share/ci/ciField.cpp

Lines changed: 55 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -22,19 +22,24 @@
2222
*
2323
*/
2424

25+
#include "ci/ciConstant.hpp"
2526
#include "ci/ciField.hpp"
27+
#include "ci/ciInlineKlass.hpp"
2628
#include "ci/ciInstanceKlass.hpp"
29+
#include "ci/ciSymbol.hpp"
2730
#include "ci/ciSymbols.hpp"
2831
#include "ci/ciUtilities.inline.hpp"
2932
#include "classfile/javaClasses.hpp"
3033
#include "classfile/vmClasses.hpp"
3134
#include "gc/shared/collectedHeap.inline.hpp"
3235
#include "interpreter/linkResolver.hpp"
36+
#include "jvm_io.h"
3337
#include "oops/klass.inline.hpp"
3438
#include "oops/oop.inline.hpp"
3539
#include "runtime/fieldDescriptor.inline.hpp"
3640
#include "runtime/handles.inline.hpp"
3741
#include "runtime/reflection.hpp"
42+
#include "utilities/globalDefinitions.hpp"
3843

3944
// ciField
4045
//
@@ -218,28 +223,57 @@ ciField::ciField(fieldDescriptor *fd) :
218223

219224
// Special copy constructor used to flatten inline type fields by
220225
// copying the fields of the inline type to a new holder klass.
221-
ciField::ciField(ciField* field, ciInstanceKlass* holder, int offset, bool is_final) {
222-
assert(field->holder()->is_inlinetype() || field->holder()->is_abstract(), "should only be used for inline type field flattening");
223-
// Set the is_final flag
224-
jint final = is_final ? JVM_ACC_FINAL : ~JVM_ACC_FINAL;
225-
AccessFlags flags(field->flags().as_int() & final);
226-
_flags = ciFlags(flags);
227-
_holder = holder;
228-
_offset = offset;
229-
// Copy remaining fields
230-
_name = field->_name;
231-
_signature = field->_signature;
232-
_type = field->_type;
233-
// Trust final flat fields
234-
_is_constant = is_final;
235-
_known_to_link_with_put = field->_known_to_link_with_put;
236-
_known_to_link_with_get = field->_known_to_link_with_get;
237-
_constant_value = field->_constant_value;
238-
assert(!field->is_flat(), "field must not be flat");
226+
ciField::ciField(ciField* declared_field, ciField* subfield) {
227+
assert(subfield->holder()->is_inlinetype() || subfield->holder()->is_abstract(), "should only be used for inline type field flattening");
228+
assert(!subfield->is_flat(), "subfield must not be flat");
229+
assert(declared_field->is_flat(), "declared field must be flat");
230+
231+
_flags = declared_field->flags();
232+
_holder = declared_field->holder();
233+
_offset = declared_field->offset_in_bytes() + (subfield->offset_in_bytes() - declared_field->type()->as_inline_klass()->payload_offset());
234+
235+
char buffer[256];
236+
jio_snprintf(buffer, sizeof(buffer), "%s.%s", declared_field->name()->as_utf8(), subfield->name()->as_utf8());
237+
_name = ciSymbol::make(buffer);
238+
239+
_signature = subfield->_signature;
240+
_type = subfield->_type;
241+
_is_constant = false;
242+
_known_to_link_with_put = subfield->_known_to_link_with_put;
243+
_known_to_link_with_get = subfield->_known_to_link_with_get;
244+
_constant_value = ciConstant();
245+
246+
_is_flat = false;
247+
_is_null_free = false;
248+
_null_marker_offset = -1;
249+
_original_holder = (subfield->_original_holder != nullptr) ? subfield->_original_holder : subfield->_holder;
250+
}
251+
252+
// Constructor for the ciField of a null marker
253+
ciField::ciField(ciField* declared_field) {
254+
assert(declared_field->is_flat(), "declared field must be flat");
255+
assert(!declared_field->is_null_free(), "must have a null marker");
256+
257+
_flags = declared_field->flags();
258+
_holder = declared_field->holder();
259+
_offset = declared_field->null_marker_offset();
260+
261+
char buffer[256];
262+
jio_snprintf(buffer, sizeof(buffer), "%s.$nullMarker$", declared_field->name()->as_utf8());
263+
_name = ciSymbol::make(buffer);
264+
265+
_signature = ciSymbols::bool_signature();
266+
_type = ciType::make(T_BOOLEAN);
267+
268+
_is_constant = false;
269+
_known_to_link_with_put = nullptr;
270+
_known_to_link_with_get = nullptr;
271+
_constant_value = ciConstant();
272+
239273
_is_flat = false;
240-
_is_null_free = field->_is_null_free;
241-
_null_marker_offset = field->_null_marker_offset;
242-
_original_holder = (field->_original_holder != nullptr) ? field->_original_holder : field->_holder;
274+
_is_null_free = false;
275+
_null_marker_offset = -1;
276+
_original_holder = nullptr;
243277
}
244278

245279
static bool trust_final_non_static_fields(ciInstanceKlass* holder) {

src/hotspot/share/ci/ciField.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,8 @@ class ciField : public ArenaObj {
6262

6363
ciField(ciInstanceKlass* klass, int index, Bytecodes::Code bc);
6464
ciField(fieldDescriptor* fd);
65-
ciField(ciField* field, ciInstanceKlass* holder, int offset, bool is_final);
65+
ciField(ciField* declared_field, ciField* sudfield);
66+
ciField(ciField* declared_field);
6667

6768
// shared constructor code
6869
void initialize_from(fieldDescriptor* fd);

src/hotspot/share/ci/ciInstanceKlass.cpp

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -525,6 +525,7 @@ void ciInstanceKlass::compute_nonstatic_fields_impl(const GrowableArray<ciField*
525525
InlineKlass* k = this_klass->get_inline_type_field_klass(fd.index());
526526
ciInlineKlass* vk = CURRENT_ENV->get_klass(k)->as_inline_klass();
527527
field_num += vk->nof_nonstatic_fields();
528+
field_num += fd.has_null_marker() ? 1 : 0;
528529
} else {
529530
field_num++;
530531
}
@@ -563,15 +564,12 @@ void ciInstanceKlass::compute_nonstatic_fields_impl(const GrowableArray<ciField*
563564
ciInlineKlass* vk = CURRENT_ENV->get_klass(k)->as_inline_klass();
564565
// Iterate over fields of the flat inline type and copy them to 'this'
565566
for (int i = 0; i < vk->nof_nonstatic_fields(); ++i) {
566-
ciField* flat_field = vk->nonstatic_field_at(i);
567-
// Adjust offset to account for missing oop header
568-
int offset = field_offset + (flat_field->offset_in_bytes() - vk->payload_offset());
569-
// A flat field can be treated as final if the non-flat
570-
// field is declared final or the holder klass is an inline type itself.
571-
bool is_final = fd.is_final() || is_inlinetype();
572-
ciField* field = new (arena) ciField(flat_field, this, offset, is_final);
573567
assert(tmp_fields != nullptr, "should be initialized");
574-
tmp_fields->append(field);
568+
tmp_fields->append(new (arena) ciField(declared_field, vk->nonstatic_field_at(i)));
569+
}
570+
if (fd.has_null_marker()) {
571+
assert(tmp_fields != nullptr, "should be initialized");
572+
tmp_fields->append(new (arena) ciField(declared_field));
575573
}
576574
} else {
577575
assert(tmp_fields != nullptr, "should be initialized");

src/hotspot/share/opto/callnode.cpp

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -510,16 +510,9 @@ void JVMState::format(PhaseRegAlloc *regalloc, const Node *n, outputStream* st)
510510
}
511511
}
512512
Node* fld_node = mcall->in(first_ind);
513-
ciField* cifield;
514513
if (iklass != nullptr) {
515514
st->print(" [");
516-
if (0 < (uint)iklass->nof_nonstatic_fields()) {
517-
cifield = iklass->nonstatic_field_at(0);
518-
cifield->print_name_on(st);
519-
} else {
520-
// Must be a null marker
521-
st->print("null marker");
522-
}
515+
iklass->nonstatic_field_at(0)->print_name_on(st);
523516
format_helper(regalloc, st, fld_node, ":", 0, &scobjs);
524517
} else {
525518
format_helper(regalloc, st, fld_node, "[", 0, &scobjs);
@@ -528,13 +521,7 @@ void JVMState::format(PhaseRegAlloc *regalloc, const Node *n, outputStream* st)
528521
fld_node = mcall->in(first_ind+j);
529522
if (iklass != nullptr) {
530523
st->print(", [");
531-
if (j < (uint)iklass->nof_nonstatic_fields()) {
532-
cifield = iklass->nonstatic_field_at(j);
533-
cifield->print_name_on(st);
534-
} else {
535-
// Must be a null marker
536-
st->print("null marker");
537-
}
524+
iklass->nonstatic_field_at(j)->print_name_on(st);
538525
format_helper(regalloc, st, fld_node, ":", j, &scobjs);
539526
} else {
540527
format_helper(regalloc, st, fld_node, ", [", j, &scobjs);

src/hotspot/share/opto/inlinetypenode.cpp

Lines changed: 16 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -195,59 +195,28 @@ Node* InlineTypeNode::field_value(uint index) const {
195195
return in(Values + index);
196196
}
197197

198-
// Get the value of the null marker at the given offset.
199-
Node* InlineTypeNode::null_marker_by_offset(int offset, int holder_offset) const {
200-
// Search through the null markers of all flat fields
201-
for (uint i = 0; i < field_count(); ++i) {
202-
if (field_is_flat(i)) {
203-
InlineTypeNode* value = field_value(i)->as_InlineType();
204-
if (!field_is_null_free(i)) {
205-
int nm_offset = holder_offset + field_null_marker_offset(i);
206-
if (nm_offset == offset) {
207-
return value->get_is_init();
208-
}
209-
}
210-
int flat_holder_offset = holder_offset + field_offset(i) - value->inline_klass()->payload_offset();
211-
Node* nm_value = value->null_marker_by_offset(offset, flat_holder_offset);
212-
if (nm_value != nullptr) {
213-
return nm_value;
214-
}
215-
}
216-
}
217-
return nullptr;
218-
}
219-
220198
// Get the value of the field at the given offset.
221199
// If 'recursive' is true, flat inline type fields will be resolved recursively.
222-
Node* InlineTypeNode::field_value_by_offset(int offset, bool recursive, bool search_null_marker) const {
223-
// First check if we are loading a null marker which is not a real field
224-
if (recursive && search_null_marker) {
225-
Node* value = null_marker_by_offset(offset);
226-
if (value != nullptr){
227-
return value;
228-
}
229-
}
230-
231-
// If the field at 'offset' belongs to a flat inline type field, 'index' refers to the
232-
// corresponding InlineTypeNode input and 'sub_offset' is the offset in the flattened inline type.
200+
Node* InlineTypeNode::field_value_by_offset(int offset, bool recursive) const {
201+
// Find the declared field which contains the field we are looking for
233202
int index = inline_klass()->field_index_by_offset(offset);
234-
int sub_offset = offset - field_offset(index);
235203
Node* value = field_value(index);
236204
assert(value != nullptr, "field value not found");
237-
if (recursive && value->is_InlineType()) {
238-
if (field_is_flat(index)) {
239-
// Flat inline type field
240-
InlineTypeNode* vt = value->as_InlineType();
241-
sub_offset += vt->inline_klass()->payload_offset(); // Add header size
242-
return vt->field_value_by_offset(sub_offset, recursive, false);
243-
} else {
244-
assert(sub_offset == 0, "should not have a sub offset");
245-
return value;
246-
}
205+
206+
if (!recursive || !field_is_flat(index)) {
207+
assert(offset == field_offset(index), "offset mismatch");
208+
return value;
209+
}
210+
211+
// Flat inline type field
212+
InlineTypeNode* vt = value->as_InlineType();
213+
if (offset == field_null_marker_offset(index)) {
214+
return vt->get_is_init();
215+
} else {
216+
int sub_offset = offset - field_offset(index); // Offset of the flattened field inside the declared field
217+
sub_offset += vt->inline_klass()->payload_offset(); // Add header size
218+
return vt->field_value_by_offset(sub_offset, recursive);
247219
}
248-
assert(!(recursive && value->is_InlineType()), "should not be an inline type");
249-
assert(sub_offset == 0, "offset mismatch");
250-
return value;
251220
}
252221

253222
void InlineTypeNode::set_field_value(uint index, Node* value) {

src/hotspot/share/opto/inlinetypenode.hpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,8 +110,7 @@ class InlineTypeNode : public TypeNode {
110110
// Inline type fields
111111
uint field_count() const { return req() - Values; }
112112
Node* field_value(uint index) const;
113-
Node* field_value_by_offset(int offset, bool recursive = false, bool search_null_marker = true) const;
114-
Node* null_marker_by_offset(int offset, int holder_offset = 0) const;
113+
Node* field_value_by_offset(int offset, bool recursive) const;
115114
void set_field_value(uint index, Node* value);
116115
void set_field_value_by_offset(int offset, Node* value);
117116
int field_offset(uint index) const;

src/hotspot/share/opto/memnode.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ static Node* find_call_fallthrough_mem_output(CallNode* call) {
153153
}
154154

155155
// Try to find a better memory input for a load from a strict final field
156-
static Node* try_optimize_strict_final_load_memory(PhaseGVN* phase, ciField* field, Node* adr, ProjNode*& base_local) {
156+
static Node* try_optimize_strict_final_load_memory(PhaseGVN* phase, Node* adr, ProjNode*& base_local) {
157157
intptr_t offset = 0;
158158
Node* base = AddPNode::Ideal_base_and_offset(adr, phase, offset);
159159
if (base == nullptr) {
@@ -246,7 +246,7 @@ Node* MemNode::optimize_simple_memory_chain(Node* mchain, const TypeOopPtr* t_oo
246246
if (is_strict_final_load) {
247247
Node* adr = load->in(MemNode::Address);
248248
assert(phase->type(adr) == t_oop, "inconsistent type");
249-
Node* tmp = try_optimize_strict_final_load_memory(phase, field, adr, base_local);
249+
Node* tmp = try_optimize_strict_final_load_memory(phase, adr, base_local);
250250
if (tmp != nullptr) {
251251
result = tmp;
252252
}

src/hotspot/share/opto/parse3.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ void Parse::do_get_xxx(Node* obj, ciField* field) {
130130

131131
if (obj->is_InlineType()) {
132132
InlineTypeNode* vt = obj->as_InlineType();
133-
Node* value = vt->field_value_by_offset(field->offset_in_bytes());
133+
Node* value = vt->field_value_by_offset(field->offset_in_bytes(), false);
134134
if (value->is_InlineType()) {
135135
value = value->as_InlineType()->adjust_scalarization_depth(this);
136136
}

src/hotspot/share/runtime/signature.hpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -589,9 +589,12 @@ class SigEntry {
589589
: _bt(bt), _offset(offset), _sort_offset(sort_offset), _symbol(symbol) {}
590590

591591
static int compare(SigEntry* e1, SigEntry* e2) {
592-
if (e1->_sort_offset != e2->_sort_offset) {
593-
return e1->_sort_offset - e2->_sort_offset;
592+
if (e1->_sort_offset < e2->_sort_offset) {
593+
return -1;
594+
} else if (e1->_sort_offset > e2->_sort_offset) {
595+
return 1;
594596
}
597+
595598
if (e1->_offset != e2->_offset) {
596599
return e1->_offset - e2->_offset;
597600
}

test/hotspot/jtreg/compiler/valhalla/inlinetypes/InlineTypes.java

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,25 @@ public class InlineTypes {
120120
"-XX:+UseFieldFlattening",
121121
"-XX:-InlineTypePassFieldsAsArgs",
122122
"-XX:-InlineTypeReturnedAsFields"
123-
)
123+
),
124+
new Scenario(6,
125+
"--enable-preview",
126+
"--add-exports", "java.base/jdk.internal.value=ALL-UNNAMED",
127+
"--add-exports", "java.base/jdk.internal.vm.annotation=ALL-UNNAMED",
128+
"--add-exports", "java.base/jdk.internal.misc=ALL-UNNAMED",
129+
"-XX:+IgnoreUnrecognizedVMOptions",
130+
"-XX:-UseACmpProfile",
131+
"-XX:+AlwaysIncrementalInline",
132+
"-XX:FlatArrayElementMaxOops=5",
133+
"-XX:+UseArrayFlattening",
134+
"-XX:-UseArrayLoadStoreProfile",
135+
"-XX:+UseFieldFlattening",
136+
"-XX:+UseNullableValueFlattening",
137+
"-XX:+UseAtomicValueFlattening",
138+
"-XX:+UseNonAtomicValueFlattening",
139+
"-XX:+InlineTypePassFieldsAsArgs",
140+
"-XX:+InlineTypeReturnedAsFields"
141+
),
124142
};
125143

126144
public static TestFramework getFramework() {

test/hotspot/jtreg/compiler/valhalla/inlinetypes/MyValue1.java

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
import compiler.lib.ir_framework.ForceCompileClassInitializer;
2929
import compiler.lib.ir_framework.ForceInline;
3030

31+
import java.util.Arrays;
32+
3133
import jdk.internal.vm.annotation.LooselyConsistentValue;
3234
import jdk.internal.vm.annotation.NullRestricted;
3335
import jdk.internal.vm.annotation.Strict;
@@ -133,13 +135,6 @@ public long hashInterpreted() {
133135
return s + sf + x + y + z + o + oa[0] + c + v1.hashInterpreted() + v2.hashInterpreted() + v3.hashInterpreted() + v4.hashInterpreted() + v5.hashInterpreted();
134136
}
135137

136-
@Override
137-
public String toString() {
138-
return "s=" + s + ", sf=" + sf + ", x=" + x + ", y=" + y + ", z=" + z +
139-
", o=" + (o != null ? (Integer)o : "NULL") + ", oa=" + (oa != null ? oa[0] : "NULL") +
140-
", v1=[" + v1 + "], v2=[" + v2 + "], v3=[" + v3 + "], v4=[" + v4 + "], v5=[" + v5 +"], c=" + c;
141-
}
142-
143138
@ForceInline
144139
static MyValue1 setX(MyValue1 v, int x) {
145140
return new MyValue1(x, v.y, v.z, v.o, v.oa, v.v1, v.v2, v.v4, v.v5, v.c);
@@ -189,4 +184,10 @@ static MyValue1 setV4(MyValue1 v, MyValue2 v4) {
189184
static MyValue1 setV5(MyValue1 v, MyValue2 v5) {
190185
return new MyValue1(v.x, v.y, v.z, v.o, v.oa, v.v1, v.v2, v.v4, v5, v.c);
191186
}
187+
188+
@Override
189+
public String toString() {
190+
return "MyValue1[s=" + s + ", sf=" + sf + ", x=" + x + ", y=" + y + ", z=" + z + ", o=" + o + ", oa=" + Arrays.toString(oa) +
191+
", v1=" + v1 + ", v2=" + v2 + ", v4=" + v4 + ", c=" + c + "]";
192+
}
192193
}

test/hotspot/jtreg/compiler/valhalla/inlinetypes/MyValue2.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ public static MyValue2Inline createWithFieldsInline(double d, long l) {
6666

6767
@Override
6868
public String toString() {
69-
return "d=" + d + ", l=" + l;
69+
return "MyValue2Inline[d=" + d + ", l=" + l + "]";
7070
}
7171
}
7272

@@ -129,11 +129,6 @@ public long hashInterpreted() {
129129
return x + y + (long)v.d + v.l;
130130
}
131131

132-
@Override
133-
public String toString() {
134-
return "x=" + x + ", y=" + y + ", v=[" + v + "]";
135-
}
136-
137132
@ForceInline
138133
static MyValue2 setX(MyValue2 v, int x) {
139134
return new MyValue2(x, v.y, v.v);
@@ -148,4 +143,9 @@ static MyValue2 setY(MyValue2 v, byte y) {
148143
static MyValue2 setV(MyValue2 v, MyValue2Inline vi) {
149144
return new MyValue2(v.x, v.y, vi);
150145
}
146+
147+
@Override
148+
public String toString() {
149+
return "MyValue2[x=" + x + ", y=" + y + ", v=" + v + "]";
150+
}
151151
}

0 commit comments

Comments
 (0)