callcc: resume works better, stack frame API
authorjrose
Tue Jul 15 00:12:32 2008 -0700 (4 years ago)
changeset 899e6c3830f6d
parent 7c0db1bded354
child 9886f9ddefb15
callcc: resume works better, stack frame API
Contributed-By: Lukas Stadler <lukas.stadler@jku.at>
rebase to jdk7-b30
callcc.patch
callcc.txt
series
--- a/callcc.patch Tue Jul 15 00:03:41 2008 -0700
+++ b/callcc.patch Tue Jul 15 00:12:32 2008 -0700
@@ -1,3 +1,76 @@ diff --git a/src/cpu/x86/vm/sharedRuntim
+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
+@@ -2272,7 +2272,7 @@ void SharedRuntime::generate_deopt_blob(
+ // allocate space for the code
+ ResourceMark rm;
+ // setup code generation tools
+- CodeBuffer buffer("deopt_blob", 1024, 1024);
++ CodeBuffer buffer("deopt_blob", 2048, 2048);
+ MacroAssembler* masm = new MacroAssembler(&buffer);
+ int frame_size_in_words;
+ OopMap* map = NULL;
+@@ -2393,6 +2393,42 @@ void SharedRuntime::generate_deopt_blob(
+ __ bind(no_pending_exception);
+ #endif
+
++ __ jmp(cont);
++
++
++ int continuation_offset = __ pc() - start;
++
++ // Prolog for the continutation case
++ // This code can be called like a void func(UnrollBlock*) from within a native method
++
++ // some cleanup (we're coming from a native method)
++ __ get_thread(rcx);
++ __ reset_last_Java_frame(rcx, false, true);
++ __ movl(Address(rcx, JavaThread::thread_state_offset()), _thread_in_Java);
++
++ // reset handle block
++ __ movl(rdi, Address(rcx, JavaThread::active_handles_offset()));
++ __ movl(Address(rdi, JNIHandleBlock::top_offset_in_bytes()), 0);
++
++ // trash the (unneeded) return pc
++ __ popl(rdi);
++ // get the UnrollBlock parameter into rdi
++ __ popl(rdi);
++
++ // return value handling for continuation case
++ __ movl(rax, Address(rdi, Deoptimization::UnrollBlock::return_value_offset_in_bytes()));
++
++ // store the correct deoptimization type
++ __ movl(Address(rdi, Deoptimization::UnrollBlock::unpack_kind_offset_in_bytes()), Deoptimization::Unpack_continuation);
++ __ movl(rsp, Address(rdi, Deoptimization::UnrollBlock::size_of_deoptimized_frame_offset_in_bytes()));
++
++ // this value will be removed later on
++ __ pushl(0xDEADDEAD);
++
++ // we don't want to call fetch_unroll_info because we already have an UnrollBlock
++ Label continuation_cont;
++ __ jmp(continuation_cont);
++
+ __ bind(cont);
+
+ // Compiled code leaves the floating point stack dirty, empty it.
+@@ -2468,6 +2504,8 @@ void SharedRuntime::generate_deopt_blob(
+
+ // Pop deoptimized frame
+ __ addl(rsp,Address(rdi,Deoptimization::UnrollBlock::size_of_deoptimized_frame_offset_in_bytes()));
++
++ __ bind(continuation_cont);
+
+ // sp should be pointing at the return address to the caller (3)
+
+@@ -2610,7 +2648,7 @@ void SharedRuntime::generate_deopt_blob(
+ // make sure all code is generated
+ masm->flush();
+
+- _deopt_blob = DeoptimizationBlob::create( &buffer, oop_maps, 0, exception_offset, reexecute_offset, frame_size_in_words);
++ _deopt_blob = DeoptimizationBlob::create( &buffer, oop_maps, 0, exception_offset, reexecute_offset, continuation_offset, frame_size_in_words);
+ _deopt_blob->set_unpack_with_exception_in_tls_offset(exception_in_tls_offset);
+ }
+
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
@@ -9,7 +82,7 @@ diff --git a/src/cpu/x86/vm/sharedRuntim
#ifdef COMPILER2
UncommonTrapBlob *SharedRuntime::_uncommon_trap_blob;
ExceptionBlob *OptoRuntime::_exception_blob;
-@@ -1986,6 +1987,8 @@ void SharedRuntime::generate_deopt_blob(
+@@ -2616,6 +2617,8 @@ void SharedRuntime::generate_deopt_blob(
__ reset_last_Java_frame(false, false);
@@ -18,31 +91,415 @@ diff --git a/src/cpu/x86/vm/sharedRuntim
// Load UnrollBlock* into rdi
__ movq(rdi, rax);
+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
+@@ -2278,6 +2278,89 @@ oop java_util_concurrent_locks_AbstractO
+ return obj->obj_field(_owner_offset);
+ }
+
++/* stack manipulation */
++
++int javax_stack_Continuation::stackFrames_offset = 0;
++int javax_stack_StackFrame::method_offset = 0;
++int javax_stack_StackFrame::bci_offset = 0;
++int javax_stack_StackFrame::localIsObject_offset = 0;
++int javax_stack_StackFrame::expressionIsObject_offset = 0;
++int javax_stack_StackFrame::valueSlots_offset = 0;
++int javax_stack_StackFrame::objectSlots_offset = 0;
++
++void javax_stack_Continuation::compute_offsets() {
++ klassOop k = SystemDictionary::continuation_klass();
++ compute_offset(stackFrames_offset, k, vmSymbols::stackFrames_name(), vmSymbols::stackFrames_signature());
++}
++
++objArrayOop javax_stack_Continuation::stack_frames(oop obj) {
++ return (objArrayOop)obj->obj_field(stackFrames_offset);
++}
++
++void javax_stack_Continuation::set_stack_frames(oop obj, objArrayOop value) {
++ obj->obj_field_put(stackFrames_offset, value);
++}
++
++
++void javax_stack_StackFrame::compute_offsets() {
++ klassOop k = SystemDictionary::stackFrame_klass();
++ compute_offset(method_offset, k, vmSymbols::method_name(), vmSymbols::method_signature());
++ compute_offset(bci_offset, k, vmSymbols::bci_name(), vmSymbols::int_signature());
++ compute_offset(localIsObject_offset, k, vmSymbols::localIsObject_name(), vmSymbols::bool_array_signature());
++ compute_offset(expressionIsObject_offset, k, vmSymbols::expressionIsObject_name(), vmSymbols::bool_array_signature());
++ compute_offset(valueSlots_offset, k, vmSymbols::valueSlots_name(), vmSymbols::int_array_signature());
++ compute_offset(objectSlots_offset, k, vmSymbols::objectSlots_name(), vmSymbols::object_array_signature());
++}
++
++oop javax_stack_StackFrame::method(oop obj) {
++ return obj->obj_field(method_offset);
++}
++
++void javax_stack_StackFrame::set_method(oop obj, oop value) {
++ obj->obj_field_put(method_offset, value);
++}
++
++int javax_stack_StackFrame::bci(oop obj) {
++ return obj->int_field(bci_offset);
++}
++
++void javax_stack_StackFrame::set_bci(oop obj, int value) {
++ obj->int_field_put(bci_offset, value);
++}
++
++typeArrayOop javax_stack_StackFrame::localIsObject(oop obj) {
++ return (typeArrayOop)obj->obj_field(localIsObject_offset);
++}
++
++void javax_stack_StackFrame::set_localIsObject(oop obj, typeArrayOop value) {
++ obj->obj_field_put(localIsObject_offset, value);
++}
++
++typeArrayOop javax_stack_StackFrame::expressionIsObject(oop obj) {
++ return (typeArrayOop)obj->obj_field(expressionIsObject_offset);
++}
++
++void javax_stack_StackFrame::set_expressionIsObject(oop obj, typeArrayOop value) {
++ obj->obj_field_put(expressionIsObject_offset, value);
++}
++
++typeArrayOop javax_stack_StackFrame::valueSlots(oop obj) {
++ return (typeArrayOop)obj->obj_field(valueSlots_offset);
++}
++
++void javax_stack_StackFrame::set_valueSlots(oop obj, typeArrayOop value) {
++ obj->obj_field_put(valueSlots_offset, value);
++}
++
++objArrayOop javax_stack_StackFrame::objectSlots(oop obj) {
++ return (objArrayOop)obj->obj_field(objectSlots_offset);
++}
++
++void javax_stack_StackFrame::set_objectSlots(oop obj, objArrayOop value) {
++ obj->obj_field_put(objectSlots_offset, value);
++}
++
++
+ // Compute hard-coded offsets
+ // Invoked before SystemDictionary::initialize, so pre-loaded classes
+ // are not available to determine the offset_of_static_fields.
+@@ -2371,6 +2454,9 @@ void JavaClasses::compute_offsets() {
+ sun_reflect_UnsafeStaticFieldAccessorImpl::compute_offsets();
+ }
+ sun_misc_AtomicLongCSImpl::compute_offsets();
++
++ javax_stack_Continuation::compute_offsets();
++ javax_stack_StackFrame::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
+@@ -925,6 +925,60 @@ class java_util_concurrent_locks_Abstrac
+ 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 stackFrames_offset;
++
++ static void compute_offsets();
++
++ public:
++ // Accessors
++ static objArrayOop stack_frames(oop obj);
++ static void set_stack_frames(oop obj, objArrayOop value);
++
++ // Debugging
++ friend class JavaClasses;
++};
++
++class javax_stack_StackFrame: AllStatic {
++ private:
++ // Note that to reduce dependencies on the JDK we compute these
++ // offsets at run-time.
++ static int method_offset;
++ static int bci_offset;
++ static int localIsObject_offset;
++ static int expressionIsObject_offset;
++ static int valueSlots_offset;
++ static int objectSlots_offset;
++
++ static void compute_offsets();
++
++ public:
++ // Accessors
++ static oop method(oop obj);
++ static void set_method(oop obj, oop value);
++
++ static int bci(oop obj);
++ static void set_bci(oop obj, int value);
++
++ static typeArrayOop localIsObject(oop obj);
++ static void set_localIsObject(oop obj, typeArrayOop value);
++
++ static typeArrayOop expressionIsObject(oop obj);
++ static void set_expressionIsObject(oop obj, typeArrayOop value);
++
++ static typeArrayOop valueSlots(oop obj);
++ static void set_valueSlots(oop obj, typeArrayOop value);
++
++ static objArrayOop objectSlots(oop obj);
++ static void set_objectSlots(oop obj, objArrayOop value);
++
++ // 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
+@@ -155,6 +155,10 @@ class ResolutionErrorTable;
+ template(short_klass, java_lang_Short, Pre) \
+ template(int_klass, java_lang_Integer, Pre) \
+ template(long_klass, java_lang_Long, Pre) \
++ \
++ /* Stack manipulation classes */ \
++ template(continuation_klass, javax_stack_Continuation, Opt) \
++ template(stackFrame_klass, javax_stack_StackFrame, 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
+@@ -316,7 +316,10 @@
+ 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") \
+@@ -418,6 +421,19 @@
+ template(serializePropertiesToByteArray_signature, "()[B") \
+ template(serializeAgentPropertiesToByteArray_name, "serializeAgentPropertiesToByteArray") \
+ template(classRedefinedCount_name, "classRedefinedCount") \
++ \
++ /* stack manipulation */ \
++ template(javax_stack_Continuation, "javax/stack/Continuation") \
++ template(javax_stack_StackFrame, "javax/stack/StackFrame") \
++ template(stackFrames_name, "stackFrames") \
++ template(stackFrames_signature, "[Ljavax/stack/StackFrame;") \
++ template(method_name, "method") \
++ template(method_signature, "Ljava/lang/reflect/Method;") \
++ template(bci_name, "bci") \
++ template(localIsObject_name, "localIsObject") \
++ template(expressionIsObject_name, "expressionIsObject") \
++ template(valueSlots_name, "valueSlots") \
++ template(objectSlots_name, "objectSlots") \
+ /*end*/
+
+
+@@ -753,6 +769,12 @@
+ 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") \
+ /*end*/
+
+
+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
+@@ -375,13 +375,15 @@ DeoptimizationBlob::DeoptimizationBlob(
+ int unpack_offset,
+ int unpack_with_exception_offset,
+ int unpack_with_reexecution_offset,
++ int unpack_with_continuation_offset,
+ int frame_size
+ )
+ : SingletonBlob("DeoptimizationBlob", cb, sizeof(DeoptimizationBlob), size, frame_size, oop_maps)
+ {
+- _unpack_offset = unpack_offset;
+- _unpack_with_exception = unpack_with_exception_offset;
+- _unpack_with_reexecution = unpack_with_reexecution_offset;
++ _unpack_offset = unpack_offset;
++ _unpack_with_exception = unpack_with_exception_offset;
++ _unpack_with_reexecution = unpack_with_reexecution_offset;
++ _unpack_with_continuation = unpack_with_continuation_offset;
+ #ifdef COMPILER1
+ _unpack_with_exception_in_tls = -1;
+ #endif
+@@ -394,6 +396,7 @@ DeoptimizationBlob* DeoptimizationBlob::
+ int unpack_offset,
+ int unpack_with_exception_offset,
+ int unpack_with_reexecution_offset,
++ int unpack_with_continuation_offset,
+ int frame_size)
+ {
+ DeoptimizationBlob* blob = NULL;
+@@ -407,6 +410,7 @@ DeoptimizationBlob* DeoptimizationBlob::
+ unpack_offset,
+ unpack_with_exception_offset,
+ unpack_with_reexecution_offset,
++ unpack_with_continuation_offset,
+ frame_size);
+ }
+
+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
+@@ -339,6 +339,7 @@ class DeoptimizationBlob: public Singlet
+ int _unpack_offset;
+ int _unpack_with_exception;
+ int _unpack_with_reexecution;
++ int _unpack_with_continuation;
+
+ int _unpack_with_exception_in_tls;
+
+@@ -350,6 +351,7 @@ class DeoptimizationBlob: public Singlet
+ int unpack_offset,
+ int unpack_with_exception_offset,
+ int unpack_with_reexecution_offset,
++ int unpack_with_continuation_offset,
+ int frame_size
+ );
+
+@@ -363,6 +365,7 @@ class DeoptimizationBlob: public Singlet
+ int unpack_offset,
+ int unpack_with_exception_offset,
+ int unpack_with_reexecution_offset,
++ int unpack_with_continuation_offset,
+ int frame_size
+ );
+
+@@ -386,9 +389,10 @@ class DeoptimizationBlob: public Singlet
+ // Printing
+ void print_value_on(outputStream* st) const PRODUCT_RETURN;
+
+- address unpack() const { return instructions_begin() + _unpack_offset; }
+- address unpack_with_exception() const { return instructions_begin() + _unpack_with_exception; }
+- address unpack_with_reexecution() const { return instructions_begin() + _unpack_with_reexecution; }
++ address unpack() const { return instructions_begin() + _unpack_offset; }
++ address unpack_with_exception() const { return instructions_begin() + _unpack_with_exception; }
++ address unpack_with_reexecution() const { return instructions_begin() + _unpack_with_reexecution; }
++ address unpack_with_continuation() const { return instructions_begin() + _unpack_with_continuation; }
+
+ // Alternate entry point for C1 where the exception and issuing pc
+ // are in JavaThread::_exception_oop and JavaThread::_exception_pc
+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,11 @@ bool CompilerOracle::has_option_string(m
+
+ bool CompilerOracle::should_exclude(methodHandle method, bool& quietly) {
+ quietly = true;
++
++ // stack manipulation/continuation: the doCopyStackContext function can never be compiled
++ if (method->intrinsic_id() == vmIntrinsics::_doCopyStackContext)
++ return true;
++
+ if (lists[ExcludeCommand] != NULL) {
+ if (lists[ExcludeCommand]->match(method)) {
+ quietly = _quiet;
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
-@@ -4290,6 +4290,7 @@ universe.inline.hpp
+@@ -4335,7 +4335,9 @@ universe.inline.hpp
+ universe.inline.hpp universe.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
-@@ -4299,6 +4300,9 @@ unsafe.cpp
+@@ -4345,6 +4347,11 @@ unsafe.cpp
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
+@@ -4426,6 +4433,7 @@ vframe.hpp
+ 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/instanceKlassKlass.cpp b/src/share/vm/oops/instanceKlassKlass.cpp
+--- a/src/share/vm/oops/instanceKlassKlass.cpp
++++ b/src/share/vm/oops/instanceKlassKlass.cpp
+@@ -302,7 +302,7 @@ void instanceKlassKlass::oop_copy_conten
+ }
+
+ oop* hk_addr = ik->adr_host_klass();
+- if (PSScavenge::should_scavenge(*hk_addr)) {
++ if (PSScavenge::should_scavenge(hk_addr)) {
+ pm->claim_or_forward_breadth(hk_addr);
+ }
+
+@@ -330,7 +330,7 @@ void instanceKlassKlass::oop_push_conten
+ }
+
+ oop* hk_addr = ik->adr_host_klass();
+- if (PSScavenge::should_scavenge(*hk_addr)) {
++ if (PSScavenge::should_scavenge(hk_addr)) {
+ pm->claim_or_forward_depth(hk_addr);
+ }
+
+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
+@@ -140,7 +140,7 @@ void methodOopDesc::mask_for(int bci, In
+ Thread* myThread = Thread::current();
+ methodHandle h_this(myThread, this);
+ #ifdef ASSERT
+- bool has_capability = myThread->is_VM_thread() ||
++/* bool has_capability = myThread->is_VM_thread() ||
+ myThread->is_ConcurrentGC_thread() ||
+ myThread->is_GC_task_thread();
+
+@@ -153,7 +153,7 @@ void methodOopDesc::mask_for(int bci, In
+ instanceKlass::cast(method_holder())->mask_for(h_this, bci, &local_mask);
+ local_mask.print();
+ }
+- }
++ } */
+ #endif
+ instanceKlass::cast(method_holder())->mask_for(h_this, bci, mask);
+ return;
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
-@@ -1024,6 +1024,368 @@ UNSAFE_END
+@@ -905,7 +905,6 @@ UNSAFE_ENTRY(jclass, Unsafe_DefineAnonym
+ }
+ UNSAFE_END
+
+-
+ UNSAFE_ENTRY(void, Unsafe_MonitorEnter(JNIEnv *env, jobject unsafe, jobject jobj))
+ UnsafeWrapper("Unsafe_MonitorEnter");
+ {
+@@ -1069,6 +1068,764 @@ UNSAFE_END
UNSAFE_END
@@ -116,12 +573,13 @@ diff --git a/src/share/vm/prims/unsafe.c
+ bool check_read() {
+ if (_rbytes.position() >= _rbytes_limit)
+ set_losing();
-+ return is_losing();
-+ }
-+
-+ void write_stack_values(StackValueCollection* vs) {
-+ write_int(vs->size());
-+ for (int i = 0; i < vs->size(); i++) {
++ return !is_losing();
++ }
++
++ void write_stack_values(StackValueCollection* vs, int ignore = 0) {
++ assert(vs->size() >= ignore, "too few stack values");
++ write_int(vs->size() - ignore);
++ for (int i = 0; i < vs->size() - ignore; i++) {
+ StackValue* v = vs->at(i);
+ BasicType vt = v->type();
+ write_int((int)vt);
@@ -144,19 +602,59 @@ diff --git a/src/share/vm/prims/unsafe.c
+ }
+ }
+
++ StackValueCollection* read_stack_values() {
++ int size = read_int();
++ StackValueCollection* coll = new StackValueCollection();
++
++ for (int i = 0; i < size; i++) {
++ BasicType vt = (BasicType)read_int();
++ switch(vt) {
++ case T_OBJECT:
++ // preserve object type
++ // TODO make sure that there can never be a gc while the object is only referenced here, it won't be found
++ coll->add( new StackValue((intptr_t) (read_oop()), T_OBJECT ));
++ LP64_ONLY(shouldNotReachHere());
++ break;
++ case T_CONFLICT:
++ // A dead local. Will be initialized to null/zero.
++ coll->add( new StackValue());
++ break;
++ case T_INT:
++ coll->add( new StackValue(read_signed_int()));
++ break;
++ default:
++ ShouldNotReachHere();
++ }
++ }
++ return coll;
++ }
++
+ void write_monitors(GrowableArray<MonitorInfo*>* ms) {
+ write_int(ms->length());
+ for (int i = 0; i < ms->length(); i++) {
+ MonitorInfo* m = ms->at(i);
+ write_oop(m->owner());
-+ }
-+ }
-+
-+ void write_frame(javaVFrame* vf);
-+ vframe* read_frame();
++ write_int(m->eliminated());
++ }
++ }
++
++ GrowableArray<MonitorInfo*>* read_monitors() {
++ int size = read_int();
++ GrowableArray<MonitorInfo*>* coll = new GrowableArray<MonitorInfo*>(size);
++ for (int i = 0; i < size; i++) {
++ oop obj = read_oop();
++ bool eliminated = (bool) read_int();
++ coll->at_put(i, new MonitorInfo(obj, NULL, eliminated));
++ }
++ return coll;
++ }
++
++ void write_frame(javaVFrame* vf, int ignore_expressions);
++ FrameInfo* read_frame(JNIEnv* env);
+
+ Handle make_stack_blob(TRAPS);
+ Handle externalize(Handle x, TRAPS);
++
+};
+
+Handle StackSerializer::externalize(Handle x, TRAPS) {
@@ -274,17 +772,66 @@ diff --git a/src/share/vm/prims/unsafe.c
+}
+
+
-+void StackSerializer::write_frame(javaVFrame* vf) {
++void StackSerializer::write_frame(javaVFrame* vf, int ignore_expressions) {
+ write_oop(vf->method());
-+ write_int(vf->bci());
++ int bci = vf->bci();
++ write_int(bci);
+ write_stack_values(vf->locals());
-+ write_stack_values(vf->expressions());
++ StackValueCollection* expressions = vf->expressions();
++ if (vf->is_compiled_frame())
++ write_stack_values(vf->expressions(), 0);
++ else
++ write_stack_values(vf->expressions(), ignore_expressions);
+ write_monitors(vf->monitors());
+ _num_frames += 1;
+}
+
-+static bool frame_matches_context(vframe* vf, jobject context) {
-+ return false; //%%% TO-DO
++methodOop methodOop_from_reflectedOop(JNIEnv *env, oop reflected)
++{
++ oop mirror = NULL;
++ int slot = 0;
++
++ if (reflected->klass() == SystemDictionary::reflect_constructor_klass()) {
++ mirror = java_lang_reflect_Constructor::clazz(reflected);
++ slot = java_lang_reflect_Constructor::slot(reflected);
++ } else {
++ if (reflected->klass() != SystemDictionary::reflect_method_klass()) {
++ tty->print("Type: ");
++ reflected->klass()->klass_part()->name()->print_symbol_on(tty);
++ }
++ assert(reflected->klass() == SystemDictionary::reflect_method_klass(), "wrong type");
++ mirror = java_lang_reflect_Method::clazz(reflected);
++ slot = java_lang_reflect_Method::slot(reflected);
++ }
++ klassOop k = java_lang_Class::as_klassOop(mirror);
++
++ JavaThread* thread = JavaThread::thread_from_jni_environment(env);
++ KlassHandle k1(thread, k);
++ // Make sure class is initialized before handing id's out to methods
++ Klass::cast(k1())->initialize(thread);
++ return instanceKlass::cast(k1())->method_with_idnum(slot);
++}
++
++methodOop methodOop_from_reflected(JNIEnv* env, jobject method)
++{
++ // method is a handle to a java.lang.reflect.Method object
++ oop reflected = JNIHandles::resolve_non_null(method);
++ return methodOop_from_reflectedOop(env, reflected);
++}
++
++FrameInfo* StackSerializer::read_frame(JNIEnv* env) {
++ methodOop method = methodOop_from_reflectedOop(env, read_oop());
++ int bci = read_int();
++ StackValueCollection* locals = read_stack_values();
++ StackValueCollection* expressions = read_stack_values();
++ GrowableArray<MonitorInfo*>* monitors = read_monitors();
++ FrameInfo* info = new FrameInfo(method, bci, locals, expressions, monitors);
++
++#ifdef ASSERT
++ info->verify();
++#endif // ASSERT
++
++ return info;
+}
+
+UNSAFE_ENTRY(jobject, Unsafe_CopyStack(JNIEnv *env, jobject unsafe, jobject context, jobject cs_exception))
@@ -302,31 +849,35 @@ diff --git a/src/share/vm/prims/unsafe.c
+
+ vframe* vf = thread->last_java_vframe(&reg_map);
+ assert(Klass::cast(javaVFrame::cast(vf)->method()->method_holder())->name() == vmSymbols::sun_misc_Unsafe(), "");
++ int callee_params = javaVFrame::cast(vf)->method()->size_of_parameters();
+ vf = vf->sender(); // Skip Unsafe.copyStack itself.
+ for (; vf; vf = vf->sender()) {
+ if (sser.is_losing()) break;
+ if (vf->is_java_frame()) {
-+ if (PrintMiscellaneous && (Verbose || WizardMode)) {
-+ tty->print_cr("copyStack: adding frame");
-+ NOT_PRODUCT(vf->print());
++ javaVFrame* jvf = javaVFrame::cast(vf);
++ if (jvf->method() && jvf->method()->intrinsic_id() == vmIntrinsics::_doCopyStackContext) {
++ StackValueCollection* locals = jvf->locals();
++ assert(locals->size() >= 3, "not enough locals");
++ // check the context parameter
++ if (locals->at(2)->get_obj()() == JNIHandles::resolve(context))
++ break;
+ }
-+ sser.write_frame(javaVFrame::cast(vf));
++ sser.write_frame(jvf, callee_params);
++ callee_params = jvf->method()->size_of_parameters();
+ } else {
-+ if (PrintMiscellaneous && (Verbose || WizardMode)) {
-+ tty->print_cr("copyStack: stopping at frame");
-+ NOT_PRODUCT(vf->print());
-+ }
++#ifdef ASSERT
++ tty->print("copyStack: stopping at "); vf->print(); //@@
++#endif
++
++ THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(), "no matching doCopyStackContext call found", NULL);
+ break;
+ }
-+ if (context != NULL && frame_matches_context(vf, context)) {
-+ if (PrintMiscellaneous && (Verbose || WizardMode)) {
-+ tty->print_cr("copyStack: stopping at context frame");
-+ }
-+ break;
-+ }
++
+ }
+
+ Handle blob = sser.make_stack_blob(CHECK_NULL);
++
++ // TODO this may need to be atomic or synchronized somehow
+
+ static int CSE_stack_offset = 0;
+ if (CSE_stack_offset == 0) {
@@ -354,85 +905,390 @@ diff --git a/src/share/vm/prims/unsafe.c
+}
+UNSAFE_END
+
-+UNSAFE_ENTRY(jlong, Unsafe_ResumeStack0(JNIEnv *env, jobject unsafe, jobject stack, jobject value, jobject exception))
-+ UnsafeWrapper("Unsafe_ResumeStack0");
++FrameInfo* read_stack_frame(JNIEnv* env, oop stackFrame);
++
++typedef void (*DeoptimizationFunction)(Deoptimization::UnrollBlock*);
++
++jlong Unsafe_ResumeStack0(JNIEnv *env, jobject unsafe, jobject context, jobject stack, jobject value, jobject exception)
+{
-+ ResourceMark rm;
-+
+ JavaThread* thread = JavaThread::thread_from_jni_environment(env);
-+ if (thread != THREAD)
-+ THROW_IE_("bad thread context", 0L);
-+
-+ if (exception != NULL)
-+ THROW_IE_("resumeStack with exception NYI", 0L);
-+
-+ // Deserialize the saved frames into a bunch of vframes:
-+ StackSerializer sser(thread, JNIHandles::resolve(stack), CHECK_0);
-+
-+ // vframeArray::fill_in and vframeArrayElement::fill_in
-+ // need to know how to pull data out of sser... but how?
-+
-+#ifndef NOT_IMPLEMENTED_YET
-+ THROW_IE_("resumeStack NYI", 0L);
-+#else //NOT_IMPLEMENTED_YET
-+ if (UseBiasedLocking) {
-+ Deoptimization::revoke_biases_of_monitors(thread, fr, &reg_map);
-+ }
-+
-+ //Deoptimization::deoptimize_single_frame(thread, fr);
-+ //address deopt = SharedRuntime::deopt_blob()->unpack();
-+ //fr.patch_pc(thread, deopt);
-+
-+ vframeArray* array = vframeArray::allocate(sser);
-+
-+ Deoptimization::UnrollBlock* info = Deoptimization::fetch_unroll_info_helper(thread, &sser);
++ JavaThread* THREAD = thread;
++ Deoptimization::UnrollBlock* unroll_block;
++
++ ThreadInVMfromNative threadInVM(thread);
++
++ if (stack == NULL)
++ THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(), "stack cannot be null", 0);
++
+ {
-+ // We will return to the deopt. blob:
-+ address deopt_addr = SharedRuntime::deopt_blob()->instructions_begin();
-+ extern intptr_t SharedRuntime_deopt_blob_resume_offset;
-+ deopt_addr += SharedRuntime_deopt_blob_resume_offset;
-+ fr.patch_pc(deopt_addr);
-+ }
-+
-+ julong info_in_long = (uintptr_t) info;
-+ NOT_LP64(info_in_long |= (info_in_long << 32)); // put the ptr into both words, just in case
-+ return info_in_long;
-+#endif //NOT_IMPLEMENTED_YET
++ No_Safepoint_Verifier no_safepoint;
++ HandleMark hm(thread);
++
++ frame caller;
++ RegisterMap reg_map(thread, false);
++ {
++ ResourceMark rm(thread);
++
++ // all the monitors that we need to release
++ GrowableArray<MonitorInfo*>* monitors = new GrowableArray<MonitorInfo*>();
++
++ // this implementation operates on frames (not vframes) and is much faster
++ // the problem is that it doesn't collect the monitors
++ caller = thread->last_frame().sender(&reg_map);
++ do {
++ if (!caller.is_java_frame()) {
++ THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(), "no doCopyStackContext call on stack or a native call above it", 0);
++ }
++
++ if (caller.is_interpreted_frame()) {
++ methodOop method = caller.interpreter_frame_method();
++ if (method != NULL && method->intrinsic_id() == vmIntrinsics::_doCopyStackContext) {
++ if ((oop)(*caller.interpreter_frame_local_at(2)) == JNIHandles::resolve(context)) {
++ break;
++ }
++ }
++ }
++
++ caller = caller.sender(&reg_map);
++ } while (true);
++
++#ifdef LOCKING_AWARE_IMPL
++ vframe* vf = thread->last_java_vframe(&reg_map);
++ do {
++ if (vf == NULL || !vf->is_java_frame()) {
++ ThreadInVMfromNative thread_in_vm(thread);
++ THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(), "no doCopyStackContext call on stack or a native call above it", 0);
++ }
++
++ javaVFrame* jvf = javaVFrame::cast(vf);
++
++ monitors->appendAll(jvf->locked_monitors());
++
++ if (jvf->method() && jvf->method()->intrinsic_id() == vmIntrinsics::_doCopyStackContext) {
++ StackValueCollection* locals = jvf->locals();
++ assert(locals->size() >= 3, "not enough locals");
++ // check the context object
++ if (locals->at(2)->get_obj()() == JNIHandles::resolve(context)) {
++ caller = *vf->frame_pointer();
++ break;
++ }
++ }
++
++ vf = vf->sender();
++ } while (true);
++#endif
++
++ if (monitors->length() > 0 && UseBiasedLocking) {
++ GrowableArray<Handle>* objects_to_revoke = new GrowableArray<Handle>();
++ for (int i=0; i<monitors->length(); i++) {
++ MonitorInfo* mon_info = monitors->at(i);
++ if (mon_info->owner() != NULL) {
++ objects_to_revoke->append(Handle(mon_info->owner()));
++ }
++ }
++ // unbias all monitors
++ if (SafepointSynchronize::is_at_safepoint()) {
++ BiasedLocking::revoke_at_safepoint(objects_to_revoke);
++ } else {
++ BiasedLocking::revoke(objects_to_revoke);
++ }
++ }
++
++ // release all monitors
++ for (int i=0; i<monitors->length(); i++)
++ ObjectSynchronizer::fast_exit(monitors->at(i)->owner(), monitors->at(i)->lock(), thread);
++
++ } // end of ResourceMark
++
++ // Allocate our special deoptimization ResourceMark
++ DeoptResourceMark* dmark = new DeoptResourceMark(thread);
++ assert(thread->deopt_mark() == NULL, "Pending deopt!");
++ thread->set_deopt_mark(dmark);
++
++ GrowableArray<FrameInfo*>* frame_infos;
++ if (JNIHandles::resolve(stack)->is_a(SystemDictionary::continuation_klass())) {
++ // Deserialize the saved frames
++ oop stack_oop = JNIHandles::resolve(stack);
++ assert(javax_stack_Continuation::stack_frames(stack_oop) != NULL, "invalid continuation object");
++ objArrayOop stackFrames_array = javax_stack_Continuation::stack_frames(stack_oop);
++ frame_infos = new GrowableArray<FrameInfo*>(stackFrames_array->length());
++ for (int i=0; i<stackFrames_array->length(); i++) {
++ frame_infos->append(read_stack_frame(env, stackFrames_array->obj_at(i)));
++ }
++ } else {
++ // Deserialize the saved frames
++ StackSerializer sser(thread, JNIHandles::resolve(stack), thread);
++ frame_infos = new GrowableArray<FrameInfo*>(sser.num_frames());
++ for (int i=0; i<sser.num_frames(); i++) {
++ frame_infos->append(sser.read_frame(env));
++ }
++ }
++
++ unroll_block = Deoptimization::fetch_unroll_info_continuation(env, frame_infos, caller);
++ unroll_block->set_return_value(JNIHandles::resolve(value));
++ unroll_block->set_exception(JNIHandles::resolve(exception));
++ }
++
++ DeoptimizationFunction deopt_func = (DeoptimizationFunction)SharedRuntime::deopt_blob()->unpack_with_continuation();
++ deopt_func(unroll_block);
++ return (jlong)unroll_block;
++}
++
++#define CHECK_ARRAY_SIZE(var, array, type, size) if(array != NULL && array->length() == size) \
++ var = array; \
++ else { \
++ var = oopFactory::new_##type##Array(size, CHECK); \
++ }
++
++// fills a StackFrame object with the state of the given javaVFrame
++void fill_stack_frame(/*javax.lang.StackFrame*/Handle stack_frame, javaVFrame* frame, int callee_params, TRAPS)
++{
++ assert(stack_frame() != NULL && stack_frame()->klass() == SystemDictionary::stackFrame_klass(), "invalid argument");
++
++ methodOop method = frame->method();
++ oop reflection_method = method;
++
++ // TODO creating the reflection objects takes a long time... but passing the internal Oops isn't good either!
++ // Maybe we can use method handles as a compromise.
++/* if (method->is_initializer()) {
++ reflection_method = Reflection::new_constructor(method, CHECK);
++ } else {
++ reflection_method = Reflection::new_method(method, UseNewReflection, false, CHECK);
++ }*/
++ javax_stack_StackFrame::set_method(stack_frame(), reflection_method);
++ javax_stack_StackFrame::set_bci(stack_frame(), frame->bci());
++
++ // get locals, expressions and monitors from the stackFrame
++ StackValueCollection* locals = frame->locals();
++ StackValueCollection* expressions = frame->expressions();
++ GrowableArray<MonitorInfo*>* monitors = frame->monitors(); // TODO: MonitorInfo contains an oop!
++
++ typeArrayHandle local_is_object;
++ typeArrayHandle expression_is_object = NULL;
++ int object_count = 0;
++ int expression_count;
++ if (frame->is_compiled_frame())
++ expression_count = expressions->size();
++ else
++ expression_count = expressions->size() - callee_params;
++
++ // create the object tag arrays only if there are locals/expressions
++ if (locals->size() > 0)
++ CHECK_ARRAY_SIZE(local_is_object, javax_stack_StackFrame::localIsObject(stack_frame()), bool, locals->size());
++ if (expression_count > 0)
++ CHECK_ARRAY_SIZE(expression_is_object, javax_stack_StackFrame::expressionIsObject(stack_frame()), bool, expression_count);
++
++ // count how many object elements there are in locals/expressions and fill the tag arrays
++ for (int i = 0; i < locals->size(); i++)
++ if (locals->at(i)->type() == T_OBJECT) {
++ local_is_object->bool_at_put(i, true);
++ object_count++;
++ }
++ for (int i = 0; i < expression_count; i++)
++ if (expressions->at(i)->type() == T_OBJECT) {
++ expression_is_object->bool_at_put(i, true);
++ object_count++;
++ }
++
++ // create the arrays for the value (int) and object slots
++ // monitors will be added at the end of the object slots!
++ int value_count = locals->size() + expression_count - object_count;
++ object_count += monitors->length();
++ value_count += monitors->length();
++ typeArrayHandle value_slots;
++ objArrayHandle object_slots;
++ if (value_count > 0)
++ CHECK_ARRAY_SIZE(value_slots, javax_stack_StackFrame::valueSlots(stack_frame()), int, value_count);
++ if (object_count > 0)
++ CHECK_ARRAY_SIZE(object_slots, javax_stack_StackFrame::objectSlots(stack_frame()), object, object_count);
++
++ int value_index = 0;
++ int object_index = 0;
++
++ for (int i=0; i<locals->size(); i++) {
++ StackValue* v = locals->at(i);
++ switch (v->type()) {
++ case T_INT:
++ value_slots->int_at_put(value_index++, v->get_int());
++ break;
++ case T_OBJECT:
++ object_slots->obj_at_put(object_index++, v->get_obj()());
++ break;
++ case T_CONFLICT:
++ value_slots->int_at_put(value_index++, 0);
++ break;
++ default:
++ ShouldNotReachHere();
++ }
++ }
++
++ for (int i=0; i<expression_count; i++) {
++ StackValue* v = expressions->at(i);
++ switch (v->type()) {
++ case T_INT:
++ value_slots->int_at_put(value_index++, v->get_int());
++ break;
++ case T_OBJECT:
++ object_slots->obj_at_put(object_index++, v->get_obj()());
++ break;
++ case T_CONFLICT:
++ value_slots->int_at_put(value_index++, 0);
++ break;
++ default:
++ ShouldNotReachHere();
++ }
++ }
++
++ for (int i=0; i<monitors->length(); i++) {
++ MonitorInfo* mon_info = monitors->at(i);
++ object_slots->obj_at_put(object_index++, mon_info->owner());
++ value_slots->int_at_put(value_index++, mon_info->eliminated());
++ }
++
++ assert(value_index == value_count, "sanity check");
++ assert(object_index == object_count, "sanity check");
++
++ javax_stack_StackFrame::set_localIsObject(stack_frame(), local_is_object());
++ javax_stack_StackFrame::set_expressionIsObject(stack_frame(), expression_is_object());
++ javax_stack_StackFrame::set_valueSlots(stack_frame(), value_slots());
++ javax_stack_StackFrame::set_objectSlots(stack_frame(), object_slots());
++}
++
++
++UNSAFE_ENTRY(jobject, Unsafe_CopyStackSimple(JNIEnv* env, jobject unsafe, jobject context, /*javax.stack.Continuation*/jobject jcontinuation))
++{
++ JavaThread* thread = JavaThread::thread_from_jni_environment(env);
++
++ Handle continuation = JNIHandles::resolve(jcontinuation);
++ if (continuation() == NULL)
++ THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(), "continuation cannot be null", NULL);
++
++ KlassHandle stackFrame_klass(SystemDictionary::stackFrame_klass());
++ stackFrame_klass->initialize(CHECK_NULL);
++
++ {
++ ResourceMark rm;
++ // Serialize the stack:
++ RegisterMap reg_map(thread, false);
++
++ vframe* vf = thread->last_java_vframe(&reg_map);
++ assert(Klass::cast(javaVFrame::cast(vf)->method()->method_holder())->name() == vmSymbols::sun_misc_Unsafe(), "");
++ GrowableArray<Handle> stackFrames;
++
++ int callee_params = javaVFrame::cast(vf)->method()->size_of_parameters();
++ vf = vf->sender(); // Skip Unsafe.copyStackSimple itself.
++
++ for (; vf; vf = vf->sender()) {
++ if (vf->is_java_frame()) {
++ javaVFrame* jvf = javaVFrame::cast(vf);
++
++ if (jvf->method() && jvf->method()->intrinsic_id() == vmIntrinsics::_doCopyStackContext) {
++ StackValueCollection* locals = jvf->locals();
++ assert(locals->size() >= 3, "not enough locals");
++ // check the context parameter
++ if (locals->at(2)->get_obj()() == JNIHandles::resolve(context))
++ break;
++ }
++
++ Handle stackFrame = instanceKlass::cast(stackFrame_klass())->allocate_instance(CHECK_NULL);
++ fill_stack_frame(stackFrame, jvf, callee_params, CHECK_NULL);
++ stackFrames.push(stackFrame);
++
++ callee_params = jvf->method()->size_of_parameters();
++ } else {
++ THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(), "no matching doCopyStackContext call found", NULL);
++ }
++ }
++ if (vf == NULL) {
++ THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(), "no matching doCopyStackContext call found", NULL);
++ }
++
++ objArrayHandle stackFrames_array;
++ if (javax_stack_Continuation::stack_frames(continuation()) != NULL && javax_stack_Continuation::stack_frames(continuation())->length() == stackFrames.length())
++ stackFrames_array = javax_stack_Continuation::stack_frames(continuation());
++ else
++ stackFrames_array = oopFactory::new_objArray(SystemDictionary::stackFrame_klass(), stackFrames.length(), CHECK_NULL);
++ for (int i=0; i<stackFrames.length(); i++)
++ stackFrames_array->obj_at_put(i, stackFrames.at(i)());
++ javax_stack_Continuation::set_stack_frames(continuation(), stackFrames_array());
++ }
++ return NULL;
+}
+UNSAFE_END
+
-+UNSAFE_ENTRY(void, Unsafe_DoCopyStackContext(JNIEnv *env, jobject unsafe, jobject context, jobject runnable))
-+ UnsafeWrapper("Unsafe_DoCopyStackContext");
-+ Unimplemented();
-+UNSAFE_END
-+
-+
++FrameInfo* read_stack_frame(JNIEnv* env, oop stackFrame)
++{
++// methodOop method = methodOop_from_reflectedOop(env, javax_stack_StackFrame::method(stackFrame));
++ methodOop method = (methodOop)javax_stack_StackFrame::method(stackFrame);
++ int bci = javax_stack_StackFrame::bci(stackFrame);
++
++ typeArrayOop local_is_object = javax_stack_StackFrame::localIsObject(stackFrame);
++ typeArrayOop expression_is_object = javax_stack_StackFrame::expressionIsObject(stackFrame);
++ typeArrayOop value_slots = javax_stack_StackFrame::valueSlots(stackFrame);
++ objArrayOop object_slots = javax_stack_StackFrame::objectSlots(stackFrame);
++
++ StackValueCollection* locals = new StackValueCollection();
++ StackValueCollection* expressions = new StackValueCollection();
++ GrowableArray<MonitorInfo*>* monitors = new GrowableArray<MonitorInfo*>();
++ int value_index = 0;
++ int object_index = 0;
++
++ if (local_is_object != NULL) {
++ for (int i=0; i<local_is_object->length(); i++) {
++ if (local_is_object->bool_at(i))
++ locals->add(new StackValue((intptr_t)object_slots->obj_at(object_index++), T_OBJECT));
++ else
++ locals->add(new StackValue(value_slots->int_at(value_index++)));
++ }
++ }
++
++ if (expression_is_object != NULL) {
++ for (int i=0; i<expression_is_object->length(); i++) {
++ if (expression_is_object->bool_at(i))
++ expressions->add(new StackValue((intptr_t)object_slots->obj_at(object_index++), T_OBJECT));
++ else
++ expressions->add(new StackValue(value_slots->int_at(value_index++)));
++ }
++ }
++
++ if (object_slots != NULL) {
++ for (; object_index < object_slots->length(); object_index++) {
++ bool eliminated = value_slots->int_at(value_index++);
++ monitors->push(new MonitorInfo(object_slots->obj_at(object_index), NULL, eliminated));
++ }
++ }
++
++ return new FrameInfo(method, bci, locals, expressions, monitors);
++}
+
/// JVM_RegisterUnsafeMethods
#define ADR "J"
-@@ -1293,6 +1655,16 @@ static JNINativeMethod methods[] = {
-
+@@ -1363,6 +2120,20 @@ JNINativeMethod dynlang_methods[] = {
+ {CC"defineAnonymousClass", CC"("DAC_Args")"CLS, FN_PTR(Unsafe_DefineAnonymousClass)},
};
+#define CSE "Lsun/misc/Unsafe$CopyStackException;"
+#define RBL LANG"Runnable;"
++#define MTH LANG"reflect/Method;"
++#define CONT "Ljavax/stack/Continuation;"
+JNINativeMethod callcc_methods[] = {
+ {CC"copyStack", CC"("OBJ CSE")"OBJ, FN_PTR(Unsafe_CopyStack)},
-+ {CC"resumeStack0", CC"("OBJ OBJ THR")J", FN_PTR(Unsafe_ResumeStack0)},
-+ {CC"doCopyStackContext", CC"("OBJ RBL")V", FN_PTR(Unsafe_DoCopyStackContext)}
++ {CC"resumeStack0", CC"("OBJ OBJ OBJ THR")J", FN_PTR(Unsafe_ResumeStack0)},
++ {CC"copyStackSimple", CC"("OBJ CONT")"OBJ, FN_PTR(Unsafe_CopyStackSimple)}
+};
++#undef CONT
++#undef MTH
+#undef CSE
+#undef RBL
+
- JNINativeMethod loadavg_method[] = {
- {CC"getLoadAverage", CC"([DI)I", FN_PTR(Unsafe_Loadavg)}
- };
-@@ -1388,6 +1760,15 @@ JVM_ENTRY(void, JVM_RegisterUnsafeMethod
+ #undef CC
+ #undef FN_PTR
+
+@@ -1432,6 +2203,13 @@ JVM_ENTRY(void, JVM_RegisterUnsafeMethod
+ }
env->ExceptionClear();
}
- }
-+ {
+ env->RegisterNatives(unsafecls, callcc_methods, sizeof(callcc_methods)/sizeof(JNINativeMethod));
+ if (env->ExceptionOccurred()) {
+ if (PrintMiscellaneous && (Verbose || WizardMode)) {
@@ -440,7 +1296,445 @@ diff --git a/src/share/vm/prims/unsafe.c
+ }
+ env->ExceptionClear();
+ }
-+ }
+ }
int status = env->RegisterNatives(unsafecls, methods, sizeof(methods)/sizeof(JNINativeMethod));
if (env->ExceptionOccurred()) {
- if (PrintMiscellaneous && (Verbose || WizardMode)) {
+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
+@@ -40,6 +40,8 @@ Deoptimization::UnrollBlock::UnrollBlock
+ _frame_pcs = frame_pcs;
+ _register_block = NEW_C_HEAP_ARRAY(intptr_t, RegisterMap::reg_count * 2);
+ _return_type = return_type;
++ _return_value = NULL;
++ _exception = NULL;
+ // PD (x86 only)
+ _counter_temp = 0;
+ _initial_fp = 0;
+@@ -428,6 +430,7 @@ void Deoptimization::cleanup_deopt_info(
+ // incremented at the beginning of fetch_unroll_info() and (in C2) at
+ // the beginning of uncommon_trap().
+ thread->dec_in_deopt_handler();
++
+ }
+
+
+@@ -457,6 +460,9 @@ JRT_LEAF(BasicType, Deoptimization::unpa
+
+ UnrollBlock* info = array->unroll_block();
+
++ if (info->exception() != NULL) {
++ thread->set_pending_async_exception(info->exception());
++ }
+ // Unpack the interpreter frames and any adapter frame (c2 only) we might create.
+ array->unpack_to_stack(stub_frame, exec_mode);
+
+@@ -564,7 +570,7 @@ JRT_LEAF(BasicType, Deoptimization::unpa
+ (iframe->interpreter_frame_expression_stack_size() == (next_mask_expression_stack_size -
+ top_frame_expression_stack_adjustment))) ||
+ (is_top_frame && (exec_mode == Unpack_exception) && iframe->interpreter_frame_expression_stack_size() == 0) ||
+- (is_top_frame && (exec_mode == Unpack_uncommon_trap || exec_mode == Unpack_reexecute) &&
++ (is_top_frame && (exec_mode == Unpack_uncommon_trap || exec_mode == Unpack_reexecute || exec_mode == Unpack_continuation) &&
+ (iframe->interpreter_frame_expression_stack_size() == mask.expression_stack_size() + cur_invoke_parameter_size))
+ )) {
+ ttyLocker ttyl;
+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
+@@ -26,6 +26,8 @@ class vframeArray;
+ class vframeArray;
+ class MonitorValue;
+ class ObjectValue;
++
++class FrameInfo;
+
+ class Deoptimization : AllStatic {
+ public:
+@@ -78,7 +80,8 @@ class Deoptimization : AllStatic {
+ Unpack_deopt = 0, // normal deoptimization, use pc computed in unpack_vframe_on_stack
+ Unpack_exception = 1, // exception is pending
+ Unpack_uncommon_trap = 2, // redo last byte code (C2 only)
+- Unpack_reexecute = 3 // reexecute bytecode (C1 only)
++ Unpack_reexecute = 3, // reexecute bytecode (C1 only)
++ Unpack_continuation = 4 // reinstate a continuation
+ };
+
+ // Checks all compiled methods. Invalid methods are deleted and
+@@ -126,6 +129,8 @@ class Deoptimization : AllStatic {
+ address* _frame_pcs; // Array of frame pc's, in bytes, for unrolling the stack
+ intptr_t* _register_block; // Block for storing callee-saved registers.
+ BasicType _return_type; // Tells if we have to restore double or long return value
++ oop _return_value; // The return value for the Unpack_continuation case
++ oop _exception; // An exception can be thrown in the Unpack_continuation case
+ // The following fields are used as temps during the unpacking phase
+ // (which is tight on registers, especially on x86). They really ought
+ // to be PD variables but that involves moving this class into its own
+@@ -164,12 +169,16 @@ class Deoptimization : AllStatic {
+ static int frame_pcs_offset_in_bytes() { return offset_of(UnrollBlock, _frame_pcs); }
+ static int register_block_offset_in_bytes() { return offset_of(UnrollBlock, _register_block); }
+ static int return_type_offset_in_bytes() { return offset_of(UnrollBlock, _return_type); }
++ static int return_value_offset_in_bytes() { return offset_of(UnrollBlock, _return_value); }
+ static int counter_temp_offset_in_bytes() { return offset_of(UnrollBlock, _counter_temp); }
+ static int initial_fp_offset_in_bytes() { return offset_of(UnrollBlock, _initial_fp); }
+ static int unpack_kind_offset_in_bytes() { return offset_of(UnrollBlock, _unpack_kind); }
+ static int sender_sp_temp_offset_in_bytes() { return offset_of(UnrollBlock, _sender_sp_temp); }
+
+ BasicType return_type() const { return _return_type; }
++ void set_return_value(oop value) { _return_value = value; }
++ oop exception() const { return _exception; }
++ void set_exception(oop exc) { _exception = exc; }
+ void print();
+ };
+
+@@ -180,6 +189,10 @@ class Deoptimization : AllStatic {
+ // @argument thread. Thread where stub_frame resides.
+ // @see OptoRuntime::deoptimization_fetch_unroll_info_C
+ static UnrollBlock* fetch_unroll_info(JavaThread* thread);
++
++
++ //** Returns an UnrollBlock for a continuation
++ static UnrollBlock* fetch_unroll_info_continuation(JNIEnv* env, GrowableArray<FrameInfo*>* frame_infos, frame caller);
+
+ //** Unpacks vframeArray onto execution stack
+ // Called by assembly stub after execution has returned to
+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
+@@ -24,6 +24,255 @@
+
+ # include "incls/_precompiled.incl"
+ # 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("%08x ", v->get_int());
++ break;
++ case T_OBJECT:
++ st->print("OBJ(%08x) ", 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);
++
++ // Migrate the BasicLocks from the stack to the monitor chunk
++ for (index = 0; index < list->length(); index++) {
++ MonitorInfo* monitor = list->at(index);
++ oop obj = monitor->owner();
++ assert(obj == NULL || (obj->is_unlocked() && !obj->has_bias_pattern()), "object must be null or locked, and unbiased");
++ BasicObjectLock* dest = _monitors->at(index);
++ dest->set_obj(obj);
++ dest->lock()->set_displaced_header(obj->mark());
++ obj->set_mark((markOop) dest->lock());
++ }
++ }
++}
++
++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;
++}
++
++
++Deoptimization::UnrollBlock* Deoptimization::fetch_unroll_info_continuation(JNIEnv* env, GrowableArray<FrameInfo*>* frame_infos,
++ frame caller) {
++
++ JavaThread* thread = JavaThread::thread_from_jni_environment(env);
++ thread->inc_in_deopt_handler();
++
++ // Note: there is a safepoint safety issue here. No matter whether we enter
++ // via vanilla deopt or uncommon trap we MUST NOT stop at a safepoint once
++ // the vframeArray is created.
++ //
++
++
++ // Ensure that no safepoint is taken after pointers have been stored
++ // in fields of rematerialized objects. If a safepoint occurs from here on
++ // out the java state residing in the vframeArray will be missed.
++ No_Safepoint_Verifier no_safepoint;
++
++ vframeArray* array = vframeArray::allocate(thread, 0, frame_infos, caller, caller);
++
++ assert(thread->vframe_array_head() == NULL, "Pending deopt!");;
++ thread->set_vframe_array_head(array);
++
++ // -- no deferred writes!
++
++ intptr_t* unpack_sp = caller.sp();
++
++ // This is a guarantee instead of an assert because if vframe doesn't match
++ // we will unpack the wrong deoptimized frame and wind up in strange places
++ // where it will be very difficult to figure out what went wrong. Better
++ // to die an early death here than some very obscure death later when the
++ // trail is cold.
++ // Note: on ia64 this guarantee can be fooled by frames with no memory stack
++ // in that it will fail to detect a problem when there is one. This needs
++ // more work in tiger timeframe.
++// guarantee(array->unextended_sp() == unpack_sp, "vframe_array_head must contain the vframeArray to unpack");
++
++ int number_of_frames = array->frames();
++
++ // Compute the vframes' sizes. Note that frame_sizes[] entries are ordered from outermost to innermost
++ // virtual activation, which is the reverse of the elements in the vframes array.
++ intptr_t* frame_sizes = NEW_C_HEAP_ARRAY(intptr_t, number_of_frames);
++ // +1 because we always have an interpreter return address for the final slot.
++ address* frame_pcs = NEW_C_HEAP_ARRAY(address, number_of_frames + 1);
++ int callee_parameters = 0;
++ int callee_locals = 0;
++ int popframe_extra_args = 0;
++ // Create an interpreter return address for the stub to use as its return
++ // address so the skeletal frames are perfectly walkable
++ frame_pcs[number_of_frames] = Interpreter::deopt_entry(vtos, 0);
++
++ //
++ // frame_sizes/frame_pcs[0] oldest frame (int or c2i)
++ // frame_sizes/frame_pcs[1] next oldest frame (int)
++ // frame_sizes/frame_pcs[n] youngest frame (int)
++ //
++ // Now a pc in frame_pcs is actually the return address to the frame's caller (a frame
++ // owns the space for the return address to it's caller). Confusing ain't it.
++ //
++ // The vframe array can address vframes with indices running from
++ // 0.._frames-1. Index 0 is the youngest frame and _frame - 1 is the oldest (root) frame.
++ // When we create the skeletal frames we need the oldest frame to be in the zero slot
++ // in the frame_sizes/frame_pcs so the assembly code can do a trivial walk.
++ // so things look a little strange in this loop.
++ //
++ for (int index = 0; index < array->frames(); index++ ) {
++ // frame[number_of_frames - 1 ] = on_stack_size(youngest)
++ // frame[number_of_frames - 2 ] = on_stack_size(sender(youngest))
++ // frame[number_of_frames - 3 ] = on_stack_size(sender(sender(youngest)))
++ frame_sizes[number_of_frames - 1 - index] = BytesPerWord * array->element(index)->on_stack_size(callee_parameters,
++ callee_locals,
++ index == 0,
++ popframe_extra_args);
++ // This pc doesn't have to be perfect just good enough to identify the frame
++ // as interpreted so the skeleton frame will be walkable
++ // The correct pc will be set when the skeleton frame is completely filled out
++ // The final pc we store in the loop is wrong and will be overwritten below
++ frame_pcs[number_of_frames - 1 - index ] = Interpreter::deopt_entry(vtos, 0) - frame::pc_return_offset;
++
++ callee_parameters = array->element(index)->method()->size_of_parameters();
++ callee_locals = array->element(index)->method()->max_locals();
++ popframe_extra_args = 0;
++ }
++
++ // Compute whether the root vframe returns a float or double value.
++ BasicType return_type;
++ {
++ HandleMark hm;
++ methodHandle method(thread, array->element(0)->method());
++ Bytecode_invoke* invoke = Bytecode_invoke_at_check(method, array->element(0)->bci());
++ return_type = (invoke != NULL) ? invoke->result_type(thread) : T_ILLEGAL;
++ assert(return_type == T_OBJECT, "T_OBJECT result expected");
++ }
++
++ // Compute information for handling adapters and adjusting the frame size of the caller.
++ int caller_adjustment = 0;
++
++ // in the continuation case the caller frame (doCopyStackContext) is always interpreted!
++ assert(caller.is_interpreted_frame(), "interpreted caller frame expected");
++ // The caller frame may need extending to accommodate
++ // non-parameter locals of the first unpacked interpreted frame.
++ // Compute that adjustment.
++ caller_adjustment = last_frame_adjust(callee_parameters, callee_locals);
++
++
++ // If the sender is deoptimized the we must retrieve the address of the handler
++ // since the frame will "magically" show the original pc before the deopt
++ // and we'd undo the deopt.
++
++ frame_pcs[0] = caller.raw_pc();
++
++ assert(CodeCache::find_blob_unsafe(frame_pcs[0]) != NULL, "bad pc");
++
++ UnrollBlock* info = new UnrollBlock((int)caller.sp(),
++ caller_adjustment * BytesPerWord,
++ number_of_frames,
++ frame_sizes,
++ frame_pcs,
++ return_type);
++#if defined(IA32) || defined(AMD64)
++ // We need a way to pass fp to the unpacking code so the skeletal frames
++ // come out correct. This is only needed for x86 because of c2 using ebp
++ // as an allocatable register. So this update is useless (and harmless)
++ // on the other platforms. It would be nice to do this in a different
++ // way but even the old style deoptimization had a problem with deriving
++ // this value. NEEDS_CLEANUP
++ // Note: now that c1 is using c2's deopt blob we must do this on all
++ // x86 based platforms
++ intptr_t** fp_addr = (intptr_t**) (((address)info) + info->initial_fp_offset_in_bytes());
++ *fp_addr = array->sender().fp(); // was adapter_caller
++#endif /* IA32 || AMD64 */
++
++ array->set_unroll_block(info);
++ return info;
++}
++
++
+
+
+ int vframeArrayElement:: bci(void) const { return (_bci == SynchronizationEntryBCI ? 0 : _bci); }
+@@ -213,6 +462,12 @@ void vframeArrayElement::unpack_on_stack
+ case Deoptimization::Unpack_deopt:
+ // use what we've got
+ break;
++ case Deoptimization::Unpack_continuation:
++ // we may want to throw an exception
++ if (thread->has_pending_exception()) {
++ pc = SharedRuntime::raw_exception_handler_for_return_address(pc);
++ }
++ break;
+ case Deoptimization::Unpack_exception:
+ // exception is pending
+ pc = SharedRuntime::raw_exception_handler_for_return_address(pc);
+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
+@@ -33,6 +33,46 @@ class MonitorStackClosure;
+ class MonitorStackClosure;
+ 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.
+@@ -66,6 +106,7 @@ class vframeArrayElement : public _Value
+ StackValueCollection* expressions(void) const { return _expressions; }
+
+ void fill_in(compiledVFrame* vf);
++ void fill_in(FrameInfo* frame_info);
+
+ // Formerly part of deoptimizedVFrame
+
+@@ -145,6 +186,10 @@ class vframeArray: public CHeapObj {
+ 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]; }
+
--- a/callcc.txt Tue Jul 15 00:03:41 2008 -0700
+++ b/callcc.txt Tue Jul 15 00:12:32 2008 -0700
@@ -9,6 +9,10 @@ Features:
- re-execution can proceed with either normal return or a throw
- continuations can be delimited by marker frames
+Authors:
+- Lukas Stadler (JKU, Linz)
+- John Rose (Sun)
+
Tests:
- jdk/test/java/dyn/Continuations/TestCopyStack.java
@@ -19,9 +23,11 @@ This does not require a full JDK build.
$ mkdir build/bootcp
$ files='
-sources/jdk/test/java/dyn/Continuations/*.java
sources/jdk/src/share/classes/sun/misc/Unsafe.java
sources/jdk/src/share/classes/sun/reflect/Reflection.java
+sources/jdk/src/share/classes/javax/stack/Continuation.java
+sources/jdk/src/share/classes/javax/stack/StackFrame.java
+sources/jdk/test/java/dyn/Continuations/*.java
'
$ javac -d build/bootcp $files
$ java -XXaltjvm=?? -Xbootclasspath/p:build/bootcp TestCopyStack
--- a/series Tue Jul 15 00:03:41 2008 -0700
+++ b/series Tue Jul 15 00:12:32 2008 -0700
@@ -3,4 +3,4 @@ annot.patch #-/annot #+jdk7-b
#meth.patch #-/meth #+jdk7-b30 #-buildable
#indy.patch #-/indy #+jdk7-b30 #-buildable
#inti.patch #-/inti #+jdk7-b30 #-buildable
-callcc.patch #-/callcc #+jdk7-b25 #-testable
+callcc.patch #-/callcc #+jdk7-b30 #-testable