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 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.util.HashSet;
  34 import java.util.NoSuchElementException;
  35 import java.util.Objects;
  36 import java.util.Set;
  37 import java.util.Spliterator;
  38 import java.util.function.Consumer;
  39 import java.util.function.Function;
  40 import java.util.stream.Stream;
  41 import java.util.stream.StreamSupport;
  42 import sun.security.action.GetPropertyAction;
  43 
  44 import static java.lang.StackStreamFactory.WalkerState.*;
  45 
  46 /**
  47  * StackStreamFactory class provides static factory methods
  48  * to get different kinds of stack walker/traverser.
  49  *
  50  * AbstractStackWalker provides the basic stack walking support
  51  * fetching stack frames from VM in batches.
  52  *
  53  * AbstractStackWalker subclass is specialized for a specific kind of stack traversal
  54  * to avoid overhead of Stream/Lambda
  55  * 1. Support traversing Stream<StackFrame>
  56  * 2. StackWalker::getCallerClass
  57  * 3. AccessControlContext getting ProtectionDomain
  58  */
  59 final class StackStreamFactory {
  60     private StackStreamFactory() {}
  61 
  62     // Stack walk implementation classes to be excluded during stack walking
  63     // lazily add subclasses when they are loaded.
  64     private final static Set<Class<?>> stackWalkImplClasses = init();
  65 
  66     private static final int SMALL_BATCH       = 8;
  67     private static final int BATCH_SIZE        = 32;
  68     private static final int LARGE_BATCH_SIZE  = 256;
  69     private static final int MIN_BATCH_SIZE    = SMALL_BATCH;
  70 
  71     // These flags must match the values maintained in the VM
  72     @Native private static final int DEFAULT_MODE              = 0x0;
  73     @Native private static final int FILL_CLASS_REFS_ONLY      = 0x2;
  74     @Native private static final int SHOW_HIDDEN_FRAMES        = 0x20;  // LambdaForms are hidden by the VM
  75     @Native private static final int FILL_LIVE_STACK_FRAMES    = 0x100;
  76     /*
  77      * For Throwable to use StackWalker, set useNewThrowable to true.
  78      * Performance work and extensive testing is needed to replace the
  79      * VM built-in backtrace filled in Throwable with the StackWalker.
  80      */
  81     final static boolean isDebug =
  82             "true".equals(GetPropertyAction.privilegedGetProperty("stackwalk.debug"));
  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                 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             throw new InternalError("Not jdk.internal.reflect.MethodAccessor: " + c.toString());
 986         }
 987         // ## should filter all @Hidden frames?
 988         return c == Method.class ||
 989                 MethodAccessor.class.isAssignableFrom(c) ||
 990                 c.getName().startsWith("java.lang.invoke.LambdaForm");
 991     }
 992 
 993 }