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