Mercurial > hg > graal-jvmci-8
changeset 9501:bef43373de39
coalesce allocations during escape analysis
line wrap: on
line diff
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/BoxingEliminationTest.java Mon Apr 29 18:38:16 2013 +0200 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/BoxingEliminationTest.java Mon Apr 29 14:53:08 2013 +0200 @@ -31,7 +31,6 @@ import com.oracle.graal.phases.*; import com.oracle.graal.phases.common.*; import com.oracle.graal.phases.tiers.*; -import com.oracle.graal.virtual.nodes.*; import com.oracle.graal.virtual.phases.ea.*; /** @@ -334,10 +333,6 @@ new CanonicalizerPhase().apply(graph, context); new PartialEscapeAnalysisPhase(false, false).apply(graph, context); - for (MaterializeObjectNode materialize : graph.getNodes(MaterializeObjectNode.class)) { - materialize.getVirtualObject().materializeAt(materialize, materialize.getValues(), false, materialize.getLockCount()); - } - new CullFrameStatesPhase().apply(graph); new DeadCodeEliminationPhase().apply(graph); new CanonicalizerPhase().apply(graph, context);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EscapeAnalysisTest.java Mon Apr 29 18:38:16 2013 +0200 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EscapeAnalysisTest.java Mon Apr 29 14:53:08 2013 +0200 @@ -35,16 +35,15 @@ import com.oracle.graal.java.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.virtual.*; import com.oracle.graal.phases.*; import com.oracle.graal.phases.common.*; import com.oracle.graal.phases.tiers.*; -import com.oracle.graal.virtual.nodes.*; import com.oracle.graal.virtual.phases.ea.*; /** - * In these test cases the probability of all invokes is set to a high value, such that an - * InliningPhase should inline them all. After that, the EscapeAnalysisPhase is expected to remove - * all allocations and return the correct values. + * The PartialEscapeAnalysisPhase is expected to remove all allocations and return the correct + * values. */ public class EscapeAnalysisTest extends GraalCompilerTest { @@ -230,7 +229,7 @@ Assert.assertTrue(returnNode.result().toString(), returnNode.result().isConstant()); Assert.assertEquals(expectedConstantResult, returnNode.result().asConstant()); } - int newInstanceCount = graph.getNodes(NewInstanceNode.class).count() + graph.getNodes(NewArrayNode.class).count() + graph.getNodes(MaterializeObjectNode.class).count(); + int newInstanceCount = graph.getNodes(NewInstanceNode.class).count() + graph.getNodes(NewArrayNode.class).count() + graph.getNodes(CommitAllocationNode.class).count(); Assert.assertEquals(0, newInstanceCount); return returnNode; }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PartialEscapeAnalysisTest.java Mon Apr 29 18:38:16 2013 +0200 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PartialEscapeAnalysisTest.java Mon Apr 29 14:53:08 2013 +0200 @@ -35,17 +35,16 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.util.*; +import com.oracle.graal.nodes.virtual.*; import com.oracle.graal.phases.*; import com.oracle.graal.phases.common.*; import com.oracle.graal.phases.graph.*; import com.oracle.graal.phases.tiers.*; -import com.oracle.graal.virtual.nodes.*; import com.oracle.graal.virtual.phases.ea.*; /** - * In these test cases the probability of all invokes is set to a high value, such that an - * InliningPhase should inline them all. After that, the PartialEscapeAnalysisPhase is expected to - * remove all allocations and return the correct values. + * The PartialEscapeAnalysisPhase is expected to remove all allocations and return the correct + * values. */ public class PartialEscapeAnalysisTest extends GraalCompilerTest { @@ -137,9 +136,9 @@ NodesToDoubles nodeProbabilities = new ComputeProbabilityClosure(result).apply(); double probabilitySum = 0; int materializeCount = 0; - for (MaterializeObjectNode materialize : result.getNodes(MaterializeObjectNode.class)) { - probabilitySum += nodeProbabilities.get(materialize); - materializeCount++; + for (CommitAllocationNode materialize : result.getNodes(CommitAllocationNode.class)) { + probabilitySum += nodeProbabilities.get(materialize) * materialize.getVirtualObjects().size(); + materializeCount += materialize.getVirtualObjects().size(); } Assert.assertEquals("unexpected number of MaterializeObjectNodes", expectedCount, materializeCount); Assert.assertEquals("unexpected probability of MaterializeObjectNodes", expectedProbability, probabilitySum, 0.01);
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java Mon Apr 29 18:38:16 2013 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java Mon Apr 29 14:53:08 2013 +0200 @@ -165,7 +165,6 @@ throw new GraalInternalError("no mapping found for virtual object %s", obj); } if (state instanceof MaterializedObjectState) { - assert !(((MaterializedObjectState) state).materializedValue() instanceof VirtualObjectNode); return toValue(((MaterializedObjectState) state).materializedValue()); } else { assert obj.entryCount() == 0 || state instanceof VirtualObjectState;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java Mon Apr 29 18:38:16 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java Mon Apr 29 14:53:08 2013 +0200 @@ -78,6 +78,7 @@ import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; +import com.oracle.graal.nodes.virtual.*; import com.oracle.graal.phases.*; import com.oracle.graal.printer.*; import com.oracle.graal.replacements.*; @@ -773,6 +774,64 @@ FixedGuardNode node = (FixedGuardNode) n; ValueAnchorNode newAnchor = graph.add(new ValueAnchorNode(tool.createGuard(node.condition(), node.getReason(), node.getAction(), node.isNegated()))); graph.replaceFixedWithFixed(node, newAnchor); + } else if (n instanceof CommitAllocationNode) { + CommitAllocationNode commit = (CommitAllocationNode) n; + + graph.addBeforeFixed(commit, graph.add(new RegionStartNode())); + List<ValueNode> allocations = new ArrayList<>(commit.getVirtualObjects().size()); + for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) { + VirtualObjectNode virtual = commit.getVirtualObjects().get(objIndex); + int lockCount = commit.getLockCounts().get(objIndex); + int entryCount = virtual.entryCount(); + + FixedWithNextNode newObject; + if (virtual instanceof VirtualInstanceNode) { + newObject = graph.add(new NewInstanceNode(virtual.type(), true, lockCount > 0)); + } else { + ResolvedJavaType element = ((VirtualArrayNode) virtual).componentType(); + newObject = graph.add(new NewArrayNode(element, ConstantNode.forInt(entryCount, graph), true, lockCount > 0)); + } + graph.addBeforeFixed(commit, newObject); + allocations.add(newObject); + } + int valuePos = 0; + for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) { + VirtualObjectNode virtual = commit.getVirtualObjects().get(objIndex); + int entryCount = virtual.entryCount(); + + ValueNode newObject = allocations.get(objIndex); + if (virtual instanceof VirtualInstanceNode) { + VirtualInstanceNode instance = (VirtualInstanceNode) virtual; + for (int i = 0; i < entryCount; i++) { + ValueNode value = commit.getValues().get(valuePos++); + if (value instanceof VirtualObjectNode) { + value = allocations.get(commit.getVirtualObjects().indexOf(value)); + } + graph.addBeforeFixed(commit, graph.add(new WriteNode(newObject, value, createFieldLocation(graph, (HotSpotResolvedJavaField) instance.field(i)), WriteBarrierType.NONE))); + } + } else { + VirtualArrayNode array = (VirtualArrayNode) virtual; + ResolvedJavaType element = array.componentType(); + for (int i = 0; i < entryCount; i++) { + ValueNode value = commit.getValues().get(valuePos++); + if (value instanceof VirtualObjectNode) { + int indexOf = commit.getVirtualObjects().indexOf(value); + assert indexOf != -1 : commit + " " + value; + value = allocations.get(indexOf); + } + graph.addBeforeFixed(commit, graph.add(new WriteNode(newObject, value, createArrayLocation(graph, element.getKind(), ConstantNode.forInt(i, graph)), WriteBarrierType.NONE))); + } + } + } + graph.addBeforeFixed(commit, graph.add(new RegionEndNode())); + for (Node usage : commit.usages().snapshot()) { + AllocatedObjectNode addObject = (AllocatedObjectNode) usage; + int index = commit.getVirtualObjects().indexOf(addObject.getVirtualObject()); + FixedValueAnchorNode anchor = graph.add(new FixedValueAnchorNode(allocations.get(index))); + graph.addBeforeFixed(commit, anchor); + graph.replaceFloating(addObject, anchor); + } + graph.removeFixed(commit); } else if (n instanceof CheckCastNode) { checkcastSnippets.lower((CheckCastNode) n, tool); } else if (n instanceof CheckCastDynamicNode) {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/AllocatedObjectNode.java Mon Apr 29 14:53:08 2013 +0200 @@ -0,0 +1,60 @@ +/* + * 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.virtual; + +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; + +/** + * Selects one object from a {@link CommitAllocationNode}. The object is identified by its + * {@link VirtualObjectNode}. + */ +public class AllocatedObjectNode extends FloatingNode implements Virtualizable { + + @Input private VirtualObjectNode virtualObject; + @Input private CommitAllocationNode commit; + + public AllocatedObjectNode(VirtualObjectNode virtualObject) { + super(StampFactory.exactNonNull(virtualObject.type())); + this.virtualObject = virtualObject; + } + + public VirtualObjectNode getVirtualObject() { + return virtualObject; + } + + public CommitAllocationNode getCommit() { + return commit; + } + + public void setCommit(CommitAllocationNode x) { + updateUsages(commit, x); + commit = x; + } + + @Override + public void virtualize(VirtualizerTool tool) { + tool.replaceWithVirtual(getVirtualObject()); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/CommitAllocationNode.java Mon Apr 29 14:53:08 2013 +0200 @@ -0,0 +1,162 @@ +/* + * 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.virtual; + +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.*; + +@NodeInfo(nameTemplate = "Alloc {i#virtualObjects}") +public final class CommitAllocationNode extends FixedWithNextNode implements VirtualizableAllocation, Lowerable, Node.IterableNodeType, Simplifiable { + + @Input private final NodeInputList<VirtualObjectNode> virtualObjects = new NodeInputList<>(this); + @Input private final NodeInputList<ValueNode> values = new NodeInputList<>(this); + private final List<Integer> lockCounts = new ArrayList<>(); + + public CommitAllocationNode() { + super(StampFactory.forVoid()); + } + + public List<VirtualObjectNode> getVirtualObjects() { + return virtualObjects; + } + + public List<ValueNode> getValues() { + return values; + } + + public List<Integer> getLockCounts() { + return lockCounts; + } + + @Override + public boolean verify() { + assertTrue(virtualObjects.size() == lockCounts.size(), "lockCounts size doesn't match"); + int valueCount = 0; + for (VirtualObjectNode virtual : virtualObjects) { + valueCount += virtual.entryCount(); + } + assertTrue(values.size() == valueCount, "values size doesn't match"); + return super.verify(); + } + + @Override + public void lower(LoweringTool tool, LoweringType loweringType) { + if (loweringType == LoweringType.AFTER_GUARDS) { + tool.getRuntime().lower(this, tool); + } + } + + @Override + public void virtualize(VirtualizerTool tool) { + int pos = 0; + for (int i = 0; i < virtualObjects.size(); i++) { + VirtualObjectNode virtualObject = virtualObjects.get(i); + int entryCount = virtualObject.entryCount(); + tool.createVirtualObject(virtualObject, values.subList(pos, pos + entryCount).toArray(new ValueNode[entryCount]), lockCounts.get(i)); + pos += entryCount; + } + tool.delete(); + } + + @Override + public Map<Object, Object> getDebugProperties(Map<Object, Object> map) { + Map<Object, Object> properties = super.getDebugProperties(map); + int valuePos = 0; + for (int objIndex = 0; objIndex < virtualObjects.size(); objIndex++) { + VirtualObjectNode virtual = virtualObjects.get(objIndex); + StringBuilder s = new StringBuilder(); + s.append(MetaUtil.toJavaName(virtual.type(), false)).append("["); + for (int i = 0; i < virtual.entryCount(); i++) { + ValueNode value = values.get(valuePos++); + s.append(i == 0 ? "" : ",").append(value == null ? "_" : value.toString(Verbosity.Id)); + } + s.append("]"); + if (lockCounts.get(objIndex) > 0) { + s.append(" locked(").append(lockCounts.get(objIndex)).append(")"); + } + properties.put("object(" + virtual.toString(Verbosity.Id) + ")", s.toString()); + } + return properties; + } + + @Override + public void simplify(SimplifierTool tool) { + boolean[] used = new boolean[virtualObjects.size()]; + int usedCount = 0; + for (Node usage : usages()) { + AllocatedObjectNode addObject = (AllocatedObjectNode) usage; + int index = virtualObjects.indexOf(addObject.getVirtualObject()); + assert !used[index]; + used[index] = true; + usedCount++; + } + boolean progress; + do { + progress = false; + int valuePos = 0; + for (int objIndex = 0; objIndex < virtualObjects.size(); objIndex++) { + VirtualObjectNode virtualObject = virtualObjects.get(objIndex); + if (used[objIndex]) { + for (int i = 0; i < virtualObject.entryCount(); i++) { + int index = virtualObjects.indexOf(values.get(valuePos + i)); + if (index != -1 && !used[index]) { + progress = true; + used[index] = true; + usedCount++; + } + } + } + valuePos += virtualObject.entryCount(); + } + + } while (progress); + + if (usedCount < virtualObjects.size()) { + List<VirtualObjectNode> newVirtualObjects = new ArrayList<>(usedCount); + List<Integer> newLockCounts = new ArrayList<>(usedCount); + List<ValueNode> newValues = new ArrayList<>(); + int valuePos = 0; + for (int objIndex = 0; objIndex < virtualObjects.size(); objIndex++) { + VirtualObjectNode virtualObject = virtualObjects.get(objIndex); + if (used[objIndex]) { + newVirtualObjects.add(virtualObject); + newLockCounts.add(lockCounts.get(objIndex)); + newValues.addAll(values.subList(valuePos, valuePos + virtualObject.entryCount())); + } + valuePos += virtualObject.entryCount(); + } + virtualObjects.clear(); + virtualObjects.addAll(newVirtualObjects); + lockCounts.clear(); + lockCounts.addAll(newLockCounts); + values.clear(); + values.addAll(newValues); + } + } + +}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualArrayNode.java Mon Apr 29 18:38:16 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualArrayNode.java Mon Apr 29 14:53:08 2013 +0200 @@ -22,14 +22,11 @@ */ package com.oracle.graal.nodes.virtual; -import java.util.*; - import sun.misc.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.spi.*; @NodeInfo(nameTemplate = "VirtualArray {p#componentType/s}[{p#length}]") @@ -72,7 +69,7 @@ } @Override - public String fieldName(int index) { + public String entryName(int index) { return "[" + index + "]"; } @@ -143,17 +140,8 @@ } @Override - public void materializeAt(FixedWithNextNode materializeNode, List<ValueNode> values, boolean defaultValuesOnly, int lockCount) { - StructuredGraph graph = (StructuredGraph) graph(); - ResolvedJavaType element = componentType(); - NewArrayNode newArray = graph.add(new NewArrayNode(element, ConstantNode.forInt(entryCount(), graph), defaultValuesOnly, lockCount > 0)); - materializeNode.replaceAtUsages(newArray); - graph.addBeforeFixed(materializeNode, newArray); - if (!defaultValuesOnly) { - for (int i = 0; i < entryCount(); i++) { - graph.addBeforeFixed(materializeNode, graph.add(new StoreIndexedNode(newArray, ConstantNode.forInt(i, graph), element.getKind(), values.get(i)))); - } - } - graph.removeFixed(materializeNode); + public AllocatedObjectNode getMaterializedRepresentation(ValueNode[] entries, int lockCount) { + assert lockCount == 0; + return new AllocatedObjectNode(this); } }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualBoxingNode.java Mon Apr 29 18:38:16 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualBoxingNode.java Mon Apr 29 14:53:08 2013 +0200 @@ -22,8 +22,6 @@ */ package com.oracle.graal.nodes.virtual; -import java.util.*; - import com.oracle.graal.api.meta.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.extended.*; @@ -48,11 +46,9 @@ } @Override - public void materializeAt(FixedWithNextNode materializeNode, List<ValueNode> values, boolean defaultValuesOnly, int lockCount) { - assert values.size() == 1; + public ValueNode getMaterializedRepresentation(ValueNode[] entries, int lockCount) { + assert entries.length == 1; assert lockCount == 0; - StructuredGraph graph = (StructuredGraph) graph(); - BoxNode valueOf = graph.add(new BoxNode(values.get(0), type(), boxingKind)); - graph.replaceFixedWithFixed(materializeNode, valueOf); + return new BoxNode(entries[0], type(), boxingKind); } }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualInstanceNode.java Mon Apr 29 18:38:16 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualInstanceNode.java Mon Apr 29 14:53:08 2013 +0200 @@ -22,14 +22,11 @@ */ package com.oracle.graal.nodes.virtual; -import java.util.*; - import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.java.*; -@NodeInfo(nameTemplate = "VirtualInstance {p#type}") +@NodeInfo(nameTemplate = "VirtualInstance {p#type/s}") public class VirtualInstanceNode extends VirtualObjectNode { private final ResolvedJavaType type; @@ -68,7 +65,7 @@ } @Override - public String fieldName(int index) { + public String entryName(int index) { return fields[index].getName(); } @@ -99,16 +96,7 @@ } @Override - public void materializeAt(FixedWithNextNode materializeNode, List<ValueNode> values, boolean defaultValuesOnly, int lockCount) { - StructuredGraph graph = (StructuredGraph) graph(); - NewInstanceNode newInstance = graph.add(new NewInstanceNode(type(), defaultValuesOnly, lockCount > 0)); - materializeNode.replaceAtUsages(newInstance); - graph.addBeforeFixed(materializeNode, newInstance); - if (!defaultValuesOnly) { - for (int i = 0; i < entryCount(); i++) { - graph.addBeforeFixed(materializeNode, graph.add(new StoreFieldNode(newInstance, field(i), values.get(i)))); - } - } - graph.removeFixed(materializeNode); + public ValueNode getMaterializedRepresentation(ValueNode[] entries, int lockCount) { + return new AllocatedObjectNode(this); } }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectNode.java Mon Apr 29 18:38:16 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectNode.java Mon Apr 29 14:53:08 2013 +0200 @@ -22,41 +22,68 @@ */ package com.oracle.graal.nodes.virtual; -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.*; -@NodeInfo(nameTemplate = "VirtualObject {p#type}") public abstract class VirtualObjectNode extends ValueNode implements LIRLowerable { public VirtualObjectNode() { super(StampFactory.virtual()); } + /** + * The type of object described by this {@link VirtualObjectNode}. In case of arrays, this is + * the array type (and not the component type). + */ public abstract ResolvedJavaType type(); + /** + * The number of entries this virtual object has. Either the number of fields or the number of + * array elements. + */ public abstract int entryCount(); + /** + * Returns the name of the entry at the given index. Only used for debugging purposes. + */ + public abstract String entryName(int i); + + /** + * If the given index denotes an entry in this virtual object, the index of this entry is + * returned. If no such entry can be found, this method returns -1. + */ + public abstract int entryIndexForOffset(long constantOffset); + + /** + * Returns the {@link Kind} of the entry at the given index. + */ + public abstract Kind entryKind(int index); + + /** + * Returns an exact duplicate of this virtual object node, which has not been added to the graph + * yet. + */ + public abstract VirtualObjectNode duplicate(); + + /** + * Specifies whether this virtual object has an object identity. If not, then the result of a + * comparison of two virtual objects is determined by comparing their contents. + */ + public boolean hasIdentity() { + return true; + } + + /** + * Returns a node that can be used to materialize this virtual object. If this returns an + * {@link AllocatedObjectNode} then this node will be attached to a {@link CommitAllocationNode} + * , otherwise the node will just be added to the graph. + */ + public abstract ValueNode getMaterializedRepresentation(ValueNode[] entries, int lockCount); + @Override public void generate(LIRGeneratorTool gen) { // nothing to do... } - - public abstract String fieldName(int i); - - public abstract void materializeAt(FixedWithNextNode materializeNode, List<ValueNode> values, boolean defaultValuesOnly, int lockCount); - - public abstract int entryIndexForOffset(long constantOffset); - - public abstract Kind entryKind(int index); - - public abstract VirtualObjectNode duplicate(); - - public boolean hasIdentity() { - return true; - } }
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/nodes/MaterializeObjectNode.java Mon Apr 29 18:38:16 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,100 +0,0 @@ -/* - * 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.virtual.nodes; - -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 {i#virtualObject}") -public final class MaterializeObjectNode extends FixedWithNextNode implements VirtualizableAllocation, Lowerable, Node.IterableNodeType, Canonicalizable, ArrayLengthProvider { - - @Input private final NodeInputList<ValueNode> values; - @Input private final VirtualObjectNode virtualObject; - private final int lockCount; - - public MaterializeObjectNode(VirtualObjectNode virtualObject, int lockCount) { - super(StampFactory.exactNonNull(virtualObject.type())); - this.virtualObject = virtualObject; - this.lockCount = lockCount; - this.values = new NodeInputList<>(this, virtualObject.entryCount()); - } - - public NodeInputList<ValueNode> getValues() { - return values; - } - - public VirtualObjectNode getVirtualObject() { - return virtualObject; - } - - public int getLockCount() { - return lockCount; - } - - @Override - public ValueNode length() { - assert virtualObject.type().isArray(); - return ConstantNode.forInt(values.size(), graph()); - } - - /** - * @return true if the object that will be created is without locks and has only entries that - * are {@link Constant#defaultForKind(Kind)}, false otherwise. - */ - public boolean isDefault() { - if (lockCount > 0) { - return false; - } else { - for (ValueNode value : values) { - if (!value.isConstant() || !value.asConstant().isDefaultForKind()) { - return false; - } - } - } - return true; - } - - @Override - public void lower(LoweringTool tool, LoweringType loweringType) { - virtualObject.materializeAt(this, values, isDefault(), lockCount); - } - - @Override - public ValueNode canonical(CanonicalizerTool tool) { - if (usages().isEmpty()) { - return null; - } else { - return this; - } - } - - @Override - public void virtualize(VirtualizerTool tool) { - tool.createVirtualObject(virtualObject, values.toArray(new ValueNode[values.size()]), lockCount); - tool.replaceWithVirtual(virtualObject); - } -}
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/BlockState.java Mon Apr 29 18:38:16 2013 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/BlockState.java Mon Apr 29 14:53:08 2013 +0200 @@ -27,13 +27,11 @@ import java.util.*; import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.Virtualizable.EscapeState; import com.oracle.graal.nodes.virtual.*; -import com.oracle.graal.virtual.nodes.*; class BlockState { @@ -151,62 +149,53 @@ public void materializeBefore(FixedNode fixed, VirtualObjectNode virtual, EscapeState state, GraphEffectList materializeEffects) { PartialEscapeClosure.METRIC_MATERIALIZATIONS.increment(); - HashSet<VirtualObjectNode> deferred = new HashSet<>(); - GraphEffectList deferredStores = new GraphEffectList(); - materializeChangedBefore(fixed, virtual, state, deferred, deferredStores, materializeEffects); - materializeEffects.addAll(deferredStores); + List<AllocatedObjectNode> objects = new ArrayList<>(2); + List<ValueNode> values = new ArrayList<>(8); + List<Integer> lockCounts = new ArrayList<>(2); + List<ValueNode> otherAllocations = new ArrayList<>(2); + materializeWithCommit(virtual, objects, lockCounts, values, otherAllocations, state); + + materializeEffects.addMaterializationBefore(fixed, objects, lockCounts, values, otherAllocations); } - private void materializeChangedBefore(FixedNode fixed, VirtualObjectNode virtual, EscapeState state, HashSet<VirtualObjectNode> deferred, GraphEffectList deferredStores, - GraphEffectList materializeEffects) { - trace("materializing %s at %s", virtual, fixed); + private void materializeWithCommit(VirtualObjectNode virtual, List<AllocatedObjectNode> objects, List<Integer> lockCounts, List<ValueNode> values, List<ValueNode> otherAllocations, EscapeState state) { + trace("materializing %s", virtual); ObjectState obj = getObjectState(virtual); if (obj.getLockCount() > 0 && obj.virtual.type().isArray()) { throw new BailoutException("array materialized with lock"); } - ValueNode[] fieldState = obj.getEntries(); - - MaterializeObjectNode materialize = new MaterializeObjectNode(virtual, obj.getLockCount()); - ValueNode[] values = new ValueNode[obj.getEntries().length]; - obj.escape(materialize, state); - deferred.add(virtual); - for (int i = 0; i < fieldState.length; i++) { - ObjectState valueObj = getObjectState(fieldState[i]); - if (valueObj != null) { - if (valueObj.isVirtual()) { - materializeChangedBefore(fixed, valueObj.virtual, state, deferred, deferredStores, materializeEffects); + ValueNode[] entries = obj.getEntries(); + ValueNode representation = virtual.getMaterializedRepresentation(entries, obj.getLockCount()); + obj.escape(representation, state); + if (representation instanceof AllocatedObjectNode) { + objects.add((AllocatedObjectNode) representation); + lockCounts.add(obj.getLockCount()); + int pos = values.size(); + while (values.size() < pos + entries.length) { + values.add(null); + } + for (int i = 0; i < entries.length; i++) { + ObjectState entryObj = getObjectState(entries[i]); + if (entryObj != null) { + if (entryObj.isVirtual()) { + materializeWithCommit(entryObj.getVirtualObject(), objects, lockCounts, values, otherAllocations, state); + } + values.set(pos + i, entryObj.getMaterializedValue()); + } else { + values.set(pos + i, entries[i]); } - if (deferred.contains(valueObj.virtual)) { - Kind fieldKind; - CyclicMaterializeStoreNode store; - if (virtual instanceof VirtualArrayNode) { - store = new CyclicMaterializeStoreNode(materialize, valueObj.getMaterializedValue(), i); - fieldKind = ((VirtualArrayNode) virtual).componentType().getKind(); - } else { - VirtualInstanceNode instanceObject = (VirtualInstanceNode) virtual; - store = new CyclicMaterializeStoreNode(materialize, valueObj.getMaterializedValue(), instanceObject.field(i)); - fieldKind = instanceObject.field(i).getType().getKind(); - } - deferredStores.addFixedNodeBefore(store, fixed); - values[i] = ConstantNode.defaultForKind(fieldKind, fixed.graph()); - } else { - values[i] = valueObj.getMaterializedValue(); + } + if (virtual instanceof VirtualInstanceNode) { + VirtualInstanceNode instance = (VirtualInstanceNode) virtual; + for (int i = 0; i < entries.length; i++) { + readCache.put(new ReadCacheEntry(instance.field(i), representation), values.get(pos + i)); } - } else { - values[i] = fieldState[i]; } + } else { + otherAllocations.add(representation); + assert obj.getLockCount() == 0; } - deferred.remove(virtual); - - if (virtual instanceof VirtualInstanceNode) { - VirtualInstanceNode instance = (VirtualInstanceNode) virtual; - for (int i = 0; i < fieldState.length; i++) { - readCache.put(new ReadCacheEntry(instance.field(i), materialize), fieldState[i]); - } - } - - materializeEffects.addMaterialization(materialize, fixed, values); } void addAndMarkAlias(VirtualObjectNode virtual, ValueNode node, NodeBitMap usages) {
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/GraphEffectList.java Mon Apr 29 18:38:16 2013 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/GraphEffectList.java Mon Apr 29 14:53:08 2013 +0200 @@ -26,10 +26,10 @@ import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.debug.*; import com.oracle.graal.nodes.virtual.*; import com.oracle.graal.phases.common.*; -import com.oracle.graal.virtual.nodes.*; public class GraphEffectList extends EffectList { @@ -118,33 +118,6 @@ } /** - * Add the materialization node to the graph's control flow at the given position, and then sets - * its values. - * - * @param node The materialization node that should be added. - * @param position The fixed node before which the materialization node should be added. - * @param values The values for the materialization node's entries. - */ - public void addMaterialization(final MaterializeObjectNode node, final FixedNode position, final ValueNode[] values) { - add(new Effect() { - - @Override - public String name() { - return "addMaterialization"; - } - - @Override - public void apply(StructuredGraph graph, ArrayList<Node> obsoleteNodes) { - assert !node.isAlive() && !node.isDeleted() && position.isAlive(); - graph.addBeforeFixed(position, graph.add(node)); - for (int i = 0; i < values.length; i++) { - node.getValues().set(i, values[i]); - } - } - }); - } - - /** * Adds an value to the given phi node. * * @param node The phi node to which the value should be added. @@ -330,4 +303,68 @@ } }); } + + /** + * Add the materialization node to the graph's control flow at the given position, and then sets + * its values. + * + * @param position The fixed node before which the materialization node should be added. + * @param objects The allocated objects. + * @param lockCounts The lock count for each object. + * @param values The values (field, elements) of all objects. + * @param otherAllocations A list of allocations that need to be added before the rest (used for + * boxing allocations). + */ + public void addMaterializationBefore(final FixedNode position, final List<AllocatedObjectNode> objects, final List<Integer> lockCounts, final List<ValueNode> values, + final List<ValueNode> otherAllocations) { + add(new Effect() { + + @Override + public String name() { + return "addMaterializationBefore"; + } + + @Override + public void apply(StructuredGraph graph, ArrayList<Node> obsoleteNodes) { + for (ValueNode otherAllocation : otherAllocations) { + graph.add(otherAllocation); + if (otherAllocation instanceof FixedWithNextNode) { + graph.addBeforeFixed(position, (FixedWithNextNode) otherAllocation); + } else { + assert otherAllocation instanceof FloatingNode; + } + } + if (!objects.isEmpty()) { + CommitAllocationNode commit; + if (position.predecessor() instanceof CommitAllocationNode) { + commit = (CommitAllocationNode) position.predecessor(); + } else { + commit = graph.add(new CommitAllocationNode()); + graph.addBeforeFixed(position, commit); + } + for (AllocatedObjectNode obj : objects) { + graph.add(obj); + commit.getVirtualObjects().add(obj.getVirtualObject()); + obj.setCommit(commit); + } + commit.getValues().addAll(values); + commit.getLockCounts().addAll(lockCounts); + + assert commit.usages().filter(AllocatedObjectNode.class).count() == commit.usages().count(); + HashSet<AllocatedObjectNode> materializedValues = new HashSet<>(commit.usages().filter(AllocatedObjectNode.class).snapshot()); + for (int i = 0; i < commit.getValues().size(); i++) { + if (materializedValues.contains(commit.getValues().get(i))) { + commit.getValues().set(i, ((AllocatedObjectNode) commit.getValues().get(i)).getVirtualObject()); + } + } + + } + } + + @Override + public boolean isVisible() { + return true; + } + }); + } }
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ObjectState.java Mon Apr 29 18:38:16 2013 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ObjectState.java Mon Apr 29 14:53:08 2013 +0200 @@ -36,7 +36,7 @@ */ class ObjectState extends Virtualizable.State { - public final VirtualObjectNode virtual; + final VirtualObjectNode virtual; private EscapeState state; private ValueNode[] entries; @@ -137,7 +137,7 @@ } if (entries != null) { for (int i = 0; i < entries.length; i++) { - str.append(virtual.fieldName(i)).append('=').append(entries[i]).append(' '); + str.append(virtual.entryName(i)).append('=').append(entries[i]).append(' '); } } if (materializedValue != null) {
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeAnalysisPhase.java Mon Apr 29 18:38:16 2013 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeAnalysisPhase.java Mon Apr 29 14:53:08 2013 +0200 @@ -32,13 +32,13 @@ import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.util.*; +import com.oracle.graal.nodes.virtual.*; import com.oracle.graal.phases.*; import com.oracle.graal.phases.common.*; import com.oracle.graal.phases.common.CanonicalizerPhase.CustomCanonicalizer; import com.oracle.graal.phases.graph.*; import com.oracle.graal.phases.schedule.*; import com.oracle.graal.phases.tiers.*; -import com.oracle.graal.virtual.nodes.*; public class PartialEscapeAnalysisPhase extends BasePhase<HighTierContext> { @@ -203,32 +203,36 @@ public static Map<Invoke, Double> getHints(StructuredGraph graph) { NodesToDoubles probabilities = new ComputeProbabilityClosure(graph).apply(); Map<Invoke, Double> hints = null; - for (MaterializeObjectNode materialize : graph.getNodes(MaterializeObjectNode.class)) { + for (CommitAllocationNode commit : graph.getNodes(CommitAllocationNode.class)) { double sum = 0; double invokeSum = 0; - for (Node usage : materialize.usages()) { - if (usage instanceof FixedNode) { - sum += probabilities.get((FixedNode) usage); - } else { - if (usage instanceof MethodCallTargetNode) { - invokeSum += probabilities.get(((MethodCallTargetNode) usage).invoke().asNode()); - } - for (Node secondLevelUage : materialize.usages()) { - if (secondLevelUage instanceof FixedNode) { - sum += probabilities.get(((FixedNode) secondLevelUage)); + for (Node commitUsage : commit.usages()) { + for (Node usage : commitUsage.usages()) { + if (usage instanceof FixedNode) { + sum += probabilities.get((FixedNode) usage); + } else { + if (usage instanceof MethodCallTargetNode) { + invokeSum += probabilities.get(((MethodCallTargetNode) usage).invoke().asNode()); + } + for (Node secondLevelUage : usage.usages()) { + if (secondLevelUage instanceof FixedNode) { + sum += probabilities.get(((FixedNode) secondLevelUage)); + } } } } } // TODO(lstadler) get rid of this magic number if (sum > 100 && invokeSum > 0) { - for (Node usage : materialize.usages()) { - if (usage instanceof MethodCallTargetNode) { - if (hints == null) { - hints = new HashMap<>(); + for (Node commitUsage : commit.usages()) { + for (Node usage : commitUsage.usages()) { + if (usage instanceof MethodCallTargetNode) { + if (hints == null) { + hints = new HashMap<>(); + } + Invoke invoke = ((MethodCallTargetNode) usage).invoke(); + hints.put(invoke, sum / invokeSum); } - Invoke invoke = ((MethodCallTargetNode) usage).invoke(); - hints.put(invoke, sum / invokeSum); } } }