< 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  *


  66     private final static 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     final static 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 stablize 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 


 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         /**




  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 sun.security.action.GetPropertyAction;
  47 
  48 import static java.lang.StackStreamFactory.WalkerState.*;
  49 
  50 /**
  51  * StackStreamFactory class provides static factory methods
  52  * to get different kinds of stack walker/traverser.
  53  *
  54  * AbstractStackWalker provides the basic stack walking support
  55  * fetching stack frames from VM in batches.
  56  *


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


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


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


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


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

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


 902         /*
 903          * Tests if this frame buffer is empty.  All frames are fetched.
 904          */
 905         final boolean isEmpty() {
 906             return origin >= fence || (origin == START_POS && fence == 0);
 907         }
 908 
 909         /*
 910          * Freezes this frame buffer.  The stack stream source is done fetching.
 911          */
 912         final void freeze() {
 913             origin = 0;
 914             fence = 0;
 915         }
 916 
 917         /*
 918          * Tests if this frame buffer is active.  It is inactive when
 919          * it is done for traversal.  All stack frames have been traversed.
 920          */
 921         final boolean isActive() {
 922             return origin > 0; //  && (fence == 0 || origin < fence || fence == currentBatchSize);
 923         }
 924 
 925         /*
 926          * Tests if this frame buffer is at the end of the stack
 927          * and all frames have been traversed.
 928          */
 929         final boolean isAtBottom() {
 930             return origin > 0 && origin >= fence && fence < currentBatchSize;
 931         }
 932 
 933         /**
 934          * Gets the class at the current frame and move to the next frame.
 935          */
 936         final Class<?> next() {
 937             if (isEmpty()) {
 938                 throw new NoSuchElementException("origin=" + origin + " fence=" + fence);
 939             }
 940             Class<?> c = at(origin);
 941             origin++;
 942             if (isDebug) {
 943                 int index = origin-1;
 944                 System.out.format("  next frame at %d: %s (origin %d fence %d)%n", index,
 945                         Objects.toString(c), index, fence);
 946             }
 947             return c;
 948         }
 949 
 950         /**


< prev index next >