Changed the way, used blocks are managed

git-svn-id: svn://svn.cc65.org/cc65/trunk@3340 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
cuz
2004-12-19 23:09:38 +00:00
parent 49d1a47269
commit e55a4bcfd4
5 changed files with 83 additions and 41 deletions

View File

@@ -13,12 +13,19 @@
; probably not work. ; probably not work.
.struct freeblock .struct freeblock
size .word size .word
next .word next .addr
prev .word prev .addr
.endstruct
; Struct usedblock
; See notes above
.struct usedblock
size .word
start .addr
.endstruct .endstruct
HEAP_ADMIN_SPACE = 2
HEAP_MIN_BLOCKSIZE = .sizeof (freeblock) ; Minimum size of an allocated block HEAP_MIN_BLOCKSIZE = .sizeof (freeblock) ; Minimum size of an allocated block
HEAP_ADMIN_SPACE = .sizeof (usedblock) ; Additional space for used bocks
; Variables ; Variables
.global __heaporg .global __heaporg

View File

@@ -1,7 +1,7 @@
/* /*
* _heap.h * _heap.h
* *
* Ullrich von Bassewitz, 03.06.1998 * Ullrich von Bassewitz, 1998-06-03, 2004-12-19
* *
*/ */
@@ -12,12 +12,22 @@
/* Structure that preceeds a user block in most cases.
* The aligned_malloc function may generate blocks where the start pointer
* and size are splitted to handle a memory hole that is needed for
* alignment.
*/
struct usedblock {
unsigned size;
struct usedblock* start;
};
/* Space needed for administering used blocks */ /* Space needed for administering used blocks */
#define HEAP_ADMIN_SPACE sizeof (unsigned) #define HEAP_ADMIN_SPACE sizeof (struct usedblock)
/* The data type used to implement the free list. /* The data type used to implement the free list.
* Beware: Field order is significant! * Beware: Field order is significant!
*/ */
struct freeblock { struct freeblock {
unsigned size; unsigned size;
struct freeblock* next; struct freeblock* next;

View File

@@ -72,23 +72,32 @@
_free: sta ptr2 _free: sta ptr2
stx ptr2+1 ; Save block stx ptr2+1 ; Save block
; Is the argument NULL? ; Is the argument NULL? If so, bail out.
ora ptr2+1 ; Is the argument NULL? ora ptr2+1 ; Is the argument NULL?
beq @L9 ; Jump if yes bne @L0 ; Jump if no
rts ; Bail out if yes
; Decrement the given pointer by the admin space amount, so it points to the ; There's a pointer below the user space that points to the real start of the
; real block allocated. The size of the block is stored in the admin space. ; raw block. The first word of the raw block is the total size of the block.
; Remember the block size in ptr1. ; Remember the block size in ptr1.
lda ptr2 @L0: lda ptr2
sub #HEAP_ADMIN_SPACE sub #2
sta ptr2 sta ptr2
bcs @L1 bcs @L1
dec ptr2+1 dec ptr2+1
@L1: ldy #freeblock::size+1 @L1: ldy #1
lda (ptr2),y ; High byte of real block address
tax
dey
lda (ptr2),y
stx ptr2+1
sta ptr2 ; Set ptr2 to start of real block
ldy #usedblock::size+1
lda (ptr2),y ; High byte of size lda (ptr2),y ; High byte of size
sta ptr1+1 ; Save it sta ptr1+1 ; Save it
dey dey
lda (ptr2),y lda (ptr2),y
sta ptr1 sta ptr1
@@ -261,7 +270,7 @@ _free: sta ptr2
; } ; }
; } else { ; } else {
; f->prev = 0; ; f->prev = 0;
; /* Special case: This is the new freelist start */ ; /* Special case: This is the new freelist start */
; _hfirst = f; ; _hfirst = f;
; } ; }
; } ; }
@@ -530,3 +539,4 @@ NoLeftMerge:

View File

@@ -309,17 +309,27 @@ SliceBlock:
stx ptr2 stx ptr2
sta ptr2+1 sta ptr2+1
; Fill the size into the admin space of the block and return the user pointer ; Fill the size and start address into the admin space of the block
; (struct usedblock) and return the user pointer
FillSizeAndRet: FillSizeAndRet:
ldy #freeblock::size ; *p = size; ldy #usedblock::size ; p->size = size;
lda ptr1 ; Low byte of block size lda ptr1 ; Low byte of block size
sta (ptr2),y sta (ptr2),y
iny ; Points to freeblock::size+1 iny ; Points to freeblock::size+1
lda ptr1+1 lda ptr1+1
sta (ptr2),y sta (ptr2),y
RetUserPtr: RetUserPtr:
ldy #usedblock::start ; p->start = p
lda ptr2
sta (ptr2),y
iny
lda ptr2+1
sta (ptr2),y
; Return the user pointer, which points behind the struct usedblock
lda ptr2 ; return ++p; lda ptr2 ; return ++p;
ldx ptr2+1 ldx ptr2+1
add #HEAP_ADMIN_SPACE add #HEAP_ADMIN_SPACE

View File

@@ -6,7 +6,7 @@
/* */ /* */
/* */ /* */
/* */ /* */
/* (C) 1998-2002 Ullrich von Bassewitz */ /* (C) 1998-2004 Ullrich von Bassewitz */
/* Wacholderweg 14 */ /* Wacholderweg 14 */
/* D-70597 Stuttgart */ /* D-70597 Stuttgart */
/* EMail: uz@musoftware.de */ /* EMail: uz@musoftware.de */
@@ -41,9 +41,10 @@
void* __fastcall__ realloc (void* block, size_t size) void* __fastcall__ realloc (void* block, size_t size)
{ {
unsigned* b; struct usedblock* b;
unsigned* newblock; struct usedblock* newblock;
unsigned oldsize; unsigned oldsize;
unsigned newhptr;
int diff; int diff;
/* Check the block parameter */ /* Check the block parameter */
@@ -56,7 +57,7 @@ void* __fastcall__ realloc (void* block, size_t size)
if (size == 0) { if (size == 0) {
/* Block is not NULL, but size is: free the block */ /* Block is not NULL, but size is: free the block */
free (block); free (block);
return 0; return 0;
} }
/* Make the internal used size from the given size */ /* Make the internal used size from the given size */
@@ -65,22 +66,26 @@ void* __fastcall__ realloc (void* block, size_t size)
size = sizeof (struct freeblock); size = sizeof (struct freeblock);
} }
/* Get a pointer to the real block, get the old block size */ /* The word below the user block contains a pointer to the start of the
b = (unsigned*) (((int) block) - 2); * raw memory block. The first word of this raw memory block is the full
oldsize = *b; * size of the block. Get a pointer to the real block, get the old block
* size.
*/
b = (((struct usedblock*) block) - 1)->start;
oldsize = b->size;
/* Get the size difference as a signed quantity */ /* Get the size difference as a signed quantity */
diff = size - oldsize; diff = size - oldsize;
/* Is the block at the current heap top? */ /* Is the block at the current heap top? */
if (((int) b) + oldsize == ((int) _heapptr)) { if (((unsigned) b) + oldsize == ((unsigned) _heapptr)) {
/* Check if we've enough memory at the heap top */ /* Check if we've enough memory at the heap top */
int newhptr; newhptr = ((unsigned) _heapptr) + diff;
newhptr = ((int) _heapptr) + diff; if (newhptr <= ((unsigned) _heapend)) {
if (newhptr <= ((int) _heapend)) {
/* Ok, there's space enough */ /* Ok, there's space enough */
_heapptr = (unsigned*) newhptr; _heapptr = (unsigned*) newhptr;
*b = size; b->size = size;
b->start = b;
return block; return block;
} }
} }
@@ -90,17 +95,17 @@ void* __fastcall__ realloc (void* block, size_t size)
*/ */
if (newblock = malloc (size)) { if (newblock = malloc (size)) {
/* Adjust the old size to the user visible portion */ /* Adjust the old size to the user visible portion */
oldsize -= sizeof (unsigned); oldsize -= HEAP_ADMIN_SPACE;
/* If the new block is larger than the old one, copy the old /* If the new block is larger than the old one, copy the old
* data only * data only
*/ */
if (size > oldsize) { if (size > oldsize) {
size = oldsize; size = oldsize;
} }
/* Copy the block data */ /* Copy the block data */
memcpy (newblock, block, size); memcpy (newblock, block, size);
free (block); free (block);
} }
@@ -109,4 +114,4 @@ void* __fastcall__ realloc (void* block, size_t size)