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