diff options
| -rw-r--r-- | runtime/openjdkjvmti/ti_phase.cc | 13 | ||||
| -rw-r--r-- | runtime/openjdkjvmti/ti_phase.h | 1 | ||||
| -rw-r--r-- | runtime/openjdkjvmti/ti_thread.cc | 42 | ||||
| -rw-r--r-- | runtime/openjdkjvmti/ti_thread.h | 10 | ||||
| -rw-r--r-- | test/924-threads/expected.txt | 5 | ||||
| -rw-r--r-- | test/924-threads/src/Main.java | 5 |
6 files changed, 58 insertions, 18 deletions
diff --git a/runtime/openjdkjvmti/ti_phase.cc b/runtime/openjdkjvmti/ti_phase.cc index e494cb6530..941cf7b73b 100644 --- a/runtime/openjdkjvmti/ti_phase.cc +++ b/runtime/openjdkjvmti/ti_phase.cc @@ -40,6 +40,7 @@ #include "scoped_thread_state_change-inl.h" #include "thread-inl.h" #include "thread_list.h" +#include "ti_thread.h" namespace openjdkjvmti { @@ -69,6 +70,7 @@ struct PhaseUtil::PhaseCallback : public art::RuntimePhaseCallback { break; case RuntimePhase::kInit: { + ThreadUtil::CacheData(); ScopedLocalRef<jthread> thread(GetJniEnv(), GetCurrentJThread()); art::ScopedThreadSuspension sts(art::Thread::Current(), art::ThreadState::kNative); event_handler->DispatchEvent<ArtJvmtiEvent::kVmInit>(nullptr, GetJniEnv(), thread.get()); @@ -105,6 +107,16 @@ jvmtiError PhaseUtil::GetPhase(jvmtiEnv* env ATTRIBUTE_UNUSED, jvmtiPhase* phase return ERR(NONE); } +bool PhaseUtil::IsLivePhase() { + jvmtiPhase now = PhaseUtil::current_phase_; + DCHECK(now == JVMTI_PHASE_ONLOAD || + now == JVMTI_PHASE_PRIMORDIAL || + now == JVMTI_PHASE_START || + now == JVMTI_PHASE_LIVE || + now == JVMTI_PHASE_DEAD); + return now == JVMTI_PHASE_LIVE; +} + void PhaseUtil::SetToOnLoad() { DCHECK_EQ(0u, static_cast<size_t>(PhaseUtil::current_phase_)); PhaseUtil::current_phase_ = JVMTI_PHASE_ONLOAD; @@ -117,6 +129,7 @@ void PhaseUtil::SetToPrimordial() { void PhaseUtil::SetToLive() { DCHECK_EQ(static_cast<size_t>(0), static_cast<size_t>(PhaseUtil::current_phase_)); + ThreadUtil::CacheData(); PhaseUtil::current_phase_ = JVMTI_PHASE_LIVE; } diff --git a/runtime/openjdkjvmti/ti_phase.h b/runtime/openjdkjvmti/ti_phase.h index 851fc27de5..a2c0d114ef 100644 --- a/runtime/openjdkjvmti/ti_phase.h +++ b/runtime/openjdkjvmti/ti_phase.h @@ -42,6 +42,7 @@ class EventHandler; class PhaseUtil { public: static jvmtiError GetPhase(jvmtiEnv* env, jvmtiPhase* phase_ptr); + static bool IsLivePhase(); static void Register(EventHandler* event_handler); static void Unregister(); diff --git a/runtime/openjdkjvmti/ti_thread.cc b/runtime/openjdkjvmti/ti_thread.cc index 788ac30873..e5ff090ddf 100644 --- a/runtime/openjdkjvmti/ti_thread.cc +++ b/runtime/openjdkjvmti/ti_thread.cc @@ -44,6 +44,7 @@ #include "mirror/object-inl.h" #include "mirror/string.h" #include "obj_ptr.h" +#include "ti_phase.h" #include "runtime.h" #include "runtime_callbacks.h" #include "ScopedLocalRef.h" @@ -54,6 +55,8 @@ namespace openjdkjvmti { +art::ArtField* ThreadUtil::context_class_loader_ = nullptr; + struct ThreadCallback : public art::ThreadLifecycleCallback, public art::RuntimePhaseCallback { jthread GetThreadObject(art::Thread* self) REQUIRES_SHARED(art::Locks::mutator_lock_) { if (self->GetPeer() == nullptr) { @@ -121,6 +124,16 @@ void ThreadUtil::Register(EventHandler* handler) { runtime->GetRuntimeCallbacks()->AddRuntimePhaseCallback(&gThreadCallback); } +void ThreadUtil::CacheData() { + art::ScopedObjectAccess soa(art::Thread::Current()); + art::ObjPtr<art::mirror::Class> thread_class = + soa.Decode<art::mirror::Class>(art::WellKnownClasses::java_lang_Thread); + CHECK(thread_class != nullptr); + context_class_loader_ = thread_class->FindDeclaredInstanceField("contextClassLoader", + "Ljava/lang/ClassLoader;"); + CHECK(context_class_loader_ != nullptr); +} + void ThreadUtil::Unregister() { art::ScopedThreadStateChange stsc(art::Thread::Current(), art::ThreadState::kWaitingForDebuggerToAttach); @@ -146,22 +159,6 @@ jvmtiError ThreadUtil::GetCurrentThread(jvmtiEnv* env ATTRIBUTE_UNUSED, jthread* return ERR(NONE); } -// Read the context classloader from a Java thread object. This is a lazy implementation -// that assumes GetThreadInfo isn't called too often. If we instead cache the ArtField, -// we will have to add synchronization as this can't be cached on startup (which is -// potentially runtime startup). -static art::ObjPtr<art::mirror::Object> GetContextClassLoader(art::ObjPtr<art::mirror::Object> peer) - REQUIRES_SHARED(art::Locks::mutator_lock_) { - if (peer == nullptr) { - return nullptr; - } - art::ObjPtr<art::mirror::Class> klass = peer->GetClass(); - art::ArtField* cc_field = klass->FindDeclaredInstanceField("contextClassLoader", - "Ljava/lang/ClassLoader;"); - CHECK(cc_field != nullptr); - return cc_field->GetObject(peer); -} - // Get the native thread. The spec says a null object denotes the current thread. static art::Thread* GetNativeThread(jthread thread, const art::ScopedObjectAccessAlreadyRunnable& soa) @@ -178,6 +175,9 @@ jvmtiError ThreadUtil::GetThreadInfo(jvmtiEnv* env, jthread thread, jvmtiThreadI if (info_ptr == nullptr) { return ERR(NULL_POINTER); } + if (!PhaseUtil::IsLivePhase()) { + return JVMTI_ERROR_WRONG_PHASE; + } art::ScopedObjectAccess soa(art::Thread::Current()); @@ -217,7 +217,10 @@ jvmtiError ThreadUtil::GetThreadInfo(jvmtiEnv* env, jthread thread, jvmtiThreadI } // Context classloader. - art::ObjPtr<art::mirror::Object> ccl = GetContextClassLoader(peer); + DCHECK(context_class_loader_ != nullptr); + art::ObjPtr<art::mirror::Object> ccl = peer != nullptr + ? context_class_loader_->GetObject(peer) + : nullptr; info_ptr->context_class_loader = ccl == nullptr ? nullptr : soa.AddLocalReference<jobject>(ccl); @@ -272,7 +275,10 @@ jvmtiError ThreadUtil::GetThreadInfo(jvmtiEnv* env, jthread thread, jvmtiThreadI } // Context classloader. - art::ObjPtr<art::mirror::Object> ccl = GetContextClassLoader(peer); + DCHECK(context_class_loader_ != nullptr); + art::ObjPtr<art::mirror::Object> ccl = peer != nullptr + ? context_class_loader_->GetObject(peer) + : nullptr; info_ptr->context_class_loader = ccl == nullptr ? nullptr : soa.AddLocalReference<jobject>(ccl); diff --git a/runtime/openjdkjvmti/ti_thread.h b/runtime/openjdkjvmti/ti_thread.h index f6f93ee91a..c7f75d8aec 100644 --- a/runtime/openjdkjvmti/ti_thread.h +++ b/runtime/openjdkjvmti/ti_thread.h @@ -35,6 +35,10 @@ #include "jni.h" #include "jvmti.h" +namespace art { +class ArtField; +} + namespace openjdkjvmti { class EventHandler; @@ -44,6 +48,9 @@ class ThreadUtil { static void Register(EventHandler* event_handler); static void Unregister(); + // To be called when it is safe to cache data. + static void CacheData(); + static jvmtiError GetAllThreads(jvmtiEnv* env, jint* threads_count_ptr, jthread** threads_ptr); static jvmtiError GetCurrentThread(jvmtiEnv* env, jthread* thread_ptr); @@ -60,6 +67,9 @@ class ThreadUtil { jvmtiStartFunction proc, const void* arg, jint priority); + + private: + static art::ArtField* context_class_loader_; }; } // namespace openjdkjvmti diff --git a/test/924-threads/expected.txt b/test/924-threads/expected.txt index 67d20eb750..4c0f4eaa5b 100644 --- a/test/924-threads/expected.txt +++ b/test/924-threads/expected.txt @@ -19,6 +19,11 @@ Daemon Thread true java.lang.ThreadGroup[name=main,maxpri=10] class dalvik.system.PathClassLoader +Subclass +5 +false +java.lang.ThreadGroup[name=main,maxpri=10] +class dalvik.system.PathClassLoader 5 5 0 = NEW diff --git a/test/924-threads/src/Main.java b/test/924-threads/src/Main.java index 716f59e3af..7328560084 100644 --- a/test/924-threads/src/Main.java +++ b/test/924-threads/src/Main.java @@ -52,6 +52,11 @@ public class Main { // Thread has died, check that we can still get info. printThreadInfo(t3); + // Try a subclass of thread. + Thread t4 = new Thread("Subclass") { + }; + printThreadInfo(t4); + doStateTests(); doAllThreadsTests(); |