substrate_wasmtime/
types.rs

1use std::fmt;
2use wasmtime_environ::{ir, wasm, EntityIndex};
3
4// Type Representations
5
6// Type attributes
7
8/// Indicator of whether a global is mutable or not
9#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
10pub enum Mutability {
11    /// The global is constant and its value does not change
12    Const,
13    /// The value of the global can change over time
14    Var,
15}
16
17/// Limits of tables/memories where the units of the limits are defined by the
18/// table/memory types.
19///
20/// A minimum is always available but the maximum may not be present.
21#[derive(Debug, Clone, Hash, Eq, PartialEq)]
22pub struct Limits {
23    min: u32,
24    max: Option<u32>,
25}
26
27impl Limits {
28    /// Creates a new set of limits with the minimum and maximum both specified.
29    pub fn new(min: u32, max: Option<u32>) -> Limits {
30        Limits { min, max }
31    }
32
33    /// Creates a new `Limits` with the `min` specified and no maximum specified.
34    pub fn at_least(min: u32) -> Limits {
35        Limits::new(min, None)
36    }
37
38    /// Returns the minimum amount for these limits.
39    pub fn min(&self) -> u32 {
40        self.min
41    }
42
43    /// Returns the maximum amount for these limits, if specified.
44    pub fn max(&self) -> Option<u32> {
45        self.max
46    }
47}
48
49// Value Types
50
51/// A list of all possible value types in WebAssembly.
52#[derive(Debug, Clone, Hash, Eq, PartialEq)]
53pub enum ValType {
54    /// Signed 32 bit integer.
55    I32,
56    /// Signed 64 bit integer.
57    I64,
58    /// Floating point 32 bit integer.
59    F32,
60    /// Floating point 64 bit integer.
61    F64,
62    /// A 128 bit number.
63    V128,
64    /// A reference to opaque data in the Wasm instance.
65    ExternRef, /* = 128 */
66    /// A reference to a Wasm function.
67    FuncRef,
68}
69
70impl fmt::Display for ValType {
71    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
72        match self {
73            ValType::I32 => write!(f, "i32"),
74            ValType::I64 => write!(f, "i64"),
75            ValType::F32 => write!(f, "f32"),
76            ValType::F64 => write!(f, "f64"),
77            ValType::V128 => write!(f, "v128"),
78            ValType::ExternRef => write!(f, "externref"),
79            ValType::FuncRef => write!(f, "funcref"),
80        }
81    }
82}
83
84impl ValType {
85    /// Returns true if `ValType` matches any of the numeric types. (e.g. `I32`,
86    /// `I64`, `F32`, `F64`).
87    pub fn is_num(&self) -> bool {
88        match self {
89            ValType::I32 | ValType::I64 | ValType::F32 | ValType::F64 => true,
90            _ => false,
91        }
92    }
93
94    /// Returns true if `ValType` matches either of the reference types.
95    pub fn is_ref(&self) -> bool {
96        match self {
97            ValType::ExternRef | ValType::FuncRef => true,
98            _ => false,
99        }
100    }
101
102    pub(crate) fn get_wasmtime_type(&self) -> ir::Type {
103        match self {
104            ValType::I32 => ir::types::I32,
105            ValType::I64 => ir::types::I64,
106            ValType::F32 => ir::types::F32,
107            ValType::F64 => ir::types::F64,
108            ValType::V128 => ir::types::I8X16,
109            ValType::ExternRef => wasmtime_runtime::ref_type(),
110            ValType::FuncRef => wasmtime_runtime::pointer_type(),
111        }
112    }
113
114    pub(crate) fn to_wasm_type(&self) -> wasm::WasmType {
115        match self {
116            Self::I32 => wasm::WasmType::I32,
117            Self::I64 => wasm::WasmType::I64,
118            Self::F32 => wasm::WasmType::F32,
119            Self::F64 => wasm::WasmType::F64,
120            Self::V128 => wasm::WasmType::V128,
121            Self::FuncRef => wasm::WasmType::FuncRef,
122            Self::ExternRef => wasm::WasmType::ExternRef,
123        }
124    }
125
126    pub(crate) fn from_wasm_type(ty: &wasm::WasmType) -> Self {
127        match ty {
128            wasm::WasmType::I32 => Self::I32,
129            wasm::WasmType::I64 => Self::I64,
130            wasm::WasmType::F32 => Self::F32,
131            wasm::WasmType::F64 => Self::F64,
132            wasm::WasmType::V128 => Self::V128,
133            wasm::WasmType::FuncRef => Self::FuncRef,
134            wasm::WasmType::ExternRef => Self::ExternRef,
135        }
136    }
137}
138
139// External Types
140
141/// A list of all possible types which can be externally referenced from a
142/// WebAssembly module.
143///
144/// This list can be found in [`ImportType`] or [`ExportType`], so these types
145/// can either be imported or exported.
146#[derive(Debug, Clone, Hash, Eq, PartialEq)]
147pub enum ExternType {
148    /// This external type is the type of a WebAssembly function.
149    Func(FuncType),
150    /// This external type is the type of a WebAssembly global.
151    Global(GlobalType),
152    /// This external type is the type of a WebAssembly table.
153    Table(TableType),
154    /// This external type is the type of a WebAssembly memory.
155    Memory(MemoryType),
156}
157
158macro_rules! accessors {
159    ($(($variant:ident($ty:ty) $get:ident $unwrap:ident))*) => ($(
160        /// Attempt to return the underlying type of this external type,
161        /// returning `None` if it is a different type.
162        pub fn $get(&self) -> Option<&$ty> {
163            if let ExternType::$variant(e) = self {
164                Some(e)
165            } else {
166                None
167            }
168        }
169
170        /// Returns the underlying descriptor of this [`ExternType`], panicking
171        /// if it is a different type.
172        ///
173        /// # Panics
174        ///
175        /// Panics if `self` is not of the right type.
176        pub fn $unwrap(&self) -> &$ty {
177            self.$get().expect(concat!("expected ", stringify!($ty)))
178        }
179    )*)
180}
181
182impl ExternType {
183    accessors! {
184        (Func(FuncType) func unwrap_func)
185        (Global(GlobalType) global unwrap_global)
186        (Table(TableType) table unwrap_table)
187        (Memory(MemoryType) memory unwrap_memory)
188    }
189}
190
191impl From<FuncType> for ExternType {
192    fn from(ty: FuncType) -> ExternType {
193        ExternType::Func(ty)
194    }
195}
196
197impl From<GlobalType> for ExternType {
198    fn from(ty: GlobalType) -> ExternType {
199        ExternType::Global(ty)
200    }
201}
202
203impl From<MemoryType> for ExternType {
204    fn from(ty: MemoryType) -> ExternType {
205        ExternType::Memory(ty)
206    }
207}
208
209impl From<TableType> for ExternType {
210    fn from(ty: TableType) -> ExternType {
211        ExternType::Table(ty)
212    }
213}
214
215/// A descriptor for a function in a WebAssembly module.
216///
217/// WebAssembly functions can have 0 or more parameters and results.
218#[derive(Debug, Clone, Hash, Eq, PartialEq)]
219pub struct FuncType {
220    params: Box<[ValType]>,
221    results: Box<[ValType]>,
222}
223
224impl FuncType {
225    /// Creates a new function descriptor from the given parameters and results.
226    ///
227    /// The function descriptor returned will represent a function which takes
228    /// `params` as arguments and returns `results` when it is finished.
229    pub fn new(params: Box<[ValType]>, results: Box<[ValType]>) -> FuncType {
230        FuncType { params, results }
231    }
232
233    /// Returns the list of parameter types for this function.
234    pub fn params(&self) -> &[ValType] {
235        &self.params
236    }
237
238    /// Returns the list of result types for this function.
239    pub fn results(&self) -> &[ValType] {
240        &self.results
241    }
242
243    pub(crate) fn to_wasm_func_type(&self) -> wasm::WasmFuncType {
244        wasm::WasmFuncType {
245            params: self.params.iter().map(|p| p.to_wasm_type()).collect(),
246            returns: self.results.iter().map(|r| r.to_wasm_type()).collect(),
247        }
248    }
249
250    /// Get the Cranelift-compatible function signature.
251    pub(crate) fn get_wasmtime_signature(&self, pointer_type: ir::Type) -> ir::Signature {
252        use wasmtime_environ::ir::{AbiParam, ArgumentPurpose, Signature};
253        use wasmtime_jit::native;
254        let call_conv = native::call_conv();
255        let mut params = self
256            .params
257            .iter()
258            .map(|p| AbiParam::new(p.get_wasmtime_type()))
259            .collect::<Vec<_>>();
260        let returns = self
261            .results
262            .iter()
263            .map(|p| AbiParam::new(p.get_wasmtime_type()))
264            .collect::<Vec<_>>();
265        params.insert(
266            0,
267            AbiParam::special(pointer_type, ArgumentPurpose::VMContext),
268        );
269        params.insert(1, AbiParam::new(pointer_type));
270
271        Signature {
272            params,
273            returns,
274            call_conv,
275        }
276    }
277
278    /// Returns `None` if any types in the signature can't be converted to the
279    /// types in this crate, but that should very rarely happen and largely only
280    /// indicate a bug in our cranelift integration.
281    pub(crate) fn from_wasm_func_type(signature: &wasm::WasmFuncType) -> FuncType {
282        let params = signature
283            .params
284            .iter()
285            .map(|p| ValType::from_wasm_type(p))
286            .collect::<Vec<_>>();
287        let results = signature
288            .returns
289            .iter()
290            .map(|r| ValType::from_wasm_type(r))
291            .collect::<Vec<_>>();
292        FuncType {
293            params: params.into_boxed_slice(),
294            results: results.into_boxed_slice(),
295        }
296    }
297}
298
299// Global Types
300
301/// A WebAssembly global descriptor.
302///
303/// This type describes an instance of a global in a WebAssembly module. Globals
304/// are local to an [`Instance`](crate::Instance) and are either immutable or
305/// mutable.
306#[derive(Debug, Clone, Hash, Eq, PartialEq)]
307pub struct GlobalType {
308    content: ValType,
309    mutability: Mutability,
310}
311
312impl GlobalType {
313    /// Creates a new global descriptor of the specified `content` type and
314    /// whether or not it's mutable.
315    pub fn new(content: ValType, mutability: Mutability) -> GlobalType {
316        GlobalType {
317            content,
318            mutability,
319        }
320    }
321
322    /// Returns the value type of this global descriptor.
323    pub fn content(&self) -> &ValType {
324        &self.content
325    }
326
327    /// Returns whether or not this global is mutable.
328    pub fn mutability(&self) -> Mutability {
329        self.mutability
330    }
331
332    /// Returns `None` if the wasmtime global has a type that we can't
333    /// represent, but that should only very rarely happen and indicate a bug.
334    pub(crate) fn from_wasmtime_global(global: &wasm::Global) -> GlobalType {
335        let ty = ValType::from_wasm_type(&global.wasm_ty);
336        let mutability = if global.mutability {
337            Mutability::Var
338        } else {
339            Mutability::Const
340        };
341        GlobalType::new(ty, mutability)
342    }
343}
344
345// Table Types
346
347/// A descriptor for a table in a WebAssembly module.
348///
349/// Tables are contiguous chunks of a specific element, typically a `funcref` or
350/// an `externref`. The most common use for tables is a function table through
351/// which `call_indirect` can invoke other functions.
352#[derive(Debug, Clone, Hash, Eq, PartialEq)]
353pub struct TableType {
354    element: ValType,
355    limits: Limits,
356}
357
358impl TableType {
359    /// Creates a new table descriptor which will contain the specified
360    /// `element` and have the `limits` applied to its length.
361    pub fn new(element: ValType, limits: Limits) -> TableType {
362        TableType { element, limits }
363    }
364
365    /// Returns the element value type of this table.
366    pub fn element(&self) -> &ValType {
367        &self.element
368    }
369
370    /// Returns the limits, in units of elements, of this table.
371    pub fn limits(&self) -> &Limits {
372        &self.limits
373    }
374
375    pub(crate) fn from_wasmtime_table(table: &wasm::Table) -> TableType {
376        let ty = match table.ty {
377            wasm::TableElementType::Func => ValType::FuncRef,
378            #[cfg(target_pointer_width = "64")]
379            wasm::TableElementType::Val(ir::types::R64) => ValType::ExternRef,
380            #[cfg(target_pointer_width = "32")]
381            wasm::TableElementType::Val(ir::types::R32) => ValType::ExternRef,
382            _ => panic!("only `funcref` and `externref` tables supported"),
383        };
384        let limits = Limits::new(table.minimum, table.maximum);
385        TableType::new(ty, limits)
386    }
387}
388
389// Memory Types
390
391/// A descriptor for a WebAssembly memory type.
392///
393/// Memories are described in units of pages (64KB) and represent contiguous
394/// chunks of addressable memory.
395#[derive(Debug, Clone, Hash, Eq, PartialEq)]
396pub struct MemoryType {
397    limits: Limits,
398}
399
400impl MemoryType {
401    /// Creates a new descriptor for a WebAssembly memory given the specified
402    /// limits of the memory.
403    pub fn new(limits: Limits) -> MemoryType {
404        MemoryType { limits }
405    }
406
407    /// Returns the limits (in pages) that are configured for this memory.
408    pub fn limits(&self) -> &Limits {
409        &self.limits
410    }
411
412    pub(crate) fn from_wasmtime_memory(memory: &wasm::Memory) -> MemoryType {
413        MemoryType::new(Limits::new(memory.minimum, memory.maximum))
414    }
415}
416
417// Entity Types
418
419#[derive(Clone, Hash, Eq, PartialEq)]
420pub(crate) enum EntityType<'module> {
421    Function(&'module wasm::WasmFuncType),
422    Table(&'module wasm::Table),
423    Memory(&'module wasm::Memory),
424    Global(&'module wasm::Global),
425}
426
427impl<'module> EntityType<'module> {
428    /// Translate from a `EntityIndex` into an `ExternType`.
429    pub(crate) fn new(
430        entity_index: &EntityIndex,
431        module: &'module wasmtime_environ::Module,
432    ) -> EntityType<'module> {
433        match entity_index {
434            EntityIndex::Function(func_index) => {
435                let sig = module.local.wasm_func_type(*func_index);
436                EntityType::Function(&sig)
437            }
438            EntityIndex::Table(table_index) => {
439                EntityType::Table(&module.local.table_plans[*table_index].table)
440            }
441            EntityIndex::Memory(memory_index) => {
442                EntityType::Memory(&module.local.memory_plans[*memory_index].memory)
443            }
444            EntityIndex::Global(global_index) => {
445                EntityType::Global(&module.local.globals[*global_index])
446            }
447        }
448    }
449
450    /// Convert this `EntityType` to an `ExternType`.
451    pub(crate) fn extern_type(&self) -> ExternType {
452        match self {
453            EntityType::Function(sig) => FuncType::from_wasm_func_type(sig).into(),
454            EntityType::Table(table) => TableType::from_wasmtime_table(table).into(),
455            EntityType::Memory(memory) => MemoryType::from_wasmtime_memory(memory).into(),
456            EntityType::Global(global) => GlobalType::from_wasmtime_global(global).into(),
457        }
458    }
459}
460
461// Import Types
462
463/// A descriptor for an imported value into a wasm module.
464///
465/// This type is primarily accessed from the
466/// [`Module::imports`](crate::Module::imports) API. Each [`ImportType`]
467/// describes an import into the wasm module with the module/name that it's
468/// imported from as well as the type of item that's being imported.
469#[derive(Clone, Hash, Eq, PartialEq)]
470pub struct ImportType<'module> {
471    /// The module of the import.
472    module: &'module str,
473
474    /// The field of the import.
475    name: &'module str,
476
477    /// The type of the import.
478    ty: EntityType<'module>,
479}
480
481impl<'module> ImportType<'module> {
482    /// Creates a new import descriptor which comes from `module` and `name` and
483    /// is of type `ty`.
484    pub(crate) fn new(
485        module: &'module str,
486        name: &'module str,
487        ty: EntityType<'module>,
488    ) -> ImportType<'module> {
489        ImportType { module, name, ty }
490    }
491
492    /// Returns the module name that this import is expected to come from.
493    pub fn module(&self) -> &'module str {
494        self.module
495    }
496
497    /// Returns the field name of the module that this import is expected to
498    /// come from.
499    pub fn name(&self) -> &'module str {
500        self.name
501    }
502
503    /// Returns the expected type of this import.
504    pub fn ty(&self) -> ExternType {
505        self.ty.extern_type()
506    }
507}
508
509impl<'module> fmt::Debug for ImportType<'module> {
510    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
511        f.debug_struct("ImportType")
512            .field("module", &self.module().to_owned())
513            .field("name", &self.name().to_owned())
514            .field("ty", &self.ty())
515            .finish()
516    }
517}
518
519// Export Types
520
521/// A descriptor for an exported WebAssembly value.
522///
523/// This type is primarily accessed from the
524/// [`Module::exports`](crate::Module::exports) accessor and describes what
525/// names are exported from a wasm module and the type of the item that is
526/// exported.
527#[derive(Clone, Hash, Eq, PartialEq)]
528pub struct ExportType<'module> {
529    /// The name of the export.
530    name: &'module str,
531
532    /// The type of the export.
533    ty: EntityType<'module>,
534}
535
536impl<'module> ExportType<'module> {
537    /// Creates a new export which is exported with the given `name` and has the
538    /// given `ty`.
539    pub(crate) fn new(name: &'module str, ty: EntityType<'module>) -> ExportType<'module> {
540        ExportType { name, ty }
541    }
542
543    /// Returns the name by which this export is known.
544    pub fn name(&self) -> &'module str {
545        self.name
546    }
547
548    /// Returns the type of this export.
549    pub fn ty(&self) -> ExternType {
550        self.ty.extern_type()
551    }
552}
553
554impl<'module> fmt::Debug for ExportType<'module> {
555    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
556        f.debug_struct("ExportType")
557            .field("name", &self.name().to_owned())
558            .field("ty", &self.ty())
559            .finish()
560    }
561}