< prev index next >

src/hotspot/share/prims/stackwalk.cpp

Print this page
@@ -44,10 +44,15 @@
  #include "runtime/vframe.inline.hpp"
  #include "utilities/formatBuffer.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");
  }

@@ -64,16 +69,75 @@
    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(), cont_scope)) {
    _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) {
+      
+     _map = rm;
+     if (cont.is_null()) {
+       _jvf  = thread->last_java_vframe(rm);
+       _cont = thread->last_continuation();
+     } else {
+       _jvf  = Continuation::last_java_vframe(cont, rm);
+       _cont = NULL;
+     }
+ }
+ 
+ void JavaFrameStream::next() { 
+   _vfst.next(); 
+   if (_vfst.method()->is_continuation_enter_intrinsic()) 
+     _vfst.next();
+ }
+ 
+ void LiveFrameStream::next() {
+   assert (_cont_scope.is_null() || cont() != (oop)NULL, "must be");
+ 
+   oop cont = this->cont();
+   if (cont != (oop)NULL && Continuation::is_continuation_entry_frame(_jvf->fr(), _jvf->register_map())) {    
+     oop scope = jdk_internal_vm_Continuation::scope(cont);
+     if (_cont_scope.not_null() && scope == _cont_scope()) {
+       _jvf = NULL;
+       return;
+     }
+     _cont = _cont->parent();
+   }
+   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.

@@ -120,10 +184,11 @@
    assert(max_nframes > 0, "invalid max_nframes");
    assert(start_index + max_nframes <= frames_array->length(), "oob");
  
    int frames_decoded = 0;
    for (; !stream.at_end(); stream.next()) {
+     assert (stream.continuation() == NULL || stream.continuation() == stream.reg_map()->cont(), "");
      Method* method = stream.method();
  
      if (method == NULL) continue;
  
      // skip hidden frames for default StackWalker option (i.e. SHOW_HIDDEN_FRAMES

@@ -159,12 +224,26 @@
          err_msg("StackWalker::getCallerClass called from @CallerSensitive '%s' method",
                  method->external_name()));
      }
      // fill in StackFrameInfo and initialize MemberName
      stream.fill_frame(index, frames_array, methodHandle(THREAD, method), CHECK_0);
-     if (++frames_decoded >= max_nframes)  break;
+ 
+     if (lt.is_enabled()) {
+       ResourceMark rm(THREAD);
+       LogStream ls(lt);
+       ls.print("  %d: done frame method: ", index);
+       method->print_short_name(&ls);
+     }
+     frames_decoded++;
+ 
+     // We end a batch on continuation bottom to let the Java side skip top frames of the next one
+     if (stream.continuation() != NULL && method->intrinsic_id() == vmIntrinsics::_Continuation_enter) break;
+ 
+     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,

@@ -282,11 +361,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) {

@@ -326,41 +405,51 @@
  //
  // 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 = 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 = cont.is_null() ? RegisterMap(jt, true, true, true)
+                                         : RegisterMap(cont(), 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);
    }
  }
  

@@ -457,11 +546,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 = THREAD;
    BaseFrameStream* existing_stream = BaseFrameStream::from_current(jt, magic, frames_array);

@@ -501,5 +590,20 @@
        return end_index;
      }
    }
    return end_index;
  }
+ 
+ void StackWalk::setContinuation(Handle stackStream, jlong magic, objArrayHandle frames_array, Handle cont, TRAPS) {
+   JavaThread* jt = JavaThread::cast(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 >