From 00d421b0fc0eaa2e84b437b89aa492aa0559c9a3 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Tue, 11 Mar 2025 11:56:55 +0100 Subject: [PATCH 1/4] Base version --- src/hotspot/share/c1/c1_Runtime1.cpp | 8 ++++---- src/hotspot/share/ci/ciReplay.cpp | 2 +- src/hotspot/share/code/codeCache.cpp | 2 +- src/hotspot/share/code/nmethod.cpp | 17 ++++++++++++----- src/hotspot/share/code/nmethod.hpp | 6 +++--- .../share/compiler/compilationPolicy.cpp | 4 ++-- src/hotspot/share/jvmci/jvmciCompilerToVM.cpp | 4 ++-- src/hotspot/share/jvmci/jvmciEnv.cpp | 4 ++-- src/hotspot/share/jvmci/jvmciRuntime.cpp | 4 ++-- src/hotspot/share/oops/instanceKlass.cpp | 2 +- src/hotspot/share/oops/method.cpp | 2 +- src/hotspot/share/prims/whitebox.cpp | 2 +- src/hotspot/share/runtime/deoptimization.cpp | 4 ++-- src/hotspot/share/runtime/javaThread.cpp | 2 +- 14 files changed, 35 insertions(+), 28 deletions(-) diff --git a/src/hotspot/share/c1/c1_Runtime1.cpp b/src/hotspot/share/c1/c1_Runtime1.cpp index 3a30c9846aab7..e16027494395b 100644 --- a/src/hotspot/share/c1/c1_Runtime1.cpp +++ b/src/hotspot/share/c1/c1_Runtime1.cpp @@ -795,7 +795,7 @@ JRT_ENTRY(void, Runtime1::deoptimize(JavaThread* current, jint trap_request)) Deoptimization::DeoptReason reason = Deoptimization::trap_request_reason(trap_request); if (action == Deoptimization::Action_make_not_entrant) { - if (nm->make_not_entrant()) { + if (nm->make_not_entrant("C1 deoptimize")) { if (reason == Deoptimization::Reason_tenured) { MethodData* trap_mdo = Deoptimization::get_method_data(current, method, true /*create_if_missing*/); if (trap_mdo != nullptr) { @@ -1087,7 +1087,7 @@ JRT_ENTRY(void, Runtime1::patch_code(JavaThread* current, C1StubId stub_id )) // safepoint, but if it's still alive then make it not_entrant. nmethod* nm = CodeCache::find_nmethod(caller_frame.pc()); if (nm != nullptr) { - nm->make_not_entrant(); + nm->make_not_entrant("C1 code patch"); } Deoptimization::deoptimize_frame(current, caller_frame.id()); @@ -1335,7 +1335,7 @@ void Runtime1::patch_code(JavaThread* current, C1StubId stub_id) { // Make sure the nmethod is invalidated, i.e. made not entrant. nmethod* nm = CodeCache::find_nmethod(caller_frame.pc()); if (nm != nullptr) { - nm->make_not_entrant(); + nm->make_not_entrant("C1 deoptimize for patching"); } } @@ -1463,7 +1463,7 @@ JRT_ENTRY(void, Runtime1::predicate_failed_trap(JavaThread* current)) nmethod* nm = CodeCache::find_nmethod(caller_frame.pc()); assert (nm != nullptr, "no more nmethod?"); - nm->make_not_entrant(); + nm->make_not_entrant("C1 predicate failed trap"); methodHandle m(current, nm->method()); MethodData* mdo = m->method_data(); diff --git a/src/hotspot/share/ci/ciReplay.cpp b/src/hotspot/share/ci/ciReplay.cpp index 1385bb637a99d..669f316463c9e 100644 --- a/src/hotspot/share/ci/ciReplay.cpp +++ b/src/hotspot/share/ci/ciReplay.cpp @@ -802,7 +802,7 @@ class CompileReplay : public StackObj { // Make sure the existence of a prior compile doesn't stop this one nmethod* nm = (entry_bci != InvocationEntryBci) ? method->lookup_osr_nmethod_for(entry_bci, comp_level, true) : method->code(); if (nm != nullptr) { - nm->make_not_entrant(); + nm->make_not_entrant("CI replay"); } replay_state = this; CompileBroker::compile_method(methodHandle(THREAD, method), entry_bci, comp_level, diff --git a/src/hotspot/share/code/codeCache.cpp b/src/hotspot/share/code/codeCache.cpp index 3b237e9643e6a..53385400ffb6f 100644 --- a/src/hotspot/share/code/codeCache.cpp +++ b/src/hotspot/share/code/codeCache.cpp @@ -1364,7 +1364,7 @@ void CodeCache::make_marked_nmethods_deoptimized() { while(iter.next()) { nmethod* nm = iter.method(); if (nm->is_marked_for_deoptimization() && !nm->has_been_deoptimized() && nm->can_be_deoptimized()) { - nm->make_not_entrant(); + nm->make_not_entrant("marked for deoptimization"); nm->make_deoptimized(); } } diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index 3381a7cb72691..ff25cbfc5dc85 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -1957,7 +1957,9 @@ void nmethod::invalidate_osr_method() { } } -void nmethod::log_state_change() const { +void nmethod::log_state_change(const char* reason) const { + assert(reason != nullptr, "Must provide a reason"); + if (LogCompilation) { if (xtty != nullptr) { ttyLocker ttyl; // keep the following output all in one block @@ -1969,9 +1971,12 @@ void nmethod::log_state_change() const { } } - CompileTask::print_ul(this, "made not entrant"); + stringStream ss; + ss.print("made not entrant: %s", reason); + + CompileTask::print_ul(this, ss.freeze()); if (PrintCompilation) { - print_on_with_msg(tty, "made not entrant"); + print_on_with_msg(tty, ss.freeze()); } } @@ -1982,7 +1987,9 @@ void nmethod::unlink_from_method() { } // Invalidate code -bool nmethod::make_not_entrant() { +bool nmethod::make_not_entrant(const char* reason) { + assert(reason != nullptr, "Must provide a reason"); + // This can be called while the system is already at a safepoint which is ok NoSafepointVerifier nsv; @@ -2040,7 +2047,7 @@ bool nmethod::make_not_entrant() { assert(success, "Transition can't fail"); // Log the transition once - log_state_change(); + log_state_change(reason); // Remove nmethod from method. unlink_from_method(); diff --git a/src/hotspot/share/code/nmethod.hpp b/src/hotspot/share/code/nmethod.hpp index ac9b1a7098f8d..f05745ffb34e7 100644 --- a/src/hotspot/share/code/nmethod.hpp +++ b/src/hotspot/share/code/nmethod.hpp @@ -631,8 +631,8 @@ class nmethod : public CodeBlob { // alive. It is used when an uncommon trap happens. Returns true // if this thread changed the state of the nmethod or false if // another thread performed the transition. - bool make_not_entrant(); - bool make_not_used() { return make_not_entrant(); } + bool make_not_entrant(const char* reason); + bool make_not_used() { return make_not_entrant("not used"); } bool is_marked_for_deoptimization() const { return deoptimization_status() != not_marked; } bool has_been_deoptimized() const { return deoptimization_status() == deoptimize_done; } @@ -945,7 +945,7 @@ class nmethod : public CodeBlob { // Logging void log_identity(xmlStream* log) const; void log_new_nmethod() const; - void log_state_change() const; + void log_state_change(const char* reason) const; // Prints block-level comments, including nmethod specific block labels: void print_nmethod_labels(outputStream* stream, address block_begin, bool print_section_labels=true) const; diff --git a/src/hotspot/share/compiler/compilationPolicy.cpp b/src/hotspot/share/compiler/compilationPolicy.cpp index 82061d92daa7c..e9ae528d0a00a 100644 --- a/src/hotspot/share/compiler/compilationPolicy.cpp +++ b/src/hotspot/share/compiler/compilationPolicy.cpp @@ -796,7 +796,7 @@ void CompilationPolicy::compile(const methodHandle& mh, int bci, CompLevel level nmethod* osr_nm = mh->lookup_osr_nmethod_for(bci, CompLevel_simple, false); if (osr_nm != nullptr && osr_nm->comp_level() > CompLevel_simple) { // Invalidate the existing OSR nmethod so that a compile at CompLevel_simple is permitted. - osr_nm->make_not_entrant(); + osr_nm->make_not_entrant("OSR invalidation for compiling with C1"); } compile(mh, bci, CompLevel_simple, THREAD); } @@ -1201,7 +1201,7 @@ void CompilationPolicy::method_back_branch_event(const methodHandle& mh, const m int osr_bci = nm->is_osr_method() ? nm->osr_entry_bci() : InvocationEntryBci; print_event(MAKE_NOT_ENTRANT, mh(), mh(), osr_bci, level); } - nm->make_not_entrant(); + nm->make_not_entrant("OSR invalidation, back branch"); } } // Fix up next_level if necessary to avoid deopts diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp index f2807dbecd79c..2e42d5df55b9b 100644 --- a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp +++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp @@ -1369,7 +1369,7 @@ C2V_VMENTRY(void, reprofile, (JNIEnv* env, jobject, ARGUMENT_PAIR(method))) nmethod* code = method->code(); if (code != nullptr) { - code->make_not_entrant(); + code->make_not_entrant("JVMCI reprofile"); } MethodData* method_data = method->method_data(); @@ -1809,7 +1809,7 @@ C2V_VMENTRY(void, materializeVirtualObjects, (JNIEnv* env, jobject, jobject _hs_ if (!fst.current()->is_compiled_frame()) { JVMCI_THROW_MSG(IllegalStateException, "compiled stack frame expected"); } - fst.current()->cb()->as_nmethod()->make_not_entrant(); + fst.current()->cb()->as_nmethod()->make_not_entrant("JVMCI materialize virtual objects"); } Deoptimization::deoptimize(thread, *fst.current(), Deoptimization::Reason_none); // look for the frame again as it has been updated by deopt (pc, deopt state...) diff --git a/src/hotspot/share/jvmci/jvmciEnv.cpp b/src/hotspot/share/jvmci/jvmciEnv.cpp index 78f5bca476957..edf0f836bf68c 100644 --- a/src/hotspot/share/jvmci/jvmciEnv.cpp +++ b/src/hotspot/share/jvmci/jvmciEnv.cpp @@ -1775,7 +1775,7 @@ void JVMCIEnv::invalidate_nmethod_mirror(JVMCIObject mirror, bool deoptimize, JV if (!deoptimize) { // Prevent future executions of the nmethod but let current executions complete. - nm->make_not_entrant(); + nm->make_not_entrant("JVMCI invalidate nmethod mirror"); // Do not clear the address field here as the Java code may still // want to later call this method with deoptimize == true. That requires @@ -1784,7 +1784,7 @@ void JVMCIEnv::invalidate_nmethod_mirror(JVMCIObject mirror, bool deoptimize, JV // Deoptimize the nmethod immediately. DeoptimizationScope deopt_scope; deopt_scope.mark(nm); - nm->make_not_entrant(); + nm->make_not_entrant("JVMCI invalidate nmethod mirror"); nm->make_deoptimized(); deopt_scope.deoptimize_marked(); diff --git a/src/hotspot/share/jvmci/jvmciRuntime.cpp b/src/hotspot/share/jvmci/jvmciRuntime.cpp index c88a4390590d0..018824a03e944 100644 --- a/src/hotspot/share/jvmci/jvmciRuntime.cpp +++ b/src/hotspot/share/jvmci/jvmciRuntime.cpp @@ -2195,8 +2195,8 @@ JVMCI::CodeInstallResult JVMCIRuntime::register_method(JVMCIEnv* JVMCIENV, char *method_name = method->name_and_sig_as_C_string(); tty->print_cr("Replacing method %s", method_name); } - if (old != nullptr ) { - old->make_not_entrant(); + if (old != nullptr) { + old->make_not_entrant("JVMCI register method"); } LogTarget(Info, nmethod, install) lt; diff --git a/src/hotspot/share/oops/instanceKlass.cpp b/src/hotspot/share/oops/instanceKlass.cpp index fb1b84b826a60..36b7b8778a0dd 100644 --- a/src/hotspot/share/oops/instanceKlass.cpp +++ b/src/hotspot/share/oops/instanceKlass.cpp @@ -3503,7 +3503,7 @@ void InstanceKlass::add_osr_nmethod(nmethod* n) { for (int l = CompLevel_limited_profile; l < n->comp_level(); l++) { nmethod *inv = lookup_osr_nmethod(n->method(), n->osr_entry_bci(), l, true); if (inv != nullptr && inv->is_in_use()) { - inv->make_not_entrant(); + inv->make_not_entrant("OSR invalidation of lower levels"); } } } diff --git a/src/hotspot/share/oops/method.cpp b/src/hotspot/share/oops/method.cpp index 1a3b908434f1d..012420aaf5063 100644 --- a/src/hotspot/share/oops/method.cpp +++ b/src/hotspot/share/oops/method.cpp @@ -970,7 +970,7 @@ void Method::set_native_function(address function, bool post_event_flag) { // If so, we have to make it not_entrant. nmethod* nm = code(); // Put it into local variable to guard against concurrent updates if (nm != nullptr) { - nm->make_not_entrant(); + nm->make_not_entrant("set native function"); } } diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index dd5a23f9209e6..4f57718f200c7 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -783,7 +783,7 @@ class VM_WhiteBoxDeoptimizeFrames : public VM_WhiteBoxOperation { if (_make_not_entrant) { nmethod* nm = CodeCache::find_nmethod(f->pc()); assert(nm != nullptr, "did not find nmethod"); - nm->make_not_entrant(); + nm->make_not_entrant("Whitebox deoptimization"); } ++_result; } diff --git a/src/hotspot/share/runtime/deoptimization.cpp b/src/hotspot/share/runtime/deoptimization.cpp index 167b3095fa9f2..748cd0d793986 100644 --- a/src/hotspot/share/runtime/deoptimization.cpp +++ b/src/hotspot/share/runtime/deoptimization.cpp @@ -1807,7 +1807,7 @@ void Deoptimization::deoptimize(JavaThread* thread, frame fr, DeoptReason reason #if INCLUDE_JVMCI address Deoptimization::deoptimize_for_missing_exception_handler(nmethod* nm) { // there is no exception handler for this pc => deoptimize - nm->make_not_entrant(); + nm->make_not_entrant("missing exception handler"); // Use Deoptimization::deoptimize for all of its side-effects: // gathering traps statistics, logging... @@ -2436,7 +2436,7 @@ JRT_ENTRY(void, Deoptimization::uncommon_trap_inner(JavaThread* current, jint tr // Recompile if (make_not_entrant) { - if (!nm->make_not_entrant()) { + if (!nm->make_not_entrant("uncommon trap")) { return; // the call did not change nmethod's state } diff --git a/src/hotspot/share/runtime/javaThread.cpp b/src/hotspot/share/runtime/javaThread.cpp index 029c984511427..9579737396a75 100644 --- a/src/hotspot/share/runtime/javaThread.cpp +++ b/src/hotspot/share/runtime/javaThread.cpp @@ -1342,7 +1342,7 @@ void JavaThread::make_zombies() { // it is a Java nmethod nmethod* nm = CodeCache::find_nmethod(fst.current()->pc()); assert(nm != nullptr, "did not find nmethod"); - nm->make_not_entrant(); + nm->make_not_entrant("zombie"); } } } From b13a1080c1dd936671bacc14520663589aea48e8 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Tue, 11 Mar 2025 12:15:48 +0100 Subject: [PATCH 2/4] Use resource allocation for temp buffer --- src/hotspot/share/code/nmethod.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index ff25cbfc5dc85..1e331cd57d37b 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -1971,7 +1971,8 @@ void nmethod::log_state_change(const char* reason) const { } } - stringStream ss; + ResourceMark rm; + stringStream ss(NEW_RESOURCE_ARRAY(char, 256), 256); ss.print("made not entrant: %s", reason); CompileTask::print_ul(this, ss.freeze()); From 38491fb26b987225f03d4cec1d6a6453a0c95764 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Wed, 12 Mar 2025 08:30:59 +0100 Subject: [PATCH 3/4] Add to LogCompilation as well --- src/hotspot/share/code/nmethod.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index 52994c531ab81..d25b88719e82f 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -1974,8 +1974,8 @@ void nmethod::log_state_change(const char* reason) const { if (LogCompilation) { if (xtty != nullptr) { ttyLocker ttyl; // keep the following output all in one block - xtty->begin_elem("make_not_entrant thread='%zu'", - os::current_thread_id()); + xtty->begin_elem("make_not_entrant thread='%zu' reason='%s'", + os::current_thread_id(), reason); log_identity(xtty); xtty->stamp(); xtty->end_elem(); From 5da9766de961d0c9ccbeda0789429c3e212e92c6 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Wed, 12 Mar 2025 18:33:51 +0100 Subject: [PATCH 4/4] Add LogCompilation support --- .../sun/hotspot/tools/compiler/LogParser.java | 4 +++ .../tools/compiler/MakeNotEntrantEvent.java | 29 +++++++++++++++++-- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/src/utils/LogCompilation/src/main/java/com/sun/hotspot/tools/compiler/LogParser.java b/src/utils/LogCompilation/src/main/java/com/sun/hotspot/tools/compiler/LogParser.java index e1e305abe109a..61cbc054200c5 100644 --- a/src/utils/LogCompilation/src/main/java/com/sun/hotspot/tools/compiler/LogParser.java +++ b/src/utils/LogCompilation/src/main/java/com/sun/hotspot/tools/compiler/LogParser.java @@ -1099,6 +1099,10 @@ public void startElement(String uri, String localName, String qname, Attributes e.setCompileKind(compileKind); String level = atts.getValue("level"); e.setLevel(level); + String reason = atts.getValue("reason"); + if (reason != null) { + e.setReason(reason); + } events.add(e); } else if (qname.equals("uncommon_trap")) { String id = atts.getValue("compile_id"); diff --git a/src/utils/LogCompilation/src/main/java/com/sun/hotspot/tools/compiler/MakeNotEntrantEvent.java b/src/utils/LogCompilation/src/main/java/com/sun/hotspot/tools/compiler/MakeNotEntrantEvent.java index b4015537c7420..d230f1b433639 100644 --- a/src/utils/LogCompilation/src/main/java/com/sun/hotspot/tools/compiler/MakeNotEntrantEvent.java +++ b/src/utils/LogCompilation/src/main/java/com/sun/hotspot/tools/compiler/MakeNotEntrantEvent.java @@ -47,6 +47,11 @@ class MakeNotEntrantEvent extends BasicLogEvent { */ private String level; + /** + * The reason of invalidation. + */ + private String reason; + /** * The compile kind. */ @@ -64,10 +69,14 @@ public NMethod getNMethod() { public void print(PrintStream stream, boolean printID) { if (isZombie()) { - stream.printf("%s make_zombie\n", getId()); + stream.printf("%s make_zombie", getId()); } else { - stream.printf("%s make_not_entrant\n", getId()); + stream.printf("%s make_not_entrant", getId()); + } + if (getReason() != null) { + stream.printf(": %s", getReason()); } + stream.println(); } public boolean isZombie() { @@ -88,7 +97,21 @@ public void setLevel(String level) { this.level = level; } - /** + /** + * @return the reason + */ + public String getReason() { + return reason; + } + + /** + * @param reason the reason to set + */ + public void setReason(String reason) { + this.reason = reason; + } + + /** * @return the compileKind */ public String getCompileKind() {