darling-libobjc2/properties.m
theraven 352e721861 Changed ptrdiff_t to int in property accessors. This is for compatibility with some changes in clang that are required to prevent things from breaking on LP64 platforms.
It would be cleaner to use a ptrdiff_t here, but unfortunately we can't because the ivar_offset field in the runtime metadata is an int so ivar offsets beyond 4GB will not work on LP64 platforms.

This probably isn't a limitation.  If you have more than 4GB of ivars in one object, you've done something badly wrong and probably shouldn't be allowed to write code anymore.
2010-03-23 16:11:57 +00:00

110 lines
2.3 KiB
Objective-C

#include "objc/runtime.h"
#include <stdio.h>
#include <unistd.h>
// Subset of NSObject interface needed for properties.
@interface NSObject {}
- (id)retain;
- (id)copy;
- (id)autorelease;
- (void)release;
@end
/**
* Number of spinlocks. This allocates one page on 32-bit platforms.
*/
#define spinlock_count (1<<10)
const int spinlock_mask = spinlock_count - 1;
/**
* Integers used as spinlocks for atomic property access.
*/
static int spinlocks[spinlock_count];
/**
* Get a spin lock from a pointer. We want to prevent lock contention between
* properties in the same object - if someone is stupid enough to be using
* atomic property access, they are probably stupid enough to do it for
* multiple properties in the same object. We also want to try to avoid
* contention between the same property in different objects, so we can't just
* use the ivar offset.
*/
static inline int *lock_for_pointer(void *ptr)
{
intptr_t hash = (intptr_t)ptr;
// Most properties will be pointers, so disregard the lowest few bits
hash >>= sizeof(void*) == 4 ? 2 : 8;
intptr_t low = hash & spinlock_mask;
hash >>= 16;
hash |= low;
return spinlocks + (hash & spinlock_mask);
}
inline static void unlock_spinlock(int *spinlock)
{
*spinlock = 0;
}
inline static void lock_spinlock(int *spinlock)
{
int count = 0;
// Set the spin lock value to 1 if it is 0.
while(!__sync_bool_compare_and_swap(spinlock, 0, 1))
{
count++;
if (0 == count % 10)
{
// If it is already 1, let another thread play with the CPU for a
// bit then try again.
sleep(0);
}
}
}
id objc_getProperty(id obj, SEL _cmd, int offset, BOOL isAtomic)
{
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, int offset, id arg, BOOL isAtomic, BOOL isCopy)
{
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];
}