Fixed @synchronize() with a class that has had an instance used for @synchronize().

main
theraven 15 years ago
parent e1a756110f
commit 7be9f34619

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

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

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

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

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

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

Loading…
Cancel
Save