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