RFR: JDK-8253001: [JVMCI] Add API for getting stacktraces independently of current thread

Erik Österlund eosterlund at openjdk.java.net
Thu Sep 24 11:18:55 UTC 2020


On Thu, 24 Sep 2020 08:02:13 GMT, Allan Gregersen <github.com+4676506+javeleon at openjdk.org> wrote:

> A lot of good comments here. Thanks!
> 
> I agree that we should look at the problem domain first. Hence, let's look at the use-cases that was brought up once
> more.
>     1. The Truffle debugger (not to be confused with a Java host debugger) in general needs to access all live stack traces
>     for all guest-language threads and read/write access to local variables.

Right, and these needs should be satisfied by the JVMTI APIs that were designed to do exactly this. Right?

>     2. Some Truffle guest languages need to access all live objects (e.g. Ruby). Espresso also needs this for implementing
>     e.g. getReferringObjects (through the debugger though) etc.

This sounds like a completely different use case. You want to get the stack locals to traverse all objects. But stacks
are only one root set out of many. Keeping the HotSpot root sets in sync outside the VM, across multiple JDK versions,
does not sound like something you want to do unless you really have to. Fortunately, this is yet another wheel that has
already been invented. For example, you can use JVMTI FollowReferences to perform a traversal through the heap from
roots (that we maintain in the VM), and get callbacks for each visited object. You can also use JVMTI
IterateThroughHeap to iterate over the heap and report the objects found with callbacks.

Over the years, there have been many fun interactions with especially (concurrent) reference processing (weak/phantom
references, finalizers, class unloading, which root sets should and should not be included, that constantly changes)
that I really don't think you want to re-discover, by performing yet another heap walk, outside of the VM. I think just
plugging in to this wheel sounds more desirable for this use case. I also don't get how you can even get a snapshot of
live objects, if you allow threads to run concurrently. You mention it is so important to get a snapshot of all thread
locals for this to work the way you want it to. But it's seemingly not just the roots you need a snapshot of, if you
allow the object graph to concurrently mutate. The JVMTI APIs solve all of this. You should be able to just plug in to
that. Right?

> 
> Onto discussing potential solutions:
> 
> After discussing the capabilities of JVMTI internally, it seems that the current implementation of getting locals might
> not be able to return anything for escape-analyzed objects. This obviously poses a serious limitation for Truffle given
> the fact that this is a corner-stone in GraalVM. I take it this played a big role in introducing iterateFrames (current
> thread only) in JVMCI a while back.

The problem you describe is what _jvmti_can_access_local_variables capability is for. A debugger will have this set,
and hence while debugging, we just don't scalarize stuff, so all objects are simply materialized. JVMCI already exposes
this variable and presumably plays by the same rules.

> Even for the debugger case we would need JVMTI to guarantee the following:
> 
>     1. A safe suspension mechanism for all target threads (what if two debuggers are connected at the same time?) that
>     would span the entirety of getAllStackTraces + fetching all locals for all frames. I don't see how something like
>     suspendThreadList would provide the safe guards that we would need here.
> 
>     2. A bulk getAllLocals to avoid fetching all stack traces + retrieving all locals in bulk for all frames.

Let me guess... these requirements you just stated are for getting a stable set of roots for the heap walk you want to
perform outside of the VM? Or is there any other client that needs the snapshotness of the thread dumps? If I'm right,
then there are many more roots that can mutate other than stacks... and the edges in the object graph can also mutate.
How are you going to ensure proper traversal of all objects without injecting GC barriers into mutating accesses? I
think what you really want is an API that can give you a snapshot heap iteration from roots (including stacks but also
a whole bunch of other roots that you really don't want to know about). And JVMTI provides that API, as discussed
above. Let's see if my guessing was right...

> Given that Truffle/GraalVM will continue to support Java 8 for quite some time, this new API should probably be exposed
> through JVMCI and backported like it was done for iterateFrames regardless of the underlying implementation.

Let's continue discussing the problem domain first. Obviously, JVMTI has been around for ages. So let's see what
problems we really have to solve, once our understanding of the problems you try to solve converge.

> Note: In the current PR we need to refactor materializeVirtualObjects into using VM operations to guarantee that we run
> stack walking and sanity checks for locating the frame in question at a safe point. I'll hold my horses a bit on that
> until there is a consensus on where this is going.

I also can't find the definition of some functions and wonder if all files are really in the PR. Seems like they are
not, unless the GUI is bugged out. But let's leave the whole discussion of the code in this PR to a point where we know
what code if any is actually going to change.

Hope this helps. I hope we can start to converge a bit in the problem domain.

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

PR: https://git.openjdk.java.net/jdk/pull/110


More information about the hotspot-compiler-dev mailing list