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