Skip to content

Commit c5fafa9

Browse files
committed
8381373: [lworld] C2 failed assert(!flat || flat_array) failed: inconsistency
Reviewed-by: qamai, dlong
1 parent 67240cc commit c5fafa9

2 files changed

Lines changed: 177 additions & 16 deletions

File tree

src/hotspot/share/ci/ciMethod.cpp

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -664,6 +664,15 @@ bool ciMethod::parameter_profiled_type(int i, ciKlass*& type, ProfilePtrKind& pt
664664
return false;
665665
}
666666

667+
// MDO updates are racy. C2 can observe the array type before the profiling code has updated the
668+
// corresponding flat/null-free flags. If the array type is known, prefer the properties it provides.
669+
static void update_flags_from_type(ciKlass* array_type, bool& flat_array, bool& null_free_array) {
670+
if (array_type != nullptr) {
671+
flat_array |= array_type->is_flat_array_klass();
672+
null_free_array |= array_type->as_array_klass()->is_elem_null_free();
673+
}
674+
}
675+
667676
bool ciMethod::array_access_profiled_type(int bci, ciKlass*& array_type, ciKlass*& element_type, ProfilePtrKind& element_ptr, bool &flat_array, bool &null_free_array) {
668677
if (method_data() != nullptr && method_data()->is_mature()) {
669678
ciProfileData* data = method_data()->bci_to_data(bci);
@@ -675,20 +684,14 @@ bool ciMethod::array_access_profiled_type(int bci, ciKlass*& array_type, ciKlass
675684
element_ptr = array_access->element()->ptr_kind();
676685
flat_array = array_access->flat_array();
677686
null_free_array = array_access->null_free_array();
678-
#ifdef ASSERT
679-
if (array_type != nullptr) {
680-
bool flat = array_type->is_flat_array_klass();
681-
bool null_free = array_type->as_array_klass()->is_elem_null_free();
682-
assert(!flat || flat_array, "inconsistency");
683-
assert(!null_free || null_free_array, "inconsistency");
684-
}
685-
#endif
687+
update_flags_from_type(array_type, flat_array, null_free_array);
686688
return true;
687689
} else if (data->is_ArrayStoreData()) {
688690
ciArrayStoreData* array_access = (ciArrayStoreData*) data->as_ArrayStoreData();
689691
array_type = array_access->array()->valid_type();
690692
flat_array = array_access->flat_array();
691693
null_free_array = array_access->null_free_array();
694+
update_flags_from_type(array_type, flat_array, null_free_array);
692695
ciCallProfile call_profile = call_profile_at_bci(bci);
693696
if (call_profile.morphism() == 1) {
694697
element_type = call_profile.receiver(0);
@@ -702,14 +705,6 @@ bool ciMethod::array_access_profiled_type(int bci, ciKlass*& array_type, ciKlass
702705
} else {
703706
element_ptr = ProfileMaybeNull;
704707
}
705-
#ifdef ASSERT
706-
if (array_type != nullptr) {
707-
bool flat = array_type->is_flat_array_klass();
708-
bool null_free = array_type->as_array_klass()->is_elem_null_free();
709-
assert(!flat || flat_array, "inconsistency");
710-
assert(!null_free || null_free_array, "inconsistency");
711-
}
712-
#endif
713708
return true;
714709
}
715710
}
Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
/*
2+
* Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
package compiler.valhalla.inlinetypes;
25+
26+
import java.lang.reflect.Method;
27+
28+
import jdk.internal.value.ValueClass;
29+
import jdk.internal.vm.annotation.LooselyConsistentValue;
30+
import jdk.test.lib.Utils;
31+
import jdk.test.whitebox.WhiteBox;
32+
33+
/*
34+
* @test
35+
* @key randomness
36+
* @summary Test racy array access profiling.
37+
* @bug 8381373
38+
* @library /test/lib /
39+
* @enablePreview
40+
* @modules java.base/jdk.internal.value
41+
* java.base/jdk.internal.vm.annotation
42+
* @build jdk.test.whitebox.WhiteBox
43+
* @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
44+
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
45+
* -Xbatch -XX:CompileCommand=compileonly,${test.main.class}::profileArray
46+
* ${test.main.class}
47+
*/
48+
public class TestArrayAccessProfileRace {
49+
private static final WhiteBox WB = WhiteBox.getWhiteBox();
50+
private static final int C1_FULL_PROFILE = 3;
51+
private static final int C2 = 4;
52+
private static volatile boolean startProfiling;
53+
54+
@LooselyConsistentValue
55+
static value class ArrayAccessValue {
56+
int x;
57+
58+
ArrayAccessValue(int x) {
59+
this.x = x;
60+
}
61+
}
62+
63+
// Trigger array load/store profiling
64+
static int profileArray(Object[] array, Object val) {
65+
int sum = 0;
66+
sum += ((ArrayAccessValue)array[0]).x;
67+
array[0] = val;
68+
sum += ((ArrayAccessValue)array[0]).x;
69+
array[0] = val;
70+
sum += ((ArrayAccessValue)array[0]).x;
71+
array[0] = val;
72+
sum += ((ArrayAccessValue)array[0]).x;
73+
array[0] = val;
74+
sum += ((ArrayAccessValue)array[0]).x;
75+
array[0] = val;
76+
sum += ((ArrayAccessValue)array[0]).x;
77+
array[0] = val;
78+
sum += ((ArrayAccessValue)array[0]).x;
79+
array[0] = val;
80+
sum += ((ArrayAccessValue)array[0]).x;
81+
array[0] = val;
82+
sum += ((ArrayAccessValue)array[0]).x;
83+
array[0] = val;
84+
sum += ((ArrayAccessValue)array[0]).x;
85+
array[0] = val;
86+
sum += ((ArrayAccessValue)array[0]).x;
87+
array[0] = val;
88+
sum += ((ArrayAccessValue)array[0]).x;
89+
array[0] = val;
90+
sum += ((ArrayAccessValue)array[0]).x;
91+
array[0] = val;
92+
sum += ((ArrayAccessValue)array[0]).x;
93+
array[0] = val;
94+
sum += ((ArrayAccessValue)array[0]).x;
95+
array[0] = val;
96+
sum += ((ArrayAccessValue)array[0]).x;
97+
array[0] = val;
98+
sum += ((ArrayAccessValue)array[0]).x;
99+
array[0] = val;
100+
sum += ((ArrayAccessValue)array[0]).x;
101+
array[0] = val;
102+
sum += ((ArrayAccessValue)array[0]).x;
103+
array[0] = val;
104+
sum += ((ArrayAccessValue)array[0]).x;
105+
array[0] = val;
106+
return sum;
107+
}
108+
109+
public static void main(String[] args) throws Exception {
110+
// Create an array with random properties
111+
Object[] array;
112+
Object val = new ArrayAccessValue(42);
113+
int arrayKind = Utils.getRandomInstance().nextInt(5);
114+
switch (arrayKind) {
115+
case 0:
116+
array = new ArrayAccessValue[1];
117+
array[0] = val;
118+
break;
119+
case 1:
120+
array = ValueClass.newNullRestrictedNonAtomicArray(ArrayAccessValue.class, 1, val);
121+
break;
122+
case 2:
123+
array = ValueClass.newNullRestrictedAtomicArray(ArrayAccessValue.class, 1, val);
124+
break;
125+
case 3:
126+
array = ValueClass.newNullableAtomicArray(ArrayAccessValue.class, 1);
127+
array[0] = val;
128+
break;
129+
case 4:
130+
array = ValueClass.newReferenceArray(ArrayAccessValue.class, 1);
131+
array[0] = val;
132+
break;
133+
default:
134+
throw new RuntimeException("Unexpected arrayKind: " + arrayKind);
135+
}
136+
Method method = TestArrayAccessProfileRace.class.getDeclaredMethod("profileArray", Object[].class, Object.class);
137+
138+
for (int i = 0; i < 100; i++) {
139+
// Reset profile information
140+
startProfiling = false;
141+
WB.deoptimizeMethod(method);
142+
WB.clearMethodState(method);
143+
144+
// C1 compile the profiling method and mark the profile
145+
// as mature so that C2 will consume it immediately
146+
WB.enqueueMethodForCompilation(method, C1_FULL_PROFILE);
147+
WB.markMethodProfiled(method);
148+
149+
// Profile asynchronously to the C2 compilation
150+
Thread profiler = new Thread(() -> {
151+
while (!startProfiling) {
152+
Thread.onSpinWait();
153+
}
154+
profileArray(array, val);
155+
});
156+
profiler.start();
157+
158+
// Start profiling and C2 compilation in the hope
159+
// that this will trigger the race.
160+
startProfiling = true;
161+
WB.enqueueMethodForCompilation(method, C2);
162+
profiler.join();
163+
}
164+
}
165+
}
166+

0 commit comments

Comments
 (0)