Clean up a few more exceptions.

This includes a fix for ExceptionInInitializerError, which previously
could have gotten thrown before itself being initialized.

Change-Id: I3f27091f79b1a7e965c6261d3ff78109e0e4a23f
diff --git a/vm/Exception.c b/vm/Exception.c
index e0edd34..f406558 100644
--- a/vm/Exception.c
+++ b/vm/Exception.c
@@ -142,6 +142,8 @@
             "Ljava/lang/ArrayStoreException;");
     ok &= initRef(&gDvm.exClassCastException,
             "Ljava/lang/ClassCastException;");
+    ok &= initRef(&gDvm.exClassNotFoundException,
+            "Ljava/lang/ClassNotFoundException;");
     ok &= initRef(&gDvm.exClassFormatError, "Ljava/lang/ClassFormatError;");
     ok &= initRef(&gDvm.exError, "Ljava/lang/Error;");
     ok &= initRef(&gDvm.exExceptionInInitializerError,
@@ -149,13 +151,21 @@
     ok &= initRef(&gDvm.exFileNotFoundException,
             "Ljava/io/FileNotFoundException;");
     ok &= initRef(&gDvm.exIOException, "Ljava/io/IOException;");
+    ok &= initRef(&gDvm.exIllegalAccessException,
+            "Ljava/lang/IllegalAccessException;");
+    ok &= initRef(&gDvm.exInterruptedException,
+            "Ljava/lang/InterruptedException;");
     ok &= initRef(&gDvm.exNegativeArraySizeException,
             "Ljava/lang/NegativeArraySizeException;");
+    ok &= initRef(&gDvm.exNoSuchFieldException,
+            "Ljava/lang/NoSuchFieldException;");
     ok &= initRef(&gDvm.exNullPointerException,
             "Ljava/lang/NullPointerException;");
     ok &= initRef(&gDvm.exRuntimeException, "Ljava/lang/RuntimeException;");
     ok &= initRef(&gDvm.exStackOverflowError,
             "Ljava/lang/StackOverflowError;");
+    ok &= initRef(&gDvm.exStaleDexCacheError,
+            "Ldalvik/system/StaleDexCacheError;");
     ok &= initRef(&gDvm.exStringIndexOutOfBoundsException,
             "Ljava/lang/StringIndexOutOfBoundsException;");
     ok &= initRef(&gDvm.exThrowable, "Ljava/lang/Throwable;");
@@ -1441,8 +1451,8 @@
 
 void dvmThrowArrayIndexOutOfBoundsException(int index, int length)
 {
-    dvmThrowExceptionFmt("Ljava/lang/ArrayIndexOutOfBoundsException;",
-        "index=%d length=%d", index, length);
+    dvmThrowExceptionFmtByClass(gDvm.exArrayIndexOutOfBoundsException,
+        "length=%d; index=%d", length, index);
 }
 
 /*
@@ -1483,8 +1493,49 @@
     dvmThrowExceptionByClass(gDvm.exClassFormatError, msg);
 }
 
-void dvmThrowClassNotFoundException(const char* msg) {
-    dvmThrowException("Ljava/lang/ClassNotFoundException;", msg);
+void dvmThrowClassNotFoundException(const char* name) {
+    // TODO: Should the name be converted into human-readable form?
+    dvmThrowExceptionByClass(gDvm.exClassNotFoundException, name);
+}
+
+void dvmThrowChainedClassNotFoundException(const char* name, Object* cause) {
+    // TODO: Should the name be converted into human-readable form?
+    dvmThrowChainedExceptionByClass(gDvm.exClassNotFoundException, name,
+            cause);
+}
+
+void dvmThrowExceptionInInitializerError(void)
+{
+    /*
+     * TODO: Do we want to wrap it if the original is an Error rather than
+     * an Exception?
+     *
+     * TODO: Should this just use dvmWrapException()?
+     */
+
+    if (gDvm.exExceptionInInitializerError == NULL) {
+        /*
+         * ExceptionInInitializerError isn't itself initialized. This
+         * can happen very early during VM startup if there is a
+         * problem with one of the corest-of-the-core classes, and it
+         * can possibly happen during a dexopt run. Rather than do
+         * anything fancier, we just abort here with a blatant
+         * message.
+         */
+        LOGE("Fatal error during early class initialization:\n");
+        dvmLogExceptionStackTrace();
+        dvmAbort();
+    }
+
+    Thread* self = dvmThreadSelf();
+    Object* exception = dvmGetException(self);
+
+    dvmAddTrackedAlloc(exception, self);
+    dvmClearException(self);
+
+    dvmThrowChainedExceptionByClass(gDvm.exExceptionInInitializerError,
+            NULL, exception);
+    dvmReleaseTrackedAlloc(exception, self);
 }
 
 void dvmThrowFileNotFoundException(const char* msg) {
@@ -1496,7 +1547,7 @@
 }
 
 void dvmThrowIllegalAccessException(const char* msg) {
-    dvmThrowException("Ljava/lang/IllegalAccessException;", msg);
+    dvmThrowExceptionByClass(gDvm.exIllegalAccessException, msg);
 }
 
 void dvmThrowIllegalAccessError(const char* msg) {
@@ -1535,7 +1586,7 @@
 }
 
 void dvmThrowInterruptedException(const char* msg) {
-    dvmThrowException("Ljava/lang/InterruptedException;", msg);
+    dvmThrowExceptionByClass(gDvm.exInterruptedException, msg);
 }
 
 void dvmThrowLinkageError(const char* msg) {
@@ -1556,7 +1607,7 @@
 }
 
 void dvmThrowNoSuchFieldException(const char* msg) {
-    dvmThrowException("Ljava/lang/NoSuchFieldException;", msg);
+    dvmThrowExceptionByClass(gDvm.exNoSuchFieldException, msg);
 }
 
 void dvmThrowNoSuchMethodError(const char* msg) {
@@ -1576,7 +1627,7 @@
 }
 
 void dvmThrowStaleDexCacheError(const char* msg) {
-    dvmThrowException("Ldalvik/system/StaleDexCacheError;", msg);
+    dvmThrowExceptionByClass(gDvm.exStaleDexCacheError, msg);
 }
 
 void dvmThrowStringIndexOutOfBoundsExceptionWithIndex(jsize stringLength,
diff --git a/vm/Exception.h b/vm/Exception.h
index 37553ba..16330a4 100644
--- a/vm/Exception.h
+++ b/vm/Exception.h
@@ -265,9 +265,22 @@
 
 /**
  * Throw a ClassNotFoundException in the current thread, with the given
- * detail message.
+ * class name as the detail message.
  */
-void dvmThrowClassNotFoundException(const char* msg);
+void dvmThrowClassNotFoundException(const char* name);
+
+/**
+ * Throw a ClassNotFoundException in the current thread, with the given
+ * cause, and the given class name as the detail message.
+ */
+void dvmThrowChainedClassNotFoundException(const char* name, Object* cause);
+
+/*
+ * Throw the VM-spec-mandated error when an exception is thrown during
+ * class initialization. Unlike other helper functions, this automatically
+ * wraps the current thread's pending exception.
+ */
+void dvmThrowExceptionInInitializerError(void);
 
 /**
  * Throw a FileNotFoundException in the current thread, with the given
diff --git a/vm/Globals.h b/vm/Globals.h
index 9c55ee7..86cd53c 100644
--- a/vm/Globals.h
+++ b/vm/Globals.h
@@ -272,14 +272,19 @@
     ClassObject* exArrayStoreException;
     ClassObject* exClassCastException;
     ClassObject* exClassFormatError;
+    ClassObject* exClassNotFoundException;
     ClassObject* exError;
     ClassObject* exExceptionInInitializerError;
     ClassObject* exFileNotFoundException; /* in java.io */
     ClassObject* exIOException;           /* in java.io */
+    ClassObject* exIllegalAccessException;
+    ClassObject* exInterruptedException;
     ClassObject* exNegativeArraySizeException;
+    ClassObject* exNoSuchFieldException;
     ClassObject* exNullPointerException;
     ClassObject* exRuntimeException;
     ClassObject* exStackOverflowError;
+    ClassObject* exStaleDexCacheError;    /* in dalvik.system */
     ClassObject* exStringIndexOutOfBoundsException;
     ClassObject* exThrowable;
     ClassObject* exUnsupportedOperationException;
diff --git a/vm/native/InternalNative.c b/vm/native/InternalNative.c
index 1376c31..92697e9 100644
--- a/vm/native/InternalNative.c
+++ b/vm/native/InternalNative.c
@@ -254,8 +254,7 @@
         Object* oldExcep = dvmGetException(self);
         dvmAddTrackedAlloc(oldExcep, self);     /* don't let this be GCed */
         dvmClearException(self);
-        dvmThrowChainedException("Ljava/lang/ClassNotFoundException;",
-            name, oldExcep);
+        dvmThrowChainedClassNotFoundException(name, oldExcep);
         dvmReleaseTrackedAlloc(oldExcep, self);
     } else {
         LOGVV("GOOD: load %s (%d) --> %p ldr=%p\n",
diff --git a/vm/oo/Class.c b/vm/oo/Class.c
index f972c5b..e12f9d2 100644
--- a/vm/oo/Class.c
+++ b/vm/oo/Class.c
@@ -3700,60 +3700,6 @@
 }
 
 /*
- * Throw the VM-spec-mandated error when an exception is thrown during
- * class initialization.
- *
- * The safest way to do this is to call the ExceptionInInitializerError
- * constructor that takes a Throwable.
- *
- * [Do we want to wrap it if the original is an Error rather than
- * an Exception?]
- */
-static void throwClinitError(void)
-{
-    if (gDvm.exExceptionInInitializerError == NULL) {
-        /*
-         * ExceptionInInitializerError isn't itself initialized. This
-         * can happen very early during VM startup if there is a
-         * problem with one of the corest-of-the-core classes, and it
-         * can possibly happen during a dexopt run. Rather than do
-         * anything fancier, we just abort here with a blatant
-         * message.
-         */
-        LOGE("Fatal error during early class initialization:\n");
-        dvmLogExceptionStackTrace();
-        dvmAbort();
-    }
-
-    Thread* self = dvmThreadSelf();
-    Object* exception = dvmGetException(self);
-
-    dvmAddTrackedAlloc(exception, self);
-    dvmClearException(self);
-
-    Object* eiie =
-        dvmAllocObject(gDvm.exExceptionInInitializerError, ALLOC_DEFAULT);
-    if (eiie == NULL)
-        goto fail;
-
-    /*
-     * Construct the new object, and replace the exception with it.
-     */
-    JValue unused;
-    dvmCallMethod(self, gDvm.methJavaLangExceptionInInitializerError_init,
-        eiie, &unused, exception);
-    dvmSetException(self, eiie);
-    dvmReleaseTrackedAlloc(eiie, NULL);
-    dvmReleaseTrackedAlloc(exception, self);
-    return;
-
-fail:       /* restore original exception */
-    dvmSetException(self, exception);
-    dvmReleaseTrackedAlloc(exception, self);
-    return;
-}
-
-/*
  * The class failed to initialize on a previous attempt, so we want to throw
  * a NoClassDefFoundError (v2 2.17.5).  The exception to this rule is if we
  * failed in verification, in which case v2 5.4.1 says we need to re-throw
@@ -4366,7 +4312,7 @@
              * never happen and we don't need to fix this.
              */
             assert(false);
-            throwClinitError();
+            dvmThrowExceptionInInitializerError();
             clazz->status = CLASS_ERROR;
             goto bail_unlock;
         }
@@ -4483,7 +4429,7 @@
          */
         LOGW("Exception %s thrown while initializing %s\n",
             (dvmGetException(self)->clazz)->descriptor, clazz->descriptor);
-        throwClinitError();
+        dvmThrowExceptionInInitializerError();
         //LOGW("+++ replaced\n");
 
         dvmLockObject(self, (Object*) clazz);