1 //! Definition of the ABI of witx functions
2 //!
3 //! This module is intended to assist with code generators which are binding or
4 //! implementing APIs defined by `*.witx` files. THis module contains all
5 //! details necessary to implement the actual ABI of these functions so wasm
6 //! modules and hosts can communicate with one another.
7 //!
8 //! Each interface types function (a function defined in `*.witx`) currently has
9 //! a well-known wasm signature associated with it. There's then also a standard
10 //! way to convert from interface-types values (whose representation is defined
11 //! per-language) into this wasm API. This module is intended to assist with
12 //! this definition.
13 //!
14 //! Contained within are two primary functions, [`InterfaceFunc::call_wasm`] and
15 //! [`InterfaceFunc::call_interface`]. These functions implement the two ways to
16 //! interact with an interface types function, namely calling the raw wasm
17 //! version and calling the high-level version with interface types. These two
18 //! functions are fed a structure that implements [`Bindgen`]. An instance of
19 //! [`Bindgen`] receives instructions which are low-level implementation details
20 //! of how to convert to and from wasm types and interface types. Code
21 //! generators will need to implement the various instructions to support APIs.
22 
23 use crate::{
24     BuiltinType, Id, IntRepr, InterfaceFunc, InterfaceFuncParam, NamedType, Type, TypeRef,
25 };
26 
27 /// Enumerates wasm types used by interface types when lowering/lifting.
28 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
29 pub enum WasmType {
30     I32,
31     I64,
32     F32,
33     F64,
34     // NOTE: we don't lower interface types to any other Wasm type,
35     // e.g. externref, so we don't need to define them here.
36 }
37 
38 impl From<IntRepr> for WasmType {
from(i: IntRepr) -> WasmType39     fn from(i: IntRepr) -> WasmType {
40         match i {
41             IntRepr::U8 | IntRepr::U16 | IntRepr::U32 => WasmType::I32,
42             IntRepr::U64 => WasmType::I64,
43         }
44     }
45 }
46 
47 /// Possible ABIs for interface functions to have.
48 ///
49 /// Note that this is a stopgap until we have more of interface types. Interface
50 /// types functions do not have ABIs, they have APIs. For the meantime, however,
51 /// we mandate ABIs to ensure we can all talk to each other.
52 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
53 pub enum Abi {
54     /// Only stable ABI currently, and is the historical WASI ABI since it was
55     /// first created.
56     ///
57     /// Note that this ABI is limited notably in its return values where it can
58     /// only return 0 results or one `Result<T, enum>` lookalike.
59     Preview1,
60 }
61 
62 // Helper macro for defining instructions without having to have tons of
63 // exhaustive `match` statements to update
64 macro_rules! def_instruction {
65     (
66         $( #[$enum_attr:meta] )*
67         pub enum Instruction<'a> {
68             $(
69                 $( #[$attr:meta] )*
70                 $variant:ident $( {
71                     $($field:ident : $field_ty:ty $(,)* )*
72                 } )?
73                     :
74                 [$num_popped:expr] => [$num_pushed:expr],
75             )*
76         }
77     ) => {
78         $( #[$enum_attr] )*
79         pub enum Instruction<'a> {
80             $(
81                 $( #[$attr] )*
82                 $variant $( {
83                     $(
84                         $field : $field_ty,
85                     )*
86                 } )? ,
87             )*
88         }
89 
90         impl Instruction<'_> {
91             /// How many operands does this instruction pop from the stack?
92             #[allow(unused_variables)]
93             pub fn operands_len(&self) -> usize {
94                 match self {
95                     $(
96                         Self::$variant $( {
97                             $(
98                                 $field,
99                             )*
100                         } )? => $num_popped,
101                     )*
102                 }
103             }
104 
105             /// How many results does this instruction push onto the stack?
106             #[allow(unused_variables)]
107             pub fn results_len(&self) -> usize {
108                 match self {
109                     $(
110                         Self::$variant $( {
111                             $(
112                                 $field,
113                             )*
114                         } )? => $num_pushed,
115                     )*
116                 }
117             }
118         }
119     };
120 }
121 
122 def_instruction! {
123     #[derive(Debug)]
124     pub enum Instruction<'a> {
125         /// Acquires the specified parameter and places it on the stack.
126         /// Depending on the context this may refer to wasm parameters or
127         /// interface types parameters.
128         GetArg { nth: usize } : [0] => [1],
129         /// Takes the value off the top of the stack and writes it into linear
130         /// memory. Pushes the address in linear memory as an `i32`.
131         AddrOf : [1] => [1],
132         /// Converts an interface type `char` value to a 32-bit integer
133         /// representing the unicode scalar value.
134         I32FromChar : [1] => [1],
135         /// Converts an interface type `u64` value to a wasm `i64`.
136         I64FromU64 : [1] => [1],
137         /// Converts an interface type `s64` value to a wasm `i64`.
138         I64FromS64 : [1] => [1],
139         /// Converts an interface type `u32` value to a wasm `i32`.
140         I32FromU32 : [1] => [1],
141         /// Converts an interface type `s32` value to a wasm `i32`.
142         I32FromS32 : [1] => [1],
143         /// Converts a language-specific `usize` value to a wasm `i32`.
144         I32FromUsize : [1] => [1],
145         /// Converts an interface type `u16` value to a wasm `i32`.
146         I32FromU16 : [1] => [1],
147         /// Converts an interface type `s16` value to a wasm `i32`.
148         I32FromS16 : [1] => [1],
149         /// Converts an interface type `u8` value to a wasm `i32`.
150         I32FromU8 : [1] => [1],
151         /// Converts an interface type `s8` value to a wasm `i32`.
152         I32FromS8 : [1] => [1],
153         /// Converts a language-specific C `char` value to a wasm `i32`.
154         I32FromChar8 : [1] => [1],
155         /// Converts a language-specific pointer value to a wasm `i32`.
156         I32FromPointer : [1] => [1],
157         /// Converts a language-specific pointer value to a wasm `i32`.
158         I32FromConstPointer : [1] => [1],
159         /// Converts a language-specific handle value to a wasm `i32`.
160         I32FromHandle { ty: &'a NamedType } : [1] => [1],
161         /// Converts a language-specific record-of-bools to the packed
162         /// representation as an `i32`.
163         I32FromBitflags { ty: &'a NamedType } : [1] => [1],
164         /// Converts a language-specific record-of-bools to the packed
165         /// representation as an `i64`.
166         I64FromBitflags { ty: &'a NamedType } : [1] => [1],
167         /// Converts an interface type list into its pointer/length, pushing
168         /// them both on the stack.
169         ListPointerLength : [1] => [2],
170         /// Pops two `i32` values from the stack and creates a list from them of
171         /// the specified type. The first operand is the pointer in linear
172         /// memory to the start of the list and the second operand is the
173         /// length.
174         ListFromPointerLength { ty: &'a TypeRef } : [2] => [1],
175         /// Conversion an interface type `f32` value to a wasm `f32`.
176         ///
177         /// This may be a noop for some implementations, but it's here in case the
178         /// native language representation of `f32` is different than the wasm
179         /// representation of `f32`.
180         F32FromIf32 : [1] => [1],
181         /// Conversion an interface type `f64` value to a wasm `f64`.
182         ///
183         /// This may be a noop for some implementations, but it's here in case the
184         /// native language representation of `f64` is different than the wasm
185         /// representation of `f64`.
186         F64FromIf64 : [1] => [1],
187 
188         /// Represents a call to a raw WebAssembly API. The module/name are
189         /// provided inline as well as the types if necessary.
190         CallWasm {
191             module: &'a str,
192             name: &'a str,
193             params: &'a [WasmType],
194             results: &'a [WasmType],
195         } : [params.len()] => [results.len()],
196 
197         /// Same as `CallWasm`, except the dual where an interface is being
198         /// called rather than a raw wasm function.
199         CallInterface {
200             module: &'a str,
201             func: &'a InterfaceFunc,
202         } : [func.params.len()] => [func.results.len()],
203 
204         /// Converts a native wasm `i32` to an interface type `s8`.
205         ///
206         /// This will truncate the upper bits of the `i32`.
207         S8FromI32 : [1] => [1],
208         /// Converts a native wasm `i32` to an interface type `u8`.
209         ///
210         /// This will truncate the upper bits of the `i32`.
211         U8FromI32 : [1] => [1],
212         /// Converts a native wasm `i32` to an interface type `s16`.
213         ///
214         /// This will truncate the upper bits of the `i32`.
215         S16FromI32 : [1] => [1],
216         /// Converts a native wasm `i32` to an interface type `u16`.
217         ///
218         /// This will truncate the upper bits of the `i32`.
219         U16FromI32 : [1] => [1],
220         /// Converts a native wasm `i32` to an interface type `s32`.
221         S32FromI32 : [1] => [1],
222         /// Converts a native wasm `i32` to an interface type `u32`.
223         U32FromI32 : [1] => [1],
224         /// Converts a native wasm `i64` to an interface type `s64`.
225         S64FromI64 : [1] => [1],
226         /// Converts a native wasm `i64` to an interface type `u64`.
227         U64FromI64 : [1] => [1],
228         /// Converts a native wasm `i32` to an interface type `char`.
229         ///
230         /// It's safe to assume that the `i32` is indeed a valid unicode code point.
231         CharFromI32 : [1] => [1],
232         /// Converts a native wasm `i32` to a language-specific C `char`.
233         ///
234         /// This will truncate the upper bits of the `i32`.
235         Char8FromI32 : [1] => [1],
236         /// Converts a native wasm `i32` to a language-specific `usize`.
237         UsizeFromI32 : [1] => [1],
238         /// Converts a native wasm `f32` to an interface type `f32`.
239         If32FromF32 : [1] => [1],
240         /// Converts a native wasm `f64` to an interface type `f64`.
241         If64FromF64 : [1] => [1],
242         /// Converts a native wasm `i32` to an interface type `handle`.
243         HandleFromI32 { ty: &'a NamedType } : [1] => [1],
244         /// Converts a native wasm `i32` to a language-specific pointer.
245         PointerFromI32 { ty: &'a TypeRef }: [1] => [1],
246         /// Converts a native wasm `i32` to a language-specific pointer.
247         ConstPointerFromI32 { ty: &'a TypeRef } : [1] => [1],
248         /// Converts a native wasm `i32` to a language-specific record-of-bools.
249         BitflagsFromI32 { ty: &'a NamedType } : [1] => [1],
250         /// Converts a native wasm `i64` to a language-specific record-of-bools.
251         BitflagsFromI64 { ty: &'a NamedType } : [1] => [1],
252         /// Acquires the return pointer `n` and pushes an `i32` on the stack.
253         ///
254         /// Implementations of [`Bindgen`] may have [`Bindgen::allocate_space`]
255         /// called to reserve space in memory for the result of a computation to
256         /// get written. This instruction acquires a pointer to the space
257         /// reserved in `allocate_space`.
258         ReturnPointerGet { n: usize } : [0] => [1],
259         /// Loads the interface types value from an `i32` pointer popped from
260         /// the stack.
261         Load { ty: &'a NamedType } : [1] => [1],
262         /// Stores an interface types value into linear memory. The first
263         /// operand is the value to store and the second operand is the pointer
264         /// in linear memory to store it at.
265         Store { ty: &'a NamedType } : [2] => [0],
266         /// Pops a native wasm `i32` from the stack, as well as two blocks
267         /// internally from the code generator.
268         ///
269         /// If the value is 0 then the first "ok" block value should be used.
270         /// If the value is anything else then the second "err" block value
271         /// should be used, and the value is used as the error enum.
272         ///
273         /// Note that this is a special instruction matching the current ABI of
274         /// WASI and intentionally differs from the type-level grammar of
275         /// interface types results.
276         ResultLift : [1] => [1],
277         /// Pops a native interface value from the stack as well as two blocks
278         /// internally from the code generator.
279         ///
280         /// A `match` is performed on the value popped and the corresponding
281         /// block for ok/err is used depending on value. This pushes a single
282         /// `i32` onto the stack representing the error code for this result.
283         ///
284         /// Note that like `ResultLift` this is specialized to the current WASI
285         /// ABI.
286         ResultLower {
287             ok: Option<&'a TypeRef>,
288             err: Option<&'a TypeRef>,
289         } : [1] => [1],
290         /// Converts a native wasm `i32` to an interface type `enum` value.
291         ///
292         /// It's guaranteed that the interface type integer value is within
293         /// range for this enum's type. Additionally `ty` is guaranteed to be
294         /// enum-like as a `Variant` where all `case` arms have no associated
295         /// type with them. The purpose of this instruction is to convert a
296         /// native wasm integer into the enum type for the interface.
297         EnumLift { ty: &'a NamedType } : [1] => [1],
298         /// Converts an interface types enum value into a wasm `i32`.
299         EnumLower { ty: &'a NamedType } : [1] => [1],
300         /// Creates a tuple from the top `n` elements on the stack, pushing the
301         /// tuple onto the stack.
302         TupleLift { amt: usize } : [*amt] => [1],
303         /// Splits a tuple at the top of the stack into its `n` components,
304         /// pushing them all onto the stack.
305         TupleLower { amt: usize } : [1] => [*amt],
306         /// This is a special instruction specifically for the original ABI of
307         /// WASI.  The raw return `i32` of a function is re-pushed onto the
308         /// stack for reuse.
309         ReuseReturn : [0] => [1],
310         /// Returns `amt` values on the stack. This is always the last
311         /// instruction.
312         Return { amt: usize } : [*amt] => [0],
313         /// This is a special instruction used at the entry of blocks used as
314         /// part of `ResultLower`, representing that the payload of that variant
315         /// being matched on should be pushed onto the stack.
316         VariantPayload : [0] => [1],
317     }
318 }
319 
320 impl Abi {
321     /// Validates the parameters/results are representable in this ABI.
322     ///
323     /// Returns an error string if they're not representable or returns `Ok` if
324     /// they're indeed representable.
validate( &self, _params: &[InterfaceFuncParam], results: &[InterfaceFuncParam], ) -> Result<(), String>325     pub fn validate(
326         &self,
327         _params: &[InterfaceFuncParam],
328         results: &[InterfaceFuncParam],
329     ) -> Result<(), String> {
330         assert_eq!(*self, Abi::Preview1);
331         match results.len() {
332             0 => {}
333             1 => match &**results[0].tref.type_() {
334                 Type::Handle(_) | Type::Builtin(_) | Type::ConstPointer(_) | Type::Pointer(_) => {}
335                 Type::Variant(v) => {
336                     let (ok, err) = match v.as_expected() {
337                         Some(pair) => pair,
338                         None => return Err("invalid return type".to_string()),
339                     };
340                     if let Some(ty) = ok {
341                         match &**ty.type_() {
342                             Type::Record(r) if r.is_tuple() => {
343                                 for member in r.members.iter() {
344                                     if !member.tref.named() {
345                                         return Err(
346                                             "only named types are allowed in results".to_string()
347                                         );
348                                     }
349                                 }
350                             }
351                             _ => {
352                                 if !ty.named() {
353                                     return Err(
354                                         "only named types are allowed in results".to_string()
355                                     );
356                                 }
357                             }
358                         }
359                     }
360                     if let Some(ty) = err {
361                         if !ty.named() {
362                             return Err("only named types are allowed in results".to_string());
363                         }
364                         if let Type::Variant(v) = &**ty.type_() {
365                             if v.is_enum() {
366                                 return Ok(());
367                             }
368                         }
369                     }
370                 }
371                 Type::Record(r) if r.bitflags_repr().is_some() => {}
372                 Type::Record(_) | Type::List(_) => return Err("invalid return type".to_string()),
373             },
374             _ => return Err("more than one result".to_string()),
375         }
376         Ok(())
377     }
378 }
379 
380 /// Trait for language implementors to use to generate glue code between native
381 /// WebAssembly signatures and interface types signatures.
382 ///
383 /// This is used as an implementation detail in interpreting the ABI between
384 /// interface types and wasm types. Eventually this will be driven by interface
385 /// types adapters themselves, but for now the ABI of a function dictates what
386 /// instructions are fed in.
387 ///
388 /// Types implementing `Bindgen` are incrementally fed `Instruction` values to
389 /// generate code for. Instructions operate like a stack machine where each
390 /// instruction has a list of inputs and a list of outputs (provided by the
391 /// `emit` function).
392 pub trait Bindgen {
393     /// The intermediate type for fragments of code for this type.
394     ///
395     /// For most languages `String` is a suitable intermediate type.
396     type Operand;
397 
398     /// Emit code to implement the given instruction.
399     ///
400     /// Each operand is given in `operands` and can be popped off if ownership
401     /// is required. It's guaranteed that `operands` has the appropriate length
402     /// for the `inst` given, as specified with [`Instruction`].
403     ///
404     /// Each result variable should be pushed onto `results`. This function must
405     /// push the appropriate number of results or binding generation will panic.
emit( &mut self, inst: &Instruction<'_>, operands: &mut Vec<Self::Operand>, results: &mut Vec<Self::Operand>, )406     fn emit(
407         &mut self,
408         inst: &Instruction<'_>,
409         operands: &mut Vec<Self::Operand>,
410         results: &mut Vec<Self::Operand>,
411     );
412 
413     /// Allocates temporary space in linear memory indexed by `slot` with enough
414     /// space to store `ty`.
415     ///
416     /// This is called when calling some wasm functions where a return pointer
417     /// is needed.
allocate_space(&mut self, slot: usize, ty: &NamedType)418     fn allocate_space(&mut self, slot: usize, ty: &NamedType);
419 
420     /// Enters a new block of code to generate code for.
421     ///
422     /// This is currently exclusively used for constructing variants. When a
423     /// variant is constructed a block here will be pushed for each case of a
424     /// variant, generating the code necessary to translate a variant case.
425     ///
426     /// Blocks are completed with `finish_block` below. It's expected that `emit`
427     /// will always push code (if necessary) into the "current block", which is
428     /// updated by calling this method and `finish_block` below.
push_block(&mut self)429     fn push_block(&mut self);
430 
431     /// Indicates to the code generator that a block is completed, and the
432     /// `operand` specified was the resulting value of the block.
433     ///
434     /// This method will be used to compute the value of each arm of lifting a
435     /// variant. The `operand` will be `None` if the variant case didn't
436     /// actually have any type associated with it. Otherwise it will be `Some`
437     /// as the last value remaining on the stack representing the value
438     /// associated with a variant's `case`.
439     ///
440     /// It's expected that this will resume code generation in the previous
441     /// block before `push_block` was called. This must also save the results
442     /// of the current block internally for instructions like `ResultLift` to
443     /// use later.
finish_block(&mut self, operand: Option<Self::Operand>)444     fn finish_block(&mut self, operand: Option<Self::Operand>);
445 }
446 
447 impl InterfaceFunc {
448     /// Get the WebAssembly type signature for this interface function
449     ///
450     /// The first entry returned is the list of parameters and the second entry
451     /// is the list of results for the wasm function signature.
wasm_signature(&self) -> (Vec<WasmType>, Vec<WasmType>)452     pub fn wasm_signature(&self) -> (Vec<WasmType>, Vec<WasmType>) {
453         assert_eq!(self.abi, Abi::Preview1);
454         let mut params = Vec::new();
455         let mut results = Vec::new();
456         for param in self.params.iter() {
457             match &**param.tref.type_() {
458                 Type::Builtin(BuiltinType::S8)
459                 | Type::Builtin(BuiltinType::U8 { .. })
460                 | Type::Builtin(BuiltinType::S16)
461                 | Type::Builtin(BuiltinType::U16)
462                 | Type::Builtin(BuiltinType::S32)
463                 | Type::Builtin(BuiltinType::U32 { .. })
464                 | Type::Builtin(BuiltinType::Char)
465                 | Type::Pointer(_)
466                 | Type::ConstPointer(_)
467                 | Type::Handle(_)
468                 | Type::Variant(_) => params.push(WasmType::I32),
469 
470                 Type::Record(r) => match r.bitflags_repr() {
471                     Some(repr) => params.push(WasmType::from(repr)),
472                     None => params.push(WasmType::I32),
473                 },
474 
475                 Type::Builtin(BuiltinType::S64) | Type::Builtin(BuiltinType::U64) => {
476                     params.push(WasmType::I64)
477                 }
478 
479                 Type::Builtin(BuiltinType::F32) => params.push(WasmType::F32),
480                 Type::Builtin(BuiltinType::F64) => params.push(WasmType::F64),
481 
482                 Type::List(_) => {
483                     params.push(WasmType::I32);
484                     params.push(WasmType::I32);
485                 }
486             }
487         }
488 
489         for param in self.results.iter() {
490             match &**param.tref.type_() {
491                 Type::Builtin(BuiltinType::S8)
492                 | Type::Builtin(BuiltinType::U8 { .. })
493                 | Type::Builtin(BuiltinType::S16)
494                 | Type::Builtin(BuiltinType::U16)
495                 | Type::Builtin(BuiltinType::S32)
496                 | Type::Builtin(BuiltinType::U32 { .. })
497                 | Type::Builtin(BuiltinType::Char)
498                 | Type::Pointer(_)
499                 | Type::ConstPointer(_)
500                 | Type::Handle(_) => results.push(WasmType::I32),
501 
502                 Type::Builtin(BuiltinType::S64) | Type::Builtin(BuiltinType::U64) => {
503                     results.push(WasmType::I64)
504                 }
505 
506                 Type::Builtin(BuiltinType::F32) => results.push(WasmType::F32),
507                 Type::Builtin(BuiltinType::F64) => results.push(WasmType::F64),
508 
509                 Type::Record(r) => match r.bitflags_repr() {
510                     Some(repr) => results.push(WasmType::from(repr)),
511                     None => unreachable!(),
512                 },
513                 Type::List(_) => unreachable!(),
514 
515                 Type::Variant(v) => {
516                     results.push(match v.tag_repr {
517                         IntRepr::U64 => WasmType::I64,
518                         IntRepr::U32 | IntRepr::U16 | IntRepr::U8 => WasmType::I32,
519                     });
520                     if v.is_enum() {
521                         continue;
522                     }
523                     // return pointer
524                     if let Some(ty) = &v.cases[0].tref {
525                         match &**ty.type_() {
526                             Type::Record(r) if r.is_tuple() => {
527                                 for _ in 0..r.members.len() {
528                                     params.push(WasmType::I32);
529                                 }
530                             }
531                             _ => params.push(WasmType::I32),
532                         }
533                     }
534                 }
535             }
536         }
537         (params, results)
538     }
539 
540     /// Generates an abstract sequence of instructions which represents this
541     /// function being adapted as an imported function.
542     ///
543     /// The instructions here, when executed, will emulate a language with
544     /// interface types calling the concrete wasm implementation. The parameters
545     /// for the returned instruction sequence are the language's own
546     /// interface-types parameters. One instruction in the instruction stream
547     /// will be a `Call` which represents calling the actual raw wasm function
548     /// signature.
549     ///
550     /// This function is useful, for example, if you're building a language
551     /// generator for WASI bindings. This will document how to translate
552     /// language-specific values into the wasm types to call a WASI function,
553     /// and it will also automatically convert the results of the WASI function
554     /// back to a language-specific value.
call_wasm(&self, module: &Id, bindgen: &mut impl Bindgen)555     pub fn call_wasm(&self, module: &Id, bindgen: &mut impl Bindgen) {
556         assert_eq!(self.abi, Abi::Preview1);
557         Generator {
558             bindgen,
559             operands: vec![],
560             results: vec![],
561             stack: vec![],
562         }
563         .call_wasm(module, self);
564     }
565 
566     /// This is the dual of [`InterfaceFunc::call_wasm`], except that instead of
567     /// calling a wasm signature it generates code to come from a wasm signature
568     /// and call an interface types signature.
call_interface(&self, module: &Id, bindgen: &mut impl Bindgen)569     pub fn call_interface(&self, module: &Id, bindgen: &mut impl Bindgen) {
570         assert_eq!(self.abi, Abi::Preview1);
571         Generator {
572             bindgen,
573             operands: vec![],
574             results: vec![],
575             stack: vec![],
576         }
577         .call_interface(module, self);
578     }
579 }
580 
581 struct Generator<'a, B: Bindgen> {
582     bindgen: &'a mut B,
583     operands: Vec<B::Operand>,
584     results: Vec<B::Operand>,
585     stack: Vec<B::Operand>,
586 }
587 
588 impl<B: Bindgen> Generator<'_, B> {
call_wasm(&mut self, module: &Id, func: &InterfaceFunc)589     fn call_wasm(&mut self, module: &Id, func: &InterfaceFunc) {
590         // Translate all parameters which are interface values by lowering them
591         // to their wasm types.
592         for (nth, param) in func.params.iter().enumerate() {
593             self.emit(&Instruction::GetArg { nth });
594             self.lower(&param.tref, None);
595         }
596 
597         // If necessary for our ABI, insert return pointers for any returned
598         // values through a result.
599         assert!(func.results.len() < 2);
600         if let Some(result) = func.results.get(0) {
601             self.prep_return_pointer(&result.tref.type_());
602         }
603 
604         let (params, results) = func.wasm_signature();
605         self.emit(&Instruction::CallWasm {
606             module: module.as_str(),
607             name: func.name.as_str(),
608             params: &params,
609             results: &results,
610         });
611 
612         // Lift the return value if one is present.
613         if let Some(result) = func.results.get(0) {
614             self.lift(&result.tref, true);
615         }
616 
617         self.emit(&Instruction::Return {
618             amt: func.results.len(),
619         });
620     }
621 
call_interface(&mut self, module: &Id, func: &InterfaceFunc)622     fn call_interface(&mut self, module: &Id, func: &InterfaceFunc) {
623         // Lift all wasm parameters into interface types first.
624         //
625         // Note that consuming arguments is somewhat janky right now by manually
626         // giving lists a second argument for their length. In the future we'll
627         // probably want to refactor the `lift` function to internally know how
628         // to consume arguments.
629         let mut nth = 0;
630         for param in func.params.iter() {
631             self.emit(&Instruction::GetArg { nth });
632             nth += 1;
633             if let Type::List(_) = &**param.tref.type_() {
634                 self.emit(&Instruction::GetArg { nth });
635                 nth += 1;
636             }
637             self.lift(&param.tref, false);
638         }
639 
640         self.emit(&Instruction::CallInterface {
641             module: module.as_str(),
642             func,
643         });
644 
645         // Like above the current ABI only has at most one result, so lower it
646         // here if necessary.
647         if let Some(result) = func.results.get(0) {
648             self.lower(&result.tref, Some(&mut nth));
649         }
650 
651         let (_params, results) = func.wasm_signature();
652         self.emit(&Instruction::Return { amt: results.len() });
653     }
654 
emit(&mut self, inst: &Instruction<'_>)655     fn emit(&mut self, inst: &Instruction<'_>) {
656         self.operands.clear();
657         self.results.clear();
658 
659         let operands_len = inst.operands_len();
660         assert!(
661             self.stack.len() >= operands_len,
662             "not enough operands on stack for {:?}",
663             inst
664         );
665         self.operands
666             .extend(self.stack.drain((self.stack.len() - operands_len)..));
667         self.results.reserve(inst.results_len());
668 
669         self.bindgen
670             .emit(inst, &mut self.operands, &mut self.results);
671 
672         assert_eq!(
673             self.results.len(),
674             inst.results_len(),
675             "{:?} expected {} results, got {}",
676             inst,
677             inst.results_len(),
678             self.results.len()
679         );
680         self.stack.extend(self.results.drain(..));
681     }
682 
lower(&mut self, ty: &TypeRef, retptr: Option<&mut usize>)683     fn lower(&mut self, ty: &TypeRef, retptr: Option<&mut usize>) {
684         use Instruction::*;
685         match &**ty.type_() {
686             Type::Builtin(BuiltinType::S8) => self.emit(&I32FromS8),
687             Type::Builtin(BuiltinType::U8 { lang_c_char: true }) => self.emit(&I32FromChar8),
688             Type::Builtin(BuiltinType::U8 { lang_c_char: false }) => self.emit(&I32FromU8),
689             Type::Builtin(BuiltinType::S16) => self.emit(&I32FromS16),
690             Type::Builtin(BuiltinType::U16) => self.emit(&I32FromU16),
691             Type::Builtin(BuiltinType::S32) => self.emit(&I32FromS32),
692             Type::Builtin(BuiltinType::U32 {
693                 lang_ptr_size: true,
694             }) => self.emit(&I32FromUsize),
695             Type::Builtin(BuiltinType::U32 {
696                 lang_ptr_size: false,
697             }) => self.emit(&I32FromU32),
698             Type::Builtin(BuiltinType::S64) => self.emit(&I64FromS64),
699             Type::Builtin(BuiltinType::U64) => self.emit(&I64FromU64),
700             Type::Builtin(BuiltinType::Char) => self.emit(&I32FromChar),
701             Type::Pointer(_) => self.emit(&I32FromPointer),
702             Type::ConstPointer(_) => self.emit(&I32FromConstPointer),
703             Type::Handle(_) => self.emit(&I32FromHandle {
704                 ty: match ty {
705                     TypeRef::Name(ty) => ty,
706                     _ => unreachable!(),
707                 },
708             }),
709             Type::Record(r) => {
710                 let ty = match ty {
711                     TypeRef::Name(ty) => ty,
712                     _ => unreachable!(),
713                 };
714                 match r.bitflags_repr() {
715                     Some(IntRepr::U64) => self.emit(&I64FromBitflags { ty }),
716                     Some(_) => self.emit(&I32FromBitflags { ty }),
717                     None => self.emit(&AddrOf),
718                 }
719             }
720             Type::Variant(v) => {
721                 // Enum-like variants are simply lowered to their discriminant.
722                 if v.is_enum() {
723                     return self.emit(&EnumLower {
724                         ty: match ty {
725                             TypeRef::Name(n) => n,
726                             _ => unreachable!(),
727                         },
728                     });
729                 }
730 
731                 // If this variant is in the return position then it's special,
732                 // otherwise it's an argument and we just pass the address.
733                 let retptr = match retptr {
734                     Some(ptr) => ptr,
735                     None => return self.emit(&AddrOf),
736                 };
737 
738                 // For the return position we emit some blocks to lower the
739                 // ok/err payloads which means that in the ok branch we're
740                 // storing to out-params and in the err branch we're simply
741                 // lowering the error enum.
742                 //
743                 // Note that this is all very specific to the current WASI ABI.
744                 let (ok, err) = v.as_expected().unwrap();
745                 self.bindgen.push_block();
746                 if let Some(ok) = ok {
747                     self.emit(&VariantPayload);
748                     let store = |me: &mut Self, ty: &TypeRef, n| {
749                         me.emit(&GetArg { nth: *retptr + n });
750                         match ty {
751                             TypeRef::Name(ty) => me.emit(&Store { ty }),
752                             _ => unreachable!(),
753                         }
754                     };
755                     match &**ok.type_() {
756                         Type::Record(r) if r.is_tuple() => {
757                             self.emit(&TupleLower {
758                                 amt: r.members.len(),
759                             });
760                             // Note that `rev()` is used here due to the order
761                             // that tuples are pushed onto the stack and how we
762                             // consume the last item first from the stack.
763                             for (i, member) in r.members.iter().enumerate().rev() {
764                                 store(self, &member.tref, i);
765                             }
766                         }
767                         _ => store(self, ok, 0),
768                     }
769                 };
770                 self.bindgen.finish_block(None);
771 
772                 self.bindgen.push_block();
773                 let err_expr = if let Some(ty) = err {
774                     self.emit(&VariantPayload);
775                     self.lower(ty, None);
776                     Some(self.stack.pop().unwrap())
777                 } else {
778                     None
779                 };
780                 self.bindgen.finish_block(err_expr);
781 
782                 self.emit(&ResultLower { ok, err });
783             }
784             Type::Builtin(BuiltinType::F32) => self.emit(&F32FromIf32),
785             Type::Builtin(BuiltinType::F64) => self.emit(&F64FromIf64),
786             Type::List(_) => self.emit(&ListPointerLength),
787         }
788     }
789 
prep_return_pointer(&mut self, ty: &Type)790     fn prep_return_pointer(&mut self, ty: &Type) {
791         // Return pointers are only needed for `Result<T, _>`...
792         let variant = match ty {
793             Type::Variant(v) => v,
794             _ => return,
795         };
796         // ... and only if `T` is actually present in `Result<T, _>`
797         let ok = match &variant.cases[0].tref {
798             Some(t) => t,
799             None => return,
800         };
801 
802         // Tuples have each individual item in a separate return pointer while
803         // all other types go through a singular return pointer.
804         let mut n = 0;
805         let mut prep = |ty: &TypeRef| {
806             match ty {
807                 TypeRef::Name(ty) => self.bindgen.allocate_space(n, ty),
808                 _ => unreachable!(),
809             }
810             self.emit(&Instruction::ReturnPointerGet { n });
811             n += 1;
812         };
813         match &**ok.type_() {
814             Type::Record(r) if r.is_tuple() => {
815                 for member in r.members.iter() {
816                     prep(&member.tref);
817                 }
818             }
819             _ => prep(ok),
820         }
821     }
822 
823     // Note that in general everything in this function is the opposite of the
824     // `lower` function above. This is intentional and should be kept this way!
lift(&mut self, ty: &TypeRef, is_return: bool)825     fn lift(&mut self, ty: &TypeRef, is_return: bool) {
826         use Instruction::*;
827         match &**ty.type_() {
828             Type::Builtin(BuiltinType::S8) => self.emit(&S8FromI32),
829             Type::Builtin(BuiltinType::U8 { lang_c_char: true }) => self.emit(&Char8FromI32),
830             Type::Builtin(BuiltinType::U8 { lang_c_char: false }) => self.emit(&U8FromI32),
831             Type::Builtin(BuiltinType::S16) => self.emit(&S16FromI32),
832             Type::Builtin(BuiltinType::U16) => self.emit(&U16FromI32),
833             Type::Builtin(BuiltinType::S32) => self.emit(&S32FromI32),
834             Type::Builtin(BuiltinType::U32 {
835                 lang_ptr_size: true,
836             }) => self.emit(&UsizeFromI32),
837             Type::Builtin(BuiltinType::U32 {
838                 lang_ptr_size: false,
839             }) => self.emit(&U32FromI32),
840             Type::Builtin(BuiltinType::S64) => self.emit(&S64FromI64),
841             Type::Builtin(BuiltinType::U64) => self.emit(&U64FromI64),
842             Type::Builtin(BuiltinType::Char) => self.emit(&CharFromI32),
843             Type::Builtin(BuiltinType::F32) => self.emit(&If32FromF32),
844             Type::Builtin(BuiltinType::F64) => self.emit(&If64FromF64),
845             Type::Pointer(ty) => self.emit(&PointerFromI32 { ty }),
846             Type::ConstPointer(ty) => self.emit(&ConstPointerFromI32 { ty }),
847             Type::Handle(_) => self.emit(&HandleFromI32 {
848                 ty: match ty {
849                     TypeRef::Name(ty) => ty,
850                     _ => unreachable!(),
851                 },
852             }),
853             Type::Variant(v) => {
854                 if v.is_enum() {
855                     return self.emit(&EnumLift {
856                         ty: match ty {
857                             TypeRef::Name(n) => n,
858                             _ => unreachable!(),
859                         },
860                     });
861                 } else if !is_return {
862                     return self.emit(&Load {
863                         ty: match ty {
864                             TypeRef::Name(n) => n,
865                             _ => unreachable!(),
866                         },
867                     });
868                 }
869 
870                 let (ok, err) = v.as_expected().unwrap();
871                 self.bindgen.push_block();
872                 let ok_expr = if let Some(ok) = ok {
873                     let mut n = 0;
874                     let mut load = |ty: &TypeRef| {
875                         self.emit(&ReturnPointerGet { n });
876                         n += 1;
877                         match ty {
878                             TypeRef::Name(ty) => self.emit(&Load { ty }),
879                             _ => unreachable!(),
880                         }
881                     };
882                     match &**ok.type_() {
883                         Type::Record(r) if r.is_tuple() => {
884                             for member in r.members.iter() {
885                                 load(&member.tref);
886                             }
887                             self.emit(&TupleLift {
888                                 amt: r.members.len(),
889                             });
890                         }
891                         _ => load(ok),
892                     }
893                     Some(self.stack.pop().unwrap())
894                 } else {
895                     None
896                 };
897                 self.bindgen.finish_block(ok_expr);
898 
899                 self.bindgen.push_block();
900                 let err_expr = if let Some(ty) = err {
901                     self.emit(&ReuseReturn);
902                     self.lift(ty, false);
903                     Some(self.stack.pop().unwrap())
904                 } else {
905                     None
906                 };
907                 self.bindgen.finish_block(err_expr);
908 
909                 self.emit(&ResultLift);
910             }
911             Type::Record(r) => {
912                 let ty = match ty {
913                     TypeRef::Name(ty) => ty,
914                     _ => unreachable!(),
915                 };
916                 match r.bitflags_repr() {
917                     Some(IntRepr::U64) => self.emit(&BitflagsFromI64 { ty }),
918                     Some(_) => self.emit(&BitflagsFromI32 { ty }),
919                     None => self.emit(&Load { ty }),
920                 }
921             }
922             Type::List(ty) => self.emit(&ListFromPointerLength { ty }),
923         }
924     }
925 }
926