The details of this approach are explained in "Lazy Continuations for Java Virtual Machines"

Current implementation

Currently the copyStack and resumeStack functions are implemented using:

Problems

This leads to a few problems:

Client compiler implementation

To solve most, if not all, of these issues I propose a continuation implementation where continuation support is built into the client compiler.

The main idea is that continuations can be seen as a list of stack frames up to the start frame of the thread. If multiple continuations are stored as linked lists of stack frames they can be collapsed into a tree structure with the stacks start frame as the ultimate root node.
Combining this with an on-demand approach to creating the continuation frames leads to a very space and time efficient implementation.

(Issue: The term "stack frame object" is misleading; e.g., stack objects in EA are pseudo-objects allocated on stack. Shall we avoid using the word "stack" for heap-resident objects? We could speak of method activation frames on stack or heap.)

We need some data structures to store the continuations:

class Continuation {
  JavaThread thread_affinity;
  StackFrameOop top;
}
class StackFrame {  // or ActivationFrame
  intptr_t sp;
  oop next;
  oop restore_last;
  StackFrameDataOop data;  
}
class StackFrameData {
  oop method;
  u2 bci;
  u2 local_count;
  u2 stack_count;
  u1 tags[];
  ... values[];
}

JavaThread needs to be enhanced with additional fields:

class JavaThread {
  ...
  StackFrameOop _next_stackframe = NULL;
  intptr_t _next_stackframe_sp = +inf;
  intptr_t _next_restore_stackframe_sp = 0;
  ...
}

Continuation::copy() looks like this:

  this.thread = thread;
  this.top = new StackFrame();
  this.top.sp = sp;
  this.top.next = thread._next_stackframe;  // there might already be a Stackframe object that shouldn't be lost...
  thread._next_stackframe = this.top;
  thread._next_stackframe_sp = sp;

Each Callsite in every method that can be contained in a continuation is enhanced with a check:

  <call instruction>
  if thread._next_stackframe_sp < sp jmp continuation_block
  ...
continuation_block:
  thread._next_stackframe.data = new StackFrameData();
  fill thread._next_stackframe.data
  if thread._next_stackframe.next == NULL then
    thread._next_stackframe.next = new StackFrame();
  else
    if thread._next_stackframe.next.sp > sp then
      tmp = new StackFrame();
      tmp.next = thread._next_stackframe.next;
      thread._next_stackframe.next = tmp;
    endif
  endif
  thread._next_stackframe = thread._next_stackframe.next;
  thread._next_stackframe.sp = sp;
  thread._next_stackframe_sp = sp;
  jmp back

What this does:

Resuming continuations

Would be implemented by a similar conditional jump at the beginning of the methods by comparing sp with thread._next_restore_stackframe_sp.
The copy-block would at the end decide if it should destroy the current stackframe immediately.
The resume method traverses the continuation starting with the top stackframe using the "next" links. While doing this it sets the restore_last pointers that can be used to find the way back up while resuming. Continuations are bound to a thread, therefore it's no problem that only one resume-path can be stored in the stackframe tree.

Some advantages:

Possible drawbacks

Further suggestions

This page is work-in-progress!