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