wasmtime_internal_component_util/
lib.rs1#![no_std]
9
10#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
12pub enum DiscriminantSize {
13 Size1,
15 Size2,
17 Size4,
19}
20
21impl DiscriminantSize {
22 pub const fn from_count(count: usize) -> Option<Self> {
24 if count <= 0xFF {
25 Some(Self::Size1)
26 } else if count <= 0xFFFF {
27 Some(Self::Size2)
28 } else if count <= 0xFFFF_FFFF {
29 Some(Self::Size4)
30 } else {
31 None
32 }
33 }
34
35 pub const fn byte_size(&self) -> u32 {
37 match self {
38 DiscriminantSize::Size1 => 1,
39 DiscriminantSize::Size2 => 2,
40 DiscriminantSize::Size4 => 4,
41 }
42 }
43}
44
45impl From<DiscriminantSize> for u32 {
46 fn from(size: DiscriminantSize) -> u32 {
48 size.byte_size()
49 }
50}
51
52impl From<DiscriminantSize> for usize {
53 fn from(size: DiscriminantSize) -> usize {
55 match size {
56 DiscriminantSize::Size1 => 1,
57 DiscriminantSize::Size2 => 2,
58 DiscriminantSize::Size4 => 4,
59 }
60 }
61}
62
63pub enum FlagsSize {
65 Size0,
67 Size1,
69 Size2,
71 Size4Plus(u8),
73}
74
75impl FlagsSize {
76 pub const fn from_count(count: usize) -> FlagsSize {
78 if count == 0 {
79 FlagsSize::Size0
80 } else if count <= 8 {
81 FlagsSize::Size1
82 } else if count <= 16 {
83 FlagsSize::Size2
84 } else {
85 let amt = count.div_ceil(32);
86 if amt > (u8::MAX as usize) {
87 panic!("too many flags");
88 }
89 FlagsSize::Size4Plus(amt as u8)
90 }
91 }
92}
93
94pub const REALLOC_AND_FREE: &str = r#"
96 (global $last (mut i32) (i32.const 8))
97 (func $realloc (export "realloc")
98 (param $old_ptr i32)
99 (param $old_size i32)
100 (param $align i32)
101 (param $new_size i32)
102 (result i32)
103
104 (local $ret i32)
105
106 ;; Test if the old pointer is non-null
107 local.get $old_ptr
108 if
109 ;; If the old size is bigger than the new size then
110 ;; this is a shrink and transparently allow it
111 local.get $old_size
112 local.get $new_size
113 i32.gt_u
114 if
115 local.get $old_ptr
116 return
117 end
118
119 ;; otherwise fall through to allocate a new chunk which will later
120 ;; copy data over
121 end
122
123 ;; align up `$last`
124 (global.set $last
125 (i32.and
126 (i32.add
127 (global.get $last)
128 (i32.add
129 (local.get $align)
130 (i32.const -1)))
131 (i32.xor
132 (i32.add
133 (local.get $align)
134 (i32.const -1))
135 (i32.const -1))))
136
137 ;; save the current value of `$last` as the return value
138 global.get $last
139 local.set $ret
140
141 ;; bump our pointer
142 (global.set $last
143 (i32.add
144 (global.get $last)
145 (local.get $new_size)))
146
147 ;; while `memory.size` is less than `$last`, grow memory
148 ;; by one page
149 (loop $loop
150 (if
151 (i32.lt_u
152 (i32.mul (memory.size) (i32.const 65536))
153 (global.get $last))
154 (then
155 i32.const 1
156 memory.grow
157 ;; test to make sure growth succeeded
158 i32.const -1
159 i32.eq
160 if unreachable end
161
162 br $loop)))
163
164
165 ;; ensure anything necessary is set to valid data by spraying a bit
166 ;; pattern that is invalid
167 local.get $ret
168 i32.const 0xde
169 local.get $new_size
170 memory.fill
171
172 ;; If the old pointer is present then that means this was a reallocation
173 ;; of an existing chunk which means the existing data must be copied.
174 local.get $old_ptr
175 if
176 local.get $ret ;; destination
177 local.get $old_ptr ;; source
178 local.get $old_size ;; size
179 memory.copy
180 end
181
182 local.get $ret
183 )
184"#;