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