1use crate::component::{
19 CanonicalAbiInfo, ComponentTypesBuilder, FLAG_MAY_ENTER, FLAG_MAY_LEAVE, FixedEncoding as FE,
20 FlatType, InterfaceType, MAX_FLAT_ASYNC_PARAMS, MAX_FLAT_PARAMS, PREPARE_ASYNC_NO_RESULT,
21 PREPARE_ASYNC_WITH_RESULT, START_FLAG_ASYNC_CALLEE, StringEncoding, Transcode,
22 TypeComponentLocalErrorContextTableIndex, TypeEnumIndex, TypeFlagsIndex, TypeFutureTableIndex,
23 TypeListIndex, TypeOptionIndex, TypeRecordIndex, TypeResourceTableIndex, TypeResultIndex,
24 TypeStreamTableIndex, TypeTupleIndex, TypeVariantIndex, VariantInfo,
25};
26use crate::fact::signature::Signature;
27use crate::fact::transcode::Transcoder;
28use crate::fact::traps::Trap;
29use crate::fact::{
30 AdapterData, Body, Function, FunctionId, Helper, HelperLocation, HelperType,
31 LinearMemoryOptions, Module, Options,
32};
33use crate::prelude::*;
34use crate::{FuncIndex, GlobalIndex};
35use std::collections::HashMap;
36use std::mem;
37use std::ops::Range;
38use wasm_encoder::{BlockType, Encode, Instruction, Instruction::*, MemArg, ValType};
39use wasmtime_component_util::{DiscriminantSize, FlagsSize};
40
41use super::DataModel;
42
43const MAX_STRING_BYTE_LENGTH: u32 = 1 << 31;
44const UTF16_TAG: u32 = 1 << 31;
45
46const INITIAL_FUEL: usize = 1_000;
49
50struct Compiler<'a, 'b> {
51 types: &'a ComponentTypesBuilder,
52 module: &'b mut Module<'a>,
53 result: FunctionId,
54
55 code: Vec<u8>,
57
58 nlocals: u32,
60
61 free_locals: HashMap<ValType, Vec<u32>>,
63
64 traps: Vec<(usize, Trap)>,
68
69 fuel: usize,
78
79 emit_resource_call: bool,
84}
85
86pub(super) fn compile(module: &mut Module<'_>, adapter: &AdapterData) {
87 fn compiler<'a, 'b>(
88 module: &'b mut Module<'a>,
89 adapter: &AdapterData,
90 ) -> (Compiler<'a, 'b>, Signature, Signature) {
91 let lower_sig = module.types.signature(&adapter.lower);
92 let lift_sig = module.types.signature(&adapter.lift);
93 let ty = module
94 .core_types
95 .function(&lower_sig.params, &lower_sig.results);
96 let result = module
97 .funcs
98 .push(Function::new(Some(adapter.name.clone()), ty));
99
100 let emit_resource_call = module.types.contains_borrow_resource(&adapter.lower);
105 assert_eq!(
106 emit_resource_call,
107 module.types.contains_borrow_resource(&adapter.lift)
108 );
109
110 (
111 Compiler::new(
112 module,
113 result,
114 lower_sig.params.len() as u32,
115 emit_resource_call,
116 ),
117 lower_sig,
118 lift_sig,
119 )
120 }
121
122 let async_start_adapter = |module: &mut Module| {
128 let sig = module
129 .types
130 .async_start_signature(&adapter.lower, &adapter.lift);
131 let ty = module.core_types.function(&sig.params, &sig.results);
132 let result = module.funcs.push(Function::new(
133 Some(format!("[async-start]{}", adapter.name)),
134 ty,
135 ));
136
137 Compiler::new(module, result, sig.params.len() as u32, false)
138 .compile_async_start_adapter(adapter, &sig);
139
140 result
141 };
142
143 let async_return_adapter = |module: &mut Module| {
152 let sig = module
153 .types
154 .async_return_signature(&adapter.lower, &adapter.lift);
155 let ty = module.core_types.function(&sig.params, &sig.results);
156 let result = module.funcs.push(Function::new(
157 Some(format!("[async-return]{}", adapter.name)),
158 ty,
159 ));
160
161 Compiler::new(module, result, sig.params.len() as u32, false)
162 .compile_async_return_adapter(adapter, &sig);
163
164 result
165 };
166
167 match (adapter.lower.options.async_, adapter.lift.options.async_) {
168 (false, false) => {
169 let (compiler, lower_sig, lift_sig) = compiler(module, adapter);
172 compiler.compile_sync_to_sync_adapter(adapter, &lower_sig, &lift_sig)
173 }
174 (true, true) => {
175 let start = async_start_adapter(module);
191 let return_ = async_return_adapter(module);
192 let (compiler, lower_sig, lift_sig) = compiler(module, adapter);
193 compiler.compile_async_to_async_adapter(
194 adapter,
195 start,
196 return_,
197 i32::try_from(lift_sig.params.len()).unwrap(),
198 &lower_sig,
199 );
200 }
201 (false, true) => {
202 let start = async_start_adapter(module);
215 let return_ = async_return_adapter(module);
216 let (compiler, lower_sig, lift_sig) = compiler(module, adapter);
217 compiler.compile_sync_to_async_adapter(
218 adapter,
219 start,
220 return_,
221 i32::try_from(lift_sig.params.len()).unwrap(),
222 &lower_sig,
223 );
224 }
225 (true, false) => {
226 let lift_sig = module.types.signature(&adapter.lift);
246 let start = async_start_adapter(module);
247 let return_ = async_return_adapter(module);
248 let (compiler, lower_sig, ..) = compiler(module, adapter);
249 compiler.compile_async_to_sync_adapter(
250 adapter,
251 start,
252 return_,
253 i32::try_from(lift_sig.params.len()).unwrap(),
254 i32::try_from(lift_sig.results.len()).unwrap(),
255 &lower_sig,
256 );
257 }
258 }
259}
260
261pub(super) fn compile_helper(module: &mut Module<'_>, result: FunctionId, helper: Helper) {
268 let mut nlocals = 0;
269 let src_flat;
270 let src = match helper.src.loc {
271 HelperLocation::Stack => {
276 src_flat = module
277 .types
278 .flatten_types(&helper.src.opts, usize::MAX, [helper.src.ty])
279 .unwrap()
280 .iter()
281 .enumerate()
282 .map(|(i, ty)| (i as u32, *ty))
283 .collect::<Vec<_>>();
284 nlocals += src_flat.len() as u32;
285 Source::Stack(Stack {
286 locals: &src_flat,
287 opts: &helper.src.opts,
288 })
289 }
290 HelperLocation::Memory => {
293 nlocals += 1;
294 Source::Memory(Memory {
295 opts: &helper.src.opts,
296 addr: TempLocal::new(0, helper.src.opts.data_model.unwrap_memory().ptr()),
297 offset: 0,
298 })
299 }
300 HelperLocation::StructField | HelperLocation::ArrayElement => todo!("CM+GC"),
301 };
302 let dst_flat;
303 let dst = match helper.dst.loc {
304 HelperLocation::Stack => {
307 dst_flat = module
308 .types
309 .flatten_types(&helper.dst.opts, usize::MAX, [helper.dst.ty])
310 .unwrap();
311 Destination::Stack(&dst_flat, &helper.dst.opts)
312 }
313 HelperLocation::Memory => {
316 nlocals += 1;
317 Destination::Memory(Memory {
318 opts: &helper.dst.opts,
319 addr: TempLocal::new(
320 nlocals - 1,
321 helper.dst.opts.data_model.unwrap_memory().ptr(),
322 ),
323 offset: 0,
324 })
325 }
326 HelperLocation::StructField | HelperLocation::ArrayElement => todo!("CM+GC"),
327 };
328 let mut compiler = Compiler {
329 types: module.types,
330 module,
331 code: Vec::new(),
332 nlocals,
333 free_locals: HashMap::new(),
334 traps: Vec::new(),
335 result,
336 fuel: INITIAL_FUEL,
337 emit_resource_call: false,
340 };
341 compiler.translate(&helper.src.ty, &src, &helper.dst.ty, &dst);
342 compiler.finish();
343}
344
345enum Source<'a> {
348 Stack(Stack<'a>),
354
355 Memory(Memory<'a>),
358
359 #[allow(dead_code, reason = "CM+GC is still WIP")]
362 Struct(GcStruct<'a>),
363
364 #[allow(dead_code, reason = "CM+GC is still WIP")]
367 Array(GcArray<'a>),
368}
369
370enum Destination<'a> {
372 Stack(&'a [ValType], &'a Options),
378
379 Memory(Memory<'a>),
381
382 #[allow(dead_code, reason = "CM+GC is still WIP")]
385 Struct(GcStruct<'a>),
386
387 #[allow(dead_code, reason = "CM+GC is still WIP")]
390 Array(GcArray<'a>),
391}
392
393struct Stack<'a> {
394 locals: &'a [(u32, ValType)],
400 opts: &'a Options,
402}
403
404struct Memory<'a> {
406 opts: &'a Options,
408 addr: TempLocal,
411 offset: u32,
414}
415
416impl<'a> Memory<'a> {
417 fn mem_opts(&self) -> &'a LinearMemoryOptions {
418 self.opts.data_model.unwrap_memory()
419 }
420}
421
422struct GcStruct<'a> {
424 opts: &'a Options,
425 }
427
428struct GcArray<'a> {
430 opts: &'a Options,
431 }
433
434impl<'a, 'b> Compiler<'a, 'b> {
435 fn new(
436 module: &'b mut Module<'a>,
437 result: FunctionId,
438 nlocals: u32,
439 emit_resource_call: bool,
440 ) -> Self {
441 Self {
442 types: module.types,
443 module,
444 result,
445 code: Vec::new(),
446 nlocals,
447 free_locals: HashMap::new(),
448 traps: Vec::new(),
449 fuel: INITIAL_FUEL,
450 emit_resource_call,
451 }
452 }
453
454 fn compile_async_to_async_adapter(
464 mut self,
465 adapter: &AdapterData,
466 start: FunctionId,
467 return_: FunctionId,
468 param_count: i32,
469 lower_sig: &Signature,
470 ) {
471 let start_call =
472 self.module
473 .import_async_start_call(&adapter.name, adapter.lift.options.callback, None);
474
475 self.call_prepare(adapter, start, return_, lower_sig, false);
476
477 self.module.exports.push((
486 adapter.callee.as_u32(),
487 format!("[adapter-callee]{}", adapter.name),
488 ));
489
490 self.instruction(RefFunc(adapter.callee.as_u32()));
491 self.instruction(I32Const(param_count));
492 self.instruction(I32Const(1));
496 self.instruction(I32Const(START_FLAG_ASYNC_CALLEE));
497 self.instruction(Call(start_call.as_u32()));
498
499 self.finish()
500 }
501
502 fn call_prepare(
515 &mut self,
516 adapter: &AdapterData,
517 start: FunctionId,
518 return_: FunctionId,
519 lower_sig: &Signature,
520 prepare_sync: bool,
521 ) {
522 let prepare = self.module.import_prepare_call(
523 &adapter.name,
524 &lower_sig.params,
525 match adapter.lift.options.data_model {
526 DataModel::Gc {} => todo!("CM+GC"),
527 DataModel::LinearMemory(LinearMemoryOptions { memory, .. }) => memory,
528 },
529 );
530
531 self.flush_code();
532 self.module.funcs[self.result]
533 .body
534 .push(Body::RefFunc(start));
535 self.module.funcs[self.result]
536 .body
537 .push(Body::RefFunc(return_));
538 self.instruction(I32Const(
539 i32::try_from(adapter.lower.instance.as_u32()).unwrap(),
540 ));
541 self.instruction(I32Const(
542 i32::try_from(adapter.lift.instance.as_u32()).unwrap(),
543 ));
544 self.instruction(I32Const(
545 i32::try_from(self.types[adapter.lift.ty].results.as_u32()).unwrap(),
546 ));
547 self.instruction(I32Const(if self.types[adapter.lift.ty].async_ {
548 1
549 } else {
550 0
551 }));
552 self.instruction(I32Const(i32::from(
553 adapter.lift.options.string_encoding as u8,
554 )));
555
556 let result_types = &self.types[self.types[adapter.lower.ty].results].types;
559 if prepare_sync {
560 self.instruction(I32Const(
561 i32::try_from(
562 self.types
563 .flatten_types(
564 &adapter.lower.options,
565 usize::MAX,
566 result_types.iter().copied(),
567 )
568 .map(|v| v.len())
569 .unwrap_or(usize::try_from(i32::MAX).unwrap()),
570 )
571 .unwrap(),
572 ));
573 } else {
574 if result_types.len() > 0 {
575 self.instruction(I32Const(PREPARE_ASYNC_WITH_RESULT.cast_signed()));
576 } else {
577 self.instruction(I32Const(PREPARE_ASYNC_NO_RESULT.cast_signed()));
578 }
579 }
580
581 for index in 0..lower_sig.params.len() {
583 self.instruction(LocalGet(u32::try_from(index).unwrap()));
584 }
585 self.instruction(Call(prepare.as_u32()));
586 }
587
588 fn compile_sync_to_async_adapter(
598 mut self,
599 adapter: &AdapterData,
600 start: FunctionId,
601 return_: FunctionId,
602 lift_param_count: i32,
603 lower_sig: &Signature,
604 ) {
605 let start_call = self.module.import_sync_start_call(
606 &adapter.name,
607 adapter.lift.options.callback,
608 &lower_sig.results,
609 );
610
611 self.call_prepare(adapter, start, return_, lower_sig, true);
612
613 self.module.exports.push((
622 adapter.callee.as_u32(),
623 format!("[adapter-callee]{}", adapter.name),
624 ));
625
626 self.instruction(RefFunc(adapter.callee.as_u32()));
627 self.instruction(I32Const(lift_param_count));
628 self.instruction(Call(start_call.as_u32()));
629
630 self.finish()
631 }
632
633 fn compile_async_to_sync_adapter(
643 mut self,
644 adapter: &AdapterData,
645 start: FunctionId,
646 return_: FunctionId,
647 param_count: i32,
648 result_count: i32,
649 lower_sig: &Signature,
650 ) {
651 let start_call =
652 self.module
653 .import_async_start_call(&adapter.name, None, adapter.lift.post_return);
654
655 self.call_prepare(adapter, start, return_, lower_sig, false);
656
657 self.module.exports.push((
661 adapter.callee.as_u32(),
662 format!("[adapter-callee]{}", adapter.name),
663 ));
664
665 self.instruction(RefFunc(adapter.callee.as_u32()));
666 self.instruction(I32Const(param_count));
667 self.instruction(I32Const(result_count));
668 self.instruction(I32Const(0));
669 self.instruction(Call(start_call.as_u32()));
670
671 self.finish()
672 }
673
674 fn compile_async_start_adapter(mut self, adapter: &AdapterData, sig: &Signature) {
680 let param_locals = sig
681 .params
682 .iter()
683 .enumerate()
684 .map(|(i, ty)| (i as u32, *ty))
685 .collect::<Vec<_>>();
686
687 self.set_flag(adapter.lift.flags, FLAG_MAY_LEAVE, false);
688 self.translate_params(adapter, ¶m_locals);
689 self.set_flag(adapter.lift.flags, FLAG_MAY_LEAVE, true);
690
691 self.finish();
692 }
693
694 fn compile_async_return_adapter(mut self, adapter: &AdapterData, sig: &Signature) {
703 let param_locals = sig
704 .params
705 .iter()
706 .enumerate()
707 .map(|(i, ty)| (i as u32, *ty))
708 .collect::<Vec<_>>();
709
710 self.set_flag(adapter.lower.flags, FLAG_MAY_LEAVE, false);
711 self.translate_results(adapter, ¶m_locals, ¶m_locals);
722 self.set_flag(adapter.lower.flags, FLAG_MAY_LEAVE, true);
723
724 self.finish()
725 }
726
727 fn compile_sync_to_sync_adapter(
734 mut self,
735 adapter: &AdapterData,
736 lower_sig: &Signature,
737 lift_sig: &Signature,
738 ) {
739 self.trap_if_not_flag(adapter.lower.flags, FLAG_MAY_LEAVE, Trap::CannotLeave);
745 if adapter.called_as_export {
746 self.trap_if_not_flag(adapter.lift.flags, FLAG_MAY_ENTER, Trap::CannotEnter);
747 self.set_flag(adapter.lift.flags, FLAG_MAY_ENTER, false);
748 } else if self.module.debug {
749 self.assert_not_flag(
750 adapter.lift.flags,
751 FLAG_MAY_ENTER,
752 "may_enter should be unset",
753 );
754 }
755
756 if self.types[adapter.lift.ty].async_ {
757 let check_blocking = self.module.import_check_blocking();
758 self.instruction(Call(check_blocking.as_u32()));
759 }
760
761 if self.emit_resource_call {
762 let enter = self.module.import_resource_enter_call();
763 self.instruction(Call(enter.as_u32()));
764 }
765
766 self.set_flag(adapter.lift.flags, FLAG_MAY_LEAVE, false);
779 let param_locals = lower_sig
780 .params
781 .iter()
782 .enumerate()
783 .map(|(i, ty)| (i as u32, *ty))
784 .collect::<Vec<_>>();
785 self.translate_params(adapter, ¶m_locals);
786 self.set_flag(adapter.lift.flags, FLAG_MAY_LEAVE, true);
787
788 self.instruction(Call(adapter.callee.as_u32()));
792 let mut result_locals = Vec::with_capacity(lift_sig.results.len());
793 let mut temps = Vec::new();
794 for ty in lift_sig.results.iter().rev() {
795 let local = self.local_set_new_tmp(*ty);
796 result_locals.push((local.idx, *ty));
797 temps.push(local);
798 }
799 result_locals.reverse();
800
801 self.set_flag(adapter.lower.flags, FLAG_MAY_LEAVE, false);
810 self.translate_results(adapter, ¶m_locals, &result_locals);
811 self.set_flag(adapter.lower.flags, FLAG_MAY_LEAVE, true);
812
813 if let Some(func) = adapter.lift.post_return {
816 for (result, _) in result_locals.iter() {
817 self.instruction(LocalGet(*result));
818 }
819 self.instruction(Call(func.as_u32()));
820 }
821 if adapter.called_as_export {
822 self.set_flag(adapter.lift.flags, FLAG_MAY_ENTER, true);
823 }
824
825 for tmp in temps {
826 self.free_temp_local(tmp);
827 }
828
829 if self.emit_resource_call {
830 let exit = self.module.import_resource_exit_call();
831 self.instruction(Call(exit.as_u32()));
832 }
833
834 self.finish()
835 }
836
837 fn translate_params(&mut self, adapter: &AdapterData, param_locals: &[(u32, ValType)]) {
838 let src_tys = self.types[adapter.lower.ty].params;
839 let src_tys = self.types[src_tys]
840 .types
841 .iter()
842 .copied()
843 .collect::<Vec<_>>();
844 let dst_tys = self.types[adapter.lift.ty].params;
845 let dst_tys = self.types[dst_tys]
846 .types
847 .iter()
848 .copied()
849 .collect::<Vec<_>>();
850 let lift_opts = &adapter.lift.options;
851 let lower_opts = &adapter.lower.options;
852
853 assert_eq!(src_tys.len(), dst_tys.len());
855
856 let max_flat_params = if adapter.lower.options.async_ {
860 MAX_FLAT_ASYNC_PARAMS
861 } else {
862 MAX_FLAT_PARAMS
863 };
864 let src_flat =
865 self.types
866 .flatten_types(lower_opts, max_flat_params, src_tys.iter().copied());
867 let dst_flat =
868 self.types
869 .flatten_types(lift_opts, MAX_FLAT_PARAMS, dst_tys.iter().copied());
870
871 let src = if let Some(flat) = &src_flat {
872 Source::Stack(Stack {
873 locals: ¶m_locals[..flat.len()],
874 opts: lower_opts,
875 })
876 } else {
877 let lower_mem_opts = lower_opts.data_model.unwrap_memory();
881 let (addr, ty) = param_locals[0];
882 assert_eq!(ty, lower_mem_opts.ptr());
883 let align = src_tys
884 .iter()
885 .map(|t| self.types.align(lower_mem_opts, t))
886 .max()
887 .unwrap_or(1);
888 Source::Memory(self.memory_operand(lower_opts, TempLocal::new(addr, ty), align))
889 };
890
891 let dst = if let Some(flat) = &dst_flat {
892 Destination::Stack(flat, lift_opts)
893 } else {
894 let abi = CanonicalAbiInfo::record(dst_tys.iter().map(|t| self.types.canonical_abi(t)));
895 match lift_opts.data_model {
896 DataModel::Gc {} => todo!("CM+GC"),
897 DataModel::LinearMemory(LinearMemoryOptions { memory64, .. }) => {
898 let (size, align) = if memory64 {
899 (abi.size64, abi.align64)
900 } else {
901 (abi.size32, abi.align32)
902 };
903
904 let size = MallocSize::Const(size);
907 Destination::Memory(self.malloc(lift_opts, size, align))
908 }
909 }
910 };
911
912 let srcs = src
913 .record_field_srcs(self.types, src_tys.iter().copied())
914 .zip(src_tys.iter());
915 let dsts = dst
916 .record_field_dsts(self.types, dst_tys.iter().copied())
917 .zip(dst_tys.iter());
918 for ((src, src_ty), (dst, dst_ty)) in srcs.zip(dsts) {
919 self.translate(&src_ty, &src, &dst_ty, &dst);
920 }
921
922 if let Destination::Memory(mem) = dst {
926 self.instruction(LocalGet(mem.addr.idx));
927 self.free_temp_local(mem.addr);
928 }
929 }
930
931 fn translate_results(
932 &mut self,
933 adapter: &AdapterData,
934 param_locals: &[(u32, ValType)],
935 result_locals: &[(u32, ValType)],
936 ) {
937 let src_tys = self.types[adapter.lift.ty].results;
938 let src_tys = self.types[src_tys]
939 .types
940 .iter()
941 .copied()
942 .collect::<Vec<_>>();
943 let dst_tys = self.types[adapter.lower.ty].results;
944 let dst_tys = self.types[dst_tys]
945 .types
946 .iter()
947 .copied()
948 .collect::<Vec<_>>();
949 let lift_opts = &adapter.lift.options;
950 let lower_opts = &adapter.lower.options;
951
952 let src_flat = self
953 .types
954 .flatten_lifting_types(lift_opts, src_tys.iter().copied());
955 let dst_flat = self
956 .types
957 .flatten_lowering_types(lower_opts, dst_tys.iter().copied());
958
959 let src = if src_flat.is_some() {
960 Source::Stack(Stack {
961 locals: result_locals,
962 opts: lift_opts,
963 })
964 } else {
965 let lift_mem_opts = lift_opts.data_model.unwrap_memory();
970 let align = src_tys
971 .iter()
972 .map(|t| self.types.align(lift_mem_opts, t))
973 .max()
974 .unwrap_or(1);
975 assert_eq!(
976 result_locals.len(),
977 if lower_opts.async_ || lift_opts.async_ {
978 2
979 } else {
980 1
981 }
982 );
983 let (addr, ty) = result_locals[0];
984 assert_eq!(ty, lift_opts.data_model.unwrap_memory().ptr());
985 Source::Memory(self.memory_operand(lift_opts, TempLocal::new(addr, ty), align))
986 };
987
988 let dst = if let Some(flat) = &dst_flat {
989 Destination::Stack(flat, lower_opts)
990 } else {
991 let lower_mem_opts = lower_opts.data_model.unwrap_memory();
995 let align = dst_tys
996 .iter()
997 .map(|t| self.types.align(lower_mem_opts, t))
998 .max()
999 .unwrap_or(1);
1000 let (addr, ty) = *param_locals.last().expect("no retptr");
1001 assert_eq!(ty, lower_opts.data_model.unwrap_memory().ptr());
1002 Destination::Memory(self.memory_operand(lower_opts, TempLocal::new(addr, ty), align))
1003 };
1004
1005 let srcs = src
1006 .record_field_srcs(self.types, src_tys.iter().copied())
1007 .zip(src_tys.iter());
1008 let dsts = dst
1009 .record_field_dsts(self.types, dst_tys.iter().copied())
1010 .zip(dst_tys.iter());
1011 for ((src, src_ty), (dst, dst_ty)) in srcs.zip(dsts) {
1012 self.translate(&src_ty, &src, &dst_ty, &dst);
1013 }
1014 }
1015
1016 fn translate(
1017 &mut self,
1018 src_ty: &InterfaceType,
1019 src: &Source<'_>,
1020 dst_ty: &InterfaceType,
1021 dst: &Destination,
1022 ) {
1023 if let Source::Memory(mem) = src {
1024 self.assert_aligned(src_ty, mem);
1025 }
1026 if let Destination::Memory(mem) = dst {
1027 self.assert_aligned(dst_ty, mem);
1028 }
1029
1030 let cost = match src_ty {
1060 InterfaceType::Bool
1064 | InterfaceType::U8
1065 | InterfaceType::S8
1066 | InterfaceType::U16
1067 | InterfaceType::S16
1068 | InterfaceType::U32
1069 | InterfaceType::S32
1070 | InterfaceType::U64
1071 | InterfaceType::S64
1072 | InterfaceType::Float32
1073 | InterfaceType::Float64 => 0,
1074
1075 InterfaceType::Char => 1,
1078
1079 InterfaceType::String => 40,
1082
1083 InterfaceType::List(_) => 40,
1086
1087 InterfaceType::Flags(i) => {
1088 let count = self.module.types[*i].names.len();
1089 match FlagsSize::from_count(count) {
1090 FlagsSize::Size0 => 0,
1091 FlagsSize::Size1 | FlagsSize::Size2 => 1,
1092 FlagsSize::Size4Plus(n) => n.into(),
1093 }
1094 }
1095
1096 InterfaceType::Record(i) => self.types[*i].fields.len(),
1097 InterfaceType::Tuple(i) => self.types[*i].types.len(),
1098 InterfaceType::Variant(i) => self.types[*i].cases.len(),
1099 InterfaceType::Enum(i) => self.types[*i].names.len(),
1100
1101 InterfaceType::Option(_) | InterfaceType::Result(_) => 2,
1103
1104 InterfaceType::Own(_)
1106 | InterfaceType::Borrow(_)
1107 | InterfaceType::Future(_)
1108 | InterfaceType::Stream(_)
1109 | InterfaceType::ErrorContext(_) => 1,
1110 };
1111
1112 match self.fuel.checked_sub(cost) {
1113 Some(n) => {
1119 self.fuel = n;
1120 match src_ty {
1121 InterfaceType::Bool => self.translate_bool(src, dst_ty, dst),
1122 InterfaceType::U8 => self.translate_u8(src, dst_ty, dst),
1123 InterfaceType::S8 => self.translate_s8(src, dst_ty, dst),
1124 InterfaceType::U16 => self.translate_u16(src, dst_ty, dst),
1125 InterfaceType::S16 => self.translate_s16(src, dst_ty, dst),
1126 InterfaceType::U32 => self.translate_u32(src, dst_ty, dst),
1127 InterfaceType::S32 => self.translate_s32(src, dst_ty, dst),
1128 InterfaceType::U64 => self.translate_u64(src, dst_ty, dst),
1129 InterfaceType::S64 => self.translate_s64(src, dst_ty, dst),
1130 InterfaceType::Float32 => self.translate_f32(src, dst_ty, dst),
1131 InterfaceType::Float64 => self.translate_f64(src, dst_ty, dst),
1132 InterfaceType::Char => self.translate_char(src, dst_ty, dst),
1133 InterfaceType::String => self.translate_string(src, dst_ty, dst),
1134 InterfaceType::List(t) => self.translate_list(*t, src, dst_ty, dst),
1135 InterfaceType::Record(t) => self.translate_record(*t, src, dst_ty, dst),
1136 InterfaceType::Flags(f) => self.translate_flags(*f, src, dst_ty, dst),
1137 InterfaceType::Tuple(t) => self.translate_tuple(*t, src, dst_ty, dst),
1138 InterfaceType::Variant(v) => self.translate_variant(*v, src, dst_ty, dst),
1139 InterfaceType::Enum(t) => self.translate_enum(*t, src, dst_ty, dst),
1140 InterfaceType::Option(t) => self.translate_option(*t, src, dst_ty, dst),
1141 InterfaceType::Result(t) => self.translate_result(*t, src, dst_ty, dst),
1142 InterfaceType::Own(t) => self.translate_own(*t, src, dst_ty, dst),
1143 InterfaceType::Borrow(t) => self.translate_borrow(*t, src, dst_ty, dst),
1144 InterfaceType::Future(t) => self.translate_future(*t, src, dst_ty, dst),
1145 InterfaceType::Stream(t) => self.translate_stream(*t, src, dst_ty, dst),
1146 InterfaceType::ErrorContext(t) => {
1147 self.translate_error_context(*t, src, dst_ty, dst)
1148 }
1149 }
1150 }
1151
1152 None => {
1158 let src_loc = match src {
1159 Source::Stack(stack) => {
1163 for (i, ty) in stack
1164 .opts
1165 .flat_types(src_ty, self.types)
1166 .unwrap()
1167 .iter()
1168 .enumerate()
1169 {
1170 let stack = stack.slice(i..i + 1);
1171 self.stack_get(&stack, (*ty).into());
1172 }
1173 HelperLocation::Stack
1174 }
1175 Source::Memory(mem) => {
1180 self.push_mem_addr(mem);
1181 HelperLocation::Memory
1182 }
1183 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1184 };
1185 let dst_loc = match dst {
1186 Destination::Stack(..) => HelperLocation::Stack,
1187 Destination::Memory(mem) => {
1188 self.push_mem_addr(mem);
1189 HelperLocation::Memory
1190 }
1191 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1192 };
1193 let helper = self.module.translate_helper(Helper {
1199 src: HelperType {
1200 ty: *src_ty,
1201 opts: *src.opts(),
1202 loc: src_loc,
1203 },
1204 dst: HelperType {
1205 ty: *dst_ty,
1206 opts: *dst.opts(),
1207 loc: dst_loc,
1208 },
1209 });
1210 self.flush_code();
1213 self.module.funcs[self.result].body.push(Body::Call(helper));
1214
1215 if let Destination::Stack(tys, opts) = dst {
1224 let flat = self
1225 .types
1226 .flatten_types(opts, usize::MAX, [*dst_ty])
1227 .unwrap();
1228 assert_eq!(flat.len(), tys.len());
1229 let locals = flat
1230 .iter()
1231 .rev()
1232 .map(|ty| self.local_set_new_tmp(*ty))
1233 .collect::<Vec<_>>();
1234 for (ty, local) in tys.iter().zip(locals.into_iter().rev()) {
1235 self.instruction(LocalGet(local.idx));
1236 self.stack_set(std::slice::from_ref(ty), local.ty);
1237 self.free_temp_local(local);
1238 }
1239 }
1240 }
1241 }
1242 }
1243
1244 fn push_mem_addr(&mut self, mem: &Memory<'_>) {
1245 self.instruction(LocalGet(mem.addr.idx));
1246 if mem.offset != 0 {
1247 self.ptr_uconst(mem.mem_opts(), mem.offset);
1248 self.ptr_add(mem.mem_opts());
1249 }
1250 }
1251
1252 fn translate_bool(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1253 assert!(matches!(dst_ty, InterfaceType::Bool));
1255 self.push_dst_addr(dst);
1256
1257 self.instruction(I32Const(1));
1260 self.instruction(I32Const(0));
1261 match src {
1262 Source::Memory(mem) => self.i32_load8u(mem),
1263 Source::Stack(stack) => self.stack_get(stack, ValType::I32),
1264 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1265 }
1266 self.instruction(Select);
1267
1268 match dst {
1269 Destination::Memory(mem) => self.i32_store8(mem),
1270 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1271 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1272 }
1273 }
1274
1275 fn translate_u8(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1276 assert!(matches!(dst_ty, InterfaceType::U8));
1278 self.convert_u8_mask(src, dst, 0xff);
1279 }
1280
1281 fn convert_u8_mask(&mut self, src: &Source<'_>, dst: &Destination<'_>, mask: u8) {
1282 self.push_dst_addr(dst);
1283 let mut needs_mask = true;
1284 match src {
1285 Source::Memory(mem) => {
1286 self.i32_load8u(mem);
1287 needs_mask = mask != 0xff;
1288 }
1289 Source::Stack(stack) => {
1290 self.stack_get(stack, ValType::I32);
1291 }
1292 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1293 }
1294 if needs_mask {
1295 self.instruction(I32Const(i32::from(mask)));
1296 self.instruction(I32And);
1297 }
1298 match dst {
1299 Destination::Memory(mem) => self.i32_store8(mem),
1300 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1301 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1302 }
1303 }
1304
1305 fn translate_s8(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1306 assert!(matches!(dst_ty, InterfaceType::S8));
1308 self.push_dst_addr(dst);
1309 match src {
1310 Source::Memory(mem) => self.i32_load8s(mem),
1311 Source::Stack(stack) => {
1312 self.stack_get(stack, ValType::I32);
1313 self.instruction(I32Extend8S);
1314 }
1315 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1316 }
1317 match dst {
1318 Destination::Memory(mem) => self.i32_store8(mem),
1319 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1320 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1321 }
1322 }
1323
1324 fn translate_u16(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1325 assert!(matches!(dst_ty, InterfaceType::U16));
1327 self.convert_u16_mask(src, dst, 0xffff);
1328 }
1329
1330 fn convert_u16_mask(&mut self, src: &Source<'_>, dst: &Destination<'_>, mask: u16) {
1331 self.push_dst_addr(dst);
1332 let mut needs_mask = true;
1333 match src {
1334 Source::Memory(mem) => {
1335 self.i32_load16u(mem);
1336 needs_mask = mask != 0xffff;
1337 }
1338 Source::Stack(stack) => {
1339 self.stack_get(stack, ValType::I32);
1340 }
1341 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1342 }
1343 if needs_mask {
1344 self.instruction(I32Const(i32::from(mask)));
1345 self.instruction(I32And);
1346 }
1347 match dst {
1348 Destination::Memory(mem) => self.i32_store16(mem),
1349 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1350 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1351 }
1352 }
1353
1354 fn translate_s16(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1355 assert!(matches!(dst_ty, InterfaceType::S16));
1357 self.push_dst_addr(dst);
1358 match src {
1359 Source::Memory(mem) => self.i32_load16s(mem),
1360 Source::Stack(stack) => {
1361 self.stack_get(stack, ValType::I32);
1362 self.instruction(I32Extend16S);
1363 }
1364 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1365 }
1366 match dst {
1367 Destination::Memory(mem) => self.i32_store16(mem),
1368 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1369 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1370 }
1371 }
1372
1373 fn translate_u32(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1374 assert!(matches!(dst_ty, InterfaceType::U32));
1376 self.convert_u32_mask(src, dst, 0xffffffff)
1377 }
1378
1379 fn convert_u32_mask(&mut self, src: &Source<'_>, dst: &Destination<'_>, mask: u32) {
1380 self.push_dst_addr(dst);
1381 match src {
1382 Source::Memory(mem) => self.i32_load(mem),
1383 Source::Stack(stack) => self.stack_get(stack, ValType::I32),
1384 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1385 }
1386 if mask != 0xffffffff {
1387 self.instruction(I32Const(mask as i32));
1388 self.instruction(I32And);
1389 }
1390 match dst {
1391 Destination::Memory(mem) => self.i32_store(mem),
1392 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1393 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1394 }
1395 }
1396
1397 fn translate_s32(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1398 assert!(matches!(dst_ty, InterfaceType::S32));
1400 self.push_dst_addr(dst);
1401 match src {
1402 Source::Memory(mem) => self.i32_load(mem),
1403 Source::Stack(stack) => self.stack_get(stack, ValType::I32),
1404 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1405 }
1406 match dst {
1407 Destination::Memory(mem) => self.i32_store(mem),
1408 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1409 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1410 }
1411 }
1412
1413 fn translate_u64(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1414 assert!(matches!(dst_ty, InterfaceType::U64));
1416 self.push_dst_addr(dst);
1417 match src {
1418 Source::Memory(mem) => self.i64_load(mem),
1419 Source::Stack(stack) => self.stack_get(stack, ValType::I64),
1420 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1421 }
1422 match dst {
1423 Destination::Memory(mem) => self.i64_store(mem),
1424 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I64),
1425 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1426 }
1427 }
1428
1429 fn translate_s64(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1430 assert!(matches!(dst_ty, InterfaceType::S64));
1432 self.push_dst_addr(dst);
1433 match src {
1434 Source::Memory(mem) => self.i64_load(mem),
1435 Source::Stack(stack) => self.stack_get(stack, ValType::I64),
1436 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1437 }
1438 match dst {
1439 Destination::Memory(mem) => self.i64_store(mem),
1440 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I64),
1441 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1442 }
1443 }
1444
1445 fn translate_f32(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1446 assert!(matches!(dst_ty, InterfaceType::Float32));
1448 self.push_dst_addr(dst);
1449 match src {
1450 Source::Memory(mem) => self.f32_load(mem),
1451 Source::Stack(stack) => self.stack_get(stack, ValType::F32),
1452 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1453 }
1454 match dst {
1455 Destination::Memory(mem) => self.f32_store(mem),
1456 Destination::Stack(stack, _) => self.stack_set(stack, ValType::F32),
1457 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1458 }
1459 }
1460
1461 fn translate_f64(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1462 assert!(matches!(dst_ty, InterfaceType::Float64));
1464 self.push_dst_addr(dst);
1465 match src {
1466 Source::Memory(mem) => self.f64_load(mem),
1467 Source::Stack(stack) => self.stack_get(stack, ValType::F64),
1468 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1469 }
1470 match dst {
1471 Destination::Memory(mem) => self.f64_store(mem),
1472 Destination::Stack(stack, _) => self.stack_set(stack, ValType::F64),
1473 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1474 }
1475 }
1476
1477 fn translate_char(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1478 assert!(matches!(dst_ty, InterfaceType::Char));
1479 match src {
1480 Source::Memory(mem) => self.i32_load(mem),
1481 Source::Stack(stack) => self.stack_get(stack, ValType::I32),
1482 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1483 }
1484 let local = self.local_set_new_tmp(ValType::I32);
1485
1486 self.instruction(Block(BlockType::Empty));
1502 self.instruction(Block(BlockType::Empty));
1503 self.instruction(LocalGet(local.idx));
1504 self.instruction(I32Const(0xd800));
1505 self.instruction(I32Xor);
1506 self.instruction(I32Const(-0x110000));
1507 self.instruction(I32Add);
1508 self.instruction(I32Const(-0x10f800));
1509 self.instruction(I32LtU);
1510 self.instruction(BrIf(0));
1511 self.instruction(LocalGet(local.idx));
1512 self.instruction(I32Const(0x110000));
1513 self.instruction(I32Ne);
1514 self.instruction(BrIf(1));
1515 self.instruction(End);
1516 self.trap(Trap::InvalidChar);
1517 self.instruction(End);
1518
1519 self.push_dst_addr(dst);
1520 self.instruction(LocalGet(local.idx));
1521 match dst {
1522 Destination::Memory(mem) => {
1523 self.i32_store(mem);
1524 }
1525 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1526 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1527 }
1528
1529 self.free_temp_local(local);
1530 }
1531
1532 fn translate_string(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1533 assert!(matches!(dst_ty, InterfaceType::String));
1534 let src_opts = src.opts();
1535 let dst_opts = dst.opts();
1536
1537 let src_mem_opts = match &src_opts.data_model {
1538 DataModel::Gc {} => todo!("CM+GC"),
1539 DataModel::LinearMemory(opts) => opts,
1540 };
1541 let dst_mem_opts = match &dst_opts.data_model {
1542 DataModel::Gc {} => todo!("CM+GC"),
1543 DataModel::LinearMemory(opts) => opts,
1544 };
1545
1546 match src {
1551 Source::Stack(s) => {
1552 assert_eq!(s.locals.len(), 2);
1553 self.stack_get(&s.slice(0..1), src_mem_opts.ptr());
1554 self.stack_get(&s.slice(1..2), src_mem_opts.ptr());
1555 }
1556 Source::Memory(mem) => {
1557 self.ptr_load(mem);
1558 self.ptr_load(&mem.bump(src_mem_opts.ptr_size().into()));
1559 }
1560 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1561 }
1562 let src_len = self.local_set_new_tmp(src_mem_opts.ptr());
1563 let src_ptr = self.local_set_new_tmp(src_mem_opts.ptr());
1564 let src_str = WasmString {
1565 ptr: src_ptr,
1566 len: src_len,
1567 opts: src_opts,
1568 };
1569
1570 let dst_str = match src_opts.string_encoding {
1571 StringEncoding::Utf8 => match dst_opts.string_encoding {
1572 StringEncoding::Utf8 => self.string_copy(&src_str, FE::Utf8, dst_opts, FE::Utf8),
1573 StringEncoding::Utf16 => self.string_utf8_to_utf16(&src_str, dst_opts),
1574 StringEncoding::CompactUtf16 => {
1575 self.string_to_compact(&src_str, FE::Utf8, dst_opts)
1576 }
1577 },
1578
1579 StringEncoding::Utf16 => {
1580 self.verify_aligned(src_mem_opts, src_str.ptr.idx, 2);
1581 match dst_opts.string_encoding {
1582 StringEncoding::Utf8 => {
1583 self.string_deflate_to_utf8(&src_str, FE::Utf16, dst_opts)
1584 }
1585 StringEncoding::Utf16 => {
1586 self.string_copy(&src_str, FE::Utf16, dst_opts, FE::Utf16)
1587 }
1588 StringEncoding::CompactUtf16 => {
1589 self.string_to_compact(&src_str, FE::Utf16, dst_opts)
1590 }
1591 }
1592 }
1593
1594 StringEncoding::CompactUtf16 => {
1595 self.verify_aligned(src_mem_opts, src_str.ptr.idx, 2);
1596
1597 self.instruction(LocalGet(src_str.len.idx));
1600 self.ptr_uconst(src_mem_opts, UTF16_TAG);
1601 self.ptr_and(src_mem_opts);
1602 self.ptr_if(src_mem_opts, BlockType::Empty);
1603
1604 self.instruction(LocalGet(src_str.len.idx));
1608 self.ptr_uconst(src_mem_opts, UTF16_TAG);
1609 self.ptr_xor(src_mem_opts);
1610 self.instruction(LocalSet(src_str.len.idx));
1611 let s1 = match dst_opts.string_encoding {
1612 StringEncoding::Utf8 => {
1613 self.string_deflate_to_utf8(&src_str, FE::Utf16, dst_opts)
1614 }
1615 StringEncoding::Utf16 => {
1616 self.string_copy(&src_str, FE::Utf16, dst_opts, FE::Utf16)
1617 }
1618 StringEncoding::CompactUtf16 => {
1619 self.string_compact_utf16_to_compact(&src_str, dst_opts)
1620 }
1621 };
1622
1623 self.instruction(Else);
1624
1625 let s2 = match dst_opts.string_encoding {
1629 StringEncoding::Utf16 => {
1630 self.string_copy(&src_str, FE::Latin1, dst_opts, FE::Utf16)
1631 }
1632 StringEncoding::Utf8 => {
1633 self.string_deflate_to_utf8(&src_str, FE::Latin1, dst_opts)
1634 }
1635 StringEncoding::CompactUtf16 => {
1636 self.string_copy(&src_str, FE::Latin1, dst_opts, FE::Latin1)
1637 }
1638 };
1639 self.instruction(LocalGet(s2.ptr.idx));
1642 self.instruction(LocalSet(s1.ptr.idx));
1643 self.instruction(LocalGet(s2.len.idx));
1644 self.instruction(LocalSet(s1.len.idx));
1645 self.instruction(End);
1646 self.free_temp_local(s2.ptr);
1647 self.free_temp_local(s2.len);
1648 s1
1649 }
1650 };
1651
1652 match dst {
1654 Destination::Stack(s, _) => {
1655 self.instruction(LocalGet(dst_str.ptr.idx));
1656 self.stack_set(&s[..1], dst_mem_opts.ptr());
1657 self.instruction(LocalGet(dst_str.len.idx));
1658 self.stack_set(&s[1..], dst_mem_opts.ptr());
1659 }
1660 Destination::Memory(mem) => {
1661 self.instruction(LocalGet(mem.addr.idx));
1662 self.instruction(LocalGet(dst_str.ptr.idx));
1663 self.ptr_store(mem);
1664 self.instruction(LocalGet(mem.addr.idx));
1665 self.instruction(LocalGet(dst_str.len.idx));
1666 self.ptr_store(&mem.bump(dst_mem_opts.ptr_size().into()));
1667 }
1668 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1669 }
1670
1671 self.free_temp_local(src_str.ptr);
1672 self.free_temp_local(src_str.len);
1673 self.free_temp_local(dst_str.ptr);
1674 self.free_temp_local(dst_str.len);
1675 }
1676
1677 fn string_copy<'c>(
1690 &mut self,
1691 src: &WasmString<'_>,
1692 src_enc: FE,
1693 dst_opts: &'c Options,
1694 dst_enc: FE,
1695 ) -> WasmString<'c> {
1696 assert!(dst_enc.width() >= src_enc.width());
1697 self.validate_string_length(src, dst_enc);
1698
1699 let src_mem_opts = {
1700 match &src.opts.data_model {
1701 DataModel::Gc {} => todo!("CM+GC"),
1702 DataModel::LinearMemory(opts) => opts,
1703 }
1704 };
1705 let dst_mem_opts = {
1706 match &dst_opts.data_model {
1707 DataModel::Gc {} => todo!("CM+GC"),
1708 DataModel::LinearMemory(opts) => opts,
1709 }
1710 };
1711
1712 let mut src_byte_len_tmp = None;
1716 let src_byte_len = if src_enc.width() == 1 {
1717 src.len.idx
1718 } else {
1719 assert_eq!(src_enc.width(), 2);
1720 self.instruction(LocalGet(src.len.idx));
1721 self.ptr_uconst(src_mem_opts, 1);
1722 self.ptr_shl(src_mem_opts);
1723 let tmp = self.local_set_new_tmp(src.opts.data_model.unwrap_memory().ptr());
1724 let ret = tmp.idx;
1725 src_byte_len_tmp = Some(tmp);
1726 ret
1727 };
1728
1729 self.convert_src_len_to_dst(
1732 src.len.idx,
1733 src.opts.data_model.unwrap_memory().ptr(),
1734 dst_opts.data_model.unwrap_memory().ptr(),
1735 );
1736 let dst_len = self.local_tee_new_tmp(dst_opts.data_model.unwrap_memory().ptr());
1737 if dst_enc.width() > 1 {
1738 assert_eq!(dst_enc.width(), 2);
1739 self.ptr_uconst(dst_mem_opts, 1);
1740 self.ptr_shl(dst_mem_opts);
1741 }
1742 let dst_byte_len = self.local_set_new_tmp(dst_opts.data_model.unwrap_memory().ptr());
1743
1744 let dst = {
1747 let dst_mem = self.malloc(
1748 dst_opts,
1749 MallocSize::Local(dst_byte_len.idx),
1750 dst_enc.width().into(),
1751 );
1752 WasmString {
1753 ptr: dst_mem.addr,
1754 len: dst_len,
1755 opts: dst_opts,
1756 }
1757 };
1758
1759 self.validate_string_inbounds(src, src_byte_len);
1764 self.validate_string_inbounds(&dst, dst_byte_len.idx);
1765
1766 let op = if src_enc == dst_enc {
1770 Transcode::Copy(src_enc)
1771 } else {
1772 assert_eq!(src_enc, FE::Latin1);
1773 assert_eq!(dst_enc, FE::Utf16);
1774 Transcode::Latin1ToUtf16
1775 };
1776 let transcode = self.transcoder(src, &dst, op);
1777 self.instruction(LocalGet(src.ptr.idx));
1778 self.instruction(LocalGet(src.len.idx));
1779 self.instruction(LocalGet(dst.ptr.idx));
1780 self.instruction(Call(transcode.as_u32()));
1781
1782 self.free_temp_local(dst_byte_len);
1783 if let Some(tmp) = src_byte_len_tmp {
1784 self.free_temp_local(tmp);
1785 }
1786
1787 dst
1788 }
1789 fn string_deflate_to_utf8<'c>(
1802 &mut self,
1803 src: &WasmString<'_>,
1804 src_enc: FE,
1805 dst_opts: &'c Options,
1806 ) -> WasmString<'c> {
1807 let src_mem_opts = match &src.opts.data_model {
1808 DataModel::Gc {} => todo!("CM+GC"),
1809 DataModel::LinearMemory(opts) => opts,
1810 };
1811 let dst_mem_opts = match &dst_opts.data_model {
1812 DataModel::Gc {} => todo!("CM+GC"),
1813 DataModel::LinearMemory(opts) => opts,
1814 };
1815
1816 self.validate_string_length(src, src_enc);
1817
1818 self.convert_src_len_to_dst(
1822 src.len.idx,
1823 src.opts.data_model.unwrap_memory().ptr(),
1824 dst_opts.data_model.unwrap_memory().ptr(),
1825 );
1826 let dst_len = self.local_tee_new_tmp(dst_opts.data_model.unwrap_memory().ptr());
1827 let dst_byte_len = self.local_set_new_tmp(dst_opts.data_model.unwrap_memory().ptr());
1828
1829 let dst = {
1830 let dst_mem = self.malloc(dst_opts, MallocSize::Local(dst_byte_len.idx), 1);
1831 WasmString {
1832 ptr: dst_mem.addr,
1833 len: dst_len,
1834 opts: dst_opts,
1835 }
1836 };
1837
1838 let mut src_byte_len_tmp = None;
1840 let src_byte_len = match src_enc {
1841 FE::Latin1 => src.len.idx,
1842 FE::Utf16 => {
1843 self.instruction(LocalGet(src.len.idx));
1844 self.ptr_uconst(src_mem_opts, 1);
1845 self.ptr_shl(src_mem_opts);
1846 let tmp = self.local_set_new_tmp(src.opts.data_model.unwrap_memory().ptr());
1847 let ret = tmp.idx;
1848 src_byte_len_tmp = Some(tmp);
1849 ret
1850 }
1851 FE::Utf8 => unreachable!(),
1852 };
1853 self.validate_string_inbounds(src, src_byte_len);
1854 self.validate_string_inbounds(&dst, dst_byte_len.idx);
1855
1856 let op = match src_enc {
1858 FE::Latin1 => Transcode::Latin1ToUtf8,
1859 FE::Utf16 => Transcode::Utf16ToUtf8,
1860 FE::Utf8 => unreachable!(),
1861 };
1862 let transcode = self.transcoder(src, &dst, op);
1863 self.instruction(LocalGet(src.ptr.idx));
1864 self.instruction(LocalGet(src.len.idx));
1865 self.instruction(LocalGet(dst.ptr.idx));
1866 self.instruction(LocalGet(dst_byte_len.idx));
1867 self.instruction(Call(transcode.as_u32()));
1868 self.instruction(LocalSet(dst.len.idx));
1869 let src_len_tmp = self.local_set_new_tmp(src.opts.data_model.unwrap_memory().ptr());
1870
1871 self.instruction(LocalGet(src_len_tmp.idx));
1875 self.instruction(LocalGet(src.len.idx));
1876 self.ptr_ne(src_mem_opts);
1877 self.instruction(If(BlockType::Empty));
1878
1879 self.instruction(LocalGet(dst.ptr.idx)); self.instruction(LocalGet(dst_byte_len.idx)); self.ptr_uconst(dst_mem_opts, 1); let factor = match src_enc {
1886 FE::Latin1 => 2,
1887 FE::Utf16 => 3,
1888 _ => unreachable!(),
1889 };
1890 self.validate_string_length_u8(src, factor);
1891 self.convert_src_len_to_dst(
1892 src.len.idx,
1893 src.opts.data_model.unwrap_memory().ptr(),
1894 dst_opts.data_model.unwrap_memory().ptr(),
1895 );
1896 self.ptr_uconst(dst_mem_opts, factor.into());
1897 self.ptr_mul(dst_mem_opts);
1898 self.instruction(LocalTee(dst_byte_len.idx));
1899 self.instruction(Call(dst_mem_opts.realloc.unwrap().as_u32()));
1900 self.instruction(LocalSet(dst.ptr.idx));
1901
1902 self.validate_string_inbounds(&dst, dst_byte_len.idx);
1904
1905 self.instruction(LocalGet(src.ptr.idx));
1910 self.instruction(LocalGet(src_len_tmp.idx));
1911 if let FE::Utf16 = src_enc {
1912 self.ptr_uconst(src_mem_opts, 1);
1913 self.ptr_shl(src_mem_opts);
1914 }
1915 self.ptr_add(src_mem_opts);
1916 self.instruction(LocalGet(src.len.idx));
1917 self.instruction(LocalGet(src_len_tmp.idx));
1918 self.ptr_sub(src_mem_opts);
1919 self.instruction(LocalGet(dst.ptr.idx));
1920 self.instruction(LocalGet(dst.len.idx));
1921 self.ptr_add(dst_mem_opts);
1922 self.instruction(LocalGet(dst_byte_len.idx));
1923 self.instruction(LocalGet(dst.len.idx));
1924 self.ptr_sub(dst_mem_opts);
1925 self.instruction(Call(transcode.as_u32()));
1926
1927 self.instruction(LocalGet(dst.len.idx));
1931 self.ptr_add(dst_mem_opts);
1932 self.instruction(LocalSet(dst.len.idx));
1933
1934 if self.module.debug {
1937 self.instruction(LocalGet(src.len.idx));
1938 self.instruction(LocalGet(src_len_tmp.idx));
1939 self.ptr_sub(src_mem_opts);
1940 self.ptr_ne(src_mem_opts);
1941 self.instruction(If(BlockType::Empty));
1942 self.trap(Trap::AssertFailed("should have finished encoding"));
1943 self.instruction(End);
1944 } else {
1945 self.instruction(Drop);
1946 }
1947
1948 self.instruction(LocalGet(dst.len.idx));
1950 self.instruction(LocalGet(dst_byte_len.idx));
1951 self.ptr_ne(dst_mem_opts);
1952 self.instruction(If(BlockType::Empty));
1953 self.instruction(LocalGet(dst.ptr.idx)); self.instruction(LocalGet(dst_byte_len.idx)); self.ptr_uconst(dst_mem_opts, 1); self.instruction(LocalGet(dst.len.idx)); self.instruction(Call(dst_mem_opts.realloc.unwrap().as_u32()));
1958 self.instruction(LocalSet(dst.ptr.idx));
1959 self.instruction(End);
1960
1961 if self.module.debug {
1964 self.instruction(Else);
1965
1966 self.instruction(LocalGet(dst.len.idx));
1967 self.instruction(LocalGet(dst_byte_len.idx));
1968 self.ptr_ne(dst_mem_opts);
1969 self.instruction(If(BlockType::Empty));
1970 self.trap(Trap::AssertFailed("should have finished encoding"));
1971 self.instruction(End);
1972 }
1973
1974 self.instruction(End); self.free_temp_local(src_len_tmp);
1977 self.free_temp_local(dst_byte_len);
1978 if let Some(tmp) = src_byte_len_tmp {
1979 self.free_temp_local(tmp);
1980 }
1981
1982 dst
1983 }
1984
1985 fn string_utf8_to_utf16<'c>(
2000 &mut self,
2001 src: &WasmString<'_>,
2002 dst_opts: &'c Options,
2003 ) -> WasmString<'c> {
2004 let src_mem_opts = match &src.opts.data_model {
2005 DataModel::Gc {} => todo!("CM+GC"),
2006 DataModel::LinearMemory(opts) => opts,
2007 };
2008 let dst_mem_opts = match &dst_opts.data_model {
2009 DataModel::Gc {} => todo!("CM+GC"),
2010 DataModel::LinearMemory(opts) => opts,
2011 };
2012
2013 self.validate_string_length(src, FE::Utf16);
2014 self.convert_src_len_to_dst(
2015 src.len.idx,
2016 src_mem_opts.ptr(),
2017 dst_opts.data_model.unwrap_memory().ptr(),
2018 );
2019 let dst_len = self.local_tee_new_tmp(dst_opts.data_model.unwrap_memory().ptr());
2020 self.ptr_uconst(dst_mem_opts, 1);
2021 self.ptr_shl(dst_mem_opts);
2022 let dst_byte_len = self.local_set_new_tmp(dst_opts.data_model.unwrap_memory().ptr());
2023 let dst = {
2024 let dst_mem = self.malloc(dst_opts, MallocSize::Local(dst_byte_len.idx), 2);
2025 WasmString {
2026 ptr: dst_mem.addr,
2027 len: dst_len,
2028 opts: dst_opts,
2029 }
2030 };
2031
2032 self.validate_string_inbounds(src, src.len.idx);
2033 self.validate_string_inbounds(&dst, dst_byte_len.idx);
2034
2035 let transcode = self.transcoder(src, &dst, Transcode::Utf8ToUtf16);
2036 self.instruction(LocalGet(src.ptr.idx));
2037 self.instruction(LocalGet(src.len.idx));
2038 self.instruction(LocalGet(dst.ptr.idx));
2039 self.instruction(Call(transcode.as_u32()));
2040 self.instruction(LocalSet(dst.len.idx));
2041
2042 self.convert_src_len_to_dst(src.len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2050 self.instruction(LocalGet(dst.len.idx));
2051 self.ptr_ne(dst_mem_opts);
2052 self.instruction(If(BlockType::Empty));
2053 self.instruction(LocalGet(dst.ptr.idx));
2054 self.instruction(LocalGet(dst_byte_len.idx));
2055 self.ptr_uconst(dst_mem_opts, 2);
2056 self.instruction(LocalGet(dst.len.idx));
2057 self.ptr_uconst(dst_mem_opts, 1);
2058 self.ptr_shl(dst_mem_opts);
2059 self.instruction(Call(match dst.opts.data_model {
2060 DataModel::Gc {} => todo!("CM+GC"),
2061 DataModel::LinearMemory(LinearMemoryOptions { realloc, .. }) => {
2062 realloc.unwrap().as_u32()
2063 }
2064 }));
2065 self.instruction(LocalSet(dst.ptr.idx));
2066 self.instruction(End); self.free_temp_local(dst_byte_len);
2069
2070 dst
2071 }
2072
2073 fn string_compact_utf16_to_compact<'c>(
2087 &mut self,
2088 src: &WasmString<'_>,
2089 dst_opts: &'c Options,
2090 ) -> WasmString<'c> {
2091 let src_mem_opts = match &src.opts.data_model {
2092 DataModel::Gc {} => todo!("CM+GC"),
2093 DataModel::LinearMemory(opts) => opts,
2094 };
2095 let dst_mem_opts = match &dst_opts.data_model {
2096 DataModel::Gc {} => todo!("CM+GC"),
2097 DataModel::LinearMemory(opts) => opts,
2098 };
2099
2100 self.validate_string_length(src, FE::Utf16);
2101 self.convert_src_len_to_dst(src.len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2102 let dst_len = self.local_tee_new_tmp(dst_mem_opts.ptr());
2103 self.ptr_uconst(dst_mem_opts, 1);
2104 self.ptr_shl(dst_mem_opts);
2105 let dst_byte_len = self.local_set_new_tmp(dst_mem_opts.ptr());
2106 let dst = {
2107 let dst_mem = self.malloc(dst_opts, MallocSize::Local(dst_byte_len.idx), 2);
2108 WasmString {
2109 ptr: dst_mem.addr,
2110 len: dst_len,
2111 opts: dst_opts,
2112 }
2113 };
2114
2115 self.convert_src_len_to_dst(
2116 dst_byte_len.idx,
2117 dst.opts.data_model.unwrap_memory().ptr(),
2118 src_mem_opts.ptr(),
2119 );
2120 let src_byte_len = self.local_set_new_tmp(src_mem_opts.ptr());
2121
2122 self.validate_string_inbounds(src, src_byte_len.idx);
2123 self.validate_string_inbounds(&dst, dst_byte_len.idx);
2124
2125 let transcode = self.transcoder(src, &dst, Transcode::Utf16ToCompactProbablyUtf16);
2126 self.instruction(LocalGet(src.ptr.idx));
2127 self.instruction(LocalGet(src.len.idx));
2128 self.instruction(LocalGet(dst.ptr.idx));
2129 self.instruction(Call(transcode.as_u32()));
2130 self.instruction(LocalSet(dst.len.idx));
2131
2132 if self.module.debug {
2135 self.instruction(LocalGet(dst.len.idx));
2136 self.ptr_uconst(dst_mem_opts, !UTF16_TAG);
2137 self.ptr_and(dst_mem_opts);
2138 self.convert_src_len_to_dst(src.len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2139 self.ptr_ne(dst_mem_opts);
2140 self.instruction(If(BlockType::Empty));
2141 self.trap(Trap::AssertFailed("expected equal code units"));
2142 self.instruction(End);
2143 }
2144
2145 self.instruction(LocalGet(dst.len.idx));
2149 self.ptr_uconst(dst_mem_opts, UTF16_TAG);
2150 self.ptr_and(dst_mem_opts);
2151 self.ptr_br_if(dst_mem_opts, 0);
2152
2153 self.instruction(LocalGet(dst.ptr.idx)); self.instruction(LocalGet(dst_byte_len.idx)); self.ptr_uconst(dst_mem_opts, 2); self.instruction(LocalGet(dst.len.idx)); self.instruction(Call(dst_mem_opts.realloc.unwrap().as_u32()));
2159 self.instruction(LocalSet(dst.ptr.idx));
2160
2161 self.free_temp_local(dst_byte_len);
2162 self.free_temp_local(src_byte_len);
2163
2164 dst
2165 }
2166
2167 fn string_to_compact<'c>(
2174 &mut self,
2175 src: &WasmString<'_>,
2176 src_enc: FE,
2177 dst_opts: &'c Options,
2178 ) -> WasmString<'c> {
2179 let src_mem_opts = match &src.opts.data_model {
2180 DataModel::Gc {} => todo!("CM+GC"),
2181 DataModel::LinearMemory(opts) => opts,
2182 };
2183 let dst_mem_opts = match &dst_opts.data_model {
2184 DataModel::Gc {} => todo!("CM+GC"),
2185 DataModel::LinearMemory(opts) => opts,
2186 };
2187
2188 self.validate_string_length(src, src_enc);
2189 self.convert_src_len_to_dst(src.len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2190 let dst_len = self.local_tee_new_tmp(dst_mem_opts.ptr());
2191 let dst_byte_len = self.local_set_new_tmp(dst_mem_opts.ptr());
2192 let dst = {
2193 let dst_mem = self.malloc(dst_opts, MallocSize::Local(dst_byte_len.idx), 2);
2194 WasmString {
2195 ptr: dst_mem.addr,
2196 len: dst_len,
2197 opts: dst_opts,
2198 }
2199 };
2200
2201 self.validate_string_inbounds(src, src.len.idx);
2202 self.validate_string_inbounds(&dst, dst_byte_len.idx);
2203
2204 let (latin1, utf16) = match src_enc {
2208 FE::Utf8 => (Transcode::Utf8ToLatin1, Transcode::Utf8ToCompactUtf16),
2209 FE::Utf16 => (Transcode::Utf16ToLatin1, Transcode::Utf16ToCompactUtf16),
2210 FE::Latin1 => unreachable!(),
2211 };
2212 let transcode_latin1 = self.transcoder(src, &dst, latin1);
2213 let transcode_utf16 = self.transcoder(src, &dst, utf16);
2214 self.instruction(LocalGet(src.ptr.idx));
2215 self.instruction(LocalGet(src.len.idx));
2216 self.instruction(LocalGet(dst.ptr.idx));
2217 self.instruction(Call(transcode_latin1.as_u32()));
2218 self.instruction(LocalSet(dst.len.idx));
2219 let src_len_tmp = self.local_set_new_tmp(src_mem_opts.ptr());
2220
2221 self.instruction(LocalGet(src_len_tmp.idx));
2224 self.instruction(LocalGet(src.len.idx));
2225 self.ptr_eq(src_mem_opts);
2226 self.instruction(If(BlockType::Empty)); self.instruction(LocalGet(dst_byte_len.idx));
2232 self.instruction(LocalGet(dst.len.idx));
2233 self.ptr_ne(dst_mem_opts);
2234 self.instruction(If(BlockType::Empty));
2235 self.instruction(LocalGet(dst.ptr.idx)); self.instruction(LocalGet(dst_byte_len.idx)); self.ptr_uconst(dst_mem_opts, 2); self.instruction(LocalGet(dst.len.idx)); self.instruction(Call(dst_mem_opts.realloc.unwrap().as_u32()));
2240 self.instruction(LocalSet(dst.ptr.idx));
2241 self.instruction(End);
2242
2243 self.instruction(Else); if src_enc.width() == 1 {
2252 self.validate_string_length_u8(src, 2);
2253 }
2254
2255 self.instruction(LocalGet(dst.ptr.idx)); self.instruction(LocalGet(dst_byte_len.idx)); self.ptr_uconst(dst_mem_opts, 2); self.convert_src_len_to_dst(src.len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2261 self.ptr_uconst(dst_mem_opts, 1);
2262 self.ptr_shl(dst_mem_opts);
2263 self.instruction(LocalTee(dst_byte_len.idx));
2264 self.instruction(Call(dst_mem_opts.realloc.unwrap().as_u32()));
2265 self.instruction(LocalSet(dst.ptr.idx));
2266
2267 self.instruction(LocalGet(src.ptr.idx));
2271 self.instruction(LocalGet(src_len_tmp.idx));
2272 if let FE::Utf16 = src_enc {
2273 self.ptr_uconst(src_mem_opts, 1);
2274 self.ptr_shl(src_mem_opts);
2275 }
2276 self.ptr_add(src_mem_opts);
2277 self.instruction(LocalGet(src.len.idx));
2278 self.instruction(LocalGet(src_len_tmp.idx));
2279 self.ptr_sub(src_mem_opts);
2280 self.instruction(LocalGet(dst.ptr.idx));
2281 self.convert_src_len_to_dst(src.len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2282 self.instruction(LocalGet(dst.len.idx));
2283 self.instruction(Call(transcode_utf16.as_u32()));
2284 self.instruction(LocalSet(dst.len.idx));
2285
2286 self.instruction(LocalGet(dst.len.idx));
2294 self.convert_src_len_to_dst(src.len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2295 self.ptr_ne(dst_mem_opts);
2296 self.instruction(If(BlockType::Empty));
2297 self.instruction(LocalGet(dst.ptr.idx)); self.instruction(LocalGet(dst_byte_len.idx)); self.ptr_uconst(dst_mem_opts, 2); self.instruction(LocalGet(dst.len.idx));
2301 self.ptr_uconst(dst_mem_opts, 1);
2302 self.ptr_shl(dst_mem_opts);
2303 self.instruction(Call(dst_mem_opts.realloc.unwrap().as_u32()));
2304 self.instruction(LocalSet(dst.ptr.idx));
2305 self.instruction(End);
2306
2307 self.instruction(LocalGet(dst.len.idx));
2309 self.ptr_uconst(dst_mem_opts, UTF16_TAG);
2310 self.ptr_or(dst_mem_opts);
2311 self.instruction(LocalSet(dst.len.idx));
2312
2313 self.instruction(End); self.free_temp_local(src_len_tmp);
2316 self.free_temp_local(dst_byte_len);
2317
2318 dst
2319 }
2320
2321 fn validate_string_length(&mut self, src: &WasmString<'_>, dst: FE) {
2322 self.validate_string_length_u8(src, dst.width())
2323 }
2324
2325 fn validate_string_length_u8(&mut self, s: &WasmString<'_>, dst: u8) {
2326 let mem_opts = match &s.opts.data_model {
2327 DataModel::Gc {} => todo!("CM+GC"),
2328 DataModel::LinearMemory(opts) => opts,
2329 };
2330
2331 self.instruction(LocalGet(s.len.idx));
2334 let max = MAX_STRING_BYTE_LENGTH / u32::from(dst);
2335 self.ptr_uconst(mem_opts, max);
2336 self.ptr_ge_u(mem_opts);
2337 self.instruction(If(BlockType::Empty));
2338 self.trap(Trap::StringLengthTooBig);
2339 self.instruction(End);
2340 }
2341
2342 fn transcoder(
2343 &mut self,
2344 src: &WasmString<'_>,
2345 dst: &WasmString<'_>,
2346 op: Transcode,
2347 ) -> FuncIndex {
2348 match (src.opts.data_model, dst.opts.data_model) {
2349 (DataModel::Gc {}, _) | (_, DataModel::Gc {}) => {
2350 todo!("CM+GC")
2351 }
2352 (
2353 DataModel::LinearMemory(LinearMemoryOptions {
2354 memory64: src64,
2355 memory: src_mem,
2356 realloc: _,
2357 }),
2358 DataModel::LinearMemory(LinearMemoryOptions {
2359 memory64: dst64,
2360 memory: dst_mem,
2361 realloc: _,
2362 }),
2363 ) => self.module.import_transcoder(Transcoder {
2364 from_memory: src_mem.unwrap(),
2365 from_memory64: src64,
2366 to_memory: dst_mem.unwrap(),
2367 to_memory64: dst64,
2368 op,
2369 }),
2370 }
2371 }
2372
2373 fn validate_string_inbounds(&mut self, s: &WasmString<'_>, byte_len: u32) {
2374 match &s.opts.data_model {
2375 DataModel::Gc {} => todo!("CM+GC"),
2376 DataModel::LinearMemory(opts) => {
2377 self.validate_memory_inbounds(opts, s.ptr.idx, byte_len, Trap::StringLengthOverflow)
2378 }
2379 }
2380 }
2381
2382 fn validate_memory_inbounds(
2383 &mut self,
2384 opts: &LinearMemoryOptions,
2385 ptr_local: u32,
2386 byte_len_local: u32,
2387 trap: Trap,
2388 ) {
2389 let extend_to_64 = |me: &mut Self| {
2390 if !opts.memory64 {
2391 me.instruction(I64ExtendI32U);
2392 }
2393 };
2394
2395 self.instruction(Block(BlockType::Empty));
2396 self.instruction(Block(BlockType::Empty));
2397
2398 self.instruction(MemorySize(opts.memory.unwrap().as_u32()));
2403 extend_to_64(self);
2404 self.instruction(I64Const(16));
2405 self.instruction(I64Shl);
2406
2407 self.instruction(LocalGet(ptr_local));
2412 extend_to_64(self);
2413 self.instruction(LocalGet(byte_len_local));
2414 extend_to_64(self);
2415 self.instruction(I64Add);
2416 if opts.memory64 {
2417 let tmp = self.local_tee_new_tmp(ValType::I64);
2418 self.instruction(LocalGet(ptr_local));
2419 self.ptr_lt_u(opts);
2420 self.instruction(BrIf(0));
2421 self.instruction(LocalGet(tmp.idx));
2422 self.free_temp_local(tmp);
2423 }
2424
2425 self.instruction(I64GeU);
2429 self.instruction(BrIf(1));
2430
2431 self.instruction(End);
2432 self.trap(trap);
2433 self.instruction(End);
2434 }
2435
2436 fn translate_list(
2437 &mut self,
2438 src_ty: TypeListIndex,
2439 src: &Source<'_>,
2440 dst_ty: &InterfaceType,
2441 dst: &Destination,
2442 ) {
2443 let src_mem_opts = match &src.opts().data_model {
2444 DataModel::Gc {} => todo!("CM+GC"),
2445 DataModel::LinearMemory(opts) => opts,
2446 };
2447 let dst_mem_opts = match &dst.opts().data_model {
2448 DataModel::Gc {} => todo!("CM+GC"),
2449 DataModel::LinearMemory(opts) => opts,
2450 };
2451
2452 let src_element_ty = &self.types[src_ty].element;
2453 let dst_element_ty = match dst_ty {
2454 InterfaceType::List(r) => &self.types[*r].element,
2455 _ => panic!("expected a list"),
2456 };
2457 let src_opts = src.opts();
2458 let dst_opts = dst.opts();
2459 let (src_size, src_align) = self.types.size_align(src_mem_opts, src_element_ty);
2460 let (dst_size, dst_align) = self.types.size_align(dst_mem_opts, dst_element_ty);
2461
2462 match src {
2467 Source::Stack(s) => {
2468 assert_eq!(s.locals.len(), 2);
2469 self.stack_get(&s.slice(0..1), src_mem_opts.ptr());
2470 self.stack_get(&s.slice(1..2), src_mem_opts.ptr());
2471 }
2472 Source::Memory(mem) => {
2473 self.ptr_load(mem);
2474 self.ptr_load(&mem.bump(src_mem_opts.ptr_size().into()));
2475 }
2476 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
2477 }
2478 let src_len = self.local_set_new_tmp(src_mem_opts.ptr());
2479 let src_ptr = self.local_set_new_tmp(src_mem_opts.ptr());
2480
2481 let src_mem = self.memory_operand(src_opts, src_ptr, src_align);
2484
2485 let src_byte_len = self.calculate_list_byte_len(src_mem_opts, src_len.idx, src_size);
2487 let dst_byte_len = if src_size == dst_size {
2488 self.convert_src_len_to_dst(src_byte_len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2489 self.local_set_new_tmp(dst_mem_opts.ptr())
2490 } else if src_mem_opts.ptr() == dst_mem_opts.ptr() {
2491 self.calculate_list_byte_len(dst_mem_opts, src_len.idx, dst_size)
2492 } else {
2493 self.convert_src_len_to_dst(src_byte_len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2494 let tmp = self.local_set_new_tmp(dst_mem_opts.ptr());
2495 let ret = self.calculate_list_byte_len(dst_mem_opts, tmp.idx, dst_size);
2496 self.free_temp_local(tmp);
2497 ret
2498 };
2499
2500 let dst_mem = self.malloc(dst_opts, MallocSize::Local(dst_byte_len.idx), dst_align);
2505
2506 self.validate_memory_inbounds(
2509 src_mem_opts,
2510 src_mem.addr.idx,
2511 src_byte_len.idx,
2512 Trap::ListByteLengthOverflow,
2513 );
2514 self.validate_memory_inbounds(
2515 dst_mem_opts,
2516 dst_mem.addr.idx,
2517 dst_byte_len.idx,
2518 Trap::ListByteLengthOverflow,
2519 );
2520
2521 self.free_temp_local(src_byte_len);
2522 self.free_temp_local(dst_byte_len);
2523
2524 if src_size > 0 || dst_size > 0 {
2528 self.instruction(Block(BlockType::Empty));
2531
2532 self.instruction(LocalGet(src_len.idx));
2534 let remaining = self.local_tee_new_tmp(src_mem_opts.ptr());
2535 self.ptr_eqz(src_mem_opts);
2536 self.instruction(BrIf(0));
2537
2538 self.instruction(LocalGet(src_mem.addr.idx));
2540 let cur_src_ptr = self.local_set_new_tmp(src_mem_opts.ptr());
2541 self.instruction(LocalGet(dst_mem.addr.idx));
2542 let cur_dst_ptr = self.local_set_new_tmp(dst_mem_opts.ptr());
2543
2544 self.instruction(Loop(BlockType::Empty));
2545
2546 let element_src = Source::Memory(Memory {
2548 opts: src_opts,
2549 offset: 0,
2550 addr: TempLocal::new(cur_src_ptr.idx, cur_src_ptr.ty),
2551 });
2552 let element_dst = Destination::Memory(Memory {
2553 opts: dst_opts,
2554 offset: 0,
2555 addr: TempLocal::new(cur_dst_ptr.idx, cur_dst_ptr.ty),
2556 });
2557 self.translate(src_element_ty, &element_src, dst_element_ty, &element_dst);
2558
2559 if src_size > 0 {
2561 self.instruction(LocalGet(cur_src_ptr.idx));
2562 self.ptr_uconst(src_mem_opts, src_size);
2563 self.ptr_add(src_mem_opts);
2564 self.instruction(LocalSet(cur_src_ptr.idx));
2565 }
2566 if dst_size > 0 {
2567 self.instruction(LocalGet(cur_dst_ptr.idx));
2568 self.ptr_uconst(dst_mem_opts, dst_size);
2569 self.ptr_add(dst_mem_opts);
2570 self.instruction(LocalSet(cur_dst_ptr.idx));
2571 }
2572
2573 self.instruction(LocalGet(remaining.idx));
2576 self.ptr_iconst(src_mem_opts, -1);
2577 self.ptr_add(src_mem_opts);
2578 self.instruction(LocalTee(remaining.idx));
2579 self.ptr_br_if(src_mem_opts, 0);
2580 self.instruction(End); self.instruction(End); self.free_temp_local(cur_dst_ptr);
2584 self.free_temp_local(cur_src_ptr);
2585 self.free_temp_local(remaining);
2586 }
2587
2588 match dst {
2590 Destination::Stack(s, _) => {
2591 self.instruction(LocalGet(dst_mem.addr.idx));
2592 self.stack_set(&s[..1], dst_mem_opts.ptr());
2593 self.convert_src_len_to_dst(src_len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2594 self.stack_set(&s[1..], dst_mem_opts.ptr());
2595 }
2596 Destination::Memory(mem) => {
2597 self.instruction(LocalGet(mem.addr.idx));
2598 self.instruction(LocalGet(dst_mem.addr.idx));
2599 self.ptr_store(mem);
2600 self.instruction(LocalGet(mem.addr.idx));
2601 self.convert_src_len_to_dst(src_len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2602 self.ptr_store(&mem.bump(dst_mem_opts.ptr_size().into()));
2603 }
2604 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
2605 }
2606
2607 self.free_temp_local(src_len);
2608 self.free_temp_local(src_mem.addr);
2609 self.free_temp_local(dst_mem.addr);
2610 }
2611
2612 fn calculate_list_byte_len(
2613 &mut self,
2614 opts: &LinearMemoryOptions,
2615 len_local: u32,
2616 elt_size: u32,
2617 ) -> TempLocal {
2618 if elt_size == 0 {
2621 self.ptr_uconst(opts, 0);
2622 return self.local_set_new_tmp(opts.ptr());
2623 }
2624
2625 if elt_size == 1 {
2633 if let ValType::I64 = opts.ptr() {
2634 self.instruction(LocalGet(len_local));
2635 self.instruction(I64Const(32));
2636 self.instruction(I64ShrU);
2637 self.instruction(I32WrapI64);
2638 self.instruction(If(BlockType::Empty));
2639 self.trap(Trap::ListByteLengthOverflow);
2640 self.instruction(End);
2641 }
2642 self.instruction(LocalGet(len_local));
2643 return self.local_set_new_tmp(opts.ptr());
2644 }
2645
2646 self.instruction(Block(BlockType::Empty));
2651 self.instruction(Block(BlockType::Empty));
2652 self.instruction(LocalGet(len_local));
2653 match opts.ptr() {
2654 ValType::I32 => self.instruction(I64ExtendI32U),
2658
2659 ValType::I64 => {
2663 self.instruction(I64Const(32));
2664 self.instruction(I64ShrU);
2665 self.instruction(I32WrapI64);
2666 self.instruction(BrIf(0));
2667 self.instruction(LocalGet(len_local));
2668 }
2669
2670 _ => unreachable!(),
2671 }
2672
2673 self.instruction(I64Const(elt_size.into()));
2682 self.instruction(I64Mul);
2683 let tmp = self.local_tee_new_tmp(ValType::I64);
2684 self.instruction(I64Const(32));
2687 self.instruction(I64ShrU);
2688 self.instruction(I64Eqz);
2689 self.instruction(BrIf(1));
2690 self.instruction(End);
2691 self.trap(Trap::ListByteLengthOverflow);
2692 self.instruction(End);
2693
2694 if opts.ptr() == ValType::I64 {
2698 tmp
2699 } else {
2700 self.instruction(LocalGet(tmp.idx));
2701 self.instruction(I32WrapI64);
2702 self.free_temp_local(tmp);
2703 self.local_set_new_tmp(ValType::I32)
2704 }
2705 }
2706
2707 fn convert_src_len_to_dst(
2708 &mut self,
2709 src_len_local: u32,
2710 src_ptr_ty: ValType,
2711 dst_ptr_ty: ValType,
2712 ) {
2713 self.instruction(LocalGet(src_len_local));
2714 match (src_ptr_ty, dst_ptr_ty) {
2715 (ValType::I32, ValType::I64) => self.instruction(I64ExtendI32U),
2716 (ValType::I64, ValType::I32) => self.instruction(I32WrapI64),
2717 (src, dst) => assert_eq!(src, dst),
2718 }
2719 }
2720
2721 fn translate_record(
2722 &mut self,
2723 src_ty: TypeRecordIndex,
2724 src: &Source<'_>,
2725 dst_ty: &InterfaceType,
2726 dst: &Destination,
2727 ) {
2728 let src_ty = &self.types[src_ty];
2729 let dst_ty = match dst_ty {
2730 InterfaceType::Record(r) => &self.types[*r],
2731 _ => panic!("expected a record"),
2732 };
2733
2734 assert_eq!(src_ty.fields.len(), dst_ty.fields.len());
2736
2737 let mut src_fields = HashMap::new();
2741 for (i, src) in src
2742 .record_field_srcs(self.types, src_ty.fields.iter().map(|f| f.ty))
2743 .enumerate()
2744 {
2745 let field = &src_ty.fields[i];
2746 src_fields.insert(&field.name, (src, &field.ty));
2747 }
2748
2749 for (i, dst) in dst
2758 .record_field_dsts(self.types, dst_ty.fields.iter().map(|f| f.ty))
2759 .enumerate()
2760 {
2761 let field = &dst_ty.fields[i];
2762 let (src, src_ty) = &src_fields[&field.name];
2763 self.translate(src_ty, src, &field.ty, &dst);
2764 }
2765 }
2766
2767 fn translate_flags(
2768 &mut self,
2769 src_ty: TypeFlagsIndex,
2770 src: &Source<'_>,
2771 dst_ty: &InterfaceType,
2772 dst: &Destination,
2773 ) {
2774 let src_ty = &self.types[src_ty];
2775 let dst_ty = match dst_ty {
2776 InterfaceType::Flags(r) => &self.types[*r],
2777 _ => panic!("expected a record"),
2778 };
2779
2780 assert_eq!(src_ty.names, dst_ty.names);
2788 let cnt = src_ty.names.len();
2789 match FlagsSize::from_count(cnt) {
2790 FlagsSize::Size0 => {}
2791 FlagsSize::Size1 => {
2792 let mask = if cnt == 8 { 0xff } else { (1 << cnt) - 1 };
2793 self.convert_u8_mask(src, dst, mask);
2794 }
2795 FlagsSize::Size2 => {
2796 let mask = if cnt == 16 { 0xffff } else { (1 << cnt) - 1 };
2797 self.convert_u16_mask(src, dst, mask);
2798 }
2799 FlagsSize::Size4Plus(n) => {
2800 let srcs = src.record_field_srcs(self.types, (0..n).map(|_| InterfaceType::U32));
2801 let dsts = dst.record_field_dsts(self.types, (0..n).map(|_| InterfaceType::U32));
2802 let n = usize::from(n);
2803 for (i, (src, dst)) in srcs.zip(dsts).enumerate() {
2804 let mask = if i == n - 1 && (cnt % 32 != 0) {
2805 (1 << (cnt % 32)) - 1
2806 } else {
2807 0xffffffff
2808 };
2809 self.convert_u32_mask(&src, &dst, mask);
2810 }
2811 }
2812 }
2813 }
2814
2815 fn translate_tuple(
2816 &mut self,
2817 src_ty: TypeTupleIndex,
2818 src: &Source<'_>,
2819 dst_ty: &InterfaceType,
2820 dst: &Destination,
2821 ) {
2822 let src_ty = &self.types[src_ty];
2823 let dst_ty = match dst_ty {
2824 InterfaceType::Tuple(t) => &self.types[*t],
2825 _ => panic!("expected a tuple"),
2826 };
2827
2828 assert_eq!(src_ty.types.len(), dst_ty.types.len());
2830
2831 let srcs = src
2832 .record_field_srcs(self.types, src_ty.types.iter().copied())
2833 .zip(src_ty.types.iter());
2834 let dsts = dst
2835 .record_field_dsts(self.types, dst_ty.types.iter().copied())
2836 .zip(dst_ty.types.iter());
2837 for ((src, src_ty), (dst, dst_ty)) in srcs.zip(dsts) {
2838 self.translate(src_ty, &src, dst_ty, &dst);
2839 }
2840 }
2841
2842 fn translate_variant(
2843 &mut self,
2844 src_ty: TypeVariantIndex,
2845 src: &Source<'_>,
2846 dst_ty: &InterfaceType,
2847 dst: &Destination,
2848 ) {
2849 let src_ty = &self.types[src_ty];
2850 let dst_ty = match dst_ty {
2851 InterfaceType::Variant(t) => &self.types[*t],
2852 _ => panic!("expected a variant"),
2853 };
2854
2855 let src_info = variant_info(self.types, src_ty.cases.iter().map(|(_, c)| c.as_ref()));
2856 let dst_info = variant_info(self.types, dst_ty.cases.iter().map(|(_, c)| c.as_ref()));
2857
2858 let iter = src_ty
2859 .cases
2860 .iter()
2861 .enumerate()
2862 .map(|(src_i, (src_case, src_case_ty))| {
2863 let dst_i = dst_ty
2864 .cases
2865 .iter()
2866 .position(|(c, _)| c == src_case)
2867 .unwrap();
2868 let dst_case_ty = &dst_ty.cases[dst_i];
2869 let src_i = u32::try_from(src_i).unwrap();
2870 let dst_i = u32::try_from(dst_i).unwrap();
2871 VariantCase {
2872 src_i,
2873 src_ty: src_case_ty.as_ref(),
2874 dst_i,
2875 dst_ty: dst_case_ty.as_ref(),
2876 }
2877 });
2878 self.convert_variant(src, &src_info, dst, &dst_info, iter);
2879 }
2880
2881 fn translate_enum(
2882 &mut self,
2883 src_ty: TypeEnumIndex,
2884 src: &Source<'_>,
2885 dst_ty: &InterfaceType,
2886 dst: &Destination,
2887 ) {
2888 let src_ty = &self.types[src_ty];
2889 let dst_ty = match dst_ty {
2890 InterfaceType::Enum(t) => &self.types[*t],
2891 _ => panic!("expected an option"),
2892 };
2893
2894 debug_assert_eq!(src_ty.info.size, dst_ty.info.size);
2895 debug_assert_eq!(src_ty.names.len(), dst_ty.names.len());
2896 debug_assert!(
2897 src_ty
2898 .names
2899 .iter()
2900 .zip(dst_ty.names.iter())
2901 .all(|(a, b)| a == b)
2902 );
2903
2904 match src {
2906 Source::Stack(s) => self.stack_get(&s.slice(0..1), ValType::I32),
2907 Source::Memory(mem) => match src_ty.info.size {
2908 DiscriminantSize::Size1 => self.i32_load8u(mem),
2909 DiscriminantSize::Size2 => self.i32_load16u(mem),
2910 DiscriminantSize::Size4 => self.i32_load(mem),
2911 },
2912 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
2913 }
2914 let tmp = self.local_tee_new_tmp(ValType::I32);
2915
2916 self.instruction(I32Const(i32::try_from(src_ty.names.len()).unwrap()));
2918 self.instruction(I32GtU);
2919 self.instruction(If(BlockType::Empty));
2920 self.trap(Trap::InvalidDiscriminant);
2921 self.instruction(End);
2922
2923 match dst {
2925 Destination::Stack(stack, _) => {
2926 self.local_get_tmp(&tmp);
2927 self.stack_set(&stack[..1], ValType::I32)
2928 }
2929 Destination::Memory(mem) => {
2930 self.push_dst_addr(dst);
2931 self.local_get_tmp(&tmp);
2932 match dst_ty.info.size {
2933 DiscriminantSize::Size1 => self.i32_store8(mem),
2934 DiscriminantSize::Size2 => self.i32_store16(mem),
2935 DiscriminantSize::Size4 => self.i32_store(mem),
2936 }
2937 }
2938 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
2939 }
2940 self.free_temp_local(tmp);
2941 }
2942
2943 fn translate_option(
2944 &mut self,
2945 src_ty: TypeOptionIndex,
2946 src: &Source<'_>,
2947 dst_ty: &InterfaceType,
2948 dst: &Destination,
2949 ) {
2950 let src_ty = &self.types[src_ty].ty;
2951 let dst_ty = match dst_ty {
2952 InterfaceType::Option(t) => &self.types[*t].ty,
2953 _ => panic!("expected an option"),
2954 };
2955 let src_ty = Some(src_ty);
2956 let dst_ty = Some(dst_ty);
2957
2958 let src_info = variant_info(self.types, [None, src_ty]);
2959 let dst_info = variant_info(self.types, [None, dst_ty]);
2960
2961 self.convert_variant(
2962 src,
2963 &src_info,
2964 dst,
2965 &dst_info,
2966 [
2967 VariantCase {
2968 src_i: 0,
2969 dst_i: 0,
2970 src_ty: None,
2971 dst_ty: None,
2972 },
2973 VariantCase {
2974 src_i: 1,
2975 dst_i: 1,
2976 src_ty,
2977 dst_ty,
2978 },
2979 ]
2980 .into_iter(),
2981 );
2982 }
2983
2984 fn translate_result(
2985 &mut self,
2986 src_ty: TypeResultIndex,
2987 src: &Source<'_>,
2988 dst_ty: &InterfaceType,
2989 dst: &Destination,
2990 ) {
2991 let src_ty = &self.types[src_ty];
2992 let dst_ty = match dst_ty {
2993 InterfaceType::Result(t) => &self.types[*t],
2994 _ => panic!("expected a result"),
2995 };
2996
2997 let src_info = variant_info(self.types, [src_ty.ok.as_ref(), src_ty.err.as_ref()]);
2998 let dst_info = variant_info(self.types, [dst_ty.ok.as_ref(), dst_ty.err.as_ref()]);
2999
3000 self.convert_variant(
3001 src,
3002 &src_info,
3003 dst,
3004 &dst_info,
3005 [
3006 VariantCase {
3007 src_i: 0,
3008 dst_i: 0,
3009 src_ty: src_ty.ok.as_ref(),
3010 dst_ty: dst_ty.ok.as_ref(),
3011 },
3012 VariantCase {
3013 src_i: 1,
3014 dst_i: 1,
3015 src_ty: src_ty.err.as_ref(),
3016 dst_ty: dst_ty.err.as_ref(),
3017 },
3018 ]
3019 .into_iter(),
3020 );
3021 }
3022
3023 fn convert_variant<'c>(
3024 &mut self,
3025 src: &Source<'_>,
3026 src_info: &VariantInfo,
3027 dst: &Destination,
3028 dst_info: &VariantInfo,
3029 src_cases: impl ExactSizeIterator<Item = VariantCase<'c>>,
3030 ) {
3031 let outer_block_ty = match dst {
3034 Destination::Stack(dst_flat, _) => match dst_flat.len() {
3035 0 => BlockType::Empty,
3036 1 => BlockType::Result(dst_flat[0]),
3037 _ => {
3038 let ty = self.module.core_types.function(&[], &dst_flat);
3039 BlockType::FunctionType(ty)
3040 }
3041 },
3042 Destination::Memory(_) => BlockType::Empty,
3043 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
3044 };
3045 self.instruction(Block(outer_block_ty));
3046
3047 let src_cases_len = src_cases.len();
3050 for _ in 0..src_cases_len - 1 {
3051 self.instruction(Block(BlockType::Empty));
3052 }
3053
3054 self.instruction(Block(BlockType::Empty));
3056
3057 self.instruction(Block(BlockType::Empty));
3060
3061 match src {
3063 Source::Stack(s) => self.stack_get(&s.slice(0..1), ValType::I32),
3064 Source::Memory(mem) => match src_info.size {
3065 DiscriminantSize::Size1 => self.i32_load8u(mem),
3066 DiscriminantSize::Size2 => self.i32_load16u(mem),
3067 DiscriminantSize::Size4 => self.i32_load(mem),
3068 },
3069 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
3070 }
3071
3072 let mut targets = Vec::new();
3075 for i in 0..src_cases_len {
3076 targets.push((i + 1) as u32);
3077 }
3078 self.instruction(BrTable(targets[..].into(), 0));
3079 self.instruction(End); self.trap(Trap::InvalidDiscriminant);
3082 self.instruction(End); let src_cases_len = u32::try_from(src_cases_len).unwrap();
3089 for case in src_cases {
3090 let VariantCase {
3091 src_i,
3092 src_ty,
3093 dst_i,
3094 dst_ty,
3095 } = case;
3096
3097 self.push_dst_addr(dst);
3100 self.instruction(I32Const(dst_i as i32));
3101 match dst {
3102 Destination::Stack(stack, _) => self.stack_set(&stack[..1], ValType::I32),
3103 Destination::Memory(mem) => match dst_info.size {
3104 DiscriminantSize::Size1 => self.i32_store8(mem),
3105 DiscriminantSize::Size2 => self.i32_store16(mem),
3106 DiscriminantSize::Size4 => self.i32_store(mem),
3107 },
3108 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
3109 }
3110
3111 let src_payload = src.payload_src(self.types, src_info, src_ty);
3112 let dst_payload = dst.payload_dst(self.types, dst_info, dst_ty);
3113
3114 match (src_ty, dst_ty) {
3117 (Some(src_ty), Some(dst_ty)) => {
3118 self.translate(src_ty, &src_payload, dst_ty, &dst_payload);
3119 }
3120 (None, None) => {}
3121 _ => unimplemented!(),
3122 }
3123
3124 if let Destination::Stack(payload_results, _) = dst_payload {
3131 if let Destination::Stack(dst_results, _) = dst {
3132 let remaining = &dst_results[1..][payload_results.len()..];
3133 for ty in remaining {
3134 match ty {
3135 ValType::I32 => self.instruction(I32Const(0)),
3136 ValType::I64 => self.instruction(I64Const(0)),
3137 ValType::F32 => self.instruction(F32Const(0.0.into())),
3138 ValType::F64 => self.instruction(F64Const(0.0.into())),
3139 _ => unreachable!(),
3140 }
3141 }
3142 }
3143 }
3144
3145 if src_i != src_cases_len - 1 {
3148 self.instruction(Br(src_cases_len - src_i - 1));
3149 }
3150 self.instruction(End); }
3152 }
3153
3154 fn translate_future(
3155 &mut self,
3156 src_ty: TypeFutureTableIndex,
3157 src: &Source<'_>,
3158 dst_ty: &InterfaceType,
3159 dst: &Destination,
3160 ) {
3161 let dst_ty = match dst_ty {
3162 InterfaceType::Future(t) => *t,
3163 _ => panic!("expected a `Future`"),
3164 };
3165 let transfer = self.module.import_future_transfer();
3166 self.translate_handle(src_ty.as_u32(), src, dst_ty.as_u32(), dst, transfer);
3167 }
3168
3169 fn translate_stream(
3170 &mut self,
3171 src_ty: TypeStreamTableIndex,
3172 src: &Source<'_>,
3173 dst_ty: &InterfaceType,
3174 dst: &Destination,
3175 ) {
3176 let dst_ty = match dst_ty {
3177 InterfaceType::Stream(t) => *t,
3178 _ => panic!("expected a `Stream`"),
3179 };
3180 let transfer = self.module.import_stream_transfer();
3181 self.translate_handle(src_ty.as_u32(), src, dst_ty.as_u32(), dst, transfer);
3182 }
3183
3184 fn translate_error_context(
3185 &mut self,
3186 src_ty: TypeComponentLocalErrorContextTableIndex,
3187 src: &Source<'_>,
3188 dst_ty: &InterfaceType,
3189 dst: &Destination,
3190 ) {
3191 let dst_ty = match dst_ty {
3192 InterfaceType::ErrorContext(t) => *t,
3193 _ => panic!("expected an `ErrorContext`"),
3194 };
3195 let transfer = self.module.import_error_context_transfer();
3196 self.translate_handle(src_ty.as_u32(), src, dst_ty.as_u32(), dst, transfer);
3197 }
3198
3199 fn translate_own(
3200 &mut self,
3201 src_ty: TypeResourceTableIndex,
3202 src: &Source<'_>,
3203 dst_ty: &InterfaceType,
3204 dst: &Destination,
3205 ) {
3206 let dst_ty = match dst_ty {
3207 InterfaceType::Own(t) => *t,
3208 _ => panic!("expected an `Own`"),
3209 };
3210 let transfer = self.module.import_resource_transfer_own();
3211 self.translate_handle(src_ty.as_u32(), src, dst_ty.as_u32(), dst, transfer);
3212 }
3213
3214 fn translate_borrow(
3215 &mut self,
3216 src_ty: TypeResourceTableIndex,
3217 src: &Source<'_>,
3218 dst_ty: &InterfaceType,
3219 dst: &Destination,
3220 ) {
3221 let dst_ty = match dst_ty {
3222 InterfaceType::Borrow(t) => *t,
3223 _ => panic!("expected an `Borrow`"),
3224 };
3225
3226 let transfer = self.module.import_resource_transfer_borrow();
3227 self.translate_handle(src_ty.as_u32(), src, dst_ty.as_u32(), dst, transfer);
3228 }
3229
3230 fn translate_handle(
3238 &mut self,
3239 src_ty: u32,
3240 src: &Source<'_>,
3241 dst_ty: u32,
3242 dst: &Destination,
3243 transfer: FuncIndex,
3244 ) {
3245 self.push_dst_addr(dst);
3246 match src {
3247 Source::Memory(mem) => self.i32_load(mem),
3248 Source::Stack(stack) => self.stack_get(stack, ValType::I32),
3249 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
3250 }
3251 self.instruction(I32Const(src_ty as i32));
3252 self.instruction(I32Const(dst_ty as i32));
3253 self.instruction(Call(transfer.as_u32()));
3254 match dst {
3255 Destination::Memory(mem) => self.i32_store(mem),
3256 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
3257 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
3258 }
3259 }
3260
3261 fn trap_if_not_flag(&mut self, flags_global: GlobalIndex, flag_to_test: i32, trap: Trap) {
3262 self.instruction(GlobalGet(flags_global.as_u32()));
3263 self.instruction(I32Const(flag_to_test));
3264 self.instruction(I32And);
3265 self.instruction(I32Eqz);
3266 self.instruction(If(BlockType::Empty));
3267 self.trap(trap);
3268 self.instruction(End);
3269 }
3270
3271 fn assert_not_flag(&mut self, flags_global: GlobalIndex, flag_to_test: i32, msg: &'static str) {
3272 self.instruction(GlobalGet(flags_global.as_u32()));
3273 self.instruction(I32Const(flag_to_test));
3274 self.instruction(I32And);
3275 self.instruction(If(BlockType::Empty));
3276 self.trap(Trap::AssertFailed(msg));
3277 self.instruction(End);
3278 }
3279
3280 fn set_flag(&mut self, flags_global: GlobalIndex, flag_to_set: i32, value: bool) {
3281 self.instruction(GlobalGet(flags_global.as_u32()));
3282 if value {
3283 self.instruction(I32Const(flag_to_set));
3284 self.instruction(I32Or);
3285 } else {
3286 self.instruction(I32Const(!flag_to_set));
3287 self.instruction(I32And);
3288 }
3289 self.instruction(GlobalSet(flags_global.as_u32()));
3290 }
3291
3292 fn verify_aligned(&mut self, opts: &LinearMemoryOptions, addr_local: u32, align: u32) {
3293 if align == 1 {
3296 return;
3297 }
3298 self.instruction(LocalGet(addr_local));
3299 assert!(align.is_power_of_two());
3300 self.ptr_uconst(opts, align - 1);
3301 self.ptr_and(opts);
3302 self.ptr_if(opts, BlockType::Empty);
3303 self.trap(Trap::UnalignedPointer);
3304 self.instruction(End);
3305 }
3306
3307 fn assert_aligned(&mut self, ty: &InterfaceType, mem: &Memory) {
3308 let mem_opts = mem.mem_opts();
3309 if !self.module.debug {
3310 return;
3311 }
3312 let align = self.types.align(mem_opts, ty);
3313 if align == 1 {
3314 return;
3315 }
3316 assert!(align.is_power_of_two());
3317 self.instruction(LocalGet(mem.addr.idx));
3318 self.ptr_uconst(mem_opts, mem.offset);
3319 self.ptr_add(mem_opts);
3320 self.ptr_uconst(mem_opts, align - 1);
3321 self.ptr_and(mem_opts);
3322 self.ptr_if(mem_opts, BlockType::Empty);
3323 self.trap(Trap::AssertFailed("pointer not aligned"));
3324 self.instruction(End);
3325 }
3326
3327 fn malloc<'c>(&mut self, opts: &'c Options, size: MallocSize, align: u32) -> Memory<'c> {
3328 match &opts.data_model {
3329 DataModel::Gc {} => todo!("CM+GC"),
3330 DataModel::LinearMemory(mem_opts) => {
3331 let realloc = mem_opts.realloc.unwrap();
3332 self.ptr_uconst(mem_opts, 0);
3333 self.ptr_uconst(mem_opts, 0);
3334 self.ptr_uconst(mem_opts, align);
3335 match size {
3336 MallocSize::Const(size) => self.ptr_uconst(mem_opts, size),
3337 MallocSize::Local(idx) => self.instruction(LocalGet(idx)),
3338 }
3339 self.instruction(Call(realloc.as_u32()));
3340 let addr = self.local_set_new_tmp(mem_opts.ptr());
3341 self.memory_operand(opts, addr, align)
3342 }
3343 }
3344 }
3345
3346 fn memory_operand<'c>(&mut self, opts: &'c Options, addr: TempLocal, align: u32) -> Memory<'c> {
3347 let ret = Memory {
3348 addr,
3349 offset: 0,
3350 opts,
3351 };
3352 self.verify_aligned(opts.data_model.unwrap_memory(), ret.addr.idx, align);
3353 ret
3354 }
3355
3356 fn local_tee_new_tmp(&mut self, ty: ValType) -> TempLocal {
3362 self.gen_temp_local(ty, LocalTee)
3363 }
3364
3365 fn local_set_new_tmp(&mut self, ty: ValType) -> TempLocal {
3368 self.gen_temp_local(ty, LocalSet)
3369 }
3370
3371 fn local_get_tmp(&mut self, local: &TempLocal) {
3372 self.instruction(LocalGet(local.idx));
3373 }
3374
3375 fn gen_temp_local(&mut self, ty: ValType, insn: fn(u32) -> Instruction<'static>) -> TempLocal {
3376 if let Some(idx) = self.free_locals.get_mut(&ty).and_then(|v| v.pop()) {
3379 self.instruction(insn(idx));
3380 return TempLocal {
3381 ty,
3382 idx,
3383 needs_free: true,
3384 };
3385 }
3386
3387 let locals = &mut self.module.funcs[self.result].locals;
3389 match locals.last_mut() {
3390 Some((cnt, prev_ty)) if ty == *prev_ty => *cnt += 1,
3391 _ => locals.push((1, ty)),
3392 }
3393 self.nlocals += 1;
3394 let idx = self.nlocals - 1;
3395 self.instruction(insn(idx));
3396 TempLocal {
3397 ty,
3398 idx,
3399 needs_free: true,
3400 }
3401 }
3402
3403 fn free_temp_local(&mut self, mut local: TempLocal) {
3406 assert!(local.needs_free);
3407 self.free_locals
3408 .entry(local.ty)
3409 .or_insert(Vec::new())
3410 .push(local.idx);
3411 local.needs_free = false;
3412 }
3413
3414 fn instruction(&mut self, instr: Instruction) {
3415 instr.encode(&mut self.code);
3416 }
3417
3418 fn trap(&mut self, trap: Trap) {
3419 self.traps.push((self.code.len(), trap));
3420 self.instruction(Unreachable);
3421 }
3422
3423 fn flush_code(&mut self) {
3428 if self.code.is_empty() {
3429 return;
3430 }
3431 self.module.funcs[self.result].body.push(Body::Raw(
3432 mem::take(&mut self.code),
3433 mem::take(&mut self.traps),
3434 ));
3435 }
3436
3437 fn finish(mut self) {
3438 self.instruction(End);
3441 self.flush_code();
3442
3443 self.module.funcs[self.result].filled_in = true;
3446 }
3447
3448 fn stack_get(&mut self, stack: &Stack<'_>, dst_ty: ValType) {
3456 assert_eq!(stack.locals.len(), 1);
3457 let (idx, src_ty) = stack.locals[0];
3458 self.instruction(LocalGet(idx));
3459 match (src_ty, dst_ty) {
3460 (ValType::I32, ValType::I32)
3461 | (ValType::I64, ValType::I64)
3462 | (ValType::F32, ValType::F32)
3463 | (ValType::F64, ValType::F64) => {}
3464
3465 (ValType::I32, ValType::F32) => self.instruction(F32ReinterpretI32),
3466 (ValType::I64, ValType::I32) => {
3467 self.assert_i64_upper_bits_not_set(idx);
3468 self.instruction(I32WrapI64);
3469 }
3470 (ValType::I64, ValType::F64) => self.instruction(F64ReinterpretI64),
3471 (ValType::I64, ValType::F32) => {
3472 self.assert_i64_upper_bits_not_set(idx);
3473 self.instruction(I32WrapI64);
3474 self.instruction(F32ReinterpretI32);
3475 }
3476
3477 (ValType::I32, ValType::I64)
3479 | (ValType::I32, ValType::F64)
3480 | (ValType::F32, ValType::I32)
3481 | (ValType::F32, ValType::I64)
3482 | (ValType::F32, ValType::F64)
3483 | (ValType::F64, ValType::I32)
3484 | (ValType::F64, ValType::I64)
3485 | (ValType::F64, ValType::F32)
3486
3487 | (ValType::Ref(_), _)
3489 | (_, ValType::Ref(_))
3490 | (ValType::V128, _)
3491 | (_, ValType::V128) => {
3492 panic!("cannot get {dst_ty:?} from {src_ty:?} local");
3493 }
3494 }
3495 }
3496
3497 fn assert_i64_upper_bits_not_set(&mut self, local: u32) {
3498 if !self.module.debug {
3499 return;
3500 }
3501 self.instruction(LocalGet(local));
3502 self.instruction(I64Const(32));
3503 self.instruction(I64ShrU);
3504 self.instruction(I32WrapI64);
3505 self.instruction(If(BlockType::Empty));
3506 self.trap(Trap::AssertFailed("upper bits are unexpectedly set"));
3507 self.instruction(End);
3508 }
3509
3510 fn stack_set(&mut self, dst_tys: &[ValType], src_ty: ValType) {
3516 assert_eq!(dst_tys.len(), 1);
3517 let dst_ty = dst_tys[0];
3518 match (src_ty, dst_ty) {
3519 (ValType::I32, ValType::I32)
3520 | (ValType::I64, ValType::I64)
3521 | (ValType::F32, ValType::F32)
3522 | (ValType::F64, ValType::F64) => {}
3523
3524 (ValType::F32, ValType::I32) => self.instruction(I32ReinterpretF32),
3525 (ValType::I32, ValType::I64) => self.instruction(I64ExtendI32U),
3526 (ValType::F64, ValType::I64) => self.instruction(I64ReinterpretF64),
3527 (ValType::F32, ValType::I64) => {
3528 self.instruction(I32ReinterpretF32);
3529 self.instruction(I64ExtendI32U);
3530 }
3531
3532 (ValType::I64, ValType::I32)
3534 | (ValType::F64, ValType::I32)
3535 | (ValType::I32, ValType::F32)
3536 | (ValType::I64, ValType::F32)
3537 | (ValType::F64, ValType::F32)
3538 | (ValType::I32, ValType::F64)
3539 | (ValType::I64, ValType::F64)
3540 | (ValType::F32, ValType::F64)
3541
3542 | (ValType::Ref(_), _)
3544 | (_, ValType::Ref(_))
3545 | (ValType::V128, _)
3546 | (_, ValType::V128) => {
3547 panic!("cannot get {dst_ty:?} from {src_ty:?} local");
3548 }
3549 }
3550 }
3551
3552 fn i32_load8u(&mut self, mem: &Memory) {
3553 self.instruction(LocalGet(mem.addr.idx));
3554 self.instruction(I32Load8U(mem.memarg(0)));
3555 }
3556
3557 fn i32_load8s(&mut self, mem: &Memory) {
3558 self.instruction(LocalGet(mem.addr.idx));
3559 self.instruction(I32Load8S(mem.memarg(0)));
3560 }
3561
3562 fn i32_load16u(&mut self, mem: &Memory) {
3563 self.instruction(LocalGet(mem.addr.idx));
3564 self.instruction(I32Load16U(mem.memarg(1)));
3565 }
3566
3567 fn i32_load16s(&mut self, mem: &Memory) {
3568 self.instruction(LocalGet(mem.addr.idx));
3569 self.instruction(I32Load16S(mem.memarg(1)));
3570 }
3571
3572 fn i32_load(&mut self, mem: &Memory) {
3573 self.instruction(LocalGet(mem.addr.idx));
3574 self.instruction(I32Load(mem.memarg(2)));
3575 }
3576
3577 fn i64_load(&mut self, mem: &Memory) {
3578 self.instruction(LocalGet(mem.addr.idx));
3579 self.instruction(I64Load(mem.memarg(3)));
3580 }
3581
3582 fn ptr_load(&mut self, mem: &Memory) {
3583 if mem.mem_opts().memory64 {
3584 self.i64_load(mem);
3585 } else {
3586 self.i32_load(mem);
3587 }
3588 }
3589
3590 fn ptr_add(&mut self, opts: &LinearMemoryOptions) {
3591 if opts.memory64 {
3592 self.instruction(I64Add);
3593 } else {
3594 self.instruction(I32Add);
3595 }
3596 }
3597
3598 fn ptr_sub(&mut self, opts: &LinearMemoryOptions) {
3599 if opts.memory64 {
3600 self.instruction(I64Sub);
3601 } else {
3602 self.instruction(I32Sub);
3603 }
3604 }
3605
3606 fn ptr_mul(&mut self, opts: &LinearMemoryOptions) {
3607 if opts.memory64 {
3608 self.instruction(I64Mul);
3609 } else {
3610 self.instruction(I32Mul);
3611 }
3612 }
3613
3614 fn ptr_ge_u(&mut self, opts: &LinearMemoryOptions) {
3615 if opts.memory64 {
3616 self.instruction(I64GeU);
3617 } else {
3618 self.instruction(I32GeU);
3619 }
3620 }
3621
3622 fn ptr_lt_u(&mut self, opts: &LinearMemoryOptions) {
3623 if opts.memory64 {
3624 self.instruction(I64LtU);
3625 } else {
3626 self.instruction(I32LtU);
3627 }
3628 }
3629
3630 fn ptr_shl(&mut self, opts: &LinearMemoryOptions) {
3631 if opts.memory64 {
3632 self.instruction(I64Shl);
3633 } else {
3634 self.instruction(I32Shl);
3635 }
3636 }
3637
3638 fn ptr_eqz(&mut self, opts: &LinearMemoryOptions) {
3639 if opts.memory64 {
3640 self.instruction(I64Eqz);
3641 } else {
3642 self.instruction(I32Eqz);
3643 }
3644 }
3645
3646 fn ptr_uconst(&mut self, opts: &LinearMemoryOptions, val: u32) {
3647 if opts.memory64 {
3648 self.instruction(I64Const(val.into()));
3649 } else {
3650 self.instruction(I32Const(val as i32));
3651 }
3652 }
3653
3654 fn ptr_iconst(&mut self, opts: &LinearMemoryOptions, val: i32) {
3655 if opts.memory64 {
3656 self.instruction(I64Const(val.into()));
3657 } else {
3658 self.instruction(I32Const(val));
3659 }
3660 }
3661
3662 fn ptr_eq(&mut self, opts: &LinearMemoryOptions) {
3663 if opts.memory64 {
3664 self.instruction(I64Eq);
3665 } else {
3666 self.instruction(I32Eq);
3667 }
3668 }
3669
3670 fn ptr_ne(&mut self, opts: &LinearMemoryOptions) {
3671 if opts.memory64 {
3672 self.instruction(I64Ne);
3673 } else {
3674 self.instruction(I32Ne);
3675 }
3676 }
3677
3678 fn ptr_and(&mut self, opts: &LinearMemoryOptions) {
3679 if opts.memory64 {
3680 self.instruction(I64And);
3681 } else {
3682 self.instruction(I32And);
3683 }
3684 }
3685
3686 fn ptr_or(&mut self, opts: &LinearMemoryOptions) {
3687 if opts.memory64 {
3688 self.instruction(I64Or);
3689 } else {
3690 self.instruction(I32Or);
3691 }
3692 }
3693
3694 fn ptr_xor(&mut self, opts: &LinearMemoryOptions) {
3695 if opts.memory64 {
3696 self.instruction(I64Xor);
3697 } else {
3698 self.instruction(I32Xor);
3699 }
3700 }
3701
3702 fn ptr_if(&mut self, opts: &LinearMemoryOptions, ty: BlockType) {
3703 if opts.memory64 {
3704 self.instruction(I64Const(0));
3705 self.instruction(I64Ne);
3706 }
3707 self.instruction(If(ty));
3708 }
3709
3710 fn ptr_br_if(&mut self, opts: &LinearMemoryOptions, depth: u32) {
3711 if opts.memory64 {
3712 self.instruction(I64Const(0));
3713 self.instruction(I64Ne);
3714 }
3715 self.instruction(BrIf(depth));
3716 }
3717
3718 fn f32_load(&mut self, mem: &Memory) {
3719 self.instruction(LocalGet(mem.addr.idx));
3720 self.instruction(F32Load(mem.memarg(2)));
3721 }
3722
3723 fn f64_load(&mut self, mem: &Memory) {
3724 self.instruction(LocalGet(mem.addr.idx));
3725 self.instruction(F64Load(mem.memarg(3)));
3726 }
3727
3728 fn push_dst_addr(&mut self, dst: &Destination) {
3729 if let Destination::Memory(mem) = dst {
3730 self.instruction(LocalGet(mem.addr.idx));
3731 }
3732 }
3733
3734 fn i32_store8(&mut self, mem: &Memory) {
3735 self.instruction(I32Store8(mem.memarg(0)));
3736 }
3737
3738 fn i32_store16(&mut self, mem: &Memory) {
3739 self.instruction(I32Store16(mem.memarg(1)));
3740 }
3741
3742 fn i32_store(&mut self, mem: &Memory) {
3743 self.instruction(I32Store(mem.memarg(2)));
3744 }
3745
3746 fn i64_store(&mut self, mem: &Memory) {
3747 self.instruction(I64Store(mem.memarg(3)));
3748 }
3749
3750 fn ptr_store(&mut self, mem: &Memory) {
3751 if mem.mem_opts().memory64 {
3752 self.i64_store(mem);
3753 } else {
3754 self.i32_store(mem);
3755 }
3756 }
3757
3758 fn f32_store(&mut self, mem: &Memory) {
3759 self.instruction(F32Store(mem.memarg(2)));
3760 }
3761
3762 fn f64_store(&mut self, mem: &Memory) {
3763 self.instruction(F64Store(mem.memarg(3)));
3764 }
3765}
3766
3767impl<'a> Source<'a> {
3768 fn record_field_srcs<'b>(
3775 &'b self,
3776 types: &'b ComponentTypesBuilder,
3777 fields: impl IntoIterator<Item = InterfaceType> + 'b,
3778 ) -> impl Iterator<Item = Source<'a>> + 'b
3779 where
3780 'a: 'b,
3781 {
3782 let mut offset = 0;
3783 fields.into_iter().map(move |ty| match self {
3784 Source::Memory(mem) => {
3785 let mem = next_field_offset(&mut offset, types, &ty, mem);
3786 Source::Memory(mem)
3787 }
3788 Source::Stack(stack) => {
3789 let cnt = types.flat_types(&ty).unwrap().len() as u32;
3790 offset += cnt;
3791 Source::Stack(stack.slice((offset - cnt) as usize..offset as usize))
3792 }
3793 Source::Struct(_) => todo!(),
3794 Source::Array(_) => todo!(),
3795 })
3796 }
3797
3798 fn payload_src(
3800 &self,
3801 types: &ComponentTypesBuilder,
3802 info: &VariantInfo,
3803 case: Option<&InterfaceType>,
3804 ) -> Source<'a> {
3805 match self {
3806 Source::Stack(s) => {
3807 let flat_len = match case {
3808 Some(case) => types.flat_types(case).unwrap().len(),
3809 None => 0,
3810 };
3811 Source::Stack(s.slice(1..s.locals.len()).slice(0..flat_len))
3812 }
3813 Source::Memory(mem) => {
3814 let mem = if mem.mem_opts().memory64 {
3815 mem.bump(info.payload_offset64)
3816 } else {
3817 mem.bump(info.payload_offset32)
3818 };
3819 Source::Memory(mem)
3820 }
3821 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
3822 }
3823 }
3824
3825 fn opts(&self) -> &'a Options {
3826 match self {
3827 Source::Stack(s) => s.opts,
3828 Source::Memory(mem) => mem.opts,
3829 Source::Struct(s) => s.opts,
3830 Source::Array(a) => a.opts,
3831 }
3832 }
3833}
3834
3835impl<'a> Destination<'a> {
3836 fn record_field_dsts<'b, I>(
3838 &'b self,
3839 types: &'b ComponentTypesBuilder,
3840 fields: I,
3841 ) -> impl Iterator<Item = Destination<'b>> + use<'b, I>
3842 where
3843 'a: 'b,
3844 I: IntoIterator<Item = InterfaceType> + 'b,
3845 {
3846 let mut offset = 0;
3847 fields.into_iter().map(move |ty| match self {
3848 Destination::Memory(mem) => {
3849 let mem = next_field_offset(&mut offset, types, &ty, mem);
3850 Destination::Memory(mem)
3851 }
3852 Destination::Stack(s, opts) => {
3853 let cnt = types.flat_types(&ty).unwrap().len() as u32;
3854 offset += cnt;
3855 Destination::Stack(&s[(offset - cnt) as usize..offset as usize], opts)
3856 }
3857 Destination::Struct(_) => todo!(),
3858 Destination::Array(_) => todo!(),
3859 })
3860 }
3861
3862 fn payload_dst(
3864 &self,
3865 types: &ComponentTypesBuilder,
3866 info: &VariantInfo,
3867 case: Option<&InterfaceType>,
3868 ) -> Destination<'_> {
3869 match self {
3870 Destination::Stack(s, opts) => {
3871 let flat_len = match case {
3872 Some(case) => types.flat_types(case).unwrap().len(),
3873 None => 0,
3874 };
3875 Destination::Stack(&s[1..][..flat_len], opts)
3876 }
3877 Destination::Memory(mem) => {
3878 let mem = if mem.mem_opts().memory64 {
3879 mem.bump(info.payload_offset64)
3880 } else {
3881 mem.bump(info.payload_offset32)
3882 };
3883 Destination::Memory(mem)
3884 }
3885 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
3886 }
3887 }
3888
3889 fn opts(&self) -> &'a Options {
3890 match self {
3891 Destination::Stack(_, opts) => opts,
3892 Destination::Memory(mem) => mem.opts,
3893 Destination::Struct(s) => s.opts,
3894 Destination::Array(a) => a.opts,
3895 }
3896 }
3897}
3898
3899fn next_field_offset<'a>(
3900 offset: &mut u32,
3901 types: &ComponentTypesBuilder,
3902 field: &InterfaceType,
3903 mem: &Memory<'a>,
3904) -> Memory<'a> {
3905 let abi = types.canonical_abi(field);
3906 let offset = if mem.mem_opts().memory64 {
3907 abi.next_field64(offset)
3908 } else {
3909 abi.next_field32(offset)
3910 };
3911 mem.bump(offset)
3912}
3913
3914impl<'a> Memory<'a> {
3915 fn memarg(&self, align: u32) -> MemArg {
3916 MemArg {
3917 offset: u64::from(self.offset),
3918 align,
3919 memory_index: self.mem_opts().memory.unwrap().as_u32(),
3920 }
3921 }
3922
3923 fn bump(&self, offset: u32) -> Memory<'a> {
3924 Memory {
3925 opts: self.opts,
3926 addr: TempLocal::new(self.addr.idx, self.addr.ty),
3927 offset: self.offset + offset,
3928 }
3929 }
3930}
3931
3932impl<'a> Stack<'a> {
3933 fn slice(&self, range: Range<usize>) -> Stack<'a> {
3934 Stack {
3935 locals: &self.locals[range],
3936 opts: self.opts,
3937 }
3938 }
3939}
3940
3941struct VariantCase<'a> {
3942 src_i: u32,
3943 src_ty: Option<&'a InterfaceType>,
3944 dst_i: u32,
3945 dst_ty: Option<&'a InterfaceType>,
3946}
3947
3948fn variant_info<'a, I>(types: &ComponentTypesBuilder, cases: I) -> VariantInfo
3949where
3950 I: IntoIterator<Item = Option<&'a InterfaceType>>,
3951 I::IntoIter: ExactSizeIterator,
3952{
3953 VariantInfo::new(
3954 cases
3955 .into_iter()
3956 .map(|ty| ty.map(|ty| types.canonical_abi(ty))),
3957 )
3958 .0
3959}
3960
3961enum MallocSize {
3962 Const(u32),
3963 Local(u32),
3964}
3965
3966struct WasmString<'a> {
3967 ptr: TempLocal,
3968 len: TempLocal,
3969 opts: &'a Options,
3970}
3971
3972struct TempLocal {
3973 idx: u32,
3974 ty: ValType,
3975 needs_free: bool,
3976}
3977
3978impl TempLocal {
3979 fn new(idx: u32, ty: ValType) -> TempLocal {
3980 TempLocal {
3981 idx,
3982 ty,
3983 needs_free: false,
3984 }
3985 }
3986}
3987
3988impl std::ops::Drop for TempLocal {
3989 fn drop(&mut self) {
3990 if self.needs_free {
3991 panic!("temporary local not free'd");
3992 }
3993 }
3994}
3995
3996impl From<FlatType> for ValType {
3997 fn from(ty: FlatType) -> ValType {
3998 match ty {
3999 FlatType::I32 => ValType::I32,
4000 FlatType::I64 => ValType::I64,
4001 FlatType::F32 => ValType::F32,
4002 FlatType::F64 => ValType::F64,
4003 }
4004 }
4005}