diff a/src/hotspot/cpu/x86/continuationFreezeThaw_x86.inline.hpp b/src/hotspot/cpu/x86/continuationFreezeThaw_x86.inline.hpp
--- a/src/hotspot/cpu/x86/continuationFreezeThaw_x86.inline.hpp
+++ b/src/hotspot/cpu/x86/continuationFreezeThaw_x86.inline.hpp
@@ -63,18 +63,24 @@
   address sender_pc = (address) *(sender_sp-1);
   assert(sender_sp != f.sp(), "must have changed");
 
   int slot = 0;
   CodeBlob* sender_cb = CodeCache::find_blob_and_oopmap(sender_pc, slot);
+
+  // Repair the sender sp if the frame has been extended
+  if (sender_cb->is_nmethod()) {
+    sender_sp = f.repair_sender_sp(sender_sp, link_addr);
+  }
+
   return sender_cb != nullptr
     ? frame(sender_sp, sender_sp, *link_addr, sender_pc, sender_cb,
             slot == -1 ? nullptr : sender_cb->oop_map_for_slot(slot, sender_pc), false)
     : frame(sender_sp, sender_sp, *link_addr, sender_pc);
 }
 
 template<typename FKind>
-frame FreezeBase::new_heap_frame(frame& f, frame& caller) {
+frame FreezeBase::new_heap_frame(frame& f, frame& caller, int size_adjust) {
   assert(FKind::is_instance(f), "");
   assert(!caller.is_interpreted_frame()
     || caller.unextended_sp() == (intptr_t*)caller.at(frame::interpreter_frame_last_sp_offset), "");
 
   intptr_t *sp, *fp; // sp is really our unextended_sp
@@ -101,12 +107,12 @@
     // We need to re-read fp out of the frame because it may be an oop and we might have
     // had a safepoint in finalize_freeze, after constructing f.
     fp = *(intptr_t**)(f.sp() - frame::sender_sp_offset);
 
     int fsize = FKind::size(f);
-    sp = caller.unextended_sp() - fsize;
-    if (caller.is_interpreted_frame()) {
+    sp = caller.unextended_sp() - fsize - size_adjust;
+    if (caller.is_interpreted_frame() && size_adjust == 0) {
       // If the caller is interpreted, our stackargs are not supposed to overlap with it
       // so we make more room by moving sp down by argsize
       int argsize = FKind::stack_argsize(f);
       sp -= argsize;
     }
@@ -169,15 +175,16 @@
   *fp_addr = hf.is_interpreted_frame() ? (intptr_t)(hf.fp() - fp_addr)
                                        : (intptr_t)hf.fp();
   assert(frame_pc == ContinuationHelper::Frame::real_pc(hf), "");
 }
 
-inline void FreezeBase::patch_pd(frame& hf, const frame& caller) {
+inline void FreezeBase::patch_pd(frame& hf, const frame& caller, bool is_bottom_frame) {
   if (caller.is_interpreted_frame()) {
     assert(!caller.is_empty(), "");
     patch_callee_link_relative(caller, caller.fp());
-  } else {
+  } else if (is_bottom_frame && caller.pc() != nullptr) {
+    assert(caller.is_compiled_frame(), "");
     // If we're the bottom-most frame frozen in this freeze, the caller might have stayed frozen in the chunk,
     // and its oop-containing fp fixed. We've now just overwritten it, so we must patch it back to its value
     // as read from the chunk.
     patch_callee_link(caller, caller.fp());
   }
@@ -204,11 +211,11 @@
 inline frame ThawBase::new_entry_frame() {
   intptr_t* sp = _cont.entrySP();
   return frame(sp, sp, _cont.entryFP(), _cont.entryPC()); // TODO PERF: This finds code blob and computes deopt state
 }
 
-template<typename FKind> frame ThawBase::new_stack_frame(const frame& hf, frame& caller, bool bottom) {
+template<typename FKind> frame ThawBase::new_stack_frame(const frame& hf, frame& caller, bool bottom, int size_adjust) {
   assert(FKind::is_instance(hf), "");
   // The values in the returned frame object will be written into the callee's stack in patch.
 
   if (FKind::interpreted) {
     intptr_t* heap_sp = hf.unextended_sp();
@@ -231,28 +238,27 @@
     // copy relativized locals from the heap frame
     *f.addr_at(frame::interpreter_frame_locals_offset) = locals_offset;
     return f;
   } else {
     int fsize = FKind::size(hf);
-    intptr_t* frame_sp = caller.unextended_sp() - fsize;
+    intptr_t* frame_sp = caller.unextended_sp() - fsize - size_adjust;
     if (bottom || caller.is_interpreted_frame()) {
-      int argsize = FKind::stack_argsize(hf);
-
-      fsize += argsize;
-      frame_sp   -= argsize;
-      caller.set_sp(caller.sp() - argsize);
-      assert(caller.sp() == frame_sp + (fsize-argsize), "");
-
+      if (size_adjust == 0) {
+        int argsize = FKind::stack_argsize(hf);
+        frame_sp -= argsize;
+      }
       frame_sp = align(hf, frame_sp, caller, bottom);
     }
+    caller.set_sp(frame_sp + fsize);
+    assert(is_aligned(frame_sp, frame::frame_alignment), "");
 
     assert(hf.cb() != nullptr, "");
     assert(hf.oop_map() != nullptr, "");
     intptr_t* fp;
     if (PreserveFramePointer) {
       // we need to recreate a "real" frame pointer, pointing into the stack
-      fp = frame_sp + FKind::size(hf) - frame::sender_sp_offset;
+      fp = frame_sp + fsize - frame::sender_sp_offset;
     } else {
       fp = FKind::stub || FKind::native
         ? frame_sp + fsize - frame::sender_sp_offset // fp always points to the address below the pushed return pc. We need correct address.
         : *(intptr_t**)(hf.sp() - frame::sender_sp_offset); // we need to re-read fp because it may be an oop and we might have fixed the frame.
     }
@@ -262,18 +268,19 @@
 
 inline intptr_t* ThawBase::align(const frame& hf, intptr_t* frame_sp, frame& caller, bool bottom) {
   if (((intptr_t)frame_sp & 0xf) != 0) {
     assert(caller.is_interpreted_frame() || (bottom && hf.compiled_frame_stack_argsize() % 2 != 0), "");
     frame_sp--;
-    caller.set_sp(caller.sp() - 1);
   }
   assert(is_aligned(frame_sp, frame::frame_alignment), "");
   return frame_sp;
 }
 
 inline void ThawBase::patch_pd(frame& f, const frame& caller) {
-  patch_callee_link(caller, caller.fp());
+  if (caller.is_interpreted_frame() || PreserveFramePointer) {
+    patch_callee_link(caller, caller.fp());
+  }
 }
 
 inline void ThawBase::patch_pd(frame& f, intptr_t* caller_sp) {
   intptr_t* fp = caller_sp - frame::sender_sp_offset;
   patch_callee_link(f, fp);
