Skip to main content

wit_bindgen_core/
abi.rs

1use std::fmt;
2use std::iter;
3
4use wit_parser::Param;
5pub use wit_parser::abi::{AbiVariant, FlatTypes, WasmSignature, WasmType};
6use wit_parser::{
7    Alignment, ArchitectureSize, ElementInfo, Enum, Flags, FlagsRepr, Function, Handle, Int,
8    Record, Resolve, Result_, SizeAlign, Tuple, Type, TypeDefKind, TypeId, Variant, align_to_arch,
9};
10
11// Helper macro for defining instructions without having to have tons of
12// exhaustive `match` statements to update
13macro_rules! def_instruction {
14    (
15        $( #[$enum_attr:meta] )*
16        pub enum $name:ident<'a> {
17            $(
18                $( #[$attr:meta] )*
19                $variant:ident $( {
20                    $($field:ident : $field_ty:ty $(,)* )*
21                } )?
22                    :
23                [$num_popped:expr] => [$num_pushed:expr],
24            )*
25        }
26    ) => {
27        $( #[$enum_attr] )*
28        pub enum $name<'a> {
29            $(
30                $( #[$attr] )*
31                $variant $( {
32                    $(
33                        $field : $field_ty,
34                    )*
35                } )? ,
36            )*
37        }
38
39        impl $name<'_> {
40            /// How many operands does this instruction pop from the stack?
41            #[allow(unused_variables, reason = "match arms bind fields for exhaustiveness, not usage")]
42            pub fn operands_len(&self) -> usize {
43                match self {
44                    $(
45                        Self::$variant $( {
46                            $(
47                                $field,
48                            )*
49                        } )? => $num_popped,
50                    )*
51                }
52            }
53
54            /// How many results does this instruction push onto the stack?
55            #[allow(unused_variables, reason = "match arms bind fields for exhaustiveness, not usage")]
56            pub fn results_len(&self) -> usize {
57                match self {
58                    $(
59                        Self::$variant $( {
60                            $(
61                                $field,
62                            )*
63                        } )? => $num_pushed,
64                    )*
65                }
66            }
67        }
68    };
69}
70
71def_instruction! {
72    #[derive(Debug)]
73    pub enum Instruction<'a> {
74        /// Acquires the specified parameter and places it on the stack.
75        /// Depending on the context this may refer to wasm parameters or
76        /// interface types parameters.
77        GetArg { nth: usize } : [0] => [1],
78
79        // Integer const/manipulation instructions
80
81        /// Pushes the constant `val` onto the stack.
82        I32Const { val: i32 } : [0] => [1],
83        /// Casts the top N items on the stack using the `Bitcast` enum
84        /// provided. Consumes the same number of operands that this produces.
85        Bitcasts { casts: &'a [Bitcast] } : [casts.len()] => [casts.len()],
86        /// Pushes a number of constant zeros for each wasm type on the stack.
87        ConstZero { tys: &'a [WasmType] } : [0] => [tys.len()],
88
89        // Memory load/store instructions
90
91        /// Pops a pointer from the stack and loads a little-endian `i32` from
92        /// it, using the specified constant offset.
93        I32Load { offset: ArchitectureSize } : [1] => [1],
94        /// Pops a pointer from the stack and loads a little-endian `i8` from
95        /// it, using the specified constant offset. The value loaded is the
96        /// zero-extended to 32-bits
97        I32Load8U { offset: ArchitectureSize } : [1] => [1],
98        /// Pops a pointer from the stack and loads a little-endian `i8` from
99        /// it, using the specified constant offset. The value loaded is the
100        /// sign-extended to 32-bits
101        I32Load8S { offset: ArchitectureSize } : [1] => [1],
102        /// Pops a pointer from the stack and loads a little-endian `i16` from
103        /// it, using the specified constant offset. The value loaded is the
104        /// zero-extended to 32-bits
105        I32Load16U { offset: ArchitectureSize } : [1] => [1],
106        /// Pops a pointer from the stack and loads a little-endian `i16` from
107        /// it, using the specified constant offset. The value loaded is the
108        /// sign-extended to 32-bits
109        I32Load16S { offset: ArchitectureSize } : [1] => [1],
110        /// Pops a pointer from the stack and loads a little-endian `i64` from
111        /// it, using the specified constant offset.
112        I64Load { offset: ArchitectureSize } : [1] => [1],
113        /// Pops a pointer from the stack and loads a little-endian `f32` from
114        /// it, using the specified constant offset.
115        F32Load { offset: ArchitectureSize } : [1] => [1],
116        /// Pops a pointer from the stack and loads a little-endian `f64` from
117        /// it, using the specified constant offset.
118        F64Load { offset: ArchitectureSize } : [1] => [1],
119
120        /// Like `I32Load` or `I64Load`, but for loading pointer values.
121        PointerLoad { offset: ArchitectureSize } : [1] => [1],
122        /// Like `I32Load` or `I64Load`, but for loading array length values.
123        LengthLoad { offset: ArchitectureSize } : [1] => [1],
124
125        /// Pops a pointer from the stack and then an `i32` value.
126        /// Stores the value in little-endian at the pointer specified plus the
127        /// constant `offset`.
128        I32Store { offset: ArchitectureSize } : [2] => [0],
129        /// Pops a pointer from the stack and then an `i32` value.
130        /// Stores the low 8 bits of the value in little-endian at the pointer
131        /// specified plus the constant `offset`.
132        I32Store8 { offset: ArchitectureSize } : [2] => [0],
133        /// Pops a pointer from the stack and then an `i32` value.
134        /// Stores the low 16 bits of the value in little-endian at the pointer
135        /// specified plus the constant `offset`.
136        I32Store16 { offset: ArchitectureSize } : [2] => [0],
137        /// Pops a pointer from the stack and then an `i64` value.
138        /// Stores the value in little-endian at the pointer specified plus the
139        /// constant `offset`.
140        I64Store { offset: ArchitectureSize } : [2] => [0],
141        /// Pops a pointer from the stack and then an `f32` value.
142        /// Stores the value in little-endian at the pointer specified plus the
143        /// constant `offset`.
144        F32Store { offset: ArchitectureSize } : [2] => [0],
145        /// Pops a pointer from the stack and then an `f64` value.
146        /// Stores the value in little-endian at the pointer specified plus the
147        /// constant `offset`.
148        F64Store { offset: ArchitectureSize } : [2] => [0],
149
150        /// Like `I32Store` or `I64Store`, but for storing pointer values.
151        PointerStore { offset: ArchitectureSize } : [2] => [0],
152        /// Like `I32Store` or `I64Store`, but for storing array length values.
153        LengthStore { offset: ArchitectureSize } : [2] => [0],
154
155        // Scalar lifting/lowering
156
157        /// Converts an interface type `char` value to a 32-bit integer
158        /// representing the unicode scalar value.
159        I32FromChar : [1] => [1],
160        /// Converts an interface type `u64` value to a wasm `i64`.
161        I64FromU64 : [1] => [1],
162        /// Converts an interface type `s64` value to a wasm `i64`.
163        I64FromS64 : [1] => [1],
164        /// Converts an interface type `u32` value to a wasm `i32`.
165        I32FromU32 : [1] => [1],
166        /// Converts an interface type `s32` value to a wasm `i32`.
167        I32FromS32 : [1] => [1],
168        /// Converts an interface type `u16` value to a wasm `i32`.
169        I32FromU16 : [1] => [1],
170        /// Converts an interface type `s16` value to a wasm `i32`.
171        I32FromS16 : [1] => [1],
172        /// Converts an interface type `u8` value to a wasm `i32`.
173        I32FromU8 : [1] => [1],
174        /// Converts an interface type `s8` value to a wasm `i32`.
175        I32FromS8 : [1] => [1],
176        /// Conversion an interface type `f32` value to a wasm `f32`.
177        ///
178        /// This may be a noop for some implementations, but it's here in case the
179        /// native language representation of `f32` is different than the wasm
180        /// representation of `f32`.
181        CoreF32FromF32 : [1] => [1],
182        /// Conversion an interface type `f64` value to a wasm `f64`.
183        ///
184        /// This may be a noop for some implementations, but it's here in case the
185        /// native language representation of `f64` is different than the wasm
186        /// representation of `f64`.
187        CoreF64FromF64 : [1] => [1],
188
189        /// Converts a native wasm `i32` to an interface type `s8`.
190        ///
191        /// This will truncate the upper bits of the `i32`.
192        S8FromI32 : [1] => [1],
193        /// Converts a native wasm `i32` to an interface type `u8`.
194        ///
195        /// This will truncate the upper bits of the `i32`.
196        U8FromI32 : [1] => [1],
197        /// Converts a native wasm `i32` to an interface type `s16`.
198        ///
199        /// This will truncate the upper bits of the `i32`.
200        S16FromI32 : [1] => [1],
201        /// Converts a native wasm `i32` to an interface type `u16`.
202        ///
203        /// This will truncate the upper bits of the `i32`.
204        U16FromI32 : [1] => [1],
205        /// Converts a native wasm `i32` to an interface type `s32`.
206        S32FromI32 : [1] => [1],
207        /// Converts a native wasm `i32` to an interface type `u32`.
208        U32FromI32 : [1] => [1],
209        /// Converts a native wasm `i64` to an interface type `s64`.
210        S64FromI64 : [1] => [1],
211        /// Converts a native wasm `i64` to an interface type `u64`.
212        U64FromI64 : [1] => [1],
213        /// Converts a native wasm `i32` to an interface type `char`.
214        ///
215        /// It's safe to assume that the `i32` is indeed a valid unicode code point.
216        CharFromI32 : [1] => [1],
217        /// Converts a native wasm `f32` to an interface type `f32`.
218        F32FromCoreF32 : [1] => [1],
219        /// Converts a native wasm `f64` to an interface type `f64`.
220        F64FromCoreF64 : [1] => [1],
221
222        /// Creates a `bool` from an `i32` input, trapping if the `i32` isn't
223        /// zero or one.
224        BoolFromI32 : [1] => [1],
225        /// Creates an `i32` from a `bool` input, must return 0 or 1.
226        I32FromBool : [1] => [1],
227
228        // lists
229
230        /// Lowers a list where the element's layout in the native language is
231        /// expected to match the canonical ABI definition of interface types.
232        ///
233        /// Pops a list value from the stack and pushes the pointer/length onto
234        /// the stack. If `realloc` is set to `Some` then this is expected to
235        /// *consume* the list which means that the data needs to be copied. An
236        /// allocation/copy is expected when:
237        ///
238        /// * A host is calling a wasm export with a list (it needs to copy the
239        ///   list in to the callee's module, allocating space with `realloc`)
240        /// * A wasm export is returning a list (it's expected to use `realloc`
241        ///   to give ownership of the list to the caller.
242        /// * A host is returning a list in a import definition, meaning that
243        ///   space needs to be allocated in the caller with `realloc`).
244        ///
245        /// A copy does not happen (e.g. `realloc` is `None`) when:
246        ///
247        /// * A wasm module calls an import with the list. In this situation
248        ///   it's expected the caller will know how to access this module's
249        ///   memory (e.g. the host has raw access or wasm-to-wasm communication
250        ///   would copy the list).
251        ///
252        /// If `realloc` is `Some` then the adapter is not responsible for
253        /// cleaning up this list because the other end is receiving the
254        /// allocation. If `realloc` is `None` then the adapter is responsible
255        /// for cleaning up any temporary allocation it created, if any.
256        ListCanonLower {
257            element: &'a Type,
258            realloc: Option<&'a str>,
259        } : [1] => [2],
260
261        /// Same as `ListCanonLower`, but used for strings
262        StringLower {
263            realloc: Option<&'a str>,
264        } : [1] => [2],
265
266        /// Lowers a list where the element's layout in the native language is
267        /// not expected to match the canonical ABI definition of interface
268        /// types.
269        ///
270        /// Pops a list value from the stack and pushes the pointer/length onto
271        /// the stack. This operation also pops a block from the block stack
272        /// which is used as the iteration body of writing each element of the
273        /// list consumed.
274        ///
275        /// The `realloc` field here behaves the same way as `ListCanonLower`.
276        /// It's only set to `None` when a wasm module calls a declared import.
277        /// Otherwise lowering in other contexts requires allocating memory for
278        /// the receiver to own.
279        ListLower {
280            element: &'a Type,
281            realloc: Option<&'a str>,
282        } : [1] => [2],
283
284        /// Lifts a list which has a canonical representation into an interface
285        /// types value.
286        ///
287        /// The term "canonical" representation here means that the
288        /// representation of the interface types value in the native language
289        /// exactly matches the canonical ABI definition of the type.
290        ///
291        /// This will consume two `i32` values from the stack, a pointer and a
292        /// length, and then produces an interface value list.
293        ListCanonLift {
294            element: &'a Type,
295            ty: TypeId,
296        } : [2] => [1],
297
298        /// Same as `ListCanonLift`, but used for strings
299        StringLift : [2] => [1],
300
301        /// Lifts a list which into an interface types value.
302        ///
303        /// This will consume two `i32` values from the stack, a pointer and a
304        /// length, and then produces an interface value list.
305        ///
306        /// This will also pop a block from the block stack which is how to
307        /// read each individual element from the list.
308        ListLift {
309            element: &'a Type,
310            ty: TypeId,
311        } : [2] => [1],
312
313        /// Lowers a map into a canonical pointer/length pair.
314        ///
315        /// This operation pops a map value from the stack and pushes pointer
316        /// and length. A block is popped from the block stack to lower one
317        /// key/value entry into linear memory.
318        MapLower {
319            key: &'a Type,
320            value: &'a Type,
321            realloc: Option<&'a str>,
322        } : [1] => [2],
323
324        /// Lifts a canonical pointer/length pair into a map.
325        ///
326        /// This operation consumes pointer and length from the stack. A block
327        /// is popped from the block stack and must produce key/value for one
328        /// map entry.
329        MapLift {
330            key: &'a Type,
331            value: &'a Type,
332            ty: TypeId,
333        } : [2] => [1],
334
335        /// Pops all fields for a fixed list off the stack and then composes them
336        /// into an array.
337        FixedLengthListLift {
338            element: &'a Type,
339            size: u32,
340            id: TypeId,
341        } : [*size as usize] => [1],
342
343        /// Pops an array off the stack, decomposes the elements and then pushes them onto the stack.
344        FixedLengthListLower {
345            element: &'a Type,
346            size: u32,
347            id: TypeId,
348        } : [1] => [*size as usize],
349
350        /// Pops an array and an address off the stack, passes each element to a block storing it
351        FixedLengthListLowerToMemory {
352            element: &'a Type,
353            size: u32,
354            id: TypeId,
355        } : [2] => [0],
356
357        /// Pops base address, pushes an array
358        ///
359        /// This will also pop a block from the block stack which is how to
360        /// read each individual element from the list.
361        FixedLengthListLiftFromMemory {
362            element: &'a Type,
363            size: u32,
364            id: TypeId,
365        } : [1] => [1],
366
367
368        /// Pushes an operand onto the stack representing the list item from
369        /// each iteration of the list.
370        ///
371        /// This is only used inside of blocks related to lowering lists.
372        IterElem { element: &'a Type } : [0] => [1],
373
374        /// Pushes an operand onto the stack representing the current map key
375        /// for each map iteration.
376        IterMapKey { key: &'a Type } : [0] => [1],
377
378        /// Pushes an operand onto the stack representing the current map value
379        /// for each map iteration.
380        IterMapValue { value: &'a Type } : [0] => [1],
381
382        /// Pushes an operand onto the stack representing the base pointer of
383        /// the next element in a list.
384        ///
385        /// This is used for both lifting and lowering lists.
386        IterBasePointer : [0] => [1],
387
388        // records and tuples
389
390        /// Pops a record value off the stack, decomposes the record to all of
391        /// its fields, and then pushes the fields onto the stack.
392        RecordLower {
393            record: &'a Record,
394            name: &'a str,
395            ty: TypeId,
396        } : [1] => [record.fields.len()],
397
398        /// Pops all fields for a record off the stack and then composes them
399        /// into a record.
400        RecordLift {
401            record: &'a Record,
402            name: &'a str,
403            ty: TypeId,
404        } : [record.fields.len()] => [1],
405
406        /// Create an `i32` from a handle.
407        HandleLower {
408            handle: &'a Handle,
409            name: &'a str,
410            ty: TypeId,
411        } : [1] => [1],
412
413        /// Create a handle from an `i32`.
414        HandleLift {
415            handle: &'a Handle,
416            name: &'a str,
417            ty: TypeId,
418        } : [1] => [1],
419
420        /// Create an `i32` from a future.
421        FutureLower {
422            payload: &'a Option<Type>,
423            ty: TypeId,
424        } : [1] => [1],
425
426        /// Create a future from an `i32`.
427        FutureLift {
428            payload: &'a Option<Type>,
429            ty: TypeId,
430        } : [1] => [1],
431
432        /// Create an `i32` from a stream.
433        StreamLower {
434            payload: &'a Option<Type>,
435            ty: TypeId,
436        } : [1] => [1],
437
438        /// Create a stream from an `i32`.
439        StreamLift {
440            payload: &'a Option<Type>,
441            ty: TypeId,
442        } : [1] => [1],
443
444        /// Create an `i32` from an error-context.
445        ErrorContextLower : [1] => [1],
446
447        /// Create a error-context from an `i32`.
448        ErrorContextLift : [1] => [1],
449
450        /// Pops a tuple value off the stack, decomposes the tuple to all of
451        /// its fields, and then pushes the fields onto the stack.
452        TupleLower {
453            tuple: &'a Tuple,
454            ty: TypeId,
455        } : [1] => [tuple.types.len()],
456
457        /// Pops all fields for a tuple off the stack and then composes them
458        /// into a tuple.
459        TupleLift {
460            tuple: &'a Tuple,
461            ty: TypeId,
462        } : [tuple.types.len()] => [1],
463
464        /// Converts a language-specific record-of-bools to a list of `i32`.
465        FlagsLower {
466            flags: &'a Flags,
467            name: &'a str,
468            ty: TypeId,
469        } : [1] => [flags.repr().count()],
470        /// Converts a list of native wasm `i32` to a language-specific
471        /// record-of-bools.
472        FlagsLift {
473            flags: &'a Flags,
474            name: &'a str,
475            ty: TypeId,
476        } : [flags.repr().count()] => [1],
477
478        // variants
479
480        /// This is a special instruction used for `VariantLower`
481        /// instruction to determine the name of the payload, if present, to use
482        /// within each block.
483        ///
484        /// Each sub-block will have this be the first instruction, and if it
485        /// lowers a payload it will expect something bound to this name.
486        VariantPayloadName : [0] => [1],
487
488        /// Pops a variant off the stack as well as `ty.cases.len()` blocks
489        /// from the code generator. Uses each of those blocks and the value
490        /// from the stack to produce `nresults` of items.
491        VariantLower {
492            variant: &'a Variant,
493            name: &'a str,
494            ty: TypeId,
495            results: &'a [WasmType],
496        } : [1] => [results.len()],
497
498        /// Pops an `i32` off the stack as well as `ty.cases.len()` blocks
499        /// from the code generator. Uses each of those blocks and the value
500        /// from the stack to produce a final variant.
501        VariantLift {
502            variant: &'a Variant,
503            name: &'a str,
504            ty: TypeId,
505        } : [1] => [1],
506
507        /// Pops an enum off the stack and pushes the `i32` representation.
508        EnumLower {
509            enum_: &'a Enum,
510            name: &'a str,
511            ty: TypeId,
512        } : [1] => [1],
513
514        /// Pops an `i32` off the stack and lifts it into the `enum` specified.
515        EnumLift {
516            enum_: &'a Enum,
517            name: &'a str,
518            ty: TypeId,
519        } : [1] => [1],
520
521        /// Specialization of `VariantLower` for specifically `option<T>` types,
522        /// otherwise behaves the same as `VariantLower` (e.g. two blocks for
523        /// the two cases.
524        OptionLower {
525            payload: &'a Type,
526            ty: TypeId,
527            results: &'a [WasmType],
528        } : [1] => [results.len()],
529
530        /// Specialization of `VariantLift` for specifically the `option<T>`
531        /// type. Otherwise behaves the same as the `VariantLift` instruction
532        /// with two blocks for the lift.
533        OptionLift {
534            payload: &'a Type,
535            ty: TypeId,
536        } : [1] => [1],
537
538        /// Specialization of `VariantLower` for specifically `result<T, E>`
539        /// types, otherwise behaves the same as `VariantLower` (e.g. two blocks
540        /// for the two cases.
541        ResultLower {
542            result: &'a Result_
543            ty: TypeId,
544            results: &'a [WasmType],
545        } : [1] => [results.len()],
546
547        /// Specialization of `VariantLift` for specifically the `result<T,
548        /// E>` type. Otherwise behaves the same as the `VariantLift`
549        /// instruction with two blocks for the lift.
550        ResultLift {
551            result: &'a Result_,
552            ty: TypeId,
553        } : [1] => [1],
554
555        // calling/control flow
556
557        /// Represents a call to a raw WebAssembly API. The module/name are
558        /// provided inline as well as the types if necessary.
559        CallWasm {
560            name: &'a str,
561            sig: &'a WasmSignature,
562        } : [sig.params.len()] => [sig.results.len()],
563
564        /// Same as `CallWasm`, except the dual where an interface is being
565        /// called rather than a raw wasm function.
566        ///
567        /// Note that this will be used for async functions, and `async_`
568        /// indicates whether the function should be invoked in an async
569        /// fashion.
570        CallInterface {
571            func: &'a Function,
572            async_: bool,
573        } : [func.params.len()] => [usize::from(func.result.is_some())],
574
575        /// Returns `amt` values on the stack. This is always the last
576        /// instruction.
577        Return { amt: usize, func: &'a Function } : [*amt] => [0],
578
579        /// Calls the `realloc` function specified in a malloc-like fashion
580        /// allocating `size` bytes with alignment `align`.
581        ///
582        /// Pushes the returned pointer onto the stack.
583        Malloc {
584            realloc: &'static str,
585            size: ArchitectureSize,
586            align: Alignment,
587        } : [0] => [1],
588
589        /// Used exclusively for guest-code generation this indicates that
590        /// the standard memory deallocation function needs to be invoked with
591        /// the specified parameters.
592        ///
593        /// This will pop a pointer from the stack and push nothing.
594        GuestDeallocate {
595            size: ArchitectureSize,
596            align: Alignment,
597        } : [1] => [0],
598
599        /// Used exclusively for guest-code generation this indicates that
600        /// a string is being deallocated. The ptr/length are on the stack and
601        /// are poppped off and used to deallocate the string.
602        GuestDeallocateString : [2] => [0],
603
604        /// Used exclusively for guest-code generation this indicates that
605        /// a list is being deallocated. The ptr/length are on the stack and
606        /// are poppped off and used to deallocate the list.
607        ///
608        /// This variant also pops a block off the block stack to be used as the
609        /// body of the deallocation loop.
610        GuestDeallocateList {
611            element: &'a Type,
612        } : [2] => [0],
613
614        /// Used exclusively for guest-code generation this indicates that a
615        /// map is being deallocated. The ptr/length are on the stack and are
616        /// popped off and used to deallocate the map entry buffer.
617        ///
618        /// This variant also pops a block off the block stack to be used as
619        /// the body of the deallocation loop over map entries.
620        GuestDeallocateMap {
621            key: &'a Type,
622            value: &'a Type,
623        } : [2] => [0],
624
625        /// Used exclusively for guest-code generation this indicates that
626        /// a variant is being deallocated. The integer discriminant is popped
627        /// off the stack as well as `blocks` number of blocks popped from the
628        /// blocks stack. The variant is used to select, at runtime, which of
629        /// the blocks is executed to deallocate the variant.
630        GuestDeallocateVariant {
631            blocks: usize,
632        } : [1] => [0],
633
634        /// Deallocates the language-specific handle representation on the top
635        /// of the stack. Used for async imports.
636        DropHandle { ty: &'a Type } : [1] => [0],
637
638        /// Call `task.return` for an async-lifted export.
639        ///
640        /// This will call core wasm import `name` which will be mapped to
641        /// `task.return` later on. The function given has `params` as its
642        /// parameters and it will return no results. This is used to pass the
643        /// lowered representation of a function's results to `task.return`.
644        AsyncTaskReturn { name: &'a str, params: &'a [WasmType] } : [params.len()] => [0],
645
646        /// Force the evaluation of the specified number of expressions and push
647        /// the results to the stack.
648        ///
649        /// This is useful prior to disposing of temporary variables and/or
650        /// allocations which are referenced by one or more not-yet-evaluated
651        /// expressions.
652        Flush { amt: usize } : [*amt] => [*amt],
653    }
654}
655
656#[derive(Debug, PartialEq)]
657pub enum Bitcast {
658    // Upcasts
659    F32ToI32,
660    F64ToI64,
661    I32ToI64,
662    F32ToI64,
663
664    // Downcasts
665    I32ToF32,
666    I64ToF64,
667    I64ToI32,
668    I64ToF32,
669
670    // PointerOrI64 conversions. These preserve provenance when the source
671    // or destination is a pointer value.
672    //
673    // These are used when pointer values are being stored in
674    // (ToP64) and loaded out of (P64To) PointerOrI64 values, so they
675    // always have to preserve provenance when the value being loaded or
676    // stored is a pointer.
677    P64ToI64,
678    I64ToP64,
679    P64ToP,
680    PToP64,
681
682    // Pointer<->number conversions. These do not preserve provenance.
683    //
684    // These are used when integer or floating-point values are being stored in
685    // (I32ToP/etc.) and loaded out of (PToI32/etc.) pointer values, so they
686    // never have any provenance to preserve.
687    I32ToP,
688    PToI32,
689    PToL,
690    LToP,
691
692    // Number<->Number conversions.
693    I32ToL,
694    LToI32,
695    I64ToL,
696    LToI64,
697
698    // Multiple conversions in sequence.
699    Sequence(Box<[Bitcast; 2]>),
700
701    None,
702}
703
704/// Whether the glue code surrounding a call is lifting arguments and lowering
705/// results or vice versa.
706#[derive(Clone, Copy, PartialEq, Eq)]
707pub enum LiftLower {
708    /// When the glue code lifts arguments and lowers results.
709    ///
710    /// ```text
711    /// Wasm --lift-args--> SourceLanguage; call; SourceLanguage --lower-results--> Wasm
712    /// ```
713    LiftArgsLowerResults,
714    /// When the glue code lowers arguments and lifts results.
715    ///
716    /// ```text
717    /// SourceLanguage --lower-args--> Wasm; call; Wasm --lift-results--> SourceLanguage
718    /// ```
719    LowerArgsLiftResults,
720}
721
722/// Trait for language implementors to use to generate glue code between native
723/// WebAssembly signatures and interface types signatures.
724///
725/// This is used as an implementation detail in interpreting the ABI between
726/// interface types and wasm types. Eventually this will be driven by interface
727/// types adapters themselves, but for now the ABI of a function dictates what
728/// instructions are fed in.
729///
730/// Types implementing `Bindgen` are incrementally fed `Instruction` values to
731/// generate code for. Instructions operate like a stack machine where each
732/// instruction has a list of inputs and a list of outputs (provided by the
733/// `emit` function).
734pub trait Bindgen {
735    /// The intermediate type for fragments of code for this type.
736    ///
737    /// For most languages `String` is a suitable intermediate type.
738    type Operand: Clone + fmt::Debug;
739
740    /// Emit code to implement the given instruction.
741    ///
742    /// Each operand is given in `operands` and can be popped off if ownership
743    /// is required. It's guaranteed that `operands` has the appropriate length
744    /// for the `inst` given, as specified with [`Instruction`].
745    ///
746    /// Each result variable should be pushed onto `results`. This function must
747    /// push the appropriate number of results or binding generation will panic.
748    fn emit(
749        &mut self,
750        resolve: &Resolve,
751        inst: &Instruction<'_>,
752        operands: &mut Vec<Self::Operand>,
753        results: &mut Vec<Self::Operand>,
754    );
755
756    /// Gets a operand reference to the return pointer area.
757    ///
758    /// The provided size and alignment is for the function's return type.
759    fn return_pointer(&mut self, size: ArchitectureSize, align: Alignment) -> Self::Operand;
760
761    /// Enters a new block of code to generate code for.
762    ///
763    /// This is currently exclusively used for constructing variants. When a
764    /// variant is constructed a block here will be pushed for each case of a
765    /// variant, generating the code necessary to translate a variant case.
766    ///
767    /// Blocks are completed with `finish_block` below. It's expected that `emit`
768    /// will always push code (if necessary) into the "current block", which is
769    /// updated by calling this method and `finish_block` below.
770    fn push_block(&mut self);
771
772    /// Indicates to the code generator that a block is completed, and the
773    /// `operand` specified was the resulting value of the block.
774    ///
775    /// This method will be used to compute the value of each arm of lifting a
776    /// variant. The `operand` will be `None` if the variant case didn't
777    /// actually have any type associated with it. Otherwise it will be `Some`
778    /// as the last value remaining on the stack representing the value
779    /// associated with a variant's `case`.
780    ///
781    /// It's expected that this will resume code generation in the previous
782    /// block before `push_block` was called. This must also save the results
783    /// of the current block internally for instructions like `ResultLift` to
784    /// use later.
785    fn finish_block(&mut self, operand: &mut Vec<Self::Operand>);
786
787    /// Returns size information that was previously calculated for all types.
788    fn sizes(&self) -> &SizeAlign;
789
790    /// Returns whether or not the specified element type is represented in a
791    /// "canonical" form for lists. This dictates whether the `ListCanonLower`
792    /// and `ListCanonLift` instructions are used or not.
793    fn is_list_canonical(&self, resolve: &Resolve, element: &Type) -> bool;
794}
795
796/// Generates an abstract sequence of instructions which represents this
797/// function being adapted as an imported function.
798///
799/// The instructions here, when executed, will emulate a language with
800/// interface types calling the concrete wasm implementation. The parameters
801/// for the returned instruction sequence are the language's own
802/// interface-types parameters. One instruction in the instruction stream
803/// will be a `Call` which represents calling the actual raw wasm function
804/// signature.
805///
806/// This function is useful, for example, if you're building a language
807/// generator for WASI bindings. This will document how to translate
808/// language-specific values into the wasm types to call a WASI function,
809/// and it will also automatically convert the results of the WASI function
810/// back to a language-specific value.
811pub fn call(
812    resolve: &Resolve,
813    variant: AbiVariant,
814    lift_lower: LiftLower,
815    func: &Function,
816    bindgen: &mut impl Bindgen,
817    async_: bool,
818) {
819    Generator::new(resolve, bindgen).call(func, variant, lift_lower, async_);
820}
821
822pub fn lower_to_memory<B: Bindgen>(
823    resolve: &Resolve,
824    bindgen: &mut B,
825    address: B::Operand,
826    value: B::Operand,
827    ty: &Type,
828) {
829    let mut generator = Generator::new(resolve, bindgen);
830    // TODO: make this configurable? Right now this function is only called for
831    // future/stream callbacks so it's appropriate to skip realloc here as it's
832    // all "lower for wasm import", but this might get reused for something else
833    // in the future.
834    generator.realloc = Some(Realloc::Export("cabi_realloc"));
835    generator.stack.push(value);
836    generator.write_to_memory(ty, address, Default::default());
837}
838
839pub fn lower_flat<B: Bindgen>(
840    resolve: &Resolve,
841    bindgen: &mut B,
842    value: B::Operand,
843    ty: &Type,
844) -> Vec<B::Operand> {
845    let mut generator = Generator::new(resolve, bindgen);
846    generator.stack.push(value);
847    generator.realloc = Some(Realloc::Export("cabi_realloc"));
848    generator.lower(ty);
849    generator.stack
850}
851
852pub fn lift_from_memory<B: Bindgen>(
853    resolve: &Resolve,
854    bindgen: &mut B,
855    address: B::Operand,
856    ty: &Type,
857) -> B::Operand {
858    let mut generator = Generator::new(resolve, bindgen);
859    generator.read_from_memory(ty, address, Default::default());
860    generator.stack.pop().unwrap()
861}
862
863/// Used in a similar manner as the `Interface::call` function except is
864/// used to generate the `post-return` callback for `func`.
865///
866/// This is only intended to be used in guest generators for exported
867/// functions and will primarily generate `GuestDeallocate*` instructions,
868/// plus others used as input to those instructions.
869pub fn post_return(resolve: &Resolve, func: &Function, bindgen: &mut impl Bindgen) {
870    Generator::new(resolve, bindgen).post_return(func);
871}
872
873/// Returns whether the `Function` specified needs a post-return function to
874/// be generated in guest code.
875///
876/// This is used when the return value contains a memory allocation such as
877/// a list or a string primarily.
878pub fn guest_export_needs_post_return(resolve: &Resolve, func: &Function) -> bool {
879    func.result
880        .map(|t| needs_deallocate(resolve, &t, Deallocate::Lists))
881        .unwrap_or(false)
882}
883
884pub fn guest_export_params_have_allocations(resolve: &Resolve, func: &Function) -> bool {
885    func.params
886        .iter()
887        .any(|param| needs_deallocate(resolve, &param.ty, Deallocate::Lists))
888}
889
890fn needs_deallocate(resolve: &Resolve, ty: &Type, what: Deallocate) -> bool {
891    match ty {
892        Type::String => true,
893        Type::ErrorContext => true,
894        Type::Id(id) => match &resolve.types[*id].kind {
895            TypeDefKind::List(_) => true,
896            TypeDefKind::Type(t) => needs_deallocate(resolve, t, what),
897            TypeDefKind::Handle(Handle::Own(_)) => what.handles(),
898            TypeDefKind::Handle(Handle::Borrow(_)) => false,
899            TypeDefKind::Resource => false,
900            TypeDefKind::Record(r) => r
901                .fields
902                .iter()
903                .any(|f| needs_deallocate(resolve, &f.ty, what)),
904            TypeDefKind::Tuple(t) => t.types.iter().any(|t| needs_deallocate(resolve, t, what)),
905            TypeDefKind::Variant(t) => t
906                .cases
907                .iter()
908                .filter_map(|t| t.ty.as_ref())
909                .any(|t| needs_deallocate(resolve, t, what)),
910            TypeDefKind::Option(t) => needs_deallocate(resolve, t, what),
911            TypeDefKind::Result(t) => [&t.ok, &t.err]
912                .iter()
913                .filter_map(|t| t.as_ref())
914                .any(|t| needs_deallocate(resolve, t, what)),
915            TypeDefKind::Flags(_) | TypeDefKind::Enum(_) => false,
916            TypeDefKind::Future(_) | TypeDefKind::Stream(_) => what.handles(),
917            TypeDefKind::Unknown => unreachable!(),
918            TypeDefKind::FixedLengthList(t, _) => needs_deallocate(resolve, t, what),
919            TypeDefKind::Map(_, _) => true,
920        },
921
922        Type::Bool
923        | Type::U8
924        | Type::S8
925        | Type::U16
926        | Type::S16
927        | Type::U32
928        | Type::S32
929        | Type::U64
930        | Type::S64
931        | Type::F32
932        | Type::F64
933        | Type::Char => false,
934    }
935}
936
937/// Generate instructions in `bindgen` to deallocate all lists in `ptr` where
938/// that's a pointer to a sequence of `types` stored in linear memory.
939pub fn deallocate_lists_in_types<B: Bindgen>(
940    resolve: &Resolve,
941    types: &[Type],
942    operands: &[B::Operand],
943    indirect: bool,
944    bindgen: &mut B,
945) {
946    Generator::new(resolve, bindgen).deallocate_in_types(
947        types,
948        operands,
949        indirect,
950        Deallocate::Lists,
951    );
952}
953
954/// Generate instructions in `bindgen` to deallocate all lists in `ptr` where
955/// that's a pointer to a sequence of `types` stored in linear memory.
956pub fn deallocate_lists_and_own_in_types<B: Bindgen>(
957    resolve: &Resolve,
958    types: &[Type],
959    operands: &[B::Operand],
960    indirect: bool,
961    bindgen: &mut B,
962) {
963    Generator::new(resolve, bindgen).deallocate_in_types(
964        types,
965        operands,
966        indirect,
967        Deallocate::ListsAndOwn,
968    );
969}
970
971#[derive(Copy, Clone)]
972pub enum Realloc {
973    None,
974    Export(&'static str),
975}
976
977/// What to deallocate in various `deallocate_*` methods.
978#[derive(Copy, Clone)]
979enum Deallocate {
980    /// Only deallocate lists.
981    Lists,
982    /// Deallocate lists and owned resources such as `own<T>` and
983    /// futures/streams.
984    ListsAndOwn,
985}
986
987impl Deallocate {
988    fn handles(&self) -> bool {
989        match self {
990            Deallocate::Lists => false,
991            Deallocate::ListsAndOwn => true,
992        }
993    }
994}
995
996struct Generator<'a, B: Bindgen> {
997    bindgen: &'a mut B,
998    resolve: &'a Resolve,
999    operands: Vec<B::Operand>,
1000    results: Vec<B::Operand>,
1001    stack: Vec<B::Operand>,
1002    return_pointer: Option<B::Operand>,
1003    realloc: Option<Realloc>,
1004}
1005
1006const MAX_FLAT_PARAMS: usize = 16;
1007const MAX_FLAT_ASYNC_PARAMS: usize = 4;
1008
1009impl<'a, B: Bindgen> Generator<'a, B> {
1010    fn new(resolve: &'a Resolve, bindgen: &'a mut B) -> Generator<'a, B> {
1011        Generator {
1012            resolve,
1013            bindgen,
1014            operands: Vec::new(),
1015            results: Vec::new(),
1016            stack: Vec::new(),
1017            return_pointer: None,
1018            realloc: None,
1019        }
1020    }
1021
1022    fn call(&mut self, func: &Function, variant: AbiVariant, lift_lower: LiftLower, async_: bool) {
1023        let sig = self.resolve.wasm_signature(variant, func);
1024
1025        // Lowering parameters calling a wasm import _or_ returning a result
1026        // from an async-lifted wasm export means we don't need to pass
1027        // ownership, but we pass ownership in all other cases.
1028        let realloc = match (variant, lift_lower, async_) {
1029            (AbiVariant::GuestImport, LiftLower::LowerArgsLiftResults, _)
1030            | (
1031                AbiVariant::GuestExport
1032                | AbiVariant::GuestExportAsync
1033                | AbiVariant::GuestExportAsyncStackful,
1034                LiftLower::LiftArgsLowerResults,
1035                true,
1036            ) => Realloc::None,
1037            _ => Realloc::Export("cabi_realloc"),
1038        };
1039        assert!(self.realloc.is_none());
1040
1041        match lift_lower {
1042            LiftLower::LowerArgsLiftResults => {
1043                self.realloc = Some(realloc);
1044
1045                // Create a function that performs individual lowering of operands
1046                let lower_to_memory = |self_: &mut Self, ptr: B::Operand| {
1047                    let mut offset = ArchitectureSize::default();
1048                    for (nth, Param { ty, .. }) in func.params.iter().enumerate() {
1049                        self_.emit(&Instruction::GetArg { nth });
1050                        offset = align_to_arch(offset, self_.bindgen.sizes().align(ty));
1051                        self_.write_to_memory(ty, ptr.clone(), offset);
1052                        offset += self_.bindgen.sizes().size(ty);
1053                    }
1054
1055                    self_.stack.push(ptr);
1056                };
1057
1058                // Lower parameters
1059                if sig.indirect_params {
1060                    // If parameters are indirect space is
1061                    // allocated for them and each argument is lowered
1062                    // individually into memory.
1063                    let ElementInfo { size, align } = self
1064                        .bindgen
1065                        .sizes()
1066                        .record(func.params.iter().map(|param| &param.ty));
1067
1068                    // Resolve the pointer to the indirectly stored parameters
1069                    let ptr = match variant {
1070                        // When a wasm module calls an import it will provide
1071                        // space that isn't explicitly deallocated.
1072                        AbiVariant::GuestImport => self.bindgen.return_pointer(size, align),
1073
1074                        AbiVariant::GuestImportAsync => {
1075                            todo!("direct param lowering for async guest import not implemented")
1076                        }
1077
1078                        // When calling a wasm module from the outside, though,
1079                        // malloc needs to be called.
1080                        AbiVariant::GuestExport => {
1081                            self.emit(&Instruction::Malloc {
1082                                realloc: "cabi_realloc",
1083                                size,
1084                                align,
1085                            });
1086                            self.stack.pop().unwrap()
1087                        }
1088
1089                        AbiVariant::GuestExportAsync | AbiVariant::GuestExportAsyncStackful => {
1090                            todo!("direct param lowering for async not implemented")
1091                        }
1092                    };
1093
1094                    // Lower the parameters to memory
1095                    lower_to_memory(self, ptr);
1096                } else {
1097                    // ... otherwise arguments are direct,
1098                    // (there aren't too many) then we simply do a normal lower
1099                    // operation for them all.
1100                    for (nth, Param { ty, .. }) in func.params.iter().enumerate() {
1101                        self.emit(&Instruction::GetArg { nth });
1102                        self.lower(ty);
1103                    }
1104                }
1105                self.realloc = None;
1106
1107                // If necessary we may need to prepare a return pointer for this ABI.
1108                if variant == AbiVariant::GuestImport && sig.retptr {
1109                    let info = self.bindgen.sizes().params(&func.result);
1110                    let ptr = self.bindgen.return_pointer(info.size, info.align);
1111                    self.return_pointer = Some(ptr.clone());
1112                    self.stack.push(ptr);
1113                }
1114
1115                // Call the Wasm function
1116                assert_eq!(self.stack.len(), sig.params.len());
1117                self.emit(&Instruction::CallWasm {
1118                    name: &func.name,
1119                    sig: &sig,
1120                });
1121
1122                // Handle the result
1123                if sig.retptr {
1124                    // If there is a return pointer, we must get the pointer to where results
1125                    // should be stored, and store the results there?
1126
1127                    let ptr = match variant {
1128                        // imports into guests means it's a wasm module
1129                        // calling an imported function. We supplied the
1130                        // return pointer as the last argument (saved in
1131                        // `self.return_pointer`) so we use that to read
1132                        // the result of the function from memory.
1133                        AbiVariant::GuestImport => {
1134                            assert!(sig.results.is_empty());
1135                            self.return_pointer.take().unwrap()
1136                        }
1137
1138                        // guest exports means that this is a host
1139                        // calling wasm so wasm returned a pointer to where
1140                        // the result is stored
1141                        AbiVariant::GuestExport => self.stack.pop().unwrap(),
1142
1143                        AbiVariant::GuestImportAsync
1144                        | AbiVariant::GuestExportAsync
1145                        | AbiVariant::GuestExportAsyncStackful => {
1146                            unreachable!()
1147                        }
1148                    };
1149
1150                    if let (AbiVariant::GuestExport, true) = (variant, async_) {
1151                        // If we're dealing with an async function, the result should not be read from memory
1152                        // immediately, as it's the async call result
1153                        //
1154                        // We can leave the result of the call (the indication of what to do as an async call)
1155                        // on the stack as a return
1156                        self.stack.push(ptr);
1157                    } else {
1158                        // If we're not dealing with an async call, the result must be in memory at this point and can be read out
1159                        self.read_results_from_memory(
1160                            &func.result,
1161                            ptr.clone(),
1162                            ArchitectureSize::default(),
1163                        );
1164                        self.emit(&Instruction::Flush {
1165                            amt: usize::from(func.result.is_some()),
1166                        });
1167                    }
1168                } else if !async_ {
1169                    // With no return pointer in use for a synchronous call, we can simply lift the
1170                    // result(s) of the function from the result of the core wasm function. For async
1171                    // calls, the component result is delivered via `task.return` and core result is
1172                    // async progress.
1173                    if let Some(ty) = &func.result {
1174                        self.lift(ty)
1175                    }
1176                }
1177
1178                // Emit the function return
1179                if async_ {
1180                    self.emit(&Instruction::AsyncTaskReturn {
1181                        name: &func.name,
1182                        params: &sig.results,
1183                    });
1184                } else {
1185                    self.emit(&Instruction::Return {
1186                        func,
1187                        amt: usize::from(func.result.is_some()),
1188                    });
1189                }
1190            }
1191
1192            LiftLower::LiftArgsLowerResults => {
1193                let max_flat_params = match (variant, async_) {
1194                    (AbiVariant::GuestImportAsync, _is_async @ true) => MAX_FLAT_ASYNC_PARAMS,
1195                    _ => MAX_FLAT_PARAMS,
1196                };
1197
1198                // Read parameters from memory
1199                let read_from_memory = |self_: &mut Self| {
1200                    let mut offset = ArchitectureSize::default();
1201                    let ptr = self_
1202                        .stack
1203                        .pop()
1204                        .expect("empty stack during read param from memory");
1205                    for Param { ty, .. } in func.params.iter() {
1206                        offset = align_to_arch(offset, self_.bindgen.sizes().align(ty));
1207                        self_.read_from_memory(ty, ptr.clone(), offset);
1208                        offset += self_.bindgen.sizes().size(ty);
1209                    }
1210                };
1211
1212                // Resolve parameters
1213                if sig.indirect_params {
1214                    // If parameters were passed indirectly, arguments must be
1215                    // read in succession from memory, with the pointer to the arguments
1216                    // being the first argument to the function.
1217                    self.emit(&Instruction::GetArg { nth: 0 });
1218                    read_from_memory(self);
1219                } else {
1220                    // ... otherwise, if parameters were passed directly then we lift each
1221                    // argument in succession from the component wasm types that
1222                    // make-up the type.
1223                    let mut offset = 0;
1224                    for Param {
1225                        name: param_name,
1226                        ty,
1227                        ..
1228                    } in func.params.iter()
1229                    {
1230                        let Some(types) = flat_types(self.resolve, ty, Some(max_flat_params))
1231                        else {
1232                            panic!(
1233                                "failed to flatten types during direct parameter lifting ('{param_name}' in func '{}')",
1234                                func.name
1235                            );
1236                        };
1237                        for _ in 0..types.len() {
1238                            self.emit(&Instruction::GetArg { nth: offset });
1239                            offset += 1;
1240                        }
1241                        self.lift(ty);
1242                    }
1243                }
1244
1245                // ... and that allows us to call the interface types function
1246                self.emit(&Instruction::CallInterface { func, async_ });
1247
1248                // The return value of an async function is *not* the result of the function
1249                // itself or a pointer but rather a status code.
1250                //
1251                // Asynchronous functions will call `task.return` after the
1252                // interface function completes, so lowering is conditional
1253                // based on slightly different logic for the `task.return`
1254                // intrinsic.
1255                //
1256                // Note that in the async import case the code below deals with the CM function being lowered,
1257                // not the core function that is underneath that (i.e. func.result may be empty,
1258                // where the associated core function underneath must have a i32 status code result)
1259                let (lower_to_memory, async_flat_results) = match (async_, &func.result) {
1260                    // All async cases pass along the function results and flatten where necesary
1261                    (_is_async @ true, func_result) => {
1262                        let results = match &func_result {
1263                            Some(ty) => flat_types(self.resolve, ty, Some(max_flat_params)),
1264                            None => Some(Vec::new()),
1265                        };
1266                        (results.is_none(), Some(results))
1267                    }
1268                    // All other non-async cases
1269                    (_is_async @ false, _) => (sig.retptr, None),
1270                };
1271
1272                // This was dynamically allocated by the caller (or async start
1273                // function) so after it's been read by the guest we need to
1274                // deallocate it.
1275                if let AbiVariant::GuestExport
1276                | AbiVariant::GuestExportAsync
1277                | AbiVariant::GuestExportAsyncStackful = variant
1278                {
1279                    if sig.indirect_params && !async_ {
1280                        let ElementInfo { size, align } = self
1281                            .bindgen
1282                            .sizes()
1283                            .record(func.params.iter().map(|param| &param.ty));
1284                        self.emit(&Instruction::GetArg { nth: 0 });
1285                        self.emit(&Instruction::GuestDeallocate { size, align });
1286                    }
1287                }
1288
1289                self.realloc = Some(realloc);
1290
1291                // Perform memory lowing of relevant results, including out pointers as well as traditional results
1292                match (lower_to_memory, sig.retptr, variant) {
1293                    // For sync calls, if no lowering to memory is required and there *is* a return pointer in use
1294                    // then we need to lower then simply lower the result(s) and return that directly from the function.
1295                    (_lower_to_memory @ false, _, _) => {
1296                        if let Some(ty) = &func.result {
1297                            self.lower(ty);
1298                        }
1299                    }
1300
1301                    // Lowering to memory for a guest import
1302                    //
1303                    // When a function is imported to a guest this means
1304                    // it's a host providing the implementation of the
1305                    // import. The result is stored in the pointer
1306                    // specified in the last argument, so we get the
1307                    // pointer here and then write the return value into
1308                    // it.
1309                    (
1310                        _lower_to_memory @ true,
1311                        _has_ret_ptr @ true,
1312                        AbiVariant::GuestImport | AbiVariant::GuestImportAsync,
1313                    ) => {
1314                        self.emit(&Instruction::GetArg {
1315                            nth: sig.params.len() - 1,
1316                        });
1317                        let ptr = self
1318                            .stack
1319                            .pop()
1320                            .expect("empty stack during result lower to memory");
1321                        self.write_params_to_memory(&func.result, ptr, Default::default());
1322                    }
1323
1324                    // Lowering to memory for a guest export
1325                    //
1326                    // For a guest import this is a function defined in
1327                    // wasm, so we're returning a pointer where the
1328                    // value was stored at. Allocate some space here
1329                    // (statically) and then write the result into that
1330                    // memory, returning the pointer at the end.
1331                    (_lower_to_memory @ true, _, variant) => match variant {
1332                        AbiVariant::GuestExport | AbiVariant::GuestExportAsync => {
1333                            let ElementInfo { size, align } =
1334                                self.bindgen.sizes().params(&func.result);
1335                            let ptr = self.bindgen.return_pointer(size, align);
1336                            self.write_params_to_memory(
1337                                &func.result,
1338                                ptr.clone(),
1339                                Default::default(),
1340                            );
1341                            self.stack.push(ptr);
1342                        }
1343                        AbiVariant::GuestImport | AbiVariant::GuestImportAsync => {
1344                            unreachable!(
1345                                "lowering to memory cannot be performed without a return pointer ({async_note} func [{func_name}], variant {variant:#?})",
1346                                async_note = async_.then_some("async").unwrap_or("sync"),
1347                                func_name = func.name,
1348                            )
1349                        }
1350                        AbiVariant::GuestExportAsyncStackful => {
1351                            todo!("stackful exports are not yet supported")
1352                        }
1353                    },
1354                }
1355
1356                // Build and emit the appropriate return
1357                match (variant, async_flat_results) {
1358                    // Async guest imports always return a i32 status code
1359                    (AbiVariant::GuestImport | AbiVariant::GuestImportAsync, None) if async_ => {
1360                        unreachable!("async guest imports must have a return")
1361                    }
1362
1363                    // Async guest imports with results return the status code, not a pointer to any results
1364                    (AbiVariant::GuestImport | AbiVariant::GuestImportAsync, Some(results))
1365                        if async_ =>
1366                    {
1367                        let name = &format!("[task-return]{}", func.name);
1368                        let params = results.as_deref().unwrap_or_default();
1369                        self.emit(&Instruction::AsyncTaskReturn { name, params });
1370                    }
1371
1372                    // All async/non-async cases with results that need to be returned
1373                    //
1374                    // In practice, async imports should not end up here, as the returned result of an
1375                    // async import is *not* a pointer but instead a status code.
1376                    (_, Some(results)) => {
1377                        let name = &format!("[task-return]{}", func.name);
1378                        let params = results.as_deref().unwrap_or(&[WasmType::Pointer]);
1379                        self.emit(&Instruction::AsyncTaskReturn { name, params });
1380                    }
1381
1382                    // All async/non-async cases with no results
1383                    (_, None) => {
1384                        if async_ {
1385                            let name = &format!("[task-return]{}", func.name);
1386                            self.emit(&Instruction::AsyncTaskReturn {
1387                                name: name,
1388                                params: if sig.results.len() > MAX_FLAT_ASYNC_PARAMS {
1389                                    &[WasmType::Pointer]
1390                                } else {
1391                                    &sig.results
1392                                },
1393                            });
1394                        } else {
1395                            self.emit(&Instruction::Return {
1396                                func,
1397                                amt: sig.results.len(),
1398                            });
1399                        }
1400                    }
1401                }
1402
1403                self.realloc = None;
1404            }
1405        }
1406
1407        assert!(self.realloc.is_none());
1408
1409        assert!(
1410            self.stack.is_empty(),
1411            "stack has {} items remaining: {:?}",
1412            self.stack.len(),
1413            self.stack,
1414        );
1415    }
1416
1417    fn post_return(&mut self, func: &Function) {
1418        let sig = self.resolve.wasm_signature(AbiVariant::GuestExport, func);
1419
1420        // Currently post-return is only used for lists and lists are always
1421        // returned indirectly through memory due to their flat representation
1422        // having more than one type. Assert that a return pointer is used,
1423        // though, in case this ever changes.
1424        assert!(sig.retptr);
1425
1426        self.emit(&Instruction::GetArg { nth: 0 });
1427        let addr = self.stack.pop().unwrap();
1428
1429        let mut types = Vec::new();
1430        types.extend(func.result);
1431        self.deallocate_in_types(&types, &[addr], true, Deallocate::Lists);
1432
1433        self.emit(&Instruction::Return { func, amt: 0 });
1434    }
1435
1436    fn deallocate_in_types(
1437        &mut self,
1438        types: &[Type],
1439        operands: &[B::Operand],
1440        indirect: bool,
1441        what: Deallocate,
1442    ) {
1443        if indirect {
1444            assert_eq!(operands.len(), 1);
1445            for (offset, ty) in self.bindgen.sizes().field_offsets(types) {
1446                self.deallocate_indirect(ty, operands[0].clone(), offset, what);
1447            }
1448            assert!(
1449                self.stack.is_empty(),
1450                "stack has {} items remaining",
1451                self.stack.len()
1452            );
1453        } else {
1454            let mut operands = operands;
1455            let mut operands_for_ty;
1456            for ty in types {
1457                let types = flat_types(self.resolve, ty, None).unwrap();
1458                (operands_for_ty, operands) = operands.split_at(types.len());
1459                self.stack.extend_from_slice(operands_for_ty);
1460                self.deallocate(ty, what);
1461                assert!(
1462                    self.stack.is_empty(),
1463                    "stack has {} items remaining",
1464                    self.stack.len()
1465                );
1466            }
1467            assert!(operands.is_empty());
1468        }
1469    }
1470
1471    fn emit(&mut self, inst: &Instruction<'_>) {
1472        self.operands.clear();
1473        self.results.clear();
1474
1475        let operands_len = inst.operands_len();
1476        assert!(
1477            self.stack.len() >= operands_len,
1478            "not enough operands on stack for {:?}: have {} need {operands_len}",
1479            inst,
1480            self.stack.len(),
1481        );
1482        self.operands
1483            .extend(self.stack.drain((self.stack.len() - operands_len)..));
1484        self.results.reserve(inst.results_len());
1485
1486        self.bindgen
1487            .emit(self.resolve, inst, &mut self.operands, &mut self.results);
1488
1489        assert_eq!(
1490            self.results.len(),
1491            inst.results_len(),
1492            "{:?} expected {} results, got {}",
1493            inst,
1494            inst.results_len(),
1495            self.results.len()
1496        );
1497        self.stack.append(&mut self.results);
1498    }
1499
1500    fn push_block(&mut self) {
1501        self.bindgen.push_block();
1502    }
1503
1504    fn finish_block(&mut self, size: usize) {
1505        self.operands.clear();
1506        assert!(
1507            size <= self.stack.len(),
1508            "not enough operands on stack for finishing block",
1509        );
1510        self.operands
1511            .extend(self.stack.drain((self.stack.len() - size)..));
1512        self.bindgen.finish_block(&mut self.operands);
1513    }
1514
1515    fn lower(&mut self, ty: &Type) {
1516        use Instruction::*;
1517
1518        match *ty {
1519            Type::Bool => self.emit(&I32FromBool),
1520            Type::S8 => self.emit(&I32FromS8),
1521            Type::U8 => self.emit(&I32FromU8),
1522            Type::S16 => self.emit(&I32FromS16),
1523            Type::U16 => self.emit(&I32FromU16),
1524            Type::S32 => self.emit(&I32FromS32),
1525            Type::U32 => self.emit(&I32FromU32),
1526            Type::S64 => self.emit(&I64FromS64),
1527            Type::U64 => self.emit(&I64FromU64),
1528            Type::Char => self.emit(&I32FromChar),
1529            Type::F32 => self.emit(&CoreF32FromF32),
1530            Type::F64 => self.emit(&CoreF64FromF64),
1531            Type::String => {
1532                let realloc = self.list_realloc();
1533                self.emit(&StringLower { realloc });
1534            }
1535            Type::ErrorContext => self.emit(&ErrorContextLower),
1536            Type::Id(id) => match &self.resolve.types[id].kind {
1537                TypeDefKind::Type(t) => self.lower(t),
1538                TypeDefKind::List(element) => {
1539                    let realloc = self.list_realloc();
1540                    if self.bindgen.is_list_canonical(self.resolve, element) {
1541                        self.emit(&ListCanonLower { element, realloc });
1542                    } else {
1543                        self.push_block();
1544                        self.emit(&IterElem { element });
1545                        self.emit(&IterBasePointer);
1546                        let addr = self.stack.pop().unwrap();
1547                        self.write_to_memory(element, addr, Default::default());
1548                        self.finish_block(0);
1549                        self.emit(&ListLower { element, realloc });
1550                    }
1551                }
1552                TypeDefKind::Handle(handle) => {
1553                    let (Handle::Own(ty) | Handle::Borrow(ty)) = handle;
1554                    self.emit(&HandleLower {
1555                        handle,
1556                        ty: id,
1557                        name: self.resolve.types[*ty].name.as_deref().unwrap(),
1558                    });
1559                }
1560                TypeDefKind::Resource => {
1561                    todo!();
1562                }
1563                TypeDefKind::Record(record) => {
1564                    self.emit(&RecordLower {
1565                        record,
1566                        ty: id,
1567                        name: self.resolve.types[id].name.as_deref().unwrap(),
1568                    });
1569                    let values = self
1570                        .stack
1571                        .drain(self.stack.len() - record.fields.len()..)
1572                        .collect::<Vec<_>>();
1573                    for (field, value) in record.fields.iter().zip(values) {
1574                        self.stack.push(value);
1575                        self.lower(&field.ty);
1576                    }
1577                }
1578                TypeDefKind::Tuple(tuple) => {
1579                    self.emit(&TupleLower { tuple, ty: id });
1580                    let values = self
1581                        .stack
1582                        .drain(self.stack.len() - tuple.types.len()..)
1583                        .collect::<Vec<_>>();
1584                    for (ty, value) in tuple.types.iter().zip(values) {
1585                        self.stack.push(value);
1586                        self.lower(ty);
1587                    }
1588                }
1589
1590                TypeDefKind::Flags(flags) => {
1591                    self.emit(&FlagsLower {
1592                        flags,
1593                        ty: id,
1594                        name: self.resolve.types[id].name.as_ref().unwrap(),
1595                    });
1596                }
1597
1598                TypeDefKind::Variant(v) => {
1599                    let results =
1600                        self.lower_variant_arms(ty, v.cases.iter().map(|c| c.ty.as_ref()));
1601                    self.emit(&VariantLower {
1602                        variant: v,
1603                        ty: id,
1604                        results: &results,
1605                        name: self.resolve.types[id].name.as_deref().unwrap(),
1606                    });
1607                }
1608                TypeDefKind::Enum(enum_) => {
1609                    self.emit(&EnumLower {
1610                        enum_,
1611                        ty: id,
1612                        name: self.resolve.types[id].name.as_deref().unwrap(),
1613                    });
1614                }
1615                TypeDefKind::Option(t) => {
1616                    let results = self.lower_variant_arms(ty, [None, Some(t)]);
1617                    self.emit(&OptionLower {
1618                        payload: t,
1619                        ty: id,
1620                        results: &results,
1621                    });
1622                }
1623                TypeDefKind::Result(r) => {
1624                    let results = self.lower_variant_arms(ty, [r.ok.as_ref(), r.err.as_ref()]);
1625                    self.emit(&ResultLower {
1626                        result: r,
1627                        ty: id,
1628                        results: &results,
1629                    });
1630                }
1631                TypeDefKind::Future(ty) => {
1632                    self.emit(&FutureLower {
1633                        payload: ty,
1634                        ty: id,
1635                    });
1636                }
1637                TypeDefKind::Stream(ty) => {
1638                    self.emit(&StreamLower {
1639                        payload: ty,
1640                        ty: id,
1641                    });
1642                }
1643                TypeDefKind::Unknown => unreachable!(),
1644                TypeDefKind::FixedLengthList(ty, size) => {
1645                    self.emit(&FixedLengthListLower {
1646                        element: ty,
1647                        size: *size,
1648                        id,
1649                    });
1650                    let mut values = self
1651                        .stack
1652                        .drain(self.stack.len() - (*size as usize)..)
1653                        .collect::<Vec<_>>();
1654                    for value in values.drain(..) {
1655                        self.stack.push(value);
1656                        self.lower(ty);
1657                    }
1658                }
1659                TypeDefKind::Map(key, value) => {
1660                    let realloc = self.list_realloc();
1661                    let value_offset = self.bindgen.sizes().field_offsets([key, value])[1].0;
1662                    self.push_block();
1663                    self.emit(&IterMapKey { key });
1664                    self.emit(&IterBasePointer);
1665                    let key_addr = self.stack.pop().unwrap();
1666                    self.write_to_memory(key, key_addr, Default::default());
1667                    self.emit(&IterMapValue { value });
1668                    self.emit(&IterBasePointer);
1669                    let value_addr = self.stack.pop().unwrap();
1670                    self.write_to_memory(value, value_addr, value_offset);
1671                    self.finish_block(0);
1672                    self.emit(&MapLower {
1673                        key,
1674                        value,
1675                        realloc,
1676                    });
1677                }
1678            },
1679        }
1680    }
1681
1682    fn lower_variant_arms<'b>(
1683        &mut self,
1684        ty: &Type,
1685        cases: impl IntoIterator<Item = Option<&'b Type>>,
1686    ) -> Vec<WasmType> {
1687        use Instruction::*;
1688        let results = flat_types(self.resolve, ty, None).unwrap();
1689        let mut casts = Vec::new();
1690        for (i, ty) in cases.into_iter().enumerate() {
1691            self.push_block();
1692            self.emit(&VariantPayloadName);
1693            let payload_name = self.stack.pop().unwrap();
1694            self.emit(&I32Const { val: i as i32 });
1695            let mut pushed = 1;
1696            if let Some(ty) = ty {
1697                // Using the payload of this block we lower the type to
1698                // raw wasm values.
1699                self.stack.push(payload_name);
1700                self.lower(ty);
1701
1702                // Determine the types of all the wasm values we just
1703                // pushed, and record how many. If we pushed too few
1704                // then we'll need to push some zeros after this.
1705                let temp = flat_types(self.resolve, ty, None).unwrap();
1706                pushed += temp.len();
1707
1708                // For all the types pushed we may need to insert some
1709                // bitcasts. This will go through and cast everything
1710                // to the right type to ensure all blocks produce the
1711                // same set of results.
1712                casts.truncate(0);
1713                for (actual, expected) in temp.iter().zip(&results[1..]) {
1714                    casts.push(cast(*actual, *expected));
1715                }
1716                if casts.iter().any(|c| *c != Bitcast::None) {
1717                    self.emit(&Bitcasts { casts: &casts });
1718                }
1719            }
1720
1721            // If we haven't pushed enough items in this block to match
1722            // what other variants are pushing then we need to push
1723            // some zeros.
1724            if pushed < results.len() {
1725                self.emit(&ConstZero {
1726                    tys: &results[pushed..],
1727                });
1728            }
1729            self.finish_block(results.len());
1730        }
1731        results
1732    }
1733
1734    fn list_realloc(&self) -> Option<&'static str> {
1735        match self.realloc.expect("realloc should be configured") {
1736            Realloc::None => None,
1737            Realloc::Export(s) => Some(s),
1738        }
1739    }
1740
1741    /// Note that in general everything in this function is the opposite of the
1742    /// `lower` function above. This is intentional and should be kept this way!
1743    fn lift(&mut self, ty: &Type) {
1744        use Instruction::*;
1745
1746        match *ty {
1747            Type::Bool => self.emit(&BoolFromI32),
1748            Type::S8 => self.emit(&S8FromI32),
1749            Type::U8 => self.emit(&U8FromI32),
1750            Type::S16 => self.emit(&S16FromI32),
1751            Type::U16 => self.emit(&U16FromI32),
1752            Type::S32 => self.emit(&S32FromI32),
1753            Type::U32 => self.emit(&U32FromI32),
1754            Type::S64 => self.emit(&S64FromI64),
1755            Type::U64 => self.emit(&U64FromI64),
1756            Type::Char => self.emit(&CharFromI32),
1757            Type::F32 => self.emit(&F32FromCoreF32),
1758            Type::F64 => self.emit(&F64FromCoreF64),
1759            Type::String => self.emit(&StringLift),
1760            Type::ErrorContext => self.emit(&ErrorContextLift),
1761            Type::Id(id) => match &self.resolve.types[id].kind {
1762                TypeDefKind::Type(t) => self.lift(t),
1763                TypeDefKind::List(element) => {
1764                    if self.bindgen.is_list_canonical(self.resolve, element) {
1765                        self.emit(&ListCanonLift { element, ty: id });
1766                    } else {
1767                        self.push_block();
1768                        self.emit(&IterBasePointer);
1769                        let addr = self.stack.pop().unwrap();
1770                        self.read_from_memory(element, addr, Default::default());
1771                        self.finish_block(1);
1772                        self.emit(&ListLift { element, ty: id });
1773                    }
1774                }
1775                TypeDefKind::Handle(handle) => {
1776                    let (Handle::Own(ty) | Handle::Borrow(ty)) = handle;
1777                    self.emit(&HandleLift {
1778                        handle,
1779                        ty: id,
1780                        name: self.resolve.types[*ty].name.as_deref().unwrap(),
1781                    });
1782                }
1783                TypeDefKind::Resource => {
1784                    todo!();
1785                }
1786                TypeDefKind::Record(record) => {
1787                    self.flat_for_each_record_type(
1788                        ty,
1789                        record.fields.iter().map(|f| &f.ty),
1790                        Self::lift,
1791                    );
1792                    self.emit(&RecordLift {
1793                        record,
1794                        ty: id,
1795                        name: self.resolve.types[id].name.as_deref().unwrap(),
1796                    });
1797                }
1798                TypeDefKind::Tuple(tuple) => {
1799                    self.flat_for_each_record_type(ty, tuple.types.iter(), Self::lift);
1800                    self.emit(&TupleLift { tuple, ty: id });
1801                }
1802                TypeDefKind::Flags(flags) => {
1803                    self.emit(&FlagsLift {
1804                        flags,
1805                        ty: id,
1806                        name: self.resolve.types[id].name.as_ref().unwrap(),
1807                    });
1808                }
1809
1810                TypeDefKind::Variant(v) => {
1811                    self.flat_for_each_variant_arm(
1812                        ty,
1813                        true,
1814                        v.cases.iter().map(|c| c.ty.as_ref()),
1815                        Self::lift,
1816                    );
1817                    self.emit(&VariantLift {
1818                        variant: v,
1819                        ty: id,
1820                        name: self.resolve.types[id].name.as_deref().unwrap(),
1821                    });
1822                }
1823
1824                TypeDefKind::Enum(enum_) => {
1825                    self.emit(&EnumLift {
1826                        enum_,
1827                        ty: id,
1828                        name: self.resolve.types[id].name.as_deref().unwrap(),
1829                    });
1830                }
1831
1832                TypeDefKind::Option(t) => {
1833                    self.flat_for_each_variant_arm(ty, true, [None, Some(t)], Self::lift);
1834                    self.emit(&OptionLift { payload: t, ty: id });
1835                }
1836
1837                TypeDefKind::Result(r) => {
1838                    self.flat_for_each_variant_arm(
1839                        ty,
1840                        true,
1841                        [r.ok.as_ref(), r.err.as_ref()],
1842                        Self::lift,
1843                    );
1844                    self.emit(&ResultLift { result: r, ty: id });
1845                }
1846
1847                TypeDefKind::Future(ty) => {
1848                    self.emit(&FutureLift {
1849                        payload: ty,
1850                        ty: id,
1851                    });
1852                }
1853                TypeDefKind::Stream(ty) => {
1854                    self.emit(&StreamLift {
1855                        payload: ty,
1856                        ty: id,
1857                    });
1858                }
1859                TypeDefKind::Unknown => unreachable!(),
1860                TypeDefKind::FixedLengthList(ty, size) => {
1861                    let temp = flat_types(self.resolve, ty, None).unwrap();
1862                    let flat_per_elem = temp.to_vec().len();
1863                    let flatsize = flat_per_elem * (*size as usize);
1864                    let mut lowered_args = self
1865                        .stack
1866                        .drain(self.stack.len() - flatsize..)
1867                        .collect::<Vec<_>>();
1868                    for _ in 0..*size {
1869                        self.stack.extend(lowered_args.drain(..flat_per_elem));
1870                        self.lift(ty);
1871                    }
1872                    self.emit(&FixedLengthListLift {
1873                        element: ty,
1874                        size: *size,
1875                        id,
1876                    });
1877                }
1878                TypeDefKind::Map(key, value) => {
1879                    let value_offset = self.bindgen.sizes().field_offsets([key, value])[1].0;
1880                    self.push_block();
1881                    self.emit(&IterBasePointer);
1882                    let entry_addr = self.stack.pop().unwrap();
1883                    self.read_from_memory(key, entry_addr.clone(), Default::default());
1884                    self.read_from_memory(value, entry_addr, value_offset);
1885                    self.finish_block(2);
1886                    self.emit(&MapLift { key, value, ty: id });
1887                }
1888            },
1889        }
1890    }
1891
1892    fn flat_for_each_record_type<'b>(
1893        &mut self,
1894        container: &Type,
1895        types: impl Iterator<Item = &'b Type>,
1896        mut iter: impl FnMut(&mut Self, &Type),
1897    ) {
1898        let temp = flat_types(self.resolve, container, None).unwrap();
1899        let mut args = self
1900            .stack
1901            .drain(self.stack.len() - temp.len()..)
1902            .collect::<Vec<_>>();
1903        for ty in types {
1904            let temp = flat_types(self.resolve, ty, None).unwrap();
1905            self.stack.extend(args.drain(..temp.len()));
1906            iter(self, ty);
1907        }
1908    }
1909
1910    fn flat_for_each_variant_arm<'b>(
1911        &mut self,
1912        ty: &Type,
1913        blocks_with_type_have_result: bool,
1914        cases: impl IntoIterator<Item = Option<&'b Type>>,
1915        mut iter: impl FnMut(&mut Self, &Type),
1916    ) {
1917        let params = flat_types(self.resolve, ty, None).unwrap();
1918        let mut casts = Vec::new();
1919        let block_inputs = self
1920            .stack
1921            .drain(self.stack.len() + 1 - params.len()..)
1922            .collect::<Vec<_>>();
1923        for ty in cases {
1924            self.push_block();
1925            if let Some(ty) = ty {
1926                // Push only the values we need for this variant onto
1927                // the stack.
1928                let temp = flat_types(self.resolve, ty, None).unwrap();
1929                self.stack
1930                    .extend(block_inputs[..temp.len()].iter().cloned());
1931
1932                // Cast all the types we have on the stack to the actual
1933                // types needed for this variant, if necessary.
1934                casts.truncate(0);
1935                for (actual, expected) in temp.iter().zip(&params[1..]) {
1936                    casts.push(cast(*expected, *actual));
1937                }
1938                if casts.iter().any(|c| *c != Bitcast::None) {
1939                    self.emit(&Instruction::Bitcasts { casts: &casts });
1940                }
1941
1942                // Then recursively lift this variant's payload.
1943                iter(self, ty);
1944            }
1945            self.finish_block(if blocks_with_type_have_result {
1946                ty.is_some() as usize
1947            } else {
1948                0
1949            });
1950        }
1951    }
1952
1953    fn write_to_memory(&mut self, ty: &Type, addr: B::Operand, offset: ArchitectureSize) {
1954        use Instruction::*;
1955
1956        match *ty {
1957            // Builtin types need different flavors of storage instructions
1958            // depending on the size of the value written.
1959            Type::Bool | Type::U8 | Type::S8 => {
1960                self.lower_and_emit(ty, addr, &I32Store8 { offset })
1961            }
1962            Type::U16 | Type::S16 => self.lower_and_emit(ty, addr, &I32Store16 { offset }),
1963            Type::U32 | Type::S32 | Type::Char => {
1964                self.lower_and_emit(ty, addr, &I32Store { offset })
1965            }
1966            Type::U64 | Type::S64 => self.lower_and_emit(ty, addr, &I64Store { offset }),
1967            Type::F32 => self.lower_and_emit(ty, addr, &F32Store { offset }),
1968            Type::F64 => self.lower_and_emit(ty, addr, &F64Store { offset }),
1969            Type::String => self.write_list_to_memory(ty, addr, offset),
1970            Type::ErrorContext => self.lower_and_emit(ty, addr, &I32Store { offset }),
1971
1972            Type::Id(id) => match &self.resolve.types[id].kind {
1973                TypeDefKind::Type(t) => self.write_to_memory(t, addr, offset),
1974                TypeDefKind::List(_) => self.write_list_to_memory(ty, addr, offset),
1975                // Maps have the same linear memory layout as list<tuple<K, V>>.
1976                TypeDefKind::Map(_, _) => self.write_list_to_memory(ty, addr, offset),
1977
1978                TypeDefKind::Future(_) | TypeDefKind::Stream(_) | TypeDefKind::Handle(_) => {
1979                    self.lower_and_emit(ty, addr, &I32Store { offset })
1980                }
1981
1982                // Decompose the record into its components and then write all
1983                // the components into memory one-by-one.
1984                TypeDefKind::Record(record) => {
1985                    self.emit(&RecordLower {
1986                        record,
1987                        ty: id,
1988                        name: self.resolve.types[id].name.as_deref().unwrap(),
1989                    });
1990                    self.write_fields_to_memory(record.fields.iter().map(|f| &f.ty), addr, offset);
1991                }
1992                TypeDefKind::Resource => {
1993                    todo!()
1994                }
1995                TypeDefKind::Tuple(tuple) => {
1996                    self.emit(&TupleLower { tuple, ty: id });
1997                    self.write_fields_to_memory(tuple.types.iter(), addr, offset);
1998                }
1999
2000                TypeDefKind::Flags(f) => {
2001                    self.lower(ty);
2002                    match f.repr() {
2003                        FlagsRepr::U8 => {
2004                            self.stack.push(addr);
2005                            self.store_intrepr(offset, Int::U8);
2006                        }
2007                        FlagsRepr::U16 => {
2008                            self.stack.push(addr);
2009                            self.store_intrepr(offset, Int::U16);
2010                        }
2011                        FlagsRepr::U32(n) => {
2012                            for i in (0..n).rev() {
2013                                self.stack.push(addr.clone());
2014                                self.emit(&I32Store {
2015                                    offset: offset.add_bytes(i * 4),
2016                                });
2017                            }
2018                        }
2019                    }
2020                }
2021
2022                // Each case will get its own block, and the first item in each
2023                // case is writing the discriminant. After that if we have a
2024                // payload we write the payload after the discriminant, aligned up
2025                // to the type's alignment.
2026                TypeDefKind::Variant(v) => {
2027                    self.write_variant_arms_to_memory(
2028                        offset,
2029                        addr,
2030                        v.tag(),
2031                        v.cases.iter().map(|c| c.ty.as_ref()),
2032                    );
2033                    self.emit(&VariantLower {
2034                        variant: v,
2035                        ty: id,
2036                        results: &[],
2037                        name: self.resolve.types[id].name.as_deref().unwrap(),
2038                    });
2039                }
2040
2041                TypeDefKind::Option(t) => {
2042                    self.write_variant_arms_to_memory(offset, addr, Int::U8, [None, Some(t)]);
2043                    self.emit(&OptionLower {
2044                        payload: t,
2045                        ty: id,
2046                        results: &[],
2047                    });
2048                }
2049
2050                TypeDefKind::Result(r) => {
2051                    self.write_variant_arms_to_memory(
2052                        offset,
2053                        addr,
2054                        Int::U8,
2055                        [r.ok.as_ref(), r.err.as_ref()],
2056                    );
2057                    self.emit(&ResultLower {
2058                        result: r,
2059                        ty: id,
2060                        results: &[],
2061                    });
2062                }
2063
2064                TypeDefKind::Enum(e) => {
2065                    self.lower(ty);
2066                    self.stack.push(addr);
2067                    self.store_intrepr(offset, e.tag());
2068                }
2069
2070                TypeDefKind::Unknown => unreachable!(),
2071                TypeDefKind::FixedLengthList(element, size) => {
2072                    // resembles write_list_to_memory
2073                    self.push_block();
2074                    self.emit(&IterElem { element });
2075                    self.emit(&IterBasePointer);
2076                    let elem_addr = self.stack.pop().unwrap();
2077                    self.write_to_memory(element, elem_addr, offset);
2078                    self.finish_block(0);
2079                    self.stack.push(addr);
2080                    self.emit(&FixedLengthListLowerToMemory {
2081                        element,
2082                        size: *size,
2083                        id,
2084                    });
2085                }
2086            },
2087        }
2088    }
2089
2090    fn write_params_to_memory<'b>(
2091        &mut self,
2092        params: impl IntoIterator<Item = &'b Type, IntoIter: ExactSizeIterator>,
2093        addr: B::Operand,
2094        offset: ArchitectureSize,
2095    ) {
2096        self.write_fields_to_memory(params, addr, offset);
2097    }
2098
2099    fn write_variant_arms_to_memory<'b>(
2100        &mut self,
2101        offset: ArchitectureSize,
2102        addr: B::Operand,
2103        tag: Int,
2104        cases: impl IntoIterator<Item = Option<&'b Type>> + Clone,
2105    ) {
2106        let payload_offset = offset + (self.bindgen.sizes().payload_offset(tag, cases.clone()));
2107        for (i, ty) in cases.into_iter().enumerate() {
2108            self.push_block();
2109            self.emit(&Instruction::VariantPayloadName);
2110            let payload_name = self.stack.pop().unwrap();
2111            self.emit(&Instruction::I32Const { val: i as i32 });
2112            self.stack.push(addr.clone());
2113            self.store_intrepr(offset, tag);
2114            if let Some(ty) = ty {
2115                self.stack.push(payload_name.clone());
2116                self.write_to_memory(ty, addr.clone(), payload_offset);
2117            }
2118            self.finish_block(0);
2119        }
2120    }
2121
2122    fn write_list_to_memory(&mut self, ty: &Type, addr: B::Operand, offset: ArchitectureSize) {
2123        // After lowering the list there's two i32 values on the stack
2124        // which we write into memory, writing the pointer into the low address
2125        // and the length into the high address.
2126        self.lower(ty);
2127        self.stack.push(addr.clone());
2128        self.emit(&Instruction::LengthStore {
2129            offset: offset + self.bindgen.sizes().align(ty).into(),
2130        });
2131        self.stack.push(addr);
2132        self.emit(&Instruction::PointerStore { offset });
2133    }
2134
2135    fn write_fields_to_memory<'b>(
2136        &mut self,
2137        tys: impl IntoIterator<Item = &'b Type, IntoIter: ExactSizeIterator>,
2138        addr: B::Operand,
2139        offset: ArchitectureSize,
2140    ) {
2141        let tys = tys.into_iter();
2142        let fields = self
2143            .stack
2144            .drain(self.stack.len() - tys.len()..)
2145            .collect::<Vec<_>>();
2146        for ((field_offset, ty), op) in self
2147            .bindgen
2148            .sizes()
2149            .field_offsets(tys)
2150            .into_iter()
2151            .zip(fields)
2152        {
2153            self.stack.push(op);
2154            self.write_to_memory(ty, addr.clone(), offset + (field_offset));
2155        }
2156    }
2157
2158    fn lower_and_emit(&mut self, ty: &Type, addr: B::Operand, instr: &Instruction) {
2159        self.lower(ty);
2160        self.stack.push(addr);
2161        self.emit(instr);
2162    }
2163
2164    fn read_from_memory(&mut self, ty: &Type, addr: B::Operand, offset: ArchitectureSize) {
2165        use Instruction::*;
2166
2167        match *ty {
2168            Type::Bool => self.emit_and_lift(ty, addr, &I32Load8U { offset }),
2169            Type::U8 => self.emit_and_lift(ty, addr, &I32Load8U { offset }),
2170            Type::S8 => self.emit_and_lift(ty, addr, &I32Load8S { offset }),
2171            Type::U16 => self.emit_and_lift(ty, addr, &I32Load16U { offset }),
2172            Type::S16 => self.emit_and_lift(ty, addr, &I32Load16S { offset }),
2173            Type::U32 | Type::S32 | Type::Char => self.emit_and_lift(ty, addr, &I32Load { offset }),
2174            Type::U64 | Type::S64 => self.emit_and_lift(ty, addr, &I64Load { offset }),
2175            Type::F32 => self.emit_and_lift(ty, addr, &F32Load { offset }),
2176            Type::F64 => self.emit_and_lift(ty, addr, &F64Load { offset }),
2177            Type::String => self.read_list_from_memory(ty, addr, offset),
2178            Type::ErrorContext => self.emit_and_lift(ty, addr, &I32Load { offset }),
2179
2180            Type::Id(id) => match &self.resolve.types[id].kind {
2181                TypeDefKind::Type(t) => self.read_from_memory(t, addr, offset),
2182
2183                TypeDefKind::List(_) => self.read_list_from_memory(ty, addr, offset),
2184                // Maps have the same linear memory layout as list<tuple<K, V>>.
2185                TypeDefKind::Map(_, _) => self.read_list_from_memory(ty, addr, offset),
2186
2187                TypeDefKind::Future(_) | TypeDefKind::Stream(_) | TypeDefKind::Handle(_) => {
2188                    self.emit_and_lift(ty, addr, &I32Load { offset })
2189                }
2190
2191                TypeDefKind::Resource => {
2192                    todo!();
2193                }
2194
2195                // Read and lift each field individually, adjusting the offset
2196                // as we go along, then aggregate all the fields into the
2197                // record.
2198                TypeDefKind::Record(record) => {
2199                    self.read_fields_from_memory(record.fields.iter().map(|f| &f.ty), addr, offset);
2200                    self.emit(&RecordLift {
2201                        record,
2202                        ty: id,
2203                        name: self.resolve.types[id].name.as_deref().unwrap(),
2204                    });
2205                }
2206
2207                TypeDefKind::Tuple(tuple) => {
2208                    self.read_fields_from_memory(&tuple.types, addr, offset);
2209                    self.emit(&TupleLift { tuple, ty: id });
2210                }
2211
2212                TypeDefKind::Flags(f) => {
2213                    match f.repr() {
2214                        FlagsRepr::U8 => {
2215                            self.stack.push(addr);
2216                            self.load_intrepr(offset, Int::U8);
2217                        }
2218                        FlagsRepr::U16 => {
2219                            self.stack.push(addr);
2220                            self.load_intrepr(offset, Int::U16);
2221                        }
2222                        FlagsRepr::U32(n) => {
2223                            for i in 0..n {
2224                                self.stack.push(addr.clone());
2225                                self.emit(&I32Load {
2226                                    offset: offset.add_bytes(i * 4),
2227                                });
2228                            }
2229                        }
2230                    }
2231                    self.lift(ty);
2232                }
2233
2234                // Each case will get its own block, and we'll dispatch to the
2235                // right block based on the `i32.load` we initially perform. Each
2236                // individual block is pretty simple and just reads the payload type
2237                // from the corresponding offset if one is available.
2238                TypeDefKind::Variant(variant) => {
2239                    self.read_variant_arms_from_memory(
2240                        offset,
2241                        addr,
2242                        variant.tag(),
2243                        variant.cases.iter().map(|c| c.ty.as_ref()),
2244                    );
2245                    self.emit(&VariantLift {
2246                        variant,
2247                        ty: id,
2248                        name: self.resolve.types[id].name.as_deref().unwrap(),
2249                    });
2250                }
2251
2252                TypeDefKind::Option(t) => {
2253                    self.read_variant_arms_from_memory(offset, addr, Int::U8, [None, Some(t)]);
2254                    self.emit(&OptionLift { payload: t, ty: id });
2255                }
2256
2257                TypeDefKind::Result(r) => {
2258                    self.read_variant_arms_from_memory(
2259                        offset,
2260                        addr,
2261                        Int::U8,
2262                        [r.ok.as_ref(), r.err.as_ref()],
2263                    );
2264                    self.emit(&ResultLift { result: r, ty: id });
2265                }
2266
2267                TypeDefKind::Enum(e) => {
2268                    self.stack.push(addr.clone());
2269                    self.load_intrepr(offset, e.tag());
2270                    self.lift(ty);
2271                }
2272
2273                TypeDefKind::Unknown => unreachable!(),
2274                TypeDefKind::FixedLengthList(ty, size) => {
2275                    self.push_block();
2276                    self.emit(&IterBasePointer);
2277                    let elemaddr = self.stack.pop().unwrap();
2278                    self.read_from_memory(ty, elemaddr, offset);
2279                    self.finish_block(1);
2280                    self.stack.push(addr.clone());
2281                    self.emit(&FixedLengthListLiftFromMemory {
2282                        element: ty,
2283                        size: *size,
2284                        id,
2285                    });
2286                }
2287            },
2288        }
2289    }
2290
2291    fn read_results_from_memory(
2292        &mut self,
2293        result: &Option<Type>,
2294        addr: B::Operand,
2295        offset: ArchitectureSize,
2296    ) {
2297        self.read_fields_from_memory(result, addr, offset)
2298    }
2299
2300    fn read_variant_arms_from_memory<'b>(
2301        &mut self,
2302        offset: ArchitectureSize,
2303        addr: B::Operand,
2304        tag: Int,
2305        cases: impl IntoIterator<Item = Option<&'b Type>> + Clone,
2306    ) {
2307        self.stack.push(addr.clone());
2308        self.load_intrepr(offset, tag);
2309        let payload_offset = offset + (self.bindgen.sizes().payload_offset(tag, cases.clone()));
2310        for ty in cases {
2311            self.push_block();
2312            if let Some(ty) = ty {
2313                self.read_from_memory(ty, addr.clone(), payload_offset);
2314            }
2315            self.finish_block(ty.is_some() as usize);
2316        }
2317    }
2318
2319    fn read_list_from_memory(&mut self, ty: &Type, addr: B::Operand, offset: ArchitectureSize) {
2320        // Read the pointer/len and then perform the standard lifting
2321        // proceses.
2322        self.stack.push(addr.clone());
2323        self.emit(&Instruction::PointerLoad { offset });
2324        self.stack.push(addr);
2325        self.emit(&Instruction::LengthLoad {
2326            offset: offset + self.bindgen.sizes().align(ty).into(),
2327        });
2328        self.lift(ty);
2329    }
2330
2331    fn read_fields_from_memory<'b>(
2332        &mut self,
2333        tys: impl IntoIterator<Item = &'b Type>,
2334        addr: B::Operand,
2335        offset: ArchitectureSize,
2336    ) {
2337        for (field_offset, ty) in self.bindgen.sizes().field_offsets(tys).iter() {
2338            self.read_from_memory(ty, addr.clone(), offset + (*field_offset));
2339        }
2340    }
2341
2342    fn emit_and_lift(&mut self, ty: &Type, addr: B::Operand, instr: &Instruction) {
2343        self.stack.push(addr);
2344        self.emit(instr);
2345        self.lift(ty);
2346    }
2347
2348    fn load_intrepr(&mut self, offset: ArchitectureSize, repr: Int) {
2349        self.emit(&match repr {
2350            Int::U64 => Instruction::I64Load { offset },
2351            Int::U32 => Instruction::I32Load { offset },
2352            Int::U16 => Instruction::I32Load16U { offset },
2353            Int::U8 => Instruction::I32Load8U { offset },
2354        });
2355    }
2356
2357    fn store_intrepr(&mut self, offset: ArchitectureSize, repr: Int) {
2358        self.emit(&match repr {
2359            Int::U64 => Instruction::I64Store { offset },
2360            Int::U32 => Instruction::I32Store { offset },
2361            Int::U16 => Instruction::I32Store16 { offset },
2362            Int::U8 => Instruction::I32Store8 { offset },
2363        });
2364    }
2365
2366    /// Runs the deallocation of `ty` for the operands currently on
2367    /// `self.stack`.
2368    ///
2369    /// This will pop the ABI items of `ty` from `self.stack`.
2370    fn deallocate(&mut self, ty: &Type, what: Deallocate) {
2371        use Instruction::*;
2372
2373        match *ty {
2374            Type::String => {
2375                self.emit(&Instruction::GuestDeallocateString);
2376            }
2377
2378            Type::Bool
2379            | Type::U8
2380            | Type::S8
2381            | Type::U16
2382            | Type::S16
2383            | Type::U32
2384            | Type::S32
2385            | Type::Char
2386            | Type::U64
2387            | Type::S64
2388            | Type::F32
2389            | Type::F64
2390            | Type::ErrorContext => {
2391                // No deallocation necessary, just discard the operand on the
2392                // stack.
2393                self.stack.pop().unwrap();
2394            }
2395
2396            Type::Id(id) => match &self.resolve.types[id].kind {
2397                TypeDefKind::Type(t) => self.deallocate(t, what),
2398
2399                TypeDefKind::List(element) => {
2400                    self.push_block();
2401                    self.emit(&IterBasePointer);
2402                    let elemaddr = self.stack.pop().unwrap();
2403                    self.deallocate_indirect(element, elemaddr, Default::default(), what);
2404                    self.finish_block(0);
2405
2406                    self.emit(&Instruction::GuestDeallocateList { element });
2407                }
2408
2409                TypeDefKind::Map(key, value) => {
2410                    let value_offset = self.bindgen.sizes().field_offsets([key, value])[1].0;
2411                    self.push_block();
2412                    self.emit(&IterBasePointer);
2413                    let entry_addr = self.stack.pop().unwrap();
2414                    self.deallocate_indirect(key, entry_addr.clone(), Default::default(), what);
2415                    self.deallocate_indirect(value, entry_addr, value_offset, what);
2416                    self.finish_block(0);
2417
2418                    self.emit(&Instruction::GuestDeallocateMap { key, value });
2419                }
2420
2421                TypeDefKind::Handle(Handle::Own(_))
2422                | TypeDefKind::Future(_)
2423                | TypeDefKind::Stream(_)
2424                    if what.handles() =>
2425                {
2426                    self.lift(ty);
2427                    self.emit(&DropHandle { ty });
2428                }
2429
2430                TypeDefKind::Record(record) => {
2431                    self.flat_for_each_record_type(
2432                        ty,
2433                        record.fields.iter().map(|f| &f.ty),
2434                        |me, ty| me.deallocate(ty, what),
2435                    );
2436                }
2437
2438                TypeDefKind::Tuple(tuple) => {
2439                    self.flat_for_each_record_type(ty, tuple.types.iter(), |me, ty| {
2440                        me.deallocate(ty, what)
2441                    });
2442                }
2443
2444                TypeDefKind::Variant(variant) => {
2445                    self.flat_for_each_variant_arm(
2446                        ty,
2447                        false,
2448                        variant.cases.iter().map(|c| c.ty.as_ref()),
2449                        |me, ty| me.deallocate(ty, what),
2450                    );
2451                    self.emit(&GuestDeallocateVariant {
2452                        blocks: variant.cases.len(),
2453                    });
2454                }
2455
2456                TypeDefKind::Option(t) => {
2457                    self.flat_for_each_variant_arm(ty, false, [None, Some(t)], |me, ty| {
2458                        me.deallocate(ty, what)
2459                    });
2460                    self.emit(&GuestDeallocateVariant { blocks: 2 });
2461                }
2462
2463                TypeDefKind::Result(e) => {
2464                    self.flat_for_each_variant_arm(
2465                        ty,
2466                        false,
2467                        [e.ok.as_ref(), e.err.as_ref()],
2468                        |me, ty| me.deallocate(ty, what),
2469                    );
2470                    self.emit(&GuestDeallocateVariant { blocks: 2 });
2471                }
2472
2473                // discard the operand on the stack, otherwise nothing to free.
2474                TypeDefKind::Flags(_)
2475                | TypeDefKind::Enum(_)
2476                | TypeDefKind::Future(_)
2477                | TypeDefKind::Stream(_)
2478                | TypeDefKind::Handle(Handle::Own(_))
2479                | TypeDefKind::Handle(Handle::Borrow(_)) => {
2480                    self.stack.pop().unwrap();
2481                }
2482
2483                TypeDefKind::Resource => unreachable!(),
2484                TypeDefKind::Unknown => unreachable!(),
2485
2486                TypeDefKind::FixedLengthList(..) => todo!(),
2487            },
2488        }
2489    }
2490
2491    fn deallocate_indirect(
2492        &mut self,
2493        ty: &Type,
2494        addr: B::Operand,
2495        offset: ArchitectureSize,
2496        what: Deallocate,
2497    ) {
2498        use Instruction::*;
2499
2500        // No need to execute any instructions if this type itself doesn't
2501        // require any form of post-return.
2502        if !needs_deallocate(self.resolve, ty, what) {
2503            return;
2504        }
2505
2506        match *ty {
2507            Type::String => {
2508                self.stack.push(addr.clone());
2509                self.emit(&Instruction::PointerLoad { offset });
2510                self.stack.push(addr);
2511                self.emit(&Instruction::LengthLoad {
2512                    offset: offset + self.bindgen.sizes().align(ty).into(),
2513                });
2514                self.deallocate(ty, what);
2515            }
2516
2517            Type::Bool
2518            | Type::U8
2519            | Type::S8
2520            | Type::U16
2521            | Type::S16
2522            | Type::U32
2523            | Type::S32
2524            | Type::Char
2525            | Type::U64
2526            | Type::S64
2527            | Type::F32
2528            | Type::F64
2529            | Type::ErrorContext => {}
2530
2531            Type::Id(id) => match &self.resolve.types[id].kind {
2532                TypeDefKind::Type(t) => self.deallocate_indirect(t, addr, offset, what),
2533
2534                TypeDefKind::List(_) => {
2535                    self.stack.push(addr.clone());
2536                    self.emit(&Instruction::PointerLoad { offset });
2537                    self.stack.push(addr);
2538                    self.emit(&Instruction::LengthLoad {
2539                        offset: offset + self.bindgen.sizes().align(ty).into(),
2540                    });
2541
2542                    self.deallocate(ty, what);
2543                }
2544
2545                TypeDefKind::Map(_, _) => {
2546                    self.stack.push(addr.clone());
2547                    self.emit(&Instruction::PointerLoad { offset });
2548                    self.stack.push(addr);
2549                    self.emit(&Instruction::LengthLoad {
2550                        offset: offset + self.bindgen.sizes().align(ty).into(),
2551                    });
2552
2553                    self.deallocate(ty, what);
2554                }
2555
2556                TypeDefKind::Handle(Handle::Own(_))
2557                | TypeDefKind::Future(_)
2558                | TypeDefKind::Stream(_)
2559                    if what.handles() =>
2560                {
2561                    self.read_from_memory(ty, addr, offset);
2562                    self.emit(&DropHandle { ty });
2563                }
2564
2565                TypeDefKind::Handle(Handle::Own(_)) => unreachable!(),
2566                TypeDefKind::Handle(Handle::Borrow(_)) => unreachable!(),
2567                TypeDefKind::Resource => unreachable!(),
2568
2569                TypeDefKind::Record(record) => {
2570                    self.deallocate_indirect_fields(
2571                        &record.fields.iter().map(|f| f.ty).collect::<Vec<_>>(),
2572                        addr,
2573                        offset,
2574                        what,
2575                    );
2576                }
2577
2578                TypeDefKind::Tuple(tuple) => {
2579                    self.deallocate_indirect_fields(&tuple.types, addr, offset, what);
2580                }
2581
2582                TypeDefKind::Flags(_) => {}
2583
2584                TypeDefKind::Variant(variant) => {
2585                    self.deallocate_indirect_variant(
2586                        offset,
2587                        addr,
2588                        variant.tag(),
2589                        variant.cases.iter().map(|c| c.ty.as_ref()),
2590                        what,
2591                    );
2592                    self.emit(&GuestDeallocateVariant {
2593                        blocks: variant.cases.len(),
2594                    });
2595                }
2596
2597                TypeDefKind::Option(t) => {
2598                    self.deallocate_indirect_variant(offset, addr, Int::U8, [None, Some(t)], what);
2599                    self.emit(&GuestDeallocateVariant { blocks: 2 });
2600                }
2601
2602                TypeDefKind::Result(e) => {
2603                    self.deallocate_indirect_variant(
2604                        offset,
2605                        addr,
2606                        Int::U8,
2607                        [e.ok.as_ref(), e.err.as_ref()],
2608                        what,
2609                    );
2610                    self.emit(&GuestDeallocateVariant { blocks: 2 });
2611                }
2612
2613                TypeDefKind::Enum(_) => {}
2614
2615                TypeDefKind::Future(_) => unreachable!(),
2616                TypeDefKind::Stream(_) => unreachable!(),
2617                TypeDefKind::Unknown => unreachable!(),
2618                TypeDefKind::FixedLengthList(_, _) => {}
2619            },
2620        }
2621    }
2622
2623    fn deallocate_indirect_variant<'b>(
2624        &mut self,
2625        offset: ArchitectureSize,
2626        addr: B::Operand,
2627        tag: Int,
2628        cases: impl IntoIterator<Item = Option<&'b Type>> + Clone,
2629        what: Deallocate,
2630    ) {
2631        self.stack.push(addr.clone());
2632        self.load_intrepr(offset, tag);
2633        let payload_offset = offset + (self.bindgen.sizes().payload_offset(tag, cases.clone()));
2634        for ty in cases {
2635            self.push_block();
2636            if let Some(ty) = ty {
2637                self.deallocate_indirect(ty, addr.clone(), payload_offset, what);
2638            }
2639            self.finish_block(0);
2640        }
2641    }
2642
2643    fn deallocate_indirect_fields(
2644        &mut self,
2645        tys: &[Type],
2646        addr: B::Operand,
2647        offset: ArchitectureSize,
2648        what: Deallocate,
2649    ) {
2650        for (field_offset, ty) in self.bindgen.sizes().field_offsets(tys) {
2651            self.deallocate_indirect(ty, addr.clone(), offset + (field_offset), what);
2652        }
2653    }
2654}
2655
2656/// Returns the [`Bitcast`] required to move a value of flat type
2657/// `from` into flat type `to` under the canonical ABI's unification
2658/// rules. Panics if the pair isn't a legal bitcast per the spec.
2659pub fn cast(from: WasmType, to: WasmType) -> Bitcast {
2660    use WasmType::*;
2661
2662    match (from, to) {
2663        (I32, I32)
2664        | (I64, I64)
2665        | (F32, F32)
2666        | (F64, F64)
2667        | (Pointer, Pointer)
2668        | (PointerOrI64, PointerOrI64)
2669        | (Length, Length) => Bitcast::None,
2670
2671        (I32, I64) => Bitcast::I32ToI64,
2672        (F32, I32) => Bitcast::F32ToI32,
2673        (F64, I64) => Bitcast::F64ToI64,
2674
2675        (I64, I32) => Bitcast::I64ToI32,
2676        (I32, F32) => Bitcast::I32ToF32,
2677        (I64, F64) => Bitcast::I64ToF64,
2678
2679        (F32, I64) => Bitcast::F32ToI64,
2680        (I64, F32) => Bitcast::I64ToF32,
2681
2682        (I64, PointerOrI64) => Bitcast::I64ToP64,
2683        (Pointer, PointerOrI64) => Bitcast::PToP64,
2684        (_, PointerOrI64) => {
2685            Bitcast::Sequence(Box::new([cast(from, I64), cast(I64, PointerOrI64)]))
2686        }
2687
2688        (PointerOrI64, I64) => Bitcast::P64ToI64,
2689        (PointerOrI64, Pointer) => Bitcast::P64ToP,
2690        (PointerOrI64, _) => Bitcast::Sequence(Box::new([cast(PointerOrI64, I64), cast(I64, to)])),
2691
2692        (I32, Pointer) => Bitcast::I32ToP,
2693        (Pointer, I32) => Bitcast::PToI32,
2694        (I32, Length) => Bitcast::I32ToL,
2695        (Length, I32) => Bitcast::LToI32,
2696        (I64, Length) => Bitcast::I64ToL,
2697        (Length, I64) => Bitcast::LToI64,
2698        (Pointer, Length) => Bitcast::PToL,
2699        (Length, Pointer) => Bitcast::LToP,
2700
2701        (F32, Pointer | Length) => Bitcast::Sequence(Box::new([cast(F32, I32), cast(I32, to)])),
2702        (Pointer | Length, F32) => Bitcast::Sequence(Box::new([cast(from, I32), cast(I32, F32)])),
2703
2704        (F32, F64)
2705        | (F64, F32)
2706        | (F64, I32)
2707        | (I32, F64)
2708        | (Pointer | Length, I64 | F64)
2709        | (I64 | F64, Pointer | Length) => {
2710            unreachable!("Don't know how to bitcast from {:?} to {:?}", from, to);
2711        }
2712    }
2713}
2714
2715/// Flatten a component-level type into its canonical-ABI wasm-type
2716/// sequence, or return `None` if the result would exceed `max_params`.
2717///
2718/// `max_params` defaults to [`Resolve::MAX_FLAT_PARAMS`] (16). It is
2719/// sometimes necessary to restrict the cap dynamically — for example
2720/// during an async guest-import call, where flat params are limited
2721/// to 4.
2722pub fn flat_types(
2723    resolve: &Resolve,
2724    ty: &Type,
2725    max_params: Option<usize>,
2726) -> Option<Vec<WasmType>> {
2727    let max_params = max_params.unwrap_or(MAX_FLAT_PARAMS);
2728    let mut storage = iter::repeat_n(WasmType::I32, max_params).collect::<Vec<_>>();
2729    let mut flat = FlatTypes::new(storage.as_mut_slice());
2730    resolve.push_flat(ty, &mut flat).then_some(flat.to_vec())
2731}