8224827: Implement fast class initialization checks on s390

Reviewed-by: vlivanov, gromero
This commit is contained in:
Martin Doerr 2019-06-12 14:22:04 +02:00
parent 460b4197c4
commit 3eaf9567b4
9 changed files with 141 additions and 11 deletions

View File

@ -82,7 +82,18 @@ int LIR_Assembler::check_icache() {
}
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 = Z_R1_scratch;
metadata2reg(method->holder()->constant_encoding(), klass);
__ clinit_barrier(klass, Z_thread, &L_skip_barrier /*L_fast_path*/);
__ load_const_optimized(klass, SharedRuntime::get_handle_wrong_method_stub());
__ z_br(klass);
__ bind(L_skip_barrier);
}
void LIR_Assembler::osr_entry() {

View File

@ -414,6 +414,19 @@ void InterpreterMacroAssembler::get_cache_entry_pointer_at_bcp(Register cache,
BLOCK_COMMENT("}");
}
void InterpreterMacroAssembler::load_resolved_method_at_index(int byte_no,
Register cache,
Register cpe_offset,
Register method) {
const int method_offset = in_bytes(
ConstantPoolCache::base_offset() +
((byte_no == TemplateTable::f2_byte)
? ConstantPoolCacheEntry::f2_offset()
: ConstantPoolCacheEntry::f1_offset()));
z_lg(method, Address(cache, cpe_offset, method_offset)); // get f1 Method*
}
// Generate a subtype check: branch to ok_is_subtype if sub_klass is
// a subtype of super_klass. Blows registers Rsuper_klass, Rsub_klass, tmp1, tmp2.
void InterpreterMacroAssembler::gen_subtype_check(Register Rsub_klass,

View File

@ -120,6 +120,8 @@ class InterpreterMacroAssembler: public MacroAssembler {
// load cpool->resolved_klass_at(index)
void load_resolved_klass_at_offset(Register cpool, Register offset, Register iklass);
void load_resolved_method_at_index(int byte_no, Register cache, Register cpe_offset, Register method);
// Pop topmost element from stack. It just disappears. Useful if
// consumed previously by access via stackTop().
void popx(int len);

View File

@ -3130,6 +3130,33 @@ void MacroAssembler::check_klass_subtype(Register sub_klass,
BLOCK_COMMENT("} check_klass_subtype");
}
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
z_cli(Address(klass, InstanceKlass::init_state_offset()), InstanceKlass::fully_initialized);
z_bre(*L_fast_path);
// Fast path check: current thread is initializer thread
z_cg(thread, Address(klass, InstanceKlass::init_thread_offset()));
if (L_slow_path == &L_fallthrough) {
z_bre(*L_fast_path);
} else if (L_fast_path == &L_fallthrough) {
z_brne(*L_slow_path);
} else {
Unimplemented();
}
bind(L_fallthrough);
}
// Increment a counter at counter_address when the eq condition code is
// set. Kills registers tmp1_reg and tmp2_reg and preserves the condition code.
void MacroAssembler::increment_counter_eq(address counter_address, Register tmp1_reg, Register tmp2_reg) {
@ -4346,6 +4373,12 @@ void MacroAssembler::load_mirror_from_const_method(Register mirror, Register con
resolve_oop_handle(mirror);
}
void MacroAssembler::load_method_holder(Register holder, Register method) {
mem2reg_opt(holder, Address(method, Method::const_offset()));
mem2reg_opt(holder, Address(holder, ConstMethod::constants_offset()));
mem2reg_opt(holder, Address(holder, ConstantPool::pool_holder_offset_in_bytes()));
}
//---------------------------------------------------------------
//--- Operations on arrays.
//---------------------------------------------------------------

View File

@ -713,6 +713,11 @@ class MacroAssembler: public Assembler {
Register temp2_reg,
Label& L_success);
void clinit_barrier(Register klass,
Register thread,
Label* L_fast_path = NULL,
Label* L_slow_path = NULL);
// Increment a counter at counter_address when the eq condition code is set.
// Kills registers tmp1_reg and tmp2_reg and preserves the condition code.
void increment_counter_eq(address counter_address, Register tmp1_reg, Register tmp2_reg);
@ -824,6 +829,7 @@ class MacroAssembler: public Assembler {
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);
//--------------------------
//--- Operations on arrays.

View File

@ -867,6 +867,23 @@ void MachPrologNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
assert(framesize % wordSize == 0, "must preserve wordSize alignment");
if (C->clinit_barrier_on_entry()) {
assert(!C->method()->holder()->is_not_initialized(), "initialization should have been started");
Label L_skip_barrier;
Register klass = Z_R1_scratch;
// Notify OOP recorder (don't need the relocation)
AddressLiteral md = __ constant_metadata_address(C->method()->holder()->constant_encoding());
__ load_const_optimized(klass, md.value());
__ clinit_barrier(klass, Z_thread, &L_skip_barrier /*L_fast_path*/);
__ load_const_optimized(klass, SharedRuntime::get_handle_wrong_method_stub());
__ z_br(klass);
__ 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

View File

@ -1832,6 +1832,20 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm,
//---------------------------------------------------------------------
wrapper_VEPStart = __ offset();
if (VM_Version::supports_fast_class_init_checks() && method->needs_clinit_barrier()) {
Label L_skip_barrier;
Register klass = Z_R1_scratch;
// Notify OOP recorder (don't need the relocation)
AddressLiteral md = __ constant_metadata_address(method->method_holder());
__ load_const_optimized(klass, md.value());
__ clinit_barrier(klass, Z_thread, &L_skip_barrier /*L_fast_path*/);
__ load_const_optimized(klass, SharedRuntime::get_handle_wrong_method_stub());
__ z_br(klass);
__ bind(L_skip_barrier);
}
__ save_return_pc();
__ generate_stack_overflow_check(frame_size_in_bytes); // Check before creating frame.
#ifndef USE_RESIZE_FRAME
@ -2696,8 +2710,28 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm
// Fallthru to VEP. Duplicate LTG, but saved taken branch.
}
address c2i_entry;
c2i_entry = gen_c2i_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs, skip_fixup);
address 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
__ testbit(Address(Z_method, Method::access_flags_offset()), JVM_ACC_STATIC_BIT);
__ z_bfalse(L_skip_barrier); // non-static
}
Register klass = Z_R11;
__ load_method_holder(klass, Z_method);
__ clinit_barrier(klass, Z_thread, &L_skip_barrier /*L_fast_path*/);
__ load_const_optimized(klass, SharedRuntime::get_handle_wrong_method_stub());
__ z_br(klass);
__ bind(L_skip_barrier);
}
gen_c2i_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs, skip_fixup);
return AdapterHandlerLibrary::new_entry(fingerprint, i2c_entry, c2i_entry, c2i_unverified_entry);
}

View File

@ -2404,14 +2404,14 @@ void TemplateTable::_return(TosState state) {
// NOTE: Cpe_offset is already computed as byte offset, so we must not
// shift it afterwards!
void TemplateTable::resolve_cache_and_index(int byte_no,
Register Rcache,
Register cache,
Register cpe_offset,
size_t index_size) {
BLOCK_COMMENT("resolve_cache_and_index {");
NearLabel resolved;
NearLabel resolved, clinit_barrier_slow;
const Register bytecode_in_cpcache = Z_R1_scratch;
const int total_f1_offset = in_bytes(ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::f1_offset());
assert_different_registers(Rcache, cpe_offset, bytecode_in_cpcache);
assert_different_registers(cache, cpe_offset, bytecode_in_cpcache);
Bytecodes::Code code = bytecode();
switch (code) {
@ -2423,19 +2423,32 @@ void TemplateTable::resolve_cache_and_index(int byte_no,
{
assert(byte_no == f1_byte || byte_no == f2_byte, "byte_no out of range");
__ get_cache_and_index_and_bytecode_at_bcp(Rcache, cpe_offset, bytecode_in_cpcache, byte_no, 1, index_size);
__ get_cache_and_index_and_bytecode_at_bcp(cache, cpe_offset, bytecode_in_cpcache, byte_no, 1, index_size);
// Have we resolved this bytecode?
__ compare32_and_branch(bytecode_in_cpcache, (int)code, Assembler::bcondEqual, resolved);
}
// Resolve first time through.
// Class initialization barrier slow path lands here as well.
__ bind(clinit_barrier_slow);
address entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_from_cache);
__ load_const_optimized(Z_ARG2, (int) code);
__ call_VM(noreg, entry, Z_ARG2);
// Update registers with resolved info.
__ get_cache_and_index_at_bcp(Rcache, cpe_offset, 1, index_size);
__ get_cache_and_index_at_bcp(cache, cpe_offset, 1, index_size);
__ bind(resolved);
// Class initialization barrier for static methods
if (VM_Version::supports_fast_class_init_checks() && bytecode() == Bytecodes::_invokestatic) {
const Register method = Z_R1_scratch;
const Register klass = Z_R1_scratch;
__ load_resolved_method_at_index(byte_no, cache, cpe_offset, method);
__ load_method_holder(klass, method);
__ clinit_barrier(klass, Z_thread, NULL /*L_fast_path*/, &clinit_barrier_slow);
}
BLOCK_COMMENT("} resolve_cache_and_index");
}
@ -3664,9 +3677,7 @@ void TemplateTable::invokeinterface(int byte_no) {
// Find entry point to call.
// Get declaring interface class from method
__ z_lg(interface, Address(method, Method::const_offset()));
__ z_lg(interface, Address(interface, ConstMethod::constants_offset()));
__ z_lg(interface, Address(interface, ConstantPool::pool_holder_offset_in_bytes()));
__ load_method_holder(interface, method);
// Get itable index from method
Register index = receiver,

View File

@ -349,6 +349,9 @@ class VM_Version: public Abstract_VM_Version {
// Override Abstract_VM_Version implementation
static void print_platform_virtualization_info(outputStream*);
// s390 supports fast class initialization checks for static methods.
static bool supports_fast_class_init_checks() { return true; }
// CPU feature query functions
static const char* get_model_string() { return _model_string; }
static bool has_StoreFacilityListExtended() { return (_features[0] & StoreFacilityListExtendedMask) == StoreFacilityListExtendedMask; }