Closed connglli closed 2 years ago
We can reproduce the reduced Test.java
in one of our desktop machine but cannot on our performant server. So please use the unreduced Test.java.orig
if you cannot reproduce the crash.
The crash didn't reproduce for me. Trying Test.java.orig
, it doesn't compile - error: package FuzzerUtils does not exist
Actually, I was able to reproduce the crash using the reduced test case on plinux (using 11.0.14.1).
vmState [0x514ff]: {J9VMSTATE_JIT} {globalValuePropagation}
@0xdaryl fyi
It doesn't reproduce on plinux using the reduced test case with the latest build.
@pshipton Sorry for fogetting FuzzerUtils.java. See this
/*
* Copyright (C) 2016 Intel Corporation
* Modifications copyright (C) 2017-2018 Azul Systems
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.util.concurrent.atomic.AtomicLong;
import java.io.PrintStream;
import java.util.Random;
// Utilities for the tests generated by Java* Fuzzer for Android*
// with modifications for Java* Fuzzer test generator
public class FuzzerUtils {
public static PrintStream out = System.out;
public static Random random = new Random(1);
public static long seed = 1L;
public static int UnknownZero = 0;
// Init seed
public static void seed(long seed){
random = new Random(seed);
FuzzerUtils.seed = seed;
}
public static int nextInt(){
return random.nextInt();
}
public static long nextLong(){
return random.nextLong();
}
public static float nextFloat(){
return random.nextFloat();
}
public static double nextDouble(){
return random.nextDouble();
}
public static boolean nextBoolean(){
return random.nextBoolean();
}
public static byte nextByte(){
return (byte)random.nextInt();
}
public static short nextShort(){
return (short)random.nextInt();
}
public static char nextChar(){
return (char)random.nextInt();
}
// Array initialization
// boolean -----------------------------------------------
public static void init(boolean[] a, boolean seed) {
for (int j = 0; j < a.length; j++) {
a[j] = (j % 2 == 0) ? seed : (j % 3 == 0);
}
}
public static void init(boolean[][] a, boolean seed) {
for (int j = 0; j < a.length; j++) {
init(a[j], seed);
}
}
// long --------------------------------------------------
public static void init(long[] a, long seed) {
for (int j = 0; j < a.length; j++) {
a[j] = (j % 2 == 0) ? seed + j : seed - j;
}
}
public static void init(long[][] a, long seed) {
for (int j = 0; j < a.length; j++) {
init(a[j], seed);
}
}
// int --------------------------------------------------
public static void init(int[] a, int seed) {
for (int j = 0; j < a.length; j++) {
a[j] = (j % 2 == 0) ? seed + j : seed - j;
}
}
public static void init(int[][] a, int seed) {
for (int j = 0; j < a.length; j++) {
init(a[j], seed);
}
}
// short --------------------------------------------------
public static void init(short[] a, short seed) {
for (int j = 0; j < a.length; j++) {
a[j] = (short) ((j % 2 == 0) ? seed + j : seed - j);
}
}
public static void init(short[][] a, short seed) {
for (int j = 0; j < a.length; j++) {
init(a[j], seed);
}
}
// char --------------------------------------------------
public static void init(char[] a, char seed) {
for (int j = 0; j < a.length; j++) {
a[j] = (char) ((j % 2 == 0) ? seed + j : seed - j);
}
}
public static void init(char[][] a, char seed) {
for (int j = 0; j < a.length; j++) {
init(a[j], seed);
}
}
// byte --------------------------------------------------
public static void init(byte[] a, byte seed) {
for (int j = 0; j < a.length; j++) {
a[j] = (byte) ((j % 2 == 0) ? seed + j : seed - j);
}
}
public static void init(byte[][] a, byte seed) {
for (int j = 0; j < a.length; j++) {
init(a[j], seed);
}
}
// double --------------------------------------------------
public static void init(double[] a, double seed) {
for (int j = 0; j < a.length; j++) {
a[j] = (j % 2 == 0) ? seed + j : seed - j;
}
}
public static void init(double[][] a, double seed) {
for (int j = 0; j < a.length; j++) {
init(a[j], seed);
}
}
// float --------------------------------------------------
public static void init(float[] a, float seed) {
for (int j = 0; j < a.length; j++) {
a[j] = (j % 2 == 0) ? seed + j : seed - j;
}
}
public static void init(float[][] a, float seed) {
for (int j = 0; j < a.length; j++) {
init(a[j], seed);
}
}
// Object -------------------------------------------------
public static void init(Object[][] a, Object seed) {
for (int j = 0; j < a.length; j++) {
init(a[j], seed);
}
}
public static void init(Object[] a, Object seed) {
for (int j = 0; j < a.length; j++)
try {
a[j] = seed.getClass().newInstance();
} catch (Exception ex) {
a[j] = seed;
}
}
// Calculate array checksum
// boolean -----------------------------------------------
public static long checkSum(boolean[] a) {
long sum = 0;
for (int j = 0; j < a.length; j++) {
sum += (a[j] ? j + 1 : 0);
}
return sum;
}
public static long checkSum(boolean[][] a) {
long sum = 0;
for (int j = 0; j < a.length; j++) {
sum += checkSum(a[j]);
}
return sum;
}
// long --------------------------------------------------
public static long checkSum(long[] a) {
long sum = 0;
for (int j = 0; j < a.length; j++) {
sum += (a[j] / (j + 1) + a[j] % (j + 1));
}
return sum;
}
public static long checkSum(long[][] a) {
long sum = 0;
for (int j = 0; j < a.length; j++) {
sum += checkSum(a[j]);
}
return sum;
}
// int --------------------------------------------------
public static long checkSum(int[] a) {
long sum = 0;
for (int j = 0; j < a.length; j++) {
sum += (a[j] / (j + 1) + a[j] % (j + 1));
}
return sum;
}
public static long checkSum(int[][] a) {
long sum = 0;
for (int j = 0; j < a.length; j++) {
sum += checkSum(a[j]);
}
return sum;
}
// short --------------------------------------------------
public static long checkSum(short[] a) {
long sum = 0;
for (int j = 0; j < a.length; j++) {
sum += (short) (a[j] / (j + 1) + a[j] % (j + 1));
}
return sum;
}
public static long checkSum(short[][] a) {
long sum = 0;
for (int j = 0; j < a.length; j++) {
sum += checkSum(a[j]);
}
return sum;
}
// char --------------------------------------------------
public static long checkSum(char[] a) {
long sum = 0;
for (int j = 0; j < a.length; j++) {
sum += (char) (a[j] / (j + 1) + a[j] % (j + 1));
}
return sum;
}
public static long checkSum(char[][] a) {
long sum = 0;
for (int j = 0; j < a.length; j++) {
sum += checkSum(a[j]);
}
return sum;
}
// byte --------------------------------------------------
public static long checkSum(byte[] a) {
long sum = 0;
for (int j = 0; j < a.length; j++) {
sum += (byte) (a[j] / (j + 1) + a[j] % (j + 1));
}
return sum;
}
public static long checkSum(byte[][] a) {
long sum = 0;
for (int j = 0; j < a.length; j++) {
sum += checkSum(a[j]);
}
return sum;
}
// double --------------------------------------------------
public static double checkSum(double[] a) {
double sum = 0;
for (int j = 0; j < a.length; j++) {
sum += (a[j] / (j + 1) + a[j] % (j + 1));
}
return sum;
}
public static double checkSum(double[][] a) {
double sum = 0;
for (int j = 0; j < a.length; j++) {
sum += checkSum(a[j]);
}
return sum;
}
// float --------------------------------------------------
public static double checkSum(float[] a) {
double sum = 0;
for (int j = 0; j < a.length; j++) {
sum += (a[j] / (j + 1) + a[j] % (j + 1));
}
return sum;
}
public static double checkSum(float[][] a) {
double sum = 0;
for (int j = 0; j < a.length; j++) {
sum += checkSum(a[j]);
}
return sum;
}
// Object --------------------------------------------------
public static long checkSum(Object[][] a) {
long sum = 0;
for (int j = 0; j < a.length; j++) {
sum += checkSum(a[j]);
}
return sum;
}
public static long checkSum(Object[] a) {
long sum = 0;
for (int j = 0; j < a.length; j++) {
sum += checkSum(a[j]) * Math.pow(2, j);
}
return sum;
}
public static long checkSum(Object a) {
if (a == null)
return 0L;
return (long) a.getClass().getCanonicalName().length();
}
// Array creation ------------------------------------------
public static byte[] byte1array(int sz, byte seed) {
byte[] ret = new byte[sz];
init(ret, seed);
return ret;
}
public static byte[][] byte2array(int sz, byte seed) {
byte[][] ret = new byte[sz][sz];
init(ret, seed);
return ret;
}
public static short[] short1array(int sz, short seed) {
short[] ret = new short[sz];
init(ret, seed);
return ret;
}
public static short[][] short2array(int sz, short seed) {
short[][] ret = new short[sz][sz];
init(ret, seed);
return ret;
}
public static int[] int1array(int sz, int seed) {
int[] ret = new int[sz];
init(ret, seed);
return ret;
}
public static int[][] int2array(int sz, int seed) {
int[][] ret = new int[sz][sz];
init(ret, seed);
return ret;
}
public static long[] long1array(int sz, long seed) {
long[] ret = new long[sz];
init(ret, seed);
return ret;
}
public static long[][] long2array(int sz, long seed) {
long[][] ret = new long[sz][sz];
init(ret, seed);
return ret;
}
public static float[] float1array(int sz, float seed) {
float[] ret = new float[sz];
init(ret, seed);
return ret;
}
public static float[][] float2array(int sz, float seed) {
float[][] ret = new float[sz][sz];
init(ret, seed);
return ret;
}
public static double[] double1array(int sz, double seed) {
double[] ret = new double[sz];
init(ret, seed);
return ret;
}
public static double[][] double2array(int sz, double seed) {
double[][] ret = new double[sz][sz];
init(ret, seed);
return ret;
}
public static char[] char1array(int sz, char seed) {
char[] ret = new char[sz];
init(ret, seed);
return ret;
}
public static char[][] char2array(int sz, char seed) {
char[][] ret = new char[sz][sz];
init(ret, seed);
return ret;
}
public static Object[] Object1array(int sz, Object seed) {
Object[] ret = new Object[sz];
init(ret, seed);
return ret;
}
public static Object[][] Object2array(int sz, Object seed) {
Object[][] ret = new Object[sz][sz];
init(ret, seed);
return ret;
}
public static boolean[] boolean1array(int sz, boolean seed) {
boolean[] ret = new boolean[sz];
init(ret, seed);
return ret;
}
public static boolean[][] boolean2array(int sz, boolean seed) {
boolean[][] ret = new boolean[sz][sz];
init(ret, seed);
return ret;
}
public static AtomicLong runningThreads = new AtomicLong(0);
public static synchronized void runThread(Runnable r) {
final Thread t = new Thread(r);
t.start();
runningThreads.incrementAndGet();
Thread t1 = new Thread(new Runnable() {
public void run() {
try {
t.join();
runningThreads.decrementAndGet();
} catch (InterruptedException e) {
}
}
});
t1.start();
}
public static void joinThreads() {
while (runningThreads.get() > 0) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
}
}
}
Using the original testcase, I can reproduce it now on xlinux on 0.32 and the latest JVM,
@hzongaro : could you have a look at this reproducible GVP crash please? Note it is initially targeted to 0.33.
This might be the same as issue #14489. I am readily able to reproduce it and am continuing to investigate.
@hzongaro I looked through the value propagation git history in OMR and tried reverting a few recent PR's. I was not able to reproduce after reverting eclipse/omr#6121.
I looked through the value propagation git history in OMR and tried reverting a few recent PR's. I was not able to reproduce after reverting https://github.com/eclipse/omr/pull/6121.
Thanks, Brad @BradleyWood! I'll take a look at whether that causes the problem, or if that change was correct, and exposed the problem. . . .
I took at look at transformations that GVP performs when OMR pull request #6121 is reverted. In that case, although there's no crash, I can see that it removes a NULLCHK
even though there is a path through which a null reference is assigned to the temporary that's involved - that's the same null reference that causes the crash in attempting to intersect constraints when that pull request is in place. So I believe that the problem already existed, but that pull request just changed the symptom of the problem - at least in this case.
n7996n BBStart <block_593> (freq 3) (catches java/lang/Exception) (cold)
...
n8175n astore <temp slot 30>[#1309 Auto] [flags 0x7 0x0 ] (X==0 sharedMemory ) [0x7f84fada0b00]
n8021n aconst NULL (X==0 sharedMemory ) [0x7f84fad9dae0]
n8176n goto --> block_580 BBStart at n8171n [0x7f84fada0b50]
n7997n BBEnd </block_593> (cold) ===== [0x7f84fad9d360]
...
n8171n BBStart <block_580> (freq 6) (in loop 14) [0x7f84fada09c0]
n8189n astore <temp slot 30>[#1309 Auto] [flags 0x7 0x0 ] [0x7f84fada0f60]
n8179n aload <temp slot 30>[#1309 Auto] [flags 0x7 0x0 ] [0x7f84fada0c40]
n1161n astore <auto slot 24>[#496 Auto] [flags 0x7 0x0 ] [0x7f84fa737aa0]
n8194n aload <temp slot 30>[#1309 Auto] [flags 0x7 0x0 ] [0x7f84fada10f0]
...
n8218n ificmpne --> block_601 BBStart at n8212n (inlineNonoverriddenGuard ) [0x7f84fada1870]
...
n8209n BBEnd </block_580> =====
...
n8212n BBStart <block_601> (freq 1) (cold) (in loop 14) [0x7f84fada1690]
n8225n NULLCHK on n8232n [#32] [0x7f84fada1aa0]
n1164n icalli java/text/DecimalFormatSymbols.getPatternSeparator()C[#498 virtual Method -160] [flags 0x500 0x0 ] (virtualCallNodeForAGuardedInlinedCall ) [0x7f84fa737b90]
n1163n aloadi <vft-symbol>[#309 Shadow] [flags 0x18607 0x0 ] [0x7f84fa737b40]
n8233n aload <auto slot 24>[#496 Auto] [flags 0x7 0x0 ] (X>=0 sharedMemory ) [0x7f84fada1d20]
n8232n aload <auto slot 24>[#496 Auto] [flags 0x7 0x0 ] [0x7f84fada1cd0]
...
Node n8232n has already been processed by mergeDefConstraints - returning NULL
aload [00007F84FADA1CD0] has existing global constraint: value 1434 is class Ljava/text/DecimalFormatSymbols; (non-NULL) {HeapObject}
syncRequired is already setup at node [00007F84FA737B90]
[ 18764] O^O VALUE PROPAGATION: Removing redundant null check node [00007F84FADA1AA0]
Now I'm trying to understand why mergeDefConstraints
is marking these constraints as global.
I'm still able to reproduce the failure with this reduced test:
import java.text.DecimalFormatSymbols;
import java.util.Locale;
import java.text.DecimalFormat;
import java.text.NumberFormat;
// Generated by Java* Fuzzer test generator (1.0.001). Sat Jun 11 23:30:48 2022
public class Test {
public void mainTest(String[] strArr1) {
for (int i30 = 0; i30 < 1000; i30++) {
java.io.PrintStream ax$29 = System.out;
java.io.PrintStream ax$30 = System.err;
for (int ax$27 = 0; ax$27 < 1000; ax$27++) {
try {
DecimalFormat ax$25 = (DecimalFormat) NumberFormat.getInstance(Locale.JAPAN);
DecimalFormatSymbols ax$24 = ax$25.getDecimalFormatSymbols();
if (ax$24.getPatternSeparator() != ';') {
}
} catch (Throwable ax$26) {
} finally {
}
}
System.setOut(ax$29);
System.setErr(ax$30);
}
}
public static void main(String[] strArr) {
Test _instance = new Test();
for (int i = 0; i < 10; i++) {
_instance.mainTest(strArr);
}
}
private static Boolean ax$32 = false;
}
I'll post some more details showing what I think is going wrong.
This is not a 0.33 regression. It is reproducible at least as far back as 0.24 on JDK11. As @hzongaro mentions above, eclipse/omr#6121 is likely a red herring.
I'm still struggling a bit with how to resolve this issue. I don't think it can be quickly resolved safely, and as it's a long-standing problem I don't think it should be considered a blocker - and I see the Peter @pshipton has already removed the blocker label.
I'll post some more details about what I see happening, and reach out to Vijay @vijaysun-omr for some advice.
Inside the inner loop (loop 6), we have several paths through inlined code and guarded calls that assigns values to #397
. The reference in #397
is used on the taken side of a guarded icalli
for DecimalFormatSymbols.getPatternSeparator
in block_47
. One of the inlined code paths results in a null reference being assigned to #397
in a catch block (block_39
); on another path, the reference assigned to #397
(in block_94
) is the result of a call to Object.clone()
, so known to be non-null.
The relevant portion of the CFG looks this:
31→32, 32→92, 92→93, 93→94, 94→47 39→26, 26→47 44→47 89→47
The branches from blocks 26, 89 and 94 are conditional; the branch from block 44 (which is on the taken side of the inlined guard for DecimalFormat.getDecimalFormatSymbols
is unconditional. Defs for #397
appear in blocks 94, 89, 26 and 44.
In processing block_94
the last time through, constrainIfcmpeqne
calls canFoldNonOverriddenGuard
, which calls getConstraint
for the first argument to the guarded call in block_47:
n3633n BBStart <block_94> (freq 9990) (in loop 6) [0x7f1372050f50] bci=[-1,42,16] rc=0 vc=494 vn=172 li=- udi=- nc=0
n3634n astore <temp slot 11>[#737 Auto] [flags 0x7 0x0 ] [0x7f1372050fa0] bci=[2,0,566] rc=0 vc=494 vn=28 li=28 udi=17 nc=1
n3635n aload <temp slot 11>[#737 Auto] [flags 0x7 0x0 ] [0x7f1372050ff0] bci=[2,0,566] rc=1 vc=494 vn=28 li=70 udi=91 nc=0
n3636n astore <auto slot 7>[#397 Auto] [flags 0x7 0x0 ] [0x7f1372051040] bci=[-1,45,16] rc=0 vc=494 vn=28 li=29 udi=18 nc=1
n3637n aload <temp slot 11>[#737 Auto] [flags 0x7 0x0 ] [0x7f1372051090] bci=[-1,42,16] rc=2 vc=494 vn=28 li=71 udi=92 nc=0
n3638n astore <pending push temp 0>[#392 Auto] [flags 0x7 0x800 ] [0x7f13720510e0] bci=[-1,42,16] rc=0 vc=494 vn=28 li=- udi=19 nc=1
n3637n ==>aload
n3639n ificmpne --> block_47 BBStart at n3190n (inlineNonoverriddenGuard ) [0x7f1372051130] bci=[3,0,303] rc=0 vc=494 vn=173 li=- udi=- nc=2 flg=0x5020
n3640n iand (X>=0 cannotOverflow ) [0x7f1372051180] bci=[3,0,303] rc=1 vc=494 vn=33 li=- udi=- nc=2 flg=0x1100
n3641n l2i [0x7f13720511d0] bci=[3,0,303] rc=1 vc=494 vn=32 li=- udi=- nc=1
n3642n lload 0x1d7158[#739 Static] [flags 0x307 0x0 ] (cannotOverflow ) [0x7f1372051220] bci=[-1,49,17] rc=1 vc=494 vn=31 li=- udi=- nc=0 flg=0x1000
n3643n iconst 4 (X!=0 X>=0 ) [0x7f1372051270] bci=[3,0,303] rc=1 vc=494 vn=22 li=- udi=- nc=0 flg=0x104
n3644n iconst 0 (X==0 X>=0 X<=0 ) [0x7f13720512c0] bci=[3,0,303] rc=1 vc=494 vn=3 li=- udi=- nc=0 flg=0x302
n3645n BBEnd </block_94> ===== [0x7f1372051310] bci=[3,4,303] rc=0 vc=494 vn=174 li=- udi=- nc=0
...
n3190n BBStart <block_47> (freq 1) (cold) [0x7f13721d84d0] bci=[-1,49,17] rc=0 vc=0 vn=- li=- udi=- nc=0
n3203n NULLCHK on n3210n [#32] [0x7f13721d88e0] bci=[-1,49,17] rc=0 vc=0 vn=- li=- udi=- nc=1
n61n icalli java/text/DecimalFormatSymbols.getPatternSeparator()C[#399 virtual Method -160] [flags 0x500 0x0 ] (virtualCallNodeForAGuardedInlinedCall ) [0x7f1371d2b2d0] bci=[-1,49,17] rc=3 vc=44 vn=- li=- udi=- nc=2 flg=0x800
n60n aloadi <vft-symbol>[#309 Shadow] [flags 0x18607 0x0 ] [0x7f1371d2b280] bci=[-1,49,17] rc=1 vc=44 vn=- li=- udi=- nc=1
n3211n aload <auto slot 7>[#397 Auto] [flags 0x7 0x0 ] [0x7f13721d8b60] bci=[-1,49,17] rc=1 vc=0 vn=- li=- udi=- nc=0
n3210n aload <auto slot 7>[#397 Auto] [flags 0x7 0x0 ] [0x7f13721d8b10] bci=[-1,49,17] rc=1 vc=0 vn=- li=- udi=- nc=0
n3204n istore <pending push temp 0>[#400 Auto] [flags 0x3 0x800 ] [0x7f13721d8930] bci=[-1,49,17] rc=0 vc=0 vn=- li=- udi=- nc=1
n61n ==>icalli
n3205n istore <temp slot 12>[#741 Auto] [flags 0x3 0x0 ] [0x7f13721d8980] bci=[-1,49,17] rc=0 vc=0 vn=- li=- udi=- nc=1
n61n ==>icalli
n3206n goto --> block_46 BBStart at n3188n [0x7f13721d89d0] bci=[-1,49,17] rc=0 vc=0 vn=- li=- udi=- nc=0
n3191n BBEnd </block_47> (cold) ===== [0x7f13721d8520] bci=[-1,49,17] rc=0 vc=0 vn=- li=- udi=- nc=0
getConstraint
calls mergeDefConstraints
for node n3210n
.
Where things go awry in mergeDefConstraints
, there are two places where unseenDefsFound
might be set to true: firstly for autos or parms that are not defined on all paths, and secondly for a store which has not been seen.
In this case, #397
is marked as defined on all paths, and the def from n3636n
is considered to be seen, but the stores from the other paths are not considered to be seen - so unseenDefsFound
is set to true. The one set of constraints that come from the def at node n3636n
is Ljava/text/DecimalFormatSymbols; (non-NULL) {HeapObject}
Later mergeDefConstraints
, as it's processing a loop the last-time through, attempting to look at back-edge constraints, it only considers autos and parms whose def node symref is not defined on all paths. All the def nodes use #397
, so they end up being ignored, unseenDefsFound
is left as false, and isGlobal
is left as true. That results in mergeDefConstraints
returning Ljava/text/DecimalFormatSymbols; (non-NULL) {HeapObject}
as a global constraint.
Later, in processing block_26
the last-time through, the same thing happens
n2990n BBStart <block_39> (freq 3) (catches java/lang/Exception) (cold) [0x7f13721d4650] bci=[1,11,2430] rc=0 vc=466 vn=- li=- udi=- nc=0
...
n3153n astore <temp slot 11>[#737 Auto] [flags 0x7 0x0 ] (X==0 sharedMemory ) [0x7f13721d7940] bci=[1,12,2431] rc=0 vc=466 vn=- li=- udi=- nc=1 flg=0x2
n3015n aconst NULL (X==0 sharedMemory ) [0x7f13721d4e20] bci=[1,12,2431] rc=1 vc=466 vn=- li=- udi=- nc=0 flg=0x2
n3154n goto --> block_26 BBStart at n3149n [0x7f13721d7990] bci=[1,13,2431] rc=0 vc=466 vn=- li=- udi=- nc=0
n2991n BBEnd </block_39> (cold) ===== [0x7f13721d46a0] bci=[1,13,2431] rc=0 vc=466 vn=- li=- udi=- nc=0
...
n3149n BBStart <block_26> (freq 6) (in loop 6) [0x7f13721d7800] bci=[-1,42,16] rc=0 vc=494 vn=193 li=- udi=- nc=0
n3167n astore <temp slot 11>[#737 Auto] [flags 0x7 0x0 ] [0x7f13721d7da0] bci=[2,0,566] rc=0 vc=494 vn=48 li=36 udi=29 nc=1
n3157n aload <temp slot 11>[#737 Auto] [flags 0x7 0x0 ] [0x7f13721d7a80] bci=[2,0,566] rc=1 vc=494 vn=48 li=82 udi=103 nc=0
n58n astore <auto slot 7>[#397 Auto] [flags 0x7 0x0 ] [0x7f1371d2b1e0] bci=[-1,45,16] rc=0 vc=494 vn=48 li=37 udi=30 nc=1
n3172n aload <temp slot 11>[#737 Auto] [flags 0x7 0x0 ] [0x7f13721d7f30] bci=[-1,42,16] rc=2 vc=494 vn=48 li=83 udi=104 nc=0
n55n astore <pending push temp 0>[#392 Auto] [flags 0x7 0x800 ] [0x7f1371d2b0f0] bci=[-1,42,16] rc=0 vc=494 vn=48 li=- udi=31 nc=1
n3172n ==>aload
n3196n ificmpne --> block_47 BBStart at n3190n (inlineNonoverriddenGuard ) [0x7f13721d86b0] bci=[3,0,303] rc=0 vc=494 vn=194 li=- udi=- nc=2 flg=0x5020
n3576n iand (X>=0 cannotOverflow ) [0x7f137204fd80] bci=[3,0,303] rc=1 vc=494 vn=51 li=- udi=- nc=2 flg=0x1100
n3575n l2i [0x7f137204fd30] bci=[3,0,303] rc=1 vc=494 vn=50 li=- udi=- nc=1
n3192n lload 0x1d7158[#739 Static] [flags 0x307 0x0 ] (cannotOverflow ) [0x7f13721d8570] bci=[-1,49,17] rc=1 vc=494 vn=49 li=- udi=- nc=0 flg=0x1000
n3573n iconst 4 (X!=0 X>=0 ) [0x7f137204fc90] bci=[3,0,303] rc=1 vc=494 vn=22 li=- udi=- nc=0 flg=0x104
n3574n iconst 0 (X==0 X>=0 X<=0 ) [0x7f137204fce0] bci=[3,0,303] rc=1 vc=494 vn=3 li=- udi=- nc=0 flg=0x302
n3187n BBEnd </block_26> ===== [0x7f13721d83e0] bci=[3,4,303] rc=0 vc=494 vn=195 li=- udi=- nc=0
But this time, the constraint from the def at node n58n is (NULL)
, mergeDefConstraints
leaves isGlobal
true and unseenDefsFound
false again, getConstraint
attempts to intersect that new (incorrectly) global constraint with the previously seen (again, incorrectly) global constraint Ljava/text/DecimalFormatSymbols; (non-NULL) {HeapObject}
, and crashes.
What I'm trying to understand is whether the later processing in mergeDefConstraints
should ensure isGlobal
ends up being set to false in these cases, but still return the constraint found from the definition on that path? Or if it should end up leaving it as unconstrained? Or something else. . . .
Vijay @vijaysun-omr, I would appreciate your thoughts, comments or questions about this
In case anyone is interested, here is the complete jitdump from which the information in the previous comment was extracted. It contains some additional tracing from getConstraint
and mergeDefConstraints
.
Fixed by OMR pull request 6619
Java -version output
Summary of problem
The following test case crashes OpenJ9's JIT compiler
Diagnostic files
By issuing
the following crash log is given:
Please also check openj9-bug-63.tar.gz for all the logs (jitdump, snap, etc.) and the testcase (Test.java, Test.class).
Notice
The given
Test.java
(which is reduced by us) is NOT always reproducible, and often take ~1min to crash when it is reproducible. So please be patient. If it is not reproducible, please useTest.java.orig
in the above link.