changeset 12570:af39ea2dc39d

made ConstantNodes (optionally) not record their usages (GRAAL-508)
author Doug Simon <doug.simon@oracle.com>
date Thu, 24 Oct 2013 14:57:57 +0200
parents 1c8d5a0891b5
children 693622f11dc3
files graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotOptions.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConstantNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MergeNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinter.java graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinterObserver.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPhase.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCache.java graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeVerificationPhase.java
diffstat 18 files changed, 174 insertions(+), 58 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java	Thu Oct 24 12:25:29 2013 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java	Thu Oct 24 14:57:57 2013 +0200
@@ -26,6 +26,7 @@
 import static com.oracle.graal.api.code.ValueUtil.*;
 import static com.oracle.graal.api.meta.Value.*;
 import static com.oracle.graal.lir.LIRValueUtil.*;
+import static com.oracle.graal.nodes.ConstantNode.*;
 import static com.oracle.graal.phases.GraalOptions.*;
 
 import java.util.*;
@@ -66,6 +67,13 @@
     protected final DebugInfoBuilder debugInfoBuilder;
 
     protected Block currentBlock;
+
+    /**
+     * Maps constants the variables within the scope of a single block to avoid loading a constant
+     * more than once per block.
+     */
+    private Map<Constant, Variable> constantsLoadedInCurrentBlock;
+
     private ValueNode currentInstruction;
     private ValueNode lastInstructionPrinted; // Debugging only
 
@@ -151,7 +159,38 @@
         if (nodeOperands == null) {
             return null;
         }
-        return nodeOperands.get(node);
+        Value operand = nodeOperands.get(node);
+        if (operand == null) {
+            return getConstantOperand(node);
+        }
+        return operand;
+    }
+
+    private Value getConstantOperand(ValueNode node) {
+        if (!ConstantNodeRecordsUsages) {
+            Constant value = node.asConstant();
+            if (value != null) {
+                if (canInlineConstant(value)) {
+                    return setResult(node, value);
+                } else {
+                    Variable loadedValue;
+                    if (constantsLoadedInCurrentBlock == null) {
+                        constantsLoadedInCurrentBlock = new HashMap<>();
+                        loadedValue = null;
+                    } else {
+                        loadedValue = constantsLoadedInCurrentBlock.get(value);
+                    }
+                    if (loadedValue == null) {
+                        loadedValue = emitMove(value);
+                        constantsLoadedInCurrentBlock.put(value, loadedValue);
+                    }
+                    return loadedValue;
+                }
+            }
+        } else {
+            // Constant is loaded by ConstantNode.generate()
+        }
+        return null;
     }
 
     public ValueNode valueForOperand(Value value) {
@@ -188,7 +227,7 @@
     @Override
     public Value setResult(ValueNode x, Value operand) {
         assert (!isRegister(operand) || !attributes(asRegister(operand)).isAllocatable());
-        assert operand(x) == null : "operand cannot be set twice";
+        assert nodeOperands == null || nodeOperands.get(x) == null : "operand cannot be set twice";
         assert operand != null && isLegal(operand) : "operand must be legal";
         assert operand.getKind().getStackKind() == x.kind() || x.kind() == Kind.Illegal : operand.getKind().getStackKind() + " must match " + x.kind();
         assert !(x instanceof VirtualObjectNode);
@@ -296,6 +335,8 @@
         }
 
         currentBlock = block;
+        resetLoadedConstants();
+
         // set up the list of LIR instructions
         assert lir.lir(block) == null : "LIR list already computed for this block";
         lir.setLir(block, new ArrayList<LIRInstruction>());
@@ -319,7 +360,9 @@
             if (TraceLIRGeneratorLevel.getValue() >= 3) {
                 TTY.println("LIRGen for " + instr);
             }
-            if (instr instanceof ValueNode) {
+            if (!ConstantNodeRecordsUsages && instr instanceof ConstantNode) {
+                // Loading of constants is done lazily by operand()
+            } else if (instr instanceof ValueNode) {
                 ValueNode valueNode = (ValueNode) instr;
                 if (operand(valueNode) == null) {
                     if (!peephole(valueNode)) {
@@ -355,6 +398,12 @@
         }
     }
 
+    private void resetLoadedConstants() {
+        if (constantsLoadedInCurrentBlock != null && !constantsLoadedInCurrentBlock.isEmpty()) {
+            constantsLoadedInCurrentBlock.clear();
+        }
+    }
+
     protected abstract boolean peephole(ValueNode valueNode);
 
     private boolean endsWithJump(Block block) {
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java	Thu Oct 24 12:25:29 2013 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java	Thu Oct 24 14:57:57 2013 +0200
@@ -361,7 +361,7 @@
             int minCount = Integer.MAX_VALUE;
             Node minCountNode = null;
             for (Node input : node.inputs()) {
-                if (input != null) {
+                if (input != null && input.recordsUsages()) {
                     int estimate = input.getUsageCountUpperBound();
                     if (estimate == 0) {
                         return null;
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java	Thu Oct 24 12:25:29 2013 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java	Thu Oct 24 14:57:57 2013 +0200
@@ -255,6 +255,7 @@
     }
 
     int getUsageCountUpperBound() {
+        assert recordsUsages();
         if (usage0 == null) {
             return 0;
         }
@@ -265,13 +266,23 @@
     }
 
     /**
-     * Gets the list of nodes that use this node (e.g., as an input).
+     * Gets the list of nodes that use this node (i.e., as an input).
      */
     public final NodeIterable<Node> usages() {
+        assert recordsUsages() : this;
         return new NodeUsageIterable();
     }
 
     /**
+     * Determines if this node records its usages (i.e. the nodes for which it is an input). All
+     * methods in {@link Node} that pertain to querying or updating usage information must not be
+     * called for a {@link Node} instance that returns false for this method.
+     */
+    public boolean recordsUsages() {
+        return true;
+    }
+
+    /**
      * 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.
      * 
@@ -311,6 +322,7 @@
      * @param node the node to add
      */
     private void addUsage(Node node) {
+        assert recordsUsages();
         incUsageModCount();
         if (usage0 == null) {
             usage0 = node;
@@ -342,6 +354,7 @@
      * @return whether or not {@code usage} was in the usage list
      */
     private boolean removeUsage(Node node) {
+        assert recordsUsages();
         // It is critical that this method maintains the invariant that
         // the usage list has no null element preceding a non-null element
         incUsageModCount();
@@ -392,6 +405,7 @@
     }
 
     private void clearUsages() {
+        assert recordsUsages();
         incUsageModCount();
         usage0 = null;
         usage1 = null;
@@ -443,16 +457,20 @@
     protected void updateUsages(Node oldInput, Node newInput) {
         if (oldInput != newInput) {
             if (oldInput != null) {
-                boolean result = removeThisFromUsages(oldInput);
-                assert assertTrue(result, "not found in usages, old input: %s", oldInput);
+                if (oldInput.recordsUsages()) {
+                    boolean result = removeThisFromUsages(oldInput);
+                    assert assertTrue(result, "not found in usages, old input: %s", oldInput);
+                }
             }
             if (newInput != null) {
-                NodeChangedListener listener = graph.inputChangedListener;
-                if (listener != null) {
-                    listener.nodeChanged(this);
+                if (newInput.recordsUsages()) {
+                    NodeChangedListener listener = graph.inputChangedListener;
+                    if (listener != null) {
+                        listener.nodeChanged(this);
+                    }
+                    newInput.addUsage(this);
                 }
-                newInput.addUsage(this);
-            } else if (oldInput != null && oldInput.usages().isEmpty()) {
+            } else if (oldInput != null && oldInput.recordsUsages() && oldInput.usages().isEmpty()) {
                 NodeChangedListener listener = graph.usagesDroppedToZeroListener;
                 if (listener != null) {
                     listener.nodeChanged(oldInput);
@@ -513,7 +531,9 @@
                 if (listener != null) {
                     listener.nodeChanged(usage);
                 }
-                other.addUsage(usage);
+                if (other.recordsUsages()) {
+                    other.addUsage(usage);
+                }
             }
         }
         clearUsages();
@@ -554,11 +574,13 @@
         assert assertFalse(isDeleted(), "cannot clear inputs of deleted node");
 
         for (Node input : inputs()) {
-            removeThisFromUsages(input);
-            if (input.usages().isEmpty()) {
-                NodeChangedListener listener = graph.usagesDroppedToZeroListener;
-                if (listener != null) {
-                    listener.nodeChanged(input);
+            if (input.recordsUsages()) {
+                removeThisFromUsages(input);
+                if (input.usages().isEmpty()) {
+                    NodeChangedListener listener = graph.usagesDroppedToZeroListener;
+                    if (listener != null) {
+                        listener.nodeChanged(input);
+                    }
                 }
             }
         }
@@ -580,7 +602,9 @@
     }
 
     private boolean checkDeletion() {
-        assertTrue(usages().isEmpty(), "cannot delete node %s because of usages: %s", this, usages());
+        if (recordsUsages()) {
+            assertTrue(usages().isEmpty(), "cannot delete node %s because of usages: %s", this, usages());
+        }
         assertTrue(predecessor == null, "cannot delete node %s because of predecessor: %s", this, predecessor);
         return true;
     }
@@ -603,7 +627,9 @@
         NodeClass clazz = getNodeClass();
         clazz.copyInputs(this, newNode);
         for (Node input : inputs()) {
-            input.addUsage(newNode);
+            if (input.recordsUsages()) {
+                input.addUsage(newNode);
+            }
         }
         return newNode;
     }
@@ -676,16 +702,18 @@
         assertTrue(isAlive(), "cannot verify inactive nodes (id=%d)", id);
         assertTrue(graph() != null, "null graph");
         for (Node input : inputs()) {
-            assertTrue(input.usages().contains(this), "missing usage in input %s", input);
+            assertTrue(!input.recordsUsages() || input.usages().contains(this), "missing usage in input %s", input);
             assertTrue(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());
             assertTrue(successor.graph() == graph(), "mismatching graph in successor %s", successor);
         }
-        for (Node usage : usages()) {
-            assertFalse(usage.isDeleted(), "usage must never be deleted");
-            assertTrue(usage.inputs().contains(this), "missing input in usage %s", usage);
+        if (recordsUsages()) {
+            for (Node usage : usages()) {
+                assertFalse(usage.isDeleted(), "usage must never be deleted");
+                assertTrue(usage.inputs().contains(this), "missing input in usage %s", usage);
+            }
         }
         if (predecessor != null) {
             assertFalse(predecessor.isDeleted(), "predecessor must never be deleted");
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java	Thu Oct 24 12:25:29 2013 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java	Thu Oct 24 14:57:57 2013 +0200
@@ -1313,7 +1313,7 @@
                     newNodes.put(node, replacement);
                 } else {
                     Node newNode = node.clone(graph, false);
-                    assert newNode.usages().count() == 0 || newNode.inputs().count() == 0;
+                    assert newNode.inputs().count() == 0 || newNode.usages().count() == 0;
                     assert newNode.getClass() == node.getClass();
                     newNodes.put(node, newNode);
                 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotOptions.java	Thu Oct 24 12:25:29 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotOptions.java	Thu Oct 24 14:57:57 2013 +0200
@@ -174,7 +174,7 @@
         if (value != null) {
             OptionValue<?> optionValue = desc.getOptionValue();
             optionValue.setValue(value);
-            // Logger.info("Set option " + fieldName + " to " + value);
+            // Logger.info("Set option " + desc.getName() + " to " + value);
         } else {
             Logger.info("Wrong value \"" + valueString + "\" for option " + optionName);
             return false;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConstantNode.java	Thu Oct 24 12:25:29 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConstantNode.java	Thu Oct 24 14:57:57 2013 +0200
@@ -45,6 +45,17 @@
     }
 
     /**
+     * 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 = Boolean.getBoolean("graal.constantNodeRecordsUsages");
+
+    @Override
+    public boolean recordsUsages() {
+        return ConstantNodeRecordsUsages;
+    }
+
+    /**
      * Constructs a new ConstantNode representing the specified constant.
      * 
      * @param value the constant
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MergeNode.java	Thu Oct 24 12:25:29 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MergeNode.java	Thu Oct 24 14:57:57 2013 +0200
@@ -90,7 +90,7 @@
             }
             ValueNode removedValue = phi.valueAt(predIndex);
             phi.removeInput(predIndex);
-            if (removedValue != null && removedValue.isAlive() && removedValue.usages().isEmpty() && GraphUtil.isFloatingNode().apply(removedValue)) {
+            if (removedValue != null && removedValue.isAlive() && removedValue.recordsUsages() && removedValue.usages().isEmpty() && GraphUtil.isFloatingNode().apply(removedValue)) {
                 GraphUtil.killWithUnusedFloatingInputs(removedValue);
             }
         }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java	Thu Oct 24 12:25:29 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java	Thu Oct 24 14:57:57 2013 +0200
@@ -123,13 +123,17 @@
     }
 
     public static void killWithUnusedFloatingInputs(Node node) {
-        List<Node> floatingInputs = node.inputs().filter(isFloatingNode()).snapshot();
-        node.safeDelete();
+        if (node.recordsUsages()) {
+            List<Node> floatingInputs = node.inputs().filter(isFloatingNode()).snapshot();
+            node.safeDelete();
 
-        for (Node in : floatingInputs) {
-            if (in.isAlive() && in.usages().isEmpty()) {
-                killWithUnusedFloatingInputs(in);
+            for (Node in : floatingInputs) {
+                if (in.isAlive() && (!in.recordsUsages() || in.usages().isEmpty())) {
+                    killWithUnusedFloatingInputs(in);
+                }
             }
+        } else {
+            assert node.inputs().isEmpty();
         }
     }
 
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java	Thu Oct 24 12:25:29 2013 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java	Thu Oct 24 14:57:57 2013 +0200
@@ -206,7 +206,7 @@
         }
 
         private static boolean tryKillUnused(Node node) {
-            if (node.isAlive() && GraphUtil.isFloatingNode().apply(node) && node.usages().isEmpty()) {
+            if (node.isAlive() && GraphUtil.isFloatingNode().apply(node) && node.recordsUsages() && node.usages().isEmpty()) {
                 GraphUtil.killWithUnusedFloatingInputs(node);
                 return true;
             }
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java	Thu Oct 24 12:25:29 2013 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java	Thu Oct 24 14:57:57 2013 +0200
@@ -631,8 +631,10 @@
             cdbc.apply(cfg.getNodeToBlock().get(succ));
         }
         ensureScheduledUsages(node, strategy);
-        for (Node usage : node.usages()) {
-            blocksForUsage(node, usage, cdbc, strategy);
+        if (node.recordsUsages()) {
+            for (Node usage : node.usages()) {
+                blocksForUsage(node, usage, cdbc, strategy);
+            }
         }
         List<FixedNode> usages = phantomUsages.get(node);
         if (usages != null) {
@@ -808,8 +810,10 @@
     }
 
     private void ensureScheduledUsages(Node node, SchedulingStrategy strategy) {
-        for (Node usage : node.usages().filter(ScheduledNode.class)) {
-            assignBlockToNode((ScheduledNode) usage, strategy);
+        if (node.recordsUsages()) {
+            for (Node usage : node.usages().filter(ScheduledNode.class)) {
+                assignBlockToNode((ScheduledNode) usage, strategy);
+            }
         }
         // now true usages are ready
     }
@@ -1057,14 +1061,16 @@
             }
 
             visited.mark(instruction);
-            for (Node usage : instruction.usages()) {
-                if (usage instanceof VirtualState) {
-                    // only fixed nodes can have VirtualState -> no need to schedule them
-                } else {
-                    if (instruction instanceof LoopExitNode && usage instanceof ProxyNode) {
-                        // value proxies should be scheduled before the loopexit, not after
+            if (instruction.recordsUsages()) {
+                for (Node usage : instruction.usages()) {
+                    if (usage instanceof VirtualState) {
+                        // only fixed nodes can have VirtualState -> no need to schedule them
                     } else {
-                        addToEarliestSorting(b, (ScheduledNode) usage, sortedInstructions, visited);
+                        if (instruction instanceof LoopExitNode && usage instanceof ProxyNode) {
+                            // value proxies should be scheduled before the loopexit, not after
+                        } else {
+                            addToEarliestSorting(b, (ScheduledNode) usage, sortedInstructions, visited);
+                        }
                     }
                 }
             }
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinter.java	Thu Oct 24 12:25:29 2013 +0200
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinter.java	Thu Oct 24 14:57:57 2013 +0200
@@ -327,7 +327,7 @@
         out.println("=== Succesors ===");
         printNamedNodes(node, node.successors().iterator(), "", "\n", null);
         out.println("=== Usages ===");
-        if (!node.usages().isEmpty()) {
+        if (node.recordsUsages() && !node.usages().isEmpty()) {
             for (Node usage : node.usages()) {
                 out.print(nodeToString(usage)).print(" ");
             }
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinterObserver.java	Thu Oct 24 12:25:29 2013 +0200
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinterObserver.java	Thu Oct 24 14:57:57 2013 +0200
@@ -94,7 +94,7 @@
             return false;
         }
 
-        if (method != curMethod || !curDecorators.equals(decorators)) {
+        if (!method.equals(curMethod) || !curDecorators.equals(decorators)) {
             cfgPrinter.printCompilation(method);
             TTY.println("CFGPrinter: Dumping method %s to %s", method, cfgFile);
             curMethod = method;
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPhase.java	Thu Oct 24 12:25:29 2013 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPhase.java	Thu Oct 24 14:57:57 2013 +0200
@@ -321,7 +321,8 @@
     }
 
     public void cleanUpReturnCheckCast(Node newInstance) {
-        if (newInstance instanceof ValueNode && (((ValueNode) newInstance).kind() != Kind.Object || ((ValueNode) newInstance).stamp() == StampFactory.forNodeIntrinsic())) {
+        if (newInstance.recordsUsages() && newInstance instanceof ValueNode &&
+                        (((ValueNode) newInstance).kind() != Kind.Object || ((ValueNode) newInstance).stamp() == StampFactory.forNodeIntrinsic())) {
             StructuredGraph graph = (StructuredGraph) newInstance.graph();
             for (CheckCastNode checkCastNode : newInstance.usages().filter(CheckCastNode.class).snapshot()) {
                 for (Node checkCastUsage : checkCastNode.usages().snapshot()) {
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java	Thu Oct 24 12:25:29 2013 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java	Thu Oct 24 14:57:57 2013 +0200
@@ -273,6 +273,20 @@
         }
     }
 
+    static class VarargsPlaceholderNode extends FloatingNode implements ArrayLengthProvider {
+
+        final Varargs varargs;
+
+        public VarargsPlaceholderNode(Varargs varargs, MetaAccessProvider metaAccess) {
+            super(StampFactory.exactNonNull(metaAccess.lookupJavaType(varargs.componentType).getArrayClass()));
+            this.varargs = varargs;
+        }
+
+        public ValueNode length() {
+            return ConstantNode.forInt(varargs.length, graph());
+        }
+    }
+
     static class CacheKey {
 
         private final ResolvedJavaMethod method;
@@ -411,7 +425,7 @@
         assert checkTemplate(metaAccess, args, method, signature);
 
         int parameterCount = args.info.getParameterCount();
-        ConstantNode[] placeholders = new ConstantNode[parameterCount];
+        VarargsPlaceholderNode[] placeholders = new VarargsPlaceholderNode[parameterCount];
 
         for (int i = 0; i < parameterCount; i++) {
             if (args.info.isConstantParameter(i)) {
@@ -426,8 +440,7 @@
                 nodeReplacements.put(snippetGraph.getLocal(i), ConstantNode.forConstant(constantArg, metaAccess, snippetCopy));
             } else if (args.info.isVarargsParameter(i)) {
                 Varargs varargs = (Varargs) args.values[i];
-                Object array = Array.newInstance(varargs.componentType, varargs.length);
-                ConstantNode placeholder = ConstantNode.forObject(array, metaAccess, snippetCopy);
+                VarargsPlaceholderNode placeholder = snippetCopy.unique(new VarargsPlaceholderNode(varargs, providers.getMetaAccess()));
                 nodeReplacements.put(snippetGraph.getLocal(i), placeholder);
                 placeholders[i] = placeholder;
             }
@@ -461,7 +474,7 @@
                 }
                 parameters[i] = locals;
 
-                ConstantNode placeholder = placeholders[i];
+                VarargsPlaceholderNode placeholder = placeholders[i];
                 assert placeholder != null;
                 for (Node usage : placeholder.usages().snapshot()) {
                     if (usage instanceof LoadIndexedNode) {
@@ -584,7 +597,7 @@
         this.returnNode = retNode;
     }
 
-    private static boolean checkAllVarargPlaceholdersAreDeleted(int parameterCount, ConstantNode[] placeholders) {
+    private static boolean checkAllVarargPlaceholdersAreDeleted(int parameterCount, VarargsPlaceholderNode[] placeholders) {
         for (int i = 0; i < parameterCount; i++) {
             if (placeholders[i] != null) {
                 assert placeholders[i].isDeleted() : placeholders[i];
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Thu Oct 24 12:25:29 2013 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Thu Oct 24 14:57:57 2013 +0200
@@ -237,13 +237,12 @@
                 ValueNode arg = arguments.get(local.index());
                 if (arg.isConstant()) {
                     Constant constant = arg.asConstant();
-                    ConstantNode constantNode = ConstantNode.forConstant(constant, phaseContext.getMetaAccess(), graphCopy);
-                    local.replaceAndDelete(constantNode);
-                    for (Node usage : constantNode.usages()) {
+                    for (Node usage : local.usages()) {
                         if (usage instanceof Canonicalizable) {
                             modifiedNodes.add(usage);
                         }
                     }
+                    local.replaceAndDelete(ConstantNode.forConstant(constant, phaseContext.getMetaAccess(), graphCopy));
                 }
             }
             Debug.scope("TruffleUnrollLoop", targetMethod, new Runnable() {
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCache.java	Thu Oct 24 12:25:29 2013 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCache.java	Thu Oct 24 14:57:57 2013 +0200
@@ -156,7 +156,7 @@
                             int beforeInvokeMark = graph.getMark();
                             expandInvoke(methodCallTarget);
                             for (Node arg : argumentSnapshot) {
-                                if (arg != null) {
+                                if (arg != null && arg.recordsUsages()) {
                                     for (Node argUsage : arg.usages()) {
                                         if (graph.isNew(beforeInvokeMark, argUsage) && argUsage instanceof Canonicalizable) {
                                             canonicalizerUsages.add(argUsage);
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java	Thu Oct 24 12:25:29 2013 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java	Thu Oct 24 14:57:57 2013 +0200
@@ -531,8 +531,10 @@
     void addAndMarkAlias(VirtualObjectNode virtual, ValueNode node) {
         if (node.isAlive()) {
             aliases.set(node, virtual);
-            for (Node usage : node.usages()) {
-                markVirtualUsages(usage);
+            if (node.recordsUsages()) {
+                for (Node usage : node.usages()) {
+                    markVirtualUsages(usage);
+                }
             }
         }
     }
--- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeVerificationPhase.java	Thu Oct 24 12:25:29 2013 +0200
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeVerificationPhase.java	Thu Oct 24 14:57:57 2013 +0200
@@ -61,6 +61,9 @@
         wordAccess.inferStamps(graph);
 
         for (ValueNode node : graph.getNodes().filter(ValueNode.class)) {
+            if (!node.recordsUsages()) {
+                continue;
+            }
             for (Node usage : node.usages()) {
                 if (usage instanceof AccessMonitorNode) {
                     verify(!isWord(node), node, usage, "word value has no monitor");