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