Improved ClassLoader support for JNI FindClass, FieldFieldID, JNI_OnLoad

Also fix AttachCurrentThread to use the peer's thread name,
not the possibly null name from the arguments.

Change-Id: I12e612619d828734d8353a0dca44fb4f11ee0c66
diff --git a/src/jni_internal.cc b/src/jni_internal.cc
index 0982f83..5052773 100644
--- a/src/jni_internal.cc
+++ b/src/jni_internal.cc
@@ -310,6 +310,15 @@
   return EncodeMethod(method);
 }
 
+const ClassLoader* GetClassLoader(Thread* self) {
+  Frame frame = self->GetTopOfStack();
+  Method* method = frame.GetMethod();
+  if (method == NULL || PrettyMethod(method, false) == "java.lang.Runtime.nativeLoad") {
+    return self->GetClassLoaderOverride();
+  }
+  return method->GetDeclaringClass()->GetClassLoader();
+}
+
 jfieldID FindFieldID(ScopedJniThreadState& ts, jclass jni_class, const char* name, const char* sig, bool is_static) {
   Class* c = Decode<Class*>(ts, jni_class);
   if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(c, true)) {
@@ -320,8 +329,7 @@
   Class* field_type;
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
   if (sig[1] != '\0') {
-    // TODO: need to get the appropriate ClassLoader.
-    const ClassLoader* cl = ts.Self()->GetClassLoaderOverride();
+    const ClassLoader* cl = GetClassLoader(ts.Self());
     field_type = class_linker->FindClass(sig, cl);
   } else {
     field_type = class_linker->FindPrimitiveClass(*sig);
@@ -641,8 +649,7 @@
     std::string descriptor(NormalizeJniClassDescriptor(name));
     Class* c = NULL;
     if (runtime->IsStarted()) {
-      // TODO: need to get the appropriate ClassLoader.
-      const ClassLoader* cl = ts.Self()->GetClassLoaderOverride();
+      const ClassLoader* cl = GetClassLoader(ts.Self());
       c = class_linker->FindClass(descriptor, cl);
     } else {
       c = class_linker->FindSystemClass(descriptor);
diff --git a/src/thread.cc b/src/thread.cc
index 6fdeefd..54d2e6c 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -164,10 +164,8 @@
 
   {
     CHECK_EQ(self->GetState(), Thread::kRunnable);
-    String* thread_name = reinterpret_cast<String*>(gThread_name->GetObject(self->peer_));
-    if (thread_name != NULL) {
-      SetThreadName(thread_name->ToModifiedUtf8().c_str());
-    }
+    SirtRef<String> thread_name(self->GetName());
+    SetThreadName(thread_name->ToModifiedUtf8().c_str());
   }
 
   Dbg::PostThreadStart(self);
@@ -264,8 +262,6 @@
 
   self->SetState(Thread::kNative);
 
-  SetThreadName(name);
-
   // If we're the main thread, ClassLinker won't be created until after we're attached,
   // so that thread needs a two-stage attach. Regular threads don't need this hack.
   if (self->thin_lock_id_ != ThreadList::kMainId) {
@@ -300,13 +296,22 @@
   peer_ = DecodeJObject(peer.get());
   SetVmData(peer_, Thread::Current());
 
-  // Because we mostly run without code available (in the compiler, in tests), we
-  // manually assign the fields the constructor should have set.
-  // TODO: lose this.
-  gThread_daemon->SetBoolean(peer_, thread_is_daemon);
-  gThread_group->SetObject(peer_, Decode<Object*>(env, thread_group.get()));
-  gThread_name->SetObject(peer_, Decode<Object*>(env, thread_name.get()));
-  gThread_priority->SetInt(peer_, thread_priority);
+  SirtRef<String> peer_thread_name(GetName());
+  if (peer_thread_name.get() == NULL) {
+    // The Thread constructor should have set the Thread.name to a
+    // non-null value. However, because we can run without code
+    // available (in the compiler, in tests), we manually assign the
+    // fields the constructor should have set.
+    gThread_daemon->SetBoolean(peer_, thread_is_daemon);
+    gThread_group->SetObject(peer_, Decode<Object*>(env, thread_group.get()));
+    gThread_name->SetObject(peer_, Decode<Object*>(env, thread_name.get()));
+    gThread_priority->SetInt(peer_, thread_priority);
+    peer_thread_name.reset(GetName());
+  }
+  // thread_name may have been null, so don't trust this to be non-null
+  if (peer_thread_name.get() != NULL) {
+    SetThreadName(GetName()->ToModifiedUtf8().c_str());
+  }
 
   // Pre-allocate an OutOfMemoryError for the double-OOME case.
   ThrowNewException("Ljava/lang/OutOfMemoryError;",