JDK-8214585 : LiveStackFrameInfo.getLocals does not materialize virtual objects
  • Type: Enhancement
  • Component: core-libs
  • Sub-Component: java.lang
  • Affected Version: 11,12
  • Priority: P3
  • Status: Open
  • Resolution: Unresolved
  • Submitted: 2018-12-02
  • Updated: 2019-08-20
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other
tbdUnresolved
Related Reports
Blocks :  
Relates :  
Relates :  
Relates :  
Description
LiveStackFrameInfo.getLocals returns null for virtual objects (the JIT compiler has eliminated a "non-escaping" allocation).  There should be a way to recognize and materialize these virtual objects.  For example, see jdk.vm.ci.hotspot.HotSpotStackFrameReference.
materializeVirtualObjects.

Test attached.
Comments
Materializing may not be enough if the caller expects object identity (==) to work, because the JIT compiler can assume that a non-escaping object != an escaping object. The getLocals() API spec probably needs to address this somehow, even if it means materializing a unique object every time and not preserving object identity.
04-12-2018

> `LiveStackFrame::getLocals` specifies that the returned array may contain null entries for local variables that are not > live. Perhaps it could return a non-null object that represents non-live local that JIT has optimized away. In this case, the local is live but "virtual". The reachabilityFence() keeps it live. The allocation has been eliminated, but it will be reallocated ("materialized") if the method is deoptimized and run in the interpeter. The javadocs doesn't seem to cover the live-but-virtual case. > Either the materialize method or annotation requires source level change that is not an ideal user model. I agree in general, but could be useful for system code, in particular doPrivileged. > An alternative may be a JVM option to specify the methods for JIT to materialize. Do you mean a command-line option? I think it would be possible to lazily materialize when getLocals is called. That would be covered by JDK-8214584.
04-12-2018

`LiveStackFrame::getLocals` specifies that the returned array may contain null entries for local variables that are not live. Perhaps it could return a non-null object that represents non-live local that JIT has optimized away. Either the materialize method or annotation requires source level change that is not an ideal user model. An alternative may be a JVM option to specify the methods for JIT to materialize.
04-12-2018

I have attached a test case (StackWalkTest9.java) that can be compiled and run standalone, back through JDK 9. The test's AssertionError: Exception in thread "main" java.lang.AssertionError: bad frame local null at iteration 15999 at StackWalkTest9.check(StackWalkTest9.java:48) at StackWalkTest9.go(StackWalkTest9.java:55) at StackWalkTest9.main(StackWalkTest9.java:62) is thrown in JDK 12 and JDK 11. Interestingly, it is not thrown in JDK 10 or 9.
04-12-2018

Instead of making getLocals() work for any arbitrary frame, we could provide a way for a particular frame to make its values visible to a stackwalk. Maybe something like class LiveStackFrameInfo { @HotspotIntrinsicCandidate static void materialize(Object value); // Tell JIT compiler that this value escapes, materialize } In the test case, it would look like: static void go(int count) { String hi = new String("hi"); if ((count % 1000) == 999) { LiveStackFrameInfo.materialize(hi); check(count); } Reference.reachabilityFence(hi); } or alternatively, with an annotation: static void go(int count) { @Escapes // or @StackWalkable ? String hi = new String("hi"); if ((count % 1000) == 999) { check(count); } Reference.reachabilityFence(hi); }
03-12-2018