Added fast path for objc_autoreleaseReturnValue() and objc_retainAutoreleasedReturnValue().

In a simple example:

- foo { return self; }

void someFunction(void)
{
	id a = foo;
	...
}

In ARC mode, this expands to:

- foo { return objc_retainAutoreleaseReturnValue(self); }

void someFunction(void)
{
	id a = objc_retainAutoreleasedReturnValue(foo);
	...
}

In the slow path, this is equivalent to:

- foo { return [[self retain] autorelease]; }

void someFunction(void)
{
	id a = [foo retain];
	...
	[a release];
}

The fast path skips the autorelease / retain pair.  The return value is stored
in thread-local storage temporarily and then retrieved, the retain balancing
out the autorelease.

This gives a 50% speedup on a single thread.  It also avoids some atomic
operations.
main
theraven 15 years ago
parent 36d21882ec
commit e3c836b090

44
arc.m

@ -6,10 +6,23 @@
#import "objc/hooks.h"
#import "objc/objc-arc.h"
#ifndef NO_PTHREADS
#include <pthread.h>
pthread_key_t ReturnRetained;
#endif
@interface NSAutoreleasePool
+ (Class)class;
+ (id)new;
- (void)release;
@end
static Class AutoreleasePool;
static IMP NewAutoreleasePool;
static IMP DeleteAutoreleasePool;
void *objc_autoreleasePoolPush(void)
{
// TODO: This should be more lightweight. We really just need to allocate
@ -17,11 +30,13 @@ void *objc_autoreleasePoolPush(void)
if (Nil == AutoreleasePool)
{
AutoreleasePool = objc_getRequiredClass("NSAutoreleasePool");
[AutoreleasePool class];
NewAutoreleasePool = class_getMethodImplementation(
object_getClass(AutoreleasePool),
//AutoreleasePool,
SELECTOR(new));
DeleteAutoreleasePool = class_getMethodImplementation(
object_getClass(AutoreleasePool),
AutoreleasePool,
SELECTOR(release));
}
return NewAutoreleasePool(AutoreleasePool, SELECTOR(new));
@ -40,8 +55,25 @@ id objc_autorelease(id obj)
id objc_autoreleaseReturnValue(id obj)
{
// TODO: Fast path for allowing this to be popped from the pool.
#ifdef NO_PTHREADS
return [obj autorelease];
#else
id old = pthread_getspecific(ReturnRetained);
objc_release(old);
pthread_setspecific(ReturnRetained, obj);
return old;
#endif
}
id objc_retainAutoreleasedReturnValue(id obj)
{
#ifdef NO_PTHREADS
return objc_retain(obj);
#else
id old = pthread_getspecific(ReturnRetained);
pthread_setspecific(ReturnRetained, NULL);
return old;
#endif
}
id objc_retain(id obj)
@ -59,11 +91,6 @@ id objc_retainAutoreleaseReturnValue(id obj)
return objc_autoreleaseReturnValue(objc_retain(obj));
}
id objc_retainAutoreleasedReturnValue(id obj)
{
// TODO: Fast path popping this from the autorelease pool
return objc_retain(obj);
}
id objc_retainBlock(id b)
{
@ -137,6 +164,9 @@ PRIVATE void init_arc(void)
{
weak_ref_initialize(&weakRefs, 128);
INIT_LOCK(weakRefLock);
#ifndef NO_PTHREADS
pthread_key_create(&ReturnRetained, (void(*)(void*))objc_release);
#endif
}
id objc_storeWeak(id *addr, id obj)

Loading…
Cancel
Save