#include "objc/runtime.h" #include #include #include #include #include "class.h" #include "properties.h" #include "spinlock.h" #include "visibility.h" #include "nsobject.h" PRIVATE int spinlocks[spinlock_count]; /** * Public function for getting a property. */ id objc_getProperty(id obj, SEL _cmd, ptrdiff_t offset, BOOL isAtomic) { if (nil == obj) { return nil; } char *addr = (char*)obj; addr += offset; id ret; if (isAtomic) { int *lock = lock_for_pointer(addr); lock_spinlock(lock); ret = *(id*)addr; ret = [ret retain]; unlock_spinlock(lock); } else { ret = *(id*)addr; ret = [ret retain]; } return [ret autorelease]; } void objc_setProperty(id obj, SEL _cmd, ptrdiff_t offset, id arg, BOOL isAtomic, BOOL isCopy) { if (nil == obj) { return; } if (isCopy) { arg = [arg copy]; } else { arg = [arg retain]; } char *addr = (char*)obj; addr += offset; id old; if (isAtomic) { int *lock = lock_for_pointer(addr); lock_spinlock(lock); old = *(id*)addr; *(id*)addr = arg; unlock_spinlock(lock); } else { old = *(id*)addr; *(id*)addr = arg; } [old release]; } /** * Structure copy function. This is provided for compatibility with the Apple * APIs (it's an ABI function, so it's semi-public), but it's a bad design so * it's not used. The problem is that it does not identify which of the * pointers corresponds to the object, which causes some excessive locking to * be needed. */ void objc_copyPropertyStruct(void *dest, void *src, ptrdiff_t size, BOOL atomic, BOOL strong) { if (atomic) { int *lock = lock_for_pointer(src); int *lock2 = lock_for_pointer(src); lock_spinlock(lock); lock_spinlock(lock2); memcpy(dest, src, size); unlock_spinlock(lock); unlock_spinlock(lock2); } else { memcpy(dest, src, size); } } /** * Get property structure function. Copies a structure from an ivar to another * variable. Locks on the address of src. */ void objc_getPropertyStruct(void *dest, void *src, ptrdiff_t size, BOOL atomic, BOOL strong) { if (atomic) { int *lock = lock_for_pointer(src); lock_spinlock(lock); memcpy(dest, src, size); unlock_spinlock(lock); } else { memcpy(dest, src, size); } } /** * Set property structure function. Copes a structure to an ivar. Locks on * dest. */ void objc_setPropertyStruct(void *dest, void *src, ptrdiff_t size, BOOL atomic, BOOL strong) { if (atomic) { int *lock = lock_for_pointer(dest); lock_spinlock(lock); memcpy(dest, src, size); unlock_spinlock(lock); } else { memcpy(dest, src, size); } } objc_property_t class_getProperty(Class cls, const char *name) { // Old ABI classes don't have declared properties if (Nil == cls || !objc_test_class_flag(cls, objc_class_flag_new_abi)) { return NULL; } struct objc_property_list *properties = cls->properties; while (NULL != properties) { for (int i=0 ; icount ; i++) { objc_property_t p = &properties->properties[i]; if (strcmp(p->name, name) == 0) { return p; } } properties = properties->next; } return NULL; } objc_property_t* class_copyPropertyList(Class cls, unsigned int *outCount) { if (Nil == cls || !objc_test_class_flag(cls, objc_class_flag_new_abi)) { if (NULL != outCount) { *outCount = 0; } return NULL; } struct objc_property_list *properties = cls->properties; unsigned int count = 0; for (struct objc_property_list *l=properties ; NULL!=l ; l=l->next) { count += l->count; } if (NULL != outCount) { *outCount = count; } if (0 == count) { return NULL; } objc_property_t *list = calloc(sizeof(objc_property_t), count); unsigned int out = 0; for (struct objc_property_list *l=properties ; NULL!=l ; l=l->next) { for (int i=0 ; icount ; i++) { list[out] = &l->properties[i]; } } return list; } const char *property_getName(objc_property_t property) { return property->name; }