new continuation patch
authorHiroshi Yamauchi <yamauchi@google.com>
Thu Oct 28 15:18:01 2010 +0200 (2 years ago)
changeset 263b63b73832341
parent 2622d3417bec342
child 2640be224a15957
new continuation patch
callcc.patch
callcc.txt
callcc_old.patch
callcc_old.txt
continuation.patch
series
--- a/series Thu Oct 28 12:09:03 2010 +0200
+++ b/series Thu Oct 28 15:18:01 2010 +0200
@@ -23,7 +23,8 @@ anonk.proj.patch #-/anonk
# Keep these separate, for debugging and review:
annot.patch #+annot #-/annot #+d1605aabd0a1 #+jdk7-b30 #-testable
inti.patch #+inti #-/inti #+d1605aabd0a1 #+jdk7-b30 #-buildable
-callcc.patch #+callcc #+/meth #+/indy #-/callcc #+d6d1af32c5f9 #-testable
+callcc_old.patch #+callcc_old #-/callcc_old #+d6d1af32c5f9 #-testable
+continuation.patch #+continuation #-/continuation #+4afae810a801
tailc.patch #+tailc-lazy #-/tailc #-tailc-eager
tailc-eager.patch #+tailc-lazy #-/tailc #-tailc-lazy
hotswap.patch #+hotswap #-/hotswap
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/callcc_old.patch Thu Oct 28 15:18:01 2010 +0200
@@ -0,0 +1,4664 @@
+diff --git a/src/cpu/x86/vm/c1_CodeStubs_x86.cpp b/src/cpu/x86/vm/c1_CodeStubs_x86.cpp
+--- a/src/cpu/x86/vm/c1_CodeStubs_x86.cpp
++++ b/src/cpu/x86/vm/c1_CodeStubs_x86.cpp
+@@ -510,4 +510,44 @@
+ #endif // SERIALGC
+ /////////////////////////////////////////////////////////////////////////////
+
++
++ContinuationStub::ContinuationStub(LIR_OpJavaCall* op): _op(op) {
++ _info = op->info();
++}
++
++
++void ContinuationStub::emit_code(LIR_Assembler* ce) {
++ // TODO handle monitor count correctly
++ assert(ce->frame_map()->num_monitors() == 0, "monitor handling not implemented!");
++
++ // IMPORTANT this nop is required because ImplicitNullCheckStub sets debug info for the first instruction
++ // after its end (at least in product builds) and this collides with our debug info
++ __ nop();
++
++ __ bind(_entry);
++ int stub_pc = ce->code_offset();
++ ce->add_call_info_here(_info);
++ ce->verify_oop_map(_info);
++
++ klassOop k = SystemDictionary::Continuation_klass();
++// k->klass_part()->initialize();
++
++ nmethod* nm = javax_stack_Continuation::get_store_frames_nmethod(_op->method()->return_type()->basic_type());
++ assert(nm, "unsupported return type");
++
++ // this move is performed in create_storeFrameGeneric_contents
++ // __ movl(rcx, rax);
++
++ // this acts as a trampoline to the generic nmethod frame copying stub
++ __ call(RuntimeAddress(nm->verified_entry_point()));
++
++ ce->add_call_info_here(_info);
++ ce->verify_oop_map(_info);
++
++ __ jmp(_continuation);
++
++ ce->compilation()->continuation_pc_table()->add_entry(_pc, stub_pc);
++
++}
++
+ #undef __
+diff --git a/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp b/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp
+--- a/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp
++++ b/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp
+@@ -436,6 +436,29 @@
+
+ int offset = code_offset();
+
++ if (compilation()->method()->create_continuation_stubs()) {
++// tty->print("codepos: %08x\n", pc());
++
++ Label skip;
++ __ get_thread(rcx);
++ __ movptr(rcx, Address(rcx, JavaThread::current_continuation_frame_offset()));
++ __ testptr(rcx, rcx);
++ __ jcc(Assembler::zero, skip);
++ __ cmpptr(rbp, Address(rcx, activationFrameOopDesc::stack_pos_offset()));
++ __ jcc(Assembler::notEqual, skip);
++
++// __ int3();
++// __ warn("continuable exception handling");
++
++ __ push(rdx);
++ __ movptr(rcx, rax);
++ __ movptr(rbx, AddressLiteral(javax_stack_Continuation::get_unwind_nmethod_adr(), relocInfo::none));
++ __ movptr(rbx, Address(rbx, nmethod::verified_entry_point_offset()));
++ __ jmp(rbx);
++
++ __ bind(skip);
++ }
++
+ // the exception oop and pc are in rax, and rdx
+ // no other registers need to be preserved, so invalidate them
+ __ invalidate_registers(false, true, true, false, true, true);
+diff --git a/src/cpu/x86/vm/c1_MacroAssembler_x86.cpp b/src/cpu/x86/vm/c1_MacroAssembler_x86.cpp
+--- a/src/cpu/x86/vm/c1_MacroAssembler_x86.cpp
++++ b/src/cpu/x86/vm/c1_MacroAssembler_x86.cpp
+@@ -138,7 +138,7 @@
+ void C1_MacroAssembler::initialize_header(Register obj, Register klass, Register len, Register t1, Register t2) {
+ assert_different_registers(obj, klass, len);
+ if (UseBiasedLocking && !len->is_valid()) {
+- assert_different_registers(obj, klass, len, t1, t2);
++ assert_different_registers(obj, klass, len, t1);
+ movptr(t1, Address(klass, Klass::prototype_header_offset_in_bytes() + klassOopDesc::klass_part_offset_in_bytes()));
+ movptr(Address(obj, oopDesc::mark_offset_in_bytes()), t1);
+ } else {
+diff --git a/src/cpu/x86/vm/interpreter_x86.hpp b/src/cpu/x86/vm/interpreter_x86.hpp
+--- a/src/cpu/x86/vm/interpreter_x86.hpp
++++ b/src/cpu/x86/vm/interpreter_x86.hpp
+@@ -30,6 +30,7 @@
+ // block of code to handle compiedl return values and cleaning
+ // the fpu stack.
+ static const int return_sentinel;
++ static const int return_sentinel2;
+
+
+ static Address::ScaleFactor stackElementScale() {
+diff --git a/src/cpu/x86/vm/interpreter_x86_32.cpp b/src/cpu/x86/vm/interpreter_x86_32.cpp
+--- a/src/cpu/x86/vm/interpreter_x86_32.cpp
++++ b/src/cpu/x86/vm/interpreter_x86_32.cpp
+@@ -29,6 +29,7 @@
+
+ // Initialize the sentinel used to distinguish an interpreter return address.
+ const int Interpreter::return_sentinel = 0xfeedbeed;
++const int Interpreter::return_sentinel2 = 0xfeedbffd;
+
+ //------------------------------------------------------------------------------------------------------------------------
+
+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
+@@ -1181,6 +1181,16 @@
+ }
+ }
+
++void create_saveContinuation_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_resumeContinuation_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_storeFrameGeneric_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_startDelimited_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_continueDelimited_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 test_continuation_resume(MacroAssembler *masm, Register thread_reg, Register temp);
++
+ // ---------------------------------------------------------------------------
+ // Generate a native wrapper for a given method. The method takes arguments
+ // in the Java compiled code convention, marshals them to the native
+@@ -1364,6 +1374,32 @@
+ __ ret(0);
+ __ bind (slowCase);
+ }
++
++ // all the continuation support methods have a hand-coded fast version that will handle the most common cases
++ if (method->intrinsic_id() == vmIntrinsics::_saveContinuation) {
++ create_saveContinuation_contents(masm, start, oop_maps, stack_slots, total_in_args, in_sig_bt, in_regs, ret_type);
++ }
++ if (method->intrinsic_id() == vmIntrinsics::_resumeContinuation) {
++ create_resumeContinuation_contents(masm, start, oop_maps, stack_slots, total_in_args, in_sig_bt, in_regs, ret_type);
++ }
++ if (method->intrinsic_id() == vmIntrinsics::_storeFrameObject ||
++ method->intrinsic_id() == vmIntrinsics::_storeFrameVoid ||
++ method->intrinsic_id() == vmIntrinsics::_storeFrameBoolean ||
++ method->intrinsic_id() == vmIntrinsics::_storeFrameByte ||
++ method->intrinsic_id() == vmIntrinsics::_storeFrameChar ||
++ method->intrinsic_id() == vmIntrinsics::_storeFrameShort ||
++ method->intrinsic_id() == vmIntrinsics::_storeFrameInt ||
++ method->intrinsic_id() == vmIntrinsics::_storeFrameLong ||
++ method->intrinsic_id() == vmIntrinsics::_storeFrameFloat ||
++ method->intrinsic_id() == vmIntrinsics::_storeFrameDouble) {
++ create_storeFrameGeneric_contents(masm, start, oop_maps, stack_slots, total_in_args, in_sig_bt, in_regs, ret_type);
++ }
++ if (method->intrinsic_id() == vmIntrinsics::_startDelimited) {
++ create_startDelimited_contents(masm, start, oop_maps, stack_slots, total_in_args, in_sig_bt, in_regs, ret_type);
++ }
++ if (method->intrinsic_id() == vmIntrinsics::_continueDelimited) {
++ create_continueDelimited_contents(masm, start, oop_maps, stack_slots, total_in_args, in_sig_bt, in_regs, ret_type);
++ }
+ #endif // COMPILER1
+
+ // The instruction at the verified entry point must be 5 bytes or longer
+@@ -1832,6 +1868,21 @@
+ // Return
+
+ __ leave();
++
++ if (method->intrinsic_id() == vmIntrinsics::_storeFrameObject ||
++ method->intrinsic_id() == vmIntrinsics::_storeFrameVoid ||
++ method->intrinsic_id() == vmIntrinsics::_storeFrameBoolean ||
++ method->intrinsic_id() == vmIntrinsics::_storeFrameByte ||
++ method->intrinsic_id() == vmIntrinsics::_storeFrameChar ||
++ method->intrinsic_id() == vmIntrinsics::_storeFrameShort ||
++ method->intrinsic_id() == vmIntrinsics::_storeFrameInt ||
++ method->intrinsic_id() == vmIntrinsics::_storeFrameLong ||
++ method->intrinsic_id() == vmIntrinsics::_storeFrameFloat ||
++ method->intrinsic_id() == vmIntrinsics::_storeFrameDouble) {
++ __ get_thread(rdi);
++ test_continuation_resume(masm, rdi, rsi);
++ }
++
+ __ ret(0);
+
+ // Unexpected paths are out of line and go here
+@@ -3077,3 +3128,862 @@
+ generate_uncommon_trap_blob();
+ #endif // COMPILER2
+ }
++
++// finds the code blob for a given pc, t1 needs to be rax ... rdx
++void find_code_blob(MacroAssembler* masm, Register pc, Register t1, Label& no_codeblob) {
++ __ cmpl(pc, (int)CodeCache::heap()->low_boundary());
++ __ jcc(Assembler::below, no_codeblob);
++ __ cmpl(pc, (int)CodeCache::heap()->high_boundary());
++ __ jcc(Assembler::aboveEqual, no_codeblob);
++
++ __ subl(pc, (int)CodeCache::heap()->begin());
++ __ shrl(pc, (int)CodeCache::heap()->log2_segment_size());
++
++ __ xorl(t1, t1);
++
++ Label loop;
++ __ bind(loop);
++ __ movb(t1, Address(pc, (int)CodeCache::heap()->segmap().low()));
++ __ cmpl(t1, 0xff);
++ __ jcc(Assembler::equal, no_codeblob);
++ __ subl(pc, t1);
++ __ testl(t1, t1);
++ __ jcc(Assembler::notZero, loop);
++
++ assert(sizeof(bool) == 1, "bool size");
++ __ shll(pc, CodeCache::heap()->log2_segment_size());
++ __ cmpb(Address(pc, in_bytes(HeapBlock::used_offset()) + (int)CodeCache::heap()->begin()), 0x00);
++ __ jcc(Assembler::zero, no_codeblob);
++
++ __ addl(pc, in_bytes(HeapBlock::allocated_offset()) + (int)CodeCache::heap()->begin());
++}
++
++
++void initialize_header(MacroAssembler* masm, Register obj, Register klass, Register t1) {
++ assert_different_registers(obj, klass);
++ if (UseBiasedLocking) {
++ assert_different_registers(obj, klass, t1);
++ __ movptr(t1, Address(klass, Klass::prototype_header_offset_in_bytes() + klassOopDesc::klass_part_offset_in_bytes()));
++ __ movptr(Address(obj, oopDesc::mark_offset_in_bytes()), t1);
++ } else {
++ // This assumes that all prototype bits fit in an int32_t
++ __ movptr(Address(obj, oopDesc::mark_offset_in_bytes ()), (int32_t)(intptr_t)markOopDesc::prototype());
++ }
++
++ __ movptr(Address(obj, oopDesc::klass_offset_in_bytes()), klass);
++}
++
++
++void test_continuation_resume(MacroAssembler *masm, Register thread_reg, Register temp) {
++ assert(temp != rdi, "cannot use rdi as temp");
++ // check if there is a pending resume operation
++ Label resume;
++ __ movptr(temp, Address(thread_reg, JavaThread::resume_common_frame_offset()));
++ __ testptr(temp, temp);
++ __ jcc(Assembler::notZero, resume);
++ __ ret(0);
++
++ __ bind(resume);
++
++ Label native_method;
++ __ movptr(temp, Address(rsp, 0));
++ __ cmpptr(temp, (int)Interpreter::code()->code_start());
++ __ jcc(Assembler::below, native_method);
++ __ cmpptr(temp, (int)Interpreter::code()->code_end());
++ __ jcc(Assembler::aboveEqual, native_method);
++
++ // we need to restore the sender_sp if the current frame is interpreted
++ __ movptr(rsp, Address(rbp, frame::interpreter_frame_sender_sp_offset * wordSize));
++ __ movptr(temp, Address(rbp, frame::return_addr_offset * wordSize));
++ __ push(temp);
++ __ movptr(temp, Address(rbp, frame::link_offset * wordSize));
++ __ push(temp);
++ __ movptr(rbp, rsp);
++
++ __ bind(native_method);
++
++ // check if we've reached the frame from where we'll resume yet, otherwise: return
++ Label resume_not_reached;
++ __ movptr(temp, Address(thread_reg, JavaThread::resume_common_frame_offset()));
++ __ cmpptr(temp, Address(thread_reg, JavaThread::current_continuation_frame_offset()));
++ __ jcc(Assembler::notEqual, resume_not_reached);
++
++ // jump to the resume method
++ __ movptr(temp, ExternalAddress(javax_stack_Continuation::get_resume_nmethod_adr()));
++ __ movptr(temp, Address(temp, nmethod::verified_entry_point_offset()));
++ __ movptr(rdi, thread_reg);
++ __ jmp(temp);
++
++ __ bind(resume_not_reached);
++
++ // destroy the last stack frame
++ __ movl(rax, 0); // clear the return value (might be an oop...)
++ __ leave();
++ __ ret(0);
++}
++
++
++void stop_if(MacroAssembler *masm, Assembler::Condition condition, const char* message) {
++ Label skip;
++ __ jcc(masm->negate_condition(condition), skip);
++
++ __ int3();
++ __ stop(message);
++ __ bind(skip);
++}
++
++void createAndPatchFrame(MacroAssembler* masm, Register& thread, Register& method, Register& frame, Register& temp1,
++ Register& temp2, Register return_address_reg, int return_address_offset, Label& slow_case) {
++ assert_different_registers(thread, method, frame, temp1, temp2);
++
++ // find the code blob that corresponds to the next frame's pc (a NULL codeblob is bad and will be handled by the C++ path)
++ __ movptr(method, Address(return_address_reg, return_address_offset));
++ find_code_blob(masm, method, temp1, slow_case);
++
++ // check if the returned blob is an nmethod, otherwise jump to the C++ path
++ __ cmpl(Address(method, CodeBlob::type_offset()), CodeBlob::_nmethod);
++ __ jcc(Assembler::notEqual, slow_case);
++
++ // get frame and parameter size, with activationFrameOop header size and object-aligned
++ __ movl(temp1, Address(method, nmethod::activation_frame_size_offset()));
++
++ // -1 is a marker for a native nmethod
++ __ cmpl(temp1, -1);
++ __ jcc(Assembler::equal, slow_case);
++
++ // allocate the next frame
++ __ tlab_allocate(frame, temp1, 0, temp2, temp1, slow_case); // new_frame = new activationFrame[temp1]
++ __ movoop(temp1, JNIHandles::make_local(Universe::activationFrameKlassObj())); // temp1 = activationFrameKlass
++ initialize_header(masm, frame, temp1, temp2);
++
++ // prepare the new frame pt1: method, fp, state
++ __ movl(Address(frame, activationFrameOopDesc::method_offset()), method); // frame->method = method
++ if (return_address_reg == rsp) {
++ __ movl(Address(frame, activationFrameOopDesc::stack_pos_offset()), rbp); // frame->stack_pos = rbp
++ } else {
++ __ movl(temp1, Address(rbp, 0));
++ __ movl(Address(frame, activationFrameOopDesc::stack_pos_offset()), temp1); // frame->stack_pos = *rbp
++ }
++ __ movl(Address(frame, activationFrameOopDesc::state_offset()), activationFrameOopDesc::_compiled_empty); // frame->state = _compiled_empty
++
++ __ movl(Address(frame, activationFrameOopDesc::thread_offset()), thread); // frame->thread = thread
++
++ {
++ // look for the patch address
++
++ // set rsi and rdi to the start and end of the continuation pc table
++ __ movl(temp2, Address(method, nmethod::nmethod_end_offset_offset()));
++ __ addl(temp2, method);
++ __ addl(method, Address(method, nmethod::continuation_pc_table_offset_offset()));
++
++ __ movl(temp1, Address(return_address_reg, return_address_offset));
++
++ // linear loop (should be binary search?) over all patch addresses
++ Label loop;
++ __ bind(loop);
++ __ cmpl(method, temp2);
++ __ jcc(Assembler::aboveEqual, slow_case);
++
++ __ addl(method, 2 * HeapWordSize);
++ __ cmpl(temp1, Address(method, -2 * HeapWordSize));
++ __ jcc(Assembler::notEqual, loop);
++
++ // patch the return address for the next frame
++ __ movl(temp1, Address(method, -HeapWordSize));
++ __ movl(Address(return_address_reg, return_address_offset), temp1);
++ }
++
++ // prepare the new frame pt2: pc
++ __ movl(Address(frame, activationFrameOopDesc::pc_offset()), temp1);
++
++ method = noreg;
++}
++
++//#define CONTINUATION_SLOW_CASE
++
++
++void create_saveContinuation_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) {
++ assert(total_in_args == 1, "unexpected number of arguments");
++ assert(ret_type == T_OBJECT, "unexpected return type");
++ assert(in_sig_bt[0] == T_OBJECT, "unexpected argument type");
++ assert(in_regs[0].first() == rcx->as_VMReg(), "unexpected argument register");
++ Register cont = rcx;
++
++ Label slow_case;
++ Label no_continuation_object;
++
++#ifdef CONTINUATION_SLOW_CASE
++ __ jmp(slow_case);
++#endif
++
++ Register thread = rdx, method = rsi, frame = rbx, temp1 = rax, temp2 = rdi;
++
++ __ get_thread(thread);
++ createAndPatchFrame(masm, thread, method, frame, temp1, temp2, rsp, 0, slow_case);
++
++ // set the newly created activationFrameOop as the current one and set its next pointer
++ __ movptr(temp1, Address(thread, JavaThread::current_continuation_frame_offset()));
++ __ movptr(Address(frame, activationFrameOopDesc::next_offset()), temp1); // frame->next = thread.current_continuation_frame
++ __ movptr(Address(thread, JavaThread::current_continuation_frame_offset()), frame); // thread.current_continuation_frame = frame
++
++ // initialize the Continuation object (if it isn't null)
++ __ testptr(cont, cont);
++ __ jcc(Assembler::zero, no_continuation_object);
++
++ __ movptr(Address(cont, javax_stack_Continuation::get_data_offset()), frame); // continuation->data = frame
++ __ movptr(temp1, Address(thread, JavaThread::threadObj_offset()));
++ __ movptr(Address(cont, javax_stack_Continuation::get_thread_offset()), temp1); // continuation->thread = thread->threadObj
++ __ store_check(cont); // store check (destroys cont)
++
++ __ bind(no_continuation_object);
++
++ __ movoop(rax, JNIHandles::make_local(javax_stack_Continuation::static_captured()));
++ __ ret(0);
++
++ //////////////////////
++ // everything else is handled by the C++ part of this method
++ __ bind(slow_case);
++}
++
++#ifndef VM_LITTLE_ENDIAN
++x86 and big endian? This should never happen...
++#endif
++
++void create_resumeContinuation_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) {
++ assert(total_in_args == 2, "unexpected number of arguments");
++ assert(in_sig_bt[0] == T_OBJECT && in_regs[0].first() == rcx->as_VMReg(), "unexpected argument type or register");
++ assert(in_sig_bt[1] == T_OBJECT && in_regs[1].first() == rdx->as_VMReg(), "unexpected argument type or register");
++ assert(ret_type == T_VOID, "unexpected return type");
++
++ /////////////////////////////////////////////////////////////////////////////////////
++ /////////////////////////////////////////////////////////////////////////////////////
++ // resume implementation
++
++ // rcx = Continuation object to be restored
++ // rdx = return value passed to resume (Object)
++
++ Label slow_case;
++ Label not_connected;
++ Label resume_from_intermediate;
++ Label step5_resume;
++
++ __ get_thread(rdi);
++
++ __ movptr(rax, Address(rdi, JavaThread::resume_common_frame_offset()));
++ __ testptr(rax, rax);
++ __ jcc(Assembler::notZero, resume_from_intermediate);
++
++
++ // check if Continuation.CAPTURED was passed as value
++ __ cmpoop(rdx, JNIHandles::make_local(javax_stack_Continuation::static_captured()));
++ __ jcc(Assembler::equal, slow_case);
++
++ // check if the Continuation belongs to our thread
++ __ movptr(rbx, Address(rcx, javax_stack_Continuation::get_thread_offset()));
++ __ cmpptr(rbx, Address(rdi, JavaThread::threadObj_offset()));
++ __ jcc(Assembler::notEqual, slow_case);
++
++ // check if the Continuation object is filled at all
++ __ movptr(rax, Address(rcx, javax_stack_Continuation::get_data_offset()));
++ __ testptr(rax, rax);
++ __ jcc(Assembler::zero, slow_case);
++
++ __ movptr(rcx, rax);
++
++#ifdef ASSERT
++ __ cmpptr(Address(rdi, JavaThread::current_continuation_frame_offset()), NULL);
++ stop_if(masm, Assembler::equal, "NULL current activation object");
++#endif
++
++ ////////////////////////////
++ // Step 1:
++ // * traverse the continuation until an empty activation object is encountered
++ {
++ Label loop;
++ Label nonfilled_frame;
++
++ __ bind(loop);
++ // check if the current frame is filled
++ __ cmpb(Address(rax, activationFrameOopDesc::state_offset()), activationFrameOopDesc::_filled);
++ __ jcc(Assembler::notEqual, nonfilled_frame);
++ __ movptr(rax, Address(rax, activationFrameOopDesc::next_offset())); // rax = rax->next
++
++#ifdef ASSERT
++ __ testptr(rax, rax);
++ stop_if(masm, Assembler::zero, "NULL frame reached during resume step1");
++#endif
++ __ jmp(loop);
++
++ __ bind(nonfilled_frame);
++
++ // the non-filled frame we found needs to be on the stack
++ __ cmpptr(Address(rax, activationFrameOopDesc::stack_pos_offset()), 0);
++ __ jcc(Assembler::equal, not_connected);
++
++ // check if rax->fp > fp
++ __ movptr(rbx, Address(rbp, 0));
++ __ cmpptr(rbx, Address(rax, activationFrameOopDesc::stack_pos_offset()));
++ __ jcc(Assembler::equal, step5_resume);
++ }
++
++ __ movptr(Address(rdi, JavaThread::resume_continuation_frame_offset()), rcx);
++ __ movptr(Address(rdi, JavaThread::resume_common_frame_offset()), rax);
++ __ movptr(Address(rdi, JavaThread::resume_return_value_offset()), rdx);
++
++ __ movptr(rcx, 0);
++ __ movptr(rbx, ExternalAddress(javax_stack_Continuation::get_save_nmethod_adr()));
++ __ movptr(rbx, Address(rbx, nmethod::verified_entry_point_offset()));
++ __ jmp(rbx);
++
++ __ bind(resume_from_intermediate);
++// __ warn("resume from intermediate");
++
++ __ movptr(rcx, Address(rdi, JavaThread::resume_continuation_frame_offset()));
++ __ movptr(rax, Address(rdi, JavaThread::resume_common_frame_offset()));
++ __ movptr(rdx, Address(rdi, JavaThread::resume_return_value_offset()));
++
++ __ movptr(Address(rdi, JavaThread::resume_continuation_frame_offset()), 0);
++ __ movptr(Address(rdi, JavaThread::resume_common_frame_offset()), 0);
++ __ movptr(Address(rdi, JavaThread::resume_return_value_offset()), 0);
++
++ ////////////////////////////
++ // Step 5: store the reverse pointers in stack_pos and reinstate the actual frames
++ __ bind(step5_resume);
++
++ // we need to restore sender_sp if the current frame is an interpreted frame
++ Label native_method;
++ __ movptr(rsi, Address(rsp, 0));
++ __ cmpptr(rsi, (int)Interpreter::code()->code_start());
++ __ jcc(Assembler::below, native_method);
++ __ cmpptr(rsi, (int)Interpreter::code()->code_end());
++ __ jcc(Assembler::aboveEqual, native_method);
++
++// __ int3();
++ // we need to restore the sender_sp if the current frame is interpreted
++ __ movptr(rsp, Address(rbp, frame::interpreter_frame_sender_sp_offset * wordSize));
++ __ movptr(rsi, Address(rbp, frame::return_addr_offset * wordSize));
++ __ push(rsi);
++ __ movptr(rsi, Address(rbp, frame::link_offset * wordSize));
++ __ push(rsi);
++ __ movptr(rbp, rsp);
++
++ __ bind(native_method);
++
++#ifdef ASSERT
++ __ cmpptr(rax, Address(rdi, JavaThread::current_continuation_frame_offset()));
++ stop_if(masm, Assembler::notEqual, "the current continuation frame is wrong during resume step 5");
++#endif
++ {
++ // rax: the activationFrameOop for the activation frame below the current one
++ // rcx: the top frame of the continuation that should be resumed
++ Label reverse_loop;
++ Label reverse_finished;
++
++ __ movptr(rsi, NULL);
++ __ bind(reverse_loop);
++ __ movptr(Address(rcx, activationFrameOopDesc::stack_pos_offset()), rsi);
++ __ movptr(rsi, rcx);
++ __ movptr(rcx, Address(rcx, activationFrameOopDesc::next_offset()));
++ __ cmpptr(rcx, rax);
++ __ jcc(Assembler::equal, reverse_finished);
++ __ jmp(reverse_loop);
++ __ bind(reverse_finished);
++
++ Label reinstate_loop;
++ Label reinstate_finished;
++ Label reinstate_interpreted;
++
++ __ movptr(rax, rsi);
++
++ __ bind(reinstate_loop);
++
++ __ cmpl(rbp, 0x1000);
++ stop_if(masm, Assembler::below, "yikes!");
++
++ // now restore the frame in rax into the stackframe starting at rbp
++
++#ifdef ASSERT
++ __ cmpb(Address(rax, activationFrameOopDesc::state_offset()), activationFrameOopDesc::_filled);
++ stop_if(masm, Assembler::notEqual, "reached frame that isn't filled during resume step 5");
++#endif
++
++ __ cmpb(Address(rax, activationFrameOopDesc::state_offset() + in_ByteSize(1)), activationFrameOopDesc::_compiled_type >> 8);
++ __ jcc(Assembler::notEqual, reinstate_interpreted);
++
++ /////////
++ // compiled frame
++
++ // rsp is not a valid stack pointer at this point!
++/* __ movptr(rsp, rbp);
++ __ warn("restoring compiled frame");
++*/
++ __ movptr(rsp, Address(rax, activationFrameOopDesc::method_offset()));
++
++ // copy the arguments into the last stack frame
++ __ movl(rcx, Address(rsp, CodeBlob::frame_size_offset()));
++
++ __ lea(rdi, Address(rbp, 2 * BytesPerWord));
++ __ lea(rsi, Address(rax, rcx, Address::times_4, activationFrameOopDesc::header_size() * HeapWordSize));
++
++ __ movl(rcx, Address(rsp, nmethod::stack_parameter_words_offset()));
++ __ rep_mov();
++
++ // update frame pointer
++ __ movl(rcx, Address(rsp, CodeBlob::frame_size_offset()));
++ __ addl(rcx, rcx);
++ __ addl(rcx, rcx);
++ __ subl(rbp, rcx);
++
++ // copy the contents into the current stack frame
++ __ lea(rdi, Address(rbp, 2 * BytesPerWord));
++ __ lea(rsi, Address(rax, activationFrameOopDesc::header_size() * HeapWordSize));
++
++ __ movl(rcx, Address(rsp, CodeBlob::frame_size_offset()));
++ __ subl(rcx, 2);
++ __ rep_mov();
++
++ // update frame pointer and return address
++ __ movl(Address(rbp, 0), rdi);
++ __ movl(rdi, Address(rax, activationFrameOopDesc::pc_offset()));
++ __ movl(Address(rbp, HeapWordSize), rdi);
++
++
++ __ movptr(rbx, rax);
++ __ movptr(rax, Address(rax, activationFrameOopDesc::stack_pos_offset()));
++ __ movptr(rcx, Address(rbp, 0));
++ __ movptr(Address(rbx, activationFrameOopDesc::stack_pos_offset()), rcx);
++ __ testptr(rax,rax);
++ __ jcc(Assembler::notZero, reinstate_loop);
++ __ jmp(reinstate_finished);
++
++ __ bind(reinstate_interpreted);
++
++
++ /////////
++ // interpreted frame
++// __ int3();
++ // rsp is not a valid stack pointer at this point!
++/* __ movptr(rsp, rbp);
++ __ warn("restoring interpreted frame");
++*/
++ __ movptr(rsp, Address(rax, activationFrameOopDesc::method_offset()));
++
++
++ __ movzwl(rcx, Address(rsp, methodOopDesc::size_of_locals_offset())); // get max_locals (this includes parameters)
++ __ negl(rcx);
++ __ lea(rbp, Address(rbp, rcx, Address::times_4)); // adjust rbp to the expanded stack frame
++ __ negl(rcx);
++
++ __ lea(rbx, Address(rbp, rcx, Address::times_4, 2 * wordSize)); // compute the old stack pointer
++ __ movptr(Address(rbp, frame::interpreter_frame_sender_sp_offset * wordSize), rbx); // store the old stack pointer (sender_sp)
++
++ __ movptr(rbx, Address(rbp, rcx, Address::times_4));
++ __ movptr(Address(rbp, frame::link_offset * wordSize), rbx); // copy the link address to the new location
++ __ movptr(rbx, Address(rbp, rcx, Address::times_4, HeapWordSize));
++ __ movptr(Address(rbp, frame::return_addr_offset * wordSize), rbx); // copy the return address to the new location
++ __ lea(rbx, Address(rbp, rcx, Address::times_4, 1 * HeapWordSize));
++ __ movptr(Address(rbp, frame::interpreter_frame_locals_offset * wordSize), rbx); // store the pointer to the locals
++
++ // copy the locals (and reverse the order)
++ __ lea(rdi, Address(rbp, 2 * HeapWordSize));
++ __ lea(rsi, Address(rax, activationFrameOopDesc::header_size() * HeapWordSize));
++ Label copy_loop;
++ __ bind(copy_loop);
++ __ movl(rbx, Address(rsi, 0));
++ __ movl(Address(rdi, rcx, Address::times_4, -1 * 4), rbx);
++ __ addptr(rsi, 4);
++ __ decrementl(rcx, 1);
++ __ jcc(Assembler::notZero, copy_loop);
++
++ __ movptr(Address(rbp, frame::interpreter_frame_method_offset * wordSize), rsp); // store the methodOop
++ __ movptr(rbx, Address(rsp, methodOopDesc::method_data_offset()));
++ __ movptr(Address(rbp, frame::interpreter_frame_mdx_offset * wordSize), rbx); // store the methodDataOop
++ __ movptr(rbx, Address(rsp, methodOopDesc::constants_offset()));
++ __ movptr(rbx, Address(rbx, constantPoolOopDesc::cache_offset_in_bytes()));
++ __ movptr(Address(rbp, frame::interpreter_frame_cache_offset * wordSize), rbx); // store the constant pool cache
++ __ lea(rbx, Address(rbp, frame::interpreter_frame_monitor_block_top_offset * wordSize));
++ __ movptr(Address(rbp, frame::interpreter_frame_monitor_block_top_offset * wordSize), rbx); // store the monitor block size
++ __ movptr(rbx, Address(rsp, methodOopDesc::const_offset())); // address of constMethodOop
++ __ addptr(rbx, in_bytes(constMethodOopDesc::codes_offset())); // + code_offset()
++ __ addptr(rbx, Address(rax, activationFrameOopDesc::bci_offset())); // + bci = bcp
++ __ movptr(Address(rbp, frame::interpreter_frame_bcx_offset * wordSize), rbx); // store the bcp
++
++ // copy the expression stack
++ __ movzwl(rcx, Address(rsp, methodOopDesc::size_of_locals_offset()));
++ __ lea(rsi, Address(rax, rcx, Address::times_4, activationFrameOopDesc::header_size() * HeapWordSize));
++ __ subl(rcx, Address(rax, activationFrameOopDesc::data_count_offset()));
++ __ lea(rdi, Address(rbp, rcx, Address::times_4, frame::interpreter_frame_initial_sp_offset * wordSize));
++ __ movptr(Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize), rdi); // store the last_sp
++ __ movptr(Address(rdi, -2 * HeapWordSize), rbp); // store the link
++ __ lea(rbp, Address(rdi, -2 * HeapWordSize));
++ __ negl(rcx);
++
++
++ Label copy_loop2;
++ __ bind(copy_loop2);
++ __ movl(rbx, Address(rsi, 0));
++ __ movl(Address(rdi, rcx, Address::times_4, -1 * 4), rbx);
++ __ addptr(rsi, 4);
++ __ decrementl(rcx, 1);
++ __ jcc(Assembler::notZero, copy_loop2);
++
++ __ movptr(rbx, Address(rax, activationFrameOopDesc::pc_offset()));
++ __ movptr(Address(rbp, HeapWordSize), rbx);
++
++ __ movptr(rbx, rax);
++ __ movptr(rax, Address(rax, activationFrameOopDesc::stack_pos_offset()));
++ __ movptr(rcx, Address(rbp, 0));
++ __ movptr(Address(rbx, activationFrameOopDesc::stack_pos_offset()), rcx);
++
++#ifdef ASSERT
++ __ cmpptr(Address(rbp, HeapWordSize), 0x01000000);
++ stop_if(masm, Assembler::greater, "suspicious pc");
++#endif
++
++ __ testptr(rax,rax);
++ __ jcc(Assembler::notZero, reinstate_loop);
++
++ __ bind(reinstate_finished);
++
++ __ movl(rax, rdx);
++ __ movl(rsp, rbp);
++
++ // get_thread needs a valid sp!
++ __ get_thread(rdi);
++ __ movptr(Address(rdi, JavaThread::current_continuation_frame_offset()), rbx);
++
++ __ pop(rbp);
++ __ ret(0);
++ }
++
++ __ bind(not_connected);
++ __ stop("unconnected continuation");
++
++ __ bind(slow_case);
++}
++
++void create_storeFrameGeneric_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 save_result = false;
++ if (ret_type == T_VOID) {
++ assert(total_in_args == 0, "unexpected number of arguments");
++ } else if (ret_type == T_LONG || ret_type == T_DOUBLE) {
++ assert(total_in_args == 2, "unexpected number of arguments");
++ } else if (ret_type == T_FLOAT) {
++ assert(total_in_args == 1, "unexpected number of arguments");
++ } else {
++ assert(total_in_args == 1, "unexpected number of arguments");
++ save_result = true;
++ }
++
++ /////////////////////////////////////////////////////////////////////////////////////
++ /////////////////////////////////////////////////////////////////////////////////////
++ // This is the shortcut implementation of the "storeFrameGeneric" method which
++ // fills the current activationFrameOop with data from the stack.
++ // The simple assembler implementation can only deal with compiled activation frames.
++
++ // rax = retValue (possibly, depends on the return value of the last method)
++ // IMPORTANT: retValue is an argument, so it should be in rcx, but it's left in rax for performance reasons
++
++ Label slow_case;
++ Label create_new_frame;
++ Label already_filled;
++ Label patch_not_found;
++ Label patching_end;
++
++#ifdef CONTINUATION_SLOW_CASE
++ __ jmp(slow_case);
++#endif
++
++ // get thread and current continuation frame
++ Register thread = rbx, frame = rdx, temp1 = rcx;
++ __ get_thread(thread);
++ __ movptr(frame, Address(thread, JavaThread::current_continuation_frame_offset()));
++
++#ifdef ASSERT
++ // let the slow implementation handle a NULL current activation frame
++ __ testl(frame, frame);
++ __ jcc(Assembler::zero, slow_case);
++#endif
++
++ ////////////////////////////
++ // fill the current activationFrameOop with data from the stack
++
++ // skip already filled frames
++ __ cmpb(Address(frame, activationFrameOopDesc::state_offset()), activationFrameOopDesc::_filled);
++ __ jcc(Assembler::equal, already_filled);
++
++ // the slow implementation will take care of non-nmethod frames
++ __ cmpb(Address(frame, activationFrameOopDesc::state_offset() + in_ByteSize(1)), activationFrameOopDesc::_compiled_type >> 8);
++ __ jcc(Assembler::notEqual, slow_case);
++
++#ifdef ASSERT
++ // check that we're filling the correct frame
++ __ cmpptr(rbp, Address(frame, activationFrameOopDesc::stack_pos_offset()));
++ stop_if(masm, Assembler::notEqual, "trying to fill the wrong activationFrameOop");
++#endif
++
++ // set the state to "filled"
++ __ movl(Address(frame, activationFrameOopDesc::state_offset()), activationFrameOopDesc::_compiled_filled);
++ __ movl(Address(frame, activationFrameOopDesc::stack_pos_offset()), 0);
++
++ // fill current continuation frame with data
++ // load rcx with stack frame size + param size
++ __ movptr(rsi, Address(frame, activationFrameOopDesc::method_offset()));
++ __ movl(temp1, Address(rsi, nmethod::stack_parameter_words_offset()));
++ __ addl(temp1, Address(rsi, nmethod::frame_size_offset()));
++ __ lea(rdi, Address(frame, activationFrameOopDesc::header_size() * HeapWordSize));
++ // we need the stack pointer without the return address (so we add one word)
++ __ lea(rsi, Address(rsp, 1 * HeapWordSize));
++ assert(temp1 == rcx, "counter register needed");
++ __ rep_mov();
++
++ // we might have changed some pointers in the activationFrameOop
++ __ movptr(temp1, frame);
++ __ store_check(temp1);
++
++ ////////////////////////////
++ // decide if a new activationFrameOop should be created
++
++ Register next_frame = rsi;
++ // check if current_continuation_frame.next == NULL
++ __ movptr(next_frame, Address(frame, activationFrameOopDesc::next_offset()));
++ __ testptr(next_frame, next_frame);
++ __ jcc(Assembler::zero, create_new_frame);
++
++ // check if current_continuation_frame.next.fp > fp
++ __ movptr(temp1, Address(rbp, 0));
++ __ cmpptr(temp1, Address(next_frame, activationFrameOopDesc::stack_pos_offset()));
++ __ jcc(Assembler::below, create_new_frame);
++
++ // fastest case: use existing continuation frame
++ __ movptr(Address(thread, JavaThread::current_continuation_frame_offset()), next_frame);
++ __ jmp(patching_end);
++ next_frame = noreg;
++
++ ////////////////////////////
++ // create a new nmethod activationFrameOop
++
++ __ bind(create_new_frame);
++
++ Register method = rsi, temp2 = rdi;
++ createAndPatchFrame(masm, thread, method, frame, temp1, temp2, rbp, HeapWordSize, slow_case);
++
++ // prepare the new frame pt3: current activation object
++ __ movl(temp1, Address(thread, JavaThread::current_continuation_frame_offset())); // temp1 = thread.current_continuation_frame
++ __ movl(Address(thread, JavaThread::current_continuation_frame_offset()), frame); // thread.current_continuation_frame = frame
++
++ // prepare the new frame pt4: next
++ __ movl(temp2, Address(temp1, activationFrameOopDesc::next_offset()));
++ __ movl(Address(frame, activationFrameOopDesc::next_offset()), temp2); // frame->next = thread.current_continuation_frame->next
++ __ movl(Address(temp1, activationFrameOopDesc::next_offset()), frame); // thread.current_continuation_frame->next = frame
++
++ // general operations for all codeblob types...
++ __ bind(patching_end);
++
++
++ test_continuation_resume(masm, thread, temp1);
++
++ ////////////////////////////
++ // out-of-order case: frame already filled
++
++ __ bind(already_filled);
++ __ movptr(Address(frame, activationFrameOopDesc::stack_pos_offset()), NULL);
++ __ movptr(temp1, Address(frame, activationFrameOopDesc::next_offset()));
++ __ movptr(Address(thread, JavaThread::current_continuation_frame_offset()), temp1);
++ __ jmp(patching_end);
++
++ ////////////////////////////
++ // switch to the complete (C++) implementation
++ __ bind(slow_case);
++
++ // move the retValue argument where the native method stub expects it
++ if (save_result) {
++ __ movl(rcx, rax);
++ }
++}
++
++void create_startDelimited_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) {
++ assert(total_in_args == 2, "unexpected number of arguments");
++ assert(ret_type == T_OBJECT, "unexpected return type");
++ assert(in_sig_bt[0] == T_OBJECT, "unexpected argument type");
++ assert(in_regs[0].first() == rcx->as_VMReg(), "unexpected argument register");
++ assert(in_sig_bt[1] == T_OBJECT, "unexpected argument type");
++ assert(in_regs[1].first() == rdx->as_VMReg(), "unexpected argument register");
++
++ Label slow_case;
++
++#ifdef CONTINUATION_SLOW_CASE
++ __ jmp(slow_case);
++#endif
++
++ Register temp1 = rsi;
++ __ enter();
++ // -2 because return address is already present and so is the saved rbp
++ __ subptr(rsp, (stack_slots - 2) * wordSize);
++
++ klassOop k = SystemDictionary::Continuation_klass();
++ methodOop method = instanceKlass::cast(k)->find_method(vmSymbols::startDelimitedInternal_name(), vmSymbols::startDelimited_signature());
++ assert(method != NULL, "missing method startDelimitedInternal");
++
++ __ movoop(rbx, JNIHandles::make_local(method));
++ __ movptr(temp1, Address(rbx, methodOopDesc::from_compiled_offset()));
++
++#ifdef ASSERT
++ __ cmpptr(temp1, 0x01000000);
++ stop_if(masm, Assembler::greater, "suspicious method entry");
++#endif
++
++ __ call(temp1);
++
++ OopMap* map = new OopMap(stack_slots, 0);
++ oop_maps->add_gc_map(__ offset(), map);
++
++ AddressLiteral polling_page(os::get_polling_page() + (SafepointPollOffset % os::vm_page_size()), relocInfo::poll_return_type);
++ __ test32(rax, polling_page);
++
++ Register thread = rdi;
++ Register frame = rdx;
++
++ __ get_thread(thread);
++ __ movptr(frame, Address(thread, JavaThread::current_continuation_frame_offset()));
++
++#ifdef ASSERT
++ __ cmpl(Address(frame, activationFrameOopDesc::state_offset()), activationFrameOopDesc::_dummy_invalid);
++ stop_if(masm, Assembler::notEqual, "invalid frame after continueDelimited");
++#endif
++
++
++ __ movptr(temp1, Address(frame, activationFrameOopDesc::next_offset()));
++ __ movptr(Address(frame, activationFrameOopDesc::next_offset()), NULL);
++ __ movptr(Address(thread, JavaThread::current_continuation_frame_offset()), temp1);
++ __ movptr(temp1, frame);
++ __ store_check(temp1);
++
++ __ movl(Address(frame, activationFrameOopDesc::state_offset()), activationFrameOopDesc::_dummy_delimited);
++ __ movb(Address(frame, activationFrameOopDesc::in_use_offset()), 0);
++ __ movptr(Address(frame, activationFrameOopDesc::stack_pos_offset()), 0);
++
++ __ leave();
++ __ ret(0);
++
++ __ bind(slow_case);
++}
++
++void create_continueDelimited_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) {
++ assert(total_in_args == 2, "unexpected number of arguments");
++ assert(ret_type == T_OBJECT, "unexpected return type");
++ assert(in_sig_bt[0] == T_OBJECT, "unexpected argument type");
++ assert(in_regs[0].first() == rcx->as_VMReg(), "unexpected argument register");
++ assert(in_sig_bt[1] == T_OBJECT, "unexpected argument type");
++ assert(in_regs[1].first() == rdx->as_VMReg(), "unexpected argument register");
++
++ Register continuation = rcx;
++ Register thread = rdi;
++ Register temp1 = rsi;
++
++ Label slow_case;
++
++#ifdef CONTINUATION_SLOW_CASE
++ __ jmp(slow_case);
++#endif
++
++ __ get_thread(thread);
++
++ // check if the Continuation belongs to our thread
++ __ movptr(temp1, Address(continuation, javax_stack_Continuation::get_thread_offset()));
++ __ cmpptr(temp1, Address(thread, JavaThread::threadObj_offset()));
++ __ jcc(Assembler::notEqual, slow_case);
++
++ Register frame = rbx;
++ // check if the Continuation object is filled at all
++ __ movptr(frame, Address(continuation, javax_stack_Continuation::get_data_offset()));
++ __ testptr(frame, frame);
++ __ jcc(Assembler::zero, slow_case);
++
++ Label loop, loop_exit;
++ __ bind(loop);
++ __ cmpptr(Address(frame, activationFrameOopDesc::next_offset()), NULL);
++ __ jcc(Assembler::equal, loop_exit);
++ __ movptr(frame, Address(frame, activationFrameOopDesc::next_offset()));
++ __ jmp(loop);
++
++ __ bind(loop_exit);
++ __ cmpl(Address(frame, activationFrameOopDesc::state_offset()), activationFrameOopDesc::_dummy_delimited);
++ __ jcc(Assembler::notEqual, slow_case);
++
++ __ cmpb(Address(frame, activationFrameOopDesc::in_use_offset()), 0);
++ __ jcc(Assembler::notEqual, slow_case);
++
++ __ movptr(temp1, Address(thread, JavaThread::current_continuation_frame_offset()));
++ __ movptr(Address(frame, activationFrameOopDesc::next_offset()), temp1);
++ __ movptr(temp1, frame);
++ __ store_check(temp1);
++ __ movptr(Address(thread, JavaThread::current_continuation_frame_offset()), frame);
++
++// __ int3();
++ // Generate a new frame for the wrapper.
++ __ enter();
++ // -2 because return address is already present and so is the saved rbp
++ __ subptr(rsp, (stack_slots - 2) * wordSize);
++
++ __ movb(Address(frame, activationFrameOopDesc::in_use_offset()), 1);
++ __ movptr(Address(frame, activationFrameOopDesc::stack_pos_offset()), rbp);
++
++ klassOop k = SystemDictionary::Continuation_klass();
++ methodOop method = instanceKlass::cast(k)->find_method(vmSymbols::continueDelimitedInternal_name(), vmSymbols::continueDelimited_signature());
++ assert(method != NULL, "missing method continueDelimitedInternal");
++
++// __ int3();
++ __ movoop(rbx, JNIHandles::make_local(method));
++ __ movptr(temp1, Address(rbx, methodOopDesc::from_compiled_offset()));
++
++#ifdef ASSERT
++ __ cmpptr(temp1, 0x01000000);
++ stop_if(masm, Assembler::greater, "suspicious method entry");
++#endif
++
++ __ call(temp1);
++
++ OopMap* map = new OopMap(stack_slots, 0);
++ oop_maps->add_gc_map(__ offset(), map);
++
++ // Note: we do not need to round double result; float result has the right precision
++ // the poll sets the condition code, but no data registers
++ AddressLiteral polling_page(os::get_polling_page() + (SafepointPollOffset % os::vm_page_size()), relocInfo::poll_return_type);
++
++ // NOTE: the requires that the polling page be reachable else the reloc
++ // goes to the movq that loads the address and not the faulting instruction
++ // which breaks the signal handler code
++ __ test32(rax, polling_page);
++
++
++ __ get_thread(thread);
++ __ movptr(frame, Address(thread, JavaThread::current_continuation_frame_offset()));
++
++#ifdef ASSERT
++ __ cmpl(Address(frame, activationFrameOopDesc::state_offset()), activationFrameOopDesc::_dummy_delimited);
++ stop_if(masm, Assembler::notEqual, "invalid frame after continueDelimited");
++ __ cmpb(Address(frame, activationFrameOopDesc::in_use_offset()), 0);
++ stop_if(masm, Assembler::equal, "in_use cannot be false after continueDelimited");
++#endif
++
++ __ movptr(temp1, Address(frame, activationFrameOopDesc::next_offset()));
++ __ movptr(Address(frame, activationFrameOopDesc::next_offset()), NULL);
++ __ movptr(Address(thread, JavaThread::current_continuation_frame_offset()), temp1);
++ __ movptr(temp1, frame);
++ __ store_check(temp1);
++
++ __ movb(Address(frame, activationFrameOopDesc::in_use_offset()), 0);
++ __ movptr(Address(frame, activationFrameOopDesc::stack_pos_offset()), 0);
++
++ __ leave();
++ __ ret(0);
++
++ __ bind(slow_case);
++}
++
+diff --git a/src/cpu/x86/vm/templateInterpreter_x86_32.cpp b/src/cpu/x86/vm/templateInterpreter_x86_32.cpp
+--- a/src/cpu/x86/vm/templateInterpreter_x86_32.cpp
++++ b/src/cpu/x86/vm/templateInterpreter_x86_32.cpp
+@@ -159,6 +159,34 @@
+ TosState incoming_state = state;
+
+ Label interpreter_entry;
++ BasicType type;
++ switch(incoming_state) {
++ case btos: type = T_BYTE; break;
++ case ctos: type = T_CHAR; break;
++ case stos: type = T_SHORT; break;
++ case itos: type = T_INT; break;
++ case ltos: type = T_LONG; break;
++ case ftos: type = T_FLOAT; break;
++ case dtos: type = T_DOUBLE; break;
++ case atos: type = T_OBJECT; break;
++ case vtos: type = T_VOID; break;
++ default:
++ ShouldNotReachHere();
++ }
++ __ jmp(interpreter_entry, relocInfo::none);
++
++ address continuation_entry = __ pc();
++ // this acts as a trampoline to the generic nmethod frame copying stub
++ __ movl(rcx, rax);
++ __ movptr(rbx, AddressLiteral(javax_stack_Continuation::get_store_frames_nmethod_adr(type), relocInfo::none));
++ __ movptr(rbx, Address(rbx, nmethod::verified_entry_point_offset()));
++ __ call(rbx);
++ __ jmp(interpreter_entry, relocInfo::none);
++
++ __ a_long((int)continuation_entry);
++ __ a_long(Interpreter::return_sentinel2);
++ __ a_long((int)0);
++
+ address compiled_entry = __ pc();
+
+ #ifdef COMPILER2
+@@ -178,8 +206,18 @@
+ }
+
+ __ jmp(interpreter_entry, relocInfo::none);
++
++ address continuation_entry2 = __ pc();
++ // this acts as a trampoline to the generic nmethod frame copying stub
++ __ movl(rcx, rax);
++ __ movptr(rbx, AddressLiteral(javax_stack_Continuation::get_store_frames_nmethod_adr(type), relocInfo::none));
++ __ movptr(rbx, Address(rbx, nmethod::verified_entry_point_offset()));
++ __ call(rbx);
++ __ jmp(interpreter_entry, relocInfo::none);
++
+ // emit a sentinel we can test for when converting an interpreter
+ // entry point to a compiled entry point.
++ __ a_long((int)continuation_entry2);
+ __ a_long(Interpreter::return_sentinel);
+ __ a_long((int)compiled_entry);
+ address entry = __ pc();
+diff --git a/src/share/vm/c1/c1_CodeStubs.hpp b/src/share/vm/c1/c1_CodeStubs.hpp
+--- a/src/share/vm/c1/c1_CodeStubs.hpp
++++ b/src/share/vm/c1/c1_CodeStubs.hpp
+@@ -582,3 +582,25 @@
+
+ #endif // SERIALGC
+ //////////////////////////////////////////////////////////////////////////////////////////
++
++
++class ContinuationStub: public CodeStub {
++private:
++ LIR_OpJavaCall* _op;
++ CodeEmitInfo* _info;
++ int _pc;
++
++public:
++ ContinuationStub(LIR_OpJavaCall* op);
++
++ virtual void emit_code(LIR_Assembler *e);
++ virtual CodeEmitInfo* info() const { return _op->info(); }
++ virtual void visit(LIR_OpVisitState* visitor) {
++ // don't pass in the code emit info since it's processed in the fast path
++ visitor->do_slow_case(_info);
++ }
++ void set_pc(int pc) { _pc = pc; }
++#ifndef PRODUCT
++ virtual void print_name(outputStream* out) const { out->print("ContinuationStub"); }
++#endif // PRODUCT
++};
+diff --git a/src/share/vm/c1/c1_Compilation.cpp b/src/share/vm/c1/c1_Compilation.cpp
+--- a/src/share/vm/c1/c1_Compilation.cpp
++++ b/src/share/vm/c1/c1_Compilation.cpp
+@@ -307,9 +307,11 @@
+ in_bytes(_frame_map->sp_offset_for_orig_pc()),
+ code(),
+ in_bytes(frame_map()->framesize_in_bytes()) / sizeof(intptr_t),
++ frame_map()->incoming_arguments()->reserved_stack_slots(),
+ debug_info_recorder()->_oopmaps,
+ exception_handler_table(),
+ implicit_exception_table(),
++ continuation_pc_table(),
+ compiler(),
+ _env->comp_level(),
+ needs_debug_information(),
+diff --git a/src/share/vm/c1/c1_Compilation.hpp b/src/share/vm/c1/c1_Compilation.hpp
+--- a/src/share/vm/c1/c1_Compilation.hpp
++++ b/src/share/vm/c1/c1_Compilation.hpp
+@@ -78,6 +78,7 @@
+ ExceptionInfoList* _exception_info_list;
+ ExceptionHandlerTable _exception_handler_table;
+ ImplicitExceptionTable _implicit_exception_table;
++ ContinuationPcTable _continuation_pc_table;
+ LinearScan* _allocator;
+ CodeOffsets _offsets;
+ CodeBuffer _code;
+@@ -114,6 +115,8 @@
+
+ static Compilation* current_compilation() { return _compilation; }
+
++ ContinuationPcTable* continuation_pc_table() { return &_continuation_pc_table; }
++
+ // accessors
+ ciEnv* env() const { return _env; }
+ AbstractCompiler* compiler() const { return _compiler; }
+diff --git a/src/share/vm/c1/c1_GraphBuilder.cpp b/src/share/vm/c1/c1_GraphBuilder.cpp
+--- a/src/share/vm/c1/c1_GraphBuilder.cpp
++++ b/src/share/vm/c1/c1_GraphBuilder.cpp
+@@ -2987,7 +2987,10 @@
+ // Clear out any existing inline bailout condition
+ clear_inline_bailout();
+
+- if (callee->should_exclude()) {
++ if (scope()->method()->create_continuation_stubs() != callee->create_continuation_stubs()) {
++ // we need clean boundaries between continuable and non-continuable methods
++ INLINE_BAILOUT("mismatch in @Continuable")
++ } else if (callee->should_exclude()) {
+ // callee is excluded
+ INLINE_BAILOUT("excluded by CompilerOracle")
+ } else if (!callee->can_be_compiled()) {
+@@ -3046,6 +3049,11 @@
+ cantrap = false;
+ break;
+
++ case vmIntrinsics::_saveContinuation :
++ case vmIntrinsics::_resumeContinuation :
++ INLINE_BAILOUT("Continuation.save and Continuation.resume cannot be inlined");
++ break;
++
+ case vmIntrinsics::_dabs : // fall through
+ case vmIntrinsics::_dsqrt : // fall through
+ case vmIntrinsics::_dsin : // fall through
+diff --git a/src/share/vm/c1/c1_IR.hpp b/src/share/vm/c1/c1_IR.hpp
+--- a/src/share/vm/c1/c1_IR.hpp
++++ b/src/share/vm/c1/c1_IR.hpp
+@@ -270,7 +270,6 @@
+ int _id;
+
+ FrameMap* frame_map() const { return scope()->compilation()->frame_map(); }
+- Compilation* compilation() const { return scope()->compilation(); }
+
+ public:
+
+@@ -293,6 +292,7 @@
+ CodeEmitInfo(CodeEmitInfo* info, bool lock_stack_only = false);
+
+ // accessors
++ Compilation* compilation() const { return scope()->compilation(); }
+ OopMap* oop_map() { return _oop_map; }
+ ciMethod* method() const { return _scope->method(); }
+ IRScope* scope() const { return _scope; }
+diff --git a/src/share/vm/c1/c1_LIRAssembler.cpp b/src/share/vm/c1/c1_LIRAssembler.cpp
+--- a/src/share/vm/c1/c1_LIRAssembler.cpp
++++ b/src/share/vm/c1/c1_LIRAssembler.cpp
+@@ -448,6 +448,13 @@
+ restore_SP();
+ }
+
++ if (compilation()->method()->create_continuation_stubs()) {
++ ContinuationStub* stub = new ContinuationStub(op);
++ _masm->bind(*stub->continuation());
++ stub->set_pc(code_offset());
++ emit_code_stub(stub);
++ }
++
+ #if defined(X86) && defined(TIERED)
+ // C2 leave fpu stack dirty clean it
+ if (UseSSE < 2) {
+diff --git a/src/share/vm/c1/c1_LIRAssembler.hpp b/src/share/vm/c1/c1_LIRAssembler.hpp
+--- a/src/share/vm/c1/c1_LIRAssembler.hpp
++++ b/src/share/vm/c1/c1_LIRAssembler.hpp
+@@ -44,8 +44,6 @@
+ void check_no_unbound_labels();
+ #endif
+
+- FrameMap* frame_map() const { return _frame_map; }
+-
+ void set_current_block(BlockBegin* b) { _current_block = b; }
+ BlockBegin* current_block() const { return _current_block; }
+
+@@ -109,6 +107,7 @@
+ public:
+ LIR_Assembler(Compilation* c);
+ ~LIR_Assembler();
++ FrameMap* frame_map() const { return _frame_map; }
+ C1_MacroAssembler* masm() const { return _masm; }
+ Compilation* compilation() const { return _compilation; }
+ ciMethod* method() const { return compilation()->method(); }
+diff --git a/src/share/vm/ci/ciEnv.cpp b/src/share/vm/ci/ciEnv.cpp
+--- a/src/share/vm/ci/ciEnv.cpp
++++ b/src/share/vm/ci/ciEnv.cpp
+@@ -866,9 +866,11 @@
+ int orig_pc_offset,
+ CodeBuffer* code_buffer,
+ int frame_words,
++ int stack_param_words,
+ OopMapSet* oop_map_set,
+ ExceptionHandlerTable* handler_table,
+ ImplicitExceptionTable* inc_table,
++ ContinuationPcTable* continuation_pc_table,
+ AbstractCompiler* compiler,
+ int comp_level,
+ bool has_debug_info,
+@@ -942,8 +944,8 @@
+ offsets,
+ orig_pc_offset,
+ debug_info(), dependencies(), code_buffer,
+- frame_words, oop_map_set,
+- handler_table, inc_table,
++ frame_words, stack_param_words, oop_map_set,
++ handler_table, inc_table, continuation_pc_table,
+ compiler, comp_level);
+
+ // Free codeBlobs
+diff --git a/src/share/vm/ci/ciEnv.hpp b/src/share/vm/ci/ciEnv.hpp
+--- a/src/share/vm/ci/ciEnv.hpp
++++ b/src/share/vm/ci/ciEnv.hpp
+@@ -282,9 +282,11 @@
+ int orig_pc_offset,
+ CodeBuffer* code_buffer,
+ int frame_words,
++ int stack_param_words,
+ OopMapSet* oop_map_set,
+ ExceptionHandlerTable* handler_table,
+ ImplicitExceptionTable* inc_table,
++ ContinuationPcTable* continuation_pc_table,
+ AbstractCompiler* compiler,
+ int comp_level,
+ bool has_debug_info = true,
+diff --git a/src/share/vm/ci/ciMethod.cpp b/src/share/vm/ci/ciMethod.cpp
+--- a/src/share/vm/ci/ciMethod.cpp
++++ b/src/share/vm/ci/ciMethod.cpp
+@@ -56,6 +56,8 @@
+ _liveness = NULL;
+ _bcea = NULL;
+ _method_blocks = NULL;
++
++ _create_continuation_stubs = h_m()->constMethod()->is_continuable();
+ #ifdef COMPILER2
+ _flow = NULL;
+ #endif // COMPILER2
+diff --git a/src/share/vm/ci/ciMethod.hpp b/src/share/vm/ci/ciMethod.hpp
+--- a/src/share/vm/ci/ciMethod.hpp
++++ b/src/share/vm/ci/ciMethod.hpp
+@@ -65,6 +65,8 @@
+ bool _is_compilable;
+ bool _can_be_statically_bound;
+
++ bool _create_continuation_stubs;
++
+ // Lazy fields, filled in on demand
+ address _code;
+ ciExceptionHandler** _exception_handlers;
+@@ -245,6 +247,7 @@
+ bool is_accessor () const;
+ bool is_initializer () const;
+ bool can_be_statically_bound() const { return _can_be_statically_bound; }
++ bool create_continuation_stubs() const { return _create_continuation_stubs; }
+
+ // Print the bytecodes of this method.
+ void print_codes_on(outputStream* st);
+diff --git a/src/share/vm/classfile/classFileParser.cpp b/src/share/vm/classfile/classFileParser.cpp
+--- a/src/share/vm/classfile/classFileParser.cpp
++++ b/src/share/vm/classfile/classFileParser.cpp
+@@ -1707,6 +1707,7 @@
+ m->set_max_stack(max_stack);
+ m->set_max_locals(max_locals);
+ m->constMethod()->set_stackmap_data(stackmap_data());
++ m->constMethod()->set_continuable(constMethodOopDesc::_not_continuable);
+
+ /**
+ * The exception_table field is the flag used to indicate
+@@ -1842,6 +1843,42 @@
+ "Method handle invokers must be defined internally to the VM", nullHandle);
+ }
+
++ // parse the annotations to get the "Continuable" attribute
++ if ((*method_annotations)() != NULL) {
++ AnnotationParser parser(*method_annotations, cp);
++
++/* if (!parser.verify(THREAD)) {
++
++ ShouldNotReachHere();
++ } */
++
++ symbolOop klass_name = vmSymbols::javax_stack_Continuable_signature();
++ Annotation ann = parser.first_annotation();
++ for (int i=0; i<parser.annotation_count(); i++) {
++ if (ann.get_type_name() == klass_name) {
++ if (ann.value_count() == 0) {
++ // the ContinuableAccess defaults to HIDDEN
++ m->constMethod()->set_continuable(constMethodOopDesc::_continuable_hidden);
++ } else if (ann.value_count() > 1) {
++ ShouldNotReachHere();
++ } else {
++ ElementValuePair value = ann.first_value();
++ if (value.value().enum_const_name()->equals("HIDDEN", 6))
++ m->constMethod()->set_continuable(constMethodOopDesc::_continuable_hidden);
++ else if (value.value().enum_const_name()->equals("READONLY", 8))
++ m->constMethod()->set_continuable(constMethodOopDesc::_continuable_readonly);
++ else if (value.value().enum_const_name()->equals("READWRITE", 9))
++ m->constMethod()->set_continuable(constMethodOopDesc::_continuable_readwrite);
++ else {
++ ShouldNotReachHere();
++ }
++ }
++ break;
++ }
++ ann = parser.next_annotation(ann, THREAD);
++ }
++ }
++
+ return m;
+ }
+
+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
+@@ -2713,6 +2713,56 @@
+ }
+ }
+
++/* stack manipulation */
++
++int javax_stack_Continuation::data_offset = 0;
++int javax_stack_Continuation::thread_offset = 0;
++int javax_stack_Continuation::static_captured_offset = 0;
++nmethod* javax_stack_Continuation::store_frames_nmethods[T_ILLEGAL+1];
++nmethod* javax_stack_Continuation::resume_nmethod;
++nmethod* javax_stack_Continuation::save_nmethod;
++nmethod* javax_stack_Continuation::unwind_nmethod;
++
++void javax_stack_Continuation::compute_offsets() {
++ klassOop k = SystemDictionary::Continuation_klass();
++ if (k != NULL) {
++ compute_offset(data_offset, k, vmSymbols::data_name(), vmSymbols::object_signature());
++ compute_offset(thread_offset, k, vmSymbols::thread_name(), vmSymbols::thread_signature());
++ compute_offset(static_captured_offset, k, vmSymbols::captured_name(), vmSymbols::object_signature());
++ }
++ memset(store_frames_nmethods, NULL, sizeof(store_frames_nmethods));
++ resume_nmethod = NULL;
++ save_nmethod = NULL;
++}
++
++activationFrameOop javax_stack_Continuation::data(oop obj) {
++ return (activationFrameOop)obj->obj_field(data_offset);
++}
++
++void javax_stack_Continuation::set_data(oop obj, activationFrameOop value) {
++ obj->obj_field_put(data_offset, (oop)value);
++}
++
++oop javax_stack_Continuation::thread(oop obj) {
++ return obj->obj_field(thread_offset);
++}
++
++void javax_stack_Continuation::set_thread(oop obj, oop value) {
++ obj->obj_field_put(thread_offset, (oop)value);
++}
++
++oop javax_stack_Continuation::static_captured() {
++ instanceKlass* ik = instanceKlass::cast(SystemDictionary::Continuation_klass());
++ char *addr = (((char *)ik->start_of_static_fields()) + static_captured_offset - ik->offset_of_static_fields());
++ if (UseCompressedOops) {
++ return oopDesc::load_decode_heap_oop((narrowOop *)addr);
++ } else {
++ return oopDesc::load_decode_heap_oop((oop*)addr);
++ }
++}
++
++
++
+ void java_util_concurrent_locks_AbstractOwnableSynchronizer::initialize(TRAPS) {
+ if (_owner_offset != 0) return;
+
+@@ -2836,6 +2886,8 @@
+
+ // generated interpreter code wants to know about the offsets we just computed:
+ AbstractAssembler::update_delayed_values();
++
++ javax_stack_Continuation::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
+@@ -1255,6 +1255,54 @@
+ static oop get_owner_threadObj(oop obj);
+ };
+
++class javax_stack_Continuation: AllStatic {
++private:
++ // Note that to reduce dependencies on the JDK we compute these
++ // offsets at run-time.
++ static int data_offset;
++ static int thread_offset;
++ static int static_captured_offset;
++ static nmethod* store_frames_nmethods[T_ILLEGAL+1];
++ static nmethod* resume_nmethod;
++ static nmethod* save_nmethod;
++ static nmethod* unwind_nmethod;
++
++ static void compute_offsets();
++
++public:
++ // Accessors
++ static activationFrameOop data(oop obj);
++ static void set_data(oop obj, activationFrameOop value);
++
++ static oop thread(oop obj);
++ static void set_thread(oop obj, oop value);
++
++ static oop static_captured();
++
++ static int get_data_offset() { return data_offset; }
++ static int get_thread_offset() { return thread_offset; }
++
++ static void set_store_frames_nmethod(BasicType type, nmethod* m) { store_frames_nmethods[type] = m; }
++ static nmethod* get_store_frames_nmethod(BasicType type) { return store_frames_nmethods[type]; }
++ static address get_store_frames_nmethod_adr(BasicType type) { return (address)(store_frames_nmethods + type); }
++
++ static void set_resume_nmethod(nmethod* m) { resume_nmethod = m; }
++ static nmethod* get_resume_nmethod() { return resume_nmethod; }
++ static address get_resume_nmethod_adr() { return (address)(&resume_nmethod); }
++
++ static void set_save_nmethod(nmethod* m) { save_nmethod = m; }
++ static nmethod* get_save_nmethod() { return save_nmethod; }
++ static address get_save_nmethod_adr() { return (address)(&save_nmethod); }
++
++ static void set_unwind_nmethod(nmethod* m) { unwind_nmethod = m; }
++ static nmethod* get_unwind_nmethod() { return unwind_nmethod; }
++ static address get_unwind_nmethod_adr() { return (address)(&unwind_nmethod); }
++
++ // 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
+@@ -170,6 +170,9 @@
+ 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(Continuation_klass, javax_stack_Continuation, 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
+@@ -355,6 +355,10 @@
+ template(void_long_signature, "()J") \
+ template(void_float_signature, "()F") \
+ template(void_double_signature, "()D") \
++ template(bool_bool_signature, "(Z)Z") \
++ template(byte_byte_signature, "(B)B") \
++ template(char_char_signature, "(C)C") \
++ template(short_short_signature, "(S)S") \
+ template(int_void_signature, "(I)V") \
+ template(int_int_signature, "(I)I") \
+ template(int_bool_signature, "(I)Z") \
+@@ -364,6 +368,7 @@
+ template(int_float_signature, "(I)F") \
+ template(long_int_signature, "(J)I") \
+ template(long_long_signature, "(J)J") \
++ template(float_float_signature, "(F)F") \
+ template(long_double_signature, "(J)D") \
+ template(byte_signature, "B") \
+ template(char_signature, "C") \
+@@ -375,10 +380,14 @@
+ template(bool_signature, "Z") \
+ template(void_signature, "V") \
+ template(byte_array_signature, "[B") \
++ template(int_array_signature, "[I") \
++ template(bool_array_signature, "[Z") \
+ template(char_array_signature, "[C") \
++ template(object_array_signature, "[Ljava/lang/Object;") \
+ template(object_void_signature, "(Ljava/lang/Object;)V") \
+ template(object_int_signature, "(Ljava/lang/Object;)I") \
+ template(object_boolean_signature, "(Ljava/lang/Object;)Z") \
++ template(object_object_signature, "(Ljava/lang/Object;)Ljava/lang/Object;") \
+ template(string_void_signature, "(Ljava/lang/String;)V") \
+ template(string_int_signature, "(Ljava/lang/String;)I") \
+ template(throwable_void_signature, "(Ljava/lang/Throwable;)V") \
+@@ -489,6 +498,13 @@
+ template(serializePropertiesToByteArray_signature, "()[B") \
+ template(serializeAgentPropertiesToByteArray_name, "serializeAgentPropertiesToByteArray") \
+ template(classRedefinedCount_name, "classRedefinedCount") \
++ \
++ /* stack manipulation */ \
++ template(javax_stack_Continuation, "javax/stack/Continuation") \
++ template(javax_stack_Continuable_signature, "Ljavax/stack/Continuable;") \
++ template(data_name, "data") \
++ template(thread_name, "thread") \
++ template(captured_name, "CAPTURED") \
+ /*end*/
+
+
+@@ -597,9 +613,8 @@
+ do_intrinsic(_arraycopy, java_lang_System, arraycopy_name, arraycopy_signature, F_S) \
+ do_name( arraycopy_name, "arraycopy") \
+ do_signature(arraycopy_signature, "(Ljava/lang/Object;ILjava/lang/Object;II)V") \
+- do_intrinsic(_isInterrupted, java_lang_Thread, isInterrupted_name, isInterrupted_signature, F_R) \
++ do_intrinsic(_isInterrupted, java_lang_Thread, isInterrupted_name, bool_bool_signature, F_R) \
+ do_name( isInterrupted_name, "isInterrupted") \
+- do_signature(isInterrupted_signature, "(Z)Z") \
+ do_intrinsic(_currentThread, java_lang_Thread, currentThread_name, currentThread_signature, F_S) \
+ do_name( currentThread_name, "currentThread") \
+ do_signature(currentThread_signature, "()Ljava/lang/Thread;") \
+@@ -825,6 +840,51 @@
+ do_name( prefetchReadStatic_name, "prefetchReadStatic") \
+ do_intrinsic(_prefetchWriteStatic, sun_misc_Unsafe, prefetchWriteStatic_name, prefetch_signature, F_SN) \
+ do_name( prefetchWriteStatic_name, "prefetchWriteStatic") \
++ \
++ /* stack manipulation intrinsic (excluded from compilation) */ \
++ do_intrinsic(_doCopyStackContext, sun_misc_Unsafe, doCopyStackContext_name, doCSC_signature, F_R) \
++ do_name( doCopyStackContext_name, "doCopyStackContext") \
++ do_signature( doCSC_signature, "(Ljava/lang/Runnable;Ljava/lang/Object;)V") \
++ \
++ /* Continuation save and resume */ \
++ do_intrinsic(_saveContinuation, javax_stack_Continuation, saveContinuation_name, void_object_signature, F_RN) \
++ do_name( saveContinuation_name, "save") \
++ do_intrinsic(_resumeContinuation, javax_stack_Continuation, resumeContinuation_name, object_void_signature, F_RN) \
++ do_name( resumeContinuation_name, "resume") \
++ do_intrinsic(_dumpContinuation, javax_stack_Continuation, dumpContinuation_name, void_object_signature, F_RN) \
++ do_name( dumpContinuation_name, "dump") \
++ do_intrinsic(_storeFrameObject, javax_stack_Continuation, storeFrameObject_name, object_object_signature, F_SN) \
++ do_name( storeFrameObject_name, "storeFrameObject") \
++ do_intrinsic(_storeFrameVoid, javax_stack_Continuation, storeFrameVoid_name, void_method_signature, F_SN) \
++ do_name( storeFrameVoid_name, "storeFrameVoid") \
++ do_intrinsic(_storeFrameBoolean, javax_stack_Continuation, storeFrameBoolean_name, bool_bool_signature, F_SN) \
++ do_name( storeFrameBoolean_name, "storeFrameBoolean") \
++ do_intrinsic(_storeFrameByte, javax_stack_Continuation, storeFrameByte_name, byte_byte_signature, F_SN) \
++ do_name( storeFrameByte_name, "storeFrameByte") \
++ do_intrinsic(_storeFrameChar, javax_stack_Continuation, storeFrameChar_name, char_char_signature, F_SN) \
++ do_name( storeFrameChar_name, "storeFrameChar") \
++ do_intrinsic(_storeFrameShort, javax_stack_Continuation, storeFrameShort_name, short_short_signature, F_SN) \
++ do_name( storeFrameShort_name, "storeFrameShort") \
++ do_intrinsic(_storeFrameInt, javax_stack_Continuation, storeFrameInt_name, int_int_signature, F_SN) \
++ do_name( storeFrameInt_name, "storeFrameInt") \
++ do_intrinsic(_storeFrameLong, javax_stack_Continuation, storeFrameLong_name, long_long_signature, F_SN) \
++ do_name( storeFrameLong_name, "storeFrameLong") \
++ do_intrinsic(_storeFrameFloat, javax_stack_Continuation, storeFrameFloat_name, float_float_signature, F_SN) \
++ do_name( storeFrameFloat_name, "storeFrameFloat") \
++ do_intrinsic(_storeFrameDouble, javax_stack_Continuation, storeFrameDouble_name, double_double_signature, F_SN) \
++ do_name( storeFrameDouble_name, "storeFrameDouble") \
++ do_intrinsic(_continuation_unwind, javax_stack_Continuation, continuation_unwind_name, throwable_throwable_signature, F_SN) \
++ do_name( continuation_unwind_name, "unwind") \
++ do_intrinsic(_startDelimited, javax_stack_Continuation, startDelimited_name, startDelimited_signature, F_SN) \
++ do_name( startDelimited_name, "startDelimited") \
++ do_signature( startDelimited_signature, "(Ljavax/stack/DelimitedRunnable;Ljava/lang/Object;)Ljava/lang/Object;") \
++ do_intrinsic(_continueDelimited, javax_stack_Continuation, continueDelimited_name, continueDelimited_signature, F_SN) \
++ do_name( continueDelimited_name, "continueDelimited") \
++ do_signature( continueDelimited_signature, "(Ljavax/stack/Continuation;Ljava/lang/Object;)Ljava/lang/Object;") \
++ do_intrinsic(_startDelimitedInternal, javax_stack_Continuation, startDelimitedInternal_name, startDelimited_signature, F_S) \
++ do_name( startDelimitedInternal_name, "startDelimitedInternal") \
++ do_intrinsic(_continueDelimitedInternal, javax_stack_Continuation, continueDelimitedInternal_name, continueDelimited_signature, F_S) \
++ do_name( continueDelimitedInternal_name, "continueDelimitedInternal") \
+ /*== LAST_COMPILER_INLINE*/ \
+ /*the compiler does have special inlining code for these; bytecode inline is just fine */ \
+ \
+diff --git a/src/share/vm/code/codeBlob.cpp b/src/share/vm/code/codeBlob.cpp
+--- a/src/share/vm/code/codeBlob.cpp
++++ b/src/share/vm/code/codeBlob.cpp
+@@ -46,7 +46,7 @@
+
+
+ // Creates a simple CodeBlob. Sets up the size of the different regions.
+-CodeBlob::CodeBlob(const char* name, int header_size, int size, int frame_complete, int locs_size) {
++CodeBlob::CodeBlob(const char* name, int header_size, int size, int frame_complete, int locs_size, CodeBlobType type) {
+ assert(size == round_to(size, oopSize), "unaligned size");
+ assert(locs_size == round_to(locs_size, oopSize), "unaligned size");
+ assert(header_size == round_to(header_size, oopSize), "unaligned size");
+@@ -60,6 +60,7 @@
+ // off the use of this table (gri 7/6/2000).
+
+ _name = name;
++ _type = type;
+ _size = size;
+ _frame_complete_offset = frame_complete;
+ _header_size = header_size;
+@@ -82,12 +83,14 @@
+ int size,
+ int frame_complete,
+ int frame_size,
+- OopMapSet* oop_maps
++ OopMapSet* oop_maps,
++ CodeBlobType type
+ ) {
+ assert(size == round_to(size, oopSize), "unaligned size");
+ assert(header_size == round_to(header_size, oopSize), "unaligned size");
+
+ _name = name;
++ _type = type;
+ _size = size;
+ _frame_complete_offset = frame_complete;
+ _header_size = header_size;
+@@ -236,7 +239,7 @@
+
+
+ BufferBlob::BufferBlob(const char* name, int size)
+-: CodeBlob(name, sizeof(BufferBlob), size, CodeOffsets::frame_never_safe, /*locs_size:*/ 0)
++: CodeBlob(name, sizeof(BufferBlob), size, CodeOffsets::frame_never_safe, /*locs_size:*/ 0, _buffer)
+ {}
+
+ BufferBlob* BufferBlob::create(const char* name, int buffer_size) {
+@@ -261,7 +264,7 @@
+
+
+ BufferBlob::BufferBlob(const char* name, int size, CodeBuffer* cb)
+- : CodeBlob(name, cb, sizeof(BufferBlob), size, CodeOffsets::frame_never_safe, 0, NULL)
++ : CodeBlob(name, cb, sizeof(BufferBlob), size, CodeOffsets::frame_never_safe, 0, NULL, _buffer)
+ {}
+
+ BufferBlob* BufferBlob::create(const char* name, CodeBuffer* cb) {
+@@ -314,7 +317,7 @@
+ OopMapSet* oop_maps,
+ bool caller_must_gc_arguments
+ )
+-: CodeBlob(name, cb, sizeof(RuntimeStub), size, frame_complete, frame_size, oop_maps)
++: CodeBlob(name, cb, sizeof(RuntimeStub), size, frame_complete, frame_size, oop_maps, _runtime_stub)
+ {
+ _caller_must_gc_arguments = caller_must_gc_arguments;
+ }
+@@ -377,7 +380,7 @@
+ int unpack_with_reexecution_offset,
+ int frame_size
+ )
+-: SingletonBlob("DeoptimizationBlob", cb, sizeof(DeoptimizationBlob), size, frame_size, oop_maps)
++: SingletonBlob("DeoptimizationBlob", cb, sizeof(DeoptimizationBlob), size, frame_size, oop_maps, _deoptimization_stub)
+ {
+ _unpack_offset = unpack_offset;
+ _unpack_with_exception = unpack_with_exception_offset;
+@@ -451,7 +454,7 @@
+ OopMapSet* oop_maps,
+ int frame_size
+ )
+-: SingletonBlob("UncommonTrapBlob", cb, sizeof(UncommonTrapBlob), size, frame_size, oop_maps)
++: SingletonBlob("UncommonTrapBlob", cb, sizeof(UncommonTrapBlob), size, frame_size, oop_maps, _uncommon_trap_stub)
+ {}
+
+
+@@ -511,7 +514,7 @@
+ OopMapSet* oop_maps,
+ int frame_size
+ )
+-: SingletonBlob("ExceptionBlob", cb, sizeof(ExceptionBlob), size, frame_size, oop_maps)
++: SingletonBlob("ExceptionBlob", cb, sizeof(ExceptionBlob), size, frame_size, oop_maps, _exception_stub)
+ {}
+
+
+@@ -570,7 +573,7 @@
+ OopMapSet* oop_maps,
+ int frame_size
+ )
+-: SingletonBlob("SafepointBlob", cb, sizeof(SafepointBlob), size, frame_size, oop_maps)
++: SingletonBlob("SafepointBlob", cb, sizeof(SafepointBlob), size, frame_size, oop_maps, _safepoint_stub)
+ {}
+
+
+diff --git a/src/share/vm/code/codeBlob.hpp b/src/share/vm/code/codeBlob.hpp
+--- a/src/share/vm/code/codeBlob.hpp
++++ b/src/share/vm/code/codeBlob.hpp
+@@ -43,8 +43,21 @@
+
+ friend class VMStructs;
+
++public:
++
++ enum CodeBlobType {
++ _buffer,
++ _nmethod,
++ _runtime_stub,
++ _deoptimization_stub,
++ _uncommon_trap_stub,
++ _exception_stub,
++ _safepoint_stub
++ };
++
+ private:
+ const char* _name;
++ CodeBlobType _type; // which kind of CodeBlob is this
+ int _size; // total size of CodeBlob in bytes
+ int _header_size; // size of header (depends on subclass)
+ int _relocation_size; // size of relocation
+@@ -73,7 +86,7 @@
+ // a) simple CodeBlob
+ // frame_complete is the offset from the beginning of the instructions
+ // to where the frame setup (from stackwalk viewpoint) is complete.
+- CodeBlob(const char* name, int header_size, int size, int frame_complete, int locs_size);
++ CodeBlob(const char* name, int header_size, int size, int frame_complete, int locs_size, CodeBlobType type);
+
+ // b) full CodeBlob
+ CodeBlob(
+@@ -83,22 +96,23 @@
+ int size,
+ int frame_complete,
+ int frame_size,
+- OopMapSet* oop_maps
++ OopMapSet* oop_maps,
++ CodeBlobType type
+ );
+
+ // Deletion
+ void flush();
+
+ // Typing
+- virtual bool is_buffer_blob() const { return false; }
+- virtual bool is_nmethod() const { return false; }
+- virtual bool is_runtime_stub() const { return false; }
+- virtual bool is_deoptimization_stub() const { return false; }
+- virtual bool is_uncommon_trap_stub() const { return false; }
+- virtual bool is_exception_stub() const { return false; }
+- virtual bool is_safepoint_stub() const { return false; }
++ bool is_buffer_blob() const { return _type == _buffer; }
++ bool is_nmethod() const { return _type == _nmethod; }
++ bool is_runtime_stub() const { return _type == _runtime_stub; }
++ bool is_deoptimization_stub() const { return _type == _deoptimization_stub; }
++ bool is_uncommon_trap_stub() const { return _type == _uncommon_trap_stub; }
++ bool is_exception_stub() const { return _type == _exception_stub; }
++ bool is_safepoint_stub() const { return _type == _safepoint_stub; }
++
+ virtual bool is_adapter_blob() const { return false; }
+-
+ virtual bool is_compiled_by_c2() const { return false; }
+ virtual bool is_compiled_by_c1() const { return false; }
+
+@@ -194,6 +208,9 @@
+ // Returns true, if the next frame is responsible for GC'ing oops passed as arguments
+ virtual bool caller_must_gc_arguments(JavaThread* thread) const { return false; }
+
++ static ByteSize frame_size_offset() { return byte_offset_of(CodeBlob, _frame_size); }
++ static ByteSize type_offset() { return byte_offset_of(CodeBlob, _type); }
++
+ // Naming
+ const char* name() const { return _name; }
+ void set_name(const char* name) { _name = name; }
+@@ -286,9 +303,6 @@
+ bool caller_must_gc_arguments
+ );
+
+- // Typing
+- bool is_runtime_stub() const { return true; }
+-
+ // GC support
+ bool caller_must_gc_arguments(JavaThread* thread) const { return _caller_must_gc_arguments; }
+
+@@ -320,9 +334,10 @@
+ int header_size,
+ int size,
+ int frame_size,
+- OopMapSet* oop_maps
++ OopMapSet* oop_maps,
++ CodeBlobType type
+ )
+- : CodeBlob(name, cb, header_size, size, CodeOffsets::frame_never_safe, frame_size, oop_maps)
++ : CodeBlob(name, cb, header_size, size, CodeOffsets::frame_never_safe, frame_size, oop_maps, type)
+ {};
+
+ bool is_alive() const { return true; }
+@@ -373,7 +388,6 @@
+ );
+
+ // Typing
+- bool is_deoptimization_stub() const { return true; }
+ const DeoptimizationBlob *as_deoptimization_stub() const { return this; }
+ bool exception_address_is_unpack_entry(address pc) const {
+ address unpack_pc = unpack();
+@@ -438,9 +452,6 @@
+ // GC for args
+ void preserve_callee_argument_oops(frame fr, const RegisterMap *reg_map, OopClosure* f) { /* nothing to do */ }
+
+- // Typing
+- bool is_uncommon_trap_stub() const { return true; }
+-
+ // Iteration
+ void oops_do(OopClosure* f) {}
+ };
+@@ -473,9 +484,6 @@
+ // GC for args
+ void preserve_callee_argument_oops(frame fr, const RegisterMap* reg_map, OopClosure* f) { /* nothing to do */ }
+
+- // Typing
+- bool is_exception_stub() const { return true; }
+-
+ // Iteration
+ void oops_do(OopClosure* f) {}
+ };
+@@ -509,9 +517,6 @@
+ // GC for args
+ void preserve_callee_argument_oops(frame fr, const RegisterMap* reg_map, OopClosure* f) { /* nothing to do */ }
+
+- // Typing
+- bool is_safepoint_stub() const { return true; }
+-
+ // Iteration
+ void oops_do(OopClosure* f) {}
+ };
+diff --git a/src/share/vm/code/codeCache.hpp b/src/share/vm/code/codeCache.hpp
+--- a/src/share/vm/code/codeCache.hpp
++++ b/src/share/vm/code/codeCache.hpp
+@@ -148,6 +148,8 @@
+
+ // Deoptimization
+ static int mark_for_deoptimization(DepChange& changes);
++
++ static CodeHeap* heap() { return _heap; }
+ #ifdef HOTSWAP
+ static int mark_for_evol_deoptimization(instanceKlassHandle dependee);
+ #endif // HOTSWAP
+diff --git a/src/share/vm/code/exceptionHandlerTable.cpp b/src/share/vm/code/exceptionHandlerTable.cpp
+--- a/src/share/vm/code/exceptionHandlerTable.cpp
++++ b/src/share/vm/code/exceptionHandlerTable.cpp
+@@ -224,3 +224,59 @@
+ fatal1("Invalid offset in ImplicitExceptionTable at %lx", _data);
+ }
+ }
++
++
++// Continuation pc->stub table
++
++void ContinuationPcTable::add_entry(int pc_offset, int stub_offset) {
++ if ((_length+1) >= _size) {
++ // not enough space => grow the table (amortized growth, double its size)
++ int new_size = _size * 2;
++ _table = REALLOC_RESOURCE_ARRAY(int, _table, _size, new_size);
++ _size = new_size;
++ }
++ assert((_length+1) < _size, "sanity check");
++ _table[_length++] = pc_offset;
++ _table[_length++] = stub_offset;
++}
++
++void ContinuationPcTable::add_patch_entry(int pos) {
++ if ((_patch_length+1) >= _patch_size) {
++ // not enough space => grow the table (amortized growth, double its size)
++ int new_size = _patch_size * 2;
++ _patch_nmethod_table = REALLOC_RESOURCE_ARRAY(int, _patch_nmethod_table, _patch_size, new_size);
++ _patch_size = new_size;
++ }
++ assert(_patch_length < _patch_size, "sanity check");
++ _patch_nmethod_table[_patch_length++] = pos;
++}
++
++ContinuationPcTable::ContinuationPcTable(int initial_size) {
++ guarantee(initial_size > 0, "initial size must be > 0");
++ _table = NEW_RESOURCE_ARRAY(int, initial_size);
++ _length = 0;
++ _size = initial_size;
++ _patch_nmethod_table = NEW_RESOURCE_ARRAY(int, initial_size);
++ _patch_length = 0;
++ _patch_size = initial_size;
++}
++
++void ContinuationPcTable::copy_to(nmethod* nm) {
++ assert(size_in_bytes() == nm->continuation_pc_table_size(), "size of space allocated in nmethod incorrect");
++ address* dest = (address*)nm->continuation_pc_table_begin();
++ for( int i=0; i<_length; i++ )
++ dest[i] = _table[i] + nm->instructions_begin();
++ for( int i=0; i<_patch_length; i++ )
++ *(nmethod**)(nm->instructions_begin() +_patch_nmethod_table[i]) = nm;
++}
++
++void ContinuationPcTable::print() const {
++ tty->print_cr("ContinuationPcTable (size = %d bytes)", size_in_bytes());
++ int i = 0;
++ while (i < _length) {
++ int pc = _table[i++];
++ int stub = _table[i++];
++ tty->print(" %08x -> %08x", pc, stub);
++ }
++}
++
+diff --git a/src/share/vm/code/exceptionHandlerTable.hpp b/src/share/vm/code/exceptionHandlerTable.hpp
+--- a/src/share/vm/code/exceptionHandlerTable.hpp
++++ b/src/share/vm/code/exceptionHandlerTable.hpp
+@@ -154,3 +154,36 @@
+ void print(address base) const;
+ void verify(nmethod *nm) const;
+ };
++
++
++// Continuation pc->stub table
++
++class ContinuationPcTable VALUE_OBJ_CLASS_SPEC {
++ private:
++ int* _table; // the table
++ int _length; // the current length of the table
++ int _size; // the number of allocated entries
++ ReallocMark _nesting; // assertion check for reallocations
++
++ int* _patch_nmethod_table;
++ int _patch_length;
++ int _patch_size;
++
++ public:
++ // (compile-time) construction within compiler
++ ContinuationPcTable(int initial_size = 8);
++
++ // add the entry & grow the table if needed
++ void add_entry(int pc_offset, int stub_offset);
++
++ // add the entry & grow the table if needed
++ void add_patch_entry(int pos);
++
++ // nmethod support
++ int size_in_bytes() const { return _length * sizeof(int); }
++ void copy_to(nmethod* nm);
++
++ // debugging
++ void print() const;
++};
++
+diff --git a/src/share/vm/code/nmethod.cpp b/src/share/vm/code/nmethod.cpp
+--- a/src/share/vm/code/nmethod.cpp
++++ b/src/share/vm/code/nmethod.cpp
+@@ -410,7 +410,8 @@
+ scopes_data_size() +
+ scopes_pcs_size() +
+ handler_table_size() +
+- nul_chk_table_size();
++ nul_chk_table_size() +
++ continuation_pc_table_size();
+ }
+
+ const char* nmethod::compile_kind() const {
+@@ -500,10 +501,11 @@
+ int orig_pc_offset,
+ DebugInformationRecorder* debug_info,
+ Dependencies* dependencies,
+- CodeBuffer* code_buffer, int frame_size,
++ CodeBuffer* code_buffer, int frame_size, int stack_param_words,
+ OopMapSet* oop_maps,
+ ExceptionHandlerTable* handler_table,
+ ImplicitExceptionTable* nul_chk_table,
++ ContinuationPcTable* continuation_pc_table,
+ AbstractCompiler* compiler,
+ int comp_level
+ )
+@@ -518,13 +520,15 @@
+ + round_to(dependencies->size_in_bytes() , oopSize)
+ + round_to(handler_table->size_in_bytes(), oopSize)
+ + round_to(nul_chk_table->size_in_bytes(), oopSize)
++ + continuation_pc_table->size_in_bytes()
+ + round_to(debug_info->data_size() , oopSize);
+ nm = new (nmethod_size)
+ nmethod(method(), nmethod_size, compile_id, entry_bci, offsets,
+- orig_pc_offset, debug_info, dependencies, code_buffer, frame_size,
++ orig_pc_offset, debug_info, dependencies, code_buffer, frame_size, stack_param_words,
+ oop_maps,
+ handler_table,
+ nul_chk_table,
++ continuation_pc_table,
+ compiler,
+ comp_level);
+ if (nm != NULL) {
+@@ -572,7 +576,7 @@
+ ByteSize basic_lock_sp_offset,
+ OopMapSet* oop_maps )
+ : CodeBlob("native nmethod", code_buffer, sizeof(nmethod),
+- nmethod_size, offsets->value(CodeOffsets::Frame_Complete), frame_size, oop_maps),
++ nmethod_size, offsets->value(CodeOffsets::Frame_Complete), frame_size, oop_maps, _nmethod),
+ _compiled_synchronized_native_basic_lock_owner_sp_offset(basic_lock_owner_sp_offset),
+ _compiled_synchronized_native_basic_lock_sp_offset(basic_lock_sp_offset)
+ {
+@@ -594,6 +598,9 @@
+ _deoptimize_offset = 0;
+ _deoptimize_mh_offset = 0;
+ _orig_pc_offset = 0;
++
++ _stack_parameter_words = -1;
++ _activation_frame_size = -1;
+ #ifdef HAVE_DTRACE_H
+ _trap_offset = 0;
+ #endif // def HAVE_DTRACE_H
+@@ -604,7 +611,8 @@
+ _dependencies_offset = _scopes_pcs_offset;
+ _handler_table_offset = _dependencies_offset;
+ _nul_chk_table_offset = _handler_table_offset;
+- _nmethod_end_offset = _nul_chk_table_offset;
++ _continuation_pc_table_offset = _nul_chk_table_offset;
++ _nmethod_end_offset = _continuation_pc_table_offset;
+ _compile_id = 0; // default
+ _comp_level = CompLevel_none;
+ _entry_point = instructions_begin();
+@@ -663,7 +671,7 @@
+ CodeBuffer* code_buffer,
+ int frame_size)
+ : CodeBlob("dtrace nmethod", code_buffer, sizeof(nmethod),
+- nmethod_size, offsets->value(CodeOffsets::Frame_Complete), frame_size, NULL),
++ nmethod_size, offsets->value(CodeOffsets::Frame_Complete), frame_size, NULL, _nmethod),
+ _compiled_synchronized_native_basic_lock_owner_sp_offset(in_ByteSize(-1)),
+ _compiled_synchronized_native_basic_lock_sp_offset(in_ByteSize(-1))
+ {
+@@ -693,7 +701,8 @@
+ _dependencies_offset = _scopes_pcs_offset;
+ _handler_table_offset = _dependencies_offset;
+ _nul_chk_table_offset = _handler_table_offset;
+- _nmethod_end_offset = _nul_chk_table_offset;
++ _continuation_pc_table_offset = _nul_chk_table_offset;
++ _nmethod_end_offset = _continuation_pc_table_offset;
+ _compile_id = 0; // default
+ _comp_level = CompLevel_none;
+ _entry_point = instructions_begin();
+@@ -761,14 +770,16 @@
+ Dependencies* dependencies,
+ CodeBuffer *code_buffer,
+ int frame_size,
++ int stack_param_words,
+ OopMapSet* oop_maps,
+ ExceptionHandlerTable* handler_table,
+ ImplicitExceptionTable* nul_chk_table,
++ ContinuationPcTable* continuation_pc_table,
+ AbstractCompiler* compiler,
+ int comp_level
+ )
+ : CodeBlob("nmethod", code_buffer, sizeof(nmethod),
+- nmethod_size, offsets->value(CodeOffsets::Frame_Complete), frame_size, oop_maps),
++ nmethod_size, offsets->value(CodeOffsets::Frame_Complete), frame_size, oop_maps, _nmethod),
+ _compiled_synchronized_native_basic_lock_owner_sp_offset(in_ByteSize(-1)),
+ _compiled_synchronized_native_basic_lock_sp_offset(in_ByteSize(-1))
+ {
+@@ -788,6 +799,9 @@
+ _scavenge_root_state = 0;
+ _compiler = compiler;
+ _orig_pc_offset = orig_pc_offset;
++
++ _stack_parameter_words = stack_param_words;
++ _activation_frame_size = align_object_size(activationFrameOopDesc::header_size() + stack_param_words + frame_size) * HeapWordSize;
+ #ifdef HAVE_DTRACE_H
+ _trap_offset = 0;
+ #endif // def HAVE_DTRACE_H
+@@ -803,7 +817,8 @@
+ _dependencies_offset = _scopes_pcs_offset + adjust_pcs_size(debug_info->pcs_size());
+ _handler_table_offset = _dependencies_offset + round_to(dependencies->size_in_bytes (), oopSize);
+ _nul_chk_table_offset = _handler_table_offset + round_to(handler_table->size_in_bytes(), oopSize);
+- _nmethod_end_offset = _nul_chk_table_offset + round_to(nul_chk_table->size_in_bytes(), oopSize);
++ _continuation_pc_table_offset = _nul_chk_table_offset + round_to(nul_chk_table->size_in_bytes(), oopSize);
++ _nmethod_end_offset = _continuation_pc_table_offset + continuation_pc_table->size_in_bytes();
+
+ _entry_point = instructions_begin();
+ _verified_entry_point = instructions_begin() + offsets->value(CodeOffsets::Verified_Entry);
+@@ -836,6 +851,7 @@
+ // Copy contents of ExceptionHandlerTable to nmethod
+ handler_table->copy_to(this);
+ nul_chk_table->copy_to(this);
++ continuation_pc_table->copy_to(this);
+
+ // we use the information of entry points to find out if a method is
+ // static or non static
+diff --git a/src/share/vm/code/nmethod.hpp b/src/share/vm/code/nmethod.hpp
+--- a/src/share/vm/code/nmethod.hpp
++++ b/src/share/vm/code/nmethod.hpp
+@@ -116,9 +116,12 @@
+ // - handler entry point array
+ // [Implicit Null Pointer exception table]
+ // - implicit null table array
++// [Continuation stub table]
++// - sorted pc->stub mapping array
+
+ class Dependencies;
+ class ExceptionHandlerTable;
++class ContinuationPcTable;
+ class ImplicitExceptionTable;
+ class AbstractCompiler;
+ class xmlStream;
+@@ -134,6 +137,9 @@
+ methodOop _method;
+ int _entry_bci; // != InvocationEntryBci if this nmethod is an on-stack replacement method
+
++ int _stack_parameter_words; // number of parameters that are passed via the stack
++ int _activation_frame_size; // aligned size of an activationFrameOop containing this frame (precalculated for performance)
++
+ // To support simple linked-list chaining of nmethods:
+ nmethod* _osr_link; // from instanceKlass::osr_nmethods_head
+ nmethod* _scavenge_root_link; // from CodeCache::scavenge_root_nmethods
+@@ -161,6 +167,7 @@
+ int _dependencies_offset;
+ int _handler_table_offset;
+ int _nul_chk_table_offset;
++ int _continuation_pc_table_offset;
+ int _nmethod_end_offset;
+
+ // location in frame (offset for sp) that deopt can store the original
+@@ -247,9 +254,11 @@
+ Dependencies* dependencies,
+ CodeBuffer *code_buffer,
+ int frame_size,
++ int stack_param_words,
+ OopMapSet* oop_maps,
+ ExceptionHandlerTable* handler_table,
+ ImplicitExceptionTable* nul_chk_table,
++ ContinuationPcTable* continuation_pc_table,
+ AbstractCompiler* compiler,
+ int comp_level);
+
+@@ -283,9 +292,11 @@
+ Dependencies* dependencies,
+ CodeBuffer *code_buffer,
+ int frame_size,
++ int stack_param_words,
+ OopMapSet* oop_maps,
+ ExceptionHandlerTable* handler_table,
+ ImplicitExceptionTable* nul_chk_table,
++ ContinuationPcTable* continuation_pc_table,
+ AbstractCompiler* compiler,
+ int comp_level);
+
+@@ -324,7 +335,6 @@
+ #endif // NOT PRODUCT
+
+ // type info
+- bool is_nmethod() const { return true; }
+ bool is_java_method() const { return !method()->is_native(); }
+ bool is_native_method() const { return method()->is_native(); }
+ bool is_osr_method() const { return _entry_bci != InvocationEntryBci; }
+@@ -351,7 +361,9 @@
+ address handler_table_begin () const { return header_begin() + _handler_table_offset ; }
+ address handler_table_end () const { return header_begin() + _nul_chk_table_offset ; }
+ address nul_chk_table_begin () const { return header_begin() + _nul_chk_table_offset ; }
+- address nul_chk_table_end () const { return header_begin() + _nmethod_end_offset ; }
++ address nul_chk_table_end () const { return header_begin() + _continuation_pc_table_offset; }
++ address continuation_pc_table_begin() const { return header_begin() + _continuation_pc_table_offset; }
++ address continuation_pc_table_end() const { return header_begin() + _nmethod_end_offset ; }
+
+ int code_size () const { return code_end () - code_begin (); }
+ int stub_size () const { return stub_end () - stub_begin (); }
+@@ -361,6 +373,7 @@
+ int dependencies_size () const { return dependencies_end () - dependencies_begin (); }
+ int handler_table_size() const { return handler_table_end() - handler_table_begin(); }
+ int nul_chk_table_size() const { return nul_chk_table_end() - nul_chk_table_begin(); }
++ int continuation_pc_table_size() const { return continuation_pc_table_end() - continuation_pc_table_begin(); }
+
+ int total_size () const;
+
+@@ -371,6 +384,7 @@
+ bool scopes_pcs_contains (PcDesc* addr) const { return scopes_pcs_begin () <= addr && addr < scopes_pcs_end (); }
+ bool handler_table_contains(address addr) const { return handler_table_begin() <= addr && addr < handler_table_end(); }
+ bool nul_chk_table_contains(address addr) const { return nul_chk_table_begin() <= addr && addr < nul_chk_table_end(); }
++ bool continuation_pc_table_contains(address addr) const { return continuation_pc_table_begin() <= addr && addr < continuation_pc_table_end(); }
+
+ // entry points
+ address entry_point() const { return _entry_point; } // normal entry point
+@@ -458,6 +472,9 @@
+ // implicit exceptions support
+ address continuation_for_implicit_exception(address pc);
+
++ int stack_parameter_words() { return _stack_parameter_words; }
++ int activation_frame_size() { return _activation_frame_size; }
++
+ // On-stack replacement support
+ int osr_entry_bci() const { assert(_entry_bci != InvocationEntryBci, "wrong kind of nmethod"); return _entry_bci; }
+ address osr_entry() const { assert(_entry_bci != InvocationEntryBci, "wrong kind of nmethod"); return _osr_entry_point; }
+@@ -641,6 +658,11 @@
+ static int verified_entry_point_offset() { return offset_of(nmethod, _verified_entry_point); }
+ static int osr_entry_point_offset() { return offset_of(nmethod, _osr_entry_point); }
+ static int entry_bci_offset() { return offset_of(nmethod, _entry_bci); }
++ static int method_offset() { return offset_of(nmethod, _method); }
++ static int stack_parameter_words_offset() { return offset_of(nmethod, _stack_parameter_words); }
++ static int activation_frame_size_offset() { return offset_of(nmethod, _activation_frame_size); }
++ static int continuation_pc_table_offset_offset(){ return offset_of(nmethod, _continuation_pc_table_offset); }
++ static int nmethod_end_offset_offset() { return offset_of(nmethod, _nmethod_end_offset); }
+
+ };
+
+diff --git a/src/share/vm/compiler/compilerOracle.cpp b/src/share/vm/compiler/compilerOracle.cpp
+--- a/src/share/vm/compiler/compilerOracle.cpp
++++ b/src/share/vm/compiler/compilerOracle.cpp
+@@ -284,6 +284,10 @@
+ }
+ }
+
++ // stack manipulation/continuation: startDelimitedInternal can never be compiled
++ if (method->intrinsic_id() == vmIntrinsics::_startDelimitedInternal)
++ return true;
++
+ if (lists[CompileOnlyCommand] != NULL) {
+ return !lists[CompileOnlyCommand]->match(method);
+ }
+diff --git a/src/share/vm/gc_implementation/shared/markSweep.cpp b/src/share/vm/gc_implementation/shared/markSweep.cpp
+--- a/src/share/vm/gc_implementation/shared/markSweep.cpp
++++ b/src/share/vm/gc_implementation/shared/markSweep.cpp
+@@ -214,9 +214,9 @@
+ _adjusted_pointers->push(p);
+ }
+
+-class AdjusterTracker: public OopClosure {
++class MarkSweepAdjusterTracker: public OopClosure {
+ public:
+- AdjusterTracker() {}
++ MarkSweepAdjusterTracker() {}
+ void do_oop(oop* o) { MarkSweep::check_adjust_pointer(o); }
+ void do_oop(narrowOop* o) { MarkSweep::check_adjust_pointer(o); }
+ };
+@@ -226,7 +226,7 @@
+ _adjusted_pointers->clear();
+ _pointer_tracking = true;
+
+- AdjusterTracker checker;
++ MarkSweepAdjusterTracker checker;
+ obj->oop_iterate(&checker);
+ }
+ }
+diff --git a/src/share/vm/includeDB_compiler1 b/src/share/vm/includeDB_compiler1
+--- a/src/share/vm/includeDB_compiler1
++++ b/src/share/vm/includeDB_compiler1
+@@ -53,6 +53,7 @@
+ c1_CodeStubs.hpp c1_LIR.hpp
+ c1_CodeStubs.hpp c1_Runtime1.hpp
+
++c1_CodeStubs_<arch>.cpp activationFrameOop.hpp
+ c1_CodeStubs_<arch>.cpp c1_CodeStubs.hpp
+ c1_CodeStubs_<arch>.cpp c1_FrameMap.hpp
+ c1_CodeStubs_<arch>.cpp c1_LIRAssembler.hpp
+@@ -222,6 +223,7 @@
+ c1_LIRAssembler.hpp methodDataOop.hpp
+ c1_LIRAssembler.hpp top.hpp
+
++c1_LIRAssembler_<arch>.cpp activationFrameOop.hpp
+ c1_LIRAssembler_<arch>.cpp barrierSet.hpp
+ c1_LIRAssembler_<arch>.cpp c1_Compilation.hpp
+ c1_LIRAssembler_<arch>.cpp c1_LIRAssembler.hpp
+diff --git a/src/share/vm/includeDB_core b/src/share/vm/includeDB_core
+--- a/src/share/vm/includeDB_core
++++ b/src/share/vm/includeDB_core
+@@ -134,6 +134,27 @@
+ accessFlags.hpp jvm.h
+ accessFlags.hpp top.hpp
+
++activationFrameKlass.cpp activationFrameKlass.hpp
++activationFrameKlass.cpp activationFrameOop.hpp
++activationFrameKlass.cpp gcLocker.hpp
++activationFrameKlass.cpp handles.inline.hpp
++activationFrameKlass.cpp interpreter.hpp
++activationFrameKlass.cpp markSweep.inline.hpp
++activationFrameKlass.cpp oop.inline.hpp
++activationFrameKlass.cpp oop.inline2.hpp
++activationFrameKlass.cpp oopMapCache.hpp
++activationFrameKlass.cpp resourceArea.hpp
++
++activationFrameKlass.hpp oop.hpp
++activationFrameKlass.hpp klass.hpp
++activationFrameKlass.hpp orderAccess.hpp
++
++activationFrameOop.cpp activationFrameOop.hpp
++
++activationFrameOop.hpp nmethod.hpp
++activationFrameOop.hpp oop.hpp
++activationFrameOop.hpp typeArrayOop.hpp
++
+ allocation.cpp allocation.hpp
+ allocation.cpp allocation.inline.hpp
+ allocation.cpp os.hpp
+@@ -148,6 +169,15 @@
+
+ allocation.inline.hpp os.hpp
+
++annotationParser.cpp annotationParser.hpp
++annotationParser.cpp oopFactory.hpp
++
++annotationParser.hpp constantPoolOop.hpp
++annotationParser.hpp typeArrayOop.hpp
++annotationParser.hpp allocation.hpp
++annotationParser.hpp symbolOop.hpp
++annotationParser.hpp systemDictionary.hpp
++
+ aprofiler.cpp aprofiler.hpp
+ aprofiler.cpp collectedHeap.inline.hpp
+ aprofiler.cpp oop.inline.hpp
+@@ -880,6 +910,7 @@
+ classFileError.cpp verifier.hpp
+
+ classFileParser.cpp allocation.hpp
++classFileParser.cpp annotationParser.hpp
+ classFileParser.cpp classFileParser.hpp
+ classFileParser.cpp classLoader.hpp
+ classFileParser.cpp classLoadingService.hpp
+@@ -1926,6 +1957,7 @@
+ heap.cpp os.hpp
+
+ heap.hpp allocation.hpp
++heap.hpp sizes.hpp
+ heap.hpp virtualspace.hpp
+
+ // heapDumper is jck optional, put cpp deps in includeDB_features
+@@ -3014,6 +3046,7 @@
+ nativeLookup.hpp handles.hpp
+ nativeLookup.hpp top.hpp
+
++nmethod.cpp activationFrameOop.hpp
+ nmethod.cpp abstractCompiler.hpp
+ nmethod.cpp bytecode.hpp
+ nmethod.cpp codeCache.hpp
+@@ -3137,6 +3170,7 @@
+ oop.inline2.hpp permGen.hpp
+ oop.inline2.hpp universe.hpp
+
++oopFactory.cpp activationFrameKlass.hpp
+ oopFactory.cpp collectedHeap.inline.hpp
+ oopFactory.cpp compiledICHolderKlass.hpp
+ oopFactory.cpp constMethodKlass.hpp
+@@ -3756,6 +3790,7 @@
+ sharedRuntime.hpp resourceArea.hpp
+ sharedRuntime.hpp threadLocalStorage.hpp
+
++sharedRuntime_<arch_model>.cpp activationFrameOop.hpp
+ sharedRuntime_<arch_model>.cpp assembler.hpp
+ sharedRuntime_<arch_model>.cpp assembler_<arch>.inline.hpp
+ sharedRuntime_<arch_model>.cpp compiledICHolderOop.hpp
+@@ -4368,6 +4403,7 @@
+ unhandledOops.cpp unhandledOops.hpp
+ unhandledOops.cpp universe.hpp
+
++universe.cpp activationFrameKlass.hpp
+ universe.cpp aprofiler.hpp
+ universe.cpp arguments.hpp
+ universe.cpp arrayKlassKlass.hpp
+@@ -4432,17 +4468,30 @@
+
+ universe.inline.hpp universe.hpp
+
++unsafe.cpp activationFrameOop.hpp
++unsafe.cpp assembler.hpp
+ unsafe.cpp allocation.inline.hpp
++unsafe.cpp biasedLocking.hpp
+ unsafe.cpp copy.hpp
++unsafe.cpp deoptimization.hpp
+ unsafe.cpp globals.hpp
+ unsafe.cpp interfaceSupport.hpp
+ unsafe.cpp jni.h
+ unsafe.cpp jvm.h
+ unsafe.cpp reflection.hpp
+ unsafe.cpp reflectionCompat.hpp
++unsafe.cpp stackMapTable.hpp
+ unsafe.cpp synchronizer.hpp
+ unsafe.cpp threadService.hpp
+ unsafe.cpp vmSymbols.hpp
++unsafe.cpp oopMapCache.hpp
++
++unsafe.cpp oopFactory.hpp
++unsafe.cpp vframe.hpp
++unsafe.cpp vframe_hp.hpp
++unsafe.cpp vframeArray.hpp
++unsafe.cpp verificationType.hpp
++unsafe.cpp constMethodOop.hpp
+
+ utf8.cpp utf8.hpp
+
+@@ -4460,6 +4509,7 @@
+ verificationType.hpp symbolOop.hpp
+ verificationType.hpp systemDictionary.hpp
+
++verifier.cpp annotationParser.hpp
+ verifier.cpp bytecodeStream.hpp
+ verifier.cpp bytes_<arch>.hpp
+ verifier.cpp classFileStream.hpp
+@@ -4523,6 +4573,7 @@
+ vframe.hpp stackValueCollection.hpp
+
+ vframeArray.cpp allocation.inline.hpp
++vframeArray.cpp bytecode.hpp
+ vframeArray.cpp events.hpp
+ vframeArray.cpp handles.inline.hpp
+ vframeArray.cpp interpreter.hpp
+diff --git a/src/share/vm/includeDB_features b/src/share/vm/includeDB_features
+--- a/src/share/vm/includeDB_features
++++ b/src/share/vm/includeDB_features
+@@ -231,6 +231,7 @@
+ restore.cpp symbolTable.hpp
+ restore.cpp systemDictionary.hpp
+
++serialize.cpp activationFrameOop.hpp
+ serialize.cpp classify.hpp
+ serialize.cpp codeCache.hpp
+ serialize.cpp compactingPermGenGen.hpp
+@@ -241,6 +242,8 @@
+ serialize.cpp symbolTable.hpp
+ serialize.cpp systemDictionary.hpp
+
++vmStructs.cpp activationFrameKlass.hpp
++vmStructs.cpp activationFrameOop.hpp
+ vmStructs.cpp arguments.hpp
+ vmStructs.cpp arrayKlass.hpp
+ vmStructs.cpp arrayKlassKlass.hpp
+diff --git a/src/share/vm/memory/classify.cpp b/src/share/vm/memory/classify.cpp
+--- a/src/share/vm/memory/classify.cpp
++++ b/src/share/vm/memory/classify.cpp
+@@ -28,6 +28,7 @@
+
+ const char* ClassifyObjectClosure::object_type_name[number_object_types] = {
+ "unknown",
++ "activationFrame",
+ "instance",
+ "instanceRef",
+ "objArray",
+@@ -57,7 +58,9 @@
+ k->set_alloc_count(k->alloc_count() + 1);
+ }
+
+- if (obj->is_instance()) {
++ if (obj->is_activationFrame()) {
++ type = activationFrame_type;
++ } else if (obj->is_instance()) {
+ if (k->oop_is_instanceRef()) {
+ type = instanceRef_type;
+ } else {
+@@ -147,7 +150,9 @@
+ const char *name;
+ if (k->name() == NULL) {
+
+- if (obj == Universe::klassKlassObj()) {
++ if (obj == Universe::activationFrameKlassObj()) {
++ name = "_activationFrameKlassObj";
++ } else if (obj == Universe::klassKlassObj()) {
+ name = "_klassKlassObj";
+ } else if (obj == Universe::arrayKlassKlassObj()) {
+ name = "_arrayKlassKlassObj";
+diff --git a/src/share/vm/memory/classify.hpp b/src/share/vm/memory/classify.hpp
+--- a/src/share/vm/memory/classify.hpp
++++ b/src/share/vm/memory/classify.hpp
+@@ -24,6 +24,7 @@
+
+ typedef enum oop_type {
+ unknown_type,
++ activationFrame_type,
+ instance_type,
+ instanceRef_type,
+ objArray_type,
+diff --git a/src/share/vm/memory/heap.hpp b/src/share/vm/memory/heap.hpp
+--- a/src/share/vm/memory/heap.hpp
++++ b/src/share/vm/memory/heap.hpp
+@@ -52,6 +52,9 @@
+ void set_used() { _header._used = true; }
+ void set_free() { _header._used = false; }
+ bool free() { return !_header._used; }
++
++ static ByteSize used_offset() { return byte_offset_of(HeapBlock, _header._used ); }
++ static ByteSize allocated_offset() { return in_ByteSize(sizeof(HeapBlock)); }
+ };
+
+ class FreeBlock: public HeapBlock {
+@@ -142,6 +145,9 @@
+ char *low_boundary() const { return _memory.low_boundary (); }
+ char *high_boundary() const { return _memory.high_boundary(); }
+
++ int log2_segment_size() const { return _log2_segment_size; }
++ const VirtualSpace& segmap() const { return _segmap; }
++
+ // Iteration
+
+ // returns the first block or NULL
+diff --git a/src/share/vm/memory/heapInspection.cpp b/src/share/vm/memory/heapInspection.cpp
+--- a/src/share/vm/memory/heapInspection.cpp
++++ b/src/share/vm/memory/heapInspection.cpp
+@@ -56,6 +56,7 @@
+ if (_klass == Universe::shortArrayKlassObj()) name = "<shortArrayKlass>"; else
+ if (_klass == Universe::intArrayKlassObj()) name = "<intArrayKlass>"; else
+ if (_klass == Universe::longArrayKlassObj()) name = "<longArrayKlass>"; else
++ if (_klass == Universe::activationFrameKlassObj()) name = "<activationFrameKlass>"; else
+ if (_klass == Universe::methodKlassObj()) name = "<methodKlass>"; else
+ if (_klass == Universe::constMethodKlassObj()) name = "<constMethodKlass>"; else
+ if (_klass == Universe::methodDataKlassObj()) name = "<methodDataKlass>"; else
+diff --git a/src/share/vm/memory/oopFactory.cpp b/src/share/vm/memory/oopFactory.cpp
+--- a/src/share/vm/memory/oopFactory.cpp
++++ b/src/share/vm/memory/oopFactory.cpp
+@@ -121,6 +121,19 @@
+ CHECK_NULL);
+ }
+
++activationFrameOop oopFactory::new_activationFrame(nmethod* method,
++ TRAPS) {
++ klassOop cmkObj = Universe::activationFrameKlassObj();
++ activationFrameKlass* cmk = activationFrameKlass::cast(cmkObj);
++ return cmk->allocate(method, CHECK_NULL);
++}
++
++activationFrameOop oopFactory::new_activationFrame(int size,
++ TRAPS) {
++ klassOop cmkObj = Universe::activationFrameKlassObj();
++ activationFrameKlass* cmk = activationFrameKlass::cast(cmkObj);
++ return cmk->allocate(size, CHECK_NULL);
++}
+
+ methodOop oopFactory::new_method(int byte_code_size, AccessFlags access_flags,
+ int compressed_line_number_size,
+diff --git a/src/share/vm/memory/oopFactory.hpp b/src/share/vm/memory/oopFactory.hpp
+--- a/src/share/vm/memory/oopFactory.hpp
++++ b/src/share/vm/memory/oopFactory.hpp
+@@ -114,6 +114,10 @@
+ bool is_conc_safe,
+ TRAPS);
+
++ static activationFrameOop new_activationFrame(nmethod* method, TRAPS);
++
++ static activationFrameOop new_activationFrame(int size, TRAPS);
++
+ // Method Data containers
+ static methodDataOop new_methodData(methodHandle method, TRAPS);
+
+diff --git a/src/share/vm/memory/serialize.cpp b/src/share/vm/memory/serialize.cpp
+--- a/src/share/vm/memory/serialize.cpp
++++ b/src/share/vm/memory/serialize.cpp
+@@ -45,6 +45,7 @@
+ // Verify the sizes of various oops in the system.
+ soc->do_tag(sizeof(oopDesc));
+ soc->do_tag(sizeof(instanceOopDesc));
++ soc->do_tag(sizeof(activationFrameOopDesc));
+ soc->do_tag(sizeof(methodOopDesc));
+ soc->do_tag(sizeof(constMethodOopDesc));
+ soc->do_tag(sizeof(methodDataOopDesc));
+diff --git a/src/share/vm/memory/universe.cpp b/src/share/vm/memory/universe.cpp
+--- a/src/share/vm/memory/universe.cpp
++++ b/src/share/vm/memory/universe.cpp
+@@ -26,6 +26,7 @@
+ # include "incls/_universe.cpp.incl"
+
+ // Known objects
++klassOop Universe::_activationFrameKlassObj = NULL;
+ klassOop Universe::_boolArrayKlassObj = NULL;
+ klassOop Universe::_byteArrayKlassObj = NULL;
+ klassOop Universe::_charArrayKlassObj = NULL;
+@@ -118,6 +119,7 @@
+
+
+ void Universe::system_classes_do(void f(klassOop)) {
++ f(activationFrameKlassObj());
+ f(symbolKlassObj());
+ f(methodKlassObj());
+ f(constMethodKlassObj());
+@@ -170,6 +172,7 @@
+ }
+ }
+ }
++ f->do_oop((oop*)&_activationFrameKlassObj);
+ f->do_oop((oop*)&_symbolKlassObj);
+ f->do_oop((oop*)&_methodKlassObj);
+ f->do_oop((oop*)&_constMethodKlassObj);
+@@ -262,6 +265,7 @@
+ _typeArrayKlassObjs[T_INT] = _intArrayKlassObj;
+ _typeArrayKlassObjs[T_LONG] = _longArrayKlassObj;
+
++ _activationFrameKlassObj = activationFrameKlass::create_klass(CHECK);
+ _methodKlassObj = methodKlass::create_klass(CHECK);
+ _constMethodKlassObj = constMethodKlass::create_klass(CHECK);
+ _methodDataKlassObj = methodDataKlass::create_klass(CHECK);
+@@ -457,6 +461,7 @@
+ void Universe::init_self_patching_vtbl_list(void** list, int count) {
+ int n = 0;
+ { klassKlass o; add_vtable(list, &n, &o, count); }
++ { activationFrameKlass o; add_vtable(list, &n, &o, count); }
+ { arrayKlassKlass o; add_vtable(list, &n, &o, count); }
+ { objArrayKlassKlass o; add_vtable(list, &n, &o, count); }
+ { instanceKlassKlass o; add_vtable(list, &n, &o, count); }
+diff --git a/src/share/vm/memory/universe.hpp b/src/share/vm/memory/universe.hpp
+--- a/src/share/vm/memory/universe.hpp
++++ b/src/share/vm/memory/universe.hpp
+@@ -133,6 +133,7 @@
+
+ static klassOop _objectArrayKlassObj;
+
++ static klassOop _activationFrameKlassObj;
+ static klassOop _symbolKlassObj;
+ static klassOop _methodKlassObj;
+ static klassOop _constMethodKlassObj;
+@@ -267,9 +268,10 @@
+ return _typeArrayKlassObjs[t];
+ }
+
++ static klassOop activationFrameKlassObj() { return _activationFrameKlassObj; }
+ static klassOop symbolKlassObj() { return _symbolKlassObj; }
+ static klassOop methodKlassObj() { return _methodKlassObj; }
+- static klassOop constMethodKlassObj() { return _constMethodKlassObj; }
++ static klassOop constMethodKlassObj() { return _constMethodKlassObj; }
+ static klassOop methodDataKlassObj() { return _methodDataKlassObj; }
+ static klassOop klassKlassObj() { return _klassKlassObj; }
+ static klassOop arrayKlassKlassObj() { return _arrayKlassKlassObj; }
+diff --git a/src/share/vm/oops/activationFrameKlass.cpp b/src/share/vm/oops/activationFrameKlass.cpp
+new file mode 100644
+--- /dev/null
++++ b/src/share/vm/oops/activationFrameKlass.cpp
+@@ -0,0 +1,283 @@
++/*
++ * Copyright 2003-2006 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 "incls/_precompiled.incl"
++# include "incls/_activationFrameKlass.cpp.incl"
++
++
++klassOop activationFrameKlass::create_klass(TRAPS) {
++ activationFrameKlass o;
++ KlassHandle h_this_klass(THREAD, Universe::klassKlassObj());
++ KlassHandle k = base_create_klass(h_this_klass, header_size(), o.vtbl_value(), CHECK_NULL);
++ // Make sure size calculation is right
++ assert(k()->size() == align_object_size(header_size()), "wrong size for object");
++ return k();
++}
++
++int activationFrameKlass::oop_size(oop obj) const {
++ assert(obj->is_activationFrame(), "must be activationFrame oop");
++ return activationFrameOop(obj)->object_size();
++}
++
++bool activationFrameKlass::oop_is_parsable(oop obj) const {
++ assert(obj->is_activationFrame(), "must be activationFrame oop");
++ return activationFrameOop(obj)->object_is_parsable();
++}
++
++activationFrameOop activationFrameKlass::allocate(nmethod* method, TRAPS) {
++ int size = activationFrameOopDesc::object_size(method->stack_parameter_words(), method->frame_size());
++ KlassHandle h_k(THREAD, as_klassOop());
++ activationFrameOop af = (activationFrameOop)CollectedHeap::permanent_obj_allocate(h_k, size, CHECK_NULL);
++ assert(!af->is_parsable(), "Not yet safely parsable");
++ No_Safepoint_Verifier no_safepoint;
++ af->_next = NULL;
++ af->_nmethod = method;
++ af->_stack_pos = NULL;
++ af->_pc = NULL;
++ af->_thread = JavaThread::current();
++ af->_state = activationFrameOopDesc::_compiled_empty;
++ assert(af->is_parsable(), "Is safely parsable by gc");
++ return af;
++}
++
++activationFrameOop activationFrameKlass::allocate(int size, TRAPS) {
++ KlassHandle h_k(THREAD, as_klassOop());
++ activationFrameOop af = (activationFrameOop)CollectedHeap::permanent_obj_allocate(h_k, size, CHECK_NULL);
++ assert(!af->is_parsable(), "Not yet safely parsable");
++ return af;
++}
++
++class ActivationFrameInterpreterClosure : public OffsetClosure {
++ private:
++ activationFrameOop _af;
++ OopClosure* _f;
++
++ public:
++ ActivationFrameInterpreterClosure(activationFrameOop af, OopClosure* f) : _af(af), _f(f) {}
++
++ void offset_do(int offset) {
++ _f->do_oop((oop*)_af->get_value_addr(offset));
++ }
++};
++
++class ActivationFrameCodeBlobClosure : public CodeBlobClosure {
++ public:
++ // Called for each code blob.
++ virtual void do_code_blob(CodeBlob* cb){
++ }
++};
++
++inline int activationFrameKlass::do_oop_internal(oop obj, OopClosure& closure) {
++ assert(obj->is_activationFrame(), "must be activationFrame oop");
++ activationFrameOop af = activationFrameOop(obj);
++ int size = af->object_size();
++ switch(af->state()) {
++ case activationFrameOopDesc::_compiled_empty:
++ case activationFrameOopDesc::_dummy_invalid:
++ case activationFrameOopDesc::_dummy_delimited:
++ // nothing to do here...
++ break;
++ case activationFrameOopDesc::_compiled_filled:
++ {
++ frame fr(af->frame_sp(), af->frame_fp(), af->pc());
++ RegisterMap map(af->thread());
++ map.set_include_argument_oops(false);
++ ActivationFrameCodeBlobClosure dummy;
++ fr.oops_do(&closure, &dummy, &map);
++ break;
++ }
++ case activationFrameOopDesc::_interpreted_empty:
++ closure.do_oop((oop*)&af->_methodOop);
++ break;
++ case activationFrameOopDesc::_interpreted_filled:
++ {
++ ActivationFrameInterpreterClosure blk(af, &closure);
++ // process locals & expression stack
++ Thread *thread = Thread::current();
++ methodHandle m (thread, af->_methodOop);
++ closure.do_oop((oop*)&af->_methodOop);
++ InterpreterOopMap mask;
++ m->mask_for(af->_bci, &mask);
++ mask.iterate_oop(&blk);
++ break;
++ }
++ default:
++ ShouldNotReachHere();
++ }
++ closure.do_oop((oop*)&af->_next);
++ return size;
++}
++
++class oop_follow_contentsClosure : public OopClosure {
++ public:
++ void do_oop(oop* p) {
++ MarkSweep::mark_and_push(p);
++ }
++ void do_oop(narrowOop* p) {
++ MarkSweep::mark_and_push(p);
++ }
++};
++
++void activationFrameKlass::oop_follow_contents(oop obj) {
++ oop_follow_contentsClosure closure;
++ do_oop_internal(obj, closure);
++}
++
++#ifndef SERIALGC
++
++class oop_follow_contents2Closure : public OopClosure {
++ ParCompactionManager* _cm;
++ public:
++ oop_follow_contents2Closure(ParCompactionManager* cm) : _cm(cm) {}
++ void do_oop(oop* p) {
++ PSParallelCompact::mark_and_push(_cm, p);
++ }
++ void do_oop(narrowOop* p) {
++ PSParallelCompact::mark_and_push(_cm, p);
++ }
++};
++
++void activationFrameKlass::oop_follow_contents(ParCompactionManager* cm, oop obj) {
++ oop_follow_contents2Closure closure(cm);
++ do_oop_internal(obj, closure);
++}
++#endif // SERIALGC
++
++int activationFrameKlass::oop_oop_iterate(oop obj, OopClosure* blk) {
++ return do_oop_internal(obj, *blk);
++}
++
++
++class oop_oop_iterate_mClosure : public OopClosure {
++ OopClosure* _closure;
++ MemRegion _mr;
++ public:
++ oop_oop_iterate_mClosure(OopClosure* closure, MemRegion mr) : _closure(closure), _mr(mr) {}
++ void do_oop(oop* p) {
++ if (_mr.contains(p)) _closure->do_oop(p);
++ }
++ void do_oop(narrowOop* p) {
++ if (_mr.contains(p)) _closure->do_oop(p);
++ }
++};
++
++int activationFrameKlass::oop_oop_iterate_m(oop obj, OopClosure* blk, MemRegion mr) {
++ oop_oop_iterate_mClosure closure(blk, mr);
++ return do_oop_internal(obj, closure);
++}
++
++
++class oop_adjust_pointersClosure : public OopClosure {
++ public:
++ void do_oop(oop* p) {
++ MarkSweep::adjust_pointer(p);
++ }
++ void do_oop(narrowOop* p) {
++ MarkSweep::adjust_pointer(p);
++ }
++};
++
++int activationFrameKlass::oop_adjust_pointers(oop obj) {
++ oop_adjust_pointersClosure closure;
++ return do_oop_internal(obj, closure);
++}
++
++#ifndef SERIALGC
++void activationFrameKlass::oop_copy_contents(PSPromotionManager* pm, oop obj) {
++ assert(obj->is_activationFrame(), "must be activationFrame oop");
++}
++
++void activationFrameKlass::oop_push_contents(PSPromotionManager* pm, oop obj) {
++ assert(obj->is_activationFrame(), "must be activationFrame oop");
++}
++
++class oop_update_pointersClosure : public OopClosure {
++public:
++ void do_oop(oop* p) {
++ PSParallelCompact::adjust_pointer(p);
++ }
++ void do_oop(narrowOop* p) {
++ PSParallelCompact::adjust_pointer(p);
++ }
++};
++
++int activationFrameKlass::oop_update_pointers(ParCompactionManager* cm, oop obj) {
++ oop_update_pointersClosure closure;
++ return do_oop_internal(obj, closure);
++}
++
++class oop_update_pointersClosure2 : public OopClosure {
++ oop* _begin;
++ oop* _end;
++public:
++ oop_update_pointersClosure2(HeapWord* begin, HeapWord* end) : _begin((oop*)begin), _end((oop*)end) {}
++
++ void do_oop(oop* p) {
++ if ( (p >= _begin) && (p <= _end) ) {
++ PSParallelCompact::adjust_pointer(p);
++ }
++ }
++ void do_oop(narrowOop* p) {
++ PSParallelCompact::adjust_pointer(p);
++ }
++};
++int activationFrameKlass::oop_update_pointers(ParCompactionManager* cm, oop obj,
++ HeapWord* beg_addr,
++ HeapWord* end_addr) {
++ oop_update_pointersClosure2 closure(beg_addr, end_addr);
++ // TODO this can be optimized... it currently ignores beg_addr and end_addr
++ return do_oop_internal(obj, closure);
++}
++#endif // SERIALGC
++
++#undef DO_OOP_ACTIVATION_FRAME
++
++#ifndef PRODUCT
++
++// Printing
++void activationFrameKlass::oop_print_on(oop obj, outputStream* st) {
++ ResourceMark rm;
++ assert(obj->is_activationFrame(), "must be activationFrame oop");
++ Klass::oop_print_on(obj, st);
++ activationFrameOop m = activationFrameOop(obj);/*
++ st->print(" - method: " INTPTR_FORMAT " ", (address)m->const_method()->method());
++ m->const_method()->method()->print_value_on(st); st->cr();
++ st->print(" - callsites: %i\n", m->callsite_count());
++ st->print(" - slots: %i\n", m->slot_count());*/
++}
++
++
++// Short version - just print the name of the method it belongs to.
++void activationFrameKlass::oop_print_value_on(oop obj, outputStream* st) {
++ assert(obj->is_activationFrame(), "must be activationFrame oop");
++ activationFrameOop m = activationFrameOop(obj);/*
++ st->print(" callsite verification data of method " );
++ m->const_method()->method()->print_value_on(st);*/
++}
++
++#endif // PRODUCT
++
++const char* activationFrameKlass::internal_name() const {
++ return "{activationFrame}";
++}
+diff --git a/src/share/vm/oops/activationFrameKlass.hpp b/src/share/vm/oops/activationFrameKlass.hpp
+new file mode 100644
+--- /dev/null
++++ b/src/share/vm/oops/activationFrameKlass.hpp
+@@ -0,0 +1,88 @@
++/*
++ * Copyright 2003-2006 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.
++ *
++ */
++
++// A activationFrameKlass is the klass of a activationFrameOop
++
++class activationFrameKlass : public Klass {
++ friend class VMStructs;
++private:
++ juint _alloc_size; // allocation profiling support
++public:
++ // Testing
++ bool oop_is_activationFrame() const { return true; }
++ virtual bool oop_is_parsable(oop obj) const;
++
++ // Allocation
++ DEFINE_ALLOCATE_PERMANENT(activationFrameKlass);
++ activationFrameOop allocate(nmethod* method, TRAPS);
++ activationFrameOop allocate(int size, TRAPS);
++ static klassOop create_klass(TRAPS);
++
++ // Sizing
++ int oop_size(oop obj) const;
++ int klass_oop_size() const { return object_size(); }
++
++ // Casting from klassOop
++ static activationFrameKlass* cast(klassOop k) {
++ assert(k->klass_part()->oop_is_activationFrame(), "cast to activationFrameKlass");
++ return (activationFrameKlass*) k->klass_part();
++ }
++
++ // Sizing
++ static int header_size() {
++ return oopDesc::header_size() + sizeof(activationFrameKlass)/HeapWordSize;
++ }
++ int object_size() const {
++ return align_object_size(header_size());
++ }
++
++ // Garbage collection
++ void oop_follow_contents(oop obj);
++ int oop_adjust_pointers(oop obj);
++
++ // Parallel Scavenge and Parallel Old
++ PARALLEL_GC_DECLS
++
++ // Allocation profiling support
++ juint alloc_size() const { return _alloc_size; }
++ void set_alloc_size(juint n) { _alloc_size = n; }
++
++ // Iterators
++ int oop_oop_iterate(oop obj, OopClosure* blk);
++ int oop_oop_iterate_m(oop obj, OopClosure* blk, MemRegion mr);
++
++private:
++ int do_oop_internal(oop obj, OopClosure& closure);
++
++#ifndef PRODUCT
++ public:
++ // Printing
++ void oop_print_on (oop obj, outputStream* st);
++ void oop_print_value_on(oop obj, outputStream* st);
++
++#endif
++
++ public:
++ const char* internal_name() const;
++};
+diff --git a/src/share/vm/oops/activationFrameOop.cpp b/src/share/vm/oops/activationFrameOop.cpp
+new file mode 100644
+--- /dev/null
++++ b/src/share/vm/oops/activationFrameOop.cpp
+@@ -0,0 +1,34 @@
++/*
++ * Copyright 2003-2006 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 "incls/_precompiled.incl"
++# include "incls/_activationFrameOop.cpp.incl"
++
++
++// How big must this Object be?
++
++int activationFrameOopDesc::object_size(int param_word_size, int data_word_size) {
++ int extra_words = param_word_size + data_word_size;
++ return align_object_size(header_size() + extra_words);
++}
+diff --git a/src/share/vm/oops/activationFrameOop.hpp b/src/share/vm/oops/activationFrameOop.hpp
+new file mode 100644
+--- /dev/null
++++ b/src/share/vm/oops/activationFrameOop.hpp
+@@ -0,0 +1,198 @@
++/*
++ * Copyright 2003-2006 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.
++ *
++ */
++
++// An activationFrameOop stores the raw data for a continuation stack frame.
++// The next pointer allows the on-the-fly creation of a tree structure of frames.
++//
++// Memory layout (each line represents a word).
++//
++// |------------------------------------------------------|
++// | header |
++// | klass |
++// |------------------------------------------------------|
++
++// TBD
++
++// | |
++// |------------------------------------------------------|
++
++
++class nmethod;
++
++class activationFrameOopDesc : public oopDesc {
++ friend class activationFrameKlass;
++ friend class VMStructs;
++public:
++ enum FrameState {
++ _unparsable = 0x000000,
++
++ _invalid = 0x000001,
++ _empty = 0x000002,
++ _filled = 0x000004,
++ _delimited = 0x000008,
++
++ _compiled_type = 0x000100,
++ _interpreted_type = 0x000200,
++ _dummy_type = 0x000400,
++
++ _compiled_filled = _compiled_type | _filled,
++ _compiled_empty = _compiled_type | _empty,
++
++ _interpreted_filled = _interpreted_type | _filled,
++ _interpreted_empty = _interpreted_type | _empty,
++
++ _dummy_invalid = _dummy_type | _invalid,
++ _dummy_delimited = _dummy_type | _delimited,
++
++ _state_mask = 0x0000ff,
++ _type_mask = 0x00ff00
++ };
++
++private:
++ FrameState _state;
++ activationFrameOop _next;
++ // for implementation reasons this is the base pointer of the next stack frame (== rsp - 2*HeapWordSize)
++ intptr_t* _stack_pos;
++
++ union {
++ nmethod* _nmethod; // compiled
++ methodOop _methodOop; // interpreted
++ };
++
++ union {
++ address _pc; // compiled & interpreted
++ bool _in_use; // only delimited
++ };
++ int _bci; // interpreted
++
++ union {
++ JavaThread* _thread; // compiled
++ int _data_count; // interpreted
++ };
++
++
++public:
++
++ FrameState state() const { return _state; }
++ void set_state(FrameState state) { _state = state; }
++
++ bool is_compiled() const { return (_state & _type_mask) == _compiled_type; }
++ bool is_interpreted() const { return (_state & _type_mask) == _interpreted_type; }
++ bool is_dummy() const { return (_state & _type_mask) == _dummy_type; }
++
++ bool is_invalid() const { return (_state & _state_mask) == _invalid; }
++ bool is_empty() const { return (_state & _state_mask) == _empty; }
++ bool is_filled() const { return (_state & _state_mask) == _filled; }
++ bool is_delimited() const { return (_state & _state_mask) == _delimited; }
++
++ intptr_t* stack_pos() const { return _stack_pos; }
++ void set_stack_pos(intptr_t* adr) {
++ assert((adr == NULL && is_filled()) || (adr == NULL && is_dummy()) || (adr != NULL && !is_filled()), "stack pos doesn't match filled state");
++ _stack_pos = adr;
++ }
++
++ activationFrameOop next() const { return _next; }
++ void set_next(activationFrameOop oop) { _next = oop; }
++
++
++ address pc() const { return _pc; }
++ void set_pc(address pc) { _pc = pc; }
++
++ int bci() const { assert(is_interpreted(), "wrong type"); return _bci; }
++ void set_bci(int bci) { assert(is_interpreted(), "wrong type"); _bci = bci; }
++
++ nmethod* get_nmethod() const { assert(is_compiled(), "wrong type"); return _nmethod; }
++ void set_nmethod(nmethod* method) { assert(is_compiled(), "wrong type"); _nmethod = method; }
++
++ methodOop get_methodOop() const { assert(is_interpreted(), "wrong type"); return _methodOop; }
++ void set_methodOop(methodOop oop) { assert(is_interpreted(), "wrong type"); _methodOop = oop; }
++
++ JavaThread* thread() const { assert(is_compiled(), "wrong type"); return _thread; }
++ void set_thread(JavaThread* thread) { assert(is_compiled(), "wrong type"); _thread = thread; }
++
++ int data_count() const { assert(is_interpreted(), "wrong type"); return _data_count; }
++ void set_data_count(int count) { assert(is_interpreted(), "wrong type"); _data_count = count; }
++
++ bool in_use() const { assert(is_delimited(), "wrong type"); return _in_use; }
++ void set_in_use(bool in_use) { assert(is_delimited(), "wrong type"); _in_use = in_use; }
++
++
++ intptr_t* frame_sp() const { assert(is_compiled(), "wrong type"); return ((intptr_t*)this) + header_size(); }
++ intptr_t* frame_fp() const { assert(is_compiled(), "wrong type"); return ((intptr_t*)this) + _nmethod->stack_parameter_words() - 2; }
++
++ void set_value(int index, intptr_t value) {
++ assert(is_interpreted(), "wrong type");
++ assert(index >= 0 && index < _data_count, "invalid index");
++ ((intptr_t*)this)[header_size() + index] = value;
++ }
++
++ intptr_t get_value(int index) {
++ assert(is_interpreted(), "wrong type");
++ assert(index >= 0 && index < _data_count, "invalid index");
++ return ((intptr_t*)this)[header_size() + index];
++ }
++
++ intptr_t* get_value_addr(int index) {
++ assert(is_interpreted(), "wrong type");
++ assert(index >= 0 && index < _data_count, "invalid index");
++ return ((intptr_t*)this) + (header_size() + index);
++ }
++
++ void mark_as_invalid() {
++ _state = (FrameState)((_state & ~_state_mask) | _invalid);
++ }
++
++ // Object size needed
++ static int object_size(int param_word_size, int data_word_size);
++
++ // Sizing
++ static int header_size() { return sizeof(activationFrameOopDesc)/HeapWordSize; }
++ int object_size() const {
++ if (is_compiled())
++ return object_size(_nmethod->stack_parameter_words(), _nmethod->frame_size());
++ else if (is_interpreted())
++ return align_object_size(header_size() + _data_count * HeapWordSize);
++ else if (is_dummy())
++ return align_object_size(header_size());
++ else {
++ ShouldNotReachHere();
++ }
++ }
++
++ bool object_is_parsable() const { return _state != _unparsable; }
++
++ // Garbage collection support
++ oop* adr_methodOop() const { return (oop*)&_methodOop; }
++
++ static ByteSize state_offset() { return byte_offset_of(activationFrameOopDesc, _state ); }
++ static ByteSize stack_pos_offset() { return byte_offset_of(activationFrameOopDesc, _stack_pos ); }
++ static ByteSize pc_offset() { return byte_offset_of(activationFrameOopDesc, _pc ); }
++ static ByteSize bci_offset() { return byte_offset_of(activationFrameOopDesc, _bci ); }
++ static ByteSize method_offset() { return byte_offset_of(activationFrameOopDesc, _nmethod ); }
++ static ByteSize next_offset() { return byte_offset_of(activationFrameOopDesc, _next ); }
++ static ByteSize thread_offset() { return byte_offset_of(activationFrameOopDesc, _thread ); }
++ static ByteSize in_use_offset() { return byte_offset_of(activationFrameOopDesc, _in_use ); }
++ static ByteSize data_count_offset() { return byte_offset_of(activationFrameOopDesc, _data_count); }
++
++};
+diff --git a/src/share/vm/oops/constMethodOop.hpp b/src/share/vm/oops/constMethodOop.hpp
+--- a/src/share/vm/oops/constMethodOop.hpp
++++ b/src/share/vm/oops/constMethodOop.hpp
+@@ -96,6 +96,15 @@
+ _has_checked_exceptions = 2,
+ _has_localvariable_table = 4
+ };
++public:
++ enum ContinuableFlag {
++ _not_continuable = 0,
++ _continuable_optimized, // this method isn't defined continuable but has been included in continuations in the past
++ _continuable_hidden, // defined as continuable, with "hidden" visibility
++ _continuable_readonly, // defined as continuable, with "readonly" visibility
++ _continuable_readwrite // defined as continuable, with "readwrite" visibility
++ };
++private:
+
+ // Bit vector of signature
+ // Callers interpret 0=not initialized yet and
+@@ -134,6 +143,7 @@
+ jbyte _interpreter_kind;
+ jbyte _flags;
+
++private:
+ // Size of Java bytecodes allocated immediately after methodOop.
+ u2 _code_size;
+ u2 _name_index; // Method name (index in constant pool)
+@@ -143,6 +153,8 @@
+ // but this may change with redefinition
+ u2 _generic_signature_index; // Generic signature (index in constant pool, 0 if absent)
+
++ ContinuableFlag _continuable;
++
+ public:
+ // Inlined tables
+ void set_inlined_tables_length(int checked_exceptions_len,
+@@ -158,6 +170,12 @@
+ bool has_localvariable_table() const
+ { return (_flags & _has_localvariable_table) != 0; }
+
++ bool is_continuable() const
++ { return _continuable != _not_continuable; }
++
++ void set_continuable(ContinuableFlag c) { _continuable = c; }
++ ContinuableFlag continuable() const { return _continuable; }
++
+ void set_interpreter_kind(int kind) { _interpreter_kind = kind; }
+ int interpreter_kind(void) const { return _interpreter_kind; }
+
+diff --git a/src/share/vm/oops/klass.hpp b/src/share/vm/oops/klass.hpp
+--- a/src/share/vm/oops/klass.hpp
++++ b/src/share/vm/oops/klass.hpp
+@@ -557,6 +557,7 @@
+
+ public:
+ // type testing operations
++ virtual bool oop_is_activationFrame() const { return false; }
+ virtual bool oop_is_instance_slow() const { return false; }
+ virtual bool oop_is_instanceRef() const { return false; }
+ virtual bool oop_is_array() const { return false; }
+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
+@@ -138,7 +138,7 @@
+ void methodOopDesc::mask_for(int bci, InterpreterOopMap* mask) {
+
+ Thread* myThread = Thread::current();
+- methodHandle h_this(myThread, this);
++ methodHandle h_this(myThread, this);/*
+ #ifdef ASSERT
+ bool has_capability = myThread->is_VM_thread() ||
+ myThread->is_ConcurrentGC_thread() ||
+@@ -154,7 +154,7 @@
+ local_mask.print();
+ }
+ }
+-#endif
++#endif*/
+ instanceKlass::cast(method_holder())->mask_for(h_this, bci, mask);
+ return;
+ }
+diff --git a/src/share/vm/oops/oop.hpp b/src/share/vm/oops/oop.hpp
+--- a/src/share/vm/oops/oop.hpp
++++ b/src/share/vm/oops/oop.hpp
+@@ -115,6 +115,7 @@
+ bool is_conc_safe();
+
+ // type test operations (inlined in oop.inline.h)
++ bool is_activationFrame() const;
+ bool is_instance() const;
+ bool is_instanceRef() const;
+ bool is_array() const;
+diff --git a/src/share/vm/oops/oop.inline.hpp b/src/share/vm/oops/oop.inline.hpp
+--- a/src/share/vm/oops/oop.inline.hpp
++++ b/src/share/vm/oops/oop.inline.hpp
+@@ -103,6 +103,7 @@
+
+ inline bool oopDesc::is_a(klassOop k) const { return blueprint()->is_subtype_of(k); }
+
++inline bool oopDesc::is_activationFrame() const { return blueprint()->oop_is_activationFrame(); }
+ inline bool oopDesc::is_instance() const { return blueprint()->oop_is_instance(); }
+ inline bool oopDesc::is_instanceRef() const { return blueprint()->oop_is_instanceRef(); }
+ inline bool oopDesc::is_array() const { return blueprint()->oop_is_array(); }
+diff --git a/src/share/vm/oops/oopsHierarchy.hpp b/src/share/vm/oops/oopsHierarchy.hpp
+--- a/src/share/vm/oops/oopsHierarchy.hpp
++++ b/src/share/vm/oops/oopsHierarchy.hpp
+@@ -34,6 +34,7 @@
+ #ifndef CHECK_UNHANDLED_OOPS
+
+ typedef class oopDesc* oop;
++typedef class activationFrameOopDesc* activationFrameOop;
+ typedef class instanceOopDesc* instanceOop;
+ typedef class methodOopDesc* methodOop;
+ typedef class constMethodOopDesc* constMethodOop;
+@@ -151,6 +152,7 @@
+ } \
+ }; \
+
++DEF_OOP(activationFrame);
+ DEF_OOP(instance);
+ DEF_OOP(method);
+ DEF_OOP(methodData);
+@@ -169,6 +171,7 @@
+ // The klass hierarchy is separate from the oop hierarchy.
+
+ class Klass;
++class activationFrameKlass;
+ class instanceKlass;
+ class instanceRefKlass;
+ class methodKlass;
+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
+@@ -77,6 +77,7 @@
+ }
+
+ extern "C" {
++ void JNICALL JVM_RegisterContinuationMethods(JNIEnv* env, jclass contcls);
+ void JNICALL JVM_RegisterUnsafeMethods(JNIEnv *env, jclass unsafecls);
+ void JNICALL JVM_RegisterMethodHandleMethods(JNIEnv *env, jclass unsafecls);
+ void JNICALL JVM_RegisterPerfMethods(JNIEnv *env, jclass perfclass);
+@@ -95,6 +96,9 @@
+ return CAST_FROM_FN_PTR(address, JVM_SetPrimitiveFieldValues);
+ }
+ }
++ if (strstr(jni_name, "Java_javax_stack_Continuation_registerNatives") != NULL) {
++ return CAST_FROM_FN_PTR(address, JVM_RegisterContinuationMethods);
++ }
+ if (strstr(jni_name, "Java_sun_misc_Unsafe_registerNatives") != NULL) {
+ return CAST_FROM_FN_PTR(address, JVM_RegisterUnsafeMethods);
+ }
+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
+@@ -1163,6 +1163,534 @@
+ UNSAFE_END
+
+
++void dump_compiledVFrame(compiledVFrame* frame) {
++ tty->print_cr("\t%s", frame->method()->name_and_sig_as_C_string());
++ tty->print("\tbci: %d ", frame->bci());
++ tty->print("locals: %d ", frame->locals()->size());
++ tty->print("expressions: %d\n", frame->expressions()->size());
++}
++
++
++class ActivationFrameInterpreterOopClosure : public OffsetClosure {
++ private:
++ activationFrameOop _af;
++
++ public:
++ ActivationFrameInterpreterOopClosure(activationFrameOop af) : _af(af) {}
++
++ void offset_do(int offset) {
++ oop value = *(oop*)_af->get_value_addr(offset);
++ if (value == NULL)
++ tty->print("null ");
++ else
++ tty->print("0x%08x (%s) ", value, value->blueprint()->name()->as_utf8());
++ }
++};
++
++class PrintOopsClosure : public OopClosure {
++public:
++ virtual void do_oop(oop* o) {
++ oop value = *o;
++ if (value == NULL)
++ tty->print("null ");
++ else
++ tty->print("0x%08x (%s) ", value, value->blueprint()->name()->as_utf8());
++ }
++ virtual void do_oop(narrowOop* o) {
++ }
++};
++
++class DummyCodeBlobClosure : public CodeBlobClosure {
++ public:
++ // Called for each code blob.
++ virtual void do_code_blob(CodeBlob* cb){
++ }
++};
++
++void dump_frame(activationFrameOop actFrame, JavaThread* thread) {
++ ResourceMark mark;
++ tty->print("frame 0x%08X ", actFrame);
++ if (actFrame->stack_pos() == NULL)
++ tty->print("(not present on stack) ", actFrame->stack_pos());
++ else
++ tty->print("(at stack pos %08x) ", actFrame->stack_pos());
++ if (actFrame->is_empty())
++ tty->print("empty ");
++ if (actFrame->is_filled())
++ tty->print("filled ");
++ if (actFrame->is_invalid())
++ tty->print("invalid ");
++ if (actFrame->is_delimited())
++ tty->print("delimited ");
++
++ if (actFrame->is_interpreted()) {
++ methodOop method = actFrame->get_methodOop();
++ tty->print("interpreted:\n");
++ tty->print_cr("\t%s", method->name_and_sig_as_C_string());
++ tty->print("\tbci: %d ", actFrame->bci());
++ tty->print("locals: %d ", method->max_locals());
++ tty->print("expressions: %d\n", actFrame->data_count() - method->max_locals());
++ tty->print("\toops: ");
++ {
++ ThreadInVMfromNative tivfn(JavaThread::current());
++ ActivationFrameInterpreterOopClosure blk(actFrame);
++ InterpreterOopMap mask;
++ actFrame->get_methodOop()->mask_for(actFrame->bci(), &mask);
++ mask.iterate_oop(&blk);
++ }
++ tty->cr();
++ }
++ if (actFrame->is_compiled()) {
++ tty->print("compiled: (pc: %08x)\n", actFrame->pc());
++ if (actFrame->is_filled()) {
++ frame fr(actFrame->frame_sp(), actFrame->frame_fp(), actFrame->pc());
++ RegisterMap map(thread);
++ vframe* frame = vframe::new_vframe(&fr, &map, thread);
++
++ dump_compiledVFrame((compiledVFrame*)frame);
++ while (!frame->is_top()) {
++ frame = frame->sender();
++ dump_compiledVFrame((compiledVFrame*)frame);
++ }
++ }
++ tty->print("\toops: ");
++ {
++ ThreadInVMfromNative tivfn(JavaThread::current());
++ PrintOopsClosure closure;
++ frame fr(actFrame->frame_sp(), actFrame->frame_fp(), actFrame->pc());
++ RegisterMap map(actFrame->thread());
++ map.set_include_argument_oops(false);
++ DummyCodeBlobClosure dummy;
++ fr.oops_do(&closure, &dummy, &map);
++ }
++ tty->cr();
++ }
++ if (actFrame->is_dummy()) {
++ tty->print("dummy frame\n");
++ }
++}
++
++
++jobject Continuation_dump(JNIEnv* env, jobject _this) {
++ tty->print("Continuation::dump\n");
++ oop simple_cont = JNIHandles::resolve(_this);
++ activationFrameOop frame = javax_stack_Continuation::data(simple_cont);
++ while (frame != NULL) {
++ dump_frame(frame, java_lang_Thread::thread(javax_stack_Continuation::thread(simple_cont)));
++ frame = frame->next();
++ }
++ klassOop k = SystemDictionary::Continuation_klass();
++ methodOop method = instanceKlass::cast(k)->find_method(vmSymbols::continueDelimitedInternal_name(), vmSymbols::continueDelimited_signature());
++ return NULL;
++}
++
++void Continuation_resume(JNIEnv* env, jobject _this, jobject value) {
++ JavaThread* THREAD = JavaThread::current();
++ ThreadInVMfromNative tivfm(THREAD);
++
++ oop thisOop = JNIHandles::resolve(_this);
++ if (javax_stack_Continuation::data(thisOop) == NULL) {
++ THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "Cannot resume an empty Continuation");
++ }
++ if (javax_stack_Continuation::thread(thisOop) != THREAD->threadObj()) {
++ THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "Cannot resume a Continuation that belongs to another thread");
++ }
++
++ oop valueOop = JNIHandles::resolve(value);
++ if (valueOop == javax_stack_Continuation::static_captured()) {
++ THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "Cannot pass Continuation.CAPTURED to resume");
++ }
++ assert(THREAD->current_continuation_frame(), "current_continuation_frame shouldn't be NULL");
++
++ // this method is intended only for error handling - all sane cases are covered by the assembler implementation
++ ShouldNotReachHere();
++}
++
++
++inline activationFrameOop createAndPatchFrame(frame &fr, TRAPS) {
++ if (fr.is_compiled_frame()) {
++ nmethod* nm = (nmethod*)fr.cb();
++
++ // native and non-continuable lead to an invalid frame
++ if (nm->is_native_method() || !nm->method()->constMethod()->is_continuable()) {
++ goto create_dummy_frame;
++ }
++
++ if (fr.pc() != fr.raw_pc()) {
++ tty->print("different pc");
++ }
++
++ // determine the address to change the return address to
++ address adr = nm->continuation_pc_table_begin();
++ address* entry;
++ while( adr < nm->continuation_pc_table_end() ) {
++ entry = (address*)adr;
++ if (entry[0] == fr.pc()) {
++ ((address *)fr.sp())[-1] = entry[1];
++ break;
++ }
++ adr += sizeof(address) * 2;
++ }
++ assert(adr != nm->continuation_pc_table_end(), "no callsite found in continuable method");
++
++ int size = align_object_size(nm->frame_size() + nm->stack_parameter_words() + activationFrameOopDesc::header_size());
++ assert(size * HeapWordSize == nm->activation_frame_size(), "wrong size");
++
++ KlassHandle h_k(Universe::activationFrameKlassObj());
++ activationFrameOopDesc* af = (activationFrameOop)CollectedHeap::obj_allocate(h_k, size, CHECK_NULL);
++
++ af->set_state(activationFrameOopDesc::_compiled_empty);
++ af->set_nmethod(nm);
++ af->set_stack_pos(fr.fp());
++ af->set_thread((JavaThread*)THREAD);
++ af->set_pc(entry[1]);
++
++ assert(af->size() == size, "wrong size");
++ return af;
++ }
++ if (fr.is_interpreted_frame()) {
++ // method might be invalidated by a safepoint
++ methodHandle method(fr.interpreter_frame_method());
++
++ // native and non-continuable lead to an invalid frame
++ if (method->is_native() || !method->constMethod()->is_continuable()) {
++ goto create_dummy_frame;
++ }
++ assert(fr.interpreter_frame_monitor_begin() == fr.interpreter_frame_monitor_end(), "cannot handle monitors in continuations");
++
++ int data_count = method->max_locals() + fr.interpreter_frame_expression_stack_size();
++ int size = align_object_size(activationFrameOopDesc::header_size() + data_count * HeapWordSize);
++
++ KlassHandle h_k(Universe::activationFrameKlassObj());
++ activationFrameOopDesc* af = (activationFrameOop)CollectedHeap::obj_allocate(h_k, size, CHECK_NULL);
++
++ af->set_state(activationFrameOopDesc::_interpreted_empty);
++ af->set_stack_pos(fr.fp());
++ af->set_methodOop(method());
++ af->set_bci(fr.interpreter_frame_bci());
++ af->set_data_count(data_count);
++
++ assert(((intptr_t*)fr.pc())[-2] == Interpreter::return_sentinel || ((intptr_t*)fr.pc())[-2] == Interpreter::return_sentinel, "missing sentinel");
++ intptr_t patch_pc = ((intptr_t*)fr.pc())[-3];
++ ((intptr_t *)fr.sp())[-1] = patch_pc;
++ af->set_pc((address)patch_pc);
++
++ assert(af->size() == size, "wrong size");
++ return af;
++ }
++
++create_dummy_frame:
++ int size = align_object_size(activationFrameOopDesc::header_size());
++
++ KlassHandle h_k(Universe::activationFrameKlassObj());
++ activationFrameOopDesc* af = (activationFrameOop)CollectedHeap::obj_allocate(h_k, size, CHECK_NULL);
++
++ af->set_state(activationFrameOopDesc::_dummy_invalid);
++ af->set_stack_pos(fr.fp());
++ af->set_pc(fr.pc());
++
++ assert(af->size() == size, "wrong size");
++ return af;
++}
++
++int cnt1 = 0;
++
++jobject Continuation_save(JNIEnv* env, jobject _this) {
++ jobject ret = NULL;
++ {
++ JavaThread* THREAD = JavaThread::current();
++ ThreadInVMfromNative tivfm(THREAD);
++
++ ret = JNIHandles::make_local(THREAD, javax_stack_Continuation::static_captured());
++
++ RegisterMap map(THREAD, false);
++ frame fr = THREAD->last_frame();
++ // skip native nmethod
++ fr = fr.sender(&map);
++
++ activationFrameOop af = createAndPatchFrame(fr, CHECK_NULL);
++ if (af->is_invalid()) {
++ THROW_MSG_0(vmSymbols::java_lang_IllegalThreadStateException(), "Cannot store continuations in non-continuable methods");
++ }
++
++ activationFrameOopDesc* last = THREAD->current_continuation_frame();
++ af->set_next(last);
++ THREAD->set_current_continuation_frame(af);
++
++// tty->print("save %i: %08x -> %08x\n", cnt1++, THREAD->current_continuation_frame(), THREAD->current_continuation_frame()->next());
++
++ if (_this != NULL) {
++ javax_stack_Continuation::set_data(JNIHandles::resolve(_this), af);
++ javax_stack_Continuation::set_thread(JNIHandles::resolve(_this), THREAD->threadObj());
++ }
++ }
++ return ret;
++}
++
++class MyObjClosure: public ObjectClosure {
++ virtual void do_object(oop obj) {
++ int* i = (int*)obj;
++ if (i == NULL)
++ return;
++ if (i[0] == (int)0xbaadbabe || i[1] == (int)0xbaadbabe) {
++ tty->print("bad");
++ }
++
++ int interp = 0;
++ int compiled = 0;
++ int dummy = 0;
++ if (obj->is_activationFrame()) {
++ activationFrameOop af = (activationFrameOop)obj;
++ if (af->is_interpreted())
++ interp++;
++ if (af->is_compiled())
++ compiled++;
++ if (af->is_dummy())
++ dummy++;
++ }
++ //tty->print("stats: %i interp, %i compiled, %i dummy\n", interp, compiled, dummy);
++ }
++};
++
++class MyOopClosure: public OopClosure {
++ virtual void do_oop(oop* obj) {
++ int* i = (int*)*obj;
++ if (i == NULL)
++ return;
++ if (i[0] == (int)0xbaadbabe || i[1] == (int)0xbaadbabe) {
++ tty->print("bad");
++ }
++ }
++ virtual void do_oop(narrowOop* obj) {
++ }
++};
++
++int cnt2 = 0;
++
++inline void Continuation_storeFrameGeneric(JNIEnv* env) {
++ JavaThread* THREAD = JavaThread::current();
++ ThreadInVMfromNative tivfm(THREAD);
++
++// tty->print("storeframe %i: %08x -> %08x\n", cnt2++, THREAD->current_continuation_frame(), THREAD->current_continuation_frame()->next());
++ RegisterMap map(THREAD, false);
++ // skip native nmethod
++ frame fr = THREAD->last_frame().sender(&map);
++
++ // save the frame contents
++ activationFrameOopDesc* fill = THREAD->current_continuation_frame();
++ assert(fill, "Continuation_storeFrameGeneric called without current AF");
++
++ if (Universe::heap()->total_collections() > 10) {
++ MyOopClosure ocl;
++ MyObjClosure cl;
++// Universe::heap()->oop_iterate(&ocl);
++// Universe::heap()->object_iterate(&cl);
++ }
++
++ if (fill->is_filled()) {
++ // just mark the frame as "not on stack"
++ fill->set_stack_pos(NULL);
++
++ } else if (fill->is_empty()) {
++
++ if (fill->state() == activationFrameOopDesc::_compiled_empty) {
++ // copy the contents of a compiled frame
++
++ jint size = fill->get_nmethod()->frame_size() + fill->get_nmethod()->stack_parameter_words();
++ intptr_t* sp = fr.unextended_sp();
++ assert(fill->stack_pos() == fr.fp(), "trying to fill the wrong activationFrameOop");
++ memcpy(fill->frame_sp(), sp, size * HeapWordSize);
++ fill->set_state(activationFrameOopDesc::_compiled_filled);
++ fill->set_stack_pos(NULL);
++ // TODO this only works with simple cardset barriers...?
++ oopDesc::bs()->write_ref_field(fill->frame_sp(), NULL);
++
++ } else if (fill->state() == activationFrameOopDesc::_interpreted_empty) {
++ // copy the contents of an interpreted frame: locals, expression stack
++
++ assert(fill->data_count() == (fr.interpreter_frame_method()->max_locals() + fr.interpreter_frame_expression_stack_size()), "wrong data count");
++ assert(fill->stack_pos() == fr.fp(), "wrong actual frame");
++ int max_locals = fill->get_methodOop()->max_locals();
++ for (int i=0; i<max_locals; i++) {
++ fill->set_value(i, *fr.interpreter_frame_local_at(i));
++ }
++ for (int i=max_locals; i<fill->data_count(); i++) {
++ int entry = i - max_locals;
++ fill->set_value(i, *fr.interpreter_frame_expression_stack_at(entry));
++ }
++ fill->set_state(activationFrameOopDesc::_interpreted_filled);
++ fill->set_stack_pos(NULL);
++ oopDesc::bs()->write_ref_field(fill, NULL);
++
++ } else {
++ ShouldNotReachHere();
++ }
++
++ } else if (fill->is_invalid()) {
++
++ if (THREAD->resume_common_frame() != NULL) {
++ // we've encountered an invalid frame while resuming
++ THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "Invalid frame encountered during resume");
++ } else {
++ // skip invalid frames
++ do {
++ fill->set_stack_pos(NULL);
++ fill = fill->next();
++// tty->print("invalid frame encountered (normal operation)\n");
++ } while(fill->is_invalid());
++ THREAD->set_current_continuation_frame(fill);
++ }
++
++ }
++
++ activationFrameHandle first_frame;
++ activationFrameHandle current(fill);
++ do {
++ fr = fr.sender(&map);
++ if (current->next() != NULL && current->next()->stack_pos() == fr.fp()) {
++#ifdef ASSERT
++ activationFrameOop next = current->next();
++ if (next->is_interpreted() || next->is_compiled()) {
++ if (fr.raw_pc() != current->next()->pc()) {
++ tty->print("different pc");
++ }
++ }
++#endif
++ // the next activationFrame already corresponds to the next stackframe, nothing to do...
++ if (first_frame.is_null())
++ first_frame = current->next();
++ //tty->print("Continuation_storeFrameGeneric: no need to create new object\n");
++ break;
++ } else {
++ activationFrameOop af = createAndPatchFrame(fr, CHECK);
++
++ if (af->is_invalid() && THREAD->resume_common_frame() != NULL)
++ Exceptions::_throw_msg(THREAD_AND_LOCATION, vmSymbols::java_lang_IllegalArgumentException(), "Invalid frame encountered during resume");
++
++ af->set_next(current->next());
++ current->set_next(af);
++ oopDesc::bs()->write_ref_field(((char*)current()) + in_bytes(activationFrameOopDesc::next_offset()), af);
++
++ if (first_frame.is_null())
++ first_frame = af;
++ current = af;
++ }
++ } while(current->is_invalid() && !fr.is_entry_frame());
++ THREAD->set_current_continuation_frame(first_frame());
++}
++
++jobject Continuation_storeFrameObject(JNIEnv* env, jclass klass, jobject retValue) {
++ Continuation_storeFrameGeneric(env);
++ return retValue;
++}
++
++void Continuation_storeFrameVoid(JNIEnv* env, jclass klass) {
++ Continuation_storeFrameGeneric(env);
++}
++
++jboolean Continuation_storeFrameBoolean(JNIEnv* env, jclass klass, jboolean retValue) {
++ Continuation_storeFrameGeneric(env);
++ return retValue;
++}
++
++jbyte Continuation_storeFrameByte(JNIEnv* env, jclass klass, jbyte retValue) {
++ Continuation_storeFrameGeneric(env);
++ return retValue;
++}
++
++jchar Continuation_storeFrameChar(JNIEnv* env, jclass klass, jchar retValue) {
++ Continuation_storeFrameGeneric(env);
++ return retValue;
++}
++
++jshort Continuation_storeFrameShort(JNIEnv* env, jclass klass, jshort retValue) {
++ Continuation_storeFrameGeneric(env);
++ return retValue;
++}
++
++jint Continuation_storeFrameInt(JNIEnv* env, jclass klass, jint retValue) {
++ Continuation_storeFrameGeneric(env);
++ return retValue;
++}
++
++jlong Continuation_storeFrameLong(JNIEnv* env, jclass klass, jlong retValue) {
++ Continuation_storeFrameGeneric(env);
++ return retValue;
++}
++
++jfloat Continuation_storeFrameFloat(JNIEnv* env, jclass klass, jfloat retValue) {
++ Continuation_storeFrameGeneric(env);
++ return retValue;
++}
++
++jdouble Continuation_storeFrameDouble(JNIEnv* env, jclass klass, jdouble retValue) {
++ Continuation_storeFrameGeneric(env);
++ return retValue;
++}
++
++jobject Continuation_unwind(JNIEnv* env, jclass klass, jobject exception) {
++ JavaThread* THREAD = JavaThread::current();
++ RegisterMap map(THREAD, false);
++ frame fr = THREAD->last_frame().sender(&map);
++ activationFrameOopDesc* fill = THREAD->current_continuation_frame();
++ if (fill->stack_pos() == fr.fp())
++ Continuation_storeFrameGeneric(env);
++
++ THROW_OOP_0(JNIHandles::resolve(exception));
++}
++
++jobject Continuation_startDelimited(JNIEnv* env, jclass klass, jobject runnable, jobject firstValue) {
++ ShouldNotReachHere();
++
++ // everything should be handled by the asm implementation
++ JavaThread* thread = JavaThread::current();
++
++ jmethodID method = env->GetStaticMethodID(klass, "startDelimitedInternal", "(Ljavax/stack/DelimitedRunnable;Ljava/lang/Object;)Ljava/lang/Object;");
++ jobject retValue = env->CallStaticObjectMethod(klass, method, runnable, firstValue);
++
++ activationFrameOop af = thread->current_continuation_frame();
++ assert(af->state() == activationFrameOopDesc::_dummy_invalid, "invalid frame state after startDelimitedInternal");
++
++ thread->set_current_continuation_frame(af->next());
++ af->set_state(activationFrameOopDesc::_dummy_delimited);
++ af->set_in_use(false);
++ af->set_stack_pos(NULL);
++ af->set_next(NULL);
++ oopDesc::bs()->write_ref_field(((char*)af) + in_bytes(activationFrameOopDesc::next_offset()), NULL);
++
++ return retValue;
++}
++
++jobject Continuation_continueDelimited(JNIEnv* env, jclass klass, jobject continuation, jobject value) {
++ JavaThread* THREAD = JavaThread::current();
++ DEBUG_ONLY(activationFrameHandle check_frame;)
++
++ oop contOop = JNIHandles::resolve(continuation);
++ if (javax_stack_Continuation::data(contOop) == NULL) {
++ THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(), "Cannot resume an empty Continuation", NULL);
++ }
++ if (javax_stack_Continuation::thread(contOop) != THREAD->threadObj()) {
++ THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(), "Cannot resume a Continuation that belongs to another thread", NULL);
++ }
++
++ activationFrameOop af = javax_stack_Continuation::data(contOop);
++ while (af->next() != NULL) {
++ af = af->next();
++ }
++
++ if (af->state() != activationFrameOopDesc::_dummy_delimited) {
++ THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(), "Continuation is not delimited", NULL);
++ }
++ if (af->in_use()) {
++ THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(), "Nested delimited continuation", NULL);
++ }
++
++ ShouldNotReachHere();
++
++ return NULL;
++}
++
++
+ /// JVM_RegisterUnsafeMethods
+
+ #define ADR "J"
+@@ -1457,6 +1985,29 @@
+ {CC"defineAnonymousClass", CC"("DAC_Args")"CLS, FN_PTR(Unsafe_DefineAnonymousClass)},
+ };
+
++#define CONT "Ljavax/stack/Continuation;"
++#define RUN "Ljavax/stack/DelimitedRunnable;"
++JNINativeMethod simple_cont_methods[] = {
++ {CC"save", CC"()"OBJ, FN_PTR(Continuation_save)},
++ {CC"resume", CC"("OBJ")V", FN_PTR(Continuation_resume)},
++ {CC"dump", CC"()"OBJ, FN_PTR(Continuation_dump)},
++ {CC"startDelimited", CC"("RUN OBJ")"OBJ, FN_PTR(Continuation_startDelimited)},
++ {CC"continueDelimited", CC"("CONT OBJ")"OBJ, FN_PTR(Continuation_continueDelimited)},
++ {CC"unwind", CC"("THR")"THR, FN_PTR(Continuation_unwind)},
++ {CC"storeFrameObject", CC"("OBJ")"OBJ, FN_PTR(Continuation_storeFrameObject)},
++ {CC"storeFrameVoid", CC"()V", FN_PTR(Continuation_storeFrameVoid)},
++ {CC"storeFrameBoolean", CC"(Z)Z", FN_PTR(Continuation_storeFrameBoolean)},
++ {CC"storeFrameByte", CC"(B)B", FN_PTR(Continuation_storeFrameByte)},
++ {CC"storeFrameChar", CC"(C)C", FN_PTR(Continuation_storeFrameChar)},
++ {CC"storeFrameShort", CC"(S)S", FN_PTR(Continuation_storeFrameShort)},
++ {CC"storeFrameInt", CC"(I)I", FN_PTR(Continuation_storeFrameInt)},
++ {CC"storeFrameLong", CC"(J)J", FN_PTR(Continuation_storeFrameLong)},
++ {CC"storeFrameFloat", CC"(F)F", FN_PTR(Continuation_storeFrameFloat)},
++ {CC"storeFrameDouble", CC"(D)D", FN_PTR(Continuation_storeFrameDouble)}
++};
++#undef RUN
++#undef CONT
++
+ #undef CC
+ #undef FN_PTR
+
+@@ -1555,3 +2106,45 @@
+ guarantee(status == 0, "register unsafe natives");
+ }
+ JVM_END
++
++#define SIMPLE_CONT_METHOD_COUNT (sizeof(simple_cont_methods)/sizeof(JNINativeMethod))
++
++JVM_ENTRY(void, JVM_RegisterContinuationMethods(JNIEnv *env, jclass contcls))
++ UnsafeWrapper("JVM_RegisterContinuationMethods");
++ {
++ ThreadToNativeFromVM ttnfv(thread);
++ {
++ env->RegisterNatives(contcls, simple_cont_methods, sizeof(simple_cont_methods)/sizeof(JNINativeMethod));
++ if (env->ExceptionOccurred()) {
++ if (PrintMiscellaneous && (Verbose || WizardMode)) {
++ tty->print_cr("Warning: SDK 1.7 Continuation classes not found.");
++ }
++ env->ExceptionClear();
++ } else {
++ // compile all native wrappers - the first three are instance methods, all other static
++ jmethodID ids[SIMPLE_CONT_METHOD_COUNT];
++ for (unsigned int i=0; i<SIMPLE_CONT_METHOD_COUNT; i++) {
++ if (i >= 3)
++ ids[i] = env->GetStaticMethodID(contcls, simple_cont_methods[i].name, simple_cont_methods[i].signature);
++ else
++ ids[i] = env->GetMethodID(contcls, simple_cont_methods[i].name, simple_cont_methods[i].signature);
++ }
++ {
++ ThreadInVMfromNative tivfn(thread);
++ for (unsigned int i=0; i<SIMPLE_CONT_METHOD_COUNT; i++) {
++ nmethod* nm = AdapterHandlerLibrary::create_native_wrapper(methodHandle(JNIHandles::resolve_jmethod_id(ids[i])));
++ if (strncmp("storeFrame", simple_cont_methods[i].name, 10) == 0)
++ javax_stack_Continuation::set_store_frames_nmethod(nm->method()->result_type(), nm);
++ if (strcmp("resume", simple_cont_methods[i].name) == 0)
++ javax_stack_Continuation::set_resume_nmethod(nm);
++ if (strcmp("save", simple_cont_methods[i].name) == 0)
++ javax_stack_Continuation::set_save_nmethod(nm);
++ if (strcmp("unwind", simple_cont_methods[i].name) == 0)
++ javax_stack_Continuation::set_unwind_nmethod(nm);
++
++ }
++ }
++ }
++ }
++ }
++JVM_END
+diff --git a/src/share/vm/runtime/annotationParser.cpp b/src/share/vm/runtime/annotationParser.cpp
+new file mode 100644
+--- /dev/null
++++ b/src/share/vm/runtime/annotationParser.cpp
+@@ -0,0 +1,186 @@
++
++# include "incls/_precompiled.incl"
++# include "incls/_annotationParser.cpp.incl"
++
++bool ElementValue::verify(symbolOop value_signature, int offset, TRAPS) {
++ AnnotationParser* parser = _annotation->_parser;
++ if (parser->length() < _start + 3)
++ return false;
++ if (offset >= value_signature->utf8_length())
++ return false;
++
++ klassOop value_type;
++ if (value_signature->byte_at(offset) == 'L')
++ value_type = parser->get_klass(oopFactory::new_symbol((char*)value_signature->base() + offset, value_signature->utf8_length() - offset, THREAD), THREAD);
++ else
++ value_type = NULL;
++
++ switch(tag()) {
++ case 'B':
++ case 'C':
++ case 'I':
++ case 'S':
++ case 'Z':
++ return value_signature->byte_at(offset) == tag() && parser->get_tag(_start + 1).is_int();
++ case 'D':
++ return value_signature->byte_at(offset) == tag() && parser->get_tag(_start + 1).is_double();
++ case 'F':
++ return value_signature->byte_at(offset) == tag() && parser->get_tag(_start + 1).is_float();
++ case 'J':
++ return value_signature->byte_at(offset) == tag() && parser->get_tag(_start + 1).is_long();
++ case 's':
++ if (!parser->get_tag(_start + 1).is_utf8())
++ return false;
++ // check that the signature return type can hold a string
++ return value_type != NULL && SystemDictionary::String_klass()->klass_part()->is_subtype_of(value_type);
++ case 'c':
++ if (!parser->get_tag(_start + 1).is_utf8())
++ return false;
++ if (parser->get_klass(_start + 1, THREAD) == NULL)
++ return false;
++ // check that the signature return type can hold a class
++ return value_type != NULL && SystemDictionary::Class_klass()->klass_part()->is_subtype_of(value_type);
++ case 'e':
++ {
++ if (parser->length() < _start + 5)
++ return false;
++ if (!parser->get_tag(_start + 1).is_utf8() || !parser->get_tag(_start + 3).is_utf8())
++ return false;
++ klassOop enum_type = parser->get_klass(_start + 1, THREAD);
++ if (enum_type == NULL)
++ return false;
++ symbolOop enum_const_name = parser->get_symbol(_start + 3);
++ if (value_type == NULL || !enum_type->klass_part()->is_subtype_of(value_type))
++ return false;
++ if (!parser->has_enum_field(instanceKlass::cast(enum_type), enum_const_name))
++ return false;
++ return true;
++ }
++ case '@':
++ {
++ Annotation annotation;
++ annotation_const(annotation);
++ if (annotation.verify(THREAD)) {
++ return value_type != NULL && annotation.get_type(THREAD)->klass_part()->is_subtype_of(value_type);
++ } else
++ return false;
++ }
++ case '[':
++ {
++ if (value_signature->byte_at(offset) != '[')
++ return false;
++ ArrayValue array;
++ array_const(array);
++ return array.verify(value_signature, offset + 1, THREAD);
++ }
++ default:
++ return false;
++ }
++}
++
++bool ArrayValue::verify(symbolOop component_signature, int offset, TRAPS) {
++ AnnotationParser* parser = _value->_annotation->_parser;
++ if (parser->length() < _start + 2)
++ return false;
++
++ ElementValue value = first_value();
++ for (int i=value_count(); i>0; i--) {
++ if (!value.verify(component_signature, offset, THREAD))
++ return false;
++ value = next_value(value, THREAD);
++ }
++ return true;
++}
++
++bool ElementValuePair::verify(instanceKlass* annotation_type, TRAPS) {
++ AnnotationParser* parser = _value._annotation->_parser;
++ if (parser->length() < start() + 2)
++ return false;
++
++ if (!parser->get_tag(start()).is_utf8())
++ return false;
++ methodOop value = parser->find_method(annotation_type, name());
++ if (value == NULL)
++ return false;
++ if (!value->is_abstract())
++ return false;
++ symbolOop signature = value->signature();
++ if (signature->byte_at(0) != '(' || signature->byte_at(1) != ')')
++ return false;
++
++ return _value.verify(signature, 2, THREAD);
++}
++
++bool Annotation::verify(TRAPS) {
++ if (_parser->length() < _start + 4)
++ return false;
++
++ if (!_parser->get_tag(_start).is_utf8())
++ return false;
++ klassOop type = get_type(THREAD);
++ if (type == NULL)
++ return false;
++ instanceKlass* klass = instanceKlass::cast(type);
++ // type needs to be an annotation type
++ if ((klass->access_flags().get_flags() & JVM_ACC_ANNOTATION) == 0)
++ return false;
++
++ ElementValuePair value = first_value();
++ for (int i=value_count(); i>0; i--) {
++ if (!value.verify(klass, THREAD))
++ return false;
++ value = next_value(value, THREAD);
++ }
++ return true;
++}
++
++bool AnnotationParser::verify(TRAPS) {
++ if (length() < 2)
++ return false;
++ Annotation annotation = first_annotation();
++ for (int i=annotation_count(); i>0; i--) {
++ if (!annotation.verify(THREAD))
++ return false;
++ annotation = next_annotation(annotation, THREAD);
++ }
++ return annotation._start == length();
++}
++
++
++methodOop AnnotationParser::find_method(instanceKlass* klass, symbolOop name) {
++ objArrayOop methods = klass->methods();
++ int len = methods->length();
++ // methods are sorted, so do binary search
++ int l = 0;
++ int h = len - 1;
++ while (l <= h) {
++ int mid = (l + h) >> 1;
++ methodOop m = (methodOop)methods->obj_at(mid);
++ assert(m->is_method(), "must be method");
++ int res = m->name()->fast_compare(name);
++ if (res == 0) {
++ return m;
++ } else if (res < 0) {
++ l = mid + 1;
++ } else {
++ h = mid - 1;
++ }
++ }
++ return NULL;
++}
++
++bool AnnotationParser::has_enum_field(instanceKlass* klass, symbolOop name) {
++ typeArrayOop fields = klass->fields();
++ constantPoolOop constants = klass->constants();
++ const int n = fields->length();
++ for (int i = 0; i < n; i += instanceKlass::next_offset ) {
++ int name_index = fields->ushort_at(i + instanceKlass::name_index_offset);
++ symbolOop f_name = constants->symbol_at(name_index);
++ if (f_name == name) {
++ return (fields->ushort_at(i + instanceKlass::access_flags_offset) & JVM_ACC_ENUM) != 0;
++ }
++ }
++ return false;
++}
++
++
+diff --git a/src/share/vm/runtime/annotationParser.hpp b/src/share/vm/runtime/annotationParser.hpp
+new file mode 100644
+--- /dev/null
++++ b/src/share/vm/runtime/annotationParser.hpp
+@@ -0,0 +1,316 @@
++
++class ElementValue;
++class ArrayValue;
++class ElementValuePair;
++class Annotation;
++class AnnotationParser;
++
++class ElementValue: public StackObj {
++ private:
++ int _start;
++ int _length;
++ Annotation* _annotation;
++
++ int length(TRAPS);
++ ElementValue(int start, Annotation* annotation) : _start(start), _length(-1), _annotation(annotation) { }
++ friend class ArrayValue;
++ friend class ElementValuePair;
++ public:
++
++ char tag();
++
++ jint int_const();
++ jlong long_const();
++ jfloat float_const();
++ jdouble double_const();
++ symbolOop string_const();
++ klassOop enum_const_type(TRAPS);
++ symbolOop enum_const_name();
++ klassOop klass_const(TRAPS);
++ // using output parameter to avoid circular dependency
++ void annotation_const(Annotation& annotation);
++ void array_const(ArrayValue& array);
++
++ bool verify(symbolOop value_signature, int offset, TRAPS);
++};
++
++class ArrayValue: public StackObj {
++ private:
++ int _start;
++ int _length;
++ ElementValue* _value;
++
++ int length(TRAPS);
++ ArrayValue() { }
++ ArrayValue(int start, ElementValue* value) : _start(start), _length(-1), _value(value) { }
++ friend class ElementValue;
++ public:
++
++ u2 value_count();
++ ElementValue first_value();
++ ElementValue next_value(ElementValue& value, TRAPS);
++
++ bool verify(symbolOop component_signature, int offset, TRAPS);
++};
++
++class ElementValuePair: public StackObj {
++ private:
++ ElementValue _value;
++
++ int start();
++ int length(TRAPS);
++ ElementValuePair(int start, Annotation* annotation) : _value(start + 2, annotation) { }
++ friend class Annotation;
++ public:
++
++ symbolOop name();
++ ElementValue& value();
++
++ bool verify(instanceKlass* annotation_type, TRAPS);
++};
++
++class Annotation: public StackObj {
++ private:
++ int _start;
++ int _length;
++ AnnotationParser* _parser;
++
++ int length(TRAPS);
++ Annotation() { }
++ Annotation(int start, AnnotationParser* parser) : _start(start), _length(-1), _parser(parser) { }
++ friend class AnnotationParser;
++ friend class ArrayValue;
++ friend class ElementValue;
++ friend class ElementValuePair;
++ public:
++ u2 value_count();
++ ElementValuePair first_value();
++ ElementValuePair next_value(ElementValuePair& value, TRAPS);
++
++ klassOop get_type(TRAPS);
++ symbolOop get_type_name();
++
++ bool verify(TRAPS);
++};
++
++class AnnotationParser: public StackObj {
++ private:
++ typeArrayHandle _array;
++ constantPoolHandle _constants;
++
++ int length() {
++ return _array->length();
++ }
++ u1 get_u1(int index) {
++ return _array->byte_at(index);
++ }
++ u2 get_u2(int index) {
++ return Bytes::get_Java_u2((u1*)_array->byte_at_addr(index));
++ }
++ symbolOop get_symbol(int index) {
++ return _constants->symbol_at(get_u2(index));
++ }
++ klassOop get_klass(int index, TRAPS) {
++ Klass* holder = _constants->pool_holder()->klass_part();
++ return SystemDictionary::resolve_or_null(get_symbol(index), holder->class_loader(), holder->protection_domain(), THREAD);
++ }
++ klassOop get_klass(symbolOop name, TRAPS) {
++ Klass* holder = _constants->pool_holder()->klass_part();
++ return SystemDictionary::resolve_or_null(name, holder->class_loader(), holder->protection_domain(), THREAD);
++ }
++
++ constantTag get_tag(int index) {
++ if (index < 0 || index >= length())
++ return constantTag(JVM_CONSTANT_Invalid);
++ else {
++ u2 cp_index = get_u2(index);
++ if (/*cp_index < 0 ||*/ cp_index >= _constants->length())
++ return constantTag(JVM_CONSTANT_Invalid);
++ else
++ return _constants->tag_at(cp_index);
++ }
++ }
++
++ friend class Annotation;
++ friend class ArrayValue;
++ friend class ElementValue;
++ friend class ElementValuePair;
++ public:
++ AnnotationParser(typeArrayHandle annotations, constantPoolHandle constants)
++ : _array(annotations), _constants(constants) {
++ }
++
++ u2 annotation_count() {
++ return get_u2(0);
++ }
++ Annotation first_annotation() {
++ return Annotation(2, this);
++ }
++ Annotation next_annotation(Annotation& ann, TRAPS) {
++ return Annotation(ann._start + ann.length(THREAD), this);
++ }
++
++ bool verify(TRAPS);
++
++ methodOop find_method(instanceKlass* klass, symbolOop name);
++ bool has_enum_field(instanceKlass* klass, symbolOop name);
++};
++
++
++// ElementValue inline functions
++
++inline int ElementValue::length(TRAPS) {
++ if (_length == -1) {
++ switch(tag()) {
++ case 'B':
++ case 'C':
++ case 'I':
++ case 'S':
++ case 'Z':
++ case 'D':
++ case 'F':
++ case 'J':
++ case 's':
++ case 'c':
++ _length = 3;
++ break;
++ case 'e':
++ _length = 5;
++ break;
++ case '@':
++ {
++ Annotation annotation;
++ annotation_const(annotation);
++ _length = annotation.length(THREAD) + 1;
++ break;
++ }
++ case '[':
++ {
++ ArrayValue array;
++ array_const(array);
++ _length = array.length(THREAD) + 1;
++ break;
++ }
++ break;
++ default:
++ ShouldNotReachHere();
++ break;
++ }
++ }
++ return _length;
++}
++inline char ElementValue::tag() {
++ return _annotation->_parser->get_u1(_start);
++}
++inline jint ElementValue::int_const() {
++ return _annotation->_parser->_constants->int_at(_annotation->_parser->get_u2(_start + 1));
++}
++inline jlong ElementValue::long_const() {
++ return _annotation->_parser->_constants->long_at(_annotation->_parser->get_u2(_start + 1));
++}
++inline jfloat ElementValue::float_const() {
++ return _annotation->_parser->_constants->float_at(_annotation->_parser->get_u2(_start + 1));
++}
++inline jdouble ElementValue::double_const() {
++ return _annotation->_parser->_constants->double_at(_annotation->_parser->get_u2(_start + 1));
++}
++inline symbolOop ElementValue::string_const() {
++ return _annotation->_parser->_constants->symbol_at(_annotation->_parser->get_u2(_start + 1));
++}
++inline klassOop ElementValue::enum_const_type(TRAPS) {
++ return _annotation->_parser->get_klass(_start + 1, THREAD);
++}
++inline symbolOop ElementValue::enum_const_name() {
++ return _annotation->_parser->get_symbol(_start + 3);
++}
++inline klassOop ElementValue::klass_const(TRAPS) {
++ return _annotation->_parser->get_klass(_start + 1, THREAD);
++}
++inline void ElementValue::annotation_const(Annotation& annotation) {
++ annotation = Annotation(_start + 1, _annotation->_parser);
++}
++inline void ElementValue::array_const(ArrayValue& array) {
++ array = ArrayValue(_start + 1, this);
++}
++
++// ArrayValue inline functions
++
++inline u2 ArrayValue::value_count() {
++ return _value->_annotation->_parser->get_u2(_start);
++}
++inline int ArrayValue::length(TRAPS) {
++ if (_length == -1) {
++ // u2 num_values
++ _length = 2;
++ ElementValue value = first_value();
++ for (int i=value_count(); i>0; i--) {
++ _length += value.length(THREAD);
++ value = next_value(value, THREAD);
++ }
++ }
++ return _length;
++}
++inline ElementValue ArrayValue::first_value() {
++ return ElementValue(_start + 2, _value->_annotation);
++}
++inline ElementValue ArrayValue::next_value(ElementValue& value, TRAPS) {
++ return ElementValue(value._start + value.length(THREAD), _value->_annotation);
++}
++
++// ElementValuePair inline functions
++inline int ElementValuePair::start() {
++ return _value._start - 2;
++}
++inline int ElementValuePair::length(TRAPS) {
++ return _value.length(THREAD) + 2;
++}
++inline symbolOop ElementValuePair::name() {
++ return _value._annotation->_parser->get_symbol(start());
++}
++inline ElementValue& ElementValuePair::value() {
++ return _value;
++}
++
++// Annotation inline functions
++
++inline int Annotation::length(TRAPS) {
++ if (_length == -1) {
++ // u2 type_index and u2 num_element_value_pairs
++ _length = 4;
++ ElementValuePair value = first_value();
++ for (int i=value_count(); i>0; i--) {
++ _length += value.length(THREAD);
++ value = next_value(value, THREAD);
++ }
++ }
++ return _length;
++}
++inline u2 Annotation::value_count() {
++ return _parser->get_u2(_start + 2);
++}
++inline ElementValuePair Annotation::first_value() {
++ return ElementValuePair(_start + 4, this);
++}
++inline ElementValuePair Annotation::next_value(ElementValuePair& value, TRAPS) {
++ return ElementValuePair(value.start() + value.length(THREAD), this);
++}
++inline klassOop Annotation::get_type(TRAPS) {
++ return _parser->get_klass(_start, THREAD);
++}
++inline symbolOop Annotation::get_type_name() {
++ return _parser->get_symbol(_start);
++}
++
++
++
++
++
++
++
++
++
++
++
++
++
++
+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
+@@ -180,6 +180,7 @@
+ };
+
+
++DEF_HANDLE(activationFrame , is_activationFrame )
+ DEF_HANDLE(instance , is_instance )
+ DEF_HANDLE(method , is_method )
+ DEF_HANDLE(constMethod , is_constMethod )
+@@ -216,6 +217,7 @@
+ };
+
+
++DEF_KLASS_HANDLE(activationFrameKlass , oop_is_activationFrame )
+ DEF_KLASS_HANDLE(instanceKlass , oop_is_instance_slow )
+ DEF_KLASS_HANDLE(methodKlass , oop_is_method )
+ DEF_KLASS_HANDLE(constMethodKlass , oop_is_constMethod )
+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
+@@ -1177,6 +1177,10 @@
+ _interp_only_mode = 0;
+ _special_runtime_exit_condition = _no_async_condition;
+ _pending_async_exception = NULL;
++ _current_continuation_frame = NULL;
++ _resume_continuation_frame = NULL;
++ _resume_common_frame = NULL;
++ _resume_return_value = NULL;
+ _is_compiling = false;
+ _thread_stat = NULL;
+ _thread_stat = new ThreadStatistics();
+@@ -2418,6 +2422,10 @@
+ f->do_oop((oop*) &_vm_result_2);
+ f->do_oop((oop*) &_exception_oop);
+ f->do_oop((oop*) &_pending_async_exception);
++ f->do_oop((oop*) &_current_continuation_frame);
++ f->do_oop((oop*) &_resume_continuation_frame);
++ f->do_oop((oop*) &_resume_common_frame);
++ f->do_oop((oop*) &_resume_return_value);
+
+ if (jvmti_thread_state() != NULL) {
+ jvmti_thread_state()->oops_do(f);
+@@ -3015,6 +3023,10 @@
+ warning("java.lang.String not initialized");
+ }
+
++ klassOop cont_klass = SystemDictionary::resolve_or_null(vmSymbolHandles::javax_stack_Continuation(), CHECK_0);
++ if (cont_klass != NULL)
++ instanceKlass::cast(cont_klass)->initialize(CHECK_0);
++
+ if (AggressiveOpts) {
+ {
+ // Forcibly initialize java/util/HashMap and mutate the private
+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
+@@ -787,6 +787,32 @@
+ // This is set to popframe_pending to signal that top Java frame should be popped immediately
+ int _popframe_condition;
+
++ //// continuation support
++ activationFrameOop _current_continuation_frame;
++ activationFrameOop _resume_continuation_frame;
++ activationFrameOop _resume_common_frame;
++ oop _resume_return_value;
++
++ public:
++ static ByteSize current_continuation_frame_offset() { return byte_offset_of(JavaThread, _current_continuation_frame); }
++ static ByteSize resume_continuation_frame_offset() { return byte_offset_of(JavaThread, _resume_continuation_frame); }
++ static ByteSize resume_common_frame_offset() { return byte_offset_of(JavaThread, _resume_common_frame); }
++ static ByteSize resume_return_value_offset() { return byte_offset_of(JavaThread, _resume_return_value); }
++
++ activationFrameOop current_continuation_frame() const { return _current_continuation_frame; }
++ void set_current_continuation_frame (activationFrameOop x) { _current_continuation_frame = x; }
++
++ activationFrameOop resume_continuation_frame() const { return _resume_continuation_frame; }
++ void set_resume_continuation_frame (activationFrameOop x) { _resume_continuation_frame = x; }
++
++ activationFrameOop resume_common_frame() const { return _resume_common_frame; }
++ void set_resume_common_frame (activationFrameOop x) { _resume_common_frame = x; }
++
++ oop resume_return_value() const { return _resume_return_value; }
++ void set_resume_return_value (oop x) { _resume_return_value = x; }
++
++ private:
++
+ #ifndef PRODUCT
+ int _jmp_ring_index;
+ struct {
+diff --git a/src/share/vm/runtime/vmStructs.cpp b/src/share/vm/runtime/vmStructs.cpp
+--- a/src/share/vm/runtime/vmStructs.cpp
++++ b/src/share/vm/runtime/vmStructs.cpp
+@@ -939,6 +939,8 @@
+ declare_type(methodKlass, Klass) \
+ declare_type(constMethodKlass, Klass) \
+ declare_type(methodOopDesc, oopDesc) \
++ declare_type(activationFrameKlass, Klass) \
++ declare_type(activationFrameOopDesc, oopDesc) \
+ declare_type(objArrayKlass, arrayKlass) \
+ declare_type(objArrayKlassKlass, arrayKlassKlass) \
+ declare_type(objArrayOopDesc, arrayOopDesc) \
+@@ -953,6 +955,7 @@
+ /* Oops */ \
+ /********/ \
+ \
++ declare_oop_type(activationFrameOop) \
+ declare_oop_type(constantPoolOop) \
+ declare_oop_type(constantPoolCacheOop) \
+ declare_oop_type(klassOop) \
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/callcc_old.txt Thu Oct 28 15:18:01 2010 +0200
@@ -0,0 +1,34 @@
+6655643: some dynamic languages need stack reification
+Summary: low-level continuation support
+
+http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6655643
+
+Features:
+- lazy continuation storage
+- optionally delimited continuations
+
+Authors:
+- Lukas Stadler (JKU, Linz)
+- John Rose (Sun)
+
+Tests:
+ (These are junit tests, they serve mainly to explain the usage of Continuations)
+ javax.stack.*
+
+Incremental testing:
+This does not require a full JDK build.
+
+$ rm -rf build/bootcp
+$ mkdir build/bootcp
+
+$ files='
+sources/jdk/src/share/classes/javax/stack/Continuation.java
+sources/jdk/src/share/classes/javax/stack/Continuable.java
+sources/jdk/src/share/classes/javax/stack/ContinuableAccess.java
+sources/jdk/src/share/classes/javax/stack/ContinuationPermission.java
+sources/jdk/src/share/classes/javax/stack/DelimitedRunnable.java
+sources/jdk/src/share/classes/javax/stack/Fiber.java
+sources/jdk/test/javax/stack/*.java
+'
+$ javac -d build/bootcp $files
+$ java -XXaltjvm=?? -Xbootclasspath/p:build/bootcp TestCopyStack
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/continuation.patch Thu Oct 28 15:18:01 2010 +0200
@@ -0,0 +1,3262 @@
+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
+@@ -31,6 +31,8 @@
+ #endif // COMPILER2
+
+ DeoptimizationBlob *SharedRuntime::_deopt_blob;
++RuntimeStub* SharedRuntime::_continuation_save_blob;
++RuntimeStub* SharedRuntime::_continuation_resume_blob;
+ SafepointBlob *SharedRuntime::_polling_page_safepoint_handler_blob;
+ SafepointBlob *SharedRuntime::_polling_page_return_handler_blob;
+ RuntimeStub* SharedRuntime::_wrong_method_blob;
+@@ -2642,6 +2644,270 @@
+ _deopt_blob->set_unpack_with_exception_in_tls_offset(exception_in_tls_offset);
+ }
+
++RuntimeStub* SharedRuntime::generate_continuation_save_blob() {
++ const char* name = "continuation_save_stub";
++ ResourceMark rm;
++ CodeBuffer buffer(name, 2048, 2048);
++ MacroAssembler* masm = new MacroAssembler(&buffer);
++ int frame_size = 0;
++
++ // This code is called like a void func(thread, sp, fp, pc, &rv_oop) from Unsafe_CutStack
++
++ // trash the (unneeded) return pc
++ __ pop(rdi);
++
++ // pop the thread
++ __ pop(rcx);
++ __ reset_last_Java_frame(rcx, false, true);
++
++ // pop arguments
++ __ pop(rdi); // sp
++ __ pop(rsi); // fp
++ __ pop(rbx); // pc
++ __ pop(rax); // &rv
++
++ // Set last Java frame
++ __ set_last_Java_frame(rcx, rdi, rsi, NULL);
++
++ // Cut to the frame
++ __ movl(rsp, rdi);
++ __ movl(rbp, rsi);
++
++ __ push(rbx); // push the cut pc as the return pc
++ __ push(rbp); // construct a dummy frame
++ __ movl(rbp, rsp);
++ __ push(rcx); // save thread ptr
++ __ push(rax); // push the address of the return value
++ __ push(rcx); // push thread ptr for the call
++
++ // Call a C function that deallocates the
++ // ThreadInVMfromNativeForContinuation object. This could block for
++ // GC.
++ __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, ThreadInVMfromNativeForContinuation::dealloc)));
++ __ addl(rsp, 4); // discard the param
++
++ __ pop(rax); // address of return value
++ __ pop(rcx); // pop the thread ptr
++ __ push(rax); // address of return value
++
++ __ movl(Address(rcx, JavaThread::thread_state_offset()), _thread_in_native_trans);
++
++ if(os::is_MP()) {
++ if (UseMembar) {
++ // Force this write out before the read below
++ __ membar(Assembler::Membar_mask_bits(
++ Assembler::LoadLoad | Assembler::LoadStore |
++ Assembler::StoreLoad | Assembler::StoreStore));
++ } else {
++ // Write serialization page so VM thread can do a pseudo remote membar.
++ // We use the current thread pointer to calculate a thread specific
++ // offset to write to within the page. This minimizes bus traffic
++ // due to cache line collision.
++ __ serialize_memory(rcx, rdx);
++ }
++ }
++
++ if (AlwaysRestoreFPU) {
++ // Make sure the control word is correct.
++ __ fldcw(ExternalAddress(StubRoutines::addr_fpu_cntrl_wrd_std()));
++ }
++
++ // check for safepoint operation in progress and/or pending suspend requests
++ { Label Continue;
++
++ __ cmp32(ExternalAddress((address)SafepointSynchronize::address_of_state()),
++ SafepointSynchronize::_not_synchronized);
++
++ Label L;
++ __ jcc(Assembler::notEqual, L);
++ __ cmpl(Address(rcx, JavaThread::suspend_flags_offset()), 0);
++ __ jcc(Assembler::equal, Continue);
++ __ bind(L);
++
++ // Don't use call_VM as it will see a possible pending exception and forward it
++ // and never return here preventing us from clearing _last_native_pc down below.
++ // Also can't use call_VM_leaf either as it will check to see if rsi & rdi are
++ // preserved and correspond to the bcp/locals pointers. So we do a runtime call
++ // by hand.
++ //
++ __ push(rcx);
++ __ push(rcx);
++ __ call(RuntimeAddress(CAST_FROM_FN_PTR(address,
++ JavaThread::check_special_condition_for_native_trans)));
++ __ increment(rsp, wordSize);
++ __ pop(rcx);
++
++ __ bind(Continue);
++ }
++
++ // reguard the stack ?
++
++ __ pop(rax); // address of return value
++ __ movl(rax, Address(rax, 0)); // unhandle rv
++
++ // reset handle block
++ __ movl(rdi, Address(rcx, JavaThread::active_handles_offset()));
++ __ movl(Address(rdi, JNIHandleBlock::top_offset_in_bytes()), 0);
++
++ // Compiled code leaves the floating point stack dirty, empty it.
++ __ empty_FPU_stack();
++
++ // Change the thread state to _thread_in_Java
++ __ movl(Address(rcx, JavaThread::thread_state_offset()), _thread_in_Java);
++
++ // This field must remain non-null so that GC won't check the
++ // outgoing arguments of the enter0 frame (they could be invalid oops
++ // if the frame above is a compiled frame). But now it should be
++ // nullified because GC won't happen in this blob at this point.
++ __ movl(Address(rcx, JavaThread::cont_thread_transition_offset()), NULL_WORD);
++
++ __ reset_last_Java_frame(rcx, true, true);
++
++ __ leave(); // deconstruct the frame
++ __ ret(0); // return to the cut pc (the top frame of the resumed stack)
++
++ // -------------
++ // make sure all code is generated
++ masm->flush();
++
++ return RuntimeStub::new_runtime_stub(name, &buffer, CodeOffsets::frame_never_safe, 0, NULL, true);
++}
++
++RuntimeStub* SharedRuntime::generate_continuation_resume_blob() {
++ const char* name = "continuation_resume_stub";
++ ResourceMark rm;
++ CodeBuffer buffer(name, 2048, 2048);
++ MacroAssembler* masm = new MacroAssembler(&buffer);
++
++ // This code is called like a void func(JavaThread* thread, ResumeBlock* rb) from Unsafe_ResumeStack0
++
++ // Pop the unneeded return pc
++ __ pop(rsi);
++
++ // Pop the thread
++ __ pop(rcx);
++ __ reset_last_Java_frame(rcx, false, true);
++
++ // Compiled code leaves the floating point stack dirty, empty it.
++ __ empty_FPU_stack();
++
++ // Pop the ResumeBlock*
++ __ pop(rdi);
++
++ // Get the image
++ __ movl(rsi, Address(rdi, ResumeBlock::top_sp_offset_in_bytes()));
++ __ movl(rax, Address(rdi, ResumeBlock::image_offset_in_bytes()));
++ __ movl(rbx, Address(rdi, ResumeBlock::image_size_offset_in_bytes()));
++ // rsi sp, rai - image, rbx - image_size
++
++ // Copy the image into the stack
++ Label resume_frames_loop;
++ __ bind(resume_frames_loop);
++ __ movl(rdx, Address(rax, 0)); // read from the image
++ __ movl(Address(rsi, 0), rdx); // write into the stack
++ __ addl(rsi, 4); // increment the pointer
++ __ addl(rax, 4); //
++ __ subl(rbx, 1); // decerement the length
++ __ jcc(Assembler::notZero, resume_frames_loop);
++
++ // Move (shift) the locals of the bottom frame
++ // rsi points to one word past the bottom here
++ Label move_bottom_frame_locals_loop;
++ Label move_bottom_frame_locals_loop_cont;
++ __ movl(rax, Address(rdi, ResumeBlock::alignment_padding_offset_in_bytes()));
++ __ movl(rbx, Address(rdi, ResumeBlock::bottom_frame_max_locals_offset_in_bytes()));
++ // Check if the padding == 0 or max_locals == 0
++ __ testl(rax, rax);
++ __ jcc(Assembler::zero, move_bottom_frame_locals_loop_cont);
++ __ testl(rbx, rbx);
++ __ jcc(Assembler::zero, move_bottom_frame_locals_loop_cont);
++
++ __ movl(rdx, rsi);
++ __ shll(rax, 2); // words -> bytes
++ __ addl(rdx, rax);
++
++ // rsi: copy dest, rdx: copy src, rbx: counter
++ // loop
++ __ bind(move_bottom_frame_locals_loop);
++ __ movl(rax, Address(rdx, 0));
++ __ movl(Address(rsi, 0), rax);
++ __ movl(Address(rdx, 0), 0xbaadbaad); // for error detection
++ __ addl(rsi, 4);
++ __ addl(rdx, 4);
++ __ subl(rbx, 1);
++ __ jcc(Assembler::notZero, move_bottom_frame_locals_loop);
++ __ bind(move_bottom_frame_locals_loop_cont);
++
++ // Set sp, fp, rv
++ __ movl(rsi, Address(rdi, ResumeBlock::top_sp_offset_in_bytes()));
++ __ movl(rbx, Address(rdi, ResumeBlock::top_fp_offset_in_bytes()));
++ __ movl(rdx, Address(rdi, ResumeBlock::top_pc_offset_in_bytes()));
++ // rax = handle of the return value
++ __ movl(rax, Address(rdi, ResumeBlock::return_value_offset_in_bytes()));
++
++ // Restore the top frame sp and fp
++ __ movl(rsp, rsi);
++ __ movl(rbp, rbx);
++
++ // Set last Java frame
++ __ set_last_Java_frame(rcx, rsi, rbx, NULL);
++ // After jumping back to the native wrapper at the end of this
++ // rountine, we could hit a safepoint. But the only pc that has an oop
++ // map in the native wrapper is the rough pc set by the native
++ // wrapper. So, we must set the last Java pc to it.
++ __ movl(rsi, Address(rdi, ResumeBlock::rough_top_pc_offset_in_bytes()));
++ __ movl(Address(rcx, JavaThread::last_Java_pc_offset()), rsi);
++
++ // The native wrapper expects to see the thread ptr preserved in rdi.
++ // Note rdi is a callee saved register in the C convention.
++ __ movl(rdi, rcx);
++
++ // push resume pc (rdx) and rv (rax) on stack to preserve across the C call.
++ __ push(rdx);
++ __ push(rax);
++ __ push(rcx); // one for each of the two calls
++ __ push(rcx);
++ // call a C function that deallocates deopt_mark
++ __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, Deoptimization::dealloc_deopt_mark)));
++ __ addl(rsp, 4); // discard the param
++
++ __ pop(rcx); // thread ptr
++ __ pop(rax); // the handle of the return value
++ __ pop(rdx); // resume pc
++
++ __ push(rdx); // push the resume pc as the return pc
++ __ push(rbp); // construct a dummy frame
++ __ movl(rbp, rsp);
++ __ push(rax); // push the handle of the return value
++ __ push(rcx); // save the thread ptr across the call
++ __ push(rcx); // push the thread ptr for the call
++
++ // call a C function that deallocates the
++ // ThreadInVMfromNativeForContinuation object. This could block for
++ // GC.
++ __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, ThreadInVMfromNativeForContinuation::dealloc)));
++ __ addl(rsp, 4); // discard the param
++
++ // This field must remain non-null so that GC won't check the
++ // outgoing arguments of the top frame which could be invalid
++ // oops. But now it should be nullified because GC won't happen in
++ // this blob at this point.
++ __ pop(rcx); // the thread ptr
++ __ movl(Address(rcx, JavaThread::cont_thread_transition_offset()), NULL_WORD);
++
++ // Since we're returning to native wrapper/entry, the return value
++ // should be handlized here.
++ __ pop(rax); // pop the handle of the return value
++
++ __ leave(); // deconstruct the frame
++ __ ret(0); // return to the resume pc (the top frame of the resumed stack)
++
++ // -------------
++ // make sure all code is generated
++ masm->flush();
++
++ return RuntimeStub::new_runtime_stub(name, &buffer, CodeOffsets::frame_never_safe, 0, NULL, true);
++}
+
+ #ifdef COMPILER2
+ //------------------------------generate_uncommon_trap_blob--------------------
+@@ -3031,7 +3297,11 @@
+ generate_handler_blob(CAST_FROM_FN_PTR(address,
+ SafepointSynchronize::handle_polling_page_exception), true);
+
++ _continuation_save_blob = generate_continuation_save_blob();
++ _continuation_resume_blob = generate_continuation_resume_blob();
++
+ generate_deopt_blob();
++
+ #ifdef COMPILER2
+ generate_uncommon_trap_blob();
+ #endif // COMPILER2
+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
+@@ -33,6 +33,8 @@
+
+ SafepointBlob *SharedRuntime::_polling_page_safepoint_handler_blob;
+ SafepointBlob *SharedRuntime::_polling_page_return_handler_blob;
++RuntimeStub* SharedRuntime::_continuation_save_blob;
++RuntimeStub* SharedRuntime::_continuation_resume_blob;
+ RuntimeStub* SharedRuntime::_wrong_method_blob;
+ RuntimeStub* SharedRuntime::_ic_miss_blob;
+ RuntimeStub* SharedRuntime::_resolve_opt_virtual_call_blob;
+@@ -2831,6 +2833,249 @@
+ _deopt_blob->set_unpack_with_exception_in_tls_offset(exception_in_tls_offset);
+ }
+
++RuntimeStub* SharedRuntime::generate_continuation_save_blob() {
++ const char* name = "continuation_save_stub";
++ ResourceMark rm;
++ CodeBuffer buffer(name, 2048, 2048);
++ MacroAssembler* masm = new MacroAssembler(&buffer);
++ int frame_size = 0;
++
++ // This code is called like a void func(thread, sp, fp, pc, &rv_oop) from Unsafe_CutStack
++ // thread on rdi
++ // sp on rsi
++ // fp on rdx
++ // pc on rcx
++ // &rv_oop on r8
++
++ // pop thread
++ __ mov(r15_thread, rdi);
++ __ reset_last_Java_frame(false, true);
++
++ // trash the (unneeded) return pc
++ __ pop(rdi);
++
++ // Set last Java frame
++ __ set_last_Java_frame(rsi, rdx, NULL);
++
++ // Cut to the frame
++ __ mov(rsp, rsi);
++ __ mov(rbp, rdx);
++
++ __ push(rcx); // push the cut pc as the return pc
++ __ push(rbp); // construct a dummy frame
++ __ mov(rbp, rsp);
++ __ push(r8); // save the address of the return value across the call
++ __ mov(rdi, r15_thread); // pass thread ptr to the call
++
++ // Call a C function that deallocates the
++ // ThreadInVMfromNativeForContinuation object. This could block for
++ // GC.
++ __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, ThreadInVMfromNativeForContinuation::dealloc)));
++ // r15_thread is callee-saved
++
++ __ movl(Address(r15_thread, JavaThread::thread_state_offset()), _thread_in_native_trans);
++
++ if(os::is_MP()) {
++ if (UseMembar) {
++ // Force this write out before the read below
++ __ membar(Assembler::Membar_mask_bits(
++ Assembler::LoadLoad | Assembler::LoadStore |
++ Assembler::StoreLoad | Assembler::StoreStore));
++ } else {
++ // Write serialization page so VM thread can do a pseudo remote membar.
++ // We use the current thread pointer to calculate a thread specific
++ // offset to write to within the page. This minimizes bus traffic
++ // due to cache line collision.
++ __ serialize_memory(r15_thread, rcx);
++ }
++ }
++
++ // check for safepoint operation in progress and/or pending suspend requests
++ {
++ Label Continue;
++
++ __ cmp32(ExternalAddress((address)SafepointSynchronize::address_of_state()),
++ SafepointSynchronize::_not_synchronized);
++
++ Label L;
++ __ jcc(Assembler::notEqual, L);
++ __ cmpl(Address(r15_thread, JavaThread::suspend_flags_offset()), 0);
++ __ jcc(Assembler::equal, Continue);
++ __ bind(L);
++
++ // Don't use call_VM as it will see a possible pending exception and forward it
++ // and never return here preventing us from clearing _last_native_pc down below.
++ // Also can't use call_VM_leaf either as it will check to see if rsi & rdi are
++ // preserved and correspond to the bcp/locals pointers. So we do a runtime call
++ // by hand.
++ //
++ __ mov(c_rarg0, r15_thread);
++ __ mov(r12, rsp); // remember sp
++ __ subptr(rsp, frame::arg_reg_save_area_bytes); // windows
++ __ andptr(rsp, -16); // align stack as required by ABI
++ __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, JavaThread::check_special_condition_for_native_trans)));
++ __ mov(rsp, r12); // restore sp
++ __ reinit_heapbase();
++ __ bind(Continue);
++
++ }
++
++ // regard the stack ?
++
++ __ pop(r8); // restore rv
++ __ movq(rax, Address(r8, 0)); // unhandle rv
++
++ // reset handle block
++ __ movptr(rdi, Address(r15_thread, JavaThread::active_handles_offset()));
++ __ movptr(Address(rdi, JNIHandleBlock::top_offset_in_bytes()), (int32_t)NULL_WORD);
++
++ __ movl(Address(r15_thread, JavaThread::thread_state_offset()), _thread_in_Java);
++
++ // This field must remain non-null so that GC won't check the
++ // outgoing arguments of the enter0 frame (they could be invalid oops
++ // if the frame above is a compiled frame). But now it should be
++ // nullified because GC won't happen in this blob at this point.
++ __ movptr(Address(r15_thread, JavaThread::cont_thread_transition_offset()), (intptr_t) NULL_WORD);
++
++ __ reset_last_Java_frame(true, true);
++
++ __ leave(); // deconstruct the frame
++ __ ret(0); // return to the cut pc (the top frame of the resumed stack)
++
++ // -------------
++ // make sure all code is generated
++ masm->flush();
++
++ return RuntimeStub::new_runtime_stub(name, &buffer, CodeOffsets::frame_never_safe, 0, NULL, true);
++}
++
++RuntimeStub* SharedRuntime::generate_continuation_resume_blob() {
++ const char* name = "continuation_resume_stub";
++ ResourceMark rm;
++ CodeBuffer buffer(name, 2048, 2048);
++ MacroAssembler* masm = new MacroAssembler(&buffer);
++
++ // This code is called like a void func(JavaThread* thread, ResumeBlock* rb) from Unsafe_ResumeStack0
++ // thread on rdi
++ // rb on rsi
++
++ // Set r15_thread
++ __ mov(r15_thread, rdi);
++ __ reset_last_Java_frame(false, true);
++
++ // Pop the unneeded return pc
++ __ pop(rdx);
++
++ // Set the ResumeBlock* in rdi
++ __ mov(rdi, rsi);
++
++ // Get the image
++ __ movq(rsi, Address(rdi, ResumeBlock::top_sp_offset_in_bytes()));
++ __ movq(rax, Address(rdi, ResumeBlock::image_offset_in_bytes()));
++ __ movq(rbx, Address(rdi, ResumeBlock::image_size_offset_in_bytes()));
++ // rsi sp, rai - image, rbx - image_size
++
++ // Copy the image into the stack
++ Label resume_frames_loop;
++ __ bind(resume_frames_loop);
++ __ movq(rdx, Address(rax, 0)); // read from the image
++ __ movq(Address(rsi, 0), rdx); // write into the stack
++ __ addq(rsi, 8); // increment the pointer
++ __ addq(rax, 8); //
++ __ subq(rbx, 1); // decerement the length
++ __ jcc(Assembler::notZero, resume_frames_loop);
++
++ // Move (shift) the locals of the bottom frame
++ // rsi points to one word past the bottom here
++ Label move_bottom_frame_locals_loop;
++ Label move_bottom_frame_locals_loop_cont;
++ __ movq(rax, Address(rdi, ResumeBlock::alignment_padding_offset_in_bytes()));
++ __ movq(rbx, Address(rdi, ResumeBlock::bottom_frame_max_locals_offset_in_bytes()));
++ // Check if the padding == 0 or max_locals == 0
++ __ testq(rax, rax);
++ __ jcc(Assembler::zero, move_bottom_frame_locals_loop_cont);
++ __ testq(rbx, rbx);
++ __ jcc(Assembler::zero, move_bottom_frame_locals_loop_cont);
++ __ mov(rdx, rsi);
++ __ shlq(rax, 3); // words -> bytes
++ __ addq(rdx, rax);
++ // rsi: copy dest, rdx: copy src, rbx: counter
++ // loop
++ __ bind(move_bottom_frame_locals_loop);
++ __ movq(rax, Address(rdx, 0));
++ __ movq(Address(rsi, 0), rax);
++ __ mov64(rax, 0xbaadbaadbaadbaad);
++ __ movq(Address(rdx, 0), rax); // for error detection
++ __ addq(rsi, 8);
++ __ addq(rdx, 8);
++ __ subq(rbx, 1);
++ __ jcc(Assembler::notZero, move_bottom_frame_locals_loop);
++ __ bind(move_bottom_frame_locals_loop_cont);
++
++ // Set sp, fp, rv
++ __ movq(rsi, Address(rdi, ResumeBlock::top_sp_offset_in_bytes()));
++ __ movq(rbx, Address(rdi, ResumeBlock::top_fp_offset_in_bytes()));
++ __ movq(rdx, Address(rdi, ResumeBlock::top_pc_offset_in_bytes()));
++ // rax = handle of the return value
++ __ movq(rax, Address(rdi, ResumeBlock::return_value_offset_in_bytes()));
++
++ // Restore the top frame sp and fp
++ __ mov(rsp, rsi);
++ __ mov(rbp, rbx);
++
++ // Set last Java frame
++ __ set_last_Java_frame(rsi, rbx, NULL);
++ // After jumping back to the native wrapper at the end of this
++ // rountine, we could hit a safepoint. But the only pc that has an oop
++ // map in the native wrapper is the rough pc set by the native
++ // wrapper. So, we must set the last Java pc to it.
++ __ movq(rsi, Address(rdi, ResumeBlock::rough_top_pc_offset_in_bytes()));
++ __ movq(Address(r15_thread, JavaThread::last_Java_pc_offset()), rsi);
++
++ // The native wrapper expects to see the thread ptr preserved in r15_thread.
++
++ // push resume pc (rdx) and rv (rax) on stack to preserve across the C call.
++ __ push(rdx);
++ __ push(rax);
++
++ __ mov(rdi, r15_thread);
++ // call a C function that deallocates deopt_mark
++ __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, Deoptimization::dealloc_deopt_mark)));
++
++ __ pop(rax); // the handle of the return value
++ __ pop(rdx); // resume pc
++
++ __ push(rdx); // push the resume pc as the return pc
++ __ push(rbp); // construct a dummy frame
++ __ mov(rbp, rsp);
++ __ push(rax); // save the handle of the return value
++
++ // call a C function that deallocates the
++ // ThreadInVMfromNativeForContinuation object. This could block for
++ // GC.
++ __ mov(rdi, r15_thread);
++ __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, ThreadInVMfromNativeForContinuation::dealloc)));
++
++ // This field must remain non-null so that GC won't check the
++ // outgoing arguments of the top frame which could be invalid
++ // oops. But now it should be nullified because GC won't happen in
++ // this blob at this point.
++ __ movptr(Address(r15_thread, JavaThread::cont_thread_transition_offset()), (intptr_t) NULL_WORD);
++
++ // Since we're returning to native wrapper/entry, the return value
++ // should be handlized here.
++ __ pop(rax); // restore the handle of the return value
++
++ __ leave(); // deconstruct the frame
++ __ ret(0); // return to the resume pc (the top frame of the resumed stack)
++
++ // -------------
++ // make sure all code is generated
++ masm->flush();
++
++ return RuntimeStub::new_runtime_stub(name, &buffer, CodeOffsets::frame_never_safe, 0, NULL, true);
++}
++
+ #ifdef COMPILER2
+ //------------------------------generate_uncommon_trap_blob--------------------
+ void SharedRuntime::generate_uncommon_trap_blob() {
+@@ -3194,6 +3439,9 @@
+ generate_handler_blob(CAST_FROM_FN_PTR(address,
+ SafepointSynchronize::handle_polling_page_exception), true);
+
++ _continuation_save_blob = generate_continuation_save_blob();
++ _continuation_resume_blob = generate_continuation_resume_blob();
++
+ generate_deopt_blob();
+
+ #ifdef COMPILER2
+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
+@@ -1909,6 +1909,7 @@
+ else if (instr->is_tls_instruction()) {
+ // Special hack for tlsLoadP
+ fprintf(fp," const Type *bottom_type() const { return TypeRawPtr::BOTTOM; } // tlsLoadP\n");
++ fprintf(fp," bool is_tlsLoadP() const { return true; } // tlsLoadP\n");
+ }
+ else if ( instr->is_ideal_if() ) {
+ fprintf(fp," const Type *bottom_type() const { return TypeTuple::IFBOTH; } // matched IfNode\n");
+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
+@@ -385,6 +385,7 @@
+ template(void_signature, "V") \
+ template(byte_array_signature, "[B") \
+ template(char_array_signature, "[C") \
++ template(long_array_signature, "[J") \
+ template(object_void_signature, "(Ljava/lang/Object;)V") \
+ template(object_int_signature, "(Ljava/lang/Object;)I") \
+ template(object_boolean_signature, "(Ljava/lang/Object;)Z") \
+@@ -842,6 +843,15 @@
+ /*== LAST_COMPILER_INLINE*/ \
+ /*the compiler does have special inlining code for these; bytecode inline is just fine */ \
+ \
++ \
++ /* continuation intrinsic (excluded from compilation) */ \
++ do_class(sun_misc_Continuation, "sun/misc/Continuation") \
++ do_intrinsic(_enter, sun_misc_Continuation, enter_name, enter_signature, F_S) \
++ do_name( enter_name, "enter") \
++ do_signature(enter_signature, "(Ljava/lang/Runnable;Ljava/lang/Object;)Ljava/lang/Object;") \
++ do_intrinsic(_enter0, sun_misc_Continuation, enter0_name, enter_signature, F_S) \
++ do_name( enter0_name, "enter0") \
++ \
+ 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/code/nmethod.cpp b/src/share/vm/code/nmethod.cpp
+--- a/src/share/vm/code/nmethod.cpp
++++ b/src/share/vm/code/nmethod.cpp
+@@ -608,6 +608,7 @@
+ _nul_chk_table_offset = _handler_table_offset;
+ _nmethod_end_offset = _nul_chk_table_offset;
+ _compile_id = 0; // default
++ _cont_ref_count = 0;
+ _comp_level = CompLevel_none;
+ _entry_point = instructions_begin();
+ _verified_entry_point = instructions_begin() + offsets->value(CodeOffsets::Verified_Entry);
+@@ -785,6 +786,7 @@
+ _oops_do_mark_link = NULL;
+ _method = method;
+ _compile_id = compile_id;
++ _cont_ref_count = 0;
+ _comp_level = comp_level;
+ _entry_bci = entry_bci;
+ _osr_link = NULL;
+@@ -1146,6 +1148,11 @@
+ bool nmethod::can_not_entrant_be_converted() {
+ assert(is_not_entrant(), "must be a non-entrant method");
+
++ // If some continuation includes a stack frame of this nmethod, say no.
++ if (cont_ref_count() > 0) {
++ return false;
++ }
++
+ // Since the nmethod sweeper only does partial sweep the sweeper's traversal
+ // count can be greater than the stack traversal count before it hits the
+ // nmethod for the second time.
+diff --git a/src/share/vm/code/nmethod.hpp b/src/share/vm/code/nmethod.hpp
+--- a/src/share/vm/code/nmethod.hpp
++++ b/src/share/vm/code/nmethod.hpp
+@@ -146,6 +146,9 @@
+
+ AbstractCompiler* _compiler; // The compiler which compiled this nmethod
+
++ // Continuation support
++ int _cont_ref_count; // how many live continuations include this nmethod
++
+ // Offsets for different nmethod parts
+ int _exception_offset;
+ // All deoptee's will resume execution at this location described by
+@@ -516,6 +519,8 @@
+ return (addr >= instructions_begin() && addr < verified_entry_point());
+ }
+
++ int orig_pc_offset() { return _orig_pc_offset; }
++
+ // unlink and deallocate this nmethod
+ // Only NMethodSweeper class is expected to use this. NMethodSweeper is not
+ // expected to use any other private methods/data in this class.
+@@ -643,6 +648,26 @@
+ int compile_id() const { return _compile_id; }
+ const char* compile_kind() const;
+
++ // Continuation support
++ int cont_ref_count() const {
++ assert(_cont_ref_count >= 0, "negative cont ref count");
++ return _cont_ref_count;
++ }
++ int inc_cont_ref_count() {
++ Atomic::inc(&_lock_count);
++ guarantee(!is_zombie(), "cannot lock a zombie method");
++
++ assert(_cont_ref_count >= 0, "negative cont ref count");
++ return ++_cont_ref_count;
++ }
++ int dec_cont_ref_count() {
++ Atomic::dec(&_lock_count);
++ guarantee(_lock_count >= 0, "unmatched nmethod lock/unlock");
++
++ assert(_cont_ref_count > 0, "negative cont ref count");
++ return --_cont_ref_count;
++ }
++
+ // For debugging
+ // CompiledIC* IC_at(char* p) const;
+ // PrimitiveIC* primitiveIC_at(char* p) const;
+diff --git a/src/share/vm/compiler/compilerOracle.cpp b/src/share/vm/compiler/compilerOracle.cpp
+--- a/src/share/vm/compiler/compilerOracle.cpp
++++ b/src/share/vm/compiler/compilerOracle.cpp
+@@ -277,6 +277,12 @@
+
+ bool CompilerOracle::should_exclude(methodHandle method, bool& quietly) {
+ quietly = true;
++
++ // Continuation: the enter method can never be compiled
++ if (method->intrinsic_id() == vmIntrinsics::_enter
++ || method->intrinsic_id() == vmIntrinsics::_enter0)
++ return true;
++
+ if (lists[ExcludeCommand] != NULL) {
+ if (lists[ExcludeCommand]->match(method)) {
+ quietly = _quiet;
+diff --git a/src/share/vm/compiler/oopMap.cpp b/src/share/vm/compiler/oopMap.cpp
+--- a/src/share/vm/compiler/oopMap.cpp
++++ b/src/share/vm/compiler/oopMap.cpp
+@@ -188,6 +188,13 @@
+ }
+ }
+
++
++void OopMap::set_thread_ptr(VMReg reg) {
++ set_xxx(reg, OopMapValue::thread_ptr_value, VMRegImpl::Bad());
++}
++
++
++
+ // OopMapSet
+
+ OopMapSet::OopMapSet() {
+@@ -543,6 +550,9 @@
+ st->print("Derived_oop_" );
+ optional->print_on(st);
+ break;
++ case OopMapValue::thread_ptr_value:
++ st->print("ThreadPtr");
++ break;
+ default:
+ ShouldNotReachHere();
+ }
+diff --git a/src/share/vm/compiler/oopMap.hpp b/src/share/vm/compiler/oopMap.hpp
+--- a/src/share/vm/compiler/oopMap.hpp
++++ b/src/share/vm/compiler/oopMap.hpp
+@@ -29,6 +29,7 @@
+ // Dead - Dead; can be Zapped for debugging
+ // CalleeXX - Callee saved; also describes which caller register is saved
+ // DerivedXX - A derived oop; original oop is described.
++// ThreadPtr - A current thread pointer
+ //
+ // OopMapValue describes a single OopMap entry
+
+@@ -46,7 +47,7 @@
+
+ public:
+ // Constants
+- enum { type_bits = 5,
++ enum { type_bits = 6,
+ register_bits = BitsPerShort - type_bits };
+
+ enum { type_shift = 0,
+@@ -63,7 +64,8 @@
+ value_value = 2,
+ narrowoop_value = 4,
+ callee_saved_value = 8,
+- derived_oop_value= 16 };
++ derived_oop_value= 16,
++ thread_ptr_value = 32};
+
+ // Constructors
+ OopMapValue () { set_value(0); set_content_reg(VMRegImpl::Bad()); }
+@@ -92,12 +94,14 @@
+ bool is_narrowoop() { return mask_bits(value(), type_mask_in_place) == narrowoop_value; }
+ bool is_callee_saved() { return mask_bits(value(), type_mask_in_place) == callee_saved_value; }
+ bool is_derived_oop() { return mask_bits(value(), type_mask_in_place) == derived_oop_value; }
++ bool is_thread_ptr() { return mask_bits(value(), type_mask_in_place) == thread_ptr_value; }
+
+ void set_oop() { set_value((value() & register_mask_in_place) | oop_value); }
+ void set_value() { set_value((value() & register_mask_in_place) | value_value); }
+ void set_narrowoop() { set_value((value() & register_mask_in_place) | narrowoop_value); }
+ void set_callee_saved() { set_value((value() & register_mask_in_place) | callee_saved_value); }
+ void set_derived_oop() { set_value((value() & register_mask_in_place) | derived_oop_value); }
++ void set_thread_ptr() { set_value((value() & register_mask_in_place) | thread_ptr_value); }
+
+ VMReg reg() const { return VMRegImpl::as_VMReg(mask_bits(value(), register_mask_in_place) >> register_shift); }
+ oop_types type() const { return (oop_types)mask_bits(value(), type_mask_in_place); }
+@@ -177,6 +181,7 @@
+ void set_dead ( VMReg local);
+ void set_callee_saved( VMReg local, VMReg caller_machine_register );
+ void set_derived_oop ( VMReg local, VMReg derived_from_local_register );
++ void set_thread_ptr ( VMReg local);
+ void set_xxx(VMReg reg, OopMapValue::oop_types x, VMReg optional);
+
+ int heap_size() const;
+diff --git a/src/share/vm/includeDB_core b/src/share/vm/includeDB_core
+--- a/src/share/vm/includeDB_core
++++ b/src/share/vm/includeDB_core
+@@ -4464,7 +4464,9 @@
+ universe.inline.hpp universe.hpp
+
+ unsafe.cpp allocation.inline.hpp
++unsafe.cpp biasedLocking.hpp
+ unsafe.cpp copy.hpp
++unsafe.cpp deoptimization.hpp
+ unsafe.cpp dtrace.hpp
+ unsafe.cpp globals.hpp
+ unsafe.cpp interfaceSupport.hpp
+@@ -4475,6 +4477,10 @@
+ unsafe.cpp synchronizer.hpp
+ unsafe.cpp threadService.hpp
+ unsafe.cpp vmSymbols.hpp
++unsafe.cpp oopMapCache.hpp
++unsafe.cpp oopFactory.hpp
++unsafe.cpp vframe.hpp
++unsafe.cpp vframeArray.hpp
+
+ utf8.cpp utf8.hpp
+
+@@ -4555,6 +4561,7 @@
+ vframe.hpp stackValueCollection.hpp
+
+ vframeArray.cpp allocation.inline.hpp
++vframeArray.cpp bytecode.hpp
+ vframeArray.cpp events.hpp
+ vframeArray.cpp handles.inline.hpp
+ vframeArray.cpp interpreter.hpp
+diff --git a/src/share/vm/oops/instanceKlass.cpp b/src/share/vm/oops/instanceKlass.cpp
+--- a/src/share/vm/oops/instanceKlass.cpp
++++ b/src/share/vm/oops/instanceKlass.cpp
+@@ -706,19 +706,20 @@
+ }
+
+
+-void instanceKlass::mask_for(methodHandle method, int bci,
+- InterpreterOopMap* entry_for) {
++void instanceKlass::mask_for(methodHandle method, int bci, InterpreterOopMap* entry_for,
++ OopMapCacheId oop_map_cache_id) {
++ OopMapCache* volatile* cache = &_oop_map_caches[oop_map_cache_id];
+ // Dirty read, then double-check under a lock.
+- if (_oop_map_cache == NULL) {
++ if (*cache == NULL) {
+ // Otherwise, allocate a new one.
+ MutexLocker x(OopMapCacheAlloc_lock);
+ // First time use. Allocate a cache in C heap
+- if (_oop_map_cache == NULL) {
+- _oop_map_cache = new OopMapCache();
++ if (*cache == NULL) {
++ *cache = new OopMapCache();
+ }
+ }
+ // _oop_map_cache is constant after init; lookup below does is own locking.
+- _oop_map_cache->lookup(method, bci, entry_for);
++ (*cache)->lookup(method, bci, entry_for);
+ }
+
+
+@@ -1911,10 +1912,13 @@
+ }
+
+ void instanceKlass::release_C_heap_structures() {
+- // Deallocate oop map cache
+- if (_oop_map_cache != NULL) {
+- delete _oop_map_cache;
+- _oop_map_cache = NULL;
++ // Deallocate oop map caches
++ for (int i = default_oop_map_cache_id; i < limit_oop_map_cache_id; i++) {
++ OopMapCache* volatile* cache = &_oop_map_caches[i];
++ if (*cache != NULL) {
++ delete *cache;
++ *cache = NULL;
++ }
+ }
+
+ // Deallocate JNI identifiers for jfieldIDs
+diff --git a/src/share/vm/oops/instanceKlass.hpp b/src/share/vm/oops/instanceKlass.hpp
+--- a/src/share/vm/oops/instanceKlass.hpp
++++ b/src/share/vm/oops/instanceKlass.hpp
+@@ -225,7 +225,7 @@
+ int _vtable_len; // length of Java vtable (in words)
+ int _itable_len; // length of Java itable (in words)
+ ReferenceType _reference_type; // reference type
+- OopMapCache* volatile _oop_map_cache; // OopMapCache for all methods in the klass (allocated lazily)
++ OopMapCache* volatile _oop_map_caches[limit_oop_map_cache_id]; // OopMapCache for all methods in the klass (allocated lazily).
+ JNIid* _jni_ids; // First JNI identifier for static fields in this class
+ jmethodID* _methods_jmethod_ids; // jmethodIDs corresponding to method_idnum, or NULL if none
+ int* _methods_cached_itable_indices; // itable_index cache for JNI invoke corresponding to methods idnum, or NULL
+@@ -569,9 +569,14 @@
+ void set_initialization_state_and_notify(ClassState state, TRAPS);
+
+ // OopMapCache support
+- OopMapCache* oop_map_cache() { return _oop_map_cache; }
+- void set_oop_map_cache(OopMapCache *cache) { _oop_map_cache = cache; }
+- void mask_for(methodHandle method, int bci, InterpreterOopMap* entry);
++ OopMapCache* oop_map_cache(OopMapCacheId oop_map_cache_id = default_oop_map_cache_id) {
++ return _oop_map_caches[oop_map_cache_id];
++ }
++ void set_oop_map_cache(OopMapCache *cache, OopMapCacheId oop_map_cache_id = default_oop_map_cache_id) {
++ _oop_map_caches[oop_map_cache_id] = cache;
++ }
++ void mask_for(methodHandle method, int bci, InterpreterOopMap* entry,
++ OopMapCacheId oop_map_cache_id = default_oop_map_cache_id);
+
+ // JNI identifier support (for static fields - for jni performance)
+ JNIid* jni_ids() { return _jni_ids; }
+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
+@@ -135,7 +135,8 @@
+ }
+
+
+-void methodOopDesc::mask_for(int bci, InterpreterOopMap* mask) {
++void methodOopDesc::mask_for(int bci, InterpreterOopMap* mask,
++ OopMapCacheId oop_map_cache_id) {
+
+ Thread* myThread = Thread::current();
+ methodHandle h_this(myThread, this);
+@@ -144,7 +145,7 @@
+ myThread->is_ConcurrentGC_thread() ||
+ myThread->is_GC_task_thread();
+
+- if (!has_capability) {
++ if (oop_map_cache_id == default_oop_map_cache_id && !has_capability) {
+ if (!VerifyStack && !VerifyLastFrame) {
+ // verify stack calls this outside VM thread
+ warning("oopmap should only be accessed by the "
+@@ -155,7 +156,7 @@
+ }
+ }
+ #endif
+- instanceKlass::cast(method_holder())->mask_for(h_this, bci, mask);
++ instanceKlass::cast(method_holder())->mask_for(h_this, bci, mask, oop_map_cache_id);
+ return;
+ }
+
+diff --git a/src/share/vm/oops/methodOop.hpp b/src/share/vm/oops/methodOop.hpp
+--- a/src/share/vm/oops/methodOop.hpp
++++ b/src/share/vm/oops/methodOop.hpp
+@@ -357,7 +357,8 @@
+ void set_signature_handler(address handler);
+
+ // Interpreter oopmap support
+- void mask_for(int bci, InterpreterOopMap* mask);
++ void mask_for(int bci, InterpreterOopMap* mask,
++ OopMapCacheId oop_map_cache_id = default_oop_map_cache_id);
+
+ #ifndef PRODUCT
+ // operations on invocation counter
+diff --git a/src/share/vm/opto/buildOopMap.cpp b/src/share/vm/opto/buildOopMap.cpp
+--- a/src/share/vm/opto/buildOopMap.cpp
++++ b/src/share/vm/opto/buildOopMap.cpp
+@@ -347,15 +347,100 @@
+ }
+
+ } else {
+- // Other - some reaching non-oop value
+- omap->set_value( r);
++ bool is_thread_ptr = false;
++ if (def->bottom_type() == TypeRawPtr::BOTTOM) {
++ // Peek through copies
++ if (DebugContinuation) {
++ tty->print_cr("build_oop_map: Traversing for tlsLoadP...");
++ }
+ #ifdef ASSERT
+- if( t->isa_rawptr() && C->cfg()->_raw_oops.member(def) ) {
+- def->dump();
+- n->dump();
+- assert(false, "there should be a oop in OopMap instead of a live raw oop at safepoint");
++ bool is_not_thread_ptr = false;
++#endif
++ Unique_Node_List worklist;
++ Unique_Node_List visited;
++ worklist.push(def);
++ while (worklist.size() > 0) {
++ Node* n = worklist.pop();
++ if (visited.member(n)) {
++ continue;
++ }
++ visited.push(n);
++
++ if (DebugContinuation) {
++ tty->print_cr("build_oop_map: Looking at %d", n->_idx);
++#ifdef ASSERT
++ n->dump();
++#endif // ASSERT
++ }
++
++ if (n->is_Mach() && n->as_Mach()->is_tlsLoadP()) {
++ is_thread_ptr = true;
++ if (DebugContinuation) {
++ tty->print_cr("build_oop_map: Found tlsLoadP ");
++ }
++#ifdef ASSERT
++ continue;
++#else
++ break;
++#endif
++ }
++
++ uint copy_in_idx = n->is_Copy();
++ if (copy_in_idx != 0) {
++ Node* copy_in = n->in(copy_in_idx);
++ worklist.push(copy_in);
++ continue;
++ }
++
++ if (n->is_Phi()) {
++ PhiNode* phi = n->as_Phi();
++ for (uint i = 1; i < phi->req(); ++i) {
++ worklist.push(phi->in(i));
++ }
++ continue;
++ }
++#ifdef ASSERT
++ is_not_thread_ptr = true;
++#else
++ break;
++#endif
++ }
++#ifdef ASSERT
++ // To conservatively check for an accidental mixup of a
++ // thread pointer and a non-thread-pointer in the compiler.
++ assert(is_thread_ptr ^ is_not_thread_ptr, "thread pointer and non-thread-pointer mixed up");
++#endif
++ if (is_thread_ptr) {
++ if (DebugContinuation) {
++ if (r->is_reg()) {
++ tty->print_cr("build_oop_map: Found a thread pointer in reg %s", r->name());
++ } else if (r->is_stack()) {
++ int stack_offset_in_bytes = r->reg2stack() * 4; // from the stack pointer
++ tty->print_cr("build_oop_map: Found a thread pointer in stack [%d]", stack_offset_in_bytes);
++ if (jvms->has_method()) {
++ tty->print_cr(" in ");
++ jvms->method()->name()->print_symbol();
++ tty->print_cr(" at bci: %d", jvms->bci());
++ }
++ } else {
++ tty->print_cr("build_oop_map: Found a thread pointer in bad VMReg");
++ }
++ }
++ assert(r->is_reg() || r->is_stack(), "thread pointer not in a reg or stack");
++ omap->set_thread_ptr(r);
++ }
+ }
++ if (!is_thread_ptr) {
++ // Other - some reaching non-oop value
++ omap->set_value( r);
++#ifdef ASSERT
++ if( t->isa_rawptr() && C->cfg()->_raw_oops.member(def) ) {
++ def->dump();
++ n->dump();
++ assert(false, "there should be a oop in OopMap instead of a live raw oop at safepoint");
++ }
+ #endif
++ }
+ }
+
+ }
+diff --git a/src/share/vm/opto/machnode.hpp b/src/share/vm/opto/machnode.hpp
+--- a/src/share/vm/opto/machnode.hpp
++++ b/src/share/vm/opto/machnode.hpp
+@@ -238,6 +238,12 @@
+ virtual const class Type *bottom_type() const { return _opnds[0]->type(); }
+ virtual uint ideal_reg() const { const Type *t = _opnds[0]->type(); return t == TypeInt::CC ? Op_RegFlags : Matcher::base2reg[t->base()]; }
+
++ // tlsLoadP is the mach node that represents the (current) thread
++ // pointer. Returns true iff this node is a tlsLoadP node. Used to
++ // compute the locations of the thread pointer in the compiled code
++ // as part of the oopmap.
++ virtual bool is_tlsLoadP() const { return false; }
++
+ // If this is a memory op, return the base pointer and fixed offset.
+ // If there are no such, return NULL. If there are multiple addresses
+ // or the address is indeterminate (rare cases) then return (Node*)-1,
+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
+@@ -78,6 +78,7 @@
+
+ extern "C" {
+ void JNICALL JVM_RegisterUnsafeMethods(JNIEnv *env, jclass unsafecls);
++ void JNICALL JVM_RegisterContinuationMethods(JNIEnv *env, jclass contcls);
+ void JNICALL JVM_RegisterMethodHandleMethods(JNIEnv *env, jclass unsafecls);
+ void JNICALL JVM_RegisterPerfMethods(JNIEnv *env, jclass perfclass);
+ }
+@@ -98,6 +99,9 @@
+ if (strstr(jni_name, "Java_sun_misc_Unsafe_registerNatives") != NULL) {
+ return CAST_FROM_FN_PTR(address, JVM_RegisterUnsafeMethods);
+ }
++ if (strstr(jni_name, "Java_sun_misc_Continuation_registerNatives") != NULL) {
++ return CAST_FROM_FN_PTR(address, JVM_RegisterContinuationMethods);
++ }
+ if (strstr(jni_name, "Java_sun_dyn_MethodHandleNatives_registerNatives") != NULL) {
+ return CAST_FROM_FN_PTR(address, JVM_RegisterMethodHandleMethods);
+ }
+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
+@@ -1169,6 +1169,1640 @@
+ Prefetch::write(addr, (intx)offset);
+ UNSAFE_END
+
++// Experimental Continuation Support -----------------------------------
++
++#define THROW_IE_(msg, rv) THROW_MSG_(vmSymbols::java_lang_InternalError(), msg, rv)
++#define THROW_IE(msg) THROW_MSG( vmSymbols::java_lang_InternalError(), msg)
++
++// Writes a single stack frame
++class StackFrameWriter : public ResourceObj {
++ private:
++ Thread* _thread;
++ frame _fr;
++ GrowableArray<intptr_t>* _relocates; // In-stack offsets of pointers within the stack
++ // Some slots hold a value at a certain offset of an oop (eg
++ // bytecode index off of a const method oop). We call those slots
++ // 'relatives'.
++ GrowableArray<intptr_t>* _relatives; // In-stack offsets of relatives
++ GrowableArray<intptr_t>* _relatives_diff; // Offsets of relatives off the base oop
++ GrowableArray<intptr_t>* _relatives_base_oop; // Base oops of relatives
++ GrowableArray<intptr_t>* _oop_offsets; // In-stack offsets of oops
++ GrowableArray<oop*>* _oop_ptrs; // Pointers to oops, shared with StackWriter
++ GrowableArray<Handle>* _oop_handles; // Handles to oops, shared with StackWriter
++ GrowableArray<intptr_t>* _thread_ptrs; // In-stack offsets of thread pointers
++ intptr_t* _frame_image; // The image of the stack frame
++ CompressedWriteStream* _stream; // Stream used to marshal the stack frame
++ intptr_t _alignment_padding; // The stack alignment (0, 4, 8, or 12) for this frame
++
++ void inc_nmethod_cont_ref_count() {
++ CodeBlob* cb = CodeCache::find_blob(_fr.pc());
++ assert(cb != NULL, "Unrecognizable pc");
++ if (cb->is_nmethod()) {
++ nmethod* nm = (nmethod*) cb;
++ nm->inc_cont_ref_count();
++ }
++ }
++
++ public:
++ StackFrameWriter(Thread* thread, frame fr, CompressedWriteStream* stream,
++ GrowableArray<oop*>* oop_ptrs,
++ GrowableArray<Handle>* oop_handles) :
++ _thread(thread),
++ _fr(fr),
++ _stream(stream),
++ _relocates(new GrowableArray<intptr_t>()),
++ _relatives(new GrowableArray<intptr_t>()),
++ _relatives_base_oop(new GrowableArray<intptr_t>()),
++ _relatives_diff(new GrowableArray<intptr_t>()),
++ _oop_offsets(new GrowableArray<intptr_t>()),
++ _oop_ptrs(oop_ptrs),
++ _oop_handles(oop_handles),
++ _thread_ptrs(new GrowableArray<intptr_t>()),
++ _alignment_padding(0) {
++ if (fr.is_compiled_frame() || fr.is_native_frame()) {
++ inc_nmethod_cont_ref_count();
++ }
++ }
++
++ frame original_frame() { return _fr; }
++
++ bool is_in_stack(address a) {
++ return _thread->stack_base() - _thread->stack_size() <= a
++ && a < _thread->stack_base();
++ }
++
++ void add_relocate(intptr_t reloc) {
++ address loc = (address) reloc;
++ address ptr = (address) * (intptr_t*) reloc;
++ if (is_in_stack(loc) && is_in_stack(ptr)) {
++ _relocates->append(reloc);
++ }
++ }
++
++ void add_thread_pointer(intptr_t* thread_ptr_addr) {
++ _thread_ptrs->append((intptr_t) thread_ptr_addr);
++ }
++
++ // If the stack being saved is one that's been resumed before,
++ // the stack alignment padding may be inserted below the bottom frame
++ // Adjust the sender_sp and the old_fp (link) offsets of the bottom frame
++ // so that the saved stack image does not account for any padding
++ void count_past_alignment_padding() {
++ intptr_t* fp = _fr.fp();
++ intptr_t* prev_fp = _fr.link();
++ intptr_t* ptr = fp;
++ // traverse fp to prev_fp and count the number of 0xbaadbaad words
++ intptr_t padding = 0;
++ // TODO: actually up to 3 iterations are enough
++ while (ptr != prev_fp) {
++#ifndef _LP64
++ if (*ptr == (intptr_t) 0xbaadbaad) { // the magic word must match with the resume blob in sharedRuntime_x86_32
++#else
++ if (*ptr == (intptr_t) 0xbaadbaadbaadbaad) { // the magic word must match with the resume blob in sharedRuntime_x86_32
++#endif // _LP64
++ padding++;
++ }
++ ptr++;
++ }
++ if (padding > 0) {
++ _alignment_padding = padding;
++ if (DebugContinuation) {
++ tty->print_cr("count_past_alignment_padding: " INTPTR_FORMAT, padding);
++ }
++ }
++ }
++
++ void add_bcx_mdx(intptr_t* bcx, intptr_t* mdx, oop const_method, oop mdo) {
++ bool is_bci = frame::is_bci(*bcx);
++ if (!is_bci) {
++ intptr_t bcp = *bcx;
++ intptr_t diff = bcp - (intptr_t) const_method;
++ intptr_t cmo_index = _oop_handles->append(Handle(const_method));
++ _relatives->append((intptr_t) bcx);
++ _relatives_base_oop->append(cmo_index);
++ _relatives_diff->append(diff);
++ if (*mdx != 0 && mdo != NULL) {
++ // mdx is an mdp when is_bci = false and is an pointer into the middle of a methodDataOop
++ intptr_t mdp = *mdx;
++ intptr_t diff = mdp - (intptr_t) mdo;
++ assert(mdo->is_oop(), "mdo isn't an oop?");
++ intptr_t mdo_index = _oop_handles->append(Handle(mdo));
++ _relatives->append((intptr_t) mdx);
++ _relatives_base_oop->append(mdo_index);
++ _relatives_diff->append(diff);
++ if (DebugContinuation) {
++ tty->print_cr("found mdp=" INTPTR_FORMAT ", mdo=" INTPTR_FORMAT,
++ (intptr_t)mdp, (intptr_t)mdo);
++ }
++ }
++ }
++ }
++
++ void finish() {
++ // Copy the frame memory
++ RegisterMap rmap(JavaThread::current(), false);
++ intptr_t size = _fr.frame_size(&rmap);
++ intptr_t* base = _fr.sp();
++
++ _frame_image = NEW_RESOURCE_ARRAY(intptr_t, size);
++ memcpy(_frame_image, base, size * sizeof(intptr_t));
++
++ // Update the prev fp of the bottom frame (the link in the enter0
++ // frame or the fp of the enter frame) in the copied image (not in
++ // the actual stack)
++ if (_alignment_padding != 0) {
++ intptr_t prev_fp_off = ((intptr_t) _fr.fp() - (intptr_t) _fr.sp()) / sizeof(intptr_t);
++ intptr_t sender_sp_off = (((intptr_t) _fr.fp() + frame::interpreter_frame_sender_sp_offset) - (intptr_t) _fr.sp()) / sizeof(intptr_t);
++ intptr_t* prev_fp = (intptr_t*) _frame_image[prev_fp_off];
++ intptr_t* sender_sp = (intptr_t*) _frame_image[sender_sp_off];
++ intptr_t* paddingless_prev_fp = prev_fp - _alignment_padding;
++ intptr_t* paddingless_sender_sp = sender_sp - _alignment_padding;
++ _frame_image[prev_fp_off] = (intptr_t) paddingless_prev_fp;
++ _frame_image[sender_sp_off] = (intptr_t) paddingless_sender_sp;
++ if (DebugContinuation) {
++ tty->print_cr("adjusting _alignment_padding: prev_fp " INTPTR_FORMAT " -> " INTPTR_FORMAT,
++ (intptr_t) prev_fp, (intptr_t) paddingless_prev_fp);
++ tty->print_cr("adjusting _alignment_padding: sender_sp " INTPTR_FORMAT " -> " INTPTR_FORMAT,
++ (intptr_t) sender_sp, (intptr_t) paddingless_sender_sp);
++ }
++ }
++
++ // Replace within-stack pointers with relative offsets and updates
++ // the relocate array with relative offsets
++ for (int i = 0; i < _relocates->length(); ++i) {
++ intptr_t off = _relocates->at(i) - (intptr_t) base;
++ intptr_t* ptr_loc = (intptr_t*)((intptr_t) _frame_image + off);
++ intptr_t* ptr = (intptr_t*)*ptr_loc;
++ *ptr_loc = ((intptr_t) ptr - (intptr_t) base) / sizeof(intptr_t);
++ _relocates->at_put(i, off/sizeof(intptr_t));
++ }
++
++ // Relatives
++ for (int i = 0; i < _relatives->length(); ++i) {
++ intptr_t off = _relatives->at(i) - (intptr_t) base;
++ _relatives->at_put(i, off / sizeof(intptr_t));
++ }
++
++ // Thread pointers
++ for (int i = 0; i < _thread_ptrs->length(); ++i) {
++ intptr_t off = _thread_ptrs->at(i) - (intptr_t) base;
++ _thread_ptrs->at_put(i, off / sizeof(intptr_t));
++ }
++
++ // Populate the oop offsets array & the oop handles array
++ // Replace oops in the frame memory with indices into the oop handles array
++ for (int k = 0; k < _oop_ptrs->length(); ++k) {
++ oop* p = _oop_ptrs->at(k);
++ intptr_t off = ((intptr_t) p - (intptr_t) base) / sizeof(intptr_t); // offsets are in words
++ // Only if the oop is within this frame
++ if (0 <= off && off < (intptr_t) size) {
++ _oop_offsets->append(off);
++ int index = _oop_handles->find(Handle(*p));
++ assert(index >= 0, "should be found");
++ _frame_image[off] = (intptr_t) index;
++ }
++ }
++ }
++
++ void print() {
++ RegisterMap rmap(JavaThread::current(), false);
++ int frame_size = _fr.frame_size(&rmap);
++ tty->print_cr("StackFrameWriter:");
++ tty->print_cr(" type=%s",
++ _fr.is_compiled_frame() ? "Compiled" : (_fr.is_native_frame() ? "Native" : "Interpreted"));
++ tty->print_cr(" sp=" INTPTR_FORMAT, 0);
++ tty->print_cr(" unextended_sp=" INTPTR_FORMAT, (intptr_t)_fr.unextended_sp() - (intptr_t) _fr.sp());
++ tty->print_cr(" fp=" INTPTR_FORMAT, (intptr_t) _fr.fp() - (intptr_t) _fr.sp());
++ tty->print_cr(" size_of_parameters=" INTPTR_FORMAT,
++ _fr.is_interpreted_frame() ? (intptr_t) _fr.interpreter_frame_method()->size_of_parameters() : 0);
++ tty->print_cr(" frame_size=" INTPTR_FORMAT, frame_size);
++ tty->print_cr(" pc=" INTPTR_FORMAT, _fr.pc());
++ tty->print_cr(" relocates:");
++ for (int i = 0; i < _relocates->length(); ++i) {
++ tty->print_cr(" [%x]=" INTPTR_FORMAT, i, _relocates->at(i));
++ }
++ tty->print_cr(" relatives:");
++ for (int i = 0; i < _relatives->length(); ++i) {
++ tty->print_cr(" [%x]=" INTPTR_FORMAT, i, _relatives->at(i));
++ }
++ tty->print_cr(" relatives_base_oop:");
++ for (int i = 0; i < _relatives_base_oop->length(); ++i) {
++ tty->print_cr(" [%x]=" INTPTR_FORMAT, i, _relatives_base_oop->at(i));
++ }
++ tty->print_cr(" relatives_diff:");
++ for (int i = 0; i < _relatives_diff->length(); ++i) {
++ tty->print_cr(" [%x]=" INTPTR_FORMAT, i, _relatives_diff->at(i));
++ }
++ tty->print_cr(" oop offsets:");
++ for (int i = 0; i < _oop_offsets->length(); ++i) {
++ tty->print_cr(" [%x]=" INTPTR_FORMAT, i, _oop_offsets->at(i));
++ }
++ tty->print_cr(" thread ptrs:");
++ for (int i = 0; i < _thread_ptrs->length(); ++i) {
++ tty->print_cr(" [%x]=" INTPTR_FORMAT, i, _thread_ptrs->at(i));
++ }
++ tty->print_cr(" image:");
++ for (int i = 0; i < frame_size; ++i) {
++ if (_relocates->contains(i)) {
++ tty->print_cr("R %x: " INTPTR_FORMAT, i, _frame_image[i]);
++ } else if (_oop_offsets->contains(i)) {
++ tty->print_cr("O %x: " INTPTR_FORMAT, i, _frame_image[i]);
++ } else {
++ tty->print_cr(" %x: " INTPTR_FORMAT, i, _frame_image[i]);
++ }
++ }
++ }
++
++ void write() {
++ CompressedWriteStream* s = _stream;
++ // Encode the frame into a byte stream
++ // frame {
++ // frame_type
++ // sp
++ // unextended_sp
++ // fp
++ // size_of_parameters (meaningful for interpreter_frame only)
++ // frame_size
++ // pc
++ // nreloc
++ // reloc[nreloc]
++ // noops
++ // oops[noops]
++ // nimage
++ // image[nimage]
++ // }
++ // Every field is a intptr_t type
++ RegisterMap rmap(JavaThread::current(), false);
++ int frame_size = _fr.frame_size(&rmap);
++#ifndef _LP64
++ s->write_int(_fr.is_compiled_frame() ? 1 : (_fr.is_native_frame() ? 2 : (_fr.is_interpreted_frame() ? 0 : -1)));
++ // Relative to sp
++ s->write_int((jint) 0);
++ s->write_int((jint) ((intptr_t) _fr.unextended_sp() - (intptr_t) _fr.sp()));
++ s->write_int((jint) ((intptr_t) _fr.fp() - (intptr_t) _fr.sp()));
++ s->write_int(_fr.is_interpreted_frame() ? (jint) _fr.interpreter_frame_method()->size_of_parameters() : 0);
++ s->write_int((jint) frame_size);
++ s->write_int((jint) _fr.pc());
++ s->write_int(_relocates->length());
++ for (int i = 0; i < _relocates->length(); ++i) {
++ s->write_int(_relocates->at(i));
++ }
++ s->write_int(_relatives->length());
++ for (int i = 0; i < _relatives->length(); ++i) {
++ s->write_int(_relatives->at(i));
++ }
++ s->write_int(_relatives_base_oop->length());
++ for (int i = 0; i < _relatives_base_oop->length(); ++i) {
++ s->write_int(_relatives_base_oop->at(i));
++ }
++ s->write_int(_relatives_diff->length());
++ for (int i = 0; i < _relatives_diff->length(); ++i) {
++ s->write_int(_relatives_diff->at(i));
++ }
++ s->write_int(_oop_offsets->length());
++ for (int i = 0; i < _oop_offsets->length(); ++i) {
++ s->write_int(_oop_offsets->at(i));
++ }
++ s->write_int(_thread_ptrs->length());
++ for (int i = 0; i < _thread_ptrs->length(); ++i) {
++ s->write_int(_thread_ptrs->at(i));
++ }
++ s->write_int(frame_size);
++ for (int i = 0; i < frame_size; ++i) {
++ s->write_int(_frame_image[i]);
++ }
++#else
++ s->write_long(_fr.is_compiled_frame() ? 1 : (_fr.is_native_frame() ? 2 : (_fr.is_interpreted_frame() ? 0 : -1)));
++ // Relative to sp
++ s->write_long((jlong) 0);
++ s->write_long((jlong) ((intptr_t) _fr.unextended_sp() - (intptr_t) _fr.sp()));
++ s->write_long((jlong) ((intptr_t) _fr.fp() - (intptr_t) _fr.sp()));
++ s->write_long(_fr.is_interpreted_frame() ? (jlong) _fr.interpreter_frame_method()->size_of_parameters() : 0);
++ s->write_long((jlong) frame_size);
++ s->write_long((jlong) _fr.pc());
++ s->write_long(_relocates->length());
++ for (int i = 0; i < _relocates->length(); ++i) {
++ s->write_long(_relocates->at(i));
++ }
++ s->write_long(_relatives->length());
++ for (int i = 0; i < _relatives->length(); ++i) {
++ s->write_long(_relatives->at(i));
++ }
++ s->write_long(_relatives_base_oop->length());
++ for (int i = 0; i < _relatives_base_oop->length(); ++i) {
++ s->write_long(_relatives_base_oop->at(i));
++ }
++ s->write_long(_relatives_diff->length());
++ for (int i = 0; i < _relatives_diff->length(); ++i) {
++ s->write_long(_relatives_diff->at(i));
++ }
++ s->write_long(_oop_offsets->length());
++ for (int i = 0; i < _oop_offsets->length(); ++i) {
++ s->write_long(_oop_offsets->at(i));
++ }
++ s->write_long(_thread_ptrs->length());
++ for (int i = 0; i < _thread_ptrs->length(); ++i) {
++ s->write_long(_thread_ptrs->at(i));
++ }
++ s->write_long(frame_size);
++ for (int i = 0; i < frame_size; ++i) {
++ s->write_long(_frame_image[i]);
++ }
++#endif
++ }
++};
++
++// Writes stack frames into the Continuation.stack object
++class StackWriter : public StackObj {
++ private:
++ GrowableArray<StackFrameWriter*>* _frameWriters; // List of StackFrameWriters
++ StackFrameWriter* _currentFrameWriter; // The current frame writer
++ Thread* _thread; // The thread
++ GrowableArray<oop*>* _oop_ptrs; // Pointers to oops
++ GrowableArray<Handle>* _oop_handles; // Handles to oops
++ CompressedWriteStream _stream; // Stream used to marshal the stack
++
++ address _rough_last_frame_pc; // GC-map-bearing pc set by native wrapper
++ address _stack_bottom; // End of the stack to be marshaled
++
++ // OopClosure is a StackObj
++ class OopCatcher : public OopClosure {
++ private:
++ GrowableArray<oop*>* _oop_ptrs;
++ public:
++ void set_oop_ptrs_array(GrowableArray<oop*>* oop_ptrs) {
++ _oop_ptrs = oop_ptrs;
++ }
++ void do_oop(oop* p) {
++ if (_oop_ptrs != NULL) {
++ if (DebugContinuation) {
++ tty->print_cr("OopCatcher::do_oop: " INTPTR_FORMAT ", " INTPTR_FORMAT,
++ (intptr_t)p, (intptr_t)*p);
++ }
++ _oop_ptrs->append(p);
++ }
++ }
++ void do_oop(narrowOop* p) { ShouldNotReachHere(); }
++ };
++
++ OopCatcher _oop_catcher;
++
++ // Create the object set to Continuation.stack. It's an Object[2].
++ // The first element is the array of oops referenced by the stack.
++ // The second element is the byte array that contains the marshaled stack image.
++ objArrayHandle create_blob() {
++ objArrayHandle oopArray = write_oop_array();
++ Handle byteArray = write_byte_array();
++
++ Thread* THREAD = _thread;
++ objArrayHandle topArray;
++ {
++ objArrayOop tem = oopFactory::new_objArray(SystemDictionary::Object_klass(),
++ 2, CHECK_NULL);
++ topArray = objArrayHandle(_thread, tem);
++ }
++ topArray->obj_at_put(0, oopArray());
++ topArray->obj_at_put(1, byteArray());
++ return topArray;
++ }
++
++ objArrayHandle write_oop_array() {
++ Thread* THREAD = _thread;
++ // Create the object array that contains the oops
++ objArrayHandle oopArray;
++ {
++ objArrayOop tem = oopFactory::new_objArray(SystemDictionary::Object_klass(),
++ _oop_handles->length(), CHECK_NULL);
++ oopArray = objArrayHandle(_thread, tem);
++ }
++ for (int i = 0; i < _oop_handles->length(); i++) {
++ oop o = _oop_handles->at(i)();
++ oopArray->obj_at_put(i, o);
++ }
++ return oopArray;
++ }
++
++ Handle write_byte_array() {
++ Thread* THREAD = _thread;
++ int size = _stream.position();
++ // Create a byte[] array to hold the compressed stream.
++ typeArrayOop ba = oopFactory::new_byteArray(size, CHECK_NH);
++ Copy::conjoint_bytes(_stream.buffer(), ba->byte_at_addr(0), size);
++ return Handle(_thread, ba);
++ }
++
++ public:
++ StackWriter(Thread* thread) :
++ _thread(thread),
++ _frameWriters(new GrowableArray<StackFrameWriter*>()),
++ _oop_ptrs(new GrowableArray<oop*>()),
++ _oop_handles(new GrowableArray<Handle>()),
++ _currentFrameWriter(NULL),
++ _stream(CompressedWriteStream(4096)) {
++ _oop_catcher.set_oop_ptrs_array(_oop_ptrs);
++ }
++
++ OopClosure* get_oop_catcher() {
++ return &_oop_catcher;
++ }
++
++ GrowableArray<oop*>* oop_ptrs() { return _oop_ptrs; }
++
++ void set_rough_last_frame_pc(address pc) { _rough_last_frame_pc = pc; }
++
++ // The end of the stack frames to be captured.
++ void set_stack_bottom(address stack_bottom) { _stack_bottom = stack_bottom; }
++
++ StackFrameWriter* writer() { return _currentFrameWriter; }
++
++ StackFrameWriter* add(frame fr) {
++ StackFrameWriter* writer = new StackFrameWriter(_thread, fr, &_stream, _oop_ptrs, _oop_handles);
++ _currentFrameWriter = writer;
++ _frameWriters->append(writer);
++ return _currentFrameWriter;
++ }
++
++ int nframes() { return _frameWriters->length(); }
++ StackFrameWriter* frame_at(int i) { return _frameWriters->at(i); }
++
++ // Creates the object set to Continuation.pcs
++ Handle getCodeCachePCs() {
++ GrowableArray<address>* pcs = new GrowableArray<address>();
++ for (int i = 0; i < _frameWriters->length(); ++i) {
++ StackFrameWriter* fw = _frameWriters->at(i);
++ frame fr = fw->original_frame();
++ if (fr.is_compiled_frame() || fr.is_native_frame()) {
++ pcs->append(fr.pc());
++ }
++ }
++ int size = pcs->length();
++ Thread* THREAD = _thread;
++ // Create a long[] array to hold the pc list.
++ typeArrayOop la = oopFactory::new_longArray(size, CHECK_NH);
++ for (int i = 0; i < size; ++i) {
++ la->long_at_put(0, (jlong) pcs->at(i));
++ }
++ return Handle(_thread, la);
++ }
++
++ objArrayHandle write() {
++ // Populate the oop handles array
++ for (int k = 0; k < _oop_ptrs->length(); ++k) {
++ oop* p = _oop_ptrs->at(k);
++ if (DebugContinuation) {
++ tty->print_cr("StackFrameWriter::write: " INTPTR_FORMAT ", " INTPTR_FORMAT,
++ (intptr_t) p, (intptr_t) *p);
++ }
++ _oop_handles->append_if_missing(Handle(*p));
++ }
++#ifndef _LP64
++ _stream.write_int((int)_rough_last_frame_pc);
++ _stream.write_int((int)_stack_bottom);
++ _stream.write_int((int)_thread);
++ // Write the number of frames
++ _stream.write_int((int)_frameWriters->length());
++#else
++ _stream.write_long((jlong)_rough_last_frame_pc);
++ _stream.write_long((jlong)_stack_bottom);
++ _stream.write_long((jlong)_thread);
++ // Write the number of frames
++ _stream.write_long((jlong)_frameWriters->length());
++#endif // _LP64
++ // Write each frame
++ for (int i = 0; i < _frameWriters->length(); ++i) {
++ StackFrameWriter* fw = _frameWriters->at(i);
++ if (i == _frameWriters->length() - 1) {
++ // for bottom frame
++ fw->count_past_alignment_padding();
++ }
++ fw->finish();
++ fw->write();
++ }
++ objArrayHandle blob = create_blob();
++ return blob;
++ }
++
++ void print() {
++ tty->print_cr("StackWriter:");
++ tty->print_cr(" rough_last_frame_pc=" INTPTR_FORMAT, (intptr_t)_rough_last_frame_pc);
++ tty->print_cr(" oops:");
++ for (int i = 0; i < _oop_handles->length(); ++i) {
++ Handle h = _oop_handles->at(i);
++ tty->print_cr(" [%x]=" INTPTR_FORMAT, i, (intptr_t) h());
++ }
++ for (int i = 0; i < _frameWriters->length(); ++i) {
++ StackFrameWriter* fw = _frameWriters->at(i);
++ fw->print();
++ }
++ }
++};
++
++// Reads a single stack frame from the Continuation.stack object
++class StackFrameReader : public ResourceObj {
++ private:
++ Thread* _thread; // Thread to resume the stack onto
++ CompressedReadStream* _stream; // Stream used to read marshaled stack image
++ intptr_t _stream_limit; // The limit of the stream
++ GrowableArray<Handle>* _oop_arr; // Handles to oops
++ GrowableArray<intptr_t>* _relocates; // Relocates. See StackFrameWriter.
++ GrowableArray<intptr_t>* _relatives; // Relatives.
++ GrowableArray<intptr_t>* _relatives_base_oop; // Base oops of relatives.
++ GrowableArray<intptr_t>* _relatives_diff; // Offsets of relatives.
++ GrowableArray<intptr_t>* _oop_offsets; // In-stack offsets of oops
++ GrowableArray<intptr_t>* _thread_ptrs; // In-stack offsets of thread pointers
++ intptr_t* _image_size; // The size of the frame image
++ intptr_t* _frame_image; // The frame image
++ address _original_thread; // The original thread that the stack was saved from
++
++ intptr_t* _sp;
++ intptr_t* _unextended_sp;
++ intptr_t* _fp;
++ address _pc;
++ intptr_t _size_of_parameters;
++ intptr_t _frame_size;
++ enum FrameType { interpreter = 0,
++ compiled = 1,
++ native = 2, }; // native wrappers
++ FrameType _frame_type;
++
++ public:
++ StackFrameReader(Thread* thread, CompressedReadStream* stream,
++ intptr_t stream_limit, GrowableArray<Handle>* oop_arr,
++ intptr_t* image_size, address original_thread) :
++ _thread(thread), _stream(stream),
++ _stream_limit(stream_limit), _oop_arr(oop_arr),
++ _relocates(new GrowableArray<intptr_t>()),
++ _relatives(new GrowableArray<intptr_t>()),
++ _relatives_base_oop(new GrowableArray<intptr_t>()),
++ _relatives_diff(new GrowableArray<intptr_t>()),
++ _oop_offsets(new GrowableArray<intptr_t>()),
++ _thread_ptrs(new GrowableArray<intptr_t>()),
++ _image_size(image_size),
++ _original_thread(original_thread) {
++ }
++
++ intptr_t* frame_image() { return _frame_image; }
++ intptr_t frame_size() { return _frame_size; }
++ intptr_t* sp() { return _sp; }
++ intptr_t* unextended_sp() { return _unextended_sp; }
++ intptr_t* fp() { return _fp; }
++ address pc() { return _pc; }
++ void set_pc(address pc) { _pc = pc; }
++ intptr_t size_of_parameters() { return _size_of_parameters; }
++ bool may_deopt() { return _frame_type == compiled || _frame_type == native; }
++
++ void read() {
++ CompressedReadStream* s = _stream;
++ // See the layout in StackFrameWriter
++#ifndef _LP64
++ // 32 bit version
++ _frame_type = (FrameType) s->read_int();
++ _sp = (intptr_t*) s->read_int();
++ _unextended_sp = (intptr_t*) s->read_int();
++ _fp = (intptr_t*) s->read_int(); // if this is a compiled frame, _fp could be an oop in which case, it may not be GC-unsafe oop
++ _size_of_parameters = s->read_int();
++ _frame_size = s->read_int();
++ *_image_size = *_image_size + _frame_size;
++ _pc = (address) s->read_int();
++
++ int nrelocates = s->read_int();
++ for (int i = 0; i < nrelocates; ++i) {
++ _relocates->append((intptr_t) s->read_int());
++ }
++ int nrelatives = s->read_int();
++ for (int i = 0; i < nrelatives; ++i) {
++ _relatives->append((intptr_t) s->read_int());
++ }
++ int nrelatives_base_oop = s->read_int();
++ for (int i = 0; i < nrelatives_base_oop; ++i) {
++ _relatives_base_oop->append((intptr_t) s->read_int());
++ }
++ int nrelatives_diff = s->read_int();
++ for (int i = 0; i < nrelatives_diff; ++i) {
++ _relatives_diff->append((intptr_t) s->read_int());
++ }
++ int noop_offsets = s->read_int();
++ for (int i = 0; i < noop_offsets; ++i) {
++ _oop_offsets->append((intptr_t) s->read_int());
++ }
++ int nthread_ptrs = s->read_int();
++ for (int i = 0; i < nthread_ptrs; ++i) {
++ _thread_ptrs->append((intptr_t) s->read_int());
++ }
++ int frame_size = s->read_int();
++ assert(frame_size == _frame_size, "inconsistent frame size");
++ _frame_image = NEW_RESOURCE_ARRAY(intptr_t, frame_size);
++ for (int i = 0; i < frame_size; ++i) {
++ _frame_image[i] = s->read_int();
++ }
++#else
++ // 64 bit version.
++ _frame_type = (FrameType) s->read_long();
++ _sp = (intptr_t*) s->read_long();
++ _unextended_sp = (intptr_t*) s->read_long();
++ _fp = (intptr_t*) s->read_long(); // if this is a compiled frame, _fp could be an oop in which case, it may not be GC-unsafe oop
++ _size_of_parameters = s->read_long();
++ _frame_size = s->read_long();
++ *_image_size = *_image_size + _frame_size;
++ _pc = (address) s->read_long();
++
++ intptr_t nrelocates = s->read_long();
++ for (int i = 0; i < nrelocates; ++i) {
++ _relocates->append((intptr_t) s->read_long());
++ }
++ intptr_t nrelatives = s->read_long();
++ for (int i = 0; i < nrelatives; ++i) {
++ _relatives->append((intptr_t) s->read_long());
++ }
++ intptr_t nrelatives_base_oop = s->read_long();
++ for (int i = 0; i < nrelatives_base_oop; ++i) {
++ _relatives_base_oop->append((intptr_t) s->read_long());
++ }
++ intptr_t nrelatives_diff = s->read_long();
++ for (int i = 0; i < nrelatives_diff; ++i) {
++ _relatives_diff->append((intptr_t) s->read_long());
++ }
++ intptr_t noop_offsets = s->read_long();
++ for (int i = 0; i < noop_offsets; ++i) {
++ _oop_offsets->append((intptr_t) s->read_long());
++ }
++ intptr_t nthread_ptrs = s->read_long();
++ for (int i = 0; i < nthread_ptrs; ++i) {
++ _thread_ptrs->append((intptr_t) s->read_long());
++ }
++ intptr_t frame_size = s->read_long();
++ assert(frame_size == _frame_size, "inconsistent frame size");
++ _frame_image = NEW_RESOURCE_ARRAY(intptr_t, frame_size);
++ for (int i = 0; i < frame_size; ++i) {
++ _frame_image[i] = (intptr_t) s->read_long();
++ }
++#endif // _LP64
++ }
++
++ void print() {
++#ifndef _LP64
++ // 32 bit version
++ tty->print_cr("StackFrameReader:");
++ tty->print( " type=");
++ switch (_frame_type) {
++ case interpreter:
++ tty->print_cr("Interpreted");
++ break;
++ case compiled:
++ tty->print_cr("Compiled");
++ break;
++ case native:
++ tty->print_cr("Native");
++ break;
++ default:
++ ShouldNotReachHere();
++ }
++ tty->print_cr(" sp=%x", _sp);
++ tty->print_cr(" unextended_sp=%x", _unextended_sp);
++ tty->print_cr(" fp=%x", _fp);
++ tty->print_cr(" size_of_parameters=%x", _size_of_parameters);
++ tty->print_cr(" frame_size=%x", _frame_size);
++ tty->print_cr(" pc=%x", _pc);
++ tty->print_cr(" relocates:");
++ for (int i = 0; i < _relocates->length(); ++i) {
++ tty->print_cr(" [%x]=%x", i, _relocates->at(i));
++ }
++ tty->print_cr(" relatives:");
++ for (int i = 0; i < _relatives->length(); ++i) {
++ tty->print_cr(" [%x]=%x", i, _relatives->at(i));
++ }
++ tty->print_cr(" relatives_base_oop:");
++ for (int i = 0; i < _relatives_base_oop->length(); ++i) {
++ tty->print_cr(" [%x]=%x", i, _relatives_base_oop->at(i));
++ }
++ tty->print_cr(" relatives_diff:");
++ for (int i = 0; i < _relatives_diff->length(); ++i) {
++ tty->print_cr(" [%x]=%x", i, _relatives_diff->at(i));
++ }
++ tty->print_cr(" oop offsets:");
++ for (int i = 0; i < _oop_offsets->length(); ++i) {
++ tty->print_cr(" [%x]=%x", i, _oop_offsets->at(i));
++ }
++ tty->print_cr(" thread ptrs:");
++ for (int i = 0; i < _thread_ptrs->length(); ++i) {
++ tty->print_cr(" [%x]=%x", i, _thread_ptrs->at(i));
++ }
++ tty->print_cr(" image:");
++ for (int i = 0; i < _frame_size; ++i) {
++ if (_relocates->contains(i)) {
++ tty->print_cr("R %x: %x", i, _frame_image[i]);
++ } else if (_oop_offsets->contains(i)) {
++ tty->print_cr("O %x: %x", i, _frame_image[i]);
++ } else {
++ tty->print_cr(" %x: %x", i, _frame_image[i]);
++ }
++ }
++#else
++ // 64 bit version.
++ tty->print_cr("StackFrameReader:");
++ tty->print( " type=");
++ switch (_frame_type) {
++ case interpreter:
++ tty->print_cr("Interpreted");
++ break;
++ case compiled:
++ tty->print_cr("Compiled");
++ break;
++ case native:
++ tty->print_cr("Native");
++ break;
++ default:
++ ShouldNotReachHere();
++ }
++ tty->print_cr(" sp=" INTPTR_FORMAT, _sp);
++ tty->print_cr(" unextended_sp=" INTPTR_FORMAT, _unextended_sp);
++ tty->print_cr(" fp=" INTPTR_FORMAT, _fp);
++ tty->print_cr(" size_of_parameters=" INTPTR_FORMAT, _size_of_parameters);
++ tty->print_cr(" frame_size=" INTPTR_FORMAT, _frame_size);
++ tty->print_cr(" pc=" INTPTR_FORMAT, _pc);
++ tty->print_cr(" relocates:");
++ for (int i = 0; i < _relocates->length(); ++i) {
++ tty->print_cr(" [%x]=" INTPTR_FORMAT, i, _relocates->at(i));
++ }
++ tty->print_cr(" relatives:");
++ for (int i = 0; i < _relatives->length(); ++i) {
++ tty->print_cr(" [%x]=" INTPTR_FORMAT, i, _relatives->at(i));
++ }
++ tty->print_cr(" relatives_base_oop:");
++ for (int i = 0; i < _relatives_base_oop->length(); ++i) {
++ tty->print_cr(" [%x]=" INTPTR_FORMAT, i, _relatives_base_oop->at(i));
++ }
++ tty->print_cr(" relatives_diff:");
++ for (int i = 0; i < _relatives_diff->length(); ++i) {
++ tty->print_cr(" [%x]=" INTPTR_FORMAT, i, _relatives_diff->at(i));
++ }
++ tty->print_cr(" oop offsets:");
++ for (int i = 0; i < _oop_offsets->length(); ++i) {
++ tty->print_cr(" [%x]=" INTPTR_FORMAT, i, _oop_offsets->at(i));
++ }
++ tty->print_cr(" thread ptrs:");
++ for (int i = 0; i < _thread_ptrs->length(); ++i) {
++ tty->print_cr(" [%x]=" INTPTR_FORMAT, i, _thread_ptrs->at(i));
++ }
++ tty->print_cr(" image:");
++ for (int i = 0; i < _frame_size; ++i) {
++ if (_relocates->contains(i)) {
++ tty->print_cr("R %x: " INTPTR_FORMAT, i, _frame_image[i]);
++ } else if (_oop_offsets->contains(i)) {
++ tty->print_cr("O %x: " INTPTR_FORMAT, i, _frame_image[i]);
++ } else {
++ tty->print_cr(" %x: " INTPTR_FORMAT, i, _frame_image[i]);
++ }
++ }
++#endif // _LP64
++ }
++
++ // base - the base address (sp) at the destination
++ void relocate(intptr_t* base) {
++ No_Safepoint_Verifier no_safepoint;
++ // update sp, fp
++ _sp = base;
++ _unextended_sp = (intptr_t*) ((intptr_t) _unextended_sp + (intptr_t) _sp);
++ _fp = (intptr_t*) ((intptr_t) _fp + (intptr_t) _sp); // if this is a compiled frame, _fp could be an oop in which case, it may not be GC-unsafe oop
++ // update relocates
++ int reloc_len = _relocates->length();
++ for (int i = 0; i < reloc_len; ++i) {
++ intptr_t* addr = _frame_image + _relocates->at(i);
++ *addr = (intptr_t)base + *addr * sizeof(intptr_t);
++ }
++ // write oops - note safe points
++ int oop_off_len = _oop_offsets->length();
++ for (int i = 0; i < oop_off_len; ++i) {
++ intptr_t* addr = _frame_image + _oop_offsets->at(i);
++ *addr = (intptr_t) _oop_arr->at(*addr)();
++ }
++ // update relatives
++ int relative_len = _relatives->length();
++ for (int i = 0; i < relative_len; ++i) {
++ intptr_t* addr = _frame_image + _relatives->at(i);
++ intptr_t base_oop = (intptr_t)_oop_arr->at(_relatives_base_oop->at(i))();
++ *addr = base_oop + _relatives_diff->at(i);
++ }
++
++ // Thread pointers
++ int thread_ptrs_len = _thread_ptrs->length();
++ for (int i = 0; i < thread_ptrs_len; ++i) {
++ intptr_t* addr = _frame_image + _thread_ptrs->at(i);
++ if (DebugContinuation) {
++ tty->print_cr("Writing thread pointer offset=" INTPTR_FORMAT, _thread_ptrs->at(i));
++ tty->print_cr("frame_size " INTPTR_FORMAT, _frame_size);
++ tty->print_cr("Thread pointer. Overwrote " INTPTR_FORMAT " with " INTPTR_FORMAT,
++ (intptr_t) *addr, (intptr_t) _thread);
++ }
++ *addr = (intptr_t) _thread;
++ }
++ }
++};
++
++class StackReader : public StackObj {
++ private:
++ Thread* _thread;
++ CompressedReadStream _stream;
++ intptr_t _stream_limit;
++ GrowableArray<Handle>* _oop_arr;
++ GrowableArray<StackFrameReader*>* _frame_readers;
++ intptr_t _nframes;
++ intptr_t _image_size;
++ address _rough_last_frame_pc;
++ address _original_stack_bottom;
++ address _original_thread;
++
++ public:
++ StackReader(Thread* thread) :
++ _thread(thread),
++ _frame_readers(new GrowableArray<StackFrameReader*>()),
++ _nframes(0),
++ _stream(CompressedReadStream(NULL, 0)),
++ _stream_limit(0),
++ _image_size(0) {
++ }
++
++ address rough_last_frame_pc() { return _rough_last_frame_pc; }
++ address original_stack_bottom() { return _original_stack_bottom; }
++
++ void read(objArrayHandle arr) {
++ assert(arr->obj_at(0) != NULL, "oop array null");
++ assert(arr->obj_at(1) != NULL, "byte array null");
++ _oop_arr = new GrowableArray<Handle>();
++ objArrayHandle oops(_thread, (objArrayOop) arr->obj_at(0));
++ for (int i = 0; i < oops->length(); ++i) {
++ _oop_arr->append(Handle(_thread, oops->obj_at(i)));
++ }
++ prepare_byte_stream(Handle(_thread, arr->obj_at(1)));
++#ifndef _LP64
++ _rough_last_frame_pc = (address) _stream.read_int();
++ _original_stack_bottom = (address) _stream.read_int();
++ _original_thread = (address) _stream.read_int();
++ _nframes = _stream.read_int();
++#else
++ _rough_last_frame_pc = (address) _stream.read_long();
++ _original_stack_bottom = (address) _stream.read_long();
++ _original_thread = (address) _stream.read_long();
++ _nframes = (intptr_t) _stream.read_long();
++#endif // _LP64
++ read_frames();
++ }
++
++ void read_frames() {
++ for (int i = 0; i < _nframes; ++i) {
++ StackFrameReader* fr = new StackFrameReader(
++ _thread, &_stream, _stream_limit, _oop_arr, &_image_size, _original_thread);
++ fr->read();
++ _frame_readers->append(fr);
++ }
++ }
++
++ intptr_t nframes() { return _nframes; }
++
++ StackFrameReader* frame_at(int i) { return _frame_readers->at(i); }
++
++ void prepare_byte_stream(Handle byte_arr) {
++ typeArrayOop ba = (typeArrayOop) byte_arr();
++ _stream_limit = ba->length();
++ const int SLOP = 10;
++ u_char* buf = NEW_RESOURCE_ARRAY(u_char, _stream_limit + SLOP);
++ Copy::conjoint_bytes(ba->byte_at_addr(0), buf, _stream_limit);
++ Copy::zero_to_bytes(buf + _stream_limit, SLOP);
++ _stream = CompressedReadStream(buf, 0);
++ }
++
++ void print() {
++ tty->print_cr("StackReader:");
++ tty->print_cr(" oops:");
++ for (int i = 0; i < _oop_arr->length(); ++i) {
++ tty->print_cr(" [%x]=" INTPTR_FORMAT, i, (intptr_t) _oop_arr->at(i)());
++ }
++ for (int i = 0; i < _frame_readers->length(); ++i) {
++ StackFrameReader* fr = _frame_readers->at(i);
++ fr->print();
++ }
++ }
++
++ // Relocate the stack image.
++ //
++ // top_frame is the frame to resume frames on top of.
++ // It's the interpreted frame for enter.
++ // Note allocations in this function are under DeoptResourceMark
++ // top_frame -> enter's frame (the frame on which to resume stack)
++ // bottom_frame_max_locals (the max_locals of the bottom frame in the saved stack)
++ ResumeBlock* relocate(frame top_frame, Handle return_value, int bottom_frame_max_locals) {
++ intptr_t* limit = top_frame.sp();
++ intptr_t* base = limit - _image_size;
++
++ intptr_t alignment_padding = 0; // the number of the alignment padding in words
++
++ {
++ if (DebugContinuation) {
++ tty->print_cr("bottom_frame_max_locals %d", bottom_frame_max_locals);
++ tty->print_cr("old limit " INTPTR_FORMAT, (intptr_t) limit);
++ tty->print_cr("old base " INTPTR_FORMAT, (intptr_t) base);
++ }
++
++ // if the stack alignment does not match the original stack,
++ // add padding at the bottom and adjust the old fp/sender_sp in the bottom frame
++ // Note: enter* are always interpreted.
++ intptr_t new_bottom = (intptr_t) limit;
++ intptr_t old_bottom = (intptr_t) _original_stack_bottom;
++ intptr_t new_alignment = new_bottom & (StackAlignmentInBytes - 1);
++ intptr_t old_alignment = old_bottom & (StackAlignmentInBytes - 1);
++
++ if (DebugContinuation) {
++ tty->print_cr("old_bottom " INTPTR_FORMAT, old_bottom);
++ tty->print_cr("new_bottom " INTPTR_FORMAT, limit);
++ tty->print_cr("old_alignment " INTPTR_FORMAT, old_alignment);
++ tty->print_cr("new_alignment " INTPTR_FORMAT, new_alignment);
++ }
++
++ if (old_alignment != new_alignment) {
++ intptr_t padding = 0;
++ padding = (new_alignment + (intptr_t)(StackAlignmentInBytes) - old_alignment) & 0xf;
++ assert(padding > 0 && padding < StackAlignmentInBytes &&
++ (padding % sizeof(intptr_t) == 0), "bad padding");
++ if (DebugContinuation) {
++ tty->print_cr("padding = " INTPTR_FORMAT " (bytes)", padding);
++ }
++ intptr_t paddingInWords = padding / sizeof(intptr_t);
++ alignment_padding = paddingInWords;
++ if (DebugContinuation) {
++ tty->print_cr("old base = " INTPTR_FORMAT, (intptr_t)base);
++ }
++ // note stack grows down
++ base -= paddingInWords;
++ limit -= paddingInWords; // though limit is dead
++ if (DebugContinuation) {
++ tty->print_cr("new base = " INTPTR_FORMAT, (intptr_t)base);
++ }
++ // adjust the old fp/sender_sp in the bottom frame
++ StackFrameReader* bottom_fr = frame_at(nframes() - 1);
++ intptr_t* btm_frame_image = bottom_fr->frame_image();
++ intptr_t btm_frame_size = bottom_fr->frame_size(); // in words
++
++#ifdef X86
++ intptr_t old_fp_index = btm_frame_size - 2 + frame::link_offset;
++ intptr_t sender_sp_index = btm_frame_size - 2 + frame::interpreter_frame_sender_sp_offset;
++ // old fp
++ if (DebugContinuation) {
++ tty->print_cr("old old_fp = " INTPTR_FORMAT, (intptr_t)btm_frame_image[old_fp_index]);
++ }
++ btm_frame_image[old_fp_index] += paddingInWords;
++ if (DebugContinuation) {
++ tty->print_cr("new old_fp = " INTPTR_FORMAT, (intptr_t)btm_frame_image[old_fp_index]);
++ }
++ // sender sp
++ if (DebugContinuation) {
++ tty->print_cr("old sender_sp = " INTPTR_FORMAT, (intptr_t)btm_frame_image[sender_sp_index]);
++ }
++ btm_frame_image[sender_sp_index] += paddingInWords;
++ if (DebugContinuation) {
++ tty->print_cr("new sender_sp = " INTPTR_FORMAT, (intptr_t)btm_frame_image[sender_sp_index]);
++ }
++#else
++ ShouldNotReachHere();
++#endif // X86
++ }
++ }
++
++ if (DebugContinuation) {
++ tty->print_cr("StackReader::relocate() limit " INTPTR_FORMAT, (intptr_t)limit);
++ tty->print_cr("StackReader::relocate() base " INTPTR_FORMAT, (intptr_t)base);
++ }
++
++ intptr_t* image = NEW_RESOURCE_ARRAY(intptr_t, _image_size);
++ intptr_t image_off = 0;
++ for (int i = 0; i < nframes(); ++i) {
++ StackFrameReader* fr = NULL;
++ int frame_size = -1;
++ fr = frame_at(i);
++ frame_size = fr->frame_size();
++ if (DebugContinuation) {
++ tty->print_cr("StackReader::relocate() relocating frame to " INTPTR_FORMAT, (intptr_t)(base + image_off));
++ }
++ fr->relocate(base + image_off);
++ memcpy(image + image_off, fr->frame_image(), frame_size * sizeof(intptr_t));
++ image_off += frame_size;
++ }
++ StackFrameReader* top_fr = frame_at(0);
++
++ // patch pc for deopt
++ // Top frame: update the pc in SFR
++ {
++ if (top_fr->may_deopt()) {
++ CodeBlob* cb = CodeCache::find_blob(top_fr->pc());
++ assert(cb != NULL, "Unrecognizable pc");
++ if (cb->is_nmethod()) {
++ nmethod* nm = (nmethod*) cb;
++ if (!nm->is_in_use() ||
++ (nm->is_osr_method() && nm->osr_entry_bci() == InvalidOSREntryBci)) // see nmethod::make_not_entrant_or_zombie for the handling of osr methods
++ {
++ address deopt_handler_pc = nm->deopt_handler_begin();
++ int orig_pc_offset = nm->orig_pc_offset();
++ if (DebugContinuation) {
++ tty->print_cr("orig_pc_offset=%d", orig_pc_offset);
++ }
++ // set original pc
++ address orig_pc_address = (address) top_fr->unextended_sp() + orig_pc_offset;
++ assert(orig_pc_address >= (address) top_fr->sp() &&
++ orig_pc_address <= (address) (top_fr->sp() + top_fr->frame_size()), "bad orig pc address");
++ address in_image_orig_pc_address = orig_pc_address - (address)base + (address)image;
++ assert(in_image_orig_pc_address >= (address) image &&
++ in_image_orig_pc_address < (address)(image + _image_size), "out of range of image");
++ *(address*)(in_image_orig_pc_address) = top_fr->pc();
++ if (DebugContinuation) {
++ tty->print_cr("deopt top_frame orig_pc = " INTPTR_FORMAT, (intptr_t)top_fr->pc());
++ }
++ // patch pc
++ top_fr->set_pc(deopt_handler_pc);
++ if (DebugContinuation) {
++ tty->print_cr("deopt top_frame deopt_pc = " INTPTR_FORMAT, (intptr_t)deopt_handler_pc);
++ }
++ }
++ }
++ }
++ }
++
++ // The rest: update the pc in the image
++ for (int i = 1; i < nframes(); ++i) {
++ StackFrameReader* fr = frame_at(i);
++ if (fr->may_deopt()) {
++ CodeBlob* cb = CodeCache::find_blob(fr->pc());
++ assert(cb != NULL, "Unrecognizable pc");
++ if (cb->is_nmethod()) {
++ nmethod* nm = (nmethod*) cb;
++ if (DebugContinuation) {
++ tty->print_cr("frame %d's nm=" INTPTR_FORMAT, i, (intptr_t)nm);
++ }
++ if (!nm->is_in_use() ||
++ (nm->is_osr_method() && nm->osr_entry_bci() == InvalidOSREntryBci)) // see nmethod::make_not_entrant_or_zombie for the handling of osr methods
++ {
++ address deopt_handler_pc = nm->deopt_handler_begin();
++ int orig_pc_offset = nm->orig_pc_offset();
++ if (DebugContinuation) {
++ tty->print_cr("orig_pc_offset=%d", orig_pc_offset);
++ }
++ // set original pc in the image
++ address orig_pc_address = (address) fr->unextended_sp() + orig_pc_offset;
++ assert(orig_pc_address >= (address) fr->sp() &&
++ orig_pc_address <= (address) (fr->sp() + fr->frame_size()), "bad orig pc address");
++ address in_image_orig_pc_address = orig_pc_address - (address)base + (address)image;
++ assert(in_image_orig_pc_address >= (address) image &&
++ in_image_orig_pc_address < (address)(image + _image_size), "out of range of image");
++ *((address*) in_image_orig_pc_address) = fr->pc();
++ if (DebugContinuation) {
++ tty->print_cr("deopt frame %d orig_pc = " INTPTR_FORMAT, i, (intptr_t)fr->pc());
++ }
++ // patch pc in the image
++ fr->set_pc(deopt_handler_pc); // this is probably useless
++#ifdef X86
++ address pc_addr = (address)(fr->sp() - 1) - (address) base + (address) image;
++ assert(pc_addr >= (address) image &&
++ pc_addr < (address)(image + _image_size), "out of image range");
++#else
++ ShouldNotReachHere();
++#endif // X86
++ *((address*) pc_addr) = deopt_handler_pc;
++ if (DebugContinuation) {
++ tty->print_cr("deopt frame %d deopt_pc = " INTPTR_FORMAT, i, (intptr_t)deopt_handler_pc);
++ }
++ }
++ }
++ }
++ }
++
++ assert(top_fr->sp() == base, "wrong base address");
++ ResumeBlock* rb = new ResumeBlock(top_fr->sp(), top_fr->fp(), top_fr->pc(),
++ _rough_last_frame_pc, return_value.raw_value(),
++ image, _image_size, bottom_frame_max_locals,
++ alignment_padding);
++ return rb;
++ }
++
++};
++
++void Continuation_DecCodeCacheRefCount(JNIEnv* env, jclass contcls, jlong pc) {
++ JavaThread* thread = JavaThread::thread_from_jni_environment(env);
++ JavaThread* THREAD = thread;
++
++ if (!UseContinuation) {
++ THROW_IE("Continuation disabled");
++ }
++
++ if (DebugContinuation) {
++ tty->print_cr("DecCodeCacheRefCount called");
++ }
++
++ CodeBlob* cb = CodeCache::find_blob((address) pc);
++ if (cb != NULL && cb->is_nmethod()) {
++ nmethod* nm = (nmethod*) cb;
++ if (nm->cont_ref_count() > 0) {
++ nm->dec_cont_ref_count();
++ }
++ }
++}
++
++typedef void (*ResumeFunction)(JavaThread*, ResumeBlock*);
++
++void Continuation_ResumeContinuation(JNIEnv *env, jclass contcls, jobject stack, jobject rv)
++{
++ JavaThread* thread = JavaThread::thread_from_jni_environment(env);
++ JavaThread* THREAD = thread;
++ ResumeBlock* rb;
++ frame top_frame;
++ int bottom_frame_max_locals = 0;
++
++ if (!UseContinuation) {
++ THROW_IE("Continuation disabled");
++ }
++
++ if (DebugContinuation) {
++ tty->print_cr("ResumeContinuation thread = " INTPTR_FORMAT, (intptr_t) thread);
++ }
++ {
++ ThreadInVMfromNative threadInVM(thread);
++ if (stack == NULL)
++ THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "stack cannot be null");
++ }
++
++ ThreadInVMfromNativeForContinuation* thread_transition = new ThreadInVMfromNativeForContinuation(thread);
++ thread->set_cont_thread_transition(thread_transition);
++
++ {
++ HandleMark hm(thread);
++
++ frame caller;
++ RegisterMap reg_map(thread, true);
++ {
++ ResourceMark rm(thread);
++ vframe* vf = thread->last_java_vframe(&reg_map);
++ vframe* prev_vf = NULL;
++ do {
++ if (vf == NULL || !vf->is_java_frame()) {
++ ThreadInVMfromNative thread_in_vm(thread);
++ THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "no enter call on stack or a native call above it");
++ }
++
++ javaVFrame* jvf = javaVFrame::cast(vf);
++
++ if (jvf->method() && jvf->method()->intrinsic_id() == vmIntrinsics::_enter) {
++ caller = *vf->frame_pointer();
++ bottom_frame_max_locals = prev_vf->frame_pointer()->interpreter_frame_method()->max_locals();
++ break;
++ }
++
++ prev_vf = vf;
++ vf = vf->sender();
++ } while (true);
++ } // end of ResourceMark
++
++ top_frame = caller;
++ assert(bottom_frame_max_locals >= 3, "not enough locals in enter0");
++ }
++
++ {
++ // Allocate our special deoptimization ResourceMark. We need a
++ // DeoptResourceMark here, as opposed to a normal ResourceMark, to
++ // allocate arena-based data structures in the C heap, to be able
++ // to deallocate them in a non-stack disciplined way (by an
++ // explicit call rather than implicitly at an the end of a source
++ // code-level scope), and to avoid the safepoint check (and
++ // possible GC) that happens at the decontruction of a normal
++ // ResourceMark.
++ DeoptResourceMark* dmark = new DeoptResourceMark(thread);
++ assert(thread->deopt_mark() == NULL, "Pending deopt!");
++ thread->set_deopt_mark(dmark);
++
++ GrowableArray<FrameInfo*>* frame_infos;
++ {
++ StackReader sr(thread);
++ // Deserialize the saved frames
++ sr.read(objArrayHandle(thread, (objArrayOop) JNIHandles::resolve(stack)));
++ if (DebugContinuation) {
++ sr.print();
++ }
++ Handle rvh(JNIHandles::resolve(rv));
++ rb = sr.relocate(top_frame, rvh, bottom_frame_max_locals);
++ if (DebugContinuation) {
++ sr.print();
++ rb->print();
++ }
++ }
++ }
++
++ ResumeFunction resume_func = (ResumeFunction) SharedRuntime::continuation_resume_blob()->entry_point();
++ resume_func(thread, rb);
++ return; // unreached.
++}
++
++class OopPrinter: public OopClosure {
++ private:
++ GrowableArray<oop*>* _oops;
++ public:
++ OopPrinter(GrowableArray<oop*>* oops) : _oops(oops) {
++ }
++ void do_oop(oop* p) {
++ _oops->append(p);
++ if (DebugContinuation) {
++ tty->print_cr(" oop: " INTPTR_FORMAT ": " INTPTR_FORMAT, p, *p);
++ }
++ }
++};
++
++static int lookup_field_offset(const char* klass_name,
++ const char* field_name,
++ symbolHandle field_signature,
++ bool is_static,
++ JavaThread* THREAD) {
++ symbolHandle klass_sym = oopFactory::new_symbol_handle(klass_name, CHECK_0);
++ instanceKlassHandle klass = SystemDictionary::resolve_or_fail(klass_sym, true, CHECK_0);
++ symbolHandle field_sym = oopFactory::new_symbol_handle(field_name, CHECK_0);
++ fieldDescriptor fd;
++ if (!klass->find_local_field(field_sym(), field_signature(), &fd)
++ || (!is_static && fd.is_static())) {
++ return 0;
++ }
++ return fd.offset();
++}
++
++typedef void (*SaveFunction)(JavaThread* thread, intptr_t sp, intptr_t fp, intptr_t pc, oop* rv);
++
++jobject Continuation_SaveContinuation(JNIEnv *env, jclass contcls, jobject continuation)
++{
++ JavaThread* thread = JavaThread::thread_from_jni_environment(env);
++ JavaThread* THREAD = thread;
++
++ if (!UseContinuation) {
++ THROW_IE_("Continuation disabled", NULL);
++ }
++
++ // Bail out if any monitor is locked in the stack
++ {
++ ThreadInVMfromNative threadInVM(thread);
++ ResourceMark rm;
++ RegisterMap reg_map(thread, true);
++ vframe* vf = thread->last_java_vframe(&reg_map);
++ int callee_params = javaVFrame::cast(vf)->method()->size_of_parameters();
++ for (; vf; vf = vf->sender()) {
++ if (vf->is_java_frame()) {
++ javaVFrame* jvf = javaVFrame::cast(vf);
++ if (jvf->method() && jvf->method()->intrinsic_id() == vmIntrinsics::_enter) {
++ break;
++ }
++ GrowableArray<MonitorInfo*>* ms = jvf->locked_monitors();
++ if (ms->length() > 0) {
++ THROW_MSG_(vmSymbols::java_lang_IllegalThreadStateException(), "a monitor is held in the continuation scope", NULL);
++ break;
++ }
++ callee_params = jvf->method()->size_of_parameters();
++ } else {
++ THROW_MSG_(vmSymbols::java_lang_IllegalThreadStateException(), "no continuation scope found", NULL);
++ break;
++ }
++ }
++ }
++
++ ThreadInVMfromNativeForContinuation* thread_transition = new ThreadInVMfromNativeForContinuation(thread);
++ thread->set_cont_thread_transition(thread_transition);
++
++ // frame to cut stack to. The frame for enter0
++ frame cut_to_frame;
++
++ // These handles need to live until the end of this function
++ Handle blob;
++ Handle pcs;
++ Handle cont;
++ Handle data1;
++ {
++ ResourceMark rm;
++ StackWriter sw(thread);
++ RegisterMap reg_map(thread, true);
++ RegisterMap reg_map_callee(&reg_map);
++ frame caller = thread->last_frame().sender(&reg_map);
++ frame callee = thread->last_frame();
++ // This is the inaccurate pc set by native_entry/native_wrapper
++ address rough_last_frame_pc = callee.pc();
++ sw.set_rough_last_frame_pc(rough_last_frame_pc);
++ intptr_t* last_frame_sp = callee.sp();
++#ifdef X86
++ // Reread pc from the stack because the last frame may have an inaccurate pc
++ // see templateInterpreter_x86_32.cpp:914 (generate_native_entry()) and
++ // sharedRuntime_x86_32.cpp:1470 (generate_native_wrapper())
++ callee = frame(callee.sp(), callee.fp());
++ // native wrapper could leave an invalid fp. So, if it's out of range,
++ // try to set fp to sp+frame_size-2
++ RegisterMap rmap(JavaThread::current(), false);
++ int callee_frame_size = callee.frame_size(&rmap);
++ address last_frame_fp = (address) callee.fp();
++ if (last_frame_fp != (address)(callee.sp() + callee_frame_size - frame::sender_sp_offset)
++ || !(last_frame_fp <= thread->stack_base() &&
++ last_frame_fp > (address) callee.sp())) {
++ // out of range
++ intptr_t* real_fp = callee.sp() + callee_frame_size - frame::sender_sp_offset;
++ if (real_fp <= (intptr_t*)thread->stack_base() &&
++ real_fp > callee.sp()) {
++ // in range
++ callee = frame(callee.sp(), real_fp);
++ } else {
++ guarantee(false, "no valid fp found for the top frame");
++ }
++ }
++#else
++ ShouldNotReachHere();
++#endif // X86
++
++ StackFrameWriter* prev_writer = NULL;
++ StackFrameWriter* writer = sw.add(callee);
++ do {
++ if (!caller.is_java_frame()) {
++ THROW_MSG_(vmSymbols::java_lang_IllegalThreadStateException(),
++ "no continuation scope found or there is a native frame inside the scope", 0);
++ }
++
++ if (DebugContinuation) {
++ RegisterMap rmap(JavaThread::current(), false);
++ int callee_frame_size = callee.frame_size(&rmap);
++ tty->print_cr("%s sp=" INTPTR_FORMAT ": " INTPTR_FORMAT " (pc=" INTPTR_FORMAT ", frame_size=%d, sp+frame_size=" INTPTR_FORMAT ", unextended_sp=" INTPTR_FORMAT ", fp=" INTPTR_FORMAT ")",
++ callee.is_interpreted_frame() ? "I" : callee.is_compiled_frame() ? "C" : "N",
++ callee.sp(),
++ *callee.sp(),
++ callee.pc(),
++ (intptr_t)callee_frame_size * sizeof(intptr_t),
++ (intptr_t)callee.sp() + callee_frame_size * sizeof(intptr_t),
++ callee.unextended_sp(),
++ callee.fp());
++ for (intptr_t* p = callee.sp() + 1; p < caller.sp(); ++p) {
++ if (p == callee.fp()) {
++ tty->print_cr(" fp=" INTPTR_FORMAT ": " INTPTR_FORMAT, p, (int)*p);
++ } else {
++ tty->print_cr(" " INTPTR_FORMAT ": " INTPTR_FORMAT, p, (int)*p);
++ }
++ }
++ }
++
++ // Need to temporarily change the pc to the rough pc set by
++ // native_wrapper in the last frame so that the OopMap is found
++ // during the oops_do call.
++ address org_pc = NULL;
++ if (last_frame_sp == callee.sp()) {
++ org_pc = callee.pc();
++ callee.set_pc(rough_last_frame_pc);
++ }
++
++ if (callee.is_interpreted_frame()) {
++ // Both GC and this code walk down the stacks and need
++ // interpreter oop maps. Because oop maps has a mutex lock,
++ // only one of the two use them at the same time and can cause
++ // deadlocks. Use the 2nd oop map cache to avoid the
++ // deadlock with GC.
++ callee.oops_interpreted_do(sw.get_oop_catcher(), &reg_map_callee, true, continuation_oop_map_cache_id);
++ } else {
++ callee.oops_do(sw.get_oop_catcher(), NULL, &reg_map_callee);
++ }
++
++ // Thread pointer map in c2 compiled frames
++ if (callee.is_compiled_frame()) {
++ CodeBlob* cb = callee.cb();
++ assert(cb != NULL, "no codeblob found");
++ OopMapSet* maps = cb->oop_maps();
++ OopMap* map = cb->oop_map_for_return_address(callee.pc());
++ assert(map != NULL, "no oop map found");
++ if (DebugContinuation) {
++ tty->print_cr("Current thread pointer " INTPTR_FORMAT, (intptr_t) thread);
++ }
++ OopMapValue omv;
++ {
++ for (OopMapStream oms(map, OopMapValue::thread_ptr_value); !oms.is_done(); oms.next()) {
++ omv = oms.current();
++ assert(omv.is_thread_ptr(), "not a OopMapValue::thread_ptr_value");
++ VMReg reg = omv.reg();
++ assert(reg->is_reg() || reg->is_stack(), "A VMReg is neither a reg or stack");
++ if (reg->is_reg()) {
++#ifndef X86
++ ShouldNotReachHere();
++#endif // X86
++ if (DebugContinuation) {
++ tty->print("Found a reg VMReg containing a thread pointer. ");
++ reg->print_on(tty);
++ tty->cr();
++ }
++ if (strcmp("ebp", reg->name()) == 0 || strcmp("rbp", reg->name()) == 0) {
++ assert(prev_writer != NULL, "prev_writer cannot be NULL");
++ frame prev_frame = prev_writer->original_frame();
++ intptr_t* thread_ptr_addr = NULL;
++ if (prev_frame.is_compiled_frame()) {
++ thread_ptr_addr = callee.sp() - frame::sender_sp_offset;
++ } else {
++ thread_ptr_addr = prev_frame.fp();
++ }
++ prev_writer->add_thread_pointer(thread_ptr_addr);
++ } else {
++ guarantee(false, "Found a reg VMReg containing a thread pointer.");
++ }
++ } else if (reg->is_stack()) {
++ int stack_offset_in_bytes = reg->reg2stack() * 4; // based off of the unextended sp. 4 bytes even on 64 bit.
++ int stack_offset_in_words = stack_offset_in_bytes / sizeof(intptr_t);
++ intptr_t* thread_ptr_addr = &callee.unextended_sp()[stack_offset_in_words];
++ intptr_t thread_ptr = *thread_ptr_addr;
++ if (DebugContinuation) {
++ tty->print_cr("Found thread pointer " INTPTR_FORMAT " in a compiled frame.",
++ thread_ptr);
++ }
++ writer->add_thread_pointer(thread_ptr_addr);
++ }
++ }
++ }
++ }
++
++ if (last_frame_sp == callee.sp()) {
++ callee.set_pc(org_pc); // set it back to the original
++ }
++
++ // Find pointers within the stack (eg sp, fp)
++ if (callee.is_interpreted_frame()) {
++#ifndef X86
++ ShouldNotReachHere();
++#endif // X86
++ writer->add_relocate((intptr_t) &callee.fp()[frame::interpreter_frame_sender_sp_offset]);
++ writer->add_relocate((intptr_t) &callee.fp()[frame::interpreter_frame_last_sp_offset]);
++ writer->add_relocate((intptr_t) &callee.fp()[frame::interpreter_frame_monitor_block_top_offset]);
++ writer->add_relocate((intptr_t) &callee.fp()[frame::interpreter_frame_locals_offset]);
++
++ intptr_t* bcx = &callee.fp()[frame::interpreter_frame_bcx_offset];
++ intptr_t* mdx = &callee.fp()[frame::interpreter_frame_mdx_offset];
++ // Note unsafe oop here
++ constMethodOop const_method = callee.interpreter_frame_method()->constMethod();
++ methodDataOop mdo = callee.interpreter_frame_method()->method_data();
++ writer->add_bcx_mdx(bcx, mdx, const_method, mdo);
++
++ if (caller.is_interpreted_frame()) {
++ writer->add_relocate((intptr_t) callee.fp());
++ if (DebugContinuation) {
++ tty->print_cr(" relocates: " INTPTR_FORMAT, (intptr_t) callee.fp());
++ }
++ } else if (caller.is_compiled_frame()) {
++#ifdef COMPILER2
++ // nothing because fp is a plain callee saved reg
++#elif COMPILER1
++ intptr_t* fp = caller.sp() - frame::sender_sp_offset;
++ writer->add_relocate((intptr_t) fp);
++ if (DebugContinuation) {
++ tty->print_cr(" relocates: %x", (intptr_t) fp);
++ }
++#else
++ ShouldNotReachHere();
++#endif // COMPILER1/2
++ } else {
++ ShouldNotReachHere();
++ }
++ } else if (callee.is_compiled_frame()) {
++ if (caller.is_interpreted_frame()) {
++ intptr_t* fp = caller.sp() - frame::sender_sp_offset;
++ writer->add_relocate((intptr_t) fp);
++ if (DebugContinuation) {
++ tty->print_cr(" relocates: " INTPTR_FORMAT, (intptr_t) fp);
++ }
++ } else if (caller.is_compiled_frame()) {
++#ifdef COMPILER2
++ // nothing because fp is a plain callee saved reg
++#elif COMPILER1
++ intptr_t* fp = caller.sp() - frame::sender_sp_offset;
++ writer->add_relocate((intptr_t) fp);
++ if (DebugContinuation) {
++ tty->print_cr(" relocates: " INTPTR_FORMAT, (intptr_t) fp);
++ }
++#else
++ ShouldNotReachHere();
++#endif // COMPILER1/2
++ } else {
++ ShouldNotReachHere();
++ }
++ } else if (callee.is_native_frame()) {
++ // this is for the second frame to the top native_wrapper frame call.
++ if (caller.is_interpreted_frame()) {
++ intptr_t* fp = caller.sp() - frame::sender_sp_offset;
++ writer->add_relocate((intptr_t) fp);
++ if (DebugContinuation) {
++ tty->print_cr(" relocates: " INTPTR_FORMAT, (intptr_t) fp);
++ }
++ } else if (caller.is_compiled_frame()) {
++#ifdef COMPILER2
++ // nothing because fp is a plain callee saved reg
++#elif COMPILER1
++ intptr_t* fp = caller.sp() - frame::sender_sp_offset;
++ writer->add_relocate((intptr_t) fp);
++ if (DebugContinuation) {
++ tty->print_cr(" relocates: " INTPTR_FORMAT, (intptr_t) fp);
++ }
++#else
++ ShouldNotReachHere();
++#endif // COMPILER1/2
++ } else {
++ ShouldNotReachHere();
++ }
++ } else {
++ if (DebugContinuation) {
++ tty->print_cr("callee.is_native = %d", callee.is_native_frame());
++ tty->print_cr("caller.is_interpreted = %d", caller.is_interpreted_frame());
++ tty->print_cr("caller.is_compiled = %d", caller.is_compiled_frame());
++ tty->print_cr("caller.is_native = %d", caller.is_native_frame());
++ }
++ ShouldNotReachHere();
++ }
++
++ if (caller.is_interpreted_frame()) {
++ // Note unsafe oop here
++ assert(thread->thread_state() == _thread_in_vm, "thread not in vm?");
++ methodHandle method = methodHandle(caller.interpreter_frame_method());
++ if (method.not_null() && method()->intrinsic_id() == vmIntrinsics::_enter) {
++ data1 = Handle((oop)(*caller.interpreter_frame_local_at(1)));
++ break;
++ }
++ }
++ reg_map_callee = reg_map;
++ prev_writer = writer;
++ writer = sw.add(caller);
++ callee = caller;
++ caller = caller.sender(&reg_map);
++ } while (true);
++
++ // At this point,
++ // caller is the enter frame
++ // callee is the enter0 frame
++ cut_to_frame = callee;
++
++ sw.set_stack_bottom((address)caller.sp());
++
++ pcs = sw.getCodeCachePCs(); // this could cause a safepoint.
++ blob = sw.write(); // this could cause a safepoint.
++ // For debugging
++ if (DebugContinuation) {
++ sw.print();
++ }
++
++ static int cont_stack_offset = 0;
++ if (cont_stack_offset == 0) {
++ cont_stack_offset = lookup_field_offset("sun/misc/Continuation",
++ "stack",
++ vmSymbolHandles::object_signature(),
++ false,
++ THREAD);
++ if (cont_stack_offset == 0) {
++ THROW_IE_("Field not found: Continuation.stack", NULL);
++ }
++ }
++ static int cont_data1_offset = 0;
++ if (cont_data1_offset == 0) {
++ cont_data1_offset = lookup_field_offset("sun/misc/Continuation",
++ "data1",
++ vmSymbolHandles::object_signature(),
++ false,
++ THREAD);
++ if (cont_data1_offset == 0) {
++ THROW_IE_("Field not found: Continuation.data1", NULL);
++ }
++ }
++ static int cont_pcs_offset = 0;
++ if (cont_pcs_offset == 0) {
++ cont_pcs_offset = lookup_field_offset("sun/misc/Continuation",
++ "pcs",
++ vmSymbolHandles::long_array_signature(),
++ false,
++ THREAD);
++ if (cont_data1_offset == 0) {
++ THROW_IE_("Field not found: Continuation.pcs", NULL);
++ }
++ }
++
++ // Signature of save_cont guarantees continuation is a Continuation
++ Handle cont_h(THREAD, JNIHandles::resolve(continuation));
++ if (cont_h->obj_field(cont_stack_offset) != NULL)
++ // Refuse to fill in a Continuation twice. It would allow various spoofs.
++ THROW_IE_("Continuation has already been filled in", NULL);
++
++ cont_h->release_obj_field_put(cont_stack_offset, blob());
++ cont_h->release_obj_field_put(cont_data1_offset, data1());
++ cont_h->release_obj_field_put(cont_pcs_offset, pcs());
++ cont = cont_h;
++ } // end of ResouceMark
++
++ if (DebugContinuation) {
++ tty->print_cr("save_cont thread=%x", (intptr_t)thread);
++ tty->print_cr("save_cont thread tlab=%x", (intptr_t)&thread->tlab());
++ tty->print_cr("save_cont thread_state=%x", (intptr_t)thread->thread_state());
++ }
++
++ // The sp/fp/pc/rv_oop to cut the stack to
++ intptr_t cut_sp = (intptr_t) cut_to_frame.sp();
++ intptr_t cut_fp = (intptr_t) cut_to_frame.fp();
++ intptr_t cut_pc = (intptr_t) cut_to_frame.pc();
++
++ SaveFunction save_func = (SaveFunction) SharedRuntime::continuation_save_blob()->entry_point();
++ save_func(thread, cut_sp, cut_fp, cut_pc, cont.raw_value());
++ return NULL;
++}
+
+ /// JVM_RegisterUnsafeMethods
+
+@@ -1464,6 +3098,14 @@
+ {CC"defineAnonymousClass", CC"("DAC_Args")"CLS, FN_PTR(Unsafe_DefineAnonymousClass)},
+ };
+
++#define CONT "Lsun/misc/Continuation;"
++JNINativeMethod continuation_methods[] = {
++ {CC"save_cont", CC"("CONT")"OBJ, FN_PTR(Continuation_SaveContinuation)},
++ {CC"resume_cont", CC"("OBJ OBJ")V", FN_PTR(Continuation_ResumeContinuation)},
++ {CC"dec_code_cache_ref_count", CC"(J)V", FN_PTR(Continuation_DecCodeCacheRefCount)}
++};
++#undef CONT
++
+ #undef CC
+ #undef FN_PTR
+
+@@ -1562,3 +3204,19 @@
+ guarantee(status == 0, "register unsafe natives");
+ }
+ JVM_END
++
++JVM_ENTRY(void, JVM_RegisterContinuationMethods(JNIEnv *env, jclass contcls))
++ UnsafeWrapper("JVM_RegisterContinuationMethods");
++ {
++ ThreadToNativeFromVM ttnfv(thread);
++ {
++ env->RegisterNatives(contcls, continuation_methods, sizeof(continuation_methods)/sizeof(JNINativeMethod));
++ if (env->ExceptionOccurred()) {
++ if (PrintMiscellaneous && (Verbose || WizardMode)) {
++ tty->print_cr("Warning: Continuation not found.");
++ }
++ env->ExceptionClear();
++ }
++ }
++ }
++JVM_END
+diff --git a/src/share/vm/runtime/arguments.cpp b/src/share/vm/runtime/arguments.cpp
+--- a/src/share/vm/runtime/arguments.cpp
++++ b/src/share/vm/runtime/arguments.cpp
+@@ -2906,6 +2906,10 @@
+ UseCompressedOops = false;
+ }
+ }
++ // Continuation currently does not support compressed oops.
++ if (UseCompressedOops && UseContinuation) {
++ UseCompressedOops = false;
++ }
+ #endif // _LP64
+
+ // Check the GC selections again.
+diff --git a/src/share/vm/runtime/deoptimization.cpp b/src/share/vm/runtime/deoptimization.cpp
+--- a/src/share/vm/runtime/deoptimization.cpp
++++ b/src/share/vm/runtime/deoptimization.cpp
+@@ -461,6 +461,11 @@
+ thread->dec_in_deopt_handler();
+ }
+
++void Deoptimization::dealloc_deopt_mark(JavaThread* thread) {
++ delete thread->deopt_mark();
++ thread->set_deopt_mark(NULL);
++}
++
+
+ // Return BasicType of value being returned
+ JRT_LEAF(BasicType, Deoptimization::unpack_frames(JavaThread* thread, int exec_mode))
+diff --git a/src/share/vm/runtime/deoptimization.hpp b/src/share/vm/runtime/deoptimization.hpp
+--- a/src/share/vm/runtime/deoptimization.hpp
++++ b/src/share/vm/runtime/deoptimization.hpp
+@@ -27,6 +27,70 @@
+ class MonitorValue;
+ class ObjectValue;
+
++class FrameInfo;
++
++// Data structure used for resuming from a continuation
++class ResumeBlock : public ResourceObj {
++ private:
++ intptr_t* _top_sp;
++ intptr_t* _top_fp;
++ address _top_pc;
++ address _rough_top_pc; // inaccurate pc that has a valid oop map, set by the native wrapper
++ oop* _return_value;
++ intptr_t* _image;
++ intptr_t _image_size;
++ intptr_t _bottom_frame_max_locals;
++ intptr_t _alignment_padding; // in words, >= 0
++
++ public:
++ ResumeBlock(intptr_t* top_sp, intptr_t* top_fp, address top_pc,
++ address rough_top_pc, oop* return_value,
++ intptr_t* image, intptr_t image_size, intptr_t bottom_frame_max_locals,
++ intptr_t alignment_padding) :
++ _top_sp(top_sp),
++ _top_fp(top_fp),
++ _top_pc(top_pc),
++ _rough_top_pc(rough_top_pc),
++ _return_value(return_value),
++ _image(image),
++ _image_size(image_size),
++ _bottom_frame_max_locals(bottom_frame_max_locals),
++ _alignment_padding(alignment_padding) {
++ }
++
++ static int top_sp_offset_in_bytes() { return offset_of(ResumeBlock, _top_sp); }
++ static int top_fp_offset_in_bytes() { return offset_of(ResumeBlock, _top_fp); }
++ static int top_pc_offset_in_bytes() { return offset_of(ResumeBlock, _top_pc); }
++ static int rough_top_pc_offset_in_bytes() { return offset_of(ResumeBlock, _rough_top_pc); }
++ static int return_value_offset_in_bytes() { return offset_of(ResumeBlock, _return_value); }
++ static int image_offset_in_bytes() { return offset_of(ResumeBlock, _image); }
++ static int image_size_offset_in_bytes() { return offset_of(ResumeBlock, _image_size); }
++ static int bottom_frame_max_locals_offset_in_bytes() { return offset_of(ResumeBlock, _bottom_frame_max_locals); }
++ static int alignment_padding_offset_in_bytes() { return offset_of(ResumeBlock, _alignment_padding); }
++
++ intptr_t* top_sp() { return _top_sp; }
++ intptr_t* top_fp() { return _top_fp; }
++ address top_pc() { return _top_pc; }
++ address rough_top_pc() { return _rough_top_pc; }
++ oop* return_value() { return _return_value; }
++ intptr_t* image() { return _image; }
++ intptr_t image_size() { return _image_size; }
++
++ void print() {
++ tty->print_cr("ResumeBlock: " INTPTR_FORMAT, (intptr_t) this);
++ tty->print_cr("top_sp=" INTPTR_FORMAT ", top_fp=" INTPTR_FORMAT ", top_pc=" INTPTR_FORMAT ", return_value=" INTPTR_FORMAT,
++ _top_sp, _top_fp, _top_pc, _return_value != NULL ? (intptr_t)*_return_value : 0);
++ tty->print_cr("image=" INTPTR_FORMAT, (intptr_t) _image);
++ tty->print_cr("image_size=" INTPTR_FORMAT, _image_size);
++ tty->print_cr("bottom_frame_max_locals=" INTPTR_FORMAT, _bottom_frame_max_locals);
++ tty->print_cr("alignment_padding=" INTPTR_FORMAT, _alignment_padding);
++ for (int i = 0; i < _image_size; ++i) {
++ intptr_t* p = &_image[i];
++ tty->print_cr(" " INTPTR_FORMAT ": " INTPTR_FORMAT ": " INTPTR_FORMAT, p, _top_sp + i, *p);
++ }
++ }
++};
++
+ class Deoptimization : AllStatic {
+ public:
+ // What condition caused the deoptimization?
+@@ -197,6 +261,9 @@
+ // Return BasicType of call return type, if any
+ static BasicType unpack_frames(JavaThread* thread, int exec_mode);
+
++ // Called by the continuation resume blob
++ static void dealloc_deopt_mark(JavaThread* thread);
++
+ // Cleans up deoptimization bits on thread after unpacking or in the
+ // case of an exception.
+ static void cleanup_deopt_info(JavaThread *thread,
+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
+@@ -838,7 +838,8 @@
+ }
+
+
+-void frame::oops_interpreted_do(OopClosure* f, const RegisterMap* map, bool query_oop_map_cache) {
++void frame::oops_interpreted_do(OopClosure* f, const RegisterMap* map, bool query_oop_map_cache,
++ OopMapCacheId oop_map_cache_id) {
+ assert(is_interpreted_frame(), "Not an interpreted frame");
+ assert(map != NULL, "map must be set");
+ Thread *thread = Thread::current();
+@@ -921,7 +922,7 @@
+ // process locals & expression stack
+ InterpreterOopMap mask;
+ if (query_oop_map_cache) {
+- m->mask_for(bci, &mask);
++ m->mask_for(bci, &mask, oop_map_cache_id);
+ } else {
+ OopMapCache::compute_one_oop_map(m, bci, &mask);
+ }
+@@ -1281,4 +1282,14 @@
+ assert(thread->has_last_Java_frame(), "sanity check");
+ _fr = thread->last_frame();
+ _is_done = false;
++ // In the call to ThreadInVMfromNativeForContinuation::dealloc in
++ // the continuation save blob, GC can occur and will walk down the
++ // stack of this thread from the enter0 frame (which is the
++ // designated last Java frame.) But here in the GC code we shouldn't
++ // examine oops in the outgoing arguments of the enter0 frame
++ // because they can be garbage if the frame above (the enter1 frame)
++ // is a compiled frame.
++ if (thread->cont_thread_transition() != NULL) {
++ _reg_map.set_include_argument_oops(false);
++ }
+ }
+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
+@@ -354,7 +354,7 @@
+
+ // Oops-do's
+ void oops_compiled_arguments_do(symbolHandle signature, bool has_receiver, const RegisterMap* reg_map, OopClosure* f);
+- void oops_interpreted_do(OopClosure* f, const RegisterMap* map, bool query_oop_map_cache = true);
++ void oops_interpreted_do(OopClosure* f, const RegisterMap* map, bool query_oop_map_cache = true, OopMapCacheId oop_map_cache_id = default_oop_map_cache_id);
+
+ private:
+ void oops_interpreted_arguments_do(symbolHandle signature, bool has_receiver, OopClosure* f);
+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
+@@ -3523,6 +3523,12 @@
+ develop(bool, TraceInvokeDynamic, false, \
+ "trace internal invoke dynamic operations") \
+ \
++ product(bool, UseContinuation, true, \
++ "Enable the Continuation feature") \
++ \
++ diagnostic(bool, DebugContinuation, false, \
++ "Print the Continuation debug messages") \
++ \
+ diagnostic(bool, PauseAtStartup, false, \
+ "Causes the VM to pause at startup time and wait for the pause " \
+ "file to be removed (default: ./vm.paused.<pid>)") \
+diff --git a/src/share/vm/runtime/interfaceSupport.hpp b/src/share/vm/runtime/interfaceSupport.hpp
+--- a/src/share/vm/runtime/interfaceSupport.hpp
++++ b/src/share/vm/runtime/interfaceSupport.hpp
+@@ -251,6 +251,33 @@
+ }
+ };
+
++// Special version of ThreadInVMfromNative for continuation operations
++class ThreadInVMfromNativeForContinuation : public CHeapObj {
++ private:
++ JavaThread* _thread;
++ public:
++ ThreadInVMfromNativeForContinuation(JavaThread* thread) {
++ _thread = thread;
++ ThreadStateTransition::transition_from_native(_thread, _thread_in_vm);
++ }
++ ~ThreadInVMfromNativeForContinuation() {
++ if (DebugContinuation) {
++ tty->print_cr("~ThreadInVMfromNativeForContinuation... " INTPTR_FORMAT,
++ (intptr_t) _thread);
++ }
++ ThreadStateTransition::transition_and_fence(_thread, _thread_in_vm, _thread_in_native);
++ }
++ static void dealloc(JavaThread* thread) {
++ ThreadInVMfromNativeForContinuation* tt = thread->cont_thread_transition();
++ assert(tt != NULL, "Null cont thread transition");
++ delete tt; // this calls the destructor and could block for GC
++ // The field thread::_cont_thread_transition must be non-null
++ // (i.e., pointing the deallocated) until the end of the
++ // continuation_{save,resume}_blob so that GCs that happen while
++ // the thread is in the blob won't look at the arguments of the
++ // top enter0 frame.
++ }
++};
+
+ class ThreadToNativeFromVM : public ThreadStateTransition {
+ public:
+diff --git a/src/share/vm/runtime/sharedRuntime.hpp b/src/share/vm/runtime/sharedRuntime.hpp
+--- a/src/share/vm/runtime/sharedRuntime.hpp
++++ b/src/share/vm/runtime/sharedRuntime.hpp
+@@ -262,9 +262,16 @@
+ // deopt blob
+ static void generate_deopt_blob(void);
+ static DeoptimizationBlob* _deopt_blob;
++ // continuation blob
++ static RuntimeStub* generate_continuation_save_blob(void);
++ static RuntimeStub* generate_continuation_resume_blob(void);
++ static RuntimeStub* _continuation_save_blob;
++ static RuntimeStub* _continuation_resume_blob;
+
+ public:
+ static DeoptimizationBlob* deopt_blob(void) { return _deopt_blob; }
++ static RuntimeStub* continuation_save_blob(void) { return _continuation_save_blob; }
++ static RuntimeStub* continuation_resume_blob(void) { return _continuation_resume_blob; }
+
+ // Resets a call-site in compiled code so it will get resolved again.
+ static methodHandle reresolve_call_site(JavaThread *thread, TRAPS);
+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
+@@ -1158,6 +1158,7 @@
+ set_vframe_array_head(NULL);
+ set_vframe_array_last(NULL);
+ set_deferred_locals(NULL);
++ set_cont_thread_transition(NULL);
+ set_deopt_mark(NULL);
+ clear_must_deopt_id();
+ set_monitor_chunks(NULL);
+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
+@@ -39,6 +39,7 @@
+ class CompilerCounters;
+ class vframeArray;
+
++class ThreadInVMfromNativeForContinuation;
+ class DeoptResourceMark;
+ class jvmtiDeferredLocalVariableSet;
+
+@@ -672,6 +673,9 @@
+
+ JNIEnv _jni_environment;
+
++ // Used by continuation operations
++ ThreadInVMfromNativeForContinuation* _cont_thread_transition;
++
+ // Deopt support
+ DeoptResourceMark* _deopt_mark; // Holds special ResourceMark for deoptimization
+
+@@ -1082,6 +1086,10 @@
+ void set_vframe_array_last(vframeArray* value) { _vframe_array_last = value; }
+ vframeArray* vframe_array_last() const { return _vframe_array_last; }
+
++ // Continuation support
++ void set_cont_thread_transition(ThreadInVMfromNativeForContinuation* value) { _cont_thread_transition = value; }
++ ThreadInVMfromNativeForContinuation* cont_thread_transition(void) { return _cont_thread_transition; }
++
+ // The special resourceMark used during deoptimization
+
+ void set_deopt_mark(DeoptResourceMark* value) { _deopt_mark = value; }
+@@ -1182,6 +1190,7 @@
+ static ByteSize callee_target_offset() { return byte_offset_of(JavaThread, _callee_target ); }
+ static ByteSize vm_result_offset() { return byte_offset_of(JavaThread, _vm_result ); }
+ static ByteSize vm_result_2_offset() { return byte_offset_of(JavaThread, _vm_result_2 ); }
++ static ByteSize cont_thread_transition_offset(){ return byte_offset_of(JavaThread, _cont_thread_transition); }
+ static ByteSize thread_state_offset() { return byte_offset_of(JavaThread, _thread_state ); }
+ static ByteSize saved_exception_pc_offset() { return byte_offset_of(JavaThread, _saved_exception_pc ); }
+ static ByteSize osthread_offset() { return byte_offset_of(JavaThread, _osthread ); }
+diff --git a/src/share/vm/runtime/vframeArray.cpp b/src/share/vm/runtime/vframeArray.cpp
+--- a/src/share/vm/runtime/vframeArray.cpp
++++ b/src/share/vm/runtime/vframeArray.cpp
+@@ -26,6 +26,117 @@
+ # include "incls/_vframeArray.cpp.incl"
+
+
++#ifndef PRODUCT
++void FrameInfo::print(outputStream* st) {
++ st->print("FrameInfo method: ");
++ _method->name()->print_symbol_on(st);
++ st->print(" (bci: %i, ", _bci);
++ st->print("locals: %i, expressions: %i, monitors: %i\n", _locals->size(), _expressions->size(), _monitors->length());
++
++ st->print(" locals: ");
++ for (int i=0; i<_locals->size(); i++) {
++ StackValue* v = _locals->at(i);
++ switch (v->type()) {
++ case T_INT:
++ st->print(INTPTR_FORMAT " ", v->get_int());
++ break;
++ case T_OBJECT:
++ st->print("OBJ(" INTPTR_FORMAT ") ", v->get_int(T_OBJECT));
++ break;
++ default:
++ ShouldNotReachHere();
++ }
++ }
++
++ st->print("\n expressions: ");
++ for (int i=0; i<_expressions->size(); i++) {
++ StackValue* v = _expressions->at(i);
++ switch (v->type()) {
++ case T_INT:
++ st->print("%08x ", v->get_int());
++ break;
++ case T_OBJECT:
++ st->print("OBJ(%08x) ", v->get_int(T_OBJECT));
++ break;
++ default:
++ ShouldNotReachHere();
++ }
++ }
++ st->print("\n monitors: ");
++ for (int i=0; i<_monitors->length(); i++) {
++ MonitorInfo* v = _monitors->at(i);
++ st->print("%08x ", v->owner());
++ }
++ st->print("\n");
++}
++#endif /* PRODUCT */
++
++#ifdef ASSERT
++void FrameInfo::verify() {
++ // TODO add useful assertions
++}
++#endif /* ASSERT */
++
++
++void vframeArrayElement::fill_in(FrameInfo* frame_info) {
++
++ // copy the info from the FrameInfo object - it has to be in the correct format (object locals and expressions as ints)
++ _method = frame_info->method();
++ _bci = frame_info->bci();
++ _locals = frame_info->locals();
++ _expressions = frame_info->expressions();
++
++ // reacquire the monitors of the stack frame
++ GrowableArray<MonitorInfo*>* list = frame_info->monitors();
++ if (list->is_empty()) {
++ _monitors = NULL;
++ } else {
++ int index;
++ JavaThread* thread = JavaThread::current();
++
++ // monitor handling is not finished...
++ //ShouldNotReachHere();
++
++ // Allocate monitor chunk
++ _monitors = new MonitorChunk(list->length());
++ thread->add_monitor_chunk(_monitors);
++
++ // Simply restore monitor entries with lockee obj + displaced
++ // header saved by write_monitors. Populate monitor chuncks (that
++ // unpack_to_stack copies to real interpreter frames later) from
++ // the MonitorInfos.
++ for (index = 0; index < list->length(); index++) {
++ MonitorInfo* monitor = list->at(index);
++ oop obj = monitor->owner();
++ BasicObjectLock* dest = _monitors->at(index);
++ dest->set_obj(obj);
++ dest->lock()->set_displaced_header(monitor->lock()->displaced_header());
++ }
++ }
++}
++
++vframeArray* vframeArray::allocate(JavaThread* thread, int frame_size, GrowableArray<FrameInfo*>* frame_infos,
++ frame sender, frame caller) {
++
++ // Allocate the vframeArray
++ vframeArray * result = (vframeArray*) AllocateHeap(sizeof(vframeArray) + // fixed part
++ sizeof(vframeArrayElement) * (frame_infos->length() - 1), // variable part
++ "vframeArray::allocate");
++ result->_frames = frame_infos->length();
++ result->_owner_thread = thread;
++ result->_sender = sender;
++ result->_caller = caller;
++ // result->_original = self;
++ result->set_unroll_block(NULL); // initialize it
++
++ result->_frame_size = frame_size;
++ for(int i = 0; i < frame_infos->length(); i++) {
++ result->element(i)->fill_in(frame_infos->at(i));
++ }
++
++ return result;
++}
++
+ int vframeArrayElement:: bci(void) const { return (_bci == SynchronizationEntryBCI ? 0 : _bci); }
+
+ void vframeArrayElement::free_monitors(JavaThread* jt) {
+diff --git a/src/share/vm/runtime/vframeArray.hpp b/src/share/vm/runtime/vframeArray.hpp
+--- a/src/share/vm/runtime/vframeArray.hpp
++++ b/src/share/vm/runtime/vframeArray.hpp
+@@ -34,6 +34,46 @@
+ class MonitorArrayElement;
+ class StackValueCollection;
+
++// Represents the current state of one stack frame. Used mainly for creating vframeArrays from scratch.
++
++class FrameInfo : public ResourceObj {
++private:
++ methodOop _method;
++ int _bci;
++ StackValueCollection* _locals;
++ StackValueCollection* _expressions;
++ GrowableArray<MonitorInfo*>* _monitors;
++
++public:
++
++ FrameInfo(methodOop method, int bci, StackValueCollection* locals, StackValueCollection* expressions, GrowableArray<MonitorInfo*>* monitors) {
++ _method = method;
++ _bci = bci;
++ _locals = locals;
++ _expressions = expressions;
++ _monitors = monitors;
++ }
++
++ methodOop method() const { return _method; }
++
++ int bci() const { return _bci; }
++
++ StackValueCollection* locals() const { return _locals; }
++
++ StackValueCollection* expressions() const { return _expressions; }
++
++ GrowableArray<MonitorInfo*>* monitors() const { return _monitors; }
++
++#ifndef PRODUCT
++ void print(outputStream* st);
++#endif /* PRODUCT */
++
++#ifdef ASSERT
++ void verify();
++#endif /* ASSERT */
++};
++
++
+ // A vframeArrayElement is an element of a vframeArray. Each element
+ // represent an interpreter frame which will eventually be created.
+
+@@ -68,6 +108,7 @@
+ StackValueCollection* expressions(void) const { return _expressions; }
+
+ void fill_in(compiledVFrame* vf);
++ void fill_in(FrameInfo* frame_info);
+
+ // Formerly part of deoptimizedVFrame
+
+@@ -147,6 +188,10 @@
+ static vframeArray* allocate(JavaThread* thread, int frame_size, GrowableArray<compiledVFrame*>* chunk,
+ RegisterMap* reg_map, frame sender, frame caller, frame self);
+
++ // special case for creating a vframeArray from scratch
++ static vframeArray* allocate(JavaThread* thread, int frame_size, GrowableArray<FrameInfo*>* frame_infos,
++ frame sender, frame caller);
++
+
+ vframeArrayElement* element(int index) { assert(is_within_bounds(index), "Bad index"); return &_elements[index]; }
+
+diff --git a/src/share/vm/runtime/vmStructs.cpp b/src/share/vm/runtime/vmStructs.cpp
+--- a/src/share/vm/runtime/vmStructs.cpp
++++ b/src/share/vm/runtime/vmStructs.cpp
+@@ -116,7 +116,7 @@
+ nonstatic_field(instanceKlass, _vtable_len, int) \
+ nonstatic_field(instanceKlass, _itable_len, int) \
+ nonstatic_field(instanceKlass, _reference_type, ReferenceType) \
+- volatile_nonstatic_field(instanceKlass, _oop_map_cache, OopMapCache*) \
++ volatile_nonstatic_field(instanceKlass, _oop_map_caches[0], OopMapCache*) \
+ nonstatic_field(instanceKlass, _jni_ids, JNIid*) \
+ nonstatic_field(instanceKlass, _osr_nmethods_head, nmethod*) \
+ nonstatic_field(instanceKlass, _breakpoints, BreakpointInfo*) \
+diff --git a/src/share/vm/utilities/globalDefinitions.hpp b/src/share/vm/utilities/globalDefinitions.hpp
+--- a/src/share/vm/utilities/globalDefinitions.hpp
++++ b/src/share/vm/utilities/globalDefinitions.hpp
+@@ -1171,3 +1171,9 @@
+ # endif /* ASSERT */
+
+ #define ARRAY_SIZE(array) (sizeof(array)/sizeof((array)[0]))
++
++enum OopMapCacheId {
++ default_oop_map_cache_id = 0,
++ continuation_oop_map_cache_id = 1,
++ limit_oop_map_cache_id = 2 // Not a real entry. Always the last.
++};
--- a/callcc.patch Thu Oct 28 12:09:03 2010 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,4664 +0,0 @@
-diff --git a/src/cpu/x86/vm/c1_CodeStubs_x86.cpp b/src/cpu/x86/vm/c1_CodeStubs_x86.cpp
---- a/src/cpu/x86/vm/c1_CodeStubs_x86.cpp
-+++ b/src/cpu/x86/vm/c1_CodeStubs_x86.cpp
-@@ -510,4 +510,44 @@
- #endif // SERIALGC
- /////////////////////////////////////////////////////////////////////////////
-
-+
-+ContinuationStub::ContinuationStub(LIR_OpJavaCall* op): _op(op) {
-+ _info = op->info();
-+}
-+
-+
-+void ContinuationStub::emit_code(LIR_Assembler* ce) {
-+ // TODO handle monitor count correctly
-+ assert(ce->frame_map()->num_monitors() == 0, "monitor handling not implemented!");
-+
-+ // IMPORTANT this nop is required because ImplicitNullCheckStub sets debug info for the first instruction
-+ // after its end (at least in product builds) and this collides with our debug info
-+ __ nop();
-+
-+ __ bind(_entry);
-+ int stub_pc = ce->code_offset();
-+ ce->add_call_info_here(_info);
-+ ce->verify_oop_map(_info);
-+
-+ klassOop k = SystemDictionary::Continuation_klass();
-+// k->klass_part()->initialize();
-+
-+ nmethod* nm = javax_stack_Continuation::get_store_frames_nmethod(_op->method()->return_type()->basic_type());
-+ assert(nm, "unsupported return type");
-+
-+ // this move is performed in create_storeFrameGeneric_contents
-+ // __ movl(rcx, rax);
-+
-+ // this acts as a trampoline to the generic nmethod frame copying stub
-+ __ call(RuntimeAddress(nm->verified_entry_point()));
-+
-+ ce->add_call_info_here(_info);
-+ ce->verify_oop_map(_info);
-+
-+ __ jmp(_continuation);
-+
-+ ce->compilation()->continuation_pc_table()->add_entry(_pc, stub_pc);
-+
-+}
-+
- #undef __
-diff --git a/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp b/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp
---- a/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp
-+++ b/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp
-@@ -436,6 +436,29 @@
-
- int offset = code_offset();
-
-+ if (compilation()->method()->create_continuation_stubs()) {
-+// tty->print("codepos: %08x\n", pc());
-+
-+ Label skip;
-+ __ get_thread(rcx);
-+ __ movptr(rcx, Address(rcx, JavaThread::current_continuation_frame_offset()));
-+ __ testptr(rcx, rcx);
-+ __ jcc(Assembler::zero, skip);
-+ __ cmpptr(rbp, Address(rcx, activationFrameOopDesc::stack_pos_offset()));
-+ __ jcc(Assembler::notEqual, skip);
-+
-+// __ int3();
-+// __ warn("continuable exception handling");
-+
-+ __ push(rdx);
-+ __ movptr(rcx, rax);
-+ __ movptr(rbx, AddressLiteral(javax_stack_Continuation::get_unwind_nmethod_adr(), relocInfo::none));
-+ __ movptr(rbx, Address(rbx, nmethod::verified_entry_point_offset()));
-+ __ jmp(rbx);
-+
-+ __ bind(skip);
-+ }
-+
- // the exception oop and pc are in rax, and rdx
- // no other registers need to be preserved, so invalidate them
- __ invalidate_registers(false, true, true, false, true, true);
-diff --git a/src/cpu/x86/vm/c1_MacroAssembler_x86.cpp b/src/cpu/x86/vm/c1_MacroAssembler_x86.cpp
---- a/src/cpu/x86/vm/c1_MacroAssembler_x86.cpp
-+++ b/src/cpu/x86/vm/c1_MacroAssembler_x86.cpp
-@@ -138,7 +138,7 @@
- void C1_MacroAssembler::initialize_header(Register obj, Register klass, Register len, Register t1, Register t2) {
- assert_different_registers(obj, klass, len);
- if (UseBiasedLocking && !len->is_valid()) {
-- assert_different_registers(obj, klass, len, t1, t2);
-+ assert_different_registers(obj, klass, len, t1);
- movptr(t1, Address(klass, Klass::prototype_header_offset_in_bytes() + klassOopDesc::klass_part_offset_in_bytes()));
- movptr(Address(obj, oopDesc::mark_offset_in_bytes()), t1);
- } else {
-diff --git a/src/cpu/x86/vm/interpreter_x86.hpp b/src/cpu/x86/vm/interpreter_x86.hpp
---- a/src/cpu/x86/vm/interpreter_x86.hpp
-+++ b/src/cpu/x86/vm/interpreter_x86.hpp
-@@ -30,6 +30,7 @@
- // block of code to handle compiedl return values and cleaning
- // the fpu stack.
- static const int return_sentinel;
-+ static const int return_sentinel2;
-
-
- static Address::ScaleFactor stackElementScale() {
-diff --git a/src/cpu/x86/vm/interpreter_x86_32.cpp b/src/cpu/x86/vm/interpreter_x86_32.cpp
---- a/src/cpu/x86/vm/interpreter_x86_32.cpp
-+++ b/src/cpu/x86/vm/interpreter_x86_32.cpp
-@@ -29,6 +29,7 @@
-
- // Initialize the sentinel used to distinguish an interpreter return address.
- const int Interpreter::return_sentinel = 0xfeedbeed;
-+const int Interpreter::return_sentinel2 = 0xfeedbffd;
-
- //------------------------------------------------------------------------------------------------------------------------
-
-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
-@@ -1181,6 +1181,16 @@
- }
- }
-
-+void create_saveContinuation_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_resumeContinuation_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_storeFrameGeneric_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_startDelimited_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_continueDelimited_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 test_continuation_resume(MacroAssembler *masm, Register thread_reg, Register temp);
-+
- // ---------------------------------------------------------------------------
- // Generate a native wrapper for a given method. The method takes arguments
- // in the Java compiled code convention, marshals them to the native
-@@ -1364,6 +1374,32 @@
- __ ret(0);
- __ bind (slowCase);
- }
-+
-+ // all the continuation support methods have a hand-coded fast version that will handle the most common cases
-+ if (method->intrinsic_id() == vmIntrinsics::_saveContinuation) {
-+ create_saveContinuation_contents(masm, start, oop_maps, stack_slots, total_in_args, in_sig_bt, in_regs, ret_type);
-+ }
-+ if (method->intrinsic_id() == vmIntrinsics::_resumeContinuation) {
-+ create_resumeContinuation_contents(masm, start, oop_maps, stack_slots, total_in_args, in_sig_bt, in_regs, ret_type);
-+ }
-+ if (method->intrinsic_id() == vmIntrinsics::_storeFrameObject ||
-+ method->intrinsic_id() == vmIntrinsics::_storeFrameVoid ||
-+ method->intrinsic_id() == vmIntrinsics::_storeFrameBoolean ||
-+ method->intrinsic_id() == vmIntrinsics::_storeFrameByte ||
-+ method->intrinsic_id() == vmIntrinsics::_storeFrameChar ||
-+ method->intrinsic_id() == vmIntrinsics::_storeFrameShort ||
-+ method->intrinsic_id() == vmIntrinsics::_storeFrameInt ||
-+ method->intrinsic_id() == vmIntrinsics::_storeFrameLong ||
-+ method->intrinsic_id() == vmIntrinsics::_storeFrameFloat ||
-+ method->intrinsic_id() == vmIntrinsics::_storeFrameDouble) {
-+ create_storeFrameGeneric_contents(masm, start, oop_maps, stack_slots, total_in_args, in_sig_bt, in_regs, ret_type);
-+ }
-+ if (method->intrinsic_id() == vmIntrinsics::_startDelimited) {
-+ create_startDelimited_contents(masm, start, oop_maps, stack_slots, total_in_args, in_sig_bt, in_regs, ret_type);
-+ }
-+ if (method->intrinsic_id() == vmIntrinsics::_continueDelimited) {
-+ create_continueDelimited_contents(masm, start, oop_maps, stack_slots, total_in_args, in_sig_bt, in_regs, ret_type);
-+ }
- #endif // COMPILER1
-
- // The instruction at the verified entry point must be 5 bytes or longer
-@@ -1832,6 +1868,21 @@
- // Return
-
- __ leave();
-+
-+ if (method->intrinsic_id() == vmIntrinsics::_storeFrameObject ||
-+ method->intrinsic_id() == vmIntrinsics::_storeFrameVoid ||
-+ method->intrinsic_id() == vmIntrinsics::_storeFrameBoolean ||
-+ method->intrinsic_id() == vmIntrinsics::_storeFrameByte ||
-+ method->intrinsic_id() == vmIntrinsics::_storeFrameChar ||
-+ method->intrinsic_id() == vmIntrinsics::_storeFrameShort ||
-+ method->intrinsic_id() == vmIntrinsics::_storeFrameInt ||
-+ method->intrinsic_id() == vmIntrinsics::_storeFrameLong ||
-+ method->intrinsic_id() == vmIntrinsics::_storeFrameFloat ||
-+ method->intrinsic_id() == vmIntrinsics::_storeFrameDouble) {
-+ __ get_thread(rdi);
-+ test_continuation_resume(masm, rdi, rsi);
-+ }
-+
- __ ret(0);
-
- // Unexpected paths are out of line and go here
-@@ -3077,3 +3128,862 @@
- generate_uncommon_trap_blob();
- #endif // COMPILER2
- }
-+
-+// finds the code blob for a given pc, t1 needs to be rax ... rdx
-+void find_code_blob(MacroAssembler* masm, Register pc, Register t1, Label& no_codeblob) {
-+ __ cmpl(pc, (int)CodeCache::heap()->low_boundary());
-+ __ jcc(Assembler::below, no_codeblob);
-+ __ cmpl(pc, (int)CodeCache::heap()->high_boundary());
-+ __ jcc(Assembler::aboveEqual, no_codeblob);
-+
-+ __ subl(pc, (int)CodeCache::heap()->begin());
-+ __ shrl(pc, (int)CodeCache::heap()->log2_segment_size());
-+
-+ __ xorl(t1, t1);
-+
-+ Label loop;
-+ __ bind(loop);
-+ __ movb(t1, Address(pc, (int)CodeCache::heap()->segmap().low()));
-+ __ cmpl(t1, 0xff);
-+ __ jcc(Assembler::equal, no_codeblob);
-+ __ subl(pc, t1);
-+ __ testl(t1, t1);
-+ __ jcc(Assembler::notZero, loop);
-+
-+ assert(sizeof(bool) == 1, "bool size");
-+ __ shll(pc, CodeCache::heap()->log2_segment_size());
-+ __ cmpb(Address(pc, in_bytes(HeapBlock::used_offset()) + (int)CodeCache::heap()->begin()), 0x00);
-+ __ jcc(Assembler::zero, no_codeblob);
-+
-+ __ addl(pc, in_bytes(HeapBlock::allocated_offset()) + (int)CodeCache::heap()->begin());
-+}
-+
-+
-+void initialize_header(MacroAssembler* masm, Register obj, Register klass, Register t1) {
-+ assert_different_registers(obj, klass);
-+ if (UseBiasedLocking) {
-+ assert_different_registers(obj, klass, t1);
-+ __ movptr(t1, Address(klass, Klass::prototype_header_offset_in_bytes() + klassOopDesc::klass_part_offset_in_bytes()));
-+ __ movptr(Address(obj, oopDesc::mark_offset_in_bytes()), t1);
-+ } else {
-+ // This assumes that all prototype bits fit in an int32_t
-+ __ movptr(Address(obj, oopDesc::mark_offset_in_bytes ()), (int32_t)(intptr_t)markOopDesc::prototype());
-+ }
-+
-+ __ movptr(Address(obj, oopDesc::klass_offset_in_bytes()), klass);
-+}
-+
-+
-+void test_continuation_resume(MacroAssembler *masm, Register thread_reg, Register temp) {
-+ assert(temp != rdi, "cannot use rdi as temp");
-+ // check if there is a pending resume operation
-+ Label resume;
-+ __ movptr(temp, Address(thread_reg, JavaThread::resume_common_frame_offset()));
-+ __ testptr(temp, temp);
-+ __ jcc(Assembler::notZero, resume);
-+ __ ret(0);
-+
-+ __ bind(resume);
-+
-+ Label native_method;
-+ __ movptr(temp, Address(rsp, 0));
-+ __ cmpptr(temp, (int)Interpreter::code()->code_start());
-+ __ jcc(Assembler::below, native_method);
-+ __ cmpptr(temp, (int)Interpreter::code()->code_end());
-+ __ jcc(Assembler::aboveEqual, native_method);
-+
-+ // we need to restore the sender_sp if the current frame is interpreted
-+ __ movptr(rsp, Address(rbp, frame::interpreter_frame_sender_sp_offset * wordSize));
-+ __ movptr(temp, Address(rbp, frame::return_addr_offset * wordSize));
-+ __ push(temp);
-+ __ movptr(temp, Address(rbp, frame::link_offset * wordSize));
-+ __ push(temp);
-+ __ movptr(rbp, rsp);
-+
-+ __ bind(native_method);
-+
-+ // check if we've reached the frame from where we'll resume yet, otherwise: return
-+ Label resume_not_reached;
-+ __ movptr(temp, Address(thread_reg, JavaThread::resume_common_frame_offset()));
-+ __ cmpptr(temp, Address(thread_reg, JavaThread::current_continuation_frame_offset()));
-+ __ jcc(Assembler::notEqual, resume_not_reached);
-+
-+ // jump to the resume method
-+ __ movptr(temp, ExternalAddress(javax_stack_Continuation::get_resume_nmethod_adr()));
-+ __ movptr(temp, Address(temp, nmethod::verified_entry_point_offset()));
-+ __ movptr(rdi, thread_reg);
-+ __ jmp(temp);
-+
-+ __ bind(resume_not_reached);
-+
-+ // destroy the last stack frame
-+ __ movl(rax, 0); // clear the return value (might be an oop...)
-+ __ leave();
-+ __ ret(0);
-+}
-+
-+
-+void stop_if(MacroAssembler *masm, Assembler::Condition condition, const char* message) {
-+ Label skip;
-+ __ jcc(masm->negate_condition(condition), skip);
-+
-+ __ int3();
-+ __ stop(message);
-+ __ bind(skip);
-+}
-+
-+void createAndPatchFrame(MacroAssembler* masm, Register& thread, Register& method, Register& frame, Register& temp1,
-+ Register& temp2, Register return_address_reg, int return_address_offset, Label& slow_case) {
-+ assert_different_registers(thread, method, frame, temp1, temp2);
-+
-+ // find the code blob that corresponds to the next frame's pc (a NULL codeblob is bad and will be handled by the C++ path)
-+ __ movptr(method, Address(return_address_reg, return_address_offset));
-+ find_code_blob(masm, method, temp1, slow_case);
-+
-+ // check if the returned blob is an nmethod, otherwise jump to the C++ path
-+ __ cmpl(Address(method, CodeBlob::type_offset()), CodeBlob::_nmethod);
-+ __ jcc(Assembler::notEqual, slow_case);
-+
-+ // get frame and parameter size, with activationFrameOop header size and object-aligned
-+ __ movl(temp1, Address(method, nmethod::activation_frame_size_offset()));
-+
-+ // -1 is a marker for a native nmethod
-+ __ cmpl(temp1, -1);
-+ __ jcc(Assembler::equal, slow_case);
-+
-+ // allocate the next frame
-+ __ tlab_allocate(frame, temp1, 0, temp2, temp1, slow_case); // new_frame = new activationFrame[temp1]
-+ __ movoop(temp1, JNIHandles::make_local(Universe::activationFrameKlassObj())); // temp1 = activationFrameKlass
-+ initialize_header(masm, frame, temp1, temp2);
-+
-+ // prepare the new frame pt1: method, fp, state
-+ __ movl(Address(frame, activationFrameOopDesc::method_offset()), method); // frame->method = method
-+ if (return_address_reg == rsp) {
-+ __ movl(Address(frame, activationFrameOopDesc::stack_pos_offset()), rbp); // frame->stack_pos = rbp
-+ } else {
-+ __ movl(temp1, Address(rbp, 0));
-+ __ movl(Address(frame, activationFrameOopDesc::stack_pos_offset()), temp1); // frame->stack_pos = *rbp
-+ }
-+ __ movl(Address(frame, activationFrameOopDesc::state_offset()), activationFrameOopDesc::_compiled_empty); // frame->state = _compiled_empty
-+
-+ __ movl(Address(frame, activationFrameOopDesc::thread_offset()), thread); // frame->thread = thread
-+
-+ {
-+ // look for the patch address
-+
-+ // set rsi and rdi to the start and end of the continuation pc table
-+ __ movl(temp2, Address(method, nmethod::nmethod_end_offset_offset()));
-+ __ addl(temp2, method);
-+ __ addl(method, Address(method, nmethod::continuation_pc_table_offset_offset()));
-+
-+ __ movl(temp1, Address(return_address_reg, return_address_offset));
-+
-+ // linear loop (should be binary search?) over all patch addresses
-+ Label loop;
-+ __ bind(loop);
-+ __ cmpl(method, temp2);
-+ __ jcc(Assembler::aboveEqual, slow_case);
-+
-+ __ addl(method, 2 * HeapWordSize);
-+ __ cmpl(temp1, Address(method, -2 * HeapWordSize));
-+ __ jcc(Assembler::notEqual, loop);
-+
-+ // patch the return address for the next frame
-+ __ movl(temp1, Address(method, -HeapWordSize));
-+ __ movl(Address(return_address_reg, return_address_offset), temp1);
-+ }
-+
-+ // prepare the new frame pt2: pc
-+ __ movl(Address(frame, activationFrameOopDesc::pc_offset()), temp1);
-+
-+ method = noreg;
-+}
-+
-+//#define CONTINUATION_SLOW_CASE
-+
-+
-+void create_saveContinuation_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) {
-+ assert(total_in_args == 1, "unexpected number of arguments");
-+ assert(ret_type == T_OBJECT, "unexpected return type");
-+ assert(in_sig_bt[0] == T_OBJECT, "unexpected argument type");
-+ assert(in_regs[0].first() == rcx->as_VMReg(), "unexpected argument register");
-+ Register cont = rcx;
-+
-+ Label slow_case;
-+ Label no_continuation_object;
-+
-+#ifdef CONTINUATION_SLOW_CASE
-+ __ jmp(slow_case);
-+#endif
-+
-+ Register thread = rdx, method = rsi, frame = rbx, temp1 = rax, temp2 = rdi;
-+
-+ __ get_thread(thread);
-+ createAndPatchFrame(masm, thread, method, frame, temp1, temp2, rsp, 0, slow_case);
-+
-+ // set the newly created activationFrameOop as the current one and set its next pointer
-+ __ movptr(temp1, Address(thread, JavaThread::current_continuation_frame_offset()));
-+ __ movptr(Address(frame, activationFrameOopDesc::next_offset()), temp1); // frame->next = thread.current_continuation_frame
-+ __ movptr(Address(thread, JavaThread::current_continuation_frame_offset()), frame); // thread.current_continuation_frame = frame
-+
-+ // initialize the Continuation object (if it isn't null)
-+ __ testptr(cont, cont);
-+ __ jcc(Assembler::zero, no_continuation_object);
-+
-+ __ movptr(Address(cont, javax_stack_Continuation::get_data_offset()), frame); // continuation->data = frame
-+ __ movptr(temp1, Address(thread, JavaThread::threadObj_offset()));
-+ __ movptr(Address(cont, javax_stack_Continuation::get_thread_offset()), temp1); // continuation->thread = thread->threadObj
-+ __ store_check(cont); // store check (destroys cont)
-+
-+ __ bind(no_continuation_object);
-+
-+ __ movoop(rax, JNIHandles::make_local(javax_stack_Continuation::static_captured()));
-+ __ ret(0);
-+
-+ //////////////////////
-+ // everything else is handled by the C++ part of this method
-+ __ bind(slow_case);
-+}
-+
-+#ifndef VM_LITTLE_ENDIAN
-+x86 and big endian? This should never happen...
-+#endif
-+
-+void create_resumeContinuation_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) {
-+ assert(total_in_args == 2, "unexpected number of arguments");
-+ assert(in_sig_bt[0] == T_OBJECT && in_regs[0].first() == rcx->as_VMReg(), "unexpected argument type or register");
-+ assert(in_sig_bt[1] == T_OBJECT && in_regs[1].first() == rdx->as_VMReg(), "unexpected argument type or register");
-+ assert(ret_type == T_VOID, "unexpected return type");
-+
-+ /////////////////////////////////////////////////////////////////////////////////////
-+ /////////////////////////////////////////////////////////////////////////////////////
-+ // resume implementation
-+
-+ // rcx = Continuation object to be restored
-+ // rdx = return value passed to resume (Object)
-+
-+ Label slow_case;
-+ Label not_connected;
-+ Label resume_from_intermediate;
-+ Label step5_resume;
-+
-+ __ get_thread(rdi);
-+
-+ __ movptr(rax, Address(rdi, JavaThread::resume_common_frame_offset()));
-+ __ testptr(rax, rax);
-+ __ jcc(Assembler::notZero, resume_from_intermediate);
-+
-+
-+ // check if Continuation.CAPTURED was passed as value
-+ __ cmpoop(rdx, JNIHandles::make_local(javax_stack_Continuation::static_captured()));
-+ __ jcc(Assembler::equal, slow_case);
-+
-+ // check if the Continuation belongs to our thread
-+ __ movptr(rbx, Address(rcx, javax_stack_Continuation::get_thread_offset()));
-+ __ cmpptr(rbx, Address(rdi, JavaThread::threadObj_offset()));
-+ __ jcc(Assembler::notEqual, slow_case);
-+
-+ // check if the Continuation object is filled at all
-+ __ movptr(rax, Address(rcx, javax_stack_Continuation::get_data_offset()));
-+ __ testptr(rax, rax);
-+ __ jcc(Assembler::zero, slow_case);
-+
-+ __ movptr(rcx, rax);
-+
-+#ifdef ASSERT
-+ __ cmpptr(Address(rdi, JavaThread::current_continuation_frame_offset()), NULL);
-+ stop_if(masm, Assembler::equal, "NULL current activation object");
-+#endif
-+
-+ ////////////////////////////
-+ // Step 1:
-+ // * traverse the continuation until an empty activation object is encountered
-+ {
-+ Label loop;
-+ Label nonfilled_frame;
-+
-+ __ bind(loop);
-+ // check if the current frame is filled
-+ __ cmpb(Address(rax, activationFrameOopDesc::state_offset()), activationFrameOopDesc::_filled);
-+ __ jcc(Assembler::notEqual, nonfilled_frame);
-+ __ movptr(rax, Address(rax, activationFrameOopDesc::next_offset())); // rax = rax->next
-+
-+#ifdef ASSERT
-+ __ testptr(rax, rax);
-+ stop_if(masm, Assembler::zero, "NULL frame reached during resume step1");
-+#endif
-+ __ jmp(loop);
-+
-+ __ bind(nonfilled_frame);
-+
-+ // the non-filled frame we found needs to be on the stack
-+ __ cmpptr(Address(rax, activationFrameOopDesc::stack_pos_offset()), 0);
-+ __ jcc(Assembler::equal, not_connected);
-+
-+ // check if rax->fp > fp
-+ __ movptr(rbx, Address(rbp, 0));
-+ __ cmpptr(rbx, Address(rax, activationFrameOopDesc::stack_pos_offset()));
-+ __ jcc(Assembler::equal, step5_resume);
-+ }
-+
-+ __ movptr(Address(rdi, JavaThread::resume_continuation_frame_offset()), rcx);
-+ __ movptr(Address(rdi, JavaThread::resume_common_frame_offset()), rax);
-+ __ movptr(Address(rdi, JavaThread::resume_return_value_offset()), rdx);
-+
-+ __ movptr(rcx, 0);
-+ __ movptr(rbx, ExternalAddress(javax_stack_Continuation::get_save_nmethod_adr()));
-+ __ movptr(rbx, Address(rbx, nmethod::verified_entry_point_offset()));
-+ __ jmp(rbx);
-+
-+ __ bind(resume_from_intermediate);
-+// __ warn("resume from intermediate");
-+
-+ __ movptr(rcx, Address(rdi, JavaThread::resume_continuation_frame_offset()));
-+ __ movptr(rax, Address(rdi, JavaThread::resume_common_frame_offset()));
-+ __ movptr(rdx, Address(rdi, JavaThread::resume_return_value_offset()));
-+
-+ __ movptr(Address(rdi, JavaThread::resume_continuation_frame_offset()), 0);
-+ __ movptr(Address(rdi, JavaThread::resume_common_frame_offset()), 0);
-+ __ movptr(Address(rdi, JavaThread::resume_return_value_offset()), 0);
-+
-+ ////////////////////////////
-+ // Step 5: store the reverse pointers in stack_pos and reinstate the actual frames
-+ __ bind(step5_resume);
-+
-+ // we need to restore sender_sp if the current frame is an interpreted frame
-+ Label native_method;
-+ __ movptr(rsi, Address(rsp, 0));
-+ __ cmpptr(rsi, (int)Interpreter::code()->code_start());
-+ __ jcc(Assembler::below, native_method);
-+ __ cmpptr(rsi, (int)Interpreter::code()->code_end());
-+ __ jcc(Assembler::aboveEqual, native_method);
-+
-+// __ int3();
-+ // we need to restore the sender_sp if the current frame is interpreted
-+ __ movptr(rsp, Address(rbp, frame::interpreter_frame_sender_sp_offset * wordSize));
-+ __ movptr(rsi, Address(rbp, frame::return_addr_offset * wordSize));
-+ __ push(rsi);
-+ __ movptr(rsi, Address(rbp, frame::link_offset * wordSize));
-+ __ push(rsi);
-+ __ movptr(rbp, rsp);
-+
-+ __ bind(native_method);
-+
-+#ifdef ASSERT
-+ __ cmpptr(rax, Address(rdi, JavaThread::current_continuation_frame_offset()));
-+ stop_if(masm, Assembler::notEqual, "the current continuation frame is wrong during resume step 5");
-+#endif
-+ {
-+ // rax: the activationFrameOop for the activation frame below the current one
-+ // rcx: the top frame of the continuation that should be resumed
-+ Label reverse_loop;
-+ Label reverse_finished;
-+
-+ __ movptr(rsi, NULL);
-+ __ bind(reverse_loop);
-+ __ movptr(Address(rcx, activationFrameOopDesc::stack_pos_offset()), rsi);
-+ __ movptr(rsi, rcx);
-+ __ movptr(rcx, Address(rcx, activationFrameOopDesc::next_offset()));
-+ __ cmpptr(rcx, rax);
-+ __ jcc(Assembler::equal, reverse_finished);
-+ __ jmp(reverse_loop);
-+ __ bind(reverse_finished);
-+
-+ Label reinstate_loop;
-+ Label reinstate_finished;
-+ Label reinstate_interpreted;
-+
-+ __ movptr(rax, rsi);
-+
-+ __ bind(reinstate_loop);
-+
-+ __ cmpl(rbp, 0x1000);
-+ stop_if(masm, Assembler::below, "yikes!");
-+
-+ // now restore the frame in rax into the stackframe starting at rbp
-+
-+#ifdef ASSERT
-+ __ cmpb(Address(rax, activationFrameOopDesc::state_offset()), activationFrameOopDesc::_filled);
-+ stop_if(masm, Assembler::notEqual, "reached frame that isn't filled during resume step 5");
-+#endif
-+
-+ __ cmpb(Address(rax, activationFrameOopDesc::state_offset() + in_ByteSize(1)), activationFrameOopDesc::_compiled_type >> 8);
-+ __ jcc(Assembler::notEqual, reinstate_interpreted);
-+
-+ /////////
-+ // compiled frame
-+
-+ // rsp is not a valid stack pointer at this point!
-+/* __ movptr(rsp, rbp);
-+ __ warn("restoring compiled frame");
-+*/
-+ __ movptr(rsp, Address(rax, activationFrameOopDesc::method_offset()));
-+
-+ // copy the arguments into the last stack frame
-+ __ movl(rcx, Address(rsp, CodeBlob::frame_size_offset()));
-+
-+ __ lea(rdi, Address(rbp, 2 * BytesPerWord));
-+ __ lea(rsi, Address(rax, rcx, Address::times_4, activationFrameOopDesc::header_size() * HeapWordSize));
-+
-+ __ movl(rcx, Address(rsp, nmethod::stack_parameter_words_offset()));
-+ __ rep_mov();
-+
-+ // update frame pointer
-+ __ movl(rcx, Address(rsp, CodeBlob::frame_size_offset()));
-+ __ addl(rcx, rcx);
-+ __ addl(rcx, rcx);
-+ __ subl(rbp, rcx);
-+
-+ // copy the contents into the current stack frame
-+ __ lea(rdi, Address(rbp, 2 * BytesPerWord));
-+ __ lea(rsi, Address(rax, activationFrameOopDesc::header_size() * HeapWordSize));
-+
-+ __ movl(rcx, Address(rsp, CodeBlob::frame_size_offset()));
-+ __ subl(rcx, 2);
-+ __ rep_mov();
-+
-+ // update frame pointer and return address
-+ __ movl(Address(rbp, 0), rdi);
-+ __ movl(rdi, Address(rax, activationFrameOopDesc::pc_offset()));
-+ __ movl(Address(rbp, HeapWordSize), rdi);
-+
-+
-+ __ movptr(rbx, rax);
-+ __ movptr(rax, Address(rax, activationFrameOopDesc::stack_pos_offset()));
-+ __ movptr(rcx, Address(rbp, 0));
-+ __ movptr(Address(rbx, activationFrameOopDesc::stack_pos_offset()), rcx);
-+ __ testptr(rax,rax);
-+ __ jcc(Assembler::notZero, reinstate_loop);
-+ __ jmp(reinstate_finished);
-+
-+ __ bind(reinstate_interpreted);
-+
-+
-+ /////////
-+ // interpreted frame
-+// __ int3();
-+ // rsp is not a valid stack pointer at this point!
-+/* __ movptr(rsp, rbp);
-+ __ warn("restoring interpreted frame");
-+*/
-+ __ movptr(rsp, Address(rax, activationFrameOopDesc::method_offset()));
-+
-+
-+ __ movzwl(rcx, Address(rsp, methodOopDesc::size_of_locals_offset())); // get max_locals (this includes parameters)
-+ __ negl(rcx);
-+ __ lea(rbp, Address(rbp, rcx, Address::times_4)); // adjust rbp to the expanded stack frame
-+ __ negl(rcx);
-+
-+ __ lea(rbx, Address(rbp, rcx, Address::times_4, 2 * wordSize)); // compute the old stack pointer
-+ __ movptr(Address(rbp, frame::interpreter_frame_sender_sp_offset * wordSize), rbx); // store the old stack pointer (sender_sp)
-+
-+ __ movptr(rbx, Address(rbp, rcx, Address::times_4));
-+ __ movptr(Address(rbp, frame::link_offset * wordSize), rbx); // copy the link address to the new location
-+ __ movptr(rbx, Address(rbp, rcx, Address::times_4, HeapWordSize));
-+ __ movptr(Address(rbp, frame::return_addr_offset * wordSize), rbx); // copy the return address to the new location
-+ __ lea(rbx, Address(rbp, rcx, Address::times_4, 1 * HeapWordSize));
-+ __ movptr(Address(rbp, frame::interpreter_frame_locals_offset * wordSize), rbx); // store the pointer to the locals
-+
-+ // copy the locals (and reverse the order)
-+ __ lea(rdi, Address(rbp, 2 * HeapWordSize));
-+ __ lea(rsi, Address(rax, activationFrameOopDesc::header_size() * HeapWordSize));
-+ Label copy_loop;
-+ __ bind(copy_loop);
-+ __ movl(rbx, Address(rsi, 0));
-+ __ movl(Address(rdi, rcx, Address::times_4, -1 * 4), rbx);
-+ __ addptr(rsi, 4);
-+ __ decrementl(rcx, 1);
-+ __ jcc(Assembler::notZero, copy_loop);
-+
-+ __ movptr(Address(rbp, frame::interpreter_frame_method_offset * wordSize), rsp); // store the methodOop
-+ __ movptr(rbx, Address(rsp, methodOopDesc::method_data_offset()));
-+ __ movptr(Address(rbp, frame::interpreter_frame_mdx_offset * wordSize), rbx); // store the methodDataOop
-+ __ movptr(rbx, Address(rsp, methodOopDesc::constants_offset()));
-+ __ movptr(rbx, Address(rbx, constantPoolOopDesc::cache_offset_in_bytes()));
-+ __ movptr(Address(rbp, frame::interpreter_frame_cache_offset * wordSize), rbx); // store the constant pool cache
-+ __ lea(rbx, Address(rbp, frame::interpreter_frame_monitor_block_top_offset * wordSize));
-+ __ movptr(Address(rbp, frame::interpreter_frame_monitor_block_top_offset * wordSize), rbx); // store the monitor block size
-+ __ movptr(rbx, Address(rsp, methodOopDesc::const_offset())); // address of constMethodOop
-+ __ addptr(rbx, in_bytes(constMethodOopDesc::codes_offset())); // + code_offset()
-+ __ addptr(rbx, Address(rax, activationFrameOopDesc::bci_offset())); // + bci = bcp
-+ __ movptr(Address(rbp, frame::interpreter_frame_bcx_offset * wordSize), rbx); // store the bcp
-+
-+ // copy the expression stack
-+ __ movzwl(rcx, Address(rsp, methodOopDesc::size_of_locals_offset()));
-+ __ lea(rsi, Address(rax, rcx, Address::times_4, activationFrameOopDesc::header_size() * HeapWordSize));
-+ __ subl(rcx, Address(rax, activationFrameOopDesc::data_count_offset()));
-+ __ lea(rdi, Address(rbp, rcx, Address::times_4, frame::interpreter_frame_initial_sp_offset * wordSize));
-+ __ movptr(Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize), rdi); // store the last_sp
-+ __ movptr(Address(rdi, -2 * HeapWordSize), rbp); // store the link
-+ __ lea(rbp, Address(rdi, -2 * HeapWordSize));
-+ __ negl(rcx);
-+
-+
-+ Label copy_loop2;
-+ __ bind(copy_loop2);
-+ __ movl(rbx, Address(rsi, 0));
-+ __ movl(Address(rdi, rcx, Address::times_4, -1 * 4), rbx);
-+ __ addptr(rsi, 4);
-+ __ decrementl(rcx, 1);
-+ __ jcc(Assembler::notZero, copy_loop2);
-+
-+ __ movptr(rbx, Address(rax, activationFrameOopDesc::pc_offset()));
-+ __ movptr(Address(rbp, HeapWordSize), rbx);
-+
-+ __ movptr(rbx, rax);
-+ __ movptr(rax, Address(rax, activationFrameOopDesc::stack_pos_offset()));
-+ __ movptr(rcx, Address(rbp, 0));
-+ __ movptr(Address(rbx, activationFrameOopDesc::stack_pos_offset()), rcx);
-+
-+#ifdef ASSERT
-+ __ cmpptr(Address(rbp, HeapWordSize), 0x01000000);
-+ stop_if(masm, Assembler::greater, "suspicious pc");
-+#endif
-+
-+ __ testptr(rax,rax);
-+ __ jcc(Assembler::notZero, reinstate_loop);
-+
-+ __ bind(reinstate_finished);
-+
-+ __ movl(rax, rdx);
-+ __ movl(rsp, rbp);
-+
-+ // get_thread needs a valid sp!
-+ __ get_thread(rdi);
-+ __ movptr(Address(rdi, JavaThread::current_continuation_frame_offset()), rbx);
-+
-+ __ pop(rbp);
-+ __ ret(0);
-+ }
-+
-+ __ bind(not_connected);
-+ __ stop("unconnected continuation");
-+
-+ __ bind(slow_case);
-+}
-+
-+void create_storeFrameGeneric_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 save_result = false;
-+ if (ret_type == T_VOID) {
-+ assert(total_in_args == 0, "unexpected number of arguments");
-+ } else if (ret_type == T_LONG || ret_type == T_DOUBLE) {
-+ assert(total_in_args == 2, "unexpected number of arguments");
-+ } else if (ret_type == T_FLOAT) {
-+ assert(total_in_args == 1, "unexpected number of arguments");
-+ } else {
-+ assert(total_in_args == 1, "unexpected number of arguments");
-+ save_result = true;
-+ }
-+
-+ /////////////////////////////////////////////////////////////////////////////////////
-+ /////////////////////////////////////////////////////////////////////////////////////
-+ // This is the shortcut implementation of the "storeFrameGeneric" method which
-+ // fills the current activationFrameOop with data from the stack.
-+ // The simple assembler implementation can only deal with compiled activation frames.
-+
-+ // rax = retValue (possibly, depends on the return value of the last method)
-+ // IMPORTANT: retValue is an argument, so it should be in rcx, but it's left in rax for performance reasons
-+
-+ Label slow_case;
-+ Label create_new_frame;
-+ Label already_filled;
-+ Label patch_not_found;
-+ Label patching_end;
-+
-+#ifdef CONTINUATION_SLOW_CASE
-+ __ jmp(slow_case);
-+#endif
-+
-+ // get thread and current continuation frame
-+ Register thread = rbx, frame = rdx, temp1 = rcx;
-+ __ get_thread(thread);
-+ __ movptr(frame, Address(thread, JavaThread::current_continuation_frame_offset()));
-+
-+#ifdef ASSERT
-+ // let the slow implementation handle a NULL current activation frame
-+ __ testl(frame, frame);
-+ __ jcc(Assembler::zero, slow_case);
-+#endif
-+
-+ ////////////////////////////
-+ // fill the current activationFrameOop with data from the stack
-+
-+ // skip already filled frames
-+ __ cmpb(Address(frame, activationFrameOopDesc::state_offset()), activationFrameOopDesc::_filled);
-+ __ jcc(Assembler::equal, already_filled);
-+
-+ // the slow implementation will take care of non-nmethod frames
-+ __ cmpb(Address(frame, activationFrameOopDesc::state_offset() + in_ByteSize(1)), activationFrameOopDesc::_compiled_type >> 8);
-+ __ jcc(Assembler::notEqual, slow_case);
-+
-+#ifdef ASSERT
-+ // check that we're filling the correct frame
-+ __ cmpptr(rbp, Address(frame, activationFrameOopDesc::stack_pos_offset()));
-+ stop_if(masm, Assembler::notEqual, "trying to fill the wrong activationFrameOop");
-+#endif
-+
-+ // set the state to "filled"
-+ __ movl(Address(frame, activationFrameOopDesc::state_offset()), activationFrameOopDesc::_compiled_filled);
-+ __ movl(Address(frame, activationFrameOopDesc::stack_pos_offset()), 0);
-+
-+ // fill current continuation frame with data
-+ // load rcx with stack frame size + param size
-+ __ movptr(rsi, Address(frame, activationFrameOopDesc::method_offset()));
-+ __ movl(temp1, Address(rsi, nmethod::stack_parameter_words_offset()));
-+ __ addl(temp1, Address(rsi, nmethod::frame_size_offset()));
-+ __ lea(rdi, Address(frame, activationFrameOopDesc::header_size() * HeapWordSize));
-+ // we need the stack pointer without the return address (so we add one word)
-+ __ lea(rsi, Address(rsp, 1 * HeapWordSize));
-+ assert(temp1 == rcx, "counter register needed");
-+ __ rep_mov();
-+
-+ // we might have changed some pointers in the activationFrameOop
-+ __ movptr(temp1, frame);
-+ __ store_check(temp1);
-+
-+ ////////////////////////////
-+ // decide if a new activationFrameOop should be created
-+
-+ Register next_frame = rsi;
-+ // check if current_continuation_frame.next == NULL
-+ __ movptr(next_frame, Address(frame, activationFrameOopDesc::next_offset()));
-+ __ testptr(next_frame, next_frame);
-+ __ jcc(Assembler::zero, create_new_frame);
-+
-+ // check if current_continuation_frame.next.fp > fp
-+ __ movptr(temp1, Address(rbp, 0));
-+ __ cmpptr(temp1, Address(next_frame, activationFrameOopDesc::stack_pos_offset()));
-+ __ jcc(Assembler::below, create_new_frame);
-+
-+ // fastest case: use existing continuation frame
-+ __ movptr(Address(thread, JavaThread::current_continuation_frame_offset()), next_frame);
-+ __ jmp(patching_end);
-+ next_frame = noreg;
-+
-+ ////////////////////////////
-+ // create a new nmethod activationFrameOop
-+
-+ __ bind(create_new_frame);
-+
-+ Register method = rsi, temp2 = rdi;
-+ createAndPatchFrame(masm, thread, method, frame, temp1, temp2, rbp, HeapWordSize, slow_case);
-+
-+ // prepare the new frame pt3: current activation object
-+ __ movl(temp1, Address(thread, JavaThread::current_continuation_frame_offset())); // temp1 = thread.current_continuation_frame
-+ __ movl(Address(thread, JavaThread::current_continuation_frame_offset()), frame); // thread.current_continuation_frame = frame
-+
-+ // prepare the new frame pt4: next
-+ __ movl(temp2, Address(temp1, activationFrameOopDesc::next_offset()));
-+ __ movl(Address(frame, activationFrameOopDesc::next_offset()), temp2); // frame->next = thread.current_continuation_frame->next
-+ __ movl(Address(temp1, activationFrameOopDesc::next_offset()), frame); // thread.current_continuation_frame->next = frame
-+
-+ // general operations for all codeblob types...
-+ __ bind(patching_end);
-+
-+
-+ test_continuation_resume(masm, thread, temp1);
-+
-+ ////////////////////////////
-+ // out-of-order case: frame already filled
-+
-+ __ bind(already_filled);
-+ __ movptr(Address(frame, activationFrameOopDesc::stack_pos_offset()), NULL);
-+ __ movptr(temp1, Address(frame, activationFrameOopDesc::next_offset()));
-+ __ movptr(Address(thread, JavaThread::current_continuation_frame_offset()), temp1);
-+ __ jmp(patching_end);
-+
-+ ////////////////////////////
-+ // switch to the complete (C++) implementation
-+ __ bind(slow_case);
-+
-+ // move the retValue argument where the native method stub expects it
-+ if (save_result) {
-+ __ movl(rcx, rax);
-+ }
-+}
-+
-+void create_startDelimited_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) {
-+ assert(total_in_args == 2, "unexpected number of arguments");
-+ assert(ret_type == T_OBJECT, "unexpected return type");
-+ assert(in_sig_bt[0] == T_OBJECT, "unexpected argument type");
-+ assert(in_regs[0].first() == rcx->as_VMReg(), "unexpected argument register");
-+ assert(in_sig_bt[1] == T_OBJECT, "unexpected argument type");
-+ assert(in_regs[1].first() == rdx->as_VMReg(), "unexpected argument register");
-+
-+ Label slow_case;
-+
-+#ifdef CONTINUATION_SLOW_CASE
-+ __ jmp(slow_case);
-+#endif
-+
-+ Register temp1 = rsi;
-+ __ enter();
-+ // -2 because return address is already present and so is the saved rbp
-+ __ subptr(rsp, (stack_slots - 2) * wordSize);
-+
-+ klassOop k = SystemDictionary::Continuation_klass();
-+ methodOop method = instanceKlass::cast(k)->find_method(vmSymbols::startDelimitedInternal_name(), vmSymbols::startDelimited_signature());
-+ assert(method != NULL, "missing method startDelimitedInternal");
-+
-+ __ movoop(rbx, JNIHandles::make_local(method));
-+ __ movptr(temp1, Address(rbx, methodOopDesc::from_compiled_offset()));
-+
-+#ifdef ASSERT
-+ __ cmpptr(temp1, 0x01000000);
-+ stop_if(masm, Assembler::greater, "suspicious method entry");
-+#endif
-+
-+ __ call(temp1);
-+
-+ OopMap* map = new OopMap(stack_slots, 0);
-+ oop_maps->add_gc_map(__ offset(), map);
-+
-+ AddressLiteral polling_page(os::get_polling_page() + (SafepointPollOffset % os::vm_page_size()), relocInfo::poll_return_type);
-+ __ test32(rax, polling_page);
-+
-+ Register thread = rdi;
-+ Register frame = rdx;
-+
-+ __ get_thread(thread);
-+ __ movptr(frame, Address(thread, JavaThread::current_continuation_frame_offset()));
-+
-+#ifdef ASSERT
-+ __ cmpl(Address(frame, activationFrameOopDesc::state_offset()), activationFrameOopDesc::_dummy_invalid);
-+ stop_if(masm, Assembler::notEqual, "invalid frame after continueDelimited");
-+#endif
-+
-+
-+ __ movptr(temp1, Address(frame, activationFrameOopDesc::next_offset()));
-+ __ movptr(Address(frame, activationFrameOopDesc::next_offset()), NULL);
-+ __ movptr(Address(thread, JavaThread::current_continuation_frame_offset()), temp1);
-+ __ movptr(temp1, frame);
-+ __ store_check(temp1);
-+
-+ __ movl(Address(frame, activationFrameOopDesc::state_offset()), activationFrameOopDesc::_dummy_delimited);
-+ __ movb(Address(frame, activationFrameOopDesc::in_use_offset()), 0);
-+ __ movptr(Address(frame, activationFrameOopDesc::stack_pos_offset()), 0);
-+
-+ __ leave();
-+ __ ret(0);
-+
-+ __ bind(slow_case);
-+}
-+
-+void create_continueDelimited_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) {
-+ assert(total_in_args == 2, "unexpected number of arguments");
-+ assert(ret_type == T_OBJECT, "unexpected return type");
-+ assert(in_sig_bt[0] == T_OBJECT, "unexpected argument type");
-+ assert(in_regs[0].first() == rcx->as_VMReg(), "unexpected argument register");
-+ assert(in_sig_bt[1] == T_OBJECT, "unexpected argument type");
-+ assert(in_regs[1].first() == rdx->as_VMReg(), "unexpected argument register");
-+
-+ Register continuation = rcx;
-+ Register thread = rdi;
-+ Register temp1 = rsi;
-+
-+ Label slow_case;
-+
-+#ifdef CONTINUATION_SLOW_CASE
-+ __ jmp(slow_case);
-+#endif
-+
-+ __ get_thread(thread);
-+
-+ // check if the Continuation belongs to our thread
-+ __ movptr(temp1, Address(continuation, javax_stack_Continuation::get_thread_offset()));
-+ __ cmpptr(temp1, Address(thread, JavaThread::threadObj_offset()));
-+ __ jcc(Assembler::notEqual, slow_case);
-+
-+ Register frame = rbx;
-+ // check if the Continuation object is filled at all
-+ __ movptr(frame, Address(continuation, javax_stack_Continuation::get_data_offset()));
-+ __ testptr(frame, frame);
-+ __ jcc(Assembler::zero, slow_case);
-+
-+ Label loop, loop_exit;
-+ __ bind(loop);
-+ __ cmpptr(Address(frame, activationFrameOopDesc::next_offset()), NULL);
-+ __ jcc(Assembler::equal, loop_exit);
-+ __ movptr(frame, Address(frame, activationFrameOopDesc::next_offset()));
-+ __ jmp(loop);
-+
-+ __ bind(loop_exit);
-+ __ cmpl(Address(frame, activationFrameOopDesc::state_offset()), activationFrameOopDesc::_dummy_delimited);
-+ __ jcc(Assembler::notEqual, slow_case);
-+
-+ __ cmpb(Address(frame, activationFrameOopDesc::in_use_offset()), 0);
-+ __ jcc(Assembler::notEqual, slow_case);
-+
-+ __ movptr(temp1, Address(thread, JavaThread::current_continuation_frame_offset()));
-+ __ movptr(Address(frame, activationFrameOopDesc::next_offset()), temp1);
-+ __ movptr(temp1, frame);
-+ __ store_check(temp1);
-+ __ movptr(Address(thread, JavaThread::current_continuation_frame_offset()), frame);
-+
-+// __ int3();
-+ // Generate a new frame for the wrapper.
-+ __ enter();
-+ // -2 because return address is already present and so is the saved rbp
-+ __ subptr(rsp, (stack_slots - 2) * wordSize);
-+
-+ __ movb(Address(frame, activationFrameOopDesc::in_use_offset()), 1);
-+ __ movptr(Address(frame, activationFrameOopDesc::stack_pos_offset()), rbp);
-+
-+ klassOop k = SystemDictionary::Continuation_klass();
-+ methodOop method = instanceKlass::cast(k)->find_method(vmSymbols::continueDelimitedInternal_name(), vmSymbols::continueDelimited_signature());
-+ assert(method != NULL, "missing method continueDelimitedInternal");
-+
-+// __ int3();
-+ __ movoop(rbx, JNIHandles::make_local(method));
-+ __ movptr(temp1, Address(rbx, methodOopDesc::from_compiled_offset()));
-+
-+#ifdef ASSERT
-+ __ cmpptr(temp1, 0x01000000);
-+ stop_if(masm, Assembler::greater, "suspicious method entry");
-+#endif
-+
-+ __ call(temp1);
-+
-+ OopMap* map = new OopMap(stack_slots, 0);
-+ oop_maps->add_gc_map(__ offset(), map);
-+
-+ // Note: we do not need to round double result; float result has the right precision
-+ // the poll sets the condition code, but no data registers
-+ AddressLiteral polling_page(os::get_polling_page() + (SafepointPollOffset % os::vm_page_size()), relocInfo::poll_return_type);
-+
-+ // NOTE: the requires that the polling page be reachable else the reloc
-+ // goes to the movq that loads the address and not the faulting instruction
-+ // which breaks the signal handler code
-+ __ test32(rax, polling_page);
-+
-+
-+ __ get_thread(thread);
-+ __ movptr(frame, Address(thread, JavaThread::current_continuation_frame_offset()));
-+
-+#ifdef ASSERT
-+ __ cmpl(Address(frame, activationFrameOopDesc::state_offset()), activationFrameOopDesc::_dummy_delimited);
-+ stop_if(masm, Assembler::notEqual, "invalid frame after continueDelimited");
-+ __ cmpb(Address(frame, activationFrameOopDesc::in_use_offset()), 0);
-+ stop_if(masm, Assembler::equal, "in_use cannot be false after continueDelimited");
-+#endif
-+
-+ __ movptr(temp1, Address(frame, activationFrameOopDesc::next_offset()));
-+ __ movptr(Address(frame, activationFrameOopDesc::next_offset()), NULL);
-+ __ movptr(Address(thread, JavaThread::current_continuation_frame_offset()), temp1);
-+ __ movptr(temp1, frame);
-+ __ store_check(temp1);
-+
-+ __ movb(Address(frame, activationFrameOopDesc::in_use_offset()), 0);
-+ __ movptr(Address(frame, activationFrameOopDesc::stack_pos_offset()), 0);
-+
-+ __ leave();
-+ __ ret(0);
-+
-+ __ bind(slow_case);
-+}
-+
-diff --git a/src/cpu/x86/vm/templateInterpreter_x86_32.cpp b/src/cpu/x86/vm/templateInterpreter_x86_32.cpp
---- a/src/cpu/x86/vm/templateInterpreter_x86_32.cpp
-+++ b/src/cpu/x86/vm/templateInterpreter_x86_32.cpp
-@@ -159,6 +159,34 @@
- TosState incoming_state = state;
-
- Label interpreter_entry;
-+ BasicType type;
-+ switch(incoming_state) {
-+ case btos: type = T_BYTE; break;
-+ case ctos: type = T_CHAR; break;
-+ case stos: type = T_SHORT; break;
-+ case itos: type = T_INT; break;
-+ case ltos: type = T_LONG; break;
-+ case ftos: type = T_FLOAT; break;
-+ case dtos: type = T_DOUBLE; break;
-+ case atos: type = T_OBJECT; break;
-+ case vtos: type = T_VOID; break;
-+ default:
-+ ShouldNotReachHere();
-+ }
-+ __ jmp(interpreter_entry, relocInfo::none);
-+
-+ address continuation_entry = __ pc();
-+ // this acts as a trampoline to the generic nmethod frame copying stub
-+ __ movl(rcx, rax);
-+ __ movptr(rbx, AddressLiteral(javax_stack_Continuation::get_store_frames_nmethod_adr(type), relocInfo::none));
-+ __ movptr(rbx, Address(rbx, nmethod::verified_entry_point_offset()));
-+ __ call(rbx);
-+ __ jmp(interpreter_entry, relocInfo::none);
-+
-+ __ a_long((int)continuation_entry);
-+ __ a_long(Interpreter::return_sentinel2);
-+ __ a_long((int)0);
-+
- address compiled_entry = __ pc();
-
- #ifdef COMPILER2
-@@ -178,8 +206,18 @@
- }
-
- __ jmp(interpreter_entry, relocInfo::none);
-+
-+ address continuation_entry2 = __ pc();
-+ // this acts as a trampoline to the generic nmethod frame copying stub
-+ __ movl(rcx, rax);
-+ __ movptr(rbx, AddressLiteral(javax_stack_Continuation::get_store_frames_nmethod_adr(type), relocInfo::none));
-+ __ movptr(rbx, Address(rbx, nmethod::verified_entry_point_offset()));
-+ __ call(rbx);
-+ __ jmp(interpreter_entry, relocInfo::none);
-+
- // emit a sentinel we can test for when converting an interpreter
- // entry point to a compiled entry point.
-+ __ a_long((int)continuation_entry2);
- __ a_long(Interpreter::return_sentinel);
- __ a_long((int)compiled_entry);
- address entry = __ pc();
-diff --git a/src/share/vm/c1/c1_CodeStubs.hpp b/src/share/vm/c1/c1_CodeStubs.hpp
---- a/src/share/vm/c1/c1_CodeStubs.hpp
-+++ b/src/share/vm/c1/c1_CodeStubs.hpp
-@@ -582,3 +582,25 @@
-
- #endif // SERIALGC
- //////////////////////////////////////////////////////////////////////////////////////////
-+
-+
-+class ContinuationStub: public CodeStub {
-+private:
-+ LIR_OpJavaCall* _op;
-+ CodeEmitInfo* _info;
-+ int _pc;
-+
-+public:
-+ ContinuationStub(LIR_OpJavaCall* op);
-+
-+ virtual void emit_code(LIR_Assembler *e);
-+ virtual CodeEmitInfo* info() const { return _op->info(); }
-+ virtual void visit(LIR_OpVisitState* visitor) {
-+ // don't pass in the code emit info since it's processed in the fast path
-+ visitor->do_slow_case(_info);
-+ }
-+ void set_pc(int pc) { _pc = pc; }
-+#ifndef PRODUCT
-+ virtual void print_name(outputStream* out) const { out->print("ContinuationStub"); }
-+#endif // PRODUCT
-+};
-diff --git a/src/share/vm/c1/c1_Compilation.cpp b/src/share/vm/c1/c1_Compilation.cpp
---- a/src/share/vm/c1/c1_Compilation.cpp
-+++ b/src/share/vm/c1/c1_Compilation.cpp
-@@ -307,9 +307,11 @@
- in_bytes(_frame_map->sp_offset_for_orig_pc()),
- code(),
- in_bytes(frame_map()->framesize_in_bytes()) / sizeof(intptr_t),
-+ frame_map()->incoming_arguments()->reserved_stack_slots(),
- debug_info_recorder()->_oopmaps,
- exception_handler_table(),
- implicit_exception_table(),
-+ continuation_pc_table(),
- compiler(),
- _env->comp_level(),
- needs_debug_information(),
-diff --git a/src/share/vm/c1/c1_Compilation.hpp b/src/share/vm/c1/c1_Compilation.hpp
---- a/src/share/vm/c1/c1_Compilation.hpp
-+++ b/src/share/vm/c1/c1_Compilation.hpp
-@@ -78,6 +78,7 @@
- ExceptionInfoList* _exception_info_list;
- ExceptionHandlerTable _exception_handler_table;
- ImplicitExceptionTable _implicit_exception_table;
-+ ContinuationPcTable _continuation_pc_table;
- LinearScan* _allocator;
- CodeOffsets _offsets;
- CodeBuffer _code;
-@@ -114,6 +115,8 @@
-
- static Compilation* current_compilation() { return _compilation; }
-
-+ ContinuationPcTable* continuation_pc_table() { return &_continuation_pc_table; }
-+
- // accessors
- ciEnv* env() const { return _env; }
- AbstractCompiler* compiler() const { return _compiler; }
-diff --git a/src/share/vm/c1/c1_GraphBuilder.cpp b/src/share/vm/c1/c1_GraphBuilder.cpp
---- a/src/share/vm/c1/c1_GraphBuilder.cpp
-+++ b/src/share/vm/c1/c1_GraphBuilder.cpp
-@@ -2987,7 +2987,10 @@
- // Clear out any existing inline bailout condition
- clear_inline_bailout();
-
-- if (callee->should_exclude()) {
-+ if (scope()->method()->create_continuation_stubs() != callee->create_continuation_stubs()) {
-+ // we need clean boundaries between continuable and non-continuable methods
-+ INLINE_BAILOUT("mismatch in @Continuable")
-+ } else if (callee->should_exclude()) {
- // callee is excluded
- INLINE_BAILOUT("excluded by CompilerOracle")
- } else if (!callee->can_be_compiled()) {
-@@ -3046,6 +3049,11 @@
- cantrap = false;
- break;
-
-+ case vmIntrinsics::_saveContinuation :
-+ case vmIntrinsics::_resumeContinuation :
-+ INLINE_BAILOUT("Continuation.save and Continuation.resume cannot be inlined");
-+ break;
-+
- case vmIntrinsics::_dabs : // fall through
- case vmIntrinsics::_dsqrt : // fall through
- case vmIntrinsics::_dsin : // fall through
-diff --git a/src/share/vm/c1/c1_IR.hpp b/src/share/vm/c1/c1_IR.hpp
---- a/src/share/vm/c1/c1_IR.hpp
-+++ b/src/share/vm/c1/c1_IR.hpp
-@@ -270,7 +270,6 @@
- int _id;
-
- FrameMap* frame_map() const { return scope()->compilation()->frame_map(); }
-- Compilation* compilation() const { return scope()->compilation(); }
-
- public:
-
-@@ -293,6 +292,7 @@
- CodeEmitInfo(CodeEmitInfo* info, bool lock_stack_only = false);
-
- // accessors
-+ Compilation* compilation() const { return scope()->compilation(); }
- OopMap* oop_map() { return _oop_map; }
- ciMethod* method() const { return _scope->method(); }
- IRScope* scope() const { return _scope; }
-diff --git a/src/share/vm/c1/c1_LIRAssembler.cpp b/src/share/vm/c1/c1_LIRAssembler.cpp
---- a/src/share/vm/c1/c1_LIRAssembler.cpp
-+++ b/src/share/vm/c1/c1_LIRAssembler.cpp
-@@ -448,6 +448,13 @@
- restore_SP();
- }
-
-+ if (compilation()->method()->create_continuation_stubs()) {
-+ ContinuationStub* stub = new ContinuationStub(op);
-+ _masm->bind(*stub->continuation());
-+ stub->set_pc(code_offset());
-+ emit_code_stub(stub);
-+ }
-+
- #if defined(X86) && defined(TIERED)
- // C2 leave fpu stack dirty clean it
- if (UseSSE < 2) {
-diff --git a/src/share/vm/c1/c1_LIRAssembler.hpp b/src/share/vm/c1/c1_LIRAssembler.hpp
---- a/src/share/vm/c1/c1_LIRAssembler.hpp
-+++ b/src/share/vm/c1/c1_LIRAssembler.hpp
-@@ -44,8 +44,6 @@
- void check_no_unbound_labels();
- #endif
-
-- FrameMap* frame_map() const { return _frame_map; }
--
- void set_current_block(BlockBegin* b) { _current_block = b; }
- BlockBegin* current_block() const { return _current_block; }
-
-@@ -109,6 +107,7 @@
- public:
- LIR_Assembler(Compilation* c);
- ~LIR_Assembler();
-+ FrameMap* frame_map() const { return _frame_map; }
- C1_MacroAssembler* masm() const { return _masm; }
- Compilation* compilation() const { return _compilation; }
- ciMethod* method() const { return compilation()->method(); }
-diff --git a/src/share/vm/ci/ciEnv.cpp b/src/share/vm/ci/ciEnv.cpp
---- a/src/share/vm/ci/ciEnv.cpp
-+++ b/src/share/vm/ci/ciEnv.cpp
-@@ -866,9 +866,11 @@
- int orig_pc_offset,
- CodeBuffer* code_buffer,
- int frame_words,
-+ int stack_param_words,
- OopMapSet* oop_map_set,
- ExceptionHandlerTable* handler_table,
- ImplicitExceptionTable* inc_table,
-+ ContinuationPcTable* continuation_pc_table,
- AbstractCompiler* compiler,
- int comp_level,
- bool has_debug_info,
-@@ -942,8 +944,8 @@
- offsets,
- orig_pc_offset,
- debug_info(), dependencies(), code_buffer,
-- frame_words, oop_map_set,
-- handler_table, inc_table,
-+ frame_words, stack_param_words, oop_map_set,
-+ handler_table, inc_table, continuation_pc_table,
- compiler, comp_level);
-
- // Free codeBlobs
-diff --git a/src/share/vm/ci/ciEnv.hpp b/src/share/vm/ci/ciEnv.hpp
---- a/src/share/vm/ci/ciEnv.hpp
-+++ b/src/share/vm/ci/ciEnv.hpp
-@@ -282,9 +282,11 @@
- int orig_pc_offset,
- CodeBuffer* code_buffer,
- int frame_words,
-+ int stack_param_words,
- OopMapSet* oop_map_set,
- ExceptionHandlerTable* handler_table,
- ImplicitExceptionTable* inc_table,
-+ ContinuationPcTable* continuation_pc_table,
- AbstractCompiler* compiler,
- int comp_level,
- bool has_debug_info = true,
-diff --git a/src/share/vm/ci/ciMethod.cpp b/src/share/vm/ci/ciMethod.cpp
---- a/src/share/vm/ci/ciMethod.cpp
-+++ b/src/share/vm/ci/ciMethod.cpp
-@@ -56,6 +56,8 @@
- _liveness = NULL;
- _bcea = NULL;
- _method_blocks = NULL;
-+
-+ _create_continuation_stubs = h_m()->constMethod()->is_continuable();
- #ifdef COMPILER2
- _flow = NULL;
- #endif // COMPILER2
-diff --git a/src/share/vm/ci/ciMethod.hpp b/src/share/vm/ci/ciMethod.hpp
---- a/src/share/vm/ci/ciMethod.hpp
-+++ b/src/share/vm/ci/ciMethod.hpp
-@@ -65,6 +65,8 @@
- bool _is_compilable;
- bool _can_be_statically_bound;
-
-+ bool _create_continuation_stubs;
-+
- // Lazy fields, filled in on demand
- address _code;
- ciExceptionHandler** _exception_handlers;
-@@ -245,6 +247,7 @@
- bool is_accessor () const;
- bool is_initializer () const;
- bool can_be_statically_bound() const { return _can_be_statically_bound; }
-+ bool create_continuation_stubs() const { return _create_continuation_stubs; }
-
- // Print the bytecodes of this method.
- void print_codes_on(outputStream* st);
-diff --git a/src/share/vm/classfile/classFileParser.cpp b/src/share/vm/classfile/classFileParser.cpp
---- a/src/share/vm/classfile/classFileParser.cpp
-+++ b/src/share/vm/classfile/classFileParser.cpp
-@@ -1707,6 +1707,7 @@
- m->set_max_stack(max_stack);
- m->set_max_locals(max_locals);
- m->constMethod()->set_stackmap_data(stackmap_data());
-+ m->constMethod()->set_continuable(constMethodOopDesc::_not_continuable);
-
- /**
- * The exception_table field is the flag used to indicate
-@@ -1842,6 +1843,42 @@
- "Method handle invokers must be defined internally to the VM", nullHandle);
- }
-
-+ // parse the annotations to get the "Continuable" attribute
-+ if ((*method_annotations)() != NULL) {
-+ AnnotationParser parser(*method_annotations, cp);
-+
-+/* if (!parser.verify(THREAD)) {
-+
-+ ShouldNotReachHere();
-+ } */
-+
-+ symbolOop klass_name = vmSymbols::javax_stack_Continuable_signature();
-+ Annotation ann = parser.first_annotation();
-+ for (int i=0; i<parser.annotation_count(); i++) {
-+ if (ann.get_type_name() == klass_name) {
-+ if (ann.value_count() == 0) {
-+ // the ContinuableAccess defaults to HIDDEN
-+ m->constMethod()->set_continuable(constMethodOopDesc::_continuable_hidden);
-+ } else if (ann.value_count() > 1) {
-+ ShouldNotReachHere();
-+ } else {
-+ ElementValuePair value = ann.first_value();
-+ if (value.value().enum_const_name()->equals("HIDDEN", 6))
-+ m->constMethod()->set_continuable(constMethodOopDesc::_continuable_hidden);
-+ else if (value.value().enum_const_name()->equals("READONLY", 8))
-+ m->constMethod()->set_continuable(constMethodOopDesc::_continuable_readonly);
-+ else if (value.value().enum_const_name()->equals("READWRITE", 9))
-+ m->constMethod()->set_continuable(constMethodOopDesc::_continuable_readwrite);
-+ else {
-+ ShouldNotReachHere();
-+ }
-+ }
-+ break;
-+ }
-+ ann = parser.next_annotation(ann, THREAD);
-+ }
-+ }
-+
- return m;
- }
-
-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
-@@ -2713,6 +2713,56 @@
- }
- }
-
-+/* stack manipulation */
-+
-+int javax_stack_Continuation::data_offset = 0;
-+int javax_stack_Continuation::thread_offset = 0;
-+int javax_stack_Continuation::static_captured_offset = 0;
-+nmethod* javax_stack_Continuation::store_frames_nmethods[T_ILLEGAL+1];
-+nmethod* javax_stack_Continuation::resume_nmethod;
-+nmethod* javax_stack_Continuation::save_nmethod;
-+nmethod* javax_stack_Continuation::unwind_nmethod;
-+
-+void javax_stack_Continuation::compute_offsets() {
-+ klassOop k = SystemDictionary::Continuation_klass();
-+ if (k != NULL) {
-+ compute_offset(data_offset, k, vmSymbols::data_name(), vmSymbols::object_signature());
-+ compute_offset(thread_offset, k, vmSymbols::thread_name(), vmSymbols::thread_signature());
-+ compute_offset(static_captured_offset, k, vmSymbols::captured_name(), vmSymbols::object_signature());
-+ }
-+ memset(store_frames_nmethods, NULL, sizeof(store_frames_nmethods));
-+ resume_nmethod = NULL;
-+ save_nmethod = NULL;
-+}
-+
-+activationFrameOop javax_stack_Continuation::data(oop obj) {
-+ return (activationFrameOop)obj->obj_field(data_offset);
-+}
-+
-+void javax_stack_Continuation::set_data(oop obj, activationFrameOop value) {
-+ obj->obj_field_put(data_offset, (oop)value);
-+}
-+
-+oop javax_stack_Continuation::thread(oop obj) {
-+ return obj->obj_field(thread_offset);
-+}
-+
-+void javax_stack_Continuation::set_thread(oop obj, oop value) {
-+ obj->obj_field_put(thread_offset, (oop)value);
-+}
-+
-+oop javax_stack_Continuation::static_captured() {
-+ instanceKlass* ik = instanceKlass::cast(SystemDictionary::Continuation_klass());
-+ char *addr = (((char *)ik->start_of_static_fields()) + static_captured_offset - ik->offset_of_static_fields());
-+ if (UseCompressedOops) {
-+ return oopDesc::load_decode_heap_oop((narrowOop *)addr);
-+ } else {
-+ return oopDesc::load_decode_heap_oop((oop*)addr);
-+ }
-+}
-+
-+
-+
- void java_util_concurrent_locks_AbstractOwnableSynchronizer::initialize(TRAPS) {
- if (_owner_offset != 0) return;
-
-@@ -2836,6 +2886,8 @@
-
- // generated interpreter code wants to know about the offsets we just computed:
- AbstractAssembler::update_delayed_values();
-+
-+ javax_stack_Continuation::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
-@@ -1255,6 +1255,54 @@
- static oop get_owner_threadObj(oop obj);
- };
-
-+class javax_stack_Continuation: AllStatic {
-+private:
-+ // Note that to reduce dependencies on the JDK we compute these
-+ // offsets at run-time.
-+ static int data_offset;
-+ static int thread_offset;
-+ static int static_captured_offset;
-+ static nmethod* store_frames_nmethods[T_ILLEGAL+1];
-+ static nmethod* resume_nmethod;
-+ static nmethod* save_nmethod;
-+ static nmethod* unwind_nmethod;
-+
-+ static void compute_offsets();
-+
-+public:
-+ // Accessors
-+ static activationFrameOop data(oop obj);
-+ static void set_data(oop obj, activationFrameOop value);
-+
-+ static oop thread(oop obj);
-+ static void set_thread(oop obj, oop value);
-+
-+ static oop static_captured();
-+
-+ static int get_data_offset() { return data_offset; }
-+ static int get_thread_offset() { return thread_offset; }
-+
-+ static void set_store_frames_nmethod(BasicType type, nmethod* m) { store_frames_nmethods[type] = m; }
-+ static nmethod* get_store_frames_nmethod(BasicType type) { return store_frames_nmethods[type]; }
-+ static address get_store_frames_nmethod_adr(BasicType type) { return (address)(store_frames_nmethods + type); }
-+
-+ static void set_resume_nmethod(nmethod* m) { resume_nmethod = m; }
-+ static nmethod* get_resume_nmethod() { return resume_nmethod; }
-+ static address get_resume_nmethod_adr() { return (address)(&resume_nmethod); }
-+
-+ static void set_save_nmethod(nmethod* m) { save_nmethod = m; }
-+ static nmethod* get_save_nmethod() { return save_nmethod; }
-+ static address get_save_nmethod_adr() { return (address)(&save_nmethod); }
-+
-+ static void set_unwind_nmethod(nmethod* m) { unwind_nmethod = m; }
-+ static nmethod* get_unwind_nmethod() { return unwind_nmethod; }
-+ static address get_unwind_nmethod_adr() { return (address)(&unwind_nmethod); }
-+
-+ // 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
-@@ -170,6 +170,9 @@
- 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(Continuation_klass, javax_stack_Continuation, 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
-@@ -355,6 +355,10 @@
- template(void_long_signature, "()J") \
- template(void_float_signature, "()F") \
- template(void_double_signature, "()D") \
-+ template(bool_bool_signature, "(Z)Z") \
-+ template(byte_byte_signature, "(B)B") \
-+ template(char_char_signature, "(C)C") \
-+ template(short_short_signature, "(S)S") \
- template(int_void_signature, "(I)V") \
- template(int_int_signature, "(I)I") \
- template(int_bool_signature, "(I)Z") \
-@@ -364,6 +368,7 @@
- template(int_float_signature, "(I)F") \
- template(long_int_signature, "(J)I") \
- template(long_long_signature, "(J)J") \
-+ template(float_float_signature, "(F)F") \
- template(long_double_signature, "(J)D") \
- template(byte_signature, "B") \
- template(char_signature, "C") \
-@@ -375,10 +380,14 @@
- template(bool_signature, "Z") \
- template(void_signature, "V") \
- template(byte_array_signature, "[B") \
-+ template(int_array_signature, "[I") \
-+ template(bool_array_signature, "[Z") \
- template(char_array_signature, "[C") \
-+ template(object_array_signature, "[Ljava/lang/Object;") \
- template(object_void_signature, "(Ljava/lang/Object;)V") \
- template(object_int_signature, "(Ljava/lang/Object;)I") \
- template(object_boolean_signature, "(Ljava/lang/Object;)Z") \
-+ template(object_object_signature, "(Ljava/lang/Object;)Ljava/lang/Object;") \
- template(string_void_signature, "(Ljava/lang/String;)V") \
- template(string_int_signature, "(Ljava/lang/String;)I") \
- template(throwable_void_signature, "(Ljava/lang/Throwable;)V") \
-@@ -489,6 +498,13 @@
- template(serializePropertiesToByteArray_signature, "()[B") \
- template(serializeAgentPropertiesToByteArray_name, "serializeAgentPropertiesToByteArray") \
- template(classRedefinedCount_name, "classRedefinedCount") \
-+ \
-+ /* stack manipulation */ \
-+ template(javax_stack_Continuation, "javax/stack/Continuation") \
-+ template(javax_stack_Continuable_signature, "Ljavax/stack/Continuable;") \
-+ template(data_name, "data") \
-+ template(thread_name, "thread") \
-+ template(captured_name, "CAPTURED") \
- /*end*/
-
-
-@@ -597,9 +613,8 @@
- do_intrinsic(_arraycopy, java_lang_System, arraycopy_name, arraycopy_signature, F_S) \
- do_name( arraycopy_name, "arraycopy") \
- do_signature(arraycopy_signature, "(Ljava/lang/Object;ILjava/lang/Object;II)V") \
-- do_intrinsic(_isInterrupted, java_lang_Thread, isInterrupted_name, isInterrupted_signature, F_R) \
-+ do_intrinsic(_isInterrupted, java_lang_Thread, isInterrupted_name, bool_bool_signature, F_R) \
- do_name( isInterrupted_name, "isInterrupted") \
-- do_signature(isInterrupted_signature, "(Z)Z") \
- do_intrinsic(_currentThread, java_lang_Thread, currentThread_name, currentThread_signature, F_S) \
- do_name( currentThread_name, "currentThread") \
- do_signature(currentThread_signature, "()Ljava/lang/Thread;") \
-@@ -825,6 +840,51 @@
- do_name( prefetchReadStatic_name, "prefetchReadStatic") \
- do_intrinsic(_prefetchWriteStatic, sun_misc_Unsafe, prefetchWriteStatic_name, prefetch_signature, F_SN) \
- do_name( prefetchWriteStatic_name, "prefetchWriteStatic") \
-+ \
-+ /* stack manipulation intrinsic (excluded from compilation) */ \
-+ do_intrinsic(_doCopyStackContext, sun_misc_Unsafe, doCopyStackContext_name, doCSC_signature, F_R) \
-+ do_name( doCopyStackContext_name, "doCopyStackContext") \
-+ do_signature( doCSC_signature, "(Ljava/lang/Runnable;Ljava/lang/Object;)V") \
-+ \
-+ /* Continuation save and resume */ \
-+ do_intrinsic(_saveContinuation, javax_stack_Continuation, saveContinuation_name, void_object_signature, F_RN) \
-+ do_name( saveContinuation_name, "save") \
-+ do_intrinsic(_resumeContinuation, javax_stack_Continuation, resumeContinuation_name, object_void_signature, F_RN) \
-+ do_name( resumeContinuation_name, "resume") \
-+ do_intrinsic(_dumpContinuation, javax_stack_Continuation, dumpContinuation_name, void_object_signature, F_RN) \
-+ do_name( dumpContinuation_name, "dump") \
-+ do_intrinsic(_storeFrameObject, javax_stack_Continuation, storeFrameObject_name, object_object_signature, F_SN) \
-+ do_name( storeFrameObject_name, "storeFrameObject") \
-+ do_intrinsic(_storeFrameVoid, javax_stack_Continuation, storeFrameVoid_name, void_method_signature, F_SN) \
-+ do_name( storeFrameVoid_name, "storeFrameVoid") \
-+ do_intrinsic(_storeFrameBoolean, javax_stack_Continuation, storeFrameBoolean_name, bool_bool_signature, F_SN) \
-+ do_name( storeFrameBoolean_name, "storeFrameBoolean") \
-+ do_intrinsic(_storeFrameByte, javax_stack_Continuation, storeFrameByte_name, byte_byte_signature, F_SN) \
-+ do_name( storeFrameByte_name, "storeFrameByte") \
-+ do_intrinsic(_storeFrameChar, javax_stack_Continuation, storeFrameChar_name, char_char_signature, F_SN) \
-+ do_name( storeFrameChar_name, "storeFrameChar") \
-+ do_intrinsic(_storeFrameShort, javax_stack_Continuation, storeFrameShort_name, short_short_signature, F_SN) \
-+ do_name( storeFrameShort_name, "storeFrameShort") \
-+ do_intrinsic(_storeFrameInt, javax_stack_Continuation, storeFrameInt_name, int_int_signature, F_SN) \
-+ do_name( storeFrameInt_name, "storeFrameInt") \
-+ do_intrinsic(_storeFrameLong, javax_stack_Continuation, storeFrameLong_name, long_long_signature, F_SN) \
-+ do_name( storeFrameLong_name, "storeFrameLong") \
-+ do_intrinsic(_storeFrameFloat, javax_stack_Continuation, storeFrameFloat_name, float_float_signature, F_SN) \
-+ do_name( storeFrameFloat_name, "storeFrameFloat") \
-+ do_intrinsic(_storeFrameDouble, javax_stack_Continuation, storeFrameDouble_name, double_double_signature, F_SN) \
-+ do_name( storeFrameDouble_name, "storeFrameDouble") \
-+ do_intrinsic(_continuation_unwind, javax_stack_Continuation, continuation_unwind_name, throwable_throwable_signature, F_SN) \
-+ do_name( continuation_unwind_name, "unwind") \
-+ do_intrinsic(_startDelimited, javax_stack_Continuation, startDelimited_name, startDelimited_signature, F_SN) \
-+ do_name( startDelimited_name, "startDelimited") \
-+ do_signature( startDelimited_signature, "(Ljavax/stack/DelimitedRunnable;Ljava/lang/Object;)Ljava/lang/Object;") \
-+ do_intrinsic(_continueDelimited, javax_stack_Continuation, continueDelimited_name, continueDelimited_signature, F_SN) \
-+ do_name( continueDelimited_name, "continueDelimited") \
-+ do_signature( continueDelimited_signature, "(Ljavax/stack/Continuation;Ljava/lang/Object;)Ljava/lang/Object;") \
-+ do_intrinsic(_startDelimitedInternal, javax_stack_Continuation, startDelimitedInternal_name, startDelimited_signature, F_S) \
-+ do_name( startDelimitedInternal_name, "startDelimitedInternal") \
-+ do_intrinsic(_continueDelimitedInternal, javax_stack_Continuation, continueDelimitedInternal_name, continueDelimited_signature, F_S) \
-+ do_name( continueDelimitedInternal_name, "continueDelimitedInternal") \
- /*== LAST_COMPILER_INLINE*/ \
- /*the compiler does have special inlining code for these; bytecode inline is just fine */ \
- \
-diff --git a/src/share/vm/code/codeBlob.cpp b/src/share/vm/code/codeBlob.cpp
---- a/src/share/vm/code/codeBlob.cpp
-+++ b/src/share/vm/code/codeBlob.cpp
-@@ -46,7 +46,7 @@
-
-
- // Creates a simple CodeBlob. Sets up the size of the different regions.
--CodeBlob::CodeBlob(const char* name, int header_size, int size, int frame_complete, int locs_size) {
-+CodeBlob::CodeBlob(const char* name, int header_size, int size, int frame_complete, int locs_size, CodeBlobType type) {
- assert(size == round_to(size, oopSize), "unaligned size");
- assert(locs_size == round_to(locs_size, oopSize), "unaligned size");
- assert(header_size == round_to(header_size, oopSize), "unaligned size");
-@@ -60,6 +60,7 @@
- // off the use of this table (gri 7/6/2000).
-
- _name = name;
-+ _type = type;
- _size = size;
- _frame_complete_offset = frame_complete;
- _header_size = header_size;
-@@ -82,12 +83,14 @@
- int size,
- int frame_complete,
- int frame_size,
-- OopMapSet* oop_maps
-+ OopMapSet* oop_maps,
-+ CodeBlobType type
- ) {
- assert(size == round_to(size, oopSize), "unaligned size");
- assert(header_size == round_to(header_size, oopSize), "unaligned size");
-
- _name = name;
-+ _type = type;
- _size = size;
- _frame_complete_offset = frame_complete;
- _header_size = header_size;
-@@ -236,7 +239,7 @@
-
-
- BufferBlob::BufferBlob(const char* name, int size)
--: CodeBlob(name, sizeof(BufferBlob), size, CodeOffsets::frame_never_safe, /*locs_size:*/ 0)
-+: CodeBlob(name, sizeof(BufferBlob), size, CodeOffsets::frame_never_safe, /*locs_size:*/ 0, _buffer)
- {}
-
- BufferBlob* BufferBlob::create(const char* name, int buffer_size) {
-@@ -261,7 +264,7 @@
-
-
- BufferBlob::BufferBlob(const char* name, int size, CodeBuffer* cb)
-- : CodeBlob(name, cb, sizeof(BufferBlob), size, CodeOffsets::frame_never_safe, 0, NULL)
-+ : CodeBlob(name, cb, sizeof(BufferBlob), size, CodeOffsets::frame_never_safe, 0, NULL, _buffer)
- {}
-
- BufferBlob* BufferBlob::create(const char* name, CodeBuffer* cb) {
-@@ -314,7 +317,7 @@
- OopMapSet* oop_maps,
- bool caller_must_gc_arguments
- )
--: CodeBlob(name, cb, sizeof(RuntimeStub), size, frame_complete, frame_size, oop_maps)
-+: CodeBlob(name, cb, sizeof(RuntimeStub), size, frame_complete, frame_size, oop_maps, _runtime_stub)
- {
- _caller_must_gc_arguments = caller_must_gc_arguments;
- }
-@@ -377,7 +380,7 @@
- int unpack_with_reexecution_offset,
- int frame_size
- )
--: SingletonBlob("DeoptimizationBlob", cb, sizeof(DeoptimizationBlob), size, frame_size, oop_maps)
-+: SingletonBlob("DeoptimizationBlob", cb, sizeof(DeoptimizationBlob), size, frame_size, oop_maps, _deoptimization_stub)
- {
- _unpack_offset = unpack_offset;
- _unpack_with_exception = unpack_with_exception_offset;
-@@ -451,7 +454,7 @@
- OopMapSet* oop_maps,
- int frame_size
- )
--: SingletonBlob("UncommonTrapBlob", cb, sizeof(UncommonTrapBlob), size, frame_size, oop_maps)
-+: SingletonBlob("UncommonTrapBlob", cb, sizeof(UncommonTrapBlob), size, frame_size, oop_maps, _uncommon_trap_stub)
- {}
-
-
-@@ -511,7 +514,7 @@
- OopMapSet* oop_maps,
- int frame_size
- )
--: SingletonBlob("ExceptionBlob", cb, sizeof(ExceptionBlob), size, frame_size, oop_maps)
-+: SingletonBlob("ExceptionBlob", cb, sizeof(ExceptionBlob), size, frame_size, oop_maps, _exception_stub)
- {}
-
-
-@@ -570,7 +573,7 @@
- OopMapSet* oop_maps,
- int frame_size
- )
--: SingletonBlob("SafepointBlob", cb, sizeof(SafepointBlob), size, frame_size, oop_maps)
-+: SingletonBlob("SafepointBlob", cb, sizeof(SafepointBlob), size, frame_size, oop_maps, _safepoint_stub)
- {}
-
-
-diff --git a/src/share/vm/code/codeBlob.hpp b/src/share/vm/code/codeBlob.hpp
---- a/src/share/vm/code/codeBlob.hpp
-+++ b/src/share/vm/code/codeBlob.hpp
-@@ -43,8 +43,21 @@
-
- friend class VMStructs;
-
-+public:
-+
-+ enum CodeBlobType {
-+ _buffer,
-+ _nmethod,
-+ _runtime_stub,
-+ _deoptimization_stub,
-+ _uncommon_trap_stub,
-+ _exception_stub,
-+ _safepoint_stub
-+ };
-+
- private:
- const char* _name;
-+ CodeBlobType _type; // which kind of CodeBlob is this
- int _size; // total size of CodeBlob in bytes
- int _header_size; // size of header (depends on subclass)
- int _relocation_size; // size of relocation
-@@ -73,7 +86,7 @@
- // a) simple CodeBlob
- // frame_complete is the offset from the beginning of the instructions
- // to where the frame setup (from stackwalk viewpoint) is complete.
-- CodeBlob(const char* name, int header_size, int size, int frame_complete, int locs_size);
-+ CodeBlob(const char* name, int header_size, int size, int frame_complete, int locs_size, CodeBlobType type);
-
- // b) full CodeBlob
- CodeBlob(
-@@ -83,22 +96,23 @@
- int size,
- int frame_complete,
- int frame_size,
-- OopMapSet* oop_maps
-+ OopMapSet* oop_maps,
-+ CodeBlobType type
- );
-
- // Deletion
- void flush();
-
- // Typing
-- virtual bool is_buffer_blob() const { return false; }
-- virtual bool is_nmethod() const { return false; }
-- virtual bool is_runtime_stub() const { return false; }
-- virtual bool is_deoptimization_stub() const { return false; }
-- virtual bool is_uncommon_trap_stub() const { return false; }
-- virtual bool is_exception_stub() const { return false; }
-- virtual bool is_safepoint_stub() const { return false; }
-+ bool is_buffer_blob() const { return _type == _buffer; }
-+ bool is_nmethod() const { return _type == _nmethod; }
-+ bool is_runtime_stub() const { return _type == _runtime_stub; }
-+ bool is_deoptimization_stub() const { return _type == _deoptimization_stub; }
-+ bool is_uncommon_trap_stub() const { return _type == _uncommon_trap_stub; }
-+ bool is_exception_stub() const { return _type == _exception_stub; }
-+ bool is_safepoint_stub() const { return _type == _safepoint_stub; }
-+
- virtual bool is_adapter_blob() const { return false; }
--
- virtual bool is_compiled_by_c2() const { return false; }
- virtual bool is_compiled_by_c1() const { return false; }
-
-@@ -194,6 +208,9 @@
- // Returns true, if the next frame is responsible for GC'ing oops passed as arguments
- virtual bool caller_must_gc_arguments(JavaThread* thread) const { return false; }
-
-+ static ByteSize frame_size_offset() { return byte_offset_of(CodeBlob, _frame_size); }
-+ static ByteSize type_offset() { return byte_offset_of(CodeBlob, _type); }
-+
- // Naming
- const char* name() const { return _name; }
- void set_name(const char* name) { _name = name; }
-@@ -286,9 +303,6 @@
- bool caller_must_gc_arguments
- );
-
-- // Typing
-- bool is_runtime_stub() const { return true; }
--
- // GC support
- bool caller_must_gc_arguments(JavaThread* thread) const { return _caller_must_gc_arguments; }
-
-@@ -320,9 +334,10 @@
- int header_size,
- int size,
- int frame_size,
-- OopMapSet* oop_maps
-+ OopMapSet* oop_maps,
-+ CodeBlobType type
- )
-- : CodeBlob(name, cb, header_size, size, CodeOffsets::frame_never_safe, frame_size, oop_maps)
-+ : CodeBlob(name, cb, header_size, size, CodeOffsets::frame_never_safe, frame_size, oop_maps, type)
- {};
-
- bool is_alive() const { return true; }
-@@ -373,7 +388,6 @@
- );
-
- // Typing
-- bool is_deoptimization_stub() const { return true; }
- const DeoptimizationBlob *as_deoptimization_stub() const { return this; }
- bool exception_address_is_unpack_entry(address pc) const {
- address unpack_pc = unpack();
-@@ -438,9 +452,6 @@
- // GC for args
- void preserve_callee_argument_oops(frame fr, const RegisterMap *reg_map, OopClosure* f) { /* nothing to do */ }
-
-- // Typing
-- bool is_uncommon_trap_stub() const { return true; }
--
- // Iteration
- void oops_do(OopClosure* f) {}
- };
-@@ -473,9 +484,6 @@
- // GC for args
- void preserve_callee_argument_oops(frame fr, const RegisterMap* reg_map, OopClosure* f) { /* nothing to do */ }
-
-- // Typing
-- bool is_exception_stub() const { return true; }
--
- // Iteration
- void oops_do(OopClosure* f) {}
- };
-@@ -509,9 +517,6 @@
- // GC for args
- void preserve_callee_argument_oops(frame fr, const RegisterMap* reg_map, OopClosure* f) { /* nothing to do */ }
-
-- // Typing
-- bool is_safepoint_stub() const { return true; }
--
- // Iteration
- void oops_do(OopClosure* f) {}
- };
-diff --git a/src/share/vm/code/codeCache.hpp b/src/share/vm/code/codeCache.hpp
---- a/src/share/vm/code/codeCache.hpp
-+++ b/src/share/vm/code/codeCache.hpp
-@@ -148,6 +148,8 @@
-
- // Deoptimization
- static int mark_for_deoptimization(DepChange& changes);
-+
-+ static CodeHeap* heap() { return _heap; }
- #ifdef HOTSWAP
- static int mark_for_evol_deoptimization(instanceKlassHandle dependee);
- #endif // HOTSWAP
-diff --git a/src/share/vm/code/exceptionHandlerTable.cpp b/src/share/vm/code/exceptionHandlerTable.cpp
---- a/src/share/vm/code/exceptionHandlerTable.cpp
-+++ b/src/share/vm/code/exceptionHandlerTable.cpp
-@@ -224,3 +224,59 @@
- fatal1("Invalid offset in ImplicitExceptionTable at %lx", _data);
- }
- }
-+
-+
-+// Continuation pc->stub table
-+
-+void ContinuationPcTable::add_entry(int pc_offset, int stub_offset) {
-+ if ((_length+1) >= _size) {
-+ // not enough space => grow the table (amortized growth, double its size)
-+ int new_size = _size * 2;
-+ _table = REALLOC_RESOURCE_ARRAY(int, _table, _size, new_size);
-+ _size = new_size;
-+ }
-+ assert((_length+1) < _size, "sanity check");
-+ _table[_length++] = pc_offset;
-+ _table[_length++] = stub_offset;
-+}
-+
-+void ContinuationPcTable::add_patch_entry(int pos) {
-+ if ((_patch_length+1) >= _patch_size) {
-+ // not enough space => grow the table (amortized growth, double its size)
-+ int new_size = _patch_size * 2;
-+ _patch_nmethod_table = REALLOC_RESOURCE_ARRAY(int, _patch_nmethod_table, _patch_size, new_size);
-+ _patch_size = new_size;
-+ }
-+ assert(_patch_length < _patch_size, "sanity check");
-+ _patch_nmethod_table[_patch_length++] = pos;
-+}
-+
-+ContinuationPcTable::ContinuationPcTable(int initial_size) {
-+ guarantee(initial_size > 0, "initial size must be > 0");
-+ _table = NEW_RESOURCE_ARRAY(int, initial_size);
-+ _length = 0;
-+ _size = initial_size;
-+ _patch_nmethod_table = NEW_RESOURCE_ARRAY(int, initial_size);
-+ _patch_length = 0;
-+ _patch_size = initial_size;
-+}
-+
-+void ContinuationPcTable::copy_to(nmethod* nm) {
-+ assert(size_in_bytes() == nm->continuation_pc_table_size(), "size of space allocated in nmethod incorrect");
-+ address* dest = (address*)nm->continuation_pc_table_begin();
-+ for( int i=0; i<_length; i++ )
-+ dest[i] = _table[i] + nm->instructions_begin();
-+ for( int i=0; i<_patch_length; i++ )
-+ *(nmethod**)(nm->instructions_begin() +_patch_nmethod_table[i]) = nm;
-+}
-+
-+void ContinuationPcTable::print() const {
-+ tty->print_cr("ContinuationPcTable (size = %d bytes)", size_in_bytes());
-+ int i = 0;
-+ while (i < _length) {
-+ int pc = _table[i++];
-+ int stub = _table[i++];
-+ tty->print(" %08x -> %08x", pc, stub);
-+ }
-+}
-+
-diff --git a/src/share/vm/code/exceptionHandlerTable.hpp b/src/share/vm/code/exceptionHandlerTable.hpp
---- a/src/share/vm/code/exceptionHandlerTable.hpp
-+++ b/src/share/vm/code/exceptionHandlerTable.hpp
-@@ -154,3 +154,36 @@
- void print(address base) const;
- void verify(nmethod *nm) const;
- };
-+
-+
-+// Continuation pc->stub table
-+
-+class ContinuationPcTable VALUE_OBJ_CLASS_SPEC {
-+ private:
-+ int* _table; // the table
-+ int _length; // the current length of the table
-+ int _size; // the number of allocated entries
-+ ReallocMark _nesting; // assertion check for reallocations
-+
-+ int* _patch_nmethod_table;
-+ int _patch_length;
-+ int _patch_size;
-+
-+ public:
-+ // (compile-time) construction within compiler
-+ ContinuationPcTable(int initial_size = 8);
-+
-+ // add the entry & grow the table if needed
-+ void add_entry(int pc_offset, int stub_offset);
-+
-+ // add the entry & grow the table if needed
-+ void add_patch_entry(int pos);
-+
-+ // nmethod support
-+ int size_in_bytes() const { return _length * sizeof(int); }
-+ void copy_to(nmethod* nm);
-+
-+ // debugging
-+ void print() const;
-+};
-+
-diff --git a/src/share/vm/code/nmethod.cpp b/src/share/vm/code/nmethod.cpp
---- a/src/share/vm/code/nmethod.cpp
-+++ b/src/share/vm/code/nmethod.cpp
-@@ -410,7 +410,8 @@
- scopes_data_size() +
- scopes_pcs_size() +
- handler_table_size() +
-- nul_chk_table_size();
-+ nul_chk_table_size() +
-+ continuation_pc_table_size();
- }
-
- const char* nmethod::compile_kind() const {
-@@ -500,10 +501,11 @@
- int orig_pc_offset,
- DebugInformationRecorder* debug_info,
- Dependencies* dependencies,
-- CodeBuffer* code_buffer, int frame_size,
-+ CodeBuffer* code_buffer, int frame_size, int stack_param_words,
- OopMapSet* oop_maps,
- ExceptionHandlerTable* handler_table,
- ImplicitExceptionTable* nul_chk_table,
-+ ContinuationPcTable* continuation_pc_table,
- AbstractCompiler* compiler,
- int comp_level
- )
-@@ -518,13 +520,15 @@
- + round_to(dependencies->size_in_bytes() , oopSize)
- + round_to(handler_table->size_in_bytes(), oopSize)
- + round_to(nul_chk_table->size_in_bytes(), oopSize)
-+ + continuation_pc_table->size_in_bytes()
- + round_to(debug_info->data_size() , oopSize);
- nm = new (nmethod_size)
- nmethod(method(), nmethod_size, compile_id, entry_bci, offsets,
-- orig_pc_offset, debug_info, dependencies, code_buffer, frame_size,
-+ orig_pc_offset, debug_info, dependencies, code_buffer, frame_size, stack_param_words,
- oop_maps,
- handler_table,
- nul_chk_table,
-+ continuation_pc_table,
- compiler,
- comp_level);
- if (nm != NULL) {
-@@ -572,7 +576,7 @@
- ByteSize basic_lock_sp_offset,
- OopMapSet* oop_maps )
- : CodeBlob("native nmethod", code_buffer, sizeof(nmethod),
-- nmethod_size, offsets->value(CodeOffsets::Frame_Complete), frame_size, oop_maps),
-+ nmethod_size, offsets->value(CodeOffsets::Frame_Complete), frame_size, oop_maps, _nmethod),
- _compiled_synchronized_native_basic_lock_owner_sp_offset(basic_lock_owner_sp_offset),
- _compiled_synchronized_native_basic_lock_sp_offset(basic_lock_sp_offset)
- {
-@@ -594,6 +598,9 @@
- _deoptimize_offset = 0;
- _deoptimize_mh_offset = 0;
- _orig_pc_offset = 0;
-+
-+ _stack_parameter_words = -1;
-+ _activation_frame_size = -1;
- #ifdef HAVE_DTRACE_H
- _trap_offset = 0;
- #endif // def HAVE_DTRACE_H
-@@ -604,7 +611,8 @@
- _dependencies_offset = _scopes_pcs_offset;
- _handler_table_offset = _dependencies_offset;
- _nul_chk_table_offset = _handler_table_offset;
-- _nmethod_end_offset = _nul_chk_table_offset;
-+ _continuation_pc_table_offset = _nul_chk_table_offset;
-+ _nmethod_end_offset = _continuation_pc_table_offset;
- _compile_id = 0; // default
- _comp_level = CompLevel_none;
- _entry_point = instructions_begin();
-@@ -663,7 +671,7 @@
- CodeBuffer* code_buffer,
- int frame_size)
- : CodeBlob("dtrace nmethod", code_buffer, sizeof(nmethod),
-- nmethod_size, offsets->value(CodeOffsets::Frame_Complete), frame_size, NULL),
-+ nmethod_size, offsets->value(CodeOffsets::Frame_Complete), frame_size, NULL, _nmethod),
- _compiled_synchronized_native_basic_lock_owner_sp_offset(in_ByteSize(-1)),
- _compiled_synchronized_native_basic_lock_sp_offset(in_ByteSize(-1))
- {
-@@ -693,7 +701,8 @@
- _dependencies_offset = _scopes_pcs_offset;
- _handler_table_offset = _dependencies_offset;
- _nul_chk_table_offset = _handler_table_offset;
-- _nmethod_end_offset = _nul_chk_table_offset;
-+ _continuation_pc_table_offset = _nul_chk_table_offset;
-+ _nmethod_end_offset = _continuation_pc_table_offset;
- _compile_id = 0; // default
- _comp_level = CompLevel_none;
- _entry_point = instructions_begin();
-@@ -761,14 +770,16 @@
- Dependencies* dependencies,
- CodeBuffer *code_buffer,
- int frame_size,
-+ int stack_param_words,
- OopMapSet* oop_maps,
- ExceptionHandlerTable* handler_table,
- ImplicitExceptionTable* nul_chk_table,
-+ ContinuationPcTable* continuation_pc_table,
- AbstractCompiler* compiler,
- int comp_level
- )
- : CodeBlob("nmethod", code_buffer, sizeof(nmethod),
-- nmethod_size, offsets->value(CodeOffsets::Frame_Complete), frame_size, oop_maps),
-+ nmethod_size, offsets->value(CodeOffsets::Frame_Complete), frame_size, oop_maps, _nmethod),
- _compiled_synchronized_native_basic_lock_owner_sp_offset(in_ByteSize(-1)),
- _compiled_synchronized_native_basic_lock_sp_offset(in_ByteSize(-1))
- {
-@@ -788,6 +799,9 @@
- _scavenge_root_state = 0;
- _compiler = compiler;
- _orig_pc_offset = orig_pc_offset;
-+
-+ _stack_parameter_words = stack_param_words;
-+ _activation_frame_size = align_object_size(activationFrameOopDesc::header_size() + stack_param_words + frame_size) * HeapWordSize;
- #ifdef HAVE_DTRACE_H
- _trap_offset = 0;
- #endif // def HAVE_DTRACE_H
-@@ -803,7 +817,8 @@
- _dependencies_offset = _scopes_pcs_offset + adjust_pcs_size(debug_info->pcs_size());
- _handler_table_offset = _dependencies_offset + round_to(dependencies->size_in_bytes (), oopSize);
- _nul_chk_table_offset = _handler_table_offset + round_to(handler_table->size_in_bytes(), oopSize);
-- _nmethod_end_offset = _nul_chk_table_offset + round_to(nul_chk_table->size_in_bytes(), oopSize);
-+ _continuation_pc_table_offset = _nul_chk_table_offset + round_to(nul_chk_table->size_in_bytes(), oopSize);
-+ _nmethod_end_offset = _continuation_pc_table_offset + continuation_pc_table->size_in_bytes();
-
- _entry_point = instructions_begin();
- _verified_entry_point = instructions_begin() + offsets->value(CodeOffsets::Verified_Entry);
-@@ -836,6 +851,7 @@
- // Copy contents of ExceptionHandlerTable to nmethod
- handler_table->copy_to(this);
- nul_chk_table->copy_to(this);
-+ continuation_pc_table->copy_to(this);
-
- // we use the information of entry points to find out if a method is
- // static or non static
-diff --git a/src/share/vm/code/nmethod.hpp b/src/share/vm/code/nmethod.hpp
---- a/src/share/vm/code/nmethod.hpp
-+++ b/src/share/vm/code/nmethod.hpp
-@@ -116,9 +116,12 @@
- // - handler entry point array
- // [Implicit Null Pointer exception table]
- // - implicit null table array
-+// [Continuation stub table]
-+// - sorted pc->stub mapping array
-
- class Dependencies;
- class ExceptionHandlerTable;
-+class ContinuationPcTable;
- class ImplicitExceptionTable;
- class AbstractCompiler;
- class xmlStream;
-@@ -134,6 +137,9 @@
- methodOop _method;
- int _entry_bci; // != InvocationEntryBci if this nmethod is an on-stack replacement method
-
-+ int _stack_parameter_words; // number of parameters that are passed via the stack
-+ int _activation_frame_size; // aligned size of an activationFrameOop containing this frame (precalculated for performance)
-+
- // To support simple linked-list chaining of nmethods:
- nmethod* _osr_link; // from instanceKlass::osr_nmethods_head
- nmethod* _scavenge_root_link; // from CodeCache::scavenge_root_nmethods
-@@ -161,6 +167,7 @@
- int _dependencies_offset;
- int _handler_table_offset;
- int _nul_chk_table_offset;
-+ int _continuation_pc_table_offset;
- int _nmethod_end_offset;
-
- // location in frame (offset for sp) that deopt can store the original
-@@ -247,9 +254,11 @@
- Dependencies* dependencies,
- CodeBuffer *code_buffer,
- int frame_size,
-+ int stack_param_words,
- OopMapSet* oop_maps,
- ExceptionHandlerTable* handler_table,
- ImplicitExceptionTable* nul_chk_table,
-+ ContinuationPcTable* continuation_pc_table,
- AbstractCompiler* compiler,
- int comp_level);
-
-@@ -283,9 +292,11 @@
- Dependencies* dependencies,
- CodeBuffer *code_buffer,
- int frame_size,
-+ int stack_param_words,
- OopMapSet* oop_maps,
- ExceptionHandlerTable* handler_table,
- ImplicitExceptionTable* nul_chk_table,
-+ ContinuationPcTable* continuation_pc_table,
- AbstractCompiler* compiler,
- int comp_level);
-
-@@ -324,7 +335,6 @@
- #endif // NOT PRODUCT
-
- // type info
-- bool is_nmethod() const { return true; }
- bool is_java_method() const { return !method()->is_native(); }
- bool is_native_method() const { return method()->is_native(); }
- bool is_osr_method() const { return _entry_bci != InvocationEntryBci; }
-@@ -351,7 +361,9 @@
- address handler_table_begin () const { return header_begin() + _handler_table_offset ; }
- address handler_table_end () const { return header_begin() + _nul_chk_table_offset ; }
- address nul_chk_table_begin () const { return header_begin() + _nul_chk_table_offset ; }
-- address nul_chk_table_end () const { return header_begin() + _nmethod_end_offset ; }
-+ address nul_chk_table_end () const { return header_begin() + _continuation_pc_table_offset; }
-+ address continuation_pc_table_begin() const { return header_begin() + _continuation_pc_table_offset; }
-+ address continuation_pc_table_end() const { return header_begin() + _nmethod_end_offset ; }
-
- int code_size () const { return code_end () - code_begin (); }
- int stub_size () const { return stub_end () - stub_begin (); }
-@@ -361,6 +373,7 @@
- int dependencies_size () const { return dependencies_end () - dependencies_begin (); }
- int handler_table_size() const { return handler_table_end() - handler_table_begin(); }
- int nul_chk_table_size() const { return nul_chk_table_end() - nul_chk_table_begin(); }
-+ int continuation_pc_table_size() const { return continuation_pc_table_end() - continuation_pc_table_begin(); }
-
- int total_size () const;
-
-@@ -371,6 +384,7 @@
- bool scopes_pcs_contains (PcDesc* addr) const { return scopes_pcs_begin () <= addr && addr < scopes_pcs_end (); }
- bool handler_table_contains(address addr) const { return handler_table_begin() <= addr && addr < handler_table_end(); }
- bool nul_chk_table_contains(address addr) const { return nul_chk_table_begin() <= addr && addr < nul_chk_table_end(); }
-+ bool continuation_pc_table_contains(address addr) const { return continuation_pc_table_begin() <= addr && addr < continuation_pc_table_end(); }
-
- // entry points
- address entry_point() const { return _entry_point; } // normal entry point
-@@ -458,6 +472,9 @@
- // implicit exceptions support
- address continuation_for_implicit_exception(address pc);
-
-+ int stack_parameter_words() { return _stack_parameter_words; }
-+ int activation_frame_size() { return _activation_frame_size; }
-+
- // On-stack replacement support
- int osr_entry_bci() const { assert(_entry_bci != InvocationEntryBci, "wrong kind of nmethod"); return _entry_bci; }
- address osr_entry() const { assert(_entry_bci != InvocationEntryBci, "wrong kind of nmethod"); return _osr_entry_point; }
-@@ -641,6 +658,11 @@
- static int verified_entry_point_offset() { return offset_of(nmethod, _verified_entry_point); }
- static int osr_entry_point_offset() { return offset_of(nmethod, _osr_entry_point); }
- static int entry_bci_offset() { return offset_of(nmethod, _entry_bci); }
-+ static int method_offset() { return offset_of(nmethod, _method); }
-+ static int stack_parameter_words_offset() { return offset_of(nmethod, _stack_parameter_words); }
-+ static int activation_frame_size_offset() { return offset_of(nmethod, _activation_frame_size); }
-+ static int continuation_pc_table_offset_offset(){ return offset_of(nmethod, _continuation_pc_table_offset); }
-+ static int nmethod_end_offset_offset() { return offset_of(nmethod, _nmethod_end_offset); }
-
- };
-
-diff --git a/src/share/vm/compiler/compilerOracle.cpp b/src/share/vm/compiler/compilerOracle.cpp
---- a/src/share/vm/compiler/compilerOracle.cpp
-+++ b/src/share/vm/compiler/compilerOracle.cpp
-@@ -284,6 +284,10 @@
- }
- }
-
-+ // stack manipulation/continuation: startDelimitedInternal can never be compiled
-+ if (method->intrinsic_id() == vmIntrinsics::_startDelimitedInternal)
-+ return true;
-+
- if (lists[CompileOnlyCommand] != NULL) {
- return !lists[CompileOnlyCommand]->match(method);
- }
-diff --git a/src/share/vm/gc_implementation/shared/markSweep.cpp b/src/share/vm/gc_implementation/shared/markSweep.cpp
---- a/src/share/vm/gc_implementation/shared/markSweep.cpp
-+++ b/src/share/vm/gc_implementation/shared/markSweep.cpp
-@@ -214,9 +214,9 @@
- _adjusted_pointers->push(p);
- }
-
--class AdjusterTracker: public OopClosure {
-+class MarkSweepAdjusterTracker: public OopClosure {
- public:
-- AdjusterTracker() {}
-+ MarkSweepAdjusterTracker() {}
- void do_oop(oop* o) { MarkSweep::check_adjust_pointer(o); }
- void do_oop(narrowOop* o) { MarkSweep::check_adjust_pointer(o); }
- };
-@@ -226,7 +226,7 @@
- _adjusted_pointers->clear();
- _pointer_tracking = true;
-
-- AdjusterTracker checker;
-+ MarkSweepAdjusterTracker checker;
- obj->oop_iterate(&checker);
- }
- }
-diff --git a/src/share/vm/includeDB_compiler1 b/src/share/vm/includeDB_compiler1
---- a/src/share/vm/includeDB_compiler1
-+++ b/src/share/vm/includeDB_compiler1
-@@ -53,6 +53,7 @@
- c1_CodeStubs.hpp c1_LIR.hpp
- c1_CodeStubs.hpp c1_Runtime1.hpp
-
-+c1_CodeStubs_<arch>.cpp activationFrameOop.hpp
- c1_CodeStubs_<arch>.cpp c1_CodeStubs.hpp
- c1_CodeStubs_<arch>.cpp c1_FrameMap.hpp
- c1_CodeStubs_<arch>.cpp c1_LIRAssembler.hpp
-@@ -222,6 +223,7 @@
- c1_LIRAssembler.hpp methodDataOop.hpp
- c1_LIRAssembler.hpp top.hpp
-
-+c1_LIRAssembler_<arch>.cpp activationFrameOop.hpp
- c1_LIRAssembler_<arch>.cpp barrierSet.hpp
- c1_LIRAssembler_<arch>.cpp c1_Compilation.hpp
- c1_LIRAssembler_<arch>.cpp c1_LIRAssembler.hpp
-diff --git a/src/share/vm/includeDB_core b/src/share/vm/includeDB_core
---- a/src/share/vm/includeDB_core
-+++ b/src/share/vm/includeDB_core
-@@ -134,6 +134,27 @@
- accessFlags.hpp jvm.h
- accessFlags.hpp top.hpp
-
-+activationFrameKlass.cpp activationFrameKlass.hpp
-+activationFrameKlass.cpp activationFrameOop.hpp
-+activationFrameKlass.cpp gcLocker.hpp
-+activationFrameKlass.cpp handles.inline.hpp
-+activationFrameKlass.cpp interpreter.hpp
-+activationFrameKlass.cpp markSweep.inline.hpp
-+activationFrameKlass.cpp oop.inline.hpp
-+activationFrameKlass.cpp oop.inline2.hpp
-+activationFrameKlass.cpp oopMapCache.hpp
-+activationFrameKlass.cpp resourceArea.hpp
-+
-+activationFrameKlass.hpp oop.hpp
-+activationFrameKlass.hpp klass.hpp
-+activationFrameKlass.hpp orderAccess.hpp
-+
-+activationFrameOop.cpp activationFrameOop.hpp
-+
-+activationFrameOop.hpp nmethod.hpp
-+activationFrameOop.hpp oop.hpp
-+activationFrameOop.hpp typeArrayOop.hpp
-+
- allocation.cpp allocation.hpp
- allocation.cpp allocation.inline.hpp
- allocation.cpp os.hpp
-@@ -148,6 +169,15 @@
-
- allocation.inline.hpp os.hpp
-
-+annotationParser.cpp annotationParser.hpp
-+annotationParser.cpp oopFactory.hpp
-+
-+annotationParser.hpp constantPoolOop.hpp
-+annotationParser.hpp typeArrayOop.hpp
-+annotationParser.hpp allocation.hpp
-+annotationParser.hpp symbolOop.hpp
-+annotationParser.hpp systemDictionary.hpp
-+
- aprofiler.cpp aprofiler.hpp
- aprofiler.cpp collectedHeap.inline.hpp
- aprofiler.cpp oop.inline.hpp
-@@ -880,6 +910,7 @@
- classFileError.cpp verifier.hpp
-
- classFileParser.cpp allocation.hpp
-+classFileParser.cpp annotationParser.hpp
- classFileParser.cpp classFileParser.hpp
- classFileParser.cpp classLoader.hpp
- classFileParser.cpp classLoadingService.hpp
-@@ -1926,6 +1957,7 @@
- heap.cpp os.hpp
-
- heap.hpp allocation.hpp
-+heap.hpp sizes.hpp
- heap.hpp virtualspace.hpp
-
- // heapDumper is jck optional, put cpp deps in includeDB_features
-@@ -3014,6 +3046,7 @@
- nativeLookup.hpp handles.hpp
- nativeLookup.hpp top.hpp
-
-+nmethod.cpp activationFrameOop.hpp
- nmethod.cpp abstractCompiler.hpp
- nmethod.cpp bytecode.hpp
- nmethod.cpp codeCache.hpp
-@@ -3137,6 +3170,7 @@
- oop.inline2.hpp permGen.hpp
- oop.inline2.hpp universe.hpp
-
-+oopFactory.cpp activationFrameKlass.hpp
- oopFactory.cpp collectedHeap.inline.hpp
- oopFactory.cpp compiledICHolderKlass.hpp
- oopFactory.cpp constMethodKlass.hpp
-@@ -3756,6 +3790,7 @@
- sharedRuntime.hpp resourceArea.hpp
- sharedRuntime.hpp threadLocalStorage.hpp
-
-+sharedRuntime_<arch_model>.cpp activationFrameOop.hpp
- sharedRuntime_<arch_model>.cpp assembler.hpp
- sharedRuntime_<arch_model>.cpp assembler_<arch>.inline.hpp
- sharedRuntime_<arch_model>.cpp compiledICHolderOop.hpp
-@@ -4368,6 +4403,7 @@
- unhandledOops.cpp unhandledOops.hpp
- unhandledOops.cpp universe.hpp
-
-+universe.cpp activationFrameKlass.hpp
- universe.cpp aprofiler.hpp
- universe.cpp arguments.hpp
- universe.cpp arrayKlassKlass.hpp
-@@ -4432,17 +4468,30 @@
-
- universe.inline.hpp universe.hpp
-
-+unsafe.cpp activationFrameOop.hpp
-+unsafe.cpp assembler.hpp
- unsafe.cpp allocation.inline.hpp
-+unsafe.cpp biasedLocking.hpp
- unsafe.cpp copy.hpp
-+unsafe.cpp deoptimization.hpp
- unsafe.cpp globals.hpp
- unsafe.cpp interfaceSupport.hpp
- unsafe.cpp jni.h
- unsafe.cpp jvm.h
- unsafe.cpp reflection.hpp
- unsafe.cpp reflectionCompat.hpp
-+unsafe.cpp stackMapTable.hpp
- unsafe.cpp synchronizer.hpp
- unsafe.cpp threadService.hpp
- unsafe.cpp vmSymbols.hpp
-+unsafe.cpp oopMapCache.hpp
-+
-+unsafe.cpp oopFactory.hpp
-+unsafe.cpp vframe.hpp
-+unsafe.cpp vframe_hp.hpp
-+unsafe.cpp vframeArray.hpp
-+unsafe.cpp verificationType.hpp
-+unsafe.cpp constMethodOop.hpp
-
- utf8.cpp utf8.hpp
-
-@@ -4460,6 +4509,7 @@
- verificationType.hpp symbolOop.hpp
- verificationType.hpp systemDictionary.hpp
-
-+verifier.cpp annotationParser.hpp
- verifier.cpp bytecodeStream.hpp
- verifier.cpp bytes_<arch>.hpp
- verifier.cpp classFileStream.hpp
-@@ -4523,6 +4573,7 @@
- vframe.hpp stackValueCollection.hpp
-
- vframeArray.cpp allocation.inline.hpp
-+vframeArray.cpp bytecode.hpp
- vframeArray.cpp events.hpp
- vframeArray.cpp handles.inline.hpp
- vframeArray.cpp interpreter.hpp
-diff --git a/src/share/vm/includeDB_features b/src/share/vm/includeDB_features
---- a/src/share/vm/includeDB_features
-+++ b/src/share/vm/includeDB_features
-@@ -231,6 +231,7 @@
- restore.cpp symbolTable.hpp
- restore.cpp systemDictionary.hpp
-
-+serialize.cpp activationFrameOop.hpp
- serialize.cpp classify.hpp
- serialize.cpp codeCache.hpp
- serialize.cpp compactingPermGenGen.hpp
-@@ -241,6 +242,8 @@
- serialize.cpp symbolTable.hpp
- serialize.cpp systemDictionary.hpp
-
-+vmStructs.cpp activationFrameKlass.hpp
-+vmStructs.cpp activationFrameOop.hpp
- vmStructs.cpp arguments.hpp
- vmStructs.cpp arrayKlass.hpp
- vmStructs.cpp arrayKlassKlass.hpp
-diff --git a/src/share/vm/memory/classify.cpp b/src/share/vm/memory/classify.cpp
---- a/src/share/vm/memory/classify.cpp
-+++ b/src/share/vm/memory/classify.cpp
-@@ -28,6 +28,7 @@
-
- const char* ClassifyObjectClosure::object_type_name[number_object_types] = {
- "unknown",
-+ "activationFrame",
- "instance",
- "instanceRef",
- "objArray",
-@@ -57,7 +58,9 @@
- k->set_alloc_count(k->alloc_count() + 1);
- }
-
-- if (obj->is_instance()) {
-+ if (obj->is_activationFrame()) {
-+ type = activationFrame_type;
-+ } else if (obj->is_instance()) {
- if (k->oop_is_instanceRef()) {
- type = instanceRef_type;
- } else {
-@@ -147,7 +150,9 @@
- const char *name;
- if (k->name() == NULL) {
-
-- if (obj == Universe::klassKlassObj()) {
-+ if (obj == Universe::activationFrameKlassObj()) {
-+ name = "_activationFrameKlassObj";
-+ } else if (obj == Universe::klassKlassObj()) {
- name = "_klassKlassObj";
- } else if (obj == Universe::arrayKlassKlassObj()) {
- name = "_arrayKlassKlassObj";
-diff --git a/src/share/vm/memory/classify.hpp b/src/share/vm/memory/classify.hpp
---- a/src/share/vm/memory/classify.hpp
-+++ b/src/share/vm/memory/classify.hpp
-@@ -24,6 +24,7 @@
-
- typedef enum oop_type {
- unknown_type,
-+ activationFrame_type,
- instance_type,
- instanceRef_type,
- objArray_type,
-diff --git a/src/share/vm/memory/heap.hpp b/src/share/vm/memory/heap.hpp
---- a/src/share/vm/memory/heap.hpp
-+++ b/src/share/vm/memory/heap.hpp
-@@ -52,6 +52,9 @@
- void set_used() { _header._used = true; }
- void set_free() { _header._used = false; }
- bool free() { return !_header._used; }
-+
-+ static ByteSize used_offset() { return byte_offset_of(HeapBlock, _header._used ); }
-+ static ByteSize allocated_offset() { return in_ByteSize(sizeof(HeapBlock)); }
- };
-
- class FreeBlock: public HeapBlock {
-@@ -142,6 +145,9 @@
- char *low_boundary() const { return _memory.low_boundary (); }
- char *high_boundary() const { return _memory.high_boundary(); }
-
-+ int log2_segment_size() const { return _log2_segment_size; }
-+ const VirtualSpace& segmap() const { return _segmap; }
-+
- // Iteration
-
- // returns the first block or NULL
-diff --git a/src/share/vm/memory/heapInspection.cpp b/src/share/vm/memory/heapInspection.cpp
---- a/src/share/vm/memory/heapInspection.cpp
-+++ b/src/share/vm/memory/heapInspection.cpp
-@@ -56,6 +56,7 @@
- if (_klass == Universe::shortArrayKlassObj()) name = "<shortArrayKlass>"; else
- if (_klass == Universe::intArrayKlassObj()) name = "<intArrayKlass>"; else
- if (_klass == Universe::longArrayKlassObj()) name = "<longArrayKlass>"; else
-+ if (_klass == Universe::activationFrameKlassObj()) name = "<activationFrameKlass>"; else
- if (_klass == Universe::methodKlassObj()) name = "<methodKlass>"; else
- if (_klass == Universe::constMethodKlassObj()) name = "<constMethodKlass>"; else
- if (_klass == Universe::methodDataKlassObj()) name = "<methodDataKlass>"; else
-diff --git a/src/share/vm/memory/oopFactory.cpp b/src/share/vm/memory/oopFactory.cpp
---- a/src/share/vm/memory/oopFactory.cpp
-+++ b/src/share/vm/memory/oopFactory.cpp
-@@ -121,6 +121,19 @@
- CHECK_NULL);
- }
-
-+activationFrameOop oopFactory::new_activationFrame(nmethod* method,
-+ TRAPS) {
-+ klassOop cmkObj = Universe::activationFrameKlassObj();
-+ activationFrameKlass* cmk = activationFrameKlass::cast(cmkObj);
-+ return cmk->allocate(method, CHECK_NULL);
-+}
-+
-+activationFrameOop oopFactory::new_activationFrame(int size,
-+ TRAPS) {
-+ klassOop cmkObj = Universe::activationFrameKlassObj();
-+ activationFrameKlass* cmk = activationFrameKlass::cast(cmkObj);
-+ return cmk->allocate(size, CHECK_NULL);
-+}
-
- methodOop oopFactory::new_method(int byte_code_size, AccessFlags access_flags,
- int compressed_line_number_size,
-diff --git a/src/share/vm/memory/oopFactory.hpp b/src/share/vm/memory/oopFactory.hpp
---- a/src/share/vm/memory/oopFactory.hpp
-+++ b/src/share/vm/memory/oopFactory.hpp
-@@ -114,6 +114,10 @@
- bool is_conc_safe,
- TRAPS);
-
-+ static activationFrameOop new_activationFrame(nmethod* method, TRAPS);
-+
-+ static activationFrameOop new_activationFrame(int size, TRAPS);
-+
- // Method Data containers
- static methodDataOop new_methodData(methodHandle method, TRAPS);
-
-diff --git a/src/share/vm/memory/serialize.cpp b/src/share/vm/memory/serialize.cpp
---- a/src/share/vm/memory/serialize.cpp
-+++ b/src/share/vm/memory/serialize.cpp
-@@ -45,6 +45,7 @@
- // Verify the sizes of various oops in the system.
- soc->do_tag(sizeof(oopDesc));
- soc->do_tag(sizeof(instanceOopDesc));
-+ soc->do_tag(sizeof(activationFrameOopDesc));
- soc->do_tag(sizeof(methodOopDesc));
- soc->do_tag(sizeof(constMethodOopDesc));
- soc->do_tag(sizeof(methodDataOopDesc));
-diff --git a/src/share/vm/memory/universe.cpp b/src/share/vm/memory/universe.cpp
---- a/src/share/vm/memory/universe.cpp
-+++ b/src/share/vm/memory/universe.cpp
-@@ -26,6 +26,7 @@
- # include "incls/_universe.cpp.incl"
-
- // Known objects
-+klassOop Universe::_activationFrameKlassObj = NULL;
- klassOop Universe::_boolArrayKlassObj = NULL;
- klassOop Universe::_byteArrayKlassObj = NULL;
- klassOop Universe::_charArrayKlassObj = NULL;
-@@ -118,6 +119,7 @@
-
-
- void Universe::system_classes_do(void f(klassOop)) {
-+ f(activationFrameKlassObj());
- f(symbolKlassObj());
- f(methodKlassObj());
- f(constMethodKlassObj());
-@@ -170,6 +172,7 @@
- }
- }
- }
-+ f->do_oop((oop*)&_activationFrameKlassObj);
- f->do_oop((oop*)&_symbolKlassObj);
- f->do_oop((oop*)&_methodKlassObj);
- f->do_oop((oop*)&_constMethodKlassObj);
-@@ -262,6 +265,7 @@
- _typeArrayKlassObjs[T_INT] = _intArrayKlassObj;
- _typeArrayKlassObjs[T_LONG] = _longArrayKlassObj;
-
-+ _activationFrameKlassObj = activationFrameKlass::create_klass(CHECK);
- _methodKlassObj = methodKlass::create_klass(CHECK);
- _constMethodKlassObj = constMethodKlass::create_klass(CHECK);
- _methodDataKlassObj = methodDataKlass::create_klass(CHECK);
-@@ -457,6 +461,7 @@
- void Universe::init_self_patching_vtbl_list(void** list, int count) {
- int n = 0;
- { klassKlass o; add_vtable(list, &n, &o, count); }
-+ { activationFrameKlass o; add_vtable(list, &n, &o, count); }
- { arrayKlassKlass o; add_vtable(list, &n, &o, count); }
- { objArrayKlassKlass o; add_vtable(list, &n, &o, count); }
- { instanceKlassKlass o; add_vtable(list, &n, &o, count); }
-diff --git a/src/share/vm/memory/universe.hpp b/src/share/vm/memory/universe.hpp
---- a/src/share/vm/memory/universe.hpp
-+++ b/src/share/vm/memory/universe.hpp
-@@ -133,6 +133,7 @@
-
- static klassOop _objectArrayKlassObj;
-
-+ static klassOop _activationFrameKlassObj;
- static klassOop _symbolKlassObj;
- static klassOop _methodKlassObj;
- static klassOop _constMethodKlassObj;
-@@ -267,9 +268,10 @@
- return _typeArrayKlassObjs[t];
- }
-
-+ static klassOop activationFrameKlassObj() { return _activationFrameKlassObj; }
- static klassOop symbolKlassObj() { return _symbolKlassObj; }
- static klassOop methodKlassObj() { return _methodKlassObj; }
-- static klassOop constMethodKlassObj() { return _constMethodKlassObj; }
-+ static klassOop constMethodKlassObj() { return _constMethodKlassObj; }
- static klassOop methodDataKlassObj() { return _methodDataKlassObj; }
- static klassOop klassKlassObj() { return _klassKlassObj; }
- static klassOop arrayKlassKlassObj() { return _arrayKlassKlassObj; }
-diff --git a/src/share/vm/oops/activationFrameKlass.cpp b/src/share/vm/oops/activationFrameKlass.cpp
-new file mode 100644
---- /dev/null
-+++ b/src/share/vm/oops/activationFrameKlass.cpp
-@@ -0,0 +1,283 @@
-+/*
-+ * Copyright 2003-2006 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 "incls/_precompiled.incl"
-+# include "incls/_activationFrameKlass.cpp.incl"
-+
-+
-+klassOop activationFrameKlass::create_klass(TRAPS) {
-+ activationFrameKlass o;
-+ KlassHandle h_this_klass(THREAD, Universe::klassKlassObj());
-+ KlassHandle k = base_create_klass(h_this_klass, header_size(), o.vtbl_value(), CHECK_NULL);
-+ // Make sure size calculation is right
-+ assert(k()->size() == align_object_size(header_size()), "wrong size for object");
-+ return k();
-+}
-+
-+int activationFrameKlass::oop_size(oop obj) const {
-+ assert(obj->is_activationFrame(), "must be activationFrame oop");
-+ return activationFrameOop(obj)->object_size();
-+}
-+
-+bool activationFrameKlass::oop_is_parsable(oop obj) const {
-+ assert(obj->is_activationFrame(), "must be activationFrame oop");
-+ return activationFrameOop(obj)->object_is_parsable();
-+}
-+
-+activationFrameOop activationFrameKlass::allocate(nmethod* method, TRAPS) {
-+ int size = activationFrameOopDesc::object_size(method->stack_parameter_words(), method->frame_size());
-+ KlassHandle h_k(THREAD, as_klassOop());
-+ activationFrameOop af = (activationFrameOop)CollectedHeap::permanent_obj_allocate(h_k, size, CHECK_NULL);
-+ assert(!af->is_parsable(), "Not yet safely parsable");
-+ No_Safepoint_Verifier no_safepoint;
-+ af->_next = NULL;
-+ af->_nmethod = method;
-+ af->_stack_pos = NULL;
-+ af->_pc = NULL;
-+ af->_thread = JavaThread::current();
-+ af->_state = activationFrameOopDesc::_compiled_empty;
-+ assert(af->is_parsable(), "Is safely parsable by gc");
-+ return af;
-+}
-+
-+activationFrameOop activationFrameKlass::allocate(int size, TRAPS) {
-+ KlassHandle h_k(THREAD, as_klassOop());
-+ activationFrameOop af = (activationFrameOop)CollectedHeap::permanent_obj_allocate(h_k, size, CHECK_NULL);
-+ assert(!af->is_parsable(), "Not yet safely parsable");
-+ return af;
-+}
-+
-+class ActivationFrameInterpreterClosure : public OffsetClosure {
-+ private:
-+ activationFrameOop _af;
-+ OopClosure* _f;
-+
-+ public:
-+ ActivationFrameInterpreterClosure(activationFrameOop af, OopClosure* f) : _af(af), _f(f) {}
-+
-+ void offset_do(int offset) {
-+ _f->do_oop((oop*)_af->get_value_addr(offset));
-+ }
-+};
-+
-+class ActivationFrameCodeBlobClosure : public CodeBlobClosure {
-+ public:
-+ // Called for each code blob.
-+ virtual void do_code_blob(CodeBlob* cb){
-+ }
-+};
-+
-+inline int activationFrameKlass::do_oop_internal(oop obj, OopClosure& closure) {
-+ assert(obj->is_activationFrame(), "must be activationFrame oop");
-+ activationFrameOop af = activationFrameOop(obj);
-+ int size = af->object_size();
-+ switch(af->state()) {
-+ case activationFrameOopDesc::_compiled_empty:
-+ case activationFrameOopDesc::_dummy_invalid:
-+ case activationFrameOopDesc::_dummy_delimited:
-+ // nothing to do here...
-+ break;
-+ case activationFrameOopDesc::_compiled_filled:
-+ {
-+ frame fr(af->frame_sp(), af->frame_fp(), af->pc());
-+ RegisterMap map(af->thread());
-+ map.set_include_argument_oops(false);
-+ ActivationFrameCodeBlobClosure dummy;
-+ fr.oops_do(&closure, &dummy, &map);
-+ break;
-+ }
-+ case activationFrameOopDesc::_interpreted_empty:
-+ closure.do_oop((oop*)&af->_methodOop);
-+ break;
-+ case activationFrameOopDesc::_interpreted_filled:
-+ {
-+ ActivationFrameInterpreterClosure blk(af, &closure);
-+ // process locals & expression stack
-+ Thread *thread = Thread::current();
-+ methodHandle m (thread, af->_methodOop);
-+ closure.do_oop((oop*)&af->_methodOop);
-+ InterpreterOopMap mask;
-+ m->mask_for(af->_bci, &mask);
-+ mask.iterate_oop(&blk);
-+ break;
-+ }
-+ default:
-+ ShouldNotReachHere();
-+ }
-+ closure.do_oop((oop*)&af->_next);
-+ return size;
-+}
-+
-+class oop_follow_contentsClosure : public OopClosure {
-+ public:
-+ void do_oop(oop* p) {
-+ MarkSweep::mark_and_push(p);
-+ }
-+ void do_oop(narrowOop* p) {
-+ MarkSweep::mark_and_push(p);
-+ }
-+};
-+
-+void activationFrameKlass::oop_follow_contents(oop obj) {
-+ oop_follow_contentsClosure closure;
-+ do_oop_internal(obj, closure);
-+}
-+
-+#ifndef SERIALGC
-+
-+class oop_follow_contents2Closure : public OopClosure {
-+ ParCompactionManager* _cm;
-+ public:
-+ oop_follow_contents2Closure(ParCompactionManager* cm) : _cm(cm) {}
-+ void do_oop(oop* p) {
-+ PSParallelCompact::mark_and_push(_cm, p);
-+ }
-+ void do_oop(narrowOop* p) {
-+ PSParallelCompact::mark_and_push(_cm, p);
-+ }
-+};
-+
-+void activationFrameKlass::oop_follow_contents(ParCompactionManager* cm, oop obj) {
-+ oop_follow_contents2Closure closure(cm);
-+ do_oop_internal(obj, closure);
-+}
-+#endif // SERIALGC
-+
-+int activationFrameKlass::oop_oop_iterate(oop obj, OopClosure* blk) {
-+ return do_oop_internal(obj, *blk);
-+}
-+
-+
-+class oop_oop_iterate_mClosure : public OopClosure {
-+ OopClosure* _closure;
-+ MemRegion _mr;
-+ public:
-+ oop_oop_iterate_mClosure(OopClosure* closure, MemRegion mr) : _closure(closure), _mr(mr) {}
-+ void do_oop(oop* p) {
-+ if (_mr.contains(p)) _closure->do_oop(p);
-+ }
-+ void do_oop(narrowOop* p) {
-+ if (_mr.contains(p)) _closure->do_oop(p);
-+ }
-+};
-+
-+int activationFrameKlass::oop_oop_iterate_m(oop obj, OopClosure* blk, MemRegion mr) {
-+ oop_oop_iterate_mClosure closure(blk, mr);
-+ return do_oop_internal(obj, closure);
-+}
-+
-+
-+class oop_adjust_pointersClosure : public OopClosure {
-+ public:
-+ void do_oop(oop* p) {
-+ MarkSweep::adjust_pointer(p);
-+ }
-+ void do_oop(narrowOop* p) {
-+ MarkSweep::adjust_pointer(p);
-+ }
-+};
-+
-+int activationFrameKlass::oop_adjust_pointers(oop obj) {
-+ oop_adjust_pointersClosure closure;
-+ return do_oop_internal(obj, closure);
-+}
-+
-+#ifndef SERIALGC
-+void activationFrameKlass::oop_copy_contents(PSPromotionManager* pm, oop obj) {
-+ assert(obj->is_activationFrame(), "must be activationFrame oop");
-+}
-+
-+void activationFrameKlass::oop_push_contents(PSPromotionManager* pm, oop obj) {
-+ assert(obj->is_activationFrame(), "must be activationFrame oop");
-+}
-+
-+class oop_update_pointersClosure : public OopClosure {
-+public:
-+ void do_oop(oop* p) {
-+ PSParallelCompact::adjust_pointer(p);
-+ }
-+ void do_oop(narrowOop* p) {
-+ PSParallelCompact::adjust_pointer(p);
-+ }
-+};
-+
-+int activationFrameKlass::oop_update_pointers(ParCompactionManager* cm, oop obj) {
-+ oop_update_pointersClosure closure;
-+ return do_oop_internal(obj, closure);
-+}
-+
-+class oop_update_pointersClosure2 : public OopClosure {
-+ oop* _begin;
-+ oop* _end;
-+public:
-+ oop_update_pointersClosure2(HeapWord* begin, HeapWord* end) : _begin((oop*)begin), _end((oop*)end) {}
-+
-+ void do_oop(oop* p) {
-+ if ( (p >= _begin) && (p <= _end) ) {
-+ PSParallelCompact::adjust_pointer(p);
-+ }
-+ }
-+ void do_oop(narrowOop* p) {
-+ PSParallelCompact::adjust_pointer(p);
-+ }
-+};
-+int activationFrameKlass::oop_update_pointers(ParCompactionManager* cm, oop obj,
-+ HeapWord* beg_addr,
-+ HeapWord* end_addr) {
-+ oop_update_pointersClosure2 closure(beg_addr, end_addr);
-+ // TODO this can be optimized... it currently ignores beg_addr and end_addr
-+ return do_oop_internal(obj, closure);
-+}
-+#endif // SERIALGC
-+
-+#undef DO_OOP_ACTIVATION_FRAME
-+
-+#ifndef PRODUCT
-+
-+// Printing
-+void activationFrameKlass::oop_print_on(oop obj, outputStream* st) {
-+ ResourceMark rm;
-+ assert(obj->is_activationFrame(), "must be activationFrame oop");
-+ Klass::oop_print_on(obj, st);
-+ activationFrameOop m = activationFrameOop(obj);/*
-+ st->print(" - method: " INTPTR_FORMAT " ", (address)m->const_method()->method());
-+ m->const_method()->method()->print_value_on(st); st->cr();
-+ st->print(" - callsites: %i\n", m->callsite_count());
-+ st->print(" - slots: %i\n", m->slot_count());*/
-+}
-+
-+
-+// Short version - just print the name of the method it belongs to.
-+void activationFrameKlass::oop_print_value_on(oop obj, outputStream* st) {
-+ assert(obj->is_activationFrame(), "must be activationFrame oop");
-+ activationFrameOop m = activationFrameOop(obj);/*
-+ st->print(" callsite verification data of method " );
-+ m->const_method()->method()->print_value_on(st);*/
-+}
-+
-+#endif // PRODUCT
-+
-+const char* activationFrameKlass::internal_name() const {
-+ return "{activationFrame}";
-+}
-diff --git a/src/share/vm/oops/activationFrameKlass.hpp b/src/share/vm/oops/activationFrameKlass.hpp
-new file mode 100644
---- /dev/null
-+++ b/src/share/vm/oops/activationFrameKlass.hpp
-@@ -0,0 +1,88 @@
-+/*
-+ * Copyright 2003-2006 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.
-+ *
-+ */
-+
-+// A activationFrameKlass is the klass of a activationFrameOop
-+
-+class activationFrameKlass : public Klass {
-+ friend class VMStructs;
-+private:
-+ juint _alloc_size; // allocation profiling support
-+public:
-+ // Testing
-+ bool oop_is_activationFrame() const { return true; }
-+ virtual bool oop_is_parsable(oop obj) const;
-+
-+ // Allocation
-+ DEFINE_ALLOCATE_PERMANENT(activationFrameKlass);
-+ activationFrameOop allocate(nmethod* method, TRAPS);
-+ activationFrameOop allocate(int size, TRAPS);
-+ static klassOop create_klass(TRAPS);
-+
-+ // Sizing
-+ int oop_size(oop obj) const;
-+ int klass_oop_size() const { return object_size(); }
-+
-+ // Casting from klassOop
-+ static activationFrameKlass* cast(klassOop k) {
-+ assert(k->klass_part()->oop_is_activationFrame(), "cast to activationFrameKlass");
-+ return (activationFrameKlass*) k->klass_part();
-+ }
-+
-+ // Sizing
-+ static int header_size() {
-+ return oopDesc::header_size() + sizeof(activationFrameKlass)/HeapWordSize;
-+ }
-+ int object_size() const {
-+ return align_object_size(header_size());
-+ }
-+
-+ // Garbage collection
-+ void oop_follow_contents(oop obj);
-+ int oop_adjust_pointers(oop obj);
-+
-+ // Parallel Scavenge and Parallel Old
-+ PARALLEL_GC_DECLS
-+
-+ // Allocation profiling support
-+ juint alloc_size() const { return _alloc_size; }
-+ void set_alloc_size(juint n) { _alloc_size = n; }
-+
-+ // Iterators
-+ int oop_oop_iterate(oop obj, OopClosure* blk);
-+ int oop_oop_iterate_m(oop obj, OopClosure* blk, MemRegion mr);
-+
-+private:
-+ int do_oop_internal(oop obj, OopClosure& closure);
-+
-+#ifndef PRODUCT
-+ public:
-+ // Printing
-+ void oop_print_on (oop obj, outputStream* st);
-+ void oop_print_value_on(oop obj, outputStream* st);
-+
-+#endif
-+
-+ public:
-+ const char* internal_name() const;
-+};
-diff --git a/src/share/vm/oops/activationFrameOop.cpp b/src/share/vm/oops/activationFrameOop.cpp
-new file mode 100644
---- /dev/null
-+++ b/src/share/vm/oops/activationFrameOop.cpp
-@@ -0,0 +1,34 @@
-+/*
-+ * Copyright 2003-2006 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 "incls/_precompiled.incl"
-+# include "incls/_activationFrameOop.cpp.incl"
-+
-+
-+// How big must this Object be?
-+
-+int activationFrameOopDesc::object_size(int param_word_size, int data_word_size) {
-+ int extra_words = param_word_size + data_word_size;
-+ return align_object_size(header_size() + extra_words);
-+}
-diff --git a/src/share/vm/oops/activationFrameOop.hpp b/src/share/vm/oops/activationFrameOop.hpp
-new file mode 100644
---- /dev/null
-+++ b/src/share/vm/oops/activationFrameOop.hpp
-@@ -0,0 +1,198 @@
-+/*
-+ * Copyright 2003-2006 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.
-+ *
-+ */
-+
-+// An activationFrameOop stores the raw data for a continuation stack frame.
-+// The next pointer allows the on-the-fly creation of a tree structure of frames.
-+//
-+// Memory layout (each line represents a word).
-+//
-+// |------------------------------------------------------|
-+// | header |
-+// | klass |
-+// |------------------------------------------------------|
-+
-+// TBD
-+
-+// | |
-+// |------------------------------------------------------|
-+
-+
-+class nmethod;
-+
-+class activationFrameOopDesc : public oopDesc {
-+ friend class activationFrameKlass;
-+ friend class VMStructs;
-+public:
-+ enum FrameState {
-+ _unparsable = 0x000000,
-+
-+ _invalid = 0x000001,
-+ _empty = 0x000002,
-+ _filled = 0x000004,
-+ _delimited = 0x000008,
-+
-+ _compiled_type = 0x000100,
-+ _interpreted_type = 0x000200,
-+ _dummy_type = 0x000400,
-+
-+ _compiled_filled = _compiled_type | _filled,
-+ _compiled_empty = _compiled_type | _empty,
-+
-+ _interpreted_filled = _interpreted_type | _filled,
-+ _interpreted_empty = _interpreted_type | _empty,
-+
-+ _dummy_invalid = _dummy_type | _invalid,
-+ _dummy_delimited = _dummy_type | _delimited,
-+
-+ _state_mask = 0x0000ff,
-+ _type_mask = 0x00ff00
-+ };
-+
-+private:
-+ FrameState _state;
-+ activationFrameOop _next;
-+ // for implementation reasons this is the base pointer of the next stack frame (== rsp - 2*HeapWordSize)
-+ intptr_t* _stack_pos;
-+
-+ union {
-+ nmethod* _nmethod; // compiled
-+ methodOop _methodOop; // interpreted
-+ };
-+
-+ union {
-+ address _pc; // compiled & interpreted
-+ bool _in_use; // only delimited
-+ };
-+ int _bci; // interpreted
-+
-+ union {
-+ JavaThread* _thread; // compiled
-+ int _data_count; // interpreted
-+ };
-+
-+
-+public:
-+
-+ FrameState state() const { return _state; }
-+ void set_state(FrameState state) { _state = state; }
-+
-+ bool is_compiled() const { return (_state & _type_mask) == _compiled_type; }
-+ bool is_interpreted() const { return (_state & _type_mask) == _interpreted_type; }
-+ bool is_dummy() const { return (_state & _type_mask) == _dummy_type; }
-+
-+ bool is_invalid() const { return (_state & _state_mask) == _invalid; }
-+ bool is_empty() const { return (_state & _state_mask) == _empty; }
-+ bool is_filled() const { return (_state & _state_mask) == _filled; }
-+ bool is_delimited() const { return (_state & _state_mask) == _delimited; }
-+
-+ intptr_t* stack_pos() const { return _stack_pos; }
-+ void set_stack_pos(intptr_t* adr) {
-+ assert((adr == NULL && is_filled()) || (adr == NULL && is_dummy()) || (adr != NULL && !is_filled()), "stack pos doesn't match filled state");
-+ _stack_pos = adr;
-+ }
-+
-+ activationFrameOop next() const { return _next; }
-+ void set_next(activationFrameOop oop) { _next = oop; }
-+
-+
-+ address pc() const { return _pc; }
-+ void set_pc(address pc) { _pc = pc; }
-+
-+ int bci() const { assert(is_interpreted(), "wrong type"); return _bci; }
-+ void set_bci(int bci) { assert(is_interpreted(), "wrong type"); _bci = bci; }
-+
-+ nmethod* get_nmethod() const { assert(is_compiled(), "wrong type"); return _nmethod; }
-+ void set_nmethod(nmethod* method) { assert(is_compiled(), "wrong type"); _nmethod = method; }
-+
-+ methodOop get_methodOop() const { assert(is_interpreted(), "wrong type"); return _methodOop; }
-+ void set_methodOop(methodOop oop) { assert(is_interpreted(), "wrong type"); _methodOop = oop; }
-+
-+ JavaThread* thread() const { assert(is_compiled(), "wrong type"); return _thread; }
-+ void set_thread(JavaThread* thread) { assert(is_compiled(), "wrong type"); _thread = thread; }
-+
-+ int data_count() const { assert(is_interpreted(), "wrong type"); return _data_count; }
-+ void set_data_count(int count) { assert(is_interpreted(), "wrong type"); _data_count = count; }
-+
-+ bool in_use() const { assert(is_delimited(), "wrong type"); return _in_use; }
-+ void set_in_use(bool in_use) { assert(is_delimited(), "wrong type"); _in_use = in_use; }
-+
-+
-+ intptr_t* frame_sp() const { assert(is_compiled(), "wrong type"); return ((intptr_t*)this) + header_size(); }
-+ intptr_t* frame_fp() const { assert(is_compiled(), "wrong type"); return ((intptr_t*)this) + _nmethod->stack_parameter_words() - 2; }
-+
-+ void set_value(int index, intptr_t value) {
-+ assert(is_interpreted(), "wrong type");
-+ assert(index >= 0 && index < _data_count, "invalid index");
-+ ((intptr_t*)this)[header_size() + index] = value;
-+ }
-+
-+ intptr_t get_value(int index) {
-+ assert(is_interpreted(), "wrong type");
-+ assert(index >= 0 && index < _data_count, "invalid index");
-+ return ((intptr_t*)this)[header_size() + index];
-+ }
-+
-+ intptr_t* get_value_addr(int index) {
-+ assert(is_interpreted(), "wrong type");
-+ assert(index >= 0 && index < _data_count, "invalid index");
-+ return ((intptr_t*)this) + (header_size() + index);
-+ }
-+
-+ void mark_as_invalid() {
-+ _state = (FrameState)((_state & ~_state_mask) | _invalid);
-+ }
-+
-+ // Object size needed
-+ static int object_size(int param_word_size, int data_word_size);
-+
-+ // Sizing
-+ static int header_size() { return sizeof(activationFrameOopDesc)/HeapWordSize; }
-+ int object_size() const {
-+ if (is_compiled())
-+ return object_size(_nmethod->stack_parameter_words(), _nmethod->frame_size());
-+ else if (is_interpreted())
-+ return align_object_size(header_size() + _data_count * HeapWordSize);
-+ else if (is_dummy())
-+ return align_object_size(header_size());
-+ else {
-+ ShouldNotReachHere();
-+ }
-+ }
-+
-+ bool object_is_parsable() const { return _state != _unparsable; }
-+
-+ // Garbage collection support
-+ oop* adr_methodOop() const { return (oop*)&_methodOop; }
-+
-+ static ByteSize state_offset() { return byte_offset_of(activationFrameOopDesc, _state ); }
-+ static ByteSize stack_pos_offset() { return byte_offset_of(activationFrameOopDesc, _stack_pos ); }
-+ static ByteSize pc_offset() { return byte_offset_of(activationFrameOopDesc, _pc ); }
-+ static ByteSize bci_offset() { return byte_offset_of(activationFrameOopDesc, _bci ); }
-+ static ByteSize method_offset() { return byte_offset_of(activationFrameOopDesc, _nmethod ); }
-+ static ByteSize next_offset() { return byte_offset_of(activationFrameOopDesc, _next ); }
-+ static ByteSize thread_offset() { return byte_offset_of(activationFrameOopDesc, _thread ); }
-+ static ByteSize in_use_offset() { return byte_offset_of(activationFrameOopDesc, _in_use ); }
-+ static ByteSize data_count_offset() { return byte_offset_of(activationFrameOopDesc, _data_count); }
-+
-+};
-diff --git a/src/share/vm/oops/constMethodOop.hpp b/src/share/vm/oops/constMethodOop.hpp
---- a/src/share/vm/oops/constMethodOop.hpp
-+++ b/src/share/vm/oops/constMethodOop.hpp
-@@ -96,6 +96,15 @@
- _has_checked_exceptions = 2,
- _has_localvariable_table = 4
- };
-+public:
-+ enum ContinuableFlag {
-+ _not_continuable = 0,
-+ _continuable_optimized, // this method isn't defined continuable but has been included in continuations in the past
-+ _continuable_hidden, // defined as continuable, with "hidden" visibility
-+ _continuable_readonly, // defined as continuable, with "readonly" visibility
-+ _continuable_readwrite // defined as continuable, with "readwrite" visibility
-+ };
-+private:
-
- // Bit vector of signature
- // Callers interpret 0=not initialized yet and
-@@ -134,6 +143,7 @@
- jbyte _interpreter_kind;
- jbyte _flags;
-
-+private:
- // Size of Java bytecodes allocated immediately after methodOop.
- u2 _code_size;
- u2 _name_index; // Method name (index in constant pool)
-@@ -143,6 +153,8 @@
- // but this may change with redefinition
- u2 _generic_signature_index; // Generic signature (index in constant pool, 0 if absent)
-
-+ ContinuableFlag _continuable;
-+
- public:
- // Inlined tables
- void set_inlined_tables_length(int checked_exceptions_len,
-@@ -158,6 +170,12 @@
- bool has_localvariable_table() const
- { return (_flags & _has_localvariable_table) != 0; }
-
-+ bool is_continuable() const
-+ { return _continuable != _not_continuable; }
-+
-+ void set_continuable(ContinuableFlag c) { _continuable = c; }
-+ ContinuableFlag continuable() const { return _continuable; }
-+
- void set_interpreter_kind(int kind) { _interpreter_kind = kind; }
- int interpreter_kind(void) const { return _interpreter_kind; }
-
-diff --git a/src/share/vm/oops/klass.hpp b/src/share/vm/oops/klass.hpp
---- a/src/share/vm/oops/klass.hpp
-+++ b/src/share/vm/oops/klass.hpp
-@@ -557,6 +557,7 @@
-
- public:
- // type testing operations
-+ virtual bool oop_is_activationFrame() const { return false; }
- virtual bool oop_is_instance_slow() const { return false; }
- virtual bool oop_is_instanceRef() const { return false; }
- virtual bool oop_is_array() const { return false; }
-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
-@@ -138,7 +138,7 @@
- void methodOopDesc::mask_for(int bci, InterpreterOopMap* mask) {
-
- Thread* myThread = Thread::current();
-- methodHandle h_this(myThread, this);
-+ methodHandle h_this(myThread, this);/*
- #ifdef ASSERT
- bool has_capability = myThread->is_VM_thread() ||
- myThread->is_ConcurrentGC_thread() ||
-@@ -154,7 +154,7 @@
- local_mask.print();
- }
- }
--#endif
-+#endif*/
- instanceKlass::cast(method_holder())->mask_for(h_this, bci, mask);
- return;
- }
-diff --git a/src/share/vm/oops/oop.hpp b/src/share/vm/oops/oop.hpp
---- a/src/share/vm/oops/oop.hpp
-+++ b/src/share/vm/oops/oop.hpp
-@@ -115,6 +115,7 @@
- bool is_conc_safe();
-
- // type test operations (inlined in oop.inline.h)
-+ bool is_activationFrame() const;
- bool is_instance() const;
- bool is_instanceRef() const;
- bool is_array() const;
-diff --git a/src/share/vm/oops/oop.inline.hpp b/src/share/vm/oops/oop.inline.hpp
---- a/src/share/vm/oops/oop.inline.hpp
-+++ b/src/share/vm/oops/oop.inline.hpp
-@@ -103,6 +103,7 @@
-
- inline bool oopDesc::is_a(klassOop k) const { return blueprint()->is_subtype_of(k); }
-
-+inline bool oopDesc::is_activationFrame() const { return blueprint()->oop_is_activationFrame(); }
- inline bool oopDesc::is_instance() const { return blueprint()->oop_is_instance(); }
- inline bool oopDesc::is_instanceRef() const { return blueprint()->oop_is_instanceRef(); }
- inline bool oopDesc::is_array() const { return blueprint()->oop_is_array(); }
-diff --git a/src/share/vm/oops/oopsHierarchy.hpp b/src/share/vm/oops/oopsHierarchy.hpp
---- a/src/share/vm/oops/oopsHierarchy.hpp
-+++ b/src/share/vm/oops/oopsHierarchy.hpp
-@@ -34,6 +34,7 @@
- #ifndef CHECK_UNHANDLED_OOPS
-
- typedef class oopDesc* oop;
-+typedef class activationFrameOopDesc* activationFrameOop;
- typedef class instanceOopDesc* instanceOop;
- typedef class methodOopDesc* methodOop;
- typedef class constMethodOopDesc* constMethodOop;
-@@ -151,6 +152,7 @@
- } \
- }; \
-
-+DEF_OOP(activationFrame);
- DEF_OOP(instance);
- DEF_OOP(method);
- DEF_OOP(methodData);
-@@ -169,6 +171,7 @@
- // The klass hierarchy is separate from the oop hierarchy.
-
- class Klass;
-+class activationFrameKlass;
- class instanceKlass;
- class instanceRefKlass;
- class methodKlass;
-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
-@@ -77,6 +77,7 @@
- }
-
- extern "C" {
-+ void JNICALL JVM_RegisterContinuationMethods(JNIEnv* env, jclass contcls);
- void JNICALL JVM_RegisterUnsafeMethods(JNIEnv *env, jclass unsafecls);
- void JNICALL JVM_RegisterMethodHandleMethods(JNIEnv *env, jclass unsafecls);
- void JNICALL JVM_RegisterPerfMethods(JNIEnv *env, jclass perfclass);
-@@ -95,6 +96,9 @@
- return CAST_FROM_FN_PTR(address, JVM_SetPrimitiveFieldValues);
- }
- }
-+ if (strstr(jni_name, "Java_javax_stack_Continuation_registerNatives") != NULL) {
-+ return CAST_FROM_FN_PTR(address, JVM_RegisterContinuationMethods);
-+ }
- if (strstr(jni_name, "Java_sun_misc_Unsafe_registerNatives") != NULL) {
- return CAST_FROM_FN_PTR(address, JVM_RegisterUnsafeMethods);
- }
-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
-@@ -1163,6 +1163,534 @@
- UNSAFE_END
-
-
-+void dump_compiledVFrame(compiledVFrame* frame) {
-+ tty->print_cr("\t%s", frame->method()->name_and_sig_as_C_string());
-+ tty->print("\tbci: %d ", frame->bci());
-+ tty->print("locals: %d ", frame->locals()->size());
-+ tty->print("expressions: %d\n", frame->expressions()->size());
-+}
-+
-+
-+class ActivationFrameInterpreterOopClosure : public OffsetClosure {
-+ private:
-+ activationFrameOop _af;
-+
-+ public:
-+ ActivationFrameInterpreterOopClosure(activationFrameOop af) : _af(af) {}
-+
-+ void offset_do(int offset) {
-+ oop value = *(oop*)_af->get_value_addr(offset);
-+ if (value == NULL)
-+ tty->print("null ");
-+ else
-+ tty->print("0x%08x (%s) ", value, value->blueprint()->name()->as_utf8());
-+ }
-+};
-+
-+class PrintOopsClosure : public OopClosure {
-+public:
-+ virtual void do_oop(oop* o) {
-+ oop value = *o;
-+ if (value == NULL)
-+ tty->print("null ");
-+ else
-+ tty->print("0x%08x (%s) ", value, value->blueprint()->name()->as_utf8());
-+ }
-+ virtual void do_oop(narrowOop* o) {
-+ }
-+};
-+
-+class DummyCodeBlobClosure : public CodeBlobClosure {
-+ public:
-+ // Called for each code blob.
-+ virtual void do_code_blob(CodeBlob* cb){
-+ }
-+};
-+
-+void dump_frame(activationFrameOop actFrame, JavaThread* thread) {
-+ ResourceMark mark;
-+ tty->print("frame 0x%08X ", actFrame);
-+ if (actFrame->stack_pos() == NULL)
-+ tty->print("(not present on stack) ", actFrame->stack_pos());
-+ else
-+ tty->print("(at stack pos %08x) ", actFrame->stack_pos());
-+ if (actFrame->is_empty())
-+ tty->print("empty ");
-+ if (actFrame->is_filled())
-+ tty->print("filled ");
-+ if (actFrame->is_invalid())
-+ tty->print("invalid ");
-+ if (actFrame->is_delimited())
-+ tty->print("delimited ");
-+
-+ if (actFrame->is_interpreted()) {
-+ methodOop method = actFrame->get_methodOop();
-+ tty->print("interpreted:\n");
-+ tty->print_cr("\t%s", method->name_and_sig_as_C_string());
-+ tty->print("\tbci: %d ", actFrame->bci());
-+ tty->print("locals: %d ", method->max_locals());
-+ tty->print("expressions: %d\n", actFrame->data_count() - method->max_locals());
-+ tty->print("\toops: ");
-+ {
-+ ThreadInVMfromNative tivfn(JavaThread::current());
-+ ActivationFrameInterpreterOopClosure blk(actFrame);
-+ InterpreterOopMap mask;
-+ actFrame->get_methodOop()->mask_for(actFrame->bci(), &mask);
-+ mask.iterate_oop(&blk);
-+ }
-+ tty->cr();
-+ }
-+ if (actFrame->is_compiled()) {
-+ tty->print("compiled: (pc: %08x)\n", actFrame->pc());
-+ if (actFrame->is_filled()) {
-+ frame fr(actFrame->frame_sp(), actFrame->frame_fp(), actFrame->pc());
-+ RegisterMap map(thread);
-+ vframe* frame = vframe::new_vframe(&fr, &map, thread);
-+
-+ dump_compiledVFrame((compiledVFrame*)frame);
-+ while (!frame->is_top()) {
-+ frame = frame->sender();
-+ dump_compiledVFrame((compiledVFrame*)frame);
-+ }
-+ }
-+ tty->print("\toops: ");
-+ {
-+ ThreadInVMfromNative tivfn(JavaThread::current());
-+ PrintOopsClosure closure;
-+ frame fr(actFrame->frame_sp(), actFrame->frame_fp(), actFrame->pc());
-+ RegisterMap map(actFrame->thread());
-+ map.set_include_argument_oops(false);
-+ DummyCodeBlobClosure dummy;
-+ fr.oops_do(&closure, &dummy, &map);
-+ }
-+ tty->cr();
-+ }
-+ if (actFrame->is_dummy()) {
-+ tty->print("dummy frame\n");
-+ }
-+}
-+
-+
-+jobject Continuation_dump(JNIEnv* env, jobject _this) {
-+ tty->print("Continuation::dump\n");
-+ oop simple_cont = JNIHandles::resolve(_this);
-+ activationFrameOop frame = javax_stack_Continuation::data(simple_cont);
-+ while (frame != NULL) {
-+ dump_frame(frame, java_lang_Thread::thread(javax_stack_Continuation::thread(simple_cont)));
-+ frame = frame->next();
-+ }
-+ klassOop k = SystemDictionary::Continuation_klass();
-+ methodOop method = instanceKlass::cast(k)->find_method(vmSymbols::continueDelimitedInternal_name(), vmSymbols::continueDelimited_signature());
-+ return NULL;
-+}
-+
-+void Continuation_resume(JNIEnv* env, jobject _this, jobject value) {
-+ JavaThread* THREAD = JavaThread::current();
-+ ThreadInVMfromNative tivfm(THREAD);
-+
-+ oop thisOop = JNIHandles::resolve(_this);
-+ if (javax_stack_Continuation::data(thisOop) == NULL) {
-+ THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "Cannot resume an empty Continuation");
-+ }
-+ if (javax_stack_Continuation::thread(thisOop) != THREAD->threadObj()) {
-+ THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "Cannot resume a Continuation that belongs to another thread");
-+ }
-+
-+ oop valueOop = JNIHandles::resolve(value);
-+ if (valueOop == javax_stack_Continuation::static_captured()) {
-+ THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "Cannot pass Continuation.CAPTURED to resume");
-+ }
-+ assert(THREAD->current_continuation_frame(), "current_continuation_frame shouldn't be NULL");
-+
-+ // this method is intended only for error handling - all sane cases are covered by the assembler implementation
-+ ShouldNotReachHere();
-+}
-+
-+
-+inline activationFrameOop createAndPatchFrame(frame &fr, TRAPS) {
-+ if (fr.is_compiled_frame()) {
-+ nmethod* nm = (nmethod*)fr.cb();
-+
-+ // native and non-continuable lead to an invalid frame
-+ if (nm->is_native_method() || !nm->method()->constMethod()->is_continuable()) {
-+ goto create_dummy_frame;
-+ }
-+
-+ if (fr.pc() != fr.raw_pc()) {
-+ tty->print("different pc");
-+ }
-+
-+ // determine the address to change the return address to
-+ address adr = nm->continuation_pc_table_begin();
-+ address* entry;
-+ while( adr < nm->continuation_pc_table_end() ) {
-+ entry = (address*)adr;
-+ if (entry[0] == fr.pc()) {
-+ ((address *)fr.sp())[-1] = entry[1];
-+ break;
-+ }
-+ adr += sizeof(address) * 2;
-+ }
-+ assert(adr != nm->continuation_pc_table_end(), "no callsite found in continuable method");
-+
-+ int size = align_object_size(nm->frame_size() + nm->stack_parameter_words() + activationFrameOopDesc::header_size());
-+ assert(size * HeapWordSize == nm->activation_frame_size(), "wrong size");
-+
-+ KlassHandle h_k(Universe::activationFrameKlassObj());
-+ activationFrameOopDesc* af = (activationFrameOop)CollectedHeap::obj_allocate(h_k, size, CHECK_NULL);
-+
-+ af->set_state(activationFrameOopDesc::_compiled_empty);
-+ af->set_nmethod(nm);
-+ af->set_stack_pos(fr.fp());
-+ af->set_thread((JavaThread*)THREAD);
-+ af->set_pc(entry[1]);
-+
-+ assert(af->size() == size, "wrong size");
-+ return af;
-+ }
-+ if (fr.is_interpreted_frame()) {
-+ // method might be invalidated by a safepoint
-+ methodHandle method(fr.interpreter_frame_method());
-+
-+ // native and non-continuable lead to an invalid frame
-+ if (method->is_native() || !method->constMethod()->is_continuable()) {
-+ goto create_dummy_frame;
-+ }
-+ assert(fr.interpreter_frame_monitor_begin() == fr.interpreter_frame_monitor_end(), "cannot handle monitors in continuations");
-+
-+ int data_count = method->max_locals() + fr.interpreter_frame_expression_stack_size();
-+ int size = align_object_size(activationFrameOopDesc::header_size() + data_count * HeapWordSize);
-+
-+ KlassHandle h_k(Universe::activationFrameKlassObj());
-+ activationFrameOopDesc* af = (activationFrameOop)CollectedHeap::obj_allocate(h_k, size, CHECK_NULL);
-+
-+ af->set_state(activationFrameOopDesc::_interpreted_empty);
-+ af->set_stack_pos(fr.fp());
-+ af->set_methodOop(method());
-+ af->set_bci(fr.interpreter_frame_bci());
-+ af->set_data_count(data_count);
-+
-+ assert(((intptr_t*)fr.pc())[-2] == Interpreter::return_sentinel || ((intptr_t*)fr.pc())[-2] == Interpreter::return_sentinel, "missing sentinel");
-+ intptr_t patch_pc = ((intptr_t*)fr.pc())[-3];
-+ ((intptr_t *)fr.sp())[-1] = patch_pc;
-+ af->set_pc((address)patch_pc);
-+
-+ assert(af->size() == size, "wrong size");
-+ return af;
-+ }
-+
-+create_dummy_frame:
-+ int size = align_object_size(activationFrameOopDesc::header_size());
-+
-+ KlassHandle h_k(Universe::activationFrameKlassObj());
-+ activationFrameOopDesc* af = (activationFrameOop)CollectedHeap::obj_allocate(h_k, size, CHECK_NULL);
-+
-+ af->set_state(activationFrameOopDesc::_dummy_invalid);
-+ af->set_stack_pos(fr.fp());
-+ af->set_pc(fr.pc());
-+
-+ assert(af->size() == size, "wrong size");
-+ return af;
-+}
-+
-+int cnt1 = 0;
-+
-+jobject Continuation_save(JNIEnv* env, jobject _this) {
-+ jobject ret = NULL;
-+ {
-+ JavaThread* THREAD = JavaThread::current();
-+ ThreadInVMfromNative tivfm(THREAD);
-+
-+ ret = JNIHandles::make_local(THREAD, javax_stack_Continuation::static_captured());
-+
-+ RegisterMap map(THREAD, false);
-+ frame fr = THREAD->last_frame();
-+ // skip native nmethod
-+ fr = fr.sender(&map);
-+
-+ activationFrameOop af = createAndPatchFrame(fr, CHECK_NULL);
-+ if (af->is_invalid()) {
-+ THROW_MSG_0(vmSymbols::java_lang_IllegalThreadStateException(), "Cannot store continuations in non-continuable methods");
-+ }
-+
-+ activationFrameOopDesc* last = THREAD->current_continuation_frame();
-+ af->set_next(last);
-+ THREAD->set_current_continuation_frame(af);
-+
-+// tty->print("save %i: %08x -> %08x\n", cnt1++, THREAD->current_continuation_frame(), THREAD->current_continuation_frame()->next());
-+
-+ if (_this != NULL) {
-+ javax_stack_Continuation::set_data(JNIHandles::resolve(_this), af);
-+ javax_stack_Continuation::set_thread(JNIHandles::resolve(_this), THREAD->threadObj());
-+ }
-+ }
-+ return ret;
-+}
-+
-+class MyObjClosure: public ObjectClosure {
-+ virtual void do_object(oop obj) {
-+ int* i = (int*)obj;
-+ if (i == NULL)
-+ return;
-+ if (i[0] == (int)0xbaadbabe || i[1] == (int)0xbaadbabe) {
-+ tty->print("bad");
-+ }
-+
-+ int interp = 0;
-+ int compiled = 0;
-+ int dummy = 0;
-+ if (obj->is_activationFrame()) {
-+ activationFrameOop af = (activationFrameOop)obj;
-+ if (af->is_interpreted())
-+ interp++;
-+ if (af->is_compiled())
-+ compiled++;
-+ if (af->is_dummy())
-+ dummy++;
-+ }
-+ //tty->print("stats: %i interp, %i compiled, %i dummy\n", interp, compiled, dummy);
-+ }
-+};
-+
-+class MyOopClosure: public OopClosure {
-+ virtual void do_oop(oop* obj) {
-+ int* i = (int*)*obj;
-+ if (i == NULL)
-+ return;
-+ if (i[0] == (int)0xbaadbabe || i[1] == (int)0xbaadbabe) {
-+ tty->print("bad");
-+ }
-+ }
-+ virtual void do_oop(narrowOop* obj) {
-+ }
-+};
-+
-+int cnt2 = 0;
-+
-+inline void Continuation_storeFrameGeneric(JNIEnv* env) {
-+ JavaThread* THREAD = JavaThread::current();
-+ ThreadInVMfromNative tivfm(THREAD);
-+
-+// tty->print("storeframe %i: %08x -> %08x\n", cnt2++, THREAD->current_continuation_frame(), THREAD->current_continuation_frame()->next());
-+ RegisterMap map(THREAD, false);
-+ // skip native nmethod
-+ frame fr = THREAD->last_frame().sender(&map);
-+
-+ // save the frame contents
-+ activationFrameOopDesc* fill = THREAD->current_continuation_frame();
-+ assert(fill, "Continuation_storeFrameGeneric called without current AF");
-+
-+ if (Universe::heap()->total_collections() > 10) {
-+ MyOopClosure ocl;
-+ MyObjClosure cl;
-+// Universe::heap()->oop_iterate(&ocl);
-+// Universe::heap()->object_iterate(&cl);
-+ }
-+
-+ if (fill->is_filled()) {
-+ // just mark the frame as "not on stack"
-+ fill->set_stack_pos(NULL);
-+
-+ } else if (fill->is_empty()) {
-+
-+ if (fill->state() == activationFrameOopDesc::_compiled_empty) {
-+ // copy the contents of a compiled frame
-+
-+ jint size = fill->get_nmethod()->frame_size() + fill->get_nmethod()->stack_parameter_words();
-+ intptr_t* sp = fr.unextended_sp();
-+ assert(fill->stack_pos() == fr.fp(), "trying to fill the wrong activationFrameOop");
-+ memcpy(fill->frame_sp(), sp, size * HeapWordSize);
-+ fill->set_state(activationFrameOopDesc::_compiled_filled);
-+ fill->set_stack_pos(NULL);
-+ // TODO this only works with simple cardset barriers...?
-+ oopDesc::bs()->write_ref_field(fill->frame_sp(), NULL);
-+
-+ } else if (fill->state() == activationFrameOopDesc::_interpreted_empty) {
-+ // copy the contents of an interpreted frame: locals, expression stack
-+
-+ assert(fill->data_count() == (fr.interpreter_frame_method()->max_locals() + fr.interpreter_frame_expression_stack_size()), "wrong data count");
-+ assert(fill->stack_pos() == fr.fp(), "wrong actual frame");
-+ int max_locals = fill->get_methodOop()->max_locals();
-+ for (int i=0; i<max_locals; i++) {
-+ fill->set_value(i, *fr.interpreter_frame_local_at(i));
-+ }
-+ for (int i=max_locals; i<fill->data_count(); i++) {
-+ int entry = i - max_locals;
-+ fill->set_value(i, *fr.interpreter_frame_expression_stack_at(entry));
-+ }
-+ fill->set_state(activationFrameOopDesc::_interpreted_filled);
-+ fill->set_stack_pos(NULL);
-+ oopDesc::bs()->write_ref_field(fill, NULL);
-+
-+ } else {
-+ ShouldNotReachHere();
-+ }
-+
-+ } else if (fill->is_invalid()) {
-+
-+ if (THREAD->resume_common_frame() != NULL) {
-+ // we've encountered an invalid frame while resuming
-+ THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "Invalid frame encountered during resume");
-+ } else {
-+ // skip invalid frames
-+ do {
-+ fill->set_stack_pos(NULL);
-+ fill = fill->next();
-+// tty->print("invalid frame encountered (normal operation)\n");
-+ } while(fill->is_invalid());
-+ THREAD->set_current_continuation_frame(fill);
-+ }
-+
-+ }
-+
-+ activationFrameHandle first_frame;
-+ activationFrameHandle current(fill);
-+ do {
-+ fr = fr.sender(&map);
-+ if (current->next() != NULL && current->next()->stack_pos() == fr.fp()) {
-+#ifdef ASSERT
-+ activationFrameOop next = current->next();
-+ if (next->is_interpreted() || next->is_compiled()) {
-+ if (fr.raw_pc() != current->next()->pc()) {
-+ tty->print("different pc");
-+ }
-+ }
-+#endif
-+ // the next activationFrame already corresponds to the next stackframe, nothing to do...
-+ if (first_frame.is_null())
-+ first_frame = current->next();
-+ //tty->print("Continuation_storeFrameGeneric: no need to create new object\n");
-+ break;
-+ } else {
-+ activationFrameOop af = createAndPatchFrame(fr, CHECK);
-+
-+ if (af->is_invalid() && THREAD->resume_common_frame() != NULL)
-+ Exceptions::_throw_msg(THREAD_AND_LOCATION, vmSymbols::java_lang_IllegalArgumentException(), "Invalid frame encountered during resume");
-+
-+ af->set_next(current->next());
-+ current->set_next(af);
-+ oopDesc::bs()->write_ref_field(((char*)current()) + in_bytes(activationFrameOopDesc::next_offset()), af);
-+
-+ if (first_frame.is_null())
-+ first_frame = af;
-+ current = af;
-+ }
-+ } while(current->is_invalid() && !fr.is_entry_frame());
-+ THREAD->set_current_continuation_frame(first_frame());
-+}
-+
-+jobject Continuation_storeFrameObject(JNIEnv* env, jclass klass, jobject retValue) {
-+ Continuation_storeFrameGeneric(env);
-+ return retValue;
-+}
-+
-+void Continuation_storeFrameVoid(JNIEnv* env, jclass klass) {
-+ Continuation_storeFrameGeneric(env);
-+}
-+
-+jboolean Continuation_storeFrameBoolean(JNIEnv* env, jclass klass, jboolean retValue) {
-+ Continuation_storeFrameGeneric(env);
-+ return retValue;
-+}
-+
-+jbyte Continuation_storeFrameByte(JNIEnv* env, jclass klass, jbyte retValue) {
-+ Continuation_storeFrameGeneric(env);
-+ return retValue;
-+}
-+
-+jchar Continuation_storeFrameChar(JNIEnv* env, jclass klass, jchar retValue) {
-+ Continuation_storeFrameGeneric(env);
-+ return retValue;
-+}
-+
-+jshort Continuation_storeFrameShort(JNIEnv* env, jclass klass, jshort retValue) {
-+ Continuation_storeFrameGeneric(env);
-+ return retValue;
-+}
-+
-+jint Continuation_storeFrameInt(JNIEnv* env, jclass klass, jint retValue) {
-+ Continuation_storeFrameGeneric(env);
-+ return retValue;
-+}
-+
-+jlong Continuation_storeFrameLong(JNIEnv* env, jclass klass, jlong retValue) {
-+ Continuation_storeFrameGeneric(env);
-+ return retValue;
-+}
-+
-+jfloat Continuation_storeFrameFloat(JNIEnv* env, jclass klass, jfloat retValue) {
-+ Continuation_storeFrameGeneric(env);
-+ return retValue;
-+}
-+
-+jdouble Continuation_storeFrameDouble(JNIEnv* env, jclass klass, jdouble retValue) {
-+ Continuation_storeFrameGeneric(env);
-+ return retValue;
-+}
-+
-+jobject Continuation_unwind(JNIEnv* env, jclass klass, jobject exception) {
-+ JavaThread* THREAD = JavaThread::current();
-+ RegisterMap map(THREAD, false);
-+ frame fr = THREAD->last_frame().sender(&map);
-+ activationFrameOopDesc* fill = THREAD->current_continuation_frame();
-+ if (fill->stack_pos() == fr.fp())
-+ Continuation_storeFrameGeneric(env);
-+
-+ THROW_OOP_0(JNIHandles::resolve(exception));
-+}
-+
-+jobject Continuation_startDelimited(JNIEnv* env, jclass klass, jobject runnable, jobject firstValue) {
-+ ShouldNotReachHere();
-+
-+ // everything should be handled by the asm implementation
-+ JavaThread* thread = JavaThread::current();
-+
-+ jmethodID method = env->GetStaticMethodID(klass, "startDelimitedInternal", "(Ljavax/stack/DelimitedRunnable;Ljava/lang/Object;)Ljava/lang/Object;");
-+ jobject retValue = env->CallStaticObjectMethod(klass, method, runnable, firstValue);
-+
-+ activationFrameOop af = thread->current_continuation_frame();
-+ assert(af->state() == activationFrameOopDesc::_dummy_invalid, "invalid frame state after startDelimitedInternal");
-+
-+ thread->set_current_continuation_frame(af->next());
-+ af->set_state(activationFrameOopDesc::_dummy_delimited);
-+ af->set_in_use(false);
-+ af->set_stack_pos(NULL);
-+ af->set_next(NULL);
-+ oopDesc::bs()->write_ref_field(((char*)af) + in_bytes(activationFrameOopDesc::next_offset()), NULL);
-+
-+ return retValue;
-+}
-+
-+jobject Continuation_continueDelimited(JNIEnv* env, jclass klass, jobject continuation, jobject value) {
-+ JavaThread* THREAD = JavaThread::current();
-+ DEBUG_ONLY(activationFrameHandle check_frame;)
-+
-+ oop contOop = JNIHandles::resolve(continuation);
-+ if (javax_stack_Continuation::data(contOop) == NULL) {
-+ THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(), "Cannot resume an empty Continuation", NULL);
-+ }
-+ if (javax_stack_Continuation::thread(contOop) != THREAD->threadObj()) {
-+ THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(), "Cannot resume a Continuation that belongs to another thread", NULL);
-+ }
-+
-+ activationFrameOop af = javax_stack_Continuation::data(contOop);
-+ while (af->next() != NULL) {
-+ af = af->next();
-+ }
-+
-+ if (af->state() != activationFrameOopDesc::_dummy_delimited) {
-+ THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(), "Continuation is not delimited", NULL);
-+ }
-+ if (af->in_use()) {
-+ THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(), "Nested delimited continuation", NULL);
-+ }
-+
-+ ShouldNotReachHere();
-+
-+ return NULL;
-+}
-+
-+
- /// JVM_RegisterUnsafeMethods
-
- #define ADR "J"
-@@ -1457,6 +1985,29 @@
- {CC"defineAnonymousClass", CC"("DAC_Args")"CLS, FN_PTR(Unsafe_DefineAnonymousClass)},
- };
-
-+#define CONT "Ljavax/stack/Continuation;"
-+#define RUN "Ljavax/stack/DelimitedRunnable;"
-+JNINativeMethod simple_cont_methods[] = {
-+ {CC"save", CC"()"OBJ, FN_PTR(Continuation_save)},
-+ {CC"resume", CC"("OBJ")V", FN_PTR(Continuation_resume)},
-+ {CC"dump", CC"()"OBJ, FN_PTR(Continuation_dump)},
-+ {CC"startDelimited", CC"("RUN OBJ")"OBJ, FN_PTR(Continuation_startDelimited)},
-+ {CC"continueDelimited", CC"("CONT OBJ")"OBJ, FN_PTR(Continuation_continueDelimited)},
-+ {CC"unwind", CC"("THR")"THR, FN_PTR(Continuation_unwind)},
-+ {CC"storeFrameObject", CC"("OBJ")"OBJ, FN_PTR(Continuation_storeFrameObject)},
-+ {CC"storeFrameVoid", CC"()V", FN_PTR(Continuation_storeFrameVoid)},
-+ {CC"storeFrameBoolean", CC"(Z)Z", FN_PTR(Continuation_storeFrameBoolean)},
-+ {CC"storeFrameByte", CC"(B)B", FN_PTR(Continuation_storeFrameByte)},
-+ {CC"storeFrameChar", CC"(C)C", FN_PTR(Continuation_storeFrameChar)},
-+ {CC"storeFrameShort", CC"(S)S", FN_PTR(Continuation_storeFrameShort)},
-+ {CC"storeFrameInt", CC"(I)I", FN_PTR(Continuation_storeFrameInt)},
-+ {CC"storeFrameLong", CC"(J)J", FN_PTR(Continuation_storeFrameLong)},
-+ {CC"storeFrameFloat", CC"(F)F", FN_PTR(Continuation_storeFrameFloat)},
-+ {CC"storeFrameDouble", CC"(D)D", FN_PTR(Continuation_storeFrameDouble)}
-+};
-+#undef RUN
-+#undef CONT
-+
- #undef CC
- #undef FN_PTR
-
-@@ -1555,3 +2106,45 @@
- guarantee(status == 0, "register unsafe natives");
- }
- JVM_END
-+
-+#define SIMPLE_CONT_METHOD_COUNT (sizeof(simple_cont_methods)/sizeof(JNINativeMethod))
-+
-+JVM_ENTRY(void, JVM_RegisterContinuationMethods(JNIEnv *env, jclass contcls))
-+ UnsafeWrapper("JVM_RegisterContinuationMethods");
-+ {
-+ ThreadToNativeFromVM ttnfv(thread);
-+ {
-+ env->RegisterNatives(contcls, simple_cont_methods, sizeof(simple_cont_methods)/sizeof(JNINativeMethod));
-+ if (env->ExceptionOccurred()) {
-+ if (PrintMiscellaneous && (Verbose || WizardMode)) {
-+ tty->print_cr("Warning: SDK 1.7 Continuation classes not found.");
-+ }
-+ env->ExceptionClear();
-+ } else {
-+ // compile all native wrappers - the first three are instance methods, all other static
-+ jmethodID ids[SIMPLE_CONT_METHOD_COUNT];
-+ for (unsigned int i=0; i<SIMPLE_CONT_METHOD_COUNT; i++) {
-+ if (i >= 3)
-+ ids[i] = env->GetStaticMethodID(contcls, simple_cont_methods[i].name, simple_cont_methods[i].signature);
-+ else
-+ ids[i] = env->GetMethodID(contcls, simple_cont_methods[i].name, simple_cont_methods[i].signature);
-+ }
-+ {
-+ ThreadInVMfromNative tivfn(thread);
-+ for (unsigned int i=0; i<SIMPLE_CONT_METHOD_COUNT; i++) {
-+ nmethod* nm = AdapterHandlerLibrary::create_native_wrapper(methodHandle(JNIHandles::resolve_jmethod_id(ids[i])));
-+ if (strncmp("storeFrame", simple_cont_methods[i].name, 10) == 0)
-+ javax_stack_Continuation::set_store_frames_nmethod(nm->method()->result_type(), nm);
-+ if (strcmp("resume", simple_cont_methods[i].name) == 0)
-+ javax_stack_Continuation::set_resume_nmethod(nm);
-+ if (strcmp("save", simple_cont_methods[i].name) == 0)
-+ javax_stack_Continuation::set_save_nmethod(nm);
-+ if (strcmp("unwind", simple_cont_methods[i].name) == 0)
-+ javax_stack_Continuation::set_unwind_nmethod(nm);
-+
-+ }
-+ }
-+ }
-+ }
-+ }
-+JVM_END
-diff --git a/src/share/vm/runtime/annotationParser.cpp b/src/share/vm/runtime/annotationParser.cpp
-new file mode 100644
---- /dev/null
-+++ b/src/share/vm/runtime/annotationParser.cpp
-@@ -0,0 +1,186 @@
-+
-+# include "incls/_precompiled.incl"
-+# include "incls/_annotationParser.cpp.incl"
-+
-+bool ElementValue::verify(symbolOop value_signature, int offset, TRAPS) {
-+ AnnotationParser* parser = _annotation->_parser;
-+ if (parser->length() < _start + 3)
-+ return false;
-+ if (offset >= value_signature->utf8_length())
-+ return false;
-+
-+ klassOop value_type;
-+ if (value_signature->byte_at(offset) == 'L')
-+ value_type = parser->get_klass(oopFactory::new_symbol((char*)value_signature->base() + offset, value_signature->utf8_length() - offset, THREAD), THREAD);
-+ else
-+ value_type = NULL;
-+
-+ switch(tag()) {
-+ case 'B':
-+ case 'C':
-+ case 'I':
-+ case 'S':
-+ case 'Z':
-+ return value_signature->byte_at(offset) == tag() && parser->get_tag(_start + 1).is_int();
-+ case 'D':
-+ return value_signature->byte_at(offset) == tag() && parser->get_tag(_start + 1).is_double();
-+ case 'F':
-+ return value_signature->byte_at(offset) == tag() && parser->get_tag(_start + 1).is_float();
-+ case 'J':
-+ return value_signature->byte_at(offset) == tag() && parser->get_tag(_start + 1).is_long();
-+ case 's':
-+ if (!parser->get_tag(_start + 1).is_utf8())
-+ return false;
-+ // check that the signature return type can hold a string
-+ return value_type != NULL && SystemDictionary::String_klass()->klass_part()->is_subtype_of(value_type);
-+ case 'c':
-+ if (!parser->get_tag(_start + 1).is_utf8())
-+ return false;
-+ if (parser->get_klass(_start + 1, THREAD) == NULL)
-+ return false;
-+ // check that the signature return type can hold a class
-+ return value_type != NULL && SystemDictionary::Class_klass()->klass_part()->is_subtype_of(value_type);
-+ case 'e':
-+ {
-+ if (parser->length() < _start + 5)
-+ return false;
-+ if (!parser->get_tag(_start + 1).is_utf8() || !parser->get_tag(_start + 3).is_utf8())
-+ return false;
-+ klassOop enum_type = parser->get_klass(_start + 1, THREAD);
-+ if (enum_type == NULL)
-+ return false;
-+ symbolOop enum_const_name = parser->get_symbol(_start + 3);
-+ if (value_type == NULL || !enum_type->klass_part()->is_subtype_of(value_type))
-+ return false;
-+ if (!parser->has_enum_field(instanceKlass::cast(enum_type), enum_const_name))
-+ return false;
-+ return true;
-+ }
-+ case '@':
-+ {
-+ Annotation annotation;
-+ annotation_const(annotation);
-+ if (annotation.verify(THREAD)) {
-+ return value_type != NULL && annotation.get_type(THREAD)->klass_part()->is_subtype_of(value_type);
-+ } else
-+ return false;
-+ }
-+ case '[':
-+ {
-+ if (value_signature->byte_at(offset) != '[')
-+ return false;
-+ ArrayValue array;
-+ array_const(array);
-+ return array.verify(value_signature, offset + 1, THREAD);
-+ }
-+ default:
-+ return false;
-+ }
-+}
-+
-+bool ArrayValue::verify(symbolOop component_signature, int offset, TRAPS) {
-+ AnnotationParser* parser = _value->_annotation->_parser;
-+ if (parser->length() < _start + 2)
-+ return false;
-+
-+ ElementValue value = first_value();
-+ for (int i=value_count(); i>0; i--) {
-+ if (!value.verify(component_signature, offset, THREAD))
-+ return false;
-+ value = next_value(value, THREAD);
-+ }
-+ return true;
-+}
-+
-+bool ElementValuePair::verify(instanceKlass* annotation_type, TRAPS) {
-+ AnnotationParser* parser = _value._annotation->_parser;
-+ if (parser->length() < start() + 2)
-+ return false;
-+
-+ if (!parser->get_tag(start()).is_utf8())
-+ return false;
-+ methodOop value = parser->find_method(annotation_type, name());
-+ if (value == NULL)
-+ return false;
-+ if (!value->is_abstract())
-+ return false;
-+ symbolOop signature = value->signature();
-+ if (signature->byte_at(0) != '(' || signature->byte_at(1) != ')')
-+ return false;
-+
-+ return _value.verify(signature, 2, THREAD);
-+}
-+
-+bool Annotation::verify(TRAPS) {
-+ if (_parser->length() < _start + 4)
-+ return false;
-+
-+ if (!_parser->get_tag(_start).is_utf8())
-+ return false;
-+ klassOop type = get_type(THREAD);
-+ if (type == NULL)
-+ return false;
-+ instanceKlass* klass = instanceKlass::cast(type);
-+ // type needs to be an annotation type
-+ if ((klass->access_flags().get_flags() & JVM_ACC_ANNOTATION) == 0)
-+ return false;
-+
-+ ElementValuePair value = first_value();
-+ for (int i=value_count(); i>0; i--) {
-+ if (!value.verify(klass, THREAD))
-+ return false;
-+ value = next_value(value, THREAD);
-+ }
-+ return true;
-+}
-+
-+bool AnnotationParser::verify(TRAPS) {
-+ if (length() < 2)
-+ return false;
-+ Annotation annotation = first_annotation();
-+ for (int i=annotation_count(); i>0; i--) {
-+ if (!annotation.verify(THREAD))
-+ return false;
-+ annotation = next_annotation(annotation, THREAD);
-+ }
-+ return annotation._start == length();
-+}
-+
-+
-+methodOop AnnotationParser::find_method(instanceKlass* klass, symbolOop name) {
-+ objArrayOop methods = klass->methods();
-+ int len = methods->length();
-+ // methods are sorted, so do binary search
-+ int l = 0;
-+ int h = len - 1;
-+ while (l <= h) {
-+ int mid = (l + h) >> 1;
-+ methodOop m = (methodOop)methods->obj_at(mid);
-+ assert(m->is_method(), "must be method");
-+ int res = m->name()->fast_compare(name);
-+ if (res == 0) {
-+ return m;
-+ } else if (res < 0) {
-+ l = mid + 1;
-+ } else {
-+ h = mid - 1;
-+ }
-+ }
-+ return NULL;
-+}
-+
-+bool AnnotationParser::has_enum_field(instanceKlass* klass, symbolOop name) {
-+ typeArrayOop fields = klass->fields();
-+ constantPoolOop constants = klass->constants();
-+ const int n = fields->length();
-+ for (int i = 0; i < n; i += instanceKlass::next_offset ) {
-+ int name_index = fields->ushort_at(i + instanceKlass::name_index_offset);
-+ symbolOop f_name = constants->symbol_at(name_index);
-+ if (f_name == name) {
-+ return (fields->ushort_at(i + instanceKlass::access_flags_offset) & JVM_ACC_ENUM) != 0;
-+ }
-+ }
-+ return false;
-+}
-+
-+
-diff --git a/src/share/vm/runtime/annotationParser.hpp b/src/share/vm/runtime/annotationParser.hpp
-new file mode 100644
---- /dev/null
-+++ b/src/share/vm/runtime/annotationParser.hpp
-@@ -0,0 +1,316 @@
-+
-+class ElementValue;
-+class ArrayValue;
-+class ElementValuePair;
-+class Annotation;
-+class AnnotationParser;
-+
-+class ElementValue: public StackObj {
-+ private:
-+ int _start;
-+ int _length;
-+ Annotation* _annotation;
-+
-+ int length(TRAPS);
-+ ElementValue(int start, Annotation* annotation) : _start(start), _length(-1), _annotation(annotation) { }
-+ friend class ArrayValue;
-+ friend class ElementValuePair;
-+ public:
-+
-+ char tag();
-+
-+ jint int_const();
-+ jlong long_const();
-+ jfloat float_const();
-+ jdouble double_const();
-+ symbolOop string_const();
-+ klassOop enum_const_type(TRAPS);
-+ symbolOop enum_const_name();
-+ klassOop klass_const(TRAPS);
-+ // using output parameter to avoid circular dependency
-+ void annotation_const(Annotation& annotation);
-+ void array_const(ArrayValue& array);
-+
-+ bool verify(symbolOop value_signature, int offset, TRAPS);
-+};
-+
-+class ArrayValue: public StackObj {
-+ private:
-+ int _start;
-+ int _length;
-+ ElementValue* _value;
-+
-+ int length(TRAPS);
-+ ArrayValue() { }
-+ ArrayValue(int start, ElementValue* value) : _start(start), _length(-1), _value(value) { }
-+ friend class ElementValue;
-+ public:
-+
-+ u2 value_count();
-+ ElementValue first_value();
-+ ElementValue next_value(ElementValue& value, TRAPS);
-+
-+ bool verify(symbolOop component_signature, int offset, TRAPS);
-+};
-+
-+class ElementValuePair: public StackObj {
-+ private:
-+ ElementValue _value;
-+
-+ int start();
-+ int length(TRAPS);
-+ ElementValuePair(int start, Annotation* annotation) : _value(start + 2, annotation) { }
-+ friend class Annotation;
-+ public:
-+
-+ symbolOop name();
-+ ElementValue& value();
-+
-+ bool verify(instanceKlass* annotation_type, TRAPS);
-+};
-+
-+class Annotation: public StackObj {
-+ private:
-+ int _start;
-+ int _length;
-+ AnnotationParser* _parser;
-+
-+ int length(TRAPS);
-+ Annotation() { }
-+ Annotation(int start, AnnotationParser* parser) : _start(start), _length(-1), _parser(parser) { }
-+ friend class AnnotationParser;
-+ friend class ArrayValue;
-+ friend class ElementValue;
-+ friend class ElementValuePair;
-+ public:
-+ u2 value_count();
-+ ElementValuePair first_value();
-+ ElementValuePair next_value(ElementValuePair& value, TRAPS);
-+
-+ klassOop get_type(TRAPS);
-+ symbolOop get_type_name();
-+
-+ bool verify(TRAPS);
-+};
-+
-+class AnnotationParser: public StackObj {
-+ private:
-+ typeArrayHandle _array;
-+ constantPoolHandle _constants;
-+
-+ int length() {
-+ return _array->length();
-+ }
-+ u1 get_u1(int index) {
-+ return _array->byte_at(index);
-+ }
-+ u2 get_u2(int index) {
-+ return Bytes::get_Java_u2((u1*)_array->byte_at_addr(index));
-+ }
-+ symbolOop get_symbol(int index) {
-+ return _constants->symbol_at(get_u2(index));
-+ }
-+ klassOop get_klass(int index, TRAPS) {
-+ Klass* holder = _constants->pool_holder()->klass_part();
-+ return SystemDictionary::resolve_or_null(get_symbol(index), holder->class_loader(), holder->protection_domain(), THREAD);
-+ }
-+ klassOop get_klass(symbolOop name, TRAPS) {
-+ Klass* holder = _constants->pool_holder()->klass_part();
-+ return SystemDictionary::resolve_or_null(name, holder->class_loader(), holder->protection_domain(), THREAD);
-+ }
-+
-+ constantTag get_tag(int index) {
-+ if (index < 0 || index >= length())
-+ return constantTag(JVM_CONSTANT_Invalid);
-+ else {
-+ u2 cp_index = get_u2(index);
-+ if (/*cp_index < 0 ||*/ cp_index >= _constants->length())
-+ return constantTag(JVM_CONSTANT_Invalid);
-+ else
-+ return _constants->tag_at(cp_index);
-+ }
-+ }
-+
-+ friend class Annotation;
-+ friend class ArrayValue;
-+ friend class ElementValue;
-+ friend class ElementValuePair;
-+ public:
-+ AnnotationParser(typeArrayHandle annotations, constantPoolHandle constants)
-+ : _array(annotations), _constants(constants) {
-+ }
-+
-+ u2 annotation_count() {
-+ return get_u2(0);
-+ }
-+ Annotation first_annotation() {
-+ return Annotation(2, this);
-+ }
-+ Annotation next_annotation(Annotation& ann, TRAPS) {
-+ return Annotation(ann._start + ann.length(THREAD), this);
-+ }
-+
-+ bool verify(TRAPS);
-+
-+ methodOop find_method(instanceKlass* klass, symbolOop name);
-+ bool has_enum_field(instanceKlass* klass, symbolOop name);
-+};
-+
-+
-+// ElementValue inline functions
-+
-+inline int ElementValue::length(TRAPS) {
-+ if (_length == -1) {
-+ switch(tag()) {
-+ case 'B':
-+ case 'C':
-+ case 'I':
-+ case 'S':
-+ case 'Z':
-+ case 'D':
-+ case 'F':
-+ case 'J':
-+ case 's':
-+ case 'c':
-+ _length = 3;
-+ break;
-+ case 'e':
-+ _length = 5;
-+ break;
-+ case '@':
-+ {
-+ Annotation annotation;
-+ annotation_const(annotation);
-+ _length = annotation.length(THREAD) + 1;
-+ break;
-+ }
-+ case '[':
-+ {
-+ ArrayValue array;
-+ array_const(array);
-+ _length = array.length(THREAD) + 1;
-+ break;
-+ }
-+ break;
-+ default:
-+ ShouldNotReachHere();
-+ break;
-+ }
-+ }
-+ return _length;
-+}
-+inline char ElementValue::tag() {
-+ return _annotation->_parser->get_u1(_start);
-+}
-+inline jint ElementValue::int_const() {
-+ return _annotation->_parser->_constants->int_at(_annotation->_parser->get_u2(_start + 1));
-+}
-+inline jlong ElementValue::long_const() {
-+ return _annotation->_parser->_constants->long_at(_annotation->_parser->get_u2(_start + 1));
-+}
-+inline jfloat ElementValue::float_const() {
-+ return _annotation->_parser->_constants->float_at(_annotation->_parser->get_u2(_start + 1));
-+}
-+inline jdouble ElementValue::double_const() {
-+ return _annotation->_parser->_constants->double_at(_annotation->_parser->get_u2(_start + 1));
-+}
-+inline symbolOop ElementValue::string_const() {
-+ return _annotation->_parser->_constants->symbol_at(_annotation->_parser->get_u2(_start + 1));
-+}
-+inline klassOop ElementValue::enum_const_type(TRAPS) {
-+ return _annotation->_parser->get_klass(_start + 1, THREAD);
-+}
-+inline symbolOop ElementValue::enum_const_name() {
-+ return _annotation->_parser->get_symbol(_start + 3);
-+}
-+inline klassOop ElementValue::klass_const(TRAPS) {
-+ return _annotation->_parser->get_klass(_start + 1, THREAD);
-+}
-+inline void ElementValue::annotation_const(Annotation& annotation) {
-+ annotation = Annotation(_start + 1, _annotation->_parser);
-+}
-+inline void ElementValue::array_const(ArrayValue& array) {
-+ array = ArrayValue(_start + 1, this);
-+}
-+
-+// ArrayValue inline functions
-+
-+inline u2 ArrayValue::value_count() {
-+ return _value->_annotation->_parser->get_u2(_start);
-+}
-+inline int ArrayValue::length(TRAPS) {
-+ if (_length == -1) {
-+ // u2 num_values
-+ _length = 2;
-+ ElementValue value = first_value();
-+ for (int i=value_count(); i>0; i--) {
-+ _length += value.length(THREAD);
-+ value = next_value(value, THREAD);
-+ }
-+ }
-+ return _length;
-+}
-+inline ElementValue ArrayValue::first_value() {
-+ return ElementValue(_start + 2, _value->_annotation);
-+}
-+inline ElementValue ArrayValue::next_value(ElementValue& value, TRAPS) {
-+ return ElementValue(value._start + value.length(THREAD), _value->_annotation);
-+}
-+
-+// ElementValuePair inline functions
-+inline int ElementValuePair::start() {
-+ return _value._start - 2;
-+}
-+inline int ElementValuePair::length(TRAPS) {
-+ return _value.length(THREAD) + 2;
-+}
-+inline symbolOop ElementValuePair::name() {
-+ return _value._annotation->_parser->get_symbol(start());
-+}
-+inline ElementValue& ElementValuePair::value() {
-+ return _value;
-+}
-+
-+// Annotation inline functions
-+
-+inline int Annotation::length(TRAPS) {
-+ if (_length == -1) {
-+ // u2 type_index and u2 num_element_value_pairs
-+ _length = 4;
-+ ElementValuePair value = first_value();
-+ for (int i=value_count(); i>0; i--) {
-+ _length += value.length(THREAD);
-+ value = next_value(value, THREAD);
-+ }
-+ }
-+ return _length;
-+}
-+inline u2 Annotation::value_count() {
-+ return _parser->get_u2(_start + 2);
-+}
-+inline ElementValuePair Annotation::first_value() {
-+ return ElementValuePair(_start + 4, this);
-+}
-+inline ElementValuePair Annotation::next_value(ElementValuePair& value, TRAPS) {
-+ return ElementValuePair(value.start() + value.length(THREAD), this);
-+}
-+inline klassOop Annotation::get_type(TRAPS) {
-+ return _parser->get_klass(_start, THREAD);
-+}
-+inline symbolOop Annotation::get_type_name() {
-+ return _parser->get_symbol(_start);
-+}
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-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
-@@ -180,6 +180,7 @@
- };
-
-
-+DEF_HANDLE(activationFrame , is_activationFrame )
- DEF_HANDLE(instance , is_instance )
- DEF_HANDLE(method , is_method )
- DEF_HANDLE(constMethod , is_constMethod )
-@@ -216,6 +217,7 @@
- };
-
-
-+DEF_KLASS_HANDLE(activationFrameKlass , oop_is_activationFrame )
- DEF_KLASS_HANDLE(instanceKlass , oop_is_instance_slow )
- DEF_KLASS_HANDLE(methodKlass , oop_is_method )
- DEF_KLASS_HANDLE(constMethodKlass , oop_is_constMethod )
-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
-@@ -1177,6 +1177,10 @@
- _interp_only_mode = 0;
- _special_runtime_exit_condition = _no_async_condition;
- _pending_async_exception = NULL;
-+ _current_continuation_frame = NULL;
-+ _resume_continuation_frame = NULL;
-+ _resume_common_frame = NULL;
-+ _resume_return_value = NULL;
- _is_compiling = false;
- _thread_stat = NULL;
- _thread_stat = new ThreadStatistics();
-@@ -2418,6 +2422,10 @@
- f->do_oop((oop*) &_vm_result_2);
- f->do_oop((oop*) &_exception_oop);
- f->do_oop((oop*) &_pending_async_exception);
-+ f->do_oop((oop*) &_current_continuation_frame);
-+ f->do_oop((oop*) &_resume_continuation_frame);
-+ f->do_oop((oop*) &_resume_common_frame);
-+ f->do_oop((oop*) &_resume_return_value);
-
- if (jvmti_thread_state() != NULL) {
- jvmti_thread_state()->oops_do(f);
-@@ -3015,6 +3023,10 @@
- warning("java.lang.String not initialized");
- }
-
-+ klassOop cont_klass = SystemDictionary::resolve_or_null(vmSymbolHandles::javax_stack_Continuation(), CHECK_0);
-+ if (cont_klass != NULL)
-+ instanceKlass::cast(cont_klass)->initialize(CHECK_0);
-+
- if (AggressiveOpts) {
- {
- // Forcibly initialize java/util/HashMap and mutate the private
-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
-@@ -787,6 +787,32 @@
- // This is set to popframe_pending to signal that top Java frame should be popped immediately
- int _popframe_condition;
-
-+ //// continuation support
-+ activationFrameOop _current_continuation_frame;
-+ activationFrameOop _resume_continuation_frame;
-+ activationFrameOop _resume_common_frame;
-+ oop _resume_return_value;
-+
-+ public:
-+ static ByteSize current_continuation_frame_offset() { return byte_offset_of(JavaThread, _current_continuation_frame); }
-+ static ByteSize resume_continuation_frame_offset() { return byte_offset_of(JavaThread, _resume_continuation_frame); }
-+ static ByteSize resume_common_frame_offset() { return byte_offset_of(JavaThread, _resume_common_frame); }
-+ static ByteSize resume_return_value_offset() { return byte_offset_of(JavaThread, _resume_return_value); }
-+
-+ activationFrameOop current_continuation_frame() const { return _current_continuation_frame; }
-+ void set_current_continuation_frame (activationFrameOop x) { _current_continuation_frame = x; }
-+
-+ activationFrameOop resume_continuation_frame() const { return _resume_continuation_frame; }
-+ void set_resume_continuation_frame (activationFrameOop x) { _resume_continuation_frame = x; }
-+
-+ activationFrameOop resume_common_frame() const { return _resume_common_frame; }
-+ void set_resume_common_frame (activationFrameOop x) { _resume_common_frame = x; }
-+
-+ oop resume_return_value() const { return _resume_return_value; }
-+ void set_resume_return_value (oop x) { _resume_return_value = x; }
-+
-+ private:
-+
- #ifndef PRODUCT
- int _jmp_ring_index;
- struct {
-diff --git a/src/share/vm/runtime/vmStructs.cpp b/src/share/vm/runtime/vmStructs.cpp
---- a/src/share/vm/runtime/vmStructs.cpp
-+++ b/src/share/vm/runtime/vmStructs.cpp
-@@ -939,6 +939,8 @@
- declare_type(methodKlass, Klass) \
- declare_type(constMethodKlass, Klass) \
- declare_type(methodOopDesc, oopDesc) \
-+ declare_type(activationFrameKlass, Klass) \
-+ declare_type(activationFrameOopDesc, oopDesc) \
- declare_type(objArrayKlass, arrayKlass) \
- declare_type(objArrayKlassKlass, arrayKlassKlass) \
- declare_type(objArrayOopDesc, arrayOopDesc) \
-@@ -953,6 +955,7 @@
- /* Oops */ \
- /********/ \
- \
-+ declare_oop_type(activationFrameOop) \
- declare_oop_type(constantPoolOop) \
- declare_oop_type(constantPoolCacheOop) \
- declare_oop_type(klassOop) \
--- a/callcc.txt Thu Oct 28 12:09:03 2010 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,34 +0,0 @@
-6655643: some dynamic languages need stack reification
-Summary: low-level continuation support
-
-http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6655643
-
-Features:
-- lazy continuation storage
-- optionally delimited continuations
-
-Authors:
-- Lukas Stadler (JKU, Linz)
-- John Rose (Sun)
-
-Tests:
- (These are junit tests, they serve mainly to explain the usage of Continuations)
- javax.stack.*
-
-Incremental testing:
-This does not require a full JDK build.
-
-$ rm -rf build/bootcp
-$ mkdir build/bootcp
-
-$ files='
-sources/jdk/src/share/classes/javax/stack/Continuation.java
-sources/jdk/src/share/classes/javax/stack/Continuable.java
-sources/jdk/src/share/classes/javax/stack/ContinuableAccess.java
-sources/jdk/src/share/classes/javax/stack/ContinuationPermission.java
-sources/jdk/src/share/classes/javax/stack/DelimitedRunnable.java
-sources/jdk/src/share/classes/javax/stack/Fiber.java
-sources/jdk/test/javax/stack/*.java
-'
-$ javac -d build/bootcp $files
-$ java -XXaltjvm=?? -Xbootclasspath/p:build/bootcp TestCopyStack