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

Doug Simon dnsimon at openjdk.java.net
Wed Sep 23 19:31:37 UTC 2020


On Wed, 23 Sep 2020 18:54:33 GMT, Erik Österlund <eosterlund at openjdk.org> wrote:

>> Tuning in to provide some background on why Truffle needs this and why we spent a lot of time to stabilize this PR. If
>> we could have gone a different route we would have.
>> Truffle introduces the separation of guest and host language. As host language, we understand the Java host VM. This is
>> either HotSpot (relevant for this PR) or SubstrateVM (Native Image). Guest languages are interpreters implemented on
>> top of Truffle, like JavaScript, Ruby, or Python, but also Espresso our Java implementation based on Truffle. Truffle
>> uses Graal and JVMCI to optimize these guest languages to optimized machine code using a technique called the first
>> Futamura projection. This Graal compilation is limited to JDKs that provide JVMCI APIs.  In Truffle we use the notion
>> of guest and host stack frames. Guest stack frames represent a method activation in the guest language and host stack
>> frames represent host Java method activations. A guest stack frame consists of the caller location  and guest local
>> variables.  Truffle languages need to access guest frames of the current thread to construct a stack trace or to lazily
>> access variables in a parent guest frame. There are two techniques to do this: 1. Have a separate stack data structure
>> on the heap that keeps track of the guest frames for each thread. 2. Walk the live local variables in Java host frames
>> to access the guest frame and caller location.  We use the technique (1) to implement Truffle guest stack traces on a
>> JVM without JVMCI support. This is pretty simple and allows us to walk the guest stack for any thread we need. But,
>> there are downsides with this:
>> * For each method invocation we have additional overhead for maintaining the extra heap data structure.
>> * The frame object always escapes the current compilation scope and can therefore not be escape analyzed by Graal.
>> 
>> Both of these issues are deal-breakers, performance-wise. With Truffle we want to be competitive with other specialized
>> VMs, so technique (1) is not good enough. JVMCI currently exposes stack walking APIs for Truffle that allows us to
>> access the host frame local variables of the current thread. This allows us to lazily reconstruct the guest frames from
>> the host frames from certain known and live local variables. We also have special logic to reconstruct read-only guest
>> frames from optimized Truffle+Graal compiled methods without the need to invalidate the optimized code.  We are using
>> the technique (2) successfully for many years, but now with the growing maturity of Truffle we have new requirements:
>> 1. We need to be able to walk all the root pointers of a guest language. This includes all active guest frames. This is
>> needed to allow languages to walk all live objects (e.g. Ruby needs that) and to compute the size of the live objects
>> of a truffle language. 2. We need to be able to read locals from other threads to produce the guest stack trace of
>> other threads in the Truffle debugger.  This was not a big issue before, because we were mostly dealing with
>> single-threaded languages (JavaScript).  The Truffle debugger should not be confused with the Java host debugger. The
>> Truffle debugger works based on the Truffle instrumentation framework and cannot debug Java host code. It only shows
>> guest stack frames and statements and is entirely agnostic to which Java methods were used to implement it and on which
>> Java VM it runs on. It is entirely built with Java, without the use of JVMTI, this allows us to debug guest code
>> without having the Java debugger attached. It allows us to on-demand enable debugging in a production scenario when it
>> is needed and only for a guest language instance that needs it without slowing down other code in host VM (e.g. in an
>> app server). Truffle debugging works on SubstrateVM (native-image) which has currently no support for JVMTI. Enabling
>> and not using the debugger also comes without any peak performance overhead (some memory and warmup overhead).  To
>> summarize: 1. We cannot use the StackWalker API as it does not allow us to access local variables. 2. We cannot
>> manually allocate extra objects for guest language frames, as this would hurt performance. 3. We cannot use JVMTI
>> because: 3a. We need it to implement language features, not just debugger features. 3b. There is no way to enable it on
>> demand for an individual guest application (we run multiple guest applications per host VM).  3c. There is no Java API
>> that allows it be used in the same process.  Therefore our best idea was to introduce this new JVMCI API. We are of
>> course open to other suggestions, if they solve our problem. This is also not an entirely new feature, this PR is an
>> extension to the existing JVMCI functionality to walk the stack frames with local variable access.  I hope these
>> clarifications were helpful.
>
> java.lang.StackWalker does expose locals as well. What am I missing?

It seems as though the `java.lang.LiveStackFrame` and `java.lang.LiveStackFrameInfo` classes are not public. However,
it may indeed provide what's needed for the Truffle use cases. Do you know how/where this internal interface is used
currently? In any case, the Truffle team will investigate further before coming back to this pull request. Thanks for
bringing up what may be a much simpler solution @fisk .

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

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


More information about the hotspot-compiler-dev mailing list