changeset 6394:466e6ceebfed

iterative partial escape analysis
author Lukas Stadler <lukas.stadler@jku.at>
date Thu, 13 Sep 2012 18:12:27 +0200
parents adf0879a41c1
children 69e94aa204b7
files graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/EscapeAnalysisPhase.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/ea/PartialEscapeAnalysisPhase.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CyclicMaterializeStoreNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MaterializeObjectNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/BoxedVirtualObjectNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectState.java
diffstat 8 files changed, 245 insertions(+), 70 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java	Thu Sep 13 11:41:43 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java	Thu Sep 13 18:12:27 2012 +0200
@@ -57,7 +57,9 @@
                     objectStates = new IdentityHashMap<>();
                 }
                 if (!objectStates.containsKey(state.object())) {
-                    objectStates.put(state.object(), state);
+                    if (!(state instanceof MaterializedObjectState) || ((MaterializedObjectState) state).materializedValue() != state.object()) {
+                        objectStates.put(state.object(), state);
+                    }
                 }
             }
             current = current.outerFrameState();
@@ -80,13 +82,13 @@
                             BoxedVirtualObjectNode boxedVirtualObjectNode = (BoxedVirtualObjectNode) vobj;
                             entry.getValue().setValues(new Value[]{toValue(boxedVirtualObjectNode.getUnboxedValue())});
                         } else {
-                            Value[] values = new Value[vobj.fieldsCount()];
+                            Value[] values = new Value[vobj.fields().length];
                             entry.getValue().setValues(values);
                             if (values.length > 0) {
                                 changed = true;
                                 VirtualObjectState currentField = (VirtualObjectState) objectStates.get(vobj);
                                 assert currentField != null;
-                                for (int i = 0; i < vobj.fieldsCount(); i++) {
+                                for (int i = 0; i < vobj.fields().length; i++) {
                                     values[i] = toValue(currentField.fieldValues().get(i));
                                 }
                             }
@@ -145,14 +147,14 @@
         if (value instanceof VirtualObjectNode) {
             VirtualObjectNode obj = (VirtualObjectNode) value;
             EscapeObjectState state = objectStates.get(obj);
-            if (state == null && obj.fieldsCount() > 0) {
+            if (state == null && obj.fields().length > 0) {
                 // null states occur for objects with 0 fields
                 throw new GraalInternalError("no mapping found for virtual object %s", obj);
             }
             if (state instanceof MaterializedObjectState) {
                 return toValue(((MaterializedObjectState) state).materializedValue());
             } else {
-                assert obj.fieldsCount() == 0 || state instanceof VirtualObjectState;
+                assert obj.fields().length == 0 || state instanceof VirtualObjectState;
                 VirtualObject ciObj = virtualObjects.get(value);
                 if (ciObj == null) {
                     ciObj = VirtualObject.get(obj.type(), null, virtualObjects.size());
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/EscapeAnalysisPhase.java	Thu Sep 13 11:41:43 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/EscapeAnalysisPhase.java	Thu Sep 13 18:12:27 2012 +0200
@@ -153,7 +153,7 @@
                 fields.put(escapeFields[i].representation(), i);
             }
             assert node.objectStamp().isExactType();
-            final VirtualObjectNode virtual = graph.add(new VirtualObjectNode(id, node.objectStamp().type(), escapeFields.length));
+            final VirtualObjectNode virtual = graph.add(new VirtualObjectNode(id, node.objectStamp().type(), escapeFields));
             Debug.log("new virtual object: " + virtual);
             node.replaceAtUsages(virtual);
             FixedNode next = node.next();
@@ -167,7 +167,7 @@
                 }
             }
 
-            if (virtual.fieldsCount() > 0) {
+            if (virtual.fields().length > 0) {
                 final BlockExitState startState = new BlockExitState(escapeFields, virtual);
                 new PostOrderNodeIterator<BlockExitState>(next, startState) {
 
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/ea/PartialEscapeAnalysisPhase.java	Thu Sep 13 11:41:43 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/ea/PartialEscapeAnalysisPhase.java	Thu Sep 13 18:12:27 2012 +0200
@@ -42,17 +42,31 @@
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.virtual.*;
 
-class EscapeRecord {
+abstract class EscapeRecord {
+
+    public final int id;
+    public final ResolvedJavaType type;
+    public final VirtualObjectNode virtualObject;
 
-    public final ResolvedJavaType type;
+    public EscapeRecord(int id, ResolvedJavaType type, VirtualObjectNode virtualObject) {
+        this.id = id;
+        this.type = type;
+        this.virtualObject = virtualObject;
+    }
+
+    public abstract String fieldName(int index);
+
+    public abstract int fieldCount();
+}
+
+class InstanceEscapeRecord extends EscapeRecord {
+
     public final EscapeField[] fields;
     public final HashMap<Object, Integer> fieldMap = new HashMap<>();
-    public final VirtualObjectNode virtualObject;
 
-    public EscapeRecord(ResolvedJavaType type, EscapeField[] fields, VirtualObjectNode virtualObject) {
-        this.type = type;
+    public InstanceEscapeRecord(int id, ResolvedJavaType type, VirtualObjectNode virtualObject, EscapeField[] fields) {
+        super(id, type, virtualObject);
         this.fields = fields;
-        this.virtualObject = virtualObject;
         for (int i = 0; i < fields.length; i++) {
             fieldMap.put(fields[i].representation(), i);
         }
@@ -60,7 +74,42 @@
 
     @Override
     public String toString() {
-        return MetaUtil.toJavaName(type, false) + "@" + (System.identityHashCode(this) % 10000);
+        return MetaUtil.toJavaName(type, false) + "@" + id;
+    }
+
+    @Override
+    public String fieldName(int index) {
+        return fields[index].name();
+    }
+
+    @Override
+    public int fieldCount() {
+        return fields.length;
+    }
+}
+
+class ArrayEscapeRecord extends EscapeRecord {
+
+    public final int length;
+
+    public ArrayEscapeRecord(int id, ResolvedJavaType type, VirtualObjectNode virtualObject, int length) {
+        super(id, type, virtualObject);
+        this.length = length;
+    }
+
+    @Override
+    public String toString() {
+        return MetaUtil.toJavaName(type.componentType(), false) + "[" + length + "]@" + id;
+    }
+
+    @Override
+    public String fieldName(int index) {
+        return "[" + index + "]";
+    }
+
+    @Override
+    public int fieldCount() {
+        return length;
     }
 }
 
@@ -75,6 +124,9 @@
     private static final DebugMetric metricOtherRemoved = Debug.metric("OtherRemoved");
     private static final DebugMetric metricMaterializations = Debug.metric("Materializations");
     private static final DebugMetric metricMaterializationFields = Debug.metric("MaterializationFields");
+    private static final DebugMetric metricLoopBailouts = Debug.metric("LoopBailouts");
+    private static final DebugMetric metricMonitorBailouts = Debug.metric("MonitorBailouts");
+
 
     private static final ValueNode DUMMY_NODE = new ValueNode(null) {
     };
@@ -94,7 +146,7 @@
     private final SchedulePhase schedule;
     private final NodeBitMap usages;
     private final NodeBitMap visitedNodes;
-    private boolean changed = false;
+    boolean changed = false;
 
     private final boolean changeGraph;
 
@@ -185,7 +237,7 @@
             }
             if (fieldState != null) {
                 for (int i = 0; i < fieldState.length; i++) {
-                    str.append(record.fields[i].name()).append('=').append(fieldState[i]).append(' ');
+                    str.append(record.fieldName(i)).append('=').append(fieldState[i]).append(' ');
                 }
             }
             if (materializedValue != null) {
@@ -232,7 +284,7 @@
             if (changeGraph) {
                 HashSet<EscapeRecord> deferred = new HashSet<>();
                 ArrayList<FixedWithNextNode> deferredStores = new ArrayList<>();
-                materializeBefore(fixed, record, deferred, deferredStores);
+                materializeChangedBefore(fixed, record, deferred, deferredStores);
                 for (FixedWithNextNode write : deferredStores) {
                     write.setProbability(fixed.probability());
                     graph.addBeforeFixed(fixed, write);
@@ -249,6 +301,7 @@
                 if (changeGraph) {
                     error("object materialized with lock: %s\n", record);
                 }
+                metricMonitorBailouts.increment();
                 throw new BailoutException("object materialized with lock");
             }
 
@@ -266,15 +319,16 @@
             obj.initialized = true;
         }
 
-        private void materializeBefore(FixedNode fixed, EscapeRecord record, HashSet<EscapeRecord> deferred, ArrayList<FixedWithNextNode> deferredStores) {
+        private void materializeChangedBefore(FixedNode fixed, EscapeRecord record, HashSet<EscapeRecord> deferred, ArrayList<FixedWithNextNode> deferredStores) {
             trace("materializing %s at %s", record, fixed);
             ObjectState obj = objectState(record);
             if (obj.lockCount > 0) {
                 error("object materialized with lock: %s\n", record);
+                metricMonitorBailouts.increment();
                 throw new BailoutException("object materialized with lock");
             }
 
-            MaterializeObjectNode materialize = graph.add(new MaterializeObjectNode(record.type, record.fields));
+            MaterializeObjectNode materialize = graph.add(new MaterializeObjectNode(record.type, record.virtualObject));
             materialize.setProbability(fixed.probability());
             ValueNode[] fieldState = obj.fieldState;
             metricMaterializations.increment();
@@ -286,15 +340,19 @@
                 ObjectState valueObj = objectState(fieldState[i]);
                 if (valueObj != null) {
                     if (valueObj.materializedValue == null) {
-                        materializeBefore(fixed, valueObj.record, deferred, deferredStores);
+                        materializeChangedBefore(fixed, valueObj.record, deferred, deferredStores);
                     }
                     if (deferred.contains(valueObj.record)) {
+                        Kind fieldKind;
                         if (record.type.isArrayClass()) {
-                            deferredStores.add(graph.add(new StoreIndexedNode(materialize, ConstantNode.forInt(i, graph), record.type.componentType().kind(), valueObj.materializedValue, -1)));
+                            deferredStores.add(graph.add(new CyclicMaterializeStoreNode(materialize, valueObj.materializedValue, i)));
+                            fieldKind = record.type.componentType().kind();
                         } else {
-                            deferredStores.add(graph.add(new StoreFieldNode(materialize, (ResolvedJavaField) record.fields[i].representation(), valueObj.materializedValue, -1)));
+                            InstanceEscapeRecord instanceRecord = (InstanceEscapeRecord) record;
+                            deferredStores.add(graph.add(new CyclicMaterializeStoreNode(materialize, valueObj.materializedValue, (ResolvedJavaField) instanceRecord.fields[i].representation())));
+                            fieldKind = instanceRecord.fields[i].type().kind();
                         }
-                        materialize.values().set(i, ConstantNode.defaultForKind(record.fields[i].type().kind(), graph));
+                        materialize.values().set(i, ConstantNode.defaultForKind(fieldKind, graph));
                     } else {
                         assert valueObj.initialized : "should be initialized: " + record + " at " + fixed;
                         materialize.values().set(i, valueObj.materializedValue);
@@ -373,12 +431,11 @@
                 }
 
                 if (op != null) {
-                    changed = true;
                     trace("{{%s}} ", node);
                     ResolvedJavaType type = op.type();
                     EscapeField[] fields = op.fields();
-                    VirtualObjectNode virtualObject = changeGraph ? graph.add(new VirtualObjectNode(virtualIds, type, fields.length)) : null;
-                    EscapeRecord record = new EscapeRecord(type, fields, virtualObject);
+                    VirtualObjectNode virtualObject = changeGraph ? graph.add(new VirtualObjectNode(virtualIds, type, fields)) : null;
+                    EscapeRecord record = type.isArrayClass() ? new ArrayEscapeRecord(virtualIds, type, virtualObject, fields.length) : new InstanceEscapeRecord(virtualIds, type, virtualObject, fields);
                     ValueNode[] fieldState = changeGraph ? op.fieldState() : new ValueNode[fields.length];
                     if (changeGraph) {
                         metricAllocationRemoved.increment();
@@ -478,6 +535,7 @@
                         obj.lockCount--;
                     }
                     if (changeGraph) {
+                        changed = true;
                         if (obj.materializedValue == null) {
                             metricLockRemoved.increment();
                             node.replaceFirstInput(x.object(), obj.record.virtualObject);
@@ -488,16 +546,32 @@
                     }
                     usageFound = true;
                 }
+            } else if (node instanceof CyclicMaterializeStoreNode) {
+                CyclicMaterializeStoreNode x = (CyclicMaterializeStoreNode) node;
+                ObjectState obj = state.objectState(x.object());
+                assert obj != null : x;
+                if (obj.record.type.isArrayClass()) {
+                    obj.fieldState[x.targetIndex()] = x.value();
+                } else {
+                    InstanceEscapeRecord record = (InstanceEscapeRecord) obj.record;
+                    int index = record.fieldMap.get(x.targetField());
+                    obj.fieldState[index] = x.value();
+                }
+                if (changeGraph) {
+                    graph.removeFixed(x);
+                }
+                usageFound = true;
             } else if (node instanceof LoadFieldNode) {
                 LoadFieldNode x = (LoadFieldNode) node;
                 ObjectState obj = state.objectState(x.object());
                 assert obj != null : x;
-                if (!obj.record.fieldMap.containsKey(x.field())) {
+                InstanceEscapeRecord record = (InstanceEscapeRecord) obj.record;
+                if (!record.fieldMap.containsKey(x.field())) {
                     // the field does not exist in the virtual object
                     ensureMaterialized(state, obj, x);
                 }
                 if (obj.materializedValue == null) {
-                    int index = obj.record.fieldMap.get(x.field());
+                    int index = record.fieldMap.get(x.field());
                     ValueNode result = obj.fieldState[index];
                     ObjectState resultObj = state.objectState(result);
                     if (resultObj != null) {
@@ -511,6 +585,7 @@
                     if (changeGraph) {
                         metricLoadRemoved.increment();
                     }
+                    changed = true;
                 } else {
                     if (changeGraph) {
                         x.replaceFirstInput(x.object(), obj.materializedValue);
@@ -523,17 +598,19 @@
                 ValueNode value = x.value();
                 ObjectState obj = state.objectState(object);
                 if (obj != null) {
-                    if (!obj.record.fieldMap.containsKey(x.field())) {
+                    InstanceEscapeRecord record = (InstanceEscapeRecord) obj.record;
+                    if (!record.fieldMap.containsKey(x.field())) {
                         // the field does not exist in the virtual object
                         ensureMaterialized(state, obj, x);
                     }
                     if (obj.materializedValue == null) {
-                        int index = obj.record.fieldMap.get(x.field());
+                        int index = record.fieldMap.get(x.field());
                         obj.fieldState[index] = value;
                         if (changeGraph) {
                             graph.removeFixed(x);
                             metricStoreRemoved.increment();
                         }
+                        changed = true;
                     } else {
                         if (changeGraph) {
                             x.replaceFirstInput(object, obj.materializedValue);
@@ -575,6 +652,7 @@
                             if (changeGraph) {
                                 metricLoadRemoved.increment();
                             }
+                            changed = true;
                         }
                     } else {
                         if (changeGraph) {
@@ -605,6 +683,7 @@
                                 graph.removeFixed(x);
                                 metricStoreRemoved.increment();
                             }
+                            changed = true;
                         }
                     } else {
                         if (changeGraph) {
@@ -631,7 +710,7 @@
                 ObjectState obj = state.objectState(x.array());
                 assert obj != null : x;
                 if (changeGraph) {
-                    graph.replaceFixedWithFloating(x, ConstantNode.forInt(obj.record.fields.length, graph));
+                    graph.replaceFixedWithFloating(x, ConstantNode.forInt(((ArrayEscapeRecord) obj.record).length, graph));
                     metricOtherRemoved.increment();
                 }
                 usageFound = true;
@@ -671,11 +750,13 @@
                         graph.replaceFloating(x, ConstantNode.forBoolean(false, graph));
                         usageFound = true;
                         metricOtherRemoved.increment();
+                        changed = true;
                     } else if (xVirtual && yVirtual) {
                         // both are virtual: check if they refer to the same object
                         graph.replaceFloating(x, ConstantNode.forBoolean(xObj == yObj, graph));
                         usageFound = true;
                         metricOtherRemoved.increment();
+                        changed = true;
                     } else {
                         assert xObj != null || yObj != null;
                         if (xObj != null) {
@@ -726,13 +807,14 @@
                                             break;
                                         }
                                     }
-                                    assert virtualObj != null;
-                                    virtual.add(virtualObj);
+                                    if (virtualObj != null) {
+                                        virtual.add(virtualObj);
+                                    }
                                 }
                             }
                         });
                         for (ObjectState obj : state.states()) {
-                            if (obj.lockCount > 0) {
+                            if (obj.materializedValue == null && obj.lockCount > 0) {
                                 virtual.add(obj);
                             }
                         }
@@ -939,7 +1021,7 @@
                         if (i == 0) {
                             sameRecord = obj.record;
                             sameType = obj.record.type;
-                            sameFieldCount = obj.record.fields.length;
+                            sameFieldCount = obj.record.fieldCount();
                         } else {
                             if (sameRecord != obj.record) {
                                 sameRecord = null;
@@ -947,7 +1029,7 @@
                             if (sameType != obj.record.type) {
                                 sameType = null;
                             }
-                            if (sameFieldCount != obj.record.fields.length) {
+                            if (sameFieldCount != obj.record.fieldCount()) {
                                 sameFieldCount = -1;
                             }
                         }
@@ -1045,6 +1127,7 @@
                             if (changeGraph) {
                                 error("object materialized within loop: %s\n", obj.record);
                             }
+                            metricLoopBailouts.increment();
                             throw new BailoutException("object materialized within loop");
                         }
                         for (int i = 0; endObj.fieldState != null && i < endObj.fieldState.length; i++) {
@@ -1104,30 +1187,38 @@
 
     @Override
     protected void run(StructuredGraph graph) {
+        iteration(graph, 0);
+    }
+
+
+    private void iteration(final StructuredGraph graph, final int num) {
         HashSet<ValueNode> allocations = new HashSet<>();
         SchedulePhase schedule = new SchedulePhase();
         schedule.apply(graph, false);
+        EscapeAnalysisIteration iteration = null;
         try {
-            new EscapeAnalysisIteration(graph, schedule, runtime, allocations, false).run();
+            iteration = new EscapeAnalysisIteration(graph, schedule, runtime, allocations, false);
+            iteration.run();
         } catch (BailoutException e) {
             // do nothing if the if the escape analysis bails out during the analysis iteration...
             return;
         }
-        try {
-            new EscapeAnalysisIteration(graph, schedule, runtime, allocations, true).run();
-            new CanonicalizerPhase(target, runtime, assumptions).apply(graph);
-        } catch (BailoutException e) {
-            throw new GraalInternalError(e);
-        }
-    }
-
-    public static boolean isValidConstantIndex(AccessIndexedNode x) {
-        Constant index = x.index().asConstant();
-        if (x.array() instanceof NewArrayNode) {
-            Constant length = ((NewArrayNode) x.array()).dimension(0).asConstant();
-            return index != null && length != null && index.asInt() >= 0 && index.asInt() < length.asInt();
-        } else {
-            return false;
+        if (iteration.changed) {
+            try {
+                new EscapeAnalysisIteration(graph, schedule, runtime, allocations, true).run();
+                new CanonicalizerPhase(target, runtime, assumptions).apply(graph);
+            } catch (BailoutException e) {
+                throw new GraalInternalError(e);
+            }
+            // next round...
+            if (num < 2) {
+                Debug.scope("next", new Runnable() {
+                    @Override
+                    public void run() {
+                        iteration(graph, num + 1);
+                    }
+                });
+            }
         }
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CyclicMaterializeStoreNode.java	Thu Sep 13 18:12:27 2012 +0200
@@ -0,0 +1,84 @@
+/*
+ * 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.*;
+
+/**
+ * The {@code StoreFieldNode} represents a write to a static or instance field.
+ */
+@NodeInfo(nameTemplate = "MaterializeStore#{p#field/s}")
+public final class CyclicMaterializeStoreNode extends FixedWithNextNode implements Lowerable {
+
+    @Input private ValueNode object;
+    @Input private ValueNode value;
+    private final Object target;
+
+    public ValueNode object() {
+        return object;
+    }
+
+    public ValueNode value() {
+        return value;
+    }
+
+    public ResolvedJavaField targetField() {
+        return (ResolvedJavaField) target;
+    }
+
+    public int targetIndex() {
+        return (int) target;
+    }
+
+    public CyclicMaterializeStoreNode(ValueNode object, ValueNode value, ResolvedJavaField field) {
+        super(StampFactory.forVoid());
+        this.object = object;
+        this.value = value;
+        this.target = field;
+    }
+
+    public CyclicMaterializeStoreNode(ValueNode object, ValueNode value, int index) {
+        super(StampFactory.forVoid());
+        this.object = object;
+        this.value = value;
+        this.target = index;
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        StructuredGraph graph = (StructuredGraph) graph();
+        ResolvedJavaType type = object.objectStamp().type();
+        FixedWithNextNode store;
+        if (target instanceof Integer) {
+            store = graph.add(new StoreIndexedNode(object, ConstantNode.forInt((int) target, graph), type.componentType().kind(), value, -1));
+        } else {
+            assert target instanceof ResolvedJavaField;
+            store = graph.add(new StoreFieldNode(object, (ResolvedJavaField) target, value, -1));
+        }
+        graph.replaceFixedWithFixed(this, store);
+    }
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MaterializeObjectNode.java	Thu Sep 13 11:41:43 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MaterializeObjectNode.java	Thu Sep 13 18:12:27 2012 +0200
@@ -35,24 +35,20 @@
 public final class MaterializeObjectNode extends FixedWithNextNode implements EscapeAnalyzable, Lowerable, Node.IterableNodeType, Canonicalizable {
 
     @Input private final NodeInputList<ValueNode> values;
+    @Input private final VirtualObjectNode virtualObject;
     private final ResolvedJavaType type;
-    private final EscapeField[] fields;
 
-    public MaterializeObjectNode(ResolvedJavaType type, EscapeField[] fields) {
+    public MaterializeObjectNode(ResolvedJavaType type, VirtualObjectNode virtualObject) {
         super(StampFactory.exactNonNull(type));
         this.type = type;
-        this.fields = fields;
-        this.values = new NodeInputList<>(this, fields.length);
+        this.virtualObject = virtualObject;
+        this.values = new NodeInputList<>(this, virtualObject.fields().length);
     }
 
     public ResolvedJavaType type() {
         return type;
     }
 
-    public EscapeField[] getFields() {
-        return fields;
-    }
-
     public NodeInputList<ValueNode> values() {
         return values;
     }
@@ -60,6 +56,7 @@
     @Override
     public void lower(LoweringTool tool) {
         StructuredGraph graph = (StructuredGraph) graph();
+        EscapeField[] fields = virtualObject.fields();
         if (type.isArrayClass()) {
             ResolvedJavaType element = type.componentType();
             NewArrayNode newArray;
@@ -118,7 +115,7 @@
 
         @Override
         public EscapeField[] fields() {
-            return fields;
+            return virtualObject.fields();
         }
 
         @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/BoxedVirtualObjectNode.java	Thu Sep 13 11:41:43 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/BoxedVirtualObjectNode.java	Thu Sep 13 18:12:27 2012 +0200
@@ -33,7 +33,7 @@
     @Input ValueNode unboxedValue;
 
     public BoxedVirtualObjectNode(int id, ResolvedJavaType type, ValueNode unboxedValue) {
-        super(id, type, 1);
+        super(id, type, new EscapeField[1]);
         this.unboxedValue = unboxedValue;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectNode.java	Thu Sep 13 11:41:43 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectNode.java	Thu Sep 13 18:12:27 2012 +0200
@@ -27,22 +27,23 @@
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
+
 @NodeInfo(nameTemplate = "VirtualObject {p#type}")
 public class VirtualObjectNode extends FloatingNode implements LIRLowerable {
 
     @SuppressWarnings("unused")
     private final int id;
     private final ResolvedJavaType type;
-    private final int fieldsCount;
+    private final EscapeField[] fields;
 
-    public VirtualObjectNode(int id, ResolvedJavaType type, int fieldCount) {
+    public VirtualObjectNode(int id, ResolvedJavaType type, EscapeField[] fields) {
         super(StampFactory.virtual());
         this.id = id;
         this.type = type;
-        this.fieldsCount = fieldCount;
+        this.fields = fields;
     }
 
-    public JavaType type() {
+    public ResolvedJavaType type() {
         return type;
     }
 
@@ -60,7 +61,7 @@
         }
     }
 
-    public int fieldsCount() {
-        return fieldsCount;
+    public EscapeField[] fields() {
+        return fields;
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectState.java	Thu Sep 13 11:41:43 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectState.java	Thu Sep 13 18:12:27 2012 +0200
@@ -41,13 +41,13 @@
 
     public VirtualObjectState(VirtualObjectNode object, ValueNode[] fieldValues) {
         super(object);
-        assert object.fieldsCount() == fieldValues.length;
+        assert object.fields().length == fieldValues.length;
         this.fieldValues = new NodeInputList<>(this, fieldValues);
     }
 
     private VirtualObjectState(VirtualObjectNode object, List<ValueNode> fieldValues) {
         super(object);
-        assert object.fieldsCount() == fieldValues.size();
+        assert object.fields().length == fieldValues.size();
         this.fieldValues = new NodeInputList<>(this, fieldValues);
     }