14c8edb95SAlex Crichton //! > **⚠️ Warning ⚠️**: this crate is an internal-only crate for the Wasmtime
24c8edb95SAlex Crichton //! > project and is not intended for general use. APIs are not strictly
34c8edb95SAlex Crichton //! > reviewed for safety and usage outside of Wasmtime may have bugs. If
44c8edb95SAlex Crichton //! > you're interested in using this feel free to file an issue on the
54c8edb95SAlex Crichton //! > Wasmtime repository to start a discussion about doing so, but otherwise
64c8edb95SAlex Crichton //! > be aware that your usage of this crate is not supported.
74c8edb95SAlex Crichton 
8d8f7c77fSAlex Crichton #![no_std]
9d8f7c77fSAlex Crichton 
107c67e620SJoel Dice /// Represents the possible sizes in bytes of the discriminant of a variant type in the component model
11bd70dbebSAlex Crichton #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
127c67e620SJoel Dice pub enum DiscriminantSize {
137c67e620SJoel Dice     /// 8-bit discriminant
147c67e620SJoel Dice     Size1,
157c67e620SJoel Dice     /// 16-bit discriminant
167c67e620SJoel Dice     Size2,
177c67e620SJoel Dice     /// 32-bit discriminant
187c67e620SJoel Dice     Size4,
197c67e620SJoel Dice }
207c67e620SJoel Dice 
217c67e620SJoel Dice impl DiscriminantSize {
227c67e620SJoel Dice     /// Calculate the size of discriminant needed to represent a variant with the specified number of cases.
from_count(count: usize) -> Option<Self>23bd70dbebSAlex Crichton     pub const fn from_count(count: usize) -> Option<Self> {
24*7d857e63SAlex Crichton         if count <= 1 << 8 {
257c67e620SJoel Dice             Some(Self::Size1)
26*7d857e63SAlex Crichton         } else if count <= 1 << 16 {
277c67e620SJoel Dice             Some(Self::Size2)
28*7d857e63SAlex Crichton         } else if count as u64 <= 1 << 32 {
297c67e620SJoel Dice             Some(Self::Size4)
307c67e620SJoel Dice         } else {
317c67e620SJoel Dice             None
327c67e620SJoel Dice         }
337c67e620SJoel Dice     }
34bd70dbebSAlex Crichton 
35bd70dbebSAlex Crichton     /// Returns the size, in bytes, of this discriminant
byte_size(&self) -> u3236bd70dbebSAlex Crichton     pub const fn byte_size(&self) -> u32 {
37bd70dbebSAlex Crichton         match self {
38bd70dbebSAlex Crichton             DiscriminantSize::Size1 => 1,
39bd70dbebSAlex Crichton             DiscriminantSize::Size2 => 2,
40bd70dbebSAlex Crichton             DiscriminantSize::Size4 => 4,
41bd70dbebSAlex Crichton         }
42bd70dbebSAlex Crichton     }
437c67e620SJoel Dice }
447c67e620SJoel Dice 
457c67e620SJoel Dice impl From<DiscriminantSize> for u32 {
467c67e620SJoel Dice     /// Size of the discriminant as a `u32`
from(size: DiscriminantSize) -> u32477c67e620SJoel Dice     fn from(size: DiscriminantSize) -> u32 {
48bd70dbebSAlex Crichton         size.byte_size()
497c67e620SJoel Dice     }
507c67e620SJoel Dice }
517c67e620SJoel Dice 
527c67e620SJoel Dice impl From<DiscriminantSize> for usize {
537c67e620SJoel Dice     /// Size of the discriminant as a `usize`
from(size: DiscriminantSize) -> usize547c67e620SJoel Dice     fn from(size: DiscriminantSize) -> usize {
557c67e620SJoel Dice         match size {
567c67e620SJoel Dice             DiscriminantSize::Size1 => 1,
577c67e620SJoel Dice             DiscriminantSize::Size2 => 2,
587c67e620SJoel Dice             DiscriminantSize::Size4 => 4,
597c67e620SJoel Dice         }
607c67e620SJoel Dice     }
617c67e620SJoel Dice }
627c67e620SJoel Dice 
637c67e620SJoel Dice /// Represents the number of bytes required to store a flags value in the component model
647c67e620SJoel Dice pub enum FlagsSize {
65893fadb4SAlex Crichton     /// There are no flags
66893fadb4SAlex Crichton     Size0,
677c67e620SJoel Dice     /// Flags can fit in a u8
687c67e620SJoel Dice     Size1,
697c67e620SJoel Dice     /// Flags can fit in a u16
707c67e620SJoel Dice     Size2,
717c67e620SJoel Dice     /// Flags can fit in a specified number of u32 fields
72bc8e36a6SAlex Crichton     Size4Plus(u8),
737c67e620SJoel Dice }
747c67e620SJoel Dice 
757c67e620SJoel Dice impl FlagsSize {
767c67e620SJoel Dice     /// Calculate the size needed to represent a value with the specified number of flags.
from_count(count: usize) -> FlagsSize77bd70dbebSAlex Crichton     pub const fn from_count(count: usize) -> FlagsSize {
78893fadb4SAlex Crichton         if count == 0 {
79893fadb4SAlex Crichton             FlagsSize::Size0
80893fadb4SAlex Crichton         } else if count <= 8 {
817c67e620SJoel Dice             FlagsSize::Size1
827c67e620SJoel Dice         } else if count <= 16 {
837c67e620SJoel Dice             FlagsSize::Size2
847c67e620SJoel Dice         } else {
851b4ea3a6SAlex Crichton             let amt = count.div_ceil(32);
86bc8e36a6SAlex Crichton             if amt > (u8::MAX as usize) {
87bc8e36a6SAlex Crichton                 panic!("too many flags");
88bc8e36a6SAlex Crichton             }
89bc8e36a6SAlex Crichton             FlagsSize::Size4Plus(amt as u8)
907c67e620SJoel Dice         }
917c67e620SJoel Dice     }
927c67e620SJoel Dice }
937c67e620SJoel Dice 
94ed8908efSJoel Dice /// A simple bump allocator which can be used with modules
95ed8908efSJoel Dice pub const REALLOC_AND_FREE: &str = r#"
96ed8908efSJoel Dice     (global $last (mut i32) (i32.const 8))
97ed8908efSJoel Dice     (func $realloc (export "realloc")
98ed8908efSJoel Dice         (param $old_ptr i32)
99ed8908efSJoel Dice         (param $old_size i32)
100ed8908efSJoel Dice         (param $align i32)
101ed8908efSJoel Dice         (param $new_size i32)
102ed8908efSJoel Dice         (result i32)
103ed8908efSJoel Dice 
104650979aeSAlex Crichton         (local $ret i32)
105650979aeSAlex Crichton 
106ed8908efSJoel Dice         ;; Test if the old pointer is non-null
107ed8908efSJoel Dice         local.get $old_ptr
108ed8908efSJoel Dice         if
109ed8908efSJoel Dice             ;; If the old size is bigger than the new size then
110ed8908efSJoel Dice             ;; this is a shrink and transparently allow it
111ed8908efSJoel Dice             local.get $old_size
112ed8908efSJoel Dice             local.get $new_size
113ed8908efSJoel Dice             i32.gt_u
114ed8908efSJoel Dice             if
115ed8908efSJoel Dice                 local.get $old_ptr
116ed8908efSJoel Dice                 return
117ed8908efSJoel Dice             end
118ed8908efSJoel Dice 
119650979aeSAlex Crichton             ;; otherwise fall through to allocate a new chunk which will later
120650979aeSAlex Crichton             ;; copy data over
121ed8908efSJoel Dice         end
122ed8908efSJoel Dice 
123ed8908efSJoel Dice         ;; align up `$last`
124ed8908efSJoel Dice         (global.set $last
125ed8908efSJoel Dice             (i32.and
126ed8908efSJoel Dice                 (i32.add
127ed8908efSJoel Dice                     (global.get $last)
128ed8908efSJoel Dice                     (i32.add
129ed8908efSJoel Dice                         (local.get $align)
130ed8908efSJoel Dice                         (i32.const -1)))
131ed8908efSJoel Dice                 (i32.xor
132ed8908efSJoel Dice                     (i32.add
133ed8908efSJoel Dice                         (local.get $align)
134ed8908efSJoel Dice                         (i32.const -1))
135ed8908efSJoel Dice                     (i32.const -1))))
136ed8908efSJoel Dice 
137ed8908efSJoel Dice         ;; save the current value of `$last` as the return value
138ed8908efSJoel Dice         global.get $last
139866ec466SAlex Crichton         local.set $ret
140866ec466SAlex Crichton 
141866ec466SAlex Crichton         ;; bump our pointer
142866ec466SAlex Crichton         (global.set $last
143866ec466SAlex Crichton             (i32.add
144866ec466SAlex Crichton                 (global.get $last)
145866ec466SAlex Crichton                 (local.get $new_size)))
146866ec466SAlex Crichton 
147866ec466SAlex Crichton         ;; while `memory.size` is less than `$last`, grow memory
148866ec466SAlex Crichton         ;; by one page
149866ec466SAlex Crichton         (loop $loop
150866ec466SAlex Crichton             (if
151866ec466SAlex Crichton                 (i32.lt_u
152866ec466SAlex Crichton                     (i32.mul (memory.size) (i32.const 65536))
153866ec466SAlex Crichton                     (global.get $last))
154866ec466SAlex Crichton                 (then
155866ec466SAlex Crichton                     i32.const 1
156866ec466SAlex Crichton                     memory.grow
157866ec466SAlex Crichton                     ;; test to make sure growth succeeded
158866ec466SAlex Crichton                     i32.const -1
159866ec466SAlex Crichton                     i32.eq
160866ec466SAlex Crichton                     if unreachable end
161866ec466SAlex Crichton 
162866ec466SAlex Crichton                     br $loop)))
163866ec466SAlex Crichton 
164ed8908efSJoel Dice 
165ed8908efSJoel Dice         ;; ensure anything necessary is set to valid data by spraying a bit
166ed8908efSJoel Dice         ;; pattern that is invalid
167866ec466SAlex Crichton         local.get $ret
168ed8908efSJoel Dice         i32.const 0xde
169ed8908efSJoel Dice         local.get $new_size
170ed8908efSJoel Dice         memory.fill
171ed8908efSJoel Dice 
172650979aeSAlex Crichton         ;; If the old pointer is present then that means this was a reallocation
173650979aeSAlex Crichton         ;; of an existing chunk which means the existing data must be copied.
174650979aeSAlex Crichton         local.get $old_ptr
175650979aeSAlex Crichton         if
176650979aeSAlex Crichton             local.get $ret          ;; destination
177650979aeSAlex Crichton             local.get $old_ptr      ;; source
178650979aeSAlex Crichton             local.get $old_size     ;; size
179650979aeSAlex Crichton             memory.copy
180650979aeSAlex Crichton         end
181650979aeSAlex Crichton 
182866ec466SAlex Crichton         local.get $ret
183ed8908efSJoel Dice     )
184ed8908efSJoel Dice "#;
185