changeset 12581:8fde330c11cd

Merge.
author Doug Simon <doug.simon@oracle.com>
date Fri, 25 Oct 2013 01:26:27 +0200
parents 7876c59a7a2f (current diff) 04e51b3026c0 (diff)
children a5a4a0bcd863
files graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotForeignCallsProvider.java
diffstat 32 files changed, 450 insertions(+), 177 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ConditionalEliminationTest.java	Fri Oct 25 01:24:19 2013 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ConditionalEliminationTest.java	Fri Oct 25 01:26:27 2013 +0200
@@ -22,6 +22,7 @@
  */
 package com.oracle.graal.compiler.test;
 
+import static com.oracle.graal.nodes.ConstantNode.*;
 import static com.oracle.graal.nodes.extended.BranchProbabilityNode.*;
 import static org.junit.Assert.*;
 
@@ -144,7 +145,9 @@
         new ConditionalEliminationPhase(getMetaAccess()).apply(graph);
         new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), null));
         for (ConstantNode constant : graph.getNodes().filter(ConstantNode.class)) {
-            assertTrue("unexpected constant: " + constant, constant.asConstant().isNull() || constant.asConstant().asInt() > 0);
+            if (ConstantNodeRecordsUsages || !constant.gatherUsages().isEmpty()) {
+                assertTrue("unexpected constant: " + constant, constant.asConstant().isNull() || constant.asConstant().asInt() > 0);
+            }
         }
     }
 
@@ -176,7 +179,9 @@
         new ConditionalEliminationPhase(getMetaAccess()).apply(graph);
         new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), null));
         for (ConstantNode constant : graph.getNodes().filter(ConstantNode.class)) {
-            assertTrue("unexpected constant: " + constant, constant.asConstant().isNull() || constant.asConstant().asInt() > 0);
+            if (ConstantNodeRecordsUsages || !constant.gatherUsages().isEmpty()) {
+                assertTrue("unexpected constant: " + constant, constant.asConstant().isNull() || constant.asConstant().asInt() > 0);
+            }
         }
     }
 
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java	Fri Oct 25 01:24:19 2013 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java	Fri Oct 25 01:26:27 2013 +0200
@@ -23,6 +23,7 @@
 package com.oracle.graal.compiler.test;
 
 import static com.oracle.graal.api.code.CodeUtil.*;
+import static com.oracle.graal.nodes.ConstantNode.*;
 import static com.oracle.graal.phases.GraalOptions.*;
 
 import java.io.*;
@@ -116,12 +117,32 @@
         assertEquals(expected, graph, false);
     }
 
+    protected int countUnusedConstants(StructuredGraph graph) {
+        int total = 0;
+        for (ConstantNode node : graph.getNodes().filter(ConstantNode.class)) {
+            if (!ConstantNodeRecordsUsages) {
+                if (node.gatherUsages().isEmpty()) {
+                    total++;
+                }
+            } else {
+                if (node.usages().isEmpty()) {
+                    total++;
+                }
+            }
+        }
+        return total;
+    }
+
+    protected int getNodeCountExcludingUnusedConstants(StructuredGraph graph) {
+        return graph.getNodeCount() - countUnusedConstants(graph);
+    }
+
     protected void assertEquals(StructuredGraph expected, StructuredGraph graph, boolean excludeVirtual) {
         String expectedString = getCanonicalGraphString(expected, excludeVirtual);
         String actualString = getCanonicalGraphString(graph, excludeVirtual);
         String mismatchString = "mismatch in graphs:\n========= expected =========\n" + expectedString + "\n\n========= actual =========\n" + actualString;
 
-        if (!excludeVirtual && expected.getNodeCount() != graph.getNodeCount()) {
+        if (!excludeVirtual && getNodeCountExcludingUnusedConstants(expected) != getNodeCountExcludingUnusedConstants(graph)) {
             Debug.dump(expected, "Node count not matching - expected");
             Debug.dump(graph, "Node count not matching - actual");
             Assert.fail("Graphs do not have the same number of nodes: " + expected.getNodeCount() + " vs. " + graph.getNodeCount() + "\n" + mismatchString);
@@ -161,16 +182,18 @@
             }
             result.append("\n");
             for (Node node : schedule.getBlockToNodesMap().get(block)) {
-                if (!excludeVirtual || !(node instanceof VirtualObjectNode || node instanceof ProxyNode)) {
-                    int id;
-                    if (canonicalId.get(node) != null) {
-                        id = canonicalId.get(node);
-                    } else {
-                        id = nextId++;
-                        canonicalId.set(node, id);
+                if (node.recordsUsages()) {
+                    if (!excludeVirtual || !(node instanceof VirtualObjectNode || node instanceof ProxyNode)) {
+                        int id;
+                        if (canonicalId.get(node) != null) {
+                            id = canonicalId.get(node);
+                        } else {
+                            id = nextId++;
+                            canonicalId.set(node, id);
+                        }
+                        String name = node instanceof ConstantNode ? node.toString(Verbosity.Name) : node.getClass().getSimpleName();
+                        result.append("  " + id + "|" + name + (excludeVirtual ? "\n" : "    (" + node.usages().count() + ")\n"));
                     }
-                    String name = node instanceof ConstantNode ? node.toString(Verbosity.Name) : node.getClass().getSimpleName();
-                    result.append("  " + id + "|" + name + (excludeVirtual ? "\n" : "    (" + node.usages().count() + ")\n"));
                 }
             }
         }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/TypeSystemTest.java	Fri Oct 25 01:24:19 2013 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/TypeSystemTest.java	Fri Oct 25 01:26:27 2013 +0200
@@ -197,7 +197,7 @@
 
     @Override
     protected void assertEquals(StructuredGraph expected, StructuredGraph graph) {
-        if (expected.getNodeCount() != graph.getNodeCount()) {
+        if (getNodeCountExcludingUnusedConstants(expected) != getNodeCountExcludingUnusedConstants(graph)) {
             outputGraph(expected, "expected");
             outputGraph(graph, "actual");
             Assert.fail("Graphs do not have the same number of nodes: " + expected.getNodeCount() + " vs. " + graph.getNodeCount());
@@ -225,7 +225,7 @@
     }
 
     private static void outputNode(Node node) {
-        TTY.print("  " + node + "    (usage count: " + node.usages().count() + ") (inputs:");
+        TTY.print("  " + node + "    (usage count: " + (node.recordsUsages() ? node.usages().count() : "?") + ") (inputs:");
         for (Node input : node.inputs()) {
             TTY.print(" " + input.toString(Verbosity.Id));
         }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/deopt/CompiledMethodTest.java	Fri Oct 25 01:24:19 2013 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/deopt/CompiledMethodTest.java	Fri Oct 25 01:26:27 2013 +0200
@@ -63,7 +63,7 @@
             if (node instanceof ConstantNode) {
                 ConstantNode constant = (ConstantNode) node;
                 if (constant.kind() == Kind.Object && " ".equals(constant.value.asObject())) {
-                    graph.replaceFloating(constant, ConstantNode.forObject("-", getMetaAccess(), graph));
+                    constant.replace(ConstantNode.forObject("-", getMetaAccess(), graph));
                 }
             }
         }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java	Fri Oct 25 01:24:19 2013 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java	Fri Oct 25 01:26:27 2013 +0200
@@ -869,8 +869,7 @@
 
         // check that the liveIn set of the first block is empty
         Block startBlock = ir.cfg.getStartBlock();
-        BitSet liveInArgs = new BitSet(blockData.get(startBlock).liveIn.size());
-        if (!blockData.get(startBlock).liveIn.equals(liveInArgs)) {
+        if (blockData.get(startBlock).liveIn.cardinality() != 0) {
             if (DetailedAsserts.getValue()) {
                 reportFailure(numBlocks);
             }
@@ -878,73 +877,76 @@
             TTY.println("preds=" + startBlock.getPredecessorCount() + ", succs=" + startBlock.getSuccessorCount());
             TTY.println("startBlock-ID: " + startBlock.getId());
 
-            // bailout of if this occurs in product mode.
-            throw new GraalInternalError("liveIn set of first block must be empty");
+            // bailout if this occurs in product mode.
+            throw new GraalInternalError("liveIn set of first block must be empty: " + blockData.get(startBlock).liveIn);
         }
     }
 
     private void reportFailure(int numBlocks) {
         TTY.println(gen.getGraph().toString());
-        TTY.println("Error: liveIn set of first block must be empty (when this fails, variables are used before they are defined)");
-        TTY.print("affected registers:");
-        TTY.println(blockData.get(ir.cfg.getStartBlock()).liveIn.toString());
+        TTY.println("Error: liveIn set of first block must be empty (when this fails, variables are used before they are defined):");
+        BitSet startBlockLiveIn = blockData.get(ir.cfg.getStartBlock()).liveIn;
+        for (int operandNum = startBlockLiveIn.nextSetBit(0); operandNum >= 0; operandNum = startBlockLiveIn.nextSetBit(operandNum + 1)) {
+            Value operand = operandFor(operandNum);
+            TTY.println("  var %d; operand=%s; node=%s", operandNum, operand.toString(), gen.valueForOperand(operand));
+        }
 
         // print some additional information to simplify debugging
-        for (int operandNum = 0; operandNum < blockData.get(ir.cfg.getStartBlock()).liveIn.size(); operandNum++) {
-            if (blockData.get(ir.cfg.getStartBlock()).liveIn.get(operandNum)) {
-                Value operand = operandFor(operandNum);
-                TTY.println(" var %d; operand=%s; node=%s", operandNum, operand.toString(), gen.valueForOperand(operand));
+        for (int operandNum = startBlockLiveIn.nextSetBit(0); operandNum >= 0; operandNum = startBlockLiveIn.nextSetBit(operandNum + 1)) {
+            Value operand = operandFor(operandNum);
+            TTY.println("---- Detailed information for var %d; operand=%s; node=%s ----", operandNum, operand.toString(), gen.valueForOperand(operand));
+
+            Deque<Block> definedIn = new ArrayDeque<>();
+            HashSet<Block> usedIn = new HashSet<>();
+            for (Block block : sortedBlocks) {
+                if (blockData.get(block).liveGen.get(operandNum)) {
+                    usedIn.add(block);
+                    TTY.println("used in block B%d {", block.getId());
+                    for (LIRInstruction ins : ir.lir(block)) {
+                        TTY.println("  " + ins.id() + ": " + ins.toString());
+                        ins.forEachState(new ValueProcedure() {
 
-                Deque<Block> definedIn = new ArrayDeque<>();
-                HashSet<Block> usedIn = new HashSet<>();
-                for (Block block : sortedBlocks) {
-                    if (blockData.get(block).liveGen.get(operandNum)) {
-                        usedIn.add(block);
-                        TTY.println("  used in block B%d", block.getId());
-                        for (LIRInstruction ins : ir.lir(block)) {
-                            TTY.println(ins.id() + ": " + ins.toString());
-                            ins.forEachState(new ValueProcedure() {
+                            @Override
+                            public Value doValue(Value liveStateOperand) {
+                                TTY.println("    operand=" + liveStateOperand);
+                                return liveStateOperand;
+                            }
+                        });
+                    }
+                    TTY.println("}");
+                }
+                if (blockData.get(block).liveKill.get(operandNum)) {
+                    definedIn.add(block);
+                    TTY.println("defined in block B%d {", block.getId());
+                    for (LIRInstruction ins : ir.lir(block)) {
+                        TTY.println("  " + ins.id() + ": " + ins.toString());
+                    }
+                    TTY.println("}");
+                }
+            }
 
-                                @Override
-                                public Value doValue(Value liveStateOperand) {
-                                    TTY.println("   operand=" + liveStateOperand);
-                                    return liveStateOperand;
-                                }
-                            });
+            int[] hitCount = new int[numBlocks];
+
+            while (!definedIn.isEmpty()) {
+                Block block = definedIn.removeFirst();
+                usedIn.remove(block);
+                for (Block successor : block.getSuccessors()) {
+                    if (successor.isLoopHeader()) {
+                        if (!block.isLoopEnd()) {
+                            definedIn.add(successor);
                         }
-                    }
-                    if (blockData.get(block).liveKill.get(operandNum)) {
-                        definedIn.add(block);
-                        TTY.println("  defined in block B%d", block.getId());
-                        for (LIRInstruction ins : ir.lir(block)) {
-                            TTY.println(ins.id() + ": " + ins.toString());
+                    } else {
+                        if (++hitCount[successor.getId()] == successor.getPredecessorCount()) {
+                            definedIn.add(successor);
                         }
                     }
                 }
-
-                int[] hitCount = new int[numBlocks];
-
-                while (!definedIn.isEmpty()) {
-                    Block block = definedIn.removeFirst();
-                    usedIn.remove(block);
-                    for (Block successor : block.getSuccessors()) {
-                        if (successor.isLoopHeader()) {
-                            if (!block.isLoopEnd()) {
-                                definedIn.add(successor);
-                            }
-                        } else {
-                            if (++hitCount[successor.getId()] == successor.getPredecessorCount()) {
-                                definedIn.add(successor);
-                            }
-                        }
-                    }
-                }
-                TTY.print("  offending usages are in: ");
-                for (Block block : usedIn) {
-                    TTY.print("B%d ", block.getId());
-                }
-                TTY.println();
             }
+            TTY.print("**** offending usages are in: ");
+            for (Block block : usedIn) {
+                TTY.print("B%d ", block.getId());
+            }
+            TTY.println();
         }
     }
 
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java	Fri Oct 25 01:24:19 2013 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java	Fri Oct 25 01:26:27 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	Fri Oct 25 01:24:19 2013 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java	Fri Oct 25 01:26:27 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	Fri Oct 25 01:24:19 2013 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java	Fri Oct 25 01:26:27 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	Fri Oct 25 01:24:19 2013 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java	Fri Oct 25 01:26:27 2013 +0200
@@ -1315,7 +1315,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	Fri Oct 25 01:24:19 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotOptions.java	Fri Oct 25 01:26:27 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.hotspot/src/com/oracle/graal/hotspot/phases/AheadOfTimeVerificationPhase.java	Fri Oct 25 01:24:19 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/AheadOfTimeVerificationPhase.java	Fri Oct 25 01:26:27 2013 +0200
@@ -39,7 +39,9 @@
     @Override
     protected boolean verify(StructuredGraph graph, PhaseContext context) {
         for (ConstantNode node : graph.getNodes().filter(ConstantNode.class)) {
-            assert !isObject(node) || isNullReference(node) || isInternedString(node) : "illegal object constant: " + node;
+            if (node.recordsUsages() || !node.gatherUsages().isEmpty()) {
+                assert !isObject(node) || isNullReference(node) || isInternedString(node) : "illegal object constant: " + node;
+            }
         }
         return true;
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/LoadJavaMirrorWithKlassPhase.java	Fri Oct 25 01:24:19 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/LoadJavaMirrorWithKlassPhase.java	Fri Oct 25 01:26:27 2013 +0200
@@ -68,7 +68,7 @@
                 LocationNode location = graph.unique(ConstantLocationNode.create(FINAL_LOCATION, stamp.kind(), classMirrorOffset, graph));
                 FloatingReadNode freadNode = graph.unique(new FloatingReadNode(klassNode, location, null, stamp));
 
-                graph.replaceFloating(node, freadNode);
+                node.replace(freadNode);
             }
         }
     }
--- a/graal/com.oracle.graal.nodes.test/src/com/oracle/graal/nodes/test/IntegerStampTest.java	Fri Oct 25 01:24:19 2013 +0200
+++ b/graal/com.oracle.graal.nodes.test/src/com/oracle/graal/nodes/test/IntegerStampTest.java	Fri Oct 25 01:26:27 2013 +0200
@@ -174,6 +174,13 @@
                         StampTool.add(StampFactory.forInteger(Kind.Long, Long.MIN_VALUE, Long.MIN_VALUE + 1), StampFactory.forInteger(Kind.Long, Integer.MIN_VALUE, Integer.MAX_VALUE)));
         assertEquals(StampFactory.forInteger(Kind.Int, -2147483647, 31 - 2147483647),
                         StampTool.add(StampFactory.forInteger(Kind.Int, 0, 31), StampFactory.forInteger(Kind.Int, -2147483647, -2147483647)));
+
+        assertEquals(StampFactory.forInteger(Kind.Int, 0x8000007e, 0x8000007f, 0x8000007eL, 0x8000007fL),
+                        StampTool.add(StampFactory.forInteger(Kind.Int, 0x7ffffffe, 0x7fffffff, 0x7ffffffeL, 0x7fffffffL), StampFactory.forInteger(Kind.Int, 128, 128)));
+
+        assertEquals(StampFactory.forInteger(Kind.Long, -9223372036854775808L, 9223372036854775806L, 0, 0xfffffffffffffffeL),
+                        StampTool.add(StampFactory.forInteger(Kind.Long, -9223372036854775808L, 9223372036854775806L, 0, 0xfffffffffffffffeL),
+                                        StampFactory.forInteger(Kind.Long, -9223372036854775808L, 9223372036854775806L, 0, 0xfffffffffffffffeL)));
     }
 
     @Test
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConstantNode.java	Fri Oct 25 01:24:19 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConstantNode.java	Fri Oct 25 01:26:27 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
@@ -54,6 +65,35 @@
         this.value = value;
     }
 
+    /**
+     * 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.
+     */
+    public List<Node> gatherUsages() {
+        assert !ConstantNodeRecordsUsages;
+        List<Node> usages = new ArrayList<>();
+        for (Node node : graph().getNodes()) {
+            for (Node input : node.inputs()) {
+                if (input == this) {
+                    usages.add(node);
+                }
+            }
+        }
+        return usages;
+    }
+
+    public void replace(Node replacement) {
+        if (!recordsUsages()) {
+            List<Node> usages = gatherUsages();
+            for (Node usage : usages) {
+                usage.replaceFirstInput(this, replacement);
+            }
+            graph().removeFloating(this);
+        } else {
+            graph().replaceFloating(this, replacement);
+        }
+    }
+
     @Override
     public void generate(LIRGeneratorTool gen) {
         if (gen.canInlineConstant(value) || onlyUsedInVirtualState()) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MergeNode.java	Fri Oct 25 01:24:19 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MergeNode.java	Fri Oct 25 01:26:27 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/type/StampTool.java	Fri Oct 25 01:24:19 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/StampTool.java	Fri Oct 25 01:26:27 2013 +0200
@@ -114,13 +114,23 @@
         return StampFactory.forKind(kind);
     }
 
-    private static boolean addOverflows(long x, long y, Kind kind) {
+    private static boolean addOverflowsPositively(long x, long y, Kind kind) {
         long result = x + y;
         if (kind == Kind.Long) {
-            return ((x ^ result) & (y ^ result)) < 0;
+            return (~x & ~y & result) < 0;
         } else {
             assert kind == Kind.Int;
-            return result > Integer.MAX_VALUE || result < Integer.MIN_VALUE;
+            return result > Integer.MAX_VALUE;
+        }
+    }
+
+    private static boolean addOverflowsNegatively(long x, long y, Kind kind) {
+        long result = x + y;
+        if (kind == Kind.Long) {
+            return (x & y & ~result) < 0;
+        } else {
+            assert kind == Kind.Int;
+            return result < Integer.MIN_VALUE;
         }
     }
 
@@ -142,16 +152,22 @@
 
             long lowerBound;
             long upperBound;
-            if (addOverflows(stamp1.lowerBound(), stamp2.lowerBound(), kind) || addOverflows(stamp1.upperBound(), stamp2.upperBound(), kind)) {
+            boolean lowerOverflowsPositively = addOverflowsPositively(stamp1.lowerBound(), stamp2.lowerBound(), kind);
+            boolean upperOverflowsPositively = addOverflowsPositively(stamp1.upperBound(), stamp2.upperBound(), kind);
+            boolean lowerOverflowsNegatively = addOverflowsNegatively(stamp1.lowerBound(), stamp2.lowerBound(), kind);
+            boolean upperOverflowsNegatively = addOverflowsNegatively(stamp1.upperBound(), stamp2.upperBound(), kind);
+            if ((lowerOverflowsNegatively && !upperOverflowsNegatively) || (!lowerOverflowsNegatively && !lowerOverflowsPositively && upperOverflowsPositively)) {
                 lowerBound = kind.getMinValue();
                 upperBound = kind.getMaxValue();
             } else {
-                lowerBound = stamp1.lowerBound() + stamp2.lowerBound();
-                upperBound = stamp1.upperBound() + stamp2.upperBound();
+                lowerBound = signExtend(stamp1.lowerBound() + stamp2.lowerBound(), kind);
+                upperBound = signExtend(stamp1.upperBound() + stamp2.upperBound(), kind);
             }
             IntegerStamp limit = StampFactory.forInteger(kind, lowerBound, upperBound);
             newUpMask &= limit.upMask();
-            return new IntegerStamp(kind, lowerBound | newDownMask, signExtend(upperBound & newUpMask, kind), newDownMask, newUpMask);
+            upperBound = signExtend(upperBound & newUpMask, kind);
+            lowerBound |= newDownMask;
+            return new IntegerStamp(kind, lowerBound, upperBound, newDownMask, newUpMask);
         } catch (Throwable e) {
             throw new RuntimeException(stamp1 + " + " + stamp2, e);
         }
@@ -239,14 +255,15 @@
                 long lowerBound;
                 long upperBound;
                 long downMask = value.downMask() >>> shiftCount;
+                long upMask = value.upMask() >>> shiftCount;
                 if (value.lowerBound() < 0) {
                     lowerBound = downMask;
-                    upperBound = IntegerStamp.defaultMask(kind) >>> shiftCount;
+                    upperBound = upMask;
                 } else {
                     lowerBound = value.lowerBound() >>> shiftCount;
                     upperBound = value.upperBound() >>> shiftCount;
                 }
-                return new IntegerStamp(kind, lowerBound, upperBound, downMask, value.upMask() >>> shiftCount);
+                return new IntegerStamp(kind, lowerBound, upperBound, downMask, upMask);
             }
         }
         long mask = IntegerStamp.upMaskFor(kind, value.lowerBound(), value.upperBound());
@@ -310,7 +327,7 @@
     }
 
     private static long signExtend(long value, Kind valueKind) {
-        if (valueKind != Kind.Char && (value >>> (valueKind.getBitCount() - 1) & 1) == 1) {
+        if (valueKind != Kind.Char && valueKind != Kind.Long && (value >>> (valueKind.getBitCount() - 1) & 1) == 1) {
             return value | (-1L << valueKind.getBitCount());
         } else {
             return value;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java	Fri Oct 25 01:24:19 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java	Fri Oct 25 01:26:27 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	Fri Oct 25 01:24:19 2013 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java	Fri Oct 25 01:26:27 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	Fri Oct 25 01:24:19 2013 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java	Fri Oct 25 01:26:27 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	Fri Oct 25 01:24:19 2013 +0200
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinter.java	Fri Oct 25 01:26:27 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	Fri Oct 25 01:24:19 2013 +0200
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinterObserver.java	Fri Oct 25 01:26:27 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	Fri Oct 25 01:24:19 2013 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPhase.java	Fri Oct 25 01:26:27 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	Fri Oct 25 01:24:19 2013 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java	Fri Oct 25 01:26:27 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	Fri Oct 25 01:24:19 2013 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Fri Oct 25 01:26:27 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	Fri Oct 25 01:24:19 2013 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCache.java	Fri Oct 25 01:26:27 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	Fri Oct 25 01:24:19 2013 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java	Fri Oct 25 01:26:27 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	Fri Oct 25 01:24:19 2013 +0200
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeVerificationPhase.java	Fri Oct 25 01:26:27 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");
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/Utils.java	Fri Oct 25 01:24:19 2013 +0200
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/Utils.java	Fri Oct 25 01:26:27 2013 +0200
@@ -306,7 +306,7 @@
             case LONG:
                 return "Long";
             case DECLARED:
-                return ((DeclaredType) mirror).asElement().getSimpleName().toString();
+                return fixECJBinaryNameIssue(((DeclaredType) mirror).asElement().getSimpleName().toString());
             case ARRAY:
                 return getTypeId(((ArrayType) mirror).getComponentType()) + "Array";
             case VOID:
@@ -379,7 +379,7 @@
     }
 
     private static String getDeclaredName(DeclaredType element) {
-        String simpleName = element.asElement().getSimpleName().toString();
+        String simpleName = fixECJBinaryNameIssue(element.asElement().getSimpleName().toString());
 
         if (element.getTypeArguments().size() == 0) {
             return simpleName;
@@ -399,6 +399,14 @@
         return b.toString();
     }
 
+    public static String fixECJBinaryNameIssue(String name) {
+        if (name.contains("$")) {
+            int lastIndex = name.lastIndexOf('$');
+            return name.substring(lastIndex + 1, name.length());
+        }
+        return name;
+    }
+
     public static String getQualifiedName(TypeElement element) {
         String qualifiedName = element.getQualifiedName().toString();
         if (qualifiedName.contains("$")) {
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/codewriter/OrganizedImports.java	Fri Oct 25 01:24:19 2013 +0200
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/codewriter/OrganizedImports.java	Fri Oct 25 01:26:27 2013 +0200
@@ -135,7 +135,7 @@
     }
 
     private String createDeclaredTypeName(Element enclosedElement, DeclaredType type) {
-        String name = type.asElement().getSimpleName().toString();
+        String name = Utils.fixECJBinaryNameIssue(type.asElement().getSimpleName().toString());
 
         if (needsImport(enclosedElement, type)) {
             TypeMirror usedByType = simpleNamesUsed.get(name);
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeCodeGenerator.java	Fri Oct 25 01:24:19 2013 +0200
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeCodeGenerator.java	Fri Oct 25 01:26:27 2013 +0200
@@ -964,16 +964,78 @@
                 for (CodeExecutableElement method : createImplicitChildrenAccessors()) {
                     clazz.add(method);
                 }
-
                 clazz.add(createGenericExecuteAndSpecialize(node, rootGroup));
                 clazz.add(createInfoMessage(node));
             }
 
+            if (needsInvokeCopyConstructorMethod()) {
+                clazz.add(createInvokeCopyConstructor(clazz.asType(), null));
+                clazz.add(createCopyPolymorphicConstructor(clazz.asType()));
+            }
+
             if (node.getGenericSpecialization() != null && node.getGenericSpecialization().isReachable()) {
                 clazz.add(createGenericExecute(node, rootGroup));
             }
         }
 
+        protected boolean needsInvokeCopyConstructorMethod() {
+            return getModel().getNode().isPolymorphic();
+        }
+
+        protected CodeExecutableElement createInvokeCopyConstructor(TypeMirror baseType, SpecializationData specialization) {
+            CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED), baseType, "invokeCopyConstructor");
+            if (specialization == null) {
+                method.getModifiers().add(ABSTRACT);
+            } else {
+                CodeTreeBuilder builder = method.createBuilder();
+                builder.startReturn();
+                builder.startNew(getElement().asType());
+                builder.string("this");
+                for (ActualParameter param : getImplicitTypeParamters(specialization)) {
+                    builder.string(implicitTypeName(param));
+                }
+                builder.end().end();
+            }
+            return method;
+        }
+
+        protected CodeExecutableElement createCopyPolymorphicConstructor(TypeMirror baseType) {
+            CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED, FINAL), baseType, "copyPolymorphic");
+            CodeTreeBuilder builder = method.createBuilder();
+            CodeTreeBuilder nullBuilder = builder.create();
+            CodeTreeBuilder oldBuilder = builder.create();
+            CodeTreeBuilder resetBuilder = builder.create();
+
+            for (ActualParameter param : getModel().getParameters()) {
+                if (!param.getSpecification().isSignature()) {
+                    continue;
+                }
+                NodeChildData child = getModel().getNode().findChild(param.getSpecification().getName());
+
+                CodeTreeBuilder access = builder.create();
+                access.string("this.").string(child.getName());
+                if (child.getCardinality().isMany()) {
+                    access.string("[").string(String.valueOf(param.getIndex())).string("]");
+                }
+
+                String oldName = "old" + Utils.firstLetterUpperCase(param.getLocalName());
+                oldBuilder.declaration(child.getNodeData().getNodeType(), oldName, access);
+                nullBuilder.startStatement().tree(access.getRoot()).string(" = null").end();
+                resetBuilder.startStatement().tree(access.getRoot()).string(" = ").string(oldName).end();
+            }
+
+            builder.tree(oldBuilder.getRoot());
+            builder.tree(nullBuilder.getRoot());
+
+            builder.startStatement().type(baseType).string(" copy = ");
+            builder.startCall("invokeCopyConstructor").end();
+            builder.end();
+
+            builder.tree(resetBuilder.getRoot());
+            builder.startReturn().string("copy").end();
+            return method;
+        }
+
         private List<CodeExecutableElement> createImplicitChildrenAccessors() {
             NodeData node = getModel().getNode();
             // Map<NodeChildData, Set<TypeData>> expectTypes = new HashMap<>();
@@ -1795,27 +1857,14 @@
             String uninitializedName = nodeSpecializationClassName(node.getUninitializedSpecialization());
             CodeTreeBuilder builder = parent.create();
 
+            builder.declaration(getElement().asType(), "currentCopy", currentNode + ".copyPolymorphic()");
             builder.declaration(polyClassName, "polymorphic", builder.create().startNew(polyClassName).string(currentNode).end());
-
-            for (ActualParameter param : node.getGenericSpecialization().getParameters()) {
-                if (!param.getSpecification().isSignature()) {
-                    continue;
-                }
-                NodeChildData child = node.findChild(param.getSpecification().getName());
-                if (child != null) {
-                    builder.startStatement().string(currentNode).string(".").string(child.getName());
-                    if (child.getCardinality().isMany()) {
-                        builder.string("[").string(String.valueOf(param.getIndex())).string("]");
-                    }
-                    builder.string(" = null").end();
-                }
-            }
             builder.startStatement().startCall(currentNode, "replace").string("polymorphic").string("message").end().end();
-            builder.startStatement().startCall("polymorphic", "setNext0").string(currentNode).end().end();
-            builder.startStatement().startCall(currentNode, "setNext0").startNew(uninitializedName).string(currentNode).end().end().end();
+            builder.startStatement().startCall("polymorphic", "setNext0").string("currentCopy").end().end();
+            builder.startStatement().startCall("currentCopy", "setNext0").startNew(uninitializedName).string(currentNode).end().end().end();
 
             builder.startReturn();
-            builder.startCall(currentNode + ".next0", executeCachedName(node.getGenericPolymorphicSpecialization()));
+            builder.startCall("currentCopy.next0", executeCachedName(node.getGenericPolymorphicSpecialization()));
             addInternalValueParameterNames(builder, node.getGenericSpecialization(), node.getGenericSpecialization(), null, true, true, null);
             builder.end();
             builder.end();
@@ -1981,6 +2030,21 @@
             }
         }
 
+        protected final List<ActualParameter> getImplicitTypeParamters(SpecializationData model) {
+            List<ActualParameter> parameter = new ArrayList<>();
+            for (ActualParameter param : model.getParameters()) {
+                if (!param.getSpecification().isSignature()) {
+                    continue;
+                }
+                NodeChildData child = getModel().getNode().findChild(param.getSpecification().getName());
+                List<TypeData> types = child.getNodeData().getTypeSystem().lookupSourceTypes(param.getTypeSystemType());
+                if (types.size() > 1) {
+                    parameter.add(param);
+                }
+            }
+            return parameter;
+        }
+
         protected final TreeSet<TypeData> lookupPolymorphicTargetTypes(ActualParameter param) {
             SpecializationData specialization = getModel();
             TreeSet<TypeData> possiblePolymorphicTypes = new TreeSet<>();
@@ -2529,6 +2593,10 @@
                 getElement().add(createUpdateType(parameter));
             }
 
+            if (needsInvokeCopyConstructorMethod()) {
+                clazz.add(createInvokeCopyConstructor(nodeGen.asType(), specialization));
+            }
+
             createCachedExecuteMethods(specialization);
 
         }
@@ -2607,6 +2675,9 @@
             if (specialization.getNode().isPolymorphic()) {
                 getElement().add(createUpdateTypes(nodeGen.asType()));
             }
+            if (needsInvokeCopyConstructorMethod()) {
+                clazz.add(createInvokeCopyConstructor(nodeGen.asType(), specialization));
+            }
         }
 
         protected void createConstructors(CodeTypeElement clazz) {
@@ -2636,20 +2707,13 @@
                         builder.statement("this.next0 = null");
                     }
 
-                    for (ActualParameter param : getModel().getParameters()) {
-                        if (!param.getSpecification().isSignature()) {
-                            continue;
-                        }
-                        NodeChildData child = getModel().getNode().findChild(param.getSpecification().getName());
-                        List<TypeData> types = child.getNodeData().getTypeSystem().lookupSourceTypes(param.getTypeSystemType());
-                        if (types.size() > 1) {
-                            clazz.add(new CodeVariableElement(modifiers(PRIVATE, FINAL), getContext().getType(Class.class), implicitTypeName(param)));
-                            superConstructor.getParameters().add(new CodeVariableElement(getContext().getType(Class.class), implicitTypeName(param)));
-
-                            builder.startStatement();
-                            builder.string("this.").string(implicitTypeName(param)).string(" = ").string(implicitTypeName(param));
-                            builder.end();
-                        }
+                    for (ActualParameter param : getImplicitTypeParamters(getModel())) {
+                        clazz.add(new CodeVariableElement(modifiers(PRIVATE, FINAL), getContext().getType(Class.class), implicitTypeName(param)));
+                        superConstructor.getParameters().add(new CodeVariableElement(getContext().getType(Class.class), implicitTypeName(param)));
+
+                        builder.startStatement();
+                        builder.string("this.").string(implicitTypeName(param)).string(" = ").string(implicitTypeName(param));
+                        builder.end();
                     }
 
                     clazz.add(superConstructor);
--- a/mxtool/mx.py	Fri Oct 25 01:24:19 2013 +0200
+++ b/mxtool/mx.py	Fri Oct 25 01:26:27 2013 +0200
@@ -768,7 +768,7 @@
             abort('Missing "suite=<name>" in ' + projectsFile)
 
     def _commands_name(self):
-        return 'mx_' + self.name.replace('-','_')
+        return 'mx_' + self.name.replace('-', '_')
 
     def _find_commands(self, name):
         commandsPath = join(self.mxDir, name + '.py')
--- a/src/share/vm/runtime/deoptimization.cpp	Fri Oct 25 01:24:19 2013 +0200
+++ b/src/share/vm/runtime/deoptimization.cpp	Fri Oct 25 01:26:27 2013 +0200
@@ -1430,7 +1430,7 @@
           } else {
             tty->print(" (Graal: installed code has no name) ");
           }
-        } else {
+        } else if (nm->is_compiled_by_graal()) {
           tty->print(" (Graal: no installed code) ");
         }
 #endif //GRAAL