diff --git a/class.h b/class.h index 8a0d726..7245ae6 100644 --- a/class.h +++ b/class.h @@ -151,7 +151,16 @@ enum objc_class_flags * It should be cleared by protocols, constant strings, and objects not * allocated by NSAllocateObject(). */ - objc_class_flag_plane_aware = (1<<6) + objc_class_flag_plane_aware = (1<<6), + /** + * This class is a hidden class (should not be registered in the class + * table nor returned from object_getClass()). + */ + objc_class_flag_hidden_class = (1<<7), + /** + * This class is a hidden class used to implement @synchronize() + */ + objc_class_flag_lock_class = (1<<8) }; static inline void objc_set_class_flag(struct objc_class *aClass, diff --git a/dtable.c b/dtable.c index d046a42..faca6a7 100644 --- a/dtable.c +++ b/dtable.c @@ -278,7 +278,13 @@ struct objc_slot* objc_dtable_lookup(dtable_t dtable, uint32_t uid) } return NULL; } - +dtable_t objc_copy_dtable_for_class(dtable_t old, Class cls) +{ + dtable_t dtable = calloc(1, sizeof(struct objc_dtable)); + dtable->cls = cls; + INIT_LOCK(dtable->lock); + return dtable; +} #else @@ -499,6 +505,11 @@ void objc_resize_dtables(uint32_t newSize) } } +dtable_t objc_copy_dtable_for_class(dtable_t old, Class cls) +{ + return SparseArrayCopy(old); +} + #endif // __OBJC_LOW_MEMORY__ void objc_resolve_class(Class); diff --git a/dtable.h b/dtable.h index c24b111..132580b 100644 --- a/dtable.h +++ b/dtable.h @@ -97,3 +97,8 @@ static inline int classHasDtable(struct objc_class *cls) * modifying a class's method list. */ void objc_update_dtable_for_class(Class); + +/** + * Creates a copy of the class's dispatch table. + */ +dtable_t objc_copy_dtable_for_class(dtable_t old, Class cls); diff --git a/objc/runtime.h b/objc/runtime.h index 3eb6ec8..451ea3e 100644 --- a/objc/runtime.h +++ b/objc/runtime.h @@ -220,9 +220,6 @@ IMP method_setImplementation(Method method, IMP imp); Class objc_allocateClassPair(Class superclass, const char *name, size_t extraBytes); -OBJC_NONPORTABLE -Class objc_allocateMetaClass(Class superclass, size_t extraBytes); - void objc_disposeClassPair(Class cls); id objc_getClass(const char *name); diff --git a/runtime.c b/runtime.c index cdbd054..7c717ff 100644 --- a/runtime.c +++ b/runtime.c @@ -591,23 +591,6 @@ Class objc_allocateClassPair(Class superclass, const char *name, size_t extraByt return newClass; } -Class objc_allocateMetaClass(Class superclass, size_t extraBytes) -{ - Class metaClass = calloc(1, sizeof(struct objc_class) + extraBytes); - - // Initialize the metaclass - metaClass->isa = superclass->isa; - metaClass->super_class = superclass->isa; - metaClass->name = "hidden class"; //strdup(superclass->name); - metaClass->info = objc_class_flag_resolved | objc_class_flag_initialized | - objc_class_flag_meta | objc_class_flag_user_created | - objc_class_flag_new_abi; - metaClass->dtable = __objc_uninstalled_dtable; - metaClass->instance_size = sizeof(struct objc_class); - - return metaClass; -} - void *object_getIndexedIvars(id obj) { @@ -623,7 +606,13 @@ Class object_getClass(id obj) { if (nil != obj) { - return obj->isa; + Class isa = obj->isa; + while ((Nil != isa) && objc_test_class_flag(isa, objc_class_flag_hidden_class)) + { + fprintf(stderr, "Skipping hidden class: %s\n", isa->name); + isa = isa->super_class; + } + return isa; } return Nil; } diff --git a/sync.m b/sync.m index 88f0aee..43aebf7 100644 --- a/sync.m +++ b/sync.m @@ -1,5 +1,7 @@ #include "objc/runtime.h" #include "lock.h" +#include "class.h" +#include "dtable.h" #include #include @@ -17,7 +19,6 @@ int snprintf(char *restrict s, size_t n, const char *restrict format, ...); @end static mutex_t at_sync_init_lock; -static unsigned long long lockClassId; void __objc_sync_init(void) { @@ -31,55 +32,61 @@ static void deallocLockClass(id obj, SEL _cmd); static inline Class findLockClass(id obj) { struct objc_object object = { obj->isa }; - SEL dealloc = SELECTOR(dealloc); - // Find the first class where this lookup is correct - if (objc_msg_lookup((id)&object, dealloc) != (IMP)deallocLockClass) + while (Nil != object.isa && + !objc_test_class_flag(object.isa, objc_class_flag_lock_class)) { - do { - object.isa = class_getSuperclass(object.isa); - } while (Nil != object.isa && - objc_msg_lookup((id)&object, dealloc) != (IMP)deallocLockClass); - } - if (Nil == object.isa) { return Nil; } - // object->isa is now either the lock class, or a class which inherits from - // the lock class - Class lastClass; - do { - lastClass = object.isa; object.isa = class_getSuperclass(object.isa); - } while (Nil != object.isa && - objc_msg_lookup((id)&object, dealloc) == (IMP)deallocLockClass); - return lastClass; + } + return object.isa; +} + +static Class allocateLockClass(Class superclass) +{ + Class newClass = calloc(1, sizeof(struct objc_class) + sizeof(mutex_t)); + + if (Nil == newClass) { return Nil; } + + // Set up the new class + newClass->isa = superclass->isa; + // Set the superclass pointer to the name. The runtime will fix this when + // the class links are resolved. + newClass->name = superclass->name; + newClass->info = objc_class_flag_resolved | + objc_class_flag_class | objc_class_flag_user_created | + objc_class_flag_new_abi | objc_class_flag_hidden_class | + objc_class_flag_lock_class; + newClass->super_class = superclass; + newClass->dtable = objc_copy_dtable_for_class(superclass->dtable, newClass); + newClass->instance_size = superclass->instance_size; + if (objc_test_class_flag(superclass, objc_class_flag_meta)) + { + newClass->info |= objc_class_flag_meta; + } + + return newClass; } static inline Class initLockObject(id obj) { - Class lockClass; + Class lockClass = allocateLockClass(obj->isa); if (class_isMetaClass(obj->isa)) { - lockClass = objc_allocateMetaClass(obj, sizeof(mutex_t)); + obj->isa = lockClass; + objc_send_initialize(obj); } else { - char nameBuffer[40]; - snprintf(nameBuffer, 39, "hiddenlockClass%lld", lockClassId++); - lockClass = objc_allocateClassPair(obj->isa, nameBuffer, - sizeof(mutex_t)); + const char *types = + method_getTypeEncoding(class_getInstanceMethod(obj->isa, + SELECTOR(dealloc))); + class_addMethod(lockClass, SELECTOR(dealloc), (IMP)deallocLockClass, + types); + obj->isa = lockClass; } - const char *types = - method_getTypeEncoding(class_getInstanceMethod(obj->isa, - SELECTOR(dealloc))); - class_addMethod(lockClass, SELECTOR(dealloc), (IMP)deallocLockClass, - types); - if (!class_isMetaClass(obj->isa)) - { - objc_registerClassPair(lockClass); - } - mutex_t *lock = object_getIndexedIvars(lockClass); INIT_LOCK(*lock); - obj->isa = lockClass; + fprintf(stderr, "Making %p hidden class for %p\n", lockClass, obj); return lockClass; } @@ -87,7 +94,8 @@ static void deallocLockClass(id obj, SEL _cmd) { Class lockClass = findLockClass(obj); Class realClass = class_getSuperclass(lockClass); - // Call the real -dealloc method + // Call the real -dealloc method (this ordering is required in case the + // user does @synchronize(self) in -dealloc) struct objc_super super = {obj, realClass }; objc_msgSendSuper(&super, SELECTOR(dealloc)); // After calling [super dealloc], the object will no longer exist. @@ -95,7 +103,7 @@ static void deallocLockClass(id obj, SEL _cmd) mutex_t *lock = object_getIndexedIvars(lockClass); DESTROY_LOCK(lock); // Free the class - objc_disposeClassPair(lockClass); + free(lockClass); } // TODO: This should probably have a special case for classes conforming to the