8207392: [PPC64] Implement JFR profiling.
authorghaug
Tue, 24 Jul 2018 12:57:40 +0200
changeset 51233 ceebbc92b3b0
parent 51232 ad1fa1db73d9
child 51234 5cff3e41d003
8207392: [PPC64] Implement JFR profiling. Reviewed-by: simonis, goetz
src/hotspot/cpu/ppc/frame_ppc.cpp
src/hotspot/os_cpu/linux_ppc/thread_linux_ppc.cpp
--- a/src/hotspot/cpu/ppc/frame_ppc.cpp	Tue Jul 24 10:07:26 2018 +0100
+++ b/src/hotspot/cpu/ppc/frame_ppc.cpp	Tue Jul 24 12:57:40 2018 +0200
@@ -49,14 +49,134 @@
 
 bool frame::safe_for_sender(JavaThread *thread) {
   bool safe = false;
-  address   cursp = (address)sp();
-  address   curfp = (address)fp();
-  if ((cursp != NULL && curfp != NULL &&
-      (cursp <= thread->stack_base() && cursp >= thread->stack_base() - thread->stack_size())) &&
-      (curfp <= thread->stack_base() && curfp >= thread->stack_base() - thread->stack_size())) {
-      safe = true;
+  address sp = (address)_sp;
+  address fp = (address)_fp;
+  address unextended_sp = (address)_unextended_sp;
+
+  // Consider stack guards when trying to determine "safe" stack pointers
+  static size_t stack_guard_size = os::uses_stack_guard_pages() ?
+    JavaThread::stack_red_zone_size() + JavaThread::stack_yellow_reserved_zone_size() : 0;
+  size_t usable_stack_size = thread->stack_size() - stack_guard_size;
+
+  // sp must be within the usable part of the stack (not in guards)
+  bool sp_safe = (sp < thread->stack_base()) &&
+                 (sp >= thread->stack_base() - usable_stack_size);
+
+
+  if (!sp_safe) {
+    return false;
+  }
+
+  // Unextended sp must be within the stack and above or equal sp
+  bool unextended_sp_safe = (unextended_sp < thread->stack_base()) && (unextended_sp >= sp);
+
+  if (!unextended_sp_safe) {
+    return false;
   }
-  return safe;
+
+  // An fp must be within the stack and above (but not equal) sp.
+  bool fp_safe = (fp <= thread->stack_base()) &&  (fp > sp);
+  // an interpreter fp must be within the stack and above (but not equal) sp
+  bool fp_interp_safe = (fp <= thread->stack_base()) &&  (fp > sp) &&
+    ((fp - sp) >= (ijava_state_size + top_ijava_frame_abi_size));
+
+  // We know sp/unextended_sp are safe, only fp is questionable here
+
+  // If the current frame is known to the code cache then we can attempt to
+  // to construct the sender and do some validation of it. This goes a long way
+  // toward eliminating issues when we get in frame construction code
+
+  if (_cb != NULL ){
+    // Entry frame checks
+    if (is_entry_frame()) {
+      // An entry frame must have a valid fp.
+      return fp_safe && is_entry_frame_valid(thread);
+    }
+
+    // Now check if the frame is complete and the test is
+    // reliable. Unfortunately we can only check frame completeness for
+    // runtime stubs and nmethods. Other generic buffer blobs are more
+    // problematic so we just assume they are OK. Adapter blobs never have a
+    // complete frame and are never OK
+    if (!_cb->is_frame_complete_at(_pc)) {
+      if (_cb->is_compiled() || _cb->is_adapter_blob() || _cb->is_runtime_stub()) {
+        return false;
+      }
+    }
+
+    // Could just be some random pointer within the codeBlob.
+    if (!_cb->code_contains(_pc)) {
+      return false;
+    }
+
+    if (is_interpreted_frame() && !fp_interp_safe) {
+      return false;
+    }
+
+    abi_minframe* sender_abi = (abi_minframe*) fp;
+    intptr_t* sender_sp = (intptr_t*) fp;
+    address   sender_pc = (address) sender_abi->lr;;
+
+    // We must always be able to find a recognizable pc.
+    CodeBlob* sender_blob = CodeCache::find_blob_unsafe(sender_pc);
+    if (sender_blob == NULL) {
+      return false;
+    }
+
+    // Could be a zombie method
+    if (sender_blob->is_zombie() || sender_blob->is_unloaded()) {
+      return false;
+    }
+
+    // It should be safe to construct the sender though it might not be valid.
+
+    frame sender(sender_sp, sender_pc);
+
+    // Do we have a valid fp?
+    address sender_fp = (address) sender.fp();
+
+    // sender_fp must be within the stack and above (but not
+    // equal) current frame's fp.
+    if (sender_fp > thread->stack_base() || sender_fp <= fp) {
+        return false;
+    }
+
+    // If the potential sender is the interpreter then we can do some more checking.
+    if (Interpreter::contains(sender_pc)) {
+      return sender.is_interpreted_frame_valid(thread);
+    }
+
+    // Could just be some random pointer within the codeBlob.
+    if (!sender.cb()->code_contains(sender_pc)) {
+      return false;
+    }
+
+    // We should never be able to see an adapter if the current frame is something from code cache.
+    if (sender_blob->is_adapter_blob()) {
+      return false;
+    }
+
+    if (sender.is_entry_frame()) {
+      return sender.is_entry_frame_valid(thread);
+    }
+
+    // Frame size is always greater than zero. If the sender frame size is zero or less,
+    // something is really weird and we better give up.
+    if (sender_blob->frame_size() <= 0) {
+      return false;
+    }
+
+    return true;
+  }
+
+  // Must be native-compiled frame. Since sender will try and use fp to find
+  // linkages it must be safe
+
+  if (!fp_safe) {
+    return false;
+  }
+
+  return true;
 }
 
 bool frame::is_interpreted_frame() const  {
--- a/src/hotspot/os_cpu/linux_ppc/thread_linux_ppc.cpp	Tue Jul 24 10:07:26 2018 +0100
+++ b/src/hotspot/os_cpu/linux_ppc/thread_linux_ppc.cpp	Tue Jul 24 12:57:40 2018 +0200
@@ -42,16 +42,60 @@
 }
 
 bool JavaThread::pd_get_top_frame_for_profiling(frame* fr_addr, void* ucontext, bool isInJava) {
-  ucontext_t* uc = (ucontext_t*) ucontext;
-  *fr_addr = frame((intptr_t*)uc->uc_mcontext.regs->gpr[1/*REG_SP*/],
-                   (address)uc->uc_mcontext.regs->nip);
-  return true;
+  assert(this->is_Java_thread(), "must be JavaThread");
+
+  // If we have a last_Java_frame, then we should use it even if
+  // isInJava == true.  It should be more reliable than ucontext info.
+  if (has_last_Java_frame() && frame_anchor()->walkable()) {
+    *fr_addr = pd_last_frame();
+    return true;
+  }
+
+  // At this point, we don't have a last_Java_frame, so
+  // we try to glean some information out of the ucontext
+  // if we were running Java code when SIGPROF came in.
+  if (isInJava) {
+    ucontext_t* uc = (ucontext_t*) ucontext;
+    frame ret_frame((intptr_t*)uc->uc_mcontext.regs->gpr[1/*REG_SP*/],
+                     (address)uc->uc_mcontext.regs->nip);
+
+    if (ret_frame.pc() == NULL) {
+      // ucontext wasn't useful
+      return false;
+    }
+
+    if (ret_frame.is_interpreted_frame()) {
+       frame::ijava_state* istate = ret_frame.get_ijava_state();
+       if (!((Method*)(istate->method))->is_metaspace_object()) {
+         return false;
+       }
+       uint64_t reg_bcp = uc->uc_mcontext.regs->gpr[14/*R14_bcp*/];
+       uint64_t istate_bcp = istate->bcp;
+       uint64_t code_start = (uint64_t)(((Method*)(istate->method))->code_base());
+       uint64_t code_end = (uint64_t)(((Method*)istate->method)->code_base() + ((Method*)istate->method)->code_size());
+       if (istate_bcp >= code_start && istate_bcp < code_end) {
+         // we have a valid bcp, don't touch it, do nothing
+       } else if (reg_bcp >= code_start && reg_bcp < code_end) {
+         istate->bcp = reg_bcp;
+      } else {
+         return false;
+       }
+    }
+    if (!ret_frame.safe_for_sender(this)) {
+      // nothing else to try if the frame isn't good
+      return false;
+    }
+    *fr_addr = ret_frame;
+    return true;
+  }
+  // nothing else to try
+  return false;
 }
 
 // Forte Analyzer AsyncGetCallTrace profiling support is not implemented on Linux/PPC.
 bool JavaThread::pd_get_top_frame_for_signal_handler(frame* fr_addr, void* ucontext, bool isInJava) {
-  Unimplemented();
-  return false;
+  assert(this->is_Java_thread(), "must be JavaThread");
+  return pd_get_top_frame_for_profiling(fr_addr, ucontext, isInJava);
 }
 
 void JavaThread::cache_global_variables() { }