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