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