wasmer_wit_parser/abi.rs
1use crate::sizealign::align_to;
2use crate::{
3 Enum, Expected, Flags, FlagsRepr, Function, Int, Interface, Record, ResourceId, Tuple, Type,
4 TypeDefKind, TypeId, Union, Variant,
5};
6use std::mem;
7
8/// A raw WebAssembly signature with params and results.
9#[derive(Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord)]
10pub struct WasmSignature {
11 /// The WebAssembly parameters of this function.
12 pub params: Vec<WasmType>,
13
14 /// The WebAssembly results of this function.
15 pub results: Vec<WasmType>,
16
17 /// Whether or not this signature is passing all of its parameters
18 /// indirectly through a pointer within `params`.
19 ///
20 /// Note that `params` still reflects the true wasm paramters of this
21 /// function, this is auxiliary information for code generators if
22 /// necessary.
23 pub indirect_params: bool,
24
25 /// Whether or not this signature is using a return pointer to store the
26 /// result of the function, which is reflected either in `params` or
27 /// `results` depending on the context this function is used (e.g. an import
28 /// or an export).
29 pub retptr: bool,
30}
31
32/// Enumerates wasm types used by interface types when lowering/lifting.
33#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
34pub enum WasmType {
35 I32,
36 I64,
37 F32,
38 F64,
39 // NOTE: we don't lower interface types to any other Wasm type,
40 // e.g. externref, so we don't need to define them here.
41}
42
43fn join(a: WasmType, b: WasmType) -> WasmType {
44 use WasmType::*;
45
46 match (a, b) {
47 (I32, I32) | (I64, I64) | (F32, F32) | (F64, F64) => a,
48
49 (I32, F32) | (F32, I32) => I32,
50
51 (_, I64 | F64) | (I64 | F64, _) => I64,
52 }
53}
54
55impl From<Int> for WasmType {
56 fn from(i: Int) -> WasmType {
57 match i {
58 Int::U8 | Int::U16 | Int::U32 => WasmType::I32,
59 Int::U64 => WasmType::I64,
60 }
61 }
62}
63
64// Helper macro for defining instructions without having to have tons of
65// exhaustive `match` statements to update
66macro_rules! def_instruction {
67 (
68 $( #[$enum_attr:meta] )*
69 pub enum $name:ident<'a> {
70 $(
71 $( #[$attr:meta] )*
72 $variant:ident $( {
73 $($field:ident : $field_ty:ty $(,)* )*
74 } )?
75 :
76 [$num_popped:expr] => [$num_pushed:expr],
77 )*
78 }
79 ) => {
80 $( #[$enum_attr] )*
81 pub enum $name<'a> {
82 $(
83 $( #[$attr] )*
84 $variant $( {
85 $(
86 $field : $field_ty,
87 )*
88 } )? ,
89 )*
90 }
91
92 impl $name<'_> {
93 /// How many operands does this instruction pop from the stack?
94 #[allow(unused_variables)]
95 pub fn operands_len(&self) -> usize {
96 match self {
97 $(
98 Self::$variant $( {
99 $(
100 $field,
101 )*
102 } )? => $num_popped,
103 )*
104 }
105 }
106
107 /// How many results does this instruction push onto the stack?
108 #[allow(unused_variables)]
109 pub fn results_len(&self) -> usize {
110 match self {
111 $(
112 Self::$variant $( {
113 $(
114 $field,
115 )*
116 } )? => $num_pushed,
117 )*
118 }
119 }
120 }
121 };
122}
123
124def_instruction! {
125 #[derive(Debug)]
126 pub enum Instruction<'a> {
127 /// Acquires the specified parameter and places it on the stack.
128 /// Depending on the context this may refer to wasm parameters or
129 /// interface types parameters.
130 GetArg { nth: usize } : [0] => [1],
131
132 // Integer const/manipulation instructions
133
134 /// Pushes the constant `val` onto the stack.
135 I32Const { val: i32 } : [0] => [1],
136 /// Casts the top N items on the stack using the `Bitcast` enum
137 /// provided. Consumes the same number of operands that this produces.
138 Bitcasts { casts: &'a [Bitcast] } : [casts.len()] => [casts.len()],
139 /// Pushes a number of constant zeros for each wasm type on the stack.
140 ConstZero { tys: &'a [WasmType] } : [0] => [tys.len()],
141
142 // Memory load/store instructions
143
144 /// Pops an `i32` from the stack and loads a little-endian `i32` from
145 /// it, using the specified constant offset.
146 I32Load { offset: i32 } : [1] => [1],
147 /// Pops an `i32` from the stack and loads a little-endian `i8` from
148 /// it, using the specified constant offset. The value loaded is the
149 /// zero-extended to 32-bits
150 I32Load8U { offset: i32 } : [1] => [1],
151 /// Pops an `i32` from the stack and loads a little-endian `i8` from
152 /// it, using the specified constant offset. The value loaded is the
153 /// sign-extended to 32-bits
154 I32Load8S { offset: i32 } : [1] => [1],
155 /// Pops an `i32` from the stack and loads a little-endian `i16` from
156 /// it, using the specified constant offset. The value loaded is the
157 /// zero-extended to 32-bits
158 I32Load16U { offset: i32 } : [1] => [1],
159 /// Pops an `i32` from the stack and loads a little-endian `i16` from
160 /// it, using the specified constant offset. The value loaded is the
161 /// sign-extended to 32-bits
162 I32Load16S { offset: i32 } : [1] => [1],
163 /// Pops an `i32` from the stack and loads a little-endian `i64` from
164 /// it, using the specified constant offset.
165 I64Load { offset: i32 } : [1] => [1],
166 /// Pops an `i32` from the stack and loads a little-endian `f32` from
167 /// it, using the specified constant offset.
168 F32Load { offset: i32 } : [1] => [1],
169 /// Pops an `i32` from the stack and loads a little-endian `f64` from
170 /// it, using the specified constant offset.
171 F64Load { offset: i32 } : [1] => [1],
172
173 /// Pops an `i32` address from the stack and then an `i32` value.
174 /// Stores the value in little-endian at the pointer specified plus the
175 /// constant `offset`.
176 I32Store { offset: i32 } : [2] => [0],
177 /// Pops an `i32` address from the stack and then an `i32` value.
178 /// Stores the low 8 bits of the value in little-endian at the pointer
179 /// specified plus the constant `offset`.
180 I32Store8 { offset: i32 } : [2] => [0],
181 /// Pops an `i32` address from the stack and then an `i32` value.
182 /// Stores the low 16 bits of the value in little-endian at the pointer
183 /// specified plus the constant `offset`.
184 I32Store16 { offset: i32 } : [2] => [0],
185 /// Pops an `i32` address from the stack and then an `i64` value.
186 /// Stores the value in little-endian at the pointer specified plus the
187 /// constant `offset`.
188 I64Store { offset: i32 } : [2] => [0],
189 /// Pops an `i32` address from the stack and then an `f32` value.
190 /// Stores the value in little-endian at the pointer specified plus the
191 /// constant `offset`.
192 F32Store { offset: i32 } : [2] => [0],
193 /// Pops an `i32` address from the stack and then an `f64` value.
194 /// Stores the value in little-endian at the pointer specified plus the
195 /// constant `offset`.
196 F64Store { offset: i32 } : [2] => [0],
197
198 // Scalar lifting/lowering
199
200 /// Converts an interface type `char` value to a 32-bit integer
201 /// representing the unicode scalar value.
202 I32FromChar : [1] => [1],
203 /// Converts an interface type `u64` value to a wasm `i64`.
204 I64FromU64 : [1] => [1],
205 /// Converts an interface type `s64` value to a wasm `i64`.
206 I64FromS64 : [1] => [1],
207 /// Converts an interface type `u32` value to a wasm `i32`.
208 I32FromU32 : [1] => [1],
209 /// Converts an interface type `s32` value to a wasm `i32`.
210 I32FromS32 : [1] => [1],
211 /// Converts an interface type `u16` value to a wasm `i32`.
212 I32FromU16 : [1] => [1],
213 /// Converts an interface type `s16` value to a wasm `i32`.
214 I32FromS16 : [1] => [1],
215 /// Converts an interface type `u8` value to a wasm `i32`.
216 I32FromU8 : [1] => [1],
217 /// Converts an interface type `s8` value to a wasm `i32`.
218 I32FromS8 : [1] => [1],
219 /// Conversion an interface type `f32` value to a wasm `f32`.
220 ///
221 /// This may be a noop for some implementations, but it's here in case the
222 /// native language representation of `f32` is different than the wasm
223 /// representation of `f32`.
224 F32FromFloat32 : [1] => [1],
225 /// Conversion an interface type `f64` value to a wasm `f64`.
226 ///
227 /// This may be a noop for some implementations, but it's here in case the
228 /// native language representation of `f64` is different than the wasm
229 /// representation of `f64`.
230 F64FromFloat64 : [1] => [1],
231
232 /// Converts a native wasm `i32` to an interface type `s8`.
233 ///
234 /// This will truncate the upper bits of the `i32`.
235 S8FromI32 : [1] => [1],
236 /// Converts a native wasm `i32` to an interface type `u8`.
237 ///
238 /// This will truncate the upper bits of the `i32`.
239 U8FromI32 : [1] => [1],
240 /// Converts a native wasm `i32` to an interface type `s16`.
241 ///
242 /// This will truncate the upper bits of the `i32`.
243 S16FromI32 : [1] => [1],
244 /// Converts a native wasm `i32` to an interface type `u16`.
245 ///
246 /// This will truncate the upper bits of the `i32`.
247 U16FromI32 : [1] => [1],
248 /// Converts a native wasm `i32` to an interface type `s32`.
249 S32FromI32 : [1] => [1],
250 /// Converts a native wasm `i32` to an interface type `u32`.
251 U32FromI32 : [1] => [1],
252 /// Converts a native wasm `i64` to an interface type `s64`.
253 S64FromI64 : [1] => [1],
254 /// Converts a native wasm `i64` to an interface type `u64`.
255 U64FromI64 : [1] => [1],
256 /// Converts a native wasm `i32` to an interface type `char`.
257 ///
258 /// It's safe to assume that the `i32` is indeed a valid unicode code point.
259 CharFromI32 : [1] => [1],
260 /// Converts a native wasm `f32` to an interface type `f32`.
261 Float32FromF32 : [1] => [1],
262 /// Converts a native wasm `f64` to an interface type `f64`.
263 Float64FromF64 : [1] => [1],
264
265 /// Creates a `bool` from an `i32` input, trapping if the `i32` isn't
266 /// zero or one.
267 BoolFromI32 : [1] => [1],
268 /// Creates an `i32` from a `bool` input, must return 0 or 1.
269 I32FromBool : [1] => [1],
270
271 /// Creates a "unit" value from nothing.
272 UnitLift : [0] => [1],
273 /// Consumes a "unit" value and returns nothing.
274 UnitLower : [1] => [0],
275
276 // Handles
277
278 /// Converts a "borrowed" handle into a wasm `i32` value.
279 ///
280 /// > **Note**: this documentation is outdated and does not reflect the
281 /// > current implementation of the canonical ABI. This needs to be
282 /// > updated.
283 ///
284 /// A "borrowed" handle in this case means one where ownership is not
285 /// being relinquished. This is only used for lowering interface types
286 /// parameters.
287 ///
288 /// Situations that this is used are:
289 ///
290 /// * A wasm exported function receives, as a parameter, handles defined
291 /// by the wasm module itself. This is effectively proof of ownership
292 /// by an external caller (be it host or wasm module) and the
293 /// ownership of the handle still lies with the caller. The wasm
294 /// module is only receiving a reference to the resource.
295 ///
296 /// * A wasm module is calling an import with a handle defined by the
297 /// import's module. Sort of the converse of the previous case this
298 /// means that the wasm module is handing out a reference to a
299 /// resource that it owns. The type in the wasm module, for example,
300 /// needs to reflect this.
301 ///
302 /// This instruction is not used for return values in either
303 /// export/import positions.
304 I32FromBorrowedHandle { ty: ResourceId } : [1] => [1],
305
306 /// Converts an "owned" handle into a wasm `i32` value.
307 ///
308 /// > **Note**: this documentation is outdated and does not reflect the
309 /// > current implementation of the canonical ABI. This needs to be
310 /// > updated.
311 ///
312 /// This conversion is used for handle values which are crossing a
313 /// module boundary for perhaps the first time. Some example cases of
314 /// when this conversion is used are:
315 ///
316 /// * When a host defines a function to be imported, returned handles
317 /// use this instruction. Handles being returned to wasm a granting a
318 /// capability, which means that this new capability is typically
319 /// wrapped up in a new integer descriptor.
320 ///
321 /// * When a wasm module calls an imported function with a type defined
322 /// by itself, then it's granting a capability to the callee. This
323 /// means that the wasm module's type is being granted for the first
324 /// time, possibly, so it needs to be an owned value that's consumed.
325 /// Note that this doesn't actually happen with `*.witx` today due to
326 /// the lack of handle type imports.
327 ///
328 /// * When a wasm module export returns a handle defined within the
329 /// module, then it's similar to calling an imported function with
330 /// that handle. The capability is being granted to the caller of the
331 /// export, so the owned value is wrapped up in an `i32`.
332 ///
333 /// * When a host is calling a wasm module with a capability defined by
334 /// the host, its' similar to the host import returning a capability.
335 /// This would be granting the wasm module with the capability so an
336 /// owned version with a fresh handle is passed to the wasm module.
337 /// Note that this doesn't happen today with `*.witx` due to the lack
338 /// of handle type imports.
339 ///
340 /// Basically this instruction is used for handle->wasm conversions
341 /// depending on the calling context and where the handle type in
342 /// question was defined.
343 I32FromOwnedHandle { ty: ResourceId } : [1] => [1],
344
345 /// Converts a native wasm `i32` into an owned handle value.
346 ///
347 /// > **Note**: this documentation is outdated and does not reflect the
348 /// > current implementation of the canonical ABI. This needs to be
349 /// > updated.
350 ///
351 /// This is the converse of `I32FromOwnedHandle` and is used in similar
352 /// situations:
353 ///
354 /// * A host definition of an import receives a handle defined in the
355 /// module itself.
356 /// * A wasm module calling an import receives a handle defined by the
357 /// import.
358 /// * A wasm module's export receives a handle defined by an external
359 /// module.
360 /// * A host calling a wasm export receives a handle defined in the
361 /// module.
362 ///
363 /// Note that like `I32FromOwnedHandle` the first and third bullets
364 /// above don't happen today because witx can't express type imports
365 /// just yet.
366 HandleOwnedFromI32 { ty: ResourceId } : [1] => [1],
367
368 /// Converts a native wasm `i32` into a borrowedhandle value.
369 ///
370 /// > **Note**: this documentation is outdated and does not reflect the
371 /// > current implementation of the canonical ABI. This needs to be
372 /// > updated.
373 ///
374 /// This is the converse of `I32FromBorrowedHandle` and is used in similar
375 /// situations:
376 ///
377 /// * An exported wasm function receives, as a parameter, a handle that
378 /// is defined by the wasm module.
379 /// * An host-defined imported function is receiving a handle, as a
380 /// parameter, that is defined by the host itself.
381 HandleBorrowedFromI32 { ty: ResourceId } : [1] => [1],
382
383 // lists
384
385 /// Lowers a list where the element's layout in the native language is
386 /// expected to match the canonical ABI definition of interface types.
387 ///
388 /// Pops a list value from the stack and pushes the pointer/length onto
389 /// the stack. If `realloc` is set to `Some` then this is expected to
390 /// *consume* the list which means that the data needs to be copied. An
391 /// allocation/copy is expected when:
392 ///
393 /// * A host is calling a wasm export with a list (it needs to copy the
394 /// list in to the callee's module, allocating space with `realloc`)
395 /// * A wasm export is returning a list (it's expected to use `realloc`
396 /// to give ownership of the list to the caller.
397 /// * A host is returning a list in a import definition, meaning that
398 /// space needs to be allocated in the caller with `realloc`).
399 ///
400 /// A copy does not happen (e.g. `realloc` is `None`) when:
401 ///
402 /// * A wasm module calls an import with the list. In this situation
403 /// it's expected the caller will know how to access this module's
404 /// memory (e.g. the host has raw access or wasm-to-wasm communication
405 /// would copy the list).
406 ///
407 /// If `realloc` is `Some` then the adapter is not responsible for
408 /// cleaning up this list because the other end is receiving the
409 /// allocation. If `realloc` is `None` then the adapter is responsible
410 /// for cleaning up any temporary allocation it created, if any.
411 ListCanonLower {
412 element: &'a Type,
413 realloc: Option<&'a str>,
414 } : [1] => [2],
415
416 /// Same as `ListCanonLower`, but used for strings
417 StringLower {
418 realloc: Option<&'a str>,
419 } : [1] => [2],
420
421 /// Lowers a list where the element's layout in the native language is
422 /// not expected to match the canonical ABI definition of interface
423 /// types.
424 ///
425 /// Pops a list value from the stack and pushes the pointer/length onto
426 /// the stack. This operation also pops a block from the block stack
427 /// which is used as the iteration body of writing each element of the
428 /// list consumed.
429 ///
430 /// The `realloc` field here behaves the same way as `ListCanonLower`.
431 /// It's only set to `None` when a wasm module calls a declared import.
432 /// Otherwise lowering in other contexts requires allocating memory for
433 /// the receiver to own.
434 ListLower {
435 element: &'a Type,
436 realloc: Option<&'a str>,
437 } : [1] => [2],
438
439 /// Lifts a list which has a canonical representation into an interface
440 /// types value.
441 ///
442 /// The term "canonical" representation here means that the
443 /// representation of the interface types value in the native language
444 /// exactly matches the canonical ABI definition of the type.
445 ///
446 /// This will consume two `i32` values from the stack, a pointer and a
447 /// length, and then produces an interface value list. If the `free`
448 /// field is set to `Some` then the pointer/length should be considered
449 /// an owned allocation and need to be deallocated by the receiver. If
450 /// it is set to `None` then a view is provided but it does not need to
451 /// be deallocated.
452 ///
453 /// The `free` field is set to `Some` in similar situations as described
454 /// by `ListCanonLower`. If `free` is `Some` then the memory must be
455 /// deallocated after the lifted list is done being consumed. If it is
456 /// `None` then the receiver of the lifted list does not own the memory
457 /// and must leave the memory as-is.
458 ListCanonLift {
459 element: &'a Type,
460 free: Option<&'a str>,
461 ty: TypeId,
462 } : [2] => [1],
463
464 /// Same as `ListCanonLift`, but used for strings
465 StringLift {
466 free: Option<&'a str>,
467 } : [2] => [1],
468
469 /// Lifts a list which into an interface types value.
470 ///
471 /// This will consume two `i32` values from the stack, a pointer and a
472 /// length, and then produces an interface value list. Note that the
473 /// pointer/length popped are **owned** and need to be deallocated with
474 /// the wasm `free` function when the list is no longer needed.
475 ///
476 /// This will also pop a block from the block stack which is how to
477 /// read each individual element from the list.
478 ListLift {
479 element: &'a Type,
480 free: Option<&'a str>,
481 ty: TypeId,
482 } : [2] => [1],
483
484 /// Pushes an operand onto the stack representing the list item from
485 /// each iteration of the list.
486 ///
487 /// This is only used inside of blocks related to lowering lists.
488 IterElem { element: &'a Type } : [0] => [1],
489
490 /// Pushes an operand onto the stack representing the base pointer of
491 /// the next element in a list.
492 ///
493 /// This is used for both lifting and lowering lists.
494 IterBasePointer : [0] => [1],
495
496 // records
497
498 /// Pops a record value off the stack, decomposes the record to all of
499 /// its fields, and then pushes the fields onto the stack.
500 RecordLower {
501 record: &'a Record,
502 name: &'a str,
503 ty: TypeId,
504 } : [1] => [record.fields.len()],
505
506 /// Pops all fields for a record off the stack and then composes them
507 /// into a record.
508 RecordLift {
509 record: &'a Record,
510 name: &'a str,
511 ty: TypeId,
512 } : [record.fields.len()] => [1],
513
514 /// Pops a tuple value off the stack, decomposes the tuple to all of
515 /// its fields, and then pushes the fields onto the stack.
516 TupleLower {
517 tuple: &'a Tuple,
518 ty: TypeId,
519 } : [1] => [tuple.types.len()],
520
521 /// Pops all fields for a tuple off the stack and then composes them
522 /// into a tuple.
523 TupleLift {
524 tuple: &'a Tuple,
525 ty: TypeId,
526 } : [tuple.types.len()] => [1],
527
528 /// Converts a language-specific record-of-bools to a list of `i32`.
529 FlagsLower {
530 flags: &'a Flags,
531 name: &'a str,
532 ty: TypeId,
533 } : [1] => [flags.repr().count()],
534 /// Converts a list of native wasm `i32` to a language-specific
535 /// record-of-bools.
536 FlagsLift {
537 flags: &'a Flags,
538 name: &'a str,
539 ty: TypeId,
540 } : [flags.repr().count()] => [1],
541
542 // variants
543
544 /// This is a special instruction used for `VariantLower`
545 /// instruction to determine the name of the payload, if present, to use
546 /// within each block.
547 ///
548 /// Each sub-block will have this be the first instruction, and if it
549 /// lowers a payload it will expect something bound to this name.
550 VariantPayloadName : [0] => [1],
551
552 /// Pops a variant off the stack as well as `ty.cases.len()` blocks
553 /// from the code generator. Uses each of those blocks and the value
554 /// from the stack to produce `nresults` of items.
555 VariantLower {
556 variant: &'a Variant,
557 name: &'a str,
558 ty: TypeId,
559 results: &'a [WasmType],
560 } : [1] => [results.len()],
561
562 /// Pops an `i32` off the stack as well as `ty.cases.len()` blocks
563 /// from the code generator. Uses each of those blocks and the value
564 /// from the stack to produce a final variant.
565 VariantLift {
566 variant: &'a Variant,
567 name: &'a str,
568 ty: TypeId,
569 } : [1] => [1],
570
571 /// Same as `VariantLower`, except used for unions.
572 UnionLower {
573 union: &'a Union,
574 name: &'a str,
575 ty: TypeId,
576 results: &'a [WasmType],
577 } : [1] => [results.len()],
578
579 /// Same as `VariantLift`, except used for unions.
580 UnionLift {
581 union: &'a Union,
582 name: &'a str,
583 ty: TypeId,
584 } : [1] => [1],
585
586 /// Pops an enum off the stack and pushes the `i32` representation.
587 EnumLower {
588 enum_: &'a Enum,
589 name: &'a str,
590 ty: TypeId,
591 } : [1] => [1],
592
593 /// Pops an `i32` off the stack and lifts it into the `enum` specified.
594 EnumLift {
595 enum_: &'a Enum,
596 name: &'a str,
597 ty: TypeId,
598 } : [1] => [1],
599
600 /// Specialization of `VariantLower` for specifically `option<T>` types,
601 /// otherwise behaves the same as `VariantLower` (e.g. two blocks for
602 /// the two cases.
603 OptionLower {
604 payload: &'a Type,
605 ty: TypeId,
606 results: &'a [WasmType],
607 } : [1] => [results.len()],
608
609 /// Specialization of `VariantLift` for specifically the `option<T>`
610 /// type. Otherwise behaves the same as the `VariantLift` instruction
611 /// with two blocks for the lift.
612 OptionLift {
613 payload: &'a Type,
614 ty: TypeId,
615 } : [1] => [1],
616
617 /// Specialization of `VariantLower` for specifically `expected<T, E>`
618 /// types, otherwise behaves the same as `VariantLower` (e.g. two blocks
619 /// for the two cases.
620 ExpectedLower {
621 expected: &'a Expected,
622 ty: TypeId,
623 results: &'a [WasmType],
624 } : [1] => [results.len()],
625
626 /// Specialization of `VariantLift` for specifically the `expected<T,
627 /// E>` type. Otherwise behaves the same as the `VariantLift`
628 /// instruction with two blocks for the lift.
629 ExpectedLift {
630 expected: &'a Expected,
631 ty: TypeId,
632 } : [1] => [1],
633
634 // calling/control flow
635
636 /// Represents a call to a raw WebAssembly API. The module/name are
637 /// provided inline as well as the types if necessary.
638 ///
639 /// Note that this instruction is not currently used for async
640 /// functions, instead `CallWasmAsyncImport` and `CallWasmAsyncExport`
641 /// are used.
642 CallWasm {
643 iface: &'a Interface,
644 name: &'a str,
645 sig: &'a WasmSignature,
646 } : [sig.params.len()] => [sig.results.len()],
647
648 /// Represents a call to an asynchronous wasm import.
649 ///
650 /// This currently only happens when a compiled-to-wasm module calls as
651 /// async import. This instruction is used to indicate that the
652 /// specified import function should be called. The specified import
653 /// function has `params` as its types, but the final two parameters
654 /// must be synthesized by this instruction which are the
655 /// callback/callback state. The actual imported function does not
656 /// return anything but the callback will be called with the `i32` state
657 /// as the first parameter and `results` as the rest of the parameters.
658 /// The callback function should return nothing.
659 ///
660 /// It's up to the bindings generator to figure out how to make this
661 /// look synchronous despite it being callback-based in the middle.
662 CallWasmAsyncImport {
663 iface: &'a Interface,
664 name: &'a str,
665 params: &'a [WasmType],
666 results: &'a [WasmType],
667 } : [params.len() - 2] => [results.len()],
668
669 /// Represents a call to an asynchronous wasm export.
670 ///
671 /// This currently only happens when a host module calls an async
672 /// function on a wasm module. The specified function will take `params`
673 /// as its argument plus one more argument of an `i32` state that the
674 /// host needs to synthesize. The function being called doesn't actually
675 /// return anything. Instead wasm will call an `async_export_done`
676 /// intrinsic in the `canonical_abi` module. This intrinsic receives a
677 /// context value and a pointer into linear memory. The context value
678 /// lines up with the final `i32` parameter of this function call (which
679 /// the bindings generator must synthesize) and the pointer into linear
680 /// memory contains the `results`, stored at 8-byte offsets in the same
681 /// manner that multiple results are transferred.
682 ///
683 /// It's up to the bindings generator to figure out how to make this
684 /// look synchronous despite it being callback-based in the middle.
685 CallWasmAsyncExport {
686 module: &'a str,
687 name: &'a str,
688 params: &'a [WasmType],
689 results: &'a [WasmType],
690 } : [params.len() - 1] => [results.len()],
691
692 /// Same as `CallWasm`, except the dual where an interface is being
693 /// called rather than a raw wasm function.
694 ///
695 /// Note that this will be used for async functions.
696 CallInterface {
697 module: &'a str,
698 func: &'a Function,
699 } : [func.params.len()] => [1],
700
701 /// Returns `amt` values on the stack. This is always the last
702 /// instruction.
703 ///
704 /// Note that this instruction is used for asynchronous functions where
705 /// the results are *lifted*, not when they're *lowered*, though. For
706 /// those modes the `ReturnAsyncExport` and `ReturnAsyncImport`
707 /// functions are used.
708 Return { amt: usize, func: &'a Function } : [*amt] => [0],
709
710 /// "Returns" from an asynchronous export.
711 ///
712 /// This is only used for compiled-to-wasm modules at this time, and
713 /// only for the exports of async functions in those modules. This
714 /// instruction receives two parameters, the first of which is the
715 /// original context from the start of the function which was provided
716 /// when the export was first called (its last parameter). The second
717 /// argument is a pointer into linear memory with the results of the
718 /// asynchronous call already encoded. This instruction should then call
719 /// the `async_export_done` intrinsic in the `canonical_abi` module.
720 ReturnAsyncExport { func: &'a Function } : [2] => [0],
721
722 /// "Returns" from an asynchronous import.
723 ///
724 /// This is only used for host modules at this time, and
725 /// only for the import of async functions in those modules. This
726 /// instruction receives the operands used to call the completion
727 /// function in the wasm module. The first parameter to this instruction
728 /// is the index into the function table of the function to call, and
729 /// the remaining parameters are the parameters to invoke the function
730 /// with.
731 ReturnAsyncImport {
732 func: &'a Function,
733 params: usize,
734 } : [*params + 2] => [0],
735
736 /// Calls the `realloc` function specified in a malloc-like fashion
737 /// allocating `size` bytes with alignment `align`.
738 ///
739 /// Pushes the returned pointer onto the stack.
740 Malloc {
741 realloc: &'static str,
742 size: usize,
743 align: usize,
744 } : [0] => [1],
745
746 /// Calls the `free` function specified to deallocate the pointer on the
747 /// stack which has `size` bytes with alignment `align`.
748 Free {
749 free: &'static str,
750 size: usize,
751 align: usize,
752 } : [1] => [0],
753 }
754}
755
756#[derive(Debug, PartialEq)]
757pub enum Bitcast {
758 // Upcasts
759 F32ToI32,
760 F64ToI64,
761 I32ToI64,
762 F32ToI64,
763
764 // Downcasts
765 I32ToF32,
766 I64ToF64,
767 I64ToI32,
768 I64ToF32,
769
770 None,
771}
772
773/// Whether the glue code surrounding a call is lifting arguments and lowering
774/// results or vice versa.
775#[derive(Clone, Copy, PartialEq, Eq)]
776pub enum LiftLower {
777 /// When the glue code lifts arguments and lowers results.
778 ///
779 /// ```text
780 /// Wasm --lift-args--> SourceLanguage; call; SourceLanguage --lower-results--> Wasm
781 /// ```
782 LiftArgsLowerResults,
783 /// When the glue code lowers arguments and lifts results.
784 ///
785 /// ```text
786 /// SourceLanguage --lower-args--> Wasm; call; Wasm --lift-results--> SourceLanguage
787 /// ```
788 LowerArgsLiftResults,
789}
790
791/// We use a different ABI for wasm importing functions exported by the host
792/// than for wasm exporting functions imported by the host.
793///
794/// Note that this reflects the flavor of ABI we generate, and not necessarily
795/// the way the resulting bindings will be used by end users. See the comments
796/// on the `Direction` enum in gen-core for details.
797///
798/// The bindings ABI has a concept of a "guest" and a "host". There are two
799/// variants of the ABI, one specialized for the "guest" importing and calling
800/// a function defined and exported in the "host", and the other specialized for
801/// the "host" importing and calling a function defined and exported in the "guest".
802#[derive(Clone, Copy, PartialEq, Eq, Debug)]
803pub enum AbiVariant {
804 /// The guest is importing and calling the function.
805 GuestImport,
806 /// The guest is defining and exporting the function.
807 GuestExport,
808}
809
810/// Trait for language implementors to use to generate glue code between native
811/// WebAssembly signatures and interface types signatures.
812///
813/// This is used as an implementation detail in interpreting the ABI between
814/// interface types and wasm types. Eventually this will be driven by interface
815/// types adapters themselves, but for now the ABI of a function dictates what
816/// instructions are fed in.
817///
818/// Types implementing `Bindgen` are incrementally fed `Instruction` values to
819/// generate code for. Instructions operate like a stack machine where each
820/// instruction has a list of inputs and a list of outputs (provided by the
821/// `emit` function).
822pub trait Bindgen {
823 /// The intermediate type for fragments of code for this type.
824 ///
825 /// For most languages `String` is a suitable intermediate type.
826 type Operand: Clone;
827
828 /// Emit code to implement the given instruction.
829 ///
830 /// Each operand is given in `operands` and can be popped off if ownership
831 /// is required. It's guaranteed that `operands` has the appropriate length
832 /// for the `inst` given, as specified with [`Instruction`].
833 ///
834 /// Each result variable should be pushed onto `results`. This function must
835 /// push the appropriate number of results or binding generation will panic.
836 fn emit(
837 &mut self,
838 iface: &Interface,
839 inst: &Instruction<'_>,
840 operands: &mut Vec<Self::Operand>,
841 results: &mut Vec<Self::Operand>,
842 );
843
844 /// Gets a operand reference to the return pointer area.
845 ///
846 /// The provided size and alignment is for the function's return type.
847 fn return_pointer(&mut self, iface: &Interface, size: usize, align: usize) -> Self::Operand;
848
849 /// Enters a new block of code to generate code for.
850 ///
851 /// This is currently exclusively used for constructing variants. When a
852 /// variant is constructed a block here will be pushed for each case of a
853 /// variant, generating the code necessary to translate a variant case.
854 ///
855 /// Blocks are completed with `finish_block` below. It's expected that `emit`
856 /// will always push code (if necessary) into the "current block", which is
857 /// updated by calling this method and `finish_block` below.
858 fn push_block(&mut self);
859
860 /// Indicates to the code generator that a block is completed, and the
861 /// `operand` specified was the resulting value of the block.
862 ///
863 /// This method will be used to compute the value of each arm of lifting a
864 /// variant. The `operand` will be `None` if the variant case didn't
865 /// actually have any type associated with it. Otherwise it will be `Some`
866 /// as the last value remaining on the stack representing the value
867 /// associated with a variant's `case`.
868 ///
869 /// It's expected that this will resume code generation in the previous
870 /// block before `push_block` was called. This must also save the results
871 /// of the current block internally for instructions like `ResultLift` to
872 /// use later.
873 fn finish_block(&mut self, operand: &mut Vec<Self::Operand>);
874
875 /// Returns size information that was previously calculated for all types.
876 fn sizes(&self) -> &crate::sizealign::SizeAlign;
877
878 /// Returns whether or not the specified element type is represented in a
879 /// "canonical" form for lists. This dictates whether the `ListCanonLower`
880 /// and `ListCanonLift` instructions are used or not.
881 fn is_list_canonical(&self, iface: &Interface, element: &Type) -> bool;
882}
883
884impl Interface {
885 /// Get the WebAssembly type signature for this interface function
886 ///
887 /// The first entry returned is the list of parameters and the second entry
888 /// is the list of results for the wasm function signature.
889 pub fn wasm_signature(&self, variant: AbiVariant, func: &Function) -> WasmSignature {
890 const MAX_FLAT_PARAMS: usize = 16;
891 const MAX_FLAT_RESULTS: usize = 1;
892
893 let mut params = Vec::new();
894 let mut indirect_params = false;
895 for (_, param) in func.params.iter() {
896 self.push_wasm(variant, param, &mut params);
897 }
898
899 if params.len() > MAX_FLAT_PARAMS {
900 params.truncate(0);
901 params.push(WasmType::I32);
902 indirect_params = true;
903 }
904
905 let mut results = Vec::new();
906 self.push_wasm(variant, &func.result, &mut results);
907
908 let mut retptr = false;
909 if func.is_async {
910 // Asynchronous functions never actually return anything since
911 // they're all callback-based, meaning that we always put all the
912 // results into a return pointer.
913 //
914 // Asynchronous exports take one extra parameter which is the
915 // context used to pass to the `async_export_done` intrinsic, and
916 // asynchronous imports take two extra parameters where the first is
917 // a pointer into the function table and the second is a context
918 // argument to pass to this function.
919 match variant {
920 AbiVariant::GuestExport => {
921 retptr = true;
922 results.truncate(0);
923 params.push(WasmType::I32);
924 }
925 AbiVariant::GuestImport => {
926 retptr = true;
927 results.truncate(0);
928 params.push(WasmType::I32);
929 params.push(WasmType::I32);
930 }
931 }
932 } else {
933 // Rust/C don't support multi-value well right now, so if a function
934 // would have multiple results then instead truncate it. Imports take a
935 // return pointer to write into and exports return a pointer they wrote
936 // into.
937 if results.len() > MAX_FLAT_RESULTS {
938 retptr = true;
939 results.truncate(0);
940 match variant {
941 AbiVariant::GuestImport => {
942 params.push(WasmType::I32);
943 }
944 AbiVariant::GuestExport => {
945 results.push(WasmType::I32);
946 }
947 }
948 }
949 }
950
951 WasmSignature {
952 params,
953 indirect_params,
954 results,
955 retptr,
956 }
957 }
958
959 fn push_wasm(&self, variant: AbiVariant, ty: &Type, result: &mut Vec<WasmType>) {
960 match ty {
961 Type::Unit => {}
962
963 Type::Bool
964 | Type::S8
965 | Type::U8
966 | Type::S16
967 | Type::U16
968 | Type::S32
969 | Type::U32
970 | Type::Char
971 | Type::Handle(_) => result.push(WasmType::I32),
972
973 Type::U64 | Type::S64 => result.push(WasmType::I64),
974 Type::Float32 => result.push(WasmType::F32),
975 Type::Float64 => result.push(WasmType::F64),
976 Type::String => {
977 result.push(WasmType::I32);
978 result.push(WasmType::I32);
979 }
980
981 Type::Id(id) => match &self.types[*id].kind {
982 TypeDefKind::Type(t) => self.push_wasm(variant, t, result),
983
984 TypeDefKind::Record(r) => {
985 for field in r.fields.iter() {
986 self.push_wasm(variant, &field.ty, result);
987 }
988 }
989
990 TypeDefKind::Tuple(t) => {
991 for ty in t.types.iter() {
992 self.push_wasm(variant, ty, result);
993 }
994 }
995
996 TypeDefKind::Flags(r) => {
997 for _ in 0..r.repr().count() {
998 result.push(WasmType::I32);
999 }
1000 }
1001
1002 TypeDefKind::List(_) => {
1003 result.push(WasmType::I32);
1004 result.push(WasmType::I32);
1005 }
1006
1007 TypeDefKind::Variant(v) => {
1008 result.push(v.tag().into());
1009 self.push_wasm_variants(variant, v.cases.iter().map(|c| &c.ty), result);
1010 }
1011
1012 TypeDefKind::Enum(e) => result.push(e.tag().into()),
1013
1014 TypeDefKind::Option(t) => {
1015 result.push(WasmType::I32);
1016 self.push_wasm_variants(variant, [&Type::Unit, t], result);
1017 }
1018
1019 TypeDefKind::Expected(e) => {
1020 result.push(WasmType::I32);
1021 self.push_wasm_variants(variant, [&e.ok, &e.err], result);
1022 }
1023
1024 TypeDefKind::Union(u) => {
1025 result.push(WasmType::I32);
1026 self.push_wasm_variants(variant, u.cases.iter().map(|c| &c.ty), result);
1027 }
1028
1029 TypeDefKind::Future(_) => {
1030 result.push(WasmType::I32);
1031 }
1032
1033 TypeDefKind::Stream(_) => {
1034 result.push(WasmType::I32);
1035 }
1036 },
1037 }
1038 }
1039
1040 fn push_wasm_variants<'a>(
1041 &self,
1042 variant: AbiVariant,
1043 tys: impl IntoIterator<Item = &'a Type>,
1044 result: &mut Vec<WasmType>,
1045 ) {
1046 let mut temp = Vec::new();
1047 let start = result.len();
1048
1049 // Push each case's type onto a temporary vector, and then
1050 // merge that vector into our final list starting at
1051 // `start`. Note that this requires some degree of
1052 // "unification" so we can handle things like `Result<i32,
1053 // f32>` where that turns into `[i32 i32]` where the second
1054 // `i32` might be the `f32` bitcasted.
1055 for ty in tys {
1056 self.push_wasm(variant, ty, &mut temp);
1057
1058 for (i, ty) in temp.drain(..).enumerate() {
1059 match result.get_mut(start + i) {
1060 Some(prev) => *prev = join(*prev, ty),
1061 None => result.push(ty),
1062 }
1063 }
1064 }
1065 }
1066
1067 /// Generates an abstract sequence of instructions which represents this
1068 /// function being adapted as an imported function.
1069 ///
1070 /// The instructions here, when executed, will emulate a language with
1071 /// interface types calling the concrete wasm implementation. The parameters
1072 /// for the returned instruction sequence are the language's own
1073 /// interface-types parameters. One instruction in the instruction stream
1074 /// will be a `Call` which represents calling the actual raw wasm function
1075 /// signature.
1076 ///
1077 /// This function is useful, for example, if you're building a language
1078 /// generator for WASI bindings. This will document how to translate
1079 /// language-specific values into the wasm types to call a WASI function,
1080 /// and it will also automatically convert the results of the WASI function
1081 /// back to a language-specific value.
1082 pub fn call(
1083 &self,
1084 variant: AbiVariant,
1085 lift_lower: LiftLower,
1086 func: &Function,
1087 bindgen: &mut impl Bindgen,
1088 ) {
1089 Generator::new(self, variant, lift_lower, bindgen).call(func);
1090 }
1091}
1092
1093struct Generator<'a, B: Bindgen> {
1094 variant: AbiVariant,
1095 lift_lower: LiftLower,
1096 bindgen: &'a mut B,
1097 iface: &'a Interface,
1098 operands: Vec<B::Operand>,
1099 results: Vec<B::Operand>,
1100 stack: Vec<B::Operand>,
1101 return_pointer: Option<B::Operand>,
1102}
1103
1104impl<'a, B: Bindgen> Generator<'a, B> {
1105 fn new(
1106 iface: &'a Interface,
1107 variant: AbiVariant,
1108 lift_lower: LiftLower,
1109 bindgen: &'a mut B,
1110 ) -> Generator<'a, B> {
1111 Generator {
1112 iface,
1113 variant,
1114 lift_lower,
1115 bindgen,
1116 operands: Vec::new(),
1117 results: Vec::new(),
1118 stack: Vec::new(),
1119 return_pointer: None,
1120 }
1121 }
1122
1123 fn call(&mut self, func: &Function) {
1124 let sig = self.iface.wasm_signature(self.variant, func);
1125
1126 match self.lift_lower {
1127 LiftLower::LowerArgsLiftResults => {
1128 if !sig.indirect_params {
1129 // If the parameters for this function aren't indirect
1130 // (there aren't too many) then we simply do a normal lower
1131 // operation for them all.
1132 for (nth, (_, ty)) in func.params.iter().enumerate() {
1133 self.emit(&Instruction::GetArg { nth });
1134 self.lower(ty);
1135 }
1136 } else {
1137 // ... otherwise if parameters are indirect space is
1138 // allocated from them and each argument is lowered
1139 // individually into memory.
1140 let (size, align) = self
1141 .bindgen
1142 .sizes()
1143 .record(func.params.iter().map(|t| &t.1));
1144 let ptr = match self.variant {
1145 // When a wasm module calls an import it will provide
1146 // static space that isn't dynamically allocated.
1147 AbiVariant::GuestImport => {
1148 self.bindgen.return_pointer(self.iface, size, align)
1149 }
1150 // When calling a wasm module from the outside, though,
1151 // malloc needs to be called.
1152 AbiVariant::GuestExport => {
1153 self.emit(&Instruction::Malloc {
1154 realloc: "canonical_abi_realloc",
1155 size,
1156 align,
1157 });
1158 self.stack.pop().unwrap()
1159 }
1160 };
1161 let mut offset = 0usize;
1162 for (nth, (_, ty)) in func.params.iter().enumerate() {
1163 self.emit(&Instruction::GetArg { nth });
1164 offset = align_to(offset, self.bindgen.sizes().align(ty));
1165 self.write_to_memory(ty, ptr.clone(), offset as i32);
1166 offset += self.bindgen.sizes().size(ty);
1167 }
1168
1169 self.stack.push(ptr);
1170 }
1171
1172 if func.is_async {
1173 // We emit custom instructions for async calls since they
1174 // have different parameters synthesized by the bindings
1175 // generator depending on what kind of call is being made.
1176 //
1177 // Note that no return pointer goop happens here because
1178 // that's all done through parameters of callbacks instead.
1179 let mut results = Vec::new();
1180 self.iface
1181 .push_wasm(self.variant, &func.result, &mut results);
1182 match self.variant {
1183 AbiVariant::GuestImport => {
1184 assert_eq!(self.stack.len(), sig.params.len() - 2);
1185 self.emit(&Instruction::CallWasmAsyncImport {
1186 iface: self.iface,
1187 name: &func.name,
1188 params: &sig.params,
1189 results: &results,
1190 });
1191 }
1192 AbiVariant::GuestExport => {
1193 assert_eq!(self.stack.len(), sig.params.len() - 1);
1194 self.emit(&Instruction::CallWasmAsyncExport {
1195 module: &self.iface.name,
1196 name: &func.name,
1197 params: &sig.params,
1198 results: &results,
1199 });
1200 }
1201 }
1202
1203 self.lift(&func.result);
1204 } else {
1205 // If necessary we may need to prepare a return pointer for
1206 // this ABI.
1207 if self.variant == AbiVariant::GuestImport && sig.retptr {
1208 let size = self.bindgen.sizes().size(&func.result);
1209 let align = self.bindgen.sizes().align(&func.result);
1210 let ptr = self.bindgen.return_pointer(self.iface, size, align);
1211 self.return_pointer = Some(ptr.clone());
1212 self.stack.push(ptr);
1213 }
1214
1215 // Now that all the wasm args are prepared we can call the
1216 // actual wasm function.
1217 assert_eq!(self.stack.len(), sig.params.len());
1218 self.emit(&Instruction::CallWasm {
1219 iface: self.iface,
1220 name: &func.name,
1221 sig: &sig,
1222 });
1223
1224 if !sig.retptr {
1225 // With no return pointer in use we can simply lift the
1226 // result of the function from the result of the core
1227 // wasm function.
1228 self.lift(&func.result);
1229 } else {
1230 let ptr = match self.variant {
1231 // imports into guests means it's a wasm module
1232 // calling an imported function. We supplied the
1233 // return poitner as the last argument (saved in
1234 // `self.return_pointer`) so we use that to read
1235 // the result of the function from memory.
1236 AbiVariant::GuestImport => {
1237 assert!(sig.results.len() == 0);
1238 self.return_pointer.take().unwrap()
1239 }
1240
1241 // guest exports means that this is a host
1242 // calling wasm so wasm returned a pointer to where
1243 // the result is stored
1244 AbiVariant::GuestExport => self.stack.pop().unwrap(),
1245 };
1246
1247 self.read_from_memory(&func.result, ptr, 0);
1248 }
1249 }
1250
1251 self.emit(&Instruction::Return { func, amt: 1 });
1252 }
1253 LiftLower::LiftArgsLowerResults => {
1254 if !sig.indirect_params {
1255 // If parameters are not passed indirectly then we lift each
1256 // argument in succession from the component wasm types that
1257 // make-up the type.
1258 let mut offset = 0;
1259 let mut temp = Vec::new();
1260 for (_, ty) in func.params.iter() {
1261 temp.truncate(0);
1262 self.iface.push_wasm(self.variant, ty, &mut temp);
1263 for _ in 0..temp.len() {
1264 self.emit(&Instruction::GetArg { nth: offset });
1265 offset += 1;
1266 }
1267 self.lift(ty);
1268 }
1269 } else {
1270 // ... otherwise argument is read in succession from memory
1271 // where the pointer to the arguments is the first argument
1272 // to the function.
1273 let mut offset = 0usize;
1274 self.emit(&Instruction::GetArg { nth: 0 });
1275 let ptr = self.stack.pop().unwrap();
1276 for (_, ty) in func.params.iter() {
1277 offset = align_to(offset, self.bindgen.sizes().align(ty));
1278 self.read_from_memory(ty, ptr.clone(), offset as i32);
1279 offset += self.bindgen.sizes().size(ty);
1280 }
1281 }
1282
1283 // ... and that allows us to call the interface types function
1284 self.emit(&Instruction::CallInterface {
1285 module: &self.iface.name,
1286 func,
1287 });
1288
1289 // This was dynamically allocated by the caller so after
1290 // it's been read by the guest we need to deallocate it.
1291 if let AbiVariant::GuestExport = self.variant {
1292 if sig.indirect_params {
1293 let (size, align) = self
1294 .bindgen
1295 .sizes()
1296 .record(func.params.iter().map(|t| &t.1));
1297 self.emit(&Instruction::GetArg { nth: 0 });
1298 self.emit(&Instruction::Free {
1299 free: "canonical_abi_free",
1300 size,
1301 align,
1302 });
1303 }
1304 }
1305
1306 if func.is_async {
1307 match self.variant {
1308 // Returning from a guest import means that the
1309 // completion callback needs to be called which is
1310 // currently given the lowered representation of the
1311 // result.
1312 AbiVariant::GuestImport => {
1313 self.lower(&func.result);
1314
1315 let mut tys = Vec::new();
1316 self.iface.push_wasm(self.variant, &func.result, &mut tys);
1317 assert_eq!(self.stack.len(), tys.len());
1318 let operands = mem::take(&mut self.stack);
1319 // function index to call
1320 self.emit(&Instruction::GetArg {
1321 nth: sig.params.len() - 2,
1322 });
1323 // environment for the function
1324 self.emit(&Instruction::GetArg {
1325 nth: sig.params.len() - 1,
1326 });
1327 self.stack.extend(operands);
1328 self.emit(&Instruction::ReturnAsyncImport {
1329 func,
1330 params: tys.len(),
1331 });
1332 }
1333
1334 // Returning from a guest export means that we need to
1335 // invoke the completion intrinsics with where the
1336 // result is stored in linear memory.
1337 AbiVariant::GuestExport => {
1338 let size = self.bindgen.sizes().size(&func.result);
1339 let align = self.bindgen.sizes().align(&func.result);
1340 let ptr = self.bindgen.return_pointer(self.iface, size, align);
1341 self.write_to_memory(&func.result, ptr.clone(), 0);
1342
1343 // Get the caller's context index.
1344 self.emit(&Instruction::GetArg {
1345 nth: sig.params.len() - 1,
1346 });
1347 self.stack.push(ptr);
1348
1349 // This will call the "done" function with the
1350 // context/pointer argument
1351 self.emit(&Instruction::ReturnAsyncExport { func });
1352 }
1353 }
1354 } else {
1355 if !sig.retptr {
1356 // With no return pointer in use we simply lower the
1357 // result and return that directly from the function.
1358 self.lower(&func.result);
1359 } else {
1360 match self.variant {
1361 // When a function is imported to a guest this means
1362 // it's a host providing the implementation of the
1363 // import. The result is stored in the pointer
1364 // specified in the last argument, so we get the
1365 // pointer here and then write the return value into
1366 // it.
1367 AbiVariant::GuestImport => {
1368 self.emit(&Instruction::GetArg {
1369 nth: sig.params.len() - 1,
1370 });
1371 let ptr = self.stack.pop().unwrap();
1372 self.write_to_memory(&func.result, ptr, 0);
1373 }
1374
1375 // For a guest import this is a function defined in
1376 // wasm, so we're returning a pointer where the
1377 // value was stored at. Allocate some space here
1378 // (statically) and then write the result into that
1379 // memory, returning the pointer at the end.
1380 AbiVariant::GuestExport => {
1381 let size = self.bindgen.sizes().size(&func.result);
1382 let align = self.bindgen.sizes().align(&func.result);
1383 let ptr = self.bindgen.return_pointer(self.iface, size, align);
1384 self.write_to_memory(&func.result, ptr.clone(), 0);
1385 self.stack.push(ptr);
1386 }
1387 }
1388 }
1389
1390 self.emit(&Instruction::Return {
1391 func,
1392 amt: sig.results.len(),
1393 });
1394 }
1395 }
1396 }
1397
1398 assert!(
1399 self.stack.is_empty(),
1400 "stack has {} items remaining",
1401 self.stack.len()
1402 );
1403 }
1404
1405 fn emit(&mut self, inst: &Instruction<'_>) {
1406 self.operands.clear();
1407 self.results.clear();
1408
1409 let operands_len = inst.operands_len();
1410 assert!(
1411 self.stack.len() >= operands_len,
1412 "not enough operands on stack for {:?}",
1413 inst
1414 );
1415 self.operands
1416 .extend(self.stack.drain((self.stack.len() - operands_len)..));
1417 self.results.reserve(inst.results_len());
1418
1419 self.bindgen
1420 .emit(self.iface, inst, &mut self.operands, &mut self.results);
1421
1422 assert_eq!(
1423 self.results.len(),
1424 inst.results_len(),
1425 "{:?} expected {} results, got {}",
1426 inst,
1427 inst.results_len(),
1428 self.results.len()
1429 );
1430 self.stack.append(&mut self.results);
1431 }
1432
1433 fn push_block(&mut self) {
1434 self.bindgen.push_block();
1435 }
1436
1437 fn finish_block(&mut self, size: usize) {
1438 self.operands.clear();
1439 assert!(
1440 size <= self.stack.len(),
1441 "not enough operands on stack for finishing block",
1442 );
1443 self.operands
1444 .extend(self.stack.drain((self.stack.len() - size)..));
1445 self.bindgen.finish_block(&mut self.operands);
1446 }
1447
1448 fn lower(&mut self, ty: &Type) {
1449 use Instruction::*;
1450
1451 match *ty {
1452 Type::Unit => self.emit(&UnitLower),
1453 Type::Bool => self.emit(&I32FromBool),
1454 Type::S8 => self.emit(&I32FromS8),
1455 Type::U8 => self.emit(&I32FromU8),
1456 Type::S16 => self.emit(&I32FromS16),
1457 Type::U16 => self.emit(&I32FromU16),
1458 Type::S32 => self.emit(&I32FromS32),
1459 Type::U32 => self.emit(&I32FromU32),
1460 Type::S64 => self.emit(&I64FromS64),
1461 Type::U64 => self.emit(&I64FromU64),
1462 Type::Char => self.emit(&I32FromChar),
1463 Type::Float32 => self.emit(&F32FromFloat32),
1464 Type::Float64 => self.emit(&F64FromFloat64),
1465 Type::Handle(ty) => {
1466 let borrowed = match self.lift_lower {
1467 // This means that a return value is being lowered, which is
1468 // never borrowed.
1469 LiftLower::LiftArgsLowerResults => false,
1470 // There's one of three possible situations we're in:
1471 //
1472 // * The handle is defined by the wasm module itself. This
1473 // is the only actual possible scenario today due to how
1474 // witx is defined. In this situation the handle is owned
1475 // by the host and "proof of ownership" is being offered
1476 // and there's no need to relinquish ownership.
1477 //
1478 // * The handle is defined by the host, and it's passing it
1479 // to a wasm module. This should use an owned conversion.
1480 // This isn't expressible in today's `*.witx` format.
1481 //
1482 // * The handle is defined by neither the host or the wasm
1483 // mdoule. This means that the host is passing a
1484 // capability from another wasm module into this one,
1485 // meaning it's doing so by reference since the host is
1486 // retaining access to its own
1487 //
1488 // Note, again, only the first bullet here is possible
1489 // today, hence the hardcoded `true` value. We'll need to
1490 // refactor `witx` to expose the other possibilities.
1491 LiftLower::LowerArgsLiftResults => true,
1492 };
1493 if borrowed {
1494 self.emit(&I32FromBorrowedHandle { ty });
1495 } else {
1496 self.emit(&I32FromOwnedHandle { ty });
1497 }
1498 }
1499 Type::String => {
1500 let realloc = self.list_realloc();
1501 self.emit(&StringLower { realloc });
1502 }
1503 Type::Id(id) => match &self.iface.types[id].kind {
1504 TypeDefKind::Type(t) => self.lower(t),
1505 TypeDefKind::List(element) => {
1506 let realloc = self.list_realloc();
1507 if self.bindgen.is_list_canonical(self.iface, element) {
1508 self.emit(&ListCanonLower { element, realloc });
1509 } else {
1510 self.push_block();
1511 self.emit(&IterElem { element });
1512 self.emit(&IterBasePointer);
1513 let addr = self.stack.pop().unwrap();
1514 self.write_to_memory(element, addr, 0);
1515 self.finish_block(0);
1516 self.emit(&ListLower { element, realloc });
1517 }
1518 }
1519 TypeDefKind::Record(record) => {
1520 self.emit(&RecordLower {
1521 record,
1522 ty: id,
1523 name: self.iface.types[id].name.as_deref().unwrap(),
1524 });
1525 let values = self
1526 .stack
1527 .drain(self.stack.len() - record.fields.len()..)
1528 .collect::<Vec<_>>();
1529 for (field, value) in record.fields.iter().zip(values) {
1530 self.stack.push(value);
1531 self.lower(&field.ty);
1532 }
1533 }
1534 TypeDefKind::Tuple(tuple) => {
1535 self.emit(&TupleLower { tuple, ty: id });
1536 let values = self
1537 .stack
1538 .drain(self.stack.len() - tuple.types.len()..)
1539 .collect::<Vec<_>>();
1540 for (ty, value) in tuple.types.iter().zip(values) {
1541 self.stack.push(value);
1542 self.lower(ty);
1543 }
1544 }
1545
1546 TypeDefKind::Flags(flags) => {
1547 self.emit(&FlagsLower {
1548 flags,
1549 ty: id,
1550 name: self.iface.types[id].name.as_ref().unwrap(),
1551 });
1552 }
1553
1554 TypeDefKind::Variant(v) => {
1555 let results = self.lower_variant_arms(ty, v.cases.iter().map(|c| &c.ty));
1556 self.emit(&VariantLower {
1557 variant: v,
1558 ty: id,
1559 results: &results,
1560 name: self.iface.types[id].name.as_deref().unwrap(),
1561 });
1562 }
1563 TypeDefKind::Enum(enum_) => {
1564 self.emit(&EnumLower {
1565 enum_,
1566 ty: id,
1567 name: self.iface.types[id].name.as_deref().unwrap(),
1568 });
1569 }
1570 TypeDefKind::Option(t) => {
1571 let results = self.lower_variant_arms(ty, [&Type::Unit, t]);
1572 self.emit(&OptionLower {
1573 payload: t,
1574 ty: id,
1575 results: &results,
1576 });
1577 }
1578 TypeDefKind::Expected(e) => {
1579 let results = self.lower_variant_arms(ty, [&e.ok, &e.err]);
1580 self.emit(&ExpectedLower {
1581 expected: e,
1582 ty: id,
1583 results: &results,
1584 });
1585 }
1586 TypeDefKind::Union(union) => {
1587 let results = self.lower_variant_arms(ty, union.cases.iter().map(|c| &c.ty));
1588 self.emit(&UnionLower {
1589 union,
1590 ty: id,
1591 results: &results,
1592 name: self.iface.types[id].name.as_deref().unwrap(),
1593 });
1594 }
1595 TypeDefKind::Future(_) => todo!("lower future"),
1596 TypeDefKind::Stream(_) => todo!("lower stream"),
1597 },
1598 }
1599 }
1600
1601 fn lower_variant_arms<'b>(
1602 &mut self,
1603 ty: &Type,
1604 cases: impl IntoIterator<Item = &'b Type>,
1605 ) -> Vec<WasmType> {
1606 use Instruction::*;
1607 let mut results = Vec::new();
1608 let mut temp = Vec::new();
1609 let mut casts = Vec::new();
1610 self.iface.push_wasm(self.variant, ty, &mut results);
1611 for (i, ty) in cases.into_iter().enumerate() {
1612 self.push_block();
1613 self.emit(&VariantPayloadName);
1614 let payload_name = self.stack.pop().unwrap();
1615 self.emit(&I32Const { val: i as i32 });
1616 let mut pushed = 1;
1617 // Using the payload of this block we lower the type to
1618 // raw wasm values.
1619 self.stack.push(payload_name.clone());
1620 self.lower(ty);
1621
1622 // Determine the types of all the wasm values we just
1623 // pushed, and record how many. If we pushed too few
1624 // then we'll need to push some zeros after this.
1625 temp.truncate(0);
1626 self.iface.push_wasm(self.variant, ty, &mut temp);
1627 pushed += temp.len();
1628
1629 // For all the types pushed we may need to insert some
1630 // bitcasts. This will go through and cast everything
1631 // to the right type to ensure all blocks produce the
1632 // same set of results.
1633 casts.truncate(0);
1634 for (actual, expected) in temp.iter().zip(&results[1..]) {
1635 casts.push(cast(*actual, *expected));
1636 }
1637 if casts.iter().any(|c| *c != Bitcast::None) {
1638 self.emit(&Bitcasts { casts: &casts });
1639 }
1640
1641 // If we haven't pushed enough items in this block to match
1642 // what other variants are pushing then we need to push
1643 // some zeros.
1644 if pushed < results.len() {
1645 self.emit(&ConstZero {
1646 tys: &results[pushed..],
1647 });
1648 }
1649 self.finish_block(results.len());
1650 }
1651 results
1652 }
1653
1654 fn list_realloc(&self) -> Option<&'static str> {
1655 // Lowering parameters calling a wasm import means
1656 // we don't need to pass ownership, but we pass
1657 // ownership in all other cases.
1658 match (self.variant, self.lift_lower) {
1659 (AbiVariant::GuestImport, LiftLower::LowerArgsLiftResults) => None,
1660 _ => Some("canonical_abi_realloc"),
1661 }
1662 }
1663
1664 /// Note that in general everything in this function is the opposite of the
1665 /// `lower` function above. This is intentional and should be kept this way!
1666 fn lift(&mut self, ty: &Type) {
1667 use Instruction::*;
1668
1669 match *ty {
1670 Type::Unit => self.emit(&UnitLift),
1671 Type::Bool => self.emit(&BoolFromI32),
1672 Type::S8 => self.emit(&S8FromI32),
1673 Type::U8 => self.emit(&U8FromI32),
1674 Type::S16 => self.emit(&S16FromI32),
1675 Type::U16 => self.emit(&U16FromI32),
1676 Type::S32 => self.emit(&S32FromI32),
1677 Type::U32 => self.emit(&U32FromI32),
1678 Type::S64 => self.emit(&S64FromI64),
1679 Type::U64 => self.emit(&U64FromI64),
1680 Type::Char => self.emit(&CharFromI32),
1681 Type::Float32 => self.emit(&Float32FromF32),
1682 Type::Float64 => self.emit(&Float64FromF64),
1683 Type::Handle(ty) => {
1684 // For more information on these values see the comments in
1685 // `lower` above.
1686 let borrowed = match self.lift_lower {
1687 LiftLower::LiftArgsLowerResults => true,
1688 LiftLower::LowerArgsLiftResults => false,
1689 };
1690 if borrowed {
1691 self.emit(&HandleBorrowedFromI32 { ty });
1692 } else {
1693 self.emit(&HandleOwnedFromI32 { ty });
1694 }
1695 }
1696 Type::String => {
1697 let free = self.list_free();
1698 self.emit(&StringLift { free });
1699 }
1700 Type::Id(id) => match &self.iface.types[id].kind {
1701 TypeDefKind::Type(t) => self.lift(t),
1702 TypeDefKind::List(element) => {
1703 let free = self.list_free();
1704 if self.is_char(element) || self.bindgen.is_list_canonical(self.iface, element)
1705 {
1706 self.emit(&ListCanonLift {
1707 element,
1708 free,
1709 ty: id,
1710 });
1711 } else {
1712 self.push_block();
1713 self.emit(&IterBasePointer);
1714 let addr = self.stack.pop().unwrap();
1715 self.read_from_memory(element, addr, 0);
1716 self.finish_block(1);
1717 self.emit(&ListLift {
1718 element,
1719 free,
1720 ty: id,
1721 });
1722 }
1723 }
1724 TypeDefKind::Record(record) => {
1725 let mut temp = Vec::new();
1726 self.iface.push_wasm(self.variant, ty, &mut temp);
1727 let mut args = self
1728 .stack
1729 .drain(self.stack.len() - temp.len()..)
1730 .collect::<Vec<_>>();
1731 for field in record.fields.iter() {
1732 temp.truncate(0);
1733 self.iface.push_wasm(self.variant, &field.ty, &mut temp);
1734 self.stack.extend(args.drain(..temp.len()));
1735 self.lift(&field.ty);
1736 }
1737 self.emit(&RecordLift {
1738 record,
1739 ty: id,
1740 name: self.iface.types[id].name.as_deref().unwrap(),
1741 });
1742 }
1743 TypeDefKind::Tuple(tuple) => {
1744 let mut temp = Vec::new();
1745 self.iface.push_wasm(self.variant, ty, &mut temp);
1746 let mut args = self
1747 .stack
1748 .drain(self.stack.len() - temp.len()..)
1749 .collect::<Vec<_>>();
1750 for ty in tuple.types.iter() {
1751 temp.truncate(0);
1752 self.iface.push_wasm(self.variant, ty, &mut temp);
1753 self.stack.extend(args.drain(..temp.len()));
1754 self.lift(ty);
1755 }
1756 self.emit(&TupleLift { tuple, ty: id });
1757 }
1758 TypeDefKind::Flags(flags) => {
1759 self.emit(&FlagsLift {
1760 flags,
1761 ty: id,
1762 name: self.iface.types[id].name.as_ref().unwrap(),
1763 });
1764 }
1765
1766 TypeDefKind::Variant(v) => {
1767 self.lift_variant_arms(ty, v.cases.iter().map(|c| &c.ty));
1768 self.emit(&VariantLift {
1769 variant: v,
1770 ty: id,
1771 name: self.iface.types[id].name.as_deref().unwrap(),
1772 });
1773 }
1774
1775 TypeDefKind::Enum(enum_) => {
1776 self.emit(&EnumLift {
1777 enum_,
1778 ty: id,
1779 name: self.iface.types[id].name.as_deref().unwrap(),
1780 });
1781 }
1782
1783 TypeDefKind::Option(t) => {
1784 self.lift_variant_arms(ty, [&Type::Unit, t]);
1785 self.emit(&OptionLift { payload: t, ty: id });
1786 }
1787
1788 TypeDefKind::Expected(e) => {
1789 self.lift_variant_arms(ty, [&e.ok, &e.err]);
1790 self.emit(&ExpectedLift {
1791 expected: e,
1792 ty: id,
1793 });
1794 }
1795
1796 TypeDefKind::Union(union) => {
1797 self.lift_variant_arms(ty, union.cases.iter().map(|c| &c.ty));
1798 self.emit(&UnionLift {
1799 union,
1800 ty: id,
1801 name: self.iface.types[id].name.as_deref().unwrap(),
1802 });
1803 }
1804
1805 TypeDefKind::Future(_) => todo!("lift future"),
1806 TypeDefKind::Stream(_) => todo!("lift stream"),
1807 },
1808 }
1809 }
1810
1811 fn lift_variant_arms<'b>(&mut self, ty: &Type, cases: impl IntoIterator<Item = &'b Type>) {
1812 let mut params = Vec::new();
1813 let mut temp = Vec::new();
1814 let mut casts = Vec::new();
1815 self.iface.push_wasm(self.variant, ty, &mut params);
1816 let block_inputs = self
1817 .stack
1818 .drain(self.stack.len() + 1 - params.len()..)
1819 .collect::<Vec<_>>();
1820 for ty in cases {
1821 self.push_block();
1822 // Push only the values we need for this variant onto
1823 // the stack.
1824 temp.truncate(0);
1825 self.iface.push_wasm(self.variant, ty, &mut temp);
1826 self.stack
1827 .extend(block_inputs[..temp.len()].iter().cloned());
1828
1829 // Cast all the types we have on the stack to the actual
1830 // types needed for this variant, if necessary.
1831 casts.truncate(0);
1832 for (actual, expected) in temp.iter().zip(¶ms[1..]) {
1833 casts.push(cast(*expected, *actual));
1834 }
1835 if casts.iter().any(|c| *c != Bitcast::None) {
1836 self.emit(&Instruction::Bitcasts { casts: &casts });
1837 }
1838
1839 // Then recursively lift this variant's payload.
1840 self.lift(ty);
1841 self.finish_block(1);
1842 }
1843 }
1844
1845 fn list_free(&self) -> Option<&'static str> {
1846 // Lifting the arguments of a defined import means that, if
1847 // possible, the caller still retains ownership and we don't
1848 // free anything.
1849 match (self.variant, self.lift_lower) {
1850 (AbiVariant::GuestImport, LiftLower::LiftArgsLowerResults) => None,
1851 _ => Some("canonical_abi_free"),
1852 }
1853 }
1854
1855 fn write_to_memory(&mut self, ty: &Type, addr: B::Operand, offset: i32) {
1856 use Instruction::*;
1857
1858 match *ty {
1859 Type::Unit => self.lower(ty),
1860 // Builtin types need different flavors of storage instructions
1861 // depending on the size of the value written.
1862 Type::Bool | Type::U8 | Type::S8 => {
1863 self.lower_and_emit(ty, addr, &I32Store8 { offset })
1864 }
1865 Type::U16 | Type::S16 => self.lower_and_emit(ty, addr, &I32Store16 { offset }),
1866 Type::U32 | Type::S32 | Type::Handle(_) | Type::Char => {
1867 self.lower_and_emit(ty, addr, &I32Store { offset })
1868 }
1869 Type::U64 | Type::S64 => self.lower_and_emit(ty, addr, &I64Store { offset }),
1870 Type::Float32 => self.lower_and_emit(ty, addr, &F32Store { offset }),
1871 Type::Float64 => self.lower_and_emit(ty, addr, &F64Store { offset }),
1872 Type::String => self.write_list_to_memory(ty, addr, offset),
1873
1874 Type::Id(id) => match &self.iface.types[id].kind {
1875 TypeDefKind::Type(t) => self.write_to_memory(t, addr, offset),
1876 TypeDefKind::List(_) => self.write_list_to_memory(ty, addr, offset),
1877
1878 // Decompose the record into its components and then write all
1879 // the components into memory one-by-one.
1880 TypeDefKind::Record(record) => {
1881 self.emit(&RecordLower {
1882 record,
1883 ty: id,
1884 name: self.iface.types[id].name.as_deref().unwrap(),
1885 });
1886 self.write_fields_to_memory(
1887 &record.fields.iter().map(|f| f.ty).collect::<Vec<_>>(),
1888 addr,
1889 offset,
1890 );
1891 }
1892 TypeDefKind::Tuple(tuple) => {
1893 self.emit(&TupleLower { tuple, ty: id });
1894 self.write_fields_to_memory(&tuple.types, addr, offset);
1895 }
1896
1897 TypeDefKind::Flags(f) => {
1898 self.lower(ty);
1899 match f.repr() {
1900 FlagsRepr::U8 => {
1901 self.stack.push(addr);
1902 self.store_intrepr(offset, Int::U8);
1903 }
1904 FlagsRepr::U16 => {
1905 self.stack.push(addr);
1906 self.store_intrepr(offset, Int::U16);
1907 }
1908 FlagsRepr::U32(n) => {
1909 for i in (0..n).rev() {
1910 self.stack.push(addr.clone());
1911 self.emit(&I32Store {
1912 offset: offset + (i as i32) * 4,
1913 });
1914 }
1915 }
1916 }
1917 }
1918
1919 // Each case will get its own block, and the first item in each
1920 // case is writing the discriminant. After that if we have a
1921 // payload we write the payload after the discriminant, aligned up
1922 // to the type's alignment.
1923 TypeDefKind::Variant(v) => {
1924 self.write_variant_arms_to_memory(
1925 offset,
1926 addr,
1927 v.tag(),
1928 v.cases.iter().map(|c| &c.ty),
1929 );
1930 self.emit(&VariantLower {
1931 variant: v,
1932 ty: id,
1933 results: &[],
1934 name: self.iface.types[id].name.as_deref().unwrap(),
1935 });
1936 }
1937
1938 TypeDefKind::Option(t) => {
1939 self.write_variant_arms_to_memory(offset, addr, Int::U8, [&Type::Unit, t]);
1940 self.emit(&OptionLower {
1941 payload: t,
1942 ty: id,
1943 results: &[],
1944 });
1945 }
1946
1947 TypeDefKind::Expected(e) => {
1948 self.write_variant_arms_to_memory(offset, addr, Int::U8, [&e.ok, &e.err]);
1949 self.emit(&ExpectedLower {
1950 expected: e,
1951 ty: id,
1952 results: &[],
1953 });
1954 }
1955
1956 TypeDefKind::Enum(e) => {
1957 self.lower(ty);
1958 self.stack.push(addr);
1959 self.store_intrepr(offset, e.tag());
1960 }
1961
1962 TypeDefKind::Union(union) => {
1963 self.write_variant_arms_to_memory(
1964 offset,
1965 addr,
1966 union.tag(),
1967 union.cases.iter().map(|c| &c.ty),
1968 );
1969 self.emit(&UnionLower {
1970 union,
1971 ty: id,
1972 results: &[],
1973 name: self.iface.types[id].name.as_deref().unwrap(),
1974 });
1975 }
1976
1977 TypeDefKind::Future(_) => todo!("write future to memory"),
1978 TypeDefKind::Stream(_) => todo!("write stream to memory"),
1979 },
1980 }
1981 }
1982
1983 fn write_variant_arms_to_memory<'b>(
1984 &mut self,
1985 offset: i32,
1986 addr: B::Operand,
1987 tag: Int,
1988 cases: impl IntoIterator<Item = &'b Type> + Clone,
1989 ) {
1990 let payload_offset =
1991 offset + (self.bindgen.sizes().payload_offset(tag, cases.clone()) as i32);
1992 for (i, ty) in cases.into_iter().enumerate() {
1993 self.push_block();
1994 self.emit(&Instruction::VariantPayloadName);
1995 let payload_name = self.stack.pop().unwrap();
1996 self.emit(&Instruction::I32Const { val: i as i32 });
1997 self.stack.push(addr.clone());
1998 self.store_intrepr(offset, tag);
1999 self.stack.push(payload_name.clone());
2000 self.write_to_memory(ty, addr.clone(), payload_offset);
2001 self.finish_block(0);
2002 }
2003 }
2004
2005 fn write_list_to_memory(&mut self, ty: &Type, addr: B::Operand, offset: i32) {
2006 // After lowering the list there's two i32 values on the stack
2007 // which we write into memory, writing the pointer into the low address
2008 // and the length into the high address.
2009 self.lower(ty);
2010 self.stack.push(addr.clone());
2011 self.emit(&Instruction::I32Store { offset: offset + 4 });
2012 self.stack.push(addr);
2013 self.emit(&Instruction::I32Store { offset });
2014 }
2015
2016 fn write_fields_to_memory(&mut self, tys: &[Type], addr: B::Operand, offset: i32) {
2017 let fields = self
2018 .stack
2019 .drain(self.stack.len() - tys.len()..)
2020 .collect::<Vec<_>>();
2021 for ((field_offset, op), ty) in self
2022 .bindgen
2023 .sizes()
2024 .field_offsets(tys.iter())
2025 .into_iter()
2026 .zip(fields)
2027 .zip(tys)
2028 {
2029 self.stack.push(op);
2030 self.write_to_memory(ty, addr.clone(), offset + (field_offset as i32));
2031 }
2032 }
2033
2034 fn lower_and_emit(&mut self, ty: &Type, addr: B::Operand, instr: &Instruction) {
2035 self.lower(ty);
2036 self.stack.push(addr);
2037 self.emit(instr);
2038 }
2039
2040 fn read_from_memory(&mut self, ty: &Type, addr: B::Operand, offset: i32) {
2041 use Instruction::*;
2042
2043 match *ty {
2044 Type::Unit => self.emit(&UnitLift),
2045 Type::Bool => self.emit_and_lift(ty, addr, &I32Load8U { offset }),
2046 Type::U8 => self.emit_and_lift(ty, addr, &I32Load8U { offset }),
2047 Type::S8 => self.emit_and_lift(ty, addr, &I32Load8S { offset }),
2048 Type::U16 => self.emit_and_lift(ty, addr, &I32Load16U { offset }),
2049 Type::S16 => self.emit_and_lift(ty, addr, &I32Load16S { offset }),
2050 Type::U32 | Type::S32 | Type::Char | Type::Handle(_) => {
2051 self.emit_and_lift(ty, addr, &I32Load { offset })
2052 }
2053 Type::U64 | Type::S64 => self.emit_and_lift(ty, addr, &I64Load { offset }),
2054 Type::Float32 => self.emit_and_lift(ty, addr, &F32Load { offset }),
2055 Type::Float64 => self.emit_and_lift(ty, addr, &F64Load { offset }),
2056 Type::String => self.read_list_from_memory(ty, addr, offset),
2057
2058 Type::Id(id) => match &self.iface.types[id].kind {
2059 TypeDefKind::Type(t) => self.read_from_memory(t, addr, offset),
2060
2061 TypeDefKind::List(_) => self.read_list_from_memory(ty, addr, offset),
2062
2063 // Read and lift each field individually, adjusting the offset
2064 // as we go along, then aggregate all the fields into the
2065 // record.
2066 TypeDefKind::Record(record) => {
2067 self.read_fields_from_memory(
2068 &record.fields.iter().map(|f| f.ty).collect::<Vec<_>>(),
2069 addr,
2070 offset,
2071 );
2072 self.emit(&RecordLift {
2073 record,
2074 ty: id,
2075 name: self.iface.types[id].name.as_deref().unwrap(),
2076 });
2077 }
2078 TypeDefKind::Tuple(tuple) => {
2079 self.read_fields_from_memory(&tuple.types, addr, offset);
2080 self.emit(&TupleLift { tuple, ty: id });
2081 }
2082
2083 TypeDefKind::Flags(f) => {
2084 match f.repr() {
2085 FlagsRepr::U8 => {
2086 self.stack.push(addr);
2087 self.load_intrepr(offset, Int::U8);
2088 }
2089 FlagsRepr::U16 => {
2090 self.stack.push(addr);
2091 self.load_intrepr(offset, Int::U16);
2092 }
2093 FlagsRepr::U32(n) => {
2094 for i in 0..n {
2095 self.stack.push(addr.clone());
2096 self.emit(&I32Load {
2097 offset: offset + (i as i32) * 4,
2098 });
2099 }
2100 }
2101 }
2102 self.lift(ty);
2103 }
2104
2105 // Each case will get its own block, and we'll dispatch to the
2106 // right block based on the `i32.load` we initially perform. Each
2107 // individual block is pretty simple and just reads the payload type
2108 // from the corresponding offset if one is available.
2109 TypeDefKind::Variant(variant) => {
2110 self.read_variant_arms_from_memory(
2111 offset,
2112 addr,
2113 variant.tag(),
2114 variant.cases.iter().map(|c| &c.ty),
2115 );
2116 self.emit(&VariantLift {
2117 variant,
2118 ty: id,
2119 name: self.iface.types[id].name.as_deref().unwrap(),
2120 });
2121 }
2122
2123 TypeDefKind::Option(t) => {
2124 self.read_variant_arms_from_memory(offset, addr, Int::U8, [&Type::Unit, t]);
2125 self.emit(&OptionLift { payload: t, ty: id });
2126 }
2127
2128 TypeDefKind::Expected(e) => {
2129 self.read_variant_arms_from_memory(offset, addr, Int::U8, [&e.ok, &e.err]);
2130 self.emit(&ExpectedLift {
2131 expected: e,
2132 ty: id,
2133 });
2134 }
2135
2136 TypeDefKind::Enum(e) => {
2137 self.stack.push(addr.clone());
2138 self.load_intrepr(offset, e.tag());
2139 self.lift(ty);
2140 }
2141
2142 TypeDefKind::Union(union) => {
2143 self.read_variant_arms_from_memory(
2144 offset,
2145 addr,
2146 union.tag(),
2147 union.cases.iter().map(|c| &c.ty),
2148 );
2149 self.emit(&UnionLift {
2150 union,
2151 ty: id,
2152 name: self.iface.types[id].name.as_deref().unwrap(),
2153 });
2154 }
2155
2156 TypeDefKind::Future(_) => todo!("read future from memory"),
2157 TypeDefKind::Stream(_) => todo!("read stream from memory"),
2158 },
2159 }
2160 }
2161
2162 fn read_variant_arms_from_memory<'b>(
2163 &mut self,
2164 offset: i32,
2165 addr: B::Operand,
2166 tag: Int,
2167 cases: impl IntoIterator<Item = &'b Type> + Clone,
2168 ) {
2169 self.stack.push(addr.clone());
2170 self.load_intrepr(offset, tag);
2171 let payload_offset =
2172 offset + (self.bindgen.sizes().payload_offset(tag, cases.clone()) as i32);
2173 for ty in cases {
2174 self.push_block();
2175 self.read_from_memory(ty, addr.clone(), payload_offset);
2176 self.finish_block(1);
2177 }
2178 }
2179
2180 fn read_list_from_memory(&mut self, ty: &Type, addr: B::Operand, offset: i32) {
2181 // Read the pointer/len and then perform the standard lifting
2182 // proceses.
2183 self.stack.push(addr.clone());
2184 self.emit(&Instruction::I32Load { offset });
2185 self.stack.push(addr);
2186 self.emit(&Instruction::I32Load { offset: offset + 4 });
2187 self.lift(ty);
2188 }
2189
2190 fn read_fields_from_memory(&mut self, tys: &[Type], addr: B::Operand, offset: i32) {
2191 for (field_offset, ty) in self.bindgen.sizes().field_offsets(tys).into_iter().zip(tys) {
2192 self.read_from_memory(ty, addr.clone(), offset + (field_offset as i32));
2193 }
2194 }
2195
2196 fn emit_and_lift(&mut self, ty: &Type, addr: B::Operand, instr: &Instruction) {
2197 self.stack.push(addr);
2198 self.emit(instr);
2199 self.lift(ty);
2200 }
2201
2202 fn load_intrepr(&mut self, offset: i32, repr: Int) {
2203 self.emit(&match repr {
2204 Int::U64 => Instruction::I64Load { offset },
2205 Int::U32 => Instruction::I32Load { offset },
2206 Int::U16 => Instruction::I32Load16U { offset },
2207 Int::U8 => Instruction::I32Load8U { offset },
2208 });
2209 }
2210
2211 fn store_intrepr(&mut self, offset: i32, repr: Int) {
2212 self.emit(&match repr {
2213 Int::U64 => Instruction::I64Store { offset },
2214 Int::U32 => Instruction::I32Store { offset },
2215 Int::U16 => Instruction::I32Store16 { offset },
2216 Int::U8 => Instruction::I32Store8 { offset },
2217 });
2218 }
2219
2220 fn is_char(&self, ty: &Type) -> bool {
2221 match ty {
2222 Type::Char => true,
2223 Type::Id(id) => match &self.iface.types[*id].kind {
2224 TypeDefKind::Type(t) => self.is_char(t),
2225 _ => false,
2226 },
2227 _ => false,
2228 }
2229 }
2230}
2231
2232fn cast(from: WasmType, to: WasmType) -> Bitcast {
2233 use WasmType::*;
2234
2235 match (from, to) {
2236 (I32, I32) | (I64, I64) | (F32, F32) | (F64, F64) => Bitcast::None,
2237
2238 (I32, I64) => Bitcast::I32ToI64,
2239 (F32, I32) => Bitcast::F32ToI32,
2240 (F64, I64) => Bitcast::F64ToI64,
2241
2242 (I64, I32) => Bitcast::I64ToI32,
2243 (I32, F32) => Bitcast::I32ToF32,
2244 (I64, F64) => Bitcast::I64ToF64,
2245
2246 (F32, I64) => Bitcast::F32ToI64,
2247 (I64, F32) => Bitcast::I64ToF32,
2248
2249 (F32, F64) | (F64, F32) | (F64, I32) | (I32, F64) => unreachable!(),
2250 }
2251}