# HG changeset patch # User Lukas Stadler # Date 1437747656 -7200 # Node ID 681c04ce9db2f0fb4521829d2bbeb6c9b5e5a09f # Parent 17b96d2fe8d67be150c683223b9bff99802fd12b PEA refactoring: simplify VirtualizerTool, arrays instead of HashMaps, route all modifications through BlockState, copy-on-write in BlockState diff -r 17b96d2fe8d6 -r 681c04ce9db2 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/ArrayCopySnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/ArrayCopySnippets.java Fri Jul 24 13:26:44 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/ArrayCopySnippets.java Fri Jul 24 16:20:56 2015 +0200 @@ -464,7 +464,7 @@ /* * At least one array is of a known type requiring no store checks, so * assume the other is of the same type. Generally this is working around - * deficiencies in our propation of type information. + * deficiencies in our propagation of type information. */ componentKind = predictedKind; if (predictedKind == Kind.Object) { diff -r 17b96d2fe8d6 -r 681c04ce9db2 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardedValueNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardedValueNode.java Fri Jul 24 13:26:44 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardedValueNode.java Fri Jul 24 16:20:56 2015 +0200 @@ -30,6 +30,7 @@ import com.oracle.graal.nodeinfo.*; import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.virtual.*; /** * A node that changes the type of its input, usually narrowing it. For example, a GuardedValueNode @@ -72,9 +73,9 @@ @Override public void virtualize(VirtualizerTool tool) { - State state = tool.getObjectState(object); - if (state != null && state.getState() == EscapeState.Virtual) { - tool.replaceWithVirtual(state.getVirtualObject()); + ValueNode alias = tool.getAlias(object()); + if (alias instanceof VirtualObjectNode) { + tool.replaceWithVirtual((VirtualObjectNode) alias); } } diff -r 17b96d2fe8d6 -r 681c04ce9db2 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PiNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PiNode.java Fri Jul 24 13:26:44 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PiNode.java Fri Jul 24 16:20:56 2015 +0200 @@ -33,6 +33,7 @@ import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; +import com.oracle.graal.nodes.virtual.*; /** * A node that changes the type of its input, usually narrowing it. For example, a {@link PiNode} @@ -90,9 +91,12 @@ @Override public void virtualize(VirtualizerTool tool) { - State state = tool.getObjectState(object); - if (state != null && state.getState() == EscapeState.Virtual && StampTool.typeOrNull(this) != null && StampTool.typeOrNull(this).isAssignableFrom(state.getVirtualObject().type())) { - tool.replaceWithVirtual(state.getVirtualObject()); + ValueNode alias = tool.getAlias(object()); + if (alias instanceof VirtualObjectNode) { + VirtualObjectNode virtual = (VirtualObjectNode) alias; + if (StampTool.typeOrNull(this) != null && StampTool.typeOrNull(this).isAssignableFrom(virtual.type())) { + tool.replaceWithVirtual(virtual); + } } } diff -r 17b96d2fe8d6 -r 681c04ce9db2 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueProxyNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueProxyNode.java Fri Jul 24 13:26:44 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueProxyNode.java Fri Jul 24 16:20:56 2015 +0200 @@ -26,6 +26,7 @@ import com.oracle.graal.graph.spi.*; import com.oracle.graal.nodeinfo.*; import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.virtual.*; @NodeInfo(nameTemplate = "Proxy({i#value})") public final class ValueProxyNode extends ProxyNode implements Canonicalizable, Virtualizable, ValueProxy { @@ -58,9 +59,9 @@ @Override public void virtualize(VirtualizerTool tool) { - State state = tool.getObjectState(value); - if (state != null && state.getState() == EscapeState.Virtual) { - tool.replaceWithVirtual(state.getVirtualObject()); + ValueNode alias = tool.getAlias(value); + if (alias instanceof VirtualObjectNode) { + tool.replaceWithVirtual((VirtualObjectNode) alias); } } diff -r 17b96d2fe8d6 -r 681c04ce9db2 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IsNullNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IsNullNode.java Fri Jul 24 13:26:44 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IsNullNode.java Fri Jul 24 16:20:56 2015 +0200 @@ -68,8 +68,10 @@ @Override public void virtualize(VirtualizerTool tool) { - if (tool.getObjectState(getValue()) != null) { - tool.replaceWithValue(LogicConstantNode.contradiction(graph())); + ValueNode alias = tool.getAlias(getValue()); + TriState fold = tryFold(alias.stamp()); + if (fold != TriState.UNKNOWN) { + tool.replaceWithValue(LogicConstantNode.forBoolean(fold.isTrue(), graph())); } } diff -r 17b96d2fe8d6 -r 681c04ce9db2 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ObjectEqualsNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ObjectEqualsNode.java Fri Jul 24 13:26:44 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ObjectEqualsNode.java Fri Jul 24 16:20:56 2015 +0200 @@ -34,6 +34,7 @@ import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.virtual.*; @NodeInfo(shortName = "==") public final class ObjectEqualsNode extends PointerEqualsNode implements Virtualizable { @@ -71,13 +72,13 @@ return super.canonicalizeSymmetricConstant(tool, constant, nonConstant, mirrored); } - private void virtualizeNonVirtualComparison(State state, ValueNode other, VirtualizerTool tool) { - if (!state.getVirtualObject().hasIdentity() && state.getVirtualObject().entryKind(0) == Kind.Boolean) { + private void virtualizeNonVirtualComparison(VirtualObjectNode virtual, ValueNode other, VirtualizerTool tool) { + if (!virtual.hasIdentity() && virtual.entryKind(0) == Kind.Boolean) { if (other.isConstant()) { JavaConstant otherUnboxed = tool.getConstantReflectionProvider().unboxPrimitive(other.asJavaConstant()); if (otherUnboxed != null && otherUnboxed.getKind() == Kind.Boolean) { int expectedValue = otherUnboxed.asBoolean() ? 1 : 0; - IntegerEqualsNode equals = new IntegerEqualsNode(state.getEntry(0), ConstantNode.forInt(expectedValue, graph())); + IntegerEqualsNode equals = new IntegerEqualsNode(tool.getEntry(virtual, 0), ConstantNode.forInt(expectedValue, graph())); tool.addNode(equals); tool.replaceWithValue(equals); } else { @@ -92,43 +93,42 @@ @Override public void virtualize(VirtualizerTool tool) { - State stateX = tool.getObjectState(getX()); - State stateY = tool.getObjectState(getY()); - boolean xVirtual = stateX != null && stateX.getState() == EscapeState.Virtual; - boolean yVirtual = stateY != null && stateY.getState() == EscapeState.Virtual; + ValueNode xAlias = tool.getAlias(getX()); + ValueNode yAlias = tool.getAlias(getY()); + + VirtualObjectNode xVirtual = xAlias instanceof VirtualObjectNode ? (VirtualObjectNode) xAlias : null; + VirtualObjectNode yVirtual = yAlias instanceof VirtualObjectNode ? (VirtualObjectNode) yAlias : null; - if (xVirtual && !yVirtual) { - virtualizeNonVirtualComparison(stateX, stateY != null ? stateY.getMaterializedValue() : getY(), tool); - } else if (!xVirtual && yVirtual) { - virtualizeNonVirtualComparison(stateY, stateX != null ? stateX.getMaterializedValue() : getX(), tool); - } else if (xVirtual && yVirtual) { - boolean xIdentity = stateX.getVirtualObject().hasIdentity(); - boolean yIdentity = stateY.getVirtualObject().hasIdentity(); - if (xIdentity ^ yIdentity) { + if (xVirtual != null && yVirtual == null) { + virtualizeNonVirtualComparison(xVirtual, yAlias, tool); + } else if (xVirtual == null && yVirtual != null) { + virtualizeNonVirtualComparison(yVirtual, xAlias, tool); + } else if (xVirtual != null && yVirtual != null) { + if (xVirtual.hasIdentity() ^ yVirtual.hasIdentity()) { /* * One of the two objects has identity, the other doesn't. In code, this looks like * "Integer.valueOf(a) == new Integer(b)", which is always false. - * + * * In other words: an object created via valueOf can never be equal to one created * by new in the same compilation unit. */ tool.replaceWithValue(LogicConstantNode.contradiction(graph())); - } else if (!xIdentity && !yIdentity) { - ResolvedJavaType type = stateX.getVirtualObject().type(); - if (type.equals(stateY.getVirtualObject().type())) { + } else if (!xVirtual.hasIdentity() && !yVirtual.hasIdentity()) { + ResolvedJavaType type = xVirtual.type(); + if (type.equals(yVirtual.type())) { MetaAccessProvider metaAccess = tool.getMetaAccessProvider(); if (type.equals(metaAccess.lookupJavaType(Integer.class)) || type.equals(metaAccess.lookupJavaType(Long.class))) { // both are virtual without identity: check contents - assert stateX.getVirtualObject().entryCount() == 1 && stateY.getVirtualObject().entryCount() == 1; - assert stateX.getVirtualObject().entryKind(0).getStackKind() == Kind.Int || stateX.getVirtualObject().entryKind(0) == Kind.Long; - IntegerEqualsNode equals = new IntegerEqualsNode(stateX.getEntry(0), stateY.getEntry(0)); + assert xVirtual.entryCount() == 1 && yVirtual.entryCount() == 1; + assert xVirtual.entryKind(0).getStackKind() == Kind.Int || xVirtual.entryKind(0) == Kind.Long; + IntegerEqualsNode equals = new IntegerEqualsNode(tool.getEntry(xVirtual, 0), tool.getEntry(yVirtual, 0)); tool.addNode(equals); tool.replaceWithValue(equals); } } } else { // both are virtual with identity: check if they refer to the same object - tool.replaceWithValue(LogicConstantNode.forBoolean(stateX == stateY, graph())); + tool.replaceWithValue(LogicConstantNode.forBoolean(xVirtual == yVirtual, graph())); } } } diff -r 17b96d2fe8d6 -r 681c04ce9db2 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/WeakCounterNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/WeakCounterNode.java Fri Jul 24 13:26:44 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/WeakCounterNode.java Fri Jul 24 16:20:56 2015 +0200 @@ -28,6 +28,7 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.virtual.*; /** * This is a special version of the dynamic counter node that removes itself as soon as it's the @@ -55,8 +56,8 @@ @Override public void virtualize(VirtualizerTool tool) { - State state = tool.getObjectState(checkedValue); - if (state != null && state.getState() == EscapeState.Virtual) { + ValueNode alias = tool.getAlias(checkedValue); + if (alias instanceof VirtualObjectNode) { tool.delete(); } } diff -r 17b96d2fe8d6 -r 681c04ce9db2 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BoxNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BoxNode.java Fri Jul 24 13:26:44 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BoxNode.java Fri Jul 24 16:20:56 2015 +0200 @@ -76,13 +76,13 @@ @Override public void virtualize(VirtualizerTool tool) { - ValueNode v = tool.getReplacedValue(getValue()); + ValueNode alias = tool.getAlias(getValue()); ResolvedJavaType type = StampTool.typeOrNull(stamp()); VirtualBoxingNode newVirtual = new VirtualBoxingNode(type, boxingKind); assert newVirtual.getFields().length == 1; - tool.createVirtualObject(newVirtual, new ValueNode[]{v}, Collections. emptyList(), false); + tool.createVirtualObject(newVirtual, new ValueNode[]{alias}, Collections. emptyList(), false); tool.replaceWithVirtual(newVirtual); } } diff -r 17b96d2fe8d6 -r 681c04ce9db2 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/GetClassNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/GetClassNode.java Fri Jul 24 13:26:44 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/GetClassNode.java Fri Jul 24 16:20:56 2015 +0200 @@ -32,6 +32,7 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.virtual.*; /** * Loads an object's class (i.e., this node can be created for {@code object.getClass()}). @@ -87,9 +88,10 @@ @Override public void virtualize(VirtualizerTool tool) { - State state = tool.getObjectState(object); - if (state != null) { - Constant javaClass = state.getVirtualObject().type().getJavaClass(); + ValueNode alias = tool.getAlias(getObject()); + if (alias instanceof VirtualObjectNode) { + VirtualObjectNode virtual = (VirtualObjectNode) alias; + Constant javaClass = virtual.type().getJavaClass(); tool.replaceWithValue(ConstantNode.forConstant(stamp(), javaClass, tool.getMetaAccessProvider(), graph())); } } diff -r 17b96d2fe8d6 -r 681c04ce9db2 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadHubNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadHubNode.java Fri Jul 24 13:26:44 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadHubNode.java Fri Jul 24 16:20:56 2015 +0200 @@ -22,8 +22,8 @@ */ package com.oracle.graal.nodes.extended; +import jdk.internal.jvmci.meta.Assumptions.AssumptionResult; import jdk.internal.jvmci.meta.*; -import jdk.internal.jvmci.meta.Assumptions.*; import com.oracle.graal.compiler.common.type.*; import com.oracle.graal.graph.*; @@ -116,10 +116,10 @@ @Override public void virtualize(VirtualizerTool tool) { - State state = tool.getObjectState(value); - if (state != null) { - Constant constantHub = state.getVirtualObject().type().getObjectHub(); - tool.replaceWithValue(ConstantNode.forConstant(stamp(), constantHub, tool.getMetaAccessProvider(), graph())); + ValueNode alias = tool.getAlias(getValue()); + ResolvedJavaType type = findSynonymType(graph(), tool.getMetaAccessProvider(), alias); + if (type != null) { + tool.replaceWithValue(ConstantNode.forConstant(stamp(), type.getObjectHub(), tool.getMetaAccessProvider(), graph())); } } } diff -r 17b96d2fe8d6 -r 681c04ce9db2 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnboxNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnboxNode.java Fri Jul 24 13:26:44 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnboxNode.java Fri Jul 24 16:20:56 2015 +0200 @@ -31,6 +31,7 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; +import com.oracle.graal.nodes.virtual.*; @NodeInfo public final class UnboxNode extends FixedWithNextNode implements Virtualizable, Lowerable, Canonicalizable.Unary { @@ -68,12 +69,13 @@ @Override public void virtualize(VirtualizerTool tool) { - State state = tool.getObjectState(getValue()); - if (state != null && state.getState() == EscapeState.Virtual) { - ResolvedJavaType objectType = state.getVirtualObject().type(); + ValueNode alias = tool.getAlias(getValue()); + if (alias instanceof VirtualObjectNode) { + VirtualObjectNode virtual = (VirtualObjectNode) alias; + ResolvedJavaType objectType = virtual.type(); ResolvedJavaType expectedType = tool.getMetaAccessProvider().lookupJavaType(boxingKind.toBoxedJavaClass()); if (objectType.equals(expectedType)) { - tool.replaceWithValue(state.getEntry(0)); + tool.replaceWithValue(tool.getEntry(virtual, 0)); } } } diff -r 17b96d2fe8d6 -r 681c04ce9db2 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeCastNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeCastNode.java Fri Jul 24 13:26:44 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeCastNode.java Fri Jul 24 16:20:56 2015 +0200 @@ -31,6 +31,7 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; +import com.oracle.graal.nodes.virtual.*; /** * The {@code UnsafeCastNode} produces the same value as its input, but with a different type. It @@ -92,9 +93,12 @@ @Override public void virtualize(VirtualizerTool tool) { - State state = tool.getObjectState(object); - if (state != null && state.getState() == EscapeState.Virtual && StampTool.typeOrNull(this) != null && StampTool.typeOrNull(this).isAssignableFrom(state.getVirtualObject().type())) { - tool.replaceWithVirtual(state.getVirtualObject()); + ValueNode alias = tool.getAlias(object); + if (alias instanceof VirtualObjectNode) { + VirtualObjectNode virtual = (VirtualObjectNode) alias; + if (StampTool.typeOrNull(this) != null && StampTool.typeOrNull(this).isAssignableFrom(virtual.type())) { + tool.replaceWithVirtual(virtual); + } } } diff -r 17b96d2fe8d6 -r 681c04ce9db2 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeLoadNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeLoadNode.java Fri Jul 24 13:26:44 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeLoadNode.java Fri Jul 24 16:20:56 2015 +0200 @@ -30,6 +30,7 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.virtual.*; /** * Load of a value from a location specified as an offset relative to an object. No null check is @@ -60,16 +61,17 @@ @Override public void virtualize(VirtualizerTool tool) { - State state = tool.getObjectState(object()); - if (state != null && state.getState() == EscapeState.Virtual) { - ValueNode offsetValue = tool.getReplacedValue(offset()); + ValueNode alias = tool.getAlias(object()); + if (alias instanceof VirtualObjectNode) { + VirtualObjectNode virtual = (VirtualObjectNode) alias; + ValueNode offsetValue = tool.getAlias(offset()); if (offsetValue.isConstant()) { long off = offsetValue.asJavaConstant().asLong(); - int entryIndex = state.getVirtualObject().entryIndexForOffset(off, accessKind()); + int entryIndex = virtual.entryIndexForOffset(off, accessKind()); if (entryIndex != -1) { - ValueNode entry = state.getEntry(entryIndex); - Kind entryKind = state.getVirtualObject().entryKind(entryIndex); + ValueNode entry = tool.getEntry(virtual, entryIndex); + Kind entryKind = virtual.entryKind(entryIndex); if (entry.getKind() == getKind() || entryKind == accessKind()) { tool.replaceWith(entry); } diff -r 17b96d2fe8d6 -r 681c04ce9db2 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeStoreNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeStoreNode.java Fri Jul 24 13:26:44 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeStoreNode.java Fri Jul 24 16:20:56 2015 +0200 @@ -31,6 +31,7 @@ import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.memory.*; import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.virtual.*; /** * Store of a value at a location specified as an offset relative to an object. No null check is @@ -79,26 +80,27 @@ @Override public void virtualize(VirtualizerTool tool) { - State state = tool.getObjectState(object()); - if (state != null && state.getState() == EscapeState.Virtual) { - ValueNode indexValue = tool.getReplacedValue(offset()); + ValueNode alias = tool.getAlias(object()); + if (alias instanceof VirtualObjectNode) { + VirtualObjectNode virtual = (VirtualObjectNode) alias; + ValueNode indexValue = tool.getAlias(offset()); if (indexValue.isConstant()) { long off = indexValue.asJavaConstant().asLong(); - int entryIndex = state.getVirtualObject().entryIndexForOffset(off, accessKind()); + int entryIndex = virtual.entryIndexForOffset(off, accessKind()); if (entryIndex != -1) { - Kind entryKind = state.getVirtualObject().entryKind(entryIndex); - ValueNode entry = state.getEntry(entryIndex); + Kind entryKind = virtual.entryKind(entryIndex); + ValueNode entry = tool.getEntry(virtual, entryIndex); if (entry.getKind() == value.getKind() || entryKind == accessKind()) { - tool.setVirtualEntry(state, entryIndex, value(), true); + tool.setVirtualEntry(virtual, entryIndex, value(), true); tool.delete(); } else { if ((accessKind() == Kind.Long || accessKind() == Kind.Double) && entryKind == Kind.Int) { - int nextIndex = state.getVirtualObject().entryIndexForOffset(off + 4, entryKind); + int nextIndex = virtual.entryIndexForOffset(off + 4, entryKind); if (nextIndex != -1) { - Kind nextKind = state.getVirtualObject().entryKind(nextIndex); + Kind nextKind = virtual.entryKind(nextIndex); if (nextKind == Kind.Int) { - tool.setVirtualEntry(state, entryIndex, value(), true); - tool.setVirtualEntry(state, nextIndex, ConstantNode.forConstant(JavaConstant.forIllegal(), tool.getMetaAccessProvider(), graph()), true); + tool.setVirtualEntry(virtual, entryIndex, value(), true); + tool.setVirtualEntry(virtual, nextIndex, ConstantNode.forConstant(JavaConstant.forIllegal(), tool.getMetaAccessProvider(), graph()), true); tool.delete(); } } diff -r 17b96d2fe8d6 -r 681c04ce9db2 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ValueAnchorNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ValueAnchorNode.java Fri Jul 24 13:26:44 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ValueAnchorNode.java Fri Jul 24 16:20:56 2015 +0200 @@ -31,6 +31,7 @@ import com.oracle.graal.nodes.memory.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.util.*; +import com.oracle.graal.nodes.virtual.*; /** * The ValueAnchor instruction keeps non-CFG (floating) nodes above a certain point in the graph. @@ -94,13 +95,14 @@ @Override public void virtualize(VirtualizerTool tool) { - if (anchored != null && !(anchored instanceof AbstractBeginNode)) { - State state = tool.getObjectState(anchored); - if (state == null || state.getState() != EscapeState.Virtual) { - return; + if (anchored == null || anchored instanceof AbstractBeginNode) { + tool.delete(); + } else { + ValueNode alias = tool.getAlias(anchored); + if (alias instanceof VirtualObjectNode) { + tool.delete(); } } - tool.delete(); } public void removeAnchoredNode() { diff -r 17b96d2fe8d6 -r 681c04ce9db2 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ArrayLengthNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ArrayLengthNode.java Fri Jul 24 13:26:44 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ArrayLengthNode.java Fri Jul 24 16:20:56 2015 +0200 @@ -136,10 +136,14 @@ @Override public void virtualize(VirtualizerTool tool) { - State state = tool.getObjectState(array()); - if (state != null) { - assert state.getVirtualObject().type().isArray(); - tool.replaceWithValue(ConstantNode.forInt(state.getVirtualObject().entryCount(), graph())); + ValueNode alias = tool.getAlias(array()); + ValueNode length = GraphUtil.arrayLength(alias); + if (length != null) { + ValueNode lengthAlias = tool.getAlias(length); + if (!lengthAlias.isAlive()) { + lengthAlias = graph().addOrUnique(lengthAlias); + } + tool.replaceWithValue(lengthAlias); } } } diff -r 17b96d2fe8d6 -r 681c04ce9db2 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java Fri Jul 24 13:26:44 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java Fri Jul 24 16:20:56 2015 +0200 @@ -240,11 +240,9 @@ @Override public void virtualize(VirtualizerTool tool) { - State state = tool.getObjectState(object); - if (state != null && state.getState() == EscapeState.Virtual) { - if (type.isAssignableFrom(state.getVirtualObject().type())) { - tool.replaceWithVirtual(state.getVirtualObject()); - } + ValueNode alias = tool.getAlias(object); + if (tryFold(alias.stamp()) == TriState.TRUE) { + tool.replaceWith(alias); } } diff -r 17b96d2fe8d6 -r 681c04ce9db2 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java Fri Jul 24 13:26:44 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java Fri Jul 24 16:20:56 2015 +0200 @@ -164,9 +164,10 @@ @Override public void virtualize(VirtualizerTool tool) { - State state = tool.getObjectState(getValue()); - if (state != null) { - tool.replaceWithValue(LogicConstantNode.forBoolean(type().isAssignableFrom(state.getVirtualObject().type()), graph())); + ValueNode alias = tool.getAlias(getValue()); + TriState fold = tryFold(alias.stamp()); + if (fold != TriState.UNKNOWN) { + tool.replaceWithValue(LogicConstantNode.forBoolean(fold.isTrue(), graph())); } } diff -r 17b96d2fe8d6 -r 681c04ce9db2 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadFieldNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadFieldNode.java Fri Jul 24 13:26:44 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadFieldNode.java Fri Jul 24 16:20:56 2015 +0200 @@ -121,11 +121,11 @@ @Override public void virtualize(VirtualizerTool tool) { - State state = tool.getObjectState(object()); - if (state != null && state.getState() == EscapeState.Virtual) { - int fieldIndex = ((VirtualInstanceNode) state.getVirtualObject()).fieldIndex(field()); + ValueNode alias = tool.getAlias(object()); + if (alias instanceof VirtualObjectNode) { + int fieldIndex = ((VirtualInstanceNode) alias).fieldIndex(field()); if (fieldIndex != -1) { - tool.replaceWith(state.getEntry(fieldIndex)); + tool.replaceWith(tool.getEntry((VirtualObjectNode) alias, fieldIndex)); } } } diff -r 17b96d2fe8d6 -r 681c04ce9db2 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadIndexedNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadIndexedNode.java Fri Jul 24 13:26:44 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadIndexedNode.java Fri Jul 24 16:20:56 2015 +0200 @@ -31,6 +31,7 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; +import com.oracle.graal.nodes.virtual.*; /** * The {@code LoadIndexedNode} represents a read from an element of an array. @@ -79,12 +80,13 @@ @Override public void virtualize(VirtualizerTool tool) { - State arrayState = tool.getObjectState(array()); - if (arrayState != null && arrayState.getState() == EscapeState.Virtual) { - ValueNode indexValue = tool.getReplacedValue(index()); + ValueNode alias = tool.getAlias(array()); + if (alias instanceof VirtualObjectNode) { + VirtualArrayNode virtual = (VirtualArrayNode) alias; + ValueNode indexValue = tool.getAlias(index()); int idx = indexValue.isConstant() ? indexValue.asJavaConstant().asInt() : -1; - if (idx >= 0 && idx < arrayState.getVirtualObject().entryCount()) { - tool.replaceWith(arrayState.getEntry(idx)); + if (idx >= 0 && idx < virtual.entryCount()) { + tool.replaceWith(tool.getEntry(virtual, idx)); } } } diff -r 17b96d2fe8d6 -r 681c04ce9db2 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorEnterNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorEnterNode.java Fri Jul 24 13:26:44 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorEnterNode.java Fri Jul 24 16:20:56 2015 +0200 @@ -30,6 +30,7 @@ import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.memory.*; import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.virtual.*; /** * The {@code MonitorEnterNode} represents the acquisition of a monitor. @@ -55,10 +56,13 @@ @Override public void virtualize(VirtualizerTool tool) { - State state = tool.getObjectState(object()); - if (state != null && state.getState() == EscapeState.Virtual && state.getVirtualObject().hasIdentity()) { - state.addLock(getMonitorId()); - tool.delete(); + ValueNode alias = tool.getAlias(object()); + if (alias instanceof VirtualObjectNode) { + VirtualObjectNode virtual = (VirtualObjectNode) alias; + if (virtual.hasIdentity()) { + tool.addLock(virtual, getMonitorId()); + tool.delete(); + } } } } diff -r 17b96d2fe8d6 -r 681c04ce9db2 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorExitNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorExitNode.java Fri Jul 24 13:26:44 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorExitNode.java Fri Jul 24 16:20:56 2015 +0200 @@ -32,6 +32,7 @@ import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.memory.*; import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.virtual.*; /** * The {@code MonitorExitNode} represents a monitor release. If it is the release of the monitor of @@ -79,12 +80,15 @@ @Override public void virtualize(VirtualizerTool tool) { - State state = tool.getObjectState(object()); // the monitor exit for a synchronized method should never be virtualized - if (state != null && state.getState() == EscapeState.Virtual && state.getVirtualObject().hasIdentity()) { - MonitorIdNode removedLock = state.removeLock(); - assert removedLock == getMonitorId() : "mismatch at " + this + ": " + removedLock + " vs. " + getMonitorId(); - tool.delete(); + ValueNode alias = tool.getAlias(object()); + if (alias instanceof VirtualObjectNode) { + VirtualObjectNode virtual = (VirtualObjectNode) alias; + if (virtual.hasIdentity()) { + MonitorIdNode removedLock = tool.removeLock(virtual); + assert removedLock == getMonitorId() : "mismatch at " + this + ": " + removedLock + " vs. " + getMonitorId(); + tool.delete(); + } } } } diff -r 17b96d2fe8d6 -r 681c04ce9db2 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 Fri Jul 24 13:26:44 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewArrayNode.java Fri Jul 24 16:20:56 2015 +0200 @@ -74,9 +74,9 @@ @Override public void virtualize(VirtualizerTool tool) { - ValueNode replacedLength = tool.getReplacedValue(length()); - if (replacedLength.asConstant() != null) { - final int constantLength = replacedLength.asJavaConstant().asInt(); + ValueNode lengthAlias = tool.getAlias(length()); + if (lengthAlias.asConstant() != null) { + int constantLength = lengthAlias.asJavaConstant().asInt(); if (constantLength >= 0 && constantLength < tool.getMaximumEntryCount()) { ValueNode[] state = new ValueNode[constantLength]; ConstantNode defaultForKind = constantLength == 0 ? null : defaultElementValue(); diff -r 17b96d2fe8d6 -r 681c04ce9db2 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/RawMonitorEnterNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/RawMonitorEnterNode.java Fri Jul 24 13:26:44 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/RawMonitorEnterNode.java Fri Jul 24 16:20:56 2015 +0200 @@ -31,6 +31,7 @@ import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.memory.*; import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.virtual.*; /** * The {@code MonitorEnterNode} represents the acquisition of a monitor. The object needs already be @@ -61,10 +62,13 @@ @Override public void virtualize(VirtualizerTool tool) { - State state = tool.getObjectState(object()); - if (state != null && state.getState() == EscapeState.Virtual && state.getVirtualObject().hasIdentity()) { - state.addLock(getMonitorId()); - tool.delete(); + ValueNode alias = tool.getAlias(object()); + if (alias instanceof VirtualObjectNode) { + VirtualObjectNode virtual = (VirtualObjectNode) alias; + if (virtual.hasIdentity()) { + tool.addLock(virtual, getMonitorId()); + tool.delete(); + } } } diff -r 17b96d2fe8d6 -r 681c04ce9db2 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/RegisterFinalizerNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/RegisterFinalizerNode.java Fri Jul 24 13:26:44 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/RegisterFinalizerNode.java Fri Jul 24 16:20:56 2015 +0200 @@ -33,6 +33,7 @@ import com.oracle.graal.nodeinfo.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.virtual.*; /** * This node is used to perform the finalizer registration at the end of the java.lang.Object @@ -94,8 +95,8 @@ @Override public void virtualize(VirtualizerTool tool) { - State state = tool.getObjectState(getValue()); - if (state != null && !state.getVirtualObject().type().hasFinalizer()) { + ValueNode alias = tool.getAlias(getValue()); + if (alias instanceof VirtualObjectNode && !((VirtualObjectNode) alias).type().hasFinalizer()) { tool.delete(); } } diff -r 17b96d2fe8d6 -r 681c04ce9db2 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/StoreFieldNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/StoreFieldNode.java Fri Jul 24 13:26:44 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/StoreFieldNode.java Fri Jul 24 16:20:56 2015 +0200 @@ -72,11 +72,12 @@ @Override public void virtualize(VirtualizerTool tool) { - State state = tool.getObjectState(object()); - if (state != null && state.getState() == EscapeState.Virtual) { - int fieldIndex = ((VirtualInstanceNode) state.getVirtualObject()).fieldIndex(field()); + ValueNode alias = tool.getAlias(object()); + if (alias instanceof VirtualObjectNode) { + VirtualInstanceNode virtual = (VirtualInstanceNode) alias; + int fieldIndex = virtual.fieldIndex(field()); if (fieldIndex != -1) { - tool.setVirtualEntry(state, fieldIndex, value(), false); + tool.setVirtualEntry(virtual, fieldIndex, value(), false); tool.delete(); } } diff -r 17b96d2fe8d6 -r 681c04ce9db2 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/StoreIndexedNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/StoreIndexedNode.java Fri Jul 24 13:26:44 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/StoreIndexedNode.java Fri Jul 24 16:20:56 2015 +0200 @@ -30,6 +30,7 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; +import com.oracle.graal.nodes.virtual.*; /** * The {@code StoreIndexedNode} represents a write to an array element. @@ -66,15 +67,16 @@ @Override public void virtualize(VirtualizerTool tool) { - State arrayState = tool.getObjectState(array()); - if (arrayState != null && arrayState.getState() == EscapeState.Virtual) { - ValueNode indexValue = tool.getReplacedValue(index()); + ValueNode alias = tool.getAlias(array()); + if (alias instanceof VirtualObjectNode) { + ValueNode indexValue = tool.getAlias(index()); int idx = indexValue.isConstant() ? indexValue.asJavaConstant().asInt() : -1; - if (idx >= 0 && idx < arrayState.getVirtualObject().entryCount()) { - ResolvedJavaType componentType = arrayState.getVirtualObject().type().getComponentType(); + VirtualArrayNode virtual = (VirtualArrayNode) alias; + if (idx >= 0 && idx < virtual.entryCount()) { + ResolvedJavaType componentType = virtual.type().getComponentType(); if (componentType.isPrimitive() || StampTool.isPointerAlwaysNull(value) || componentType.getSuperclass() == null || (StampTool.typeOrNull(value) != null && componentType.isAssignableFrom(StampTool.typeOrNull(value)))) { - tool.setVirtualEntry(arrayState, idx, value(), false); + tool.setVirtualEntry(virtual, idx, value(), false); tool.delete(); } } diff -r 17b96d2fe8d6 -r 681c04ce9db2 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/TypeCheckNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/TypeCheckNode.java Fri Jul 24 13:26:44 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/TypeCheckNode.java Fri Jul 24 16:20:56 2015 +0200 @@ -123,9 +123,10 @@ @Override public void virtualize(VirtualizerTool tool) { - State state = tool.getObjectState(getValue()); - if (state != null) { - tool.replaceWithValue(LogicConstantNode.forBoolean(type().equals(state.getVirtualObject().type()), graph())); + ValueNode alias = tool.getAlias(getValue()); + TriState state = tryFold(alias.stamp()); + if (state != TriState.UNKNOWN) { + tool.replaceWithValue(LogicConstantNode.forBoolean(state.isTrue(), graph())); } } diff -r 17b96d2fe8d6 -r 681c04ce9db2 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Virtualizable.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Virtualizable.java Fri Jul 24 13:26:44 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Virtualizable.java Fri Jul 24 16:20:56 2015 +0200 @@ -22,10 +22,6 @@ */ package com.oracle.graal.nodes.spi; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.java.*; -import com.oracle.graal.nodes.virtual.*; - /** * This interface allows a node to convey information about what its effect would be if some of its * inputs were virtualized. The {@link #virtualize(VirtualizerTool)} method will only be called for @@ -34,30 +30,6 @@ */ public interface Virtualizable { - public static enum EscapeState { - Virtual, - Materialized - } - - public abstract static class State { - - public abstract EscapeState getState(); - - public abstract VirtualObjectNode getVirtualObject(); - - public abstract ValueNode getEntry(int index); - - public abstract void addLock(MonitorIdNode monitorId); - - public abstract MonitorIdNode removeLock(); - - public abstract ValueNode getMaterializedValue(); - - public abstract void setEnsureVirtualized(boolean ensureVirtualized); - - public abstract boolean getEnsureVirtualized(); - } - /** * A node class can implement this method to convey information about what its effect would be * if some of its inputs were virtualized. All modifications must be made through the supplied diff -r 17b96d2fe8d6 -r 681c04ce9db2 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/VirtualizerTool.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/VirtualizerTool.java Fri Jul 24 13:26:44 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/VirtualizerTool.java Fri Jul 24 16:20:56 2015 +0200 @@ -29,7 +29,6 @@ import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.java.*; -import com.oracle.graal.nodes.spi.Virtualizable.State; import com.oracle.graal.nodes.virtual.*; /** @@ -72,45 +71,43 @@ void createVirtualObject(VirtualObjectNode virtualObject, ValueNode[] entryState, List locks, boolean ensureVirtualized); /** - * Queries the current state of the given value: if it is virtualized (thread-local and the - * compiler knows all entries) or not. + * Returns a VirtualObjectNode if the given value is aliased with a virtual object that is still + * virtual, the materialized value of the given value is aliased with a virtual object that was + * materialized, the replacement if the give value was replaced, otherwise the given value. * - * @param value the value whose state should be queried. - * @return the {@link State} representing the value if it has been virtualized at some point, - * null otherwise. + * Replacements via {@link #replaceWithValue(ValueNode)} are not immediately committed. This + * method can be used to determine if a value was replaced by another one (e.g., a load field by + * the loaded value). */ - State getObjectState(ValueNode value); + ValueNode getAlias(ValueNode value); /** * Sets the entry (field or array element) with the given index in the virtualized object. * - * @param state the state. * @param index the index to be set. * @param value the new value for the given index. * @param unsafe if true, then mismatching value {@link Kind}s will be accepted. */ - void setVirtualEntry(State state, int index, ValueNode value, boolean unsafe); + void setVirtualEntry(VirtualObjectNode virtualObject, int index, ValueNode value, boolean unsafe); - // scalar replacement + ValueNode getEntry(VirtualObjectNode virtualObject, int index); + + void addLock(VirtualObjectNode virtualObject, MonitorIdNode monitorId); - /** - * Replacements via {@link #replaceWithValue(ValueNode)} are not immediately committed. This - * method can be used to determine if a value was replaced by another one (e.g., a load field by - * the loaded value). - * - * @param original the original input value. - * @return the replacement value, or the original value if there is no replacement. - */ - ValueNode getReplacedValue(ValueNode original); + MonitorIdNode removeLock(VirtualObjectNode virtualObject); + + void setEnsureVirtualized(VirtualObjectNode virtualObject, boolean ensureVirtualized); + + boolean getEnsureVirtualized(VirtualObjectNode virtualObject); // operations on the current node /** * Deletes the current node and replaces it with the given virtualized object. * - * @param virtual the virtualized object that should replace the current node. + * @param virtualObject the virtualized object that should replace the current node. */ - void replaceWithVirtual(VirtualObjectNode virtual); + void replaceWithVirtual(VirtualObjectNode virtualObject); /** * Deletes the current node and replaces it with the given value. diff -r 17b96d2fe8d6 -r 681c04ce9db2 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/EnsureVirtualizedNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/EnsureVirtualizedNode.java Fri Jul 24 13:26:44 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/EnsureVirtualizedNode.java Fri Jul 24 16:20:56 2015 +0200 @@ -44,14 +44,15 @@ } public void virtualize(VirtualizerTool tool) { - State state = tool.getObjectState(object); - if (state != null && state.getState() == EscapeState.Virtual) { - if (state.getVirtualObject() instanceof VirtualBoxingNode) { - Throwable exception = new VerificationError("ensureVirtual is not valid for boxing objects: %s", state.getVirtualObject().type().getName()); + ValueNode alias = tool.getAlias(object); + if (alias instanceof VirtualObjectNode) { + VirtualObjectNode virtual = (VirtualObjectNode) alias; + if (virtual instanceof VirtualBoxingNode) { + Throwable exception = new VerificationError("ensureVirtual is not valid for boxing objects: %s", virtual.type().getName()); throw GraphUtil.approxSourceException(this, exception); } if (!localOnly) { - state.setEnsureVirtualized(true); + tool.setEnsureVirtualized(virtual, true); } tool.delete(); } diff -r 17b96d2fe8d6 -r 681c04ce9db2 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 Fri Jul 24 13:26:44 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectNode.java Fri Jul 24 16:20:56 2015 +0200 @@ -35,12 +35,32 @@ public static final NodeClass TYPE = NodeClass.create(VirtualObjectNode.class); protected boolean hasIdentity; + private int objectId = -1; protected VirtualObjectNode(NodeClass c, ResolvedJavaType type, boolean hasIdentity) { super(c, StampFactory.exactNonNull(type)); this.hasIdentity = hasIdentity; } + public final int getObjectId() { + return objectId; + } + + public final void resetObjectId() { + this.objectId = -1; + } + + public final void setObjectId(int objectId) { + assert objectId != -1; + this.objectId = objectId; + } + + @Override + protected void afterClone(Node other) { + super.afterClone(other); + resetObjectId(); + } + /** * The type of object described by this {@link VirtualObjectNode}. In case of arrays, this is * the array type (and not the component type). diff -r 17b96d2fe8d6 -r 681c04ce9db2 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ArrayEqualsNode.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ArrayEqualsNode.java Fri Jul 24 13:26:44 2015 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ArrayEqualsNode.java Fri Jul 24 16:20:56 2015 +0200 @@ -32,6 +32,7 @@ import com.oracle.graal.nodes.memory.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.util.*; +import com.oracle.graal.nodes.virtual.*; // JaCoCo Exclude @@ -76,32 +77,33 @@ } public void virtualize(VirtualizerTool tool) { - State state1 = tool.getObjectState(array1); - if (state1 != null) { - State state2 = tool.getObjectState(array2); - if (state2 != null) { - if (state1.getVirtualObject() == state2.getVirtualObject()) { - // the same virtual objects will always have the same contents + ValueNode alias1 = tool.getAlias(array1); + ValueNode alias2 = tool.getAlias(array2); + if (alias1 == alias2) { + // the same virtual objects will always have the same contents + tool.replaceWithValue(ConstantNode.forBoolean(true, graph())); + } else if (alias1 instanceof VirtualObjectNode && alias2 instanceof VirtualObjectNode) { + VirtualObjectNode virtual1 = (VirtualObjectNode) alias1; + VirtualObjectNode virtual2 = (VirtualObjectNode) alias2; + + if (virtual1.entryCount() == virtual2.entryCount()) { + int entryCount = virtual1.entryCount(); + boolean allEqual = true; + for (int i = 0; i < entryCount; i++) { + ValueNode entry1 = tool.getEntry(virtual1, i); + ValueNode entry2 = tool.getEntry(virtual2, i); + if (entry1 != entry2) { + // the contents might be different + allEqual = false; + } + if (entry1.stamp().alwaysDistinct(entry2.stamp())) { + // the contents are different + tool.replaceWithValue(ConstantNode.forBoolean(false, graph())); + return; + } + } + if (allEqual) { tool.replaceWithValue(ConstantNode.forBoolean(true, graph())); - } else if (state1.getVirtualObject().entryCount() == state2.getVirtualObject().entryCount() && state1.getState() == EscapeState.Virtual && state2.getState() == EscapeState.Virtual) { - int entryCount = state1.getVirtualObject().entryCount(); - boolean allEqual = true; - for (int i = 0; i < entryCount; i++) { - ValueNode entry1 = state1.getEntry(i); - ValueNode entry2 = state2.getEntry(i); - if (entry1 != entry2) { - // the contents might be different - allEqual = false; - } - if (entry1.stamp().alwaysDistinct(entry2.stamp())) { - // the contents are different - tool.replaceWithValue(ConstantNode.forBoolean(false, graph())); - return; - } - } - if (allEqual) { - tool.replaceWithValue(ConstantNode.forBoolean(true, graph())); - } } } } diff -r 17b96d2fe8d6 -r 681c04ce9db2 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BasicArrayCopyNode.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BasicArrayCopyNode.java Fri Jul 24 13:26:44 2015 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BasicArrayCopyNode.java Fri Jul 24 16:20:56 2015 +0200 @@ -131,21 +131,11 @@ return position >= 0 && position + length <= virtualObject.entryCount(); } - private static boolean checkEntryTypes(int srcPos, int length, State srcState, ResolvedJavaType destComponentType, VirtualizerTool tool) { + private static boolean checkEntryTypes(int srcPos, int length, VirtualObjectNode src, ResolvedJavaType destComponentType, VirtualizerTool tool) { if (destComponentType.getKind() == Kind.Object) { for (int i = 0; i < length; i++) { - ValueNode entry = srcState.getEntry(srcPos + i); - State state = tool.getObjectState(entry); - ResolvedJavaType type; - if (state != null) { - if (state.getState() == EscapeState.Virtual) { - type = state.getVirtualObject().type(); - } else { - type = StampTool.typeOrNull(state.getMaterializedValue()); - } - } else { - type = StampTool.typeOrNull(entry); - } + ValueNode entry = tool.getEntry(src, srcPos + i); + ResolvedJavaType type = StampTool.typeOrNull(entry); if (type == null || !destComponentType.isAssignableFrom(type)) { return false; } @@ -177,52 +167,49 @@ @Override public void virtualize(VirtualizerTool tool) { - ValueNode sourcePosition = tool.getReplacedValue(getSourcePosition()); - ValueNode destinationPosition = tool.getReplacedValue(getDestinationPosition()); - ValueNode replacedLength = tool.getReplacedValue(getLength()); + ValueNode sourcePosition = tool.getAlias(getSourcePosition()); + ValueNode destinationPosition = tool.getAlias(getDestinationPosition()); + ValueNode replacedLength = tool.getAlias(getLength()); if (sourcePosition.isConstant() && destinationPosition.isConstant() && replacedLength.isConstant()) { int srcPosInt = sourcePosition.asJavaConstant().asInt(); int destPosInt = destinationPosition.asJavaConstant().asInt(); int len = replacedLength.asJavaConstant().asInt(); - State destState = tool.getObjectState(getDestination()); + ValueNode destAlias = tool.getAlias(getDestination()); - if (destState != null && destState.getState() == EscapeState.Virtual) { - VirtualObjectNode destVirtual = destState.getVirtualObject(); - if (!(destVirtual instanceof VirtualArrayNode)) { - return; - } + if (destAlias instanceof VirtualArrayNode) { + VirtualArrayNode destVirtual = (VirtualArrayNode) destAlias; if (len < 0 || !checkBounds(destPosInt, len, destVirtual)) { return; } - State srcState = tool.getObjectState(getSource()); - if (srcState != null && srcState.getState() == EscapeState.Virtual) { - VirtualObjectNode srcVirtual = srcState.getVirtualObject(); - if (((VirtualArrayNode) destVirtual).componentType().getKind() != Kind.Object) { + ValueNode srcAlias = tool.getAlias(getSource()); + + if (srcAlias instanceof VirtualObjectNode) { + if (!(srcAlias instanceof VirtualArrayNode)) { return; } - if (!(srcVirtual instanceof VirtualArrayNode)) { + VirtualArrayNode srcVirtual = (VirtualArrayNode) srcAlias; + if (destVirtual.componentType().getKind() != Kind.Object) { return; } - if (((VirtualArrayNode) srcVirtual).componentType().getKind() != Kind.Object) { + if (srcVirtual.componentType().getKind() != Kind.Object) { return; } if (!checkBounds(srcPosInt, len, srcVirtual)) { return; } - if (!checkEntryTypes(srcPosInt, len, srcState, destVirtual.type().getComponentType(), tool)) { + if (!checkEntryTypes(srcPosInt, len, srcVirtual, destVirtual.type().getComponentType(), tool)) { return; } for (int i = 0; i < len; i++) { - tool.setVirtualEntry(destState, destPosInt + i, srcState.getEntry(srcPosInt + i), false); + tool.setVirtualEntry(destVirtual, destPosInt + i, tool.getEntry(srcVirtual, srcPosInt + i), false); } tool.delete(); if (Debug.isLogEnabled()) { Debug.log("virtualized arraycopyf(%s, %d, %s, %d, %d)", getSource(), srcPosInt, getDestination(), destPosInt, len); } } else { - ValueNode source = srcState == null ? tool.getReplacedValue(getSource()) : srcState.getMaterializedValue(); - ResolvedJavaType sourceType = StampTool.typeOrNull(source); + ResolvedJavaType sourceType = StampTool.typeOrNull(srcAlias); if (sourceType == null || !sourceType.isArray()) { return; } @@ -232,9 +219,9 @@ return; } for (int i = 0; i < len; i++) { - LoadIndexedNode load = new LoadIndexedNode(source, ConstantNode.forInt(i + srcPosInt, graph()), destComponentType.getKind()); + LoadIndexedNode load = new LoadIndexedNode(srcAlias, ConstantNode.forInt(i + srcPosInt, graph()), destComponentType.getKind()); tool.addNode(load); - tool.setVirtualEntry(destState, destPosInt + i, load, false); + tool.setVirtualEntry(destVirtual, destPosInt + i, load, false); } tool.delete(); } diff -r 17b96d2fe8d6 -r 681c04ce9db2 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BasicObjectCloneNode.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BasicObjectCloneNode.java Fri Jul 24 13:26:44 2015 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BasicObjectCloneNode.java Fri Jul 24 16:20:56 2015 +0200 @@ -90,26 +90,20 @@ @Override public void virtualize(VirtualizerTool tool) { - State originalState = tool.getObjectState(getObject()); - if (originalState != null && originalState.getState() == EscapeState.Virtual) { - VirtualObjectNode originalVirtual = originalState.getVirtualObject(); + ValueNode originalAlias = tool.getAlias(getObject()); + if (originalAlias instanceof VirtualObjectNode) { + VirtualObjectNode originalVirtual = (VirtualObjectNode) originalAlias; if (isCloneableType(originalVirtual.type(), tool.getMetaAccessProvider())) { ValueNode[] newEntryState = new ValueNode[originalVirtual.entryCount()]; for (int i = 0; i < newEntryState.length; i++) { - newEntryState[i] = originalState.getEntry(i); + newEntryState[i] = tool.getEntry(originalVirtual, i); } VirtualObjectNode newVirtual = originalVirtual.duplicate(); tool.createVirtualObject(newVirtual, newEntryState, Collections. emptyList(), false); tool.replaceWithVirtual(newVirtual); } } else { - ValueNode obj; - if (originalState != null) { - obj = originalState.getMaterializedValue(); - } else { - obj = tool.getReplacedValue(getObject()); - } - ResolvedJavaType type = getConcreteType(obj.stamp(), graph().getAssumptions(), tool.getMetaAccessProvider()); + ResolvedJavaType type = getConcreteType(originalAlias.stamp(), graph().getAssumptions(), tool.getMetaAccessProvider()); if (type != null && !type.isArray()) { VirtualInstanceNode newVirtual = createVirtualInstanceNode(type, true); ResolvedJavaField[] fields = newVirtual.getFields(); @@ -117,7 +111,7 @@ ValueNode[] state = new ValueNode[fields.length]; final LoadFieldNode[] loads = new LoadFieldNode[fields.length]; for (int i = 0; i < fields.length; i++) { - state[i] = loads[i] = new LoadFieldNode(obj, fields[i]); + state[i] = loads[i] = new LoadFieldNode(originalAlias, fields[i]); tool.addNode(loads[i]); } tool.createVirtualObject(newVirtual, state, Collections. emptyList(), false); diff -r 17b96d2fe8d6 -r 681c04ce9db2 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/VirtualizableInvokeMacroNode.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/VirtualizableInvokeMacroNode.java Fri Jul 24 13:26:44 2015 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/VirtualizableInvokeMacroNode.java Fri Jul 24 16:20:56 2015 +0200 @@ -29,6 +29,7 @@ import com.oracle.graal.nodes.CallTargetNode.InvokeKind; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.virtual.*; /** * A helper class to allow elimination of byte code instrumentation that could interfere with escape @@ -46,8 +47,8 @@ @Override public void virtualize(VirtualizerTool tool) { for (ValueNode arg : arguments) { - State state = tool.getObjectState(arg); - if (state != null && state.getState() == EscapeState.Virtual) { + ValueNode alias = tool.getAlias(arg); + if (alias instanceof VirtualObjectNode) { tool.delete(); } } diff -r 17b96d2fe8d6 -r 681c04ce9db2 graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/GraphEffectList.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/GraphEffectList.java Fri Jul 24 13:26:44 2015 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/GraphEffectList.java Fri Jul 24 16:20:56 2015 +0200 @@ -176,8 +176,9 @@ * */ public void replaceAtUsages(ValueNode node, ValueNode replacement) { + assert node != null && replacement != null : node + " " + replacement; add("replace at usages", (graph, obsoleteNodes) -> { - assert node.isAlive() && replacement.isAlive(); + assert node.isAlive() && replacement.isAlive() : node + " " + replacement; if (replacement instanceof FixedWithNextNode && ((FixedWithNextNode) replacement).next() == null) { assert node instanceof FixedNode; graph.addBeforeFixed((FixedNode) node, (FixedWithNextNode) replacement); diff -r 17b96d2fe8d6 -r 681c04ce9db2 graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ObjectState.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ObjectState.java Fri Jul 24 13:26:44 2015 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ObjectState.java Fri Jul 24 16:20:56 2015 +0200 @@ -28,8 +28,6 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.java.*; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.nodes.spi.Virtualizable.EscapeState; import com.oracle.graal.nodes.virtual.*; import com.oracle.graal.virtual.nodes.*; @@ -38,14 +36,11 @@ * the fields or array elements (called "entries") and the lock count if the object is still * virtual. If the object was materialized, it contains the current materialized value. */ -public class ObjectState extends Virtualizable.State { +public class ObjectState { public static final DebugMetric CREATE_ESCAPED_OBJECT_STATE = Debug.metric("CreateEscapeObjectState"); public static final DebugMetric GET_ESCAPED_OBJECT_STATE = Debug.metric("GetEscapeObjectState"); - final VirtualObjectNode virtual; - - private EscapeState state; private ValueNode[] entries; private ValueNode materializedValue; private LockState locks; @@ -53,35 +48,32 @@ private EscapeObjectState cachedState; - public ObjectState(VirtualObjectNode virtual, ValueNode[] entries, EscapeState state, List locks, boolean ensureVirtualized) { - this(virtual, entries, state, (LockState) null, ensureVirtualized); + boolean copyOnWrite; + + public ObjectState(ValueNode[] entries, List locks, boolean ensureVirtualized) { + this(entries, (LockState) null, ensureVirtualized); for (int i = locks.size() - 1; i >= 0; i--) { this.locks = new LockState(locks.get(i), this.locks); } } - public ObjectState(VirtualObjectNode virtual, ValueNode[] entries, EscapeState state, LockState locks, boolean ensureVirtualized) { - this.virtual = virtual; + public ObjectState(ValueNode[] entries, LockState locks, boolean ensureVirtualized) { this.entries = entries; - this.state = state; this.locks = locks; this.ensureVirtualized = ensureVirtualized; } - public ObjectState(VirtualObjectNode virtual, ValueNode materializedValue, EscapeState state, LockState locks, boolean ensureVirtualized) { - this.virtual = virtual; + public ObjectState(ValueNode materializedValue, LockState locks, boolean ensureVirtualized) { + assert materializedValue != null; this.materializedValue = materializedValue; - this.state = state; this.locks = locks; this.ensureVirtualized = ensureVirtualized; } private ObjectState(ObjectState other) { - virtual = other.virtual; entries = other.entries == null ? null : other.entries.clone(); materializedValue = other.materializedValue; locks = other.locks; - state = other.state; cachedState = other.cachedState; ensureVirtualized = other.ensureVirtualized; } @@ -90,7 +82,7 @@ return new ObjectState(this); } - public EscapeObjectState createEscapeObjectState() { + public EscapeObjectState createEscapeObjectState(VirtualObjectNode virtual) { GET_ESCAPED_OBJECT_STATE.increment(); if (cachedState == null) { CREATE_ESCAPED_OBJECT_STATE.increment(); @@ -100,68 +92,55 @@ } - @Override - public EscapeState getState() { - return state; + public boolean isVirtual() { + assert materializedValue == null ^ entries == null; + return materializedValue == null; } - @Override - public VirtualObjectNode getVirtualObject() { - return virtual; - } - - public boolean isVirtual() { - return state == EscapeState.Virtual; - } - + /** + * Users of this method are not allowed to change the entries of the returned array. + */ public ValueNode[] getEntries() { - assert isVirtual() && entries != null; + assert isVirtual(); return entries; } - @Override public ValueNode getEntry(int index) { assert isVirtual(); return entries[index]; } + public ValueNode getMaterializedValue() { + assert !isVirtual(); + return materializedValue; + } + public void setEntry(int index, ValueNode value) { assert isVirtual(); - if (entries[index] != value) { - cachedState = null; - entries[index] = value; - } + cachedState = null; + entries[index] = value; } - public void escape(ValueNode materialized, EscapeState newState) { - assert state == EscapeState.Virtual && newState == EscapeState.Materialized; - state = newState; + public void escape(ValueNode materialized) { + assert isVirtual(); + assert materialized != null; materializedValue = materialized; entries = null; cachedState = null; assert !isVirtual(); } - @Override - public ValueNode getMaterializedValue() { - assert state == EscapeState.Materialized; - return materializedValue; - } - public void updateMaterializedValue(ValueNode value) { assert !isVirtual(); - if (value != materializedValue) { - cachedState = null; - materializedValue = value; - } + assert value != null; + cachedState = null; + materializedValue = value; } - @Override public void addLock(MonitorIdNode monitorId) { locks = new LockState(monitorId, locks); } - @Override public MonitorIdNode removeLock() { try { return locks.monitorId; @@ -188,12 +167,10 @@ return a == null && b == null; } - @Override public void setEnsureVirtualized(boolean ensureVirtualized) { this.ensureVirtualized = ensureVirtualized; } - @Override public boolean getEnsureVirtualized() { return ensureVirtualized; } @@ -206,7 +183,7 @@ } if (entries != null) { for (int i = 0; i < entries.length; i++) { - str.append(virtual.entryName(i)).append('=').append(entries[i]).append(' '); + str.append("entry").append(i).append('=').append(entries[i]).append(' '); } } if (materializedValue != null) { @@ -223,8 +200,6 @@ result = prime * result + Arrays.hashCode(entries); result = prime * result + (locks != null ? locks.monitorId.getLockDepth() : 0); result = prime * result + ((materializedValue == null) ? 0 : materializedValue.hashCode()); - result = prime * result + ((state == null) ? 0 : state.hashCode()); - result = prime * result + ((virtual == null) ? 0 : virtual.hashCode()); return result; } @@ -250,13 +225,11 @@ } else if (!materializedValue.equals(other.materializedValue)) { return false; } - if (state != other.state) { - return false; - } - assert virtual != null && other.virtual != null; - if (!virtual.equals(other.virtual)) { - return false; - } return true; } + + public ObjectState share() { + copyOnWrite = true; + return this; + } } diff -r 17b96d2fe8d6 -r 681c04ce9db2 graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeBlockState.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeBlockState.java Fri Jul 24 13:26:44 2015 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeBlockState.java Fri Jul 24 16:20:56 2015 +0200 @@ -24,16 +24,22 @@ import java.util.*; -import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.java.*; -import com.oracle.graal.nodes.spi.Virtualizable.EscapeState; import com.oracle.graal.nodes.virtual.*; public abstract class PartialEscapeBlockState> extends EffectsBlockState { - protected final Map objectStates = Node.newIdentityMap(); + private static final ObjectState[] EMPTY_ARRAY = new ObjectState[0]; + + private ObjectState[] objectStates; + + private static class RefCount { + private int refCount = 1; + } + + private RefCount arrayRefCount; /** * Final subclass of PartialEscapeBlockState, for performance and to make everything behave @@ -50,32 +56,91 @@ } protected PartialEscapeBlockState() { + objectStates = EMPTY_ARRAY; + arrayRefCount = new RefCount(); } protected PartialEscapeBlockState(PartialEscapeBlockState other) { super(other); - for (Map.Entry entry : other.objectStates.entrySet()) { - objectStates.put(entry.getKey(), entry.getValue().cloneState()); - } + adoptAddObjectStates(other); + } + + public ObjectState getObjectState(int object) { + ObjectState state = objectStates[object]; + assert state != null; + return state; + } + + public ObjectState getObjectStateOptional(int object) { + return object >= objectStates.length ? null : objectStates[object]; } public ObjectState getObjectState(VirtualObjectNode object) { - assert objectStates.containsKey(object); - return objectStates.get(object); + ObjectState state = objectStates[object.getObjectId()]; + assert state != null; + return state; } public ObjectState getObjectStateOptional(VirtualObjectNode object) { - return objectStates.get(object); + int id = object.getObjectId(); + return id >= objectStates.length ? null : objectStates[id]; + } + + private ObjectState[] getObjectStateArrayForModification() { + if (arrayRefCount.refCount > 1) { + objectStates = objectStates.clone(); + arrayRefCount = new RefCount(); + } + return objectStates; + } + + private ObjectState getObjectStateForModification(int object) { + ObjectState[] array = getObjectStateArrayForModification(); + ObjectState objectState = array[object]; + if (objectState.copyOnWrite) { + array[object] = objectState = objectState.cloneState(); + } + return objectState; } - public void materializeBefore(FixedNode fixed, VirtualObjectNode virtual, EscapeState state, GraphEffectList materializeEffects) { + public void setEntry(int object, int entryIndex, ValueNode value) { + if (objectStates[object].getEntry(entryIndex) != value) { + getObjectStateForModification(object).setEntry(entryIndex, value); + } + } + + public void escape(int object, ValueNode materialized) { + getObjectStateForModification(object).escape(materialized); + } + + public void addLock(int object, MonitorIdNode monitorId) { + getObjectStateForModification(object).addLock(monitorId); + } + + public MonitorIdNode removeLock(int object) { + return getObjectStateForModification(object).removeLock(); + } + + public void setEnsureVirtualized(int object, boolean ensureVirtualized) { + if (objectStates[object].getEnsureVirtualized() != ensureVirtualized) { + getObjectStateForModification(object).setEnsureVirtualized(ensureVirtualized); + } + } + + public void updateMaterializedValue(int object, ValueNode value) { + if (objectStates[object].getMaterializedValue() != value) { + getObjectStateForModification(object).updateMaterializedValue(value); + } + } + + public void materializeBefore(FixedNode fixed, VirtualObjectNode virtual, GraphEffectList materializeEffects) { PartialEscapeClosure.METRIC_MATERIALIZATIONS.increment(); List objects = new ArrayList<>(2); List values = new ArrayList<>(8); List> locks = new ArrayList<>(2); List otherAllocations = new ArrayList<>(2); List ensureVirtual = new ArrayList<>(2); - materializeWithCommit(fixed, virtual, objects, locks, values, ensureVirtual, otherAllocations, state); + materializeWithCommit(fixed, virtual, objects, locks, values, ensureVirtual, otherAllocations); materializeEffects.add("materializeBefore", (graph, obsoleteNodes) -> { for (ValueNode otherAllocation : otherAllocations) { @@ -117,13 +182,14 @@ } private void materializeWithCommit(FixedNode fixed, VirtualObjectNode virtual, List objects, List> locks, List values, - List ensureVirtual, List otherAllocations, EscapeState state) { + List ensureVirtual, List otherAllocations) { ObjectState obj = getObjectState(virtual); ValueNode[] entries = obj.getEntries(); ValueNode representation = virtual.getMaterializedRepresentation(fixed, entries, obj.getLocks()); - obj.escape(representation, state); - PartialEscapeClosure.updateStatesForMaterialized(this, obj); + escape(virtual.getObjectId(), representation); + obj = getObjectState(virtual); + PartialEscapeClosure.updateStatesForMaterialized(this, virtual, obj.getMaterializedValue()); if (representation instanceof AllocatedObjectNode) { objects.add((AllocatedObjectNode) representation); locks.add(LockState.asList(obj.getLocks())); @@ -134,9 +200,11 @@ } for (int i = 0; i < entries.length; i++) { if (entries[i] instanceof VirtualObjectNode) { - ObjectState entryObj = getObjectState((VirtualObjectNode) entries[i]); + VirtualObjectNode entryVirtual = (VirtualObjectNode) entries[i]; + ObjectState entryObj = getObjectState(entryVirtual); if (entryObj.isVirtual()) { - materializeWithCommit(fixed, entryObj.getVirtualObject(), objects, locks, values, ensureVirtual, otherAllocations, state); + materializeWithCommit(fixed, entryVirtual, objects, locks, values, ensureVirtual, otherAllocations); + entryObj = getObjectState(entryVirtual); } values.set(pos + i, entryObj.getMaterializedValue()); } else { @@ -155,26 +223,46 @@ VirtualUtil.trace("materialized %s as %s with values %s", virtual, representation, values); } - public void addObject(VirtualObjectNode virtual, ObjectState state) { - objectStates.put(virtual, state); + public void addObject(int virtual, ObjectState state) { + ensureSize(virtual)[virtual] = state; } - public Iterable getStates() { - return objectStates.values(); + private ObjectState[] ensureSize(int objectId) { + if (objectStates.length <= objectId) { + objectStates = Arrays.copyOf(objectStates, Math.max(objectId * 2, 4)); + arrayRefCount.refCount--; + arrayRefCount = new RefCount(); + return objectStates; + } else { + return getObjectStateArrayForModification(); + } } - public Set getVirtualObjects() { - return objectStates.keySet(); + public int getStateCount() { + return objectStates.length; } @Override public String toString() { - return super.toString() + ", Object States: " + objectStates; + return super.toString() + ", Object States: " + Arrays.toString(objectStates); } @Override public boolean equivalentTo(T other) { - return compareMaps(objectStates, other.objectStates); + int length = Math.max(objectStates.length, other.getStateCount()); + for (int i = 0; i < length; i++) { + ObjectState left = getObjectStateOptional(i); + ObjectState right = other.getObjectStateOptional(i); + if (left != right) { + if (left == null || right == null) { + return false; + } + if (!left.equals(right)) { + return false; + } + } + } + return true; } protected static boolean compareMaps(Map left, Map right) { @@ -212,4 +300,42 @@ } } + public void resetObjectStates(int size) { + objectStates = new ObjectState[size]; + } + + public static boolean identicalObjectStates(PartialEscapeBlockState[] states) { + for (int i = 1; i < states.length; i++) { + if (states[0].objectStates != states[i].objectStates) { + return false; + } + } + return true; + } + + public static boolean identicalObjectStates(PartialEscapeBlockState[] states, int object) { + for (int i = 1; i < states.length; i++) { + if (states[0].objectStates[object] != states[i].objectStates[object]) { + return false; + } + } + return true; + } + + public void adoptAddObjectStates(PartialEscapeBlockState other) { + if (objectStates != null) { + arrayRefCount.refCount--; + } + objectStates = other.objectStates; + arrayRefCount = other.arrayRefCount; + + if (arrayRefCount.refCount == 1) { + for (ObjectState state : objectStates) { + if (state != null) { + state.share(); + } + } + } + arrayRefCount.refCount++; + } } diff -r 17b96d2fe8d6 -r 681c04ce9db2 graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java Fri Jul 24 13:26:44 2015 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java Fri Jul 24 16:20:56 2015 +0200 @@ -23,6 +23,7 @@ package com.oracle.graal.virtual.phases.ea; import java.util.*; +import java.util.function.*; import com.oracle.graal.debug.*; import jdk.internal.jvmci.meta.*; @@ -37,7 +38,6 @@ import com.oracle.graal.nodes.VirtualState.NodeClosure; import com.oracle.graal.nodes.cfg.*; import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.nodes.spi.Virtualizable.EscapeState; import com.oracle.graal.nodes.virtual.*; import com.oracle.graal.phases.schedule.*; @@ -56,12 +56,14 @@ private final NodeBitMap hasVirtualInputs; private final VirtualizerToolImpl tool; + public final ArrayList virtualObjects = new ArrayList<>(); + private final class CollectVirtualObjectsClosure extends NodeClosure { - private final Set virtual; + private final Set virtual; private final GraphEffectList effects; private final BlockT state; - private CollectVirtualObjectsClosure(Set virtual, GraphEffectList effects, BlockT state) { + private CollectVirtualObjectsClosure(Set virtual, GraphEffectList effects, BlockT state) { this.virtual = virtual; this.effects = effects; this.state = state; @@ -69,20 +71,17 @@ @Override public void apply(Node usage, ValueNode value) { - ObjectState valueObj = getObjectState(state, value); - if (valueObj != null) { - virtual.add(valueObj); - effects.replaceFirstInput(usage, value, valueObj.virtual); - } else if (value instanceof VirtualObjectNode) { - ObjectState virtualObj = null; - for (ObjectState obj : state.getStates()) { - if (value == obj.virtual) { - virtualObj = obj; - break; - } + if (value instanceof VirtualObjectNode) { + VirtualObjectNode object = (VirtualObjectNode) value; + if (object.getObjectId() != -1 && state.getObjectStateOptional(object) != null) { + virtual.add(object); } - if (virtualObj != null) { - virtual.add(virtualObj); + } else { + ValueNode alias = getAlias(value); + if (alias instanceof VirtualObjectNode) { + VirtualObjectNode object = (VirtualObjectNode) alias; + virtual.add(object); + effects.replaceFirstInput(usage, value, object); } } } @@ -196,17 +195,11 @@ } if (canonicalizedValue != node && canonicalizedValue != null) { if (canonicalizedValue.isAlive()) { - ObjectState obj = getObjectState(state, canonicalizedValue); - if (obj != null) { - if (obj.getState() == EscapeState.Virtual) { - addAndMarkAlias(obj.virtual, node); - effects.deleteNode(node); - } else { - effects.replaceAtUsages(node, obj.getMaterializedValue()); - addScalarAlias(node, obj.getMaterializedValue()); - } + ValueNode alias = getAliasAndResolve(state, canonicalizedValue); + if (alias instanceof VirtualObjectNode) { + addAndMarkAlias((VirtualObjectNode) alias, node); + effects.deleteNode(node); } else { - ValueNode alias = getScalarAlias(canonicalizedValue); effects.replaceAtUsages(node, alias); addScalarAlias(node, alias); } @@ -240,7 +233,7 @@ if (input.isAlive()) { ObjectState obj = getObjectState(state, (ValueNode) input); if (obj != null) { - if (obj.getState() == EscapeState.Virtual) { + if (obj.isVirtual()) { return false; } else { pos.initialize(node, obj.getMaterializedValue()); @@ -262,10 +255,12 @@ VirtualUtil.trace("processing nodewithstate: %s", node); for (Node input : node.inputs()) { if (input instanceof ValueNode) { - ObjectState obj = getObjectState(state, (ValueNode) input); - if (obj != null) { - VirtualUtil.trace("replacing input %s at %s: %s", input, node, obj); - replaceWithMaterialized(input, node, insertBefore, state, obj, effects, METRIC_MATERIALIZATIONS_UNHANDLED); + ValueNode alias = getAlias((ValueNode) input); + if (alias instanceof VirtualObjectNode) { + int id = ((VirtualObjectNode) alias).getObjectId(); + ensureMaterialized(state, id, insertBefore, effects, METRIC_MATERIALIZATIONS_UNHANDLED); + effects.replaceFirstInput(node, input, state.getObjectState(id).getMaterializedValue()); + VirtualUtil.trace("replacing input %s at %s", input, node); } } } @@ -287,11 +282,11 @@ private void processNodeWithState(NodeWithState nodeWithState, BlockT state, GraphEffectList effects) { for (FrameState fs : nodeWithState.states()) { FrameState frameState = getUniqueFramestate(nodeWithState, fs); - Set virtual = new ArraySet<>(); + Set virtual = new ArraySet<>(); frameState.applyToNonVirtual(new CollectVirtualObjectsClosure(virtual, effects, state)); collectLockedVirtualObjects(state, virtual); collectReferencedVirtualObjects(state, virtual); - addVirtualMappings(effects, frameState, virtual); + addVirtualMappings(frameState, virtual, state, effects); } } @@ -305,23 +300,27 @@ return frameState; } - private static void addVirtualMappings(GraphEffectList effects, FrameState frameState, Set virtual) { - for (ObjectState obj : virtual) { - effects.addVirtualMapping(frameState, obj.createEscapeObjectState()); + private void addVirtualMappings(FrameState frameState, Set virtual, BlockT state, GraphEffectList effects) { + for (VirtualObjectNode obj : virtual) { + effects.addVirtualMapping(frameState, state.getObjectState(obj).createEscapeObjectState(obj)); } } - private void collectReferencedVirtualObjects(final BlockT state, final Set virtual) { - ArrayDeque queue = new ArrayDeque<>(virtual); + private void collectReferencedVirtualObjects(BlockT state, Set virtual) { + ArrayDeque queue = new ArrayDeque<>(virtual); while (!queue.isEmpty()) { - ObjectState obj = queue.removeLast(); - if (obj.isVirtual()) { - for (ValueNode entry : obj.getEntries()) { - if (entry instanceof VirtualObjectNode) { - ObjectState fieldObj = state.getObjectState((VirtualObjectNode) entry); - if (fieldObj.isVirtual() && !virtual.contains(fieldObj)) { - virtual.add(fieldObj); - queue.addLast(fieldObj); + VirtualObjectNode object = queue.removeLast(); + int id = object.getObjectId(); + if (id != -1) { + ObjectState objState = state.getObjectStateOptional(id); + if (objState != null && objState.isVirtual()) { + for (ValueNode entry : objState.getEntries()) { + if (entry instanceof VirtualObjectNode) { + VirtualObjectNode entryVirtual = (VirtualObjectNode) entry; + if (!virtual.contains(entryVirtual)) { + virtual.add(entryVirtual); + queue.addLast(entryVirtual); + } } } } @@ -329,10 +328,11 @@ } } - private void collectLockedVirtualObjects(final BlockT state, Set virtual) { - for (ObjectState obj : state.getStates()) { - if (obj.isVirtual() && obj.hasLocks()) { - virtual.add(obj); + private void collectLockedVirtualObjects(BlockT state, Set virtual) { + for (int i = 0; i < state.getStateCount(); i++) { + ObjectState objState = state.getObjectStateOptional(i); + if (objState != null && objState.isVirtual() && objState.hasLocks()) { + virtual.add(virtualObjects.get(i)); } } } @@ -340,49 +340,41 @@ /** * @return true if materialization happened, false if not. */ - private boolean ensureMaterialized(BlockT state, ObjectState obj, FixedNode materializeBefore, GraphEffectList effects, DebugMetric metric) { - assert obj != null; - if (obj.getState() == EscapeState.Virtual) { + private boolean ensureMaterialized(PartialEscapeBlockState state, int object, FixedNode materializeBefore, GraphEffectList effects, DebugMetric metric) { + if (state.getObjectState(object).isVirtual()) { metric.increment(); - state.materializeBefore(materializeBefore, obj.virtual, EscapeState.Materialized, effects); - updateStatesForMaterialized(state, obj); - assert !obj.isVirtual(); + VirtualObjectNode virtual = virtualObjects.get(object); + state.materializeBefore(materializeBefore, virtual, effects); + updateStatesForMaterialized(state, virtual, state.getObjectState(object).getMaterializedValue()); return true; } else { - assert obj.getState() == EscapeState.Materialized; return false; } } - public static void updateStatesForMaterialized(PartialEscapeBlockState state, ObjectState obj) { + public static void updateStatesForMaterialized(PartialEscapeBlockState state, VirtualObjectNode virtual, ValueNode materializedValue) { // update all existing states with the newly materialized object - for (ObjectState objState : state.objectStates.values()) { - if (objState.isVirtual()) { + for (int i = 0; i < state.getStateCount(); i++) { + ObjectState objState = state.getObjectStateOptional(i); + if (objState != null && objState.isVirtual()) { ValueNode[] entries = objState.getEntries(); - for (int i = 0; i < entries.length; i++) { - if (entries[i] == obj.virtual) { - objState.setEntry(i, obj.getMaterializedValue()); + for (int i2 = 0; i2 < entries.length; i2++) { + if (entries[i2] == virtual) { + state.setEntry(i, i2, materializedValue); } } } } } - private boolean replaceWithMaterialized(Node value, Node usage, FixedNode materializeBefore, BlockT state, ObjectState obj, GraphEffectList effects, DebugMetric metric) { - boolean materialized = ensureMaterialized(state, obj, materializeBefore, effects, metric); - effects.replaceFirstInput(usage, value, obj.getMaterializedValue()); - return materialized; - } - @Override protected void processInitialLoopState(Loop loop, BlockT initialState) { - super.processInitialLoopState(loop, initialState); - for (PhiNode phi : ((LoopBeginNode) loop.getHeader().getBeginNode()).phis()) { if (phi.valueAt(0) != null) { - ObjectState state = getObjectState(initialState, phi.valueAt(0)); - if (state != null && state.isVirtual()) { - addAndMarkAlias(state.virtual, phi); + ValueNode alias = getAliasAndResolve(initialState, phi.valueAt(0)); + if (alias instanceof VirtualObjectNode) { + VirtualObjectNode virtual = (VirtualObjectNode) alias; + addAndMarkAlias(virtual, phi); } } } @@ -391,49 +383,55 @@ @Override protected void processLoopExit(LoopExitNode exitNode, BlockT initialState, BlockT exitState, GraphEffectList effects) { if (exitNode.graph().hasValueProxies()) { - Map proxies = Node.newMap(); + Map proxies = new IdentityHashMap<>(); for (ProxyNode proxy : exitNode.proxies()) { - ObjectState obj = getObjectState(exitState, proxy.value()); - if (obj != null) { - proxies.put(obj.virtual, proxy); + ValueNode alias = getAlias(proxy.value()); + if (alias instanceof VirtualObjectNode) { + VirtualObjectNode virtual = (VirtualObjectNode) alias; + proxies.put(virtual.getObjectId(), proxy); } } - for (ObjectState obj : exitState.getStates()) { - ObjectState initialObj = initialState.getObjectStateOptional(obj.virtual); - if (obj.isVirtual()) { - processVirtualAtLoopExit(exitNode, effects, obj, initialObj); - } else { - processMaterializedAtLoopExit(exitNode, effects, proxies, obj, initialObj); + for (int i = 0; i < exitState.getStateCount(); i++) { + ObjectState exitObjState = exitState.getObjectStateOptional(i); + if (exitObjState != null) { + ObjectState initialObjState = initialState.getObjectStateOptional(i); + + if (exitObjState.isVirtual()) { + processVirtualAtLoopExit(exitNode, effects, i, exitObjState, initialObjState, exitState); + } else { + processMaterializedAtLoopExit(exitNode, effects, proxies, i, exitObjState, initialObjState, exitState); + } } } } } - private static void processMaterializedAtLoopExit(LoopExitNode exitNode, GraphEffectList effects, Map proxies, ObjectState obj, ObjectState initialObj) { - if (initialObj == null || initialObj.isVirtual()) { - ProxyNode proxy = proxies.get(obj.virtual); + private static void processMaterializedAtLoopExit(LoopExitNode exitNode, GraphEffectList effects, Map proxies, int object, ObjectState exitObjState, + ObjectState initialObjState, PartialEscapeBlockState exitState) { + if (initialObjState == null || initialObjState.isVirtual()) { + ProxyNode proxy = proxies.get(object); if (proxy == null) { - proxy = new ValueProxyNode(obj.getMaterializedValue(), exitNode); + proxy = new ValueProxyNode(exitObjState.getMaterializedValue(), exitNode); effects.addFloatingNode(proxy, "proxy"); } else { - effects.replaceFirstInput(proxy, proxy.value(), obj.getMaterializedValue()); + effects.replaceFirstInput(proxy, proxy.value(), exitObjState.getMaterializedValue()); // nothing to do - will be handled in processNode } - obj.updateMaterializedValue(proxy); + exitState.updateMaterializedValue(object, proxy); } else { - if (initialObj.getMaterializedValue() == obj.getMaterializedValue()) { - Debug.log("materialized value changes within loop: %s vs. %s at %s", initialObj.getMaterializedValue(), obj.getMaterializedValue(), exitNode); + if (initialObjState.getMaterializedValue() != exitObjState.getMaterializedValue()) { + Debug.log("materialized value changes within loop: %s vs. %s at %s", initialObjState.getMaterializedValue(), exitObjState.getMaterializedValue(), exitNode); } } } - private static void processVirtualAtLoopExit(LoopExitNode exitNode, GraphEffectList effects, ObjectState obj, ObjectState initialObj) { - for (int i = 0; i < obj.getEntries().length; i++) { - ValueNode value = obj.getEntry(i); + private static void processVirtualAtLoopExit(LoopExitNode exitNode, GraphEffectList effects, int object, ObjectState exitObjState, ObjectState initialObjState, PartialEscapeBlockState exitState) { + for (int i = 0; i < exitObjState.getEntries().length; i++) { + ValueNode value = exitState.getObjectState(object).getEntry(i); if (!(value instanceof VirtualObjectNode || value.isConstant())) { - if (exitNode.loopBegin().isPhiAtMerge(value) || initialObj == null || !initialObj.isVirtual() || initialObj.getEntry(i) != value) { + if (exitNode.loopBegin().isPhiAtMerge(value) || initialObjState == null || !initialObjState.isVirtual() || initialObjState.getEntry(i) != value) { ProxyNode proxy = new ValueProxyNode(value, exitNode); - obj.setEntry(i, proxy); + exitState.setEntry(object, i, proxy); effects.addFloatingNode(proxy, "virtualProxy"); } } @@ -525,56 +523,72 @@ * reached. This method needs to be careful to place the effects of the merging operation * into the correct blocks. * - * @param states the predecessor block states of the merge + * @param statesList the predecessor block states of the merge */ @Override - protected void merge(List states) { - super.merge(states); + protected void merge(List statesList) { + super.merge(statesList); + + PartialEscapeBlockState[] states = new PartialEscapeBlockState[statesList.size()]; + for (int i = 0; i < statesList.size(); i++) { + states[i] = statesList.get(i); + } // calculate the set of virtual objects that exist in all predecessors - Set virtualObjTemp = intersectVirtualObjects(states); + int[] virtualObjTemp = intersectVirtualObjects(states); - ObjectState[] objStates = new ObjectState[states.size()]; boolean materialized; do { materialized = false; - for (VirtualObjectNode object : virtualObjTemp) { - for (int i = 0; i < objStates.length; i++) { - objStates[i] = states.get(i).getObjectState(object); - } + + if (PartialEscapeBlockState.identicalObjectStates(states)) { + newState.adoptAddObjectStates(states[0]); + } else { - // determine if all inputs are virtual or the same materialized value - int virtual = 0; - ObjectState startObj = objStates[0]; - boolean locksMatch = true; - ValueNode uniqueMaterializedValue = startObj.isVirtual() ? null : startObj.getMaterializedValue(); - for (ObjectState obj : objStates) { - if (obj.isVirtual()) { - virtual++; - uniqueMaterializedValue = null; - locksMatch &= obj.locksEqual(startObj); - } else if (obj.getMaterializedValue() != uniqueMaterializedValue) { - uniqueMaterializedValue = null; + for (int object : virtualObjTemp) { + + if (PartialEscapeBlockState.identicalObjectStates(states, object)) { + newState.addObject(object, states[0].getObjectState(object).share()); + continue; } - } - if (virtual == objStates.length && locksMatch) { - materialized |= mergeObjectStates(object, objStates, states); - } else { - if (uniqueMaterializedValue != null) { - newState.addObject(object, new ObjectState(object, uniqueMaterializedValue, EscapeState.Materialized, null, false)); + // determine if all inputs are virtual or the same materialized value + int virtualCount = 0; + ObjectState startObj = states[0].getObjectState(object); + boolean locksMatch = true; + boolean ensureVirtual = true; + ValueNode uniqueMaterializedValue = startObj.isVirtual() ? null : startObj.getMaterializedValue(); + for (int i = 0; i < states.length; i++) { + ObjectState obj = states[i].getObjectState(object); + ensureVirtual &= obj.getEnsureVirtualized(); + if (obj.isVirtual()) { + virtualCount++; + uniqueMaterializedValue = null; + locksMatch &= obj.locksEqual(startObj); + } else if (obj.getMaterializedValue() != uniqueMaterializedValue) { + uniqueMaterializedValue = null; + } + } + + if (virtualCount == states.length && locksMatch) { + materialized |= mergeObjectStates(object, null, states); } else { - PhiNode materializedValuePhi = getPhi(object, StampFactory.forKind(Kind.Object)); - mergeEffects.addFloatingNode(materializedValuePhi, "materializedPhi"); - for (int i = 0; i < objStates.length; i++) { - ObjectState obj = objStates[i]; - if (obj.isVirtual()) { - Block predecessor = getPredecessor(i); - materialized |= ensureMaterialized(states.get(i), obj, predecessor.getEndNode(), blockEffects.get(predecessor), METRIC_MATERIALIZATIONS_MERGE); + if (uniqueMaterializedValue != null) { + newState.addObject(object, new ObjectState(uniqueMaterializedValue, null, ensureVirtual)); + } else { + PhiNode materializedValuePhi = getPhi(object, StampFactory.forKind(Kind.Object)); + mergeEffects.addFloatingNode(materializedValuePhi, "materializedPhi"); + for (int i = 0; i < states.length; i++) { + ObjectState obj = states[i].getObjectState(object); + if (obj.isVirtual()) { + Block predecessor = getPredecessor(i); + materialized |= ensureMaterialized(states[i], object, predecessor.getEndNode(), blockEffects.get(predecessor), METRIC_MATERIALIZATIONS_MERGE); + obj = states[i].getObjectState(object); + } + setPhiInput(materializedValuePhi, i, obj.getMaterializedValue()); } - setPhiInput(materializedValuePhi, i, obj.getMaterializedValue()); + newState.addObject(object, new ObjectState(materializedValuePhi, null, false)); } - newState.addObject(object, new ObjectState(object, materializedValuePhi, EscapeState.Materialized, null, false)); } } } @@ -585,19 +599,41 @@ } } if (materialized) { - newState.objectStates.clear(); + newState.resetObjectStates(virtualObjects.size()); mergeEffects.clear(); afterMergeEffects.clear(); } } while (materialized); } - private Set intersectVirtualObjects(List states) { - Set virtualObjTemp = Node.newSet(states.get(0).getVirtualObjects()); - for (int i = 1; i < states.size(); i++) { - virtualObjTemp.retainAll(states.get(i).getVirtualObjects()); + private int[] intersectVirtualObjects(PartialEscapeBlockState[] states) { + int length = states[0].getStateCount(); + for (int i = 1; i < states.length; i++) { + length = Math.min(length, states[i].getStateCount()); } - return virtualObjTemp; + boolean[] result = new boolean[length]; + Arrays.fill(result, true); + int count = length; + for (int i = 0; i < states.length; i++) { + PartialEscapeBlockState state = states[i]; + for (int i2 = 0; i2 < length; i2++) { + if (result[i2]) { + if (state.getObjectStateOptional(i2) == null) { + result[i2] = false; + count--; + } + } + } + } + int[] resultInts = new int[count]; + int index = 0; + for (int i = 0; i < length; i++) { + if (result[i]) { + resultInts[index++] = i; + } + } + assert index == count; + return resultInts; } /** @@ -608,28 +644,30 @@ * can be incompatible if they contain {@code long} or {@code double} values occupying two * {@code int} slots in such a way that that their values cannot be merged using PhiNodes. * - * @param object the virtual object that should be associated with the merged object state - * @param objStates the incoming object states (all of which need to be virtual) - * @param blockStates the predecessor block states of the merge + * @param states the predecessor block states of the merge * @return true if materialization happened during the merge, false otherwise */ - private boolean mergeObjectStates(VirtualObjectNode object, ObjectState[] objStates, List blockStates) { + private boolean mergeObjectStates(int resultObject, int[] sourceObjects, PartialEscapeBlockState[] states) { boolean compatible = true; boolean ensureVirtual = true; - ValueNode[] values = objStates[0].getEntries().clone(); + IntFunction getObject = index -> sourceObjects == null ? resultObject : sourceObjects[index]; + + VirtualObjectNode virtual = virtualObjects.get(resultObject); + int entryCount = virtual.entryCount(); // determine all entries that have a two-slot value Kind[] twoSlotKinds = null; - outer: for (int i = 0; i < objStates.length; i++) { - ValueNode[] entries = objStates[i].getEntries(); + outer: for (int i = 0; i < states.length; i++) { + ObjectState objectState = states[i].getObjectState(getObject.apply(i)); + ValueNode[] entries = objectState.getEntries(); int valueIndex = 0; - ensureVirtual &= objStates[i].getEnsureVirtualized(); - while (valueIndex < values.length) { + ensureVirtual &= objectState.getEnsureVirtualized(); + while (valueIndex < entryCount) { Kind otherKind = entries[valueIndex].getKind(); - Kind entryKind = object.entryKind(valueIndex); + Kind entryKind = virtual.entryKind(valueIndex); if (entryKind == Kind.Int && otherKind.needsTwoSlots()) { if (twoSlotKinds == null) { - twoSlotKinds = new Kind[values.length]; + twoSlotKinds = new Kind[entryCount]; } if (twoSlotKinds[valueIndex] != null && twoSlotKinds[valueIndex] != otherKind) { compatible = false; @@ -647,18 +685,20 @@ } if (compatible && twoSlotKinds != null) { // if there are two-slot values then make sure the incoming states can be merged - outer: for (int valueIndex = 0; valueIndex < values.length; valueIndex++) { + outer: for (int valueIndex = 0; valueIndex < entryCount; valueIndex++) { if (twoSlotKinds[valueIndex] != null) { - assert valueIndex < object.entryCount() - 1 && object.entryKind(valueIndex) == Kind.Int && object.entryKind(valueIndex + 1) == Kind.Int; - for (int i = 0; i < objStates.length; i++) { - ValueNode value = objStates[i].getEntry(valueIndex); + assert valueIndex < virtual.entryCount() - 1 && virtual.entryKind(valueIndex) == Kind.Int && virtual.entryKind(valueIndex + 1) == Kind.Int; + for (int i = 0; i < states.length; i++) { + int object = getObject.apply(i); + ObjectState objectState = states[i].getObjectState(object); + ValueNode value = objectState.getEntry(valueIndex); Kind valueKind = value.getKind(); if (valueKind != twoSlotKinds[valueIndex]) { - ValueNode nextValue = objStates[i].getEntry(valueIndex + 1); + ValueNode nextValue = objectState.getEntry(valueIndex + 1); if (value.isConstant() && value.asConstant().equals(JavaConstant.INT_0) && nextValue.isConstant() && nextValue.asConstant().equals(JavaConstant.INT_0)) { // rewrite to a zero constant of the larger kind - objStates[i].setEntry(valueIndex, ConstantNode.defaultForKind(twoSlotKinds[valueIndex], graph())); - objStates[i].setEntry(valueIndex + 1, ConstantNode.forConstant(JavaConstant.forIllegal(), tool.getMetaAccessProvider(), graph())); + states[i].setEntry(object, valueIndex, ConstantNode.defaultForKind(twoSlotKinds[valueIndex], graph())); + states[i].setEntry(object, valueIndex + 1, ConstantNode.forConstant(JavaConstant.forIllegal(), tool.getMetaAccessProvider(), graph())); } else { compatible = false; break outer; @@ -671,12 +711,13 @@ if (compatible) { // virtual objects are compatible: create phis for all entries that need them - PhiNode[] phis = getValuePhis(object, object.entryCount()); + ValueNode[] values = states[0].getObjectState(getObject.apply(0)).getEntries().clone(); + PhiNode[] phis = getValuePhis(virtual, virtual.entryCount()); int valueIndex = 0; while (valueIndex < values.length) { - for (int i = 1; i < objStates.length; i++) { + for (int i = 1; i < states.length; i++) { if (phis[valueIndex] == null) { - ValueNode field = objStates[i].getEntry(valueIndex); + ValueNode field = states[i].getObjectState(getObject.apply(i)).getEntry(valueIndex); if (values[valueIndex] != field) { phis[valueIndex] = createValuePhi(values[valueIndex].stamp().unrestricted()); } @@ -699,26 +740,31 @@ PhiNode phi = phis[i]; if (phi != null) { mergeEffects.addFloatingNode(phi, "virtualMergePhi"); - if (object.entryKind(i) == Kind.Object) { - materialized |= mergeObjectEntry(objStates, blockStates, phi, i); + if (virtual.entryKind(i) == Kind.Object) { + materialized |= mergeObjectEntry(getObject, states, phi, i); } else { - mergePrimitiveEntry(objStates, phi, i); + for (int i2 = 0; i2 < states.length; i2++) { + ObjectState state = states[i2].getObjectState(getObject.apply(i2)); + if (!state.isVirtual()) { + break; + } + setPhiInput(phi, i2, state.getEntry(i)); + } } values[i] = phi; } } - newState.addObject(object, new ObjectState(object, values, EscapeState.Virtual, objStates[0].getLocks(), ensureVirtual)); + newState.addObject(resultObject, new ObjectState(values, states[0].getObjectState(getObject.apply(0)).getLocks(), ensureVirtual)); return materialized; } else { // not compatible: materialize in all predecessors - PhiNode materializedValuePhi = getPhi(object, StampFactory.forKind(Kind.Object)); - for (int i = 0; i < blockStates.size(); i++) { - ObjectState obj = objStates[i]; + PhiNode materializedValuePhi = getPhi(resultObject, StampFactory.forKind(Kind.Object)); + for (int i = 0; i < states.length; i++) { Block predecessor = getPredecessor(i); - ensureMaterialized(blockStates.get(i), obj, predecessor.getEndNode(), blockEffects.get(predecessor), METRIC_MATERIALIZATIONS_MERGE); - setPhiInput(materializedValuePhi, i, obj.getMaterializedValue()); + ensureMaterialized(states[i], getObject.apply(i), predecessor.getEndNode(), blockEffects.get(predecessor), METRIC_MATERIALIZATIONS_MERGE); + setPhiInput(materializedValuePhi, i, states[i].getObjectState(getObject.apply(i)).getMaterializedValue()); } - newState.addObject(object, new ObjectState(object, materializedValuePhi, EscapeState.Materialized, null, false)); + newState.addObject(resultObject, new ObjectState(materializedValuePhi, null, ensureVirtual)); return true; } } @@ -729,19 +775,22 @@ * * @return true if materialization happened during the merge, false otherwise */ - private boolean mergeObjectEntry(ObjectState[] objStates, List blockStates, PhiNode phi, int entryIndex) { + private boolean mergeObjectEntry(IntFunction objectIdFunc, PartialEscapeBlockState[] states, PhiNode phi, int entryIndex) { boolean materialized = false; - for (int i = 0; i < objStates.length; i++) { - if (!objStates[i].isVirtual()) { + for (int i = 0; i < states.length; i++) { + int object = objectIdFunc.apply(i); + ObjectState objectState = states[i].getObjectState(object); + if (!objectState.isVirtual()) { break; } - ValueNode entry = objStates[i].getEntry(entryIndex); + ValueNode entry = objectState.getEntry(entryIndex); if (entry instanceof VirtualObjectNode) { - ObjectState obj = blockStates.get(i).getObjectState((VirtualObjectNode) entry); + VirtualObjectNode entryVirtual = (VirtualObjectNode) entry; Block predecessor = getPredecessor(i); - materialized |= ensureMaterialized(blockStates.get(i), obj, predecessor.getEndNode(), blockEffects.get(predecessor), METRIC_MATERIALIZATIONS_MERGE); - if (objStates[i].isVirtual()) { - objStates[i].setEntry(entryIndex, entry = obj.getMaterializedValue()); + materialized |= ensureMaterialized(states[i], entryVirtual.getObjectId(), predecessor.getEndNode(), blockEffects.get(predecessor), METRIC_MATERIALIZATIONS_MERGE); + objectState = states[i].getObjectState(object); + if (objectState.isVirtual()) { + states[i].setEntry(object, entryIndex, entry = states[i].getObjectState(entryVirtual.getObjectId()).getMaterializedValue()); } } setPhiInput(phi, i, entry); @@ -750,20 +799,6 @@ } /** - * Fill the inputs of the PhiNode corresponding to one primitive entry in the virtual - * object. - */ - private void mergePrimitiveEntry(ObjectState[] objStates, PhiNode phi, int entryIndex) { - for (int i = 0; i < objStates.length; i++) { - ObjectState state = objStates[i]; - if (!state.isVirtual()) { - break; - } - setPhiInput(phi, i, state.getEntry(entryIndex)); - } - } - - /** * Examine a PhiNode and try to replace it with merging of virtual objects if all its inputs * refer to virtual object states. In order for the merging to happen, all incoming object * states need to be compatible and without object identity (meaning that their object @@ -775,40 +810,46 @@ * and therefore also exist in the merged state * @return true if materialization happened during the merge, false otherwise */ - private boolean processPhi(ValuePhiNode phi, List states, Set mergedVirtualObjects) { + private boolean processPhi(ValuePhiNode phi, PartialEscapeBlockState[] states, int[] mergedVirtualObjects) { aliases.set(phi, null); // determine how many inputs are virtual and if they're all the same virtual object int virtualInputs = 0; - ObjectState[] objStates = new ObjectState[states.size()]; boolean uniqueVirtualObject = true; - for (int i = 0; i < objStates.length; i++) { - ObjectState obj = objStates[i] = getObjectState(states.get(i), getPhiValueAt(phi, i)); - if (obj != null) { - if (obj.isVirtual()) { - if (objStates[0] == null || objStates[0].virtual != obj.virtual) { + VirtualObjectNode[] virtualObjs = new VirtualObjectNode[states.length]; + for (int i = 0; i < states.length; i++) { + ValueNode alias = getAlias(getPhiValueAt(phi, i)); + if (alias instanceof VirtualObjectNode) { + VirtualObjectNode virtual = (VirtualObjectNode) alias; + virtualObjs[i] = virtual; + if (states[i].getObjectState(virtual).isVirtual()) { + if (virtualObjs[0] != alias) { uniqueVirtualObject = false; } virtualInputs++; } } } - if (virtualInputs == objStates.length) { + if (virtualInputs == states.length) { if (uniqueVirtualObject) { // all inputs refer to the same object: just make the phi node an alias - addAndMarkAlias(objStates[0].virtual, phi); + addAndMarkAlias(virtualObjs[0], phi); mergeEffects.deleteNode(phi); return false; } else { // all inputs are virtual: check if they're compatible and without identity boolean compatible = true; boolean hasIdentity = false; - ObjectState firstObj = objStates[0]; - for (int i = 0; i < objStates.length; i++) { - ObjectState obj = objStates[i]; - hasIdentity |= obj.virtual.hasIdentity(); - boolean identitySurvives = obj.virtual.hasIdentity() && mergedVirtualObjects.contains(obj.virtual); - if (identitySurvives || !firstObj.virtual.type().equals(obj.virtual.type()) || firstObj.virtual.entryCount() != obj.virtual.entryCount() || !firstObj.locksEqual(obj)) { + VirtualObjectNode firstVirtual = virtualObjs[0]; + for (int i = 0; i < states.length; i++) { + VirtualObjectNode virtual = virtualObjs[i]; + hasIdentity |= virtual.hasIdentity(); + boolean identitySurvives = virtual.hasIdentity() && Arrays.asList(mergedVirtualObjects).contains(virtual.getObjectId()); + if (identitySurvives || !firstVirtual.type().equals(virtual.type()) || firstVirtual.entryCount() != virtual.entryCount()) { + compatible = false; + break; + } + if (!states[0].getObjectState(firstVirtual).locksEqual(states[i].getObjectState(virtual))) { compatible = false; break; } @@ -816,22 +857,34 @@ if (compatible && hasIdentity) { // we still need to check whether this value is referenced by any other phi outer: for (PhiNode otherPhi : getPhis().filter(otherPhi -> otherPhi != phi)) { - for (int i = 0; i < objStates.length; i++) { - ObjectState otherPhiValueState = getObjectState(states.get(i), getPhiValueAt(otherPhi, i)); - if (Arrays.asList(objStates).contains(otherPhiValueState)) { - compatible = false; - break outer; + for (int i = 0; i < states.length; i++) { + ValueNode alias = getAliasAndResolve(states[i], getPhiValueAt(otherPhi, i)); + if (alias instanceof VirtualObjectNode) { + VirtualObjectNode phiValueVirtual = (VirtualObjectNode) alias; + if (Arrays.asList(virtualObjs).contains(phiValueVirtual)) { + compatible = false; + break outer; + } } } } } if (compatible) { - VirtualObjectNode virtual = getValueObjectVirtual(phi, getObjectState(states.get(0), getPhiValueAt(phi, 0)).virtual); + VirtualObjectNode virtual = getValueObjectVirtual(phi, virtualObjs[0]); mergeEffects.addFloatingNode(virtual, "valueObjectNode"); mergeEffects.deleteNode(phi); + if (virtual.getObjectId() == -1) { + int id = virtualObjects.size(); + virtualObjects.add(virtual); + virtual.setObjectId(id); + } - boolean materialized = mergeObjectStates(virtual, objStates, states); + int[] virtualObjectIds = new int[states.length]; + for (int i = 0; i < states.length; i++) { + virtualObjectIds[i] = virtualObjs[i].getObjectId(); + } + boolean materialized = mergeObjectStates(virtual.getObjectId(), virtualObjectIds, states); addAndMarkAlias(virtual, virtual); addAndMarkAlias(virtual, phi); return materialized; @@ -841,12 +894,12 @@ // otherwise: materialize all phi inputs boolean materialized = false; - for (int i = 0; i < objStates.length; i++) { - ObjectState obj = objStates[i]; - if (obj != null) { + for (int i = 0; i < states.length; i++) { + VirtualObjectNode virtual = virtualObjs[i]; + if (virtual != null) { Block predecessor = getPredecessor(i); - materialized |= ensureMaterialized(states.get(i), obj, predecessor.getEndNode(), blockEffects.get(predecessor), METRIC_MATERIALIZATIONS_PHI); - setPhiInput(phi, i, obj.getMaterializedValue()); + materialized |= ensureMaterialized(states[i], virtual.getObjectId(), predecessor.getEndNode(), blockEffects.get(predecessor), METRIC_MATERIALIZATIONS_PHI); + setPhiInput(phi, i, getAliasAndResolve(states[i], virtual)); } } return materialized; @@ -868,6 +921,29 @@ } } + public ValueNode getAlias(ValueNode value) { + if (value != null && !(value instanceof VirtualObjectNode)) { + if (value.isAlive() && !aliases.isNew(value)) { + ValueNode result = aliases.get(value); + if (result != null) { + return result; + } + } + } + return value; + } + + public ValueNode getAliasAndResolve(PartialEscapeBlockState state, ValueNode value) { + ValueNode result = getAlias(value); + if (result instanceof VirtualObjectNode) { + int id = ((VirtualObjectNode) result).getObjectId(); + if (id != -1 && !state.getObjectState(id).isVirtual()) { + result = state.getObjectState(id).getMaterializedValue(); + } + } + return result; + } + void addAndMarkAlias(VirtualObjectNode virtual, ValueNode node) { if (node.isAlive()) { aliases.set(node, virtual); diff -r 17b96d2fe8d6 -r 681c04ce9db2 graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapePhase.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapePhase.java Fri Jul 24 13:26:44 2015 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapePhase.java Fri Jul 24 16:20:56 2015 +0200 @@ -33,6 +33,7 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.cfg.*; import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.virtual.*; import com.oracle.graal.phases.*; import com.oracle.graal.phases.common.*; import com.oracle.graal.phases.schedule.*; @@ -83,6 +84,9 @@ @Override protected Closure createEffectsClosure(PhaseContext context, SchedulePhase schedule, ControlFlowGraph cfg) { + for (VirtualObjectNode virtual : cfg.graph.getNodes(VirtualObjectNode.TYPE)) { + virtual.resetObjectId(); + } assert schedule != null; if (readElimination) { return new PEReadEliminationClosure(schedule, context.getMetaAccess(), context.getConstantReflection()); diff -r 17b96d2fe8d6 -r 681c04ce9db2 graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualUtil.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualUtil.java Fri Jul 24 13:26:44 2015 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualUtil.java Fri Jul 24 16:20:56 2015 +0200 @@ -109,6 +109,7 @@ } if (!success) { TTY.println(); + Debug.dump(graph, "assertNonReachable"); } return success; } diff -r 17b96d2fe8d6 -r 681c04ce9db2 graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualizerToolImpl.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualizerToolImpl.java Fri Jul 24 13:26:44 2015 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualizerToolImpl.java Fri Jul 24 16:20:56 2015 +0200 @@ -33,8 +33,6 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.java.*; -import com.oracle.graal.nodes.spi.Virtualizable.EscapeState; -import com.oracle.graal.nodes.spi.Virtualizable.State; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.virtual.*; @@ -78,33 +76,35 @@ } @Override - public State getObjectState(ValueNode value) { - return closure.getObjectState(state, value); + public ValueNode getAlias(ValueNode value) { + return closure.getAliasAndResolve(state, value); + } + + public ValueNode getEntry(VirtualObjectNode virtualObject, int index) { + return state.getObjectState(virtualObject).getEntry(index); } @Override - public void setVirtualEntry(State objectState, int index, ValueNode value, boolean unsafe) { - ObjectState obj = (ObjectState) objectState; - assert obj != null && obj.isVirtual() : "not virtual: " + obj; + public void setVirtualEntry(VirtualObjectNode virtual, int index, ValueNode value, boolean unsafe) { + ObjectState obj = state.getObjectState(virtual); + assert obj.isVirtual() : "not virtual: " + obj; ValueNode newValue; if (value == null) { newValue = null; } else { - ObjectState valueState = closure.getObjectState(state, value); - if (valueState == null) { - newValue = getReplacedValue(value); - assert unsafe || obj.getEntry(index) == null || obj.getEntry(index).getKind() == newValue.getKind() || (isObjectEntry(obj.getEntry(index)) && isObjectEntry(newValue)); - } else { - if (valueState.getState() != EscapeState.Virtual) { - newValue = valueState.getMaterializedValue(); - assert newValue.getKind() == Kind.Object; - } else { - newValue = valueState.getVirtualObject(); - } - assert obj.getEntry(index) == null || isObjectEntry(obj.getEntry(index)); - } + newValue = closure.getAliasAndResolve(state, value); + assert unsafe || obj.getEntry(index) == null || obj.getEntry(index).getKind() == newValue.getKind() || (isObjectEntry(obj.getEntry(index)) && isObjectEntry(newValue)); } - obj.setEntry(index, newValue); + state.setEntry(virtual.getObjectId(), index, newValue); + } + + public void setEnsureVirtualized(VirtualObjectNode virtualObject, boolean ensureVirtualized) { + int id = virtualObject.getObjectId(); + state.setEnsureVirtualized(id, ensureVirtualized); + } + + public boolean getEnsureVirtualized(VirtualObjectNode virtualObject) { + return state.getObjectState(virtualObject).getEnsureVirtualized(); } private static boolean isObjectEntry(ValueNode value) { @@ -112,11 +112,6 @@ } @Override - public ValueNode getReplacedValue(ValueNode original) { - return closure.getScalarAlias(original); - } - - @Override public void replaceWithVirtual(VirtualObjectNode virtual) { closure.addAndMarkAlias(virtual, current); effects.deleteNode(current); @@ -157,16 +152,16 @@ effects.addFloatingNode(virtualObject, "newVirtualObject"); } for (int i = 0; i < entryState.length; i++) { - if (!(entryState[i] instanceof VirtualObjectNode)) { - ObjectState v = closure.getObjectState(state, entryState[i]); - if (v != null) { - entryState[i] = v.isVirtual() ? v.getVirtualObject() : v.getMaterializedValue(); - } else { - entryState[i] = closure.getScalarAlias(entryState[i]); - } - } + ValueNode entry = entryState[i]; + entryState[i] = entry instanceof VirtualObjectNode ? entry : closure.getAliasAndResolve(state, entry); } - state.addObject(virtualObject, new ObjectState(virtualObject, entryState, EscapeState.Virtual, locks, ensureVirtualized)); + int id = virtualObject.getObjectId(); + if (id == -1) { + id = closure.virtualObjects.size(); + closure.virtualObjects.add(virtualObject); + virtualObject.setObjectId(id); + } + state.addObject(id, new ObjectState(entryState, locks, ensureVirtualized)); closure.addAndMarkAlias(virtualObject, virtualObject); PartialEscapeClosure.METRIC_ALLOCATION_REMOVED.increment(); } @@ -178,18 +173,23 @@ @Override public void replaceWith(ValueNode node) { - State resultState = getObjectState(node); - if (resultState == null) { - replaceWithValue(node); + if (node instanceof VirtualObjectNode) { + replaceWithVirtual((VirtualObjectNode) node); } else { - if (resultState.getState() == EscapeState.Virtual) { - replaceWithVirtual(resultState.getVirtualObject()); - } else { - replaceWithValue(resultState.getMaterializedValue()); - } + replaceWithValue(node); } } + public void addLock(VirtualObjectNode virtualObject, MonitorIdNode monitorId) { + int id = virtualObject.getObjectId(); + state.addLock(id, monitorId); + } + + public MonitorIdNode removeLock(VirtualObjectNode virtualObject) { + int id = virtualObject.getObjectId(); + return state.removeLock(id); + } + public MetaAccessProvider getMetaAccess() { return metaAccess; }