# HG changeset patch # User Lukas Stadler # Date 1347553025 -7200 # Node ID 2ba1f4cdecd0cb8f478b0d32458d07d17e0963c6 # Parent 69e94aa204b74eda2d60f84884f275023797d2ce# Parent d44835610b527ec78090e59a19bc03f0e5fc37c9 Merge. diff -r d44835610b52 -r 2ba1f4cdecd0 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java Thu Sep 13 17:45:04 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java Thu Sep 13 18:17:05 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()); diff -r d44835610b52 -r 2ba1f4cdecd0 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/EscapeAnalysisPhase.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/EscapeAnalysisPhase.java Thu Sep 13 17:45:04 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/EscapeAnalysisPhase.java Thu Sep 13 18:17:05 2012 +0200 @@ -143,17 +143,17 @@ private void process() { for (Node usage : node.usages().snapshot()) { - op.beforeUpdate(node, usage); + op.beforeUpdate(usage); } } public void removeAllocation() { - escapeFields = op.fields(node); + escapeFields = op.fields(); for (int i = 0; i < escapeFields.length; i++) { 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(next, startState) { diff -r d44835610b52 -r 2ba1f4cdecd0 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/ea/PartialEscapeAnalysisPhase.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/ea/PartialEscapeAnalysisPhase.java Thu Sep 13 17:45:04 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/ea/PartialEscapeAnalysisPhase.java Thu Sep 13 18:17:05 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 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 deferred = new HashSet<>(); ArrayList 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 deferred, ArrayList deferredStores) { + private void materializeChangedBefore(FixedNode fixed, EscapeRecord record, HashSet deferred, ArrayList 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,17 +431,13 @@ } if (op != null) { - changed = true; trace("{{%s}} ", node); - ResolvedJavaType type = op.type(node); - EscapeField[] fields = op.fields(node); - VirtualObjectNode virtualObject = changeGraph ? graph.add(new VirtualObjectNode(virtualIds, type, fields.length)) : null; - EscapeRecord record = new EscapeRecord(type, fields, virtualObject); - ValueNode[] fieldState = new ValueNode[fields.length]; + ResolvedJavaType type = op.type(); + EscapeField[] fields = op.fields(); + 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) { - for (int i = 0; i < fields.length; i++) { - fieldState[i] = ConstantNode.defaultForKind(fields[i].type().kind(), virtualObject.graph()); - } metricAllocationRemoved.increment(); metricAllocationFieldsRemoved.add(fieldState.length); } else { @@ -481,6 +535,7 @@ obj.lockCount--; } if (changeGraph) { + changed = true; if (obj.materializedValue == null) { metricLockRemoved.increment(); node.replaceFirstInput(x.object(), obj.record.virtualObject); @@ -491,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) { @@ -514,6 +585,7 @@ if (changeGraph) { metricLoadRemoved.increment(); } + changed = true; } else { if (changeGraph) { x.replaceFirstInput(x.object(), obj.materializedValue); @@ -526,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); @@ -578,6 +652,7 @@ if (changeGraph) { metricLoadRemoved.increment(); } + changed = true; } } else { if (changeGraph) { @@ -608,6 +683,7 @@ graph.removeFixed(x); metricStoreRemoved.increment(); } + changed = true; } } else { if (changeGraph) { @@ -634,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; @@ -674,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) { @@ -729,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); } } @@ -942,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; @@ -950,7 +1029,7 @@ if (sameType != obj.record.type) { sameType = null; } - if (sameFieldCount != obj.record.fields.length) { + if (sameFieldCount != obj.record.fieldCount()) { sameFieldCount = -1; } } @@ -1048,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++) { @@ -1107,30 +1187,38 @@ @Override protected void run(StructuredGraph graph) { + iteration(graph, 0); + } + + + private void iteration(final StructuredGraph graph, final int num) { HashSet 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); + } + }); + } } } } diff -r d44835610b52 -r 2ba1f4cdecd0 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CyclicMaterializeStoreNode.java --- /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:17:05 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); + } +} diff -r d44835610b52 -r 2ba1f4cdecd0 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MaterializeObjectNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MaterializeObjectNode.java Thu Sep 13 17:45:04 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MaterializeObjectNode.java Thu Sep 13 18:17:05 2012 +0200 @@ -22,34 +22,33 @@ */ package com.oracle.graal.nodes.java; +import java.util.*; + 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.*; +import com.oracle.graal.nodes.virtual.*; @NodeInfo(nameTemplate = "Materialize {p#type/s}") -public final class MaterializeObjectNode extends FixedWithNextNode implements Lowerable, Node.IterableNodeType, Canonicalizable { +public final class MaterializeObjectNode extends FixedWithNextNode implements EscapeAnalyzable, Lowerable, Node.IterableNodeType, Canonicalizable { @Input private final NodeInputList 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 values() { return values; } @@ -57,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; @@ -100,4 +100,37 @@ return this; } } + + @Override + public EscapeOp getEscapeOp() { + return new EscapeOpImpl(); + } + + private final class EscapeOpImpl extends EscapeOp { + + @Override + public ResolvedJavaType type() { + return type; + } + + @Override + public EscapeField[] fields() { + return virtualObject.fields(); + } + + @Override + public ValueNode[] fieldState() { + return values.toArray(new ValueNode[values.size()]); + } + + @Override + public void beforeUpdate(Node usage) { + throw new UnsupportedOperationException("MaterializeNode can only be escape analyzed using partial escape analysis"); + } + + @Override + public int updateState(VirtualObjectNode node, Node current, Map fieldIndex, ValueNode[] fieldState) { + throw new UnsupportedOperationException("MaterializeNode can only be escape analyzed using partial escape analysis"); + } + } } diff -r d44835610b52 -r 2ba1f4cdecd0 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewArrayNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewArrayNode.java Thu Sep 13 17:45:04 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewArrayNode.java Thu Sep 13 18:17:05 2012 +0200 @@ -30,6 +30,7 @@ import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; import com.oracle.graal.nodes.util.*; +import com.oracle.graal.nodes.virtual.*; /** * The {@code NewArrayNode} class is the base of all instructions that allocate arrays. @@ -85,58 +86,65 @@ return 1; } - public EscapeOp getEscapeOp() { - Constant constantLength = length().asConstant(); - if (constantLength != null && constantLength.asInt() >= 0 && constantLength.asInt() < MaximumEscapeAnalysisArrayLength) { - return ESCAPE; - } else { - return null; - } - } - @Override public void lower(LoweringTool tool) { tool.getRuntime().lower(this, tool); } - private static final EscapeOp ESCAPE = new EscapeOp() { + @Override + public EscapeOp getEscapeOp() { + Constant constantLength = length().asConstant(); + if (constantLength != null && constantLength.asInt() >= 0 && constantLength.asInt() < MaximumEscapeAnalysisArrayLength) { + return new EscapeOpImpl(); + } else { + return null; + } + } + + private final class EscapeOpImpl extends EscapeOp { @Override - public EscapeField[] fields(Node node) { - NewArrayNode x = (NewArrayNode) node; - assert x.elementType.arrayOf().isArrayClass(); - int length = x.dimension(0).asConstant().asInt(); - EscapeField[] fields = new EscapeField[length]; - for (int i = 0; i < length; i++) { + public ResolvedJavaType type() { + return elementType.arrayOf(); + } + + @Override + public EscapeField[] fields() { + int constantLength = dimension(0).asConstant().asInt(); + EscapeField[] fields = new EscapeField[constantLength]; + for (int i = 0; i < constantLength; i++) { Integer representation = i; - fields[i] = new EscapeField(Integer.toString(i), representation, ((NewArrayNode) node).elementType()); + fields[i] = new EscapeField(Integer.toString(i), representation, elementType()); } return fields; } @Override - public ResolvedJavaType type(Node node) { - NewArrayNode x = (NewArrayNode) node; - return x.elementType.arrayOf(); + public ValueNode[] fieldState() { + ValueNode[] state = new ValueNode[dimension(0).asConstant().asInt()]; + for (int i = 0; i < state.length; i++) { + state[i] = ConstantNode.defaultForKind(elementType().kind(), graph()); + } + return state; } @Override - public void beforeUpdate(Node node, Node usage) { + public void beforeUpdate(Node usage) { if (usage instanceof ArrayLengthNode) { ArrayLengthNode x = (ArrayLengthNode) usage; - StructuredGraph graph = (StructuredGraph) node.graph(); - x.replaceAtUsages(((NewArrayNode) node).dimension(0)); + StructuredGraph graph = (StructuredGraph) graph(); + x.replaceAtUsages(dimension(0)); graph.removeFixed(x); } else { - super.beforeUpdate(node, usage); + beforeUpdate(NewArrayNode.this, usage); } } @Override - public int updateState(Node node, Node current, Map fieldIndex, ValueNode[] fieldState) { + public int updateState(VirtualObjectNode virtualObject, Node current, Map fieldIndex, ValueNode[] fieldState) { if (current instanceof AccessIndexedNode) { AccessIndexedNode x = (AccessIndexedNode) current; - if (GraphUtil.unProxify(x.array()) == node) { + if (GraphUtil.unProxify(x.array()) == virtualObject) { int index = ((AccessIndexedNode) current).index().asConstant().asInt(); StructuredGraph graph = (StructuredGraph) x.graph(); if (current instanceof LoadIndexedNode) { @@ -151,5 +159,6 @@ } return -1; } - }; + + } } diff -r d44835610b52 -r 2ba1f4cdecd0 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewInstanceNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewInstanceNode.java Thu Sep 13 17:45:04 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewInstanceNode.java Thu Sep 13 18:17:05 2012 +0200 @@ -30,6 +30,7 @@ import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; import com.oracle.graal.nodes.util.*; +import com.oracle.graal.nodes.virtual.*; /** * The {@code NewInstanceNode} represents the allocation of an instance class object. @@ -72,11 +73,17 @@ gen.visitNewInstance(this); } + @Override public EscapeOp getEscapeOp() { - return instanceClass == null ? null : ESCAPE; + return instanceClass == null ? null : new EscapeOpImpl(); } - private static final EscapeOp ESCAPE = new EscapeOp() { + private final class EscapeOpImpl extends EscapeOp { + + @Override + public ResolvedJavaType type() { + return instanceClass(); + } private void fillEscapeFields(ResolvedJavaType type, List escapeFields) { if (type != null) { @@ -90,32 +97,35 @@ } @Override - public ResolvedJavaType type(Node node) { - NewInstanceNode x = (NewInstanceNode) node; - return x.instanceClass(); - } - - @Override - public EscapeField[] fields(Node node) { - NewInstanceNode x = (NewInstanceNode) node; - assert !x.instanceClass().isArrayClass(); + public EscapeField[] fields() { + assert !instanceClass().isArrayClass(); List escapeFields = new ArrayList<>(); - fillEscapeFields(x.instanceClass(), escapeFields); + fillEscapeFields(instanceClass(), escapeFields); return escapeFields.toArray(new EscapeField[escapeFields.size()]); } @Override - public void beforeUpdate(Node node, Node usage) { + public ValueNode[] fieldState() { + EscapeField[] fields = fields(); + ValueNode[] state = new ValueNode[fields.length]; + for (int i = 0; i < state.length; i++) { + state[i] = ConstantNode.defaultForKind(fields[i].type().kind(), graph()); + } + return state; + } + + @Override + public void beforeUpdate(Node usage) { if (usage instanceof RegisterFinalizerNode) { RegisterFinalizerNode x = (RegisterFinalizerNode) usage; ((StructuredGraph) x.graph()).removeFixed(x); } else { - super.beforeUpdate(node, usage); + super.beforeUpdate(NewInstanceNode.this, usage); } } @Override - public int updateState(Node node, Node current, Map fieldIndex, ValueNode[] fieldState) { + public int updateState(VirtualObjectNode node, Node current, Map fieldIndex, ValueNode[] fieldState) { if (current instanceof AccessFieldNode) { AccessFieldNode x = (AccessFieldNode) current; if (GraphUtil.unProxify(x.object()) == node) { @@ -134,5 +144,5 @@ } return -1; } - }; + } } diff -r d44835610b52 -r 2ba1f4cdecd0 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/EscapeOp.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/EscapeOp.java Thu Sep 13 17:45:04 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/EscapeOp.java Thu Sep 13 18:17:05 2012 +0200 @@ -29,14 +29,28 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.virtual.*; public abstract class EscapeOp { - public abstract EscapeField[] fields(Node node); + /** + * Returns the type of object that is created by the associated node. + */ + public abstract ResolvedJavaType type(); - public abstract ResolvedJavaType type(Node node); + /** + * Returns all the fields that the objects create by the associated node have. + */ + public abstract EscapeField[] fields(); - public void beforeUpdate(Node node, Node usage) { + /** + * Returns the initial value of all fields, in the same order as {@link #fields()}. + */ + public abstract ValueNode[] fieldState(); + + public abstract void beforeUpdate(Node usage); + + protected static void beforeUpdate(Node node, Node usage) { // IsNullNode and IsTypeNode should have been eliminated by the CanonicalizerPhase, but we can't rely on this if (usage instanceof IsNullNode) { IsNullNode x = (IsNullNode) usage; @@ -50,7 +64,6 @@ } } - public abstract int updateState(Node node, Node current, Map fieldIndex, ValueNode[] fieldState); - + public abstract int updateState(VirtualObjectNode virtualObject, Node current, Map fieldIndex, ValueNode[] fieldState); } diff -r d44835610b52 -r 2ba1f4cdecd0 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/BoxedVirtualObjectNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/BoxedVirtualObjectNode.java Thu Sep 13 17:45:04 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/BoxedVirtualObjectNode.java Thu Sep 13 18:17:05 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; } diff -r d44835610b52 -r 2ba1f4cdecd0 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectNode.java Thu Sep 13 17:45:04 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectNode.java Thu Sep 13 18:17:05 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; } } diff -r d44835610b52 -r 2ba1f4cdecd0 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectState.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectState.java Thu Sep 13 17:45:04 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectState.java Thu Sep 13 18:17:05 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 fieldValues) { super(object); - assert object.fieldsCount() == fieldValues.size(); + assert object.fields().length == fieldValues.size(); this.fieldValues = new NodeInputList<>(this, fieldValues); }