8350209: Preserve adapters in AOT cache
Co-authored-by: Ashutosh Mehra <asmehra@openjdk.org> Reviewed-by: vlivanov, asmehra, ihse, iklam
This commit is contained in:
parent
c116b18b89
commit
aae2bb6249
@ -125,6 +125,7 @@ endif
|
||||
ifneq ($(call check-jvm-feature, cds), true)
|
||||
JVM_CFLAGS_FEATURES += -DINCLUDE_CDS=0
|
||||
JVM_EXCLUDE_FILES += \
|
||||
aotCodeCache.cpp \
|
||||
classLoaderDataShared.cpp \
|
||||
classLoaderExt.cpp \
|
||||
systemDictionaryShared.cpp
|
||||
|
@ -675,6 +675,9 @@ void MacroAssembler::set_last_Java_frame(Register last_java_sp,
|
||||
}
|
||||
|
||||
static inline bool target_needs_far_branch(address addr) {
|
||||
if (AOTCodeCache::is_on_for_dump()) {
|
||||
return true;
|
||||
}
|
||||
// codecache size <= 128M
|
||||
if (!MacroAssembler::far_branches()) {
|
||||
return false;
|
||||
@ -859,6 +862,9 @@ void MacroAssembler::call_VM_helper(Register oop_result, address entry_point, in
|
||||
|
||||
// Check the entry target is always reachable from any branch.
|
||||
static bool is_always_within_branch_range(Address entry) {
|
||||
if (AOTCodeCache::is_on_for_dump()) {
|
||||
return false;
|
||||
}
|
||||
const address target = entry.target();
|
||||
|
||||
if (!CodeCache::contains(target)) {
|
||||
@ -2154,7 +2160,7 @@ void MacroAssembler::call_VM_leaf_base(address entry_point,
|
||||
|
||||
stp(rscratch1, rmethod, Address(pre(sp, -2 * wordSize)));
|
||||
|
||||
mov(rscratch1, entry_point);
|
||||
mov(rscratch1, RuntimeAddress(entry_point));
|
||||
blr(rscratch1);
|
||||
if (retaddr)
|
||||
bind(*retaddr);
|
||||
@ -3231,9 +3237,13 @@ void MacroAssembler::resolve_global_jobject(Register value, Register tmp1, Regis
|
||||
}
|
||||
|
||||
void MacroAssembler::stop(const char* msg) {
|
||||
BLOCK_COMMENT(msg);
|
||||
// Skip AOT caching C strings in scratch buffer.
|
||||
const char* str = (code_section()->scratch_emit()) ? msg : AOTCodeCache::add_C_string(msg);
|
||||
BLOCK_COMMENT(str);
|
||||
// load msg into r0 so we can access it from the signal handler
|
||||
// ExternalAddress enables saving and restoring via the code cache
|
||||
lea(c_rarg0, ExternalAddress((address) str));
|
||||
dcps1(0xdeae);
|
||||
emit_int64((uintptr_t)msg);
|
||||
}
|
||||
|
||||
void MacroAssembler::unimplemented(const char* what) {
|
||||
|
@ -27,6 +27,7 @@
|
||||
#define CPU_AARCH64_MACROASSEMBLER_AARCH64_HPP
|
||||
|
||||
#include "asm/assembler.inline.hpp"
|
||||
#include "code/aotCodeCache.hpp"
|
||||
#include "code/vmreg.hpp"
|
||||
#include "metaprogramming/enableIf.hpp"
|
||||
#include "oops/compressedOops.hpp"
|
||||
@ -1315,6 +1316,10 @@ public:
|
||||
|
||||
// Check if branches to the non nmethod section require a far jump
|
||||
static bool codestub_branch_needs_far_jump() {
|
||||
if (AOTCodeCache::is_on_for_dump()) {
|
||||
// To calculate far_codestub_branch_size correctly.
|
||||
return true;
|
||||
}
|
||||
return CodeCache::max_distance_to_non_nmethod() > branch_range;
|
||||
}
|
||||
|
||||
|
@ -557,40 +557,6 @@ void SharedRuntime::gen_i2c_adapter(MacroAssembler *masm,
|
||||
// If this happens, control eventually transfers back to the compiled
|
||||
// caller, but with an uncorrected stack, causing delayed havoc.
|
||||
|
||||
if (VerifyAdapterCalls &&
|
||||
(Interpreter::code() != nullptr || StubRoutines::final_stubs_code() != nullptr)) {
|
||||
#if 0
|
||||
// So, let's test for cascading c2i/i2c adapters right now.
|
||||
// assert(Interpreter::contains($return_addr) ||
|
||||
// StubRoutines::contains($return_addr),
|
||||
// "i2c adapter must return to an interpreter frame");
|
||||
__ block_comment("verify_i2c { ");
|
||||
Label L_ok;
|
||||
if (Interpreter::code() != nullptr) {
|
||||
range_check(masm, rax, r11,
|
||||
Interpreter::code()->code_start(), Interpreter::code()->code_end(),
|
||||
L_ok);
|
||||
}
|
||||
if (StubRoutines::initial_stubs_code() != nullptr) {
|
||||
range_check(masm, rax, r11,
|
||||
StubRoutines::initial_stubs_code()->code_begin(),
|
||||
StubRoutines::initial_stubs_code()->code_end(),
|
||||
L_ok);
|
||||
}
|
||||
if (StubRoutines::final_stubs_code() != nullptr) {
|
||||
range_check(masm, rax, r11,
|
||||
StubRoutines::final_stubs_code()->code_begin(),
|
||||
StubRoutines::final_stubs_code()->code_end(),
|
||||
L_ok);
|
||||
}
|
||||
const char* msg = "i2c adapter must return to an interpreter frame";
|
||||
__ block_comment(msg);
|
||||
__ stop(msg);
|
||||
__ bind(L_ok);
|
||||
__ block_comment("} verify_i2ce ");
|
||||
#endif
|
||||
}
|
||||
|
||||
// Cut-out for having no stack args.
|
||||
int comp_words_on_stack = align_up(comp_args_on_stack*VMRegImpl::stack_slot_size, wordSize)>>LogBytesPerWord;
|
||||
if (comp_args_on_stack) {
|
||||
@ -711,12 +677,12 @@ void SharedRuntime::gen_i2c_adapter(MacroAssembler *masm,
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm,
|
||||
int total_args_passed,
|
||||
int comp_args_on_stack,
|
||||
const BasicType *sig_bt,
|
||||
const VMRegPair *regs,
|
||||
AdapterFingerPrint* fingerprint) {
|
||||
void SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm,
|
||||
int total_args_passed,
|
||||
int comp_args_on_stack,
|
||||
const BasicType *sig_bt,
|
||||
const VMRegPair *regs,
|
||||
AdapterHandlerEntry* handler) {
|
||||
address i2c_entry = __ pc();
|
||||
|
||||
gen_i2c_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs);
|
||||
@ -777,7 +743,8 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm
|
||||
|
||||
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, c2i_no_clinit_check_entry);
|
||||
handler->set_entry_points(i2c_entry, c2i_entry, c2i_unverified_entry, c2i_no_clinit_check_entry);
|
||||
return;
|
||||
}
|
||||
|
||||
static int c_calling_convention_priv(const BasicType *sig_bt,
|
||||
|
@ -612,12 +612,12 @@ static void gen_c2i_adapter(MacroAssembler *masm,
|
||||
|
||||
}
|
||||
|
||||
AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm,
|
||||
int total_args_passed,
|
||||
int comp_args_on_stack,
|
||||
const BasicType *sig_bt,
|
||||
const VMRegPair *regs,
|
||||
AdapterFingerPrint* fingerprint) {
|
||||
void SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm,
|
||||
int total_args_passed,
|
||||
int comp_args_on_stack,
|
||||
const BasicType *sig_bt,
|
||||
const VMRegPair *regs,
|
||||
AdapterHandlerEntry* handler) {
|
||||
address i2c_entry = __ pc();
|
||||
gen_i2c_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs);
|
||||
|
||||
@ -637,7 +637,8 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm
|
||||
address c2i_entry = __ pc();
|
||||
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);
|
||||
handler->set_entry_points(i2c_entry, c2i_entry, c2i_unverified_entry, nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1143,12 +1143,12 @@ void SharedRuntime::gen_i2c_adapter(MacroAssembler *masm,
|
||||
__ bctr();
|
||||
}
|
||||
|
||||
AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm,
|
||||
int total_args_passed,
|
||||
int comp_args_on_stack,
|
||||
const BasicType *sig_bt,
|
||||
const VMRegPair *regs,
|
||||
AdapterFingerPrint* fingerprint) {
|
||||
void SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm,
|
||||
int total_args_passed,
|
||||
int comp_args_on_stack,
|
||||
const BasicType *sig_bt,
|
||||
const VMRegPair *regs,
|
||||
AdapterHandlerEntry* handler) {
|
||||
address i2c_entry;
|
||||
address c2i_unverified_entry;
|
||||
address c2i_entry;
|
||||
@ -1223,8 +1223,8 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm
|
||||
|
||||
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,
|
||||
c2i_no_clinit_check_entry);
|
||||
handler->set_entry_points(i2c_entry, c2i_entry, c2i_unverified_entry, c2i_no_clinit_check_entry);
|
||||
return;
|
||||
}
|
||||
|
||||
// An oop arg. Must pass a handle not the oop itself.
|
||||
|
@ -596,12 +596,13 @@ void SharedRuntime::gen_i2c_adapter(MacroAssembler *masm,
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm,
|
||||
int total_args_passed,
|
||||
int comp_args_on_stack,
|
||||
const BasicType *sig_bt,
|
||||
const VMRegPair *regs,
|
||||
AdapterFingerPrint* fingerprint) {
|
||||
|
||||
void SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm,
|
||||
int total_args_passed,
|
||||
int comp_args_on_stack,
|
||||
const BasicType *sig_bt,
|
||||
const VMRegPair *regs,
|
||||
AdapterHandlerEntry* handler) {
|
||||
address i2c_entry = __ pc();
|
||||
gen_i2c_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs);
|
||||
|
||||
@ -658,7 +659,8 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm
|
||||
|
||||
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, c2i_no_clinit_check_entry);
|
||||
handler->set_entry_points(i2c_entry, c2i_entry, c2i_unverified_entry, c2i_no_clinit_check_entry);
|
||||
return;
|
||||
}
|
||||
|
||||
int SharedRuntime::vector_calling_convention(VMRegPair *regs,
|
||||
|
@ -2352,12 +2352,12 @@ void SharedRuntime::gen_i2c_adapter(MacroAssembler *masm,
|
||||
__ z_br(Z_R1_scratch);
|
||||
}
|
||||
|
||||
AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm,
|
||||
int total_args_passed,
|
||||
int comp_args_on_stack,
|
||||
const BasicType *sig_bt,
|
||||
const VMRegPair *regs,
|
||||
AdapterFingerPrint* fingerprint) {
|
||||
void SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm,
|
||||
int total_args_passed,
|
||||
int comp_args_on_stack,
|
||||
const BasicType *sig_bt,
|
||||
const VMRegPair *regs,
|
||||
AdapterHandlerEntry* handler) {
|
||||
__ align(CodeEntryAlignment);
|
||||
address i2c_entry = __ pc();
|
||||
gen_i2c_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs);
|
||||
@ -2411,7 +2411,8 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm
|
||||
|
||||
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, c2i_no_clinit_check_entry);
|
||||
handler->set_entry_points(i2c_entry, c2i_entry, c2i_unverified_entry, c2i_no_clinit_check_entry);
|
||||
return;
|
||||
}
|
||||
|
||||
// This function returns the adjust size (in number of words) to a c2i adapter
|
||||
|
@ -24,6 +24,7 @@
|
||||
|
||||
#include "asm/assembler.hpp"
|
||||
#include "asm/assembler.inline.hpp"
|
||||
#include "code/aotCodeCache.hpp"
|
||||
#include "code/compiledIC.hpp"
|
||||
#include "compiler/compiler_globals.hpp"
|
||||
#include "compiler/disassembler.hpp"
|
||||
@ -366,7 +367,9 @@ void MacroAssembler::stop(const char* msg) {
|
||||
lea(c_rarg1, InternalAddress(rip));
|
||||
movq(c_rarg2, rsp); // pass pointer to regs array
|
||||
}
|
||||
lea(c_rarg0, ExternalAddress((address) msg));
|
||||
// Skip AOT caching C strings in scratch buffer.
|
||||
const char* str = (code_section()->scratch_emit()) ? msg : AOTCodeCache::add_C_string(msg);
|
||||
lea(c_rarg0, ExternalAddress((address) str));
|
||||
andq(rsp, -16); // align stack as required by ABI
|
||||
call(RuntimeAddress(CAST_FROM_FN_PTR(address, MacroAssembler::debug64)));
|
||||
hlt();
|
||||
|
@ -675,7 +675,6 @@ static void patch_callers_callsite(MacroAssembler *masm) {
|
||||
__ bind(L);
|
||||
}
|
||||
|
||||
|
||||
static void gen_c2i_adapter(MacroAssembler *masm,
|
||||
int total_args_passed,
|
||||
int comp_args_on_stack,
|
||||
@ -826,19 +825,6 @@ static void gen_c2i_adapter(MacroAssembler *masm,
|
||||
__ jmp(rcx);
|
||||
}
|
||||
|
||||
static void range_check(MacroAssembler* masm, Register pc_reg, Register temp_reg,
|
||||
address code_start, address code_end,
|
||||
Label& L_ok) {
|
||||
Label L_fail;
|
||||
__ lea(temp_reg, AddressLiteral(code_start, relocInfo::none));
|
||||
__ cmpptr(pc_reg, temp_reg);
|
||||
__ jcc(Assembler::belowEqual, L_fail);
|
||||
__ lea(temp_reg, AddressLiteral(code_end, relocInfo::none));
|
||||
__ cmpptr(pc_reg, temp_reg);
|
||||
__ jcc(Assembler::below, L_ok);
|
||||
__ bind(L_fail);
|
||||
}
|
||||
|
||||
void SharedRuntime::gen_i2c_adapter(MacroAssembler *masm,
|
||||
int total_args_passed,
|
||||
int comp_args_on_stack,
|
||||
@ -871,41 +857,6 @@ void SharedRuntime::gen_i2c_adapter(MacroAssembler *masm,
|
||||
// If this happens, control eventually transfers back to the compiled
|
||||
// caller, but with an uncorrected stack, causing delayed havoc.
|
||||
|
||||
if (VerifyAdapterCalls &&
|
||||
(Interpreter::code() != nullptr || StubRoutines::final_stubs_code() != nullptr)) {
|
||||
// So, let's test for cascading c2i/i2c adapters right now.
|
||||
// assert(Interpreter::contains($return_addr) ||
|
||||
// StubRoutines::contains($return_addr),
|
||||
// "i2c adapter must return to an interpreter frame");
|
||||
__ block_comment("verify_i2c { ");
|
||||
// Pick up the return address
|
||||
__ movptr(rax, Address(rsp, 0));
|
||||
Label L_ok;
|
||||
if (Interpreter::code() != nullptr) {
|
||||
range_check(masm, rax, r11,
|
||||
Interpreter::code()->code_start(),
|
||||
Interpreter::code()->code_end(),
|
||||
L_ok);
|
||||
}
|
||||
if (StubRoutines::initial_stubs_code() != nullptr) {
|
||||
range_check(masm, rax, r11,
|
||||
StubRoutines::initial_stubs_code()->code_begin(),
|
||||
StubRoutines::initial_stubs_code()->code_end(),
|
||||
L_ok);
|
||||
}
|
||||
if (StubRoutines::final_stubs_code() != nullptr) {
|
||||
range_check(masm, rax, r11,
|
||||
StubRoutines::final_stubs_code()->code_begin(),
|
||||
StubRoutines::final_stubs_code()->code_end(),
|
||||
L_ok);
|
||||
}
|
||||
const char* msg = "i2c adapter must return to an interpreter frame";
|
||||
__ block_comment(msg);
|
||||
__ stop(msg);
|
||||
__ bind(L_ok);
|
||||
__ block_comment("} verify_i2ce ");
|
||||
}
|
||||
|
||||
// Must preserve original SP for loading incoming arguments because
|
||||
// we need to align the outgoing SP for compiled code.
|
||||
__ movptr(r11, rsp);
|
||||
@ -1050,12 +1001,12 @@ void SharedRuntime::gen_i2c_adapter(MacroAssembler *masm,
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm,
|
||||
int total_args_passed,
|
||||
int comp_args_on_stack,
|
||||
const BasicType *sig_bt,
|
||||
const VMRegPair *regs,
|
||||
AdapterFingerPrint* fingerprint) {
|
||||
void SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm,
|
||||
int total_args_passed,
|
||||
int comp_args_on_stack,
|
||||
const BasicType *sig_bt,
|
||||
const VMRegPair *regs,
|
||||
AdapterHandlerEntry* handler) {
|
||||
address i2c_entry = __ pc();
|
||||
|
||||
gen_i2c_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs);
|
||||
@ -1117,7 +1068,8 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm
|
||||
|
||||
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, c2i_no_clinit_check_entry);
|
||||
handler->set_entry_points(i2c_entry, c2i_entry, c2i_unverified_entry, c2i_no_clinit_check_entry);
|
||||
return;
|
||||
}
|
||||
|
||||
int SharedRuntime::c_calling_convention(const BasicType *sig_bt,
|
||||
|
@ -50,18 +50,17 @@ int SharedRuntime::java_calling_convention(const BasicType *sig_bt,
|
||||
return 0;
|
||||
}
|
||||
|
||||
AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(
|
||||
MacroAssembler *masm,
|
||||
int total_args_passed,
|
||||
int comp_args_on_stack,
|
||||
const BasicType *sig_bt,
|
||||
const VMRegPair *regs,
|
||||
AdapterFingerPrint *fingerprint) {
|
||||
return AdapterHandlerLibrary::new_entry(
|
||||
fingerprint,
|
||||
CAST_FROM_FN_PTR(address,zero_null_code_stub),
|
||||
CAST_FROM_FN_PTR(address,zero_null_code_stub),
|
||||
CAST_FROM_FN_PTR(address,zero_null_code_stub));
|
||||
void SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm,
|
||||
int total_args_passed,
|
||||
int comp_args_on_stack,
|
||||
const BasicType *sig_bt,
|
||||
const VMRegPair *regs,
|
||||
AdapterHandlerEntry* handler) {
|
||||
handler->set_entry_points(CAST_FROM_FN_PTR(address,zero_null_code_stub),
|
||||
CAST_FROM_FN_PTR(address,zero_null_code_stub),
|
||||
CAST_FROM_FN_PTR(address,zero_null_code_stub),
|
||||
nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm,
|
||||
|
@ -271,11 +271,8 @@ bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info,
|
||||
stub = SharedRuntime::handle_unsafe_access(thread, next_pc);
|
||||
}
|
||||
} else if (sig == SIGILL && nativeInstruction_at(pc)->is_stop()) {
|
||||
// Pull a pointer to the error message out of the instruction
|
||||
// stream.
|
||||
const uint64_t *detail_msg_ptr
|
||||
= (uint64_t*)(pc + NativeInstruction::instruction_size);
|
||||
const char *detail_msg = (const char *)*detail_msg_ptr;
|
||||
// A pointer to the message will have been placed in r0
|
||||
const char *detail_msg = (const char *)(uc->uc_mcontext->DU3_PREFIX(ss,x[0]));
|
||||
const char *msg = "stop";
|
||||
if (TraceTraps) {
|
||||
tty->print_cr("trap: %s: (SIGILL)", msg);
|
||||
|
@ -248,11 +248,8 @@ bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info,
|
||||
stub = SharedRuntime::handle_unsafe_access(thread, next_pc);
|
||||
}
|
||||
} else if (sig == SIGILL && nativeInstruction_at(pc)->is_stop()) {
|
||||
// Pull a pointer to the error message out of the instruction
|
||||
// stream.
|
||||
const uint64_t *detail_msg_ptr
|
||||
= (uint64_t*)(pc + NativeInstruction::instruction_size);
|
||||
const char *detail_msg = (const char *)*detail_msg_ptr;
|
||||
// A pointer to the message will have been placed in r0
|
||||
const char *detail_msg = (const char *)(uc->uc_mcontext.regs[0]);
|
||||
const char *msg = "stop";
|
||||
if (TraceTraps) {
|
||||
tty->print_cr("trap: %s: (SIGILL)", msg);
|
||||
|
@ -722,7 +722,7 @@ void CodeBuffer::copy_code_to(CodeBlob* dest_blob) {
|
||||
#ifndef PRODUCT
|
||||
if (PrintNMethods && (WizardMode || Verbose)) {
|
||||
tty->print("done with CodeBuffer:");
|
||||
((CodeBuffer*)this)->print();
|
||||
((CodeBuffer*)this)->print_on(tty);
|
||||
}
|
||||
#endif //PRODUCT
|
||||
|
||||
@ -861,7 +861,7 @@ void CodeBuffer::expand(CodeSection* which_cs, csize_t amount) {
|
||||
#ifndef PRODUCT
|
||||
if (PrintNMethods && (WizardMode || Verbose)) {
|
||||
tty->print("expanding CodeBuffer:");
|
||||
this->print();
|
||||
this->print_on(tty);
|
||||
}
|
||||
|
||||
if (StressCodeBuffers && blob() != nullptr) {
|
||||
@ -949,7 +949,7 @@ void CodeBuffer::expand(CodeSection* which_cs, csize_t amount) {
|
||||
_decode_begin = nullptr; // sanity
|
||||
if (PrintNMethods && (WizardMode || Verbose)) {
|
||||
tty->print("expanded CodeBuffer:");
|
||||
this->print();
|
||||
this->print_on(tty);
|
||||
}
|
||||
#endif //PRODUCT
|
||||
}
|
||||
@ -1066,24 +1066,24 @@ void CodeBuffer::decode() {
|
||||
_decode_begin = insts_end();
|
||||
}
|
||||
|
||||
void CodeSection::print(const char* name) {
|
||||
void CodeSection::print_on(outputStream* st, const char* name) {
|
||||
csize_t locs_size = locs_end() - locs_start();
|
||||
tty->print_cr(" %7s.code = " PTR_FORMAT " : " PTR_FORMAT " : " PTR_FORMAT " (%d of %d)",
|
||||
st->print_cr(" %7s.code = " PTR_FORMAT " : " PTR_FORMAT " : " PTR_FORMAT " (%d of %d)",
|
||||
name, p2i(start()), p2i(end()), p2i(limit()), size(), capacity());
|
||||
tty->print_cr(" %7s.locs = " PTR_FORMAT " : " PTR_FORMAT " : " PTR_FORMAT " (%d of %d) point=%d",
|
||||
st->print_cr(" %7s.locs = " PTR_FORMAT " : " PTR_FORMAT " : " PTR_FORMAT " (%d of %d) point=%d",
|
||||
name, p2i(locs_start()), p2i(locs_end()), p2i(locs_limit()), locs_size, locs_capacity(), locs_point_off());
|
||||
if (PrintRelocations && (locs_size != 0)) {
|
||||
RelocIterator iter(this);
|
||||
iter.print();
|
||||
iter.print_on(st);
|
||||
}
|
||||
}
|
||||
|
||||
void CodeBuffer::print() {
|
||||
tty->print_cr("CodeBuffer:");
|
||||
void CodeBuffer::print_on(outputStream* st) {
|
||||
st->print_cr("CodeBuffer:%s", name());
|
||||
for (int n = 0; n < (int)SECT_LIMIT; n++) {
|
||||
// print each section
|
||||
CodeSection* cs = code_section(n);
|
||||
cs->print(code_section_name(n));
|
||||
cs->print_on(st, code_section_name(n));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -89,6 +89,7 @@ public:
|
||||
// They are filled concurrently, and concatenated at the end.
|
||||
class CodeSection {
|
||||
friend class CodeBuffer;
|
||||
friend class AOTCodeReader;
|
||||
public:
|
||||
typedef int csize_t; // code size type; would be size_t except for history
|
||||
|
||||
@ -283,7 +284,7 @@ class CodeSection {
|
||||
|
||||
#ifndef PRODUCT
|
||||
void decode();
|
||||
void print(const char* name);
|
||||
void print_on(outputStream* st, const char* name);
|
||||
#endif //PRODUCT
|
||||
};
|
||||
|
||||
@ -386,6 +387,7 @@ typedef GrowableArray<SharedStubToInterpRequest> SharedStubToInterpRequests;
|
||||
class CodeBuffer: public StackObj DEBUG_ONLY(COMMA private Scrubber) {
|
||||
friend class CodeSection;
|
||||
friend class StubCodeGenerator;
|
||||
friend class AOTCodeReader;
|
||||
|
||||
private:
|
||||
// CodeBuffers must be allocated on the stack except for a single
|
||||
@ -742,7 +744,7 @@ class CodeBuffer: public StackObj DEBUG_ONLY(COMMA private Scrubber) {
|
||||
// Printing / Decoding
|
||||
// decodes from decode_begin() to code_end() and sets decode_begin to end
|
||||
void decode();
|
||||
void print();
|
||||
void print_on(outputStream* st);
|
||||
#endif
|
||||
// Directly disassemble code buffer.
|
||||
void decode(address start, address end);
|
||||
|
55
src/hotspot/share/cds/aotCacheAccess.cpp
Normal file
55
src/hotspot/share/cds/aotCacheAccess.cpp
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "cds/aotCacheAccess.hpp"
|
||||
#include "cds/archiveBuilder.hpp"
|
||||
#include "cds/cdsConfig.hpp"
|
||||
#include "cds/filemap.hpp"
|
||||
#include "cds/heapShared.hpp"
|
||||
#include "cds/metaspaceShared.hpp"
|
||||
#include "classfile/stringTable.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "logging/logStream.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "memory/universe.hpp"
|
||||
#include "memory/virtualspace.hpp"
|
||||
#include "oops/instanceKlass.hpp"
|
||||
|
||||
void* AOTCacheAccess::allocate_aot_code_region(size_t size) {
|
||||
assert(CDSConfig::is_dumping_final_static_archive(), "must be");
|
||||
return (void*)ArchiveBuilder::ac_region_alloc(size);
|
||||
}
|
||||
|
||||
size_t AOTCacheAccess::get_aot_code_region_size() {
|
||||
assert(CDSConfig::is_using_archive(), "must be");
|
||||
FileMapInfo* mapinfo = FileMapInfo::current_info();
|
||||
assert(mapinfo != nullptr, "must be");
|
||||
return mapinfo->region_at(MetaspaceShared::ac)->used_aligned();
|
||||
}
|
||||
|
||||
bool AOTCacheAccess::map_aot_code_region(ReservedSpace rs) {
|
||||
FileMapInfo* static_mapinfo = FileMapInfo::current_info();
|
||||
assert(UseSharedSpaces && static_mapinfo != nullptr, "must be");
|
||||
return static_mapinfo->map_aot_code_region(rs);
|
||||
}
|
47
src/hotspot/share/cds/aotCacheAccess.hpp
Normal file
47
src/hotspot/share/cds/aotCacheAccess.hpp
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SHARE_CDS_AOTCACHEACCESS_HPP
|
||||
#define SHARE_CDS_AOTCACHEACCESS_HPP
|
||||
|
||||
#include "cds/archiveBuilder.hpp"
|
||||
#include "cds/archiveUtils.hpp"
|
||||
#include "memory/allStatic.hpp"
|
||||
#include "oops/oopsHierarchy.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
|
||||
class ReservedSpace;
|
||||
|
||||
// AOT Cache API for AOT compiler
|
||||
|
||||
class AOTCacheAccess : AllStatic {
|
||||
public:
|
||||
static void* allocate_aot_code_region(size_t size) NOT_CDS_RETURN_(nullptr);
|
||||
|
||||
static size_t get_aot_code_region_size() NOT_CDS_RETURN_(0);
|
||||
|
||||
static bool map_aot_code_region(ReservedSpace rs) NOT_CDS_RETURN_(false);
|
||||
};
|
||||
|
||||
#endif // SHARE_CDS_AOTCACHEACCESS_HPP
|
@ -42,6 +42,7 @@
|
||||
#include "classfile/symbolTable.hpp"
|
||||
#include "classfile/systemDictionaryShared.hpp"
|
||||
#include "classfile/vmClasses.hpp"
|
||||
#include "code/aotCodeCache.hpp"
|
||||
#include "interpreter/abstractInterpreter.hpp"
|
||||
#include "jvm.h"
|
||||
#include "logging/log.hpp"
|
||||
@ -163,6 +164,7 @@ ArchiveBuilder::ArchiveBuilder() :
|
||||
_pz_region("pz", MAX_SHARED_DELTA), // protection zone -- used only during dumping; does NOT exist in cds archive.
|
||||
_rw_region("rw", MAX_SHARED_DELTA),
|
||||
_ro_region("ro", MAX_SHARED_DELTA),
|
||||
_ac_region("ac", MAX_SHARED_DELTA),
|
||||
_ptrmap(mtClassShared),
|
||||
_rw_ptrmap(mtClassShared),
|
||||
_ro_ptrmap(mtClassShared),
|
||||
@ -306,7 +308,8 @@ void ArchiveBuilder::sort_klasses() {
|
||||
}
|
||||
|
||||
address ArchiveBuilder::reserve_buffer() {
|
||||
size_t buffer_size = LP64_ONLY(CompressedClassSpaceSize) NOT_LP64(256 * M);
|
||||
// AOTCodeCache::max_aot_code_size() accounts for aot code region.
|
||||
size_t buffer_size = LP64_ONLY(CompressedClassSpaceSize) NOT_LP64(256 * M) + AOTCodeCache::max_aot_code_size();
|
||||
ReservedSpace rs = MemoryReserver::reserve(buffer_size,
|
||||
MetaspaceShared::core_region_alignment(),
|
||||
os::vm_page_size(),
|
||||
@ -532,6 +535,13 @@ ArchiveBuilder::FollowMode ArchiveBuilder::get_follow_mode(MetaspaceClosure::Ref
|
||||
} else if (ref->msotype() == MetaspaceObj::MethodDataType ||
|
||||
ref->msotype() == MetaspaceObj::MethodCountersType) {
|
||||
return set_to_null;
|
||||
} else if (ref->msotype() == MetaspaceObj::AdapterHandlerEntryType) {
|
||||
if (AOTCodeCache::is_dumping_adapters()) {
|
||||
AdapterHandlerEntry* entry = (AdapterHandlerEntry*)ref->obj();
|
||||
return AdapterHandlerLibrary::is_abstract_method_adapter(entry) ? set_to_null : make_a_copy;
|
||||
} else {
|
||||
return set_to_null;
|
||||
}
|
||||
} else {
|
||||
if (ref->msotype() == MetaspaceObj::ClassType) {
|
||||
Klass* klass = (Klass*)ref->obj();
|
||||
@ -705,6 +715,11 @@ void ArchiveBuilder::mark_and_relocate_to_buffered_addr(address* ptr_location) {
|
||||
ArchivePtrMarker::mark_pointer(ptr_location);
|
||||
}
|
||||
|
||||
bool ArchiveBuilder::has_been_archived(address src_addr) const {
|
||||
SourceObjInfo* p = _src_obj_table.get(src_addr);
|
||||
return (p != nullptr);
|
||||
}
|
||||
|
||||
bool ArchiveBuilder::has_been_buffered(address src_addr) const {
|
||||
if (RegeneratedClasses::has_been_regenerated(src_addr) ||
|
||||
_src_obj_table.get(src_addr) == nullptr ||
|
||||
@ -973,6 +988,15 @@ address ArchiveBuilder::offset_to_buffered_address(u4 offset) const {
|
||||
return buffered_addr;
|
||||
}
|
||||
|
||||
void ArchiveBuilder::start_ac_region() {
|
||||
ro_region()->pack();
|
||||
start_dump_region(&_ac_region);
|
||||
}
|
||||
|
||||
void ArchiveBuilder::end_ac_region() {
|
||||
_ac_region.pack();
|
||||
}
|
||||
|
||||
#if INCLUDE_CDS_JAVA_HEAP
|
||||
narrowKlass ArchiveBuilder::get_requested_narrow_klass(Klass* k) {
|
||||
assert(CDSConfig::is_dumping_heap(), "sanity");
|
||||
@ -1082,8 +1106,9 @@ int ArchiveBuilder::precomputed_narrow_klass_shift() {
|
||||
#endif // _LP64
|
||||
|
||||
void ArchiveBuilder::relocate_to_requested() {
|
||||
ro_region()->pack();
|
||||
|
||||
if (!ro_region()->is_packed()) {
|
||||
ro_region()->pack();
|
||||
}
|
||||
size_t my_archive_size = buffer_top() - buffer_bottom();
|
||||
|
||||
if (CDSConfig::is_dumping_static_archive()) {
|
||||
@ -1527,6 +1552,7 @@ void ArchiveBuilder::write_archive(FileMapInfo* mapinfo, ArchiveHeapInfo* heap_i
|
||||
|
||||
write_region(mapinfo, MetaspaceShared::rw, &_rw_region, /*read_only=*/false,/*allow_exec=*/false);
|
||||
write_region(mapinfo, MetaspaceShared::ro, &_ro_region, /*read_only=*/true, /*allow_exec=*/false);
|
||||
write_region(mapinfo, MetaspaceShared::ac, &_ac_region, /*read_only=*/false,/*allow_exec=*/false);
|
||||
|
||||
// Split pointer map into read-write and read-only bitmaps
|
||||
ArchivePtrMarker::initialize_rw_ro_maps(&_rw_ptrmap, &_ro_ptrmap);
|
||||
@ -1579,6 +1605,7 @@ void ArchiveBuilder::print_region_stats(FileMapInfo *mapinfo, ArchiveHeapInfo* h
|
||||
|
||||
_rw_region.print(total_reserved);
|
||||
_ro_region.print(total_reserved);
|
||||
_ac_region.print(total_reserved);
|
||||
|
||||
print_bitmap_region_stats(bitmap_used, total_reserved);
|
||||
|
||||
|
@ -217,6 +217,7 @@ private:
|
||||
|
||||
DumpRegion _rw_region;
|
||||
DumpRegion _ro_region;
|
||||
DumpRegion _ac_region; // AOT code
|
||||
|
||||
// Combined bitmap to track pointers in both RW and RO regions. This is updated
|
||||
// as objects are copied into RW and RO.
|
||||
@ -372,6 +373,7 @@ public:
|
||||
DumpRegion* pz_region() { return &_pz_region; }
|
||||
DumpRegion* rw_region() { return &_rw_region; }
|
||||
DumpRegion* ro_region() { return &_ro_region; }
|
||||
DumpRegion* ac_region() { return &_ac_region; }
|
||||
|
||||
static char* rw_region_alloc(size_t num_bytes) {
|
||||
return current()->rw_region()->allocate(num_bytes);
|
||||
@ -379,6 +381,12 @@ public:
|
||||
static char* ro_region_alloc(size_t num_bytes) {
|
||||
return current()->ro_region()->allocate(num_bytes);
|
||||
}
|
||||
static char* ac_region_alloc(size_t num_bytes) {
|
||||
return current()->ac_region()->allocate(num_bytes);
|
||||
}
|
||||
|
||||
void start_ac_region();
|
||||
void end_ac_region();
|
||||
|
||||
template <typename T>
|
||||
static Array<T>* new_ro_array(int length) {
|
||||
@ -426,6 +434,8 @@ public:
|
||||
mark_and_relocate_to_buffered_addr((address*)ptr_location);
|
||||
}
|
||||
|
||||
bool has_been_archived(address src_addr) const;
|
||||
|
||||
bool has_been_buffered(address src_addr) const;
|
||||
template <typename T> bool has_been_buffered(T src_addr) const {
|
||||
return has_been_buffered((address)src_addr);
|
||||
|
@ -270,9 +270,10 @@ void DumpRegion::append_intptr_t(intptr_t n, bool need_to_mark) {
|
||||
}
|
||||
|
||||
void DumpRegion::print(size_t total_bytes) const {
|
||||
char* base = used() > 0 ? ArchiveBuilder::current()->to_requested(_base) : nullptr;
|
||||
log_debug(cds)("%s space: %9zu [ %4.1f%% of total] out of %9zu bytes [%5.1f%% used] at " INTPTR_FORMAT,
|
||||
_name, used(), percent_of(used(), total_bytes), reserved(), percent_of(used(), reserved()),
|
||||
p2i(ArchiveBuilder::current()->to_requested(_base)));
|
||||
p2i(base));
|
||||
}
|
||||
|
||||
void DumpRegion::print_out_of_space_msg(const char* failing_region, size_t needed_bytes) {
|
||||
@ -295,7 +296,10 @@ void DumpRegion::init(ReservedSpace* rs, VirtualSpace* vs) {
|
||||
}
|
||||
|
||||
void DumpRegion::pack(DumpRegion* next) {
|
||||
assert(!is_packed(), "sanity");
|
||||
if (!is_packed()) {
|
||||
_end = (char*)align_up(_top, MetaspaceShared::core_region_alignment());
|
||||
_is_packed = true;
|
||||
}
|
||||
_end = (char*)align_up(_top, MetaspaceShared::core_region_alignment());
|
||||
_is_packed = true;
|
||||
if (next != nullptr) {
|
||||
|
@ -180,6 +180,7 @@ public:
|
||||
bool is_allocatable() const {
|
||||
return !is_packed() && _base != nullptr;
|
||||
}
|
||||
bool is_empty() const { return _base == _top; }
|
||||
|
||||
void print(size_t total_bytes) const;
|
||||
void print_out_of_space_msg(const char* failing_region, size_t needed_bytes);
|
||||
|
@ -402,6 +402,10 @@ void CDSConfig::check_aot_flags() {
|
||||
CHECK_SINGLE_PATH(AOTCache);
|
||||
CHECK_SINGLE_PATH(AOTConfiguration);
|
||||
|
||||
if (FLAG_IS_DEFAULT(AOTCache) && AOTAdapterCaching) {
|
||||
log_debug(aot,codecache,init)("AOTCache is not specified - AOTAdapterCaching is ignored");
|
||||
}
|
||||
|
||||
if (FLAG_IS_DEFAULT(AOTCache) && FLAG_IS_DEFAULT(AOTConfiguration) && FLAG_IS_DEFAULT(AOTMode)) {
|
||||
// AOTCache/AOTConfiguration/AOTMode not used.
|
||||
return;
|
||||
@ -517,7 +521,7 @@ bool CDSConfig::check_vm_args_consistency(bool patch_mod_javabase, bool mode_fla
|
||||
}
|
||||
|
||||
if (is_dumping_static_archive()) {
|
||||
if (is_dumping_preimage_static_archive()) {
|
||||
if (is_dumping_preimage_static_archive() || is_dumping_final_static_archive()) {
|
||||
// Don't tweak execution mode
|
||||
} else if (!mode_flag_cmd_line) {
|
||||
// By default, -Xshare:dump runs in interpreter-only mode, which is required for deterministic archive.
|
||||
@ -844,3 +848,22 @@ bool CDSConfig::is_dumping_method_handles() {
|
||||
}
|
||||
|
||||
#endif // INCLUDE_CDS_JAVA_HEAP
|
||||
|
||||
// AOT code generation and its archiving is disabled by default.
|
||||
// We enable it only in the final image dump after the metadata and heap are dumped.
|
||||
// This affects only JITed code because it may have embedded oops and metadata pointers
|
||||
// which AOT code encodes as offsets in final CDS archive regions.
|
||||
|
||||
static bool _is_dumping_aot_code = false;
|
||||
|
||||
bool CDSConfig::is_dumping_aot_code() {
|
||||
return _is_dumping_aot_code;
|
||||
}
|
||||
|
||||
void CDSConfig::disable_dumping_aot_code() {
|
||||
_is_dumping_aot_code = false;
|
||||
}
|
||||
|
||||
void CDSConfig::enable_dumping_aot_code() {
|
||||
_is_dumping_aot_code = true;
|
||||
}
|
||||
|
@ -181,6 +181,12 @@ public:
|
||||
static void stop_dumping_full_module_graph(const char* reason = nullptr) NOT_CDS_JAVA_HEAP_RETURN;
|
||||
static void stop_using_full_module_graph(const char* reason = nullptr) NOT_CDS_JAVA_HEAP_RETURN;
|
||||
|
||||
// --- AOT code
|
||||
|
||||
static bool is_dumping_aot_code() NOT_CDS_RETURN_(false);
|
||||
static void disable_dumping_aot_code() NOT_CDS_RETURN;
|
||||
static void enable_dumping_aot_code() NOT_CDS_RETURN;
|
||||
|
||||
// Some CDS functions assume that they are called only within a single-threaded context. I.e.,
|
||||
// they are called from:
|
||||
// - The VM thread (e.g., inside VM_PopulateDumpSharedSpace)
|
||||
|
@ -127,6 +127,22 @@
|
||||
product(bool, AOTCacheParallelRelocation, true, DIAGNOSTIC, \
|
||||
"Use parallel relocation code to speed up startup.") \
|
||||
\
|
||||
/* AOT Code flags */ \
|
||||
\
|
||||
product(bool, AOTAdapterCaching, false, DIAGNOSTIC, \
|
||||
"Enable saving and restoring i2c2i adapters in AOT cache") \
|
||||
\
|
||||
product(uint, AOTCodeMaxSize, 10*M, DIAGNOSTIC, \
|
||||
"Buffer size in bytes for AOT code caching") \
|
||||
range(1*M, max_jint) \
|
||||
\
|
||||
product(bool, AbortVMOnAOTCodeFailure, false, DIAGNOSTIC, \
|
||||
"Abort VM on the first occurrence of AOT code load or store " \
|
||||
"failure. By default VM will continue execute without AOT code.") \
|
||||
\
|
||||
develop(bool, TestAOTAdapterLinkFailure, false, \
|
||||
"Test failure of adapter linking when loading from AOT cache.") \
|
||||
|
||||
// end of CDS_FLAGS
|
||||
|
||||
DECLARE_FLAGS(CDS_FLAGS)
|
||||
|
@ -281,6 +281,8 @@ intptr_t* CppVtables::get_archived_vtable(MetaspaceObj::Type msotype, address ob
|
||||
case MetaspaceObj::AnnotationsType:
|
||||
case MetaspaceObj::MethodCountersType:
|
||||
case MetaspaceObj::RecordComponentType:
|
||||
case MetaspaceObj::AdapterHandlerEntryType:
|
||||
case MetaspaceObj::AdapterFingerPrintType:
|
||||
// These have no vtables.
|
||||
break;
|
||||
case MetaspaceObj::MethodDataType:
|
||||
|
@ -824,7 +824,7 @@ bool FileMapRegion::check_region_crc(char* base) const {
|
||||
|
||||
static const char* region_name(int region_index) {
|
||||
static const char* names[] = {
|
||||
"rw", "ro", "bm", "hp"
|
||||
"rw", "ro", "bm", "hp", "ac"
|
||||
};
|
||||
const int num_regions = sizeof(names)/sizeof(names[0]);
|
||||
assert(0 <= region_index && region_index < num_regions, "sanity");
|
||||
@ -910,6 +910,9 @@ void FileMapInfo::write_region(int region, char* base, size_t size,
|
||||
" bytes, addr " INTPTR_FORMAT " file offset 0x%08" PRIxPTR
|
||||
" crc 0x%08x",
|
||||
region_name(region), region, size, p2i(requested_base), _file_offset, crc);
|
||||
} else {
|
||||
log_info(cds)("Shared file region (%s) %d: %8zu"
|
||||
" bytes", region_name(region), region, size);
|
||||
}
|
||||
|
||||
r->init(region, mapping_offset, size, read_only, allow_exec, crc);
|
||||
@ -1111,7 +1114,7 @@ bool FileMapInfo::remap_shared_readonly_as_readwrite() {
|
||||
}
|
||||
|
||||
// Memory map a region in the address space.
|
||||
static const char* shared_region_name[] = { "ReadWrite", "ReadOnly", "Bitmap", "Heap" };
|
||||
static const char* shared_region_name[] = { "ReadWrite", "ReadOnly", "Bitmap", "Heap", "Code" };
|
||||
|
||||
MapArchiveResult FileMapInfo::map_regions(int regions[], int num_regions, char* mapped_base_address, ReservedSpace rs) {
|
||||
DEBUG_ONLY(FileMapRegion* last_region = nullptr);
|
||||
@ -1274,6 +1277,42 @@ char* FileMapInfo::map_bitmap_region() {
|
||||
return bitmap_base;
|
||||
}
|
||||
|
||||
bool FileMapInfo::map_aot_code_region(ReservedSpace rs) {
|
||||
FileMapRegion* r = region_at(MetaspaceShared::ac);
|
||||
assert(r->used() > 0 && r->used_aligned() == rs.size(), "must be");
|
||||
|
||||
char* requested_base = rs.base();
|
||||
assert(requested_base != nullptr, "should be inside code cache");
|
||||
|
||||
char* mapped_base;
|
||||
if (MetaspaceShared::use_windows_memory_mapping()) {
|
||||
if (!read_region(MetaspaceShared::ac, requested_base, r->used_aligned(), /* do_commit = */ true)) {
|
||||
log_info(cds)("Failed to read aot code shared space into reserved space at " INTPTR_FORMAT,
|
||||
p2i(requested_base));
|
||||
return false;
|
||||
}
|
||||
mapped_base = requested_base;
|
||||
} else {
|
||||
// We do not execute in-place in the AOT code region.
|
||||
// AOT code is copied to the CodeCache for execution.
|
||||
bool read_only = false, allow_exec = false;
|
||||
mapped_base = map_memory(_fd, _full_path, r->file_offset(),
|
||||
requested_base, r->used_aligned(), read_only, allow_exec, mtClassShared);
|
||||
}
|
||||
if (mapped_base == nullptr) {
|
||||
log_info(cds)("failed to map aot code region");
|
||||
return false;
|
||||
} else {
|
||||
assert(mapped_base == requested_base, "must be");
|
||||
r->set_mapped_from_file(true);
|
||||
r->set_mapped_base(mapped_base);
|
||||
log_info(cds)("Mapped static region #%d at base " INTPTR_FORMAT " top " INTPTR_FORMAT " (%s)",
|
||||
MetaspaceShared::ac, p2i(r->mapped_base()), p2i(r->mapped_end()),
|
||||
shared_region_name[MetaspaceShared::ac]);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
class SharedDataRelocationTask : public ArchiveWorkerTask {
|
||||
private:
|
||||
BitMapView* const _rw_bm;
|
||||
|
@ -368,6 +368,7 @@ public:
|
||||
MemRegion get_heap_region_requested_range() NOT_CDS_JAVA_HEAP_RETURN_(MemRegion());
|
||||
bool read_region(int i, char* base, size_t size, bool do_commit);
|
||||
char* map_bitmap_region();
|
||||
bool map_aot_code_region(ReservedSpace rs);
|
||||
void unmap_region(int i);
|
||||
void close();
|
||||
bool is_open() { return _file_open; }
|
||||
|
@ -59,6 +59,7 @@
|
||||
#include "classfile/systemDictionaryShared.hpp"
|
||||
#include "classfile/vmClasses.hpp"
|
||||
#include "classfile/vmSymbols.hpp"
|
||||
#include "code/aotCodeCache.hpp"
|
||||
#include "code/codeCache.hpp"
|
||||
#include "gc/shared/gcVMOperations.hpp"
|
||||
#include "interpreter/bytecodeStream.hpp"
|
||||
@ -491,6 +492,8 @@ void MetaspaceShared::serialize(SerializeClosure* soc) {
|
||||
soc->do_ptr((void**)&_archived_method_handle_intrinsics);
|
||||
|
||||
LambdaFormInvokers::serialize(soc);
|
||||
AdapterHandlerLibrary::serialize_shared_table_header(soc);
|
||||
|
||||
soc->do_tag(666);
|
||||
}
|
||||
|
||||
@ -609,6 +612,10 @@ char* VM_PopulateDumpSharedSpace::dump_read_only_tables(AOTClassLocationConfig*&
|
||||
// Write lambform lines into archive
|
||||
LambdaFormInvokers::dump_static_archive_invokers();
|
||||
|
||||
if (AOTCodeCache::is_dumping_adapters()) {
|
||||
AdapterHandlerLibrary::dump_aot_adapter_table();
|
||||
}
|
||||
|
||||
// Write the other data to the output array.
|
||||
DumpRegion* ro_region = ArchiveBuilder::current()->ro_region();
|
||||
char* start = ro_region->top();
|
||||
@ -998,6 +1005,17 @@ void MetaspaceShared::preload_and_dump_impl(StaticArchiveBuilder& builder, TRAPS
|
||||
VM_PopulateDumpSharedSpace op(builder);
|
||||
VMThread::execute(&op);
|
||||
|
||||
if (AOTCodeCache::is_on_for_dump() && CDSConfig::is_dumping_final_static_archive()) {
|
||||
CDSConfig::enable_dumping_aot_code();
|
||||
{
|
||||
builder.start_ac_region();
|
||||
// Write the contents to AOT code region and close AOTCodeCache before packing the region
|
||||
AOTCodeCache::close();
|
||||
builder.end_ac_region();
|
||||
}
|
||||
CDSConfig::disable_dumping_aot_code();
|
||||
}
|
||||
|
||||
if (!write_static_archive(&builder, op.map_info(), op.heap_info())) {
|
||||
THROW_MSG(vmSymbols::java_io_IOException(), "Encountered error while dumping");
|
||||
}
|
||||
@ -1769,6 +1787,7 @@ void MetaspaceShared::initialize_shared_spaces() {
|
||||
static_mapinfo->patch_heap_embedded_pointers();
|
||||
ArchiveHeapLoader::finish_initialization();
|
||||
Universe::load_archived_object_instances();
|
||||
AOTCodeCache::initialize();
|
||||
|
||||
// Close the mapinfo file
|
||||
static_mapinfo->close();
|
||||
@ -1820,6 +1839,11 @@ void MetaspaceShared::initialize_shared_spaces() {
|
||||
SystemDictionaryShared::print_shared_archive(tty, false/*dynamic*/);
|
||||
}
|
||||
|
||||
if (AOTCodeCache::is_on_for_use()) {
|
||||
tty->print_cr("\n\nAOT Code");
|
||||
AOTCodeCache::print_on(tty);
|
||||
}
|
||||
|
||||
// collect shared symbols and strings
|
||||
CountSharedSymbols cl;
|
||||
SymbolTable::shared_symbols_do(&cl);
|
||||
|
@ -67,8 +67,9 @@ class MetaspaceShared : AllStatic {
|
||||
ro = 1, // read-only shared space
|
||||
bm = 2, // relocation bitmaps (freed after file mapping is finished)
|
||||
hp = 3, // heap region
|
||||
ac = 4, // aot code
|
||||
num_core_region = 2, // rw and ro
|
||||
n_regions = 4 // total number of regions
|
||||
n_regions = 5 // total number of regions
|
||||
};
|
||||
|
||||
static void preload_and_dump(TRAPS) NOT_CDS_RETURN;
|
||||
|
@ -282,7 +282,15 @@ public:
|
||||
}
|
||||
|
||||
template <class ITER>
|
||||
inline void iterate(ITER* iter) const {
|
||||
inline void iterate(ITER* iter) const { iterate([&](V v) { iter->do_value(v); }); }
|
||||
|
||||
template<typename Function>
|
||||
inline void iterate(const Function& function) const { // lambda enabled API
|
||||
iterate(const_cast<Function&>(function));
|
||||
}
|
||||
|
||||
template<typename Function>
|
||||
inline void iterate(Function& function) const { // lambda enabled API
|
||||
for (u4 i = 0; i < _bucket_count; i++) {
|
||||
u4 bucket_info = _buckets[i];
|
||||
u4 bucket_offset = BUCKET_OFFSET(bucket_info);
|
||||
@ -290,11 +298,11 @@ public:
|
||||
u4* entry = _entries + bucket_offset;
|
||||
|
||||
if (bucket_type == VALUE_ONLY_BUCKET_TYPE) {
|
||||
iter->do_value(decode(entry[0]));
|
||||
function(decode(entry[0]));
|
||||
} else {
|
||||
u4*entry_max = _entries + BUCKET_OFFSET(_buckets[i + 1]);
|
||||
u4* entry_max = _entries + BUCKET_OFFSET(_buckets[i + 1]);
|
||||
while (entry < entry_max) {
|
||||
iter->do_value(decode(entry[1]));
|
||||
function(decode(entry[1]));
|
||||
entry += 2;
|
||||
}
|
||||
}
|
||||
|
1324
src/hotspot/share/code/aotCodeCache.cpp
Normal file
1324
src/hotspot/share/code/aotCodeCache.cpp
Normal file
File diff suppressed because it is too large
Load Diff
365
src/hotspot/share/code/aotCodeCache.hpp
Normal file
365
src/hotspot/share/code/aotCodeCache.hpp
Normal file
@ -0,0 +1,365 @@
|
||||
/*
|
||||
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SHARE_CODE_AOTCODECACHE_HPP
|
||||
#define SHARE_CODE_AOTCODECACHE_HPP
|
||||
|
||||
/*
|
||||
* AOT Code Cache collects code from Code Cache and corresponding metadata
|
||||
* during application training run.
|
||||
* In following "production" runs this code and data can be loaded into
|
||||
* Code Cache skipping its generation.
|
||||
*/
|
||||
|
||||
class CodeBuffer;
|
||||
class RelocIterator;
|
||||
class AOTCodeCache;
|
||||
class AdapterBlob;
|
||||
class ExceptionBlob;
|
||||
class ImmutableOopMapSet;
|
||||
|
||||
enum class vmIntrinsicID : int;
|
||||
enum CompLevel : signed char;
|
||||
|
||||
// Descriptor of AOT Code Cache's entry
|
||||
class AOTCodeEntry {
|
||||
public:
|
||||
enum Kind {
|
||||
None = 0,
|
||||
Adapter = 1,
|
||||
Blob = 2
|
||||
};
|
||||
|
||||
private:
|
||||
AOTCodeEntry* _next;
|
||||
Kind _kind;
|
||||
uint _id; // Adapter's id, vmIntrinsic::ID for stub or name's hash for nmethod
|
||||
uint _offset; // Offset to entry
|
||||
uint _size; // Entry size
|
||||
uint _name_offset; // Code blob name
|
||||
uint _name_size;
|
||||
uint _blob_offset; // Start of code in cache
|
||||
bool _has_oop_maps;
|
||||
address _dumptime_content_start_addr; // CodeBlob::content_begin() at dump time; used for applying relocations
|
||||
|
||||
public:
|
||||
AOTCodeEntry(Kind kind, uint id,
|
||||
uint offset, uint size,
|
||||
uint name_offset, uint name_size,
|
||||
uint blob_offset, bool has_oop_maps,
|
||||
address dumptime_content_start_addr) {
|
||||
_next = nullptr;
|
||||
_kind = kind;
|
||||
_id = id;
|
||||
_offset = offset;
|
||||
_size = size;
|
||||
_name_offset = name_offset;
|
||||
_name_size = name_size;
|
||||
_blob_offset = blob_offset;
|
||||
_has_oop_maps = has_oop_maps;
|
||||
_dumptime_content_start_addr = dumptime_content_start_addr;
|
||||
}
|
||||
void* operator new(size_t x, AOTCodeCache* cache);
|
||||
// Delete is a NOP
|
||||
void operator delete( void *ptr ) {}
|
||||
|
||||
AOTCodeEntry* next() const { return _next; }
|
||||
void set_next(AOTCodeEntry* next) { _next = next; }
|
||||
|
||||
Kind kind() const { return _kind; }
|
||||
uint id() const { return _id; }
|
||||
|
||||
uint offset() const { return _offset; }
|
||||
void set_offset(uint off) { _offset = off; }
|
||||
|
||||
uint size() const { return _size; }
|
||||
uint name_offset() const { return _name_offset; }
|
||||
uint name_size() const { return _name_size; }
|
||||
uint blob_offset() const { return _blob_offset; }
|
||||
bool has_oop_maps() const { return _has_oop_maps; }
|
||||
address dumptime_content_start_addr() const { return _dumptime_content_start_addr; }
|
||||
|
||||
static bool is_valid_entry_kind(Kind kind) { return kind == Adapter || kind == Blob; }
|
||||
};
|
||||
|
||||
// Addresses of stubs, blobs and runtime finctions called from compiled code.
|
||||
class AOTCodeAddressTable : public CHeapObj<mtCode> {
|
||||
private:
|
||||
address* _extrs_addr;
|
||||
address* _blobs_addr;
|
||||
uint _extrs_length;
|
||||
uint _blobs_length;
|
||||
|
||||
bool _extrs_complete;
|
||||
bool _shared_blobs_complete;
|
||||
bool _complete;
|
||||
|
||||
public:
|
||||
AOTCodeAddressTable() :
|
||||
_extrs_addr(nullptr),
|
||||
_blobs_addr(nullptr),
|
||||
_extrs_length(0),
|
||||
_blobs_length(0),
|
||||
_extrs_complete(false),
|
||||
_shared_blobs_complete(false),
|
||||
_complete(false)
|
||||
{ }
|
||||
~AOTCodeAddressTable();
|
||||
void init_extrs();
|
||||
void init_shared_blobs();
|
||||
const char* add_C_string(const char* str);
|
||||
int id_for_C_string(address str);
|
||||
address address_for_C_string(int idx);
|
||||
int id_for_address(address addr, RelocIterator iter, CodeBlob* code_blob);
|
||||
address address_for_id(int id);
|
||||
};
|
||||
|
||||
class AOTCodeCache : public CHeapObj<mtCode> {
|
||||
|
||||
// Classes used to describe AOT code cache.
|
||||
protected:
|
||||
class Config {
|
||||
uint _compressedOopShift;
|
||||
uint _compressedKlassShift;
|
||||
uint _contendedPaddingWidth;
|
||||
uint _objectAlignment;
|
||||
uint _gc;
|
||||
enum Flags {
|
||||
none = 0,
|
||||
debugVM = 1,
|
||||
compressedOops = 2,
|
||||
compressedClassPointers = 4,
|
||||
useTLAB = 8,
|
||||
systemClassAssertions = 16,
|
||||
userClassAssertions = 32,
|
||||
enableContendedPadding = 64,
|
||||
restrictContendedPadding = 128
|
||||
};
|
||||
uint _flags;
|
||||
|
||||
public:
|
||||
void record();
|
||||
bool verify() const;
|
||||
};
|
||||
|
||||
class Header : public CHeapObj<mtCode> {
|
||||
private:
|
||||
enum {
|
||||
AOT_CODE_VERSION = 1
|
||||
};
|
||||
uint _version; // AOT code version (should match when reading code cache)
|
||||
uint _cache_size; // cache size in bytes
|
||||
uint _strings_count; // number of recorded C strings
|
||||
uint _strings_offset; // offset to recorded C strings
|
||||
uint _entries_count; // number of recorded entries
|
||||
uint _entries_offset; // offset of AOTCodeEntry array describing entries
|
||||
uint _adapters_count;
|
||||
uint _blobs_count;
|
||||
Config _config;
|
||||
|
||||
public:
|
||||
void init(uint cache_size,
|
||||
uint strings_count, uint strings_offset,
|
||||
uint entries_count, uint entries_offset,
|
||||
uint adapters_count, uint blobs_count) {
|
||||
_version = AOT_CODE_VERSION;
|
||||
_cache_size = cache_size;
|
||||
_strings_count = strings_count;
|
||||
_strings_offset = strings_offset;
|
||||
_entries_count = entries_count;
|
||||
_entries_offset = entries_offset;
|
||||
_adapters_count = adapters_count;
|
||||
_blobs_count = blobs_count;
|
||||
|
||||
_config.record();
|
||||
}
|
||||
|
||||
|
||||
uint cache_size() const { return _cache_size; }
|
||||
uint strings_count() const { return _strings_count; }
|
||||
uint strings_offset() const { return _strings_offset; }
|
||||
uint entries_count() const { return _entries_count; }
|
||||
uint entries_offset() const { return _entries_offset; }
|
||||
uint adapters_count() const { return _adapters_count; }
|
||||
uint blobs_count() const { return _blobs_count; }
|
||||
|
||||
bool verify_config(uint load_size) const;
|
||||
bool verify_vm_config() const { // Called after Universe initialized
|
||||
return _config.verify();
|
||||
}
|
||||
};
|
||||
|
||||
// Continue with AOTCodeCache class definition.
|
||||
private:
|
||||
Header* _load_header;
|
||||
char* _load_buffer; // Aligned buffer for loading cached code
|
||||
char* _store_buffer; // Aligned buffer for storing cached code
|
||||
char* _C_store_buffer; // Original unaligned buffer
|
||||
|
||||
uint _write_position; // Position in _store_buffer
|
||||
uint _load_size; // Used when reading cache
|
||||
uint _store_size; // Used when writing cache
|
||||
bool _for_use; // AOT cache is open for using AOT code
|
||||
bool _for_dump; // AOT cache is open for dumping AOT code
|
||||
bool _closing; // Closing cache file
|
||||
bool _failed; // Failed read/write to/from cache (cache is broken?)
|
||||
bool _lookup_failed; // Failed to lookup for info (skip only this code load)
|
||||
|
||||
AOTCodeAddressTable* _table;
|
||||
|
||||
AOTCodeEntry* _load_entries; // Used when reading cache
|
||||
uint* _search_entries; // sorted by ID table [id, index]
|
||||
AOTCodeEntry* _store_entries; // Used when writing cache
|
||||
const char* _C_strings_buf; // Loaded buffer for _C_strings[] table
|
||||
uint _store_entries_cnt;
|
||||
|
||||
static AOTCodeCache* open_for_use();
|
||||
static AOTCodeCache* open_for_dump();
|
||||
|
||||
bool set_write_position(uint pos);
|
||||
bool align_write();
|
||||
address reserve_bytes(uint nbytes);
|
||||
uint write_bytes(const void* buffer, uint nbytes);
|
||||
const char* addr(uint offset) const { return _load_buffer + offset; }
|
||||
static AOTCodeAddressTable* addr_table() {
|
||||
return is_on() && (cache()->_table != nullptr) ? cache()->_table : nullptr;
|
||||
}
|
||||
|
||||
void set_lookup_failed() { _lookup_failed = true; }
|
||||
void clear_lookup_failed() { _lookup_failed = false; }
|
||||
bool lookup_failed() const { return _lookup_failed; }
|
||||
|
||||
public:
|
||||
AOTCodeCache(bool is_dumping, bool is_using);
|
||||
~AOTCodeCache();
|
||||
|
||||
const char* cache_buffer() const { return _load_buffer; }
|
||||
bool failed() const { return _failed; }
|
||||
void set_failed() { _failed = true; }
|
||||
|
||||
static uint max_aot_code_size();
|
||||
|
||||
uint load_size() const { return _load_size; }
|
||||
uint write_position() const { return _write_position; }
|
||||
|
||||
void load_strings();
|
||||
int store_strings();
|
||||
|
||||
static void init_extrs_table() NOT_CDS_RETURN;
|
||||
static void init_shared_blobs_table() NOT_CDS_RETURN;
|
||||
|
||||
address address_for_id(int id) const { return _table->address_for_id(id); }
|
||||
|
||||
bool for_use() const { return _for_use && !_failed; }
|
||||
bool for_dump() const { return _for_dump && !_failed; }
|
||||
|
||||
bool closing() const { return _closing; }
|
||||
|
||||
AOTCodeEntry* add_entry() {
|
||||
_store_entries_cnt++;
|
||||
_store_entries -= 1;
|
||||
return _store_entries;
|
||||
}
|
||||
|
||||
AOTCodeEntry* find_entry(AOTCodeEntry::Kind kind, uint id);
|
||||
|
||||
bool finish_write();
|
||||
|
||||
bool write_relocations(CodeBlob& code_blob);
|
||||
bool write_oop_map_set(CodeBlob& cb);
|
||||
|
||||
static bool store_code_blob(CodeBlob& blob,
|
||||
AOTCodeEntry::Kind entry_kind,
|
||||
uint id, const char* name,
|
||||
int entry_offset_count,
|
||||
int* entry_offsets) NOT_CDS_RETURN_(false);
|
||||
|
||||
static CodeBlob* load_code_blob(AOTCodeEntry::Kind kind,
|
||||
uint id, const char* name,
|
||||
int entry_offset_count,
|
||||
int* entry_offsets) NOT_CDS_RETURN_(nullptr);
|
||||
|
||||
static uint store_entries_cnt() {
|
||||
if (is_on_for_dump()) {
|
||||
return cache()->_store_entries_cnt;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Static access
|
||||
|
||||
private:
|
||||
static AOTCodeCache* _cache;
|
||||
|
||||
static bool open_cache(bool is_dumping, bool is_using);
|
||||
static bool verify_vm_config() {
|
||||
if (is_on_for_use()) {
|
||||
return _cache->_load_header->verify_vm_config();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
public:
|
||||
static AOTCodeCache* cache() { return _cache; }
|
||||
static void initialize() NOT_CDS_RETURN;
|
||||
static void init2() NOT_CDS_RETURN;
|
||||
static void close() NOT_CDS_RETURN;
|
||||
static bool is_on() CDS_ONLY({ return _cache != nullptr && !_cache->closing(); }) NOT_CDS_RETURN_(false);
|
||||
static bool is_on_for_use() { return is_on() && _cache->for_use(); }
|
||||
static bool is_on_for_dump() { return is_on() && _cache->for_dump(); }
|
||||
|
||||
static bool is_dumping_adapters() NOT_CDS_RETURN_(false);
|
||||
static bool is_using_adapters() NOT_CDS_RETURN_(false);
|
||||
|
||||
static const char* add_C_string(const char* str) NOT_CDS_RETURN_(str);
|
||||
|
||||
static void print_on(outputStream* st) NOT_CDS_RETURN;
|
||||
};
|
||||
|
||||
// Concurent AOT code reader
|
||||
class AOTCodeReader {
|
||||
private:
|
||||
const AOTCodeCache* _cache;
|
||||
const AOTCodeEntry* _entry;
|
||||
const char* _load_buffer; // Loaded cached code buffer
|
||||
uint _read_position; // Position in _load_buffer
|
||||
uint read_position() const { return _read_position; }
|
||||
void set_read_position(uint pos);
|
||||
const char* addr(uint offset) const { return _load_buffer + offset; }
|
||||
|
||||
bool _lookup_failed; // Failed to lookup for info (skip only this code load)
|
||||
void set_lookup_failed() { _lookup_failed = true; }
|
||||
void clear_lookup_failed() { _lookup_failed = false; }
|
||||
bool lookup_failed() const { return _lookup_failed; }
|
||||
|
||||
AOTCodeEntry* aot_code_entry() { return (AOTCodeEntry*)_entry; }
|
||||
public:
|
||||
AOTCodeReader(AOTCodeCache* cache, AOTCodeEntry* entry);
|
||||
|
||||
CodeBlob* compile_code_blob(const char* name, int entry_offset_count, int* entry_offsets);
|
||||
|
||||
ImmutableOopMapSet* read_oop_map_set();
|
||||
|
||||
void fix_relocations(CodeBlob* code_blob);
|
||||
};
|
||||
#endif // SHARE_CODE_AOTCODECACH_HPP
|
@ -78,9 +78,12 @@ const BufferBlob::Vptr BufferBlob::_vpntr;
|
||||
const RuntimeStub::Vptr RuntimeStub::_vpntr;
|
||||
const SingletonBlob::Vptr SingletonBlob::_vpntr;
|
||||
const DeoptimizationBlob::Vptr DeoptimizationBlob::_vpntr;
|
||||
#ifdef COMPILER2
|
||||
const ExceptionBlob::Vptr ExceptionBlob::_vpntr;
|
||||
#endif // COMPILER2
|
||||
const UpcallStub::Vptr UpcallStub::_vpntr;
|
||||
|
||||
const CodeBlob::Vptr* CodeBlob::vptr() const {
|
||||
const CodeBlob::Vptr* CodeBlob::vptr(CodeBlobKind kind) {
|
||||
constexpr const CodeBlob::Vptr* array[(size_t)CodeBlobKind::Number_Of_Kinds] = {
|
||||
nullptr/* None */,
|
||||
&nmethod::_vpntr,
|
||||
@ -98,7 +101,11 @@ const CodeBlob::Vptr* CodeBlob::vptr() const {
|
||||
&UpcallStub::_vpntr
|
||||
};
|
||||
|
||||
return array[(size_t)_kind];
|
||||
return array[(size_t)kind];
|
||||
}
|
||||
|
||||
const CodeBlob::Vptr* CodeBlob::vptr() const {
|
||||
return vptr(_kind);
|
||||
}
|
||||
|
||||
unsigned int CodeBlob::align_code_offset(int offset) {
|
||||
@ -181,6 +188,19 @@ CodeBlob::CodeBlob(const char* name, CodeBlobKind kind, int size, uint16_t heade
|
||||
assert(_mutable_data = blob_end(), "sanity");
|
||||
}
|
||||
|
||||
void CodeBlob::restore_mutable_data(address reloc_data) {
|
||||
// Relocation data is now stored as part of the mutable data area; allocate it before copy relocations
|
||||
if (_mutable_data_size > 0) {
|
||||
_mutable_data = (address)os::malloc(_mutable_data_size, mtCode);
|
||||
if (_mutable_data == nullptr) {
|
||||
vm_exit_out_of_memory(_mutable_data_size, OOM_MALLOC_ERROR, "codebuffer: no space for mutable data");
|
||||
}
|
||||
}
|
||||
if (_relocation_size > 0) {
|
||||
memcpy((address)relocation_begin(), reloc_data, relocation_size());
|
||||
}
|
||||
}
|
||||
|
||||
void CodeBlob::purge() {
|
||||
assert(_mutable_data != nullptr, "should never be null");
|
||||
if (_mutable_data != blob_end()) {
|
||||
@ -215,6 +235,68 @@ void CodeBlob::print_code_on(outputStream* st) {
|
||||
Disassembler::decode(this, st);
|
||||
}
|
||||
|
||||
void CodeBlob::prepare_for_archiving_impl() {
|
||||
set_name(nullptr);
|
||||
_oop_maps = nullptr;
|
||||
_mutable_data = nullptr;
|
||||
#ifndef PRODUCT
|
||||
asm_remarks().clear();
|
||||
dbg_strings().clear();
|
||||
#endif /* PRODUCT */
|
||||
}
|
||||
|
||||
void CodeBlob::prepare_for_archiving() {
|
||||
vptr(_kind)->prepare_for_archiving(this);
|
||||
}
|
||||
|
||||
void CodeBlob::archive_blob(CodeBlob* blob, address archive_buffer) {
|
||||
blob->copy_to(archive_buffer);
|
||||
CodeBlob* archived_blob = (CodeBlob*)archive_buffer;
|
||||
archived_blob->prepare_for_archiving();
|
||||
}
|
||||
|
||||
void CodeBlob::post_restore_impl() {
|
||||
// Track memory usage statistic after releasing CodeCache_lock
|
||||
MemoryService::track_code_cache_memory_usage();
|
||||
}
|
||||
|
||||
void CodeBlob::post_restore() {
|
||||
vptr(_kind)->post_restore(this);
|
||||
}
|
||||
|
||||
CodeBlob* CodeBlob::restore(address code_cache_buffer, const char* name, address archived_reloc_data, ImmutableOopMapSet* archived_oop_maps) {
|
||||
copy_to(code_cache_buffer);
|
||||
CodeBlob* code_blob = (CodeBlob*)code_cache_buffer;
|
||||
code_blob->set_name(name);
|
||||
code_blob->restore_mutable_data(archived_reloc_data);
|
||||
code_blob->set_oop_maps(archived_oop_maps);
|
||||
return code_blob;
|
||||
}
|
||||
|
||||
CodeBlob* CodeBlob::create(CodeBlob* archived_blob, const char* name, address archived_reloc_data, ImmutableOopMapSet* archived_oop_maps) {
|
||||
ThreadInVMfromUnknown __tiv; // get to VM state in case we block on CodeCache_lock
|
||||
|
||||
CodeCache::gc_on_allocation();
|
||||
|
||||
CodeBlob* blob = nullptr;
|
||||
unsigned int size = archived_blob->size();
|
||||
{
|
||||
MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
|
||||
address code_cache_buffer = (address)CodeCache::allocate(size, CodeBlobType::NonNMethod);
|
||||
if (code_cache_buffer != nullptr) {
|
||||
blob = archived_blob->restore(code_cache_buffer, name, archived_reloc_data, archived_oop_maps);
|
||||
assert(blob != nullptr, "sanity check");
|
||||
// Flush the code block
|
||||
ICache::invalidate_range(blob->code_begin(), blob->code_size());
|
||||
CodeCache::commit(blob); // Count adapters
|
||||
}
|
||||
}
|
||||
if (blob != nullptr) {
|
||||
blob->post_restore();
|
||||
}
|
||||
return blob;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------------
|
||||
// Creates a RuntimeBlob from a CodeBuffer and copy code and relocation info.
|
||||
|
||||
@ -720,7 +802,7 @@ void CodeBlob::print_value_on(outputStream* st) const {
|
||||
}
|
||||
|
||||
void CodeBlob::print_on_impl(outputStream* st) const {
|
||||
st->print_cr("[CodeBlob (" INTPTR_FORMAT ")]", p2i(this));
|
||||
st->print_cr("[CodeBlob kind:%d (" INTPTR_FORMAT ")]", (int)_kind, p2i(this));
|
||||
st->print_cr("Framesize: %d", _frame_size);
|
||||
}
|
||||
|
||||
|
@ -97,11 +97,16 @@ enum class CodeBlobKind : u1 {
|
||||
class UpcallStub; // for as_upcall_stub()
|
||||
class RuntimeStub; // for as_runtime_stub()
|
||||
class JavaFrameAnchor; // for UpcallStub::jfa_for_frame
|
||||
class AdapterBlob;
|
||||
class ExceptionBlob;
|
||||
|
||||
class CodeBlob {
|
||||
friend class VMStructs;
|
||||
friend class JVMCIVMStructs;
|
||||
|
||||
private:
|
||||
void restore_mutable_data(address reloc_data);
|
||||
|
||||
protected:
|
||||
// order fields from large to small to minimize padding between fields
|
||||
ImmutableOopMapSet* _oop_maps; // OopMap for this CodeBlob
|
||||
@ -140,8 +145,15 @@ protected:
|
||||
public:
|
||||
virtual void print_on(const CodeBlob* instance, outputStream* st) const = 0;
|
||||
virtual void print_value_on(const CodeBlob* instance, outputStream* st) const = 0;
|
||||
virtual void prepare_for_archiving(CodeBlob* instance) const {
|
||||
instance->prepare_for_archiving_impl();
|
||||
};
|
||||
virtual void post_restore(CodeBlob* instance) const {
|
||||
instance->post_restore_impl();
|
||||
};
|
||||
};
|
||||
|
||||
static const Vptr* vptr(CodeBlobKind kind);
|
||||
const Vptr* vptr() const;
|
||||
|
||||
CodeBlob(const char* name, CodeBlobKind kind, CodeBuffer* cb, int size, uint16_t header_size,
|
||||
@ -151,8 +163,12 @@ protected:
|
||||
// Simple CodeBlob used for simple BufferBlob.
|
||||
CodeBlob(const char* name, CodeBlobKind kind, int size, uint16_t header_size);
|
||||
|
||||
|
||||
void operator delete(void* p) { }
|
||||
|
||||
void prepare_for_archiving_impl();
|
||||
void post_restore_impl();
|
||||
|
||||
public:
|
||||
|
||||
~CodeBlob() {
|
||||
@ -188,6 +204,7 @@ public:
|
||||
nmethod* as_nmethod_or_null() const { return is_nmethod() ? (nmethod*) this : nullptr; }
|
||||
nmethod* as_nmethod() const { assert(is_nmethod(), "must be nmethod"); return (nmethod*) this; }
|
||||
CodeBlob* as_codeblob() const { return (CodeBlob*) this; }
|
||||
AdapterBlob* as_adapter_blob() const { assert(is_adapter_blob(), "must be adapter blob"); return (AdapterBlob*) this; }
|
||||
UpcallStub* as_upcall_stub() const { assert(is_upcall_stub(), "must be upcall stub"); return (UpcallStub*) this; }
|
||||
RuntimeStub* as_runtime_stub() const { assert(is_runtime_stub(), "must be runtime blob"); return (RuntimeStub*) this; }
|
||||
|
||||
@ -244,6 +261,7 @@ public:
|
||||
// OopMap for frame
|
||||
ImmutableOopMapSet* oop_maps() const { return _oop_maps; }
|
||||
void set_oop_maps(OopMapSet* p);
|
||||
void set_oop_maps(ImmutableOopMapSet* p) { _oop_maps = p; }
|
||||
|
||||
const ImmutableOopMap* oop_map_for_slot(int slot, address return_address) const;
|
||||
const ImmutableOopMap* oop_map_for_return_address(address return_address) const;
|
||||
@ -278,6 +296,19 @@ public:
|
||||
void use_remarks(AsmRemarks &remarks) { _asm_remarks.share(remarks); }
|
||||
void use_strings(DbgStrings &strings) { _dbg_strings.share(strings); }
|
||||
#endif
|
||||
|
||||
void copy_to(address buffer) {
|
||||
memcpy(buffer, this, this->size());
|
||||
}
|
||||
|
||||
// methods to archive a blob into AOT code cache
|
||||
void prepare_for_archiving();
|
||||
static void archive_blob(CodeBlob* blob, address archive_buffer);
|
||||
|
||||
// methods to restore a blob from AOT code cache into the CodeCache
|
||||
void post_restore();
|
||||
CodeBlob* restore(address code_cache_buffer, const char* name, address archived_reloc_data, ImmutableOopMapSet* archived_oop_maps);
|
||||
static CodeBlob* create(CodeBlob* archived_blob, const char* name, address archived_reloc_data, ImmutableOopMapSet* archived_oop_maps);
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
@ -617,6 +648,18 @@ class ExceptionBlob: public SingletonBlob {
|
||||
OopMapSet* oop_maps,
|
||||
int frame_size
|
||||
);
|
||||
|
||||
void post_restore_impl() {
|
||||
trace_new_stub(this, "ExceptionBlob");
|
||||
}
|
||||
|
||||
class Vptr : public SingletonBlob::Vptr {
|
||||
void post_restore(CodeBlob* instance) const override {
|
||||
((ExceptionBlob*)instance)->post_restore_impl();
|
||||
}
|
||||
};
|
||||
|
||||
static const Vptr _vpntr;
|
||||
};
|
||||
#endif // COMPILER2
|
||||
|
||||
|
@ -3243,7 +3243,7 @@ void nmethod::print_relocations() {
|
||||
ResourceMark m; // in case methods get printed via the debugger
|
||||
tty->print_cr("relocations:");
|
||||
RelocIterator iter(this);
|
||||
iter.print();
|
||||
iter.print_on(tty);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -179,8 +179,31 @@ RelocIterator::RelocIterator(CodeSection* cs, address begin, address limit) {
|
||||
set_limits(begin, limit);
|
||||
}
|
||||
|
||||
RelocIterator::RelocIterator(CodeBlob* cb) {
|
||||
initialize_misc();
|
||||
if (cb->is_nmethod()) {
|
||||
_code = cb->as_nmethod();
|
||||
} else {
|
||||
_code = nullptr;
|
||||
}
|
||||
_current = cb->relocation_begin() - 1;
|
||||
_end = cb->relocation_end();
|
||||
_addr = cb->content_begin();
|
||||
|
||||
_section_start[CodeBuffer::SECT_CONSTS] = cb->content_begin();
|
||||
_section_start[CodeBuffer::SECT_INSTS] = cb->code_begin();
|
||||
|
||||
_section_end[CodeBuffer::SECT_CONSTS] = cb->code_begin();
|
||||
_section_start[CodeBuffer::SECT_INSTS] = cb->code_end();
|
||||
assert(!has_current(), "just checking");
|
||||
set_limits(nullptr, nullptr);
|
||||
}
|
||||
|
||||
bool RelocIterator::addr_in_const() const {
|
||||
const int n = CodeBuffer::SECT_CONSTS;
|
||||
if (_section_start[n] == nullptr) {
|
||||
return false;
|
||||
}
|
||||
return section_start(n) <= addr() && addr() < section_end(n);
|
||||
}
|
||||
|
||||
@ -471,7 +494,9 @@ void trampoline_stub_Relocation::unpack_data() {
|
||||
void external_word_Relocation::pack_data_to(CodeSection* dest) {
|
||||
short* p = (short*) dest->locs_end();
|
||||
int index = ExternalsRecorder::find_index(_target);
|
||||
p = pack_1_int_to(p, index);
|
||||
// Use 4 bytes to store index to be able patch it when
|
||||
// updating relocations in AOTCodeReader::read_relocations().
|
||||
p = add_jint(p, index);
|
||||
dest->set_locs_end((relocInfo*) p);
|
||||
}
|
||||
|
||||
@ -766,6 +791,14 @@ void internal_word_Relocation::fix_relocation_after_move(const CodeBuffer* src,
|
||||
set_value(target);
|
||||
}
|
||||
|
||||
void internal_word_Relocation::fix_relocation_after_aot_load(address orig_base_addr, address current_base_addr) {
|
||||
address target = _target;
|
||||
if (target == nullptr) {
|
||||
target = this->target();
|
||||
target = current_base_addr + (target - orig_base_addr);
|
||||
}
|
||||
set_value(target);
|
||||
}
|
||||
|
||||
address internal_word_Relocation::target() {
|
||||
address target = _target;
|
||||
@ -779,12 +812,7 @@ address internal_word_Relocation::target() {
|
||||
return target;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
// Non-product code
|
||||
|
||||
#ifndef PRODUCT
|
||||
|
||||
static const char* reloc_type_string(relocInfo::relocType t) {
|
||||
const char* relocInfo::type_name(relocInfo::relocType t) {
|
||||
switch (t) {
|
||||
#define EACH_CASE(name) \
|
||||
case relocInfo::name##_type: \
|
||||
@ -802,26 +830,25 @@ static const char* reloc_type_string(relocInfo::relocType t) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void RelocIterator::print_current() {
|
||||
void RelocIterator::print_current_on(outputStream* st) {
|
||||
if (!has_current()) {
|
||||
tty->print_cr("(no relocs)");
|
||||
st->print_cr("(no relocs)");
|
||||
return;
|
||||
}
|
||||
tty->print("relocInfo@" INTPTR_FORMAT " [type=%d(%s) addr=" INTPTR_FORMAT " offset=%d",
|
||||
p2i(_current), type(), reloc_type_string((relocInfo::relocType) type()), p2i(_addr), _current->addr_offset());
|
||||
st->print("relocInfo@" INTPTR_FORMAT " [type=%d(%s) addr=" INTPTR_FORMAT " offset=%d",
|
||||
p2i(_current), type(), relocInfo::type_name((relocInfo::relocType) type()), p2i(_addr), _current->addr_offset());
|
||||
if (current()->format() != 0)
|
||||
tty->print(" format=%d", current()->format());
|
||||
st->print(" format=%d", current()->format());
|
||||
if (datalen() == 1) {
|
||||
tty->print(" data=%d", data()[0]);
|
||||
st->print(" data=%d", data()[0]);
|
||||
} else if (datalen() > 0) {
|
||||
tty->print(" data={");
|
||||
st->print(" data={");
|
||||
for (int i = 0; i < datalen(); i++) {
|
||||
tty->print("%04x", data()[i] & 0xFFFF);
|
||||
st->print("%04x", data()[i] & 0xFFFF);
|
||||
}
|
||||
tty->print("}");
|
||||
st->print("}");
|
||||
}
|
||||
tty->print("]");
|
||||
st->print("]");
|
||||
switch (type()) {
|
||||
case relocInfo::oop_type:
|
||||
{
|
||||
@ -834,14 +861,14 @@ void RelocIterator::print_current() {
|
||||
raw_oop = *oop_addr;
|
||||
oop_value = r->oop_value();
|
||||
}
|
||||
tty->print(" | [oop_addr=" INTPTR_FORMAT " *=" INTPTR_FORMAT "]",
|
||||
st->print(" | [oop_addr=" INTPTR_FORMAT " *=" INTPTR_FORMAT "]",
|
||||
p2i(oop_addr), p2i(raw_oop));
|
||||
// Do not print the oop by default--we want this routine to
|
||||
// work even during GC or other inconvenient times.
|
||||
if (WizardMode && oop_value != nullptr) {
|
||||
tty->print("oop_value=" INTPTR_FORMAT ": ", p2i(oop_value));
|
||||
st->print("oop_value=" INTPTR_FORMAT ": ", p2i(oop_value));
|
||||
if (oopDesc::is_oop(oop_value)) {
|
||||
oop_value->print_value_on(tty);
|
||||
oop_value->print_value_on(st);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -857,11 +884,11 @@ void RelocIterator::print_current() {
|
||||
raw_metadata = *metadata_addr;
|
||||
metadata_value = r->metadata_value();
|
||||
}
|
||||
tty->print(" | [metadata_addr=" INTPTR_FORMAT " *=" INTPTR_FORMAT "]",
|
||||
st->print(" | [metadata_addr=" INTPTR_FORMAT " *=" INTPTR_FORMAT "]",
|
||||
p2i(metadata_addr), p2i(raw_metadata));
|
||||
if (metadata_value != nullptr) {
|
||||
tty->print("metadata_value=" INTPTR_FORMAT ": ", p2i(metadata_value));
|
||||
metadata_value->print_value_on(tty);
|
||||
st->print("metadata_value=" INTPTR_FORMAT ": ", p2i(metadata_value));
|
||||
metadata_value->print_value_on(st);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -870,17 +897,17 @@ void RelocIterator::print_current() {
|
||||
case relocInfo::section_word_type:
|
||||
{
|
||||
DataRelocation* r = (DataRelocation*) reloc();
|
||||
tty->print(" | [target=" INTPTR_FORMAT "]", p2i(r->value())); //value==target
|
||||
st->print(" | [target=" INTPTR_FORMAT "]", p2i(r->value())); //value==target
|
||||
break;
|
||||
}
|
||||
case relocInfo::static_call_type:
|
||||
{
|
||||
static_call_Relocation* r = (static_call_Relocation*) reloc();
|
||||
tty->print(" | [destination=" INTPTR_FORMAT " metadata=" INTPTR_FORMAT "]",
|
||||
st->print(" | [destination=" INTPTR_FORMAT " metadata=" INTPTR_FORMAT "]",
|
||||
p2i(r->destination()), p2i(r->method_value()));
|
||||
CodeBlob* cb = CodeCache::find_blob(r->destination());
|
||||
if (cb != nullptr) {
|
||||
tty->print(" Blob::%s", cb->name());
|
||||
st->print(" Blob::%s", cb->name());
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -889,28 +916,28 @@ void RelocIterator::print_current() {
|
||||
{
|
||||
CallRelocation* r = (CallRelocation*) reloc();
|
||||
address dest = r->destination();
|
||||
tty->print(" | [destination=" INTPTR_FORMAT "]", p2i(dest));
|
||||
st->print(" | [destination=" INTPTR_FORMAT "]", p2i(dest));
|
||||
if (StubRoutines::contains(dest)) {
|
||||
StubCodeDesc* desc = StubCodeDesc::desc_for(dest);
|
||||
if (desc == nullptr) {
|
||||
desc = StubCodeDesc::desc_for(dest + frame::pc_return_offset);
|
||||
}
|
||||
if (desc != nullptr) {
|
||||
tty->print(" Stub::%s", desc->name());
|
||||
st->print(" Stub::%s", desc->name());
|
||||
}
|
||||
} else {
|
||||
CodeBlob* cb = CodeCache::find_blob(dest);
|
||||
if (cb != nullptr) {
|
||||
tty->print(" %s", cb->name());
|
||||
st->print(" %s", cb->name());
|
||||
} else {
|
||||
ResourceMark rm;
|
||||
const int buflen = 1024;
|
||||
char* buf = NEW_RESOURCE_ARRAY(char, buflen);
|
||||
int offset;
|
||||
if (os::dll_address_to_function_name(dest, buf, buflen, &offset)) {
|
||||
tty->print(" %s", buf);
|
||||
st->print(" %s", buf);
|
||||
if (offset != 0) {
|
||||
tty->print("+%d", offset);
|
||||
st->print("+%d", offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -920,45 +947,45 @@ void RelocIterator::print_current() {
|
||||
case relocInfo::virtual_call_type:
|
||||
{
|
||||
virtual_call_Relocation* r = (virtual_call_Relocation*) reloc();
|
||||
tty->print(" | [destination=" INTPTR_FORMAT " cached_value=" INTPTR_FORMAT " metadata=" INTPTR_FORMAT "]",
|
||||
st->print(" | [destination=" INTPTR_FORMAT " cached_value=" INTPTR_FORMAT " metadata=" INTPTR_FORMAT "]",
|
||||
p2i(r->destination()), p2i(r->cached_value()), p2i(r->method_value()));
|
||||
CodeBlob* cb = CodeCache::find_blob(r->destination());
|
||||
if (cb != nullptr) {
|
||||
tty->print(" Blob::%s", cb->name());
|
||||
st->print(" Blob::%s", cb->name());
|
||||
}
|
||||
break;
|
||||
}
|
||||
case relocInfo::static_stub_type:
|
||||
{
|
||||
static_stub_Relocation* r = (static_stub_Relocation*) reloc();
|
||||
tty->print(" | [static_call=" INTPTR_FORMAT "]", p2i(r->static_call()));
|
||||
st->print(" | [static_call=" INTPTR_FORMAT "]", p2i(r->static_call()));
|
||||
break;
|
||||
}
|
||||
case relocInfo::trampoline_stub_type:
|
||||
{
|
||||
trampoline_stub_Relocation* r = (trampoline_stub_Relocation*) reloc();
|
||||
tty->print(" | [trampoline owner=" INTPTR_FORMAT "]", p2i(r->owner()));
|
||||
st->print(" | [trampoline owner=" INTPTR_FORMAT "]", p2i(r->owner()));
|
||||
break;
|
||||
}
|
||||
case relocInfo::opt_virtual_call_type:
|
||||
{
|
||||
opt_virtual_call_Relocation* r = (opt_virtual_call_Relocation*) reloc();
|
||||
tty->print(" | [destination=" INTPTR_FORMAT " metadata=" INTPTR_FORMAT "]",
|
||||
st->print(" | [destination=" INTPTR_FORMAT " metadata=" INTPTR_FORMAT "]",
|
||||
p2i(r->destination()), p2i(r->method_value()));
|
||||
CodeBlob* cb = CodeCache::find_blob(r->destination());
|
||||
if (cb != nullptr) {
|
||||
tty->print(" Blob::%s", cb->name());
|
||||
st->print(" Blob::%s", cb->name());
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
tty->cr();
|
||||
st->cr();
|
||||
}
|
||||
|
||||
|
||||
void RelocIterator::print() {
|
||||
void RelocIterator::print_on(outputStream* st) {
|
||||
RelocIterator save_this = (*this);
|
||||
relocInfo* scan = _current;
|
||||
if (!has_current()) scan += 1; // nothing to scan here!
|
||||
@ -969,32 +996,37 @@ void RelocIterator::print() {
|
||||
got_next = (skip_next || next());
|
||||
skip_next = false;
|
||||
|
||||
tty->print(" @" INTPTR_FORMAT ": ", p2i(scan));
|
||||
st->print(" @" INTPTR_FORMAT ": ", p2i(scan));
|
||||
relocInfo* newscan = _current+1;
|
||||
if (!has_current()) newscan -= 1; // nothing to scan here!
|
||||
while (scan < newscan) {
|
||||
tty->print("%04x", *(short*)scan & 0xFFFF);
|
||||
st->print("%04x", *(short*)scan & 0xFFFF);
|
||||
scan++;
|
||||
}
|
||||
tty->cr();
|
||||
st->cr();
|
||||
|
||||
if (!got_next) break;
|
||||
print_current();
|
||||
print_current_on(st);
|
||||
}
|
||||
|
||||
(*this) = save_this;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
// Non-product code
|
||||
|
||||
#ifndef PRODUCT
|
||||
|
||||
// For the debugger:
|
||||
extern "C"
|
||||
void print_blob_locs(nmethod* nm) {
|
||||
nm->print();
|
||||
RelocIterator iter(nm);
|
||||
iter.print();
|
||||
iter.print_on(tty);
|
||||
}
|
||||
extern "C"
|
||||
void print_buf_locs(CodeBuffer* cb) {
|
||||
FlagSetting fs(PrintRelocations, true);
|
||||
cb->print();
|
||||
cb->print_on(tty);
|
||||
}
|
||||
#endif // !PRODUCT
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -451,6 +451,8 @@ class relocInfo {
|
||||
length_limit = 1 + 1 + (3*BytesPerWord/BytesPerShort) + 1,
|
||||
have_format = format_width > 0
|
||||
};
|
||||
|
||||
static const char* type_name(relocInfo::relocType t);
|
||||
};
|
||||
|
||||
#define FORWARD_DECLARE_EACH_CLASS(name) \
|
||||
@ -600,6 +602,7 @@ class RelocIterator : public StackObj {
|
||||
// constructor
|
||||
RelocIterator(nmethod* nm, address begin = nullptr, address limit = nullptr);
|
||||
RelocIterator(CodeSection* cb, address begin = nullptr, address limit = nullptr);
|
||||
RelocIterator(CodeBlob* cb);
|
||||
|
||||
// get next reloc info, return !eos
|
||||
bool next() {
|
||||
@ -638,11 +641,11 @@ class RelocIterator : public StackObj {
|
||||
bool addr_in_const() const;
|
||||
|
||||
address section_start(int n) const {
|
||||
assert(_section_start[n], "must be initialized");
|
||||
assert(_section_start[n], "section %d must be initialized", n);
|
||||
return _section_start[n];
|
||||
}
|
||||
address section_end(int n) const {
|
||||
assert(_section_end[n], "must be initialized");
|
||||
assert(_section_end[n], "section %d must be initialized", n);
|
||||
return _section_end[n];
|
||||
}
|
||||
|
||||
@ -658,11 +661,9 @@ class RelocIterator : public StackObj {
|
||||
// generic relocation accessor; switches on type to call the above
|
||||
Relocation* reloc();
|
||||
|
||||
#ifndef PRODUCT
|
||||
public:
|
||||
void print();
|
||||
void print_current();
|
||||
#endif
|
||||
void print_on(outputStream* st);
|
||||
void print_current_on(outputStream* st);
|
||||
};
|
||||
|
||||
|
||||
@ -672,6 +673,7 @@ class RelocIterator : public StackObj {
|
||||
|
||||
class Relocation {
|
||||
friend class RelocIterator;
|
||||
friend class AOTCodeReader;
|
||||
|
||||
private:
|
||||
// When a relocation has been created by a RelocIterator,
|
||||
@ -1377,6 +1379,8 @@ class internal_word_Relocation : public DataRelocation {
|
||||
void unpack_data() override;
|
||||
|
||||
void fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) override;
|
||||
void fix_relocation_after_aot_load(address orig_base_addr, address current_base_addr);
|
||||
|
||||
address target(); // if _target==nullptr, fetch addr from code stream
|
||||
int section() { return _section; }
|
||||
address value() override { return target(); }
|
||||
|
@ -729,7 +729,6 @@ bool ImmutableOopMap::has_any(OopMapValue::oop_types type) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef ASSERT
|
||||
int ImmutableOopMap::nr_of_bytes() const {
|
||||
OopMapStream oms(this);
|
||||
|
||||
@ -738,7 +737,6 @@ int ImmutableOopMap::nr_of_bytes() const {
|
||||
}
|
||||
return sizeof(ImmutableOopMap) + oms.stream_position();
|
||||
}
|
||||
#endif
|
||||
|
||||
ImmutableOopMapBuilder::ImmutableOopMapBuilder(const OopMapSet* set) : _set(set), _empty(nullptr), _last(nullptr), _empty_offset(-1), _last_offset(-1), _offset(0), _required(-1), _new_set(nullptr) {
|
||||
_mapping = NEW_RESOURCE_ARRAY(Mapping, _set->size());
|
||||
|
@ -292,9 +292,7 @@ public:
|
||||
bool has_derived_oops() const { return _has_derived_oops; }
|
||||
bool has_any(OopMapValue::oop_types type) const;
|
||||
|
||||
#ifdef ASSERT
|
||||
int nr_of_bytes() const; // this is an expensive operation, only used in debug builds
|
||||
#endif
|
||||
int nr_of_bytes() const; // this is an expensive operation, only used in debug builds or in aot code generation
|
||||
|
||||
void oops_do(const frame* fr, const RegisterMap* reg_map, OopClosure* f, DerivedOopClosure* df) const;
|
||||
void oops_do(const frame* fr, const RegisterMap* reg_map, OopClosure* f, DerivedPointerIterationMode derived_mode) const;
|
||||
@ -378,9 +376,7 @@ class OopMapStream : public StackObj {
|
||||
bool is_done() { if(!_valid_omv) { find_next(); } return !_valid_omv; }
|
||||
void next() { find_next(); }
|
||||
OopMapValue current() { return _omv; }
|
||||
#ifdef ASSERT
|
||||
int stream_position() const { return _stream.position(); }
|
||||
#endif
|
||||
};
|
||||
|
||||
class ImmutableOopMapBuilder {
|
||||
|
@ -35,12 +35,12 @@
|
||||
//
|
||||
// Also, this is a C header file. Do not use C++ here.
|
||||
|
||||
#define NUM_CDS_REGIONS 4 // this must be the same as MetaspaceShared::n_regions
|
||||
#define NUM_CDS_REGIONS 5 // this must be the same as MetaspaceShared::n_regions
|
||||
#define CDS_ARCHIVE_MAGIC 0xf00baba2
|
||||
#define CDS_DYNAMIC_ARCHIVE_MAGIC 0xf00baba8
|
||||
#define CDS_PREIMAGE_ARCHIVE_MAGIC 0xcafea07c
|
||||
#define CDS_GENERIC_HEADER_SUPPORTED_MIN_VERSION 13
|
||||
#define CURRENT_CDS_ARCHIVE_VERSION 18
|
||||
#define CURRENT_CDS_ARCHIVE_VERSION 19
|
||||
|
||||
typedef struct CDSFileMapRegion {
|
||||
int _crc; // CRC checksum of this region.
|
||||
|
@ -314,7 +314,9 @@ class MetaspaceObj {
|
||||
f(ConstantPoolCache) \
|
||||
f(Annotations) \
|
||||
f(MethodCounters) \
|
||||
f(RecordComponent)
|
||||
f(RecordComponent) \
|
||||
f(AdapterHandlerEntry) \
|
||||
f(AdapterFingerPrint)
|
||||
|
||||
#define METASPACE_OBJ_TYPE_DECLARE(name) name ## Type,
|
||||
#define METASPACE_OBJ_TYPE_NAME_CASE(name) case name ## Type: return #name;
|
||||
|
@ -396,6 +396,11 @@ bool VirtualMemoryTracker::add_reserved_region(address base_addr, size_t size,
|
||||
return true;
|
||||
}
|
||||
|
||||
if (reserved_rgn->mem_tag() == mtCode) {
|
||||
assert(reserved_rgn->contain_region(base_addr, size), "Reserved code region should contain this mapping region");
|
||||
return true;
|
||||
}
|
||||
|
||||
// Print some more details. Don't use UL here to avoid circularities.
|
||||
tty->print_cr("Error: existing region: [" INTPTR_FORMAT "-" INTPTR_FORMAT "), memory tag %u.\n"
|
||||
" new region: [" INTPTR_FORMAT "-" INTPTR_FORMAT "), memory tag %u.",
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include "classfile/symbolTable.hpp"
|
||||
#include "classfile/systemDictionary.hpp"
|
||||
#include "classfile/vmClasses.hpp"
|
||||
#include "code/aotCodeCache.hpp"
|
||||
#include "code/codeCache.hpp"
|
||||
#include "code/debugInfoRec.hpp"
|
||||
#include "compiler/compilationPolicy.hpp"
|
||||
@ -392,6 +393,7 @@ void Method::metaspace_pointers_do(MetaspaceClosure* it) {
|
||||
} else {
|
||||
it->push(&_constMethod);
|
||||
}
|
||||
it->push(&_adapter);
|
||||
it->push(&_method_data);
|
||||
it->push(&_method_counters);
|
||||
NOT_PRODUCT(it->push(&_name);)
|
||||
@ -405,11 +407,18 @@ void Method::metaspace_pointers_do(MetaspaceClosure* it) {
|
||||
|
||||
void Method::remove_unshareable_info() {
|
||||
unlink_method();
|
||||
if (AOTCodeCache::is_dumping_adapters() && _adapter != nullptr) {
|
||||
_adapter->remove_unshareable_info();
|
||||
}
|
||||
JFR_ONLY(REMOVE_METHOD_ID(this);)
|
||||
}
|
||||
|
||||
void Method::restore_unshareable_info(TRAPS) {
|
||||
assert(is_method() && is_valid_method(this), "ensure C++ vtable is restored");
|
||||
if (_adapter != nullptr) {
|
||||
assert(_adapter->is_linked(), "must be");
|
||||
_from_compiled_entry = _adapter->get_c2i_entry();
|
||||
}
|
||||
assert(!queued_for_compilation(), "method's queued_for_compilation flag should not be set");
|
||||
}
|
||||
#endif
|
||||
@ -1137,7 +1146,9 @@ void Method::unlink_code() {
|
||||
void Method::unlink_method() {
|
||||
assert(CDSConfig::is_dumping_archive(), "sanity");
|
||||
_code = nullptr;
|
||||
_adapter = nullptr;
|
||||
if (!AOTCodeCache::is_dumping_adapters() || AdapterHandlerLibrary::is_abstract_method_adapter(_adapter)) {
|
||||
_adapter = nullptr;
|
||||
}
|
||||
_i2i_entry = nullptr;
|
||||
_from_compiled_entry = nullptr;
|
||||
_from_interpreted_entry = nullptr;
|
||||
@ -1178,14 +1189,18 @@ void Method::link_method(const methodHandle& h_method, TRAPS) {
|
||||
// If the code cache is full, we may reenter this function for the
|
||||
// leftover methods that weren't linked.
|
||||
if (adapter() != nullptr) {
|
||||
return;
|
||||
if (adapter()->is_shared()) {
|
||||
assert(adapter()->is_linked(), "Adapter is shared but not linked");
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
assert( _code == nullptr, "nothing compiled yet" );
|
||||
|
||||
// Setup interpreter entrypoint
|
||||
assert(this == h_method(), "wrong h_method()" );
|
||||
|
||||
assert(adapter() == nullptr, "init'd to null");
|
||||
assert(adapter() == nullptr || adapter()->is_linked(), "init'd to null or restored from cache");
|
||||
address entry = Interpreter::entry_for_method(h_method);
|
||||
assert(entry != nullptr, "interpreter entry must be non-null");
|
||||
// Sets both _i2i_entry and _from_interpreted_entry
|
||||
@ -1206,7 +1221,10 @@ void Method::link_method(const methodHandle& h_method, TRAPS) {
|
||||
// called from the vtable. We need adapters on such methods that get loaded
|
||||
// later. Ditto for mega-morphic itable calls. If this proves to be a
|
||||
// problem we'll make these lazily later.
|
||||
(void) make_adapters(h_method, CHECK);
|
||||
if (_adapter == nullptr) {
|
||||
(void) make_adapters(h_method, CHECK);
|
||||
assert(adapter()->is_linked(), "Adapter must have been linked");
|
||||
}
|
||||
|
||||
// ONLY USE the h_method now as make_adapter may have blocked
|
||||
|
||||
@ -1482,6 +1500,9 @@ methodHandle Method::make_method_handle_intrinsic(vmIntrinsics::ID iid,
|
||||
|
||||
#if INCLUDE_CDS
|
||||
void Method::restore_archived_method_handle_intrinsic(methodHandle m, TRAPS) {
|
||||
if (m->adapter() != nullptr) {
|
||||
m->set_from_compiled_entry(m->adapter()->get_c2i_entry());
|
||||
}
|
||||
m->link_method(m, CHECK);
|
||||
|
||||
if (m->intrinsic_id() == vmIntrinsics::_linkToNative) {
|
||||
|
@ -113,6 +113,7 @@ enum class OptoStubId :int {
|
||||
|
||||
class OptoRuntime : public AllStatic {
|
||||
friend class Matcher; // allow access to stub names
|
||||
friend class AOTCodeAddressTable;
|
||||
|
||||
private:
|
||||
// declare opto stub address/blob holder static fields
|
||||
|
@ -24,6 +24,7 @@
|
||||
|
||||
#include "classfile/stringTable.hpp"
|
||||
#include "classfile/symbolTable.hpp"
|
||||
#include "code/aotCodeCache.hpp"
|
||||
#include "compiler/compiler_globals.hpp"
|
||||
#include "gc/shared/collectedHeap.hpp"
|
||||
#include "gc/shared/gcHeapSummary.hpp"
|
||||
@ -143,7 +144,7 @@ jint init_globals() {
|
||||
LSAN_REGISTER_ROOT_REGION(summary.start(), summary.reserved_size());
|
||||
}
|
||||
#endif // LEAK_SANITIZER
|
||||
|
||||
AOTCodeCache::init2(); // depends on universe_init
|
||||
AsyncLogWriter::initialize();
|
||||
gc_barrier_stubs_init(); // depends on universe_init, must be before interpreter_init
|
||||
continuations_init(); // must precede continuation stub generation
|
||||
@ -156,6 +157,8 @@ jint init_globals() {
|
||||
InterfaceSupport_init();
|
||||
VMRegImpl::set_regName(); // need this before generate_stubs (for printing oop maps).
|
||||
SharedRuntime::generate_stubs();
|
||||
AOTCodeCache::init_shared_blobs_table(); // need this after generate_stubs
|
||||
SharedRuntime::init_adapter_library(); // do this after AOTCodeCache::init_shared_blobs_table
|
||||
return JNI_OK;
|
||||
}
|
||||
|
||||
|
@ -123,6 +123,8 @@ Mutex* CodeHeapStateAnalytics_lock = nullptr;
|
||||
|
||||
Mutex* ExternalsRecorder_lock = nullptr;
|
||||
|
||||
Mutex* AOTCodeCStrings_lock = nullptr;
|
||||
|
||||
Monitor* ContinuationRelativize_lock = nullptr;
|
||||
|
||||
Mutex* Metaspace_lock = nullptr;
|
||||
@ -319,6 +321,8 @@ void mutex_init() {
|
||||
// tty_lock is held when printing nmethod and its relocations which use this lock.
|
||||
MUTEX_DEFL(ExternalsRecorder_lock , PaddedMutex , tty_lock);
|
||||
|
||||
MUTEX_DEFL(AOTCodeCStrings_lock , PaddedMutex , tty_lock);
|
||||
|
||||
MUTEX_DEFL(Threads_lock , PaddedMonitor, CompileThread_lock, true);
|
||||
MUTEX_DEFL(Compile_lock , PaddedMutex , MethodCompileQueue_lock);
|
||||
MUTEX_DEFL(JNICritical_lock , PaddedMonitor, AdapterHandlerLibrary_lock); // used for JNI critical regions
|
||||
|
@ -148,6 +148,8 @@ extern Mutex* CodeHeapStateAnalytics_lock; // lock print functions against
|
||||
|
||||
extern Mutex* ExternalsRecorder_lock; // used to guard access to the external addresses table
|
||||
|
||||
extern Mutex* AOTCodeCStrings_lock; // used to guard access to the AOT code C strings table
|
||||
|
||||
extern Monitor* ContinuationRelativize_lock;
|
||||
|
||||
#if INCLUDE_JVMCI
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -25,10 +25,12 @@
|
||||
#ifndef SHARE_RUNTIME_SHAREDRUNTIME_HPP
|
||||
#define SHARE_RUNTIME_SHAREDRUNTIME_HPP
|
||||
|
||||
#include "classfile/compactHashtable.hpp"
|
||||
#include "code/codeBlob.hpp"
|
||||
#include "code/vmreg.hpp"
|
||||
#include "interpreter/linkResolver.hpp"
|
||||
#include "memory/allStatic.hpp"
|
||||
#include "memory/metaspaceClosure.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "runtime/stubDeclarations.hpp"
|
||||
#include "utilities/macros.hpp"
|
||||
@ -114,6 +116,7 @@ class SharedRuntime: AllStatic {
|
||||
// For c2: call to runtime to return a buffer lease.
|
||||
static RuntimeStub* generate_jfr_return_lease();
|
||||
#endif
|
||||
static void init_adapter_library();
|
||||
|
||||
static const char *stub_name(SharedStubId id) {
|
||||
assert(id > SharedStubId::NO_STUBID && id < SharedStubId::NUM_STUBIDS, "stub id out of range");
|
||||
@ -464,12 +467,12 @@ class SharedRuntime: AllStatic {
|
||||
// pointer as needed. This means the i2c adapter code doesn't need any special
|
||||
// handshaking path with compiled code to keep the stack walking correct.
|
||||
|
||||
static AdapterHandlerEntry* generate_i2c2i_adapters(MacroAssembler *_masm,
|
||||
int total_args_passed,
|
||||
int max_arg,
|
||||
const BasicType *sig_bt,
|
||||
const VMRegPair *regs,
|
||||
AdapterFingerPrint* fingerprint);
|
||||
static void generate_i2c2i_adapters(MacroAssembler *_masm,
|
||||
int total_args_passed,
|
||||
int max_arg,
|
||||
const BasicType *sig_bt,
|
||||
const VMRegPair *regs,
|
||||
AdapterHandlerEntry* handler);
|
||||
|
||||
static void gen_i2c_adapter(MacroAssembler *_masm,
|
||||
int total_args_passed,
|
||||
@ -666,15 +669,21 @@ class SharedRuntime: AllStatic {
|
||||
// used by the adapters. The code generation happens here because it's very
|
||||
// similar to what the adapters have to do.
|
||||
|
||||
class AdapterHandlerEntry : public CHeapObj<mtCode> {
|
||||
class AdapterHandlerEntry : public MetaspaceObj {
|
||||
friend class AdapterHandlerLibrary;
|
||||
|
||||
public:
|
||||
static const int ENTRIES_COUNT = 4;
|
||||
|
||||
private:
|
||||
AdapterFingerPrint* _fingerprint;
|
||||
address _i2c_entry;
|
||||
address _c2i_entry;
|
||||
address _c2i_unverified_entry;
|
||||
address _c2i_no_clinit_check_entry;
|
||||
bool _linked;
|
||||
|
||||
static const char *_entry_names[];
|
||||
|
||||
#ifdef ASSERT
|
||||
// Captures code and signature used to generate this adapter when
|
||||
@ -683,27 +692,58 @@ class AdapterHandlerEntry : public CHeapObj<mtCode> {
|
||||
int _saved_code_length;
|
||||
#endif
|
||||
|
||||
AdapterHandlerEntry(AdapterFingerPrint* fingerprint, address i2c_entry, address c2i_entry,
|
||||
address c2i_unverified_entry,
|
||||
address c2i_no_clinit_check_entry) :
|
||||
AdapterHandlerEntry(AdapterFingerPrint* fingerprint) :
|
||||
_fingerprint(fingerprint),
|
||||
_i2c_entry(i2c_entry),
|
||||
_c2i_entry(c2i_entry),
|
||||
_c2i_unverified_entry(c2i_unverified_entry),
|
||||
_c2i_no_clinit_check_entry(c2i_no_clinit_check_entry)
|
||||
_i2c_entry(nullptr),
|
||||
_c2i_entry(nullptr),
|
||||
_c2i_unverified_entry(nullptr),
|
||||
_c2i_no_clinit_check_entry(nullptr),
|
||||
_linked(false)
|
||||
#ifdef ASSERT
|
||||
, _saved_code_length(0)
|
||||
, _saved_code(nullptr),
|
||||
_saved_code_length(0)
|
||||
#endif
|
||||
{ }
|
||||
|
||||
~AdapterHandlerEntry();
|
||||
|
||||
// Allocate on CHeap instead of metaspace (see JDK-8331086).
|
||||
// Dummy argument is used to avoid C++ warning about using
|
||||
// deleted opearator MetaspaceObj::delete().
|
||||
void* operator new(size_t size, size_t dummy) throw() {
|
||||
void* p = AllocateHeap(size, mtCode);
|
||||
memset(p, 0, size);
|
||||
return p;
|
||||
}
|
||||
|
||||
public:
|
||||
static AdapterHandlerEntry* allocate(AdapterFingerPrint* fingerprint) {
|
||||
return new(0) AdapterHandlerEntry(fingerprint);
|
||||
}
|
||||
|
||||
static void deallocate(AdapterHandlerEntry *handler) {
|
||||
handler->~AdapterHandlerEntry();
|
||||
}
|
||||
|
||||
void set_entry_points(address i2c_entry, address c2i_entry, address c2i_unverified_entry, address c2i_no_clinit_check_entry, bool linked = true) {
|
||||
_i2c_entry = i2c_entry;
|
||||
_c2i_entry = c2i_entry;
|
||||
_c2i_unverified_entry = c2i_unverified_entry;
|
||||
_c2i_no_clinit_check_entry = c2i_no_clinit_check_entry;
|
||||
_linked = linked;
|
||||
}
|
||||
|
||||
address get_i2c_entry() const { return _i2c_entry; }
|
||||
address get_c2i_entry() const { return _c2i_entry; }
|
||||
address get_c2i_unverified_entry() const { return _c2i_unverified_entry; }
|
||||
address get_c2i_no_clinit_check_entry() const { return _c2i_no_clinit_check_entry; }
|
||||
|
||||
static const char* entry_name(int i) {
|
||||
assert(i >=0 && i < ENTRIES_COUNT, "entry id out of range");
|
||||
return _entry_names[i];
|
||||
}
|
||||
|
||||
bool is_linked() const { return _linked; }
|
||||
address base_address();
|
||||
void relocate(address new_base);
|
||||
|
||||
@ -717,8 +757,19 @@ class AdapterHandlerEntry : public CHeapObj<mtCode> {
|
||||
|
||||
//virtual void print_on(outputStream* st) const; DO NOT USE
|
||||
void print_adapter_on(outputStream* st) const;
|
||||
|
||||
void metaspace_pointers_do(MetaspaceClosure* it);
|
||||
int size() const {return (int)heap_word_size(sizeof(AdapterHandlerEntry)); }
|
||||
MetaspaceObj::Type type() const { return AdapterHandlerEntryType; }
|
||||
|
||||
void remove_unshareable_info() NOT_CDS_RETURN;
|
||||
void link() NOT_CDS_RETURN;
|
||||
};
|
||||
|
||||
#if INCLUDE_CDS
|
||||
class ArchivedAdapterTable;
|
||||
#endif // INCLUDE_CDS
|
||||
|
||||
class AdapterHandlerLibrary: public AllStatic {
|
||||
friend class SharedRuntime;
|
||||
private:
|
||||
@ -729,31 +780,54 @@ class AdapterHandlerLibrary: public AllStatic {
|
||||
static AdapterHandlerEntry* _obj_arg_handler;
|
||||
static AdapterHandlerEntry* _obj_int_arg_handler;
|
||||
static AdapterHandlerEntry* _obj_obj_arg_handler;
|
||||
#if INCLUDE_CDS
|
||||
static ArchivedAdapterTable _aot_adapter_handler_table;
|
||||
#endif // INCLUDE_CDS
|
||||
|
||||
static BufferBlob* buffer_blob();
|
||||
static void initialize();
|
||||
static AdapterHandlerEntry* get_simple_adapter(const methodHandle& method);
|
||||
static AdapterBlob* lookup_aot_cache(AdapterHandlerEntry* handler);
|
||||
static AdapterHandlerEntry* create_adapter(AdapterBlob*& new_adapter,
|
||||
int total_args_passed,
|
||||
BasicType* sig_bt,
|
||||
bool allocate_code_blob);
|
||||
static AdapterHandlerEntry* get_simple_adapter(const methodHandle& method);
|
||||
bool is_transient = false);
|
||||
static void create_abstract_method_handler();
|
||||
static void lookup_simple_adapters() NOT_CDS_RETURN;
|
||||
#ifndef PRODUCT
|
||||
static void print_adapter_handler_info(outputStream* st, AdapterHandlerEntry* handler, AdapterBlob* adapter_blob);
|
||||
#endif // PRODUCT
|
||||
public:
|
||||
|
||||
static AdapterHandlerEntry* new_entry(AdapterFingerPrint* fingerprint,
|
||||
address i2c_entry,
|
||||
address c2i_entry,
|
||||
address c2i_unverified_entry,
|
||||
address c2i_no_clinit_check_entry = nullptr);
|
||||
static AdapterHandlerEntry* new_entry(AdapterFingerPrint* fingerprint);
|
||||
static void create_native_wrapper(const methodHandle& method);
|
||||
static AdapterHandlerEntry* get_adapter(const methodHandle& method);
|
||||
static AdapterHandlerEntry* lookup(int total_args_passed, BasicType* sig_bt);
|
||||
static bool generate_adapter_code(AdapterBlob*& adapter_blob,
|
||||
AdapterHandlerEntry* handler,
|
||||
int total_args_passed,
|
||||
BasicType* sig_bt,
|
||||
bool is_transient);
|
||||
|
||||
#ifdef ASSERT
|
||||
static void verify_adapter_sharing(int total_args_passed, BasicType* sig_bt, AdapterHandlerEntry* cached);
|
||||
#endif // ASSERT
|
||||
|
||||
static void print_handler(const CodeBlob* b) { print_handler_on(tty, b); }
|
||||
static void print_handler_on(outputStream* st, const CodeBlob* b);
|
||||
static bool contains(const CodeBlob* b);
|
||||
static const char* name(AdapterFingerPrint* fingerprint);
|
||||
static uint32_t id(AdapterFingerPrint* fingerprint);
|
||||
#ifndef PRODUCT
|
||||
static void print_statistics();
|
||||
#endif // PRODUCT
|
||||
|
||||
static bool is_abstract_method_adapter(AdapterHandlerEntry* adapter);
|
||||
|
||||
static AdapterBlob* link_aot_adapter_handler(AdapterHandlerEntry* handler) NOT_CDS_RETURN_(nullptr);
|
||||
static void dump_aot_adapter_table() NOT_CDS_RETURN;
|
||||
static void serialize_shared_table_header(SerializeClosure* soc) NOT_CDS_RETURN;
|
||||
static void link_aot_adapters() NOT_CDS_RETURN;
|
||||
};
|
||||
|
||||
#endif // SHARE_RUNTIME_SHAREDRUNTIME_HPP
|
||||
|
@ -410,6 +410,7 @@ hotspot_appcds_dynamic = \
|
||||
runtime/cds/appcds/ \
|
||||
-runtime/cds/appcds/aotCache \
|
||||
-runtime/cds/appcds/aotClassLinking \
|
||||
-runtime/cds/appcds/aotCode \
|
||||
-runtime/cds/appcds/applications \
|
||||
-runtime/cds/appcds/cacheObject \
|
||||
-runtime/cds/appcds/complexURI \
|
||||
@ -511,6 +512,7 @@ hotspot_aot_classlinking = \
|
||||
runtime/cds \
|
||||
-runtime/cds/appcds/aotCache \
|
||||
-runtime/cds/appcds/aotClassLinking \
|
||||
-runtime/cds/appcds/aotCode \
|
||||
-runtime/cds/appcds/BadBSM.java \
|
||||
-runtime/cds/appcds/cacheObject/ArchivedIntegerCacheTest.java \
|
||||
-runtime/cds/appcds/cacheObject/ArchivedModuleCompareTest.java \
|
||||
@ -589,6 +591,7 @@ hotspot_metaspace = \
|
||||
# A subset of AppCDS tests to be run in tier1
|
||||
tier1_runtime_appcds = \
|
||||
runtime/cds/appcds/aotCache/HelloAOTCache.java \
|
||||
runtime/cds/appcds/aotCode \
|
||||
runtime/cds/appcds/HelloTest.java
|
||||
|
||||
tier1_runtime_appcds_exclude = \
|
||||
|
108
test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeFlags.java
Normal file
108
test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeFlags.java
Normal file
@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @summary Sanity test of combinations of the AOT Code Caching diagnostic flags
|
||||
* @requires vm.cds
|
||||
* @requires vm.cds.supports.aot.class.linking
|
||||
* @requires vm.flagless
|
||||
* @comment work around JDK-8345635
|
||||
* @requires !vm.jvmci.enabled
|
||||
* @library /test/lib /test/setup_aot
|
||||
* @build AOTCodeFlags JavacBenchApp
|
||||
* @run driver jdk.test.lib.helpers.ClassFileInstaller -jar app.jar
|
||||
* JavacBenchApp
|
||||
* JavacBenchApp$ClassFile
|
||||
* JavacBenchApp$FileManager
|
||||
* JavacBenchApp$SourceFile
|
||||
* @run driver AOTCodeFlags
|
||||
*/
|
||||
|
||||
import jdk.test.lib.cds.CDSAppTester;
|
||||
import jdk.test.lib.process.OutputAnalyzer;
|
||||
|
||||
public class AOTCodeFlags {
|
||||
public static int flag_sign = 0;
|
||||
public static void main(String... args) throws Exception {
|
||||
Tester t = new Tester();
|
||||
for (int i = 0; i < 2; i++) {
|
||||
flag_sign = i;
|
||||
t.run(new String[] {"AOT"});
|
||||
}
|
||||
}
|
||||
static class Tester extends CDSAppTester {
|
||||
public Tester() {
|
||||
super("AOTCodeFlags" + flag_sign);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String classpath(RunMode runMode) {
|
||||
return "app.jar";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] vmArgs(RunMode runMode) {
|
||||
switch (runMode) {
|
||||
case RunMode.ASSEMBLY:
|
||||
case RunMode.PRODUCTION:
|
||||
return new String[] {
|
||||
"-XX:+UnlockDiagnosticVMOptions",
|
||||
"-XX:" + (flag_sign == 0 ? "-" : "+") + "AOTAdapterCaching",
|
||||
"-Xlog:aot+codecache+init=debug",
|
||||
"-Xlog:aot+codecache+exit=debug",
|
||||
};
|
||||
}
|
||||
return new String[] {};
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] appCommandLine(RunMode runMode) {
|
||||
return new String[] {
|
||||
"JavacBenchApp", "10"
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkExecution(OutputAnalyzer out, RunMode runMode) throws Exception {
|
||||
if (flag_sign == 0) {
|
||||
switch (runMode) {
|
||||
case RunMode.ASSEMBLY:
|
||||
case RunMode.PRODUCTION:
|
||||
out.shouldNotContain("Adapters: total");
|
||||
break;
|
||||
}
|
||||
|
||||
} else {
|
||||
switch (runMode) {
|
||||
case RunMode.ASSEMBLY:
|
||||
case RunMode.PRODUCTION:
|
||||
out.shouldContain("Adapters: total");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user