Skip to content

Commit a8b8705

Browse files
committed
Rewrite realloc in asm
-80 bytes, -39% cycles
1 parent 6593768 commit a8b8705

File tree

2 files changed

+213
-114
lines changed

2 files changed

+213
-114
lines changed

libsrc/common/realloc.c

Lines changed: 0 additions & 114 deletions
This file was deleted.

libsrc/common/realloc.s

Lines changed: 213 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,213 @@
1+
;
2+
; Colin Leroy-Mira, 2024
3+
;
4+
; void* __fastcall__ realloc (void* block, register size_t size)
5+
;
6+
7+
.importzp ptr1, ptr2, ptr3, ptr4, tmp1, tmp2, tmp3, tmp4, sp
8+
.import _malloc, _memcpy, _free
9+
.import pushax, popptr1, return0
10+
.import incsp2, decsp2
11+
.export _realloc
12+
13+
.include "_heap.inc"
14+
15+
.macpack generic
16+
17+
;----------------------------------------------------------------------------
18+
; Aliases for clarity
19+
20+
block = ptr1
21+
size = ptr2
22+
ublock = ptr3
23+
oldsize = ptr4
24+
newblock = tmp1 ; (and tmp2)
25+
orgblock = tmp3 ; (and tmp4)
26+
27+
;----------------------------------------------------------------------------
28+
; Code
29+
30+
_realloc:
31+
sta size ; Store size
32+
stx size+1
33+
34+
jsr popptr1 ; Pop block
35+
36+
lda block+1 ; Is block null?
37+
tax
38+
ora block
39+
bne :+
40+
41+
lda size ; Block is null, just malloc
42+
ldx size+1
43+
jmp _malloc
44+
45+
: lda size ; Is size 0?
46+
ora size+1
47+
bne :+
48+
49+
lda block ; It is: free block (high byte already in X)
50+
jsr _free
51+
jmp return0
52+
53+
: clc ; Add internal used size
54+
lda size
55+
adc #HEAP_ADMIN_SPACE
56+
sta size
57+
bcc :+
58+
inc size+1
59+
bne :+
60+
61+
lda #$00 ; Size high byte now 0: We overflowed!
62+
tax
63+
rts
64+
65+
: ldx size+1 ; Should we round size up?
66+
bne :+
67+
cmp #.sizeof (freeblock)
68+
bcs :+
69+
70+
lda #.sizeof (freeblock)
71+
sta size ; (we presuppose that sizeof (freeblock) is < 256)
72+
73+
: lda block ; Get pointer to raw memory block
74+
sta orgblock ; Store original pointer
75+
sec
76+
sbc #.sizeof(usedblock)
77+
sta ublock
78+
lda block+1
79+
sta orgblock+1 ; Finish storing original pointer
80+
sbc #0
81+
sta ublock+1 ; We have our usedblock struct
82+
83+
; Get block start
84+
ldy #usedblock::start+1
85+
lda (ublock),y
86+
tax ; Backup ublock high
87+
dey
88+
lda (ublock),y
89+
90+
sta ublock ; Store ublock
91+
stx ublock+1
92+
93+
; Remember oldsize
94+
ldy #usedblock::size+1
95+
lda (ublock),y
96+
sta oldsize+1
97+
dey
98+
lda (ublock),y
99+
sta oldsize
100+
101+
clc ; Is the block at heap top?
102+
adc ublock
103+
tay
104+
lda ublock+1
105+
adc oldsize+1
106+
cmp ___heapptr+1
107+
bne must_malloc_new
108+
cpy ___heapptr
109+
bne must_malloc_new
110+
111+
tya ; Put ___heapptr back in A
112+
sec ; Check if we have enough memory at heap top
113+
sbc oldsize ; Substract oldsize
114+
sta newblock
115+
lda ___heapptr+1
116+
sbc oldsize+1
117+
sta newblock+1
118+
clc
119+
lda newblock ; And add size
120+
adc size
121+
sta newblock
122+
lda newblock+1
123+
adc size+1
124+
sta newblock+1
125+
bcs must_malloc_new ; If we have a carry there we overflowed
126+
127+
cmp ___heapend+1
128+
bne :+
129+
lda newblock
130+
cmp ___heapend
131+
: bcc :+
132+
bne must_malloc_new
133+
134+
: lda newblock ; There is enough space
135+
sta ___heapptr ; Update heapptr
136+
lda newblock+1
137+
sta ___heapptr+1
138+
139+
ldy #usedblock::start+1
140+
lda ublock+1
141+
sta (ublock),y ; Update block start
142+
dey
143+
lda ublock
144+
sta (ublock),y
145+
dey
146+
147+
.assert usedblock::size = usedblock::start-2, error
148+
lda size+1
149+
sta (ublock),y ; Update block size
150+
dey
151+
lda size
152+
sta (ublock),y
153+
154+
lda orgblock ; Return original block
155+
ldx orgblock+1
156+
rts
157+
158+
must_malloc_new: ; The block is not at heap top, or too big
159+
lda size+1
160+
pha ; Backup new size (at this point the only ptr
161+
tax ; we'll need after malloc). tmp* are safe
162+
lda size ; from malloc, memcpy and free.
163+
pha
164+
jsr _malloc
165+
166+
cmp #$00 ; Did malloc succeed?
167+
bne :+
168+
cpx #$00
169+
bne :+
170+
pla ; Pop size backup and return NULL
171+
pla
172+
txa ; X already 0
173+
rts ; No
174+
175+
: sta newblock ; Yes, store newblock
176+
stx newblock+1
177+
jsr pushax ; Push newblock for memcpy
178+
179+
lda orgblock ; Push orgblock for memcpy
180+
ldx orgblock+1
181+
jsr pushax
182+
183+
sec ; Remove admin space from oldsize
184+
lda oldsize
185+
sbc #<HEAP_ADMIN_SPACE
186+
sta oldsize
187+
lda oldsize+1
188+
sbc #>HEAP_ADMIN_SPACE
189+
sta oldsize+1
190+
191+
pla ; Restore new size to AX
192+
tay
193+
pla
194+
tax
195+
tya
196+
197+
cmp oldsize ; Find the smallest size
198+
bcc :+
199+
cpx oldsize+1
200+
bcc :+
201+
202+
lda oldsize
203+
ldx oldsize+1
204+
205+
: jsr _memcpy ; And copy data
206+
207+
lda orgblock ; Free old block
208+
ldx orgblock+1
209+
jsr _free
210+
211+
lda newblock ; Return new block
212+
ldx newblock+1
213+
rts

0 commit comments

Comments
 (0)