001/* 002 * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. 008 * 009 * This code is distributed in the hope that it will be useful, but WITHOUT 010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 011 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 012 * version 2 for more details (a copy is included in the LICENSE file that 013 * accompanied this code). 014 * 015 * You should have received a copy of the GNU General Public License version 016 * 2 along with this work; if not, write to the Free Software Foundation, 017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 018 * 019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 020 * or visit www.oracle.com if you need additional information or have any 021 * questions. 022 */ 023package com.oracle.graal.hotspot.test; 024 025import java.lang.reflect.*; 026import java.util.*; 027 028import jdk.internal.jvmci.code.*; 029import jdk.internal.jvmci.meta.*; 030 031import org.junit.*; 032 033import com.oracle.graal.compiler.test.*; 034import com.oracle.graal.graph.*; 035import com.oracle.graal.hotspot.replacements.arraycopy.*; 036import com.oracle.graal.nodes.*; 037 038/** 039 * Tests intrinsification of {@link System#arraycopy(Object, int, Object, int, int)}. 040 */ 041public class ArrayCopyIntrinsificationTest extends GraalCompilerTest { 042 043 @Override 044 protected InstalledCode getCode(ResolvedJavaMethod method, StructuredGraph g) { 045 StructuredGraph graph = g == null ? parseForCompile(method) : g; 046 int nodeCount = graph.getNodeCount(); 047 InstalledCode result = super.getCode(method, graph); 048 boolean graphWasProcessed = nodeCount != graph.getNodeCount(); 049 if (graphWasProcessed) { 050 if (mustIntrinsify) { 051 for (Node node : graph.getNodes()) { 052 if (node instanceof Invoke) { 053 Invoke invoke = (Invoke) node; 054 Assert.assertTrue(invoke.callTarget() instanceof DirectCallTargetNode); 055 LoweredCallTargetNode directCall = (LoweredCallTargetNode) invoke.callTarget(); 056 JavaMethod callee = directCall.targetMethod(); 057 if (callee.getDeclaringClass().equals(getMetaAccess().lookupJavaType(System.class)) && callee.getName().equals("arraycopy")) { 058 // A partial snippet (e.g., ArrayCopySnippets.checkcastArraycopy) may 059 // call the original arraycopy method 060 } else { 061 Assert.assertTrue(callee.toString(), callee.getName().equals("<init>")); 062 Assert.assertTrue(getMetaAccess().lookupJavaType(ArrayIndexOutOfBoundsException.class).equals(callee.getDeclaringClass()) || 063 getMetaAccess().lookupJavaType(NullPointerException.class).equals(callee.getDeclaringClass())); 064 } 065 } 066 } 067 } else { 068 boolean found = false; 069 for (Node node : graph.getNodes()) { 070 if (node instanceof Invoke) { 071 Invoke invoke = (Invoke) node; 072 LoweredCallTargetNode directCall = (LoweredCallTargetNode) invoke.callTarget(); 073 JavaMethod callee = directCall.targetMethod(); 074 if (callee.getDeclaringClass().equals(getMetaAccess().lookupJavaType(System.class)) && callee.getName().equals("arraycopy")) { 075 found = true; 076 } else { 077 fail("found invoke to some method other than arraycopy: " + callee); 078 } 079 } 080 } 081 Assert.assertTrue("did not find invoke to arraycopy", found); 082 } 083 } 084 return result; 085 } 086 087 boolean mustIntrinsify = true; 088 089 @Test 090 public void test0() { 091 // Array store checks 092 test("genericArraycopy", new Object(), 0, new Object[0], 0, 0); 093 test("genericArraycopy", new Object[0], 0, new Object(), 0, 0); 094 } 095 096 @Test 097 public void test1() { 098 String name = "intArraycopy"; 099 int[] src = {234, 5345, 756, 23, 8, 345, 873, 440}; 100 // Null checks 101 test(name, null, 0, src, 0, 0); 102 test(name, src, 0, null, 0, 0); 103 // Bounds checks 104 test(name, src, 0, src, 0, -1); 105 test(name, src, 0, src, 0, src.length + 1); 106 } 107 108 @Test 109 public void testByte() { 110 byte[] src = {-1, 0, 1, 2, 3, 4}; 111 testHelper("byteArraycopy", src); 112 } 113 114 @Test 115 public void testChar() { 116 char[] src = "some string of chars".toCharArray(); 117 testHelper("charArraycopy", src); 118 } 119 120 @Test 121 public void testShort() { 122 short[] src = {234, 5345, 756, 23, 8, 345, 873, 440}; 123 testHelper("shortArraycopy", src); 124 } 125 126 @Test 127 public void testInt() { 128 int[] src = {234, 5345, 756, 23, 8, 345, 873, 440}; 129 testHelper("intArraycopy", src); 130 } 131 132 @Test 133 public void testFloat() { 134 float[] src = {234, 5345, 756, 23, 8, 345, 873, 440}; 135 testHelper("floatArraycopy", src); 136 } 137 138 @Test 139 public void testLong() { 140 long[] src = {234, 5345, 756, 23, 8, 345, 873, 440}; 141 testHelper("longArraycopy", src); 142 } 143 144 @Test 145 public void testDouble() { 146 double[] src = {234, 5345, 756, 23, 8, 345, 873, 440}; 147 testHelper("doubleArraycopy", src); 148 } 149 150 @Test 151 public void testObject() { 152 Object[] src = {"one", "two", "three", new ArrayList<>(), new HashMap<>()}; 153 testHelper("objectArraycopy", src); 154 } 155 156 /** 157 * Tests {@link ArrayCopySnippets#checkcastArraycopyWork(Object, int, Object, int, int)}. 158 */ 159 @Test 160 public void testArrayStoreException() { 161 Object[] src = {"one", "two", "three", new ArrayList<>(), new HashMap<>()}; 162 Object[] dst = new CharSequence[src.length]; 163 // Will throw ArrayStoreException for 4th element 164 test("objectArraycopy", src, 0, dst, 0, src.length); 165 } 166 167 @Test 168 public void testDisjointObject() { 169 Integer[] src1 = {1, 2, 3, 4}; 170 test("objectArraycopy", src1, 0, src1, 1, src1.length - 1); 171 172 Integer[] src2 = {1, 2, 3, 4}; 173 test("objectArraycopy", src2, 1, src2, 0, src2.length - 1); 174 } 175 176 @Test 177 public void testObjectExact() { 178 Integer[] src = {1, 2, 3, 4}; 179 testHelper("objectArraycopyExact", src); 180 } 181 182 private static Object newArray(Object proto, int length) { 183 assert proto != null; 184 assert proto.getClass().isArray(); 185 return Array.newInstance(proto.getClass().getComponentType(), length); 186 } 187 188 private void testHelper(String name, Object src) { 189 int srcLength = Array.getLength(src); 190 191 // Complete array copy 192 test(name, src, 0, newArray(src, srcLength), 0, srcLength); 193 194 for (int length : new int[]{0, 1, srcLength - 1, srcLength}) { 195 // Partial array copying 196 test(name, src, 0, newArray(src, length), 0, length); 197 test(name, src, srcLength - length, newArray(src, length), 0, length); 198 test(name, src, 0, newArray(src, srcLength), 0, length); 199 } 200 201 if (srcLength > 1) { 202 test(name, src, 0, src, 1, srcLength - 1); 203 } 204 } 205 206 public static Object genericArraycopy(Object src, int srcPos, Object dst, int dstPos, int length) { 207 System.arraycopy(src, srcPos, dst, dstPos, length); 208 return dst; 209 } 210 211 public static Object[] objectArraycopy(Object[] src, int srcPos, Object[] dst, int dstPos, int length) { 212 System.arraycopy(src, srcPos, dst, dstPos, length); 213 return dst; 214 } 215 216 public static Object[] objectArraycopyExact(Integer[] src, int srcPos, Integer[] dst, int dstPos, int length) { 217 System.arraycopy(src, srcPos, dst, dstPos, length); 218 return dst; 219 } 220 221 public static boolean[] booleanArraycopy(boolean[] src, int srcPos, boolean[] dst, int dstPos, int length) { 222 System.arraycopy(src, srcPos, dst, dstPos, length); 223 return dst; 224 } 225 226 public static byte[] byteArraycopy(byte[] src, int srcPos, byte[] dst, int dstPos, int length) { 227 System.arraycopy(src, srcPos, dst, dstPos, length); 228 return dst; 229 } 230 231 public static char[] charArraycopy(char[] src, int srcPos, char[] dst, int dstPos, int length) { 232 System.arraycopy(src, srcPos, dst, dstPos, length); 233 return dst; 234 } 235 236 public static short[] shortArraycopy(short[] src, int srcPos, short[] dst, int dstPos, int length) { 237 System.arraycopy(src, srcPos, dst, dstPos, length); 238 return dst; 239 } 240 241 public static int[] intArraycopy(int[] src, int srcPos, int[] dst, int dstPos, int length) { 242 System.arraycopy(src, srcPos, dst, dstPos, length); 243 return dst; 244 } 245 246 public static float[] floatArraycopy(float[] src, int srcPos, float[] dst, int dstPos, int length) { 247 System.arraycopy(src, srcPos, dst, dstPos, length); 248 return dst; 249 } 250 251 public static long[] longArraycopy(long[] src, int srcPos, long[] dst, int dstPos, int length) { 252 System.arraycopy(src, srcPos, dst, dstPos, length); 253 return dst; 254 } 255 256 public static double[] doubleArraycopy(double[] src, int srcPos, double[] dst, int dstPos, int length) { 257 System.arraycopy(src, srcPos, dst, dstPos, length); 258 return dst; 259 } 260 261 /** 262 * Test case derived from assertion while compiling <a href= 263 * "https://code.google.com/r/baggiogamp-guava/source/browse/guava/src/com/google/common/collect/ArrayTable.java?r=d2e06112416223cb5437d43c12a989c0adc7345b#181" 264 * > com.google.common.collect.ArrayTable(ArrayTable other)</a>. 265 */ 266 @Test 267 public void testCopyRows() { 268 Object[][] rows = {{"a1", "a2", "a3", "a4"}, {"b1", "b2", "b3", "b4"}, {"c1", "c2", "c3", "c4"}}; 269 test("copyRows", rows, 4, new Integer(rows.length)); 270 } 271 272 public static Object[][] copyRows(Object[][] rows, int rowSize, Integer rowCount) { 273 Object[][] copy = new Object[rows.length][rowSize]; 274 for (int i = 0; i < rowCount.intValue(); i++) { 275 System.arraycopy(rows[i], 0, copy[i], 0, rows[i].length); 276 } 277 return copy; 278 } 279}