< prev index next >

src/java.base/share/classes/java/lang/StackStreamFactory.java

Print this page

        

@@ -30,10 +30,12 @@
 import java.lang.StackWalker.StackFrame;
 
 import java.lang.annotation.Native;
 import java.lang.reflect.Method;
 import java.lang.reflect.Constructor;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
 import java.util.HashSet;
 import java.util.NoSuchElementException;
 import java.util.Objects;
 import java.util.Set;
 import java.util.Spliterator;

@@ -81,11 +83,11 @@
      * Performance work and extensive testing is needed to replace the
      * VM built-in backtrace filled in Throwable with the StackWalker.
      */
     final static boolean isDebug =
             "true".equals(GetPropertyAction.privilegedGetProperty("stackwalk.debug"));
-
+    
     static <T> StackFrameTraverser<T>
         makeStackTraverser(StackWalker walker, Function<? super Stream<StackFrame>, ? extends T> function)
     {
         if (walker.hasLocalsOperandsOption())
             return new LiveStackInfoTraverser<>(walker, function);

@@ -124,10 +126,12 @@
         protected final int maxDepth;
         protected final long mode;
         protected int depth;    // traversed stack depth
         protected FrameBuffer<? extends T> frameBuffer;
         protected long anchor;
+        protected final ContinuationScope contScope;
+        protected Continuation continuation;
 
         // buffers to fill in stack frame information
         protected AbstractStackWalker(StackWalker walker, int mode) {
             this(walker, mode, Integer.MAX_VALUE);
         }

@@ -135,10 +139,12 @@
             this.thread = Thread.currentThread();
             this.mode = toStackWalkMode(walker, mode);
             this.walker = walker;
             this.maxDepth = maxDepth;
             this.depth = 0;
+            this.contScope = walker.getContScope();
+            this.continuation = walker.getContinuation();
         }
 
         private int toStackWalkMode(StackWalker walker, int mode) {
             int newMode = mode;
             if (walker.hasOption(Option.SHOW_HIDDEN_FRAMES) &&

@@ -234,10 +240,16 @@
          * Walks stack frames until {@link #consumeFrames} is done consuming
          * the frames it is interested in.
          */
         final R walk() {
             checkState(NEW);
+            return continuation != null
+                ? Continuation.wrapWalk(continuation, contScope, this::walkHelper)
+                : walkHelper();
+        }
+
+        private final R walkHelper() {
             try {
                 // VM will need to stablize the stack before walking.  It will invoke
                 // the AbstractStackWalker::doStackWalk method once it fetches the first batch.
                 // the callback will be invoked within the scope of the callStackWalk frame.
                 return beginStackWalk();

@@ -298,10 +310,12 @@
                 System.err.format("doStackWalk: skip %d start %d end %d%n",
                         skipFrames, bufStartIndex, bufEndIndex);
             }
 
             this.anchor = anchor;  // set anchor for this bulk stack frame traversal
+
+            int numFrames = bufEndIndex - bufStartIndex;
             frameBuffer.setBatch(depth, bufStartIndex, bufEndIndex);
 
             // traverse all frames and perform the action on the stack frames, if specified
             return consumeFrames();
         }

@@ -309,19 +323,37 @@
         /*
          * Get next batch of stack frames.
          */
         private int getNextBatch() {
             int nextBatchSize = Math.min(maxDepth - depth, getNextBatchSize());
-            if (!frameBuffer.isActive() || nextBatchSize <= 0) {
+
+            if (!frameBuffer.isActive() || nextBatchSize <= 0 || (frameBuffer.isAtBottom() && !hasMoreContinuations())) {
                 if (isDebug) {
                     System.out.format("  more stack walk done%n");
                 }
                 frameBuffer.freeze();   // stack walk done
                 return 0;
             }
 
-            return fetchStackFrames(nextBatchSize);
+            if (frameBuffer.isAtBottom() && hasMoreContinuations()) {
+                setContinuation(continuation.getParent());
+            }
+
+            int numFrames = fetchStackFrames(nextBatchSize);
+            if (numFrames == 0 && !hasMoreContinuations()) {
+                frameBuffer.freeze(); // done stack walking
+            }
+            return numFrames;
+        }
+
+        private boolean hasMoreContinuations() {
+            return continuation != null && continuation.getScope() != contScope && continuation.getParent() != null;
+        }
+
+        private void setContinuation(Continuation cont) {
+            this.continuation = cont;
+            setContinuation(anchor, frameBuffer.frames(), cont);
         }
 
         /*
          * This method traverses the next stack frame and returns the Class
          * invoking that stack frame.

@@ -365,11 +397,12 @@
          */
         private R beginStackWalk() {
             // initialize buffers for VM to fill the stack frame info
             initFrameBuffer();
 
-            return callStackWalk(mode, 0,
+            return callStackWalk(mode, 0, 
+                                 contScope, continuation,
                                  frameBuffer.curBatchFrameCount(),
                                  frameBuffer.startIndex(),
                                  frameBuffer.frames());
         }
 

@@ -388,14 +421,14 @@
                                             frameBuffer.frames());
             if (isDebug) {
                 System.out.format("  more stack walk requesting %d got %d to %d frames%n",
                                   batchSize, frameBuffer.startIndex(), endIndex);
             }
+
             int numFrames = endIndex - startIndex;
-            if (numFrames == 0) {
-                frameBuffer.freeze(); // done stack walking
-            } else {
+
+            if (numFrames > 0) {
                 frameBuffer.setBatch(depth, startIndex, endIndex);
             }
             return numFrames;
         }
 

@@ -403,17 +436,20 @@
          * Begins stack walking.  This method anchors this frame and invokes
          * AbstractStackWalker::doStackWalk after fetching the first batch of stack frames.
          *
          * @param mode        mode of stack walking
          * @param skipframes  number of frames to be skipped before filling the frame buffer.
+         * @param contScope   the continuation scope to walk.
+         * @param continuation the continuation to walk, or {@code null} if walking a thread.
          * @param batchSize   the batch size, max. number of elements to be filled in the frame buffers.
          * @param startIndex  start index of the frame buffers to be filled.
          * @param frames      Either a Class<?> array, if mode is {@link #FILL_CLASS_REFS_ONLY}
          *                    or a {@link StackFrameInfo} (or derivative) array otherwise.
          * @return            Result of AbstractStackWalker::doStackWalk
          */
-        private native R callStackWalk(long mode, int skipframes,
+        private native R callStackWalk(long mode, int skipframes, 
+                                       ContinuationScope contScope, Continuation continuation,
                                        int batchSize, int startIndex,
                                        T[] frames);
 
         /**
          * Fetch the next batch of stack frames.

@@ -428,10 +464,12 @@
          * @return the end index to the frame buffers
          */
         private native int fetchStackFrames(long mode, long anchor,
                                             int batchSize, int startIndex,
                                             T[] frames);
+
+        private native void setContinuation(long anchor, T[] frames, Continuation cont);
     }
 
     /*
      * This StackFrameTraverser supports {@link Stream} traversal.
      *

@@ -879,11 +917,19 @@
         /*
          * Tests if this frame buffer is active.  It is inactive when
          * it is done for traversal.  All stack frames have been traversed.
          */
         final boolean isActive() {
-            return origin > 0 && (fence == 0 || origin < fence || fence == currentBatchSize);
+            return origin > 0; //  && (fence == 0 || origin < fence || fence == currentBatchSize);
+        }
+
+        /*
+         * Tests if this frame buffer is at the end of the stack
+         * and all frames have been traversed.
+         */
+        final boolean isAtBottom() {
+            return origin > 0 && origin >= fence && fence < currentBatchSize;
         }
 
         /**
          * Gets the class at the current frame and move to the next frame.
          */
< prev index next >