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