< prev index next >

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

Print this page

  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 package java.lang;
  26 
  27 import jdk.internal.reflect.MethodAccessor;
  28 import jdk.internal.reflect.ConstructorAccessor;
  29 import java.lang.StackWalker.Option;
  30 import java.lang.StackWalker.StackFrame;
  31 
  32 import java.lang.annotation.Native;
  33 import java.lang.reflect.Method;
  34 import java.lang.reflect.Constructor;


  35 import java.util.HashSet;
  36 import java.util.NoSuchElementException;
  37 import java.util.Objects;
  38 import java.util.Set;
  39 import java.util.Spliterator;
  40 import java.util.function.Consumer;
  41 import java.util.function.Function;
  42 import java.util.stream.Stream;
  43 import java.util.stream.StreamSupport;


  44 import sun.security.action.GetPropertyAction;
  45 
  46 import static java.lang.StackStreamFactory.WalkerState.*;
  47 
  48 /**
  49  * StackStreamFactory class provides static factory methods
  50  * to get different kinds of stack walker/traverser.
  51  *
  52  * AbstractStackWalker provides the basic stack walking support
  53  * fetching stack frames from VM in batches.
  54  *
  55  * AbstractStackWalker subclass is specialized for a specific kind of stack traversal
  56  * to avoid overhead of Stream/Lambda
  57  * 1. Support traversing Stream<StackFrame>
  58  * 2. StackWalker::getCallerClass
  59  * 3. AccessControlContext getting ProtectionDomain
  60  */
  61 final class StackStreamFactory {
  62     private StackStreamFactory() {}
  63 

  66     private static final Set<Class<?>> stackWalkImplClasses = init();
  67 
  68     private static final int SMALL_BATCH       = 8;
  69     private static final int BATCH_SIZE        = 32;
  70     private static final int LARGE_BATCH_SIZE  = 256;
  71     private static final int MIN_BATCH_SIZE    = SMALL_BATCH;
  72 
  73     // These flags must match the values maintained in the VM
  74     @Native private static final int DEFAULT_MODE              = 0x0;
  75     @Native private static final int FILL_CLASS_REFS_ONLY      = 0x2;
  76     @Native private static final int GET_CALLER_CLASS          = 0x4;
  77     @Native private static final int SHOW_HIDDEN_FRAMES        = 0x20;  // LambdaForms are hidden by the VM
  78     @Native private static final int FILL_LIVE_STACK_FRAMES    = 0x100;
  79     /*
  80      * For Throwable to use StackWalker, set useNewThrowable to true.
  81      * Performance work and extensive testing is needed to replace the
  82      * VM built-in backtrace filled in Throwable with the StackWalker.
  83      */
  84     static final boolean isDebug =
  85             "true".equals(GetPropertyAction.privilegedGetProperty("stackwalk.debug"));
  86 
  87     static <T> StackFrameTraverser<T>
  88         makeStackTraverser(StackWalker walker, Function<? super Stream<StackFrame>, ? extends T> function)
  89     {
  90         if (walker.hasLocalsOperandsOption())
  91             return new LiveStackInfoTraverser<>(walker, function);
  92         else
  93             return new StackFrameTraverser<>(walker, function);
  94     }
  95 
  96     /**
  97      * Gets a stack stream to find caller class.
  98      */
  99     static CallerClassFinder makeCallerFinder(StackWalker walker) {
 100         return new CallerClassFinder(walker);
 101     }
 102 
 103     enum WalkerState {
 104         NEW,     // the stream is new and stack walking has not started
 105         OPEN,    // the stream is open when it is being traversed.
 106         CLOSED;  // the stream is closed when the stack walking is done

 109     /**
 110      * Subclass of AbstractStackWalker implements a specific stack walking logic.
 111      * It needs to set up the frame buffer and stack walking mode.
 112      *
 113      * It initiates the VM stack walking via the callStackWalk method that serves
 114      * as the anchored frame and VM will call up to AbstractStackWalker::doStackWalk.
 115      *
 116      * @param <R> the type of the result returned from stack walking
 117      * @param <T> the type of the data gathered for each frame.
 118      *            For example, StackFrameInfo for StackWalker::walk or
 119      *            Class<?> for StackWalker::getCallerClass
 120      */
 121     static abstract class AbstractStackWalker<R, T> {
 122         protected final StackWalker walker;
 123         protected final Thread thread;
 124         protected final int maxDepth;
 125         protected final long mode;
 126         protected int depth;    // traversed stack depth
 127         protected FrameBuffer<? extends T> frameBuffer;
 128         protected long anchor;


 129 
 130         // buffers to fill in stack frame information
 131         protected AbstractStackWalker(StackWalker walker, int mode) {
 132             this(walker, mode, Integer.MAX_VALUE);
 133         }
 134         protected AbstractStackWalker(StackWalker walker, int mode, int maxDepth) {
 135             this.thread = Thread.currentThread();
 136             this.mode = toStackWalkMode(walker, mode);
 137             this.walker = walker;
 138             this.maxDepth = maxDepth;
 139             this.depth = 0;








 140         }
 141 
 142         private int toStackWalkMode(StackWalker walker, int mode) {
 143             int newMode = mode;
 144             if (walker.hasOption(Option.SHOW_HIDDEN_FRAMES) &&
 145                     (mode & FILL_CLASS_REFS_ONLY) != FILL_CLASS_REFS_ONLY)
 146                 newMode |= SHOW_HIDDEN_FRAMES;
 147             if (walker.hasLocalsOperandsOption())
 148                 newMode |= FILL_LIVE_STACK_FRAMES;
 149             return newMode;
 150         }
 151 
 152         /**
 153          * A callback method to consume the stack frames.  This method is invoked
 154          * once stack walking begins (i.e. it is only invoked when walkFrames is called).
 155          *
 156          * Each specialized AbstractStackWalker subclass implements the consumeFrames method
 157          * to control the following:
 158          * 1. fetch the subsequent batches of stack frames
 159          * 2. reuse or expand the allocated buffers

 219                 case CLOSED:
 220                     if (anchor != -1L) {
 221                         throw new IllegalStateException("This stack stream is not closed.");
 222                     }
 223             }
 224         }
 225 
 226         /*
 227          * Close this stream.  This stream becomes invalid to walk.
 228          */
 229         private void close() {
 230             this.anchor = -1L;
 231         }
 232 
 233         /*
 234          * Walks stack frames until {@link #consumeFrames} is done consuming
 235          * the frames it is interested in.
 236          */
 237         final R walk() {
 238             checkState(NEW);






 239             try {
 240                 // VM will need to stabilize the stack before walking.  It will invoke
 241                 // the AbstractStackWalker::doStackWalk method once it fetches the first batch.
 242                 // the callback will be invoked within the scope of the callStackWalk frame.
 243                 return beginStackWalk();
 244             } finally {
 245                 close();  // done traversal; close the stream
 246             }
 247         }
 248 
 249         private boolean skipReflectionFrames() {
 250             return !walker.hasOption(Option.SHOW_REFLECT_FRAMES) &&
 251                        !walker.hasOption(Option.SHOW_HIDDEN_FRAMES);
 252         }
 253 
 254         /*
 255          * Returns {@code Class} object at the current frame;
 256          * or {@code null} if no more frame. If advanceToNextBatch is true,
 257          * it will only fetch the next batch.
 258          */

 283          *
 284          * It will invoke the consumeFrames method to start the stack walking
 285          * with the first batch of stack frames.  Each specialized AbstractStackWalker
 286          * subclass implements the consumeFrames method to control the following:
 287          * 1. fetch the subsequent batches of stack frames
 288          * 2. reuse or expand the allocated buffers
 289          * 3. create specialized StackFrame objects
 290          */
 291         private Object doStackWalk(long anchor, int skipFrames, int batchSize,
 292                                                 int bufStartIndex, int bufEndIndex) {
 293             checkState(NEW);
 294 
 295             frameBuffer.check(skipFrames);
 296 
 297             if (isDebug) {
 298                 System.err.format("doStackWalk: skip %d start %d end %d%n",
 299                         skipFrames, bufStartIndex, bufEndIndex);
 300             }
 301 
 302             this.anchor = anchor;  // set anchor for this bulk stack frame traversal


 303             frameBuffer.setBatch(depth, bufStartIndex, bufEndIndex);
 304 
 305             // traverse all frames and perform the action on the stack frames, if specified
 306             return consumeFrames();
 307         }
 308 
 309         /*
 310          * Get next batch of stack frames.
 311          */
 312         private int getNextBatch() {
 313             int nextBatchSize = Math.min(maxDepth - depth, getNextBatchSize());
 314             if (!frameBuffer.isActive() || nextBatchSize <= 0) {

 315                 if (isDebug) {
 316                     System.out.format("  more stack walk done%n");
 317                 }
 318                 frameBuffer.freeze();   // stack walk done
 319                 return 0;
 320             }
 321 
 322             return fetchStackFrames(nextBatchSize);

















 323         }
 324 
 325         /*
 326          * This method traverses the next stack frame and returns the Class
 327          * invoking that stack frame.
 328          *
 329          * This method can only be called during the walk method.  This is intended
 330          * to be used to walk the stack frames in one single invocation and
 331          * this stack stream will be invalidated once walk is done.
 332          *
 333          * @see #tryNextFrame
 334          */
 335         final Class<?> nextFrame() {
 336             if (!hasNext()) {
 337                 return null;
 338             }
 339 
 340             Class<?> c = frameBuffer.next();
 341             depth++;
 342             return c;

 350         final boolean hasNext() {
 351             return peekFrame() != null;
 352         }
 353 
 354         /**
 355          * Begin stack walking - pass the allocated arrays to the VM to fill in
 356          * stack frame information.
 357          *
 358          * VM first anchors the frame of the current thread.  A traversable stream
 359          * on this thread's stack will be opened.  The VM will fetch the first batch
 360          * of stack frames and call AbstractStackWalker::doStackWalk to invoke the
 361          * stack walking function on each stack frame.
 362          *
 363          * If all fetched stack frames are traversed, AbstractStackWalker::fetchStackFrames will
 364          * fetch the next batch of stack frames to continue.
 365          */
 366         private R beginStackWalk() {
 367             // initialize buffers for VM to fill the stack frame info
 368             initFrameBuffer();
 369 
 370             return callStackWalk(mode, 0,

 371                                  frameBuffer.curBatchFrameCount(),
 372                                  frameBuffer.startIndex(),
 373                                  frameBuffer.frames());
 374         }
 375 
 376         /*
 377          * Fetches stack frames.
 378          *
 379          * @params batchSize number of elements of the frame  buffers for this batch
 380          * @returns number of frames fetched in this batch
 381          */
 382         private int fetchStackFrames(int batchSize) {
 383             int startIndex = frameBuffer.startIndex();
 384             frameBuffer.resize(startIndex, batchSize);
 385 
 386             int endIndex = fetchStackFrames(mode, anchor, batchSize,
 387                                             startIndex,
 388                                             frameBuffer.frames());
 389             if (isDebug) {
 390                 System.out.format("  more stack walk requesting %d got %d to %d frames%n",
 391                                   batchSize, frameBuffer.startIndex(), endIndex);
 392             }

 393             int numFrames = endIndex - startIndex;
 394             if (numFrames == 0) {
 395                 frameBuffer.freeze(); // done stack walking
 396             } else {
 397                 frameBuffer.setBatch(depth, startIndex, endIndex);
 398             }
 399             return numFrames;
 400         }
 401 
 402         /**
 403          * Begins stack walking.  This method anchors this frame and invokes
 404          * AbstractStackWalker::doStackWalk after fetching the first batch of stack frames.
 405          *
 406          * @param mode        mode of stack walking
 407          * @param skipframes  number of frames to be skipped before filling the frame buffer.


 408          * @param batchSize   the batch size, max. number of elements to be filled in the frame buffers.
 409          * @param startIndex  start index of the frame buffers to be filled.
 410          * @param frames      Either a Class<?> array, if mode is {@link #FILL_CLASS_REFS_ONLY}
 411          *                    or a {@link StackFrameInfo} (or derivative) array otherwise.
 412          * @return            Result of AbstractStackWalker::doStackWalk
 413          */
 414         private native R callStackWalk(long mode, int skipframes,

 415                                        int batchSize, int startIndex,
 416                                        T[] frames);
 417 
 418         /**
 419          * Fetch the next batch of stack frames.
 420          *
 421          * @param mode        mode of stack walking
 422          * @param anchor
 423          * @param batchSize   the batch size, max. number of elements to be filled in the frame buffers.
 424          * @param startIndex  start index of the frame buffers to be filled.
 425          * @param frames      Either a Class<?> array, if mode is {@link #FILL_CLASS_REFS_ONLY}
 426          *                    or a {@link StackFrameInfo} (or derivative) array otherwise.
 427          *
 428          * @return the end index to the frame buffers
 429          */
 430         private native int fetchStackFrames(long mode, long anchor,
 431                                             int batchSize, int startIndex,
 432                                             T[] frames);


 433     }
 434 
 435     /*
 436      * This StackFrameTraverser supports {@link Stream} traversal.
 437      *
 438      * This class implements Spliterator::forEachRemaining and Spliterator::tryAdvance.
 439      */
 440     static class StackFrameTraverser<T> extends AbstractStackWalker<T, StackFrameInfo>
 441             implements Spliterator<StackFrame>
 442     {
 443         static {
 444             stackWalkImplClasses.add(StackFrameTraverser.class);
 445         }
 446         private static final int CHARACTERISTICS = Spliterator.ORDERED | Spliterator.IMMUTABLE;
 447 
 448         final class StackFrameBuffer extends FrameBuffer<StackFrameInfo> {
 449             private StackFrameInfo[] stackFrames;
 450             StackFrameBuffer(int initialBatchSize) {
 451                 super(initialBatchSize);
 452 

 480                     stackFrames[i] = new StackFrameInfo(walker);
 481                 }
 482                 currentBatchSize = size;
 483             }
 484 
 485             @Override
 486             StackFrameInfo nextStackFrame() {
 487                 if (isEmpty()) {
 488                     throw new NoSuchElementException("origin=" + origin + " fence=" + fence);
 489                 }
 490 
 491                 StackFrameInfo frame = stackFrames[origin];
 492                 origin++;
 493                 return frame;
 494             }
 495 
 496             @Override
 497             final Class<?> at(int index) {
 498                 return stackFrames[index].declaringClass();
 499             }





 500         }
 501 
 502         final Function<? super Stream<StackFrame>, ? extends T> function;  // callback
 503 
 504         StackFrameTraverser(StackWalker walker,
 505                             Function<? super Stream<StackFrame>, ? extends T> function) {
 506             this(walker, function, DEFAULT_MODE);
 507         }
 508         StackFrameTraverser(StackWalker walker,
 509                             Function<? super Stream<StackFrame>, ? extends T> function,
 510                             int mode) {
 511             super(walker, mode);
 512             this.function = function;
 513         }
 514 
 515         /**
 516          * Returns next StackFrame object in the current batch of stack frames;
 517          * or null if no more stack frame.
 518          */
 519         StackFrame nextStackFrame() {

 616 
 617         private Class<?> caller;
 618 
 619         CallerClassFinder(StackWalker walker) {
 620             super(walker, FILL_CLASS_REFS_ONLY|GET_CALLER_CLASS);
 621         }
 622 
 623         static final class ClassBuffer extends FrameBuffer<Class<?>> {
 624             Class<?>[] classes;      // caller class for fast path
 625             ClassBuffer(int batchSize) {
 626                 super(batchSize);
 627                 classes = new Class<?>[batchSize];
 628             }
 629 
 630             @Override
 631             Class<?>[] frames() { return classes;}
 632 
 633             @Override
 634             final Class<?> at(int index) { return classes[index];}
 635 



 636 
 637             // ------ subclass may override the following methods -------
 638             /**
 639              * Resizes the buffers for VM to fill in the next batch of stack frames.
 640              * The next batch will start at the given startIndex with the maximum number
 641              * of elements.
 642              *
 643              * <p> Subclass may override this method to manage the allocated buffers.
 644              *
 645              * @param startIndex the start index for the first frame of the next batch to fill in.
 646              * @param elements the number of elements for the next batch to fill in.
 647              *
 648              */
 649             @Override
 650             void resize(int startIndex, int elements) {
 651                 if (!isActive())
 652                     throw new IllegalStateException("inactive frame buffer can't be resized");
 653 
 654                 assert startIndex == START_POS :
 655                        "bad start index " + startIndex + " expected " + START_POS;

 748                 }
 749 
 750                 currentBatchSize = size;
 751             }
 752 
 753             @Override
 754             LiveStackFrameInfo nextStackFrame() {
 755                 if (isEmpty()) {
 756                     throw new NoSuchElementException("origin=" + origin + " fence=" + fence);
 757                 }
 758 
 759                 LiveStackFrameInfo frame = stackFrames[origin];
 760                 origin++;
 761                 return frame;
 762             }
 763 
 764             @Override
 765             final Class<?> at(int index) {
 766                 return stackFrames[index].declaringClass();
 767             }





 768         }
 769 
 770         LiveStackInfoTraverser(StackWalker walker,
 771                                Function<? super Stream<StackFrame>, ? extends T> function) {
 772             super(walker, function, DEFAULT_MODE);
 773         }
 774 
 775         @Override
 776         protected void initFrameBuffer() {
 777             this.frameBuffer = new LiveStackFrameBuffer(getNextBatchSize());
 778         }
 779     }
 780 
 781     /*
 782      * Frame buffer
 783      *
 784      * Each specialized AbstractStackWalker subclass may subclass the FrameBuffer.
 785      */
 786     static abstract class FrameBuffer<F> {
 787         static final int START_POS = 2;     // 0th and 1st elements are reserved

 817         /**
 818          * Resizes the buffers for VM to fill in the next batch of stack frames.
 819          * The next batch will start at the given startIndex with the maximum number
 820          * of elements.
 821          *
 822          * <p> Subclass may override this method to manage the allocated buffers.
 823          *
 824          * @param startIndex the start index for the first frame of the next batch to fill in.
 825          * @param elements the number of elements for the next batch to fill in.
 826          *
 827          */
 828         abstract void resize(int startIndex, int elements);
 829 
 830         /**
 831          * Return the class at the given position in the current batch.
 832          * @param index the position of the frame.
 833          * @return the class at the given position in the current batch.
 834          */
 835         abstract Class<?> at(int index);
 836 







 837         // ------ subclass may override the following methods -------
 838 
 839         /*
 840          * Returns the start index for this frame buffer is refilled.
 841          *
 842          * This implementation reuses the allocated buffer for the next batch
 843          * of stack frames.  For subclass to retain the fetched stack frames,
 844          * it should override this method to return the index at which the frame
 845          * should be filled in for the next batch.
 846          */
 847         int startIndex() {
 848             return START_POS;
 849         }
 850 
 851         /**
 852          * Returns next StackFrame object in the current batch of stack frames
 853          */
 854         F nextStackFrame() {
 855             throw new InternalError("should not reach here");
 856         }

 864         /*
 865          * Tests if this frame buffer is empty.  All frames are fetched.
 866          */
 867         final boolean isEmpty() {
 868             return origin >= fence || (origin == START_POS && fence == 0);
 869         }
 870 
 871         /*
 872          * Freezes this frame buffer.  The stack stream source is done fetching.
 873          */
 874         final void freeze() {
 875             origin = 0;
 876             fence = 0;
 877         }
 878 
 879         /*
 880          * Tests if this frame buffer is active.  It is inactive when
 881          * it is done for traversal.  All stack frames have been traversed.
 882          */
 883         final boolean isActive() {
 884             return origin > 0 && (fence == 0 || origin < fence || fence == currentBatchSize);








 885         }
 886 
 887         /**
 888          * Gets the class at the current frame and move to the next frame.
 889          */
 890         final Class<?> next() {
 891             if (isEmpty()) {
 892                 throw new NoSuchElementException("origin=" + origin + " fence=" + fence);
 893             }
 894             Class<?> c = at(origin);
 895             origin++;
 896             if (isDebug) {
 897                 int index = origin-1;
 898                 System.out.format("  next frame at %d: %s (origin %d fence %d)%n", index,
 899                         Objects.toString(c), index, fence);
 900             }
 901             return c;
 902         }
 903 
 904         /**

 912         }
 913 
 914         /*
 915          * Returns the index of the current frame.
 916          */
 917         final int getIndex() {
 918             return origin;
 919         }
 920 
 921         /*
 922          * Set the start and end index of a new batch of stack frames that have
 923          * been filled in this frame buffer.
 924          */
 925         final void setBatch(int depth, int startIndex, int endIndex) {
 926             if (startIndex <= 0 || endIndex <= 0)
 927                 throw new IllegalArgumentException("startIndex=" + startIndex
 928                         + " endIndex=" + endIndex);
 929 
 930             this.origin = startIndex;
 931             this.fence = endIndex;
 932             if (depth == 0 && fence > 0) {
 933                 // filter the frames due to the stack stream implementation
 934                 for (int i = START_POS; i < fence; i++) {
 935                     Class<?> c = at(i);
 936                     if (isDebug) System.err.format("  frame %d: %s%n", i, c);
 937                     if (filterStackWalkImpl(c)) {
 938                         origin++;
 939                     } else {
 940                         break;
 941                     }
 942                 }
 943             }
 944         }
 945 
 946         /*
 947          * Checks if the origin is the expected start index.
 948          */
 949         final void check(int skipFrames) {
 950             int index = skipFrames + START_POS;
 951             if (origin != index) {
 952                 // stack walk must continue with the previous frame depth
 953                 throw new IllegalStateException("origin " + origin + " != " + index);
 954             }
 955         }
 956     }
 957 
 958     private static native boolean checkStackWalkModes();
 959 
 960     // avoid loading other subclasses as they may not be used
 961     private static Set<Class<?>> init() {

  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 package java.lang;
  26 
  27 import jdk.internal.reflect.MethodAccessor;
  28 import jdk.internal.reflect.ConstructorAccessor;
  29 import java.lang.StackWalker.Option;
  30 import java.lang.StackWalker.StackFrame;
  31 
  32 import java.lang.annotation.Native;
  33 import java.lang.reflect.Method;
  34 import java.lang.reflect.Constructor;
  35 import java.security.AccessController;
  36 import java.security.PrivilegedAction;
  37 import java.util.HashSet;
  38 import java.util.NoSuchElementException;
  39 import java.util.Objects;
  40 import java.util.Set;
  41 import java.util.Spliterator;
  42 import java.util.function.Consumer;
  43 import java.util.function.Function;
  44 import java.util.stream.Stream;
  45 import java.util.stream.StreamSupport;
  46 import jdk.internal.vm.Continuation;
  47 import jdk.internal.vm.ContinuationScope;
  48 import sun.security.action.GetPropertyAction;
  49 
  50 import static java.lang.StackStreamFactory.WalkerState.*;
  51 
  52 /**
  53  * StackStreamFactory class provides static factory methods
  54  * to get different kinds of stack walker/traverser.
  55  *
  56  * AbstractStackWalker provides the basic stack walking support
  57  * fetching stack frames from VM in batches.
  58  *
  59  * AbstractStackWalker subclass is specialized for a specific kind of stack traversal
  60  * to avoid overhead of Stream/Lambda
  61  * 1. Support traversing Stream<StackFrame>
  62  * 2. StackWalker::getCallerClass
  63  * 3. AccessControlContext getting ProtectionDomain
  64  */
  65 final class StackStreamFactory {
  66     private StackStreamFactory() {}
  67 

  70     private static final Set<Class<?>> stackWalkImplClasses = init();
  71 
  72     private static final int SMALL_BATCH       = 8;
  73     private static final int BATCH_SIZE        = 32;
  74     private static final int LARGE_BATCH_SIZE  = 256;
  75     private static final int MIN_BATCH_SIZE    = SMALL_BATCH;
  76 
  77     // These flags must match the values maintained in the VM
  78     @Native private static final int DEFAULT_MODE              = 0x0;
  79     @Native private static final int FILL_CLASS_REFS_ONLY      = 0x2;
  80     @Native private static final int GET_CALLER_CLASS          = 0x4;
  81     @Native private static final int SHOW_HIDDEN_FRAMES        = 0x20;  // LambdaForms are hidden by the VM
  82     @Native private static final int FILL_LIVE_STACK_FRAMES    = 0x100;
  83     /*
  84      * For Throwable to use StackWalker, set useNewThrowable to true.
  85      * Performance work and extensive testing is needed to replace the
  86      * VM built-in backtrace filled in Throwable with the StackWalker.
  87      */
  88     static final boolean isDebug =
  89             "true".equals(GetPropertyAction.privilegedGetProperty("stackwalk.debug"));
  90     
  91     static <T> StackFrameTraverser<T>
  92         makeStackTraverser(StackWalker walker, Function<? super Stream<StackFrame>, ? extends T> function)
  93     {
  94         if (walker.hasLocalsOperandsOption())
  95             return new LiveStackInfoTraverser<>(walker, function);
  96         else
  97             return new StackFrameTraverser<>(walker, function);
  98     }
  99 
 100     /**
 101      * Gets a stack stream to find caller class.
 102      */
 103     static CallerClassFinder makeCallerFinder(StackWalker walker) {
 104         return new CallerClassFinder(walker);
 105     }
 106 
 107     enum WalkerState {
 108         NEW,     // the stream is new and stack walking has not started
 109         OPEN,    // the stream is open when it is being traversed.
 110         CLOSED;  // the stream is closed when the stack walking is done

 113     /**
 114      * Subclass of AbstractStackWalker implements a specific stack walking logic.
 115      * It needs to set up the frame buffer and stack walking mode.
 116      *
 117      * It initiates the VM stack walking via the callStackWalk method that serves
 118      * as the anchored frame and VM will call up to AbstractStackWalker::doStackWalk.
 119      *
 120      * @param <R> the type of the result returned from stack walking
 121      * @param <T> the type of the data gathered for each frame.
 122      *            For example, StackFrameInfo for StackWalker::walk or
 123      *            Class<?> for StackWalker::getCallerClass
 124      */
 125     static abstract class AbstractStackWalker<R, T> {
 126         protected final StackWalker walker;
 127         protected final Thread thread;
 128         protected final int maxDepth;
 129         protected final long mode;
 130         protected int depth;    // traversed stack depth
 131         protected FrameBuffer<? extends T> frameBuffer;
 132         protected long anchor;
 133         protected final ContinuationScope contScope;
 134         protected Continuation continuation;
 135 
 136         // buffers to fill in stack frame information
 137         protected AbstractStackWalker(StackWalker walker, int mode) {
 138             this(walker, mode, Integer.MAX_VALUE);
 139         }
 140         protected AbstractStackWalker(StackWalker walker, int mode, int maxDepth) {
 141             this.thread = Thread.currentThread();
 142             this.mode = toStackWalkMode(walker, mode);
 143             this.walker = walker;
 144             this.maxDepth = maxDepth;
 145             this.depth = 0;
 146             ContinuationScope scope = walker.getContScope();
 147             if (scope == null && thread.isVirtual()) {
 148                 this.contScope = VirtualThread.continuationScope();
 149                 this.continuation = null;
 150             } else {
 151                 this.contScope = walker.getContScope();
 152                 this.continuation = walker.getContinuation();
 153             }
 154         }
 155 
 156         private int toStackWalkMode(StackWalker walker, int mode) {
 157             int newMode = mode;
 158             if (walker.hasOption(Option.SHOW_HIDDEN_FRAMES) &&
 159                     (mode & FILL_CLASS_REFS_ONLY) != FILL_CLASS_REFS_ONLY)
 160                 newMode |= SHOW_HIDDEN_FRAMES;
 161             if (walker.hasLocalsOperandsOption())
 162                 newMode |= FILL_LIVE_STACK_FRAMES;
 163             return newMode;
 164         }
 165 
 166         /**
 167          * A callback method to consume the stack frames.  This method is invoked
 168          * once stack walking begins (i.e. it is only invoked when walkFrames is called).
 169          *
 170          * Each specialized AbstractStackWalker subclass implements the consumeFrames method
 171          * to control the following:
 172          * 1. fetch the subsequent batches of stack frames
 173          * 2. reuse or expand the allocated buffers

 233                 case CLOSED:
 234                     if (anchor != -1L) {
 235                         throw new IllegalStateException("This stack stream is not closed.");
 236                     }
 237             }
 238         }
 239 
 240         /*
 241          * Close this stream.  This stream becomes invalid to walk.
 242          */
 243         private void close() {
 244             this.anchor = -1L;
 245         }
 246 
 247         /*
 248          * Walks stack frames until {@link #consumeFrames} is done consuming
 249          * the frames it is interested in.
 250          */
 251         final R walk() {
 252             checkState(NEW);
 253             return continuation != null
 254                 ? Continuation.wrapWalk(continuation, contScope, this::walkHelper)
 255                 : walkHelper();
 256         }
 257 
 258         private final R walkHelper() {
 259             try {
 260                 // VM will need to stabilize the stack before walking.  It will invoke
 261                 // the AbstractStackWalker::doStackWalk method once it fetches the first batch.
 262                 // the callback will be invoked within the scope of the callStackWalk frame.
 263                 return beginStackWalk();
 264             } finally {
 265                 close();  // done traversal; close the stream
 266             }
 267         }
 268 
 269         private boolean skipReflectionFrames() {
 270             return !walker.hasOption(Option.SHOW_REFLECT_FRAMES) &&
 271                        !walker.hasOption(Option.SHOW_HIDDEN_FRAMES);
 272         }
 273 
 274         /*
 275          * Returns {@code Class} object at the current frame;
 276          * or {@code null} if no more frame. If advanceToNextBatch is true,
 277          * it will only fetch the next batch.
 278          */

 303          *
 304          * It will invoke the consumeFrames method to start the stack walking
 305          * with the first batch of stack frames.  Each specialized AbstractStackWalker
 306          * subclass implements the consumeFrames method to control the following:
 307          * 1. fetch the subsequent batches of stack frames
 308          * 2. reuse or expand the allocated buffers
 309          * 3. create specialized StackFrame objects
 310          */
 311         private Object doStackWalk(long anchor, int skipFrames, int batchSize,
 312                                                 int bufStartIndex, int bufEndIndex) {
 313             checkState(NEW);
 314 
 315             frameBuffer.check(skipFrames);
 316 
 317             if (isDebug) {
 318                 System.err.format("doStackWalk: skip %d start %d end %d%n",
 319                         skipFrames, bufStartIndex, bufEndIndex);
 320             }
 321 
 322             this.anchor = anchor;  // set anchor for this bulk stack frame traversal
 323 
 324             int numFrames = bufEndIndex - bufStartIndex;
 325             frameBuffer.setBatch(depth, bufStartIndex, bufEndIndex);
 326 
 327             // traverse all frames and perform the action on the stack frames, if specified
 328             return consumeFrames();
 329         }
 330 
 331         /*
 332          * Get next batch of stack frames.
 333          */
 334         private int getNextBatch() {
 335             int nextBatchSize = Math.min(maxDepth - depth, getNextBatchSize());
 336 
 337             if (!frameBuffer.isActive() || nextBatchSize <= 0 || (frameBuffer.isAtBottom() && !hasMoreContinuations())) {
 338                 if (isDebug) {
 339                     System.out.format("  more stack walk done%n");
 340                 }
 341                 frameBuffer.freeze();   // stack walk done
 342                 return 0;
 343             }
 344 
 345             if (frameBuffer.isAtBottom() && hasMoreContinuations()) {
 346                 setContinuation(continuation.getParent());
 347             }
 348 
 349             int numFrames = fetchStackFrames(nextBatchSize);
 350             if (numFrames == 0 && !hasMoreContinuations()) {
 351                 frameBuffer.freeze(); // done stack walking
 352             }
 353             return numFrames;
 354         }
 355 
 356         private boolean hasMoreContinuations() {
 357             return continuation != null && continuation.getScope() != contScope && continuation.getParent() != null;
 358         }
 359 
 360         private void setContinuation(Continuation cont) {
 361             this.continuation = cont;
 362             setContinuation(anchor, frameBuffer.frames(), cont);
 363         }
 364 
 365         /*
 366          * This method traverses the next stack frame and returns the Class
 367          * invoking that stack frame.
 368          *
 369          * This method can only be called during the walk method.  This is intended
 370          * to be used to walk the stack frames in one single invocation and
 371          * this stack stream will be invalidated once walk is done.
 372          *
 373          * @see #tryNextFrame
 374          */
 375         final Class<?> nextFrame() {
 376             if (!hasNext()) {
 377                 return null;
 378             }
 379 
 380             Class<?> c = frameBuffer.next();
 381             depth++;
 382             return c;

 390         final boolean hasNext() {
 391             return peekFrame() != null;
 392         }
 393 
 394         /**
 395          * Begin stack walking - pass the allocated arrays to the VM to fill in
 396          * stack frame information.
 397          *
 398          * VM first anchors the frame of the current thread.  A traversable stream
 399          * on this thread's stack will be opened.  The VM will fetch the first batch
 400          * of stack frames and call AbstractStackWalker::doStackWalk to invoke the
 401          * stack walking function on each stack frame.
 402          *
 403          * If all fetched stack frames are traversed, AbstractStackWalker::fetchStackFrames will
 404          * fetch the next batch of stack frames to continue.
 405          */
 406         private R beginStackWalk() {
 407             // initialize buffers for VM to fill the stack frame info
 408             initFrameBuffer();
 409 
 410             return callStackWalk(mode, 0, 
 411                                  contScope, continuation,
 412                                  frameBuffer.curBatchFrameCount(),
 413                                  frameBuffer.startIndex(),
 414                                  frameBuffer.frames());
 415         }
 416 
 417         /*
 418          * Fetches stack frames.
 419          *
 420          * @params batchSize number of elements of the frame  buffers for this batch
 421          * @returns number of frames fetched in this batch
 422          */
 423         private int fetchStackFrames(int batchSize) {
 424             int startIndex = frameBuffer.startIndex();
 425             frameBuffer.resize(startIndex, batchSize);
 426 
 427             int endIndex = fetchStackFrames(mode, anchor, batchSize,
 428                                             startIndex,
 429                                             frameBuffer.frames());
 430             if (isDebug) {
 431                 System.out.format("  more stack walk requesting %d got %d to %d frames%n",
 432                                   batchSize, frameBuffer.startIndex(), endIndex);
 433             }
 434 
 435             int numFrames = endIndex - startIndex;
 436 
 437             if (numFrames > 0) {

 438                 frameBuffer.setBatch(depth, startIndex, endIndex);
 439             }
 440             return numFrames;
 441         }
 442 
 443         /**
 444          * Begins stack walking.  This method anchors this frame and invokes
 445          * AbstractStackWalker::doStackWalk after fetching the first batch of stack frames.
 446          *
 447          * @param mode        mode of stack walking
 448          * @param skipframes  number of frames to be skipped before filling the frame buffer.
 449          * @param contScope   the continuation scope to walk.
 450          * @param continuation the continuation to walk, or {@code null} if walking a thread.
 451          * @param batchSize   the batch size, max. number of elements to be filled in the frame buffers.
 452          * @param startIndex  start index of the frame buffers to be filled.
 453          * @param frames      Either a Class<?> array, if mode is {@link #FILL_CLASS_REFS_ONLY}
 454          *                    or a {@link StackFrameInfo} (or derivative) array otherwise.
 455          * @return            Result of AbstractStackWalker::doStackWalk
 456          */
 457         private native R callStackWalk(long mode, int skipframes, 
 458                                        ContinuationScope contScope, Continuation continuation,
 459                                        int batchSize, int startIndex,
 460                                        T[] frames);
 461 
 462         /**
 463          * Fetch the next batch of stack frames.
 464          *
 465          * @param mode        mode of stack walking
 466          * @param anchor
 467          * @param batchSize   the batch size, max. number of elements to be filled in the frame buffers.
 468          * @param startIndex  start index of the frame buffers to be filled.
 469          * @param frames      Either a Class<?> array, if mode is {@link #FILL_CLASS_REFS_ONLY}
 470          *                    or a {@link StackFrameInfo} (or derivative) array otherwise.
 471          *
 472          * @return the end index to the frame buffers
 473          */
 474         private native int fetchStackFrames(long mode, long anchor,
 475                                             int batchSize, int startIndex,
 476                                             T[] frames);
 477 
 478         private native void setContinuation(long anchor, T[] frames, Continuation cont);
 479     }
 480 
 481     /*
 482      * This StackFrameTraverser supports {@link Stream} traversal.
 483      *
 484      * This class implements Spliterator::forEachRemaining and Spliterator::tryAdvance.
 485      */
 486     static class StackFrameTraverser<T> extends AbstractStackWalker<T, StackFrameInfo>
 487             implements Spliterator<StackFrame>
 488     {
 489         static {
 490             stackWalkImplClasses.add(StackFrameTraverser.class);
 491         }
 492         private static final int CHARACTERISTICS = Spliterator.ORDERED | Spliterator.IMMUTABLE;
 493 
 494         final class StackFrameBuffer extends FrameBuffer<StackFrameInfo> {
 495             private StackFrameInfo[] stackFrames;
 496             StackFrameBuffer(int initialBatchSize) {
 497                 super(initialBatchSize);
 498 

 526                     stackFrames[i] = new StackFrameInfo(walker);
 527                 }
 528                 currentBatchSize = size;
 529             }
 530 
 531             @Override
 532             StackFrameInfo nextStackFrame() {
 533                 if (isEmpty()) {
 534                     throw new NoSuchElementException("origin=" + origin + " fence=" + fence);
 535                 }
 536 
 537                 StackFrameInfo frame = stackFrames[origin];
 538                 origin++;
 539                 return frame;
 540             }
 541 
 542             @Override
 543             final Class<?> at(int index) {
 544                 return stackFrames[index].declaringClass();
 545             }
 546 
 547             @Override
 548             final boolean filter(int index) {
 549                 return stackFrames[index].declaringClass() == Continuation.class && "yield0".equals(stackFrames[index].getMethodName());
 550             }
 551         }
 552 
 553         final Function<? super Stream<StackFrame>, ? extends T> function;  // callback
 554 
 555         StackFrameTraverser(StackWalker walker,
 556                             Function<? super Stream<StackFrame>, ? extends T> function) {
 557             this(walker, function, DEFAULT_MODE);
 558         }
 559         StackFrameTraverser(StackWalker walker,
 560                             Function<? super Stream<StackFrame>, ? extends T> function,
 561                             int mode) {
 562             super(walker, mode);
 563             this.function = function;
 564         }
 565 
 566         /**
 567          * Returns next StackFrame object in the current batch of stack frames;
 568          * or null if no more stack frame.
 569          */
 570         StackFrame nextStackFrame() {

 667 
 668         private Class<?> caller;
 669 
 670         CallerClassFinder(StackWalker walker) {
 671             super(walker, FILL_CLASS_REFS_ONLY|GET_CALLER_CLASS);
 672         }
 673 
 674         static final class ClassBuffer extends FrameBuffer<Class<?>> {
 675             Class<?>[] classes;      // caller class for fast path
 676             ClassBuffer(int batchSize) {
 677                 super(batchSize);
 678                 classes = new Class<?>[batchSize];
 679             }
 680 
 681             @Override
 682             Class<?>[] frames() { return classes;}
 683 
 684             @Override
 685             final Class<?> at(int index) { return classes[index];}
 686 
 687             @Override
 688             final boolean filter(int index) { return false; }
 689 
 690 
 691             // ------ subclass may override the following methods -------
 692             /**
 693              * Resizes the buffers for VM to fill in the next batch of stack frames.
 694              * The next batch will start at the given startIndex with the maximum number
 695              * of elements.
 696              *
 697              * <p> Subclass may override this method to manage the allocated buffers.
 698              *
 699              * @param startIndex the start index for the first frame of the next batch to fill in.
 700              * @param elements the number of elements for the next batch to fill in.
 701              *
 702              */
 703             @Override
 704             void resize(int startIndex, int elements) {
 705                 if (!isActive())
 706                     throw new IllegalStateException("inactive frame buffer can't be resized");
 707 
 708                 assert startIndex == START_POS :
 709                        "bad start index " + startIndex + " expected " + START_POS;

 802                 }
 803 
 804                 currentBatchSize = size;
 805             }
 806 
 807             @Override
 808             LiveStackFrameInfo nextStackFrame() {
 809                 if (isEmpty()) {
 810                     throw new NoSuchElementException("origin=" + origin + " fence=" + fence);
 811                 }
 812 
 813                 LiveStackFrameInfo frame = stackFrames[origin];
 814                 origin++;
 815                 return frame;
 816             }
 817 
 818             @Override
 819             final Class<?> at(int index) {
 820                 return stackFrames[index].declaringClass();
 821             }
 822 
 823             @Override
 824             final boolean filter(int index) {
 825                 return stackFrames[index].declaringClass() == Continuation.class && "yield0".equals(stackFrames[index].getMethodName());
 826             }
 827         }
 828 
 829         LiveStackInfoTraverser(StackWalker walker,
 830                                Function<? super Stream<StackFrame>, ? extends T> function) {
 831             super(walker, function, DEFAULT_MODE);
 832         }
 833 
 834         @Override
 835         protected void initFrameBuffer() {
 836             this.frameBuffer = new LiveStackFrameBuffer(getNextBatchSize());
 837         }
 838     }
 839 
 840     /*
 841      * Frame buffer
 842      *
 843      * Each specialized AbstractStackWalker subclass may subclass the FrameBuffer.
 844      */
 845     static abstract class FrameBuffer<F> {
 846         static final int START_POS = 2;     // 0th and 1st elements are reserved

 876         /**
 877          * Resizes the buffers for VM to fill in the next batch of stack frames.
 878          * The next batch will start at the given startIndex with the maximum number
 879          * of elements.
 880          *
 881          * <p> Subclass may override this method to manage the allocated buffers.
 882          *
 883          * @param startIndex the start index for the first frame of the next batch to fill in.
 884          * @param elements the number of elements for the next batch to fill in.
 885          *
 886          */
 887         abstract void resize(int startIndex, int elements);
 888 
 889         /**
 890          * Return the class at the given position in the current batch.
 891          * @param index the position of the frame.
 892          * @return the class at the given position in the current batch.
 893          */
 894         abstract Class<?> at(int index);
 895 
 896         /**
 897          * Filter out frames at the top of a batch
 898          * @param index the position of the frame.
 899          * @return true if the frame should be skipped
 900          */
 901         abstract boolean filter(int index);
 902 
 903         // ------ subclass may override the following methods -------
 904 
 905         /*
 906          * Returns the start index for this frame buffer is refilled.
 907          *
 908          * This implementation reuses the allocated buffer for the next batch
 909          * of stack frames.  For subclass to retain the fetched stack frames,
 910          * it should override this method to return the index at which the frame
 911          * should be filled in for the next batch.
 912          */
 913         int startIndex() {
 914             return START_POS;
 915         }
 916 
 917         /**
 918          * Returns next StackFrame object in the current batch of stack frames
 919          */
 920         F nextStackFrame() {
 921             throw new InternalError("should not reach here");
 922         }

 930         /*
 931          * Tests if this frame buffer is empty.  All frames are fetched.
 932          */
 933         final boolean isEmpty() {
 934             return origin >= fence || (origin == START_POS && fence == 0);
 935         }
 936 
 937         /*
 938          * Freezes this frame buffer.  The stack stream source is done fetching.
 939          */
 940         final void freeze() {
 941             origin = 0;
 942             fence = 0;
 943         }
 944 
 945         /*
 946          * Tests if this frame buffer is active.  It is inactive when
 947          * it is done for traversal.  All stack frames have been traversed.
 948          */
 949         final boolean isActive() {
 950             return origin > 0; //  && (fence == 0 || origin < fence || fence == currentBatchSize);
 951         }
 952 
 953         /*
 954          * Tests if this frame buffer is at the end of the stack
 955          * and all frames have been traversed.
 956          */
 957         final boolean isAtBottom() {
 958             return origin > 0 && origin >= fence && fence < currentBatchSize;
 959         }
 960 
 961         /**
 962          * Gets the class at the current frame and move to the next frame.
 963          */
 964         final Class<?> next() {
 965             if (isEmpty()) {
 966                 throw new NoSuchElementException("origin=" + origin + " fence=" + fence);
 967             }
 968             Class<?> c = at(origin);
 969             origin++;
 970             if (isDebug) {
 971                 int index = origin-1;
 972                 System.out.format("  next frame at %d: %s (origin %d fence %d)%n", index,
 973                         Objects.toString(c), index, fence);
 974             }
 975             return c;
 976         }
 977 
 978         /**

 986         }
 987 
 988         /*
 989          * Returns the index of the current frame.
 990          */
 991         final int getIndex() {
 992             return origin;
 993         }
 994 
 995         /*
 996          * Set the start and end index of a new batch of stack frames that have
 997          * been filled in this frame buffer.
 998          */
 999         final void setBatch(int depth, int startIndex, int endIndex) {
1000             if (startIndex <= 0 || endIndex <= 0)
1001                 throw new IllegalArgumentException("startIndex=" + startIndex
1002                         + " endIndex=" + endIndex);
1003 
1004             this.origin = startIndex;
1005             this.fence = endIndex;
1006             for (int i = START_POS; i < fence; i++) {
1007                 if (isDebug) System.err.format("  frame %d: %s%n", i, at(i));
1008                 if ((depth == 0 && filterStackWalkImpl(at(i))) // filter the frames due to the stack stream implementation
1009                         || filter(i)) {
1010                     origin++;
1011                 } else {
1012                     break;



1013                 }
1014             }
1015         }
1016 
1017         /*
1018          * Checks if the origin is the expected start index.
1019          */
1020         final void check(int skipFrames) {
1021             int index = skipFrames + START_POS;
1022             if (origin != index) {
1023                 // stack walk must continue with the previous frame depth
1024                 throw new IllegalStateException("origin " + origin + " != " + index);
1025             }
1026         }
1027     }
1028 
1029     private static native boolean checkStackWalkModes();
1030 
1031     // avoid loading other subclasses as they may not be used
1032     private static Set<Class<?>> init() {
< prev index next >