diff --git a/Headers/gnustep/base/NSObject.h b/Headers/gnustep/base/NSObject.h index 7db548b59..ea9b5bf9a 100644 --- a/Headers/gnustep/base/NSObject.h +++ b/Headers/gnustep/base/NSObject.h @@ -192,6 +192,15 @@ extern NSRecursiveLock *gnustep_global_lock; - read: (TypedStream*)aStream; - write: (TypedStream*)aStream; @end + +/* + * Protocol for garbage collection finalization - same as libFoundation + * for compatibility. + */ +@protocol GCFinalization +- (void) gcFinalize; +@end + #endif #include @@ -210,8 +219,22 @@ extern NSRecursiveLock *gnustep_global_lock; /* * RETAIN(), RELEASE(), and AUTORELEASE() are placeholders for the - * (possible) future day when we have garbage collecting. + * future day when we have garbage collecting. */ +#ifndef GS_WITH_GC +#define GS_WITH_GC 0 +#endif +#if GS_WITH_GC + +#define RETAIN(object) ((id)object) +#define RELEASE(object) +#define AUTORELEASE(object) ((id)object) + +#define ASSIGN(object,value) (object = value) +#define DESTROY(object) (object = nil) + +#else + #define RETAIN(object) [object retain] #define RELEASE(object) [object release] #define AUTORELEASE(object) [object autorelease] @@ -241,5 +264,6 @@ if (value != object) \ * object later. */ #define DESTROY(object) ([object release], object = nil) +#endif #endif /* __NSObject_h_GNUSTEP_BASE_INCLUDE */ diff --git a/Headers/gnustep/base/NSZone.h b/Headers/gnustep/base/NSZone.h index e559dad96..30a8c991d 100644 --- a/Headers/gnustep/base/NSZone.h +++ b/Headers/gnustep/base/NSZone.h @@ -23,16 +23,12 @@ #ifndef __NSZone_h_GNUSTEP_BASE_INCLUDE #define __NSZone_h_GNUSTEP_BASE_INCLUDE - #include - @class NSString; - typedef struct _NSZone NSZone; - /* The members are the same as the structure mstats which is in the GNU C library. */ struct NSZoneStats @@ -60,19 +56,93 @@ struct _NSZone NSZone *next; }; +void *GSOutOfMemory(size_t size, BOOL retry); + +#ifndef GS_WITH_GC +#define GS_WITH_GC 0 +#endif +#if GS_WITH_GC + +#include + +extern inline NSZone* NSCreateZone (size_t start, size_t gran, BOOL canFree) +{ return 0; } + +extern inline NSZone* NSDefaultMallocZone (void) +{ return 0; } + +extern inline NSZone* NSZoneFromPointer (void *ptr) +{ return 0; } + +extern inline void* NSZoneMalloc (NSZone *zone, size_t size) +{ + void *ptr = (void*)GC_MALLOC(size); + + if (ptr == 0) + ptr = GSOutOfMemory(size, YES); + return ptr; +} + +extern inline void* NSZoneCalloc (NSZone *zone, size_t elems, size_t bytes) +{ + size_t size = elems * bytes; + void *ptr = (void*)GC_MALLOC(size); + + void *ptr = (void*)GC_MALLOC(size, YES); + if (ptr == 0) + ptr = GSOutOfMemory(size); + memset(ptr, '\0', size); + return ptr; +} + +extern inline void* NSZoneRealloc (NSZone *zone, void *ptr, size_t size) +{ + ptr = GC_REALLOC(ptr, size); + if (ptr == 0) + GSOutOfMemory(size, NO); + return ptr; +} + +extern inline void NSRecycleZone (NSZone *zone) +{ +} + +extern inline void NSZoneFree (NSZone *zone, void *ptr) +{ + GC_FREE(ptr); +} + +extern inline void NSSetZoneName (NSZone *zone, NSString *name) +{ +} + +extern inline NSString* NSZoneName (NSZone *zone) +{ + return nil; +} + +extern inline BOOL NSZoneCheck (NSZone *zone) +{ + return YES; +} + +extern inline struct NSZoneStats NSZoneStats (NSZone *zone) +{ + struct NSZoneStats stats = { 0 }; + return stats; +} + +#else /* GS_WITH_GC */ /* Default zone. Name is hopelessly long so that no one will ever want to use it. ;) Private variable. */ extern NSZone* __nszone_private_hidden_default_zone; - extern NSZone* NSCreateZone (size_t start, size_t gran, BOOL canFree); extern inline NSZone* NSDefaultMallocZone (void) { return __nszone_private_hidden_default_zone; } -extern void NSSetDefaultMallocZone (NSZone *zone); // Not in OpenStep - extern NSZone* NSZoneFromPointer (void *ptr); extern inline void* NSZoneMalloc (NSZone *zone, size_t size) @@ -108,4 +178,6 @@ extern inline struct NSZoneStats NSZoneStats (NSZone *zone) { if (!zone) zone = NSDefaultMallocZone(); return (zone->stats)(zone); } +#endif /* GS_WITH_GC */ + #endif /* not __NSZone_h_GNUSTEP_BASE_INCLUDE */ diff --git a/Source/NSObject.m b/Source/NSObject.m index d39424ad1..249d5d39c 100644 --- a/Source/NSObject.m +++ b/Source/NSObject.m @@ -100,8 +100,10 @@ void _fastBuildCache() * correct zone to free memory very fast. */ +#if GS_WITH_GC == 0 #define REFCNT_LOCAL 1 #define CACHE_ZONE 1 +#endif #if defined(REFCNT_LOCAL) || defined(CACHE_ZONE) @@ -140,6 +142,22 @@ typedef struct obj_layout *obj; #endif /* defined(REFCNT_LOCAL) || defined(CACHE_ZONE) */ +#if GS_WITH_GC + +void +NSIncrementExtraRefCount(id anObject) +{ +} +#define NSIncrementExtraRefCount(X) +BOOL +NSDecrementExtraRefCountWasZero(id anObject) +{ + return NO; +} +#define NSDecrementExtraRefCountWasZero(X) NO + +#else /* GS_WITH_GC */ + /* * Now do conditional compilation of reference count functions * depending on whether we are using local or global counting. @@ -226,12 +244,72 @@ extraRefCount (id anObject) #endif /* defined(REFCNT_LOCAL) */ +#endif /* GS_WITH_GC */ + /* * Now do conditional compilation of memory allocation functions * depending on what information (if any) we are storing before * the start of each object. */ +#if GS_WITH_GC + +inline NSZone * +fastZone(NSObject *object) +{ + return 0; +} + +static void +GSFinalize(void* object, void* data) +{ + [(id)object gcFinalize]; + + /* Set the class of anObject to FREED_OBJECT. The further messages to this + object will cause an error to occur. */ + ((id)object)->class_pointer = __freedObjectClass; + +#ifndef NDEBUG + GSDebugAllocationRemove(((id)object)->class_pointer); +#endif + ((id)object)->class_pointer = (void*) 0xdeadface; +} + +inline NSObject * +NSAllocateObject (Class aClass, unsigned extraBytes, NSZone *zone) +{ + id new = nil; + int size = aClass->instance_size + extraBytes; + if (CLS_ISCLASS (aClass)) + new = NSZoneMalloc (zone, size); + if (new != nil) + { + memset (new, 0, size); + new->class_pointer = aClass; + } + if ([new respondsToSelector: @selector(gcFinalize)]) + { +#ifndef NDEBUG + /* + * We only do allocation counting for objects that can be + * finalised - for other objects we have no way of decrementing + * the count when the object is collected. + */ + GSDebugAllocationAdd(aClass); +#endif + GC_REGISTER_FINALIZER (new, GSFinalize, NULL, NULL, NULL); + } + + return new; +} + +inline void +NSDeallocateObject(NSObject *anObject) +{ +} + +#else /* GS_WITH_GC */ + #if defined(REFCNT_LOCAL) || defined(CACHE_ZONE) #if defined(CACHE_ZONE) @@ -239,9 +317,9 @@ extraRefCount (id anObject) inline NSZone * fastZone(NSObject *object) { - if (fastClass(object) == _fastCls._NXConstantString) - return NSDefaultMallocZone(); - return ((obj)object)[-1].zone; + if (fastClass(object) == _fastCls._NXConstantString) + return NSDefaultMallocZone(); + return ((obj)object)[-1].zone; } #else /* defined(CACHE_ZONE) */ @@ -249,9 +327,9 @@ fastZone(NSObject *object) inline NSZone * fastZone(NSObject *object) { - if (fastClass(object) == _fastCls._NXConstantString) - return NSDefaultMallocZone(); - return NSZoneFromPointer(&((obj)object)[-1]); + if (fastClass(object) == _fastCls._NXConstantString) + return NSDefaultMallocZone(); + return NSZoneFromPointer(&((obj)object)[-1]); } #endif /* defined(CACHE_ZONE) */ @@ -345,11 +423,17 @@ NSDeallocateObject(NSObject *anObject) #endif /* defined(REFCNT_LOCAL) || defined(CACHE_ZONE) */ +#endif /* GS_WITH_GC */ + BOOL NSShouldRetainWithZone (NSObject *anObject, NSZone *requestedZone) { - return (!requestedZone || requestedZone == NSDefaultMallocZone() +#if GS_WITH_GC + return YES; +#else + return (!requestedZone || requestedZone == NSDefaultMallocZone() || fastZone(anObject) == requestedZone); +#endif } @@ -630,6 +714,7 @@ static BOOL double_release_check_enabled = NO; - autorelease { +#if GS_WITH_GC == 0 if (double_release_check_enabled) { unsigned release_count; @@ -643,6 +728,7 @@ static BOOL double_release_check_enabled = NO; } (*autorelease_imp)(autorelease_class, autorelease_sel, self); +#endif return self; } @@ -781,6 +867,7 @@ static BOOL double_release_check_enabled = NO; - (oneway void) release { +#if GS_WITH_GC == 0 if (double_release_check_enabled) { unsigned release_count; @@ -793,7 +880,7 @@ static BOOL double_release_check_enabled = NO; if (NSDecrementExtraRefCountWasZero(self)) [self dealloc]; - return; +#endif } + (oneway void) release @@ -815,7 +902,9 @@ static BOOL double_release_check_enabled = NO; - retain { +#if GS_WITH_GC == 0 NSIncrementExtraRefCount(self); +#endif return self; } @@ -826,7 +915,11 @@ static BOOL double_release_check_enabled = NO; - (unsigned) retainCount { +#if GS_WITH_GC + return UINT_MAX; +#else return extraRefCount(self) + 1; +#endif } + (unsigned) retainCount diff --git a/Source/NSZone.m b/Source/NSZone.m index 2e8b6473a..8eefda344 100644 --- a/Source/NSZone.m +++ b/Source/NSZone.m @@ -92,6 +92,22 @@ #include +/* + * Try to get more memory - the normal process has failed. + * If we can't do anything, bomb out. + */ +void * +GSOutOfMemory(size_t size, BOOL retry) +{ + /* + * It would be nice to raise an exception - but how can we if there is + * no memory available? + */ + abort(); +} + +#if GS_WITH_GC == 0 + /* Alignment */ #define ALIGN ((__alignof__(double) < 8) ? 8 : __alignof__(double)) #define MINGRAN 256 /* Minimum granularity. */ @@ -1659,13 +1675,6 @@ NSDefaultMallocZone (void) return __nszone_private_hidden_default_zone; } -/* Not in OpenStep. */ -void -NSSetDefaultMallocZone (NSZone *zone) -{ - __nszone_private_hidden_default_zone = zone; -} - inline void* NSZoneMalloc (NSZone *zone, size_t size) { @@ -1743,3 +1752,6 @@ NSZoneStats (NSZone *zone) zone = NSDefaultMallocZone(); return (zone->stats)(zone); } + +#endif /* GS_WITH_GC */ +