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