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 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 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
129pub(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 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 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 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 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 emit_resource_call: false,
203 };
204 compiler.translate(&helper.src.ty, &src, &helper.dst.ty, &dst);
205 compiler.finish();
206}
207
208enum Source<'a> {
211 Stack(Stack<'a>),
217
218 Memory(Memory<'a>),
221}
222
223enum Destination<'a> {
225 Stack(&'a [ValType], &'a Options),
231
232 Memory(Memory<'a>),
234}
235
236struct Stack<'a> {
237 locals: &'a [(u32, ValType)],
243 opts: &'a Options,
245}
246
247struct Memory<'a> {
249 opts: &'a Options,
251 addr: TempLocal,
254 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 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 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, ¶m_locals);
308 self.set_flag(adapter.lift.flags, FLAG_MAY_LEAVE, true);
309
310 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 self.set_flag(adapter.lower.flags, FLAG_MAY_LEAVE, false);
332 self.translate_results(adapter, ¶m_locals, &result_locals);
333 self.set_flag(adapter.lower.flags, FLAG_MAY_LEAVE, true);
334
335 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 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: ¶m_locals[..flat.len()],
388 opts: lower_opts,
389 })
390 } else {
391 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 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 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 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 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 let cost = match src_ty {
558 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 InterfaceType::Char => 1,
576
577 InterfaceType::String => 40,
580
581 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 InterfaceType::Option(_) | InterfaceType::Result(_) => 2,
601
602 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 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 None => {
658 let src_loc = match src {
659 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 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 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 self.flush_code();
711 self.module.funcs[self.result].body.push(Body::Call(helper));
712
713 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 assert!(matches!(dst_ty, InterfaceType::Bool));
753 self.push_dst_addr(dst);
754
755 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 self.validate_string_inbounds(src, src_byte_len);
1210 self.validate_string_inbounds(&dst, dst_byte_len.idx);
1211
1212 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 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 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 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 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 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 self.instruction(LocalGet(dst.ptr.idx)); self.instruction(LocalGet(dst_byte_len.idx)); self.ptr_uconst(dst.opts, 1); 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 self.validate_string_inbounds(&dst, dst_byte_len.idx);
1333
1334 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 self.instruction(LocalGet(dst.len.idx));
1360 self.ptr_add(dst.opts);
1361 self.instruction(LocalSet(dst.len.idx));
1362
1363 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 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)); 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()));
1387 self.instruction(LocalSet(dst.ptr.idx));
1388 self.instruction(End);
1389
1390 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); 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 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 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); self.free_temp_local(dst_byte_len);
1480
1481 dst
1482 }
1483
1484 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 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 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 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()));
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 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 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 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)); 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)); 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()));
1629 self.instruction(LocalSet(dst.ptr.idx));
1630 self.instruction(End);
1631
1632 self.instruction(Else); if src_enc.width() == 1 {
1641 self.validate_string_length_u8(src, 2);
1642 }
1643
1644 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());
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 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 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)); self.instruction(LocalGet(dst_byte_len.idx)); self.ptr_uconst(dst.opts, 2); 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 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); 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 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 self.instruction(MemorySize(opts.memory.unwrap().as_u32()));
1766 extend_to_64(self);
1767 self.instruction(I64Const(16));
1768 self.instruction(I64Shl);
1769
1770 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 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 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 let src_mem = self.memory_operand(src_opts, src_ptr, src_align);
1837
1838 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 let dst_mem = self.malloc(dst_opts, MallocSize::Local(dst_byte_len.idx), dst_align);
1858
1859 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 if src_size > 0 || dst_size > 0 {
1881 self.instruction(Block(BlockType::Empty));
1884
1885 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 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 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 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 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); self.instruction(End); self.free_temp_local(cur_dst_ptr);
1937 self.free_temp_local(cur_src_ptr);
1938 self.free_temp_local(remaining);
1939 }
1940
1941 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 if elt_size == 0 {
1973 self.ptr_uconst(opts, 0);
1974 return self.local_set_new_tmp(opts.ptr());
1975 }
1976
1977 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 self.instruction(Block(BlockType::Empty));
2003 self.instruction(Block(BlockType::Empty));
2004 self.instruction(LocalGet(len_local));
2005 match opts.ptr() {
2006 ValType::I32 => self.instruction(I64ExtendI32U),
2010
2011 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 self.instruction(I64Const(elt_size.into()));
2034 self.instruction(I64Mul);
2035 let tmp = self.local_tee_new_tmp(ValType::I64);
2036 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 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 assert_eq!(src_ty.fields.len(), dst_ty.fields.len());
2088
2089 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 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 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 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 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 let src_cases_len = src_cases.len();
2373 for _ in 0..src_cases_len - 1 {
2374 self.instruction(Block(BlockType::Empty));
2375 }
2376
2377 self.instruction(Block(BlockType::Empty));
2379
2380 self.instruction(Block(BlockType::Empty));
2383
2384 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 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); self.trap(Trap::InvalidDiscriminant);
2404 self.instruction(End); 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 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 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 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 if src_i != src_cases_len - 1 {
2469 self.instruction(Br(src_cases_len - src_i - 1));
2470 }
2471 self.instruction(End); }
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 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 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 fn local_tee_new_tmp(&mut self, ty: ValType) -> TempLocal {
2630 self.gen_temp_local(ty, LocalTee)
2631 }
2632
2633 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 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 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 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 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 self.instruction(End);
2705 self.flush_code();
2706
2707 self.module.funcs[self.result].filled_in = true;
2710 }
2711
2712 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 (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 | (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 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 (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 | (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 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 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 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 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}