# HG changeset patch # User mdoerr # Date 1560239493 -7200 # Node ID bc5baf2054754116cc538741ae97567eb80ba621 # Parent ddda023e6f66d54292d17a060236bbd672d6e4de 8224826: Implement fast class initialization checks on PPC64 Reviewed-by: vlivanov, gromero diff -r ddda023e6f66 -r bc5baf205475 src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp --- 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() { diff -r ddda023e6f66 -r bc5baf205475 src/hotspot/cpu/ppc/interp_masm_ppc.hpp --- 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 diff -r ddda023e6f66 -r bc5baf205475 src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp --- 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, diff -r ddda023e6f66 -r bc5baf205475 src/hotspot/cpu/ppc/macroAssembler_ppc.cpp --- 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) { diff -r ddda023e6f66 -r bc5baf205475 src/hotspot/cpu/ppc/macroAssembler_ppc.hpp --- 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); diff -r ddda023e6f66 -r bc5baf205475 src/hotspot/cpu/ppc/ppc.ad --- 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 diff -r ddda023e6f66 -r bc5baf205475 src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp --- 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. diff -r ddda023e6f66 -r bc5baf205475 src/hotspot/cpu/ppc/templateTable_ppc_64.cpp --- 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); diff -r ddda023e6f66 -r bc5baf205475 src/hotspot/cpu/ppc/vm_version_ppc.hpp --- 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; }