--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/callcc.patch Tue Apr 15 01:26:33 2008 -0700
@@ -0,0 +1,459 @@
+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
+@@ -26,6 +26,7 @@
+ #include "incls/_sharedRuntime_x86_64.cpp.incl"
+
+ DeoptimizationBlob *SharedRuntime::_deopt_blob;
++intptr_t SharedRuntime_deopt_blob_resume_offset = 0; // %%% rename
+ #ifdef COMPILER2
+ UncommonTrapBlob *SharedRuntime::_uncommon_trap_blob;
+ ExceptionBlob *OptoRuntime::_exception_blob;
+@@ -1986,6 +1987,8 @@ void SharedRuntime::generate_deopt_blob(
+
+ __ reset_last_Java_frame(false, false);
+
++ SharedRuntime_deopt_blob_resume_offset = (__ pc() - start);
++
+ // Load UnrollBlock* into rdi
+ __ movq(rdi, rax);
+
+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
+@@ -313,7 +313,7 @@ constantPoolHandle ClassFileParser::pars
+ "Invalid constant pool index %u in class file %s",
+ class_index, CHECK_(nullHandle));
+ symbolOop name = cp->symbol_at(class_index);
+- klassOop wkk = SystemDictionary::find_well_known_klass(name);
++ klassOop wkk = NULL; //%%% S.B. SystemDictionary::find_well_known_klass(name);
+ if (wkk != NULL) {
+ cp->klass_at_put(index, wkk); // eagerly resolve
+ } else {
+@@ -431,7 +431,7 @@ void ClassFileParser::patch_constant_poo
+ case JVM_CONSTANT_UnresolvedClass :
+ // Patching a class means pre-resolving it.
+ // The name in the constant pool is ignored.
+- if (java_lang_Class::is_instance(patch())) {
++ if (patch->klass() == SystemDictionary::class_klass()) { // %%% java_lang_Class::is_instance
+ guarantee_property(!java_lang_Class::is_primitive(patch()),
+ "Illegal class patch at %d in class file %s",
+ index, CHECK);
+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
+
+ unsafe.cpp allocation.inline.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
+ unsafe.cpp synchronizer.hpp
+ unsafe.cpp threadService.hpp
+ unsafe.cpp vmSymbols.hpp
++
++unsafe.cpp oopFactory.hpp
++unsafe.cpp vframe.hpp
+
+ utf8.cpp utf8.hpp
+
+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,360 @@ UNSAFE_END
+ 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)
++
++class StackSerializer : public StackObj {
++ private:
++ JavaThread* _thread;
++ int _num_frames;
++
++ // Writer side:
++ GrowableArray<Handle>* _woops;
++ CompressedWriteStream _wbytes;
++
++ // Reader side:
++ CompressedReadStream _rbytes;
++ int _rbytes_limit;
++ objArrayHandle _roops;
++
++ bool _losing;
++
++ public:
++ enum { // layout of the stack_blob, which is of type Object[]
++ BYTES_INDEX = 0,
++ FIRST_OOP_INDEX = 1
++ };
++
++ // write constructor:
++ StackSerializer(JavaThread* thread)
++ : _thread(thread),
++ _num_frames(0),
++ _losing(false),
++ _woops(new GrowableArray<Handle>(100, 0, false)),
++ _wbytes(1000),
++ // null values:
++ _rbytes(NULL, 0), _rbytes_limit(0), _roops()
++ {
++ _woops->push(Handle());
++ assert(_woops->length() == FIRST_OOP_INDEX, "");
++ // Ready to collect frames...
++ }
++
++ // read constructor:
++ StackSerializer(JavaThread* thread, oop stack_blob_oop, TRAPS);
++
++ // read/write accessors:
++ int num_frames() {
++ return _num_frames;
++ }
++ oop oop_at(int i) {
++ return (_woops != NULL) ? _woops->at(i)() : _roops->obj_at(i);
++ }
++ int num_oops() {
++ return (_woops != NULL) ? _woops->length() : _roops->length();
++ }
++ bool is_losing() { return _losing; }
++ void set_losing() { _losing = true; }
++
++ void write_int(jint x) { _wbytes.write_int(x); }
++ void write_signed_int(jint x) { _wbytes.write_signed_int(x); }
++ void write_oop(oop x) { _wbytes.write_int( find_oop_index(x) ); }
++ jint find_oop_index(oop x);
++
++ jint read_int() { return !check_read() ? 0 : _rbytes.read_int(); }
++ jint read_signed_int() { return !check_read() ? 0 : _rbytes.read_signed_int(); }
++ oop read_oop() { return find_index_oop(_rbytes.read_int()); }
++ oop find_index_oop(jint x);
++ 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++) {
++ StackValue* v = vs->at(i);
++ BasicType vt = v->type();
++ write_int((int)vt);
++ switch (vt) {
++ case T_INT:
++ {
++ intptr_t x = v->get_int();
++ write_signed_int((jint)x);
++ LP64_ONLY({ x >>= 32; write_signed_int((jint)x); });
++ }
++ break;
++ case T_OBJECT:
++ write_oop(v->get_obj()());
++ break;
++ case T_CONFLICT:
++ break; //nothing to write
++ default:
++ ShouldNotReachHere();
++ }
++ }
++ }
++
++ 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();
++
++ Handle make_stack_blob(TRAPS);
++ Handle externalize(Handle x, TRAPS);
++};
++
++Handle StackSerializer::externalize(Handle x, TRAPS) {
++ Klass* xk = Klass::cast(x->klass());
++ if (!xk->is_subtype_of(SystemDictionary::object_klass())) {
++ if (xk->oop_is_method()) {
++ // Replace method refs by reflective methods.
++ x = Reflection::new_method((methodOop)x(), UseNewReflection, false, CHECK_NH);
++ } else {
++ assert(false, "unknown oop in stack frame");
++ return Handle();
++ }
++ } else {
++ assert(!x->is_method(), "");
++ assert(x->is_instance() || x->is_javaArray(), "");
++ }
++ return x;
++}
++
++Handle StackSerializer::make_stack_blob(TRAPS) {
++ if (is_losing())
++ THROW_IE_("bad StackSerializer state", Handle());
++
++ // Now we can write the header:
++ u_char wheader_buf[40];
++ CompressedWriteStream wheader(&wheader_buf[0], sizeof(wheader_buf));
++ wheader.write_int(num_frames());
++ int size1 = wheader.position();
++ int size2 = _wbytes.position();
++ int num_bytes = size1 + size2;
++
++ { // Create a byte[] array to hold the compressed stream.
++ typeArrayOop ba = oopFactory::new_byteArray(num_bytes, CHECK_NH);
++ Copy::conjoint_bytes(wheader.buffer(), ba->byte_at_addr(0), size1);
++ Copy::conjoint_bytes(_wbytes.buffer(), ba->byte_at_addr(size1), size2);
++ _woops->at_put(BYTES_INDEX, Handle(_thread, ba));
++ }
++
++ objArrayHandle blob;
++ {
++ objArrayOop tem = oopFactory::new_objArray(SystemDictionary::object_klass(), _woops->length(), CHECK_NH);
++ blob = objArrayHandle(_thread, tem);
++ }
++
++ for (int i = 0; i < _woops->length(); i++) {
++ Handle x = oop_at(i);
++ x = externalize(x, CHECK_NH);
++ blob->obj_at_put(i, x());
++ }
++ return blob;
++}
++
++StackSerializer::StackSerializer(JavaThread* thread, oop stack_blob_oop, TRAPS)
++ : _thread(thread),
++ _losing(false),
++ //for the moment:
++ _rbytes(NULL, 0),
++ // null values:
++ _wbytes(NULL, 0), _woops(NULL)
++{
++ // The handles are local. The data structures are resource-allocated,
++ // including the vframes. The StackSerializer itself is stack-allocated.
++ // It is used only as a stream of values to stuff into the vframeArray,
++ // which is heap allocated.
++
++ if (!(stack_blob_oop != NULL &&
++ stack_blob_oop->is_objArray() &&
++ ((objArrayOop)stack_blob_oop)->length() >= FIRST_OOP_INDEX &&
++ ((objArrayOop)stack_blob_oop)->obj_at(BYTES_INDEX) != NULL &&
++ ((objArrayOop)stack_blob_oop)->obj_at(BYTES_INDEX)->is_typeArray()))
++ THROW_IE("resumeStack on illegal state");
++
++ _roops = objArrayHandle(thread, (objArrayOop) stack_blob_oop);
++ stack_blob_oop = NULL;
++
++ {
++ typeArrayOop ba = (typeArrayOop) oop_at(BYTES_INDEX);
++ _rbytes_limit = ba->length();
++ const int SLOP = 10;
++ u_char* buf = NEW_RESOURCE_ARRAY(u_char, _rbytes_limit + SLOP);
++ Copy::conjoint_bytes(ba->byte_at_addr(0), buf, _rbytes_limit);
++ Copy::zero_to_bytes(buf + _rbytes_limit, SLOP);
++ _rbytes = CompressedReadStream(buf, 0);
++ ba = NULL;
++ }
++
++ _num_frames = read_int();
++}
++
++
++jint StackSerializer::find_oop_index(oop x) {
++ assert(_woops != NULL, "must be writing");
++ if (x == NULL) return FIRST_OOP_INDEX-1;
++ int n_oops = num_oops();
++ const int SEARCH_WINDOW = 100;
++ int probe_limit = MAX2((int)FIRST_OOP_INDEX, n_oops - SEARCH_WINDOW);
++ for (int i = n_oops-1; i > probe_limit; i--) {
++ if (oop_at(i) == x)
++ return i;
++ }
++ _woops->push(Handle(_thread, x));
++ assert(oop_at(n_oops) == x, "");
++ return n_oops;
++}
++
++oop StackSerializer::find_index_oop(jint x) {
++ assert(_roops.not_null(), "must be reading");
++ if (x < FIRST_OOP_INDEX || x >= num_oops()) {
++ if (x != FIRST_OOP_INDEX-1) {
++ set_losing(); // garbage index!
++ }
++ return NULL;
++ }
++ return oop_at(x);
++}
++
++
++void StackSerializer::write_frame(javaVFrame* vf) {
++ write_oop(vf->method());
++ write_int(vf->bci());
++ write_stack_values(vf->locals());
++ write_stack_values(vf->expressions());
++ write_monitors(vf->monitors());
++ _num_frames += 1;
++}
++
++static bool frame_matches_context(vframe* vf, jobject context) {
++ return false; //%%% TO-DO
++}
++
++UNSAFE_ENTRY(jobject, Unsafe_CopyStack(JNIEnv *env, jobject unsafe, jobject context, jobject cs_exception))
++ UnsafeWrapper("Unsafe_CopyStack");
++{
++ ResourceMark rm;
++
++ JavaThread* thread = JavaThread::thread_from_jni_environment(env);
++ if (thread != THREAD)
++ THROW_IE_("bad thread context", NULL);
++
++ // Serialize the stack:
++ StackSerializer sser(thread);
++ RegisterMap reg_map(thread, false);
++
++ vframe* vf = thread->last_java_vframe(®_map);
++ assert(Klass::cast(javaVFrame::cast(vf)->method()->method_holder())->name() == vmSymbols::sun_misc_Unsafe(), "");
++ vf = vf->sender(); // Skip Unsafe.copyStack itself.
++ for (; vf; vf = vf->sender()) {
++ if (sser.is_losing()) break;
++ if (vf->is_java_frame()) {
++ tty->print("copyStack: adding "); vf->print(); //@@
++ sser.write_frame(javaVFrame::cast(vf));
++ } else {
++ tty->print("copyStack: stopping at "); vf->print(); //@@
++ break;
++ }
++ if (context != NULL && frame_matches_context(vf, context)) {
++ tty->print("copyStack: stopping at context frame"); //@@
++ break;
++ }
++ }
++
++ Handle blob = sser.make_stack_blob(CHECK_NULL);
++
++ static int CSE_stack_offset = 0;
++ if (CSE_stack_offset == 0) {
++ // %%% Move this to javaClasses.cpp.
++ const char* CSE_name = "sun/misc/Unsafe$CopyStackException";
++ symbolHandle CSE_sym = oopFactory::new_symbol_handle(CSE_name, CHECK_NULL);
++ instanceKlassHandle CSE_klass = SystemDictionary::resolve_or_fail(CSE_sym, true, CHECK_NULL);
++ symbolHandle stack_sym = oopFactory::new_symbol_handle("stack", CHECK_NULL);
++ fieldDescriptor stack_fd;
++ if (!CSE_klass->find_local_field(stack_sym(), vmSymbols::object_signature(), &stack_fd)
++ || stack_fd.is_static())
++ THROW_IE_("missing field CopyStackException.stack", NULL);
++ CSE_stack_offset = stack_fd.offset();
++ }
++
++ // Signature of copyStack guarantees cs_exception is a CopyStackException.
++ Handle cs_ex_h(THREAD, JNIHandles::resolve(cs_exception));
++ if (cs_ex_h->obj_field(CSE_stack_offset) != NULL)
++ // Refuse to fill in a CSE twice. It would allow various spoofs.
++ THROW_IE_("CopyStackException has already been filled in", NULL);
++
++ cs_ex_h->obj_field_put(CSE_stack_offset, blob());
++
++ THROW_OOP_0(cs_ex_h());
++}
++UNSAFE_END
++
++UNSAFE_ENTRY(jlong, Unsafe_ResumeStack0(JNIEnv *env, jobject unsafe, jobject stack, jobject value, jobject exception))
++ UnsafeWrapper("Unsafe_ResumeStack0");
++{
++ 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, ®_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);
++ {
++ // 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
++}
++UNSAFE_END
++
++UNSAFE_ENTRY(void, Unsafe_DoCopyStackContext(JNIEnv *env, jobject unsafe, jobject context, jobject runnable))
++ UnsafeWrapper("Unsafe_DoCopyStackContext");
++ Unimplemented();
++UNSAFE_END
++
++
++
+ /// JVM_RegisterUnsafeMethods
+
+ #define ADR "J"
+@@ -1293,6 +1647,16 @@ static JNINativeMethod methods[] = {
+
+ };
+
++#define CSE "Lsun/misc/Unsafe$CopyStackException;"
++#define RBL LANG"Runnable;"
++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)}
++};
++#undef CSE
++#undef RBL
++
+ JNINativeMethod loadavg_method[] = {
+ {CC"getLoadAverage", CC"([DI)I", FN_PTR(Unsafe_Loadavg)}
+ };
+@@ -1388,6 +1752,15 @@ JVM_ENTRY(void, JVM_RegisterUnsafeMethod
+ env->ExceptionClear();
+ }
+ }
++ {
++ env->RegisterNatives(unsafecls, callcc_methods, sizeof(callcc_methods)/sizeof(JNINativeMethod));
++ if (env->ExceptionOccurred()) {
++ if (PrintMiscellaneous && (Verbose || WizardMode)) {
++ tty->print_cr("Warning: SDK 1.7 Unsafe.copyStack not found.");
++ }
++ env->ExceptionClear();
++ }
++ }
+ int status = env->RegisterNatives(unsafecls, methods, sizeof(methods)/sizeof(JNINativeMethod));
+ if (env->ExceptionOccurred()) {
+ if (PrintMiscellaneous && (Verbose || WizardMode)) {