RFR: 8268829: Provide an optimized way to walk the stack with Class object only [v6]

Rémi Forax forax at openjdk.org
Sat Aug 26 09:45:23 UTC 2023


On Fri, 25 Aug 2023 22:22:43 GMT, Mandy Chung <mchung at openjdk.org> wrote:

>> 8268829: Provide an optimized way to walk the stack with Class object only
>> 
>> `StackWalker::walk` creates one `StackFrame` per frame and the current implementation
>> allocates one `StackFrameInfo` and one `MemberName` objects per frame. Some frameworks
>> like logging may only interest in the Class object but not the method name nor the BCI,
>> for example, filters out its implementation classes to find the caller class.  It's
>> similar to `StackWalker::getCallerClass` but allows a predicate to filter out the element.
>> 
>> This PR proposes to add `StackWalker.Kind` enum to specify the information that a stack walker
>> collects.  If no method information is needed, a `StackWalker` of `CLASS_INFO` can be used
>> instead and such stack walker will save the overhead (1) to extract the method information
>> and (2) the memory used for the stack walking.   In addition, this can also fix
>> 
>> - [8311500](https://bugs.openjdk.org/browse/JDK-8311500): StackWalker.getCallerClass() throws UOE if invoked reflectively
>> 
>> New factory methods to take a parameter to specify the kind of stack walker to be created are defined.
>> This provides a simple way for existing code, for example logging frameworks, to take advantage of
>> this enhancement with the least change as it can keep the existing function for traversing
>> `StackFrame`s.
>> 
>> For example: to find the first caller filtering a known list of implementation class,
>> existing code can call `StackWalker::getInstance(CLASS_INFO, ...)` to create a stack walker instance:
>> 
>> 
>>      StackWalker walker = StackWalker.getInstance(Kind.CLASS_INFO, Option.RETAIN_CLASS_REFERENCE);
>>      Optional<Class<?>> callerClass = walker.walk(s ->
>>              s.map(StackFrame::getDeclaringClass)
>>               .filter(interestingClasses::contains)
>>               .findFirst());
>> 
>> 
>> If method information is accessed on the `StackFrame`s produced by this stack walker such as
>> `StackFrame::getMethodName`, then `UnsupportedOperationException` will be thrown.
>> 
>> #### Javadoc & specdiff
>> 
>> https://cr.openjdk.org/~mchung/api/java.base/java/lang/StackWalker.html
>> https://cr.openjdk.org/~mchung/jdk22/specdiff/overview-summary.html
>> 
>> #### Alternatives Considered
>> One alternative is to provide a new API:
>> `<T> T walkClass(Function<? super Stream<Class<?>, ? extends T> function)`
>> 
>> In this case, the caller would need to pass a function that takes a stream
>> of `Class` object instead of `StackFrame`.  Existing code would hav...
>
> Mandy Chung has updated the pull request incrementally with two additional commits since the last revision:
> 
>  - fixup javadoc
>  - Review feedback: move JLIA to ClassFrameInfo

src/java.base/share/classes/java/lang/StackWalker.java line 81:

> 79:  *     Optional<Class<?>> callerClass = walker.walk(s ->
> 80:  *             s.map(StackFrame::getDeclaringClass)
> 81:  *              .filter(interestingClasses::contains)

Usually it's more `.filter(Predicate.not(implClasses::contains))`

src/java.base/share/classes/java/lang/StackWalker.java line 88:

> 86:  * {@snippet lang="java" :
> 87:  *     List<StackFrame> stack = StackWalker.getInstance().walk(s ->
> 88:  *             s.limit(10).collect(Collectors.toList()));

`s.limit(10).toList()`

src/java.base/share/classes/java/lang/StackWalker.java line 505:

> 503:      */
> 504:     public static StackWalker getInstance(Kind kind, Option... options) {
> 505:         return getInstance(Objects.requireNonNull(kind), Set.of(Objects.requireNonNull(options)));

Set.of() already does a NPE check

src/java.base/share/classes/java/lang/StackWalker.java line 649:

> 647:      *         s.dropWhile(f -> f.getClassName().startsWith("com.foo."))
> 648:      *          .limit(10)
> 649:      *          .collect(Collectors.toList()));

`.toList())`

-------------

PR Review Comment: https://git.openjdk.org/jdk/pull/15370#discussion_r1306390180
PR Review Comment: https://git.openjdk.org/jdk/pull/15370#discussion_r1306390266
PR Review Comment: https://git.openjdk.org/jdk/pull/15370#discussion_r1306390553
PR Review Comment: https://git.openjdk.org/jdk/pull/15370#discussion_r1306390713


More information about the core-libs-dev mailing list