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