Skip to content

Commit

Permalink
Merge pull request cc65#2384 from colinleroy/asm-realloc
Browse files Browse the repository at this point in the history
Rewrite realloc in asm
  • Loading branch information
mrdudz authored Jan 26, 2024
2 parents 782dad2 + a8b8705 commit 8682095
Show file tree
Hide file tree
Showing 2 changed files with 213 additions and 114 deletions.
114 changes: 0 additions & 114 deletions libsrc/common/realloc.c

This file was deleted.

213 changes: 213 additions & 0 deletions libsrc/common/realloc.s
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit 8682095

Please sign in to comment.