mirror of
https://github.com/gnustep/libs-base.git
synced 2025-04-22 16:33:29 +00:00
Performance improvements - 10% or thereabouts
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@2898 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
7cb7aa24bb
commit
3e828bffdb
3 changed files with 205 additions and 27 deletions
12
ChangeLog
12
ChangeLog
|
@ -1,4 +1,14 @@
|
|||
Thu Aug 3 35:00:00 1998 Richard Frith-Macdonald <richard@brainstorm.co.uk>
|
||||
Fri Aug 4 09:30:00 1998 Richard Frith-Macdonald <richard@brainstorm.co.uk>
|
||||
|
||||
* src/GNUmakefile: Removed NSAllocateObject.m and
|
||||
NSDeallocateObject.m (contents merged into NSObject.m).
|
||||
* src/NSObject.m: Modified to perform storage of retain counts local
|
||||
to the objects concerned in order to speed up performance - also
|
||||
modified to cache an objects zone with it - in order to maintain
|
||||
(or better) current performance when we get the NSZone code fixed
|
||||
to work with malloced memory.
|
||||
|
||||
Thu Aug 3 15:35:00 1998 Richard Frith-Macdonald <richard@brainstorm.co.uk>
|
||||
|
||||
* src/include/NSGCString.h: Added _hash instance variable.
|
||||
* src/include/NSGString.h: Added _hash instance variable.
|
||||
|
|
|
@ -288,7 +288,6 @@ objc/zone.h
|
|||
# GNUStep source files
|
||||
|
||||
BASE_MFILES = \
|
||||
NSAllocateObject.m \
|
||||
NSAttributedString.m \
|
||||
NSArchiver.m \
|
||||
NSArray.m \
|
||||
|
@ -307,7 +306,6 @@ NSConnection.m \
|
|||
NSData.m \
|
||||
NSDate.m \
|
||||
NSDebug.m \
|
||||
NSDeallocateObject.m \
|
||||
NSDictionary.m \
|
||||
NSDistantObject.m \
|
||||
NSDistributedLock.m \
|
||||
|
|
|
@ -38,36 +38,76 @@
|
|||
#include <limits.h>
|
||||
|
||||
|
||||
/* Reference count management */
|
||||
/*
|
||||
* Reference count and memory management
|
||||
*
|
||||
* If REFCNT_LOCAL is defined, reference counts for object are stored
|
||||
* with the object, otherwise they are stored in a global map table
|
||||
* that has to be protected by mutexes in a multithreraded environment.
|
||||
* You therefore want REFCNT_LOCAL defined for best performance.
|
||||
*
|
||||
* If CACHE_ZONE is defined, the zone in which an object has been
|
||||
* allocated is stored with the object - this makes lookup of the
|
||||
* correct zone to free memory very fast.
|
||||
*/
|
||||
|
||||
/* Handles multi-threaded access.
|
||||
?? Doesn't handle exceptions. */
|
||||
#define REFCNT_LOCAL 1
|
||||
/* #define CACHE_ZONE 1 */
|
||||
|
||||
#if defined(REFCNT_LOCAL) || defined(CACHE_ZONE)
|
||||
|
||||
/*
|
||||
* Define a structure to hold information that is held locally
|
||||
* (before the start) in each object.
|
||||
*/
|
||||
struct obj_layout {
|
||||
#if defined(REFCNT_LOCAL)
|
||||
unsigned retained;
|
||||
#endif
|
||||
#if defined(CACHE_ZONE)
|
||||
NSZone *zone;
|
||||
#endif
|
||||
};
|
||||
typedef struct obj_layout *obj;
|
||||
|
||||
#endif /* defined(REFCNT_LOCAL) || defined(CACHE_ZONE) */
|
||||
|
||||
|
||||
/*
|
||||
* Now do conditional compilation of reference count functions
|
||||
* depending on whether we are using local or global counting.
|
||||
*/
|
||||
#if defined(REFCNT_LOCAL)
|
||||
void
|
||||
NSIncrementExtraRefCount(id anObject)
|
||||
{
|
||||
((obj)anObject)[-1].retained++;
|
||||
}
|
||||
|
||||
#define NSIncrementExtraRefCount(X) \
|
||||
((obj)(X))[-1].retained++
|
||||
|
||||
BOOL
|
||||
NSDecrementExtraRefCountWasZero(id anObject)
|
||||
{
|
||||
if (((obj)anObject)[-1].retained-- == 0)
|
||||
return YES;
|
||||
else
|
||||
return NO;
|
||||
}
|
||||
|
||||
#define NSDecrementExtraRefCountWasZero(X) \
|
||||
(((obj)(X))[-1].retained-- == 0 ? YES : NO)
|
||||
|
||||
#define extraRefCount(X) (((obj)(X))[-1].retained)
|
||||
|
||||
#else
|
||||
|
||||
/* The maptable of retain counts on objects */
|
||||
static o_map_t *retain_counts = NULL;
|
||||
/* The mutex lock to protect multi-threaded use of `retain_counts' */
|
||||
static objc_mutex_t retain_counts_gate = NULL;
|
||||
|
||||
/* The mutex lock to protect RETAIN_COUNTS. */
|
||||
static objc_mutex_t retain_counts_gate;
|
||||
|
||||
/* The Class responsible for handling autorelease's. This does not
|
||||
need mutex protection, since it is simply a pointer that gets read
|
||||
and set. */
|
||||
static id autorelease_class = nil;
|
||||
|
||||
/* When this is `YES', every call to release/autorelease, checks to
|
||||
make sure isn't being set up to release itself too many times.
|
||||
This does not need mutex protection. */
|
||||
static BOOL double_release_check_enabled = NO;
|
||||
|
||||
BOOL
|
||||
NSShouldRetainWithZone (NSObject *anObject, NSZone *requestedZone)
|
||||
{
|
||||
return (!requestedZone || requestedZone == NSDefaultMallocZone()
|
||||
|| [anObject zone] == requestedZone);
|
||||
}
|
||||
|
||||
void
|
||||
NSIncrementExtraRefCount (id anObject)
|
||||
{
|
||||
|
@ -117,6 +157,127 @@ extraRefCount (id anObject)
|
|||
return ret; /* ExtraRefCount + 1 */
|
||||
}
|
||||
|
||||
#endif /* defined(REFCNT_LOCAL) */
|
||||
|
||||
|
||||
/*
|
||||
* Now do conditional compilation of memory allocation functions
|
||||
* depending on what information (if any) we are storing before
|
||||
* the start of each object.
|
||||
*/
|
||||
#if defined(REFCNT_LOCAL) || defined(CACHE_ZONE)
|
||||
|
||||
NSObject *NSAllocateObject (Class aClass, unsigned extraBytes, NSZone *zone)
|
||||
{
|
||||
id new = nil;
|
||||
int size = aClass->instance_size + extraBytes + sizeof(struct obj_layout);
|
||||
if (CLS_ISCLASS (aClass))
|
||||
{
|
||||
if (zone == 0)
|
||||
zone = NSDefaultMallocZone();
|
||||
new = NSZoneMalloc(zone, size);
|
||||
}
|
||||
if (new != nil)
|
||||
{
|
||||
memset (new, 0, size);
|
||||
#if defined(CACHE_ZONE)
|
||||
((obj)new)->zone = zone;
|
||||
#endif
|
||||
new = (id)&((obj)new)[1];
|
||||
new->class_pointer = aClass;
|
||||
}
|
||||
#ifndef NDEBUG
|
||||
GSDebugAllocationAdd(aClass);
|
||||
#endif
|
||||
return new;
|
||||
}
|
||||
|
||||
void NSDeallocateObject(NSObject *anObject)
|
||||
{
|
||||
if ((anObject!=nil) && CLS_ISCLASS(((id)anObject)->class_pointer))
|
||||
{
|
||||
NSZone *z;
|
||||
obj o = &((obj)anObject)[-1];
|
||||
|
||||
#ifndef NDEBUG
|
||||
GSDebugAllocationRemove(((id)anObject)->class_pointer);
|
||||
#endif
|
||||
#if defined(CACHE_ZONE)
|
||||
z = o->zone;
|
||||
#else
|
||||
z = [anObject zone];
|
||||
#endif
|
||||
((id)anObject)->class_pointer = (void*) 0xdeadface;
|
||||
NSZoneFree(z, o);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
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;
|
||||
}
|
||||
#ifndef NDEBUG
|
||||
GSDebugAllocationAdd(aClass);
|
||||
#endif
|
||||
return new;
|
||||
}
|
||||
|
||||
void NSDeallocateObject(NSObject *anObject)
|
||||
{
|
||||
if ((anObject!=nil) && CLS_ISCLASS(((id)anObject)->class_pointer))
|
||||
{
|
||||
NSZone *z = [anObject zone];
|
||||
|
||||
#ifndef NDEBUG
|
||||
GSDebugAllocationRemove(((id)anObject)->class_pointer);
|
||||
#endif
|
||||
((id)anObject)->class_pointer = (void*) 0xdeadface;
|
||||
NSZoneFree(z, anObject);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
#endif /* defined(REFCNT_LOCAL) || defined(CACHE_ZONE) */
|
||||
|
||||
#if defined(CACHE_ZONE)
|
||||
BOOL
|
||||
NSShouldRetainWithZone (NSObject *anObject, NSZone *requestedZone)
|
||||
{
|
||||
return (!requestedZone || requestedZone == NSDefaultMallocZone()
|
||||
|| ((obj)anObject)[-1].zone == requestedZone);
|
||||
}
|
||||
#else
|
||||
BOOL
|
||||
NSShouldRetainWithZone (NSObject *anObject, NSZone *requestedZone)
|
||||
{
|
||||
return (!requestedZone || requestedZone == NSDefaultMallocZone()
|
||||
|| [anObject zone] == requestedZone);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
/* The Class responsible for handling autorelease's. This does not
|
||||
need mutex protection, since it is simply a pointer that gets read
|
||||
and set. */
|
||||
static id autorelease_class = nil;
|
||||
|
||||
/* When this is `YES', every call to release/autorelease, checks to
|
||||
make sure isn't being set up to release itself too many times.
|
||||
This does not need mutex protection. */
|
||||
static BOOL double_release_check_enabled = NO;
|
||||
|
||||
|
||||
@implementation NSObject
|
||||
|
||||
|
@ -126,10 +287,11 @@ extraRefCount (id anObject)
|
|||
{
|
||||
// Create the global lock
|
||||
gnustep_global_lock = [[NSRecursiveLock alloc] init];
|
||||
|
||||
#if !defined(REFCNT_LOCAL)
|
||||
retain_counts = o_map_with_callbacks (o_callbacks_for_non_owned_void_p,
|
||||
o_callbacks_for_int);
|
||||
retain_counts_gate = objc_mutex_allocate ();
|
||||
#endif
|
||||
autorelease_class = [NSAutoreleasePool class];
|
||||
}
|
||||
return;
|
||||
|
@ -498,7 +660,15 @@ extraRefCount (id anObject)
|
|||
|
||||
- (NSZone *)zone
|
||||
{
|
||||
#if defined(REFCNT_LOCAL) || defined(CACHE_ZONE)
|
||||
#if defined(CACHE_ZONE)
|
||||
return ((obj)self)[-1].zone;
|
||||
#else
|
||||
return NSZoneFromPointer(&((obj)self)[-1]);
|
||||
#endif
|
||||
#else
|
||||
return NSZoneFromPointer(self);
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void) encodeWithCoder: (NSCoder*)aCoder
|
||||
|
|
Loading…
Reference in a new issue