1 /*
   2  * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  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 sun.misc.VM;
  28 
  29 import java.io.PrintStream;
  30 import java.lang.StackWalker.Option;
  31 import java.lang.StackWalker.StackFrame;
  32 
  33 import java.lang.reflect.Method;
  34 import java.security.AccessController;
  35 import java.security.PrivilegedAction;
  36 import java.util.Arrays;
  37 import java.util.EnumSet;
  38 import java.util.HashSet;
  39 import java.util.NoSuchElementException;
  40 import java.util.Objects;
  41 import java.util.Optional;
  42 import java.util.Set;
  43 import java.util.Spliterator;
  44 import java.util.function.Consumer;
  45 import java.util.function.Function;
  46 import java.util.stream.Stream;
  47 import java.util.stream.StreamSupport;
  48 
  49 import static java.lang.StackStreamFactory.WalkerState.*;
  50 
  51 /**
  52  * StackStreamFactory class provides static factory methods
  53  * to get different kinds of stack walker/traverser.
  54  *
  55  * AbstractStackWalker provides the basic stack walking support
  56  * fetching stack frames from VM in batches.
  57  *
  58  * AbstractStackWalker subclass is specialized for a specific kind of stack traversal
  59  * to avoid overhead of Stream/Lambda
  60  * 1. Support traversing Stream<StackFrame>
  61  * 2. StackWalker::getCallerClass
  62  * 3. Throwable::init and Throwable::getStackTrace
  63  * 4. AccessControlContext getting ProtectionDomain
  64  */
  65 final class StackStreamFactory {
  66     private StackStreamFactory() {}
  67 
  68     // Stack walk implementation classes to be excluded during stack walking
  69     // lazily add subclasses when they are loaded.
  70     private final static 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     private static final int DEFAULT_MODE              = 0x0;
  79     private static final int FILL_CLASS_REFS_ONLY      = 0x2;
  80     private static final int FILTER_FILL_IN_STACKTRACE = 0x10;
  81     private static final int SHOW_HIDDEN_FRAMES        = 0x20;  // LambdaForms are hidden by the VM
  82     private static final int FILL_LOCALS_OPERANDS      = 0x100;
  83 
  84     /*
  85      * For Throwable to use StackWalker, set useNewThrowable to true.
  86      * Performance work and extensive testing is needed to replace the
  87      * VM built-in backtrace filled in Throwable with the StackWalker.
  88      */
  89     final static boolean useNewThrowable = getProperty("stackwalk.newThrowable", false);
  90     final static boolean isDebug = getProperty("stackwalk.debug", false);
  91 
  92     static <T> StackFrameTraverser<T>
  93         makeStackTraverser(StackWalker walker, Function<? super Stream<StackFrame>, ? extends T> function)
  94     {
  95         if (walker.hasLocalsOperandsOption())
  96             return new LiveStackInfoTraverser<T>(walker, function);
  97         else
  98             return new StackFrameTraverser<T>(walker, function);
  99 
 100     }
 101 
 102     /**
 103      * Gets a stack stream to find caller class.
 104      */
 105     static CallerClassFinder makeCallerFinder(StackWalker walker) {
 106         return new CallerClassFinder(walker);
 107     }
 108 
 109     static boolean useStackTrace(Throwable t) {
 110         if (t instanceof VirtualMachineError)
 111             return false;
 112 
 113         return VM.isBooted() && StackStreamFactory.useNewThrowable;
 114     }
 115 
 116     /*
 117      * This should only be used by Throwable::<init>.
 118      */
 119     static StackTrace makeStackTrace(Throwable ex) {
 120         return StackTrace.dump(ex);
 121     }
 122 
 123     /*
 124      * This creates StackTrace for Thread::dumpThread to use.
 125      */
 126     static StackTrace makeStackTrace() {
 127         return StackTrace.dump();
 128     }
 129 
 130     enum WalkerState {
 131         NEW,     // the stream is new and stack walking has not started
 132         OPEN,    // the stream is open when it is being traversed.
 133         CLOSED;  // the stream is closed when the stack walking is done
 134     }
 135 
 136     static abstract class AbstractStackWalker<T> {
 137         // VM writes to these arrays to fill the stack frame information
 138         // for each batch
 139         protected final StackWalker walker;
 140         protected final Thread thread;
 141         protected final int maxDepth;
 142         protected final long mode;
 143         protected int depth;          // traversed stack depth
 144         protected FrameBuffer frameBuffer;
 145         protected long anchor;
 146 
 147         // buffers to fill in stack frame information
 148         protected AbstractStackWalker(StackWalker walker, int mode) {
 149             this(walker, mode, Integer.MAX_VALUE);
 150         }
 151         protected AbstractStackWalker(StackWalker walker, int mode, int maxDepth) {
 152             this.thread = Thread.currentThread();
 153             this.mode = toStackWalkMode(walker, mode);
 154             this.walker = walker;
 155             this.maxDepth = maxDepth;
 156             this.depth = 0;
 157         }
 158 
 159         private int toStackWalkMode(StackWalker walker, int mode) {
 160             int newMode = mode;
 161             if (walker.hasOption(Option.SHOW_HIDDEN_FRAMES) &&
 162                     !fillCallerClassOnly(newMode) /* don't show hidden frames for getCallerClass */)
 163                 newMode |= SHOW_HIDDEN_FRAMES;
 164             if (walker.hasLocalsOperandsOption())
 165                 newMode |= FILL_LOCALS_OPERANDS;
 166             return newMode;
 167         }
 168 
 169         private boolean fillCallerClassOnly(int mode) {
 170             return (mode|FILL_CLASS_REFS_ONLY) != FILL_CLASS_REFS_ONLY;
 171         }
 172         /**
 173          * A callback method to consume the stack frames.  This method is invoked
 174          * once stack walking begins (i.e. it is only invoked when walkFrames is called).
 175          *
 176          * Each specialized AbstractStackWalker subclass implements the consumeFrames method
 177          * to control the following:
 178          * 1. fetch the subsequent batches of stack frames
 179          * 2. reuse or expand the allocated buffers
 180          * 3. create specialized StackFrame objects
 181          *
 182          * @return the number of consumed frames
 183          */
 184          protected abstract T consumeFrames();
 185 
 186         /**
 187          * Initialize FrameBuffer.  Subclass should implement this method to
 188          * create its custom frame buffers.
 189          */
 190          protected abstract void initFrameBuffer();
 191 
 192         /**
 193          * Returns the suggested next batch size.
 194          *
 195          * Subclass should override this method to change the batch size
 196          * or invoke the function passed to the StackWalker::walk method
 197          *
 198          * @param lastBatchFrameCount number of frames in the last batch; or zero
 199          * @return suggested batch size
 200          */
 201         protected abstract int batchSize(int lastBatchFrameCount);
 202 
 203         /*
 204          * Returns the next batch size, always >= minimum batch size (32)
 205          *
 206          * Subclass may override this method if the minimum batch size is different.
 207          */
 208         protected int getNextBatchSize() {
 209             int lastBatchSize = depth == 0 ? 0 : frameBuffer.curBatchFrameCount();
 210             int nextBatchSize = batchSize(lastBatchSize);
 211             if (isDebug) {
 212                 System.err.println("last batch size = " + lastBatchSize +
 213                                    " next batch size = " + nextBatchSize);
 214             }
 215             return nextBatchSize >= MIN_BATCH_SIZE ? nextBatchSize : MIN_BATCH_SIZE;
 216         }
 217 
 218         /*
 219          * Checks if this stream is in the given state. Otherwise, throws IllegalStateException.
 220          *
 221          * VM also validates this stream if it's anchored for stack walking
 222          * when stack frames are fetched for each batch.
 223          */
 224         final void checkState(WalkerState state) {
 225             if (thread != Thread.currentThread()) {
 226                 throw new IllegalStateException("Invalid thread walking this stack stream: " +
 227                         Thread.currentThread().getName() + " " + thread.getName());
 228             }
 229             switch (state) {
 230                 case NEW:
 231                     if (this.anchor != 0) {
 232                         throw new IllegalStateException("This stack stream is being reused.");
 233                     }
 234                     break;
 235                 case OPEN:
 236                     if (this.anchor <= 0) {
 237                         throw new IllegalStateException("This stack stream is not valid for walking");
 238                     }
 239                     break;
 240                 case CLOSED:
 241                     if (this.anchor != -1L) {
 242                         throw new IllegalStateException("This stack stream is not closed.");
 243                     }
 244             }
 245         }
 246 
 247         /*
 248          * Close this stream.  This stream becomes invalid to walk.
 249          */
 250         private void close() {
 251             this.anchor = -1L;
 252         }
 253 
 254         /*
 255          * Walks stack frames until {@link #consumeFrames} is done consuming
 256          * the frames it is interested in.
 257          */
 258         final T walk() {
 259             checkState(NEW);
 260             try {
 261                 // VM will need to stablize the stack before walking.  It will invoke
 262                 // the AbstractStackWalker::doStackWalk method once it fetches the first batch.
 263                 // the callback will be invoked within the scope of the callStackWalk frame.
 264                 return beginStackWalk();
 265             } finally {
 266                 close();  // done traversal; close the stream
 267             }
 268         }
 269 
 270         private boolean skipReflectionFrames() {
 271             return !walker.hasOption(Option.SHOW_REFLECT_FRAMES) &&
 272                        !walker.hasOption(Option.SHOW_HIDDEN_FRAMES);
 273         }
 274 
 275         /*
 276          * Returns {@code Class} object at the current frame;
 277          * or {@code null} if no more frame. If advanceToNextBatch is true,
 278          * it will only fetch the next batch.
 279          */
 280         final Class<?> peekFrame() {
 281             while (frameBuffer.isActive() && depth < maxDepth) {
 282                 if (frameBuffer.isEmpty()) {
 283                     // fetch another batch of stack frames
 284                     getNextBatch();
 285                 } else {
 286                     Class<?> c = frameBuffer.get();
 287                     if (skipReflectionFrames() && isReflectionFrame(c)) {
 288                         if (isDebug)
 289                             System.err.println("  skip: frame " + frameBuffer.getIndex() + " " + c);
 290 
 291                         frameBuffer.next();
 292                         depth++;
 293                         continue;
 294                     } else {
 295                         return c;
 296                     }
 297                 }
 298             }
 299             return null;
 300         }
 301 
 302         /*
 303          * This method is only invoked by VM.
 304          *
 305          * It will invoke the consumeFrames method to start the stack walking
 306          * with the first batch of stack frames.  Each specialized AbstractStackWalker
 307          * subclass implements the consumeFrames method to control the following:
 308          * 1. fetch the subsequent batches of stack frames
 309          * 2. reuse or expand the allocated buffers
 310          * 3. create specialized StackFrame objects
 311          */
 312         private Object doStackWalk(long anchor, int skipFrames, int batchSize,
 313                                                 int bufStartIndex, int bufEndIndex) {
 314             checkState(NEW);
 315 
 316             frameBuffer.check(skipFrames);
 317 
 318             if (isDebug) {
 319                 System.err.format("doStackWalk: skip %d start %d end %d%n",
 320                         skipFrames, bufStartIndex, bufEndIndex);
 321             }
 322 
 323             this.anchor = anchor;  // set anchor for this bulk stack frame traversal
 324             frameBuffer.setBatch(bufStartIndex, bufEndIndex);
 325 
 326             // traverse all frames and perform the action on the stack frames, if specified
 327             return consumeFrames();
 328         }
 329 
 330         /*
 331          * Get next batch of stack frames.
 332          */
 333         private int getNextBatch() {
 334             int nextBatchSize = Math.min(maxDepth - depth, getNextBatchSize());
 335             if (!frameBuffer.isActive() || nextBatchSize <= 0) {
 336                 if (isDebug) {
 337                     System.out.format("  more stack walk done%n");
 338                 }
 339                 frameBuffer.freeze();   // stack walk done
 340                 return 0;
 341             }
 342 
 343             return fetchStackFrames(nextBatchSize);
 344         }
 345 
 346         /*
 347          * This method traverses the next stack frame and returns the Class
 348          * invoking that stack frame.
 349          *
 350          * This method can only be called during the walk method.  This is intended
 351          * to be used to walk the stack frames in one single invocation and
 352          * this stack stream will be invalidated once walk is done.
 353          *
 354          * @see #tryNextFrame
 355          */
 356         final Class<?> nextFrame() {
 357             if (!hasNext()) {
 358                 return null;
 359             }
 360 
 361             Class<?> c = frameBuffer.next();
 362             depth++;
 363             return c;
 364         }
 365 
 366         /*
 367          * Returns true if there is next frame to be traversed.
 368          * This skips hidden frames unless this StackWalker has
 369          * {@link Option#SHOW_REFLECT_FRAMES}
 370          */
 371         final boolean hasNext() {
 372             return peekFrame() != null;
 373         }
 374 
 375         /**
 376          * Begin stack walking - pass the allocated arrays to the VM to fill in
 377          * stack frame information.
 378          *
 379          * VM first anchors the frame of the current thread.  A traversable stream
 380          * on this thread's stack will be opened.  The VM will fetch the first batch
 381          * of stack frames and call AbstractStackWalker::doStackWalk to invoke the
 382          * stack walking function on each stack frame.
 383          *
 384          * If all fetched stack frames are traversed, AbstractStackWalker::fetchStackFrames will
 385          * fetch the next batch of stack frames to continue.
 386          */
 387         private T beginStackWalk() {
 388             // initialize buffers for VM to fill the stack frame info
 389             initFrameBuffer();
 390 
 391             return callStackWalk(mode, 0,
 392                                  frameBuffer.curBatchFrameCount(),
 393                                  frameBuffer.startIndex(),
 394                                  frameBuffer.classes,
 395                                  frameBuffer.stackFrames);
 396         }
 397 
 398         /*
 399          * Fetches stack frames.
 400          *
 401          * @params batchSize number of elements of the frame  buffers for this batch
 402          * @returns number of frames fetched in this batch
 403          */
 404         private int fetchStackFrames(int batchSize) {
 405             int startIndex = frameBuffer.startIndex();
 406             frameBuffer.resize(startIndex, batchSize);
 407 
 408             int endIndex = fetchStackFrames(mode, anchor, batchSize,
 409                                             startIndex,
 410                                             frameBuffer.classes,
 411                                             frameBuffer.stackFrames);
 412             if (isDebug) {
 413                 System.out.format("  more stack walk requesting %d got %d to %d frames%n",
 414                                   batchSize, frameBuffer.startIndex(), endIndex);
 415             }
 416             int numFrames = endIndex - startIndex;
 417             if (numFrames == 0) {
 418                 frameBuffer.freeze(); // done stack walking
 419             } else {
 420                 frameBuffer.setBatch(startIndex, endIndex);
 421             }
 422             return numFrames;
 423         }
 424 
 425         /**
 426          * Begins stack walking.  This method anchors this frame and invokes
 427          * AbstractStackWalker::doStackWalk after fetching the firt batch of stack frames.
 428          *
 429          * @param mode        mode of stack walking
 430          * @param skipframes  number of frames to be skipped before filling the frame buffer.
 431          * @param batchSize   the batch size, max. number of elements to be filled in the frame buffers.
 432          * @param startIndex  start index of the frame buffers to be filled.
 433          * @param classes     Classes buffer of the stack frames
 434          * @param frames      StackFrame buffer, or null
 435          * @return            Result of AbstractStackWalker::doStackWalk
 436          */
 437         private native T callStackWalk(long mode, int skipframes,
 438                                        int batchSize, int startIndex,
 439                                        Class<?>[] classes,
 440                                        StackFrame[] frames);
 441 
 442         /**
 443          * Fetch the next batch of stack frames.
 444          *
 445          * @param mode        mode of stack walking
 446          * @param anchor
 447          * @param batchSize   the batch size, max. number of elements to be filled in the frame buffers.
 448          * @param startIndex  start index of the frame buffers to be filled.
 449          * @param classes     Classes buffer of the stack frames
 450          * @param frames      StackFrame buffer, or null
 451          *
 452          * @return the end index to the frame buffers
 453          */
 454         private native int fetchStackFrames(long mode, long anchor,
 455                                             int batchSize, int startIndex,
 456                                             Class<?>[] classes,
 457                                             StackFrame[] frames);
 458 
 459 
 460         /*
 461          * Frame buffer
 462          *
 463          * Each specialized AbstractStackWalker subclass may subclass the FrameBuffer.
 464          */
 465         class FrameBuffer {
 466             static final int START_POS = 2;     // 0th and 1st elements are reserved
 467 
 468             // buffers for VM to fill stack frame info
 469             int currentBatchSize;    // current batch size
 470             Class<?>[] classes;      // caller class for fast path
 471 
 472             StackFrame[] stackFrames;
 473 
 474             int origin;         // index to the current traversed stack frame
 475             int fence;          // index to the last frame in the current batch
 476 
 477             FrameBuffer(int initialBatchSize) {
 478                 if (initialBatchSize < MIN_BATCH_SIZE) {
 479                     throw new IllegalArgumentException(initialBatchSize + " < minimum batch size: " + MIN_BATCH_SIZE);
 480                 }
 481                 this.origin = START_POS;
 482                 this.fence = 0;
 483                 this.currentBatchSize = initialBatchSize;
 484                 this.classes = new Class<?>[currentBatchSize];
 485             }
 486 
 487             int curBatchFrameCount() {
 488                 return currentBatchSize-START_POS;
 489             }
 490 
 491             /*
 492              * Tests if this frame buffer is empty.  All frames are fetched.
 493              */
 494             final boolean isEmpty() {
 495                 return origin >= fence || (origin == START_POS && fence == 0);
 496             }
 497 
 498             /*
 499              * Freezes this frame buffer.  The stack stream source is done fetching.
 500              */
 501             final void freeze() {
 502                 origin = 0;
 503                 fence = 0;
 504             }
 505 
 506             /*
 507              * Tests if this frame buffer is active.  It is inactive when
 508              * it is done for traversal.  All stack frames have been traversed.
 509              */
 510             final boolean isActive() {
 511                 return origin > 0 && (fence == 0 || origin < fence || fence == currentBatchSize);
 512             }
 513 
 514             /**
 515              * Gets the class at the current frame and move to the next frame.
 516              */
 517             final Class<?> next() {
 518                 if (isEmpty()) {
 519                     throw new NoSuchElementException("origin=" + origin + " fence=" + fence);
 520                 }
 521                 Class<?> c = classes[origin++];
 522                 if (isDebug) {
 523                     int index = origin-1;
 524                     System.out.format("  next frame at %d: %s (origin %d fence %d)%n", index,
 525                                       Objects.toString(c), index, fence);
 526                 }
 527                 return c;
 528             }
 529 
 530             /**
 531              * Gets the class at the current frame.
 532              */
 533             final Class<?> get() {
 534                 if (isEmpty()) {
 535                     throw new NoSuchElementException("origin=" + origin + " fence=" + fence);
 536                 }
 537                 return classes[origin];
 538             }
 539 
 540             /*
 541              * Returns the index of the current frame.
 542              */
 543             final int getIndex() {
 544                 return origin;
 545             }
 546 
 547             /*
 548              * Set the start and end index of a new batch of stack frames that have
 549              * been filled in this frame buffer.
 550              */
 551             final void setBatch(int startIndex, int endIndex) {
 552                 if (startIndex <= 0 || endIndex <= 0)
 553                     throw new IllegalArgumentException("startIndex=" + startIndex + " endIndex=" + endIndex);
 554 
 555                 this.origin = startIndex;
 556                 this.fence = endIndex;
 557                 if (depth == 0 && fence > 0) {
 558                     // filter the frames due to the stack stream implementation
 559                     for (int i = START_POS; i < fence; i++) {
 560                         Class<?> c = classes[i];
 561                         if (isDebug) System.err.format("  frame %d: %s%n", i, c);
 562                         if (filterStackWalkImpl(c)) {
 563                             origin++;
 564                         } else {
 565                             break;
 566                         }
 567                     }
 568                 }
 569             }
 570 
 571             /*
 572              * Checks if the origin is the expected start index.
 573              */
 574             final void check(int skipFrames) {
 575                 int index = skipFrames + START_POS;
 576                 if (origin != index) {
 577                     // stack walk must continue with the previous frame depth
 578                     throw new IllegalStateException("origin " + origin + " != " + index);
 579                 }
 580             }
 581 
 582             // ------ subclass may override the following methods -------
 583             /**
 584              * Resizes the buffers for VM to fill in the next batch of stack frames.
 585              * The next batch will start at the given startIndex with the maximum number
 586              * of elements.
 587              *
 588              * <p> Subclass may override this method to manage the allocated buffers.
 589              *
 590              * @param startIndex the start index for the first frame of the next batch to fill in.
 591              * @param elements the number of elements for the next batch to fill in.
 592              *
 593              */
 594             void resize(int startIndex, int elements) {
 595                 if (!isActive())
 596                     throw new IllegalStateException("inactive frame buffer can't be resized");
 597 
 598                 int size = startIndex+elements;
 599                 if (classes.length < size) {
 600                     // copy the elements in classes array to the newly allocated one.
 601                     // classes[0] is a Thread object
 602                     Class<?>[] prev = classes;
 603                     classes = new Class<?>[size];
 604                     System.arraycopy(prev, 0, classes, 0, START_POS);
 605                 }
 606                 currentBatchSize = size;
 607             }
 608 
 609             /*
 610              * Returns the start index for this frame buffer is refilled.
 611              *
 612              * This implementation reuses the allocated buffer for the next batch
 613              * of stack frames.  For subclass to retain the fetched stack frames,
 614              * it should override this method to return the index at which the frame
 615              * should be filled in for the next batch.
 616              */
 617             int startIndex() {
 618                 return START_POS;
 619             }
 620 
 621             /**
 622              * Returns next StackFrame object in the current batch of stack frames
 623              */
 624             StackFrame nextStackFrame() {
 625                 throw new InternalError("should not reach here");
 626             }
 627         }
 628     }
 629 
 630     /*
 631      * This StackFrameTraverser supports {@link Stream} traversal.
 632      *
 633      * This class implements Spliterator::forEachRemaining and Spliterator::tryAdvance.
 634      */
 635     static class StackFrameTraverser<T> extends AbstractStackWalker<T>
 636             implements Spliterator<StackFrame>
 637     {
 638         static {
 639             stackWalkImplClasses.add(StackFrameTraverser.class);
 640         }
 641         private static final int CHARACTERISTICS = Spliterator.ORDERED | Spliterator.IMMUTABLE;
 642         class Buffer extends FrameBuffer {
 643             Buffer(int initialBatchSize) {
 644                 super(initialBatchSize);
 645 
 646                 this.stackFrames = new StackFrame[initialBatchSize];
 647                 for (int i = START_POS; i < initialBatchSize; i++) {
 648                     stackFrames[i] = new StackFrameInfo(walker);
 649                 }
 650             }
 651 
 652             @Override
 653             void resize(int startIndex, int elements) {
 654                 super.resize(startIndex, elements);
 655 
 656                 int size = startIndex+elements;
 657                 if (stackFrames.length < size) {
 658                     stackFrames = new StackFrame[size];
 659                 }
 660                 for (int i = startIndex(); i < size; i++) {
 661                     stackFrames[i] = new StackFrameInfo(walker);
 662                 }
 663             }
 664 
 665             @Override
 666             StackFrame nextStackFrame() {
 667                 if (isEmpty()) {
 668                     throw new NoSuchElementException("origin=" + origin + " fence=" + fence);
 669                 }
 670 
 671                 StackFrame frame = stackFrames[origin];
 672                 origin++;
 673                 return frame;
 674             }
 675         }
 676 
 677         final Function<? super Stream<StackFrame>, ? extends T> function;  // callback
 678 
 679         StackFrameTraverser(StackWalker walker,
 680                             Function<? super Stream<StackFrame>, ? extends T> function) {
 681             this(walker, function, DEFAULT_MODE);
 682         }
 683         StackFrameTraverser(StackWalker walker,
 684                             Function<? super Stream<StackFrame>, ? extends T> function,
 685                             int mode) {
 686             super(walker, mode);
 687             this.function = function;
 688         }
 689 
 690         /**
 691          * Returns next StackFrame object in the current batch of stack frames;
 692          * or null if no more stack frame.
 693          */
 694         StackFrame nextStackFrame() {
 695             if (!hasNext()) {
 696                 return null;
 697             }
 698 
 699             StackFrame frame = frameBuffer.nextStackFrame();
 700             depth++;
 701             return frame;
 702         }
 703 
 704         @Override
 705         protected T consumeFrames() {
 706             checkState(OPEN);
 707             Stream<StackFrame> stream = StreamSupport.stream(this, false);
 708             if (function != null) {
 709                 return function.apply(stream);
 710             } else
 711                 throw new UnsupportedOperationException();
 712         }
 713 
 714         @Override
 715         protected void initFrameBuffer() {
 716             this.frameBuffer = new Buffer(getNextBatchSize());
 717         }
 718 
 719         @Override
 720         protected int batchSize(int lastBatchFrameCount) {
 721             if (lastBatchFrameCount == 0) {
 722                 // First batch, use estimateDepth if not exceed the large batch size
 723                 // and not too small
 724                 int initialBatchSize = Math.max(walker.estimateDepth(), SMALL_BATCH);
 725                 return Math.min(initialBatchSize, LARGE_BATCH_SIZE);
 726             } else {
 727                 if (lastBatchFrameCount > BATCH_SIZE) {
 728                     return lastBatchFrameCount;
 729                 } else {
 730                     return Math.min(lastBatchFrameCount*2, BATCH_SIZE);
 731                 }
 732             }
 733         }
 734 
 735         // ------- Implementation of Spliterator
 736 
 737         @Override
 738         public Spliterator<StackFrame> trySplit() {
 739             return null;   // ordered stream and do not allow to split
 740         }
 741 
 742         @Override
 743         public long estimateSize() {
 744             return maxDepth;
 745         }
 746 
 747         @Override
 748         public int characteristics() {
 749             return CHARACTERISTICS;
 750         }
 751 
 752         @Override
 753         public void forEachRemaining(Consumer<? super StackFrame> action) {
 754             checkState(OPEN);
 755             for (int n = 0; n < maxDepth; n++) {
 756                 StackFrame frame = nextStackFrame();
 757                 if (frame == null) break;
 758 
 759                 action.accept(frame);
 760             }
 761         }
 762 
 763         @Override
 764         public boolean tryAdvance(Consumer<? super StackFrame> action) {
 765             checkState(OPEN);
 766 
 767             int index = frameBuffer.getIndex();
 768             if (hasNext()) {
 769                 StackFrame frame = nextStackFrame();
 770                 action.accept(frame);
 771                 if (isDebug) {
 772                     System.err.println("tryAdvance: " + index + " " + frame);
 773                 }
 774                 return true;
 775             }
 776             if (isDebug) {
 777                 System.err.println("tryAdvance: " + index + " NO element");
 778             }
 779             return false;
 780         }
 781     }
 782 
 783     /*
 784      * CallerClassFinder is specialized to return Class<?> for each stack frame.
 785      * StackFrame is not requested.
 786      */
 787     static class CallerClassFinder extends AbstractStackWalker<Integer> {
 788         static {
 789             stackWalkImplClasses.add(CallerClassFinder.class);
 790         }
 791 
 792         private Class<?> caller;
 793 
 794         CallerClassFinder(StackWalker walker) {
 795             super(walker, FILL_CLASS_REFS_ONLY);
 796         }
 797 
 798         Class<?> findCaller() {
 799             walk();
 800             return caller;
 801         }
 802 
 803         @Override
 804         protected Integer consumeFrames() {
 805             checkState(OPEN);
 806             int n = 0;
 807             Class<?>[] frames = new Class<?>[2];
 808             // skip the API calling this getCallerClass method
 809             // 0: StackWalker::getCallerClass
 810             // 1: caller-sensitive method
 811             // 2: caller class, Thread::run, or no such frame
 812             while (n < 2 && (caller = nextFrame()) != null) {
 813                 if (isMethodHandleFrame(caller)) continue;
 814 
 815                 frames[n++] = caller;
 816             }
 817 
 818             // methods in Thread class doesn't call getCallerClass
 819             // it's safe to simply check Thread.class
 820             if (frames[1] == null || frames[1] == Thread.class) {
 821                 // return the entry point of the thread
 822                 caller = frames[0];
 823             }
 824             return n;
 825         }
 826 
 827         @Override
 828         protected void initFrameBuffer() {
 829             this.frameBuffer = new FrameBuffer(getNextBatchSize());
 830         }
 831 
 832         @Override
 833         protected int batchSize(int lastBatchFrameCount) {
 834             return MIN_BATCH_SIZE;
 835         }
 836 
 837         @Override
 838         protected int getNextBatchSize() {
 839             return MIN_BATCH_SIZE;
 840         }
 841     }
 842 
 843     /*
 844      * StackTrace caches all frames in the buffer.  StackTraceElements are
 845      * created lazily when Throwable::getStackTrace is called.
 846      */
 847     static class StackTrace extends AbstractStackWalker<Integer> {
 848         static {
 849             stackWalkImplClasses.add(StackTrace.class);
 850         }
 851 
 852         class GrowableBuffer extends FrameBuffer {
 853             GrowableBuffer(int initialBatchSize) {
 854                 super(initialBatchSize);
 855 
 856                 this.stackFrames = new StackFrame[initialBatchSize];
 857                 for (int i = START_POS; i < initialBatchSize; i++) {
 858                     stackFrames[i] = new StackFrameInfo(walker);
 859                 }
 860             }
 861 
 862             /*
 863              * Returns the next index to fill
 864              */
 865             @Override
 866             int startIndex() {
 867                 return origin;
 868             }
 869 
 870             /**
 871              * Initialize the buffers for VM to fill in the stack frame information.
 872              * The next batch will start at the given startIndex to
 873              * the length of the buffer.
 874              */
 875             @Override
 876             void resize(int startIndex, int elements) {
 877                 // Expand the frame buffer.
 878                 // Do not call super.resize that will reuse the filled elements
 879                 // in this frame buffer
 880                 int size = startIndex+elements;
 881                 if (classes.length < size) {
 882                     // resize the frame buffer
 883                     classes = Arrays.copyOf(classes, size);
 884                     stackFrames = Arrays.copyOf(stackFrames, size);
 885                 }
 886                 for (int i = startIndex; i < size; i++) {
 887                     stackFrames[i] = new StackFrameInfo(walker);
 888                 }
 889                 currentBatchSize = size;
 890             }
 891 
 892             StackTraceElement get(int index) {
 893                 return new StackTraceElement(classes[index].getName(), "unknown", null, -1);
 894             }
 895 
 896             /**
 897              * Returns an array of StackTraceElement for all stack frames cached in
 898              * this StackTrace object.
 899              * <p>
 900              * This method is intended for Throwable::getOurStackTrace use only.
 901              */
 902             StackTraceElement[] toStackTraceElements() {
 903                 int startIndex = START_POS;
 904                 for (int i = startIndex; i < classes.length; i++) {
 905                     if (classes[i] != null && filterStackWalkImpl(classes[i])) {
 906                         startIndex++;
 907                     } else {
 908                         break;
 909                     }
 910                 }
 911 
 912                 // VM fills in the method name, filename, line number info
 913                 StackFrameInfo.fillInStackFrames(0, stackFrames, startIndex, startIndex + depth);
 914 
 915                 StackTraceElement[] stes = new StackTraceElement[depth];
 916                 for (int i = startIndex, j = 0; i < classes.length && j < depth; i++, j++) {
 917                     if (isDebug) {
 918                         System.err.println("StackFrame: " + i + " " + stackFrames[i]);
 919                     }
 920                     stes[j] = stackFrames[i].toStackTraceElement();
 921                 }
 922                 return stes;
 923             }
 924         }
 925 
 926         private static final int MAX_STACK_FRAMES = 1024;
 927         private static final StackWalker STACKTRACE_WALKER =
 928             StackWalker.newInstanceNoCheck(EnumSet.of(Option.SHOW_REFLECT_FRAMES));
 929 
 930         private StackTraceElement[] stes;
 931         static StackTrace dump() {
 932             return new StackTrace();
 933         }
 934 
 935         static StackTrace dump(Throwable ex) {
 936             return new StackTrace(ex);
 937         }
 938 
 939         private StackTrace() {
 940             this(STACKTRACE_WALKER, DEFAULT_MODE);
 941         }
 942 
 943         /*
 944          * Throwable::fillInStackTrace and <init> of Throwable and subclasses
 945          * are filtered in the VM.
 946          */
 947         private StackTrace(Throwable ex) {
 948             this(STACKTRACE_WALKER, FILTER_FILL_IN_STACKTRACE);  // skip Throwable::init frames
 949             if (isDebug) {
 950                 System.err.println("dump stack for " + ex.getClass().getName());
 951             }
 952         }
 953 
 954         StackTrace(StackWalker walker, int mode) {
 955             super(walker, mode, MAX_STACK_FRAMES);
 956 
 957             // snapshot the stack trace
 958             walk();
 959         }
 960 
 961         @Override
 962         protected Integer consumeFrames() {
 963             // traverse all frames and perform the action on the stack frames, if specified
 964             int n = 0;
 965             while (n < maxDepth && nextFrame() != null) {
 966                 n++;
 967             }
 968             return n;
 969         }
 970 
 971         @Override
 972         protected void initFrameBuffer() {
 973             this.frameBuffer = new GrowableBuffer(getNextBatchSize());
 974         }
 975 
 976         // TODO: implement better heuristic
 977         @Override
 978         protected int batchSize(int lastBatchFrameCount) {
 979             // chunk size of VM backtrace is 32
 980             return lastBatchFrameCount == 0 ? 32 : 32;
 981         }
 982 
 983         /**
 984          * Returns an array of StackTraceElement for all stack frames cached in
 985          * this StackTrace object.
 986          * <p>
 987          * This method is intended for Throwable::getOurStackTrace use only.
 988          */
 989         synchronized StackTraceElement[] getStackTraceElements() {
 990             if (stes == null) {
 991                 stes = ((GrowableBuffer) frameBuffer).toStackTraceElements();
 992                 // release the frameBuffer memory
 993                 frameBuffer = null;
 994             }
 995             return stes;
 996         }
 997 
 998         /*
 999          * Prints stack trace to the given PrintStream.
1000          *
1001          * Further implementation could skip creating StackTraceElement objects
1002          * print directly to the PrintStream.
1003          */
1004         void printStackTrace(PrintStream s) {
1005             StackTraceElement[] stes = getStackTraceElements();
1006             synchronized (s) {
1007                 s.println("Stack trace");
1008                 for (StackTraceElement traceElement : stes)
1009                     s.println("\tat " + traceElement);
1010             }
1011         }
1012     }
1013 
1014     static class LiveStackInfoTraverser<T> extends StackFrameTraverser<T> {
1015         static {
1016             stackWalkImplClasses.add(LiveStackInfoTraverser.class);
1017         }
1018         // VM will fill in all method info and live stack info directly in StackFrameInfo
1019         class Buffer extends FrameBuffer {
1020             Buffer(int initialBatchSize) {
1021                 super(initialBatchSize);
1022                 this.stackFrames = new StackFrame[initialBatchSize];
1023                 for (int i = START_POS; i < initialBatchSize; i++) {
1024                     stackFrames[i] = new LiveStackFrameInfo(walker);
1025                 }
1026             }
1027 
1028             @Override
1029             void resize(int startIndex, int elements) {
1030                 super.resize(startIndex, elements);
1031                 int size = startIndex + elements;
1032 
1033                 if (stackFrames.length < size) {
1034                     this.stackFrames = new StackFrame[size];
1035                 }
1036 
1037                 for (int i = startIndex(); i < size; i++) {
1038                     stackFrames[i] = new LiveStackFrameInfo(walker);
1039                 }
1040             }
1041 
1042             @Override
1043             StackFrame nextStackFrame() {
1044                 if (isEmpty()) {
1045                     throw new NoSuchElementException("origin=" + origin + " fence=" + fence);
1046                 }
1047 
1048                 StackFrame frame = stackFrames[origin];
1049                 origin++;
1050                 return frame;
1051             }
1052         }
1053 
1054         LiveStackInfoTraverser(StackWalker walker,
1055                                Function<? super Stream<StackFrame>, ? extends T> function) {
1056             super(walker, function, DEFAULT_MODE);
1057         }
1058 
1059         @Override
1060         protected void initFrameBuffer() {
1061             this.frameBuffer = new Buffer(getNextBatchSize());
1062         }
1063     }
1064 
1065     // avoid loading other subclasses as they may not be used
1066     private static Set<Class<?>> init() {
1067         Set<Class<?>> classes = new HashSet<>();
1068         classes.add(StackWalker.class);
1069         classes.add(StackStreamFactory.class);
1070         classes.add(AbstractStackWalker.class);
1071         return classes;
1072     }
1073 
1074     private static boolean filterStackWalkImpl(Class<?> c) {
1075         return stackWalkImplClasses.contains(c) ||
1076                 c.getName().startsWith("java.util.stream.");
1077     }
1078 
1079     // MethodHandle frames are not hidden and CallerClassFinder has
1080     // to filter them out
1081     private static boolean isMethodHandleFrame(Class<?> c) {
1082         return c.getName().startsWith("java.lang.invoke.");
1083     }
1084 
1085     private static boolean isReflectionFrame(Class<?> c) {
1086         if (c.getName().startsWith("sun.reflect") &&
1087                 !sun.reflect.MethodAccessor.class.isAssignableFrom(c)) {
1088             throw new InternalError("Not sun.reflect.MethodAccessor: " + c.toString());
1089         }
1090         // ## should filter all @Hidden frames?
1091         return c == Method.class ||
1092                 sun.reflect.MethodAccessor.class.isAssignableFrom(c) ||
1093                 c.getName().startsWith("java.lang.invoke.LambdaForm");
1094     }
1095 
1096     private static boolean getProperty(String key, boolean value) {
1097         String s = AccessController.doPrivileged(new PrivilegedAction<>() {
1098             @Override
1099             public String run() {
1100                 return System.getProperty(key);
1101             }
1102         });
1103         if (s != null) {
1104             return Boolean.valueOf(s);
1105         }
1106         return value;
1107     }
1108 }