8224826: Implement fast class initialization checks on PPC64
Reviewed-by: vlivanov, gromero
--- a/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp Tue Jun 11 09:27:51 2019 +0200
+++ b/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp Tue Jun 11 09:51:33 2019 +0200
@@ -80,7 +80,19 @@
}
void LIR_Assembler::clinit_barrier(ciMethod* method) {
- ShouldNotReachHere(); // not implemented
+ assert(!method->holder()->is_not_initialized(), "initialization should have been started");
+
+ Label L_skip_barrier;
+ Register klass = R20;
+
+ metadata2reg(method->holder()->constant_encoding(), klass);
+ __ clinit_barrier(klass, R16_thread, &L_skip_barrier /*L_fast_path*/);
+
+ __ load_const_optimized(klass, SharedRuntime::get_handle_wrong_method_stub(), R0);
+ __ mtctr(klass);
+ __ bctr();
+
+ __ bind(L_skip_barrier);
}
void LIR_Assembler::osr_entry() {
--- a/src/hotspot/cpu/ppc/interp_masm_ppc.hpp Tue Jun 11 09:27:51 2019 +0200
+++ b/src/hotspot/cpu/ppc/interp_masm_ppc.hpp Tue Jun 11 09:51:33 2019 +0200
@@ -82,6 +82,8 @@
// load cpool->resolved_klass_at(index)
void load_resolved_klass_at_offset(Register Rcpool, Register Roffset, Register Rklass);
+ void load_resolved_method_at_index(int byte_no, Register cache, Register method);
+
void load_receiver(Register Rparam_count, Register Rrecv_dst);
// helpers for expression stack
--- a/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp Tue Jun 11 09:27:51 2019 +0200
+++ b/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp Tue Jun 11 09:51:33 2019 +0200
@@ -516,6 +516,18 @@
ldx(Rklass, Rklass, Roffset);
}
+void InterpreterMacroAssembler::load_resolved_method_at_index(int byte_no,
+ Register cache,
+ Register method) {
+ const int method_offset = in_bytes(
+ ConstantPoolCache::base_offset() +
+ ((byte_no == TemplateTable::f2_byte)
+ ? ConstantPoolCacheEntry::f2_offset()
+ : ConstantPoolCacheEntry::f1_offset()));
+
+ ld(method, method_offset, cache); // get f1 Method*
+}
+
// Generate a subtype check: branch to ok_is_subtype if sub_klass is
// a subtype of super_klass. Blows registers Rsub_klass, tmp1, tmp2.
void InterpreterMacroAssembler::gen_subtype_check(Register Rsub_klass, Register Rsuper_klass, Register Rtmp1,
--- a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp Tue Jun 11 09:27:51 2019 +0200
+++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp Tue Jun 11 09:51:33 2019 +0200
@@ -2011,6 +2011,35 @@
bind(L_failure); // Fallthru if not successful.
}
+void MacroAssembler::clinit_barrier(Register klass, Register thread, Label* L_fast_path, Label* L_slow_path) {
+ assert(L_fast_path != NULL || L_slow_path != NULL, "at least one is required");
+
+ Label L_fallthrough;
+ if (L_fast_path == NULL) {
+ L_fast_path = &L_fallthrough;
+ } else if (L_slow_path == NULL) {
+ L_slow_path = &L_fallthrough;
+ }
+
+ // Fast path check: class is fully initialized
+ lbz(R0, in_bytes(InstanceKlass::init_state_offset()), klass);
+ cmpwi(CCR0, R0, InstanceKlass::fully_initialized);
+ beq(CCR0, *L_fast_path);
+
+ // Fast path check: current thread is initializer thread
+ ld(R0, in_bytes(InstanceKlass::init_thread_offset()), klass);
+ cmpd(CCR0, thread, R0);
+ if (L_slow_path == &L_fallthrough) {
+ beq(CCR0, *L_fast_path);
+ } else if (L_fast_path == &L_fallthrough) {
+ bne(CCR0, *L_slow_path);
+ } else {
+ Unimplemented();
+ }
+
+ bind(L_fallthrough);
+}
+
void MacroAssembler::check_method_handle_type(Register mtype_reg, Register mh_reg,
Register temp_reg,
Label& wrong_method_type) {
@@ -3194,6 +3223,12 @@
resolve_oop_handle(mirror);
}
+void MacroAssembler::load_method_holder(Register holder, Register method) {
+ ld(holder, in_bytes(Method::const_offset()), method);
+ ld(holder, in_bytes(ConstMethod::constants_offset()), holder);
+ ld(holder, ConstantPool::pool_holder_offset_in_bytes(), holder);
+}
+
// Clear Array
// For very short arrays. tmp == R0 is allowed.
void MacroAssembler::clear_memory_unrolled(Register base_ptr, int cnt_dwords, Register tmp, int offset) {
--- a/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp Tue Jun 11 09:27:51 2019 +0200
+++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp Tue Jun 11 09:51:33 2019 +0200
@@ -559,6 +559,11 @@
Register temp2_reg,
Label& L_success);
+ void clinit_barrier(Register klass,
+ Register thread,
+ Label* L_fast_path = NULL,
+ Label* L_slow_path = NULL);
+
// Method handle support (JSR 292).
void check_method_handle_type(Register mtype_reg, Register mh_reg, Register temp_reg, Label& wrong_method_type);
@@ -722,6 +727,7 @@
void resolve_oop_handle(Register result);
void load_mirror_from_const_method(Register mirror, Register const_method);
+ void load_method_holder(Register holder, Register method);
static int instr_size_for_decode_klass_not_null();
void decode_klass_not_null(Register dst, Register src = noreg);
--- a/src/hotspot/cpu/ppc/ppc.ad Tue Jun 11 09:27:51 2019 +0200
+++ b/src/hotspot/cpu/ppc/ppc.ad Tue Jun 11 09:51:33 2019 +0200
@@ -1400,6 +1400,24 @@
___(mflr) mflr(return_pc);
}
+ if (C->clinit_barrier_on_entry()) {
+ assert(!C->method()->holder()->is_not_initialized(), "initialization should have been started");
+
+ Label L_skip_barrier;
+ Register klass = toc_temp;
+
+ // Notify OOP recorder (don't need the relocation)
+ AddressLiteral md = __ constant_metadata_address(C->method()->holder()->constant_encoding());
+ __ load_const_optimized(klass, md.value(), R0);
+ __ clinit_barrier(klass, R16_thread, &L_skip_barrier /*L_fast_path*/);
+
+ __ load_const_optimized(klass, SharedRuntime::get_handle_wrong_method_stub(), R0);
+ __ mtctr(klass);
+ __ bctr();
+
+ __ bind(L_skip_barrier);
+ }
+
// Calls to C2R adapters often do not accept exceptional returns.
// We require that their callers must bang for them. But be
// careful, because some VM calls (such as call site linkage) can
--- a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp Tue Jun 11 09:27:51 2019 +0200
+++ b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp Tue Jun 11 09:51:33 2019 +0200
@@ -1274,7 +1274,30 @@
// entry: c2i
- c2i_entry = gen_c2i_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs, call_interpreter, ientry);
+ c2i_entry = __ pc();
+
+ // Class initialization barrier for static methods
+ if (VM_Version::supports_fast_class_init_checks()) {
+ Label L_skip_barrier;
+
+ { // Bypass the barrier for non-static methods
+ __ lwz(R0, in_bytes(Method::access_flags_offset()), R19_method);
+ __ andi_(R0, R0, JVM_ACC_STATIC);
+ __ beq(CCR0, L_skip_barrier); // non-static
+ }
+
+ Register klass = R11_scratch1;
+ __ load_method_holder(klass, R19_method);
+ __ clinit_barrier(klass, R16_thread, &L_skip_barrier /*L_fast_path*/);
+
+ __ load_const_optimized(klass, SharedRuntime::get_handle_wrong_method_stub(), R0);
+ __ mtctr(klass);
+ __ bctr();
+
+ __ bind(L_skip_barrier);
+ }
+
+ gen_c2i_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs, call_interpreter, ientry);
return AdapterHandlerLibrary::new_entry(fingerprint, i2c_entry, c2i_entry, c2i_unverified_entry);
}
@@ -2106,6 +2129,21 @@
__ tabort_();
}
+ if (VM_Version::supports_fast_class_init_checks() && method->needs_clinit_barrier()) {
+ Label L_skip_barrier;
+ Register klass = r_temp_1;
+ // Notify OOP recorder (don't need the relocation)
+ AddressLiteral md = __ constant_metadata_address(method->method_holder());
+ __ load_const_optimized(klass, md.value(), R0);
+ __ clinit_barrier(klass, R16_thread, &L_skip_barrier /*L_fast_path*/);
+
+ __ load_const_optimized(klass, SharedRuntime::get_handle_wrong_method_stub(), R0);
+ __ mtctr(klass);
+ __ bctr();
+
+ __ bind(L_skip_barrier);
+ }
+
__ save_LR_CR(r_temp_1);
__ generate_stack_overflow_check(frame_size_in_bytes); // Check before creating frame.
__ mr(r_callers_sp, R1_SP); // Remember frame pointer.
--- a/src/hotspot/cpu/ppc/templateTable_ppc_64.cpp Tue Jun 11 09:27:51 2019 +0200
+++ b/src/hotspot/cpu/ppc/templateTable_ppc_64.cpp Tue Jun 11 09:51:33 2019 +0200
@@ -2232,7 +2232,7 @@
void TemplateTable::resolve_cache_and_index(int byte_no, Register Rcache, Register Rscratch, size_t index_size) {
__ get_cache_and_index_at_bcp(Rcache, 1, index_size);
- Label Lresolved, Ldone;
+ Label Lresolved, Ldone, L_clinit_barrier_slow;
Bytecodes::Code code = bytecode();
switch (code) {
@@ -2253,6 +2253,9 @@
__ cmpdi(CCR0, Rscratch, (int)code);
__ beq(CCR0, Lresolved);
+ // Class initialization barrier slow path lands here as well.
+ __ bind(L_clinit_barrier_slow);
+
address entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_from_cache);
__ li(R4_ARG2, code);
__ call_VM(noreg, entry, R4_ARG2, true);
@@ -2263,6 +2266,17 @@
__ bind(Lresolved);
__ isync(); // Order load wrt. succeeding loads.
+
+ // Class initialization barrier for static methods
+ if (VM_Version::supports_fast_class_init_checks() && bytecode() == Bytecodes::_invokestatic) {
+ const Register method = Rscratch;
+ const Register klass = Rscratch;
+
+ __ load_resolved_method_at_index(byte_no, Rcache, method);
+ __ load_method_holder(klass, method);
+ __ clinit_barrier(klass, R16_thread, NULL /*L_fast_path*/, &L_clinit_barrier_slow);
+ }
+
__ bind(Ldone);
}
@@ -2329,7 +2343,7 @@
// Already resolved.
__ get_cache_and_index_at_bcp(Rcache, 1);
} else {
- resolve_cache_and_index(byte_no, Rcache, R0, is_invokedynamic ? sizeof(u4) : sizeof(u2));
+ resolve_cache_and_index(byte_no, Rcache, /* temp */ Rmethod, is_invokedynamic ? sizeof(u4) : sizeof(u2));
}
__ ld(Rmethod, method_offset, Rcache);
@@ -3634,9 +3648,7 @@
// Find entry point to call.
// Get declaring interface class from method
- __ ld(Rinterface_klass, in_bytes(Method::const_offset()), Rmethod);
- __ ld(Rinterface_klass, in_bytes(ConstMethod::constants_offset()), Rinterface_klass);
- __ ld(Rinterface_klass, ConstantPool::pool_holder_offset_in_bytes(), Rinterface_klass);
+ __ load_method_holder(Rinterface_klass, Rmethod);
// Get itable index from method
__ lwa(Rindex, in_bytes(Method::itable_index_offset()), Rmethod);
--- a/src/hotspot/cpu/ppc/vm_version_ppc.hpp Tue Jun 11 09:27:51 2019 +0200
+++ b/src/hotspot/cpu/ppc/vm_version_ppc.hpp Tue Jun 11 09:51:33 2019 +0200
@@ -95,6 +95,9 @@
// Override Abstract_VM_Version implementation
static bool use_biased_locking();
+ // PPC64 supports fast class initialization checks for static methods.
+ static bool supports_fast_class_init_checks() { return true; }
+
static bool is_determine_features_test_running() { return _is_determine_features_test_running; }
// CPU instruction support
static bool has_fsqrt() { return (_features & fsqrt_m) != 0; }