diff --git a/GNUmakefile b/GNUmakefile index 2cf7a96..073ea3d 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -20,9 +20,9 @@ libobjc_C_FILES = \ category_loader.c\ class_table.c\ dtable.c\ + eh_personality.c\ encoding2.c\ hash_table.c\ - eh_personality.c\ hooks.c\ ivar.c\ loader.c\ @@ -43,6 +43,7 @@ ifneq ($(install_headers), no) libobjc_HEADER_FILES = \ Availability.h\ blocks_runtime.h\ + hooks.h\ runtime.h\ slot.h endif @@ -55,8 +56,8 @@ libobjc_CPPFLAGS += -D__OBJC_RUNTIME_INTERNAL__=1 -D_XOPEN_SOURCE=500 # Note to Riccardo. Please do not 'fix' C99isms in this. The new ABI is only # useful on compilers that support C99 (currently only clang), so there is no # benefit from supporting platforms with no C99 compiler. -libobjc_CFLAGS += -Werror -std=c99 -g -march=native -fexceptions #-fno-inline -libobjc_OBJCFLAGS += -g -std=c99 -march=native +libobjc_CFLAGS += -std=c99 -g -march=native -fexceptions -fno-inline +libobjc_OBJCFLAGS += $(libobjc_CFLAGS) libobjc_LDFLAGS += -g -ltoydispatch libobjc_LIB_DIRS += -L toydispatch/obj diff --git a/eh_personality.c b/eh_personality.c index 5fc2d3b..5d91faa 100644 --- a/eh_personality.c +++ b/eh_personality.c @@ -76,39 +76,33 @@ Class get_type_table_entry(struct _Unwind_Context *context, return (Class)objc_getClass(class_name); } -static BOOL isKindOfClass(struct _Unwind_Exception *ex, Class type) +static BOOL isKindOfClass(Class thrown, Class type, BOOL foreignException) { // Nil is a catchall, but we only want to catch things that are not foreign // exceptions in it. if (Nil == type) { - return ex->exception_class == objc_exception_class; + return (Nil != thrown) && !foreignException; } - if (ex->exception_class != objc_exception_class) - { - // FIXME: Box and stuff. - return NO; - } - id object = *(id*)(ex + 1); do { - if (object->isa == type) + if (thrown == type) { return YES; } - type = class_getSuperclass(type); - } while (Nil != type); + thrown = class_getSuperclass(thrown); + } while (Nil != thrown); return NO; } static BOOL check_action_record(struct _Unwind_Context *context, - int64_t exceptionClass, + BOOL foreignException, struct dwarf_eh_lsda *lsda, dw_eh_ptr_t action_record, - struct _Unwind_Exception *ex, + Class thrown_class, unsigned long *selector) { while (action_record) @@ -120,7 +114,7 @@ static BOOL check_action_record(struct _Unwind_Context *context, if (filter > 0) { Class type = get_type_table_entry(context, lsda, filter); - if (ex && isKindOfClass(ex, type)) + if (isKindOfClass(thrown_class, type, foreignException)) { return YES; } @@ -161,14 +155,21 @@ _Unwind_Reason_Code __gnu_objc_personality_v0(int version, // then we ignore it (for now) BOOL foreignException = exceptionClass != objc_exception_class; + Class thrown_class = Nil; + // If it's not a foreign exception, then we know the layout of the // language-specific exception stuff. if (!foreignException) { ex = (struct objc_exception*) ((char*)exceptionObject - offsetof(struct objc_exception, unwindHeader)); - } + thrown_class = ex->object->isa; + } + else if (_objc_class_for_boxing_foreign_exception) + { + thrown_class = _objc_class_for_boxing_foreign_exception(exceptionClass); + } unsigned char *lsda_addr = (void*)_Unwind_GetLanguageSpecificData(context); // No LSDA implies no landing pads - try the next frame @@ -182,8 +183,8 @@ _Unwind_Reason_Code __gnu_objc_personality_v0(int version, { struct dwarf_eh_lsda lsda = parse_lsda(context, lsda_addr); action = dwarf_eh_find_callsite(context, &lsda); - BOOL found_handler = check_action_record(context, exceptionClass, &lsda, - action.action_record, exceptionObject, &selector); + BOOL found_handler = check_action_record(context, foreignException, + &lsda, action.action_record, thrown_class, &selector); // If there's no action record, we've only found a cleanup, so keep // searching for something real if (found_handler) @@ -200,18 +201,33 @@ _Unwind_Reason_Code __gnu_objc_personality_v0(int version, return _URC_CONTINUE_UNWIND; } - if (!(actions & _UA_HANDLER_FRAME) || foreignException) + // TODO: If this is a C++ exception, we can cache the lookup and cheat a + // bit + id object = nil; + if (!(actions & _UA_HANDLER_FRAME)) { struct dwarf_eh_lsda lsda = parse_lsda(context, lsda_addr); action = dwarf_eh_find_callsite(context, &lsda); if (0 == action.landing_pad) { return _URC_CONTINUE_UNWIND; } selector = 0; } + else if (foreignException) + { + struct dwarf_eh_lsda lsda = parse_lsda(context, lsda_addr); + action = dwarf_eh_find_callsite(context, &lsda); + check_action_record(context, foreignException, &lsda, + action.action_record, thrown_class, &selector); + //[thrown_class exceptionWithForeignException: exceptionObject]; + SEL box_sel = sel_registerName("exceptionWithForeignException:"); + IMP boxfunction = objc_msg_lookup((id)thrown_class, box_sel); + object = boxfunction((id)thrown_class, box_sel, exceptionObject); + } else { // Restore the saved info if we saved some last time. action.landing_pad = ex->landingPad; selector = ex->handlerSwitchValue; + object = ex->object; } diff --git a/objc/hooks.h b/objc/hooks.h index d372da5..2cc8261 100644 --- a/objc/hooks.h +++ b/objc/hooks.h @@ -21,7 +21,7 @@ OBJC_HOOK Class (*_objc_lookup_class)(const char *name); /** * Class load callback. */ -OBJC_HOOK void (*_objc_load_callback)(Class class, struct objc_category *category); +OBJC_HOOK void (*_objc_load_callback)(Class cls, struct objc_category *category); /** * The hook used for fast proxy lookups. This takes an object and a selector * and returns the instance that the message should be forwarded to. @@ -44,3 +44,15 @@ OBJC_HOOK IMP (*__objc_msg_forward2)(id, SEL); * called. */ OBJC_HOOK void (*_objc_unexpected_exception)(id exception); +/** + * Hook defined to return the class to be used for boxing a foreign exception + * type. The class must implement: + * + * + (id)exceptionWithForeignException: (_Unwind_Exception*)ex; + * + * This will return an instance of the class that encapsulates the exception. + * + * Note: Due to limitations of the current ABI, there is no way for the handler + * to + */ +OBJC_HOOK Class (*_objc_class_for_boxing_foreign_exception)(int64_t exceptionClass);