1 /*
   2  * Copyright (c) 2014, 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 package org.graalvm.compiler.replacements.test;
  24 
  25 import java.util.Arrays;
  26 
  27 import org.junit.Assert;
  28 import org.junit.Test;
  29 
  30 import org.graalvm.compiler.nodes.ReturnNode;
  31 import org.graalvm.compiler.nodes.StructuredGraph;
  32 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
  33 import org.graalvm.compiler.phases.OptimisticOptimizations;
  34 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
  35 import org.graalvm.compiler.phases.common.inlining.InliningPhase;
  36 import org.graalvm.compiler.phases.tiers.HighTierContext;
  37 import org.graalvm.compiler.phases.tiers.PhaseContext;
  38 import org.graalvm.compiler.replacements.ArraysSubstitutions;
  39 import org.graalvm.compiler.replacements.nodes.ArrayEqualsNode;
  40 import org.graalvm.compiler.virtual.phases.ea.PartialEscapePhase;
  41 
  42 /**
  43  * Tests {@link ArraysSubstitutions}.
  44  */
  45 public class ArraysSubstitutionsTest extends MethodSubstitutionTest {
  46 
  47     private static final int N = 10;
  48 
  49     @Test
  50     public void testEqualsBoolean() {
  51         Object[] args1 = new Object[N];
  52         Object[] args2 = new Object[N];
  53         int n = 0;
  54 
  55         // equal arrays
  56         for (int i = 0; i < N / 2; i++, n++) {
  57             args1[n] = new boolean[i];
  58             args2[n] = new boolean[i];
  59         }
  60 
  61         // non-equal arrays
  62         for (int i = 0; i < N / 2; i++, n++) {
  63             boolean[] a2 = new boolean[i];
  64             if (i > 0) {
  65                 a2[i - 1] = true;
  66             }
  67             args1[n] = new boolean[i];
  68             args2[n] = a2;
  69         }
  70         Class<?>[] parameterTypes = new Class<?>[]{boolean[].class, boolean[].class};
  71         testSubstitution("arraysEqualsBoolean", ArrayEqualsNode.class, Arrays.class, "equals", parameterTypes, false, args1, args2);
  72     }
  73 
  74     @SuppressWarnings("all")
  75     public static boolean arraysEqualsBoolean(boolean[] a, boolean[] b) {
  76         return Arrays.equals(a, b);
  77     }
  78 
  79     @Test
  80     public void testEqualsByte() {
  81         Object[] args1 = new Object[N];
  82         Object[] args2 = new Object[N];
  83         int n = 0;
  84 
  85         // equal arrays
  86         for (int i = 0; i < N / 2; i++, n++) {
  87             args1[n] = new byte[i];
  88             args2[n] = new byte[i];
  89         }
  90 
  91         // non-equal arrays
  92         for (int i = 0; i < N / 2; i++, n++) {
  93             byte[] a2 = new byte[i];
  94             if (i > 0) {
  95                 a2[i - 1] = 1;
  96             }
  97             args1[n] = new byte[i];
  98             args2[n] = a2;
  99         }
 100 
 101         Class<?>[] parameterTypes = new Class<?>[]{byte[].class, byte[].class};
 102         testSubstitution("arraysEqualsByte", ArrayEqualsNode.class, Arrays.class, "equals", parameterTypes, false, args1, args2);
 103     }
 104 
 105     @SuppressWarnings("all")
 106     public static boolean arraysEqualsByte(byte[] a, byte[] b) {
 107         return Arrays.equals(a, b);
 108     }
 109 
 110     @Test
 111     public void testEqualsChar() {
 112         Object[] args1 = new Object[N];
 113         Object[] args2 = new Object[N];
 114         int n = 0;
 115 
 116         // equal arrays
 117         for (int i = 0; i < N / 2; i++, n++) {
 118             args1[n] = new char[i];
 119             args2[n] = new char[i];
 120         }
 121 
 122         // non-equal arrays
 123         for (int i = 0; i < N / 2; i++, n++) {
 124             char[] a2 = new char[i];
 125             if (i > 0) {
 126                 a2[i - 1] = 1;
 127             }
 128             args1[n] = new char[i];
 129             args2[n] = a2;
 130         }
 131 
 132         Class<?>[] parameterTypes = new Class<?>[]{char[].class, char[].class};
 133         testSubstitution("arraysEqualsChar", ArrayEqualsNode.class, Arrays.class, "equals", parameterTypes, false, args1, args2);
 134     }
 135 
 136     @SuppressWarnings("all")
 137     public static boolean arraysEqualsChar(char[] a, char[] b) {
 138         return Arrays.equals(a, b);
 139     }
 140 
 141     @Test
 142     public void testEqualsShort() {
 143         Object[] args1 = new Object[N];
 144         Object[] args2 = new Object[N];
 145         int n = 0;
 146 
 147         // equal arrays
 148         for (int i = 0; i < N / 2; i++, n++) {
 149             args1[n] = new short[i];
 150             args2[n] = new short[i];
 151         }
 152 
 153         // non-equal arrays
 154         for (int i = 0; i < N / 2; i++, n++) {
 155             short[] a2 = new short[i];
 156             if (i > 0) {
 157                 a2[i - 1] = 1;
 158             }
 159             args1[n] = new short[i];
 160             args2[n] = a2;
 161         }
 162 
 163         Class<?>[] parameterTypes = new Class<?>[]{short[].class, short[].class};
 164         testSubstitution("arraysEqualsShort", ArrayEqualsNode.class, Arrays.class, "equals", parameterTypes, false, args1, args2);
 165     }
 166 
 167     @SuppressWarnings("all")
 168     public static boolean arraysEqualsShort(short[] a, short[] b) {
 169         return Arrays.equals(a, b);
 170     }
 171 
 172     @Test
 173     public void testEqualsInt() {
 174         Object[] args1 = new Object[N];
 175         Object[] args2 = new Object[N];
 176         int n = 0;
 177 
 178         // equal arrays
 179         for (int i = 0; i < N / 2; i++, n++) {
 180             args1[n] = new int[i];
 181             args2[n] = new int[i];
 182         }
 183 
 184         // non-equal arrays
 185         for (int i = 0; i < N / 2; i++, n++) {
 186             int[] a2 = new int[i];
 187             if (i > 0) {
 188                 a2[i - 1] = 1;
 189             }
 190             args1[n] = new int[i];
 191             args2[n] = a2;
 192         }
 193 
 194         Class<?>[] parameterTypes = new Class<?>[]{int[].class, int[].class};
 195         testSubstitution("arraysEqualsInt", ArrayEqualsNode.class, Arrays.class, "equals", parameterTypes, false, args1, args2);
 196     }
 197 
 198     @SuppressWarnings("all")
 199     public static boolean arraysEqualsInt(int[] a, int[] b) {
 200         return Arrays.equals(a, b);
 201     }
 202 
 203     @Test
 204     public void testEqualsLong() {
 205         Object[] args1 = new Object[N];
 206         Object[] args2 = new Object[N];
 207         int n = 0;
 208 
 209         // equal arrays
 210         for (int i = 0; i < N / 2; i++, n++) {
 211             args1[n] = new long[i];
 212             args2[n] = new long[i];
 213         }
 214 
 215         // non-equal arrays
 216         for (int i = 0; i < N / 2; i++, n++) {
 217             long[] a2 = new long[i];
 218             if (i > 0) {
 219                 a2[i - 1] = 1;
 220             }
 221             args1[n] = new long[i];
 222             args2[n] = a2;
 223         }
 224 
 225         Class<?>[] parameterTypes = new Class<?>[]{long[].class, long[].class};
 226         testSubstitution("arraysEqualsLong", ArrayEqualsNode.class, Arrays.class, "equals", parameterTypes, false, args1, args2);
 227     }
 228 
 229     @SuppressWarnings("all")
 230     public static boolean arraysEqualsLong(long[] a, long[] b) {
 231         return Arrays.equals(a, b);
 232     }
 233 
 234     @Test
 235     public void testEqualsFloat() {
 236         Object[] args1 = new Object[N];
 237         Object[] args2 = new Object[N];
 238         int n = 0;
 239 
 240         // equal arrays
 241         for (int i = 0; i < N / 2; i++, n++) {
 242             args1[n] = new float[i];
 243             args2[n] = new float[i];
 244         }
 245 
 246         // non-equal arrays
 247         for (int i = 0; i < N / 2; i++, n++) {
 248             float[] a2 = new float[i];
 249             if (i > 0) {
 250                 a2[i - 1] = 1;
 251             }
 252             args1[n] = new float[i];
 253             args2[n] = a2;
 254         }
 255 
 256         Class<?>[] parameterTypes = new Class<?>[]{float[].class, float[].class};
 257         testSubstitution("arraysEqualsFloat", ArrayEqualsNode.class, Arrays.class, "equals", parameterTypes, false, args1, args2);
 258     }
 259 
 260     @SuppressWarnings("all")
 261     public static boolean arraysEqualsFloat(float[] a, float[] b) {
 262         return Arrays.equals(a, b);
 263     }
 264 
 265     @Test
 266     public void testEqualsDouble() {
 267         Object[] args1 = new Object[N];
 268         Object[] args2 = new Object[N];
 269         int n = 0;
 270 
 271         // equal arrays
 272         for (int i = 0; i < N / 2; i++, n++) {
 273             args1[n] = new double[i];
 274             args2[n] = new double[i];
 275         }
 276 
 277         // non-equal arrays
 278         for (int i = 0; i < N / 2; i++, n++) {
 279             double[] a2 = new double[i];
 280             if (i > 0) {
 281                 a2[i - 1] = 1;
 282             }
 283             args1[n] = new double[i];
 284             args2[n] = a2;
 285         }
 286 
 287         Class<?>[] parameterTypes = new Class<?>[]{double[].class, double[].class};
 288         testSubstitution("arraysEqualsDouble", ArrayEqualsNode.class, Arrays.class, "equals", parameterTypes, false, args1, args2);
 289     }
 290 
 291     @SuppressWarnings("all")
 292     public static boolean arraysEqualsDouble(double[] a, double[] b) {
 293         return Arrays.equals(a, b);
 294     }
 295 
 296     @Test
 297     public void testEqualsNodeGVN() {
 298         test("testEqualsNodeGVNSnippet", true);
 299     }
 300 
 301     public static int[] intArrayCompare = new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9};
 302     public static int[] intArray;
 303 
 304     public static boolean testEqualsNodeGVNSnippet(boolean b) {
 305         int[] newIntArray = new int[]{0, 2, 3, 4, 5, 6, 7, 8, 9};
 306         intArray = newIntArray;
 307 
 308         if (b) {
 309             newIntArray[0] = 1;
 310             return Arrays.equals(newIntArray, intArrayCompare);
 311         } else {
 312             newIntArray[0] = 1;
 313             return Arrays.equals(newIntArray, intArrayCompare);
 314         }
 315     }
 316 
 317     @Test
 318     public void testConstants() {
 319         testGraph("testConstantsSnippet");
 320     }
 321 
 322     public static final int[] constantArray1 = new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9};
 323     public static final int[] constantArray2 = new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9};
 324 
 325     public static boolean testConstantsSnippet() {
 326         constantArray2[0] = 10;
 327         try {
 328             return Arrays.equals(constantArray1, constantArray2);
 329         } finally {
 330             constantArray2[0] = 1;
 331         }
 332     }
 333 
 334     @Test
 335     public void testCanonicalLength() {
 336         StructuredGraph graph = parseEager("testCanonicalLengthSnippet", AllowAssumptions.NO);
 337         HighTierContext context = new HighTierContext(getProviders(), getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
 338         new InliningPhase(new CanonicalizerPhase()).apply(graph, context);
 339         new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders()));
 340 
 341         Assert.assertTrue(graph.getNodes(ReturnNode.TYPE).first().result().asJavaConstant().asLong() == 0);
 342     }
 343 
 344     public static final int[] constantArray3 = new int[]{1, 2, 3};
 345 
 346     public static boolean testCanonicalLengthSnippet() {
 347         return Arrays.equals(constantArray1, constantArray3);
 348     }
 349 
 350     @Test
 351     public void testCanonicalEqual() {
 352         StructuredGraph graph = parseEager("testCanonicalEqualSnippet", AllowAssumptions.NO);
 353         HighTierContext context = new HighTierContext(getProviders(), getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
 354         new InliningPhase(new CanonicalizerPhase()).apply(graph, context);
 355         new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders()));
 356 
 357         Assert.assertTrue(graph.getNodes(ReturnNode.TYPE).first().result().asJavaConstant().asLong() == 1);
 358     }
 359 
 360     public static boolean testCanonicalEqualSnippet() {
 361         return Arrays.equals(constantArray1, constantArray1);
 362     }
 363 
 364     @Test
 365     public void testVirtualEqual() {
 366         StructuredGraph graph = parseEager("testVirtualEqualSnippet", AllowAssumptions.NO);
 367         HighTierContext context = new HighTierContext(getProviders(), getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
 368         new InliningPhase(new CanonicalizerPhase()).apply(graph, context);
 369         new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders()));
 370         new PartialEscapePhase(false, new CanonicalizerPhase()).apply(graph, context);
 371         new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders()));
 372 
 373         Assert.assertTrue(graph.getNodes(ReturnNode.TYPE).first().result().asJavaConstant().asLong() == 1);
 374     }
 375 
 376     public static boolean testVirtualEqualSnippet() {
 377         int[] array1 = new int[]{1, 2, 3, 4};
 378         int[] array2 = new int[]{1, 2, 3, 4};
 379         return Arrays.equals(array1, array2);
 380     }
 381 
 382     @Test
 383     public void testVirtualNotEqual() {
 384         StructuredGraph graph = parseEager("testVirtualNotEqualSnippet", AllowAssumptions.NO);
 385         HighTierContext context = getDefaultHighTierContext();
 386         new InliningPhase(new CanonicalizerPhase()).apply(graph, context);
 387         new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders()));
 388         new PartialEscapePhase(false, new CanonicalizerPhase()).apply(graph, context);
 389         new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders()));
 390 
 391         Assert.assertTrue(graph.getNodes(ReturnNode.TYPE).first().result().asJavaConstant().asLong() == 0);
 392     }
 393 
 394     public static boolean testVirtualNotEqualSnippet(int x) {
 395         int[] array1 = new int[]{1, 2, 100, x};
 396         int[] array2 = new int[]{1, 2, 3, 4};
 397         return Arrays.equals(array1, array2);
 398     }
 399 }