Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Save/load nmethod without going through CodeBuffer #27

Draft
wants to merge 1 commit into
base: premain
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
351 changes: 226 additions & 125 deletions src/hotspot/share/ci/ciEnv.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -981,6 +981,214 @@
}
}

// scc_entry != nullptr implies loading compiled code from AOT code cache
bool ciEnv::is_compilation_valid(JavaThread* thread, ciMethod* target, bool preload, bool install_code, CodeBuffer* code_buffer, SCCEntry* scc_entry) {
methodHandle method(thread, target->get_Method());

// We require method counters to store some method state (max compilation levels) required by the compilation policy.
if (!preload && method->get_method_counters(thread) == nullptr) {
record_failure("can't create method counters");
if (scc_entry == nullptr || !UseNewCode2) {
// All buffers in the CodeBuffer are allocated in the CodeCache.
// If the code buffer is created on each compile attempt
// as in C2, then it must be freed.
// But keep shared code.
code_buffer->free_blob();
}
return false;
}

if (scc_entry != nullptr) {
// Invalid compilation states:
// - SCCache is closed, SCC entry is garbage.
// - SCC entry indicates this shared code was marked invalid while it was loaded.
if (!SCCache::is_on() || scc_entry->not_entrant()) {
if (!UseNewCode2) {
code_buffer->free_blob();

Check failure on line 1007 in src/hotspot/share/ci/ciEnv.cpp

View check run for this annotation

openjdk / jcheck-openjdk/leyden-27

Whitespace error

Column 0: tab
}
return false;
}
}

// Change in Jvmti state may invalidate compilation.
if (!failing() && jvmti_state_changed()) {
record_failure("Jvmti state change invalidated dependencies");
}

// Change in DTrace flags may invalidate compilation.
if (!failing() &&
( (!dtrace_method_probes() && DTraceMethodProbes) ||
(!dtrace_alloc_probes() && DTraceAllocProbes) )) {

Check failure on line 1021 in src/hotspot/share/ci/ciEnv.cpp

View check run for this annotation

openjdk / jcheck-openjdk/leyden-27

Whitespace error

Column 0: tab
record_failure("DTrace flags change invalidated dependencies");
}

if (!preload && !failing() && target->needs_clinit_barrier() &&
target->holder()->is_in_error_state()) {
record_failure("method holder is in error state");
}

if (!failing() && (scc_entry == nullptr)) {
if (log() != nullptr) {
// Log the dependencies which this compilation declares.
dependencies()->log_all_dependencies();
}

// Encode the dependencies now, so we can check them right away.
dependencies()->encode_content_bytes();
}
// Check for {class loads, evolution, breakpoints, ...} during compilation
if (!failing() && install_code) {
// Check for {class loads, evolution, breakpoints, ...} during compilation
validate_compile_task_dependencies(target);
if (failing() && preload) {
ResourceMark rm;
char *method_name = method->name_and_sig_as_C_string();
log_info(scc)("preload code for '%s' failed dependency check", method_name);
}
}

if (failing()) {
// While not a true deoptimization, it is a preemptive decompile.
MethodData* mdo = method()->method_data();
if (mdo != nullptr && _inc_decompile_count_on_failure) {
mdo->inc_decompile_count();
}

if (scc_entry == nullptr && !UseNewCode2) {
// All buffers in the CodeBuffer are allocated in the CodeCache.
// If the code buffer is created on each compile attempt
// as in C2, then it must be freed.
code_buffer->free_blob();
}
return false;
}
return true;
}

void ciEnv::make_code_usable(JavaThread* thread, ciMethod* target, bool preload, int entry_bci, SCCEntry* scc_entry, nmethod* nm) {
methodHandle method(thread, target->get_Method());

if (entry_bci == InvocationEntryBci) {
if (TieredCompilation) {
// If there is an old version we're done with it
nmethod* old = method->code();
if (TraceMethodReplacement && old != nullptr) {
ResourceMark rm;

Check failure on line 1076 in src/hotspot/share/ci/ciEnv.cpp

View check run for this annotation

openjdk / jcheck-openjdk/leyden-27

Whitespace error

Column 0: tab
char *method_name = method->name_and_sig_as_C_string();

Check failure on line 1077 in src/hotspot/share/ci/ciEnv.cpp

View check run for this annotation

openjdk / jcheck-openjdk/leyden-27

Whitespace error

Column 0: tab
tty->print_cr("Replacing method %s", method_name);

Check failure on line 1078 in src/hotspot/share/ci/ciEnv.cpp

View check run for this annotation

openjdk / jcheck-openjdk/leyden-27

Whitespace error

Column 0: tab
}
if (old != nullptr) {
old->make_not_used();

Check failure on line 1081 in src/hotspot/share/ci/ciEnv.cpp

View check run for this annotation

openjdk / jcheck-openjdk/leyden-27

Whitespace error

Column 0: tab
}
}

LogTarget(Info, nmethod, install) lt;
if (lt.is_enabled()) {
ResourceMark rm;
char *method_name = method->name_and_sig_as_C_string();
lt.print("Installing method (L%d) %s id=%d scc=%s%s%u",
task()->comp_level(), method_name, compile_id(),

Check failure on line 1090 in src/hotspot/share/ci/ciEnv.cpp

View check run for this annotation

openjdk / jcheck-openjdk/leyden-27

Whitespace error

Column 0: tab Column 1: tab
task()->is_scc() ? "A" : "", preload ? "P" : "",

Check failure on line 1091 in src/hotspot/share/ci/ciEnv.cpp

View check run for this annotation

openjdk / jcheck-openjdk/leyden-27

Whitespace error

Column 0: tab Column 1: tab
(scc_entry != nullptr ? scc_entry->offset() : 0));

Check failure on line 1092 in src/hotspot/share/ci/ciEnv.cpp

View check run for this annotation

openjdk / jcheck-openjdk/leyden-27

Whitespace error

Column 0: tab Column 1: tab
}
// Allow the code to be executed
MutexLocker ml(NMethodState_lock, Mutex::_no_safepoint_check_flag);
if (nm->make_in_use()) {
#ifdef ASSERT
BarrierSetNMethod* bs_nm = BarrierSet::barrier_set()->barrier_set_nmethod();
if (bs_nm != nullptr && bs_nm->supports_entry_barrier(nm)) {
if (!bs_nm->is_armed(nm)) {

Check failure on line 1100 in src/hotspot/share/ci/ciEnv.cpp

View check run for this annotation

openjdk / jcheck-openjdk/leyden-27

Whitespace error

Column 0: tab
log_info(init)("nmethod %d %d not armed", nm->compile_id(), nm->comp_level());

Check failure on line 1101 in src/hotspot/share/ci/ciEnv.cpp

View check run for this annotation

openjdk / jcheck-openjdk/leyden-27

Whitespace error

Column 0: tab
}

Check failure on line 1102 in src/hotspot/share/ci/ciEnv.cpp

View check run for this annotation

openjdk / jcheck-openjdk/leyden-27

Whitespace error

Column 0: tab
}
#endif // ASSERT
if (preload) {
method->set_preload_code(nm);

Check failure on line 1106 in src/hotspot/share/ci/ciEnv.cpp

View check run for this annotation

openjdk / jcheck-openjdk/leyden-27

Whitespace error

Column 0: tab
}
if (!preload || target->holder()->is_linked()) {
method->set_code(method, nm);

Check failure on line 1109 in src/hotspot/share/ci/ciEnv.cpp

View check run for this annotation

openjdk / jcheck-openjdk/leyden-27

Whitespace error

Column 0: tab
}
}
} else {
LogTarget(Info, nmethod, install) lt;
if (lt.is_enabled()) {
ResourceMark rm;
char *method_name = method->name_and_sig_as_C_string();
lt.print("Installing osr method (L%d) %s @ %d id=%u scc=%s%u",
task()->comp_level(), method_name, entry_bci, compile_id(),

Check failure on line 1118 in src/hotspot/share/ci/ciEnv.cpp

View check run for this annotation

openjdk / jcheck-openjdk/leyden-27

Whitespace error

Column 0: tab
task()->is_scc() ? "A" : "",

Check failure on line 1119 in src/hotspot/share/ci/ciEnv.cpp

View check run for this annotation

openjdk / jcheck-openjdk/leyden-27

Whitespace error

Column 0: tab
(scc_entry != nullptr ? scc_entry->offset() : 0));

Check failure on line 1120 in src/hotspot/share/ci/ciEnv.cpp

View check run for this annotation

openjdk / jcheck-openjdk/leyden-27

Whitespace error

Column 0: tab
}
MutexLocker ml(NMethodState_lock, Mutex::_no_safepoint_check_flag);
if (nm->make_in_use()) {
method->method_holder()->add_osr_nmethod(nm);
}
}
}

void ciEnv::register_aot_method(ciMethod* target,
AbstractCompiler* compiler,
int entry_bci,
GrowableArray<oop>& oop_list,
GrowableArray<Metadata*>& metadata_list,
GrowableArray<oop>& reloc_imm_oop_list,
GrowableArray<Metadata*>& reloc_imm_metadata_list,
SCCReader* scc_reader,
SCnmethod* scnm) {
SCCEntry* scc_entry = task()->scc_entry();
assert(scc_entry != nullptr, "must be");
VM_ENTRY_MARK;
nmethod* nm = nullptr;
{
methodHandle method(THREAD, target->get_Method());
bool preload = task()->preload(); // Code is preloaded before Java method execution

// Check if memory should be freed before allocation
CodeCache::gc_on_allocation();

// To prevent compile queue updates.
MutexLocker locker(THREAD, MethodCompileQueue_lock);

// Prevent InstanceKlass::add_to_hierarchy from running
// and invalidating our dependencies until we install this method.
// No safepoints are allowed. Otherwise, class redefinition can occur in between.
MutexLocker ml(Compile_lock);
NoSafepointVerifier nsv;

if (!is_compilation_valid(THREAD, target, preload, true /*install_code*/, nullptr /*code_buffer*/, scc_entry)) {
return;
}

nm = nmethod::new_nmethod(method,
compiler,
compile_id(),
CompLevel(task()->comp_level()),
entry_bci,
preload,
oop_list,
metadata_list,
reloc_imm_oop_list,
reloc_imm_metadata_list,
scc_reader,
scnm);

if (nm != nullptr) {
make_code_usable(THREAD, target, preload, entry_bci, scc_entry, nm);
}
}

NoSafepointVerifier nsv;
if (nm != nullptr) {
// Compilation succeeded, post what we know about it
nm->post_compiled_method(task());
task()->set_num_inlined_bytecodes(num_inlined_bytecodes());
} else {
// The CodeCache is full.
record_failure("code cache is full");
}
// safepoints are allowed again
}

// ------------------------------------------------------------------
// ciEnv::register_method
void ciEnv::register_method(ciMethod* target,
Expand Down Expand Up @@ -1008,17 +1216,6 @@
methodHandle method(THREAD, target->get_Method());
bool preload = task()->preload(); // Code is preloaded before Java method execution

// We require method counters to store some method state (max compilation levels) required by the compilation policy.
if (!preload && method->get_method_counters(THREAD) == nullptr) {
record_failure("can't create method counters");
// All buffers in the CodeBuffer are allocated in the CodeCache.
// If the code buffer is created on each compile attempt
// as in C2, then it must be freed.
// But keep shared code.
code_buffer->free_blob();
return;
}

// Check if memory should be freed before allocation
CodeCache::gc_on_allocation();

Expand All @@ -1031,71 +1228,14 @@
MutexLocker ml(Compile_lock);
NoSafepointVerifier nsv;

if (scc_entry != nullptr) {
// Invalid compilation states:
// - SCCache is closed, SCC entry is garbage.
// - SCC entry indicates this shared code was marked invalid while it was loaded.
if (!SCCache::is_on() || scc_entry->not_entrant()) {
code_buffer->free_blob();
return;
}
}

// Change in Jvmti state may invalidate compilation.
if (!failing() && jvmti_state_changed()) {
record_failure("Jvmti state change invalidated dependencies");
}

// Change in DTrace flags may invalidate compilation.
if (!failing() &&
( (!dtrace_method_probes() && DTraceMethodProbes) ||
(!dtrace_alloc_probes() && DTraceAllocProbes) )) {
record_failure("DTrace flags change invalidated dependencies");
}

if (!preload && !failing() && target->needs_clinit_barrier() &&
target->holder()->is_in_error_state()) {
record_failure("method holder is in error state");
}

if (!failing() && (scc_entry == nullptr)) {
if (log() != nullptr) {
// Log the dependencies which this compilation declares.
dependencies()->log_all_dependencies();
}

// Encode the dependencies now, so we can check them right away.
dependencies()->encode_content_bytes();
}
// Check for {class loads, evolution, breakpoints, ...} during compilation
if (!failing() && install_code) {
// Check for {class loads, evolution, breakpoints, ...} during compilation
validate_compile_task_dependencies(target);
if (failing() && preload) {
ResourceMark rm;
char *method_name = method->name_and_sig_as_C_string();
log_info(scc)("preload code for '%s' failed dependency check", method_name);
}
}

if (failing()) {
// While not a true deoptimization, it is a preemptive decompile.
MethodData* mdo = method()->method_data();
if (mdo != nullptr && _inc_decompile_count_on_failure) {
mdo->inc_decompile_count();
}

// All buffers in the CodeBuffer are allocated in the CodeCache.
// If the code buffer is created on each compile attempt
// as in C2, then it must be freed.
code_buffer->free_blob();
if (!is_compilation_valid(THREAD, target, preload, install_code, code_buffer, scc_entry)) {
return;
}

assert(offsets->value(CodeOffsets::Deopt) != -1, "must have deopt entry");
assert(offsets->value(CodeOffsets::Exceptions) != -1, "must have exception entry");

if (scc_entry == nullptr) {
if (scc_entry == nullptr && !UseNewCode2) {
scc_entry = SCCache::store_nmethod(method,
compile_id(),
entry_bci,
Expand Down Expand Up @@ -1149,62 +1289,23 @@
nm->set_has_clinit_barriers(has_clinit_barriers);
assert(!method->is_synchronized() || nm->has_monitors(), "");

if (entry_bci == InvocationEntryBci) {
if (TieredCompilation) {
// If there is an old version we're done with it
nmethod* old = method->code();
if (TraceMethodReplacement && old != nullptr) {
ResourceMark rm;
char *method_name = method->name_and_sig_as_C_string();
tty->print_cr("Replacing method %s", method_name);
}
if (old != nullptr) {
old->make_not_used();
}
}

LogTarget(Info, nmethod, install) lt;
if (lt.is_enabled()) {
ResourceMark rm;
char *method_name = method->name_and_sig_as_C_string();
lt.print("Installing method (L%d) %s id=%d scc=%s%s%u",
task()->comp_level(), method_name, compile_id(),
task()->is_scc() ? "A" : "", preload ? "P" : "",
(scc_entry != nullptr ? scc_entry->offset() : 0));
}
// Allow the code to be executed
MutexLocker ml(NMethodState_lock, Mutex::_no_safepoint_check_flag);
if (nm->make_in_use()) {
#ifdef ASSERT
BarrierSetNMethod* bs_nm = BarrierSet::barrier_set()->barrier_set_nmethod();
if (bs_nm != nullptr && bs_nm->supports_entry_barrier(nm)) {
if (!bs_nm->is_armed(nm)) {
log_info(init)("nmethod %d %d not armed", nm->compile_id(), nm->comp_level());
}
}
#endif // ASSERT
if (preload) {
method->set_preload_code(nm);
}
if (!preload || target->holder()->is_linked()) {
method->set_code(method, nm);
}
}
} else {
LogTarget(Info, nmethod, install) lt;
if (lt.is_enabled()) {
ResourceMark rm;
char *method_name = method->name_and_sig_as_C_string();
lt.print("Installing osr method (L%d) %s @ %d id=%u scc=%s%u",
task()->comp_level(), method_name, entry_bci, compile_id(),
task()->is_scc() ? "A" : "",
(scc_entry != nullptr ? scc_entry->offset() : 0));
}
MutexLocker ml(NMethodState_lock, Mutex::_no_safepoint_check_flag);
if (nm->make_in_use()) {
method->method_holder()->add_osr_nmethod(nm);
}
if (scc_entry == nullptr && UseNewCode2) {
scc_entry = SCCache::store_nmethod_v1(nm,

Check failure on line 1293 in src/hotspot/share/ci/ciEnv.cpp

View check run for this annotation

openjdk / jcheck-openjdk/leyden-27

Whitespace error

Column 0: tab
compiler,
dependencies()->size_in_bytes(),
for_preload);
if (scc_entry != nullptr) {

Check failure on line 1297 in src/hotspot/share/ci/ciEnv.cpp

View check run for this annotation

openjdk / jcheck-openjdk/leyden-27

Whitespace error

Column 0: tab
scc_entry->set_inlined_bytecodes(num_inlined_bytecodes());

Check failure on line 1298 in src/hotspot/share/ci/ciEnv.cpp

View check run for this annotation

openjdk / jcheck-openjdk/leyden-27

Whitespace error

Column 0: tab
if (has_clinit_barriers) {

Check failure on line 1299 in src/hotspot/share/ci/ciEnv.cpp

View check run for this annotation

openjdk / jcheck-openjdk/leyden-27

Whitespace error

Column 0: tab
set_scc_clinit_barriers_entry(scc_entry); // Record it

Check failure on line 1300 in src/hotspot/share/ci/ciEnv.cpp

View check run for this annotation

openjdk / jcheck-openjdk/leyden-27

Whitespace error

Column 0: tab
return;
} else if (!for_preload) {

Check failure on line 1302 in src/hotspot/share/ci/ciEnv.cpp

View check run for this annotation

openjdk / jcheck-openjdk/leyden-27

Whitespace error

Column 0: tab
SCCEntry* previous_entry = scc_clinit_barriers_entry();

Check failure on line 1303 in src/hotspot/share/ci/ciEnv.cpp

View check run for this annotation

openjdk / jcheck-openjdk/leyden-27

Whitespace error

Column 0: tab
scc_entry->set_next(previous_entry); // Link it for case of deoptimization

Check failure on line 1304 in src/hotspot/share/ci/ciEnv.cpp

View check run for this annotation

openjdk / jcheck-openjdk/leyden-27

Whitespace error

Column 0: tab
}

Check failure on line 1305 in src/hotspot/share/ci/ciEnv.cpp

View check run for this annotation

openjdk / jcheck-openjdk/leyden-27

Whitespace error

Column 0: tab
}

Check failure on line 1306 in src/hotspot/share/ci/ciEnv.cpp

View check run for this annotation

openjdk / jcheck-openjdk/leyden-27

Whitespace error

Column 0: tab
}
make_code_usable(THREAD, target, preload, entry_bci, scc_entry, nm);
}
}

Expand Down
Loading