|
|
|
|
@ -1,5 +1,7 @@
|
|
|
|
|
#include "objc/runtime.h"
|
|
|
|
|
#include "lock.h"
|
|
|
|
|
#include "class.h"
|
|
|
|
|
#include "dtable.h"
|
|
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
@ -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);
|
|
|
|
|
if (!class_isMetaClass(obj->isa))
|
|
|
|
|
{
|
|
|
|
|
objc_registerClassPair(lockClass);
|
|
|
|
|
obj->isa = 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
|
|
|
|
|
|