Commit | Line | Data |
---|---|---|
33309c6a JM |
1 | (module $mem |
2 | (global $MEM_SIZE i32 1048576) | |
3 | (global $STRING_MEM_SIZE i32 1048576) | |
4 | ||
5 | (global $heap_start (mut i32) 0) | |
6 | (global $heap_end (mut i32) 0) | |
7 | ||
8 | (global $mem (mut i32) 0) | |
9 | (global $mem_unused_start (mut i32) 0) | |
10 | (global $mem_free_list (mut i32) 0) | |
11 | (global $mem_user_start (mut i32) 0) | |
12 | ||
50eea9ad JM |
13 | (global $string_mem (mut i32) 0) |
14 | (global $string_mem_next (mut i32) 0) | |
15 | (global $string_mem_user_start (mut i32) 0) | |
33309c6a JM |
16 | |
17 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
18 | ;; General type storage/pointer functions | |
19 | ||
20 | (func $VAL0_ptr (param $mv i32) (result i32) | |
21 | (i32.add $mv 4)) | |
22 | (func $VAL1_ptr (param $mv i32) (result i32) | |
23 | (i32.add $mv 8)) | |
24 | ||
25 | (func $VAL0 (param $mv i32) (result i32) | |
26 | (i32.load (i32.add $mv 4))) | |
27 | (func $VAL1 (param $mv i32) (result i32) | |
28 | (i32.load (i32.add $mv 8))) | |
29 | ||
30 | ||
31 | (func $MEM_VAL0_ptr (param $mv i32) (result i32) | |
0a19c2f1 | 32 | (i32.add (global.get $mem) |
0c62f14e | 33 | (i32.mul (i32.load (i32.add $mv 4)) 4))) |
33309c6a | 34 | (func $MEM_VAL1_ptr (param $mv i32) (result i32) |
0a19c2f1 | 35 | (i32.add (global.get $mem) |
0c62f14e | 36 | (i32.mul (i32.load (i32.add $mv 8)) 4))) |
33309c6a | 37 | (func $MEM_VAL2_ptr (param $mv i32) (result i32) |
0a19c2f1 | 38 | (i32.add (global.get $mem) |
0c62f14e | 39 | (i32.mul (i32.load (i32.add $mv 12)) 4))) |
3ea09886 JM |
40 | |
41 | ;; Returns the memory index mem of mv | |
42 | ;; Will usually be used with a load or store by the caller | |
43 | (func $IDX (param $mv i32) (result i32) | |
44 | ;; MalVal memory 64 bit (2 * i32) aligned | |
0a19c2f1 | 45 | (i32.div_u (i32.sub $mv (global.get $mem)) 4)) |
33309c6a JM |
46 | |
47 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
48 | ||
49 | ;; Returns the address of 'mem[mv_idx]' | |
50 | (func $MalVal_ptr (param $mv_idx i32) (result i32) | |
51 | ;; MalVal memory 64 bit (2 * i32) aligned | |
52 | ;;; mem[mv_idx].refcnt_type | |
0a19c2f1 | 53 | (i32.add (global.get $mem) (i32.mul $mv_idx 4))) |
33309c6a JM |
54 | |
55 | ;; Returns the address of 'mem[mv_idx].refcnt_type' | |
56 | (func $MalVal_refcnt_type (param $mv_idx i32) (result i32) | |
57 | (i32.load ($MalVal_ptr $mv_idx))) | |
58 | ||
59 | (func $TYPE (param $mv i32) (result i32) | |
60 | ;;; type = mv->refcnt_type & 31 | |
61 | (i32.and (i32.load $mv) 0x1f)) ;; 0x1f == 31 | |
62 | ||
3ea09886 JM |
63 | (func $SET_TYPE (param $mv i32 $type i32) |
64 | ;;; type = mv->refcnt_type & 31 | |
65 | ;;; mv->refcnt_type += - (mv->refcnt_type & 31) + type | |
66 | (i32.store $mv (i32.or | |
67 | (i32.and $type 0x1f) ;; 0x1f == 31 | |
68 | (i32.and (i32.load $mv) 0xffffffe1))) | |
69 | ) | |
70 | ||
71 | ||
33309c6a JM |
72 | (func $REFS (param $mv i32) (result i32) |
73 | ;;; type = mv->refcnt_type & 31 | |
74 | (i32.shr_u (i32.load $mv) 5)) ;; / 32 | |
75 | ||
76 | ;; Returns the address of 'mem[mv_idx].val[val]' | |
77 | ;; Will usually be used with a load or store by the caller | |
3ea09886 | 78 | (func $MalVal_val_ptr (param $mv_idx i32 $val i32) (result i32) |
33309c6a | 79 | (i32.add (i32.add ($MalVal_ptr $mv_idx) 4) |
0c62f14e | 80 | (i32.mul $val 4))) |
33309c6a JM |
81 | |
82 | ;; Returns the value of 'mem[mv_idx].val[val]' | |
3ea09886 | 83 | (func $MalVal_val (param $mv_idx i32 $val i32) (result i32) |
33309c6a JM |
84 | (i32.load ($MalVal_val_ptr $mv_idx $val))) |
85 | ||
86 | (func $MalType_size (param $type i32) (result i32) | |
87 | ;;; if (type <= 5 || type == 9 || type == 12) | |
77bf4e61 | 88 | (if (result i32) (OR (i32.le_u $type 5) |
3ea09886 JM |
89 | (i32.eq $type 9) |
90 | (i32.eq $type 12)) | |
33309c6a JM |
91 | (then 2) |
92 | (else | |
93 | ;;; else if (type == 8 || type == 10 || type == 11) | |
77bf4e61 | 94 | (if (result i32) (OR (i32.eq $type 8) |
3ea09886 JM |
95 | (i32.eq $type 10) |
96 | (i32.eq $type 11)) | |
33309c6a JM |
97 | (then 4) |
98 | (else 3))))) | |
99 | ||
100 | (func $MalVal_size (param $mv i32) (result i32) | |
349faa83 | 101 | (LET $type ($TYPE $mv)) |
33309c6a | 102 | ;; if (type == FREE_T) |
0a19c2f1 | 103 | (if (result i32) (i32.eq $type (global.get $FREE_T)) |
33309c6a JM |
104 | (then |
105 | ;;; return (mv->refcnt_type & 0xffe0)>>5 | |
106 | (i32.shr_u (i32.and (i32.load $mv) 0xffe0) 5)) ;;; / 32 | |
107 | (else | |
108 | ;;; return MalType_size(type) | |
109 | ($MalType_size $type)))) | |
110 | ||
111 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
112 | ;; init_memory | |
113 | ||
114 | (func $init_memory | |
349faa83 | 115 | (LET $heap_size 0) |
33309c6a JM |
116 | |
117 | ;; ($print ">>> init_memory\n") | |
118 | ||
50eea9ad | 119 | ($init_printf_mem) |
33309c6a | 120 | |
3ea09886 | 121 | ;; error_str string buffer |
0a19c2f1 | 122 | (global.set $error_str (STATIC_ARRAY 100)) |
3ea09886 | 123 | ;; reader token string buffer |
0a19c2f1 | 124 | (global.set $token_buf (STATIC_ARRAY 256)) |
3ea09886 | 125 | ;; printer string buffer |
0a19c2f1 | 126 | (global.set $printer_buf (STATIC_ARRAY 4096)) |
33309c6a | 127 | |
0a19c2f1 JM |
128 | (local.set $heap_size (i32.add (global.get $MEM_SIZE) |
129 | (global.get $STRING_MEM_SIZE))) | |
130 | (global.set $heap_start (i32.add (global.get $memoryBase) | |
131 | (global.get $S_STRING_END))) | |
132 | (global.set $heap_end (i32.add (global.get $heap_start) | |
33309c6a JM |
133 | $heap_size)) |
134 | ||
0a19c2f1 JM |
135 | (global.set $mem (global.get $heap_start)) |
136 | (global.set $mem_unused_start 0) | |
137 | (global.set $mem_free_list 0) | |
33309c6a | 138 | |
0a19c2f1 JM |
139 | (global.set $string_mem (i32.add (global.get $heap_start) |
140 | (global.get $MEM_SIZE))) | |
141 | (global.set $string_mem_next (global.get $string_mem)) | |
50eea9ad | 142 | |
0a19c2f1 JM |
143 | (global.set $mem_user_start (global.get $mem_unused_start)) |
144 | (global.set $string_mem_user_start (global.get $string_mem_next)) | |
33309c6a JM |
145 | |
146 | ;; Empty values | |
0a19c2f1 JM |
147 | (global.set $NIL |
148 | ($ALLOC_SCALAR (global.get $NIL_T) 0)) | |
149 | (global.set $FALSE | |
150 | ($ALLOC_SCALAR (global.get $BOOLEAN_T) 0)) | |
151 | (global.set $TRUE | |
152 | ($ALLOC_SCALAR (global.get $BOOLEAN_T) 1)) | |
153 | (global.set $EMPTY_LIST | |
154 | ($ALLOC (global.get $LIST_T) | |
155 | (global.get $NIL) (global.get $NIL) (global.get $NIL))) | |
156 | (global.set $EMPTY_VECTOR | |
157 | ($ALLOC (global.get $VECTOR_T) | |
158 | (global.get $NIL) (global.get $NIL) (global.get $NIL))) | |
159 | (global.set $EMPTY_HASHMAP | |
160 | ($ALLOC (global.get $HASHMAP_T) | |
161 | (global.get $NIL) (global.get $NIL) (global.get $NIL))) | |
33309c6a JM |
162 | |
163 | ;; ($print "<<< init_memory\n") | |
164 | ||
165 | ) | |
166 | ||
167 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
168 | ;; memory management | |
169 | ||
3ea09886 JM |
170 | (func $ALLOC_INTERNAL (param $type i32 |
171 | $val1 i32 $val2 i32 $val3 i32) (result i32) | |
0a19c2f1 JM |
172 | (LET $prev (global.get $mem_free_list) |
173 | $res (global.get $mem_free_list) | |
349faa83 | 174 | $size ($MalType_size $type)) |
33309c6a JM |
175 | |
176 | (block $loop_done | |
177 | (loop $loop | |
178 | ;; res == mem_unused_start | |
0a19c2f1 | 179 | (if (i32.eq $res (global.get $mem_unused_start)) |
33309c6a JM |
180 | (then |
181 | ;; ALLOC_UNUSED | |
182 | ;;; if (res + size > MEM_SIZE) | |
0a19c2f1 | 183 | (if (i32.gt_u (i32.add $res $size) (global.get $MEM_SIZE)) |
50eea9ad JM |
184 | ;; Out of memory, exit |
185 | ($fatal 7 "Out of mal memory!\n")) | |
33309c6a | 186 | ;;; if (mem_unused_start += size) |
0a19c2f1 JM |
187 | (global.set $mem_unused_start |
188 | (i32.add (global.get $mem_unused_start) $size)) | |
33309c6a JM |
189 | ;;; if (prev == res) |
190 | (if (i32.eq $prev $res) | |
191 | (then | |
0a19c2f1 | 192 | (global.set $mem_free_list (global.get $mem_unused_start))) |
33309c6a JM |
193 | (else |
194 | ;;; mem[prev].val[0] = mem_unused_start | |
195 | (i32.store | |
196 | ($MalVal_val_ptr $prev 0) | |
0a19c2f1 | 197 | (global.get $mem_unused_start)))) |
33309c6a JM |
198 | (br $loop_done))) |
199 | ;; if (MalVal_size(mem+res) == size) | |
200 | (if (i32.eq ($MalVal_size ($MalVal_ptr $res)) | |
201 | $size) | |
202 | (then | |
203 | ;; ALLOC_MIDDLE | |
204 | ;;; if (res == mem_free_list) | |
0a19c2f1 | 205 | (if (i32.eq $res (global.get $mem_free_list)) |
33309c6a JM |
206 | ;; set free pointer (mem_free_list) to next free |
207 | ;;; mem_free_list = mem[res].val[0]; | |
0a19c2f1 | 208 | (global.set $mem_free_list ($MalVal_val $res 0))) |
33309c6a | 209 | ;; if (res != mem_free_list) |
0a19c2f1 | 210 | (if (i32.ne $res (global.get $mem_free_list)) |
33309c6a JM |
211 | ;; set previous free to next free |
212 | ;;; mem[prev].val[0] = mem[res].val[0] | |
213 | (i32.store ($MalVal_val_ptr $prev 0) ($MalVal_val $res 0))) | |
214 | (br $loop_done))) | |
215 | ;;; prev = res | |
0a19c2f1 | 216 | (local.set $prev $res) |
33309c6a | 217 | ;;; res = mem[res].val[0] |
0a19c2f1 | 218 | (local.set $res ($MalVal_val $res 0)) |
33309c6a JM |
219 | (br $loop) |
220 | ) | |
221 | ) | |
222 | ;; ALLOC_DONE | |
223 | ;;; mem[res].refcnt_type = type + 32 | |
224 | (i32.store ($MalVal_ptr $res) (i32.add $type 32)) | |
225 | ;; set val to default val1 | |
226 | ;;; mem[res].val[0] = val1 | |
227 | (i32.store ($MalVal_val_ptr $res 0) $val1) | |
228 | ;;; if (type > 5 && type != 9) | |
3ea09886 JM |
229 | (if (AND (i32.gt_u $type 5) |
230 | (i32.ne $type 9)) | |
33309c6a JM |
231 | (then |
232 | ;; inc refcnt of referenced value | |
233 | ;;; mem[val1].refcnt_type += 32 | |
234 | (i32.store ($MalVal_ptr $val1) | |
235 | (i32.add ($MalVal_refcnt_type $val1) 32)))) | |
236 | ;;; if (size > 2) | |
237 | (if (i32.gt_u $size 2) | |
238 | (then | |
239 | ;; inc refcnt of referenced value | |
240 | ;;; mem[val2].refcnt_type += 32 | |
241 | (i32.store ($MalVal_ptr $val2) | |
242 | (i32.add ($MalVal_refcnt_type $val2) 32)) | |
243 | ;;; mem[res].val[1] = val2 | |
244 | (i32.store ($MalVal_val_ptr $res 1) $val2))) | |
245 | ;;; if (size > 3) | |
246 | (if (i32.gt_u $size 3) | |
247 | (then | |
248 | ;; inc refcnt of referenced value | |
249 | ;;; mem[val3].refcnt_type += 32 | |
250 | (i32.store ($MalVal_ptr $val3) | |
251 | (i32.add ($MalVal_refcnt_type $val3) 32)) | |
252 | ;;; mem[res].val[2] = val3 | |
253 | (i32.store ($MalVal_val_ptr $res 2) $val3))) | |
254 | ||
255 | ;;; return mem + res | |
256 | ($MalVal_ptr $res) | |
257 | ) | |
258 | ||
3ea09886 | 259 | (func $ALLOC_SCALAR (param $type i32 $val1 i32) (result i32) |
33309c6a JM |
260 | ($ALLOC_INTERNAL $type $val1 0 0) |
261 | ) | |
262 | ||
3ea09886 JM |
263 | (func $ALLOC (param $type i32 $val1 i32 $val2 i32 $val3 i32) (result i32) |
264 | ($ALLOC_INTERNAL $type ($IDX $val1) ($IDX $val2) ($IDX $val3)) | |
33309c6a JM |
265 | ) |
266 | ||
267 | (func $RELEASE (param $mv i32) | |
349faa83 | 268 | (LET $idx 0 $type 0 $size 0) |
33309c6a JM |
269 | |
270 | ;; Ignore NULLs | |
271 | ;;; if (mv == NULL) { return; } | |
272 | (if (i32.eqz $mv) (return)) | |
273 | ;;; idx = mv - mem | |
0a19c2f1 | 274 | (local.set $idx ($IDX $mv)) |
33309c6a | 275 | ;;; type = mv->refcnt_type & 31 |
0a19c2f1 | 276 | (local.set $type (i32.and (i32.load $mv) 0x1f)) ;; 0x1f == 31 |
33309c6a | 277 | ;;; size = MalType_size(type) |
0a19c2f1 | 278 | (local.set $size ($MalType_size $type)) |
33309c6a JM |
279 | |
280 | ;; DEBUG | |
281 | ;;; printf(">>> RELEASE idx: %d, type: %d, size: %d\n", idx, type, size) | |
282 | ||
283 | (if (i32.eq 0 $mv) | |
50eea9ad | 284 | ($fatal 7 "RELEASE of NULL!\n")) |
33309c6a | 285 | |
0a19c2f1 | 286 | (if (i32.eq (global.get $FREE_T) $type) |
33309c6a JM |
287 | (then |
288 | ($printf_2 "RELEASE of already free mv: 0x%x, idx: 0x%x\n" $mv $idx) | |
50eea9ad | 289 | ($fatal 1 ""))) |
33309c6a JM |
290 | (if (i32.lt_u ($MalVal_refcnt_type $idx) 15) |
291 | (then | |
292 | ($printf_2 "RELEASE of unowned mv: 0x%x, idx: 0x%x\n" $mv $idx) | |
50eea9ad | 293 | ($fatal 1 ""))) |
33309c6a JM |
294 | |
295 | ;; decrease reference count by one | |
296 | (i32.store ($MalVal_ptr $idx) | |
0c62f14e | 297 | (i32.sub ($MalVal_refcnt_type $idx) 32)) |
33309c6a JM |
298 | |
299 | ;; nil, false, true, empty sequences | |
0a19c2f1 | 300 | (if (i32.le_u $mv (global.get $EMPTY_HASHMAP)) |
33309c6a JM |
301 | (then |
302 | (if (i32.lt_u ($MalVal_refcnt_type $idx) 32) | |
303 | (then | |
304 | ($printf_2 "RELEASE of unowned mv: 0x%x, idx: 0x%x\n" $mv $idx) | |
50eea9ad | 305 | ($fatal 1 ""))) |
33309c6a JM |
306 | (return))) |
307 | ||
308 | ;; our reference count is not 0, so don't release | |
309 | (if (i32.ge_u ($MalVal_refcnt_type $idx) 32) | |
310 | (return)) | |
311 | ||
312 | (block $done | |
3ea09886 JM |
313 | (block (block (block (block (block (block (block (block (block |
314 | (br_table 0 0 0 0 1 1 2 2 3 0 4 4 5 6 7 8 8 $type)) | |
33309c6a JM |
315 | ;; nil, boolean, integer, float |
316 | (br $done)) | |
317 | ;; string, kw, symbol | |
318 | ;; release string, then FREE reference | |
0a19c2f1 | 319 | ($RELEASE_STRING (i32.add (global.get $string_mem) ($VAL0 $mv))) |
33309c6a JM |
320 | (br $done)) |
321 | ;; list, vector | |
322 | (if (i32.ne ($MalVal_val $idx 0) 0) | |
323 | (then | |
324 | ;; release next element and value | |
325 | ($RELEASE ($MEM_VAL0_ptr $mv)) | |
326 | ($RELEASE ($MEM_VAL1_ptr $mv)))) | |
327 | (br $done)) | |
328 | ;; hashmap | |
329 | (if (i32.ne ($MalVal_val $idx 0) 0) | |
330 | (then | |
331 | ;; release next element, value, and key | |
332 | ($RELEASE ($MEM_VAL0_ptr $mv)) | |
333 | ($RELEASE ($MEM_VAL2_ptr $mv)) | |
334 | ($RELEASE ($MEM_VAL1_ptr $mv)))) | |
335 | (br $done)) | |
3ea09886 JM |
336 | ;; mal / macro function |
337 | ;; release ast, params, and environment | |
338 | ($RELEASE ($MEM_VAL2_ptr $mv)) | |
339 | ($RELEASE ($MEM_VAL1_ptr $mv)) | |
340 | ($RELEASE ($MEM_VAL0_ptr $mv)) | |
341 | (br $done)) | |
342 | ;; atom | |
343 | ;; release contained/referred value | |
344 | ($RELEASE ($MEM_VAL0_ptr $mv)) | |
345 | (br $done)) | |
33309c6a JM |
346 | ;; env |
347 | ;; if outer is set then release outer | |
348 | (if (i32.ne ($MalVal_val $idx 1) 0) | |
349 | ($RELEASE ($MEM_VAL1_ptr $mv))) | |
3ea09886 JM |
350 | ;; release the env data (hashmap) |
351 | ($RELEASE ($MEM_VAL0_ptr $mv)) | |
352 | (br $done)) | |
353 | ;; metadata | |
354 | ;; release object and metdata object | |
33309c6a | 355 | ($RELEASE ($MEM_VAL0_ptr $mv)) |
3ea09886 | 356 | ($RELEASE ($MEM_VAL1_ptr $mv)) |
33309c6a JM |
357 | (br $done)) |
358 | ;; default/unknown | |
359 | ) | |
360 | ||
361 | ;; FREE, free the current element | |
362 | ||
363 | ;; set type(FREE/15) and size | |
364 | ;;; mv->refcnt_type = size*32 + FREE_T | |
0a19c2f1 JM |
365 | (i32.store $mv (i32.add (i32.mul $size 32) (global.get $FREE_T))) |
366 | (i32.store ($MalVal_val_ptr $idx 0) (global.get $mem_free_list)) | |
367 | (global.set $mem_free_list $idx) | |
33309c6a JM |
368 | (if (i32.ge_u $size 3) (i32.store ($MalVal_val_ptr $idx 1) 0)) |
369 | (if (i32.eq $size 4) (i32.store ($MalVal_val_ptr $idx 2) 0)) | |
370 | ) | |
371 | ||
50eea9ad JM |
372 | ;; find string in string memory or 0 if not found |
373 | (func $FIND_STRING (param $str i32) (result i32) | |
0a19c2f1 | 374 | (LET $ms (global.get $string_mem)) |
50eea9ad JM |
375 | (block $done |
376 | (loop $loop | |
0a19c2f1 | 377 | (br_if $done (i32.ge_s $ms (global.get $string_mem_next))) |
50eea9ad JM |
378 | (if (i32.eqz ($strcmp $str (i32.add $ms 4))) |
379 | (return $ms)) | |
33309c6a | 380 | |
0a19c2f1 | 381 | (local.set $ms (i32.add $ms (i32.load16_u (i32.add $ms 2)))) |
50eea9ad JM |
382 | (br $loop) |
383 | ) | |
384 | ) | |
385 | 0 | |
386 | ) | |
33309c6a | 387 | |
50eea9ad JM |
388 | ;; str is a NULL terminated string |
389 | ;; size is number of characters in the string not including the | |
390 | ;; trailing NULL | |
391 | (func $ALLOC_STRING (param $str i32 $size i32 $intern i32) (result i32) | |
349faa83 | 392 | (LET $ms 0) |
33309c6a | 393 | |
50eea9ad JM |
394 | ;; search for matching string in string_mem |
395 | (if $intern | |
396 | (then | |
0a19c2f1 | 397 | (local.set $ms ($FIND_STRING $str)) |
50eea9ad JM |
398 | (if $ms |
399 | (then | |
400 | ;;; ms->refcnt += 1 | |
0c62f14e | 401 | (i32.store16 $ms (i32.add (i32.load16_u $ms) 1)) |
50eea9ad JM |
402 | (return $ms))))) |
403 | ||
404 | ;; no existing matching string so create a new one | |
0a19c2f1 | 405 | (local.set $ms (global.get $string_mem_next)) |
0c62f14e | 406 | (i32.store16 $ms 1) |
50eea9ad | 407 | ;;; ms->size = sizeof(MalString)+size+1 |
0c62f14e | 408 | (i32.store16 offset=2 $ms (i32.add (i32.add 4 $size) 1)) |
50eea9ad JM |
409 | ($memmove (i32.add $ms 4) $str (i32.add $size 1)) |
410 | ;;; string_mem_next = (void *)ms + ms->size | |
0a19c2f1 | 411 | (global.set $string_mem_next |
50eea9ad JM |
412 | ;;(i32.add $ms (i32.load16_u (i32.add $ms 2)))) |
413 | (i32.add $ms (i32.load16_u offset=2 $ms))) | |
414 | ||
415 | ;;($printf_2 "ALLOC_STRING 6 ms 0x%x, refs: %d\n" $ms (i32.load16_u $ms)) | |
416 | $ms | |
33309c6a JM |
417 | ) |
418 | ||
50eea9ad | 419 | (func $RELEASE_STRING (param $ms i32) |
349faa83 | 420 | (LET $size 0 $next 0 $ms_idx 0 $idx 0 $type 0 $mv 0) |
33309c6a | 421 | |
50eea9ad JM |
422 | (if (i32.le_s (i32.load16_u $ms) 0) |
423 | (then | |
424 | ($printf_2 "Release of already free string: %d (0x%x)\n" | |
0a19c2f1 | 425 | (i32.sub $ms (global.get $string_mem)) $ms) |
50eea9ad | 426 | ($fatal 1 ""))) |
33309c6a | 427 | |
50eea9ad | 428 | ;;; size = ms->size |
0a19c2f1 | 429 | (local.set $size (i32.load16_u (i32.add $ms 2))) |
50eea9ad | 430 | ;;; *next = (void *)ms + size |
0a19c2f1 | 431 | (local.set $next (i32.add $ms $size)) |
50eea9ad JM |
432 | |
433 | ;;; ms->refcnt -= 1 | |
0c62f14e | 434 | (i32.store16 $ms (i32.sub (i32.load16_u $ms) 1)) |
33309c6a | 435 | |
50eea9ad JM |
436 | (if (i32.eqz (i32.load16_u $ms)) |
437 | (then | |
0a19c2f1 | 438 | (if (i32.gt_s (global.get $string_mem_next) $next) |
50eea9ad JM |
439 | (then |
440 | ;; If no more references to this string then free it up by | |
441 | ;; shifting up every string afterwards to fill the gap | |
442 | ;; (splice). | |
0a19c2f1 | 443 | ($memmove $ms $next (i32.sub (global.get $string_mem_next) |
50eea9ad JM |
444 | $next)) |
445 | ||
446 | ;; Scan the mem values for string types after the freed | |
447 | ;; string and shift their indexes by size | |
0a19c2f1 JM |
448 | (local.set $ms_idx (i32.sub $ms (global.get $string_mem))) |
449 | (local.set $idx ($IDX (global.get $EMPTY_HASHMAP))) | |
50eea9ad | 450 | (loop $loop |
0a19c2f1 JM |
451 | (local.set $mv ($MalVal_ptr $idx)) |
452 | (local.set $type ($TYPE $mv)) | |
50eea9ad | 453 | (if (AND (i32.gt_s ($VAL0 $mv) $ms_idx) |
0a19c2f1 JM |
454 | (OR (i32.eq $type (global.get $STRING_T)) |
455 | (i32.eq $type (global.get $SYMBOL_T)))) | |
0c62f14e | 456 | (i32.store ($VAL0_ptr $mv) (i32.sub ($VAL0 $mv) $size))) |
0a19c2f1 | 457 | (local.set $idx (i32.add $idx ($MalVal_size $mv))) |
50eea9ad | 458 | |
0a19c2f1 | 459 | (br_if $loop (i32.lt_s $idx (global.get $mem_unused_start))) |
50eea9ad JM |
460 | ))) |
461 | ||
0a19c2f1 JM |
462 | (global.set $string_mem_next |
463 | (i32.sub (global.get $string_mem_next) $size)))) | |
33309c6a JM |
464 | ) |
465 | ) |