changeset 16529:f6ac86d3334e

Change API for stack walking to a visitor: TruffleRuntime#iterateFrames replaces TruffleRuntime#getStackTrace
author Christian Wimmer <christian.wimmer@oracle.com>
date Tue, 15 Jul 2014 16:34:53 -0700
parents b0ea5c266655
children 6694631668a6
files CHANGELOG.md graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/stack/InspectedFrame.java graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/stack/InspectedFrameVisitor.java graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/stack/StackIntrospection.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotStackFrameReference.java graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleRuntime.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameInstanceVisitor.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultTruffleRuntime.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLHelloEqualsWorldBuiltin.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLStackTraceBuiltin.java mx/projects
diffstat 13 files changed, 171 insertions(+), 69 deletions(-) [+]
line wrap: on
line diff
--- 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.
--- 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);
 }
--- /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> {
+
+    T visitFrame(InspectedFrame frame);
+}
--- 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<InspectedFrame> getStackTrace(ResolvedJavaMethod[] initialMethods, ResolvedJavaMethod[] matchingMethods, int initialSkip);
+    <T> T iterateFrames(ResolvedJavaMethod[] initialMethods, ResolvedJavaMethod[] matchingMethods, int initialSkip, InspectedFrameVisitor<T> visitor);
 }
--- 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<InspectedFrame> getStackTrace(ResolvedJavaMethod[] initialMethods, ResolvedJavaMethod[] matchingMethods, int initialSkip) {
+    @Override
+    public <T> T iterateFrames(ResolvedJavaMethod[] initialMethods, ResolvedJavaMethod[] matchingMethods, int initialSkip, InspectedFrameVisitor<T> visitor) {
         final long[] initialMetaMethods = toMeta(initialMethods);
         final long[] matchingMetaMethods = toMeta(matchingMethods);
-        class StackFrameIterator implements Iterator<InspectedFrame> {
 
-            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<InspectedFrame>() {
-            public Iterator<InspectedFrame> iterator() {
-                return new StackFrameIterator();
-            }
-        };
+        return null;
     }
 
     private static long[] toMeta(ResolvedJavaMethod[] methods) {
--- 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;
     }
--- 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<FrameInstance> getStackTrace() {
+    @Override
+    public <T> T iterateFrames(FrameInstanceVisitor<T> visitor) {
         initStackIntrospection();
-        final Iterator<InspectedFrame> frames = stackIntrospection.getStackTrace(anyFrameMethod, anyFrameMethod, 1).iterator();
-        class FrameIterator implements Iterator<FrameInstance> {
 
-            public boolean hasNext() {
-                return frames.hasNext();
-            }
+        InspectedFrameVisitor<T> inspectedFrameVisitor = new InspectedFrameVisitor<T>() {
+            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<FrameInstance>() {
-            public Iterator<FrameInstance> 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<InspectedFrame> 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) {
--- 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<FrameInstance> getStackTrace();
+    <T> T iterateFrames(FrameInstanceVisitor<T> 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
--- /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> {
+
+    T visitFrame(FrameInstance frameInstance);
+}
--- 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<FrameInstance> getStackTrace() {
-        return getThreadLocalStackTrace();
+    @Override
+    public <T> T iterateFrames(FrameInstanceVisitor<T> 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();
     }
--- 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");
--- 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<FrameInstance> 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();
     }
 
--- 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