changeset 19368:4d9ff841882c

Merge.
author Thomas Wuerthinger <thomas.wuerthinger@oracle.com>
date Fri, 13 Feb 2015 23:45:16 +0100
parents f9ccdf258dd4 (diff) afe80ca4b0f0 (current diff)
children aac293bfdced
files
diffstat 13 files changed, 215 insertions(+), 78 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/BciBlockMapping.java	Fri Feb 13 17:42:58 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/BciBlockMapping.java	Fri Feb 13 23:45:16 2015 +0100
@@ -84,6 +84,7 @@
         public int loopId;
         public int loopEnd;
         protected List<BciBlock> successors;
+        private int predecessorCount;
 
         private FixedWithNextNode firstInstruction;
         private AbstractFrameStateBuilder<?, ?> entryState;
@@ -127,6 +128,10 @@
             return id;
         }
 
+        public int getPredecessorCount() {
+            return this.predecessorCount;
+        }
+
         public int numNormalSuccessors() {
             if (exceptionDispatchBlock() != null) {
                 return successors.size() - 1;
@@ -391,6 +396,18 @@
         public void setId(int i) {
             this.id = i;
         }
+
+        public void addSuccessor(BciBlock sux) {
+            successors.add(sux);
+            sux.predecessorCount++;
+        }
+
+        public void clearSucccessors() {
+            for (BciBlock sux : successors) {
+                sux.predecessorCount--;
+            }
+            successors.clear();
+        }
     }
 
     public static class ExceptionDispatchBlock extends BciBlock {
@@ -421,6 +438,7 @@
     public LocalLiveness liveness;
     private int blocksNotYetAssignedId;
     private final boolean consecutiveLoopBlocks;
+    public int returnCount;
 
     /**
      * Creates a new BlockMap instance from bytecode of the given method .
@@ -441,6 +459,10 @@
         return this.blocks;
     }
 
+    public int getReturnCount() {
+        return this.returnCount;
+    }
+
     /**
      * Builds the block map and conservative CFG and numbers blocks.
      */
@@ -527,6 +549,7 @@
                 case DRETURN: // fall through
                 case ARETURN: // fall through
                 case RETURN: {
+                    returnCount++;
                     current = null;
                     break;
                 }
@@ -653,11 +676,13 @@
             blocksNotYetAssignedId++;
             newBlock.startBci = startBci;
             newBlock.endBci = oldBlock.endBci;
-            newBlock.getSuccessors().addAll(oldBlock.getSuccessors());
+            for (BciBlock oldSuccessor : oldBlock.getSuccessors()) {
+                newBlock.addSuccessor(oldSuccessor);
+            }
 
             oldBlock.endBci = startBci - 1;
-            oldBlock.getSuccessors().clear();
-            oldBlock.getSuccessors().add(newBlock);
+            oldBlock.clearSucccessors();
+            oldBlock.addSuccessor(newBlock);
 
             for (int i = startBci; i <= newBlock.endBci; i++) {
                 blockMap[i] = newBlock;
@@ -686,7 +711,7 @@
         if (sux.isExceptionEntry) {
             throw new BailoutException("Exception handler can be reached by both normal and exceptional control flow");
         }
-        predecessor.getSuccessors().add(sux);
+        predecessor.addSuccessor(sux);
     }
 
     private final ArrayList<BciBlock> jsrVisited = new ArrayList<>();
@@ -697,7 +722,7 @@
 
         if (block.endsWithRet()) {
             block.setRetSuccessor(blockMap[scope.nextReturnAddress()]);
-            block.getSuccessors().add(block.getRetSuccessor());
+            block.addSuccessor(block.getRetSuccessor());
             assert block.getRetSuccessor() != block.getJsrSuccessor();
         }
         Debug.log("JSR alternatives block %s  sux %s  jsrSux %s  retSux %s  jsrScope %s", block, block.getSuccessors(), block.getJsrSuccessor(), block.getRetSuccessor(), block.getJsrScope());
@@ -766,9 +791,9 @@
                     curHandler.endBci = -1;
                     curHandler.deoptBci = bci;
                     curHandler.handler = h;
-                    curHandler.getSuccessors().add(blockMap[h.getHandlerBCI()]);
+                    curHandler.addSuccessor(blockMap[h.getHandlerBCI()]);
                     if (lastHandler != null) {
-                        curHandler.getSuccessors().add(lastHandler);
+                        curHandler.addSuccessor(lastHandler);
                     }
                     exceptionDispatch.put(h, curHandler);
                 }
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Fri Feb 13 17:42:58 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Fri Feb 13 23:45:16 2015 +0100
@@ -204,6 +204,8 @@
             private final boolean explodeLoops;
             private Stack<ExplodedLoopContext> explodeLoopsContext;
             private int nextPeelIteration = 1;
+            private int returnCount;
+            private boolean controlFlowSplit;
 
             public BytecodeParser(MetaAccessProvider metaAccess, ResolvedJavaMethod method, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts, int entryBCI) {
                 super(metaAccess, method, graphBuilderConfig, optimisticOpts);
@@ -251,6 +253,7 @@
                     BciBlockMapping blockMap = BciBlockMapping.create(method, graphBuilderConfig.doLivenessAnalysis(), explodeLoops);
                     loopHeaders = blockMap.getLoopHeaders();
                     liveness = blockMap.liveness;
+                    returnCount = blockMap.getReturnCount();
 
                     lastInstr = startInstruction;
                     this.setCurrentFrameState(startFrameState);
@@ -282,7 +285,7 @@
                     currentBlock = blockMap.startBlock;
                     blockMap.startBlock.setEntryState(0, frameState);
                     if (blockMap.startBlock.isLoopHeader && !explodeLoops) {
-                        appendGoto(createTarget(blockMap.startBlock, frameState));
+                        appendGoto(blockMap.startBlock);
                     } else {
                         blockMap.startBlock.setFirstInstruction(0, lastInstr);
                     }
@@ -500,6 +503,7 @@
                     dispatchBegin.setStateAfter(dispatchState.create(bci));
                     dispatchState.setRethrowException(true);
                 }
+                this.controlFlowSplit = true;
                 FixedNode target = createTarget(dispatchBlock, dispatchState);
                 FixedWithNextNode finishedDispatch = finishInstruction(dispatchBegin, dispatchState);
                 finishedDispatch.setNext(target);
@@ -613,22 +617,22 @@
 
             @Override
             protected ValueNode genNarrow(ValueNode input, int bitCount) {
-                return new NarrowNode(input, bitCount);
+                return NarrowNode.create(input, bitCount);
             }
 
             @Override
             protected ValueNode genSignExtend(ValueNode input, int bitCount) {
-                return new SignExtendNode(input, bitCount);
+                return SignExtendNode.create(input, bitCount);
             }
 
             @Override
             protected ValueNode genZeroExtend(ValueNode input, int bitCount) {
-                return new ZeroExtendNode(input, bitCount);
+                return ZeroExtendNode.create(input, bitCount);
             }
 
             @Override
             protected void genGoto() {
-                appendGoto(createTarget(currentBlock.getSuccessors().get(0), frameState));
+                appendGoto(currentBlock.getSuccessor(0));
                 assert currentBlock.numNormalSuccessors() == 1;
             }
 
@@ -870,7 +874,6 @@
                         return;
                     }
                 }
-
                 InlineInvokePlugin inlineInvokePlugin = graphBuilderConfig.getInlineInvokePlugin();
                 if (inlineInvokePlugin != null && invokeKind.isDirect() && targetMethod.canBeInlined() && targetMethod.hasBytecodes() &&
                                 inlineInvokePlugin.shouldInlineInvoke(targetMethod, currentDepth)) {
@@ -884,10 +887,10 @@
                         TTY.print(s);
                         TTY.println(" inlining call " + targetMethod.getName());
                     }
-                    parseAndInlineCallee(targetMethod, args);
+
+                    ResolvedJavaMethod inlinedTargetMethod = inlineInvokePlugin.inlinedMethod(this, targetMethod, args);
+                    parseAndInlineCallee(inlinedTargetMethod, args);
                     return;
-                } else {
-                    // System.out.println("Could not inline invoke " + targetMethod);
                 }
 
                 MethodCallTargetNode callTarget = currentGraph.add(createMethodCallTarget(invokeKind, targetMethod, args, returnType));
@@ -1004,10 +1007,18 @@
                     beforeReturn(x);
                     append(new ReturnNode(x));
                 } else {
-                    if (x != null) {
-                        frameState.push(x.getKind(), x);
+                    if (returnCount == 1 || !controlFlowSplit) {
+                        // There is only a single return.
+                        this.returnValue = x;
+                        this.beforeReturnNode = this.lastInstr;
+                        this.lastInstr = null;
+                    } else {
+                        if (x != null) {
+                            frameState.push(x.getKind(), x);
+                        }
+                        assert returnCount > 1;
+                        appendGoto(returnBlock(bci()));
                     }
-                    appendGoto(createTarget(returnBlock(bci()), frameState));
                 }
             }
 
@@ -1055,7 +1066,7 @@
                 }
                 ConstantNode nextBciNode = getJsrConstant(nextBci);
                 frameState.push(Kind.Int, nextBciNode);
-                appendGoto(createTarget(successor, frameState));
+                appendGoto(successor);
             }
 
             @Override
@@ -1071,7 +1082,7 @@
                 if (!successor.getJsrScope().equals(scope.pop())) {
                     throw new JsrNotSupportedBailout("unstructured control flow (ret leaves more than one scope)");
                 }
-                appendGoto(createTarget(successor, frameState));
+                appendGoto(successor);
             }
 
             private ConstantNode getJsrConstant(long bci) {
@@ -1083,6 +1094,7 @@
 
             @Override
             protected void genIntegerSwitch(ValueNode value, ArrayList<BciBlock> actualSuccessors, int[] keys, double[] keyProbabilities, int[] keySuccessors) {
+                this.controlFlowSplit = true;
                 double[] successorProbabilities = successorProbabilites(actualSuccessors.size(), keySuccessors, keyProbabilities);
                 IntegerSwitchNode switchNode = append(new IntegerSwitchNode(value, actualSuccessors.size(), keys, keyProbabilities, keySuccessors));
                 for (int i = 0; i < actualSuccessors.size(); i++) {
@@ -1191,7 +1203,7 @@
                                 firstLoopExit = loopExit;
                             }
                             lastLoopExit = loopExit;
-                            Debug.log("Target %s (%s) Exits %s, scanning framestates...", targetBlock, target, loop);
+                            Debug.log("Target %s Exits %s, scanning framestates...", targetBlock, loop);
                             newState.insertLoopProxies(loopExit, (HIRFrameStateBuilder) loop.getEntryState(this.getCurrentDimension()));
                             loopExit.setStateAfter(newState.create(bci));
                         }
@@ -1214,6 +1226,10 @@
             }
 
             private FixedNode createTarget(BciBlock block, HIRFrameStateBuilder state) {
+                return createTarget(block, state, false);
+            }
+
+            private FixedNode createTarget(BciBlock block, HIRFrameStateBuilder state, boolean isGoto) {
                 assert block != null && state != null;
                 assert !block.isExceptionEntry || state.stackSize() == 1;
 
@@ -1258,7 +1274,13 @@
                      * this block again.
                      */
                     FixedNode targetNode;
-                    block.setFirstInstruction(operatingDimension, currentGraph.add(new BeginNode()));
+                    if (isGoto && (block.getPredecessorCount() == 1 || !controlFlowSplit) && !block.isLoopHeader && (currentBlock.loops & ~block.loops) == 0 &&
+                                    !(lastInstr instanceof AbstractMergeNode)) {
+                        block.setFirstInstruction(operatingDimension, lastInstr);
+                        lastInstr = null;
+                    } else {
+                        block.setFirstInstruction(operatingDimension, currentGraph.add(new BeginNode()));
+                    }
                     targetNode = block.getFirstInstruction(operatingDimension);
                     Target target = checkLoopExit(targetNode, block, state);
                     FixedNode result = target.fixed;
@@ -1445,7 +1467,7 @@
                 assert frameState.stackSize() == 1 : frameState;
                 if (block.handler.isCatchAll()) {
                     assert block.getSuccessorCount() == 1;
-                    appendGoto(createTarget(block.getSuccessor(0), frameState));
+                    appendGoto(block.getSuccessor(0));
                     return;
                 }
 
@@ -1485,9 +1507,10 @@
                 }
             }
 
-            private void appendGoto(FixedNode target) {
-                if (lastInstr != null) {
-                    lastInstr.setNext(target);
+            private void appendGoto(BciBlock successor) {
+                FixedNode targetInstr = createTarget(successor, frameState, true);
+                if (lastInstr != null && lastInstr != targetInstr) {
+                    lastInstr.setNext(targetInstr);
                 }
             }
 
@@ -1500,6 +1523,7 @@
                 if (block.isLoopHeader && !explodeLoops) {
                     // Create the loop header block, which later will merge the backward branches of
                     // the loop.
+                    controlFlowSplit = true;
                     AbstractEndNode preLoopEnd = currentGraph.add(new EndNode());
                     LoopBeginNode loopBegin = currentGraph.add(new LoopBeginNode());
                     lastInstr.setNext(preLoopEnd);
@@ -1585,7 +1609,7 @@
                             assert !block.getSuccessor(0).isExceptionEntry;
                             assert block.numNormalSuccessors() == 1;
                             // we fell through to the next block, add a goto and break
-                            appendGoto(createTarget(block.getSuccessor(0), frameState));
+                            appendGoto(block.getSuccessor(0));
                             break;
                         }
                     }
@@ -1633,11 +1657,11 @@
             protected void genIf(ValueNode x, Condition cond, ValueNode y) {
                 // assert !x.isDeleted() && !y.isDeleted();
                 // assert currentBlock.numNormalSuccessors() == 2;
-                assert currentBlock.getSuccessors().size() == 2;
-                BciBlock trueBlock = currentBlock.getSuccessors().get(0);
-                BciBlock falseBlock = currentBlock.getSuccessors().get(1);
+                assert currentBlock.getSuccessorCount() == 2;
+                BciBlock trueBlock = currentBlock.getSuccessor(0);
+                BciBlock falseBlock = currentBlock.getSuccessor(1);
                 if (trueBlock == falseBlock) {
-                    appendGoto(createTarget(trueBlock, frameState));
+                    appendGoto(trueBlock);
                     return;
                 }
 
@@ -1674,8 +1698,10 @@
                     if (value) {
                         nextBlock = trueBlock;
                     }
-                    appendGoto(createTarget(nextBlock, frameState));
+                    appendGoto(nextBlock);
                 } else {
+
+                    this.controlFlowSplit = true;
                     ValueNode trueSuccessor = createBlockTarget(probability, trueBlock, frameState);
                     ValueNode falseSuccessor = createBlockTarget(1 - probability, falseBlock, frameState);
 
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPlugins.java	Fri Feb 13 17:42:58 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPlugins.java	Fri Feb 13 23:45:16 2015 +0100
@@ -54,6 +54,10 @@
     }
 
     public interface InlineInvokePlugin extends GraphBuilderPlugin {
+        default ResolvedJavaMethod inlinedMethod(@SuppressWarnings("unused") GraphBuilderContext builder, ResolvedJavaMethod original, @SuppressWarnings("unused") ValueNode[] arguments) {
+            return original;
+        }
+
         boolean shouldInlineInvoke(ResolvedJavaMethod method, int depth);
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerConvertNode.java	Fri Feb 13 17:42:58 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerConvertNode.java	Fri Feb 13 23:45:16 2015 +0100
@@ -86,13 +86,20 @@
 
     @Override
     public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
+        ValueNode synonym = findSynonym(getOp(forValue), forValue, inputBits, resultBits, stamp());
+        if (synonym != null) {
+            return synonym;
+        }
+        return this;
+    }
+
+    protected static <T> ValueNode findSynonym(IntegerConvertOp<T> operation, ValueNode value, int inputBits, int resultBits, Stamp stamp) {
         if (inputBits == resultBits) {
             return value;
         } else if (value.isConstant()) {
-            return ConstantNode.forPrimitive(stamp(), convert(forValue.asConstant(), tool.getConstantReflection()));
-        } else {
-            return this;
+            return ConstantNode.forPrimitive(stamp, operation.foldConstant(inputBits, resultBits, value.asConstant()));
         }
+        return null;
     }
 
     public static ValueNode convert(ValueNode input, Stamp stamp) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NarrowNode.java	Fri Feb 13 17:42:58 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NarrowNode.java	Fri Feb 13 23:45:16 2015 +0100
@@ -23,6 +23,7 @@
 package com.oracle.graal.nodes.calc;
 
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.compiler.common.type.ArithmeticOpTable.*;
 import com.oracle.graal.compiler.common.type.ArithmeticOpTable.IntegerConvertOp.Narrow;
 import com.oracle.graal.compiler.common.type.ArithmeticOpTable.IntegerConvertOp.SignExtend;
 import com.oracle.graal.graph.spi.*;
@@ -46,6 +47,20 @@
         super(ArithmeticOpTable::getNarrow, ArithmeticOpTable::getSignExtend, inputBits, resultBits, input);
     }
 
+    public static ValueNode create(ValueNode input, int resultBits) {
+        return create(input, PrimitiveStamp.getBits(input.stamp()), resultBits);
+    }
+
+    public static ValueNode create(ValueNode input, int inputBits, int resultBits) {
+        IntegerConvertOp<Narrow> signExtend = ArithmeticOpTable.forStamp(input.stamp()).getNarrow();
+        ValueNode synonym = findSynonym(signExtend, input, inputBits, resultBits, signExtend.foldStamp(inputBits, resultBits, input.stamp()));
+        if (synonym != null) {
+            return synonym;
+        } else {
+            return new NarrowNode(input, inputBits, resultBits);
+        }
+    }
+
     @Override
     public boolean isLossless() {
         return false;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/SignExtendNode.java	Fri Feb 13 17:42:58 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/SignExtendNode.java	Fri Feb 13 23:45:16 2015 +0100
@@ -23,6 +23,7 @@
 package com.oracle.graal.nodes.calc;
 
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.compiler.common.type.ArithmeticOpTable.IntegerConvertOp;
 import com.oracle.graal.compiler.common.type.ArithmeticOpTable.IntegerConvertOp.Narrow;
 import com.oracle.graal.compiler.common.type.ArithmeticOpTable.IntegerConvertOp.SignExtend;
 import com.oracle.graal.graph.spi.*;
@@ -46,6 +47,20 @@
         super(ArithmeticOpTable::getSignExtend, ArithmeticOpTable::getNarrow, inputBits, resultBits, input);
     }
 
+    public static ValueNode create(ValueNode input, int resultBits) {
+        return create(input, PrimitiveStamp.getBits(input.stamp()), resultBits);
+    }
+
+    public static ValueNode create(ValueNode input, int inputBits, int resultBits) {
+        IntegerConvertOp<SignExtend> signExtend = ArithmeticOpTable.forStamp(input.stamp()).getSignExtend();
+        ValueNode synonym = findSynonym(signExtend, input, inputBits, resultBits, signExtend.foldStamp(inputBits, resultBits, input.stamp()));
+        if (synonym != null) {
+            return synonym;
+        } else {
+            return new SignExtendNode(input, inputBits, resultBits);
+        }
+    }
+
     @Override
     public boolean isLossless() {
         return true;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ZeroExtendNode.java	Fri Feb 13 17:42:58 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ZeroExtendNode.java	Fri Feb 13 23:45:16 2015 +0100
@@ -25,8 +25,8 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.compiler.common.type.ArithmeticOpTable.IntegerConvertOp.Narrow;
-import com.oracle.graal.compiler.common.type.ArithmeticOpTable.IntegerConvertOp.ZeroExtend;
+import com.oracle.graal.compiler.common.type.ArithmeticOpTable.*;
+import com.oracle.graal.compiler.common.type.ArithmeticOpTable.IntegerConvertOp.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodeinfo.*;
@@ -48,6 +48,20 @@
         super(ArithmeticOpTable::getZeroExtend, ArithmeticOpTable::getNarrow, inputBits, resultBits, input);
     }
 
+    public static ValueNode create(ValueNode input, int resultBits) {
+        return create(input, PrimitiveStamp.getBits(input.stamp()), resultBits);
+    }
+
+    public static ValueNode create(ValueNode input, int inputBits, int resultBits) {
+        IntegerConvertOp<ZeroExtend> signExtend = ArithmeticOpTable.forStamp(input.stamp()).getZeroExtend();
+        ValueNode synonym = findSynonym(signExtend, input, inputBits, resultBits, signExtend.foldStamp(inputBits, resultBits, input.stamp()));
+        if (synonym != null) {
+            return synonym;
+        } else {
+            return new ZeroExtendNode(input, inputBits, resultBits);
+        }
+    }
+
     @Override
     public boolean isLossless() {
         return true;
--- a/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java	Fri Feb 13 17:42:58 2015 +0100
+++ b/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java	Fri Feb 13 23:45:16 2015 +0100
@@ -103,7 +103,7 @@
     }
 
     private static void installOptimizedCallTargetCallDirect() {
-        if (TruffleCompilerOptions.TruffleFunctionInlining.getValue()) {
+        if (TruffleCompilerOptions.TruffleFunctionInlining.getValue() && !TruffleCompilerOptions.FastPE.getValue()) {
             ((HotSpotResolvedJavaMethod) getGraalProviders().getMetaAccess().lookupJavaMethod(OptimizedCallTarget.getCallDirectMethod())).setNotInlineable();
         }
     }
--- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/PartialEvaluationTest.java	Fri Feb 13 17:42:58 2015 +0100
+++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/PartialEvaluationTest.java	Fri Feb 13 23:45:16 2015 +0100
@@ -89,7 +89,7 @@
         compilable.call(arguments);
 
         try (Scope s = Debug.scope("TruffleCompilation", new TruffleDebugJavaMethod(compilable))) {
-            return truffleCompiler.getPartialEvaluator().createGraph(compilable, allowAssumptions, null);
+            return truffleCompiler.getPartialEvaluator().createGraph(compilable, allowAssumptions, truffleCompiler.createGraphBuilderSuitePlugins());
         } catch (Throwable e) {
             throw Debug.handle(e);
         }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Fri Feb 13 17:42:58 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Fri Feb 13 23:45:16 2015 +0100
@@ -30,6 +30,7 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.replacements.*;
+import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.debug.internal.*;
@@ -192,6 +193,36 @@
 
     private class InlineInvokePlugin implements GraphBuilderPlugins.InlineInvokePlugin {
 
+        private final TruffleInlining inlining;
+        private OptimizedDirectCallNode lastDirectCallNode;
+
+        public InlineInvokePlugin(TruffleInlining inlining) {
+            this.inlining = inlining;
+        }
+
+        public ResolvedJavaMethod inlinedMethod(GraphBuilderContext builder, ResolvedJavaMethod original, ValueNode[] arguments) {
+            if (original.equals(callSiteProxyMethod)) {
+                ValueNode arg1 = arguments[0];
+                if (!arg1.isConstant()) {
+                    GraalInternalError.shouldNotReachHere("The direct call node does not resolve to a constant!");
+                }
+
+                Object callNode = builder.getSnippetReflection().asObject(Object.class, (JavaConstant) arg1.asConstant());
+                if (callNode instanceof OptimizedDirectCallNode) {
+                    OptimizedDirectCallNode directCallNode = (OptimizedDirectCallNode) callNode;
+                    lastDirectCallNode = directCallNode;
+                }
+            } else if (original.equals(callDirectMethod)) {
+                TruffleInliningDecision decision = getDecision(inlining, lastDirectCallNode);
+                lastDirectCallNode = null;
+                if (decision != null && decision.isInline()) {
+                    builder.getAssumptions().record(new AssumptionValidAssumption((OptimizedAssumption) decision.getTarget().getNodeRewritingAssumption()));
+                    return callInlinedMethod;
+                }
+            }
+            return original;
+        }
+
         public boolean shouldInlineInvoke(ResolvedJavaMethod method, int depth) {
             return method.getAnnotation(TruffleBoundary.class) == null;
         }
@@ -211,7 +242,8 @@
         GraphBuilderConfiguration newConfig = configForRoot.copy();
         newConfig.setLoadFieldPlugin(new InterceptLoadFieldPlugin());
         newConfig.setParameterPlugin(new InterceptReceiverPlugin(callTarget));
-        newConfig.setInlineInvokePlugin(new InlineInvokePlugin());
+        callTarget.setInlining(new TruffleInlining(callTarget, new DefaultInliningPolicy()));
+        newConfig.setInlineInvokePlugin(new InlineInvokePlugin(callTarget.getInlining()));
         newConfig.setLoopExplosionPlugin(new LoopExplosionPlugin());
         DefaultGraphBuilderPlugins plugins = graalPlugins == null ? new DefaultGraphBuilderPlugins() : graalPlugins.copy();
         TruffleGraphBuilderPlugins.registerPlugins(providers.getMetaAccess(), plugins);
@@ -508,6 +540,25 @@
             return null;
         }
 
+        TruffleInliningDecision decision = getDecision(inlining, callNode);
+
+        StructuredGraph graph;
+        if (decision != null && decision.isInline()) {
+            if (inliningCache == null) {
+                graph = createInlineGraph(phaseContext, caller, null, decision);
+            } else {
+                graph = inliningCache.getCachedGraph(phaseContext, caller, decision);
+            }
+            caller.getAssumptions().record(new AssumptionValidAssumption((OptimizedAssumption) decision.getTarget().getNodeRewritingAssumption()));
+        } else {
+            // we continue expansion of callDirect until we reach the callBoundary.
+            graph = parseGraph(methodCallTargetNode.targetMethod(), methodCallTargetNode.arguments(), phaseContext);
+        }
+
+        return graph;
+    }
+
+    private static TruffleInliningDecision getDecision(TruffleInlining inlining, OptimizedDirectCallNode callNode) {
         TruffleInliningDecision decision = inlining.findByCall(callNode);
         if (decision == null) {
             if (TruffleCompilerOptions.TraceTrufflePerformanceWarnings.getValue()) {
@@ -524,25 +575,9 @@
                 properties.put("callNode", callNode);
                 TracePerformanceWarningsListener.logPerformanceWarning(String.format("CallTarget changed during compilation. Call node could not be inlined."), properties);
             }
-            decision = null;
+            return null;
         }
-
-        StructuredGraph graph;
-        if (decision != null && decision.isInline()) {
-            if (inliningCache == null) {
-                graph = createInlineGraph(phaseContext, caller, null, decision);
-            } else {
-                graph = inliningCache.getCachedGraph(phaseContext, caller, decision);
-            }
-            decision.getProfile().setGraalDeepNodeCount(graph.getNodeCount());
-
-            caller.getAssumptions().record(new AssumptionValidAssumption((OptimizedAssumption) decision.getTarget().getNodeRewritingAssumption()));
-        } else {
-            // we continue expansion of callDirect until we reach the callBoundary.
-            graph = parseGraph(methodCallTargetNode.targetMethod(), methodCallTargetNode.arguments(), phaseContext);
-        }
-
-        return graph;
+        return decision;
     }
 
     private OptimizedDirectCallNode resolveConstantCallNode(MethodCallTargetNode methodCallTargetNode) {
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java	Fri Feb 13 17:42:58 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java	Fri Feb 13 23:45:16 2015 +0100
@@ -237,4 +237,8 @@
     public PartialEvaluator getPartialEvaluator() {
         return partialEvaluator;
     }
+
+    public GraphBuilderPlugins createGraphBuilderSuitePlugins() {
+        return this.createGraphBuilderSuite().plugins;
+    }
 }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningProfile.java	Fri Feb 13 17:42:58 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningProfile.java	Fri Feb 13 23:45:16 2015 +0100
@@ -32,7 +32,6 @@
     private final double frequency;
     private final boolean recursiveCall;
 
-    private int graalDeepNodeCount = -1;
     private String failedReason;
     private int queryIndex = -1;
     private double score;
@@ -103,19 +102,7 @@
         properties.put("frequency", String.format("%8.4f", getFrequency()));
         properties.put("score", String.format("%8.4f", getScore()));
         properties.put(String.format("index=%3d, force=%s, callSites=%2d", queryIndex, (isForced() ? "Y" : "N"), getCallSites()), "");
-        if (graalDeepNodeCount != -1) {
-            properties.put("graalCount", String.format("%5d", graalDeepNodeCount));
-        }
         properties.put("reason", failedReason);
         return properties;
     }
-
-    public void setGraalDeepNodeCount(int graalDeepNodeCount) {
-        this.graalDeepNodeCount = graalDeepNodeCount;
-    }
-
-    public int getGraalDeepNodeCount() {
-        return graalDeepNodeCount;
-    }
-
 }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/TruffleGraphBuilderPlugins.java	Fri Feb 13 17:42:58 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/TruffleGraphBuilderPlugins.java	Fri Feb 13 23:45:16 2015 +0100
@@ -160,6 +160,17 @@
                 return true;
             }
         });
+        registerUnsafeCast(r);
+
+        registerUnsafeLoadStorePlugins(r, Kind.Int, Kind.Long, Kind.Float, Kind.Double, Kind.Object);
+
+        // CompilerDirectives.class
+        r = new Registration(plugins, metaAccess, UnsafeAccessImpl.class);
+        registerUnsafeCast(r);
+        registerUnsafeLoadStorePlugins(r, Kind.Boolean, Kind.Byte, Kind.Int, Kind.Short, Kind.Long, Kind.Float, Kind.Double, Kind.Object);
+    }
+
+    private static void registerUnsafeCast(Registration r) {
         r.register4("unsafeCast", Object.class, Class.class, boolean.class, boolean.class, new InvocationPlugin() {
             public boolean apply(GraphBuilderContext builder, ValueNode object, ValueNode clazz, ValueNode condition, ValueNode nonNull) {
                 if (clazz.isConstant() && nonNull.isConstant()) {
@@ -189,12 +200,6 @@
                 throw GraalInternalError.shouldNotReachHere("unsafeCast arguments could not reduce to a constant: " + clazz + ", " + nonNull);
             }
         });
-
-        registerUnsafeLoadStorePlugins(r, Kind.Int, Kind.Long, Kind.Float, Kind.Double, Kind.Object);
-
-        // CompilerDirectives.class
-        r = new Registration(plugins, metaAccess, UnsafeAccessImpl.class);
-        registerUnsafeLoadStorePlugins(r, Kind.Boolean, Kind.Byte, Kind.Int, Kind.Short, Kind.Long, Kind.Float, Kind.Double, Kind.Object);
     }
 
     protected static void registerUnsafeLoadStorePlugins(Registration r, Kind... kinds) {