1/*
2 * Copyright (c) 2012, 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 */
23package org.graalvm.compiler.replacements.test;
24
25import java.lang.reflect.Array;
26import java.lang.reflect.InvocationTargetException;
27import java.util.List;
28
29import org.junit.Test;
30
31import org.graalvm.compiler.core.test.GraalCompilerTest;
32import org.graalvm.compiler.nodes.ConstantNode;
33import org.graalvm.compiler.nodes.StructuredGraph;
34import org.graalvm.compiler.nodes.ValueNode;
35import org.graalvm.compiler.nodes.java.NewMultiArrayNode;
36import org.graalvm.compiler.options.OptionValues;
37
38import jdk.vm.ci.code.InstalledCode;
39import jdk.vm.ci.meta.ResolvedJavaMethod;
40import jdk.vm.ci.meta.ResolvedJavaType;
41
42/**
43 * Tests the lowering of the MULTIANEWARRAY instruction.
44 */
45public class NewMultiArrayTest extends GraalCompilerTest {
46
47    private static int rank(ResolvedJavaType type) {
48        String name = type.getName();
49        int dims = 0;
50        while (dims < name.length() && name.charAt(dims) == '[') {
51            dims++;
52        }
53        return dims;
54    }
55
56    @Override
57    protected InstalledCode getCode(ResolvedJavaMethod method, StructuredGraph g, boolean ignore, boolean installAsDefault, OptionValues options) {
58        StructuredGraph graph = g == null ? parseForCompile(method, options) : g;
59        boolean forceCompile = false;
60        if (bottomType != null) {
61            List<NewMultiArrayNode> snapshot = graph.getNodes().filter(NewMultiArrayNode.class).snapshot();
62            assert snapshot != null;
63            assert snapshot.size() == 1;
64
65            NewMultiArrayNode node = snapshot.get(0);
66            assert rank(arrayType) == dimensions.length;
67            int rank = dimensions.length;
68            ValueNode[] dimensionNodes = new ValueNode[rank];
69            for (int i = 0; i < rank; i++) {
70                dimensionNodes[i] = ConstantNode.forInt(dimensions[i], graph);
71            }
72
73            NewMultiArrayNode repl = graph.add(new NewMultiArrayNode(arrayType, dimensionNodes));
74            graph.replaceFixedWithFixed(node, repl);
75            forceCompile = true;
76        }
77        return super.getCode(method, graph, forceCompile, installAsDefault, options);
78    }
79
80    @Override
81    protected Object referenceInvoke(ResolvedJavaMethod method, Object receiver, Object... args)
82                    throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException {
83        if (bottomType != null) {
84            try {
85                return Array.newInstance(bottomClass, dimensions);
86            } catch (Exception e) {
87                throw new InvocationTargetException(e);
88            }
89        }
90        return super.referenceInvoke(method, receiver, args);
91    }
92
93    ResolvedJavaType arrayType;
94    ResolvedJavaType bottomType;
95    Class<?> bottomClass;
96    int[] dimensions;
97
98    @Test
99    public void test1() {
100        for (Class<?> clazz : new Class<?>[]{byte.class, char.class, short.class, int.class, float.class, long.class, double.class, String.class}) {
101            bottomClass = clazz;
102            bottomType = getMetaAccess().lookupJavaType(clazz);
103            arrayType = bottomType;
104            for (int rank : new int[]{1, 2, 10, 50, 100, 200, 254, 255}) {
105                while (rank(arrayType) != rank) {
106                    arrayType = arrayType.getArrayClass();
107                }
108
109                dimensions = new int[rank];
110                for (int i = 0; i < rank; i++) {
111                    dimensions[i] = 1;
112                }
113
114                test("newMultiArray");
115            }
116        }
117        bottomType = null;
118        arrayType = null;
119    }
120
121    public static Object newMultiArray() {
122        // This is merely a template - the NewMultiArrayNode is replaced in getCode() above.
123        // This also means we need a separate test for correct handling of negative dimensions
124        // as deoptimization won't do what we want for a graph modified to be different from the
125        // source bytecode.
126        return new Object[10][9][8];
127    }
128
129    @Test
130    public void test2() {
131        test("newMultiArrayException");
132    }
133
134    public static Object newMultiArrayException() {
135        return new Object[10][9][-8];
136    }
137}
138