< prev index next >

src/hotspot/cpu/x86/frame_x86.inline.hpp

Print this page

        

@@ -24,64 +24,134 @@
 
 #ifndef CPU_X86_FRAME_X86_INLINE_HPP
 #define CPU_X86_FRAME_X86_INLINE_HPP
 
 #include "code/codeCache.hpp"
+#include "code/codeCache.inline.hpp"
 #include "code/vmreg.inline.hpp"
+#include "compiler/oopMap.inline.hpp"
+#include "runtime/sharedRuntime.hpp"
 
 // Inline functions for Intel frames:
 
+class ContinuationCodeBlobLookup {
+public:
+  enum { has_oopmap_lookup = true };
+
+  static CodeBlob* find_blob(address pc) {
+    CodeBlob* cb = CodeCache::find_blob_fast(pc);
+    /*Prefetch::read(cb, PrefetchScanIntervalInBytes);
+    Prefetch::read((void*)cb->is_compiled_addr(), PrefetchScanIntervalInBytes);
+    Prefetch::read((void*) ((CompiledMethod*) cb)->deopt_handler_begin_addr(), PrefetchScanIntervalInBytes);*/
+    return cb;
+  }
+
+  static CodeBlob* find_blob_and_oopmap(address pc, int& slot) {
+    return CodeCache::find_blob_and_oopmap(pc, slot);
+  }
+};
+
 // Constructors:
 
 inline frame::frame() {
   _pc = NULL;
   _sp = NULL;
   _unextended_sp = NULL;
   _fp = NULL;
   _cb = NULL;
   _deopt_state = unknown;
+  _oop_map = NULL;
 }
 
 inline void frame::init(intptr_t* sp, intptr_t* fp, address pc) {
   _sp = sp;
   _unextended_sp = sp;
   _fp = fp;
   _pc = pc;
   assert(pc != NULL, "no pc?");
-  _cb = CodeCache::find_blob(pc);
+  _cb = CodeCache::find_blob_fast(pc);
   adjust_unextended_sp();
 
   address original_pc = CompiledMethod::get_deopt_original_pc(this);
   if (original_pc != NULL) {
     _pc = original_pc;
     _deopt_state = is_deoptimized;
   } else {
     _deopt_state = not_deoptimized;
   }
+
+  _oop_map = NULL;
 }
 
 inline frame::frame(intptr_t* sp, intptr_t* fp, address pc) {
   init(sp, fp, pc);
 }
 
+inline frame::frame(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, address pc, CodeBlob* cb) {
+  _sp = sp;
+  _unextended_sp = unextended_sp;
+  _fp = fp;
+  _pc = pc;
+  assert(pc != NULL, "no pc?");
+  _cb = cb;
+  _oop_map = NULL;
+  setup(pc);
+}
+
+inline frame::frame(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, address pc, CodeBlob* cb, const ImmutableOopMap* oop_map) {
+  _sp = sp;
+  _unextended_sp = unextended_sp;
+  _fp = fp;
+  _pc = pc;
+  assert(pc != NULL, "no pc?");
+  _cb = cb;
+  _oop_map = oop_map;
+  setup(pc);
+}
+
+inline frame::frame(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, address pc, CodeBlob* cb, const ImmutableOopMap* oop_map, bool dummy) {
+  _sp = sp;
+  _unextended_sp = unextended_sp;
+  _fp = fp;
+  _pc = pc;
+  assert(pc != NULL, "no pc?");
+  _cb = cb;
+  _oop_map = oop_map;
+  _deopt_state = not_deoptimized;
+#ifdef ASSERT
+  // The following assertion has been disabled because it would sometime trap for Continuation.run, which is not *in* a continuation
+  // and therefore does not clear the _cont_fastpath flag, but this is benign even in fast mode (see Freeze::setup_jump)
+  // if (cb != NULL) {
+  //   setup(pc);
+  //   assert(_pc == pc && _deopt_state == not_deoptimized, "");
+  // }
+#endif
+}
+
 inline frame::frame(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, address pc) {
   _sp = sp;
   _unextended_sp = unextended_sp;
   _fp = fp;
   _pc = pc;
   assert(pc != NULL, "no pc?");
-  _cb = CodeCache::find_blob(pc);
+  _cb = CodeCache::find_blob(pc); // TODO R find_blob_fast
+  _oop_map = NULL;
+  setup(pc);
+}
+
+inline void frame::setup(address pc) {
   adjust_unextended_sp();
 
+  assert(_cb != NULL, "pc: " INTPTR_FORMAT, p2i(pc));
   address original_pc = CompiledMethod::get_deopt_original_pc(this);
   if (original_pc != NULL) {
     _pc = original_pc;
     assert(_cb->as_compiled_method()->insts_contains_inclusive(_pc),
            "original PC must be in the main code section of the the compiled method (or must be immediately following it)");
     _deopt_state = is_deoptimized;
   } else {
-    if (_cb->is_deoptimization_stub()) {
+    if (_cb == SharedRuntime::deopt_blob()) {
       _deopt_state = is_deoptimized;
     } else {
       _deopt_state = not_deoptimized;
     }
   }

@@ -113,10 +183,23 @@
     _pc = original_pc;
     _deopt_state = is_deoptimized;
   } else {
     _deopt_state = not_deoptimized;
   }
+  _oop_map = NULL;
+}
+
+inline frame::frame(int sp, int ref_sp, intptr_t fp, address pc, CodeBlob* cb, bool deopt) {
+  _cont_sp._sp = sp;
+  _cont_sp._ref_sp = ref_sp;
+  _unextended_sp = NULL;
+  _fp = (intptr_t*)fp;
+  _pc = pc;
+  assert(pc != NULL, "no pc?");
+  _cb = cb;
+  _deopt_state = deopt ? is_deoptimized : not_deoptimized;
+  _oop_map = NULL;
 }
 
 // Accessors
 
 inline bool frame::equal(frame other) const {

@@ -141,10 +224,52 @@
 
 inline intptr_t* frame::link() const              { return (intptr_t*) *(intptr_t **)addr_at(link_offset); }
 
 inline intptr_t* frame::unextended_sp() const     { return _unextended_sp; }
 
+inline intptr_t* frame::real_fp() const {
+  if (_cb != NULL) {
+    // use the frame size if valid
+    int size = _cb->frame_size();
+    if (size > 0) {
+      return unextended_sp() + size;
+    }
+  }
+  // else rely on fp()
+  assert(! is_compiled_frame(), "unknown compiled frame size");
+  return fp();
+}
+
+// helper to update a map with callee-saved RBP
+
+template <typename RegisterMapT>
+void frame::update_map_with_saved_link(RegisterMapT* map, intptr_t** link_addr) {
+  // The interpreter and compiler(s) always save EBP/RBP in a known
+  // location on entry. We must record where that location is
+  // so this if EBP/RBP was live on callout from c2 we can find
+  // the saved copy no matter what it called.
+
+  // Since the interpreter always saves EBP/RBP if we record where it is then
+  // we don't have to always save EBP/RBP on entry and exit to c2 compiled
+  // code, on entry will be enough.
+  map->set_location(rbp->as_VMReg(), (address) link_addr);
+#ifdef AMD64
+  // this is weird "H" ought to be at a higher address however the
+  // oopMaps seems to have the "H" regs at the same address and the
+  // vanilla register.
+  // XXXX make this go away
+  if (true) {
+    map->set_location(rbp->as_VMReg()->next(), (address) link_addr);
+  }
+#endif // AMD64
+}
+
+template <typename RegisterMapT>
+intptr_t** frame::saved_link_address(const RegisterMapT* map) {
+  return (intptr_t**)map->location(rbp->as_VMReg());
+}
+
 // Return address:
 
 inline address* frame::sender_pc_addr()      const { return (address*) addr_at( return_addr_offset); }
 inline address  frame::sender_pc()           const { return *sender_pc_addr(); }
 

@@ -238,6 +363,111 @@
   guarantee(result_adr != NULL, "bad register save location");
 
   *result_adr = obj;
 }
 
+inline bool frame::is_interpreted_frame() const {
+  return Interpreter::contains(pc());
+}
+
+template <typename LOOKUP>
+frame frame::frame_sender(RegisterMap* map) const {
+  // Default is we done have to follow them. The sender_for_xxx will
+  // update it accordingly
+  map->set_include_argument_oops(false);
+
+  if (is_entry_frame())       return sender_for_entry_frame(map);
+  if (is_interpreted_frame()) return sender_for_interpreter_frame(map);
+
+  assert(_cb == CodeCache::find_blob(pc()), "Must be the same");
+
+  if (_cb != NULL) {
+    return is_compiled_frame() ? sender_for_compiled_frame<LOOKUP, false>(map) : sender_for_compiled_frame<LOOKUP, true>(map);
+  }
+  // Must be native-compiled frame, i.e. the marshaling code for native
+  // methods that exists in the core system.
+  return frame(sender_sp(), link(), sender_pc());
+}
+
+//------------------------------------------------------------------------------
+// frame::sender_for_compiled_frame
+template <typename LOOKUP, bool stub>
+frame frame::sender_for_compiled_frame(RegisterMap* map) const {
+  assert(map != NULL, "map must be set");
+
+  if (map->in_cont()) { // already in an h-stack
+    return Continuation::sender_for_compiled_frame(*this, map);
+  }
+
+  // frame owned by optimizing compiler
+  assert(_cb->frame_size() >= 0, "must have non-zero frame size");
+  intptr_t* sender_sp = unextended_sp() + _cb->frame_size();
+
+  assert (sender_sp == real_fp(), "sender_sp: " INTPTR_FORMAT " real_fp: " INTPTR_FORMAT, p2i(sender_sp), p2i(real_fp()));
+
+  // On Intel the return_address is always the word on the stack
+  address sender_pc = (address) *(sender_sp-1);
+
+  // This is the saved value of EBP which may or may not really be an FP.
+  // It is only an FP if the sender is an interpreter frame (or C1?).
+  intptr_t** saved_fp_addr = (intptr_t**) (sender_sp - frame::sender_sp_offset);
+  intptr_t* sender_fp = *saved_fp_addr;
+  if (map->update_map()) {
+    // Tell GC to use argument oopmaps for some runtime stubs that need it.
+    // For C1, the runtime stub might not have oop maps, so set this flag
+    // outside of update_register_map.
+    if (stub) { // compiled frames do not use callee-saved registers
+      map->set_include_argument_oops(_cb->caller_must_gc_arguments(map->thread()));
+      if (oop_map() != NULL) { 
+        _oop_map->update_register_map(this, map);
+      }
+    } else {
+      assert (!_cb->caller_must_gc_arguments(map->thread()), "");
+      assert (!map->include_argument_oops(), "");
+      assert (oop_map() == NULL || OopMapStream(oop_map(), OopMapValue::callee_saved_value).is_done(), "callee-saved value in compiled frame");
+    }
+
+    // Since the prolog does the save and restore of EBP there is no oopmap
+    // for it so we must fill in its location as if there was an oopmap entry
+    // since if our caller was compiled code there could be live jvm state in it.
+    update_map_with_saved_link(map, saved_fp_addr);
+  }
+
+  assert(sender_sp != sp(), "must have changed");
+
+  if (Continuation::is_return_barrier_entry(sender_pc)) {       
+    if (map->walk_cont()) { // about to walk into an h-stack    
+      return Continuation::top_frame(*this, map);       
+    } else {
+      Continuation::fix_continuation_bottom_sender(map, *this, &sender_pc, &sender_sp, &sender_fp);     
+    }
+  }
+
+  intptr_t* unextended_sp = sender_sp;
+  CodeBlob* sender_cb = LOOKUP::find_blob(sender_pc);
+  if (sender_cb != NULL) {
+    return frame(sender_sp, unextended_sp, sender_fp, sender_pc, sender_cb);
+  }
+  // tty->print_cr(">>>> NO CB:"); print_on(tty);
+  return frame(sender_sp, unextended_sp, sender_fp, sender_pc);
+}
+
+inline const ImmutableOopMap* frame::get_oop_map() const {
+  if (_cb == NULL) return NULL;
+  if (_cb->oop_maps() != NULL) {
+    NativePostCallNop* nop = nativePostCallNop_at(_pc);
+    if (nop != NULL &&
+#ifdef CONT_DOUBLE_NOP
+      !nop->is_mode2() &&
+#endif
+      nop->displacement() != 0
+    ) {
+      int slot = ((nop->displacement() >> 24) & 0xff);
+      return _cb->oop_map_for_slot(slot, _pc);
+    }
+    const ImmutableOopMap* oop_map = OopMapSet::find_map(this);
+    return oop_map;
+  }
+  return NULL;
+}
+
 #endif // CPU_X86_FRAME_X86_INLINE_HPP
< prev index next >