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> A {@code StackWalker} object can be used to do multiple stack walks.
  56  * A permission check is performed when a {@code StackWalker} is created,
  57  * according to the options it requests.
  58  * No further permission check is done at stack walking time.
  59  *
  60  * @apiNote
  61  * Examples
  62  *
  63  * <p>1. To find the first caller filtering a known list of implementation class:
  64  * <pre>{@code
  65  *     StackWalker walker = StackWalker.create(Option.RETAIN_CLASS_REFERENCE);
  66  *     Optional<Class<?>> callerClass = walker.walk(s ->
  67  *         s.map(StackFrame::getDeclaringClass)
  68  *          .filter(interestingClasses::contains)
  69  *          .findFirst());
  70  * }</pre>
  71  *
  72  * <p>2. To snapshot the top 10 stack frames of the current thread,
  73  * <pre>{@code
  74  *     List<StackFrame> stack = StackWalker.create().walk(s ->
  75  *         s.limit(10).collect(Collectors.toList()));
  76  * }</pre>
  77  *
  78  * Unless otherwise noted, passing a {@code null} argument to a
  79  * constructor or method in this {@code StackWalker} class
  80  * will cause a {@link NullPointerException NullPointerException}
  81  * to be thrown.
  82  *
  83  * @since 1.9
  84  */
  85 public final class StackWalker {
  86     /**
  87      * A {@code StackFrame} object represents a method invocation returned by
  88      * {@link StackWalker}.
  89      *
  90      * <p> The {@link #getDeclaringClass()} method may be unsupported as determined
  91      * by the {@linkplain Option stack walking options} of a {@linkplain
  92      * StackWalker stack walker}.
  93      *
  94      * @since 1.9
  95      * @jvms 2.6
  96      */
  97     public static interface StackFrame {
  98         /**
  99          * Gets the <a href="ClassLoader.html#name">binary name</a>
 100          * of the declaring class of the method represented by this stack frame.
 101          *
 102          * @return the binary name of the method represented
 103          *         by this stack frame
 104          *
 105          * @jls 13.1 The Form of a Binary
 106          */
 107         public String getClassName();
 108 
 109         /**
 110          * Gets the name of the method represented by this stack frame.
 111          * @return the name of the method represented by this stack frame
 112          */
 113         public String getMethodName();
 114 
 115         /**
 116          * Gets the declaring {@code Class} for the method represented by
 117          * this stack frame.
 118          *
 119          * @return the declaring {@code Class} of the method represented by
 120          * this stack frame
 121          *
 122          * @throws UnsupportedOperationException if this {@code StackWalker}
 123          *         is not configured with {@link Option#RETAIN_CLASS_REFERENCE
 124          *         Option.RETAIN_CLASS_REFERENCE}.
 125          */
 126         public Class<?> getDeclaringClass();
 127 
 128         /**
 129          * Returns the name of the source file containing the execution point
 130          * represented by this stack frame.  Generally, this corresponds
 131          * to the {@code SourceFile} attribute of the relevant {@code class}
 132          * file as defined by <cite>The Java Virtual Machine Specification</cite>.
 133          * In some systems, the name may refer to some source code unit
 134          * other than a file, such as an entry in a source repository.
 135          *
 136          * @return the name of the file containing the execution point
 137          *         represented by this stack frame, or empty {@code Optional}
 138          *         is unavailable.
 139          *
 140          * @jvms 4.7.10 The {@code SourceFile} Attribute
 141          */
 142         public Optional<String> getFileName();
 143 
 144         /**
 145          * Returns the line number of the source line containing the execution
 146          * point represented by this stack frame.  Generally, this is
 147          * derived from the {@code LineNumberTable} attribute of the relevant
 148          * {@code class} file as defined by <cite>The Java Virtual Machine
 149          * Specification</cite>.
 150          *
 151          * @return the line number of the source line containing the execution
 152          *         point represented by this stack frame, or empty
 153          *         {@code Optional} if this information is unavailable.
 154          *
 155          * @jvms 4.7.12 The {@code LineNumberTable} Attribute
 156          */
 157         public OptionalInt getLineNumber();
 158 
 159         /**
 160          * Returns {@code true} if the method containing the execution point
 161          * represented by this stack frame is a native method.
 162          *
 163          * @return {@code true} if the method containing the execution point
 164          *         represented by this stack frame is a native method.
 165          */
 166         public boolean isNativeMethod();
 167 
 168         /**
 169          * Gets a {@code StackTraceElement} for this stack frame.
 170          *
 171          * @return {@code StackTraceElement} for this stack frame.
 172          *
 173          * */
 174         public default StackTraceElement toStackTraceElement() {
 175             return new StackTraceElement(getClassName(), getMethodName(),
 176                                          getFileName().orElse(null),
 177                                          getLineNumber().orElse(-1));
 178         }
 179     }
 180 
 181     /**
 182      * Stack walker option to configure the {@linkplain StackFrame stack frame}
 183      * information obtained by a {@code StackWalker}.
 184      *
 185      * @since 1.9
 186      */
 187     public enum Option {
 188         /**
 189          * Retains {@code Class} object in {@code StackFrame}s
 190          * walked by this {@code StackWalker}.
 191          *
 192          * <p> A {@code StackWalker} configured with this option will support
 193          * {@link StackWalker#getCallerClass()} and
 194          * {@link StackFrame#getDeclaringClass() StackFrame.getDeclaringClass()}.
 195          */
 196         RETAIN_CLASS_REFERENCE,
 197         /**
 198          * Shows all reflection frames.
 199          *
 200          * <p>By default, reflection frames are hidden.  This includes the
 201          * {@link java.lang.reflect.Method#invoke} method
 202          * and the reflection implementation classes. A {@code StackWalker} with
 203          * this {@code SHOW_REFLECT_FRAMES} option will show all reflection frames.
 204          * The {@link #SHOW_HIDDEN_FRAMES} option can also be used to show all
 205          * reflection frames and it will also show other hidden frames that
 206          * are implementation-specific.
 207          */
 208         SHOW_REFLECT_FRAMES,
 209         /**
 210          * Shows all hidden frames.
 211          *
 212          * <p>A Java Virtual Machine implementation may hide implementation
 213          * specific frames in addition to {@linkplain #SHOW_REFLECT_FRAMES
 214          * reflection frames}. A {@code StackWalker} with this {@code SHOW_HIDDEN_FRAMES}
 215          * option will show all hidden frames (including reflection frames).
 216          */
 217         SHOW_HIDDEN_FRAMES;
 218     }
 219 
 220     enum ExtendedOption {
 221         /**
 222          * Obtain locals and operands.
 223          */
 224         LOCALS_AND_OPERANDS
 225     };
 226 
 227     static final EnumSet<Option> DEFAULT_EMPTY_OPTION = EnumSet.noneOf(Option.class);
 228 
 229     private static StackWalker DEFAULT_WALKER =
 230         new StackWalker(DEFAULT_EMPTY_OPTION);
 231 
 232     private final Set<Option> options;
 233     private final ExtendedOption extendedOption;
 234     private final int estimateDepth;
 235 
 236     /**
 237      * Creates a {@code StackWalker} instance.
 238      *
 239      * <p> This {@code StackWalker} is configured to skip all
 240      * {@linkplain Option#SHOW_HIDDEN_FRAMES hidden frames} and
 241      * no {@linkplain Option#RETAIN_CLASS_REFERENCE class reference} is retained.
 242      *
 243      * @return a {@code StackWalker} configured to skip all
 244      * {@linkplain Option#SHOW_HIDDEN_FRAMES hidden frames} and
 245      * no {@linkplain Option#RETAIN_CLASS_REFERENCE class reference} is retained.
 246      *
 247      */
 248     public static StackWalker create() {
 249         // no permission check needed
 250         return DEFAULT_WALKER;
 251     }
 252 
 253     /**
 254      * Creates a {@code StackWalker} instance with the given option specifying
 255      * the stack frame information it can access.
 256      *
 257      * <p>
 258      * If a security manager is present and the given {@code option} is
 259      * {@link Option#RETAIN_CLASS_REFERENCE Option.RETAIN_CLASS_REFERENCE},
 260      * it calls its {@link SecurityManager#checkPermission checkPermission}
 261      * method for {@code StackFramePermission("retainClassReference")}.
 262      *
 263      * @param option {@link Option stack walking option}
 264      *
 265      * @return a {@code StackWalker} configured with the given option
 266      *
 267      * @throws SecurityException if a security manager exists and its
 268      *         {@code checkPermission} method denies access.
 269      */
 270     public static StackWalker create(Option option) {
 271         return create(EnumSet.of(Objects.requireNonNull(option)));
 272     }
 273 
 274     /**
 275      * Creates a {@code StackWalker} instance with the given {@ocde options} specifying
 276      * the stack frame information it can access.  If the given {@ocde options}
 277      * is empty, this {@code StackWalker} is configured to skip all
 278      * {@linkplain Option#SHOW_HIDDEN_FRAMES hidden frames} and no
 279      * {@linkplain Option#RETAIN_CLASS_REFERENCE class reference} is retained.
 280      *
 281      * <p>
 282      * If a security manager is present and the given {@code option} is
 283      * {@link Option#RETAIN_CLASS_REFERENCE Option.RETAIN_CLASS_REFERENCE},
 284      * it calls its {@link SecurityManager#checkPermission checkPermission}
 285      * method for {@code StackFramePermission("retainClassReference")}.
 286      *
 287      * @param options {@link Option stack walking option}
 288      *
 289      * @return a {@code StackWalker} configured with the given options
 290      *
 291      * @throws SecurityException if a security manager exists and its
 292      *         {@code checkPermission} method denies access.
 293      */
 294     public static StackWalker create(Set<Option> options) {
 295         if (options.isEmpty()) {
 296             return DEFAULT_WALKER;
 297         }
 298 
 299         checkPermission(options);
 300         return new StackWalker(toEnumSet(options));
 301     }
 302 
 303     /**
 304      * Creates a {@code StackWalker} instance with the given {@ocde options} specifying
 305      * the stack frame information it can access. If the given {@ocde options}
 306      * is empty, this {@code StackWalker} is configured to skip all
 307      * {@linkplain Option#SHOW_HIDDEN_FRAMES hidden frames} and no
 308      * {@linkplain Option#RETAIN_CLASS_REFERENCE class reference} is retained.
 309      *
 310      * <p>
 311      * If a security manager is present and the given {@code option} is
 312      * {@link Option#RETAIN_CLASS_REFERENCE Option.RETAIN_CLASS_REFERENCE},
 313      * it calls its {@link SecurityManager#checkPermission checkPermission}
 314      * method for {@code StackFramePermission("retainClassReference")}.
 315      *
 316      * <p>
 317      * The {@code estimateDepth} specifies the estimate number of stack frames
 318      * this {@code StackWalker} will traverse that the {@code StackWalker} could
 319      * use as a hint for the buffer size.
 320      *
 321      * @param options {@link Option stack walking options}
 322      * @param estimateDepth Estimate number of stack frames to be traversed.
 323      *
 324      * @return a {@code StackWalker} configured with the given options
 325      *
 326      * @throws IllegalArgumentException if {@code estimateDepth <= 0}
 327      * @throws SecurityException if a security manager exists and its
 328      *         {@code checkPermission} method denies access.
 329      */
 330     public static StackWalker create(Set<Option> options, int estimateDepth) {
 331         if (estimateDepth <= 0) {
 332             throw new IllegalArgumentException("estimateDepth must be > 0");
 333         }
 334         checkPermission(options);
 335         return new StackWalker(toEnumSet(options), estimateDepth);
 336     }
 337 
 338     /**
 339      * TO BE REMOVED
 340      */
 341     private int maxDepth = 1024;
 342     int maxDepth() {
 343         return maxDepth;
 344     }
 345 
 346     /**
 347      * TO BE REMOVED
 348      *
 349      * @param maxDepth Maximum number of stack frames to be traversed.
 350      * @param options {@link Option stack walking options}
 351      */
 352     public StackWalker(int maxDepth, Set<Option> options) {
 353         if (maxDepth <= 0) {
 354             throw new IllegalArgumentException("maxDepth must be > 0");
 355         }
 356         checkPermission(options);
 357         this.options = options;
 358         this.estimateDepth = 0;
 359         this.maxDepth = maxDepth;
 360         this.extendedOption = null;
 361     }
 362 
 363     // ----- private constructors ------
 364     private StackWalker(EnumSet<Option> options) {
 365         this(options, 0, null);
 366     }
 367     private StackWalker(EnumSet<Option> options, int estimateDepth) {
 368         this(options, estimateDepth, null);
 369     }
 370     private StackWalker(EnumSet<Option> options, int estimateDepth, ExtendedOption extendedOption) {
 371         this.options = options;
 372         this.estimateDepth = estimateDepth;
 373         this.extendedOption = extendedOption;
 374     }
 375 
 376     private static void checkPermission(Set<Option> options) {
 377         Objects.requireNonNull(options);
 378         SecurityManager sm = System.getSecurityManager();
 379         if (sm != null) {
 380             if (options.contains(Option.RETAIN_CLASS_REFERENCE)) {
 381                 sm.checkPermission(new StackFramePermission("retainClassReference"));
 382             }
 383         }
 384     }
 385 
 386     /*
 387      * Returns a defensive copy
 388      */
 389     private static EnumSet<Option> toEnumSet(Set<Option> options) {
 390         Objects.requireNonNull(options);
 391         if (options.isEmpty()) {
 392             return DEFAULT_EMPTY_OPTION;
 393         } else {
 394             return EnumSet.copyOf(options);
 395         }
 396     }
 397 
 398     /**
 399      * Applies the given function to the stream of {@code StackFrame}s
 400      * for the current thread, traversing from the top frame of the stack,
 401      * which is the method calling this {@code walk} method.
 402      *
 403      * <p>The {@code StackFrame} stream will be closed when
 404      * this method returns.  When a closed {@code Stream<StackFrame>} object
 405      * is reused, {@code IllegalStateException} will be thrown.
 406      *
 407      * @apiNote
 408      * For example, to find the first 10 calling frames, first skipping those frames
 409      * whose declaring class is in package {@code com.foo}:
 410      * <blockquote>
 411      * <pre>{@code
 412      * List<StackFrame> frames = StackWalker.create().walk(s ->
 413      *     s.dropWhile(f -> f.getClassName().startsWith("com.foo."))
 414      *      .limit(10)
 415      *      .collect(Collectors.toList()));
 416      * }</pre></blockquote>
 417      *
 418      * <p>This method takes a {@code Function} accepting a {@code Stream<StackFrame>},
 419      * rather than returning a {@code Stream<StackFrame>} and allowing the
 420      * caller to directly manipulate the stream. The Java virtual machine is
 421      * free to reorganize a thread's control stack, for example, via
 422      * deoptimization. By taking a {@code Function} parameter, this method
 423      * allows access to stack frames through a stable view of a thread's control
 424      * stack.
 425      *
 426      * <p>Parallel execution is effectively disabled and stream pipeline
 427      * execution will only occur on the current thread.
 428      *
 429      * @implNote The implementation stabilizes the stack by anchoring a frame
 430      * specific to the stack walking and ensures that the stack walking is
 431      * performed above the anchored frame. When the stream object is closed or
 432      * being reused, {@code IllegalStateException} will be thrown.
 433      *
 434      * @param function a function that takes a stream of
 435      *                 {@linkplain StackFrame stack frames} and returns a result.
 436      * @param <T> The type of the result of applying the function to the
 437      *            stream of {@linkplain StackFrame stack frame}.
 438      *
 439      * @return the result of applying the function to the stream of
 440      *         {@linkplain StackFrame stack frame}.
 441      */
 442     @CallerSensitive
 443     public <T> T walk(Function<? super Stream<StackFrame>, ? extends T> function) {
 444         // Returning a Stream<StackFrame> would be unsafe, as the stream could
 445         // be used to access the stack frames in an uncontrolled manner.  For
 446         // example, a caller might pass a Spliterator of stack frames after one
 447         // or more frames had been traversed. There is no robust way to detect
 448         // whether the execution point when
 449         // Spliterator.tryAdvance(java.util.function.Consumer<? super T>) is
 450         // invoked is the exact same execution point where the stack frame
 451         // traversal is expected to resume.
 452 
 453         Objects.requireNonNull(function);
 454         return StackStreamFactory.makeStackTraverser(this, function)
 455                                  .walk();
 456     }
 457 
 458     /**
 459      * Performs the given action on each element of {@code StackFrame} stream
 460      * of the current thread, traversing from the top frame of the stack,
 461      * which is the method calling this {@code forEach} method.
 462      *
 463      * <p> This method is equivalent to calling
 464      * <blockquote>
 465      * {@code walk(s -> { s.forEach(action); return null; });}
 466      * </blockquote>
 467      *
 468      * @param action an action to be performed on each {@code StackFrame}
 469      *               of the stack of the current thread
 470      */
 471     @CallerSensitive
 472     public void forEach(Consumer<? super StackFrame> action) {
 473         Objects.requireNonNull(action);
 474         StackStreamFactory.makeStackTraverser(this, s -> {
 475             s.forEach(action);
 476             return null;
 477         }).walk();
 478     }
 479 
 480     /**
 481      *
 482      * Gets the {@code Class} object of the caller invoking the method
 483      * that calls this {@code getCallerClass} method, if present; otherwise,
 484      * this method returns an empty {@code Optional}.
 485      * This is equivalent to calling
 486      * <pre>{@code
 487      *     walk(s -> s.map(StackFrame::getDeclaringClass)
 488      *                .skip(2)
 489      *                .findFirst());
 490      * }</pre>
 491      *
 492      * @apiNote
 493      * For example, {@code ResourceBundleUtil::getBundle} loads a resource bundle
 494      * on behalf of the caller.  It calls this {@code getCallerClass} method
 495      * to find the method calling {@code Util::getResourceBundle} and use the caller's
 496      * class loader to load the resource bundle. The caller class in this example
 497      * is the {@code MyTool} class.
 498      *
 499      * <pre>{@code
 500      *     class ResourceBundleUtil {
 501      *         private final StackWalker walker = new StackWalker(EnumSet.of(Option.RETAIN_CLASS_REFERENCE));
 502      *         public ResourceBundle getBundle(String bundleName) {
 503      *             Class<?> caller = walker.getCallerClass();
 504      *             return ResourceBundle.getBundle(bundleName, caller.getClassLoader());
 505      *         }
 506      *     }
 507      *
 508      *     class MyTool {
 509      *         private void init() {
 510      *             ResourceBundle rb = Util.getResourceBundle("mybundle");
 511      *         }
 512      *     }
 513      * }</pre>
 514      *
 515      * <p> If this {@code getCallerClass} method is called by the last frame
 516      * on the stack, for example when this {@code getCallerClass} method is
 517      * invoked from the {@code static main} entry point or
 518      * a method called from a JNI attached thread, this method returns
 519      * an empty {@code Optional} since the caller's class is not found.
 520      *
 521      * @return {@code Class} object of the caller's caller invoking this method;
 522      * or an empty {@code Optional} if the caller's caller is not present.
 523      *
 524      * @throws UnsupportedOperationException if this {@code StackWalker}
 525      *         is not configured with {@link Option#RETAIN_CLASS_REFERENCE
 526      *         Option.RETAIN_CLASS_REFERENCE}.
 527      */
 528     @CallerSensitive
 529     public Optional<Class<?>> getCallerClass() {
 530         if (!options.contains(Option.RETAIN_CLASS_REFERENCE)) {
 531             throw new UnsupportedOperationException("This stack walker " +
 532                     "does not have RETAIN_CLASS_REFERENCE access");
 533         }
 534 
 535         return StackStreamFactory.makeCallerFinder(this).findCaller();
 536     }
 537 
 538     // ---- package access ----
 539     static StackWalker newInstanceNoCheck(EnumSet<Option> options) {
 540         return new StackWalker(options, 0, null);
 541     }
 542 
 543     static StackWalker newInstance(Set<Option> options, ExtendedOption extendedOption) {
 544         checkPermission(options);
 545         return new StackWalker(toEnumSet(options), 0, extendedOption);
 546     }
 547 
 548     int estimateDepth() {
 549         return estimateDepth;
 550     }
 551 
 552     boolean hasOption(Option option) {
 553         return options.contains(option);
 554     }
 555 
 556     boolean hasLocalsOperandsOption() {
 557         return extendedOption == ExtendedOption.LOCALS_AND_OPERANDS;
 558     }
 559 
 560     void ensureAccessEnabled(Option access) {
 561         if (!hasOption(access)) {
 562             throw new UnsupportedOperationException("No access to " + access +
 563                     ": " + options.toString());
 564         }
 565     }
 566 }