Skip to content

Commit eac896d

Browse files
author
duke
committed
Backport f23752a
1 parent 58be870 commit eac896d

File tree

15 files changed

+274
-73
lines changed

15 files changed

+274
-73
lines changed

src/hotspot/share/jfr/jfr.cpp

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -32,6 +32,7 @@
3232
#include "jfr/recorder/repository/jfrEmergencyDump.hpp"
3333
#include "jfr/recorder/repository/jfrRepository.hpp"
3434
#include "jfr/recorder/service/jfrOptionSet.hpp"
35+
#include "jfr/recorder/service/jfrRecorderService.hpp"
3536
#include "jfr/support/jfrClassDefineEvent.hpp"
3637
#include "jfr/support/jfrKlassExtension.hpp"
3738
#include "jfr/support/jfrResolution.hpp"
@@ -43,6 +44,7 @@
4344
#include "runtime/java.hpp"
4445
#include "runtime/javaThread.hpp"
4546

47+
4648
bool Jfr::is_enabled() {
4749
return JfrRecorder::is_enabled();
4850
}
@@ -153,9 +155,9 @@ void Jfr::on_resolution(const Method* caller, const Method* target, TRAPS) {
153155
}
154156
#endif
155157

156-
void Jfr::on_vm_shutdown(bool emit_old_object_samples, bool emit_event_shutdown, bool halt) {
158+
void Jfr::on_vm_shutdown(bool exception_handler /* false */, bool halt /* false */, bool oom /* false */) {
157159
if (!halt && JfrRecorder::is_recording()) {
158-
JfrEmergencyDump::on_vm_shutdown(emit_old_object_samples, emit_event_shutdown);
160+
JfrEmergencyDump::on_vm_shutdown(exception_handler, oom);
159161
}
160162
}
161163

@@ -173,6 +175,12 @@ bool Jfr::on_start_flight_recording_option(const JavaVMOption** option, char* de
173175
return JfrOptionSet::parse_start_flight_recording_option(option, delimiter);
174176
}
175177

178+
void Jfr::on_report_java_out_of_memory() {
179+
if (CrashOnOutOfMemoryError && JfrRecorder::is_recording()) {
180+
JfrRecorderService::emit_leakprofiler_events_on_oom();
181+
}
182+
}
183+
176184
#if INCLUDE_CDS
177185
void Jfr::on_restoration(const Klass* k, JavaThread* jt) {
178186
assert(k != nullptr, "invariant");

src/hotspot/share/jfr/jfr.hpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -71,14 +71,15 @@ class Jfr : AllStatic {
7171
static void on_resolution(const Method* caller, const Method* target, TRAPS);
7272
static void on_java_thread_start(JavaThread* starter, JavaThread* startee);
7373
static void on_set_current_thread(JavaThread* jt, oop thread);
74-
static void on_vm_shutdown(bool emit_old_object_samples, bool emit_event_shutdown, bool halt = false);
74+
static void on_vm_shutdown(bool exception_handler = false, bool halt = false, bool oom = false);
7575
static void on_vm_error_report(outputStream* st);
7676
static bool on_flight_recorder_option(const JavaVMOption** option, char* delimiter);
7777
static bool on_start_flight_recording_option(const JavaVMOption** option, char* delimiter);
7878
static void on_backpatching(const Method* callee_method, JavaThread* jt);
7979
static void initialize_main_thread(JavaThread* jt);
8080
static bool has_sample_request(JavaThread* jt);
8181
static void check_and_process_sample_request(JavaThread* jt);
82+
static void on_report_java_out_of_memory();
8283
CDS_ONLY(static void on_restoration(const Klass* k, JavaThread* jt);)
8384
};
8485

src/hotspot/share/jfr/jni/jfrJniMethod.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -364,8 +364,7 @@ JVM_ENTRY_NO_ENV(void, jfr_set_force_instrumentation(JNIEnv* env, jclass jvm, jb
364364
JVM_END
365365

366366
NO_TRANSITION(void, jfr_emit_old_object_samples(JNIEnv* env, jclass jvm, jlong cutoff_ticks, jboolean emit_all, jboolean skip_bfs))
367-
JfrRecorderService service;
368-
service.emit_leakprofiler_events(cutoff_ticks, emit_all == JNI_TRUE, skip_bfs == JNI_TRUE);
367+
JfrRecorderService::emit_leakprofiler_events(cutoff_ticks, emit_all == JNI_TRUE, skip_bfs == JNI_TRUE);
369368
NO_TRANSITION_END
370369

371370
JVM_ENTRY_NO_ENV(void, jfr_exclude_thread(JNIEnv* env, jclass jvm, jobject t))

src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.cpp

Lines changed: 32 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2012, 2026, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -38,6 +38,8 @@
3838
#include "runtime/mutexLocker.hpp"
3939
#include "runtime/os.hpp"
4040
#include "runtime/thread.inline.hpp"
41+
#include "runtime/vmOperations.hpp"
42+
#include "runtime/vmThread.hpp"
4143
#include "utilities/growableArray.hpp"
4244
#include "utilities/ostream.hpp"
4345

@@ -460,15 +462,6 @@ static void release_locks(Thread* thread) {
460462
assert(thread != nullptr, "invariant");
461463
assert(!thread->is_Java_thread() || JavaThread::cast(thread)->thread_state() == _thread_in_vm, "invariant");
462464

463-
#ifdef ASSERT
464-
Mutex* owned_lock = thread->owned_locks();
465-
while (owned_lock != nullptr) {
466-
Mutex* next = owned_lock->next();
467-
owned_lock->unlock();
468-
owned_lock = next;
469-
}
470-
#endif // ASSERT
471-
472465
if (Threads_lock->owned_by_self()) {
473466
Threads_lock->unlock();
474467
}
@@ -550,17 +543,14 @@ class JavaThreadInVMAndNative : public StackObj {
550543
}
551544
};
552545

553-
static void post_events(bool emit_old_object_samples, bool emit_event_shutdown, Thread* thread) {
554-
if (emit_old_object_samples) {
555-
LeakProfiler::emit_events(max_jlong, false, false);
556-
}
557-
if (emit_event_shutdown) {
546+
static void post_events(bool exception_handler, bool oom, Thread * thread) {
547+
if (exception_handler) {
558548
EventShutdown e;
559-
e.set_reason("VM Error");
549+
e.set_reason(oom ? "CrashOnOutOfMemoryError" : "VM Error");
560550
e.commit();
561551
}
562552
EventDumpReason event;
563-
event.set_reason(emit_old_object_samples ? "Out of Memory" : "Crash");
553+
event.set_reason(exception_handler && oom ? "CrashOnOutOfMemoryError" : exception_handler ? "Crash" : "Out of Memory");
564554
event.set_recordingId(-1);
565555
event.commit();
566556
}
@@ -594,20 +584,40 @@ static bool guard_reentrancy() {
594584
return false;
595585
}
596586

597-
void JfrEmergencyDump::on_vm_shutdown(bool emit_old_object_samples, bool emit_event_shutdown) {
587+
void JfrEmergencyDump::on_vm_shutdown(bool exception_handler, bool oom) {
598588
if (!guard_reentrancy()) {
599589
return;
600590
}
591+
601592
Thread* const thread = Thread::current_or_null_safe();
602593
assert(thread != nullptr, "invariant");
594+
595+
// Ensure a JavaThread is _thread_in_vm when we make this call
596+
JavaThreadInVMAndNative jtivm(thread);
597+
post_events(exception_handler, oom, thread);
598+
603599
if (thread->is_Watcher_thread()) {
604-
log_info(jfr, system)("The Watcher thread crashed so no jfr emergency dump will be generated.");
600+
// We cannot attempt an emergency dump using the Watcher thread
601+
// because we rely on the WatcherThread task "is_error_reported()",
602+
// to exit the VM after a hardcoded timeout, should the relatively
603+
// risky operation of an emergency dump fail (deadlock, livelock).
604+
log_warning(jfr, system)
605+
("The Watcher thread crashed so no jfr emergency dump will be generated.");
605606
return;
606607
}
607-
// Ensure a JavaThread is _thread_in_vm when we make this call
608-
JavaThreadInVMAndNative jtivm(thread);
608+
609+
if (thread->is_VM_thread()) {
610+
const VM_Operation* const operation = VMThread::vm_operation();
611+
if (operation != nullptr && operation->type() == VM_Operation::VMOp_JFROldObject) {
612+
// We will not be able to issue a rotation because the rotation lock
613+
// is held by the JFR Recorder Thread that issued the VM_Operation.
614+
log_warning(jfr, system)
615+
("The VM Thread crashed as part of emitting leak profiler events so no jfr emergency dump will be generated.");
616+
return;
617+
}
618+
}
619+
609620
release_locks(thread);
610-
post_events(emit_old_object_samples, emit_event_shutdown, thread);
611621

612622
// if JavaThread, transition to _thread_in_native to issue a final flushpoint
613623
NoHandleMark nhm;

src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -39,7 +39,7 @@ class JfrEmergencyDump : AllStatic {
3939
static const char* chunk_path(const char* repository_path);
4040
static void on_vm_error(const char* repository_path);
4141
static void on_vm_error_report(outputStream* st, const char* repository_path);
42-
static void on_vm_shutdown(bool emit_old_object_samples, bool emit_event_shutdown);
42+
static void on_vm_shutdown(bool exception_handler, bool oom);
4343
};
4444

4545
#endif // SHARE_JFR_RECORDER_REPOSITORY_JFREMERGENCYDUMP_HPP

src/hotspot/share/jfr/recorder/service/jfrPostBox.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2013, 2026, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -34,7 +34,8 @@
3434
(MSGBIT(MSG_START)) | \
3535
(MSGBIT(MSG_CLONE_IN_MEMORY)) | \
3636
(MSGBIT(MSG_VM_ERROR)) | \
37-
(MSGBIT(MSG_FLUSHPOINT)) \
37+
(MSGBIT(MSG_FLUSHPOINT)) | \
38+
(MSGBIT(MSG_EMIT_LEAKP_REFCHAINS)) \
3839
)
3940

4041
static JfrPostBox* _instance = nullptr;
@@ -165,7 +166,7 @@ void JfrPostBox::notify_waiters() {
165166
assert(JfrMsg_lock->owned_by_self(), "incrementing _msg_handled_serial is protected by JfrMsg_lock.");
166167
// Update made visible on release of JfrMsg_lock via fence instruction in Monitor::IUnlock.
167168
++_msg_handled_serial;
168-
JfrMsg_lock->notify();
169+
JfrMsg_lock->notify_all();
169170
}
170171

171172
// safeguard to ensure no threads are left waiting

src/hotspot/share/jfr/recorder/service/jfrPostBox.hpp

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2013, 2026, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -43,6 +43,7 @@ enum JFR_Msg {
4343
MSG_SHUTDOWN,
4444
MSG_VM_ERROR,
4545
MSG_FLUSHPOINT,
46+
MSG_EMIT_LEAKP_REFCHAINS,
4647
MSG_NO_OF_MSGS
4748
};
4849

@@ -51,23 +52,25 @@ enum JFR_Msg {
5152
*
5253
* Synchronous messages (posting thread waits for message completion):
5354
*
54-
* MSG_CLONE_IN_MEMORY (0) ; MSGBIT(MSG_CLONE_IN_MEMORY) == (1 << 0) == 0x1
55-
* MSG_START(1) ; MSGBIT(MSG_START) == (1 << 0x1) == 0x2
56-
* MSG_STOP (2) ; MSGBIT(MSG_STOP) == (1 << 0x2) == 0x4
57-
* MSG_ROTATE (3) ; MSGBIT(MSG_ROTATE) == (1 << 0x3) == 0x8
58-
* MSG_VM_ERROR (8) ; MSGBIT(MSG_VM_ERROR) == (1 << 0x8) == 0x100
59-
* MSG_FLUSHPOINT (9) ; MSGBIT(MSG_FLUSHPOINT) == (1 << 0x9) == 0x200
55+
* MSG_CLONE_IN_MEMORY (0) ; MSGBIT(MSG_CLONE_IN_MEMORY) == (1 << 0) == 0x1
56+
* MSG_START(1) ; MSGBIT(MSG_START) == (1 << 0x1) == 0x2
57+
* MSG_STOP (2) ; MSGBIT(MSG_STOP) == (1 << 0x2) == 0x4
58+
* MSG_ROTATE (3) ; MSGBIT(MSG_ROTATE) == (1 << 0x3) == 0x8
59+
* MSG_VM_ERROR (8) ; MSGBIT(MSG_VM_ERROR) == (1 << 0x8) == 0x100
60+
* MSG_FLUSHPOINT (9) ; MSGBIT(MSG_FLUSHPOINT) == (1 << 0x9) == 0x200
61+
* MSG_EMIT_LEAKP_REFCHAINS (10); MSGBIT(MSG_EMIT_LEAKP_REFCHAINS) == (1 << 0xa) == 0x400
6062
*
6163
* Asynchronous messages (posting thread returns immediately upon deposit):
6264
*
63-
* MSG_FULLBUFFER (4) ; MSGBIT(MSG_FULLBUFFER) == (1 << 0x4) == 0x10
64-
* MSG_CHECKPOINT (5) ; MSGBIT(CHECKPOINT) == (1 << 0x5) == 0x20
65-
* MSG_WAKEUP (6) ; MSGBIT(WAKEUP) == (1 << 0x6) == 0x40
66-
* MSG_SHUTDOWN (7) ; MSGBIT(MSG_SHUTDOWN) == (1 << 0x7) == 0x80
65+
* MSG_FULLBUFFER (4) ; MSGBIT(MSG_FULLBUFFER) == (1 << 0x4) == 0x10
66+
* MSG_CHECKPOINT (5) ; MSGBIT(CHECKPOINT) == (1 << 0x5) == 0x20
67+
* MSG_WAKEUP (6) ; MSGBIT(WAKEUP) == (1 << 0x6) == 0x40
68+
* MSG_SHUTDOWN (7) ; MSGBIT(MSG_SHUTDOWN) == (1 << 0x7) == 0x80
6769
*/
6870

6971
class JfrPostBox : public JfrCHeapObj {
7072
friend class JfrRecorder;
73+
friend class JfrRecorderService;
7174
public:
7275
void post(JFR_Msg msg);
7376

0 commit comments

Comments
 (0)