Mercurial > hg > graal-compiler
changeset 6431:2e376f8ea4e2
added snippet for lowering NewMultiArrayNodes
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); + } } } }