< prev index next > src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp
Print this page
// 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);
} else {
// template code (for LM_LEGACY):
//
// markWord displaced_header = obj->mark().set_unlocked();
// monitor->lock()->set_displaced_header(displaced_header);
// 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_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);
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;
assert_different_registers(header, object_mark_addr, current_header, tmp);
// markWord displaced_header = obj->mark().set_unlocked();
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, slow_case, cas_failed;
assert_different_registers(header, object_mark_addr, current_header, tmp);
// markWord displaced_header = obj->mark().set_unlocked();
bne(CCR0, slow_case);
}
if (LockingMode == LM_LIGHTWEIGHT) {
lightweight_lock(monitor, object, header, tmp, slow_case);
! b(count_locking);
} 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).
bne(CCR0, slow_case);
}
if (LockingMode == LM_LIGHTWEIGHT) {
lightweight_lock(monitor, object, header, tmp, slow_case);
! 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).
// 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);
// }
! 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.
// 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_preemptable(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), monitor);
// }
!
! 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.
// 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*/);
bind(done);
}
}
// Load compiled (i2c) or interpreter entry when calling from interpreted and
// Exchange worked, do monitor->set_obj(nullptr);
align(32, 12);
bind(free_slot);
li(R0, 0);
std(R0, in_bytes(BasicObjectLock::obj_offset()), monitor);
! if (LockingMode == LM_LEGACY) {
+ dec_held_monitor_count(current_header /*tmp*/);
+ }
bind(done);
}
}
// Load compiled (i2c) or interpreter entry when calling from interpreted and
align(32, 12);
bind(Ldone);
}
! void InterpreterMacroAssembler::call_VM(Register oop_result, address entry_point, bool check_exceptions) {
save_interpreter_state(R11_scratch1);
! MacroAssembler::call_VM(oop_result, entry_point, false);
restore_interpreter_state(R11_scratch1, /*bcp_and_mdx_only*/ true);
check_and_handle_popframe(R11_scratch1);
check_and_handle_earlyret(R11_scratch1);
align(32, 12);
bind(Ldone);
}
! 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 /*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);
// 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);
< prev index next >