changeset 19776:16ad9711b44f

always inline intrinsics in the graph builder as well as any methods (recursively) called from an instrinsic replace BytecodeParser.currentDepth with BytecodeParser.parent
author Doug Simon <doug.simon@oracle.com>
date Thu, 19 Feb 2015 15:40:17 +0100
parents 95aa11d4822d
children 017eb83853dd
files graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FinalizableSubclassTest.java graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EATestBase.java graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/tutorial/StaticAnalysis.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSuitesProvider.java graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderContext.java graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPlugin.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCacheImpl.java
diffstat 11 files changed, 148 insertions(+), 98 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FinalizableSubclassTest.java	Thu Feb 19 13:25:23 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FinalizableSubclassTest.java	Thu Feb 19 15:40:17 2015 +0100
@@ -68,7 +68,7 @@
         StructuredGraph graph = new StructuredGraph(javaMethod, allowAssumptions);
 
         GraphBuilderConfiguration conf = GraphBuilderConfiguration.getSnippetDefault();
-        new GraphBuilderPhase.Instance(getMetaAccess(), getProviders().getStampProvider(), getProviders().getConstantReflection(), conf, OptimisticOptimizations.ALL).apply(graph);
+        new GraphBuilderPhase.Instance(getMetaAccess(), getProviders().getStampProvider(), getProviders().getConstantReflection(), conf, OptimisticOptimizations.ALL, false).apply(graph);
         HighTierContext context = new HighTierContext(getProviders(), null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
         new InliningPhase(new CanonicalizerPhase(true)).apply(graph, context);
         new CanonicalizerPhase(true).apply(graph, context);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EATestBase.java	Thu Feb 19 13:25:23 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EATestBase.java	Thu Feb 19 15:40:17 2015 +0100
@@ -152,7 +152,7 @@
         graph = new StructuredGraph(method, AllowAssumptions.NO);
         try (Scope s = Debug.scope(getClass(), graph, method, getCodeCache())) {
             new GraphBuilderPhase.Instance(getMetaAccess(), getProviders().getStampProvider(), getProviders().getConstantReflection(), GraphBuilderConfiguration.getEagerDefault(),
-                            OptimisticOptimizations.ALL).apply(graph);
+                            OptimisticOptimizations.ALL, false).apply(graph);
             context = new HighTierContext(getProviders(), null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
             new InliningPhase(new CanonicalizerPhase(true)).apply(graph, context);
             new DeadCodeEliminationPhase().apply(graph);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/tutorial/StaticAnalysis.java	Thu Feb 19 13:25:23 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/tutorial/StaticAnalysis.java	Thu Feb 19 15:40:17 2015 +0100
@@ -237,7 +237,7 @@
                      */
                     OptimisticOptimizations optimisticOpts = OptimisticOptimizations.NONE;
 
-                    GraphBuilderPhase.Instance graphBuilder = new GraphBuilderPhase.Instance(metaAccess, stampProvider, null, graphBuilderConfig, optimisticOpts);
+                    GraphBuilderPhase.Instance graphBuilder = new GraphBuilderPhase.Instance(metaAccess, stampProvider, null, graphBuilderConfig, optimisticOpts, false);
                     graphBuilder.apply(graph);
                 } catch (Throwable ex) {
                     Debug.handle(ex);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSuitesProvider.java	Thu Feb 19 13:25:23 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSuitesProvider.java	Thu Feb 19 15:40:17 2015 +0100
@@ -129,78 +129,88 @@
     protected PhaseSuite<HighTierContext> createGraphBuilderSuite(MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, Replacements replacements) {
         PhaseSuite<HighTierContext> suite = new PhaseSuite<>();
         GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault();
-        if (InlineDuringParsing.getValue()) {
-            config.setLoadFieldPlugin(new LoadFieldPlugin() {
-                public boolean apply(GraphBuilderContext builder, ValueNode receiver, ResolvedJavaField field) {
+        config.setLoadFieldPlugin(new LoadFieldPlugin() {
+            public boolean apply(GraphBuilderContext builder, ValueNode receiver, ResolvedJavaField field) {
+                if (InlineDuringParsing.getValue() || builder.parsingReplacement()) {
                     if (receiver.isConstant()) {
                         JavaConstant asJavaConstant = receiver.asJavaConstant();
                         return tryConstantFold(builder, metaAccess, constantReflection, field, asJavaConstant);
                     }
-                    return false;
-                }
-
-                public boolean apply(GraphBuilderContext builder, ResolvedJavaField staticField) {
-                    return tryConstantFold(builder, metaAccess, constantReflection, staticField, null);
                 }
-            });
-            config.setInlineInvokePlugin(new InlineInvokePlugin() {
-                public ResolvedJavaMethod getInlinedMethod(GraphBuilderContext builder, ResolvedJavaMethod method, ValueNode[] args, JavaType returnType, int depth) {
-                    ResolvedJavaMethod subst = replacements.getMethodSubstitutionMethod(method);
-                    if (subst != null) {
-                        return subst;
+                return false;
+            }
+
+            public boolean apply(GraphBuilderContext builder, ResolvedJavaField staticField) {
+                return tryConstantFold(builder, metaAccess, constantReflection, staticField, null);
+            }
+        });
+        config.setInlineInvokePlugin(new InlineInvokePlugin() {
+            public ResolvedJavaMethod getInlinedMethod(GraphBuilderContext builder, ResolvedJavaMethod method, ValueNode[] args, JavaType returnType) {
+                ResolvedJavaMethod subst = replacements.getMethodSubstitutionMethod(method);
+                if (subst != null) {
+                    // Forced inlining of intrinsics
+                    return subst;
+                }
+                if (builder.parsingReplacement()) {
+                    if (getIntrinsifier().getIntrinsic(method) != null) {
+                        // @NodeIntrinsic methods are handled by the AnnotatedInvocationPlugin
+                        // registered below
+                        return null;
                     }
-                    if (builder.parsingReplacement() && method.getAnnotation(NodeIntrinsic.class) == null) {
-                        return method;
-                    }
-                    if (method.hasBytecodes() && method.getCode().length <= TrivialInliningSize.getValue() && depth < InlineDuringParsingMaxDepth.getValue()) {
+                    // Force inlining when parsing replacements
+                    return method;
+                } else {
+                    assert getIntrinsifier().getIntrinsic(method) == null : String.format("@%s method %s must only be called from within a replacement%n%s", NodeIntrinsic.class.getSimpleName(),
+                                    method.format("%h.%n"), builder);
+                    if (InlineDuringParsing.getValue() && method.hasBytecodes() && method.getCode().length <= TrivialInliningSize.getValue() &&
+                                    builder.getDepth() < InlineDuringParsingMaxDepth.getValue()) {
                         return method;
                     }
-                    return null;
                 }
-            });
-            config.setAnnotatedInvocationPlugin(new AnnotatedInvocationPlugin() {
-                public boolean apply(GraphBuilderContext builder, ResolvedJavaMethod method, ValueNode[] args) {
-                    if (builder.parsingReplacement()) {
-                        @SuppressWarnings("hiding")
-                        NodeIntrinsificationPhase intrinsifier = getIntrinsifier();
-                        NodeIntrinsic intrinsic = intrinsifier.getIntrinsic(method);
-                        if (intrinsic != null) {
-                            Signature sig = method.getSignature();
-                            Kind returnKind = sig.getReturnKind();
-                            Stamp stamp = StampFactory.forKind(returnKind);
-                            if (returnKind == Kind.Object) {
-                                JavaType returnType = sig.getReturnType(method.getDeclaringClass());
-                                if (returnType instanceof ResolvedJavaType) {
-                                    stamp = StampFactory.declared((ResolvedJavaType) returnType);
-                                }
+                return null;
+            }
+        });
+        config.setAnnotatedInvocationPlugin(new AnnotatedInvocationPlugin() {
+            public boolean apply(GraphBuilderContext builder, ResolvedJavaMethod method, ValueNode[] args) {
+                if (builder.parsingReplacement()) {
+                    NodeIntrinsificationPhase intrins = getIntrinsifier();
+                    NodeIntrinsic intrinsic = intrins.getIntrinsic(method);
+                    if (intrinsic != null) {
+                        Signature sig = method.getSignature();
+                        Kind returnKind = sig.getReturnKind();
+                        Stamp stamp = StampFactory.forKind(returnKind);
+                        if (returnKind == Kind.Object) {
+                            JavaType returnType = sig.getReturnType(method.getDeclaringClass());
+                            if (returnType instanceof ResolvedJavaType) {
+                                stamp = StampFactory.declared((ResolvedJavaType) returnType);
                             }
+                        }
 
-                            ValueNode res = intrinsifier.createIntrinsicNode(Arrays.asList(args), stamp, method, builder.getGraph(), intrinsic);
-                            res = builder.append(res);
-                            if (res.getKind().getStackKind() != Kind.Void) {
-                                builder.push(returnKind.getStackKind(), res);
+                        ValueNode res = intrins.createIntrinsicNode(Arrays.asList(args), stamp, method, builder.getGraph(), intrinsic);
+                        res = builder.append(res);
+                        if (res.getKind().getStackKind() != Kind.Void) {
+                            builder.push(returnKind.getStackKind(), res);
+                        }
+                        return true;
+                    } else if (intrins.isFoldable(method)) {
+                        ResolvedJavaType[] parameterTypes = resolveJavaTypes(method.toParameterTypes(), method.getDeclaringClass());
+                        JavaConstant constant = intrins.tryFold(Arrays.asList(args), parameterTypes, method);
+                        if (!COULD_NOT_FOLD.equals(constant)) {
+                            if (constant != null) {
+                                // Replace the invoke with the result of the call
+                                ConstantNode res = builder.append(ConstantNode.forConstant(constant, getMetaAccess()));
+                                builder.push(res.getKind().getStackKind(), builder.append(res));
+                            } else {
+                                // This must be a void invoke
+                                assert method.getSignature().getReturnKind() == Kind.Void;
                             }
                             return true;
-                        } else if (intrinsifier.isFoldable(method)) {
-                            ResolvedJavaType[] parameterTypes = resolveJavaTypes(method.toParameterTypes(), method.getDeclaringClass());
-                            JavaConstant constant = intrinsifier.tryFold(Arrays.asList(args), parameterTypes, method);
-                            if (!COULD_NOT_FOLD.equals(constant)) {
-                                if (constant != null) {
-                                    // Replace the invoke with the result of the call
-                                    ConstantNode res = builder.append(ConstantNode.forConstant(constant, getMetaAccess()));
-                                    builder.push(res.getKind().getStackKind(), builder.append(res));
-                                } else {
-                                    // This must be a void invoke
-                                    assert method.getSignature().getReturnKind() == Kind.Void;
-                                }
-                                return true;
-                            }
                         }
                     }
-                    return false;
                 }
-            });
-        }
+                return false;
+            }
+        });
         suite.appendPhase(new GraphBuilderPhase(config));
         return suite;
     }
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderContext.java	Thu Feb 19 13:25:23 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderContext.java	Thu Feb 19 15:40:17 2015 +0100
@@ -60,6 +60,16 @@
     StructuredGraph getGraph();
 
     /**
+     * Gets the parsing context for the method that inlines the method being parsed by this context.
+     */
+    GraphBuilderContext getParent();
+
+    /**
+     * Gets the inline depth of this context. 0 implies this is the context for the root method.
+     */
+    int getDepth();
+
+    /**
      * Determines if the graph builder is parsing a snippet or method substitution.
      */
     boolean parsingReplacement();
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Thu Feb 19 13:25:23 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Thu Feb 19 15:40:17 2015 +0100
@@ -76,7 +76,7 @@
 
     @Override
     protected void run(StructuredGraph graph, HighTierContext context) {
-        new Instance(context.getMetaAccess(), context.getStampProvider(), null, context.getConstantReflection(), graphBuilderConfig, context.getOptimisticOptimizations()).run(graph);
+        new Instance(context.getMetaAccess(), context.getStampProvider(), null, context.getConstantReflection(), graphBuilderConfig, context.getOptimisticOptimizations(), false).run(graph);
     }
 
     public GraphBuilderConfiguration getGraphBuilderConfig() {
@@ -90,6 +90,7 @@
         private final MetaAccessProvider metaAccess;
 
         private ResolvedJavaMethod rootMethod;
+        private final boolean rootMethodIsReplacement;
 
         private final GraphBuilderConfiguration graphBuilderConfig;
         private final OptimisticOptimizations optimisticOpts;
@@ -105,19 +106,20 @@
         }
 
         public Instance(MetaAccessProvider metaAccess, StampProvider stampProvider, SnippetReflectionProvider snippetReflectionProvider, ConstantReflectionProvider constantReflection,
-                        GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts) {
+                        GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts, boolean rootMethodIsReplacement) {
             this.graphBuilderConfig = graphBuilderConfig;
             this.optimisticOpts = optimisticOpts;
             this.metaAccess = metaAccess;
             this.stampProvider = stampProvider;
             this.constantReflection = constantReflection;
             this.snippetReflectionProvider = snippetReflectionProvider;
+            this.rootMethodIsReplacement = rootMethodIsReplacement;
             assert metaAccess != null;
         }
 
         public Instance(MetaAccessProvider metaAccess, StampProvider stampProvider, ConstantReflectionProvider constantReflection, GraphBuilderConfiguration graphBuilderConfig,
-                        OptimisticOptimizations optimisticOpts) {
-            this(metaAccess, stampProvider, null, constantReflection, graphBuilderConfig, optimisticOpts);
+                        OptimisticOptimizations optimisticOpts, boolean rootMethodIsReplacement) {
+            this(metaAccess, stampProvider, null, constantReflection, graphBuilderConfig, optimisticOpts, rootMethodIsReplacement);
         }
 
         @Override
@@ -131,8 +133,8 @@
             frameState.initializeForMethodStart(graphBuilderConfig.eagerResolving(), this.graphBuilderConfig.getParameterPlugin());
             TTY.Filter filter = new TTY.Filter(PrintFilter.getValue(), method);
             try {
-                BytecodeParser parser = new BytecodeParser(metaAccess, method, graphBuilderConfig, optimisticOpts, entryBCI, false);
-                parser.build(0, graph.start(), frameState);
+                BytecodeParser parser = new BytecodeParser(null, metaAccess, method, graphBuilderConfig, optimisticOpts, entryBCI, rootMethodIsReplacement);
+                parser.build(graph.start(), frameState);
 
                 parser.connectLoopEndToBegin();
 
@@ -177,7 +179,7 @@
             private BciBlockMapping blockMap;
             private LocalLiveness liveness;
             protected final int entryBCI;
-            private int currentDepth;
+            private final BytecodeParser parent;
 
             private LineNumberTable lnt;
             private int previousLineNumber;
@@ -206,10 +208,11 @@
              *            implements the semantics of another method (i.e., an intrinsic) or
              *            bytecode instruction (i.e., a snippet)
              */
-            public BytecodeParser(MetaAccessProvider metaAccess, ResolvedJavaMethod method, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts, int entryBCI,
-                            boolean isReplacement) {
+            public BytecodeParser(BytecodeParser parent, MetaAccessProvider metaAccess, ResolvedJavaMethod method, GraphBuilderConfiguration graphBuilderConfig,
+                            OptimisticOptimizations optimisticOpts, int entryBCI, boolean isReplacement) {
                 super(metaAccess, method, graphBuilderConfig, optimisticOpts, isReplacement);
                 this.entryBCI = entryBCI;
+                this.parent = parent;
 
                 if (graphBuilderConfig.insertNonSafepointDebugInfo()) {
                     lnt = method.getLineNumberTable();
@@ -240,8 +243,7 @@
                 return this.beforeUnwindNode;
             }
 
-            protected void build(int depth, FixedWithNextNode startInstruction, HIRFrameStateBuilder startFrameState) {
-                this.currentDepth = depth;
+            protected void build(FixedWithNextNode startInstruction, HIRFrameStateBuilder startFrameState) {
                 if (PrintProfilingInformation.getValue() && profilingInfo != null) {
                     TTY.println("Profiling info for " + method.format("%H.%n(%p)"));
                     TTY.println(MetaUtil.indent(profilingInfo.toString(method, CodeUtil.NEW_LINE), "  "));
@@ -851,14 +853,14 @@
 
                 if (tryInvocationPlugin(args, targetMethod, resultType)) {
                     if (GraalOptions.TraceInlineDuringParsing.getValue()) {
-                        TTY.println(format("%sUsed invocation plugin for %s", nSpaces(currentDepth), targetMethod));
+                        TTY.println(format("%sUsed invocation plugin for %s", nSpaces(getDepth()), targetMethod));
                     }
                     return;
                 }
 
                 if (tryAnnotatedInvocationPlugin(args, targetMethod)) {
                     if (GraalOptions.TraceInlineDuringParsing.getValue()) {
-                        TTY.println(format("%sUsed annotated invocation plugin for %s", nSpaces(currentDepth), targetMethod));
+                        TTY.println(format("%sUsed annotated invocation plugin for %s", nSpaces(getDepth()), targetMethod));
                     }
                     return;
                 }
@@ -922,14 +924,14 @@
                 if (plugin == null || !invokeKind.isDirect() || !targetMethod.canBeInlined()) {
                     return false;
                 }
-                ResolvedJavaMethod inlinedMethod = plugin.getInlinedMethod(this, targetMethod, args, returnType, currentDepth);
-                if (inlinedMethod != null && inlinedMethod.hasBytecodes()) {
+                ResolvedJavaMethod inlinedMethod = plugin.getInlinedMethod(this, targetMethod, args, returnType);
+                if (inlinedMethod != null) {
                     if (TraceInlineDuringParsing.getValue()) {
                         int bci = this.bci();
                         StackTraceElement ste = this.method.asStackTraceElement(bci);
-                        TTY.println(format("%s%s (%s:%d) inlining call to %s", nSpaces(currentDepth), method.getName(), ste.getFileName(), ste.getLineNumber(), inlinedMethod.format("%h.%n(%p)")));
+                        TTY.println(format("%s%s (%s:%d) inlining call to %s", nSpaces(getDepth()), method.getName(), ste.getFileName(), ste.getLineNumber(), inlinedMethod.format("%h.%n(%p)")));
                     }
-                    parseAndInlineCallee(inlinedMethod, args, parsingReplacement || !inlinedMethod.equals(targetMethod));
+                    parseAndInlineCallee(inlinedMethod, args, parsingReplacement || inlinedMethod != targetMethod);
                     plugin.postInline(inlinedMethod);
                     return true;
                 }
@@ -938,7 +940,7 @@
             }
 
             private void parseAndInlineCallee(ResolvedJavaMethod targetMethod, ValueNode[] args, boolean isReplacement) {
-                BytecodeParser parser = new BytecodeParser(metaAccess, targetMethod, graphBuilderConfig, optimisticOpts, INVOCATION_ENTRY_BCI, isReplacement);
+                BytecodeParser parser = new BytecodeParser(this, metaAccess, targetMethod, graphBuilderConfig, optimisticOpts, INVOCATION_ENTRY_BCI, isReplacement);
                 final FrameState[] lazyFrameState = new FrameState[1];
 
                 // Replacements often produce nodes with an illegal kind (e.g., pointer stamps)
@@ -953,7 +955,7 @@
                     return lazyFrameState[0];
                 });
                 startFrameState.initializeFromArgumentsArray(args);
-                parser.build(currentDepth + 1, this.lastInstr, startFrameState);
+                parser.build(this.lastInstr, startFrameState);
 
                 FixedWithNextNode calleeBeforeReturnNode = parser.getBeforeReturnNode();
                 this.lastInstr = calleeBeforeReturnNode;
@@ -1007,7 +1009,7 @@
             @Override
             protected void genReturn(ValueNode x) {
 
-                if (this.currentDepth == 0) {
+                if (parent == null) {
                     frameState.setRethrowException(false);
                     frameState.clearStack();
                     beforeReturn(x);
@@ -1515,7 +1517,7 @@
                         this.returnValue = x;
                         this.beforeReturnNode = this.lastInstr;
                     } else if (block == blockMap.getUnwindBlock()) {
-                        if (currentDepth == 0) {
+                        if (parent == null) {
                             frameState.setRethrowException(false);
                             createUnwind();
                         } else {
@@ -1684,7 +1686,7 @@
                     int opcode = stream.currentBC();
                     assert traceState();
                     assert traceInstruction(bci, opcode, bci == block.startBci);
-                    if (currentDepth == 0 && bci == entryBCI) {
+                    if (parent == null && bci == entryBCI) {
                         if (block.getJsrScope() != JsrScope.EMPTY_SCOPE) {
                             throw new BailoutException("OSR into a JSR scope is not supported");
                         }
@@ -1831,7 +1833,7 @@
                             boolean genConditional = false;
                             if (gotoOrFallThroughAfterConstant(trueBlock) && gotoOrFallThroughAfterConstant(falseBlock) && trueBlock.getSuccessor(0) == falseBlock.getSuccessor(0)) {
                                 genConditional = true;
-                            } else if (this.currentDepth != 0 && returnAfterConstant(trueBlock) && returnAfterConstant(falseBlock)) {
+                            } else if (parent != null && returnAfterConstant(trueBlock) && returnAfterConstant(falseBlock)) {
                                 genReturn = true;
                                 genConditional = true;
                             }
@@ -1934,6 +1936,7 @@
             }
 
             public StructuredGraph getGraph() {
+
                 return currentGraph;
             }
 
@@ -1941,9 +1944,28 @@
                 return (GuardingNode) getFirstInstruction(currentBlock, getCurrentDimension());
             }
 
+            public GraphBuilderContext getParent() {
+                return parent;
+            }
+
+            public int getDepth() {
+                return parent == null ? 0 : 1 + parent.getDepth();
+            }
+
             @Override
             public String toString() {
-                return method.format("%H.%n(%p)@") + bci();
+                Formatter fmt = new Formatter();
+                BytecodeParser bp = this;
+                String indent = "";
+                while (bp != null) {
+                    if (bp != this) {
+                        fmt.format("%n%s", indent);
+                    }
+                    fmt.format("%s replacement=%s", bp.method.asStackTraceElement(bp.bci()), parsingReplacement);
+                    bp = bp.parent;
+                    indent += " ";
+                }
+                return fmt.toString();
             }
         }
     }
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPlugin.java	Thu Feb 19 13:25:23 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPlugin.java	Thu Feb 19 15:40:17 2015 +0100
@@ -55,20 +55,27 @@
     }
 
     /**
-     * Plugin for customizing how the graph builder handles a CHECKCAST instruction in the context
-     * of the instruction that consumes it from the stack.
+     * Plugin for specifying what is inlined during graph parsing.
      */
-    public interface CheckCastPlugin extends GraphBuilderPlugin {
-        boolean apply(GraphBuilderContext builder, ResolvedJavaType type, ValueNode object, JavaTypeProfile profileForTypeCheck);
-    }
+    public interface InlineInvokePlugin extends GraphBuilderPlugin {
 
-    public interface InlineInvokePlugin extends GraphBuilderPlugin {
+        /**
+         * Gets the method to be inlined for a call to a given method. A non-null return value other
+         * than {@code method} is interpreted as a
+         * {@linkplain GraphBuilderContext#parsingReplacement() replacement} by the graph builder
+         * context used for inlining it.
+         *
+         * @param method the target method of an invoke
+         * @param args the arguments to the invoke
+         * @param returnType the return type derived from {@code method}'s signature
+         * @return the method to inline for a call to {@code method} or null if the call should not
+         *         be inlined
+         */
+        ResolvedJavaMethod getInlinedMethod(GraphBuilderContext builder, ResolvedJavaMethod method, ValueNode[] args, JavaType returnType);
 
         default void postInline(@SuppressWarnings("unused") ResolvedJavaMethod inlinedTargetMethod) {
 
         }
-
-        ResolvedJavaMethod getInlinedMethod(GraphBuilderContext builder, ResolvedJavaMethod method, ValueNode[] args, JavaType returnType, int depth);
     }
 
     public interface LoopExplosionPlugin extends GraphBuilderPlugin {
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Thu Feb 19 13:25:23 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Thu Feb 19 15:40:17 2015 +0100
@@ -638,7 +638,7 @@
 
         protected Instance createGraphBuilder(MetaAccessProvider metaAccess, StampProvider stampProvider, ConstantReflectionProvider constantReflection, GraphBuilderConfiguration graphBuilderConfig,
                         OptimisticOptimizations optimisticOpts) {
-            return new GraphBuilderPhase.Instance(metaAccess, stampProvider, constantReflection, graphBuilderConfig, optimisticOpts);
+            return new GraphBuilderPhase.Instance(metaAccess, stampProvider, constantReflection, graphBuilderConfig, optimisticOpts, true);
         }
 
         protected void afterParsing(StructuredGraph graph) {
--- a/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java	Thu Feb 19 13:25:23 2015 +0100
+++ b/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java	Thu Feb 19 15:40:17 2015 +0100
@@ -191,7 +191,7 @@
         LIRSuites lirSuites = suitesProvider.createLIRSuites();
         removeInliningPhase(suites);
         StructuredGraph graph = new StructuredGraph(javaMethod, AllowAssumptions.NO);
-        new GraphBuilderPhase.Instance(metaAccess, providers.getStampProvider(), providers.getConstantReflection(), GraphBuilderConfiguration.getEagerDefault(), OptimisticOptimizations.ALL).apply(graph);
+        new GraphBuilderPhase.Instance(metaAccess, providers.getStampProvider(), providers.getConstantReflection(), GraphBuilderConfiguration.getEagerDefault(), OptimisticOptimizations.ALL, false).apply(graph);
         PhaseSuite<HighTierContext> graphBuilderSuite = getGraphBuilderSuite(suitesProvider);
         CallingConvention cc = getCallingConvention(providers.getCodeCache(), Type.JavaCallee, graph.method(), false);
         Backend backend = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend();
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Thu Feb 19 13:25:23 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Thu Feb 19 15:40:17 2015 +0100
@@ -195,7 +195,7 @@
             this.replacements = replacements;
         }
 
-        public ResolvedJavaMethod getInlinedMethod(GraphBuilderContext builder, ResolvedJavaMethod original, ValueNode[] arguments, JavaType returnType, int depth) {
+        public ResolvedJavaMethod getInlinedMethod(GraphBuilderContext builder, ResolvedJavaMethod original, ValueNode[] arguments, JavaType returnType) {
             if (original.getAnnotation(TruffleBoundary.class) != null) {
                 return null;
             }
@@ -250,7 +250,8 @@
         newConfig.setInlineInvokePlugin(new InlineInvokePlugin(callTarget.getInlining(), providers.getReplacements()));
         newConfig.setLoopExplosionPlugin(new LoopExplosionPlugin());
         TruffleGraphBuilderPlugins.registerInvocationPlugins(providers.getMetaAccess(), newConfig.getInvocationPlugins());
-        new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), this.snippetReflection, providers.getConstantReflection(), newConfig, TruffleCompilerImpl.Optimizations).apply(graph);
+        new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), this.snippetReflection, providers.getConstantReflection(), newConfig,
+                        TruffleCompilerImpl.Optimizations, false).apply(graph);
         Debug.dump(graph, "After FastPE");
 
         for (MethodCallTargetNode methodCallTargetNode : graph.getNodes(MethodCallTargetNode.TYPE)) {
@@ -320,13 +321,13 @@
     }
 
     public StructuredGraph createRootGraph(StructuredGraph graph) {
-        new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), providers.getConstantReflection(), configForRoot, TruffleCompilerImpl.Optimizations).apply(graph);
+        new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), providers.getConstantReflection(), configForRoot, TruffleCompilerImpl.Optimizations, false).apply(graph);
         return graph;
     }
 
     public StructuredGraph createInlineGraph(String name, StructuredGraph caller) {
         StructuredGraph graph = new StructuredGraph(name, callInlinedMethod, AllowAssumptions.from(caller.getAssumptions() != null));
-        new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), providers.getConstantReflection(), configForRoot, TruffleCompilerImpl.Optimizations).apply(graph);
+        new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), providers.getConstantReflection(), configForRoot, TruffleCompilerImpl.Optimizations, false).apply(graph);
         return graph;
     }
 
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCacheImpl.java	Thu Feb 19 13:25:23 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCacheImpl.java	Thu Feb 19 15:40:17 2015 +0100
@@ -269,7 +269,7 @@
     }
 
     protected StructuredGraph parseGraph(StructuredGraph graph, final PhaseContext phaseContext) {
-        new GraphBuilderPhase.Instance(phaseContext.getMetaAccess(), phaseContext.getStampProvider(), null, config, optimisticOptimizations).apply(graph);
+        new GraphBuilderPhase.Instance(phaseContext.getMetaAccess(), phaseContext.getStampProvider(), null, config, optimisticOptimizations, false).apply(graph);
         return graph;
     }