@@ -59,17 +59,21 @@ #elif defined(OF_THREADS) # import "threading.h" #endif struct pre_ivar { - int32_t retainCount; - void **memoryChunks; - unsigned int memoryChunksSize; + int32_t retainCount; + struct pre_mem *firstMem, *lastMem; #if !defined(OF_ATOMIC_OPS) && defined(OF_THREADS) of_spinlock_t retainCountSpinlock; #endif }; + +struct pre_mem { + id owner; + struct pre_mem *prev, *next; +}; /* Hopefully no arch needs more than 16 bytes padding */ #ifndef __BIGGEST_ALIGNMENT__ # define __BIGGEST_ALIGNMENT__ 16 #endif @@ -76,10 +80,14 @@ #define PRE_IVAR_ALIGN ((sizeof(struct pre_ivar) + \ (__BIGGEST_ALIGNMENT__ - 1)) & ~(__BIGGEST_ALIGNMENT__ - 1)) #define PRE_IVAR ((struct pre_ivar*)(void*)((char*)self - PRE_IVAR_ALIGN)) +#define PRE_MEM_ALIGN ((sizeof(struct pre_mem) + \ + (__BIGGEST_ALIGNMENT__ - 1)) & ~(__BIGGEST_ALIGNMENT__ - 1)) +#define PRE_MEM(mem) ((struct pre_mem*)(void*)((char*)mem - PRE_MEM_ALIGN)) + #ifdef OF_OLD_GNU_RUNTIME extern void __objc_update_dispatch_table_for_class(Class); #endif static struct { @@ -236,12 +244,10 @@ if ((instance = calloc(instanceSize + PRE_IVAR_ALIGN, 1)) == NULL) { alloc_failed_exception.isa = [OFAllocFailedException class]; @throw (OFAllocFailedException*)&alloc_failed_exception; } - ((struct pre_ivar*)instance)->memoryChunks = NULL; - ((struct pre_ivar*)instance)->memoryChunksSize = 0; ((struct pre_ivar*)instance)->retainCount = 1; #if !defined(OF_ATOMIC_OPS) && defined(OF_THREADS) if (!of_spinlock_new( &((struct pre_ivar*)instance)->retainCountSpinlock)) { @@ -751,63 +757,33 @@ { /* Classes containing data should reimplement this! */ return [OFString stringWithFormat: @"<%@: %p>", [self className], self]; } -- (void)addMemoryToPool: (void*)pointer -{ - void **memoryChunks; - unsigned int memoryChunksSize; - - memoryChunksSize = PRE_IVAR->memoryChunksSize + 1; - - if (UINT_MAX - PRE_IVAR->memoryChunksSize < 1 || - memoryChunksSize > UINT_MAX / sizeof(void*)) - @throw [OFOutOfRangeException exceptionWithClass: isa]; - - if ((memoryChunks = realloc(PRE_IVAR->memoryChunks, - memoryChunksSize * sizeof(void*))) == NULL) - @throw [OFOutOfMemoryException - exceptionWithClass: isa - requestedSize: memoryChunksSize]; - - PRE_IVAR->memoryChunks = memoryChunks; - PRE_IVAR->memoryChunks[PRE_IVAR->memoryChunksSize] = pointer; - PRE_IVAR->memoryChunksSize = memoryChunksSize; -} - -- (void*)allocMemoryWithSize: (size_t)size -{ - void *pointer, **memoryChunks; - unsigned int memoryChunksSize; - - if (size == 0) - return NULL; - - memoryChunksSize = PRE_IVAR->memoryChunksSize + 1; - - if (UINT_MAX - PRE_IVAR->memoryChunksSize == 0 || - memoryChunksSize > UINT_MAX / sizeof(void*)) - @throw [OFOutOfRangeException exceptionWithClass: isa]; - - if ((pointer = malloc(size)) == NULL) - @throw [OFOutOfMemoryException exceptionWithClass: isa - requestedSize: size]; - - if ((memoryChunks = realloc(PRE_IVAR->memoryChunks, - memoryChunksSize * sizeof(void*))) == NULL) { - free(pointer); - @throw [OFOutOfMemoryException - exceptionWithClass: isa - requestedSize: memoryChunksSize]; - } - - PRE_IVAR->memoryChunks = memoryChunks; - PRE_IVAR->memoryChunks[PRE_IVAR->memoryChunksSize] = pointer; - PRE_IVAR->memoryChunksSize = memoryChunksSize; - - return pointer; +- (void*)allocMemoryWithSize: (size_t)size +{ + void *pointer; + struct pre_mem *preMem; + + if (size > SIZE_MAX - PRE_IVAR_ALIGN) + @throw [OFOutOfRangeException exceptionWithClass: isa]; + + if ((pointer = malloc(PRE_MEM_ALIGN + size)) == NULL) + @throw [OFOutOfMemoryException exceptionWithClass: isa + requestedSize: size]; + preMem = pointer; + + preMem->owner = self; + preMem->prev = PRE_IVAR->lastMem; + preMem->next = NULL; + + if (PRE_IVAR->lastMem != NULL) + PRE_IVAR->lastMem->next = preMem; + + PRE_IVAR->lastMem = preMem; + + return (char*)pointer + PRE_MEM_ALIGN; } - (void*)allocMemoryForNItems: (size_t)nItems ofSize: (size_t)size { @@ -821,37 +797,44 @@ } - (void*)resizeMemory: (void*)pointer toSize: (size_t)size { - void **iter; + void *new; + struct pre_mem *preMem; if (pointer == NULL) return [self allocMemoryWithSize: size]; if (size == 0) { [self freeMemory: pointer]; return NULL; } - iter = PRE_IVAR->memoryChunks + PRE_IVAR->memoryChunksSize; - - while (iter-- > PRE_IVAR->memoryChunks) { - if (OF_UNLIKELY(*iter == pointer)) { - if (OF_UNLIKELY((pointer = realloc(pointer, - size)) == NULL)) - @throw [OFOutOfMemoryException - exceptionWithClass: isa - requestedSize: size]; - - *iter = pointer; - return pointer; - } - } - - @throw [OFMemoryNotPartOfObjectException exceptionWithClass: isa - pointer: pointer]; + if (PRE_MEM(pointer)->owner != self) + @throw [OFMemoryNotPartOfObjectException + exceptionWithClass: isa + pointer: pointer]; + + if ((new = realloc(PRE_MEM(pointer), PRE_MEM_ALIGN + size)) == NULL) + @throw [OFOutOfMemoryException exceptionWithClass: isa + requestedSize: size]; + preMem = new; + + if (preMem != PRE_MEM(pointer)) { + if (preMem->prev != NULL) + preMem->prev->next = preMem; + if (preMem->next != NULL) + preMem->next->prev = preMem; + + if (PRE_IVAR->firstMem == PRE_MEM(pointer)) + PRE_IVAR->firstMem = preMem; + if (PRE_IVAR->lastMem == PRE_MEM(pointer)) + PRE_IVAR->lastMem = preMem; + } + + return (char*)new + PRE_MEM_ALIGN; } - (void*)resizeMemory: (void*)pointer toNItems: (size_t)nItems ofSize: (size_t)size @@ -872,56 +855,32 @@ toSize: nItems * size]; } - (void)freeMemory: (void*)pointer { - void **iter, *last, **memoryChunks; - unsigned int i, memoryChunksSize; - if (pointer == NULL) return; - iter = PRE_IVAR->memoryChunks + PRE_IVAR->memoryChunksSize; - i = PRE_IVAR->memoryChunksSize; - - while (iter-- > PRE_IVAR->memoryChunks) { - i--; - - if (OF_UNLIKELY(*iter == pointer)) { - memoryChunksSize = PRE_IVAR->memoryChunksSize - 1; - last = PRE_IVAR->memoryChunks[memoryChunksSize]; - - assert(PRE_IVAR->memoryChunksSize != 0 && - memoryChunksSize <= UINT_MAX / sizeof(void*)); - - if (OF_UNLIKELY(memoryChunksSize == 0)) { - free(pointer); - free(PRE_IVAR->memoryChunks); - - PRE_IVAR->memoryChunks = NULL; - PRE_IVAR->memoryChunksSize = 0; - - return; - } - - free(pointer); - PRE_IVAR->memoryChunks[i] = last; - PRE_IVAR->memoryChunksSize = memoryChunksSize; - - if (OF_UNLIKELY((memoryChunks = realloc( - PRE_IVAR->memoryChunks, memoryChunksSize * - sizeof(void*))) == NULL)) - return; - - PRE_IVAR->memoryChunks = memoryChunks; - - return; - } - } - - @throw [OFMemoryNotPartOfObjectException exceptionWithClass: isa - pointer: pointer]; + if (PRE_MEM(pointer)->owner != self) + @throw [OFMemoryNotPartOfObjectException + exceptionWithClass: isa + pointer: pointer]; + + if (PRE_MEM(pointer)->prev != NULL) + PRE_MEM(pointer)->prev->next = PRE_MEM(pointer)->next; + if (PRE_MEM(pointer)->next != NULL) + PRE_MEM(pointer)->next->prev = PRE_MEM(pointer)->prev; + + if (PRE_IVAR->firstMem == PRE_MEM(pointer)) + PRE_IVAR->firstMem = PRE_MEM(pointer)->next; + if (PRE_IVAR->lastMem == PRE_MEM(pointer)) + PRE_IVAR->lastMem = PRE_MEM(pointer)->prev; + + /* To detect double-free */ + PRE_MEM(pointer)->owner = nil; + + free(PRE_MEM(pointer)); } - retain { #if defined(OF_ATOMIC_OPS) @@ -989,11 +948,11 @@ - (void)dealloc { Class class; void (*last)(id, SEL) = NULL; - void **iter; + struct pre_mem *iter; for (class = isa; class != Nil; class = class_getSuperclass(class)) { void (*destruct)(id, SEL); if ([class instancesRespondToSelector: cxx_destruct]) { @@ -1004,16 +963,18 @@ last = destruct; } else break; } - iter = PRE_IVAR->memoryChunks + PRE_IVAR->memoryChunksSize; - while (iter-- > PRE_IVAR->memoryChunks) - free(*iter); + iter = PRE_IVAR->firstMem; + while (iter != NULL) { + struct pre_mem *next = iter->next; + + free(iter); - if (PRE_IVAR->memoryChunks != NULL) - free(PRE_IVAR->memoryChunks); + iter = next; + } free((char*)self - PRE_IVAR_ALIGN); } /* Required to use properties with the Apple runtime */ @@ -1037,16 +998,10 @@ /* * Those are needed as the root class is the superclass of the root class's * metaclass and thus instance methods can be sent to class objects as well. */ -+ (void)addMemoryToPool: (void*)pointer -{ - @throw [OFNotImplementedException exceptionWithClass: self - selector: _cmd]; -} - + (void*)allocMemoryWithSize: (size_t)size { @throw [OFNotImplementedException exceptionWithClass: self selector: _cmd]; }