Add support for catching C++ (and Java / Ada) exceptions in Objective-C.

main
theraven 16 years ago
parent 121e14a3b8
commit f375d20d7a

@ -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

@ -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;
}

@ -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);

Loading…
Cancel
Save