1use 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
42const 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 code: Vec<u8>,
53
54 nlocals: u32,
56
57 free_locals: HashMap<ValType, Vec<u32>>,
59
60 traps: Vec<(usize, Trap)>,
64
65 fuel: usize,
74
75 emit_resource_call: bool,
80}
81
82pub(super) fn compile(module: &mut Module<'_>, adapter: &AdapterData) {
83 let lower_sig = module.types.signature(&adapter.lower, Context::Lower);
84 let lift_sig = module.types.signature(&adapter.lift, Context::Lift);
85 let ty = module
86 .core_types
87 .function(&lower_sig.params, &lower_sig.results);
88 let result = module
89 .funcs
90 .push(Function::new(Some(adapter.name.clone()), ty));
91
92 let emit_resource_call = module.types.contains_borrow_resource(&adapter.lower);
97 assert_eq!(
98 emit_resource_call,
99 module.types.contains_borrow_resource(&adapter.lift)
100 );
101
102 Compiler {
103 types: module.types,
104 module,
105 code: Vec::new(),
106 nlocals: lower_sig.params.len() as u32,
107 free_locals: HashMap::new(),
108 traps: Vec::new(),
109 result,
110 fuel: INITIAL_FUEL,
111 emit_resource_call,
112 }
113 .compile_adapter(adapter, &lower_sig, &lift_sig)
114}
115
116pub(super) fn compile_helper(module: &mut Module<'_>, result: FunctionId, helper: Helper) {
123 let mut nlocals = 0;
124 let src_flat;
125 let src = match helper.src.loc {
126 HelperLocation::Stack => {
131 src_flat = module
132 .types
133 .flatten_types(&helper.src.opts, usize::MAX, [helper.src.ty])
134 .unwrap()
135 .iter()
136 .enumerate()
137 .map(|(i, ty)| (i as u32, *ty))
138 .collect::<Vec<_>>();
139 nlocals += src_flat.len() as u32;
140 Source::Stack(Stack {
141 locals: &src_flat,
142 opts: &helper.src.opts,
143 })
144 }
145 HelperLocation::Memory => {
148 nlocals += 1;
149 Source::Memory(Memory {
150 opts: &helper.src.opts,
151 addr: TempLocal::new(0, helper.src.opts.ptr()),
152 offset: 0,
153 })
154 }
155 };
156 let dst_flat;
157 let dst = match helper.dst.loc {
158 HelperLocation::Stack => {
161 dst_flat = module
162 .types
163 .flatten_types(&helper.dst.opts, usize::MAX, [helper.dst.ty])
164 .unwrap();
165 Destination::Stack(&dst_flat, &helper.dst.opts)
166 }
167 HelperLocation::Memory => {
170 nlocals += 1;
171 Destination::Memory(Memory {
172 opts: &helper.dst.opts,
173 addr: TempLocal::new(nlocals - 1, helper.dst.opts.ptr()),
174 offset: 0,
175 })
176 }
177 };
178 let mut compiler = Compiler {
179 types: module.types,
180 module,
181 code: Vec::new(),
182 nlocals,
183 free_locals: HashMap::new(),
184 traps: Vec::new(),
185 result,
186 fuel: INITIAL_FUEL,
187 emit_resource_call: false,
190 };
191 compiler.translate(&helper.src.ty, &src, &helper.dst.ty, &dst);
192 compiler.finish();
193}
194
195enum Source<'a> {
198 Stack(Stack<'a>),
204
205 Memory(Memory<'a>),
208}
209
210enum Destination<'a> {
212 Stack(&'a [ValType], &'a Options),
218
219 Memory(Memory<'a>),
221}
222
223struct Stack<'a> {
224 locals: &'a [(u32, ValType)],
230 opts: &'a Options,
232}
233
234struct Memory<'a> {
236 opts: &'a Options,
238 addr: TempLocal,
241 offset: u32,
244}
245
246impl Compiler<'_, '_> {
247 fn compile_adapter(
248 mut self,
249 adapter: &AdapterData,
250 lower_sig: &Signature,
251 lift_sig: &Signature,
252 ) {
253 self.trap_if_not_flag(adapter.lower.flags, FLAG_MAY_LEAVE, Trap::CannotLeave);
259 if adapter.called_as_export {
260 self.trap_if_not_flag(adapter.lift.flags, FLAG_MAY_ENTER, Trap::CannotEnter);
261 self.set_flag(adapter.lift.flags, FLAG_MAY_ENTER, false);
262 } else if self.module.debug {
263 self.assert_not_flag(
264 adapter.lift.flags,
265 FLAG_MAY_ENTER,
266 "may_enter should be unset",
267 );
268 }
269
270 if self.emit_resource_call {
271 let enter = self.module.import_resource_enter_call();
272 self.instruction(Call(enter.as_u32()));
273 }
274
275 self.set_flag(adapter.lift.flags, FLAG_MAY_LEAVE, false);
288 let param_locals = lower_sig
289 .params
290 .iter()
291 .enumerate()
292 .map(|(i, ty)| (i as u32, *ty))
293 .collect::<Vec<_>>();
294 self.translate_params(adapter, ¶m_locals);
295 self.set_flag(adapter.lift.flags, FLAG_MAY_LEAVE, true);
296
297 self.instruction(Call(adapter.callee.as_u32()));
301 let mut result_locals = Vec::with_capacity(lift_sig.results.len());
302 let mut temps = Vec::new();
303 for ty in lift_sig.results.iter().rev() {
304 let local = self.local_set_new_tmp(*ty);
305 result_locals.push((local.idx, *ty));
306 temps.push(local);
307 }
308 result_locals.reverse();
309
310 self.set_flag(adapter.lower.flags, FLAG_MAY_LEAVE, false);
319 self.translate_results(adapter, ¶m_locals, &result_locals);
320 self.set_flag(adapter.lower.flags, FLAG_MAY_LEAVE, true);
321
322 if let Some(func) = adapter.lift.post_return {
325 for (result, _) in result_locals.iter() {
326 self.instruction(LocalGet(*result));
327 }
328 self.instruction(Call(func.as_u32()));
329 }
330 if adapter.called_as_export {
331 self.set_flag(adapter.lift.flags, FLAG_MAY_ENTER, true);
332 }
333
334 for tmp in temps {
335 self.free_temp_local(tmp);
336 }
337
338 if self.emit_resource_call {
339 let exit = self.module.import_resource_exit_call();
340 self.instruction(Call(exit.as_u32()));
341 }
342
343 self.finish()
344 }
345
346 fn translate_params(&mut self, adapter: &AdapterData, param_locals: &[(u32, ValType)]) {
347 let src_tys = self.types[adapter.lower.ty].params;
348 let src_tys = self.types[src_tys]
349 .types
350 .iter()
351 .copied()
352 .collect::<Vec<_>>();
353 let dst_tys = self.types[adapter.lift.ty].params;
354 let dst_tys = self.types[dst_tys]
355 .types
356 .iter()
357 .copied()
358 .collect::<Vec<_>>();
359 let lift_opts = &adapter.lift.options;
360 let lower_opts = &adapter.lower.options;
361
362 assert_eq!(src_tys.len(), dst_tys.len());
364
365 let src_flat =
366 self.types
367 .flatten_types(lower_opts, MAX_FLAT_PARAMS, src_tys.iter().copied());
368 let dst_flat =
369 self.types
370 .flatten_types(lift_opts, MAX_FLAT_PARAMS, dst_tys.iter().copied());
371
372 let src = if let Some(flat) = &src_flat {
373 Source::Stack(Stack {
374 locals: ¶m_locals[..flat.len()],
375 opts: lower_opts,
376 })
377 } else {
378 let (addr, ty) = param_locals[0];
382 assert_eq!(ty, lower_opts.ptr());
383 let align = src_tys
384 .iter()
385 .map(|t| self.types.align(lower_opts, t))
386 .max()
387 .unwrap_or(1);
388 Source::Memory(self.memory_operand(lower_opts, TempLocal::new(addr, ty), align))
389 };
390
391 let dst = if let Some(flat) = &dst_flat {
392 Destination::Stack(flat, lift_opts)
393 } else {
394 let abi = CanonicalAbiInfo::record(dst_tys.iter().map(|t| self.types.canonical_abi(t)));
397 let (size, align) = if lift_opts.memory64 {
398 (abi.size64, abi.align64)
399 } else {
400 (abi.size32, abi.align32)
401 };
402 let size = MallocSize::Const(size);
403 Destination::Memory(self.malloc(lift_opts, size, align))
404 };
405
406 let srcs = src
407 .record_field_srcs(self.types, src_tys.iter().copied())
408 .zip(src_tys.iter());
409 let dsts = dst
410 .record_field_dsts(self.types, dst_tys.iter().copied())
411 .zip(dst_tys.iter());
412 for ((src, src_ty), (dst, dst_ty)) in srcs.zip(dsts) {
413 self.translate(&src_ty, &src, &dst_ty, &dst);
414 }
415
416 if let Destination::Memory(mem) = dst {
420 self.instruction(LocalGet(mem.addr.idx));
421 self.free_temp_local(mem.addr);
422 }
423 }
424
425 fn translate_results(
426 &mut self,
427 adapter: &AdapterData,
428 param_locals: &[(u32, ValType)],
429 result_locals: &[(u32, ValType)],
430 ) {
431 let src_tys = self.types[adapter.lift.ty].results;
432 let src_tys = self.types[src_tys]
433 .types
434 .iter()
435 .copied()
436 .collect::<Vec<_>>();
437 let dst_tys = self.types[adapter.lower.ty].results;
438 let dst_tys = self.types[dst_tys]
439 .types
440 .iter()
441 .copied()
442 .collect::<Vec<_>>();
443 let lift_opts = &adapter.lift.options;
444 let lower_opts = &adapter.lower.options;
445
446 let src_flat =
447 self.types
448 .flatten_types(lift_opts, MAX_FLAT_RESULTS, src_tys.iter().copied());
449 let dst_flat =
450 self.types
451 .flatten_types(lower_opts, MAX_FLAT_RESULTS, dst_tys.iter().copied());
452
453 let src = if src_flat.is_some() {
454 Source::Stack(Stack {
455 locals: result_locals,
456 opts: lift_opts,
457 })
458 } else {
459 let align = src_tys
464 .iter()
465 .map(|t| self.types.align(lift_opts, t))
466 .max()
467 .unwrap_or(1);
468 assert_eq!(result_locals.len(), 1);
469 let (addr, ty) = result_locals[0];
470 assert_eq!(ty, lift_opts.ptr());
471 Source::Memory(self.memory_operand(lift_opts, TempLocal::new(addr, ty), align))
472 };
473
474 let dst = if let Some(flat) = &dst_flat {
475 Destination::Stack(flat, lower_opts)
476 } else {
477 let align = dst_tys
481 .iter()
482 .map(|t| self.types.align(lower_opts, t))
483 .max()
484 .unwrap_or(1);
485 let (addr, ty) = *param_locals.last().expect("no retptr");
486 assert_eq!(ty, lower_opts.ptr());
487 Destination::Memory(self.memory_operand(lower_opts, TempLocal::new(addr, ty), align))
488 };
489
490 let srcs = src
491 .record_field_srcs(self.types, src_tys.iter().copied())
492 .zip(src_tys.iter());
493 let dsts = dst
494 .record_field_dsts(self.types, dst_tys.iter().copied())
495 .zip(dst_tys.iter());
496 for ((src, src_ty), (dst, dst_ty)) in srcs.zip(dsts) {
497 self.translate(&src_ty, &src, &dst_ty, &dst);
498 }
499 }
500
501 fn translate(
502 &mut self,
503 src_ty: &InterfaceType,
504 src: &Source<'_>,
505 dst_ty: &InterfaceType,
506 dst: &Destination,
507 ) {
508 if let Source::Memory(mem) = src {
509 self.assert_aligned(src_ty, mem);
510 }
511 if let Destination::Memory(mem) = dst {
512 self.assert_aligned(dst_ty, mem);
513 }
514
515 let cost = match src_ty {
545 InterfaceType::Bool
549 | InterfaceType::U8
550 | InterfaceType::S8
551 | InterfaceType::U16
552 | InterfaceType::S16
553 | InterfaceType::U32
554 | InterfaceType::S32
555 | InterfaceType::U64
556 | InterfaceType::S64
557 | InterfaceType::Float32
558 | InterfaceType::Float64 => 0,
559
560 InterfaceType::Char => 1,
563
564 InterfaceType::String => 40,
567
568 InterfaceType::List(_) => 40,
571
572 InterfaceType::Flags(i) => {
573 let count = self.module.types[*i].names.len();
574 match FlagsSize::from_count(count) {
575 FlagsSize::Size0 => 0,
576 FlagsSize::Size1 | FlagsSize::Size2 => 1,
577 FlagsSize::Size4Plus(n) => n.into(),
578 }
579 }
580
581 InterfaceType::Record(i) => self.types[*i].fields.len(),
582 InterfaceType::Tuple(i) => self.types[*i].types.len(),
583 InterfaceType::Variant(i) => self.types[*i].cases.len(),
584 InterfaceType::Enum(i) => self.types[*i].names.len(),
585
586 InterfaceType::Option(_) | InterfaceType::Result(_) => 2,
588
589 InterfaceType::Own(_) | InterfaceType::Borrow(_) => 1,
591 };
592
593 match self.fuel.checked_sub(cost) {
594 Some(n) => {
600 self.fuel = n;
601 match src_ty {
602 InterfaceType::Bool => self.translate_bool(src, dst_ty, dst),
603 InterfaceType::U8 => self.translate_u8(src, dst_ty, dst),
604 InterfaceType::S8 => self.translate_s8(src, dst_ty, dst),
605 InterfaceType::U16 => self.translate_u16(src, dst_ty, dst),
606 InterfaceType::S16 => self.translate_s16(src, dst_ty, dst),
607 InterfaceType::U32 => self.translate_u32(src, dst_ty, dst),
608 InterfaceType::S32 => self.translate_s32(src, dst_ty, dst),
609 InterfaceType::U64 => self.translate_u64(src, dst_ty, dst),
610 InterfaceType::S64 => self.translate_s64(src, dst_ty, dst),
611 InterfaceType::Float32 => self.translate_f32(src, dst_ty, dst),
612 InterfaceType::Float64 => self.translate_f64(src, dst_ty, dst),
613 InterfaceType::Char => self.translate_char(src, dst_ty, dst),
614 InterfaceType::String => self.translate_string(src, dst_ty, dst),
615 InterfaceType::List(t) => self.translate_list(*t, src, dst_ty, dst),
616 InterfaceType::Record(t) => self.translate_record(*t, src, dst_ty, dst),
617 InterfaceType::Flags(f) => self.translate_flags(*f, src, dst_ty, dst),
618 InterfaceType::Tuple(t) => self.translate_tuple(*t, src, dst_ty, dst),
619 InterfaceType::Variant(v) => self.translate_variant(*v, src, dst_ty, dst),
620 InterfaceType::Enum(t) => self.translate_enum(*t, src, dst_ty, dst),
621 InterfaceType::Option(t) => self.translate_option(*t, src, dst_ty, dst),
622 InterfaceType::Result(t) => self.translate_result(*t, src, dst_ty, dst),
623 InterfaceType::Own(t) => self.translate_own(*t, src, dst_ty, dst),
624 InterfaceType::Borrow(t) => self.translate_borrow(*t, src, dst_ty, dst),
625 }
626 }
627
628 None => {
634 let src_loc = match src {
635 Source::Stack(stack) => {
639 for (i, ty) in stack
640 .opts
641 .flat_types(src_ty, self.types)
642 .unwrap()
643 .iter()
644 .enumerate()
645 {
646 let stack = stack.slice(i..i + 1);
647 self.stack_get(&stack, (*ty).into());
648 }
649 HelperLocation::Stack
650 }
651 Source::Memory(mem) => {
656 self.push_mem_addr(mem);
657 HelperLocation::Memory
658 }
659 };
660 let dst_loc = match dst {
661 Destination::Stack(..) => HelperLocation::Stack,
662 Destination::Memory(mem) => {
663 self.push_mem_addr(mem);
664 HelperLocation::Memory
665 }
666 };
667 let helper = self.module.translate_helper(Helper {
673 src: HelperType {
674 ty: *src_ty,
675 opts: *src.opts(),
676 loc: src_loc,
677 },
678 dst: HelperType {
679 ty: *dst_ty,
680 opts: *dst.opts(),
681 loc: dst_loc,
682 },
683 });
684 self.flush_code();
687 self.module.funcs[self.result].body.push(Body::Call(helper));
688
689 if let Destination::Stack(tys, opts) = dst {
698 let flat = self
699 .types
700 .flatten_types(opts, usize::MAX, [*dst_ty])
701 .unwrap();
702 assert_eq!(flat.len(), tys.len());
703 let locals = flat
704 .iter()
705 .rev()
706 .map(|ty| self.local_set_new_tmp(*ty))
707 .collect::<Vec<_>>();
708 for (ty, local) in tys.iter().zip(locals.into_iter().rev()) {
709 self.instruction(LocalGet(local.idx));
710 self.stack_set(std::slice::from_ref(ty), local.ty);
711 self.free_temp_local(local);
712 }
713 }
714 }
715 }
716 }
717
718 fn push_mem_addr(&mut self, mem: &Memory<'_>) {
719 self.instruction(LocalGet(mem.addr.idx));
720 if mem.offset != 0 {
721 self.ptr_uconst(mem.opts, mem.offset);
722 self.ptr_add(mem.opts);
723 }
724 }
725
726 fn translate_bool(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
727 assert!(matches!(dst_ty, InterfaceType::Bool));
729 self.push_dst_addr(dst);
730
731 self.instruction(I32Const(1));
734 self.instruction(I32Const(0));
735 match src {
736 Source::Memory(mem) => self.i32_load8u(mem),
737 Source::Stack(stack) => self.stack_get(stack, ValType::I32),
738 }
739 self.instruction(Select);
740
741 match dst {
742 Destination::Memory(mem) => self.i32_store8(mem),
743 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
744 }
745 }
746
747 fn translate_u8(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
748 assert!(matches!(dst_ty, InterfaceType::U8));
750 self.convert_u8_mask(src, dst, 0xff);
751 }
752
753 fn convert_u8_mask(&mut self, src: &Source<'_>, dst: &Destination<'_>, mask: u8) {
754 self.push_dst_addr(dst);
755 let mut needs_mask = true;
756 match src {
757 Source::Memory(mem) => {
758 self.i32_load8u(mem);
759 needs_mask = mask != 0xff;
760 }
761 Source::Stack(stack) => {
762 self.stack_get(stack, ValType::I32);
763 }
764 }
765 if needs_mask {
766 self.instruction(I32Const(i32::from(mask)));
767 self.instruction(I32And);
768 }
769 match dst {
770 Destination::Memory(mem) => self.i32_store8(mem),
771 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
772 }
773 }
774
775 fn translate_s8(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
776 assert!(matches!(dst_ty, InterfaceType::S8));
778 self.push_dst_addr(dst);
779 match src {
780 Source::Memory(mem) => self.i32_load8s(mem),
781 Source::Stack(stack) => {
782 self.stack_get(stack, ValType::I32);
783 self.instruction(I32Extend8S);
784 }
785 }
786 match dst {
787 Destination::Memory(mem) => self.i32_store8(mem),
788 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
789 }
790 }
791
792 fn translate_u16(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
793 assert!(matches!(dst_ty, InterfaceType::U16));
795 self.convert_u16_mask(src, dst, 0xffff);
796 }
797
798 fn convert_u16_mask(&mut self, src: &Source<'_>, dst: &Destination<'_>, mask: u16) {
799 self.push_dst_addr(dst);
800 let mut needs_mask = true;
801 match src {
802 Source::Memory(mem) => {
803 self.i32_load16u(mem);
804 needs_mask = mask != 0xffff;
805 }
806 Source::Stack(stack) => {
807 self.stack_get(stack, ValType::I32);
808 }
809 }
810 if needs_mask {
811 self.instruction(I32Const(i32::from(mask)));
812 self.instruction(I32And);
813 }
814 match dst {
815 Destination::Memory(mem) => self.i32_store16(mem),
816 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
817 }
818 }
819
820 fn translate_s16(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
821 assert!(matches!(dst_ty, InterfaceType::S16));
823 self.push_dst_addr(dst);
824 match src {
825 Source::Memory(mem) => self.i32_load16s(mem),
826 Source::Stack(stack) => {
827 self.stack_get(stack, ValType::I32);
828 self.instruction(I32Extend16S);
829 }
830 }
831 match dst {
832 Destination::Memory(mem) => self.i32_store16(mem),
833 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
834 }
835 }
836
837 fn translate_u32(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
838 assert!(matches!(dst_ty, InterfaceType::U32));
840 self.convert_u32_mask(src, dst, 0xffffffff)
841 }
842
843 fn convert_u32_mask(&mut self, src: &Source<'_>, dst: &Destination<'_>, mask: u32) {
844 self.push_dst_addr(dst);
845 match src {
846 Source::Memory(mem) => self.i32_load(mem),
847 Source::Stack(stack) => self.stack_get(stack, ValType::I32),
848 }
849 if mask != 0xffffffff {
850 self.instruction(I32Const(mask as i32));
851 self.instruction(I32And);
852 }
853 match dst {
854 Destination::Memory(mem) => self.i32_store(mem),
855 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
856 }
857 }
858
859 fn translate_s32(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
860 assert!(matches!(dst_ty, InterfaceType::S32));
862 self.push_dst_addr(dst);
863 match src {
864 Source::Memory(mem) => self.i32_load(mem),
865 Source::Stack(stack) => self.stack_get(stack, ValType::I32),
866 }
867 match dst {
868 Destination::Memory(mem) => self.i32_store(mem),
869 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
870 }
871 }
872
873 fn translate_u64(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
874 assert!(matches!(dst_ty, InterfaceType::U64));
876 self.push_dst_addr(dst);
877 match src {
878 Source::Memory(mem) => self.i64_load(mem),
879 Source::Stack(stack) => self.stack_get(stack, ValType::I64),
880 }
881 match dst {
882 Destination::Memory(mem) => self.i64_store(mem),
883 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I64),
884 }
885 }
886
887 fn translate_s64(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
888 assert!(matches!(dst_ty, InterfaceType::S64));
890 self.push_dst_addr(dst);
891 match src {
892 Source::Memory(mem) => self.i64_load(mem),
893 Source::Stack(stack) => self.stack_get(stack, ValType::I64),
894 }
895 match dst {
896 Destination::Memory(mem) => self.i64_store(mem),
897 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I64),
898 }
899 }
900
901 fn translate_f32(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
902 assert!(matches!(dst_ty, InterfaceType::Float32));
904 self.push_dst_addr(dst);
905 match src {
906 Source::Memory(mem) => self.f32_load(mem),
907 Source::Stack(stack) => self.stack_get(stack, ValType::F32),
908 }
909 match dst {
910 Destination::Memory(mem) => self.f32_store(mem),
911 Destination::Stack(stack, _) => self.stack_set(stack, ValType::F32),
912 }
913 }
914
915 fn translate_f64(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
916 assert!(matches!(dst_ty, InterfaceType::Float64));
918 self.push_dst_addr(dst);
919 match src {
920 Source::Memory(mem) => self.f64_load(mem),
921 Source::Stack(stack) => self.stack_get(stack, ValType::F64),
922 }
923 match dst {
924 Destination::Memory(mem) => self.f64_store(mem),
925 Destination::Stack(stack, _) => self.stack_set(stack, ValType::F64),
926 }
927 }
928
929 fn translate_char(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
930 assert!(matches!(dst_ty, InterfaceType::Char));
931 match src {
932 Source::Memory(mem) => self.i32_load(mem),
933 Source::Stack(stack) => self.stack_get(stack, ValType::I32),
934 }
935 let local = self.local_set_new_tmp(ValType::I32);
936
937 self.instruction(Block(BlockType::Empty));
953 self.instruction(Block(BlockType::Empty));
954 self.instruction(LocalGet(local.idx));
955 self.instruction(I32Const(0xd800));
956 self.instruction(I32Xor);
957 self.instruction(I32Const(-0x110000));
958 self.instruction(I32Add);
959 self.instruction(I32Const(-0x10f800));
960 self.instruction(I32LtU);
961 self.instruction(BrIf(0));
962 self.instruction(LocalGet(local.idx));
963 self.instruction(I32Const(0x110000));
964 self.instruction(I32Ne);
965 self.instruction(BrIf(1));
966 self.instruction(End);
967 self.trap(Trap::InvalidChar);
968 self.instruction(End);
969
970 self.push_dst_addr(dst);
971 self.instruction(LocalGet(local.idx));
972 match dst {
973 Destination::Memory(mem) => {
974 self.i32_store(mem);
975 }
976 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
977 }
978
979 self.free_temp_local(local);
980 }
981
982 fn translate_string(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
983 assert!(matches!(dst_ty, InterfaceType::String));
984 let src_opts = src.opts();
985 let dst_opts = dst.opts();
986
987 match src {
992 Source::Stack(s) => {
993 assert_eq!(s.locals.len(), 2);
994 self.stack_get(&s.slice(0..1), src_opts.ptr());
995 self.stack_get(&s.slice(1..2), src_opts.ptr());
996 }
997 Source::Memory(mem) => {
998 self.ptr_load(mem);
999 self.ptr_load(&mem.bump(src_opts.ptr_size().into()));
1000 }
1001 }
1002 let src_len = self.local_set_new_tmp(src_opts.ptr());
1003 let src_ptr = self.local_set_new_tmp(src_opts.ptr());
1004 let src_str = WasmString {
1005 ptr: src_ptr,
1006 len: src_len,
1007 opts: src_opts,
1008 };
1009
1010 let dst_str = match src_opts.string_encoding {
1011 StringEncoding::Utf8 => match dst_opts.string_encoding {
1012 StringEncoding::Utf8 => self.string_copy(&src_str, FE::Utf8, dst_opts, FE::Utf8),
1013 StringEncoding::Utf16 => self.string_utf8_to_utf16(&src_str, dst_opts),
1014 StringEncoding::CompactUtf16 => {
1015 self.string_to_compact(&src_str, FE::Utf8, dst_opts)
1016 }
1017 },
1018
1019 StringEncoding::Utf16 => {
1020 self.verify_aligned(src_opts, src_str.ptr.idx, 2);
1021 match dst_opts.string_encoding {
1022 StringEncoding::Utf8 => {
1023 self.string_deflate_to_utf8(&src_str, FE::Utf16, dst_opts)
1024 }
1025 StringEncoding::Utf16 => {
1026 self.string_copy(&src_str, FE::Utf16, dst_opts, FE::Utf16)
1027 }
1028 StringEncoding::CompactUtf16 => {
1029 self.string_to_compact(&src_str, FE::Utf16, dst_opts)
1030 }
1031 }
1032 }
1033
1034 StringEncoding::CompactUtf16 => {
1035 self.verify_aligned(src_opts, src_str.ptr.idx, 2);
1036
1037 self.instruction(LocalGet(src_str.len.idx));
1040 self.ptr_uconst(src_opts, UTF16_TAG);
1041 self.ptr_and(src_opts);
1042 self.ptr_if(src_opts, BlockType::Empty);
1043
1044 self.instruction(LocalGet(src_str.len.idx));
1048 self.ptr_uconst(src_opts, UTF16_TAG);
1049 self.ptr_xor(src_opts);
1050 self.instruction(LocalSet(src_str.len.idx));
1051 let s1 = match dst_opts.string_encoding {
1052 StringEncoding::Utf8 => {
1053 self.string_deflate_to_utf8(&src_str, FE::Utf16, dst_opts)
1054 }
1055 StringEncoding::Utf16 => {
1056 self.string_copy(&src_str, FE::Utf16, dst_opts, FE::Utf16)
1057 }
1058 StringEncoding::CompactUtf16 => {
1059 self.string_compact_utf16_to_compact(&src_str, dst_opts)
1060 }
1061 };
1062
1063 self.instruction(Else);
1064
1065 let s2 = match dst_opts.string_encoding {
1069 StringEncoding::Utf16 => {
1070 self.string_copy(&src_str, FE::Latin1, dst_opts, FE::Utf16)
1071 }
1072 StringEncoding::Utf8 => {
1073 self.string_deflate_to_utf8(&src_str, FE::Latin1, dst_opts)
1074 }
1075 StringEncoding::CompactUtf16 => {
1076 self.string_copy(&src_str, FE::Latin1, dst_opts, FE::Latin1)
1077 }
1078 };
1079 self.instruction(LocalGet(s2.ptr.idx));
1082 self.instruction(LocalSet(s1.ptr.idx));
1083 self.instruction(LocalGet(s2.len.idx));
1084 self.instruction(LocalSet(s1.len.idx));
1085 self.instruction(End);
1086 self.free_temp_local(s2.ptr);
1087 self.free_temp_local(s2.len);
1088 s1
1089 }
1090 };
1091
1092 match dst {
1094 Destination::Stack(s, _) => {
1095 self.instruction(LocalGet(dst_str.ptr.idx));
1096 self.stack_set(&s[..1], dst_opts.ptr());
1097 self.instruction(LocalGet(dst_str.len.idx));
1098 self.stack_set(&s[1..], dst_opts.ptr());
1099 }
1100 Destination::Memory(mem) => {
1101 self.instruction(LocalGet(mem.addr.idx));
1102 self.instruction(LocalGet(dst_str.ptr.idx));
1103 self.ptr_store(mem);
1104 self.instruction(LocalGet(mem.addr.idx));
1105 self.instruction(LocalGet(dst_str.len.idx));
1106 self.ptr_store(&mem.bump(dst_opts.ptr_size().into()));
1107 }
1108 }
1109
1110 self.free_temp_local(src_str.ptr);
1111 self.free_temp_local(src_str.len);
1112 self.free_temp_local(dst_str.ptr);
1113 self.free_temp_local(dst_str.len);
1114 }
1115
1116 fn string_copy<'a>(
1129 &mut self,
1130 src: &WasmString<'_>,
1131 src_enc: FE,
1132 dst_opts: &'a Options,
1133 dst_enc: FE,
1134 ) -> WasmString<'a> {
1135 assert!(dst_enc.width() >= src_enc.width());
1136 self.validate_string_length(src, dst_enc);
1137
1138 let mut src_byte_len_tmp = None;
1142 let src_byte_len = if src_enc.width() == 1 {
1143 src.len.idx
1144 } else {
1145 assert_eq!(src_enc.width(), 2);
1146 self.instruction(LocalGet(src.len.idx));
1147 self.ptr_uconst(src.opts, 1);
1148 self.ptr_shl(src.opts);
1149 let tmp = self.local_set_new_tmp(src.opts.ptr());
1150 let ret = tmp.idx;
1151 src_byte_len_tmp = Some(tmp);
1152 ret
1153 };
1154
1155 self.convert_src_len_to_dst(src.len.idx, src.opts.ptr(), dst_opts.ptr());
1158 let dst_len = self.local_tee_new_tmp(dst_opts.ptr());
1159 if dst_enc.width() > 1 {
1160 assert_eq!(dst_enc.width(), 2);
1161 self.ptr_uconst(dst_opts, 1);
1162 self.ptr_shl(dst_opts);
1163 }
1164 let dst_byte_len = self.local_set_new_tmp(dst_opts.ptr());
1165
1166 let dst = {
1169 let dst_mem = self.malloc(
1170 dst_opts,
1171 MallocSize::Local(dst_byte_len.idx),
1172 dst_enc.width().into(),
1173 );
1174 WasmString {
1175 ptr: dst_mem.addr,
1176 len: dst_len,
1177 opts: dst_opts,
1178 }
1179 };
1180
1181 self.validate_string_inbounds(src, src_byte_len);
1186 self.validate_string_inbounds(&dst, dst_byte_len.idx);
1187
1188 let op = if src_enc == dst_enc {
1192 Transcode::Copy(src_enc)
1193 } else {
1194 assert_eq!(src_enc, FE::Latin1);
1195 assert_eq!(dst_enc, FE::Utf16);
1196 Transcode::Latin1ToUtf16
1197 };
1198 let transcode = self.transcoder(src, &dst, op);
1199 self.instruction(LocalGet(src.ptr.idx));
1200 self.instruction(LocalGet(src.len.idx));
1201 self.instruction(LocalGet(dst.ptr.idx));
1202 self.instruction(Call(transcode.as_u32()));
1203
1204 self.free_temp_local(dst_byte_len);
1205 if let Some(tmp) = src_byte_len_tmp {
1206 self.free_temp_local(tmp);
1207 }
1208
1209 dst
1210 }
1211 fn string_deflate_to_utf8<'a>(
1224 &mut self,
1225 src: &WasmString<'_>,
1226 src_enc: FE,
1227 dst_opts: &'a Options,
1228 ) -> WasmString<'a> {
1229 self.validate_string_length(src, src_enc);
1230
1231 self.convert_src_len_to_dst(src.len.idx, src.opts.ptr(), dst_opts.ptr());
1235 let dst_len = self.local_tee_new_tmp(dst_opts.ptr());
1236 let dst_byte_len = self.local_set_new_tmp(dst_opts.ptr());
1237
1238 let dst = {
1239 let dst_mem = self.malloc(dst_opts, MallocSize::Local(dst_byte_len.idx), 1);
1240 WasmString {
1241 ptr: dst_mem.addr,
1242 len: dst_len,
1243 opts: dst_opts,
1244 }
1245 };
1246
1247 let mut src_byte_len_tmp = None;
1249 let src_byte_len = match src_enc {
1250 FE::Latin1 => src.len.idx,
1251 FE::Utf16 => {
1252 self.instruction(LocalGet(src.len.idx));
1253 self.ptr_uconst(src.opts, 1);
1254 self.ptr_shl(src.opts);
1255 let tmp = self.local_set_new_tmp(src.opts.ptr());
1256 let ret = tmp.idx;
1257 src_byte_len_tmp = Some(tmp);
1258 ret
1259 }
1260 FE::Utf8 => unreachable!(),
1261 };
1262 self.validate_string_inbounds(src, src_byte_len);
1263 self.validate_string_inbounds(&dst, dst_byte_len.idx);
1264
1265 let op = match src_enc {
1267 FE::Latin1 => Transcode::Latin1ToUtf8,
1268 FE::Utf16 => Transcode::Utf16ToUtf8,
1269 FE::Utf8 => unreachable!(),
1270 };
1271 let transcode = self.transcoder(src, &dst, op);
1272 self.instruction(LocalGet(src.ptr.idx));
1273 self.instruction(LocalGet(src.len.idx));
1274 self.instruction(LocalGet(dst.ptr.idx));
1275 self.instruction(LocalGet(dst_byte_len.idx));
1276 self.instruction(Call(transcode.as_u32()));
1277 self.instruction(LocalSet(dst.len.idx));
1278 let src_len_tmp = self.local_set_new_tmp(src.opts.ptr());
1279
1280 self.instruction(LocalGet(src_len_tmp.idx));
1284 self.instruction(LocalGet(src.len.idx));
1285 self.ptr_ne(src.opts);
1286 self.instruction(If(BlockType::Empty));
1287
1288 self.instruction(LocalGet(dst.ptr.idx)); self.instruction(LocalGet(dst_byte_len.idx)); self.ptr_uconst(dst.opts, 1); let factor = match src_enc {
1295 FE::Latin1 => 2,
1296 FE::Utf16 => 3,
1297 _ => unreachable!(),
1298 };
1299 self.validate_string_length_u8(src, factor);
1300 self.convert_src_len_to_dst(src.len.idx, src.opts.ptr(), dst_opts.ptr());
1301 self.ptr_uconst(dst_opts, factor.into());
1302 self.ptr_mul(dst_opts);
1303 self.instruction(LocalTee(dst_byte_len.idx));
1304 self.instruction(Call(dst_opts.realloc.unwrap().as_u32()));
1305 self.instruction(LocalSet(dst.ptr.idx));
1306
1307 self.validate_string_inbounds(&dst, dst_byte_len.idx);
1309
1310 self.instruction(LocalGet(src.ptr.idx));
1315 self.instruction(LocalGet(src_len_tmp.idx));
1316 if let FE::Utf16 = src_enc {
1317 self.ptr_uconst(src.opts, 1);
1318 self.ptr_shl(src.opts);
1319 }
1320 self.ptr_add(src.opts);
1321 self.instruction(LocalGet(src.len.idx));
1322 self.instruction(LocalGet(src_len_tmp.idx));
1323 self.ptr_sub(src.opts);
1324 self.instruction(LocalGet(dst.ptr.idx));
1325 self.instruction(LocalGet(dst.len.idx));
1326 self.ptr_add(dst.opts);
1327 self.instruction(LocalGet(dst_byte_len.idx));
1328 self.instruction(LocalGet(dst.len.idx));
1329 self.ptr_sub(dst.opts);
1330 self.instruction(Call(transcode.as_u32()));
1331
1332 self.instruction(LocalGet(dst.len.idx));
1336 self.ptr_add(dst.opts);
1337 self.instruction(LocalSet(dst.len.idx));
1338
1339 if self.module.debug {
1342 self.instruction(LocalGet(src.len.idx));
1343 self.instruction(LocalGet(src_len_tmp.idx));
1344 self.ptr_sub(src.opts);
1345 self.ptr_ne(src.opts);
1346 self.instruction(If(BlockType::Empty));
1347 self.trap(Trap::AssertFailed("should have finished encoding"));
1348 self.instruction(End);
1349 } else {
1350 self.instruction(Drop);
1351 }
1352
1353 self.instruction(LocalGet(dst.len.idx));
1355 self.instruction(LocalGet(dst_byte_len.idx));
1356 self.ptr_ne(dst.opts);
1357 self.instruction(If(BlockType::Empty));
1358 self.instruction(LocalGet(dst.ptr.idx)); self.instruction(LocalGet(dst_byte_len.idx)); self.ptr_uconst(dst.opts, 1); self.instruction(LocalGet(dst.len.idx)); self.instruction(Call(dst.opts.realloc.unwrap().as_u32()));
1363 self.instruction(LocalSet(dst.ptr.idx));
1364 self.instruction(End);
1365
1366 if self.module.debug {
1369 self.instruction(Else);
1370
1371 self.instruction(LocalGet(dst.len.idx));
1372 self.instruction(LocalGet(dst_byte_len.idx));
1373 self.ptr_ne(dst_opts);
1374 self.instruction(If(BlockType::Empty));
1375 self.trap(Trap::AssertFailed("should have finished encoding"));
1376 self.instruction(End);
1377 }
1378
1379 self.instruction(End); self.free_temp_local(src_len_tmp);
1382 self.free_temp_local(dst_byte_len);
1383 if let Some(tmp) = src_byte_len_tmp {
1384 self.free_temp_local(tmp);
1385 }
1386
1387 dst
1388 }
1389
1390 fn string_utf8_to_utf16<'a>(
1405 &mut self,
1406 src: &WasmString<'_>,
1407 dst_opts: &'a Options,
1408 ) -> WasmString<'a> {
1409 self.validate_string_length(src, FE::Utf16);
1410 self.convert_src_len_to_dst(src.len.idx, src.opts.ptr(), dst_opts.ptr());
1411 let dst_len = self.local_tee_new_tmp(dst_opts.ptr());
1412 self.ptr_uconst(dst_opts, 1);
1413 self.ptr_shl(dst_opts);
1414 let dst_byte_len = self.local_set_new_tmp(dst_opts.ptr());
1415 let dst = {
1416 let dst_mem = self.malloc(dst_opts, MallocSize::Local(dst_byte_len.idx), 2);
1417 WasmString {
1418 ptr: dst_mem.addr,
1419 len: dst_len,
1420 opts: dst_opts,
1421 }
1422 };
1423
1424 self.validate_string_inbounds(src, src.len.idx);
1425 self.validate_string_inbounds(&dst, dst_byte_len.idx);
1426
1427 let transcode = self.transcoder(src, &dst, Transcode::Utf8ToUtf16);
1428 self.instruction(LocalGet(src.ptr.idx));
1429 self.instruction(LocalGet(src.len.idx));
1430 self.instruction(LocalGet(dst.ptr.idx));
1431 self.instruction(Call(transcode.as_u32()));
1432 self.instruction(LocalSet(dst.len.idx));
1433
1434 self.convert_src_len_to_dst(src.len.idx, src.opts.ptr(), dst.opts.ptr());
1442 self.instruction(LocalGet(dst.len.idx));
1443 self.ptr_ne(dst_opts);
1444 self.instruction(If(BlockType::Empty));
1445 self.instruction(LocalGet(dst.ptr.idx));
1446 self.instruction(LocalGet(dst_byte_len.idx));
1447 self.ptr_uconst(dst.opts, 2);
1448 self.instruction(LocalGet(dst.len.idx));
1449 self.ptr_uconst(dst.opts, 1);
1450 self.ptr_shl(dst.opts);
1451 self.instruction(Call(dst.opts.realloc.unwrap().as_u32()));
1452 self.instruction(LocalSet(dst.ptr.idx));
1453 self.instruction(End); self.free_temp_local(dst_byte_len);
1456
1457 dst
1458 }
1459
1460 fn string_compact_utf16_to_compact<'a>(
1474 &mut self,
1475 src: &WasmString<'_>,
1476 dst_opts: &'a Options,
1477 ) -> WasmString<'a> {
1478 self.validate_string_length(src, FE::Utf16);
1479 self.convert_src_len_to_dst(src.len.idx, src.opts.ptr(), dst_opts.ptr());
1480 let dst_len = self.local_tee_new_tmp(dst_opts.ptr());
1481 self.ptr_uconst(dst_opts, 1);
1482 self.ptr_shl(dst_opts);
1483 let dst_byte_len = self.local_set_new_tmp(dst_opts.ptr());
1484 let dst = {
1485 let dst_mem = self.malloc(dst_opts, MallocSize::Local(dst_byte_len.idx), 2);
1486 WasmString {
1487 ptr: dst_mem.addr,
1488 len: dst_len,
1489 opts: dst_opts,
1490 }
1491 };
1492
1493 self.convert_src_len_to_dst(dst_byte_len.idx, dst.opts.ptr(), src.opts.ptr());
1494 let src_byte_len = self.local_set_new_tmp(src.opts.ptr());
1495
1496 self.validate_string_inbounds(src, src_byte_len.idx);
1497 self.validate_string_inbounds(&dst, dst_byte_len.idx);
1498
1499 let transcode = self.transcoder(src, &dst, Transcode::Utf16ToCompactProbablyUtf16);
1500 self.instruction(LocalGet(src.ptr.idx));
1501 self.instruction(LocalGet(src.len.idx));
1502 self.instruction(LocalGet(dst.ptr.idx));
1503 self.instruction(Call(transcode.as_u32()));
1504 self.instruction(LocalSet(dst.len.idx));
1505
1506 if self.module.debug {
1509 self.instruction(LocalGet(dst.len.idx));
1510 self.ptr_uconst(dst.opts, !UTF16_TAG);
1511 self.ptr_and(dst.opts);
1512 self.convert_src_len_to_dst(src.len.idx, src.opts.ptr(), dst.opts.ptr());
1513 self.ptr_ne(dst.opts);
1514 self.instruction(If(BlockType::Empty));
1515 self.trap(Trap::AssertFailed("expected equal code units"));
1516 self.instruction(End);
1517 }
1518
1519 self.instruction(LocalGet(dst.len.idx));
1523 self.ptr_uconst(dst.opts, UTF16_TAG);
1524 self.ptr_and(dst.opts);
1525 self.ptr_br_if(dst.opts, 0);
1526
1527 self.instruction(LocalGet(dst.ptr.idx)); self.instruction(LocalGet(dst_byte_len.idx)); self.ptr_uconst(dst.opts, 2); self.instruction(LocalGet(dst.len.idx)); self.instruction(Call(dst.opts.realloc.unwrap().as_u32()));
1533 self.instruction(LocalSet(dst.ptr.idx));
1534
1535 self.free_temp_local(dst_byte_len);
1536 self.free_temp_local(src_byte_len);
1537
1538 dst
1539 }
1540
1541 fn string_to_compact<'a>(
1548 &mut self,
1549 src: &WasmString<'_>,
1550 src_enc: FE,
1551 dst_opts: &'a Options,
1552 ) -> WasmString<'a> {
1553 self.validate_string_length(src, src_enc);
1554 self.convert_src_len_to_dst(src.len.idx, src.opts.ptr(), dst_opts.ptr());
1555 let dst_len = self.local_tee_new_tmp(dst_opts.ptr());
1556 let dst_byte_len = self.local_set_new_tmp(dst_opts.ptr());
1557 let dst = {
1558 let dst_mem = self.malloc(dst_opts, MallocSize::Local(dst_byte_len.idx), 2);
1559 WasmString {
1560 ptr: dst_mem.addr,
1561 len: dst_len,
1562 opts: dst_opts,
1563 }
1564 };
1565
1566 self.validate_string_inbounds(src, src.len.idx);
1567 self.validate_string_inbounds(&dst, dst_byte_len.idx);
1568
1569 let (latin1, utf16) = match src_enc {
1573 FE::Utf8 => (Transcode::Utf8ToLatin1, Transcode::Utf8ToCompactUtf16),
1574 FE::Utf16 => (Transcode::Utf16ToLatin1, Transcode::Utf16ToCompactUtf16),
1575 FE::Latin1 => unreachable!(),
1576 };
1577 let transcode_latin1 = self.transcoder(src, &dst, latin1);
1578 let transcode_utf16 = self.transcoder(src, &dst, utf16);
1579 self.instruction(LocalGet(src.ptr.idx));
1580 self.instruction(LocalGet(src.len.idx));
1581 self.instruction(LocalGet(dst.ptr.idx));
1582 self.instruction(Call(transcode_latin1.as_u32()));
1583 self.instruction(LocalSet(dst.len.idx));
1584 let src_len_tmp = self.local_set_new_tmp(src.opts.ptr());
1585
1586 self.instruction(LocalGet(src_len_tmp.idx));
1589 self.instruction(LocalGet(src.len.idx));
1590 self.ptr_eq(src.opts);
1591 self.instruction(If(BlockType::Empty)); self.instruction(LocalGet(dst_byte_len.idx));
1597 self.instruction(LocalGet(dst.len.idx));
1598 self.ptr_ne(dst.opts);
1599 self.instruction(If(BlockType::Empty));
1600 self.instruction(LocalGet(dst.ptr.idx)); self.instruction(LocalGet(dst_byte_len.idx)); self.ptr_uconst(dst.opts, 2); self.instruction(LocalGet(dst.len.idx)); self.instruction(Call(dst.opts.realloc.unwrap().as_u32()));
1605 self.instruction(LocalSet(dst.ptr.idx));
1606 self.instruction(End);
1607
1608 self.instruction(Else); if src_enc.width() == 1 {
1617 self.validate_string_length_u8(src, 2);
1618 }
1619
1620 self.instruction(LocalGet(dst.ptr.idx)); self.instruction(LocalGet(dst_byte_len.idx)); self.ptr_uconst(dst.opts, 2); self.convert_src_len_to_dst(src.len.idx, src.opts.ptr(), dst.opts.ptr());
1626 self.ptr_uconst(dst.opts, 1);
1627 self.ptr_shl(dst.opts);
1628 self.instruction(LocalTee(dst_byte_len.idx));
1629 self.instruction(Call(dst.opts.realloc.unwrap().as_u32()));
1630 self.instruction(LocalSet(dst.ptr.idx));
1631
1632 self.instruction(LocalGet(src.ptr.idx));
1636 self.instruction(LocalGet(src_len_tmp.idx));
1637 if let FE::Utf16 = src_enc {
1638 self.ptr_uconst(src.opts, 1);
1639 self.ptr_shl(src.opts);
1640 }
1641 self.ptr_add(src.opts);
1642 self.instruction(LocalGet(src.len.idx));
1643 self.instruction(LocalGet(src_len_tmp.idx));
1644 self.ptr_sub(src.opts);
1645 self.instruction(LocalGet(dst.ptr.idx));
1646 self.convert_src_len_to_dst(src.len.idx, src.opts.ptr(), dst.opts.ptr());
1647 self.instruction(LocalGet(dst.len.idx));
1648 self.instruction(Call(transcode_utf16.as_u32()));
1649 self.instruction(LocalSet(dst.len.idx));
1650
1651 self.instruction(LocalGet(dst.len.idx));
1659 self.convert_src_len_to_dst(src.len.idx, src.opts.ptr(), dst.opts.ptr());
1660 self.ptr_ne(dst.opts);
1661 self.instruction(If(BlockType::Empty));
1662 self.instruction(LocalGet(dst.ptr.idx)); self.instruction(LocalGet(dst_byte_len.idx)); self.ptr_uconst(dst.opts, 2); self.instruction(LocalGet(dst.len.idx));
1666 self.ptr_uconst(dst.opts, 1);
1667 self.ptr_shl(dst.opts);
1668 self.instruction(Call(dst.opts.realloc.unwrap().as_u32()));
1669 self.instruction(LocalSet(dst.ptr.idx));
1670 self.instruction(End);
1671
1672 self.instruction(LocalGet(dst.len.idx));
1674 self.ptr_uconst(dst.opts, UTF16_TAG);
1675 self.ptr_or(dst.opts);
1676 self.instruction(LocalSet(dst.len.idx));
1677
1678 self.instruction(End); self.free_temp_local(src_len_tmp);
1681 self.free_temp_local(dst_byte_len);
1682
1683 dst
1684 }
1685
1686 fn validate_string_length(&mut self, src: &WasmString<'_>, dst: FE) {
1687 self.validate_string_length_u8(src, dst.width())
1688 }
1689
1690 fn validate_string_length_u8(&mut self, s: &WasmString<'_>, dst: u8) {
1691 self.instruction(LocalGet(s.len.idx));
1694 let max = MAX_STRING_BYTE_LENGTH / u32::from(dst);
1695 self.ptr_uconst(s.opts, max);
1696 self.ptr_ge_u(s.opts);
1697 self.instruction(If(BlockType::Empty));
1698 self.trap(Trap::StringLengthTooBig);
1699 self.instruction(End);
1700 }
1701
1702 fn transcoder(
1703 &mut self,
1704 src: &WasmString<'_>,
1705 dst: &WasmString<'_>,
1706 op: Transcode,
1707 ) -> FuncIndex {
1708 self.module.import_transcoder(Transcoder {
1709 from_memory: src.opts.memory.unwrap(),
1710 from_memory64: src.opts.memory64,
1711 to_memory: dst.opts.memory.unwrap(),
1712 to_memory64: dst.opts.memory64,
1713 op,
1714 })
1715 }
1716
1717 fn validate_string_inbounds(&mut self, s: &WasmString<'_>, byte_len: u32) {
1718 self.validate_memory_inbounds(s.opts, s.ptr.idx, byte_len, Trap::StringLengthOverflow)
1719 }
1720
1721 fn validate_memory_inbounds(
1722 &mut self,
1723 opts: &Options,
1724 ptr_local: u32,
1725 byte_len_local: u32,
1726 trap: Trap,
1727 ) {
1728 let extend_to_64 = |me: &mut Self| {
1729 if !opts.memory64 {
1730 me.instruction(I64ExtendI32U);
1731 }
1732 };
1733
1734 self.instruction(Block(BlockType::Empty));
1735 self.instruction(Block(BlockType::Empty));
1736
1737 self.instruction(MemorySize(opts.memory.unwrap().as_u32()));
1742 extend_to_64(self);
1743 self.instruction(I64Const(16));
1744 self.instruction(I64Shl);
1745
1746 self.instruction(LocalGet(ptr_local));
1751 extend_to_64(self);
1752 self.instruction(LocalGet(byte_len_local));
1753 extend_to_64(self);
1754 self.instruction(I64Add);
1755 if opts.memory64 {
1756 let tmp = self.local_tee_new_tmp(ValType::I64);
1757 self.instruction(LocalGet(ptr_local));
1758 self.ptr_lt_u(opts);
1759 self.instruction(BrIf(0));
1760 self.instruction(LocalGet(tmp.idx));
1761 self.free_temp_local(tmp);
1762 }
1763
1764 self.instruction(I64GeU);
1768 self.instruction(BrIf(1));
1769
1770 self.instruction(End);
1771 self.trap(trap);
1772 self.instruction(End);
1773 }
1774
1775 fn translate_list(
1776 &mut self,
1777 src_ty: TypeListIndex,
1778 src: &Source<'_>,
1779 dst_ty: &InterfaceType,
1780 dst: &Destination,
1781 ) {
1782 let src_element_ty = &self.types[src_ty].element;
1783 let dst_element_ty = match dst_ty {
1784 InterfaceType::List(r) => &self.types[*r].element,
1785 _ => panic!("expected a list"),
1786 };
1787 let src_opts = src.opts();
1788 let dst_opts = dst.opts();
1789 let (src_size, src_align) = self.types.size_align(src_opts, src_element_ty);
1790 let (dst_size, dst_align) = self.types.size_align(dst_opts, dst_element_ty);
1791
1792 match src {
1797 Source::Stack(s) => {
1798 assert_eq!(s.locals.len(), 2);
1799 self.stack_get(&s.slice(0..1), src_opts.ptr());
1800 self.stack_get(&s.slice(1..2), src_opts.ptr());
1801 }
1802 Source::Memory(mem) => {
1803 self.ptr_load(mem);
1804 self.ptr_load(&mem.bump(src_opts.ptr_size().into()));
1805 }
1806 }
1807 let src_len = self.local_set_new_tmp(src_opts.ptr());
1808 let src_ptr = self.local_set_new_tmp(src_opts.ptr());
1809
1810 let src_mem = self.memory_operand(src_opts, src_ptr, src_align);
1813
1814 let src_byte_len = self.calculate_list_byte_len(src_opts, src_len.idx, src_size);
1816 let dst_byte_len = if src_size == dst_size {
1817 self.convert_src_len_to_dst(src_byte_len.idx, src_opts.ptr(), dst_opts.ptr());
1818 self.local_set_new_tmp(dst_opts.ptr())
1819 } else if src_opts.ptr() == dst_opts.ptr() {
1820 self.calculate_list_byte_len(dst_opts, src_len.idx, dst_size)
1821 } else {
1822 self.convert_src_len_to_dst(src_byte_len.idx, src_opts.ptr(), dst_opts.ptr());
1823 let tmp = self.local_set_new_tmp(dst_opts.ptr());
1824 let ret = self.calculate_list_byte_len(dst_opts, tmp.idx, dst_size);
1825 self.free_temp_local(tmp);
1826 ret
1827 };
1828
1829 let dst_mem = self.malloc(dst_opts, MallocSize::Local(dst_byte_len.idx), dst_align);
1834
1835 self.validate_memory_inbounds(
1838 src_opts,
1839 src_mem.addr.idx,
1840 src_byte_len.idx,
1841 Trap::ListByteLengthOverflow,
1842 );
1843 self.validate_memory_inbounds(
1844 dst_opts,
1845 dst_mem.addr.idx,
1846 dst_byte_len.idx,
1847 Trap::ListByteLengthOverflow,
1848 );
1849
1850 self.free_temp_local(src_byte_len);
1851 self.free_temp_local(dst_byte_len);
1852
1853 if src_size > 0 || dst_size > 0 {
1857 self.instruction(Block(BlockType::Empty));
1860
1861 self.instruction(LocalGet(src_len.idx));
1863 let remaining = self.local_tee_new_tmp(src_opts.ptr());
1864 self.ptr_eqz(src_opts);
1865 self.instruction(BrIf(0));
1866
1867 self.instruction(LocalGet(src_mem.addr.idx));
1869 let cur_src_ptr = self.local_set_new_tmp(src_opts.ptr());
1870 self.instruction(LocalGet(dst_mem.addr.idx));
1871 let cur_dst_ptr = self.local_set_new_tmp(dst_opts.ptr());
1872
1873 self.instruction(Loop(BlockType::Empty));
1874
1875 let element_src = Source::Memory(Memory {
1877 opts: src_opts,
1878 offset: 0,
1879 addr: TempLocal::new(cur_src_ptr.idx, cur_src_ptr.ty),
1880 });
1881 let element_dst = Destination::Memory(Memory {
1882 opts: dst_opts,
1883 offset: 0,
1884 addr: TempLocal::new(cur_dst_ptr.idx, cur_dst_ptr.ty),
1885 });
1886 self.translate(src_element_ty, &element_src, dst_element_ty, &element_dst);
1887
1888 if src_size > 0 {
1890 self.instruction(LocalGet(cur_src_ptr.idx));
1891 self.ptr_uconst(src_opts, src_size);
1892 self.ptr_add(src_opts);
1893 self.instruction(LocalSet(cur_src_ptr.idx));
1894 }
1895 if dst_size > 0 {
1896 self.instruction(LocalGet(cur_dst_ptr.idx));
1897 self.ptr_uconst(dst_opts, dst_size);
1898 self.ptr_add(dst_opts);
1899 self.instruction(LocalSet(cur_dst_ptr.idx));
1900 }
1901
1902 self.instruction(LocalGet(remaining.idx));
1905 self.ptr_iconst(src_opts, -1);
1906 self.ptr_add(src_opts);
1907 self.instruction(LocalTee(remaining.idx));
1908 self.ptr_br_if(src_opts, 0);
1909 self.instruction(End); self.instruction(End); self.free_temp_local(cur_dst_ptr);
1913 self.free_temp_local(cur_src_ptr);
1914 self.free_temp_local(remaining);
1915 }
1916
1917 match dst {
1919 Destination::Stack(s, _) => {
1920 self.instruction(LocalGet(dst_mem.addr.idx));
1921 self.stack_set(&s[..1], dst_opts.ptr());
1922 self.convert_src_len_to_dst(src_len.idx, src_opts.ptr(), dst_opts.ptr());
1923 self.stack_set(&s[1..], dst_opts.ptr());
1924 }
1925 Destination::Memory(mem) => {
1926 self.instruction(LocalGet(mem.addr.idx));
1927 self.instruction(LocalGet(dst_mem.addr.idx));
1928 self.ptr_store(mem);
1929 self.instruction(LocalGet(mem.addr.idx));
1930 self.convert_src_len_to_dst(src_len.idx, src_opts.ptr(), dst_opts.ptr());
1931 self.ptr_store(&mem.bump(dst_opts.ptr_size().into()));
1932 }
1933 }
1934
1935 self.free_temp_local(src_len);
1936 self.free_temp_local(src_mem.addr);
1937 self.free_temp_local(dst_mem.addr);
1938 }
1939
1940 fn calculate_list_byte_len(
1941 &mut self,
1942 opts: &Options,
1943 len_local: u32,
1944 elt_size: u32,
1945 ) -> TempLocal {
1946 if elt_size == 0 {
1949 self.ptr_uconst(opts, 0);
1950 return self.local_set_new_tmp(opts.ptr());
1951 }
1952
1953 if elt_size == 1 {
1961 if let ValType::I64 = opts.ptr() {
1962 self.instruction(LocalGet(len_local));
1963 self.instruction(I64Const(32));
1964 self.instruction(I64ShrU);
1965 self.instruction(I32WrapI64);
1966 self.instruction(If(BlockType::Empty));
1967 self.trap(Trap::ListByteLengthOverflow);
1968 self.instruction(End);
1969 }
1970 self.instruction(LocalGet(len_local));
1971 return self.local_set_new_tmp(opts.ptr());
1972 }
1973
1974 self.instruction(Block(BlockType::Empty));
1979 self.instruction(Block(BlockType::Empty));
1980 self.instruction(LocalGet(len_local));
1981 match opts.ptr() {
1982 ValType::I32 => self.instruction(I64ExtendI32U),
1986
1987 ValType::I64 => {
1991 self.instruction(I64Const(32));
1992 self.instruction(I64ShrU);
1993 self.instruction(I32WrapI64);
1994 self.instruction(BrIf(0));
1995 self.instruction(LocalGet(len_local));
1996 }
1997
1998 _ => unreachable!(),
1999 }
2000
2001 self.instruction(I64Const(elt_size.into()));
2010 self.instruction(I64Mul);
2011 let tmp = self.local_tee_new_tmp(ValType::I64);
2012 self.instruction(I64Const(32));
2015 self.instruction(I64ShrU);
2016 self.instruction(I64Eqz);
2017 self.instruction(BrIf(1));
2018 self.instruction(End);
2019 self.trap(Trap::ListByteLengthOverflow);
2020 self.instruction(End);
2021
2022 if opts.ptr() == ValType::I64 {
2026 tmp
2027 } else {
2028 self.instruction(LocalGet(tmp.idx));
2029 self.instruction(I32WrapI64);
2030 self.free_temp_local(tmp);
2031 self.local_set_new_tmp(ValType::I32)
2032 }
2033 }
2034
2035 fn convert_src_len_to_dst(
2036 &mut self,
2037 src_len_local: u32,
2038 src_ptr_ty: ValType,
2039 dst_ptr_ty: ValType,
2040 ) {
2041 self.instruction(LocalGet(src_len_local));
2042 match (src_ptr_ty, dst_ptr_ty) {
2043 (ValType::I32, ValType::I64) => self.instruction(I64ExtendI32U),
2044 (ValType::I64, ValType::I32) => self.instruction(I32WrapI64),
2045 (src, dst) => assert_eq!(src, dst),
2046 }
2047 }
2048
2049 fn translate_record(
2050 &mut self,
2051 src_ty: TypeRecordIndex,
2052 src: &Source<'_>,
2053 dst_ty: &InterfaceType,
2054 dst: &Destination,
2055 ) {
2056 let src_ty = &self.types[src_ty];
2057 let dst_ty = match dst_ty {
2058 InterfaceType::Record(r) => &self.types[*r],
2059 _ => panic!("expected a record"),
2060 };
2061
2062 assert_eq!(src_ty.fields.len(), dst_ty.fields.len());
2064
2065 let mut src_fields = HashMap::new();
2069 for (i, src) in src
2070 .record_field_srcs(self.types, src_ty.fields.iter().map(|f| f.ty))
2071 .enumerate()
2072 {
2073 let field = &src_ty.fields[i];
2074 src_fields.insert(&field.name, (src, &field.ty));
2075 }
2076
2077 for (i, dst) in dst
2086 .record_field_dsts(self.types, dst_ty.fields.iter().map(|f| f.ty))
2087 .enumerate()
2088 {
2089 let field = &dst_ty.fields[i];
2090 let (src, src_ty) = &src_fields[&field.name];
2091 self.translate(src_ty, src, &field.ty, &dst);
2092 }
2093 }
2094
2095 fn translate_flags(
2096 &mut self,
2097 src_ty: TypeFlagsIndex,
2098 src: &Source<'_>,
2099 dst_ty: &InterfaceType,
2100 dst: &Destination,
2101 ) {
2102 let src_ty = &self.types[src_ty];
2103 let dst_ty = match dst_ty {
2104 InterfaceType::Flags(r) => &self.types[*r],
2105 _ => panic!("expected a record"),
2106 };
2107
2108 assert_eq!(src_ty.names, dst_ty.names);
2116 let cnt = src_ty.names.len();
2117 match FlagsSize::from_count(cnt) {
2118 FlagsSize::Size0 => {}
2119 FlagsSize::Size1 => {
2120 let mask = if cnt == 8 { 0xff } else { (1 << cnt) - 1 };
2121 self.convert_u8_mask(src, dst, mask);
2122 }
2123 FlagsSize::Size2 => {
2124 let mask = if cnt == 16 { 0xffff } else { (1 << cnt) - 1 };
2125 self.convert_u16_mask(src, dst, mask);
2126 }
2127 FlagsSize::Size4Plus(n) => {
2128 let srcs = src.record_field_srcs(self.types, (0..n).map(|_| InterfaceType::U32));
2129 let dsts = dst.record_field_dsts(self.types, (0..n).map(|_| InterfaceType::U32));
2130 let n = usize::from(n);
2131 for (i, (src, dst)) in srcs.zip(dsts).enumerate() {
2132 let mask = if i == n - 1 && (cnt % 32 != 0) {
2133 (1 << (cnt % 32)) - 1
2134 } else {
2135 0xffffffff
2136 };
2137 self.convert_u32_mask(&src, &dst, mask);
2138 }
2139 }
2140 }
2141 }
2142
2143 fn translate_tuple(
2144 &mut self,
2145 src_ty: TypeTupleIndex,
2146 src: &Source<'_>,
2147 dst_ty: &InterfaceType,
2148 dst: &Destination,
2149 ) {
2150 let src_ty = &self.types[src_ty];
2151 let dst_ty = match dst_ty {
2152 InterfaceType::Tuple(t) => &self.types[*t],
2153 _ => panic!("expected a tuple"),
2154 };
2155
2156 assert_eq!(src_ty.types.len(), dst_ty.types.len());
2158
2159 let srcs = src
2160 .record_field_srcs(self.types, src_ty.types.iter().copied())
2161 .zip(src_ty.types.iter());
2162 let dsts = dst
2163 .record_field_dsts(self.types, dst_ty.types.iter().copied())
2164 .zip(dst_ty.types.iter());
2165 for ((src, src_ty), (dst, dst_ty)) in srcs.zip(dsts) {
2166 self.translate(src_ty, &src, dst_ty, &dst);
2167 }
2168 }
2169
2170 fn translate_variant(
2171 &mut self,
2172 src_ty: TypeVariantIndex,
2173 src: &Source<'_>,
2174 dst_ty: &InterfaceType,
2175 dst: &Destination,
2176 ) {
2177 let src_ty = &self.types[src_ty];
2178 let dst_ty = match dst_ty {
2179 InterfaceType::Variant(t) => &self.types[*t],
2180 _ => panic!("expected a variant"),
2181 };
2182
2183 let src_info = variant_info(self.types, src_ty.cases.iter().map(|(_, c)| c.as_ref()));
2184 let dst_info = variant_info(self.types, dst_ty.cases.iter().map(|(_, c)| c.as_ref()));
2185
2186 let iter = src_ty
2187 .cases
2188 .iter()
2189 .enumerate()
2190 .map(|(src_i, (src_case, src_case_ty))| {
2191 let dst_i = dst_ty
2192 .cases
2193 .iter()
2194 .position(|(c, _)| c == src_case)
2195 .unwrap();
2196 let dst_case_ty = &dst_ty.cases[dst_i];
2197 let src_i = u32::try_from(src_i).unwrap();
2198 let dst_i = u32::try_from(dst_i).unwrap();
2199 VariantCase {
2200 src_i,
2201 src_ty: src_case_ty.as_ref(),
2202 dst_i,
2203 dst_ty: dst_case_ty.as_ref(),
2204 }
2205 });
2206 self.convert_variant(src, &src_info, dst, &dst_info, iter);
2207 }
2208
2209 fn translate_enum(
2210 &mut self,
2211 src_ty: TypeEnumIndex,
2212 src: &Source<'_>,
2213 dst_ty: &InterfaceType,
2214 dst: &Destination,
2215 ) {
2216 let src_ty = &self.types[src_ty];
2217 let dst_ty = match dst_ty {
2218 InterfaceType::Enum(t) => &self.types[*t],
2219 _ => panic!("expected an option"),
2220 };
2221 let src_info = variant_info(self.types, src_ty.names.iter().map(|_| None));
2222 let dst_info = variant_info(self.types, dst_ty.names.iter().map(|_| None));
2223
2224 self.convert_variant(
2225 src,
2226 &src_info,
2227 dst,
2228 &dst_info,
2229 src_ty.names.iter().enumerate().map(|(src_i, src_name)| {
2230 let dst_i = dst_ty.names.iter().position(|n| n == src_name).unwrap();
2231 let src_i = u32::try_from(src_i).unwrap();
2232 let dst_i = u32::try_from(dst_i).unwrap();
2233 VariantCase {
2234 src_i,
2235 dst_i,
2236 src_ty: None,
2237 dst_ty: None,
2238 }
2239 }),
2240 );
2241 }
2242
2243 fn translate_option(
2244 &mut self,
2245 src_ty: TypeOptionIndex,
2246 src: &Source<'_>,
2247 dst_ty: &InterfaceType,
2248 dst: &Destination,
2249 ) {
2250 let src_ty = &self.types[src_ty].ty;
2251 let dst_ty = match dst_ty {
2252 InterfaceType::Option(t) => &self.types[*t].ty,
2253 _ => panic!("expected an option"),
2254 };
2255 let src_ty = Some(src_ty);
2256 let dst_ty = Some(dst_ty);
2257
2258 let src_info = variant_info(self.types, [None, src_ty]);
2259 let dst_info = variant_info(self.types, [None, dst_ty]);
2260
2261 self.convert_variant(
2262 src,
2263 &src_info,
2264 dst,
2265 &dst_info,
2266 [
2267 VariantCase {
2268 src_i: 0,
2269 dst_i: 0,
2270 src_ty: None,
2271 dst_ty: None,
2272 },
2273 VariantCase {
2274 src_i: 1,
2275 dst_i: 1,
2276 src_ty,
2277 dst_ty,
2278 },
2279 ]
2280 .into_iter(),
2281 );
2282 }
2283
2284 fn translate_result(
2285 &mut self,
2286 src_ty: TypeResultIndex,
2287 src: &Source<'_>,
2288 dst_ty: &InterfaceType,
2289 dst: &Destination,
2290 ) {
2291 let src_ty = &self.types[src_ty];
2292 let dst_ty = match dst_ty {
2293 InterfaceType::Result(t) => &self.types[*t],
2294 _ => panic!("expected a result"),
2295 };
2296
2297 let src_info = variant_info(self.types, [src_ty.ok.as_ref(), src_ty.err.as_ref()]);
2298 let dst_info = variant_info(self.types, [dst_ty.ok.as_ref(), dst_ty.err.as_ref()]);
2299
2300 self.convert_variant(
2301 src,
2302 &src_info,
2303 dst,
2304 &dst_info,
2305 [
2306 VariantCase {
2307 src_i: 0,
2308 dst_i: 0,
2309 src_ty: src_ty.ok.as_ref(),
2310 dst_ty: dst_ty.ok.as_ref(),
2311 },
2312 VariantCase {
2313 src_i: 1,
2314 dst_i: 1,
2315 src_ty: src_ty.err.as_ref(),
2316 dst_ty: dst_ty.err.as_ref(),
2317 },
2318 ]
2319 .into_iter(),
2320 );
2321 }
2322
2323 fn convert_variant<'a>(
2324 &mut self,
2325 src: &Source<'_>,
2326 src_info: &VariantInfo,
2327 dst: &Destination,
2328 dst_info: &VariantInfo,
2329 src_cases: impl ExactSizeIterator<Item = VariantCase<'a>>,
2330 ) {
2331 let outer_block_ty = match dst {
2334 Destination::Stack(dst_flat, _) => match dst_flat.len() {
2335 0 => BlockType::Empty,
2336 1 => BlockType::Result(dst_flat[0]),
2337 _ => {
2338 let ty = self.module.core_types.function(&[], &dst_flat);
2339 BlockType::FunctionType(ty)
2340 }
2341 },
2342 Destination::Memory(_) => BlockType::Empty,
2343 };
2344 self.instruction(Block(outer_block_ty));
2345
2346 let src_cases_len = src_cases.len();
2349 for _ in 0..src_cases_len - 1 {
2350 self.instruction(Block(BlockType::Empty));
2351 }
2352
2353 self.instruction(Block(BlockType::Empty));
2355
2356 self.instruction(Block(BlockType::Empty));
2359
2360 match src {
2362 Source::Stack(s) => self.stack_get(&s.slice(0..1), ValType::I32),
2363 Source::Memory(mem) => match src_info.size {
2364 DiscriminantSize::Size1 => self.i32_load8u(mem),
2365 DiscriminantSize::Size2 => self.i32_load16u(mem),
2366 DiscriminantSize::Size4 => self.i32_load(mem),
2367 },
2368 }
2369
2370 let mut targets = Vec::new();
2373 for i in 0..src_cases_len {
2374 targets.push((i + 1) as u32);
2375 }
2376 self.instruction(BrTable(targets[..].into(), 0));
2377 self.instruction(End); self.trap(Trap::InvalidDiscriminant);
2380 self.instruction(End); let src_cases_len = u32::try_from(src_cases_len).unwrap();
2387 for case in src_cases {
2388 let VariantCase {
2389 src_i,
2390 src_ty,
2391 dst_i,
2392 dst_ty,
2393 } = case;
2394
2395 self.push_dst_addr(dst);
2398 self.instruction(I32Const(dst_i as i32));
2399 match dst {
2400 Destination::Stack(stack, _) => self.stack_set(&stack[..1], ValType::I32),
2401 Destination::Memory(mem) => match dst_info.size {
2402 DiscriminantSize::Size1 => self.i32_store8(mem),
2403 DiscriminantSize::Size2 => self.i32_store16(mem),
2404 DiscriminantSize::Size4 => self.i32_store(mem),
2405 },
2406 }
2407
2408 let src_payload = src.payload_src(self.types, src_info, src_ty);
2409 let dst_payload = dst.payload_dst(self.types, dst_info, dst_ty);
2410
2411 match (src_ty, dst_ty) {
2414 (Some(src_ty), Some(dst_ty)) => {
2415 self.translate(src_ty, &src_payload, dst_ty, &dst_payload);
2416 }
2417 (None, None) => {}
2418 _ => unimplemented!(),
2419 }
2420
2421 if let Destination::Stack(payload_results, _) = dst_payload {
2428 if let Destination::Stack(dst_results, _) = dst {
2429 let remaining = &dst_results[1..][payload_results.len()..];
2430 for ty in remaining {
2431 match ty {
2432 ValType::I32 => self.instruction(I32Const(0)),
2433 ValType::I64 => self.instruction(I64Const(0)),
2434 ValType::F32 => self.instruction(F32Const(0.0)),
2435 ValType::F64 => self.instruction(F64Const(0.0)),
2436 _ => unreachable!(),
2437 }
2438 }
2439 }
2440 }
2441
2442 if src_i != src_cases_len - 1 {
2445 self.instruction(Br(src_cases_len - src_i - 1));
2446 }
2447 self.instruction(End); }
2449 }
2450
2451 fn translate_own(
2452 &mut self,
2453 src_ty: TypeResourceTableIndex,
2454 src: &Source<'_>,
2455 dst_ty: &InterfaceType,
2456 dst: &Destination,
2457 ) {
2458 let dst_ty = match dst_ty {
2459 InterfaceType::Own(t) => *t,
2460 _ => panic!("expected an `Own`"),
2461 };
2462 let transfer = self.module.import_resource_transfer_own();
2463 self.translate_resource(src_ty, src, dst_ty, dst, transfer);
2464 }
2465
2466 fn translate_borrow(
2467 &mut self,
2468 src_ty: TypeResourceTableIndex,
2469 src: &Source<'_>,
2470 dst_ty: &InterfaceType,
2471 dst: &Destination,
2472 ) {
2473 let dst_ty = match dst_ty {
2474 InterfaceType::Borrow(t) => *t,
2475 _ => panic!("expected an `Borrow`"),
2476 };
2477
2478 let transfer = self.module.import_resource_transfer_borrow();
2479 self.translate_resource(src_ty, src, dst_ty, dst, transfer);
2480 }
2481
2482 fn translate_resource(
2490 &mut self,
2491 src_ty: TypeResourceTableIndex,
2492 src: &Source<'_>,
2493 dst_ty: TypeResourceTableIndex,
2494 dst: &Destination,
2495 transfer: FuncIndex,
2496 ) {
2497 self.push_dst_addr(dst);
2498 match src {
2499 Source::Memory(mem) => self.i32_load(mem),
2500 Source::Stack(stack) => self.stack_get(stack, ValType::I32),
2501 }
2502 self.instruction(I32Const(src_ty.as_u32() as i32));
2503 self.instruction(I32Const(dst_ty.as_u32() as i32));
2504 self.instruction(Call(transfer.as_u32()));
2505 match dst {
2506 Destination::Memory(mem) => self.i32_store(mem),
2507 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
2508 }
2509 }
2510
2511 fn trap_if_not_flag(&mut self, flags_global: GlobalIndex, flag_to_test: i32, trap: Trap) {
2512 self.instruction(GlobalGet(flags_global.as_u32()));
2513 self.instruction(I32Const(flag_to_test));
2514 self.instruction(I32And);
2515 self.instruction(I32Eqz);
2516 self.instruction(If(BlockType::Empty));
2517 self.trap(trap);
2518 self.instruction(End);
2519 }
2520
2521 fn assert_not_flag(&mut self, flags_global: GlobalIndex, flag_to_test: i32, msg: &'static str) {
2522 self.instruction(GlobalGet(flags_global.as_u32()));
2523 self.instruction(I32Const(flag_to_test));
2524 self.instruction(I32And);
2525 self.instruction(If(BlockType::Empty));
2526 self.trap(Trap::AssertFailed(msg));
2527 self.instruction(End);
2528 }
2529
2530 fn set_flag(&mut self, flags_global: GlobalIndex, flag_to_set: i32, value: bool) {
2531 self.instruction(GlobalGet(flags_global.as_u32()));
2532 if value {
2533 self.instruction(I32Const(flag_to_set));
2534 self.instruction(I32Or);
2535 } else {
2536 self.instruction(I32Const(!flag_to_set));
2537 self.instruction(I32And);
2538 }
2539 self.instruction(GlobalSet(flags_global.as_u32()));
2540 }
2541
2542 fn verify_aligned(&mut self, opts: &Options, addr_local: u32, align: u32) {
2543 if align == 1 {
2546 return;
2547 }
2548 self.instruction(LocalGet(addr_local));
2549 assert!(align.is_power_of_two());
2550 self.ptr_uconst(opts, align - 1);
2551 self.ptr_and(opts);
2552 self.ptr_if(opts, BlockType::Empty);
2553 self.trap(Trap::UnalignedPointer);
2554 self.instruction(End);
2555 }
2556
2557 fn assert_aligned(&mut self, ty: &InterfaceType, mem: &Memory) {
2558 if !self.module.debug {
2559 return;
2560 }
2561 let align = self.types.align(mem.opts, ty);
2562 if align == 1 {
2563 return;
2564 }
2565 assert!(align.is_power_of_two());
2566 self.instruction(LocalGet(mem.addr.idx));
2567 self.ptr_uconst(mem.opts, mem.offset);
2568 self.ptr_add(mem.opts);
2569 self.ptr_uconst(mem.opts, align - 1);
2570 self.ptr_and(mem.opts);
2571 self.ptr_if(mem.opts, BlockType::Empty);
2572 self.trap(Trap::AssertFailed("pointer not aligned"));
2573 self.instruction(End);
2574 }
2575
2576 fn malloc<'a>(&mut self, opts: &'a Options, size: MallocSize, align: u32) -> Memory<'a> {
2577 let realloc = opts.realloc.unwrap();
2578 self.ptr_uconst(opts, 0);
2579 self.ptr_uconst(opts, 0);
2580 self.ptr_uconst(opts, align);
2581 match size {
2582 MallocSize::Const(size) => self.ptr_uconst(opts, size),
2583 MallocSize::Local(idx) => self.instruction(LocalGet(idx)),
2584 }
2585 self.instruction(Call(realloc.as_u32()));
2586 let addr = self.local_set_new_tmp(opts.ptr());
2587 self.memory_operand(opts, addr, align)
2588 }
2589
2590 fn memory_operand<'a>(&mut self, opts: &'a Options, addr: TempLocal, align: u32) -> Memory<'a> {
2591 let ret = Memory {
2592 addr,
2593 offset: 0,
2594 opts,
2595 };
2596 self.verify_aligned(opts, ret.addr.idx, align);
2597 ret
2598 }
2599
2600 fn local_tee_new_tmp(&mut self, ty: ValType) -> TempLocal {
2606 self.gen_temp_local(ty, LocalTee)
2607 }
2608
2609 fn local_set_new_tmp(&mut self, ty: ValType) -> TempLocal {
2612 self.gen_temp_local(ty, LocalSet)
2613 }
2614
2615 fn gen_temp_local(&mut self, ty: ValType, insn: fn(u32) -> Instruction<'static>) -> TempLocal {
2616 if let Some(idx) = self.free_locals.get_mut(&ty).and_then(|v| v.pop()) {
2619 self.instruction(insn(idx));
2620 return TempLocal {
2621 ty,
2622 idx,
2623 needs_free: true,
2624 };
2625 }
2626
2627 let locals = &mut self.module.funcs[self.result].locals;
2629 match locals.last_mut() {
2630 Some((cnt, prev_ty)) if ty == *prev_ty => *cnt += 1,
2631 _ => locals.push((1, ty)),
2632 }
2633 self.nlocals += 1;
2634 let idx = self.nlocals - 1;
2635 self.instruction(insn(idx));
2636 TempLocal {
2637 ty,
2638 idx,
2639 needs_free: true,
2640 }
2641 }
2642
2643 fn free_temp_local(&mut self, mut local: TempLocal) {
2646 assert!(local.needs_free);
2647 self.free_locals
2648 .entry(local.ty)
2649 .or_insert(Vec::new())
2650 .push(local.idx);
2651 local.needs_free = false;
2652 }
2653
2654 fn instruction(&mut self, instr: Instruction) {
2655 instr.encode(&mut self.code);
2656 }
2657
2658 fn trap(&mut self, trap: Trap) {
2659 self.traps.push((self.code.len(), trap));
2660 self.instruction(Unreachable);
2661 }
2662
2663 fn flush_code(&mut self) {
2668 if self.code.is_empty() {
2669 return;
2670 }
2671 self.module.funcs[self.result].body.push(Body::Raw(
2672 mem::take(&mut self.code),
2673 mem::take(&mut self.traps),
2674 ));
2675 }
2676
2677 fn finish(mut self) {
2678 self.instruction(End);
2681 self.flush_code();
2682
2683 self.module.funcs[self.result].filled_in = true;
2686 }
2687
2688 fn stack_get(&mut self, stack: &Stack<'_>, dst_ty: ValType) {
2696 assert_eq!(stack.locals.len(), 1);
2697 let (idx, src_ty) = stack.locals[0];
2698 self.instruction(LocalGet(idx));
2699 match (src_ty, dst_ty) {
2700 (ValType::I32, ValType::I32)
2701 | (ValType::I64, ValType::I64)
2702 | (ValType::F32, ValType::F32)
2703 | (ValType::F64, ValType::F64) => {}
2704
2705 (ValType::I32, ValType::F32) => self.instruction(F32ReinterpretI32),
2706 (ValType::I64, ValType::I32) => {
2707 self.assert_i64_upper_bits_not_set(idx);
2708 self.instruction(I32WrapI64);
2709 }
2710 (ValType::I64, ValType::F64) => self.instruction(F64ReinterpretI64),
2711 (ValType::I64, ValType::F32) => {
2712 self.assert_i64_upper_bits_not_set(idx);
2713 self.instruction(I32WrapI64);
2714 self.instruction(F32ReinterpretI32);
2715 }
2716
2717 (ValType::I32, ValType::I64)
2719 | (ValType::I32, ValType::F64)
2720 | (ValType::F32, ValType::I32)
2721 | (ValType::F32, ValType::I64)
2722 | (ValType::F32, ValType::F64)
2723 | (ValType::F64, ValType::I32)
2724 | (ValType::F64, ValType::I64)
2725 | (ValType::F64, ValType::F32)
2726
2727 | (ValType::Ref(_), _)
2729 | (_, ValType::Ref(_))
2730 | (ValType::V128, _)
2731 | (_, ValType::V128) => {
2732 panic!("cannot get {dst_ty:?} from {src_ty:?} local");
2733 }
2734 }
2735 }
2736
2737 fn assert_i64_upper_bits_not_set(&mut self, local: u32) {
2738 if !self.module.debug {
2739 return;
2740 }
2741 self.instruction(LocalGet(local));
2742 self.instruction(I64Const(32));
2743 self.instruction(I64ShrU);
2744 self.instruction(I32WrapI64);
2745 self.instruction(If(BlockType::Empty));
2746 self.trap(Trap::AssertFailed("upper bits are unexpectedly set"));
2747 self.instruction(End);
2748 }
2749
2750 fn stack_set(&mut self, dst_tys: &[ValType], src_ty: ValType) {
2756 assert_eq!(dst_tys.len(), 1);
2757 let dst_ty = dst_tys[0];
2758 match (src_ty, dst_ty) {
2759 (ValType::I32, ValType::I32)
2760 | (ValType::I64, ValType::I64)
2761 | (ValType::F32, ValType::F32)
2762 | (ValType::F64, ValType::F64) => {}
2763
2764 (ValType::F32, ValType::I32) => self.instruction(I32ReinterpretF32),
2765 (ValType::I32, ValType::I64) => self.instruction(I64ExtendI32U),
2766 (ValType::F64, ValType::I64) => self.instruction(I64ReinterpretF64),
2767 (ValType::F32, ValType::I64) => {
2768 self.instruction(I32ReinterpretF32);
2769 self.instruction(I64ExtendI32U);
2770 }
2771
2772 (ValType::I64, ValType::I32)
2774 | (ValType::F64, ValType::I32)
2775 | (ValType::I32, ValType::F32)
2776 | (ValType::I64, ValType::F32)
2777 | (ValType::F64, ValType::F32)
2778 | (ValType::I32, ValType::F64)
2779 | (ValType::I64, ValType::F64)
2780 | (ValType::F32, ValType::F64)
2781
2782 | (ValType::Ref(_), _)
2784 | (_, ValType::Ref(_))
2785 | (ValType::V128, _)
2786 | (_, ValType::V128) => {
2787 panic!("cannot get {dst_ty:?} from {src_ty:?} local");
2788 }
2789 }
2790 }
2791
2792 fn i32_load8u(&mut self, mem: &Memory) {
2793 self.instruction(LocalGet(mem.addr.idx));
2794 self.instruction(I32Load8U(mem.memarg(0)));
2795 }
2796
2797 fn i32_load8s(&mut self, mem: &Memory) {
2798 self.instruction(LocalGet(mem.addr.idx));
2799 self.instruction(I32Load8S(mem.memarg(0)));
2800 }
2801
2802 fn i32_load16u(&mut self, mem: &Memory) {
2803 self.instruction(LocalGet(mem.addr.idx));
2804 self.instruction(I32Load16U(mem.memarg(1)));
2805 }
2806
2807 fn i32_load16s(&mut self, mem: &Memory) {
2808 self.instruction(LocalGet(mem.addr.idx));
2809 self.instruction(I32Load16S(mem.memarg(1)));
2810 }
2811
2812 fn i32_load(&mut self, mem: &Memory) {
2813 self.instruction(LocalGet(mem.addr.idx));
2814 self.instruction(I32Load(mem.memarg(2)));
2815 }
2816
2817 fn i64_load(&mut self, mem: &Memory) {
2818 self.instruction(LocalGet(mem.addr.idx));
2819 self.instruction(I64Load(mem.memarg(3)));
2820 }
2821
2822 fn ptr_load(&mut self, mem: &Memory) {
2823 if mem.opts.memory64 {
2824 self.i64_load(mem);
2825 } else {
2826 self.i32_load(mem);
2827 }
2828 }
2829
2830 fn ptr_add(&mut self, opts: &Options) {
2831 if opts.memory64 {
2832 self.instruction(I64Add);
2833 } else {
2834 self.instruction(I32Add);
2835 }
2836 }
2837
2838 fn ptr_sub(&mut self, opts: &Options) {
2839 if opts.memory64 {
2840 self.instruction(I64Sub);
2841 } else {
2842 self.instruction(I32Sub);
2843 }
2844 }
2845
2846 fn ptr_mul(&mut self, opts: &Options) {
2847 if opts.memory64 {
2848 self.instruction(I64Mul);
2849 } else {
2850 self.instruction(I32Mul);
2851 }
2852 }
2853
2854 fn ptr_ge_u(&mut self, opts: &Options) {
2855 if opts.memory64 {
2856 self.instruction(I64GeU);
2857 } else {
2858 self.instruction(I32GeU);
2859 }
2860 }
2861
2862 fn ptr_lt_u(&mut self, opts: &Options) {
2863 if opts.memory64 {
2864 self.instruction(I64LtU);
2865 } else {
2866 self.instruction(I32LtU);
2867 }
2868 }
2869
2870 fn ptr_shl(&mut self, opts: &Options) {
2871 if opts.memory64 {
2872 self.instruction(I64Shl);
2873 } else {
2874 self.instruction(I32Shl);
2875 }
2876 }
2877
2878 fn ptr_eqz(&mut self, opts: &Options) {
2879 if opts.memory64 {
2880 self.instruction(I64Eqz);
2881 } else {
2882 self.instruction(I32Eqz);
2883 }
2884 }
2885
2886 fn ptr_uconst(&mut self, opts: &Options, val: u32) {
2887 if opts.memory64 {
2888 self.instruction(I64Const(val.into()));
2889 } else {
2890 self.instruction(I32Const(val as i32));
2891 }
2892 }
2893
2894 fn ptr_iconst(&mut self, opts: &Options, val: i32) {
2895 if opts.memory64 {
2896 self.instruction(I64Const(val.into()));
2897 } else {
2898 self.instruction(I32Const(val));
2899 }
2900 }
2901
2902 fn ptr_eq(&mut self, opts: &Options) {
2903 if opts.memory64 {
2904 self.instruction(I64Eq);
2905 } else {
2906 self.instruction(I32Eq);
2907 }
2908 }
2909
2910 fn ptr_ne(&mut self, opts: &Options) {
2911 if opts.memory64 {
2912 self.instruction(I64Ne);
2913 } else {
2914 self.instruction(I32Ne);
2915 }
2916 }
2917
2918 fn ptr_and(&mut self, opts: &Options) {
2919 if opts.memory64 {
2920 self.instruction(I64And);
2921 } else {
2922 self.instruction(I32And);
2923 }
2924 }
2925
2926 fn ptr_or(&mut self, opts: &Options) {
2927 if opts.memory64 {
2928 self.instruction(I64Or);
2929 } else {
2930 self.instruction(I32Or);
2931 }
2932 }
2933
2934 fn ptr_xor(&mut self, opts: &Options) {
2935 if opts.memory64 {
2936 self.instruction(I64Xor);
2937 } else {
2938 self.instruction(I32Xor);
2939 }
2940 }
2941
2942 fn ptr_if(&mut self, opts: &Options, ty: BlockType) {
2943 if opts.memory64 {
2944 self.instruction(I64Const(0));
2945 self.instruction(I64Ne);
2946 }
2947 self.instruction(If(ty));
2948 }
2949
2950 fn ptr_br_if(&mut self, opts: &Options, depth: u32) {
2951 if opts.memory64 {
2952 self.instruction(I64Const(0));
2953 self.instruction(I64Ne);
2954 }
2955 self.instruction(BrIf(depth));
2956 }
2957
2958 fn f32_load(&mut self, mem: &Memory) {
2959 self.instruction(LocalGet(mem.addr.idx));
2960 self.instruction(F32Load(mem.memarg(2)));
2961 }
2962
2963 fn f64_load(&mut self, mem: &Memory) {
2964 self.instruction(LocalGet(mem.addr.idx));
2965 self.instruction(F64Load(mem.memarg(3)));
2966 }
2967
2968 fn push_dst_addr(&mut self, dst: &Destination) {
2969 if let Destination::Memory(mem) = dst {
2970 self.instruction(LocalGet(mem.addr.idx));
2971 }
2972 }
2973
2974 fn i32_store8(&mut self, mem: &Memory) {
2975 self.instruction(I32Store8(mem.memarg(0)));
2976 }
2977
2978 fn i32_store16(&mut self, mem: &Memory) {
2979 self.instruction(I32Store16(mem.memarg(1)));
2980 }
2981
2982 fn i32_store(&mut self, mem: &Memory) {
2983 self.instruction(I32Store(mem.memarg(2)));
2984 }
2985
2986 fn i64_store(&mut self, mem: &Memory) {
2987 self.instruction(I64Store(mem.memarg(3)));
2988 }
2989
2990 fn ptr_store(&mut self, mem: &Memory) {
2991 if mem.opts.memory64 {
2992 self.i64_store(mem);
2993 } else {
2994 self.i32_store(mem);
2995 }
2996 }
2997
2998 fn f32_store(&mut self, mem: &Memory) {
2999 self.instruction(F32Store(mem.memarg(2)));
3000 }
3001
3002 fn f64_store(&mut self, mem: &Memory) {
3003 self.instruction(F64Store(mem.memarg(3)));
3004 }
3005}
3006
3007impl<'a> Source<'a> {
3008 fn record_field_srcs<'b>(
3015 &'b self,
3016 types: &'b ComponentTypesBuilder,
3017 fields: impl IntoIterator<Item = InterfaceType> + 'b,
3018 ) -> impl Iterator<Item = Source<'a>> + 'b
3019 where
3020 'a: 'b,
3021 {
3022 let mut offset = 0;
3023 fields.into_iter().map(move |ty| match self {
3024 Source::Memory(mem) => {
3025 let mem = next_field_offset(&mut offset, types, &ty, mem);
3026 Source::Memory(mem)
3027 }
3028 Source::Stack(stack) => {
3029 let cnt = types.flat_types(&ty).unwrap().len() as u32;
3030 offset += cnt;
3031 Source::Stack(stack.slice((offset - cnt) as usize..offset as usize))
3032 }
3033 })
3034 }
3035
3036 fn payload_src(
3038 &self,
3039 types: &ComponentTypesBuilder,
3040 info: &VariantInfo,
3041 case: Option<&InterfaceType>,
3042 ) -> Source<'a> {
3043 match self {
3044 Source::Stack(s) => {
3045 let flat_len = match case {
3046 Some(case) => types.flat_types(case).unwrap().len(),
3047 None => 0,
3048 };
3049 Source::Stack(s.slice(1..s.locals.len()).slice(0..flat_len))
3050 }
3051 Source::Memory(mem) => {
3052 let mem = if mem.opts.memory64 {
3053 mem.bump(info.payload_offset64)
3054 } else {
3055 mem.bump(info.payload_offset32)
3056 };
3057 Source::Memory(mem)
3058 }
3059 }
3060 }
3061
3062 fn opts(&self) -> &'a Options {
3063 match self {
3064 Source::Stack(s) => s.opts,
3065 Source::Memory(mem) => mem.opts,
3066 }
3067 }
3068}
3069
3070impl<'a> Destination<'a> {
3071 fn record_field_dsts<'b>(
3073 &'b self,
3074 types: &'b ComponentTypesBuilder,
3075 fields: impl IntoIterator<Item = InterfaceType> + 'b,
3076 ) -> impl Iterator<Item = Destination> + 'b
3077 where
3078 'a: 'b,
3079 {
3080 let mut offset = 0;
3081 fields.into_iter().map(move |ty| match self {
3082 Destination::Memory(mem) => {
3083 let mem = next_field_offset(&mut offset, types, &ty, mem);
3084 Destination::Memory(mem)
3085 }
3086 Destination::Stack(s, opts) => {
3087 let cnt = types.flat_types(&ty).unwrap().len() as u32;
3088 offset += cnt;
3089 Destination::Stack(&s[(offset - cnt) as usize..offset as usize], opts)
3090 }
3091 })
3092 }
3093
3094 fn payload_dst(
3096 &self,
3097 types: &ComponentTypesBuilder,
3098 info: &VariantInfo,
3099 case: Option<&InterfaceType>,
3100 ) -> Destination {
3101 match self {
3102 Destination::Stack(s, opts) => {
3103 let flat_len = match case {
3104 Some(case) => types.flat_types(case).unwrap().len(),
3105 None => 0,
3106 };
3107 Destination::Stack(&s[1..][..flat_len], opts)
3108 }
3109 Destination::Memory(mem) => {
3110 let mem = if mem.opts.memory64 {
3111 mem.bump(info.payload_offset64)
3112 } else {
3113 mem.bump(info.payload_offset32)
3114 };
3115 Destination::Memory(mem)
3116 }
3117 }
3118 }
3119
3120 fn opts(&self) -> &'a Options {
3121 match self {
3122 Destination::Stack(_, opts) => opts,
3123 Destination::Memory(mem) => mem.opts,
3124 }
3125 }
3126}
3127
3128fn next_field_offset<'a>(
3129 offset: &mut u32,
3130 types: &ComponentTypesBuilder,
3131 field: &InterfaceType,
3132 mem: &Memory<'a>,
3133) -> Memory<'a> {
3134 let abi = types.canonical_abi(field);
3135 let offset = if mem.opts.memory64 {
3136 abi.next_field64(offset)
3137 } else {
3138 abi.next_field32(offset)
3139 };
3140 mem.bump(offset)
3141}
3142
3143impl<'a> Memory<'a> {
3144 fn memarg(&self, align: u32) -> MemArg {
3145 MemArg {
3146 offset: u64::from(self.offset),
3147 align,
3148 memory_index: self.opts.memory.unwrap().as_u32(),
3149 }
3150 }
3151
3152 fn bump(&self, offset: u32) -> Memory<'a> {
3153 Memory {
3154 opts: self.opts,
3155 addr: TempLocal::new(self.addr.idx, self.addr.ty),
3156 offset: self.offset + offset,
3157 }
3158 }
3159}
3160
3161impl<'a> Stack<'a> {
3162 fn slice(&self, range: Range<usize>) -> Stack<'a> {
3163 Stack {
3164 locals: &self.locals[range],
3165 opts: self.opts,
3166 }
3167 }
3168}
3169
3170struct VariantCase<'a> {
3171 src_i: u32,
3172 src_ty: Option<&'a InterfaceType>,
3173 dst_i: u32,
3174 dst_ty: Option<&'a InterfaceType>,
3175}
3176
3177fn variant_info<'a, I>(types: &ComponentTypesBuilder, cases: I) -> VariantInfo
3178where
3179 I: IntoIterator<Item = Option<&'a InterfaceType>>,
3180 I::IntoIter: ExactSizeIterator,
3181{
3182 VariantInfo::new(
3183 cases
3184 .into_iter()
3185 .map(|ty| ty.map(|ty| types.canonical_abi(ty))),
3186 )
3187 .0
3188}
3189
3190enum MallocSize {
3191 Const(u32),
3192 Local(u32),
3193}
3194
3195struct WasmString<'a> {
3196 ptr: TempLocal,
3197 len: TempLocal,
3198 opts: &'a Options,
3199}
3200
3201struct TempLocal {
3202 idx: u32,
3203 ty: ValType,
3204 needs_free: bool,
3205}
3206
3207impl TempLocal {
3208 fn new(idx: u32, ty: ValType) -> TempLocal {
3209 TempLocal {
3210 idx,
3211 ty,
3212 needs_free: false,
3213 }
3214 }
3215}
3216
3217impl std::ops::Drop for TempLocal {
3218 fn drop(&mut self) {
3219 if self.needs_free {
3220 panic!("temporary local not free'd");
3221 }
3222 }
3223}
3224
3225impl From<FlatType> for ValType {
3226 fn from(ty: FlatType) -> ValType {
3227 match ty {
3228 FlatType::I32 => ValType::I32,
3229 FlatType::I64 => ValType::I64,
3230 FlatType::F32 => ValType::F32,
3231 FlatType::F64 => ValType::F64,
3232 }
3233 }
3234}