mirror of
https://github.com/gnustep/libs-base.git
synced 2025-04-22 16:33:29 +00:00
Use the runtime's ARC autorelease pools if available.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@35031 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
11f622c738
commit
889cad62db
3 changed files with 165 additions and 52 deletions
|
@ -34,6 +34,13 @@
|
|||
#import "Foundation/NSException.h"
|
||||
#import "Foundation/NSThread.h"
|
||||
|
||||
#if __has_include(<objc/capabilities.h>)
|
||||
# include <objc/capabilities.h>
|
||||
# ifdef OBJC_ARC_AUTORELEASE_DEBUG
|
||||
# include <objc/objc-arc.h>
|
||||
# define ARC_RUNTIME 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if GS_WITH_GC || __OBJC_GC__
|
||||
|
||||
|
@ -209,6 +216,8 @@ static Class PoolClass;
|
|||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if !GS_WITH_GC
|
||||
|
||||
/* When this is `NO', autoreleased objects are never actually recorded
|
||||
|
@ -333,6 +342,73 @@ pop_pool_from_cache (struct autorelease_thread_vars *tv)
|
|||
return (*initImp)(arp, @selector(init));
|
||||
}
|
||||
|
||||
#ifdef ARC_RUNTIME
|
||||
|
||||
- (id) init
|
||||
{
|
||||
_released = objc_autoreleasePoolPush();
|
||||
{
|
||||
struct autorelease_thread_vars *tv = ARP_THREAD_VARS;
|
||||
unsigned level = 0;
|
||||
_parent = tv->current_pool;
|
||||
if (_parent)
|
||||
{
|
||||
NSAutoreleasePool *pool = _parent;
|
||||
|
||||
while (nil != pool)
|
||||
{
|
||||
level++;
|
||||
pool = pool->_parent;
|
||||
}
|
||||
_parent->_child = self;
|
||||
}
|
||||
tv->current_pool = self;
|
||||
if (level > pool_number_warning_threshhold)
|
||||
{
|
||||
[NSException raise: NSGenericException
|
||||
format: @"Too many (%u) autorelease pools ... leaking them?", level];
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (unsigned) autoreleaseCountForObject: (id)anObject
|
||||
{
|
||||
return objc_arc_autorelease_count_for_object_np(anObject);
|
||||
}
|
||||
|
||||
+ (unsigned) autoreleaseCountForObject: (id)anObject
|
||||
{
|
||||
return objc_arc_autorelease_count_for_object_np(anObject);
|
||||
}
|
||||
|
||||
- (unsigned) autoreleaseCount
|
||||
{
|
||||
return objc_arc_autorelease_count_np();
|
||||
}
|
||||
|
||||
+ (void) addObject: (id)anObj
|
||||
{
|
||||
if (autorelease_enabled)
|
||||
objc_autorelease(anObj);
|
||||
}
|
||||
|
||||
- (void) addObject: (id)anObj
|
||||
{
|
||||
if (autorelease_enabled)
|
||||
objc_autorelease(anObj);
|
||||
}
|
||||
- (void) emptyPool
|
||||
{
|
||||
objc_autoreleasePoolPop(_released);
|
||||
}
|
||||
/**
|
||||
* Indicate to the runtime that we have an ARC-compatible implementation of
|
||||
* NSAutoreleasePool and that it doesn't need to bother creating objects for
|
||||
* pools.
|
||||
*/
|
||||
- (void)_ARCCompatibleAutoreleasePool {}
|
||||
#else
|
||||
- (id) init
|
||||
{
|
||||
if (!_released_head)
|
||||
|
@ -429,11 +505,6 @@ pop_pool_from_cache (struct autorelease_thread_vars *tv)
|
|||
return count;
|
||||
}
|
||||
|
||||
+ (id) currentPool
|
||||
{
|
||||
return ARP_THREAD_VARS->current_pool;
|
||||
}
|
||||
|
||||
+ (void) addObject: (id)anObj
|
||||
{
|
||||
NSThread *t = GSCurrentThread();
|
||||
|
@ -512,52 +583,6 @@ pop_pool_from_cache (struct autorelease_thread_vars *tv)
|
|||
_released_count++;
|
||||
}
|
||||
|
||||
- (void) drain
|
||||
{
|
||||
// Don't call -release, make both -release and -drain have the same cost in
|
||||
// non-GC mode.
|
||||
[self dealloc];
|
||||
}
|
||||
|
||||
- (id) retain
|
||||
{
|
||||
[NSException raise: NSGenericException
|
||||
format: @"Don't call `-retain' on a NSAutoreleasePool"];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (oneway void) release
|
||||
{
|
||||
[self dealloc];
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
struct autorelease_thread_vars *tv = ARP_THREAD_VARS;
|
||||
|
||||
[self emptyPool];
|
||||
|
||||
/* Remove self from the linked list of pools in use.
|
||||
* We already know that we have deallocated any child (in -emptyPool),
|
||||
* but we may have a parent which needs to know we have gone.
|
||||
* The only other place where the parent/child linked list is modified
|
||||
* should be in -init
|
||||
*/
|
||||
if (tv->current_pool == self)
|
||||
{
|
||||
tv->current_pool = _parent;
|
||||
}
|
||||
if (_parent != nil)
|
||||
{
|
||||
_parent->_child = nil;
|
||||
_parent = nil;
|
||||
}
|
||||
|
||||
/* Don't deallocate ourself, just save us for later use. */
|
||||
push_pool_to_cache (tv, self);
|
||||
GSNOSUPERDEALLOC;
|
||||
}
|
||||
|
||||
- (void) emptyPool
|
||||
{
|
||||
unsigned i;
|
||||
|
@ -662,6 +687,60 @@ pop_pool_from_cache (struct autorelease_thread_vars *tv)
|
|||
}
|
||||
}
|
||||
|
||||
#endif // ARC_RUNTIME
|
||||
|
||||
+ (id) currentPool
|
||||
{
|
||||
return ARP_THREAD_VARS->current_pool;
|
||||
}
|
||||
|
||||
|
||||
- (void) drain
|
||||
{
|
||||
// Don't call -release, make both -release and -drain have the same cost in
|
||||
// non-GC mode.
|
||||
[self dealloc];
|
||||
}
|
||||
|
||||
- (id) retain
|
||||
{
|
||||
[NSException raise: NSGenericException
|
||||
format: @"Don't call `-retain' on a NSAutoreleasePool"];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (oneway void) release
|
||||
{
|
||||
[self dealloc];
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
struct autorelease_thread_vars *tv = ARP_THREAD_VARS;
|
||||
|
||||
[self emptyPool];
|
||||
|
||||
/* Remove self from the linked list of pools in use.
|
||||
* We already know that we have deallocated any child (in -emptyPool),
|
||||
* but we may have a parent which needs to know we have gone.
|
||||
* The only other place where the parent/child linked list is modified
|
||||
* should be in -init
|
||||
*/
|
||||
if (tv->current_pool == self)
|
||||
{
|
||||
tv->current_pool = _parent;
|
||||
}
|
||||
if (_parent != nil)
|
||||
{
|
||||
_parent->_child = nil;
|
||||
_parent = nil;
|
||||
}
|
||||
|
||||
/* Don't deallocate ourself, just save us for later use. */
|
||||
push_pool_to_cache (tv, self);
|
||||
GSNOSUPERDEALLOC;
|
||||
}
|
||||
|
||||
- (void) _reallyDealloc
|
||||
{
|
||||
struct autorelease_array_list *a;
|
||||
|
@ -735,4 +814,4 @@ pop_pool_from_cache (struct autorelease_thread_vars *tv)
|
|||
}
|
||||
|
||||
@end
|
||||
#endif
|
||||
#endif // !GS_WITH_GC
|
||||
|
|
0
Tests/base/NSAutoreleasePool/TestInfo
Normal file
0
Tests/base/NSAutoreleasePool/TestInfo
Normal file
34
Tests/base/NSAutoreleasePool/basic.m
Normal file
34
Tests/base/NSAutoreleasePool/basic.m
Normal file
|
@ -0,0 +1,34 @@
|
|||
#import "ObjectTesting.h"
|
||||
#import <Foundation/NSAutoreleasePool.h>
|
||||
#import <Foundation/NSObject.h>
|
||||
|
||||
static BOOL freed;
|
||||
@interface Test : NSObject @end
|
||||
@implementation Test
|
||||
- (void)dealloc
|
||||
{
|
||||
freed = YES;
|
||||
[super dealloc];
|
||||
}
|
||||
@end
|
||||
|
||||
int main()
|
||||
{
|
||||
NSAutoreleasePool *arp = [NSAutoreleasePool new];
|
||||
NSObject *o = [NSObject new];
|
||||
for (unsigned i=0 ; i<1000 ; i++)
|
||||
{
|
||||
[[o retain] autorelease];
|
||||
}
|
||||
NSUInteger totalCount = [arp autoreleaseCount];
|
||||
PASS(totalCount == 1000, "Autorelease count is correct");
|
||||
PASS([NSAutoreleasePool autoreleaseCountForObject: o] == 1000,
|
||||
"Autorelease count for object is correct");
|
||||
PASS(freed == NO, "Object not prematurely freed");
|
||||
[arp release];
|
||||
arp = [NSAutoreleasePool new];
|
||||
[o release];
|
||||
PASS(freed == NO, "Object freed by autoreleasing");
|
||||
[arp release];
|
||||
return 0;
|
||||
}
|
Loading…
Reference in a new issue