hotspot/test/compiler/rangechecks/TestRangeCheckSmearing.java
changeset 28044 ede40159fd3b
child 28201 c4fe49894a22
equal deleted inserted replaced
28043:59286db74db6 28044:ede40159fd3b
       
     1 /*
       
     2  * Copyright (c) 2014, 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 /*
       
    25  * @test
       
    26  * @bug 8066103
       
    27  * @summary C2's range check smearing allows out of bound array accesses
       
    28  * @library /testlibrary /testlibrary/whitebox /compiler/whitebox /testlibrary/com/oracle/java/testlibrary
       
    29  * @build TestRangeCheckSmearing
       
    30  * @run main ClassFileInstaller sun.hotspot.WhiteBox
       
    31  * @run main ClassFileInstaller com.oracle.java.testlibrary.Platform
       
    32  * @run main/othervm -ea -Xmixed -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
       
    33  *                   -XX:-BackgroundCompilation -XX:-UseOnStackReplacement TestRangeCheckSmearing
       
    34  *
       
    35  */
       
    36 
       
    37 import java.lang.annotation.*;
       
    38 import java.lang.reflect.*;
       
    39 import java.util.*;
       
    40 import sun.hotspot.WhiteBox;
       
    41 import sun.hotspot.code.NMethod;
       
    42 import com.oracle.java.testlibrary.Platform;
       
    43 
       
    44 public class TestRangeCheckSmearing {
       
    45     private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();
       
    46 
       
    47     @Retention(RetentionPolicy.RUNTIME)
       
    48     @interface Args { int[] value(); }
       
    49 
       
    50     // first range check is i + max of all constants
       
    51     @Args({0, 8})
       
    52     static int m1(int[] array, int i, boolean allaccesses) {
       
    53         int res = 0;
       
    54         res += array[i+9];
       
    55         if (allaccesses) {
       
    56             res += array[i+8];
       
    57             res += array[i+7];
       
    58             res += array[i+6];
       
    59             res += array[i+5];
       
    60             res += array[i+4];
       
    61             res += array[i+3];
       
    62             res += array[i+2];
       
    63             res += array[i+1];
       
    64         }
       
    65         return res;
       
    66     }
       
    67 
       
    68     // first range check is i + min of all constants
       
    69     @Args({0, -9})
       
    70     static int m2(int[] array, int i, boolean allaccesses) {
       
    71         int res = 0;
       
    72         res += array[i+1];
       
    73         if (allaccesses) {
       
    74             res += array[i+2];
       
    75             res += array[i+3];
       
    76             res += array[i+4];
       
    77             res += array[i+5];
       
    78             res += array[i+6];
       
    79             res += array[i+7];
       
    80             res += array[i+8];
       
    81             res += array[i+9];
       
    82         }
       
    83         return res;
       
    84     }
       
    85 
       
    86     // first range check is not i + min/max of all constants
       
    87     @Args({0, 8})
       
    88     static int m3(int[] array, int i, boolean allaccesses) {
       
    89         int res = 0;
       
    90         res += array[i+3];
       
    91         if (allaccesses) {
       
    92             res += array[i+2];
       
    93             res += array[i+1];
       
    94             res += array[i+4];
       
    95             res += array[i+5];
       
    96             res += array[i+6];
       
    97             res += array[i+7];
       
    98             res += array[i+8];
       
    99             res += array[i+9];
       
   100         }
       
   101         return res;
       
   102     }
       
   103 
       
   104     @Args({0, -9})
       
   105     static int m4(int[] array, int i, boolean allaccesses) {
       
   106         int res = 0;
       
   107         res += array[i+3];
       
   108         if (allaccesses) {
       
   109             res += array[i+4];
       
   110             res += array[i+1];
       
   111             res += array[i+2];
       
   112             res += array[i+5];
       
   113             res += array[i+6];
       
   114             res += array[i+7];
       
   115             res += array[i+8];
       
   116             res += array[i+9];
       
   117         }
       
   118         return res;
       
   119     }
       
   120 
       
   121     @Args({0, -3})
       
   122     static int m5(int[] array, int i, boolean allaccesses) {
       
   123         int res = 0;
       
   124         res += array[i+3];
       
   125         res += array[i+2];
       
   126         if (allaccesses) {
       
   127             res += array[i+1];
       
   128             res += array[i+4];
       
   129             res += array[i+5];
       
   130             res += array[i+6];
       
   131             res += array[i+7];
       
   132             res += array[i+8];
       
   133             res += array[i+9];
       
   134         }
       
   135         return res;
       
   136     }
       
   137 
       
   138     @Args({0, 6})
       
   139     static int m6(int[] array, int i, boolean allaccesses) {
       
   140         int res = 0;
       
   141         res += array[i+3];
       
   142         res += array[i+4];
       
   143         if (allaccesses) {
       
   144             res += array[i+2];
       
   145             res += array[i+1];
       
   146             res += array[i+5];
       
   147             res += array[i+6];
       
   148             res += array[i+7];
       
   149             res += array[i+8];
       
   150             res += array[i+9];
       
   151         }
       
   152         return res;
       
   153     }
       
   154 
       
   155     @Args({0, 6})
       
   156     static int m7(int[] array, int i, boolean allaccesses) {
       
   157         int res = 0;
       
   158         res += array[i+3];
       
   159         res += array[i+2];
       
   160         res += array[i+4];
       
   161         if (allaccesses) {
       
   162             res += array[i+1];
       
   163             res += array[i+5];
       
   164             res += array[i+6];
       
   165             res += array[i+7];
       
   166             res += array[i+8];
       
   167             res += array[i+9];
       
   168         }
       
   169         return res;
       
   170     }
       
   171 
       
   172     @Args({0, -3})
       
   173     static int m8(int[] array, int i, boolean allaccesses) {
       
   174         int res = 0;
       
   175         res += array[i+3];
       
   176         res += array[i+4];
       
   177         res += array[i+2];
       
   178         if (allaccesses) {
       
   179             res += array[i+1];
       
   180             res += array[i+5];
       
   181             res += array[i+6];
       
   182             res += array[i+7];
       
   183             res += array[i+8];
       
   184             res += array[i+9];
       
   185         }
       
   186         return res;
       
   187     }
       
   188 
       
   189     @Args({6, 15})
       
   190     static int m9(int[] array, int i, boolean allaccesses) {
       
   191         int res = 0;
       
   192         res += array[i+3];
       
   193         if (allaccesses) {
       
   194             res += array[i-2];
       
   195             res += array[i-1];
       
   196             res += array[i-4];
       
   197             res += array[i-5];
       
   198             res += array[i-6];
       
   199         }
       
   200         return res;
       
   201     }
       
   202 
       
   203     @Args({3, 12})
       
   204     static int m10(int[] array, int i, boolean allaccesses) {
       
   205         int res = 0;
       
   206         res += array[i+3];
       
   207         if (allaccesses) {
       
   208             res += array[i-2];
       
   209             res += array[i-1];
       
   210             res += array[i-3];
       
   211             res += array[i+4];
       
   212             res += array[i+5];
       
   213             res += array[i+6];
       
   214         }
       
   215         return res;
       
   216     }
       
   217 
       
   218     @Args({3, -3})
       
   219     static int m11(int[] array, int i, boolean allaccesses) {
       
   220         int res = 0;
       
   221         res += array[i+3];
       
   222         res += array[i-2];
       
   223         if (allaccesses) {
       
   224             res += array[i+5];
       
   225             res += array[i+6];
       
   226         }
       
   227         return res;
       
   228     }
       
   229 
       
   230     @Args({3, 6})
       
   231     static int m12(int[] array, int i, boolean allaccesses) {
       
   232         int res = 0;
       
   233         res += array[i+3];
       
   234         res += array[i+6];
       
   235         if (allaccesses) {
       
   236             res += array[i-2];
       
   237             res += array[i-3];
       
   238         }
       
   239         return res;
       
   240     }
       
   241 
       
   242     // check that identical range check is replaced by dominating one
       
   243     // only when correct
       
   244     @Args({0})
       
   245     static int m13(int[] array, int i, boolean ignore) {
       
   246         int res = 0;
       
   247         res += array[i+3];
       
   248         res += array[i+3];
       
   249         return res;
       
   250     }
       
   251 
       
   252     @Args({2, 0})
       
   253     static int m14(int[] array, int i, boolean ignore) {
       
   254         int res = 0;
       
   255 
       
   256         res += array[i];
       
   257         res += array[i-2];
       
   258         res += array[i]; // If range check below were to be removed first this cannot be considered identical to first range check
       
   259         res += array[i-1]; // range check removed so i-1 array access depends on previous check
       
   260 
       
   261         return res;
       
   262     }
       
   263 
       
   264     static int[] m15_dummy = new int[10];
       
   265     @Args({2, 0})
       
   266     static int m15(int[] array, int i, boolean ignore) {
       
   267         int res = 0;
       
   268         res += array[i];
       
   269 
       
   270         // When the loop is optimized out we don't want the
       
   271         // array[i-1] access which is dependent on array[i]'s
       
   272         // range check to become dependent on the identical range
       
   273         // check above.
       
   274 
       
   275         int[] array2 = m15_dummy;
       
   276         int j = 0;
       
   277         for (; j < 10; j++);
       
   278         if (j == 10) {
       
   279             array2 = array;
       
   280         }
       
   281 
       
   282         res += array2[i-2];
       
   283         res += array2[i];
       
   284         res += array2[i-1]; // range check removed so i-1 array access depends on previous check
       
   285 
       
   286         return res;
       
   287     }
       
   288 
       
   289     @Args({2, 0})
       
   290     static int m16(int[] array, int i, boolean ignore) {
       
   291         int res = 0;
       
   292 
       
   293         res += array[i];
       
   294         res += array[i-1];
       
   295         res += array[i-1];
       
   296         res += array[i-2];
       
   297 
       
   298         return res;
       
   299     }
       
   300 
       
   301     @Args({2, 0})
       
   302     static int m17(int[] array, int i, boolean ignore) {
       
   303         int res = 0;
       
   304 
       
   305         res += array[i];
       
   306         res += array[i-2];
       
   307         res += array[i-2];
       
   308         res += array[i+2];
       
   309         res += array[i+2];
       
   310         res += array[i-1];
       
   311         res += array[i-1];
       
   312 
       
   313         return res;
       
   314     }
       
   315 
       
   316     static public void main(String[] args) {
       
   317         if (WHITE_BOX.getBooleanVMFlag("BackgroundCompilation")) {
       
   318             throw new AssertionError("Background compilation enabled");
       
   319         }
       
   320         new TestRangeCheckSmearing().doTests();
       
   321     }
       
   322     boolean success = true;
       
   323     boolean exception = false;
       
   324     final int[] array = new int[10];
       
   325     final HashMap<String,Method> tests = new HashMap<>();
       
   326     {
       
   327         final Class<?> TEST_PARAM_TYPES[] = { int[].class, int.class, boolean.class };
       
   328         for (Method m : this.getClass().getDeclaredMethods()) {
       
   329             if (m.getName().matches("m[0-9]+")) {
       
   330                 assert(Modifier.isStatic(m.getModifiers())) : m;
       
   331                 assert(m.getReturnType() == int.class) : m;
       
   332                 assert(Arrays.equals(m.getParameterTypes(), TEST_PARAM_TYPES)) : m;
       
   333                 tests.put(m.getName(), m);
       
   334             }
       
   335         }
       
   336     }
       
   337 
       
   338     void invokeTest(Method m, int[] array, int index, boolean z) {
       
   339         try {
       
   340             m.invoke(null, array, index, z);
       
   341         } catch (ReflectiveOperationException roe) {
       
   342             Throwable ex = roe.getCause();
       
   343             if (ex instanceof ArrayIndexOutOfBoundsException)
       
   344                 throw (ArrayIndexOutOfBoundsException) ex;
       
   345             throw new AssertionError(roe);
       
   346         }
       
   347     }
       
   348 
       
   349     void doTest(String name) {
       
   350         Method m = tests.get(name);
       
   351         tests.remove(name);
       
   352         int[] args = m.getAnnotation(Args.class).value();
       
   353         int index0 = args[0], index1;
       
   354         boolean exceptionRequired = true;
       
   355         if (args.length == 2) {
       
   356             index1 = args[1];
       
   357         } else {
       
   358             // no negative test for this one
       
   359             assert(args.length == 1);
       
   360             assert(name.equals("m13"));
       
   361             exceptionRequired = false;
       
   362             index1 = index0;
       
   363         }
       
   364         // Get the method compiled.
       
   365         if (!WHITE_BOX.isMethodCompiled(m)) {
       
   366             // If not, try to compile it with C2
       
   367             if(!WHITE_BOX.enqueueMethodForCompilation(m, CompilerWhiteBoxTest.COMP_LEVEL_FULL_OPTIMIZATION)) {
       
   368                 // C2 compiler not available, try to compile with C1
       
   369                 WHITE_BOX.enqueueMethodForCompilation(m, CompilerWhiteBoxTest.COMP_LEVEL_SIMPLE);
       
   370             }
       
   371         }
       
   372         if (!WHITE_BOX.isMethodCompiled(m)) {
       
   373             throw new RuntimeException(m + " not compiled");
       
   374         }
       
   375 
       
   376         // valid access
       
   377         invokeTest(m, array, index0, true);
       
   378 
       
   379         if (!WHITE_BOX.isMethodCompiled(m)) {
       
   380             throw new RuntimeException(m + " deoptimized on valid array access");
       
   381         }
       
   382 
       
   383         exception = false;
       
   384         boolean test_success = true;
       
   385         try {
       
   386             invokeTest(m, array, index1, false);
       
   387         } catch(ArrayIndexOutOfBoundsException aioob) {
       
   388             exception = true;
       
   389             System.out.println("ArrayIndexOutOfBoundsException thrown in "+name);
       
   390         }
       
   391         if (!exception) {
       
   392             System.out.println("ArrayIndexOutOfBoundsException was not thrown in "+name);
       
   393         }
       
   394 
       
   395         if (Platform.isServer()) {
       
   396             if (exceptionRequired == WHITE_BOX.isMethodCompiled(m)) {
       
   397                 System.out.println((exceptionRequired?"Didn't deoptimized":"deoptimized") + " in "+name);
       
   398                 test_success = false;
       
   399             }
       
   400         }
       
   401 
       
   402         if (exception != exceptionRequired) {
       
   403             System.out.println((exceptionRequired?"exception required but not thrown":"not exception required but thrown") + " in "+name);
       
   404             test_success = false;
       
   405         }
       
   406 
       
   407         if (!test_success) {
       
   408             success = false;
       
   409             System.out.println("TEST FAILED: "+name);
       
   410         }
       
   411 
       
   412     }
       
   413     void doTests() {
       
   414         doTest("m1");
       
   415         doTest("m2");
       
   416         doTest("m3");
       
   417         doTest("m4");
       
   418         doTest("m5");
       
   419         doTest("m6");
       
   420         doTest("m7");
       
   421         doTest("m8");
       
   422         doTest("m9");
       
   423         doTest("m10");
       
   424         doTest("m11");
       
   425         doTest("m12");
       
   426         doTest("m13");
       
   427         doTest("m14");
       
   428         doTest("m15");
       
   429         doTest("m16");
       
   430         doTest("m17");
       
   431         if (!success) {
       
   432             throw new RuntimeException("Some tests failed");
       
   433         }
       
   434         assert(tests.isEmpty()) : tests;
       
   435     }
       
   436 }