Add a bit of structure to the Exception startup code.
This is in preparation for having a *lot* more exception classes get
looked up at startup time.
Change-Id: Id464c5b19a6a15f6779d8959f5d6397a0c6c5842
diff --git a/vm/Exception.c b/vm/Exception.c
index 2e93242..f00b6fc 100644
--- a/vm/Exception.c
+++ b/vm/Exception.c
@@ -101,6 +101,30 @@
/*
+ * Helper for dvmExceptionStartup(), which looks up classes and stores
+ * them to the indicated pointer, returning a failure code (false ==
+ * failure).
+ */
+static bool initRef(ClassObject** pClass, const char* name)
+{
+ ClassObject* result;
+
+ if (name[0] == '[') {
+ result = dvmFindArrayClass(name, NULL);
+ } else {
+ result = dvmFindSystemClassNoInit(name);
+ }
+
+ if (result == NULL) {
+ LOGE("Could not find exception class %s\n", name);
+ return false;
+ }
+
+ *pClass = result;
+ return true;
+}
+
+/*
* Cache pointers to some of the exception classes we use locally.
*
* Note this is NOT called during dexopt optimization. Some of the fields
@@ -108,23 +132,21 @@
*/
bool dvmExceptionStartup(void)
{
- gDvm.classJavaLangThrowable =
- dvmFindSystemClassNoInit("Ljava/lang/Throwable;");
- gDvm.classJavaLangRuntimeException =
- dvmFindSystemClassNoInit("Ljava/lang/RuntimeException;");
- gDvm.classJavaLangStackOverflowError =
- dvmFindSystemClassNoInit("Ljava/lang/StackOverflowError;");
- gDvm.classJavaLangError =
- dvmFindSystemClassNoInit("Ljava/lang/Error;");
- gDvm.classJavaLangStackTraceElement =
- dvmFindSystemClassNoInit("Ljava/lang/StackTraceElement;");
- gDvm.classJavaLangStackTraceElementArray =
- dvmFindArrayClass("[Ljava/lang/StackTraceElement;", NULL);
- if (gDvm.classJavaLangThrowable == NULL ||
- gDvm.classJavaLangStackTraceElement == NULL ||
- gDvm.classJavaLangStackTraceElementArray == NULL)
- {
- LOGE("Could not find one or more essential exception classes\n");
+ bool ok = true;
+
+ ok &= initRef(&gDvm.exError, "Ljava/lang/Error;");
+ ok &= initRef(&gDvm.exExceptionInInitializerError,
+ "Ljava/lang/ExceptionInInitializerError;");
+ ok &= initRef(&gDvm.exRuntimeException, "Ljava/lang/RuntimeException;");
+ ok &= initRef(&gDvm.exStackOverflowError,
+ "Ljava/lang/StackOverflowError;");
+ ok &= initRef(&gDvm.exThrowable, "Ljava/lang/Throwable;");
+ ok &= initRef(&gDvm.classJavaLangStackTraceElement,
+ "Ljava/lang/StackTraceElement;");
+ ok &= initRef(&gDvm.classJavaLangStackTraceElementArray,
+ "[Ljava/lang/StackTraceElement;");
+
+ if (!ok) {
return false;
}
@@ -145,7 +167,7 @@
/* grab an offset for the stackData field */
gDvm.offJavaLangThrowable_stackState =
- dvmFindFieldOffset(gDvm.classJavaLangThrowable,
+ dvmFindFieldOffset(gDvm.exThrowable,
"stackState", "Ljava/lang/Object;");
if (gDvm.offJavaLangThrowable_stackState < 0) {
LOGE("Unable to find Throwable.stackState\n");
@@ -154,13 +176,26 @@
/* and one for the cause field, just 'cause */
gDvm.offJavaLangThrowable_cause =
- dvmFindFieldOffset(gDvm.classJavaLangThrowable,
+ dvmFindFieldOffset(gDvm.exThrowable,
"cause", "Ljava/lang/Throwable;");
if (gDvm.offJavaLangThrowable_cause < 0) {
LOGE("Unable to find Throwable.cause\n");
return false;
}
+ /*
+ * ExceptionInInitializerError is used in the guts of Class.c; it
+ * wants to call the constructor more directly, so look that up
+ * explicitly, here.
+ */
+ gDvm.methJavaLangExceptionInInitializerError_init =
+ dvmFindDirectMethodByDescriptor(gDvm.exExceptionInInitializerError,
+ "<init>", "(Ljava/lang/Throwable;)V");
+ if (gDvm.methJavaLangExceptionInInitializerError_init == NULL) {
+ LOGE("Unable to prep java/lang/ExceptionInInitializerError\n");
+ return false;
+ }
+
return true;
}
@@ -425,7 +460,7 @@
}
if (cause != NULL) {
- if (!dvmInstanceof(cause->clazz, gDvm.classJavaLangThrowable)) {
+ if (!dvmInstanceof(cause->clazz, gDvm.exThrowable)) {
LOGE("Tried to init exception with cause '%s'\n",
cause->clazz->descriptor);
dvmAbort();
@@ -519,7 +554,7 @@
excepClass->descriptor, msg, initKind);
assert(strcmp(excepClass->descriptor,
"Ljava/lang/RuntimeException;") != 0);
- dvmThrowChainedException("Ljava/lang/RuntimeException;",
+ dvmThrowChainedExceptionByClass(gDvm.exRuntimeException,
"re-throw on exception class missing constructor", NULL);
goto bail;
}
@@ -620,8 +655,8 @@
*/
bool dvmIsCheckedException(const Object* exception)
{
- if (dvmInstanceof(exception->clazz, gDvm.classJavaLangError) ||
- dvmInstanceof(exception->clazz, gDvm.classJavaLangRuntimeException))
+ if (dvmInstanceof(exception->clazz, gDvm.exError) ||
+ dvmInstanceof(exception->clazz, gDvm.exRuntimeException))
{
return false;
} else {
@@ -690,7 +725,7 @@
*/
Object* dvmGetExceptionCause(const Object* exception)
{
- if (!dvmInstanceof(exception->clazz, gDvm.classJavaLangThrowable)) {
+ if (!dvmInstanceof(exception->clazz, gDvm.exThrowable)) {
LOGE("Tried to get cause from object of type '%s'\n",
exception->clazz->descriptor);
dvmAbort();
@@ -1003,7 +1038,7 @@
if (dvmIsBreakFrame((u4*)fp))
break;
- if (!dvmInstanceof(method->clazz, gDvm.classJavaLangThrowable))
+ if (!dvmInstanceof(method->clazz, gDvm.exThrowable))
break;
//LOGD("EXCEP: ignoring %s.%s\n",
// method->clazz->descriptor, method->name);
@@ -1490,7 +1525,7 @@
}
void dvmThrowRuntimeException(const char* msg) {
- dvmThrowException("Ljava/lang/RuntimeException;", msg);
+ dvmThrowExceptionByClass(gDvm.exRuntimeException, msg);
}
void dvmThrowStaleDexCacheError(const char* msg) {
diff --git a/vm/Globals.h b/vm/Globals.h
index d0be494..5cca83c 100644
--- a/vm/Globals.h
+++ b/vm/Globals.h
@@ -236,16 +236,12 @@
*/
ClassObject* classJavaLangClass;
ClassObject* classJavaLangClassArray;
- ClassObject* classJavaLangError;
ClassObject* classJavaLangObject;
ClassObject* classJavaLangObjectArray;
- ClassObject* classJavaLangRuntimeException;
ClassObject* classJavaLangString;
ClassObject* classJavaLangThread;
ClassObject* classJavaLangVMThread;
ClassObject* classJavaLangThreadGroup;
- ClassObject* classJavaLangThrowable;
- ClassObject* classJavaLangStackOverflowError;
ClassObject* classJavaLangStackTraceElement;
ClassObject* classJavaLangStackTraceElementArray;
ClassObject* classJavaLangAnnotationAnnotationArray;
@@ -258,7 +254,6 @@
ClassObject* classJavaLangReflectMethod;
ClassObject* classJavaLangReflectMethodArray;
ClassObject* classJavaLangReflectProxy;
- ClassObject* classJavaLangExceptionInInitializerError;
ClassObject* classJavaLangRefPhantomReference;
ClassObject* classJavaLangRefReference;
ClassObject* classJavaNioReadWriteDirectByteBuffer;
@@ -267,6 +262,17 @@
ClassObject* classOrgApacheHarmonyLangAnnotationAnnotationMember;
ClassObject* classOrgApacheHarmonyLangAnnotationAnnotationMemberArray;
+ /*
+ * classes representing exception types. The names here don't include
+ * packages, just to keep the use sites a bit less verbose. All are
+ * in java.lang, except where noted.
+ */
+ ClassObject* exError;
+ ClassObject* exExceptionInInitializerError;
+ ClassObject* exRuntimeException;
+ ClassObject* exStackOverflowError;
+ ClassObject* exThrowable;
+
/* synthetic classes for arrays of primitives */
ClassObject* classArrayBoolean;
ClassObject* classArrayChar;
diff --git a/vm/analysis/CodeVerify.c b/vm/analysis/CodeVerify.c
index d86c45f..760ef3b 100644
--- a/vm/analysis/CodeVerify.c
+++ b/vm/analysis/CodeVerify.c
@@ -2887,7 +2887,7 @@
foundPossibleHandler = true;
if (handler->typeIdx == kDexNoIndex)
- clazz = gDvm.classJavaLangThrowable;
+ clazz = gDvm.exThrowable;
else
clazz = dvmOptResolveClass(meth->clazz, handler->typeIdx,
&localFailure);
@@ -3449,11 +3449,11 @@
if (gDvm.classJavaLangString == NULL)
gDvm.classJavaLangString =
dvmFindSystemClassNoInit("Ljava/lang/String;");
- if (gDvm.classJavaLangThrowable == NULL) {
- gDvm.classJavaLangThrowable =
+ if (gDvm.exThrowable == NULL) {
+ gDvm.exThrowable =
dvmFindSystemClassNoInit("Ljava/lang/Throwable;");
gDvm.offJavaLangThrowable_cause =
- dvmFindFieldOffset(gDvm.classJavaLangThrowable,
+ dvmFindFieldOffset(gDvm.exThrowable,
"cause", "Ljava/lang/Throwable;");
}
if (gDvm.classJavaLangObject == NULL)
@@ -4285,7 +4285,7 @@
case OP_THROW:
resClass = getClassFromRegister(workLine, decInsn.vA, &failure);
if (VERIFY_OK(failure) && resClass != NULL) {
- if (!dvmInstanceof(resClass, gDvm.classJavaLangThrowable)) {
+ if (!dvmInstanceof(resClass, gDvm.exThrowable)) {
LOG_VFY("VFY: thrown class %s not instanceof Throwable\n",
resClass->descriptor);
failure = VERIFY_ERROR_GENERIC;
diff --git a/vm/interp/Stack.c b/vm/interp/Stack.c
index 14696a7..fd1d791 100644
--- a/vm/interp/Stack.c
+++ b/vm/interp/Stack.c
@@ -1064,8 +1064,7 @@
LOGW("Stack overflow while throwing exception\n");
dvmClearException(self);
}
- dvmThrowChainedExceptionByClass(gDvm.classJavaLangStackOverflowError,
- NULL, excep);
+ dvmThrowChainedExceptionByClass(gDvm.exStackOverflowError, NULL, excep);
}
/*
@@ -1078,7 +1077,7 @@
assert(self->stackOverflowed);
- if (exception->clazz != gDvm.classJavaLangStackOverflowError) {
+ if (exception->clazz != gDvm.exStackOverflowError) {
/* exception caused during SOE, not the SOE itself */
return;
}
diff --git a/vm/oo/Class.c b/vm/oo/Class.c
index 66c9fca..7b37f74 100644
--- a/vm/oo/Class.c
+++ b/vm/oo/Class.c
@@ -3711,37 +3711,28 @@
*/
static void throwClinitError(void)
{
- Thread* self = dvmThreadSelf();
- Object* exception;
- Object* eiie;
+ 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();
+ }
- exception = dvmGetException(self);
+ Thread* self = dvmThreadSelf();
+ Object* exception = dvmGetException(self);
+
dvmAddTrackedAlloc(exception, self);
dvmClearException(self);
- if (gDvm.classJavaLangExceptionInInitializerError == NULL) {
- /*
- * Always resolves to same thing -- no race condition.
- */
- gDvm.classJavaLangExceptionInInitializerError =
- dvmFindSystemClass(
- "Ljava/lang/ExceptionInInitializerError;");
- if (gDvm.classJavaLangExceptionInInitializerError == NULL) {
- LOGE("Unable to prep java/lang/ExceptionInInitializerError\n");
- goto fail;
- }
-
- gDvm.methJavaLangExceptionInInitializerError_init =
- dvmFindDirectMethodByDescriptor(gDvm.classJavaLangExceptionInInitializerError,
- "<init>", "(Ljava/lang/Throwable;)V");
- if (gDvm.methJavaLangExceptionInInitializerError_init == NULL) {
- LOGE("Unable to prep java/lang/ExceptionInInitializerError\n");
- goto fail;
- }
- }
-
- eiie = dvmAllocObject(gDvm.classJavaLangExceptionInInitializerError,
- ALLOC_DEFAULT);
+ Object* eiie =
+ dvmAllocObject(gDvm.exExceptionInInitializerError, ALLOC_DEFAULT);
if (eiie == NULL)
goto fail;