iPerformance and GC improvements

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@13726 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Richard Frith-Macdonald 2002-05-28 05:23:36 +00:00
parent 5651fe7dbb
commit ecbcc202a1
15 changed files with 167 additions and 114 deletions

View file

@ -1,3 +1,29 @@
2002-05-28 Richard Frith-Macdonald <rfm@gnu.org>
* Headers/gnustep/base/GSIMap.h:
* Headers/gnustep/base/NSHashTable.h:
* Headers/gnustep/base/NSMapTable.h:
* Source/GSArray.m:
* Source/GSSet.m:
* Source/GSTcpPort.m:
* Source/NSBundle.m:
* Source/NSConnection.m:
* Source/NSData.m:
* Source/NSHashTable.m:
* Source/NSMapTable.m:
* Source/NSObject.m:
* Source/NSRunLoop.m:
Applied patches by James Knight, to improve memory efficiency and
insertion.deletion speed to hash and map tables. Also fixes for
some GC problems.
Fixed minor problem in patch, and added code to call functions to
clean up after hash and map enumerations. Modified cleanup function
to clear enumerator ... for memory release on GC system.
*WARNING* This introduces a binary incompatibility in that the size
of the map table and hash table enumeration types has grown.
If you have binaries which use the NSEnumerateHashTable() or the
NSEnumeratemapTable() functions, you need to rebuild them.
2002-05-27 Richard Frith-Macdonald <rfm@gnu.org>
* Headers/Foundation/GSMime.h: Tidy up and add convenience methods.

View file

@ -132,6 +132,15 @@
*/
#include <base/GSUnion.h>
#if (GSI_MAP_KTYPES) & GSUNION_OBJ
#define GSI_MAP_CLEAR_KEY(node) node->key.obj = nil
#elif (GSI_MAP_KTYPES) & GSUNION_PTR
#define GSI_MAP_CLEAR_KEY(node) node->key.ptr = 0
#else
#define GSI_MAP_CLEAR_KEY(node)
#endif
/*
* If there is no bitmask defined to supply the types that
* may be used as values in the map, default to permitting all types.
@ -172,6 +181,14 @@
*/
#include <base/GSUnion.h>
#if (GSI_MAP_VTYPES) & GSUNION_OBJ
#define GSI_MAP_CLEAR_VAL(node) node->value.obj = nil
#elif (GSI_MAP_VTYPES) & GSUNION_PTR
#define GSI_MAP_CLEAR_VAL(node) node->value.ptr = 0
#else
#define GSI_MAP_CLEAR_VAL(node)
#endif
typedef struct _GSIMapTable GSIMapTable_t;
typedef struct _GSIMapBucket GSIMapBucket_t;
@ -183,7 +200,6 @@ typedef GSIMapNode_t *GSIMapNode;
struct _GSIMapNode {
GSIMapNode nextInBucket; /* Linked list of bucket. */
GSIMapNode nextInMap; /* For enumerating. */
GSIMapKey key;
#if GSI_MAP_HAS_VALUE
GSIMapVal value;
@ -198,7 +214,6 @@ struct _GSIMapBucket {
struct _GSIMapTable {
NSZone *zone;
size_t nodeCount; /* Number of nodes in map. */
GSIMapNode firstNode; /* List for enumerating. */
size_t bucketCount; /* Number of buckets in map. */
GSIMapBucket buckets; /* Array of buckets. */
GSIMapNode freeNodes; /* List of unused nodes. */
@ -215,6 +230,7 @@ typedef GSI_MAP_ENUMERATOR GSIMapEnumerator_t;
struct _GSIMapEnumerator {
GSIMapTable map; /* the map being enumerated. */
GSIMapNode node; /* The next node to use. */
size_t bucket; /* The next bucket to use. */
};
typedef struct _GSIMapEnumerator GSIMapEnumerator_t;
#endif
@ -260,33 +276,6 @@ GSIMapUnlinkNodeFromBucket(GSIMapBucket bucket, GSIMapNode node)
node->nextInBucket = 0;
}
static INLINE void
GSIMapLinkNodeIntoMap(GSIMapTable map, GSIMapNode node)
{
node->nextInMap = map->firstNode;
map->firstNode = node;
}
static INLINE void
GSIMapUnlinkNodeFromMap(GSIMapTable map, GSIMapNode node)
{
if (node == map->firstNode)
{
map->firstNode = node->nextInMap;
}
else
{
GSIMapNode tmp = map->firstNode;
while (tmp->nextInMap != node)
{
tmp = tmp->nextInMap;
}
tmp->nextInMap = node->nextInMap;
}
node->nextInMap = 0;
}
static INLINE void
GSIMapAddNodeToBucket(GSIMapBucket bucket, GSIMapNode node)
{
@ -301,7 +290,6 @@ GSIMapAddNodeToMap(GSIMapTable map, GSIMapNode node)
bucket = GSIMapBucketForKey(map, node->key);
GSIMapAddNodeToBucket(bucket, node);
GSIMapLinkNodeIntoMap(map, node);
map->nodeCount++;
}
@ -316,7 +304,6 @@ static INLINE void
GSIMapRemoveNodeFromMap(GSIMapTable map, GSIMapBucket bkt, GSIMapNode node)
{
map->nodeCount--;
GSIMapUnlinkNodeFromMap(map, node);
GSIMapRemoveNodeFromBucket(bkt, node);
}
@ -394,10 +381,10 @@ GSIMapMoreNodes(GSIMapTable map, unsigned required)
if (newNodes)
{
map->nodeChunks[map->chunkCount++] = newNodes;
newNodes[--chunkCount].nextInMap = map->freeNodes;
newNodes[--chunkCount].nextInBucket = map->freeNodes;
while (chunkCount--)
{
newNodes[chunkCount].nextInMap = &newNodes[chunkCount+1];
newNodes[chunkCount].nextInBucket = &newNodes[chunkCount+1];
}
map->freeNodes = newNodes;
}
@ -420,11 +407,10 @@ GSIMapNewNode(GSIMapTable map, GSIMapKey key, GSIMapVal value)
}
}
map->freeNodes = node->nextInMap;
map->freeNodes = node->nextInBucket;
node->key = key;
node->value = value;
node->nextInBucket = 0;
node->nextInMap = 0;
return node;
}
@ -444,10 +430,9 @@ GSIMapNewNode(GSIMapTable map, GSIMapKey key)
}
}
map->freeNodes = node->nextInMap;
map->freeNodes = node->nextInBucket;
node->key = key;
node->nextInBucket = 0;
node->nextInMap = 0;
return node;
}
#endif
@ -456,10 +441,13 @@ static INLINE void
GSIMapFreeNode(GSIMapTable map, GSIMapNode node)
{
GSI_MAP_RELEASE_KEY(map, node->key);
GSI_MAP_CLEAR_KEY(node);
#if GSI_MAP_HAS_VALUE
GSI_MAP_RELEASE_VAL(map, node->value);
GSI_MAP_CLEAR_VAL(node);
#endif
node->nextInMap = map->freeNodes;
node->nextInBucket = map->freeNodes;
map->freeNodes = node;
}
@ -592,7 +580,8 @@ GSIMapEnumeratorForMap(GSIMapTable map)
GSIMapEnumerator_t enumerator;
enumerator.map = map;
enumerator.node = map->firstNode;
enumerator.node = 0;
enumerator.bucket = 0;
return enumerator;
}
@ -601,11 +590,16 @@ static INLINE GSIMapNode
GSIMapEnumeratorNextNode(GSIMapEnumerator enumerator)
{
GSIMapNode node;
int bucketCount = ((GSIMapTable)enumerator->map)->bucketCount;
node = enumerator->node;
while(!node && enumerator->bucket < bucketCount)
{
node = (((GSIMapTable)enumerator->map)->buckets[enumerator->bucket]).firstNode;
enumerator->bucket++;
}
if (node != 0)
enumerator->node = node->nextInMap;
enumerator->node = node->nextInBucket;
/* Send back NODE. */
return node;
@ -680,17 +674,13 @@ static INLINE void
GSIMapRemoveKey(GSIMapTable map, GSIMapKey key)
{
GSIMapBucket bucket = GSIMapBucketForKey(map, key);
if (bucket != 0)
GSIMapNode node;
node = GSIMapNodeForKeyInBucket(map, bucket, key);
if (node != 0)
{
GSIMapNode node;
node = GSIMapNodeForKeyInBucket(map, bucket, key);
if (node != 0)
{
GSIMapRemoveNodeFromMap(map, bucket, node);
GSIMapFreeNode(map, node);
}
GSIMapRemoveNodeFromMap(map, bucket, node);
GSIMapFreeNode(map, node);
}
}
@ -701,35 +691,36 @@ GSIMapCleanMap(GSIMapTable map)
{
GSIMapBucket bucket = map->buckets;
int i;
GSIMapNode start = map->firstNode;
GSIMapNode node = start;
unsigned int end = map->nodeCount - 1;
GSIMapNode startNode = 0;
GSIMapNode prevNode = 0;
GSIMapNode node;
map->nodeCount = 0;
map->firstNode = 0;
for (i = 0; i < map->bucketCount; i++)
{
node = bucket->firstNode;
if(prevNode)
prevNode->nextInBucket = node;
else
startNode = node;
while(node != 0)
{
GSI_MAP_RELEASE_KEY(map, node->key);
#if GSI_MAP_HAS_VALUE
GSI_MAP_RELEASE_VAL(map, node->value);
#endif
prevNode = node;
node = node->nextInBucket;
}
bucket->nodeCount = 0;
bucket->firstNode = 0;
bucket++;
}
for (i = 0; i < end; i++)
{
GSI_MAP_RELEASE_KEY(map, node->key);
#if GSI_MAP_HAS_VALUE
GSI_MAP_RELEASE_VAL(map, node->value);
#endif
node->nextInBucket = 0;
node = node->nextInMap;
}
GSI_MAP_RELEASE_KEY(map, node->key);
#if GSI_MAP_HAS_VALUE
GSI_MAP_RELEASE_VAL(map, node->value);
#endif
node->nextInBucket = 0;
node->nextInMap = map->freeNodes;
map->freeNodes = start;
}
prevNode->nextInBucket = map->freeNodes;
map->freeNodes = startNode;
}
}
static INLINE void
@ -740,7 +731,6 @@ GSIMapEmptyMap(GSIMapTable map)
#ifdef GSI_MAP_NOCLEAN
if (GSI_MAP_NOCLEAN)
{
map->firstNode = 0;
map->nodeCount = 0;
}
else
@ -776,7 +766,6 @@ GSIMapInitWithZoneAndCapacity(GSIMapTable map, NSZone *zone, size_t capacity)
map->zone = zone;
map->nodeCount = 0;
map->bucketCount = 0;
map->firstNode = 0;
map->buckets = 0;
map->nodeChunks = 0;
map->freeNodes = 0;

View file

@ -44,7 +44,7 @@ typedef void* NSHashTable;
* Type for enumerating.
* NB. layout *must* correspond to that used by the GSIMap code.
*/
typedef struct { void *map; void *node; } NSHashEnumerator;
typedef struct { void *map; void *node; size_t bucket; } NSHashEnumerator;
/** Callback functions. <br />*/
typedef struct _NSHashTableCallBacks

View file

@ -43,7 +43,7 @@ typedef void *NSMapTable;
* Type for enumerating.
* NB. layout *must* correspond to that used by the GSIMap code.
*/
typedef struct { void *map; void *node; } NSMapEnumerator;
typedef struct { void *map; void *node; size_t bucket; } NSMapEnumerator;
/* Callback functions for a key. */
typedef struct _NSMapTableKeyCallBacks

View file

@ -3029,7 +3029,7 @@ static NSCharacterSet *tokenSet = nil;
}
/**
* Convenience method to set the content of the document aslong with
* Convenience method to set the content of the document along with
* creating a content-type header for it.
*/
- (BOOL) setContent: (id)newContent

View file

@ -464,6 +464,7 @@ static SEL eqSel;
}
_count--;
RELEASE(_contents_array[_count]);
_contents_array[_count] = 0;
}
- (void) removeObject: (id)anObject
@ -504,6 +505,7 @@ static SEL eqSel;
_contents_array[pos-1] = _contents_array[pos];
}
_count--;
_contents_array[_count] = 0;
RELEASE(obj);
}
}
@ -533,6 +535,7 @@ static SEL eqSel;
_contents_array[index] = _contents_array[index+1];
index++;
}
_contents_array[_count] = 0;
RELEASE(obj); /* Adjust array BEFORE releasing object. */
}
@ -560,6 +563,7 @@ static SEL eqSel;
_contents_array[pos-1] = _contents_array[pos];
}
_count--;
_contents_array[_count] = 0;
RELEASE(obj);
}
}

View file

@ -129,7 +129,12 @@ static Class mutableSetClass;
{
if (map.nodeCount > 0)
{
return map.firstNode->key.obj;
GSIMapBucket bucket = map.buckets;
while(1)
if(bucket->firstNode)
return bucket->firstNode->key.obj;
else
bucket++;
}
else
{

View file

@ -1285,9 +1285,12 @@ static Class tcpPortClass;
h->myLock = [NSRecursiveLock new];
}
}
NSEndMapTableEnumeration(&hEnum);
}
}
NSEndMapTableEnumeration(&mEnum);
}
NSEndMapTableEnumeration(&pEnum);
}
[[NSNotificationCenter defaultCenter]
removeObserver: self
@ -1656,6 +1659,7 @@ static Class tcpPortClass;
fds[(*count)++] = sock;
}
}
NSEndMapTableEnumeration(&me);
DO_UNLOCK(myLock);
}
@ -1675,9 +1679,11 @@ static Class tcpPortClass;
if ([handle recvPort] == recvPort)
{
DO_UNLOCK(myLock);
NSEndMapTableEnumeration(&me);
return handle;
}
}
NSEndMapTableEnumeration(&me);
if (handle == nil)
{
int opt = 1;

View file

@ -517,13 +517,15 @@ _bundle_load_callback(Class theClass, struct objc_category *theCategory)
while (NSNextMapEnumeratorPair(&enumerate, &key, (void **)&bundle))
{
if (bundle->_bundleType == NSBUNDLE_FRAMEWORK)
continue;
{
continue;
}
if ([array indexOfObjectIdenticalTo: bundle] == NSNotFound)
{
[array addObject: bundle];
}
}
NSEndMapTableEnumeration(&enumerate);
}
[load_lock unlock];
return array;
@ -546,6 +548,7 @@ _bundle_load_callback(Class theClass, struct objc_category *theCategory)
[array addObject: bundle];
}
}
NSEndMapTableEnumeration(&enumerate);
[load_lock unlock];
return array;
}

View file

@ -292,6 +292,7 @@ existingConnection(NSPort *receivePort, NSPort *sendPort)
break;
}
}
NSEndHashTableEnumeration(&enumerator);
F_UNLOCK(connection_table_gate);
return c;
}
@ -381,6 +382,7 @@ static BOOL multi_threaded = NO;
c->_refGate = [NSRecursiveLock new];
}
}
NSEndHashTableEnumeration(&enumerator);
}
[[NSNotificationCenter defaultCenter]
removeObserver: self
@ -2067,6 +2069,7 @@ static void retEncoder (DOContext *ctxt)
count++;
}
}
NSEndHashTableEnumeration(&enumerator);
M_UNLOCK(connection_table_gate);
return count;

View file

@ -977,7 +977,7 @@ failure:
#if GS_WITH_GC == 0
*(char**)data = (char*)NSZoneMalloc(NSDefaultMallocZone(), len);
#else
*(char**)data = (char*)NSZoneMalloc(NSAtomicMallocZone(), len);
*(char**)data = (char*)NSZoneMalloc(GSAtomicMallocZone(), len);
#endif
}
@ -1044,7 +1044,7 @@ failure:
#if GS_WITH_GC == 0
*(char**)data = (char*)NSZoneMalloc(NSDefaultMallocZone(), len);
#else
*(char**)data = (char*)NSZoneMalloc(NSAtomicMallocZone(), len);
*(char**)data = (char*)NSZoneMalloc(GSAtomicMallocZone(), len);
#endif
[self deserializeDataAt: *(char**)data
ofObjCType: type
@ -2096,7 +2096,7 @@ getBytes(void* dst, void* src, unsigned len, unsigned limit, unsigned *pos)
#if GS_WITH_GC == 0
*(char**)data = (char*)NSZoneMalloc(NSDefaultMallocZone(), len+1);
#else
*(char**)data = (char*)NSZoneMalloc(NSAtomicMallocZone(), len+1);
*(char**)data = (char*)NSZoneMalloc(GSAtomicMallocZone(), len+1);
#endif
}
getBytes(*(void**)data, bytes, len, length, cursor);
@ -2160,7 +2160,7 @@ getBytes(void* dst, void* src, unsigned len, unsigned limit, unsigned *pos)
#if GS_WITH_GC == 0
*(char**)data = (char*)NSZoneMalloc(NSDefaultMallocZone(), len);
#else
*(char**)data = (char*)NSZoneMalloc(NSAtomicMallocZone(), len);
*(char**)data = (char*)NSZoneMalloc(GSAtomicMallocZone(), len);
#endif
[self deserializeDataAt: *(char**)data
ofObjCType: type

View file

@ -122,15 +122,14 @@ NSCompareHashTables(NSHashTable *table1, NSHashTable *table2)
}
else
{
GSIMapNode n = t1->firstNode;
while (n != 0)
{
NSHashEnumerator enumerator = GSIMapEnumeratorForMap((GSIMapTable)t1);
GSIMapNode n;
while ((n = GSIMapEnumeratorNextNode(&enumerator)) != 0)
{
if (GSIMapNodeForKey(t2, n->key) == 0)
{
return NO;
}
n = n->nextInMap;
}
return YES;
}
@ -144,7 +143,8 @@ NSCopyHashTableWithZone(NSHashTable *table, NSZone *zone)
{
GSIMapTable t;
GSIMapNode n;
NSHashEnumerator enumerator;
if (table == 0)
{
NSWarnFLog(@"Nul table argument supplied");
@ -154,11 +154,10 @@ NSCopyHashTableWithZone(NSHashTable *table, NSZone *zone)
t = (GSIMapTable)NSZoneMalloc(zone, sizeof(GSIMapTable_t));
GSIMapInitWithZoneAndCapacity(t, zone, ((GSIMapTable)table)->nodeCount);
t->extra = ((GSIMapTable)table)->extra;
n = ((GSIMapTable)table)->firstNode;
while (n != 0)
enumerator = GSIMapEnumeratorForMap((GSIMapTable)table);
while ((n = GSIMapEnumeratorNextNode(&enumerator)) != 0)
{
GSIMapAddKey(t, n->key);
n = n->nextInMap;
}
return (NSHashTable*)t;
@ -225,7 +224,7 @@ NSCreateHashTableWithZone(
/**
* Function to be called when finished with the enumerator.
* Not required in GNUstep ... just provided for MacOS-X compatibility.
* This permits memory used by the enumerator to be released.
*/
void
NSEndHashTableEnumeration(NSHashEnumerator *enumerator)
@ -233,7 +232,11 @@ NSEndHashTableEnumeration(NSHashEnumerator *enumerator)
if (enumerator == 0)
{
NSWarnFLog(@"Nul enumerator argument supplied");
return;
}
#if GS_WITH_GC
memset(enumerator, 0, sizeof(*enumerator));
#endif
}
/**
@ -245,7 +248,7 @@ NSEnumerateHashTable(NSHashTable *table)
{
if (table == 0)
{
NSHashEnumerator v = { 0, 0 };
NSHashEnumerator v = { 0, 0, 0 };
NSWarnFLog(@"Nul table argument supplied");
return v;

View file

@ -99,6 +99,7 @@ NSAllMapTableKeys(NSMapTable *table)
{
[keyArray addObject: key];
}
NSEndMapTableEnumeration(&enumerator);
return keyArray;
}
@ -131,6 +132,7 @@ NSAllMapTableValues(NSMapTable *table)
{
[valueArray addObject: value];
}
NSEndMapTableEnumeration(&enumerator);
return valueArray;
}
@ -169,16 +171,15 @@ NSCompareMapTables(NSMapTable *table1, NSMapTable *table2)
}
else
{
GSIMapNode n = t1->firstNode;
while (n != 0)
{
if (GSIMapNodeForKey(t2, n->key) == 0)
{
return NO;
}
n = n->nextInMap;
}
NSMapEnumerator enumerator = GSIMapEnumeratorForMap((GSIMapTable)t1);
GSIMapNode n;
while ((n = GSIMapEnumeratorNextNode(&enumerator)) != 0)
{
if (GSIMapNodeForKey(t2, n->key) == 0)
{
return NO;
}
}
return YES;
}
}
@ -191,7 +192,8 @@ NSCopyMapTableWithZone(NSMapTable *table, NSZone *zone)
{
GSIMapTable t;
GSIMapNode n;
NSMapEnumerator enumerator;
if (table == 0)
{
NSWarnFLog(@"Nul table argument supplied");
@ -202,11 +204,10 @@ NSCopyMapTableWithZone(NSMapTable *table, NSZone *zone)
GSIMapInitWithZoneAndCapacity(t, zone, ((GSIMapTable)table)->nodeCount);
t->extra.k = ((GSIMapTable)table)->extra.k;
t->extra.v = ((GSIMapTable)table)->extra.v;
n = ((GSIMapTable)table)->firstNode;
while (n != 0)
enumerator = GSIMapEnumeratorForMap((GSIMapTable)table);
while ((n = GSIMapEnumeratorNextNode(&enumerator)) != 0)
{
GSIMapAddPair(t, n->key, n->value);
n = n->nextInMap;
}
return (NSMapTable*)t;
@ -284,7 +285,7 @@ NSCreateMapTableWithZone(
/**
* Function to be called when finished with the enumerator.
* Not required in GNUstep ... just provided for MacOS-X compatibility.
* This permits memory used by the enumerator to be released!
*/
void
NSEndMapTableEnumeration(NSMapEnumerator *enumerator)
@ -292,7 +293,11 @@ NSEndMapTableEnumeration(NSMapEnumerator *enumerator)
if (enumerator == 0)
{
NSWarnFLog(@"Nul enumerator argument supplied");
return;
}
#if GS_WITH_GC
memset(enumerator, 0, sizeof(*enumerator));
#endif
}
/**
@ -608,6 +613,7 @@ NSStringFromMapTable(NSMapTable *table)
(t->extra.k.describe)(table, key),
(t->extra.v.describe)(table, value)];
}
NSEndMapTableEnumeration(&enumerator);
return string;
}

View file

@ -52,9 +52,11 @@
extern BOOL __objc_responds_to(id, SEL);
#endif
#if GS_WITH_GC == 0
@class _FastMallocBuffer;
static Class fastMallocClass;
static unsigned fastMallocOffset;
#endif
static Class NSConstantStringClass;
@ -726,15 +728,13 @@ static BOOL double_release_check_enabled = NO;
autorelease_class = [NSAutoreleasePool class];
autorelease_sel = @selector(addObject:);
autorelease_imp = [autorelease_class methodForSelector: autorelease_sel];
fastMallocClass = [_FastMallocBuffer class];
#if GS_WITH_GC == 0
fastMallocClass = [_FastMallocBuffer class];
#if !defined(REFCNT_LOCAL)
GSIMapInitWithZoneAndCapacity(&retain_counts,
NSDefaultMallocZone(), 1024);
#endif
fastMallocOffset = fastMallocClass->instance_size % ALIGN;
#else
fastMallocOffset = 0;
#endif
NSConstantStringClass = [NSString constantStringClass];
GSBuildStrings();
@ -1584,11 +1584,13 @@ static BOOL double_release_check_enabled = NO;
/*
* Stuff for temporary memory management.
*/
#if GS_WITH_GC == 0
@interface _FastMallocBuffer : NSObject
@end
@implementation _FastMallocBuffer
@end
#endif
/*
* Function for giving us the fastest possible allocation of memory to
@ -1597,12 +1599,16 @@ static BOOL double_release_check_enabled = NO;
void *
_fastMallocBuffer(unsigned size)
{
#if GS_WITH_GC
return GC_malloc(size);
#else
_FastMallocBuffer *o;
o = (_FastMallocBuffer*)NSAllocateObject(fastMallocClass,
size + fastMallocOffset, NSDefaultMallocZone());
(*autorelease_imp)(autorelease_class, autorelease_sel, o);
return ((void*)&o[1])+fastMallocOffset;
#endif
}

View file

@ -1382,6 +1382,7 @@ if (0) {
}
}
}
NSEndMapTableEnumeration(&enumerator);
/*
* Finally, fire the requests.
@ -2115,6 +2116,7 @@ if (0) {
}
}
}
NSEndMapTableEnumeration(&enumerator);
}
- (void) configureAsServer