1 #pragma once 2 #include <string_view> 3 4 // From crates/component-util/src/lib.rs 5 inline constexpr std::string_view REALLOC_AND_FREE = 6 R"END( 7 (global $last (mut i32) (i32.const 8)) 8 (func $realloc (export "realloc") 9 (param $old_ptr i32) 10 (param $old_size i32) 11 (param $align i32) 12 (param $new_size i32) 13 (result i32) 14 15 (local $ret i32) 16 17 ;; Test if the old pointer is non-null 18 local.get $old_ptr 19 if 20 ;; If the old size is bigger than the new size then 21 ;; this is a shrink and transparently allow it 22 local.get $old_size 23 local.get $new_size 24 i32.gt_u 25 if 26 local.get $old_ptr 27 return 28 end 29 30 ;; otherwise fall through to allocate a new chunk which will later 31 ;; copy data over 32 end 33 34 ;; align up `$last` 35 (global.set $last 36 (i32.and 37 (i32.add 38 (global.get $last) 39 (i32.add 40 (local.get $align) 41 (i32.const -1))) 42 (i32.xor 43 (i32.add 44 (local.get $align) 45 (i32.const -1)) 46 (i32.const -1)))) 47 48 ;; save the current value of `$last` as the return value 49 global.get $last 50 local.set $ret 51 52 ;; bump our pointer 53 (global.set $last 54 (i32.add 55 (global.get $last) 56 (local.get $new_size))) 57 58 ;; while `memory.size` is less than `$last`, grow memory 59 ;; by one page 60 (loop $loop 61 (if 62 (i32.lt_u 63 (i32.mul (memory.size) (i32.const 65536)) 64 (global.get $last)) 65 (then 66 i32.const 1 67 memory.grow 68 ;; test to make sure growth succeeded 69 i32.const -1 70 i32.eq 71 if unreachable end 72 73 br $loop))) 74 75 76 ;; ensure anything necessary is set to valid data by spraying a bit 77 ;; pattern that is invalid 78 local.get $ret 79 i32.const 0xde 80 local.get $new_size 81 memory.fill 82 83 ;; If the old pointer is present then that means this was a reallocation 84 ;; of an existing chunk which means the existing data must be copied. 85 local.get $old_ptr 86 if 87 local.get $ret ;; destination 88 local.get $old_ptr ;; source 89 local.get $old_size ;; size 90 memory.copy 91 end 92 93 local.get $ret 94 ) 95 )END"; 96