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) {
|
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() {
|
void LIR_Assembler::osr_entry() {
|
||||||
|
@ -414,6 +414,19 @@ void InterpreterMacroAssembler::get_cache_entry_pointer_at_bcp(Register cache,
|
|||||||
BLOCK_COMMENT("}");
|
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
|
// 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.
|
// a subtype of super_klass. Blows registers Rsuper_klass, Rsub_klass, tmp1, tmp2.
|
||||||
void InterpreterMacroAssembler::gen_subtype_check(Register Rsub_klass,
|
void InterpreterMacroAssembler::gen_subtype_check(Register Rsub_klass,
|
||||||
|
@ -120,6 +120,8 @@ class InterpreterMacroAssembler: public MacroAssembler {
|
|||||||
// load cpool->resolved_klass_at(index)
|
// load cpool->resolved_klass_at(index)
|
||||||
void load_resolved_klass_at_offset(Register cpool, Register offset, Register iklass);
|
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
|
// Pop topmost element from stack. It just disappears. Useful if
|
||||||
// consumed previously by access via stackTop().
|
// consumed previously by access via stackTop().
|
||||||
void popx(int len);
|
void popx(int len);
|
||||||
|
@ -3130,6 +3130,33 @@ void MacroAssembler::check_klass_subtype(Register sub_klass,
|
|||||||
BLOCK_COMMENT("} check_klass_subtype");
|
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
|
// 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.
|
// 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) {
|
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);
|
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.
|
//--- Operations on arrays.
|
||||||
//---------------------------------------------------------------
|
//---------------------------------------------------------------
|
||||||
|
@ -713,6 +713,11 @@ class MacroAssembler: public Assembler {
|
|||||||
Register temp2_reg,
|
Register temp2_reg,
|
||||||
Label& L_success);
|
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.
|
// 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.
|
// 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);
|
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 resolve_oop_handle(Register result);
|
||||||
void load_mirror_from_const_method(Register mirror, Register const_method);
|
void load_mirror_from_const_method(Register mirror, Register const_method);
|
||||||
|
void load_method_holder(Register holder, Register method);
|
||||||
|
|
||||||
//--------------------------
|
//--------------------------
|
||||||
//--- Operations on arrays.
|
//--- Operations on arrays.
|
||||||
|
@ -867,6 +867,23 @@ void MachPrologNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
|
|||||||
|
|
||||||
assert(framesize % wordSize == 0, "must preserve wordSize alignment");
|
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.
|
// Calls to C2R adapters often do not accept exceptional returns.
|
||||||
// We require that their callers must bang for them. But be
|
// We require that their callers must bang for them. But be
|
||||||
// careful, because some VM calls (such as call site linkage) can
|
// 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();
|
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();
|
__ save_return_pc();
|
||||||
__ generate_stack_overflow_check(frame_size_in_bytes); // Check before creating frame.
|
__ generate_stack_overflow_check(frame_size_in_bytes); // Check before creating frame.
|
||||||
#ifndef USE_RESIZE_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.
|
// Fallthru to VEP. Duplicate LTG, but saved taken branch.
|
||||||
}
|
}
|
||||||
|
|
||||||
address c2i_entry;
|
address c2i_entry = __ pc();
|
||||||
c2i_entry = gen_c2i_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs, skip_fixup);
|
|
||||||
|
// 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);
|
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
|
// NOTE: Cpe_offset is already computed as byte offset, so we must not
|
||||||
// shift it afterwards!
|
// shift it afterwards!
|
||||||
void TemplateTable::resolve_cache_and_index(int byte_no,
|
void TemplateTable::resolve_cache_and_index(int byte_no,
|
||||||
Register Rcache,
|
Register cache,
|
||||||
Register cpe_offset,
|
Register cpe_offset,
|
||||||
size_t index_size) {
|
size_t index_size) {
|
||||||
BLOCK_COMMENT("resolve_cache_and_index {");
|
BLOCK_COMMENT("resolve_cache_and_index {");
|
||||||
NearLabel resolved;
|
NearLabel resolved, clinit_barrier_slow;
|
||||||
const Register bytecode_in_cpcache = Z_R1_scratch;
|
const Register bytecode_in_cpcache = Z_R1_scratch;
|
||||||
const int total_f1_offset = in_bytes(ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::f1_offset());
|
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();
|
Bytecodes::Code code = bytecode();
|
||||||
switch (code) {
|
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");
|
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?
|
// Have we resolved this bytecode?
|
||||||
__ compare32_and_branch(bytecode_in_cpcache, (int)code, Assembler::bcondEqual, resolved);
|
__ compare32_and_branch(bytecode_in_cpcache, (int)code, Assembler::bcondEqual, resolved);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resolve first time through.
|
// 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);
|
address entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_from_cache);
|
||||||
__ load_const_optimized(Z_ARG2, (int) code);
|
__ load_const_optimized(Z_ARG2, (int) code);
|
||||||
__ call_VM(noreg, entry, Z_ARG2);
|
__ call_VM(noreg, entry, Z_ARG2);
|
||||||
|
|
||||||
// Update registers with resolved info.
|
// 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);
|
__ 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");
|
BLOCK_COMMENT("} resolve_cache_and_index");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3664,9 +3677,7 @@ void TemplateTable::invokeinterface(int byte_no) {
|
|||||||
// Find entry point to call.
|
// Find entry point to call.
|
||||||
|
|
||||||
// Get declaring interface class from method
|
// Get declaring interface class from method
|
||||||
__ z_lg(interface, Address(method, Method::const_offset()));
|
__ load_method_holder(interface, method);
|
||||||
__ z_lg(interface, Address(interface, ConstMethod::constants_offset()));
|
|
||||||
__ z_lg(interface, Address(interface, ConstantPool::pool_holder_offset_in_bytes()));
|
|
||||||
|
|
||||||
// Get itable index from method
|
// Get itable index from method
|
||||||
Register index = receiver,
|
Register index = receiver,
|
||||||
|
@ -349,6 +349,9 @@ class VM_Version: public Abstract_VM_Version {
|
|||||||
// Override Abstract_VM_Version implementation
|
// Override Abstract_VM_Version implementation
|
||||||
static void print_platform_virtualization_info(outputStream*);
|
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
|
// CPU feature query functions
|
||||||
static const char* get_model_string() { return _model_string; }
|
static const char* get_model_string() { return _model_string; }
|
||||||
static bool has_StoreFacilityListExtended() { return (_features[0] & StoreFacilityListExtendedMask) == StoreFacilityListExtendedMask; }
|
static bool has_StoreFacilityListExtended() { return (_features[0] & StoreFacilityListExtendedMask) == StoreFacilityListExtendedMask; }
|
||||||
|
Loading…
x
Reference in New Issue
Block a user