changeset 13346:f17969ae4a35

Merge
author Erik Eckstein <erik.eckstein@oracle.com>
date Mon, 16 Dec 2013 08:20:36 +0100
parents 0393767ae0fc (current diff) 652f24858aad (diff)
children e3b0608d6ab8
files graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java
diffstat 48 files changed, 1010 insertions(+), 614 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalDebugConfig.java	Fri Dec 13 16:40:41 2013 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalDebugConfig.java	Mon Dec 16 08:20:36 2013 +0100
@@ -110,6 +110,10 @@
         return isEnabled(logFilter);
     }
 
+    public boolean isLogEnabledForMethod() {
+        return isEnabledForMethod(logFilter);
+    }
+
     public boolean isMeterEnabled() {
         return isEnabled(meterFilter);
     }
@@ -118,6 +122,10 @@
         return isEnabled(dumpFilter);
     }
 
+    public boolean isDumpEnabledForMethod() {
+        return isEnabledForMethod(dumpFilter);
+    }
+
     public boolean isTimeEnabled() {
         return isEnabled(timerFilter);
     }
@@ -130,6 +138,10 @@
         return checkDebugFilter(Debug.currentScope(), filter) && checkMethodFilter();
     }
 
+    private boolean isEnabledForMethod(DebugFilter filter) {
+        return filter != null && checkMethodFilter();
+    }
+
     private static boolean checkDebugFilter(String currentScope, DebugFilter filter) {
         return filter != null && filter.matches(currentScope);
     }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java	Fri Dec 13 16:40:41 2013 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java	Mon Dec 16 08:20:36 2013 +0100
@@ -83,12 +83,6 @@
     private final boolean printIRWithLIR;
 
     /**
-     * Maps constants to variables within the scope of a single block to avoid loading a constant
-     * more than once per block.
-     */
-    private Map<Constant, Variable> constantsLoadedInCurrentBlock;
-
-    /**
      * Handle for an operation that loads a constant into a variable. The operation starts in the
      * first block where the constant is used but will eventually be
      * {@linkplain LIRGenerator#insertConstantLoads() moved} to a block dominating all usages of the
@@ -246,63 +240,46 @@
         if (nodeOperands == null) {
             return null;
         }
-        Value operand = !node.isExternal() ? nodeOperands.get(node) : null;
+        Value operand = nodeOperands.get(node);
         if (operand == null) {
             return getConstantOperand(node);
         }
         return operand;
     }
 
-    /**
-     * Controls whether commoning is performed on {@linkplain #canInlineConstant(Constant)
-     * non-inlinable} constants.
-     */
-    private static final boolean CommonConstantLoads = Boolean.parseBoolean(System.getProperty("graal.commonConstantLoads", "true"));
-
     private Value getConstantOperand(ValueNode node) {
         if (!ConstantNodeRecordsUsages) {
             Constant value = node.asConstant();
             if (value != null) {
                 if (canInlineConstant(value)) {
-                    return !node.isExternal() ? setResult(node, value) : value;
+                    return setResult(node, value);
                 } else {
                     Variable loadedValue;
-                    if (CommonConstantLoads) {
-                        if (constantLoads == null) {
-                            constantLoads = new HashMap<>();
-                        }
-                        LoadConstant load = constantLoads.get(value);
-                        if (load == null) {
-                            int index = lir.lir(currentBlock).size();
-                            // loadedValue = newVariable(value.getPlatformKind());
-                            loadedValue = emitMove(value);
-                            LIRInstruction op = lir.lir(currentBlock).get(index);
-                            constantLoads.put(value, new LoadConstant(loadedValue, currentBlock, index, op));
+                    if (constantLoads == null) {
+                        constantLoads = new HashMap<>();
+                    }
+                    LoadConstant load = constantLoads.get(value);
+                    if (load == null) {
+                        int index = lir.lir(currentBlock).size();
+                        // loadedValue = newVariable(value.getPlatformKind());
+                        loadedValue = emitMove(value);
+                        LIRInstruction op = lir.lir(currentBlock).get(index);
+                        constantLoads.put(value, new LoadConstant(loadedValue, currentBlock, index, op));
+                    } else {
+                        Block dominator = ControlFlowGraph.commonDominator(load.block, currentBlock);
+                        loadedValue = load.variable;
+                        if (dominator != load.block) {
+                            if (load.index >= 0) {
+                                // Replace the move with a filler op so that the operation
+                                // list does not need to be adjusted.
+                                List<LIRInstruction> instructions = lir.lir(load.block);
+                                instructions.set(load.index, new NoOp(null, -1));
+                                load.index = -1;
+                            }
                         } else {
-                            Block dominator = ControlFlowGraph.commonDominator(load.block, currentBlock);
-                            loadedValue = load.variable;
-                            if (dominator != load.block) {
-                                if (load.index >= 0) {
-                                    List<LIRInstruction> instructions = lir.lir(load.block);
-                                    instructions.set(load.index, new NoOp(null, -1));
-                                    load.index = -1;
-                                }
-                            } else {
-                                assert load.block != currentBlock || load.index < lir.lir(currentBlock).size();
-                            }
-                            load.block = dominator;
+                            assert load.block != currentBlock || load.index < lir.lir(currentBlock).size();
                         }
-                    } else {
-                        if (constantsLoadedInCurrentBlock == null) {
-                            constantsLoadedInCurrentBlock = new HashMap<>();
-                            loadedValue = null;
-                        } else {
-                            loadedValue = constantsLoadedInCurrentBlock.get(value);
-                        }
-                        if (loadedValue == null) {
-                            loadedValue = emitMove(value);
-                            constantsLoadedInCurrentBlock.put(value, loadedValue);
-                        }
+                        load.block = dominator;
                     }
                     return loadedValue;
                 }
@@ -455,7 +432,6 @@
         }
 
         currentBlock = block;
-        resetLoadedConstants();
 
         // set up the list of LIR instructions
         assert lir.lir(block) == null : "LIR list already computed for this block";
@@ -519,12 +495,6 @@
         }
     }
 
-    private void resetLoadedConstants() {
-        if (constantsLoadedInCurrentBlock != null && !constantsLoadedInCurrentBlock.isEmpty()) {
-            constantsLoadedInCurrentBlock.clear();
-        }
-    }
-
     protected abstract boolean peephole(ValueNode valueNode);
 
     private boolean hasBlockEnd(Block block) {
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Debug.java	Fri Dec 13 16:40:41 2013 +0100
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Debug.java	Mon Dec 16 08:20:36 2013 +0100
@@ -69,6 +69,17 @@
         return ENABLED;
     }
 
+    public static boolean isDumpEnabledForMethod() {
+        if (!ENABLED) {
+            return false;
+        }
+        DebugConfig config = DebugScope.getConfig();
+        if (config == null) {
+            return false;
+        }
+        return config.isDumpEnabledForMethod();
+    }
+
     public static boolean isDumpEnabled() {
         return ENABLED && DebugScope.getInstance().isDumpEnabled();
     }
@@ -81,6 +92,17 @@
         return ENABLED && DebugScope.getInstance().isTimeEnabled();
     }
 
+    public static boolean isLogEnabledForMethod() {
+        if (!ENABLED) {
+            return false;
+        }
+        DebugConfig config = DebugScope.getConfig();
+        if (config == null) {
+            return false;
+        }
+        return config.isLogEnabledForMethod();
+    }
+
     public static boolean isLogEnabled() {
         return ENABLED && DebugScope.getInstance().isLogEnabled();
     }
@@ -431,6 +453,10 @@
                 return isLogEnabled;
             }
 
+            public boolean isLogEnabledForMethod() {
+                return isLogEnabled;
+            }
+
             @Override
             public boolean isMeterEnabled() {
                 return isMeterEnabled;
@@ -441,6 +467,10 @@
                 return isDumpEnabled;
             }
 
+            public boolean isDumpEnabledForMethod() {
+                return isDumpEnabled;
+            }
+
             @Override
             public boolean isTimeEnabled() {
                 return isTimerEnabled;
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/DebugConfig.java	Fri Dec 13 16:40:41 2013 +0100
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/DebugConfig.java	Mon Dec 16 08:20:36 2013 +0100
@@ -36,6 +36,12 @@
     boolean isLogEnabled();
 
     /**
+     * Determines if logging can be enabled in the current method, regardless of the
+     * {@linkplain Debug#currentScope() current debug scope}.
+     */
+    boolean isLogEnabledForMethod();
+
+    /**
      * Determines if metering is enabled in the {@linkplain Debug#currentScope() current debug
      * scope}.
      * 
@@ -52,6 +58,12 @@
     boolean isDumpEnabled();
 
     /**
+     * Determines if dumping can be enabled in the current method, regardless of the
+     * {@linkplain Debug#currentScope() current debug scope}.
+     */
+    boolean isDumpEnabledForMethod();
+
+    /**
      * Adds an object the context used by this configuration to do filtering.
      */
     void addToContext(Object o);
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/DelegatingDebugConfig.java	Fri Dec 13 16:40:41 2013 +0100
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/DelegatingDebugConfig.java	Mon Dec 16 08:20:36 2013 +0100
@@ -38,6 +38,10 @@
         return delegate.isLogEnabled();
     }
 
+    public boolean isLogEnabledForMethod() {
+        return delegate.isLogEnabledForMethod();
+    }
+
     @Override
     public boolean isMeterEnabled() {
         return delegate.isMeterEnabled();
@@ -48,6 +52,10 @@
         return delegate.isDumpEnabled();
     }
 
+    public boolean isDumpEnabledForMethod() {
+        return delegate.isDumpEnabledForMethod();
+    }
+
     @Override
     public boolean isTimeEnabled() {
         return delegate.isTimeEnabled();
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java	Fri Dec 13 16:40:41 2013 +0100
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java	Mon Dec 16 08:20:36 2013 +0100
@@ -75,11 +75,6 @@
     NodeChangedListener usagesDroppedToZeroListener;
     private final HashMap<CacheEntry, Node> cachedNodes = new HashMap<>();
 
-    /**
-     * Determines if external nodes will use {@link Graph}'s canonicalization cache.
-     */
-    public static final boolean CacheExternalNodesInGraph = Boolean.parseBoolean(System.getProperty("graal.cacheExternalNodesInGraph", "false"));
-
     private static final class CacheEntry {
 
         private final Node node;
@@ -347,24 +342,6 @@
         return uniqueHelper(node, true);
     }
 
-    /**
-     * Looks for a node <i>similar</i> to {@code node}. If not found, {@code node} is added to a
-     * cache in this graph used to canonicalize nodes.
-     * <p>
-     * Note that node must implement {@link ValueNumberable} and must be an
-     * {@linkplain Node#isExternal() external} node.
-     * 
-     * @return a node similar to {@code node} if one exists, otherwise {@code node}
-     */
-    public <T extends Node> T uniqueExternal(T node) {
-        assert node.isExternal() : node;
-        assert node instanceof ValueNumberable : node;
-        if (!CacheExternalNodesInGraph) {
-            return node;
-        }
-        return uniqueHelper(node, false);
-    }
-
     @SuppressWarnings("unchecked")
     <T extends Node> T uniqueHelper(T node, boolean addIfMissing) {
         assert node.getNodeClass().valueNumberable();
@@ -381,14 +358,13 @@
     }
 
     void putNodeIntoCache(Node node) {
-        assert node.isExternal() || node.graph() == this || node.graph() == null;
+        assert node.graph() == this || node.graph() == null;
         assert node.getNodeClass().valueNumberable();
         assert node.getNodeClass().isLeafNode() : node.getClass();
         cachedNodes.put(new CacheEntry(node), node);
     }
 
     Node findNodeInCache(Node node) {
-        assert !node.isExternal() || CacheExternalNodesInGraph;
         CacheEntry key = new CacheEntry(node);
         Node result = cachedNodes.get(key);
         if (result != null && result.isDeleted()) {
@@ -589,7 +565,7 @@
      * ordering between the nodes within the list.
      */
     public boolean maybeCompress() {
-        if (Debug.isEnabled()) {
+        if (Debug.isDumpEnabledForMethod() || Debug.isLogEnabledForMethod()) {
             return false;
         }
         int liveNodeCount = getNodeCount();
@@ -785,7 +761,6 @@
     }
 
     void register(Node node) {
-        assert !node.isExternal();
         assert node.id() == Node.INITIAL_ID;
         if (nodes.length == nodesSize) {
             nodes = Arrays.copyOf(nodes, (nodesSize * 2) + 1);
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java	Fri Dec 13 16:40:41 2013 +0100
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java	Mon Dec 16 08:20:36 2013 +0100
@@ -157,11 +157,9 @@
     }
 
     /**
-     * Gets the graph context of this node. This must not be called for {@linkplain #isExternal()
-     * external} nodes.
+     * Gets the graph context of this node.
      */
     public Graph graph() {
-        assert !isExternal() : "external node has no graph: " + this;
         return graph;
     }
 
@@ -288,15 +286,6 @@
     }
 
     /**
-     * Determines if this node has a {@linkplain #graph() graph} context or is external to any
-     * graph. The {@link #graph()} method must only be called on nodes for which this method returns
-     * true.
-     */
-    public boolean isExternal() {
-        return false;
-    }
-
-    /**
      * Finds the index of the last non-null entry in a node array. The search assumes that all
      * non-null entries precede the first null entry in the array.
      * 
@@ -531,7 +520,6 @@
         assert assertFalse(other == this, "cannot replace a node with itself");
         assert assertFalse(isDeleted(), "cannot replace deleted node");
         assert assertTrue(other == null || !other.isDeleted(), "cannot replace with deleted node %s", other);
-        assert assertTrue(other == null || other.isExternal() || other.graph() == graph, "cannot replace with node in different graph: %s", other == null || other.isExternal() ? null : other.graph());
         return true;
     }
 
@@ -588,7 +576,7 @@
         assert assertFalse(isDeleted(), "cannot clear inputs of deleted node");
 
         for (Node input : inputs()) {
-            if (input.recordsUsages() && !input.isExternal()) {
+            if (input.recordsUsages()) {
                 removeThisFromUsages(input);
                 if (input.usages().isEmpty()) {
                     NodeChangedListener listener = graph.usagesDroppedToZeroListener;
@@ -637,7 +625,6 @@
     }
 
     public final Node copyWithInputs() {
-        assert !isExternal();
         Node newNode = clone(graph);
         NodeClass clazz = getNodeClass();
         clazz.copyInputs(this, newNode);
@@ -676,7 +663,6 @@
     }
 
     final Node clone(Graph into, boolean clearInputsAndSuccessors) {
-        assert !isExternal();
         NodeClass nodeClass = getNodeClass();
         if (nodeClass.valueNumberable() && nodeClass.isLeafNode()) {
             Node otherNode = into.findNodeInCache(this);
@@ -711,23 +697,6 @@
         return newNode;
     }
 
-    /**
-     * Determines if a given node is {@linkplain Graph#uniqueExternal(Node) unique} within a given
-     * graph if the node is non-null and {@linkplain #isExternal() external}.
-     * 
-     * @param node node to check
-     * @param graph graph context to use
-     * @return true if node is null, not external or unique within {@code graph} otherwise raises a
-     *         {@link VerificationError}
-     */
-    public static boolean verifyUniqueIfExternal(Node node, Graph graph) {
-        if (node != null && node.isExternal() && Graph.CacheExternalNodesInGraph) {
-            Node cached = graph.findNodeInCache(node);
-            node.assertTrue(cached == node, "external node does not match canonical node %s", cached);
-        }
-        return true;
-    }
-
     protected void afterClone(@SuppressWarnings("unused") Node other) {
     }
 
@@ -736,8 +705,6 @@
         assertTrue(graph() != null, "null graph");
         for (Node input : inputs()) {
             assertTrue(!input.recordsUsages() || input.usages().contains(this), "missing usage in input %s", input);
-            assert verifyUniqueIfExternal(input, graph());
-            assertTrue(input.isExternal() || input.graph() == graph(), "mismatching graph in input %s", input);
         }
         for (Node successor : successors()) {
             assertTrue(successor.predecessor() == this, "missing predecessor in %s (actual: %s)", successor, successor.predecessor());
@@ -791,9 +758,7 @@
     }
 
     /**
-     * Nodes always use an {@linkplain System#identityHashCode(Object) identity} hash code. For this
-     * reason, {@linkplain #isExternal() external} nodes should still be {@link Graph#unique unique}
-     * within the context of a graph.
+     * Nodes always use an {@linkplain System#identityHashCode(Object) identity} hash code.
      */
     @Override
     public final int hashCode() {
@@ -801,8 +766,7 @@
     }
 
     /**
-     * Equality tests must rely solely on identity. For this reason, {@linkplain #isExternal()
-     * external} nodes should still be {@link Graph#unique unique} within the context of a graph.
+     * Equality tests must rely solely on identity.
      */
     @Override
     public final boolean equals(Object obj) {
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java	Fri Dec 13 16:40:41 2013 +0100
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java	Mon Dec 16 08:20:36 2013 +0100
@@ -937,7 +937,6 @@
             if (input != null) {
                 Node newInput = duplicationReplacement.replacement(input, true);
                 node.updateUsages(null, newInput);
-                assert Node.verifyUniqueIfExternal(newInput, node.graph());
                 assert newInput == null || fieldTypes.get(inputOffsets[index]).isAssignableFrom(newInput.getClass()) : "Can not assign " + newInput.getClass() + " to " +
                                 fieldTypes.get(inputOffsets[index]) + " in " + node;
                 putNode(node, inputOffsets[index], newInput);
@@ -994,7 +993,6 @@
             Node oldNode = list.get(i);
             if (oldNode != null) {
                 Node newNode = duplicationReplacement.replacement(oldNode, true);
-                assert Node.verifyUniqueIfExternal(newNode, node.graph());
                 result.set(i, newNode);
             }
         }
@@ -1079,7 +1077,6 @@
     }
 
     public boolean replaceFirstInput(Node node, Node old, Node other) {
-        assert Node.verifyUniqueIfExternal(other, node.graph());
         int index = 0;
         while (index < directInputCount) {
             Node input = getNode(node, inputOffsets[index]);
@@ -1384,9 +1381,6 @@
         InplaceUpdateClosure replacementClosure = new InplaceUpdateClosure() {
 
             public Node replacement(Node node, boolean isInput) {
-                if (node.isExternal() && node instanceof ValueNumberable) {
-                    return graph.uniqueExternal(node);
-                }
                 Node target = newNodes.get(node);
                 if (target == null) {
                     Node replacement = node;
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopEx.java	Fri Dec 13 16:40:41 2013 +0100
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopEx.java	Mon Dec 16 08:20:36 2013 +0100
@@ -84,7 +84,7 @@
     }
 
     public boolean isOutsideLoop(Node n) {
-        return n.isExternal() || !whole().contains(n);
+        return !whole().contains(n);
     }
 
     public LoopBeginNode loopBegin() {
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragment.java	Fri Dec 13 16:40:41 2013 +0100
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragment.java	Mon Dec 16 08:20:36 2013 +0100
@@ -71,10 +71,7 @@
     @SuppressWarnings("unchecked")
     public <New extends Node, Old extends New> New getDuplicatedNode(Old n) {
         assert isDuplicate();
-        if (!n.isExternal()) {
-            return (New) duplicationMap.get(n);
-        }
-        return n;
+        return (New) duplicationMap.get(n);
     }
 
     protected <New extends Node, Old extends New> void putDuplicatedNode(Old oldNode, New newNode) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConstantNode.java	Fri Dec 13 16:40:41 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConstantNode.java	Mon Dec 16 08:20:36 2013 +0100
@@ -22,8 +22,6 @@
  */
 package com.oracle.graal.nodes;
 
-import static com.oracle.graal.graph.Graph.*;
-
 import java.util.*;
 
 import com.oracle.graal.api.meta.*;
@@ -68,40 +66,17 @@
         return value;
     }
 
-    private static boolean ConstantNodesAreExternal = Boolean.parseBoolean(System.getProperty("graal.constantNodesAreExternal", "true"));
-
     /**
      * Used to measure the impact of ConstantNodes not recording their usages. This and all code
      * predicated on this value being true will be removed at some point.
      */
-    public static final boolean ConstantNodeRecordsUsages = !ConstantNodesAreExternal && Boolean.getBoolean("graal.constantNodeRecordsUsages");
+    public static final boolean ConstantNodeRecordsUsages = Boolean.getBoolean("graal.constantNodeRecordsUsages");
 
     @Override
     public boolean recordsUsages() {
         return ConstantNodeRecordsUsages;
     }
 
-    @Override
-    public boolean isDeleted() {
-        if (!ConstantNodesAreExternal) {
-            return super.isDeleted();
-        }
-        return false;
-    }
-
-    @Override
-    public boolean isAlive() {
-        if (!ConstantNodesAreExternal) {
-            return super.isAlive();
-        }
-        return true;
-    }
-
-    @Override
-    public boolean isExternal() {
-        return ConstantNodesAreExternal;
-    }
-
     /**
      * Computes the usages of this node by iterating over all the nodes in the graph, searching for
      * those that have this node as an input.
@@ -121,23 +96,10 @@
 
     /**
      * Gathers all the {@link ConstantNode}s that are inputs to the
-     * {@linkplain StructuredGraph#getNodes() live nodes} in a given graph. This is an expensive
-     * operation that should only be used in test/verification/AOT code.
+     * {@linkplain StructuredGraph#getNodes() live nodes} in a given graph.
      */
     public static NodeIterable<ConstantNode> getConstantNodes(StructuredGraph graph) {
-        if (!ConstantNodesAreExternal) {
-            return graph.getNodes().filter(ConstantNode.class);
-        }
-
-        Map<ConstantNode, ConstantNode> result = new HashMap<>();
-        for (Node node : graph.getNodes()) {
-            for (Node input : node.inputs()) {
-                if (input instanceof ConstantNode) {
-                    result.put((ConstantNode) input, (ConstantNode) input);
-                }
-            }
-        }
-        return new ConstantNodeList(result.keySet());
+        return graph.getNodes().filter(ConstantNode.class);
     }
 
     /**
@@ -150,9 +112,7 @@
             for (Node usage : usages) {
                 usage.replaceFirstInput(this, replacement);
             }
-            if (!isExternal()) {
-                graph.removeFloating(this);
-            }
+            graph.removeFloating(this);
         } else {
             assert graph == graph();
             graph().replaceFloating(this, replacement);
@@ -184,10 +144,6 @@
         if (constant.getKind().getStackKind() == Kind.Int && constant.getKind() != Kind.Int) {
             return forInt(constant.asInt(), graph);
         }
-        if (ConstantNodesAreExternal && !CacheExternalNodesInGraph) {
-            Stamp stamp = constant.getKind() == Kind.Object ? StampFactory.forConstant(constant, metaAccess) : StampFactory.forConstant(constant);
-            return graph.asConstantNode(constant, stamp);
-        }
         if (constant.getKind() == Kind.Object) {
             return unique(graph, new ConstantNode(constant, StampFactory.forConstant(constant, metaAccess)));
         } else {
@@ -210,9 +166,6 @@
      * @return a node for a double constant
      */
     public static ConstantNode forDouble(double d, StructuredGraph graph) {
-        if (ConstantNodesAreExternal && !CacheExternalNodesInGraph) {
-            return graph.asConstantNode(Constant.forDouble(d), null);
-        }
         return unique(graph, createPrimitive(Constant.forDouble(d)));
     }
 
@@ -223,9 +176,6 @@
      * @return a node for a float constant
      */
     public static ConstantNode forFloat(float f, StructuredGraph graph) {
-        if (ConstantNodesAreExternal && !CacheExternalNodesInGraph) {
-            return graph.asConstantNode(Constant.forFloat(f), null);
-        }
         return unique(graph, createPrimitive(Constant.forFloat(f)));
     }
 
@@ -236,9 +186,6 @@
      * @return a node for an long constant
      */
     public static ConstantNode forLong(long i, StructuredGraph graph) {
-        if (ConstantNodesAreExternal && !CacheExternalNodesInGraph) {
-            return graph.asConstantNode(Constant.forLong(i), null);
-        }
         return unique(graph, createPrimitive(Constant.forLong(i)));
     }
 
@@ -249,9 +196,6 @@
      * @return a node for an integer constant
      */
     public static ConstantNode forInt(int i, StructuredGraph graph) {
-        if (ConstantNodesAreExternal && !CacheExternalNodesInGraph) {
-            return graph.asConstantNode(Constant.forInt(i), null);
-        }
         return unique(graph, createPrimitive(Constant.forInt(i)));
     }
 
@@ -262,9 +206,6 @@
      * @return a node representing the boolean
      */
     public static ConstantNode forBoolean(boolean i, StructuredGraph graph) {
-        if (ConstantNodesAreExternal && !CacheExternalNodesInGraph) {
-            return graph.asConstantNode(i ? Constant.INT_1 : Constant.INT_0, null);
-        }
         return unique(graph, createPrimitive(Constant.forInt(i ? 1 : 0)));
     }
 
@@ -275,9 +216,6 @@
      * @return a node representing the byte
      */
     public static ConstantNode forByte(byte i, StructuredGraph graph) {
-        if (ConstantNodesAreExternal && !CacheExternalNodesInGraph) {
-            return graph.asConstantNode(Constant.forInt(i), null);
-        }
         return unique(graph, createPrimitive(Constant.forInt(i)));
     }
 
@@ -288,9 +226,6 @@
      * @return a node representing the char
      */
     public static ConstantNode forChar(char i, StructuredGraph graph) {
-        if (ConstantNodesAreExternal && !CacheExternalNodesInGraph) {
-            return graph.asConstantNode(Constant.forInt(i), null);
-        }
         return unique(graph, createPrimitive(Constant.forInt(i)));
     }
 
@@ -301,9 +236,6 @@
      * @return a node representing the short
      */
     public static ConstantNode forShort(short i, StructuredGraph graph) {
-        if (ConstantNodesAreExternal && !CacheExternalNodesInGraph) {
-            return graph.asConstantNode(Constant.forInt(i), null);
-        }
         return unique(graph, createPrimitive(Constant.forInt(i)));
     }
 
@@ -316,18 +248,11 @@
     public static ConstantNode forObject(Object o, MetaAccessProvider metaAccess, StructuredGraph graph) {
         assert !(o instanceof Constant) : "wrapping a Constant into a Constant";
         Constant constant = Constant.forObject(o);
-        if (ConstantNodesAreExternal && !CacheExternalNodesInGraph) {
-            return graph.asConstantNode(constant, StampFactory.forConstant(constant, metaAccess));
-        }
         return unique(graph, new ConstantNode(constant, StampFactory.forConstant(constant, metaAccess)));
     }
 
     private static ConstantNode unique(StructuredGraph graph, ConstantNode node) {
-        if (!ConstantNodesAreExternal) {
-            return graph.unique(node);
-        }
-        assert CacheExternalNodesInGraph;
-        return graph.uniqueExternal(node);
+        return graph.unique(node);
     }
 
     public static ConstantNode forIntegerKind(Kind kind, long value, StructuredGraph graph) {
@@ -390,15 +315,4 @@
             return super.toString(verbosity);
         }
     }
-
-    static class ConstantNodeList extends NodeList<ConstantNode> {
-
-        public ConstantNodeList(Collection<ConstantNode> nodes) {
-            super(nodes.toArray(new ConstantNode[nodes.size()]));
-        }
-
-        @Override
-        protected void update(ConstantNode oldNode, ConstantNode newNode) {
-        }
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java	Fri Dec 13 16:40:41 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java	Mon Dec 16 08:20:36 2013 +0100
@@ -29,7 +29,6 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.nodes.util.*;
 
 /**
@@ -82,38 +81,6 @@
     private boolean isAfterFloatingReadPhase = false;
 
     /**
-     * Used to create canonical {@link ConstantNode}s for {@link Constant}s in this graph.
-     */
-    private Map<Constant, ConstantNode> constants;
-
-    /**
-     * Gets a node for a given constant that is unique/canonical within this graph.
-     * 
-     * @param stamp the stamp for an {@link Kind#Object} constant (ignored otherwise)
-     */
-    public ConstantNode asConstantNode(Constant constant, Stamp stamp) {
-        ConstantNode node;
-        if (constants == null) {
-            constants = new HashMap<>();
-            node = null;
-        } else {
-            node = constants.get(constant);
-        }
-        if (node == null) {
-            node = new ConstantNode(constant, stamp == null ? StampFactory.forConstant(constant) : stamp);
-            constants.put(constant, node);
-        }
-        return node;
-    }
-
-    @SuppressWarnings("unchecked")
-    @Override
-    public <T extends Node> T uniqueExternal(T node) {
-        ConstantNode cn = (ConstantNode) node;
-        return (T) asConstantNode(cn.asConstant(), cn.stamp());
-    }
-
-    /**
      * Creates a new Graph containing a single {@link AbstractBeginNode} as the {@link #start()
      * start} node.
      */
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AbstractNewArrayNode.java	Fri Dec 13 16:40:41 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AbstractNewArrayNode.java	Mon Dec 16 08:20:36 2013 +0100
@@ -22,7 +22,6 @@
  */
 package com.oracle.graal.nodes.java;
 
-import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
@@ -31,10 +30,9 @@
 /**
  * The {@code AbstractNewArrayNode} is used for all 1-dimensional array allocations.
  */
-public class AbstractNewArrayNode extends DeoptimizingFixedWithNextNode implements Canonicalizable, Lowerable, ArrayLengthProvider {
+public class AbstractNewArrayNode extends AbstractNewObjectNode implements ArrayLengthProvider {
 
     @Input private ValueNode length;
-    private final boolean fillContents;
 
     @Override
     public ValueNode length() {
@@ -49,16 +47,8 @@
      * @param fillContents determines whether the array elements should be initialized to zero/null.
      */
     protected AbstractNewArrayNode(Stamp stamp, ValueNode length, boolean fillContents) {
-        super(stamp);
+        super(stamp, fillContents);
         this.length = length;
-        this.fillContents = fillContents;
-    }
-
-    /**
-     * @return <code>true</code> if the elements of the array will be initialized.
-     */
-    public boolean fillContents() {
-        return fillContents;
     }
 
     /**
@@ -77,23 +67,11 @@
     }
 
     @Override
-    public Node canonical(CanonicalizerTool tool) {
-        if (usages().isEmpty()) {
-            Stamp stamp = length.stamp();
-            if (stamp instanceof IntegerStamp && ((IntegerStamp) stamp).isPositive()) {
-                return null;
-            }
+    public void simplify(SimplifierTool tool) {
+        Stamp stamp = length.stamp();
+        if (stamp instanceof IntegerStamp && ((IntegerStamp) stamp).isPositive()) {
+            // otherwise, removing the allocation might swallow a NegativeArraySizeException
+            super.simplify(tool);
         }
-        return this;
-    }
-
-    @Override
-    public void lower(LoweringTool tool) {
-        tool.getLowerer().lower(this, tool);
-    }
-
-    @Override
-    public boolean canDeoptimize() {
-        return true;
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AbstractNewObjectNode.java	Mon Dec 16 08:20:36 2013 +0100
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.nodes.java;
+
+import java.util.*;
+
+import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
+
+/**
+ * The {@code AbstractNewObjectNode} is the base class for the new instance and new array nodes.
+ */
+public class AbstractNewObjectNode extends DeoptimizingFixedWithNextNode implements Simplifiable, Lowerable {
+
+    private final boolean fillContents;
+
+    /**
+     * Constructs a new AbstractNewObjectNode.
+     * 
+     * @param stamp the stamp of the newly created object
+     * @param fillContents determines if the object's contents should be initialized to zero/null.
+     */
+    protected AbstractNewObjectNode(Stamp stamp, boolean fillContents) {
+        super(stamp);
+        this.fillContents = fillContents;
+    }
+
+    /**
+     * @return <code>true</code> if the object's contents should be initialized to zero/null.
+     */
+    public boolean fillContents() {
+        return fillContents;
+    }
+
+    @Override
+    public void simplify(SimplifierTool tool) {
+        // poor man's escape analysis: check if the object can be trivially removed
+        for (Node usage : usages()) {
+            if (usage instanceof FixedValueAnchorNode) {
+                if (((FixedValueAnchorNode) usage).usages().isNotEmpty()) {
+                    return;
+                }
+            } else if (usage instanceof WriteNode) {
+                if (((WriteNode) usage).object() != this || usage.usages().isNotEmpty()) {
+                    // we would need to fix up the memory graph if the write has usages
+                    return;
+                }
+            } else {
+                return;
+            }
+        }
+        for (Node usage : usages().snapshot()) {
+            List<Node> snapshot = usage.inputs().snapshot();
+            graph().removeFixed((FixedWithNextNode) usage);
+            for (Node input : snapshot) {
+                tool.removeIfUnused(input);
+            }
+        }
+        List<Node> snapshot = inputs().snapshot();
+        graph().removeFixed(this);
+        for (Node input : snapshot) {
+            tool.removeIfUnused(input);
+        }
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        tool.getLowerer().lower(this, tool);
+    }
+
+    @Override
+    public boolean canDeoptimize() {
+        return true;
+    }
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/DynamicNewArrayNode.java	Fri Dec 13 16:40:41 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/DynamicNewArrayNode.java	Mon Dec 16 08:20:36 2013 +0100
@@ -23,6 +23,7 @@
 package com.oracle.graal.nodes.java;
 
 import java.lang.reflect.*;
+import java.util.*;
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
@@ -34,7 +35,7 @@
  * The {@code DynamicNewArrayNode} is used for allocation of arrays when the type is not a
  * compile-time constant.
  */
-public class DynamicNewArrayNode extends AbstractNewArrayNode implements Canonicalizable {
+public class DynamicNewArrayNode extends AbstractNewArrayNode {
 
     @Input private ValueNode elementType;
 
@@ -52,15 +53,20 @@
     }
 
     @Override
-    public Node canonical(CanonicalizerTool tool) {
-        if (elementType.isConstant()) {
+    public void simplify(SimplifierTool tool) {
+        if (isAlive() && elementType.isConstant()) {
             Class<?> elementClass = (Class<?>) elementType.asConstant().asObject();
             if (elementClass != null && !(elementClass.equals(void.class))) {
                 ResolvedJavaType javaType = tool.getMetaAccess().lookupJavaType(elementClass);
-                return graph().add(new NewArrayNode(javaType, length(), fillContents()));
+                NewArrayNode newArray = graph().add(new NewArrayNode(javaType, length(), fillContents()));
+                List<Node> snapshot = inputs().snapshot();
+                graph().replaceFixedWithFixed(this, newArray);
+                for (Node input : snapshot) {
+                    tool.removeIfUnused(input);
+                }
+                tool.addToWorkList(newArray);
             }
         }
-        return this;
     }
 
     @NodeIntrinsic
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewInstanceNode.java	Fri Dec 13 16:40:41 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewInstanceNode.java	Mon Dec 16 08:20:36 2013 +0100
@@ -26,7 +26,6 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
@@ -36,10 +35,9 @@
  * The {@code NewInstanceNode} represents the allocation of an instance class object.
  */
 @NodeInfo(nameTemplate = "New {p#instanceClass/s}")
-public class NewInstanceNode extends DeoptimizingFixedWithNextNode implements Canonicalizable, Lowerable, VirtualizableAllocation {
+public class NewInstanceNode extends AbstractNewObjectNode implements VirtualizableAllocation {
 
     private final ResolvedJavaType instanceClass;
-    private final boolean fillContents;
 
     /**
      * Constructs a NewInstanceNode.
@@ -49,10 +47,9 @@
      *            zero/null.
      */
     public NewInstanceNode(ResolvedJavaType type, boolean fillContents) {
-        super(StampFactory.exactNonNull(type));
+        super(StampFactory.exactNonNull(type), fillContents);
         assert !type.isArray();
         this.instanceClass = type;
-        this.fillContents = fillContents;
     }
 
     /**
@@ -64,27 +61,6 @@
         return instanceClass;
     }
 
-    /**
-     * @return <code>true</code> if the fields of the new object will be initialized.
-     */
-    public boolean fillContents() {
-        return fillContents;
-    }
-
-    @Override
-    public Node canonical(CanonicalizerTool tool) {
-        if (usages().isEmpty()) {
-            return null;
-        } else {
-            return this;
-        }
-    }
-
-    @Override
-    public void lower(LoweringTool tool) {
-        tool.getLowerer().lower(this, tool);
-    }
-
     @Override
     public void virtualize(VirtualizerTool tool) {
         /*
@@ -107,9 +83,4 @@
     protected ConstantNode defaultFieldValue(ResolvedJavaField field) {
         return ConstantNode.defaultForKind(field.getType().getKind(), graph());
     }
-
-    @Override
-    public boolean canDeoptimize() {
-        return true;
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java	Fri Dec 13 16:40:41 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java	Mon Dec 16 08:20:36 2013 +0100
@@ -123,7 +123,7 @@
     }
 
     public static void killWithUnusedFloatingInputs(Node node) {
-        if (node.recordsUsages() && !node.isExternal()) {
+        if (node.recordsUsages()) {
             List<Node> floatingInputs = node.inputs().filter(isFloatingNode()).snapshot();
             node.safeDelete();
 
@@ -354,14 +354,14 @@
          * Process a node as part of this search.
          * 
          * @param node the next node encountered in the search
-         * @param worklist if non-null and {@code node} is not external, {@code node} will be added
-         *            to this list. Otherwise, {@code node} is treated as a candidate result.
+         * @param worklist if non-null, {@code node} will be added to this list. Otherwise,
+         *            {@code node} is treated as a candidate result.
          * @return true if the search should continue, false if a definitive {@link #result} has
          *         been found
          */
         private boolean process(ValueNode node, NodeWorkList worklist) {
             if (node.isAlive()) {
-                if (node.isExternal() || worklist == null) {
+                if (worklist == null) {
                     if (result == null) {
                         // Initial candidate result: continue search
                         result = node;
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/DeadCodeEliminationPhase.java	Fri Dec 13 16:40:41 2013 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/DeadCodeEliminationPhase.java	Mon Dec 16 08:20:36 2013 +0100
@@ -112,17 +112,13 @@
         for (Node node : graph.getNodes()) {
             if (flood.isMarked(node)) {
                 for (Node input : node.inputs()) {
-                    if (!input.isExternal()) {
-                        flood.add(input);
-                    }
+                    flood.add(input);
                 }
             }
         }
         for (Node current : flood) {
             for (Node input : current.inputs()) {
-                if (!input.isExternal()) {
-                    flood.add(input);
-                }
+                flood.add(input);
             }
         }
     }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/GuardLoweringPhase.java	Fri Dec 13 16:40:41 2013 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/GuardLoweringPhase.java	Mon Dec 16 08:20:36 2013 +0100
@@ -27,6 +27,7 @@
 import java.util.*;
 import java.util.Map.Entry;
 
+import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.StructuredGraph.GuardsStage;
@@ -34,7 +35,6 @@
 import com.oracle.graal.nodes.cfg.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.util.*;
-import com.oracle.graal.options.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.graph.*;
 import com.oracle.graal.phases.schedule.*;
@@ -54,13 +54,6 @@
  * does the actual control-flow expansion of the remaining {@link GuardNode GuardNodes}.
  */
 public class GuardLoweringPhase extends BasePhase<MidTierContext> {
-    static class Options {
-        //@formatter:off
-        @Option(help = "")
-        public static final OptionValue<Boolean> UseGuardIdAsSpeculationId = new OptionValue<>(false);
-        //@formatter:on
-    }
-
     private static class UseImplicitNullChecks extends ScheduledNodeIterator {
 
         private final IdentityHashMap<ValueNode, GuardNode> nullGuarded = new IdentityHashMap<>();
@@ -134,9 +127,9 @@
         private final Block block;
         private boolean useGuardIdAsSpeculationId;
 
-        public LowerGuards(Block block) {
+        public LowerGuards(Block block, boolean useGuardIdAsSpeculationId) {
             this.block = block;
-            this.useGuardIdAsSpeculationId = Options.UseGuardIdAsSpeculationId.getValue();
+            this.useGuardIdAsSpeculationId = useGuardIdAsSpeculationId;
         }
 
         @Override
@@ -203,6 +196,6 @@
         if (OptImplicitNullChecks.getValue() && implicitNullCheckLimit > 0) {
             new UseImplicitNullChecks(implicitNullCheckLimit).processNodes(block, schedule);
         }
-        new LowerGuards(block).processNodes(block, schedule);
+        new LowerGuards(block, Debug.isDumpEnabledForMethod() || Debug.isLogEnabledForMethod()).processNodes(block, schedule);
     }
 }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java	Fri Dec 13 16:40:41 2013 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java	Mon Dec 16 08:20:36 2013 +0100
@@ -40,7 +40,6 @@
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.Graph.DuplicationReplacement;
-import com.oracle.graal.graph.Node.ValueNumberable;
 import com.oracle.graal.graph.Node.Verbosity;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
@@ -1433,12 +1432,7 @@
             if (returnNode.result() instanceof LocalNode) {
                 returnValue = localReplacement.replacement(returnNode.result());
             } else if (returnNode.result() != null) {
-                returnValue = returnNode.result();
-                if (!returnValue.isExternal()) {
-                    returnValue = duplicates.get(returnValue);
-                } else if (returnValue instanceof ValueNumberable) {
-                    returnValue = graph.uniqueExternal(returnValue);
-                }
+                returnValue = duplicates.get(returnNode.result());
             }
             invoke.asNode().replaceAtUsages(returnValue);
             Node returnDuplicate = duplicates.get(returnNode);
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoweringPhase.java	Fri Dec 13 16:40:41 2013 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoweringPhase.java	Mon Dec 16 08:20:36 2013 +0100
@@ -324,7 +324,7 @@
                     assert (unscheduledUsages = getUnscheduledUsages(node)) != null;
                     Mark preLoweringMark = node.graph().getMark();
                     ((Lowerable) node).lower(loweringTool);
-                    if (node == startAnchor && node.isDeleted()) {
+                    if (loweringTool.guardAnchor.asNode().isDeleted()) {
                         loweringTool.guardAnchor = BeginNode.prevBegin(nextNode);
                     }
                     assert checkPostNodeLowering(node, loweringTool, preLoweringMark, unscheduledUsages);
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java	Fri Dec 13 16:40:41 2013 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java	Mon Dec 16 08:20:36 2013 +0100
@@ -365,7 +365,7 @@
                         // stop iterating: fixed nodes within the given set are traversal roots
                         // anyway, and all other
                         // fixed nodes are known to be outside.
-                    } else if (!node.isExternal() && !aboveBound.isMarked(node)) {
+                    } else if (!aboveBound.isMarked(node)) {
                         worklist.add(node);
                         aboveBound.mark(node);
                     }
@@ -378,9 +378,7 @@
             while (!worklist.isEmpty()) {
                 Node current = worklist.remove();
                 for (Node input : current.inputs()) {
-                    if (!input.isExternal()) {
-                        aboveClosure.apply(current, input);
-                    }
+                    aboveClosure.apply(current, input);
                 }
             }
 
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java	Fri Dec 13 16:40:41 2013 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java	Mon Dec 16 08:20:36 2013 +0100
@@ -759,10 +759,6 @@
      * Determines the earliest block in which the given node can be scheduled.
      */
     private Block earliestBlock(Node node) {
-        if (node.isExternal()) {
-            return cfg.getStartBlock();
-        }
-
         Block earliest = cfg.getNodeToBlock().get(node);
         if (earliest != null) {
             return earliest;
@@ -1088,7 +1084,7 @@
             for (Node input : state.inputs()) {
                 if (input instanceof VirtualState) {
                     addUnscheduledToLatestSorting(b, (VirtualState) input, sortedInstructions, visited, reads, beforeLastLocation);
-                } else if (!input.isExternal()) {
+                } else {
                     addToLatestSorting(b, (ScheduledNode) input, sortedInstructions, visited, reads, beforeLastLocation);
                 }
             }
@@ -1105,7 +1101,7 @@
             if (input instanceof FrameState) {
                 assert state == null;
                 state = (FrameState) input;
-            } else if (!input.isExternal()) {
+            } else {
                 addToLatestSorting(b, (ScheduledNode) input, sortedInstructions, visited, reads, beforeLastLocation);
 
             }
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/BinaryGraphPrinter.java	Fri Dec 13 16:40:41 2013 +0100
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/BinaryGraphPrinter.java	Mon Dec 16 08:20:36 2013 +0100
@@ -105,7 +105,6 @@
     }
 
     private final ConstantPool constantPool;
-    private final Map<Node, Integer> externalNodeIds;
     private final ByteBuffer buffer;
     private final WritableByteChannel channel;
 
@@ -113,7 +112,6 @@
         constantPool = new ConstantPool();
         buffer = ByteBuffer.allocateDirect(256 * 1024);
         this.channel = channel;
-        this.externalNodeIds = new HashMap<>();
     }
 
     public void print(Graph graph, String title, SchedulePhase predefinedSchedule) throws IOException {
@@ -389,25 +387,9 @@
         }
     }
 
-    /**
-     * Should be higher than any internal {@link Node#getId() node id}.
-     */
-    @SuppressWarnings("javadoc") private static final int FIRST_EXTERNAL_NODE_ID = Integer.getInteger("graal.binaryGraphPrinter.firstExternalNodeId", 10000000);
-
     @SuppressWarnings("deprecation")
-    private int getNodeId(Node node) {
-        if (!node.isExternal()) {
-            assert node.getId() < FIRST_EXTERNAL_NODE_ID : "internal node ids exceeded lowest external node id (" + FIRST_EXTERNAL_NODE_ID +
-                            ") - use graal.binaryGraphPrinter.firstExternalNodeId system property to increase the latter";
-            return node.getId();
-        } else {
-            Integer id = externalNodeIds.get(node);
-            if (id == null) {
-                id = FIRST_EXTERNAL_NODE_ID + externalNodeIds.size();
-                externalNodeIds.put(node, id);
-            }
-            return id;
-        }
+    private static int getNodeId(Node node) {
+        return node.getId();
     }
 
     private void writeNodes(Graph graph) throws IOException {
@@ -419,16 +401,8 @@
             }
         }
         Map<Object, Object> props = new HashMap<>();
-        Map<Node, Integer> externalNodes = new HashMap<>();
-        for (Node node : graph.getNodes()) {
-            for (Node input : node.inputs()) {
-                if (input.isExternal()) {
-                    externalNodes.put(input, getNodeId(input));
-                }
-            }
-        }
 
-        writeInt(graph.getNodeCount() + externalNodes.size());
+        writeInt(graph.getNodeCount());
 
         for (Node node : graph.getNodes()) {
             NodeClass nodeClass = node.getNodeClass();
@@ -453,22 +427,6 @@
 
             props.clear();
         }
-        for (Map.Entry<Node, Integer> e : externalNodes.entrySet()) {
-            Node node = e.getKey();
-            NodeClass nodeClass = node.getNodeClass();
-            node.getDebugProperties(props);
-            writeInt(e.getValue());
-            writePoolObject(nodeClass);
-            writeByte(0);
-            // properties
-            writeShort((char) props.size());
-            for (Entry<Object, Object> entry : props.entrySet()) {
-                String key = entry.getKey().toString();
-                writePoolObject(key);
-                writePropertyObject(entry.getValue());
-            }
-            props.clear();
-        }
     }
 
     private void writeEdges(Node node, Collection<Position> positions) throws IOException {
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java	Fri Dec 13 16:40:41 2013 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java	Mon Dec 16 08:20:36 2013 +0100
@@ -60,7 +60,7 @@
     @Option(help = "")
     public static final OptionValue<Integer> TruffleInliningMaxRecursiveDepth = new OptionValue<>(2);
     @Option(help = "")
-    public static final OptionValue<Integer> TruffleInliningMaxCallerSize = new OptionValue<>(2500);
+    public static final OptionValue<Integer> TruffleInliningMaxCallerSize = new OptionValue<>(2250);
     @Option(help = "")
     public static final OptionValue<Integer> TruffleInliningMaxCalleeSize = new OptionValue<>(250);
     @Option(help = "")
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsClosure.java	Fri Dec 13 16:40:41 2013 +0100
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsClosure.java	Mon Dec 16 08:20:36 2013 +0100
@@ -231,7 +231,7 @@
 
     public ValueNode getScalarAlias(ValueNode node) {
         assert !(node instanceof VirtualObjectNode);
-        if (node == null || !node.isAlive() || node.isExternal() || aliases.isNew(node)) {
+        if (node == null || !node.isAlive() || aliases.isNew(node)) {
             return node;
         }
         ValueNode result = aliases.get(node);
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java	Fri Dec 13 16:40:41 2013 +0100
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java	Mon Dec 16 08:20:36 2013 +0100
@@ -611,7 +611,7 @@
     }
 
     public ObjectState getObjectState(PartialEscapeBlockState<?> state, ValueNode value) {
-        if (value == null || value.isExternal()) {
+        if (value == null) {
             return null;
         }
         if (value.isAlive() && !aliases.isNew(value)) {
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualUtil.java	Fri Dec 13 16:40:41 2013 +0100
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualUtil.java	Mon Dec 16 08:20:36 2013 +0100
@@ -69,22 +69,18 @@
         for (Node node : graph.getNodes()) {
             if (flood.isMarked(node)) {
                 for (Node input : node.inputs()) {
-                    if (!input.isExternal()) {
-                        flood.add(input);
-                        if (!path.containsKey(input)) {
-                            path.put(input, node);
-                        }
+                    flood.add(input);
+                    if (!path.containsKey(input)) {
+                        path.put(input, node);
                     }
                 }
             }
         }
         for (Node current : flood) {
             for (Node input : current.inputs()) {
-                if (!input.isExternal()) {
-                    flood.add(input);
-                    if (!path.containsKey(input)) {
-                        path.put(input, current);
-                    }
+                flood.add(input);
+                if (!path.containsKey(input)) {
+                    path.put(input, current);
                 }
             }
         }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/utilities/AlwaysValidAssumptionTest.java	Mon Dec 16 08:20:36 2013 +0100
@@ -0,0 +1,51 @@
+/*
+ * 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.truffle.api.test.utilities;
+
+import static org.junit.Assert.*;
+import org.junit.*;
+
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.api.utilities.*;
+
+public class AlwaysValidAssumptionTest {
+
+    @Test
+    public void testCheck() throws InvalidAssumptionException {
+        final AlwaysValidAssumption assumption = AlwaysValidAssumption.INSTANCE;
+        assumption.check();
+    }
+
+    @Test
+    public void testIsValid() {
+        final AlwaysValidAssumption assumption = AlwaysValidAssumption.INSTANCE;
+        assertTrue(assumption.isValid());
+    }
+
+    @Test(expected = UnsupportedOperationException.class)
+    public void testCannotInvalidate() {
+        final AlwaysValidAssumption assumption = AlwaysValidAssumption.INSTANCE;
+        assumption.invalidate();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/utilities/AssumedValueTest.java	Mon Dec 16 08:20:36 2013 +0100
@@ -0,0 +1,46 @@
+/*
+ * 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.truffle.api.test.utilities;
+
+import static org.junit.Assert.*;
+import org.junit.*;
+
+import com.oracle.truffle.api.utilities.*;
+
+public class AssumedValueTest {
+
+    @Test
+    public void testGet() {
+        final AssumedValue<String> assumedValue = new AssumedValue<>("assumed-value", "1");
+        assertEquals("1", assumedValue.get());
+    }
+
+    @Test
+    public void testSet() {
+        final AssumedValue<String> assumedValue = new AssumedValue<>("assumed-value", "1");
+        assertEquals("1", assumedValue.get());
+        assumedValue.set("2");
+        assertEquals("2", assumedValue.get());
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/utilities/BranchProfileTest.java	Mon Dec 16 08:20:36 2013 +0100
@@ -0,0 +1,38 @@
+/*
+ * 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.truffle.api.test.utilities;
+
+import org.junit.*;
+
+import com.oracle.truffle.api.utilities.*;
+
+public class BranchProfileTest {
+
+    @Test
+    public void testEnter() {
+        BranchProfile profile = new BranchProfile();
+        profile.enter();
+        profile.enter();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/utilities/CyclicAssumptionTest.java	Mon Dec 16 08:20:36 2013 +0100
@@ -0,0 +1,62 @@
+/*
+ * 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.truffle.api.test.utilities;
+
+import static org.junit.Assert.*;
+
+import org.junit.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.utilities.*;
+
+public class CyclicAssumptionTest {
+
+    @Test
+    public void testIsValid() {
+        final CyclicAssumption assumption = new CyclicAssumption("cyclic-assumption");
+        assertTrue(assumption.getAssumption().isValid());
+    }
+
+    @Test
+    public void testInvalidate() {
+        final CyclicAssumption cyclicAssumption = new CyclicAssumption("cyclic-assumption");
+
+        final Assumption firstAssumption = cyclicAssumption.getAssumption();
+        assertEquals("cyclic-assumption", firstAssumption.getName());
+        assertTrue(firstAssumption.isValid());
+
+        cyclicAssumption.invalidate();
+
+        assertFalse(firstAssumption.isValid());
+
+        final Assumption secondAssumption = cyclicAssumption.getAssumption();
+        assertEquals("cyclic-assumption", secondAssumption.getName());
+        assertTrue(secondAssumption.isValid());
+
+        cyclicAssumption.invalidate();
+
+        assertFalse(firstAssumption.isValid());
+        assertFalse(secondAssumption.isValid());
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/utilities/UnionAssumptionTest.java	Mon Dec 16 08:20:36 2013 +0100
@@ -0,0 +1,119 @@
+/*
+ * 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.truffle.api.test.utilities;
+
+import static org.junit.Assert.*;
+
+import org.junit.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.api.utilities.*;
+
+public class UnionAssumptionTest {
+
+    @Test
+    public void testIsValid() {
+        final Assumption first = Truffle.getRuntime().createAssumption("first");
+        final Assumption second = Truffle.getRuntime().createAssumption("second");
+        final UnionAssumption union = new UnionAssumption(first, second);
+        assertTrue(union.isValid());
+    }
+
+    @Test
+    public void testCheck() throws InvalidAssumptionException {
+        final Assumption first = Truffle.getRuntime().createAssumption("first");
+        final Assumption second = Truffle.getRuntime().createAssumption("second");
+        final UnionAssumption union = new UnionAssumption(first, second);
+        union.check();
+    }
+
+    @Test
+    public void testFirstInvalidateIsValid() {
+        final Assumption first = Truffle.getRuntime().createAssumption("first");
+        final Assumption second = Truffle.getRuntime().createAssumption("second");
+        final UnionAssumption union = new UnionAssumption(first, second);
+
+        first.invalidate();
+
+        assertFalse(union.isValid());
+    }
+
+    @Test(expected = InvalidAssumptionException.class)
+    public void testFirstInvalidateCheck() throws InvalidAssumptionException {
+        final Assumption first = Truffle.getRuntime().createAssumption("first");
+        final Assumption second = Truffle.getRuntime().createAssumption("second");
+        final UnionAssumption union = new UnionAssumption(first, second);
+
+        first.invalidate();
+
+        union.check();
+    }
+
+    @Test
+    public void testSecondInvalidateIsValid() {
+        final Assumption first = Truffle.getRuntime().createAssumption("first");
+        final Assumption second = Truffle.getRuntime().createAssumption("second");
+        final UnionAssumption union = new UnionAssumption(first, second);
+
+        second.invalidate();
+
+        assertFalse(union.isValid());
+    }
+
+    @Test(expected = InvalidAssumptionException.class)
+    public void testSecondInvalidateCheck() throws InvalidAssumptionException {
+        final Assumption first = Truffle.getRuntime().createAssumption("first");
+        final Assumption second = Truffle.getRuntime().createAssumption("second");
+        final UnionAssumption union = new UnionAssumption(first, second);
+
+        second.invalidate();
+
+        union.check();
+    }
+
+    @Test
+    public void testBothInvalidateIsValid() {
+        final Assumption first = Truffle.getRuntime().createAssumption("first");
+        final Assumption second = Truffle.getRuntime().createAssumption("second");
+        final UnionAssumption union = new UnionAssumption(first, second);
+
+        first.invalidate();
+        second.invalidate();
+
+        assertFalse(union.isValid());
+    }
+
+    @Test(expected = InvalidAssumptionException.class)
+    public void testBothInvalidateCheck() throws InvalidAssumptionException {
+        final Assumption first = Truffle.getRuntime().createAssumption("first");
+        final Assumption second = Truffle.getRuntime().createAssumption("second");
+        final UnionAssumption union = new UnionAssumption(first, second);
+
+        first.invalidate();
+        second.invalidate();
+
+        union.check();
+    }
+
+}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/Truffle.java	Fri Dec 13 16:40:41 2013 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/Truffle.java	Mon Dec 16 08:20:36 2013 +0100
@@ -31,19 +31,21 @@
  */
 public class Truffle {
 
-    private static TruffleRuntime runtime;
+    private static final TruffleRuntime RUNTIME;
 
     private static native TruffleRuntime initializeRuntime();
 
     public static TruffleRuntime getRuntime() {
-        return runtime;
+        return RUNTIME;
     }
 
     static {
+        TruffleRuntime runtime;
         try {
             runtime = initializeRuntime();
         } catch (UnsatisfiedLinkError e) {
             runtime = new DefaultTruffleRuntime();
         }
+        RUNTIME = runtime;
     }
 }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultCallTarget.java	Fri Dec 13 16:40:41 2013 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultCallTarget.java	Mon Dec 16 08:20:36 2013 +0100
@@ -50,6 +50,10 @@
         return rootNode.execute(frame);
     }
 
+    public FrameDescriptor getFrameDescriptor() {
+        return frameDescriptor;
+    }
+
     public RootNode getRootNode() {
         return rootNode;
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/AlwaysValidAssumption.java	Mon Dec 16 08:20:36 2013 +0100
@@ -0,0 +1,60 @@
+/*
+ * 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.  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.utilities;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.nodes.*;
+
+/**
+ * An assumption that is always valid. Used as a placeholder where an assumption is needed but never
+ * invalidated.
+ */
+public final class AlwaysValidAssumption implements Assumption {
+
+    public static final AlwaysValidAssumption INSTANCE = new AlwaysValidAssumption();
+
+    private AlwaysValidAssumption() {
+    }
+
+    @Override
+    public void check() throws InvalidAssumptionException {
+    }
+
+    @Override
+    public void invalidate() {
+        throw new UnsupportedOperationException("Cannot invalidate this assumption - it is always valid");
+    }
+
+    @Override
+    public String getName() {
+        return getClass().getName();
+    }
+
+    @Override
+    public boolean isValid() {
+        return true;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/AssumedValue.java	Mon Dec 16 08:20:36 2013 +0100
@@ -0,0 +1,68 @@
+/*
+ * 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.  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.utilities;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
+import com.oracle.truffle.api.nodes.*;
+
+/**
+ * A {@link CompilationFinal} value combined with an {@link Assumption} to notify when it changes.
+ * Note that you should be careful that modifications to this value do not cause deoptimization
+ * loops. This could be by using a value that is monotonic.
+ */
+public class AssumedValue<T> {
+
+    @CompilationFinal private T value;
+    private final CyclicAssumption assumption;
+
+    public AssumedValue(String name, T initialValue) {
+        assumption = new CyclicAssumption(name);
+        value = initialValue;
+    }
+
+    /**
+     * Get the current value, updating it if it has been {@link #set}. The compiler may be able to
+     * make this method return a constant value, but still accommodate mutation.
+     */
+    public T get() {
+        try {
+            assumption.getAssumption().check();
+        } catch (InvalidAssumptionException e) {
+            // No need to rewrite anything - just pick up the new value
+        }
+
+        return value;
+    }
+
+    /**
+     * Set a new value, which will be picked up the next time {@link #get} is called.
+     */
+    public void set(T newValue) {
+        value = newValue;
+        assumption.invalidate();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/BranchProfile.java	Mon Dec 16 08:20:36 2013 +0100
@@ -0,0 +1,47 @@
+/*
+ * 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.  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.utilities;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.CompilerDirectives.*;
+
+/**
+ * Utility class to speculate on branches to be never visited. If the {@link #enter()} method is
+ * invoked first the optimized code is invalidated and the branch where {@link #enter()} is invoked
+ * is enabled for compilation. Otherwise if the {@link #enter()} method was never invoked the branch
+ * will not get compiled.
+ */
+public final class BranchProfile {
+
+    @CompilationFinal private boolean visited;
+
+    public void enter() {
+        if (!visited) {
+            CompilerDirectives.transferToInterpreterAndInvalidate();
+            visited = true;
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/CyclicAssumption.java	Mon Dec 16 08:20:36 2013 +0100
@@ -0,0 +1,58 @@
+/*
+ * 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.  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.utilities;
+
+import com.oracle.truffle.api.*;
+
+/**
+ * Holds an {@link Assumption}, and knows how to recreate it with the same properties on
+ * invalidation. Used so that mutability is isolated in this class, and all other classes that need
+ * an assumption that may be recreated can have a final reference to an object of this class. Note
+ * that you should be careful that repeated invalidations do not cause a deoptimization loop in that
+ * same way that you would with any other assumption.
+ */
+public class CyclicAssumption {
+
+    private final String name;
+    private Assumption assumption;
+
+    public CyclicAssumption(String name) {
+        this.name = name;
+        invalidate();
+    }
+
+    public void invalidate() {
+        if (assumption != null) {
+            assumption.invalidate();
+        }
+
+        assumption = Truffle.getRuntime().createAssumption(name);
+    }
+
+    public Assumption getAssumption() {
+        return assumption;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/UnionAssumption.java	Mon Dec 16 08:20:36 2013 +0100
@@ -0,0 +1,72 @@
+/*
+ * 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.  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.utilities;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.nodes.*;
+
+/**
+ * An assumption that combines two other assumptions. A check on this assumption checks both of the
+ * child assumptions.
+ */
+public class UnionAssumption implements Assumption {
+
+    private final String name;
+    private final Assumption first;
+    private final Assumption second;
+
+    public UnionAssumption(String name, Assumption first, Assumption second) {
+        this.name = name;
+        this.first = first;
+        this.second = second;
+    }
+
+    public UnionAssumption(Assumption first, Assumption second) {
+        this(null, first, second);
+    }
+
+    @Override
+    public void check() throws InvalidAssumptionException {
+        first.check();
+        second.check();
+    }
+
+    @Override
+    public void invalidate() {
+        first.invalidate();
+        second.invalidate();
+    }
+
+    @Override
+    public String getName() {
+        return name;
+    }
+
+    @Override
+    public boolean isValid() {
+        return first.isValid() && second.isValid();
+    }
+
+}
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/CallNode.java	Fri Dec 13 16:40:41 2013 +0100
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/CallNode.java	Mon Dec 16 08:20:36 2013 +0100
@@ -34,127 +34,126 @@
     private static final int INLINE_CACHE_SIZE = 2;
 
     @Child protected TypedNode functionNode;
-
-    private CallNode(TypedNode functionNode) {
-        this.functionNode = adoptChild(functionNode);
-    }
+    @Child protected ArgumentsNode argumentsNode;
 
-    private CallTarget executeCallTargetNode(VirtualFrame frame) {
-        try {
-            return functionNode.executeCallTarget(frame);
-        } catch (UnexpectedResultException e) {
-            throw new UnsupportedOperationException("Call to " + e.getMessage() + " not supported.");
-        }
+    public CallNode(TypedNode functionNode, ArgumentsNode argumentsNode) {
+        this.functionNode = adoptChild(functionNode);
+        this.argumentsNode = adoptChild(argumentsNode);
     }
 
     @Override
     public final Object executeGeneric(VirtualFrame frame) {
-        return executeGeneric(frame, executeCallTargetNode(frame));
+        CallTarget function;
+        try {
+            function = functionNode.executeCallTarget(frame);
+        } catch (UnexpectedResultException e) {
+            throw new UnsupportedOperationException("Call to " + e.getMessage() + " not supported.");
+        }
+        Object[] arguments = argumentsNode.executeArray(frame);
+        return executeCall(frame, function, arguments);
     }
 
-    public abstract Object executeGeneric(VirtualFrame frame, CallTarget function);
+    public abstract Object executeCall(VirtualFrame frame, CallTarget function, Object[] arguments);
 
     public static CallNode create(TypedNode function, TypedNode[] arguments) {
         return new UninitializedCallNode(function, new ArgumentsNode(arguments), 0);
     }
 
-    private static final class CachedCallNode extends CallNode {
-
-        @Child protected CallNode nextNode;
-        @Child protected TypedNode currentNode;
-        private final CallTarget cachedFunction;
-
-        public CachedCallNode(TypedNode function, TypedNode current, CallNode next, CallTarget cachedFunction) {
-            super(function);
-            this.currentNode = adoptChild(current);
-            this.nextNode = adoptChild(next);
-            this.cachedFunction = cachedFunction;
-        }
-
-        @Override
-        public Object executeGeneric(VirtualFrame frame, CallTarget function) {
-            if (this.cachedFunction == function) {
-                return currentNode.executeGeneric(frame);
-            }
-            return nextNode.executeGeneric(frame, function);
-        }
-    }
-
     private static final class UninitializedCallNode extends CallNode {
 
-        @Child protected ArgumentsNode uninitializedArgs;
         protected final int depth;
 
         UninitializedCallNode(TypedNode function, ArgumentsNode args, int depth) {
-            super(function);
-            this.uninitializedArgs = adoptChild(args);
+            super(function, args);
             this.depth = depth;
         }
 
         UninitializedCallNode(UninitializedCallNode copy) {
-            super(null);
-            this.uninitializedArgs = adoptChild(copy.uninitializedArgs);
+            super(null, null);
             this.depth = copy.depth + 1;
         }
 
         @Override
-        public Object executeGeneric(VirtualFrame frame, CallTarget function) {
+        public Object executeCall(VirtualFrame frame, CallTarget function, Object[] arguments) {
             CompilerDirectives.transferToInterpreter();
-            return specialize(function).executeGeneric(frame, function);
+            return specialize(function).executeCall(frame, function, arguments);
         }
 
         private CallNode specialize(CallTarget function) {
             CompilerAsserts.neverPartOfCompilation();
 
             if (depth < INLINE_CACHE_SIZE) {
-                TypedNode current = createCacheNode(function);
+                DefaultCallTarget callTarget = (DefaultCallTarget) function;
+                FunctionRootNode root = (FunctionRootNode) callTarget.getRootNode();
                 CallNode next = new UninitializedCallNode(this);
-                return replace(new CachedCallNode(this.functionNode, current, next, function));
+                InlinableDirectCallNode directCall = new InlinableDirectCallNode(functionNode, argumentsNode, next, callTarget);
+                replace(directCall);
+                if (root.isInlineImmediatly()) {
+                    return directCall.inlineImpl();
+                } else {
+                    return directCall;
+                }
             } else {
-                CallNode topMost = (CallNode) getTopNode();
-                return topMost.replace(new GenericCallNode(topMost.functionNode, uninitializedArgs));
+                CallNode topMost = (CallNode) NodeUtil.getNthParent(this, depth);
+                return topMost.replace(new GenericCallNode(topMost.functionNode, topMost.argumentsNode));
             }
         }
 
-        protected Node getTopNode() {
-            Node parentNode = this;
-            for (int i = 0; i < depth; i++) {
-                parentNode = parentNode.getParent();
-            }
-            return parentNode;
+    }
+
+    private abstract static class DirectCallNode extends CallNode {
+
+        protected final DefaultCallTarget cachedFunction;
+
+        @Child protected CallNode nextNode;
+
+        public DirectCallNode(TypedNode function, ArgumentsNode arguments, DefaultCallTarget cachedFunction, CallNode next) {
+            super(function, arguments);
+            this.cachedFunction = cachedFunction;
+            this.nextNode = adoptChild(next);
         }
 
-        protected TypedNode createCacheNode(CallTarget function) {
-            ArgumentsNode clonedArgs = NodeUtil.cloneNode(uninitializedArgs);
+        @Override
+        public Object executeCall(VirtualFrame frame, CallTarget function, Object[] arguments) {
+            if (this.cachedFunction == function) {
+                return executeCurrent(frame, arguments);
+            }
+            return nextNode.executeCall(frame, function, arguments);
+        }
 
-            if (function instanceof DefaultCallTarget) {
-                DefaultCallTarget defaultFunction = (DefaultCallTarget) function;
-                RootNode rootNode = defaultFunction.getRootNode();
-                if (rootNode instanceof FunctionRootNode) {
-                    FunctionRootNode root = (FunctionRootNode) rootNode;
-                    if (root.isAlwaysInline()) {
-                        TypedNode inlinedCall = root.inline(clonedArgs);
-                        if (inlinedCall != null) {
-                            return inlinedCall;
-                        }
-                    }
-                    return new InlinableCallNode((DefaultCallTarget) function, clonedArgs);
-                }
-                // got a call target that is not inlinable (should not occur for SL)
-                return new DispatchedCallNode(defaultFunction, clonedArgs);
-            } else {
-                throw new AssertionError();
-            }
+        protected abstract Object executeCurrent(VirtualFrame frame, Object[] arguments);
 
-        }
     }
 
-    private static final class InlinableCallNode extends DispatchedCallNode implements InlinableCallSite {
+    private static final class InlinableDirectCallNode extends DirectCallNode implements InlinableCallSite {
 
         @CompilationFinal private int callCount;
 
-        InlinableCallNode(DefaultCallTarget function, ArgumentsNode arguments) {
-            super(function, arguments);
+        InlinableDirectCallNode(TypedNode function, ArgumentsNode arguments, CallNode next, DefaultCallTarget cachedFunction) {
+            super(function, arguments, cachedFunction, next);
+        }
+
+        @Override
+        public Object executeCurrent(VirtualFrame frame, Object[] arguments) {
+            if (CompilerDirectives.inInterpreter()) {
+                callCount++;
+            }
+            return cachedFunction.call(frame.pack(), new SLArguments(arguments));
+        }
+
+        InlinedDirectCallNode inlineImpl() {
+            CompilerAsserts.neverPartOfCompilation();
+            RootNode root = cachedFunction.getRootNode();
+            TypedNode inlinedNode = ((FunctionRootNode) root).inline();
+            assert inlinedNode != null;
+            return replace(new InlinedDirectCallNode(this, inlinedNode), "Inlined " + root);
+        }
+
+        @Override
+        public boolean inline(FrameFactory factory) {
+            inlineImpl();
+            /* SL is always able to inline if required. */
+            return true;
         }
 
         @Override
@@ -169,7 +168,7 @@
 
         @Override
         public Node getInlineTree() {
-            RootNode root = function.getRootNode();
+            RootNode root = cachedFunction.getRootNode();
             if (root instanceof FunctionRootNode) {
                 return ((FunctionRootNode) root).getUninitializedBody();
             }
@@ -177,67 +176,46 @@
         }
 
         @Override
-        public boolean inline(FrameFactory factory) {
-            CompilerAsserts.neverPartOfCompilation();
-            TypedNode functionCall = null;
-
-            RootNode root = function.getRootNode();
-            if (root instanceof FunctionRootNode) {
-                functionCall = ((FunctionRootNode) root).inline(NodeUtil.cloneNode(args));
-            }
-            if (functionCall != null) {
-                this.replace(functionCall);
-                return true;
-            } else {
-                return false;
-            }
-        }
-
-        @Override
-        public Object executeGeneric(VirtualFrame frame) {
-            if (CompilerDirectives.inInterpreter()) {
-                callCount++;
-            }
-            return super.executeGeneric(frame);
-        }
-
-        @Override
         public CallTarget getCallTarget() {
-            return function;
+            return cachedFunction;
         }
 
     }
 
-    private static class DispatchedCallNode extends TypedNode {
+    private static class InlinedDirectCallNode extends DirectCallNode implements InlinedCallSite {
+
+        private final FrameDescriptor descriptor;
+        @Child private TypedNode inlinedBody;
 
-        @Child protected ArgumentsNode args;
-        protected final DefaultCallTarget function;
-
-        DispatchedCallNode(DefaultCallTarget function, ArgumentsNode arguments) {
-            this.args = adoptChild(arguments);
-            this.function = function;
+        InlinedDirectCallNode(InlinableDirectCallNode prev, TypedNode inlinedBody) {
+            super(prev.functionNode, prev.argumentsNode, prev.cachedFunction, prev.nextNode);
+            this.descriptor = cachedFunction.getFrameDescriptor();
+            this.inlinedBody = adoptChild(inlinedBody);
         }
 
         @Override
-        public Object executeGeneric(VirtualFrame frame) {
-            SLArguments argsObject = new SLArguments(args.executeArray(frame));
-            return function.call(frame.pack(), argsObject);
+        public Object executeCurrent(VirtualFrame frame, Object[] arguments) {
+            SLArguments slArguments = new SLArguments(arguments);
+            VirtualFrame newFrame = Truffle.getRuntime().createVirtualFrame(frame.pack(), slArguments, descriptor);
+            return inlinedBody.executeGeneric(newFrame);
         }
+
+        @Override
+        public CallTarget getCallTarget() {
+            return cachedFunction;
+        }
+
     }
 
     private static final class GenericCallNode extends CallNode {
 
-        @Child protected ArgumentsNode args;
-
         GenericCallNode(TypedNode functionNode, ArgumentsNode arguments) {
-            super(functionNode);
-            this.args = adoptChild(arguments);
+            super(functionNode, arguments);
         }
 
         @Override
-        public Object executeGeneric(VirtualFrame frame, CallTarget function) {
-            SLArguments argsObject = new SLArguments(args.executeArray(frame));
-            return function.call(frame.pack(), argsObject);
+        public Object executeCall(VirtualFrame frame, CallTarget function, Object[] arguments) {
+            return function.call(frame.pack(), new SLArguments(arguments));
         }
     }
 
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/FunctionRootNode.java	Fri Dec 13 16:40:41 2013 +0100
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/FunctionRootNode.java	Mon Dec 16 08:20:36 2013 +0100
@@ -35,14 +35,14 @@
 
     private final TypedNode uninitializedBody;
     private final String name;
-    private final boolean alwaysInline;
+    private final boolean inlineImmediatly;
 
-    private FunctionRootNode(TypedNode body, String name, boolean alwaysInline) {
+    private FunctionRootNode(TypedNode body, String name, boolean inlineImmediatly) {
         super(null);
         this.uninitializedBody = NodeUtil.cloneNode(body);
         this.body = adoptChild(body);
         this.name = name;
-        this.alwaysInline = alwaysInline;
+        this.inlineImmediatly = inlineImmediatly;
     }
 
     public static CallTarget createBuiltin(SLContext context, NodeFactory<? extends BuiltinNode> factory, String name) {
@@ -67,36 +67,12 @@
         return body.executeGeneric(frame);
     }
 
-    public boolean isAlwaysInline() {
-        return alwaysInline;
-    }
-
-    public TypedNode inline(ArgumentsNode clonedArgs) {
-        TypedNode clonedBody = NodeUtil.cloneNode(uninitializedBody);
-        if (clonedBody instanceof BuiltinNode) {
-            return inlineBuiltin(clonedArgs, (BuiltinNode) clonedBody);
-        } else if (clonedBody instanceof FunctionBodyNode) {
-            return inlineFunction(clonedArgs, (FunctionBodyNode) clonedBody);
-        } else {
-            throw new UnsupportedOperationException();
-        }
+    public boolean isInlineImmediatly() {
+        return inlineImmediatly;
     }
 
-    private InlinedFunctionNode inlineFunction(ArgumentsNode clonedArgs, FunctionBodyNode clonedBody) {
-        return new InlinedFunctionNode(getCallTarget(), clonedBody, clonedArgs);
-    }
-
-    private static TypedNode inlineBuiltin(ArgumentsNode clonedArgs, BuiltinNode builtin) {
-        TypedNode[] callerArgs = clonedArgs.getArguments();
-        TypedNode[] builtinArgs = builtin.getArguments();
-        for (int i = 0; i < builtinArgs.length; i++) {
-            if (i < callerArgs.length) {
-                builtinArgs[i].replace(callerArgs[i]);
-            } else {
-                builtinArgs[i].replace(new NullLiteralNode());
-            }
-        }
-        return builtin;
+    public TypedNode inline() {
+        return NodeUtil.cloneNode(uninitializedBody);
     }
 
     public Node getUninitializedBody() {
@@ -108,34 +84,6 @@
         return "function " + name;
     }
 
-    private static final class InlinedFunctionNode extends TypedNode implements InlinedCallSite {
-
-        @Child private FunctionBodyNode body;
-        @Child private ArgumentsNode arguments;
-
-        private final CallTarget callTarget;
-        private final FrameDescriptor frameDescriptor;
-
-        public InlinedFunctionNode(CallTarget callTarget, FunctionBodyNode body, ArgumentsNode arguments) {
-            this.callTarget = callTarget;
-            this.body = adoptChild(body);
-            this.frameDescriptor = body.getFrameDescriptor();
-            this.arguments = adoptChild(arguments);
-        }
-
-        @Override
-        public Object executeGeneric(VirtualFrame frame) {
-            SLArguments args = new SLArguments(arguments.executeArray(frame));
-            VirtualFrame childFrame = Truffle.getRuntime().createVirtualFrame(frame.pack(), args, frameDescriptor);
-            return body.executeGeneric(childFrame);
-        }
-
-        public CallTarget getCallTarget() {
-            return callTarget;
-        }
-
-    }
-
     public String getName() {
         return name;
     }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/IfNode.java	Fri Dec 13 16:40:41 2013 +0100
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/IfNode.java	Mon Dec 16 08:20:36 2013 +0100
@@ -24,6 +24,7 @@
 
 import com.oracle.truffle.api.dsl.*;
 import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.utilities.*;
 
 @NodeChild(value = "conditionNode", type = ConditionNode.class)
 public abstract class IfNode extends StatementNode {
@@ -31,6 +32,9 @@
     @Child private StatementNode thenPartNode;
     @Child private StatementNode elsePartNode;
 
+    private final BranchProfile ifBranch = new BranchProfile();
+    private final BranchProfile elseBranch = new BranchProfile();
+
     public IfNode(StatementNode thenPart, StatementNode elsePart) {
         this.thenPartNode = adoptChild(thenPart);
         this.elsePartNode = adoptChild(elsePart);
@@ -43,9 +47,11 @@
     @Specialization
     public void doVoid(VirtualFrame frame, boolean condition) {
         if (condition) {
+            ifBranch.enter();
             thenPartNode.executeVoid(frame);
         } else {
             if (elsePartNode != null) {
+                elseBranch.enter();
                 elsePartNode.executeVoid(frame);
             }
         }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/ReadArgumentNode.java	Fri Dec 13 16:40:41 2013 +0100
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/ReadArgumentNode.java	Mon Dec 16 08:20:36 2013 +0100
@@ -23,12 +23,16 @@
 package com.oracle.truffle.sl.nodes;
 
 import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.utilities.*;
 import com.oracle.truffle.sl.runtime.*;
 
 public class ReadArgumentNode extends TypedNode {
 
     private final int index;
 
+    private final BranchProfile outOfBounds = new BranchProfile();
+    private final BranchProfile inBounds = new BranchProfile();
+
     public ReadArgumentNode(int index) {
         this.index = index;
     }
@@ -37,8 +41,10 @@
     public Object executeGeneric(VirtualFrame frame) {
         Object[] args = SLArguments.get(frame).arguments;
         if (index < args.length) {
+            inBounds.enter();
             return args[index];
         } else {
+            outOfBounds.enter();
             return SLNull.INSTANCE;
         }
     }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/ReadFunctionNode.java	Fri Dec 13 16:40:41 2013 +0100
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/ReadFunctionNode.java	Mon Dec 16 08:20:36 2013 +0100
@@ -23,16 +23,15 @@
 package com.oracle.truffle.sl.nodes;
 
 import com.oracle.truffle.api.*;
-import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
 import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.utilities.*;
 import com.oracle.truffle.sl.runtime.*;
 
 public final class ReadFunctionNode extends TypedNode {
 
     private final SLFunctionRegistry registry;
     private final String name;
-
-    @CompilationFinal private boolean seenInvalidFunction;
+    private final BranchProfile invalidFunction = new BranchProfile();
 
     public ReadFunctionNode(SLFunctionRegistry registry, String name) {
         this.registry = registry;
@@ -50,14 +49,8 @@
         if (target != null) {
             return target;
         }
-        if (!seenInvalidFunction) {
-            CompilerDirectives.transferToInterpreter();
-            seenInvalidFunction = true;
-        }
-        if (seenInvalidFunction) {
-            throw new RuntimeException("Function with name '" + name + "' not found.");
-        }
-        return null;
+        invalidFunction.enter();
+        throw new RuntimeException("Function with name '" + name + "' not found.");
     }
 
 }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/WhileNode.java	Fri Dec 13 16:40:41 2013 +0100
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/WhileNode.java	Mon Dec 16 08:20:36 2013 +0100
@@ -23,6 +23,7 @@
 package com.oracle.truffle.sl.nodes;
 
 import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.utilities.*;
 
 public class WhileNode extends StatementNode {
 
@@ -33,6 +34,11 @@
     private final BreakException breakTarget;
     private final ContinueException continueTarget;
 
+    private final BranchProfile continueMismatch = new BranchProfile();
+    private final BranchProfile continueMatch = new BranchProfile();
+    private final BranchProfile breakMismatch = new BranchProfile();
+    private final BranchProfile breakMatch = new BranchProfile();
+
     public WhileNode(ConditionNode condition, StatementNode body) {
         this.condition = adoptChild(condition);
         this.body = adoptChild(body);
@@ -49,15 +55,19 @@
                     body.executeVoid(frame);
                 } catch (ContinueException ex) {
                     if (ex != continueTarget) {
+                        continueMismatch.enter();
                         throw ex;
                     }
+                    continueMatch.enter();
                     // Fall through to next loop iteration.
                 }
             }
         } catch (BreakException ex) {
             if (ex != breakTarget) {
+                breakMismatch.enter();
                 throw ex;
             }
+            breakMatch.enter();
             // Done executing this loop, exit method to execute statement following the loop.
         }
     }
--- a/mx/mx_graal.py	Fri Dec 13 16:40:41 2013 +0100
+++ b/mx/mx_graal.py	Mon Dec 16 08:20:36 2013 +0100
@@ -1452,7 +1452,7 @@
 
     mx.distribution('GRAAL').add_update_listener(_installGraalJarInJdks)
 
-def packagejar(classpath, outputFile, mainClass, annotationProcessor=None):
+def packagejar(classpath, outputFile, mainClass=None, annotationProcessor=None, stripDebug=False):
     prefix = '' if mx.get_os() != 'windows' else '\\??\\' # long file name hack
     print "creating", outputFile
     filecount, totalsize = 0, 0
@@ -1483,5 +1483,5 @@
             filecount += 1
             totalsize += zi.file_size
     print "%d files (total size: %.2f kB, jar size: %.2f kB)" % (filecount, totalsize / 1e3, os.path.getsize(outputFile) / 1e3)
-    mx.run([mx.exe_suffix(join(mx.java().jdk, 'bin', 'pack200')), '-r', '-G', outputFile])
+    mx.run([mx.exe_suffix(join(mx.java().jdk, 'bin', 'pack200')), '-r'] + (['-G'] if stripDebug else []) + [outputFile])
     print "repacked jar size: %.2f kB" % (os.path.getsize(outputFile) / 1e3)
--- a/src/share/vm/runtime/vframe.cpp	Fri Dec 13 16:40:41 2013 +0100
+++ b/src/share/vm/runtime/vframe.cpp	Mon Dec 16 08:20:36 2013 +0100
@@ -266,7 +266,7 @@
 
   // Get oopmap describing oops and int for current bci
   InterpreterOopMap oop_mask;
-  if (TraceDeoptimization && Verbose) {
+  if ((TraceDeoptimization && Verbose) GRAAL_ONLY( || PrintDeoptimizationDetails)) {
     methodHandle m_h(thread(), method());
     OopMapCache::compute_one_oop_map(m_h, bci(), &oop_mask);
   } else {
@@ -333,7 +333,7 @@
 
   InterpreterOopMap oop_mask;
   // Get oopmap describing oops and int for current bci
-  if (TraceDeoptimization && Verbose) {
+  if ((TraceDeoptimization && Verbose) GRAAL_ONLY( || PrintDeoptimizationDetails)) {
     methodHandle m_h(method());
     OopMapCache::compute_one_oop_map(m_h, bci(), &oop_mask);
   } else {