changeset 52753:528d904ccf11 cont

refactor and improve performance
author rpressler
date Sun, 25 Nov 2018 16:11:37 +0000
parents 1589afaeeec6
children 22ad27a2b8f2 cb23b56b3407
files src/hotspot/cpu/x86/frame_x86.cpp src/hotspot/cpu/x86/frame_x86.inline.hpp src/hotspot/cpu/x86/stubGenerator_x86_64.cpp src/hotspot/os_cpu/bsd_x86/thread_bsd_x86.cpp src/hotspot/os_cpu/linux_x86/thread_linux_x86.cpp src/hotspot/share/runtime/continuation.cpp src/hotspot/share/runtime/frame.hpp src/hotspot/share/runtime/registerMap.hpp src/hotspot/share/runtime/stubRoutines.cpp src/hotspot/share/runtime/stubRoutines.hpp
diffstat 10 files changed, 147 insertions(+), 61 deletions(-) [+]
line wrap: on
line diff
--- a/src/hotspot/cpu/x86/frame_x86.cpp	Fri Nov 23 17:45:49 2018 +0000
+++ b/src/hotspot/cpu/x86/frame_x86.cpp	Sun Nov 25 16:11:37 2018 +0000
@@ -374,6 +374,45 @@
   return fr;
 }
 
+frame frame::sender_for_stub_frame(RegisterMap* map) const {
+  assert(map != NULL, "map must be set");
+  assert (!(map->walk_cont() && map->cont() != NULL), "");
+  assert(_cb->frame_size() >= 0, "must have non-zero frame size");
+  
+  intptr_t* sender_sp = unextended_sp() + _cb->frame_size();
+  intptr_t* unextended_sp = sender_sp;
+
+  // 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);
+
+  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.
+    map->set_include_argument_oops(_cb->caller_must_gc_arguments(map->thread()));
+    if (oop_map() != NULL) {
+      _oop_map->update_register_map(this, map);
+    }
+ 
+    // 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)) { // can happen for safepoint blob
+    assert (!map->walk_cont(), "");
+    sender_pc = Continuation::fix_continuation_bottom_sender(this, map, sender_pc);
+  }
+  return frame(sender_sp, unextended_sp, *saved_fp_addr, sender_pc);
+}
+
 //------------------------------------------------------------------------------
 // frame::verify_deopt_original_pc
 //
--- a/src/hotspot/cpu/x86/frame_x86.inline.hpp	Fri Nov 23 17:45:49 2018 +0000
+++ b/src/hotspot/cpu/x86/frame_x86.inline.hpp	Sun Nov 25 16:11:37 2018 +0000
@@ -305,7 +305,9 @@
   assert(_cb == CodeCache::find_blob(pc()), "Must be the same");
 
   if (_cb != NULL) {
-    return sender_for_compiled_frame<LOOKUP>(map);
+    if (is_compiled_frame())
+      return sender_for_compiled_frame<LOOKUP>(map);
+    return sender_for_stub_frame(map);
   }
   // Must be native-compiled frame, i.e. the marshaling code for native
   // methods that exists in the core system.
@@ -327,7 +329,7 @@
   intptr_t* sender_sp = unextended_sp() + _cb->frame_size();
   intptr_t* unextended_sp = sender_sp;
 
-  assert (!is_compiled_frame() || sender_sp == real_fp(), "sender_sp: " INTPTR_FORMAT " real_fp: " INTPTR_FORMAT, p2i(sender_sp), p2i(real_fp()));
+  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);
@@ -340,11 +342,12 @@
     // 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.
-    map->set_include_argument_oops(_cb->caller_must_gc_arguments(map->thread()));
-    if (!is_compiled_frame() && oop_map() != NULL) { // compiled frames do not use callee-saved registers
-      _oop_map->update_register_map(this, map);
-    }
-    assert (!is_compiled_frame() || oop_map() == NULL || OopMapStream(oop_map(), OopMapValue::callee_saved_value).is_done(), "callee-saved value in compiled frame");
+    assert (!_cb->caller_must_gc_arguments(map->thread()), "");
+    assert (!map->include_argument_oops(), "");
+    // if (!is_compiled_frame() && oop_map() != NULL) { // compiled frames do not use callee-saved registers
+    //   _oop_map->update_register_map(this, map);
+    // }
+    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
@@ -352,10 +355,6 @@
     update_map_with_saved_link(map, saved_fp_addr);
   }
 
-  if (sender_sp == sp()) {
-    tty->print_cr("sender_sp: " INTPTR_FORMAT " sp: " INTPTR_FORMAT, p2i(sender_sp), p2i(sp()));
-    print_on(tty);
-  }
   assert(sender_sp != sp(), "must have changed");
 
   if (Continuation::is_return_barrier_entry(sender_pc)) {
--- a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp	Fri Nov 23 17:45:49 2018 +0000
+++ b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp	Sun Nov 25 16:11:37 2018 +0000
@@ -5612,7 +5612,7 @@
 }
 
   // c_rarg1 ContinuationScope
-address generate_cont_doYield() {
+RuntimeStub* generate_cont_doYield() {
     const char *name = "cont_doYield";
 
     enum layout {
@@ -5693,7 +5693,7 @@
                                   frame_complete,
                                   (framesize >> (LogBytesPerWord - LogBytesPerInt)),
                                   oop_maps, false);
-    return stub->entry_point();
+    return stub;
   }
 
   // c_rarg1 - sp
@@ -6067,7 +6067,8 @@
     StubRoutines::_cont_thaw          = generate_cont_thaw();
     StubRoutines::_cont_returnBarrier = generate_cont_returnBarrier();
     StubRoutines::_cont_returnBarrierExc = generate_cont_returnBarrier_exception();
-    StubRoutines::_cont_doYield    = generate_cont_doYield();
+    StubRoutines::_cont_doYield_stub = generate_cont_doYield();
+    StubRoutines::_cont_doYield    = StubRoutines::_cont_doYield_stub->entry_point();
     StubRoutines::_cont_jump       = generate_cont_jump();
     StubRoutines::_cont_getSP      = generate_cont_getSP();
     StubRoutines::_cont_getPC      = generate_cont_getPC();
--- a/src/hotspot/os_cpu/bsd_x86/thread_bsd_x86.cpp	Fri Nov 23 17:45:49 2018 +0000
+++ b/src/hotspot/os_cpu/bsd_x86/thread_bsd_x86.cpp	Sun Nov 25 16:11:37 2018 +0000
@@ -30,6 +30,8 @@
 frame JavaThread::pd_last_frame() {
   assert(has_last_Java_frame(), "must have last_Java_sp() when suspended");
   vmassert(_anchor.last_Java_pc() != NULL, "not walkable");
+  if (StubRoutines::cont_doYield_stub()->contains(_anchor.last_Java_pc())) // give this special case a little boost in finding the CodeBlob
+    return frame(_anchor.last_Java_sp(), _anchor.last_Java_sp(), _anchor.last_Java_fp(), _anchor.last_Java_pc(), StubRoutines::cont_doYield_stub());
   return frame(_anchor.last_Java_sp(), _anchor.last_Java_fp(), _anchor.last_Java_pc());
 }
 
--- a/src/hotspot/os_cpu/linux_x86/thread_linux_x86.cpp	Fri Nov 23 17:45:49 2018 +0000
+++ b/src/hotspot/os_cpu/linux_x86/thread_linux_x86.cpp	Sun Nov 25 16:11:37 2018 +0000
@@ -30,6 +30,8 @@
 frame JavaThread::pd_last_frame() {
   assert(has_last_Java_frame(), "must have last_Java_sp() when suspended");
   vmassert(_anchor.last_Java_pc() != NULL, "not walkable");
+  if (StubRoutines::cont_doYield_stub()->contains(_anchor.last_Java_pc())) // give this special case a little boost in finding the CodeBlob
+    return frame(_anchor.last_Java_sp(), _anchor.last_Java_sp(), _anchor.last_Java_fp(), _anchor.last_Java_pc(), StubRoutines::cont_doYield_stub());
   return frame(_anchor.last_Java_sp(), _anchor.last_Java_fp(), _anchor.last_Java_pc());
 }
 
--- a/src/hotspot/share/runtime/continuation.cpp	Fri Nov 23 17:45:49 2018 +0000
+++ b/src/hotspot/share/runtime/continuation.cpp	Sun Nov 25 16:11:37 2018 +0000
@@ -133,6 +133,8 @@
   unsigned short uncompressed_size;
 };
 
+static const void* TOMBSTONE = reinterpret_cast<void*>(-1);
+
 #define METADATA_SIZE sizeof(HFrameMetadata) // bytes
 
 #define ELEM_SIZE sizeof(jint) // stack is int[]
@@ -1587,6 +1589,37 @@
 }
 #endif
 
+static const VMReg vmRegRbp = rbp->as_VMReg();
+static const VMReg vmRegRbpNext = vmRegRbp->next();
+
+static void update_map_with_saved_link(RegisterMap* map, intptr_t** link_addr) { // see frame::update_map_with_saved_link
+  map->update_location(vmRegRbp, (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->update_location(vmRegRbpNext, (address) link_addr);
+  }
+#endif // AMD64
+}
+
+static inline frame sender_for_compiled_frame(frame& f, intptr_t** link_addr, ContMirror& cont) {
+  intptr_t* sender_sp = (intptr_t*)(link_addr + frame::sender_sp_offset); //  f.unextended_sp() + (fsize/wordSize); // 
+  address sender_pc = (address) *(sender_sp-1);
+  assert(sender_sp != f.sp(), "must have changed");
+
+  if (Continuation::is_return_barrier_entry(sender_pc)) {
+    sender_pc = cont.entryPC();
+  }
+
+  CodeBlob* sender_cb = ContinuationCodeBlobLookup::find_blob(sender_pc);
+  return sender_cb != NULL 
+   ? frame(sender_sp, sender_sp, *link_addr, sender_pc, sender_cb)
+   : frame(sender_sp, sender_sp, *link_addr, sender_pc);
+}
+
 class FreezeContinuation {
 
 class CompiledFreezeOopFn: public ContOopBase {
@@ -1678,6 +1711,8 @@
   ContMirror& _mirror;
   intptr_t *_bottom_address;
 
+  RegisterMap& _map;
+
   int _oops;
   int _size; // total size of all frames plus metadata. keeps track of offset where a frame should be written and how many bytes we need to allocate.
   int _frames;
@@ -1695,21 +1730,15 @@
   bool _is_first;
   bool _is_last;
 
-  VMReg vmRegRbp;
-  VMReg vmRegRbpNext;
-
   bool is_first() { return _is_first; }
   bool is_last()  { return _is_last;  } // this is only true after returning from the recursive call
 
 public:
-  FreezeContinuation(JavaThread* thread, ContMirror& mirror) : 
-    _thread(thread), _mirror(mirror), _bottom_address(mirror.entrySP()), 
+  FreezeContinuation(JavaThread* thread, ContMirror& mirror, RegisterMap& map) : 
+    _thread(thread), _mirror(mirror), _bottom_address(mirror.entrySP()), _map(map),
     _oops(0), _size(0), _frames(0), _wsp(0), _wref_sp(0),
     _has_fp_oop(false), _fp_index(0),
     _is_first(false), _is_last(false) {
-
-      vmRegRbp = rbp->as_VMReg();
-      vmRegRbpNext = rbp->as_VMReg()->next();
   }
 
   int nr_oops() const { return _oops; }
@@ -1719,14 +1748,13 @@
   hframe top_hframe() { return _top; }
   frame entry_frame() { return _entry_frame; }
 
-  res_freeze freeze(frame f, RegisterMap& regmap) {
-    RegisterMap map = regmap;
-    assert (map.update_map(), "RegisterMap not set to update");
-    map.set_include_argument_oops(false);
+  res_freeze freeze(frame f) {
+    // assert (map.update_map(), "RegisterMap not set to update");
+    assert (!_map.include_argument_oops(), "should be");
     hframe caller;
 
     _is_first = true; // the first frame we'll visit is the top
-    res_freeze result = freeze(f, map, caller);
+    res_freeze result = freeze(f, frame::saved_link_address(&_map), caller); // we do update the link address for the first frame in the map
 
     if (_has_fp_oop) {
       assert(!caller.is_interpreted_frame(), "only compiled frames");
@@ -1828,32 +1856,33 @@
 
       OopMapDo<CompiledFreezeOopFn, CompiledFreezeOopFn, IncludeAllValues> visitor(&oopFn, &oopFn, false /* no derived table lock */);
       visitor.oops_do(&f, &map, oopmap);
-      if (map.include_argument_oops()) {
-        ForwardingOopClosure<CompiledFreezeOopFn> oopClosure(&oopFn);
-        f.cb()->preserve_callee_argument_oops(f, &map, &oopClosure);
-      }
+      assert (!map.include_argument_oops(), "");
+      // if (map.include_argument_oops()) {
+      //   ForwardingOopClosure<CompiledFreezeOopFn> oopClosure(&oopFn);
+      //   f.cb()->preserve_callee_argument_oops(f, &map, &oopClosure);
+      // }
       return oopFn.count();
     }
   };
 
   template <typename FreezeOops>
-  void freeze_oops(frame& f, intptr_t* vsp, intptr_t *hsp, RegisterMap& map, int num_oops) {
+  void freeze_oops(frame& f, intptr_t* vsp, intptr_t *hsp, int num_oops) {
     if (Continuation::PERFTEST_LEVEL < 30) {
       return;
     }
 
     log_trace(jvmcont)("Walking oops (freeze)");
 
-    assert (!map.include_argument_oops(), "");
+    assert (!_map.include_argument_oops(), "");
 
     _has_fp_oop = false;
     int starting_index = _wref_sp - num_oops;
-    int frozen = FreezeOops::freeze_oops(_mirror, this, f, vsp, hsp, map, starting_index);
+    int frozen = FreezeOops::freeze_oops(_mirror, this, f, vsp, hsp, _map, starting_index);
     assert(frozen == num_oops, "check");
     _wref_sp = starting_index;
   }
 
-  res_freeze freeze_interpreted_stackframe(frame& f, RegisterMap& map, hframe& caller) {
+  res_freeze freeze_interpreted_stackframe(frame& f, hframe& caller) {
     if (is_interpreted_frame_owning_locks(f)) {
       return freeze_pinned_monitor;
     }
@@ -1867,7 +1896,7 @@
     _size += fsize + METADATA_SIZE;
     _oops += oops;
 
-    res_freeze result = freeze_caller(f, map, caller); // <----- recursive call
+    res_freeze result = freeze_caller<true>(f, link_address(f, true), caller); // <----- recursive call
     if (result != freeze_ok) {
       return result;
     }
@@ -1898,7 +1927,7 @@
     // patch our stuff - this used to happen in the caller so it needs to happen last
     patch<true>(f, hf, caller); 
 
-    freeze_oops<FreezeInterpretedOops>(f, vsp, hsp, map, oops);
+    freeze_oops<FreezeInterpretedOops>(f, vsp, hsp, oops);
 
     caller = hf;
 
@@ -1909,8 +1938,8 @@
     return freeze_ok;
   }
 
-  res_freeze freeze_compiled_stackframe(frame& f, RegisterMap& map, hframe& caller) {
-    if (is_compiled_frame_owning_locks(_mirror.thread(), &map, f)) {
+  res_freeze freeze_compiled_stackframe(frame& f, intptr_t** callee_link_address, hframe& caller) {
+    if (is_compiled_frame_owning_locks(_mirror.thread(), &_map, f)) {
       return freeze_pinned_monitor;
     }
 
@@ -1923,7 +1952,8 @@
     _size += fsize + METADATA_SIZE;
     _oops += oops;
 
-    res_freeze result = freeze_caller(f, map, caller); // <----- recursive call
+    intptr_t** my_link_address = (intptr_t**) (f.unextended_sp() + f.cb()->frame_size() - frame::sender_sp_offset); // x86 - specific // link_address(f, false)
+    res_freeze result = freeze_caller<false>(f, my_link_address, caller); // <----- recursive call
     if (result != freeze_ok) {
       return result;
     }
@@ -1952,7 +1982,9 @@
     assert (Interpreter::contains(hf.return_pc(_mirror)) == ((!caller.is_empty() && caller.is_interpreted_frame()) || (caller.is_empty() && !_mirror.is_empty() && _mirror.is_flag(FLAG_LAST_FRAME_INTERPRETED))), "");
     bool may_need_alignment = Interpreter::contains(hf.return_pc(_mirror)); // do after fixing return_pc in patch (and/or use equivalent condition above)
 
-    freeze_oops<FreezeCompiledOops>(f, vsp, hsp, map, oops); // must be called after patch, as patch uses the previous freeze_oop data
+    update_map_with_saved_link(&_map, callee_link_address);
+
+    freeze_oops<FreezeCompiledOops>(f, vsp, hsp, oops); // must be called after patch, as patch uses the previous freeze_oop data
 
     caller = hf;
 
@@ -1992,25 +2024,28 @@
     return freeze_ok;
   }
 
-  inline res_freeze freeze_caller(frame& f, RegisterMap& map, hframe& caller) { // TODO: templatize by callee frame type and use in sender;
+  template <bool interpreted>
+  inline res_freeze freeze_caller(frame& f, intptr_t** link_address, hframe& caller) {
     bool is_first = _is_first;
     if (is_first) _is_first = false;
 
-    address link1 = map.trusted_location(vmRegRbp);
-    //address link2 = map.trusted_location(vmRegRbpNext);
-    
-    frame sender = f.frame_sender<ContinuationCodeBlobLookup>(&map); // LOOKUP // TODO: templatize by callee frame type
-    res_freeze result = freeze(sender, map, caller);
-
-    map.update_location(vmRegRbp,     link1);
-    map.update_location(vmRegRbpNext, link1);
+    // address link1 = map.trusted_location(vmRegRbp);
+    // //address link2 = map.trusted_location(vmRegRbpNext);
+
+    frame sender = interpreted
+      ? f.frame_sender<ContinuationCodeBlobLookup>(&_map)
+      : sender_for_compiled_frame(f, link_address, _mirror); // f.sender_for_compiled_frame<ContinuationCodeBlobLookup>(&map); // 
+    res_freeze result = freeze(sender, link_address, caller);
+
+    // map.update_location(vmRegRbp,     link1);
+    // map.update_location(vmRegRbpNext, link1);
 
     _is_first = is_first;
 
     return result;
   }
 
-  res_freeze freeze(frame& f, RegisterMap& map, hframe& caller) {
+  res_freeze freeze(frame& f, intptr_t** callee_link_address, hframe& caller) {
     if (f.real_fp() > _bottom_address) {
       _is_last = true; // the next frame we return to is bottom
       return finalize(f); // done with recursion
@@ -2023,13 +2058,13 @@
       if (f.oop_map() == NULL) {
         return freeze_pinned_native; // special native frame
       }
-      result = freeze_compiled_stackframe(f, map, caller);
+      result = freeze_compiled_stackframe(f, callee_link_address, caller);
     } else {
       bool is_interpreted = f.is_interpreted_frame();
       if (!is_interpreted) {
         return freeze_pinned_native;
       }
-      result = freeze_interpreted_stackframe(f, map, caller);
+      result = freeze_interpreted_stackframe(f, caller);
     }
 
     if (_is_last) _is_last = false;
@@ -2121,8 +2156,8 @@
 
   const bool empty = cont.is_empty();
 
-  FreezeContinuation fc(thread, cont);
-  res_freeze result = fc.freeze(f, map);
+  FreezeContinuation fc(thread, cont, map);
+  res_freeze result = fc.freeze(f);
   if (result != freeze_ok) {
     return result;
   }
@@ -2192,11 +2227,15 @@
   oop cont = get_continuation(thread);
   assert(cont != NULL && oopDesc::is_oop_or_null(cont), "Invalid cont: " INTPTR_FORMAT, p2i((void*)cont));
 
-  RegisterMap map(thread, true);
+  RegisterMap map(thread, false, false, false);
   map.set_include_argument_oops(false);
   // Note: if the doYield stub does not have its own frame, we may need to consider deopt here, especially if yield is inlinable
-  frame f = thread->last_frame(); // this is the doYield stub frame. last_frame is set up by the call_VM infrastructure
+  frame f = thread->last_frame(); // this is the doYield stub frame. last_frame is set up by the call_VM infrastructure // <---- CodeCache::find_blob is expensive
+  // f.print_on(tty);
+
+  frame::update_map_with_saved_link(&map, link_address(f));
   f = f.frame_sender<ContinuationCodeBlobLookup>(&map); // LOOKUP // this is the yield frame
+
   assert (f.pc() == fi->pc, "");
   // The following doesn't work because fi->fp can contain an oop, that a GC doesn't know about when walking.
   // frame::update_map_with_saved_link(&map, (intptr_t **)&fi->fp);
--- a/src/hotspot/share/runtime/frame.hpp	Fri Nov 23 17:45:49 2018 +0000
+++ b/src/hotspot/share/runtime/frame.hpp	Sun Nov 25 16:11:37 2018 +0000
@@ -171,9 +171,10 @@
 
  private:
   // Helper methods for better factored code in frame::sender
-  frame sender_for_entry_frame(RegisterMap* map) const;
   template <typename LOOKUP>
   frame sender_for_compiled_frame(RegisterMap* map) const;
+  frame sender_for_entry_frame(RegisterMap* map) const;
+  frame sender_for_stub_frame(RegisterMap* map) const;
   frame sender_for_interpreter_frame(RegisterMap* map) const;
   frame sender_for_native_frame(RegisterMap* map) const;
 
--- a/src/hotspot/share/runtime/registerMap.hpp	Fri Nov 23 17:45:49 2018 +0000
+++ b/src/hotspot/share/runtime/registerMap.hpp	Sun Nov 25 16:11:37 2018 +0000
@@ -77,7 +77,7 @@
   Handle      _cont;                    // The current continuation, if any
   bool        _update_map;              // Tells if the register map need to be
                                         // updated when traversing the stack
-  bool        _validate_oops;           // whether to perform valid oop checks in asserts
+  bool        _validate_oops;           // whether to perform valid oop checks in asserts -- used only in the map use for continuation freeze/thaw
   bool        _walk_cont;               // whether to walk frames on a continuation stack
 
 #ifdef ASSERT
@@ -110,7 +110,7 @@
     int index = reg->value() / location_valid_type_size;
     assert(0 <= reg->value() && reg->value() < reg_count, "range check");
     assert(0 <= index && index < location_valid_size, "range check");
-    assert(_update_map, "updating map that does not need updating");
+    assert(!_validate_oops || _update_map, "updating map that does not need updating");
     _location[reg->value()] = (intptr_t*) loc;
     check_location_valid();
   }
@@ -119,7 +119,7 @@
     int index = reg->value() / location_valid_type_size;
     assert(0 <= reg->value() && reg->value() < reg_count, "range check");
     assert(0 <= index && index < location_valid_size, "range check");
-    assert(_update_map, "updating map that does not need updating");
+    assert(!_validate_oops || _update_map, "updating map that does not need updating");
     _location[reg->value()] = (intptr_t*) loc;
     _location_valid[index] |= ((LocationValidType)1 << (reg->value() % location_valid_type_size));
     check_location_valid();
--- a/src/hotspot/share/runtime/stubRoutines.cpp	Fri Nov 23 17:45:49 2018 +0000
+++ b/src/hotspot/share/runtime/stubRoutines.cpp	Sun Nov 25 16:11:37 2018 +0000
@@ -177,6 +177,7 @@
 address StubRoutines::_safefetchN_fault_pc               = NULL;
 address StubRoutines::_safefetchN_continuation_pc        = NULL;
 
+RuntimeStub* StubRoutines::_cont_doYield_stub = NULL;
 address StubRoutines::_cont_doYield       = NULL;
 address StubRoutines::_cont_jump          = NULL;
 address StubRoutines::_cont_thaw          = NULL;
--- a/src/hotspot/share/runtime/stubRoutines.hpp	Fri Nov 23 17:45:49 2018 +0000
+++ b/src/hotspot/share/runtime/stubRoutines.hpp	Sun Nov 25 16:11:37 2018 +0000
@@ -208,6 +208,7 @@
   static address _dlibm_tan_cot_huge;
   static address _dtan;
 
+  static RuntimeStub* _cont_doYield_stub;
   static address _cont_doYield;
   static address _cont_jump;
   static address _cont_thaw;
@@ -393,6 +394,7 @@
   static address dlibm_tan_cot_huge()  { return _dlibm_tan_cot_huge; }
   static address dtan()                { return _dtan; }
 
+  static RuntimeStub* cont_doYield_stub() { return _cont_doYield_stub; }
   static address cont_doYield()        { return _cont_doYield; }
   static address cont_jump()           { return _cont_jump; }
   static address cont_thaw()           { return _cont_thaw; }