First pass at hybrid GC mode. This will try use retain-release mode if the collector is not running. Code will run in retain/release mode unless something compiled with -fobjc-gc-only is loaded.

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@33174 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
David Chisnall 2011-05-28 14:51:40 +00:00
parent 86fa2414ec
commit 4db587f9d6
3 changed files with 131 additions and 23 deletions

View file

@ -34,12 +34,18 @@
#import "Foundation/NSException.h"
#import "Foundation/NSThread.h"
#if GS_WITH_GC || __OBJC_GC__
#if GS_WITH_GC || __OBJC_GC__
#if __OBJC_GC__
@interface GSAutoreleasePool : NSAutoreleasePool @end
#endif
@implementation NSAutoreleasePool
static NSAutoreleasePool *pool = nil;
#if GS_WITH_GC
+ (void) initialize
{
pool = NSAllocateObject(self, 0, NSDefaultMallocZone());
@ -55,6 +61,42 @@ static NSAutoreleasePool *pool = nil;
{
return pool;
}
#endif
#ifdef __OBJC_GC__
static Class PoolClass;
+ (void) initialize
{
if ([NSGarbageCollector defaultCollector])
{
pool = NSAllocateObject(self, 0, NSDefaultMallocZone());
}
else
{
PoolClass = [GSAutoreleasePool class];
}
return;
}
+ (id) allocWithZone: (NSZone*)zone
{
if (nil == pool)
{
return NSAllocateObject(PoolClass, 0, 0);
}
return pool;
}
+ (id) new
{
if (nil == pool)
{
return [NSAllocateObject(PoolClass, 0, 0) init];
}
return pool;
}
#endif
- (id) init
{
@ -165,7 +207,9 @@ static NSAutoreleasePool *pool = nil;
@end
#else
#endif
#if !GS_WITH_GC
/* When this is `NO', autoreleased objects are never actually recorded
in an NSAutoreleasePool, and are not sent a `release' message.
@ -249,7 +293,11 @@ pop_pool_from_cache (struct autorelease_thread_vars *tv)
}
#if __OBJC_GC__
@implementation GSAutoreleasePool
#else
@implementation NSAutoreleasePool
#endif
+ (void) initialize
{

View file

@ -64,6 +64,10 @@
#endif
#endif // __GNUC__
#ifdef __OBJC_GC__
#include <objc/objc-auto.h>
#endif
#define IN_NSOBJECT_M 1
#import "GSPrivate.h"
@ -125,7 +129,7 @@ BOOL NSDeallocateZombies = NO;
static Class zombieClass = Nil;
static NSMapTable *zombieMap = 0;
#if !GS_WITH_GC && !__OBJC_GC__
#if !GS_WITH_GC
static void GSMakeZombie(NSObject *o)
{
Class c;
@ -421,7 +425,26 @@ struct obj_layout {
};
typedef struct obj_layout *obj;
#ifdef __OBJC_GC__
/**
* If -base is compiled in GC mode, then we want to still support manual
* reference counting if we are linked with non-GC code.
*/
static BOOL GSDecrementExtraRefCountWasZero(id anObject);
BOOL
NSDecrementExtraRefCountWasZero(id anObject)
{
if (!objc_collecting_enabled())
{
return GSDecrementExtraRefCountWasZero(anObject);
}
}
static BOOL GSDecrementExtraRefCountWasZero(id anObject)
#else
/**
* Examines the extra reference count for the object and, if non-zero
* decrements it, otherwise leaves it unchanged.<br />
@ -431,8 +454,9 @@ typedef struct obj_layout *obj;
*/
BOOL
NSDecrementExtraRefCountWasZero(id anObject)
#endif
{
#if !GS_WITH_GC && !__OBJC_GC__
#if !GS_WITH_GC
if (double_release_check_enabled)
{
NSUInteger release_count;
@ -506,13 +530,38 @@ NSDecrementExtraRefCountWasZero(id anObject)
inline NSUInteger
NSExtraRefCount(id anObject)
{
#if GS_WITH_GC || __OBJC_GC__
#ifdef __OBJC_GC__
if (objc_collecting_enabled())
{
return UINT_MAX-1;
}
#endif
#if GS_WITH_GC
return UINT_MAX - 1;
#else /* GS_WITH_GC */
return ((obj)anObject)[-1].retained;
#endif /* GS_WITH_GC */
}
#ifdef __OBJC_GC__
/**
* If -base is compiled in GC mode, then we want to still support manual
* reference counting if we are linked with non-GC code.
*/
static void GSIncrementExtraRefCount(id anObject);
inline void NSIncrementExtraRefCount(id anObject)
{
if (!objc_collecting_enabled())
{
GSIncrementExtraRefCount(anObject);
}
}
static void GSIncrementExtraRefCount(id anObject)
#else
/**
* Increments the extra reference count for anObject.<br />
* The GNUstep version raises an exception if the reference count
@ -521,6 +570,7 @@ NSExtraRefCount(id anObject)
*/
inline void
NSIncrementExtraRefCount(id anObject)
#endif
{
#if GS_WITH_GC || __OBJC_GC__
return;
@ -1947,7 +1997,7 @@ objc_create_block_classes_as_subclasses_of(Class super);
*/
- (oneway void) release
{
#if (GS_WITH_GC == 0) && !__OBJC_GC__
#if (GS_WITH_GC == 0)
if (NSDecrementExtraRefCountWasZero(self))
{
[self dealloc];
@ -1997,7 +2047,7 @@ objc_create_block_classes_as_subclasses_of(Class super);
*/
- (id) retain
{
#if (GS_WITH_GC == 0) && !__OBJC_GC__
#if (GS_WITH_GC == 0)
NSIncrementExtraRefCount(self);
#endif
return self;
@ -2024,7 +2074,7 @@ objc_create_block_classes_as_subclasses_of(Class super);
*/
- (NSUInteger) retainCount
{
#if GS_WITH_GC || __OBJC_GC__
#if GS_WITH_GC
return UINT_MAX;
#else
return NSExtraRefCount(self) + 1;

View file

@ -234,6 +234,10 @@ NSZoneName (NSZone *zone)
__strong void *
NSAllocateCollectable(NSUInteger size, NSUInteger options)
{
if (!objc_collecting_enabled())
{
return calloc(1, size);
}
id obj = objc_gc_allocate_collectable(size,
((options & NSScannedOption) == NSScannedOption));
if ((options & NSCollectorDisabledOption) == NSCollectorDisabledOption)
@ -246,19 +250,26 @@ NSAllocateCollectable(NSUInteger size, NSUInteger options)
__strong void *
NSReallocateCollectable(void *ptr, NSUInteger size, NSUInteger options)
{
if (!objc_collecting_enabled())
{
return realloc(ptr, size);
}
return objc_gc_reallocate_collectable(ptr, size,
((options & NSScannedOption) == NSScannedOption));
}
id NSMakeCollectable(id obj)
{
objc_gc_release(obj);
if (objc_collecting_enabled())
{
objc_gc_release(obj);
}
return obj;
}
NSZone*
NSCreateZone (NSUInteger start, NSUInteger gran, BOOL canFree)
{
NSLog(@" *** Creating a zone while running GC is ignored.");
return &default_zone;
}
@ -268,15 +279,6 @@ NSDefaultMallocZone (void)
return &default_zone;
}
// This is an ugly hack. We should be using NSAllocateCollectable() without
// NSScannedOption, not trying to fudge this with stuff that's totally
// incompatible with Apple's design.
NSZone*
GSAtomicMallocZone (void)
{
return &default_zone;
}
NSZone*
NSZoneFromPointer (void *ptr)
{
@ -318,15 +320,23 @@ NSZoneMalloc (NSZone *zone, NSUInteger size)
void*
NSZoneCalloc (NSZone *zone, NSUInteger elems, NSUInteger bytes)
{
// FIXME: Overflow checking
size_t size = elems * bytes;
return objc_gc_allocate_collectable(size, YES);
if (objc_collecting_enabled())
{
// FIXME: Overflow checking
size_t size = elems * bytes;
return objc_gc_allocate_collectable(size, YES);
}
return calloc(elems, bytes);
}
void*
NSZoneRealloc (NSZone *zone, void *ptr, NSUInteger size)
{
return objc_gc_reallocate_collectable(ptr, size, YES);
if (objc_collecting_enabled())
{
return objc_gc_reallocate_collectable(ptr, size, YES);
}
return realloc(ptr, size);
}
void NSZoneFree (NSZone *zone, void *ptr) { }