diff a/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp b/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp
--- a/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp
+++ b/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp
@@ -930,11 +930,11 @@
 //             which must be initialized with the object to lock.
 //   object  - Address of the object to be locked.
 //
 void InterpreterMacroAssembler::lock_object(Register monitor, Register object) {
   if (LockingMode == LM_MONITOR) {
-    call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), monitor);
+    call_VM_preemptable(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), monitor);
   } else {
     // template code (for LM_LEGACY):
     //
     // markWord displaced_header = obj->mark().set_unlocked();
     // monitor->lock()->set_displaced_header(displaced_header);
@@ -951,12 +951,11 @@
     const Register header           = R7_ARG5;
     const Register object_mark_addr = R8_ARG6;
     const Register current_header   = R9_ARG7;
     const Register tmp              = R10_ARG8;
 
-    Label count_locking, done;
-    Label cas_failed, slow_case;
+    Label count_locking, done, slow_case, cas_failed;
 
     assert_different_registers(header, object_mark_addr, current_header, tmp);
 
     // markWord displaced_header = obj->mark().set_unlocked();
 
@@ -967,11 +966,11 @@
       bne(CCR0, slow_case);
     }
 
     if (LockingMode == LM_LIGHTWEIGHT) {
       lightweight_lock(monitor, object, header, tmp, slow_case);
-      b(count_locking);
+      b(done);
     } else if (LockingMode == LM_LEGACY) {
       // Load markWord from object into header.
       ld(header, oopDesc::mark_offset_in_bytes(), object);
 
       // Set displaced_header to be (markWord of object | UNLOCK_VALUE).
@@ -1033,16 +1032,19 @@
     //   InterpreterRuntime::monitorenter(THREAD, monitor);
 
     // None of the above fast optimizations worked so we have to get into the
     // slow case of monitor enter.
     bind(slow_case);
-    call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), monitor);
-    b(done);
+    call_VM_preemptable(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), monitor);
     // }
-    align(32, 12);
-    bind(count_locking);
-    inc_held_monitor_count(current_header /*tmp*/);
+
+    if (LockingMode == LM_LEGACY) {
+      b(done);
+      align(32, 12);
+      bind(count_locking);
+      inc_held_monitor_count(current_header /*tmp*/);
+    }
     bind(done);
   }
 }
 
 // Unlocks an object. Used in monitorexit bytecode and remove_activation.
@@ -1135,11 +1137,13 @@
     // Exchange worked, do monitor->set_obj(nullptr);
     align(32, 12);
     bind(free_slot);
     li(R0, 0);
     std(R0, in_bytes(BasicObjectLock::obj_offset()), monitor);
-    dec_held_monitor_count(current_header /*tmp*/);
+    if (LockingMode == LM_LEGACY) {
+      dec_held_monitor_count(current_header /*tmp*/);
+    }
     bind(done);
   }
 }
 
 // Load compiled (i2c) or interpreter entry when calling from interpreted and
@@ -2131,14 +2135,14 @@
 
   align(32, 12);
   bind(Ldone);
 }
 
-void InterpreterMacroAssembler::call_VM(Register oop_result, address entry_point, bool check_exceptions) {
+void InterpreterMacroAssembler::call_VM(Register oop_result, address entry_point, bool check_exceptions, Label* last_java_pc) {
   save_interpreter_state(R11_scratch1);
 
-  MacroAssembler::call_VM(oop_result, entry_point, false);
+  MacroAssembler::call_VM(oop_result, entry_point, false /*check_exceptions*/, last_java_pc);
 
   restore_interpreter_state(R11_scratch1, /*bcp_and_mdx_only*/ true);
 
   check_and_handle_popframe(R11_scratch1);
   check_and_handle_earlyret(R11_scratch1);
@@ -2153,10 +2157,78 @@
   // ARG1 is reserved for the thread.
   mr_if_needed(R4_ARG2, arg_1);
   call_VM(oop_result, entry_point, check_exceptions);
 }
 
+void InterpreterMacroAssembler::call_VM_preemptable(Register oop_result, address entry_point,
+                                        Register arg_1, bool check_exceptions) {
+  if (!Continuations::enabled()) {
+    call_VM(oop_result, entry_point, arg_1, check_exceptions);
+    return;
+  }
+
+  Label resume_pc, not_preempted;
+
+  DEBUG_ONLY(ld(R0, in_bytes(JavaThread::preempt_alternate_return_offset()), R16_thread));
+  DEBUG_ONLY(cmpdi(CCR0, R0, 0));
+  asm_assert_eq("Should not have alternate return address set");
+
+  // Preserve 2 registers
+  assert(nonvolatile_accross_vthread_preemtion(R31) && nonvolatile_accross_vthread_preemtion(R22), "");
+  ld(R3_ARG1, _abi0(callers_sp), R1_SP); // load FP
+  std(R31, _ijava_state_neg(lresult), R3_ARG1);
+  std(R22, _ijava_state_neg(fresult), R3_ARG1);
+
+  // We set resume_pc as last java pc. It will be saved if the vthread gets preempted.
+  // Later execution will continue right there.
+  mr_if_needed(R4_ARG2, arg_1);
+  push_cont_fastpath();
+  call_VM(oop_result, entry_point, false /*check_exceptions*/, &resume_pc /* last_java_pc */);
+  pop_cont_fastpath();
+
+  // Jump to handler if the call was preempted
+  ld(R0, in_bytes(JavaThread::preempt_alternate_return_offset()), R16_thread);
+  cmpdi(CCR0, R0, 0);
+  beq(CCR0, not_preempted);
+  mtlr(R0);
+  li(R0, 0);
+  std(R0, in_bytes(JavaThread::preempt_alternate_return_offset()), R16_thread);
+  blr();
+
+  bind(resume_pc); // Location to resume execution
+  restore_after_resume(noreg /* fp */);
+  bind(not_preempted);
+}
+
+void InterpreterMacroAssembler::restore_after_resume(Register fp) {
+  if (!Continuations::enabled()) return;
+
+  const address resume_adapter = TemplateInterpreter::cont_resume_interpreter_adapter();
+  add_const_optimized(R31, R29_TOC, MacroAssembler::offset_to_global_toc(resume_adapter));
+  mtctr(R31);
+  bctrl();
+  // Restore registers that are preserved across vthread preemption
+  assert(nonvolatile_accross_vthread_preemtion(R31) && nonvolatile_accross_vthread_preemtion(R22), "");
+  ld(R3_ARG1, _abi0(callers_sp), R1_SP); // load FP
+  ld(R31, _ijava_state_neg(lresult), R3_ARG1);
+  ld(R22, _ijava_state_neg(fresult), R3_ARG1);
+#ifdef ASSERT
+  // Assert FP is in R11_scratch1 (see generate_cont_resume_interpreter_adapter())
+  {
+    Label ok;
+    ld(R12_scratch2, 0, R1_SP);  // load fp
+    cmpd(CCR0, R12_scratch2, R11_scratch1);
+    beq(CCR0, ok);
+    stop(FILE_AND_LINE ": FP is expected in R11_scratch1");
+    bind(ok);
+  }
+#endif
+  if (fp != noreg && fp != R11_scratch1) {
+    mr(fp, R11_scratch1);
+  }
+}
+
 void InterpreterMacroAssembler::call_VM(Register oop_result, address entry_point,
                                         Register arg_1, Register arg_2,
                                         bool check_exceptions) {
   // ARG1 is reserved for the thread.
   mr_if_needed(R4_ARG2, arg_1);
