# HG changeset patch # User Christian Wimmer # Date 1405467293 25200 # Node ID f6ac86d3334ea8be8d2d6bbb82668c6ef80a9ac5 # Parent b0ea5c266655253934e403f00d69aedc1f68e052 Change API for stack walking to a visitor: TruffleRuntime#iterateFrames replaces TruffleRuntime#getStackTrace diff -r b0ea5c266655 -r f6ac86d3334e CHANGELOG.md --- a/CHANGELOG.md Tue Jul 15 15:49:12 2014 +0200 +++ b/CHANGELOG.md Tue Jul 15 16:34:53 2014 -0700 @@ -10,6 +10,7 @@ * Enabled use of separate class loader (via -XX:+UseGraalClassLoader) for classes loaded from graal.jar to hide them from application classes. ### Truffle +* Change API for stack walking to a visitor: `TruffleRuntime#iterateFrames` replaces `TruffleRuntime#getStackTrace` * New flag -G:+TraceTruffleCompilationCallTree to print the tree of inlined calls before compilation. * `truffle.jar`: strip out build-time only dependency into a seperated JAR file (`truffle-dsl-processor.jar`) * New flag -G:+TraceTruffleCompilationAST to print the AST before compilation. diff -r b0ea5c266655 -r f6ac86d3334e graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/stack/InspectedFrame.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/stack/InspectedFrame.java Tue Jul 15 15:49:12 2014 +0200 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/stack/InspectedFrame.java Tue Jul 15 16:34:53 2014 -0700 @@ -60,4 +60,10 @@ * @return the current method */ ResolvedJavaMethod getMethod(); + + /** + * Checks if the current method is equal to the given method. This is semantically equivalent to + * {@code method.equals(getMethod())}, but can be implemented more efficiently. + */ + boolean isMethod(ResolvedJavaMethod method); } diff -r b0ea5c266655 -r f6ac86d3334e graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/stack/InspectedFrameVisitor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/stack/InspectedFrameVisitor.java Tue Jul 15 16:34:53 2014 -0700 @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.api.code.stack; + +/** + * Callback interface for {@link StackIntrospection#iterateFrames}. Implementations of + * {@link #visitFrame} return null to indicate that frame iteration should continue and the next + * caller frame should be visited; and return any non-null value to indicate that frame iteration + * should stop. + */ +public interface InspectedFrameVisitor { + + T visitFrame(InspectedFrame frame); +} diff -r b0ea5c266655 -r f6ac86d3334e graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/stack/StackIntrospection.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/stack/StackIntrospection.java Tue Jul 15 15:49:12 2014 +0200 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/stack/StackIntrospection.java Tue Jul 15 16:34:53 2014 -0700 @@ -27,13 +27,19 @@ public interface StackIntrospection { /** - * Accesses the current stack, returning a collection of {@link InspectedFrame}s that can be - * used to inspect the stack frames' contents. + * Accesses the current stack, providing {@link InspectedFrame}s to the visitor that can be used + * to inspect the stack frames' contents. Iteration continues as long as + * {@link InspectedFrameVisitor#visitFrame}, which is invoked for every {@link InspectedFrame}, + * returns null. Any non-null result of the visitor indicates that frame iteration should stop. * * @param initialMethods if this is non-{@code null}, then the stack trace will start at these * methods * @param matchingMethods if this is non-{@code null}, then only matching stack frames are * returned + * @param initialSkip the number of matching methods to skip (including the initial method) + * @param visitor the visitor that is called for every matching method + * @return the last result returned by the visitor (which is non-null to indicate that iteration + * should stop), or null if the whole stack was iterated. */ - Iterable getStackTrace(ResolvedJavaMethod[] initialMethods, ResolvedJavaMethod[] matchingMethods, int initialSkip); + T iterateFrames(ResolvedJavaMethod[] initialMethods, ResolvedJavaMethod[] matchingMethods, int initialSkip, InspectedFrameVisitor visitor); } diff -r b0ea5c266655 -r f6ac86d3334e graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java Tue Jul 15 15:49:12 2014 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java Tue Jul 15 16:34:53 2014 -0700 @@ -519,38 +519,20 @@ } } - public Iterable getStackTrace(ResolvedJavaMethod[] initialMethods, ResolvedJavaMethod[] matchingMethods, int initialSkip) { + @Override + public T iterateFrames(ResolvedJavaMethod[] initialMethods, ResolvedJavaMethod[] matchingMethods, int initialSkip, InspectedFrameVisitor visitor) { final long[] initialMetaMethods = toMeta(initialMethods); final long[] matchingMetaMethods = toMeta(matchingMethods); - class StackFrameIterator implements Iterator { - private HotSpotStackFrameReference current = compilerToVm.getNextStackFrame(null, initialMetaMethods, initialSkip); - // we don't want to read ahead if hasNext isn't called - private boolean advanced = true; - - public boolean hasNext() { - update(); - return current != null; + HotSpotStackFrameReference current = compilerToVm.getNextStackFrame(null, initialMetaMethods, initialSkip); + while (current != null) { + T result = visitor.visitFrame(current); + if (result != null) { + return result; } - - public InspectedFrame next() { - update(); - advanced = false; - return current; - } - - private void update() { - if (!advanced) { - current = compilerToVm.getNextStackFrame(current, matchingMetaMethods, 0); - advanced = true; - } - } + current = compilerToVm.getNextStackFrame(current, matchingMetaMethods, 0); } - return new Iterable() { - public Iterator iterator() { - return new StackFrameIterator(); - } - }; + return null; } private static long[] toMeta(ResolvedJavaMethod[] methods) { diff -r b0ea5c266655 -r f6ac86d3334e graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotStackFrameReference.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotStackFrameReference.java Tue Jul 15 15:49:12 2014 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotStackFrameReference.java Tue Jul 15 16:34:53 2014 -0700 @@ -51,26 +51,37 @@ return frameNumber; } + @Override public Object getLocal(int index) { return locals[index]; } + @Override public boolean isVirtual(int index) { return localIsVirtual == null ? false : localIsVirtual[index]; } + @Override public void materializeVirtualObjects(boolean invalidateCode) { compilerToVM.materializeVirtualObjects(this, invalidateCode); } + @Override public int getBytecodeIndex() { return bci; } + @Override public ResolvedJavaMethod getMethod() { return HotSpotResolvedJavaMethod.fromMetaspace(metaspaceMethod); } + @Override + public boolean isMethod(ResolvedJavaMethod method) { + return metaspaceMethod == ((HotSpotResolvedJavaMethod) method).getMetaspaceMethod(); + } + + @Override public boolean hasVirtualObjects() { return localIsVirtual != null; } diff -r b0ea5c266655 -r f6ac86d3334e graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java --- a/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java Tue Jul 15 15:49:12 2014 +0200 +++ b/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java Tue Jul 15 16:34:53 2014 -0700 @@ -245,33 +245,31 @@ } @SlowPath - public Iterable getStackTrace() { + @Override + public T iterateFrames(FrameInstanceVisitor visitor) { initStackIntrospection(); - final Iterator frames = stackIntrospection.getStackTrace(anyFrameMethod, anyFrameMethod, 1).iterator(); - class FrameIterator implements Iterator { - public boolean hasNext() { - return frames.hasNext(); - } + InspectedFrameVisitor inspectedFrameVisitor = new InspectedFrameVisitor() { + private boolean skipNext = false; - public FrameInstance next() { - InspectedFrame frame = frames.next(); - if (frame.getMethod().equals(callNodeMethod[0])) { - assert frames.hasNext(); - InspectedFrame calltarget2 = frames.next(); - assert calltarget2.getMethod().equals(callTargetMethod[0]); - return new HotSpotFrameInstance.CallNodeFrame(frame); + public T visitFrame(InspectedFrame frame) { + if (skipNext) { + assert frame.isMethod(callTargetMethod[0]); + skipNext = false; + return null; + } + + if (frame.isMethod(callNodeMethod[0])) { + skipNext = true; + return visitor.visitFrame(new HotSpotFrameInstance.CallNodeFrame(frame)); } else { - assert frame.getMethod().equals(callTargetMethod[0]); - return new HotSpotFrameInstance.CallTargetFrame(frame, false); + assert frame.isMethod(callTargetMethod[0]); + return visitor.visitFrame(new HotSpotFrameInstance.CallTargetFrame(frame, false)); } - } - } - return new Iterable() { - public Iterator iterator() { - return new FrameIterator(); + } }; + return stackIntrospection.iterateFrames(anyFrameMethod, anyFrameMethod, 1, inspectedFrameVisitor); } private void initStackIntrospection() { @@ -280,15 +278,17 @@ } } + @Override + public FrameInstance getCallerFrame() { + return iterateFrames(frame -> frame); + } + @SlowPath + @Override public FrameInstance getCurrentFrame() { initStackIntrospection(); - Iterator frames = stackIntrospection.getStackTrace(callTargetMethod, callTargetMethod, 0).iterator(); - if (frames.hasNext()) { - return new HotSpotFrameInstance.CallTargetFrame(frames.next(), true); - } else { - return null; - } + + return stackIntrospection.iterateFrames(callTargetMethod, callTargetMethod, 0, frame -> new HotSpotFrameInstance.CallTargetFrame(frame, true)); } public void compile(OptimizedCallTarget optimizedCallTarget, boolean mayBeAsynchronous) { diff -r b0ea5c266655 -r f6ac86d3334e graal/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleRuntime.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleRuntime.java Tue Jul 15 15:49:12 2014 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleRuntime.java Tue Jul 15 16:34:53 2014 -0700 @@ -109,9 +109,21 @@ * {@link CallTarget}s. Iteration starts at the caller frame, i.e., it does not include the * current frame. * - * @return a lazy collection of {@link FrameInstance}. + * Iteration continues as long as {@link FrameInstanceVisitor#visitFrame}, which is invoked for + * every {@link FrameInstance}, returns null. Any non-null result of the visitor indicates that + * frame iteration should stop. + * + * @param visitor the visitor that is called for every matching frame. + * @return the last result returned by the visitor (which is non-null to indicate that iteration + * should stop), or null if the whole stack was iterated. */ - Iterable getStackTrace(); + T iterateFrames(FrameInstanceVisitor visitor); + + /** + * Accesses the caller frame. This is a convenience method that returns the first frame that is + * passed to the visitor of {@link #iterateFrames}. + */ + FrameInstance getCallerFrame(); /** * Accesses the current frame, i.e., the frame of the closest {@link CallTarget}. It is diff -r b0ea5c266655 -r f6ac86d3334e graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameInstanceVisitor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameInstanceVisitor.java Tue Jul 15 16:34:53 2014 -0700 @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2014, 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.frame; + +import com.oracle.truffle.api.*; + +/** + * Callback interface for {@link TruffleRuntime#iterateFrames}. Implementations of + * {@link #visitFrame} return null to indicate that frame iteration should continue and the next + * caller frame should be visited; and return any non-null value to indicate that frame iteration + * should stop. + */ +public interface FrameInstanceVisitor { + + T visitFrame(FrameInstance frameInstance); +} diff -r b0ea5c266655 -r f6ac86d3334e graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultTruffleRuntime.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultTruffleRuntime.java Tue Jul 15 15:49:12 2014 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultTruffleRuntime.java Tue Jul 15 16:34:53 2014 -0700 @@ -114,10 +114,24 @@ getThreadLocalStackTrace().removeFirst(); } - public Iterable getStackTrace() { - return getThreadLocalStackTrace(); + @Override + public T iterateFrames(FrameInstanceVisitor visitor) { + T result = null; + for (FrameInstance frameInstance : getThreadLocalStackTrace()) { + result = visitor.visitFrame(frameInstance); + if (result != null) { + return result; + } + } + return result; } + @Override + public FrameInstance getCallerFrame() { + return getThreadLocalStackTrace().peekFirst(); + } + + @Override public FrameInstance getCurrentFrame() { return currentFrames.get(); } diff -r b0ea5c266655 -r f6ac86d3334e graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLHelloEqualsWorldBuiltin.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLHelloEqualsWorldBuiltin.java Tue Jul 15 15:49:12 2014 +0200 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLHelloEqualsWorldBuiltin.java Tue Jul 15 16:34:53 2014 -0700 @@ -36,7 +36,7 @@ @Specialization public String change() { - FrameInstance frameInstance = Truffle.getRuntime().getStackTrace().iterator().next(); + FrameInstance frameInstance = Truffle.getRuntime().getCallerFrame(); Frame frame = frameInstance.getFrame(FrameAccess.READ_WRITE, false); FrameSlot slot = frame.getFrameDescriptor().findOrAddFrameSlot("hello"); frame.setObject(slot, "world"); diff -r b0ea5c266655 -r f6ac86d3334e graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLStackTraceBuiltin.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLStackTraceBuiltin.java Tue Jul 15 15:49:12 2014 +0200 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLStackTraceBuiltin.java Tue Jul 15 16:34:53 2014 -0700 @@ -45,13 +45,11 @@ @SlowPath private static String createStackTrace() { StringBuilder str = new StringBuilder(); - Iterable frames = Truffle.getRuntime().getStackTrace(); - if (frames != null) { - for (FrameInstance frame : frames) { - dumpFrame(str, frame.getCallTarget(), frame.getFrame(FrameAccess.READ_ONLY, true), frame.isVirtualFrame()); - } - } + Truffle.getRuntime().iterateFrames(frameInstance -> { + dumpFrame(str, frameInstance.getCallTarget(), frameInstance.getFrame(FrameAccess.READ_ONLY, true), frameInstance.isVirtualFrame()); + return null; + }); return str.toString(); } diff -r b0ea5c266655 -r f6ac86d3334e mx/projects --- a/mx/projects Tue Jul 15 15:49:12 2014 +0200 +++ b/mx/projects Tue Jul 15 16:34:53 2014 -0700 @@ -776,7 +776,7 @@ project@com.oracle.truffle.sl@sourceDirs=src project@com.oracle.truffle.sl@dependencies=com.oracle.truffle.api.dsl project@com.oracle.truffle.sl@checkstyle=com.oracle.graal.graph -project@com.oracle.truffle.sl@javaCompliance=1.7 +project@com.oracle.truffle.sl@javaCompliance=1.8 project@com.oracle.truffle.sl@annotationProcessors=com.oracle.truffle.dsl.processor project@com.oracle.truffle.sl@workingSets=Truffle,SimpleLanguage @@ -785,7 +785,7 @@ project@com.oracle.truffle.sl.test@sourceDirs=src project@com.oracle.truffle.sl.test@dependencies=com.oracle.truffle.sl,JUNIT project@com.oracle.truffle.sl.test@checkstyle=com.oracle.graal.graph -project@com.oracle.truffle.sl.test@javaCompliance=1.7 +project@com.oracle.truffle.sl.test@javaCompliance=1.8 project@com.oracle.truffle.sl.test@workingSets=Truffle,SimpleLanguage,Test # graal.truffle