From 32bb3da6f05959749161ce7f9103027f11597fe3 Mon Sep 17 00:00:00 2001 From: Dan Bornstein Date: Thu, 24 Feb 2011 15:47:20 -0800 Subject: [PATCH] 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 --- vm/Exception.c | 87 +++++++++++++++++++++++++++++++++--------------- vm/Globals.h | 16 ++++++--- vm/analysis/CodeVerify.c | 10 +++--- vm/interp/Stack.c | 5 ++- vm/oo/Class.c | 43 ++++++++++-------------- 5 files changed, 96 insertions(+), 65 deletions(-) diff --git a/vm/Exception.c b/vm/Exception.c index 2e9324272..f00b6fc68 100644 --- a/vm/Exception.c +++ b/vm/Exception.c @@ -101,6 +101,30 @@ static bool initException(Object* exception, const char* msg, Object* cause, /* + * 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 @@ static bool initException(Object* exception, const char* msg, Object* cause, */ 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 @@ bool dvmExceptionStartup(void) /* 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 @@ bool dvmExceptionStartup(void) /* 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, + "", "(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 @@ static bool initException(Object* exception, const char* msg, Object* cause, } 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 @@ static bool initException(Object* exception, const char* msg, Object* cause, 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 @@ void dvmClearOptException(Thread* self) */ 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 @@ void dvmWrapException(const char* newExcepStr) */ 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 @@ void* dvmFillInStackTraceInternal(Thread* thread, bool wantObject, int* pCount) 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 dvmThrowOutOfMemoryError(const char* msg) { } 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 d0be494bd..5cca83c2e 100644 --- a/vm/Globals.h +++ b/vm/Globals.h @@ -236,16 +236,12 @@ struct DvmGlobals { */ 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 @@ struct DvmGlobals { ClassObject* classJavaLangReflectMethod; ClassObject* classJavaLangReflectMethodArray; ClassObject* classJavaLangReflectProxy; - ClassObject* classJavaLangExceptionInInitializerError; ClassObject* classJavaLangRefPhantomReference; ClassObject* classJavaLangRefReference; ClassObject* classJavaNioReadWriteDirectByteBuffer; @@ -267,6 +262,17 @@ struct DvmGlobals { 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 d86c45fe4..760ef3b0e 100644 --- a/vm/analysis/CodeVerify.c +++ b/vm/analysis/CodeVerify.c @@ -2887,7 +2887,7 @@ static ClassObject* getCaughtExceptionType(const Method* meth, int insnIdx, foundPossibleHandler = true; if (handler->typeIdx == kDexNoIndex) - clazz = gDvm.classJavaLangThrowable; + clazz = gDvm.exThrowable; else clazz = dvmOptResolveClass(meth->clazz, handler->typeIdx, &localFailure); @@ -3449,11 +3449,11 @@ static void verifyPrep(void) 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 @@ static bool verifyInstruction(const Method* meth, InsnFlags* insnFlags, 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 14696a727..fd1d7913b 100644 --- a/vm/interp/Stack.c +++ b/vm/interp/Stack.c @@ -1064,8 +1064,7 @@ void dvmHandleStackOverflow(Thread* self, const Method* method) LOGW("Stack overflow while throwing exception\n"); dvmClearException(self); } - dvmThrowChainedExceptionByClass(gDvm.classJavaLangStackOverflowError, - NULL, excep); + dvmThrowChainedExceptionByClass(gDvm.exStackOverflowError, NULL, excep); } /* @@ -1078,7 +1077,7 @@ void dvmCleanupStackOverflow(Thread* self, const Object* exception) 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 66c9fca99..7b37f7479 100644 --- a/vm/oo/Class.c +++ b/vm/oo/Class.c @@ -3711,37 +3711,28 @@ static bool computeFieldOffsets(ClassObject* clazz) */ 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; - Object* eiie; + Object* exception = dvmGetException(self); - 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, - "", "(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; -- 2.11.0