diff --git a/ChangeLog b/ChangeLog index 7a5e9672d..e3521d7bd 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,17 @@ +2011-05-24 David Chisnall + + * Source/NSBundle.m + * Source/NSGarbageCollector.m + * Source/NSKeyValueObserving.m + * Source/NSZone.m + * Source/NSObject.m + * Source/NSAutoreleasePool.m + First pass at supporting fully Apple-compatible GC in -base. Code sitting + on top of -base should not require modifying (in theory, at least, and + unless it does the sort of evil tricks that LanguageKit does for + performance). + + 2011-05-24 Richard Frith-Macdonald * Source/NSAutoreleasePool.m: diff --git a/Source/NSAutoreleasePool.m b/Source/NSAutoreleasePool.m index e2cac2fdd..b42683141 100644 --- a/Source/NSAutoreleasePool.m +++ b/Source/NSAutoreleasePool.m @@ -34,7 +34,7 @@ #import "Foundation/NSException.h" #import "Foundation/NSThread.h" -#if GS_WITH_GC +#if GS_WITH_GC || __OBJC_GC__ @implementation NSAutoreleasePool @@ -120,6 +120,8 @@ static NSAutoreleasePool *pool = nil; - (void) dealloc { + [NSException raise: NSGenericException + format: @"dealloc should not be called in garbage collected mode"]; GSNOSUPERDEALLOC; return; } diff --git a/Source/NSBundle.m b/Source/NSBundle.m index 60dd12701..dbd251f62 100644 --- a/Source/NSBundle.m +++ b/Source/NSBundle.m @@ -1305,13 +1305,21 @@ _bundle_load_callback(Class theClass, struct objc_category *theCategory) { bundle = (NSBundle *)NSMapGet(_byIdentifier, identifier); IF_NO_GC( - if (bundle != nil) - { - [bundle retain]; /* retain - look as if we were alloc'ed */ - } + [bundle retain]; /* retain - look as if we were alloc'ed */ ) } [load_lock unlock]; + // Some OS X apps try to get the foundation bundle by looking it up by + // identifier. This is expected to be faster than looking it up by class, so + // we lazily insert it into the table if it's requested. + if (nil == bundle && [@"com.apple.Foundation" isEqualToString: identifier]) + { + NSBundle *foundation = [self bundleForClass: self]; + [load_lock lock]; + NSMapInsert(_byIdentifier, @"com.apple.Foundation", foundation); + [load_lock unlock]; + return foundation; + } return AUTORELEASE(bundle); } diff --git a/Source/NSGarbageCollector.m b/Source/NSGarbageCollector.m index 7f204634b..65a1bca51 100644 --- a/Source/NSGarbageCollector.m +++ b/Source/NSGarbageCollector.m @@ -27,8 +27,91 @@ #import "Foundation/NSGarbageCollector.h" static NSGarbageCollector *collector = nil; -static unsigned disabled = 0; +#if __OBJC_GC__ +#include + +id CFRetain(id obj) +{ + return objc_gc_retain(obj); +} + +void CFRelease(id obj) +{ + objc_gc_release(obj); +} + +@implementation NSGarbageCollector + ++ (id) defaultCollector +{ + return collector; +} + ++ (void) initialize +{ + collector = [self alloc]; +} + +- (void) collectIfNeeded +{ + objc_collect(OBJC_COLLECT_IF_NEEDED | OBJC_FULL_COLLECTION); +} + +- (void) collectExhaustively +{ + objc_collect(OBJC_EXHAUSTIVE_COLLECTION); +} + +- (void) disable +{ + objc_gc_disable(); +} + +- (void) disableCollectorForPointer: (void *)ptr +{ + CFRetain(ptr); +} + +- (void) enable +{ + objc_gc_enable(); +} + +- (void) enableCollectorForPointer: (void *)ptr +{ + CFRelease(ptr); +} + +- (id) init +{ + if (self != collector) + { + [self dealloc]; + self = nil; + } + return self; +} + +- (BOOL) isCollecting +{ + return NO; +} + +- (BOOL) isEnabled +{ + return objc_collectingEnabled(); +} + +- (NSZone*) zone +{ + return NSDefaultMallocZone(); +} +@end + +#else + +static unsigned disabled = 0; #if GS_WITH_GC #include @@ -152,3 +235,4 @@ static NSHashTable *uncollectable = 0; } @end +#endif // __OBJC_GC__ diff --git a/Source/NSKeyValueObserving.m b/Source/NSKeyValueObserving.m index c060e2b24..87a85d520 100644 --- a/Source/NSKeyValueObserving.m +++ b/Source/NSKeyValueObserving.m @@ -1705,6 +1705,7 @@ replacementForClass(Class c) } pathInfo = [info lockReturningPathInfoForKey: aKey]; + //[pathInfo retain]; if (pathInfo != nil) { if (pathInfo->recursion == 1) @@ -1730,6 +1731,7 @@ replacementForClass(Class c) } [self didChangeValueForDependentsOfKey: aKey]; + //[pathInfo release]; } - (void) didChange: (NSKeyValueChange)changeKind diff --git a/Source/NSObject.m b/Source/NSObject.m index 11c83f943..4dd7a1bae 100644 --- a/Source/NSObject.m +++ b/Source/NSObject.m @@ -125,7 +125,7 @@ BOOL NSDeallocateZombies = NO; static Class zombieClass = Nil; static NSMapTable *zombieMap = 0; -#if !GS_WITH_GC +#if !GS_WITH_GC && !__OBJC_GC__ static void GSMakeZombie(NSObject *o) { Class c; @@ -414,7 +414,7 @@ typedef struct obj_layout *obj; BOOL NSDecrementExtraRefCountWasZero(id anObject) { -#if !GS_WITH_GC +#if !GS_WITH_GC && !__OBJC_GC__ if (double_release_check_enabled) { NSUInteger release_count; @@ -504,7 +504,7 @@ NSExtraRefCount(id anObject) inline void NSIncrementExtraRefCount(id anObject) { -#if GS_WITH_GC +#if GS_WITH_GC || __OBJC_GC__ return; #else /* GS_WITH_GC */ if (allocationLock != 0) @@ -594,7 +594,32 @@ callCXXConstructors(Class aClass, id anObject) * depending on what information (if any) we are storing before * the start of each object. */ -#if GS_WITH_GC +#if __OBJC_GC__ + +inline NSZone * +GSObjCZone(NSObject *object) +{ + return NSDefaultMallocZone(); +} + +inline id +NSAllocateObject(Class aClass, NSUInteger extraBytes, NSZone *zone) +{ + id new = class_createInstance(aClass, extraBytes); + if (0 == cxx_construct) + { + cxx_construct = sel_registerName(".cxx_construct"); + cxx_destruct = sel_registerName(".cxx_destruct"); + } + callCXXConstructors(aClass, new); + return new; +} + +inline void +NSDeallocateObject(id anObject) +{ +} +#elif GS_WITH_GC inline NSZone * GSObjCZone(NSObject *object) @@ -777,7 +802,7 @@ NSDeallocateObject(id anObject) BOOL NSShouldRetainWithZone (NSObject *anObject, NSZone *requestedZone) { -#if GS_WITH_GC +#if GS_WITH_GC || __OBJC_GC__ return YES; #else return (!requestedZone || requestedZone == NSDefaultMallocZone() @@ -1904,7 +1929,7 @@ objc_create_block_classes_as_subclasses_of(Class super); */ - (oneway void) release { -#if GS_WITH_GC == 0 +#if GS_WITH_GC == 0 && !__OBJC_GC__ if (NSDecrementExtraRefCountWasZero(self)) { [self dealloc]; @@ -1954,7 +1979,7 @@ objc_create_block_classes_as_subclasses_of(Class super); */ - (id) retain { -#if GS_WITH_GC == 0 +#if GS_WITH_GC == 0 && !__OBJC_GC__ NSIncrementExtraRefCount(self); #endif return self; diff --git a/Source/NSZone.m b/Source/NSZone.m index 041c8cb2e..f9aee896f 100644 --- a/Source/NSZone.m +++ b/Source/NSZone.m @@ -227,8 +227,100 @@ NSZoneName (NSZone *zone) zone = NSDefaultMallocZone(); return zone->name; } +#if __OBJC_GC__ -#if GS_WITH_GC +#include +void * +NSAllocateCollectable(NSUInteger size, NSUInteger options) +{ + return objc_gc_allocate_collectable(size, + ((options & NSScannedOption) == NSScannedOption)); +} + +void * +NSReallocateCollectable(void *ptr, NSUInteger size, NSUInteger options) +{ + return objc_gc_reallocate_collectable(ptr, size, + ((options & NSScannedOption) == NSScannedOption)); +} + +NSZone* +NSCreateZone (NSUInteger start, NSUInteger gran, BOOL canFree) +{ + NSLog(@" *** Creating a zone while running GC is ignored."); + return &default_zone; +} + +NSZone* +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) +{ + return &default_zone; +} + +void +NSRecycleZone (NSZone *zone) { } + +BOOL +NSZoneCheck (NSZone *zone) +{ + return YES; +} + +struct +NSZoneStats NSZoneStats (NSZone *zone) +{ + struct NSZoneStats stats = { 0 }; + return stats; +} + +void +GSMakeWeakPointer(Class theClass, const char *iVarName) { } + +BOOL +GSAssignZeroingWeakPointer(void **destination, void *source) +{ + objc_assign_weak(source, (id*)destination); + return YES; +} + +void* +NSZoneMalloc (NSZone *zone, NSUInteger size) +{ + return NSZoneCalloc(zone, 1, size); +} + +void* +NSZoneCalloc (NSZone *zone, NSUInteger elems, NSUInteger bytes) +{ + // FIXME: Overflow checking + size_t size = elems * bytes; + return objc_gc_allocate_collectable(size, YES); +} + +void* +NSZoneRealloc (NSZone *zone, void *ptr, NSUInteger size) +{ + return objc_gc_reallocate_collectable(ptr, size, YES); +} + +void NSZoneFree (NSZone *zone, void *ptr) { } + +#elif GS_WITH_GC #if defined(DEBUG) #define GC_DEBUG 1