# HG changeset patch # User Doug Simon # Date 1428954679 -7200 # Node ID 44d8f20d4f5536503ac843a0a75992910b716a39 # Parent dc58f4ca21c9d27a4b510e58e524546af9c947f1# Parent c893d4112f30d2a2c0eabecc3c94207cce7f7403 Merge. diff -r dc58f4ca21c9 -r 44d8f20d4f55 graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/AbstractObjectStamp.java --- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/AbstractObjectStamp.java Mon Apr 13 21:50:37 2015 +0200 +++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/AbstractObjectStamp.java Mon Apr 13 21:51:19 2015 +0200 @@ -98,9 +98,6 @@ if (this == otherStamp) { return this; } - if (!isCompatible(otherStamp)) { - return StampFactory.illegal(Kind.Illegal); - } AbstractObjectStamp other = (AbstractObjectStamp) otherStamp; if (isIllegal()) { return other; @@ -170,9 +167,6 @@ if (this == otherStamp) { return this; } - if (!isCompatible(otherStamp)) { - return StampFactory.illegal(Kind.Illegal); - } AbstractObjectStamp other = (AbstractObjectStamp) otherStamp; if (isIllegal()) { return this; diff -r dc58f4ca21c9 -r 44d8f20d4f55 graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/FloatStamp.java --- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/FloatStamp.java Mon Apr 13 21:50:37 2015 +0200 +++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/FloatStamp.java Mon Apr 13 21:51:19 2015 +0200 @@ -176,9 +176,6 @@ if (otherStamp == this) { return this; } - if (!(otherStamp instanceof FloatStamp)) { - return StampFactory.illegal(Kind.Illegal); - } FloatStamp other = (FloatStamp) otherStamp; assert getBits() == other.getBits(); double meetUpperBound = meetBounds(upperBound, other.upperBound, Math::max); @@ -198,9 +195,6 @@ if (otherStamp == this) { return this; } - if (!(otherStamp instanceof FloatStamp)) { - return StampFactory.illegal(Kind.Illegal); - } FloatStamp other = (FloatStamp) otherStamp; assert getBits() == other.getBits(); double joinUpperBound = Math.min(upperBound, other.upperBound); diff -r dc58f4ca21c9 -r 44d8f20d4f55 graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/IllegalStamp.java --- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/IllegalStamp.java Mon Apr 13 21:50:37 2015 +0200 +++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/IllegalStamp.java Mon Apr 13 21:51:19 2015 +0200 @@ -27,7 +27,9 @@ import com.oracle.graal.compiler.common.spi.*; /** - * This stamp represents the illegal type. Values with this type can not exist at run time. + * This stamp represents the type of the {@link Kind#Illegal} value in the second slot of + * {@link Kind#Long} and {@link Kind#Double} values. It can only appear in framestates or virtual + * objects. */ public final class IllegalStamp extends Stamp { @@ -56,7 +58,8 @@ @Override public Stamp constant(Constant c, MetaAccessProvider meta) { - throw GraalInternalError.shouldNotReachHere("illegal stamp has no value"); + assert ((PrimitiveConstant) c).getKind() == Kind.Illegal; + return this; } @Override @@ -66,17 +69,19 @@ @Override public Stamp meet(Stamp other) { + assert other instanceof IllegalStamp; return this; } @Override public Stamp join(Stamp other) { + assert other instanceof IllegalStamp; return this; } @Override public boolean isCompatible(Stamp stamp) { - return false; + return stamp instanceof IllegalStamp; } @Override @@ -91,6 +96,7 @@ @Override public Stamp improveWith(Stamp other) { + assert other instanceof IllegalStamp; return this; } diff -r dc58f4ca21c9 -r 44d8f20d4f55 graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/IntegerStamp.java --- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/IntegerStamp.java Mon Apr 13 21:50:37 2015 +0200 +++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/IntegerStamp.java Mon Apr 13 21:51:19 2015 +0200 @@ -253,9 +253,6 @@ if (otherStamp == this) { return this; } - if (!(otherStamp instanceof IntegerStamp)) { - return StampFactory.illegal(Kind.Illegal); - } IntegerStamp other = (IntegerStamp) otherStamp; return createStamp(other, Math.max(upperBound, other.upperBound), Math.min(lowerBound, other.lowerBound), downMask & other.downMask, upMask | other.upMask); } @@ -265,9 +262,6 @@ if (otherStamp == this) { return this; } - if (!(otherStamp instanceof IntegerStamp)) { - return StampFactory.illegal(Kind.Illegal); - } IntegerStamp other = (IntegerStamp) otherStamp; long newDownMask = downMask | other.downMask; long newLowerBound = Math.max(lowerBound, other.lowerBound) | newDownMask; diff -r dc58f4ca21c9 -r 44d8f20d4f55 graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/StampFactory.java --- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/StampFactory.java Mon Apr 13 21:50:37 2015 +0200 +++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/StampFactory.java Mon Apr 13 21:51:19 2015 +0200 @@ -76,10 +76,9 @@ for (Kind k : Kind.values()) { if (stampCache[k.ordinal()] != null) { illegalStampCache[k.ordinal()] = stampCache[k.ordinal()].illegal(); - } else { - illegalStampCache[k.ordinal()] = IllegalStamp.getInstance(); } } + illegalStampCache[Kind.Illegal.ordinal()] = IllegalStamp.getInstance(); } public static Stamp tautology() { @@ -122,10 +121,6 @@ return positiveInt; } - public static Stamp illegal() { - return illegal(Kind.Illegal); - } - public static Stamp illegal(Kind kind) { return illegalStampCache[kind.ordinal()]; } diff -r dc58f4ca21c9 -r 44d8f20d4f55 graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/VoidStamp.java --- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/VoidStamp.java Mon Apr 13 21:50:37 2015 +0200 +++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/VoidStamp.java Mon Apr 13 21:51:19 2015 +0200 @@ -46,10 +46,8 @@ @Override public Stamp improveWith(Stamp other) { - if (other instanceof VoidStamp) { - return this; - } - return StampFactory.illegal(Kind.Illegal); + assert other instanceof VoidStamp; + return this; } @Override @@ -74,29 +72,19 @@ @Override public Stamp meet(Stamp other) { - if (other instanceof IllegalStamp) { - return other.join(this); - } - if (this == other) { - return this; - } - return StampFactory.illegal(Kind.Illegal); + assert other instanceof VoidStamp; + return this; } @Override public Stamp join(Stamp other) { - if (other instanceof IllegalStamp) { - return other.join(this); - } - if (this == other) { - return this; - } - return StampFactory.illegal(Kind.Illegal); + assert other instanceof VoidStamp; + return this; } @Override public boolean isCompatible(Stamp stamp) { - return this == stamp; + return stamp instanceof VoidStamp; } @Override diff -r dc58f4ca21c9 -r 44d8f20d4f55 graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/util/UnsafeArrayTypeWriter.java --- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/util/UnsafeArrayTypeWriter.java Mon Apr 13 21:50:37 2015 +0200 +++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/util/UnsafeArrayTypeWriter.java Mon Apr 13 21:51:19 2015 +0200 @@ -37,12 +37,17 @@ */ public class UnsafeArrayTypeWriter implements TypeWriter { - private static final int CHUNK_SIZE = 4000; + private static final int MIN_CHUNK_LENGTH = 200; + private static final int MAX_CHUNK_LENGTH = 16000; static class Chunk { - protected final byte[] data = new byte[CHUNK_SIZE]; + protected final byte[] data; protected int size; protected Chunk next; + + protected Chunk(int arrayLength) { + data = new byte[arrayLength]; + } } private Chunk firstChunk; @@ -50,7 +55,7 @@ private int totalSize; public UnsafeArrayTypeWriter() { - firstChunk = new Chunk(); + firstChunk = new Chunk(MIN_CHUNK_LENGTH); writeChunk = firstChunk; } @@ -153,7 +158,7 @@ private long writeOffset(int writeBytes) { if (writeChunk.size + writeBytes >= writeChunk.data.length) { - Chunk newChunk = new Chunk(); + Chunk newChunk = new Chunk(Math.min(writeChunk.data.length * 2, MAX_CHUNK_LENGTH)); writeChunk.next = newChunk; writeChunk = newChunk; } diff -r dc58f4ca21c9 -r 44d8f20d4f55 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/NodeLIRBuilder.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/NodeLIRBuilder.java Mon Apr 13 21:50:37 2015 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/NodeLIRBuilder.java Mon Apr 13 21:51:19 2015 +0200 @@ -304,7 +304,7 @@ } protected void emitNode(ValueNode node) { - if (Debug.isLogEnabled() && node.stamp() instanceof IllegalStamp) { + if (Debug.isLogEnabled() && node.stamp().isIllegal()) { Debug.log("This node has invalid type, we are emitting dead code(?): %s", node); } if (node instanceof LIRLowerable) { diff -r dc58f4ca21c9 -r 44d8f20d4f55 graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java --- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java Mon Apr 13 21:50:37 2015 +0200 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java Mon Apr 13 21:51:19 2015 +0200 @@ -433,7 +433,7 @@ this.movUsageFromEndTo(1); return true; } - for (int i = 0; i < this.extraUsagesCount; ++i) { + for (int i = this.extraUsagesCount - 1; i >= 0; i--) { if (extraUsages[i] == node) { this.movUsageFromEndTo(i + INLINE_USAGE_COUNT); return true; @@ -683,12 +683,12 @@ } private void unregisterInputs() { - for (Node input : inputs()) { - removeThisFromUsages(input); + acceptInputs((node, input) -> { + node.removeThisFromUsages(input); if (input.hasNoUsages()) { - maybeNotifyZeroUsages(input); + node.maybeNotifyZeroUsages(input); } - } + }); } public void clearInputs() { diff -r dc58f4ca21c9 -r 44d8f20d4f55 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/type/MetaspacePointerStamp.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/type/MetaspacePointerStamp.java Mon Apr 13 21:50:37 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/type/MetaspacePointerStamp.java Mon Apr 13 21:51:19 2015 +0200 @@ -40,9 +40,7 @@ @Override public Stamp meet(Stamp other) { - if (!isCompatible(other)) { - return StampFactory.illegal(); - } + assert isCompatible(other); return this; } @@ -53,9 +51,7 @@ @Override public Stamp join(Stamp other) { - if (!isCompatible(other)) { - return StampFactory.illegal(); - } + assert isCompatible(other); return this; } diff -r dc58f4ca21c9 -r 44d8f20d4f55 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/EncodedGraph.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/EncodedGraph.java Mon Apr 13 21:50:37 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/EncodedGraph.java Mon Apr 13 21:51:19 2015 +0200 @@ -41,6 +41,12 @@ private final Assumptions assumptions; private final Set inlinedMethods; + /** + * The "table of contents" of the encoded graph, i.e., the mapping from orderId numbers to the + * offset in the encoded byte[] array. Used as a cache during decoding. + */ + protected long[] nodeStartOffsets; + public EncodedGraph(byte[] encoding, long startOffset, Object[] objects, NodeClass[] types, Assumptions assumptions, Set inlinedMethods) { this.encoding = encoding; this.startOffset = startOffset; diff -r dc58f4ca21c9 -r 44d8f20d4f55 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java Mon Apr 13 21:50:37 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java Mon Apr 13 21:51:19 2015 +0200 @@ -227,11 +227,11 @@ * the stack. */ public FrameState duplicateModifiedDuringCall(int newBci, Kind popKind) { - return duplicateModified(newBci, rethrowException, true, popKind); + return duplicateModified(graph(), newBci, rethrowException, true, popKind); } public FrameState duplicateModifiedBeforeCall(int newBci, Kind popKind, ValueNode... pushedValues) { - return duplicateModified(newBci, rethrowException, false, popKind, pushedValues); + return duplicateModified(graph(), newBci, rethrowException, false, popKind, pushedValues); } /** @@ -241,7 +241,7 @@ * followed by a null slot. */ public FrameState duplicateModified(int newBci, boolean newRethrowException, Kind popKind, ValueNode... pushedValues) { - return duplicateModified(newBci, newRethrowException, duringCall, popKind, pushedValues); + return duplicateModified(graph(), newBci, newRethrowException, duringCall, popKind, pushedValues); } /** @@ -250,7 +250,7 @@ */ public FrameState duplicateModified(Kind popKind, ValueNode pushedValue) { assert pushedValue != null && pushedValue.getKind() == popKind; - return duplicateModified(bci, rethrowException, duringCall, popKind, pushedValue); + return duplicateModified(graph(), bci, rethrowException, duringCall, popKind, pushedValue); } /** @@ -259,7 +259,7 @@ * correctly in slot encoding: a long or double will be followed by a null slot. The bci will be * changed to newBci. */ - private FrameState duplicateModified(int newBci, boolean newRethrowException, boolean newDuringCall, Kind popKind, ValueNode... pushedValues) { + public FrameState duplicateModified(StructuredGraph graph, int newBci, boolean newRethrowException, boolean newDuringCall, Kind popKind, ValueNode... pushedValues) { ArrayList copy; if (newRethrowException && !rethrowException && popKind == Kind.Void) { assert popKind == Kind.Void; @@ -285,7 +285,7 @@ copy.addAll(values.subList(localsSize + stackSize, values.size())); assert checkStackDepth(bci, stackSize, duringCall, rethrowException, newBci, newStackSize, newDuringCall, newRethrowException); - return graph().add(new FrameState(outerFrameState(), method, newBci, copy, localsSize, newStackSize, newRethrowException, newDuringCall, monitorIds, virtualObjectMappings)); + return graph.add(new FrameState(outerFrameState(), method, newBci, copy, localsSize, newStackSize, newRethrowException, newDuringCall, monitorIds, virtualObjectMappings)); } /** diff -r dc58f4ca21c9 -r 44d8f20d4f55 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GraphDecoder.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GraphDecoder.java Mon Apr 13 21:50:37 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GraphDecoder.java Mon Apr 13 21:51:19 2015 +0200 @@ -26,6 +26,7 @@ import java.util.*; +import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.common.*; import com.oracle.graal.compiler.common.util.*; import com.oracle.graal.debug.*; @@ -70,48 +71,38 @@ protected static class MethodScope { /** The target graph where decoded nodes are added to. */ public final StructuredGraph graph; - /** The state of the caller method. Only non-null during method inlining. */ - public final MethodScope caller; /** The encode graph that is decoded. */ public final EncodedGraph encodedGraph; /** Access to the encoded graph. */ public final TypeReader reader; - /** - * The "table of contents" of the encoded graph, i.e., the mapping from orderId numbers to - * the offset in the encoded byte[] array. - */ - public final long[] nodeStartOffsets; /** The kind of loop explosion to be performed during decoding. */ public final LoopExplosionKind loopExplosion; - /** - * The start node of the decoded graph. This is a temporary node for inlined graphs that - * needs to be deleted after inlining. - */ - public StartNode startNode; /** All return nodes encountered during decoding. */ public final List returnNodes; /** The exception unwind node encountered during decoding, or null. */ public UnwindNode unwindNode; - protected MethodScope(StructuredGraph graph, MethodScope caller, EncodedGraph encodedGraph, LoopExplosionKind loopExplosion) { + protected MethodScope(StructuredGraph graph, EncodedGraph encodedGraph, LoopExplosionKind loopExplosion) { this.graph = graph; - this.caller = caller; this.encodedGraph = encodedGraph; this.loopExplosion = loopExplosion; this.returnNodes = new ArrayList<>(); - reader = new UnsafeArrayTypeReader(encodedGraph.getEncoding(), encodedGraph.getStartOffset()); - int nodeCount = reader.getUVInt(); - nodeStartOffsets = new long[nodeCount]; - for (int i = 0; i < nodeCount; i++) { - nodeStartOffsets[i] = encodedGraph.getStartOffset() - reader.getUV(); + if (encodedGraph != null) { + reader = new UnsafeArrayTypeReader(encodedGraph.getEncoding(), encodedGraph.getStartOffset()); + if (encodedGraph.nodeStartOffsets == null) { + int nodeCount = reader.getUVInt(); + long[] nodeStartOffsets = new long[nodeCount]; + for (int i = 0; i < nodeCount; i++) { + nodeStartOffsets[i] = encodedGraph.getStartOffset() - reader.getUV(); + } + encodedGraph.nodeStartOffsets = nodeStartOffsets; + } + } else { + reader = null; } } - - public boolean isInlinedMethod() { - return caller != null; - } } /** Decoding state maintained for each loop in the encoded graph. */ @@ -153,7 +144,7 @@ this.iterationStates = null; this.loopBeginOrderId = -1; - int nodeCount = methodScope.nodeStartOffsets.length; + int nodeCount = methodScope.encodedGraph.nodeStartOffsets.length; this.nodesToProcess = new BitSet(nodeCount); this.initialCreatedNodes = new Node[nodeCount]; this.createdNodes = new Node[nodeCount]; @@ -226,22 +217,55 @@ } } + /** + * Additional information encoded for {@link Invoke} nodes to allow method inlining without + * decoding the frame state and successors beforehand. + */ + protected static class InvokeData { + public final Invoke invoke; + public final ResolvedJavaType contextType; + public final int invokeOrderId; + public final int callTargetOrderId; + public final int stateAfterOrderId; + public final int nextOrderId; + + public final int nextNextOrderId; + public final int exceptionOrderId; + public final int exceptionStateOrderId; + public final int exceptionNextOrderId; + + protected InvokeData(Invoke invoke, ResolvedJavaType contextType, int invokeOrderId, int callTargetOrderId, int stateAfterOrderId, int nextOrderId, int nextNextOrderId, int exceptionOrderId, + int exceptionStateOrderId, int exceptionNextOrderId) { + this.invoke = invoke; + this.contextType = contextType; + this.invokeOrderId = invokeOrderId; + this.callTargetOrderId = callTargetOrderId; + this.stateAfterOrderId = stateAfterOrderId; + this.nextOrderId = nextOrderId; + this.nextNextOrderId = nextNextOrderId; + this.exceptionOrderId = exceptionOrderId; + this.exceptionStateOrderId = exceptionStateOrderId; + this.exceptionNextOrderId = exceptionNextOrderId; + } + } + public final void decode(StructuredGraph graph, EncodedGraph encodedGraph) { - MethodScope methodScope = new MethodScope(graph, null, encodedGraph, LoopExplosionKind.NONE); - decode(methodScope); + MethodScope methodScope = new MethodScope(graph, encodedGraph, LoopExplosionKind.NONE); + decode(methodScope, null); cleanupGraph(methodScope); methodScope.graph.verify(); } - protected final void decode(MethodScope methodScope) { + protected final void decode(MethodScope methodScope, FixedWithNextNode startNode) { LoopScope loopScope = new LoopScope(methodScope); - if (methodScope.isInlinedMethod()) { - methodScope.startNode = methodScope.graph.add(new StartNode()); - methodScope.startNode.setNext(makeStubNode(methodScope, loopScope, GraphEncoder.FIRST_NODE_ORDER_ID)); + FixedNode firstNode; + if (startNode != null) { + firstNode = makeStubNode(methodScope, loopScope, GraphEncoder.FIRST_NODE_ORDER_ID); + startNode.setNext(firstNode); loopScope.nodesToProcess.set(GraphEncoder.FIRST_NODE_ORDER_ID); } else { - methodScope.startNode = methodScope.graph.start(); - registerNode(loopScope, GraphEncoder.START_NODE_ORDER_ID, methodScope.startNode, false, false); + firstNode = methodScope.graph.start(); + registerNode(loopScope, GraphEncoder.START_NODE_ORDER_ID, firstNode, false, false); loopScope.nodesToProcess.set(GraphEncoder.START_NODE_ORDER_ID); } @@ -262,7 +286,7 @@ if (methodScope.loopExplosion == LoopExplosionKind.MERGE_EXPLODE) { cleanupGraph(methodScope); Debug.dump(methodScope.graph, "Before loop detection"); - detectLoops(methodScope.graph, methodScope.startNode); + detectLoops(methodScope.graph, firstNode); } } @@ -275,6 +299,18 @@ return loopScope; } + if ((node instanceof MergeNode || (node instanceof LoopBeginNode && (methodScope.loopExplosion == LoopExplosionKind.FULL_UNROLL || methodScope.loopExplosion == LoopExplosionKind.FULL_EXPLODE))) && + ((AbstractMergeNode) node).forwardEndCount() == 1) { + AbstractMergeNode merge = (AbstractMergeNode) node; + EndNode singleEnd = merge.forwardEndAt(0); + FixedNode next = makeStubNode(methodScope, loopScope, nodeOrderId + GraphEncoder.BEGIN_NEXT_ORDER_ID_OFFSET); + singleEnd.replaceAtPredecessor(next); + + merge.safeDelete(); + singleEnd.safeDelete(); + return loopScope; + } + LoopScope successorAddScope = loopScope; boolean updatePredecessors = true; if (node instanceof LoopExitNode) { @@ -282,7 +318,7 @@ updatePredecessors = methodScope.loopExplosion == LoopExplosionKind.NONE; } - methodScope.reader.setByteIndex(methodScope.nodeStartOffsets[nodeOrderId]); + methodScope.reader.setByteIndex(methodScope.encodedGraph.nodeStartOffsets[nodeOrderId]); int typeId = methodScope.reader.getUVInt(); assert node.getNodeClass() == methodScope.encodedGraph.getNodeClasses()[typeId]; readProperties(methodScope, node); @@ -299,7 +335,7 @@ if (methodScope.loopExplosion != LoopExplosionKind.NONE) { handleLoopExplosionProxyNodes(methodScope, loopScope, (LoopExitNode) node, nodeOrderId); } else { - handleProxyNodes(methodScope, loopScope); + handleProxyNodes(methodScope, loopScope, (LoopExitNode) node); } } else if (node instanceof AbstractEndNode) { @@ -311,7 +347,7 @@ phiNodeScope = loopScope.nextIterations.getLast(); } - int mergeOrderId = methodScope.reader.getUVInt(); + int mergeOrderId = readOrderId(methodScope); AbstractMergeNode merge = (AbstractMergeNode) lookupNode(phiNodeScope, mergeOrderId); if (merge == null) { merge = (AbstractMergeNode) makeStubNode(methodScope, phiNodeScope, mergeOrderId); @@ -332,7 +368,8 @@ handlePhiFunctions(methodScope, phiInputScope, phiNodeScope, (AbstractEndNode) node, merge); } else if (node instanceof Invoke) { - simplifyInvoke(methodScope, loopScope, nodeOrderId, (Invoke) node); + InvokeData invokeData = readInvokeData(methodScope, nodeOrderId, (Invoke) node); + handleInvoke(methodScope, loopScope, invokeData); } else if (node instanceof ReturnNode) { methodScope.returnNodes.add((ReturnNode) node); @@ -347,15 +384,45 @@ return resultScope; } + private InvokeData readInvokeData(MethodScope methodScope, int invokeOrderId, Invoke invoke) { + ResolvedJavaType contextType = (ResolvedJavaType) readObject(methodScope); + int callTargetOrderId = readOrderId(methodScope); + int stateAfterOrderId = readOrderId(methodScope); + int nextOrderId = readOrderId(methodScope); + + if (invoke instanceof InvokeWithExceptionNode) { + int nextNextOrderId = readOrderId(methodScope); + int exceptionOrderId = readOrderId(methodScope); + int exceptionStateOrderId = readOrderId(methodScope); + int exceptionNextOrderId = readOrderId(methodScope); + return new InvokeData(invoke, contextType, invokeOrderId, callTargetOrderId, stateAfterOrderId, nextOrderId, nextNextOrderId, exceptionOrderId, exceptionStateOrderId, exceptionNextOrderId); + } else { + return new InvokeData(invoke, contextType, invokeOrderId, callTargetOrderId, stateAfterOrderId, nextOrderId, -1, -1, -1, -1); + } + } + /** - * Hook for subclasses. - * - * @param methodScope The current method. - * @param loopScope The current loop. - * @param invokeOrderId The orderId of the method invocation node. - * @param invoke The invocation node. + * {@link Invoke} nodes do not have the {@link CallTargetNode}, {@link FrameState}, and + * successors encoded. Instead, this information is provided separately to allow method inlining + * without decoding and adding them to the graph upfront. For non-inlined methods, this method + * restores the normal state. Subclasses can override it to perform method inlining. */ - protected void simplifyInvoke(MethodScope methodScope, LoopScope loopScope, int invokeOrderId, Invoke invoke) { + protected void handleInvoke(MethodScope methodScope, LoopScope loopScope, InvokeData invokeData) { + assert invokeData.invoke.callTarget() == null : "callTarget edge is ignored during decoding of Invoke"; + CallTargetNode callTarget = (CallTargetNode) ensureNodeCreated(methodScope, loopScope, invokeData.callTargetOrderId); + if (invokeData.invoke instanceof InvokeWithExceptionNode) { + ((InvokeWithExceptionNode) invokeData.invoke).setCallTarget(callTarget); + } else { + ((InvokeNode) invokeData.invoke).setCallTarget(callTarget); + } + + assert invokeData.invoke.stateAfter() == null && invokeData.invoke.stateDuring() == null : "FrameState edges are ignored during decoding of Invoke"; + invokeData.invoke.setStateAfter((FrameState) ensureNodeCreated(methodScope, loopScope, invokeData.stateAfterOrderId)); + + invokeData.invoke.setNext(makeStubNode(methodScope, loopScope, invokeData.nextOrderId)); + if (invokeData.invoke instanceof InvokeWithExceptionNode) { + ((InvokeWithExceptionNode) invokeData.invoke).setExceptionEdge((AbstractBeginNode) makeStubNode(methodScope, loopScope, invokeData.exceptionOrderId)); + } } protected void handleLoopExplosionBegin(MethodScope methodScope, LoopScope loopScope, LoopBeginNode loopBegin) { @@ -432,10 +499,14 @@ protected void simplifyFixedNode(MethodScope methodScope, LoopScope loopScope, int nodeOrderId, FixedNode node) { } - protected void handleProxyNodes(MethodScope methodScope, LoopScope loopScope) { + protected void handleProxyNodes(MethodScope methodScope, LoopScope loopScope, LoopExitNode loopExit) { + assert loopExit.stateAfter() == null; + int stateAfterOrderId = readOrderId(methodScope); + loopExit.setStateAfter((FrameState) ensureNodeCreated(methodScope, loopScope, stateAfterOrderId)); + int numProxies = methodScope.reader.getUVInt(); for (int i = 0; i < numProxies; i++) { - int proxyOrderId = methodScope.reader.getUVInt(); + int proxyOrderId = readOrderId(methodScope); ProxyNode proxy = (ProxyNode) ensureNodeCreated(methodScope, loopScope, proxyOrderId); /* * The ProxyNode transports a value from the loop to the outer scope. We therefore @@ -446,9 +517,11 @@ } protected void handleLoopExplosionProxyNodes(MethodScope methodScope, LoopScope loopScope, LoopExitNode loopExit, int loopExitOrderId) { + assert loopExit.stateAfter() == null; + int stateAfterOrderId = readOrderId(methodScope); + BeginNode begin = methodScope.graph.add(new BeginNode()); - FrameState loopExitState = loopExit.stateAfter(); FixedNode loopExitSuccessor = loopExit.next(); loopExit.replaceAtPredecessor(begin); @@ -457,33 +530,43 @@ * iterations now take the same loop exit, so we have to introduce a new merge node to * handle the merge. */ - MergeNode merge; - if (lookupNode(loopScope.outer, loopExitOrderId) == null) { + MergeNode merge = null; + Node existingExit = lookupNode(loopScope.outer, loopExitOrderId); + if (existingExit == null) { + /* First loop iteration that exits. No merge necessary yet. */ + registerNode(loopScope.outer, loopExitOrderId, begin, false, false); + begin.setNext(loopExitSuccessor); + + } else if (existingExit instanceof BeginNode) { + /* Second loop iteration that exits. Create the merge. */ merge = methodScope.graph.add(new MergeNode()); - registerNode(loopScope.outer, loopExitOrderId, merge, false, false); + registerNode(loopScope.outer, loopExitOrderId, merge, true, false); + /* Add the first iteration. */ + EndNode firstEnd = methodScope.graph.add(new EndNode()); + ((BeginNode) existingExit).setNext(firstEnd); + merge.addForwardEnd(firstEnd); merge.setNext(loopExitSuccessor); + } else { - merge = (MergeNode) loopScope.outer.createdNodes[loopExitOrderId]; + /* Subsequent loop iteration. Merge already created. */ + merge = (MergeNode) existingExit; } - FrameState oldStateAfter = merge.stateAfter(); - merge.setStateAfter(loopExitState); - if (oldStateAfter != null) { - oldStateAfter.safeDelete(); + if (merge != null) { + EndNode end = methodScope.graph.add(new EndNode()); + begin.setNext(end); + merge.addForwardEnd(end); } - EndNode end = methodScope.graph.add(new EndNode()); - begin.setNext(end); - merge.addForwardEnd(end); - /* * Possibly create phi nodes for the original proxy nodes that flow out of the loop. Note * that we definitely do not need a proxy node itself anymore, since the loop was exploded * and is no longer present. */ int numProxies = methodScope.reader.getUVInt(); + boolean phiCreated = false; for (int i = 0; i < numProxies; i++) { - int proxyOrderId = methodScope.reader.getUVInt(); + int proxyOrderId = readOrderId(methodScope); ProxyNode proxy = (ProxyNode) ensureNodeCreated(methodScope, loopScope, proxyOrderId); ValueNode phiInput = proxy.value(); ValueNode replacement; @@ -508,6 +591,7 @@ phi.addInput(phiInput); registerNode(loopScope.outer, proxyOrderId, phi, true, false); replacement = phi; + phiCreated = true; } else { /* Phi node has been created before, so just add the new input. */ @@ -519,9 +603,22 @@ methodScope.graph.replaceFloating(proxy, replacement); } + if (merge != null && (merge.stateAfter() == null || phiCreated)) { + FrameState oldStateAfter = merge.stateAfter(); + registerNode(loopScope.outer, stateAfterOrderId, null, true, true); + merge.setStateAfter((FrameState) ensureNodeCreated(methodScope, loopScope.outer, stateAfterOrderId)); + if (oldStateAfter != null) { + oldStateAfter.safeDelete(); + } + } + loopExit.safeDelete(); assert loopExitSuccessor.predecessor() == null; - merge.getNodeClass().getSuccessorEdges().update(merge, null, loopExitSuccessor); + if (merge != null) { + merge.getNodeClass().getSuccessorEdges().update(merge, null, loopExitSuccessor); + } else { + begin.getNodeClass().getSuccessorEdges().update(begin, null, loopExitSuccessor); + } } protected void handlePhiFunctions(MethodScope methodScope, LoopScope phiInputScope, LoopScope phiNodeScope, AbstractEndNode end, AbstractMergeNode merge) { @@ -555,8 +652,8 @@ boolean lazyPhi = !(merge instanceof LoopBeginNode) || methodScope.loopExplosion != LoopExplosionKind.NONE; int numPhis = methodScope.reader.getUVInt(); for (int i = 0; i < numPhis; i++) { - int phiInputOrderId = methodScope.reader.getUVInt(); - int phiNodeOrderId = methodScope.reader.getUVInt(); + int phiInputOrderId = readOrderId(methodScope); + int phiNodeOrderId = readOrderId(methodScope); ValueNode phiInput = (ValueNode) ensureNodeCreated(methodScope, phiInputScope, phiInputOrderId); @@ -588,7 +685,7 @@ } protected Node instantiateNode(MethodScope methodScope, int nodeOrderId) { - methodScope.reader.setByteIndex(methodScope.nodeStartOffsets[nodeOrderId]); + methodScope.reader.setByteIndex(methodScope.encodedGraph.nodeStartOffsets[nodeOrderId]); NodeClass nodeClass = methodScope.encodedGraph.getNodeClasses()[methodScope.reader.getUVInt()]; return nodeClass.allocateInstance(); } @@ -600,8 +697,7 @@ long primitive = methodScope.reader.getSV(); fields.setRawPrimitive(node, pos, primitive); } else { - int objectId = methodScope.reader.getUVInt(); - Object value = methodScope.encodedGraph.getObjects()[objectId]; + Object value = readObject(methodScope); fields.set(node, pos, value); } } @@ -619,7 +715,7 @@ if (skipEdge(node, edges, index, true, true)) { continue; } - int orderId = methodScope.reader.getUVInt(); + int orderId = readOrderId(methodScope); Node value = ensureNodeCreated(methodScope, loopScope, orderId); Edges.initializeNode(node, edges.getOffsets(), index, value); if (updateUsages && value != null && !value.isDeleted()) { @@ -636,7 +732,7 @@ NodeList nodeList = new NodeInputList<>(node, size); Edges.initializeList(node, edges.getOffsets(), index, nodeList); for (int idx = 0; idx < size; idx++) { - int orderId = methodScope.reader.getUVInt(); + int orderId = readOrderId(methodScope); Node value = ensureNodeCreated(methodScope, loopScope, orderId); nodeList.initialize(idx, value); if (updateUsages && value != null && !value.isDeleted()) { @@ -656,17 +752,7 @@ return node; } - long readerByteIndex = methodScope.reader.getByteIndex(); - node = instantiateNode(methodScope, nodeOrderId); - assert !(node instanceof FixedNode); - - /* Read the properties of the node. */ - readProperties(methodScope, node); - /* There must not be any successors to read, since it is a non-fixed node. */ - assert node.getNodeClass().getEdges(Edges.Type.Successors).getCount() == 0; - /* Read the inputs of the node, possibly creating them recursively. */ - makeInputNodes(methodScope, loopScope, node, false); - methodScope.reader.setByteIndex(readerByteIndex); + node = decodeFloatingNode(methodScope, loopScope, nodeOrderId); if (node instanceof ProxyNode || node instanceof PhiNode) { /* @@ -688,6 +774,24 @@ } /** + * Decodes a non-fixed node, but does not do any post-processing and does not register it. + */ + protected Node decodeFloatingNode(MethodScope methodScope, LoopScope loopScope, int nodeOrderId) { + long readerByteIndex = methodScope.reader.getByteIndex(); + Node node = instantiateNode(methodScope, nodeOrderId); + assert !(node instanceof FixedNode); + + /* Read the properties of the node. */ + readProperties(methodScope, node); + /* There must not be any successors to read, since it is a non-fixed node. */ + assert node.getNodeClass().getEdges(Edges.Type.Successors).getCount() == 0; + /* Read the inputs of the node, possibly creating them recursively. */ + makeInputNodes(methodScope, loopScope, node, false); + methodScope.reader.setByteIndex(readerByteIndex); + return node; + } + + /** * Hook for subclasses to process a non-fixed node before it is added to the graph. * * @param methodScope The current method. @@ -722,7 +826,7 @@ if (skipEdge(node, edges, index, true, true)) { continue; } - int orderId = methodScope.reader.getUVInt(); + int orderId = readOrderId(methodScope); Node value = makeStubNode(methodScope, loopScope, orderId); Edges.initializeNode(node, edges.getOffsets(), index, value); if (updatePredecessors && value != null) { @@ -738,7 +842,7 @@ NodeList nodeList = new NodeSuccessorList<>(node, size); Edges.initializeList(node, edges.getOffsets(), index, nodeList); for (int idx = 0; idx < size; idx++) { - int orderId = methodScope.reader.getUVInt(); + int orderId = readOrderId(methodScope); Node value = makeStubNode(methodScope, loopScope, orderId); nodeList.initialize(idx, value); if (updatePredecessors && value != null) { @@ -792,6 +896,26 @@ assert index == edges.getCount() - 1 : "MergeNode has one variable size input (the ends)"; assert Edges.getNodeList(node, edges.getOffsets(), index) != null : "Input list must have been already created"; return true; + + } else if (node instanceof LoopExitNode && edges.type() == Edges.Type.Inputs && edges.getType(index) == FrameState.class) { + /* The stateAfter of the loop exit is filled manually. */ + return true; + + } else if (node instanceof Invoke) { + assert node instanceof InvokeNode || node instanceof InvokeWithExceptionNode : "The only two Invoke node classes"; + assert direct : "Invoke and InvokeWithException only have direct successor and input edges"; + if (edges.type() == Edges.Type.Successors) { + assert edges.getCount() == (node instanceof InvokeWithExceptionNode ? 2 : 1) : "InvokeNode has one successor (next); InvokeWithExceptionNode has two successors (next, exceptionEdge)"; + return true; + } else { + assert edges.type() == Edges.Type.Inputs; + if (edges.getType(index) == CallTargetNode.class) { + return true; + } else if (edges.getType(index) == FrameState.class) { + assert edges.get(node, index) == null || edges.get(node, index) == ((Invoke) node).stateAfter() : "Only stateAfter can be a FrameState during encoding"; + return true; + } + } } return false; } @@ -807,6 +931,14 @@ loopScope.createdNodes[nodeOrderId] = node; } + protected int readOrderId(MethodScope methodScope) { + return methodScope.reader.getUVInt(); + } + + protected Object readObject(MethodScope methodScope) { + return methodScope.encodedGraph.getObjects()[methodScope.reader.getUVInt()]; + } + /* * The following methods are a literal copy from GraphBuilderPhase. */ diff -r dc58f4ca21c9 -r 44d8f20d4f55 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GraphEncoder.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GraphEncoder.java Mon Apr 13 21:50:37 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GraphEncoder.java Mon Apr 13 21:51:19 2015 +0200 @@ -29,6 +29,7 @@ import com.oracle.graal.graph.*; import com.oracle.graal.graph.iterators.*; import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions; +import com.oracle.graal.nodes.java.*; /** * Encodes a {@link StructuredGraph} to a compact byte[] array. All nodes of the graph and edges @@ -100,6 +101,12 @@ public static final int FIRST_NODE_ORDER_ID = 2; /** + * The known offset between the orderId of a {@link AbstractBeginNode} and its + * {@link AbstractBeginNode#next() successor}. + */ + protected static final int BEGIN_NEXT_ORDER_ID_OFFSET = 1; + + /** * Collects all non-primitive data referenced from nodes. The encoding uses an index into an * array for decoding. Because of the variable-length encoding, it is beneficial that frequently * used objects have the small indices. @@ -148,6 +155,9 @@ objects.addObject(nodeClass.getData().get(node, i)); } } + if (node instanceof Invoke) { + objects.addObject(((Invoke) node).getContextType()); + } } } @@ -182,7 +192,10 @@ long[] nodeStartOffsets = new long[nodeCount]; for (Map.Entry entry : nodeOrder.orderIds.entries()) { Node node = entry.getKey(); - nodeStartOffsets[entry.getValue()] = writer.getBytesWritten(); + Integer orderId = entry.getValue(); + + assert !(node instanceof AbstractBeginNode) || nodeOrder.orderIds.get(((AbstractBeginNode) node).next()) == orderId + BEGIN_NEXT_ORDER_ID_OFFSET; + nodeStartOffsets[orderId] = writer.getBytesWritten(); /* Write out the type, properties, and edges. */ NodeClass nodeClass = node.getNodeClass(); @@ -213,11 +226,30 @@ } else if (node instanceof LoopExitNode) { LoopExitNode exit = (LoopExitNode) node; + writeOrderId(exit.stateAfter(), nodeOrder); /* Write all proxy nodes of the LoopExitNode. */ writer.putUV(exit.proxies().count()); for (ProxyNode proxy : exit.proxies()) { writeOrderId(proxy, nodeOrder); } + + } else if (node instanceof Invoke) { + Invoke invoke = (Invoke) node; + assert invoke.stateDuring() == null : "stateDuring is not used in high-level graphs"; + + writeObjectId(invoke.getContextType()); + writeOrderId(invoke.callTarget(), nodeOrder); + writeOrderId(invoke.stateAfter(), nodeOrder); + writeOrderId(invoke.next(), nodeOrder); + if (invoke instanceof InvokeWithExceptionNode) { + InvokeWithExceptionNode invokeWithExcpetion = (InvokeWithExceptionNode) invoke; + ExceptionObjectNode exceptionEdge = (ExceptionObjectNode) invokeWithExcpetion.exceptionEdge(); + + writeOrderId(invokeWithExcpetion.next().next(), nodeOrder); + writeOrderId(invokeWithExcpetion.exceptionEdge(), nodeOrder); + writeOrderId(exceptionEdge.stateAfter(), nodeOrder); + writeOrderId(exceptionEdge.next(), nodeOrder); + } } } @@ -252,13 +284,8 @@ FixedNode current = graph.start(); do { add(current); - if (current instanceof InvokeWithExceptionNode) { - /* - * Special handling for invokes: the orderID of the invocation, the regular - * successor, and the exception edge must be consecutive. - */ - add(((InvokeWithExceptionNode) current).next()); - add(((InvokeWithExceptionNode) current).exceptionEdge()); + if (current instanceof AbstractBeginNode) { + add(((AbstractBeginNode) current).next()); } if (current instanceof FixedWithNextNode) { @@ -308,7 +335,7 @@ writer.putSV(primitive); } else { Object property = fields.get(node, idx); - writer.putUV(objects.getIndex(property)); + writeObjectId(property); } } } @@ -343,6 +370,10 @@ writer.putUV(node == null ? NULL_ORDER_ID : nodeOrder.orderIds.get(node)); } + protected void writeObjectId(Object object) { + writer.putUV(objects.getIndex(object)); + } + /** * Verification code that checks that the decoding of an encode graph is the same as the * original graph. @@ -365,7 +396,7 @@ pushToWorklist(expectedGraph.start(), actualGraph.start(), nodeMapping, workList); while (!workList.isEmpty()) { - Pair pair = workList.pop(); + Pair pair = workList.removeFirst(); Node expectedNode = pair.first; Node actualNode = pair.second; assert expectedNode.getClass() == actualNode.getClass(); @@ -377,7 +408,7 @@ /* The order of the ends can be different, so ignore them. */ verifyNodesEqual(expectedNode.inputs(), actualNode.inputs(), nodeMapping, workList, true); } else if (expectedNode instanceof PhiNode) { - /* The order of phi inputs can be different, so they are checked manually below. */ + verifyPhi((PhiNode) expectedNode, (PhiNode) actualNode, nodeMapping, workList); } else { verifyNodesEqual(expectedNode.inputs(), actualNode.inputs(), nodeMapping, workList, false); } @@ -413,20 +444,34 @@ return true; } + protected static void verifyPhi(PhiNode expectedPhi, PhiNode actualPhi, NodeMap nodeMapping, Deque> workList) { + AbstractMergeNode expectedMergeNode = expectedPhi.merge(); + AbstractMergeNode actualMergeNode = actualPhi.merge(); + assert actualMergeNode == nodeMapping.get(expectedMergeNode); + + for (EndNode expectedEndNode : expectedMergeNode.ends) { + EndNode actualEndNode = (EndNode) nodeMapping.get(expectedEndNode); + if (actualEndNode != null) { + ValueNode expectedPhiInput = expectedPhi.valueAt(expectedEndNode); + ValueNode actualPhiInput = actualPhi.valueAt(actualEndNode); + verifyNodeEqual(expectedPhiInput, actualPhiInput, nodeMapping, workList, false); + } + } + } + protected static void verifyPhis(AbstractEndNode expectedEndNode, AbstractEndNode actualEndNode, NodeMap nodeMapping, Deque> workList) { AbstractMergeNode expectedMergeNode = expectedEndNode.merge(); AbstractMergeNode actualMergeNode = (AbstractMergeNode) nodeMapping.get(expectedMergeNode); - - Iterator actualPhis = actualMergeNode.phis().iterator(); - for (PhiNode expectedPhi : expectedMergeNode.phis()) { - PhiNode actualPhi = actualPhis.next(); - verifyNodeEqual(expectedPhi, actualPhi, nodeMapping, workList, false); + assert actualMergeNode != null; - ValueNode expectedPhiInput = expectedPhi.valueAt(expectedEndNode); - ValueNode actualPhiInput = actualPhi.valueAt(actualEndNode); - verifyNodeEqual(expectedPhiInput, actualPhiInput, nodeMapping, workList, false); + for (PhiNode expectedPhi : expectedMergeNode.phis()) { + PhiNode actualPhi = (PhiNode) nodeMapping.get(expectedPhi); + if (actualPhi != null) { + ValueNode expectedPhiInput = expectedPhi.valueAt(expectedEndNode); + ValueNode actualPhiInput = actualPhi.valueAt(actualEndNode); + verifyNodeEqual(expectedPhiInput, actualPhiInput, nodeMapping, workList, false); + } } - assert !actualPhis.hasNext(); } private static void verifyNodesEqual(NodeIterable expectedNodes, NodeIterable actualNodes, NodeMap nodeMapping, Deque> workList, boolean ignoreEndNode) { @@ -453,7 +498,12 @@ protected static void pushToWorklist(Node expectedNode, Node actualNode, NodeMap nodeMapping, Deque> workList) { nodeMapping.set(expectedNode, actualNode); - workList.push(new Pair<>(expectedNode, actualNode)); + if (expectedNode instanceof AbstractEndNode) { + /* To ensure phi nodes have been added, we handle everything before block ends. */ + workList.addLast(new Pair<>(expectedNode, actualNode)); + } else { + workList.addFirst(new Pair<>(expectedNode, actualNode)); + } } } diff -r dc58f4ca21c9 -r 44d8f20d4f55 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardingPiNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardingPiNode.java Mon Apr 13 21:50:37 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardingPiNode.java Mon Apr 13 21:51:19 2015 +0200 @@ -107,7 +107,7 @@ @Override public Node canonical(CanonicalizerTool tool) { - if (stamp() == StampFactory.illegal(object.getKind())) { + if (stamp().isIllegal()) { // The guard always fails return new DeoptimizeNode(action, reason); } diff -r dc58f4ca21c9 -r 44d8f20d4f55 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java Mon Apr 13 21:50:37 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java Mon Apr 13 21:51:19 2015 +0200 @@ -140,6 +140,15 @@ return super.verify(); } + public void eliminateNegation() { + AbstractBeginNode oldTrueSuccessor = trueSuccessor; + AbstractBeginNode oldFalseSuccessor = falseSuccessor; + trueSuccessor = oldFalseSuccessor; + falseSuccessor = oldTrueSuccessor; + trueSuccessorProbability = 1 - trueSuccessorProbability; + setCondition(((LogicNegationNode) condition).getValue()); + } + @Override public void simplify(SimplifierTool tool) { if (trueSuccessor().next() instanceof DeoptimizeNode) { @@ -155,15 +164,7 @@ } if (condition() instanceof LogicNegationNode) { - AbstractBeginNode trueSucc = trueSuccessor(); - AbstractBeginNode falseSucc = falseSuccessor(); - setTrueSuccessor(null); - setFalseSuccessor(null); - LogicNegationNode negation = (LogicNegationNode) condition(); - IfNode newIfNode = graph().add(new IfNode(negation.getValue(), falseSucc, trueSucc, 1 - trueSuccessorProbability)); - predecessor().replaceFirstSuccessor(this, newIfNode); - GraphUtil.killWithUnusedFloatingInputs(this); - return; + eliminateNegation(); } if (condition() instanceof LogicConstantNode) { LogicConstantNode c = (LogicConstantNode) condition(); diff -r dc58f4ca21c9 -r 44d8f20d4f55 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java Mon Apr 13 21:50:37 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java Mon Apr 13 21:51:19 2015 +0200 @@ -64,6 +64,11 @@ return callTarget; } + void setCallTarget(CallTargetNode callTarget) { + updateUsages(this.callTarget, callTarget); + this.callTarget = callTarget; + } + @Override public boolean isPolymorphic() { return polymorphic; diff -r dc58f4ca21c9 -r 44d8f20d4f55 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java Mon Apr 13 21:50:37 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java Mon Apr 13 21:51:19 2015 +0200 @@ -81,6 +81,11 @@ return callTarget; } + void setCallTarget(CallTargetNode callTarget) { + updateUsages(this.callTarget, callTarget); + this.callTarget = callTarget; + } + public MethodCallTargetNode methodCallTarget() { return (MethodCallTargetNode) callTarget; } diff -r dc58f4ca21c9 -r 44d8f20d4f55 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatConvertNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatConvertNode.java Mon Apr 13 21:50:37 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatConvertNode.java Mon Apr 13 21:51:19 2015 +0200 @@ -22,6 +22,8 @@ */ package com.oracle.graal.nodes.calc; +import java.util.*; + import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.common.calc.*; import com.oracle.graal.compiler.common.type.*; @@ -43,8 +45,16 @@ protected final FloatConvert op; + private static final EnumMap> getOps; + static { + getOps = new EnumMap<>(FloatConvert.class); + for (FloatConvert op : FloatConvert.values()) { + getOps.put(op, table -> table.getFloatConvert(op)); + } + } + public FloatConvertNode(FloatConvert op, ValueNode input) { - super(TYPE, table -> table.getFloatConvert(op), input); + super(TYPE, getOps.get(op), input); this.op = op; } diff -r dc58f4ca21c9 -r 44d8f20d4f55 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 Mon Apr 13 21:50:37 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java Mon Apr 13 21:51:19 2015 +0200 @@ -116,7 +116,7 @@ Stamp newStamp = StampFactory.declaredTrusted(type).improveWith(object().stamp()); ValueNode condition; ValueNode theValue = object; - if (newStamp instanceof IllegalStamp) { + if (newStamp.isIllegal()) { // This is a check cast that will always fail condition = LogicConstantNode.contradiction(graph()); newStamp = StampFactory.declaredTrusted(type); diff -r dc58f4ca21c9 -r 44d8f20d4f55 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java Mon Apr 13 21:50:37 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java Mon Apr 13 21:51:19 2015 +0200 @@ -150,11 +150,11 @@ public static void killWithUnusedFloatingInputs(Node node) { node.safeDelete(); - for (Node in : node.inputs()) { + node.acceptInputs((n, in) -> { if (in.isAlive() && in.hasNoUsages() && !(in instanceof FixedNode)) { killWithUnusedFloatingInputs(in); } - } + }); } public static void removeFixedWithUnusedInputs(FixedWithNextNode fixed) { diff -r dc58f4ca21c9 -r 44d8f20d4f55 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java Mon Apr 13 21:50:37 2015 +0200 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java Mon Apr 13 21:51:19 2015 +0200 @@ -306,7 +306,7 @@ if (callerLockDepth != 0) { for (MonitorIdNode original : inlineGraph.getNodes(MonitorIdNode.TYPE)) { MonitorIdNode monitor = (MonitorIdNode) duplicates.get(original); - processMonitorId(invoke, monitor); + processMonitorId(invoke.stateAfter(), monitor); } } } else { @@ -432,8 +432,7 @@ return pos; } - public static void processMonitorId(Invoke invoke, MonitorIdNode monitorIdNode) { - FrameState stateAfter = invoke.stateAfter(); + public static void processMonitorId(FrameState stateAfter, MonitorIdNode monitorIdNode) { if (stateAfter != null) { int callerLockDepth = stateAfter.nestedLockDepth(); monitorIdNode.setLockDepth(monitorIdNode.getLockDepth() + callerLockDepth); @@ -579,26 +578,43 @@ } public static ValueNode mergeReturns(AbstractMergeNode merge, List returnNodes, List canonicalizedNodes) { + ValueNode singleReturnValue = null; PhiNode returnValuePhi = null; - for (ReturnNode returnNode : returnNodes) { - // create and wire up a new EndNode - EndNode endNode = merge.graph().add(new EndNode()); - merge.addForwardEnd(endNode); + if (returnNode.result() != null) { + if (returnValuePhi == null && (singleReturnValue == null || singleReturnValue == returnNode.result())) { + /* Only one return value, so no need yet for a phi node. */ + singleReturnValue = returnNode.result(); - if (returnNode.result() != null) { - if (returnValuePhi == null) { + } else if (returnValuePhi == null) { + /* Found a second return value, so create phi node. */ returnValuePhi = merge.graph().addWithoutUnique(new ValuePhiNode(returnNode.result().stamp().unrestricted(), merge)); if (canonicalizedNodes != null) { canonicalizedNodes.add(returnValuePhi); } + for (int i = 0; i < merge.forwardEndCount(); i++) { + returnValuePhi.addInput(singleReturnValue); + } + returnValuePhi.addInput(returnNode.result()); + + } else { + /* Multiple return values, just add to existing phi node. */ + returnValuePhi.addInput(returnNode.result()); } - returnValuePhi.addInput(returnNode.result()); } + + // create and wire up a new EndNode + EndNode endNode = merge.graph().add(new EndNode()); + merge.addForwardEnd(endNode); returnNode.replaceAndDelete(endNode); - } - return returnValuePhi; + + if (returnValuePhi != null) { + assert returnValuePhi.verify(); + return returnValuePhi; + } else { + return singleReturnValue; + } } private static boolean checkContainsOnlyInvalidOrAfterFrameState(Map duplicates) { diff -r dc58f4ca21c9 -r 44d8f20d4f55 graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/InferStamps.java --- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/InferStamps.java Mon Apr 13 21:50:37 2015 +0200 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/InferStamps.java Mon Apr 13 21:51:19 2015 +0200 @@ -88,7 +88,7 @@ for (Node n : graph.getNodes()) { if (n instanceof ValuePhiNode) { ValueNode node = (ValueNode) n; - assert !(node.stamp() instanceof IllegalStamp) : "Stamp is illegal after analysis. This is not necessarily an error, but a condition that we want to investigate (and then maybe relax or remove the assertion)."; + assert node.stamp().isLegal() : "Stamp is illegal after analysis. This is not necessarily an error, but a condition that we want to investigate (and then maybe relax or remove the assertion)."; } } return true; diff -r dc58f4ca21c9 -r 44d8f20d4f55 graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/InstrumentationPartialEvaluationTest.java --- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/InstrumentationPartialEvaluationTest.java Mon Apr 13 21:50:37 2015 +0200 +++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/InstrumentationPartialEvaluationTest.java Mon Apr 13 21:51:19 2015 +0200 @@ -67,7 +67,7 @@ RootTestNode root = new RootTestNode(fd, "constantValue", result); root.adoptChildren(); Probe probe = result.probe(); - Instrument instrument = Instrument.create(new DefaultInstrumentListener(), "Null test Instrument"); + Instrument instrument = Instrument.create(new DefaultSimpleInstrumentListener(), "Null test Instrument"); probe.attach(instrument); assertPartialEvalEquals("constant42", root); } @@ -79,7 +79,7 @@ RootTestNode root = new RootTestNode(fd, "constantValue", result); root.adoptChildren(); Probe probe = result.probe(); - Instrument instrument = Instrument.create(new DefaultASTInstrumentListener(), "Null test Instrument"); + Instrument instrument = Instrument.create(new DefaultStandardInstrumentListener(), "Null test Instrument"); probe.attach(instrument); assertPartialEvalEquals("constant42", root); } @@ -91,7 +91,7 @@ RootTestNode root = new RootTestNode(fd, "constantValue", result); root.adoptChildren(); Probe probe = result.probe(); - Instrument instrument = Instrument.create(new DefaultInstrumentListener(), "Null test Instrument"); + Instrument instrument = Instrument.create(new DefaultSimpleInstrumentListener(), "Null test Instrument"); probe.attach(instrument); instrument.dispose(); assertPartialEvalEquals("constant42", root); @@ -104,7 +104,7 @@ RootTestNode root = new RootTestNode(fd, "constantValue", result); root.adoptChildren(); Probe probe = result.probe(); - Instrument instrument = Instrument.create(new DefaultASTInstrumentListener(), "Null test Instrument"); + Instrument instrument = Instrument.create(new DefaultStandardInstrumentListener(), "Null test Instrument"); probe.attach(instrument); instrument.dispose(); assertPartialEvalEquals("constant42", root); @@ -117,9 +117,9 @@ RootTestNode root = new RootTestNode(fd, "constantValue", result); root.adoptChildren(); Probe probe = result.probe(); - Instrument instrument1 = Instrument.create(new DefaultInstrumentListener(), "Null test Instrument 1"); + Instrument instrument1 = Instrument.create(new DefaultSimpleInstrumentListener(), "Null test Instrument 1"); probe.attach(instrument1); - Instrument instrument2 = Instrument.create(new DefaultInstrumentListener(), "Null test Instrument 2"); + Instrument instrument2 = Instrument.create(new DefaultSimpleInstrumentListener(), "Null test Instrument 2"); probe.attach(instrument2); assertPartialEvalEquals("constant42", root); } @@ -131,9 +131,9 @@ RootTestNode root = new RootTestNode(fd, "constantValue", result); root.adoptChildren(); Probe probe = result.probe(); - Instrument instrument1 = Instrument.create(new DefaultASTInstrumentListener(), "Null test Instrument 1"); + Instrument instrument1 = Instrument.create(new DefaultStandardInstrumentListener(), "Null test Instrument 1"); probe.attach(instrument1); - Instrument instrument2 = Instrument.create(new DefaultASTInstrumentListener(), "Null test Instrument 2"); + Instrument instrument2 = Instrument.create(new DefaultStandardInstrumentListener(), "Null test Instrument 2"); probe.attach(instrument2); assertPartialEvalEquals("constant42", root); } @@ -145,11 +145,11 @@ RootTestNode root = new RootTestNode(fd, "constantValue", result); root.adoptChildren(); Probe probe = result.probe(); - Instrument instrument1 = Instrument.create(new DefaultInstrumentListener(), "Null test Instrument 1"); + Instrument instrument1 = Instrument.create(new DefaultSimpleInstrumentListener(), "Null test Instrument 1"); probe.attach(instrument1); - Instrument instrument2 = Instrument.create(new DefaultInstrumentListener(), "Null test Instrument 2"); + Instrument instrument2 = Instrument.create(new DefaultSimpleInstrumentListener(), "Null test Instrument 2"); probe.attach(instrument2); - Instrument instrument3 = Instrument.create(new DefaultInstrumentListener(), "Null test Instrument 3"); + Instrument instrument3 = Instrument.create(new DefaultSimpleInstrumentListener(), "Null test Instrument 3"); probe.attach(instrument3); assertPartialEvalEquals("constant42", root); } @@ -161,11 +161,11 @@ RootTestNode root = new RootTestNode(fd, "constantValue", result); root.adoptChildren(); Probe probe = result.probe(); - Instrument instrument1 = Instrument.create(new DefaultASTInstrumentListener(), "Null test Instrument 1"); + Instrument instrument1 = Instrument.create(new DefaultStandardInstrumentListener(), "Null test Instrument 1"); probe.attach(instrument1); - Instrument instrument2 = Instrument.create(new DefaultASTInstrumentListener(), "Null test Instrument 2"); + Instrument instrument2 = Instrument.create(new DefaultStandardInstrumentListener(), "Null test Instrument 2"); probe.attach(instrument2); - Instrument instrument3 = Instrument.create(new DefaultASTInstrumentListener(), "Null test Instrument 3"); + Instrument instrument3 = Instrument.create(new DefaultStandardInstrumentListener(), "Null test Instrument 3"); probe.attach(instrument3); assertPartialEvalEquals("constant42", root); } @@ -177,11 +177,11 @@ RootTestNode root = new RootTestNode(fd, "constantValue", result); root.adoptChildren(); Probe probe = result.probe(); - Instrument instrument1 = Instrument.create(new DefaultInstrumentListener(), "Null test Instrument 1"); + Instrument instrument1 = Instrument.create(new DefaultSimpleInstrumentListener(), "Null test Instrument 1"); probe.attach(instrument1); - Instrument instrument2 = Instrument.create(new DefaultInstrumentListener(), "Null test Instrument 2"); + Instrument instrument2 = Instrument.create(new DefaultSimpleInstrumentListener(), "Null test Instrument 2"); probe.attach(instrument2); - Instrument instrument3 = Instrument.create(new DefaultInstrumentListener(), "Null test Instrument 3"); + Instrument instrument3 = Instrument.create(new DefaultSimpleInstrumentListener(), "Null test Instrument 3"); probe.attach(instrument3); instrument2.dispose(); assertPartialEvalEquals("constant42", root); @@ -194,11 +194,11 @@ RootTestNode root = new RootTestNode(fd, "constantValue", result); root.adoptChildren(); Probe probe = result.probe(); - Instrument instrument1 = Instrument.create(new DefaultASTInstrumentListener(), "Null test Instrument 1"); + Instrument instrument1 = Instrument.create(new DefaultStandardInstrumentListener(), "Null test Instrument 1"); probe.attach(instrument1); - Instrument instrument2 = Instrument.create(new DefaultASTInstrumentListener(), "Null test Instrument 2"); + Instrument instrument2 = Instrument.create(new DefaultStandardInstrumentListener(), "Null test Instrument 2"); probe.attach(instrument2); - Instrument instrument3 = Instrument.create(new DefaultASTInstrumentListener(), "Null test Instrument 3"); + Instrument instrument3 = Instrument.create(new DefaultStandardInstrumentListener(), "Null test Instrument 3"); probe.attach(instrument3); instrument2.dispose(); assertPartialEvalEquals("constant42", root); @@ -280,7 +280,7 @@ Assert.assertEquals(0, count[0]); // Didn't count anything // Add a counting instrument; this changes the "Probe state" and should cause a deopt - final Instrument countingInstrument = Instrument.create(new DefaultInstrumentListener() { + final Instrument countingInstrument = Instrument.create(new DefaultSimpleInstrumentListener() { @Override public void enter(Probe p) { diff -r dc58f4ca21c9 -r 44d8f20d4f55 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PEGraphDecoder.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PEGraphDecoder.java Mon Apr 13 21:50:37 2015 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PEGraphDecoder.java Mon Apr 13 21:51:19 2015 +0200 @@ -29,13 +29,14 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; -import com.oracle.graal.debug.*; +import com.oracle.graal.compiler.common.type.*; import com.oracle.graal.graph.*; import com.oracle.graal.graph.spi.*; import com.oracle.graal.graphbuilderconf.*; import com.oracle.graal.graphbuilderconf.InlineInvokePlugin.InlineInfo; import com.oracle.graal.graphbuilderconf.InvocationPlugins.InvocationPluginReceiver; import com.oracle.graal.java.*; +import com.oracle.graal.nodeinfo.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.CallTargetNode.InvokeKind; import com.oracle.graal.nodes.extended.*; @@ -63,8 +64,11 @@ protected final StampProvider stampProvider; protected class PEMethodScope extends MethodScope { + /** The state of the caller method. Only non-null during method inlining. */ + protected final PEMethodScope caller; + protected final LoopScope callerLoopScope; protected final ResolvedJavaMethod method; - protected final Invoke invoke; + protected final InvokeData invokeData; protected final int inliningDepth; protected final LoopExplosionPlugin loopExplosionPlugin; @@ -73,15 +77,20 @@ protected final ParameterPlugin parameterPlugin; protected final ValueNode[] arguments; - protected FrameState outerFrameState; + protected FrameState outerState; + protected FrameState exceptionState; + protected ExceptionPlaceholderNode exceptionPlaceholderNode; protected BytecodePosition bytecodePosition; - protected PEMethodScope(StructuredGraph targetGraph, MethodScope caller, EncodedGraph encodedGraph, ResolvedJavaMethod method, Invoke invoke, int inliningDepth, - LoopExplosionPlugin loopExplosionPlugin, InvocationPlugins invocationPlugins, InlineInvokePlugin inlineInvokePlugin, ParameterPlugin parameterPlugin, ValueNode[] arguments) { - super(targetGraph, caller, encodedGraph, loopExplosionKind(method, loopExplosionPlugin)); + protected PEMethodScope(StructuredGraph targetGraph, PEMethodScope caller, LoopScope callerLoopScope, EncodedGraph encodedGraph, ResolvedJavaMethod method, InvokeData invokeData, + int inliningDepth, LoopExplosionPlugin loopExplosionPlugin, InvocationPlugins invocationPlugins, InlineInvokePlugin inlineInvokePlugin, ParameterPlugin parameterPlugin, + ValueNode[] arguments) { + super(targetGraph, encodedGraph, loopExplosionKind(method, loopExplosionPlugin)); + this.caller = caller; + this.callerLoopScope = callerLoopScope; this.method = method; - this.invoke = invoke; + this.invokeData = invokeData; this.inliningDepth = inliningDepth; this.loopExplosionPlugin = loopExplosionPlugin; this.invocationPlugins = invocationPlugins; @@ -89,6 +98,10 @@ this.parameterPlugin = parameterPlugin; this.arguments = arguments; } + + public boolean isInlinedMethod() { + return caller != null; + } } protected class PECanonicalizerTool implements CanonicalizerTool { @@ -114,7 +127,7 @@ } protected class PENonAppendGraphBuilderContext implements GraphBuilderContext { - private final PEMethodScope methodScope; + protected final PEMethodScope methodScope; public PENonAppendGraphBuilderContext(PEMethodScope methodScope) { this.methodScope = methodScope; @@ -212,13 +225,11 @@ } protected class PEAppendGraphBuilderContext extends PENonAppendGraphBuilderContext { - protected final Invoke invoke; protected FixedWithNextNode lastInstr; protected ValueNode pushedNode; - public PEAppendGraphBuilderContext(PEMethodScope methodScope, Invoke invoke, FixedWithNextNode lastInstr) { + public PEAppendGraphBuilderContext(PEMethodScope methodScope, FixedWithNextNode lastInstr) { super(methodScope); - this.invoke = invoke; this.lastInstr = lastInstr; } @@ -232,7 +243,9 @@ @Override public FrameState createStateAfter() { - return invoke.stateAfter().duplicate(); + Node stateAfter = decodeFloatingNode(methodScope.caller, methodScope.callerLoopScope, methodScope.invokeData.stateAfterOrderId); + getGraph().add(stateAfter); + return (FrameState) handleFloatingNodeAfterAdd(methodScope.caller, methodScope.callerLoopScope, stateAfter); } @Override @@ -274,6 +287,15 @@ } } + @NodeInfo + static class ExceptionPlaceholderNode extends ValueNode { + public static final NodeClass TYPE = NodeClass.create(ExceptionPlaceholderNode.class); + + public ExceptionPlaceholderNode() { + super(TYPE, StampFactory.object()); + } + } + public PEGraphDecoder(MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, StampProvider stampProvider) { this.metaAccess = metaAccess; this.constantReflection = constantReflection; @@ -294,8 +316,9 @@ public void decode(StructuredGraph targetGraph, ResolvedJavaMethod method, LoopExplosionPlugin loopExplosionPlugin, InvocationPlugins invocationPlugins, InlineInvokePlugin inlineInvokePlugin, ParameterPlugin parameterPlugin) { - PEMethodScope methodScope = new PEMethodScope(targetGraph, null, lookupEncodedGraph(method), method, null, 0, loopExplosionPlugin, invocationPlugins, inlineInvokePlugin, parameterPlugin, null); - decode(methodScope); + PEMethodScope methodScope = new PEMethodScope(targetGraph, null, null, lookupEncodedGraph(method), method, null, 0, loopExplosionPlugin, invocationPlugins, inlineInvokePlugin, + parameterPlugin, null); + decode(methodScope, null); cleanupGraph(methodScope); methodScope.graph.verify(); } @@ -310,8 +333,6 @@ protected void checkLoopExplosionIteration(MethodScope s, LoopScope loopScope) { PEMethodScope methodScope = (PEMethodScope) s; - Debug.dump(methodScope.graph, "Loop iteration " + loopScope.loopIteration); - if (loopScope.loopIteration > MaximumLoopExplosionCount.getValue()) { String message = "too many loop explosion iterations - does the explosion not terminate for method " + methodScope.method + "?"; if (FailedLoopExplosionIsFatal.getValue()) { @@ -323,39 +344,52 @@ } @Override - protected void simplifyInvoke(MethodScope s, LoopScope loopScope, int invokeOrderId, Invoke invoke) { - if (!(invoke.callTarget() instanceof MethodCallTargetNode)) { - return; - } + protected void handleInvoke(MethodScope s, LoopScope loopScope, InvokeData invokeData) { PEMethodScope methodScope = (PEMethodScope) s; - MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget(); + + /* + * Decode the call target, but do not add it to the graph yet. This avoids adding usages for + * all the arguments, which are expensive to remove again when we can inline the method. + */ + assert invokeData.invoke.callTarget() == null : "callTarget edge is ignored during decoding of Invoke"; + CallTargetNode callTarget = (CallTargetNode) decodeFloatingNode(methodScope, loopScope, invokeData.callTargetOrderId); + if (!(callTarget instanceof MethodCallTargetNode) || !trySimplifyInvoke(methodScope, loopScope, invokeData, (MethodCallTargetNode) callTarget)) { + /* We know that we need an invoke, so now we can add the call target to the graph. */ + methodScope.graph.add(callTarget); + registerNode(loopScope, invokeData.callTargetOrderId, callTarget, false, false); + super.handleInvoke(methodScope, loopScope, invokeData); + } + } + + protected boolean trySimplifyInvoke(PEMethodScope methodScope, LoopScope loopScope, InvokeData invokeData, MethodCallTargetNode callTarget) { // attempt to devirtualize the call - ResolvedJavaType contextType = (invoke.stateAfter() == null && invoke.stateDuring() == null) ? null : invoke.getContextType(); - ResolvedJavaMethod specialCallTarget = MethodCallTargetNode.findSpecialCallTarget(callTarget.invokeKind(), callTarget.receiver(), callTarget.targetMethod(), contextType); + ResolvedJavaMethod specialCallTarget = MethodCallTargetNode.findSpecialCallTarget(callTarget.invokeKind(), callTarget.receiver(), callTarget.targetMethod(), invokeData.contextType); if (specialCallTarget != null) { callTarget.setTargetMethod(specialCallTarget); callTarget.setInvokeKind(InvokeKind.Special); } - if (tryInvocationPlugin(methodScope, loopScope, invokeOrderId, invoke)) { - return; + if (tryInvocationPlugin(methodScope, loopScope, invokeData, callTarget)) { + return true; } - if (tryInline(methodScope, loopScope, invokeOrderId, invoke)) { - return; + if (tryInline(methodScope, loopScope, invokeData, callTarget)) { + return true; } if (methodScope.inlineInvokePlugin != null) { - methodScope.inlineInvokePlugin.notifyOfNoninlinedInvoke(new PENonAppendGraphBuilderContext(methodScope), callTarget.targetMethod(), invoke); + methodScope.inlineInvokePlugin.notifyOfNoninlinedInvoke(new PENonAppendGraphBuilderContext(methodScope), callTarget.targetMethod(), invokeData.invoke); } + return false; } - protected boolean tryInvocationPlugin(PEMethodScope methodScope, LoopScope loopScope, int invokeOrderId, Invoke invoke) { + protected boolean tryInvocationPlugin(PEMethodScope methodScope, LoopScope loopScope, InvokeData invokeData, MethodCallTargetNode callTarget) { if (methodScope.invocationPlugins == null) { return false; } - MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget(); + Invoke invoke = invokeData.invoke; + ResolvedJavaMethod targetMethod = callTarget.targetMethod(); InvocationPlugin invocationPlugin = methodScope.invocationPlugins.lookupInvocation(targetMethod); if (invocationPlugin == null) { @@ -364,52 +398,41 @@ ValueNode[] arguments = callTarget.arguments().toArray(new ValueNode[0]); FixedWithNextNode invokePredecessor = (FixedWithNextNode) invoke.asNode().predecessor(); - FixedNode invokeNext = invoke.next(); - AbstractBeginNode invokeException = null; - if (invoke instanceof InvokeWithExceptionNode) { - invokeException = ((InvokeWithExceptionNode) invoke).exceptionEdge(); - } + /* Remove invoke from graph so that invocation plugin can append nodes to the predecessor. */ invoke.asNode().replaceAtPredecessor(null); - PEAppendGraphBuilderContext graphBuilderContext = new PEAppendGraphBuilderContext(methodScope, invoke, invokePredecessor); + PEMethodScope inlineScope = new PEMethodScope(methodScope.graph, methodScope, loopScope, null, targetMethod, invokeData, methodScope.inliningDepth + 1, methodScope.loopExplosionPlugin, + methodScope.invocationPlugins, methodScope.inlineInvokePlugin, null, arguments); + PEAppendGraphBuilderContext graphBuilderContext = new PEAppendGraphBuilderContext(inlineScope, invokePredecessor); InvocationPluginReceiver invocationPluginReceiver = new InvocationPluginReceiver(graphBuilderContext); + if (invocationPlugin.execute(graphBuilderContext, targetMethod, invocationPluginReceiver.init(targetMethod, arguments), arguments)) { if (graphBuilderContext.lastInstr != null) { - registerNode(loopScope, invokeOrderId, graphBuilderContext.pushedNode, true, true); + registerNode(loopScope, invokeData.invokeOrderId, graphBuilderContext.pushedNode, true, true); invoke.asNode().replaceAtUsages(graphBuilderContext.pushedNode); + graphBuilderContext.lastInstr.setNext(nodeAfterInvoke(methodScope, loopScope, invokeData)); } else { assert graphBuilderContext.pushedNode == null : "Why push a node when the invoke does not return anyway?"; invoke.asNode().replaceAtUsages(null); } deleteInvoke(invoke); - if (invokeException != null) { - invokeException.safeDelete(); - } - - if (graphBuilderContext.lastInstr != null) { - graphBuilderContext.lastInstr.setNext(invokeNext); - } else { - invokeNext.replaceAtPredecessor(null); - invokeNext.safeDelete(); - } return true; } else { - /* Restore original state: invoke is in Graph. */ + /* Intrinsification failed, restore original state: invoke is in Graph. */ invokePredecessor.setNext(invoke.asNode()); return false; } } - protected boolean tryInline(PEMethodScope methodScope, LoopScope loopScope, int invokeOrderId, Invoke invoke) { - if (methodScope.inlineInvokePlugin == null || !invoke.getInvokeKind().isDirect()) { + protected boolean tryInline(PEMethodScope methodScope, LoopScope loopScope, InvokeData invokeData, MethodCallTargetNode callTarget) { + if (methodScope.inlineInvokePlugin == null || !callTarget.invokeKind().isDirect()) { return false; } - MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget(); ResolvedJavaMethod targetMethod = callTarget.targetMethod(); if (!targetMethod.canBeInlined()) { return false; @@ -429,50 +452,72 @@ return false; } - int exceptionObjectOrderId = -1; - if (invoke instanceof InvokeWithExceptionNode) { - /* - * We need to have the regular next node (usually a KillingBeginNode) and the exception - * edge node (always an ExceptionObjectNode) fully decoded, because both can be changed - * or replaced as part of the inlining process. The GraphEncoder adds these two - * successors in a known order (first the regular next node, then the exception edge) - * that we can rely on here. - */ - assert ((InvokeWithExceptionNode) invoke).next().next() == null; - processNextNode(methodScope, loopScope); - assert ((InvokeWithExceptionNode) invoke).next().next() != null; + Invoke invoke = invokeData.invoke; + FixedNode invokeNode = invoke.asNode(); + FixedWithNextNode predecessor = (FixedWithNextNode) invokeNode.predecessor(); + invokeNode.replaceAtPredecessor(null); - assert ((InvokeWithExceptionNode) invoke).exceptionEdge().next() == null; - exceptionObjectOrderId = loopScope.nodesToProcess.nextSetBit(0); - processNextNode(methodScope, loopScope); - assert ((InvokeWithExceptionNode) invoke).exceptionEdge().next() != null; - } - - PEMethodScope inlineScope = new PEMethodScope(methodScope.graph, methodScope, graphToInline, inlineMethod, invoke, methodScope.inliningDepth + 1, methodScope.loopExplosionPlugin, - methodScope.invocationPlugins, methodScope.inlineInvokePlugin, null, arguments); + PEMethodScope inlineScope = new PEMethodScope(methodScope.graph, methodScope, loopScope, graphToInline, inlineMethod, invokeData, methodScope.inliningDepth + 1, + methodScope.loopExplosionPlugin, methodScope.invocationPlugins, methodScope.inlineInvokePlugin, null, arguments); /* Do the actual inlining by decoding the inlineMethod */ - decode(inlineScope); + decode(inlineScope, predecessor); ValueNode exceptionValue = null; if (inlineScope.unwindNode != null) { exceptionValue = inlineScope.unwindNode.exception(); } + UnwindNode unwindNode = inlineScope.unwindNode; - FixedNode firstInlinedNode = inlineScope.startNode.next(); - /* The StartNode was only necessary as a placeholder during decoding. */ - inlineScope.startNode.safeDelete(); + if (invoke instanceof InvokeWithExceptionNode) { + InvokeWithExceptionNode invokeWithException = ((InvokeWithExceptionNode) invoke); + assert invokeWithException.next() == null; + assert invokeWithException.exceptionEdge() == null; + + if (unwindNode != null) { + assert unwindNode.predecessor() != null; + Node n = makeStubNode(methodScope, loopScope, invokeData.exceptionNextOrderId); + unwindNode.replaceAndDelete(n); + } + + } else { + if (unwindNode != null && !unwindNode.isDeleted()) { + DeoptimizeNode deoptimizeNode = methodScope.graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.NotCompiledExceptionHandler)); + unwindNode.replaceAndDelete(deoptimizeNode); + } + } + + assert invoke.next() == null; - assert inlineScope.startNode.stateAfter() == null; - ValueNode returnValue = InliningUtil.finishInlining(invoke, methodScope.graph, firstInlinedNode, inlineScope.returnNodes, inlineScope.unwindNode, inlineScope.encodedGraph.getAssumptions(), - inlineScope.encodedGraph.getInlinedMethods(), null); + ValueNode returnValue; + List returnNodes = inlineScope.returnNodes; + if (!returnNodes.isEmpty()) { + FixedNode n; + n = nodeAfterInvoke(methodScope, loopScope, invokeData); + if (returnNodes.size() == 1) { + ReturnNode returnNode = returnNodes.get(0); + returnValue = returnNode.result(); + returnNode.replaceAndDelete(n); + } else { + AbstractMergeNode merge = methodScope.graph.add(new MergeNode()); + merge.setStateAfter((FrameState) ensureNodeCreated(methodScope, loopScope, invokeData.stateAfterOrderId)); + returnValue = InliningUtil.mergeReturns(merge, returnNodes, null); + merge.setNext(n); + } + } else { + returnValue = null; + } + invokeNode.replaceAtUsages(returnValue); /* * Usage the handles that we have on the return value and the exception to update the * orderId->Node table. */ - registerNode(loopScope, invokeOrderId, returnValue, true, true); + registerNode(loopScope, invokeData.invokeOrderId, returnValue, true, true); if (invoke instanceof InvokeWithExceptionNode) { - registerNode(loopScope, exceptionObjectOrderId, exceptionValue, true, true); + registerNode(loopScope, invokeData.exceptionOrderId, exceptionValue, true, true); + } + if (inlineScope.exceptionPlaceholderNode != null) { + inlineScope.exceptionPlaceholderNode.replaceAndDelete(exceptionValue); } deleteInvoke(invoke); @@ -480,6 +525,16 @@ return true; } + public FixedNode nodeAfterInvoke(PEMethodScope methodScope, LoopScope loopScope, InvokeData invokeData) { + FixedNode n; + if (invokeData.invoke instanceof InvokeWithExceptionNode) { + n = makeStubNode(methodScope, loopScope, invokeData.nextNextOrderId); + } else { + n = makeStubNode(methodScope, loopScope, invokeData.nextOrderId); + } + return n; + } + private static void deleteInvoke(Invoke invoke) { /* * Clean up unused nodes. We cannot just call killCFG on the invoke node because that can @@ -487,7 +542,7 @@ */ FrameState frameState = invoke.stateAfter(); invoke.asNode().safeDelete(); - invoke.callTarget().safeDelete(); + assert invoke.callTarget() == null : "must not have been added to the graph yet"; if (frameState != null && frameState.hasNoUsages()) { frameState.safeDelete(); } @@ -499,15 +554,20 @@ protected void simplifyFixedNode(MethodScope s, LoopScope loopScope, int nodeOrderId, FixedNode node) { PEMethodScope methodScope = (PEMethodScope) s; - if (node instanceof IfNode && ((IfNode) node).condition() instanceof LogicConstantNode) { + if (node instanceof IfNode) { IfNode ifNode = (IfNode) node; - boolean condition = ((LogicConstantNode) ifNode.condition()).getValue(); - AbstractBeginNode survivingSuccessor = ifNode.getSuccessor(condition); - AbstractBeginNode deadSuccessor = ifNode.getSuccessor(!condition); + if (ifNode.condition() instanceof LogicNegationNode) { + ifNode.eliminateNegation(); + } + if (ifNode.condition() instanceof LogicConstantNode) { + boolean condition = ((LogicConstantNode) ifNode.condition()).getValue(); + AbstractBeginNode survivingSuccessor = ifNode.getSuccessor(condition); + AbstractBeginNode deadSuccessor = ifNode.getSuccessor(!condition); - methodScope.graph.removeSplit(ifNode, survivingSuccessor); - assert deadSuccessor.next() == null : "must not be parsed yet"; - deadSuccessor.safeDelete(); + methodScope.graph.removeSplit(ifNode, survivingSuccessor); + assert deadSuccessor.next() == null : "must not be parsed yet"; + deadSuccessor.safeDelete(); + } } else if (node instanceof IntegerSwitchNode && ((IntegerSwitchNode) node).value().isConstant()) { IntegerSwitchNode switchNode = (IntegerSwitchNode) node; @@ -587,31 +647,68 @@ return node; } + protected void ensureOuterStateDecoded(PEMethodScope methodScope) { + if (methodScope.outerState == null && methodScope.caller != null) { + FrameState stateAtReturn = methodScope.invokeData.invoke.stateAfter(); + if (stateAtReturn == null) { + stateAtReturn = (FrameState) decodeFloatingNode(methodScope.caller, methodScope.callerLoopScope, methodScope.invokeData.stateAfterOrderId); + } + + Kind invokeReturnKind = methodScope.invokeData.invoke.asNode().getKind(); + FrameState outerState = stateAtReturn.duplicateModified(methodScope.graph, methodScope.invokeData.invoke.bci(), stateAtReturn.rethrowException(), true, invokeReturnKind); + + if (methodScope.caller != null) { + ensureOuterStateDecoded(methodScope.caller); + outerState.setOuterFrameState(methodScope.caller.outerState); + } + methodScope.outerState = outerState; + } + } + + protected void ensureStateAfterDecoded(PEMethodScope methodScope) { + if (methodScope.invokeData.invoke.stateAfter() == null) { + methodScope.invokeData.invoke.setStateAfter((FrameState) ensureNodeCreated(methodScope.caller, methodScope.callerLoopScope, methodScope.invokeData.stateAfterOrderId)); + } + } + + protected void ensureExceptionStateDecoded(PEMethodScope methodScope) { + if (methodScope.exceptionState == null && methodScope.caller != null && methodScope.invokeData.invoke instanceof InvokeWithExceptionNode) { + ensureStateAfterDecoded(methodScope); + + assert methodScope.exceptionPlaceholderNode == null; + methodScope.exceptionPlaceholderNode = methodScope.graph.add(new ExceptionPlaceholderNode()); + registerNode(methodScope.callerLoopScope, methodScope.invokeData.exceptionOrderId, methodScope.exceptionPlaceholderNode, false, false); + FrameState exceptionState = (FrameState) ensureNodeCreated(methodScope.caller, methodScope.callerLoopScope, methodScope.invokeData.exceptionStateOrderId); + + if (methodScope.caller != null) { + ensureOuterStateDecoded(methodScope.caller); + exceptionState.setOuterFrameState(methodScope.caller.outerState); + } + methodScope.exceptionState = exceptionState; + } + } + @Override protected Node handleFloatingNodeAfterAdd(MethodScope s, LoopScope loopScope, Node node) { PEMethodScope methodScope = (PEMethodScope) s; if (methodScope.isInlinedMethod()) { if (node instanceof SimpleInfopointNode) { - methodScope.bytecodePosition = InliningUtil.processSimpleInfopoint(methodScope.invoke, (SimpleInfopointNode) node, methodScope.bytecodePosition); + methodScope.bytecodePosition = InliningUtil.processSimpleInfopoint(methodScope.invokeData.invoke, (SimpleInfopointNode) node, methodScope.bytecodePosition); return node; } else if (node instanceof FrameState) { - FrameState stateAtExceptionEdge = null; - if (methodScope.invoke instanceof InvokeWithExceptionNode) { - InvokeWithExceptionNode invokeWithException = ((InvokeWithExceptionNode) methodScope.invoke); - ExceptionObjectNode obj = (ExceptionObjectNode) invokeWithException.exceptionEdge(); - stateAtExceptionEdge = obj.stateAfter(); + FrameState frameState = (FrameState) node; + + ensureOuterStateDecoded(methodScope); + if (frameState.bci < 0) { + ensureExceptionStateDecoded(methodScope); } - if (methodScope.outerFrameState == null) { - FrameState stateAtReturn = methodScope.invoke.stateAfter(); - Kind invokeReturnKind = methodScope.invoke.asNode().getKind(); - methodScope.outerFrameState = stateAtReturn.duplicateModifiedDuringCall(methodScope.invoke.bci(), invokeReturnKind); - } - return InliningUtil.processFrameState((FrameState) node, methodScope.invoke, methodScope.method, stateAtExceptionEdge, methodScope.outerFrameState, true); + return InliningUtil.processFrameState(frameState, methodScope.invokeData.invoke, methodScope.method, methodScope.exceptionState, methodScope.outerState, true); } else if (node instanceof MonitorIdNode) { - InliningUtil.processMonitorId(methodScope.invoke, (MonitorIdNode) node); + ensureOuterStateDecoded(methodScope); + InliningUtil.processMonitorId(methodScope.outerState, (MonitorIdNode) node); return node; } } diff -r dc58f4ca21c9 -r 44d8f20d4f55 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java Mon Apr 13 21:50:37 2015 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java Mon Apr 13 21:51:19 2015 +0200 @@ -164,28 +164,74 @@ private class PEInlineInvokePlugin implements InlineInvokePlugin { - private final boolean duringParsing; private Deque inlining; private OptimizedDirectCallNode lastDirectCallNode; private final Replacements replacements; - private final InvocationPlugins invocationPlugins; - private final LoopExplosionPlugin loopExplosionPlugin; - - public PEInlineInvokePlugin(TruffleInlining inlining, Replacements replacements, boolean duringParsing, InvocationPlugins invocationPlugins, LoopExplosionPlugin loopExplosionPlugin) { + public PEInlineInvokePlugin(TruffleInlining inlining, Replacements replacements) { this.inlining = new ArrayDeque<>(); this.inlining.push(inlining); this.replacements = replacements; - this.duringParsing = duringParsing; + } + + @Override + public InlineInfo getInlineInfo(GraphBuilderContext builder, ResolvedJavaMethod original, ValueNode[] arguments, JavaType returnType) { + if (original.getAnnotation(TruffleBoundary.class) != null) { + return null; + } + if (replacements != null && replacements.hasSubstitution(original)) { + return null; + } + assert !builder.parsingReplacement(); + if (TruffleCompilerOptions.TruffleFunctionInlining.getValue()) { + if (original.equals(callSiteProxyMethod)) { + ValueNode arg1 = arguments[0]; + if (!arg1.isConstant()) { + GraalInternalError.shouldNotReachHere("The direct call node does not resolve to a constant!"); + } + + Object callNode = snippetReflection.asObject(Object.class, (JavaConstant) arg1.asConstant()); + if (callNode instanceof OptimizedDirectCallNode) { + OptimizedDirectCallNode directCallNode = (OptimizedDirectCallNode) callNode; + lastDirectCallNode = directCallNode; + } + } else if (original.equals(callDirectMethod)) { + TruffleInliningDecision decision = getDecision(inlining.peek(), lastDirectCallNode); + lastDirectCallNode = null; + if (decision != null && decision.isInline()) { + inlining.push(decision); + builder.getAssumptions().record(new AssumptionValidAssumption((OptimizedAssumption) decision.getTarget().getNodeRewritingAssumption())); + return new InlineInfo(callInlinedMethod, false, false); + } + } + } + + return new InlineInfo(original, false, false); + } + + @Override + public void postInline(ResolvedJavaMethod inlinedTargetMethod) { + if (inlinedTargetMethod.equals(callInlinedMethod)) { + inlining.pop(); + } + } + } + + private class ParsingInlineInvokePlugin implements InlineInvokePlugin { + + private final Replacements replacements; + private final InvocationPlugins invocationPlugins; + private final LoopExplosionPlugin loopExplosionPlugin; + private final boolean inlineDuringParsing; + + public ParsingInlineInvokePlugin(Replacements replacements, InvocationPlugins invocationPlugins, LoopExplosionPlugin loopExplosionPlugin, boolean inlineDuringParsing) { + this.replacements = replacements; this.invocationPlugins = invocationPlugins; this.loopExplosionPlugin = loopExplosionPlugin; + this.inlineDuringParsing = inlineDuringParsing; } private boolean hasMethodHandleArgument(ValueNode[] arguments) { - /* - * We want to process invokes that have a constant MethodHandle parameter. And the - * method must be statically bound, otherwise we do not have a single target method. - */ for (ValueNode argument : arguments) { if (argument.isConstant()) { JavaConstant constant = argument.asJavaConstant(); @@ -197,58 +243,31 @@ return false; } + @Override public InlineInfo getInlineInfo(GraphBuilderContext builder, ResolvedJavaMethod original, ValueNode[] arguments, JavaType returnType) { - if (duringParsing && (invocationPlugins.lookupInvocation(original) != null || loopExplosionPlugin.shouldExplodeLoops(original))) { + if (invocationPlugins.lookupInvocation(original) != null || loopExplosionPlugin.shouldExplodeLoops(original)) { return null; } - if (original.getAnnotation(TruffleBoundary.class) != null) { return null; } if (replacements != null && replacements.hasSubstitution(original)) { return null; } - assert !builder.parsingReplacement(); - if (TruffleCompilerOptions.TruffleFunctionInlining.getValue()) { - if (original.equals(callSiteProxyMethod)) { - if (duringParsing) { - return null; - } - ValueNode arg1 = arguments[0]; - if (!arg1.isConstant()) { - GraalInternalError.shouldNotReachHere("The direct call node does not resolve to a constant!"); - } - - Object callNode = snippetReflection.asObject(Object.class, (JavaConstant) arg1.asConstant()); - if (callNode instanceof OptimizedDirectCallNode) { - OptimizedDirectCallNode directCallNode = (OptimizedDirectCallNode) callNode; - lastDirectCallNode = directCallNode; - } - } else if (original.equals(callDirectMethod)) { - if (duringParsing) { - return null; - } - TruffleInliningDecision decision = getDecision(inlining.peek(), lastDirectCallNode); - lastDirectCallNode = null; - if (decision != null && decision.isInline()) { - inlining.push(decision); - builder.getAssumptions().record(new AssumptionValidAssumption((OptimizedAssumption) decision.getTarget().getNodeRewritingAssumption())); - return new InlineInfo(callInlinedMethod, false, false); - } - } - } - - if (duringParsing && (!original.hasBytecodes() || original.getCode().length >= TrivialInliningSize.getValue() || builder.getDepth() >= InlineDuringParsingMaxDepth.getValue()) && - !hasMethodHandleArgument(arguments)) { + if (original.equals(callSiteProxyMethod) || original.equals(callDirectMethod)) { return null; } - return new InlineInfo(original, false, false); - } - - public void postInline(ResolvedJavaMethod inlinedTargetMethod) { - if (inlinedTargetMethod.equals(callInlinedMethod)) { - inlining.pop(); + if (hasMethodHandleArgument(arguments)) { + /* + * We want to inline invokes that have a constant MethodHandle parameter to remove + * invokedynamic related calls as early as possible. + */ + return new InlineInfo(original, false, false); } + if (inlineDuringParsing && original.hasBytecodes() && original.getCode().length < TrivialInliningSize.getValue() && builder.getDepth() < InlineDuringParsingMaxDepth.getValue()) { + return new InlineInfo(original, false, false); + } + return null; } } @@ -279,7 +298,7 @@ plugins.setParameterPlugin(new InterceptReceiverPlugin(callTarget)); callTarget.setInlining(new TruffleInlining(callTarget, new DefaultInliningPolicy())); - InlineInvokePlugin inlinePlugin = new PEInlineInvokePlugin(callTarget.getInlining(), providers.getReplacements(), false, null, null); + InlineInvokePlugin inlinePlugin = new PEInlineInvokePlugin(callTarget.getInlining(), providers.getReplacements()); if (PrintTruffleExpansionHistogram.getValue()) { inlinePlugin = new HistogramInlineInvokePlugin(graph, inlinePlugin); } @@ -303,7 +322,7 @@ newConfig.setUseProfiling(false); Plugins plugins = newConfig.getPlugins(); plugins.setLoadFieldPlugin(new InterceptLoadFieldPlugin()); - plugins.setInlineInvokePlugin(new PEInlineInvokePlugin(callTarget.getInlining(), providers.getReplacements(), true, parsingInvocationPlugins, loopExplosionPlugin)); + plugins.setInlineInvokePlugin(new ParsingInlineInvokePlugin(providers.getReplacements(), parsingInvocationPlugins, loopExplosionPlugin, !PrintTruffleExpansionHistogram.getValue())); CachingPEGraphDecoder decoder = new CachingPEGraphDecoder(providers, newConfig, AllowAssumptions.from(graph.getAssumptions() != null)); @@ -311,7 +330,7 @@ InvocationPlugins decodingInvocationPlugins = new InvocationPlugins(providers.getMetaAccess()); TruffleGraphBuilderPlugins.registerInvocationPlugins(providers.getMetaAccess(), decodingInvocationPlugins, false, snippetReflection); - InlineInvokePlugin decodingInlinePlugin = new PEInlineInvokePlugin(callTarget.getInlining(), providers.getReplacements(), false, decodingInvocationPlugins, loopExplosionPlugin); + InlineInvokePlugin decodingInlinePlugin = new PEInlineInvokePlugin(callTarget.getInlining(), providers.getReplacements()); if (PrintTruffleExpansionHistogram.getValue()) { decodingInlinePlugin = new HistogramInlineInvokePlugin(graph, decodingInlinePlugin); } @@ -431,7 +450,9 @@ if (!TruffleCompilerOptions.TruffleInlineAcrossTruffleBoundary.getValue()) { // Do not inline across Truffle boundaries. for (MethodCallTargetNode mct : graph.getNodes(MethodCallTargetNode.TYPE)) { - mct.invoke().setUseForInlining(false); + if (mct.targetMethod().getAnnotation(TruffleBoundary.class) != null) { + mct.invoke().setUseForInlining(false); + } } } } diff -r dc58f4ca21c9 -r 44d8f20d4f55 graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/InstrumentationTest.java --- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/InstrumentationTest.java Mon Apr 13 21:50:37 2015 +0200 +++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/InstrumentationTest.java Mon Apr 13 21:51:19 2015 +0200 @@ -157,7 +157,6 @@ // Check that the "probed" AST still executes correctly assertEquals(13, callTarget1.call()); - } @Test @@ -178,11 +177,10 @@ // Check instrumentation with the simplest kind of counters. // They should all be removed when the check is finished. - checkCounters(probe, callTarget, rootNode, new TestInstrumentCounter(), new TestInstrumentCounter(), new TestInstrumentCounter()); + checkCounters(probe, callTarget, rootNode, new TestSimpleInstrumentCounter(), new TestSimpleInstrumentCounter(), new TestSimpleInstrumentCounter()); // Now try with the more complex flavor of listener - checkCounters(probe, callTarget, rootNode, new TestASTInstrumentCounter(), new TestASTInstrumentCounter(), new TestASTInstrumentCounter()); - + checkCounters(probe, callTarget, rootNode, new TestStandardInstrumentCounter(), new TestStandardInstrumentCounter(), new TestStandardInstrumentCounter()); } private static void checkCounters(Probe probe, CallTarget callTarget, RootNode rootNode, TestCounter counterA, TestCounter counterB, TestCounter counterC) { @@ -280,12 +278,10 @@ assertEquals(counterB.leaveCount(), 8); assertEquals(counterC.enterCount(), 2); assertEquals(counterC.leaveCount(), 2); - } @Test public void testTagging() { - // Applies appropriate tags final TestASTProber astProber = new TestASTProber(); Probe.registerASTProber(astProber); @@ -341,7 +337,6 @@ assertEquals(valueCounter.count, 2); Probe.unregisterASTProber(astProber); - } private interface TestCounter { @@ -353,92 +348,107 @@ void attach(Probe probe); void dispose(); - } /** - * A counter for the number of times execution enters and leaves a probed AST node, using the - * simplest kind of listener. + * A counter for the number of times execution enters and leaves a probed AST node. */ - private class TestInstrumentCounter implements TestCounter { + private class TestSimpleInstrumentCounter implements TestCounter { public int enterCount = 0; public int leaveCount = 0; public final Instrument instrument; - public TestInstrumentCounter() { + public TestSimpleInstrumentCounter() { this.instrument = Instrument.create(new SimpleInstrumentListener() { - @Override public void enter(Probe probe) { enterCount++; } - @Override - public void returnAny(Probe probe) { + public void returnVoid(Probe probe) { + leaveCount++; + } + + public void returnValue(Probe probe, Object result) { + leaveCount++; + } + + public void returnExceptional(Probe probe, Exception exception) { leaveCount++; } }, "Instrumentation Test Counter"); - } + @Override public int enterCount() { return enterCount; } + @Override public int leaveCount() { return leaveCount; } + @Override public void attach(Probe probe) { probe.attach(instrument); } + @Override public void dispose() { instrument.dispose(); } } /** - * A counter for the number of times execution enters and leaves a probed AST node, using the - * simplest kind of listener. + * A counter for the number of times execution enters and leaves a probed AST node. */ - private class TestASTInstrumentCounter implements TestCounter { + private class TestStandardInstrumentCounter implements TestCounter { public int enterCount = 0; public int leaveCount = 0; public final Instrument instrument; - public TestASTInstrumentCounter() { - this.instrument = Instrument.create(new SimpleASTInstrumentListener() { + public TestStandardInstrumentCounter() { + this.instrument = Instrument.create(new StandardInstrumentListener() { - @Override public void enter(Probe probe, Node node, VirtualFrame vFrame) { enterCount++; } - @Override - public void returnAny(Probe probe, Node node, VirtualFrame vFrame) { + public void returnVoid(Probe probe, Node node, VirtualFrame vFrame) { + leaveCount++; + } + + public void returnValue(Probe probe, Node node, VirtualFrame vFrame, Object result) { + leaveCount++; + } + + public void returnExceptional(Probe probe, Node node, VirtualFrame vFrame, Exception exception) { leaveCount++; } }, "Instrumentation Test Counter"); - } + @Override public int enterCount() { return enterCount; } + @Override public int leaveCount() { return leaveCount; } + @Override public void attach(Probe probe) { probe.attach(instrument); } + @Override public void dispose() { instrument.dispose(); } @@ -475,7 +485,7 @@ /** * Counts the number of "enter" events at probed nodes using the simplest AST listener. */ - static final class TestInstrumentListener extends DefaultInstrumentListener { + static final class TestSimpleInstrumentListener extends DefaultSimpleInstrumentListener { public int counter = 0; @@ -483,13 +493,12 @@ public void enter(Probe probe) { counter++; } - } /** * Counts the number of "enter" events at probed nodes using the AST listener. */ - static final class TestASTInstrumentListener extends DefaultASTInstrumentListener { + static final class TestASTInstrumentListener extends DefaultStandardInstrumentListener { public int counter = 0; @@ -497,7 +506,6 @@ public void enter(Probe probe, Node node, VirtualFrame vFrame) { counter++; } - } /** @@ -514,7 +522,7 @@ // where we want to count executions. // it will get copied when ASTs cloned, so // keep the count in this outer class. - probe.attach(Instrument.create(new DefaultInstrumentListener() { + probe.attach(Instrument.create(new DefaultSimpleInstrumentListener() { @Override public void enter(Probe p) { @@ -539,5 +547,4 @@ tagCount++; } } - } diff -r dc58f4ca21c9 -r 44d8f20d4f55 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ASTInstrumentListener.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ASTInstrumentListener.java Mon Apr 13 21:50:37 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.truffle.api.instrument; - -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.nodes.*; - -/** - * A listener of Truffle AST runtime execution events that can collect information, examine the - * execution state at a particular node, and possibly intervene on behalf of an external tool. - */ -public interface ASTInstrumentListener { - - /** - * Receive notification that an AST node's execute method is about to be called. - */ - void enter(Probe probe, Node node, VirtualFrame vFrame); - - /** - * Receive notification that an AST Node's {@code void}-valued execute method has just returned. - */ - void returnVoid(Probe probe, Node node, VirtualFrame vFrame); - - /** - * Receive notification that an AST Node's execute method has just returned a value (boxed if - * primitive). - */ - void returnValue(Probe probe, Node node, VirtualFrame vFrame, Object result); - - /** - * Receive notification that an AST Node's execute method has just thrown an exception. - */ - void returnExceptional(Probe probe, Node node, VirtualFrame vFrame, Exception exception); - -} diff -r dc58f4ca21c9 -r 44d8f20d4f55 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrument.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrument.java Mon Apr 13 21:50:37 2015 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrument.java Mon Apr 13 21:51:19 2015 +0200 @@ -25,145 +25,67 @@ package com.oracle.truffle.api.instrument; import com.oracle.truffle.api.*; -import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.frame.*; import com.oracle.truffle.api.instrument.InstrumentationNode.TruffleEvents; -import com.oracle.truffle.api.instrument.impl.*; import com.oracle.truffle.api.nodes.*; import com.oracle.truffle.api.source.*; -// TODO (mlvdv) migrate some of this to external documentation. // TODO (mlvdv) move all this to a factory implemented in .impl (together with Probe), // then break out some of the nested classes into package privates. /** - * A dynamically added/removed binding between a {@link Probe}, which provides notification of - * execution events taking place at a {@link Node} in a Guest Language (GL) Truffle AST, - * and a listener, which consumes notifications on behalf of an external tool. There are at - * present two kinds of listeners that be used: - *
    - *
  1. {@link InstrumentListener} is the simplest and is intended for tools that require no access - * to the internal execution state of the Truffle execution, only that execution has passed - * through a particular location in the program. Information about that location is made available - * via the {@link Probe} argument in notification methods, including the {@linkplain SourceSection - * source location} of the node and any {@linkplain SyntaxTag tags} that have been applied to the - * node.
  2. - *
  3. {@link ASTInstrumentListener} reports the same events and {@link Probe} argument, but - * additionally provides access to the execution state via the explicit {@link Node} and - * {@link Frame} at the current execution site.
  4. - *
- *

- *

Summary: How to "instrument" an AST location:

- *

+ * A binding between: *

    - *
  1. Create an implementation of a listener interface.
  2. - *
  3. Create an Instrument via factory methods - * {@link Instrument#create(InstrumentListener, String)} or - * {@link Instrument#create(ASTInstrumentListener, String)}.
  4. - *
  5. "Attach" the Instrument to a Probe via {@link Probe#attach(Instrument)}, at which point event - * notifications begin to arrive at the listener.
  6. - *
  7. When no longer needed, "detach" the Instrument via {@link ASTInstrument#dispose()}, at which - * point event notifications to the listener cease, and the Instrument becomes unusable.
  8. - *
- *

- *

Options for creating listeners:

- *

- *

    - *
  1. Implement one of the listener interfaces: {@link InstrumentListener} or - * {@link ASTInstrumentListener} . Their event handling methods account for both the entry into an - * AST node (about to call) and three possible kinds of execution return from an AST node.
  2. - *
  3. Extend one of the helper implementations: {@link DefaultInstrumentListener} or - * {@link DefaultASTInstrumentListener}. These provide no-op implementation of every listener - * method, so only the methods of interest need to be overridden.
  4. - *
  5. Extend one of the helper implementations: {@link SimpleInstrumentListener} or - * {@link SimpleASTInstrumentListener}. These re-route all execution returns to a single - * method, ignoring return values, so only two methods (for "enter" and "return") will notify all - * events.
  6. + *
  7. A {@link Probe}: a source of execution events taking place at a program location in + * an executing Truffle AST, and
  8. + *
  9. A listener: a consumer of execution events on behalf of an external client. *
*

- *

General guidelines for {@link ASTInstrumentListener} implementation:

+ * Client-oriented documentation for the use of Instruments is available online at Listening for + * Execution Events *

- * Unlike the listener interface {@link InstrumentListener}, which isolates implementations - * completely from Truffle internals (and is thus Truffle-safe), implementations of - * {@link ASTInstrumentListener} can interact directly with (and potentially affect) Truffle - * execution in general and Truffle optimization in particular. For example, it is possible to - * implement a debugger with this interface. - *

+ * The implementation of Instruments is complicated by the requirement that Truffle be able to clone + * ASTs at any time. In particular, any instrumentation-supporting Nodes that have been attached to + * an AST must be cloned along with the AST: AST clones are not permitted to share Nodes. *

- * As a consequence, implementations of {@link ASTInstrumentListener} effectively become part of the - * Truffle execution and must be coded according to general guidelines for Truffle implementations. - * For example: - *

    - *
  • Do not store {@link Frame} or {@link Node} references in fields.
  • - *
  • Prefer {@code final} fields and (where performance is important) short methods.
  • - *
  • If needed, pass along the {@link VirtualFrame} reference from an event notification as far as - * possible through code that is expected to be inlined, since this incurs no runtime overhead. When - * access to frame data is needed, substitute a more expensive {@linkplain Frame#materialize() - * materialized} representation of the frame.
  • - *
  • If a listener calls back to its tool during event handling, and if performance is an issue, - * then this should be through a final "callback" field in the instrument, and the called methods - * should be minimal.
  • - *
  • On the other hand, implementations should prevent Truffle from inlining beyond a reasonable - * point with the method annotation {@link TruffleBoundary}.
  • - *
  • The implicit "outer" pointer in a non-static inner class is a useful (and - * Truffle-optimizable) way to implement callbacks to owner tools.
  • - *
  • Primitive-valued return events are boxed for event notification, but Truffle will eliminate - * the boxing if they are cast back to their primitive values quickly (in particular before crossing - * any {@link TruffleBoundary} annotations). - *
+ * AST cloning is intended to be as transparent as possible to clients. This is encouraged + * by providing the {@link SimpleInstrumentListener} for clients that need know nothing more than + * the properties associated with a Probe: it's {@link SourceSection} and any associated instances + * of {@link SyntaxTag}. *

- *

Allowing for AST cloning:

+ * AST cloning is not transparent to clients that use the + * {@link StandardInstrumentListener}, since those event methods identify the concrete Node instance + * (and thus the AST instance) where the event takes place. *

- * Truffle routinely clones ASTs, which has consequences for implementations of - * {@link ASTInstrumentListener} (but not for implementations of {@link InstrumentListener}, from - * which cloning is hidden). - *

    - *
  • Even though a {@link Probe} is uniquely associated with a particular location in the - * executing Guest Language program, execution events at that location will in general be - * implemented by different {@link Node} instances, i.e. clones of the originally probed - * node.
  • - *
  • Because of cloning the {@link Node} supplied with notifications to a particular - * listener will vary, but because they all represent the same GL program location the events should - * be treated as equivalent for most purposes.
  • - *
- *

- *

Access to execution state via {@link ASTInstrumentListener}:

+ *

Implementation Notes: the Life Cycle of an {@link Instrument} at a {@link Probe}

*

*

    - *
  • Notification arguments provide primary access to the GL program's execution states: - *
      - *
    • {@link Node}: the concrete node (in one of the AST's clones) from which the event originated. + *
    • A new Instrument is created in permanent association with a client-provided + * listener.
    • + *
    • Multiple Instruments may share a single listener.
    • + *
    • An Instrument does nothing until it is {@linkplain Probe#attach(Instrument) attached} to a + * Probe, at which time the Instrument begins routing execution events from the Probe's AST location + * to the Instrument's listener.
    • + *
    • Neither Instruments nor Probes are {@link Node}s.
    • + *
    • A Probe has a single source-based location in an AST, but manages a separate + * instrumentation chain of Nodes at the equivalent location in each clone of the AST.
    • + *
    • When a probed AST is cloned, the instrumentation chain associated with each Probe is cloned + * along with the rest of the AST.
    • + *
    • When a new Instrument (for example an instance of {@link SimpleInstrument} is attached to a + * Probe, the Instrument inserts a new instance of its private Node type, + * {@link SimpleInstrument.SimpleInstrumentNode}, into each of the instrument chains + * managed by the Probe, i.e. one node instance per existing clone of the AST.
    • + *
    • If an Instrument is attached to a Probe in an AST that subsequently gets cloned, then the + * Instrument's private Node type will be cloned along with the rest of the the AST.
    • + *
    • Each Instrument's private Node type is a dynamic inner class whose only state is in the + * shared (outer) Instrument instance; that state includes a reference to the Instrument's listener. *
    • - *
    • {@link VirtualFrame}: the current execution frame. - *
    - *
  • Truffle global information is available, for example the execution - * {@linkplain TruffleRuntime#iterateFrames(FrameInstanceVisitor) stack}.
  • - *
  • Additional API access to execution state may be added in the future.
  • + *
  • When an Instrument that has been attached to a Probe is {@linkplain #dispose() disposed}, the + * Instrument searches every instrument chain associated with the Probe and removes the instance of + * its private Node type.
  • + *
  • Attaching and disposing an Instrument at a Probe deoptimizes any compilations of the + * AST.
  • *
- *

- *

Activating and deactivating Instruments:

- *

- * Instruments are single-use: - *

    - *
  • An instrument becomes active only when attached to a Probe via - * {@link Probe#attach(Instrument)}, and it may only be attached to a single Probe. It is a runtime - * error to attempt attaching a previously attached instrument.
  • - *
  • Attaching an instrument modifies every existing clone of the AST to which it is being - * attached, which can trigger deoptimization.
  • - *
  • The method {@link Instrument#dispose()} makes an instrument inactive by removing it from the - * Probe to which it was attached and rendering it permanently inert.
  • - *
  • Disposal removes the implementation of an instrument from all ASTs to which it was attached, - * which can trigger deoptimization.
  • - *
- *

- *

Sharing listeners:

- *

- * Although an Instrument may only be attached to a single Probe, a listener can be shared among - * multiple Instruments. This can be useful for observing events that might happen at different - * locations in a single AST, for example all assignments to a particular variable. In this case a - * new Instrument would be created and attached at each assignment node, but all the Instruments - * would be created with the same listener. - *

- * Disclaimer: experimental; under development. * * @see Probe * @see TruffleEvents @@ -177,21 +99,21 @@ * @param instrumentInfo optional description of the instrument's role, useful for debugging. * @return a new instrument, ready for attachment at a probe */ - public static Instrument create(InstrumentListener listener, String instrumentInfo) { - return new BasicInstrument(listener, instrumentInfo); + public static Instrument create(SimpleInstrumentListener listener, String instrumentInfo) { + return new SimpleInstrument(listener, instrumentInfo); } /** * Creates an instrument that will route execution events to a listener, along with access to * internal execution state. * - * @param astListener a listener for event generated by the instrument that provides access to - * internal execution state + * @param standardListener a listener for event generated by the instrument that provides access + * to internal execution state * @param instrumentInfo optional description of the instrument's role, useful for debugging. * @return a new instrument, ready for attachment at a probe */ - public static Instrument create(ASTInstrumentListener astListener, String instrumentInfo) { - return new ASTInstrument(astListener, instrumentInfo); + public static Instrument create(StandardInstrumentListener standardListener, String instrumentInfo) { + return new StandardInstrument(standardListener, instrumentInfo); } /** @@ -232,8 +154,7 @@ } /** - * Removes this instrument (and any clones) from the probe to which it attached and renders the - * instrument inert. + * Removes this instrument from the probe to which it attached and renders the instrument inert. * * @throws IllegalStateException if this instrument has already been disposed */ @@ -266,23 +187,23 @@ abstract AbstractInstrumentNode addToChain(AbstractInstrumentNode nextNode); /** - * An instrument that propagates events to an instance of {@link InstrumentListener}. + * An instrument that propagates events to an instance of {@link SimpleInstrumentListener}. */ - private static final class BasicInstrument extends Instrument { + private static final class SimpleInstrument extends Instrument { /** * Tool-supplied listener for events. */ - private final InstrumentListener instrumentListener; + private final SimpleInstrumentListener simpleListener; - private BasicInstrument(InstrumentListener basicListener, String instrumentInfo) { + private SimpleInstrument(SimpleInstrumentListener simpleListener, String instrumentInfo) { super(instrumentInfo); - this.instrumentListener = basicListener; + this.simpleListener = simpleListener; } @Override AbstractInstrumentNode addToChain(AbstractInstrumentNode nextNode) { - return new BasicInstrumentNode(nextNode); + return new SimpleInstrumentNode(nextNode); } @Override @@ -294,7 +215,7 @@ return instrumentNode.nextInstrumentNode; } // Match not at the head of the chain; remove it. - found = instrumentNode.removeFromChain(BasicInstrument.this); + found = instrumentNode.removeFromChain(SimpleInstrument.this); } if (!found) { throw new IllegalStateException("Couldn't find instrument node to remove: " + this); @@ -303,35 +224,35 @@ } @NodeInfo(cost = NodeCost.NONE) - private final class BasicInstrumentNode extends AbstractInstrumentNode { + private final class SimpleInstrumentNode extends AbstractInstrumentNode { - private BasicInstrumentNode(AbstractInstrumentNode nextNode) { + private SimpleInstrumentNode(AbstractInstrumentNode nextNode) { super(nextNode); } public void enter(Node node, VirtualFrame vFrame) { - BasicInstrument.this.instrumentListener.enter(BasicInstrument.this.probe); + SimpleInstrument.this.simpleListener.enter(SimpleInstrument.this.probe); if (nextInstrumentNode != null) { nextInstrumentNode.enter(node, vFrame); } } public void returnVoid(Node node, VirtualFrame vFrame) { - BasicInstrument.this.instrumentListener.returnVoid(BasicInstrument.this.probe); + SimpleInstrument.this.simpleListener.returnVoid(SimpleInstrument.this.probe); if (nextInstrumentNode != null) { nextInstrumentNode.returnVoid(node, vFrame); } } public void returnValue(Node node, VirtualFrame vFrame, Object result) { - BasicInstrument.this.instrumentListener.returnValue(BasicInstrument.this.probe, result); + SimpleInstrument.this.simpleListener.returnValue(SimpleInstrument.this.probe, result); if (nextInstrumentNode != null) { nextInstrumentNode.returnValue(node, vFrame, result); } } public void returnExceptional(Node node, VirtualFrame vFrame, Exception exception) { - BasicInstrument.this.instrumentListener.returnExceptional(BasicInstrument.this.probe, exception); + SimpleInstrument.this.simpleListener.returnExceptional(SimpleInstrument.this.probe, exception); if (nextInstrumentNode != null) { nextInstrumentNode.returnExceptional(node, vFrame, exception); } @@ -339,7 +260,7 @@ public String instrumentationInfo() { final String info = getInstrumentInfo(); - return info != null ? info : instrumentListener.getClass().getSimpleName(); + return info != null ? info : simpleListener.getClass().getSimpleName(); } } } @@ -350,23 +271,23 @@ abstract AbstractInstrumentNode removeFromChain(AbstractInstrumentNode instrumentNode); /** - * An instrument that propagates events to an instance of {@link ASTInstrumentListener}. + * An instrument that propagates events to an instance of {@link StandardInstrumentListener}. */ - private static final class ASTInstrument extends Instrument { + private static final class StandardInstrument extends Instrument { /** * Tool-supplied listener for AST events. */ - private final ASTInstrumentListener astListener; + private final StandardInstrumentListener standardListener; - private ASTInstrument(ASTInstrumentListener astListener, String instrumentInfo) { + private StandardInstrument(StandardInstrumentListener standardListener, String instrumentInfo) { super(instrumentInfo); - this.astListener = astListener; + this.standardListener = standardListener; } @Override AbstractInstrumentNode addToChain(AbstractInstrumentNode nextNode) { - return new ASTInstrumentNode(nextNode); + return new StandardInstrumentNode(nextNode); } @Override @@ -378,7 +299,7 @@ return instrumentNode.nextInstrumentNode; } // Match not at the head of the chain; remove it. - found = instrumentNode.removeFromChain(ASTInstrument.this); + found = instrumentNode.removeFromChain(StandardInstrument.this); } if (!found) { throw new IllegalStateException("Couldn't find instrument node to remove: " + this); @@ -387,35 +308,35 @@ } @NodeInfo(cost = NodeCost.NONE) - private final class ASTInstrumentNode extends AbstractInstrumentNode { + private final class StandardInstrumentNode extends AbstractInstrumentNode { - private ASTInstrumentNode(AbstractInstrumentNode nextNode) { + private StandardInstrumentNode(AbstractInstrumentNode nextNode) { super(nextNode); } public void enter(Node node, VirtualFrame vFrame) { - ASTInstrument.this.astListener.enter(ASTInstrument.this.probe, node, vFrame); + standardListener.enter(StandardInstrument.this.probe, node, vFrame); if (nextInstrumentNode != null) { nextInstrumentNode.enter(node, vFrame); } } public void returnVoid(Node node, VirtualFrame vFrame) { - ASTInstrument.this.astListener.returnVoid(ASTInstrument.this.probe, node, vFrame); + standardListener.returnVoid(StandardInstrument.this.probe, node, vFrame); if (nextInstrumentNode != null) { nextInstrumentNode.returnVoid(node, vFrame); } } public void returnValue(Node node, VirtualFrame vFrame, Object result) { - ASTInstrument.this.astListener.returnValue(ASTInstrument.this.probe, node, vFrame, result); + standardListener.returnValue(StandardInstrument.this.probe, node, vFrame, result); if (nextInstrumentNode != null) { nextInstrumentNode.returnValue(node, vFrame, result); } } public void returnExceptional(Node node, VirtualFrame vFrame, Exception exception) { - ASTInstrument.this.astListener.returnExceptional(ASTInstrument.this.probe, node, vFrame, exception); + standardListener.returnExceptional(StandardInstrument.this.probe, node, vFrame, exception); if (nextInstrumentNode != null) { nextInstrumentNode.returnExceptional(node, vFrame, exception); } @@ -423,14 +344,14 @@ public String instrumentationInfo() { final String info = getInstrumentInfo(); - return info != null ? info : astListener.getClass().getSimpleName(); + return info != null ? info : standardListener.getClass().getSimpleName(); } } - } + // TODO (mlvdv) EXPERIMENTAL- UNDER DEVELOPMENT /** - * An instrument that propagates events to an instance of {@link ASTInstrumentListener}. + * An instrument that propagates events to an instance of {@link StandardInstrumentListener}. */ private static final class ToolNodeInstrument extends Instrument { @@ -524,7 +445,6 @@ return info != null ? info : toolNodeListener.getClass().getSimpleName(); } } - } public interface TruffleOptListener { @@ -605,7 +525,6 @@ return info != null ? info : toolOptListener.getClass().getSimpleName(); } } - } @NodeInfo(cost = NodeCost.NONE) @@ -658,7 +577,5 @@ protected String getInstrumentInfo() { return Instrument.this.instrumentInfo; } - } - } diff -r dc58f4ca21c9 -r 44d8f20d4f55 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/InstrumentListener.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/InstrumentListener.java Mon Apr 13 21:50:37 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.truffle.api.instrument; - -/** - * A listener of Truffle execution events that can collect information on behalf of an external - * tool. Contextual information about the source of the event, if not stored in the implementation - * of the listener, can be obtained via access to the {@link Probe} that generates the event. - */ -public interface InstrumentListener { - - /** - * Receive notification that an AST node's execute method is about to be called. - */ - void enter(Probe probe); - - /** - * Receive notification that an AST Node's {@code void}-valued execute method has just returned. - */ - void returnVoid(Probe probe); - - /** - * Receive notification that an AST Node's execute method has just returned a value (boxed if - * primitive). - */ - void returnValue(Probe probe, Object result); - - /** - * Receive notification that an AST Node's execute method has just thrown an exception. - */ - void returnExceptional(Probe probe, Exception exception); -} diff -r dc58f4ca21c9 -r 44d8f20d4f55 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/InstrumentationNode.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/InstrumentationNode.java Mon Apr 13 21:50:37 2015 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/InstrumentationNode.java Mon Apr 13 21:51:19 2015 +0200 @@ -28,8 +28,9 @@ import com.oracle.truffle.api.nodes.*; /** - * A marker interface for Truffle {@linkplain Node nodes} that support Instrumentation and - * are should not be part of any Guest Language execution semantics. + * A marker interface for Truffle {@linkplain Node nodes} that internally implement the + * Instrumentation Framework. Such nodes should not be part of any Guest Language execution + * semantics, and should in general not be visible to ordinary Instrumentation clients. */ public interface InstrumentationNode { @@ -39,7 +40,8 @@ String instrumentationInfo(); /** - * Events at a Truffle node that get propagated through the Instrumentation Framework. + * Events that propagate through the {@linkplain InstrumentationNode implementation nodes} of + * the Instrumentation Framework, not visible in this form to Instrumentation clients. */ interface TruffleEvents { @@ -62,6 +64,5 @@ * An AST Node's execute method has just thrown an exception. */ void returnExceptional(Node node, VirtualFrame vFrame, Exception exception); - } } diff -r dc58f4ca21c9 -r 44d8f20d4f55 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/SimpleInstrumentListener.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/SimpleInstrumentListener.java Mon Apr 13 21:51:19 2015 +0200 @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.api.instrument; + +import com.oracle.truffle.api.source.*; + +/** + * A receiver of Truffle execution events that can act on behalf of an external client. + *

+ * The {@link Probe} instance provides access to the {@link SourceSection} associated with the + * event, as well as any {@link SyntaxTag}s that have been applied at that program's location. + *

+ * This is the simplest kind of listener, suitable for clients that need no other information about + * the program's execution state at the time of the event. Clients that require access to the AST + * execution state should use {@link StandardInstrumentListener}. + *

+ * Clients are free, of course, to record additional information in the listener implementation that + * carries additional information about the context and reason for the particular {@link Instrument} + * that is to be created from the listener. + */ +public interface SimpleInstrumentListener { + + /** + * Receive notification that a program location is about to be executed. + *

+ * Synchronous: Truffle execution waits until the call returns. + */ + void enter(Probe probe); + + /** + * Receive notification that a program location's {@code void}-valued execution has just + * completed. + *

+ * Synchronous: Truffle execution waits until the call returns. + */ + void returnVoid(Probe probe); + + /** + * Receive notification that a program location's execution has just completed and returned a + * value (boxed if primitive). + *

+ * Synchronous: Truffle execution waits until the call returns. + */ + void returnValue(Probe probe, Object result); + + /** + * Receive notification that a program location's execution has just thrown an exception. + *

+ * Synchronous: Truffle execution waits until the call returns. + */ + void returnExceptional(Probe probe, Exception exception); +} diff -r dc58f4ca21c9 -r 44d8f20d4f55 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/StandardInstrumentListener.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/StandardInstrumentListener.java Mon Apr 13 21:51:19 2015 +0200 @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.api.instrument; + +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.api.source.*; + +/** + * A receiver of Truffle execution events that can act on behalf of an external client. + *

+ * The {@link Probe} argument provides access to the {@link SourceSection} associated with the + * event, as well as any {@link SyntaxTag}s that have been applied at that AST node. + *

+ * This listener is designed for clients that also require access to the AST execution state at the + * time of the event. Clients that do not require access to the AST execution state should use the + * {@link SimpleInstrumentListener}. + *

+ * Clients are free, of course, to record additional information in the listener implementation that + * carries additional information about the context and reason for the particular {@link Instrument} + * that is to be created from the listener. + */ +public interface StandardInstrumentListener { + + /** + * Receive notification that an AST node's execute method is about to be called. + *

+ * Synchronous: Truffle execution waits until the call returns. + */ + void enter(Probe probe, Node node, VirtualFrame vFrame); + + /** + * Receive notification that an AST Node's {@code void}-valued execute method has just returned. + *

+ * Synchronous: Truffle execution waits until the call returns. + */ + void returnVoid(Probe probe, Node node, VirtualFrame vFrame); + + /** + * Receive notification that an AST Node's execute method has just returned a value (boxed if + * primitive). + *

+ * Synchronous: Truffle execution waits until the call returns. + */ + void returnValue(Probe probe, Node node, VirtualFrame vFrame, Object result); + + /** + * Receive notification that an AST Node's execute method has just thrown an exception. + *

+ * Synchronous: Truffle execution waits until the call returns. + */ + void returnExceptional(Probe probe, Node node, VirtualFrame vFrame, Exception exception); +} diff -r dc58f4ca21c9 -r 44d8f20d4f55 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/DefaultASTInstrumentListener.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/DefaultASTInstrumentListener.java Mon Apr 13 21:50:37 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.truffle.api.instrument.impl; - -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.instrument.*; -import com.oracle.truffle.api.nodes.*; - -/** - * A listener for AST {@linkplain ASTInstrumentListener execution events} that provides a no-op - * implementation of every event. - */ -public class DefaultASTInstrumentListener implements ASTInstrumentListener { - - public void enter(Probe probe, Node node, VirtualFrame vFrame) { - } - - public void returnVoid(Probe probe, Node node, VirtualFrame vFrame) { - } - - public void returnValue(Probe probe, Node node, VirtualFrame vFrame, Object result) { - } - - public void returnExceptional(Probe probe, Node node, VirtualFrame vFrame, Exception exception) { - } - -} diff -r dc58f4ca21c9 -r 44d8f20d4f55 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/DefaultInstrumentListener.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/DefaultInstrumentListener.java Mon Apr 13 21:50:37 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.truffle.api.instrument.impl; - -import com.oracle.truffle.api.instrument.*; - -/** - * A listener for Truffle execution events that provides a no-op implementation of every event. - */ -public class DefaultInstrumentListener implements InstrumentListener { - - public void enter(Probe probe) { - } - - public void returnVoid(Probe probe) { - } - - public void returnValue(Probe probe, Object result) { - } - - public void returnExceptional(Probe probe, Exception exception) { - } -} diff -r dc58f4ca21c9 -r 44d8f20d4f55 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/DefaultSimpleInstrumentListener.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/DefaultSimpleInstrumentListener.java Mon Apr 13 21:51:19 2015 +0200 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.api.instrument.impl; + +import com.oracle.truffle.api.instrument.*; + +/** + * A listener for Truffle execution events that provides a no-op implementation of every event. + */ +public class DefaultSimpleInstrumentListener implements SimpleInstrumentListener { + + public void enter(Probe probe) { + } + + public void returnVoid(Probe probe) { + } + + public void returnValue(Probe probe, Object result) { + } + + public void returnExceptional(Probe probe, Exception exception) { + } +} diff -r dc58f4ca21c9 -r 44d8f20d4f55 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/DefaultStandardInstrumentListener.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/DefaultStandardInstrumentListener.java Mon Apr 13 21:51:19 2015 +0200 @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.api.instrument.impl; + +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.instrument.*; +import com.oracle.truffle.api.nodes.*; + +/** + * A listener for AST {@linkplain StandardInstrumentListener execution events} that provides a no-op + * implementation of every event. + */ +public class DefaultStandardInstrumentListener implements StandardInstrumentListener { + + public void enter(Probe probe, Node node, VirtualFrame vFrame) { + } + + public void returnVoid(Probe probe, Node node, VirtualFrame vFrame) { + } + + public void returnValue(Probe probe, Node node, VirtualFrame vFrame, Object result) { + } + + public void returnExceptional(Probe probe, Node node, VirtualFrame vFrame, Exception exception) { + } + +} diff -r dc58f4ca21c9 -r 44d8f20d4f55 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/SimpleASTInstrumentListener.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/SimpleASTInstrumentListener.java Mon Apr 13 21:50:37 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.truffle.api.instrument.impl; - -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.instrument.*; -import com.oracle.truffle.api.nodes.*; - -/** - * An abstract listener for AST {@linkplain ASTInstrumentListener execution events} that ignores - * return values and supports handling all events by overriding only two methods: - *

    - *
  • {@link #enter(Probe, Node, VirtualFrame)}, and
  • - *
  • {@link #returnAny(Probe, Node, VirtualFrame)}.
  • - *
- */ -public abstract class SimpleASTInstrumentListener implements ASTInstrumentListener { - - public void enter(Probe probe, Node node, VirtualFrame vFrame) { - } - - /** - * Receive notification that one of an AST Node's execute methods has just returned by any - * means: with or without a return value (ignored) or via exception (ignored). - * - * @param probe where the event originated - * @param node specific node of the event - * @param vFrame - */ - protected void returnAny(Probe probe, Node node, VirtualFrame vFrame) { - } - - public final void returnVoid(Probe probe, Node node, VirtualFrame vFrame) { - returnAny(probe, node, vFrame); - } - - public final void returnValue(Probe probe, Node node, VirtualFrame vFrame, Object result) { - returnAny(probe, node, vFrame); - } - - public final void returnExceptional(Probe probe, Node node, VirtualFrame vFrame, Exception e) { - returnAny(probe, node, vFrame); - } - -} diff -r dc58f4ca21c9 -r 44d8f20d4f55 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/SimpleInstrumentListener.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/SimpleInstrumentListener.java Mon Apr 13 21:50:37 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,63 +0,0 @@ -/* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.truffle.api.instrument.impl; - -import com.oracle.truffle.api.instrument.*; - -/** - * An abstract listener for Truffle {@linkplain InstrumentListener execution events} that ignores - * return values and supports handling all events by overriding only two methods: - *
    - *
  • {@link #enter(Probe)}, and
  • - *
  • {@link #returnAny(Probe)}.
  • - *
- */ -public abstract class SimpleInstrumentListener implements InstrumentListener { - - public void enter(Probe probe) { - } - - /** - * Receive notification that an execute method has just returned by any means: with or without a - * return value (ignored) or via exception (ignored). - * - * @param probe - */ - protected void returnAny(Probe probe) { - } - - public final void returnVoid(Probe probe) { - returnAny(probe); - } - - public final void returnValue(Probe probe, Object result) { - returnAny(probe); - } - - public final void returnExceptional(Probe probe, Exception e) { - returnAny(probe); - } - -} diff -r dc58f4ca21c9 -r 44d8f20d4f55 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/tools/CoverageTracker.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/tools/CoverageTracker.java Mon Apr 13 21:50:37 2015 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/tools/CoverageTracker.java Mon Apr 13 21:51:19 2015 +0200 @@ -48,7 +48,7 @@ *

*

    *
  • "Execution call" on a node is is defined as invocation of a node method that is instrumented - * to produce the event {@link InstrumentListener#enter(Probe)};
  • + * to produce the event {@link SimpleInstrumentListener#enter(Probe)}; *
  • Execution calls are tabulated only at instrumented nodes, i.e. those for which * {@linkplain Node#isInstrumentable() isInstrumentable() == true};
  • *
  • Execution calls are tabulated only at nodes present in the AST when originally created; @@ -226,7 +226,7 @@ * A listener for events at each instrumented AST location. This listener counts * "execution calls" to the instrumented node. */ - private final class CoverageRecord extends DefaultInstrumentListener { + private final class CoverageRecord extends DefaultSimpleInstrumentListener { private final SourceSection srcSection; // The text of the code being counted private Instrument instrument; // The attached Instrument, in case need to remove. diff -r dc58f4ca21c9 -r 44d8f20d4f55 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/tools/NodeExecCounter.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/tools/NodeExecCounter.java Mon Apr 13 21:50:37 2015 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/tools/NodeExecCounter.java Mon Apr 13 21:51:19 2015 +0200 @@ -49,7 +49,7 @@ *

    *

      *
    • "Execution call" on a node is is defined as invocation of a node method that is instrumented - * to produce the event {@link ASTInstrumentListener#enter(Probe, Node, VirtualFrame)};
    • + * to produce the event {@link StandardInstrumentListener#enter(Probe, Node, VirtualFrame)}; *
    • Execution calls are tabulated only at instrumented nodes, i.e. those for which * {@linkplain Node#isInstrumentable() isInstrumentable() == true};
    • *
    • Execution calls are tabulated only at nodes present in the AST when originally created; @@ -95,7 +95,7 @@ * Listener for events at instrumented nodes. Counts are maintained in a shared table, so the * listener is stateless and can be shared by every {@link Instrument}. */ - private final ASTInstrumentListener instrumentListener = new DefaultASTInstrumentListener() { + private final StandardInstrumentListener instrumentListener = new DefaultStandardInstrumentListener() { @Override public void enter(Probe probe, Node node, VirtualFrame vFrame) { if (isEnabled()) { diff -r dc58f4ca21c9 -r 44d8f20d4f55 graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/instrument/SLInstrumentTestRunner.java --- a/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/instrument/SLInstrumentTestRunner.java Mon Apr 13 21:50:37 2015 +0200 +++ b/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/instrument/SLInstrumentTestRunner.java Mon Apr 13 21:51:19 2015 +0200 @@ -274,7 +274,7 @@ * attached at {@link SLWriteLocalVariableNode}, but provides no guards to protect it from being * attached elsewhere. */ - public final class SLPrintAssigmentValueListener extends DefaultInstrumentListener { + public final class SLPrintAssigmentValueListener extends DefaultSimpleInstrumentListener { private PrintStream output; diff -r dc58f4ca21c9 -r 44d8f20d4f55 src/share/vm/graal/graalCompilerToVM.cpp --- a/src/share/vm/graal/graalCompilerToVM.cpp Mon Apr 13 21:50:37 2015 +0200 +++ b/src/share/vm/graal/graalCompilerToVM.cpp Mon Apr 13 21:51:19 2015 +0200 @@ -154,7 +154,7 @@ } } - return (jbyteArray) JNIHandles::make_local(reconstituted_code); + return (jbyteArray) JNIHandles::make_local(THREAD, reconstituted_code); C2V_END C2V_VMENTRY(jint, exceptionTableLength, (JNIEnv *, jobject, jlong metaspace_method)) @@ -576,7 +576,7 @@ } Handle result = java_lang_String::create_from_platform_dependent_str(st.as_string(), CHECK_NULL); - return JNIHandles::make_local(result()); + return JNIHandles::make_local(THREAD, result()); C2V_END C2V_VMENTRY(jobject, getStackTraceElement, (JNIEnv*, jobject, jlong metaspace_method, int bci)) @@ -585,7 +585,7 @@ methodHandle method = asMethod(metaspace_method); oop element = java_lang_StackTraceElement::create(method, bci, CHECK_NULL); - return JNIHandles::make_local(element); + return JNIHandles::make_local(THREAD, element); C2V_END C2V_VMENTRY(jobject, executeCompiledMethodVarargs, (JNIEnv*, jobject, jobject args, jobject hotspotInstalledCode)) @@ -609,7 +609,7 @@ if (jap.get_ret_type() == T_VOID) { return NULL; } else if (jap.get_ret_type() == T_OBJECT || jap.get_ret_type() == T_ARRAY) { - return JNIHandles::make_local((oop) result.get_jobject()); + return JNIHandles::make_local(THREAD, (oop) result.get_jobject()); } else { jvalue *value = (jvalue *) result.get_value_addr(); // Narrow the value down if required (Important on big endian machines) @@ -628,7 +628,7 @@ break; } oop o = java_lang_boxing_object::create(jap.get_ret_type(), value, CHECK_NULL); - return JNIHandles::make_local(o); + return JNIHandles::make_local(THREAD, o); } C2V_END @@ -656,7 +656,7 @@ i += 2; } - return (jlongArray) JNIHandles::make_local(result); + return (jlongArray) JNIHandles::make_local(THREAD, result); C2V_END C2V_VMENTRY(jlong, getLocalVariableTableStart, (JNIEnv *, jobject, jlong metaspace_method)) @@ -709,9 +709,9 @@ InstalledCode::set_address(hotspotInstalledCode, 0); C2V_END -C2V_VMENTRY(jobject, getJavaMirror, (JNIEnv*, jobject, jlong metaspace_klass)) +C2V_VMENTRY(jobject, getJavaMirror, (JNIEnv* env, jobject, jlong metaspace_klass)) Klass* klass = asKlass(metaspace_klass); - return JNIHandles::make_local(klass->java_mirror()); + return JNIHandles::make_local(THREAD, klass->java_mirror()); C2V_END C2V_VMENTRY(jlong, readUnsafeKlassPointer, (JNIEnv*, jobject, jobject o)) @@ -722,13 +722,13 @@ C2V_VMENTRY(jobject, readUncompressedOop, (JNIEnv*, jobject, jlong addr)) oop ret = oopDesc::load_decode_heap_oop((oop*)(address)addr); - return JNIHandles::make_local(ret); + return JNIHandles::make_local(THREAD, ret); C2V_END C2V_VMENTRY(jlongArray, collectCounters, (JNIEnv*, jobject)) typeArrayOop arrayOop = oopFactory::new_longArray(GraalCounterSize, CHECK_NULL); JavaThread::collect_counters(arrayOop); - return (jlongArray) JNIHandles::make_local(arrayOop); + return (jlongArray) JNIHandles::make_local(THREAD, arrayOop); C2V_END C2V_VMENTRY(int, allocateCompileId, (JNIEnv*, jobject, jlong metaspace_method, int entry_bci)) diff -r dc58f4ca21c9 -r 44d8f20d4f55 src/share/vm/graal/graalRuntime.cpp --- a/src/share/vm/graal/graalRuntime.cpp Mon Apr 13 21:50:37 2015 +0200 +++ b/src/share/vm/graal/graalRuntime.cpp Mon Apr 13 21:51:19 2015 +0200 @@ -647,7 +647,7 @@ TempNewSymbol sig = SymbolTable::new_symbol("()Lcom/oracle/truffle/api/TruffleRuntime;", CHECK_NULL); JavaValue result(T_OBJECT); JavaCalls::call_static(&result, klass, makeInstance, sig, CHECK_NULL); - return JNIHandles::make_local((oop) result.get_jobject()); + return JNIHandles::make_local(THREAD, (oop) result.get_jobject()); JVM_END // private static NativeFunctionInterfaceRuntime.createInterface() @@ -660,7 +660,7 @@ TempNewSymbol sig = SymbolTable::new_symbol("()Lcom/oracle/nfi/api/NativeFunctionInterface;", CHECK_NULL); JavaValue result(T_OBJECT); JavaCalls::call_static(&result, klass, makeInstance, sig, CHECK_NULL); - return JNIHandles::make_local((oop) result.get_jobject()); + return JNIHandles::make_local(THREAD, (oop) result.get_jobject()); JVM_END void GraalRuntime::check_generated_sources_sha1(TRAPS) {