# HG changeset patch # User Doug Simon # Date 1382619477 -7200 # Node ID af39ea2dc39db3aaaf4dabbb243c47f58084e992 # Parent 1c8d5a0891b5c61bc762e1bfcbaef8bc629f98d4 made ConstantNodes (optionally) not record their usages (GRAAL-508) diff -r 1c8d5a0891b5 -r af39ea2dc39d graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java --- 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 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()); @@ -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) { diff -r 1c8d5a0891b5 -r af39ea2dc39d graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java --- 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; diff -r 1c8d5a0891b5 -r af39ea2dc39d graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java --- 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 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"); diff -r 1c8d5a0891b5 -r af39ea2dc39d graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java --- 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); } diff -r 1c8d5a0891b5 -r af39ea2dc39d graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotOptions.java --- 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; diff -r 1c8d5a0891b5 -r af39ea2dc39d graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConstantNode.java --- 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 diff -r 1c8d5a0891b5 -r af39ea2dc39d graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MergeNode.java --- 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); } } diff -r 1c8d5a0891b5 -r af39ea2dc39d graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java --- 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 floatingInputs = node.inputs().filter(isFloatingNode()).snapshot(); - node.safeDelete(); + if (node.recordsUsages()) { + List 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(); } } diff -r 1c8d5a0891b5 -r af39ea2dc39d graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java --- 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; } diff -r 1c8d5a0891b5 -r af39ea2dc39d graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java --- 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 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); + } } } } diff -r 1c8d5a0891b5 -r af39ea2dc39d graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinter.java --- 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(" "); } diff -r 1c8d5a0891b5 -r af39ea2dc39d graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinterObserver.java --- 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; diff -r 1c8d5a0891b5 -r af39ea2dc39d graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPhase.java --- 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()) { diff -r 1c8d5a0891b5 -r af39ea2dc39d graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java --- 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]; diff -r 1c8d5a0891b5 -r af39ea2dc39d graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java --- 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() { diff -r 1c8d5a0891b5 -r af39ea2dc39d graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCache.java --- 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); diff -r 1c8d5a0891b5 -r af39ea2dc39d graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java --- 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); + } } } } diff -r 1c8d5a0891b5 -r af39ea2dc39d graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeVerificationPhase.java --- 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");