dfd3da3f52
Reviewed-by: thartmann, roland
183 lines
7.3 KiB
Java
183 lines
7.3 KiB
Java
/*
|
|
* Copyright (c) 2023, 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
|
|
* under the terms of the GNU General Public License version 2 only, as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
* version 2 for more details (a copy is included in the LICENSE file that
|
|
* accompanied this code).
|
|
*
|
|
* You should have received a copy of the GNU General Public License version
|
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*
|
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
* or visit www.oracle.com if you need additional information or have any
|
|
* questions.
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* @test
|
|
* @bug 8307683
|
|
* @library /test/lib /
|
|
* @requires vm.compiler2.enabled
|
|
* @summary Tests that IfNode is not wrongly chosen as range check by Loop Predication leading to crashes and wrong executions.
|
|
* @run main/othervm -Xcomp -XX:CompileCommand=compileonly,compiler.predicates.TestHoistedPredicateForNonRangeCheck::test*
|
|
* compiler.predicates.TestHoistedPredicateForNonRangeCheck
|
|
* @run main/othervm -Xcomp -XX:CompileCommand=compileonly,compiler.predicates.TestHoistedPredicateForNonRangeCheck::test*
|
|
* -XX:LoopMaxUnroll=0 compiler.predicates.TestHoistedPredicateForNonRangeCheck
|
|
*/
|
|
|
|
/*
|
|
* @test
|
|
* @bug 8307683
|
|
* @library /test/lib /
|
|
* @summary Tests that IfNode is not wrongly chosen as range check by Loop Predication leading to crashes and wrong executions.
|
|
* @run main/othervm -Xbatch compiler.predicates.TestHoistedPredicateForNonRangeCheck calendar
|
|
*/
|
|
|
|
package compiler.predicates;
|
|
|
|
import jdk.test.lib.Asserts;
|
|
|
|
import java.util.Calendar;
|
|
import java.util.Date;
|
|
|
|
|
|
public class TestHoistedPredicateForNonRangeCheck {
|
|
static int iFld, iFld2;
|
|
static int[] iArr = new int[100];
|
|
|
|
public static void main(String[] args) {
|
|
if (args.length == 0) {
|
|
Integer.compareUnsigned(34, 34); // Ensure Integer class is loaded and we do not emit a trap inside test() for it.
|
|
|
|
for (int i = 0; i < 2; i++) {
|
|
iFld = 0;
|
|
iFld2 = 0;
|
|
test();
|
|
Asserts.assertEQ(iFld, 3604, "wrong value");
|
|
Asserts.assertEQ(iFld2, 400, "wrong value");
|
|
}
|
|
|
|
for (int i = 0; i < 2000; i++) {
|
|
iFld = -100;
|
|
testRangeCheckNode();
|
|
}
|
|
iFld = -1;
|
|
iFld2 = 0;
|
|
testRangeCheckNode();
|
|
Asserts.assertEQ(iFld2, 36, "wrong value");
|
|
} else {
|
|
boolean flag = false;
|
|
for (int i = 0; i < 10000; i++) {
|
|
testCalendar1();
|
|
testCalendar2(flag);
|
|
}
|
|
}
|
|
}
|
|
|
|
public static void test() {
|
|
for (int i = -1; i < 1000; i++) {
|
|
// We hoist this check and insert a Hoisted Predicate for the lower and upper bound:
|
|
// -1 >=u 100 && 1000 >= u 100 -> always true and the predicates are removed.
|
|
// Template Assertion Predicates, however, are kept. When splitting this loop further, we insert an Assertion
|
|
// Predicate which fails for i = 0 and we halt.
|
|
// When not splitting this loop (with LoopMaxUnroll=0), we have a wrong execution due to never executing
|
|
// iFld2++ (we remove the check and the branch with the trap when creating the Hoisted Predicates).
|
|
if (Integer.compareUnsigned(i, 100) < 0) {
|
|
iFld2++;
|
|
Float.isNaN(34); // Float class is unloaded with -Xcomp -> inserts trap
|
|
} else {
|
|
iFld++;
|
|
}
|
|
|
|
// Same but flipped condition and moved trap to other branch - result is the same.
|
|
if (Integer.compareUnsigned(i, 100) >= 0) { // Loop Predication creates a Hoisted Range Check Predicate due to trap with Float.isNan().
|
|
iFld++;
|
|
} else {
|
|
iFld2++;
|
|
Float.isNaN(34); // Float class is unloaded with -Xcomp -> inserts trap
|
|
}
|
|
|
|
// Same but with LoadRangeNode.
|
|
if (Integer.compareUnsigned(i, iArr.length) >= 0) { // Loop Predication creates a Hoisted Range Check Predicate due to trap with Float.isNan().
|
|
iFld++;
|
|
} else {
|
|
iFld2++;
|
|
Float.isNaN(34); // Float class is unloaded with -Xcomp -> inserts trap
|
|
}
|
|
|
|
// Same but with LoadRangeNode and flipped condition and moved trap to other branch - result is the same.
|
|
if (Integer.compareUnsigned(i, iArr.length) >= 0) { // Loop Predication creates a Hoisted Range Check Predicate due to trap with Float.isNan().
|
|
iFld++;
|
|
} else {
|
|
iFld2++;
|
|
Float.isNaN(34); // Float class is unloaded with -Xcomp -> inserts trap
|
|
}
|
|
}
|
|
}
|
|
|
|
static void testRangeCheckNode() {
|
|
int array[] = new int[34];
|
|
// Hoisted Range Check Predicate with flipped bool because trap is on success proj and no trap on false proj due
|
|
// to catching exception:
|
|
// iFld >=u 34 && iFld+36 >=u 34
|
|
// This is always false for first 2000 iterations where, initially, iFld = -100
|
|
// It is still true in the last iteration where, initially, iFld = -1. But suddenly, in the second iteration,
|
|
// where iFld = 0, we would take the true projection for the first time - but we removed that branch when
|
|
// creating the Hoisted Range Check Predicate. We therefore run into the same problem as with test(): We either
|
|
// halt due to Assertion Predicates catching this case or we have a wrong execution (iFld2 never updated).
|
|
for (int i = 0; i < 37; i++) {
|
|
try {
|
|
array[iFld] = 34; // Normal RangeCheckNode
|
|
iFld2++;
|
|
Math.ceil(34); // Never taken and unloaded -> trap
|
|
} catch (Exception e) {
|
|
// False Proj of RangeCheckNode
|
|
iFld++;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Reported in JDK-8307683
|
|
static void testCalendar1() {
|
|
Calendar c = Calendar.getInstance();
|
|
c.setLenient(false);
|
|
c.set(Calendar.HOUR_OF_DAY, 0);
|
|
c.set(Calendar.MINUTE, 0);
|
|
c.getTime();
|
|
}
|
|
|
|
// Reported in JDK-8307978
|
|
static void testCalendar2(boolean flag) {
|
|
flag = !flag;
|
|
Calendar timespan = removeTime(new Date(), flag);
|
|
timespan.getTime();
|
|
}
|
|
|
|
static Calendar removeTime(Date date, boolean flag) {
|
|
Calendar calendar = Calendar.getInstance();
|
|
if (flag) {
|
|
calendar.setLenient(false);
|
|
}
|
|
calendar.setTime(date);
|
|
calendar = removeTime(calendar);
|
|
return calendar;
|
|
}
|
|
|
|
static Calendar removeTime(Calendar calendar) {
|
|
calendar.set(Calendar.HOUR_OF_DAY, 0);
|
|
calendar.set(Calendar.MINUTE, 0);
|
|
calendar.set(Calendar.SECOND, 0);
|
|
calendar.set(Calendar.MILLISECOND, 0);
|
|
return calendar;
|
|
}
|
|
}
|