1 /* 2 * Copyright (c) 2011, 2018, 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.hotspot.test; 26 27 import java.lang.reflect.Array; 28 import java.util.ArrayList; 29 import java.util.HashMap; 30 31 import org.graalvm.compiler.core.test.GraalCompilerTest; 32 import org.graalvm.compiler.graph.Node; 33 import org.graalvm.compiler.replacements.arraycopy.ArrayCopySnippets; 34 import org.graalvm.compiler.nodes.DirectCallTargetNode; 35 import org.graalvm.compiler.nodes.Invoke; 36 import org.graalvm.compiler.nodes.LoweredCallTargetNode; 37 import org.graalvm.compiler.nodes.StructuredGraph; 38 import org.graalvm.compiler.options.OptionValues; 39 import org.junit.Assert; 40 import org.junit.Test; 41 42 import jdk.vm.ci.code.InstalledCode; 43 import jdk.vm.ci.meta.JavaMethod; 44 import jdk.vm.ci.meta.ResolvedJavaMethod; 45 46 /** 47 * Tests intrinsification of {@link System#arraycopy(Object, int, Object, int, int)}. 48 */ 49 public class ArrayCopyIntrinsificationTest extends GraalCompilerTest { 50 51 @Override 52 protected InstalledCode getCode(ResolvedJavaMethod method, StructuredGraph g, boolean forceCompile, boolean installAsDefault, OptionValues options) { 53 StructuredGraph graph = g == null ? parseForCompile(method) : g; 54 int nodeCount = graph.getNodeCount(); 55 InstalledCode result = super.getCode(method, graph, forceCompile, installAsDefault, options); 56 boolean graphWasProcessed = nodeCount != graph.getNodeCount(); 57 if (graphWasProcessed) { 58 if (mustIntrinsify) { 59 for (Node node : graph.getNodes()) { 60 if (node instanceof Invoke) { 61 Invoke invoke = (Invoke) node; 62 Assert.assertTrue(invoke.callTarget() instanceof DirectCallTargetNode); 63 LoweredCallTargetNode directCall = (LoweredCallTargetNode) invoke.callTarget(); 64 JavaMethod callee = directCall.targetMethod(); 65 if (callee.getDeclaringClass().equals(getMetaAccess().lookupJavaType(System.class)) && callee.getName().equals("arraycopy")) { 66 // A partial snippet (e.g., ArrayCopySnippets.checkcastArraycopy) may 67 // call the original arraycopy method 68 } else { 69 Assert.assertTrue(callee.toString(), callee.getName().equals("<init>")); 70 Assert.assertTrue(getMetaAccess().lookupJavaType(ArrayIndexOutOfBoundsException.class).equals(callee.getDeclaringClass()) || 71 getMetaAccess().lookupJavaType(NullPointerException.class).equals(callee.getDeclaringClass())); 72 } 73 } 74 } 75 } else { 76 boolean found = false; 77 for (Node node : graph.getNodes()) { 78 if (node instanceof Invoke) { 79 Invoke invoke = (Invoke) node; 80 LoweredCallTargetNode directCall = (LoweredCallTargetNode) invoke.callTarget(); 81 JavaMethod callee = directCall.targetMethod(); 82 if (callee.getDeclaringClass().equals(getMetaAccess().lookupJavaType(System.class)) && callee.getName().equals("arraycopy")) { 83 found = true; 84 } else { 85 fail("found invoke to some method other than arraycopy: " + callee); 86 } 87 } 88 } 89 Assert.assertTrue("did not find invoke to arraycopy", found); 90 } 91 } 92 return result; 93 } 94 95 boolean mustIntrinsify = true; 96 97 @Test 98 public void test0() { 99 // Array store checks 100 test("genericArraycopy", new Object(), 0, new Object[0], 0, 0); 101 test("genericArraycopy", new Object[0], 0, new Object(), 0, 0); 102 } 103 104 @Test 105 public void test1() { 106 String name = "intArraycopy"; 107 int[] src = {234, 5345, 756, 23, 8, 345, 873, 440}; 108 // Null checks 109 test(name, null, 0, src, 0, 0); 110 test(name, src, 0, null, 0, 0); 111 // Bounds checks 112 test(name, src, 0, src, 0, -1); 113 test(name, src, 0, src, 0, src.length + 1); 114 } 115 116 @Test 117 public void testByte() { 118 byte[] src = {-1, 0, 1, 2, 3, 4}; 119 testHelper("byteArraycopy", src); 120 } 121 122 @Test 123 public void testChar() { 124 char[] src = "some string of chars".toCharArray(); 125 testHelper("charArraycopy", src); 126 } 127 128 @Test 129 public void testShort() { 130 short[] src = {234, 5345, 756, 23, 8, 345, 873, 440}; 131 testHelper("shortArraycopy", src); 132 } 133 134 @Test 135 public void testInt() { 136 int[] src = {234, 5345, 756, 23, 8, 345, 873, 440}; 137 testHelper("intArraycopy", src); 138 } 139 140 @Test 141 public void testFloat() { 142 float[] src = {234, 5345, 756, 23, 8, 345, 873, 440}; 143 testHelper("floatArraycopy", src); 144 } 145 146 @Test 147 public void testLong() { 148 long[] src = {234, 5345, 756, 23, 8, 345, 873, 440}; 149 testHelper("longArraycopy", src); 150 } 151 152 @Test 153 public void testDouble() { 154 double[] src = {234, 5345, 756, 23, 8, 345, 873, 440}; 155 testHelper("doubleArraycopy", src); 156 } 157 158 @Test 159 public void testObject() { 160 Object[] src = {"one", "two", "three", new ArrayList<>(), new HashMap<>()}; 161 testHelper("objectArraycopy", src); 162 } 163 164 /** 165 * Tests {@link ArrayCopySnippets#arraycopyGenericSnippet} with checkcast. 166 */ 167 @Test 168 public void testArrayStoreException() { 169 Object[] src = {"one", "two", "three", new ArrayList<>(), new HashMap<>()}; 170 Object[] dst = new CharSequence[src.length]; 171 // Will throw ArrayStoreException for 4th element 172 test("objectArraycopy", src, 0, dst, 0, src.length); 173 } 174 175 @Test 176 public void testDisjointObject() { 177 Integer[] src1 = {1, 2, 3, 4}; 178 test("objectArraycopy", src1, 0, src1, 1, src1.length - 1); 179 180 Integer[] src2 = {1, 2, 3, 4}; 181 test("objectArraycopy", src2, 1, src2, 0, src2.length - 1); 182 } 183 184 @Test 185 public void testObjectExact() { 186 Integer[] src = {1, 2, 3, 4}; 187 testHelper("objectArraycopyExact", src); 188 } 189 190 private static Object newArray(Object proto, int length) { 191 assert proto != null; 192 assert proto.getClass().isArray(); 193 return Array.newInstance(proto.getClass().getComponentType(), length); 194 } 195 196 private void testHelper(String name, Object src) { 197 int srcLength = Array.getLength(src); 198 199 // Complete array copy 200 test(name, src, 0, newArray(src, srcLength), 0, srcLength); 201 202 for (int length : new int[]{0, 1, srcLength - 1, srcLength}) { 203 // Partial array copying 204 test(name, src, 0, newArray(src, length), 0, length); 205 test(name, src, srcLength - length, newArray(src, length), 0, length); 206 test(name, src, 0, newArray(src, srcLength), 0, length); 207 } 208 209 if (srcLength > 1) { 210 test(name, src, 0, src, 1, srcLength - 1); 211 } 212 } 213 214 public static Object genericArraycopy(Object src, int srcPos, Object dst, int dstPos, int length) { 215 System.arraycopy(src, srcPos, dst, dstPos, length); 216 return dst; 217 } 218 219 public static Object[] objectArraycopy(Object[] src, int srcPos, Object[] dst, int dstPos, int length) { 220 System.arraycopy(src, srcPos, dst, dstPos, length); 221 return dst; 222 } 223 224 public static Object[] objectArraycopyExact(Integer[] src, int srcPos, Integer[] dst, int dstPos, int length) { 225 System.arraycopy(src, srcPos, dst, dstPos, length); 226 return dst; 227 } 228 229 public static boolean[] booleanArraycopy(boolean[] src, int srcPos, boolean[] dst, int dstPos, int length) { 230 System.arraycopy(src, srcPos, dst, dstPos, length); 231 return dst; 232 } 233 234 public static byte[] byteArraycopy(byte[] src, int srcPos, byte[] dst, int dstPos, int length) { 235 System.arraycopy(src, srcPos, dst, dstPos, length); 236 return dst; 237 } 238 239 public static char[] charArraycopy(char[] src, int srcPos, char[] dst, int dstPos, int length) { 240 System.arraycopy(src, srcPos, dst, dstPos, length); 241 return dst; 242 } 243 244 public static short[] shortArraycopy(short[] src, int srcPos, short[] dst, int dstPos, int length) { 245 System.arraycopy(src, srcPos, dst, dstPos, length); 246 return dst; 247 } 248 249 public static int[] intArraycopy(int[] src, int srcPos, int[] dst, int dstPos, int length) { 250 System.arraycopy(src, srcPos, dst, dstPos, length); 251 return dst; 252 } 253 254 public static float[] floatArraycopy(float[] src, int srcPos, float[] dst, int dstPos, int length) { 255 System.arraycopy(src, srcPos, dst, dstPos, length); 256 return dst; 257 } 258 259 public static long[] longArraycopy(long[] src, int srcPos, long[] dst, int dstPos, int length) { 260 System.arraycopy(src, srcPos, dst, dstPos, length); 261 return dst; 262 } 263 264 public static double[] doubleArraycopy(double[] src, int srcPos, double[] dst, int dstPos, int length) { 265 System.arraycopy(src, srcPos, dst, dstPos, length); 266 return dst; 267 } 268 269 /** 270 * Test case derived from assertion while compiling <a href= 271 * "https://code.google.com/r/baggiogamp-guava/source/browse/guava/src/com/google/common/collect/ArrayTable.java?r=d2e06112416223cb5437d43c12a989c0adc7345b#181" 272 * > com.google.common.collect.ArrayTable(ArrayTable other)</a>. 273 */ 274 @Test 275 public void testCopyRows() { 276 Object[][] rows = {{"a1", "a2", "a3", "a4"}, {"b1", "b2", "b3", "b4"}, {"c1", "c2", "c3", "c4"}}; 277 test("copyRows", rows, 4, Integer.valueOf(rows.length)); 278 } 279 280 public static Object[][] copyRows(Object[][] rows, int rowSize, Integer rowCount) { 281 Object[][] copy = new Object[rows.length][rowSize]; 282 for (int i = 0; i < rowCount.intValue(); i++) { 283 System.arraycopy(rows[i], 0, copy[i], 0, rows[i].length); 284 } 285 return copy; 286 } 287 }