8224827: Implement fast class initialization checks on s390
Reviewed-by: vlivanov, gromero
This commit is contained in:
parent
460b4197c4
commit
3eaf9567b4
@ -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() {
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
//---------------------------------------------------------------
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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; }
|
||||
|
Loading…
x
Reference in New Issue
Block a user