garbage collecting fixes

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@27638 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Richard Frith-MacDonald 2009-01-20 10:15:52 +00:00
parent d8cf9c2d35
commit e82bd33ab1
6 changed files with 275 additions and 156 deletions

View file

@ -159,7 +159,11 @@ static SEL objSel;
[aCoder decodeValueOfObjCType: @encode(unsigned)
at: &count];
#if GS_WITH_GC
GSIMapInitWithZoneAndCapacity(&map, GSScannedMallocZone(), count);
#else
GSIMapInitWithZoneAndCapacity(&map, GSObjCZone(self), count);
#endif
while (count-- > 0)
{
(*imp)(aCoder, sel, type, &key);
@ -175,7 +179,12 @@ static SEL objSel;
{
unsigned int i;
#if GS_WITH_GC
GSIMapInitWithZoneAndCapacity(&map, GSScannedMallocZone(), c);
#else
GSIMapInitWithZoneAndCapacity(&map, GSObjCZone(self), c);
#endif
for (i = 0; i < c; i++)
{
GSIMapNode node;
@ -214,9 +223,14 @@ static SEL objSel;
- (id) initWithDictionary: (NSDictionary*)other
copyItems: (BOOL)shouldCopy
{
NSZone *z = GSObjCZone(self);
NSZone *z;
unsigned c = [other count];
#if GS_WITH_GC
z = GSScannedMallocZone();
#else
z = GSObjCZone(self);
#endif
GSIMapInitWithZoneAndCapacity(&map, z, c);
if (c > 0)
@ -369,7 +383,11 @@ static SEL objSel;
/* Designated initialiser */
- (id) initWithCapacity: (unsigned)cap
{
#if GS_WITH_GC
GSIMapInitWithZoneAndCapacity(&map, GSScannedMallocZone(), cap);
#else
GSIMapInitWithZoneAndCapacity(&map, GSObjCZone(self), cap);
#endif
return self;
}

View file

@ -138,7 +138,7 @@ static inline void setup()
@interface GSKVOObservation : NSObject
{
@public
NSObject *observer; // Not retained
NSObject *observer; // Not retained (zeroing weak pointer)
void *context;
int options;
}
@ -586,7 +586,8 @@ replacementForClass(Class c)
if (!found)
{
NSDebugLLog(@"KVC", @"class %@ not KVC complient for %@", original, aKey);
NSDebugLLog(@"KVC", @"class %@ not KVC complient for %@",
original, aKey);
/*
[NSException raise: NSInvalidArgumentException
format: @"class not KVC complient for %@", aKey];
@ -804,6 +805,12 @@ replacementForClass(Class c)
@implementation GSKVOObservation
#if GS_WITH_GC
+ (void) initialize
{
GSMakeWeakPointer(self, "observer");
}
#endif
@end
@implementation GSKVOPathInfo
@ -956,17 +963,26 @@ replacementForClass(Class c)
o = [pathInfo->observations objectAtIndex: count];
if (o->observer == anObserver)
{
o->observer = anObserver;
o->context = aContext;
o->options = options;
observation = o;
}
#if GS_WITH_GC
else if (o->observer == nil)
{
/* The observer for thsi observation must have been collected.
*/
[pathInfo->observations removeObjectAtIndex: count];
continue;
}
#endif
pathInfo->allOptions |= o->options;
}
if (observation == nil)
{
observation = [GSKVOObservation new];
observation->observer = anObserver;
GSAssignZeroingWeakPointer((void**)&observation->observer,
(void*)anObserver);
observation->context = aContext;
observation->options = options;
[pathInfo->observations addObject: observation];
@ -1050,7 +1066,7 @@ replacementForClass(Class c)
GSKVOObservation *o;
o = [pathInfo->observations objectAtIndex: count];
if (o->observer == anObserver)
if (o->observer == anObserver || o->observer == nil)
{
[pathInfo->observations removeObjectAtIndex: count];
if ([pathInfo->observations count] == 0)
@ -1088,6 +1104,14 @@ replacementForClass(Class c)
context = o->context;
break;
}
#if GS_WITH_GC
else if (o->observer == nil)
{
/* The observer for thsi observation must have been collected.
*/
[pathInfo->observations removeObjectAtIndex: count];
}
#endif
}
}
[iLock unlock];

View file

@ -41,7 +41,6 @@
* a collected observer removed.
*/
#if GS_WITH_GC
#include <gc.h>
#define purgeCollected(X) (X = listPurge(X, nil))
#else
#define purgeCollected(X) (X)
@ -437,7 +436,7 @@ static void obsFree(Observation *o)
NCTable *t = o->link;
#if GS_WITH_GC
GC_unregister_disappearing_link((GC_PTR*)&o->observer);
GSAssignZeroingWeakPointer((void**)&o->observer, 0);
#endif
o->link = (NCTable*)t->freeList;
t->freeList = o;
@ -705,23 +704,14 @@ static NSNotificationCenter *default_center = nil;
o = obsNew(TABLE);
o->selector = selector;
o->method = method;
#if GS_WITH_GC
GSAssignZeroingWeakPointer((void**)&o->observer, (void*)observer);
#else
o->observer = observer;
#endif
o->retained = 0;
o->next = 0;
#if GS_WITH_GC
/* Ensure that if the observer is garbage collected, we clear the
* oservation so that we don't end up sending notifications to the
* deallocated object.
* The observer must be a real GC-allocated object or this mechanism
* can't be used.
*/
if (GC_base(observer) != 0)
{
GC_general_register_disappearing_link((GC_PTR*)&o->observer, observer);
}
#endif
if (object != nil)
{
object = CHEATGC(object);

View file

@ -1837,14 +1837,8 @@ NSReallocateCollectable(void *ptr, NSUInteger size, NSUInteger options)
#define GS_ZONE_ATTR __attribute__((unused))
#endif
#ifndef GS_WITH_GC
#define GS_WITH_GC 0
#endif
#if GS_WITH_GC
#include <gc.h>
NSZone*
NSCreateZone (size_t start, size_t gran, BOOL canFree)
{
@ -1875,76 +1869,11 @@ NSZoneFromPointer (void *ptr)
return &default_zone;
}
void*
NSZoneMalloc (NSZone *zone, size_t size)
{
void *ptr;
if (zone == GSAtomicMallocZone())
ptr = (void*)GC_MALLOC_ATOMIC(size);
else if (zone == GSScannedMallocZone())
ptr = (void*)GC_MALLOC(size);
else
ptr = (void*)malloc(size);
if (ptr == 0)
ptr = GSOutOfMemory(size, YES);
return ptr;
}
void*
NSZoneCalloc (NSZone *zone, size_t elems, size_t bytes)
{
size_t size = elems * bytes;
void *ptr;
if (zone == &atomic_zone)
ptr = (void*)GC_MALLOC_ATOMIC(size);
else if (zone == &scanned_zone)
ptr = (void*)GC_MALLOC(size);
else
ptr = (void*)malloc(size);
if (ptr == 0)
ptr = GSOutOfMemory(size, NO);
memset(ptr, '\0', size);
return ptr;
}
void*
NSZoneRealloc (NSZone *zone, void *ptr, size_t size)
{
if (GC_base(ptr) != 0)
{
ptr = GC_REALLOC(ptr, size);
}
else
{
ptr = realloc(ptr, size);
}
if (ptr == 0)
GSOutOfMemory(size, NO);
return ptr;
}
void
NSRecycleZone (NSZone *zone)
{
}
void
NSZoneFree (NSZone *zone, void *ptr)
{
if (GC_base(ptr) != 0)
{
GC_FREE(ptr);
}
else
{
free(ptr);
}
}
void
NSSetZoneName (NSZone *zone, NSString *name)
{
@ -1969,6 +1898,101 @@ NSZoneStats NSZoneStats (NSZone *zone)
return stats;
}
void
GSMakeWeakPointer(Class class, const char *iVarName)
{
class_ivar_set_gcinvisible(class, iVarName, YES);
}
#include <gc.h>
BOOL
GSAssignZeroingWeakPointer(void **destination, void *source)
{
if (GC_base(destination) == 0)
{
return NO; // Destination is not in garbage collection system.
}
if (*destination == source)
{
return YES; // Already assigned.
}
if (source != 0 && GC_base(source) == 0)
{
return NO; // Source is not garbage collectable.
}
if (*destination != 0)
{
GC_unregister_disappearing_link((GC_PTR*)destination);
}
*destination = source;
GC_general_register_disappearing_link((GC_PTR*)destination, source);
return YES;
}
void*
NSZoneMalloc (NSZone *zone, size_t size)
{
return NSZoneCalloc(zone, 1, size);
}
void*
NSZoneCalloc (NSZone *zone, size_t elems, size_t bytes)
{
size_t size = elems * bytes;
void *ptr;
if (zone == &atomic_zone)
{
ptr = (void*)GC_MALLOC_ATOMIC(size);
}
else if (zone == &scanned_zone)
{
ptr = (void*)GC_MALLOC(size);
}
else
{
ptr = (void*)malloc(size);
if (ptr == 0)
{
ptr = GSOutOfMemory(size, NO);
}
if (ptr != 0)
{
memset(ptr, '\0', size);
}
}
return ptr;
}
void*
NSZoneRealloc (NSZone *zone, void *ptr, size_t size)
{
if (GC_base(ptr) != 0)
{
ptr = GC_REALLOC(ptr, size);
}
else
{
ptr = realloc(ptr, size);
}
return ptr;
}
void
NSZoneFree (NSZone *zone, void *ptr)
{
if (GC_base(ptr) != 0)
{
GC_FREE(ptr);
}
else
{
free(ptr);
}
}
#else /* GS_WITH_GC */
NSZone*
@ -1989,6 +2013,23 @@ GSScannedMallocZone (void)
return &default_zone;
}
void
GSMakeWeakPointer(Class class, const char *iVarName)
{
return;
}
BOOL
GSAssignZeroingWeakPointer(void **destination, void *source)
{
if (destination == 0)
{
return NO;
}
*destination = source;
return YES;
}
void*
NSZoneMalloc (NSZone *zone, size_t size)
{