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