wasmtime_environ/fact/
trampoline.rs

1//! Low-level compilation of an fused adapter function.
2//!
3//! This module is tasked with the top-level `compile` function which creates a
4//! single WebAssembly function which will perform the steps of the fused
5//! adapter for an `AdapterData` provided. This is the "meat" of compilation
6//! where the validation of the canonical ABI or similar all happens to
7//! translate arguments from one module to another.
8//!
9//! ## Traps and their ordering
10//!
11//! Currently this compiler is pretty "loose" about the ordering of precisely
12//! what trap happens where. The main reason for this is that to core wasm all
13//! traps are the same and for fused adapters if a trap happens no intermediate
14//! side effects are visible (as designed by the canonical ABI itself). For this
15//! it's important to note that some of the precise choices of control flow here
16//! can be somewhat arbitrary, an intentional decision.
17
18use crate::component::{
19    CanonicalAbiInfo, ComponentTypesBuilder, FixedEncoding as FE, FlatType, InterfaceType,
20    StringEncoding, Transcode, TypeEnumIndex, TypeFlagsIndex, TypeListIndex, TypeOptionIndex,
21    TypeRecordIndex, TypeResourceTableIndex, TypeResultIndex, TypeTupleIndex, TypeVariantIndex,
22    VariantInfo, FLAG_MAY_ENTER, FLAG_MAY_LEAVE, MAX_FLAT_PARAMS, MAX_FLAT_RESULTS,
23};
24use crate::fact::signature::Signature;
25use crate::fact::transcode::Transcoder;
26use crate::fact::traps::Trap;
27use crate::fact::{
28    AdapterData, Body, Context, Function, FunctionId, Helper, HelperLocation, HelperType, Module,
29    Options,
30};
31use crate::prelude::*;
32use crate::{FuncIndex, GlobalIndex};
33use std::collections::HashMap;
34use std::mem;
35use std::ops::Range;
36use wasm_encoder::{BlockType, Encode, Instruction, Instruction::*, MemArg, ValType};
37use wasmtime_component_util::{DiscriminantSize, FlagsSize};
38
39const MAX_STRING_BYTE_LENGTH: u32 = 1 << 31;
40const UTF16_TAG: u32 = 1 << 31;
41
42/// This value is arbitrarily chosen and should be fine to change at any time,
43/// it just seemed like a halfway reasonable starting point.
44const INITIAL_FUEL: usize = 1_000;
45
46struct Compiler<'a, 'b> {
47    types: &'a ComponentTypesBuilder,
48    module: &'b mut Module<'a>,
49    result: FunctionId,
50
51    /// The encoded WebAssembly function body so far, not including locals.
52    code: Vec<u8>,
53
54    /// Total number of locals generated so far.
55    nlocals: u32,
56
57    /// Locals partitioned by type which are not currently in use.
58    free_locals: HashMap<ValType, Vec<u32>>,
59
60    /// Metadata about all `unreachable` trap instructions in this function and
61    /// what the trap represents. The offset within `self.code` is recorded as
62    /// well.
63    traps: Vec<(usize, Trap)>,
64
65    /// A heuristic which is intended to limit the size of a generated function
66    /// to a certain maximum to avoid generating arbitrarily large functions.
67    ///
68    /// This fuel counter is decremented each time `translate` is called and
69    /// when fuel is entirely consumed further translations, if necessary, will
70    /// be done through calls to other functions in the module. This is intended
71    /// to be a heuristic to split up the main function into theoretically
72    /// reusable portions.
73    fuel: usize,
74
75    /// Indicates whether an "enter call" should be emitted in the generated
76    /// function with a call to `Resource{Enter,Exit}Call` at the beginning and
77    /// end of the function for tracking of information related to borrowed
78    /// resources.
79    emit_resource_call: bool,
80}
81
82pub(super) fn compile(module: &mut Module<'_>, adapter: &AdapterData) {
83    let lower_sig = module.types.signature(&adapter.lower, Context::Lower);
84    let lift_sig = module.types.signature(&adapter.lift, Context::Lift);
85    let ty = module
86        .core_types
87        .function(&lower_sig.params, &lower_sig.results);
88    let result = module
89        .funcs
90        .push(Function::new(Some(adapter.name.clone()), ty));
91
92    // If this type signature contains any borrowed resources then invocations
93    // of enter/exit call for resource-related metadata tracking must be used.
94    // It shouldn't matter whether the lower/lift signature is used here as both
95    // should return the same answer.
96    let emit_resource_call = module.types.contains_borrow_resource(&adapter.lower);
97    assert_eq!(
98        emit_resource_call,
99        module.types.contains_borrow_resource(&adapter.lift)
100    );
101
102    Compiler {
103        types: module.types,
104        module,
105        code: Vec::new(),
106        nlocals: lower_sig.params.len() as u32,
107        free_locals: HashMap::new(),
108        traps: Vec::new(),
109        result,
110        fuel: INITIAL_FUEL,
111        emit_resource_call,
112    }
113    .compile_adapter(adapter, &lower_sig, &lift_sig)
114}
115
116/// Compiles a helper function as specified by the `Helper` configuration.
117///
118/// This function is invoked when the translation process runs out of fuel for
119/// some prior function which enqueues a helper to get translated later. This
120/// translation function will perform one type translation as specified by
121/// `Helper` which can either be in the stack or memory for each side.
122pub(super) fn compile_helper(module: &mut Module<'_>, result: FunctionId, helper: Helper) {
123    let mut nlocals = 0;
124    let src_flat;
125    let src = match helper.src.loc {
126        // If the source is on the stack then it's specified in the parameters
127        // to the function, so this creates the flattened representation and
128        // then lists those as the locals with appropriate types for the source
129        // values.
130        HelperLocation::Stack => {
131            src_flat = module
132                .types
133                .flatten_types(&helper.src.opts, usize::MAX, [helper.src.ty])
134                .unwrap()
135                .iter()
136                .enumerate()
137                .map(|(i, ty)| (i as u32, *ty))
138                .collect::<Vec<_>>();
139            nlocals += src_flat.len() as u32;
140            Source::Stack(Stack {
141                locals: &src_flat,
142                opts: &helper.src.opts,
143            })
144        }
145        // If the source is in memory then that's just propagated here as the
146        // first local is the pointer to the source.
147        HelperLocation::Memory => {
148            nlocals += 1;
149            Source::Memory(Memory {
150                opts: &helper.src.opts,
151                addr: TempLocal::new(0, helper.src.opts.ptr()),
152                offset: 0,
153            })
154        }
155    };
156    let dst_flat;
157    let dst = match helper.dst.loc {
158        // This is the same as the stack-based source although `Destination` is
159        // configured slightly differently.
160        HelperLocation::Stack => {
161            dst_flat = module
162                .types
163                .flatten_types(&helper.dst.opts, usize::MAX, [helper.dst.ty])
164                .unwrap();
165            Destination::Stack(&dst_flat, &helper.dst.opts)
166        }
167        // This is the same as a memory-based source but note that the address
168        // of the destination is passed as the final parameter to the function.
169        HelperLocation::Memory => {
170            nlocals += 1;
171            Destination::Memory(Memory {
172                opts: &helper.dst.opts,
173                addr: TempLocal::new(nlocals - 1, helper.dst.opts.ptr()),
174                offset: 0,
175            })
176        }
177    };
178    let mut compiler = Compiler {
179        types: module.types,
180        module,
181        code: Vec::new(),
182        nlocals,
183        free_locals: HashMap::new(),
184        traps: Vec::new(),
185        result,
186        fuel: INITIAL_FUEL,
187        // This is a helper function and only the top-level function is
188        // responsible for emitting these intrinsic calls.
189        emit_resource_call: false,
190    };
191    compiler.translate(&helper.src.ty, &src, &helper.dst.ty, &dst);
192    compiler.finish();
193}
194
195/// Possible ways that a interface value is represented in the core wasm
196/// canonical ABI.
197enum Source<'a> {
198    /// This value is stored on the "stack" in wasm locals.
199    ///
200    /// This could mean that it's inline from the parameters to the function or
201    /// that after a function call the results were stored in locals and the
202    /// locals are the inline results.
203    Stack(Stack<'a>),
204
205    /// This value is stored in linear memory described by the `Memory`
206    /// structure.
207    Memory(Memory<'a>),
208}
209
210/// Same as `Source` but for where values are translated into.
211enum Destination<'a> {
212    /// This value is destined for the WebAssembly stack which means that
213    /// results are simply pushed as we go along.
214    ///
215    /// The types listed are the types that are expected to be on the stack at
216    /// the end of translation.
217    Stack(&'a [ValType], &'a Options),
218
219    /// This value is to be placed in linear memory described by `Memory`.
220    Memory(Memory<'a>),
221}
222
223struct Stack<'a> {
224    /// The locals that comprise a particular value.
225    ///
226    /// The length of this list represents the flattened list of types that make
227    /// up the component value. Each list has the index of the local being
228    /// accessed as well as the type of the local itself.
229    locals: &'a [(u32, ValType)],
230    /// The lifting/lowering options for where this stack of values comes from
231    opts: &'a Options,
232}
233
234/// Representation of where a value is going to be stored in linear memory.
235struct Memory<'a> {
236    /// The lifting/lowering options with memory configuration
237    opts: &'a Options,
238    /// The index of the local that contains the base address of where the
239    /// storage is happening.
240    addr: TempLocal,
241    /// A "static" offset that will be baked into wasm instructions for where
242    /// memory loads/stores happen.
243    offset: u32,
244}
245
246impl Compiler<'_, '_> {
247    fn compile_adapter(
248        mut self,
249        adapter: &AdapterData,
250        lower_sig: &Signature,
251        lift_sig: &Signature,
252    ) {
253        // Check the instance flags required for this trampoline.
254        //
255        // This inserts the initial check required by `canon_lower` that the
256        // caller instance can be left and additionally checks the
257        // flags on the callee if necessary whether it can be entered.
258        self.trap_if_not_flag(adapter.lower.flags, FLAG_MAY_LEAVE, Trap::CannotLeave);
259        if adapter.called_as_export {
260            self.trap_if_not_flag(adapter.lift.flags, FLAG_MAY_ENTER, Trap::CannotEnter);
261            self.set_flag(adapter.lift.flags, FLAG_MAY_ENTER, false);
262        } else if self.module.debug {
263            self.assert_not_flag(
264                adapter.lift.flags,
265                FLAG_MAY_ENTER,
266                "may_enter should be unset",
267            );
268        }
269
270        if self.emit_resource_call {
271            let enter = self.module.import_resource_enter_call();
272            self.instruction(Call(enter.as_u32()));
273        }
274
275        // Perform the translation of arguments. Note that `FLAG_MAY_LEAVE` is
276        // cleared around this invocation for the callee as per the
277        // `canon_lift` definition in the spec. Additionally note that the
278        // precise ordering of traps here is not required since internal state
279        // is not visible to either instance and a trap will "lock down" both
280        // instances to no longer be visible. This means that we're free to
281        // reorder lifts/lowers and flags and such as is necessary and
282        // convenient here.
283        //
284        // TODO: if translation doesn't actually call any functions in either
285        // instance then there's no need to set/clear the flag here and that can
286        // be optimized away.
287        self.set_flag(adapter.lift.flags, FLAG_MAY_LEAVE, false);
288        let param_locals = lower_sig
289            .params
290            .iter()
291            .enumerate()
292            .map(|(i, ty)| (i as u32, *ty))
293            .collect::<Vec<_>>();
294        self.translate_params(adapter, &param_locals);
295        self.set_flag(adapter.lift.flags, FLAG_MAY_LEAVE, true);
296
297        // With all the arguments on the stack the actual target function is
298        // now invoked. The core wasm results of the function are then placed
299        // into locals for result translation afterwards.
300        self.instruction(Call(adapter.callee.as_u32()));
301        let mut result_locals = Vec::with_capacity(lift_sig.results.len());
302        let mut temps = Vec::new();
303        for ty in lift_sig.results.iter().rev() {
304            let local = self.local_set_new_tmp(*ty);
305            result_locals.push((local.idx, *ty));
306            temps.push(local);
307        }
308        result_locals.reverse();
309
310        // Like above during the translation of results the caller cannot be
311        // left (as we might invoke things like `realloc`). Again the precise
312        // order of everything doesn't matter since intermediate states cannot
313        // be witnessed, hence the setting of flags here to encapsulate both
314        // liftings and lowerings.
315        //
316        // TODO: like above the management of the `MAY_LEAVE` flag can probably
317        // be elided here for "simple" results.
318        self.set_flag(adapter.lower.flags, FLAG_MAY_LEAVE, false);
319        self.translate_results(adapter, &param_locals, &result_locals);
320        self.set_flag(adapter.lower.flags, FLAG_MAY_LEAVE, true);
321
322        // And finally post-return state is handled here once all results/etc
323        // are all translated.
324        if let Some(func) = adapter.lift.post_return {
325            for (result, _) in result_locals.iter() {
326                self.instruction(LocalGet(*result));
327            }
328            self.instruction(Call(func.as_u32()));
329        }
330        if adapter.called_as_export {
331            self.set_flag(adapter.lift.flags, FLAG_MAY_ENTER, true);
332        }
333
334        for tmp in temps {
335            self.free_temp_local(tmp);
336        }
337
338        if self.emit_resource_call {
339            let exit = self.module.import_resource_exit_call();
340            self.instruction(Call(exit.as_u32()));
341        }
342
343        self.finish()
344    }
345
346    fn translate_params(&mut self, adapter: &AdapterData, param_locals: &[(u32, ValType)]) {
347        let src_tys = self.types[adapter.lower.ty].params;
348        let src_tys = self.types[src_tys]
349            .types
350            .iter()
351            .copied()
352            .collect::<Vec<_>>();
353        let dst_tys = self.types[adapter.lift.ty].params;
354        let dst_tys = self.types[dst_tys]
355            .types
356            .iter()
357            .copied()
358            .collect::<Vec<_>>();
359        let lift_opts = &adapter.lift.options;
360        let lower_opts = &adapter.lower.options;
361
362        // TODO: handle subtyping
363        assert_eq!(src_tys.len(), dst_tys.len());
364
365        let src_flat =
366            self.types
367                .flatten_types(lower_opts, MAX_FLAT_PARAMS, src_tys.iter().copied());
368        let dst_flat =
369            self.types
370                .flatten_types(lift_opts, MAX_FLAT_PARAMS, dst_tys.iter().copied());
371
372        let src = if let Some(flat) = &src_flat {
373            Source::Stack(Stack {
374                locals: &param_locals[..flat.len()],
375                opts: lower_opts,
376            })
377        } else {
378            // If there are too many parameters then that means the parameters
379            // are actually a tuple stored in linear memory addressed by the
380            // first parameter local.
381            let (addr, ty) = param_locals[0];
382            assert_eq!(ty, lower_opts.ptr());
383            let align = src_tys
384                .iter()
385                .map(|t| self.types.align(lower_opts, t))
386                .max()
387                .unwrap_or(1);
388            Source::Memory(self.memory_operand(lower_opts, TempLocal::new(addr, ty), align))
389        };
390
391        let dst = if let Some(flat) = &dst_flat {
392            Destination::Stack(flat, lift_opts)
393        } else {
394            // If there are too many parameters then space is allocated in the
395            // destination module for the parameters via its `realloc` function.
396            let abi = CanonicalAbiInfo::record(dst_tys.iter().map(|t| self.types.canonical_abi(t)));
397            let (size, align) = if lift_opts.memory64 {
398                (abi.size64, abi.align64)
399            } else {
400                (abi.size32, abi.align32)
401            };
402            let size = MallocSize::Const(size);
403            Destination::Memory(self.malloc(lift_opts, size, align))
404        };
405
406        let srcs = src
407            .record_field_srcs(self.types, src_tys.iter().copied())
408            .zip(src_tys.iter());
409        let dsts = dst
410            .record_field_dsts(self.types, dst_tys.iter().copied())
411            .zip(dst_tys.iter());
412        for ((src, src_ty), (dst, dst_ty)) in srcs.zip(dsts) {
413            self.translate(&src_ty, &src, &dst_ty, &dst);
414        }
415
416        // If the destination was linear memory instead of the stack then the
417        // actual parameter that we're passing is the address of the values
418        // stored, so ensure that's happening in the wasm body here.
419        if let Destination::Memory(mem) = dst {
420            self.instruction(LocalGet(mem.addr.idx));
421            self.free_temp_local(mem.addr);
422        }
423    }
424
425    fn translate_results(
426        &mut self,
427        adapter: &AdapterData,
428        param_locals: &[(u32, ValType)],
429        result_locals: &[(u32, ValType)],
430    ) {
431        let src_tys = self.types[adapter.lift.ty].results;
432        let src_tys = self.types[src_tys]
433            .types
434            .iter()
435            .copied()
436            .collect::<Vec<_>>();
437        let dst_tys = self.types[adapter.lower.ty].results;
438        let dst_tys = self.types[dst_tys]
439            .types
440            .iter()
441            .copied()
442            .collect::<Vec<_>>();
443        let lift_opts = &adapter.lift.options;
444        let lower_opts = &adapter.lower.options;
445
446        let src_flat =
447            self.types
448                .flatten_types(lift_opts, MAX_FLAT_RESULTS, src_tys.iter().copied());
449        let dst_flat =
450            self.types
451                .flatten_types(lower_opts, MAX_FLAT_RESULTS, dst_tys.iter().copied());
452
453        let src = if src_flat.is_some() {
454            Source::Stack(Stack {
455                locals: result_locals,
456                opts: lift_opts,
457            })
458        } else {
459            // The original results to read from in this case come from the
460            // return value of the function itself. The imported function will
461            // return a linear memory address at which the values can be read
462            // from.
463            let align = src_tys
464                .iter()
465                .map(|t| self.types.align(lift_opts, t))
466                .max()
467                .unwrap_or(1);
468            assert_eq!(result_locals.len(), 1);
469            let (addr, ty) = result_locals[0];
470            assert_eq!(ty, lift_opts.ptr());
471            Source::Memory(self.memory_operand(lift_opts, TempLocal::new(addr, ty), align))
472        };
473
474        let dst = if let Some(flat) = &dst_flat {
475            Destination::Stack(flat, lower_opts)
476        } else {
477            // This is slightly different than `translate_params` where the
478            // return pointer was provided by the caller of this function
479            // meaning the last parameter local is a pointer into linear memory.
480            let align = dst_tys
481                .iter()
482                .map(|t| self.types.align(lower_opts, t))
483                .max()
484                .unwrap_or(1);
485            let (addr, ty) = *param_locals.last().expect("no retptr");
486            assert_eq!(ty, lower_opts.ptr());
487            Destination::Memory(self.memory_operand(lower_opts, TempLocal::new(addr, ty), align))
488        };
489
490        let srcs = src
491            .record_field_srcs(self.types, src_tys.iter().copied())
492            .zip(src_tys.iter());
493        let dsts = dst
494            .record_field_dsts(self.types, dst_tys.iter().copied())
495            .zip(dst_tys.iter());
496        for ((src, src_ty), (dst, dst_ty)) in srcs.zip(dsts) {
497            self.translate(&src_ty, &src, &dst_ty, &dst);
498        }
499    }
500
501    fn translate(
502        &mut self,
503        src_ty: &InterfaceType,
504        src: &Source<'_>,
505        dst_ty: &InterfaceType,
506        dst: &Destination,
507    ) {
508        if let Source::Memory(mem) = src {
509            self.assert_aligned(src_ty, mem);
510        }
511        if let Destination::Memory(mem) = dst {
512            self.assert_aligned(dst_ty, mem);
513        }
514
515        // Calculate a cost heuristic for what the translation of this specific
516        // layer of the type is going to incur. The purpose of this cost is that
517        // we'll deduct it from `self.fuel` and if no fuel is remaining then
518        // translation is outlined into a separate function rather than being
519        // translated into this function.
520        //
521        // The general goal is to avoid creating an exponentially sized function
522        // for a linearly sized input (the type section). By outlining helper
523        // functions there will ideally be a constant set of helper functions
524        // per type (to accommodate in-memory or on-stack transfers as well as
525        // src/dst options) which means that each function is at most a certain
526        // size and we have a linear number of functions which should guarantee
527        // an overall linear size of the output.
528        //
529        // To implement this the current heuristic is that each layer of
530        // translating a type has a cost associated with it and this cost is
531        // accounted for in `self.fuel`. Some conversions are considered free as
532        // they generate basically as much code as the `call` to the translation
533        // function while other are considered proportionally expensive to the
534        // size of the type. The hope is that some upper layers are of a type's
535        // translation are all inlined into one function but bottom layers end
536        // up getting outlined to separate functions. Theoretically, again this
537        // is built on hopes and dreams, the outlining can be shared amongst
538        // tightly-intertwined type hierarchies which will reduce the size of
539        // the output module due to the helpers being used.
540        //
541        // This heuristic of how to split functions has changed a few times in
542        // the past and this isn't necessarily guaranteed to be the final
543        // iteration.
544        let cost = match src_ty {
545            // These types are all quite simple to load/store and equate to
546            // basically the same cost of the `call` instruction to call an
547            // out-of-line translation function, so give them 0 cost.
548            InterfaceType::Bool
549            | InterfaceType::U8
550            | InterfaceType::S8
551            | InterfaceType::U16
552            | InterfaceType::S16
553            | InterfaceType::U32
554            | InterfaceType::S32
555            | InterfaceType::U64
556            | InterfaceType::S64
557            | InterfaceType::Float32
558            | InterfaceType::Float64 => 0,
559
560            // This has a small amount of validation associated with it, so
561            // give it a cost of 1.
562            InterfaceType::Char => 1,
563
564            // This has a fair bit of code behind it depending on the
565            // strings/encodings in play, so arbitrarily assign it this cost.
566            InterfaceType::String => 40,
567
568            // Iteration of a loop is along the lines of the cost of a string
569            // so give it the same cost
570            InterfaceType::List(_) => 40,
571
572            InterfaceType::Flags(i) => {
573                let count = self.module.types[*i].names.len();
574                match FlagsSize::from_count(count) {
575                    FlagsSize::Size0 => 0,
576                    FlagsSize::Size1 | FlagsSize::Size2 => 1,
577                    FlagsSize::Size4Plus(n) => n.into(),
578                }
579            }
580
581            InterfaceType::Record(i) => self.types[*i].fields.len(),
582            InterfaceType::Tuple(i) => self.types[*i].types.len(),
583            InterfaceType::Variant(i) => self.types[*i].cases.len(),
584            InterfaceType::Enum(i) => self.types[*i].names.len(),
585
586            // 2 cases to consider for each of these variants.
587            InterfaceType::Option(_) | InterfaceType::Result(_) => 2,
588
589            // TODO(#6696) - something nonzero, is 1 right?
590            InterfaceType::Own(_) | InterfaceType::Borrow(_) => 1,
591        };
592
593        match self.fuel.checked_sub(cost) {
594            // This function has enough fuel to perform the layer of translation
595            // necessary for this type, so the fuel is updated in-place and
596            // translation continues. Note that the recursion here is bounded by
597            // the static recursion limit for all interface types as imposed
598            // during the translation phase.
599            Some(n) => {
600                self.fuel = n;
601                match src_ty {
602                    InterfaceType::Bool => self.translate_bool(src, dst_ty, dst),
603                    InterfaceType::U8 => self.translate_u8(src, dst_ty, dst),
604                    InterfaceType::S8 => self.translate_s8(src, dst_ty, dst),
605                    InterfaceType::U16 => self.translate_u16(src, dst_ty, dst),
606                    InterfaceType::S16 => self.translate_s16(src, dst_ty, dst),
607                    InterfaceType::U32 => self.translate_u32(src, dst_ty, dst),
608                    InterfaceType::S32 => self.translate_s32(src, dst_ty, dst),
609                    InterfaceType::U64 => self.translate_u64(src, dst_ty, dst),
610                    InterfaceType::S64 => self.translate_s64(src, dst_ty, dst),
611                    InterfaceType::Float32 => self.translate_f32(src, dst_ty, dst),
612                    InterfaceType::Float64 => self.translate_f64(src, dst_ty, dst),
613                    InterfaceType::Char => self.translate_char(src, dst_ty, dst),
614                    InterfaceType::String => self.translate_string(src, dst_ty, dst),
615                    InterfaceType::List(t) => self.translate_list(*t, src, dst_ty, dst),
616                    InterfaceType::Record(t) => self.translate_record(*t, src, dst_ty, dst),
617                    InterfaceType::Flags(f) => self.translate_flags(*f, src, dst_ty, dst),
618                    InterfaceType::Tuple(t) => self.translate_tuple(*t, src, dst_ty, dst),
619                    InterfaceType::Variant(v) => self.translate_variant(*v, src, dst_ty, dst),
620                    InterfaceType::Enum(t) => self.translate_enum(*t, src, dst_ty, dst),
621                    InterfaceType::Option(t) => self.translate_option(*t, src, dst_ty, dst),
622                    InterfaceType::Result(t) => self.translate_result(*t, src, dst_ty, dst),
623                    InterfaceType::Own(t) => self.translate_own(*t, src, dst_ty, dst),
624                    InterfaceType::Borrow(t) => self.translate_borrow(*t, src, dst_ty, dst),
625                }
626            }
627
628            // This function does not have enough fuel left to perform this
629            // layer of translation so the translation is deferred to a helper
630            // function. The actual translation here is then done by marshalling
631            // the src/dst into the function we're calling and then processing
632            // the results.
633            None => {
634                let src_loc = match src {
635                    // If the source is on the stack then `stack_get` is used to
636                    // convert everything to the appropriate flat representation
637                    // for the source type.
638                    Source::Stack(stack) => {
639                        for (i, ty) in stack
640                            .opts
641                            .flat_types(src_ty, self.types)
642                            .unwrap()
643                            .iter()
644                            .enumerate()
645                        {
646                            let stack = stack.slice(i..i + 1);
647                            self.stack_get(&stack, (*ty).into());
648                        }
649                        HelperLocation::Stack
650                    }
651                    // If the source is in memory then the pointer is passed
652                    // through, but note that the offset must be factored in
653                    // here since the translation function will start from
654                    // offset 0.
655                    Source::Memory(mem) => {
656                        self.push_mem_addr(mem);
657                        HelperLocation::Memory
658                    }
659                };
660                let dst_loc = match dst {
661                    Destination::Stack(..) => HelperLocation::Stack,
662                    Destination::Memory(mem) => {
663                        self.push_mem_addr(mem);
664                        HelperLocation::Memory
665                    }
666                };
667                // Generate a `FunctionId` corresponding to the `Helper`
668                // configuration that is necessary here. This will ideally be a
669                // "cache hit" and use a preexisting helper which represents
670                // outlining what would otherwise be duplicate code within a
671                // function to one function.
672                let helper = self.module.translate_helper(Helper {
673                    src: HelperType {
674                        ty: *src_ty,
675                        opts: *src.opts(),
676                        loc: src_loc,
677                    },
678                    dst: HelperType {
679                        ty: *dst_ty,
680                        opts: *dst.opts(),
681                        loc: dst_loc,
682                    },
683                });
684                // Emit a `call` instruction which will get "relocated" to a
685                // function index once translation has completely finished.
686                self.flush_code();
687                self.module.funcs[self.result].body.push(Body::Call(helper));
688
689                // If the destination of the translation was on the stack then
690                // the types on the stack need to be optionally converted to
691                // different types (e.g. if the result here is part of a variant
692                // somewhere else).
693                //
694                // This translation happens inline here by popping the results
695                // into new locals and then using those locals to do a
696                // `stack_set`.
697                if let Destination::Stack(tys, opts) = dst {
698                    let flat = self
699                        .types
700                        .flatten_types(opts, usize::MAX, [*dst_ty])
701                        .unwrap();
702                    assert_eq!(flat.len(), tys.len());
703                    let locals = flat
704                        .iter()
705                        .rev()
706                        .map(|ty| self.local_set_new_tmp(*ty))
707                        .collect::<Vec<_>>();
708                    for (ty, local) in tys.iter().zip(locals.into_iter().rev()) {
709                        self.instruction(LocalGet(local.idx));
710                        self.stack_set(std::slice::from_ref(ty), local.ty);
711                        self.free_temp_local(local);
712                    }
713                }
714            }
715        }
716    }
717
718    fn push_mem_addr(&mut self, mem: &Memory<'_>) {
719        self.instruction(LocalGet(mem.addr.idx));
720        if mem.offset != 0 {
721            self.ptr_uconst(mem.opts, mem.offset);
722            self.ptr_add(mem.opts);
723        }
724    }
725
726    fn translate_bool(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
727        // TODO: subtyping
728        assert!(matches!(dst_ty, InterfaceType::Bool));
729        self.push_dst_addr(dst);
730
731        // Booleans are canonicalized to 0 or 1 as they pass through the
732        // component boundary, so use a `select` instruction to do so.
733        self.instruction(I32Const(1));
734        self.instruction(I32Const(0));
735        match src {
736            Source::Memory(mem) => self.i32_load8u(mem),
737            Source::Stack(stack) => self.stack_get(stack, ValType::I32),
738        }
739        self.instruction(Select);
740
741        match dst {
742            Destination::Memory(mem) => self.i32_store8(mem),
743            Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
744        }
745    }
746
747    fn translate_u8(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
748        // TODO: subtyping
749        assert!(matches!(dst_ty, InterfaceType::U8));
750        self.convert_u8_mask(src, dst, 0xff);
751    }
752
753    fn convert_u8_mask(&mut self, src: &Source<'_>, dst: &Destination<'_>, mask: u8) {
754        self.push_dst_addr(dst);
755        let mut needs_mask = true;
756        match src {
757            Source::Memory(mem) => {
758                self.i32_load8u(mem);
759                needs_mask = mask != 0xff;
760            }
761            Source::Stack(stack) => {
762                self.stack_get(stack, ValType::I32);
763            }
764        }
765        if needs_mask {
766            self.instruction(I32Const(i32::from(mask)));
767            self.instruction(I32And);
768        }
769        match dst {
770            Destination::Memory(mem) => self.i32_store8(mem),
771            Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
772        }
773    }
774
775    fn translate_s8(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
776        // TODO: subtyping
777        assert!(matches!(dst_ty, InterfaceType::S8));
778        self.push_dst_addr(dst);
779        match src {
780            Source::Memory(mem) => self.i32_load8s(mem),
781            Source::Stack(stack) => {
782                self.stack_get(stack, ValType::I32);
783                self.instruction(I32Extend8S);
784            }
785        }
786        match dst {
787            Destination::Memory(mem) => self.i32_store8(mem),
788            Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
789        }
790    }
791
792    fn translate_u16(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
793        // TODO: subtyping
794        assert!(matches!(dst_ty, InterfaceType::U16));
795        self.convert_u16_mask(src, dst, 0xffff);
796    }
797
798    fn convert_u16_mask(&mut self, src: &Source<'_>, dst: &Destination<'_>, mask: u16) {
799        self.push_dst_addr(dst);
800        let mut needs_mask = true;
801        match src {
802            Source::Memory(mem) => {
803                self.i32_load16u(mem);
804                needs_mask = mask != 0xffff;
805            }
806            Source::Stack(stack) => {
807                self.stack_get(stack, ValType::I32);
808            }
809        }
810        if needs_mask {
811            self.instruction(I32Const(i32::from(mask)));
812            self.instruction(I32And);
813        }
814        match dst {
815            Destination::Memory(mem) => self.i32_store16(mem),
816            Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
817        }
818    }
819
820    fn translate_s16(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
821        // TODO: subtyping
822        assert!(matches!(dst_ty, InterfaceType::S16));
823        self.push_dst_addr(dst);
824        match src {
825            Source::Memory(mem) => self.i32_load16s(mem),
826            Source::Stack(stack) => {
827                self.stack_get(stack, ValType::I32);
828                self.instruction(I32Extend16S);
829            }
830        }
831        match dst {
832            Destination::Memory(mem) => self.i32_store16(mem),
833            Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
834        }
835    }
836
837    fn translate_u32(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
838        // TODO: subtyping
839        assert!(matches!(dst_ty, InterfaceType::U32));
840        self.convert_u32_mask(src, dst, 0xffffffff)
841    }
842
843    fn convert_u32_mask(&mut self, src: &Source<'_>, dst: &Destination<'_>, mask: u32) {
844        self.push_dst_addr(dst);
845        match src {
846            Source::Memory(mem) => self.i32_load(mem),
847            Source::Stack(stack) => self.stack_get(stack, ValType::I32),
848        }
849        if mask != 0xffffffff {
850            self.instruction(I32Const(mask as i32));
851            self.instruction(I32And);
852        }
853        match dst {
854            Destination::Memory(mem) => self.i32_store(mem),
855            Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
856        }
857    }
858
859    fn translate_s32(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
860        // TODO: subtyping
861        assert!(matches!(dst_ty, InterfaceType::S32));
862        self.push_dst_addr(dst);
863        match src {
864            Source::Memory(mem) => self.i32_load(mem),
865            Source::Stack(stack) => self.stack_get(stack, ValType::I32),
866        }
867        match dst {
868            Destination::Memory(mem) => self.i32_store(mem),
869            Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
870        }
871    }
872
873    fn translate_u64(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
874        // TODO: subtyping
875        assert!(matches!(dst_ty, InterfaceType::U64));
876        self.push_dst_addr(dst);
877        match src {
878            Source::Memory(mem) => self.i64_load(mem),
879            Source::Stack(stack) => self.stack_get(stack, ValType::I64),
880        }
881        match dst {
882            Destination::Memory(mem) => self.i64_store(mem),
883            Destination::Stack(stack, _) => self.stack_set(stack, ValType::I64),
884        }
885    }
886
887    fn translate_s64(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
888        // TODO: subtyping
889        assert!(matches!(dst_ty, InterfaceType::S64));
890        self.push_dst_addr(dst);
891        match src {
892            Source::Memory(mem) => self.i64_load(mem),
893            Source::Stack(stack) => self.stack_get(stack, ValType::I64),
894        }
895        match dst {
896            Destination::Memory(mem) => self.i64_store(mem),
897            Destination::Stack(stack, _) => self.stack_set(stack, ValType::I64),
898        }
899    }
900
901    fn translate_f32(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
902        // TODO: subtyping
903        assert!(matches!(dst_ty, InterfaceType::Float32));
904        self.push_dst_addr(dst);
905        match src {
906            Source::Memory(mem) => self.f32_load(mem),
907            Source::Stack(stack) => self.stack_get(stack, ValType::F32),
908        }
909        match dst {
910            Destination::Memory(mem) => self.f32_store(mem),
911            Destination::Stack(stack, _) => self.stack_set(stack, ValType::F32),
912        }
913    }
914
915    fn translate_f64(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
916        // TODO: subtyping
917        assert!(matches!(dst_ty, InterfaceType::Float64));
918        self.push_dst_addr(dst);
919        match src {
920            Source::Memory(mem) => self.f64_load(mem),
921            Source::Stack(stack) => self.stack_get(stack, ValType::F64),
922        }
923        match dst {
924            Destination::Memory(mem) => self.f64_store(mem),
925            Destination::Stack(stack, _) => self.stack_set(stack, ValType::F64),
926        }
927    }
928
929    fn translate_char(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
930        assert!(matches!(dst_ty, InterfaceType::Char));
931        match src {
932            Source::Memory(mem) => self.i32_load(mem),
933            Source::Stack(stack) => self.stack_get(stack, ValType::I32),
934        }
935        let local = self.local_set_new_tmp(ValType::I32);
936
937        // This sequence is copied from the output of LLVM for:
938        //
939        //      pub extern "C" fn foo(x: u32) -> char {
940        //          char::try_from(x)
941        //              .unwrap_or_else(|_| std::arch::wasm32::unreachable())
942        //      }
943        //
944        // Apparently this does what's required by the canonical ABI:
945        //
946        //    def i32_to_char(opts, i):
947        //      trap_if(i >= 0x110000)
948        //      trap_if(0xD800 <= i <= 0xDFFF)
949        //      return chr(i)
950        //
951        // ... but I don't know how it works other than "well I trust LLVM"
952        self.instruction(Block(BlockType::Empty));
953        self.instruction(Block(BlockType::Empty));
954        self.instruction(LocalGet(local.idx));
955        self.instruction(I32Const(0xd800));
956        self.instruction(I32Xor);
957        self.instruction(I32Const(-0x110000));
958        self.instruction(I32Add);
959        self.instruction(I32Const(-0x10f800));
960        self.instruction(I32LtU);
961        self.instruction(BrIf(0));
962        self.instruction(LocalGet(local.idx));
963        self.instruction(I32Const(0x110000));
964        self.instruction(I32Ne);
965        self.instruction(BrIf(1));
966        self.instruction(End);
967        self.trap(Trap::InvalidChar);
968        self.instruction(End);
969
970        self.push_dst_addr(dst);
971        self.instruction(LocalGet(local.idx));
972        match dst {
973            Destination::Memory(mem) => {
974                self.i32_store(mem);
975            }
976            Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
977        }
978
979        self.free_temp_local(local);
980    }
981
982    fn translate_string(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
983        assert!(matches!(dst_ty, InterfaceType::String));
984        let src_opts = src.opts();
985        let dst_opts = dst.opts();
986
987        // Load the pointer/length of this string into temporary locals. These
988        // will be referenced a good deal so this just makes it easier to deal
989        // with them consistently below rather than trying to reload from memory
990        // for example.
991        match src {
992            Source::Stack(s) => {
993                assert_eq!(s.locals.len(), 2);
994                self.stack_get(&s.slice(0..1), src_opts.ptr());
995                self.stack_get(&s.slice(1..2), src_opts.ptr());
996            }
997            Source::Memory(mem) => {
998                self.ptr_load(mem);
999                self.ptr_load(&mem.bump(src_opts.ptr_size().into()));
1000            }
1001        }
1002        let src_len = self.local_set_new_tmp(src_opts.ptr());
1003        let src_ptr = self.local_set_new_tmp(src_opts.ptr());
1004        let src_str = WasmString {
1005            ptr: src_ptr,
1006            len: src_len,
1007            opts: src_opts,
1008        };
1009
1010        let dst_str = match src_opts.string_encoding {
1011            StringEncoding::Utf8 => match dst_opts.string_encoding {
1012                StringEncoding::Utf8 => self.string_copy(&src_str, FE::Utf8, dst_opts, FE::Utf8),
1013                StringEncoding::Utf16 => self.string_utf8_to_utf16(&src_str, dst_opts),
1014                StringEncoding::CompactUtf16 => {
1015                    self.string_to_compact(&src_str, FE::Utf8, dst_opts)
1016                }
1017            },
1018
1019            StringEncoding::Utf16 => {
1020                self.verify_aligned(src_opts, src_str.ptr.idx, 2);
1021                match dst_opts.string_encoding {
1022                    StringEncoding::Utf8 => {
1023                        self.string_deflate_to_utf8(&src_str, FE::Utf16, dst_opts)
1024                    }
1025                    StringEncoding::Utf16 => {
1026                        self.string_copy(&src_str, FE::Utf16, dst_opts, FE::Utf16)
1027                    }
1028                    StringEncoding::CompactUtf16 => {
1029                        self.string_to_compact(&src_str, FE::Utf16, dst_opts)
1030                    }
1031                }
1032            }
1033
1034            StringEncoding::CompactUtf16 => {
1035                self.verify_aligned(src_opts, src_str.ptr.idx, 2);
1036
1037                // Test the tag big to see if this is a utf16 or a latin1 string
1038                // at runtime...
1039                self.instruction(LocalGet(src_str.len.idx));
1040                self.ptr_uconst(src_opts, UTF16_TAG);
1041                self.ptr_and(src_opts);
1042                self.ptr_if(src_opts, BlockType::Empty);
1043
1044                // In the utf16 block unset the upper bit from the length local
1045                // so further calculations have the right value. Afterwards the
1046                // string transcode proceeds assuming utf16.
1047                self.instruction(LocalGet(src_str.len.idx));
1048                self.ptr_uconst(src_opts, UTF16_TAG);
1049                self.ptr_xor(src_opts);
1050                self.instruction(LocalSet(src_str.len.idx));
1051                let s1 = match dst_opts.string_encoding {
1052                    StringEncoding::Utf8 => {
1053                        self.string_deflate_to_utf8(&src_str, FE::Utf16, dst_opts)
1054                    }
1055                    StringEncoding::Utf16 => {
1056                        self.string_copy(&src_str, FE::Utf16, dst_opts, FE::Utf16)
1057                    }
1058                    StringEncoding::CompactUtf16 => {
1059                        self.string_compact_utf16_to_compact(&src_str, dst_opts)
1060                    }
1061                };
1062
1063                self.instruction(Else);
1064
1065                // In the latin1 block the `src_len` local is already the number
1066                // of code units, so the string transcoding is all that needs to
1067                // happen.
1068                let s2 = match dst_opts.string_encoding {
1069                    StringEncoding::Utf16 => {
1070                        self.string_copy(&src_str, FE::Latin1, dst_opts, FE::Utf16)
1071                    }
1072                    StringEncoding::Utf8 => {
1073                        self.string_deflate_to_utf8(&src_str, FE::Latin1, dst_opts)
1074                    }
1075                    StringEncoding::CompactUtf16 => {
1076                        self.string_copy(&src_str, FE::Latin1, dst_opts, FE::Latin1)
1077                    }
1078                };
1079                // Set our `s2` generated locals to the `s2` generated locals
1080                // as the resulting pointer of this transcode.
1081                self.instruction(LocalGet(s2.ptr.idx));
1082                self.instruction(LocalSet(s1.ptr.idx));
1083                self.instruction(LocalGet(s2.len.idx));
1084                self.instruction(LocalSet(s1.len.idx));
1085                self.instruction(End);
1086                self.free_temp_local(s2.ptr);
1087                self.free_temp_local(s2.len);
1088                s1
1089            }
1090        };
1091
1092        // Store the ptr/length in the desired destination
1093        match dst {
1094            Destination::Stack(s, _) => {
1095                self.instruction(LocalGet(dst_str.ptr.idx));
1096                self.stack_set(&s[..1], dst_opts.ptr());
1097                self.instruction(LocalGet(dst_str.len.idx));
1098                self.stack_set(&s[1..], dst_opts.ptr());
1099            }
1100            Destination::Memory(mem) => {
1101                self.instruction(LocalGet(mem.addr.idx));
1102                self.instruction(LocalGet(dst_str.ptr.idx));
1103                self.ptr_store(mem);
1104                self.instruction(LocalGet(mem.addr.idx));
1105                self.instruction(LocalGet(dst_str.len.idx));
1106                self.ptr_store(&mem.bump(dst_opts.ptr_size().into()));
1107            }
1108        }
1109
1110        self.free_temp_local(src_str.ptr);
1111        self.free_temp_local(src_str.len);
1112        self.free_temp_local(dst_str.ptr);
1113        self.free_temp_local(dst_str.len);
1114    }
1115
1116    // Corresponding function for `store_string_copy` in the spec.
1117    //
1118    // This performs a transcoding of the string with a one-pass copy from
1119    // the `src` encoding to the `dst` encoding. This is only possible for
1120    // fixed encodings where the first allocation is guaranteed to be an
1121    // appropriate fit so it's not suitable for all encodings.
1122    //
1123    // Imported host transcoding functions here take the src/dst pointers as
1124    // well as the number of code units in the source (which always matches
1125    // the number of code units in the destination). There is no return
1126    // value from the transcode function since the encoding should always
1127    // work on the first pass.
1128    fn string_copy<'a>(
1129        &mut self,
1130        src: &WasmString<'_>,
1131        src_enc: FE,
1132        dst_opts: &'a Options,
1133        dst_enc: FE,
1134    ) -> WasmString<'a> {
1135        assert!(dst_enc.width() >= src_enc.width());
1136        self.validate_string_length(src, dst_enc);
1137
1138        // Calculate the source byte length given the size of each code
1139        // unit. Note that this shouldn't overflow given
1140        // `validate_string_length` above.
1141        let mut src_byte_len_tmp = None;
1142        let src_byte_len = if src_enc.width() == 1 {
1143            src.len.idx
1144        } else {
1145            assert_eq!(src_enc.width(), 2);
1146            self.instruction(LocalGet(src.len.idx));
1147            self.ptr_uconst(src.opts, 1);
1148            self.ptr_shl(src.opts);
1149            let tmp = self.local_set_new_tmp(src.opts.ptr());
1150            let ret = tmp.idx;
1151            src_byte_len_tmp = Some(tmp);
1152            ret
1153        };
1154
1155        // Convert the source code units length to the destination byte
1156        // length type.
1157        self.convert_src_len_to_dst(src.len.idx, src.opts.ptr(), dst_opts.ptr());
1158        let dst_len = self.local_tee_new_tmp(dst_opts.ptr());
1159        if dst_enc.width() > 1 {
1160            assert_eq!(dst_enc.width(), 2);
1161            self.ptr_uconst(dst_opts, 1);
1162            self.ptr_shl(dst_opts);
1163        }
1164        let dst_byte_len = self.local_set_new_tmp(dst_opts.ptr());
1165
1166        // Allocate space in the destination using the calculated byte
1167        // length.
1168        let dst = {
1169            let dst_mem = self.malloc(
1170                dst_opts,
1171                MallocSize::Local(dst_byte_len.idx),
1172                dst_enc.width().into(),
1173            );
1174            WasmString {
1175                ptr: dst_mem.addr,
1176                len: dst_len,
1177                opts: dst_opts,
1178            }
1179        };
1180
1181        // Validate that `src_len + src_ptr` and
1182        // `dst_mem.addr_local + dst_byte_len` are both in-bounds. This
1183        // is done by loading the last byte of the string and if that
1184        // doesn't trap then it's known valid.
1185        self.validate_string_inbounds(src, src_byte_len);
1186        self.validate_string_inbounds(&dst, dst_byte_len.idx);
1187
1188        // If the validations pass then the host `transcode` intrinsic
1189        // is invoked. This will either raise a trap or otherwise succeed
1190        // in which case we're done.
1191        let op = if src_enc == dst_enc {
1192            Transcode::Copy(src_enc)
1193        } else {
1194            assert_eq!(src_enc, FE::Latin1);
1195            assert_eq!(dst_enc, FE::Utf16);
1196            Transcode::Latin1ToUtf16
1197        };
1198        let transcode = self.transcoder(src, &dst, op);
1199        self.instruction(LocalGet(src.ptr.idx));
1200        self.instruction(LocalGet(src.len.idx));
1201        self.instruction(LocalGet(dst.ptr.idx));
1202        self.instruction(Call(transcode.as_u32()));
1203
1204        self.free_temp_local(dst_byte_len);
1205        if let Some(tmp) = src_byte_len_tmp {
1206            self.free_temp_local(tmp);
1207        }
1208
1209        dst
1210    }
1211    // Corresponding function for `store_string_to_utf8` in the spec.
1212    //
1213    // This translation works by possibly performing a number of
1214    // reallocations. First a buffer of size input-code-units is used to try
1215    // to get the transcoding correct on the first try. If that fails the
1216    // maximum worst-case size is used and then that is resized down if it's
1217    // too large.
1218    //
1219    // The host transcoding function imported here will receive src ptr/len
1220    // and dst ptr/len and return how many code units were consumed on both
1221    // sides. The amount of code units consumed in the source dictates which
1222    // branches are taken in this conversion.
1223    fn string_deflate_to_utf8<'a>(
1224        &mut self,
1225        src: &WasmString<'_>,
1226        src_enc: FE,
1227        dst_opts: &'a Options,
1228    ) -> WasmString<'a> {
1229        self.validate_string_length(src, src_enc);
1230
1231        // Optimistically assume that the code unit length of the source is
1232        // all that's needed in the destination. Perform that allocation
1233        // here and proceed to transcoding below.
1234        self.convert_src_len_to_dst(src.len.idx, src.opts.ptr(), dst_opts.ptr());
1235        let dst_len = self.local_tee_new_tmp(dst_opts.ptr());
1236        let dst_byte_len = self.local_set_new_tmp(dst_opts.ptr());
1237
1238        let dst = {
1239            let dst_mem = self.malloc(dst_opts, MallocSize::Local(dst_byte_len.idx), 1);
1240            WasmString {
1241                ptr: dst_mem.addr,
1242                len: dst_len,
1243                opts: dst_opts,
1244            }
1245        };
1246
1247        // Ensure buffers are all in-bounds
1248        let mut src_byte_len_tmp = None;
1249        let src_byte_len = match src_enc {
1250            FE::Latin1 => src.len.idx,
1251            FE::Utf16 => {
1252                self.instruction(LocalGet(src.len.idx));
1253                self.ptr_uconst(src.opts, 1);
1254                self.ptr_shl(src.opts);
1255                let tmp = self.local_set_new_tmp(src.opts.ptr());
1256                let ret = tmp.idx;
1257                src_byte_len_tmp = Some(tmp);
1258                ret
1259            }
1260            FE::Utf8 => unreachable!(),
1261        };
1262        self.validate_string_inbounds(src, src_byte_len);
1263        self.validate_string_inbounds(&dst, dst_byte_len.idx);
1264
1265        // Perform the initial transcode
1266        let op = match src_enc {
1267            FE::Latin1 => Transcode::Latin1ToUtf8,
1268            FE::Utf16 => Transcode::Utf16ToUtf8,
1269            FE::Utf8 => unreachable!(),
1270        };
1271        let transcode = self.transcoder(src, &dst, op);
1272        self.instruction(LocalGet(src.ptr.idx));
1273        self.instruction(LocalGet(src.len.idx));
1274        self.instruction(LocalGet(dst.ptr.idx));
1275        self.instruction(LocalGet(dst_byte_len.idx));
1276        self.instruction(Call(transcode.as_u32()));
1277        self.instruction(LocalSet(dst.len.idx));
1278        let src_len_tmp = self.local_set_new_tmp(src.opts.ptr());
1279
1280        // Test if the source was entirely transcoded by comparing
1281        // `src_len_tmp`, the number of code units transcoded from the
1282        // source, with `src_len`, the original number of code units.
1283        self.instruction(LocalGet(src_len_tmp.idx));
1284        self.instruction(LocalGet(src.len.idx));
1285        self.ptr_ne(src.opts);
1286        self.instruction(If(BlockType::Empty));
1287
1288        // Here a worst-case reallocation is performed to grow `dst_mem`.
1289        // In-line a check is also performed that the worst-case byte size
1290        // fits within the maximum size of strings.
1291        self.instruction(LocalGet(dst.ptr.idx)); // old_ptr
1292        self.instruction(LocalGet(dst_byte_len.idx)); // old_size
1293        self.ptr_uconst(dst.opts, 1); // align
1294        let factor = match src_enc {
1295            FE::Latin1 => 2,
1296            FE::Utf16 => 3,
1297            _ => unreachable!(),
1298        };
1299        self.validate_string_length_u8(src, factor);
1300        self.convert_src_len_to_dst(src.len.idx, src.opts.ptr(), dst_opts.ptr());
1301        self.ptr_uconst(dst_opts, factor.into());
1302        self.ptr_mul(dst_opts);
1303        self.instruction(LocalTee(dst_byte_len.idx));
1304        self.instruction(Call(dst_opts.realloc.unwrap().as_u32()));
1305        self.instruction(LocalSet(dst.ptr.idx));
1306
1307        // Verify that the destination is still in-bounds
1308        self.validate_string_inbounds(&dst, dst_byte_len.idx);
1309
1310        // Perform another round of transcoding that should be guaranteed
1311        // to succeed. Note that all the parameters here are offset by the
1312        // results of the first transcoding to only perform the remaining
1313        // transcode on the final units.
1314        self.instruction(LocalGet(src.ptr.idx));
1315        self.instruction(LocalGet(src_len_tmp.idx));
1316        if let FE::Utf16 = src_enc {
1317            self.ptr_uconst(src.opts, 1);
1318            self.ptr_shl(src.opts);
1319        }
1320        self.ptr_add(src.opts);
1321        self.instruction(LocalGet(src.len.idx));
1322        self.instruction(LocalGet(src_len_tmp.idx));
1323        self.ptr_sub(src.opts);
1324        self.instruction(LocalGet(dst.ptr.idx));
1325        self.instruction(LocalGet(dst.len.idx));
1326        self.ptr_add(dst.opts);
1327        self.instruction(LocalGet(dst_byte_len.idx));
1328        self.instruction(LocalGet(dst.len.idx));
1329        self.ptr_sub(dst.opts);
1330        self.instruction(Call(transcode.as_u32()));
1331
1332        // Add the second result, the amount of destination units encoded,
1333        // to `dst_len` so it's an accurate reflection of the final size of
1334        // the destination buffer.
1335        self.instruction(LocalGet(dst.len.idx));
1336        self.ptr_add(dst.opts);
1337        self.instruction(LocalSet(dst.len.idx));
1338
1339        // In debug mode verify the first result consumed the entire string,
1340        // otherwise simply discard it.
1341        if self.module.debug {
1342            self.instruction(LocalGet(src.len.idx));
1343            self.instruction(LocalGet(src_len_tmp.idx));
1344            self.ptr_sub(src.opts);
1345            self.ptr_ne(src.opts);
1346            self.instruction(If(BlockType::Empty));
1347            self.trap(Trap::AssertFailed("should have finished encoding"));
1348            self.instruction(End);
1349        } else {
1350            self.instruction(Drop);
1351        }
1352
1353        // Perform a downsizing if the worst-case size was too large
1354        self.instruction(LocalGet(dst.len.idx));
1355        self.instruction(LocalGet(dst_byte_len.idx));
1356        self.ptr_ne(dst.opts);
1357        self.instruction(If(BlockType::Empty));
1358        self.instruction(LocalGet(dst.ptr.idx)); // old_ptr
1359        self.instruction(LocalGet(dst_byte_len.idx)); // old_size
1360        self.ptr_uconst(dst.opts, 1); // align
1361        self.instruction(LocalGet(dst.len.idx)); // new_size
1362        self.instruction(Call(dst.opts.realloc.unwrap().as_u32()));
1363        self.instruction(LocalSet(dst.ptr.idx));
1364        self.instruction(End);
1365
1366        // If the first transcode was enough then assert that the returned
1367        // amount of destination items written equals the byte size.
1368        if self.module.debug {
1369            self.instruction(Else);
1370
1371            self.instruction(LocalGet(dst.len.idx));
1372            self.instruction(LocalGet(dst_byte_len.idx));
1373            self.ptr_ne(dst_opts);
1374            self.instruction(If(BlockType::Empty));
1375            self.trap(Trap::AssertFailed("should have finished encoding"));
1376            self.instruction(End);
1377        }
1378
1379        self.instruction(End); // end of "first transcode not enough"
1380
1381        self.free_temp_local(src_len_tmp);
1382        self.free_temp_local(dst_byte_len);
1383        if let Some(tmp) = src_byte_len_tmp {
1384            self.free_temp_local(tmp);
1385        }
1386
1387        dst
1388    }
1389
1390    // Corresponds to the `store_utf8_to_utf16` function in the spec.
1391    //
1392    // When converting utf-8 to utf-16 a pessimistic allocation is
1393    // done which is twice the byte length of the utf-8 string.
1394    // The host then transcodes and returns how many code units were
1395    // actually used during the transcoding and if it's beneath the
1396    // pessimistic maximum then the buffer is reallocated down to
1397    // a smaller amount.
1398    //
1399    // The host-imported transcoding function takes the src/dst pointer as
1400    // well as the code unit size of both the source and destination. The
1401    // destination should always be big enough to hold the result of the
1402    // transcode and so the result of the host function is how many code
1403    // units were written to the destination.
1404    fn string_utf8_to_utf16<'a>(
1405        &mut self,
1406        src: &WasmString<'_>,
1407        dst_opts: &'a Options,
1408    ) -> WasmString<'a> {
1409        self.validate_string_length(src, FE::Utf16);
1410        self.convert_src_len_to_dst(src.len.idx, src.opts.ptr(), dst_opts.ptr());
1411        let dst_len = self.local_tee_new_tmp(dst_opts.ptr());
1412        self.ptr_uconst(dst_opts, 1);
1413        self.ptr_shl(dst_opts);
1414        let dst_byte_len = self.local_set_new_tmp(dst_opts.ptr());
1415        let dst = {
1416            let dst_mem = self.malloc(dst_opts, MallocSize::Local(dst_byte_len.idx), 2);
1417            WasmString {
1418                ptr: dst_mem.addr,
1419                len: dst_len,
1420                opts: dst_opts,
1421            }
1422        };
1423
1424        self.validate_string_inbounds(src, src.len.idx);
1425        self.validate_string_inbounds(&dst, dst_byte_len.idx);
1426
1427        let transcode = self.transcoder(src, &dst, Transcode::Utf8ToUtf16);
1428        self.instruction(LocalGet(src.ptr.idx));
1429        self.instruction(LocalGet(src.len.idx));
1430        self.instruction(LocalGet(dst.ptr.idx));
1431        self.instruction(Call(transcode.as_u32()));
1432        self.instruction(LocalSet(dst.len.idx));
1433
1434        // If the number of code units returned by transcode is not
1435        // equal to the original number of code units then
1436        // the buffer must be shrunk.
1437        //
1438        // Note that the byte length of the final allocation we
1439        // want is twice the code unit length returned by the
1440        // transcoding function.
1441        self.convert_src_len_to_dst(src.len.idx, src.opts.ptr(), dst.opts.ptr());
1442        self.instruction(LocalGet(dst.len.idx));
1443        self.ptr_ne(dst_opts);
1444        self.instruction(If(BlockType::Empty));
1445        self.instruction(LocalGet(dst.ptr.idx));
1446        self.instruction(LocalGet(dst_byte_len.idx));
1447        self.ptr_uconst(dst.opts, 2);
1448        self.instruction(LocalGet(dst.len.idx));
1449        self.ptr_uconst(dst.opts, 1);
1450        self.ptr_shl(dst.opts);
1451        self.instruction(Call(dst.opts.realloc.unwrap().as_u32()));
1452        self.instruction(LocalSet(dst.ptr.idx));
1453        self.instruction(End); // end of shrink-to-fit
1454
1455        self.free_temp_local(dst_byte_len);
1456
1457        dst
1458    }
1459
1460    // Corresponds to `store_probably_utf16_to_latin1_or_utf16` in the spec.
1461    //
1462    // This will try to transcode the input utf16 string to utf16 in the
1463    // destination. If utf16 isn't needed though and latin1 could be used
1464    // then that's used instead and a reallocation to downsize occurs
1465    // afterwards.
1466    //
1467    // The host transcode function here will take the src/dst pointers as
1468    // well as src length. The destination byte length is twice the src code
1469    // unit length. The return value is the tagged length of the returned
1470    // string. If the upper bit is set then utf16 was used and the
1471    // conversion is done. If the upper bit is not set then latin1 was used
1472    // and a downsizing needs to happen.
1473    fn string_compact_utf16_to_compact<'a>(
1474        &mut self,
1475        src: &WasmString<'_>,
1476        dst_opts: &'a Options,
1477    ) -> WasmString<'a> {
1478        self.validate_string_length(src, FE::Utf16);
1479        self.convert_src_len_to_dst(src.len.idx, src.opts.ptr(), dst_opts.ptr());
1480        let dst_len = self.local_tee_new_tmp(dst_opts.ptr());
1481        self.ptr_uconst(dst_opts, 1);
1482        self.ptr_shl(dst_opts);
1483        let dst_byte_len = self.local_set_new_tmp(dst_opts.ptr());
1484        let dst = {
1485            let dst_mem = self.malloc(dst_opts, MallocSize::Local(dst_byte_len.idx), 2);
1486            WasmString {
1487                ptr: dst_mem.addr,
1488                len: dst_len,
1489                opts: dst_opts,
1490            }
1491        };
1492
1493        self.convert_src_len_to_dst(dst_byte_len.idx, dst.opts.ptr(), src.opts.ptr());
1494        let src_byte_len = self.local_set_new_tmp(src.opts.ptr());
1495
1496        self.validate_string_inbounds(src, src_byte_len.idx);
1497        self.validate_string_inbounds(&dst, dst_byte_len.idx);
1498
1499        let transcode = self.transcoder(src, &dst, Transcode::Utf16ToCompactProbablyUtf16);
1500        self.instruction(LocalGet(src.ptr.idx));
1501        self.instruction(LocalGet(src.len.idx));
1502        self.instruction(LocalGet(dst.ptr.idx));
1503        self.instruction(Call(transcode.as_u32()));
1504        self.instruction(LocalSet(dst.len.idx));
1505
1506        // Assert that the untagged code unit length is the same as the
1507        // source code unit length.
1508        if self.module.debug {
1509            self.instruction(LocalGet(dst.len.idx));
1510            self.ptr_uconst(dst.opts, !UTF16_TAG);
1511            self.ptr_and(dst.opts);
1512            self.convert_src_len_to_dst(src.len.idx, src.opts.ptr(), dst.opts.ptr());
1513            self.ptr_ne(dst.opts);
1514            self.instruction(If(BlockType::Empty));
1515            self.trap(Trap::AssertFailed("expected equal code units"));
1516            self.instruction(End);
1517        }
1518
1519        // If the UTF16_TAG is set then utf16 was used and the destination
1520        // should be appropriately sized. Bail out of the "is this string
1521        // empty" block and fall through otherwise to resizing.
1522        self.instruction(LocalGet(dst.len.idx));
1523        self.ptr_uconst(dst.opts, UTF16_TAG);
1524        self.ptr_and(dst.opts);
1525        self.ptr_br_if(dst.opts, 0);
1526
1527        // Here `realloc` is used to downsize the string
1528        self.instruction(LocalGet(dst.ptr.idx)); // old_ptr
1529        self.instruction(LocalGet(dst_byte_len.idx)); // old_size
1530        self.ptr_uconst(dst.opts, 2); // align
1531        self.instruction(LocalGet(dst.len.idx)); // new_size
1532        self.instruction(Call(dst.opts.realloc.unwrap().as_u32()));
1533        self.instruction(LocalSet(dst.ptr.idx));
1534
1535        self.free_temp_local(dst_byte_len);
1536        self.free_temp_local(src_byte_len);
1537
1538        dst
1539    }
1540
1541    // Corresponds to `store_string_to_latin1_or_utf16` in the spec.
1542    //
1543    // This will attempt a first pass of transcoding to latin1 and on
1544    // failure a larger buffer is allocated for utf16 and then utf16 is
1545    // encoded in-place into the buffer. After either latin1 or utf16 the
1546    // buffer is then resized to fit the final string allocation.
1547    fn string_to_compact<'a>(
1548        &mut self,
1549        src: &WasmString<'_>,
1550        src_enc: FE,
1551        dst_opts: &'a Options,
1552    ) -> WasmString<'a> {
1553        self.validate_string_length(src, src_enc);
1554        self.convert_src_len_to_dst(src.len.idx, src.opts.ptr(), dst_opts.ptr());
1555        let dst_len = self.local_tee_new_tmp(dst_opts.ptr());
1556        let dst_byte_len = self.local_set_new_tmp(dst_opts.ptr());
1557        let dst = {
1558            let dst_mem = self.malloc(dst_opts, MallocSize::Local(dst_byte_len.idx), 2);
1559            WasmString {
1560                ptr: dst_mem.addr,
1561                len: dst_len,
1562                opts: dst_opts,
1563            }
1564        };
1565
1566        self.validate_string_inbounds(src, src.len.idx);
1567        self.validate_string_inbounds(&dst, dst_byte_len.idx);
1568
1569        // Perform the initial latin1 transcode. This returns the number of
1570        // source code units consumed and the number of destination code
1571        // units (bytes) written.
1572        let (latin1, utf16) = match src_enc {
1573            FE::Utf8 => (Transcode::Utf8ToLatin1, Transcode::Utf8ToCompactUtf16),
1574            FE::Utf16 => (Transcode::Utf16ToLatin1, Transcode::Utf16ToCompactUtf16),
1575            FE::Latin1 => unreachable!(),
1576        };
1577        let transcode_latin1 = self.transcoder(src, &dst, latin1);
1578        let transcode_utf16 = self.transcoder(src, &dst, utf16);
1579        self.instruction(LocalGet(src.ptr.idx));
1580        self.instruction(LocalGet(src.len.idx));
1581        self.instruction(LocalGet(dst.ptr.idx));
1582        self.instruction(Call(transcode_latin1.as_u32()));
1583        self.instruction(LocalSet(dst.len.idx));
1584        let src_len_tmp = self.local_set_new_tmp(src.opts.ptr());
1585
1586        // If the source was entirely consumed then the transcode completed
1587        // and all that's necessary is to optionally shrink the buffer.
1588        self.instruction(LocalGet(src_len_tmp.idx));
1589        self.instruction(LocalGet(src.len.idx));
1590        self.ptr_eq(src.opts);
1591        self.instruction(If(BlockType::Empty)); // if latin1-or-utf16 block
1592
1593        // Test if the original byte length of the allocation is the same as
1594        // the number of written bytes, and if not then shrink the buffer
1595        // with a call to `realloc`.
1596        self.instruction(LocalGet(dst_byte_len.idx));
1597        self.instruction(LocalGet(dst.len.idx));
1598        self.ptr_ne(dst.opts);
1599        self.instruction(If(BlockType::Empty));
1600        self.instruction(LocalGet(dst.ptr.idx)); // old_ptr
1601        self.instruction(LocalGet(dst_byte_len.idx)); // old_size
1602        self.ptr_uconst(dst.opts, 2); // align
1603        self.instruction(LocalGet(dst.len.idx)); // new_size
1604        self.instruction(Call(dst.opts.realloc.unwrap().as_u32()));
1605        self.instruction(LocalSet(dst.ptr.idx));
1606        self.instruction(End);
1607
1608        // In this block the latin1 encoding failed. The host transcode
1609        // returned how many units were consumed from the source and how
1610        // many bytes were written to the destination. Here the buffer is
1611        // inflated and sized and the second utf16 intrinsic is invoked to
1612        // perform the final inflation.
1613        self.instruction(Else); // else latin1-or-utf16 block
1614
1615        // For utf8 validate that the inflated size is still within bounds.
1616        if src_enc.width() == 1 {
1617            self.validate_string_length_u8(src, 2);
1618        }
1619
1620        // Reallocate the buffer with twice the source code units in byte
1621        // size.
1622        self.instruction(LocalGet(dst.ptr.idx)); // old_ptr
1623        self.instruction(LocalGet(dst_byte_len.idx)); // old_size
1624        self.ptr_uconst(dst.opts, 2); // align
1625        self.convert_src_len_to_dst(src.len.idx, src.opts.ptr(), dst.opts.ptr());
1626        self.ptr_uconst(dst.opts, 1);
1627        self.ptr_shl(dst.opts);
1628        self.instruction(LocalTee(dst_byte_len.idx));
1629        self.instruction(Call(dst.opts.realloc.unwrap().as_u32()));
1630        self.instruction(LocalSet(dst.ptr.idx));
1631
1632        // Call the host utf16 transcoding function. This will inflate the
1633        // prior latin1 bytes and then encode the rest of the source string
1634        // as utf16 into the remaining space in the destination buffer.
1635        self.instruction(LocalGet(src.ptr.idx));
1636        self.instruction(LocalGet(src_len_tmp.idx));
1637        if let FE::Utf16 = src_enc {
1638            self.ptr_uconst(src.opts, 1);
1639            self.ptr_shl(src.opts);
1640        }
1641        self.ptr_add(src.opts);
1642        self.instruction(LocalGet(src.len.idx));
1643        self.instruction(LocalGet(src_len_tmp.idx));
1644        self.ptr_sub(src.opts);
1645        self.instruction(LocalGet(dst.ptr.idx));
1646        self.convert_src_len_to_dst(src.len.idx, src.opts.ptr(), dst.opts.ptr());
1647        self.instruction(LocalGet(dst.len.idx));
1648        self.instruction(Call(transcode_utf16.as_u32()));
1649        self.instruction(LocalSet(dst.len.idx));
1650
1651        // If the returned number of code units written to the destination
1652        // is not equal to the size of the allocation then the allocation is
1653        // resized down to the appropriate size.
1654        //
1655        // Note that the byte size desired is `2*dst_len` and the current
1656        // byte buffer size is `2*src_len` so the `2` factor isn't checked
1657        // here, just the lengths.
1658        self.instruction(LocalGet(dst.len.idx));
1659        self.convert_src_len_to_dst(src.len.idx, src.opts.ptr(), dst.opts.ptr());
1660        self.ptr_ne(dst.opts);
1661        self.instruction(If(BlockType::Empty));
1662        self.instruction(LocalGet(dst.ptr.idx)); // old_ptr
1663        self.instruction(LocalGet(dst_byte_len.idx)); // old_size
1664        self.ptr_uconst(dst.opts, 2); // align
1665        self.instruction(LocalGet(dst.len.idx));
1666        self.ptr_uconst(dst.opts, 1);
1667        self.ptr_shl(dst.opts);
1668        self.instruction(Call(dst.opts.realloc.unwrap().as_u32()));
1669        self.instruction(LocalSet(dst.ptr.idx));
1670        self.instruction(End);
1671
1672        // Tag the returned pointer as utf16
1673        self.instruction(LocalGet(dst.len.idx));
1674        self.ptr_uconst(dst.opts, UTF16_TAG);
1675        self.ptr_or(dst.opts);
1676        self.instruction(LocalSet(dst.len.idx));
1677
1678        self.instruction(End); // end latin1-or-utf16 block
1679
1680        self.free_temp_local(src_len_tmp);
1681        self.free_temp_local(dst_byte_len);
1682
1683        dst
1684    }
1685
1686    fn validate_string_length(&mut self, src: &WasmString<'_>, dst: FE) {
1687        self.validate_string_length_u8(src, dst.width())
1688    }
1689
1690    fn validate_string_length_u8(&mut self, s: &WasmString<'_>, dst: u8) {
1691        // Check to see if the source byte length is out of bounds in
1692        // which case a trap is generated.
1693        self.instruction(LocalGet(s.len.idx));
1694        let max = MAX_STRING_BYTE_LENGTH / u32::from(dst);
1695        self.ptr_uconst(s.opts, max);
1696        self.ptr_ge_u(s.opts);
1697        self.instruction(If(BlockType::Empty));
1698        self.trap(Trap::StringLengthTooBig);
1699        self.instruction(End);
1700    }
1701
1702    fn transcoder(
1703        &mut self,
1704        src: &WasmString<'_>,
1705        dst: &WasmString<'_>,
1706        op: Transcode,
1707    ) -> FuncIndex {
1708        self.module.import_transcoder(Transcoder {
1709            from_memory: src.opts.memory.unwrap(),
1710            from_memory64: src.opts.memory64,
1711            to_memory: dst.opts.memory.unwrap(),
1712            to_memory64: dst.opts.memory64,
1713            op,
1714        })
1715    }
1716
1717    fn validate_string_inbounds(&mut self, s: &WasmString<'_>, byte_len: u32) {
1718        self.validate_memory_inbounds(s.opts, s.ptr.idx, byte_len, Trap::StringLengthOverflow)
1719    }
1720
1721    fn validate_memory_inbounds(
1722        &mut self,
1723        opts: &Options,
1724        ptr_local: u32,
1725        byte_len_local: u32,
1726        trap: Trap,
1727    ) {
1728        let extend_to_64 = |me: &mut Self| {
1729            if !opts.memory64 {
1730                me.instruction(I64ExtendI32U);
1731            }
1732        };
1733
1734        self.instruction(Block(BlockType::Empty));
1735        self.instruction(Block(BlockType::Empty));
1736
1737        // Calculate the full byte size of memory with `memory.size`. Note that
1738        // arithmetic here is done always in 64-bits to accommodate 4G memories.
1739        // Additionally it's assumed that 64-bit memories never fill up
1740        // entirely.
1741        self.instruction(MemorySize(opts.memory.unwrap().as_u32()));
1742        extend_to_64(self);
1743        self.instruction(I64Const(16));
1744        self.instruction(I64Shl);
1745
1746        // Calculate the end address of the string. This is done by adding the
1747        // base pointer to the byte length. For 32-bit memories there's no need
1748        // to check for overflow since everything is extended to 64-bit, but for
1749        // 64-bit memories overflow is checked.
1750        self.instruction(LocalGet(ptr_local));
1751        extend_to_64(self);
1752        self.instruction(LocalGet(byte_len_local));
1753        extend_to_64(self);
1754        self.instruction(I64Add);
1755        if opts.memory64 {
1756            let tmp = self.local_tee_new_tmp(ValType::I64);
1757            self.instruction(LocalGet(ptr_local));
1758            self.ptr_lt_u(opts);
1759            self.instruction(BrIf(0));
1760            self.instruction(LocalGet(tmp.idx));
1761            self.free_temp_local(tmp);
1762        }
1763
1764        // If the byte size of memory is greater than the final address of the
1765        // string then the string is invalid. Note that if it's precisely equal
1766        // then that's ok.
1767        self.instruction(I64GeU);
1768        self.instruction(BrIf(1));
1769
1770        self.instruction(End);
1771        self.trap(trap);
1772        self.instruction(End);
1773    }
1774
1775    fn translate_list(
1776        &mut self,
1777        src_ty: TypeListIndex,
1778        src: &Source<'_>,
1779        dst_ty: &InterfaceType,
1780        dst: &Destination,
1781    ) {
1782        let src_element_ty = &self.types[src_ty].element;
1783        let dst_element_ty = match dst_ty {
1784            InterfaceType::List(r) => &self.types[*r].element,
1785            _ => panic!("expected a list"),
1786        };
1787        let src_opts = src.opts();
1788        let dst_opts = dst.opts();
1789        let (src_size, src_align) = self.types.size_align(src_opts, src_element_ty);
1790        let (dst_size, dst_align) = self.types.size_align(dst_opts, dst_element_ty);
1791
1792        // Load the pointer/length of this list into temporary locals. These
1793        // will be referenced a good deal so this just makes it easier to deal
1794        // with them consistently below rather than trying to reload from memory
1795        // for example.
1796        match src {
1797            Source::Stack(s) => {
1798                assert_eq!(s.locals.len(), 2);
1799                self.stack_get(&s.slice(0..1), src_opts.ptr());
1800                self.stack_get(&s.slice(1..2), src_opts.ptr());
1801            }
1802            Source::Memory(mem) => {
1803                self.ptr_load(mem);
1804                self.ptr_load(&mem.bump(src_opts.ptr_size().into()));
1805            }
1806        }
1807        let src_len = self.local_set_new_tmp(src_opts.ptr());
1808        let src_ptr = self.local_set_new_tmp(src_opts.ptr());
1809
1810        // Create a `Memory` operand which will internally assert that the
1811        // `src_ptr` value is properly aligned.
1812        let src_mem = self.memory_operand(src_opts, src_ptr, src_align);
1813
1814        // Calculate the source/destination byte lengths into unique locals.
1815        let src_byte_len = self.calculate_list_byte_len(src_opts, src_len.idx, src_size);
1816        let dst_byte_len = if src_size == dst_size {
1817            self.convert_src_len_to_dst(src_byte_len.idx, src_opts.ptr(), dst_opts.ptr());
1818            self.local_set_new_tmp(dst_opts.ptr())
1819        } else if src_opts.ptr() == dst_opts.ptr() {
1820            self.calculate_list_byte_len(dst_opts, src_len.idx, dst_size)
1821        } else {
1822            self.convert_src_len_to_dst(src_byte_len.idx, src_opts.ptr(), dst_opts.ptr());
1823            let tmp = self.local_set_new_tmp(dst_opts.ptr());
1824            let ret = self.calculate_list_byte_len(dst_opts, tmp.idx, dst_size);
1825            self.free_temp_local(tmp);
1826            ret
1827        };
1828
1829        // Here `realloc` is invoked (in a `malloc`-like fashion) to allocate
1830        // space for the list in the destination memory. This will also
1831        // internally insert checks that the returned pointer is aligned
1832        // correctly for the destination.
1833        let dst_mem = self.malloc(dst_opts, MallocSize::Local(dst_byte_len.idx), dst_align);
1834
1835        // With all the pointers and byte lengths verity that both the source
1836        // and the destination buffers are in-bounds.
1837        self.validate_memory_inbounds(
1838            src_opts,
1839            src_mem.addr.idx,
1840            src_byte_len.idx,
1841            Trap::ListByteLengthOverflow,
1842        );
1843        self.validate_memory_inbounds(
1844            dst_opts,
1845            dst_mem.addr.idx,
1846            dst_byte_len.idx,
1847            Trap::ListByteLengthOverflow,
1848        );
1849
1850        self.free_temp_local(src_byte_len);
1851        self.free_temp_local(dst_byte_len);
1852
1853        // This is the main body of the loop to actually translate list types.
1854        // Note that if both element sizes are 0 then this won't actually do
1855        // anything so the loop is removed entirely.
1856        if src_size > 0 || dst_size > 0 {
1857            // This block encompasses the entire loop and is use to exit before even
1858            // entering the loop if the list size is zero.
1859            self.instruction(Block(BlockType::Empty));
1860
1861            // Set the `remaining` local and only continue if it's > 0
1862            self.instruction(LocalGet(src_len.idx));
1863            let remaining = self.local_tee_new_tmp(src_opts.ptr());
1864            self.ptr_eqz(src_opts);
1865            self.instruction(BrIf(0));
1866
1867            // Initialize the two destination pointers to their initial values
1868            self.instruction(LocalGet(src_mem.addr.idx));
1869            let cur_src_ptr = self.local_set_new_tmp(src_opts.ptr());
1870            self.instruction(LocalGet(dst_mem.addr.idx));
1871            let cur_dst_ptr = self.local_set_new_tmp(dst_opts.ptr());
1872
1873            self.instruction(Loop(BlockType::Empty));
1874
1875            // Translate the next element in the list
1876            let element_src = Source::Memory(Memory {
1877                opts: src_opts,
1878                offset: 0,
1879                addr: TempLocal::new(cur_src_ptr.idx, cur_src_ptr.ty),
1880            });
1881            let element_dst = Destination::Memory(Memory {
1882                opts: dst_opts,
1883                offset: 0,
1884                addr: TempLocal::new(cur_dst_ptr.idx, cur_dst_ptr.ty),
1885            });
1886            self.translate(src_element_ty, &element_src, dst_element_ty, &element_dst);
1887
1888            // Update the two loop pointers
1889            if src_size > 0 {
1890                self.instruction(LocalGet(cur_src_ptr.idx));
1891                self.ptr_uconst(src_opts, src_size);
1892                self.ptr_add(src_opts);
1893                self.instruction(LocalSet(cur_src_ptr.idx));
1894            }
1895            if dst_size > 0 {
1896                self.instruction(LocalGet(cur_dst_ptr.idx));
1897                self.ptr_uconst(dst_opts, dst_size);
1898                self.ptr_add(dst_opts);
1899                self.instruction(LocalSet(cur_dst_ptr.idx));
1900            }
1901
1902            // Update the remaining count, falling through to break out if it's zero
1903            // now.
1904            self.instruction(LocalGet(remaining.idx));
1905            self.ptr_iconst(src_opts, -1);
1906            self.ptr_add(src_opts);
1907            self.instruction(LocalTee(remaining.idx));
1908            self.ptr_br_if(src_opts, 0);
1909            self.instruction(End); // end of loop
1910            self.instruction(End); // end of block
1911
1912            self.free_temp_local(cur_dst_ptr);
1913            self.free_temp_local(cur_src_ptr);
1914            self.free_temp_local(remaining);
1915        }
1916
1917        // Store the ptr/length in the desired destination
1918        match dst {
1919            Destination::Stack(s, _) => {
1920                self.instruction(LocalGet(dst_mem.addr.idx));
1921                self.stack_set(&s[..1], dst_opts.ptr());
1922                self.convert_src_len_to_dst(src_len.idx, src_opts.ptr(), dst_opts.ptr());
1923                self.stack_set(&s[1..], dst_opts.ptr());
1924            }
1925            Destination::Memory(mem) => {
1926                self.instruction(LocalGet(mem.addr.idx));
1927                self.instruction(LocalGet(dst_mem.addr.idx));
1928                self.ptr_store(mem);
1929                self.instruction(LocalGet(mem.addr.idx));
1930                self.convert_src_len_to_dst(src_len.idx, src_opts.ptr(), dst_opts.ptr());
1931                self.ptr_store(&mem.bump(dst_opts.ptr_size().into()));
1932            }
1933        }
1934
1935        self.free_temp_local(src_len);
1936        self.free_temp_local(src_mem.addr);
1937        self.free_temp_local(dst_mem.addr);
1938    }
1939
1940    fn calculate_list_byte_len(
1941        &mut self,
1942        opts: &Options,
1943        len_local: u32,
1944        elt_size: u32,
1945    ) -> TempLocal {
1946        // Zero-size types are easy to handle here because the byte size of the
1947        // destination is always zero.
1948        if elt_size == 0 {
1949            self.ptr_uconst(opts, 0);
1950            return self.local_set_new_tmp(opts.ptr());
1951        }
1952
1953        // For one-byte elements in the destination the check here can be a bit
1954        // more optimal than the general case below. In these situations if the
1955        // source pointer type is 32-bit then we're guaranteed to not overflow,
1956        // so the source length is simply casted to the destination's type.
1957        //
1958        // If the source is 64-bit then all that needs to be checked is to
1959        // ensure that it does not have the upper 32-bits set.
1960        if elt_size == 1 {
1961            if let ValType::I64 = opts.ptr() {
1962                self.instruction(LocalGet(len_local));
1963                self.instruction(I64Const(32));
1964                self.instruction(I64ShrU);
1965                self.instruction(I32WrapI64);
1966                self.instruction(If(BlockType::Empty));
1967                self.trap(Trap::ListByteLengthOverflow);
1968                self.instruction(End);
1969            }
1970            self.instruction(LocalGet(len_local));
1971            return self.local_set_new_tmp(opts.ptr());
1972        }
1973
1974        // The main check implemented by this function is to verify that
1975        // `src_len_local` does not exceed the 32-bit range. Byte sizes for
1976        // lists must always fit in 32-bits to get transferred to 32-bit
1977        // memories.
1978        self.instruction(Block(BlockType::Empty));
1979        self.instruction(Block(BlockType::Empty));
1980        self.instruction(LocalGet(len_local));
1981        match opts.ptr() {
1982            // The source's list length is guaranteed to be less than 32-bits
1983            // so simply extend it up to a 64-bit type for the multiplication
1984            // below.
1985            ValType::I32 => self.instruction(I64ExtendI32U),
1986
1987            // If the source is a 64-bit memory then if the item length doesn't
1988            // fit in 32-bits the byte length definitely won't, so generate a
1989            // branch to our overflow trap here if any of the upper 32-bits are set.
1990            ValType::I64 => {
1991                self.instruction(I64Const(32));
1992                self.instruction(I64ShrU);
1993                self.instruction(I32WrapI64);
1994                self.instruction(BrIf(0));
1995                self.instruction(LocalGet(len_local));
1996            }
1997
1998            _ => unreachable!(),
1999        }
2000
2001        // Next perform a 64-bit multiplication with the element byte size that
2002        // is itself guaranteed to fit in 32-bits. The result is then checked
2003        // to see if we overflowed the 32-bit space. The two input operands to
2004        // the multiplication are guaranteed to be 32-bits at most which means
2005        // that this multiplication shouldn't overflow.
2006        //
2007        // The result of the multiplication is saved into a local as well to
2008        // get the result afterwards.
2009        self.instruction(I64Const(elt_size.into()));
2010        self.instruction(I64Mul);
2011        let tmp = self.local_tee_new_tmp(ValType::I64);
2012        // Branch to success if the upper 32-bits are zero, otherwise
2013        // fall-through to the trap.
2014        self.instruction(I64Const(32));
2015        self.instruction(I64ShrU);
2016        self.instruction(I64Eqz);
2017        self.instruction(BrIf(1));
2018        self.instruction(End);
2019        self.trap(Trap::ListByteLengthOverflow);
2020        self.instruction(End);
2021
2022        // If a fresh local was used to store the result of the multiplication
2023        // then convert it down to 32-bits which should be guaranteed to not
2024        // lose information at this point.
2025        if opts.ptr() == ValType::I64 {
2026            tmp
2027        } else {
2028            self.instruction(LocalGet(tmp.idx));
2029            self.instruction(I32WrapI64);
2030            self.free_temp_local(tmp);
2031            self.local_set_new_tmp(ValType::I32)
2032        }
2033    }
2034
2035    fn convert_src_len_to_dst(
2036        &mut self,
2037        src_len_local: u32,
2038        src_ptr_ty: ValType,
2039        dst_ptr_ty: ValType,
2040    ) {
2041        self.instruction(LocalGet(src_len_local));
2042        match (src_ptr_ty, dst_ptr_ty) {
2043            (ValType::I32, ValType::I64) => self.instruction(I64ExtendI32U),
2044            (ValType::I64, ValType::I32) => self.instruction(I32WrapI64),
2045            (src, dst) => assert_eq!(src, dst),
2046        }
2047    }
2048
2049    fn translate_record(
2050        &mut self,
2051        src_ty: TypeRecordIndex,
2052        src: &Source<'_>,
2053        dst_ty: &InterfaceType,
2054        dst: &Destination,
2055    ) {
2056        let src_ty = &self.types[src_ty];
2057        let dst_ty = match dst_ty {
2058            InterfaceType::Record(r) => &self.types[*r],
2059            _ => panic!("expected a record"),
2060        };
2061
2062        // TODO: subtyping
2063        assert_eq!(src_ty.fields.len(), dst_ty.fields.len());
2064
2065        // First a map is made of the source fields to where they're coming
2066        // from (e.g. which offset or which locals). This map is keyed by the
2067        // fields' names
2068        let mut src_fields = HashMap::new();
2069        for (i, src) in src
2070            .record_field_srcs(self.types, src_ty.fields.iter().map(|f| f.ty))
2071            .enumerate()
2072        {
2073            let field = &src_ty.fields[i];
2074            src_fields.insert(&field.name, (src, &field.ty));
2075        }
2076
2077        // .. and next translation is performed in the order of the destination
2078        // fields in case the destination is the stack to ensure that the stack
2079        // has the fields all in the right order.
2080        //
2081        // Note that the lookup in `src_fields` is an infallible lookup which
2082        // will panic if the field isn't found.
2083        //
2084        // TODO: should that lookup be fallible with subtyping?
2085        for (i, dst) in dst
2086            .record_field_dsts(self.types, dst_ty.fields.iter().map(|f| f.ty))
2087            .enumerate()
2088        {
2089            let field = &dst_ty.fields[i];
2090            let (src, src_ty) = &src_fields[&field.name];
2091            self.translate(src_ty, src, &field.ty, &dst);
2092        }
2093    }
2094
2095    fn translate_flags(
2096        &mut self,
2097        src_ty: TypeFlagsIndex,
2098        src: &Source<'_>,
2099        dst_ty: &InterfaceType,
2100        dst: &Destination,
2101    ) {
2102        let src_ty = &self.types[src_ty];
2103        let dst_ty = match dst_ty {
2104            InterfaceType::Flags(r) => &self.types[*r],
2105            _ => panic!("expected a record"),
2106        };
2107
2108        // TODO: subtyping
2109        //
2110        // Notably this implementation does not support reordering flags from
2111        // the source to the destination nor having more flags in the
2112        // destination. Currently this is a copy from source to destination
2113        // in-bulk. Otherwise reordering indices would have to have some sort of
2114        // fancy bit twiddling tricks or something like that.
2115        assert_eq!(src_ty.names, dst_ty.names);
2116        let cnt = src_ty.names.len();
2117        match FlagsSize::from_count(cnt) {
2118            FlagsSize::Size0 => {}
2119            FlagsSize::Size1 => {
2120                let mask = if cnt == 8 { 0xff } else { (1 << cnt) - 1 };
2121                self.convert_u8_mask(src, dst, mask);
2122            }
2123            FlagsSize::Size2 => {
2124                let mask = if cnt == 16 { 0xffff } else { (1 << cnt) - 1 };
2125                self.convert_u16_mask(src, dst, mask);
2126            }
2127            FlagsSize::Size4Plus(n) => {
2128                let srcs = src.record_field_srcs(self.types, (0..n).map(|_| InterfaceType::U32));
2129                let dsts = dst.record_field_dsts(self.types, (0..n).map(|_| InterfaceType::U32));
2130                let n = usize::from(n);
2131                for (i, (src, dst)) in srcs.zip(dsts).enumerate() {
2132                    let mask = if i == n - 1 && (cnt % 32 != 0) {
2133                        (1 << (cnt % 32)) - 1
2134                    } else {
2135                        0xffffffff
2136                    };
2137                    self.convert_u32_mask(&src, &dst, mask);
2138                }
2139            }
2140        }
2141    }
2142
2143    fn translate_tuple(
2144        &mut self,
2145        src_ty: TypeTupleIndex,
2146        src: &Source<'_>,
2147        dst_ty: &InterfaceType,
2148        dst: &Destination,
2149    ) {
2150        let src_ty = &self.types[src_ty];
2151        let dst_ty = match dst_ty {
2152            InterfaceType::Tuple(t) => &self.types[*t],
2153            _ => panic!("expected a tuple"),
2154        };
2155
2156        // TODO: subtyping
2157        assert_eq!(src_ty.types.len(), dst_ty.types.len());
2158
2159        let srcs = src
2160            .record_field_srcs(self.types, src_ty.types.iter().copied())
2161            .zip(src_ty.types.iter());
2162        let dsts = dst
2163            .record_field_dsts(self.types, dst_ty.types.iter().copied())
2164            .zip(dst_ty.types.iter());
2165        for ((src, src_ty), (dst, dst_ty)) in srcs.zip(dsts) {
2166            self.translate(src_ty, &src, dst_ty, &dst);
2167        }
2168    }
2169
2170    fn translate_variant(
2171        &mut self,
2172        src_ty: TypeVariantIndex,
2173        src: &Source<'_>,
2174        dst_ty: &InterfaceType,
2175        dst: &Destination,
2176    ) {
2177        let src_ty = &self.types[src_ty];
2178        let dst_ty = match dst_ty {
2179            InterfaceType::Variant(t) => &self.types[*t],
2180            _ => panic!("expected a variant"),
2181        };
2182
2183        let src_info = variant_info(self.types, src_ty.cases.iter().map(|(_, c)| c.as_ref()));
2184        let dst_info = variant_info(self.types, dst_ty.cases.iter().map(|(_, c)| c.as_ref()));
2185
2186        let iter = src_ty
2187            .cases
2188            .iter()
2189            .enumerate()
2190            .map(|(src_i, (src_case, src_case_ty))| {
2191                let dst_i = dst_ty
2192                    .cases
2193                    .iter()
2194                    .position(|(c, _)| c == src_case)
2195                    .unwrap();
2196                let dst_case_ty = &dst_ty.cases[dst_i];
2197                let src_i = u32::try_from(src_i).unwrap();
2198                let dst_i = u32::try_from(dst_i).unwrap();
2199                VariantCase {
2200                    src_i,
2201                    src_ty: src_case_ty.as_ref(),
2202                    dst_i,
2203                    dst_ty: dst_case_ty.as_ref(),
2204                }
2205            });
2206        self.convert_variant(src, &src_info, dst, &dst_info, iter);
2207    }
2208
2209    fn translate_enum(
2210        &mut self,
2211        src_ty: TypeEnumIndex,
2212        src: &Source<'_>,
2213        dst_ty: &InterfaceType,
2214        dst: &Destination,
2215    ) {
2216        let src_ty = &self.types[src_ty];
2217        let dst_ty = match dst_ty {
2218            InterfaceType::Enum(t) => &self.types[*t],
2219            _ => panic!("expected an option"),
2220        };
2221        let src_info = variant_info(self.types, src_ty.names.iter().map(|_| None));
2222        let dst_info = variant_info(self.types, dst_ty.names.iter().map(|_| None));
2223
2224        self.convert_variant(
2225            src,
2226            &src_info,
2227            dst,
2228            &dst_info,
2229            src_ty.names.iter().enumerate().map(|(src_i, src_name)| {
2230                let dst_i = dst_ty.names.iter().position(|n| n == src_name).unwrap();
2231                let src_i = u32::try_from(src_i).unwrap();
2232                let dst_i = u32::try_from(dst_i).unwrap();
2233                VariantCase {
2234                    src_i,
2235                    dst_i,
2236                    src_ty: None,
2237                    dst_ty: None,
2238                }
2239            }),
2240        );
2241    }
2242
2243    fn translate_option(
2244        &mut self,
2245        src_ty: TypeOptionIndex,
2246        src: &Source<'_>,
2247        dst_ty: &InterfaceType,
2248        dst: &Destination,
2249    ) {
2250        let src_ty = &self.types[src_ty].ty;
2251        let dst_ty = match dst_ty {
2252            InterfaceType::Option(t) => &self.types[*t].ty,
2253            _ => panic!("expected an option"),
2254        };
2255        let src_ty = Some(src_ty);
2256        let dst_ty = Some(dst_ty);
2257
2258        let src_info = variant_info(self.types, [None, src_ty]);
2259        let dst_info = variant_info(self.types, [None, dst_ty]);
2260
2261        self.convert_variant(
2262            src,
2263            &src_info,
2264            dst,
2265            &dst_info,
2266            [
2267                VariantCase {
2268                    src_i: 0,
2269                    dst_i: 0,
2270                    src_ty: None,
2271                    dst_ty: None,
2272                },
2273                VariantCase {
2274                    src_i: 1,
2275                    dst_i: 1,
2276                    src_ty,
2277                    dst_ty,
2278                },
2279            ]
2280            .into_iter(),
2281        );
2282    }
2283
2284    fn translate_result(
2285        &mut self,
2286        src_ty: TypeResultIndex,
2287        src: &Source<'_>,
2288        dst_ty: &InterfaceType,
2289        dst: &Destination,
2290    ) {
2291        let src_ty = &self.types[src_ty];
2292        let dst_ty = match dst_ty {
2293            InterfaceType::Result(t) => &self.types[*t],
2294            _ => panic!("expected a result"),
2295        };
2296
2297        let src_info = variant_info(self.types, [src_ty.ok.as_ref(), src_ty.err.as_ref()]);
2298        let dst_info = variant_info(self.types, [dst_ty.ok.as_ref(), dst_ty.err.as_ref()]);
2299
2300        self.convert_variant(
2301            src,
2302            &src_info,
2303            dst,
2304            &dst_info,
2305            [
2306                VariantCase {
2307                    src_i: 0,
2308                    dst_i: 0,
2309                    src_ty: src_ty.ok.as_ref(),
2310                    dst_ty: dst_ty.ok.as_ref(),
2311                },
2312                VariantCase {
2313                    src_i: 1,
2314                    dst_i: 1,
2315                    src_ty: src_ty.err.as_ref(),
2316                    dst_ty: dst_ty.err.as_ref(),
2317                },
2318            ]
2319            .into_iter(),
2320        );
2321    }
2322
2323    fn convert_variant<'a>(
2324        &mut self,
2325        src: &Source<'_>,
2326        src_info: &VariantInfo,
2327        dst: &Destination,
2328        dst_info: &VariantInfo,
2329        src_cases: impl ExactSizeIterator<Item = VariantCase<'a>>,
2330    ) {
2331        // The outermost block is special since it has the result type of the
2332        // translation here. That will depend on the `dst`.
2333        let outer_block_ty = match dst {
2334            Destination::Stack(dst_flat, _) => match dst_flat.len() {
2335                0 => BlockType::Empty,
2336                1 => BlockType::Result(dst_flat[0]),
2337                _ => {
2338                    let ty = self.module.core_types.function(&[], &dst_flat);
2339                    BlockType::FunctionType(ty)
2340                }
2341            },
2342            Destination::Memory(_) => BlockType::Empty,
2343        };
2344        self.instruction(Block(outer_block_ty));
2345
2346        // After the outermost block generate a new block for each of the
2347        // remaining cases.
2348        let src_cases_len = src_cases.len();
2349        for _ in 0..src_cases_len - 1 {
2350            self.instruction(Block(BlockType::Empty));
2351        }
2352
2353        // Generate a block for an invalid variant discriminant
2354        self.instruction(Block(BlockType::Empty));
2355
2356        // And generate one final block that we'll be jumping out of with the
2357        // `br_table`
2358        self.instruction(Block(BlockType::Empty));
2359
2360        // Load the discriminant
2361        match src {
2362            Source::Stack(s) => self.stack_get(&s.slice(0..1), ValType::I32),
2363            Source::Memory(mem) => match src_info.size {
2364                DiscriminantSize::Size1 => self.i32_load8u(mem),
2365                DiscriminantSize::Size2 => self.i32_load16u(mem),
2366                DiscriminantSize::Size4 => self.i32_load(mem),
2367            },
2368        }
2369
2370        // Generate the `br_table` for the discriminant. Each case has an
2371        // offset of 1 to skip the trapping block.
2372        let mut targets = Vec::new();
2373        for i in 0..src_cases_len {
2374            targets.push((i + 1) as u32);
2375        }
2376        self.instruction(BrTable(targets[..].into(), 0));
2377        self.instruction(End); // end the `br_table` block
2378
2379        self.trap(Trap::InvalidDiscriminant);
2380        self.instruction(End); // end the "invalid discriminant" block
2381
2382        // Translate each case individually within its own block. Note that the
2383        // iteration order here places the first case in the innermost block
2384        // and the last case in the outermost block. This matches the order
2385        // of the jump targets in the `br_table` instruction.
2386        let src_cases_len = u32::try_from(src_cases_len).unwrap();
2387        for case in src_cases {
2388            let VariantCase {
2389                src_i,
2390                src_ty,
2391                dst_i,
2392                dst_ty,
2393            } = case;
2394
2395            // Translate the discriminant here, noting that `dst_i` may be
2396            // different than `src_i`.
2397            self.push_dst_addr(dst);
2398            self.instruction(I32Const(dst_i as i32));
2399            match dst {
2400                Destination::Stack(stack, _) => self.stack_set(&stack[..1], ValType::I32),
2401                Destination::Memory(mem) => match dst_info.size {
2402                    DiscriminantSize::Size1 => self.i32_store8(mem),
2403                    DiscriminantSize::Size2 => self.i32_store16(mem),
2404                    DiscriminantSize::Size4 => self.i32_store(mem),
2405                },
2406            }
2407
2408            let src_payload = src.payload_src(self.types, src_info, src_ty);
2409            let dst_payload = dst.payload_dst(self.types, dst_info, dst_ty);
2410
2411            // Translate the payload of this case using the various types from
2412            // the dst/src.
2413            match (src_ty, dst_ty) {
2414                (Some(src_ty), Some(dst_ty)) => {
2415                    self.translate(src_ty, &src_payload, dst_ty, &dst_payload);
2416                }
2417                (None, None) => {}
2418                _ => unimplemented!(),
2419            }
2420
2421            // If the results of this translation were placed on the stack then
2422            // the stack values may need to be padded with more zeros due to
2423            // this particular case being possibly smaller than the entire
2424            // variant. That's handled here by pushing remaining zeros after
2425            // accounting for the discriminant pushed as well as the results of
2426            // this individual payload.
2427            if let Destination::Stack(payload_results, _) = dst_payload {
2428                if let Destination::Stack(dst_results, _) = dst {
2429                    let remaining = &dst_results[1..][payload_results.len()..];
2430                    for ty in remaining {
2431                        match ty {
2432                            ValType::I32 => self.instruction(I32Const(0)),
2433                            ValType::I64 => self.instruction(I64Const(0)),
2434                            ValType::F32 => self.instruction(F32Const(0.0)),
2435                            ValType::F64 => self.instruction(F64Const(0.0)),
2436                            _ => unreachable!(),
2437                        }
2438                    }
2439                }
2440            }
2441
2442            // Branch to the outermost block. Note that this isn't needed for
2443            // the outermost case since it simply falls through.
2444            if src_i != src_cases_len - 1 {
2445                self.instruction(Br(src_cases_len - src_i - 1));
2446            }
2447            self.instruction(End); // end this case's block
2448        }
2449    }
2450
2451    fn translate_own(
2452        &mut self,
2453        src_ty: TypeResourceTableIndex,
2454        src: &Source<'_>,
2455        dst_ty: &InterfaceType,
2456        dst: &Destination,
2457    ) {
2458        let dst_ty = match dst_ty {
2459            InterfaceType::Own(t) => *t,
2460            _ => panic!("expected an `Own`"),
2461        };
2462        let transfer = self.module.import_resource_transfer_own();
2463        self.translate_resource(src_ty, src, dst_ty, dst, transfer);
2464    }
2465
2466    fn translate_borrow(
2467        &mut self,
2468        src_ty: TypeResourceTableIndex,
2469        src: &Source<'_>,
2470        dst_ty: &InterfaceType,
2471        dst: &Destination,
2472    ) {
2473        let dst_ty = match dst_ty {
2474            InterfaceType::Borrow(t) => *t,
2475            _ => panic!("expected an `Borrow`"),
2476        };
2477
2478        let transfer = self.module.import_resource_transfer_borrow();
2479        self.translate_resource(src_ty, src, dst_ty, dst, transfer);
2480    }
2481
2482    /// Translates the index `src`, which resides in the table `src_ty`, into
2483    /// and index within `dst_ty` and is stored at `dst`.
2484    ///
2485    /// Actual translation of the index happens in a wasmtime libcall, which a
2486    /// cranelift-generated trampoline to satisfy this import will call. The
2487    /// `transfer` function is an imported function which takes the src, src_ty,
2488    /// and dst_ty, and returns the dst index.
2489    fn translate_resource(
2490        &mut self,
2491        src_ty: TypeResourceTableIndex,
2492        src: &Source<'_>,
2493        dst_ty: TypeResourceTableIndex,
2494        dst: &Destination,
2495        transfer: FuncIndex,
2496    ) {
2497        self.push_dst_addr(dst);
2498        match src {
2499            Source::Memory(mem) => self.i32_load(mem),
2500            Source::Stack(stack) => self.stack_get(stack, ValType::I32),
2501        }
2502        self.instruction(I32Const(src_ty.as_u32() as i32));
2503        self.instruction(I32Const(dst_ty.as_u32() as i32));
2504        self.instruction(Call(transfer.as_u32()));
2505        match dst {
2506            Destination::Memory(mem) => self.i32_store(mem),
2507            Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
2508        }
2509    }
2510
2511    fn trap_if_not_flag(&mut self, flags_global: GlobalIndex, flag_to_test: i32, trap: Trap) {
2512        self.instruction(GlobalGet(flags_global.as_u32()));
2513        self.instruction(I32Const(flag_to_test));
2514        self.instruction(I32And);
2515        self.instruction(I32Eqz);
2516        self.instruction(If(BlockType::Empty));
2517        self.trap(trap);
2518        self.instruction(End);
2519    }
2520
2521    fn assert_not_flag(&mut self, flags_global: GlobalIndex, flag_to_test: i32, msg: &'static str) {
2522        self.instruction(GlobalGet(flags_global.as_u32()));
2523        self.instruction(I32Const(flag_to_test));
2524        self.instruction(I32And);
2525        self.instruction(If(BlockType::Empty));
2526        self.trap(Trap::AssertFailed(msg));
2527        self.instruction(End);
2528    }
2529
2530    fn set_flag(&mut self, flags_global: GlobalIndex, flag_to_set: i32, value: bool) {
2531        self.instruction(GlobalGet(flags_global.as_u32()));
2532        if value {
2533            self.instruction(I32Const(flag_to_set));
2534            self.instruction(I32Or);
2535        } else {
2536            self.instruction(I32Const(!flag_to_set));
2537            self.instruction(I32And);
2538        }
2539        self.instruction(GlobalSet(flags_global.as_u32()));
2540    }
2541
2542    fn verify_aligned(&mut self, opts: &Options, addr_local: u32, align: u32) {
2543        // If the alignment is 1 then everything is trivially aligned and the
2544        // check can be omitted.
2545        if align == 1 {
2546            return;
2547        }
2548        self.instruction(LocalGet(addr_local));
2549        assert!(align.is_power_of_two());
2550        self.ptr_uconst(opts, align - 1);
2551        self.ptr_and(opts);
2552        self.ptr_if(opts, BlockType::Empty);
2553        self.trap(Trap::UnalignedPointer);
2554        self.instruction(End);
2555    }
2556
2557    fn assert_aligned(&mut self, ty: &InterfaceType, mem: &Memory) {
2558        if !self.module.debug {
2559            return;
2560        }
2561        let align = self.types.align(mem.opts, ty);
2562        if align == 1 {
2563            return;
2564        }
2565        assert!(align.is_power_of_two());
2566        self.instruction(LocalGet(mem.addr.idx));
2567        self.ptr_uconst(mem.opts, mem.offset);
2568        self.ptr_add(mem.opts);
2569        self.ptr_uconst(mem.opts, align - 1);
2570        self.ptr_and(mem.opts);
2571        self.ptr_if(mem.opts, BlockType::Empty);
2572        self.trap(Trap::AssertFailed("pointer not aligned"));
2573        self.instruction(End);
2574    }
2575
2576    fn malloc<'a>(&mut self, opts: &'a Options, size: MallocSize, align: u32) -> Memory<'a> {
2577        let realloc = opts.realloc.unwrap();
2578        self.ptr_uconst(opts, 0);
2579        self.ptr_uconst(opts, 0);
2580        self.ptr_uconst(opts, align);
2581        match size {
2582            MallocSize::Const(size) => self.ptr_uconst(opts, size),
2583            MallocSize::Local(idx) => self.instruction(LocalGet(idx)),
2584        }
2585        self.instruction(Call(realloc.as_u32()));
2586        let addr = self.local_set_new_tmp(opts.ptr());
2587        self.memory_operand(opts, addr, align)
2588    }
2589
2590    fn memory_operand<'a>(&mut self, opts: &'a Options, addr: TempLocal, align: u32) -> Memory<'a> {
2591        let ret = Memory {
2592            addr,
2593            offset: 0,
2594            opts,
2595        };
2596        self.verify_aligned(opts, ret.addr.idx, align);
2597        ret
2598    }
2599
2600    /// Generates a new local in this function of the `ty` specified,
2601    /// initializing it with the top value on the current wasm stack.
2602    ///
2603    /// The returned `TempLocal` must be freed after it is finished with
2604    /// `free_temp_local`.
2605    fn local_tee_new_tmp(&mut self, ty: ValType) -> TempLocal {
2606        self.gen_temp_local(ty, LocalTee)
2607    }
2608
2609    /// Same as `local_tee_new_tmp` but initializes the local with `LocalSet`
2610    /// instead of `LocalTee`.
2611    fn local_set_new_tmp(&mut self, ty: ValType) -> TempLocal {
2612        self.gen_temp_local(ty, LocalSet)
2613    }
2614
2615    fn gen_temp_local(&mut self, ty: ValType, insn: fn(u32) -> Instruction<'static>) -> TempLocal {
2616        // First check to see if any locals are available in this function which
2617        // were previously generated but are no longer in use.
2618        if let Some(idx) = self.free_locals.get_mut(&ty).and_then(|v| v.pop()) {
2619            self.instruction(insn(idx));
2620            return TempLocal {
2621                ty,
2622                idx,
2623                needs_free: true,
2624            };
2625        }
2626
2627        // Failing that generate a fresh new local.
2628        let locals = &mut self.module.funcs[self.result].locals;
2629        match locals.last_mut() {
2630            Some((cnt, prev_ty)) if ty == *prev_ty => *cnt += 1,
2631            _ => locals.push((1, ty)),
2632        }
2633        self.nlocals += 1;
2634        let idx = self.nlocals - 1;
2635        self.instruction(insn(idx));
2636        TempLocal {
2637            ty,
2638            idx,
2639            needs_free: true,
2640        }
2641    }
2642
2643    /// Used to release a `TempLocal` from a particular lexical scope to allow
2644    /// its possible reuse in later scopes.
2645    fn free_temp_local(&mut self, mut local: TempLocal) {
2646        assert!(local.needs_free);
2647        self.free_locals
2648            .entry(local.ty)
2649            .or_insert(Vec::new())
2650            .push(local.idx);
2651        local.needs_free = false;
2652    }
2653
2654    fn instruction(&mut self, instr: Instruction) {
2655        instr.encode(&mut self.code);
2656    }
2657
2658    fn trap(&mut self, trap: Trap) {
2659        self.traps.push((self.code.len(), trap));
2660        self.instruction(Unreachable);
2661    }
2662
2663    /// Flushes out the current `code` instructions (and `traps` if there are
2664    /// any) into the destination function.
2665    ///
2666    /// This is a noop if no instructions have been encoded yet.
2667    fn flush_code(&mut self) {
2668        if self.code.is_empty() {
2669            return;
2670        }
2671        self.module.funcs[self.result].body.push(Body::Raw(
2672            mem::take(&mut self.code),
2673            mem::take(&mut self.traps),
2674        ));
2675    }
2676
2677    fn finish(mut self) {
2678        // Append the final `end` instruction which all functions require, and
2679        // then empty out the temporary buffer in `Compiler`.
2680        self.instruction(End);
2681        self.flush_code();
2682
2683        // Flag the function as "done" which helps with an assert later on in
2684        // emission that everything was eventually finished.
2685        self.module.funcs[self.result].filled_in = true;
2686    }
2687
2688    /// Fetches the value contained with the local specified by `stack` and
2689    /// converts it to `dst_ty`.
2690    ///
2691    /// This is only intended for use in primitive operations where `stack` is
2692    /// guaranteed to have only one local. The type of the local on the stack is
2693    /// then converted to `dst_ty` appropriately. Note that the types may be
2694    /// different due to the "flattening" of variant types.
2695    fn stack_get(&mut self, stack: &Stack<'_>, dst_ty: ValType) {
2696        assert_eq!(stack.locals.len(), 1);
2697        let (idx, src_ty) = stack.locals[0];
2698        self.instruction(LocalGet(idx));
2699        match (src_ty, dst_ty) {
2700            (ValType::I32, ValType::I32)
2701            | (ValType::I64, ValType::I64)
2702            | (ValType::F32, ValType::F32)
2703            | (ValType::F64, ValType::F64) => {}
2704
2705            (ValType::I32, ValType::F32) => self.instruction(F32ReinterpretI32),
2706            (ValType::I64, ValType::I32) => {
2707                self.assert_i64_upper_bits_not_set(idx);
2708                self.instruction(I32WrapI64);
2709            }
2710            (ValType::I64, ValType::F64) => self.instruction(F64ReinterpretI64),
2711            (ValType::I64, ValType::F32) => {
2712                self.assert_i64_upper_bits_not_set(idx);
2713                self.instruction(I32WrapI64);
2714                self.instruction(F32ReinterpretI32);
2715            }
2716
2717            // should not be possible given the `join` function for variants
2718            (ValType::I32, ValType::I64)
2719            | (ValType::I32, ValType::F64)
2720            | (ValType::F32, ValType::I32)
2721            | (ValType::F32, ValType::I64)
2722            | (ValType::F32, ValType::F64)
2723            | (ValType::F64, ValType::I32)
2724            | (ValType::F64, ValType::I64)
2725            | (ValType::F64, ValType::F32)
2726
2727            // not used in the component model
2728            | (ValType::Ref(_), _)
2729            | (_, ValType::Ref(_))
2730            | (ValType::V128, _)
2731            | (_, ValType::V128) => {
2732                panic!("cannot get {dst_ty:?} from {src_ty:?} local");
2733            }
2734        }
2735    }
2736
2737    fn assert_i64_upper_bits_not_set(&mut self, local: u32) {
2738        if !self.module.debug {
2739            return;
2740        }
2741        self.instruction(LocalGet(local));
2742        self.instruction(I64Const(32));
2743        self.instruction(I64ShrU);
2744        self.instruction(I32WrapI64);
2745        self.instruction(If(BlockType::Empty));
2746        self.trap(Trap::AssertFailed("upper bits are unexpectedly set"));
2747        self.instruction(End);
2748    }
2749
2750    /// Converts the top value on the WebAssembly stack which has type
2751    /// `src_ty` to `dst_tys[0]`.
2752    ///
2753    /// This is only intended for conversion of primitives where the `dst_tys`
2754    /// list is known to be of length 1.
2755    fn stack_set(&mut self, dst_tys: &[ValType], src_ty: ValType) {
2756        assert_eq!(dst_tys.len(), 1);
2757        let dst_ty = dst_tys[0];
2758        match (src_ty, dst_ty) {
2759            (ValType::I32, ValType::I32)
2760            | (ValType::I64, ValType::I64)
2761            | (ValType::F32, ValType::F32)
2762            | (ValType::F64, ValType::F64) => {}
2763
2764            (ValType::F32, ValType::I32) => self.instruction(I32ReinterpretF32),
2765            (ValType::I32, ValType::I64) => self.instruction(I64ExtendI32U),
2766            (ValType::F64, ValType::I64) => self.instruction(I64ReinterpretF64),
2767            (ValType::F32, ValType::I64) => {
2768                self.instruction(I32ReinterpretF32);
2769                self.instruction(I64ExtendI32U);
2770            }
2771
2772            // should not be possible given the `join` function for variants
2773            (ValType::I64, ValType::I32)
2774            | (ValType::F64, ValType::I32)
2775            | (ValType::I32, ValType::F32)
2776            | (ValType::I64, ValType::F32)
2777            | (ValType::F64, ValType::F32)
2778            | (ValType::I32, ValType::F64)
2779            | (ValType::I64, ValType::F64)
2780            | (ValType::F32, ValType::F64)
2781
2782            // not used in the component model
2783            | (ValType::Ref(_), _)
2784            | (_, ValType::Ref(_))
2785            | (ValType::V128, _)
2786            | (_, ValType::V128) => {
2787                panic!("cannot get {dst_ty:?} from {src_ty:?} local");
2788            }
2789        }
2790    }
2791
2792    fn i32_load8u(&mut self, mem: &Memory) {
2793        self.instruction(LocalGet(mem.addr.idx));
2794        self.instruction(I32Load8U(mem.memarg(0)));
2795    }
2796
2797    fn i32_load8s(&mut self, mem: &Memory) {
2798        self.instruction(LocalGet(mem.addr.idx));
2799        self.instruction(I32Load8S(mem.memarg(0)));
2800    }
2801
2802    fn i32_load16u(&mut self, mem: &Memory) {
2803        self.instruction(LocalGet(mem.addr.idx));
2804        self.instruction(I32Load16U(mem.memarg(1)));
2805    }
2806
2807    fn i32_load16s(&mut self, mem: &Memory) {
2808        self.instruction(LocalGet(mem.addr.idx));
2809        self.instruction(I32Load16S(mem.memarg(1)));
2810    }
2811
2812    fn i32_load(&mut self, mem: &Memory) {
2813        self.instruction(LocalGet(mem.addr.idx));
2814        self.instruction(I32Load(mem.memarg(2)));
2815    }
2816
2817    fn i64_load(&mut self, mem: &Memory) {
2818        self.instruction(LocalGet(mem.addr.idx));
2819        self.instruction(I64Load(mem.memarg(3)));
2820    }
2821
2822    fn ptr_load(&mut self, mem: &Memory) {
2823        if mem.opts.memory64 {
2824            self.i64_load(mem);
2825        } else {
2826            self.i32_load(mem);
2827        }
2828    }
2829
2830    fn ptr_add(&mut self, opts: &Options) {
2831        if opts.memory64 {
2832            self.instruction(I64Add);
2833        } else {
2834            self.instruction(I32Add);
2835        }
2836    }
2837
2838    fn ptr_sub(&mut self, opts: &Options) {
2839        if opts.memory64 {
2840            self.instruction(I64Sub);
2841        } else {
2842            self.instruction(I32Sub);
2843        }
2844    }
2845
2846    fn ptr_mul(&mut self, opts: &Options) {
2847        if opts.memory64 {
2848            self.instruction(I64Mul);
2849        } else {
2850            self.instruction(I32Mul);
2851        }
2852    }
2853
2854    fn ptr_ge_u(&mut self, opts: &Options) {
2855        if opts.memory64 {
2856            self.instruction(I64GeU);
2857        } else {
2858            self.instruction(I32GeU);
2859        }
2860    }
2861
2862    fn ptr_lt_u(&mut self, opts: &Options) {
2863        if opts.memory64 {
2864            self.instruction(I64LtU);
2865        } else {
2866            self.instruction(I32LtU);
2867        }
2868    }
2869
2870    fn ptr_shl(&mut self, opts: &Options) {
2871        if opts.memory64 {
2872            self.instruction(I64Shl);
2873        } else {
2874            self.instruction(I32Shl);
2875        }
2876    }
2877
2878    fn ptr_eqz(&mut self, opts: &Options) {
2879        if opts.memory64 {
2880            self.instruction(I64Eqz);
2881        } else {
2882            self.instruction(I32Eqz);
2883        }
2884    }
2885
2886    fn ptr_uconst(&mut self, opts: &Options, val: u32) {
2887        if opts.memory64 {
2888            self.instruction(I64Const(val.into()));
2889        } else {
2890            self.instruction(I32Const(val as i32));
2891        }
2892    }
2893
2894    fn ptr_iconst(&mut self, opts: &Options, val: i32) {
2895        if opts.memory64 {
2896            self.instruction(I64Const(val.into()));
2897        } else {
2898            self.instruction(I32Const(val));
2899        }
2900    }
2901
2902    fn ptr_eq(&mut self, opts: &Options) {
2903        if opts.memory64 {
2904            self.instruction(I64Eq);
2905        } else {
2906            self.instruction(I32Eq);
2907        }
2908    }
2909
2910    fn ptr_ne(&mut self, opts: &Options) {
2911        if opts.memory64 {
2912            self.instruction(I64Ne);
2913        } else {
2914            self.instruction(I32Ne);
2915        }
2916    }
2917
2918    fn ptr_and(&mut self, opts: &Options) {
2919        if opts.memory64 {
2920            self.instruction(I64And);
2921        } else {
2922            self.instruction(I32And);
2923        }
2924    }
2925
2926    fn ptr_or(&mut self, opts: &Options) {
2927        if opts.memory64 {
2928            self.instruction(I64Or);
2929        } else {
2930            self.instruction(I32Or);
2931        }
2932    }
2933
2934    fn ptr_xor(&mut self, opts: &Options) {
2935        if opts.memory64 {
2936            self.instruction(I64Xor);
2937        } else {
2938            self.instruction(I32Xor);
2939        }
2940    }
2941
2942    fn ptr_if(&mut self, opts: &Options, ty: BlockType) {
2943        if opts.memory64 {
2944            self.instruction(I64Const(0));
2945            self.instruction(I64Ne);
2946        }
2947        self.instruction(If(ty));
2948    }
2949
2950    fn ptr_br_if(&mut self, opts: &Options, depth: u32) {
2951        if opts.memory64 {
2952            self.instruction(I64Const(0));
2953            self.instruction(I64Ne);
2954        }
2955        self.instruction(BrIf(depth));
2956    }
2957
2958    fn f32_load(&mut self, mem: &Memory) {
2959        self.instruction(LocalGet(mem.addr.idx));
2960        self.instruction(F32Load(mem.memarg(2)));
2961    }
2962
2963    fn f64_load(&mut self, mem: &Memory) {
2964        self.instruction(LocalGet(mem.addr.idx));
2965        self.instruction(F64Load(mem.memarg(3)));
2966    }
2967
2968    fn push_dst_addr(&mut self, dst: &Destination) {
2969        if let Destination::Memory(mem) = dst {
2970            self.instruction(LocalGet(mem.addr.idx));
2971        }
2972    }
2973
2974    fn i32_store8(&mut self, mem: &Memory) {
2975        self.instruction(I32Store8(mem.memarg(0)));
2976    }
2977
2978    fn i32_store16(&mut self, mem: &Memory) {
2979        self.instruction(I32Store16(mem.memarg(1)));
2980    }
2981
2982    fn i32_store(&mut self, mem: &Memory) {
2983        self.instruction(I32Store(mem.memarg(2)));
2984    }
2985
2986    fn i64_store(&mut self, mem: &Memory) {
2987        self.instruction(I64Store(mem.memarg(3)));
2988    }
2989
2990    fn ptr_store(&mut self, mem: &Memory) {
2991        if mem.opts.memory64 {
2992            self.i64_store(mem);
2993        } else {
2994            self.i32_store(mem);
2995        }
2996    }
2997
2998    fn f32_store(&mut self, mem: &Memory) {
2999        self.instruction(F32Store(mem.memarg(2)));
3000    }
3001
3002    fn f64_store(&mut self, mem: &Memory) {
3003        self.instruction(F64Store(mem.memarg(3)));
3004    }
3005}
3006
3007impl<'a> Source<'a> {
3008    /// Given this `Source` returns an iterator over the `Source` for each of
3009    /// the component `fields` specified.
3010    ///
3011    /// This will automatically slice stack-based locals to the appropriate
3012    /// width for each component type and additionally calculate the appropriate
3013    /// offset for each memory-based type.
3014    fn record_field_srcs<'b>(
3015        &'b self,
3016        types: &'b ComponentTypesBuilder,
3017        fields: impl IntoIterator<Item = InterfaceType> + 'b,
3018    ) -> impl Iterator<Item = Source<'a>> + 'b
3019    where
3020        'a: 'b,
3021    {
3022        let mut offset = 0;
3023        fields.into_iter().map(move |ty| match self {
3024            Source::Memory(mem) => {
3025                let mem = next_field_offset(&mut offset, types, &ty, mem);
3026                Source::Memory(mem)
3027            }
3028            Source::Stack(stack) => {
3029                let cnt = types.flat_types(&ty).unwrap().len() as u32;
3030                offset += cnt;
3031                Source::Stack(stack.slice((offset - cnt) as usize..offset as usize))
3032            }
3033        })
3034    }
3035
3036    /// Returns the corresponding discriminant source and payload source f
3037    fn payload_src(
3038        &self,
3039        types: &ComponentTypesBuilder,
3040        info: &VariantInfo,
3041        case: Option<&InterfaceType>,
3042    ) -> Source<'a> {
3043        match self {
3044            Source::Stack(s) => {
3045                let flat_len = match case {
3046                    Some(case) => types.flat_types(case).unwrap().len(),
3047                    None => 0,
3048                };
3049                Source::Stack(s.slice(1..s.locals.len()).slice(0..flat_len))
3050            }
3051            Source::Memory(mem) => {
3052                let mem = if mem.opts.memory64 {
3053                    mem.bump(info.payload_offset64)
3054                } else {
3055                    mem.bump(info.payload_offset32)
3056                };
3057                Source::Memory(mem)
3058            }
3059        }
3060    }
3061
3062    fn opts(&self) -> &'a Options {
3063        match self {
3064            Source::Stack(s) => s.opts,
3065            Source::Memory(mem) => mem.opts,
3066        }
3067    }
3068}
3069
3070impl<'a> Destination<'a> {
3071    /// Same as `Source::record_field_srcs` but for destinations.
3072    fn record_field_dsts<'b>(
3073        &'b self,
3074        types: &'b ComponentTypesBuilder,
3075        fields: impl IntoIterator<Item = InterfaceType> + 'b,
3076    ) -> impl Iterator<Item = Destination> + 'b
3077    where
3078        'a: 'b,
3079    {
3080        let mut offset = 0;
3081        fields.into_iter().map(move |ty| match self {
3082            Destination::Memory(mem) => {
3083                let mem = next_field_offset(&mut offset, types, &ty, mem);
3084                Destination::Memory(mem)
3085            }
3086            Destination::Stack(s, opts) => {
3087                let cnt = types.flat_types(&ty).unwrap().len() as u32;
3088                offset += cnt;
3089                Destination::Stack(&s[(offset - cnt) as usize..offset as usize], opts)
3090            }
3091        })
3092    }
3093
3094    /// Returns the corresponding discriminant source and payload source f
3095    fn payload_dst(
3096        &self,
3097        types: &ComponentTypesBuilder,
3098        info: &VariantInfo,
3099        case: Option<&InterfaceType>,
3100    ) -> Destination {
3101        match self {
3102            Destination::Stack(s, opts) => {
3103                let flat_len = match case {
3104                    Some(case) => types.flat_types(case).unwrap().len(),
3105                    None => 0,
3106                };
3107                Destination::Stack(&s[1..][..flat_len], opts)
3108            }
3109            Destination::Memory(mem) => {
3110                let mem = if mem.opts.memory64 {
3111                    mem.bump(info.payload_offset64)
3112                } else {
3113                    mem.bump(info.payload_offset32)
3114                };
3115                Destination::Memory(mem)
3116            }
3117        }
3118    }
3119
3120    fn opts(&self) -> &'a Options {
3121        match self {
3122            Destination::Stack(_, opts) => opts,
3123            Destination::Memory(mem) => mem.opts,
3124        }
3125    }
3126}
3127
3128fn next_field_offset<'a>(
3129    offset: &mut u32,
3130    types: &ComponentTypesBuilder,
3131    field: &InterfaceType,
3132    mem: &Memory<'a>,
3133) -> Memory<'a> {
3134    let abi = types.canonical_abi(field);
3135    let offset = if mem.opts.memory64 {
3136        abi.next_field64(offset)
3137    } else {
3138        abi.next_field32(offset)
3139    };
3140    mem.bump(offset)
3141}
3142
3143impl<'a> Memory<'a> {
3144    fn memarg(&self, align: u32) -> MemArg {
3145        MemArg {
3146            offset: u64::from(self.offset),
3147            align,
3148            memory_index: self.opts.memory.unwrap().as_u32(),
3149        }
3150    }
3151
3152    fn bump(&self, offset: u32) -> Memory<'a> {
3153        Memory {
3154            opts: self.opts,
3155            addr: TempLocal::new(self.addr.idx, self.addr.ty),
3156            offset: self.offset + offset,
3157        }
3158    }
3159}
3160
3161impl<'a> Stack<'a> {
3162    fn slice(&self, range: Range<usize>) -> Stack<'a> {
3163        Stack {
3164            locals: &self.locals[range],
3165            opts: self.opts,
3166        }
3167    }
3168}
3169
3170struct VariantCase<'a> {
3171    src_i: u32,
3172    src_ty: Option<&'a InterfaceType>,
3173    dst_i: u32,
3174    dst_ty: Option<&'a InterfaceType>,
3175}
3176
3177fn variant_info<'a, I>(types: &ComponentTypesBuilder, cases: I) -> VariantInfo
3178where
3179    I: IntoIterator<Item = Option<&'a InterfaceType>>,
3180    I::IntoIter: ExactSizeIterator,
3181{
3182    VariantInfo::new(
3183        cases
3184            .into_iter()
3185            .map(|ty| ty.map(|ty| types.canonical_abi(ty))),
3186    )
3187    .0
3188}
3189
3190enum MallocSize {
3191    Const(u32),
3192    Local(u32),
3193}
3194
3195struct WasmString<'a> {
3196    ptr: TempLocal,
3197    len: TempLocal,
3198    opts: &'a Options,
3199}
3200
3201struct TempLocal {
3202    idx: u32,
3203    ty: ValType,
3204    needs_free: bool,
3205}
3206
3207impl TempLocal {
3208    fn new(idx: u32, ty: ValType) -> TempLocal {
3209        TempLocal {
3210            idx,
3211            ty,
3212            needs_free: false,
3213        }
3214    }
3215}
3216
3217impl std::ops::Drop for TempLocal {
3218    fn drop(&mut self) {
3219        if self.needs_free {
3220            panic!("temporary local not free'd");
3221        }
3222    }
3223}
3224
3225impl From<FlatType> for ValType {
3226    fn from(ty: FlatType) -> ValType {
3227        match ty {
3228            FlatType::I32 => ValType::I32,
3229            FlatType::I64 => ValType::I64,
3230            FlatType::F32 => ValType::F32,
3231            FlatType::F64 => ValType::F64,
3232        }
3233    }
3234}