Merge "Improve debug-ability of native method registration" into dalvik-dev
diff --git a/src/class_linker.cc b/src/class_linker.cc
index 6f1e5aa..cf0c094 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -186,6 +186,7 @@
   "Ljava/lang/ClassLoader;",
   "Ldalvik/system/BaseDexClassLoader;",
   "Ldalvik/system/PathClassLoader;",
+  "Ljava/lang/Throwable;",
   "Ljava/lang/StackTraceElement;",
   "Z",
   "B",
@@ -470,7 +471,9 @@
   SetClassRoot(kDalvikSystemPathClassLoader, dalvik_system_PathClassLoader);
   PathClassLoader::SetClass(dalvik_system_PathClassLoader);
 
-  // Set up java.lang.StackTraceElement as a convenience
+  // Set up java.lang.Throwable and java.lang.StackTraceElement as a convenience
+  SetClassRoot(kJavaLangThrowable, FindSystemClass("Ljava/lang/Throwable;"));
+  Throwable::SetClass(GetClassRoot(kJavaLangThrowable));
   SetClassRoot(kJavaLangStackTraceElement, FindSystemClass("Ljava/lang/StackTraceElement;"));
   SetClassRoot(kJavaLangStackTraceElementArrayClass, FindSystemClass("[Ljava/lang/StackTraceElement;"));
   StackTraceElement::SetClass(GetClassRoot(kJavaLangStackTraceElement));
@@ -933,6 +936,7 @@
   LongArray::SetArrayClass(GetClassRoot(kLongArrayClass));
   ShortArray::SetArrayClass(GetClassRoot(kShortArrayClass));
   PathClassLoader::SetClass(GetClassRoot(kDalvikSystemPathClassLoader));
+  Throwable::SetClass(GetClassRoot(kJavaLangThrowable));
   StackTraceElement::SetClass(GetClassRoot(kJavaLangStackTraceElement));
 
   FinishInit();
@@ -1009,6 +1013,7 @@
   LongArray::ResetArrayClass();
   ShortArray::ResetArrayClass();
   PathClassLoader::ResetClass();
+  Throwable::ResetClass();
   StackTraceElement::ResetClass();
   STLDeleteElements(&boot_class_path_);
   STLDeleteElements(&oat_files_);
diff --git a/src/class_linker.h b/src/class_linker.h
index 10d8305..f2b44a3 100644
--- a/src/class_linker.h
+++ b/src/class_linker.h
@@ -429,6 +429,7 @@
     kJavaLangClassLoader,
     kDalvikSystemBaseDexClassLoader,
     kDalvikSystemPathClassLoader,
+    kJavaLangThrowable,
     kJavaLangStackTraceElement,
     kPrimitiveBoolean,
     kPrimitiveByte,
diff --git a/src/object.cc b/src/object.cc
index f90031a..9e3e9d3 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -1382,6 +1382,20 @@
   return result;
 }
 
+
+Class* Throwable::java_lang_Throwable_ = NULL;
+
+void Throwable::SetClass(Class* java_lang_Throwable) {
+  CHECK(java_lang_Throwable_ == NULL);
+  CHECK(java_lang_Throwable != NULL);
+  java_lang_Throwable_ = java_lang_Throwable;
+}
+
+void Throwable::ResetClass() {
+  CHECK(java_lang_Throwable_ != NULL);
+  java_lang_Throwable_ = NULL;
+}
+
 Class* StackTraceElement::java_lang_StackTraceElement_ = NULL;
 
 void StackTraceElement::SetClass(Class* java_lang_StackTraceElement) {
diff --git a/src/object.h b/src/object.h
index e9556ef..c2f8cc1 100644
--- a/src/object.h
+++ b/src/object.h
@@ -2278,6 +2278,15 @@
   // in cases like the verifier where the checks cannot fail and initCause isn't overridden.
   void SetCause(Throwable* cause);
   bool IsCheckedException() const;
+
+  static Class* GetJavaLangThrowable() {
+    DCHECK(java_lang_Throwable_ != NULL);
+    return java_lang_Throwable_;
+  }
+
+  static void SetClass(Class* java_lang_Throwable);
+  static void ResetClass();
+
  private:
   Object* GetStackState() const {
     return GetFieldObject<Object*>(OFFSET_OF_OBJECT_MEMBER(Throwable, stack_state_), true);
@@ -2290,6 +2299,8 @@
   Object* stack_trace_;
   Object* suppressed_exceptions_;
 
+  static Class* java_lang_Throwable_;
+
   friend struct ThrowableOffsets;  // for verifying offset information
   DISALLOW_IMPLICIT_CONSTRUCTORS(Throwable);
 };
diff --git a/src/runtime.cc b/src/runtime.cc
index d7b0d15..579e591 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -650,6 +650,8 @@
 
 void Runtime::RegisterRuntimeNativeMethods(JNIEnv* env) {
 #define REGISTER(FN) extern void FN(JNIEnv*); FN(env)
+  // Register Throwable first so that registration of other native methods can throw exceptions
+  REGISTER(register_java_lang_Throwable);
   REGISTER(register_dalvik_system_DexFile);
   REGISTER(register_dalvik_system_VMDebug);
   REGISTER(register_dalvik_system_VMRuntime);
@@ -661,7 +663,6 @@
   REGISTER(register_java_lang_String);
   REGISTER(register_java_lang_System);
   REGISTER(register_java_lang_Thread);
-  REGISTER(register_java_lang_Throwable);
   REGISTER(register_java_lang_VMClassLoader);
   REGISTER(register_java_lang_reflect_Array);
   REGISTER(register_java_lang_reflect_Constructor);
diff --git a/src/thread.cc b/src/thread.cc
index 7113655..54b17d0 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -54,7 +54,6 @@
 pthread_key_t Thread::pthread_key_self_;
 
 static Class* gThreadLock = NULL;
-static Class* gThrowable = NULL;
 static Field* gThread_daemon = NULL;
 static Field* gThread_group = NULL;
 static Field* gThread_lock = NULL;
@@ -739,7 +738,6 @@
   Class* ThreadGroup_class = FindClassOrDie(class_linker, "Ljava/lang/ThreadGroup;");
   Class* UncaughtExceptionHandler_class = FindClassOrDie(class_linker, "Ljava/lang/Thread$UncaughtExceptionHandler;");
   gThreadLock = FindClassOrDie(class_linker, "Ljava/lang/ThreadLock;");
-  gThrowable = FindClassOrDie(class_linker, "Ljava/lang/Throwable;");
 
   gThread_daemon = FindFieldOrDie(Thread_class, "daemon", "Z");
   gThread_group = FindFieldOrDie(Thread_class, "group", "Ljava/lang/ThreadGroup;");
@@ -1001,8 +999,8 @@
     // We want to skip frames up to and including the exception's constructor.
     // Note we also skip the frame if it doesn't have a method (namely the callee
     // save frame)
-    DCHECK(gThrowable != NULL);
-    if (skipping_ && frame.HasMethod() && !gThrowable->IsAssignableFrom(frame.GetMethod()->GetDeclaringClass())) {
+    if (skipping_ && frame.HasMethod() &&
+        !Throwable::GetJavaLangThrowable()->IsAssignableFrom(frame.GetMethod()->GetDeclaringClass())) {
       skipping_ = false;
     }
     if (!skipping_) {