Skip to content

Commit c65b458

Browse files
committed
8356599: [lworld] C2 incorrectly folds array object klass load for atomic arrays
8355941: [lworld] TestArrayAccessDeopt.java fails due to unexpected deoptimization
1 parent 1163cc6 commit c65b458

File tree

13 files changed

+153
-53
lines changed

13 files changed

+153
-53
lines changed

src/hotspot/share/ci/ciArrayKlass.cpp

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -117,9 +117,6 @@ ciArrayKlass* ciArrayKlass::make(ciType* element_type, bool flat, bool null_free
117117
if (flat && vk->maybe_flat_in_array()) {
118118
LayoutKind lk;
119119
if (null_free) {
120-
if (vk->is_naturally_atomic()) {
121-
atomic = vk->has_atomic_layout();
122-
}
123120
if (!atomic && !vk->has_non_atomic_layout()) {
124121
// TODO 8350865 Impossible type
125122
lk = vk->has_atomic_layout() ? LayoutKind::ATOMIC_FLAT : LayoutKind::NULLABLE_ATOMIC_FLAT;

src/hotspot/share/ci/ciKlass.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,11 @@ void ciKlass::print_impl(outputStream* st) {
251251
st->print(" name=");
252252
print_name_on(st);
253253
st->print(" loaded=%s", (is_loaded() ? "true" : "false"));
254+
GUARDED_VM_ENTRY(
255+
if (is_flat_array_klass()) {
256+
st->print(" layout_kind=%d", (int)((FlatArrayKlass*)get_Klass())->layout_kind());
257+
}
258+
)
254259
}
255260

256261
// ------------------------------------------------------------------

src/hotspot/share/opto/graphKit.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1227,12 +1227,12 @@ Node* GraphKit::ConvL2I(Node* offset) {
12271227
}
12281228

12291229
//-------------------------load_object_klass-----------------------------------
1230-
Node* GraphKit::load_object_klass(Node* obj) {
1230+
Node* GraphKit::load_object_klass(Node* obj, bool fold_for_arrays) {
12311231
// Special-case a fresh allocation to avoid building nodes:
12321232
Node* akls = AllocateNode::Ideal_klass(obj, &_gvn);
12331233
if (akls != nullptr) return akls;
12341234
Node* k_adr = basic_plus_adr(obj, oopDesc::klass_offset_in_bytes());
1235-
return _gvn.transform(LoadKlassNode::make(_gvn, immutable_memory(), k_adr, TypeInstPtr::KLASS, TypeInstKlassPtr::OBJECT));
1235+
return _gvn.transform(LoadKlassNode::make(_gvn, immutable_memory(), k_adr, TypeInstPtr::KLASS, TypeInstKlassPtr::OBJECT, fold_for_arrays));
12361236
}
12371237

12381238
//-------------------------load_array_length-----------------------------------
@@ -3787,7 +3787,8 @@ Node* GraphKit::null_free_atomic_array_test(Node* array, ciInlineKlass* vk) {
37873787
return intcon(0); // Never atomic
37883788
}
37893789

3790-
Node* array_klass = load_object_klass(array);
3790+
// TODO 8350865 Don't fold this klass load because atomicity is currently not included in the typesystem
3791+
Node* array_klass = load_object_klass(array, /* fold_for_arrays = */ false);
37913792
int layout_kind_offset = in_bytes(FlatArrayKlass::layout_kind_offset());
37923793
Node* layout_kind_addr = basic_plus_adr(array_klass, array_klass, layout_kind_offset);
37933794
Node* layout_kind = make_load(nullptr, layout_kind_addr, TypeInt::INT, T_INT, MemNode::unordered);

src/hotspot/share/opto/graphKit.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -355,7 +355,7 @@ class GraphKit : public Phase {
355355
Node* ConvI2UL(Node* offset);
356356
Node* ConvL2I(Node* offset);
357357
// Find out the klass of an object.
358-
Node* load_object_klass(Node* object);
358+
Node* load_object_klass(Node* object, bool fold_for_arrays = true);
359359
// Find out the length of an array.
360360
Node* load_array_length(Node* array);
361361
// Cast array allocation's length as narrow as possible.

src/hotspot/share/opto/inlinetypenode.cpp

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1302,9 +1302,9 @@ InlineTypeNode* InlineTypeNode::make_from_flat_impl(GraphKit* kit, ciInlineKlass
13021302
bool null_free = (null_marker_offset == -1);
13031303
InlineTypeNode* vt = make_uninitialized(kit->gvn(), vk, null_free);
13041304

1305+
bool is_array = (kit->gvn().type(obj)->isa_aryptr() != nullptr);
13051306
if (atomic) {
13061307
// Read atomically and convert from payload
1307-
bool is_array = (kit->gvn().type(obj)->isa_aryptr() != nullptr);
13081308
#ifdef ASSERT
13091309
bool is_naturally_atomic = (!is_array && vk->is_empty()) || (null_free && vk->nof_declared_nonstatic_fields() == 1);
13101310
assert(!is_naturally_atomic, "No atomic access required");
@@ -1342,21 +1342,22 @@ InlineTypeNode* InlineTypeNode::make_from_flat_impl(GraphKit* kit, ciInlineKlass
13421342
Node* bol = kit->null_free_array_test(obj); // Argument evaluation order is undefined in C++ and since this sets control, it needs to come first
13431343
IfNode* iff = kit->create_and_map_if(kit->control(), bol, PROB_FAIR, COUNT_UNKNOWN);
13441344

1345-
kit->set_control(kit->IfFalse(iff));
1346-
region->init_req(1, kit->control());
1347-
13481345
// Nullable
1346+
kit->set_control(kit->IfFalse(iff));
13491347
if (!kit->stopped()) {
13501348
assert(!null_free && vk->has_nullable_atomic_layout(), "Flat array can't be nullable");
1351-
Node* load = kit->access_load_at(obj, ptr, TypeRawPtr::BOTTOM, val_type, bt, is_array ? (decorators | IS_ARRAY) : decorators, kit->control());
1349+
1350+
Node* cast = obj;
1351+
Node* adr = kit->flat_array_element_address(cast, idx, vk, /* null_free */ false, /* not_null_free */ true, /* atomic */ true);
1352+
Node* load = kit->access_load_at(cast, adr, TypeRawPtr::BOTTOM, val_type, bt, is_array ? (decorators | IS_ARRAY) : decorators, kit->control());
13521353
payload->init_req(1, load);
13531354
mem->init_req(1, kit->reset_memory());
13541355
io->init_req(1, kit->i_o());
13551356
}
1356-
1357-
kit->set_control(kit->IfTrue(iff));
1357+
region->init_req(1, kit->control());
13581358

13591359
// Null-free
1360+
kit->set_control(kit->IfTrue(iff));
13601361
if (!kit->stopped()) {
13611362
kit->set_all_memory(input_memory_state);
13621363

@@ -1446,7 +1447,6 @@ InlineTypeNode* InlineTypeNode::make_from_flat_impl(GraphKit* kit, ciInlineKlass
14461447
holder_offset -= vk->payload_offset();
14471448

14481449
if (!null_free) {
1449-
bool is_array = (kit->gvn().type(obj)->isa_aryptr() != nullptr);
14501450
Node* adr = kit->basic_plus_adr(obj, ptr, null_marker_offset);
14511451
Node* nm_value = kit->access_load_at(obj, adr, TypeRawPtr::BOTTOM, TypeInt::BOOL, T_BOOLEAN, is_array ? (decorators | IS_ARRAY) : decorators);
14521452
vt->set_req(IsInit, nm_value);

src/hotspot/share/opto/library_call.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4599,7 +4599,7 @@ bool LibraryCallKit::inline_newArray(bool null_free, bool atomic) {
45994599

46004600
ciArrayKlass* array_klass = ciArrayKlass::make(t, flat, null_free, atomic);
46014601
if (array_klass->is_loaded() && array_klass->element_klass()->as_inline_klass()->is_initialized()) {
4602-
const TypeAryKlassPtr* array_klass_type = TypeKlassPtr::make(array_klass, Type::trust_interfaces)->is_aryklassptr();
4602+
const TypeAryKlassPtr* array_klass_type = TypeAryKlassPtr::make(array_klass, Type::trust_interfaces);
46034603
if (null_free) {
46044604
if (init_val->is_InlineType()) {
46054605
if (array_klass_type->is_flat() && init_val->as_InlineType()->is_all_zero(&gvn(), /* flat */ true)) {
@@ -5665,6 +5665,7 @@ bool LibraryCallKit::inline_native_clone(bool is_virtual) {
56655665
PhiNode* result_mem = new PhiNode(result_reg, Type::MEMORY, TypePtr::BOTTOM);
56665666
record_for_igvn(result_reg);
56675667

5668+
// TODO 8350865 For arrays, this might be folded and then not account for atomic arrays
56685669
Node* obj_klass = load_object_klass(obj);
56695670
// We only go to the fast case code if we pass a number of guards.
56705671
// The paths which do not pass are accumulated in the slow_region.

src/hotspot/share/opto/memnode.cpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2619,27 +2619,27 @@ Node* LoadNNode::Ideal(PhaseGVN* phase, bool can_reshape) {
26192619
//=============================================================================
26202620
//----------------------------LoadKlassNode::make------------------------------
26212621
// Polymorphic factory method:
2622-
Node* LoadKlassNode::make(PhaseGVN& gvn, Node* mem, Node* adr, const TypePtr* at, const TypeKlassPtr* tk) {
2622+
Node* LoadKlassNode::make(PhaseGVN& gvn, Node* mem, Node* adr, const TypePtr* at, const TypeKlassPtr* tk, bool fold_for_arrays) {
26232623
// sanity check the alias category against the created node type
26242624
const TypePtr* adr_type = adr->bottom_type()->isa_ptr();
26252625
assert(adr_type != nullptr, "expecting TypeKlassPtr");
26262626
#ifdef _LP64
26272627
if (adr_type->is_ptr_to_narrowklass()) {
26282628
assert(UseCompressedClassPointers, "no compressed klasses");
2629-
Node* load_klass = gvn.transform(new LoadNKlassNode(mem, adr, at, tk->make_narrowklass(), MemNode::unordered));
2629+
Node* load_klass = gvn.transform(new LoadNKlassNode(mem, adr, at, tk->make_narrowklass(), MemNode::unordered, fold_for_arrays));
26302630
return new DecodeNKlassNode(load_klass, load_klass->bottom_type()->make_ptr());
26312631
}
26322632
#endif
26332633
assert(!adr_type->is_ptr_to_narrowklass() && !adr_type->is_ptr_to_narrowoop(), "should have got back a narrow oop");
2634-
return new LoadKlassNode(mem, adr, at, tk, MemNode::unordered);
2634+
return new LoadKlassNode(mem, adr, at, tk, MemNode::unordered, fold_for_arrays);
26352635
}
26362636

26372637
//------------------------------Value------------------------------------------
26382638
const Type* LoadKlassNode::Value(PhaseGVN* phase) const {
2639-
return klass_value_common(phase);
2639+
return klass_value_common(phase, _fold_for_arrays);
26402640
}
26412641

2642-
const Type* LoadNode::klass_value_common(PhaseGVN* phase) const {
2642+
const Type* LoadNode::klass_value_common(PhaseGVN* phase, bool fold_for_arrays) const {
26432643
// Either input is TOP ==> the result is TOP
26442644
const Type *t1 = phase->type( in(MemNode::Memory) );
26452645
if (t1 == Type::TOP) return Type::TOP;
@@ -2699,7 +2699,7 @@ const Type* LoadNode::klass_value_common(PhaseGVN* phase) const {
26992699

27002700
// Check for loading klass from an array
27012701
const TypeAryPtr* tary = tp->isa_aryptr();
2702-
if (tary != nullptr &&
2702+
if (tary != nullptr && fold_for_arrays &&
27032703
tary->offset() == oopDesc::klass_offset_in_bytes()) {
27042704
return tary->as_klass_type(true);
27052705
}
@@ -2814,7 +2814,7 @@ LoadNode* LoadNode::clone_pinned() const {
28142814

28152815
//------------------------------Value------------------------------------------
28162816
const Type* LoadNKlassNode::Value(PhaseGVN* phase) const {
2817-
const Type *t = klass_value_common(phase);
2817+
const Type *t = klass_value_common(phase, _fold_for_arrays);
28182818
if (t == Type::TOP)
28192819
return t;
28202820

src/hotspot/share/opto/memnode.hpp

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,7 @@ class LoadNode : public MemNode {
265265
virtual const Type* Value(PhaseGVN* phase) const;
266266

267267
// Common methods for LoadKlass and LoadNKlass nodes.
268-
const Type* klass_value_common(PhaseGVN* phase) const;
268+
const Type* klass_value_common(PhaseGVN* phase, bool fold_for_arrays) const;
269269
Node* klass_identity_common(PhaseGVN* phase);
270270

271271
virtual uint ideal_reg() const;
@@ -527,9 +527,17 @@ class LoadNNode : public LoadNode {
527527
//------------------------------LoadKlassNode----------------------------------
528528
// Load a Klass from an object
529529
class LoadKlassNode : public LoadPNode {
530+
bool _fold_for_arrays;
531+
532+
virtual uint size_of() const { return sizeof(*this); }
533+
virtual uint hash() const { return LoadNode::hash() + _fold_for_arrays; }
534+
virtual bool cmp( const Node &n ) const {
535+
return _fold_for_arrays == ((LoadKlassNode&)n)._fold_for_arrays && LoadNode::cmp(n);
536+
}
537+
530538
private:
531-
LoadKlassNode(Node* mem, Node* adr, const TypePtr* at, const TypeKlassPtr* tk, MemOrd mo)
532-
: LoadPNode(nullptr, mem, adr, at, tk, mo) {}
539+
LoadKlassNode(Node* mem, Node* adr, const TypePtr* at, const TypeKlassPtr* tk, MemOrd mo, bool fold_for_arrays)
540+
: LoadPNode(nullptr, mem, adr, at, tk, mo), _fold_for_arrays(fold_for_arrays) {}
533541

534542
public:
535543
virtual int Opcode() const;
@@ -539,7 +547,7 @@ class LoadKlassNode : public LoadPNode {
539547

540548
// Polymorphic factory method:
541549
static Node* make(PhaseGVN& gvn, Node* mem, Node* adr, const TypePtr* at,
542-
const TypeKlassPtr* tk = TypeInstKlassPtr::OBJECT);
550+
const TypeKlassPtr* tk = TypeInstKlassPtr::OBJECT, bool fold_for_arrays = true);
543551
};
544552

545553
//------------------------------LoadNKlassNode---------------------------------
@@ -551,10 +559,18 @@ class LoadKlassNode : public LoadPNode {
551559
// extract the actual class pointer. C2's type system is agnostic on whether the
552560
// input address directly points into the class pointer.
553561
class LoadNKlassNode : public LoadNNode {
562+
bool _fold_for_arrays;
563+
564+
virtual uint size_of() const { return sizeof(*this); }
565+
virtual uint hash() const { return LoadNode::hash() + _fold_for_arrays; }
566+
virtual bool cmp( const Node &n ) const {
567+
return _fold_for_arrays == ((LoadNKlassNode&)n)._fold_for_arrays && LoadNode::cmp(n);
568+
}
569+
554570
private:
555-
friend Node* LoadKlassNode::make(PhaseGVN&, Node*, Node*, const TypePtr*, const TypeKlassPtr*);
556-
LoadNKlassNode(Node* mem, Node* adr, const TypePtr* at, const TypeNarrowKlass* tk, MemOrd mo)
557-
: LoadNNode(nullptr, mem, adr, at, tk, mo) {}
571+
friend Node* LoadKlassNode::make(PhaseGVN&, Node*, Node*, const TypePtr*, const TypeKlassPtr*, bool fold_for_arrays);
572+
LoadNKlassNode(Node* mem, Node* adr, const TypePtr* at, const TypeNarrowKlass* tk, MemOrd mo, bool fold_for_arrays)
573+
: LoadNNode(nullptr, mem, adr, at, tk, mo), _fold_for_arrays(fold_for_arrays) {}
558574

559575
public:
560576
virtual int Opcode() const;

src/hotspot/share/opto/type.cpp

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5191,9 +5191,6 @@ const TypeAryPtr* TypeAryPtr::make(PTR ptr, const TypeAry *ary, ciKlass* k, bool
51915191
k->as_obj_array_klass()->base_element_klass()->is_interface()) {
51925192
k = nullptr;
51935193
}
5194-
if (k != nullptr && k->is_flat_array_klass() && !ary->_flat) {
5195-
k = nullptr;
5196-
}
51975194
return (TypeAryPtr*)(new TypeAryPtr(ptr, nullptr, ary, k, xk, offset, field_offset, instance_id, false, speculative, inline_depth))->hashcons();
51985195
}
51995196

@@ -5210,9 +5207,6 @@ const TypeAryPtr* TypeAryPtr::make(PTR ptr, ciObject* o, const TypeAry *ary, ciK
52105207
k->as_obj_array_klass()->base_element_klass()->is_interface()) {
52115208
k = nullptr;
52125209
}
5213-
if (k != nullptr && k->is_flat_array_klass() && !ary->_flat) {
5214-
k = nullptr;
5215-
}
52165210
return (TypeAryPtr*)(new TypeAryPtr(ptr, o, ary, k, xk, offset, field_offset, instance_id, is_autobox_cache, speculative, inline_depth))->hashcons();
52175211
}
52185212

@@ -6804,7 +6798,7 @@ const TypeAryKlassPtr* TypeAryKlassPtr::make(PTR ptr, ciKlass* k, Offset offset,
68046798
} else if (k->is_flat_array_klass()) {
68056799
ciKlass* eklass = k->as_flat_array_klass()->element_klass();
68066800
const TypeKlassPtr* etype = TypeKlassPtr::make(eklass, interface_handling)->cast_to_exactness(false);
6807-
return TypeAryKlassPtr::make(ptr, etype, nullptr, offset, not_flat, not_null_free, flat, null_free);
6801+
return TypeAryKlassPtr::make(ptr, etype, k, offset, not_flat, not_null_free, flat, null_free);
68086802
} else {
68096803
ShouldNotReachHere();
68106804
return nullptr;
@@ -6920,9 +6914,7 @@ ciKlass* TypeAryPtr::exact_klass_helper() const {
69206914
if (k == nullptr) {
69216915
return nullptr;
69226916
}
6923-
// TODO 8350865 We assume atomic if the atomic layout is available
6924-
bool atomic = k->is_inlinetype() && (is_null_free() ? k->as_inline_klass()->has_atomic_layout() : k->as_inline_klass()->has_nullable_atomic_layout());
6925-
k = ciArrayKlass::make(k, is_flat(), is_null_free(), atomic);
6917+
k = ciArrayKlass::make(k, is_flat(), is_null_free());
69266918
return k;
69276919
}
69286920

@@ -7320,9 +7312,12 @@ ciKlass* TypeAryKlassPtr::exact_klass_helper() const {
73207312
if (k == nullptr) {
73217313
return nullptr;
73227314
}
7323-
// TODO 8350865 We assume atomic if the atomic layout is available
7324-
bool atomic = k->is_inlinetype() && (is_null_free() ? k->as_inline_klass()->has_atomic_layout() : k->as_inline_klass()->has_nullable_atomic_layout());
7325-
k = ciArrayKlass::make(k, is_flat(), is_null_free(), atomic);
7315+
// TODO 8350865 LibraryCallKit::inline_newArray passes a constant TypeAryKlassPtr to GraphKit::new_array
7316+
// As long as atomicity is not tracked by TypeAryKlassPtr, don't re-compute it here to avoid loosing atomicity information
7317+
if (k->is_inlinetype() && _klass != nullptr) {
7318+
return _klass;
7319+
}
7320+
k = ciArrayKlass::make(k, is_flat(), is_null_free());
73267321
return k;
73277322
}
73287323

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
/**
2525
* @test
2626
* @summary Verify that certain array accesses do not trigger deoptimization.
27+
* @requires vm.debug == true
2728
* @library /test/lib
2829
* @enablePreview
2930
* @modules java.base/jdk.internal.value
@@ -100,6 +101,7 @@ static public void main(String[] args) throws Exception {
100101
"-XX:CompileCommand=quiet", "-XX:CompileCommand=compileonly,TestArrayAccessDeopt::test*", "-XX:-UseArrayLoadStoreProfile",
101102
"-XX:+TraceDeoptimization", "-Xbatch", "-XX:-MonomorphicArrayCheck", "-Xmixed", "-XX:+ProfileInterpreter", "TestArrayAccessDeopt", "run"};
102103
OutputAnalyzer oa = ProcessTools.executeTestJava(arg);
104+
oa.shouldHaveExitValue(0);
103105
String output = oa.getOutput();
104106
oa.shouldNotContain("UNCOMMON TRAP");
105107
} else {

0 commit comments

Comments
 (0)