changeset 6295:904517c1cd06

Merge.
author Doug Simon <doug.simon@oracle.com>
date Tue, 28 Aug 2012 14:17:22 +0200
parents 01d274503562 (diff) b0fc02623974 (current diff)
children 6a51bc216306
files
diffstat 22 files changed, 368 insertions(+), 100 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java	Tue Aug 28 13:55:11 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java	Tue Aug 28 14:17:22 2012 +0200
@@ -43,25 +43,30 @@
 
 
     private HashMap<VirtualObjectNode, VirtualObject> virtualObjects = new HashMap<>();
+    private IdentityHashMap<VirtualObjectNode, EscapeObjectState> objectStates = new IdentityHashMap<>();
 
     public LIRFrameState build(FrameState topState, LockScope locks, List<StackSlot> pointerSlots, LabelRef exceptionEdge, long leafGraphId) {
         assert virtualObjects.size() == 0;
+        assert objectStates.size() == 0;
+
+        // collect all VirtualObjectField instances:
+        FrameState current = topState;
+        do {
+            for (EscapeObjectState state : current.virtualObjectMappings()) {
+                if (objectStates == null) {
+                    objectStates = new IdentityHashMap<>();
+                }
+                if (!objectStates.containsKey(state.object())) {
+                    objectStates.put(state.object(), state);
+                }
+            }
+            current = current.outerFrameState();
+        } while (current != null);
+
         BytecodeFrame frame = computeFrameForState(topState, locks, leafGraphId);
 
         VirtualObject[] virtualObjectsArray = null;
         if (virtualObjects.size() != 0) {
-            // collect all VirtualObjectField instances:
-            IdentityHashMap<VirtualObjectNode, VirtualObjectState> objectStates = new IdentityHashMap<>();
-            FrameState current = topState;
-            do {
-                for (VirtualObjectState state : current.virtualObjectMappings()) {
-                    // null states occur for objects with 0 fields
-                    if (!objectStates.containsKey(state.object())) {
-                        objectStates.put(state.object(), state);
-                    }
-                }
-                current = current.outerFrameState();
-            } while (current != null);
             // fill in the VirtualObject values:
             // during this process new VirtualObjects might be discovered, so repeat until no more changes occur.
             boolean changed;
@@ -79,7 +84,7 @@
                             entry.getValue().setValues(values);
                             if (values.length > 0) {
                                 changed = true;
-                                VirtualObjectState currentField = objectStates.get(vobj);
+                                VirtualObjectState currentField = (VirtualObjectState) objectStates.get(vobj);
                                 assert currentField != null;
                                 for (int i = 0; i < vobj.fieldsCount(); i++) {
                                     values[i] = toValue(currentField.fieldValues().get(i));
@@ -93,6 +98,7 @@
             virtualObjectsArray = virtualObjects.values().toArray(new VirtualObject[virtualObjects.size()]);
             virtualObjects.clear();
         }
+        objectStates.clear();
 
         return new LIRFrameState(frame, virtualObjectsArray, pointerSlots, exceptionEdge);
     }
@@ -138,14 +144,23 @@
     private Value toValue(ValueNode value) {
         if (value instanceof VirtualObjectNode) {
             VirtualObjectNode obj = (VirtualObjectNode) value;
-            VirtualObject ciObj = virtualObjects.get(value);
-            if (ciObj == null) {
-                ciObj = VirtualObject.get(obj.type(), null, virtualObjects.size());
-                virtualObjects.put(obj, ciObj);
+            EscapeObjectState state = objectStates.get(obj);
+            if (state == null && obj.fieldsCount() > 0) {
+                // null states occur for objects with 0 fields
+                throw new GraalInternalError("no mapping found for virtual object %s", obj);
             }
-            Debug.metric("StateVirtualObjects").increment();
-            return ciObj;
-
+            if (state instanceof MaterializedObjectState) {
+                return toValue(((MaterializedObjectState) state).materializedValue());
+            } else {
+                assert obj.fieldsCount() == 0 || state instanceof VirtualObjectState;
+                VirtualObject ciObj = virtualObjects.get(value);
+                if (ciObj == null) {
+                    ciObj = VirtualObject.get(obj.type(), null, virtualObjects.size());
+                    virtualObjects.put(obj, ciObj);
+                }
+                Debug.metric("StateVirtualObjects").increment();
+                return ciObj;
+            }
         } else if (value instanceof ConstantNode) {
             Debug.metric("StateConstants").increment();
             return ((ConstantNode) value).value;
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/BoxingEliminationPhase.java	Tue Aug 28 13:55:11 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/BoxingEliminationPhase.java	Tue Aug 28 14:17:22 2012 +0200
@@ -36,6 +36,8 @@
 
 public class BoxingEliminationPhase extends Phase {
 
+    private int virtualIds = Integer.MIN_VALUE;
+
     @Override
     protected void run(StructuredGraph graph) {
         if (graph.getNodes(UnboxNode.class).isNotEmpty()) {
@@ -105,7 +107,7 @@
         }
     }
 
-    private static void tryEliminate(BoxNode boxNode) {
+    private void tryEliminate(BoxNode boxNode) {
 
         assert boxNode.objectStamp().isExactType();
         virtualizeUsages(boxNode, boxNode.source(), boxNode.objectStamp().type());
@@ -122,12 +124,12 @@
         ((StructuredGraph) boxNode.graph()).removeFixed(boxNode);
     }
 
-    private static void virtualizeUsages(ValueNode boxNode, ValueNode replacement, ResolvedJavaType exactType) {
+    private void virtualizeUsages(ValueNode boxNode, ValueNode replacement, ResolvedJavaType exactType) {
         ValueNode virtualValueNode = null;
         VirtualObjectNode virtualObjectNode = null;
         for (Node n : boxNode.usages().filter(NodePredicates.isA(VirtualState.class)).snapshot()) {
             if (virtualValueNode == null) {
-                virtualObjectNode = n.graph().unique(new BoxedVirtualObjectNode(exactType, replacement));
+                virtualObjectNode = n.graph().unique(new BoxedVirtualObjectNode(virtualIds++, exactType, replacement));
             }
             n.replaceFirstInput(boxNode, virtualObjectNode);
         }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/CanonicalizerPhase.java	Tue Aug 28 13:55:11 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/CanonicalizerPhase.java	Tue Aug 28 14:17:22 2012 +0200
@@ -180,6 +180,7 @@
 
     public static boolean tryCanonicalize(final Node node, final StructuredGraph graph, final SimplifierTool tool) {
         if (node instanceof Canonicalizable) {
+            assert !(node instanceof Simplifiable);
             METRIC_CANONICALIZATION_CONSIDERED_NODES.increment();
             return Debug.scope("CanonicalizeNode", node, new Callable<Boolean>(){
                 public Boolean call() {
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/EscapeAnalysisPhase.java	Tue Aug 28 13:55:11 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/EscapeAnalysisPhase.java	Tue Aug 28 14:17:22 2012 +0200
@@ -38,13 +38,13 @@
 import com.oracle.graal.nodes.virtual.*;
 import com.oracle.max.criutils.*;
 
-
 public class EscapeAnalysisPhase extends Phase {
 
     /**
      * Encapsulates the state of the virtual object, which is updated while traversing the control flow graph.
      */
-    public static class BlockExitState implements MergeableState<BlockExitState> {
+    private static class BlockExitState implements MergeableState<BlockExitState> {
+
         public final ValueNode[] fieldState;
         public final VirtualObjectNode virtualObject;
         public final Graph graph;
@@ -115,16 +115,17 @@
         }
     }
 
-
-    public static class EscapementFixup {
+    private static class EscapementFixup {
 
         private final Map<Object, Integer> fields = new HashMap<>();
         private final EscapeOp op;
         private final StructuredGraph graph;
         private final FixedWithNextNode node;
         private EscapeField[] escapeFields;
+        private final int id;
 
-        public EscapementFixup(EscapeOp op, StructuredGraph graph, FixedWithNextNode node) {
+        public EscapementFixup(int id, EscapeOp op, StructuredGraph graph, FixedWithNextNode node) {
+            this.id = id;
             this.op = op;
             this.graph = graph;
             this.node = node;
@@ -151,7 +152,7 @@
                 fields.put(escapeFields[i].representation(), i);
             }
             assert node.objectStamp().isExactType();
-            final VirtualObjectNode virtual = graph.add(new VirtualObjectNode(node.objectStamp().type(), escapeFields));
+            final VirtualObjectNode virtual = graph.add(new VirtualObjectNode(id, node.objectStamp().type(), escapeFields.length));
             if (GraalOptions.TraceEscapeAnalysis || GraalOptions.PrintEscapeAnalysis) {
                 TTY.println("new virtual object: " + virtual);
             }
@@ -170,6 +171,7 @@
             if (virtual.fieldsCount() > 0) {
                 final BlockExitState startState = new BlockExitState(escapeFields, virtual);
                 new PostOrderNodeIterator<BlockExitState>(next, startState) {
+
                     @Override
                     protected void node(FixedNode curNode) {
                         op.updateState(virtual, curNode, fields, state.fieldState);
@@ -188,6 +190,10 @@
         }
     }
 
+
+    private int virtualIds = 0;
+
+
     private final TargetDescription target;
     private final GraalCodeCacheProvider runtime;
     private final Assumptions assumptions;
@@ -204,7 +210,7 @@
         this.optimisticOpts = optimisticOpts;
     }
 
-    public static class EscapeRecord {
+    private static class EscapeRecord {
 
         public final Node node;
         public final ArrayList<Node> escapesThrough = new ArrayList<>();
@@ -380,7 +386,7 @@
     }
 
     protected void removeAllocation(StructuredGraph graph, FixedWithNextNode node, EscapeOp op) {
-        new EscapementFixup(op, graph, node).apply();
+        new EscapementFixup(virtualIds++, op, graph, node).apply();
 
         for (PhiNode phi : node.graph().getNodes(PhiNode.class)) {
             ValueNode simpleValue = phi;
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/util/InliningUtil.java	Tue Aug 28 13:55:11 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/util/InliningUtil.java	Tue Aug 28 14:17:22 2012 +0200
@@ -196,7 +196,7 @@
             ValueAnchorNode anchor = graph.add(new ValueAnchorNode());
             assert invoke.predecessor() != null;
 
-            ValueNode anchoredReceiver = createAnchoredReceiver(graph, anchor, type, receiver);
+            ValueNode anchoredReceiver = createAnchoredReceiver(graph, anchor, type, receiver, true);
             invoke.callTarget().replaceFirstInput(receiver, anchoredReceiver);
 
             graph.addBeforeFixed(invoke.node(), objectClass);
@@ -352,7 +352,8 @@
 
                 ResolvedJavaType commonType = getLeastCommonType(i);
                 ValueNode receiver = invokeForInlining.callTarget().receiver();
-                PiNode anchoredReceiver = createAnchoredReceiver(graph, node, commonType, receiver);
+                boolean exact = getTypeCount(i) == 1;
+                PiNode anchoredReceiver = createAnchoredReceiver(graph, node, commonType, receiver, exact);
                 invokeForInlining.callTarget().replaceFirstInput(receiver, anchoredReceiver);
 
                 ResolvedJavaMethod concrete = concretes.get(i);
@@ -388,6 +389,16 @@
             }
         }
 
+        private int getTypeCount(int concreteMethodIndex) {
+            int count = 0;
+            for (int i = 0; i < typesToConcretes.length; i++) {
+                if (typesToConcretes[i] == concreteMethodIndex) {
+                    count++;
+                }
+            }
+            return count;
+        }
+
         private ResolvedJavaType getLeastCommonType(int concreteMethodIndex) {
             ResolvedJavaType commonType = null;
             for (int i = 0; i < typesToConcretes.length; i++) {
@@ -709,9 +720,9 @@
         }
     }
 
-    private static PiNode createAnchoredReceiver(StructuredGraph graph, FixedNode anchor, ResolvedJavaType commonType, ValueNode receiver) {
+    private static PiNode createAnchoredReceiver(StructuredGraph graph, FixedNode anchor, ResolvedJavaType commonType, ValueNode receiver, boolean exact) {
         // to avoid that floating reads on receiver fields float above the type check
-        return graph.unique(new PiNode(receiver, anchor, StampFactory.declaredNonNull(commonType)));
+        return graph.unique(new PiNode(receiver, anchor, exact ? StampFactory.exactNonNull(commonType) : StampFactory.declaredNonNull(commonType)));
     }
 
     private static boolean checkInvokeConditions(Invoke invoke) {
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeMap.java	Tue Aug 28 13:55:11 2012 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeMap.java	Tue Aug 28 14:17:22 2012 +0200
@@ -23,8 +23,7 @@
 package com.oracle.graal.graph;
 
 import java.util.AbstractMap.SimpleEntry;
-import java.util.Arrays;
-import java.util.Iterator;
+import java.util.*;
 import java.util.Map.Entry;
 
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java	Tue Aug 28 13:55:11 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java	Tue Aug 28 14:17:22 2012 +0200
@@ -100,7 +100,7 @@
 
     @Input private final NodeInputList<ValueNode> values;
 
-    @Input private final NodeInputList<VirtualObjectState> virtualObjectMappings;
+    @Input private final NodeInputList<EscapeObjectState> virtualObjectMappings;
 
     /**
      * The bytecode index to which this frame state applies.
@@ -117,7 +117,7 @@
      * @param stackSize size of the stack
      * @param rethrowException if true the VM should re-throw the exception on top of the stack when deopt'ing using this framestate
      */
-    public FrameState(ResolvedJavaMethod method, int bci, List<ValueNode> values, int stackSize, boolean rethrowException, boolean duringCall, InliningIdentifier inliningIdentifier, List<VirtualObjectState> virtualObjectMappings) {
+    public FrameState(ResolvedJavaMethod method, int bci, List<ValueNode> values, int stackSize, boolean rethrowException, boolean duringCall, InliningIdentifier inliningIdentifier, List<EscapeObjectState> virtualObjectMappings) {
         assert stackSize >= 0;
         assert (bci >= 0 && method != null) || (bci < 0 && method == null && values.isEmpty());
         this.method = method;
@@ -137,7 +137,7 @@
      * @param bci marker bci, needs to be < 0
      */
     public FrameState(int bci) {
-        this(null, bci, Collections.<ValueNode>emptyList(), 0, false, false, null, Collections.<VirtualObjectState>emptyList());
+        this(null, bci, Collections.<ValueNode>emptyList(), 0, false, false, null, Collections.<EscapeObjectState>emptyList());
     }
 
     public FrameState(ResolvedJavaMethod method, int bci, ValueNode[] locals, ValueNode[] stack, int stackSize, boolean rethrowException, boolean duringCall, InliningIdentifier inliningIdentifier) {
@@ -199,7 +199,7 @@
         return method;
     }
 
-    public void addVirtualObjectMapping(VirtualObjectState virtualObject) {
+    public void addVirtualObjectMapping(EscapeObjectState virtualObject) {
         virtualObjectMappings.add(virtualObject);
     }
 
@@ -211,7 +211,7 @@
         return virtualObjectMappings.get(i);
     }
 
-    public NodeInputList<VirtualObjectState> virtualObjectMappings() {
+    public NodeInputList<EscapeObjectState> virtualObjectMappings() {
         return virtualObjectMappings;
     }
 
@@ -241,8 +241,8 @@
         if (newOuterFrameState != null) {
             newOuterFrameState = newOuterFrameState.duplicateWithVirtualState();
         }
-        ArrayList<VirtualObjectState> newVirtualMappings = new ArrayList<>(virtualObjectMappings.size());
-        for (VirtualObjectState state : virtualObjectMappings) {
+        ArrayList<EscapeObjectState> newVirtualMappings = new ArrayList<>(virtualObjectMappings.size());
+        for (EscapeObjectState state : virtualObjectMappings) {
             newVirtualMappings.add(state.duplicateWithVirtualState());
         }
         FrameState other = graph().add(new FrameState(method, bci, values, stackSize, rethrowException, duringCall, inliningIdentifier, newVirtualMappings));
@@ -380,7 +380,7 @@
         for (ValueNode value : values.nonNull()) {
             closure.apply(this, value);
         }
-        for (VirtualObjectState state : virtualObjectMappings) {
+        for (EscapeObjectState state : virtualObjectMappings) {
             state.applyToNonVirtual(closure);
         }
         if (outerFrameState() != null) {
@@ -391,7 +391,7 @@
     @Override
     public void applyToVirtual(VirtualClosure closure) {
         closure.apply(this);
-        for (VirtualObjectState state : virtualObjectMappings) {
+        for (EscapeObjectState state : virtualObjectMappings) {
             state.applyToVirtual(closure);
         }
         if (outerFrameState() != null) {
@@ -407,7 +407,7 @@
         if (outerFrameState() != null && outerFrameState().isPartOfThisState(state)) {
             return true;
         }
-        for (VirtualObjectState objectState : virtualObjectMappings) {
+        for (EscapeObjectState objectState : virtualObjectMappings) {
             if (objectState.isPartOfThisState(state)) {
                 return true;
             }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PiNode.java	Tue Aug 28 13:55:11 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PiNode.java	Tue Aug 28 14:17:22 2012 +0200
@@ -53,6 +53,11 @@
 
     @Override
     public boolean inferStamp() {
+        if (object().objectStamp().alwaysNull() && objectStamp().nonNull()) {
+            // a null value flowing into a nonNull PiNode can happen should be guarded by a type/isNull guard, but the
+            // compiler might see this situation before the branch is deleted
+            return false;
+        }
         return updateStamp(stamp().join(object().stamp()));
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java	Tue Aug 28 13:55:11 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java	Tue Aug 28 14:17:22 2012 +0200
@@ -22,6 +22,7 @@
  */
 package com.oracle.graal.nodes.extended;
 
+import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
@@ -31,7 +32,7 @@
 /**
  * Reads an {@linkplain AccessNode accessed} value.
  */
-public final class ReadNode extends AccessNode implements Node.IterableNodeType, LIRLowerable/*, Canonicalizable*/ {
+public final class ReadNode extends AccessNode implements Node.IterableNodeType, LIRLowerable, Simplifiable/*, Canonicalizable*/ {
 
     public ReadNode(ValueNode object, LocationNode location, Stamp stamp) {
         super(object, location, stamp);
@@ -42,7 +43,7 @@
         gen.setResult(this, gen.emitLoad(gen.makeAddress(location(), object()), getNullCheck()));
     }
 
-    // Canonicalization disabled untill we have a solution for non-Object oops in Hotspot
+    // Canonicalization disabled until we have a solution for non-Object oops in Hotspot
     /*@Override
     public ValueNode canonical(CanonicalizerTool tool) {
         return canonicalizeRead(this, tool);
@@ -64,4 +65,16 @@
         }
         return (ValueNode) read;
     }
+
+    @Override
+    public void simplify(SimplifierTool tool) {
+        if (object().isConstant() && object().asConstant().isNull()) {
+            FixedNode successor = next();
+            tool.deleteBranch(successor);
+            if (isAlive()) {
+                replaceAtPredecessor(graph().add(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.NullCheckException)));
+                safeDelete();
+            }
+        }
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteNode.java	Tue Aug 28 13:55:11 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteNode.java	Tue Aug 28 14:17:22 2012 +0200
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.nodes.extended;
 
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
@@ -30,7 +32,7 @@
 /**
  * Writes a given {@linkplain #value() value} a {@linkplain AccessNode memory location}.
  */
-public final class WriteNode extends AccessNode implements StateSplit, LIRLowerable {
+public final class WriteNode extends AccessNode implements StateSplit, LIRLowerable, Simplifiable {
     @Input private ValueNode value;
     @Input(notDataflow = true) private FrameState stateAfter;
 
@@ -61,4 +63,16 @@
     public void generate(LIRGeneratorTool gen) {
         gen.emitStore(gen.makeAddress(location(), object()), gen.operand(value()), getNullCheck());
     }
+
+    @Override
+    public void simplify(SimplifierTool tool) {
+        if (object().isConstant() && object().asConstant().isNull()) {
+            FixedNode successor = next();
+            tool.deleteBranch(successor);
+            if (isAlive()) {
+                replaceAtPredecessor(graph().add(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.NullCheckException)));
+                safeDelete();
+            }
+        }
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessIndexedNode.java	Tue Aug 28 13:55:11 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessIndexedNode.java	Tue Aug 28 14:17:22 2012 +0200
@@ -24,13 +24,14 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
 /**
  * The {@code AccessIndexedNode} class is the base class of instructions that read or write
  * elements of an array.
  */
-public abstract class AccessIndexedNode extends AccessArrayNode {
+public abstract class AccessIndexedNode extends AccessArrayNode implements Lowerable {
 
     @Input private ValueNode index;
     private final Kind elementType;
@@ -65,4 +66,9 @@
     public long leafGraphId() {
         return leafGraphId;
     }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        tool.getRuntime().lower(this, tool);
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadIndexedNode.java	Tue Aug 28 13:55:11 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadIndexedNode.java	Tue Aug 28 14:17:22 2012 +0200
@@ -33,7 +33,7 @@
 /**
  * The {@code LoadIndexedNode} represents a read from an element of an array.
  */
-public final class LoadIndexedNode extends AccessIndexedNode implements Canonicalizable, Lowerable, Node.IterableNodeType {
+public final class LoadIndexedNode extends AccessIndexedNode implements Canonicalizable, Node.IterableNodeType {
 
     /**
      * Creates a new LoadIndexedNode.
@@ -54,11 +54,6 @@
     }
 
     @Override
-    public void lower(LoweringTool tool) {
-        tool.getRuntime().lower(this, tool);
-    }
-
-    @Override
     public ValueNode canonical(CanonicalizerTool tool) {
         MetaAccessProvider runtime = tool.runtime();
         if (runtime != null && index().isConstant() && array().isConstant() && !array().isNullConstant()) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MaterializeObjectNode.java	Tue Aug 28 14:17:22 2012 +0200
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.nodes.java;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
+
+@NodeInfo(nameTemplate = "Materialize {p#type/s}")
+public final class MaterializeObjectNode extends FixedWithNextNode implements Lowerable, Node.IterableNodeType {
+
+    @Input private final NodeInputList<ValueNode> values;
+    private final ResolvedJavaType type;
+    private final EscapeField[] fields;
+
+    public MaterializeObjectNode(ResolvedJavaType type, EscapeField[] fields, ValueNode[] values) {
+        super(StampFactory.exactNonNull(type));
+        this.type = type;
+        this.fields = fields;
+        this.values = new NodeInputList<>(this, values);
+    }
+
+    public ResolvedJavaType type() {
+        return type;
+    }
+
+    public EscapeField[] getFields() {
+        return fields;
+    }
+
+    public NodeInputList<ValueNode> getValues() {
+        return values;
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        StructuredGraph graph = (StructuredGraph) graph();
+        if (type.isArrayClass()) {
+            ResolvedJavaType element = type.componentType();
+            NewArrayNode newArray;
+            if (element.kind() == Kind.Object) {
+                newArray = graph.add(new NewObjectArrayNode(element, ConstantNode.forInt(fields.length, graph)));
+            } else {
+                newArray = graph.add(new NewPrimitiveArrayNode(element, ConstantNode.forInt(fields.length, graph)));
+            }
+            this.replaceAtUsages(newArray);
+            graph.addAfterFixed(this, newArray);
+
+            FixedWithNextNode position = newArray;
+            for (int i = 0; i < fields.length; i++) {
+                StoreIndexedNode store = graph.add(new StoreIndexedNode(newArray, ConstantNode.forInt(i, graph), element.kind(), values.get(i), -1));
+                graph.addAfterFixed(position, store);
+                position = store;
+            }
+
+            graph.removeFixed(this);
+        } else {
+            NewInstanceNode newInstance = graph.add(new NewInstanceNode(type));
+            this.replaceAtUsages(newInstance);
+            graph.addAfterFixed(this, newInstance);
+
+            FixedWithNextNode position = newInstance;
+            for (int i = 0; i < fields.length; i++) {
+                StoreFieldNode store = graph.add(new StoreFieldNode(newInstance, (ResolvedJavaField) fields[i].representation(), values.get(i), -1));
+                graph.addAfterFixed(position, store);
+                position = store;
+            }
+
+            graph.removeFixed(this);
+        }
+    }
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewArrayNode.java	Tue Aug 28 13:55:11 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewArrayNode.java	Tue Aug 28 14:17:22 2012 +0200
@@ -80,7 +80,12 @@
     }
 
     public EscapeOp getEscapeOp() {
-        return ESCAPE;
+        Constant constantLength = length().asConstant();
+        if (constantLength != null && constantLength.asInt() >= 0 && constantLength.asInt() < MaximumEscapeAnalysisArrayLength) {
+            return ESCAPE;
+        } else {
+            return null;
+        }
     }
 
     @Override
@@ -110,6 +115,12 @@
         }
 
         @Override
+        public ResolvedJavaType type(Node node) {
+            NewArrayNode x = (NewArrayNode) node;
+            return x.elementType.arrayOf();
+        }
+
+        @Override
         public void beforeUpdate(Node node, Node usage) {
             if (usage instanceof ArrayLengthNode) {
                 ArrayLengthNode x = (ArrayLengthNode) usage;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewInstanceNode.java	Tue Aug 28 13:55:11 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewInstanceNode.java	Tue Aug 28 14:17:22 2012 +0200
@@ -67,7 +67,7 @@
     }
 
     public EscapeOp getEscapeOp() {
-        return ESCAPE;
+        return instanceClass == null ? null : ESCAPE;
     }
 
     private static final EscapeOp ESCAPE = new EscapeOp() {
@@ -89,6 +89,12 @@
         }
 
         @Override
+        public ResolvedJavaType type(Node node) {
+            NewInstanceNode x = (NewInstanceNode) node;
+            return x.instanceClass();
+        }
+
+        @Override
         public EscapeField[] fields(Node node) {
             NewInstanceNode x = (NewInstanceNode) node;
             List<EscapeField> escapeFields = new ArrayList<>();
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/StoreIndexedNode.java	Tue Aug 28 13:55:11 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/StoreIndexedNode.java	Tue Aug 28 14:17:22 2012 +0200
@@ -64,9 +64,4 @@
         super(StampFactory.forVoid(), array, index, elementKind, leafGraphId);
         this.value = value;
     }
-
-    @Override
-    public void lower(LoweringTool tool) {
-        tool.getRuntime().lower(this, tool);
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/EscapeOp.java	Tue Aug 28 13:55:11 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/EscapeOp.java	Tue Aug 28 14:17:22 2012 +0200
@@ -101,6 +101,8 @@
 
     public abstract EscapeField[] fields(Node node);
 
+    public abstract ResolvedJavaType type(Node node);
+
     public void beforeUpdate(Node node, Node usage) {
         // IsNonNullNode and IsTypeNode should have been eliminated by the CanonicalizerPhase, but we can't rely on this
         if (usage instanceof IsNullNode) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/BoxedVirtualObjectNode.java	Tue Aug 28 13:55:11 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/BoxedVirtualObjectNode.java	Tue Aug 28 14:17:22 2012 +0200
@@ -32,8 +32,8 @@
 
     @Input ValueNode unboxedValue;
 
-    public BoxedVirtualObjectNode(ResolvedJavaType type, ValueNode unboxedValue) {
-        super(type, 1);
+    public BoxedVirtualObjectNode(int id, ResolvedJavaType type, ValueNode unboxedValue) {
+        super(id, type, 1);
         this.unboxedValue = unboxedValue;
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/EscapeObjectState.java	Tue Aug 28 14:17:22 2012 +0200
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.nodes.virtual;
+
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+
+public abstract class EscapeObjectState extends VirtualState implements Node.IterableNodeType, LIRLowerable {
+
+    @Input private VirtualObjectNode object;
+
+    public VirtualObjectNode object() {
+        return object;
+    }
+
+    public EscapeObjectState(VirtualObjectNode object) {
+        this.object = object;
+    }
+
+    @Override
+    public void generate(LIRGeneratorTool generator) {
+        // Nothing to do, virtual object states are processed as part of the handling of StateSplit nodes.
+    }
+
+    @Override
+    public abstract EscapeObjectState duplicateWithVirtualState();
+
+    @Override
+    public boolean isPartOfThisState(VirtualState state) {
+        return this == state;
+    }
+
+    @Override
+    public void applyToVirtual(VirtualClosure closure) {
+        closure.apply(this);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/MaterializedObjectState.java	Tue Aug 28 14:17:22 2012 +0200
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.nodes.virtual;
+
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+
+/**
+ * This class encapsulated the materialized state of an escape analyzed object.
+ */
+public final class MaterializedObjectState extends EscapeObjectState implements Node.IterableNodeType, LIRLowerable {
+
+    @Input private ValueNode materializedValue;
+
+    public ValueNode materializedValue() {
+        return materializedValue;
+    }
+
+    public MaterializedObjectState(VirtualObjectNode object, ValueNode materializedValue) {
+        super(object);
+        this.materializedValue = materializedValue;
+    }
+
+    @Override
+    public void generate(LIRGeneratorTool generator) {
+        // Nothing to do, virtual object states are processed as part of the handling of StateSplit nodes.
+    }
+
+    @Override
+    public MaterializedObjectState duplicateWithVirtualState() {
+        return graph().add(new MaterializedObjectState(object(), materializedValue));
+    }
+
+    @Override
+    public void applyToNonVirtual(NodeClosure< ? super ValueNode> closure) {
+        closure.apply(this, materializedValue);
+    }
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectNode.java	Tue Aug 28 13:55:11 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectNode.java	Tue Aug 28 14:17:22 2012 +0200
@@ -30,19 +30,14 @@
 @NodeInfo(nameTemplate = "VirtualObject {p#type}")
 public class VirtualObjectNode extends FloatingNode implements LIRLowerable {
 
-    private ResolvedJavaType type;
-    private EscapeField[] fields;
-    private int fieldsCount;
+    @SuppressWarnings("unused")
+    private final int id;
+    private final ResolvedJavaType type;
+    private final int fieldsCount;
 
-    public VirtualObjectNode(ResolvedJavaType type, EscapeField[] fields) {
+    public VirtualObjectNode(int id, ResolvedJavaType type, int fieldCount) {
         super(StampFactory.virtual());
-        this.type = type;
-        this.fields = fields;
-        this.fieldsCount = fields.length;
-    }
-
-    public VirtualObjectNode(ResolvedJavaType type, int fieldCount) {
-        super(StampFactory.virtual());
+        this.id = id;
         this.type = type;
         this.fieldsCount = fieldCount;
     }
@@ -51,10 +46,6 @@
         return type;
     }
 
-    public EscapeField[] fields() {
-        return fields;
-    }
-
     @Override
     public void generate(LIRGeneratorTool gen) {
         // nothing to do...
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectState.java	Tue Aug 28 13:55:11 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectState.java	Tue Aug 28 14:17:22 2012 +0200
@@ -31,28 +31,23 @@
 /**
  * This class encapsulated the virtual state of an escape analyzed object.
  */
-public final class VirtualObjectState extends VirtualState implements Node.IterableNodeType, LIRLowerable {
+public final class VirtualObjectState extends EscapeObjectState implements Node.IterableNodeType, LIRLowerable {
 
-    @Input private VirtualObjectNode object;
     @Input private NodeInputList<ValueNode> fieldValues;
 
-    public VirtualObjectNode object() {
-        return object;
-    }
-
     public NodeInputList<ValueNode> fieldValues() {
         return fieldValues;
     }
 
     public VirtualObjectState(VirtualObjectNode object, ValueNode[] fieldValues) {
+        super(object);
         assert object.fieldsCount() == fieldValues.length;
-        this.object = object;
         this.fieldValues = new NodeInputList<>(this, fieldValues);
     }
 
     private VirtualObjectState(VirtualObjectNode object, List<ValueNode> fieldValues) {
+        super(object);
         assert object.fieldsCount() == fieldValues.size();
-        this.object = object;
         this.fieldValues = new NodeInputList<>(this, fieldValues);
     }
 
@@ -63,7 +58,7 @@
 
     @Override
     public VirtualObjectState duplicateWithVirtualState() {
-        return graph().add(new VirtualObjectState(object, fieldValues));
+        return graph().add(new VirtualObjectState(object(), fieldValues));
     }
 
     @Override
@@ -72,14 +67,4 @@
             closure.apply(this, value);
         }
     }
-
-    @Override
-    public boolean isPartOfThisState(VirtualState state) {
-        return this == state;
-    }
-
-    @Override
-    public void applyToVirtual(VirtualClosure closure) {
-        closure.apply(this);
-    }
 }