# HG changeset patch # User Stefan Anzinger # Date 1426242481 -3600 # Node ID 7d74d3ad09f4581d73be53ecaf7c8fb50232bd71 # Parent 9f1404a45a6f96c77b9e878ed0f4034bad7d891b# Parent a5b09092003af9c7740fc5cfc60102589bde77fd Merge diff -r 9f1404a45a6f -r 7d74d3ad09f4 graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/GraalOptions.java --- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/GraalOptions.java Thu Mar 12 17:08:19 2015 +0100 +++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/GraalOptions.java Fri Mar 13 11:28:01 2015 +0100 @@ -134,9 +134,6 @@ @Option(help = "", type = OptionType.Debug) public static final OptionValue PrintFilter = new OptionValue<>(null); - @Option(help = "", type = OptionType.Debug) - public static final StableOptionValue DumpDuringGraphBuilding = new StableOptionValue<>(false); - // Debug settings: @Option(help = "", type = OptionType.Debug) public static final OptionValue BootstrapReplacements = new OptionValue<>(false); @@ -324,13 +321,6 @@ @Option(help = "Mark well-known stable fields as such.", type = OptionType.Debug) public static final OptionValue ImplicitStableValues = new OptionValue<>(true); - - @Option(help = "Max number of loop explosions per method.", type = OptionType.Debug) - public static final OptionValue MaximumLoopExplosionCount = new OptionValue<>(10000); - - @Option(help = "Do not bail out but throw an exception on failed loop explosion.", type = OptionType.Debug) - public static final OptionValue FailedLoopExplosionIsFatal = new OptionValue<>(false); - /** * Counts the various paths taken through snippets. */ diff -r 9f1404a45a6f -r 7d74d3ad09f4 graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java --- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java Thu Mar 12 17:08:19 2015 +0100 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java Fri Mar 13 11:28:01 2015 +0100 @@ -182,9 +182,7 @@ NodeClass snc = superNodeClass; while (snc != null && IterableNodeType.class.isAssignableFrom(snc.getClazz())) { - assert !containsId(this.iterableId, snc.iterableIds); - snc.iterableIds = Arrays.copyOf(snc.iterableIds, snc.iterableIds.length + 1); - snc.iterableIds[snc.iterableIds.length - 1] = this.iterableId; + snc.addIterableId(iterableId); snc = snc.superNodeClass; } @@ -195,6 +193,23 @@ this.iterableIds = null; } nodeIterableCount = Debug.metric("NodeIterable_%s", clazz); + assert verifyIterableIds(); + } + + private synchronized void addIterableId(int newIterableId) { + assert !containsId(newIterableId, iterableIds); + int[] copy = Arrays.copyOf(iterableIds, iterableIds.length + 1); + copy[iterableIds.length] = newIterableId; + iterableIds = copy; + } + + private boolean verifyIterableIds() { + NodeClass snc = superNodeClass; + while (snc != null && IterableNodeType.class.isAssignableFrom(snc.getClazz())) { + assert containsId(iterableId, snc.iterableIds); + snc = snc.superNodeClass; + } + return true; } private static boolean containsId(int iterableId, int[] iterableIds) { diff -r 9f1404a45a6f -r 7d74d3ad09f4 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java Thu Mar 12 17:08:19 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java Fri Mar 13 11:28:01 2015 +0100 @@ -1444,6 +1444,7 @@ @HotSpotVMValue(expression = "SharedRuntime::dsin", get = HotSpotVMValue.Type.ADDRESS) @Stable public long arithmeticSinAddress; @HotSpotVMValue(expression = "SharedRuntime::dcos", get = HotSpotVMValue.Type.ADDRESS) @Stable public long arithmeticCosAddress; @HotSpotVMValue(expression = "SharedRuntime::dtan", get = HotSpotVMValue.Type.ADDRESS) @Stable public long arithmeticTanAddress; + @HotSpotVMValue(expression = "SharedRuntime::dpow", get = HotSpotVMValue.Type.ADDRESS) @Stable public long arithmeticPowAddress; @HotSpotVMValue(expression = "(jint) GraalCounterSize") @Stable public int graalCountersSize; diff -r 9f1404a45a6f -r 7d74d3ad09f4 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostForeignCallsProvider.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostForeignCallsProvider.java Thu Mar 12 17:08:19 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostForeignCallsProvider.java Fri Mar 13 11:28:01 2015 +0100 @@ -150,6 +150,7 @@ registerForeignCall(ARITHMETIC_SIN, c.arithmeticSinAddress, NativeCall, DESTROYS_REGISTERS, LEAF, REEXECUTABLE, NO_LOCATIONS); registerForeignCall(ARITHMETIC_COS, c.arithmeticCosAddress, NativeCall, DESTROYS_REGISTERS, LEAF, REEXECUTABLE, NO_LOCATIONS); registerForeignCall(ARITHMETIC_TAN, c.arithmeticTanAddress, NativeCall, DESTROYS_REGISTERS, LEAF, REEXECUTABLE, NO_LOCATIONS); + registerForeignCall(ARITHMETIC_POW, c.arithmeticPowAddress, NativeCall, DESTROYS_REGISTERS, LEAF, REEXECUTABLE, NO_LOCATIONS); registerForeignCall(LOAD_AND_CLEAR_EXCEPTION, c.loadAndClearExceptionAddress, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, ANY_LOCATION); registerForeignCall(EXCEPTION_HANDLER_FOR_PC, c.exceptionHandlerForPcAddress, NativeCall, DESTROYS_REGISTERS, NOT_LEAF, REEXECUTABLE, ANY_LOCATION); diff -r 9f1404a45a6f -r 7d74d3ad09f4 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInlineInvokePlugin.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInlineInvokePlugin.java Thu Mar 12 17:08:19 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInlineInvokePlugin.java Fri Mar 13 11:28:01 2015 +0100 @@ -27,10 +27,10 @@ import static java.lang.String.*; import com.oracle.graal.api.meta.*; -import com.oracle.graal.api.replacements.*; import com.oracle.graal.graph.Node.NodeIntrinsic; import com.oracle.graal.hotspot.word.*; import com.oracle.graal.java.*; +import com.oracle.graal.java.GraphBuilderContext.Replacement; import com.oracle.graal.java.GraphBuilderPlugin.InlineInvokePlugin; import com.oracle.graal.nodes.*; import com.oracle.graal.replacements.*; @@ -69,8 +69,10 @@ public void notifyOfNoninlinedInvoke(GraphBuilderContext b, ResolvedJavaMethod method, Invoke invoke) { if (b.parsingReplacement()) { - boolean compilingSnippet = b.getRootMethod().getAnnotation(MethodSubstitution.class) == null; - assert compilingSnippet : format("All calls in the replacement %s must be inlined or intrinsified: found call to %s", b.getRootMethod().format("%H.%n(%p)"), method.format("%h.%n(%p)")); + boolean compilingSnippet = b.getRootMethod().getAnnotation(Snippet.class) != null; + Replacement replacement = b.getReplacement(); + assert compilingSnippet : format("All calls in the replacement %s must be inlined or intrinsified: found call to %s", replacement.getReplacementMethod().format("%H.%n(%p)"), + method.format("%h.%n(%p)")); } } } diff -r 9f1404a45a6f -r 7d74d3ad09f4 graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractBytecodeParser.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractBytecodeParser.java Thu Mar 12 17:08:19 2015 +0100 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractBytecodeParser.java Fri Mar 13 11:28:01 2015 +0100 @@ -27,6 +27,7 @@ import static com.oracle.graal.api.meta.DeoptimizationReason.*; import static com.oracle.graal.bytecode.Bytecodes.*; import static com.oracle.graal.java.AbstractBytecodeParser.Options.*; + import java.util.*; import com.oracle.graal.api.code.*; @@ -37,6 +38,7 @@ import com.oracle.graal.compiler.common.calc.*; import com.oracle.graal.debug.*; import com.oracle.graal.java.BciBlockMapping.BciBlock; +import com.oracle.graal.java.GraphBuilderContext.Replacement; import com.oracle.graal.java.GraphBuilderPhase.Instance.BytecodeParser; import com.oracle.graal.java.GraphBuilderPlugin.LoadFieldPlugin; import com.oracle.graal.java.GraphBuilderPlugin.LoadIndexedPlugin; @@ -51,18 +53,27 @@ @Option(help = "The trace level for the bytecode parser used when building a graph from bytecode", type = OptionType.Debug) public static final OptionValue TraceBytecodeParserLevel = new OptionValue<>(0); - @Option(help = "Inlines trivial methods during parsing of the bytecodes.", type = OptionType.Expert) + @Option(help = "Inlines trivial methods during bytecode parsing.", type = OptionType.Expert) public static final StableOptionValue InlineDuringParsing = new StableOptionValue<>(false); - @Option(help = "Traces inlining eagerly performed during bytecode parsing", type = OptionType.Debug) + @Option(help = "Traces inlining performed during bytecode parsing.", type = OptionType.Debug) public static final StableOptionValue TraceInlineDuringParsing = new StableOptionValue<>(false); - @Option(help = "Traces use of bytecode parser plugins", type = OptionType.Debug) + @Option(help = "Traces use of plugins during bytecode parsing.", type = OptionType.Debug) public static final StableOptionValue TraceParserPlugins = new StableOptionValue<>(false); - @Option(help = "Maximum depth when inlining during parsing.", type = OptionType.Debug) + @Option(help = "Maximum depth when inlining during bytecode parsing.", type = OptionType.Debug) public static final StableOptionValue InlineDuringParsingMaxDepth = new StableOptionValue<>(10); + @Option(help = "Dump graphs after non-trivial changes during bytecode parsing.", type = OptionType.Debug) + public static final StableOptionValue DumpDuringGraphBuilding = new StableOptionValue<>(false); + + @Option(help = "Max number of loop explosions per method.", type = OptionType.Debug) + public static final OptionValue MaximumLoopExplosionCount = new OptionValue<>(10000); + + @Option(help = "Do not bail out but throw an exception on failed loop explosion.", type = OptionType.Debug) + public static final OptionValue FailedLoopExplosionIsFatal = new OptionValue<>(false); + // @formatter:on } @@ -71,7 +82,7 @@ * happen when a call to a {@link MethodSubstitution} is encountered or the root of compilation * is a {@link MethodSubstitution} or a snippet. */ - static class ReplacementContext { + static class ReplacementContext implements Replacement { /** * The method being replaced. */ @@ -87,6 +98,18 @@ this.replacement = substitute; } + public ResolvedJavaMethod getOriginalMethod() { + return method; + } + + public ResolvedJavaMethod getReplacementMethod() { + return replacement; + } + + public boolean isIntrinsic() { + return false; + } + /** * Determines if a call within the compilation scope of a replacement represents a call to * the original method. @@ -102,7 +125,7 @@ /** * Context for a replacement being inlined as a compiler intrinsic. Deoptimization within a - * compiler intrinic must replay the intrinsified call. This context object retains the + * compiler intrinsic must replay the intrinsified call. This context object retains the * information required to build a frame state denoting the JVM state just before the * intrinsified call. */ @@ -127,6 +150,11 @@ this.invokeBci = invokeBci; } + @Override + public boolean isIntrinsic() { + return true; + } + /** * Gets the frame state that will restart the interpreter just before the intrinsified * invocation. diff -r 9f1404a45a6f -r 7d74d3ad09f4 graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderContext.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderContext.java Thu Mar 12 17:08:19 2015 +0100 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderContext.java Fri Mar 13 11:28:01 2015 +0100 @@ -34,6 +34,30 @@ */ public interface GraphBuilderContext { + /** + * Information about a snippet or method substitution currently being processed by the graph + * builder. + */ + public interface Replacement { + + /** + * Gets the method being replaced. + */ + ResolvedJavaMethod getOriginalMethod(); + + /** + * Gets the replacement method. + */ + ResolvedJavaMethod getReplacementMethod(); + + /** + * Determines if this replacement is being inlined as a compiler intrinsic. A compiler + * intrinsic is atomic with respect to deoptimization. Deoptimization within a compiler + * intrinsic will restart the interpreter at the intrinsified call. + */ + boolean isIntrinsic(); + } + T append(T fixed); T append(T fixed); @@ -87,7 +111,15 @@ /** * Determines if the current parsing context is a snippet or method substitution. */ - boolean parsingReplacement(); + default boolean parsingReplacement() { + return getReplacement() == null; + } + + /** + * Gets the replacement of the current parsing context or {@code null} if not + * {@link #parsingReplacement() parsing a replacement}. + */ + Replacement getReplacement(); /** * @see GuardingPiNode#nullCheckedValue(ValueNode) diff -r 9f1404a45a6f -r 7d74d3ad09f4 graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java Thu Mar 12 17:08:19 2015 +0100 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java Fri Mar 13 11:28:01 2015 +0100 @@ -461,7 +461,7 @@ for (int i = loopBegins.size() - 1; i >= 0; --i) { LoopBeginNode loopBegin = loopBegins.get(i); insertLoopExits(loopBegin, innerLoopsMap); - if (GraalOptions.DumpDuringGraphBuilding.getValue()) { + if (DumpDuringGraphBuilding.getValue()) { Debug.dump(currentGraph, "After building loop exits for %s.", loopBegin); } } @@ -527,7 +527,7 @@ for (LoopBeginNode inner : innerLoopBegins) { addLoopExits(loopBegin, inner, innerLoopsMap, visited); - if (GraalOptions.DumpDuringGraphBuilding.getValue()) { + if (DumpDuringGraphBuilding.getValue()) { Debug.dump(currentGraph, "After adding loop exits for %s.", inner); } } @@ -1210,9 +1210,10 @@ } ReplacementContext context = this.replacementContext; if (context != null && context.isCallToOriginal(targetMethod)) { + assert context.asIntrinsic() == null : "intrinsic cannot call the method it is intrinsifying"; // Self recursive replacement means the original // method should be called. - if (targetMethod.hasBytecodes()) { + if (context.method.hasBytecodes()) { parseAndInlineCallee(context.method, args, null); } else { return false; @@ -1225,9 +1226,13 @@ context = new ReplacementContext(targetMethod, inlinedMethod); } } - parseAndInlineCallee(inlinedMethod, args, context); - if (plugin != null) { - plugin.postInline(inlinedMethod); + if (inlinedMethod.hasBytecodes()) { + parseAndInlineCallee(inlinedMethod, args, context); + if (plugin != null) { + plugin.postInline(inlinedMethod); + } + } else { + return false; } } return true; @@ -2350,6 +2355,10 @@ return parent == null ? 0 : 1 + parent.getDepth(); } + public Replacement getReplacement() { + return replacementContext; + } + public ResolvedJavaMethod getRootMethod() { return rootMethod; } diff -r 9f1404a45a6f -r 7d74d3ad09f4 graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPlugin.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPlugin.java Thu Mar 12 17:08:19 2015 +0100 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPlugin.java Fri Mar 13 11:28:01 2015 +0100 @@ -77,7 +77,7 @@ /** * The method to be inlined. If this is not equal to the {@code method} argument passed * to {@link InlineInvokePlugin#getClass()}, the graph builder context interprets it as - * a {@linkplain GraphBuilderContext#parsingReplacement() replacement}. + * a {@linkplain GraphBuilderContext.Replacement replacement}. */ public final ResolvedJavaMethod methodToInline; diff -r 9f1404a45a6f -r 7d74d3ad09f4 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 Thu Mar 12 17:08:19 2015 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java Fri Mar 13 11:28:01 2015 +0100 @@ -438,10 +438,11 @@ } else { // only handle the outermost frame states if (frameState.outerFrameState() == null) { + assert frameState.bci != BytecodeFrame.AFTER_EXCEPTION_BCI : frameState; assert frameState.bci != BytecodeFrame.BEFORE_BCI : frameState; - assert frameState.bci == BytecodeFrame.INVALID_FRAMESTATE_BCI || frameState.method().equals(inlineGraph.method()); - assert frameState.bci != BytecodeFrame.AFTER_EXCEPTION_BCI && frameState.bci != BytecodeFrame.BEFORE_BCI && frameState.bci != BytecodeFrame.AFTER_EXCEPTION_BCI && - frameState.bci != BytecodeFrame.UNWIND_BCI : frameState.bci; + assert frameState.bci != BytecodeFrame.UNKNOWN_BCI : frameState; + assert frameState.bci != BytecodeFrame.UNWIND_BCI : frameState; + assert frameState.bci == BytecodeFrame.INVALID_FRAMESTATE_BCI || frameState.method().equals(inlineGraph.method()) : frameState; if (outerFrameState == null) { outerFrameState = stateAtReturn.duplicateModifiedDuringCall(invoke.bci(), invokeReturnKind); } diff -r 9f1404a45a6f -r 7d74d3ad09f4 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ReplacementsParseTest.java --- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ReplacementsParseTest.java Thu Mar 12 17:08:19 2015 +0100 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ReplacementsParseTest.java Fri Mar 13 11:28:01 2015 +0100 @@ -51,16 +51,6 @@ static class TestMethodsSubstitutions { @MethodSubstitution(isStatic = true) - static double next(double v) { - return TestMethods.next(v); - } - - @MethodSubstitution(isStatic = true) - static double next2(double v) { - return next2(v); - } - - @MethodSubstitution(isStatic = true) static double nextAfter(double x, double d) { double xx = (x == -0.0 ? 0.0 : x); return Math.nextAfter(xx, d); diff -r 9f1404a45a6f -r 7d74d3ad09f4 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/StandardMethodSubstitutionsTest.java --- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/StandardMethodSubstitutionsTest.java Thu Mar 12 17:08:19 2015 +0100 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/StandardMethodSubstitutionsTest.java Fri Mar 13 11:28:01 2015 +0100 @@ -57,42 +57,68 @@ test("mathAll", value); } - @SuppressWarnings("all") + @Test + public void testMathPow() { + double a = 34567.891D; + double b = 4.6D; + test("mathPow", a, b); + + // Test the values directly handled by the substitution + + // If the second argument is positive or negative zero, then the result is 1.0. + test("mathPow", a, 0.0D); + test("mathPow", a, -0.0D); + // If the second argument is 1.0, then the result is the same as the first argument. + test("mathPow", a, 1.0D); + // If the second argument is NaN, then the result is NaN. + test("mathPow", a, Double.NaN); + // If the first argument is NaN and the second argument is nonzero, then the result is NaN. + test("mathPow", Double.NaN, b); + test("mathPow", Double.NaN, 0.0D); + // x**-1 = 1/x + test("mathPow", a, -1.0D); + // x**2 = x*x + test("mathPow", a, 2.0D); + // x**0.5 = sqrt(x) + test("mathPow", a, 0.5D); + } + + public static double mathPow(double a, double b) { + return mathPow0(a, b); + } + + public static double mathPow0(double a, double b) { + return Math.pow(a, b); + } + public static double mathAbs(double value) { return Math.abs(value); } - @SuppressWarnings("all") public static double mathSqrt(double value) { return Math.sqrt(value); } - @SuppressWarnings("all") public static double mathLog(double value) { return Math.log(value); } - @SuppressWarnings("all") public static double mathLog10(double value) { return Math.log10(value); } - @SuppressWarnings("all") public static double mathSin(double value) { return Math.sin(value); } - @SuppressWarnings("all") public static double mathCos(double value) { return Math.cos(value); } - @SuppressWarnings("all") public static double mathTan(double value) { return Math.tan(value); } - @SuppressWarnings("all") public static double mathAll(double value) { return Math.sqrt(value) + Math.log(value) + Math.log10(value) + Math.sin(value) + Math.cos(value) + Math.tan(value); } @@ -130,22 +156,18 @@ testSubstitution("integerBitCount", BitCountNode.class, Integer.class, "bitCount", true, args); } - @SuppressWarnings("all") public static int integerReverseBytes(int value) { return Integer.reverseBytes(value); } - @SuppressWarnings("all") public static int integerNumberOfLeadingZeros(int value) { return Integer.numberOfLeadingZeros(value); } - @SuppressWarnings("all") public static int integerNumberOfTrailingZeros(int value) { return Integer.numberOfTrailingZeros(value); } - @SuppressWarnings("all") public static int integerBitCount(int value) { return Integer.bitCount(value); } @@ -160,22 +182,18 @@ testSubstitution("longBitCount", BitCountNode.class, Long.class, "bitCount", true, args); } - @SuppressWarnings("all") public static long longReverseBytes(long value) { return Long.reverseBytes(value); } - @SuppressWarnings("all") public static int longNumberOfLeadingZeros(long value) { return Long.numberOfLeadingZeros(value); } - @SuppressWarnings("all") public static int longNumberOfTrailingZeros(long value) { return Long.numberOfTrailingZeros(value); } - @SuppressWarnings("all") public static int longBitCount(long value) { return Long.bitCount(value); } @@ -186,12 +204,10 @@ testGraph("intBitsToFloat"); } - @SuppressWarnings("all") public static int floatToIntBits(float value) { return Float.floatToIntBits(value); } - @SuppressWarnings("all") public static float intBitsToFloat(int value) { return Float.intBitsToFloat(value); } @@ -202,22 +218,18 @@ testGraph("longBitsToDouble"); } - @SuppressWarnings("all") public static long doubleToLongBits(double value) { return Double.doubleToLongBits(value); } - @SuppressWarnings("all") public static double longBitsToDouble(long value) { return Double.longBitsToDouble(value); } - @SuppressWarnings("all") public static boolean isInstance(Class clazz, Object object) { return clazz.isInstance(object); } - @SuppressWarnings("all") public static boolean isAssignableFrom(Class clazz, Class other) { return clazz.isAssignableFrom(other); } diff -r 9f1404a45a6f -r 7d74d3ad09f4 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/MathSubstitutionsX86.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/MathSubstitutionsX86.java Thu Mar 12 17:08:19 2015 +0100 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/MathSubstitutionsX86.java Fri Mar 13 11:28:01 2015 +0100 @@ -46,12 +46,12 @@ @MethodSubstitution(guard = MathGuard.class) public static double pow(double x, double y) { // If the second argument is positive or negative zero, then the result is 1.0. - if (y == 0) { + if (y == 0.0D) { return 1; } // If the second argument is 1.0, then the result is the same as the first argument. - if (y == 1) { + if (y == 1.0D) { return x; } @@ -61,26 +61,25 @@ } // If the first argument is NaN and the second argument is nonzero, then the result is NaN. - if (Double.isNaN(x) && y != 0) { + if (Double.isNaN(x) && y != 0.0D) { return Double.NaN; } // x**-1 = 1/x - if (y == -1) { + if (y == -1.0D) { return 1 / x; } // x**2 = x*x - if (y == 2) { + if (y == 2.0D) { return x * x; } // x**0.5 = sqrt(x) - if (y == 0.5 && x >= 0) { + if (y == 0.5D && x >= 0.0D) { return Math.sqrt(x); } - - return pow(x, y); + return callDouble2(ARITHMETIC_POW, x, y); } // NOTE on snippets below: @@ -94,7 +93,7 @@ if (Math.abs(x) < PI_4) { return MathIntrinsicNode.compute(x, Operation.SIN); } else { - return callDouble(ARITHMETIC_SIN, x); + return callDouble1(ARITHMETIC_SIN, x); } } @@ -103,7 +102,7 @@ if (Math.abs(x) < PI_4) { return MathIntrinsicNode.compute(x, Operation.COS); } else { - return callDouble(ARITHMETIC_COS, x); + return callDouble1(ARITHMETIC_COS, x); } } @@ -112,7 +111,7 @@ if (Math.abs(x) < PI_4) { return MathIntrinsicNode.compute(x, Operation.TAN); } else { - return callDouble(ARITHMETIC_TAN, x); + return callDouble1(ARITHMETIC_TAN, x); } } @@ -127,7 +126,11 @@ public static final ForeignCallDescriptor ARITHMETIC_SIN = new ForeignCallDescriptor("arithmeticSin", double.class, double.class); public static final ForeignCallDescriptor ARITHMETIC_COS = new ForeignCallDescriptor("arithmeticCos", double.class, double.class); public static final ForeignCallDescriptor ARITHMETIC_TAN = new ForeignCallDescriptor("arithmeticTan", double.class, double.class); + public static final ForeignCallDescriptor ARITHMETIC_POW = new ForeignCallDescriptor("arithmeticPow", double.class, double.class, double.class); @NodeIntrinsic(value = ForeignCallNode.class, setStampFromReturnType = true) - public static native double callDouble(@ConstantNodeParameter ForeignCallDescriptor descriptor, double value); + private static native double callDouble1(@ConstantNodeParameter ForeignCallDescriptor descriptor, double value); + + @NodeIntrinsic(value = ForeignCallNode.class, setStampFromReturnType = true) + private static native double callDouble2(@ConstantNodeParameter ForeignCallDescriptor descriptor, double a, double b); } diff -r 9f1404a45a6f -r 7d74d3ad09f4 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 Thu Mar 12 17:08:19 2015 +0100 +++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/InstrumentationPartialEvaluationTest.java Fri Mar 13 11:28:01 2015 +0100 @@ -61,72 +61,144 @@ } @Test - public void constantValueProbedNullInstrument() { + public void constantValueProbedNullInstrument1() { + FrameDescriptor fd = new FrameDescriptor(); + AbstractTestNode result = new ConstantTestNode(42); + RootTestNode root = new RootTestNode(fd, "constantValue", result); + root.adoptChildren(); + Probe probe = result.probe(); + Instrument instrument = Instrument.create(new DefaultInstrumentListener(), "Null test Instrument"); + probe.attach(instrument); + assertPartialEvalEquals("constant42", root); + } + + @Test + public void constantValueProbedNullInstrument2() { FrameDescriptor fd = new FrameDescriptor(); AbstractTestNode result = new ConstantTestNode(42); RootTestNode root = new RootTestNode(fd, "constantValue", result); root.adoptChildren(); Probe probe = result.probe(); - Instrument instrument = Instrument.create(new DefaultEventListener(), "Null test Instrument"); + Instrument instrument = Instrument.create(new DefaultASTInstrumentListener(), "Null test Instrument"); probe.attach(instrument); assertPartialEvalEquals("constant42", root); } @Test - public void constantValueProbedNullInstrumentDisposed() { + public void constantValueProbedNullInstrumentDisposed1() { FrameDescriptor fd = new FrameDescriptor(); AbstractTestNode result = new ConstantTestNode(42); RootTestNode root = new RootTestNode(fd, "constantValue", result); root.adoptChildren(); Probe probe = result.probe(); - Instrument instrument = Instrument.create(new DefaultEventListener(), "Null test Instrument"); + Instrument instrument = Instrument.create(new DefaultInstrumentListener(), "Null test Instrument"); + probe.attach(instrument); + instrument.dispose(); + assertPartialEvalEquals("constant42", root); + } + + @Test + public void constantValueProbedNullInstrumentDisposed2() { + FrameDescriptor fd = new FrameDescriptor(); + AbstractTestNode result = new ConstantTestNode(42); + RootTestNode root = new RootTestNode(fd, "constantValue", result); + root.adoptChildren(); + Probe probe = result.probe(); + Instrument instrument = Instrument.create(new DefaultASTInstrumentListener(), "Null test Instrument"); probe.attach(instrument); instrument.dispose(); assertPartialEvalEquals("constant42", root); } @Test - public void constantValueProbedTwoNullInstruments() { + public void constantValueProbedTwoNullInstruments1() { FrameDescriptor fd = new FrameDescriptor(); AbstractTestNode result = new ConstantTestNode(42); RootTestNode root = new RootTestNode(fd, "constantValue", result); root.adoptChildren(); Probe probe = result.probe(); - Instrument instrument1 = Instrument.create(new DefaultEventListener(), "Null test Instrument 1"); + Instrument instrument1 = Instrument.create(new DefaultInstrumentListener(), "Null test Instrument 1"); probe.attach(instrument1); - Instrument instrument2 = Instrument.create(new DefaultEventListener(), "Null test Instrument 2"); + Instrument instrument2 = Instrument.create(new DefaultInstrumentListener(), "Null test Instrument 2"); probe.attach(instrument2); assertPartialEvalEquals("constant42", root); } @Test - public void constantValueProbedThreeNullInstruments() { + public void constantValueProbedTwoNullInstruments2() { + FrameDescriptor fd = new FrameDescriptor(); + AbstractTestNode result = new ConstantTestNode(42); + RootTestNode root = new RootTestNode(fd, "constantValue", result); + root.adoptChildren(); + Probe probe = result.probe(); + Instrument instrument1 = Instrument.create(new DefaultASTInstrumentListener(), "Null test Instrument 1"); + probe.attach(instrument1); + Instrument instrument2 = Instrument.create(new DefaultASTInstrumentListener(), "Null test Instrument 2"); + probe.attach(instrument2); + assertPartialEvalEquals("constant42", root); + } + + @Test + public void constantValueProbedThreeNullInstruments1() { FrameDescriptor fd = new FrameDescriptor(); AbstractTestNode result = new ConstantTestNode(42); RootTestNode root = new RootTestNode(fd, "constantValue", result); root.adoptChildren(); Probe probe = result.probe(); - Instrument instrument1 = Instrument.create(new DefaultEventListener(), "Null test Instrument 1"); + Instrument instrument1 = Instrument.create(new DefaultInstrumentListener(), "Null test Instrument 1"); probe.attach(instrument1); - Instrument instrument2 = Instrument.create(new DefaultEventListener(), "Null test Instrument 2"); + Instrument instrument2 = Instrument.create(new DefaultInstrumentListener(), "Null test Instrument 2"); probe.attach(instrument2); - Instrument instrument3 = Instrument.create(new DefaultEventListener(), "Null test Instrument 3"); + Instrument instrument3 = Instrument.create(new DefaultInstrumentListener(), "Null test Instrument 3"); + probe.attach(instrument3); + assertPartialEvalEquals("constant42", root); + } + + @Test + public void constantValueProbedThreeNullInstruments2() { + FrameDescriptor fd = new FrameDescriptor(); + AbstractTestNode result = new ConstantTestNode(42); + RootTestNode root = new RootTestNode(fd, "constantValue", result); + root.adoptChildren(); + Probe probe = result.probe(); + Instrument instrument1 = Instrument.create(new DefaultASTInstrumentListener(), "Null test Instrument 1"); + probe.attach(instrument1); + Instrument instrument2 = Instrument.create(new DefaultASTInstrumentListener(), "Null test Instrument 2"); + probe.attach(instrument2); + Instrument instrument3 = Instrument.create(new DefaultASTInstrumentListener(), "Null test Instrument 3"); probe.attach(instrument3); assertPartialEvalEquals("constant42", root); } @Test - public void constantValueProbedThreeNullInstrumentsOneDisposed() { + public void constantValueProbedThreeNullInstrumentsOneDisposed1() { FrameDescriptor fd = new FrameDescriptor(); AbstractTestNode result = new ConstantTestNode(42); RootTestNode root = new RootTestNode(fd, "constantValue", result); root.adoptChildren(); Probe probe = result.probe(); - Instrument instrument1 = Instrument.create(new DefaultEventListener(), "Null test Instrument 1"); + Instrument instrument1 = Instrument.create(new DefaultInstrumentListener(), "Null test Instrument 1"); probe.attach(instrument1); - Instrument instrument2 = Instrument.create(new DefaultEventListener(), "Null test Instrument 2"); + Instrument instrument2 = Instrument.create(new DefaultInstrumentListener(), "Null test Instrument 2"); probe.attach(instrument2); - Instrument instrument3 = Instrument.create(new DefaultEventListener(), "Null test Instrument 3"); + Instrument instrument3 = Instrument.create(new DefaultInstrumentListener(), "Null test Instrument 3"); + probe.attach(instrument3); + instrument2.dispose(); + assertPartialEvalEquals("constant42", root); + } + + @Test + public void constantValueProbedThreeNullInstrumentsOneDisposed2() { + FrameDescriptor fd = new FrameDescriptor(); + AbstractTestNode result = new ConstantTestNode(42); + RootTestNode root = new RootTestNode(fd, "constantValue", result); + root.adoptChildren(); + Probe probe = result.probe(); + Instrument instrument1 = Instrument.create(new DefaultASTInstrumentListener(), "Null test Instrument 1"); + probe.attach(instrument1); + Instrument instrument2 = Instrument.create(new DefaultASTInstrumentListener(), "Null test Instrument 2"); + probe.attach(instrument2); + Instrument instrument3 = Instrument.create(new DefaultASTInstrumentListener(), "Null test Instrument 3"); probe.attach(instrument3); instrument2.dispose(); assertPartialEvalEquals("constant42", root); @@ -167,13 +239,13 @@ 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 DefaultEventListener() { + final Instrument countingInstrument = Instrument.create(new DefaultInstrumentListener() { @Override - public void enter(Node node, VirtualFrame frame) { + public void enter(Probe p) { count[0] = count[0] + 1; } - }); + }, null); probe[0].attach(countingInstrument); Assert.assertEquals(42, callTarget.call()); // Correct result diff -r 9f1404a45a6f -r 7d74d3ad09f4 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 Thu Mar 12 17:08:19 2015 +0100 +++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/InstrumentationTest.java Fri Mar 13 11:28:01 2015 +0100 @@ -83,7 +83,7 @@ }; @Test - public void testBasicInstrumentation() { + public void testInstrumentationStructure() { // Create a simple addition AST final TruffleRuntime runtime = Truffle.getRuntime(); final TestValueNode leftValueNode = new TestValueNode(6); @@ -117,7 +117,7 @@ assertEquals(13, callTarget1.call()); // Probe the addition node - final Probe probe = addNode.probe(); + addNode.probe(); // Check the modified tree structure assertEquals(addNode, leftValueNode.getParent()); @@ -153,103 +153,129 @@ // Check that the "probed" AST still executes correctly assertEquals(13, callTarget1.call()); + } + + @Test + public void testListeners() { + + // Create a simple addition AST + final TruffleRuntime runtime = Truffle.getRuntime(); + final TestValueNode leftValueNode = new TestValueNode(6); + final TestValueNode rightValueNode = new TestValueNode(7); + final TestAdditionNode addNode = new TestAdditionNode(leftValueNode, rightValueNode); + final TestRootNode rootNode = new TestRootNode(addNode); + + // Creating a call target sets the parent pointers in this tree and is necessary prior to + // checking any parent/child relationships + final CallTarget callTarget = runtime.createCallTarget(rootNode); + // Probe the addition node + final Probe probe = addNode.probe(); + + // 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()); + + // Now try with the more complex flavor of listener + checkCounters(probe, callTarget, rootNode, new TestASTInstrumentCounter(), new TestASTInstrumentCounter(), new TestASTInstrumentCounter()); + + } + + private static void checkCounters(Probe probe, CallTarget callTarget, RootNode rootNode, TestCounter counterA, TestCounter counterB, TestCounter counterC) { + // Attach a counting instrument to the probe - final TestCounter counterA = new TestCounter(); counterA.attach(probe); // Attach a second counting instrument to the probe - final TestCounter counterB = new TestCounter(); counterB.attach(probe); // Run it again and check that the two instruments are working - assertEquals(13, callTarget1.call()); - assertEquals(counterA.enterCount, 1); - assertEquals(counterA.leaveCount, 1); - assertEquals(counterB.enterCount, 1); - assertEquals(counterB.leaveCount, 1); + assertEquals(13, callTarget.call()); + assertEquals(counterA.enterCount(), 1); + assertEquals(counterA.leaveCount(), 1); + assertEquals(counterB.enterCount(), 1); + assertEquals(counterB.leaveCount(), 1); - // Remove counterA and check the "instrument chain" + // Remove counterA counterA.dispose(); - iterator = probeNode.getChildren().iterator(); // Run it again and check that instrument B is still working but not A - assertEquals(13, callTarget1.call()); - assertEquals(counterA.enterCount, 1); - assertEquals(counterA.leaveCount, 1); - assertEquals(counterB.enterCount, 2); - assertEquals(counterB.leaveCount, 2); + assertEquals(13, callTarget.call()); + assertEquals(counterA.enterCount(), 1); + assertEquals(counterA.leaveCount(), 1); + assertEquals(counterB.enterCount(), 2); + assertEquals(counterB.leaveCount(), 2); // Simulate a split by cloning the AST - final CallTarget callTarget2 = runtime.createCallTarget((TestRootNode) rootNode.copy()); + final CallTarget callTarget2 = Truffle.getRuntime().createCallTarget((TestRootNode) rootNode.copy()); // Run the clone and check that instrument B is still working but not A assertEquals(13, callTarget2.call()); - assertEquals(counterA.enterCount, 1); - assertEquals(counterA.leaveCount, 1); - assertEquals(counterB.enterCount, 3); - assertEquals(counterB.leaveCount, 3); + assertEquals(counterA.enterCount(), 1); + assertEquals(counterA.leaveCount(), 1); + assertEquals(counterB.enterCount(), 3); + assertEquals(counterB.leaveCount(), 3); // Run the original and check that instrument B is still working but not A assertEquals(13, callTarget2.call()); - assertEquals(counterA.enterCount, 1); - assertEquals(counterA.leaveCount, 1); - assertEquals(counterB.enterCount, 4); - assertEquals(counterB.leaveCount, 4); + assertEquals(counterA.enterCount(), 1); + assertEquals(counterA.leaveCount(), 1); + assertEquals(counterB.enterCount(), 4); + assertEquals(counterB.leaveCount(), 4); // Attach a second instrument to the probe - final TestCounter counterC = new TestCounter(); counterC.attach(probe); // Run the original and check that instruments B,C working but not A - assertEquals(13, callTarget1.call()); - assertEquals(counterA.enterCount, 1); - assertEquals(counterA.leaveCount, 1); - assertEquals(counterB.enterCount, 5); - assertEquals(counterB.leaveCount, 5); - assertEquals(counterC.enterCount, 1); - assertEquals(counterC.leaveCount, 1); + assertEquals(13, callTarget.call()); + assertEquals(counterA.enterCount(), 1); + assertEquals(counterA.leaveCount(), 1); + assertEquals(counterB.enterCount(), 5); + assertEquals(counterB.leaveCount(), 5); + assertEquals(counterC.enterCount(), 1); + assertEquals(counterC.leaveCount(), 1); // Run the clone and check that instruments B,C working but not A assertEquals(13, callTarget2.call()); - assertEquals(counterA.enterCount, 1); - assertEquals(counterA.leaveCount, 1); - assertEquals(counterB.enterCount, 6); - assertEquals(counterB.leaveCount, 6); - assertEquals(counterC.enterCount, 2); - assertEquals(counterC.leaveCount, 2); + assertEquals(counterA.enterCount(), 1); + assertEquals(counterA.leaveCount(), 1); + assertEquals(counterB.enterCount(), 6); + assertEquals(counterB.leaveCount(), 6); + assertEquals(counterC.enterCount(), 2); + assertEquals(counterC.leaveCount(), 2); // Remove instrumentC counterC.dispose(); // Run the original and check that instrument B working but not A,C - assertEquals(13, callTarget1.call()); - assertEquals(counterA.enterCount, 1); - assertEquals(counterA.leaveCount, 1); - assertEquals(counterB.enterCount, 7); - assertEquals(counterB.leaveCount, 7); - assertEquals(counterC.enterCount, 2); - assertEquals(counterC.leaveCount, 2); + assertEquals(13, callTarget.call()); + assertEquals(counterA.enterCount(), 1); + assertEquals(counterA.leaveCount(), 1); + assertEquals(counterB.enterCount(), 7); + assertEquals(counterB.leaveCount(), 7); + assertEquals(counterC.enterCount(), 2); + assertEquals(counterC.leaveCount(), 2); // Run the clone and check that instrument B working but not A,C assertEquals(13, callTarget2.call()); - assertEquals(counterA.enterCount, 1); - assertEquals(counterA.leaveCount, 1); - assertEquals(counterB.enterCount, 8); - assertEquals(counterB.leaveCount, 8); - assertEquals(counterC.enterCount, 2); - assertEquals(counterC.leaveCount, 2); + assertEquals(counterA.enterCount(), 1); + assertEquals(counterA.leaveCount(), 1); + assertEquals(counterB.enterCount(), 8); + assertEquals(counterB.leaveCount(), 8); + assertEquals(counterC.enterCount(), 2); + assertEquals(counterC.leaveCount(), 2); // Remove instrumentB counterB.dispose(); // Run both the original and clone, check that no instruments working - assertEquals(13, callTarget1.call()); + assertEquals(13, callTarget.call()); assertEquals(13, callTarget2.call()); - assertEquals(counterA.enterCount, 1); - assertEquals(counterA.leaveCount, 1); - assertEquals(counterB.enterCount, 8); - assertEquals(counterB.leaveCount, 8); - assertEquals(counterC.enterCount, 2); - assertEquals(counterC.leaveCount, 2); + assertEquals(counterA.enterCount(), 1); + assertEquals(counterA.leaveCount(), 1); + assertEquals(counterB.enterCount(), 8); + assertEquals(counterB.leaveCount(), 8); + assertEquals(counterC.enterCount(), 2); + assertEquals(counterC.leaveCount(), 2); + } @Test @@ -313,131 +339,6 @@ } - @Test - public void testProbeLite() { - - // Use the "lite-probing" option, limited to a single pass of - // probing and a single Instrument at each probed node. This - // particular test uses a shared event listener at every - // lite-probed node. - final TestEventListener listener = new TestEventListener(); - - TestASTLiteProber astLiteProber = new TestASTLiteProber(listener); - Probe.registerASTProber(astLiteProber); - - // Create a simple addition AST - final TruffleRuntime runtime = Truffle.getRuntime(); - final TestValueNode leftValueNode = new TestValueNode(6); - final TestValueNode rightValueNode = new TestValueNode(7); - final TestAdditionNode addNode = new TestAdditionNode(leftValueNode, rightValueNode); - final TestRootNode rootNode = new TestRootNode(addNode); - - // Creating a call target sets the parent pointers in this tree and is necessary prior to - // checking any parent/child relationships - final CallTarget callTarget = runtime.createCallTarget(rootNode); - - // Check that the instrument is working as expected. - assertEquals(0, listener.counter); - callTarget.call(); - assertEquals(2, listener.counter); - - // Check that you can't probe a node that's already received a probeLite() call - try { - leftValueNode.probe(); - fail(); - } catch (IllegalStateException e) { - } - - try { - rightValueNode.probe(); - fail(); - } catch (IllegalStateException e) { - } - - // Check tree structure - assertTrue(leftValueNode.getParent() instanceof TestLanguageWrapperNode); - assertTrue(rightValueNode.getParent() instanceof TestLanguageWrapperNode); - TestLanguageWrapperNode leftWrapper = (TestLanguageWrapperNode) leftValueNode.getParent(); - TestLanguageWrapperNode rightWrapper = (TestLanguageWrapperNode) rightValueNode.getParent(); - assertEquals(addNode, leftWrapper.getParent()); - assertEquals(addNode, rightWrapper.getParent()); - Iterator iterator = addNode.getChildren().iterator(); - assertEquals(leftWrapper, iterator.next()); - assertEquals(rightWrapper, iterator.next()); - assertFalse(iterator.hasNext()); - assertEquals(rootNode, addNode.getParent()); - iterator = rootNode.getChildren().iterator(); - assertEquals(addNode, iterator.next()); - assertFalse(iterator.hasNext()); - - // Check that you can't get a probe on the wrappers because they were "lite-probed" - try { - leftWrapper.getProbe(); - fail(); - } catch (IllegalStateException e) { - } - try { - rightWrapper.getProbe(); - fail(); - } catch (IllegalStateException e) { - } - - // Check that you can't probe the wrappers - try { - leftWrapper.probe(); - fail(); - } catch (ProbeException e) { - assertEquals(e.getFailure().getReason(), ProbeFailure.Reason.WRAPPER_NODE); - } - try { - rightWrapper.probe(); - fail(); - } catch (ProbeException e) { - assertEquals(e.getFailure().getReason(), ProbeFailure.Reason.WRAPPER_NODE); - } - try { - leftWrapper.probeLite(null); - fail(); - } catch (ProbeException e) { - assertEquals(e.getFailure().getReason(), ProbeFailure.Reason.WRAPPER_NODE); - } - try { - rightWrapper.probeLite(null); - fail(); - } catch (ProbeException e) { - assertEquals(e.getFailure().getReason(), ProbeFailure.Reason.WRAPPER_NODE); - } - - // Use reflection to check that each WrapperNode has a ProbeLiteNode with a - // SimpleEventListener - try { - java.lang.reflect.Field probeNodeField = leftWrapper.getClass().getDeclaredField("probeNode"); - - // cheat: probeNode is private, so we change it's accessibility at runtime - probeNodeField.setAccessible(true); - ProbeNode probeNode = (ProbeNode) probeNodeField.get(leftWrapper); - - // hack: Since ProbeLiteNode is not visible, we do a string compare here - assertTrue(probeNode.getClass().toString().endsWith("ProbeLiteNode")); - - // Now we do the same to check the type of the eventListener in ProbeLiteNode - java.lang.reflect.Field eventListenerField = probeNode.getClass().getDeclaredField("eventListener"); - eventListenerField.setAccessible(true); - TruffleEventListener eventListener = (TruffleEventListener) eventListenerField.get(probeNode); - assertTrue(eventListener instanceof SimpleEventListener); - - // Reset accessibility - probeNodeField.setAccessible(false); - eventListenerField.setAccessible(false); - - } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) { - fail(); - } - - Probe.unregisterASTProber(astLiteProber); - - } - private abstract class TestLanguageNode extends Node { public abstract Object execute(VirtualFrame vFrame); @@ -578,28 +479,51 @@ } } + private interface TestCounter { + + int enterCount(); + + int leaveCount(); + + void attach(Probe probe); + + void dispose(); + + } + /** - * A counter for the number of times execution enters and leaves a probed AST node. + * A counter for the number of times execution enters and leaves a probed AST node, using the + * simplest kind of listener. */ - private class TestCounter { + private class TestInstrumentCounter implements TestCounter { public int enterCount = 0; public int leaveCount = 0; public final Instrument instrument; - public TestCounter() { - instrument = Instrument.create(new SimpleEventListener() { + public TestInstrumentCounter() { + this.instrument = Instrument.create(new SimpleInstrumentListener() { @Override - public void enter(Node node, VirtualFrame vFrame) { + public void enter(Probe probe) { enterCount++; } @Override - public void returnAny(Node node, VirtualFrame vFrame) { + public void returnAny(Probe probe) { leaveCount++; } + }, "Instrumentation Test Counter"); + + } + + public int enterCount() { + return enterCount; + } + + public int leaveCount() { + return leaveCount; } public void attach(Probe probe) { @@ -609,7 +533,50 @@ 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. + */ + private class TestASTInstrumentCounter implements TestCounter { + + public int enterCount = 0; + public int leaveCount = 0; + public final Instrument instrument; + + public TestASTInstrumentCounter() { + this.instrument = Instrument.create(new SimpleASTInstrumentListener() { + + @Override + public void enter(Probe probe, Node node, VirtualFrame vFrame) { + enterCount++; + } + + @Override + public void returnAny(Probe probe, Node node, VirtualFrame vFrame) { + leaveCount++; + } + + }, "Instrumentation Test Counter"); + + } + + public int enterCount() { + return enterCount; + } + + public int leaveCount() { + return leaveCount; + } + + public void attach(Probe probe) { + probe.attach(instrument); + } + + public void dispose() { + instrument.dispose(); + } } /** @@ -641,38 +608,28 @@ } /** - * "lite-probes" every value node with a shared event listener. + * Counts the number of "enter" events at probed nodes using the simplest AST listener. */ - private static final class TestASTLiteProber implements NodeVisitor, ASTProber { - private final TruffleEventListener eventListener; - - public TestASTLiteProber(SimpleEventListener simpleEventListener) { - this.eventListener = simpleEventListener; - } - - public boolean visit(Node node) { - if (node instanceof TestValueNode) { - final TestLanguageNode testNode = (TestValueNode) node; - testNode.probeLite(eventListener); - } - return true; - } - - public void probeAST(Node node) { - node.accept(this); - } - } - - /** - * Counts the number of "enter" events at probed nodes. - * - */ - static final class TestEventListener extends SimpleEventListener { + static final class TestInstrumentListener extends DefaultInstrumentListener { public int counter = 0; @Override - public void enter(Node node, VirtualFrame frame) { + 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 { + + public int counter = 0; + + @Override + public void enter(Probe probe, Node node, VirtualFrame vFrame) { counter++; } @@ -692,10 +649,10 @@ // 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 SimpleEventListener() { + probe.attach(Instrument.create(new DefaultInstrumentListener() { @Override - public void enter(Node node, VirtualFrame vFrame) { + public void enter(Probe p) { count++; } }, "Instrumentation Test MultiCounter")); diff -r 9f1404a45a6f -r 7d74d3ad09f4 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ASTInstrumentListener.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ASTInstrumentListener.java Fri Mar 13 11:28:01 2015 +0100 @@ -0,0 +1,57 @@ +/* + * 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 9f1404a45a6f -r 7d74d3ad09f4 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 Thu Mar 12 17:08:19 2015 +0100 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrument.java Fri Mar 13 11:28:01 2015 +0100 @@ -27,45 +27,71 @@ 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 - * {@linkplain TruffleEventListener execution events} taking place at a {@link Node} in a Guest - * Language (GL) Truffle AST, and a {@linkplain TruffleEventListener listener}, which consumes - * notifications on behalf of an external tool. + * 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:

+ *

*

    - *
  1. Create an implementation of {@link TruffleEventListener} that responds to events on behalf of - * a tool.
  2. - *
  3. Create an Instrument via factory method {@link Instrument#create(TruffleEventListener)}.
  4. + *
  5. Create an implementation of a listener interface.
  6. + *
  7. Create an Instrument via factory methods + * {@link Instrument#create(InstrumentListener, String)} or + * {@link Instrument#create(ASTInstrumentListener, String)}.
  8. *
  9. "Attach" the Instrument to a Probe via {@link Probe#attach(Instrument)}, at which point event * notifications begin to arrive at the listener.
  10. - *
  11. When no longer needed, "detach" the Instrument via {@link TruffleEventInstrument#dispose()}, - * at which point event notifications to the listener cease, and the Instrument becomes unusable.
  12. + *
  13. 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.
  14. *
*

*

Options for creating listeners:

*

*

    - *
  1. Implement the interface {@link TruffleEventListener}. The event handling methods account for - * both the entry into an AST node (about to call) and several possible kinds of exit from an AST - * node (just returned).
  2. - *
  3. Extend {@link DefaultEventListener}, which provides a no-op implementation of every - * {@link TruffleEventListener} method; override the methods of interest.
  4. - *
  5. Extend {@link SimpleEventListener}, where return values are ignored so only two methods (for - * "enter" and "return") will notify all events.
  6. + *
  7. 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.
  8. + *
  9. 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.
  10. + *
  11. 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.
  12. *
*

- *

General guidelines for listener implementation:

+ *

General guidelines for {@link ASTInstrumentListener} implementation:

*

- * When an Instrument is attached to a Probe, the listener effectively becomes part of the executing - * GL program; performance can be affected by the listener's implementation. + * 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. + *

+ *

+ * 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.
  • @@ -78,16 +104,18 @@ * 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 way to implement - * callbacks to owner tools.
  • - *
  • Primitive-valued return events are boxed for 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). + *
  • 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). *
*

*

Allowing for AST cloning:

*

- * Truffle routinely clones ASTs, which has consequences for listener implementation. + * 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 @@ -98,22 +126,18 @@ * be treated as equivalent for most purposes.
  • *
*

- *

Access to execution state:

+ *

Access to execution state via {@link ASTInstrumentListener}:

*

*

    - *
  • Event notification arguments provide primary access to the GL program's execution states: + *
  • 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. *
    • *
    • {@link VirtualFrame}: the current execution frame. *
    - *
  • Some global information is available, for example the execution + *
  • Truffle global information is available, for example the execution * {@linkplain TruffleRuntime#iterateFrames(FrameInstanceVisitor) stack}.
  • - *
  • Additional information needed by a listener could be stored when created, preferably - * {@code final} of course. For example, a reference to the {@link Probe} to which the listener's - * Instrument has been attached would give access to its corresponding - * {@linkplain Probe#getProbedSourceSection() source location} or to the collection of - * {@linkplain SyntaxTag tags} currently applied to the Probe.
  • + *
  • Additional API access to execution state may be added in the future.
  • *
*

*

Activating and deactivating Instruments:

@@ -125,8 +149,8 @@ * 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 TruffleEventInstrument#dispose()} makes an instrument inactive by removing - * it from the Probe to which it was attached and rendering it permanently inert.
  • + *
  • 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.
  • * @@ -142,26 +166,32 @@ * Disclaimer: experimental; under development. * * @see Probe - * @see TruffleEventListener + * @see TruffleEvents */ public abstract class Instrument { /** * Creates an instrument that will route execution events to a listener. * - * @param listener a listener for event generated by the instrument - * @param instrumentInfo optional description of the instrument's role + * @param listener a minimal listener for event generated by the instrument. + * @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(TruffleEventListener listener, String instrumentInfo) { - return new TruffleEventInstrument(listener, instrumentInfo); + public static Instrument create(InstrumentListener listener, String instrumentInfo) { + return new BasicInstrument(listener, instrumentInfo); } /** - * Creates an instrument that will route execution events to a listener. + * 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 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(TruffleEventListener listener) { - return new TruffleEventInstrument(listener, null); + public static Instrument create(ASTInstrumentListener astListener, String instrumentInfo) { + return new ASTInstrument(astListener, instrumentInfo); } // TODO (mlvdv) experimental @@ -177,7 +207,7 @@ */ private boolean isDisposed = false; - private Probe probe = null; + protected Probe probe = null; /** * Optional documentation, mainly for debugging. @@ -220,32 +250,30 @@ return isDisposed; } - abstract InstrumentNode addToChain(InstrumentNode nextNode); + abstract AbstractInstrumentNode addToChain(AbstractInstrumentNode nextNode); /** - * Removes this instrument from an instrument chain. + * An instrument that propagates events to an instance of {@link InstrumentListener}. */ - abstract InstrumentNode removeFromChain(InstrumentNode instrumentNode); - - private static final class TruffleEventInstrument extends Instrument { + private static final class BasicInstrument extends Instrument { /** * Tool-supplied listener for events. */ - private final TruffleEventListener toolEventListener; + private final InstrumentListener instrumentListener; - private TruffleEventInstrument(TruffleEventListener listener, String instrumentInfo) { + private BasicInstrument(InstrumentListener basicListener, String instrumentInfo) { super(instrumentInfo); - this.toolEventListener = listener; + this.instrumentListener = basicListener; } @Override - InstrumentNode addToChain(InstrumentNode nextNode) { - return new TruffleEventInstrumentNode(nextNode); + AbstractInstrumentNode addToChain(AbstractInstrumentNode nextNode) { + return new BasicInstrumentNode(nextNode); } @Override - InstrumentNode removeFromChain(InstrumentNode instrumentNode) { + AbstractInstrumentNode removeFromChain(AbstractInstrumentNode instrumentNode) { boolean found = false; if (instrumentNode != null) { if (instrumentNode.getInstrument() == this) { @@ -253,7 +281,7 @@ return instrumentNode.nextInstrument; } // Match not at the head of the chain; remove it. - found = instrumentNode.removeFromChain(TruffleEventInstrument.this); + found = instrumentNode.removeFromChain(BasicInstrument.this); } if (!found) { throw new IllegalStateException("Couldn't find instrument node to remove: " + this); @@ -262,35 +290,35 @@ } @NodeInfo(cost = NodeCost.NONE) - private final class TruffleEventInstrumentNode extends InstrumentNode { + private final class BasicInstrumentNode extends AbstractInstrumentNode { - private TruffleEventInstrumentNode(InstrumentNode nextNode) { + private BasicInstrumentNode(AbstractInstrumentNode nextNode) { super(nextNode); } public void enter(Node node, VirtualFrame vFrame) { - TruffleEventInstrument.this.toolEventListener.enter(node, vFrame); + BasicInstrument.this.instrumentListener.enter(BasicInstrument.this.probe); if (nextInstrument != null) { nextInstrument.enter(node, vFrame); } } public void returnVoid(Node node, VirtualFrame vFrame) { - TruffleEventInstrument.this.toolEventListener.returnVoid(node, vFrame); + BasicInstrument.this.instrumentListener.returnVoid(BasicInstrument.this.probe); if (nextInstrument != null) { nextInstrument.returnVoid(node, vFrame); } } public void returnValue(Node node, VirtualFrame vFrame, Object result) { - TruffleEventInstrument.this.toolEventListener.returnValue(node, vFrame, result); + BasicInstrument.this.instrumentListener.returnValue(BasicInstrument.this.probe, result); if (nextInstrument != null) { nextInstrument.returnValue(node, vFrame, result); } } public void returnExceptional(Node node, VirtualFrame vFrame, Exception exception) { - TruffleEventInstrument.this.toolEventListener.returnExceptional(node, vFrame, exception); + BasicInstrument.this.instrumentListener.returnExceptional(BasicInstrument.this.probe, exception); if (nextInstrument != null) { nextInstrument.returnExceptional(node, vFrame, exception); } @@ -298,7 +326,91 @@ public String instrumentationInfo() { final String info = getInstrumentInfo(); - return info != null ? info : toolEventListener.getClass().getSimpleName(); + return info != null ? info : instrumentListener.getClass().getSimpleName(); + } + } + } + + /** + * Removes this instrument from an instrument chain. + */ + abstract AbstractInstrumentNode removeFromChain(AbstractInstrumentNode instrumentNode); + + /** + * An instrument that propagates events to an instance of {@link ASTInstrumentListener}. + */ + private static final class ASTInstrument extends Instrument { + + /** + * Tool-supplied listener for AST events. + */ + private final ASTInstrumentListener astListener; + + private ASTInstrument(ASTInstrumentListener astListener, String instrumentInfo) { + super(instrumentInfo); + this.astListener = astListener; + } + + @Override + AbstractInstrumentNode addToChain(AbstractInstrumentNode nextNode) { + return new ASTInstrumentNode(nextNode); + } + + @Override + AbstractInstrumentNode removeFromChain(AbstractInstrumentNode instrumentNode) { + boolean found = false; + if (instrumentNode != null) { + if (instrumentNode.getInstrument() == this) { + // Found the match at the head of the chain + return instrumentNode.nextInstrument; + } + // Match not at the head of the chain; remove it. + found = instrumentNode.removeFromChain(ASTInstrument.this); + } + if (!found) { + throw new IllegalStateException("Couldn't find instrument node to remove: " + this); + } + return instrumentNode; + } + + @NodeInfo(cost = NodeCost.NONE) + private final class ASTInstrumentNode extends AbstractInstrumentNode { + + private ASTInstrumentNode(AbstractInstrumentNode nextNode) { + super(nextNode); + } + + public void enter(Node node, VirtualFrame vFrame) { + ASTInstrument.this.astListener.enter(ASTInstrument.this.probe, node, vFrame); + if (nextInstrument != null) { + nextInstrument.enter(node, vFrame); + } + } + + public void returnVoid(Node node, VirtualFrame vFrame) { + ASTInstrument.this.astListener.returnVoid(ASTInstrument.this.probe, node, vFrame); + if (nextInstrument != null) { + nextInstrument.returnVoid(node, vFrame); + } + } + + public void returnValue(Node node, VirtualFrame vFrame, Object result) { + ASTInstrument.this.astListener.returnValue(ASTInstrument.this.probe, node, vFrame, result); + if (nextInstrument != null) { + nextInstrument.returnValue(node, vFrame, result); + } + } + + public void returnExceptional(Node node, VirtualFrame vFrame, Exception exception) { + ASTInstrument.this.astListener.returnExceptional(ASTInstrument.this.probe, node, vFrame, exception); + if (nextInstrument != null) { + nextInstrument.returnExceptional(node, vFrame, exception); + } + } + + public String instrumentationInfo() { + final String info = getInstrumentInfo(); + return info != null ? info : astListener.getClass().getSimpleName(); } } @@ -318,12 +430,12 @@ } @Override - InstrumentNode addToChain(InstrumentNode nextNode) { + AbstractInstrumentNode addToChain(AbstractInstrumentNode nextNode) { return new TruffleOptInstrumentNode(nextNode); } @Override - InstrumentNode removeFromChain(InstrumentNode instrumentNode) { + AbstractInstrumentNode removeFromChain(AbstractInstrumentNode instrumentNode) { boolean found = false; if (instrumentNode != null) { if (instrumentNode.getInstrument() == this) { @@ -340,11 +452,11 @@ } @NodeInfo(cost = NodeCost.NONE) - private final class TruffleOptInstrumentNode extends InstrumentNode { + private final class TruffleOptInstrumentNode extends AbstractInstrumentNode { private boolean isCompiled; - private TruffleOptInstrumentNode(InstrumentNode nextNode) { + private TruffleOptInstrumentNode(AbstractInstrumentNode nextNode) { super(nextNode); this.isCompiled = CompilerDirectives.inCompiledCode(); } @@ -386,10 +498,11 @@ } @NodeInfo(cost = NodeCost.NONE) - abstract class InstrumentNode extends Node implements TruffleEventListener, InstrumentationNode { - @Child protected InstrumentNode nextInstrument; + abstract class AbstractInstrumentNode extends Node implements TruffleEvents, InstrumentationNode { - protected InstrumentNode(InstrumentNode nextNode) { + @Child protected AbstractInstrumentNode nextInstrument; + + protected AbstractInstrumentNode(AbstractInstrumentNode nextNode) { this.nextInstrument = nextNode; } diff -r 9f1404a45a6f -r 7d74d3ad09f4 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/InstrumentListener.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/InstrumentListener.java Fri Mar 13 11:28:01 2015 +0100 @@ -0,0 +1,54 @@ +/* + * 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 9f1404a45a6f -r 7d74d3ad09f4 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 Thu Mar 12 17:08:19 2015 +0100 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/InstrumentationNode.java Fri Mar 13 11:28:01 2015 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -24,6 +24,7 @@ */ package com.oracle.truffle.api.instrument; +import com.oracle.truffle.api.frame.*; import com.oracle.truffle.api.nodes.*; /** @@ -36,4 +37,31 @@ * A short description of the particular role played by the node, intended to support debugging. */ String instrumentationInfo(); + + /** + * Events at a Truffle node that get propagated through the Instrumentation Framework. + */ + interface TruffleEvents { + + /** + * An AST node's execute method is about to be called. + */ + void enter(Node node, VirtualFrame vFrame); + + /** + * An AST Node's {@code void}-valued execute method has just returned. + */ + void returnVoid(Node node, VirtualFrame vFrame); + + /** + * An AST Node's execute method has just returned a value (boxed if primitive). + */ + void returnValue(Node node, VirtualFrame vFrame, Object result); + + /** + * An AST Node's execute method has just thrown an exception. + */ + void returnExceptional(Node node, VirtualFrame vFrame, Exception exception); + + } } diff -r 9f1404a45a6f -r 7d74d3ad09f4 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Probe.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Probe.java Thu Mar 12 17:08:19 2015 +0100 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Probe.java Fri Mar 13 11:28:01 2015 +0100 @@ -29,6 +29,7 @@ import com.oracle.truffle.api.*; import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; +import com.oracle.truffle.api.instrument.InstrumentationNode.TruffleEvents; import com.oracle.truffle.api.nodes.*; import com.oracle.truffle.api.source.*; import com.oracle.truffle.api.utilities.*; @@ -41,9 +42,9 @@ * is intended to persist at the location, even if the specific node instance is * {@linkplain Node#replace(Node) replaced}. *

    - * The effect of a binding is to intercept {@linkplain TruffleEventListener execution events} - * arriving at the node and notify each attached {@link Instrument} before execution is allowed to - * proceed to the child. + * The effect of a binding is to intercept {@linkplain TruffleEvents execution events} arriving at + * the node and notify each attached {@link Instrument} before execution is allowed to proceed to + * the child. *

    * A Probe is "inserted" into a GL node via a call to {@link Node#probe()}. No more than one Probe * can be inserted at a node. diff -r 9f1404a45a6f -r 7d74d3ad09f4 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ProbeNode.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ProbeNode.java Thu Mar 12 17:08:19 2015 +0100 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ProbeNode.java Fri Mar 13 11:28:01 2015 +0100 @@ -27,14 +27,15 @@ import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.instrument.Instrument.InstrumentNode; +import com.oracle.truffle.api.instrument.Instrument.AbstractInstrumentNode; +import com.oracle.truffle.api.instrument.InstrumentationNode.TruffleEvents; import com.oracle.truffle.api.nodes.*; import com.oracle.truffle.api.source.*; /** * Implementation interfaces and classes for attaching {@link Probe}s to {@link WrapperNode}s. */ -public abstract class ProbeNode extends Node implements TruffleEventListener, InstrumentationNode { +public abstract class ProbeNode extends Node implements TruffleEvents, InstrumentationNode { /** * A node that can be inserted into a Truffle AST, and which enables {@linkplain Instrument @@ -84,14 +85,14 @@ /** * Gets the node being "wrapped", i.e. the AST node for which - * {@linkplain TruffleEventListener execution events} will be reported through the - * Instrumentation Framework. + * {@linkplain InstrumentationNode.TruffleEvents execution events} will be reported through + * the Instrumentation Framework. */ Node getChild(); /** * Gets the {@link Probe} responsible for installing this wrapper; none if the wrapper - * installed via {@linkplain Node#probeLite(TruffleEventListener) "lite-Probing"}. + * installed via {@linkplain Node#probeLite(ASTInstrumentListener) "lite-Probing"}. */ Probe getProbe(); @@ -119,8 +120,8 @@ * Creates a new {@link ProbeLiteNode} associated with, and attached to, a Guest Language * specific instance of {@link WrapperNode}. */ - public static void insertProbeLite(WrapperNode wrapper, TruffleEventListener eventListener) { - final ProbeLiteNode probeLiteNode = new ProbeLiteNode(eventListener); + public static void insertProbeLite(WrapperNode wrapper, ASTInstrumentListener instrumentListener) { + final ProbeLiteNode probeLiteNode = new ProbeLiteNode(instrumentListener); wrapper.insertProbe(probeLiteNode); } @@ -137,7 +138,7 @@ public abstract Probe getProbe() throws IllegalStateException; /** - * Adds an {@link InstrumentNode} to this chain. + * Adds an {@link AbstractInstrumentNode} to this chain. * * @throws IllegalStateException if at a "lite-Probed" location. */ @@ -168,9 +169,10 @@ private static final class ProbeFullNode extends ProbeNode { /** - * First {@link InstrumentNode} node in chain; {@code null} of no instruments in chain. + * First {@link AbstractInstrumentNode} node in chain; {@code null} of no instruments in + * chain. */ - @Child protected InstrumentNode firstInstrument; + @Child protected AbstractInstrumentNode firstInstrument; // Never changed once set. @CompilationFinal private Probe probe = null; @@ -208,7 +210,7 @@ @TruffleBoundary void removeInstrument(Instrument instrument) { assert instrument.getProbe() == probe; - final InstrumentNode modifiedChain = instrument.removeFromChain(firstInstrument); + final AbstractInstrumentNode modifiedChain = instrument.removeFromChain(firstInstrument); if (modifiedChain == null) { firstInstrument = null; } else { @@ -256,15 +258,15 @@ /** * Implementation of a probe that only ever has a single "instrument" associated with it. No * {@link Instrument} is ever created; instead this method simply delegates the various enter - * and return events to a {@link TruffleEventListener} passed in during construction. + * and return events to a {@link TruffleEvents} passed in during construction. */ @NodeInfo(cost = NodeCost.NONE) private static final class ProbeLiteNode extends ProbeNode { - private final TruffleEventListener eventListener; + private final ASTInstrumentListener instrumentListener; - private ProbeLiteNode(TruffleEventListener eventListener) { - this.eventListener = eventListener; + private ProbeLiteNode(ASTInstrumentListener eventListener) { + this.instrumentListener = eventListener; } @Override @@ -285,19 +287,19 @@ } public void enter(Node node, VirtualFrame vFrame) { - eventListener.enter(node, vFrame); + instrumentListener.enter(getProbe(), node, vFrame); } public void returnVoid(Node node, VirtualFrame vFrame) { - eventListener.returnVoid(node, vFrame); + instrumentListener.returnVoid(getProbe(), node, vFrame); } public void returnValue(Node node, VirtualFrame vFrame, Object result) { - eventListener.returnValue(node, vFrame, result); + instrumentListener.returnValue(getProbe(), node, vFrame, result); } public void returnExceptional(Node node, VirtualFrame vFrame, Exception exception) { - eventListener.returnExceptional(node, vFrame, exception); + instrumentListener.returnExceptional(getProbe(), node, vFrame, exception); } public String instrumentationInfo() { diff -r 9f1404a45a6f -r 7d74d3ad09f4 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/TruffleEventListener.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/TruffleEventListener.java Thu Mar 12 17:08:19 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2013, 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 and possibly - * intervene on behalf of an external tool. - */ -public interface TruffleEventListener { - - /** - * Receive notification that an AST node's execute method is about to be called. - */ - void enter(Node node, VirtualFrame vFrame); - - /** - * Receive notification that an AST Node's {@code void}-valued execute method has just returned. - */ - void returnVoid(Node node, VirtualFrame vFrame); - - /** - * Receive notification that an AST Node'sexecute method has just returned a value (boxed if - * primitive). - */ - void returnValue(Node node, VirtualFrame vFrame, Object result); - - /** - * Receive notification that an AST Node's execute method has just thrown an exception. - */ - void returnExceptional(Node node, VirtualFrame vFrame, Exception exception); - -} diff -r 9f1404a45a6f -r 7d74d3ad09f4 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/DefaultASTInstrumentListener.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/DefaultASTInstrumentListener.java Fri Mar 13 11:28:01 2015 +0100 @@ -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 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 9f1404a45a6f -r 7d74d3ad09f4 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/DefaultEventListener.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/DefaultEventListener.java Thu Mar 12 17:08:19 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,49 +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.frame.*; -import com.oracle.truffle.api.instrument.*; -import com.oracle.truffle.api.nodes.*; - -/** - * A listener for AST {@linkplain TruffleEventListener execution events} that provides a no-op - * implementation of every event. - */ -public class DefaultEventListener implements TruffleEventListener { - - public void enter(Node node, VirtualFrame vFrame) { - } - - public void returnVoid(Node node, VirtualFrame vFrame) { - } - - public void returnValue(Node node, VirtualFrame vFrame, Object result) { - } - - public void returnExceptional(Node node, VirtualFrame vFrame, Exception exception) { - } - -} diff -r 9f1404a45a6f -r 7d74d3ad09f4 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/DefaultInstrumentListener.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/DefaultInstrumentListener.java Fri Mar 13 11:28:01 2015 +0100 @@ -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 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 9f1404a45a6f -r 7d74d3ad09f4 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/SimpleASTInstrumentListener.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/SimpleASTInstrumentListener.java Fri Mar 13 11:28:01 2015 +0100 @@ -0,0 +1,67 @@ +/* + * 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 9f1404a45a6f -r 7d74d3ad09f4 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/SimpleEventListener.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/SimpleEventListener.java Thu Mar 12 17:08:19 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,66 +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.frame.*; -import com.oracle.truffle.api.instrument.*; -import com.oracle.truffle.api.nodes.*; - -/** - * An abstract listener for AST {@linkplain TruffleEventListener execution events} that ignores - * return values and supports handling all events by overriding only two methods: - *
      - *
    • {@link #enter(Node, VirtualFrame)}, and
    • - *
    • {@link #returnAny(Node, VirtualFrame)}.
    • - *
    - */ -public abstract class SimpleEventListener implements TruffleEventListener { - - public void enter(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 node - * @param vFrame - */ - public void returnAny(Node node, VirtualFrame vFrame) { - } - - public final void returnVoid(Node node, VirtualFrame vFrame) { - returnAny(node, vFrame); - } - - public final void returnValue(Node node, VirtualFrame vFrame, Object result) { - returnAny(node, vFrame); - } - - public final void returnExceptional(Node node, VirtualFrame vFrame, Exception e) { - returnAny(node, vFrame); - } - -} diff -r 9f1404a45a6f -r 7d74d3ad09f4 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/SimpleInstrumentListener.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/SimpleInstrumentListener.java Fri Mar 13 11:28:01 2015 +0100 @@ -0,0 +1,63 @@ +/* + * 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 9f1404a45a6f -r 7d74d3ad09f4 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java Thu Mar 12 17:08:19 2015 +0100 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java Fri Mar 13 11:28:01 2015 +0100 @@ -504,16 +504,16 @@ * its parent; the wrapper node must be provided by implementations of * {@link #createWrapperNode()}. *

    - * Unlike {@link #probe()}, once {@link #probeLite(TruffleEventListener)} is called at a node, + * Unlike {@link #probe()}, once {@link #probeLite(ASTInstrumentListener)} is called at a node, * no additional probing can be added and no additional instrumentation can be attached. *

    * This restricted form of instrumentation is intended for special cases where only one kind of * instrumentation is desired, and for which performance is a concern * - * @param eventListener + * @param instrumentListener * @throws ProbeException (unchecked) when a probe cannot be created, leaving the AST unchanged */ - public final void probeLite(TruffleEventListener eventListener) { + public final void probeLite(ASTInstrumentListener instrumentListener) { if (this instanceof WrapperNode) { throw new ProbeException(ProbeFailure.Reason.WRAPPER_NODE, null, this, null); @@ -545,7 +545,7 @@ } // Connect it to a Probe - ProbeNode.insertProbeLite(wrapper, eventListener); + ProbeNode.insertProbeLite(wrapper, instrumentListener); // Replace this node in the AST with the wrapper this.replace(wrapperNode); diff -r 9f1404a45a6f -r 7d74d3ad09f4 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 Thu Mar 12 17:08:19 2015 +0100 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/tools/CoverageTracker.java Fri Mar 13 11:28:01 2015 +0100 @@ -28,7 +28,6 @@ import java.util.*; import java.util.Map.Entry; -import com.oracle.truffle.api.frame.*; import com.oracle.truffle.api.instrument.*; import com.oracle.truffle.api.instrument.impl.*; import com.oracle.truffle.api.nodes.*; @@ -49,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 TruffleEventListener#enter(Node, VirtualFrame)};
    • + * to produce the event {@link InstrumentListener#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; @@ -227,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 DefaultEventListener { + private final class CoverageRecord extends DefaultInstrumentListener { private final SourceSection srcSection; // The text of the code being counted private Instrument instrument; // The attached Instrument, in case need to remove. @@ -238,7 +237,7 @@ } @Override - public void enter(Node node, VirtualFrame vFrame) { + public void enter(Probe probe) { if (isEnabled()) { count++; } diff -r 9f1404a45a6f -r 7d74d3ad09f4 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 Thu Mar 12 17:08:19 2015 +0100 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/tools/NodeExecCounter.java Fri Mar 13 11:28:01 2015 +0100 @@ -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 TruffleEventListener#enter(Node, VirtualFrame)};
      • + * to produce the event {@link ASTInstrumentListener#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,15 +95,15 @@ * 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 TruffleEventListener eventListener = new DefaultEventListener() { + private final ASTInstrumentListener instrumentListener = new DefaultASTInstrumentListener() { @Override - public void enter(Node node, VirtualFrame vFrame) { + public void enter(Probe probe, Node node, VirtualFrame vFrame) { if (isEnabled()) { final Class nodeClass = node.getClass(); /* * Everything up to here is inlined by Truffle compilation. Delegate the next part * to a method behind an inlining boundary. - * + * * Note that it is not permitted to pass a {@link VirtualFrame} across an inlining * boundary; they are truly virtual in inlined code. */ @@ -280,7 +280,7 @@ if (node.isInstrumentable()) { try { - final Instrument instrument = Instrument.create(eventListener, "NodeExecCounter"); + final Instrument instrument = Instrument.create(instrumentListener, "NodeExecCounter"); instruments.add(instrument); node.probe().attach(instrument); } catch (ProbeException ex) { @@ -304,7 +304,7 @@ @Override public void probeTaggedAs(Probe probe, SyntaxTag tag, Object tagValue) { if (countingTag == tag) { - final Instrument instrument = Instrument.create(eventListener, NodeExecCounter.class.getSimpleName()); + final Instrument instrument = Instrument.create(instrumentListener, NodeExecCounter.class.getSimpleName()); instruments.add(instrument); probe.attach(instrument); } diff -r 9f1404a45a6f -r 7d74d3ad09f4 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 Thu Mar 12 17:08:19 2015 +0100 +++ b/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/instrument/SLInstrumentTestRunner.java Fri Mar 13 11:28:01 2015 +0100 @@ -36,10 +36,8 @@ import org.junit.runners.*; import org.junit.runners.model.*; -import com.oracle.truffle.api.frame.*; import com.oracle.truffle.api.instrument.*; import com.oracle.truffle.api.instrument.impl.*; -import com.oracle.truffle.api.nodes.*; import com.oracle.truffle.api.source.*; import com.oracle.truffle.sl.factory.*; import com.oracle.truffle.sl.nodes.instrument.*; @@ -271,12 +269,12 @@ } /** - * This sample instrument listener provides prints the value of an assignment (after the - * assignment is complete) to the {@link PrintStream} specified in the constructor. This - * instrument can only be attached to a wrapped {@link SLWriteLocalVariableNode}, but provides - * no guards to protect it from being attached elsewhere. + * This sample listener provides prints the value of an assignment (after the assignment is + * complete) to the {@link PrintStream} specified in the constructor. This listener can only be + * attached at {@link SLWriteLocalVariableNode}, but provides no guards to protect it from being + * attached elsewhere. */ - public final class SLPrintAssigmentValueListener extends DefaultEventListener { + public final class SLPrintAssigmentValueListener extends DefaultInstrumentListener { private PrintStream output; @@ -285,7 +283,7 @@ } @Override - public void returnValue(Node node, VirtualFrame frame, Object result) { + public void returnValue(Probe probe, Object result) { output.println(result); } } diff -r 9f1404a45a6f -r 7d74d3ad09f4 src/share/vm/opto/compile.cpp --- a/src/share/vm/opto/compile.cpp Thu Mar 12 17:08:19 2015 +0100 +++ b/src/share/vm/opto/compile.cpp Fri Mar 13 11:28:01 2015 +0100 @@ -2184,6 +2184,8 @@ if (failing()) return; } } + // Ensure that major progress is now clear + C->clear_major_progress(); { // Verify that all previous optimizations produced a valid graph