Path: blob/main/crates/component-util/src/lib.rs
1692 views
//! > **⚠️ Warning ⚠️**: this crate is an internal-only crate for the Wasmtime1//! > project and is not intended for general use. APIs are not strictly2//! > reviewed for safety and usage outside of Wasmtime may have bugs. If3//! > you're interested in using this feel free to file an issue on the4//! > Wasmtime repository to start a discussion about doing so, but otherwise5//! > be aware that your usage of this crate is not supported.67#![no_std]89/// Represents the possible sizes in bytes of the discriminant of a variant type in the component model10#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]11pub enum DiscriminantSize {12/// 8-bit discriminant13Size1,14/// 16-bit discriminant15Size2,16/// 32-bit discriminant17Size4,18}1920impl DiscriminantSize {21/// Calculate the size of discriminant needed to represent a variant with the specified number of cases.22pub const fn from_count(count: usize) -> Option<Self> {23if count <= 0xFF {24Some(Self::Size1)25} else if count <= 0xFFFF {26Some(Self::Size2)27} else if count <= 0xFFFF_FFFF {28Some(Self::Size4)29} else {30None31}32}3334/// Returns the size, in bytes, of this discriminant35pub const fn byte_size(&self) -> u32 {36match self {37DiscriminantSize::Size1 => 1,38DiscriminantSize::Size2 => 2,39DiscriminantSize::Size4 => 4,40}41}42}4344impl From<DiscriminantSize> for u32 {45/// Size of the discriminant as a `u32`46fn from(size: DiscriminantSize) -> u32 {47size.byte_size()48}49}5051impl From<DiscriminantSize> for usize {52/// Size of the discriminant as a `usize`53fn from(size: DiscriminantSize) -> usize {54match size {55DiscriminantSize::Size1 => 1,56DiscriminantSize::Size2 => 2,57DiscriminantSize::Size4 => 4,58}59}60}6162/// Represents the number of bytes required to store a flags value in the component model63pub enum FlagsSize {64/// There are no flags65Size0,66/// Flags can fit in a u867Size1,68/// Flags can fit in a u1669Size2,70/// Flags can fit in a specified number of u32 fields71Size4Plus(u8),72}7374impl FlagsSize {75/// Calculate the size needed to represent a value with the specified number of flags.76pub const fn from_count(count: usize) -> FlagsSize {77if count == 0 {78FlagsSize::Size079} else if count <= 8 {80FlagsSize::Size181} else if count <= 16 {82FlagsSize::Size283} else {84let amt = count.div_ceil(32);85if amt > (u8::MAX as usize) {86panic!("too many flags");87}88FlagsSize::Size4Plus(amt as u8)89}90}91}9293/// A simple bump allocator which can be used with modules94pub const REALLOC_AND_FREE: &str = r#"95(global $last (mut i32) (i32.const 8))96(func $realloc (export "realloc")97(param $old_ptr i32)98(param $old_size i32)99(param $align i32)100(param $new_size i32)101(result i32)102103(local $ret i32)104105;; Test if the old pointer is non-null106local.get $old_ptr107if108;; If the old size is bigger than the new size then109;; this is a shrink and transparently allow it110local.get $old_size111local.get $new_size112i32.gt_u113if114local.get $old_ptr115return116end117118;; otherwise fall through to allocate a new chunk which will later119;; copy data over120end121122;; align up `$last`123(global.set $last124(i32.and125(i32.add126(global.get $last)127(i32.add128(local.get $align)129(i32.const -1)))130(i32.xor131(i32.add132(local.get $align)133(i32.const -1))134(i32.const -1))))135136;; save the current value of `$last` as the return value137global.get $last138local.set $ret139140;; bump our pointer141(global.set $last142(i32.add143(global.get $last)144(local.get $new_size)))145146;; while `memory.size` is less than `$last`, grow memory147;; by one page148(loop $loop149(if150(i32.lt_u151(i32.mul (memory.size) (i32.const 65536))152(global.get $last))153(then154i32.const 1155memory.grow156;; test to make sure growth succeeded157i32.const -1158i32.eq159if unreachable end160161br $loop)))162163164;; ensure anything necessary is set to valid data by spraying a bit165;; pattern that is invalid166local.get $ret167i32.const 0xde168local.get $new_size169memory.fill170171;; If the old pointer is present then that means this was a reallocation172;; of an existing chunk which means the existing data must be copied.173local.get $old_ptr174if175local.get $ret ;; destination176local.get $old_ptr ;; source177local.get $old_size ;; size178memory.copy179end180181local.get $ret182)183"#;184185186