changeset 6431:2e376f8ea4e2

added snippet for lowering NewMultiArrayNodes
author Doug Simon <doug.simon@oracle.com>
date Tue, 25 Sep 2012 09:09:19 +0200
parents c96407df35ea
children 3638582c26eb
files graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/GraalOptions.java graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DimensionsNode.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewMultiArrayStubCall.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/NewObjectSnippets.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/target/amd64/AMD64NewMultiArrayStubCallOp.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewMultiArrayNode.java graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/NewMultiArrayTest.java graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetTemplate.java
diffstat 10 files changed, 454 insertions(+), 5 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/GraalOptions.java	Tue Sep 25 09:01:58 2012 +0200
+++ b/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/GraalOptions.java	Tue Sep 25 09:09:19 2012 +0200
@@ -268,6 +268,7 @@
     public static String HIRLowerNewInstance = "";
     public static String HIRLowerNewArray = "";
     public static String HIRLowerMonitors = "MonitorTest";
+    public static String HIRLowerNewMultiArray = "";
 
     /**
      * Use XIR to lower {@link Invoke} nodes.
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java	Tue Sep 25 09:01:58 2012 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java	Tue Sep 25 09:09:19 2012 +0200
@@ -196,6 +196,10 @@
         Assert.assertTrue(failed + " of " + n + " failed", failed == 0);
     }
 
+    protected Object referenceInvoke(Method method, Object receiver, Object... args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
+        return method.invoke(receiver, args);
+    }
+
     protected void test(String name, Object... args) {
         Method method = getMethod(name);
         Object expect = null;
@@ -203,7 +207,7 @@
         Throwable exception = null;
         try {
             // This gives us both the expected return value as well as ensuring that the method to be compiled is fully resolved
-            expect = method.invoke(this, args);
+            expect = referenceInvoke(method, receiver, args);
         } catch (InvocationTargetException e) {
             exception = e.getTargetException();
         } catch (Exception e) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java	Tue Sep 25 09:01:58 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java	Tue Sep 25 09:09:19 2012 +0200
@@ -441,6 +441,10 @@
             newObjectSnippets.lower((InitializeObjectNode) n, tool);
         } else if (n instanceof InitializeArrayNode) {
             newObjectSnippets.lower((InitializeArrayNode) n, tool);
+        } else if (n instanceof NewMultiArrayNode) {
+            if (matches(graph, GraalOptions.HIRLowerNewMultiArray)) {
+                newObjectSnippets.lower((NewMultiArrayNode) n, tool);
+            }
         } else {
             assert false : "Node implementing Lowerable not handled: " + n;
         }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DimensionsNode.java	Tue Sep 25 09:09:19 2012 +0200
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.nodes;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.gen.*;
+import com.oracle.graal.compiler.target.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.snippets.*;
+
+
+/**
+ * Intrinsic for allocating an on-stack array of integers to hold the dimensions
+ * of a multianewarray instruction.
+ */
+public final class DimensionsNode extends FixedWithNextNode implements LIRGenLowerable, MonitorEnter {
+
+    private final int rank;
+
+    public DimensionsNode(int rank, Kind wordKind) {
+        super(StampFactory.forWord(wordKind, true));
+        this.rank = rank;
+    }
+
+    @Override
+    public void generate(LIRGenerator gen) {
+        int size = rank * 4;
+        StackSlot array = gen.frameMap().allocateStackBlock(size, false);
+        Value result = gen.emitLea(array);
+        gen.setResult(this, result);
+    }
+
+    @SuppressWarnings("unused")
+    @NodeIntrinsic
+    public static Word allocaDimsArray(@ConstantNodeParameter int rank, @ConstantNodeParameter Kind wordKind) {
+        throw new UnsupportedOperationException();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewMultiArrayStubCall.java	Tue Sep 25 09:09:19 2012 +0200
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.nodes;
+
+import static com.oracle.graal.hotspot.target.amd64.AMD64NewMultiArrayStubCallOp.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.gen.*;
+import com.oracle.graal.compiler.target.*;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.hotspot.target.amd64.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.snippets.*;
+
+/**
+ * Node implementing a call to HotSpot's {@code new_multi_array} stub.
+ */
+public class NewMultiArrayStubCall extends FixedWithNextNode implements LIRGenLowerable {
+
+    private static final Stamp defaultStamp = StampFactory.objectNonNull();
+
+    @Input private final ValueNode hub;
+    @Input private final ValueNode dims;
+    private final int rank;
+
+    public NewMultiArrayStubCall(ValueNode hub, int rank, ValueNode dims) {
+        super(defaultStamp);
+        this.hub = hub;
+        this.rank = rank;
+        this.dims = dims;
+    }
+
+    @Override
+    public boolean inferStamp() {
+        if (stamp() == defaultStamp && hub.isConstant()) {
+            HotSpotKlassOop klassOop = (HotSpotKlassOop) this.hub.asConstant().asObject();
+            updateStamp(StampFactory.exactNonNull(klassOop.type));
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public void generate(LIRGenerator gen) {
+        RegisterValue hubFixed = HUB.asValue(Kind.Object);
+        RegisterValue resultFixed = RESULT.asValue(Kind.Object);
+        RegisterValue rankFixed = RANK.asValue(Kind.Int);
+        RegisterValue dimsFixed = DIMS.asValue(gen.target().wordKind);
+        gen.emitMove(gen.operand(hub), hubFixed);
+        gen.emitMove(gen.operand(dims), dimsFixed);
+        gen.emitMove(Constant.forInt(rank), rankFixed);
+        LIRFrameState state = gen.state();
+        gen.append(new AMD64NewMultiArrayStubCallOp(resultFixed, hubFixed, rankFixed, dimsFixed, state));
+        Variable result = gen.emitMove(resultFixed);
+        gen.setResult(this, result);
+    }
+
+    @SuppressWarnings("unused")
+    @NodeIntrinsic
+    public static Object call(Object hub, @ConstantNodeParameter int rank, Word dims) {
+        throw new UnsupportedOperationException();
+    }
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/NewObjectSnippets.java	Tue Sep 25 09:01:58 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/NewObjectSnippets.java	Tue Sep 25 09:09:19 2012 +0200
@@ -42,9 +42,12 @@
 import com.oracle.graal.snippets.*;
 import com.oracle.graal.snippets.Snippet.ConstantParameter;
 import com.oracle.graal.snippets.Snippet.Parameter;
+import com.oracle.graal.snippets.Snippet.Varargs;
+import com.oracle.graal.snippets.Snippet.VarargsParameter;
 import com.oracle.graal.snippets.SnippetTemplate.AbstractTemplates;
 import com.oracle.graal.snippets.SnippetTemplate.Arguments;
 import com.oracle.graal.snippets.SnippetTemplate.Key;
+import com.oracle.graal.snippets.nodes.*;
 
 /**
  * Snippets used for implementing NEW, ANEWARRAY and NEWARRAY.
@@ -153,6 +156,22 @@
     }
 
     /**
+     * Calls the runtime stub for implementing MULTIANEWARRAY.
+     */
+    @Snippet
+    public static Object newmultiarray(
+                    @Parameter("hub") Object hub,
+                    @ConstantParameter("rank") int rank,
+                    @VarargsParameter("dimensions") int[] dimensions) {
+        Word dims = DimensionsNode.allocaDimsArray(rank, wordKind());
+        ExplodeLoopNode.explodeLoop();
+        for (int i = 0; i < rank; i++) {
+            DirectObjectStoreNode.storeInt(dims, 0, i * 4, dimensions[i]);
+        }
+        return NewMultiArrayStubCall.call(hub, rank, dims);
+    }
+
+    /**
      * Maximum size of an object whose body is initialized by a sequence of
      * zero-stores to its fields. Larger objects have their bodies initialized
      * in a loop.
@@ -203,6 +222,7 @@
         private final ResolvedJavaMethod initializeObjectArray;
         private final ResolvedJavaMethod initializePrimitiveArray;
         private final ResolvedJavaMethod allocateArrayAndInitialize;
+        private final ResolvedJavaMethod newmultiarray;
         private final TargetDescription target;
         private final boolean useTLAB;
 
@@ -215,6 +235,7 @@
             initializeObjectArray = snippet("initializeObjectArray", Word.class, Object.class, int.class, int.class, Word.class, int.class, boolean.class);
             initializePrimitiveArray = snippet("initializePrimitiveArray", Word.class, Object.class, int.class, int.class, Word.class, int.class, boolean.class);
             allocateArrayAndInitialize = snippet("allocateArrayAndInitialize", int.class, int.class, int.class, int.class, ResolvedJavaType.class, Kind.class);
+            newmultiarray = snippet("newmultiarray", Object.class, int.class, int[].class);
         }
 
         /**
@@ -330,6 +351,22 @@
             Debug.log("Lowering initializeObjectArray in %s: node=%s, template=%s, arguments=%s", graph, initializeNode, template, arguments);
             template.instantiate(runtime, initializeNode, arguments);
         }
+
+        @SuppressWarnings("unused")
+        public void lower(NewMultiArrayNode newmultiarrayNode, LoweringTool tool) {
+            StructuredGraph graph = (StructuredGraph) newmultiarrayNode.graph();
+            int rank = newmultiarrayNode.dimensionCount();
+            ValueNode[] dims = new ValueNode[rank];
+            for (int i = 0; i < newmultiarrayNode.dimensionCount(); i++) {
+                dims[i] = newmultiarrayNode.dimension(i);
+            }
+            HotSpotResolvedJavaType type = (HotSpotResolvedJavaType) newmultiarrayNode.type();
+            HotSpotKlassOop hub = type.klassOop();
+            Key key = new Key(newmultiarray).add("dimensions", Varargs.vargargs(int.class, rank)).add("rank", rank);
+            Arguments arguments = arguments("dimensions", dims).add("hub", hub);
+            SnippetTemplate template = cache.get(key);
+            template.instantiate(runtime, newmultiarrayNode, arguments);
+        }
     }
 
     private static final SnippetCounter.Group countersNew = GraalOptions.SnippetCounters ? new SnippetCounter.Group("NewInstance") : null;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/target/amd64/AMD64NewMultiArrayStubCallOp.java	Tue Sep 25 09:09:19 2012 +0200
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.target.amd64;
+
+import static com.oracle.graal.api.code.ValueUtil.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.LIRInstruction.*;
+import com.oracle.graal.lir.amd64.*;
+import com.oracle.graal.lir.asm.*;
+import com.oracle.max.asm.target.amd64.*;
+
+/**
+ * LIR instruction for calling HotSpot's {@code new_multi_array} stub. This stub is declared in c1_Runtime1.hpp
+ * and implemented in Runtime1::generate_code_for() which is located in c1_Runtime1_x86.cpp.
+ */
+@Opcode("NEW_MULTI_ARRAY_STUB")
+public class AMD64NewMultiArrayStubCallOp extends AMD64LIRInstruction {
+
+    /**
+     * The stub places the result in RAX.
+     */
+    public static final Register RESULT = AMD64.rax;
+
+    /**
+     * The stub expects the hub in RAX.
+     */
+    public static final Register HUB = AMD64.rax;
+
+    /**
+     * The stub expects the rank in RBX.
+     */
+    public static final Register RANK = AMD64.rbx;
+
+    /**
+     * The stub expects the dimensions in RCX.
+     */
+    public static final Register DIMS = AMD64.rcx;
+
+    @Def protected Value result;
+    @Use protected Value hub;
+    @Use protected Value rank;
+    @Use protected Value dims;
+
+    @State protected LIRFrameState state;
+
+    public AMD64NewMultiArrayStubCallOp(Value result, Value hub, Value rank, Value dims, LIRFrameState state) {
+        this.result = result;
+        this.hub = hub;
+        this.rank = rank;
+        this.dims = dims;
+        this.state = state;
+    }
+
+    @Override
+    public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) {
+        HotSpotVMConfig config = HotSpotGraalRuntime.getInstance().getConfig();
+        long stub = config.newMultiArrayStub;
+        AMD64Call.directCall(tasm, masm, stub, state);
+    }
+
+    @Override
+    protected void verify() {
+        super.verify();
+        assert asRegister(hub) == HUB : "stub expects hub in " + HUB;
+        assert asRegister(rank) == RANK : "stub expect rank in " + RANK;
+        assert asRegister(dims) == DIMS : "stub expect dims in " + DIMS;
+        assert asRegister(result) == RESULT : "stub places result in " + RESULT;
+    }
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewMultiArrayNode.java	Tue Sep 25 09:01:58 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewMultiArrayNode.java	Tue Sep 25 09:09:19 2012 +0200
@@ -32,7 +32,7 @@
  * The {@code NewMultiArrayNode} represents an allocation of a multi-dimensional object
  * array.
  */
-public final class NewMultiArrayNode extends FixedWithNextNode implements LIRLowerable {
+public final class NewMultiArrayNode extends FixedWithNextNode implements LIRLowerable, Lowerable {
 
     @Input private final NodeInputList<ValueNode> dimensions;
     private final ResolvedJavaType type;
@@ -58,6 +58,11 @@
     }
 
     @Override
+    public void lower(LoweringTool tool) {
+        tool.getRuntime().lower(this, tool);
+    }
+
+    @Override
     public void generate(LIRGeneratorTool gen) {
         gen.visitNewMultiArray(this);
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/NewMultiArrayTest.java	Tue Sep 25 09:09:19 2012 +0200
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.snippets;
+
+import java.lang.reflect.*;
+import java.util.*;
+
+import org.junit.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.test.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.java.*;
+
+/**
+ * Tests the lowering of the MULTIANEWARRAY instruction.
+ */
+public class NewMultiArrayTest extends GraalCompilerTest {
+
+    @Override
+    protected void assertEquals(Object expected, Object actual) {
+        Assert.assertTrue(expected != null);
+        Assert.assertTrue(actual != null);
+        super.assertEquals(expected.getClass(), actual.getClass());
+        if (expected instanceof int[]) {
+            Assert.assertArrayEquals((int[]) expected, (int[]) actual);
+        } else if (expected instanceof byte[]) {
+            Assert.assertArrayEquals((byte[]) expected, (byte[]) actual);
+        } else if (expected instanceof char[]) {
+            Assert.assertArrayEquals((char[]) expected, (char[]) actual);
+        } else if (expected instanceof short[]) {
+            Assert.assertArrayEquals((short[]) expected, (short[]) actual);
+        } else if (expected instanceof float[]) {
+            Assert.assertArrayEquals((float[]) expected, (float[]) actual, 0.0f);
+        } else if (expected instanceof long[]) {
+            Assert.assertArrayEquals((long[]) expected, (long[]) actual);
+        } else if (expected instanceof double[]) {
+            Assert.assertArrayEquals((double[]) expected, (double[]) actual, 0.0d);
+        } else if (expected instanceof Object[]) {
+            Assert.assertArrayEquals((Object[]) expected, (Object[]) actual);
+        } else {
+            Assert.fail("non-array value encountered: " + expected);
+        }
+    }
+
+    private static int rank(ResolvedJavaType type) {
+        String name = type.name();
+        int dims = 0;
+        while (dims < name.length() && name.charAt(dims) == '[') {
+            dims++;
+        }
+        return dims;
+    }
+
+    @Override
+    protected InstalledCode getCode(final ResolvedJavaMethod method, final StructuredGraph graph) {
+        boolean forceCompile = false;
+        if (bottomType != null) {
+            List<NewMultiArrayNode> snapshot = graph.getNodes().filter(NewMultiArrayNode.class).snapshot();
+            assert snapshot != null;
+            assert snapshot.size() == 1;
+
+            NewMultiArrayNode node = snapshot.get(0);
+            assert rank(arrayType) == dimensions.length;
+            int rank = dimensions.length;
+            ValueNode[] dimensionNodes = new ValueNode[rank];
+            for (int i = 0; i < rank; i++) {
+                dimensionNodes[i] = graph.unique(ConstantNode.forInt(dimensions[i], graph));
+            }
+
+            NewMultiArrayNode repl = graph.add(new NewMultiArrayNode(arrayType, dimensionNodes));
+            graph.replaceFixedWithFixed(node, repl);
+            forceCompile = true;
+        }
+        return super.getCode(method, graph, forceCompile);
+    }
+
+    @Override
+    protected Object referenceInvoke(Method method, Object receiver, Object... args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
+        if (bottomType != null) {
+            Class< ? > componentType = bottomType.toJava();
+            try {
+                return Array.newInstance(componentType, dimensions);
+            } catch (Exception e) {
+                throw new InvocationTargetException(e);
+            }
+        }
+        return super.referenceInvoke(method, receiver, args);
+    }
+
+    ResolvedJavaType arrayType;
+    ResolvedJavaType bottomType;
+    int[] dimensions;
+
+    @Test
+    public void test1() {
+        for (Class clazz : new Class[] {byte.class, char.class, short.class, int.class, float.class, long.class, double.class, String.class}) {
+            bottomType = runtime.getResolvedJavaType(clazz);
+            arrayType = bottomType;
+            for (int rank : new int[] {1, 2, 10, 50, 100, 200, 254, 255}) {
+                while (rank(arrayType) != rank) {
+                    arrayType = arrayType.arrayOf();
+                }
+
+                dimensions = new int[rank];
+                for (int i = 0; i < rank; i++) {
+                    dimensions[i] = 1;
+                }
+
+                test("newMultiArray");
+            }
+        }
+        bottomType = null;
+        arrayType = null;
+    }
+
+    public static Object newMultiArray() {
+        // This is merely a template - the NewMultiArrayNode is replaced in getCode() above.
+        // This also means we need a separate test for correct handling of negative dimensions
+        // as deoptimization won't do what we want for a graph modified to be different from the source bytecode.
+        return new Object[10][9][8];
+    }
+
+    @Test
+    public void test2() {
+        test("newMultiArrayException");
+    }
+
+    public static Object newMultiArrayException() {
+        return new Object[10][9][-8];
+    }
+}
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetTemplate.java	Tue Sep 25 09:01:58 2012 +0200
+++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetTemplate.java	Tue Sep 25 09:09:19 2012 +0200
@@ -498,9 +498,14 @@
                 for (int j = 0; j < length; j++) {
                     LocalNode local = locals[j];
                     assert local != null;
-                    Constant constant = Constant.forBoxed(local.kind(), Array.get(array, j));
-                    ConstantNode element = ConstantNode.forConstant(constant, runtime, replaceeGraph);
-                    replacements.put(local, element);
+                    Object value = Array.get(array, j);
+                    if (value instanceof ValueNode) {
+                        replacements.put(local, (ValueNode) value);
+                    } else {
+                        Constant constant = Constant.forBoxed(local.kind(), value);
+                        ConstantNode element = ConstantNode.forConstant(constant, runtime, replaceeGraph);
+                        replacements.put(local, element);
+                    }
                 }
             }
         }