changeset 496:b4050524c2ff

coro: updated patch, new coro-simple version
author Lukas Stadler <lukas.stadler@jku.at>
date Thu, 26 Jul 2012 17:10:47 +0200
parents b078b2c12089
children 3bd88fb254b4
files coro-meth.patch coro-simple.patch coro-standalone.patch coro.patch series
diffstat 5 files changed, 2172 insertions(+), 571 deletions(-) [+]
line wrap: on
line diff
--- a/coro-meth.patch	Mon Jul 23 10:36:37 2012 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,183 +0,0 @@
-diff --git a/src/cpu/x86/vm/frame_x86.cpp b/src/cpu/x86/vm/frame_x86.cpp
---- a/src/cpu/x86/vm/frame_x86.cpp
-+++ b/src/cpu/x86/vm/frame_x86.cpp
-@@ -305,7 +305,8 @@
- }
- 
- BasicObjectLock* frame::interpreter_frame_monitor_end() const {
--  BasicObjectLock* result = (BasicObjectLock*) *addr_at(interpreter_frame_monitor_block_top_offset);
-+  intptr_t* original = *(intptr_t**)addr_at(interpreter_frame_monitor_block_top_offset);
-+  BasicObjectLock* result = (BasicObjectLock*) (original + _displacement);
-   // make sure the pointer points inside the frame
-   assert(sp() <= (intptr_t*) result, "monitor end should be above the stack pointer");
-   assert((intptr_t*) result < fp(),  "monitor end should be strictly below the frame pointer");
-@@ -418,7 +419,7 @@
-   intptr_t* sender_sp = this->sender_sp();
- 
-   // This is the sp before any possible extension (adapter/locals).
--  intptr_t* unextended_sp = interpreter_frame_sender_sp();
-+  intptr_t* unextended_sp = interpreter_frame_sender_sp() + _displacement;
- 
- #ifdef COMPILER2
-   if (map->update_map()) {
-@@ -426,7 +427,7 @@
-   }
- #endif // COMPILER2
- 
--  return frame(sender_sp, unextended_sp, link(), sender_pc());
-+  return frame(sender_sp, unextended_sp, link(), sender_pc(), _displacement);
- }
- 
- 
-@@ -446,7 +447,7 @@
- 
-   // This is the saved value of EBP which may or may not really be an FP.
-   // It is only an FP if the sender is an interpreter frame (or C1?).
--  intptr_t** saved_fp_addr = (intptr_t**) (sender_sp - frame::sender_sp_offset);
-+  intptr_t** saved_fp_addr = (intptr_t**) (sender_sp - frame::sender_sp_offset) + _displacement;
- 
-   if (map->update_map()) {
-     // Tell GC to use argument oopmaps for some runtime stubs that need it.
-@@ -464,7 +465,7 @@
-   }
- 
-   assert(sender_sp != sp(), "must have changed");
--  return frame(sender_sp, unextended_sp, *saved_fp_addr, sender_pc);
-+  return frame(sender_sp, unextended_sp, *saved_fp_addr, sender_pc, _displacement);
- }
- 
- 
-@@ -485,7 +486,7 @@
-   }
-   // Must be native-compiled frame, i.e. the marshaling code for native
-   // methods that exists in the core system.
--  return frame(sender_sp(), link(), sender_pc());
-+  return frame(sender_sp(), link(), sender_pc(), _displacement);
- }
- 
- 
-diff --git a/src/share/vm/prims/nativeLookup.cpp b/src/share/vm/prims/nativeLookup.cpp
---- a/src/share/vm/prims/nativeLookup.cpp
-+++ b/src/share/vm/prims/nativeLookup.cpp
-@@ -105,6 +105,7 @@
- }
- 
- extern "C" {
-+  void JNICALL JVM_RegisterCoroutineSupportMethods(JNIEnv* env, jclass corocls);
-   void JNICALL JVM_RegisterUnsafeMethods(JNIEnv *env, jclass unsafecls);
-   void JNICALL JVM_RegisterMethodHandleMethods(JNIEnv *env, jclass unsafecls);
-   void JNICALL JVM_RegisterPerfMethods(JNIEnv *env, jclass perfclass);
-@@ -121,6 +122,7 @@
-   { CC"Java_sun_misc_Unsafe_registerNatives",                      NULL, FN_PTR(JVM_RegisterUnsafeMethods)       },
-   { CC"Java_java_lang_invoke_MethodHandleNatives_registerNatives", NULL, FN_PTR(JVM_RegisterMethodHandleMethods) },
-   { CC"Java_sun_misc_Perf_registerNatives",                        NULL, FN_PTR(JVM_RegisterPerfMethods)         },
-+  { CC"Java_java_dyn_CoroutineSupport_registerNatives",            NULL, FN_PTR(JVM_RegisterCoroutineSupportMethods)},
-   { CC"Java_sun_hotspot_WhiteBox_registerNatives",                 NULL, FN_PTR(JVM_RegisterWhiteBoxMethods)     },
- };
- 
-diff --git a/src/cpu/x86/vm/frame_x86.hpp b/src/cpu/x86/vm/frame_x86.hpp
---- a/src/cpu/x86/vm/frame_x86.hpp
-+++ b/src/cpu/x86/vm/frame_x86.hpp
-@@ -182,8 +182,12 @@
- 
-   frame(intptr_t* sp, intptr_t* fp, address pc);
- 
-+  frame(intptr_t* sp, intptr_t* fp, address pc, intptr_t displacement);
-+
-   frame(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, address pc);
- 
-+  frame(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, address pc, intptr_t displacement);
-+
-   frame(intptr_t* sp, intptr_t* fp);
- 
-   // accessors for the instance variables
-diff --git a/src/cpu/x86/vm/frame_x86.inline.hpp b/src/cpu/x86/vm/frame_x86.inline.hpp
---- a/src/cpu/x86/vm/frame_x86.inline.hpp
-+++ b/src/cpu/x86/vm/frame_x86.inline.hpp
-@@ -36,6 +36,7 @@
-   _fp = NULL;
-   _cb = NULL;
-   _deopt_state = unknown;
-+  _displacement = 0;
- }
- 
- inline frame::frame(intptr_t* sp, intptr_t* fp, address pc) {
-@@ -53,6 +54,25 @@
-   } else {
-     _deopt_state = not_deoptimized;
-   }
-+  _displacement = 0;
-+}
-+
-+inline frame::frame(intptr_t* sp, intptr_t* fp, address pc, intptr_t displacement) {
-+  _sp = sp;
-+  _unextended_sp = sp;
-+  _fp = fp;
-+  _pc = pc;
-+  assert(pc != NULL, "no pc?");
-+  _cb = CodeCache::find_blob(pc);
-+
-+  address original_pc = nmethod::get_deopt_original_pc(this);
-+  if (original_pc != NULL) {
-+    _pc = original_pc;
-+    _deopt_state = is_deoptimized;
-+  } else {
-+    _deopt_state = not_deoptimized;
-+  }
-+  _displacement = displacement;
- }
- 
- inline frame::frame(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, address pc) {
-@@ -71,6 +91,26 @@
-   } else {
-     _deopt_state = not_deoptimized;
-   }
-+  _displacement = 0;
-+}
-+
-+inline frame::frame(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, address pc, intptr_t displacement) {
-+  _sp = sp;
-+  _unextended_sp = unextended_sp;
-+  _fp = fp;
-+  _pc = pc;
-+  assert(pc != NULL, "no pc?");
-+  _cb = CodeCache::find_blob(pc);
-+
-+  address original_pc = nmethod::get_deopt_original_pc(this);
-+  if (original_pc != NULL) {
-+    _pc = original_pc;
-+    assert(((nmethod*)_cb)->code_contains(_pc), "original PC must be in nmethod");
-+    _deopt_state = is_deoptimized;
-+  } else {
-+    _deopt_state = not_deoptimized;
-+  }
-+  _displacement = displacement;
- }
- 
- inline frame::frame(intptr_t* sp, intptr_t* fp) {
-@@ -99,6 +139,7 @@
-   } else {
-     _deopt_state = not_deoptimized;
-   }
-+  _displacement = 0;
- }
- 
- // Accessors
-@@ -202,7 +243,7 @@
- }
- 
- inline intptr_t* frame::interpreter_frame_last_sp() const {
--  return *(intptr_t**)addr_at(interpreter_frame_last_sp_offset);
-+  return *(intptr_t**)addr_at(interpreter_frame_last_sp_offset) + _displacement;
- }
- 
- inline intptr_t* frame::interpreter_frame_bcx_addr() const {
-@@ -268,7 +309,7 @@
- // Entry frames
- 
- inline JavaCallWrapper* frame::entry_frame_call_wrapper() const {
-- return (JavaCallWrapper*)at(entry_frame_call_wrapper_offset);
-+ return (JavaCallWrapper*)((intptr_t*)at(entry_frame_call_wrapper_offset) + _displacement);
- }
- 
- 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/coro-simple.patch	Thu Jul 26 17:10:47 2012 +0200
@@ -0,0 +1,1976 @@
+diff --git a/src/cpu/x86/vm/assembler_x86.cpp b/src/cpu/x86/vm/assembler_x86.cpp
+--- a/src/cpu/x86/vm/assembler_x86.cpp
++++ b/src/cpu/x86/vm/assembler_x86.cpp
+@@ -6074,7 +6074,7 @@
+   andq(rsp, -16);     // align stack as required by push_CPU_state and call
+   push_CPU_state();   // keeps alignment at 16 bytes
+   lea(c_rarg0, ExternalAddress((address) msg));
+-  call_VM_leaf(CAST_FROM_FN_PTR(address, warning), c_rarg0);
++  call_VM_leaf(CAST_FROM_FN_PTR(address, warning_fixed_args), c_rarg0);
+   pop_CPU_state();
+   mov(rsp, rbp);
+   pop(rbp);
+diff --git a/src/cpu/x86/vm/sharedRuntime_x86_32.cpp b/src/cpu/x86/vm/sharedRuntime_x86_32.cpp
+--- a/src/cpu/x86/vm/sharedRuntime_x86_32.cpp
++++ b/src/cpu/x86/vm/sharedRuntime_x86_32.cpp
+@@ -41,6 +41,8 @@
+ #include "opto/runtime.hpp"
+ #endif
+ 
++#include "runtime/coroutine.hpp"
++
+ #define __ masm->
+ 
+ const int StackAlignmentInSlots = StackAlignmentInBytes / VMRegImpl::stack_slot_size;
+@@ -1434,6 +1436,8 @@
+                                                  receiver_reg, member_reg, /*for_compiler_entry:*/ true);
+ }
+ 
++void create_switchTo_contents(MacroAssembler *masm, int start, OopMapSet* oop_maps, int &stack_slots, int total_in_args, BasicType *in_sig_bt, VMRegPair *in_regs, BasicType ret_type, bool terminate);
++
+ // ---------------------------------------------------------------------------
+ // Generate a native wrapper for a given method.  The method takes arguments
+ // in the Java compiled code convention, marshals them to the native
+@@ -1760,6 +1764,16 @@
+     // need a 5 byte instruction to allow MT safe patching to non-entrant
+     __ fat_nop();
+   }
++  
++  // the coroutine support methods have a hand-coded fast version that will handle the most common cases
++  if (method->intrinsic_id() == vmIntrinsics::_switchTo) {
++    create_switchTo_contents(masm, start, oop_maps, stack_slots, total_in_args, in_sig_bt, in_regs, ret_type, false);
++  } else if (method->intrinsic_id() == vmIntrinsics::_switchToAndTerminate) {
++    create_switchTo_contents(masm, start, oop_maps, stack_slots, total_in_args, in_sig_bt, in_regs, ret_type, true);
++  } else if (method->intrinsic_id() == vmIntrinsics::_switchToAndExit) {
++    create_switchTo_contents(masm, start, oop_maps, stack_slots, total_in_args, in_sig_bt, in_regs, ret_type, true);
++  }
++
+ 
+   // Generate a new frame for the wrapper.
+   __ enter();
+@@ -3460,3 +3474,167 @@
+   // frame_size_words or bytes??
+   return RuntimeStub::new_runtime_stub(name, &buffer, frame_complete, frame_size_words, oop_maps, true);
+ }
++
++void stop_if(MacroAssembler *masm, Assembler::Condition condition, const char* message) {
++  Label skip;
++  __ jcc(masm->negate_condition(condition), skip);
++
++  __ warn(message);
++  __ int3();
++
++  __ bind(skip);
++}
++
++void stop_if_null(MacroAssembler *masm, Register reg, const char* message) {
++  __ testptr(reg, reg);
++  stop_if(masm, Assembler::zero, message);
++}
++
++void stop_if_null(MacroAssembler *masm, Address adr, const char* message) {
++  __ cmpptr(adr, 0);
++  stop_if(masm, Assembler::zero, message);
++}
++
++void check_heap_internal(const char* msg) {
++  tty->print("check(%s) ", msg);
++  os::check_heap(true);
++}
++
++void check_heap(MacroAssembler *masm, const char* msg) {
++  __ pusha();
++  __ push((int)msg);
++  __ call(RuntimeAddress((address)check_heap_internal));
++  __ addptr(rsp, HeapWordSize);
++  __ popa();
++}
++
++void create_switchTo_contents(MacroAssembler *masm, int start, OopMapSet* oop_maps, int &stack_slots, int total_in_args,
++                              BasicType *in_sig_bt, VMRegPair *in_regs, BasicType ret_type, bool terminate) {
++  assert(total_in_args == 2, "wrong number of arguments");
++
++  if (terminate) {
++    __ get_thread(rax);
++    __ movptr(Address(rax, JavaThread::coroutine_temp_offset()), rcx);
++  }
++
++  Register target_coroutine = rdx;
++  // check that we're dealing with sane objects...
++  DEBUG_ONLY(stop_if_null(masm, target_coroutine, "null new_coroutine"));
++  __ movptr(target_coroutine, Address(target_coroutine, java_dyn_CoroutineBase::get_data_offset()));
++  DEBUG_ONLY(stop_if_null(masm, target_coroutine, "new_coroutine without data"));
++
++  {
++    //////////////////////////////////////////////////////////////////////////
++    // store information into the old coroutine's object
++    //
++    // valid registers: rcx = old Coroutine, rdx = target Coroutine
++
++    Register old_coroutine = rcx;
++    Register old_stack = rdi;
++    Register temp = rsi;
++
++    // check that we're dealing with sane objects...
++    DEBUG_ONLY(stop_if_null(masm, old_coroutine, "null old_coroutine"));
++    __ movptr(old_coroutine, Address(old_coroutine, java_dyn_CoroutineBase::get_data_offset()));
++    DEBUG_ONLY(stop_if_null(masm, target_coroutine, "old_coroutine without data"));
++
++    __ movptr(old_stack, Address(old_coroutine, Coroutine::stack_offset()));
++
++#ifdef _WINDOWS
++    // rescue the SEH pointer
++    __ prefix(Assembler::FS_segment);
++    __ movptr(temp, Address(noreg, 0x00));
++    __ movptr(Address(old_coroutine, Coroutine::last_SEH_offset()), temp);
++#endif
++
++    Register thread = rax;
++    __ get_thread(thread);
++
++    __ movl(Address(old_coroutine, Coroutine::state_offset()) , Coroutine::_onstack);
++
++    // rescue old handle and resource areas
++    __ movptr(temp, Address(thread, Thread::handle_area_offset()));
++    __ movptr(Address(old_coroutine, Coroutine::handle_area_offset()), temp);
++    __ movptr(temp, Address(thread, Thread::resource_area_offset()));
++    __ movptr(Address(old_coroutine, Coroutine::resource_area_offset()), temp);
++    __ movptr(temp, Address(thread, Thread::last_handle_mark_offset()));
++    __ movptr(Address(old_coroutine, Coroutine::last_handle_mark_offset()), temp);
++
++    // push the current IP and frame pointer onto the stack
++    __ push(rbp);
++
++    __ movptr(Address(old_stack, CoroutineStack::last_sp_offset()), rsp);
++  }
++
++  {
++    //////////////////////////////////////////////////////////////////////////
++    // perform the switch to the new stack
++    //
++    // valid registers: rdx = target Coroutine
++
++    Register target_stack = rbx;
++    __ movptr(target_stack, Address(target_coroutine, Coroutine::stack_offset()));
++
++    __ movl(Address(target_coroutine, Coroutine::state_offset()), Coroutine::_current);
++
++    Register temp = rsi;
++    Register temp2 = rdi;
++    {
++      Register thread = rax;
++      __ get_thread(rax);
++      // set new handle and resource areas
++      __ movptr(temp, Address(target_coroutine, Coroutine::handle_area_offset()));
++      __ movptr(Address(target_coroutine, Coroutine::handle_area_offset()), (intptr_t)NULL_WORD);                // TODO is this really needed?
++      __ movptr(Address(thread, Thread::handle_area_offset()), temp);
++      __ movptr(temp, Address(target_coroutine, Coroutine::resource_area_offset()));
++      __ movptr(Address(target_coroutine, Coroutine::resource_area_offset()), (intptr_t)NULL_WORD);              // TODO is this really needed?
++      __ movptr(Address(thread, Thread::resource_area_offset()), temp);
++      __ movptr(temp, Address(target_coroutine, Coroutine::last_handle_mark_offset()));
++      __ movptr(Address(target_coroutine, Coroutine::last_handle_mark_offset()), (intptr_t)NULL_WORD);              // TODO is this really needed?
++      __ movptr(Address(thread, Thread::last_handle_mark_offset()), temp);
++
++      // update the thread's stack base and size
++      __ movptr(temp, Address(target_stack, CoroutineStack::stack_base_offset()));
++      __ movptr(Address(thread, JavaThread::stack_base_offset()), temp);
++      __ movl(temp2, Address(target_stack, CoroutineStack::stack_size_offset()));
++      __ movl(Address(thread, JavaThread::stack_size_offset()), temp2);
++    }
++#ifdef _WINDOWS
++    {
++      Register tib = rax;
++      // get the linear address of the TIB (thread info block)
++      __ prefix(Assembler::FS_segment);
++      __ movptr(tib, Address(noreg, 0x18));
++
++      // update the TIB stack base and top
++      __ movptr(Address(tib, 4), temp);
++      __ subptr(temp, temp2);
++      __ movptr(Address(tib, 8), temp);
++
++      // exchange the TIB structured exception handler pointer
++      __ movptr(temp, Address(target_coroutine, Coroutine::last_SEH_offset()));
++      __ movptr(Address(tib, 0), temp);
++    }
++#endif
++    // restore the stack pointer
++    __ movptr(temp, Address(target_stack, CoroutineStack::last_sp_offset()));
++    __ movptr(rsp, temp);
++
++    __ pop(rbp);
++    
++    if (!terminate) {
++      //////////////////////////////////////////////////////////////////////////
++      // normal case (resume immediately)
++      __ ret(0);        // <-- this will jump to the stored IP of the target coroutine
++      
++    } else {
++      //////////////////////////////////////////////////////////////////////////
++      // slow case (terminate old coroutine)
++      __ get_thread(rax);
++      __ movptr(rcx, Address(rax, JavaThread::coroutine_temp_offset()));
++      __ movptr(Address(rax, JavaThread::coroutine_temp_offset()), (intptr_t)NULL_WORD);
++      __ movptr(rdx, (intptr_t)NULL_WORD);
++      
++    }
++  }
++}
+diff --git a/src/cpu/x86/vm/sharedRuntime_x86_64.cpp b/src/cpu/x86/vm/sharedRuntime_x86_64.cpp
+--- a/src/cpu/x86/vm/sharedRuntime_x86_64.cpp
++++ b/src/cpu/x86/vm/sharedRuntime_x86_64.cpp
+@@ -41,6 +41,11 @@
+ #include "opto/runtime.hpp"
+ #endif
+ 
++#include "runtime/coroutine.hpp"
++
++void coroutine_start(Coroutine* coroutine, jobject coroutineObj);
++
++
+ #define __ masm->
+ 
+ const int StackAlignmentInSlots = StackAlignmentInBytes / VMRegImpl::stack_slot_size;
+@@ -1681,6 +1686,9 @@
+                                                  receiver_reg, member_reg, /*for_compiler_entry:*/ true);
+ }
+ 
++void create_switchTo_contents(MacroAssembler *masm, int start, OopMapSet* oop_maps, int &stack_slots, int total_in_args, BasicType *in_sig_bt, VMRegPair *in_regs, BasicType ret_type, bool terminate);
++
++
+ // ---------------------------------------------------------------------------
+ // Generate a native wrapper for a given method.  The method takes arguments
+ // in the Java compiled code convention, marshals them to the native
+@@ -1971,6 +1979,15 @@
+     __ fat_nop();
+   }
+ 
++  // the coroutine support methods have a hand-coded fast version that will handle the most common cases
++  if (method->intrinsic_id() == vmIntrinsics::_switchTo) {
++    create_switchTo_contents(masm, start, oop_maps, stack_slots, total_in_args, in_sig_bt, in_regs, ret_type, false);
++  } else if (method->intrinsic_id() == vmIntrinsics::_switchToAndTerminate) {
++    create_switchTo_contents(masm, start, oop_maps, stack_slots, total_in_args, in_sig_bt, in_regs, ret_type, true);
++  } else if (method->intrinsic_id() == vmIntrinsics::_switchToAndExit) {
++    create_switchTo_contents(masm, start, oop_maps, stack_slots, total_in_args, in_sig_bt, in_regs, ret_type, true);
++  }
++
+   // Generate a new frame for the wrapper.
+   __ enter();
+   // -2 because return address is already present and so is saved rbp
+@@ -2484,6 +2501,21 @@
+   }
+ 
+   // Return
++  if (method->intrinsic_id() == vmIntrinsics::_switchToAndTerminate ||
++      method->intrinsic_id() == vmIntrinsics::_switchToAndExit) {
++
++    Label normal;
++    __ lea(rcx, RuntimeAddress((unsigned char*)coroutine_start));
++    __ cmpq(Address(rsp, 0), rcx);
++    __ jcc(Assembler::notEqual, normal);
++
++    __ movq(c_rarg0, Address(rsp, HeapWordSize * 2));
++    __ movq(c_rarg1, Address(rsp, HeapWordSize * 3));
++
++    __ bind(normal);
++
++    __ ret(0);        // <-- this will jump to the stored IP of the target coroutine
++  }
+ 
+   __ ret(0);
+ 
+@@ -4051,3 +4083,208 @@
+   _exception_blob =  ExceptionBlob::create(&buffer, oop_maps, SimpleRuntimeFrame::framesize >> 1);
+ }
+ #endif // COMPILER2
++
++
++void stop_if(MacroAssembler *masm, Assembler::Condition condition, const char* message) {
++  Label skip;
++  __ jcc(masm->negate_condition(condition), skip);
++
++  __ stop(message);
++  __ int3();
++
++  __ bind(skip);
++}
++
++void stop_if_null(MacroAssembler *masm, Register reg, const char* message) {
++  __ testptr(reg, reg);
++  stop_if(masm, Assembler::zero, message);
++}
++
++void stop_if_null(MacroAssembler *masm, Address adr, const char* message) {
++  __ cmpptr(adr, 0);
++  stop_if(masm, Assembler::zero, message);
++}
++
++MacroAssembler* debug_line(MacroAssembler* masm, int l) {
++/*    masm->movptr(r13, Address(rdx, Coroutine::stack_offset()));
++    masm->movptr(r13, Address(r13, CoroutineStack::stack_base_offset()));
++    masm->subptr(r13, HeapWordSize);
++    masm->movptr(Address(r13, -16), 0);
++
++*/    masm->movl(r13, l);
++    return masm;
++}
++
++void create_switchTo_contents(MacroAssembler *masm, int start, OopMapSet* oop_maps, int &stack_slots, int total_in_args, 
++                              BasicType *in_sig_bt, VMRegPair *in_regs, BasicType ret_type, bool terminate) {
++  assert(total_in_args == 2, "wrong number of arguments");
++
++  if (j_rarg0 != rsi) {
++    __ movptr(rsi, j_rarg0);
++  }
++  if (j_rarg1 != rdx) {
++    __ movptr(rdx, j_rarg1);
++  }
++
++  // push the current IP and frame pointer onto the stack
++  __ push(rbp);
++  
++  Register thread = r15;
++  Register target_coroutine = rdx;
++  // check that we're dealing with sane objects...
++  DEBUG_ONLY(stop_if_null(masm, target_coroutine, "null new_coroutine"));
++  __ movptr(target_coroutine, Address(target_coroutine, java_dyn_CoroutineBase::get_data_offset()));
++  DEBUG_ONLY(stop_if_null(masm, target_coroutine, "new_coroutine without data"));
++
++  /*
++#ifdef ASSERT
++#undef __
++#define __ debug_line(masm, __LINE__)->
++#endif
++*/
++  {
++    //////////////////////////////////////////////////////////////////////////
++    // store information into the old coroutine's object
++    //
++    // valid registers: rsi = old Coroutine, rdx = target Coroutine
++
++    Register old_coroutine_obj = rsi;
++    Register old_coroutine = r9;
++    Register old_stack = r10;
++    Register temp = r8;
++    
++    // check that we're dealing with sane objects...
++    DEBUG_ONLY(stop_if_null(masm, old_coroutine_obj, "null old_coroutine"));
++    __ movptr(old_coroutine, Address(old_coroutine_obj, java_dyn_CoroutineBase::get_data_offset()));
++    DEBUG_ONLY(stop_if_null(masm, old_coroutine, "old_coroutine without data"));
++
++    // saving r12 is not necessary - it is restored by reinit_heapbase()
++//    __ movq(Address(old_coroutine, Coroutine::storage_offset() + in_ByteSize(0 * HeapWordSize)), r12);
++//    __ movq(Address(old_coroutine, Coroutine::storage_offset() + in_ByteSize(1 * HeapWordSize)), r14);
++
++    __ movptr(old_stack, Address(old_coroutine, Coroutine::stack_offset()));
++
++#if defined(_WINDOWS)
++    // rescue the SEH pointer
++    __ prefix(Assembler::GS_segment);
++    __ movptr(temp, Address(noreg, 0x00));
++    __ movptr(Address(old_coroutine, Coroutine::last_SEH_offset()), temp);
++#endif
++
++    __ movl(Address(old_coroutine, Coroutine::state_offset()) , Coroutine::_onstack);
++
++    // rescue old handle and resource areas
++    __ movptr(temp, Address(thread, Thread::handle_area_offset()));
++    __ movptr(Address(old_coroutine, Coroutine::handle_area_offset()), temp);
++    __ movptr(temp, Address(thread, Thread::resource_area_offset()));
++    __ movptr(Address(old_coroutine, Coroutine::resource_area_offset()), temp);
++    __ movptr(temp, Address(thread, Thread::last_handle_mark_offset()));
++    __ movptr(Address(old_coroutine, Coroutine::last_handle_mark_offset()), temp);
++#ifdef ASSERT
++    __ movl(temp, Address(thread, JavaThread::java_call_counter_offset()));
++    __ movl(Address(old_coroutine, Coroutine::java_call_counter_offset()), temp);
++#endif
++
++    __ movptr(Address(old_stack, CoroutineStack::last_sp_offset()), rsp);
++  }
++  Register target_stack = r12;
++  __ movptr(target_stack, Address(target_coroutine, Coroutine::stack_offset()));
++
++  {
++    //////////////////////////////////////////////////////////////////////////
++    // perform the switch to the new stack
++    //
++    // valid registers: rdx = target Coroutine
++
++    __ movl(Address(target_coroutine, Coroutine::state_offset()), Coroutine::_current);
++
++    Register temp = r8;
++    Register temp2 = r9;
++    {
++      Register thread = r15;
++      // set new handle and resource areas
++      __ movptr(temp, Address(target_coroutine, Coroutine::handle_area_offset()));
++      __ movptr(Address(thread, Thread::handle_area_offset()), temp);
++      __ movptr(temp, Address(target_coroutine, Coroutine::resource_area_offset()));
++      __ movptr(Address(thread, Thread::resource_area_offset()), temp);
++      __ movptr(temp, Address(target_coroutine, Coroutine::last_handle_mark_offset()));
++      __ movptr(Address(thread, Thread::last_handle_mark_offset()), temp);
++
++#ifdef ASSERT
++      __ movl(temp, Address(target_coroutine, Coroutine::java_call_counter_offset()));
++      __ movl(Address(thread, JavaThread::java_call_counter_offset()), temp);
++
++      __ movptr(Address(target_coroutine, Coroutine::handle_area_offset()), (intptr_t)NULL_WORD);
++      __ movptr(Address(target_coroutine, Coroutine::resource_area_offset()), (intptr_t)NULL_WORD);
++      __ movptr(Address(target_coroutine, Coroutine::last_handle_mark_offset()), (intptr_t)NULL_WORD);
++      __ movl(Address(target_coroutine, Coroutine::java_call_counter_offset()), 0);
++#endif
++
++      // update the thread's stack base and size
++      __ movptr(temp, Address(target_stack, CoroutineStack::stack_base_offset()));
++      __ movptr(Address(thread, JavaThread::stack_base_offset()), temp);
++      __ movl(temp2, Address(target_stack, CoroutineStack::stack_size_offset()));
++      __ movl(Address(thread, JavaThread::stack_size_offset()), temp2);
++    }
++#if defined(_WINDOWS)
++    {
++      Register tib = rax;
++      // get the linear address of the TIB (thread info block)
++      __ prefix(Assembler::GS_segment);
++      __ movptr(tib, Address(noreg, 0x30));
++
++      // update the TIB stack base and top
++      __ movptr(Address(tib, 0x8), temp);
++      __ subptr(temp, temp2);
++      __ movptr(Address(tib, 0x10), temp);
++
++      // exchange the TIB structured exception handler pointer
++      __ movptr(temp, Address(target_coroutine, Coroutine::last_SEH_offset()));
++      __ movptr(Address(tib, 0), temp);
++    }
++#endif
++    // restore the stack pointer
++    __ movptr(temp, Address(target_stack, CoroutineStack::last_sp_offset()));
++    __ movptr(rsp, temp);
++
++    __ pop(rbp);
++
++    __ int3();
++    
++    if (!terminate) {
++      //////////////////////////////////////////////////////////////////////////
++      // normal case (resume immediately)
++
++      // this will reset r12
++      __ reinit_heapbase();
++//    __ movq(r12, Address(target_coroutine, Coroutine::storage_offset() + in_ByteSize(0 * HeapWordSize)));
++//    __ movq(r14, Address(target_coroutine, Coroutine::storage_offset() + in_ByteSize(1 * HeapWordSize)));
++
++      Label normal;
++      __ lea(rcx, RuntimeAddress((unsigned char*)coroutine_start));
++      __ cmpq(Address(rsp, 0), rcx);
++      __ jcc(Assembler::notEqual, normal);
++
++      __ movq(c_rarg0, Address(rsp, HeapWordSize * 2));
++      __ movq(c_rarg1, Address(rsp, HeapWordSize * 3));
++
++      __ bind(normal);
++
++      __ ret(0);        // <-- this will jump to the stored IP of the target coroutine
++      
++    } else {
++      //////////////////////////////////////////////////////////////////////////
++      // slow case (terminate old coroutine)
++
++      // this will reset r12
++      __ reinit_heapbase();
++//    __ movq(r12, Address(target_coroutine, Coroutine::storage_offset() + in_ByteSize(0 * HeapWordSize)));
++//    __ movq(r14, Address(target_coroutine, Coroutine::storage_offset() + in_ByteSize(1 * HeapWordSize)));
++
++      if (j_rarg0 != rsi) {
++        __ movptr(j_rarg0, rsi);
++      }
++      __ movptr(j_rarg1, 0);
++    }
++  }
++}
+diff --git a/src/os/windows/vm/os_windows.cpp b/src/os/windows/vm/os_windows.cpp
+--- a/src/os/windows/vm/os_windows.cpp
++++ b/src/os/windows/vm/os_windows.cpp
+@@ -2324,7 +2324,7 @@
+     bool in_java = thread->thread_state() == _thread_in_Java;
+ 
+     // Handle potential stack overflows up front.
+-    if (exception_code == EXCEPTION_STACK_OVERFLOW) {
++    if (exception_code == EXCEPTION_STACK_OVERFLOW || exception_code == EXCEPTION_GUARD_PAGE) {
+       if (os::uses_stack_guard_pages()) {
+ #ifdef _M_IA64
+         //
+diff --git a/src/os_cpu/bsd_x86/vm/threadLS_bsd_x86.cpp b/src/os_cpu/bsd_x86/vm/threadLS_bsd_x86.cpp
+--- a/src/os_cpu/bsd_x86/vm/threadLS_bsd_x86.cpp
++++ b/src/os_cpu/bsd_x86/vm/threadLS_bsd_x86.cpp
+@@ -90,3 +90,25 @@
+   }
+ #endif // !AMD64
+ }
++
++void ThreadLocalStorage::pd_add_coroutine_stack(Thread* thread, address stack_base, size_t stack_size) {
++#ifndef AMD64
++  for (address p = stack_base - stack_size; p < stack_base; p += PAGE_SIZE) {
++    assert(thread == NULL || _sp_map[(uintptr_t)p >> PAGE_SHIFT] == NULL ||
++           thread == _sp_map[(uintptr_t)p >> PAGE_SHIFT],
++           "coroutine exited without detaching from VM??");
++    _sp_map[(uintptr_t)p >> PAGE_SHIFT] = thread;
++  }
++#endif // !AMD64
++}
++
++
++void ThreadLocalStorage::pd_remove_coroutine_stack(Thread* thread, address stack_base, size_t stack_size) {
++#ifndef AMD64
++  for (address p = stack_base - stack_size; p < stack_base; p += PAGE_SIZE) {
++    assert(thread == _sp_map[(uintptr_t)p >> PAGE_SHIFT],
++           "coroutine exited without detaching from VM??");
++    _sp_map[(uintptr_t)p >> PAGE_SHIFT] = NULL;
++  }
++#endif // !AMD64
++}
+diff --git a/src/os_cpu/linux_x86/vm/threadLS_linux_x86.cpp b/src/os_cpu/linux_x86/vm/threadLS_linux_x86.cpp
+--- a/src/os_cpu/linux_x86/vm/threadLS_linux_x86.cpp
++++ b/src/os_cpu/linux_x86/vm/threadLS_linux_x86.cpp
+@@ -96,4 +96,27 @@
+ void ThreadLocalStorage::pd_set_thread(Thread* thread) {
+   os::thread_local_storage_at_put(ThreadLocalStorage::thread_index(), thread);
+ }
++
++void ThreadLocalStorage::pd_add_coroutine_stack(Thread* thread, address stack_base, size_t stack_size) {
++#ifndef AMD64
++  for (address p = stack_base - stack_size; p < stack_base; p += PAGE_SIZE) {
++    assert(thread == NULL || _sp_map[(uintptr_t)p >> PAGE_SHIFT] == NULL ||
++           thread == _sp_map[(uintptr_t)p >> PAGE_SHIFT],
++           "coroutine exited without detaching from VM??");
++    _sp_map[(uintptr_t)p >> PAGE_SHIFT] = thread;
++  }
++#endif // !AMD64
++}
++
++
++void ThreadLocalStorage::pd_remove_coroutine_stack(Thread* thread, address stack_base, size_t stack_size) {
++#ifndef AMD64
++  for (address p = stack_base - stack_size; p < stack_base; p += PAGE_SIZE) {
++    assert(thread == _sp_map[(uintptr_t)p >> PAGE_SHIFT],
++           "coroutine exited without detaching from VM??");
++    _sp_map[(uintptr_t)p >> PAGE_SHIFT] = NULL;
++  }
++#endif // !AMD64
++}
++
+ #endif // !AMD64 && !MINIMIZE_RAM_USAGE
+diff --git a/src/os_cpu/windows_x86/vm/threadLS_windows_x86.cpp b/src/os_cpu/windows_x86/vm/threadLS_windows_x86.cpp
+--- a/src/os_cpu/windows_x86/vm/threadLS_windows_x86.cpp
++++ b/src/os_cpu/windows_x86/vm/threadLS_windows_x86.cpp
+@@ -47,3 +47,12 @@
+ void ThreadLocalStorage::pd_set_thread(Thread* thread)  {
+   os::thread_local_storage_at_put(ThreadLocalStorage::thread_index(), thread);
+ }
++
++
++void ThreadLocalStorage::pd_add_coroutine_stack(Thread* thread, address stack_base, size_t stack_size) {
++  // nothing to do
++}
++
++void ThreadLocalStorage::pd_remove_coroutine_stack(Thread* thread, address stack_base, size_t stack_size) {
++  // nothing to do
++}
+diff --git a/src/share/vm/classfile/javaClasses.cpp b/src/share/vm/classfile/javaClasses.cpp
+--- a/src/share/vm/classfile/javaClasses.cpp
++++ b/src/share/vm/classfile/javaClasses.cpp
+@@ -2896,6 +2896,25 @@
+   compute_offset(_limit_offset, k, vmSymbols::limit_name(), vmSymbols::int_signature());
+ }
+ 
++/* stack manipulation */
++
++int java_dyn_CoroutineBase::data_offset = 0;
++
++void java_dyn_CoroutineBase::compute_offsets() {
++  klassOop k = SystemDictionary::coroutine_base_klass();
++  if (k != NULL) {
++    compute_offset(data_offset,    k, vmSymbols::data_name(),    vmSymbols::long_signature());
++  }
++}
++
++jlong java_dyn_CoroutineBase::data(oop obj) {
++  return obj->long_field(data_offset);
++}
++
++void java_dyn_CoroutineBase::set_data(oop obj, jlong value) {
++  obj->long_field_put(data_offset, value);
++}
++
+ void java_util_concurrent_locks_AbstractOwnableSynchronizer::initialize(TRAPS) {
+   if (_owner_offset != 0) return;
+ 
+@@ -2999,6 +3018,8 @@
+ 
+   // generated interpreter code wants to know about the offsets we just computed:
+   AbstractAssembler::update_delayed_values();
++
++  java_dyn_CoroutineBase::compute_offsets();
+ }
+ 
+ #ifndef PRODUCT
+diff --git a/src/share/vm/classfile/javaClasses.hpp b/src/share/vm/classfile/javaClasses.hpp
+--- a/src/share/vm/classfile/javaClasses.hpp
++++ b/src/share/vm/classfile/javaClasses.hpp
+@@ -1287,6 +1287,24 @@
+   CLASS_INJECTED_FIELDS(macro)              \
+   MEMBERNAME_INJECTED_FIELDS(macro)
+ 
++class java_dyn_CoroutineBase: AllStatic {
++private:
++  // Note that to reduce dependencies on the JDK we compute these offsets at run-time.
++  static int data_offset;
++
++  static void compute_offsets();
++
++public:
++  // Accessors
++  static jlong data(oop obj);
++  static void set_data(oop obj, jlong value);
++
++  static int get_data_offset()    { return data_offset; }
++
++  // Debugging
++  friend class JavaClasses;
++};
++
+ // Interface to hard-coded offset checking
+ 
+ class JavaClasses : AllStatic {
+diff --git a/src/share/vm/classfile/systemDictionary.hpp b/src/share/vm/classfile/systemDictionary.hpp
+--- a/src/share/vm/classfile/systemDictionary.hpp
++++ b/src/share/vm/classfile/systemDictionary.hpp
+@@ -179,6 +179,10 @@
+   template(Short_klass,                  java_lang_Short,                Pre) \
+   template(Integer_klass,                java_lang_Integer,              Pre) \
+   template(Long_klass,                   java_lang_Long,                 Pre) \
++                                                                              \
++  /* Stack manipulation classes */                                            \
++  template(coroutine_support_klass,      java_dyn_CoroutineSupport,      Opt) \
++  template(coroutine_base_klass,         java_dyn_CoroutineBase,         Opt) \
+   /*end*/
+ 
+ 
+diff --git a/src/share/vm/classfile/vmSymbols.hpp b/src/share/vm/classfile/vmSymbols.hpp
+--- a/src/share/vm/classfile/vmSymbols.hpp
++++ b/src/share/vm/classfile/vmSymbols.hpp
+@@ -391,6 +391,7 @@
+   template(void_float_signature,                      "()F")                                      \
+   template(void_double_signature,                     "()D")                                      \
+   template(int_void_signature,                        "(I)V")                                     \
++  template(long_void_signature,                       "(J)V")                                     \
+   template(int_int_signature,                         "(I)I")                                     \
+   template(char_char_signature,                       "(C)C")                                     \
+   template(short_short_signature,                     "(S)S")                                     \
+@@ -508,7 +509,7 @@
+   template(createGarbageCollectorMBean_signature,      "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/management/GarbageCollectorMBean;") \
+   template(trigger_name,                               "trigger")                                                 \
+   template(clear_name,                                 "clear")                                                   \
+-  template(trigger_method_signature,                   "(ILjava/lang/management/MemoryUsage;)V")                                                 \
++  template(trigger_method_signature,                   "(ILjava/lang/management/MemoryUsage;)V")                  \
+   template(startAgent_name,                            "startAgent")                                              \
+   template(startRemoteAgent_name,                      "startRemoteManagementAgent")                              \
+   template(startLocalAgent_name,                       "startLocalManagementAgent")                               \
+@@ -530,7 +531,7 @@
+   template(addThreadDumpForMonitors_name,              "addThreadDumpForMonitors")                                \
+   template(addThreadDumpForSynchronizers_name,         "addThreadDumpForSynchronizers")                           \
+   template(addThreadDumpForMonitors_signature,         "(Ljava/lang/management/ThreadInfo;[Ljava/lang/Object;[I)V") \
+-  template(addThreadDumpForSynchronizers_signature,    "(Ljava/lang/management/ThreadInfo;[Ljava/lang/Object;)V")   \
++  template(addThreadDumpForSynchronizers_signature,    "(Ljava/lang/management/ThreadInfo;[Ljava/lang/Object;)V") \
+                                                                                                                   \
+   /* JVMTI/java.lang.instrument support and VM Attach mechanism */                                                \
+   template(sun_misc_VMSupport,                         "sun/misc/VMSupport")                                      \
+@@ -541,6 +542,26 @@
+   template(serializeAgentPropertiesToByteArray_name,   "serializeAgentPropertiesToByteArray")                     \
+   template(classRedefinedCount_name,                   "classRedefinedCount")                                     \
+                                                                                                                   \
++  /* coroutine support */                                                                                         \
++  template(java_dyn_CoroutineSupport,                  "java/dyn/CoroutineSupport")                               \
++  template(java_dyn_CoroutineBase,                     "java/dyn/CoroutineBase")                                  \
++  template(java_dyn_CoroutineExitException,            "java/dyn/CoroutineExitException")                         \
++  template(data_name,                                  "data")                                                    \
++  template(stack_name,                                 "stack")                                                   \
++  template(current_name,                               "current")                                                 \
++  template(java_dyn_CoroutineBase_signature,           "Ljava/dyn/CoroutineBase;")                                \
++  template(reflect_method_signature,                   "Ljava/lang/reflect/Method;")                              \
++  template(startInternal_method_name,                  "startInternal")                                           \
++  template(initializeCoroutineSupport_method_name,     "initializeCoroutineSupport")                              \
++  template(method_name,                                "method")                                                  \
++  template(bci_name,                                   "bci")                                                     \
++  template(localCount_name,                            "localCount")                                              \
++  template(expressionCount_name,                       "expressionCount")                                         \
++  template(scalarValues_name,                          "scalarValues")                                            \
++  template(objectValues_name,                          "objectValues")                                            \
++  template(long_array_signature,                       "[J")                                                      \
++  template(object_array_signature,                     "[Ljava/lang/Object;")                                     \
++                                                                                                                  \
+   /* trace signatures */                                                                                          \
+   TRACE_TEMPLATES(template)                                                                                       \
+                                                                                                                   \
+@@ -879,9 +900,19 @@
+    do_name(     prefetchReadStatic_name,                         "prefetchReadStatic")                                  \
+   do_intrinsic(_prefetchWriteStatic,      sun_misc_Unsafe,        prefetchWriteStatic_name, prefetch_signature,  F_SN)  \
+    do_name(     prefetchWriteStatic_name,                        "prefetchWriteStatic")                                 \
++                                                                                                                        \
+     /*== LAST_COMPILER_INLINE*/                                                                                         \
+     /*the compiler does have special inlining code for these; bytecode inline is just fine */                           \
+                                                                                                                         \
++  /* coroutine intrinsics */                                                                                            \
++  do_intrinsic(_switchTo,                 java_dyn_CoroutineSupport, switchTo_name, switchTo_signature, F_SN)           \
++   do_name(     switchTo_name,                                    "switchTo")                                           \
++   do_signature(switchTo_signature,                               "(Ljava/dyn/CoroutineBase;Ljava/dyn/CoroutineBase;)V") \
++  do_intrinsic(_switchToAndTerminate,     java_dyn_CoroutineSupport, switchToAndTerminate_name, switchTo_signature, F_SN) \
++   do_name(     switchToAndTerminate_name,                        "switchToAndTerminate")                               \
++  do_intrinsic(_switchToAndExit,          java_dyn_CoroutineSupport, switchToAndExit_name, switchTo_signature, F_SN)    \
++   do_name(     switchToAndExit_name,                             "switchToAndExit")                                    \
++                                                                                                                        \
+   do_intrinsic(_fillInStackTrace,         java_lang_Throwable, fillInStackTrace_name, void_throwable_signature,  F_RNY) \
+                                                                                                                           \
+   do_intrinsic(_StringBuilder_void,   java_lang_StringBuilder, object_initializer_name, void_method_signature,     F_R)   \
+diff --git a/src/share/vm/prims/jni.cpp b/src/share/vm/prims/jni.cpp
+--- a/src/share/vm/prims/jni.cpp
++++ b/src/share/vm/prims/jni.cpp
+@@ -5152,6 +5152,28 @@
+ 
+     // Check if we should compile all classes on bootclasspath
+     NOT_PRODUCT(if (CompileTheWorld) ClassLoader::compile_the_world();)
++
++    JavaThread* __the_thread__ = thread;
++    HandleMark hm(THREAD);
++    Handle obj(THREAD, thread->threadObj());
++    JavaValue result(T_VOID);
++
++    if (SystemDictionary::coroutine_support_klass() != NULL) {
++      instanceKlass::cast(SystemDictionary::Class_klass())->initialize(CHECK_0);
++      instanceKlass::cast(SystemDictionary::coroutine_support_klass())->initialize(CHECK_0);
++      JavaCalls::call_virtual(&result,
++                              obj,
++                              KlassHandle(THREAD, SystemDictionary::Thread_klass()),
++                              vmSymbols::initializeCoroutineSupport_method_name(),
++                              vmSymbols::void_method_signature(),
++                              THREAD);
++      if (THREAD->has_pending_exception()) {
++        java_lang_Throwable::print_stack_trace(THREAD->pending_exception(), tty);
++        THREAD->clear_pending_exception();
++        vm_abort(false);
++      }
++    }
++
+     // Since this is not a JVM_ENTRY we have to set the thread state manually before leaving.
+     ThreadStateTransition::transition_and_fence(thread, _thread_in_vm, _thread_in_native);
+   } else {
+@@ -5282,7 +5304,7 @@
+   thread->set_thread_state(_thread_in_vm);
+   // Must do this before initialize_thread_local_storage
+   thread->record_stack_base_and_size();
+-
++  thread->initialize_coroutine_support();
+   thread->initialize_thread_local_storage();
+ 
+   if (!os::create_attached_thread(thread)) {
+diff --git a/src/share/vm/prims/jvm.cpp b/src/share/vm/prims/jvm.cpp
+--- a/src/share/vm/prims/jvm.cpp
++++ b/src/share/vm/prims/jvm.cpp
+@@ -2620,6 +2620,22 @@
+   HandleMark hm(THREAD);
+   Handle obj(THREAD, thread->threadObj());
+   JavaValue result(T_VOID);
++
++  if (SystemDictionary::coroutine_support_klass() != NULL) {
++    instanceKlass::cast(SystemDictionary::Class_klass())->initialize(CHECK);
++    instanceKlass::cast(SystemDictionary::coroutine_support_klass())->initialize(CHECK);
++    JavaCalls::call_virtual(&result,
++                            obj,
++                            KlassHandle(THREAD, SystemDictionary::Thread_klass()),
++                            vmSymbols::initializeCoroutineSupport_method_name(),
++                            vmSymbols::void_method_signature(),
++                            THREAD);
++    if (THREAD->has_pending_exception()) {
++      java_lang_Throwable::print_stack_trace(THREAD->pending_exception(), tty);
++      THREAD->clear_pending_exception();
++      vm_abort(false);
++    }
++  }
+   JavaCalls::call_virtual(&result,
+                           obj,
+                           KlassHandle(THREAD, SystemDictionary::Thread_klass()),
+diff --git a/src/share/vm/prims/nativeLookup.cpp b/src/share/vm/prims/nativeLookup.cpp
+--- a/src/share/vm/prims/nativeLookup.cpp
++++ b/src/share/vm/prims/nativeLookup.cpp
+@@ -118,6 +118,7 @@
+ }
+ 
+ extern "C" {
++  void JNICALL JVM_RegisterCoroutineSupportMethods(JNIEnv* env, jclass corocls);
+   void JNICALL JVM_RegisterUnsafeMethods(JNIEnv *env, jclass unsafecls);
+   void JNICALL JVM_RegisterMethodHandleMethods(JNIEnv *env, jclass unsafecls);
+   void JNICALL JVM_RegisterPerfMethods(JNIEnv *env, jclass perfclass);
+@@ -135,6 +136,7 @@
+   { CC"Java_sun_misc_Unsafe_registerNatives",                      NULL, FN_PTR(JVM_RegisterUnsafeMethods)       },
+   { CC"Java_java_lang_invoke_MethodHandleNatives_registerNatives", NULL, FN_PTR(JVM_RegisterMethodHandleMethods) },
+   { CC"Java_sun_misc_Perf_registerNatives",                        NULL, FN_PTR(JVM_RegisterPerfMethods)         },
++  { CC"Java_java_dyn_CoroutineSupport_registerNatives",            NULL, FN_PTR(JVM_RegisterCoroutineSupportMethods)},
+   { CC"Java_sun_hotspot_WhiteBox_registerNatives",                 NULL, FN_PTR(JVM_RegisterWhiteBoxMethods)     },
+ };
+ 
+diff --git a/src/share/vm/prims/unsafe.cpp b/src/share/vm/prims/unsafe.cpp
+--- a/src/share/vm/prims/unsafe.cpp
++++ b/src/share/vm/prims/unsafe.cpp
+@@ -27,9 +27,11 @@
+ #ifndef SERIALGC
+ #include "gc_implementation/g1/g1SATBCardTableModRefBS.hpp"
+ #endif // SERIALGC
++#include "compiler/compileBroker.hpp"
+ #include "memory/allocation.inline.hpp"
+ #include "prims/jni.h"
+ #include "prims/jvm.h"
++#include "runtime/coroutine.hpp"
+ #include "runtime/globals.hpp"
+ #include "runtime/interfaceSupport.hpp"
+ #include "runtime/reflection.hpp"
+@@ -1288,6 +1290,107 @@
+   Prefetch::write(addr, (intx)offset);
+ UNSAFE_END
+ 
++jlong CoroutineSupport_getThreadCoroutine(JNIEnv* env, jclass klass) {
++  DEBUG_CORO_PRINT("CoroutineSupport_getThreadCoroutine\n");
++
++  JavaThread* THREAD = JavaThread::thread_from_jni_environment(env);
++  Coroutine* list = THREAD->coroutine_list();
++  assert(list != NULL, "thread isn't initialized for coroutines");
++
++  return (jlong)list;
++}
++
++void CoroutineSupport_switchTo(JNIEnv* env, jclass klass, jobject old_coroutine, jobject target_coroutine) {
++  ShouldNotReachHere();
++}
++
++void CoroutineSupport_switchToAndTerminate(JNIEnv* env, jclass klass, jobject old_coroutine, jobject target_coroutine) {
++  JavaThread* THREAD = JavaThread::thread_from_jni_environment(env);
++
++  assert(old_coroutine != NULL, "NULL old CoroutineBase in switchToAndTerminate");
++  assert(target_coroutine == NULL, "expecting NULL");
++
++  oop old_oop = JNIHandles::resolve(old_coroutine);
++  Coroutine* coro = (Coroutine*)java_dyn_CoroutineBase::data(old_oop);
++  assert(coro != NULL, "NULL old coroutine in switchToAndTerminate");
++
++  java_dyn_CoroutineBase::set_data(old_oop, 0);
++
++  CoroutineStack* stack = coro->stack();
++  stack->remove_from_list(THREAD->coroutine_stack_list());
++  if (THREAD->coroutine_stack_cache_size() < MaxFreeCoroutinesCacheSize) {
++    stack->insert_into_list(THREAD->coroutine_stack_cache());
++    THREAD->coroutine_stack_cache_size() ++;
++  } else {
++    CoroutineStack::free_stack(stack, THREAD);
++  }
++  Coroutine::free_coroutine(coro, THREAD);
++}
++
++void CoroutineSupport_switchToAndExit(JNIEnv* env, jclass klass, jobject old_coroutine, jobject target_coroutine) {
++  JavaThread* THREAD = JavaThread::thread_from_jni_environment(env);
++
++  {
++    ThreadInVMfromNative tivm(THREAD);
++    HandleMark mark(THREAD);
++    THROW(vmSymbols::java_dyn_CoroutineExitException());
++  }
++}
++
++jlong CoroutineSupport_createCoroutine(JNIEnv* env, jclass klass, jobject coroutine, jlong stack_size) {
++  DEBUG_CORO_PRINT("CoroutineSupport_createCoroutine\n");
++
++  assert(coroutine != NULL, "cannot create coroutine with NULL Coroutine object");
++
++  JavaThread* THREAD = JavaThread::thread_from_jni_environment(env);
++  ThreadInVMfromNative tivm(THREAD);
++
++  if (stack_size == 0 || stack_size < -1) {
++    THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "invalid stack size");
++  }
++  CoroutineStack* stack = NULL;
++  if (stack_size <= 0 && THREAD->coroutine_stack_cache_size() > 0) {
++    stack = THREAD->coroutine_stack_cache();
++    stack->remove_from_list(THREAD->coroutine_stack_cache());
++    THREAD->coroutine_stack_cache_size() --;
++    DEBUG_CORO_ONLY(tty->print("reused coroutine stack at %08x\n", stack->_stack_base));
++  } else {
++    stack = CoroutineStack::create_stack(THREAD, stack_size);
++    if (stack == NULL) {
++      THROW_0(vmSymbols::java_lang_OutOfMemoryError());
++    }
++  }
++  stack->insert_into_list(THREAD->coroutine_stack_list());
++
++  Coroutine* coro = Coroutine::create_coroutine(THREAD, stack, JNIHandles::resolve(coroutine));
++  if (coro == NULL) {
++    ThreadInVMfromNative tivm(THREAD);
++    HandleMark mark(THREAD);
++    THROW_0(vmSymbols::java_lang_OutOfMemoryError());
++  }
++  coro->insert_into_list(THREAD->coroutine_list());
++  return (jlong)coro;
++}
++
++jboolean CoroutineSupport_isDisposable(JNIEnv* env, jclass klass, jlong coroutineLong) {
++  DEBUG_CORO_PRINT("CoroutineSupport_isDisposable\n");
++
++  JavaThread* THREAD = JavaThread::thread_from_jni_environment(env);
++  Coroutine* coro = (Coroutine*)coroutineLong;
++  assert(coro != NULL, "cannot free NULL coroutine");
++  assert(!coro->is_thread_coroutine(), "cannot free thread coroutine");
++
++  return coro->is_disposable();
++}
++
++jobject CoroutineSupport_cleanupCoroutine(JNIEnv* env, jclass klass) {
++  DEBUG_CORO_PRINT("CoroutineSupport_cleanupCoroutine\n");
++
++  JavaThread* THREAD = JavaThread::thread_from_jni_environment(env);
++  // TODO: implementation needed...
++
++  return NULL;
++}
+ 
+ /// JVM_RegisterUnsafeMethods
+ 
+@@ -1587,6 +1690,22 @@
+     {CC"shouldBeInitialized",CC"("CLS")Z",               FN_PTR(Unsafe_ShouldBeInitialized)},
+ };
+ 
++#define COBA "Ljava/dyn/CoroutineBase;"
++
++JNINativeMethod coroutine_support_methods[] = {
++    {CC"getThreadCoroutine",      CC"()J",            FN_PTR(CoroutineSupport_getThreadCoroutine)},
++    {CC"createCoroutine",         CC"("COBA"J)J",     FN_PTR(CoroutineSupport_createCoroutine)},
++    {CC"isDisposable",            CC"(J)Z",           FN_PTR(CoroutineSupport_isDisposable)},
++    {CC"switchTo",                CC"("COBA COBA")V", FN_PTR(CoroutineSupport_switchTo)},
++    {CC"switchToAndTerminate",    CC"("COBA COBA")V", FN_PTR(CoroutineSupport_switchToAndTerminate)},
++    {CC"switchToAndExit",         CC"("COBA COBA")V", FN_PTR(CoroutineSupport_switchToAndExit)},
++    {CC"cleanupCoroutine",        CC"()"COBA,         FN_PTR(CoroutineSupport_cleanupCoroutine)},
++};
++
++#define COMPILE_CORO_METHODS_FROM (3)
++
++#undef COBA
++
+ #undef CC
+ #undef FN_PTR
+ 
+@@ -1694,3 +1813,30 @@
+     guarantee(status == 0, "register unsafe natives");
+   }
+ JVM_END
++
++JVM_ENTRY(void, JVM_RegisterCoroutineSupportMethods(JNIEnv *env, jclass corocls))
++  UnsafeWrapper("JVM_RegisterCoroutineSupportMethods");
++  {
++    ThreadToNativeFromVM ttnfv(thread);
++    {
++      int coro_method_count = (int)(sizeof(coroutine_support_methods)/sizeof(JNINativeMethod));
++
++      for (int i=0; i<coro_method_count; i++) {
++        env->RegisterNatives(corocls, coroutine_support_methods + i, 1);
++        if (env->ExceptionOccurred()) {
++          tty->print_cr("Warning:  Coroutine classes not found (%i)", i);
++          vm_exit(1);
++        }
++      }
++      for (int i=COMPILE_CORO_METHODS_FROM; i<coro_method_count; i++) {
++        jmethodID id = env->GetStaticMethodID(corocls, coroutine_support_methods[i].name, coroutine_support_methods[i].signature);
++        {
++          ThreadInVMfromNative tivfn(thread);
++          methodHandle method(JNIHandles::resolve_jmethod_id(id));
++          uint id = 0; // CompileBroker::assign_compile_id(method, InvocationEntryBci);
++          nmethod* nm = AdapterHandlerLibrary::create_native_wrapper(method, id);
++        }
++      }
++    }
++  }
++JVM_END
+diff --git a/src/share/vm/runtime/coroutine.cpp b/src/share/vm/runtime/coroutine.cpp
+new file mode 100644
+--- /dev/null
++++ b/src/share/vm/runtime/coroutine.cpp
+@@ -0,0 +1,342 @@
++/*
++ * Copyright 2001-2010 Sun Microsystems, Inc.  All Rights Reserved.
++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
++ *
++ * This code is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 only, as
++ * published by the Free Software Foundation.
++ *
++ * This code is distributed in the hope that it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * version 2 for more details (a copy is included in the LICENSE file that
++ * accompanied this code).
++ *
++ * You should have received a copy of the GNU General Public License version
++ * 2 along with this work; if not, write to the Free Software Foundation,
++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
++ * CA 95054 USA or visit www.sun.com if you need additional information or
++ * have any questions.
++ *
++ */
++
++#include "precompiled.hpp"
++#include "runtime/coroutine.hpp"
++#ifdef TARGET_ARCH_x86
++# include "vmreg_x86.inline.hpp"
++#endif
++#ifdef TARGET_ARCH_sparc
++# include "vmreg_sparc.inline.hpp"
++#endif
++#ifdef TARGET_ARCH_zero
++# include "vmreg_zero.inline.hpp"
++#endif
++
++
++#ifdef _WINDOWS
++
++LONG WINAPI topLevelExceptionFilter(struct _EXCEPTION_POINTERS* exceptionInfo);
++
++
++void coroutine_start(Coroutine* coroutine, jobject coroutineObj) {
++  coroutine->thread()->set_thread_state(_thread_in_vm);
++
++  if (UseVectoredExceptions) {
++    // If we are using vectored exception we don't need to set a SEH
++    coroutine->run(coroutineObj);
++  }
++  else {
++    // Install a win32 structured exception handler around every thread created
++    // by VM, so VM can genrate error dump when an exception occurred in non-
++    // Java thread (e.g. VM thread).
++    __try {
++       coroutine->run(coroutineObj);
++    } __except(topLevelExceptionFilter((_EXCEPTION_POINTERS*)_exception_info())) {
++    }
++  }
++
++  ShouldNotReachHere();
++}
++#endif
++
++#if defined(LINUX) || defined(_ALLBSD_SOURCE)
++
++void coroutine_start(Coroutine* coroutine, jobject coroutineObj) {
++  coroutine->thread()->set_thread_state(_thread_in_vm);
++
++  coroutine->run(coroutineObj);
++  ShouldNotReachHere();
++}
++#endif
++
++void Coroutine::run(jobject coroutine) {
++
++  // do not call JavaThread::current() here!
++
++  _thread->set_resource_area(new (mtThread) ResourceArea(32));
++  _thread->set_handle_area(new (mtThread) HandleArea(NULL, 32));
++
++  // used to test validitity of stack trace backs
++//  this->record_base_of_stack_pointer();
++
++  // Record real stack base and size.
++//  this->record_stack_base_and_size();
++
++  // Initialize thread local storage; set before calling MutexLocker
++//  this->initialize_thread_local_storage();
++
++//  this->create_stack_guard_pages();
++
++  // Thread is now sufficient initialized to be handled by the safepoint code as being
++  // in the VM. Change thread state from _thread_new to _thread_in_vm
++//  ThreadStateTransition::transition_and_fence(this, _thread_new, _thread_in_vm);
++
++  // This operation might block. We call that after all safepoint checks for a new thread has
++  // been completed.
++//  this->set_active_handles(JNIHandleBlock::allocate_block());
++
++  // We call another function to do the rest so we are sure that the stack addresses used
++  // from there will be lower than the stack base just computed
++  {
++    HandleMark hm(_thread);
++    HandleMark hm2(_thread);
++    Handle obj(_thread, JNIHandles::resolve(coroutine));
++    JNIHandles::destroy_global(coroutine);
++    JavaValue result(T_VOID);
++    JavaCalls::call_virtual(&result,
++                            obj,
++                            KlassHandle(_thread, SystemDictionary::coroutine_base_klass()),
++                            vmSymbols::startInternal_method_name(),
++                            vmSymbols::void_method_signature(),
++                            _thread);
++  }
++}
++
++Coroutine* Coroutine::create_thread_coroutine(JavaThread* thread, CoroutineStack* stack) {
++  Coroutine* coro = new Coroutine();
++  if (coro == NULL)
++    return NULL;
++
++  coro->_state = _current;
++  coro->_is_thread_coroutine = true;
++  coro->_thread = thread;
++  coro->_stack = stack;
++  coro->_resource_area = NULL;
++  coro->_handle_area = NULL;
++  coro->_last_handle_mark = NULL;
++#ifdef ASSERT
++  coro->_java_call_counter = 0;
++#endif
++#if defined(_WINDOWS)
++  coro->_last_SEH = NULL;
++#endif
++  return coro;
++}
++
++Coroutine* Coroutine::create_coroutine(JavaThread* thread, CoroutineStack* stack, oop coroutineObj) {
++  Coroutine* coro = new Coroutine();
++  if (coro == NULL) {
++    return NULL;
++  }
++
++  intptr_t** d = (intptr_t**)stack->stack_base();
++  *(--d) = NULL;
++  jobject obj = JNIHandles::make_global(coroutineObj);
++  *(--d) = (intptr_t*)obj;
++  *(--d) = (intptr_t*)coro;
++  *(--d) = NULL;
++  *(--d) = (intptr_t*)coroutine_start;
++  *(--d) = NULL;
++
++  stack->set_last_sp((address) d);
++
++  coro->_state = _onstack;
++  coro->_is_thread_coroutine = false;
++  coro->_thread = thread;
++  coro->_stack = stack;
++  coro->_resource_area = NULL;
++  coro->_handle_area = NULL;
++  coro->_last_handle_mark = NULL;
++#ifdef ASSERT
++  coro->_java_call_counter = 0;
++#endif
++#if defined(_WINDOWS)
++  coro->_last_SEH = NULL;
++#endif
++  return coro;
++}
++
++void Coroutine::free_coroutine(Coroutine* coroutine, JavaThread* thread) {
++  coroutine->remove_from_list(thread->coroutine_list());
++  delete coroutine;
++}
++
++void Coroutine::frames_do(FrameClosure* fc) {
++  switch (_state) {
++    case Coroutine::_current:
++      // the contents of this coroutine have already been visited
++      break;
++    case Coroutine::_onstack:
++      _stack->frames_do(fc);
++      break;
++    case Coroutine::_dead:
++      // coroutine is dead, ignore
++      break;
++  }
++}
++
++class oops_do_Closure: public FrameClosure {
++private:
++  OopClosure* _f;
++  CodeBlobClosure* _cf;
++public:
++  oops_do_Closure(OopClosure* f, CodeBlobClosure* cf): _f(f), _cf(cf) { }
++  void frames_do(frame* fr, RegisterMap* map) { fr->oops_do(_f, _cf, map); }
++};
++
++void Coroutine::oops_do(OopClosure* f, CodeBlobClosure* cf) {
++  oops_do_Closure fc(f, cf);
++  frames_do(&fc);
++  if (_state == _onstack &&_handle_area != NULL) {
++    DEBUG_CORO_ONLY(tty->print_cr("collecting handle area %08x", _handle_area));
++    _handle_area->oops_do(f);
++  }
++}
++
++class nmethods_do_Closure: public FrameClosure {
++private:
++  CodeBlobClosure* _cf;
++public:
++  nmethods_do_Closure(CodeBlobClosure* cf): _cf(cf) { }
++  void frames_do(frame* fr, RegisterMap* map) { fr->nmethods_do(_cf); }
++};
++
++void Coroutine::nmethods_do(CodeBlobClosure* cf) {
++  nmethods_do_Closure fc(cf);
++  frames_do(&fc);
++}
++
++class frames_do_Closure: public FrameClosure {
++private:
++  void (*_f)(frame*, const RegisterMap*);
++public:
++  frames_do_Closure(void f(frame*, const RegisterMap*)): _f(f) { }
++  void frames_do(frame* fr, RegisterMap* map) { _f(fr, map); }
++};
++
++void Coroutine::frames_do(void f(frame*, const RegisterMap* map)) {
++  frames_do_Closure fc(f);
++  frames_do(&fc);
++}
++
++bool Coroutine::is_disposable() {
++  return false;
++}
++
++
++CoroutineStack* CoroutineStack::create_thread_stack(JavaThread* thread) {
++  CoroutineStack* stack = new CoroutineStack(0);
++  if (stack == NULL)
++    return NULL;
++
++  stack->_thread = thread;
++  stack->_is_thread_stack = true;
++  stack->_reserved_space;
++  stack->_virtual_space;
++  stack->_stack_base = thread->stack_base();
++  stack->_stack_size = thread->stack_size();
++  stack->_last_sp = NULL;
++  stack->_default_size = false;
++  return stack;
++}
++
++CoroutineStack* CoroutineStack::create_stack(JavaThread* thread, intptr_t size/* = -1*/) {
++  bool default_size = false;
++  if (size <= 0) {
++    size = DefaultCoroutineStackSize;
++    default_size = true;
++  }
++
++  uint reserved_pages = StackShadowPages + StackRedPages + StackYellowPages;
++  uintx real_stack_size = size + (reserved_pages * os::vm_page_size());
++  uintx reserved_size = align_size_up(real_stack_size, os::vm_allocation_granularity());
++
++  CoroutineStack* stack = new CoroutineStack(reserved_size);
++  if (stack == NULL)
++    return NULL;
++  if (!stack->_virtual_space.initialize(stack->_reserved_space, real_stack_size)) {
++    stack->_reserved_space.release();
++    delete stack;
++    return NULL;
++  }
++
++  stack->_thread = thread;
++  stack->_is_thread_stack = false;
++  stack->_stack_base = (address)stack->_virtual_space.high();
++  stack->_stack_size = stack->_virtual_space.committed_size();
++  stack->_last_sp = NULL;
++  stack->_default_size = default_size;
++
++  if (os::uses_stack_guard_pages()) {
++    address low_addr = stack->stack_base() - stack->stack_size();
++    size_t len = (StackYellowPages + StackRedPages) * os::vm_page_size();
++
++    bool allocate = os::allocate_stack_guard_pages();
++
++    if (!os::guard_memory((char *) low_addr, len)) {
++      warning("Attempt to protect stack guard pages failed.");
++      if (os::uncommit_memory((char *) low_addr, len)) {
++        warning("Attempt to deallocate stack guard pages failed.");
++      }
++    }
++  }
++
++  ThreadLocalStorage::add_coroutine_stack(thread, stack->stack_base(), stack->stack_size());
++  DEBUG_CORO_ONLY(tty->print("created coroutine stack at %08x with stack size %i (real size: %i)\n", stack->_stack_base, size, stack->_stack_size));
++  return stack;
++}
++
++void CoroutineStack::free_stack(CoroutineStack* stack, JavaThread* thread) {
++  guarantee(!stack->is_thread_stack(), "cannot free thread stack");
++  ThreadLocalStorage::remove_coroutine_stack(thread, stack->stack_base(), stack->stack_size());
++
++  if (stack->_reserved_space.size() > 0) {
++    stack->_virtual_space.release();
++    stack->_reserved_space.release();
++  }
++  delete stack;
++}
++
++void CoroutineStack::frames_do(FrameClosure* fc) {
++  assert(_last_sp != NULL, "CoroutineStack with NULL last_sp");
++
++  DEBUG_CORO_ONLY(tty->print_cr("frames_do stack %08x", _stack_base));
++
++  intptr_t* fp = ((intptr_t**)_last_sp)[0];
++  if (fp != NULL) {
++    address pc = ((address*)_last_sp)[1];
++    intptr_t* sp = ((intptr_t*)_last_sp) + 2;
++
++    frame fr(sp, fp, pc);
++    StackFrameStream fst(_thread, fr);
++    fst.register_map()->set_location(rbp->as_VMReg(), (address)_last_sp);
++    fst.register_map()->set_include_argument_oops(false);
++    for(; !fst.is_done(); fst.next()) {
++      fc->frames_do(fst.current(), fst.register_map());
++    }
++  }
++}
++
++frame CoroutineStack::last_frame(Coroutine* coro, RegisterMap& map) const {
++  DEBUG_CORO_ONLY(tty->print_cr("last_frame CoroutineStack"));
++
++  intptr_t* fp = ((intptr_t**)_last_sp)[0];
++  assert(fp != NULL, "coroutine with NULL fp");
++
++  address pc = ((address*)_last_sp)[1];
++  intptr_t* sp = ((intptr_t*)_last_sp) + 2;
++
++  return frame(sp, fp, pc);
++}
+diff --git a/src/share/vm/runtime/coroutine.hpp b/src/share/vm/runtime/coroutine.hpp
+new file mode 100644
+--- /dev/null
++++ b/src/share/vm/runtime/coroutine.hpp
+@@ -0,0 +1,244 @@
++/*
++ * Copyright 1999-2010 Sun Microsystems, Inc.  All Rights Reserved.
++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
++ *
++ * This code is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 only, as
++ * published by the Free Software Foundation.
++ *
++ * This code is distributed in the hope that it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * version 2 for more details (a copy is included in the LICENSE file that
++ * accompanied this code).
++ *
++ * You should have received a copy of the GNU General Public License version
++ * 2 along with this work; if not, write to the Free Software Foundation,
++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
++ * CA 95054 USA or visit www.sun.com if you need additional information or
++ * have any questions.
++ *
++ */
++
++#ifndef SHARE_VM_RUNTIME_COROUTINE_HPP
++#define SHARE_VM_RUNTIME_COROUTINE_HPP
++
++#include "runtime/jniHandles.hpp"
++#include "runtime/handles.hpp"
++#include "memory/resourceArea.hpp"
++#include "runtime/javaFrameAnchor.hpp"
++#include "runtime/monitorChunk.hpp"
++
++// number of heap words that prepareSwitch will add as a safety measure to the CoroutineData size
++#define COROUTINE_DATA_OVERSIZE (64)
++
++//#define DEBUG_COROUTINES
++
++#ifdef DEBUG_COROUTINES
++#define DEBUG_CORO_ONLY(x) x
++#define DEBUG_CORO_PRINT(x) tty->print(x)
++#else
++#define DEBUG_CORO_ONLY(x) 
++#define DEBUG_CORO_PRINT(x)
++#endif
++
++class Coroutine;
++class CoroutineStack;
++
++
++template<class T>
++class DoublyLinkedList {
++private:
++  T*  _last;
++  T*  _next;
++
++public:
++  DoublyLinkedList() {
++    _last = NULL;
++    _next = NULL;
++  }
++
++  typedef T* pointer;
++
++  void remove_from_list(pointer& list);
++  void insert_into_list(pointer& list);
++
++  T* last() const   { return _last; }
++  T* next() const   { return _next; }
++};
++
++class FrameClosure: public StackObj {
++public:
++  virtual void frames_do(frame* fr, RegisterMap* map) = 0;
++  virtual ~FrameClosure() { }
++};
++
++
++class Coroutine: public CHeapObj<mtThread>, public DoublyLinkedList<Coroutine> {
++public:
++  enum CoroutineState {
++    _onstack    = 0x00000001,
++    _current    = 0x00000002,
++    _dead       = 0x00000003,      // TODO is this really needed?
++    _dummy      = 0xffffffff
++  };
++
++private:
++  CoroutineState  _state;
++
++  bool            _is_thread_coroutine;
++
++  JavaThread*     _thread;
++  CoroutineStack* _stack;
++
++  ResourceArea*   _resource_area;
++  HandleArea*     _handle_area;
++  HandleMark*     _last_handle_mark;
++#ifdef ASSERT
++  int             _java_call_counter;
++#endif
++
++#ifdef _LP64
++  intptr_t        _storage[2];
++#endif
++
++  // objects of this type can only be created via static functions
++  Coroutine() { }
++  virtual ~Coroutine() { }
++
++  void frames_do(FrameClosure* fc);
++
++public:
++  void run(jobject coroutine);
++
++  static Coroutine* create_thread_coroutine(JavaThread* thread, CoroutineStack* stack);
++  static Coroutine* create_coroutine(JavaThread* thread, CoroutineStack* stack, oop coroutineObj);
++  static void free_coroutine(Coroutine* coroutine, JavaThread* thread);
++
++  CoroutineState state() const      { return _state; }
++  void set_state(CoroutineState x)  { _state = x; }
++
++  bool is_thread_coroutine() const  { return _is_thread_coroutine; }
++
++  JavaThread* thread() const        { return _thread; }
++  void set_thread(JavaThread* x)    { _thread = x; }
++
++  CoroutineStack* stack() const     { return _stack; }
++
++  ResourceArea* resource_area() const     { return _resource_area; }
++  void set_resource_area(ResourceArea* x) { _resource_area = x; }
++
++  HandleArea* handle_area() const         { return _handle_area; }
++  void set_handle_area(HandleArea* x)     { _handle_area = x; }
++
++  HandleMark* last_handle_mark() const    { return _last_handle_mark; }
++  void set_last_handle_mark(HandleMark* x){ _last_handle_mark = x; }
++
++#ifdef ASSERT
++  int java_call_counter() const           { return _java_call_counter; }
++  void set_java_call_counter(int x)       { _java_call_counter = x; }
++#endif
++
++  bool is_disposable();
++
++  // GC support
++  void oops_do(OopClosure* f, CodeBlobClosure* cf);
++  void nmethods_do(CodeBlobClosure* cf);
++  void frames_do(void f(frame*, const RegisterMap* map));
++
++  static ByteSize state_offset()              { return byte_offset_of(Coroutine, _state); }
++  static ByteSize stack_offset()              { return byte_offset_of(Coroutine, _stack); }
++
++  static ByteSize resource_area_offset()      { return byte_offset_of(Coroutine, _resource_area); }
++  static ByteSize handle_area_offset()        { return byte_offset_of(Coroutine, _handle_area); }
++  static ByteSize last_handle_mark_offset()   { return byte_offset_of(Coroutine, _last_handle_mark); }
++#ifdef ASSERT
++  static ByteSize java_call_counter_offset()  { return byte_offset_of(Coroutine, _java_call_counter); }
++#endif
++
++#ifdef _LP64
++  static ByteSize storage_offset()            { return byte_offset_of(Coroutine, _storage); }
++#endif
++
++#if defined(_WINDOWS)
++private:
++  address _last_SEH;
++public:
++  static ByteSize last_SEH_offset()           { return byte_offset_of(Coroutine, _last_SEH); }
++#endif
++};
++
++class CoroutineStack: public CHeapObj<mtThread>, public DoublyLinkedList<CoroutineStack> {
++private:
++  JavaThread*     _thread;
++
++  bool            _is_thread_stack;
++  ReservedSpace   _reserved_space;
++  VirtualSpace    _virtual_space;
++
++  address         _stack_base;
++  intptr_t        _stack_size;
++  bool            _default_size;
++
++  address         _last_sp;
++
++  // objects of this type can only be created via static functions
++  CoroutineStack(intptr_t size) : _reserved_space(size) { }
++  virtual ~CoroutineStack() { }
++
++public:
++  static CoroutineStack* create_thread_stack(JavaThread* thread);
++  static CoroutineStack* create_stack(JavaThread* thread, intptr_t size = -1);
++  static void free_stack(CoroutineStack* stack, JavaThread* THREAD);
++
++  static intptr_t get_start_method();
++
++  JavaThread* thread() const                { return _thread; }
++  bool is_thread_stack() const              { return _is_thread_stack; }
++
++  address last_sp() const                   { return _last_sp; }
++  void set_last_sp(address x)               { _last_sp = x; }
++
++  address stack_base() const                { return _stack_base; }
++  intptr_t stack_size() const               { return _stack_size; }
++  bool is_default_size() const              { return _default_size; }
++
++  frame last_frame(Coroutine* coro, RegisterMap& map) const;
++
++  // GC support
++  void frames_do(FrameClosure* fc);
++
++  static ByteSize stack_base_offset()         { return byte_offset_of(CoroutineStack, _stack_base); }
++  static ByteSize stack_size_offset()         { return byte_offset_of(CoroutineStack, _stack_size); }
++  static ByteSize last_sp_offset()            { return byte_offset_of(CoroutineStack, _last_sp); }
++};
++
++template<class T> void DoublyLinkedList<T>::remove_from_list(pointer& list) {
++  if (list == this) {
++    if (list->_next == list)
++      list = NULL;
++    else
++      list = list->_next;
++  }
++  _last->_next = _next;
++  _next->_last = _last;
++  _last = NULL;
++  _next = NULL;
++}
++
++template<class T> void DoublyLinkedList<T>::insert_into_list(pointer& list) {
++  if (list == NULL) {
++    _next = (T*)this;
++    _last = (T*)this;
++    list = (T*)this;
++  } else {
++    _next = list->_next;
++    list->_next = (T*)this;
++    _last = list;
++    _next->_last = (T*)this;
++  }
++}
++
++#endif // SHARE_VM_RUNTIME_COROUTINE_HPP
+diff --git a/src/share/vm/runtime/frame.cpp b/src/share/vm/runtime/frame.cpp
+--- a/src/share/vm/runtime/frame.cpp
++++ b/src/share/vm/runtime/frame.cpp
+@@ -1415,6 +1415,11 @@
+   _is_done = false;
+ }
+ 
++StackFrameStream::StackFrameStream(JavaThread *thread, frame last_frame, bool update) : _reg_map(thread, update) {
++  _fr = last_frame;
++  _is_done = false;
++}
++
+ 
+ #ifndef PRODUCT
+ 
+diff --git a/src/share/vm/runtime/frame.hpp b/src/share/vm/runtime/frame.hpp
+--- a/src/share/vm/runtime/frame.hpp
++++ b/src/share/vm/runtime/frame.hpp
+@@ -549,6 +549,7 @@
+   bool        _is_done;
+  public:
+    StackFrameStream(JavaThread *thread, bool update = true);
++   StackFrameStream(JavaThread *thread, frame last_frame, bool update = true);
+ 
+   // Iteration
+   bool is_done()                  { return (_is_done) ? true : (_is_done = _fr.is_first_frame(), false); }
+diff --git a/src/share/vm/runtime/globals.hpp b/src/share/vm/runtime/globals.hpp
+--- a/src/share/vm/runtime/globals.hpp
++++ b/src/share/vm/runtime/globals.hpp
+@@ -3890,6 +3890,12 @@
+           "EINTR for I/O operations results in OS_INTRPT. The default value"\
+           " of this flag is true for JDK 6 and earlier")                    \
+                                                                             \
++  product(uintx, DefaultCoroutineStackSize, 8*8*K,                          \
++        "Default size of the stack that is associated with new coroutines") \
++                                                                            \
++  product(uintx, MaxFreeCoroutinesCacheSize, 20,                            \
++          "The number of free coroutine stacks a thread can keep")          \
++                                                                            \
+   diagnostic(bool, WhiteBoxAPI, false,                                      \
+           "Enable internal testing APIs")                                   \
+                                                                             \
+diff --git a/src/share/vm/runtime/handles.cpp b/src/share/vm/runtime/handles.cpp
+--- a/src/share/vm/runtime/handles.cpp
++++ b/src/share/vm/runtime/handles.cpp
+@@ -121,6 +121,23 @@
+   thread->set_last_handle_mark(this);
+ }
+ 
++HandleMark::HandleMark(Thread* thread, HandleArea* area, HandleMark* last_handle_mark) {
++  _thread = thread;
++  // Save area
++  _area  = area;
++  // Save current top
++  _chunk = _area->_chunk;
++  _hwm   = _area->_hwm;
++  _max   = _area->_max;
++  NOT_PRODUCT(_size_in_bytes = _area->_size_in_bytes;)
++  debug_only(_area->_handle_mark_nesting++);
++  assert(_area->_handle_mark_nesting > 0, "must stack allocate HandleMarks");
++  debug_only(Atomic::inc(&_nof_handlemarks);)
++
++  // Link this in the thread
++  set_previous_handle_mark(last_handle_mark);
++}
++
+ 
+ HandleMark::~HandleMark() {
+   HandleArea* area = _area;   // help compilers with poor alias analysis
+diff --git a/src/share/vm/runtime/handles.hpp b/src/share/vm/runtime/handles.hpp
+--- a/src/share/vm/runtime/handles.hpp
++++ b/src/share/vm/runtime/handles.hpp
+@@ -243,6 +243,7 @@
+   friend class NoHandleMark;
+   friend class ResetNoHandleMark;
+ #ifdef ASSERT
++public:
+   int _handle_mark_nesting;
+   int _no_handle_mark_nesting;
+ #endif
+@@ -254,6 +255,11 @@
+     debug_only(_no_handle_mark_nesting = 0);
+     _prev = prev;
+   }
++  HandleArea(HandleArea* prev, size_t init_size) : Arena(init_size) {
++    debug_only(_handle_mark_nesting    = 0);
++    debug_only(_no_handle_mark_nesting = 0);
++    _prev = prev;
++  }
+ 
+   // Handle allocation
+  private:
+@@ -322,6 +328,7 @@
+  public:
+   HandleMark();                            // see handles_inline.hpp
+   HandleMark(Thread* thread)                      { initialize(thread); }
++  HandleMark(Thread* thread, HandleArea* area, HandleMark* last_handle_mark);
+   ~HandleMark();
+ 
+   // Functions used by HandleMarkCleaner
+diff --git a/src/share/vm/runtime/javaCalls.cpp b/src/share/vm/runtime/javaCalls.cpp
+--- a/src/share/vm/runtime/javaCalls.cpp
++++ b/src/share/vm/runtime/javaCalls.cpp
+@@ -119,6 +119,15 @@
+   }
+ }
+ 
++void JavaCallWrapper::initialize(JavaThread* thread, JNIHandleBlock* handles, methodOop callee_method, oop receiver, JavaValue* result) {
++  _thread = thread;
++  _handles = handles;
++  _callee_method = callee_method;
++  _receiver = receiver;
++  _result = result;
++  _anchor.clear();
++}
++
+ 
+ JavaCallWrapper::~JavaCallWrapper() {
+   assert(_thread == JavaThread::current(), "must still be the same thread");
+diff --git a/src/share/vm/runtime/javaCalls.hpp b/src/share/vm/runtime/javaCalls.hpp
+--- a/src/share/vm/runtime/javaCalls.hpp
++++ b/src/share/vm/runtime/javaCalls.hpp
+@@ -79,8 +79,11 @@
+    JavaCallWrapper(methodHandle callee_method, Handle receiver, JavaValue* result, TRAPS);
+   ~JavaCallWrapper();
+ 
++  void initialize(JavaThread* thread, JNIHandleBlock* handles, methodOop callee_method, oop receiver, JavaValue* result);
++
+   // Accessors
+   JavaThread*      thread() const           { return _thread; }
++
+   JNIHandleBlock*  handles() const          { return _handles; }
+ 
+   JavaFrameAnchor* anchor(void)             { return &_anchor; }
+diff --git a/src/share/vm/runtime/thread.cpp b/src/share/vm/runtime/thread.cpp
+--- a/src/share/vm/runtime/thread.cpp
++++ b/src/share/vm/runtime/thread.cpp
+@@ -47,6 +47,7 @@
+ #include "runtime/aprofiler.hpp"
+ #include "runtime/arguments.hpp"
+ #include "runtime/biasedLocking.hpp"
++#include "runtime/coroutine.hpp"
+ #include "runtime/deoptimization.hpp"
+ #include "runtime/fprofiler.hpp"
+ #include "runtime/frame.inline.hpp"
+@@ -324,6 +325,7 @@
+ 
+ 
+ Thread::~Thread() {
++
+   // Reclaim the objectmonitors from the omFreeList of the moribund thread.
+   ObjectSynchronizer::omFlush (this) ;
+ 
+@@ -1347,6 +1349,13 @@
+   _interp_only_mode    = 0;
+   _special_runtime_exit_condition = _no_async_condition;
+   _pending_async_exception = NULL;
++
++  _coroutine_stack_cache = NULL;
++  _coroutine_stack_cache_size = 0;
++
++  _coroutine_stack_list = NULL;
++  _coroutine_list = NULL;
++
+   _is_compiling = false;
+   _thread_stat = NULL;
+   _thread_stat = new ThreadStatistics();
+@@ -1482,6 +1491,13 @@
+ }
+ 
+ JavaThread::~JavaThread() {
++
++  while (coroutine_stack_cache() != NULL) {
++    CoroutineStack* stack = coroutine_stack_cache();
++    stack->remove_from_list(coroutine_stack_cache());
++    CoroutineStack::free_stack(stack, this);
++  }
++
+   if (TraceThreadEvents) {
+       tty->print_cr("terminate thread %p", this);
+   }
+@@ -1536,6 +1552,8 @@
+   // Record real stack base and size.
+   this->record_stack_base_and_size();
+ 
++  this->initialize_coroutine_support();
++
+   // Initialize thread local storage; set before calling MutexLocker
+   this->initialize_thread_local_storage();
+ 
+@@ -2480,6 +2498,12 @@
+     frame* fr = fst.current();
+     f(fr, fst.register_map());
+   }
++  // traverse the coroutine stack frames
++  Coroutine* current = _coroutine_list;
++  do {
++    current->frames_do(f);
++    current = current->next();
++  } while (current != _coroutine_list);
+ }
+ 
+ 
+@@ -2636,6 +2660,13 @@
+       fst.current()->oops_do(f, cf, fst.register_map());
+     }
+   }
++  
++
++  Coroutine* current = _coroutine_list;
++  do {
++    current->oops_do(f, cf);
++    current = current->next();
++  } while (current != _coroutine_list);
+ 
+   // callee_target is never live across a gc point so NULL it here should
+   // it still contain a methdOop.
+@@ -2677,6 +2708,13 @@
+       fst.current()->nmethods_do(cf);
+     }
+   }
++
++  Coroutine* current = _coroutine_list;
++  do {
++    current->nmethods_do(cf);
++    current = current->next();
++  } while (current != _coroutine_list);
++
+ }
+ 
+ // Printing
+@@ -3243,6 +3281,7 @@
+   // stacksize. This adjusted size is what is used to figure the placement
+   // of the guard pages.
+   main_thread->record_stack_base_and_size();
++  main_thread->initialize_coroutine_support();
+   main_thread->initialize_thread_local_storage();
+ 
+   main_thread->set_active_handles(JNIHandleBlock::allocate_block());
+@@ -4552,3 +4591,9 @@
+   VMThread* thread = VMThread::vm_thread();
+   if (thread != NULL) thread->verify();
+ }
++
++
++void JavaThread::initialize_coroutine_support() {
++  CoroutineStack::create_thread_stack(this)->insert_into_list(_coroutine_stack_list);
++  Coroutine::create_thread_coroutine(this, _coroutine_stack_list)->insert_into_list(_coroutine_list);
++}
+diff --git a/src/share/vm/runtime/thread.hpp b/src/share/vm/runtime/thread.hpp
+--- a/src/share/vm/runtime/thread.hpp
++++ b/src/share/vm/runtime/thread.hpp
+@@ -82,6 +82,9 @@
+ 
+ class WorkerThread;
+ 
++class Coroutine;
++class CoroutineStack;
++
+ // Class hierarchy
+ // - Thread
+ //   - NamedThread
+@@ -583,6 +586,10 @@
+   void leaving_jvmti_env_iteration()             { --_jvmti_env_iteration_count; }
+   bool is_inside_jvmti_env_iteration()           { return _jvmti_env_iteration_count > 0; }
+ 
++  static ByteSize resource_area_offset()         { return byte_offset_of(Thread, _resource_area); }
++  static ByteSize handle_area_offset()           { return byte_offset_of(Thread, _handle_area); }
++  static ByteSize last_handle_mark_offset()      { return byte_offset_of(Thread, _last_handle_mark); }
++
+   // Code generation
+   static ByteSize exception_file_offset()        { return byte_offset_of(Thread, _exception_file   ); }
+   static ByteSize exception_line_offset()        { return byte_offset_of(Thread, _exception_line   ); }
+@@ -897,6 +904,26 @@
+   // This is set to popframe_pending to signal that top Java frame should be popped immediately
+   int _popframe_condition;
+ 
++  // coroutine support
++  CoroutineStack*   _coroutine_stack_cache;
++  uintx             _coroutine_stack_cache_size;
++  CoroutineStack*   _coroutine_stack_list;
++  Coroutine*        _coroutine_list;
++
++  intptr_t          _coroutine_temp;
++
++ public:
++  CoroutineStack*& coroutine_stack_cache()       { return _coroutine_stack_cache; }
++  uintx& coroutine_stack_cache_size()            { return _coroutine_stack_cache_size; }
++  CoroutineStack*& coroutine_stack_list()        { return _coroutine_stack_list; }
++  Coroutine*& coroutine_list()                   { return _coroutine_list; }
++
++  static ByteSize coroutine_temp_offset()        { return byte_offset_of(JavaThread, _coroutine_temp); }
++  
++  void initialize_coroutine_support();
++
++ private:
++
+ #ifndef PRODUCT
+   int _jmp_ring_index;
+   struct {
+@@ -1316,6 +1343,9 @@
+   static ByteSize is_method_handle_return_offset() { return byte_offset_of(JavaThread, _is_method_handle_return); }
+   static ByteSize stack_guard_state_offset()     { return byte_offset_of(JavaThread, _stack_guard_state   ); }
+   static ByteSize suspend_flags_offset()         { return byte_offset_of(JavaThread, _suspend_flags       ); }
++#ifdef ASSERT
++  static ByteSize java_call_counter_offset()     { return byte_offset_of(JavaThread, _java_call_counter); }
++#endif
+ 
+   static ByteSize do_not_unlock_if_synchronized_offset() { return byte_offset_of(JavaThread, _do_not_unlock_if_synchronized); }
+   static ByteSize should_post_on_exceptions_flag_offset() {
+diff --git a/src/share/vm/runtime/threadLocalStorage.cpp b/src/share/vm/runtime/threadLocalStorage.cpp
+--- a/src/share/vm/runtime/threadLocalStorage.cpp
++++ b/src/share/vm/runtime/threadLocalStorage.cpp
+@@ -57,6 +57,14 @@
+   guarantee(get_thread_slow() == thread, "must be the same thread, slowly");
+ }
+ 
++void ThreadLocalStorage::add_coroutine_stack(Thread* thread, address stack_base, size_t stack_size) {
++  pd_add_coroutine_stack(thread, stack_base, stack_size);
++}
++
++void ThreadLocalStorage::remove_coroutine_stack(Thread* thread, address stack_base, size_t stack_size) {
++  pd_remove_coroutine_stack(thread, stack_base, stack_size);
++}
++
+ void ThreadLocalStorage::init() {
+   assert(!is_initialized(),
+          "More than one attempt to initialize threadLocalStorage");
+diff --git a/src/share/vm/runtime/threadLocalStorage.hpp b/src/share/vm/runtime/threadLocalStorage.hpp
+--- a/src/share/vm/runtime/threadLocalStorage.hpp
++++ b/src/share/vm/runtime/threadLocalStorage.hpp
+@@ -43,6 +43,9 @@
+   static Thread* get_thread_slow();
+   static void    invalidate_all() { pd_invalidate_all(); }
+ 
++  static void    add_coroutine_stack(Thread* thread, address stack_base, size_t stack_size);
++  static void    remove_coroutine_stack(Thread* thread, address stack_base, size_t stack_size);
++
+   // Machine dependent stuff
+ #ifdef TARGET_OS_ARCH_linux_x86
+ # include "threadLS_linux_x86.hpp"
+@@ -94,6 +97,10 @@
+   // Processor dependent parts of set_thread and initialization
+   static void pd_set_thread(Thread* thread);
+   static void pd_init();
++
++  static void pd_add_coroutine_stack(Thread* thread, address stack_base, size_t stack_size);
++  static void pd_remove_coroutine_stack(Thread* thread, address stack_base, size_t stack_size);
++
+   // Invalidate any thread cacheing or optimization schemes.
+   static void pd_invalidate_all();
+ 
+diff --git a/src/share/vm/utilities/debug.cpp b/src/share/vm/utilities/debug.cpp
+--- a/src/share/vm/utilities/debug.cpp
++++ b/src/share/vm/utilities/debug.cpp
+@@ -106,6 +106,16 @@
+   if (BreakAtWarning) BREAKPOINT;
+ }
+ 
++void warning_fixed_args(const char* message) {
++  // In case error happens before init or during shutdown
++  if (tty == NULL) ostream_init();
++
++  tty->print("%s warning: ", VM_Version::vm_name());
++  tty->print_cr(message);
++  if (BreakAtWarning) BREAKPOINT;
++}
++
++
+ #ifndef PRODUCT
+ 
+ #define is_token_break(ch) (isspace(ch) || (ch) == ',')
+diff --git a/src/share/vm/utilities/debug.hpp b/src/share/vm/utilities/debug.hpp
+--- a/src/share/vm/utilities/debug.hpp
++++ b/src/share/vm/utilities/debug.hpp
+@@ -201,6 +201,7 @@
+ void report_untested(const char* file, int line, const char* message);
+ 
+ void warning(const char* format, ...);
++void warning_fixed_args(const char* message);
+ 
+ // out of shared space reporting
+ enum SharedSpaceType {
--- a/coro-standalone.patch	Mon Jul 23 10:36:37 2012 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,189 +0,0 @@
-diff --git a/src/cpu/x86/vm/frame_x86.cpp b/src/cpu/x86/vm/frame_x86.cpp
---- a/src/cpu/x86/vm/frame_x86.cpp
-+++ b/src/cpu/x86/vm/frame_x86.cpp
-@@ -305,7 +305,8 @@
- }
- 
- BasicObjectLock* frame::interpreter_frame_monitor_end() const {
--  BasicObjectLock* result = (BasicObjectLock*) *addr_at(interpreter_frame_monitor_block_top_offset);
-+  intptr_t* original = *(intptr_t**)addr_at(interpreter_frame_monitor_block_top_offset);
-+  BasicObjectLock* result = (BasicObjectLock*) (original + _displacement);
-   // make sure the pointer points inside the frame
-   assert(sp() <= (intptr_t*) result, "monitor end should be above the stack pointer");
-   assert((intptr_t*) result < fp(),  "monitor end should be strictly below the frame pointer");
-@@ -370,10 +371,10 @@
-   intptr_t* sender_sp = this->sender_sp();
- 
-   // This is the sp before any possible extension (adapter/locals).
--  intptr_t* unextended_sp = interpreter_frame_sender_sp();
-+  intptr_t* unextended_sp = interpreter_frame_sender_sp() + _displacement;
- 
-   // Stored FP.
--  intptr_t* saved_fp = link();
-+  intptr_t* saved_fp = link() + _displacement;
- 
-   address sender_pc = this->sender_pc();
-   CodeBlob* sender_cb = CodeCache::find_blob_unsafe(sender_pc);
-@@ -419,7 +420,7 @@
-   }
- #endif // COMPILER2
- 
--  return frame(sender_sp, unextended_sp, saved_fp, sender_pc);
-+  return frame(sender_sp, unextended_sp, saved_fp, sender_pc, _displacement);
- }
- 
- 
-@@ -438,7 +439,7 @@
- 
-   // This is the saved value of EBP which may or may not really be an FP.
-   // It is only an FP if the sender is an interpreter frame (or C1?).
--  intptr_t* saved_fp = (intptr_t*) *(sender_sp - frame::sender_sp_offset);
-+  intptr_t* saved_fp = (intptr_t*) *(sender_sp - frame::sender_sp_offset) + _displacement;
- 
-   // If we are returning to a compiled MethodHandle call site, the
-   // saved_fp will in fact be a saved value of the unextended SP.  The
-@@ -488,7 +489,7 @@
-   }
- 
-   assert(sender_sp != sp(), "must have changed");
--  return frame(sender_sp, unextended_sp, saved_fp, sender_pc);
-+  return frame(sender_sp, unextended_sp, saved_fp, sender_pc, _displacement);
- }
- 
- 
-@@ -508,7 +509,7 @@
-   }
-   // Must be native-compiled frame, i.e. the marshaling code for native
-   // methods that exists in the core system.
--  return frame(sender_sp(), link(), sender_pc());
-+  return frame(sender_sp(), link(), sender_pc(), _displacement);
- }
- 
- 
-diff --git a/src/cpu/x86/vm/frame_x86.hpp b/src/cpu/x86/vm/frame_x86.hpp
---- a/src/cpu/x86/vm/frame_x86.hpp
-+++ b/src/cpu/x86/vm/frame_x86.hpp
-@@ -182,8 +182,12 @@
- 
-   frame(intptr_t* sp, intptr_t* fp, address pc);
- 
-+  frame(intptr_t* sp, intptr_t* fp, address pc, intptr_t displacement);
-+
-   frame(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, address pc);
- 
-+  frame(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, address pc, intptr_t displacement);
-+
-   frame(intptr_t* sp, intptr_t* fp);
- 
-   // accessors for the instance variables
-diff --git a/src/cpu/x86/vm/frame_x86.inline.hpp b/src/cpu/x86/vm/frame_x86.inline.hpp
---- a/src/cpu/x86/vm/frame_x86.inline.hpp
-+++ b/src/cpu/x86/vm/frame_x86.inline.hpp
-@@ -36,6 +36,7 @@
-   _fp = NULL;
-   _cb = NULL;
-   _deopt_state = unknown;
-+  _displacement = 0;
- }
- 
- inline frame::frame(intptr_t* sp, intptr_t* fp, address pc) {
-@@ -53,6 +54,25 @@
-   } else {
-     _deopt_state = not_deoptimized;
-   }
-+  _displacement = 0;
-+}
-+
-+inline frame::frame(intptr_t* sp, intptr_t* fp, address pc, intptr_t displacement) {
-+  _sp = sp;
-+  _unextended_sp = sp;
-+  _fp = fp;
-+  _pc = pc;
-+  assert(pc != NULL, "no pc?");
-+  _cb = CodeCache::find_blob(pc);
-+
-+  address original_pc = nmethod::get_deopt_original_pc(this);
-+  if (original_pc != NULL) {
-+    _pc = original_pc;
-+    _deopt_state = is_deoptimized;
-+  } else {
-+    _deopt_state = not_deoptimized;
-+  }
-+  _displacement = displacement;
- }
- 
- inline frame::frame(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, address pc) {
-@@ -71,6 +91,26 @@
-   } else {
-     _deopt_state = not_deoptimized;
-   }
-+  _displacement = 0;
-+}
-+
-+inline frame::frame(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, address pc, intptr_t displacement) {
-+  _sp = sp;
-+  _unextended_sp = unextended_sp;
-+  _fp = fp;
-+  _pc = pc;
-+  assert(pc != NULL, "no pc?");
-+  _cb = CodeCache::find_blob(pc);
-+
-+  address original_pc = nmethod::get_deopt_original_pc(this);
-+  if (original_pc != NULL) {
-+    _pc = original_pc;
-+    assert(((nmethod*)_cb)->code_contains(_pc), "original PC must be in nmethod");
-+    _deopt_state = is_deoptimized;
-+  } else {
-+    _deopt_state = not_deoptimized;
-+  }
-+  _displacement = displacement;
- }
- 
- inline frame::frame(intptr_t* sp, intptr_t* fp) {
-@@ -99,6 +139,7 @@
-   } else {
-     _deopt_state = not_deoptimized;
-   }
-+  _displacement = 0;
- }
- 
- // Accessors
-@@ -202,7 +243,7 @@
- }
- 
- inline intptr_t* frame::interpreter_frame_last_sp() const {
--  return *(intptr_t**)addr_at(interpreter_frame_last_sp_offset);
-+  return *(intptr_t**)addr_at(interpreter_frame_last_sp_offset) + _displacement;
- }
- 
- inline intptr_t* frame::interpreter_frame_bcx_addr() const {
-@@ -268,7 +309,7 @@
- // Entry frames
- 
- inline JavaCallWrapper* frame::entry_frame_call_wrapper() const {
-- return (JavaCallWrapper*)at(entry_frame_call_wrapper_offset);
-+ return (JavaCallWrapper*)((intptr_t*)at(entry_frame_call_wrapper_offset) + _displacement);
- }
- 
- 
-diff --git a/src/share/vm/prims/nativeLookup.cpp b/src/share/vm/prims/nativeLookup.cpp
---- a/src/share/vm/prims/nativeLookup.cpp
-+++ b/src/share/vm/prims/nativeLookup.cpp
-@@ -105,6 +105,7 @@
- }
- 
- extern "C" {
-+  void JNICALL JVM_RegisterCoroutineSupportMethods(JNIEnv* env, jclass corocls);
-   void JNICALL JVM_RegisterUnsafeMethods(JNIEnv *env, jclass unsafecls);
-   void JNICALL JVM_RegisterMethodHandleMethods(JNIEnv *env, jclass unsafecls);
-   void JNICALL JVM_RegisterPerfMethods(JNIEnv *env, jclass perfclass);
-@@ -120,7 +121,8 @@
- 
-   { CC"Java_sun_misc_Unsafe_registerNatives",                      NULL, FN_PTR(JVM_RegisterUnsafeMethods)       },
-   { CC"Java_java_lang_invoke_MethodHandleNatives_registerNatives", NULL, FN_PTR(JVM_RegisterMethodHandleMethods) },
--  { CC"Java_sun_misc_Perf_registerNatives",                        NULL, FN_PTR(JVM_RegisterPerfMethods)         }
-+  { CC"Java_sun_misc_Perf_registerNatives",                        NULL, FN_PTR(JVM_RegisterPerfMethods)         },
-+  { CC"Java_java_dyn_CoroutineSupport_registerNatives",            NULL, FN_PTR(JVM_RegisterCoroutineSupportMethods)}
- };
- 
- static address lookup_special_native(char* jni_name) {
--- a/coro.patch	Mon Jul 23 10:36:37 2012 -0700
+++ b/coro.patch	Thu Jul 26 17:10:47 2012 +0200
@@ -1,15 +1,15 @@
 diff --git a/src/cpu/x86/vm/assembler_x86.cpp b/src/cpu/x86/vm/assembler_x86.cpp
 --- a/src/cpu/x86/vm/assembler_x86.cpp
 +++ b/src/cpu/x86/vm/assembler_x86.cpp
-@@ -6003,7 +6003,7 @@
- 
+@@ -6074,7 +6074,7 @@
+   andq(rsp, -16);     // align stack as required by push_CPU_state and call
    push_CPU_state();   // keeps alignment at 16 bytes
    lea(c_rarg0, ExternalAddress((address) msg));
 -  call_VM_leaf(CAST_FROM_FN_PTR(address, warning), c_rarg0);
 +  call_VM_leaf(CAST_FROM_FN_PTR(address, warning_fixed_args), c_rarg0);
    pop_CPU_state();
-   pop(rsp);
- }
+   mov(rsp, rbp);
+   pop(rbp);
 diff --git a/src/cpu/x86/vm/assembler_x86.hpp b/src/cpu/x86/vm/assembler_x86.hpp
 --- a/src/cpu/x86/vm/assembler_x86.hpp
 +++ b/src/cpu/x86/vm/assembler_x86.hpp
@@ -25,12 +25,11 @@
 diff --git a/src/cpu/x86/vm/frame_x86.cpp b/src/cpu/x86/vm/frame_x86.cpp
 --- a/src/cpu/x86/vm/frame_x86.cpp
 +++ b/src/cpu/x86/vm/frame_x86.cpp
-@@ -310,12 +310,11 @@
+@@ -310,11 +310,11 @@
  }
  
  BasicObjectLock* frame::interpreter_frame_monitor_end() const {
--  intptr_t* original = *(intptr_t**)addr_at(interpreter_frame_monitor_block_top_offset);
--  BasicObjectLock* result = (BasicObjectLock*) (original + _displacement);
+-  BasicObjectLock* result = (BasicObjectLock*) *addr_at(interpreter_frame_monitor_block_top_offset);
 +  intptr_t* result = *(intptr_t**)addr_at(interpreter_frame_monitor_block_top_offset);
    // make sure the pointer points inside the frame
 -  assert(sp() <= (intptr_t*) result, "monitor end should be above the stack pointer");
@@ -41,7 +40,7 @@
  }
  
  void frame::interpreter_frame_set_monitor_end(BasicObjectLock* value) {
-@@ -381,13 +380,13 @@
+@@ -380,13 +380,13 @@
      // saved_fp.
      if (sender_nm->is_deopt_mh_entry(_pc)) {
        DEBUG_ONLY(verify_deopt_mh_original_pc(sender_nm, _fp));
@@ -57,16 +56,52 @@
      }
    }
  }
-@@ -452,7 +451,7 @@
+@@ -423,7 +423,7 @@
+   intptr_t* sender_sp = this->sender_sp();
+ 
+   // This is the sp before any possible extension (adapter/locals).
+-  intptr_t* unextended_sp = interpreter_frame_sender_sp();
++  intptr_t* unextended_sp = interpreter_frame_sender_sp() + _displacement;
+ 
+ #ifdef COMPILER2
+   if (map->update_map()) {
+@@ -431,7 +431,7 @@
+   }
+ #endif // COMPILER2
+ 
+-  return frame(sender_sp, unextended_sp, link(), sender_pc());
++  return frame(sender_sp, unextended_sp, link(), sender_pc(), _displacement);
+ }
+ 
+ 
+@@ -450,7 +450,7 @@
  
    // This is the saved value of EBP which may or may not really be an FP.
    // It is only an FP if the sender is an interpreter frame (or C1?).
--  intptr_t** saved_fp_addr = (intptr_t**) (sender_sp - frame::sender_sp_offset) + _displacement;
+-  intptr_t** saved_fp_addr = (intptr_t**) (sender_sp - frame::sender_sp_offset);
 +  intptr_t** saved_fp_addr = (intptr_t**) (sender_sp - frame::sender_sp_offset)/* + _displacement*/;
  
    if (map->update_map()) {
      // Tell GC to use argument oopmaps for some runtime stubs that need it.
-@@ -521,7 +520,7 @@
+@@ -468,7 +468,7 @@
+   }
+ 
+   assert(sender_sp != sp(), "must have changed");
+-  return frame(sender_sp, unextended_sp, *saved_fp_addr, sender_pc);
++  return frame(sender_sp, unextended_sp, *saved_fp_addr, sender_pc, _displacement);
+ }
+ 
+ 
+@@ -488,7 +488,7 @@
+   }
+   // Must be native-compiled frame, i.e. the marshaling code for native
+   // methods that exists in the core system.
+-  return frame(sender_sp(), link(), sender_pc());
++  return frame(sender_sp(), link(), sender_pc(), _displacement);
+ }
+ 
+ 
+@@ -518,7 +518,7 @@
    if (sp() == 0 || (intptr_t(sp()) & (wordSize-1)) != 0) {
      return false;
    }
@@ -75,7 +110,7 @@
      return false;
    }
    // These are hacks to keep us out of trouble.
-@@ -541,7 +540,7 @@
+@@ -538,7 +538,7 @@
  
    // stack frames shouldn't be much larger than max_stack elements
  
@@ -84,7 +119,7 @@
      return false;
    }
  
-@@ -564,7 +563,7 @@
+@@ -561,7 +561,7 @@
  
    address locals =  (address) *interpreter_frame_locals_addr();
  
@@ -93,41 +128,57 @@
  
    // We'd have to be pretty unlucky to be mislead at this point
  
+diff --git a/src/cpu/x86/vm/frame_x86.hpp b/src/cpu/x86/vm/frame_x86.hpp
+--- a/src/cpu/x86/vm/frame_x86.hpp
++++ b/src/cpu/x86/vm/frame_x86.hpp
+@@ -183,8 +183,12 @@
+ 
+   frame(intptr_t* sp, intptr_t* fp, address pc);
+ 
++  frame(intptr_t* sp, intptr_t* fp, address pc, intptr_t displacement);
++
+   frame(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, address pc);
+ 
++  frame(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, address pc, intptr_t displacement);
++
+   frame(intptr_t* sp, intptr_t* fp);
+ 
+   // accessors for the instance variables
 diff --git a/src/cpu/x86/vm/frame_x86.inline.hpp b/src/cpu/x86/vm/frame_x86.inline.hpp
 --- a/src/cpu/x86/vm/frame_x86.inline.hpp
 +++ b/src/cpu/x86/vm/frame_x86.inline.hpp
-@@ -40,6 +40,7 @@
+@@ -36,9 +36,30 @@
+   _fp = NULL;
+   _cb = NULL;
+   _deopt_state = unknown;
++  _displacement = 0;
  }
  
  inline frame::frame(intptr_t* sp, intptr_t* fp, address pc) {
 +  _displacement = 0;
-   _sp = sp;
-   _unextended_sp = sp;
-   _fp = fp;
-@@ -55,16 +56,17 @@
-   } else {
-     _deopt_state = not_deoptimized;
-   }
--  _displacement = 0;
- }
- 
- inline frame::frame(intptr_t* sp, intptr_t* fp, address pc, intptr_t displacement) {
++  _sp = sp;
++  _unextended_sp = sp;
++  _fp = fp;
++  _pc = pc;
++  assert(pc != NULL, "no pc?");
++  _cb = CodeCache::find_blob(pc);
++  adjust_unextended_sp();
++
++  address original_pc = nmethod::get_deopt_original_pc(this);
++  if (original_pc != NULL) {
++    _pc = original_pc;
++    _deopt_state = is_deoptimized;
++  } else {
++    _deopt_state = not_deoptimized;
++  }
++}
++
++inline frame::frame(intptr_t* sp, intptr_t* fp, address pc, intptr_t displacement) {
 +  _displacement = displacement;
    _sp = sp;
    _unextended_sp = sp;
    _fp = fp;
-   _pc = pc;
-   assert(pc != NULL, "no pc?");
-   _cb = CodeCache::find_blob(pc);
-+  adjust_unextended_sp();
- 
-   address original_pc = nmethod::get_deopt_original_pc(this);
-   if (original_pc != NULL) {
-@@ -73,10 +75,10 @@
-   } else {
-     _deopt_state = not_deoptimized;
-   }
--  _displacement = displacement;
+@@ -57,6 +78,7 @@
  }
  
  inline frame::frame(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, address pc) {
@@ -135,123 +186,52 @@
    _sp = sp;
    _unextended_sp = unextended_sp;
    _fp = fp;
-@@ -93,16 +95,17 @@
-   } else {
-     _deopt_state = not_deoptimized;
+@@ -75,7 +97,28 @@
    }
--  _displacement = 0;
  }
  
- inline frame::frame(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, address pc, intptr_t displacement) {
++inline frame::frame(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, address pc, intptr_t displacement) {
 +  _displacement = displacement;
-   _sp = sp;
-   _unextended_sp = unextended_sp;
-   _fp = fp;
-   _pc = pc;
-   assert(pc != NULL, "no pc?");
-   _cb = CodeCache::find_blob(pc);
++  _sp = sp;
++  _unextended_sp = unextended_sp;
++  _fp = fp;
++  _pc = pc;
++  assert(pc != NULL, "no pc?");
++  _cb = CodeCache::find_blob(pc);
 +  adjust_unextended_sp();
- 
-   address original_pc = nmethod::get_deopt_original_pc(this);
-   if (original_pc != NULL) {
-@@ -112,10 +115,10 @@
-   } else {
-     _deopt_state = not_deoptimized;
-   }
--  _displacement = displacement;
- }
- 
++
++  address original_pc = nmethod::get_deopt_original_pc(this);
++  if (original_pc != NULL) {
++    _pc = original_pc;
++    assert(((nmethod*)_cb)->code_contains(_pc), "original PC must be in nmethod");
++    _deopt_state = is_deoptimized;
++  } else {
++    _deopt_state = not_deoptimized;
++  }
++}
++
  inline frame::frame(intptr_t* sp, intptr_t* fp) {
 +  _displacement = 0;
    _sp = sp;
    _unextended_sp = sp;
    _fp = fp;
-@@ -142,7 +145,6 @@
-   } else {
-     _deopt_state = not_deoptimized;
-   }
--  _displacement = 0;
+@@ -205,7 +248,7 @@
  }
  
- // Accessors
-diff --git a/src/cpu/x86/vm/methodHandles_x86.cpp b/src/cpu/x86/vm/methodHandles_x86.cpp
---- a/src/cpu/x86/vm/methodHandles_x86.cpp
-+++ b/src/cpu/x86/vm/methodHandles_x86.cpp
-@@ -81,7 +81,7 @@
-   RicochetFrame* f = RicochetFrame::from_frame(fr);
-   if (map->update_map())
-     frame::update_map_with_saved_link(map, &f->_sender_link);
--  return frame(f->extended_sender_sp(), f->exact_sender_sp(), f->sender_link(), f->sender_pc());
-+  return frame(f->extended_sender_sp(), f->exact_sender_sp() + fr._displacement, f->sender_link(), f->sender_pc(), fr._displacement);
+ inline intptr_t* frame::interpreter_frame_last_sp() const {
+-  return *(intptr_t**)addr_at(interpreter_frame_last_sp_offset);
++  return *(intptr_t**)addr_at(interpreter_frame_last_sp_offset) + _displacement;
  }
  
- void MethodHandles::ricochet_frame_oops_do(const frame& fr, OopClosure* blk, const RegisterMap* reg_map) {
-@@ -106,10 +106,10 @@
-   assert(!invoker->is_static(), "must have MH argument");
-   int slot_count = invoker->size_of_parameters();
-   assert(slot_count >= 1, "must include 'this'");
--  intptr_t* base = f->saved_args_base();
-+  intptr_t* base = f->saved_args_base() + fr._displacement;
-   intptr_t* retval = NULL;
-   if (f->has_return_value_slot())
--    retval = f->return_value_slot_addr();
-+    retval = f->return_value_slot_addr(fr._displacement);
-   int slot_num = slot_count;
-   intptr_t* loc = &base[slot_num -= 1];
-   //blk->do_oop((oop*) loc);   // original target, which is irrelevant
-@@ -412,7 +412,7 @@
-   assert(ebp_off + wordSize*frame::return_addr_offset                   == sender_pc_offset_in_bytes(), "");
+ inline intptr_t* frame::interpreter_frame_bcx_addr() const {
+@@ -271,7 +314,7 @@
+ // Entry frames
+ 
+ inline JavaCallWrapper* frame::entry_frame_call_wrapper() const {
+- return (JavaCallWrapper*)at(entry_frame_call_wrapper_offset);
++ return (JavaCallWrapper*)((intptr_t*)at(entry_frame_call_wrapper_offset) + _displacement);
  }
  
--void MethodHandles::RicochetFrame::verify() const {
-+void MethodHandles::RicochetFrame::verify(intptr_t  displacement) const {
-   verify_offsets();
-   assert(magic_number_1() == MAGIC_NUMBER_1, err_msg(PTR_FORMAT " == " PTR_FORMAT, magic_number_1(), MAGIC_NUMBER_1));
-   assert(magic_number_2() == MAGIC_NUMBER_2, err_msg(PTR_FORMAT " == " PTR_FORMAT, magic_number_2(), MAGIC_NUMBER_2));
-@@ -430,7 +430,7 @@
-          conv_op == java_lang_invoke_AdapterMethodHandle::OP_PRIM_TO_REF,
-          "must be a sane conversion");
-   if (has_return_value_slot()) {
--    assert(*return_value_slot_addr() == RETURN_VALUE_PLACEHOLDER, "");
-+    assert(*return_value_slot_addr(displacement) == RETURN_VALUE_PLACEHOLDER, "");
-   }
- }
- #endif //PRODUCT
-diff --git a/src/cpu/x86/vm/methodHandles_x86.hpp b/src/cpu/x86/vm/methodHandles_x86.hpp
---- a/src/cpu/x86/vm/methodHandles_x86.hpp
-+++ b/src/cpu/x86/vm/methodHandles_x86.hpp
-@@ -146,9 +146,9 @@
-   bool has_return_value_slot() const {
-     return return_value_type() != T_VOID;
-   }
--  intptr_t* return_value_slot_addr() const {
-+  intptr_t* return_value_slot_addr(intptr_t  displacement) const {
-     assert(has_return_value_slot(), "");
--    return saved_arg_slot_addr(return_value_slot_number());
-+    return saved_arg_slot_addr(return_value_slot_number()) + displacement;
-   }
-   intptr_t* saved_target_slot_addr() const {
-     return saved_arg_slot_addr(saved_args_length());
-@@ -192,7 +192,7 @@
-   enum { RETURN_VALUE_PLACEHOLDER = (NOT_DEBUG(0) DEBUG_ONLY(42)) };
- 
-   static void verify_offsets() NOT_DEBUG_RETURN;
--  void verify() const NOT_DEBUG_RETURN; // check for MAGIC_NUMBER, etc.
-+  void verify(intptr_t  _displacement) const NOT_DEBUG_RETURN; // check for MAGIC_NUMBER, etc.
-   void zap_arguments() NOT_DEBUG_RETURN;
- 
-   static void generate_ricochet_blob(MacroAssembler* _masm,
-@@ -217,9 +217,9 @@
-   }
- 
-   static RicochetFrame* from_frame(const frame& fr) {
--    address bp = (address) fr.fp();
-+    address bp = (address) (fr.fp() + fr._displacement);
-     RicochetFrame* rf = (RicochetFrame*)(bp - sender_link_offset_in_bytes());
--    rf->verify();
-+    rf->verify(fr._displacement);
-     return rf;
-   }
  
 diff --git a/src/cpu/x86/vm/sharedRuntime_x86_32.cpp b/src/cpu/x86/vm/sharedRuntime_x86_32.cpp
 --- a/src/cpu/x86/vm/sharedRuntime_x86_32.cpp
@@ -265,17 +245,17 @@
  #define __ masm->
  
  const int StackAlignmentInSlots = StackAlignmentInBytes / VMRegImpl::stack_slot_size;
-@@ -1294,6 +1296,9 @@
+@@ -1434,6 +1436,9 @@
+                                                  receiver_reg, member_reg, /*for_compiler_entry:*/ true);
  }
  
- 
 +void create_prepareSwitch_contents(MacroAssembler *masm, int start, OopMapSet* oop_maps, int &stack_slots, int total_in_args, BasicType *in_sig_bt, VMRegPair *in_regs, BasicType ret_type);
 +void create_switchTo_contents(MacroAssembler *masm, int start, OopMapSet* oop_maps, int &stack_slots, int total_in_args, BasicType *in_sig_bt, VMRegPair *in_regs, BasicType ret_type, bool terminate);
 +
  // ---------------------------------------------------------------------------
  // Generate a native wrapper for a given method.  The method takes arguments
  // in the Java compiled code convention, marshals them to the native
-@@ -1597,6 +1602,18 @@
+@@ -1760,6 +1765,18 @@
      // need a 5 byte instruction to allow MT safe patching to non-entrant
      __ fat_nop();
    }
@@ -294,7 +274,7 @@
  
    // Generate a new frame for the wrapper.
    __ enter();
-@@ -3297,3 +3314,384 @@
+@@ -3460,3 +3477,384 @@
    // frame_size_words or bytes??
    return RuntimeStub::new_runtime_stub(name, &buffer, frame_complete, frame_size_words, oop_maps, true);
  }
@@ -694,9 +674,9 @@
  #define __ masm->
  
  const int StackAlignmentInSlots = StackAlignmentInBytes / VMRegImpl::stack_slot_size;
-@@ -1533,6 +1538,10 @@
- };
- 
+@@ -1681,6 +1686,10 @@
+                                                  receiver_reg, member_reg, /*for_compiler_entry:*/ true);
+ }
  
 +void create_prepareSwitch_contents(MacroAssembler *masm, int start, OopMapSet* oop_maps, int &stack_slots, int total_in_args, BasicType *in_sig_bt, VMRegPair *in_regs, BasicType ret_type);
 +void create_switchTo_contents(MacroAssembler *masm, int start, OopMapSet* oop_maps, int &stack_slots, int total_in_args, BasicType *in_sig_bt, VMRegPair *in_regs, BasicType ret_type, bool terminate);
@@ -705,7 +685,7 @@
  // ---------------------------------------------------------------------------
  // Generate a native wrapper for a given method.  The method takes arguments
  // in the Java compiled code convention, marshals them to the native
-@@ -1777,6 +1786,17 @@
+@@ -1971,6 +1980,17 @@
      __ fat_nop();
    }
  
@@ -723,7 +703,7 @@
    // Generate a new frame for the wrapper.
    __ enter();
    // -2 because return address is already present and so is saved rbp
-@@ -2290,6 +2310,21 @@
+@@ -2484,6 +2504,21 @@
    }
  
    // Return
@@ -745,7 +725,7 @@
  
    __ ret(0);
  
-@@ -3857,3 +3892,466 @@
+@@ -4051,3 +4086,466 @@
    _exception_blob =  ExceptionBlob::create(&buffer, oop_maps, SimpleRuntimeFrame::framesize >> 1);
  }
  #endif // COMPILER2
@@ -1215,7 +1195,7 @@
 diff --git a/src/os/windows/vm/os_windows.cpp b/src/os/windows/vm/os_windows.cpp
 --- a/src/os/windows/vm/os_windows.cpp
 +++ b/src/os/windows/vm/os_windows.cpp
-@@ -2308,7 +2308,7 @@
+@@ -2324,7 +2324,7 @@
      bool in_java = thread->thread_state() == _thread_in_Java;
  
      // Handle potential stack overflows up front.
@@ -1315,7 +1295,7 @@
 diff --git a/src/share/vm/adlc/output_h.cpp b/src/share/vm/adlc/output_h.cpp
 --- a/src/share/vm/adlc/output_h.cpp
 +++ b/src/share/vm/adlc/output_h.cpp
-@@ -1884,6 +1884,7 @@
+@@ -1887,6 +1887,7 @@
      else if (instr->is_tls_instruction()) {
        // Special hack for tlsLoadP
        fprintf(fp,"  const Type            *bottom_type() const { return TypeRawPtr::BOTTOM; } // tlsLoadP\n");
@@ -1326,7 +1306,7 @@
 diff --git a/src/share/vm/classfile/javaClasses.cpp b/src/share/vm/classfile/javaClasses.cpp
 --- a/src/share/vm/classfile/javaClasses.cpp
 +++ b/src/share/vm/classfile/javaClasses.cpp
-@@ -2992,6 +2992,99 @@
+@@ -2896,6 +2896,99 @@
    compute_offset(_limit_offset, k, vmSymbols::limit_name(), vmSymbols::int_signature());
  }
  
@@ -1426,7 +1406,7 @@
  void java_util_concurrent_locks_AbstractOwnableSynchronizer::initialize(TRAPS) {
    if (_owner_offset != 0) return;
  
-@@ -3099,6 +3192,9 @@
+@@ -2999,6 +3092,9 @@
  
    // generated interpreter code wants to know about the offsets we just computed:
    AbstractAssembler::update_delayed_values();
@@ -1439,9 +1419,9 @@
 diff --git a/src/share/vm/classfile/javaClasses.hpp b/src/share/vm/classfile/javaClasses.hpp
 --- a/src/share/vm/classfile/javaClasses.hpp
 +++ b/src/share/vm/classfile/javaClasses.hpp
-@@ -1430,6 +1430,68 @@
-   MEMBERNAME_INJECTED_FIELDS(macro)         \
-   METHODTYPEFORM_INJECTED_FIELDS(macro)
+@@ -1287,6 +1287,68 @@
+   CLASS_INJECTED_FIELDS(macro)              \
+   MEMBERNAME_INJECTED_FIELDS(macro)
  
 +class java_dyn_CoroutineBase: AllStatic {
 +private:
@@ -1511,7 +1491,7 @@
 diff --git a/src/share/vm/classfile/systemDictionary.hpp b/src/share/vm/classfile/systemDictionary.hpp
 --- a/src/share/vm/classfile/systemDictionary.hpp
 +++ b/src/share/vm/classfile/systemDictionary.hpp
-@@ -183,6 +183,11 @@
+@@ -179,6 +179,11 @@
    template(Short_klass,                  java_lang_Short,                Pre) \
    template(Integer_klass,                java_lang_Integer,              Pre) \
    template(Long_klass,                   java_lang_Long,                 Pre) \
@@ -1526,7 +1506,7 @@
 diff --git a/src/share/vm/classfile/vmSymbols.hpp b/src/share/vm/classfile/vmSymbols.hpp
 --- a/src/share/vm/classfile/vmSymbols.hpp
 +++ b/src/share/vm/classfile/vmSymbols.hpp
-@@ -400,6 +400,7 @@
+@@ -391,6 +391,7 @@
    template(void_float_signature,                      "()F")                                      \
    template(void_double_signature,                     "()D")                                      \
    template(int_void_signature,                        "(I)V")                                     \
@@ -1534,7 +1514,7 @@
    template(int_int_signature,                         "(I)I")                                     \
    template(char_char_signature,                       "(C)C")                                     \
    template(short_short_signature,                     "(S)S")                                     \
-@@ -517,7 +518,7 @@
+@@ -508,7 +509,7 @@
    template(createGarbageCollectorMBean_signature,      "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/management/GarbageCollectorMBean;") \
    template(trigger_name,                               "trigger")                                                 \
    template(clear_name,                                 "clear")                                                   \
@@ -1543,7 +1523,7 @@
    template(startAgent_name,                            "startAgent")                                              \
    template(startRemoteAgent_name,                      "startRemoteManagementAgent")                              \
    template(startLocalAgent_name,                       "startLocalManagementAgent")                               \
-@@ -539,7 +540,7 @@
+@@ -530,7 +531,7 @@
    template(addThreadDumpForMonitors_name,              "addThreadDumpForMonitors")                                \
    template(addThreadDumpForSynchronizers_name,         "addThreadDumpForSynchronizers")                           \
    template(addThreadDumpForMonitors_signature,         "(Ljava/lang/management/ThreadInfo;[Ljava/lang/Object;[I)V") \
@@ -1552,7 +1532,7 @@
                                                                                                                    \
    /* JVMTI/java.lang.instrument support and VM Attach mechanism */                                                \
    template(sun_misc_VMSupport,                         "sun/misc/VMSupport")                                      \
-@@ -550,6 +551,27 @@
+@@ -541,6 +542,27 @@
    template(serializeAgentPropertiesToByteArray_name,   "serializeAgentPropertiesToByteArray")                     \
    template(classRedefinedCount_name,                   "classRedefinedCount")                                     \
                                                                                                                    \
@@ -1580,7 +1560,7 @@
    /* trace signatures */                                                                                          \
    TRACE_TEMPLATES(template)                                                                                       \
                                                                                                                    \
-@@ -888,9 +910,22 @@
+@@ -879,9 +901,22 @@
     do_name(     prefetchReadStatic_name,                         "prefetchReadStatic")                                  \
    do_intrinsic(_prefetchWriteStatic,      sun_misc_Unsafe,        prefetchWriteStatic_name, prefetch_signature,  F_SN)  \
     do_name(     prefetchWriteStatic_name,                        "prefetchWriteStatic")                                 \
@@ -1699,7 +1679,7 @@
 diff --git a/src/share/vm/oops/methodOop.cpp b/src/share/vm/oops/methodOop.cpp
 --- a/src/share/vm/oops/methodOop.cpp
 +++ b/src/share/vm/oops/methodOop.cpp
-@@ -158,7 +158,8 @@
+@@ -154,7 +154,8 @@
  #ifdef ASSERT
    bool has_capability = myThread->is_VM_thread() ||
                          myThread->is_ConcurrentGC_thread() ||
@@ -1810,7 +1790,7 @@
 diff --git a/src/share/vm/prims/jni.cpp b/src/share/vm/prims/jni.cpp
 --- a/src/share/vm/prims/jni.cpp
 +++ b/src/share/vm/prims/jni.cpp
-@@ -5151,6 +5151,28 @@
+@@ -5152,6 +5152,28 @@
  
      // Check if we should compile all classes on bootclasspath
      NOT_PRODUCT(if (CompileTheWorld) ClassLoader::compile_the_world();)
@@ -1839,7 +1819,7 @@
      // Since this is not a JVM_ENTRY we have to set the thread state manually before leaving.
      ThreadStateTransition::transition_and_fence(thread, _thread_in_vm, _thread_in_native);
    } else {
-@@ -5281,7 +5303,7 @@
+@@ -5282,7 +5304,7 @@
    thread->set_thread_state(_thread_in_vm);
    // Must do this before initialize_thread_local_storage
    thread->record_stack_base_and_size();
@@ -1851,7 +1831,7 @@
 diff --git a/src/share/vm/prims/jvm.cpp b/src/share/vm/prims/jvm.cpp
 --- a/src/share/vm/prims/jvm.cpp
 +++ b/src/share/vm/prims/jvm.cpp
-@@ -2615,6 +2615,22 @@
+@@ -2620,6 +2620,22 @@
    HandleMark hm(THREAD);
    Handle obj(THREAD, thread->threadObj());
    JavaValue result(T_VOID);
@@ -1874,6 +1854,25 @@
    JavaCalls::call_virtual(&result,
                            obj,
                            KlassHandle(THREAD, SystemDictionary::Thread_klass()),
+diff --git a/src/share/vm/prims/nativeLookup.cpp b/src/share/vm/prims/nativeLookup.cpp
+--- a/src/share/vm/prims/nativeLookup.cpp
++++ b/src/share/vm/prims/nativeLookup.cpp
+@@ -118,6 +118,7 @@
+ }
+ 
+ extern "C" {
++  void JNICALL JVM_RegisterCoroutineSupportMethods(JNIEnv* env, jclass corocls);
+   void JNICALL JVM_RegisterUnsafeMethods(JNIEnv *env, jclass unsafecls);
+   void JNICALL JVM_RegisterMethodHandleMethods(JNIEnv *env, jclass unsafecls);
+   void JNICALL JVM_RegisterPerfMethods(JNIEnv *env, jclass perfclass);
+@@ -135,6 +136,7 @@
+   { CC"Java_sun_misc_Unsafe_registerNatives",                      NULL, FN_PTR(JVM_RegisterUnsafeMethods)       },
+   { CC"Java_java_lang_invoke_MethodHandleNatives_registerNatives", NULL, FN_PTR(JVM_RegisterMethodHandleMethods) },
+   { CC"Java_sun_misc_Perf_registerNatives",                        NULL, FN_PTR(JVM_RegisterPerfMethods)         },
++  { CC"Java_java_dyn_CoroutineSupport_registerNatives",            NULL, FN_PTR(JVM_RegisterCoroutineSupportMethods)},
+   { CC"Java_sun_hotspot_WhiteBox_registerNatives",                 NULL, FN_PTR(JVM_RegisterWhiteBoxMethods)     },
+ };
+ 
 diff --git a/src/share/vm/prims/unsafe.cpp b/src/share/vm/prims/unsafe.cpp
 --- a/src/share/vm/prims/unsafe.cpp
 +++ b/src/share/vm/prims/unsafe.cpp
@@ -1889,7 +1888,7 @@
  #include "runtime/globals.hpp"
  #include "runtime/interfaceSupport.hpp"
  #include "runtime/reflection.hpp"
-@@ -1289,6 +1291,414 @@
+@@ -1288,6 +1290,414 @@
    Prefetch::write(addr, (intx)offset);
  UNSAFE_END
  
@@ -2304,8 +2303,8 @@
  
  /// JVM_RegisterUnsafeMethods
  
-@@ -1584,6 +1994,33 @@
-     {CC"defineAnonymousClass", CC"("DAC_Args")"CLS,      FN_PTR(Unsafe_DefineAnonymousClass)},
+@@ -1587,6 +1997,33 @@
+     {CC"shouldBeInitialized",CC"("CLS")Z",               FN_PTR(Unsafe_ShouldBeInitialized)},
  };
  
 +#define COBA "Ljava/dyn/CoroutineBase;"
@@ -2338,7 +2337,7 @@
  #undef CC
  #undef FN_PTR
  
-@@ -1682,3 +2119,30 @@
+@@ -1694,3 +2131,30 @@
      guarantee(status == 0, "register unsafe natives");
    }
  JVM_END
@@ -2451,8 +2450,8 @@
 +
 +  // do not call JavaThread::current() here!
 +
-+  _thread->set_resource_area(new ResourceArea(32));
-+  _thread->set_handle_area(new HandleArea(NULL, 32));
++  _thread->set_resource_area(new (mtThread) ResourceArea(32));
++  _thread->set_handle_area(new (mtThread) HandleArea(NULL, 32));
 +
 +  // used to test validitity of stack trace backs
 +//  this->record_base_of_stack_pointer();
@@ -2678,7 +2677,7 @@
 +  assert((sizeof(CoroutineData) % HeapWordSize) == 0, "misaligned CoroutineData size");
 +  intptr_t alloc_size = (capacity * HeapWordSize) + sizeof(CoroutineData);
 +
-+  void* buf = os::malloc(alloc_size);
++  void* buf = os::malloc(alloc_size, mtThread);
 +  CoroutineData* data = new (buf) CoroutineData(capacity);
 +  if (data == NULL)
 +    return NULL;
@@ -2740,7 +2739,7 @@
 +  assert((sizeof(CoroutineData) % HeapWordSize) == 0, "misaligned CoroutineData size");
 +  intptr_t alloc_size = (overall_size * HeapWordSize) + sizeof(CoroutineData);
 +
-+  void* buf = os::malloc(alloc_size);
++  void* buf = os::malloc(alloc_size, mtThread);
 +  CoroutineData* data = new (buf) CoroutineData(overall_size);
 +  if (data == NULL)
 +    return NULL;
@@ -3233,7 +3232,7 @@
 +};
 +
 +
-+class Coroutine: public CHeapObj, public DoublyLinkedList<Coroutine> {
++class Coroutine: public CHeapObj<mtThread>, public DoublyLinkedList<Coroutine> {
 +public:
 +  enum CoroutineState {
 +    _stored     = 0x00000000,
@@ -3364,7 +3363,7 @@
 +  static ByteSize content_offset()  { return in_ByteSize(sizeof(CoroutineData)); }
 +};
 +
-+class CoroutineStack: public CHeapObj, public DoublyLinkedList<CoroutineStack> {
++class CoroutineStack: public CHeapObj<mtThread>, public DoublyLinkedList<CoroutineStack> {
 +private:
 +  JavaThread*     _thread;
 +  Coroutine*      _current_coroutine;
@@ -3467,7 +3466,7 @@
 diff --git a/src/share/vm/runtime/frame.cpp b/src/share/vm/runtime/frame.cpp
 --- a/src/share/vm/runtime/frame.cpp
 +++ b/src/share/vm/runtime/frame.cpp
-@@ -513,7 +513,7 @@
+@@ -506,7 +506,7 @@
  
  intptr_t* frame::interpreter_frame_local_at(int index) const {
    const int n = Interpreter::local_offset_in_bytes(index)/wordSize;
@@ -3476,7 +3475,7 @@
  }
  
  intptr_t* frame::interpreter_frame_expression_stack_at(jint offset) const {
-@@ -1435,6 +1435,11 @@
+@@ -1415,6 +1415,11 @@
    _is_done = false;
  }
  
@@ -3505,7 +3504,7 @@
    // Accessors
  
    // pc: Returns the pc at which this frame will continue normally.
-@@ -186,7 +190,7 @@
+@@ -185,7 +189,7 @@
  
   public:
  
@@ -3514,7 +3513,7 @@
    intptr_t  at(int index) const                  { return *addr_at(index); }
  
    // accessors for locals
-@@ -551,6 +555,7 @@
+@@ -549,6 +553,7 @@
    bool        _is_done;
   public:
     StackFrameStream(JavaThread *thread, bool update = true);
@@ -3525,7 +3524,7 @@
 diff --git a/src/share/vm/runtime/globals.hpp b/src/share/vm/runtime/globals.hpp
 --- a/src/share/vm/runtime/globals.hpp
 +++ b/src/share/vm/runtime/globals.hpp
-@@ -3898,6 +3898,12 @@
+@@ -3890,6 +3890,12 @@
            "EINTR for I/O operations results in OS_INTRPT. The default value"\
            " of this flag is true for JDK 6 and earlier")                    \
                                                                              \
@@ -3568,7 +3567,7 @@
 diff --git a/src/share/vm/runtime/handles.hpp b/src/share/vm/runtime/handles.hpp
 --- a/src/share/vm/runtime/handles.hpp
 +++ b/src/share/vm/runtime/handles.hpp
-@@ -244,6 +244,7 @@
+@@ -243,6 +243,7 @@
    friend class NoHandleMark;
    friend class ResetNoHandleMark;
  #ifdef ASSERT
@@ -3576,7 +3575,7 @@
    int _handle_mark_nesting;
    int _no_handle_mark_nesting;
  #endif
-@@ -255,6 +256,11 @@
+@@ -254,6 +255,11 @@
      debug_only(_no_handle_mark_nesting = 0);
      _prev = prev;
    }
@@ -3588,7 +3587,7 @@
  
    // Handle allocation
   private:
-@@ -323,6 +329,7 @@
+@@ -322,6 +328,7 @@
   public:
    HandleMark();                            // see handles_inline.hpp
    HandleMark(Thread* thread)                      { initialize(thread); }
@@ -3654,7 +3653,7 @@
  #include "runtime/deoptimization.hpp"
  #include "runtime/fprofiler.hpp"
  #include "runtime/frame.inline.hpp"
-@@ -1335,6 +1336,10 @@
+@@ -1347,6 +1348,10 @@
    _interp_only_mode    = 0;
    _special_runtime_exit_condition = _no_async_condition;
    _pending_async_exception = NULL;
@@ -3665,7 +3664,7 @@
    _is_compiling = false;
    _thread_stat = NULL;
    _thread_stat = new ThreadStatistics();
-@@ -1518,6 +1523,8 @@
+@@ -1536,6 +1541,8 @@
    // Record real stack base and size.
    this->record_stack_base_and_size();
  
@@ -3674,7 +3673,7 @@
    // Initialize thread local storage; set before calling MutexLocker
    this->initialize_thread_local_storage();
  
-@@ -2462,6 +2469,12 @@
+@@ -2480,6 +2487,12 @@
      frame* fr = fst.current();
      f(fr, fst.register_map());
    }
@@ -3687,7 +3686,7 @@
  }
  
  
-@@ -2618,6 +2631,13 @@
+@@ -2636,6 +2649,13 @@
        fst.current()->oops_do(f, cf, fst.register_map());
      }
    }
@@ -3701,7 +3700,7 @@
  
    // callee_target is never live across a gc point so NULL it here should
    // it still contain a methdOop.
-@@ -2659,6 +2679,13 @@
+@@ -2677,6 +2697,13 @@
        fst.current()->nmethods_do(cf);
      }
    }
@@ -3715,7 +3714,7 @@
  }
  
  // Printing
-@@ -3220,6 +3247,7 @@
+@@ -3243,6 +3270,7 @@
    // stacksize. This adjusted size is what is used to figure the placement
    // of the guard pages.
    main_thread->record_stack_base_and_size();
@@ -3723,7 +3722,7 @@
    main_thread->initialize_thread_local_storage();
  
    main_thread->set_active_handles(JNIHandleBlock::allocate_block());
-@@ -4512,3 +4540,9 @@
+@@ -4552,3 +4580,9 @@
    VMThread* thread = VMThread::vm_thread();
    if (thread != NULL) thread->verify();
  }
@@ -3736,7 +3735,7 @@
 diff --git a/src/share/vm/runtime/thread.hpp b/src/share/vm/runtime/thread.hpp
 --- a/src/share/vm/runtime/thread.hpp
 +++ b/src/share/vm/runtime/thread.hpp
-@@ -81,6 +81,9 @@
+@@ -82,6 +82,9 @@
  
  class WorkerThread;
  
@@ -3746,7 +3745,7 @@
  // Class hierarchy
  // - Thread
  //   - NamedThread
-@@ -579,6 +582,10 @@
+@@ -583,6 +586,10 @@
    void leaving_jvmti_env_iteration()             { --_jvmti_env_iteration_count; }
    bool is_inside_jvmti_env_iteration()           { return _jvmti_env_iteration_count > 0; }
  
@@ -3757,7 +3756,7 @@
    // Code generation
    static ByteSize exception_file_offset()        { return byte_offset_of(Thread, _exception_file   ); }
    static ByteSize exception_line_offset()        { return byte_offset_of(Thread, _exception_line   ); }
-@@ -893,6 +900,22 @@
+@@ -897,6 +904,22 @@
    // This is set to popframe_pending to signal that top Java frame should be popped immediately
    int _popframe_condition;
  
@@ -3780,7 +3779,7 @@
  #ifndef PRODUCT
    int _jmp_ring_index;
    struct {
-@@ -1306,6 +1329,9 @@
+@@ -1316,6 +1339,9 @@
    static ByteSize is_method_handle_return_offset() { return byte_offset_of(JavaThread, _is_method_handle_return); }
    static ByteSize stack_guard_state_offset()     { return byte_offset_of(JavaThread, _stack_guard_state   ); }
    static ByteSize suspend_flags_offset()         { return byte_offset_of(JavaThread, _suspend_flags       ); }
--- a/series	Mon Jul 23 10:36:37 2012 -0700
+++ b/series	Thu Jul 26 17:10:47 2012 +0200
@@ -19,10 +19,8 @@
 hotswap.patch   #+hotswap       #-/hotswap
 hotswaplight.patch   #+hotswaplight       #-/hotswaplight
 
-# coro-standalone and coro-meth contain parts that have to be applied differently with/without meth
-# no explicit rev guard on coro-standalone, since the positive guard is needed for /meth
-#coro-standalone.patch          #+/meth #-/coro
-coro-meth.patch         #+coro  #-/meth #-/coro #(dd785aabe02b)
-coro.patch    	        #+coro          #-/coro #(dd785aabe02b)
+# Coroutine patches: full version and simple version (no thread migration, no serialization, no stack sharing) 
+coro.patch                      #+coro          #(dd785aabe02b)
+coro-simple.patch               #+coro-simple   #(dd785aabe02b)
 
 tuple-tsig.patch        #+tuple #-/tuple #-testable