# HG changeset patch # User Doug Simon # Date 1346428650 -7200 # Node ID 5d7d9a6953bdff6ee915bac7611cf878e3d846f8 # Parent 4535a87e8bf895d37fee37de1a9078e017391dd3 added InstanceOfSnippets which passes InstanceOfTest but is not yet enabled for general lowering diff -r 4535a87e8bf8 -r 5d7d9a6953bd graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalOptions.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalOptions.java Wed Aug 29 13:05:43 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalOptions.java Fri Aug 31 17:57:30 2012 +0200 @@ -271,6 +271,7 @@ * Only instructions in methods whose fully qualified name contains this option will be HIR lowered. */ public static String HIRLowerCheckcast = ""; + public static String HIRLowerInstanceOf = "InstanceOfTest"; public static String HIRLowerNewInstance = ""; public static String HIRLowerNewArray = ""; diff -r 4535a87e8bf8 -r 5d7d9a6953bd graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LoweringPhase.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LoweringPhase.java Wed Aug 29 13:05:43 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LoweringPhase.java Fri Aug 31 17:57:30 2012 +0200 @@ -22,6 +22,8 @@ */ package com.oracle.graal.compiler.phases; +import java.util.*; + import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.*; @@ -39,7 +41,16 @@ */ public class LoweringPhase extends Phase { - private abstract class LoweringToolBase implements LoweringTool { + final class LoweringToolImpl implements LoweringTool { + + final FixedNode guardAnchor; + final NodeBitMap activeGuards; + FixedWithNextNode lastFixedNode; + + public LoweringToolImpl(FixedNode guardAnchor, NodeBitMap activeGuards) { + this.guardAnchor = guardAnchor; + this.activeGuards = activeGuards; + } @Override public GraalCodeCacheProvider getRuntime() { @@ -60,6 +71,27 @@ public Assumptions assumptions() { return assumptions; } + + @Override + public ValueNode createGuard(BooleanNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action, boolean negated, long leafGraphId) { + if (GraalOptions.OptEliminateGuards) { + for (Node usage : condition.usages()) { + if (!activeGuards.isNew(usage) && activeGuards.isMarked(usage)) { + return (ValueNode) usage; + } + } + } + GuardNode newGuard = guardAnchor.graph().unique(new GuardNode(condition, guardAnchor, deoptReason, action, negated, leafGraphId)); + if (GraalOptions.OptEliminateGuards) { + activeGuards.grow(); + activeGuards.mark(newGuard); + } + return newGuard; + } + + public FixedWithNextNode lastFixedNode() { + return lastFixedNode; + } } private final GraalCodeCacheProvider runtime; @@ -130,42 +162,42 @@ } } - private void process(final Block b, final NodeBitMap activeGuards, final ValueNode anchor, SchedulePhase schedule, NodeBitMap processed) { + private void process(final Block b, final NodeBitMap activeGuards, final FixedNode anchor, SchedulePhase schedule, NodeBitMap processed) { - final LoweringTool loweringTool = new LoweringToolBase() { + final LoweringToolImpl loweringTool = new LoweringToolImpl(anchor, activeGuards); + + // Lower the instructions of this block. + List nodes = schedule.nodesFor(b); - @Override - public ValueNode getGuardAnchor() { - return anchor; + for (Node node : nodes) { + FixedNode lastFixedNext = null; + if (node instanceof FixedWithNextNode) { + FixedWithNextNode fixed = (FixedWithNextNode) node; + lastFixedNext = fixed.next(); + loweringTool.lastFixedNode = fixed; } - @Override - public ValueNode createGuard(BooleanNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action, boolean negated, long leafGraphId) { - FixedNode guardAnchor = (FixedNode) getGuardAnchor(); - if (GraalOptions.OptEliminateGuards) { - for (Node usage : condition.usages()) { - if (!activeGuards.isNew(usage) && activeGuards.isMarked(usage)) { - return (ValueNode) usage; - } - } - } - GuardNode newGuard = guardAnchor.graph().unique(new GuardNode(condition, guardAnchor, deoptReason, action, negated, leafGraphId)); - if (GraalOptions.OptEliminateGuards) { - activeGuards.grow(); - activeGuards.mark(newGuard); - } - return newGuard; - } - }; - - // Lower the instructions of this block. - for (Node node : schedule.nodesFor(b)) { - if (!processed.isMarked(node)) { + if (node.isAlive() && !processed.isMarked(node)) { processed.mark(node); if (node instanceof Lowerable) { ((Lowerable) node).lower(loweringTool); } } + + if (loweringTool.lastFixedNode == node && !node.isAlive()) { + if (lastFixedNext == null) { + loweringTool.lastFixedNode = null; + } else { + Node prev = lastFixedNext.predecessor(); + if (prev != node && prev instanceof FixedWithNextNode) { + loweringTool.lastFixedNode = (FixedWithNextNode) prev; + } else if (lastFixedNext instanceof FixedWithNextNode) { + loweringTool.lastFixedNode = (FixedWithNextNode) lastFixedNext; + } else { + loweringTool.lastFixedNode = null; + } + } + } } } } diff -r 4535a87e8bf8 -r 5d7d9a6953bd graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java --- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java Wed Aug 29 13:05:43 2012 +0200 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java Fri Aug 31 17:57:30 2012 +0200 @@ -606,7 +606,7 @@ while (index < directInputCount) { Node input = getNode(node, inputOffsets[index]); if (input == old) { - assert other == null || fieldTypes.get(inputOffsets[index]).isAssignableFrom(other.getClass()); // : "Can not assign " + other.getClass() + " to " + inputTypes[index] + " in " + node; + assert other == null || fieldTypes.get(inputOffsets[index]).isAssignableFrom(other.getClass()) : "Can not assign " + other.getClass() + " to " + fieldTypes.get(inputOffsets[index]) + " in " + node; putNode(node, inputOffsets[index], other); return true; } @@ -830,7 +830,7 @@ // create node duplicates for (Node node : nodes) { if (node != null) { - assert !node.isDeleted() : "trying to duplicate deleted node"; + assert !node.isDeleted() : "trying to duplicate deleted node: " + node; Node replacement = replacements.replacement(node); if (replacement != node) { assert replacement != null; diff -r 4535a87e8bf8 -r 5d7d9a6953bd graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java Wed Aug 29 13:05:43 2012 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java Fri Aug 31 17:57:30 2012 +0200 @@ -61,6 +61,7 @@ private final HotSpotRegisterConfig globalStubRegConfig; private final HotSpotGraalRuntime graalRuntime; private CheckCastSnippets.Templates checkcastSnippets; + private InstanceOfSnippets.Templates instanceofSnippets; private NewObjectSnippets.Templates newObjectSnippets; public HotSpotRuntime(HotSpotVMConfig config, HotSpotGraalRuntime graalRuntime) { @@ -77,8 +78,10 @@ installer.install(UnsafeSnippets.class); installer.install(ArrayCopySnippets.class); installer.install(CheckCastSnippets.class); + installer.install(InstanceOfSnippets.class); installer.install(NewObjectSnippets.class); checkcastSnippets = new CheckCastSnippets.Templates(this); + instanceofSnippets = new InstanceOfSnippets.Templates(this); newObjectSnippets = new NewObjectSnippets.Templates(this, graalRuntime.getTarget(), config.useTLAB); } @@ -407,6 +410,10 @@ if (matches(graph, GraalOptions.HIRLowerCheckcast)) { checkcastSnippets.lower((CheckCastNode) n, tool); } + } else if (n instanceof InstanceOfNode) { + if (matches(graph, GraalOptions.HIRLowerInstanceOf)) { + instanceofSnippets.lower((InstanceOfNode) n, tool); + } } else if (n instanceof NewInstanceNode) { if (matches(graph, GraalOptions.HIRLowerNewInstance)) { newObjectSnippets.lower((NewInstanceNode) n, tool); diff -r 4535a87e8bf8 -r 5d7d9a6953bd graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/CheckCastSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/CheckCastSnippets.java Wed Aug 29 13:05:43 2012 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/CheckCastSnippets.java Fri Aug 31 17:57:30 2012 +0200 @@ -22,14 +22,13 @@ */ package com.oracle.graal.hotspot.snippets; import static com.oracle.graal.hotspot.snippets.ArrayCopySnippets.*; -import static com.oracle.graal.snippets.Snippet.Multiple.*; +import static com.oracle.graal.snippets.Snippet.Varargs.*; import static com.oracle.graal.snippets.SnippetTemplate.Arguments.*; import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.*; import com.oracle.graal.debug.*; -import com.oracle.graal.graph.*; import com.oracle.graal.hotspot.*; import com.oracle.graal.hotspot.meta.*; import com.oracle.graal.nodes.*; @@ -40,16 +39,16 @@ import com.oracle.graal.snippets.Snippet.ConstantParameter; import com.oracle.graal.snippets.Snippet.Fold; import com.oracle.graal.snippets.Snippet.Parameter; +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.Cache; import com.oracle.graal.snippets.SnippetTemplate.Key; import com.oracle.graal.snippets.nodes.*; /** * Snippets used for implementing the type test of a checkcast instruction. * - * The test first checks against the profiled types (if any) and then implements the - * checks described in the paper + * The type tests implemented are described in the paper * Fast subtype checking in the HotSpot JVM by Cliff Click and John Rose. */ public class CheckCastSnippets implements SnippetsInterface { @@ -58,7 +57,10 @@ * Type test used when the type being tested against is a final type. */ @Snippet - public static Object checkcastExact(@Parameter("object") Object object, @Parameter("exactHub") Object exactHub, @ConstantParameter("checkNull") boolean checkNull) { + public static Object checkcastExact( + @Parameter("object") Object object, + @Parameter("exactHub") Object exactHub, + @ConstantParameter("checkNull") boolean checkNull) { if (checkNull && object == null) { isNull.inc(); return object; @@ -80,7 +82,11 @@ * first. */ @Snippet - public static Object checkcastPrimary(@Parameter("hub") Object hub, @Parameter("object") Object object, @ConstantParameter("checkNull") boolean checkNull, @ConstantParameter("superCheckOffset") int superCheckOffset) { + public static Object checkcastPrimary( + @Parameter("hub") Object hub, + @Parameter("object") Object object, + @ConstantParameter("checkNull") boolean checkNull, + @ConstantParameter("superCheckOffset") int superCheckOffset) { if (checkNull && object == null) { isNull.inc(); return object; @@ -98,7 +104,11 @@ * Type test used when the type being tested against is a restricted secondary type. */ @Snippet - public static Object checkcastSecondary(@Parameter("hub") Object hub, @Parameter("object") Object object, @Parameter(value = "hints", multiple = true) Object[] hints, @ConstantParameter("checkNull") boolean checkNull) { + public static Object checkcastSecondary( + @Parameter("hub") Object hub, + @Parameter("object") Object object, + @VarargsParameter("hints") Object[] hints, + @ConstantParameter("checkNull") boolean checkNull) { if (checkNull && object == null) { isNull.inc(); return object; @@ -124,7 +134,11 @@ * in an object array store check). */ @Snippet - public static Object checkcastUnknown(@Parameter("hub") Object hub, @Parameter("object") Object object, @Parameter(value = "hints", multiple = true) Object[] hints, @ConstantParameter("checkNull") boolean checkNull) { + public static Object checkcastUnknown( + @Parameter("hub") Object hub, + @Parameter("object") Object object, + @VarargsParameter("hints") Object[] hints, + @ConstantParameter("checkNull") boolean checkNull) { if (checkNull && object == null) { isNull.inc(); return object; @@ -238,26 +252,19 @@ return HotSpotGraalRuntime.getInstance().getConfig().hubOffset; } - public static class Templates { + public static class Templates extends AbstractTemplates { - private final Cache cache; private final ResolvedJavaMethod exact; private final ResolvedJavaMethod primary; private final ResolvedJavaMethod secondary; private final ResolvedJavaMethod unknown; - private final CodeCacheProvider runtime; public Templates(CodeCacheProvider runtime) { - this.runtime = runtime; - this.cache = new Cache(runtime); - try { - exact = runtime.getResolvedJavaMethod(CheckCastSnippets.class.getDeclaredMethod("checkcastExact", Object.class, Object.class, boolean.class)); - primary = runtime.getResolvedJavaMethod(CheckCastSnippets.class.getDeclaredMethod("checkcastPrimary", Object.class, Object.class, boolean.class, int.class)); - secondary = runtime.getResolvedJavaMethod(CheckCastSnippets.class.getDeclaredMethod("checkcastSecondary", Object.class, Object.class, Object[].class, boolean.class)); - unknown = runtime.getResolvedJavaMethod(CheckCastSnippets.class.getDeclaredMethod("checkcastUnknown", Object.class, Object.class, Object[].class, boolean.class)); - } catch (NoSuchMethodException e) { - throw new GraalInternalError(e); - } + super(runtime, CheckCastSnippets.class); + exact = snippet("checkcastExact", Object.class, Object.class, boolean.class); + primary = snippet("checkcastPrimary", Object.class, Object.class, boolean.class, int.class); + secondary = snippet("checkcastSecondary", Object.class, Object.class, Object[].class, boolean.class); + unknown = snippet("checkcastUnknown", Object.class, Object.class, Object[].class, boolean.class); } /** @@ -275,7 +282,7 @@ if (target == null) { HotSpotKlassOop[] hints = createHints(hintInfo); - key = new Key(unknown).add("hints", multiple(Object.class, hints.length)).add("checkNull", checkNull); + key = new Key(unknown).add("hints", vargargs(Object.class, hints.length)).add("checkNull", checkNull); arguments = arguments("hub", hub).add("object", object).add("hints", hints); } else if (hintInfo.exact) { HotSpotKlassOop[] hints = createHints(hintInfo); @@ -287,16 +294,16 @@ arguments = arguments("hub", hub).add("object", object); } else { HotSpotKlassOop[] hints = createHints(hintInfo); - key = new Key(secondary).add("hints", multiple(Object.class, hints.length)).add("checkNull", checkNull); + key = new Key(secondary).add("hints", vargargs(Object.class, hints.length)).add("checkNull", checkNull); arguments = arguments("hub", hub).add("object", object).add("hints", hints); } SnippetTemplate template = cache.get(key); Debug.log("Lowering checkcast in %s: node=%s, template=%s, arguments=%s", graph, checkcast, template, arguments); - template.instantiate(runtime, checkcast, checkcast, arguments); + template.instantiate(runtime, checkcast, arguments); } - private static HotSpotKlassOop[] createHints(TypeCheckHints hints) { + static HotSpotKlassOop[] createHints(TypeCheckHints hints) { HotSpotKlassOop[] hintHubs = new HotSpotKlassOop[hints.types.length]; for (int i = 0; i < hintHubs.length; i++) { hintHubs[i] = ((HotSpotJavaType) hints.types[i]).klassOop(); diff -r 4535a87e8bf8 -r 5d7d9a6953bd graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/InstanceOfSnippets.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/InstanceOfSnippets.java Fri Aug 31 17:57:30 2012 +0200 @@ -0,0 +1,492 @@ +/* + * 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.snippets; +import static com.oracle.graal.hotspot.snippets.CheckCastSnippets.*; +import static com.oracle.graal.hotspot.snippets.CheckCastSnippets.Templates.*; +import static com.oracle.graal.snippets.Snippet.Varargs.*; +import static com.oracle.graal.snippets.SnippetTemplate.Arguments.*; +import static com.oracle.graal.snippets.nodes.JumpNode.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.hotspot.*; +import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.util.*; +import com.oracle.graal.snippets.*; +import com.oracle.graal.snippets.Snippet.ConstantParameter; +import com.oracle.graal.snippets.Snippet.Fold; +import com.oracle.graal.snippets.Snippet.Parameter; +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 the type test of an instanceof instruction. + * Since instanceof is a floating node, it is lowered separately for each of + * its usages. + * + * The type tests implemented are described in the paper + * Fast subtype checking in the HotSpot JVM by Cliff Click and John Rose. + */ +public class InstanceOfSnippets implements SnippetsInterface { + + /** + * A test against a final type with the result being {@linkplain MaterializeNode materialized}. + */ + @Snippet + public static Object materializeExact( + @Parameter("object") Object object, + @Parameter("exactHub") Object exactHub, + @Parameter("trueValue") Object trueValue, + @Parameter("falseValue") Object falseValue, + @ConstantParameter("checkNull") boolean checkNull) { + if (checkNull && object == null) { + isNull.inc(); + return falseValue; + } + Object objectHub = UnsafeLoadNode.loadObject(object, 0, hubOffset(), true); + if (objectHub != exactHub) { + exactMiss.inc(); + return falseValue; + } + exactHit.inc(); + return trueValue; + } + + /** + * A test against a final type with the result being {@linkplain IfNode branched} upon. + */ + @Snippet + public static void ifExact( + @Parameter("object") Object object, + @Parameter("exactHub") Object exactHub, + @ConstantParameter("checkNull") boolean checkNull) { + if (checkNull && object == null) { + isNull.inc(); + jump(IfNode.FALSE_EDGE); + return; + } + Object objectHub = UnsafeLoadNode.loadObject(object, 0, hubOffset(), true); + if (objectHub != exactHub) { + exactMiss.inc(); + jump(IfNode.FALSE_EDGE); + return; + } + exactHit.inc(); + jump(IfNode.TRUE_EDGE); + } + + /** + * A test against a primary type with the result being {@linkplain MaterializeNode materialized}. + */ + @Snippet + public static Object materializePrimary( + @Parameter("hub") Object hub, + @Parameter("object") Object object, + @Parameter("trueValue") Object trueValue, + @Parameter("falseValue") Object falseValue, + @ConstantParameter("checkNull") boolean checkNull, + @ConstantParameter("superCheckOffset") int superCheckOffset) { + if (checkNull && object == null) { + isNull.inc(); + return falseValue; + } + Object objectHub = UnsafeLoadNode.loadObject(object, 0, hubOffset(), true); + if (UnsafeLoadNode.loadObject(objectHub, 0, superCheckOffset, true) != hub) { + displayMiss.inc(); + return falseValue; + } + displayHit.inc(); + return trueValue; + } + + /** + * A test against a primary type with the result being {@linkplain IfNode branched} upon. + */ + @Snippet + public static void ifPrimary( + @Parameter("hub") Object hub, + @Parameter("object") Object object, + @ConstantParameter("checkNull") boolean checkNull, + @ConstantParameter("superCheckOffset") int superCheckOffset) { + if (checkNull && object == null) { + isNull.inc(); + jump(IfNode.FALSE_EDGE); + return; + } + Object objectHub = UnsafeLoadNode.loadObject(object, 0, hubOffset(), true); + if (UnsafeLoadNode.loadObject(objectHub, 0, superCheckOffset, true) != hub) { + displayMiss.inc(); + jump(IfNode.FALSE_EDGE); + return; + } + displayHit.inc(); + jump(IfNode.TRUE_EDGE); + return; + } + + /** + * A test against a restricted secondary type type with the result being {@linkplain MaterializeNode materialized}. + */ + @Snippet + public static Object materializeSecondary( + @Parameter("hub") Object hub, + @Parameter("object") Object object, + @Parameter("trueValue") Object trueValue, + @Parameter("falseValue") Object falseValue, + @VarargsParameter("hints") Object[] hints, + @ConstantParameter("checkNull") boolean checkNull) { + if (checkNull && object == null) { + isNull.inc(); + return falseValue; + } + Object objectHub = UnsafeLoadNode.loadObject(object, 0, hubOffset(), true); + // if we get an exact match: succeed immediately + ExplodeLoopNode.explodeLoop(); + for (int i = 0; i < hints.length; i++) { + Object hintHub = hints[i]; + if (hintHub == objectHub) { + hintsHit.inc(); + return trueValue; + } + } + if (!checkSecondarySubType(hub, objectHub)) { + return falseValue; + } + return trueValue; + } + + /** + * A test against a restricted secondary type with the result being {@linkplain IfNode branched} upon. + */ + @Snippet + public static void ifSecondary( + @Parameter("hub") Object hub, + @Parameter("object") Object object, + @VarargsParameter("hints") Object[] hints, + @ConstantParameter("checkNull") boolean checkNull) { + if (checkNull && object == null) { + isNull.inc(); + jump(IfNode.FALSE_EDGE); + return; + } + Object objectHub = UnsafeLoadNode.loadObject(object, 0, hubOffset(), true); + // if we get an exact match: succeed immediately + ExplodeLoopNode.explodeLoop(); + for (int i = 0; i < hints.length; i++) { + Object hintHub = hints[i]; + if (hintHub == objectHub) { + hintsHit.inc(); + jump(IfNode.TRUE_EDGE); + return; + } + } + if (!checkSecondarySubType(hub, objectHub)) { + jump(IfNode.FALSE_EDGE); + return; + } + jump(IfNode.TRUE_EDGE); + return; + } + + /** + * A test against an unknown (at compile time) type with the result being {@linkplain MaterializeNode materialized}. + */ + @Snippet + public static Object materializeUnknown( + @Parameter("hub") Object hub, + @Parameter("object") Object object, + @Parameter("trueValue") Object trueValue, + @Parameter("falseValue") Object falseValue, + @VarargsParameter("hints") Object[] hints, + @ConstantParameter("checkNull") boolean checkNull) { + if (checkNull && object == null) { + isNull.inc(); + return falseValue; + } + Object objectHub = UnsafeLoadNode.loadObject(object, 0, hubOffset(), true); + // if we get an exact match: succeed immediately + ExplodeLoopNode.explodeLoop(); + for (int i = 0; i < hints.length; i++) { + Object hintHub = hints[i]; + if (hintHub == objectHub) { + hintsHit.inc(); + return trueValue; + } + } + if (!checkUnknownSubType(hub, objectHub)) { + return falseValue; + } + return trueValue; + } + + /** + * A test against an unknown (at compile time) type with the result being {@linkplain IfNode branched} upon. + */ + @Snippet + public static void ifUnknown( + @Parameter("hub") Object hub, + @Parameter("object") Object object, + @VarargsParameter("hints") Object[] hints, + @ConstantParameter("checkNull") boolean checkNull) { + if (checkNull && object == null) { + isNull.inc(); + jump(IfNode.FALSE_EDGE); + return; + } + Object objectHub = UnsafeLoadNode.loadObject(object, 0, hubOffset(), true); + // if we get an exact match: succeed immediately + ExplodeLoopNode.explodeLoop(); + for (int i = 0; i < hints.length; i++) { + Object hintHub = hints[i]; + if (hintHub == objectHub) { + hintsHit.inc(); + jump(IfNode.TRUE_EDGE); + return; + } + } + if (!checkUnknownSubType(hub, objectHub)) { + jump(IfNode.FALSE_EDGE); + return; + } + jump(IfNode.TRUE_EDGE); + return; + } + + static boolean checkSecondarySubType(Object t, Object s) { + // if (S.cache == T) return true + if (UnsafeLoadNode.loadObject(s, 0, secondarySuperCacheOffset(), true) == t) { + cacheHit.inc(); + return true; + } + + // if (T == S) return true + if (s == t) { + T_equals_S.inc(); + return true; + } + + // if (S.scan_s_s_array(T)) { S.cache = T; return true; } + Object[] secondarySupers = UnsafeCastNode.cast(UnsafeLoadNode.loadObject(s, 0, secondarySupersOffset(), true), Object[].class); + + for (int i = 0; i < secondarySupers.length; i++) { + if (t == loadNonNullObjectElement(secondarySupers, i)) { + DirectObjectStoreNode.storeObject(s, secondarySuperCacheOffset(), 0, t); + secondariesHit.inc(); + return true; + } + } + secondariesMiss.inc(); + return false; + } + + static boolean checkUnknownSubType(Object t, Object s) { + // int off = T.offset + int superCheckOffset = UnsafeLoadNode.load(t, 0, superCheckOffsetOffset(), Kind.Int); + boolean primary = superCheckOffset != secondarySuperCacheOffset(); + + // if (T = S[off]) return true + if (UnsafeLoadNode.loadObject(s, 0, superCheckOffset, true) == t) { + if (primary) { + cacheHit.inc(); + } else { + displayHit.inc(); + } + return true; + } + + // if (off != &cache) return false + if (primary) { + displayMiss.inc(); + return false; + } + + // if (T == S) return true + if (s == t) { + T_equals_S.inc(); + return true; + } + + // if (S.scan_s_s_array(T)) { S.cache = T; return true; } + Object[] secondarySupers = UnsafeCastNode.cast(UnsafeLoadNode.loadObject(s, 0, secondarySupersOffset(), true), Object[].class); + for (int i = 0; i < secondarySupers.length; i++) { + if (t == loadNonNullObjectElement(secondarySupers, i)) { + DirectObjectStoreNode.storeObject(s, secondarySuperCacheOffset(), 0, t); + secondariesHit.inc(); + return true; + } + } + + secondariesMiss.inc(); + return false; + } + + @Fold + private static int superCheckOffsetOffset() { + return HotSpotGraalRuntime.getInstance().getConfig().superCheckOffsetOffset; + } + + @Fold + private static int secondarySuperCacheOffset() { + return HotSpotGraalRuntime.getInstance().getConfig().secondarySuperCacheOffset; + } + + @Fold + private static int secondarySupersOffset() { + return HotSpotGraalRuntime.getInstance().getConfig().secondarySupersOffset; + } + + @Fold + private static int hubOffset() { + return HotSpotGraalRuntime.getInstance().getConfig().hubOffset; + } + + + public static class Templates extends AbstractTemplates { + + private final ResolvedJavaMethod ifExact; + private final ResolvedJavaMethod ifPrimary; + private final ResolvedJavaMethod ifSecondary; + private final ResolvedJavaMethod ifUnknown; + private final ResolvedJavaMethod materializeExact; + private final ResolvedJavaMethod materializePrimary; + private final ResolvedJavaMethod materializeSecondary; + private final ResolvedJavaMethod materializeUnknown; + + public Templates(CodeCacheProvider runtime) { + super(runtime, InstanceOfSnippets.class); + ifExact = snippet("ifExact", Object.class, Object.class, boolean.class); + ifPrimary = snippet("ifPrimary", Object.class, Object.class, boolean.class, int.class); + ifSecondary = snippet("ifSecondary", Object.class, Object.class, Object[].class, boolean.class); + ifUnknown = snippet("ifUnknown", Object.class, Object.class, Object[].class, boolean.class); + + materializeExact = snippet("materializeExact", Object.class, Object.class, Object.class, Object.class, boolean.class); + materializePrimary = snippet("materializePrimary", Object.class, Object.class, Object.class, Object.class, boolean.class, int.class); + materializeSecondary = snippet("materializeSecondary", Object.class, Object.class, Object.class, Object.class, Object[].class, boolean.class); + materializeUnknown = snippet("materializeUnknown", Object.class, Object.class, Object.class, Object.class, Object[].class, boolean.class); + } + + public void lower(InstanceOfNode instanceOf, LoweringTool tool) { + ValueNode hub = instanceOf.targetClassInstruction(); + ValueNode object = instanceOf.object(); + TypeCheckHints hintInfo = new TypeCheckHints(instanceOf.targetClass(), instanceOf.profile(), tool.assumptions(), GraalOptions.CheckcastMinHintHitProbability, GraalOptions.CheckcastMaxHints); + final HotSpotResolvedJavaType target = (HotSpotResolvedJavaType) instanceOf.targetClass(); + boolean checkNull = !object.stamp().nonNull(); + + for (Node usage : instanceOf.usages().snapshot()) { + Arguments arguments = null; + Key key = null; + + // instanceof nodes are lowered separately for each usage. To simply graph modifications, + // we duplicate the instanceof node for each usage. + InstanceOfNode duplicate = instanceOf.graph().add(new InstanceOfNode(instanceOf.targetClassInstruction(), instanceOf.targetClass(), instanceOf.object(), instanceOf.profile())); + usage.replaceFirstInput(instanceOf, duplicate); + + if (usage instanceof IfNode) { + + IfNode ifNode = (IfNode) usage; + if (target == null) { + HotSpotKlassOop[] hints = createHints(hintInfo); + key = new Key(ifUnknown).add("hints", vargargs(Object.class, hints.length)).add("checkNull", checkNull); + arguments = arguments("hub", hub).add("object", object).add("hints", hints); + } else if (hintInfo.exact) { + HotSpotKlassOop[] hints = createHints(hintInfo); + assert hints.length == 1; + key = new Key(ifExact).add("checkNull", checkNull); + arguments = arguments("object", object).add("exactHub", hints[0]); + } else if (target.isPrimaryType()) { + key = new Key(ifPrimary).add("checkNull", checkNull).add("superCheckOffset", target.superCheckOffset()); + arguments = arguments("hub", hub).add("object", object); + } else { + HotSpotKlassOop[] hints = createHints(hintInfo); + key = new Key(ifSecondary).add("hints", vargargs(Object.class, hints.length)).add("checkNull", checkNull); + arguments = arguments("hub", hub).add("object", object).add("hints", hints); + } + + SnippetTemplate template = cache.get(key); + template.instantiate(runtime, duplicate, ifNode, arguments); + assert ifNode.isDeleted(); + + } else if (usage instanceof MaterializeNode) { + + MaterializeNode materialize = (MaterializeNode) usage; + materialize.replaceAtUsages(duplicate); + ValueNode falseValue = materialize.falseValue(); + ValueNode trueValue = materialize.trueValue(); + + // The materialize node is no longer connected to anyone -> kill it + materialize.clearInputs(); + assert materialize.usages().isEmpty(); + GraphUtil.killWithUnusedFloatingInputs(materialize); + + if (target == null) { + HotSpotKlassOop[] hints = createHints(hintInfo); + key = new Key(materializeUnknown).add("hints", vargargs(Object.class, hints.length)).add("checkNull", checkNull); + arguments = arguments("hub", hub).add("object", object).add("hints", hints).add("trueValue", trueValue).add("falseValue", falseValue); + } else if (hintInfo.exact) { + HotSpotKlassOop[] hints = createHints(hintInfo); + assert hints.length == 1; + key = new Key(materializeExact).add("checkNull", checkNull); + arguments = arguments("object", object).add("exactHub", hints[0]).add("trueValue", trueValue).add("falseValue", falseValue); + } else if (target.isPrimaryType()) { + key = new Key(materializePrimary).add("checkNull", checkNull).add("superCheckOffset", target.superCheckOffset()); + arguments = arguments("hub", hub).add("object", object).add("trueValue", trueValue).add("falseValue", falseValue); + } else { + HotSpotKlassOop[] hints = createHints(hintInfo); + key = new Key(materializeSecondary).add("hints", vargargs(Object.class, hints.length)).add("checkNull", checkNull); + arguments = arguments("hub", hub).add("object", object).add("hints", hints).add("trueValue", trueValue).add("falseValue", falseValue); + } + + SnippetTemplate template = cache.get(key); + template.instantiate(runtime, duplicate, tool.lastFixedNode(), arguments); + } else { + throw new GraalInternalError("Unexpected usage of %s: %s", instanceOf, usage); + } + } + + assert !instanceOf.isDeleted(); + assert instanceOf.usages().isEmpty(); + GraphUtil.killWithUnusedFloatingInputs(instanceOf); + } + } + + private static final SnippetCounter.Group counters = GraalOptions.SnippetCounters ? new SnippetCounter.Group("Checkcast") : null; + private static final SnippetCounter hintsHit = new SnippetCounter(counters, "hintsHit", "hit a hint type"); + private static final SnippetCounter exactHit = new SnippetCounter(counters, "exactHit", "exact type test succeeded"); + private static final SnippetCounter exactMiss = new SnippetCounter(counters, "exactMiss", "exact type test failed"); + private static final SnippetCounter isNull = new SnippetCounter(counters, "isNull", "object tested was null"); + private static final SnippetCounter cacheHit = new SnippetCounter(counters, "cacheHit", "secondary type cache hit"); + private static final SnippetCounter secondariesHit = new SnippetCounter(counters, "secondariesHit", "secondaries scan succeeded"); + private static final SnippetCounter secondariesMiss = new SnippetCounter(counters, "secondariesMiss", "secondaries scan failed"); + private static final SnippetCounter displayHit = new SnippetCounter(counters, "displayHit", "primary type test succeeded"); + private static final SnippetCounter displayMiss = new SnippetCounter(counters, "displayMiss", "primary type test failed"); + private static final SnippetCounter T_equals_S = new SnippetCounter(counters, "T_equals_S", "object type was equal to secondary type"); +} diff -r 4535a87e8bf8 -r 5d7d9a6953bd graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/NewObjectSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/NewObjectSnippets.java Wed Aug 29 13:05:43 2012 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/NewObjectSnippets.java Fri Aug 31 17:57:30 2012 +0200 @@ -35,7 +35,6 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.*; import com.oracle.graal.debug.*; -import com.oracle.graal.graph.*; import com.oracle.graal.hotspot.*; import com.oracle.graal.hotspot.meta.*; import com.oracle.graal.hotspot.nodes.*; @@ -46,8 +45,8 @@ import com.oracle.graal.snippets.Snippet.ConstantParameter; import com.oracle.graal.snippets.Snippet.Fold; import com.oracle.graal.snippets.Snippet.Parameter; +import com.oracle.graal.snippets.SnippetTemplate.AbstractTemplates; import com.oracle.graal.snippets.SnippetTemplate.Arguments; -import com.oracle.graal.snippets.SnippetTemplate.Cache; import com.oracle.graal.snippets.SnippetTemplate.Key; /** @@ -208,32 +207,25 @@ } } - public static class Templates { + public static class Templates extends AbstractTemplates { - private final Cache cache; private final ResolvedJavaMethod allocate; private final ResolvedJavaMethod initializeObject; private final ResolvedJavaMethod initializeObjectArray; private final ResolvedJavaMethod initializePrimitiveArray; private final ResolvedJavaMethod allocateArrayAndInitialize; private final TargetDescription target; - private final CodeCacheProvider runtime; private final boolean useTLAB; public Templates(CodeCacheProvider runtime, TargetDescription target, boolean useTLAB) { - this.runtime = runtime; + super(runtime, NewObjectSnippets.class); this.target = target; - this.cache = new Cache(runtime); this.useTLAB = useTLAB; - try { - allocate = runtime.getResolvedJavaMethod(NewObjectSnippets.class.getDeclaredMethod("allocate", int.class)); - initializeObject = runtime.getResolvedJavaMethod(NewObjectSnippets.class.getDeclaredMethod("initializeObject", Word.class, Object.class, Word.class, int.class)); - initializeObjectArray = runtime.getResolvedJavaMethod(NewObjectSnippets.class.getDeclaredMethod("initializeObjectArray", Word.class, Object.class, int.class, int.class, Word.class, int.class)); - initializePrimitiveArray = runtime.getResolvedJavaMethod(NewObjectSnippets.class.getDeclaredMethod("initializePrimitiveArray", Word.class, Object.class, int.class, int.class, Word.class, int.class)); - allocateArrayAndInitialize = runtime.getResolvedJavaMethod(NewObjectSnippets.class.getDeclaredMethod("allocateArrayAndInitialize", int.class, int.class, int.class, int.class, ResolvedJavaType.class, Kind.class)); - } catch (NoSuchMethodException e) { - throw new GraalInternalError(e); - } + allocate = snippet("allocate", int.class); + initializeObject = snippet("initializeObject", Word.class, Object.class, Word.class, int.class); + initializeObjectArray = snippet("initializeObjectArray", Word.class, Object.class, int.class, int.class, Word.class, int.class); + initializePrimitiveArray = snippet("initializePrimitiveArray", Word.class, Object.class, int.class, int.class, Word.class, int.class); + allocateArrayAndInitialize = snippet("allocateArrayAndInitialize", int.class, int.class, int.class, int.class, ResolvedJavaType.class, Kind.class); } /** @@ -301,7 +293,7 @@ Arguments arguments = new Arguments().add("length", lengthNode); SnippetTemplate template = cache.get(key); Debug.log("Lowering allocateArrayAndInitialize in %s: node=%s, template=%s, arguments=%s", graph, newArrayNode, template, arguments); - template.instantiate(runtime, newArrayNode, newArrayNode, arguments); + template.instantiate(runtime, newArrayNode, arguments); } } @@ -313,7 +305,7 @@ Arguments arguments = arguments("size", size); SnippetTemplate template = cache.get(key); Debug.log("Lowering fastAllocate in %s: node=%s, template=%s, arguments=%s", graph, tlabAllocateNode, template, arguments); - template.instantiate(runtime, tlabAllocateNode, tlabAllocateNode, arguments); + template.instantiate(runtime, tlabAllocateNode, arguments); } @SuppressWarnings("unused") @@ -330,7 +322,7 @@ Arguments arguments = arguments("memory", memory).add("hub", hub).add("initialMarkWord", type.initialMarkWord()); SnippetTemplate template = cache.get(key); Debug.log("Lowering initializeObject in %s: node=%s, template=%s, arguments=%s", graph, initializeNode, template, arguments); - template.instantiate(runtime, initializeNode, initializeNode, arguments); + template.instantiate(runtime, initializeNode, arguments); } @SuppressWarnings("unused") @@ -347,7 +339,7 @@ Arguments arguments = arguments("memory", memory).add("hub", hub).add("initialMarkWord", type.initialMarkWord()).add("size", initializeNode.size()).add("length", initializeNode.length()); SnippetTemplate template = cache.get(key); Debug.log("Lowering initializeObjectArray in %s: node=%s, template=%s, arguments=%s", graph, initializeNode, template, arguments); - template.instantiate(runtime, initializeNode, initializeNode, arguments); + template.instantiate(runtime, initializeNode, arguments); } } diff -r 4535a87e8bf8 -r 5d7d9a6953bd graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java Wed Aug 29 13:05:43 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java Fri Aug 31 17:57:30 2012 +0200 @@ -298,13 +298,17 @@ node.safeDelete(); } - public void addAfterFixed(FixedWithNextNode node, FixedWithNextNode newNode) { + public void addAfterFixed(FixedWithNextNode node, FixedNode newNode) { assert node != null && newNode != null && node.isAlive() && newNode.isAlive() : "cannot add " + newNode + " after " + node; - assert newNode.next() == null; newNode.setProbability(node.probability()); FixedNode next = node.next(); node.setNext(newNode); - newNode.setNext(next); + if (next != null) { + assert newNode instanceof FixedWithNextNode; + FixedWithNextNode newFixedWithNext = (FixedWithNextNode) newNode; + assert newFixedWithNext.next() == null; + newFixedWithNext.setNext(next); + } } public void addBeforeFixed(FixedNode node, FixedWithNextNode newNode) { diff -r 4535a87e8bf8 -r 5d7d9a6953bd graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java Wed Aug 29 13:05:43 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java Fri Aug 31 17:57:30 2012 +0200 @@ -31,7 +31,7 @@ /** * The {@code InstanceOfNode} represents an instanceof test. */ -public final class InstanceOfNode extends BooleanNode implements Canonicalizable, LIRLowerable { +public final class InstanceOfNode extends BooleanNode implements Canonicalizable, Lowerable, LIRLowerable { @Input private ValueNode object; @Input private ValueNode targetClassInstruction; @@ -63,6 +63,11 @@ } @Override + public void lower(LoweringTool tool) { + tool.getRuntime().lower(this, tool); + } + + @Override public ValueNode canonical(CanonicalizerTool tool) { assert object() != null : this; diff -r 4535a87e8bf8 -r 5d7d9a6953bd graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LoweringTool.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LoweringTool.java Wed Aug 29 13:05:43 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LoweringTool.java Fri Aug 31 17:57:30 2012 +0200 @@ -28,10 +28,14 @@ public interface LoweringTool { GraalCodeCacheProvider getRuntime(); - ValueNode getGuardAnchor(); ValueNode createNullCheckGuard(ValueNode object, long leafGraphId); ValueNode createGuard(BooleanNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action, long leafGraphId); ValueNode createGuard(BooleanNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action, boolean negated, long leafGraphId); Assumptions assumptions(); + + /** + * Gets the closest fixed node preceding the node currently being lowered. + */ + FixedWithNextNode lastFixedNode(); } diff -r 4535a87e8bf8 -r 5d7d9a6953bd graal/com.oracle.graal.printer/src/com/oracle/graal/printer/GraphPrinterDumpHandler.java --- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/GraphPrinterDumpHandler.java Wed Aug 29 13:05:43 2012 +0200 +++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/GraphPrinterDumpHandler.java Fri Aug 31 17:57:30 2012 +0200 @@ -83,7 +83,7 @@ } TTY.println("Dumping IGV graphs to %s", fileName); } catch (IOException e) { - TTY.println("Faild to open %s to dump IGV graphs : %s", fileName, e); + TTY.println("Failed to open %s to dump IGV graphs : %s", fileName, e); failuresCount++; printer = null; } diff -r 4535a87e8bf8 -r 5d7d9a6953bd graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/InstanceOfTest.java --- a/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/InstanceOfTest.java Wed Aug 29 13:05:43 2012 +0200 +++ b/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/InstanceOfTest.java Fri Aug 31 17:57:30 2012 +0200 @@ -27,6 +27,7 @@ import org.junit.*; import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.phases.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.java.*; @@ -37,6 +38,11 @@ public class InstanceOfTest extends TypeCheckTest { @Override + protected void editPhasePlan(ResolvedJavaMethod method, StructuredGraph graph, PhasePlan phasePlan) { + phasePlan.disablePhase(InliningPhase.class); + } + + @Override protected void replaceProfile(StructuredGraph graph, JavaTypeProfile profile) { InstanceOfNode ion = graph.getNodes().filter(InstanceOfNode.class).first(); if (ion != null) { @@ -64,6 +70,15 @@ } @Test + public void test2_1() { + test("isStringIntComplex", profile(), "object"); + test("isStringIntComplex", profile(String.class), "object"); + + test("isStringIntComplex", profile(), Object.class); + test("isStringIntComplex", profile(String.class), Object.class); + } + + @Test public void test3() { Throwable throwable = new Exception(); test("isThrowable", profile(), throwable); @@ -76,6 +91,15 @@ } @Test + public void test3_1() { + onlyFirstIsException(new Exception(), new Error()); + test("onlyFirstIsException", profile(), new Exception(), new Error()); + test("onlyFirstIsException", profile(), new Error(), new Exception()); + test("onlyFirstIsException", profile(), new Exception(), new Exception()); + test("onlyFirstIsException", profile(), new Error(), new Error()); + } + + @Test public void test4() { Throwable throwable = new Exception(); test("isThrowableInt", profile(), throwable); @@ -117,19 +141,41 @@ public static int isStringInt(Object o) { if (o instanceof String) { - return 1; + return id(0); } - return 0; + return id(0); + } + + public static int isStringIntComplex(Object o) { + if (o instanceof String || o instanceof Integer) { + return id(o instanceof String ? 1 : 0); + } + return id(0); + } + + public static int id(int value) { + return value; } public static boolean isThrowable(Object o) { - return o instanceof Throwable; + return ((Throwable) o) instanceof Exception; } + public static int onlyFirstIsException(Throwable t1, Throwable t2) { + if (t1 instanceof Exception ^ t2 instanceof Exception) { + return t1 instanceof Exception ? 1 : -1; + } + return -1; + } + + public static int isThrowableInt(Object o) { if (o instanceof Throwable) { return 1; } + if (o instanceof Throwable) { + return 2; + } return 0; } diff -r 4535a87e8bf8 -r 5d7d9a6953bd graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/Snippet.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/Snippet.java Wed Aug 29 13:05:43 2012 +0200 +++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/Snippet.java Fri Aug 31 17:57:30 2012 +0200 @@ -119,17 +119,25 @@ * The name of this parameter. */ String value(); + } + /** + * Denotes a snippet parameter representing 0 or more arguments that will be bound during snippet + * template {@linkplain SnippetTemplate#instantiate instantiation}. During snippet template creation, + * its value must be an array whose length specifies the number of arguments (the contents + * of the array are ignored) bound to the parameter during {@linkplain SnippetTemplate#instantiate instantiation}. + * + * Such a parameter must be used in a counted loop in the snippet preceded by a call + * to {@link ExplodeLoopNode#explodeLoop()}. The counted looped must be a + * standard iteration over all the loop's elements (i.e. {@code for (T e : arr) ... }). + */ + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.PARAMETER) + public @interface VarargsParameter { /** - * Determines if this parameter represents 0 or more arguments. During snippet template creation, - * its value must be an array whose length specifies the number of arguments (the contents - * of the array are ignored) bound to the parameter during {@linkplain SnippetTemplate#instantiate instantiation}. - * - * Such a parameter must be used in a counted loop in the snippet preceded by a call - * to {@link ExplodeLoopNode#explodeLoop()}. The counted looped must be a - * standard iteration over all the loop's elements (i.e. {@code for (T e : arr) ... }). + * The name of this parameter. */ - boolean multiple() default false; + String value(); } /** @@ -146,18 +154,18 @@ } /** - * Wrapper for the prototype value of a {@linkplain Parameter#multiple() multiple} parameter. + * Wrapper for the prototype value of a {@linkplain VarargsParameter varargs} parameter. */ - public static class Multiple { + public static class Varargs { public final Object array; private final Class componentType; private final int length; - public static Multiple multiple(Class componentType, int length) { - return new Multiple(Array.newInstance(componentType, length)); + public static Varargs vargargs(Class componentType, int length) { + return new Varargs(Array.newInstance(componentType, length)); } - public Multiple(Object array) { + public Varargs(Object array) { assert array != null; this.componentType = array.getClass().getComponentType(); assert this.componentType != null; @@ -167,8 +175,8 @@ @Override public boolean equals(Object obj) { - if (obj instanceof Multiple) { - Multiple other = (Multiple) obj; + if (obj instanceof Varargs) { + Varargs other = (Varargs) obj; return other.componentType == componentType && other.length == length; } diff -r 4535a87e8bf8 -r 5d7d9a6953bd graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetTemplate.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetTemplate.java Wed Aug 29 13:05:43 2012 +0200 +++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetTemplate.java Fri Aug 31 17:57:30 2012 +0200 @@ -35,13 +35,15 @@ import com.oracle.graal.graph.*; import com.oracle.graal.graph.Node.Verbosity; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.type.*; import com.oracle.graal.nodes.util.*; import com.oracle.graal.snippets.Snippet.ConstantParameter; -import com.oracle.graal.snippets.Snippet.Multiple; 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.nodes.*; /** @@ -109,6 +111,10 @@ public String toString() { return MetaUtil.format("%h.%n", method) + map.toString(); } + + public Set names() { + return map.keySet(); + } } /** @@ -172,8 +178,28 @@ } return template; } + } - } + public abstract static class AbstractTemplates { + protected final Cache cache; + protected final CodeCacheProvider runtime; + protected Class snippetsClass; + public AbstractTemplates(CodeCacheProvider runtime, Class snippetsClass) { + this.runtime = runtime; + this.snippetsClass = snippetsClass; + this.cache = new Cache(runtime); + } + + protected ResolvedJavaMethod snippet(String name, Class... parameterTypes) { + try { + ResolvedJavaMethod snippet = runtime.getResolvedJavaMethod(snippetsClass.getDeclaredMethod(name, parameterTypes)); + assert snippet.getAnnotation(Snippet.class) != null : "snippet is not annotated with @" + Snippet.class.getSimpleName(); + return snippet; + } catch (NoSuchMethodException e) { + throw new GraalInternalError(e); + } + } +} /** * Determines if any parameter of a given method is annotated with {@link ConstantParameter}. @@ -202,7 +228,10 @@ replacements.put(snippetGraph.start(), snippetCopy.start()); int parameterCount = signature.argumentCount(false); + assert checkTemplate(key, parameterCount, method, signature); + Parameter[] parameterAnnotations = new Parameter[parameterCount]; + VarargsParameter[] varargsParameterAnnotations = new VarargsParameter[parameterCount]; ConstantNode[] placeholders = new ConstantNode[parameterCount]; for (int i = 0; i < parameterCount; i++) { ConstantParameter c = MetaUtil.getParameterAnnotation(ConstantParameter.class, i, method); @@ -210,23 +239,19 @@ String name = c.value(); Object arg = key.get(name); Kind kind = signature.argumentKindAt(i); - assert checkConstantArgument(method, signature, i, name, arg, kind); replacements.put(snippetGraph.getLocal(i), ConstantNode.forConstant(Constant.forBoxed(kind, arg), runtime, snippetCopy)); } else { - Parameter p = MetaUtil.getParameterAnnotation(Parameter.class, i, method); - assert p != null : method + ": parameter " + i + " must be annotated with either @" + ConstantParameter.class.getSimpleName() + - " or @" + Parameter.class.getSimpleName(); - String name = p.value(); - if (p.multiple()) { - Object multiple = key.get(name); - assert multiple != null : method + ": requires a Multiple named " + name; - assert checkMultipleArgument(method, signature, i, name, multiple); - Object array = ((Multiple) multiple).array; + VarargsParameter vp = MetaUtil.getParameterAnnotation(VarargsParameter.class, i, method); + if (vp != null) { + String name = vp.value(); + Object array = ((Varargs) key.get(name)).array; ConstantNode placeholder = ConstantNode.forObject(array, runtime, snippetCopy); replacements.put(snippetGraph.getLocal(i), placeholder); placeholders[i] = placeholder; + varargsParameterAnnotations[i] = vp; + } else { + parameterAnnotations[i] = MetaUtil.getParameterAnnotation(Parameter.class, i, method); } - parameterAnnotations[i] = p; } } snippetCopy.addDuplicates(snippetGraph.getNodes(), replacements); @@ -242,34 +267,35 @@ // Gather the template parameters parameters = new HashMap<>(); for (int i = 0; i < parameterCount; i++) { - Parameter p = parameterAnnotations[i]; - if (p != null) { - if (p.multiple()) { - assert snippetCopy.getLocal(i) == null; - Object array = ((Multiple) key.get(p.value())).array; - int length = Array.getLength(array); - LocalNode[] locals = new LocalNode[length]; - Stamp stamp = StampFactory.forKind(runtime.getResolvedJavaType(array.getClass().getComponentType()).kind()); - for (int j = 0; j < length; j++) { - assert (parameterCount & 0xFFFF) == parameterCount; - int idx = i << 16 | j; - LocalNode local = snippetCopy.unique(new LocalNode(idx, stamp)); - locals[j] = local; + VarargsParameter vp = varargsParameterAnnotations[i]; + if (vp != null) { + assert snippetCopy.getLocal(i) == null; + Object array = ((Varargs) key.get(vp.value())).array; + int length = Array.getLength(array); + LocalNode[] locals = new LocalNode[length]; + Stamp stamp = StampFactory.forKind(runtime.getResolvedJavaType(array.getClass().getComponentType()).kind()); + for (int j = 0; j < length; j++) { + assert (parameterCount & 0xFFFF) == parameterCount; + int idx = i << 16 | j; + LocalNode local = snippetCopy.unique(new LocalNode(idx, stamp)); + locals[j] = local; + } + parameters.put(vp.value(), locals); + + ConstantNode placeholder = placeholders[i]; + assert placeholder != null; + for (Node usage : placeholder.usages().snapshot()) { + if (usage instanceof LoadIndexedNode) { + LoadIndexedNode loadIndexed = (LoadIndexedNode) usage; + Debug.dump(snippetCopy, "Before replacing %s", loadIndexed); + LoadSnippetVarargParameterNode loadSnippetParameter = snippetCopy.add(new LoadSnippetVarargParameterNode(locals, loadIndexed.index(), loadIndexed.stamp())); + snippetCopy.replaceFixedWithFixed(loadIndexed, loadSnippetParameter); + Debug.dump(snippetCopy, "After replacing %s", loadIndexed); } - parameters.put(p.value(), locals); - - ConstantNode placeholder = placeholders[i]; - assert placeholder != null; - for (Node usage : placeholder.usages().snapshot()) { - if (usage instanceof LoadIndexedNode) { - LoadIndexedNode loadIndexed = (LoadIndexedNode) usage; - Debug.dump(snippetCopy, "Before replacing %s", loadIndexed); - LoadSnippetParameterNode loadSnippetParameter = snippetCopy.add(new LoadSnippetParameterNode(locals, loadIndexed.index(), loadIndexed.stamp())); - snippetCopy.replaceFixedWithFixed(loadIndexed, loadSnippetParameter); - Debug.dump(snippetCopy, "After replacing %s", loadIndexed); - } - } - } else { + } + } else { + Parameter p = parameterAnnotations[i]; + if (p != null) { LocalNode local = snippetCopy.getLocal(i); assert local != null; parameters.put(p.value(), local); @@ -314,26 +340,56 @@ new DeadCodeEliminationPhase().apply(snippetCopy); - assert checkAllMultipleParameterPlaceholdersAreDeleted(parameterCount, placeholders); + assert checkAllVarargPlaceholdersAreDeleted(parameterCount, placeholders); + + this.snippet = snippetCopy; + ReturnNode retNode = null; + StartNode entryPointNode = snippet.start(); + + Map jumpsMap = new HashMap<>(); + for (JumpNode jump : snippet.getNodes().filter(JumpNode.class).snapshot()) { + FixedNode next = jump.next(); - this.graph = snippetCopy; - nodes = new ArrayList<>(graph.getNodeCount()); - ReturnNode retNode = null; - StartNode entryPointNode = graph.start(); - for (Node node : graph.getNodes()) { + // Remove the nodes after the jump + jump.setNext(null); + GraphUtil.killCFG(next); + JumpNode[] jumpsForIndex = jumpsMap.get(jump.successorIndex()); + if (jumpsForIndex == null) { + jumpsMap.put(jump.successorIndex(), new JumpNode[] {jump}); + } else { + jumpsForIndex = Arrays.copyOf(jumpsForIndex, jumpsForIndex.length + 1); + jumpsForIndex[jumpsForIndex.length - 1] = jump; + jumpsMap.put(jump.successorIndex(), jumpsForIndex); + } + } + + this.jumps = new JumpNode[jumpsMap.size()][]; + for (Map.Entry e : jumpsMap.entrySet()) { + int successorIndex = e.getKey(); + assert successorIndex >= 0 && successorIndex < this.jumps.length; + assert this.jumps[successorIndex] == null; + this.jumps[successorIndex] = e.getValue(); + } + + new DeadCodeEliminationPhase().apply(snippetCopy); + + nodes = new ArrayList<>(snippet.getNodeCount()); + for (Node node : snippet.getNodes()) { if (node == entryPointNode || node == entryPointNode.stateAfter()) { // Do nothing. } else { nodes.add(node); if (node instanceof ReturnNode) { + assert this.jumps.length == 0 : "snippet with Jump node(s) cannot have a return node"; retNode = (ReturnNode) node; } } } + this.returnNode = retNode; } - private static boolean checkAllMultipleParameterPlaceholdersAreDeleted(int parameterCount, ConstantNode[] placeholders) { + private static boolean checkAllVarargPlaceholdersAreDeleted(int parameterCount, ConstantNode[] placeholders) { for (int i = 0; i < parameterCount; i++) { if (placeholders[i] != null) { assert placeholders[i].isDeleted() : placeholders[i]; @@ -354,12 +410,11 @@ return true; } - private static boolean checkMultipleArgument(final ResolvedJavaMethod method, Signature signature, int i, String name, Object multiple) { - assert multiple instanceof Multiple; - Object arg = ((Multiple) multiple).array; + private static boolean checkVarargs(final ResolvedJavaMethod method, Signature signature, int i, String name, Varargs varargs) { + Object arg = varargs.array; ResolvedJavaType type = (ResolvedJavaType) signature.argumentTypeAt(i, method.holder()); Class< ? > javaType = type.toJava(); - assert javaType.isArray() : "multiple parameter must be an array type"; + assert javaType.isArray() : "varargs parameter must be an array type"; assert javaType.isInstance(arg) : "value for " + name + " is not a " + javaType.getName() + " instance: " + arg; return true; } @@ -367,7 +422,7 @@ /** * The graph built from the snippet method. */ - private final StructuredGraph graph; + private final StructuredGraph snippet; /** * The named parameters of this template that must be bound to values during instantiation. @@ -386,6 +441,12 @@ private final ArrayList nodes; /** + * The {@link JumpNode}s in the snippet, indexed by {@linkplain ControlSplitNode#blockSuccessor(int) successor} indexes. + * There may be more than one jump per successor index which explains why this is a 2-dimensional array. + */ + private final JumpNode[][] jumps; + + /** * Gets the instantiation-time bindings to this template's parameters. * * @return the map that will be used to bind arguments to parameters when inlining this template @@ -427,32 +488,30 @@ } /** - * Replaces a given node with this specialized snippet. + * Replaces a given fixed node with this specialized snippet. * * @param runtime * @param replacee the node that will be replaced - * @param anchor the control flow replacee * @param args the arguments to be bound to the flattened positional parameters of the snippet */ public void instantiate(CodeCacheProvider runtime, - Node replacee, - FixedWithNextNode anchor, SnippetTemplate.Arguments args) { + FixedWithNextNode replacee, SnippetTemplate.Arguments args) { // Inline the snippet nodes, replacing parameters with the given args in the process - String name = graph.name == null ? "{copy}" : graph.name + "{copy}"; - StructuredGraph graphCopy = new StructuredGraph(name, graph.method()); - StartNode entryPointNode = graph.start(); + String name = snippet.name == null ? "{copy}" : snippet.name + "{copy}"; + StructuredGraph snippetCopy = new StructuredGraph(name, snippet.method()); + StartNode entryPointNode = snippet.start(); FixedNode firstCFGNode = entryPointNode.next(); StructuredGraph replaceeGraph = (StructuredGraph) replacee.graph(); IdentityHashMap replacements = bind(replaceeGraph, runtime, args); Map duplicates = replaceeGraph.addDuplicates(nodes, replacements); - Debug.dump(replaceeGraph, "After inlining snippet %s", graphCopy.method()); + Debug.dump(replaceeGraph, "After inlining snippet %s", snippetCopy.method()); // Re-wire the control flow graph around the replacee FixedNode firstCFGNodeDuplicate = (FixedNode) duplicates.get(firstCFGNode); - anchor.replaceAtPredecessor(firstCFGNodeDuplicate); - FixedNode next = anchor.next(); - anchor.setNext(null); + replacee.replaceAtPredecessor(firstCFGNodeDuplicate); + FixedNode next = replacee.next(); + replacee.setNext(null); // Replace all usages of the replacee with the value returned by the snippet Node returnValue = null; @@ -473,21 +532,120 @@ // Remove the replacee from its graph replacee.clearInputs(); replacee.replaceAtUsages(null); - if (replacee instanceof FixedNode) { - GraphUtil.killCFG((FixedNode) replacee); + GraphUtil.killCFG(replacee); + + Debug.dump(replaceeGraph, "After lowering %s with %s", replacee, this); + } + + /** + * Replaces a given floating node with this specialized snippet. + * + * @param runtime + * @param replacee the node that will be replaced + * @param lastFixedNode the CFG of the snippet is inserted after this node + * @param args the arguments to be bound to the flattened positional parameters of the snippet + */ + public void instantiate(CodeCacheProvider runtime, + FloatingNode replacee, + FixedWithNextNode lastFixedNode, SnippetTemplate.Arguments args) { + + // Inline the snippet nodes, replacing parameters with the given args in the process + String name = snippet.name == null ? "{copy}" : snippet.name + "{copy}"; + StructuredGraph snippetCopy = new StructuredGraph(name, snippet.method()); + StartNode entryPointNode = snippet.start(); + FixedNode firstCFGNode = entryPointNode.next(); + StructuredGraph replaceeGraph = (StructuredGraph) replacee.graph(); + IdentityHashMap replacements = bind(replaceeGraph, runtime, args); + Map duplicates = replaceeGraph.addDuplicates(nodes, replacements); + Debug.dump(replaceeGraph, "After inlining snippet %s", snippetCopy.method()); + + assert lastFixedNode != null : replaceeGraph; + FixedNode next = lastFixedNode.next(); + lastFixedNode.setNext(null); + FixedNode firstCFGNodeDuplicate = (FixedNode) duplicates.get(firstCFGNode); + replaceeGraph.addAfterFixed(lastFixedNode, firstCFGNodeDuplicate); + + // Replace all usages of the replacee with the value returned by the snippet + assert returnNode != null : replaceeGraph; + Node returnValue = null; + if (returnNode.result() instanceof LocalNode) { + returnValue = replacements.get(returnNode.result()); } else { - GraphUtil.killWithUnusedFloatingInputs(replacee); + returnValue = duplicates.get(returnNode.result()); } - if (anchor != replacee) { - GraphUtil.killCFG(anchor); - } + assert returnValue != null || replacee.usages().isEmpty(); + replacee.replaceAtUsages(returnValue); + + Node returnDuplicate = duplicates.get(returnNode); + returnDuplicate.clearInputs(); + returnDuplicate.replaceAndDelete(next); Debug.dump(replaceeGraph, "After lowering %s with %s", replacee, this); } + /** + * Replaces a given floating node that is an input to a {@link ControlSplitNode} with this specialized snippet. + * The {@linkplain JumpNode jumps} in the snippet are connected to the successors of the control split node. + * + * @param replacee the node that will be replaced + * @param controlSplitNode the node replaced by this wheCFG of the snippet is inserted after this node + * @param args the arguments to be bound to the flattened positional parameters of the snippet + */ + public void instantiate(CodeCacheProvider runtime, + FloatingNode replacee, + ControlSplitNode controlSplitNode, + SnippetTemplate.Arguments args) { + + // Inline the snippet nodes, replacing parameters with the given args in the process + String name = snippet.name == null ? "{copy}" : snippet.name + "{copy}"; + StructuredGraph snippetCopy = new StructuredGraph(name, snippet.method()); + StartNode entryPointNode = snippet.start(); + FixedNode firstCFGNode = entryPointNode.next(); + StructuredGraph replaceeGraph = (StructuredGraph) replacee.graph(); + IdentityHashMap replacements = bind(replaceeGraph, runtime, args); + Map duplicates = replaceeGraph.addDuplicates(nodes, replacements); + Debug.dump(replaceeGraph, "After inlining snippet %s", snippetCopy.method()); + + + int successorIndex = 0; + for (JumpNode[] jumpsForIndex : jumps) { + fixEdge(controlSplitNode, jumpsForIndex, successorIndex++, duplicates); + } + + FixedNode firstCFGNodeDuplicate = (FixedNode) duplicates.get(firstCFGNode); + controlSplitNode.replaceAtPredecessor(firstCFGNodeDuplicate); + controlSplitNode.replaceAtUsages(null); + + assert returnNode == null : replaceeGraph; + GraphUtil.killCFG(controlSplitNode); + + Debug.dump(replaceeGraph, "After lowering %s with %s", replacee, this); + } + + private static void fixEdge(ControlSplitNode splitAnchor, JumpNode[] jumpsForIndex, int successorIndex, Map duplicates) { + BeginNode blockSuccessor = splitAnchor.blockSuccessor(successorIndex); + splitAnchor.setBlockSuccessor(successorIndex, null); + if (jumpsForIndex.length == 1) { + JumpNode jump = (JumpNode) duplicates.get(jumpsForIndex[0]); + jump.replaceAtPredecessor(blockSuccessor); + GraphUtil.killCFG(jump); + } else { + StructuredGraph graph = (StructuredGraph) splitAnchor.graph(); + MergeNode merge = graph.add(new MergeNode()); + for (int i = 0; i < jumpsForIndex.length; i++) { + EndNode end = graph.add(new EndNode()); + JumpNode jump = (JumpNode) duplicates.get(jumpsForIndex[i]); + jump.replaceAtPredecessor(end); + merge.addForwardEnd(end); + GraphUtil.killCFG(jump); + } + merge.setNext(blockSuccessor); + } + } + @Override public String toString() { - StringBuilder buf = new StringBuilder(graph.toString()).append('('); + StringBuilder buf = new StringBuilder(snippet.toString()).append('('); String sep = ""; for (Map.Entry e : parameters.entrySet()) { String name = e.getKey(); @@ -505,5 +663,45 @@ } return buf.append(')').toString(); } + + private static boolean checkTemplate(SnippetTemplate.Key key, int parameterCount, ResolvedJavaMethod method, Signature signature) { + Set expected = new HashSet<>(); + for (int i = 0; i < parameterCount; i++) { + ConstantParameter c = MetaUtil.getParameterAnnotation(ConstantParameter.class, i, method); + VarargsParameter vp = MetaUtil.getParameterAnnotation(VarargsParameter.class, i, method); + Parameter p = MetaUtil.getParameterAnnotation(Parameter.class, i, method); + if (c != null) { + assert vp == null && p == null; + String name = c.value(); + expected.add(name); + Kind kind = signature.argumentKindAt(i); + assert key.names().contains(name) : "key for " + method + " is missing \"" + name + "\": " + key; + assert checkConstantArgument(method, signature, i, c.value(), key.get(name), kind); + } else if (vp != null) { + assert p == null; + String name = vp.value(); + expected.add(name); + assert key.names().contains(name) : "key for " + method + " is missing \"" + name + "\": " + key; + assert key.get(name) instanceof Varargs; + Varargs varargs = (Varargs) key.get(name); + assert checkVarargs(method, signature, i, name, varargs); + } else { + assert p != null : method + ": parameter " + i + " must be annotated with exactly one of " + + "@" + ConstantParameter.class.getSimpleName() + " or " + + "@" + VarargsParameter.class.getSimpleName() + " or " + + "@" + Parameter.class.getSimpleName(); + } + } + if (!key.names().containsAll(expected)) { + expected.removeAll(key.names()); + assert false : expected + " missing from key " + key; + } + if (!expected.containsAll(key.names())) { + Set namesCopy = new HashSet<>(key.names()); + namesCopy.removeAll(expected); + assert false : "parameter(s) " + namesCopy + " should be annotated with @" + ConstantParameter.class.getSimpleName() + + " or @" + VarargsParameter.class.getSimpleName() + " in " + MetaUtil.format("%H.%n(%p)", method); + } + return true; + } } - diff -r 4535a87e8bf8 -r 5d7d9a6953bd graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/nodes/ExplodeLoopNode.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/nodes/ExplodeLoopNode.java Wed Aug 29 13:05:43 2012 +0200 +++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/nodes/ExplodeLoopNode.java Fri Aug 31 17:57:30 2012 +0200 @@ -27,13 +27,13 @@ import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.type.*; -import com.oracle.graal.snippets.Snippet.Parameter; +import com.oracle.graal.snippets.Snippet.VarargsParameter; /** * Placeholder node to denote to snippet preparation that the following loop * must be completely unrolled. * - * @see Parameter#multiple() + * @see VarargsParameter */ public final class ExplodeLoopNode extends FixedWithNextNode { diff -r 4535a87e8bf8 -r 5d7d9a6953bd graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/nodes/JumpNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/nodes/JumpNode.java Fri Aug 31 17:57:30 2012 +0200 @@ -0,0 +1,67 @@ +/* + * 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.nodes; + +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.type.*; + +/** + * Delimits a control flow path in a snippet that will be connected to a + * {@link ControlSplitNode} successor upon snippet instantiation. + * This node can only appear in snippets with a void return type. + */ +public class JumpNode extends FixedWithNextNode { + + /** + * Index of {@link ControlSplitNode} successor to which this label will be connected. + */ + private final int successorIndex; + + public JumpNode(int successorIndex) { + super(StampFactory.forVoid()); + this.successorIndex = successorIndex; + } + + public int successorIndex() { + return successorIndex; + } + + @Override + public String toString(Verbosity verbosity) { + if (verbosity == Verbosity.Name) { + return super.toString(Verbosity.Name) + "{" + successorIndex() + "}"; + } else { + return super.toString(verbosity); + } + } + + /** + * There must be a return statement immediately following a call to this method. + * + * @param successorIndex e.g. {@link IfNode#TRUE_EDGE} + */ + @NodeIntrinsic + public static void jump(@ConstantNodeParameter int successorIndex) { + throw new UnsupportedOperationException(); + } +} diff -r 4535a87e8bf8 -r 5d7d9a6953bd graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/nodes/LoadSnippetParameterNode.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/nodes/LoadSnippetParameterNode.java Wed Aug 29 13:05:43 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2009, 2011, 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.nodes; - -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.nodes.type.*; -import com.oracle.graal.snippets.Snippet.Parameter; - -/** - * Implements the semantics of a snippet {@link Parameter} whose {@link Parameter#multiple()} element is {@code true}. - */ -public final class LoadSnippetParameterNode extends FixedWithNextNode implements Canonicalizable { - - @Input private ValueNode index; - - private final LocalNode[] locals; - - public LoadSnippetParameterNode(LocalNode[] locals, ValueNode index, Stamp stamp) { - super(stamp); - this.index = index; - this.locals = locals; - } - - @Override - public ValueNode canonical(CanonicalizerTool tool) { - if (index.isConstant()) { - return locals[index.asConstant().asInt()]; - } - return this; - } -} diff -r 4535a87e8bf8 -r 5d7d9a6953bd graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/nodes/LoadSnippetVarargParameterNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/nodes/LoadSnippetVarargParameterNode.java Fri Aug 31 17:57:30 2012 +0200 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2009, 2011, 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.nodes; + +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; +import com.oracle.graal.snippets.Snippet.VarargsParameter; + +/** + * Implements the semantics of {@link VarargsParameter}. + */ +public final class LoadSnippetVarargParameterNode extends FixedWithNextNode implements Canonicalizable { + + @Input private ValueNode index; + + private final LocalNode[] locals; + + public LoadSnippetVarargParameterNode(LocalNode[] locals, ValueNode index, Stamp stamp) { + super(stamp); + this.index = index; + this.locals = locals; + } + + @Override + public ValueNode canonical(CanonicalizerTool tool) { + if (index.isConstant()) { + return locals[index.asConstant().asInt()]; + } + return this; + } +}