< prev index next >

src/hotspot/share/prims/stackwalk.cpp

Print this page

        

@@ -39,10 +39,15 @@
 #include "runtime/thread.inline.hpp"
 #include "runtime/vframe.inline.hpp"
 #include "utilities/globalDefinitions.hpp"
 
 // setup and cleanup actions
+BaseFrameStream::BaseFrameStream(JavaThread* thread, Handle continuation) 
+  : _thread(thread), _continuation(continuation), _anchor(0L) {
+    assert (thread != NULL, "");
+}
+
 void BaseFrameStream::setup_magic_on_entry(objArrayHandle frames_array) {
   frames_array->obj_at_put(magic_pos, _thread->threadObj());
   _anchor = address_value();
   assert(check_magic(frames_array), "invalid magic");
 }

@@ -59,16 +64,90 @@
   frames_array->obj_at_put(magic_pos, NULL);
   _anchor = 0L;
   return ok;
 }
 
-JavaFrameStream::JavaFrameStream(JavaThread* thread, int mode)
-  : BaseFrameStream(thread), _vfst(thread) {
+void BaseFrameStream::set_continuation(Handle cont) {
+  // ensure that the lifetime of the handle is that of the entire walk
+  // This actually also sets a copy of the handle in the RegisterMap,
+  // but that's OK, because we want them to be the same, anyway.
+  // (although we don't rely on this sharing, and set the other copy again)
+  // tty->print_cr("-- BaseFrameStream::set_continuation: %p", (oopDesc*)cont());
+  *(_continuation.raw_value()) = cont();
+}
+
+// static inline Handle continuation_of(Handle cont_or_scope) {
+//   return (cont_or_scope.not_null() && cont_or_scope()->is_a(SystemDictionary::Continuation_klass()))
+//             ? cont_or_scope
+//             : Handle();
+// }
+
+// static inline Handle continuationScope_of(JavaThread* thread, Handle cont_or_scope) {
+//   if (cont_or_scope.is_null() || cont_or_scope()->is_a(SystemDictionary::ContinuationScope_klass()))
+//     return cont_or_scope;
+//   assert (cont_or_scope()->is_a(SystemDictionary::Continuation_klass()), "must be");
+//   return Handle(thread, Continuation::continuation_scope(cont_or_scope()));
+// }
+
+JavaFrameStream::JavaFrameStream(JavaThread* thread, int mode, Handle cont_scope, Handle cont)
+  : BaseFrameStream(thread, cont), 
+   _vfst(cont.is_null()
+      ? vframeStream(thread, cont_scope)
+      : vframeStream(cont)) {
   _need_method_info = StackWalk::need_method_info(mode);
 }
 
-void JavaFrameStream::next() { _vfst.next();}
+LiveFrameStream::LiveFrameStream(JavaThread* thread, RegisterMap* rm, Handle cont_scope, Handle cont)
+   : BaseFrameStream(thread, cont), _cont_scope(cont_scope),
+    _cont(cont.not_null() ? cont : Handle(thread, thread->last_continuation())) {
+     
+    _map = rm;
+    if (cont.is_null()) {
+      _jvf  = thread->last_java_vframe(rm);
+      // _cont = Handle(thread, thread->last_continuation());
+    } else {
+      _jvf  = Continuation::has_last_Java_frame(cont) ? Continuation::last_java_vframe(cont, rm) : NULL;
+      // _cont = cont;
+    }
+}
+
+void JavaFrameStream::set_continuation(Handle cont) {
+  BaseFrameStream::set_continuation(cont);
+
+  _vfst = vframeStream(continuation()); // we must not use the handle argument (lifetime; see BaseFrameStream::set_continuation)
+}
+
+void LiveFrameStream::set_continuation(Handle cont) {
+  BaseFrameStream::set_continuation(cont);
+
+  _jvf = Continuation::last_java_vframe(continuation(), _map); // we must not use the handle argument (lifetime; see BaseFrameStream::set_continuation)
+  _cont = continuation(); // *(_cont.raw_value()) = cont(); // preserve handle
+  tty->print_cr("-- LiveFrameStream::set_continuation: %p", (oopDesc*)_cont());
+}
+
+void JavaFrameStream::next() { 
+  _vfst.next(); 
+}
+
+void LiveFrameStream::next() {
+  assert (_cont_scope.is_null() || _cont.not_null(), "must be");
+  if (_cont.not_null() && Continuation::is_continuation_entry_frame(_jvf->fr(), _jvf->register_map())) {
+    oop cont = _cont();
+    oop scope = java_lang_Continuation::scope(cont);
+
+    *(_cont.raw_value()) = java_lang_Continuation::parent(cont);
+    
+    if (_cont_scope.not_null() && oopDesc::equals(scope, _cont_scope())) {
+      assert (Continuation::is_frame_in_continuation(_jvf->fr(), cont), "must be");
+      _jvf = NULL;
+      return;
+    }
+  }
+  assert (!Continuation::is_scope_bottom(_cont_scope(), _jvf->fr(), _jvf->register_map()), "");
+  
+  _jvf = _jvf->java_sender();
+}
 
 // Returns the BaseFrameStream for the current stack being traversed.
 //
 // Parameters:
 //  thread         Current Java thread.

@@ -155,12 +234,22 @@
         err_msg("StackWalker::getCallerClass called from @CallerSensitive '%s' method",
                 method->external_name()));
     }
     // fill in StackFrameInfo and initialize MemberName
     stream.fill_frame(index, frames_array, method, CHECK_0);
+
+    if (lt.is_enabled()) {
+      ResourceMark rm(THREAD);
+      LogStream ls(lt);
+      ls.print("  %d: done frame method: ", index);
+      method->print_short_name(&ls);
+    }
+
     if (++frames_decoded >= max_nframes)  break;
   }
+  log_debug(stackwalk)("fill_in_frames done frames_decoded=%d at_end=%d", frames_decoded, stream.at_end());
+
   return frames_decoded;
 }
 
 // Fill in the LiveStackFrameInfo at the given index in frames_array
 void LiveFrameStream::fill_frame(int index, objArrayHandle  frames_array,

@@ -278,11 +367,11 @@
   return array_h;
 }
 
 // Fill StackFrameInfo with bci and initialize memberName
 void BaseFrameStream::fill_stackframe(Handle stackFrame, const methodHandle& method, TRAPS) {
-  java_lang_StackFrameInfo::set_method_and_bci(stackFrame, method, bci(), THREAD);
+  java_lang_StackFrameInfo::set_method_and_bci(stackFrame, method, bci(), cont(), THREAD);
 }
 
 // Fill LiveStackFrameInfo with locals, monitors, and expressions
 void LiveFrameStream::fill_live_stackframe(Handle stackFrame,
                                            const methodHandle& method, TRAPS) {

@@ -319,41 +408,50 @@
 //
 // Parameters:
 //   stackStream    StackStream object
 //   mode           Stack walking mode.
 //   skip_frames    Number of frames to be skipped.
+//   cont_scope     Continuation scope to walk (if not in this scope, we'll walk all the way).
 //   frame_count    Number of frames to be traversed.
 //   start_index    Start index to the user-supplied buffers.
 //   frames_array   Buffer to store StackFrame in, starting at start_index.
 //                  frames array is a Class<?>[] array when only getting caller
 //                  reference, and a StackFrameInfo[] array (or derivative)
 //                  otherwise. It should never be null.
 //
 // Returns Object returned from AbstractStackWalker::doStackWalk call.
 //
-oop StackWalk::walk(Handle stackStream, jlong mode,
-                    int skip_frames, int frame_count, int start_index,
-                    objArrayHandle frames_array,
+oop StackWalk::walk(Handle stackStream, jlong mode, int skip_frames, Handle cont_scope, Handle cont, 
+                    int frame_count, int start_index, objArrayHandle frames_array,
                     TRAPS) {
   ResourceMark rm(THREAD);
+  HandleMark hm(THREAD); // needed to store a continuation in the RegisterMap
+
   JavaThread* jt = (JavaThread*)THREAD;
-  log_debug(stackwalk)("Start walking: mode " JLONG_FORMAT " skip %d frames batch size %d",
-                       mode, skip_frames, frame_count);
+  log_debug(stackwalk)("Start walking: mode " JLONG_FORMAT " skip %d frames batch size %d", mode, skip_frames, frame_count);
+  LogTarget(Debug, stackwalk) lt;
+  if (lt.is_enabled()) {
+    ResourceMark rm(THREAD);
+    LogStream ls(lt);
+    ls.print("cont_scope: ");
+    cont_scope()->print_on(&ls);
+    ls.cr();
+  }
 
   if (frames_array.is_null()) {
     THROW_MSG_(vmSymbols::java_lang_NullPointerException(), "frames_array is NULL", NULL);
   }
 
   // Setup traversal onto my stack.
   if (live_frame_info(mode)) {
     assert (use_frames_array(mode), "Bad mode for get live frame");
-    RegisterMap regMap(jt, true);
-    LiveFrameStream stream(jt, &regMap);
+    RegisterMap regMap(jt, true, true);
+    LiveFrameStream stream(jt, &regMap, cont_scope, cont);
     return fetchFirstBatch(stream, stackStream, mode, skip_frames, frame_count,
                            start_index, frames_array, THREAD);
   } else {
-    JavaFrameStream stream(jt, mode);
+    JavaFrameStream stream(jt, mode, cont_scope, cont);
     return fetchFirstBatch(stream, stackStream, mode, skip_frames, frame_count,
                            start_index, frames_array, THREAD);
   }
 }
 

@@ -449,11 +547,11 @@
 //   frames_array   Buffer to store StackFrame in, starting at start_index.
 //
 // Returns the end index of frame filled in the buffer.
 //
 jint StackWalk::fetchNextBatch(Handle stackStream, jlong mode, jlong magic,
-                               int frame_count, int start_index,
+                               int frame_count, int start_index, 
                                objArrayHandle frames_array,
                                TRAPS)
 {
   JavaThread* jt = (JavaThread*)THREAD;
   BaseFrameStream* existing_stream = BaseFrameStream::from_current(jt, magic, frames_array);

@@ -488,5 +586,20 @@
       return end_index;
     }
   }
   return end_index;
 }
+
+void StackWalk::setContinuation(Handle stackStream, jlong magic, objArrayHandle frames_array, Handle cont, TRAPS) {
+  JavaThread* jt = (JavaThread*)THREAD;
+
+  if (frames_array.is_null()) {
+    THROW_MSG(vmSymbols::java_lang_NullPointerException(), "frames_array is NULL");
+  }
+
+  BaseFrameStream* existing_stream = BaseFrameStream::from_current(jt, magic, frames_array);
+  if (existing_stream == NULL) {
+    THROW_MSG(vmSymbols::java_lang_InternalError(), "doStackWalk: corrupted buffers");
+  }
+
+  existing_stream->set_continuation(cont);
+}
< prev index next >