wasmer_types/
types.rs

1use crate::indexes::{FunctionIndex, GlobalIndex};
2use crate::lib::std::fmt;
3use crate::lib::std::format;
4use crate::lib::std::string::{String, ToString};
5use crate::lib::std::vec::Vec;
6use crate::units::Pages;
7use crate::values::{Value, WasmValueType};
8use std::cell::UnsafeCell;
9use std::rc::Rc;
10use std::sync::Arc;
11
12// Type Representations
13
14// Value Types
15
16/// A list of all possible value types in WebAssembly.
17#[derive(
18    Copy, Debug, Clone, Eq, PartialEq, Hash, rkyv::Serialize, rkyv::Deserialize, rkyv::Archive,
19)]
20#[archive(as = "Self")]
21pub enum Type {
22    /// Signed 32 bit integer.
23    I32,
24    /// Signed 64 bit integer.
25    I64,
26    /// Floating point 32 bit integer.
27    F32,
28    /// Floating point 64 bit integer.
29    F64,
30    /// A 128 bit number.
31    V128,
32    /// A reference to opaque data in the Wasm instance.
33    ExternRef, /* = 128 */
34    /// A reference to a Wasm function.
35    FuncRef,
36}
37
38impl Type {
39    /// Returns true if `Type` matches any of the numeric types. (e.g. `I32`,
40    /// `I64`, `F32`, `F64`, `V128`).
41    pub fn is_num(self) -> bool {
42        matches!(
43            self,
44            Self::I32 | Self::I64 | Self::F32 | Self::F64 | Self::V128
45        )
46    }
47
48    /// Returns true if `Type` matches either of the reference types.
49    pub fn is_ref(self) -> bool {
50        matches!(self, Self::ExternRef | Self::FuncRef)
51    }
52}
53
54impl fmt::Display for Type {
55    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
56        write!(f, "{:?}", self)
57    }
58}
59
60#[derive(
61    Copy, Clone, Debug, Eq, PartialEq, Hash, rkyv::Serialize, rkyv::Deserialize, rkyv::Archive,
62)]
63#[archive(as = "Self")]
64/// The WebAssembly V128 type
65pub struct V128(pub(crate) [u8; 16]);
66
67impl V128 {
68    /// Get the bytes corresponding to the V128 value
69    pub fn bytes(&self) -> &[u8; 16] {
70        &self.0
71    }
72    /// Iterate over the bytes in the constant.
73    pub fn iter(&self) -> impl Iterator<Item = &u8> {
74        self.0.iter()
75    }
76
77    /// Convert the immediate into a vector.
78    pub fn to_vec(self) -> Vec<u8> {
79        self.0.to_vec()
80    }
81
82    /// Convert the immediate into a slice.
83    pub fn as_slice(&self) -> &[u8] {
84        &self.0[..]
85    }
86}
87
88impl From<[u8; 16]> for V128 {
89    fn from(array: [u8; 16]) -> Self {
90        Self(array)
91    }
92}
93
94impl From<&[u8]> for V128 {
95    fn from(slice: &[u8]) -> Self {
96        assert_eq!(slice.len(), 16);
97        let mut buffer = [0; 16];
98        buffer.copy_from_slice(slice);
99        Self(buffer)
100    }
101}
102
103// External Types
104
105/// A list of all possible types which can be externally referenced from a
106/// WebAssembly module.
107///
108/// This list can be found in [`ImportType`] or [`ExportType`], so these types
109/// can either be imported or exported.
110#[derive(Debug, Clone, PartialEq, Eq, Hash)]
111pub enum ExternType {
112    /// This external type is the type of a WebAssembly function.
113    Function(FunctionType),
114    /// This external type is the type of a WebAssembly global.
115    Global(GlobalType),
116    /// This external type is the type of a WebAssembly table.
117    Table(TableType),
118    /// This external type is the type of a WebAssembly memory.
119    Memory(MemoryType),
120}
121
122macro_rules! accessors {
123    ($(($variant:ident($ty:ty) $get:ident $unwrap:ident))*) => ($(
124        /// Attempt to return the underlying type of this external type,
125        /// returning `None` if it is a different type.
126        pub fn $get(&self) -> Option<&$ty> {
127            if let Self::$variant(e) = self {
128                Some(e)
129            } else {
130                None
131            }
132        }
133
134        /// Returns the underlying descriptor of this [`ExternType`], panicking
135        /// if it is a different type.
136        ///
137        /// # Panics
138        ///
139        /// Panics if `self` is not of the right type.
140        pub fn $unwrap(&self) -> &$ty {
141            self.$get().expect(concat!("expected ", stringify!($ty)))
142        }
143    )*)
144}
145
146impl ExternType {
147    accessors! {
148        (Function(FunctionType) func unwrap_func)
149        (Global(GlobalType) global unwrap_global)
150        (Table(TableType) table unwrap_table)
151        (Memory(MemoryType) memory unwrap_memory)
152    }
153}
154
155// TODO: `shrink_to_fit` these or change it to `Box<[Type]>` if not using
156// Cow or something else
157/// The signature of a function that is either implemented
158/// in a Wasm module or exposed to Wasm by the host.
159///
160/// WebAssembly functions can have 0 or more parameters and results.
161#[derive(Debug, Clone, PartialEq, Eq, Hash, rkyv::Serialize, rkyv::Deserialize, rkyv::Archive)]
162pub struct FunctionType {
163    /// The parameters of the function
164    params: Arc<[Type]>,
165    /// The return values of the function
166    results: Arc<[Type]>,
167}
168
169impl FunctionType {
170    /// Creates a new Function Type with the given parameter and return types.
171    pub fn new<Params, Returns>(params: Params, returns: Returns) -> Self
172    where
173        Params: Into<Arc<[Type]>>,
174        Returns: Into<Arc<[Type]>>,
175    {
176        Self {
177            params: params.into(),
178            results: returns.into(),
179        }
180    }
181
182    /// Parameter types.
183    pub fn params(&self) -> &[Type] {
184        &self.params
185    }
186
187    /// Return types.
188    pub fn results(&self) -> &[Type] {
189        &self.results
190    }
191}
192
193impl fmt::Display for FunctionType {
194    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
195        let params = self
196            .params
197            .iter()
198            .map(|p| format!("{:?}", p))
199            .collect::<Vec<_>>()
200            .join(", ");
201        let results = self
202            .results
203            .iter()
204            .map(|p| format!("{:?}", p))
205            .collect::<Vec<_>>()
206            .join(", ");
207        write!(f, "[{}] -> [{}]", params, results)
208    }
209}
210
211// Macro needed until https://rust-lang.github.io/rfcs/2000-const-generics.html is stable.
212// See https://users.rust-lang.org/t/how-to-implement-trait-for-fixed-size-array-of-any-size/31494
213macro_rules! implement_from_pair_to_functiontype {
214    ($($N:literal,$M:literal)+) => {
215        $(
216            impl From<([Type; $N], [Type; $M])> for FunctionType {
217                fn from(pair: ([Type; $N], [Type; $M])) -> Self {
218                    Self::new(&pair.0[..], &pair.1[..])
219                }
220            }
221        )+
222    }
223}
224
225implement_from_pair_to_functiontype! {
226    0,0 0,1 0,2 0,3 0,4 0,5 0,6 0,7 0,8 0,9
227    1,0 1,1 1,2 1,3 1,4 1,5 1,6 1,7 1,8 1,9
228    2,0 2,1 2,2 2,3 2,4 2,5 2,6 2,7 2,8 2,9
229    3,0 3,1 3,2 3,3 3,4 3,5 3,6 3,7 3,8 3,9
230    4,0 4,1 4,2 4,3 4,4 4,5 4,6 4,7 4,8 4,9
231    5,0 5,1 5,2 5,3 5,4 5,5 5,6 5,7 5,8 5,9
232    6,0 6,1 6,2 6,3 6,4 6,5 6,6 6,7 6,8 6,9
233    7,0 7,1 7,2 7,3 7,4 7,5 7,6 7,7 7,8 7,9
234    8,0 8,1 8,2 8,3 8,4 8,5 8,6 8,7 8,8 8,9
235    9,0 9,1 9,2 9,3 9,4 9,5 9,6 9,7 9,8 9,9
236}
237
238impl From<&FunctionType> for FunctionType {
239    fn from(as_ref: &FunctionType) -> Self {
240        as_ref.clone()
241    }
242}
243
244/// Borrowed version of [`FunctionType`].
245pub struct FunctionTypeRef<'a> {
246    /// The parameters of the function
247    params: &'a [Type],
248    /// The return values of the function
249    results: &'a [Type],
250}
251
252impl<'a> FunctionTypeRef<'a> {
253    /// Create a new temporary function type.
254    pub fn new(params: &'a [Type], results: &'a [Type]) -> Self {
255        Self { params, results }
256    }
257
258    /// Parameter types.
259    pub fn params(&self) -> &[Type] {
260        self.params
261    }
262
263    /// Return types.
264    pub fn results(&self) -> &[Type] {
265        self.results
266    }
267}
268
269impl<'a> From<&'a FunctionType> for FunctionTypeRef<'a> {
270    fn from(FunctionType { params, results }: &'a FunctionType) -> Self {
271        Self { params, results }
272    }
273}
274
275impl<'a> From<&'a ArchivedFunctionType> for FunctionTypeRef<'a> {
276    fn from(ArchivedFunctionType { params, results }: &'a ArchivedFunctionType) -> Self {
277        Self {
278            params: &**params,
279            results: &**results,
280        }
281    }
282}
283
284/// Indicator of whether a global is mutable or not
285#[derive(
286    Debug, Clone, Copy, PartialEq, Eq, Hash, rkyv::Serialize, rkyv::Deserialize, rkyv::Archive,
287)]
288#[archive(as = "Self")]
289pub enum Mutability {
290    /// The global is constant and its value does not change
291    Const,
292    /// The value of the global can change over time
293    Var,
294}
295
296impl Mutability {
297    /// Returns a boolean indicating if the enum is set to mutable.
298    pub fn is_mutable(self) -> bool {
299        match self {
300            Self::Const => false,
301            Self::Var => true,
302        }
303    }
304}
305
306/// WebAssembly global.
307#[derive(
308    Debug, Clone, Copy, PartialEq, Eq, Hash, rkyv::Serialize, rkyv::Deserialize, rkyv::Archive,
309)]
310#[archive(as = "Self")]
311pub struct GlobalType {
312    /// The type of the value stored in the global.
313    pub ty: Type,
314    /// A flag indicating whether the value may change at runtime.
315    pub mutability: Mutability,
316}
317
318// Global Types
319
320/// A WebAssembly global descriptor.
321///
322/// This type describes an instance of a global in a WebAssembly
323/// module. Globals are local to an `Instance` and are either
324/// immutable or mutable.
325impl GlobalType {
326    /// Create a new Global variable
327    /// # Usage:
328    /// ```
329    /// use wasmer_types::{GlobalType, Type, Mutability, Value};
330    ///
331    /// // An I32 constant global
332    /// let global = GlobalType::new(Type::I32, Mutability::Const);
333    /// // An I64 mutable global
334    /// let global = GlobalType::new(Type::I64, Mutability::Var);
335    /// ```
336    pub fn new(ty: Type, mutability: Mutability) -> Self {
337        Self { ty, mutability }
338    }
339}
340
341impl fmt::Display for GlobalType {
342    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
343        let mutability = match self.mutability {
344            Mutability::Const => "constant",
345            Mutability::Var => "mutable",
346        };
347        write!(f, "{} ({})", self.ty, mutability)
348    }
349}
350
351/// Globals are initialized via the `const` operators or by referring to another import.
352#[derive(Debug, Clone, Copy, PartialEq, rkyv::Serialize, rkyv::Deserialize, rkyv::Archive)]
353#[archive(as = "Self")]
354pub enum GlobalInit {
355    /// An `i32.const`.
356    I32Const(i32),
357    /// An `i64.const`.
358    I64Const(i64),
359    /// An `f32.const`.
360    F32Const(f32),
361    /// An `f64.const`.
362    F64Const(f64),
363    /// A `v128.const`.
364    V128Const(V128),
365    /// A `global.get` of another global.
366    GetGlobal(GlobalIndex),
367    // TODO(reftypes): `ref.null func` and `ref.null extern` seem to be 2 different
368    // things: we need to handle both. Perhaps this handled in context by the
369    // global knowing its own type?
370    /// A `ref.null`.
371    RefNullConst,
372    /// A `ref.func <index>`.
373    RefFunc(FunctionIndex),
374}
375
376impl Eq for GlobalInit {}
377
378impl GlobalInit {
379    /// Get the `GlobalInit` from a given `Value`
380    pub fn from_value<T: WasmValueType>(value: Value<T>) -> Self {
381        match value {
382            Value::I32(i) => Self::I32Const(i),
383            Value::I64(i) => Self::I64Const(i),
384            Value::F32(f) => Self::F32Const(f),
385            Value::F64(f) => Self::F64Const(f),
386            _ => unimplemented!("GlobalInit from_value for {:?}", value),
387        }
388    }
389    /// Get the `Value` from the Global init value
390    pub fn to_value<T: WasmValueType>(&self) -> Value<T> {
391        match self {
392            Self::I32Const(i) => Value::I32(*i),
393            Self::I64Const(i) => Value::I64(*i),
394            Self::F32Const(f) => Value::F32(*f),
395            Self::F64Const(f) => Value::F64(*f),
396            _ => unimplemented!("GlobalInit to_value for {:?}", self),
397        }
398    }
399}
400
401// Table Types
402
403/// A descriptor for a table in a WebAssembly module.
404///
405/// Tables are contiguous chunks of a specific element, typically a `funcref` or
406/// an `externref`. The most common use for tables is a function table through
407/// which `call_indirect` can invoke other functions.
408#[derive(
409    Debug, Clone, Copy, PartialEq, Eq, Hash, rkyv::Serialize, rkyv::Deserialize, rkyv::Archive,
410)]
411pub struct TableType {
412    /// The type of data stored in elements of the table.
413    pub ty: Type,
414    /// The minimum number of elements in the table.
415    pub minimum: u32,
416    /// The maximum number of elements in the table.
417    pub maximum: Option<u32>,
418}
419
420impl TableType {
421    /// Creates a new table descriptor which will contain the specified
422    /// `element` and have the `limits` applied to its length.
423    pub fn new(ty: Type, minimum: u32, maximum: Option<u32>) -> Self {
424        Self {
425            ty,
426            minimum,
427            maximum,
428        }
429    }
430}
431
432impl fmt::Display for TableType {
433    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
434        if let Some(maximum) = self.maximum {
435            write!(f, "{} ({}..{})", self.ty, self.minimum, maximum)
436        } else {
437            write!(f, "{} ({}..)", self.ty, self.minimum)
438        }
439    }
440}
441
442// Memory Types
443
444/// A descriptor for a WebAssembly memory type.
445///
446/// Memories are described in units of pages (64KB) and represent contiguous
447/// chunks of addressable memory.
448#[derive(
449    Debug, Clone, Copy, PartialEq, Eq, Hash, rkyv::Serialize, rkyv::Deserialize, rkyv::Archive,
450)]
451pub struct MemoryType {
452    /// The minimum number of pages in the memory.
453    pub minimum: Pages,
454    /// The maximum number of pages in the memory.
455    pub maximum: Option<Pages>,
456    /// Whether the memory may be shared between multiple threads.
457    pub shared: bool,
458}
459
460impl MemoryType {
461    /// Creates a new descriptor for a WebAssembly memory given the specified
462    /// limits of the memory.
463    pub fn new<IntoPages>(minimum: IntoPages, maximum: Option<IntoPages>, shared: bool) -> Self
464    where
465        IntoPages: Into<Pages>,
466    {
467        Self {
468            minimum: minimum.into(),
469            maximum: maximum.map(Into::into),
470            shared,
471        }
472    }
473}
474
475impl fmt::Display for MemoryType {
476    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
477        let shared = if self.shared { "shared" } else { "not shared" };
478        if let Some(maximum) = self.maximum {
479            write!(f, "{} ({:?}..{:?})", shared, self.minimum, maximum)
480        } else {
481            write!(f, "{} ({:?}..)", shared, self.minimum)
482        }
483    }
484}
485
486// Import Types
487
488/// A descriptor for an imported value into a wasm module.
489///
490/// This type is primarily accessed from the `Module::imports`
491/// API. Each `ImportType` describes an import into the wasm module
492/// with the module/name that it's imported from as well as the type
493/// of item that's being imported.
494#[derive(Debug, Clone, PartialEq, Eq, Hash)]
495pub struct Import<S = String, T = ExternType> {
496    module: S,
497    name: S,
498    index: u32,
499    ty: T,
500}
501
502impl<S: AsRef<str>, T> Import<S, T> {
503    /// Creates a new import descriptor which comes from `module` and `name` and
504    /// is of type `ty`.
505    pub fn new(module: S, name: S, index: u32, ty: T) -> Self {
506        Self {
507            module,
508            name,
509            index,
510            ty,
511        }
512    }
513
514    /// Returns the module name that this import is expected to come from.
515    pub fn module(&self) -> &str {
516        self.module.as_ref()
517    }
518
519    /// Returns the field name of the module that this import is expected to
520    /// come from.
521    pub fn name(&self) -> &str {
522        self.name.as_ref()
523    }
524
525    /// The index of the import in the module.
526    pub fn index(&self) -> u32 {
527        self.index
528    }
529
530    /// Returns the expected type of this import.
531    pub fn ty(&self) -> &T {
532        &self.ty
533    }
534}
535
536// Export Types
537
538/// A descriptor for an exported WebAssembly value.
539///
540/// This type is primarily accessed from the `Module::exports`
541/// accessor and describes what names are exported from a wasm module
542/// and the type of the item that is exported.
543///
544/// The `<T>` refefers to `ExternType`, however it can also refer to use
545/// `MemoryType`, `TableType`, `FunctionType` and `GlobalType` for ease of
546/// use.
547#[derive(Debug, Clone, PartialEq, Eq, Hash)]
548pub struct ExportType<T = ExternType> {
549    name: String,
550    ty: T,
551}
552
553impl<T> ExportType<T> {
554    /// Creates a new export which is exported with the given `name` and has the
555    /// given `ty`.
556    pub fn new(name: &str, ty: T) -> Self {
557        Self {
558            name: name.to_string(),
559            ty,
560        }
561    }
562
563    /// Returns the name by which this export is known by.
564    pub fn name(&self) -> &str {
565        &self.name
566    }
567
568    /// Returns the type of this export.
569    pub fn ty(&self) -> &T {
570        &self.ty
571    }
572}
573
574/// Fast gas counter with very simple structure, could be exposed to compiled code in the VM.
575#[repr(C)]
576#[derive(Debug, Clone, PartialEq, Eq)]
577pub struct FastGasCounter {
578    /// The following three fields must be put next to another to make sure
579    /// generated gas counting code can use and adjust them.
580    /// We will share counter to ensure we never miss synchronization.
581    /// This could change and in such a case synchronization required between compiled WASM code
582    /// and the host code.
583
584    /// The amount of gas that was irreversibly used for contract execution.
585    pub burnt_gas: u64,
586    /// Hard gas limit for execution
587    pub gas_limit: u64,
588    /// Single WASM opcode cost
589    pub opcode_cost: u64,
590}
591
592impl FastGasCounter {
593    /// New fast gas counter.
594    pub fn new(limit: u64, opcode: u64) -> Self {
595        FastGasCounter {
596            burnt_gas: 0,
597            gas_limit: limit,
598            opcode_cost: opcode,
599        }
600    }
601    /// Amount of gas burnt, maybe load as atomic to avoid aliasing issues.
602    pub fn burnt(&self) -> u64 {
603        self.burnt_gas
604    }
605}
606
607impl fmt::Display for FastGasCounter {
608    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
609        write!(
610            f,
611            "burnt: {} limit: {} op_cost: {} ",
612            self.burnt(),
613            self.gas_limit,
614            self.opcode_cost
615        )
616    }
617}
618
619/// External configuration of execution environment for Instance.
620#[derive(Clone)]
621pub struct InstanceConfig {
622    /// External gas counter pointer.
623    pub gas_counter: *mut FastGasCounter,
624    default_gas_counter: Option<Rc<UnsafeCell<FastGasCounter>>>,
625    /// Stack limit, in 8-byte slots.
626    pub stack_limit: i32,
627}
628
629// Default stack limit, in 8-byte stack slots.
630const DEFAULT_STACK_LIMIT: i32 = 100 * 1024;
631
632impl InstanceConfig {
633    /// Create default instance configuration.
634    pub fn default() -> Self {
635        let result = Rc::new(UnsafeCell::new(FastGasCounter {
636            burnt_gas: 0,
637            gas_limit: u64::MAX,
638            opcode_cost: 0,
639        }));
640        Self {
641            gas_counter: result.get(),
642            default_gas_counter: Some(result),
643            stack_limit: DEFAULT_STACK_LIMIT,
644        }
645    }
646
647    /// Create instance configuration with an external gas counter, unsafe as it creates
648    /// an alias on raw memory of gas_counter. This memory could be accessed until
649    /// instance configured with this `InstanceConfig` exists.
650    pub unsafe fn with_counter(mut self, gas_counter: *mut FastGasCounter) -> Self {
651        self.gas_counter = gas_counter;
652        self.default_gas_counter = None;
653        self
654    }
655
656    /// Create instance configuration with given stack limit.
657    pub unsafe fn with_stack_limit(mut self, stack_limit: i32) -> Self {
658        self.stack_limit = stack_limit;
659        self
660    }
661}
662
663#[cfg(test)]
664mod tests {
665    use super::*;
666
667    const VOID_TO_VOID: ([Type; 0], [Type; 0]) = ([], []);
668    const I32_I32_TO_VOID: ([Type; 2], [Type; 0]) = ([Type::I32, Type::I32], []);
669    const V128_I64_TO_I32: ([Type; 2], [Type; 1]) = ([Type::V128, Type::I64], [Type::I32]);
670    const NINE_V128_TO_NINE_I32: ([Type; 9], [Type; 9]) = ([Type::V128; 9], [Type::I32; 9]);
671
672    #[test]
673    fn convert_tuple_to_functiontype() {
674        let ty: FunctionType = VOID_TO_VOID.into();
675        assert_eq!(ty.params().len(), 0);
676        assert_eq!(ty.results().len(), 0);
677
678        let ty: FunctionType = I32_I32_TO_VOID.into();
679        assert_eq!(ty.params().len(), 2);
680        assert_eq!(ty.params()[0], Type::I32);
681        assert_eq!(ty.params()[1], Type::I32);
682        assert_eq!(ty.results().len(), 0);
683
684        let ty: FunctionType = V128_I64_TO_I32.into();
685        assert_eq!(ty.params().len(), 2);
686        assert_eq!(ty.params()[0], Type::V128);
687        assert_eq!(ty.params()[1], Type::I64);
688        assert_eq!(ty.results().len(), 1);
689        assert_eq!(ty.results()[0], Type::I32);
690
691        let ty: FunctionType = NINE_V128_TO_NINE_I32.into();
692        assert_eq!(ty.params().len(), 9);
693        assert_eq!(ty.results().len(), 9);
694    }
695}