8215205: javaVFrame much slower than vframeStream
authordlong
Tue, 18 Dec 2018 12:36:27 -0800
changeset 53065 2f41e4935c34
parent 53064 103ed9569fc8
child 53066 a7bd89486175
8215205: javaVFrame much slower than vframeStream Reviewed-by: mchung, thartmann
src/hotspot/share/code/scopeDesc.cpp
src/hotspot/share/code/scopeDesc.hpp
src/hotspot/share/runtime/vframe.cpp
src/hotspot/share/runtime/vframe.hpp
src/hotspot/share/runtime/vframe.inline.hpp
src/hotspot/share/runtime/vframe_hp.cpp
src/hotspot/share/runtime/vframe_hp.hpp
--- a/src/hotspot/share/code/scopeDesc.cpp	Tue Dec 18 12:08:51 2018 -0800
+++ b/src/hotspot/share/code/scopeDesc.cpp	Tue Dec 18 12:36:27 2018 -0800
@@ -51,9 +51,9 @@
 }
 
 
-ScopeDesc::ScopeDesc(const ScopeDesc* parent) {
+void ScopeDesc::initialize(const ScopeDesc* parent, int decode_offset) {
   _code          = parent->_code;
-  _decode_offset = parent->_sender_decode_offset;
+  _decode_offset = decode_offset;
   _objects       = parent->_objects;
   _reexecute     = false; //reexecute only applies to the first scope
   _rethrow_exception = false;
@@ -61,6 +61,14 @@
   decode_body();
 }
 
+ScopeDesc::ScopeDesc(const ScopeDesc* parent) {
+  initialize(parent, parent->_sender_decode_offset);
+}
+
+ScopeDesc::ScopeDesc(const ScopeDesc* parent, int decode_offset) {
+  initialize(parent, decode_offset);
+}
+
 
 void ScopeDesc::decode_body() {
   if (decode_offset() == DebugInformationRecorder::serialized_null) {
--- a/src/hotspot/share/code/scopeDesc.hpp	Tue Dec 18 12:08:51 2018 -0800
+++ b/src/hotspot/share/code/scopeDesc.hpp	Tue Dec 18 12:36:27 2018 -0800
@@ -67,6 +67,9 @@
   // avoid a .hpp-.hpp dependency.)
   ScopeDesc(const CompiledMethod* code, int decode_offset, bool reexecute, bool rethrow_exception, bool return_oop);
 
+  // Direct access to scope
+  ScopeDesc* at_offset(int decode_offset) { return new ScopeDesc(this, decode_offset); }
+
   // JVM state
   Method* method()      const { return _method; }
   int          bci()      const { return _bci;    }
@@ -85,12 +88,16 @@
   // Returns where the scope was decoded
   int decode_offset() const { return _decode_offset; }
 
+  int sender_decode_offset() const { return _sender_decode_offset; }
+
   // Tells whether sender() returns NULL
   bool is_top() const;
 
  private:
-  // Alternative constructor
+  void initialize(const ScopeDesc* parent, int decode_offset);
+  // Alternative constructors
   ScopeDesc(const ScopeDesc* parent);
+  ScopeDesc(const ScopeDesc* parent, int decode_offset);
 
   // JVM state
   Method*       _method;
--- a/src/hotspot/share/runtime/vframe.cpp	Tue Dec 18 12:08:51 2018 -0800
+++ b/src/hotspot/share/runtime/vframe.cpp	Tue Dec 18 12:36:27 2018 -0800
@@ -452,8 +452,10 @@
   _stop_at_java_call_stub = stop_at_java_call_stub;
 
   // skip top frame, as it may not be at safepoint
+  _prev_frame = top_frame;
   _frame  = top_frame.sender(&_reg_map);
   while (!fill_from_frame()) {
+    _prev_frame = _frame;
     _frame = _frame.sender(&_reg_map);
   }
 }
@@ -534,6 +536,37 @@
   }
 }
 
+javaVFrame* vframeStreamCommon::asJavaVFrame() {
+  javaVFrame* result = NULL;
+  if (_mode == compiled_mode) {
+    guarantee(_frame.is_compiled_frame(), "expected compiled Java frame");
+
+    // lazy update to register map
+    bool update_map = true;
+    RegisterMap map(_thread, update_map);
+    frame f = _prev_frame.sender(&map);
+
+    guarantee(f.is_compiled_frame(), "expected compiled Java frame");
+
+    compiledVFrame* cvf = compiledVFrame::cast(vframe::new_vframe(&f, &map, _thread));
+
+    guarantee(cvf->cb() == cb(), "wrong code blob");
+
+    // get the same scope as this stream
+    cvf = cvf->at_scope(_decode_offset, _vframe_id);
+
+    guarantee(cvf->scope()->decode_offset() == _decode_offset, "wrong scope");
+    guarantee(cvf->scope()->sender_decode_offset() == _sender_decode_offset, "wrong scope");
+    guarantee(cvf->vframe_id() == _vframe_id, "wrong vframe");
+
+    result = cvf;
+  } else {
+    result = javaVFrame::cast(vframe::new_vframe(&_frame, &_reg_map, _thread));
+  }
+  guarantee(result->method() == method(), "wrong method");
+  return result;
+}
+
 
 #ifndef PRODUCT
 void vframe::print() {
--- a/src/hotspot/share/runtime/vframe.hpp	Tue Dec 18 12:08:51 2018 -0800
+++ b/src/hotspot/share/runtime/vframe.hpp	Tue Dec 18 12:36:27 2018 -0800
@@ -278,12 +278,16 @@
 class vframeStreamCommon : StackObj {
  protected:
   // common
+  frame        _prev_frame;
   frame        _frame;
   JavaThread*  _thread;
   RegisterMap  _reg_map;
   enum { interpreted_mode, compiled_mode, at_end_mode } _mode;
 
+  // For compiled_mode
+  int _decode_offset;
   int _sender_decode_offset;
+  int _vframe_id;
 
   // Cached information
   Method* _method;
@@ -320,6 +324,8 @@
       return (CompiledMethod*) cb();
   }
 
+  javaVFrame* asJavaVFrame();
+
   // Frame type
   inline bool is_interpreted_frame() const;
   inline bool is_entry_frame() const;
--- a/src/hotspot/share/runtime/vframe.inline.hpp	Tue Dec 18 12:08:51 2018 -0800
+++ b/src/hotspot/share/runtime/vframe.inline.hpp	Tue Dec 18 12:36:27 2018 -0800
@@ -44,6 +44,7 @@
 
   // handle general case
   do {
+    _prev_frame = _frame;
     _frame = _frame.sender(&_reg_map);
   } while (!fill_from_frame());
 }
@@ -59,6 +60,7 @@
 
   _frame = _thread->last_frame();
   while (!fill_from_frame()) {
+    _prev_frame = _frame;
     _frame = _frame.sender(&_reg_map);
   }
 }
@@ -68,12 +70,14 @@
     return false;
   }
   fill_from_compiled_frame(_sender_decode_offset);
+  ++_vframe_id;
   return true;
 }
 
 
 inline void vframeStreamCommon::fill_from_compiled_frame(int decode_offset) {
   _mode = compiled_mode;
+  _decode_offset = decode_offset;
 
   // Range check to detect ridiculous offsets.
   if (decode_offset == DebugInformationRecorder::serialized_null ||
@@ -118,6 +122,8 @@
 inline void vframeStreamCommon::fill_from_compiled_native_frame() {
   _mode = compiled_mode;
   _sender_decode_offset = DebugInformationRecorder::serialized_null;
+  _decode_offset = DebugInformationRecorder::serialized_null;
+  _vframe_id = 0;
   _method = nm()->method();
   _bci = 0;
 }
@@ -187,6 +193,7 @@
         decode_offset = pc_desc->scope_decode_offset();
       }
       fill_from_compiled_frame(decode_offset);
+      _vframe_id = 0;
     }
     return true;
   }
--- a/src/hotspot/share/runtime/vframe_hp.cpp	Tue Dec 18 12:08:51 2018 -0800
+++ b/src/hotspot/share/runtime/vframe_hp.cpp	Tue Dec 18 12:36:27 2018 -0800
@@ -252,6 +252,14 @@
   guarantee(_scope != NULL, "scope must be present");
 }
 
+compiledVFrame* compiledVFrame::at_scope(int decode_offset, int vframe_id) {
+  if (scope()->decode_offset() != decode_offset) {
+    ScopeDesc* scope = this->scope()->at_offset(decode_offset);
+    return new compiledVFrame(frame_pointer(), register_map(), thread(), scope, vframe_id);
+  }
+  assert(_vframe_id == vframe_id, "wrong frame id");
+  return this;
+}
 
 bool compiledVFrame::is_top() const {
   // FIX IT: Remove this when new native stubs are in place
--- a/src/hotspot/share/runtime/vframe_hp.hpp	Tue Dec 18 12:08:51 2018 -0800
+++ b/src/hotspot/share/runtime/vframe_hp.hpp	Tue Dec 18 12:36:27 2018 -0800
@@ -72,6 +72,9 @@
   // Returns the scopeDesc
   ScopeDesc* scope() const { return _scope; }
 
+  // Return the compiledVFrame for the desired scope
+  compiledVFrame* at_scope(int decode_offset, int vframe_id);
+
   // Returns SynchronizationEntryBCI or bci() (used for synchronization)
   int raw_bci() const;