changeset 15093:5634b199c4da

Truffle: API-change: renamed CallNode to DirectCallNode and added IndirectCallNode.
author Christian Humer <christian.humer@gmail.com>
date Mon, 14 Apr 2014 20:32:25 +0200
parents c73ce0dd3583
children 04703cff4ef2
files CHANGELOG.md graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotFrameInstance.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/MaterializedFrameNotify.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallNode.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTargetLog.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallUtils.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedDirectCallNode.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedIndirectCallNode.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningHandler.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningProfile.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningResult.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleTreeDumpHandler.java graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ThreadSafetyTest.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleRuntime.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameInstance.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultCallNode.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultDirectCallNode.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultIndirectCallNode.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultTruffleRuntime.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/MaterializedFrameNotify.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/CallNode.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/DirectCallNode.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/IndirectCallNode.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/RootNode.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLDirectDispatchNode.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLGenericDispatchNode.java
diffstat 28 files changed, 739 insertions(+), 553 deletions(-) [+]
line wrap: on
line diff
--- a/CHANGELOG.md	Mon Apr 14 19:11:47 2014 +0200
+++ b/CHANGELOG.md	Mon Apr 14 20:32:25 2014 +0200
@@ -12,7 +12,11 @@
 
 ### Truffle
 * Support for collecting stack traces and for accessing the current frame in slow paths
-* CallNode#inline was renamed to CallNode#forceInlining().
+* Renamed CallNode to DirectCallNode.
+* Renamed TruffleRuntime#createCallNode to TruffleRuntime#createDirectCallNode.
+* Added IndirectCallNode for calls with a changing CallTarget. 
+* Added TruffleRuntime#createIndirectCallNode to create an IndirectCallNode.
+* DirectCallNode#inline was renamed to DirectCallNode#forceInlining().
 * ...
 
 ## Version 0.2
--- a/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotFrameInstance.java	Mon Apr 14 19:11:47 2014 +0200
+++ b/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotFrameInstance.java	Mon Apr 14 20:32:25 2014 +0200
@@ -30,7 +30,6 @@
 import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.CompilerDirectives.SlowPath;
 import com.oracle.truffle.api.frame.*;
-import com.oracle.truffle.api.impl.*;
 import com.oracle.truffle.api.nodes.*;
 
 public abstract class HotSpotFrameInstance implements FrameInstance {
@@ -89,10 +88,10 @@
 
     public abstract CallTarget getTargetCallTarget();
 
-    public CallNode getCallNode() {
+    public DirectCallNode getCallNode() {
         Object receiver = stackFrame.getLocal(getNotifyIndex());
-        if (receiver instanceof CallNode) {
-            return (CallNode) receiver;
+        if (receiver instanceof DirectCallNode) {
+            return (DirectCallNode) receiver;
         } else {
             return null;
         }
@@ -100,14 +99,14 @@
 
     /**
      * This class represents a frame that is taken from the
-     * {@link OptimizedCallNode#callProxy(MaterializedFrameNotify, OptimizedCallTarget, VirtualFrame, Object[], boolean)}
+     * {@link OptimizedDirectCallNode#callProxy(MaterializedFrameNotify, CallTarget, VirtualFrame, Object[], boolean)}
      * method.
      */
     public static final class CallNodeFrame extends HotSpotFrameInstance {
         public static final Method METHOD;
         static {
             try {
-                METHOD = OptimizedCallNode.class.getDeclaredMethod("callProxy", MaterializedFrameNotify.class, OptimizedCallTarget.class, VirtualFrame.class, Object[].class, boolean.class);
+                METHOD = OptimizedDirectCallNode.class.getDeclaredMethod("callProxy", MaterializedFrameNotify.class, CallTarget.class, VirtualFrame.class, Object[].class, boolean.class);
             } catch (NoSuchMethodException | SecurityException e) {
                 throw new GraalInternalError(e);
             }
--- a/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java	Mon Apr 14 19:11:47 2014 +0200
+++ b/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java	Mon Apr 14 20:32:25 2014 +0200
@@ -92,14 +92,18 @@
         return new HotSpotOptimizedCallTarget(rootNode, truffleCompiler, TruffleMinInvokeThreshold.getValue(), TruffleCompilationThreshold.getValue(), acceptForCompilation(rootNode));
     }
 
-    public CallNode createCallNode(CallTarget target) {
+    public DirectCallNode createDirectCallNode(CallTarget target) {
         if (target instanceof OptimizedCallTarget) {
-            return OptimizedCallNode.create((OptimizedCallTarget) target);
+            return OptimizedDirectCallNode.create((OptimizedCallTarget) target);
         } else {
-            return new DefaultCallNode(target);
+            return new DefaultDirectCallNode(target);
         }
     }
 
+    public IndirectCallNode createIndirectCallNode() {
+        return new OptimizedIndirectCallNode();
+    }
+
     @Override
     public VirtualFrame createVirtualFrame(Object[] arguments, FrameDescriptor frameDescriptor) {
         return OptimizedCallTarget.createFrame(frameDescriptor, arguments);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/MaterializedFrameNotify.java	Mon Apr 14 20:32:25 2014 +0200
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.truffle;
+
+import com.oracle.truffle.api.frame.FrameInstance.*;
+
+public interface MaterializedFrameNotify {
+
+    FrameAccess getOutsideFrameAccess();
+
+    void setOutsideFrameAccess(FrameAccess outsideFrameAccess);
+}
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallNode.java	Mon Apr 14 19:11:47 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,194 +0,0 @@
-/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.truffle;
-
-import com.oracle.truffle.api.*;
-import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
-import com.oracle.truffle.api.frame.*;
-import com.oracle.truffle.api.frame.FrameInstance.*;
-import com.oracle.truffle.api.impl.*;
-import com.oracle.truffle.api.nodes.*;
-import com.oracle.truffle.api.nodes.NodeUtil.NodeCountFilter;
-
-/**
- * A call node with a constant {@link CallTarget} that can be optimized by Graal.
- */
-public final class OptimizedCallNode extends DefaultCallNode {
-
-    private int callCount;
-    private boolean trySplit = true;
-
-    @CompilationFinal private boolean inlined;
-    @CompilationFinal private OptimizedCallTarget splitCallTarget;
-
-    private OptimizedCallNode(OptimizedCallTarget target) {
-        super(target);
-    }
-
-    @Override
-    public boolean isSplittable() {
-        return getCallTarget().getRootNode().isSplittable();
-    }
-
-    @Override
-    public OptimizedCallTarget getCallTarget() {
-        return (OptimizedCallTarget) super.getCallTarget();
-    }
-
-    public int getCallCount() {
-        return callCount;
-    }
-
-    @Override
-    public OptimizedCallTarget getCurrentCallTarget() {
-        return (OptimizedCallTarget) super.getCurrentCallTarget();
-    }
-
-    @Override
-    public OptimizedCallTarget getSplitCallTarget() {
-        return splitCallTarget;
-    }
-
-    @Override
-    public Object call(VirtualFrame frame, Object[] arguments) {
-        if (CompilerDirectives.inInterpreter()) {
-            onInterpreterCall();
-        }
-        return callProxy(this, getCurrentCallTarget(), frame, arguments, inlined);
-    }
-
-    public static Object callProxy(MaterializedFrameNotify notify, OptimizedCallTarget callTarget, VirtualFrame frame, Object[] arguments, boolean inlined) {
-        try {
-            if (notify.getOutsideFrameAccess() != FrameAccess.NONE) {
-                CompilerDirectives.materialize(frame);
-            }
-            if (inlined) {
-                return callTarget.callInlined(arguments);
-            } else {
-                return callTarget.call(arguments);
-            }
-        } finally {
-            // this assertion is needed to keep the values from being cleared as non-live locals
-            assert notify != null & callTarget != null & frame != null;
-        }
-    }
-
-    private void onInterpreterCall() {
-        callCount++;
-        if (trySplit) {
-            if (callCount == 1) {
-                // on first call
-                getCurrentCallTarget().incrementKnownCallSites();
-            }
-            if (callCount > 1 && !inlined) {
-                trySplit = false;
-                if (shouldSplit()) {
-                    splitImpl(true);
-                }
-            }
-        }
-    }
-
-    /* Called by the runtime system if this CallNode is really going to be inlined. */
-    void inline() {
-        inlined = true;
-    }
-
-    @Override
-    public boolean isInlined() {
-        return inlined;
-    }
-
-    @Override
-    public boolean split() {
-        splitImpl(false);
-        return true;
-    }
-
-    private void splitImpl(boolean heuristic) {
-        CompilerAsserts.neverPartOfCompilation();
-
-        OptimizedCallTarget splitTarget = (OptimizedCallTarget) Truffle.getRuntime().createCallTarget(getCallTarget().getRootNode().split());
-        splitTarget.setSplitSource(getCallTarget());
-        if (heuristic) {
-            OptimizedCallTargetLog.logSplit(this, getCallTarget(), splitTarget);
-        }
-        if (callCount >= 1) {
-            getCallTarget().decrementKnownCallSites();
-            splitTarget.incrementKnownCallSites();
-        }
-        this.splitCallTarget = splitTarget;
-    }
-
-    private boolean shouldSplit() {
-        if (splitCallTarget != null) {
-            return false;
-        }
-        if (!TruffleCompilerOptions.TruffleSplittingEnabled.getValue()) {
-            return false;
-        }
-        if (!isSplittable()) {
-            return false;
-        }
-        OptimizedCallTarget splitTarget = getCallTarget();
-        int nodeCount = OptimizedCallUtils.countNonTrivialNodes(splitTarget, false);
-        if (nodeCount > TruffleCompilerOptions.TruffleSplittingMaxCalleeSize.getValue()) {
-            return false;
-        }
-
-        // disable recursive splitting for now
-        OptimizedCallTarget root = (OptimizedCallTarget) getRootNode().getCallTarget();
-        if (root == splitTarget || root.getSplitSource() == splitTarget) {
-            // recursive call found
-            return false;
-        }
-
-        // max one child call and callCount > 2 and kind of small number of nodes
-        if (isMaxSingleCall()) {
-            return true;
-        }
-        return countPolymorphic() >= 1;
-    }
-
-    private boolean isMaxSingleCall() {
-        return NodeUtil.countNodes(getCurrentCallTarget().getRootNode(), new NodeCountFilter() {
-            public boolean isCounted(Node node) {
-                return node instanceof CallNode;
-            }
-        }) <= 1;
-    }
-
-    private int countPolymorphic() {
-        return NodeUtil.countNodes(getCurrentCallTarget().getRootNode(), new NodeCountFilter() {
-            public boolean isCounted(Node node) {
-                NodeCost cost = node.getCost();
-                boolean polymorphic = cost == NodeCost.POLYMORPHIC || cost == NodeCost.MEGAMORPHIC;
-                return polymorphic;
-            }
-        });
-    }
-
-    public static OptimizedCallNode create(OptimizedCallTarget target) {
-        return new OptimizedCallNode(target);
-    }
-}
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTargetLog.java	Mon Apr 14 19:11:47 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTargetLog.java	Mon Apr 14 20:32:25 2014 +0200
@@ -64,8 +64,8 @@
     }
 
     private static void logInliningDecisionRecursive(TruffleInliningResult result, int depth) {
-        List<OptimizedCallNode> callNodes = searchCallNodes(result.getCallTarget());
-        for (OptimizedCallNode callNode : callNodes) {
+        List<OptimizedDirectCallNode> callNodes = searchCallNodes(result.getCallTarget());
+        for (OptimizedDirectCallNode callNode : callNodes) {
             TruffleInliningProfile profile = result.getProfiles().get(callNode);
             boolean inlined = result.isInlined(callNode);
             String msg = inlined ? "inline success" : "inline failed";
@@ -76,12 +76,12 @@
         }
     }
 
-    private static List<OptimizedCallNode> searchCallNodes(final OptimizedCallTarget target) {
-        final List<OptimizedCallNode> callNodes = new ArrayList<>();
+    private static List<OptimizedDirectCallNode> searchCallNodes(final OptimizedCallTarget target) {
+        final List<OptimizedDirectCallNode> callNodes = new ArrayList<>();
         target.getRootNode().accept(new NodeVisitor() {
             public boolean visit(Node node) {
-                if (node instanceof OptimizedCallNode) {
-                    callNodes.add((OptimizedCallNode) node);
+                if (node instanceof OptimizedDirectCallNode) {
+                    callNodes.add((OptimizedDirectCallNode) node);
                 }
                 return true;
             }
@@ -169,8 +169,8 @@
                         String msg = kind == NodeCost.MEGAMORPHIC ? "megamorphic" : "polymorphic";
                         log(0, msg, node.toString(), props);
                     }
-                    if (node instanceof CallNode) {
-                        CallNode callNode = (CallNode) node;
+                    if (node instanceof DirectCallNode) {
+                        DirectCallNode callNode = (DirectCallNode) node;
                         if (callNode.isInliningForced()) {
                             callNode.getCurrentRootNode().accept(this);
                         }
@@ -184,7 +184,7 @@
 
     private static int splitCount = 0;
 
-    static void logSplit(OptimizedCallNode callNode, OptimizedCallTarget target, OptimizedCallTarget newTarget) {
+    static void logSplit(OptimizedDirectCallNode callNode, OptimizedCallTarget target, OptimizedCallTarget newTarget) {
         if (TraceTruffleSplitting.getValue()) {
             Map<String, Object> properties = new LinkedHashMap<>();
             addASTSizeProperty(target, properties);
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallUtils.java	Mon Apr 14 19:11:47 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallUtils.java	Mon Apr 14 20:32:25 2014 +0200
@@ -30,7 +30,7 @@
     public static int countCalls(OptimizedCallTarget target) {
         return NodeUtil.countNodes(target.getRootNode(), new NodeCountFilter() {
             public boolean isCounted(Node node) {
-                return node instanceof CallNode;
+                return node instanceof DirectCallNode;
             }
         }, true);
     }
@@ -38,7 +38,7 @@
     public static int countCallsInlined(OptimizedCallTarget target) {
         return NodeUtil.countNodes(target.getRootNode(), new NodeCountFilter() {
             public boolean isCounted(Node node) {
-                return (node instanceof OptimizedCallNode) && ((OptimizedCallNode) node).isInlined();
+                return (node instanceof OptimizedDirectCallNode) && ((OptimizedDirectCallNode) node).isInlined();
             }
         }, true);
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedDirectCallNode.java	Mon Apr 14 20:32:25 2014 +0200
@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.truffle;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
+import com.oracle.truffle.api.frame.FrameInstance.FrameAccess;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.api.nodes.NodeUtil.NodeCountFilter;
+
+/**
+ * A call node with a constant {@link CallTarget} that can be optimized by Graal.
+ */
+public final class OptimizedDirectCallNode extends DirectCallNode implements MaterializedFrameNotify {
+
+    private int callCount;
+    private boolean trySplit = true;
+    private boolean inliningForced;
+
+    @CompilationFinal private boolean inlined;
+    @CompilationFinal private OptimizedCallTarget splitCallTarget;
+    @CompilationFinal private FrameAccess outsideFrameAccess = FrameAccess.NONE;
+
+    private OptimizedDirectCallNode(OptimizedCallTarget target) {
+        super(target);
+    }
+
+    @Override
+    public Object call(VirtualFrame frame, Object[] arguments) {
+        if (CompilerDirectives.inInterpreter()) {
+            onInterpreterCall();
+        }
+        return callProxy(this, getCurrentCallTarget(), frame, arguments, inlined);
+    }
+
+    public static Object callProxy(MaterializedFrameNotify notify, CallTarget callTarget, VirtualFrame frame, Object[] arguments, boolean inlined) {
+        try {
+            if (notify.getOutsideFrameAccess() != FrameAccess.NONE) {
+                CompilerDirectives.materialize(frame);
+            }
+            if (inlined) {
+                return ((OptimizedCallTarget) callTarget).callInlined(arguments);
+            } else {
+                return callTarget.call(arguments);
+            }
+        } finally {
+            // this assertion is needed to keep the values from being cleared as non-live locals
+            assert notify != null & callTarget != null & frame != null;
+        }
+    }
+
+    @Override
+    public boolean isInlinable() {
+        return true;
+    }
+
+    @Override
+    public void forceInlining() {
+        inliningForced = true;
+    }
+
+    @Override
+    public boolean isInliningForced() {
+        return inliningForced;
+    }
+
+    @Override
+    public FrameAccess getOutsideFrameAccess() {
+        return outsideFrameAccess;
+    }
+
+    @Override
+    public void setOutsideFrameAccess(FrameAccess outsideFrameAccess) {
+        this.outsideFrameAccess = outsideFrameAccess;
+    }
+
+    @Override
+    public boolean isSplittable() {
+        return getCallTarget().getRootNode().isSplittable();
+    }
+
+    @Override
+    public OptimizedCallTarget getCallTarget() {
+        return (OptimizedCallTarget) super.getCallTarget();
+    }
+
+    public int getCallCount() {
+        return callCount;
+    }
+
+    @Override
+    public OptimizedCallTarget getCurrentCallTarget() {
+        return (OptimizedCallTarget) super.getCurrentCallTarget();
+    }
+
+    @Override
+    public OptimizedCallTarget getSplitCallTarget() {
+        return splitCallTarget;
+    }
+
+    private void onInterpreterCall() {
+        callCount++;
+        if (trySplit) {
+            if (callCount == 1) {
+                // on first call
+                getCurrentCallTarget().incrementKnownCallSites();
+            }
+            if (callCount > 1 && !inlined) {
+                trySplit = false;
+                if (shouldSplit()) {
+                    splitImpl(true);
+                }
+            }
+        }
+    }
+
+    /* Called by the runtime system if this CallNode is really going to be inlined. */
+    void inline() {
+        inlined = true;
+    }
+
+    @Override
+    public boolean isInlined() {
+        return inlined;
+    }
+
+    @Override
+    public boolean split() {
+        splitImpl(false);
+        return true;
+    }
+
+    private void splitImpl(boolean heuristic) {
+        CompilerAsserts.neverPartOfCompilation();
+
+        OptimizedCallTarget splitTarget = (OptimizedCallTarget) Truffle.getRuntime().createCallTarget(getCallTarget().getRootNode().split());
+        splitTarget.setSplitSource(getCallTarget());
+        if (heuristic) {
+            OptimizedCallTargetLog.logSplit(this, getCallTarget(), splitTarget);
+        }
+        if (callCount >= 1) {
+            getCallTarget().decrementKnownCallSites();
+            splitTarget.incrementKnownCallSites();
+        }
+        this.splitCallTarget = splitTarget;
+    }
+
+    private boolean shouldSplit() {
+        if (splitCallTarget != null) {
+            return false;
+        }
+        if (!TruffleCompilerOptions.TruffleSplittingEnabled.getValue()) {
+            return false;
+        }
+        if (!isSplittable()) {
+            return false;
+        }
+        OptimizedCallTarget splitTarget = getCallTarget();
+        int nodeCount = OptimizedCallUtils.countNonTrivialNodes(splitTarget, false);
+        if (nodeCount > TruffleCompilerOptions.TruffleSplittingMaxCalleeSize.getValue()) {
+            return false;
+        }
+
+        // disable recursive splitting for now
+        OptimizedCallTarget root = (OptimizedCallTarget) getRootNode().getCallTarget();
+        if (root == splitTarget || root.getSplitSource() == splitTarget) {
+            // recursive call found
+            return false;
+        }
+
+        // max one child call and callCount > 2 and kind of small number of nodes
+        if (isMaxSingleCall()) {
+            return true;
+        }
+        return countPolymorphic() >= 1;
+    }
+
+    private boolean isMaxSingleCall() {
+        return NodeUtil.countNodes(getCurrentCallTarget().getRootNode(), new NodeCountFilter() {
+            public boolean isCounted(Node node) {
+                return node instanceof DirectCallNode;
+            }
+        }) <= 1;
+    }
+
+    private int countPolymorphic() {
+        return NodeUtil.countNodes(getCurrentCallTarget().getRootNode(), new NodeCountFilter() {
+            public boolean isCounted(Node node) {
+                NodeCost cost = node.getCost();
+                boolean polymorphic = cost == NodeCost.POLYMORPHIC || cost == NodeCost.MEGAMORPHIC;
+                return polymorphic;
+            }
+        });
+    }
+
+    public static OptimizedDirectCallNode create(OptimizedCallTarget target) {
+        return new OptimizedDirectCallNode(target);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedIndirectCallNode.java	Mon Apr 14 20:32:25 2014 +0200
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.truffle;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
+import com.oracle.truffle.api.frame.FrameInstance.FrameAccess;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+
+/**
+ * A call node with a constant {@link CallTarget} that can be optimized by Graal.
+ */
+public final class OptimizedIndirectCallNode extends IndirectCallNode implements MaterializedFrameNotify {
+
+    @CompilationFinal private FrameAccess outsideFrameAccess = FrameAccess.NONE;
+
+    @Override
+    public Object call(VirtualFrame frame, CallTarget target, Object[] arguments) {
+        return OptimizedDirectCallNode.callProxy(this, target, frame, arguments, false);
+    }
+
+    @Override
+    public FrameAccess getOutsideFrameAccess() {
+        return outsideFrameAccess;
+    }
+
+    @Override
+    public void setOutsideFrameAccess(FrameAccess outsideFrameAccess) {
+        this.outsideFrameAccess = outsideFrameAccess;
+    }
+
+}
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningHandler.java	Mon Apr 14 19:11:47 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningHandler.java	Mon Apr 14 20:32:25 2014 +0200
@@ -67,23 +67,23 @@
     }
 
     private List<TruffleInliningProfile> lookupProfiles(final OptimizedCallTarget target, int depth) {
-        final List<OptimizedCallNode> callNodes = new ArrayList<>();
+        final List<OptimizedDirectCallNode> callNodes = new ArrayList<>();
         target.getRootNode().accept(new NodeVisitor() {
             public boolean visit(Node node) {
-                if (node instanceof OptimizedCallNode) {
-                    callNodes.add((OptimizedCallNode) node);
+                if (node instanceof OptimizedDirectCallNode) {
+                    callNodes.add((OptimizedDirectCallNode) node);
                 }
                 return true;
             }
         });
         final List<TruffleInliningProfile> profiles = new ArrayList<>();
-        for (OptimizedCallNode callNode : callNodes) {
+        for (OptimizedDirectCallNode callNode : callNodes) {
             profiles.add(lookupProfile(target, callNode, depth));
         }
         return profiles;
     }
 
-    public TruffleInliningProfile lookupProfile(OptimizedCallTarget parentTarget, OptimizedCallNode ocn, int depth) {
+    public TruffleInliningProfile lookupProfile(OptimizedCallTarget parentTarget, OptimizedDirectCallNode ocn, int depth) {
         OptimizedCallTarget target = ocn.getCurrentCallTarget();
 
         int callSites = ocn.getCurrentCallTarget().getKnownCallSiteCount();
@@ -116,7 +116,7 @@
         return policy;
     }
 
-    private static double calculateFrequency(OptimizedCallTarget target, OptimizedCallNode ocn) {
+    private static double calculateFrequency(OptimizedCallTarget target, OptimizedDirectCallNode ocn) {
         return (double) Math.max(1, target.getCompilationProfile().getCallCount()) / Math.max(1, ocn.getCallCount());
     }
 
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningProfile.java	Mon Apr 14 19:11:47 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningProfile.java	Mon Apr 14 20:32:25 2014 +0200
@@ -26,7 +26,7 @@
 
 public class TruffleInliningProfile {
 
-    private final OptimizedCallNode callNode;
+    private final OptimizedDirectCallNode callNode;
     private final int nodeCount;
     private final int deepNodeCount;
     private final int callSites;
@@ -39,7 +39,7 @@
     private int queryIndex = -1;
     private double score;
 
-    public TruffleInliningProfile(OptimizedCallNode callNode, int callSites, int nodeCount, int deepNodeCount, double frequency, boolean forced, boolean recursiveCall,
+    public TruffleInliningProfile(OptimizedDirectCallNode callNode, int callSites, int nodeCount, int deepNodeCount, double frequency, boolean forced, boolean recursiveCall,
                     TruffleInliningResult recursiveResult) {
         this.callNode = callNode;
         this.callSites = callSites;
@@ -55,7 +55,7 @@
         return recursiveCall;
     }
 
-    public OptimizedCallNode getCallNode() {
+    public OptimizedDirectCallNode getCallNode() {
         return callNode;
     }
 
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningResult.java	Mon Apr 14 19:11:47 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningResult.java	Mon Apr 14 20:32:25 2014 +0200
@@ -27,7 +27,7 @@
 public final class TruffleInliningResult implements Iterable<TruffleInliningProfile> {
 
     private final OptimizedCallTarget callTarget;
-    private final Map<OptimizedCallNode, TruffleInliningProfile> profiles;
+    private final Map<OptimizedDirectCallNode, TruffleInliningProfile> profiles;
     private final Set<TruffleInliningProfile> inlined;
     private final int nodeCount;
 
@@ -41,7 +41,7 @@
         this.inlined = inlined;
     }
 
-    public Map<OptimizedCallNode, TruffleInliningProfile> getProfiles() {
+    public Map<OptimizedDirectCallNode, TruffleInliningProfile> getProfiles() {
         return profiles;
     }
 
@@ -53,7 +53,7 @@
         return callTarget;
     }
 
-    public boolean isInlined(OptimizedCallNode path) {
+    public boolean isInlined(OptimizedDirectCallNode path) {
         return inlined.contains(profiles.get(path));
     }
 
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleTreeDumpHandler.java	Mon Apr 14 19:11:47 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleTreeDumpHandler.java	Mon Apr 14 20:32:25 2014 +0200
@@ -53,9 +53,9 @@
         visitor.setChildSupplier(new ChildSupplier() {
 
             public Object startNode(Object callNode) {
-                if (callNode instanceof OptimizedCallNode) {
-                    if (((OptimizedCallNode) callNode).isInlined()) {
-                        return ((OptimizedCallNode) callNode).getCurrentRootNode();
+                if (callNode instanceof OptimizedDirectCallNode) {
+                    if (((OptimizedDirectCallNode) callNode).isInlined()) {
+                        return ((OptimizedDirectCallNode) callNode).getCurrentRootNode();
                     }
                 }
                 return null;
--- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ThreadSafetyTest.java	Mon Apr 14 19:11:47 2014 +0200
+++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ThreadSafetyTest.java	Mon Apr 14 20:32:25 2014 +0200
@@ -50,7 +50,7 @@
         RecursiveCallNode callNode = new RecursiveCallNode(new ConstNode(42));
         TestRootNode rootNode2 = new TestRootNode(new RewritingNode(new RewritingNode(new RewritingNode(new RewritingNode(new RewritingNode(callNode))))));
         final CallTarget target2 = runtime.createCallTarget(rootNode2);
-        callNode.setCallNode(runtime.createCallNode(target2));
+        callNode.setCallNode(runtime.createDirectCallNode(target2));
         NodeUtil.verify(rootNode2);
 
         testTarget(target1, 47, 1_000_000);
@@ -165,7 +165,7 @@
     }
 
     static class RecursiveCallNode extends ValueNode {
-        @Child CallNode callNode;
+        @Child DirectCallNode callNode;
         @Child private ValueNode valueNode;
 
         RecursiveCallNode(ValueNode value) {
@@ -182,7 +182,7 @@
             }
         }
 
-        void setCallNode(CallNode callNode) {
+        void setCallNode(DirectCallNode callNode) {
             this.callNode = insert(callNode);
         }
     }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleRuntime.java	Mon Apr 14 19:11:47 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleRuntime.java	Mon Apr 14 20:32:25 2014 +0200
@@ -50,7 +50,20 @@
      */
     RootCallTarget createCallTarget(RootNode rootNode);
 
-    CallNode createCallNode(CallTarget target);
+    /**
+     * Creates a new runtime specific version of {@link DirectCallNode}.
+     *
+     * @param target the direct {@link CallTarget} to call
+     * @return the new call node
+     */
+    DirectCallNode createDirectCallNode(CallTarget target);
+
+    /**
+     * Creates a new runtime specific version of {@link IndirectCallNode}.
+     *
+     * @return the new call node
+     */
+    IndirectCallNode createIndirectCallNode();
 
     /**
      * Creates a new assumption object that can be checked and invalidated.
@@ -104,4 +117,5 @@
      * important to note that this {@link FrameInstance} supports only slow path access.
      */
     FrameInstance getCurrentFrame();
+
 }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameInstance.java	Mon Apr 14 19:11:47 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameInstance.java	Mon Apr 14 20:32:25 2014 +0200
@@ -40,7 +40,7 @@
 
     boolean isVirtualFrame();
 
-    CallNode getCallNode();
+    DirectCallNode getCallNode();
 
     CallTarget getCallTarget();
 
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultCallNode.java	Mon Apr 14 19:11:47 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,97 +0,0 @@
-/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.api.impl;
-
-import com.oracle.truffle.api.*;
-import com.oracle.truffle.api.CompilerDirectives.*;
-import com.oracle.truffle.api.frame.*;
-import com.oracle.truffle.api.frame.FrameInstance.*;
-import com.oracle.truffle.api.nodes.*;
-
-public class DefaultCallNode extends CallNode implements MaterializedFrameNotify {
-
-    @CompilationFinal private FrameAccess outsideFrameAccess = FrameAccess.NONE;
-
-    private boolean inliningForced;
-
-    public DefaultCallNode(CallTarget target) {
-        super(target);
-    }
-
-    @Override
-    public Object call(VirtualFrame frame, Object[] arguments) {
-        return getCurrentCallTarget().call(arguments);
-    }
-
-    @Override
-    public FrameAccess getOutsideFrameAccess() {
-        return outsideFrameAccess;
-    }
-
-    @Override
-    public void setOutsideFrameAccess(FrameAccess outsideFrameAccess) {
-        this.outsideFrameAccess = outsideFrameAccess;
-    }
-
-    @Override
-    public void forceInlining() {
-        inliningForced = true;
-    }
-
-    @Override
-    public CallTarget getSplitCallTarget() {
-        return null;
-    }
-
-    @Override
-    public boolean split() {
-        return false;
-    }
-
-    @Override
-    public boolean isInlined() {
-        return false;
-    }
-
-    @Override
-    public boolean isSplittable() {
-        return false;
-    }
-
-    @Override
-    public boolean isInliningForced() {
-        return inliningForced;
-    }
-
-    @Override
-    public boolean isInlinable() {
-        return false;
-    }
-
-    @Override
-    public String toString() {
-        return (getParent() != null ? getParent().toString() : super.toString()) + " call " + getCurrentCallTarget().toString();
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultDirectCallNode.java	Mon Apr 14 20:32:25 2014 +0200
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.impl;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+
+/**
+ * This is runtime specific API. Do not use in a guest language.
+ */
+public final class DefaultDirectCallNode extends DirectCallNode {
+
+    private boolean inliningForced;
+
+    public DefaultDirectCallNode(CallTarget target) {
+        super(target);
+    }
+
+    @Override
+    public Object call(VirtualFrame frame, Object[] arguments) {
+        return getCurrentCallTarget().call(arguments);
+    }
+
+    @Override
+    public void forceInlining() {
+        inliningForced = true;
+    }
+
+    @Override
+    public boolean isInliningForced() {
+        return inliningForced;
+    }
+
+    @Override
+    public CallTarget getSplitCallTarget() {
+        return null;
+    }
+
+    @Override
+    public boolean split() {
+        return false;
+    }
+
+    @Override
+    public boolean isInlined() {
+        return false;
+    }
+
+    @Override
+    public boolean isSplittable() {
+        return false;
+    }
+
+    @Override
+    public boolean isInlinable() {
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        return (getParent() != null ? getParent().toString() : super.toString()) + " call " + getCurrentCallTarget().toString();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultIndirectCallNode.java	Mon Apr 14 20:32:25 2014 +0200
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.impl;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+
+/**
+ * This is runtime specific API. Do not use in a guest language.
+ */
+final class DefaultIndirectCallNode extends IndirectCallNode {
+
+    @Override
+    public Object call(VirtualFrame frame, CallTarget target, Object[] arguments) {
+        return target.call(arguments);
+    }
+
+}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultTruffleRuntime.java	Mon Apr 14 19:11:47 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultTruffleRuntime.java	Mon Apr 14 20:32:25 2014 +0200
@@ -53,8 +53,12 @@
         return new DefaultCallTarget(rootNode);
     }
 
-    public CallNode createCallNode(CallTarget target) {
-        return new DefaultCallNode(target);
+    public DirectCallNode createDirectCallNode(CallTarget target) {
+        return new DefaultDirectCallNode(target);
+    }
+
+    public IndirectCallNode createIndirectCallNode() {
+        return new DefaultIndirectCallNode();
     }
 
     @Override
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/MaterializedFrameNotify.java	Mon Apr 14 19:11:47 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,34 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.api.impl;
-
-import com.oracle.truffle.api.frame.FrameInstance.*;
-
-public interface MaterializedFrameNotify {
-
-    FrameAccess getOutsideFrameAccess();
-
-    void setOutsideFrameAccess(FrameAccess outsideFrameAccess);
-}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/CallNode.java	Mon Apr 14 19:11:47 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,166 +0,0 @@
-/*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.api.nodes;
-
-import com.oracle.truffle.api.*;
-import com.oracle.truffle.api.frame.*;
-
-/**
- * Represents a call to a {@link CallTarget} in the Truffle AST. In addition to calling the
- * {@link CallTarget}, this {@link Node} enables the runtime system to implement further
- * optimizations. Optimizations that can possibly be applied to a {@link CallNode} are inlining and
- * splitting. Inlining inlines this call site into the call graph of the parent {@link CallTarget}.
- * Splitting duplicates the {@link CallTarget} using {@link RootNode#split()} to collect call site
- * sensitive profiling information.
- *
- * Please note: This class is not intended to be subclassed by guest language implementations.
- *
- * @see TruffleRuntime#createCallNode(CallTarget)
- * @see #forceInlining()
- * @see #split()
- */
-public abstract class CallNode extends Node {
-
-    protected final CallTarget callTarget;
-
-    protected CallNode(CallTarget callTarget) {
-        this.callTarget = callTarget;
-    }
-
-    /**
-     * Calls the inner {@link CallTarget} returned by {@link #getCurrentCallTarget()}.
-     *
-     * @param arguments the arguments that should be passed to the callee
-     * @return the return result of the call
-     */
-    public abstract Object call(VirtualFrame frame, Object[] arguments);
-
-    /**
-     * Returns the originally supplied {@link CallTarget} when this call node was created. Please
-     * note that the returned {@link CallTarget} is not necessarily the {@link CallTarget} that is
-     * called. For that use {@link #getCurrentCallTarget()} instead.
-     *
-     * @return the {@link CallTarget} provided.
-     */
-    public CallTarget getCallTarget() {
-        return callTarget;
-    }
-
-    /**
-     * Returns <code>true</code> if the underlying runtime system supports inlining for the
-     * {@link CallTarget} in this {@link CallNode}.
-     *
-     * @return true if inlining is supported.
-     */
-    public abstract boolean isInlinable();
-
-    /**
-     * Returns <code>true</code> if the {@link CallTarget} is forced to be inlined. A
-     * {@link CallNode} can either be inlined manually by invoking {@link #forceInlining()} or by
-     * the runtime system which may at any point decide to inline.
-     *
-     * @return true if this method was inlined else false.
-     */
-    public abstract boolean isInliningForced();
-
-    /**
-     * Enforces the runtime system to inline the {@link CallTarget} at this call site. If the
-     * runtime system does not support inlining or it is already inlined this method has no effect.
-     * The runtime system may decide to not inline calls which were forced to inline.
-     */
-    public abstract void forceInlining();
-
-    /**
-     * Returns true if the runtime system has decided to inline this call-site. If the
-     * {@link CallNode} was forced to inline then this does not necessarily mean that the
-     * {@link CallNode} is really going to be inlined. This depends on whether or not the runtime
-     * system supports inlining. The runtime system may also decide to not inline calls which were
-     * forced to inline.
-     */
-    public abstract boolean isInlined();
-
-    /**
-     * Returns <code>true</code> if this {@link CallNode} can be split. A {@link CallNode} can only
-     * be split if the runtime system supports splitting and if the {@link RootNode} contained the
-     * {@link CallTarget} returns <code>true</code> for {@link RootNode#isSplittable()}.
-     *
-     * @return <code>true</code> if the target can be split
-     */
-    public abstract boolean isSplittable();
-
-    /**
-     * Enforces the runtime system to split the {@link CallTarget}. If the {@link CallNode} is not
-     * splittable this methods has no effect.
-     */
-    public abstract boolean split();
-
-    /**
-     * Returns <code>true</code> if the target of the {@link CallNode} was split.
-     *
-     * @return if the target was split
-     */
-    public final boolean isSplit() {
-        return getSplitCallTarget() != null;
-    }
-
-    /**
-     * Returns the split {@link CallTarget} if this method is split.
-     *
-     * @return the split {@link CallTarget}
-     */
-    public abstract CallTarget getSplitCallTarget();
-
-    /**
-     * Returns the used call target when {@link #call(VirtualFrame, Object[])} is invoked. If the
-     * {@link CallTarget} was split this method returns the {@link CallTarget} returned by
-     * {@link #getSplitCallTarget()}.
-     *
-     * @return the used {@link CallTarget} when node is called
-     */
-    public CallTarget getCurrentCallTarget() {
-        CallTarget split = getSplitCallTarget();
-        if (split != null) {
-            return split;
-        } else {
-            return getCallTarget();
-        }
-    }
-
-    /**
-     * Returns the {@link RootNode} associated with {@link CallTarget} returned by
-     * {@link #getCurrentCallTarget()}. If the stored {@link CallTarget} does not contain a
-     * {@link RootNode} this method returns <code>null</code>.
-     *
-     * @see #getCurrentCallTarget()
-     * @return the root node of the used call target
-     */
-    public final RootNode getCurrentRootNode() {
-        CallTarget target = getCurrentCallTarget();
-        if (target instanceof RootCallTarget) {
-            return ((RootCallTarget) target).getRootNode();
-        }
-        return null;
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/DirectCallNode.java	Mon Apr 14 20:32:25 2014 +0200
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.nodes;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+
+/**
+ * Represents a direct call to a {@link CallTarget}. Direct calls are calls for which the
+ * {@link CallTarget} remains the same for each consecutive call. This part of the Truffle API
+ * enables the runtime system to perform additional optimizations on direct calls.
+ *
+ * Optimizations that can be applied to a {@link DirectCallNode} are inlining and splitting.
+ * Inlining inlines this call site into the call graph of the parent {@link CallTarget}. Splitting
+ * duplicates the {@link CallTarget} using {@link RootNode#split()} to collect call site sensitive
+ * profiling information.
+ *
+ * Please note: This class is not intended to be subclassed by guest language implementations.
+ *
+ * @see IndirectCallNode for calls with a non-constant target
+ * @see TruffleRuntime#createDirectCallNode(CallTarget)
+ * @see #forceInlining()
+ * @see #split()
+ */
+public abstract class DirectCallNode extends Node {
+
+    protected final CallTarget callTarget;
+
+    protected DirectCallNode(CallTarget callTarget) {
+        this.callTarget = callTarget;
+    }
+
+    /**
+     * Calls the inner {@link CallTarget} returned by {@link #getCurrentCallTarget()}.
+     *
+     * @param arguments the arguments that should be passed to the callee
+     * @return the return result of the call
+     */
+    public abstract Object call(VirtualFrame frame, Object[] arguments);
+
+    /**
+     * Returns the originally supplied {@link CallTarget} when this call node was created. Please
+     * note that the returned {@link CallTarget} is not necessarily the {@link CallTarget} that is
+     * called. For that use {@link #getCurrentCallTarget()} instead.
+     *
+     * @return the {@link CallTarget} provided.
+     */
+    public CallTarget getCallTarget() {
+        return callTarget;
+    }
+
+    /**
+     * Returns <code>true</code> if the underlying runtime system supports inlining for the
+     * {@link CallTarget} in this {@link DirectCallNode}.
+     *
+     * @return true if inlining is supported.
+     */
+    public abstract boolean isInlinable();
+
+    /**
+     * Returns <code>true</code> if the {@link CallTarget} is forced to be inlined. A
+     * {@link DirectCallNode} can either be inlined manually by invoking {@link #forceInlining()} or
+     * by the runtime system which may at any point decide to inline.
+     *
+     * @return true if this method was inlined else false.
+     */
+    public abstract boolean isInliningForced();
+
+    /**
+     * Enforces the runtime system to inline the {@link CallTarget} at this call site. If the
+     * runtime system does not support inlining or it is already inlined this method has no effect.
+     * The runtime system may decide to not inline calls which were forced to inline.
+     */
+    public abstract void forceInlining();
+
+    /**
+     * Returns true if the runtime system has decided to inline this call-site. If the
+     * {@link DirectCallNode} was forced to inline then this does not necessarily mean that the
+     * {@link DirectCallNode} is really going to be inlined. This depends on whether or not the
+     * runtime system supports inlining. The runtime system may also decide to not inline calls
+     * which were forced to inline.
+     */
+    public abstract boolean isInlined();
+
+    /**
+     * Returns <code>true</code> if this {@link DirectCallNode} can be split. A
+     * {@link DirectCallNode} can only be split if the runtime system supports splitting and if the
+     * {@link RootNode} contained the {@link CallTarget} returns <code>true</code> for
+     * {@link RootNode#isSplittable()}.
+     *
+     * @return <code>true</code> if the target can be split
+     */
+    public abstract boolean isSplittable();
+
+    /**
+     * Enforces the runtime system to split the {@link CallTarget}. If the {@link DirectCallNode} is
+     * not splittable this methods has no effect.
+     */
+    public abstract boolean split();
+
+    /**
+     * Returns <code>true</code> if the target of the {@link DirectCallNode} was split.
+     *
+     * @return if the target was split
+     */
+    public final boolean isSplit() {
+        return getSplitCallTarget() != null;
+    }
+
+    /**
+     * Returns the split {@link CallTarget} if this method is split.
+     *
+     * @return the split {@link CallTarget}
+     */
+    public abstract CallTarget getSplitCallTarget();
+
+    /**
+     * Returns the used call target when {@link #call(VirtualFrame, Object[])} is invoked. If the
+     * {@link CallTarget} was split this method returns the {@link CallTarget} returned by
+     * {@link #getSplitCallTarget()}.
+     *
+     * @return the used {@link CallTarget} when node is called
+     */
+    public CallTarget getCurrentCallTarget() {
+        CallTarget split = getSplitCallTarget();
+        if (split != null) {
+            return split;
+        } else {
+            return getCallTarget();
+        }
+    }
+
+    /**
+     * Returns the {@link RootNode} associated with {@link CallTarget} returned by
+     * {@link #getCurrentCallTarget()}. If the stored {@link CallTarget} does not contain a
+     * {@link RootNode} this method returns <code>null</code>.
+     *
+     * @see #getCurrentCallTarget()
+     * @return the root node of the used call target
+     */
+    public final RootNode getCurrentRootNode() {
+        CallTarget target = getCurrentCallTarget();
+        if (target instanceof RootCallTarget) {
+            return ((RootCallTarget) target).getRootNode();
+        }
+        return null;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/IndirectCallNode.java	Mon Apr 14 20:32:25 2014 +0200
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.nodes;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+
+/**
+ * Represents an indirect call to a {@link CallTarget}. Indirect calls are calls for which the
+ * {@link CallTarget} may change dynamically for each consecutive call. This part of the Truffle API
+ * enables the runtime system to perform additional optimizations on indirect calls.
+ *
+ * Please note: This class is not intended to be sub classed by guest language implementations.
+ *
+ * @see DirectCallNode for faster calls with a constantly known {@link CallTarget}.
+ */
+public abstract class IndirectCallNode extends Node {
+
+    /**
+     * Performs an indirect call to the given {@link CallTarget} target with the provided arguments.
+     *
+     * @param frame the caller frame
+     * @param target the {@link CallTarget} to call
+     * @param arguments the arguments to provide
+     * @return the return value of the call
+     */
+    public abstract Object call(VirtualFrame frame, CallTarget target, Object[] arguments);
+
+}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java	Mon Apr 14 19:11:47 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java	Mon Apr 14 20:32:25 2014 +0200
@@ -636,8 +636,8 @@
                 nodeCount++;
             }
 
-            if (visitInlinedCallNodes && node instanceof CallNode) {
-                CallNode call = (CallNode) node;
+            if (visitInlinedCallNodes && node instanceof DirectCallNode) {
+                DirectCallNode call = (DirectCallNode) node;
                 if (call.isInlined()) {
                     Node target = ((RootCallTarget) call.getCurrentCallTarget()).getRootNode();
                     if (target != null) {
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/RootNode.java	Mon Apr 14 19:11:47 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/RootNode.java	Mon Apr 14 20:32:25 2014 +0200
@@ -67,7 +67,7 @@
 
     /**
      * Returns <code>true</code> if this {@link RootNode} can be split. A {@link RootNode} can be
-     * split inside of a {@link CallTarget} that is invoked using a {@link CallNode}. If this method
+     * split inside of a {@link CallTarget} that is invoked using a {@link DirectCallNode}. If this method
      * returns <code>true</code> a proper implementation of {@link #split()} must also be provided.
      * This method is intended to be overridden by a subclass.
      * 
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLDirectDispatchNode.java	Mon Apr 14 19:11:47 2014 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLDirectDispatchNode.java	Mon Apr 14 20:32:25 2014 +0200
@@ -36,11 +36,11 @@
     private final SLFunction cachedFunction;
 
     /**
-     * {@link CallNode} is part of the Truffle API and handles all the steps necessary for method
+     * {@link DirectCallNode} is part of the Truffle API and handles all the steps necessary for method
      * inlining: if the call is executed frequently and the callee is small, then the call is
      * inlined, i.e., the call node is replaced with a copy of the callee's AST.
      */
-    @Child private CallNode callCachedTargetNode;
+    @Child private DirectCallNode callCachedTargetNode;
 
     /** Assumption that the {@link #callCachedTargetNode} is still valid. */
     private final Assumption cachedTargetStable;
@@ -53,7 +53,7 @@
 
     protected SLDirectDispatchNode(SLAbstractDispatchNode next, SLFunction cachedFunction) {
         this.cachedFunction = cachedFunction;
-        this.callCachedTargetNode = Truffle.getRuntime().createCallNode(cachedFunction.getCallTarget());
+        this.callCachedTargetNode = Truffle.getRuntime().createDirectCallNode(cachedFunction.getCallTarget());
         this.cachedTargetStable = cachedFunction.getCallTargetStable();
         this.nextNode = next;
     }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLGenericDispatchNode.java	Mon Apr 14 19:11:47 2014 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLGenericDispatchNode.java	Mon Apr 14 20:32:25 2014 +0200
@@ -22,19 +22,23 @@
  */
 package com.oracle.truffle.sl.nodes.call;
 
-import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
+import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.frame.*;
-import com.oracle.truffle.api.frame.FrameInstance.FrameAccess;
-import com.oracle.truffle.api.impl.*;
+import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.sl.runtime.*;
 
 /**
  * Slow-path code for a call, used when the polymorphic inline cache exceeded its maximum size. Such
  * calls are not optimized any further, e.g., no method inlining is performed.
  */
-final class SLGenericDispatchNode extends SLAbstractDispatchNode implements MaterializedFrameNotify {
+final class SLGenericDispatchNode extends SLAbstractDispatchNode {
 
-    @CompilationFinal private FrameAccess outsideFrameAccess = FrameAccess.NONE;
+    /**
+     * {@link IndirectCallNode} is part of the Truffle API and handles all the steps necessary for
+     * calling a megamorphic call-site. The Graal specific version of this node performs additional
+     * optimizations for the fast access of the SimpleLanguage stack trace.
+     */
+    @Child private IndirectCallNode callNode = Truffle.getRuntime().createIndirectCallNode();
 
     @Override
     protected Object executeDispatch(VirtualFrame frame, SLFunction function, Object[] arguments) {
@@ -42,14 +46,7 @@
          * SL has a quite simple call lookup: just ask the function for the current call target, and
          * call it.
          */
-        return function.getCallTarget().call(arguments);
+        return callNode.call(frame, function.getCallTarget(), arguments);
     }
 
-    public FrameAccess getOutsideFrameAccess() {
-        return outsideFrameAccess;
-    }
-
-    public void setOutsideFrameAccess(FrameAccess outsideFrameAccess) {
-        this.outsideFrameAccess = outsideFrameAccess;
-    }
 }