1 /*
   2  * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 package java.lang;
  26 
  27 import sun.reflect.CallerSensitive;
  28 
  29 import java.util.*;
  30 import java.util.function.Consumer;
  31 import java.util.function.Function;
  32 import java.util.stream.Stream;
  33 
  34 /**
  35  * A stack walker.
  36  *
  37  * <p> The {@link StackWalker#walk walk} method opens a sequential stream
  38  * of {@link StackFrame StackFrame}s for the current thread and then applies
  39  * the given function to walk the {@code StackFrame} stream.
  40  * The stream reports stack frame elements in order, from the top most frame
  41  * that represents the execution point at which the stack was generated to
  42  * the bottom most frame.
  43  * The {@code StackFrame} stream is closed when the {@code walk} method returns.
  44  * If an attempt is made to reuse the closed stream,
  45  * {@code IllegalStateException} will be thrown.
  46  *
  47  * <p> The {@linkplain Option <em>stack walking options</em>} of a
  48  * {@code StackWalker} determines the information of
  49  * {@link StackFrame StackFrame} objects to be returned.
  50  * By default, stack frames of the reflection API and implementation
  51  * classes are {@linkplain Option#SHOW_HIDDEN_FRAMES hidden}
  52  * and {@code StackFrame}s have the class name and method name
  53  * available but not the {@link StackFrame#getDeclaringClass() Class reference}.
  54  *
  55  * <p> {@code StackWalker} is thread-safe. Multiple threads can share
  56  * a single {@code StackWalker} object to traverse its own stack.
  57  * A permission check is performed when a {@code StackWalker} is created,
  58  * according to the options it requests.
  59  * No further permission check is done at stack walking time.
  60  *
  61  * @apiNote
  62  * Examples
  63  *
  64  * <p>1. To find the first caller filtering a known list of implementation class:
  65  * <pre>{@code
  66  *     StackWalker walker = StackWalker.getInstance(Option.RETAIN_CLASS_REFERENCE);
  67  *     Optional<Class<?>> callerClass = walker.walk(s ->
  68  *         s.map(StackFrame::getDeclaringClass)
  69  *          .filter(interestingClasses::contains)
  70  *          .findFirst());
  71  * }</pre>
  72  *
  73  * <p>2. To snapshot the top 10 stack frames of the current thread,
  74  * <pre>{@code
  75  *     List<StackFrame> stack = StackWalker.getInstance().walk(s ->
  76  *         s.limit(10).collect(Collectors.toList()));
  77  * }</pre>
  78  *
  79  * Unless otherwise noted, passing a {@code null} argument to a
  80  * constructor or method in this {@code StackWalker} class
  81  * will cause a {@link NullPointerException NullPointerException}
  82  * to be thrown.
  83  *
  84  * @since 9
  85  */
  86 public final class StackWalker {
  87     /**
  88      * A {@code StackFrame} object represents a method invocation returned by
  89      * {@link StackWalker}.
  90      *
  91      * <p> The {@link #getDeclaringClass()} method may be unsupported as determined
  92      * by the {@linkplain Option stack walking options} of a {@linkplain
  93      * StackWalker stack walker}.
  94      *
  95      * @since 9
  96      * @jvms 2.6
  97      */
  98     public static interface StackFrame {
  99         /**
 100          * Gets the <a href="ClassLoader.html#name">binary name</a>
 101          * of the declaring class of the method represented by this stack frame.
 102          *
 103          * @return the binary name of the declaring class of the method
 104          *         represented by this stack frame
 105          *
 106          * @jls 13.1 The Form of a Binary
 107          */
 108         public String getClassName();
 109 
 110         /**
 111          * Gets the name of the method represented by this stack frame.
 112          * @return the name of the method represented by this stack frame
 113          */
 114         public String getMethodName();
 115 
 116         /**
 117          * Gets the declaring {@code Class} for the method represented by
 118          * this stack frame.
 119          *
 120          * @return the declaring {@code Class} of the method represented by
 121          * this stack frame
 122          *
 123          * @throws UnsupportedOperationException if this {@code StackWalker}
 124          *         is not configured with {@link Option#RETAIN_CLASS_REFERENCE
 125          *         Option.RETAIN_CLASS_REFERENCE}.
 126          */
 127         public Class<?> getDeclaringClass();
 128 
 129         /**
 130          * Returns {@code true} if the method containing the execution point
 131          * represented by this stack frame is a native method.
 132          *
 133          * @return {@code true} if the method containing the execution point
 134          *         represented by this stack frame is a native method.
 135          */
 136         public boolean isNativeMethod();
 137 
 138         /**
 139          * Gets a {@code StackTraceElement} for this stack frame.
 140          *
 141          * @return {@code StackTraceElement} for this stack frame.
 142          */
 143         public StackTraceElement toStackTraceElement();
 144     }
 145 
 146     /**
 147      * Stack walker option to configure the {@linkplain StackFrame stack frame}
 148      * information obtained by a {@code StackWalker}.
 149      *
 150      * @since 9
 151      */
 152     public enum Option {
 153         /**
 154          * Retains {@code Class} object in {@code StackFrame}s
 155          * walked by this {@code StackWalker}.
 156          *
 157          * <p> A {@code StackWalker} configured with this option will support
 158          * {@link StackWalker#getCallerClass()} and
 159          * {@link StackFrame#getDeclaringClass() StackFrame.getDeclaringClass()}.
 160          */
 161         RETAIN_CLASS_REFERENCE,
 162         /**
 163          * Shows all reflection frames.
 164          *
 165          * <p>By default, reflection frames are hidden.  This includes the
 166          * {@link java.lang.reflect.Method#invoke} method
 167          * and the reflection implementation classes. A {@code StackWalker} with
 168          * this {@code SHOW_REFLECT_FRAMES} option will show all reflection frames.
 169          * The {@link #SHOW_HIDDEN_FRAMES} option can also be used to show all
 170          * reflection frames and it will also show other hidden frames that
 171          * are implementation-specific.
 172          */
 173         SHOW_REFLECT_FRAMES,
 174         /**
 175          * Shows all hidden frames.
 176          *
 177          * <p>A Java Virtual Machine implementation may hide implementation
 178          * specific frames in addition to {@linkplain #SHOW_REFLECT_FRAMES
 179          * reflection frames}. A {@code StackWalker} with this {@code SHOW_HIDDEN_FRAMES}
 180          * option will show all hidden frames (including reflection frames).
 181          */
 182         SHOW_HIDDEN_FRAMES;
 183     }
 184 
 185     enum ExtendedOption {
 186         /**
 187          * Obtain monitors, locals and operands.
 188          */
 189         LOCALS_AND_OPERANDS
 190     };
 191 
 192     static final EnumSet<Option> DEFAULT_EMPTY_OPTION = EnumSet.noneOf(Option.class);
 193 
 194     private final static StackWalker DEFAULT_WALKER =
 195         new StackWalker(DEFAULT_EMPTY_OPTION);
 196 
 197     private final Set<Option> options;
 198     private final ExtendedOption extendedOption;
 199     private final int estimateDepth;
 200 
 201     /**
 202      * Returns a {@code StackWalker} instance.
 203      *
 204      * <p> This {@code StackWalker} is configured to skip all
 205      * {@linkplain Option#SHOW_HIDDEN_FRAMES hidden frames} and
 206      * no {@linkplain Option#RETAIN_CLASS_REFERENCE class reference} is retained.
 207      *
 208      * @return a {@code StackWalker} configured to skip all
 209      * {@linkplain Option#SHOW_HIDDEN_FRAMES hidden frames} and
 210      * no {@linkplain Option#RETAIN_CLASS_REFERENCE class reference} is retained.
 211      *
 212      */
 213     public static StackWalker getInstance() {
 214         // no permission check needed
 215         return DEFAULT_WALKER;
 216     }
 217 
 218     /**
 219      * Returns a {@code StackWalker} instance with the given option specifying
 220      * the stack frame information it can access.
 221      *
 222      * <p>
 223      * If a security manager is present and the given {@code option} is
 224      * {@link Option#RETAIN_CLASS_REFERENCE Option.RETAIN_CLASS_REFERENCE},
 225      * it calls its {@link SecurityManager#checkPermission checkPermission}
 226      * method for {@code StackFramePermission("retainClassReference")}.
 227      *
 228      * @param option {@link Option stack walking option}
 229      *
 230      * @return a {@code StackWalker} configured with the given option
 231      *
 232      * @throws SecurityException if a security manager exists and its
 233      *         {@code checkPermission} method denies access.
 234      */
 235     public static StackWalker getInstance(Option option) {
 236         return getInstance(EnumSet.of(Objects.requireNonNull(option)));
 237     }
 238 
 239     /**
 240      * Returns a {@code StackWalker} instance with the given {@code options} specifying
 241      * the stack frame information it can access.  If the given {@code options}
 242      * is empty, this {@code StackWalker} is configured to skip all
 243      * {@linkplain Option#SHOW_HIDDEN_FRAMES hidden frames} and no
 244      * {@linkplain Option#RETAIN_CLASS_REFERENCE class reference} is retained.
 245      *
 246      * <p>
 247      * If a security manager is present and the given {@code options} contains
 248      * {@link Option#RETAIN_CLASS_REFERENCE Option.RETAIN_CLASS_REFERENCE},
 249      * it calls its {@link SecurityManager#checkPermission checkPermission}
 250      * method for {@code StackFramePermission("retainClassReference")}.
 251      *
 252      * @param options {@link Option stack walking option}
 253      *
 254      * @return a {@code StackWalker} configured with the given options
 255      *
 256      * @throws SecurityException if a security manager exists and its
 257      *         {@code checkPermission} method denies access.
 258      */
 259     public static StackWalker getInstance(Set<Option> options) {
 260         if (options.isEmpty()) {
 261             return DEFAULT_WALKER;
 262         }
 263 
 264         checkPermission(options);
 265         return new StackWalker(toEnumSet(options));
 266     }
 267 
 268     /**
 269      * Returns a {@code StackWalker} instance with the given {@code options} specifying
 270      * the stack frame information it can access. If the given {@code options}
 271      * is empty, this {@code StackWalker} is configured to skip all
 272      * {@linkplain Option#SHOW_HIDDEN_FRAMES hidden frames} and no
 273      * {@linkplain Option#RETAIN_CLASS_REFERENCE class reference} is retained.
 274      *
 275      * <p>
 276      * If a security manager is present and the given {@code options} contains
 277      * {@link Option#RETAIN_CLASS_REFERENCE Option.RETAIN_CLASS_REFERENCE},
 278      * it calls its {@link SecurityManager#checkPermission checkPermission}
 279      * method for {@code StackFramePermission("retainClassReference")}.
 280      *
 281      * <p>
 282      * The {@code estimateDepth} specifies the estimate number of stack frames
 283      * this {@code StackWalker} will traverse that the {@code StackWalker} could
 284      * use as a hint for the buffer size.
 285      *
 286      * @param options {@link Option stack walking options}
 287      * @param estimateDepth Estimate number of stack frames to be traversed.
 288      *
 289      * @return a {@code StackWalker} configured with the given options
 290      *
 291      * @throws IllegalArgumentException if {@code estimateDepth <= 0}
 292      * @throws SecurityException if a security manager exists and its
 293      *         {@code checkPermission} method denies access.
 294      */
 295     public static StackWalker getInstance(Set<Option> options, int estimateDepth) {
 296         if (estimateDepth <= 0) {
 297             throw new IllegalArgumentException("estimateDepth must be > 0");
 298         }
 299         checkPermission(options);
 300         return new StackWalker(toEnumSet(options), estimateDepth);
 301     }
 302 
 303     // ----- private constructors ------
 304     private StackWalker(EnumSet<Option> options) {
 305         this(options, 0, null);
 306     }
 307     private StackWalker(EnumSet<Option> options, int estimateDepth) {
 308         this(options, estimateDepth, null);
 309     }
 310     private StackWalker(EnumSet<Option> options, int estimateDepth, ExtendedOption extendedOption) {
 311         this.options = options;
 312         this.estimateDepth = estimateDepth;
 313         this.extendedOption = extendedOption;
 314     }
 315 
 316     private static void checkPermission(Set<Option> options) {
 317         Objects.requireNonNull(options);
 318         SecurityManager sm = System.getSecurityManager();
 319         if (sm != null) {
 320             if (options.contains(Option.RETAIN_CLASS_REFERENCE)) {
 321                 sm.checkPermission(new StackFramePermission("retainClassReference"));
 322             }
 323         }
 324     }
 325 
 326     /*
 327      * Returns a defensive copy
 328      */
 329     private static EnumSet<Option> toEnumSet(Set<Option> options) {
 330         Objects.requireNonNull(options);
 331         if (options.isEmpty()) {
 332             return DEFAULT_EMPTY_OPTION;
 333         } else {
 334             return EnumSet.copyOf(options);
 335         }
 336     }
 337 
 338     /**
 339      * Applies the given function to the stream of {@code StackFrame}s
 340      * for the current thread, traversing from the top frame of the stack,
 341      * which is the method calling this {@code walk} method.
 342      *
 343      * <p>The {@code StackFrame} stream will be closed when
 344      * this method returns.  When a closed {@code Stream<StackFrame>} object
 345      * is reused, {@code IllegalStateException} will be thrown.
 346      *
 347      * @apiNote
 348      * For example, to find the first 10 calling frames, first skipping those frames
 349      * whose declaring class is in package {@code com.foo}:
 350      * <blockquote>
 351      * <pre>{@code
 352      * List<StackFrame> frames = StackWalker.getInstance().walk(s ->
 353      *     s.dropWhile(f -> f.getClassName().startsWith("com.foo."))
 354      *      .limit(10)
 355      *      .collect(Collectors.toList()));
 356      * }</pre></blockquote>
 357      *
 358      * <p>This method takes a {@code Function} accepting a {@code Stream<StackFrame>},
 359      * rather than returning a {@code Stream<StackFrame>} and allowing the
 360      * caller to directly manipulate the stream. The Java virtual machine is
 361      * free to reorganize a thread's control stack, for example, via
 362      * deoptimization. By taking a {@code Function} parameter, this method
 363      * allows access to stack frames through a stable view of a thread's control
 364      * stack.
 365      *
 366      * <p>Parallel execution is effectively disabled and stream pipeline
 367      * execution will only occur on the current thread.
 368      *
 369      * @implNote The implementation stabilizes the stack by anchoring a frame
 370      * specific to the stack walking and ensures that the stack walking is
 371      * performed above the anchored frame. When the stream object is closed or
 372      * being reused, {@code IllegalStateException} will be thrown.
 373      *
 374      * @param function a function that takes a stream of
 375      *                 {@linkplain StackFrame stack frames} and returns a result.
 376      * @param <T> The type of the result of applying the function to the
 377      *            stream of {@linkplain StackFrame stack frame}.
 378      *
 379      * @return the result of applying the function to the stream of
 380      *         {@linkplain StackFrame stack frame}.
 381      */
 382     @CallerSensitive
 383     public <T> T walk(Function<? super Stream<StackFrame>, ? extends T> function) {
 384         // Returning a Stream<StackFrame> would be unsafe, as the stream could
 385         // be used to access the stack frames in an uncontrolled manner.  For
 386         // example, a caller might pass a Spliterator of stack frames after one
 387         // or more frames had been traversed. There is no robust way to detect
 388         // whether the execution point when
 389         // Spliterator.tryAdvance(java.util.function.Consumer<? super T>) is
 390         // invoked is the exact same execution point where the stack frame
 391         // traversal is expected to resume.
 392 
 393         Objects.requireNonNull(function);
 394         return StackStreamFactory.makeStackTraverser(this, function)
 395                                  .walk();
 396     }
 397 
 398     /**
 399      * Performs the given action on each element of {@code StackFrame} stream
 400      * of the current thread, traversing from the top frame of the stack,
 401      * which is the method calling this {@code forEach} method.
 402      *
 403      * <p> This method is equivalent to calling
 404      * <blockquote>
 405      * {@code walk(s -> { s.forEach(action); return null; });}
 406      * </blockquote>
 407      *
 408      * @param action an action to be performed on each {@code StackFrame}
 409      *               of the stack of the current thread
 410      */
 411     @CallerSensitive
 412     public void forEach(Consumer<? super StackFrame> action) {
 413         Objects.requireNonNull(action);
 414         StackStreamFactory.makeStackTraverser(this, s -> {
 415             s.forEach(action);
 416             return null;
 417         }).walk();
 418     }
 419 
 420     /**
 421      * Gets the {@code Class} object of the caller invoking the method
 422      * that calls this {@code getCallerClass} method.
 423      *
 424      * <p> Reflection frames, {@link java.lang.invoke.MethodHandle} and
 425      * hidden frames are filtered regardless of the
 426      * {@link Option#SHOW_REFLECT_FRAMES SHOW_REFLECT_FRAMES}
 427      * and {@link Option#SHOW_HIDDEN_FRAMES SHOW_HIDDEN_FRAMES} options
 428      * this {@code StackWalker} has been configured.
 429      *
 430      * <p> This method throws {@code UnsupportedOperationException}
 431      * if this {@code StackWalker} is not configured with
 432      * {@link Option#RETAIN_CLASS_REFERENCE RETAIN_CLASS_REFERENCE} option,
 433      * This method should be called when a caller frame is present.  If
 434      * it is called from the last frame on the stack;
 435      * {@code IllegalStateException} will be thrown.
 436      *
 437      * @apiNote
 438      * For example, {@code Util::getResourceBundle} loads a resource bundle
 439      * on behalf of the caller.  It calls this {@code getCallerClass} method
 440      * to find the method calling {@code Util::getResourceBundle} and use the caller's
 441      * class loader to load the resource bundle. The caller class in this example
 442      * is the {@code MyTool} class.
 443      *
 444      * <pre>{@code
 445      * class Util {
 446      *     private final StackWalker walker = StackWalker.getInstance(Option.RETAIN_CLASS_REFERENCE);
 447      *     public ResourceBundle getResourceBundle(String bundleName) {
 448      *         Class<?> caller = walker.getCallerClass();
 449      *         return ResourceBundle.getBundle(bundleName, Locale.getDefault(), caller.getClassLoader());
 450      *     }
 451      * }
 452      *
 453      * class MyTool {
 454      *     private final Util util = new Util();
 455      *     private void init() {
 456      *         ResourceBundle rb = util.getResourceBundle("mybundle");
 457      *     }
 458      * }
 459      * }</pre>
 460      *
 461      * An equivalent way to find the caller class using the
 462      * {@link StackWalker#walk walk} method is as follows
 463      * (filtering the reflection frames, {@code MethodHandle} and hidden frames
 464      * not shown below):
 465      * <pre>{@code
 466      *     Optional<Class<?>> caller = walker.walk(s ->
 467      *         s.map(StackFrame::getDeclaringClass)
 468      *          .skip(2)
 469      *          .findFirst());
 470      * }</pre>
 471      *
 472      * When the {@code getCallerClass} method is called from a method that
 473      * is the last frame on the stack,
 474      * for example, {@code static public void main} method launched by the
 475      * {@code java} launcher or a method invoked from a JNI attached thread.
 476      * {@code IllegalStateException} is thrown.
 477      *
 478      * @return {@code Class} object of the caller's caller invoking this method.
 479      *
 480      * @throws UnsupportedOperationException if this {@code StackWalker}
 481      *         is not configured with {@link Option#RETAIN_CLASS_REFERENCE
 482      *         Option.RETAIN_CLASS_REFERENCE}.
 483      * @throws IllegalStateException if there is no caller frame, i.e.
 484      *         when this {@code getCallerClass} method is called from a method
 485      *         which is the last frame on the stack.
 486      */
 487     @CallerSensitive
 488     public Class<?> getCallerClass() {
 489         if (!options.contains(Option.RETAIN_CLASS_REFERENCE)) {
 490             throw new UnsupportedOperationException("This stack walker " +
 491                     "does not have RETAIN_CLASS_REFERENCE access");
 492         }
 493 
 494         return StackStreamFactory.makeCallerFinder(this).findCaller();
 495     }
 496 
 497     // ---- package access ----
 498     static StackWalker newInstanceNoCheck(EnumSet<Option> options) {
 499         return new StackWalker(options, 0, null);
 500     }
 501 
 502     static StackWalker newInstance(Set<Option> options, ExtendedOption extendedOption) {
 503         checkPermission(options);
 504         return new StackWalker(toEnumSet(options), 0, extendedOption);
 505     }
 506 
 507     int estimateDepth() {
 508         return estimateDepth;
 509     }
 510 
 511     boolean hasOption(Option option) {
 512         return options.contains(option);
 513     }
 514 
 515     boolean hasLocalsOperandsOption() {
 516         return extendedOption == ExtendedOption.LOCALS_AND_OPERANDS;
 517     }
 518 
 519     void ensureAccessEnabled(Option access) {
 520         if (!hasOption(access)) {
 521             throw new UnsupportedOperationException("No access to " + access +
 522                     ": " + options.toString());
 523         }
 524     }
 525 }