From 10c67c9d1834bd1fe4a027720cbc02e7ae8985dc Mon Sep 17 00:00:00 2001 From: Marc Chevalier Date: Mon, 6 Jul 2026 11:01:31 +0200 Subject: [PATCH 01/20] disable --- src/hotspot/share/opto/phaseX.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/hotspot/share/opto/phaseX.cpp b/src/hotspot/share/opto/phaseX.cpp index aef867fc70c..7884828d0b7 100644 --- a/src/hotspot/share/opto/phaseX.cpp +++ b/src/hotspot/share/opto/phaseX.cpp @@ -2816,10 +2816,12 @@ void PhaseIterGVN::add_users_of_use_to_worklist(Node* n, Node* use, Unique_Node_ if (use_op == Op_CastP2X) { for (DUIterator_Fast i2max, i2 = use->fast_outs(i2max); i2 < i2max; i2++) { Node* u = use->fast_out(i2); +#if 0 // TODO 8350865 Still needed? Yes, I think this is from PhaseMacroExpand::expand_mh_intrinsic_return if (u->Opcode() == Op_AndX) { worklist.push(u); } +#endif // Search for CmpL(OrL(CastP2X(..), CastP2X(..)), 0L) if (u->Opcode() == Op_OrL) { for (DUIterator_Fast i3max, i3 = u->fast_outs(i3max); i3 < i3max; i3++) { @@ -3235,6 +3237,7 @@ void PhaseCCP::push_counted_loop_phi(Unique_Node_List& worklist, Node* parent, c // TODO 8350865 Still needed? Yes, I think this is from PhaseMacroExpand::expand_mh_intrinsic_return void PhaseCCP::push_cast(Unique_Node_List& worklist, const Node* use) { +#if 0 uint use_op = use->Opcode(); if (use_op == Op_CastP2X) { for (DUIterator_Fast i2max, i2 = use->fast_outs(i2max); i2 < i2max; i2++) { @@ -3244,6 +3247,7 @@ void PhaseCCP::push_cast(Unique_Node_List& worklist, const Node* use) { } } } +#endif } // Loading the java mirror from a Klass requires two loads and the type of the mirror load depends on the type of 'n'. From e5a73b38e76d1e58af429f8d763a111678e4bc68 Mon Sep 17 00:00:00 2001 From: Marc Chevalier Date: Thu, 16 Jul 2026 10:22:57 +0200 Subject: [PATCH 02/20] Re-enable --- src/hotspot/share/opto/phaseX.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/hotspot/share/opto/phaseX.cpp b/src/hotspot/share/opto/phaseX.cpp index 7884828d0b7..40db50d4d05 100644 --- a/src/hotspot/share/opto/phaseX.cpp +++ b/src/hotspot/share/opto/phaseX.cpp @@ -2816,12 +2816,9 @@ void PhaseIterGVN::add_users_of_use_to_worklist(Node* n, Node* use, Unique_Node_ if (use_op == Op_CastP2X) { for (DUIterator_Fast i2max, i2 = use->fast_outs(i2max); i2 < i2max; i2++) { Node* u = use->fast_out(i2); -#if 0 - // TODO 8350865 Still needed? Yes, I think this is from PhaseMacroExpand::expand_mh_intrinsic_return if (u->Opcode() == Op_AndX) { worklist.push(u); } -#endif // Search for CmpL(OrL(CastP2X(..), CastP2X(..)), 0L) if (u->Opcode() == Op_OrL) { for (DUIterator_Fast i3max, i3 = u->fast_outs(i3max); i3 < i3max; i3++) { @@ -3235,9 +3232,7 @@ void PhaseCCP::push_counted_loop_phi(Unique_Node_List& worklist, Node* parent, c } } -// TODO 8350865 Still needed? Yes, I think this is from PhaseMacroExpand::expand_mh_intrinsic_return void PhaseCCP::push_cast(Unique_Node_List& worklist, const Node* use) { -#if 0 uint use_op = use->Opcode(); if (use_op == Op_CastP2X) { for (DUIterator_Fast i2max, i2 = use->fast_outs(i2max); i2 < i2max; i2++) { @@ -3247,7 +3242,6 @@ void PhaseCCP::push_cast(Unique_Node_List& worklist, const Node* use) { } } } -#endif } // Loading the java mirror from a Klass requires two loads and the type of the mirror load depends on the type of 'n'. From 05049b0bbdadf972bfd9cfc41cdd6a3c3fd6f8e0 Mon Sep 17 00:00:00 2001 From: Marc Chevalier Date: Thu, 9 Jul 2026 12:07:25 +0200 Subject: [PATCH 03/20] Trying --- src/hotspot/share/ci/ciInstanceKlass.cpp | 45 ++++++++++++++------ src/hotspot/share/ci/ciReplay.cpp | 54 +++++++++++++++--------- src/hotspot/share/memory/oopFactory.cpp | 2 +- 3 files changed, 69 insertions(+), 32 deletions(-) diff --git a/src/hotspot/share/ci/ciInstanceKlass.cpp b/src/hotspot/share/ci/ciInstanceKlass.cpp index 41adc7de96b..353bba95bed 100644 --- a/src/hotspot/share/ci/ciInstanceKlass.cpp +++ b/src/hotspot/share/ci/ciInstanceKlass.cpp @@ -863,8 +863,21 @@ void StaticFieldPrinter::do_field_helper(fieldDescriptor* fd, oop mirror, bool i break; } case T_ARRAY: // fall-through - case T_OBJECT: - if (!fd->is_null_free_inline_type()) { + case T_OBJECT: { + InstanceKlass* k = nullptr; + ResetNoHandleMark rnhm; + Thread* THREAD = Thread::current(); + SignatureStream ss(fd->signature(), false); + Symbol* name = ss.as_symbol(); + assert(!HAS_PENDING_EXCEPTION, "can resolve klass?"); + InstanceKlass* holder = fd->field_holder(); + if (field_type == T_OBJECT) { + k = SystemDictionary::find_instance_klass(THREAD, name, Handle(THREAD, holder->class_loader())); + // handling of null free inline type + guarantee(k != nullptr && !HAS_PENDING_EXCEPTION, "can resolve klass?"); + } + + if (k == nullptr || !k->is_inline_klass()) { _out->print("%s ", fd->signature()->as_quoted_ascii()); oop value = mirror->obj_field_acquire(fd->offset()); if (value == nullptr) { @@ -886,6 +899,23 @@ void StaticFieldPrinter::do_field_helper(fieldDescriptor* fd, oop mirror, bool i _out->print("%d", a->length()); if (value->is_objArray()) { objArrayOop oa = (objArrayOop)value; + if (value->is_flatArray()) { + FlatArrayKlass* klass = ((flatArrayOop)oa)->klass(); + LayoutKind lk = klass->layout_kind(); + _out->print(" flat"); + if (LayoutKindHelper::is_atomic_flat(lk)) { + _out->print(" atomic"); + } else { + _out->print(" non-atomic"); + } + if (LayoutKindHelper::is_nullable_flat(lk)) { + _out->print(" nullable"); + } else { + _out->print(" null-free"); + } + } else { + _out->print(" ref"); + } const char* klass_name = value->klass()->name()->as_quoted_ascii(); _out->print(" %s", klass_name); } @@ -894,16 +924,6 @@ void StaticFieldPrinter::do_field_helper(fieldDescriptor* fd, oop mirror, bool i } break; } else { - // handling of null free inline type - ResetNoHandleMark rnhm; - Thread* THREAD = Thread::current(); - SignatureStream ss(fd->signature(), false); - Symbol* name = ss.as_symbol(); - assert(!HAS_PENDING_EXCEPTION, "can resolve klass?"); - InstanceKlass* holder = fd->field_holder(); - InstanceKlass* k = SystemDictionary::find_instance_klass(THREAD, name, - Handle(THREAD, holder->class_loader())); - guarantee(k != nullptr && !HAS_PENDING_EXCEPTION, "can resolve klass?"); InlineKlass* vk = InlineKlass::cast(k); oop obj; if (is_flat) { @@ -916,6 +936,7 @@ void StaticFieldPrinter::do_field_helper(fieldDescriptor* fd, oop mirror, bool i vk->do_nonstatic_fields(&print_field); break; } + } default: ShouldNotReachHere(); } diff --git a/src/hotspot/share/ci/ciReplay.cpp b/src/hotspot/share/ci/ciReplay.cpp index be55687cca4..5de0e328931 100644 --- a/src/hotspot/share/ci/ciReplay.cpp +++ b/src/hotspot/share/ci/ciReplay.cpp @@ -515,14 +515,14 @@ class CompileReplay : public StackObj { } obj = ciReplay::obj_field(obj, field); // TODO 8350865 I think we need to handle null-free/flat arrays here - if (obj != nullptr && obj->is_refArray()) { - refArrayOop arr = oop_cast(obj); + if (obj != nullptr && obj->is_objArray()) { + objArrayOop arr = oop_cast(obj); int index = parse_int("index"); if (index >= arr->length()) { report_error("bad array index"); return nullptr; } - obj = arr->obj_at(index); + obj = arr->obj_at(index, THREAD); } } while (obj != nullptr); if (obj == nullptr) { @@ -1139,12 +1139,23 @@ class CompileReplay : public StackObj { value = oopFactory::new_longArray(length, CHECK_(true)); } else if (field_signature[0] == JVM_SIGNATURE_ARRAY && field_signature[1] == JVM_SIGNATURE_CLASS) { - Klass* actual_array_klass = parse_klass(CHECK_(true)); - // TODO 8350865 I think we need to handle null-free/flat arrays here - // This handling will change the array property argument passed to the - // factory below - Klass* kelem = ObjArrayKlass::cast(actual_array_klass)->element_klass(); - value = oopFactory::new_objArray(kelem, length, CHECK_(true)); + const char* flatness = parse_string(); + if (strcmp(flatness, "ref") == 0) { + Klass* actual_array_klass = parse_klass(CHECK_(true)); + Klass* kelem = ObjArrayKlass::cast(actual_array_klass)->element_klass(); + value = oopFactory::new_refArray(kelem, length, CHECK_(true)); + } else if (strcmp(flatness, "flat") == 0) { + const char* atomicity = parse_string(); + const char* nullability = parse_string(); + bool non_atomic = (strcmp(atomicity, "non-atomic") == 0); + bool null_restricted = (strcmp(nullability, "null-free") == 0); + Klass* actual_array_klass = parse_klass(CHECK_(true)); + Klass* kelem = ObjArrayKlass::cast(actual_array_klass)->element_klass(); + ArrayProperties props = ArrayProperties::Default().with_non_atomic(non_atomic).with_null_restricted(null_restricted); + value = oopFactory::new_flatArray(InlineKlass::cast(kelem), length, props, CHECK_(true)); + } else { + report_error("unrecognized array kind"); + } } else { report_error("unhandled array staticfield"); } @@ -1234,17 +1245,22 @@ class CompileReplay : public StackObj { const char* string_value = parse_escaped_string(); double value = atof(string_value); java_mirror->double_field_put(fd.offset(), value); - } else if (fd.is_null_free_inline_type()) { - Klass* kelem = resolve_klass(field_signature, CHECK); - InlineKlass* vk = InlineKlass::cast(kelem); - oop value = vk->allocate_instance(CHECK); - InlineTypeFieldInitializer init_fields(value, this); - vk->do_nonstatic_fields(&init_fields); - java_mirror->obj_field_put(fd.offset(), value); } else { - bool res = process_staticfield_reference(field_signature, java_mirror, &fd, CHECK); - if (!res) { - report_error("unhandled staticfield"); + Klass* kelem = nullptr; + if (fd.field_type() == T_OBJECT) { + kelem = resolve_klass(field_signature, CHECK); + } + if (kelem != nullptr && kelem->is_inline_klass()) { + InlineKlass* vk = InlineKlass::cast(kelem); + oop value = vk->allocate_instance(CHECK); + InlineTypeFieldInitializer init_fields(value, this); + vk->do_nonstatic_fields(&init_fields); + java_mirror->obj_field_put(fd.offset(), value); + } else { + bool res = process_staticfield_reference(field_signature, java_mirror, &fd, CHECK); + if (!res) { + report_error("unhandled staticfield"); + } } } } diff --git a/src/hotspot/share/memory/oopFactory.cpp b/src/hotspot/share/memory/oopFactory.cpp index d7fdffb6c32..c1f9f8dacc8 100644 --- a/src/hotspot/share/memory/oopFactory.cpp +++ b/src/hotspot/share/memory/oopFactory.cpp @@ -117,7 +117,7 @@ objArrayOop oopFactory::new_objArray(Klass* klass, int length, ArrayProperties p } objArrayOop oopFactory::new_objArray(Klass* klass, int length, TRAPS) { - return new_objArray(klass, length, ArrayProperties::Default(), THREAD); + return new_objArray(klass, length, ArrayProperties::Default(), THREAD); } refArrayOop oopFactory::new_refArray(Klass* klass, int length, ArrayProperties properties, TRAPS) { From 4531d8b2010ac45befa50f7698f2f492edaf3255 Mon Sep 17 00:00:00 2001 From: Marc Chevalier Date: Thu, 16 Jul 2026 10:47:52 +0200 Subject: [PATCH 04/20] remove comment, nullability for ref arrays --- src/hotspot/share/ci/ciInstanceKlass.cpp | 15 ++++++++++----- src/hotspot/share/ci/ciReplay.cpp | 10 ++++++---- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/src/hotspot/share/ci/ciInstanceKlass.cpp b/src/hotspot/share/ci/ciInstanceKlass.cpp index 353bba95bed..24eea62a0b8 100644 --- a/src/hotspot/share/ci/ciInstanceKlass.cpp +++ b/src/hotspot/share/ci/ciInstanceKlass.cpp @@ -903,18 +903,23 @@ void StaticFieldPrinter::do_field_helper(fieldDescriptor* fd, oop mirror, bool i FlatArrayKlass* klass = ((flatArrayOop)oa)->klass(); LayoutKind lk = klass->layout_kind(); _out->print(" flat"); - if (LayoutKindHelper::is_atomic_flat(lk)) { - _out->print(" atomic"); - } else { - _out->print(" non-atomic"); - } if (LayoutKindHelper::is_nullable_flat(lk)) { _out->print(" nullable"); } else { _out->print(" null-free"); } + if (LayoutKindHelper::is_atomic_flat(lk)) { + _out->print(" atomic"); + } else { + _out->print(" non-atomic"); + } } else { _out->print(" ref"); + if (oa->klass()->is_null_free_array_klass()) { + _out->print(" nullable"); + } else { + _out->print(" null-free"); + } } const char* klass_name = value->klass()->name()->as_quoted_ascii(); _out->print(" %s", klass_name); diff --git a/src/hotspot/share/ci/ciReplay.cpp b/src/hotspot/share/ci/ciReplay.cpp index 5de0e328931..e58a878799e 100644 --- a/src/hotspot/share/ci/ciReplay.cpp +++ b/src/hotspot/share/ci/ciReplay.cpp @@ -514,7 +514,6 @@ class CompileReplay : public StackObj { return k; } obj = ciReplay::obj_field(obj, field); - // TODO 8350865 I think we need to handle null-free/flat arrays here if (obj != nullptr && obj->is_objArray()) { objArrayOop arr = oop_cast(obj); int index = parse_int("index"); @@ -1141,14 +1140,17 @@ class CompileReplay : public StackObj { field_signature[1] == JVM_SIGNATURE_CLASS) { const char* flatness = parse_string(); if (strcmp(flatness, "ref") == 0) { + const char* nullability = parse_string(); + bool null_restricted = (strcmp(nullability, "null-free") == 0); Klass* actual_array_klass = parse_klass(CHECK_(true)); Klass* kelem = ObjArrayKlass::cast(actual_array_klass)->element_klass(); - value = oopFactory::new_refArray(kelem, length, CHECK_(true)); + ArrayProperties props = ArrayProperties::Default().with_non_atomic(false).with_null_restricted(null_restricted); + value = oopFactory::new_refArray(kelem, length, props, CHECK_(true)); } else if (strcmp(flatness, "flat") == 0) { - const char* atomicity = parse_string(); const char* nullability = parse_string(); - bool non_atomic = (strcmp(atomicity, "non-atomic") == 0); + const char* atomicity = parse_string(); bool null_restricted = (strcmp(nullability, "null-free") == 0); + bool non_atomic = (strcmp(atomicity, "non-atomic") == 0); Klass* actual_array_klass = parse_klass(CHECK_(true)); Klass* kelem = ObjArrayKlass::cast(actual_array_klass)->element_klass(); ArrayProperties props = ArrayProperties::Default().with_non_atomic(non_atomic).with_null_restricted(null_restricted); From 1f5dbac6a9b177f7da830bcb0d2b078cac443890 Mon Sep 17 00:00:00 2001 From: Marc Chevalier Date: Thu, 16 Jul 2026 13:47:11 +0200 Subject: [PATCH 05/20] Oops --- src/hotspot/share/ci/ciInstanceKlass.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/ci/ciInstanceKlass.cpp b/src/hotspot/share/ci/ciInstanceKlass.cpp index 24eea62a0b8..cce69921de4 100644 --- a/src/hotspot/share/ci/ciInstanceKlass.cpp +++ b/src/hotspot/share/ci/ciInstanceKlass.cpp @@ -916,9 +916,9 @@ void StaticFieldPrinter::do_field_helper(fieldDescriptor* fd, oop mirror, bool i } else { _out->print(" ref"); if (oa->klass()->is_null_free_array_klass()) { - _out->print(" nullable"); - } else { _out->print(" null-free"); + } else { + _out->print(" nullable"); } } const char* klass_name = value->klass()->name()->as_quoted_ascii(); From 6592eb66e8beeddbea92f8ce9d89e6682d9c48f4 Mon Sep 17 00:00:00 2001 From: Marc Chevalier Date: Wed, 22 Jul 2026 10:09:10 +0200 Subject: [PATCH 06/20] revering replay part --- src/hotspot/share/ci/ciInstanceKlass.cpp | 50 +++++--------------- src/hotspot/share/ci/ciReplay.cpp | 58 ++++++++---------------- src/hotspot/share/memory/oopFactory.cpp | 2 +- 3 files changed, 33 insertions(+), 77 deletions(-) diff --git a/src/hotspot/share/ci/ciInstanceKlass.cpp b/src/hotspot/share/ci/ciInstanceKlass.cpp index cce69921de4..41adc7de96b 100644 --- a/src/hotspot/share/ci/ciInstanceKlass.cpp +++ b/src/hotspot/share/ci/ciInstanceKlass.cpp @@ -863,21 +863,8 @@ void StaticFieldPrinter::do_field_helper(fieldDescriptor* fd, oop mirror, bool i break; } case T_ARRAY: // fall-through - case T_OBJECT: { - InstanceKlass* k = nullptr; - ResetNoHandleMark rnhm; - Thread* THREAD = Thread::current(); - SignatureStream ss(fd->signature(), false); - Symbol* name = ss.as_symbol(); - assert(!HAS_PENDING_EXCEPTION, "can resolve klass?"); - InstanceKlass* holder = fd->field_holder(); - if (field_type == T_OBJECT) { - k = SystemDictionary::find_instance_klass(THREAD, name, Handle(THREAD, holder->class_loader())); - // handling of null free inline type - guarantee(k != nullptr && !HAS_PENDING_EXCEPTION, "can resolve klass?"); - } - - if (k == nullptr || !k->is_inline_klass()) { + case T_OBJECT: + if (!fd->is_null_free_inline_type()) { _out->print("%s ", fd->signature()->as_quoted_ascii()); oop value = mirror->obj_field_acquire(fd->offset()); if (value == nullptr) { @@ -899,28 +886,6 @@ void StaticFieldPrinter::do_field_helper(fieldDescriptor* fd, oop mirror, bool i _out->print("%d", a->length()); if (value->is_objArray()) { objArrayOop oa = (objArrayOop)value; - if (value->is_flatArray()) { - FlatArrayKlass* klass = ((flatArrayOop)oa)->klass(); - LayoutKind lk = klass->layout_kind(); - _out->print(" flat"); - if (LayoutKindHelper::is_nullable_flat(lk)) { - _out->print(" nullable"); - } else { - _out->print(" null-free"); - } - if (LayoutKindHelper::is_atomic_flat(lk)) { - _out->print(" atomic"); - } else { - _out->print(" non-atomic"); - } - } else { - _out->print(" ref"); - if (oa->klass()->is_null_free_array_klass()) { - _out->print(" null-free"); - } else { - _out->print(" nullable"); - } - } const char* klass_name = value->klass()->name()->as_quoted_ascii(); _out->print(" %s", klass_name); } @@ -929,6 +894,16 @@ void StaticFieldPrinter::do_field_helper(fieldDescriptor* fd, oop mirror, bool i } break; } else { + // handling of null free inline type + ResetNoHandleMark rnhm; + Thread* THREAD = Thread::current(); + SignatureStream ss(fd->signature(), false); + Symbol* name = ss.as_symbol(); + assert(!HAS_PENDING_EXCEPTION, "can resolve klass?"); + InstanceKlass* holder = fd->field_holder(); + InstanceKlass* k = SystemDictionary::find_instance_klass(THREAD, name, + Handle(THREAD, holder->class_loader())); + guarantee(k != nullptr && !HAS_PENDING_EXCEPTION, "can resolve klass?"); InlineKlass* vk = InlineKlass::cast(k); oop obj; if (is_flat) { @@ -941,7 +916,6 @@ void StaticFieldPrinter::do_field_helper(fieldDescriptor* fd, oop mirror, bool i vk->do_nonstatic_fields(&print_field); break; } - } default: ShouldNotReachHere(); } diff --git a/src/hotspot/share/ci/ciReplay.cpp b/src/hotspot/share/ci/ciReplay.cpp index e58a878799e..be55687cca4 100644 --- a/src/hotspot/share/ci/ciReplay.cpp +++ b/src/hotspot/share/ci/ciReplay.cpp @@ -514,14 +514,15 @@ class CompileReplay : public StackObj { return k; } obj = ciReplay::obj_field(obj, field); - if (obj != nullptr && obj->is_objArray()) { - objArrayOop arr = oop_cast(obj); + // TODO 8350865 I think we need to handle null-free/flat arrays here + if (obj != nullptr && obj->is_refArray()) { + refArrayOop arr = oop_cast(obj); int index = parse_int("index"); if (index >= arr->length()) { report_error("bad array index"); return nullptr; } - obj = arr->obj_at(index, THREAD); + obj = arr->obj_at(index); } } while (obj != nullptr); if (obj == nullptr) { @@ -1138,26 +1139,12 @@ class CompileReplay : public StackObj { value = oopFactory::new_longArray(length, CHECK_(true)); } else if (field_signature[0] == JVM_SIGNATURE_ARRAY && field_signature[1] == JVM_SIGNATURE_CLASS) { - const char* flatness = parse_string(); - if (strcmp(flatness, "ref") == 0) { - const char* nullability = parse_string(); - bool null_restricted = (strcmp(nullability, "null-free") == 0); - Klass* actual_array_klass = parse_klass(CHECK_(true)); - Klass* kelem = ObjArrayKlass::cast(actual_array_klass)->element_klass(); - ArrayProperties props = ArrayProperties::Default().with_non_atomic(false).with_null_restricted(null_restricted); - value = oopFactory::new_refArray(kelem, length, props, CHECK_(true)); - } else if (strcmp(flatness, "flat") == 0) { - const char* nullability = parse_string(); - const char* atomicity = parse_string(); - bool null_restricted = (strcmp(nullability, "null-free") == 0); - bool non_atomic = (strcmp(atomicity, "non-atomic") == 0); - Klass* actual_array_klass = parse_klass(CHECK_(true)); - Klass* kelem = ObjArrayKlass::cast(actual_array_klass)->element_klass(); - ArrayProperties props = ArrayProperties::Default().with_non_atomic(non_atomic).with_null_restricted(null_restricted); - value = oopFactory::new_flatArray(InlineKlass::cast(kelem), length, props, CHECK_(true)); - } else { - report_error("unrecognized array kind"); - } + Klass* actual_array_klass = parse_klass(CHECK_(true)); + // TODO 8350865 I think we need to handle null-free/flat arrays here + // This handling will change the array property argument passed to the + // factory below + Klass* kelem = ObjArrayKlass::cast(actual_array_klass)->element_klass(); + value = oopFactory::new_objArray(kelem, length, CHECK_(true)); } else { report_error("unhandled array staticfield"); } @@ -1247,22 +1234,17 @@ class CompileReplay : public StackObj { const char* string_value = parse_escaped_string(); double value = atof(string_value); java_mirror->double_field_put(fd.offset(), value); + } else if (fd.is_null_free_inline_type()) { + Klass* kelem = resolve_klass(field_signature, CHECK); + InlineKlass* vk = InlineKlass::cast(kelem); + oop value = vk->allocate_instance(CHECK); + InlineTypeFieldInitializer init_fields(value, this); + vk->do_nonstatic_fields(&init_fields); + java_mirror->obj_field_put(fd.offset(), value); } else { - Klass* kelem = nullptr; - if (fd.field_type() == T_OBJECT) { - kelem = resolve_klass(field_signature, CHECK); - } - if (kelem != nullptr && kelem->is_inline_klass()) { - InlineKlass* vk = InlineKlass::cast(kelem); - oop value = vk->allocate_instance(CHECK); - InlineTypeFieldInitializer init_fields(value, this); - vk->do_nonstatic_fields(&init_fields); - java_mirror->obj_field_put(fd.offset(), value); - } else { - bool res = process_staticfield_reference(field_signature, java_mirror, &fd, CHECK); - if (!res) { - report_error("unhandled staticfield"); - } + bool res = process_staticfield_reference(field_signature, java_mirror, &fd, CHECK); + if (!res) { + report_error("unhandled staticfield"); } } } diff --git a/src/hotspot/share/memory/oopFactory.cpp b/src/hotspot/share/memory/oopFactory.cpp index c1f9f8dacc8..d7fdffb6c32 100644 --- a/src/hotspot/share/memory/oopFactory.cpp +++ b/src/hotspot/share/memory/oopFactory.cpp @@ -117,7 +117,7 @@ objArrayOop oopFactory::new_objArray(Klass* klass, int length, ArrayProperties p } objArrayOop oopFactory::new_objArray(Klass* klass, int length, TRAPS) { - return new_objArray(klass, length, ArrayProperties::Default(), THREAD); + return new_objArray(klass, length, ArrayProperties::Default(), THREAD); } refArrayOop oopFactory::new_refArray(Klass* klass, int length, ArrayProperties properties, TRAPS) { From dc92615a0d8bf1647b48e32b4c737c9b002ded08 Mon Sep 17 00:00:00 2001 From: Marc Chevalier Date: Thu, 9 Jul 2026 12:32:59 +0200 Subject: [PATCH 07/20] TestIntrinsics --- .../compiler/valhalla/inlinetypes/TestIntrinsics.java | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestIntrinsics.java b/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestIntrinsics.java index 299230f0b98..6b80a897495 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestIntrinsics.java +++ b/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestIntrinsics.java @@ -2035,9 +2035,8 @@ public class TestIntrinsics { // Test correctness of the ValueClass::isAtomicArray intrinsic @Test - // TODO 8350865 Implemented intrinsic - // @IR(failOn = {STATIC_CALL_OF_METHOD, "jdk.internal.value.ValueClass::isAtomicArray", - // STATIC_CALL_OF_METHOD, "jdk.internal.value.ValueClass::isAtomicArray0"}) + @IR(failOn = {STATIC_CALL_OF_METHOD, "jdk.internal.value.ValueClass::isAtomicArray", + STATIC_CALL_OF_METHOD, "jdk.internal.value.ValueClass::isAtomicArray0"}) public boolean test87(Object[] array) { return ValueClass.isAtomicArray(array); } @@ -2053,9 +2052,8 @@ public class TestIntrinsics { // Verify that ValueClass::isAtomicArray checks with statically known classes are folded @Test - // TODO 8350865 Implemented intrinsic - // @IR(failOn = {LOAD_KLASS, STATIC_CALL_OF_METHOD, "jdk.internal.value.ValueClass::isAtomicArray", - // STATIC_CALL_OF_METHOD, "jdk.internal.value.ValueClass::isAtomicArray0"}) + @IR(failOn = {LOAD_KLASS, STATIC_CALL_OF_METHOD, "jdk.internal.value.ValueClass::isAtomicArray", + STATIC_CALL_OF_METHOD, "jdk.internal.value.ValueClass::isAtomicArray0"}) public boolean test88() { boolean check1 = ValueClass.isAtomicArray(TEST_ARRAY1); if (!TEST_ARRAY1_IS_ATOMIC) { From 6e0a9cc092223f30d70a10e8ee0c4d6f5bebec02 Mon Sep 17 00:00:00 2001 From: Marc Chevalier Date: Thu, 16 Jul 2026 10:52:13 +0200 Subject: [PATCH 08/20] cleanup --- .../jtreg/compiler/valhalla/inlinetypes/TestIntrinsics.java | 1 - 1 file changed, 1 deletion(-) diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestIntrinsics.java b/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestIntrinsics.java index 6b80a897495..7a311143ece 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestIntrinsics.java +++ b/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestIntrinsics.java @@ -43,7 +43,6 @@ import static compiler.valhalla.inlinetypes.InlineTypes.rL; import static compiler.lib.ir_framework.IRNode.LOAD; import static compiler.lib.ir_framework.IRNode.LOAD_KLASS; -import static compiler.valhalla.inlinetypes.InlineTypes.*; /* * @test From 914bb2ac327fe5206ff36d7c0dab1d23c62c1380 Mon Sep 17 00:00:00 2001 From: Marc Chevalier Date: Thu, 9 Jul 2026 17:59:46 +0200 Subject: [PATCH 09/20] Trying with FlatArrayElementMaxOops --- .../inlinetypes/TestFlatInArraysFolding.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestFlatInArraysFolding.java b/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestFlatInArraysFolding.java index d6716ba5f50..d58f1acef8b 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestFlatInArraysFolding.java +++ b/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestFlatInArraysFolding.java @@ -78,9 +78,8 @@ public class TestFlatInArraysFolding { static int iFld; public static void main(String[] args) { - // TODO 8350865 Scenarios are equivalent, FlatArrayElementMaxSize does not exist anymore - Scenario flatArrayElementMaxSize1Scenario = new Scenario(1, "-XX:-UseArrayFlattening"); - Scenario flatArrayElementMaxSize4Scenario = new Scenario(2, "-XX:-UseArrayFlattening"); + Scenario flatArrayElementMaxSize1Scenario = new Scenario(1, "-XX:FlatArrayElementMaxOops=0"); + Scenario flatArrayElementMaxSize4Scenario = new Scenario(2, "-XX:FlatArrayElementMaxOops=4"); Scenario noFlagsScenario = new Scenario(3); TestFramework testFramework = new TestFramework(); testFramework.setDefaultWarmup(0) @@ -166,7 +165,7 @@ public class TestFlatInArraysFolding { } // TODO 8350865 FlatArrayElementMaxSize does not exist anymore - // PUnique is the unique concrete sub class of AUnique and is not flat in array (with FlatArrayElementMaxSize=4). + // PUnique is the unique concrete sub class of AUnique and is not flat in array (with FlatArrayElementMaxOops=0). // The CheckCastPP output of the sub type check uses PUnique while the sub type check itself uses AUnique. This leads // to a bad graph because the type system determines that the flat in array super klass cannot be met with the // not flat in array sub klass. But the sub type check does not fold away because AUnique *could* be flat in array. @@ -253,10 +252,10 @@ public class TestFlatInArraysFolding { @LooselyConsistentValue static value class PUnique extends AUnique { int x; - int y; + String y; PUnique(int x) { this.x = x; - this.y = 34; + this.y = "abc"; } public void foo() {} @@ -282,14 +281,15 @@ public class TestFlatInArraysFolding { public void bar() {} } - // TODO 8350865 FlatArrayElementMaxSize does not exist anymore - // Not flat in array with -XX:FlatArrayElementMaxSize=4 + // Not flat in array with -XX:FlatArrayElementMaxOops=0 static value class NotFlatInArray extends A implements I { int x; int y; + String z; NotFlatInArray(int x) { this.x = x; this.y = 34; + this.z = "abc"; } public void foo() {} From 06ed3fb1e71c713303e3e9eadd97e7caecce35b6 Mon Sep 17 00:00:00 2001 From: Marc Chevalier Date: Thu, 9 Jul 2026 18:01:10 +0200 Subject: [PATCH 10/20] Fix comment --- .../compiler/valhalla/inlinetypes/TestFlatInArraysFolding.java | 1 - 1 file changed, 1 deletion(-) diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestFlatInArraysFolding.java b/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestFlatInArraysFolding.java index d58f1acef8b..1cad6bec219 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestFlatInArraysFolding.java +++ b/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestFlatInArraysFolding.java @@ -164,7 +164,6 @@ public class TestFlatInArraysFolding { } } - // TODO 8350865 FlatArrayElementMaxSize does not exist anymore // PUnique is the unique concrete sub class of AUnique and is not flat in array (with FlatArrayElementMaxOops=0). // The CheckCastPP output of the sub type check uses PUnique while the sub type check itself uses AUnique. This leads // to a bad graph because the type system determines that the flat in array super klass cannot be met with the From d4e20a47fc3385eeffd83f4ed4a51e3a184f9e4a Mon Sep 17 00:00:00 2001 From: Marc Chevalier Date: Thu, 9 Jul 2026 17:19:20 +0200 Subject: [PATCH 11/20] TestBasicFunctionality --- .../valhalla/inlinetypes/TestBasicFunctionality.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestBasicFunctionality.java b/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestBasicFunctionality.java index ebab0a1052b..b2ccdee0c86 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestBasicFunctionality.java +++ b/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestBasicFunctionality.java @@ -573,12 +573,11 @@ static MyValue1 tmp = null; // correctly allocated. @Test @IR(applyIf = {"InlineTypePassFieldsAsArgs", "true"}, - counts = {ALLOC_OF_MYVALUE_KLASS, "<= 1"}, // 1 MyValue2 allocation (if not the all-zero value) + counts = {ALLOC_OF_MYVALUE_KLASS, "<= 1"}, // 1 MyValue2 allocation (if not the all-zero value): MyValue1.createWithFieldsInline -> setV4 failOn = {LOAD_OF_ANY_KLASS}) - // TODO 8350865 - //@IR(applyIf = {"InlineTypePassFieldsAsArgs", "false"}, - // counts = {ALLOC_OF_MYVALUE_KLASS, "<= 2"}, // 1 MyValue1 and 1 MyValue2 allocation (if not the all-zero value) - // failOn = LOAD_OF_ANY_KLASS) + @IR(applyIf = {"InlineTypePassFieldsAsArgs", "false"}, + counts = {ALLOC_OF_MYVALUE_KLASS, "<= 2"}, // 1 MyValue1 and 1 MyValue2 allocation (if not the all-zero value): same as above + the local v (MyValue1) + MyValue2.DEFAULT for the calls to MyValue2.hashInterpreted() + failOn = LOAD_OF_ANY_KLASS) public long test20(boolean deopt, Method m) { MyValue1 v = MyValue1.createWithFieldsInline(rI, rL); MyValue2[] va = (MyValue2[])ValueClass.newNullRestrictedNonAtomicArray(MyValue2.class, 3, MyValue2.DEFAULT); From 062f630740929f44e16ce3e7eff1b5f6f5201733 Mon Sep 17 00:00:00 2001 From: Marc Chevalier Date: Fri, 10 Jul 2026 09:25:43 +0200 Subject: [PATCH 12/20] ... --- .../compiler/valhalla/inlinetypes/TestBasicFunctionality.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestBasicFunctionality.java b/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestBasicFunctionality.java index b2ccdee0c86..6519a4191bd 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestBasicFunctionality.java +++ b/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestBasicFunctionality.java @@ -576,7 +576,7 @@ static MyValue1 tmp = null; counts = {ALLOC_OF_MYVALUE_KLASS, "<= 1"}, // 1 MyValue2 allocation (if not the all-zero value): MyValue1.createWithFieldsInline -> setV4 failOn = {LOAD_OF_ANY_KLASS}) @IR(applyIf = {"InlineTypePassFieldsAsArgs", "false"}, - counts = {ALLOC_OF_MYVALUE_KLASS, "<= 2"}, // 1 MyValue1 and 1 MyValue2 allocation (if not the all-zero value): same as above + the local v (MyValue1) + MyValue2.DEFAULT for the calls to MyValue2.hashInterpreted() + counts = {ALLOC_OF_MYVALUE_KLASS, "<= 3"}, // 1 MyValue1 and 2 MyValue2 allocation (if not the all-zero value): same as above + the local v (MyValue1) + MyValue2.DEFAULT for the calls to MyValue2.hashInterpreted() failOn = LOAD_OF_ANY_KLASS) public long test20(boolean deopt, Method m) { MyValue1 v = MyValue1.createWithFieldsInline(rI, rL); From 23abceae2e7e9329960378bae94cdbff505a7924 Mon Sep 17 00:00:00 2001 From: Marc Chevalier Date: Wed, 15 Jul 2026 14:06:07 +0200 Subject: [PATCH 13/20] More tests --- .../valhalla/inlinetypes/TestLWorld.java | 410 +++++++++++++++--- 1 file changed, 358 insertions(+), 52 deletions(-) diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestLWorld.java b/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestLWorld.java index ef64dc12e78..bd79eba29e2 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestLWorld.java +++ b/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestLWorld.java @@ -25,6 +25,7 @@ package compiler.valhalla.inlinetypes; import compiler.lib.ir_framework.*; import jdk.test.lib.Asserts; +import jdk.test.whitebox.WhiteBox; import test.java.lang.invoke.lib.InstructionHelper; import java.lang.invoke.MethodHandle; @@ -53,7 +54,6 @@ import static compiler.lib.ir_framework.IRNode.COUNTED_LOOP_MAIN; import static compiler.lib.ir_framework.IRNode.DYNAMIC_CALL_OF_METHOD; import static compiler.lib.ir_framework.IRNode.FIELD_ACCESS; import static compiler.lib.ir_framework.IRNode.LOAD; -import static compiler.lib.ir_framework.IRNode.STORE; import static compiler.lib.ir_framework.IRNode.LOAD_P; import static compiler.lib.ir_framework.IRNode.LOOP; import static compiler.lib.ir_framework.IRNode.MEMBAR; @@ -4606,11 +4606,11 @@ public class TestLWorld { } @LooselyConsistentValue - static value class ValueClassWithDouble { - double d; + static value class ValueClassWithFloat { + float f; - ValueClassWithDouble(double d) { - this.d = d; + ValueClassWithFloat(float f) { + this.f = f; } } @@ -4634,36 +4634,71 @@ public class TestLWorld { } @LooselyConsistentValue - static value class SubValueClassWithDouble extends AbstractValueClassWithByte { - double d; + static value class SubValueClassWithFloat extends AbstractValueClassWithByte { + float f; - SubValueClassWithDouble(double d) { - this.d = d; - super((byte)(d + 1)); + SubValueClassWithFloat(float f) { + this.f = f; + super((byte)(f + 1)); } } // TODO 8350865 We need more copies of these tests for all ValueClass array factories - static final ValueClassWithInt[] VALUE_CLASS_WITH_INT_ARRAY = (ValueClassWithInt[]) ValueClass.newNullRestrictedNonAtomicArray(ValueClassWithInt.class, 2, new ValueClassWithInt(0)); - static final ValueClassWithDouble[] VALUE_CLASS_WITH_DOUBLE_ARRAY = (ValueClassWithDouble[]) ValueClass.newNullRestrictedNonAtomicArray(ValueClassWithDouble.class, 2, new ValueClassWithDouble(0)); - static final SubValueClassWithInt[] SUB_VALUE_CLASS_WITH_INT_ARRAY = (SubValueClassWithInt[]) ValueClass.newNullRestrictedNonAtomicArray(SubValueClassWithInt.class, 2, new SubValueClassWithInt(0)); - static final SubValueClassWithDouble[] SUB_VALUE_CLASS_WITH_DOUBLE_ARRAY = (SubValueClassWithDouble[]) ValueClass.newNullRestrictedNonAtomicArray(SubValueClassWithDouble.class, 2, new SubValueClassWithDouble(0)); + static final ValueClassWithInt[] VALUE_CLASS_WITH_INT_ARRAY_NULL_RESTRICTED_NON_ATOMIC = (ValueClassWithInt[]) ValueClass.newNullRestrictedNonAtomicArray(ValueClassWithInt.class, 2, new ValueClassWithInt(0)); + static final ValueClassWithFloat[] VALUE_CLASS_WITH_FLOAT_ARRAY_NULL_RESTRICTED_NON_ATOMIC = (ValueClassWithFloat[]) ValueClass.newNullRestrictedNonAtomicArray(ValueClassWithFloat.class, 2, new ValueClassWithFloat(0)); + static final SubValueClassWithInt[] SUB_VALUE_CLASS_WITH_INT_ARRAY_NULL_RESTRICTED_NON_ATOMIC = (SubValueClassWithInt[]) ValueClass.newNullRestrictedNonAtomicArray(SubValueClassWithInt.class, 2, new SubValueClassWithInt(0)); + static final SubValueClassWithFloat[] SUB_VALUE_CLASS_WITH_FLOAT_ARRAY_NULL_RESTRICTED_NON_ATOMIC = (SubValueClassWithFloat[]) ValueClass.newNullRestrictedNonAtomicArray(SubValueClassWithFloat.class, 2, new SubValueClassWithFloat(0)); + static final ValueClassWithInt[] VALUE_CLASS_WITH_INT_ARRAY_NULL_RESTRICTED_ATOMIC = (ValueClassWithInt[]) ValueClass.newNullRestrictedAtomicArray(ValueClassWithInt.class, 2, new ValueClassWithInt(0)); + static final ValueClassWithFloat[] VALUE_CLASS_WITH_FLOAT_ARRAY_NULL_RESTRICTED_ATOMIC = (ValueClassWithFloat[]) ValueClass.newNullRestrictedAtomicArray(ValueClassWithFloat.class, 2, new ValueClassWithFloat(0)); + static final SubValueClassWithInt[] SUB_VALUE_CLASS_WITH_INT_ARRAY_NULL_RESTRICTED_ATOMIC = (SubValueClassWithInt[]) ValueClass.newNullRestrictedAtomicArray(SubValueClassWithInt.class, 2, new SubValueClassWithInt(0)); + static final SubValueClassWithFloat[] SUB_VALUE_CLASS_WITH_FLOAT_ARRAY_NULL_RESTRICTED_ATOMIC = (SubValueClassWithFloat[]) ValueClass.newNullRestrictedAtomicArray(SubValueClassWithFloat.class, 2, new SubValueClassWithFloat(0)); + + static final ValueClassWithInt[] VALUE_CLASS_WITH_INT_ARRAY_NULLABLE_ATOMIC = (ValueClassWithInt[]) ValueClass.newNullableAtomicArray(ValueClassWithInt.class, 2); + static final ValueClassWithFloat[] VALUE_CLASS_WITH_FLOAT_ARRAY_NULLABLE_ATOMIC = (ValueClassWithFloat[]) ValueClass.newNullableAtomicArray(ValueClassWithFloat.class, 2); + static final SubValueClassWithInt[] SUB_VALUE_CLASS_WITH_INT_ARRAY_NULLABLE_ATOMIC = (SubValueClassWithInt[]) ValueClass.newNullableAtomicArray(SubValueClassWithInt.class, 2); + static final SubValueClassWithFloat[] SUB_VALUE_CLASS_WITH_FLOAT_ARRAY_NULLABLE_ATOMIC = (SubValueClassWithFloat[]) ValueClass.newNullableAtomicArray(SubValueClassWithFloat.class, 2); + + static final ValueClassWithInt[] VALUE_CLASS_WITH_INT_ARRAY_REF = (ValueClassWithInt[]) ValueClass.newReferenceArray(ValueClassWithInt.class, 2); + static final ValueClassWithFloat[] VALUE_CLASS_WITH_FLOAT_ARRAY_REF = (ValueClassWithFloat[]) ValueClass.newReferenceArray(ValueClassWithFloat.class, 2); + static final SubValueClassWithInt[] SUB_VALUE_CLASS_WITH_INT_ARRAY_REF = (SubValueClassWithInt[]) ValueClass.newReferenceArray(SubValueClassWithInt.class, 2); + static final SubValueClassWithFloat[] SUB_VALUE_CLASS_WITH_FLOAT_ARRAY_REF = (SubValueClassWithFloat[]) ValueClass.newReferenceArray(SubValueClassWithFloat.class, 2); static { - VALUE_CLASS_WITH_INT_ARRAY[0] = new ValueClassWithInt(5); - VALUE_CLASS_WITH_DOUBLE_ARRAY[0] = new ValueClassWithDouble(6); - SUB_VALUE_CLASS_WITH_INT_ARRAY[0] = new SubValueClassWithInt(7); - SUB_VALUE_CLASS_WITH_DOUBLE_ARRAY[0] = new SubValueClassWithDouble(8); + VALUE_CLASS_WITH_INT_ARRAY_NULL_RESTRICTED_NON_ATOMIC[0] = new ValueClassWithInt(5); + VALUE_CLASS_WITH_FLOAT_ARRAY_NULL_RESTRICTED_NON_ATOMIC[0] = new ValueClassWithFloat(6); + SUB_VALUE_CLASS_WITH_INT_ARRAY_NULL_RESTRICTED_NON_ATOMIC[0] = new SubValueClassWithInt(7); + SUB_VALUE_CLASS_WITH_FLOAT_ARRAY_NULL_RESTRICTED_NON_ATOMIC[0] = new SubValueClassWithFloat(8); + + VALUE_CLASS_WITH_INT_ARRAY_NULL_RESTRICTED_ATOMIC[0] = new ValueClassWithInt(5); + VALUE_CLASS_WITH_FLOAT_ARRAY_NULL_RESTRICTED_ATOMIC[0] = new ValueClassWithFloat(6); + SUB_VALUE_CLASS_WITH_INT_ARRAY_NULL_RESTRICTED_ATOMIC[0] = new SubValueClassWithInt(7); + SUB_VALUE_CLASS_WITH_FLOAT_ARRAY_NULL_RESTRICTED_ATOMIC[0] = new SubValueClassWithFloat(8); + + VALUE_CLASS_WITH_INT_ARRAY_NULLABLE_ATOMIC[0] = new ValueClassWithInt(5); + VALUE_CLASS_WITH_FLOAT_ARRAY_NULLABLE_ATOMIC[0] = new ValueClassWithFloat(6); + SUB_VALUE_CLASS_WITH_INT_ARRAY_NULLABLE_ATOMIC[0] = new SubValueClassWithInt(7); + SUB_VALUE_CLASS_WITH_FLOAT_ARRAY_NULLABLE_ATOMIC[0] = new SubValueClassWithFloat(8); + + VALUE_CLASS_WITH_INT_ARRAY_REF[0] = new ValueClassWithInt(5); + VALUE_CLASS_WITH_FLOAT_ARRAY_REF[0] = new ValueClassWithFloat(6); + SUB_VALUE_CLASS_WITH_INT_ARRAY_REF[0] = new SubValueClassWithInt(7); + SUB_VALUE_CLASS_WITH_FLOAT_ARRAY_REF[0] = new SubValueClassWithFloat(8); + } + + // Make sure the WhiteBox API is only loaded in the Test VM such that we can run this test in driver mode + static class Flags { + private static final WhiteBox WHITEBOX = WhiteBox.getWhiteBox(); + private static final boolean UseArrayFlattening = WHITEBOX.getBooleanVMFlag("UseArrayFlattening"); } @Test - static void testFlatArrayInexactObjectStore(Object o, boolean flag) { + static void testFlatArrayInexactObjectStore_NullRestricted_NonAtomic(Object o, boolean flag) { Object[] oArr; if (flag) { - oArr = VALUE_CLASS_WITH_INT_ARRAY; // VALUE_CLASS_WITH_INT_ARRAY is statically known to be flat. + oArr = VALUE_CLASS_WITH_INT_ARRAY_NULL_RESTRICTED_NON_ATOMIC; // VALUE_CLASS_WITH_INT_ARRAY_NULL_RESTRICTED_NON_ATOMIC is statically known to be flat. } else { - oArr = VALUE_CLASS_WITH_DOUBLE_ARRAY; // VALUE_CLASS_WITH_DOUBLE_ARRAY is statically known to be flat. + oArr = VALUE_CLASS_WITH_FLOAT_ARRAY_NULL_RESTRICTED_NON_ATOMIC; // VALUE_CLASS_WITH_FLOAT_ARRAY_NULL_RESTRICTED_NON_ATOMIC is statically known to be flat. } // The type of 'oArr' is inexact here because we merge two arrays. Since both arrays are flat, 'oArr' is also flat: // Type: flat:narrowoop: java/lang/Object:NotNull * (flat in array)[int:2] @@ -4673,12 +4708,12 @@ public class TestLWorld { } @Test - static Object testFlatArrayInexactObjectLoad(boolean flag) { + static Object testFlatArrayInexactObjectLoad_NullRestricted_NonAtomic(boolean flag) { Object[] oArr; if (flag) { - oArr = VALUE_CLASS_WITH_INT_ARRAY; // VALUE_CLASS_WITH_INT_ARRAY is statically known to be flat. + oArr = VALUE_CLASS_WITH_INT_ARRAY_NULL_RESTRICTED_NON_ATOMIC; // VALUE_CLASS_WITH_INT_ARRAY_NULL_RESTRICTED_NON_ATOMIC is statically known to be flat. } else { - oArr = VALUE_CLASS_WITH_DOUBLE_ARRAY; // VALUE_CLASS_WITH_DOUBLE_ARRAY is statically known to be flat. + oArr = VALUE_CLASS_WITH_FLOAT_ARRAY_NULL_RESTRICTED_NON_ATOMIC; // VALUE_CLASS_WITH_FLOAT_ARRAY_NULL_RESTRICTED_NON_ATOMIC is statically known to be flat. } // The type of 'oArr' is inexact here because we merge two arrays. Since both arrays are flat, 'oArr' is also flat: // Type: flat:narrowoop: java/lang/Object:NotNull * (flat in array)[int:2] @@ -4688,59 +4723,330 @@ public class TestLWorld { } @Test - static void testFlatArrayInexactAbstractValueClassStore(AbstractValueClassWithByte abstractValueClassWithByte, + static void testFlatArrayInexactAbstractValueClassStore_NullRestricted_NonAtomic(AbstractValueClassWithByte abstractValueClassWithByte, boolean flag) { AbstractValueClassWithByte[] avArr; if (flag) { - avArr = SUB_VALUE_CLASS_WITH_INT_ARRAY; + avArr = SUB_VALUE_CLASS_WITH_INT_ARRAY_NULL_RESTRICTED_NON_ATOMIC; } else { - avArr = SUB_VALUE_CLASS_WITH_DOUBLE_ARRAY; + avArr = SUB_VALUE_CLASS_WITH_FLOAT_ARRAY_NULL_RESTRICTED_NON_ATOMIC; } - // Same as testFlatArrayInexactObjectStore() but the inexact type is with an abstract value class: + // Same as testFlatArrayInexactObjectStore_NullRestricted_NonAtomic() but the inexact type is with an abstract value class: // flat:narrowoop: compiler/valhalla/inlinetypes/TestLWorld$AbstractValueClassWithByte:NotNull * (flat in array)[int:2] avArr[0] = abstractValueClassWithByte; } @Test - static AbstractValueClassWithByte testFlatArrayInexactAbstractValueClassLoad(boolean flag) { + static AbstractValueClassWithByte testFlatArrayInexactAbstractValueClassLoad_NullRestricted_NonAtomic(boolean flag) { AbstractValueClassWithByte[] avArr; if (flag) { - avArr = SUB_VALUE_CLASS_WITH_INT_ARRAY; + avArr = SUB_VALUE_CLASS_WITH_INT_ARRAY_NULL_RESTRICTED_NON_ATOMIC; } else { - avArr = SUB_VALUE_CLASS_WITH_DOUBLE_ARRAY; + avArr = SUB_VALUE_CLASS_WITH_FLOAT_ARRAY_NULL_RESTRICTED_NON_ATOMIC; } - // Same as testFlatArrayInexactObjectLoad() but the inexact type is with an abstract value class: + // Same as testFlatArrayInexactObjectLoad_NullRestricted_NonAtomic() but the inexact type is with an abstract value class: // flat:narrowoop: compiler/valhalla/inlinetypes/TestLWorld$AbstractValueClassWithByte:NotNull * (flat in array)[int:2] return avArr[0]; } - @Run(test = {"testFlatArrayInexactObjectStore", - "testFlatArrayInexactObjectLoad", - "testFlatArrayInexactAbstractValueClassStore", - "testFlatArrayInexactAbstractValueClassLoad"}) - static void runFlatArrayInexactLoadAndStore() { - boolean flag = true; + @Run(test = {"testFlatArrayInexactObjectStore_NullRestricted_NonAtomic", + "testFlatArrayInexactObjectLoad_NullRestricted_NonAtomic", + "testFlatArrayInexactAbstractValueClassStore_NullRestricted_NonAtomic", + "testFlatArrayInexactAbstractValueClassLoad_NullRestricted_NonAtomic"}) + static void runFlatArrayInexactLoadAndStore_NullRestricted_NonAtomic() { + Asserts.assertEQ(Flags.UseArrayFlattening, ValueClass.isFlatArray(VALUE_CLASS_WITH_INT_ARRAY_NULL_RESTRICTED_NON_ATOMIC)); + Asserts.assertEQ(Flags.UseArrayFlattening, ValueClass.isFlatArray(VALUE_CLASS_WITH_FLOAT_ARRAY_NULL_RESTRICTED_NON_ATOMIC)); + Asserts.assertEQ(Flags.UseArrayFlattening, ValueClass.isFlatArray(SUB_VALUE_CLASS_WITH_INT_ARRAY_NULL_RESTRICTED_NON_ATOMIC)); + Asserts.assertEQ(Flags.UseArrayFlattening, ValueClass.isFlatArray(SUB_VALUE_CLASS_WITH_FLOAT_ARRAY_NULL_RESTRICTED_NON_ATOMIC)); + ValueClassWithInt valueClassWithInt = new ValueClassWithInt(15); - ValueClassWithDouble valueClassWithDouble = new ValueClassWithDouble(16); + ValueClassWithFloat ValueClassWithFloat = new ValueClassWithFloat(16); - testFlatArrayInexactObjectStore(valueClassWithInt, true); - Asserts.assertEQ(valueClassWithInt, VALUE_CLASS_WITH_INT_ARRAY[0]); - testFlatArrayInexactObjectStore(valueClassWithDouble, false); - Asserts.assertEQ(valueClassWithDouble, VALUE_CLASS_WITH_DOUBLE_ARRAY[0]); + testFlatArrayInexactObjectStore_NullRestricted_NonAtomic(valueClassWithInt, true); + Asserts.assertEQ(valueClassWithInt, VALUE_CLASS_WITH_INT_ARRAY_NULL_RESTRICTED_NON_ATOMIC[0]); + testFlatArrayInexactObjectStore_NullRestricted_NonAtomic(ValueClassWithFloat, false); + Asserts.assertEQ(ValueClassWithFloat, VALUE_CLASS_WITH_FLOAT_ARRAY_NULL_RESTRICTED_NON_ATOMIC[0]); - Asserts.assertEQ(valueClassWithInt, testFlatArrayInexactObjectLoad(true)); - Asserts.assertEQ(valueClassWithDouble, testFlatArrayInexactObjectLoad(false)); + Asserts.assertEQ(valueClassWithInt, testFlatArrayInexactObjectLoad_NullRestricted_NonAtomic(true)); + Asserts.assertEQ(ValueClassWithFloat, testFlatArrayInexactObjectLoad_NullRestricted_NonAtomic(false)); SubValueClassWithInt subValueClassWithInt = new SubValueClassWithInt(17); - SubValueClassWithDouble subValueClassWithDouble = new SubValueClassWithDouble(18); + SubValueClassWithFloat subValueClassWithFloat = new SubValueClassWithFloat(18); - testFlatArrayInexactAbstractValueClassStore(subValueClassWithInt, true); - Asserts.assertEQ(subValueClassWithInt, SUB_VALUE_CLASS_WITH_INT_ARRAY[0]); - testFlatArrayInexactAbstractValueClassStore(subValueClassWithDouble, false); - Asserts.assertEQ(subValueClassWithDouble, SUB_VALUE_CLASS_WITH_DOUBLE_ARRAY[0]); + testFlatArrayInexactAbstractValueClassStore_NullRestricted_NonAtomic(subValueClassWithInt, true); + Asserts.assertEQ(subValueClassWithInt, SUB_VALUE_CLASS_WITH_INT_ARRAY_NULL_RESTRICTED_NON_ATOMIC[0]); + testFlatArrayInexactAbstractValueClassStore_NullRestricted_NonAtomic(subValueClassWithFloat, false); + Asserts.assertEQ(subValueClassWithFloat, SUB_VALUE_CLASS_WITH_FLOAT_ARRAY_NULL_RESTRICTED_NON_ATOMIC[0]); - Asserts.assertEQ(subValueClassWithInt, testFlatArrayInexactAbstractValueClassLoad(true)); - Asserts.assertEQ(subValueClassWithDouble, testFlatArrayInexactAbstractValueClassLoad(false)); + Asserts.assertEQ(subValueClassWithInt, testFlatArrayInexactAbstractValueClassLoad_NullRestricted_NonAtomic(true)); + Asserts.assertEQ(subValueClassWithFloat, testFlatArrayInexactAbstractValueClassLoad_NullRestricted_NonAtomic(false)); + } + + @Test + static void testFlatArrayInexactObjectStore_NullRestricted_Atomic(Object o, boolean flag) { + Object[] oArr; + if (flag) { + oArr = VALUE_CLASS_WITH_INT_ARRAY_NULL_RESTRICTED_ATOMIC; // VALUE_CLASS_WITH_INT_ARRAY_NULL_RESTRICTED_ATOMIC is statically known to be flat. + } else { + oArr = VALUE_CLASS_WITH_FLOAT_ARRAY_NULL_RESTRICTED_ATOMIC; // VALUE_CLASS_WITH_FLOAT_ARRAY_NULL_RESTRICTED_ATOMIC is statically known to be flat. + } + // The type of 'oArr' is inexact here because we merge two arrays. Since both arrays are flat, 'oArr' is also flat: + // Type: flat:narrowoop: java/lang/Object:NotNull * (flat in array)[int:2] + // Since the type is inexact, we do not know the exact flat array layout statically and thus need to fall back + // to call "store_unknown_inline_Type()" at runtime where we know the flat array layout + oArr[0] = o; + } + + @Test + static Object testFlatArrayInexactObjectLoad_NullRestricted_Atomic(boolean flag) { + Object[] oArr; + if (flag) { + oArr = VALUE_CLASS_WITH_INT_ARRAY_NULL_RESTRICTED_ATOMIC; // VALUE_CLASS_WITH_INT_ARRAY is statically known to be flat. + } else { + oArr = VALUE_CLASS_WITH_FLOAT_ARRAY_NULL_RESTRICTED_ATOMIC; // VALUE_CLASS_WITH_FLOAT_ARRAY is statically known to be flat. + } + // The type of 'oArr' is inexact here because we merge two arrays. Since both arrays are flat, 'oArr' is also flat: + // Type: flat:narrowoop: java/lang/Object:NotNull * (flat in array)[int:2] + // Since the type is inexact, we do not know the exact flat array layout statically and thus need to fall back + // to call "load_unknown_inline_Type()" at runtime where we know the flat array layout + return oArr[0]; + } + + @Test + static void testFlatArrayInexactAbstractValueClassStore_NullRestricted_Atomic(AbstractValueClassWithByte abstractValueClassWithByte, boolean flag) { + AbstractValueClassWithByte[] avArr; + if (flag) { + avArr = SUB_VALUE_CLASS_WITH_INT_ARRAY_NULL_RESTRICTED_ATOMIC; + } else { + avArr = SUB_VALUE_CLASS_WITH_FLOAT_ARRAY_NULL_RESTRICTED_ATOMIC; + } + // Same as testFlatArrayInexactObjectStore_NullRestricted_Atomic() but the inexact type is with an abstract value class: + // flat:narrowoop: compiler/valhalla/inlinetypes/TestLWorld$AbstractValueClassWithByte:NotNull * (flat in array)[int:2] + avArr[0] = abstractValueClassWithByte; + } + + @Test + static AbstractValueClassWithByte testFlatArrayInexactAbstractValueClassLoad_NullRestricted_Atomic(boolean flag) { + AbstractValueClassWithByte[] avArr; + if (flag) { + avArr = SUB_VALUE_CLASS_WITH_INT_ARRAY_NULL_RESTRICTED_ATOMIC; + } else { + avArr = SUB_VALUE_CLASS_WITH_FLOAT_ARRAY_NULL_RESTRICTED_ATOMIC; + } + // Same as testFlatArrayInexactObjectLoad_NullRestricted_Atomic() but the inexact type is with an abstract value class: + // flat:narrowoop: compiler/valhalla/inlinetypes/TestLWorld$AbstractValueClassWithByte:NotNull * (flat in array)[int:2] + return avArr[0]; + } + + @Run(test = {"testFlatArrayInexactObjectStore_NullRestricted_Atomic", + "testFlatArrayInexactObjectLoad_NullRestricted_Atomic", + "testFlatArrayInexactAbstractValueClassStore_NullRestricted_Atomic", + "testFlatArrayInexactAbstractValueClassLoad_NullRestricted_Atomic"}) + static void runFlatArrayInexactLoadAndStore_NullRestricted_Atomic() { + Asserts.assertEQ(Flags.UseArrayFlattening, ValueClass.isFlatArray(VALUE_CLASS_WITH_INT_ARRAY_NULL_RESTRICTED_ATOMIC)); + Asserts.assertEQ(Flags.UseArrayFlattening, ValueClass.isFlatArray(VALUE_CLASS_WITH_FLOAT_ARRAY_NULL_RESTRICTED_ATOMIC)); + Asserts.assertEQ(Flags.UseArrayFlattening, ValueClass.isFlatArray(SUB_VALUE_CLASS_WITH_INT_ARRAY_NULL_RESTRICTED_ATOMIC)); + Asserts.assertEQ(Flags.UseArrayFlattening, ValueClass.isFlatArray(SUB_VALUE_CLASS_WITH_FLOAT_ARRAY_NULL_RESTRICTED_ATOMIC)); + + ValueClassWithInt valueClassWithInt = new ValueClassWithInt(15); + ValueClassWithFloat ValueClassWithFloat = new ValueClassWithFloat(16); + + testFlatArrayInexactObjectStore_NullRestricted_Atomic(valueClassWithInt, true); + Asserts.assertEQ(valueClassWithInt, VALUE_CLASS_WITH_INT_ARRAY_NULL_RESTRICTED_ATOMIC[0]); + testFlatArrayInexactObjectStore_NullRestricted_Atomic(ValueClassWithFloat, false); + Asserts.assertEQ(ValueClassWithFloat, VALUE_CLASS_WITH_FLOAT_ARRAY_NULL_RESTRICTED_ATOMIC[0]); + + Asserts.assertEQ(valueClassWithInt, testFlatArrayInexactObjectLoad_NullRestricted_Atomic(true)); + Asserts.assertEQ(ValueClassWithFloat, testFlatArrayInexactObjectLoad_NullRestricted_Atomic(false)); + + SubValueClassWithInt subValueClassWithInt = new SubValueClassWithInt(17); + SubValueClassWithFloat subValueClassWithFloat = new SubValueClassWithFloat(18); + + testFlatArrayInexactAbstractValueClassStore_NullRestricted_Atomic(subValueClassWithInt, true); + Asserts.assertEQ(subValueClassWithInt, SUB_VALUE_CLASS_WITH_INT_ARRAY_NULL_RESTRICTED_ATOMIC[0]); + testFlatArrayInexactAbstractValueClassStore_NullRestricted_Atomic(subValueClassWithFloat, false); + Asserts.assertEQ(subValueClassWithFloat, SUB_VALUE_CLASS_WITH_FLOAT_ARRAY_NULL_RESTRICTED_ATOMIC[0]); + + Asserts.assertEQ(subValueClassWithInt, testFlatArrayInexactAbstractValueClassLoad_NullRestricted_Atomic(true)); + Asserts.assertEQ(subValueClassWithFloat, testFlatArrayInexactAbstractValueClassLoad_NullRestricted_Atomic(false)); + } + + @Test + static void testFlatArrayInexactObjectStore_Nullable_Atomic(Object o, boolean flag) { + Object[] oArr; + if (flag) { + oArr = VALUE_CLASS_WITH_INT_ARRAY_NULLABLE_ATOMIC; // VALUE_CLASS_WITH_INT_ARRAY_NULLABLE_ATOMIC is statically known to be flat. + } else { + oArr = VALUE_CLASS_WITH_FLOAT_ARRAY_NULLABLE_ATOMIC; // VALUE_CLASS_WITH_FLOAT_ARRAY_NULLABLE_ATOMIC is statically known to be flat. + } + // The type of 'oArr' is inexact here because we merge two arrays. Since both arrays are flat, 'oArr' is also flat: + // Type: flat:narrowoop: java/lang/Object:NotNull * (flat in array)[int:2] + // Since the type is inexact, we do not know the exact flat array layout statically and thus need to fall back + // to call "store_unknown_inline_Type()" at runtime where we know the flat array layout + oArr[0] = o; + } + + @Test + static Object testFlatArrayInexactObjectLoad_Nullable_Atomic(boolean flag) { + Object[] oArr; + if (flag) { + oArr = VALUE_CLASS_WITH_INT_ARRAY_NULLABLE_ATOMIC; // VALUE_CLASS_WITH_INT_ARRAY_NULLABLE_ATOMIC is statically known to be flat. + } else { + oArr = VALUE_CLASS_WITH_FLOAT_ARRAY_NULLABLE_ATOMIC; // VALUE_CLASS_WITH_FLOAT_ARRAY_NULLABLE_ATOMIC is statically known to be flat. + } + // The type of 'oArr' is inexact here because we merge two arrays. Since both arrays are flat, 'oArr' is also flat: + // Type: flat:narrowoop: java/lang/Object:NotNull * (flat in array)[int:2] + // Since the type is inexact, we do not know the exact flat array layout statically and thus need to fall back + // to call "load_unknown_inline_Type()" at runtime where we know the flat array layout + return oArr[0]; + } + + @Test + static void testFlatArrayInexactAbstractValueClassStore_Nullable_Atomic(AbstractValueClassWithByte abstractValueClassWithByte, boolean flag) { + AbstractValueClassWithByte[] avArr; + if (flag) { + avArr = SUB_VALUE_CLASS_WITH_INT_ARRAY_NULLABLE_ATOMIC; + } else { + avArr = SUB_VALUE_CLASS_WITH_FLOAT_ARRAY_NULLABLE_ATOMIC; + } + // Same as testFlatArrayInexactObjectStore_Nullable_Atomic() but the inexact type is with an abstract value class: + // flat:narrowoop: compiler/valhalla/inlinetypes/TestLWorld$AbstractValueClassWithByte:NotNull * (flat in array)[int:2] + avArr[0] = abstractValueClassWithByte; + } + + @Test + static AbstractValueClassWithByte testFlatArrayInexactAbstractValueClassLoad_Nullable_Atomic(boolean flag) { + AbstractValueClassWithByte[] avArr; + if (flag) { + avArr = SUB_VALUE_CLASS_WITH_INT_ARRAY_NULLABLE_ATOMIC; + } else { + avArr = SUB_VALUE_CLASS_WITH_FLOAT_ARRAY_NULLABLE_ATOMIC; + } + // Same as testFlatArrayInexactObjectLoad_Nullable_Atomic() but the inexact type is with an abstract value class: + // flat:narrowoop: compiler/valhalla/inlinetypes/TestLWorld$AbstractValueClassWithByte:NotNull * (flat in array)[int:2] + return avArr[0]; + } + + @Run(test = {"testFlatArrayInexactObjectStore_Nullable_Atomic", + "testFlatArrayInexactObjectLoad_Nullable_Atomic", + "testFlatArrayInexactAbstractValueClassStore_Nullable_Atomic", + "testFlatArrayInexactAbstractValueClassLoad_Nullable_Atomic"}) + static void runFlatArrayInexactLoadAndStore_Nullable_Atomic() { + Asserts.assertEQ(Flags.UseArrayFlattening, ValueClass.isFlatArray(VALUE_CLASS_WITH_INT_ARRAY_NULLABLE_ATOMIC)); + Asserts.assertEQ(Flags.UseArrayFlattening, ValueClass.isFlatArray(VALUE_CLASS_WITH_FLOAT_ARRAY_NULLABLE_ATOMIC)); + Asserts.assertEQ(Flags.UseArrayFlattening, ValueClass.isFlatArray(SUB_VALUE_CLASS_WITH_INT_ARRAY_NULLABLE_ATOMIC)); + Asserts.assertEQ(Flags.UseArrayFlattening, ValueClass.isFlatArray(SUB_VALUE_CLASS_WITH_FLOAT_ARRAY_NULLABLE_ATOMIC)); + + ValueClassWithInt valueClassWithInt = new ValueClassWithInt(15); + ValueClassWithFloat ValueClassWithFloat = new ValueClassWithFloat(16); + + testFlatArrayInexactObjectStore_Nullable_Atomic(valueClassWithInt, true); + Asserts.assertEQ(valueClassWithInt, VALUE_CLASS_WITH_INT_ARRAY_NULLABLE_ATOMIC[0]); + testFlatArrayInexactObjectStore_Nullable_Atomic(ValueClassWithFloat, false); + Asserts.assertEQ(ValueClassWithFloat, VALUE_CLASS_WITH_FLOAT_ARRAY_NULLABLE_ATOMIC[0]); + + Asserts.assertEQ(valueClassWithInt, testFlatArrayInexactObjectLoad_Nullable_Atomic(true)); + Asserts.assertEQ(ValueClassWithFloat, testFlatArrayInexactObjectLoad_Nullable_Atomic(false)); + + SubValueClassWithInt subValueClassWithInt = new SubValueClassWithInt(17); + SubValueClassWithFloat subValueClassWithFloat = new SubValueClassWithFloat(18); + + testFlatArrayInexactAbstractValueClassStore_Nullable_Atomic(subValueClassWithInt, true); + Asserts.assertEQ(subValueClassWithInt, SUB_VALUE_CLASS_WITH_INT_ARRAY_NULLABLE_ATOMIC[0]); + testFlatArrayInexactAbstractValueClassStore_Nullable_Atomic(subValueClassWithFloat, false); + Asserts.assertEQ(subValueClassWithFloat, SUB_VALUE_CLASS_WITH_FLOAT_ARRAY_NULLABLE_ATOMIC[0]); + + Asserts.assertEQ(subValueClassWithInt, testFlatArrayInexactAbstractValueClassLoad_Nullable_Atomic(true)); + Asserts.assertEQ(subValueClassWithFloat, testFlatArrayInexactAbstractValueClassLoad_Nullable_Atomic(false)); + } + + @Test + static void testFlatArrayInexactObjectStore_Ref(Object o, boolean flag) { + Object[] oArr; + if (flag) { + oArr = VALUE_CLASS_WITH_INT_ARRAY_REF; // VALUE_CLASS_WITH_INT_ARRAY_REF is statically known not to be flat. + } else { + oArr = VALUE_CLASS_WITH_FLOAT_ARRAY_REF; // VALUE_CLASS_WITH_FLOAT_ARRAY_REF is statically known not to be flat. + } + // The type of 'oArr' is inexact here because we merge two arrays. Since both arrays are flat, 'oArr' is also flat: + // Type: flat:narrowoop: java/lang/Object:NotNull * (flat in array)[int:2] + // Since the type is inexact, we do not know the exact flat array layout statically and thus need to fall back + // to call "store_unknown_inline_Type()" at runtime where we know the flat array layout + oArr[0] = o; + } + + @Test + static Object testFlatArrayInexactObjectLoad_Ref(boolean flag) { + Object[] oArr; + if (flag) { + oArr = VALUE_CLASS_WITH_INT_ARRAY_REF; // VALUE_CLASS_WITH_INT_ARRAY_REF is statically known not to be flat. + } else { + oArr = VALUE_CLASS_WITH_FLOAT_ARRAY_REF; // VALUE_CLASS_WITH_FLOAT_ARRAY_REF is statically known not to be flat. + } + // The type of 'oArr' is inexact here because we merge two arrays. Since both arrays are flat, 'oArr' is also flat: + // Type: flat:narrowoop: java/lang/Object:NotNull * (flat in array)[int:2] + // Since the type is inexact, we do not know the exact flat array layout statically and thus need to fall back + // to call "load_unknown_inline_Type()" at runtime where we know the flat array layout + return oArr[0]; + } + + @Test + static void testFlatArrayInexactAbstractValueClassStore_Ref(AbstractValueClassWithByte abstractValueClassWithByte, boolean flag) { + AbstractValueClassWithByte[] avArr; + if (flag) { + avArr = SUB_VALUE_CLASS_WITH_INT_ARRAY_REF; + } else { + avArr = SUB_VALUE_CLASS_WITH_FLOAT_ARRAY_REF; + } + // Same as testFlatArrayInexactObjectStore_Ref() but the inexact type is with an abstract value class: + // flat:narrowoop: compiler/valhalla/inlinetypes/TestLWorld$AbstractValueClassWithByte:NotNull * (flat in array)[int:2] + avArr[0] = abstractValueClassWithByte; + } + + @Test + static AbstractValueClassWithByte testFlatArrayInexactAbstractValueClassLoad_Ref(boolean flag) { + AbstractValueClassWithByte[] avArr; + if (flag) { + avArr = SUB_VALUE_CLASS_WITH_INT_ARRAY_REF; + } else { + avArr = SUB_VALUE_CLASS_WITH_FLOAT_ARRAY_REF; + } + // Same as testFlatArrayInexactObjectLoad_Ref() but the inexact type is with an abstract value class: + // flat:narrowoop: compiler/valhalla/inlinetypes/TestLWorld$AbstractValueClassWithByte:NotNull * (flat in array)[int:2] + return avArr[0]; + } + + @Run(test = {"testFlatArrayInexactObjectStore_Ref", + "testFlatArrayInexactObjectLoad_Ref", + "testFlatArrayInexactAbstractValueClassStore_Ref", + "testFlatArrayInexactAbstractValueClassLoad_Ref"}) + static void runFlatArrayInexactLoadAndStore_Ref() { + Asserts.assertFalse(ValueClass.isFlatArray(VALUE_CLASS_WITH_INT_ARRAY_REF)); + Asserts.assertFalse(ValueClass.isFlatArray(VALUE_CLASS_WITH_FLOAT_ARRAY_REF)); + Asserts.assertFalse(ValueClass.isFlatArray(SUB_VALUE_CLASS_WITH_INT_ARRAY_REF)); + Asserts.assertFalse(ValueClass.isFlatArray(SUB_VALUE_CLASS_WITH_FLOAT_ARRAY_REF)); + + ValueClassWithInt valueClassWithInt = new ValueClassWithInt(15); + ValueClassWithFloat ValueClassWithFloat = new ValueClassWithFloat(16); + + testFlatArrayInexactObjectStore_Ref(valueClassWithInt, true); + Asserts.assertEQ(valueClassWithInt, VALUE_CLASS_WITH_INT_ARRAY_REF[0]); + testFlatArrayInexactObjectStore_Ref(ValueClassWithFloat, false); + Asserts.assertEQ(ValueClassWithFloat, VALUE_CLASS_WITH_FLOAT_ARRAY_REF[0]); + + Asserts.assertEQ(valueClassWithInt, testFlatArrayInexactObjectLoad_Ref(true)); + Asserts.assertEQ(ValueClassWithFloat, testFlatArrayInexactObjectLoad_Ref(false)); + + SubValueClassWithInt subValueClassWithInt = new SubValueClassWithInt(17); + SubValueClassWithFloat subValueClassWithFloat = new SubValueClassWithFloat(18); + + testFlatArrayInexactAbstractValueClassStore_Ref(subValueClassWithInt, true); + Asserts.assertEQ(subValueClassWithInt, SUB_VALUE_CLASS_WITH_INT_ARRAY_REF[0]); + testFlatArrayInexactAbstractValueClassStore_Ref(subValueClassWithFloat, false); + Asserts.assertEQ(subValueClassWithFloat, SUB_VALUE_CLASS_WITH_FLOAT_ARRAY_REF[0]); + + Asserts.assertEQ(subValueClassWithInt, testFlatArrayInexactAbstractValueClassLoad_Ref(true)); + Asserts.assertEQ(subValueClassWithFloat, testFlatArrayInexactAbstractValueClassLoad_Ref(false)); } // Check that comparisons between Java mirrors are optimized to comparisons of the klass From 8529531bcf3cfadb371e221ab9abb6c3ef280655 Mon Sep 17 00:00:00 2001 From: Marc Chevalier Date: Thu, 16 Jul 2026 11:02:33 +0200 Subject: [PATCH 14/20] Remove comment --- test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestLWorld.java | 1 - 1 file changed, 1 deletion(-) diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestLWorld.java b/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestLWorld.java index bd79eba29e2..bea5884be24 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestLWorld.java +++ b/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestLWorld.java @@ -4643,7 +4643,6 @@ public class TestLWorld { } } - // TODO 8350865 We need more copies of these tests for all ValueClass array factories static final ValueClassWithInt[] VALUE_CLASS_WITH_INT_ARRAY_NULL_RESTRICTED_NON_ATOMIC = (ValueClassWithInt[]) ValueClass.newNullRestrictedNonAtomicArray(ValueClassWithInt.class, 2, new ValueClassWithInt(0)); static final ValueClassWithFloat[] VALUE_CLASS_WITH_FLOAT_ARRAY_NULL_RESTRICTED_NON_ATOMIC = (ValueClassWithFloat[]) ValueClass.newNullRestrictedNonAtomicArray(ValueClassWithFloat.class, 2, new ValueClassWithFloat(0)); static final SubValueClassWithInt[] SUB_VALUE_CLASS_WITH_INT_ARRAY_NULL_RESTRICTED_NON_ATOMIC = (SubValueClassWithInt[]) ValueClass.newNullRestrictedNonAtomicArray(SubValueClassWithInt.class, 2, new SubValueClassWithInt(0)); From 1b39838c600ea037813869c15ddab7cc50304b7b Mon Sep 17 00:00:00 2001 From: Marc Chevalier Date: Thu, 16 Jul 2026 11:06:02 +0200 Subject: [PATCH 15/20] Remove comment --- src/hotspot/share/opto/subtypenode.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/hotspot/share/opto/subtypenode.cpp b/src/hotspot/share/opto/subtypenode.cpp index c759b948299..91076d0cef7 100644 --- a/src/hotspot/share/opto/subtypenode.cpp +++ b/src/hotspot/share/opto/subtypenode.cpp @@ -47,7 +47,6 @@ const Type* SubTypeCheckNode::sub(const Type* sub_t, const Type* super_t) const } } - // TODO 8350865 Shouldn't this be encoded in helper methods of the type system (maybe_java_subtype_of() etc.?) // Similar to logic in CmpPNode::sub() bool unrelated_classes = false; From 9b2a82a9c52d0efec51e0b7d318ef1f29221bbe9 Mon Sep 17 00:00:00 2001 From: Marc Chevalier Date: Fri, 17 Jul 2026 10:23:57 +0200 Subject: [PATCH 16/20] Remove TODO --- src/hotspot/share/opto/graphKit.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/hotspot/share/opto/graphKit.cpp b/src/hotspot/share/opto/graphKit.cpp index 1c4d96c6526..6a3b5e6723b 100644 --- a/src/hotspot/share/opto/graphKit.cpp +++ b/src/hotspot/share/opto/graphKit.cpp @@ -3984,7 +3984,6 @@ Node* GraphKit::null_free_array_test(Node* array, bool null_free) { Node* GraphKit::null_free_atomic_array_test(Node* array, ciInlineKlass* vk) { assert(vk->has_null_free_atomic_layout() || vk->has_null_free_non_atomic_layout(), "Can't be null-free and flat"); - // TODO 8350865 Add a stress flag to always access atomic if layout exists? if (!vk->has_null_free_non_atomic_layout()) { return intcon(1); // Always atomic } else if (!vk->has_null_free_atomic_layout()) { From 4a45eae03fd1bd0289b53bc4bb279e32e73cd465 Mon Sep 17 00:00:00 2001 From: Marc Chevalier Date: Fri, 17 Jul 2026 11:05:22 +0200 Subject: [PATCH 17/20] Change number --- src/hotspot/share/opto/library_call.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp index ad0a720c211..ec407fee384 100644 --- a/src/hotspot/share/opto/library_call.cpp +++ b/src/hotspot/share/opto/library_call.cpp @@ -2740,7 +2740,7 @@ bool LibraryCallKit::inline_unsafe_flat_access(bool is_store, AccessKind kind) { if (layout == LayoutKind::REFERENCE) { if (!base_type->is_aryptr()->is_not_flat()) { const TypeAryPtr* array_type = base_type->is_aryptr()->cast_to_not_flat(); - // TODO 8350865 This should be a CheckCastPP, can we add a test? + // TODO 8388444 This should be a CheckCastPP, can we add a test? Node* new_base = _gvn.transform(new CastPPNode(control(), base, array_type, ConstraintCastNode::DependencyType::NonFloatingNarrowing)); replace_in_map(base, new_base); base = new_base; @@ -2757,7 +2757,7 @@ bool LibraryCallKit::inline_unsafe_flat_access(bool is_store, AccessKind kind) { ptr = basic_plus_adr(base, ConvL2X(offset)); const TypeAryPtr* ptr_type = _gvn.type(ptr)->is_aryptr(); if (ptr_type->field_offset().get() != 0) { - // TODO 8350865 This should be a CheckCastPP, can we add a test? + // TODO 8388444 This should be a CheckCastPP, can we add a test? ptr = _gvn.transform(new CastPPNode(control(), ptr, ptr_type->with_field_offset(0), ConstraintCastNode::DependencyType::NonFloatingNarrowing)); } } else { From 618f64cab40186ee45ab45aa025f9ba930b43445 Mon Sep 17 00:00:00 2001 From: Marc Chevalier Date: Mon, 6 Jul 2026 11:10:05 +0200 Subject: [PATCH 18/20] Trying something --- src/hotspot/share/ci/ciTypeFlow.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/ci/ciTypeFlow.cpp b/src/hotspot/share/ci/ciTypeFlow.cpp index 073e2788ba2..257e4d57752 100644 --- a/src/hotspot/share/ci/ciTypeFlow.cpp +++ b/src/hotspot/share/ci/ciTypeFlow.cpp @@ -608,7 +608,11 @@ void ciTypeFlow::StateVector::do_aload(ciBytecodeStream* str) { (Deoptimization::Reason_unloaded, Deoptimization::Action_reinterpret)); } else { - push_object(element_klass); + ciType* maybe_null_free_element_klass = element_klass; + if (array_klass->is_null_free()) { + maybe_null_free_element_klass = outer()->mark_as_null_free(element_klass); + } + push(maybe_null_free_element_klass); } } From e8e782c1787fbe99d516174502dedb527cff2a3d Mon Sep 17 00:00:00 2001 From: Marc Chevalier Date: Thu, 16 Jul 2026 10:30:02 +0200 Subject: [PATCH 19/20] Remove comment --- src/hotspot/share/ci/ciTypeFlow.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/hotspot/share/ci/ciTypeFlow.cpp b/src/hotspot/share/ci/ciTypeFlow.cpp index 257e4d57752..a34692b1d48 100644 --- a/src/hotspot/share/ci/ciTypeFlow.cpp +++ b/src/hotspot/share/ci/ciTypeFlow.cpp @@ -600,7 +600,6 @@ void ciTypeFlow::StateVector::do_aload(ciBytecodeStream* str) { return; } ciKlass* element_klass = array_klass->element_klass(); - // TODO 8350865 Can we check that array_klass is null_free and use mark_as_null_free on the result here? if (!element_klass->is_loaded() && element_klass->is_instance_klass()) { Untested("unloaded array element class in ciTypeFlow"); trap(str, element_klass, From 8683e5b47e4729b147beac55161066c4fb9c896b Mon Sep 17 00:00:00 2001 From: Marc Chevalier Date: Mon, 20 Jul 2026 10:16:04 +0200 Subject: [PATCH 20/20] Trying a better fix --- src/hotspot/share/ci/ciTypeFlow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/share/ci/ciTypeFlow.cpp b/src/hotspot/share/ci/ciTypeFlow.cpp index a34692b1d48..77054bafbbc 100644 --- a/src/hotspot/share/ci/ciTypeFlow.cpp +++ b/src/hotspot/share/ci/ciTypeFlow.cpp @@ -608,7 +608,7 @@ void ciTypeFlow::StateVector::do_aload(ciBytecodeStream* str) { Deoptimization::Action_reinterpret)); } else { ciType* maybe_null_free_element_klass = element_klass; - if (array_klass->is_null_free()) { + if (array_klass->is_refined() && array_klass->is_elem_null_free()) { maybe_null_free_element_klass = outer()->mark_as_null_free(element_klass); } push(maybe_null_free_element_klass);