Added support for ARC.

Weak references are still not supported, but code that doesn't use them (i.e. any code that wants to be compatible with OS X 10.6) will work fine.

The current implementation is VERY inefficient and has a large number of missed optimisation opportunities: this is the 'make it right' phase, and should be almost equivalent to explicit retain / release code.
main
theraven 15 years ago
parent 6412c7a4e7
commit b5380d50d3

@ -18,6 +18,7 @@ ${LIBOBJC}_VERSION = 4
${LIBOBJC}_OBJC_FILES = \ ${LIBOBJC}_OBJC_FILES = \
NSBlocks.m\ NSBlocks.m\
Protocol2.m\ Protocol2.m\
arc.m\
associate.m\ associate.m\
blocks_runtime.m\ blocks_runtime.m\
mutation.m\ mutation.m\

123
arc.m

@ -0,0 +1,123 @@
#import "objc/runtime.h"
#import "objc/blocks_runtime.h"
#import "nsobject.h"
#import "selector.h"
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
// an array here...
if (Nil == AutoreleasePool)
{
AutoreleasePool = objc_getRequiredClass("NSAutoreleasePool");
NewAutoreleasePool = class_getMethodImplementation(
object_getClass(AutoreleasePool),
SELECTOR(new));
DeleteAutoreleasePool = class_getMethodImplementation(
object_getClass(AutoreleasePool),
SELECTOR(release));
}
return NewAutoreleasePool(AutoreleasePool, SELECTOR(new));
}
void objc_autoreleasePoolPop(void *pool)
{
// TODO: Keep a small pool of autorelease pools per thread and allocate
// from there.
DeleteAutoreleasePool(pool, SELECTOR(release));
}
id objc_autorelease(id obj)
{
return [obj autorelease];
}
id objc_autoreleaseReturnValue(id obj)
{
// TODO: Fast path for allowing this to be popped from the pool.
return [obj autorelease];
}
id objc_retain(id obj)
{
return [obj retain];
}
id objc_retainAutorelease(id obj)
{
return objc_autorelease(objc_retain(obj));
}
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)
{
return _Block_copy(b);
}
void objc_release(id obj)
{
[obj release];
}
id objc_storeStrong(id *object, id value)
{
value = [value retain];
id oldValue = *object;
*object = value;
[oldValue release];
return value;
}
////////////////////////////////////////////////////////////////////////////////
// Weak references
////////////////////////////////////////////////////////////////////////////////
//
//FIXME: These are all stubs!
#if 0
id objc_storeWeak(id*addr, id obj) { return obj;}
id objc_loadWeakRetained(id* obj)
{
}
id objc_loadWeak(id* object)
{
return objc_autorelease(objc_loadWeakRetained(object));
}
void objc_moveWeak(id *dest, id *src)
{
}
void objc_copyWeak(id *dest, id *src)
{
objc_release(objc_initWeak(dest, objc_loadWeakRetained(src)));
}
void objc_destroyWeak(id* obj)
{
objc_storeWeak(object, nil);
}
id objc_initWeak(id*, id)
{
*object = nil;
return objc_storeWeak(object, value);
}
#endif

@ -186,45 +186,14 @@ BOOL objc_atomicCompareAndSwapInstanceVariableBarrier(id predicate, id replaceme
return objc_atomicCompareAndSwapPtr(predicate, replacement, objectLocation); return objc_atomicCompareAndSwapPtr(predicate, replacement, objectLocation);
} }
SEL copy;
static const int MaxStackClasses = 16;
static Class StackClasses[MaxStackClasses];
static IMP StackCopyFunctions[MaxStackClasses];
static int StackClassCount;
static inline id copy_to_heap(id val)
{
if ((0 == val) || ((1 & (intptr_t)val) == 1)) { return val; }
for (unsigned int i=0 ; i<StackClassCount ; i++)
{
if (val->isa == StackClasses[i])
{
return StackCopyFunctions[i](val, copy);
}
}
return val;
}
BOOL objc_register_stack_class(Class cls, IMP copyFunction)
{
LOCK_RUNTIME_FOR_SCOPE();
if (StackClassCount+1 >= MaxStackClasses) { return NO; }
StackClasses[StackClassCount] = cls;
StackCopyFunctions[StackClassCount] = copyFunction;
StackClassCount++;
return YES;
}
id objc_assign_strongCast(id val, id *ptr) id objc_assign_strongCast(id val, id *ptr)
{ {
val = copy_to_heap(val);
*ptr = val; *ptr = val;
return val; return val;
} }
id objc_assign_global(id val, id *ptr) id objc_assign_global(id val, id *ptr)
{ {
val = copy_to_heap(val);
if (isGCEnabled) if (isGCEnabled)
{ {
GC_add_roots(ptr, ptr+1); GC_add_roots(ptr, ptr+1);
@ -235,7 +204,6 @@ id objc_assign_global(id val, id *ptr)
id objc_assign_ivar(id val, id dest, ptrdiff_t offset) id objc_assign_ivar(id val, id dest, ptrdiff_t offset)
{ {
val = copy_to_heap(val);
*(id*)((char*)dest+offset) = val; *(id*)((char*)dest+offset) = val;
return val; return val;
} }
@ -697,7 +665,7 @@ PRIVATE void init_gc(void)
int s = envValue[0] ? (int)strtol(envValue, NULL, 10) : SIGUSR2; int s = envValue[0] ? (int)strtol(envValue, NULL, 10) : SIGUSR2;
signal(s, collectAndDumpStats); signal(s, collectAndDumpStats);
} }
GC_clear_roots(); //GC_clear_roots();
} }
BOOL objc_collecting_enabled(void) BOOL objc_collecting_enabled(void)
@ -761,7 +729,5 @@ PRIVATE void enableGC(BOOL exclude)
refcount_initialize(&refcounts, 4096); refcount_initialize(&refcounts, 4096);
finalize = sel_registerName("finalize"); finalize = sel_registerName("finalize");
cxx_destruct = sel_registerName(".cxx_destruct"); cxx_destruct = sel_registerName(".cxx_destruct");
copy = sel_registerName("copy");
GC_finalizer_notifier = runFinalizers; GC_finalizer_notifier = runFinalizers;
objc_register_stack_class(&_NSConcreteStackBlock, (IMP)_Block_copy);
} }

@ -9,6 +9,13 @@ extern "C" {
# define __GNUSTEP_RUNTIME__ # define __GNUSTEP_RUNTIME__
#endif #endif
#ifndef __unsafe_unretained
# ifndef __has_feature
# define __unsafe_unretained
# elif !__has_feature(objc_arc)
# define __unsafe_unretained
# endif
#endif
#include <stdint.h> #include <stdint.h>
@ -74,7 +81,7 @@ typedef struct objc_object
struct objc_super struct objc_super
{ {
/** The receiver of the message. */ /** The receiver of the message. */
id receiver; __unsafe_unretained id receiver;
/** The class containing the method to call. */ /** The class containing the method to call. */
# if !defined(__cplusplus) && !__OBJC2__ # if !defined(__cplusplus) && !__OBJC2__
Class class; Class class;
@ -224,7 +231,7 @@ objc_property_t* class_copyPropertyList(Class cls, unsigned int *outCount);
* outCount argument is set to the number of protocols returned. The caller is * outCount argument is set to the number of protocols returned. The caller is
* responsible for freeing the returned buffer. * responsible for freeing the returned buffer.
*/ */
Protocol ** class_copyProtocolList(Class cls, unsigned int *outCount); Protocol *const* class_copyProtocolList(Class cls, unsigned int *outCount);
/** /**
* Creates an instance of this class, allocating memory using malloc. * Creates an instance of this class, allocating memory using malloc.
@ -606,7 +613,7 @@ objc_property_t *protocol_copyPropertyList(Protocol *p, unsigned int *count);
* number of protocols in the array being returned via the last argument. The * number of protocols in the array being returned via the last argument. The
* caller is responsible for freeing this array. * caller is responsible for freeing this array.
*/ */
Protocol **protocol_copyProtocolList(Protocol *p, unsigned int *count); Protocol *const*protocol_copyProtocolList(Protocol *p, unsigned int *count);
/** /**
* Returns all of the protocols that the runtime is aware of. Note that * Returns all of the protocols that the runtime is aware of. Note that
@ -616,7 +623,7 @@ Protocol **protocol_copyProtocolList(Protocol *p, unsigned int *count);
* *
* The caller is responsible for freeing the returned array. * The caller is responsible for freeing the returned array.
*/ */
Protocol **objc_copyProtocolList(unsigned int *outCount); Protocol *const*objc_copyProtocolList(unsigned int *outCount);
/** /**
* Returns the method description for the specified method within a given * Returns the method description for the specified method within a given
* protocol. * protocol.

@ -329,7 +329,7 @@ struct objc_method_description *protocol_copyMethodDescriptionList(Protocol *p,
return out; return out;
} }
Protocol **protocol_copyProtocolList(Protocol *p, unsigned int *count) Protocol*const* protocol_copyProtocolList(Protocol *p, unsigned int *count)
{ {
if (NULL == p) { return NULL; } if (NULL == p) { return NULL; }
*count = 0; *count = 0;
@ -474,7 +474,7 @@ BOOL protocol_isEqual(Protocol *p, Protocol *other)
return NO; return NO;
} }
Protocol **objc_copyProtocolList(unsigned int *outCount) Protocol*const* objc_copyProtocolList(unsigned int *outCount)
{ {
unsigned int total = known_protocol_table->table_used; unsigned int total = known_protocol_table->table_used;
Protocol **p = calloc(sizeof(Protocol*), known_protocol_table->table_used); Protocol **p = calloc(sizeof(Protocol*), known_protocol_table->table_used);

@ -235,7 +235,7 @@ Method * class_copyMethodList(Class cls, unsigned int *outCount)
return list; return list;
} }
Protocol** class_copyProtocolList(Class cls, unsigned int *outCount) Protocol*const* class_copyProtocolList(Class cls, unsigned int *outCount)
{ {
CHECK_ARG(cls); CHECK_ARG(cls);
struct objc_protocol_list *protocolList = NULL; struct objc_protocol_list *protocolList = NULL;

Loading…
Cancel
Save