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}