changeset 13615:f4c776ad613e

Merge
author Lukas Stadler <lukas.stadler@jku.at>
date Mon, 13 Jan 2014 13:45:25 +0100
parents 0774f3303c2e (current diff) 428403544e77 (diff)
children 6888c58b810b
files graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ArrayCopyNode.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ObjectAccessTest.java graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/PointerTest.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCache.java
diffstat 22 files changed, 136 insertions(+), 68 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/Interval.java	Mon Jan 13 13:20:30 2014 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/Interval.java	Mon Jan 13 13:45:25 2014 +0100
@@ -183,7 +183,7 @@
      * increasing order of priority are are used to optimize spilling when multiple overlapping
      * intervals compete for limited registers.
      */
-    enum RegisterPriority {
+    public enum RegisterPriority {
         /**
          * No special reason for an interval to be allocated a register.
          */
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java	Mon Jan 13 13:20:30 2014 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java	Mon Jan 13 13:45:25 2014 +0100
@@ -1036,7 +1036,7 @@
             // detection of method-parameters and roundfp-results
             interval.setSpillState(SpillState.StartInMemory);
         }
-        interval.addMaterializationValue(gen.getMaterializedValue(op, operand));
+        interval.addMaterializationValue(gen.getMaterializedValue(op, operand, interval));
 
         Debug.log("add def: %s defPos %d (%s)", interval, defPos, registerPriority.name());
     }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java	Mon Jan 13 13:20:30 2014 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java	Mon Jan 13 13:45:25 2014 +0100
@@ -36,6 +36,7 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.*;
+import com.oracle.graal.compiler.alloc.*;
 import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
@@ -192,14 +193,29 @@
      * 
      * @param op An instruction which defines a value
      * @param operand The destination operand of the instruction
+     * @param interval The interval for this defined value.
      * @return Returns the value which is moved to the instruction and which can be reused at all
      *         reload-locations in case the interval of this instruction is spilled. Currently this
      *         can only be a {@link Constant}.
      */
-    public Constant getMaterializedValue(LIRInstruction op, Value operand) {
+    public Constant getMaterializedValue(LIRInstruction op, Value operand, Interval interval) {
         if (op instanceof MoveOp) {
             MoveOp move = (MoveOp) op;
             if (move.getInput() instanceof Constant) {
+                /*
+                 * Check if the interval has any uses which would accept an stack location (priority
+                 * == ShouldHaveRegister). Rematerialization of such intervals can result in a
+                 * degradation, because rematerialization always inserts a constant load, even if
+                 * the value is not needed in a register.
+                 */
+                Interval.UsePosList usePosList = interval.usePosList();
+                int numUsePos = usePosList.size();
+                for (int useIdx = 0; useIdx < numUsePos; useIdx++) {
+                    Interval.RegisterPriority priority = usePosList.registerPriority(useIdx);
+                    if (priority == Interval.RegisterPriority.ShouldHaveRegister) {
+                        return null;
+                    }
+                }
                 return (Constant) move.getInput();
             }
         }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaField.java	Mon Jan 13 13:20:30 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaField.java	Mon Jan 13 13:45:25 2014 +0100
@@ -98,7 +98,7 @@
         ResolvedJavaMethod initMethod = null;
         try {
             Class<?> rjm = ResolvedJavaMethod.class;
-            makeGraphMethod = metaAccess.lookupJavaMethod(ReplacementsImpl.class.getDeclaredMethod("makeGraph", rjm, rjm, SnippetInliningPolicy.class, boolean.class));
+            makeGraphMethod = metaAccess.lookupJavaMethod(ReplacementsImpl.class.getDeclaredMethod("makeGraph", rjm, rjm, rjm, SnippetInliningPolicy.class, boolean.class, boolean.class));
             initMethod = metaAccess.lookupJavaMethod(SnippetTemplate.AbstractTemplates.class.getDeclaredMethod("template", Arguments.class));
         } catch (NoSuchMethodException | SecurityException e) {
             throw new GraalInternalError(e);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ArrayCopyNode.java	Mon Jan 13 13:20:30 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ArrayCopyNode.java	Mon Jan 13 13:45:25 2014 +0100
@@ -107,7 +107,7 @@
             final ResolvedJavaMethod snippetMethod = tool.getMetaAccess().lookupJavaMethod(ArrayCopySnippets.genericArraycopySnippet);
             snippetGraph = null;
             try (Scope s = Debug.scope("ArrayCopySnippet", snippetMethod)) {
-                snippetGraph = replacements.getSnippet(snippetMethod).copy();
+                snippetGraph = replacements.getSnippet(snippetMethod, getTargetMethod()).copy();
             } catch (Throwable e) {
                 throw Debug.handle(e);
             }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/GraphKit.java	Mon Jan 13 13:20:30 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/GraphKit.java	Mon Jan 13 13:45:25 2014 +0100
@@ -158,7 +158,7 @@
     public void inline(InvokeNode invoke) {
         ResolvedJavaMethod method = ((MethodCallTargetNode) invoke.callTarget()).targetMethod();
         ReplacementsImpl repl = new ReplacementsImpl(providers, new Assumptions(false), providers.getCodeCache().getTarget());
-        StructuredGraph calleeGraph = repl.makeGraph(method, null, null, false);
+        StructuredGraph calleeGraph = repl.makeGraph(method, null, method, null, false, false);
         InliningUtil.inline(invoke, calleeGraph, false);
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/DynamicNewInstanceNode.java	Mon Jan 13 13:20:30 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/DynamicNewInstanceNode.java	Mon Jan 13 13:45:25 2014 +0100
@@ -28,7 +28,7 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.type.*;
 
-public class DynamicNewInstanceNode extends AbstractNewObjectNode {
+public class DynamicNewInstanceNode extends AbstractNewObjectNode implements Canonicalizable {
 
     @Input private ValueNode clazz;
 
@@ -45,11 +45,11 @@
                 Class staticClass = (Class) clazzConstant.asObject();
                 ResolvedJavaType type = tool.getMetaAccess().lookupJavaType(staticClass);
                 if (type.isInitialized()) {
-                    return new NewInstanceNode(type, fillContents());
+                    return graph().add(new NewInstanceNode(type, fillContents()));
                 }
             }
         }
-        return super.canonical(tool);
+        return this;
     }
 
     public ValueNode getInstanceType() {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Replacements.java	Mon Jan 13 13:20:30 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Replacements.java	Mon Jan 13 13:45:25 2014 +0100
@@ -42,6 +42,16 @@
     StructuredGraph getSnippet(ResolvedJavaMethod method);
 
     /**
+     * Gets the snippet graph derived from a given method.
+     * 
+     * @param recursiveEntry if the snippet contains a call to this method, it's considered as
+     *            recursive call and won't be processed for {@linkplain MethodSubstitution
+     *            substitutions} or {@linkplain MacroSubstitution macro nodes}.
+     * @return the snippet graph, if any, that is derived from {@code method}
+     */
+    StructuredGraph getSnippet(ResolvedJavaMethod method, ResolvedJavaMethod recursiveEntry);
+
+    /**
      * Registers a method as snippet.
      */
     void registerSnippet(ResolvedJavaMethod method);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/ObjectStamp.java	Mon Jan 13 13:20:30 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/ObjectStamp.java	Mon Jan 13 13:45:25 2014 +0100
@@ -37,7 +37,7 @@
 
     public ObjectStamp(ResolvedJavaType type, boolean exactType, boolean nonNull, boolean alwaysNull) {
         super(Kind.Object);
-        assert !exactType || (type != null && (!Modifier.isAbstract(type.getModifiers()) || type.isArray()));
+        assert !exactType || (type != null && (isConcreteType(type)));
         this.type = type;
         this.exactType = exactType;
         this.nonNull = nonNull;
@@ -198,7 +198,7 @@
         }
         if (joinAlwaysNull && joinNonNull) {
             return StampFactory.illegal(Kind.Object);
-        } else if (joinExactType && Modifier.isAbstract(joinType.getModifiers()) && !joinType.isArray()) {
+        } else if (joinExactType && !isConcreteType(joinType)) {
             return StampFactory.illegal(Kind.Object);
         }
         if (joinType == type && joinExactType == exactType && joinNonNull == nonNull && joinAlwaysNull == alwaysNull) {
@@ -210,6 +210,10 @@
         }
     }
 
+    public static boolean isConcreteType(ResolvedJavaType type) {
+        return !(Modifier.isAbstract(type.getModifiers()) && !type.isArray());
+    }
+
     private static ResolvedJavaType meetTypes(ResolvedJavaType a, ResolvedJavaType b) {
         if (a == b) {
             return a;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/StampFactory.java	Mon Jan 13 13:20:30 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/StampFactory.java	Mon Jan 13 13:45:25 2014 +0100
@@ -218,7 +218,11 @@
     }
 
     public static Stamp exactNonNull(ResolvedJavaType type) {
-        return new ObjectStamp(type, true, true, false);
+        if (ObjectStamp.isConcreteType(type)) {
+            return new ObjectStamp(type, true, true, false);
+        } else {
+            return illegal(Kind.Object);
+        }
     }
 
     public static Stamp exact(ResolvedJavaType type) {
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java	Mon Jan 13 13:20:30 2014 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java	Mon Jan 13 13:45:25 2014 +0100
@@ -234,7 +234,6 @@
 
         public boolean baseTryCanonicalize(final Node node, NodeClass nodeClass) {
             if (nodeClass.isCanonicalizable()) {
-                assert !nodeClass.isSimplifiable();
                 METRIC_CANONICALIZATION_CONSIDERED_NODES.increment();
                 try (Scope s = Debug.scope("CanonicalizeNode", node)) {
                     Node canonical = node.canonical(tool);
@@ -242,7 +241,9 @@
                 } catch (Throwable e) {
                     throw Debug.handle(e);
                 }
-            } else if (nodeClass.isSimplifiable()) {
+            }
+
+            if (nodeClass.isSimplifiable()) {
                 Debug.log("Canonicalizer: simplifying %s", node);
                 METRIC_SIMPLIFICATION_CONSIDERED_NODES.increment();
                 try (Scope s = Debug.scope("SimplifyNode", node)) {
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java	Mon Jan 13 13:20:30 2014 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java	Mon Jan 13 13:45:25 2014 +0100
@@ -328,7 +328,7 @@
                 assert inlineable instanceof InlineableMacroNode;
 
                 Class<? extends FixedWithNextNode> macroNodeClass = ((InlineableMacroNode) inlineable).getMacroNodeClass();
-                inlineMacroNode(invoke, concrete, graph, macroNodeClass);
+                inlineMacroNode(invoke, concrete, macroNodeClass);
             }
 
             InlinedBytecodes.add(concrete.getCodeSize());
@@ -1492,7 +1492,8 @@
         return replacements.getMacroSubstitution(target);
     }
 
-    public static FixedWithNextNode inlineMacroNode(Invoke invoke, ResolvedJavaMethod concrete, StructuredGraph graph, Class<? extends FixedWithNextNode> macroNodeClass) throws GraalInternalError {
+    public static FixedWithNextNode inlineMacroNode(Invoke invoke, ResolvedJavaMethod concrete, Class<? extends FixedWithNextNode> macroNodeClass) throws GraalInternalError {
+        StructuredGraph graph = invoke.asNode().graph();
         if (((MethodCallTargetNode) invoke.callTarget()).targetMethod() != concrete) {
             assert ((MethodCallTargetNode) invoke.callTarget()).invokeKind() != InvokeKind.Static;
             InliningUtil.replaceInvokeCallTarget(invoke, graph, InvokeKind.Special, concrete);
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java	Mon Jan 13 13:20:30 2014 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java	Mon Jan 13 13:45:25 2014 +0100
@@ -491,7 +491,7 @@
             return latestBlock;
         }
 
-        Stack<Block> path = computePathInDominatorTree(earliestBlock, latestBlock);
+        Deque<Block> path = computePathInDominatorTree(earliestBlock, latestBlock);
         Debug.printf("|path| is %d: %s\n", path.size(), path);
 
         // follow path, start at earliest schedule
@@ -542,8 +542,8 @@
      * 
      * @return the order of the stack is such as the first element is the earliest schedule.
      */
-    private static Stack<Block> computePathInDominatorTree(Block earliestBlock, Block latestBlock) {
-        Stack<Block> path = new Stack<>();
+    private static Deque<Block> computePathInDominatorTree(Block earliestBlock, Block latestBlock) {
+        Deque<Block> path = new LinkedList<>();
         Block currentBlock = latestBlock;
         while (currentBlock != null && earliestBlock.dominates(currentBlock)) {
             path.push(currentBlock);
@@ -559,17 +559,17 @@
      */
     private static HashSet<Block> computeRegion(Block dominatorBlock, Block dominatedBlock) {
         HashSet<Block> region = new HashSet<>();
-        Stack<Block> workList = new Stack<>();
+        Queue<Block> workList = new LinkedList<>();
 
         region.add(dominatorBlock);
-        workList.addAll(0, dominatorBlock.getSuccessors());
+        workList.addAll(dominatorBlock.getSuccessors());
         while (workList.size() > 0) {
-            Block current = workList.pop();
+            Block current = workList.poll();
             if (current != dominatedBlock) {
                 region.add(current);
                 for (Block b : current.getSuccessors()) {
                     if (!region.contains(b) && !workList.contains(b)) {
-                        workList.add(b);
+                        workList.offer(b);
                     }
                 }
             }
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ObjectAccessTest.java	Mon Jan 13 13:20:30 2014 +0100
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ObjectAccessTest.java	Mon Jan 13 13:45:25 2014 +0100
@@ -54,7 +54,7 @@
     @Override
     protected StructuredGraph parse(Method m) {
         ResolvedJavaMethod resolvedMethod = getMetaAccess().lookupJavaMethod(m);
-        return installer.makeGraph(resolvedMethod, null, inliningPolicy.get(), false);
+        return installer.makeGraph(resolvedMethod, null, resolvedMethod, inliningPolicy.get(), false, false);
     }
 
     @Test
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/PointerTest.java	Mon Jan 13 13:20:30 2014 +0100
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/PointerTest.java	Mon Jan 13 13:45:25 2014 +0100
@@ -60,7 +60,7 @@
     @Override
     protected StructuredGraph parse(Method m) {
         ResolvedJavaMethod resolvedMethod = getMetaAccess().lookupJavaMethod(m);
-        return installer.makeGraph(resolvedMethod, null, inliningPolicy.get(), false);
+        return installer.makeGraph(resolvedMethod, null, resolvedMethod, inliningPolicy.get(), false, false);
     }
 
     @Test
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/WordTest.java	Mon Jan 13 13:20:30 2014 +0100
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/WordTest.java	Mon Jan 13 13:45:25 2014 +0100
@@ -49,7 +49,7 @@
     @Override
     protected StructuredGraph parse(Method m) {
         ResolvedJavaMethod resolvedMethod = getMetaAccess().lookupJavaMethod(m);
-        return installer.makeGraph(resolvedMethod, null, inliningPolicy.get(), false);
+        return installer.makeGraph(resolvedMethod, null, resolvedMethod, inliningPolicy.get(), false, false);
     }
 
     @LongTest
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/InstanceOfSnippetsTemplates.java	Mon Jan 13 13:20:30 2014 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/InstanceOfSnippetsTemplates.java	Mon Jan 13 13:45:25 2014 +0100
@@ -93,7 +93,7 @@
      */
     protected InstanceOfUsageReplacer createReplacer(FloatingNode instanceOf, Instantiation instantiation, Node usage, final StructuredGraph graph) {
         InstanceOfUsageReplacer replacer;
-        if (usage instanceof IfNode || usage instanceof FixedGuardNode || usage instanceof ShortCircuitOrNode || usage instanceof GuardingPiNode) {
+        if (usage instanceof IfNode || usage instanceof FixedGuardNode || usage instanceof ShortCircuitOrNode || usage instanceof GuardingPiNode || usage instanceof ConditionAnchorNode) {
             replacer = new NonMaterializationUsageReplacer(instantiation, ConstantNode.forInt(1, graph), ConstantNode.forInt(0, graph), instanceOf, usage);
         } else {
             assert usage instanceof ConditionalNode : "unexpected usage of " + instanceOf + ": " + usage;
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Mon Jan 13 13:20:30 2014 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Mon Jan 13 13:45:25 2014 +0100
@@ -84,15 +84,19 @@
     private static final boolean UseSnippetGraphCache = Boolean.parseBoolean(System.getProperty("graal.useSnippetGraphCache", "true"));
     private static final DebugTimer SnippetPreparationTime = Debug.timer("SnippetPreparationTime");
 
+    public StructuredGraph getSnippet(ResolvedJavaMethod method) {
+        return getSnippet(method, null);
+    }
+
     @Override
-    public StructuredGraph getSnippet(ResolvedJavaMethod method) {
+    public StructuredGraph getSnippet(ResolvedJavaMethod method, ResolvedJavaMethod recursiveEntry) {
         assert method.getAnnotation(Snippet.class) != null : "Snippet must be annotated with @" + Snippet.class.getSimpleName();
         assert !Modifier.isAbstract(method.getModifiers()) && !Modifier.isNative(method.getModifiers()) : "Snippet must not be abstract or native";
 
         StructuredGraph graph = UseSnippetGraphCache ? graphs.get(method) : null;
         if (graph == null) {
             try (TimerCloseable a = SnippetPreparationTime.start()) {
-                StructuredGraph newGraph = makeGraph(method, null, inliningPolicy(method), method.getAnnotation(Snippet.class).removeAllFrameStates());
+                StructuredGraph newGraph = makeGraph(method, recursiveEntry, recursiveEntry, inliningPolicy(method), method.getAnnotation(Snippet.class).removeAllFrameStates(), false);
                 Debug.metric("SnippetNodeCount[" + method.getName() + "]").add(newGraph.getNodeCount());
                 if (!UseSnippetGraphCache) {
                     return newGraph;
@@ -127,7 +131,7 @@
         }
         StructuredGraph graph = graphs.get(substitute);
         if (graph == null) {
-            graphs.putIfAbsent(substitute, makeGraph(substitute, original, inliningPolicy(substitute), false));
+            graphs.putIfAbsent(substitute, makeGraph(substitute, original, substitute, inliningPolicy(substitute), false, true));
             graph = graphs.get(substitute);
         }
         return graph;
@@ -259,15 +263,16 @@
      * @param policy the inlining policy to use during preprocessing
      * @param removeAllFrameStates removes all frame states from side effecting instructions
      */
-    public StructuredGraph makeGraph(ResolvedJavaMethod method, ResolvedJavaMethod original, SnippetInliningPolicy policy, boolean removeAllFrameStates) {
-        return createGraphMaker(method, original).makeGraph(policy, removeAllFrameStates);
+    public StructuredGraph makeGraph(ResolvedJavaMethod method, ResolvedJavaMethod original, ResolvedJavaMethod recursiveEntry, SnippetInliningPolicy policy, boolean removeAllFrameStates,
+                    boolean isMethodSubstitution) {
+        return createGraphMaker(method, original, recursiveEntry, isMethodSubstitution).makeGraph(policy, removeAllFrameStates);
     }
 
     /**
      * Can be overridden to return an object that specializes various parts of graph preprocessing.
      */
-    protected GraphMaker createGraphMaker(ResolvedJavaMethod substitute, ResolvedJavaMethod original) {
-        return new GraphMaker(substitute, original);
+    protected GraphMaker createGraphMaker(ResolvedJavaMethod substitute, ResolvedJavaMethod original, ResolvedJavaMethod recursiveEntry, boolean isMethodSubstitution) {
+        return new GraphMaker(substitute, original, recursiveEntry, isMethodSubstitution);
     }
 
     /**
@@ -279,23 +284,32 @@
      * Creates and preprocesses a graph for a replacement.
      */
     protected class GraphMaker {
-
         /**
          * The method for which a graph is being created.
          */
         protected final ResolvedJavaMethod method;
 
         /**
-         * The original method if {@link #method} is a {@linkplain MethodSubstitution substitution}
-         * otherwise null.
+         * The method which is used when a call to {@link #recursiveEntry} is found.
          */
-        protected final ResolvedJavaMethod original;
+        protected final ResolvedJavaMethod substitutedMethod;
+
+        /**
+         * The method which is used to detect a recursive call.
+         */
+        protected final ResolvedJavaMethod recursiveEntry;
 
-        boolean substituteCallsOriginal;
+        /**
+         * Controls if FrameStates should be removed or processed with the
+         * {@link SnippetFrameStateCleanupPhase}.
+         */
+        protected final boolean isMethodSubstitution;
 
-        protected GraphMaker(ResolvedJavaMethod substitute, ResolvedJavaMethod original) {
+        protected GraphMaker(ResolvedJavaMethod substitute, ResolvedJavaMethod substitutedMethod, ResolvedJavaMethod recursiveEntry, boolean isMethodSubstitution) {
             this.method = substitute;
-            this.original = original;
+            this.substitutedMethod = substitutedMethod;
+            this.recursiveEntry = recursiveEntry;
+            this.isMethodSubstitution = isMethodSubstitution;
         }
 
         public StructuredGraph makeGraph(final SnippetInliningPolicy policy, final boolean removeAllFrameStates) {
@@ -325,7 +339,7 @@
             }
             new ConvertDeoptimizeToGuardPhase().apply(graph);
 
-            if (original == null) {
+            if (!isMethodSubstitution) {
                 if (removeAllFrameStates) {
                     for (Node node : graph.getNodes()) {
                         if (node instanceof StateSplit) {
@@ -405,38 +419,44 @@
         }
 
         private StructuredGraph buildGraph(final ResolvedJavaMethod methodToParse, final SnippetInliningPolicy policy) {
-            assert !Modifier.isAbstract(methodToParse.getModifiers()) && !Modifier.isNative(methodToParse.getModifiers()) : methodToParse;
+            assert isInlinableSnippet(methodToParse) : methodToParse;
             final StructuredGraph graph = buildInitialGraph(methodToParse);
             try (Scope s = Debug.scope("buildGraph", graph)) {
 
                 for (MethodCallTargetNode callTarget : graph.getNodes(MethodCallTargetNode.class)) {
                     ResolvedJavaMethod callee = callTarget.targetMethod();
-                    if (callee == method) {
-                        final StructuredGraph originalGraph = buildInitialGraph(original);
-                        InliningUtil.inline(callTarget.invoke(), originalGraph, true);
+                    if (callee == recursiveEntry) {
+                        if (isInlinableSnippet(substitutedMethod)) {
+                            final StructuredGraph originalGraph = buildInitialGraph(substitutedMethod);
+                            InliningUtil.inline(callTarget.invoke(), originalGraph, true);
 
-                        Debug.dump(graph, "after inlining %s", callee);
-                        afterInline(graph, originalGraph, null);
-                        substituteCallsOriginal = true;
+                            Debug.dump(graph, "after inlining %s", callee);
+                            afterInline(graph, originalGraph, null);
+                        }
                     } else {
-                        StructuredGraph intrinsicGraph = InliningUtil.getIntrinsicGraph(ReplacementsImpl.this, callee);
-                        if ((callTarget.invokeKind() == InvokeKind.Static || callTarget.invokeKind() == InvokeKind.Special) &&
-                                        (policy.shouldInline(callee, methodToParse) || (intrinsicGraph != null && policy.shouldUseReplacement(callee, methodToParse)))) {
-                            StructuredGraph targetGraph;
-                            if (intrinsicGraph != null && policy.shouldUseReplacement(callee, methodToParse)) {
-                                targetGraph = intrinsicGraph;
-                            } else {
-                                if (callee.getName().startsWith("$jacoco")) {
-                                    throw new GraalInternalError("Parsing call to JaCoCo instrumentation method " + format("%H.%n(%p)", callee) + " from " + format("%H.%n(%p)", methodToParse) +
-                                                    " while preparing replacement " + format("%H.%n(%p)", method) + ". Placing \"//JaCoCo Exclude\" anywhere in " +
-                                                    methodToParse.getDeclaringClass().getSourceFileName() + " should fix this.");
+                        Class<? extends FixedWithNextNode> macroNodeClass = InliningUtil.getMacroNodeClass(ReplacementsImpl.this, callee);
+                        if (macroNodeClass != null) {
+                            InliningUtil.inlineMacroNode(callTarget.invoke(), callee, macroNodeClass);
+                        } else {
+                            StructuredGraph intrinsicGraph = InliningUtil.getIntrinsicGraph(ReplacementsImpl.this, callee);
+                            if ((callTarget.invokeKind() == InvokeKind.Static || callTarget.invokeKind() == InvokeKind.Special) &&
+                                            (policy.shouldInline(callee, methodToParse) || (intrinsicGraph != null && policy.shouldUseReplacement(callee, methodToParse)))) {
+                                StructuredGraph targetGraph;
+                                if (intrinsicGraph != null && policy.shouldUseReplacement(callee, methodToParse)) {
+                                    targetGraph = intrinsicGraph;
+                                } else {
+                                    if (callee.getName().startsWith("$jacoco")) {
+                                        throw new GraalInternalError("Parsing call to JaCoCo instrumentation method " + format("%H.%n(%p)", callee) + " from " + format("%H.%n(%p)", methodToParse) +
+                                                        " while preparing replacement " + format("%H.%n(%p)", method) + ". Placing \"//JaCoCo Exclude\" anywhere in " +
+                                                        methodToParse.getDeclaringClass().getSourceFileName() + " should fix this.");
+                                    }
+                                    targetGraph = parseGraph(callee, policy);
                                 }
-                                targetGraph = parseGraph(callee, policy);
+                                Object beforeInlineData = beforeInline(callTarget, targetGraph);
+                                InliningUtil.inline(callTarget.invoke(), targetGraph, true);
+                                Debug.dump(graph, "after inlining %s", callee);
+                                afterInline(graph, targetGraph, beforeInlineData);
                             }
-                            Object beforeInlineData = beforeInline(callTarget, targetGraph);
-                            InliningUtil.inline(callTarget.invoke(), targetGraph, true);
-                            Debug.dump(graph, "after inlining %s", callee);
-                            afterInline(graph, targetGraph, beforeInlineData);
                         }
                     }
                 }
@@ -455,6 +475,10 @@
         }
     }
 
+    private static boolean isInlinableSnippet(final ResolvedJavaMethod methodToParse) {
+        return !Modifier.isAbstract(methodToParse.getModifiers()) && !Modifier.isNative(methodToParse.getModifiers());
+    }
+
     private static String originalName(Method substituteMethod, String methodSubstitution) {
         if (methodSubstitution.isEmpty()) {
             return substituteMethod.getName();
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java	Mon Jan 13 13:20:30 2014 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java	Mon Jan 13 13:45:25 2014 +0100
@@ -38,6 +38,7 @@
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.tiers.*;
+import com.oracle.graal.replacements.*;
 
 public class MacroNode extends AbstractMemoryCheckpoint implements Lowerable, MemoryCheckpoint.Single {
 
@@ -86,6 +87,13 @@
     protected StructuredGraph getLoweredSubstitutionGraph(LoweringTool tool) {
         StructuredGraph methodSubstitution = tool.getReplacements().getMethodSubstitution(getTargetMethod());
         if (methodSubstitution != null) {
+            if (stateAfter() == null) {
+                /*
+                 * handles the case of a MacroNode inside a snippet used for another MacroNode
+                 * lowering
+                 */
+                new SnippetFrameStateCleanupPhase().apply(methodSubstitution);
+            }
             return lowerReplacement(methodSubstitution.copy(), tool);
         }
         return null;
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Mon Jan 13 13:20:30 2014 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Mon Jan 13 13:45:25 2014 +0100
@@ -194,7 +194,7 @@
                     Replacements replacements = providers.getReplacements();
                     Class<? extends FixedWithNextNode> macroSubstitution = replacements.getMacroSubstitution(methodCallTargetNode.targetMethod());
                     if (macroSubstitution != null) {
-                        InliningUtil.inlineMacroNode(methodCallTargetNode.invoke(), methodCallTargetNode.targetMethod(), methodCallTargetNode.graph(), macroSubstitution);
+                        InliningUtil.inlineMacroNode(methodCallTargetNode.invoke(), methodCallTargetNode.targetMethod(), macroSubstitution);
                         changed = true;
                         continue;
                     }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCache.java	Mon Jan 13 13:20:30 2014 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCache.java	Mon Jan 13 13:45:25 2014 +0100
@@ -135,7 +135,7 @@
                                 MethodCallTargetNode methodCallTargetNode = (MethodCallTargetNode) newNode;
                                 Class<? extends FixedWithNextNode> macroSubstitution = providers.getReplacements().getMacroSubstitution(methodCallTargetNode.targetMethod());
                                 if (macroSubstitution != null) {
-                                    InliningUtil.inlineMacroNode(methodCallTargetNode.invoke(), methodCallTargetNode.targetMethod(), methodCallTargetNode.graph(), macroSubstitution);
+                                    InliningUtil.inlineMacroNode(methodCallTargetNode.invoke(), methodCallTargetNode.targetMethod(), macroSubstitution);
                                 } else {
                                     tryCutOffRuntimeExceptions(methodCallTargetNode);
                                 }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/phases/ReplaceIntrinsicsPhase.java	Mon Jan 13 13:20:30 2014 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/phases/ReplaceIntrinsicsPhase.java	Mon Jan 13 13:45:25 2014 +0100
@@ -49,7 +49,7 @@
                 if (invokeKind == InvokeKind.Static || invokeKind == InvokeKind.Special) {
                     Class<? extends FixedWithNextNode> macroSubstitution = replacements.getMacroSubstitution(methodCallTarget.targetMethod());
                     if (macroSubstitution != null) {
-                        InliningUtil.inlineMacroNode(methodCallTarget.invoke(), methodCallTarget.targetMethod(), graph, macroSubstitution);
+                        InliningUtil.inlineMacroNode(methodCallTarget.invoke(), methodCallTarget.targetMethod(), macroSubstitution);
                         Debug.dump(graph, "After inlining %s", methodCallTarget.targetMethod().toString());
                     } else {
                         StructuredGraph inlineGraph = replacements.getMethodSubstitution(methodCallTarget.targetMethod());