1 /*
   2  * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 package java.lang;
  26 
  27 import jdk.internal.reflect.MethodAccessor;
  28 import java.lang.StackWalker.Option;
  29 import java.lang.StackWalker.StackFrame;
  30 
  31 import java.lang.annotation.Native;
  32 import java.lang.reflect.Method;
  33 import java.util.HashSet;
  34 import java.util.NoSuchElementException;
  35 import java.util.Objects;
  36 import java.util.Set;
  37 import java.util.Spliterator;
  38 import java.util.function.Consumer;
  39 import java.util.function.Function;
  40 import java.util.stream.Stream;
  41 import java.util.stream.StreamSupport;
  42 import sun.security.action.GetPropertyAction;
  43 
  44 import static java.lang.StackStreamFactory.WalkerState.*;
  45 
  46 /**
  47  * StackStreamFactory class provides static factory methods
  48  * to get different kinds of stack walker/traverser.
  49  *
  50  * AbstractStackWalker provides the basic stack walking support
  51  * fetching stack frames from VM in batches.
  52  *
  53  * AbstractStackWalker subclass is specialized for a specific kind of stack traversal
  54  * to avoid overhead of Stream/Lambda
  55  * 1. Support traversing Stream<StackFrame>
  56  * 2. StackWalker::getCallerClass
  57  * 3. AccessControlContext getting ProtectionDomain
  58  */
  59 final class StackStreamFactory {
  60     private StackStreamFactory() {}
  61 
  62     // Stack walk implementation classes to be excluded during stack walking
  63     // lazily add subclasses when they are loaded.
  64     private final static Set<Class<?>> stackWalkImplClasses = init();
  65 
  66     private static final int SMALL_BATCH       = 8;
  67     private static final int BATCH_SIZE        = 32;
  68     private static final int LARGE_BATCH_SIZE  = 256;
  69     private static final int MIN_BATCH_SIZE    = SMALL_BATCH;
  70 
  71     // These flags must match the values maintained in the VM
  72     @Native private static final int DEFAULT_MODE              = 0x0;
  73     @Native private static final int FILL_CLASS_REFS_ONLY      = 0x2;
  74     @Native private static final int GET_CALLER_CLASS          = 0x4;
  75     @Native private static final int SHOW_HIDDEN_FRAMES        = 0x20;  // LambdaForms are hidden by the VM
  76     @Native private static final int FILL_LIVE_STACK_FRAMES    = 0x100;
  77     /*
  78      * For Throwable to use StackWalker, set useNewThrowable to true.
  79      * Performance work and extensive testing is needed to replace the
  80      * VM built-in backtrace filled in Throwable with the StackWalker.
  81      */
  82     final static boolean isDebug =
  83             "true".equals(GetPropertyAction.privilegedGetProperty("stackwalk.debug"));
  84 
  85     static <T> StackFrameTraverser<T>
  86         makeStackTraverser(StackWalker walker, Function<? super Stream<StackFrame>, ? extends T> function)
  87     {
  88         if (walker.hasLocalsOperandsOption())
  89             return new LiveStackInfoTraverser<>(walker, function);
  90         else
  91             return new StackFrameTraverser<>(walker, function);
  92     }
  93 
  94     /**
  95      * Gets a stack stream to find caller class.
  96      */
  97     static CallerClassFinder makeCallerFinder(StackWalker walker) {
  98         return new CallerClassFinder(walker);
  99     }
 100 
 101     enum WalkerState {
 102         NEW,     // the stream is new and stack walking has not started
 103         OPEN,    // the stream is open when it is being traversed.
 104         CLOSED;  // the stream is closed when the stack walking is done
 105     }
 106 
 107     /**
 108      * Subclass of AbstractStackWalker implements a specific stack walking logic.
 109      * It needs to set up the frame buffer and stack walking mode.
 110      *
 111      * It initiates the VM stack walking via the callStackWalk method that serves
 112      * as the anchored frame and VM will call up to AbstractStackWalker::doStackWalk.
 113      *
 114      * @param <R> the type of the result returned from stack walking
 115      * @param <T> the type of the data gathered for each frame.
 116      *            For example, StackFrameInfo for StackWalker::walk or
 117      *            Class<?> for StackWalker::getCallerClass
 118      */
 119     static abstract class AbstractStackWalker<R, T> {
 120         protected final StackWalker walker;
 121         protected final Thread thread;
 122         protected final int maxDepth;
 123         protected final long mode;
 124         protected int depth;    // traversed stack depth
 125         protected FrameBuffer<? extends T> frameBuffer;
 126         protected long anchor;
 127 
 128         // buffers to fill in stack frame information
 129         protected AbstractStackWalker(StackWalker walker, int mode) {
 130             this(walker, mode, Integer.MAX_VALUE);
 131         }
 132         protected AbstractStackWalker(StackWalker walker, int mode, int maxDepth) {
 133             this.thread = Thread.currentThread();
 134             this.mode = toStackWalkMode(walker, mode);
 135             this.walker = walker;
 136             this.maxDepth = maxDepth;
 137             this.depth = 0;
 138         }
 139 
 140         private int toStackWalkMode(StackWalker walker, int mode) {
 141             int newMode = mode;
 142             if (walker.hasOption(Option.SHOW_HIDDEN_FRAMES) &&
 143                     (mode & FILL_CLASS_REFS_ONLY) != FILL_CLASS_REFS_ONLY)
 144                 newMode |= SHOW_HIDDEN_FRAMES;
 145             if (walker.hasLocalsOperandsOption())
 146                 newMode |= FILL_LIVE_STACK_FRAMES;
 147             return newMode;
 148         }
 149 
 150         /**
 151          * A callback method to consume the stack frames.  This method is invoked
 152          * once stack walking begins (i.e. it is only invoked when walkFrames is called).
 153          *
 154          * Each specialized AbstractStackWalker subclass implements the consumeFrames method
 155          * to control the following:
 156          * 1. fetch the subsequent batches of stack frames
 157          * 2. reuse or expand the allocated buffers
 158          * 3. create specialized StackFrame objects
 159          *
 160          * @return the number of consumed frames
 161          */
 162          protected abstract R consumeFrames();
 163 
 164         /**
 165          * Initialize FrameBuffer.  Subclass should implement this method to
 166          * create its custom frame buffers.
 167          */
 168          protected abstract void initFrameBuffer();
 169 
 170         /**
 171          * Returns the suggested next batch size.
 172          *
 173          * Subclass should override this method to change the batch size
 174          *
 175          * @param lastBatchFrameCount number of frames in the last batch; or zero
 176          * @return suggested batch size
 177          */
 178         protected abstract int batchSize(int lastBatchFrameCount);
 179 
 180         /*
 181          * Returns the next batch size, always >= minimum batch size (32)
 182          *
 183          * Subclass may override this method if the minimum batch size is different.
 184          */
 185         protected int getNextBatchSize() {
 186             int lastBatchSize = depth == 0 ? 0 : frameBuffer.curBatchFrameCount();
 187             int nextBatchSize = batchSize(lastBatchSize);
 188             if (isDebug) {
 189                 System.err.println("last batch size = " + lastBatchSize +
 190                                    " next batch size = " + nextBatchSize);
 191             }
 192             return nextBatchSize >= MIN_BATCH_SIZE ? nextBatchSize : MIN_BATCH_SIZE;
 193         }
 194 
 195         /*
 196          * Checks if this stream is in the given state. Otherwise, throws IllegalStateException.
 197          *
 198          * VM also validates this stream if it's anchored for stack walking
 199          * when stack frames are fetched for each batch.
 200          */
 201         final void checkState(WalkerState state) {
 202             if (thread != Thread.currentThread()) {
 203                 throw new IllegalStateException("Invalid thread walking this stack stream: " +
 204                         Thread.currentThread().getName() + " " + thread.getName());
 205             }
 206             switch (state) {
 207                 case NEW:
 208                     if (anchor != 0) {
 209                         throw new IllegalStateException("This stack stream is being reused.");
 210                     }
 211                     break;
 212                 case OPEN:
 213                     if (anchor == 0 || anchor == -1L) {
 214                         throw new IllegalStateException("This stack stream is not valid for walking.");
 215                     }
 216                     break;
 217                 case CLOSED:
 218                     if (anchor != -1L) {
 219                         throw new IllegalStateException("This stack stream is not closed.");
 220                     }
 221             }
 222         }
 223 
 224         /*
 225          * Close this stream.  This stream becomes invalid to walk.
 226          */
 227         private void close() {
 228             this.anchor = -1L;
 229         }
 230 
 231         /*
 232          * Walks stack frames until {@link #consumeFrames} is done consuming
 233          * the frames it is interested in.
 234          */
 235         final R walk() {
 236             checkState(NEW);
 237             try {
 238                 // VM will need to stablize the stack before walking.  It will invoke
 239                 // the AbstractStackWalker::doStackWalk method once it fetches the first batch.
 240                 // the callback will be invoked within the scope of the callStackWalk frame.
 241                 return beginStackWalk();
 242             } finally {
 243                 close();  // done traversal; close the stream
 244             }
 245         }
 246 
 247         private boolean skipReflectionFrames() {
 248             return !walker.hasOption(Option.SHOW_REFLECT_FRAMES) &&
 249                        !walker.hasOption(Option.SHOW_HIDDEN_FRAMES);
 250         }
 251 
 252         /*
 253          * Returns {@code Class} object at the current frame;
 254          * or {@code null} if no more frame. If advanceToNextBatch is true,
 255          * it will only fetch the next batch.
 256          */
 257         final Class<?> peekFrame() {
 258             while (frameBuffer.isActive() && depth < maxDepth) {
 259                 if (frameBuffer.isEmpty()) {
 260                     // fetch another batch of stack frames
 261                     getNextBatch();
 262                 } else {
 263                     Class<?> c = frameBuffer.get();
 264                     if (skipReflectionFrames() && isReflectionFrame(c)) {
 265                         if (isDebug)
 266                             System.err.println("  skip: frame " + frameBuffer.getIndex() + " " + c);
 267 
 268                         frameBuffer.next();
 269                         depth++;
 270                         continue;
 271                     } else {
 272                         return c;
 273                     }
 274                 }
 275             }
 276             return null;
 277         }
 278 
 279         /*
 280          * This method is only invoked by VM.
 281          *
 282          * It will invoke the consumeFrames method to start the stack walking
 283          * with the first batch of stack frames.  Each specialized AbstractStackWalker
 284          * subclass implements the consumeFrames method to control the following:
 285          * 1. fetch the subsequent batches of stack frames
 286          * 2. reuse or expand the allocated buffers
 287          * 3. create specialized StackFrame objects
 288          */
 289         private Object doStackWalk(long anchor, int skipFrames, int batchSize,
 290                                                 int bufStartIndex, int bufEndIndex) {
 291             checkState(NEW);
 292 
 293             frameBuffer.check(skipFrames);
 294 
 295             if (isDebug) {
 296                 System.err.format("doStackWalk: skip %d start %d end %d%n",
 297                         skipFrames, bufStartIndex, bufEndIndex);
 298             }
 299 
 300             this.anchor = anchor;  // set anchor for this bulk stack frame traversal
 301             frameBuffer.setBatch(depth, bufStartIndex, bufEndIndex);
 302 
 303             // traverse all frames and perform the action on the stack frames, if specified
 304             return consumeFrames();
 305         }
 306 
 307         /*
 308          * Get next batch of stack frames.
 309          */
 310         private int getNextBatch() {
 311             int nextBatchSize = Math.min(maxDepth - depth, getNextBatchSize());
 312             if (!frameBuffer.isActive() || nextBatchSize <= 0) {
 313                 if (isDebug) {
 314                     System.out.format("  more stack walk done%n");
 315                 }
 316                 frameBuffer.freeze();   // stack walk done
 317                 return 0;
 318             }
 319 
 320             return fetchStackFrames(nextBatchSize);
 321         }
 322 
 323         /*
 324          * This method traverses the next stack frame and returns the Class
 325          * invoking that stack frame.
 326          *
 327          * This method can only be called during the walk method.  This is intended
 328          * to be used to walk the stack frames in one single invocation and
 329          * this stack stream will be invalidated once walk is done.
 330          *
 331          * @see #tryNextFrame
 332          */
 333         final Class<?> nextFrame() {
 334             if (!hasNext()) {
 335                 return null;
 336             }
 337 
 338             Class<?> c = frameBuffer.next();
 339             depth++;
 340             return c;
 341         }
 342 
 343         /*
 344          * Returns true if there is next frame to be traversed.
 345          * This skips hidden frames unless this StackWalker has
 346          * {@link Option#SHOW_REFLECT_FRAMES}
 347          */
 348         final boolean hasNext() {
 349             return peekFrame() != null;
 350         }
 351 
 352         /**
 353          * Begin stack walking - pass the allocated arrays to the VM to fill in
 354          * stack frame information.
 355          *
 356          * VM first anchors the frame of the current thread.  A traversable stream
 357          * on this thread's stack will be opened.  The VM will fetch the first batch
 358          * of stack frames and call AbstractStackWalker::doStackWalk to invoke the
 359          * stack walking function on each stack frame.
 360          *
 361          * If all fetched stack frames are traversed, AbstractStackWalker::fetchStackFrames will
 362          * fetch the next batch of stack frames to continue.
 363          */
 364         private R beginStackWalk() {
 365             // initialize buffers for VM to fill the stack frame info
 366             initFrameBuffer();
 367 
 368             return callStackWalk(mode, 0,
 369                                  frameBuffer.curBatchFrameCount(),
 370                                  frameBuffer.startIndex(),
 371                                  frameBuffer.frames());
 372         }
 373 
 374         /*
 375          * Fetches stack frames.
 376          *
 377          * @params batchSize number of elements of the frame  buffers for this batch
 378          * @returns number of frames fetched in this batch
 379          */
 380         private int fetchStackFrames(int batchSize) {
 381             int startIndex = frameBuffer.startIndex();
 382             frameBuffer.resize(startIndex, batchSize);
 383 
 384             int endIndex = fetchStackFrames(mode, anchor, batchSize,
 385                                             startIndex,
 386                                             frameBuffer.frames());
 387             if (isDebug) {
 388                 System.out.format("  more stack walk requesting %d got %d to %d frames%n",
 389                                   batchSize, frameBuffer.startIndex(), endIndex);
 390             }
 391             int numFrames = endIndex - startIndex;
 392             if (numFrames == 0) {
 393                 frameBuffer.freeze(); // done stack walking
 394             } else {
 395                 frameBuffer.setBatch(depth, startIndex, endIndex);
 396             }
 397             return numFrames;
 398         }
 399 
 400         /**
 401          * Begins stack walking.  This method anchors this frame and invokes
 402          * AbstractStackWalker::doStackWalk after fetching the first batch of stack frames.
 403          *
 404          * @param mode        mode of stack walking
 405          * @param skipframes  number of frames to be skipped before filling the frame buffer.
 406          * @param batchSize   the batch size, max. number of elements to be filled in the frame buffers.
 407          * @param startIndex  start index of the frame buffers to be filled.
 408          * @param frames      Either a Class<?> array, if mode is {@link #FILL_CLASS_REFS_ONLY}
 409          *                    or a {@link StackFrameInfo} (or derivative) array otherwise.
 410          * @return            Result of AbstractStackWalker::doStackWalk
 411          */
 412         private native R callStackWalk(long mode, int skipframes,
 413                                        int batchSize, int startIndex,
 414                                        T[] frames);
 415 
 416         /**
 417          * Fetch the next batch of stack frames.
 418          *
 419          * @param mode        mode of stack walking
 420          * @param anchor
 421          * @param batchSize   the batch size, max. number of elements to be filled in the frame buffers.
 422          * @param startIndex  start index of the frame buffers to be filled.
 423          * @param frames      Either a Class<?> array, if mode is {@link #FILL_CLASS_REFS_ONLY}
 424          *                    or a {@link StackFrameInfo} (or derivative) array otherwise.
 425          *
 426          * @return the end index to the frame buffers
 427          */
 428         private native int fetchStackFrames(long mode, long anchor,
 429                                             int batchSize, int startIndex,
 430                                             T[] frames);
 431     }
 432 
 433     /*
 434      * This StackFrameTraverser supports {@link Stream} traversal.
 435      *
 436      * This class implements Spliterator::forEachRemaining and Spliterator::tryAdvance.
 437      */
 438     static class StackFrameTraverser<T> extends AbstractStackWalker<T, StackFrameInfo>
 439             implements Spliterator<StackFrame>
 440     {
 441         static {
 442             stackWalkImplClasses.add(StackFrameTraverser.class);
 443         }
 444         private static final int CHARACTERISTICS = Spliterator.ORDERED | Spliterator.IMMUTABLE;
 445 
 446         final class StackFrameBuffer extends FrameBuffer<StackFrameInfo> {
 447             private StackFrameInfo[] stackFrames;
 448             StackFrameBuffer(int initialBatchSize) {
 449                 super(initialBatchSize);
 450 
 451                 this.stackFrames = new StackFrameInfo[initialBatchSize];
 452                 for (int i = START_POS; i < initialBatchSize; i++) {
 453                     stackFrames[i] = new StackFrameInfo(walker);
 454                 }
 455             }
 456 
 457             @Override
 458             StackFrameInfo[] frames() {
 459                 return stackFrames;
 460             }
 461 
 462             @Override
 463             void resize(int startIndex, int elements) {
 464                 if (!isActive())
 465                     throw new IllegalStateException("inactive frame buffer can't be resized");
 466 
 467                 assert startIndex == START_POS :
 468                        "bad start index " + startIndex + " expected " + START_POS;
 469 
 470                 int size = startIndex+elements;
 471                 if (stackFrames.length < size) {
 472                     StackFrameInfo[] newFrames = new StackFrameInfo[size];
 473                     // copy initial magic...
 474                     System.arraycopy(stackFrames, 0, newFrames, 0, startIndex);
 475                     stackFrames = newFrames;
 476                 }
 477                 for (int i = startIndex; i < size; i++) {
 478                     stackFrames[i] = new StackFrameInfo(walker);
 479                 }
 480                 currentBatchSize = size;
 481             }
 482 
 483             @Override
 484             StackFrameInfo nextStackFrame() {
 485                 if (isEmpty()) {
 486                     throw new NoSuchElementException("origin=" + origin + " fence=" + fence);
 487                 }
 488 
 489                 StackFrameInfo frame = stackFrames[origin];
 490                 origin++;
 491                 return frame;
 492             }
 493 
 494             @Override
 495             final Class<?> at(int index) {
 496                 return stackFrames[index].declaringClass();
 497             }
 498         }
 499 
 500         final Function<? super Stream<StackFrame>, ? extends T> function;  // callback
 501 
 502         StackFrameTraverser(StackWalker walker,
 503                             Function<? super Stream<StackFrame>, ? extends T> function) {
 504             this(walker, function, DEFAULT_MODE);
 505         }
 506         StackFrameTraverser(StackWalker walker,
 507                             Function<? super Stream<StackFrame>, ? extends T> function,
 508                             int mode) {
 509             super(walker, mode);
 510             this.function = function;
 511         }
 512 
 513         /**
 514          * Returns next StackFrame object in the current batch of stack frames;
 515          * or null if no more stack frame.
 516          */
 517         StackFrame nextStackFrame() {
 518             if (!hasNext()) {
 519                 return null;
 520             }
 521 
 522             StackFrameInfo frame = frameBuffer.nextStackFrame();
 523             depth++;
 524             return frame;
 525         }
 526 
 527         @Override
 528         protected T consumeFrames() {
 529             checkState(OPEN);
 530             Stream<StackFrame> stream = StreamSupport.stream(this, false);
 531             if (function != null) {
 532                 return function.apply(stream);
 533             } else
 534                 throw new UnsupportedOperationException();
 535         }
 536 
 537         @Override
 538         protected void initFrameBuffer() {
 539             this.frameBuffer = new StackFrameBuffer(getNextBatchSize());
 540         }
 541 
 542         @Override
 543         protected int batchSize(int lastBatchFrameCount) {
 544             if (lastBatchFrameCount == 0) {
 545                 // First batch, use estimateDepth if not exceed the large batch size
 546                 // and not too small
 547                 int initialBatchSize = Math.max(walker.estimateDepth(), SMALL_BATCH);
 548                 return Math.min(initialBatchSize, LARGE_BATCH_SIZE);
 549             } else {
 550                 if (lastBatchFrameCount > BATCH_SIZE) {
 551                     return lastBatchFrameCount;
 552                 } else {
 553                     return Math.min(lastBatchFrameCount*2, BATCH_SIZE);
 554                 }
 555             }
 556         }
 557 
 558         // ------- Implementation of Spliterator
 559 
 560         @Override
 561         public Spliterator<StackFrame> trySplit() {
 562             return null;   // ordered stream and do not allow to split
 563         }
 564 
 565         @Override
 566         public long estimateSize() {
 567             return maxDepth;
 568         }
 569 
 570         @Override
 571         public int characteristics() {
 572             return CHARACTERISTICS;
 573         }
 574 
 575         @Override
 576         public void forEachRemaining(Consumer<? super StackFrame> action) {
 577             checkState(OPEN);
 578             for (int n = 0; n < maxDepth; n++) {
 579                 StackFrame frame = nextStackFrame();
 580                 if (frame == null) break;
 581 
 582                 action.accept(frame);
 583             }
 584         }
 585 
 586         @Override
 587         public boolean tryAdvance(Consumer<? super StackFrame> action) {
 588             checkState(OPEN);
 589 
 590             int index = frameBuffer.getIndex();
 591             if (hasNext()) {
 592                 StackFrame frame = nextStackFrame();
 593                 action.accept(frame);
 594                 if (isDebug) {
 595                     System.err.println("tryAdvance: " + index + " " + frame);
 596                 }
 597                 return true;
 598             }
 599             if (isDebug) {
 600                 System.err.println("tryAdvance: " + index + " NO element");
 601             }
 602             return false;
 603         }
 604     }
 605 
 606     /*
 607      * CallerClassFinder is specialized to return Class<?> for each stack frame.
 608      * StackFrame is not requested.
 609      */
 610     static final class CallerClassFinder extends AbstractStackWalker<Integer, Class<?>> {
 611         static {
 612             stackWalkImplClasses.add(CallerClassFinder.class);
 613         }
 614 
 615         private Class<?> caller;
 616 
 617         CallerClassFinder(StackWalker walker) {
 618             super(walker, FILL_CLASS_REFS_ONLY|GET_CALLER_CLASS);


 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                 if (isReflectionFrame(caller)) { continue; }
 684                 frames[n++] = caller;
 685             }
 686             if (frames[1] == null) {
 687                 throw new IllegalStateException("no caller frame");
 688             }
 689             return n;
 690         }
 691 
 692         @Override
 693         protected void initFrameBuffer() {
 694             this.frameBuffer = new ClassBuffer(getNextBatchSize());
 695         }
 696 
 697         @Override
 698         protected int batchSize(int lastBatchFrameCount) {
 699             return MIN_BATCH_SIZE;
 700         }
 701 
 702         @Override
 703         protected int getNextBatchSize() {
 704             return MIN_BATCH_SIZE;
 705         }
 706     }
 707 
 708     static final class LiveStackInfoTraverser<T> extends StackFrameTraverser<T> {
 709         static {
 710             stackWalkImplClasses.add(LiveStackInfoTraverser.class);
 711         }
 712         // VM will fill in all method info and live stack info directly in StackFrameInfo
 713         final class LiveStackFrameBuffer extends FrameBuffer<LiveStackFrameInfo> {
 714             private LiveStackFrameInfo[] stackFrames;
 715             LiveStackFrameBuffer(int initialBatchSize) {
 716                 super(initialBatchSize);
 717                 this.stackFrames = new LiveStackFrameInfo[initialBatchSize];
 718                 for (int i = START_POS; i < initialBatchSize; i++) {
 719                     stackFrames[i] = new LiveStackFrameInfo(walker);
 720                 }
 721             }
 722 
 723             @Override
 724             LiveStackFrameInfo[] frames() {
 725                 return stackFrames;
 726             }
 727 
 728             @Override
 729             void resize(int startIndex, int elements) {
 730                 if (!isActive()) {
 731                     throw new IllegalStateException("inactive frame buffer can't be resized");
 732                 }
 733                 assert startIndex == START_POS :
 734                        "bad start index " + startIndex + " expected " + START_POS;
 735 
 736                 int size = startIndex + elements;
 737                 if (stackFrames.length < size) {
 738                     LiveStackFrameInfo[] newFrames = new LiveStackFrameInfo[size];
 739                     // copy initial magic...
 740                     System.arraycopy(stackFrames, 0, newFrames, 0, startIndex);
 741                     stackFrames = newFrames;
 742                 }
 743 
 744                 for (int i = startIndex(); i < size; i++) {
 745                     stackFrames[i] = new LiveStackFrameInfo(walker);
 746                 }
 747 
 748                 currentBatchSize = size;
 749             }
 750 
 751             @Override
 752             LiveStackFrameInfo nextStackFrame() {
 753                 if (isEmpty()) {
 754                     throw new NoSuchElementException("origin=" + origin + " fence=" + fence);
 755                 }
 756 
 757                 LiveStackFrameInfo frame = stackFrames[origin];
 758                 origin++;
 759                 return frame;
 760             }
 761 
 762             @Override
 763             final Class<?> at(int index) {
 764                 return stackFrames[index].declaringClass();
 765             }
 766         }
 767 
 768         LiveStackInfoTraverser(StackWalker walker,
 769                                Function<? super Stream<StackFrame>, ? extends T> function) {
 770             super(walker, function, DEFAULT_MODE);
 771         }
 772 
 773         @Override
 774         protected void initFrameBuffer() {
 775             this.frameBuffer = new LiveStackFrameBuffer(getNextBatchSize());
 776         }
 777     }
 778 
 779     /*
 780      * Frame buffer
 781      *
 782      * Each specialized AbstractStackWalker subclass may subclass the FrameBuffer.
 783      */
 784     static abstract class FrameBuffer<F> {
 785         static final int START_POS = 2;     // 0th and 1st elements are reserved
 786 
 787         // buffers for VM to fill stack frame info
 788         int currentBatchSize;    // current batch size
 789         int origin;         // index to the current traversed stack frame
 790         int fence;          // index to the last frame in the current batch
 791 
 792         FrameBuffer(int initialBatchSize) {
 793             if (initialBatchSize < MIN_BATCH_SIZE) {
 794                 throw new IllegalArgumentException(initialBatchSize +
 795                         " < minimum batch size: " + MIN_BATCH_SIZE);
 796             }
 797             this.origin = START_POS;
 798             this.fence = 0;
 799             this.currentBatchSize = initialBatchSize;
 800         }
 801 
 802         /**
 803          * Returns an array of frames that may be used to store frame objects
 804          * when walking the stack.
 805          *
 806          * May be an array of {@code Class<?>} if the {@code AbstractStackWalker}
 807          * mode is {@link #FILL_CLASS_REFS_ONLY}, or an array of
 808          * {@link StackFrameInfo} (or derivative) array otherwise.
 809          *
 810          * @return An array of frames that may be used to store frame objects
 811          * when walking the stack. Must not be null.
 812          */
 813         abstract F[] frames(); // must not return null
 814 
 815         /**
 816          * Resizes the buffers for VM to fill in the next batch of stack frames.
 817          * The next batch will start at the given startIndex with the maximum number
 818          * of elements.
 819          *
 820          * <p> Subclass may override this method to manage the allocated buffers.
 821          *
 822          * @param startIndex the start index for the first frame of the next batch to fill in.
 823          * @param elements the number of elements for the next batch to fill in.
 824          *
 825          */
 826         abstract void resize(int startIndex, int elements);
 827 
 828         /**
 829          * Return the class at the given position in the current batch.
 830          * @param index the position of the frame.
 831          * @return the class at the given position in the current batch.
 832          */
 833         abstract Class<?> at(int index);
 834 
 835         // ------ subclass may override the following methods -------
 836 
 837         /*
 838          * Returns the start index for this frame buffer is refilled.
 839          *
 840          * This implementation reuses the allocated buffer for the next batch
 841          * of stack frames.  For subclass to retain the fetched stack frames,
 842          * it should override this method to return the index at which the frame
 843          * should be filled in for the next batch.
 844          */
 845         int startIndex() {
 846             return START_POS;
 847         }
 848 
 849         /**
 850          * Returns next StackFrame object in the current batch of stack frames
 851          */
 852         F nextStackFrame() {
 853             throw new InternalError("should not reach here");
 854         }
 855 
 856         // ------ FrameBuffer implementation ------
 857 
 858         final int curBatchFrameCount() {
 859             return currentBatchSize-START_POS;
 860         }
 861 
 862         /*
 863          * Tests if this frame buffer is empty.  All frames are fetched.
 864          */
 865         final boolean isEmpty() {
 866             return origin >= fence || (origin == START_POS && fence == 0);
 867         }
 868 
 869         /*
 870          * Freezes this frame buffer.  The stack stream source is done fetching.
 871          */
 872         final void freeze() {
 873             origin = 0;
 874             fence = 0;
 875         }
 876 
 877         /*
 878          * Tests if this frame buffer is active.  It is inactive when
 879          * it is done for traversal.  All stack frames have been traversed.
 880          */
 881         final boolean isActive() {
 882             return origin > 0 && (fence == 0 || origin < fence || fence == currentBatchSize);
 883         }
 884 
 885         /**
 886          * Gets the class at the current frame and move to the next frame.
 887          */
 888         final Class<?> next() {
 889             if (isEmpty()) {
 890                 throw new NoSuchElementException("origin=" + origin + " fence=" + fence);
 891             }
 892             Class<?> c = at(origin);
 893             origin++;
 894             if (isDebug) {
 895                 int index = origin-1;
 896                 System.out.format("  next frame at %d: %s (origin %d fence %d)%n", index,
 897                         Objects.toString(c), index, fence);
 898             }
 899             return c;
 900         }
 901 
 902         /**
 903          * Gets the class at the current frame.
 904          */
 905         final Class<?> get() {
 906             if (isEmpty()) {
 907                 throw new NoSuchElementException("origin=" + origin + " fence=" + fence);
 908             }
 909             return at(origin);
 910         }
 911 
 912         /*
 913          * Returns the index of the current frame.
 914          */
 915         final int getIndex() {
 916             return origin;
 917         }
 918 
 919         /*
 920          * Set the start and end index of a new batch of stack frames that have
 921          * been filled in this frame buffer.
 922          */
 923         final void setBatch(int depth, int startIndex, int endIndex) {
 924             if (startIndex <= 0 || endIndex <= 0)
 925                 throw new IllegalArgumentException("startIndex=" + startIndex + " endIndex=" + endIndex);
 926 
 927             this.origin = startIndex;
 928             this.fence = endIndex;
 929             if (depth == 0 && fence > 0) {
 930                 // filter the frames due to the stack stream implementation
 931                 for (int i = START_POS; i < fence; i++) {
 932                     Class<?> c = at(i);
 933                     if (isDebug) System.err.format("  frame %d: %s%n", i, c);
 934                     if (filterStackWalkImpl(c)) {
 935                         origin++;
 936                     } else {
 937                         break;
 938                     }
 939                 }
 940             }
 941         }
 942 
 943         /*
 944          * Checks if the origin is the expected start index.
 945          */
 946         final void check(int skipFrames) {
 947             int index = skipFrames + START_POS;
 948             if (origin != index) {
 949                 // stack walk must continue with the previous frame depth
 950                 throw new IllegalStateException("origin " + origin + " != " + index);
 951             }
 952         }
 953     }
 954 
 955     private static native boolean checkStackWalkModes();
 956 
 957     // avoid loading other subclasses as they may not be used
 958     private static Set<Class<?>> init() {
 959         if (!checkStackWalkModes()) {
 960             throw new InternalError("StackWalker mode values do not match with JVM");
 961         }
 962 
 963         Set<Class<?>> classes = new HashSet<>();
 964         classes.add(StackWalker.class);
 965         classes.add(StackStreamFactory.class);
 966         classes.add(AbstractStackWalker.class);
 967         return classes;
 968     }
 969 
 970     private static boolean filterStackWalkImpl(Class<?> c) {
 971         return stackWalkImplClasses.contains(c) ||
 972                 c.getName().startsWith("java.util.stream.");
 973     }
 974 
 975     // MethodHandle frames are not hidden and CallerClassFinder has
 976     // to filter them out
 977     private static boolean isMethodHandleFrame(Class<?> c) {
 978         return c.getName().startsWith("java.lang.invoke.");
 979     }
 980 
 981     private static boolean isReflectionFrame(Class<?> c) {
 982         if (c.getName().startsWith("jdk.internal.reflect") &&
 983                 !MethodAccessor.class.isAssignableFrom(c)) {
 984             throw new InternalError("Not jdk.internal.reflect.MethodAccessor: " + c.toString());
 985         }
 986         // ## should filter all @Hidden frames?
 987         return c == Method.class ||
 988                 MethodAccessor.class.isAssignableFrom(c) ||
 989                 c.getName().startsWith("java.lang.invoke.LambdaForm");
 990     }
 991 
 992 }
--- EOF ---