changeset 53259:10e98b552e0e cont

Add continuation scope name to stack traces
author rpressler
date Fri, 04 Jan 2019 15:37:15 +0000
parents a8fab0f44f6c
children 8898bf2c1712 169b5b8a916d
files src/hotspot/share/classfile/javaClasses.cpp src/hotspot/share/classfile/javaClasses.hpp src/hotspot/share/classfile/javaClasses.inline.hpp src/hotspot/share/jvmci/jvmciCompilerToVM.cpp src/hotspot/share/prims/stackwalk.cpp src/hotspot/share/prims/stackwalk.hpp src/hotspot/share/runtime/continuation.cpp src/hotspot/share/runtime/thread.cpp src/hotspot/share/runtime/thread.hpp src/hotspot/share/runtime/vframe.cpp src/hotspot/share/runtime/vframe.hpp src/hotspot/share/runtime/vframe.inline.hpp src/hotspot/share/services/threadService.cpp src/hotspot/share/services/threadService.hpp src/java.base/share/classes/java/lang/Continuation.java src/java.base/share/classes/java/lang/ContinuationScope.java src/java.base/share/classes/java/lang/StackFrameInfo.java src/java.base/share/classes/java/lang/StackStreamFactory.java src/java.base/share/classes/java/lang/StackTraceElement.java src/java.base/share/classes/java/lang/StackWalker.java test/jdk/java/lang/Continuation/Scoped.java
diffstat 21 files changed, 264 insertions(+), 67 deletions(-) [+]
line wrap: on
line diff
--- a/src/hotspot/share/classfile/javaClasses.cpp	Wed Jan 02 17:05:38 2019 +0000
+++ b/src/hotspot/share/classfile/javaClasses.cpp	Fri Jan 04 15:37:15 2019 +0000
@@ -1985,6 +1985,7 @@
   typeArrayOop    _bcis;
   objArrayOop     _mirrors;
   typeArrayOop    _names; // needed to insulate method name against redefinition
+  objArrayOop     _conts;
   int             _index;
   NoSafepointVerifier _nsv;
 
@@ -1993,6 +1994,7 @@
     trace_bcis_offset    = java_lang_Throwable::trace_bcis_offset,
     trace_mirrors_offset = java_lang_Throwable::trace_mirrors_offset,
     trace_names_offset   = java_lang_Throwable::trace_names_offset,
+    trace_conts_offset   = java_lang_Throwable::trace_conts_offset,
     trace_next_offset    = java_lang_Throwable::trace_next_offset,
     trace_size           = java_lang_Throwable::trace_size,
     trace_chunk_size     = java_lang_Throwable::trace_chunk_size
@@ -2019,11 +2021,16 @@
     assert(names != NULL, "names array should be initialized in backtrace");
     return names;
   }
+  static objArrayOop get_conts(objArrayHandle chunk) {
+    objArrayOop conts = typeArrayOop(chunk->obj_at(trace_conts_offset));
+    assert(conts != NULL, "conts array should be initialized in backtrace");
+    return conts;
+  }
 
  public:
 
   // constructor for new backtrace
-  BacktraceBuilder(TRAPS): _head(NULL), _methods(NULL), _bcis(NULL), _mirrors(NULL), _names(NULL) {
+  BacktraceBuilder(TRAPS): _head(NULL), _methods(NULL), _bcis(NULL), _mirrors(NULL), _names(NULL), _conts(NULL) {
     expand(CHECK);
     _backtrace = Handle(THREAD, _head);
     _index = 0;
@@ -2034,9 +2041,11 @@
     _bcis = get_bcis(backtrace);
     _mirrors = get_mirrors(backtrace);
     _names = get_names(backtrace);
+    _conts = get_conts(backtrace);
     assert(_methods->length() == _bcis->length() &&
            _methods->length() == _mirrors->length() &&
-           _mirrors->length() == _names->length(),
+           _mirrors->length() == _names->length() && 
+           _names->length() == _conts->length(),
            "method and source information arrays should match");
 
     // head is the preallocated backtrace
@@ -2064,6 +2073,9 @@
     typeArrayOop names = oopFactory::new_symbolArray(trace_chunk_size, CHECK);
     typeArrayHandle new_names(THREAD, names);
 
+    objArrayOop conts = oopFactory::new_objectArray(trace_chunk_size, CHECK);
+    objArrayHandle new_conts(THREAD, conts);
+
     if (!old_head.is_null()) {
       old_head->obj_at_put(trace_next_offset, new_head());
     }
@@ -2071,12 +2083,14 @@
     new_head->obj_at_put(trace_bcis_offset, new_bcis());
     new_head->obj_at_put(trace_mirrors_offset, new_mirrors());
     new_head->obj_at_put(trace_names_offset, new_names());
+    new_head->obj_at_put(trace_conts_offset, new_conts());
 
     _head    = new_head();
     _methods = new_methods();
     _bcis = new_bcis();
     _mirrors = new_mirrors();
     _names  = new_names();
+    _conts  = new_conts();
     _index = 0;
   }
 
@@ -2084,7 +2098,7 @@
     return _backtrace();
   }
 
-  inline void push(Method* method, int bci, TRAPS) {
+  inline void push(Method* method, int bci, oop contScopeName, TRAPS) {
     // Smear the -1 bci to 0 since the array only holds unsigned
     // shorts.  The later line number lookup would just smear the -1
     // to a 0 even if it could be recorded.
@@ -2108,6 +2122,9 @@
     // from being unloaded while we still have this stack trace.
     assert(method->method_holder()->java_mirror() != NULL, "never push null for mirror");
     _mirrors->obj_at_put(_index, method->method_holder()->java_mirror());
+
+    _conts->obj_at_put(_index, contScopeName);
+
     _index++;
   }
 
@@ -2119,8 +2136,9 @@
   int _version;
   Symbol* _name;
   Handle _mirror;
-  BacktraceElement(Handle mirror, int mid, int version, int bci, Symbol* name) :
-                   _method_id(mid), _bci(bci), _version(version), _name(name), _mirror(mirror) {}
+  Handle _cont; // the continuation scope name (String)
+  BacktraceElement(Handle mirror, int mid, int version, int bci, Symbol* name, Handle cont) :
+                   _method_id(mid), _bci(bci), _version(version), _name(name), _mirror(mirror), _cont(cont) {}
 };
 
 class BacktraceIterator : public StackObj {
@@ -2130,6 +2148,7 @@
   typeArrayHandle _methods;
   typeArrayHandle _bcis;
   typeArrayHandle _names;
+  objArrayHandle  _conts;
 
   void init(objArrayHandle result, Thread* thread) {
     // Get method id, bci, version and mirror from chunk
@@ -2139,6 +2158,7 @@
       _bcis = typeArrayHandle(thread, BacktraceBuilder::get_bcis(_result));
       _mirrors = objArrayHandle(thread, BacktraceBuilder::get_mirrors(_result));
       _names = typeArrayHandle(thread, BacktraceBuilder::get_names(_result));
+      _conts = objArrayHandle(thread, BacktraceBuilder::get_conts(_result));
       _index = 0;
     }
   }
@@ -2153,7 +2173,8 @@
                         _methods->ushort_at(_index),
                         Backtrace::version_at(_bcis->int_at(_index)),
                         Backtrace::bci_at(_bcis->int_at(_index)),
-                        _names->symbol_at(_index));
+                        _names->symbol_at(_index),
+                        Handle(thread, _conts->obj_at(_index)));
     _index++;
 
     if (_index >= java_lang_Throwable::trace_chunk_size) {
@@ -2336,7 +2357,7 @@
   // with bci 0
   if (!thread->has_last_Java_frame()) {
     if (max_depth >= 1 && method() != NULL) {
-      bt.push(method(), 0, CHECK);
+      bt.push(method(), 0, NULL, CHECK);
       log_info(stacktrace)("%s, %d", throwable->klass()->external_name(), 1);
       set_depth(throwable(), 1);
       set_backtrace(throwable(), bt.backtrace());
@@ -2361,10 +2382,12 @@
   bool skip_fillInStackTrace_check = false;
   bool skip_throwableInit_check = false;
   bool skip_hidden = !ShowHiddenFrames;
-
-  for (frame fr = thread->last_frame(); max_depth == 0 || max_depth != total_count;) {
+  bool is_last = false;
+  oop cont = thread->last_continuation();
+  for (frame fr = thread->last_frame(); (max_depth == 0 || max_depth != total_count) && !is_last;) {
     Method* method = NULL;
     int bci = 0;
+    oop contScopeName = cont != NULL ? java_lang_ContinuationScope::name(java_lang_Continuation::scope(cont)) : NULL;
 
     // Compiled java method case.
     if (decode_offset != 0) {
@@ -2374,7 +2397,12 @@
       bci = stream.read_bci();
     } else {
       if (fr.is_first_frame()) break;
-      if (Continuation::is_scope_bottom(contScope(), fr, &map)) break;
+      if (Continuation::is_scope_bottom(contScope(), fr, &map)) 
+        is_last = true;
+
+      if (cont != NULL && Continuation::is_continuation_entry_frame(fr, &map)) {
+        cont = java_lang_Continuation::parent(cont);
+      }
       address pc = fr.pc();
       if (fr.is_interpreted_frame()) {
         address bcp;
@@ -2444,7 +2472,8 @@
     if (method->is_hidden()) {
       if (skip_hidden)  continue;
     }
-    bt.push(method, bci, CHECK);
+
+    bt.push(method, bci, contScopeName, CHECK);
     total_count++;
   }
 
@@ -2508,7 +2537,7 @@
   // fill in as much stack trace as possible
   int chunk_count = 0;
   for (;!st.at_end(); st.next()) {
-    bt.push(st.method(), st.bci(), CHECK);
+    bt.push(st.method(), st.bci(), NULL, CHECK);
     chunk_count++;
 
     // Bail-out for deep stacks
@@ -2555,11 +2584,13 @@
                                          method,
                                          bte._version,
                                          bte._bci,
-                                         bte._name, CHECK);
+                                         bte._name, 
+                                         bte._cont,
+                                         CHECK);
   }
 }
 
-oop java_lang_StackTraceElement::create(const methodHandle& method, int bci, TRAPS) {
+oop java_lang_StackTraceElement::create(const methodHandle& method, int bci, Handle contScope, TRAPS) {
   // Allocate java.lang.StackTraceElement instance
   InstanceKlass* k = SystemDictionary::StackTraceElement_klass();
   assert(k != NULL, "must be loaded in 1.4+");
@@ -2570,13 +2601,13 @@
   Handle element = k->allocate_instance_handle(CHECK_0);
 
   int version = method->constants()->version();
-  fill_in(element, method->method_holder(), method, version, bci, method->name(), CHECK_0);
+  fill_in(element, method->method_holder(), method, version, bci, method->name(), contScope, CHECK_0);
   return element();
 }
 
 void java_lang_StackTraceElement::fill_in(Handle element,
                                           InstanceKlass* holder, const methodHandle& method,
-                                          int version, int bci, Symbol* name, TRAPS) {
+                                          int version, int bci, Symbol* name, Handle contScopeName, TRAPS) {
   assert(element->is_a(SystemDictionary::StackTraceElement_klass()), "sanity check");
 
   // Fill in class name
@@ -2626,6 +2657,9 @@
     int line_number = Backtrace::get_line_number(method, bci);
     java_lang_StackTraceElement::set_lineNumber(element(), line_number);
   }
+
+  // Fill in continuation scope
+  java_lang_StackTraceElement::set_contScopeName(element(), contScopeName());
 }
 
 Method* java_lang_StackFrameInfo::get_method(Handle stackFrame, InstanceKlass* holder, TRAPS) {
@@ -2636,7 +2670,7 @@
   return method;
 }
 
-void java_lang_StackFrameInfo::set_method_and_bci(Handle stackFrame, const methodHandle& method, int bci, TRAPS) {
+void java_lang_StackFrameInfo::set_method_and_bci(Handle stackFrame, const methodHandle& method, int bci, oop cont, TRAPS) {
   // set Method* or mid/cpref
   Handle mname(Thread::current(), stackFrame->obj_field(_memberName_offset));
   InstanceKlass* ik = method->method_holder();
@@ -2648,6 +2682,9 @@
   int version = method->constants()->version();
   assert((jushort)version == version, "version should be short");
   java_lang_StackFrameInfo::set_version(stackFrame(), (short)version);
+
+  oop contScopeName = cont != NULL ? java_lang_ContinuationScope::name(java_lang_Continuation::scope(cont)): NULL;
+  java_lang_StackFrameInfo::set_contScopeName(stackFrame(), contScopeName);
 }
 
 void java_lang_StackFrameInfo::to_stack_trace_element(Handle stackFrame, Handle stack_trace_element, TRAPS) {
@@ -2656,16 +2693,18 @@
   Klass* clazz = java_lang_Class::as_Klass(java_lang_invoke_MemberName::clazz(mname()));
   InstanceKlass* holder = InstanceKlass::cast(clazz);
   Method* method = java_lang_StackFrameInfo::get_method(stackFrame, holder, CHECK);
+  Handle contScopeName(THREAD, stackFrame->obj_field(java_lang_StackFrameInfo::_contScopeName_offset));
 
   short version = stackFrame->short_field(_version_offset);
   short bci = stackFrame->short_field(_bci_offset);
   Symbol* name = method->name();
-  java_lang_StackTraceElement::fill_in(stack_trace_element, holder, method, version, bci, name, CHECK);
+  java_lang_StackTraceElement::fill_in(stack_trace_element, holder, method, version, bci, name, contScopeName, CHECK);
 }
 
 #define STACKFRAMEINFO_FIELDS_DO(macro) \
-  macro(_memberName_offset,     k, "memberName",  object_signature, false); \
-  macro(_bci_offset,            k, "bci",         short_signature,  false)
+  macro(_memberName_offset,     k, "memberName",    object_signature, false); \
+  macro(_bci_offset,            k, "bci",           short_signature,  false); \
+  macro(_contScopeName_offset,  k, "contScopeName", string_signature, false)
 
 void java_lang_StackFrameInfo::compute_offsets() {
   InstanceKlass* k = SystemDictionary::StackFrameInfo_klass();
@@ -4038,6 +4077,7 @@
 int java_lang_ref_Reference::discovered_offset;
 int java_lang_ref_SoftReference::timestamp_offset;
 int java_lang_ref_SoftReference::static_clock_offset;
+int java_lang_ContinuationScope::_name_offset;
 int java_lang_Continuation::_scope_offset;
 int java_lang_Continuation::_target_offset;
 int java_lang_Continuation::_stack_offset;
@@ -4069,9 +4109,11 @@
 int java_lang_StackTraceElement::classLoaderName_offset;
 int java_lang_StackTraceElement::declaringClass_offset;
 int java_lang_StackTraceElement::declaringClassObject_offset;
+int java_lang_StackTraceElement::contScope_offset;
 int java_lang_StackFrameInfo::_memberName_offset;
 int java_lang_StackFrameInfo::_bci_offset;
 int java_lang_StackFrameInfo::_version_offset;
+int java_lang_StackFrameInfo::_contScopeName_offset;
 int java_lang_LiveStackFrameInfo::_monitors_offset;
 int java_lang_LiveStackFrameInfo::_locals_offset;
 int java_lang_LiveStackFrameInfo::_operands_offset;
@@ -4095,7 +4137,8 @@
   macro(declaringClass_offset,  k, "declaringClass",  string_signature, false); \
   macro(methodName_offset,      k, "methodName",      string_signature, false); \
   macro(fileName_offset,        k, "fileName",        string_signature, false); \
-  macro(lineNumber_offset,      k, "lineNumber",      int_signature,    false)
+  macro(lineNumber_offset,      k, "lineNumber",      int_signature,    false); \
+  macro(contScope_offset,       k, "contScopeName",   string_signature, false)
 
 // Support for java_lang_StackTraceElement
 void java_lang_StackTraceElement::compute_offsets() {
@@ -4141,6 +4184,10 @@
   element->obj_field_put(declaringClassObject_offset, value);
 }
 
+void java_lang_StackTraceElement::set_contScopeName(oop element, oop value) {
+  element->obj_field_put(contScope_offset, value);
+}
+
 void java_lang_StackFrameInfo::set_version(oop element, short value) {
   element->short_field_put(_version_offset, value);
 }
@@ -4149,6 +4196,10 @@
   element->int_field_put(_bci_offset, value);
 }
 
+void java_lang_StackFrameInfo::set_contScopeName(oop element, oop value) {
+  element->obj_field_put(_contScopeName_offset, value);
+}
+
 void java_lang_LiveStackFrameInfo::set_monitors(oop element, oop value) {
   element->obj_field_put(_monitors_offset, value);
 }
@@ -4204,6 +4255,22 @@
   o->bool_field_put(deflt_offset, val);
 }
 
+// Support for java.lang.ContinuationScope
+
+#define CONTINUATIONSCOPE_FIELDS_DO(macro) \
+  macro(_name_offset, k, vmSymbols::name_name(), string_signature, false);
+
+void java_lang_ContinuationScope::compute_offsets() {
+  InstanceKlass* k = SystemDictionary::ContinuationScope_klass();
+  CONTINUATIONSCOPE_FIELDS_DO(FIELD_COMPUTE_OFFSET);
+}
+
+#if INCLUDE_CDS
+void java_lang_ContinuationScope::serialize_offsets(SerializeClosure* f) {
+  CONTINUATIONSCOPE_FIELDS_DO(FIELD_SERIALIZE_OFFSET);
+}
+#endif
+
 // Support for java.lang.Continuation
 
 #define CONTINUATION_FIELDS_DO(macro) \
--- a/src/hotspot/share/classfile/javaClasses.hpp	Wed Jan 02 17:05:38 2019 +0000
+++ b/src/hotspot/share/classfile/javaClasses.hpp	Fri Jan 04 15:37:15 2019 +0000
@@ -81,6 +81,7 @@
   f(java_lang_StackTraceElement) \
   f(java_lang_StackFrameInfo) \
   f(java_lang_LiveStackFrameInfo) \
+  f(java_lang_ContinuationScope) \
   f(java_lang_Continuation) \
   f(java_util_concurrent_locks_AbstractOwnableSynchronizer) \
   //end
@@ -514,8 +515,9 @@
     trace_bcis_offset    = 1,
     trace_mirrors_offset = 2,
     trace_names_offset   = 3,
-    trace_next_offset    = 4,
-    trace_size           = 5,
+    trace_conts_offset   = 4,
+    trace_next_offset    = 5,
+    trace_size           = 6,
     trace_chunk_size     = 32
   };
 
@@ -941,6 +943,19 @@
   static void serialize_offsets(SerializeClosure* f) NOT_CDS_RETURN;
 };
 
+// Interface to java.lang.ContinuationScope objects
+class java_lang_ContinuationScope: AllStatic {
+  friend class JavaClasses;
+ private:
+  static int _name_offset;
+
+  static void compute_offsets();
+ public:
+  static void serialize_offsets(SerializeClosure* f) NOT_CDS_RETURN;
+
+  static inline oop name(oop ref);
+};
+  
 // Interface to java.lang.Continuation objects
 class java_lang_Continuation: AllStatic {
   friend class JavaClasses;
@@ -1416,6 +1431,7 @@
   static int methodName_offset;
   static int fileName_offset;
   static int lineNumber_offset;
+  static int contScope_offset;
 
   // Setters
   static void set_classLoaderName(oop element, oop value);
@@ -1426,13 +1442,14 @@
   static void set_fileName(oop element, oop value);
   static void set_lineNumber(oop element, int value);
   static void set_declaringClassObject(oop element, oop value);
+  static void set_contScopeName(oop element, oop value);
 
  public:
   // Create an instance of StackTraceElement
-  static oop create(const methodHandle& method, int bci, TRAPS);
+  static oop create(const methodHandle& method, int bci, Handle contScope, TRAPS);
 
   static void fill_in(Handle element, InstanceKlass* holder, const methodHandle& method,
-                      int version, int bci, Symbol* name, TRAPS);
+                      int version, int bci, Symbol* name, Handle contScopeName, TRAPS);
 
   static void compute_offsets();
   static void serialize_offsets(SerializeClosure* f) NOT_CDS_RETURN;
@@ -1468,15 +1485,17 @@
   static int _memberName_offset;
   static int _bci_offset;
   static int _version_offset;
+  static int _contScopeName_offset;
 
   static Method* get_method(Handle stackFrame, InstanceKlass* holder, TRAPS);
 
 public:
   // Setters
-  static void set_method_and_bci(Handle stackFrame, const methodHandle& method, int bci, TRAPS);
+  static void set_method_and_bci(Handle stackFrame, const methodHandle& method, int bci, oop cont, TRAPS);
   static void set_bci(oop info, int value);
 
   static void set_version(oop info, short value);
+  static void set_contScopeName(oop info, oop value);
 
   static void compute_offsets();
   static void serialize_offsets(SerializeClosure* f) NOT_CDS_RETURN;
--- a/src/hotspot/share/classfile/javaClasses.inline.hpp	Wed Jan 02 17:05:38 2019 +0000
+++ b/src/hotspot/share/classfile/javaClasses.inline.hpp	Fri Jan 04 15:37:15 2019 +0000
@@ -135,6 +135,10 @@
   return InstanceKlass::cast(ref->klass())->reference_type() == REF_PHANTOM;
 }
 
+inline oop java_lang_ContinuationScope::name(oop ref) {
+  return ref->obj_field(_name_offset);
+}
+
 inline oop java_lang_Continuation::scope(oop ref) {
   return ref->obj_field(_scope_offset);
 }
--- a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp	Wed Jan 02 17:05:38 2019 +0000
+++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp	Fri Jan 04 15:37:15 2019 +0000
@@ -843,7 +843,7 @@
   HandleMark hm;
 
   methodHandle method = CompilerToVM::asMethod(jvmci_method);
-  oop element = java_lang_StackTraceElement::create(method, bci, CHECK_NULL);
+  oop element = java_lang_StackTraceElement::create(method, bci, Handle(), CHECK_NULL);
   return JNIHandles::make_local(THREAD, element);
 C2V_END
 
--- a/src/hotspot/share/prims/stackwalk.cpp	Wed Jan 02 17:05:38 2019 +0000
+++ b/src/hotspot/share/prims/stackwalk.cpp	Fri Jan 04 15:37:15 2019 +0000
@@ -89,11 +89,17 @@
 }
 
 LiveFrameStream::LiveFrameStream(JavaThread* thread, RegisterMap* rm, Handle cont_scope, Handle cont)
-   : BaseFrameStream(thread, cont), _cont_scope(cont_scope) {
+   : BaseFrameStream(thread, cont), _cont_scope(cont_scope),
+    _cont(cont.not_null() ? cont : Handle(thread, thread->last_continuation())) {
      
     _map = rm;
-    _jvf = cont.is_null() ? thread->last_java_vframe(rm)
-                          : Continuation::last_java_vframe(cont, rm);
+    if (cont.is_null()) {
+      _jvf  = thread->last_java_vframe(rm);
+      // _cont = Handle(thread, thread->last_continuation());
+    } else {
+      _jvf  = Continuation::last_java_vframe(cont, rm);
+      // _cont = cont;
+    }
 }
 
 void JavaFrameStream::set_continuation(Handle cont) {
@@ -106,9 +112,22 @@
   BaseFrameStream::set_continuation(cont);
 
   _jvf = Continuation::last_java_vframe(continuation(), _map); // we must not use the handle argument (lifetime; see BaseFrameStream::set_continuation)
+  _cont = cont;
 }
 
-void JavaFrameStream::next() { _vfst.next();}
+void JavaFrameStream::next() { _vfst.next(); }
+
+void LiveFrameStream::next() { 
+  if (_cont.not_null() && Continuation::is_continuation_entry_frame(_jvf->fr(), _jvf->register_map())) {
+    *(_cont.raw_value()) = java_lang_Continuation::parent(_cont());
+  }
+  
+  if (Continuation::is_scope_bottom(_cont_scope(), _jvf->fr(), _jvf->register_map())) {
+    _jvf = NULL;
+  } else {
+    _jvf = _jvf->java_sender();
+  }
+}
 
 // Returns the BaseFrameStream for the current stack being traversed.
 //
@@ -330,7 +349,7 @@
 
 // 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
--- a/src/hotspot/share/prims/stackwalk.hpp	Wed Jan 02 17:05:38 2019 +0000
+++ b/src/hotspot/share/prims/stackwalk.hpp	Fri Jan 04 15:37:15 2019 +0000
@@ -57,6 +57,7 @@
 
   virtual Method* method()=0;
   virtual int     bci()=0;
+  virtual oop     cont()=0; // returns the current continuation (even when walking a thread)
 
   virtual void    fill_frame(int index, objArrayHandle  frames_array,
                              const methodHandle& method, TRAPS)=0;
@@ -92,6 +93,7 @@
 
   Method* method() { return _vfst.method(); }
   int bci()        { return _vfst.bci(); }
+  oop cont()       { return _vfst.continuation(); }
 
   void fill_frame(int index, objArrayHandle  frames_array,
                   const methodHandle& method, TRAPS);
@@ -106,9 +108,11 @@
     MODE_COMPILED    = 0x02
   };
 
+  Handle                _cont_scope;  // the delimitation of this walk
+
   RegisterMap*          _map;
   javaVFrame*           _jvf;
-  Handle                _cont_scope;
+  Handle                _cont; // the current continuation
 
   void fill_live_stackframe(Handle stackFrame, const methodHandle& method, TRAPS);
   static oop create_primitive_slot_instance(StackValueCollection* values,
@@ -119,11 +123,12 @@
 public:
   LiveFrameStream(JavaThread* thread, RegisterMap* rm, Handle cont_scope, Handle cont);
 
-  void next()      { _jvf = _jvf->java_sender(); }
-  bool at_end()    { return _jvf == NULL || Continuation::is_scope_bottom(_cont_scope(), _jvf->fr(), _jvf->register_map()); }
+  void next();
+  bool at_end()    { return _jvf == NULL; }
 
   Method* method() { return _jvf->method(); }
   int bci()        { return _jvf->bci(); }
+  oop cont()       { return _jvf->continuation(); }
 
   void fill_frame(int index, objArrayHandle  frames_array,
                   const methodHandle& method, TRAPS);
--- a/src/hotspot/share/runtime/continuation.cpp	Wed Jan 02 17:05:38 2019 +0000
+++ b/src/hotspot/share/runtime/continuation.cpp	Fri Jan 04 15:37:15 2019 +0000
@@ -161,7 +161,7 @@
 }
 
 static oop get_continuation(JavaThread* thread) {
-  return java_lang_Thread::continuation(thread->threadObj());
+  return thread->last_continuation();
 }
 
 static long java_tid(JavaThread* thread) {
@@ -2346,7 +2346,7 @@
   oop scope = NULL;
   oop innermost = get_continuation(thread);
   for (oop c = innermost; c != NULL; c = java_lang_Continuation::parent(c)) {
-    if (c == cont) {
+    if (oopDesc::equals(c, cont)) {
       scope = java_lang_Continuation::scope(c);
       break;
     }
@@ -2357,10 +2357,16 @@
   if (thread->_cont_yield) {
     return -2; // during yield
   }
-  if (!oopDesc::equals(innermost, cont)) {
+  if (!oopDesc::equals(innermost, cont)) { // we have nested continuations
+    // make sure none of the continuations in the hierarchy are pinned
+    // for (oop c = innermost; c != NULL && !oopDesc::equals(c, cont); c = java_lang_Continuation::parent(c)) {
+    //   if ()
+    //     return PINNED;
+    // }
+
     java_lang_Continuation::set_yieldInfo(cont, scope);
   }
-  
+
 // #ifdef ASSERT
 //   tty->print_cr("FREEZING:");
 //   frame lf = thread->last_frame();
--- a/src/hotspot/share/runtime/thread.cpp	Wed Jan 02 17:05:38 2019 +0000
+++ b/src/hotspot/share/runtime/thread.cpp	Fri Jan 04 15:37:15 2019 +0000
@@ -3313,6 +3313,9 @@
   return NULL;
 }
 
+oop JavaThread::last_continuation() {
+  return java_lang_Thread::continuation(threadObj());
+}
 
 Klass* JavaThread::security_get_caller_class(int depth) {
   vframeStream vfst(this);
--- a/src/hotspot/share/runtime/thread.hpp	Wed Jan 02 17:05:38 2019 +0000
+++ b/src/hotspot/share/runtime/thread.hpp	Fri Jan 04 15:37:15 2019 +0000
@@ -1857,6 +1857,8 @@
   }
   javaVFrame* last_java_vframe(RegisterMap* reg_map);
 
+  oop last_continuation();
+  
   // Returns method at 'depth' java or native frames down the stack
   // Used for security checks
   Klass* security_get_caller_class(int depth);
--- a/src/hotspot/share/runtime/vframe.cpp	Wed Jan 02 17:05:38 2019 +0000
+++ b/src/hotspot/share/runtime/vframe.cpp	Fri Jan 04 15:37:15 2019 +0000
@@ -499,9 +499,14 @@
   }
 
   _frame = _thread->last_frame();
+  oop cont = _thread->last_continuation();
   while (!fill_from_frame()) {
+    if (cont != (oop)NULL && Continuation::is_continuation_entry_frame(_frame, &_reg_map)) {
+      cont = java_lang_Continuation::parent(cont);
+    }
     _frame = _frame.sender(&_reg_map);
   }
+  _cont = Handle(thread, cont);
 }
 
 vframeStream::vframeStream(Handle continuation) 
@@ -516,6 +521,7 @@
   }
 
   _frame = Continuation::last_frame(continuation, &_reg_map);
+  _cont = continuation;
   while (!fill_from_frame()) {
     _frame = _frame.sender(&_reg_map);
   }
--- a/src/hotspot/share/runtime/vframe.hpp	Wed Jan 02 17:05:38 2019 +0000
+++ b/src/hotspot/share/runtime/vframe.hpp	Fri Jan 04 15:37:15 2019 +0000
@@ -74,6 +74,7 @@
   frame*             frame_pointer() { return &_fr;       }
   const RegisterMap* register_map() const { return &_reg_map; }
   JavaThread*        thread()       const { return _thread;   }
+  oop                continuation() const { return _reg_map.cont(); }
 
   // Returns the sender vframe
   virtual vframe* sender() const;
@@ -292,6 +293,7 @@
   // Cached information
   Method* _method;
   int       _bci;
+  Handle   _cont; // the current frame's continuation
 
   // Should VM activations be ignored or not
   bool _stop_at_java_call_stub;
@@ -319,6 +321,7 @@
   int bci() const { return _bci; }
   inline intptr_t* frame_id() const;
   address frame_pc() const { return _frame.pc(); }
+  oop continuation() const { return _cont(); }
 
   CodeBlob*          cb()         const { return _frame.cb();  }
   CompiledMethod*   nm()         const {
--- a/src/hotspot/share/runtime/vframe.inline.hpp	Wed Jan 02 17:05:38 2019 +0000
+++ b/src/hotspot/share/runtime/vframe.inline.hpp	Fri Jan 04 15:37:15 2019 +0000
@@ -48,6 +48,14 @@
 
   // handle general case
   do {
+    if (_cont.not_null() && Continuation::is_continuation_entry_frame(_frame, &_reg_map)) {
+      *(_cont.raw_value()) = java_lang_Continuation::parent(_cont());
+    }
+    if (Continuation::is_scope_bottom(_continuation_scope(), _frame, &_reg_map)) {
+      _mode = at_end_mode;
+      break;
+    }
+
     _prev_frame = _frame;
     _frame = _frame.sender(&_reg_map);
   } while (!fill_from_frame());
@@ -63,10 +71,15 @@
   }
 
   _frame = _thread->last_frame();
+  oop cont = _thread->last_continuation();
   while (!fill_from_frame()) {
+    if (cont != (oop)NULL && Continuation::is_continuation_entry_frame(_frame, &_reg_map)) {
+      cont = java_lang_Continuation::parent(cont);
+    }
     _prev_frame = _frame;
     _frame = _frame.sender(&_reg_map);
   }
+  _cont = Handle(thread, cont);
 }
 
 inline bool vframeStreamCommon::fill_in_compiled_inlined_sender() {
@@ -141,10 +154,6 @@
   // Interpreted frame
   if (_frame.is_interpreted_frame()) {
     fill_from_interpreter_frame();
-
-    if (Continuation::is_scope_bottom(_continuation_scope(), _frame, &_reg_map))
-      _mode = at_end_mode;
-
     return true;
   }
 
@@ -207,9 +216,6 @@
       }
       fill_from_compiled_frame(decode_offset);
 
-      if (Continuation::is_scope_bottom(_continuation_scope(), _frame, &_reg_map))
-        _mode = at_end_mode;
-
       _vframe_id = 0;
     }
     return true;
--- a/src/hotspot/share/services/threadService.cpp	Wed Jan 02 17:05:38 2019 +0000
+++ b/src/hotspot/share/services/threadService.cpp	Fri Jan 04 15:37:15 2019 +0000
@@ -537,6 +537,7 @@
   _bci = jvf->bci();
   _class_holder = _method->method_holder()->klass_holder();
   _locked_monitors = NULL;
+  _cont_scope_name = jvf->continuation() != NULL ? java_lang_ContinuationScope::name(java_lang_Continuation::scope(jvf->continuation())) : NULL;
   if (with_lock_info) {
     ResourceMark rm;
     GrowableArray<MonitorInfo*>* list = jvf->locked_monitors();
@@ -560,6 +561,7 @@
     }
   }
   f->do_oop(&_class_holder);
+  f->do_oop(&_cont_scope_name);
 }
 
 void StackFrameInfo::metadata_do(void f(Metadata*)) {
@@ -681,7 +683,8 @@
   for (int j = 0; j < _depth; j++) {
     StackFrameInfo* frame = _frames->at(j);
     methodHandle mh(THREAD, frame->method());
-    oop element = java_lang_StackTraceElement::create(mh, frame->bci(), CHECK_NH);
+    Handle contScopeNameH(THREAD, frame->cont_scope_name());
+    oop element = java_lang_StackTraceElement::create(mh, frame->bci(), contScopeNameH, CHECK_NH);
     backtrace->obj_at_put(j, element);
   }
   return backtrace;
--- a/src/hotspot/share/services/threadService.hpp	Wed Jan 02 17:05:38 2019 +0000
+++ b/src/hotspot/share/services/threadService.hpp	Fri Jan 04 15:37:15 2019 +0000
@@ -287,6 +287,7 @@
  private:
   Method*             _method;
   int                 _bci;
+  oop                 _cont_scope_name;
   GrowableArray<oop>* _locked_monitors; // list of object monitors locked by this frame
   // We need to save the mirrors in the backtrace to keep the class
   // from being unloaded while we still have this stack trace.
@@ -300,8 +301,9 @@
       delete _locked_monitors;
     }
   };
-  Method*   method() const       { return _method; }
-  int       bci()    const       { return _bci; }
+  Method*   method() const          { return _method; }
+  int       bci()    const          { return _bci; }
+  oop       cont_scope_name() const { return _cont_scope_name; }
   void      oops_do(OopClosure* f);
   void      metadata_do(void f(Metadata*));
 
--- a/src/java.base/share/classes/java/lang/Continuation.java	Wed Jan 02 17:05:38 2019 +0000
+++ b/src/java.base/share/classes/java/lang/Continuation.java	Fri Jan 04 15:37:15 2019 +0000
@@ -814,8 +814,12 @@
 
     /**
      * TBD
+     * Subclasses may throw an {@link UnsupportedOperationException}, but this does not prevent
+     * the continuation from being preempted on a parent scope.
+     * 
      * @param thread TBD
      * @return TBD
+     * @throws UnsupportedOperationException if this continuation does not support preemption
      */
     public PreemptStatus tryPreempt(Thread thread) {
         return preemptStatus(tryForceYield0(thread));
--- a/src/java.base/share/classes/java/lang/ContinuationScope.java	Wed Jan 02 17:05:38 2019 +0000
+++ b/src/java.base/share/classes/java/lang/ContinuationScope.java	Fri Jan 04 15:37:15 2019 +0000
@@ -45,11 +45,29 @@
      * A constructor providing no name is available to subclasses.
      */
     protected ContinuationScope() {
-        this.name = null;
+        this.name = getClass().getName();
+    }
+
+    /**
+     * Returns this scope's name.
+     * @return this scope's name
+     */
+    public final String getName() {
+        return name;
     }
 
     @Override
-    public String toString() {
-        return name != null ? name : getClass().getName();
+    public final String toString() {
+        return name;
+    }
+
+    @Override
+    public final int hashCode() {
+        return super.hashCode();
+    }
+
+    @Override
+    public final boolean equals(Object obj) {
+        return super.equals(obj);
     }
 }
--- a/src/java.base/share/classes/java/lang/StackFrameInfo.java	Wed Jan 02 17:05:38 2019 +0000
+++ b/src/java.base/share/classes/java/lang/StackFrameInfo.java	Fri Jan 04 15:37:15 2019 +0000
@@ -40,6 +40,8 @@
     private final byte flags;
     private Object memberName;
     private short bci;
+    private String contScopeName;
+
     private volatile StackTraceElement ste;
 
     /*
@@ -66,6 +68,10 @@
         this.bci = bci;
     }
 
+    void setContinuationScopeName(String contScopeName) {
+        this.contScopeName = contScopeName;
+    }
+    
     protected void clear() {
     }
 
@@ -128,6 +134,11 @@
     }
 
     @Override
+    public java.lang.String getContinuationScopeName() {
+        return contScopeName;
+    }
+
+    @Override
     public String toString() {
         return toStackTraceElement().toString();
     }
--- a/src/java.base/share/classes/java/lang/StackStreamFactory.java	Wed Jan 02 17:05:38 2019 +0000
+++ b/src/java.base/share/classes/java/lang/StackStreamFactory.java	Fri Jan 04 15:37:15 2019 +0000
@@ -566,6 +566,7 @@
             sfi.clear();
             sfi.setMemberName(enter);
             sfi.setBCI((short)-1);
+            sfi.setContinuationScopeName(continuation.getScope().getName());
         }
 
         final Function<? super Stream<StackFrame>, ? extends T> function;  // callback
--- a/src/java.base/share/classes/java/lang/StackTraceElement.java	Wed Jan 02 17:05:38 2019 +0000
+++ b/src/java.base/share/classes/java/lang/StackTraceElement.java	Fri Jan 04 15:37:15 2019 +0000
@@ -66,6 +66,7 @@
     private String declaringClass;
     private String methodName;
     private String fileName;
+    private String contScopeName;
     private int    lineNumber;
     private byte   format = 0; // Default to show all
 
@@ -353,11 +354,21 @@
         }
         s = s.isEmpty() ? declaringClass : s + "/" + declaringClass;
 
-        return s + "." + methodName + "(" +
+        s = s + "." + methodName + "(" +
              (isNativeMethod() ? "Native Method)" :
               (fileName != null && lineNumber >= 0 ?
                fileName + ":" + lineNumber + ")" :
                 (fileName != null ?  ""+fileName+")" : "Unknown Source)")));
+
+        if (contScopeName != null && isContinuationEntry()) {
+            s = s + " " + contScopeName;
+        }
+
+        return s;
+    }
+
+    private boolean isContinuationEntry() {
+        return declaringClass.equals(Continuation.class.getName()) && methodName.equals("enter");
     }
 
     /**
@@ -398,7 +409,8 @@
             e.declaringClass.equals(declaringClass) &&
             e.lineNumber == lineNumber &&
             Objects.equals(methodName, e.methodName) &&
-            Objects.equals(fileName, e.fileName);
+            Objects.equals(fileName, e.fileName) &&
+            Objects.equals(contScopeName, e.contScopeName);
     }
 
     /**
@@ -410,6 +422,7 @@
         result = 31*result + Objects.hashCode(moduleName);
         result = 31*result + Objects.hashCode(moduleVersion);
         result = 31*result + Objects.hashCode(fileName);
+        result = 31*result + Objects.hashCode(contScopeName);
         result = 31*result + lineNumber;
         return result;
     }
--- a/src/java.base/share/classes/java/lang/StackWalker.java	Wed Jan 02 17:05:38 2019 +0000
+++ b/src/java.base/share/classes/java/lang/StackWalker.java	Fri Jan 04 15:37:15 2019 +0000
@@ -225,6 +225,16 @@
         public boolean isNativeMethod();
 
         /**
+         * Returns the name of the {@link ContinuationScope} of the continuation 
+         * (if any) in which this frame exists.
+         * 
+         * @return the name of the {@link ContinuationScope} of the continuation 
+         *         in which this frame exists or {@code null} if this frame is 
+         *         not in a continuation.
+         */
+        public String getContinuationScopeName();
+
+        /**
          * Gets a {@code StackTraceElement} for this stack frame.
          *
          * @return {@code StackTraceElement} for this stack frame.
--- a/test/jdk/java/lang/Continuation/Scoped.java	Wed Jan 02 17:05:38 2019 +0000
+++ b/test/jdk/java/lang/Continuation/Scoped.java	Fri Jan 04 15:37:15 2019 +0000
@@ -116,28 +116,23 @@
                 Continuation cont = new Continuation(C, ()-> {
                         Continuation.yield(A);
 
-                        StackWalker walker = StackWalker.getInstance();
-                        List<String> frames = walker.walk(fs -> fs.map(StackWalker.StackFrame::getMethodName).collect(Collectors.toList()));
+                        List<String> frames = StackWalker.getInstance().walk(fs -> fs.map(StackWalker.StackFrame::getMethodName).collect(Collectors.toList()));
                 
                         assertEquals(frames.subList(0, 15), Arrays.asList("lambda$bar$14", "enter0", "enter", "run", "bar", "lambda$foo$8", "enter0", "enter", "run", "foo", "lambda$test1$0", "enter0", "enter", "run", "test1"));
                 
-                        walker = StackWalker.getInstance(C);
-                        frames = walker.walk(fs -> fs.map(StackWalker.StackFrame::getMethodName).collect(Collectors.toList()));
+                        frames = StackWalker.getInstance(C).walk(fs -> fs.map(StackWalker.StackFrame::getMethodName).collect(Collectors.toList()));
                 
-                        assertEquals(frames, Arrays.asList("lambda$bar$14", "enter0"));
+                        assertEquals(frames, Arrays.asList("lambda$bar$14", "enter0", "enter"));
 
-                        walker = StackWalker.getInstance(B);
-                        frames = walker.walk(fs -> fs.map(StackWalker.StackFrame::getMethodName).collect(Collectors.toList()));
+                        frames = StackWalker.getInstance(B).walk(fs -> fs.map(StackWalker.StackFrame::getMethodName).collect(Collectors.toList()));
                 
-                        assertEquals(frames, Arrays.asList("lambda$bar$14", "enter0", "enter", "run", "bar", "lambda$foo$8", "enter0"));
+                        assertEquals(frames, Arrays.asList("lambda$bar$14", "enter0", "enter", "run", "bar", "lambda$foo$8", "enter0", "enter"));
 
-                        walker = StackWalker.getInstance(A);
-                        frames = walker.walk(fs -> fs.map(StackWalker.StackFrame::getMethodName).collect(Collectors.toList()));
+                        frames = StackWalker.getInstance(A).walk(fs -> fs.map(StackWalker.StackFrame::getMethodName).collect(Collectors.toList()));
                 
-                        assertEquals(frames, Arrays.asList("lambda$bar$14", "enter0", "enter", "run", "bar", "lambda$foo$8", "enter0", "enter", "run", "foo", "lambda$test1$0", "enter0"));
+                        assertEquals(frames, Arrays.asList("lambda$bar$14", "enter0", "enter", "run", "bar", "lambda$foo$8", "enter0", "enter", "run", "foo", "lambda$test1$0", "enter0", "enter"));
 
-                        walker = StackWalker.getInstance(K);
-                        frames = walker.walk(fs -> fs.map(StackWalker.StackFrame::getMethodName).collect(Collectors.toList()));
+                        frames = StackWalker.getInstance(K).walk(fs -> fs.map(StackWalker.StackFrame::getMethodName).collect(Collectors.toList()));
                 
                         assertEquals(frames.subList(0, 15), Arrays.asList("lambda$bar$14", "enter0", "enter", "run", "bar", "lambda$foo$8", "enter0", "enter", "run", "foo", "lambda$test1$0", "enter0", "enter", "run", "test1"));