mirror of
https://github.com/cc65/cc65.git
synced 2025-01-05 15:30:44 +00:00
Merge pull request #2384 from colinleroy/asm-realloc
Rewrite realloc in asm
This commit is contained in:
commit
8682095f9f
@ -1,114 +0,0 @@
|
|||||||
/*****************************************************************************/
|
|
||||||
/* */
|
|
||||||
/* realloc.c */
|
|
||||||
/* */
|
|
||||||
/* Change the size of an allocated memory block */
|
|
||||||
/* */
|
|
||||||
/* */
|
|
||||||
/* */
|
|
||||||
/* (C) 1998-2004 Ullrich von Bassewitz */
|
|
||||||
/* Wacholderweg 14 */
|
|
||||||
/* D-70597 Stuttgart */
|
|
||||||
/* EMail: uz@musoftware.de */
|
|
||||||
/* */
|
|
||||||
/* */
|
|
||||||
/* This software is provided 'as-is', without any expressed or implied */
|
|
||||||
/* warranty. In no event will the authors be held liable for any damages */
|
|
||||||
/* arising from the use of this software. */
|
|
||||||
/* */
|
|
||||||
/* Permission is granted to anyone to use this software for any purpose, */
|
|
||||||
/* including commercial applications, and to alter it and redistribute it */
|
|
||||||
/* freely, subject to the following restrictions: */
|
|
||||||
/* */
|
|
||||||
/* 1. The origin of this software must not be misrepresented; you must not */
|
|
||||||
/* claim that you wrote the original software. If you use this software */
|
|
||||||
/* in a product, an acknowledgment in the product documentation would be */
|
|
||||||
/* appreciated but is not required. */
|
|
||||||
/* 2. Altered source versions must be plainly marked as such, and must not */
|
|
||||||
/* be misrepresented as being the original software. */
|
|
||||||
/* 3. This notice may not be removed or altered from any source */
|
|
||||||
/* distribution. */
|
|
||||||
/* */
|
|
||||||
/*****************************************************************************/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <_heap.h>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void* __fastcall__ realloc (void* block, register size_t size)
|
|
||||||
{
|
|
||||||
register struct usedblock* b;
|
|
||||||
struct usedblock* newblock;
|
|
||||||
unsigned oldsize;
|
|
||||||
unsigned newhptr;
|
|
||||||
|
|
||||||
/* Check the block parameter */
|
|
||||||
if (!block) {
|
|
||||||
/* Block is NULL, same as malloc */
|
|
||||||
return malloc (size);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check the size parameter */
|
|
||||||
if (size == 0) {
|
|
||||||
/* Block is not NULL, but size is: free the block */
|
|
||||||
free (block);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Don't overflow! */
|
|
||||||
if (size > 0xFFFF - HEAP_ADMIN_SPACE) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Make the internal used size from the given size */
|
|
||||||
size += HEAP_ADMIN_SPACE;
|
|
||||||
if (size < sizeof (struct freeblock)) {
|
|
||||||
size = sizeof (struct freeblock);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The word below the user block contains a pointer to the start of the
|
|
||||||
** raw memory block. The first word of this raw memory block is the full
|
|
||||||
** 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;
|
|
||||||
|
|
||||||
/* Is the block at the current heap top? */
|
|
||||||
if (((unsigned) b) + oldsize == ((unsigned) __heapptr)) {
|
|
||||||
/* Check if we've enough memory at the heap top */
|
|
||||||
newhptr = ((unsigned) __heapptr) - oldsize + size;
|
|
||||||
if (newhptr <= ((unsigned) __heapend)) {
|
|
||||||
/* Ok, there's space enough */
|
|
||||||
__heapptr = (unsigned*) newhptr;
|
|
||||||
b->size = size;
|
|
||||||
b->start = b;
|
|
||||||
return block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The given block was not located on top of the heap, or there's no
|
|
||||||
** room left. Try to allocate a new block and copy the data.
|
|
||||||
*/
|
|
||||||
if (newblock = malloc (size)) {
|
|
||||||
|
|
||||||
/* Adjust the old size to the user visible portion */
|
|
||||||
oldsize -= HEAP_ADMIN_SPACE;
|
|
||||||
|
|
||||||
/* If the new block is larger than the old one, copy the old
|
|
||||||
** data only
|
|
||||||
*/
|
|
||||||
if (size > oldsize) {
|
|
||||||
size = oldsize;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Copy the block data */
|
|
||||||
memcpy (newblock, block, size);
|
|
||||||
free (block);
|
|
||||||
}
|
|
||||||
return newblock;
|
|
||||||
}
|
|
213
libsrc/common/realloc.s
Normal file
213
libsrc/common/realloc.s
Normal file
@ -0,0 +1,213 @@
|
|||||||
|
;
|
||||||
|
; Colin Leroy-Mira, 2024
|
||||||
|
;
|
||||||
|
; void* __fastcall__ realloc (void* block, register size_t size)
|
||||||
|
;
|
||||||
|
|
||||||
|
.importzp ptr1, ptr2, ptr3, ptr4, tmp1, tmp2, tmp3, tmp4, sp
|
||||||
|
.import _malloc, _memcpy, _free
|
||||||
|
.import pushax, popptr1, return0
|
||||||
|
.import incsp2, decsp2
|
||||||
|
.export _realloc
|
||||||
|
|
||||||
|
.include "_heap.inc"
|
||||||
|
|
||||||
|
.macpack generic
|
||||||
|
|
||||||
|
;----------------------------------------------------------------------------
|
||||||
|
; Aliases for clarity
|
||||||
|
|
||||||
|
block = ptr1
|
||||||
|
size = ptr2
|
||||||
|
ublock = ptr3
|
||||||
|
oldsize = ptr4
|
||||||
|
newblock = tmp1 ; (and tmp2)
|
||||||
|
orgblock = tmp3 ; (and tmp4)
|
||||||
|
|
||||||
|
;----------------------------------------------------------------------------
|
||||||
|
; Code
|
||||||
|
|
||||||
|
_realloc:
|
||||||
|
sta size ; Store size
|
||||||
|
stx size+1
|
||||||
|
|
||||||
|
jsr popptr1 ; Pop block
|
||||||
|
|
||||||
|
lda block+1 ; Is block null?
|
||||||
|
tax
|
||||||
|
ora block
|
||||||
|
bne :+
|
||||||
|
|
||||||
|
lda size ; Block is null, just malloc
|
||||||
|
ldx size+1
|
||||||
|
jmp _malloc
|
||||||
|
|
||||||
|
: lda size ; Is size 0?
|
||||||
|
ora size+1
|
||||||
|
bne :+
|
||||||
|
|
||||||
|
lda block ; It is: free block (high byte already in X)
|
||||||
|
jsr _free
|
||||||
|
jmp return0
|
||||||
|
|
||||||
|
: clc ; Add internal used size
|
||||||
|
lda size
|
||||||
|
adc #HEAP_ADMIN_SPACE
|
||||||
|
sta size
|
||||||
|
bcc :+
|
||||||
|
inc size+1
|
||||||
|
bne :+
|
||||||
|
|
||||||
|
lda #$00 ; Size high byte now 0: We overflowed!
|
||||||
|
tax
|
||||||
|
rts
|
||||||
|
|
||||||
|
: ldx size+1 ; Should we round size up?
|
||||||
|
bne :+
|
||||||
|
cmp #.sizeof (freeblock)
|
||||||
|
bcs :+
|
||||||
|
|
||||||
|
lda #.sizeof (freeblock)
|
||||||
|
sta size ; (we presuppose that sizeof (freeblock) is < 256)
|
||||||
|
|
||||||
|
: lda block ; Get pointer to raw memory block
|
||||||
|
sta orgblock ; Store original pointer
|
||||||
|
sec
|
||||||
|
sbc #.sizeof(usedblock)
|
||||||
|
sta ublock
|
||||||
|
lda block+1
|
||||||
|
sta orgblock+1 ; Finish storing original pointer
|
||||||
|
sbc #0
|
||||||
|
sta ublock+1 ; We have our usedblock struct
|
||||||
|
|
||||||
|
; Get block start
|
||||||
|
ldy #usedblock::start+1
|
||||||
|
lda (ublock),y
|
||||||
|
tax ; Backup ublock high
|
||||||
|
dey
|
||||||
|
lda (ublock),y
|
||||||
|
|
||||||
|
sta ublock ; Store ublock
|
||||||
|
stx ublock+1
|
||||||
|
|
||||||
|
; Remember oldsize
|
||||||
|
ldy #usedblock::size+1
|
||||||
|
lda (ublock),y
|
||||||
|
sta oldsize+1
|
||||||
|
dey
|
||||||
|
lda (ublock),y
|
||||||
|
sta oldsize
|
||||||
|
|
||||||
|
clc ; Is the block at heap top?
|
||||||
|
adc ublock
|
||||||
|
tay
|
||||||
|
lda ublock+1
|
||||||
|
adc oldsize+1
|
||||||
|
cmp ___heapptr+1
|
||||||
|
bne must_malloc_new
|
||||||
|
cpy ___heapptr
|
||||||
|
bne must_malloc_new
|
||||||
|
|
||||||
|
tya ; Put ___heapptr back in A
|
||||||
|
sec ; Check if we have enough memory at heap top
|
||||||
|
sbc oldsize ; Substract oldsize
|
||||||
|
sta newblock
|
||||||
|
lda ___heapptr+1
|
||||||
|
sbc oldsize+1
|
||||||
|
sta newblock+1
|
||||||
|
clc
|
||||||
|
lda newblock ; And add size
|
||||||
|
adc size
|
||||||
|
sta newblock
|
||||||
|
lda newblock+1
|
||||||
|
adc size+1
|
||||||
|
sta newblock+1
|
||||||
|
bcs must_malloc_new ; If we have a carry there we overflowed
|
||||||
|
|
||||||
|
cmp ___heapend+1
|
||||||
|
bne :+
|
||||||
|
lda newblock
|
||||||
|
cmp ___heapend
|
||||||
|
: bcc :+
|
||||||
|
bne must_malloc_new
|
||||||
|
|
||||||
|
: lda newblock ; There is enough space
|
||||||
|
sta ___heapptr ; Update heapptr
|
||||||
|
lda newblock+1
|
||||||
|
sta ___heapptr+1
|
||||||
|
|
||||||
|
ldy #usedblock::start+1
|
||||||
|
lda ublock+1
|
||||||
|
sta (ublock),y ; Update block start
|
||||||
|
dey
|
||||||
|
lda ublock
|
||||||
|
sta (ublock),y
|
||||||
|
dey
|
||||||
|
|
||||||
|
.assert usedblock::size = usedblock::start-2, error
|
||||||
|
lda size+1
|
||||||
|
sta (ublock),y ; Update block size
|
||||||
|
dey
|
||||||
|
lda size
|
||||||
|
sta (ublock),y
|
||||||
|
|
||||||
|
lda orgblock ; Return original block
|
||||||
|
ldx orgblock+1
|
||||||
|
rts
|
||||||
|
|
||||||
|
must_malloc_new: ; The block is not at heap top, or too big
|
||||||
|
lda size+1
|
||||||
|
pha ; Backup new size (at this point the only ptr
|
||||||
|
tax ; we'll need after malloc). tmp* are safe
|
||||||
|
lda size ; from malloc, memcpy and free.
|
||||||
|
pha
|
||||||
|
jsr _malloc
|
||||||
|
|
||||||
|
cmp #$00 ; Did malloc succeed?
|
||||||
|
bne :+
|
||||||
|
cpx #$00
|
||||||
|
bne :+
|
||||||
|
pla ; Pop size backup and return NULL
|
||||||
|
pla
|
||||||
|
txa ; X already 0
|
||||||
|
rts ; No
|
||||||
|
|
||||||
|
: sta newblock ; Yes, store newblock
|
||||||
|
stx newblock+1
|
||||||
|
jsr pushax ; Push newblock for memcpy
|
||||||
|
|
||||||
|
lda orgblock ; Push orgblock for memcpy
|
||||||
|
ldx orgblock+1
|
||||||
|
jsr pushax
|
||||||
|
|
||||||
|
sec ; Remove admin space from oldsize
|
||||||
|
lda oldsize
|
||||||
|
sbc #<HEAP_ADMIN_SPACE
|
||||||
|
sta oldsize
|
||||||
|
lda oldsize+1
|
||||||
|
sbc #>HEAP_ADMIN_SPACE
|
||||||
|
sta oldsize+1
|
||||||
|
|
||||||
|
pla ; Restore new size to AX
|
||||||
|
tay
|
||||||
|
pla
|
||||||
|
tax
|
||||||
|
tya
|
||||||
|
|
||||||
|
cmp oldsize ; Find the smallest size
|
||||||
|
bcc :+
|
||||||
|
cpx oldsize+1
|
||||||
|
bcc :+
|
||||||
|
|
||||||
|
lda oldsize
|
||||||
|
ldx oldsize+1
|
||||||
|
|
||||||
|
: jsr _memcpy ; And copy data
|
||||||
|
|
||||||
|
lda orgblock ; Free old block
|
||||||
|
ldx orgblock+1
|
||||||
|
jsr _free
|
||||||
|
|
||||||
|
lda newblock ; Return new block
|
||||||
|
ldx newblock+1
|
||||||
|
rts
|
Loading…
Reference in New Issue
Block a user