diff --git a/ChangeLog b/ChangeLog index d6de0cab2..7e87c7d43 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,4 @@ -2017-11-25 Graham Lee +2017-12-18 Graham Lee * Source/NSJSONSerialization.m: Fix for bug #12 on github. This makes sure that unsigned integer types are written as such, @@ -6,6 +6,26 @@ * Tests/base/NSJSONSerialization/tests00.m: Test case for above. +2017-12-17 David Chisnall + + * Source/NSObject.m: Refactor refcount usage. + + This makes it easier for the runtime to change how reference + counts are + stored by removing any refcount manipulation from -base when + the runtime + provides accessors. This should have no functionality + change with + existing runtimes, but will let newer runtimes drop in + alternative + representations easily. + +2017-12-03 Fred Kiefer + + * Headers/Foundation/NSFileManager.h + * Source/NSFileManager.m: Correct setting the delegate. + Add new symbolic link method. + 2017-11-16 Richard Frith-Macdonald * Source/NSArray.m: Fix for bug reported on github by zneak. diff --git a/Headers/Foundation/NSFileManager.h b/Headers/Foundation/NSFileManager.h index 4ccb21701..ce5cda07b 100644 --- a/Headers/Foundation/NSFileManager.h +++ b/Headers/Foundation/NSFileManager.h @@ -302,6 +302,14 @@ typedef NSUInteger NSDirectoryEnumerationOptions; */ - (BOOL) removeItemAtURL: (NSURL*)url error: (NSError**)error; +/** + * Creates a symbolic link at the path + * that point to the destination path.
+ * Returns YES on success, otherwise NO. + */ +- (BOOL) createSymbolicLinkAtPath: (NSString*)path + withDestinationPath: (NSString*)destPath + error: (NSError**)error; #endif /** diff --git a/Headers/GNUstepBase/GSBlocks.h b/Headers/GNUstepBase/GSBlocks.h index 6123e9e74..de0045d00 100644 --- a/Headers/GNUstepBase/GSBlocks.h +++ b/Headers/GNUstepBase/GSBlocks.h @@ -107,6 +107,10 @@ typedef retTy(^name)() #endif /* __has_feature(blocks) */ +#if __has_include() +# include +#else + #ifdef __cplusplus extern "C" { #endif @@ -136,5 +140,7 @@ void _Block_release(const void *) __attribute__((weak)); # define Block_release(x) _Block_release((const void *)(x)) #endif +#endif /* __has_include() */ + #endif /* __GSBlocks_h_GNUSTEP_BASE_INCLUDE */ diff --git a/NSTimeZones/NSTimeZones.tar b/NSTimeZones/NSTimeZones.tar index f711b1a75..21fdf638f 100644 Binary files a/NSTimeZones/NSTimeZones.tar and b/NSTimeZones/NSTimeZones.tar differ diff --git a/Source/NSFileManager.m b/Source/NSFileManager.m index 37f8d8ecc..f57014c03 100644 --- a/Source/NSFileManager.m +++ b/Source/NSFileManager.m @@ -361,7 +361,7 @@ static NSStringEncoding defaultEncoding; return _delegate; } -- (void) setDelegate: (NSFileManager *)delegate { +- (void) setDelegate: (id)delegate { _delegate = delegate; } @@ -1586,6 +1586,26 @@ static NSStringEncoding defaultEncoding; return [self removeItemAtPath: [url path] error: error]; } +- (BOOL) createSymbolicLinkAtPath: (NSString*)path + withDestinationPath: (NSString*)destPath + error: (NSError**)error +{ + BOOL result; + + DESTROY(_lastError); + result = [self createSymbolicLinkAtPath: path pathContent: destPath]; + + if (error != NULL) + { + if (NO == result) + { + *error = [self _errorFrom: path to: destPath]; + } + } + + return result; +} + - (BOOL) fileExistsAtPath: (NSString*)path { return [self fileExistsAtPath: path isDirectory: 0]; diff --git a/Source/NSMapTable.m b/Source/NSMapTable.m index 26e3d93ec..7dd263474 100644 --- a/Source/NSMapTable.m +++ b/Source/NSMapTable.m @@ -100,29 +100,29 @@ static Class concreteClass = 0; + (id) strongToStrongObjectsMapTable { - return [self mapTableWithKeyOptions: NSMapTableObjectPointerPersonality - valueOptions: NSMapTableObjectPointerPersonality]; + return [self mapTableWithKeyOptions: NSPointerFunctionsObjectPersonality + valueOptions: NSPointerFunctionsObjectPersonality]; } + (id) strongToWeakObjectsMapTable { - return [self mapTableWithKeyOptions: NSMapTableObjectPointerPersonality - valueOptions: NSMapTableObjectPointerPersonality | + return [self mapTableWithKeyOptions: NSPointerFunctionsObjectPersonality + valueOptions: NSPointerFunctionsObjectPersonality | NSMapTableWeakMemory]; } + (id) weakToStrongObjectsMapTable { - return [self mapTableWithKeyOptions: NSMapTableObjectPointerPersonality | + return [self mapTableWithKeyOptions: NSPointerFunctionsObjectPersonality | NSMapTableWeakMemory - valueOptions: NSMapTableObjectPointerPersonality]; + valueOptions: NSPointerFunctionsObjectPersonality]; } + (id) weakToWeakObjectsMapTable { - return [self mapTableWithKeyOptions: NSMapTableObjectPointerPersonality | + return [self mapTableWithKeyOptions: NSPointerFunctionsObjectPersonality | NSMapTableWeakMemory - valueOptions: NSMapTableObjectPointerPersonality | + valueOptions: NSPointerFunctionsObjectPersonality | NSMapTableWeakMemory]; } diff --git a/Source/NSObject.m b/Source/NSObject.m index 701af3f4a..c68b06232 100644 --- a/Source/NSObject.m +++ b/Source/NSObject.m @@ -125,6 +125,7 @@ BOOL NSDeallocateZombies = NO; static Class zombieClass = Nil; static NSMapTable *zombieMap = 0; +#ifndef OBJC_CAP_ARC static void GSMakeZombie(NSObject *o, Class c) { object_setClass(o, zombieClass); @@ -135,6 +136,7 @@ static void GSMakeZombie(NSObject *o, Class c) [allocationLock unlock]; } } +#endif static void GSLogZombie(id o, SEL sel) { @@ -444,15 +446,24 @@ struct obj_layout { }; typedef struct obj_layout *obj; -/** - * Examines the extra reference count for the object and, if non-zero - * decrements it, otherwise leaves it unchanged.
- * Returns a flag to say whether the count was zero - * (and hence whether the extra reference count was decremented).
- * This function is used by the [NSObject-release] method. +/* + * These symbols are provided by newer versions of the GNUstep Objective-C + * runtime. When linked against an older version, we will use our internal + * versions. */ -inline BOOL -NSDecrementExtraRefCountWasZero(id anObject) +__attribute__((weak)) +BOOL objc_release_fast_no_destroy_np(id anObject); + +__attribute__((weak)) +void objc_release_fast_np(id anObject); + +__attribute__((weak)) +size_t object_getRetainCount_np(id anObject); + +__attribute__((weak)) +id objc_retain_fast_np(id anObject); + +static BOOL objc_release_fast_no_destroy_internal(id anObject) { if (double_release_check_enabled) { @@ -483,6 +494,9 @@ NSDecrementExtraRefCountWasZero(id anObject) * have been greater than zero) */ (((obj)anObject)[-1].retained) = 0; +# ifdef OBJC_CAP_ARC + objc_delete_weak_refs(anObject); +# endif return YES; } #else /* GSATOMICREAD */ @@ -491,6 +505,9 @@ NSDecrementExtraRefCountWasZero(id anObject) [theLock lock]; if (((obj)anObject)[-1].retained == 0) { +# ifdef OBJC_CAP_ARC + objc_delete_weak_refs(anObject); +# endif [theLock unlock]; return YES; } @@ -505,6 +522,67 @@ NSDecrementExtraRefCountWasZero(id anObject) return NO; } +static BOOL release_fast_no_destroy(id anObject) +{ + if (objc_release_fast_no_destroy_np) + { + return objc_release_fast_no_destroy_np(anObject); + } + else + { + return objc_release_fast_no_destroy_internal(anObject); + } +} + +static void objc_release_fast_np_internal(id anObject) +{ + if (release_fast_no_destroy(anObject)) + { + [anObject dealloc]; + } +} + +static void release_fast(id anObject) +{ + if (objc_release_fast_np) + { + objc_release_fast_np(anObject); + } + else + { + objc_release_fast_np_internal(anObject); + } +} + +/** + * Examines the extra reference count for the object and, if non-zero + * decrements it, otherwise leaves it unchanged.
+ * Returns a flag to say whether the count was zero + * (and hence whether the extra reference count was decremented).
+ */ +inline BOOL +NSDecrementExtraRefCountWasZero(id anObject) +{ + return release_fast_no_destroy(anObject); +} + +size_t object_getRetainCount_np_internal(id anObject) +{ + return ((obj)anObject)[-1].retained + 1; +} + +size_t getRetainCount(id anObject) +{ + if (object_getRetainCount_np) + { + return object_getRetainCount_np(anObject); + } + else + { + return object_getRetainCount_np_internal(anObject); + } +} + /** * Return the extra reference count of anObject (a value in the range * from 0 to the maximum unsigned integer value minus one).
@@ -513,7 +591,7 @@ NSDecrementExtraRefCountWasZero(id anObject) inline NSUInteger NSExtraRefCount(id anObject) { - return ((obj)anObject)[-1].retained; + return getRetainCount(anObject) - 1; } /** @@ -522,8 +600,7 @@ NSExtraRefCount(id anObject) * would be incremented to too large a value.
* This is used by the [NSObject-retain] method. */ -inline void -NSIncrementExtraRefCount(id anObject) +static id objc_retain_fast_np_internal(id anObject) { BOOL tooFar = NO; @@ -586,6 +663,31 @@ NSIncrementExtraRefCount(id anObject) @" for %@ - %@", base, anObject]; } } + return anObject; +} + +static id retain_fast(id anObject) +{ + if (objc_retain_fast_np) + { + return objc_retain_fast_np(anObject); + } + else + { + return objc_retain_fast_np_internal(anObject); + } +} + +/** + * Increments the extra reference count for anObject.
+ * The GNUstep version raises an exception if the reference count + * would be incremented to too large a value.
+ * This is used by the [NSObject-retain] method. + */ +inline void +NSIncrementExtraRefCount(id anObject) +{ + retain_fast(anObject); } #ifndef NDEBUG @@ -596,6 +698,8 @@ NSIncrementExtraRefCount(id anObject) #define AREM(c, o) #endif + +#ifndef OBJC_CAP_ARC static SEL cxx_construct, cxx_destruct; /** @@ -629,6 +733,7 @@ callCXXConstructors(Class aClass, id anObject) } return constructor; } +#endif /* @@ -642,6 +747,9 @@ callCXXConstructors(Class aClass, id anObject) inline id NSAllocateObject (Class aClass, NSUInteger extraBytes, NSZone *zone) { +#ifdef OBJC_CAP_ARC + return class_createInstance(aClass, extraBytes); +#else id new; int size; @@ -674,17 +782,21 @@ NSAllocateObject (Class aClass, NSUInteger extraBytes, NSZone *zone) callCXXConstructors(aClass, new); return new; +#endif } inline void NSDeallocateObject(id anObject) { + Class aClass = object_getClass(anObject); if ((anObject != nil) && !class_isMetaClass(aClass)) { +#ifndef OBJC_CAP_ARC obj o = &((obj)anObject)[-1]; NSZone *z = NSZoneFromPointer(o); +#endif /* Call the default finalizer to handle C++ destructors. */ @@ -693,16 +805,37 @@ NSDeallocateObject(id anObject) AREM(aClass, (id)anObject); if (NSZombieEnabled == YES) { +#ifdef OBJC_CAP_ARC + if (0 != zombieMap) + { + [allocationLock lock]; + NSMapInsert(zombieMap, (void*)anObject, (void*)aClass); + [allocationLock unlock]; + } + if (NSDeallocateZombies == YES) + { + object_dispose(anObject); + } + else + { + object_setClass(anObject, zombieClass); + } +#else GSMakeZombie(anObject, aClass); if (NSDeallocateZombies == YES) { NSZoneFree(z, o); } +#endif } else { +#ifdef OBJC_CAP_ARC + object_dispose(anObject); +#else object_setClass((id)anObject, (Class)(void*)0xdeadface); NSZoneFree(z, o); +#endif } } return; @@ -1197,6 +1330,7 @@ static id gs_weak_load(id obj) - (void) finalize { +#ifndef OBJC_CAP_ARC Class destructorClass = Nil; IMP destructor = 0; /* @@ -1251,6 +1385,7 @@ static id gs_weak_load(id obj) } } return; +#endif } /** @@ -1893,13 +2028,7 @@ static id gs_weak_load(id obj) */ - (oneway void) release { - if (NSDecrementExtraRefCountWasZero(self)) - { -# ifdef OBJC_CAP_ARC - objc_delete_weak_refs(self); -# endif - [self dealloc]; - } + release_fast(self); } /** @@ -1958,8 +2087,7 @@ static id gs_weak_load(id obj) */ - (id) retain { - NSIncrementExtraRefCount(self); - return self; + return retain_fast(self); } /** @@ -1983,7 +2111,7 @@ static id gs_weak_load(id obj) */ - (NSUInteger) retainCount { - return NSExtraRefCount(self) + 1; + return getRetainCount(self); } /** diff --git a/Tests/base/NSProxy/basic.m b/Tests/base/NSProxy/basic.m index bb21489cf..5a977c73c 100644 --- a/Tests/base/NSProxy/basic.m +++ b/Tests/base/NSProxy/basic.m @@ -1,6 +1,9 @@ #import "ObjectTesting.h" #import #import +#if __has_include() +#include +#endif int main() { @@ -24,8 +27,10 @@ int main() obj1 = [NSProxy allocWithZone:testZone]; PASS(obj1 != nil, "%s has working allocWithZone:",prefix); +#ifndef OBJC_CAP_ARC PASS(NSZoneFromPointer(obj1) == testZone, "%s uses zone for alloc",prefix); PASS([obj1 zone] == testZone, "%s -zone works",prefix); +#endif PASS([obj1 hash] != 0, "%s has working -hash",prefix); PASS([obj1 isEqual:obj1] == YES, "%s has working -isEqual:",prefix);