On Tue, 11 Jul 2023 15:47:35 GMT, Volker Simonis <simo...@openjdk.org> wrote:
>> As the included jtreg test demonstrates, `StackWalker.getCallerClass()` can >> throw an `UnsupportedOperationException` if called reflectively. Currently >> this only happens if we invoke `StackWalker.getCallerClass()` recursively >> reflectively, but this issue will become more prominent once we fix >> [JDK-8285447](https://bugs.openjdk.org/browse/JDK-8285447). The gory details >> follow below: >> >> The protocol between the Java API and the JVM for >> `StackWalker.getCallerClass()/walk()` is as follows: >> - On the Java side, `StackWalker` calls into `StackStreamFactory` for the >> real work. >> - For `StackWalker.getCallerClass()` `StackStreamFactory` basically creates >> a `Class[]` which will be passed down and filled in the JVM. For >> `StackWalker.walk()` it will normally be a `StackFrameInfo[]` (or a >> `LiveStackFrameInfo[]` if the internal `ExtendedOption.LOCALS_AND_OPERANDS` >> option was used). >> - The default size of this arrays is currently >> `StackStreamFactory.SMALL_BATCH` which is 8 (but see >> [JDK-8285447](https://bugs.openjdk.org/browse/JDK-8285447)). >> - `StackStreamFactory` than calls `AbstractStackWalker.callStackWalk()` >> which is a natively implemented in the VM by `JVM_CallStackWalk()`. >> - `JVM_CallStackWalk()` calls `StackWalk::walk()` which calls >> `StackWalk::fetchFirstBatch()` which calls `StackWalk::fill_in_frames()` >> which walks the stack and fills in the available class/stackframe slots in >> the passed in array until the array is full or there are no more stack >> frames, >> - Once `StackWalk::fill_in_frames()` returns, >> `StackWalk::fetchFirstBatch()` calls back to Java by invoking >> `AbstractStackWalker::doStackWalk()` to consume the result. >> - `AbstractStackWalker::doStackWalk()` calls `consumeFrames()` (which is >> overridden depending on whether we initially called `getCallerClass()` or >> `walk()`) which consumes the frames until it either finishes (e.g. finds the >> caller class) or until there are no more frames. >> - In the latter case `consumeFrames()` will call into the the VM again by >> calling `AbstractStackWalker.fetchStackFrames()` to fetch additional frames >> from the stack. >> - `AbstractStackWalker.fetchStackFrames()` is implemented by >> `JVM_MoreStackWalk()` which calls `StackWalk::fetchNextBatch()` which calls >> `StackWalk::fill_in_frames()` (the same method that already fetched the >> initial batch of frames). >> >> Following is a stacktrace of what I've explained so far: >> >> Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native >> code) >> V [libjvm.so+0x1... > > Volker Simonis has updated the pull request incrementally with one additional > commit since the last revision: > > Fixed case when calling getCallerClass() from a @CallerSensitive method > reflectively src/hotspot/share/prims/stackwalk.cpp line 164: > 162: method->method_holder()->is_subtype_of(constructor_accessor) || > 163: // MethodHandle frames are not hidden and > StackWalker::getCallerClass has to filter them out > 164: method->method_holder()->name()->starts_with("java/lang/invoke")); Shouldn’t this be: Suggestion: method->method_holder()->name()->starts_with("java/lang/invoke/")); ------------- PR Review Comment: https://git.openjdk.org/jdk/pull/14773#discussion_r1263467101