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(i32::from(
548 adapter.lift.options.string_encoding as u8,
549 )));
550
551 let result_types = &self.types[self.types[adapter.lower.ty].results].types;
554 if prepare_sync {
555 self.instruction(I32Const(
556 i32::try_from(
557 self.types
558 .flatten_types(
559 &adapter.lower.options,
560 usize::MAX,
561 result_types.iter().copied(),
562 )
563 .map(|v| v.len())
564 .unwrap_or(usize::try_from(i32::MAX).unwrap()),
565 )
566 .unwrap(),
567 ));
568 } else {
569 if result_types.len() > 0 {
570 self.instruction(I32Const(PREPARE_ASYNC_WITH_RESULT.cast_signed()));
571 } else {
572 self.instruction(I32Const(PREPARE_ASYNC_NO_RESULT.cast_signed()));
573 }
574 }
575
576 for index in 0..lower_sig.params.len() {
578 self.instruction(LocalGet(u32::try_from(index).unwrap()));
579 }
580 self.instruction(Call(prepare.as_u32()));
581 }
582
583 fn compile_sync_to_async_adapter(
593 mut self,
594 adapter: &AdapterData,
595 start: FunctionId,
596 return_: FunctionId,
597 lift_param_count: i32,
598 lower_sig: &Signature,
599 ) {
600 let start_call = self.module.import_sync_start_call(
601 &adapter.name,
602 adapter.lift.options.callback,
603 &lower_sig.results,
604 );
605
606 self.call_prepare(adapter, start, return_, lower_sig, true);
607
608 self.module.exports.push((
617 adapter.callee.as_u32(),
618 format!("[adapter-callee]{}", adapter.name),
619 ));
620
621 self.instruction(RefFunc(adapter.callee.as_u32()));
622 self.instruction(I32Const(lift_param_count));
623 self.instruction(Call(start_call.as_u32()));
624
625 self.finish()
626 }
627
628 fn compile_async_to_sync_adapter(
638 mut self,
639 adapter: &AdapterData,
640 start: FunctionId,
641 return_: FunctionId,
642 param_count: i32,
643 result_count: i32,
644 lower_sig: &Signature,
645 ) {
646 let start_call =
647 self.module
648 .import_async_start_call(&adapter.name, None, adapter.lift.post_return);
649
650 self.call_prepare(adapter, start, return_, lower_sig, false);
651
652 self.module.exports.push((
656 adapter.callee.as_u32(),
657 format!("[adapter-callee]{}", adapter.name),
658 ));
659
660 self.instruction(RefFunc(adapter.callee.as_u32()));
661 self.instruction(I32Const(param_count));
662 self.instruction(I32Const(result_count));
663 self.instruction(I32Const(0));
664 self.instruction(Call(start_call.as_u32()));
665
666 self.finish()
667 }
668
669 fn compile_async_start_adapter(mut self, adapter: &AdapterData, sig: &Signature) {
675 let param_locals = sig
676 .params
677 .iter()
678 .enumerate()
679 .map(|(i, ty)| (i as u32, *ty))
680 .collect::<Vec<_>>();
681
682 self.set_flag(adapter.lift.flags, FLAG_MAY_LEAVE, false);
683 self.translate_params(adapter, ¶m_locals);
684 self.set_flag(adapter.lift.flags, FLAG_MAY_LEAVE, true);
685
686 self.finish();
687 }
688
689 fn compile_async_return_adapter(mut self, adapter: &AdapterData, sig: &Signature) {
698 let param_locals = sig
699 .params
700 .iter()
701 .enumerate()
702 .map(|(i, ty)| (i as u32, *ty))
703 .collect::<Vec<_>>();
704
705 self.set_flag(adapter.lower.flags, FLAG_MAY_LEAVE, false);
706 self.translate_results(adapter, ¶m_locals, ¶m_locals);
717 self.set_flag(adapter.lower.flags, FLAG_MAY_LEAVE, true);
718
719 self.finish()
720 }
721
722 fn compile_sync_to_sync_adapter(
729 mut self,
730 adapter: &AdapterData,
731 lower_sig: &Signature,
732 lift_sig: &Signature,
733 ) {
734 self.trap_if_not_flag(adapter.lower.flags, FLAG_MAY_LEAVE, Trap::CannotLeave);
740 if adapter.called_as_export {
741 self.trap_if_not_flag(adapter.lift.flags, FLAG_MAY_ENTER, Trap::CannotEnter);
742 self.set_flag(adapter.lift.flags, FLAG_MAY_ENTER, false);
743 } else if self.module.debug {
744 self.assert_not_flag(
745 adapter.lift.flags,
746 FLAG_MAY_ENTER,
747 "may_enter should be unset",
748 );
749 }
750
751 if self.emit_resource_call {
752 let enter = self.module.import_resource_enter_call();
753 self.instruction(Call(enter.as_u32()));
754 }
755
756 self.set_flag(adapter.lift.flags, FLAG_MAY_LEAVE, false);
769 let param_locals = lower_sig
770 .params
771 .iter()
772 .enumerate()
773 .map(|(i, ty)| (i as u32, *ty))
774 .collect::<Vec<_>>();
775 self.translate_params(adapter, ¶m_locals);
776 self.set_flag(adapter.lift.flags, FLAG_MAY_LEAVE, true);
777
778 self.instruction(Call(adapter.callee.as_u32()));
782 let mut result_locals = Vec::with_capacity(lift_sig.results.len());
783 let mut temps = Vec::new();
784 for ty in lift_sig.results.iter().rev() {
785 let local = self.local_set_new_tmp(*ty);
786 result_locals.push((local.idx, *ty));
787 temps.push(local);
788 }
789 result_locals.reverse();
790
791 self.set_flag(adapter.lower.flags, FLAG_MAY_LEAVE, false);
800 self.translate_results(adapter, ¶m_locals, &result_locals);
801 self.set_flag(adapter.lower.flags, FLAG_MAY_LEAVE, true);
802
803 if let Some(func) = adapter.lift.post_return {
806 for (result, _) in result_locals.iter() {
807 self.instruction(LocalGet(*result));
808 }
809 self.instruction(Call(func.as_u32()));
810 }
811 if adapter.called_as_export {
812 self.set_flag(adapter.lift.flags, FLAG_MAY_ENTER, true);
813 }
814
815 for tmp in temps {
816 self.free_temp_local(tmp);
817 }
818
819 if self.emit_resource_call {
820 let exit = self.module.import_resource_exit_call();
821 self.instruction(Call(exit.as_u32()));
822 }
823
824 self.finish()
825 }
826
827 fn translate_params(&mut self, adapter: &AdapterData, param_locals: &[(u32, ValType)]) {
828 let src_tys = self.types[adapter.lower.ty].params;
829 let src_tys = self.types[src_tys]
830 .types
831 .iter()
832 .copied()
833 .collect::<Vec<_>>();
834 let dst_tys = self.types[adapter.lift.ty].params;
835 let dst_tys = self.types[dst_tys]
836 .types
837 .iter()
838 .copied()
839 .collect::<Vec<_>>();
840 let lift_opts = &adapter.lift.options;
841 let lower_opts = &adapter.lower.options;
842
843 assert_eq!(src_tys.len(), dst_tys.len());
845
846 let max_flat_params = if adapter.lower.options.async_ {
850 MAX_FLAT_ASYNC_PARAMS
851 } else {
852 MAX_FLAT_PARAMS
853 };
854 let src_flat =
855 self.types
856 .flatten_types(lower_opts, max_flat_params, src_tys.iter().copied());
857 let dst_flat =
858 self.types
859 .flatten_types(lift_opts, MAX_FLAT_PARAMS, dst_tys.iter().copied());
860
861 let src = if let Some(flat) = &src_flat {
862 Source::Stack(Stack {
863 locals: ¶m_locals[..flat.len()],
864 opts: lower_opts,
865 })
866 } else {
867 let lower_mem_opts = lower_opts.data_model.unwrap_memory();
871 let (addr, ty) = param_locals[0];
872 assert_eq!(ty, lower_mem_opts.ptr());
873 let align = src_tys
874 .iter()
875 .map(|t| self.types.align(lower_mem_opts, t))
876 .max()
877 .unwrap_or(1);
878 Source::Memory(self.memory_operand(lower_opts, TempLocal::new(addr, ty), align))
879 };
880
881 let dst = if let Some(flat) = &dst_flat {
882 Destination::Stack(flat, lift_opts)
883 } else {
884 let abi = CanonicalAbiInfo::record(dst_tys.iter().map(|t| self.types.canonical_abi(t)));
885 match lift_opts.data_model {
886 DataModel::Gc {} => todo!("CM+GC"),
887 DataModel::LinearMemory(LinearMemoryOptions { memory64, .. }) => {
888 let (size, align) = if memory64 {
889 (abi.size64, abi.align64)
890 } else {
891 (abi.size32, abi.align32)
892 };
893
894 let size = MallocSize::Const(size);
897 Destination::Memory(self.malloc(lift_opts, size, align))
898 }
899 }
900 };
901
902 let srcs = src
903 .record_field_srcs(self.types, src_tys.iter().copied())
904 .zip(src_tys.iter());
905 let dsts = dst
906 .record_field_dsts(self.types, dst_tys.iter().copied())
907 .zip(dst_tys.iter());
908 for ((src, src_ty), (dst, dst_ty)) in srcs.zip(dsts) {
909 self.translate(&src_ty, &src, &dst_ty, &dst);
910 }
911
912 if let Destination::Memory(mem) = dst {
916 self.instruction(LocalGet(mem.addr.idx));
917 self.free_temp_local(mem.addr);
918 }
919 }
920
921 fn translate_results(
922 &mut self,
923 adapter: &AdapterData,
924 param_locals: &[(u32, ValType)],
925 result_locals: &[(u32, ValType)],
926 ) {
927 let src_tys = self.types[adapter.lift.ty].results;
928 let src_tys = self.types[src_tys]
929 .types
930 .iter()
931 .copied()
932 .collect::<Vec<_>>();
933 let dst_tys = self.types[adapter.lower.ty].results;
934 let dst_tys = self.types[dst_tys]
935 .types
936 .iter()
937 .copied()
938 .collect::<Vec<_>>();
939 let lift_opts = &adapter.lift.options;
940 let lower_opts = &adapter.lower.options;
941
942 let src_flat = self
943 .types
944 .flatten_lifting_types(lift_opts, src_tys.iter().copied());
945 let dst_flat = self
946 .types
947 .flatten_lowering_types(lower_opts, dst_tys.iter().copied());
948
949 let src = if src_flat.is_some() {
950 Source::Stack(Stack {
951 locals: result_locals,
952 opts: lift_opts,
953 })
954 } else {
955 let lift_mem_opts = lift_opts.data_model.unwrap_memory();
960 let align = src_tys
961 .iter()
962 .map(|t| self.types.align(lift_mem_opts, t))
963 .max()
964 .unwrap_or(1);
965 assert_eq!(
966 result_locals.len(),
967 if lower_opts.async_ || lift_opts.async_ {
968 2
969 } else {
970 1
971 }
972 );
973 let (addr, ty) = result_locals[0];
974 assert_eq!(ty, lift_opts.data_model.unwrap_memory().ptr());
975 Source::Memory(self.memory_operand(lift_opts, TempLocal::new(addr, ty), align))
976 };
977
978 let dst = if let Some(flat) = &dst_flat {
979 Destination::Stack(flat, lower_opts)
980 } else {
981 let lower_mem_opts = lower_opts.data_model.unwrap_memory();
985 let align = dst_tys
986 .iter()
987 .map(|t| self.types.align(lower_mem_opts, t))
988 .max()
989 .unwrap_or(1);
990 let (addr, ty) = *param_locals.last().expect("no retptr");
991 assert_eq!(ty, lower_opts.data_model.unwrap_memory().ptr());
992 Destination::Memory(self.memory_operand(lower_opts, TempLocal::new(addr, ty), align))
993 };
994
995 let srcs = src
996 .record_field_srcs(self.types, src_tys.iter().copied())
997 .zip(src_tys.iter());
998 let dsts = dst
999 .record_field_dsts(self.types, dst_tys.iter().copied())
1000 .zip(dst_tys.iter());
1001 for ((src, src_ty), (dst, dst_ty)) in srcs.zip(dsts) {
1002 self.translate(&src_ty, &src, &dst_ty, &dst);
1003 }
1004 }
1005
1006 fn translate(
1007 &mut self,
1008 src_ty: &InterfaceType,
1009 src: &Source<'_>,
1010 dst_ty: &InterfaceType,
1011 dst: &Destination,
1012 ) {
1013 if let Source::Memory(mem) = src {
1014 self.assert_aligned(src_ty, mem);
1015 }
1016 if let Destination::Memory(mem) = dst {
1017 self.assert_aligned(dst_ty, mem);
1018 }
1019
1020 let cost = match src_ty {
1050 InterfaceType::Bool
1054 | InterfaceType::U8
1055 | InterfaceType::S8
1056 | InterfaceType::U16
1057 | InterfaceType::S16
1058 | InterfaceType::U32
1059 | InterfaceType::S32
1060 | InterfaceType::U64
1061 | InterfaceType::S64
1062 | InterfaceType::Float32
1063 | InterfaceType::Float64 => 0,
1064
1065 InterfaceType::Char => 1,
1068
1069 InterfaceType::String => 40,
1072
1073 InterfaceType::List(_) => 40,
1076
1077 InterfaceType::Flags(i) => {
1078 let count = self.module.types[*i].names.len();
1079 match FlagsSize::from_count(count) {
1080 FlagsSize::Size0 => 0,
1081 FlagsSize::Size1 | FlagsSize::Size2 => 1,
1082 FlagsSize::Size4Plus(n) => n.into(),
1083 }
1084 }
1085
1086 InterfaceType::Record(i) => self.types[*i].fields.len(),
1087 InterfaceType::Tuple(i) => self.types[*i].types.len(),
1088 InterfaceType::Variant(i) => self.types[*i].cases.len(),
1089 InterfaceType::Enum(i) => self.types[*i].names.len(),
1090
1091 InterfaceType::Option(_) | InterfaceType::Result(_) => 2,
1093
1094 InterfaceType::Own(_)
1096 | InterfaceType::Borrow(_)
1097 | InterfaceType::Future(_)
1098 | InterfaceType::Stream(_)
1099 | InterfaceType::ErrorContext(_) => 1,
1100 };
1101
1102 match self.fuel.checked_sub(cost) {
1103 Some(n) => {
1109 self.fuel = n;
1110 match src_ty {
1111 InterfaceType::Bool => self.translate_bool(src, dst_ty, dst),
1112 InterfaceType::U8 => self.translate_u8(src, dst_ty, dst),
1113 InterfaceType::S8 => self.translate_s8(src, dst_ty, dst),
1114 InterfaceType::U16 => self.translate_u16(src, dst_ty, dst),
1115 InterfaceType::S16 => self.translate_s16(src, dst_ty, dst),
1116 InterfaceType::U32 => self.translate_u32(src, dst_ty, dst),
1117 InterfaceType::S32 => self.translate_s32(src, dst_ty, dst),
1118 InterfaceType::U64 => self.translate_u64(src, dst_ty, dst),
1119 InterfaceType::S64 => self.translate_s64(src, dst_ty, dst),
1120 InterfaceType::Float32 => self.translate_f32(src, dst_ty, dst),
1121 InterfaceType::Float64 => self.translate_f64(src, dst_ty, dst),
1122 InterfaceType::Char => self.translate_char(src, dst_ty, dst),
1123 InterfaceType::String => self.translate_string(src, dst_ty, dst),
1124 InterfaceType::List(t) => self.translate_list(*t, src, dst_ty, dst),
1125 InterfaceType::Record(t) => self.translate_record(*t, src, dst_ty, dst),
1126 InterfaceType::Flags(f) => self.translate_flags(*f, src, dst_ty, dst),
1127 InterfaceType::Tuple(t) => self.translate_tuple(*t, src, dst_ty, dst),
1128 InterfaceType::Variant(v) => self.translate_variant(*v, src, dst_ty, dst),
1129 InterfaceType::Enum(t) => self.translate_enum(*t, src, dst_ty, dst),
1130 InterfaceType::Option(t) => self.translate_option(*t, src, dst_ty, dst),
1131 InterfaceType::Result(t) => self.translate_result(*t, src, dst_ty, dst),
1132 InterfaceType::Own(t) => self.translate_own(*t, src, dst_ty, dst),
1133 InterfaceType::Borrow(t) => self.translate_borrow(*t, src, dst_ty, dst),
1134 InterfaceType::Future(t) => self.translate_future(*t, src, dst_ty, dst),
1135 InterfaceType::Stream(t) => self.translate_stream(*t, src, dst_ty, dst),
1136 InterfaceType::ErrorContext(t) => {
1137 self.translate_error_context(*t, src, dst_ty, dst)
1138 }
1139 }
1140 }
1141
1142 None => {
1148 let src_loc = match src {
1149 Source::Stack(stack) => {
1153 for (i, ty) in stack
1154 .opts
1155 .flat_types(src_ty, self.types)
1156 .unwrap()
1157 .iter()
1158 .enumerate()
1159 {
1160 let stack = stack.slice(i..i + 1);
1161 self.stack_get(&stack, (*ty).into());
1162 }
1163 HelperLocation::Stack
1164 }
1165 Source::Memory(mem) => {
1170 self.push_mem_addr(mem);
1171 HelperLocation::Memory
1172 }
1173 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1174 };
1175 let dst_loc = match dst {
1176 Destination::Stack(..) => HelperLocation::Stack,
1177 Destination::Memory(mem) => {
1178 self.push_mem_addr(mem);
1179 HelperLocation::Memory
1180 }
1181 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1182 };
1183 let helper = self.module.translate_helper(Helper {
1189 src: HelperType {
1190 ty: *src_ty,
1191 opts: *src.opts(),
1192 loc: src_loc,
1193 },
1194 dst: HelperType {
1195 ty: *dst_ty,
1196 opts: *dst.opts(),
1197 loc: dst_loc,
1198 },
1199 });
1200 self.flush_code();
1203 self.module.funcs[self.result].body.push(Body::Call(helper));
1204
1205 if let Destination::Stack(tys, opts) = dst {
1214 let flat = self
1215 .types
1216 .flatten_types(opts, usize::MAX, [*dst_ty])
1217 .unwrap();
1218 assert_eq!(flat.len(), tys.len());
1219 let locals = flat
1220 .iter()
1221 .rev()
1222 .map(|ty| self.local_set_new_tmp(*ty))
1223 .collect::<Vec<_>>();
1224 for (ty, local) in tys.iter().zip(locals.into_iter().rev()) {
1225 self.instruction(LocalGet(local.idx));
1226 self.stack_set(std::slice::from_ref(ty), local.ty);
1227 self.free_temp_local(local);
1228 }
1229 }
1230 }
1231 }
1232 }
1233
1234 fn push_mem_addr(&mut self, mem: &Memory<'_>) {
1235 self.instruction(LocalGet(mem.addr.idx));
1236 if mem.offset != 0 {
1237 self.ptr_uconst(mem.mem_opts(), mem.offset);
1238 self.ptr_add(mem.mem_opts());
1239 }
1240 }
1241
1242 fn translate_bool(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1243 assert!(matches!(dst_ty, InterfaceType::Bool));
1245 self.push_dst_addr(dst);
1246
1247 self.instruction(I32Const(1));
1250 self.instruction(I32Const(0));
1251 match src {
1252 Source::Memory(mem) => self.i32_load8u(mem),
1253 Source::Stack(stack) => self.stack_get(stack, ValType::I32),
1254 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1255 }
1256 self.instruction(Select);
1257
1258 match dst {
1259 Destination::Memory(mem) => self.i32_store8(mem),
1260 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1261 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1262 }
1263 }
1264
1265 fn translate_u8(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1266 assert!(matches!(dst_ty, InterfaceType::U8));
1268 self.convert_u8_mask(src, dst, 0xff);
1269 }
1270
1271 fn convert_u8_mask(&mut self, src: &Source<'_>, dst: &Destination<'_>, mask: u8) {
1272 self.push_dst_addr(dst);
1273 let mut needs_mask = true;
1274 match src {
1275 Source::Memory(mem) => {
1276 self.i32_load8u(mem);
1277 needs_mask = mask != 0xff;
1278 }
1279 Source::Stack(stack) => {
1280 self.stack_get(stack, ValType::I32);
1281 }
1282 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1283 }
1284 if needs_mask {
1285 self.instruction(I32Const(i32::from(mask)));
1286 self.instruction(I32And);
1287 }
1288 match dst {
1289 Destination::Memory(mem) => self.i32_store8(mem),
1290 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1291 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1292 }
1293 }
1294
1295 fn translate_s8(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1296 assert!(matches!(dst_ty, InterfaceType::S8));
1298 self.push_dst_addr(dst);
1299 match src {
1300 Source::Memory(mem) => self.i32_load8s(mem),
1301 Source::Stack(stack) => {
1302 self.stack_get(stack, ValType::I32);
1303 self.instruction(I32Extend8S);
1304 }
1305 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1306 }
1307 match dst {
1308 Destination::Memory(mem) => self.i32_store8(mem),
1309 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1310 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1311 }
1312 }
1313
1314 fn translate_u16(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1315 assert!(matches!(dst_ty, InterfaceType::U16));
1317 self.convert_u16_mask(src, dst, 0xffff);
1318 }
1319
1320 fn convert_u16_mask(&mut self, src: &Source<'_>, dst: &Destination<'_>, mask: u16) {
1321 self.push_dst_addr(dst);
1322 let mut needs_mask = true;
1323 match src {
1324 Source::Memory(mem) => {
1325 self.i32_load16u(mem);
1326 needs_mask = mask != 0xffff;
1327 }
1328 Source::Stack(stack) => {
1329 self.stack_get(stack, ValType::I32);
1330 }
1331 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1332 }
1333 if needs_mask {
1334 self.instruction(I32Const(i32::from(mask)));
1335 self.instruction(I32And);
1336 }
1337 match dst {
1338 Destination::Memory(mem) => self.i32_store16(mem),
1339 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1340 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1341 }
1342 }
1343
1344 fn translate_s16(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1345 assert!(matches!(dst_ty, InterfaceType::S16));
1347 self.push_dst_addr(dst);
1348 match src {
1349 Source::Memory(mem) => self.i32_load16s(mem),
1350 Source::Stack(stack) => {
1351 self.stack_get(stack, ValType::I32);
1352 self.instruction(I32Extend16S);
1353 }
1354 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1355 }
1356 match dst {
1357 Destination::Memory(mem) => self.i32_store16(mem),
1358 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1359 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1360 }
1361 }
1362
1363 fn translate_u32(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1364 assert!(matches!(dst_ty, InterfaceType::U32));
1366 self.convert_u32_mask(src, dst, 0xffffffff)
1367 }
1368
1369 fn convert_u32_mask(&mut self, src: &Source<'_>, dst: &Destination<'_>, mask: u32) {
1370 self.push_dst_addr(dst);
1371 match src {
1372 Source::Memory(mem) => self.i32_load(mem),
1373 Source::Stack(stack) => self.stack_get(stack, ValType::I32),
1374 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1375 }
1376 if mask != 0xffffffff {
1377 self.instruction(I32Const(mask as i32));
1378 self.instruction(I32And);
1379 }
1380 match dst {
1381 Destination::Memory(mem) => self.i32_store(mem),
1382 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1383 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1384 }
1385 }
1386
1387 fn translate_s32(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1388 assert!(matches!(dst_ty, InterfaceType::S32));
1390 self.push_dst_addr(dst);
1391 match src {
1392 Source::Memory(mem) => self.i32_load(mem),
1393 Source::Stack(stack) => self.stack_get(stack, ValType::I32),
1394 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1395 }
1396 match dst {
1397 Destination::Memory(mem) => self.i32_store(mem),
1398 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1399 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1400 }
1401 }
1402
1403 fn translate_u64(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1404 assert!(matches!(dst_ty, InterfaceType::U64));
1406 self.push_dst_addr(dst);
1407 match src {
1408 Source::Memory(mem) => self.i64_load(mem),
1409 Source::Stack(stack) => self.stack_get(stack, ValType::I64),
1410 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1411 }
1412 match dst {
1413 Destination::Memory(mem) => self.i64_store(mem),
1414 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I64),
1415 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1416 }
1417 }
1418
1419 fn translate_s64(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1420 assert!(matches!(dst_ty, InterfaceType::S64));
1422 self.push_dst_addr(dst);
1423 match src {
1424 Source::Memory(mem) => self.i64_load(mem),
1425 Source::Stack(stack) => self.stack_get(stack, ValType::I64),
1426 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1427 }
1428 match dst {
1429 Destination::Memory(mem) => self.i64_store(mem),
1430 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I64),
1431 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1432 }
1433 }
1434
1435 fn translate_f32(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1436 assert!(matches!(dst_ty, InterfaceType::Float32));
1438 self.push_dst_addr(dst);
1439 match src {
1440 Source::Memory(mem) => self.f32_load(mem),
1441 Source::Stack(stack) => self.stack_get(stack, ValType::F32),
1442 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1443 }
1444 match dst {
1445 Destination::Memory(mem) => self.f32_store(mem),
1446 Destination::Stack(stack, _) => self.stack_set(stack, ValType::F32),
1447 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1448 }
1449 }
1450
1451 fn translate_f64(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1452 assert!(matches!(dst_ty, InterfaceType::Float64));
1454 self.push_dst_addr(dst);
1455 match src {
1456 Source::Memory(mem) => self.f64_load(mem),
1457 Source::Stack(stack) => self.stack_get(stack, ValType::F64),
1458 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1459 }
1460 match dst {
1461 Destination::Memory(mem) => self.f64_store(mem),
1462 Destination::Stack(stack, _) => self.stack_set(stack, ValType::F64),
1463 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1464 }
1465 }
1466
1467 fn translate_char(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1468 assert!(matches!(dst_ty, InterfaceType::Char));
1469 match src {
1470 Source::Memory(mem) => self.i32_load(mem),
1471 Source::Stack(stack) => self.stack_get(stack, ValType::I32),
1472 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1473 }
1474 let local = self.local_set_new_tmp(ValType::I32);
1475
1476 self.instruction(Block(BlockType::Empty));
1492 self.instruction(Block(BlockType::Empty));
1493 self.instruction(LocalGet(local.idx));
1494 self.instruction(I32Const(0xd800));
1495 self.instruction(I32Xor);
1496 self.instruction(I32Const(-0x110000));
1497 self.instruction(I32Add);
1498 self.instruction(I32Const(-0x10f800));
1499 self.instruction(I32LtU);
1500 self.instruction(BrIf(0));
1501 self.instruction(LocalGet(local.idx));
1502 self.instruction(I32Const(0x110000));
1503 self.instruction(I32Ne);
1504 self.instruction(BrIf(1));
1505 self.instruction(End);
1506 self.trap(Trap::InvalidChar);
1507 self.instruction(End);
1508
1509 self.push_dst_addr(dst);
1510 self.instruction(LocalGet(local.idx));
1511 match dst {
1512 Destination::Memory(mem) => {
1513 self.i32_store(mem);
1514 }
1515 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1516 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1517 }
1518
1519 self.free_temp_local(local);
1520 }
1521
1522 fn translate_string(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1523 assert!(matches!(dst_ty, InterfaceType::String));
1524 let src_opts = src.opts();
1525 let dst_opts = dst.opts();
1526
1527 let src_mem_opts = match &src_opts.data_model {
1528 DataModel::Gc {} => todo!("CM+GC"),
1529 DataModel::LinearMemory(opts) => opts,
1530 };
1531 let dst_mem_opts = match &dst_opts.data_model {
1532 DataModel::Gc {} => todo!("CM+GC"),
1533 DataModel::LinearMemory(opts) => opts,
1534 };
1535
1536 match src {
1541 Source::Stack(s) => {
1542 assert_eq!(s.locals.len(), 2);
1543 self.stack_get(&s.slice(0..1), src_mem_opts.ptr());
1544 self.stack_get(&s.slice(1..2), src_mem_opts.ptr());
1545 }
1546 Source::Memory(mem) => {
1547 self.ptr_load(mem);
1548 self.ptr_load(&mem.bump(src_mem_opts.ptr_size().into()));
1549 }
1550 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1551 }
1552 let src_len = self.local_set_new_tmp(src_mem_opts.ptr());
1553 let src_ptr = self.local_set_new_tmp(src_mem_opts.ptr());
1554 let src_str = WasmString {
1555 ptr: src_ptr,
1556 len: src_len,
1557 opts: src_opts,
1558 };
1559
1560 let dst_str = match src_opts.string_encoding {
1561 StringEncoding::Utf8 => match dst_opts.string_encoding {
1562 StringEncoding::Utf8 => self.string_copy(&src_str, FE::Utf8, dst_opts, FE::Utf8),
1563 StringEncoding::Utf16 => self.string_utf8_to_utf16(&src_str, dst_opts),
1564 StringEncoding::CompactUtf16 => {
1565 self.string_to_compact(&src_str, FE::Utf8, dst_opts)
1566 }
1567 },
1568
1569 StringEncoding::Utf16 => {
1570 self.verify_aligned(src_mem_opts, src_str.ptr.idx, 2);
1571 match dst_opts.string_encoding {
1572 StringEncoding::Utf8 => {
1573 self.string_deflate_to_utf8(&src_str, FE::Utf16, dst_opts)
1574 }
1575 StringEncoding::Utf16 => {
1576 self.string_copy(&src_str, FE::Utf16, dst_opts, FE::Utf16)
1577 }
1578 StringEncoding::CompactUtf16 => {
1579 self.string_to_compact(&src_str, FE::Utf16, dst_opts)
1580 }
1581 }
1582 }
1583
1584 StringEncoding::CompactUtf16 => {
1585 self.verify_aligned(src_mem_opts, src_str.ptr.idx, 2);
1586
1587 self.instruction(LocalGet(src_str.len.idx));
1590 self.ptr_uconst(src_mem_opts, UTF16_TAG);
1591 self.ptr_and(src_mem_opts);
1592 self.ptr_if(src_mem_opts, BlockType::Empty);
1593
1594 self.instruction(LocalGet(src_str.len.idx));
1598 self.ptr_uconst(src_mem_opts, UTF16_TAG);
1599 self.ptr_xor(src_mem_opts);
1600 self.instruction(LocalSet(src_str.len.idx));
1601 let s1 = match dst_opts.string_encoding {
1602 StringEncoding::Utf8 => {
1603 self.string_deflate_to_utf8(&src_str, FE::Utf16, dst_opts)
1604 }
1605 StringEncoding::Utf16 => {
1606 self.string_copy(&src_str, FE::Utf16, dst_opts, FE::Utf16)
1607 }
1608 StringEncoding::CompactUtf16 => {
1609 self.string_compact_utf16_to_compact(&src_str, dst_opts)
1610 }
1611 };
1612
1613 self.instruction(Else);
1614
1615 let s2 = match dst_opts.string_encoding {
1619 StringEncoding::Utf16 => {
1620 self.string_copy(&src_str, FE::Latin1, dst_opts, FE::Utf16)
1621 }
1622 StringEncoding::Utf8 => {
1623 self.string_deflate_to_utf8(&src_str, FE::Latin1, dst_opts)
1624 }
1625 StringEncoding::CompactUtf16 => {
1626 self.string_copy(&src_str, FE::Latin1, dst_opts, FE::Latin1)
1627 }
1628 };
1629 self.instruction(LocalGet(s2.ptr.idx));
1632 self.instruction(LocalSet(s1.ptr.idx));
1633 self.instruction(LocalGet(s2.len.idx));
1634 self.instruction(LocalSet(s1.len.idx));
1635 self.instruction(End);
1636 self.free_temp_local(s2.ptr);
1637 self.free_temp_local(s2.len);
1638 s1
1639 }
1640 };
1641
1642 match dst {
1644 Destination::Stack(s, _) => {
1645 self.instruction(LocalGet(dst_str.ptr.idx));
1646 self.stack_set(&s[..1], dst_mem_opts.ptr());
1647 self.instruction(LocalGet(dst_str.len.idx));
1648 self.stack_set(&s[1..], dst_mem_opts.ptr());
1649 }
1650 Destination::Memory(mem) => {
1651 self.instruction(LocalGet(mem.addr.idx));
1652 self.instruction(LocalGet(dst_str.ptr.idx));
1653 self.ptr_store(mem);
1654 self.instruction(LocalGet(mem.addr.idx));
1655 self.instruction(LocalGet(dst_str.len.idx));
1656 self.ptr_store(&mem.bump(dst_mem_opts.ptr_size().into()));
1657 }
1658 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1659 }
1660
1661 self.free_temp_local(src_str.ptr);
1662 self.free_temp_local(src_str.len);
1663 self.free_temp_local(dst_str.ptr);
1664 self.free_temp_local(dst_str.len);
1665 }
1666
1667 fn string_copy<'c>(
1680 &mut self,
1681 src: &WasmString<'_>,
1682 src_enc: FE,
1683 dst_opts: &'c Options,
1684 dst_enc: FE,
1685 ) -> WasmString<'c> {
1686 assert!(dst_enc.width() >= src_enc.width());
1687 self.validate_string_length(src, dst_enc);
1688
1689 let src_mem_opts = {
1690 match &src.opts.data_model {
1691 DataModel::Gc {} => todo!("CM+GC"),
1692 DataModel::LinearMemory(opts) => opts,
1693 }
1694 };
1695 let dst_mem_opts = {
1696 match &dst_opts.data_model {
1697 DataModel::Gc {} => todo!("CM+GC"),
1698 DataModel::LinearMemory(opts) => opts,
1699 }
1700 };
1701
1702 let mut src_byte_len_tmp = None;
1706 let src_byte_len = if src_enc.width() == 1 {
1707 src.len.idx
1708 } else {
1709 assert_eq!(src_enc.width(), 2);
1710 self.instruction(LocalGet(src.len.idx));
1711 self.ptr_uconst(src_mem_opts, 1);
1712 self.ptr_shl(src_mem_opts);
1713 let tmp = self.local_set_new_tmp(src.opts.data_model.unwrap_memory().ptr());
1714 let ret = tmp.idx;
1715 src_byte_len_tmp = Some(tmp);
1716 ret
1717 };
1718
1719 self.convert_src_len_to_dst(
1722 src.len.idx,
1723 src.opts.data_model.unwrap_memory().ptr(),
1724 dst_opts.data_model.unwrap_memory().ptr(),
1725 );
1726 let dst_len = self.local_tee_new_tmp(dst_opts.data_model.unwrap_memory().ptr());
1727 if dst_enc.width() > 1 {
1728 assert_eq!(dst_enc.width(), 2);
1729 self.ptr_uconst(dst_mem_opts, 1);
1730 self.ptr_shl(dst_mem_opts);
1731 }
1732 let dst_byte_len = self.local_set_new_tmp(dst_opts.data_model.unwrap_memory().ptr());
1733
1734 let dst = {
1737 let dst_mem = self.malloc(
1738 dst_opts,
1739 MallocSize::Local(dst_byte_len.idx),
1740 dst_enc.width().into(),
1741 );
1742 WasmString {
1743 ptr: dst_mem.addr,
1744 len: dst_len,
1745 opts: dst_opts,
1746 }
1747 };
1748
1749 self.validate_string_inbounds(src, src_byte_len);
1754 self.validate_string_inbounds(&dst, dst_byte_len.idx);
1755
1756 let op = if src_enc == dst_enc {
1760 Transcode::Copy(src_enc)
1761 } else {
1762 assert_eq!(src_enc, FE::Latin1);
1763 assert_eq!(dst_enc, FE::Utf16);
1764 Transcode::Latin1ToUtf16
1765 };
1766 let transcode = self.transcoder(src, &dst, op);
1767 self.instruction(LocalGet(src.ptr.idx));
1768 self.instruction(LocalGet(src.len.idx));
1769 self.instruction(LocalGet(dst.ptr.idx));
1770 self.instruction(Call(transcode.as_u32()));
1771
1772 self.free_temp_local(dst_byte_len);
1773 if let Some(tmp) = src_byte_len_tmp {
1774 self.free_temp_local(tmp);
1775 }
1776
1777 dst
1778 }
1779 fn string_deflate_to_utf8<'c>(
1792 &mut self,
1793 src: &WasmString<'_>,
1794 src_enc: FE,
1795 dst_opts: &'c Options,
1796 ) -> WasmString<'c> {
1797 let src_mem_opts = match &src.opts.data_model {
1798 DataModel::Gc {} => todo!("CM+GC"),
1799 DataModel::LinearMemory(opts) => opts,
1800 };
1801 let dst_mem_opts = match &dst_opts.data_model {
1802 DataModel::Gc {} => todo!("CM+GC"),
1803 DataModel::LinearMemory(opts) => opts,
1804 };
1805
1806 self.validate_string_length(src, src_enc);
1807
1808 self.convert_src_len_to_dst(
1812 src.len.idx,
1813 src.opts.data_model.unwrap_memory().ptr(),
1814 dst_opts.data_model.unwrap_memory().ptr(),
1815 );
1816 let dst_len = self.local_tee_new_tmp(dst_opts.data_model.unwrap_memory().ptr());
1817 let dst_byte_len = self.local_set_new_tmp(dst_opts.data_model.unwrap_memory().ptr());
1818
1819 let dst = {
1820 let dst_mem = self.malloc(dst_opts, MallocSize::Local(dst_byte_len.idx), 1);
1821 WasmString {
1822 ptr: dst_mem.addr,
1823 len: dst_len,
1824 opts: dst_opts,
1825 }
1826 };
1827
1828 let mut src_byte_len_tmp = None;
1830 let src_byte_len = match src_enc {
1831 FE::Latin1 => src.len.idx,
1832 FE::Utf16 => {
1833 self.instruction(LocalGet(src.len.idx));
1834 self.ptr_uconst(src_mem_opts, 1);
1835 self.ptr_shl(src_mem_opts);
1836 let tmp = self.local_set_new_tmp(src.opts.data_model.unwrap_memory().ptr());
1837 let ret = tmp.idx;
1838 src_byte_len_tmp = Some(tmp);
1839 ret
1840 }
1841 FE::Utf8 => unreachable!(),
1842 };
1843 self.validate_string_inbounds(src, src_byte_len);
1844 self.validate_string_inbounds(&dst, dst_byte_len.idx);
1845
1846 let op = match src_enc {
1848 FE::Latin1 => Transcode::Latin1ToUtf8,
1849 FE::Utf16 => Transcode::Utf16ToUtf8,
1850 FE::Utf8 => unreachable!(),
1851 };
1852 let transcode = self.transcoder(src, &dst, op);
1853 self.instruction(LocalGet(src.ptr.idx));
1854 self.instruction(LocalGet(src.len.idx));
1855 self.instruction(LocalGet(dst.ptr.idx));
1856 self.instruction(LocalGet(dst_byte_len.idx));
1857 self.instruction(Call(transcode.as_u32()));
1858 self.instruction(LocalSet(dst.len.idx));
1859 let src_len_tmp = self.local_set_new_tmp(src.opts.data_model.unwrap_memory().ptr());
1860
1861 self.instruction(LocalGet(src_len_tmp.idx));
1865 self.instruction(LocalGet(src.len.idx));
1866 self.ptr_ne(src_mem_opts);
1867 self.instruction(If(BlockType::Empty));
1868
1869 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 {
1876 FE::Latin1 => 2,
1877 FE::Utf16 => 3,
1878 _ => unreachable!(),
1879 };
1880 self.validate_string_length_u8(src, factor);
1881 self.convert_src_len_to_dst(
1882 src.len.idx,
1883 src.opts.data_model.unwrap_memory().ptr(),
1884 dst_opts.data_model.unwrap_memory().ptr(),
1885 );
1886 self.ptr_uconst(dst_mem_opts, factor.into());
1887 self.ptr_mul(dst_mem_opts);
1888 self.instruction(LocalTee(dst_byte_len.idx));
1889 self.instruction(Call(dst_mem_opts.realloc.unwrap().as_u32()));
1890 self.instruction(LocalSet(dst.ptr.idx));
1891
1892 self.validate_string_inbounds(&dst, dst_byte_len.idx);
1894
1895 self.instruction(LocalGet(src.ptr.idx));
1900 self.instruction(LocalGet(src_len_tmp.idx));
1901 if let FE::Utf16 = src_enc {
1902 self.ptr_uconst(src_mem_opts, 1);
1903 self.ptr_shl(src_mem_opts);
1904 }
1905 self.ptr_add(src_mem_opts);
1906 self.instruction(LocalGet(src.len.idx));
1907 self.instruction(LocalGet(src_len_tmp.idx));
1908 self.ptr_sub(src_mem_opts);
1909 self.instruction(LocalGet(dst.ptr.idx));
1910 self.instruction(LocalGet(dst.len.idx));
1911 self.ptr_add(dst_mem_opts);
1912 self.instruction(LocalGet(dst_byte_len.idx));
1913 self.instruction(LocalGet(dst.len.idx));
1914 self.ptr_sub(dst_mem_opts);
1915 self.instruction(Call(transcode.as_u32()));
1916
1917 self.instruction(LocalGet(dst.len.idx));
1921 self.ptr_add(dst_mem_opts);
1922 self.instruction(LocalSet(dst.len.idx));
1923
1924 if self.module.debug {
1927 self.instruction(LocalGet(src.len.idx));
1928 self.instruction(LocalGet(src_len_tmp.idx));
1929 self.ptr_sub(src_mem_opts);
1930 self.ptr_ne(src_mem_opts);
1931 self.instruction(If(BlockType::Empty));
1932 self.trap(Trap::AssertFailed("should have finished encoding"));
1933 self.instruction(End);
1934 } else {
1935 self.instruction(Drop);
1936 }
1937
1938 self.instruction(LocalGet(dst.len.idx));
1940 self.instruction(LocalGet(dst_byte_len.idx));
1941 self.ptr_ne(dst_mem_opts);
1942 self.instruction(If(BlockType::Empty));
1943 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()));
1948 self.instruction(LocalSet(dst.ptr.idx));
1949 self.instruction(End);
1950
1951 if self.module.debug {
1954 self.instruction(Else);
1955
1956 self.instruction(LocalGet(dst.len.idx));
1957 self.instruction(LocalGet(dst_byte_len.idx));
1958 self.ptr_ne(dst_mem_opts);
1959 self.instruction(If(BlockType::Empty));
1960 self.trap(Trap::AssertFailed("should have finished encoding"));
1961 self.instruction(End);
1962 }
1963
1964 self.instruction(End); self.free_temp_local(src_len_tmp);
1967 self.free_temp_local(dst_byte_len);
1968 if let Some(tmp) = src_byte_len_tmp {
1969 self.free_temp_local(tmp);
1970 }
1971
1972 dst
1973 }
1974
1975 fn string_utf8_to_utf16<'c>(
1990 &mut self,
1991 src: &WasmString<'_>,
1992 dst_opts: &'c Options,
1993 ) -> WasmString<'c> {
1994 let src_mem_opts = match &src.opts.data_model {
1995 DataModel::Gc {} => todo!("CM+GC"),
1996 DataModel::LinearMemory(opts) => opts,
1997 };
1998 let dst_mem_opts = match &dst_opts.data_model {
1999 DataModel::Gc {} => todo!("CM+GC"),
2000 DataModel::LinearMemory(opts) => opts,
2001 };
2002
2003 self.validate_string_length(src, FE::Utf16);
2004 self.convert_src_len_to_dst(
2005 src.len.idx,
2006 src_mem_opts.ptr(),
2007 dst_opts.data_model.unwrap_memory().ptr(),
2008 );
2009 let dst_len = self.local_tee_new_tmp(dst_opts.data_model.unwrap_memory().ptr());
2010 self.ptr_uconst(dst_mem_opts, 1);
2011 self.ptr_shl(dst_mem_opts);
2012 let dst_byte_len = self.local_set_new_tmp(dst_opts.data_model.unwrap_memory().ptr());
2013 let dst = {
2014 let dst_mem = self.malloc(dst_opts, MallocSize::Local(dst_byte_len.idx), 2);
2015 WasmString {
2016 ptr: dst_mem.addr,
2017 len: dst_len,
2018 opts: dst_opts,
2019 }
2020 };
2021
2022 self.validate_string_inbounds(src, src.len.idx);
2023 self.validate_string_inbounds(&dst, dst_byte_len.idx);
2024
2025 let transcode = self.transcoder(src, &dst, Transcode::Utf8ToUtf16);
2026 self.instruction(LocalGet(src.ptr.idx));
2027 self.instruction(LocalGet(src.len.idx));
2028 self.instruction(LocalGet(dst.ptr.idx));
2029 self.instruction(Call(transcode.as_u32()));
2030 self.instruction(LocalSet(dst.len.idx));
2031
2032 self.convert_src_len_to_dst(src.len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2040 self.instruction(LocalGet(dst.len.idx));
2041 self.ptr_ne(dst_mem_opts);
2042 self.instruction(If(BlockType::Empty));
2043 self.instruction(LocalGet(dst.ptr.idx));
2044 self.instruction(LocalGet(dst_byte_len.idx));
2045 self.ptr_uconst(dst_mem_opts, 2);
2046 self.instruction(LocalGet(dst.len.idx));
2047 self.ptr_uconst(dst_mem_opts, 1);
2048 self.ptr_shl(dst_mem_opts);
2049 self.instruction(Call(match dst.opts.data_model {
2050 DataModel::Gc {} => todo!("CM+GC"),
2051 DataModel::LinearMemory(LinearMemoryOptions { realloc, .. }) => {
2052 realloc.unwrap().as_u32()
2053 }
2054 }));
2055 self.instruction(LocalSet(dst.ptr.idx));
2056 self.instruction(End); self.free_temp_local(dst_byte_len);
2059
2060 dst
2061 }
2062
2063 fn string_compact_utf16_to_compact<'c>(
2077 &mut self,
2078 src: &WasmString<'_>,
2079 dst_opts: &'c Options,
2080 ) -> WasmString<'c> {
2081 let src_mem_opts = match &src.opts.data_model {
2082 DataModel::Gc {} => todo!("CM+GC"),
2083 DataModel::LinearMemory(opts) => opts,
2084 };
2085 let dst_mem_opts = match &dst_opts.data_model {
2086 DataModel::Gc {} => todo!("CM+GC"),
2087 DataModel::LinearMemory(opts) => opts,
2088 };
2089
2090 self.validate_string_length(src, FE::Utf16);
2091 self.convert_src_len_to_dst(src.len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2092 let dst_len = self.local_tee_new_tmp(dst_mem_opts.ptr());
2093 self.ptr_uconst(dst_mem_opts, 1);
2094 self.ptr_shl(dst_mem_opts);
2095 let dst_byte_len = self.local_set_new_tmp(dst_mem_opts.ptr());
2096 let dst = {
2097 let dst_mem = self.malloc(dst_opts, MallocSize::Local(dst_byte_len.idx), 2);
2098 WasmString {
2099 ptr: dst_mem.addr,
2100 len: dst_len,
2101 opts: dst_opts,
2102 }
2103 };
2104
2105 self.convert_src_len_to_dst(
2106 dst_byte_len.idx,
2107 dst.opts.data_model.unwrap_memory().ptr(),
2108 src_mem_opts.ptr(),
2109 );
2110 let src_byte_len = self.local_set_new_tmp(src_mem_opts.ptr());
2111
2112 self.validate_string_inbounds(src, src_byte_len.idx);
2113 self.validate_string_inbounds(&dst, dst_byte_len.idx);
2114
2115 let transcode = self.transcoder(src, &dst, Transcode::Utf16ToCompactProbablyUtf16);
2116 self.instruction(LocalGet(src.ptr.idx));
2117 self.instruction(LocalGet(src.len.idx));
2118 self.instruction(LocalGet(dst.ptr.idx));
2119 self.instruction(Call(transcode.as_u32()));
2120 self.instruction(LocalSet(dst.len.idx));
2121
2122 if self.module.debug {
2125 self.instruction(LocalGet(dst.len.idx));
2126 self.ptr_uconst(dst_mem_opts, !UTF16_TAG);
2127 self.ptr_and(dst_mem_opts);
2128 self.convert_src_len_to_dst(src.len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2129 self.ptr_ne(dst_mem_opts);
2130 self.instruction(If(BlockType::Empty));
2131 self.trap(Trap::AssertFailed("expected equal code units"));
2132 self.instruction(End);
2133 }
2134
2135 self.instruction(LocalGet(dst.len.idx));
2139 self.ptr_uconst(dst_mem_opts, UTF16_TAG);
2140 self.ptr_and(dst_mem_opts);
2141 self.ptr_br_if(dst_mem_opts, 0);
2142
2143 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()));
2149 self.instruction(LocalSet(dst.ptr.idx));
2150
2151 self.free_temp_local(dst_byte_len);
2152 self.free_temp_local(src_byte_len);
2153
2154 dst
2155 }
2156
2157 fn string_to_compact<'c>(
2164 &mut self,
2165 src: &WasmString<'_>,
2166 src_enc: FE,
2167 dst_opts: &'c Options,
2168 ) -> WasmString<'c> {
2169 let src_mem_opts = match &src.opts.data_model {
2170 DataModel::Gc {} => todo!("CM+GC"),
2171 DataModel::LinearMemory(opts) => opts,
2172 };
2173 let dst_mem_opts = match &dst_opts.data_model {
2174 DataModel::Gc {} => todo!("CM+GC"),
2175 DataModel::LinearMemory(opts) => opts,
2176 };
2177
2178 self.validate_string_length(src, src_enc);
2179 self.convert_src_len_to_dst(src.len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2180 let dst_len = self.local_tee_new_tmp(dst_mem_opts.ptr());
2181 let dst_byte_len = self.local_set_new_tmp(dst_mem_opts.ptr());
2182 let dst = {
2183 let dst_mem = self.malloc(dst_opts, MallocSize::Local(dst_byte_len.idx), 2);
2184 WasmString {
2185 ptr: dst_mem.addr,
2186 len: dst_len,
2187 opts: dst_opts,
2188 }
2189 };
2190
2191 self.validate_string_inbounds(src, src.len.idx);
2192 self.validate_string_inbounds(&dst, dst_byte_len.idx);
2193
2194 let (latin1, utf16) = match src_enc {
2198 FE::Utf8 => (Transcode::Utf8ToLatin1, Transcode::Utf8ToCompactUtf16),
2199 FE::Utf16 => (Transcode::Utf16ToLatin1, Transcode::Utf16ToCompactUtf16),
2200 FE::Latin1 => unreachable!(),
2201 };
2202 let transcode_latin1 = self.transcoder(src, &dst, latin1);
2203 let transcode_utf16 = self.transcoder(src, &dst, utf16);
2204 self.instruction(LocalGet(src.ptr.idx));
2205 self.instruction(LocalGet(src.len.idx));
2206 self.instruction(LocalGet(dst.ptr.idx));
2207 self.instruction(Call(transcode_latin1.as_u32()));
2208 self.instruction(LocalSet(dst.len.idx));
2209 let src_len_tmp = self.local_set_new_tmp(src_mem_opts.ptr());
2210
2211 self.instruction(LocalGet(src_len_tmp.idx));
2214 self.instruction(LocalGet(src.len.idx));
2215 self.ptr_eq(src_mem_opts);
2216 self.instruction(If(BlockType::Empty)); self.instruction(LocalGet(dst_byte_len.idx));
2222 self.instruction(LocalGet(dst.len.idx));
2223 self.ptr_ne(dst_mem_opts);
2224 self.instruction(If(BlockType::Empty));
2225 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()));
2230 self.instruction(LocalSet(dst.ptr.idx));
2231 self.instruction(End);
2232
2233 self.instruction(Else); if src_enc.width() == 1 {
2242 self.validate_string_length_u8(src, 2);
2243 }
2244
2245 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());
2251 self.ptr_uconst(dst_mem_opts, 1);
2252 self.ptr_shl(dst_mem_opts);
2253 self.instruction(LocalTee(dst_byte_len.idx));
2254 self.instruction(Call(dst_mem_opts.realloc.unwrap().as_u32()));
2255 self.instruction(LocalSet(dst.ptr.idx));
2256
2257 self.instruction(LocalGet(src.ptr.idx));
2261 self.instruction(LocalGet(src_len_tmp.idx));
2262 if let FE::Utf16 = src_enc {
2263 self.ptr_uconst(src_mem_opts, 1);
2264 self.ptr_shl(src_mem_opts);
2265 }
2266 self.ptr_add(src_mem_opts);
2267 self.instruction(LocalGet(src.len.idx));
2268 self.instruction(LocalGet(src_len_tmp.idx));
2269 self.ptr_sub(src_mem_opts);
2270 self.instruction(LocalGet(dst.ptr.idx));
2271 self.convert_src_len_to_dst(src.len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2272 self.instruction(LocalGet(dst.len.idx));
2273 self.instruction(Call(transcode_utf16.as_u32()));
2274 self.instruction(LocalSet(dst.len.idx));
2275
2276 self.instruction(LocalGet(dst.len.idx));
2284 self.convert_src_len_to_dst(src.len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2285 self.ptr_ne(dst_mem_opts);
2286 self.instruction(If(BlockType::Empty));
2287 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));
2291 self.ptr_uconst(dst_mem_opts, 1);
2292 self.ptr_shl(dst_mem_opts);
2293 self.instruction(Call(dst_mem_opts.realloc.unwrap().as_u32()));
2294 self.instruction(LocalSet(dst.ptr.idx));
2295 self.instruction(End);
2296
2297 self.instruction(LocalGet(dst.len.idx));
2299 self.ptr_uconst(dst_mem_opts, UTF16_TAG);
2300 self.ptr_or(dst_mem_opts);
2301 self.instruction(LocalSet(dst.len.idx));
2302
2303 self.instruction(End); self.free_temp_local(src_len_tmp);
2306 self.free_temp_local(dst_byte_len);
2307
2308 dst
2309 }
2310
2311 fn validate_string_length(&mut self, src: &WasmString<'_>, dst: FE) {
2312 self.validate_string_length_u8(src, dst.width())
2313 }
2314
2315 fn validate_string_length_u8(&mut self, s: &WasmString<'_>, dst: u8) {
2316 let mem_opts = match &s.opts.data_model {
2317 DataModel::Gc {} => todo!("CM+GC"),
2318 DataModel::LinearMemory(opts) => opts,
2319 };
2320
2321 self.instruction(LocalGet(s.len.idx));
2324 let max = MAX_STRING_BYTE_LENGTH / u32::from(dst);
2325 self.ptr_uconst(mem_opts, max);
2326 self.ptr_ge_u(mem_opts);
2327 self.instruction(If(BlockType::Empty));
2328 self.trap(Trap::StringLengthTooBig);
2329 self.instruction(End);
2330 }
2331
2332 fn transcoder(
2333 &mut self,
2334 src: &WasmString<'_>,
2335 dst: &WasmString<'_>,
2336 op: Transcode,
2337 ) -> FuncIndex {
2338 match (src.opts.data_model, dst.opts.data_model) {
2339 (DataModel::Gc {}, _) | (_, DataModel::Gc {}) => {
2340 todo!("CM+GC")
2341 }
2342 (
2343 DataModel::LinearMemory(LinearMemoryOptions {
2344 memory64: src64,
2345 memory: src_mem,
2346 realloc: _,
2347 }),
2348 DataModel::LinearMemory(LinearMemoryOptions {
2349 memory64: dst64,
2350 memory: dst_mem,
2351 realloc: _,
2352 }),
2353 ) => self.module.import_transcoder(Transcoder {
2354 from_memory: src_mem.unwrap(),
2355 from_memory64: src64,
2356 to_memory: dst_mem.unwrap(),
2357 to_memory64: dst64,
2358 op,
2359 }),
2360 }
2361 }
2362
2363 fn validate_string_inbounds(&mut self, s: &WasmString<'_>, byte_len: u32) {
2364 match &s.opts.data_model {
2365 DataModel::Gc {} => todo!("CM+GC"),
2366 DataModel::LinearMemory(opts) => {
2367 self.validate_memory_inbounds(opts, s.ptr.idx, byte_len, Trap::StringLengthOverflow)
2368 }
2369 }
2370 }
2371
2372 fn validate_memory_inbounds(
2373 &mut self,
2374 opts: &LinearMemoryOptions,
2375 ptr_local: u32,
2376 byte_len_local: u32,
2377 trap: Trap,
2378 ) {
2379 let extend_to_64 = |me: &mut Self| {
2380 if !opts.memory64 {
2381 me.instruction(I64ExtendI32U);
2382 }
2383 };
2384
2385 self.instruction(Block(BlockType::Empty));
2386 self.instruction(Block(BlockType::Empty));
2387
2388 self.instruction(MemorySize(opts.memory.unwrap().as_u32()));
2393 extend_to_64(self);
2394 self.instruction(I64Const(16));
2395 self.instruction(I64Shl);
2396
2397 self.instruction(LocalGet(ptr_local));
2402 extend_to_64(self);
2403 self.instruction(LocalGet(byte_len_local));
2404 extend_to_64(self);
2405 self.instruction(I64Add);
2406 if opts.memory64 {
2407 let tmp = self.local_tee_new_tmp(ValType::I64);
2408 self.instruction(LocalGet(ptr_local));
2409 self.ptr_lt_u(opts);
2410 self.instruction(BrIf(0));
2411 self.instruction(LocalGet(tmp.idx));
2412 self.free_temp_local(tmp);
2413 }
2414
2415 self.instruction(I64GeU);
2419 self.instruction(BrIf(1));
2420
2421 self.instruction(End);
2422 self.trap(trap);
2423 self.instruction(End);
2424 }
2425
2426 fn translate_list(
2427 &mut self,
2428 src_ty: TypeListIndex,
2429 src: &Source<'_>,
2430 dst_ty: &InterfaceType,
2431 dst: &Destination,
2432 ) {
2433 let src_mem_opts = match &src.opts().data_model {
2434 DataModel::Gc {} => todo!("CM+GC"),
2435 DataModel::LinearMemory(opts) => opts,
2436 };
2437 let dst_mem_opts = match &dst.opts().data_model {
2438 DataModel::Gc {} => todo!("CM+GC"),
2439 DataModel::LinearMemory(opts) => opts,
2440 };
2441
2442 let src_element_ty = &self.types[src_ty].element;
2443 let dst_element_ty = match dst_ty {
2444 InterfaceType::List(r) => &self.types[*r].element,
2445 _ => panic!("expected a list"),
2446 };
2447 let src_opts = src.opts();
2448 let dst_opts = dst.opts();
2449 let (src_size, src_align) = self.types.size_align(src_mem_opts, src_element_ty);
2450 let (dst_size, dst_align) = self.types.size_align(dst_mem_opts, dst_element_ty);
2451
2452 match src {
2457 Source::Stack(s) => {
2458 assert_eq!(s.locals.len(), 2);
2459 self.stack_get(&s.slice(0..1), src_mem_opts.ptr());
2460 self.stack_get(&s.slice(1..2), src_mem_opts.ptr());
2461 }
2462 Source::Memory(mem) => {
2463 self.ptr_load(mem);
2464 self.ptr_load(&mem.bump(src_mem_opts.ptr_size().into()));
2465 }
2466 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
2467 }
2468 let src_len = self.local_set_new_tmp(src_mem_opts.ptr());
2469 let src_ptr = self.local_set_new_tmp(src_mem_opts.ptr());
2470
2471 let src_mem = self.memory_operand(src_opts, src_ptr, src_align);
2474
2475 let src_byte_len = self.calculate_list_byte_len(src_mem_opts, src_len.idx, src_size);
2477 let dst_byte_len = if src_size == dst_size {
2478 self.convert_src_len_to_dst(src_byte_len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2479 self.local_set_new_tmp(dst_mem_opts.ptr())
2480 } else if src_mem_opts.ptr() == dst_mem_opts.ptr() {
2481 self.calculate_list_byte_len(dst_mem_opts, src_len.idx, dst_size)
2482 } else {
2483 self.convert_src_len_to_dst(src_byte_len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2484 let tmp = self.local_set_new_tmp(dst_mem_opts.ptr());
2485 let ret = self.calculate_list_byte_len(dst_mem_opts, tmp.idx, dst_size);
2486 self.free_temp_local(tmp);
2487 ret
2488 };
2489
2490 let dst_mem = self.malloc(dst_opts, MallocSize::Local(dst_byte_len.idx), dst_align);
2495
2496 self.validate_memory_inbounds(
2499 src_mem_opts,
2500 src_mem.addr.idx,
2501 src_byte_len.idx,
2502 Trap::ListByteLengthOverflow,
2503 );
2504 self.validate_memory_inbounds(
2505 dst_mem_opts,
2506 dst_mem.addr.idx,
2507 dst_byte_len.idx,
2508 Trap::ListByteLengthOverflow,
2509 );
2510
2511 self.free_temp_local(src_byte_len);
2512 self.free_temp_local(dst_byte_len);
2513
2514 if src_size > 0 || dst_size > 0 {
2518 self.instruction(Block(BlockType::Empty));
2521
2522 self.instruction(LocalGet(src_len.idx));
2524 let remaining = self.local_tee_new_tmp(src_mem_opts.ptr());
2525 self.ptr_eqz(src_mem_opts);
2526 self.instruction(BrIf(0));
2527
2528 self.instruction(LocalGet(src_mem.addr.idx));
2530 let cur_src_ptr = self.local_set_new_tmp(src_mem_opts.ptr());
2531 self.instruction(LocalGet(dst_mem.addr.idx));
2532 let cur_dst_ptr = self.local_set_new_tmp(dst_mem_opts.ptr());
2533
2534 self.instruction(Loop(BlockType::Empty));
2535
2536 let element_src = Source::Memory(Memory {
2538 opts: src_opts,
2539 offset: 0,
2540 addr: TempLocal::new(cur_src_ptr.idx, cur_src_ptr.ty),
2541 });
2542 let element_dst = Destination::Memory(Memory {
2543 opts: dst_opts,
2544 offset: 0,
2545 addr: TempLocal::new(cur_dst_ptr.idx, cur_dst_ptr.ty),
2546 });
2547 self.translate(src_element_ty, &element_src, dst_element_ty, &element_dst);
2548
2549 if src_size > 0 {
2551 self.instruction(LocalGet(cur_src_ptr.idx));
2552 self.ptr_uconst(src_mem_opts, src_size);
2553 self.ptr_add(src_mem_opts);
2554 self.instruction(LocalSet(cur_src_ptr.idx));
2555 }
2556 if dst_size > 0 {
2557 self.instruction(LocalGet(cur_dst_ptr.idx));
2558 self.ptr_uconst(dst_mem_opts, dst_size);
2559 self.ptr_add(dst_mem_opts);
2560 self.instruction(LocalSet(cur_dst_ptr.idx));
2561 }
2562
2563 self.instruction(LocalGet(remaining.idx));
2566 self.ptr_iconst(src_mem_opts, -1);
2567 self.ptr_add(src_mem_opts);
2568 self.instruction(LocalTee(remaining.idx));
2569 self.ptr_br_if(src_mem_opts, 0);
2570 self.instruction(End); self.instruction(End); self.free_temp_local(cur_dst_ptr);
2574 self.free_temp_local(cur_src_ptr);
2575 self.free_temp_local(remaining);
2576 }
2577
2578 match dst {
2580 Destination::Stack(s, _) => {
2581 self.instruction(LocalGet(dst_mem.addr.idx));
2582 self.stack_set(&s[..1], dst_mem_opts.ptr());
2583 self.convert_src_len_to_dst(src_len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2584 self.stack_set(&s[1..], dst_mem_opts.ptr());
2585 }
2586 Destination::Memory(mem) => {
2587 self.instruction(LocalGet(mem.addr.idx));
2588 self.instruction(LocalGet(dst_mem.addr.idx));
2589 self.ptr_store(mem);
2590 self.instruction(LocalGet(mem.addr.idx));
2591 self.convert_src_len_to_dst(src_len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2592 self.ptr_store(&mem.bump(dst_mem_opts.ptr_size().into()));
2593 }
2594 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
2595 }
2596
2597 self.free_temp_local(src_len);
2598 self.free_temp_local(src_mem.addr);
2599 self.free_temp_local(dst_mem.addr);
2600 }
2601
2602 fn calculate_list_byte_len(
2603 &mut self,
2604 opts: &LinearMemoryOptions,
2605 len_local: u32,
2606 elt_size: u32,
2607 ) -> TempLocal {
2608 if elt_size == 0 {
2611 self.ptr_uconst(opts, 0);
2612 return self.local_set_new_tmp(opts.ptr());
2613 }
2614
2615 if elt_size == 1 {
2623 if let ValType::I64 = opts.ptr() {
2624 self.instruction(LocalGet(len_local));
2625 self.instruction(I64Const(32));
2626 self.instruction(I64ShrU);
2627 self.instruction(I32WrapI64);
2628 self.instruction(If(BlockType::Empty));
2629 self.trap(Trap::ListByteLengthOverflow);
2630 self.instruction(End);
2631 }
2632 self.instruction(LocalGet(len_local));
2633 return self.local_set_new_tmp(opts.ptr());
2634 }
2635
2636 self.instruction(Block(BlockType::Empty));
2641 self.instruction(Block(BlockType::Empty));
2642 self.instruction(LocalGet(len_local));
2643 match opts.ptr() {
2644 ValType::I32 => self.instruction(I64ExtendI32U),
2648
2649 ValType::I64 => {
2653 self.instruction(I64Const(32));
2654 self.instruction(I64ShrU);
2655 self.instruction(I32WrapI64);
2656 self.instruction(BrIf(0));
2657 self.instruction(LocalGet(len_local));
2658 }
2659
2660 _ => unreachable!(),
2661 }
2662
2663 self.instruction(I64Const(elt_size.into()));
2672 self.instruction(I64Mul);
2673 let tmp = self.local_tee_new_tmp(ValType::I64);
2674 self.instruction(I64Const(32));
2677 self.instruction(I64ShrU);
2678 self.instruction(I64Eqz);
2679 self.instruction(BrIf(1));
2680 self.instruction(End);
2681 self.trap(Trap::ListByteLengthOverflow);
2682 self.instruction(End);
2683
2684 if opts.ptr() == ValType::I64 {
2688 tmp
2689 } else {
2690 self.instruction(LocalGet(tmp.idx));
2691 self.instruction(I32WrapI64);
2692 self.free_temp_local(tmp);
2693 self.local_set_new_tmp(ValType::I32)
2694 }
2695 }
2696
2697 fn convert_src_len_to_dst(
2698 &mut self,
2699 src_len_local: u32,
2700 src_ptr_ty: ValType,
2701 dst_ptr_ty: ValType,
2702 ) {
2703 self.instruction(LocalGet(src_len_local));
2704 match (src_ptr_ty, dst_ptr_ty) {
2705 (ValType::I32, ValType::I64) => self.instruction(I64ExtendI32U),
2706 (ValType::I64, ValType::I32) => self.instruction(I32WrapI64),
2707 (src, dst) => assert_eq!(src, dst),
2708 }
2709 }
2710
2711 fn translate_record(
2712 &mut self,
2713 src_ty: TypeRecordIndex,
2714 src: &Source<'_>,
2715 dst_ty: &InterfaceType,
2716 dst: &Destination,
2717 ) {
2718 let src_ty = &self.types[src_ty];
2719 let dst_ty = match dst_ty {
2720 InterfaceType::Record(r) => &self.types[*r],
2721 _ => panic!("expected a record"),
2722 };
2723
2724 assert_eq!(src_ty.fields.len(), dst_ty.fields.len());
2726
2727 let mut src_fields = HashMap::new();
2731 for (i, src) in src
2732 .record_field_srcs(self.types, src_ty.fields.iter().map(|f| f.ty))
2733 .enumerate()
2734 {
2735 let field = &src_ty.fields[i];
2736 src_fields.insert(&field.name, (src, &field.ty));
2737 }
2738
2739 for (i, dst) in dst
2748 .record_field_dsts(self.types, dst_ty.fields.iter().map(|f| f.ty))
2749 .enumerate()
2750 {
2751 let field = &dst_ty.fields[i];
2752 let (src, src_ty) = &src_fields[&field.name];
2753 self.translate(src_ty, src, &field.ty, &dst);
2754 }
2755 }
2756
2757 fn translate_flags(
2758 &mut self,
2759 src_ty: TypeFlagsIndex,
2760 src: &Source<'_>,
2761 dst_ty: &InterfaceType,
2762 dst: &Destination,
2763 ) {
2764 let src_ty = &self.types[src_ty];
2765 let dst_ty = match dst_ty {
2766 InterfaceType::Flags(r) => &self.types[*r],
2767 _ => panic!("expected a record"),
2768 };
2769
2770 assert_eq!(src_ty.names, dst_ty.names);
2778 let cnt = src_ty.names.len();
2779 match FlagsSize::from_count(cnt) {
2780 FlagsSize::Size0 => {}
2781 FlagsSize::Size1 => {
2782 let mask = if cnt == 8 { 0xff } else { (1 << cnt) - 1 };
2783 self.convert_u8_mask(src, dst, mask);
2784 }
2785 FlagsSize::Size2 => {
2786 let mask = if cnt == 16 { 0xffff } else { (1 << cnt) - 1 };
2787 self.convert_u16_mask(src, dst, mask);
2788 }
2789 FlagsSize::Size4Plus(n) => {
2790 let srcs = src.record_field_srcs(self.types, (0..n).map(|_| InterfaceType::U32));
2791 let dsts = dst.record_field_dsts(self.types, (0..n).map(|_| InterfaceType::U32));
2792 let n = usize::from(n);
2793 for (i, (src, dst)) in srcs.zip(dsts).enumerate() {
2794 let mask = if i == n - 1 && (cnt % 32 != 0) {
2795 (1 << (cnt % 32)) - 1
2796 } else {
2797 0xffffffff
2798 };
2799 self.convert_u32_mask(&src, &dst, mask);
2800 }
2801 }
2802 }
2803 }
2804
2805 fn translate_tuple(
2806 &mut self,
2807 src_ty: TypeTupleIndex,
2808 src: &Source<'_>,
2809 dst_ty: &InterfaceType,
2810 dst: &Destination,
2811 ) {
2812 let src_ty = &self.types[src_ty];
2813 let dst_ty = match dst_ty {
2814 InterfaceType::Tuple(t) => &self.types[*t],
2815 _ => panic!("expected a tuple"),
2816 };
2817
2818 assert_eq!(src_ty.types.len(), dst_ty.types.len());
2820
2821 let srcs = src
2822 .record_field_srcs(self.types, src_ty.types.iter().copied())
2823 .zip(src_ty.types.iter());
2824 let dsts = dst
2825 .record_field_dsts(self.types, dst_ty.types.iter().copied())
2826 .zip(dst_ty.types.iter());
2827 for ((src, src_ty), (dst, dst_ty)) in srcs.zip(dsts) {
2828 self.translate(src_ty, &src, dst_ty, &dst);
2829 }
2830 }
2831
2832 fn translate_variant(
2833 &mut self,
2834 src_ty: TypeVariantIndex,
2835 src: &Source<'_>,
2836 dst_ty: &InterfaceType,
2837 dst: &Destination,
2838 ) {
2839 let src_ty = &self.types[src_ty];
2840 let dst_ty = match dst_ty {
2841 InterfaceType::Variant(t) => &self.types[*t],
2842 _ => panic!("expected a variant"),
2843 };
2844
2845 let src_info = variant_info(self.types, src_ty.cases.iter().map(|(_, c)| c.as_ref()));
2846 let dst_info = variant_info(self.types, dst_ty.cases.iter().map(|(_, c)| c.as_ref()));
2847
2848 let iter = src_ty
2849 .cases
2850 .iter()
2851 .enumerate()
2852 .map(|(src_i, (src_case, src_case_ty))| {
2853 let dst_i = dst_ty
2854 .cases
2855 .iter()
2856 .position(|(c, _)| c == src_case)
2857 .unwrap();
2858 let dst_case_ty = &dst_ty.cases[dst_i];
2859 let src_i = u32::try_from(src_i).unwrap();
2860 let dst_i = u32::try_from(dst_i).unwrap();
2861 VariantCase {
2862 src_i,
2863 src_ty: src_case_ty.as_ref(),
2864 dst_i,
2865 dst_ty: dst_case_ty.as_ref(),
2866 }
2867 });
2868 self.convert_variant(src, &src_info, dst, &dst_info, iter);
2869 }
2870
2871 fn translate_enum(
2872 &mut self,
2873 src_ty: TypeEnumIndex,
2874 src: &Source<'_>,
2875 dst_ty: &InterfaceType,
2876 dst: &Destination,
2877 ) {
2878 let src_ty = &self.types[src_ty];
2879 let dst_ty = match dst_ty {
2880 InterfaceType::Enum(t) => &self.types[*t],
2881 _ => panic!("expected an option"),
2882 };
2883
2884 debug_assert_eq!(src_ty.info.size, dst_ty.info.size);
2885 debug_assert_eq!(src_ty.names.len(), dst_ty.names.len());
2886 debug_assert!(
2887 src_ty
2888 .names
2889 .iter()
2890 .zip(dst_ty.names.iter())
2891 .all(|(a, b)| a == b)
2892 );
2893
2894 match src {
2896 Source::Stack(s) => self.stack_get(&s.slice(0..1), ValType::I32),
2897 Source::Memory(mem) => match src_ty.info.size {
2898 DiscriminantSize::Size1 => self.i32_load8u(mem),
2899 DiscriminantSize::Size2 => self.i32_load16u(mem),
2900 DiscriminantSize::Size4 => self.i32_load(mem),
2901 },
2902 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
2903 }
2904 let tmp = self.local_tee_new_tmp(ValType::I32);
2905
2906 self.instruction(I32Const(i32::try_from(src_ty.names.len()).unwrap()));
2908 self.instruction(I32GtU);
2909 self.instruction(If(BlockType::Empty));
2910 self.trap(Trap::InvalidDiscriminant);
2911 self.instruction(End);
2912
2913 match dst {
2915 Destination::Stack(stack, _) => {
2916 self.local_get_tmp(&tmp);
2917 self.stack_set(&stack[..1], ValType::I32)
2918 }
2919 Destination::Memory(mem) => {
2920 self.push_dst_addr(dst);
2921 self.local_get_tmp(&tmp);
2922 match dst_ty.info.size {
2923 DiscriminantSize::Size1 => self.i32_store8(mem),
2924 DiscriminantSize::Size2 => self.i32_store16(mem),
2925 DiscriminantSize::Size4 => self.i32_store(mem),
2926 }
2927 }
2928 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
2929 }
2930 self.free_temp_local(tmp);
2931 }
2932
2933 fn translate_option(
2934 &mut self,
2935 src_ty: TypeOptionIndex,
2936 src: &Source<'_>,
2937 dst_ty: &InterfaceType,
2938 dst: &Destination,
2939 ) {
2940 let src_ty = &self.types[src_ty].ty;
2941 let dst_ty = match dst_ty {
2942 InterfaceType::Option(t) => &self.types[*t].ty,
2943 _ => panic!("expected an option"),
2944 };
2945 let src_ty = Some(src_ty);
2946 let dst_ty = Some(dst_ty);
2947
2948 let src_info = variant_info(self.types, [None, src_ty]);
2949 let dst_info = variant_info(self.types, [None, dst_ty]);
2950
2951 self.convert_variant(
2952 src,
2953 &src_info,
2954 dst,
2955 &dst_info,
2956 [
2957 VariantCase {
2958 src_i: 0,
2959 dst_i: 0,
2960 src_ty: None,
2961 dst_ty: None,
2962 },
2963 VariantCase {
2964 src_i: 1,
2965 dst_i: 1,
2966 src_ty,
2967 dst_ty,
2968 },
2969 ]
2970 .into_iter(),
2971 );
2972 }
2973
2974 fn translate_result(
2975 &mut self,
2976 src_ty: TypeResultIndex,
2977 src: &Source<'_>,
2978 dst_ty: &InterfaceType,
2979 dst: &Destination,
2980 ) {
2981 let src_ty = &self.types[src_ty];
2982 let dst_ty = match dst_ty {
2983 InterfaceType::Result(t) => &self.types[*t],
2984 _ => panic!("expected a result"),
2985 };
2986
2987 let src_info = variant_info(self.types, [src_ty.ok.as_ref(), src_ty.err.as_ref()]);
2988 let dst_info = variant_info(self.types, [dst_ty.ok.as_ref(), dst_ty.err.as_ref()]);
2989
2990 self.convert_variant(
2991 src,
2992 &src_info,
2993 dst,
2994 &dst_info,
2995 [
2996 VariantCase {
2997 src_i: 0,
2998 dst_i: 0,
2999 src_ty: src_ty.ok.as_ref(),
3000 dst_ty: dst_ty.ok.as_ref(),
3001 },
3002 VariantCase {
3003 src_i: 1,
3004 dst_i: 1,
3005 src_ty: src_ty.err.as_ref(),
3006 dst_ty: dst_ty.err.as_ref(),
3007 },
3008 ]
3009 .into_iter(),
3010 );
3011 }
3012
3013 fn convert_variant<'c>(
3014 &mut self,
3015 src: &Source<'_>,
3016 src_info: &VariantInfo,
3017 dst: &Destination,
3018 dst_info: &VariantInfo,
3019 src_cases: impl ExactSizeIterator<Item = VariantCase<'c>>,
3020 ) {
3021 let outer_block_ty = match dst {
3024 Destination::Stack(dst_flat, _) => match dst_flat.len() {
3025 0 => BlockType::Empty,
3026 1 => BlockType::Result(dst_flat[0]),
3027 _ => {
3028 let ty = self.module.core_types.function(&[], &dst_flat);
3029 BlockType::FunctionType(ty)
3030 }
3031 },
3032 Destination::Memory(_) => BlockType::Empty,
3033 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
3034 };
3035 self.instruction(Block(outer_block_ty));
3036
3037 let src_cases_len = src_cases.len();
3040 for _ in 0..src_cases_len - 1 {
3041 self.instruction(Block(BlockType::Empty));
3042 }
3043
3044 self.instruction(Block(BlockType::Empty));
3046
3047 self.instruction(Block(BlockType::Empty));
3050
3051 match src {
3053 Source::Stack(s) => self.stack_get(&s.slice(0..1), ValType::I32),
3054 Source::Memory(mem) => match src_info.size {
3055 DiscriminantSize::Size1 => self.i32_load8u(mem),
3056 DiscriminantSize::Size2 => self.i32_load16u(mem),
3057 DiscriminantSize::Size4 => self.i32_load(mem),
3058 },
3059 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
3060 }
3061
3062 let mut targets = Vec::new();
3065 for i in 0..src_cases_len {
3066 targets.push((i + 1) as u32);
3067 }
3068 self.instruction(BrTable(targets[..].into(), 0));
3069 self.instruction(End); self.trap(Trap::InvalidDiscriminant);
3072 self.instruction(End); let src_cases_len = u32::try_from(src_cases_len).unwrap();
3079 for case in src_cases {
3080 let VariantCase {
3081 src_i,
3082 src_ty,
3083 dst_i,
3084 dst_ty,
3085 } = case;
3086
3087 self.push_dst_addr(dst);
3090 self.instruction(I32Const(dst_i as i32));
3091 match dst {
3092 Destination::Stack(stack, _) => self.stack_set(&stack[..1], ValType::I32),
3093 Destination::Memory(mem) => match dst_info.size {
3094 DiscriminantSize::Size1 => self.i32_store8(mem),
3095 DiscriminantSize::Size2 => self.i32_store16(mem),
3096 DiscriminantSize::Size4 => self.i32_store(mem),
3097 },
3098 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
3099 }
3100
3101 let src_payload = src.payload_src(self.types, src_info, src_ty);
3102 let dst_payload = dst.payload_dst(self.types, dst_info, dst_ty);
3103
3104 match (src_ty, dst_ty) {
3107 (Some(src_ty), Some(dst_ty)) => {
3108 self.translate(src_ty, &src_payload, dst_ty, &dst_payload);
3109 }
3110 (None, None) => {}
3111 _ => unimplemented!(),
3112 }
3113
3114 if let Destination::Stack(payload_results, _) = dst_payload {
3121 if let Destination::Stack(dst_results, _) = dst {
3122 let remaining = &dst_results[1..][payload_results.len()..];
3123 for ty in remaining {
3124 match ty {
3125 ValType::I32 => self.instruction(I32Const(0)),
3126 ValType::I64 => self.instruction(I64Const(0)),
3127 ValType::F32 => self.instruction(F32Const(0.0.into())),
3128 ValType::F64 => self.instruction(F64Const(0.0.into())),
3129 _ => unreachable!(),
3130 }
3131 }
3132 }
3133 }
3134
3135 if src_i != src_cases_len - 1 {
3138 self.instruction(Br(src_cases_len - src_i - 1));
3139 }
3140 self.instruction(End); }
3142 }
3143
3144 fn translate_future(
3145 &mut self,
3146 src_ty: TypeFutureTableIndex,
3147 src: &Source<'_>,
3148 dst_ty: &InterfaceType,
3149 dst: &Destination,
3150 ) {
3151 let dst_ty = match dst_ty {
3152 InterfaceType::Future(t) => *t,
3153 _ => panic!("expected a `Future`"),
3154 };
3155 let transfer = self.module.import_future_transfer();
3156 self.translate_handle(src_ty.as_u32(), src, dst_ty.as_u32(), dst, transfer);
3157 }
3158
3159 fn translate_stream(
3160 &mut self,
3161 src_ty: TypeStreamTableIndex,
3162 src: &Source<'_>,
3163 dst_ty: &InterfaceType,
3164 dst: &Destination,
3165 ) {
3166 let dst_ty = match dst_ty {
3167 InterfaceType::Stream(t) => *t,
3168 _ => panic!("expected a `Stream`"),
3169 };
3170 let transfer = self.module.import_stream_transfer();
3171 self.translate_handle(src_ty.as_u32(), src, dst_ty.as_u32(), dst, transfer);
3172 }
3173
3174 fn translate_error_context(
3175 &mut self,
3176 src_ty: TypeComponentLocalErrorContextTableIndex,
3177 src: &Source<'_>,
3178 dst_ty: &InterfaceType,
3179 dst: &Destination,
3180 ) {
3181 let dst_ty = match dst_ty {
3182 InterfaceType::ErrorContext(t) => *t,
3183 _ => panic!("expected an `ErrorContext`"),
3184 };
3185 let transfer = self.module.import_error_context_transfer();
3186 self.translate_handle(src_ty.as_u32(), src, dst_ty.as_u32(), dst, transfer);
3187 }
3188
3189 fn translate_own(
3190 &mut self,
3191 src_ty: TypeResourceTableIndex,
3192 src: &Source<'_>,
3193 dst_ty: &InterfaceType,
3194 dst: &Destination,
3195 ) {
3196 let dst_ty = match dst_ty {
3197 InterfaceType::Own(t) => *t,
3198 _ => panic!("expected an `Own`"),
3199 };
3200 let transfer = self.module.import_resource_transfer_own();
3201 self.translate_handle(src_ty.as_u32(), src, dst_ty.as_u32(), dst, transfer);
3202 }
3203
3204 fn translate_borrow(
3205 &mut self,
3206 src_ty: TypeResourceTableIndex,
3207 src: &Source<'_>,
3208 dst_ty: &InterfaceType,
3209 dst: &Destination,
3210 ) {
3211 let dst_ty = match dst_ty {
3212 InterfaceType::Borrow(t) => *t,
3213 _ => panic!("expected an `Borrow`"),
3214 };
3215
3216 let transfer = self.module.import_resource_transfer_borrow();
3217 self.translate_handle(src_ty.as_u32(), src, dst_ty.as_u32(), dst, transfer);
3218 }
3219
3220 fn translate_handle(
3228 &mut self,
3229 src_ty: u32,
3230 src: &Source<'_>,
3231 dst_ty: u32,
3232 dst: &Destination,
3233 transfer: FuncIndex,
3234 ) {
3235 self.push_dst_addr(dst);
3236 match src {
3237 Source::Memory(mem) => self.i32_load(mem),
3238 Source::Stack(stack) => self.stack_get(stack, ValType::I32),
3239 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
3240 }
3241 self.instruction(I32Const(src_ty as i32));
3242 self.instruction(I32Const(dst_ty as i32));
3243 self.instruction(Call(transfer.as_u32()));
3244 match dst {
3245 Destination::Memory(mem) => self.i32_store(mem),
3246 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
3247 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
3248 }
3249 }
3250
3251 fn trap_if_not_flag(&mut self, flags_global: GlobalIndex, flag_to_test: i32, trap: Trap) {
3252 self.instruction(GlobalGet(flags_global.as_u32()));
3253 self.instruction(I32Const(flag_to_test));
3254 self.instruction(I32And);
3255 self.instruction(I32Eqz);
3256 self.instruction(If(BlockType::Empty));
3257 self.trap(trap);
3258 self.instruction(End);
3259 }
3260
3261 fn assert_not_flag(&mut self, flags_global: GlobalIndex, flag_to_test: i32, msg: &'static str) {
3262 self.instruction(GlobalGet(flags_global.as_u32()));
3263 self.instruction(I32Const(flag_to_test));
3264 self.instruction(I32And);
3265 self.instruction(If(BlockType::Empty));
3266 self.trap(Trap::AssertFailed(msg));
3267 self.instruction(End);
3268 }
3269
3270 fn set_flag(&mut self, flags_global: GlobalIndex, flag_to_set: i32, value: bool) {
3271 self.instruction(GlobalGet(flags_global.as_u32()));
3272 if value {
3273 self.instruction(I32Const(flag_to_set));
3274 self.instruction(I32Or);
3275 } else {
3276 self.instruction(I32Const(!flag_to_set));
3277 self.instruction(I32And);
3278 }
3279 self.instruction(GlobalSet(flags_global.as_u32()));
3280 }
3281
3282 fn verify_aligned(&mut self, opts: &LinearMemoryOptions, addr_local: u32, align: u32) {
3283 if align == 1 {
3286 return;
3287 }
3288 self.instruction(LocalGet(addr_local));
3289 assert!(align.is_power_of_two());
3290 self.ptr_uconst(opts, align - 1);
3291 self.ptr_and(opts);
3292 self.ptr_if(opts, BlockType::Empty);
3293 self.trap(Trap::UnalignedPointer);
3294 self.instruction(End);
3295 }
3296
3297 fn assert_aligned(&mut self, ty: &InterfaceType, mem: &Memory) {
3298 let mem_opts = mem.mem_opts();
3299 if !self.module.debug {
3300 return;
3301 }
3302 let align = self.types.align(mem_opts, ty);
3303 if align == 1 {
3304 return;
3305 }
3306 assert!(align.is_power_of_two());
3307 self.instruction(LocalGet(mem.addr.idx));
3308 self.ptr_uconst(mem_opts, mem.offset);
3309 self.ptr_add(mem_opts);
3310 self.ptr_uconst(mem_opts, align - 1);
3311 self.ptr_and(mem_opts);
3312 self.ptr_if(mem_opts, BlockType::Empty);
3313 self.trap(Trap::AssertFailed("pointer not aligned"));
3314 self.instruction(End);
3315 }
3316
3317 fn malloc<'c>(&mut self, opts: &'c Options, size: MallocSize, align: u32) -> Memory<'c> {
3318 match &opts.data_model {
3319 DataModel::Gc {} => todo!("CM+GC"),
3320 DataModel::LinearMemory(mem_opts) => {
3321 let realloc = mem_opts.realloc.unwrap();
3322 self.ptr_uconst(mem_opts, 0);
3323 self.ptr_uconst(mem_opts, 0);
3324 self.ptr_uconst(mem_opts, align);
3325 match size {
3326 MallocSize::Const(size) => self.ptr_uconst(mem_opts, size),
3327 MallocSize::Local(idx) => self.instruction(LocalGet(idx)),
3328 }
3329 self.instruction(Call(realloc.as_u32()));
3330 let addr = self.local_set_new_tmp(mem_opts.ptr());
3331 self.memory_operand(opts, addr, align)
3332 }
3333 }
3334 }
3335
3336 fn memory_operand<'c>(&mut self, opts: &'c Options, addr: TempLocal, align: u32) -> Memory<'c> {
3337 let ret = Memory {
3338 addr,
3339 offset: 0,
3340 opts,
3341 };
3342 self.verify_aligned(opts.data_model.unwrap_memory(), ret.addr.idx, align);
3343 ret
3344 }
3345
3346 fn local_tee_new_tmp(&mut self, ty: ValType) -> TempLocal {
3352 self.gen_temp_local(ty, LocalTee)
3353 }
3354
3355 fn local_set_new_tmp(&mut self, ty: ValType) -> TempLocal {
3358 self.gen_temp_local(ty, LocalSet)
3359 }
3360
3361 fn local_get_tmp(&mut self, local: &TempLocal) {
3362 self.instruction(LocalGet(local.idx));
3363 }
3364
3365 fn gen_temp_local(&mut self, ty: ValType, insn: fn(u32) -> Instruction<'static>) -> TempLocal {
3366 if let Some(idx) = self.free_locals.get_mut(&ty).and_then(|v| v.pop()) {
3369 self.instruction(insn(idx));
3370 return TempLocal {
3371 ty,
3372 idx,
3373 needs_free: true,
3374 };
3375 }
3376
3377 let locals = &mut self.module.funcs[self.result].locals;
3379 match locals.last_mut() {
3380 Some((cnt, prev_ty)) if ty == *prev_ty => *cnt += 1,
3381 _ => locals.push((1, ty)),
3382 }
3383 self.nlocals += 1;
3384 let idx = self.nlocals - 1;
3385 self.instruction(insn(idx));
3386 TempLocal {
3387 ty,
3388 idx,
3389 needs_free: true,
3390 }
3391 }
3392
3393 fn free_temp_local(&mut self, mut local: TempLocal) {
3396 assert!(local.needs_free);
3397 self.free_locals
3398 .entry(local.ty)
3399 .or_insert(Vec::new())
3400 .push(local.idx);
3401 local.needs_free = false;
3402 }
3403
3404 fn instruction(&mut self, instr: Instruction) {
3405 instr.encode(&mut self.code);
3406 }
3407
3408 fn trap(&mut self, trap: Trap) {
3409 self.traps.push((self.code.len(), trap));
3410 self.instruction(Unreachable);
3411 }
3412
3413 fn flush_code(&mut self) {
3418 if self.code.is_empty() {
3419 return;
3420 }
3421 self.module.funcs[self.result].body.push(Body::Raw(
3422 mem::take(&mut self.code),
3423 mem::take(&mut self.traps),
3424 ));
3425 }
3426
3427 fn finish(mut self) {
3428 self.instruction(End);
3431 self.flush_code();
3432
3433 self.module.funcs[self.result].filled_in = true;
3436 }
3437
3438 fn stack_get(&mut self, stack: &Stack<'_>, dst_ty: ValType) {
3446 assert_eq!(stack.locals.len(), 1);
3447 let (idx, src_ty) = stack.locals[0];
3448 self.instruction(LocalGet(idx));
3449 match (src_ty, dst_ty) {
3450 (ValType::I32, ValType::I32)
3451 | (ValType::I64, ValType::I64)
3452 | (ValType::F32, ValType::F32)
3453 | (ValType::F64, ValType::F64) => {}
3454
3455 (ValType::I32, ValType::F32) => self.instruction(F32ReinterpretI32),
3456 (ValType::I64, ValType::I32) => {
3457 self.assert_i64_upper_bits_not_set(idx);
3458 self.instruction(I32WrapI64);
3459 }
3460 (ValType::I64, ValType::F64) => self.instruction(F64ReinterpretI64),
3461 (ValType::I64, ValType::F32) => {
3462 self.assert_i64_upper_bits_not_set(idx);
3463 self.instruction(I32WrapI64);
3464 self.instruction(F32ReinterpretI32);
3465 }
3466
3467 (ValType::I32, ValType::I64)
3469 | (ValType::I32, ValType::F64)
3470 | (ValType::F32, ValType::I32)
3471 | (ValType::F32, ValType::I64)
3472 | (ValType::F32, ValType::F64)
3473 | (ValType::F64, ValType::I32)
3474 | (ValType::F64, ValType::I64)
3475 | (ValType::F64, ValType::F32)
3476
3477 | (ValType::Ref(_), _)
3479 | (_, ValType::Ref(_))
3480 | (ValType::V128, _)
3481 | (_, ValType::V128) => {
3482 panic!("cannot get {dst_ty:?} from {src_ty:?} local");
3483 }
3484 }
3485 }
3486
3487 fn assert_i64_upper_bits_not_set(&mut self, local: u32) {
3488 if !self.module.debug {
3489 return;
3490 }
3491 self.instruction(LocalGet(local));
3492 self.instruction(I64Const(32));
3493 self.instruction(I64ShrU);
3494 self.instruction(I32WrapI64);
3495 self.instruction(If(BlockType::Empty));
3496 self.trap(Trap::AssertFailed("upper bits are unexpectedly set"));
3497 self.instruction(End);
3498 }
3499
3500 fn stack_set(&mut self, dst_tys: &[ValType], src_ty: ValType) {
3506 assert_eq!(dst_tys.len(), 1);
3507 let dst_ty = dst_tys[0];
3508 match (src_ty, dst_ty) {
3509 (ValType::I32, ValType::I32)
3510 | (ValType::I64, ValType::I64)
3511 | (ValType::F32, ValType::F32)
3512 | (ValType::F64, ValType::F64) => {}
3513
3514 (ValType::F32, ValType::I32) => self.instruction(I32ReinterpretF32),
3515 (ValType::I32, ValType::I64) => self.instruction(I64ExtendI32U),
3516 (ValType::F64, ValType::I64) => self.instruction(I64ReinterpretF64),
3517 (ValType::F32, ValType::I64) => {
3518 self.instruction(I32ReinterpretF32);
3519 self.instruction(I64ExtendI32U);
3520 }
3521
3522 (ValType::I64, ValType::I32)
3524 | (ValType::F64, ValType::I32)
3525 | (ValType::I32, ValType::F32)
3526 | (ValType::I64, ValType::F32)
3527 | (ValType::F64, ValType::F32)
3528 | (ValType::I32, ValType::F64)
3529 | (ValType::I64, ValType::F64)
3530 | (ValType::F32, ValType::F64)
3531
3532 | (ValType::Ref(_), _)
3534 | (_, ValType::Ref(_))
3535 | (ValType::V128, _)
3536 | (_, ValType::V128) => {
3537 panic!("cannot get {dst_ty:?} from {src_ty:?} local");
3538 }
3539 }
3540 }
3541
3542 fn i32_load8u(&mut self, mem: &Memory) {
3543 self.instruction(LocalGet(mem.addr.idx));
3544 self.instruction(I32Load8U(mem.memarg(0)));
3545 }
3546
3547 fn i32_load8s(&mut self, mem: &Memory) {
3548 self.instruction(LocalGet(mem.addr.idx));
3549 self.instruction(I32Load8S(mem.memarg(0)));
3550 }
3551
3552 fn i32_load16u(&mut self, mem: &Memory) {
3553 self.instruction(LocalGet(mem.addr.idx));
3554 self.instruction(I32Load16U(mem.memarg(1)));
3555 }
3556
3557 fn i32_load16s(&mut self, mem: &Memory) {
3558 self.instruction(LocalGet(mem.addr.idx));
3559 self.instruction(I32Load16S(mem.memarg(1)));
3560 }
3561
3562 fn i32_load(&mut self, mem: &Memory) {
3563 self.instruction(LocalGet(mem.addr.idx));
3564 self.instruction(I32Load(mem.memarg(2)));
3565 }
3566
3567 fn i64_load(&mut self, mem: &Memory) {
3568 self.instruction(LocalGet(mem.addr.idx));
3569 self.instruction(I64Load(mem.memarg(3)));
3570 }
3571
3572 fn ptr_load(&mut self, mem: &Memory) {
3573 if mem.mem_opts().memory64 {
3574 self.i64_load(mem);
3575 } else {
3576 self.i32_load(mem);
3577 }
3578 }
3579
3580 fn ptr_add(&mut self, opts: &LinearMemoryOptions) {
3581 if opts.memory64 {
3582 self.instruction(I64Add);
3583 } else {
3584 self.instruction(I32Add);
3585 }
3586 }
3587
3588 fn ptr_sub(&mut self, opts: &LinearMemoryOptions) {
3589 if opts.memory64 {
3590 self.instruction(I64Sub);
3591 } else {
3592 self.instruction(I32Sub);
3593 }
3594 }
3595
3596 fn ptr_mul(&mut self, opts: &LinearMemoryOptions) {
3597 if opts.memory64 {
3598 self.instruction(I64Mul);
3599 } else {
3600 self.instruction(I32Mul);
3601 }
3602 }
3603
3604 fn ptr_ge_u(&mut self, opts: &LinearMemoryOptions) {
3605 if opts.memory64 {
3606 self.instruction(I64GeU);
3607 } else {
3608 self.instruction(I32GeU);
3609 }
3610 }
3611
3612 fn ptr_lt_u(&mut self, opts: &LinearMemoryOptions) {
3613 if opts.memory64 {
3614 self.instruction(I64LtU);
3615 } else {
3616 self.instruction(I32LtU);
3617 }
3618 }
3619
3620 fn ptr_shl(&mut self, opts: &LinearMemoryOptions) {
3621 if opts.memory64 {
3622 self.instruction(I64Shl);
3623 } else {
3624 self.instruction(I32Shl);
3625 }
3626 }
3627
3628 fn ptr_eqz(&mut self, opts: &LinearMemoryOptions) {
3629 if opts.memory64 {
3630 self.instruction(I64Eqz);
3631 } else {
3632 self.instruction(I32Eqz);
3633 }
3634 }
3635
3636 fn ptr_uconst(&mut self, opts: &LinearMemoryOptions, val: u32) {
3637 if opts.memory64 {
3638 self.instruction(I64Const(val.into()));
3639 } else {
3640 self.instruction(I32Const(val as i32));
3641 }
3642 }
3643
3644 fn ptr_iconst(&mut self, opts: &LinearMemoryOptions, val: i32) {
3645 if opts.memory64 {
3646 self.instruction(I64Const(val.into()));
3647 } else {
3648 self.instruction(I32Const(val));
3649 }
3650 }
3651
3652 fn ptr_eq(&mut self, opts: &LinearMemoryOptions) {
3653 if opts.memory64 {
3654 self.instruction(I64Eq);
3655 } else {
3656 self.instruction(I32Eq);
3657 }
3658 }
3659
3660 fn ptr_ne(&mut self, opts: &LinearMemoryOptions) {
3661 if opts.memory64 {
3662 self.instruction(I64Ne);
3663 } else {
3664 self.instruction(I32Ne);
3665 }
3666 }
3667
3668 fn ptr_and(&mut self, opts: &LinearMemoryOptions) {
3669 if opts.memory64 {
3670 self.instruction(I64And);
3671 } else {
3672 self.instruction(I32And);
3673 }
3674 }
3675
3676 fn ptr_or(&mut self, opts: &LinearMemoryOptions) {
3677 if opts.memory64 {
3678 self.instruction(I64Or);
3679 } else {
3680 self.instruction(I32Or);
3681 }
3682 }
3683
3684 fn ptr_xor(&mut self, opts: &LinearMemoryOptions) {
3685 if opts.memory64 {
3686 self.instruction(I64Xor);
3687 } else {
3688 self.instruction(I32Xor);
3689 }
3690 }
3691
3692 fn ptr_if(&mut self, opts: &LinearMemoryOptions, ty: BlockType) {
3693 if opts.memory64 {
3694 self.instruction(I64Const(0));
3695 self.instruction(I64Ne);
3696 }
3697 self.instruction(If(ty));
3698 }
3699
3700 fn ptr_br_if(&mut self, opts: &LinearMemoryOptions, depth: u32) {
3701 if opts.memory64 {
3702 self.instruction(I64Const(0));
3703 self.instruction(I64Ne);
3704 }
3705 self.instruction(BrIf(depth));
3706 }
3707
3708 fn f32_load(&mut self, mem: &Memory) {
3709 self.instruction(LocalGet(mem.addr.idx));
3710 self.instruction(F32Load(mem.memarg(2)));
3711 }
3712
3713 fn f64_load(&mut self, mem: &Memory) {
3714 self.instruction(LocalGet(mem.addr.idx));
3715 self.instruction(F64Load(mem.memarg(3)));
3716 }
3717
3718 fn push_dst_addr(&mut self, dst: &Destination) {
3719 if let Destination::Memory(mem) = dst {
3720 self.instruction(LocalGet(mem.addr.idx));
3721 }
3722 }
3723
3724 fn i32_store8(&mut self, mem: &Memory) {
3725 self.instruction(I32Store8(mem.memarg(0)));
3726 }
3727
3728 fn i32_store16(&mut self, mem: &Memory) {
3729 self.instruction(I32Store16(mem.memarg(1)));
3730 }
3731
3732 fn i32_store(&mut self, mem: &Memory) {
3733 self.instruction(I32Store(mem.memarg(2)));
3734 }
3735
3736 fn i64_store(&mut self, mem: &Memory) {
3737 self.instruction(I64Store(mem.memarg(3)));
3738 }
3739
3740 fn ptr_store(&mut self, mem: &Memory) {
3741 if mem.mem_opts().memory64 {
3742 self.i64_store(mem);
3743 } else {
3744 self.i32_store(mem);
3745 }
3746 }
3747
3748 fn f32_store(&mut self, mem: &Memory) {
3749 self.instruction(F32Store(mem.memarg(2)));
3750 }
3751
3752 fn f64_store(&mut self, mem: &Memory) {
3753 self.instruction(F64Store(mem.memarg(3)));
3754 }
3755}
3756
3757impl<'a> Source<'a> {
3758 fn record_field_srcs<'b>(
3765 &'b self,
3766 types: &'b ComponentTypesBuilder,
3767 fields: impl IntoIterator<Item = InterfaceType> + 'b,
3768 ) -> impl Iterator<Item = Source<'a>> + 'b
3769 where
3770 'a: 'b,
3771 {
3772 let mut offset = 0;
3773 fields.into_iter().map(move |ty| match self {
3774 Source::Memory(mem) => {
3775 let mem = next_field_offset(&mut offset, types, &ty, mem);
3776 Source::Memory(mem)
3777 }
3778 Source::Stack(stack) => {
3779 let cnt = types.flat_types(&ty).unwrap().len() as u32;
3780 offset += cnt;
3781 Source::Stack(stack.slice((offset - cnt) as usize..offset as usize))
3782 }
3783 Source::Struct(_) => todo!(),
3784 Source::Array(_) => todo!(),
3785 })
3786 }
3787
3788 fn payload_src(
3790 &self,
3791 types: &ComponentTypesBuilder,
3792 info: &VariantInfo,
3793 case: Option<&InterfaceType>,
3794 ) -> Source<'a> {
3795 match self {
3796 Source::Stack(s) => {
3797 let flat_len = match case {
3798 Some(case) => types.flat_types(case).unwrap().len(),
3799 None => 0,
3800 };
3801 Source::Stack(s.slice(1..s.locals.len()).slice(0..flat_len))
3802 }
3803 Source::Memory(mem) => {
3804 let mem = if mem.mem_opts().memory64 {
3805 mem.bump(info.payload_offset64)
3806 } else {
3807 mem.bump(info.payload_offset32)
3808 };
3809 Source::Memory(mem)
3810 }
3811 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
3812 }
3813 }
3814
3815 fn opts(&self) -> &'a Options {
3816 match self {
3817 Source::Stack(s) => s.opts,
3818 Source::Memory(mem) => mem.opts,
3819 Source::Struct(s) => s.opts,
3820 Source::Array(a) => a.opts,
3821 }
3822 }
3823}
3824
3825impl<'a> Destination<'a> {
3826 fn record_field_dsts<'b, I>(
3828 &'b self,
3829 types: &'b ComponentTypesBuilder,
3830 fields: I,
3831 ) -> impl Iterator<Item = Destination<'b>> + use<'b, I>
3832 where
3833 'a: 'b,
3834 I: IntoIterator<Item = InterfaceType> + 'b,
3835 {
3836 let mut offset = 0;
3837 fields.into_iter().map(move |ty| match self {
3838 Destination::Memory(mem) => {
3839 let mem = next_field_offset(&mut offset, types, &ty, mem);
3840 Destination::Memory(mem)
3841 }
3842 Destination::Stack(s, opts) => {
3843 let cnt = types.flat_types(&ty).unwrap().len() as u32;
3844 offset += cnt;
3845 Destination::Stack(&s[(offset - cnt) as usize..offset as usize], opts)
3846 }
3847 Destination::Struct(_) => todo!(),
3848 Destination::Array(_) => todo!(),
3849 })
3850 }
3851
3852 fn payload_dst(
3854 &self,
3855 types: &ComponentTypesBuilder,
3856 info: &VariantInfo,
3857 case: Option<&InterfaceType>,
3858 ) -> Destination<'_> {
3859 match self {
3860 Destination::Stack(s, opts) => {
3861 let flat_len = match case {
3862 Some(case) => types.flat_types(case).unwrap().len(),
3863 None => 0,
3864 };
3865 Destination::Stack(&s[1..][..flat_len], opts)
3866 }
3867 Destination::Memory(mem) => {
3868 let mem = if mem.mem_opts().memory64 {
3869 mem.bump(info.payload_offset64)
3870 } else {
3871 mem.bump(info.payload_offset32)
3872 };
3873 Destination::Memory(mem)
3874 }
3875 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
3876 }
3877 }
3878
3879 fn opts(&self) -> &'a Options {
3880 match self {
3881 Destination::Stack(_, opts) => opts,
3882 Destination::Memory(mem) => mem.opts,
3883 Destination::Struct(s) => s.opts,
3884 Destination::Array(a) => a.opts,
3885 }
3886 }
3887}
3888
3889fn next_field_offset<'a>(
3890 offset: &mut u32,
3891 types: &ComponentTypesBuilder,
3892 field: &InterfaceType,
3893 mem: &Memory<'a>,
3894) -> Memory<'a> {
3895 let abi = types.canonical_abi(field);
3896 let offset = if mem.mem_opts().memory64 {
3897 abi.next_field64(offset)
3898 } else {
3899 abi.next_field32(offset)
3900 };
3901 mem.bump(offset)
3902}
3903
3904impl<'a> Memory<'a> {
3905 fn memarg(&self, align: u32) -> MemArg {
3906 MemArg {
3907 offset: u64::from(self.offset),
3908 align,
3909 memory_index: self.mem_opts().memory.unwrap().as_u32(),
3910 }
3911 }
3912
3913 fn bump(&self, offset: u32) -> Memory<'a> {
3914 Memory {
3915 opts: self.opts,
3916 addr: TempLocal::new(self.addr.idx, self.addr.ty),
3917 offset: self.offset + offset,
3918 }
3919 }
3920}
3921
3922impl<'a> Stack<'a> {
3923 fn slice(&self, range: Range<usize>) -> Stack<'a> {
3924 Stack {
3925 locals: &self.locals[range],
3926 opts: self.opts,
3927 }
3928 }
3929}
3930
3931struct VariantCase<'a> {
3932 src_i: u32,
3933 src_ty: Option<&'a InterfaceType>,
3934 dst_i: u32,
3935 dst_ty: Option<&'a InterfaceType>,
3936}
3937
3938fn variant_info<'a, I>(types: &ComponentTypesBuilder, cases: I) -> VariantInfo
3939where
3940 I: IntoIterator<Item = Option<&'a InterfaceType>>,
3941 I::IntoIter: ExactSizeIterator,
3942{
3943 VariantInfo::new(
3944 cases
3945 .into_iter()
3946 .map(|ty| ty.map(|ty| types.canonical_abi(ty))),
3947 )
3948 .0
3949}
3950
3951enum MallocSize {
3952 Const(u32),
3953 Local(u32),
3954}
3955
3956struct WasmString<'a> {
3957 ptr: TempLocal,
3958 len: TempLocal,
3959 opts: &'a Options,
3960}
3961
3962struct TempLocal {
3963 idx: u32,
3964 ty: ValType,
3965 needs_free: bool,
3966}
3967
3968impl TempLocal {
3969 fn new(idx: u32, ty: ValType) -> TempLocal {
3970 TempLocal {
3971 idx,
3972 ty,
3973 needs_free: false,
3974 }
3975 }
3976}
3977
3978impl std::ops::Drop for TempLocal {
3979 fn drop(&mut self) {
3980 if self.needs_free {
3981 panic!("temporary local not free'd");
3982 }
3983 }
3984}
3985
3986impl From<FlatType> for ValType {
3987 fn from(ty: FlatType) -> ValType {
3988 match ty {
3989 FlatType::I32 => ValType::I32,
3990 FlatType::I64 => ValType::I64,
3991 FlatType::F32 => ValType::F32,
3992 FlatType::F64 => ValType::F64,
3993 }
3994 }
3995}