Path: blob/master/test/hotspot/jtreg/compiler/rangechecks/TestRangeCheckSmearing.java
41149 views
/*1* Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223/*24* @test25* @bug 806610326* @summary C2's range check smearing allows out of bound array accesses27* @library /test/lib /28* @modules java.base/jdk.internal.misc29* java.management30* @build sun.hotspot.WhiteBox31* @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox32* @run main/othervm -ea -Xmixed -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI33* -XX:-BackgroundCompilation -XX:-UseOnStackReplacement34* -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockExperimentalVMOptions -XX:+EagerJVMCI35* compiler.rangechecks.TestRangeCheckSmearing36*37*/3839package compiler.rangechecks;4041import compiler.whitebox.CompilerWhiteBoxTest;42import compiler.testlibrary.CompilerUtils;43import jdk.test.lib.Platform;44import sun.hotspot.WhiteBox;4546import java.lang.annotation.Retention;47import java.lang.annotation.RetentionPolicy;48import java.lang.reflect.Method;49import java.lang.reflect.Modifier;50import java.util.Arrays;51import java.util.HashMap;5253public class TestRangeCheckSmearing {54private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();5556@Retention(RetentionPolicy.RUNTIME)57@interface Args { int[] value(); }5859// first range check is i + max of all constants60@Args({0, 8})61static int m1(int[] array, int i, boolean allaccesses) {62int res = 0;63res += array[i+9];64if (allaccesses) {65res += array[i+8];66res += array[i+7];67res += array[i+6];68res += array[i+5];69res += array[i+4];70res += array[i+3];71res += array[i+2];72res += array[i+1];73}74return res;75}7677// first range check is i + min of all constants78@Args({0, -9})79static int m2(int[] array, int i, boolean allaccesses) {80int res = 0;81res += array[i+1];82if (allaccesses) {83res += array[i+2];84res += array[i+3];85res += array[i+4];86res += array[i+5];87res += array[i+6];88res += array[i+7];89res += array[i+8];90res += array[i+9];91}92return res;93}9495// first range check is not i + min/max of all constants96@Args({0, 8})97static int m3(int[] array, int i, boolean allaccesses) {98int res = 0;99res += array[i+3];100if (allaccesses) {101res += array[i+2];102res += array[i+1];103res += array[i+4];104res += array[i+5];105res += array[i+6];106res += array[i+7];107res += array[i+8];108res += array[i+9];109}110return res;111}112113@Args({0, -9})114static int m4(int[] array, int i, boolean allaccesses) {115int res = 0;116res += array[i+3];117if (allaccesses) {118res += array[i+4];119res += array[i+1];120res += array[i+2];121res += array[i+5];122res += array[i+6];123res += array[i+7];124res += array[i+8];125res += array[i+9];126}127return res;128}129130@Args({0, -3})131static int m5(int[] array, int i, boolean allaccesses) {132int res = 0;133res += array[i+3];134res += array[i+2];135if (allaccesses) {136res += array[i+1];137res += array[i+4];138res += array[i+5];139res += array[i+6];140res += array[i+7];141res += array[i+8];142res += array[i+9];143}144return res;145}146147@Args({0, 6})148static int m6(int[] array, int i, boolean allaccesses) {149int res = 0;150res += array[i+3];151res += array[i+4];152if (allaccesses) {153res += array[i+2];154res += array[i+1];155res += array[i+5];156res += array[i+6];157res += array[i+7];158res += array[i+8];159res += array[i+9];160}161return res;162}163164@Args({0, 6})165static int m7(int[] array, int i, boolean allaccesses) {166int res = 0;167res += array[i+3];168res += array[i+2];169res += array[i+4];170if (allaccesses) {171res += array[i+1];172res += array[i+5];173res += array[i+6];174res += array[i+7];175res += array[i+8];176res += array[i+9];177}178return res;179}180181@Args({0, -3})182static int m8(int[] array, int i, boolean allaccesses) {183int res = 0;184res += array[i+3];185res += array[i+4];186res += array[i+2];187if (allaccesses) {188res += array[i+1];189res += array[i+5];190res += array[i+6];191res += array[i+7];192res += array[i+8];193res += array[i+9];194}195return res;196}197198@Args({6, 15})199static int m9(int[] array, int i, boolean allaccesses) {200int res = 0;201res += array[i+3];202if (allaccesses) {203res += array[i-2];204res += array[i-1];205res += array[i-4];206res += array[i-5];207res += array[i-6];208}209return res;210}211212@Args({3, 12})213static int m10(int[] array, int i, boolean allaccesses) {214int res = 0;215res += array[i+3];216if (allaccesses) {217res += array[i-2];218res += array[i-1];219res += array[i-3];220res += array[i+4];221res += array[i+5];222res += array[i+6];223}224return res;225}226227@Args({3, -3})228static int m11(int[] array, int i, boolean allaccesses) {229int res = 0;230res += array[i+3];231res += array[i-2];232if (allaccesses) {233res += array[i+5];234res += array[i+6];235}236return res;237}238239@Args({3, 6})240static int m12(int[] array, int i, boolean allaccesses) {241int res = 0;242res += array[i+3];243res += array[i+6];244if (allaccesses) {245res += array[i-2];246res += array[i-3];247}248return res;249}250251// check that identical range check is replaced by dominating one252// only when correct253@Args({0})254static int m13(int[] array, int i, boolean ignore) {255int res = 0;256res += array[i+3];257res += array[i+3];258return res;259}260261@Args({2, 0})262static int m14(int[] array, int i, boolean ignore) {263int res = 0;264265res += array[i];266res += array[i-2];267res += array[i]; // If range check below were to be removed first this cannot be considered identical to first range check268res += array[i-1]; // range check removed so i-1 array access depends on previous check269270return res;271}272273static int[] m15_dummy = new int[10];274@Args({2, 0})275static int m15(int[] array, int i, boolean ignore) {276int res = 0;277res += array[i];278279// When the loop is optimized out we don't want the280// array[i-1] access which is dependent on array[i]'s281// range check to become dependent on the identical range282// check above.283284int[] array2 = m15_dummy;285int j = 0;286for (; j < 10; j++);287if (j == 10) {288array2 = array;289}290291res += array2[i-2];292res += array2[i];293res += array2[i-1]; // range check removed so i-1 array access depends on previous check294295return res;296}297298@Args({2, 0})299static int m16(int[] array, int i, boolean ignore) {300int res = 0;301302res += array[i];303res += array[i-1];304res += array[i-1];305res += array[i-2];306307return res;308}309310@Args({2, 0})311static int m17(int[] array, int i, boolean ignore) {312int res = 0;313314res += array[i];315res += array[i-2];316res += array[i-2];317res += array[i+2];318res += array[i+2];319res += array[i-1];320res += array[i-1];321322return res;323}324325static public void main(String[] args) {326if (WHITE_BOX.getBooleanVMFlag("BackgroundCompilation")) {327throw new AssertionError("Background compilation enabled");328}329new TestRangeCheckSmearing().doTests();330}331boolean success = true;332boolean exception = false;333final int[] array = new int[10];334final HashMap<String,Method> tests = new HashMap<>();335{336final Class<?> TEST_PARAM_TYPES[] = { int[].class, int.class, boolean.class };337for (Method m : this.getClass().getDeclaredMethods()) {338if (m.getName().matches("m[0-9]+")) {339assert(Modifier.isStatic(m.getModifiers())) : m;340assert(m.getReturnType() == int.class) : m;341assert(Arrays.equals(m.getParameterTypes(), TEST_PARAM_TYPES)) : m;342tests.put(m.getName(), m);343}344}345}346347void invokeTest(Method m, int[] array, int index, boolean z) {348try {349m.invoke(null, array, index, z);350} catch (ReflectiveOperationException roe) {351Throwable ex = roe.getCause();352if (ex instanceof ArrayIndexOutOfBoundsException)353throw (ArrayIndexOutOfBoundsException) ex;354throw new AssertionError(roe);355}356}357358void doTest(String name) {359Method m = tests.get(name);360tests.remove(name);361int[] args = m.getAnnotation(Args.class).value();362int index0 = args[0], index1;363boolean exceptionRequired = true;364if (args.length == 2) {365index1 = args[1];366} else {367// no negative test for this one368assert(args.length == 1);369assert(name.equals("m13"));370exceptionRequired = false;371index1 = index0;372}373// Get the method compiled.374if (!WHITE_BOX.isMethodCompiled(m)) {375// If not, try to compile it with C2376if(!WHITE_BOX.enqueueMethodForCompilation(m, CompilerWhiteBoxTest.COMP_LEVEL_FULL_OPTIMIZATION)) {377// C2 compiler not available, try to compile with C1378WHITE_BOX.enqueueMethodForCompilation(m, CompilerWhiteBoxTest.COMP_LEVEL_SIMPLE);379}380}381if (!WHITE_BOX.isMethodCompiled(m)) {382throw new RuntimeException(m + " not compiled");383}384385// valid access386invokeTest(m, array, index0, true);387388if (!WHITE_BOX.isMethodCompiled(m)) {389throw new RuntimeException(m + " deoptimized on valid array access");390}391392exception = false;393boolean test_success = true;394try {395invokeTest(m, array, index1, false);396} catch(ArrayIndexOutOfBoundsException aioob) {397exception = true;398System.out.println("ArrayIndexOutOfBoundsException thrown in "+name);399}400if (!exception) {401System.out.println("ArrayIndexOutOfBoundsException was not thrown in "+name);402}403404if (CompilerUtils.getMaxCompilationLevel() == CompilerWhiteBoxTest.COMP_LEVEL_FULL_OPTIMIZATION) {405if (exceptionRequired == WHITE_BOX.isMethodCompiled(m)) {406System.out.println((exceptionRequired?"Didn't deoptimized":"deoptimized") + " in "+name);407test_success = false;408}409}410411if (exception != exceptionRequired) {412System.out.println((exceptionRequired?"exception required but not thrown":"not exception required but thrown") + " in "+name);413test_success = false;414}415416if (!test_success) {417success = false;418System.out.println("TEST FAILED: "+name);419}420421}422void doTests() {423doTest("m1");424doTest("m2");425doTest("m3");426doTest("m4");427doTest("m5");428doTest("m6");429doTest("m7");430doTest("m8");431doTest("m9");432doTest("m10");433doTest("m11");434doTest("m12");435doTest("m13");436doTest("m14");437doTest("m15");438doTest("m16");439doTest("m17");440if (!success) {441throw new RuntimeException("Some tests failed");442}443assert(tests.isEmpty()) : tests;444}445}446447448