Skip to content
Permalink
Browse files
8238812: assert(false) failed: bad AD file
Reviewed-by: thartmann, chagedorn, roland
  • Loading branch information
Rahul Raghavan committed Mar 10, 2021
1 parent b2a2ddf commit 4b5be40ab90bc721c0bfaefce7440f0ca57f1e73
Show file tree
Hide file tree
Showing 4 changed files with 208 additions and 10 deletions.
@@ -4161,10 +4161,10 @@ Node* Compile::conv_I2X_index(PhaseGVN* phase, Node* idx, const TypeInt* sizetyp
}

// Convert integer value to a narrowed long type dependent on ctrl (for example, a range check)
Node* Compile::constrained_convI2L(PhaseGVN* phase, Node* value, const TypeInt* itype, Node* ctrl) {
Node* Compile::constrained_convI2L(PhaseGVN* phase, Node* value, const TypeInt* itype, Node* ctrl, bool carry_dependency) {
if (ctrl != NULL) {
// Express control dependency by a CastII node with a narrow type.
value = new CastIINode(value, itype, false, true /* range check dependency */);
value = new CastIINode(value, itype, carry_dependency, true /* range check dependency */);
// Make the CastII node dependent on the control input to prevent the narrowed ConvI2L
// node from floating above the range check during loop optimizations. Otherwise, the
// ConvI2L node may be eliminated independently of the range check, causing the data path
@@ -1157,7 +1157,7 @@ class Compile : public Phase {
Node* ctrl = NULL);

// Convert integer value to a narrowed long type dependent on ctrl (for example, a range check)
static Node* constrained_convI2L(PhaseGVN* phase, Node* value, const TypeInt* itype, Node* ctrl);
static Node* constrained_convI2L(PhaseGVN* phase, Node* value, const TypeInt* itype, Node* ctrl, bool carry_dependency = false);

// Auxiliary methods for randomized fuzzing/stressing
int random();
@@ -863,10 +863,16 @@ bool Parse::create_jump_tables(Node* key_val, SwitchRange* lo, SwitchRange* hi)

// Clean the 32-bit int into a real 64-bit offset.
// Otherwise, the jint value 0 might turn into an offset of 0x0800000000.
const TypeInt* ikeytype = TypeInt::make(0, num_cases, Type::WidenMin);
// Make I2L conversion control dependent to prevent it from
// floating above the range check during loop optimizations.
key_val = C->conv_I2X_index(&_gvn, key_val, ikeytype, control());
// Do not use a narrow int type here to prevent the data path from dying
// while the control path is not removed. This can happen if the type of key_val
// is later known to be out of bounds of [0, num_cases] and therefore a narrow cast
// would be replaced by TOP while C2 is not able to fold the corresponding range checks.
// Set _carry_dependency for the cast to avoid being removed by IGVN.
#ifdef _LP64
key_val = C->constrained_convI2L(&_gvn, key_val, TypeInt::INT, control(), true /* carry_dependency */);
#endif

// Shift the value by wordsize so we have an index into the table, rather
// than a switch value
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -23,18 +23,24 @@

/**
* @test
* @bug 8229855
* @bug 8229855 8238812
* @summary Test jump table with key value that gets out of bounds after loop unrolling.
* @run main/othervm -XX:CompileCommand=dontinline,compiler.c2.TestJumpTable::test*
* -Xbatch -XX:+UnlockDiagnosticVMOptions -XX:-TieredCompilation -XX:-UseSwitchProfiling
* compiler.c2.TestJumpTable
* @run main/othervm -XX:CompileCommand=dontinline,compiler.c2.TestJumpTable::test*
* -Xbatch -XX:-TieredCompilation -XX:-UseOnStackReplacement
* compiler.c2.TestJumpTable
* @run main/othervm -XX:CompileCommand=dontinline,compiler.c2.TestJumpTable::test*
* -Xbatch -XX:+UnlockDiagnosticVMOptions -XX:-TieredCompilation -XX:+StressIGVN
* compiler.c2.TestJumpTable
*/

package compiler.c2;

public class TestJumpTable {

public static int test() {
public static int test0() {
int res = 0;
for (int i = 10; i < 50; ++i) {
switch (i * 5) {
@@ -53,9 +59,195 @@ public static int test() {
return res;
}

static int field;

// Original (slightly simplified) fuzzer generated test
public static void test1() {
int i4, i5 = 99, i6, i9 = 89;
for (i4 = 12; i4 < 365; i4++) {
for (i6 = 5; i6 > 1; i6--) {
switch ((i6 * 5) + 11) {
case 13:
case 19:
case 26:
case 31:
case 35:
case 41:
case 43:
case 61:
case 71:
case 83:
case 314:
i9 = i5;
break;
}
}
}
}

// This generates the following subgraph:
/*
// i: -10..4
if ((i+min_jint) u<= max_jint) { <- This is always true but not folded by C2
...
} else {
...
CastII(i-5, 0..45) <- Replaced by TOP because i-5 range is -15..-1 but still considered reachable by C2 although it is dead code
...
}
*/
public static void test2() {
for (int i = 5; i > -10; i--) {
switch (i) {
case 0:
case 4:
case 10:
case 20:
case 30:
case 40:
case 50:
case 100:
field = 42;
break;
}
}
}

// This generates the following subgraph:
/*
// i: -20..0
if (i != 0) {
// i: -20..-1
if (i < 0) { <- This is always true but not folded by C2
// Fall through
} else {
...
CastII(i-1, 0..4) <- Replaced by TOP because i-1 range is -21..-1 but still considered reachable by C2 although it is dead code
...
}
} else {
StoreI <- Due to this additional store on, IfNode::has_shared_region returns false and the fold compares optimization does not kick in
}
*/
public static void test3() {
for (int i = 5; i > -20; i -= 5) {
switch (i) {
case 0:
case 10:
case 20:
case 30:
case 40:
case 50:
case 60:
case 100:
field = 42;
break;
}
}
}

// This generates the following subgraph:
/*
// i: -20..0
if (i != 0) {
// i: -20..-1
if (i u< 101) { <- This is always false but not folded by C2 because CmpU is not handled
CastII(i-1, 0..49) <- Replaced by TOP because i-1 range is -21..-1 but still considered reachable by C2 although it is dead code
} else {
...
}
} else {
...
}
*/
public static void test4() {
int local = 0;
for (int i = 5; i > -20; i -= 5) {
switch (i) {
case 0:
case 10:
case 20:
case 30:
case 40:
case 50:
case 100:
local = 42;
break;
}
}
}

// This generates the following subgraph:
/*
// i: 0..20
if (i != 20) {
// i: 0..19
if ((i-20) u< 281) { <- This is always false but not folded by C2 because the two ifs compare different values
CastII(i-21, 0..49) <- Replaced by TOP because i-21 range is -21..-1 but still considered reachable by C2 although it is dead code
} else {
...
}
} else {
...
}
*/
public static void test5() {
int local;
for (int i = 25; i > 0; i -= 5) {
switch (i) {
case 20:
case 30:
case 40:
case 50:
case 60:
case 70:
case 300:
local = 42;
break;
}
}
}

// This generates the following subgraph:
/*
// i: 0..20
if ((i+10) != 30) {
// i: 0..19
if ((i-20) u< 271) { <- This is always false but not folded by C2 because the two ifs compare different values
CastII(i-21, 0..4) <- Replaced by TOP because i-21 range is -21..-1 but still considered reachable by C2 although it is dead code
} else {
...
}
} else {
...
}
*/
public static void test6() {
int local;
for (int i = 25; i > 0; i -= 5) {
switch (i + 10) {
case 30:
case 40:
case 50:
case 60:
case 70:
case 80:
case 300:
local = 42;
break;
}
}
}

public static void main(String[] args) {
for (int i = 0; i < 20_000; ++i) {
test();
for (int i = 0; i < 50_000; ++i) {
test0();
test1();
test2();
test3();
test4();
test5();
test6();
}
}
}

0 comments on commit 4b5be40

Please sign in to comment.