< prev index next >

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

Print this page
*** 30,19 ***
--- 30,23 ---
  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;
  import java.util.function.Consumer;
  import java.util.function.Function;
  import java.util.stream.Stream;
  import java.util.stream.StreamSupport;
+ import jdk.internal.vm.Continuation;
+ import jdk.internal.vm.ContinuationScope;
  import sun.security.action.GetPropertyAction;
  
  import static java.lang.StackStreamFactory.WalkerState.*;
  
  /**

*** 81,11 ***
       * Performance work and extensive testing is needed to replace the
       * VM built-in backtrace filled in Throwable with the StackWalker.
       */
      static final 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);
--- 85,11 ---
       * Performance work and extensive testing is needed to replace the
       * VM built-in backtrace filled in Throwable with the StackWalker.
       */
      static final 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 ***
--- 128,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 ***
--- 141,18 ---
              this.thread = Thread.currentThread();
              this.mode = toStackWalkMode(walker, mode);
              this.walker = walker;
              this.maxDepth = maxDepth;
              this.depth = 0;
+             ContinuationScope scope = walker.getContScope();
+             if (scope == null && thread.isVirtual()) {
+                 this.contScope = VirtualThread.continuationScope();
+                 this.continuation = null;
+             } else {
+                 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 ***
--- 248,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 stabilize 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 ***
--- 318,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 ***
          /*
           * Get next batch of stack frames.
           */
          private int getNextBatch() {
              int nextBatchSize = Math.min(maxDepth - depth, getNextBatchSize());
!             if (!frameBuffer.isActive() || nextBatchSize <= 0) {
                  if (isDebug) {
                      System.out.format("  more stack walk done%n");
                  }
                  frameBuffer.freeze();   // stack walk done
                  return 0;
              }
  
!             return fetchStackFrames(nextBatchSize);
          }
  
          /*
           * This method traverses the next stack frame and returns the Class
           * invoking that stack frame.
--- 331,37 ---
          /*
           * Get next batch of stack frames.
           */
          private int getNextBatch() {
              int nextBatchSize = Math.min(maxDepth - depth, getNextBatchSize());
! 
+             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;
              }
  
!             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 ***
           */
          private R beginStackWalk() {
              // initialize buffers for VM to fill the stack frame info
              initFrameBuffer();
  
!             return callStackWalk(mode, 0,
                                   frameBuffer.curBatchFrameCount(),
                                   frameBuffer.startIndex(),
                                   frameBuffer.frames());
          }
  
--- 405,12 ---
           */
          private R beginStackWalk() {
              // initialize buffers for VM to fill the stack frame info
              initFrameBuffer();
  
!             return callStackWalk(mode, 0, 
+                                  contScope, continuation,
                                   frameBuffer.curBatchFrameCount(),
                                   frameBuffer.startIndex(),
                                   frameBuffer.frames());
          }
  

*** 388,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 {
                  frameBuffer.setBatch(depth, startIndex, endIndex);
              }
              return numFrames;
          }
  
--- 429,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.setBatch(depth, startIndex, endIndex);
              }
              return numFrames;
          }
  

*** 403,17 ***
           * 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 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,
                                         int batchSize, int startIndex,
                                         T[] frames);
  
          /**
           * Fetch the next batch of stack frames.
--- 444,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, 
+                                        ContinuationScope contScope, Continuation continuation,
                                         int batchSize, int startIndex,
                                         T[] frames);
  
          /**
           * Fetch the next batch of stack frames.

*** 428,10 ***
--- 472,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.
       *

*** 495,10 ***
--- 541,15 ---
  
              @Override
              final Class<?> at(int index) {
                  return stackFrames[index].declaringClass();
              }
+ 
+             @Override
+             final boolean filter(int index) {
+                 return stackFrames[index].declaringClass() == Continuation.class && "yield0".equals(stackFrames[index].getMethodName());
+             }
          }
  
          final Function<? super Stream<StackFrame>, ? extends T> function;  // callback
  
          StackFrameTraverser(StackWalker walker,

*** 631,10 ***
--- 682,13 ---
              Class<?>[] frames() { return classes;}
  
              @Override
              final Class<?> at(int index) { return classes[index];}
  
+             @Override
+             final boolean filter(int index) { return false; }
+ 
  
              // ------ subclass may override the following methods -------
              /**
               * Resizes the buffers for VM to fill in the next batch of stack frames.
               * The next batch will start at the given startIndex with the maximum number

*** 763,10 ***
--- 817,15 ---
  
              @Override
              final Class<?> at(int index) {
                  return stackFrames[index].declaringClass();
              }
+ 
+             @Override
+             final boolean filter(int index) {
+                 return stackFrames[index].declaringClass() == Continuation.class && "yield0".equals(stackFrames[index].getMethodName());
+             }
          }
  
          LiveStackInfoTraverser(StackWalker walker,
                                 Function<? super Stream<StackFrame>, ? extends T> function) {
              super(walker, function, DEFAULT_MODE);

*** 832,10 ***
--- 891,17 ---
           * @param index the position of the frame.
           * @return the class at the given position in the current batch.
           */
          abstract Class<?> at(int index);
  
+         /**
+          * Filter out frames at the top of a batch
+          * @param index the position of the frame.
+          * @return true if the frame should be skipped
+          */
+         abstract boolean filter(int index);
+ 
          // ------ subclass may override the following methods -------
  
          /*
           * Returns the start index for this frame buffer is refilled.
           *

*** 879,11 ***
          /*
           * 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);
          }
  
          /**
           * Gets the class at the current frame and move to the next frame.
           */
--- 945,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);
+         }
+ 
+         /*
+          * 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.
           */

*** 927,20 ***
                  throw new IllegalArgumentException("startIndex=" + startIndex
                          + " endIndex=" + endIndex);
  
              this.origin = startIndex;
              this.fence = endIndex;
!             if (depth == 0 && fence > 0) {
!                 // filter the frames due to the stack stream implementation
!                 for (int i = START_POS; i < fence; i++) {
!                     Class<?> c = at(i);
!                     if (isDebug) System.err.format("  frame %d: %s%n", i, c);
!                     if (filterStackWalkImpl(c)) {
!                         origin++;
-                     } else {
-                         break;
-                     }
                  }
              }
          }
  
          /*
--- 1001,17 ---
                  throw new IllegalArgumentException("startIndex=" + startIndex
                          + " endIndex=" + endIndex);
  
              this.origin = startIndex;
              this.fence = endIndex;
!             for (int i = START_POS; i < fence; i++) {
!                 if (isDebug) System.err.format("  frame %d: %s%n", i, at(i));
!                 if ((depth == 0 && filterStackWalkImpl(at(i))) // filter the frames due to the stack stream implementation
!                         || filter(i)) {
!                     origin++;
!                 } else {
!                     break;
                  }
              }
          }
  
          /*
< prev index next >