changeset 8:99e6c3830f6d

callcc: resume works better, stack frame API Contributed-By: Lukas Stadler <lukas.stadler@jku.at> rebase to jdk7-b30
author jrose
date Tue, 15 Jul 2008 00:12:32 -0700
parents c0db1bded354
children 886f9ddefb15
files callcc.patch callcc.txt series
diffstat 3 files changed, 1380 insertions(+), 80 deletions(-) [+]
line wrap: on
line diff
--- 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/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 @@
  #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 @@
    // 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 @@
 +  bool check_read() {
 +    if (_rbytes.position() >= _rbytes_limit)
 +      set_losing();
-+    return is_losing();
++    return !is_losing();
 +  }
 +
-+  void write_stack_values(StackValueCollection* vs) {
-+    write_int(vs->size());
-+    for (int i = 0; i < vs->size(); i++) {
++  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 @@
 +    }
 +  }
 +
++  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());
++      write_int(m->eliminated());
 +    }
 +  }
 +
-+  void write_frame(javaVFrame* vf);
-+  vframe* read_frame();
++  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 @@
 +}
 +
 +
-+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,32 +849,36 @@
 +
 +  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) {
 +    // %%% Move this to javaClasses.cpp.
@@ -354,85 +905,390 @@
 +}
 +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);
++  JavaThread* THREAD = thread;
++  Deoptimization::UnrollBlock* unroll_block;
 +
-+  JavaThread* thread = JavaThread::thread_from_jni_environment(env);
-+  if (thread != THREAD)
-+    THROW_IE_("bad thread context", 0L);
++  ThreadInVMfromNative threadInVM(thread);
 +
-+  if (exception != NULL)
-+    THROW_IE_("resumeStack with exception NYI", 0L);
++  if (stack == NULL)
++    THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(), "stack cannot be null", 0);
 +
-+  // Deserialize the saved frames into a bunch of vframes:
-+  StackSerializer sser(thread, JNIHandles::resolve(stack), CHECK_0);
++  {
++    No_Safepoint_Verifier no_safepoint;
++    HandleMark hm(thread);
 +
-+  // vframeArray::fill_in and vframeArrayElement::fill_in
-+  // need to know how to pull data out of sser...  but how?
++    frame caller;
++    RegisterMap     reg_map(thread, false);
++    {
++      ResourceMark rm(thread);
 +
-+#ifndef NOT_IMPLEMENTED_YET
-+  THROW_IE_("resumeStack NYI", 0L);
-+#else //NOT_IMPLEMENTED_YET
-+  if (UseBiasedLocking) {
-+    Deoptimization::revoke_biases_of_monitors(thread, fr, &reg_map);
++      // 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));
 +  }
 +
-+  //Deoptimization::deoptimize_single_frame(thread, fr);
-+  //address deopt = SharedRuntime::deopt_blob()->unpack();
-+  //fr.patch_pc(thread, deopt);
++  DeoptimizationFunction deopt_func = (DeoptimizationFunction)SharedRuntime::deopt_blob()->unpack_with_continuation();
++  deopt_func(unroll_block);
++  return (jlong)unroll_block;
++}
 +
-+  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);
++#define CHECK_ARRAY_SIZE(var, array, type, size) if(array != NULL && array->length() == size)             \
++    var = array;                                                                                          \
++  else {                                                                                                  \
++    var = oopFactory::new_##type##Array(size, CHECK);                                                     \
 +  }
 +
-+  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
++// 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 @@
 +        }
 +        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 @@
 - 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 @@
 $ 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 @@
 #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