8140450: Implement JEP 259: Stack-Walking API
authormchung
Mon, 23 Nov 2015 12:44:43 -0800
changeset 34253 ba3946143842
parent 34252 59d76c40998a
child 34256 8f3bbb94c253
child 34260 140ad0a387ff
child 34263 51465b543879
child 34265 fdd66cad641d
8140450: Implement JEP 259: Stack-Walking API Reviewed-by: coleenp, dfuchs, bchristi, psandoz, sspitsyn Contributed-by: Mandy Chung <mandy.chung@oracle.com>, Brent Christian <brent.christian@oracle.com>, Daniel Fuchs <daniel.fuchs@oracle.com>, Hamlin Li <huaming.li@oracle.com>
hotspot/make/share/makefiles/mapfile-vers
hotspot/src/share/vm/classfile/javaClasses.cpp
hotspot/src/share/vm/classfile/javaClasses.hpp
hotspot/src/share/vm/classfile/javaClasses.inline.hpp
hotspot/src/share/vm/classfile/systemDictionary.hpp
hotspot/src/share/vm/classfile/vmSymbols.hpp
hotspot/src/share/vm/memory/universe.cpp
hotspot/src/share/vm/memory/universe.hpp
hotspot/src/share/vm/prims/jvm.cpp
hotspot/src/share/vm/prims/jvm.h
hotspot/src/share/vm/prims/stackwalk.cpp
hotspot/src/share/vm/prims/stackwalk.hpp
hotspot/src/share/vm/runtime/globals.hpp
hotspot/src/share/vm/runtime/vframe.hpp
--- a/hotspot/make/share/makefiles/mapfile-vers	Fri Nov 20 12:42:21 2015 +0100
+++ b/hotspot/make/share/makefiles/mapfile-vers	Mon Nov 23 12:44:43 2015 -0800
@@ -7,6 +7,7 @@
                 JVM_ActiveProcessorCount;
                 JVM_ArrayCopy;
                 JVM_AssertionStatusDirectives;
+                JVM_CallStackWalk;
                 JVM_ClassDepth;
                 JVM_ClassLoaderDepth;
                 JVM_Clone;
@@ -36,6 +37,7 @@
                 JVM_DumpAllStacks;
                 JVM_DumpThreads;
                 JVM_FillInStackTrace;
+                JVM_FillStackFrames;
                 JVM_FindClassFromCaller;
                 JVM_FindClassFromClass;
                 JVM_FindClassFromBootLoader;
@@ -133,6 +135,7 @@
                 JVM_MonitorNotify;
                 JVM_MonitorNotifyAll;
                 JVM_MonitorWait;
+                JVM_MoreStackWalk;
                 JVM_NanoTime;
                 JVM_NativePath;
                 JVM_NewArray;
@@ -150,6 +153,7 @@
                 JVM_SetClassSigners;
                 JVM_SetNativeThreadName;
                 JVM_SetPrimitiveArrayElement;
+                JVM_SetMethodInfo;
                 JVM_SetThreadPriority;
                 JVM_Sleep;
                 JVM_StartThread;
--- a/hotspot/src/share/vm/classfile/javaClasses.cpp	Fri Nov 20 12:42:21 2015 +0100
+++ b/hotspot/src/share/vm/classfile/javaClasses.cpp	Mon Nov 23 12:44:43 2015 -0800
@@ -1518,43 +1518,11 @@
 // After this many redefines, the stack trace is unreliable.
 const int MAX_VERSION = USHRT_MAX;
 
-// Helper backtrace functions to store bci|version together.
-static inline int merge_bci_and_version(int bci, int version) {
-  // only store u2 for version, checking for overflow.
-  if (version > USHRT_MAX || version < 0) version = MAX_VERSION;
-  assert((jushort)bci == bci, "bci should be short");
-  return build_int_from_shorts(version, bci);
-}
-
-static inline int bci_at(unsigned int merged) {
-  return extract_high_short_from_int(merged);
-}
-static inline int version_at(unsigned int merged) {
-  return extract_low_short_from_int(merged);
-}
-
 static inline bool version_matches(Method* method, int version) {
   assert(version < MAX_VERSION, "version is too big");
   return method != NULL && (method->constants()->version() == version);
 }
 
-static inline int get_line_number(Method* method, int bci) {
-  int line_number = 0;
-  if (method->is_native()) {
-    // Negative value different from -1 below, enabling Java code in
-    // class java.lang.StackTraceElement to distinguish "native" from
-    // "no LineNumberTable".  JDK tests for -2.
-    line_number = -2;
-  } else {
-    // Returns -1 if no LineNumberTable, and otherwise actual line number
-    line_number = method->line_number_from_bci(bci);
-    if (line_number == -1 && ShowHiddenFrames) {
-      line_number = bci + 1000000;
-    }
-  }
-  return line_number;
-}
-
 // This class provides a simple wrapper over the internal structure of
 // exception backtrace to insulate users of the backtrace from needing
 // to know what it looks like.
@@ -1676,7 +1644,7 @@
     }
 
     _methods->short_at_put(_index, method->orig_method_idnum());
-    _bcis->int_at_put(_index, merge_bci_and_version(bci, method->constants()->version()));
+    _bcis->int_at_put(_index, Backtrace::merge_bci_and_version(bci, method->constants()->version()));
     _cprefs->short_at_put(_index, method->name_index());
 
     // We need to save the mirrors in the backtrace to keep the class
@@ -1688,19 +1656,6 @@
 
 };
 
-Symbol* get_source_file_name(InstanceKlass* holder, int version) {
-  // Find the specific ik version that contains this source_file_name_index
-  // via the previous versions list, but use the current version's
-  // constant pool to look it up.  The previous version's index has been
-  // merged for the current constant pool.
-  InstanceKlass* ik = holder->get_klass_version(version);
-  // This version has been cleaned up.
-  if (ik == NULL) return NULL;
-  int source_file_name_index = ik->source_file_name_index();
-  return (source_file_name_index == 0) ?
-      (Symbol*)NULL : holder->constants()->symbol_at(source_file_name_index);
-}
-
 // Print stack trace element to resource allocated buffer
 char* java_lang_Throwable::print_stack_element_to_buffer(Handle mirror,
                                   int method_id, int version, int bci, int cpref) {
@@ -1718,7 +1673,7 @@
   buf_len += (int)strlen(method_name);
 
   char* source_file_name = NULL;
-  Symbol* source = get_source_file_name(holder, version);
+  Symbol* source = Backtrace::get_source_file_name(holder, version);
   if (source != NULL) {
     source_file_name = source->as_C_string();
     buf_len += (int)strlen(source_file_name);
@@ -1733,7 +1688,7 @@
   if (!version_matches(method, version)) {
     strcat(buf, "(Redefined)");
   } else {
-    int line_number = get_line_number(method, bci);
+    int line_number = Backtrace::get_line_number(method, bci);
     if (line_number == -2) {
       strcat(buf, "(Native Method)");
     } else {
@@ -1802,8 +1757,8 @@
         // NULL mirror means end of stack trace
         if (mirror.is_null()) goto handle_cause;
         int method = methods->short_at(index);
-        int version = version_at(bcis->int_at(index));
-        int bci = bci_at(bcis->int_at(index));
+        int version = Backtrace::version_at(bcis->int_at(index));
+        int bci = Backtrace::bci_at(bcis->int_at(index));
         int cpref = cprefs->short_at(index);
         print_stack_element(st, mirror, method, version, bci, cpref);
       }
@@ -2090,8 +2045,8 @@
   assert(methods != NULL && bcis != NULL && mirrors != NULL, "sanity check");
 
   int method = methods->short_at(chunk_index);
-  int version = version_at(bcis->int_at(chunk_index));
-  int bci = bci_at(bcis->int_at(chunk_index));
+  int version = Backtrace::version_at(bcis->int_at(chunk_index));
+  int bci = Backtrace::bci_at(bcis->int_at(chunk_index));
   int cpref = cprefs->short_at(chunk_index);
   Handle mirror(THREAD, mirrors->obj_at(chunk_index));
 
@@ -2114,6 +2069,7 @@
   }
 
   Handle element = ik->allocate_instance_handle(CHECK_0);
+
   // Fill in class name
   ResourceMark rm(THREAD);
   InstanceKlass* holder = InstanceKlass::cast(java_lang_Class::as_Klass(mirror()));
@@ -2136,13 +2092,13 @@
     java_lang_StackTraceElement::set_lineNumber(element(), -1);
   } else {
     // Fill in source file name and line number.
-    Symbol* source = get_source_file_name(holder, version);
+    Symbol* source = Backtrace::get_source_file_name(holder, version);
     if (ShowHiddenFrames && source == NULL)
       source = vmSymbols::unknown_class_name();
     oop filename = StringTable::intern(source, CHECK_0);
     java_lang_StackTraceElement::set_fileName(element(), filename);
 
-    int line_number = get_line_number(method, bci);
+    int line_number = Backtrace::get_line_number(method, bci);
     java_lang_StackTraceElement::set_lineNumber(element(), line_number);
   }
   return element();
@@ -2155,6 +2111,108 @@
   return create(mirror, method_id, method->constants()->version(), bci, cpref, THREAD);
 }
 
+Method* java_lang_StackFrameInfo::get_method(Handle stackFrame, InstanceKlass* holder, TRAPS) {
+  if (MemberNameInStackFrame) {
+    Handle mname(THREAD, stackFrame->obj_field(_memberName_offset));
+    Method* method = (Method*)java_lang_invoke_MemberName::vmtarget(mname());
+    // we should expand MemberName::name when Throwable uses StackTrace
+    // MethodHandles::expand_MemberName(mname, MethodHandles::_suppress_defc|MethodHandles::_suppress_type, CHECK_NULL);
+    return method;
+  } else {
+    short mid       = stackFrame->short_field(_mid_offset);
+    short version   = stackFrame->short_field(_version_offset);
+    return holder->method_with_orig_idnum(mid, version);
+  }
+}
+
+Symbol* java_lang_StackFrameInfo::get_file_name(Handle stackFrame, InstanceKlass* holder) {
+  if (MemberNameInStackFrame) {
+    return holder->source_file_name();
+  } else {
+    short version = stackFrame->short_field(_version_offset);
+    return Backtrace::get_source_file_name(holder, version);
+  }
+}
+
+void java_lang_StackFrameInfo::set_method_and_bci(Handle stackFrame, const methodHandle& method, int bci) {
+  // set Method* or mid/cpref
+  if (MemberNameInStackFrame) {
+    oop mname = stackFrame->obj_field(_memberName_offset);
+    InstanceKlass* ik = method->method_holder();
+    CallInfo info(method(), ik);
+    MethodHandles::init_method_MemberName(mname, info);
+  } else {
+    int mid = method->orig_method_idnum();
+    int cpref = method->name_index();
+    assert((jushort)mid == mid,        "mid should be short");
+    assert((jushort)cpref == cpref,    "cpref should be short");
+    java_lang_StackFrameInfo::set_mid(stackFrame(),     (short)mid);
+    java_lang_StackFrameInfo::set_cpref(stackFrame(),   (short)cpref);
+  }
+  // set bci
+  java_lang_StackFrameInfo::set_bci(stackFrame(), bci);
+  // method may be redefined; store the version
+  int version = method->constants()->version();
+  assert((jushort)version == version, "version should be short");
+  java_lang_StackFrameInfo::set_version(stackFrame(), (short)version);
+}
+
+void java_lang_StackFrameInfo::fill_methodInfo(Handle stackFrame, TRAPS) {
+  ResourceMark rm(THREAD);
+  oop k = stackFrame->obj_field(_declaringClass_offset);
+  InstanceKlass* holder = InstanceKlass::cast(java_lang_Class::as_Klass(k));
+  Method* method = java_lang_StackFrameInfo::get_method(stackFrame, holder, CHECK);
+  int bci = stackFrame->int_field(_bci_offset);
+
+  // The method can be NULL if the requested class version is gone
+  Symbol* sym = (method != NULL) ? method->name() : NULL;
+  if (MemberNameInStackFrame) {
+    assert(sym != NULL, "MemberName must have method name");
+  } else {
+      // The method can be NULL if the requested class version is gone
+    if (sym == NULL) {
+      short cpref   = stackFrame->short_field(_cpref_offset);
+      sym = holder->constants()->symbol_at(cpref);
+    }
+  }
+
+  // set method name
+  oop methodname = StringTable::intern(sym, CHECK);
+  java_lang_StackFrameInfo::set_methodName(stackFrame(), methodname);
+
+  // set file name and line number
+  Symbol* source = get_file_name(stackFrame, holder);
+  if (source != NULL) {
+    oop filename = StringTable::intern(source, CHECK);
+    java_lang_StackFrameInfo::set_fileName(stackFrame(), filename);
+  }
+
+  // if the method has been redefined, the bci is no longer applicable
+  short version = stackFrame->short_field(_version_offset);
+  if (version_matches(method, version)) {
+    int line_number = Backtrace::get_line_number(method, bci);
+    java_lang_StackFrameInfo::set_lineNumber(stackFrame(), line_number);
+  }
+}
+
+void java_lang_StackFrameInfo::compute_offsets() {
+  Klass* k = SystemDictionary::StackFrameInfo_klass();
+  compute_offset(_declaringClass_offset, k, vmSymbols::declaringClass_name(),  vmSymbols::class_signature());
+  compute_offset(_memberName_offset,     k, vmSymbols::memberName_name(),  vmSymbols::object_signature());
+  compute_offset(_bci_offset,            k, vmSymbols::bci_name(),         vmSymbols::int_signature());
+  compute_offset(_methodName_offset,     k, vmSymbols::methodName_name(),  vmSymbols::string_signature());
+  compute_offset(_fileName_offset,       k, vmSymbols::fileName_name(),    vmSymbols::string_signature());
+  compute_offset(_lineNumber_offset,     k, vmSymbols::lineNumber_name(),  vmSymbols::int_signature());
+  STACKFRAMEINFO_INJECTED_FIELDS(INJECTED_FIELD_COMPUTE_OFFSET);
+}
+
+void java_lang_LiveStackFrameInfo::compute_offsets() {
+  Klass* k = SystemDictionary::LiveStackFrameInfo_klass();
+  compute_offset(_monitors_offset,   k, vmSymbols::monitors_name(),    vmSymbols::object_array_signature());
+  compute_offset(_locals_offset,     k, vmSymbols::locals_name(),      vmSymbols::object_array_signature());
+  compute_offset(_operands_offset,   k, vmSymbols::operands_name(),    vmSymbols::object_array_signature());
+}
+
 void java_lang_reflect_AccessibleObject::compute_offsets() {
   Klass* k = SystemDictionary::reflect_AccessibleObject_klass();
   compute_offset(override_offset, k, vmSymbols::override_name(), vmSymbols::bool_signature());
@@ -3471,6 +3529,18 @@
 int java_lang_StackTraceElement::methodName_offset;
 int java_lang_StackTraceElement::fileName_offset;
 int java_lang_StackTraceElement::lineNumber_offset;
+int java_lang_StackFrameInfo::_declaringClass_offset;
+int java_lang_StackFrameInfo::_memberName_offset;
+int java_lang_StackFrameInfo::_bci_offset;
+int java_lang_StackFrameInfo::_methodName_offset;
+int java_lang_StackFrameInfo::_fileName_offset;
+int java_lang_StackFrameInfo::_lineNumber_offset;
+int java_lang_StackFrameInfo::_mid_offset;
+int java_lang_StackFrameInfo::_version_offset;
+int java_lang_StackFrameInfo::_cpref_offset;
+int java_lang_LiveStackFrameInfo::_monitors_offset;
+int java_lang_LiveStackFrameInfo::_locals_offset;
+int java_lang_LiveStackFrameInfo::_operands_offset;
 int java_lang_AssertionStatusDirectives::classes_offset;
 int java_lang_AssertionStatusDirectives::classEnabled_offset;
 int java_lang_AssertionStatusDirectives::packages_offset;
@@ -3500,6 +3570,50 @@
   element->int_field_put(lineNumber_offset, value);
 }
 
+// Support for java_lang_StackFrameInfo
+void java_lang_StackFrameInfo::set_declaringClass(oop element, oop value) {
+  element->obj_field_put(_declaringClass_offset, value);
+}
+
+void java_lang_StackFrameInfo::set_mid(oop element, short value) {
+  element->short_field_put(_mid_offset, value);
+}
+
+void java_lang_StackFrameInfo::set_version(oop element, short value) {
+  element->short_field_put(_version_offset, value);
+}
+
+void java_lang_StackFrameInfo::set_cpref(oop element, short value) {
+  element->short_field_put(_cpref_offset, value);
+}
+
+void java_lang_StackFrameInfo::set_bci(oop element, int value) {
+  element->int_field_put(_bci_offset, value);
+}
+
+void java_lang_StackFrameInfo::set_fileName(oop element, oop value) {
+  element->obj_field_put(_fileName_offset, value);
+}
+
+void java_lang_StackFrameInfo::set_methodName(oop element, oop value) {
+  element->obj_field_put(_methodName_offset, value);
+}
+
+void java_lang_StackFrameInfo::set_lineNumber(oop element, int value) {
+  element->int_field_put(_lineNumber_offset, value);
+}
+
+void java_lang_LiveStackFrameInfo::set_monitors(oop element, oop value) {
+  element->obj_field_put(_monitors_offset, value);
+}
+
+void java_lang_LiveStackFrameInfo::set_locals(oop element, oop value) {
+  element->obj_field_put(_locals_offset, value);
+}
+
+void java_lang_LiveStackFrameInfo::set_operands(oop element, oop value) {
+  element->obj_field_put(_operands_offset, value);
+}
 
 // Support for java Assertions - java_lang_AssertionStatusDirectives.
 
@@ -3633,6 +3747,8 @@
   sun_reflect_ConstantPool::compute_offsets();
   sun_reflect_UnsafeStaticFieldAccessorImpl::compute_offsets();
   java_lang_reflect_Parameter::compute_offsets();
+  java_lang_StackFrameInfo::compute_offsets();
+  java_lang_LiveStackFrameInfo::compute_offsets();
 
   // generated interpreter code wants to know about the offsets we just computed:
   AbstractAssembler::update_delayed_values();
--- a/hotspot/src/share/vm/classfile/javaClasses.hpp	Fri Nov 20 12:42:21 2015 +0100
+++ b/hotspot/src/share/vm/classfile/javaClasses.hpp	Mon Nov 23 12:44:43 2015 -0800
@@ -1359,6 +1359,85 @@
 };
 
 
+class Backtrace: AllStatic {
+ public:
+  // Helper backtrace functions to store bci|version together.
+  static int merge_bci_and_version(int bci, int version);
+  static int merge_mid_and_cpref(int mid, int cpref);
+  static int bci_at(unsigned int merged);
+  static int version_at(unsigned int merged);
+  static int mid_at(unsigned int merged);
+  static int cpref_at(unsigned int merged);
+  static int get_line_number(const methodHandle& method, int bci);
+  static Symbol* get_source_file_name(InstanceKlass* holder, int version);
+
+  // Debugging
+  friend class JavaClasses;
+};
+
+// Interface to java.lang.StackFrameInfo objects
+
+#define STACKFRAMEINFO_INJECTED_FIELDS(macro)                      \
+  macro(java_lang_StackFrameInfo, mid,     short_signature, false) \
+  macro(java_lang_StackFrameInfo, version, short_signature, false) \
+  macro(java_lang_StackFrameInfo, cpref,   short_signature, false)
+
+class java_lang_StackFrameInfo: AllStatic {
+private:
+  static int _declaringClass_offset;
+  static int _memberName_offset;
+  static int _bci_offset;
+  static int _methodName_offset;
+  static int _fileName_offset;
+  static int _lineNumber_offset;
+
+  static int _mid_offset;
+  static int _version_offset;
+  static int _cpref_offset;
+
+  static Method* get_method(Handle stackFrame, InstanceKlass* holder, TRAPS);
+  static Symbol* get_file_name(Handle stackFrame, InstanceKlass* holder);
+
+public:
+  // Setters
+  static void set_declaringClass(oop info, oop value);
+  static void set_method_and_bci(Handle stackFrame, const methodHandle& method, int bci);
+  static void set_bci(oop info, int value);
+
+  // set method info in an instance of StackFrameInfo
+  static void fill_methodInfo(Handle info, TRAPS);
+  static void set_methodName(oop info, oop value);
+  static void set_fileName(oop info, oop value);
+  static void set_lineNumber(oop info, int value);
+
+  // these injected fields are only used if -XX:-MemberNameInStackFrame set
+  static void set_mid(oop info, short value);
+  static void set_version(oop info, short value);
+  static void set_cpref(oop info, short value);
+
+  static void compute_offsets();
+
+  // Debugging
+  friend class JavaClasses;
+};
+
+class java_lang_LiveStackFrameInfo: AllStatic {
+ private:
+  static int _monitors_offset;
+  static int _locals_offset;
+  static int _operands_offset;
+
+ public:
+  static void set_monitors(oop info, oop value);
+  static void set_locals(oop info, oop value);
+  static void set_operands(oop info, oop value);
+
+  static void compute_offsets();
+
+  // Debugging
+  friend class JavaClasses;
+};
+
 // Interface to java.lang.AssertionStatusDirectives objects
 
 class java_lang_AssertionStatusDirectives: AllStatic {
@@ -1442,7 +1521,9 @@
   CLASS_INJECTED_FIELDS(macro)              \
   CLASSLOADER_INJECTED_FIELDS(macro)        \
   MEMBERNAME_INJECTED_FIELDS(macro)         \
-  CALLSITECONTEXT_INJECTED_FIELDS(macro)
+  CALLSITECONTEXT_INJECTED_FIELDS(macro)    \
+  STACKFRAMEINFO_INJECTED_FIELDS(macro)
+
 
 // Interface to hard-coded offset checking
 
--- a/hotspot/src/share/vm/classfile/javaClasses.inline.hpp	Fri Nov 20 12:42:21 2015 +0100
+++ b/hotspot/src/share/vm/classfile/javaClasses.inline.hpp	Mon Nov 23 12:44:43 2015 -0800
@@ -73,4 +73,67 @@
   return obj != NULL && is_subclass(obj->klass());
 }
 
+inline int Backtrace::merge_bci_and_version(int bci, int version) {
+  // only store u2 for version, checking for overflow.
+  if (version > USHRT_MAX || version < 0) version = USHRT_MAX;
+  assert((jushort)bci == bci, "bci should be short");
+  return build_int_from_shorts(version, bci);
+}
+
+inline int Backtrace::merge_mid_and_cpref(int mid, int cpref) {
+  // only store u2 for mid and cpref, checking for overflow.
+  assert((jushort)mid == mid, "mid should be short");
+  assert((jushort)cpref == cpref, "cpref should be short");
+  return build_int_from_shorts(cpref, mid);
+}
+
+inline int Backtrace::bci_at(unsigned int merged) {
+  return extract_high_short_from_int(merged);
+}
+
+inline int Backtrace::version_at(unsigned int merged) {
+  return extract_low_short_from_int(merged);
+}
+
+inline int Backtrace::mid_at(unsigned int merged) {
+  return extract_high_short_from_int(merged);
+}
+
+inline int Backtrace::cpref_at(unsigned int merged) {
+  return extract_low_short_from_int(merged);
+}
+
+inline int Backtrace::get_line_number(const methodHandle& method, int bci) {
+  int line_number = 0;
+  if (method->is_native()) {
+    // Negative value different from -1 below, enabling Java code in
+    // class java.lang.StackTraceElement to distinguish "native" from
+    // "no LineNumberTable".  JDK tests for -2.
+    line_number = -2;
+  } else {
+    // Returns -1 if no LineNumberTable, and otherwise actual line number
+    line_number = method->line_number_from_bci(bci);
+    if (line_number == -1 && ShowHiddenFrames) {
+      line_number = bci + 1000000;
+    }
+  }
+  return line_number;
+}
+
+/*
+ * Returns the source file name of a given InstanceKlass and version
+ */
+inline Symbol* Backtrace::get_source_file_name(InstanceKlass* holder, int version) {
+  // Find the specific ik version that contains this source_file_name_index
+  // via the previous versions list, but use the current version's
+  // constant pool to look it up.  The previous version's index has been
+  // merged for the current constant pool.
+  InstanceKlass* ik = holder->get_klass_version(version);
+  // This version has been cleaned up.
+  if (ik == NULL) return NULL;
+  int source_file_name_index = ik->source_file_name_index();
+  return (source_file_name_index == 0) ?
+      (Symbol*)NULL : holder->constants()->symbol_at(source_file_name_index);
+}
+
 #endif // SHARE_VM_CLASSFILE_JAVACLASSES_INLINE_HPP
--- a/hotspot/src/share/vm/classfile/systemDictionary.hpp	Fri Nov 20 12:42:21 2015 +0100
+++ b/hotspot/src/share/vm/classfile/systemDictionary.hpp	Mon Nov 23 12:44:43 2015 -0800
@@ -179,11 +179,17 @@
   do_klass(sun_misc_Launcher_klass,                     sun_misc_Launcher,                         Pre                 ) \
   do_klass(CodeSource_klass,                            java_security_CodeSource,                  Pre                 ) \
                                                                                                                          \
-  /* It's NULL in non-1.4 JDKs. */                                                                                       \
   do_klass(StackTraceElement_klass,                     java_lang_StackTraceElement,               Opt                 ) \
+                                                                                                                         \
   /* It's okay if this turns out to be NULL in non-1.4 JDKs. */                                                          \
   do_klass(nio_Buffer_klass,                            java_nio_Buffer,                           Opt                 ) \
                                                                                                                          \
+  /* Stack Walking */                                                                                                    \
+  do_klass(StackWalker_klass,                           java_lang_StackWalker,                     Opt                 ) \
+  do_klass(AbstractStackWalker_klass,                   java_lang_StackStreamFactory_AbstractStackWalker, Opt          ) \
+  do_klass(StackFrameInfo_klass,                        java_lang_StackFrameInfo,                  Opt                 ) \
+  do_klass(LiveStackFrameInfo_klass,                    java_lang_LiveStackFrameInfo,              Opt                 ) \
+                                                                                                                         \
   /* Preload boxing klasses */                                                                                           \
   do_klass(Boolean_klass,                               java_lang_Boolean,                         Pre                 ) \
   do_klass(Character_klass,                             java_lang_Character,                       Pre                 ) \
--- a/hotspot/src/share/vm/classfile/vmSymbols.hpp	Fri Nov 20 12:42:21 2015 +0100
+++ b/hotspot/src/share/vm/classfile/vmSymbols.hpp	Mon Nov 23 12:44:43 2015 -0800
@@ -310,6 +310,22 @@
   /* Support for JVMCI */                                                                                                             \
   JVMCI_VM_SYMBOLS_DO(template, do_alias)                                                         \
                                                                                                   \
+  template(java_lang_StackWalker,                     "java/lang/StackWalker")                    \
+  template(java_lang_StackFrameInfo,                  "java/lang/StackFrameInfo")                 \
+  template(java_lang_LiveStackFrameInfo,              "java/lang/LiveStackFrameInfo")             \
+  template(java_lang_StackStreamFactory_AbstractStackWalker, "java/lang/StackStreamFactory$AbstractStackWalker") \
+  template(doStackWalk_name,                          "doStackWalk")                              \
+  template(doStackWalk_signature,                     "(JIIII)Ljava/lang/Object;")                \
+  template(asPrimitive_name,                          "asPrimitive")                              \
+  template(asPrimitive_int_signature,                 "(I)Ljava/lang/LiveStackFrame$PrimitiveValue;") \
+  template(asPrimitive_long_signature,                "(J)Ljava/lang/LiveStackFrame$PrimitiveValue;") \
+  template(asPrimitive_short_signature,               "(S)Ljava/lang/LiveStackFrame$PrimitiveValue;") \
+  template(asPrimitive_byte_signature,                "(B)Ljava/lang/LiveStackFrame$PrimitiveValue;") \
+  template(asPrimitive_char_signature,                "(C)Ljava/lang/LiveStackFrame$PrimitiveValue;") \
+  template(asPrimitive_float_signature,               "(F)Ljava/lang/LiveStackFrame$PrimitiveValue;") \
+  template(asPrimitive_double_signature,              "(D)Ljava/lang/LiveStackFrame$PrimitiveValue;") \
+  template(asPrimitive_boolean_signature,             "(Z)Ljava/lang/LiveStackFrame$PrimitiveValue;") \
+                                                                                                  \
   /* common method and field names */                                                             \
   template(object_initializer_name,                   "<init>")                                   \
   template(class_initializer_name,                    "<clinit>")                                 \
@@ -410,6 +426,18 @@
   template(append_name,                               "append")                                   \
   template(klass_name,                                "klass")                                    \
   template(array_klass_name,                          "array_klass")                              \
+  template(declaringClass_name,                       "declaringClass")                           \
+  template(memberName_name,                           "memberName")                               \
+  template(mid_name,                                  "mid")                                      \
+  template(cpref_name,                                "cpref")                                    \
+  template(version_name,                              "version")                                  \
+  template(bci_name,                                  "bci")                                      \
+  template(methodName_name,                           "methodName")                               \
+  template(fileName_name,                             "fileName")                                 \
+  template(lineNumber_name,                           "lineNumber")                               \
+  template(monitors_name,                             "monitors")                                 \
+  template(locals_name,                               "locals")                                   \
+  template(operands_name,                             "operands")                                 \
   template(oop_size_name,                             "oop_size")                                 \
   template(static_oop_field_count_name,               "static_oop_field_count")                   \
   template(protection_domain_name,                    "protection_domain")                        \
@@ -514,6 +542,7 @@
   template(class_array_signature,                     "[Ljava/lang/Class;")                                       \
   template(classloader_signature,                     "Ljava/lang/ClassLoader;")                                  \
   template(object_signature,                          "Ljava/lang/Object;")                                       \
+  template(object_array_signature,                    "[Ljava/lang/Object;")                                      \
   template(class_signature,                           "Ljava/lang/Class;")                                        \
   template(string_signature,                          "Ljava/lang/String;")                                       \
   template(reference_signature,                       "Ljava/lang/ref/Reference;")                                \
--- a/hotspot/src/share/vm/memory/universe.cpp	Fri Nov 20 12:42:21 2015 +0100
+++ b/hotspot/src/share/vm/memory/universe.cpp	Mon Nov 23 12:44:43 2015 -0800
@@ -115,6 +115,7 @@
 LatestMethodCache* Universe::_loader_addClass_cache    = NULL;
 LatestMethodCache* Universe::_pd_implies_cache         = NULL;
 LatestMethodCache* Universe::_throw_illegal_access_error_cache = NULL;
+LatestMethodCache* Universe::_do_stack_walk_cache     = NULL;
 oop Universe::_out_of_memory_error_java_heap          = NULL;
 oop Universe::_out_of_memory_error_metaspace          = NULL;
 oop Universe::_out_of_memory_error_class_metaspace    = NULL;
@@ -240,6 +241,7 @@
   _loader_addClass_cache->serialize(f);
   _pd_implies_cache->serialize(f);
   _throw_illegal_access_error_cache->serialize(f);
+  _do_stack_walk_cache->serialize(f);
 }
 
 void Universe::check_alignment(uintx size, uintx alignment, const char* name) {
@@ -674,6 +676,7 @@
   Universe::_loader_addClass_cache    = new LatestMethodCache();
   Universe::_pd_implies_cache         = new LatestMethodCache();
   Universe::_throw_illegal_access_error_cache = new LatestMethodCache();
+  Universe::_do_stack_walk_cache = new LatestMethodCache();
 
   if (UseSharedSpaces) {
     // Read the data structures supporting the shared spaces (shared
@@ -1048,6 +1051,17 @@
       SystemDictionary::ProtectionDomain_klass(), m);
   }
 
+  // Setup method for stack walking
+  InstanceKlass::cast(SystemDictionary::AbstractStackWalker_klass())->link_class(CHECK_false);
+  m = InstanceKlass::cast(SystemDictionary::AbstractStackWalker_klass())->
+            find_method(vmSymbols::doStackWalk_name(),
+                        vmSymbols::doStackWalk_signature());
+  // Allow NULL which should only happen with bootstrapping.
+  if (m != NULL) {
+    Universe::_do_stack_walk_cache->init(
+      SystemDictionary::AbstractStackWalker_klass(), m);
+  }
+
   // This needs to be done before the first scavenge/gc, since
   // it's an input to soft ref clearing policy.
   {
--- a/hotspot/src/share/vm/memory/universe.hpp	Fri Nov 20 12:42:21 2015 +0100
+++ b/hotspot/src/share/vm/memory/universe.hpp	Mon Nov 23 12:44:43 2015 -0800
@@ -149,6 +149,7 @@
   static LatestMethodCache* _loader_addClass_cache;    // method for registering loaded classes in class loader vector
   static LatestMethodCache* _pd_implies_cache;         // method for checking protection domain attributes
   static LatestMethodCache* _throw_illegal_access_error_cache; // Unsafe.throwIllegalAccessError() method
+  static LatestMethodCache* _do_stack_walk_cache;      // method for stack walker callback
 
   // preallocated error objects (no backtrace)
   static oop          _out_of_memory_error_java_heap;
@@ -314,6 +315,8 @@
   static Method*      protection_domain_implies_method() { return _pd_implies_cache->get_method(); }
   static Method*      throw_illegal_access_error()    { return _throw_illegal_access_error_cache->get_method(); }
 
+  static Method*      do_stack_walk_method()          { return _do_stack_walk_cache->get_method(); }
+
   static oop          null_ptr_exception_instance()   { return _null_ptr_exception_instance;   }
   static oop          arithmetic_exception_instance() { return _arithmetic_exception_instance; }
   static oop          virtual_machine_error_instance() { return _virtual_machine_error_instance; }
--- a/hotspot/src/share/vm/prims/jvm.cpp	Fri Nov 20 12:42:21 2015 +0100
+++ b/hotspot/src/share/vm/prims/jvm.cpp	Mon Nov 23 12:44:43 2015 -0800
@@ -46,6 +46,7 @@
 #include "prims/jvmtiThreadState.hpp"
 #include "prims/nativeLookup.hpp"
 #include "prims/privilegedStack.hpp"
+#include "prims/stackwalk.hpp"
 #include "runtime/arguments.hpp"
 #include "runtime/atomic.inline.hpp"
 #include "runtime/handles.inline.hpp"
@@ -547,6 +548,94 @@
 JVM_END
 
 
+// java.lang.StackWalker //////////////////////////////////////////////////////
+
+
+JVM_ENTRY(jobject, JVM_CallStackWalk(JNIEnv *env, jobject stackStream, jlong mode,
+                                     jint skip_frames, jint frame_count, jint start_index,
+                                     jobjectArray classes,
+                                     jobjectArray frames))
+  JVMWrapper("JVM_CallStackWalk");
+  JavaThread* jt = (JavaThread*) THREAD;
+  if (!jt->is_Java_thread() || !jt->has_last_Java_frame()) {
+    THROW_MSG_(vmSymbols::java_lang_InternalError(), "doStackWalk: no stack trace", NULL);
+  }
+
+  Handle stackStream_h(THREAD, JNIHandles::resolve_non_null(stackStream));
+  objArrayOop ca = objArrayOop(JNIHandles::resolve_non_null(classes));
+  objArrayHandle classes_array_h(THREAD, ca);
+
+  // frames array is null when only getting caller reference
+  objArrayOop fa = objArrayOop(JNIHandles::resolve(frames));
+  objArrayHandle frames_array_h(THREAD, fa);
+
+  int limit = start_index + frame_count;
+  if (classes_array_h->length() < limit) {
+    THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(), "not enough space in buffers", NULL);
+  }
+
+  Handle result = StackWalk::walk(stackStream_h, mode, skip_frames, frame_count,
+                                  start_index, classes_array_h,
+                                  frames_array_h, CHECK_NULL);
+  return JNIHandles::make_local(env, result());
+JVM_END
+
+
+JVM_ENTRY(jint, JVM_MoreStackWalk(JNIEnv *env, jobject stackStream, jlong mode, jlong anchor,
+                                  jint frame_count, jint start_index,
+                                  jobjectArray classes,
+                                  jobjectArray frames))
+  JVMWrapper("JVM_MoreStackWalk");
+  JavaThread* jt = (JavaThread*) THREAD;
+  objArrayOop ca = objArrayOop(JNIHandles::resolve_non_null(classes));
+  objArrayHandle classes_array_h(THREAD, ca);
+
+  // frames array is null when only getting caller reference
+  objArrayOop fa = objArrayOop(JNIHandles::resolve(frames));
+  objArrayHandle frames_array_h(THREAD, fa);
+
+  int limit = start_index+frame_count;
+  if (classes_array_h->length() < limit) {
+    THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "not enough space in buffers");
+  }
+
+  Handle stackStream_h(THREAD, JNIHandles::resolve_non_null(stackStream));
+  return StackWalk::moreFrames(stackStream_h, mode, anchor, frame_count,
+                               start_index, classes_array_h,
+                               frames_array_h, THREAD);
+JVM_END
+
+JVM_ENTRY(void, JVM_FillStackFrames(JNIEnv *env, jclass stackStream,
+                                    jint start_index,
+                                    jobjectArray frames,
+                                    jint from_index, jint to_index))
+  JVMWrapper("JVM_FillStackFrames");
+  if (TraceStackWalk) {
+    tty->print("JVM_FillStackFrames() start_index=%d from_index=%d to_index=%d\n",
+               start_index, from_index, to_index);
+  }
+
+  JavaThread* jt = (JavaThread*) THREAD;
+
+  objArrayOop fa = objArrayOop(JNIHandles::resolve_non_null(frames));
+  objArrayHandle frames_array_h(THREAD, fa);
+
+  if (frames_array_h->length() < to_index) {
+    THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "array length not matched");
+  }
+
+  for (int i = from_index; i < to_index; i++) {
+    Handle stackFrame(THREAD, frames_array_h->obj_at(i));
+    java_lang_StackFrameInfo::fill_methodInfo(stackFrame, CHECK);
+  }
+JVM_END
+
+JVM_ENTRY(void, JVM_SetMethodInfo(JNIEnv *env, jobject frame))
+  JVMWrapper("JVM_SetMethodInfo");
+  Handle stackFrame(THREAD, JNIHandles::resolve(frame));
+  java_lang_StackFrameInfo::fill_methodInfo(stackFrame, THREAD);
+JVM_END
+
 // java.lang.Object ///////////////////////////////////////////////
 
 
--- a/hotspot/src/share/vm/prims/jvm.h	Fri Nov 20 12:42:21 2015 +0100
+++ b/hotspot/src/share/vm/prims/jvm.h	Mon Nov 23 12:44:43 2015 -0800
@@ -201,6 +201,37 @@
 JVM_GetStackTraceElement(JNIEnv *env, jobject throwable, jint index);
 
 /*
+ * java.lang.StackWalker
+ */
+enum {
+  JVM_STACKWALK_FILL_CLASS_REFS_ONLY       = 0x2,
+  JVM_STACKWALK_FILTER_FILL_IN_STACK_TRACE = 0x10,
+  JVM_STACKWALK_SHOW_HIDDEN_FRAMES         = 0x20,
+  JVM_STACKWALK_FILL_LIVE_STACK_FRAMES     = 0x100
+};
+
+JNIEXPORT jobject JNICALL
+JVM_CallStackWalk(JNIEnv *env, jobject stackStream, jlong mode,
+                  jint skip_frames, jint frame_count, jint start_index,
+                  jobjectArray classes,
+                  jobjectArray frames);
+
+JNIEXPORT jint JNICALL
+JVM_MoreStackWalk(JNIEnv *env, jobject stackStream, jlong mode, jlong anchor,
+                  jint frame_count, jint start_index,
+                  jobjectArray classes,
+                  jobjectArray frames);
+
+JNIEXPORT void JNICALL
+JVM_FillStackFrames(JNIEnv* env, jclass cls,
+                    jint start_index,
+                    jobjectArray frames,
+                    jint from_index, jint toIndex);
+
+JNIEXPORT void JNICALL
+JVM_SetMethodInfo(JNIEnv* env, jobject frame);
+
+/*
  * java.lang.Thread
  */
 JNIEXPORT void JNICALL
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/prims/stackwalk.cpp	Mon Nov 23 12:44:43 2015 -0800
@@ -0,0 +1,470 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "classfile/javaClasses.hpp"
+#include "classfile/javaClasses.inline.hpp"
+#include "classfile/vmSymbols.hpp"
+#include "memory/oopFactory.hpp"
+#include "oops/oop.inline.hpp"
+#include "oops/objArrayOop.inline.hpp"
+#include "prims/stackwalk.hpp"
+#include "runtime/globals.hpp"
+#include "runtime/handles.inline.hpp"
+#include "runtime/javaCalls.hpp"
+#include "runtime/vframe.hpp"
+#include "utilities/globalDefinitions.hpp"
+
+// setup and cleanup actions
+void StackWalkAnchor::setup_magic_on_entry(objArrayHandle classes_array) {
+  classes_array->obj_at_put(magic_pos, _thread->threadObj());
+  _anchor = address_value();
+  assert(check_magic(classes_array), "invalid magic");
+}
+
+bool StackWalkAnchor::check_magic(objArrayHandle classes_array) {
+  oop   m1 = classes_array->obj_at(magic_pos);
+  jlong m2 = _anchor;
+  if (m1 == _thread->threadObj() && m2 == address_value())  return true;
+  return false;
+}
+
+bool StackWalkAnchor::cleanup_magic_on_exit(objArrayHandle classes_array) {
+  bool ok = check_magic(classes_array);
+  classes_array->obj_at_put(magic_pos, NULL);
+  _anchor = 0L;
+  return ok;
+}
+
+// Returns StackWalkAnchor for the current stack being traversed.
+//
+// Parameters:
+//  thread         Current Java thread.
+//  magic          Magic value used for each stack walking
+//  classes_array  User-supplied buffers.  The 0th element is reserved
+//                 to this StackWalkAnchor to use
+//
+StackWalkAnchor* StackWalkAnchor::from_current(JavaThread* thread, jlong magic,
+                                               objArrayHandle classes_array)
+{
+  assert(thread != NULL && thread->is_Java_thread(), "");
+  oop m1 = classes_array->obj_at(magic_pos);
+  if (m1 != thread->threadObj())      return NULL;
+  if (magic == 0L)                    return NULL;
+  StackWalkAnchor* anchor = (StackWalkAnchor*) (intptr_t) magic;
+  if (!anchor->is_valid_in(thread, classes_array))   return NULL;
+  return anchor;
+}
+
+// Unpacks one or more frames into user-supplied buffers.
+// Updates the end index, and returns the number of unpacked frames.
+// Always start with the existing vfst.method and bci.
+// Do not call vfst.next to advance over the last returned value.
+// In other words, do not leave any stale data in the vfst.
+//
+// Parameters:
+//   mode           Restrict which frames to be decoded.
+//   vfst           vFrameStream.
+//   max_nframes    Maximum number of frames to be filled.
+//   start_index    Start index to the user-supplied buffers.
+//   classes_array  Buffer to store classes in, starting at start_index.
+//   frames_array   Buffer to store StackFrame in, starting at start_index.
+//                  NULL if not used.
+//   end_index      End index to the user-supplied buffers with unpacked frames.
+//
+// Returns the number of frames whose information was transferred into the buffers.
+//
+int StackWalk::fill_in_frames(jlong mode, vframeStream& vfst,
+                              int max_nframes, int start_index,
+                              objArrayHandle  classes_array,
+                              objArrayHandle  frames_array,
+                              int& end_index, TRAPS) {
+  if (TraceStackWalk) {
+    tty->print_cr("fill_in_frames limit=%d start=%d frames length=%d",
+                  max_nframes, start_index, classes_array->length());
+  }
+  assert(max_nframes > 0, "invalid max_nframes");
+  assert(start_index + max_nframes <= classes_array->length(), "oob");
+
+  int frames_decoded = 0;
+  for (; !vfst.at_end(); vfst.next()) {
+    Method* method = vfst.method();
+    int bci = vfst.bci();
+
+    if (method == NULL) continue;
+    if (!ShowHiddenFrames && StackWalk::skip_hidden_frames(mode)) {
+      if (method->is_hidden()) {
+        if (TraceStackWalk) {
+          tty->print("  hidden method: "); method->print_short_name();
+          tty->print("\n");
+        }
+        continue;
+      }
+    }
+
+    int index = end_index++;
+    if (TraceStackWalk) {
+      tty->print("  %d: frame method: ", index); method->print_short_name();
+      tty->print_cr(" bci=%d", bci);
+    }
+
+    classes_array->obj_at_put(index, method->method_holder()->java_mirror());
+    // fill in StackFrameInfo and initialize MemberName
+    if (live_frame_info(mode)) {
+      Handle stackFrame(frames_array->obj_at(index));
+      fill_live_stackframe(stackFrame, method, bci, vfst.java_frame(), CHECK_0);
+    } else if (need_method_info(mode)) {
+      Handle stackFrame(frames_array->obj_at(index));
+      fill_stackframe(stackFrame, method, bci);
+    }
+    if (++frames_decoded >= max_nframes)  break;
+  }
+  return frames_decoded;
+}
+
+static oop create_primitive_value_instance(StackValueCollection* values, int i, TRAPS) {
+  Klass* k = SystemDictionary::resolve_or_null(vmSymbols::java_lang_LiveStackFrameInfo(), CHECK_NULL);
+  instanceKlassHandle ik (THREAD, k);
+
+  JavaValue result(T_OBJECT);
+  JavaCallArguments args;
+  Symbol* signature = NULL;
+
+  // ## TODO: type is only available in LocalVariable table, if present.
+  // ## StackValue type is T_INT or T_OBJECT.
+  switch (values->at(i)->type()) {
+    case T_INT:
+      args.push_int(values->int_at(i));
+      signature = vmSymbols::asPrimitive_int_signature();
+      break;
+
+    case T_LONG:
+      args.push_long(values->long_at(i));
+      signature = vmSymbols::asPrimitive_long_signature();
+      break;
+
+    case T_FLOAT:
+      args.push_float(values->float_at(i));
+      signature = vmSymbols::asPrimitive_float_signature();
+      break;
+
+    case T_DOUBLE:
+      args.push_double(values->double_at(i));
+      signature = vmSymbols::asPrimitive_double_signature();
+      break;
+
+    case T_BYTE:
+      args.push_int(values->int_at(i));
+      signature = vmSymbols::asPrimitive_byte_signature();
+      break;
+
+    case T_SHORT:
+      args.push_int(values->int_at(i));
+      signature = vmSymbols::asPrimitive_short_signature();
+      break;
+
+    case T_CHAR:
+      args.push_int(values->int_at(i));
+      signature = vmSymbols::asPrimitive_char_signature();
+      break;
+
+    case T_BOOLEAN:
+      args.push_int(values->int_at(i));
+      signature = vmSymbols::asPrimitive_boolean_signature();
+      break;
+
+    case T_OBJECT:
+      return values->obj_at(i)();
+
+    case T_CONFLICT:
+      // put a non-null slot
+      args.push_int(0);
+      signature = vmSymbols::asPrimitive_int_signature();
+      break;
+
+    default: ShouldNotReachHere();
+  }
+  JavaCalls::call_static(&result,
+                         ik,
+                         vmSymbols::asPrimitive_name(),
+                         signature,
+                         &args,
+                         CHECK_NULL);
+  return (instanceOop) result.get_jobject();
+}
+
+static objArrayHandle values_to_object_array(StackValueCollection* values, TRAPS) {
+  objArrayHandle empty;
+  int length = values->size();
+  objArrayOop array_oop = oopFactory::new_objArray(SystemDictionary::Object_klass(),
+                                                   length, CHECK_(empty));
+  objArrayHandle array_h(THREAD, array_oop);
+  for (int i = 0; i < values->size(); i++) {
+    StackValue* st = values->at(i);
+    oop obj = create_primitive_value_instance(values, i, CHECK_(empty));
+    if (obj != NULL)
+      array_h->obj_at_put(i, obj);
+  }
+  return array_h;
+}
+
+static objArrayHandle monitors_to_object_array(GrowableArray<MonitorInfo*>* monitors, TRAPS) {
+  int length = monitors->length();
+  objArrayOop array_oop = oopFactory::new_objArray(SystemDictionary::Object_klass(),
+                                                   length, CHECK_(objArrayHandle()));
+  objArrayHandle array_h(THREAD, array_oop);
+  for (int i = 0; i < length; i++) {
+    MonitorInfo* monitor = monitors->at(i);
+    array_h->obj_at_put(i, monitor->owner());
+  }
+  return array_h;
+}
+
+// Fill StackFrameInfo with declaringClass and bci and initialize memberName
+void StackWalk::fill_stackframe(Handle stackFrame, const methodHandle& method, int bci) {
+  java_lang_StackFrameInfo::set_declaringClass(stackFrame(), method->method_holder()->java_mirror());
+  java_lang_StackFrameInfo::set_method_and_bci(stackFrame(), method, bci);
+}
+
+// Fill LiveStackFrameInfo with locals, monitors, and expressions
+void StackWalk::fill_live_stackframe(Handle stackFrame, const methodHandle& method,
+                                     int bci, javaVFrame* jvf, TRAPS) {
+  fill_stackframe(stackFrame, method, bci);
+  if (jvf != NULL) {
+    StackValueCollection* locals = jvf->locals();
+    StackValueCollection* expressions = jvf->expressions();
+    GrowableArray<MonitorInfo*>* monitors = jvf->monitors();
+
+    if (!locals->is_empty()) {
+      objArrayHandle locals_h = values_to_object_array(locals, CHECK);
+      java_lang_LiveStackFrameInfo::set_locals(stackFrame(), locals_h());
+    }
+    if (!expressions->is_empty()) {
+      objArrayHandle expressions_h = values_to_object_array(expressions, CHECK);
+      java_lang_LiveStackFrameInfo::set_operands(stackFrame(), expressions_h());
+    }
+    if (monitors->length() > 0) {
+      objArrayHandle monitors_h = monitors_to_object_array(monitors, CHECK);
+      java_lang_LiveStackFrameInfo::set_monitors(stackFrame(), monitors_h());
+    }
+  }
+}
+
+// Begins stack walking.
+//
+// Parameters:
+//   stackStream    StackStream object
+//   mode           Stack walking mode.
+//   skip_frames    Number of frames to be skipped.
+//   frame_count    Number of frames to be traversed.
+//   start_index    Start index to the user-supplied buffers.
+//   classes_array  Buffer to store classes in, starting at start_index.
+//   frames_array   Buffer to store StackFrame in, starting at start_index.
+//                  NULL if not used.
+//
+// Returns Object returned from AbstractStackWalker::doStackWalk call.
+//
+oop StackWalk::walk(Handle stackStream, jlong mode,
+                    int skip_frames, int frame_count, int start_index,
+                    objArrayHandle classes_array,
+                    objArrayHandle frames_array,
+                    TRAPS) {
+  JavaThread* jt = (JavaThread*)THREAD;
+  if (TraceStackWalk) {
+    tty->print_cr("Start walking: mode " JLONG_FORMAT " skip %d frames batch size %d",
+                  mode, skip_frames, frame_count);
+  }
+
+  if (need_method_info(mode)) {
+    if (frames_array.is_null()) {
+      THROW_MSG_(vmSymbols::java_lang_NullPointerException(), "frames_array is NULL", NULL);
+    }
+  }
+
+  Klass* stackWalker_klass = SystemDictionary::StackWalker_klass();
+  Klass* abstractStackWalker_klass = SystemDictionary::AbstractStackWalker_klass();
+
+  methodHandle m_doStackWalk(THREAD, Universe::do_stack_walk_method());
+
+  // Open up a traversable stream onto my stack.
+  // This stream will be made available by *reference* to the inner Java call.
+  StackWalkAnchor anchor(jt);
+  vframeStream& vfst = anchor.vframe_stream();
+
+  {
+    // Skip all methods from AbstractStackWalker and StackWalk (enclosing method)
+    if (!fill_in_stacktrace(mode)) {
+      while (!vfst.at_end()) {
+        InstanceKlass* ik = vfst.method()->method_holder();
+        if (ik != stackWalker_klass &&
+              ik != abstractStackWalker_klass && ik->super() != abstractStackWalker_klass)  {
+          break;
+        }
+
+        if (TraceStackWalk) {
+          tty->print("  skip "); vfst.method()->print_short_name(); tty->print("\n");
+        }
+        vfst.next();
+      }
+    }
+
+    // For exceptions, skip Throwable::fillInStackTrace and <init> methods
+    // of the exception class and superclasses
+    if (fill_in_stacktrace(mode)) {
+      bool skip_to_fillInStackTrace = false;
+      bool skip_throwableInit_check = false;
+      while (!vfst.at_end() && !skip_throwableInit_check) {
+        InstanceKlass* ik = vfst.method()->method_holder();
+        Method* method = vfst.method();
+        if (!skip_to_fillInStackTrace) {
+          if (ik == SystemDictionary::Throwable_klass() &&
+              method->name() == vmSymbols::fillInStackTrace_name()) {
+              // this frame will be skipped
+              skip_to_fillInStackTrace = true;
+          }
+        } else if (!(ik->is_subclass_of(SystemDictionary::Throwable_klass()) &&
+                     method->name() == vmSymbols::object_initializer_name())) {
+            // there are none or we've seen them all - either way stop checking
+            skip_throwableInit_check = true;
+            break;
+        }
+
+        if (TraceStackWalk) {
+          tty->print("stack walk: skip "); vfst.method()->print_short_name(); tty->print("\n");
+        }
+        vfst.next();
+      }
+    }
+
+    // stack frame has been traversed individually and resume stack walk
+    // from the stack frame at depth == skip_frames.
+    for (int n=0; n < skip_frames && !vfst.at_end(); vfst.next(), n++) {
+      if (TraceStackWalk) {
+        tty->print("  skip "); vfst.method()->print_short_name();
+        tty->print_cr(" frame id: " PTR_FORMAT " pc: " PTR_FORMAT,
+                      p2i(vfst.frame_id()), p2i(vfst.frame_pc()));
+      }
+    }
+  }
+
+  // The Method* pointer in the vfst has a very short shelf life.  Grab it now.
+  int end_index = start_index;
+  int numFrames = 0;
+  if (!vfst.at_end()) {
+    numFrames = fill_in_frames(mode, vfst, frame_count, start_index, classes_array,
+                               frames_array, end_index, CHECK_NULL);
+    if (numFrames < 1) {
+      THROW_MSG_(vmSymbols::java_lang_InternalError(), "stack walk: decode failed", NULL);
+    }
+  }
+
+  // JVM_CallStackWalk walks the stack and fills in stack frames, then calls to
+  // Java method java.lang.StackStreamFactory.AbstractStackWalker::doStackWalk
+  // which calls the implementation to consume the stack frames.
+  // When JVM_CallStackWalk returns, it invalidates the stack stream.
+  JavaValue result(T_OBJECT);
+  JavaCallArguments args(stackStream);
+  args.push_long(anchor.address_value());
+  args.push_int(skip_frames);
+  args.push_int(frame_count);
+  args.push_int(start_index);
+  args.push_int(end_index);
+
+  // Link the thread and vframe stream into the callee-visible object
+  anchor.setup_magic_on_entry(classes_array);
+
+  JavaCalls::call(&result, m_doStackWalk, &args, THREAD);
+
+  // Do this before anything else happens, to disable any lingering stream objects
+  bool ok = anchor.cleanup_magic_on_exit(classes_array);
+
+  // Throw pending exception if we must
+  (void) (CHECK_NULL);
+
+  if (!ok) {
+    THROW_MSG_(vmSymbols::java_lang_InternalError(), "doStackWalk: corrupted buffers on exit", NULL);
+  }
+
+  // Return normally
+  return (oop)result.get_jobject();
+
+}
+
+// Walk the next batch of stack frames
+//
+// Parameters:
+//   stackStream    StackStream object
+//   mode           Stack walking mode.
+//   magic          Must be valid value to continue the stack walk
+//   frame_count    Number of frames to be decoded.
+//   start_index    Start index to the user-supplied buffers.
+//   classes_array  Buffer to store classes in, starting at start_index.
+//   frames_array   Buffer to store StackFrame in, starting at start_index.
+//                  NULL if not used.
+//
+// Returns the end index of frame filled in the buffer.
+//
+jint StackWalk::moreFrames(Handle stackStream, jlong mode, jlong magic,
+                           int frame_count, int start_index,
+                           objArrayHandle classes_array,
+                           objArrayHandle frames_array,
+                           TRAPS)
+{
+  JavaThread* jt = (JavaThread*)THREAD;
+  StackWalkAnchor* existing_anchor = StackWalkAnchor::from_current(jt, magic, classes_array);
+  if (existing_anchor == NULL) {
+    THROW_MSG_(vmSymbols::java_lang_InternalError(), "doStackWalk: corrupted buffers", 0L);
+  }
+
+  if ((need_method_info(mode) || live_frame_info(mode)) && frames_array.is_null()) {
+    THROW_MSG_(vmSymbols::java_lang_NullPointerException(), "frames_array is NULL", 0L);
+  }
+
+  if (TraceStackWalk) {
+    tty->print_cr("StackWalk::moreFrames frame_count %d existing_anchor " PTR_FORMAT " start %d frames %d",
+                  frame_count, p2i(existing_anchor), start_index, classes_array->length());
+  }
+  int end_index = start_index;
+  if (frame_count <= 0) {
+    return end_index;        // No operation.
+  }
+
+  int count = frame_count + start_index;
+  assert (classes_array->length() >= count, "not enough space in buffers");
+
+  StackWalkAnchor& anchor = (*existing_anchor);
+  vframeStream& vfst = anchor.vframe_stream();
+  if (!vfst.at_end()) {
+    vfst.next();  // this was the last frame decoded in the previous batch
+    if (!vfst.at_end()) {
+      int n = fill_in_frames(mode, vfst, frame_count, start_index, classes_array,
+                             frames_array, end_index, CHECK_0);
+      if (n < 1) {
+        THROW_MSG_(vmSymbols::java_lang_InternalError(), "doStackWalk: later decode failed", 0L);
+      }
+      return end_index;
+    }
+  }
+  return end_index;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/prims/stackwalk.hpp	Mon Nov 23 12:44:43 2015 -0800
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+
+#ifndef SHARE_VM_PRIMS_STACKWALK_HPP
+#define SHARE_VM_PRIMS_STACKWALK_HPP
+
+#include "oops/oop.hpp"
+#include "runtime/vframe.hpp"
+
+class StackWalkAnchor : public StackObj {
+private:
+  enum {
+    magic_pos = 0
+  };
+
+  JavaThread*           _thread;
+  vframeStream          _vfst;
+  jlong                 _anchor;
+public:
+  StackWalkAnchor(JavaThread* thread)
+    : _thread(thread), _vfst(thread), _anchor(0L) {}
+
+  vframeStream&   vframe_stream()         { return _vfst; }
+  JavaThread*     thread()                { return _thread; }
+
+  void setup_magic_on_entry(objArrayHandle classes_array);
+  bool check_magic(objArrayHandle classes_array);
+  bool cleanup_magic_on_exit(objArrayHandle classes_array);
+
+  bool is_valid_in(Thread* thread, objArrayHandle classes_array) {
+    return (_thread == thread && check_magic(classes_array));
+  }
+
+  jlong address_value() {
+    return (jlong) castable_address(this);
+  }
+
+  static StackWalkAnchor* from_current(JavaThread* thread, jlong anchor, objArrayHandle frames_array);
+};
+
+class StackWalk : public AllStatic {
+private:
+  static int fill_in_frames(jlong mode, vframeStream& vfst,
+                            int max_nframes, int start_index,
+                            objArrayHandle classes_array,
+                            objArrayHandle frames_array,
+                            int& end_index, TRAPS);
+
+  static void fill_stackframe(Handle stackFrame, const methodHandle& method, int bci);
+
+  static void fill_live_stackframe(Handle stackFrame, const methodHandle& method, int bci,
+                                   javaVFrame* jvf, TRAPS);
+
+  static inline bool skip_hidden_frames(int mode) {
+    return (mode & JVM_STACKWALK_SHOW_HIDDEN_FRAMES) == 0;
+  }
+  static inline bool need_method_info(int mode) {
+    return (mode & JVM_STACKWALK_FILL_CLASS_REFS_ONLY) == 0;
+  }
+  static inline bool live_frame_info(int mode) {
+    return (mode & JVM_STACKWALK_FILL_LIVE_STACK_FRAMES) != 0;
+  }
+  static inline bool fill_in_stacktrace(int mode) {
+    return (mode & JVM_STACKWALK_FILTER_FILL_IN_STACK_TRACE) != 0;
+  }
+
+public:
+  static oop walk(Handle stackStream, jlong mode,
+                  int skip_frames, int frame_count, int start_index,
+                  objArrayHandle classes_array,
+                  objArrayHandle frames_array,
+                  TRAPS);
+
+  static jint moreFrames(Handle stackStream, jlong mode, jlong magic,
+                         int frame_count, int start_index,
+                         objArrayHandle classes_array,
+                         objArrayHandle frames_array,
+                         TRAPS);
+};
+#endif // SHARE_VM_PRIMS_STACKWALK_HPP
--- a/hotspot/src/share/vm/runtime/globals.hpp	Fri Nov 20 12:42:21 2015 +0100
+++ b/hotspot/src/share/vm/runtime/globals.hpp	Mon Nov 23 12:44:43 2015 -0800
@@ -3118,6 +3118,12 @@
           "exceptions (0 means all)")                                       \
           range(0, max_jint/2)                                              \
                                                                             \
+  develop(bool, TraceStackWalk, false,                                      \
+          "Trace stack walking")                                            \
+                                                                            \
+  product(bool, MemberNameInStackFrame, true,                               \
+          "Use MemberName in StackFrame")                                   \
+                                                                            \
   /* notice: the max range value here is max_jint, not max_intx  */         \
   /* because of overflow issue                                   */         \
   NOT_EMBEDDED(diagnostic(intx, GuaranteedSafepointInterval, 1000,          \
--- a/hotspot/src/share/vm/runtime/vframe.hpp	Fri Nov 20 12:42:21 2015 +0100
+++ b/hotspot/src/share/vm/runtime/vframe.hpp	Mon Nov 23 12:44:43 2015 -0800
@@ -317,10 +317,18 @@
   intptr_t* frame_id() const { return _frame.id(); }
   address frame_pc() const { return _frame.pc(); }
 
+  javaVFrame* java_frame() {
+    vframe* vf = vframe::new_vframe(&_frame, &_reg_map, _thread);
+    if (vf->is_java_frame()) {
+      return (javaVFrame*)vf;
+    }
+    return NULL;
+  }
+
   CodeBlob*          cb()         const { return _frame.cb();  }
   nmethod*           nm()         const {
-      assert( cb() != NULL && cb()->is_nmethod(), "usage");
-      return (nmethod*) cb();
+    assert( cb() != NULL && cb()->is_nmethod(), "usage");
+    return (nmethod*) cb();
   }
 
   // Frame type