ART: Fix GetThreadInfo

Fix the retrieval of the context classloader. Make sure to have
the field from the Thread class, don't look into a subclass.

Add caching for the field. Also fix the usage restriction of the
function, which is only valid during the Live phase.

Bug: 36654185
Test: ./test.py --host -r -t 924
Change-Id: I5cce41b31c32e59c80bb7c3afa03e8b0975ec54e
diff --git a/runtime/openjdkjvmti/ti_thread.cc b/runtime/openjdkjvmti/ti_thread.cc
index 788ac30..e5ff090 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 @@
   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 @@
   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 @@
   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 @@
     }
 
     // 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 @@
     }
 
     // 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);