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