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 = count.div_ceil(32);
79 if amt > (u8::MAX as usize) {
80 panic!("too many flags");
81 }
82 FlagsSize::Size4Plus(amt as u8)
83 }
84 }
85}
86
87pub const REALLOC_AND_FREE: &str = r#"
89 (global $last (mut i32) (i32.const 8))
90 (func $realloc (export "realloc")
91 (param $old_ptr i32)
92 (param $old_size i32)
93 (param $align i32)
94 (param $new_size i32)
95 (result i32)
96
97 (local $ret i32)
98
99 ;; Test if the old pointer is non-null
100 local.get $old_ptr
101 if
102 ;; If the old size is bigger than the new size then
103 ;; this is a shrink and transparently allow it
104 local.get $old_size
105 local.get $new_size
106 i32.gt_u
107 if
108 local.get $old_ptr
109 return
110 end
111
112 ;; otherwise fall through to allocate a new chunk which will later
113 ;; copy data over
114 end
115
116 ;; align up `$last`
117 (global.set $last
118 (i32.and
119 (i32.add
120 (global.get $last)
121 (i32.add
122 (local.get $align)
123 (i32.const -1)))
124 (i32.xor
125 (i32.add
126 (local.get $align)
127 (i32.const -1))
128 (i32.const -1))))
129
130 ;; save the current value of `$last` as the return value
131 global.get $last
132 local.set $ret
133
134 ;; bump our pointer
135 (global.set $last
136 (i32.add
137 (global.get $last)
138 (local.get $new_size)))
139
140 ;; while `memory.size` is less than `$last`, grow memory
141 ;; by one page
142 (loop $loop
143 (if
144 (i32.lt_u
145 (i32.mul (memory.size) (i32.const 65536))
146 (global.get $last))
147 (then
148 i32.const 1
149 memory.grow
150 ;; test to make sure growth succeeded
151 i32.const -1
152 i32.eq
153 if unreachable end
154
155 br $loop)))
156
157
158 ;; ensure anything necessary is set to valid data by spraying a bit
159 ;; pattern that is invalid
160 local.get $ret
161 i32.const 0xde
162 local.get $new_size
163 memory.fill
164
165 ;; If the old pointer is present then that means this was a reallocation
166 ;; of an existing chunk which means the existing data must be copied.
167 local.get $old_ptr
168 if
169 local.get $ret ;; destination
170 local.get $old_ptr ;; source
171 local.get $old_size ;; size
172 memory.copy
173 end
174
175 local.get $ret
176 )
177"#;