From 08ee7ae67246b45be9684a4a283f0103f5f1c0c4 Mon Sep 17 00:00:00 2001 From: David Holmes Date: Thu, 24 Jun 2021 23:58:32 +0000 Subject: [PATCH] 8268855: Cleanup name handling in the Thread class and subclasses Reviewed-by: lfoltan, coleenp --- .../gc/shared/barrierSetNMethod_aarch64.cpp | 2 +- .../x86/gc/shared/barrierSetNMethod_x86.cpp | 4 +-- src/hotspot/share/compiler/compileBroker.cpp | 16 +++++------ .../share/gc/shared/concurrentGCThread.hpp | 3 ++ src/hotspot/share/gc/shared/workgroup.hpp | 3 ++ .../gc/shenandoah/shenandoahControlThread.hpp | 2 +- .../periodic/sampling/jfrThreadSampler.cpp | 3 +- src/hotspot/share/jvmci/jvmciCompilerToVM.cpp | 2 +- src/hotspot/share/jvmci/jvmciEnv.cpp | 2 +- src/hotspot/share/logging/logAsyncWriter.hpp | 3 +- src/hotspot/share/prims/jni.cpp | 2 +- src/hotspot/share/runtime/nonJavaThread.hpp | 17 ++++++++--- src/hotspot/share/runtime/thread.cpp | 28 ++++++------------- src/hotspot/share/runtime/thread.hpp | 24 +++++++++++----- src/hotspot/share/runtime/vmThread.hpp | 3 ++ src/hotspot/share/services/threadService.cpp | 8 +++--- 16 files changed, 71 insertions(+), 51 deletions(-) diff --git a/src/hotspot/cpu/aarch64/gc/shared/barrierSetNMethod_aarch64.cpp b/src/hotspot/cpu/aarch64/gc/shared/barrierSetNMethod_aarch64.cpp index 8598fb7e7c1..4ce9869a157 100644 --- a/src/hotspot/cpu/aarch64/gc/shared/barrierSetNMethod_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/gc/shared/barrierSetNMethod_aarch64.cpp @@ -116,7 +116,7 @@ void BarrierSetNMethod::deoptimize(nmethod* nm, address* return_address_ptr) { log_trace(nmethod, barrier)("deoptimize(nmethod: %s(%p), return_addr: %p, osr: %d, thread: %p(%s), making rsp: %p) -> %p", nm->method()->name_and_sig_as_C_string(), nm, *(address *) return_address_ptr, nm->is_osr_method(), thread, - thread->get_thread_name(), frame.sp(), nm->verified_entry_point()); + thread->name(), frame.sp(), nm->verified_entry_point()); } new_frame->sp = frame.sp(); diff --git a/src/hotspot/cpu/x86/gc/shared/barrierSetNMethod_x86.cpp b/src/hotspot/cpu/x86/gc/shared/barrierSetNMethod_x86.cpp index d96ea768914..9da848f65bc 100644 --- a/src/hotspot/cpu/x86/gc/shared/barrierSetNMethod_x86.cpp +++ b/src/hotspot/cpu/x86/gc/shared/barrierSetNMethod_x86.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2021, 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 @@ -132,7 +132,7 @@ void BarrierSetNMethod::deoptimize(nmethod* nm, address* return_address_ptr) { ResourceMark mark; log_trace(nmethod, barrier)("deoptimize(nmethod: %p, return_addr: %p, osr: %d, thread: %p(%s), making rsp: %p) -> %p", nm, (address *) return_address_ptr, nm->is_osr_method(), jth, - jth->get_thread_name(), callers_rsp, nm->verified_entry_point()); + jth->name(), callers_rsp, nm->verified_entry_point()); } assert(nm->frame_size() >= 3, "invariant"); diff --git a/src/hotspot/share/compiler/compileBroker.cpp b/src/hotspot/share/compiler/compileBroker.cpp index 8f573b0fc8a..c8a331e6f7b 100644 --- a/src/hotspot/share/compiler/compileBroker.cpp +++ b/src/hotspot/share/compiler/compileBroker.cpp @@ -1008,9 +1008,9 @@ void CompileBroker::init_compiler_sweeper_threads() { _compilers[1]->set_num_compiler_threads(i + 1); if (TraceCompilerThreads) { ResourceMark rm; - ThreadsListHandle tlh; // get_thread_name() depends on the TLH. + ThreadsListHandle tlh; // name() depends on the TLH. assert(tlh.includes(ct), "ct=" INTPTR_FORMAT " exited unexpectedly.", p2i(ct)); - tty->print_cr("Added initial compiler thread %s", ct->get_thread_name()); + tty->print_cr("Added initial compiler thread %s", ct->name()); } } } @@ -1029,9 +1029,9 @@ void CompileBroker::init_compiler_sweeper_threads() { _compilers[0]->set_num_compiler_threads(i + 1); if (TraceCompilerThreads) { ResourceMark rm; - ThreadsListHandle tlh; // get_thread_name() depends on the TLH. + ThreadsListHandle tlh; // name() depends on the TLH. assert(tlh.includes(ct), "ct=" INTPTR_FORMAT " exited unexpectedly.", p2i(ct)); - tty->print_cr("Added initial compiler thread %s", ct->get_thread_name()); + tty->print_cr("Added initial compiler thread %s", ct->name()); } } } @@ -1116,10 +1116,10 @@ void CompileBroker::possibly_add_compiler_threads(JavaThread* THREAD) { _compilers[1]->set_num_compiler_threads(i + 1); if (TraceCompilerThreads) { ResourceMark rm; - ThreadsListHandle tlh; // get_thread_name() depends on the TLH. + ThreadsListHandle tlh; // name() depends on the TLH. assert(tlh.includes(ct), "ct=" INTPTR_FORMAT " exited unexpectedly.", p2i(ct)); tty->print_cr("Added compiler thread %s (available memory: %dMB, available non-profiled code cache: %dMB)", - ct->get_thread_name(), (int)(available_memory/M), (int)(available_cc_np/M)); + ct->name(), (int)(available_memory/M), (int)(available_cc_np/M)); } } } @@ -1137,10 +1137,10 @@ void CompileBroker::possibly_add_compiler_threads(JavaThread* THREAD) { _compilers[0]->set_num_compiler_threads(i + 1); if (TraceCompilerThreads) { ResourceMark rm; - ThreadsListHandle tlh; // get_thread_name() depends on the TLH. + ThreadsListHandle tlh; // name() depends on the TLH. assert(tlh.includes(ct), "ct=" INTPTR_FORMAT " exited unexpectedly.", p2i(ct)); tty->print_cr("Added compiler thread %s (available memory: %dMB, available profiled code cache: %dMB)", - ct->get_thread_name(), (int)(available_memory/M), (int)(available_cc_p/M)); + ct->name(), (int)(available_memory/M), (int)(available_cc_p/M)); } } } diff --git a/src/hotspot/share/gc/shared/concurrentGCThread.hpp b/src/hotspot/share/gc/shared/concurrentGCThread.hpp index 34c4717c9f3..d7bcf4a42ce 100644 --- a/src/hotspot/share/gc/shared/concurrentGCThread.hpp +++ b/src/hotspot/share/gc/shared/concurrentGCThread.hpp @@ -49,6 +49,9 @@ public: bool should_terminate() const; bool has_terminated() const; + + // Printing + const char* type_name() const { return "ConcurrentGCThread"; } }; #endif // SHARE_GC_SHARED_CONCURRENTGCTHREAD_HPP diff --git a/src/hotspot/share/gc/shared/workgroup.hpp b/src/hotspot/share/gc/shared/workgroup.hpp index 02b39c83890..c43cd873ec2 100644 --- a/src/hotspot/share/gc/shared/workgroup.hpp +++ b/src/hotspot/share/gc/shared/workgroup.hpp @@ -219,6 +219,9 @@ public: // Predicate for Thread bool is_GC_task_thread() const override { return gang()->are_GC_task_threads(); } bool is_ConcurrentGC_thread() const override { return gang()->are_ConcurrentGC_threads(); } + + // Printing + const char* type_name() const override { return "GCTaskThread"; } }; // A class that acts as a synchronisation barrier. Workers enter diff --git a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.hpp b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.hpp index 84ffa11e8f0..532d59f216c 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.hpp @@ -143,7 +143,7 @@ public: void prepare_for_graceful_shutdown(); bool in_graceful_shutdown(); - char* name() const { return (char*)"ShenandoahControlThread";} + const char* name() const { return "ShenandoahControlThread";} // Printing void print_on(outputStream* st) const; diff --git a/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp b/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp index eb40abf2fd4..96ba5bf14c9 100644 --- a/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp +++ b/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp @@ -343,7 +343,8 @@ class JfrThreadSampler : public NonJavaThread { protected: virtual void post_run(); public: - virtual char* name() const { return (char*)"JFR Thread Sampler"; } + virtual const char* name() const { return "JFR Thread Sampler"; } + virtual const char* type_name() const { return "JfrThreadSampler"; } bool is_JfrSampler_thread() const { return true; } void run(); static Monitor* transition_block() { return JfrThreadSampler_lock; } diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp index 7184962d14f..26af6ed2183 100644 --- a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp +++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp @@ -2279,7 +2279,7 @@ C2V_VMENTRY_PREFIX(jboolean, attachCurrentThread, (JNIEnv* env, jobject c2vm, jb JavaVMAttachArgs attach_args; attach_args.version = JNI_VERSION_1_2; - attach_args.name = thread->name(); + attach_args.name = const_cast(thread->name()); attach_args.group = NULL; JNIEnv* peerJNIEnv; if (runtime->GetEnv(thread, (void**) &peerJNIEnv, JNI_VERSION_1_2) == JNI_OK) { diff --git a/src/hotspot/share/jvmci/jvmciEnv.cpp b/src/hotspot/share/jvmci/jvmciEnv.cpp index ff8074c67d0..aaebf8dc111 100644 --- a/src/hotspot/share/jvmci/jvmciEnv.cpp +++ b/src/hotspot/share/jvmci/jvmciEnv.cpp @@ -205,7 +205,7 @@ void JVMCIEnv::init_env_mode_runtime(JavaThread* thread, JNIEnv* parent_env) { ResourceMark rm; // Thread name is resource allocated JavaVMAttachArgs attach_args; attach_args.version = JNI_VERSION_1_2; - attach_args.name = thread->name(); + attach_args.name = const_cast(thread->name()); attach_args.group = NULL; if (_runtime->AttachCurrentThread(thread, (void**) &_env, &attach_args) != JNI_OK) { fatal("Error attaching current thread (%s) to JVMCI shared library JNI interface", attach_args.name); diff --git a/src/hotspot/share/logging/logAsyncWriter.hpp b/src/hotspot/share/logging/logAsyncWriter.hpp index e907fd207fa..0cb36405647 100644 --- a/src/hotspot/share/logging/logAsyncWriter.hpp +++ b/src/hotspot/share/logging/logAsyncWriter.hpp @@ -160,7 +160,8 @@ class AsyncLogWriter : public NonJavaThread { NonJavaThread::pre_run(); log_debug(logging, thread)("starting AsyncLog Thread tid = " INTX_FORMAT, os::current_thread_id()); } - char* name() const override { return (char*)"AsyncLog Thread"; } + const char* name() const override { return "AsyncLog Thread"; } + const char* type_name() const override { return "AsyncLogWriter"; } void print_on(outputStream* st) const override { st->print("\"%s\" ", name()); Thread::print_on(st); diff --git a/src/hotspot/share/prims/jni.cpp b/src/hotspot/share/prims/jni.cpp index a0b0e36b8e6..6ed7d845e1e 100644 --- a/src/hotspot/share/prims/jni.cpp +++ b/src/hotspot/share/prims/jni.cpp @@ -576,7 +576,7 @@ JNI_ENTRY_NO_PRESERVE(void, jni_ExceptionDescribe(JNIEnv *env)) if (thread != NULL && thread->threadObj() != NULL) { ResourceMark rm(THREAD); jio_fprintf(defaultStream::error_stream(), - "in thread \"%s\" ", thread->get_thread_name()); + "in thread \"%s\" ", thread->name()); } if (ex->is_a(vmClasses::Throwable_klass())) { JavaValue result(T_VOID); diff --git a/src/hotspot/share/runtime/nonJavaThread.hpp b/src/hotspot/share/runtime/nonJavaThread.hpp index 04693bb8327..0556fa95044 100644 --- a/src/hotspot/share/runtime/nonJavaThread.hpp +++ b/src/hotspot/share/runtime/nonJavaThread.hpp @@ -70,8 +70,10 @@ public: void step(); }; -// Name support for threads. non-JavaThread subclasses with multiple -// uniquely named instances should derive from this. +// A base class for non-JavaThread subclasses with multiple +// uniquely named instances. NamedThreads also provide a common +// location to store GC information needed by GC threads +// and the VMThread. class NamedThread: public NonJavaThread { friend class VMStructs; enum { @@ -89,7 +91,8 @@ class NamedThread: public NonJavaThread { // May only be called once per thread. void set_name(const char* format, ...) ATTRIBUTE_PRINTF(2, 3); virtual bool is_Named_thread() const { return true; } - virtual char* name() const { return _name == NULL ? (char*)"Unknown Thread" : _name; } + virtual const char* name() const { return _name == NULL ? "Unknown Thread" : _name; } + virtual const char* type_name() const { return "NamedThread"; } Thread *processed_thread() { return _processed_thread; } void set_processed_thread(Thread *thread) { _processed_thread = thread; } virtual void print_on(outputStream* st) const; @@ -117,6 +120,10 @@ class WorkerThread: public NamedThread { void set_id(uint work_id) { _id = work_id; } uint id() const { return _id; } + + // Printing + virtual const char* type_name() const { return "WorkerThread"; } + }; // A single WatcherThread is used for simulating timer interrupts. @@ -132,6 +139,7 @@ class WatcherThread: public NonJavaThread { // volatile due to at least one lock-free read volatile static bool _should_terminate; public: + enum SomeConstants { delay_interval = 10 // interrupt delay in milliseconds }; @@ -148,7 +156,8 @@ class WatcherThread: public NonJavaThread { bool is_Watcher_thread() const { return true; } // Printing - char* name() const { return (char*)"VM Periodic Task Thread"; } + const char* name() const { return "VM Periodic Task Thread"; } + const char* type_name() const { return "WatcherThread"; } void print_on(outputStream* st) const; void unpark(); diff --git a/src/hotspot/share/runtime/thread.cpp b/src/hotspot/share/runtime/thread.cpp index 684d47c76cc..2d381c8349f 100644 --- a/src/hotspot/share/runtime/thread.cpp +++ b/src/hotspot/share/runtime/thread.cpp @@ -162,7 +162,7 @@ void universe_post_module_init(); // must happen after call_initPhase2 { \ ResourceMark rm(this); \ int len = 0; \ - const char* name = (javathread)->get_thread_name(); \ + const char* name = (javathread)->name(); \ len = strlen(name); \ HOTSPOT_THREAD_PROBE_##probe(/* probe = start, stop */ \ (char *) name, len, \ @@ -609,17 +609,7 @@ void Thread::print() const { print_on(tty); } void Thread::print_on_error(outputStream* st, char* buf, int buflen) const { assert(!(is_Compiler_thread() || is_Java_thread()), "Can't call name() here if it allocates"); - if (is_VM_thread()) { st->print("VMThread"); } - else if (is_GC_task_thread()) { st->print("GCTaskThread"); } - else if (is_Watcher_thread()) { st->print("WatcherThread"); } - else if (is_ConcurrentGC_thread()) { st->print("ConcurrentGCThread"); } - else if (this == AsyncLogWriter::instance()) { - st->print("%s", this->name()); - } else { st->print("Thread"); } - - if (is_Named_thread()) { - st->print(" \"%s\"", name()); - } + st->print("%s \"%s\"", type_name(), name()); OSThread* os_thr = osthread(); if (os_thr != NULL) { @@ -1272,7 +1262,7 @@ void JavaThread::thread_main_inner() { !java_lang_Thread::is_stillborn(this->threadObj())) { { ResourceMark rm(this); - this->set_native_thread_name(this->get_thread_name()); + this->set_native_thread_name(this->name()); } HandleMark hm(this); this->entry_point()(this, this); @@ -1351,7 +1341,7 @@ void JavaThread::exit(bool destroy_vm, ExitType exit_type) { "\nException: %s thrown from the UncaughtExceptionHandler" " in thread \"%s\"\n", pending_exception()->klass()->external_name(), - get_thread_name()); + name()); CLEAR_PENDING_EXCEPTION; } } @@ -1456,7 +1446,7 @@ void JavaThread::exit(bool destroy_vm, ExitType exit_type) { char* thread_name = NULL; if (log_is_enabled(Debug, os, thread, timer)) { ResourceMark rm(this); - thread_name = os::strdup(get_thread_name()); + thread_name = os::strdup(name()); } log_info(os, thread)("JavaThread %s (tid: " UINTX_FORMAT ").", @@ -2053,7 +2043,7 @@ void JavaThread::print_thread_state_on(outputStream *st) const { // Called by Threads::print() for VM_PrintThreads operation void JavaThread::print_on(outputStream *st, bool print_extended_info) const { st->print_raw("\""); - st->print_raw(get_thread_name()); + st->print_raw(name()); st->print_raw("\" "); oop thread_oop = threadObj(); if (thread_oop != NULL) { @@ -2091,7 +2081,7 @@ void JavaThread::print_name_on_error(outputStream* st, char *buf, int buflen) co // Called by fatal error handler. The difference between this and // JavaThread::print() is that we can't grab lock or allocate memory. void JavaThread::print_on_error(outputStream* st, char *buf, int buflen) const { - st->print("JavaThread \"%s\"", get_thread_name_string(buf, buflen)); + st->print("%s \"%s\"", type_name(), get_thread_name_string(buf, buflen)); oop thread_obj = threadObj(); if (thread_obj != NULL) { if (java_lang_Thread::is_daemon(thread_obj)) st->print(" daemon"); @@ -2139,7 +2129,7 @@ void JavaThread::verify() { // seen prior to having its threadObj set (e.g., JNI attaching threads and // if vm exit occurs during initialization). These cases can all be accounted // for such that this method never returns NULL. -const char* JavaThread::get_thread_name() const { +const char* JavaThread::name() const { if (Thread::is_JavaThread_protected(this)) { // The target JavaThread is protected so get_thread_name_string() is safe: return get_thread_name_string(); @@ -2165,7 +2155,7 @@ const char* JavaThread::get_thread_name_string(char* buf, int buflen) const { } else if (is_attaching_via_jni()) { // workaround for 6412693 - see 6404306 name_str = ""; } else { - name_str = Thread::name(); + name_str = ""; } } else { name_str = Thread::name(); diff --git a/src/hotspot/share/runtime/thread.hpp b/src/hotspot/share/runtime/thread.hpp index d36098f913d..d26f130452f 100644 --- a/src/hotspot/share/runtime/thread.hpp +++ b/src/hotspot/share/runtime/thread.hpp @@ -352,7 +352,15 @@ class Thread: public ThreadShadow { // If so it must participate in the safepoint protocol. virtual bool is_active_Java_thread() const { return false; } - virtual char* name() const { return (char*)"Unknown thread"; } + // All threads are given names. For singleton subclasses we can + // just hard-wire the known name of the instance. JavaThreads and + // NamedThreads support multiple named instances, and dynamic + // changing of the name of an instance. + virtual const char* name() const { return "Unknown thread"; } + + // A thread's type name is also made available for debugging + // and logging. + virtual const char* type_name() const { return "Thread"; } // Returns the current thread (ASSERTS if NULL) static inline Thread* current(); @@ -568,6 +576,7 @@ protected: virtual void print_on(outputStream* st) const { print_on(st, false); } void print() const; virtual void print_on_error(outputStream* st, char* buf, int buflen) const; + // Basic, non-virtual, printing support that is simple and always safe. void print_value_on(outputStream* st) const; // Debug-only code @@ -1347,6 +1356,9 @@ class JavaThread: public Thread { private: void set_entry_point(ThreadFunction entry_point) { _entry_point = entry_point; } + // factor out low-level mechanics for use in both normal and error cases + const char* get_thread_name_string(char* buf = NULL, int buflen = 0) const; + public: // Frame iteration; calls the function f for all frames on the stack @@ -1366,7 +1378,9 @@ class JavaThread: public Thread { DEBUG_ONLY(void verify_states_for_handshake();) // Misc. operations - char* name() const { return (char*)get_thread_name(); } + const char* name() const; + const char* type_name() const { return "JavaThread"; } + void print_on(outputStream* st, bool print_extended_info) const; void print_on(outputStream* st) const { print_on(st, false); } void print() const; @@ -1374,11 +1388,7 @@ class JavaThread: public Thread { void print_on_error(outputStream* st, char* buf, int buflen) const; void print_name_on_error(outputStream* st, char* buf, int buflen) const; void verify(); - const char* get_thread_name() const; - protected: - // factor out low-level mechanics for use in both normal and error cases - virtual const char* get_thread_name_string(char* buf = NULL, int buflen = 0) const; - public: + // Accessing frames frame last_frame() { _anchor.make_walkable(this); diff --git a/src/hotspot/share/runtime/vmThread.hpp b/src/hotspot/share/runtime/vmThread.hpp index e15a26c01e9..e37189d586e 100644 --- a/src/hotspot/share/runtime/vmThread.hpp +++ b/src/hotspot/share/runtime/vmThread.hpp @@ -130,6 +130,9 @@ class VMThread: public NamedThread { static void wait_until_executed(VM_Operation* op); + // Printing + const char* type_name() const { return "VMThread"; } + private: // VM_Operation support static VM_Operation* _cur_vm_operation; // Current VM operation diff --git a/src/hotspot/share/services/threadService.cpp b/src/hotspot/share/services/threadService.cpp index 284a8424b0c..494ca337cf4 100644 --- a/src/hotspot/share/services/threadService.cpp +++ b/src/hotspot/share/services/threadService.cpp @@ -975,7 +975,7 @@ void DeadlockCycle::print_on_with(ThreadsList * t_list, outputStream* st) const waitingToLockRawMonitor = currentThread->current_pending_raw_monitor(); waitingToLockBlocker = currentThread->current_park_blocker(); st->cr(); - st->print_cr("\"%s\":", currentThread->get_thread_name()); + st->print_cr("\"%s\":", currentThread->name()); const char* owner_desc = ",\n which is held by"; // Note: As the JVM TI "monitor contended enter" event callback is executed after ObjectMonitor @@ -987,7 +987,7 @@ void DeadlockCycle::print_on_with(ThreadsList * t_list, outputStream* st) const if (owner != NULL) { if (owner->is_Java_thread()) { currentThread = JavaThread::cast(owner); - st->print_cr("%s \"%s\"", owner_desc, currentThread->get_thread_name()); + st->print_cr("%s \"%s\"", owner_desc, currentThread->name()); } else { st->print_cr(",\n which has now been released"); } @@ -1026,7 +1026,7 @@ void DeadlockCycle::print_on_with(ThreadsList * t_list, outputStream* st) const currentThread = java_lang_Thread::thread(ownerObj); assert(currentThread != NULL, "AbstractOwnableSynchronizer owning thread is unexpectedly NULL"); } - st->print_cr("%s \"%s\"", owner_desc, currentThread->get_thread_name()); + st->print_cr("%s \"%s\"", owner_desc, currentThread->name()); } st->cr(); @@ -1038,7 +1038,7 @@ void DeadlockCycle::print_on_with(ThreadsList * t_list, outputStream* st) const st->print_cr("==================================================="); for (int j = 0; j < len; j++) { currentThread = _threads->at(j); - st->print_cr("\"%s\":", currentThread->get_thread_name()); + st->print_cr("\"%s\":", currentThread->name()); currentThread->print_stack_on(st); } JavaMonitorsInStackTrace = oldJavaMonitorsInStackTrace;