1 //! > **⚠️ Warning ⚠️**: this crate is an internal-only crate for the Wasmtime 2 //! > project and is not intended for general use. APIs are not strictly 3 //! > reviewed for safety and usage outside of Wasmtime may have bugs. If 4 //! > you're interested in using this feel free to file an issue on the 5 //! > Wasmtime repository to start a discussion about doing so, but otherwise 6 //! > be aware that your usage of this crate is not supported. 7 8 #![no_std] 9 10 /// Represents the possible sizes in bytes of the discriminant of a variant type in the component model 11 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 12 pub enum DiscriminantSize { 13 /// 8-bit discriminant 14 Size1, 15 /// 16-bit discriminant 16 Size2, 17 /// 32-bit discriminant 18 Size4, 19 } 20 21 impl DiscriminantSize { 22 /// Calculate the size of discriminant needed to represent a variant with the specified number of cases. from_count(count: usize) -> Option<Self>23 pub const fn from_count(count: usize) -> Option<Self> { 24 if count <= 1 << 8 { 25 Some(Self::Size1) 26 } else if count <= 1 << 16 { 27 Some(Self::Size2) 28 } else if count as u64 <= 1 << 32 { 29 Some(Self::Size4) 30 } else { 31 None 32 } 33 } 34 35 /// Returns the size, in bytes, of this discriminant byte_size(&self) -> u3236 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 45 impl From<DiscriminantSize> for u32 { 46 /// Size of the discriminant as a `u32` from(size: DiscriminantSize) -> u3247 fn from(size: DiscriminantSize) -> u32 { 48 size.byte_size() 49 } 50 } 51 52 impl From<DiscriminantSize> for usize { 53 /// Size of the discriminant as a `usize` from(size: DiscriminantSize) -> usize54 fn from(size: DiscriminantSize) -> usize { 55 match size { 56 DiscriminantSize::Size1 => 1, 57 DiscriminantSize::Size2 => 2, 58 DiscriminantSize::Size4 => 4, 59 } 60 } 61 } 62 63 /// Represents the number of bytes required to store a flags value in the component model 64 pub enum FlagsSize { 65 /// There are no flags 66 Size0, 67 /// Flags can fit in a u8 68 Size1, 69 /// Flags can fit in a u16 70 Size2, 71 /// Flags can fit in a specified number of u32 fields 72 Size4Plus(u8), 73 } 74 75 impl FlagsSize { 76 /// Calculate the size needed to represent a value with the specified number of flags. from_count(count: usize) -> FlagsSize77 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 94 /// A simple bump allocator which can be used with modules 95 pub 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 "#; 185