diff --git a/GNUmakefile b/GNUmakefile index 542fc91..c1c1e5e 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -5,12 +5,14 @@ LIBRARY_NAME = libobjc libobjc_VERSION = 4 libobjc_OBJC_FILES = \ - blocks_runtime.m\ - linking.m\ - mutation.m\ + NSBlocks.m\ NXConstStr.m\ Object.m\ Protocol.m\ + blocks_runtime.m\ + linking.m\ + mutation.m\ + properties.m\ sync.m @@ -31,6 +33,7 @@ libobjc_C_FILES = \ selector.c\ sendmsg.c\ thr.c + libobjc_HEADER_FILES_DIR = objc libobjc_HEADER_FILES_INSTALL_DIR = objc libobjc_HEADER_FILES = \ diff --git a/NSBlocks.m b/NSBlocks.m new file mode 100644 index 0000000..183c494 --- /dev/null +++ b/NSBlocks.m @@ -0,0 +1,56 @@ +#import +#import "objc/runtime.h" +#import "objc/blocks_runtime.h" +#include + +struct objc_class _NSConcreteGlobalBlock; +struct objc_class _NSConcreteStackBlock; + +@interface NSBlock : NSObject @end + +void __objc_update_dispatch_table_for_class(Class); +extern struct sarray *__objc_uninstalled_dtable; +extern objc_mutex_t __objc_runtime_mutex; +static void createNSBlockSubclass(Class newClass, char *name) +{ + Class superclass = [NSBlock class]; + // Create the metaclass + Class metaClass = calloc(1, sizeof(struct objc_class)); + + // Initialize the metaclass + metaClass->class_pointer = superclass->class_pointer; + metaClass->super_class = superclass->class_pointer->super_class; + metaClass->info = _CLS_META; + metaClass->dtable = __objc_uninstalled_dtable; + + // Set up the new class + newClass->class_pointer = metaClass; + newClass->super_class = superclass; + newClass->name = name; + newClass->info = _CLS_CLASS; + newClass->dtable = __objc_uninstalled_dtable; + + // Initialize the dispatch table for the class and metaclass. + __objc_update_dispatch_table_for_class(metaClass); + __objc_update_dispatch_table_for_class(newClass); + CLS_SETINITIALIZED(metaClass); + CLS_SETINITIALIZED(newClass); + CLS_SETRESOLV(metaClass); + CLS_SETRESOLV(newClass); + // Add pointer from super class + objc_mutex_lock(__objc_runtime_mutex); + newClass->sibling_class = newClass->super_class->subclass_list; + newClass->super_class->subclass_list = newClass; + metaClass->sibling_class = metaClass->super_class->subclass_list; + metaClass->super_class->subclass_list = metaClass; + objc_mutex_unlock(__objc_runtime_mutex); +} + +@implementation NSBlock ++ (void)load +{ + createNSBlockSubclass(&_NSConcreteGlobalBlock, "_NSConcreteGlobalBlockPrivate"); + createNSBlockSubclass(&_NSConcreteStackBlock, "_NSConcreteStackBlockPrivate"); +} +@end + diff --git a/exception.c b/exception.c index 5100a23..7c57dfa 100644 --- a/exception.c +++ b/exception.c @@ -27,6 +27,10 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see //#include #include "unwind-pe.h" +void (*__objc_unhandled_exception)(id) = 0; + +__attribute__((weak)) int main(void); + #ifdef __ARM_EABI_UNWINDER__ @@ -451,6 +455,13 @@ PERSONALITY_FUNCTION (int version, install_context: if (saw_cleanup == 0) { + if (_Unwind_GetRegionStart(context) == (int)main) + { + if (__objc_unhandled_exception) + { + __objc_unhandled_exception(xh->value); + } + } return_object = xh->value; if (!(actions & _UA_SEARCH_PHASE)) _Unwind_DeleteException(&xh->base); diff --git a/objc/runtime.h b/objc/runtime.h index a3e0c24..5cfbb41 100644 --- a/objc/runtime.h +++ b/objc/runtime.h @@ -315,6 +315,12 @@ id (*objc_proxy_lookup)(id receiver, SEL op) OBJC_NONPORTABLE; */ struct objc_slot *(*objc_msg_forward3)(id receiver, SEL op) OBJC_NONPORTABLE; +/** + * Runtime hook for unhandled exceptions. This is called if an exception is + * not caught. + */ +void (*__objc_unhandled_exception)(id); + // Global self so that self is a valid symbol everywhere. Will be replaced by // a real self in an inner scope if there is one. static const id self = nil; diff --git a/properties.m b/properties.m new file mode 100644 index 0000000..eaff548 --- /dev/null +++ b/properties.m @@ -0,0 +1,47 @@ +#include "objc/runtime.h" + +// Subset of NSObject interface needed for properties. +@interface NSObject {} +- (id)retain; +- (id)copy; +- (id)autorelease; +- (void)release; +@end + +id objc_getProperty(id obj, SEL _cmd, ptrdiff_t offset, BOOL isAtomic) +{ + if (isAtomic) + { + @synchronized(obj) { + return objc_getProperty(obj, _cmd, offset, NO); + } + } + char *addr = (char*)obj; + addr += offset; + id ret = *(id*)addr; + return [[ret retain] autorelease]; +} + +void objc_setProperty(id obj, SEL _cmd, ptrdiff_t offset, id arg, BOOL isAtomic, BOOL isCopy) +{ + if (isAtomic) + { + @synchronized(obj) { + objc_setProperty(obj, _cmd, offset, arg, NO, isCopy); + return; + } + } + if (isCopy) + { + arg = [arg copy]; + } + else + { + arg = [arg retain]; + } + char *addr = (char*)obj; + addr += offset; + id old = *(id*)addr; + *(id*)addr = arg; + [old release]; +} diff --git a/sendmsg.c b/sendmsg.c index eb9bff1..f1fb7cc 100644 --- a/sendmsg.c +++ b/sendmsg.c @@ -606,7 +606,7 @@ static void merge_methods_from_superclass (Class class) method_list = method_list->method_next; } } - while (super = super->super_class); + while ((super = super->super_class)); if (class->subclass_list) /* Traverse subclasses */ for (Class next = class->subclass_list; next; next = next->sibling_class) merge_methods_from_superclass (next);