diff --git a/ChangeLog b/ChangeLog index cd6c92b2a..f08736dec 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,7 +1,31 @@ +2009-04-13 Richard Frith-Macdonald + + * Source/GSString.m: Change placeholder string initialisation so that, + in a GC world, it checks to see if the buffer passed to it is + collectable and forces a copy if it isn't. This prevents memory leaks + when a malloc'ed buffer is passed to the initialiser. + +2009-04-11 Richard Frith-Macdonald + + * Source/GSPrivate.h: New private functions. + * Source/NSObject.m: Add function to swizzle isa pointer safely. + * Source/NSZone.m: Add function to check for collectable memory. + * Source/NSData.m: Add finalisation for shared memory and mapped + files. Add finalized subclasses to deal with memory which must be + freed when the NSData is collected. + 2009-04-11 01:12-EDT Gregory John Casamento * Source/NSLock.m: Move the warning to a debug log. +2009-04-10 Richard Frith-Macdonald + + * Source/cifframe.m: + * Source/callrame.m: + Update for GC to use scanned memory to hold pointers we got from + the stack so that memory will persist as long as the invocation + needs it. + 2009-04-10 Richard Frith-Macdonald * Source/GSPrivate.h: diff --git a/Headers/Foundation/NSHashTable.h b/Headers/Foundation/NSHashTable.h index 66669bc55..b0a8dce89 100644 --- a/Headers/Foundation/NSHashTable.h +++ b/Headers/Foundation/NSHashTable.h @@ -31,16 +31,123 @@ /**** Included Headers *******************************************************/ -#import +#import +#import #import -#import #if defined(__cplusplus) extern "C" { #endif +#if 0 +@class NSArray, NSSet, NSHashTable; + /**** Type, Constant, and Macro Definitions **********************************/ +enum { + NSHashTableStrongMemory + = NSPointerFunctionsStrongMemory, + NSHashTableZeroingWeakMemory + = NSPointerFunctionsZeroingWeakMemory, + NSHashTableCopyIn + = NSPointerFunctionsCopyIn, + NSHashTableObjectPointerPersonality + = NSPointerFunctionsObjectPointerPersonality, +}; + +typedef NSUInteger NSHashTableOptions; + +@interface NSHashTable : NSObject + ++ (id) hashTableWithOptions: (NSPointerFunctionsOptions)options; + ++ (id) hashTableWithWeakObjects; + +- (id) initWithOptions: (NSPointerFunctionsOptions)options + capacity: (NSUInteger)initialCapacity; + +- (id) initWithPointerFunctions: (NSPointerFunctions*)functions + capacity: (NSUInteger)initialCapacity; + +/** Adds the object to the receiver. + */ +- (void) addObject: (id)object; + +/** Returns an array containing all objects in the receiver. + */ +- (NSArray*) allObjects; + +/** Returns any objct from the receiver, or nil if the receiver contains no + * objects. + */ +- (id) anyObject; + +/** Returns YES if the receiver contains an item equal to anObject, or NO + * otherwise. + */ +- (BOOL) containsObject: (id)anObject; + +/** Return the number of items atored in the receiver. + */ +- (NSUInteger) count; + +/** Removes from the receiver any items which are not also present in 'other'. + */ +- (void) intersectHashTable: (NSHashTable*)other; + +/** Returns YES if the receiver and 'other' contain any items in common. + */ +- (BOOL) intersectsHashTable: (NSHashTable*)other; + +/** Returns YES if the receiver and 'other' contain equal sets of items. + */ +- (BOOL) isEqualToHashTable: (NSHashTable*)other; + +/** Returns YES fi all the items in the receiver are also present in 'other' + */ +- (BOOL) isSubsetOfHashTable: (NSHashTable*)other; + +/** Returns an item stored in the receiver which is equal to the supplied + * object argument, or nil if no matchi is found. + */ +- (id) member: (id)object; + +/** Removes from the receivr all those items which are prsent in both + * the receiver and in 'other'. + */ +- (void) minusHashTable: (NSHashTable*)other; + +/** Return an enumerator for the receiver. + */ +- (NSEnumerator*) objectEnumerator; + +/** Return an NSPointerFunctions value describing the functions used by the + * receiver to handle its contents. + */ +- (NSPointerFunctions*) pointerFunctions; + +/** Removes all objects. + */ +- (void) removeAllObjects; + +/** Remove the object (or any equal object) from the receiver. + */ +- (void) removeObject: (id)object; + +/** Returns a set containing all the objects in the receiver. + */ +- (NSSet*) setRepresentation; + +/** Adds to the receiver thse items present in 'other' which were + * not present in the receiver. + */ +- (void) unionHashTable: (NSHashTable*)other; + + +@end + +#endif + /** * Hash table type ... an opaque pointer to a data structure. */ diff --git a/Headers/Foundation/NSZone.h b/Headers/Foundation/NSZone.h index f986578b6..527b16f11 100644 --- a/Headers/Foundation/NSZone.h +++ b/Headers/Foundation/NSZone.h @@ -62,28 +62,6 @@ typedef struct _NSZone NSZone; extern "C" { #endif -/** - * Primary structure representing an NSZone. Technically it - * consists of a set of function pointers for zone upkeep functions plus some - * other things- - -{ - // Functions for zone. - void *(*malloc)(struct _NSZone *zone, size_t size); - void *(*realloc)(struct _NSZone *zone, void *ptr, size_t size); - void (*free)(struct _NSZone *zone, void *ptr); - void (*recycle)(struct _NSZone *zone); - BOOL (*check)(struct _NSZone *zone); - BOOL (*lookup)(struct _NSZone *zone, void *ptr); - - // Zone statistics (not always maintained). - struct NSZoneStats (*stats)(struct _NSZone *zone); - - size_t gran; // Zone granularity (passed in on initialization) - NSString *name; // Name of zone (default is 'nil') - NSZone *next; // Pointer used for internal management of multiple zones. -} -*/ struct _NSZone { /* Functions for zone. */ @@ -100,41 +78,68 @@ struct _NSZone NSZone *next; }; +/** + * Creates a new zone of start bytes, which will grow and shrink by + * granularity bytes. If canFree is 0, memory in zone is allocated but + * never freed, meaning allocation will be very fast. The whole zone can + * still be freed with NSRecycleZone(), and you should still call NSZoneFree + * on memory in the zone that is no longer needed, since a count of allocated + * pointers is kept and must reach zero before freeing the zone.
+ * If Garbage Collection is enabled, this function does nothing other than + * log a warning and return the same value as the NSDefaultMallocZone() + * function. + */ GS_EXPORT NSZone* NSCreateZone (NSUInteger start, NSUInteger gran, BOOL canFree); +/** Returns the default zone for memory allocation. Memory created in this + * zone is the same as memory allocates using the system malloc() function. + */ GS_EXPORT NSZone* NSDefaultMallocZone (void); +/** + * Searches and finds the zone ptr was allocated from. The speed depends + * upon the number of zones and their size.
+ * If Garbage Collection is enabled, this function always returns the + * same as the NSDefaultMallocZone() function. + */ GS_EXPORT NSZone* NSZoneFromPointer (void *ptr); /** - * Allocates and returns memory for elems items of size bytes, in the - * given zone. Returns NULL if allocation of size 0 requested. Raises - * NSMallocException if not enough free memory in zone to - * allocate and no more can be obtained from system, unless using the - * default zone, in which case NULL is returned. + * Allocates and returns memory for elems items of size bytes, in the + * given zone. Returns NULL if allocation of size 0 requested. Raises + * NSMallocException if not enough free memory in zone to + * allocate and no more can be obtained from system, unless using the + * default zone, in which case NULL is returned.
+ * If Garbage Collection is enabled, this function always allocates + * non-scanned, non-collectable memory in the NSDefaultMallocZone() and + * the zone argument is ignored. */ GS_EXPORT void* NSZoneMalloc (NSZone *zone, NSUInteger size); /** - * Allocates and returns cleared memory for elems items of size bytes, in the - * given zone. Returns NULL if allocation of size 0 requested. Raises - * NSMallocException if not enough free memory in zone to - * allocate and no more can be obtained from system, unless using the - * default zone, in which case NULL is returned. + * Allocates and returns cleared memory for elems items of size bytes, in the + * given zone. Returns NULL if allocation of size 0 requested. Raises + * NSMallocException if not enough free memory in zone to + * allocate and no more can be obtained from system, unless using the + * default zone, in which case NULL is returned.
+ * If Garbage Collection is enabled, this function always allocates + * non-scanned, non-collectable memory in the NSDefaultMallocZone() and + * the zone argument is ignored. */ GS_EXPORT void* NSZoneCalloc (NSZone *zone, NSUInteger elems, NSUInteger bytes); /** - * Reallocates the chunk of memory in zone pointed to by ptr to a new one of - * size bytes. Existing contents in ptr are copied over. Raises an - * NSMallocException if insufficient memory is available in the - * zone and no more memory can be obtained from the system, unless using the - * default zone, in which case NULL is returned. + * Reallocates the chunk of memory in zone pointed to by ptr to a new one of + * size bytes. Existing contents in ptr are copied over. Raises an + * NSMallocException if insufficient memory is available in the + * zone and no more memory can be obtained from the system, unless using the + * default zone, in which case NULL is returned.
+ * If Garbage Collection is enabled, the zone argument is ignored. */ GS_EXPORT void* NSZoneRealloc (NSZone *zone, void *ptr, NSUInteger size); @@ -144,7 +149,8 @@ NSZoneRealloc (NSZone *zone, void *ptr, NSUInteger size); * unless all memory in the zone has been explicitly freed (by calls to * NSZoneFree()). For "non-freeable" zones, the number of NSZoneFree() calls * must simply equal the number of allocation calls. The default zone, on the - * other hand, cannot be recycled. + * other hand, cannot be recycled.
+ * If Garbage Collection is enabled, this function has not effect. */ GS_EXPORT void NSRecycleZone (NSZone *zone); @@ -153,7 +159,9 @@ NSRecycleZone (NSZone *zone); * Frees memory pointed to by ptr (which should have been allocated by a * previous call to NSZoneMalloc(), NSZoneCalloc(), or NSZoneRealloc()) and * returns it to zone. Note, if this is a nonfreeable zone, the memory is - * not actually freed, but the count of number of free()s is updated. + * not actually freed, but the count of number of free()s is updated.
+ * If Garbage Collection is enabled, the zone argument is ignored and this + * function causes ptr to be deallocated immediately. */ GS_EXPORT void NSZoneFree (NSZone *zone, void *ptr); @@ -165,7 +173,7 @@ GS_EXPORT void NSSetZoneName (NSZone *zone, NSString *name); /** - * Sets name of the given zone (useful for debugging and logging). + * Returns the name of the given zone (useful for debugging and logging). */ GS_EXPORT NSString* NSZoneName (NSZone *zone); diff --git a/Source/GSPrivate.h b/Source/GSPrivate.h index 3de3ebe3e..ccc9cadeb 100644 --- a/Source/GSPrivate.h +++ b/Source/GSPrivate.h @@ -501,7 +501,7 @@ GSPrivateUnloadModule(FILE *errorStream, void (*unloadCallback)(Class, struct objc_category *)) GS_ATTRIB_PRIVATE; -/* Memory to use to put executabel code in. +/* Memory to use to put executable code in. */ @interface GSCodeBuffer : NSObject { @@ -514,6 +514,15 @@ GSPrivateUnloadModule(FILE *errorStream, - (void) protect; @end +/* Function to safely change the class of an object by 'isa' swizzling + * wile maintaining allocation accounting and finalization in a GC world. + */ +void +GSPrivateSwizzle(id o, Class c) GS_ATTRIB_PRIVATE; + +BOOL +GSPrivateIsCollectable(const void *ptr) GS_ATTRIB_PRIVATE; + NSZone* GSAtomicMallocZone (void); diff --git a/Source/GSString.m b/Source/GSString.m index ffa9f734d..94ad276fa 100644 --- a/Source/GSString.m +++ b/Source/GSString.m @@ -592,8 +592,26 @@ fixBOM(unsigned char **bytes, NSUInteger*length, BOOL *owned, } } + if (encoding == internalEncoding) { +#if GS_WITH_GC + /* If we are using GC, copy and free any non-collectable buffer so + * we don't leak memory. + */ + if (GSPrivateIsCollectable(chars.c) == NO) + { + me = (GSStr)NSAllocateObject(GSCInlineStringClass, length, + GSObjCZone(self)); + me->_contents.c = (unsigned char*)&((GSCInlineString*)me)[1]; + me->_count = length; + me->_flags.wide = 0; + me->_flags.owned = 1; // Ignored on dealloc, but means we own buffer + memcpy(me->_contents.c, chars.c, length); + NSZoneFree(NSZoneFromPointer(chars.c), chars.c); + return (id)me; + } +#endif me = (GSStr)NSAllocateObject(GSCBufferStringClass, 0, GSObjCZone(self)); me->_contents.c = chars.c; me->_count = length; @@ -658,6 +676,23 @@ fixBOM(unsigned char **bytes, NSUInteger*length, BOOL *owned, } else { +#if GS_WITH_GC + /* If we are using GC, copy and free any non-collectable buffer so + * we don't leak memory. + */ + if (GSPrivateIsCollectable(chars.u) == NO) + { + me = (GSStr)NSAllocateObject(GSUnicodeInlineStringClass, length, + GSObjCZone(self)); + me->_contents.u = (unichar*)&((GSUnicodeInlineString*)me)[1]; + me->_count = length; + me->_flags.wide = 1; + me->_flags.owned = 1; // Ignored on dealloc, but means we own buffer + memcpy(me->_contents.u, chars.u, length * sizeof(unichar)); + NSZoneFree(NSZoneFromPointer(chars.u), chars.u); + return (id)me; + } +#endif me = (GSStr)NSAllocateObject(GSUnicodeBufferStringClass, 0, GSObjCZone(self)); me->_contents.u = chars.u; diff --git a/Source/NSData.m b/Source/NSData.m index cc6e9e591..aaf2d29c7 100644 --- a/Source/NSData.m +++ b/Source/NSData.m @@ -51,9 +51,11 @@ * NSDataMalloc Concrete class. * NSDataMappedFile Memory mapped files. * NSDataShared Extension for shared memory. + * NSDataFinalized For GC of non-GC data. * NSMutableData Abstract base class. * NSMutableDataMalloc Concrete class. * NSMutableDataShared Extension for shared memory. + * NSDataMutableFinalized For GC of non-GC data. * * NSMutableDataMalloc MUST share it's initial instance variable layout * with NSDataMalloc so that it can use the 'behavior' code to inherit @@ -113,17 +115,20 @@ #endif @class NSDataMalloc; +@class NSDataFinalized; @class NSDataStatic; @class NSMutableDataMalloc; +@class NSMutableDataFinalized; /* * Some static variables to cache classes and methods for quick access - * these are set up at process startup or in [NSData +initialize] */ -static SEL appendSel; static Class dataStatic; static Class dataMalloc; +static Class dataFinalized; static Class mutableDataMalloc; +static Class mutableDataFinalized; static Class NSDataAbstract; static Class NSMutableDataAbstract; static SEL appendSel; @@ -294,19 +299,23 @@ failure: void *bytes; } @end + @interface NSDataEmpty: NSDataStatic @end @interface NSDataMalloc : NSDataStatic -{ -} +@end + +@interface NSDataFinalized : NSDataMalloc @end @interface NSMutableDataMalloc : NSMutableData { NSUInteger length; void *bytes; -#if !GS_WITH_GC +#if GS_WITH_GC + BOOL owned; +#else NSZone *zone; #endif NSUInteger capacity; @@ -316,6 +325,9 @@ failure: - (void) _grow: (NSUInteger)minimum; @end +@interface NSMutableDataFinalized : NSMutableDataMalloc +@end + #ifdef HAVE_MMAP @interface NSDataMappedFile : NSDataMalloc @end @@ -357,9 +369,11 @@ failure: { NSDataAbstract = self; NSMutableDataAbstract = [NSMutableData class]; - dataMalloc = [NSDataMalloc class]; dataStatic = [NSDataStatic class]; + dataMalloc = [NSDataMalloc class]; + dataFinalized = [NSDataFinalized class]; mutableDataMalloc = [NSMutableDataMalloc class]; + mutableDataFinalized = [NSMutableDataFinalized class]; appendSel = @selector(appendBytes:length:); appendImp = [mutableDataMalloc instanceMethodForSelector: appendSel]; } @@ -386,7 +400,7 @@ failure: if (empty == nil) { - empty = [NSDataEmpty allocWithZone: NSDefaultMallocZone()]; + empty = [dataStatic allocWithZone: NSDefaultMallocZone()]; empty = [empty initWithBytesNoCopy: 0 length: 0 freeWhenDone: NO]; } return empty; @@ -2924,20 +2938,29 @@ getBytes(void* dst, void* src, unsigned len, unsigned limit, unsigned *pos) { if (shouldFree == NO) { -#ifndef NDEBUG - GSDebugAllocationRemove(self->isa, self); -#endif - self->isa = dataStatic; -#ifndef NDEBUG - GSDebugAllocationAdd(self->isa, self); -#endif + GSPrivateSwizzle(self, dataStatic); } +#if GS_WITH_GC + else if (aBuffer != 0 && GSPrivateIsCollectable(aBuffer) == NO) + { + GSPrivateSwizzle(self, dataFinalized); + } +#endif bytes = aBuffer; length = bufferSize; return self; } @end + +@implementation NSDataFinalized +- (void) finalize +{ + NSZoneFree(NSDefaultMallocZone(), bytes); + [super finalize]; +} +@end + #ifdef HAVE_MMAP @implementation NSDataMappedFile @@ -2947,13 +2970,19 @@ getBytes(void* dst, void* src, unsigned len, unsigned limit, unsigned *pos) } - (void) dealloc +{ + [self finalize]; + [super dealloc]; +} + +- (void) finalize { if (bytes != 0) { munmap(bytes, length); bytes = 0; } - [super dealloc]; + [super finalize]; } /** @@ -3196,10 +3225,18 @@ getBytes(void* dst, void* src, unsigned len, unsigned limit, unsigned *pos) } return self; } +#if GS_WITH_GC + if (shouldFree == YES && GSPrivateIsCollectable(aBuffer) == NO) + { + GSPrivateSwizzle(self, mutableDataFinalized); + } +#endif self = [self initWithCapacity: 0]; if (self) { -#if !GS_WITH_GC +#if GS_WITH_GC + owned = shouldFree; // Free memory on finalisation. +#else if (shouldFree == NO) { zone = 0; // Don't free this memory. @@ -3655,7 +3692,13 @@ getBytes(void* dst, void* src, unsigned len, unsigned limit, unsigned *pos) if (bytes) { memcpy(tmp, bytes, capacity < size ? capacity : size); -#if !GS_WITH_GC +#if GS_WITH_GC + if (owned == YES) + { + NSZoneFree(NSDefaultMallocZone(), bytes); + owned = NO; + } +#else if (zone == 0) { zone = NSDefaultMallocZone(); @@ -3705,6 +3748,15 @@ getBytes(void* dst, void* src, unsigned len, unsigned limit, unsigned *pos) @end +@implementation NSMutableDataFinalized +- (void) finalize +{ + if (owned == YES) + NSZoneFree(NSDefaultMallocZone(), bytes); + [super finalize]; +} +@end + #ifdef HAVE_SHMCTL @implementation NSMutableDataShared @@ -3714,6 +3766,12 @@ getBytes(void* dst, void* src, unsigned len, unsigned limit, unsigned *pos) } - (void) dealloc +{ + [self finalize]; + [super dealloc]; +} + +- (void) finalize { if (bytes != 0) { @@ -3742,7 +3800,7 @@ getBytes(void* dst, void* src, unsigned len, unsigned limit, unsigned *pos) capacity = 0; shmid = -1; } - [super dealloc]; + [super finalize]; } - (id) initWithBytes: (const void*)aBuffer length: (NSUInteger)bufferSize diff --git a/Source/NSObject.m b/Source/NSObject.m index 56645cbcd..916a38444 100644 --- a/Source/NSObject.m +++ b/Source/NSObject.m @@ -484,6 +484,13 @@ NSIncrementExtraRefCount(id anObject) #endif /* GS_WITH_GC */ } +#ifndef NDEBUG +#define AADD(c, o) GSDebugAllocationAdd(c, o) +#define AREM(c, o) GSDebugAllocationRemove(c, o) +#else +#define AADD(c, o) +#define AREM(c, o) +#endif /* * Now do conditional compilation of memory allocation functions @@ -504,12 +511,49 @@ static void GSFinalize(void* object, void* data) { [(id)object finalize]; -#ifndef NDEBUG - GSDebugAllocationRemove(((id)object)->class_pointer, (id)object); -#endif + AREM(((id)object)->class_pointer, (id)object); ((id)object)->class_pointer = (void*)0xdeadface; } +static BOOL +GSIsFinalizable(Class c) +{ + if (get_imp(c, finalize_sel) != finalize_imp) + return YES; + return NO; +} + +void +GSPrivateSwizzle(id o, Class c) +{ + if (o->class_pointer != c) + { +#if GS_WITH_GC + /* 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. + */ + if (GSIsFinalizable(o->class_pointer)) + { + /* Already finalizable, so we just need to do any allocation + * accounting. + */ + AREM(o->class_pointer, o); + AADD(c, o); + } + else if (GSIsFinalizable(c)) + { + /* New clas is finalizable, so we must register the instance + * for finalisation and do allocation acounting for it. + */ + AADD(c, o); + GC_REGISTER_FINALIZER (o, GSFinalize, NULL, NULL, NULL); + } +#endif /* GS_WITH_GC */ + o->class_pointer = c; + } +} + inline NSObject * NSAllocateObject(Class aClass, NSUInteger extraBytes, NSZone *zone) { @@ -542,16 +586,13 @@ NSAllocateObject(Class aClass, NSUInteger extraBytes, NSZone *zone) if (new != nil) { new->class_pointer = aClass; - if (get_imp(aClass, finalize_sel) != finalize_imp) + if (GSIsFinalizable(aClass)) { -#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. + /* 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, new); -#endif + AADD(aClass, new); GC_REGISTER_FINALIZER (new, GSFinalize, NULL, NULL, NULL); } } @@ -576,9 +617,6 @@ GSObjCZone(NSObject *object) inline NSObject * NSAllocateObject (Class aClass, NSUInteger extraBytes, NSZone *zone) { -#ifndef NDEBUG - extern void GSDebugAllocationAdd(Class c, id o); -#endif id new; int size; @@ -595,9 +633,7 @@ NSAllocateObject (Class aClass, NSUInteger extraBytes, NSZone *zone) ((obj)new)->zone = zone; new = (id)&((obj)new)[1]; new->class_pointer = aClass; -#ifndef NDEBUG - GSDebugAllocationAdd(aClass, new); -#endif + AADD(aClass, new); } return new; } @@ -605,17 +641,12 @@ NSAllocateObject (Class aClass, NSUInteger extraBytes, NSZone *zone) inline void NSDeallocateObject(NSObject *anObject) { -#ifndef NDEBUG - extern void GSDebugAllocationRemove(Class c, id o); -#endif if ((anObject!=nil) && CLS_ISCLASS(((id)anObject)->class_pointer)) { obj o = &((obj)anObject)[-1]; NSZone *z = GSObjCZone(anObject); -#ifndef NDEBUG - GSDebugAllocationRemove(((id)anObject)->class_pointer, (id)anObject); -#endif + AREM(((id)anObject)->class_pointer, (id)anObject); if (NSZombieEnabled == YES) { GSMakeZombie(anObject); diff --git a/Source/NSZone.m b/Source/NSZone.m index eb9e7adc8..2b1ee6a09 100644 --- a/Source/NSZone.m +++ b/Source/NSZone.m @@ -95,6 +95,20 @@ #include "Foundation/NSString.h" #include "Foundation/NSZone.h" #include "Foundation/NSLock.h" +#include "GSPrivate.h" + +/** + * Try to get more memory - the normal process has failed. + * If we can't do anything, just return a null pointer. + * Try to do some logging if possible. + */ +void * +GSOutOfMemory(NSUInteger size, BOOL retry) +{ + fprintf(stderr, "GSOutOfMemory ... wanting %lu bytes.\n", + (unsigned long)size); + return 0; +} /* Default zone functions for default zone. */ static void* default_malloc (NSZone *zone, size_t size); @@ -196,9 +210,6 @@ NSZone *__nszone_private_hidden_default_zone = &default_zone; -/** - * Sets name of the given zone (useful for debugging and logging). - */ void NSSetZoneName (NSZone *zone, NSString *name) { @@ -452,21 +463,15 @@ NSZoneFree (NSZone *zone, void *ptr) } } -#else /* GS_WITH_GC */ - -/** - * Try to get more memory - the normal process has failed. - * If we can't do anything, just return a null pointer. - * Try to do some logging if possible. - */ -void * -GSOutOfMemory(NSUInteger size, BOOL retry) +BOOL +GSPrivateIsCollectable(const void *ptr) { - fprintf(stderr, "GSOutOfMemory ... wanting %lu bytes.\n", - (unsigned long)size); - return 0; + if (GC_base((void*)ptr) == 0) return NO; + else return YES; } +#else /* GS_WITH_GC */ + /* Alignment */ #ifdef ALIGN @@ -1818,10 +1823,6 @@ rrealloc (NSZone *zone, void *ptr, size_t size) static void rnfree (NSZone *zone, void *ptr); -/** - * Searches and finds the zone ptr was allocated from. The speed depends - * upon the number of zones and their size. - */ GS_DECLARE NSZone* NSZoneFromPointer(void *ptr) { @@ -1845,14 +1846,6 @@ NSZoneFromPointer(void *ptr) return (zone == 0) ? &default_zone : zone; } -/** - * Creates a new zone of start bytes, which will grow and shrink by - * granularity bytes. If canFree is 0, memory in zone is allocated but - * never freed, meaning allocation will be very fast. The whole zone can - * still be freed with NSRecycleZone(), and you should still call NSZoneFree - * on memory in the zone that is no longer needed, since a count of allocated - * pointers is kept and must reach zero before freeing the zone. - */ NSZone* NSCreateZone (NSUInteger start, NSUInteger gran, BOOL canFree) { @@ -1968,12 +1961,6 @@ NSCreateZone (NSUInteger start, NSUInteger gran, BOOL canFree) return newZone; } -/** - * Allocates and returns cleared memory for elems items of size bytes, in the - * given zone. Returns NULL if allocation of size 0 requested. Raises - * NSMallocException if not enough free memory in zone to - * allocate and no more can be obtained from system. - */ void* NSZoneCalloc (NSZone *zone, NSUInteger elems, NSUInteger bytes) { @@ -2069,4 +2056,10 @@ NSZoneStats (NSZone *zone) return (zone->stats)(zone); } +BOOL +GSPrivateIsCollectable(const void *ptr) +{ + return NO; +} + #endif /* GS_WITH_GC */ diff --git a/Source/callframe.m b/Source/callframe.m index f07d8727b..d56892de8 100644 --- a/Source/callframe.m +++ b/Source/callframe.m @@ -90,7 +90,11 @@ callframe_from_info (NSArgumentInfo *info, int numargs, void **retval) } pos = full; full += MAX(info[0].size, sizeof(smallret_t)); +#if GS_WITH_GC + cframe = buf = NSAllocateCollectable(full, NSScannedOption); +#else cframe = buf = NSZoneCalloc(NSDefaultMallocZone(), full, 1); +#endif if (cframe) { *retval = buf + pos; @@ -98,7 +102,11 @@ callframe_from_info (NSArgumentInfo *info, int numargs, void **retval) } else { +#if GS_WITH_GC + cframe = buf = NSAllocateCollectable(size, NSScannedOption); +#else cframe = buf = NSZoneCalloc(NSDefaultMallocZone(), size, 1); +#endif } if (cframe) @@ -567,8 +575,9 @@ callframe_do_call (DOContext *ctxt, } } } - +#if !GS_WITH_GC NSZoneFree(NSDefaultMallocZone(), ctxt->datToFree); +#endif ctxt->datToFree = 0; return; @@ -647,12 +656,17 @@ callframe_build_return (NSInvocation *inv, tmptype++; retLength = objc_sizeof_type(tmptype); /* Allocate memory to hold the value we're pointing to. */ +#if GS_WITH_GC + *(void**)retval = + NSAllocateCollectable(retLength, NSScannedOption); +#else *(void**)retval = NSZoneCalloc(NSDefaultMallocZone(), retLength, 1); /* We are responsible for making sure this memory gets free'd eventually. Ask NSData class to autorelease it. */ [NSData dataWithBytesNoCopy: *(void**)retval length: retLength]; +#endif ctxt->type = tmptype; ctxt->datum = *(void**)retval; /* Decode the return value into the memory we allocated. */ @@ -758,7 +772,9 @@ callframe_build_return (NSInvocation *inv, if (ctxt->datToFree != 0) { +#if !GS_WITH_GC NSZoneFree(NSDefaultMallocZone(), ctxt->datToFree); +#endif ctxt->datToFree = 0; } diff --git a/Source/cifframe.m b/Source/cifframe.m index 51caafbcc..3a6cc507d 100644 --- a/Source/cifframe.m +++ b/Source/cifframe.m @@ -200,7 +200,11 @@ cifframe_from_info (NSArgumentInfo *info, int numargs, void **retval) * memory by the ffi stuff. */ full += 64; +#if GS_WITH_GC + cframe = buf = NSAllocateCollectable(full, NSScannedOption); +#else cframe = buf = NSZoneCalloc(NSDefaultMallocZone(), full, 1); +#endif if (cframe && retval) { *retval = buf + pos; @@ -208,7 +212,11 @@ cifframe_from_info (NSArgumentInfo *info, int numargs, void **retval) } else { +#if GS_WITH_GC + cframe = buf = NSAllocateCollectable(size, NSScannedOption); +#else cframe = buf = NSZoneCalloc(NSDefaultMallocZone(), size, 1); +#endif } if (cframe) @@ -1042,8 +1050,9 @@ cifframe_do_call (DOContext *ctxt, } } } - +#if !GS_WITH_GC NSZoneFree(NSDefaultMallocZone(), ctxt->datToFree); +#endif ctxt->datToFree = 0; return; @@ -1122,12 +1131,17 @@ cifframe_build_return (NSInvocation *inv, tmptype++; retLength = objc_sizeof_type(tmptype); /* Allocate memory to hold the value we're pointing to. */ +#if GS_WITH_GC + *(void**)retval = + NSAllocateCollectable(retLength, NSScannedOption); +#else *(void**)retval = NSZoneCalloc(NSDefaultMallocZone(), retLength, 1); /* We are responsible for making sure this memory gets free'd eventually. Ask NSData class to autorelease it. */ [NSData dataWithBytesNoCopy: *(void**)retval length: retLength]; +#endif ctxt->type = tmptype; ctxt->datum = *(void**)retval; /* Decode the return value into the memory we allocated. */ @@ -1232,7 +1246,9 @@ cifframe_build_return (NSInvocation *inv, if (ctxt->datToFree != 0) { +#if !GS_WITH_GC NSZoneFree(NSDefaultMallocZone(), ctxt->datToFree); +#endif ctxt->datToFree = 0; }