JDK-6655643 : Some dynamic languages need stack reification
  • Type: Enhancement
  • Component: hotspot
  • Sub-Component: compiler
  • Affected Version: 7,9,10
  • Priority: P4
  • Status: Closed
  • Resolution: Duplicate
  • OS: generic
  • CPU: generic
  • Submitted: 2008-01-27
  • Updated: 2017-02-15
  • Resolved: 2017-02-15
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.
JDK 10
Related Reports
Duplicate :  
Relates :  
https://blogs.oracle.com/jrose/entry/continuations_in_the_vm (forthcoming)

Some important dynamic languages allow programs to inspect the control stack.  (For example, a method might check whether it was invoked by a given caller.)  Such stack inspection requires either that every method take costly steps to record its internal state on the current thread, or else that some sort of debugging mechanism allow the current thread to be inspected on an as-needed basis.  The latter is preferable for performance reasons, much as Hotspot makes few compromises in compiled code quality, and relies on as-needed stack walking or deoptimization to cover the occasional requests for stack information.

Hotspot's stack walking mechanism should be surfaced (somehow) to an API that language implementors can use for stack inspection.  The existing debugger interfaces do this, but they designed for loosely-coupled client processes.  A tightly-coupled access path is needed.

Second use case:  The Scheme language allows a program to form a handle to the future of a thread's execution.  This handle, called a "continuation" is opaque, and does not support inspection, but it does allow the thread's computation to be reset back to the execution state (of the control stack) where the continuation was formed.

Third use case:  Some programming frameworks for Java, notably http://rifers.org/, support continuations as a natural notation for web sessions and other intermittent or restartable processes.  They current do this by transforming Java bytecodes into a stackless format.  There would be less need for bytecode rewriting if the JVM stack did not get in the way, and editable continuations seem the likely native expression in the JVM of such patterns.

A prototype to support these use cases is under construction, based on the pair of unsafe functions copyStack and resumeStack.  See Suggested Fix.

The key object revealed (reified) by the JVM (in CopyStackException.stack) is an array of objects, starting with a byte array of serialized structure information.  (Indexes in the serialization call out to other elements of the object array.)  The format is non-opaque, and allows new JVM stack states to be created from whole cloth, supporting a low-level form of thread mobility.  Previously captured states can be modified, supporting advanced performance tuning or configuration management, as Hotspot does internally at present.

JEP 259: "Stack-Walking API" (JDK-8043814).

SUGGESTED FIX // low-level hook, to be wrapped in one or more safe APIs: class sun.misc.Unsafe; /** * Captures a snapshot of the JVM state, places it into the given exception, * and throws it. The caller may choose to catch it immediately, or let * someone up the call-chain catch it. * <p> * Later on, if the captured JVM state is resumed, the function returns normally, * with whatever value the resumer provides, or (again) throws an exception, * with whatever throwable the resumer provides. This can happen any number of * times. Thus, we distinguish between the initial call to copyStack, * and any number (zero or more) of returns. * <p> * If the context is null, the captured JVM state specifies all frames of * the current thread. Otherwise, the context must correspond to a live * call (in the same thread, not yet returned) to doCopyStackContext. * (Correspondence is determined by reference identity, not Object.equals.) * The captured JVM state then specifies only stack frames which are younger than * that call to doCopyStackContext. It is an error for a resumed computation * to attempt to return to that call to doCopyStackContext. * The context is stored into the supplied CopyStackException, which must * not already have a stored context. (That is, its 'stack' field must be null.) * <p> * Security note: The caller must be privileged, as TBD. * All methods on the stack trace will have an opportunity to * observe the thrown exception, but some may be less-privileged, * and must be prevented from observing the contents of the stack. * <p> * Note: This method must return twice, and so two different execution * paths must be created, either by some sort of data test (e.g., a boolean * or a 2-array with one null element) or by distinguishing normal return * from an exceptional return. This API uses the last option, because * in many use cases (but not all) the copyStack call will be followed by * some sort of suspension of the computation, back to a containing context, * which will only ever be resume by an explicit resumeStack call. */ public native Object copyStack(Object context, CopyStackException ex) throws CopyStackException; /** * Resume a captured snapshot of a JVM state, which is suspended at a call * to copyStack. This call returns normally with the given value, or (if the * exception is not null) by immediately throwing the given exception. * <p> * A captured snapshot may be resumed any number of times, with any combination * of normal and abnormal exits, and in any thread (or many threads, concurrently). * <p> * Note that the stack object must be obtained from inside a CopyStackException. * This is not possible unless copyStack and resumeStack agree on which * subclass of CopyStackException they are using, and if that subclass * grants resumeStack access to its internal 'stack' field. */ public native /*unreached*/ void resumeStack(Object stack, Object value, Throwable exception); /** * Establish a context for any nested calls to copyStack. * The context object is arbitrary; often the expression new Object() works well. * The run method is called. * The only interesting use of this context object is as a non-null argument to copyStack. */ public native void doCopyStackContext(Object context, Runnable r); + /** Exception thrown by an initial call to copyStack. */ public static class CopyStackException extends RuntimeException { /** The JVM state, in an implementation dependent format. */ protected Object stack; }