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 cranelift_entity::Signed;
36use std::collections::HashMap;
37use std::mem;
38use std::ops::Range;
39use wasm_encoder::{BlockType, Encode, Instruction, Instruction::*, MemArg, ValType};
40use wasmtime_component_util::{DiscriminantSize, FlagsSize};
41
42use super::DataModel;
43
44const MAX_STRING_BYTE_LENGTH: u32 = 1 << 31;
45const UTF16_TAG: u32 = 1 << 31;
46
47const INITIAL_FUEL: usize = 1_000;
50
51struct Compiler<'a, 'b> {
52 types: &'a ComponentTypesBuilder,
53 module: &'b mut Module<'a>,
54 result: FunctionId,
55
56 code: Vec<u8>,
58
59 nlocals: u32,
61
62 free_locals: HashMap<ValType, Vec<u32>>,
64
65 traps: Vec<(usize, Trap)>,
69
70 fuel: usize,
79
80 emit_resource_call: bool,
85}
86
87pub(super) fn compile(module: &mut Module<'_>, adapter: &AdapterData) {
88 fn compiler<'a, 'b>(
89 module: &'b mut Module<'a>,
90 adapter: &AdapterData,
91 ) -> (Compiler<'a, 'b>, Signature, Signature) {
92 let lower_sig = module.types.signature(&adapter.lower);
93 let lift_sig = module.types.signature(&adapter.lift);
94 let ty = module
95 .core_types
96 .function(&lower_sig.params, &lower_sig.results);
97 let result = module
98 .funcs
99 .push(Function::new(Some(adapter.name.clone()), ty));
100
101 let emit_resource_call = module.types.contains_borrow_resource(&adapter.lower);
106 assert_eq!(
107 emit_resource_call,
108 module.types.contains_borrow_resource(&adapter.lift)
109 );
110
111 (
112 Compiler::new(
113 module,
114 result,
115 lower_sig.params.len() as u32,
116 emit_resource_call,
117 ),
118 lower_sig,
119 lift_sig,
120 )
121 }
122
123 let async_start_adapter = |module: &mut Module| {
129 let sig = module
130 .types
131 .async_start_signature(&adapter.lower, &adapter.lift);
132 let ty = module.core_types.function(&sig.params, &sig.results);
133 let result = module.funcs.push(Function::new(
134 Some(format!("[async-start]{}", adapter.name)),
135 ty,
136 ));
137
138 Compiler::new(module, result, sig.params.len() as u32, false)
139 .compile_async_start_adapter(adapter, &sig);
140
141 result
142 };
143
144 let async_return_adapter = |module: &mut Module| {
153 let sig = module
154 .types
155 .async_return_signature(&adapter.lower, &adapter.lift);
156 let ty = module.core_types.function(&sig.params, &sig.results);
157 let result = module.funcs.push(Function::new(
158 Some(format!("[async-return]{}", adapter.name)),
159 ty,
160 ));
161
162 Compiler::new(module, result, sig.params.len() as u32, false)
163 .compile_async_return_adapter(adapter, &sig);
164
165 result
166 };
167
168 match (adapter.lower.options.async_, adapter.lift.options.async_) {
169 (false, false) => {
170 let (compiler, lower_sig, lift_sig) = compiler(module, adapter);
173 compiler.compile_sync_to_sync_adapter(adapter, &lower_sig, &lift_sig)
174 }
175 (true, true) => {
176 let start = async_start_adapter(module);
192 let return_ = async_return_adapter(module);
193 let (compiler, lower_sig, lift_sig) = compiler(module, adapter);
194 compiler.compile_async_to_async_adapter(
195 adapter,
196 start,
197 return_,
198 i32::try_from(lift_sig.params.len()).unwrap(),
199 &lower_sig,
200 );
201 }
202 (false, true) => {
203 let start = async_start_adapter(module);
216 let return_ = async_return_adapter(module);
217 let (compiler, lower_sig, lift_sig) = compiler(module, adapter);
218 compiler.compile_sync_to_async_adapter(
219 adapter,
220 start,
221 return_,
222 i32::try_from(lift_sig.params.len()).unwrap(),
223 &lower_sig,
224 );
225 }
226 (true, false) => {
227 let lift_sig = module.types.signature(&adapter.lift);
247 let start = async_start_adapter(module);
248 let return_ = async_return_adapter(module);
249 let (compiler, lower_sig, ..) = compiler(module, adapter);
250 compiler.compile_async_to_sync_adapter(
251 adapter,
252 start,
253 return_,
254 i32::try_from(lift_sig.params.len()).unwrap(),
255 i32::try_from(lift_sig.results.len()).unwrap(),
256 &lower_sig,
257 );
258 }
259 }
260}
261
262pub(super) fn compile_helper(module: &mut Module<'_>, result: FunctionId, helper: Helper) {
269 let mut nlocals = 0;
270 let src_flat;
271 let src = match helper.src.loc {
272 HelperLocation::Stack => {
277 src_flat = module
278 .types
279 .flatten_types(&helper.src.opts, usize::MAX, [helper.src.ty])
280 .unwrap()
281 .iter()
282 .enumerate()
283 .map(|(i, ty)| (i as u32, *ty))
284 .collect::<Vec<_>>();
285 nlocals += src_flat.len() as u32;
286 Source::Stack(Stack {
287 locals: &src_flat,
288 opts: &helper.src.opts,
289 })
290 }
291 HelperLocation::Memory => {
294 nlocals += 1;
295 Source::Memory(Memory {
296 opts: &helper.src.opts,
297 addr: TempLocal::new(0, helper.src.opts.data_model.unwrap_memory().ptr()),
298 offset: 0,
299 })
300 }
301 HelperLocation::StructField | HelperLocation::ArrayElement => todo!("CM+GC"),
302 };
303 let dst_flat;
304 let dst = match helper.dst.loc {
305 HelperLocation::Stack => {
308 dst_flat = module
309 .types
310 .flatten_types(&helper.dst.opts, usize::MAX, [helper.dst.ty])
311 .unwrap();
312 Destination::Stack(&dst_flat, &helper.dst.opts)
313 }
314 HelperLocation::Memory => {
317 nlocals += 1;
318 Destination::Memory(Memory {
319 opts: &helper.dst.opts,
320 addr: TempLocal::new(
321 nlocals - 1,
322 helper.dst.opts.data_model.unwrap_memory().ptr(),
323 ),
324 offset: 0,
325 })
326 }
327 HelperLocation::StructField | HelperLocation::ArrayElement => todo!("CM+GC"),
328 };
329 let mut compiler = Compiler {
330 types: module.types,
331 module,
332 code: Vec::new(),
333 nlocals,
334 free_locals: HashMap::new(),
335 traps: Vec::new(),
336 result,
337 fuel: INITIAL_FUEL,
338 emit_resource_call: false,
341 };
342 compiler.translate(&helper.src.ty, &src, &helper.dst.ty, &dst);
343 compiler.finish();
344}
345
346enum Source<'a> {
349 Stack(Stack<'a>),
355
356 Memory(Memory<'a>),
359
360 #[allow(dead_code, reason = "CM+GC is still WIP")]
363 Struct(GcStruct<'a>),
364
365 #[allow(dead_code, reason = "CM+GC is still WIP")]
368 Array(GcArray<'a>),
369}
370
371enum Destination<'a> {
373 Stack(&'a [ValType], &'a Options),
379
380 Memory(Memory<'a>),
382
383 #[allow(dead_code, reason = "CM+GC is still WIP")]
386 Struct(GcStruct<'a>),
387
388 #[allow(dead_code, reason = "CM+GC is still WIP")]
391 Array(GcArray<'a>),
392}
393
394struct Stack<'a> {
395 locals: &'a [(u32, ValType)],
401 opts: &'a Options,
403}
404
405struct Memory<'a> {
407 opts: &'a Options,
409 addr: TempLocal,
412 offset: u32,
415}
416
417impl<'a> Memory<'a> {
418 fn mem_opts(&self) -> &'a LinearMemoryOptions {
419 self.opts.data_model.unwrap_memory()
420 }
421}
422
423struct GcStruct<'a> {
425 opts: &'a Options,
426 }
428
429struct GcArray<'a> {
431 opts: &'a Options,
432 }
434
435impl<'a, 'b> Compiler<'a, 'b> {
436 fn new(
437 module: &'b mut Module<'a>,
438 result: FunctionId,
439 nlocals: u32,
440 emit_resource_call: bool,
441 ) -> Self {
442 Self {
443 types: module.types,
444 module,
445 result,
446 code: Vec::new(),
447 nlocals,
448 free_locals: HashMap::new(),
449 traps: Vec::new(),
450 fuel: INITIAL_FUEL,
451 emit_resource_call,
452 }
453 }
454
455 fn compile_async_to_async_adapter(
465 mut self,
466 adapter: &AdapterData,
467 start: FunctionId,
468 return_: FunctionId,
469 param_count: i32,
470 lower_sig: &Signature,
471 ) {
472 let start_call =
473 self.module
474 .import_async_start_call(&adapter.name, adapter.lift.options.callback, None);
475
476 self.call_prepare(adapter, start, return_, lower_sig, false);
477
478 self.module.exports.push((
487 adapter.callee.as_u32(),
488 format!("[adapter-callee]{}", adapter.name),
489 ));
490
491 self.instruction(RefFunc(adapter.callee.as_u32()));
492 self.instruction(I32Const(param_count));
493 self.instruction(I32Const(1));
497 self.instruction(I32Const(START_FLAG_ASYNC_CALLEE));
498 self.instruction(Call(start_call.as_u32()));
499
500 self.finish()
501 }
502
503 fn call_prepare(
516 &mut self,
517 adapter: &AdapterData,
518 start: FunctionId,
519 return_: FunctionId,
520 lower_sig: &Signature,
521 prepare_sync: bool,
522 ) {
523 let prepare = self.module.import_prepare_call(
524 &adapter.name,
525 &lower_sig.params,
526 match adapter.lift.options.data_model {
527 DataModel::Gc {} => todo!("CM+GC"),
528 DataModel::LinearMemory(LinearMemoryOptions { memory, .. }) => memory,
529 },
530 );
531
532 self.flush_code();
533 self.module.funcs[self.result]
534 .body
535 .push(Body::RefFunc(start));
536 self.module.funcs[self.result]
537 .body
538 .push(Body::RefFunc(return_));
539 self.instruction(I32Const(
540 i32::try_from(adapter.lower.instance.as_u32()).unwrap(),
541 ));
542 self.instruction(I32Const(
543 i32::try_from(adapter.lift.instance.as_u32()).unwrap(),
544 ));
545 self.instruction(I32Const(
546 i32::try_from(self.types[adapter.lift.ty].results.as_u32()).unwrap(),
547 ));
548 self.instruction(I32Const(i32::from(
549 adapter.lift.options.string_encoding as u8,
550 )));
551
552 let result_types = &self.types[self.types[adapter.lower.ty].results].types;
555 if prepare_sync {
556 self.instruction(I32Const(
557 i32::try_from(
558 self.types
559 .flatten_types(
560 &adapter.lower.options,
561 usize::MAX,
562 result_types.iter().copied(),
563 )
564 .map(|v| v.len())
565 .unwrap_or(usize::try_from(i32::MAX).unwrap()),
566 )
567 .unwrap(),
568 ));
569 } else {
570 if result_types.len() > 0 {
571 self.instruction(I32Const(PREPARE_ASYNC_WITH_RESULT.signed()));
572 } else {
573 self.instruction(I32Const(PREPARE_ASYNC_NO_RESULT.signed()));
574 }
575 }
576
577 for index in 0..lower_sig.params.len() {
579 self.instruction(LocalGet(u32::try_from(index).unwrap()));
580 }
581 self.instruction(Call(prepare.as_u32()));
582 }
583
584 fn compile_sync_to_async_adapter(
594 mut self,
595 adapter: &AdapterData,
596 start: FunctionId,
597 return_: FunctionId,
598 lift_param_count: i32,
599 lower_sig: &Signature,
600 ) {
601 let start_call = self.module.import_sync_start_call(
602 &adapter.name,
603 adapter.lift.options.callback,
604 &lower_sig.results,
605 );
606
607 self.call_prepare(adapter, start, return_, lower_sig, true);
608
609 self.module.exports.push((
618 adapter.callee.as_u32(),
619 format!("[adapter-callee]{}", adapter.name),
620 ));
621
622 self.instruction(RefFunc(adapter.callee.as_u32()));
623 self.instruction(I32Const(lift_param_count));
624 self.instruction(Call(start_call.as_u32()));
625
626 self.finish()
627 }
628
629 fn compile_async_to_sync_adapter(
639 mut self,
640 adapter: &AdapterData,
641 start: FunctionId,
642 return_: FunctionId,
643 param_count: i32,
644 result_count: i32,
645 lower_sig: &Signature,
646 ) {
647 let start_call =
648 self.module
649 .import_async_start_call(&adapter.name, None, adapter.lift.post_return);
650
651 self.call_prepare(adapter, start, return_, lower_sig, false);
652
653 self.module.exports.push((
657 adapter.callee.as_u32(),
658 format!("[adapter-callee]{}", adapter.name),
659 ));
660
661 self.instruction(RefFunc(adapter.callee.as_u32()));
662 self.instruction(I32Const(param_count));
663 self.instruction(I32Const(result_count));
664 self.instruction(I32Const(0));
665 self.instruction(Call(start_call.as_u32()));
666
667 self.finish()
668 }
669
670 fn compile_async_start_adapter(mut self, adapter: &AdapterData, sig: &Signature) {
676 let param_locals = sig
677 .params
678 .iter()
679 .enumerate()
680 .map(|(i, ty)| (i as u32, *ty))
681 .collect::<Vec<_>>();
682
683 self.set_flag(adapter.lift.flags, FLAG_MAY_LEAVE, false);
684 self.translate_params(adapter, ¶m_locals);
685 self.set_flag(adapter.lift.flags, FLAG_MAY_LEAVE, true);
686
687 self.finish();
688 }
689
690 fn compile_async_return_adapter(mut self, adapter: &AdapterData, sig: &Signature) {
699 let param_locals = sig
700 .params
701 .iter()
702 .enumerate()
703 .map(|(i, ty)| (i as u32, *ty))
704 .collect::<Vec<_>>();
705
706 self.set_flag(adapter.lower.flags, FLAG_MAY_LEAVE, false);
707 self.translate_results(adapter, ¶m_locals, ¶m_locals);
718 self.set_flag(adapter.lower.flags, FLAG_MAY_LEAVE, true);
719
720 self.finish()
721 }
722
723 fn compile_sync_to_sync_adapter(
730 mut self,
731 adapter: &AdapterData,
732 lower_sig: &Signature,
733 lift_sig: &Signature,
734 ) {
735 self.trap_if_not_flag(adapter.lower.flags, FLAG_MAY_LEAVE, Trap::CannotLeave);
741 if adapter.called_as_export {
742 self.trap_if_not_flag(adapter.lift.flags, FLAG_MAY_ENTER, Trap::CannotEnter);
743 self.set_flag(adapter.lift.flags, FLAG_MAY_ENTER, false);
744 } else if self.module.debug {
745 self.assert_not_flag(
746 adapter.lift.flags,
747 FLAG_MAY_ENTER,
748 "may_enter should be unset",
749 );
750 }
751
752 if self.emit_resource_call {
753 let enter = self.module.import_resource_enter_call();
754 self.instruction(Call(enter.as_u32()));
755 }
756
757 self.set_flag(adapter.lift.flags, FLAG_MAY_LEAVE, false);
770 let param_locals = lower_sig
771 .params
772 .iter()
773 .enumerate()
774 .map(|(i, ty)| (i as u32, *ty))
775 .collect::<Vec<_>>();
776 self.translate_params(adapter, ¶m_locals);
777 self.set_flag(adapter.lift.flags, FLAG_MAY_LEAVE, true);
778
779 self.instruction(Call(adapter.callee.as_u32()));
783 let mut result_locals = Vec::with_capacity(lift_sig.results.len());
784 let mut temps = Vec::new();
785 for ty in lift_sig.results.iter().rev() {
786 let local = self.local_set_new_tmp(*ty);
787 result_locals.push((local.idx, *ty));
788 temps.push(local);
789 }
790 result_locals.reverse();
791
792 self.set_flag(adapter.lower.flags, FLAG_MAY_LEAVE, false);
801 self.translate_results(adapter, ¶m_locals, &result_locals);
802 self.set_flag(adapter.lower.flags, FLAG_MAY_LEAVE, true);
803
804 if let Some(func) = adapter.lift.post_return {
807 for (result, _) in result_locals.iter() {
808 self.instruction(LocalGet(*result));
809 }
810 self.instruction(Call(func.as_u32()));
811 }
812 if adapter.called_as_export {
813 self.set_flag(adapter.lift.flags, FLAG_MAY_ENTER, true);
814 }
815
816 for tmp in temps {
817 self.free_temp_local(tmp);
818 }
819
820 if self.emit_resource_call {
821 let exit = self.module.import_resource_exit_call();
822 self.instruction(Call(exit.as_u32()));
823 }
824
825 self.finish()
826 }
827
828 fn translate_params(&mut self, adapter: &AdapterData, param_locals: &[(u32, ValType)]) {
829 let src_tys = self.types[adapter.lower.ty].params;
830 let src_tys = self.types[src_tys]
831 .types
832 .iter()
833 .copied()
834 .collect::<Vec<_>>();
835 let dst_tys = self.types[adapter.lift.ty].params;
836 let dst_tys = self.types[dst_tys]
837 .types
838 .iter()
839 .copied()
840 .collect::<Vec<_>>();
841 let lift_opts = &adapter.lift.options;
842 let lower_opts = &adapter.lower.options;
843
844 assert_eq!(src_tys.len(), dst_tys.len());
846
847 let max_flat_params = if adapter.lower.options.async_ {
851 MAX_FLAT_ASYNC_PARAMS
852 } else {
853 MAX_FLAT_PARAMS
854 };
855 let src_flat =
856 self.types
857 .flatten_types(lower_opts, max_flat_params, src_tys.iter().copied());
858 let dst_flat =
859 self.types
860 .flatten_types(lift_opts, MAX_FLAT_PARAMS, dst_tys.iter().copied());
861
862 let src = if let Some(flat) = &src_flat {
863 Source::Stack(Stack {
864 locals: ¶m_locals[..flat.len()],
865 opts: lower_opts,
866 })
867 } else {
868 let lower_mem_opts = lower_opts.data_model.unwrap_memory();
872 let (addr, ty) = param_locals[0];
873 assert_eq!(ty, lower_mem_opts.ptr());
874 let align = src_tys
875 .iter()
876 .map(|t| self.types.align(lower_mem_opts, t))
877 .max()
878 .unwrap_or(1);
879 Source::Memory(self.memory_operand(lower_opts, TempLocal::new(addr, ty), align))
880 };
881
882 let dst = if let Some(flat) = &dst_flat {
883 Destination::Stack(flat, lift_opts)
884 } else {
885 let abi = CanonicalAbiInfo::record(dst_tys.iter().map(|t| self.types.canonical_abi(t)));
886 match lift_opts.data_model {
887 DataModel::Gc {} => todo!("CM+GC"),
888 DataModel::LinearMemory(LinearMemoryOptions { memory64, .. }) => {
889 let (size, align) = if memory64 {
890 (abi.size64, abi.align64)
891 } else {
892 (abi.size32, abi.align32)
893 };
894
895 let size = MallocSize::Const(size);
898 Destination::Memory(self.malloc(lift_opts, size, align))
899 }
900 }
901 };
902
903 let srcs = src
904 .record_field_srcs(self.types, src_tys.iter().copied())
905 .zip(src_tys.iter());
906 let dsts = dst
907 .record_field_dsts(self.types, dst_tys.iter().copied())
908 .zip(dst_tys.iter());
909 for ((src, src_ty), (dst, dst_ty)) in srcs.zip(dsts) {
910 self.translate(&src_ty, &src, &dst_ty, &dst);
911 }
912
913 if let Destination::Memory(mem) = dst {
917 self.instruction(LocalGet(mem.addr.idx));
918 self.free_temp_local(mem.addr);
919 }
920 }
921
922 fn translate_results(
923 &mut self,
924 adapter: &AdapterData,
925 param_locals: &[(u32, ValType)],
926 result_locals: &[(u32, ValType)],
927 ) {
928 let src_tys = self.types[adapter.lift.ty].results;
929 let src_tys = self.types[src_tys]
930 .types
931 .iter()
932 .copied()
933 .collect::<Vec<_>>();
934 let dst_tys = self.types[adapter.lower.ty].results;
935 let dst_tys = self.types[dst_tys]
936 .types
937 .iter()
938 .copied()
939 .collect::<Vec<_>>();
940 let lift_opts = &adapter.lift.options;
941 let lower_opts = &adapter.lower.options;
942
943 let src_flat = self
944 .types
945 .flatten_lifting_types(lift_opts, src_tys.iter().copied());
946 let dst_flat = self
947 .types
948 .flatten_lowering_types(lower_opts, dst_tys.iter().copied());
949
950 let src = if src_flat.is_some() {
951 Source::Stack(Stack {
952 locals: result_locals,
953 opts: lift_opts,
954 })
955 } else {
956 let lift_mem_opts = lift_opts.data_model.unwrap_memory();
961 let align = src_tys
962 .iter()
963 .map(|t| self.types.align(lift_mem_opts, t))
964 .max()
965 .unwrap_or(1);
966 assert_eq!(
967 result_locals.len(),
968 if lower_opts.async_ || lift_opts.async_ {
969 2
970 } else {
971 1
972 }
973 );
974 let (addr, ty) = result_locals[0];
975 assert_eq!(ty, lift_opts.data_model.unwrap_memory().ptr());
976 Source::Memory(self.memory_operand(lift_opts, TempLocal::new(addr, ty), align))
977 };
978
979 let dst = if let Some(flat) = &dst_flat {
980 Destination::Stack(flat, lower_opts)
981 } else {
982 let lower_mem_opts = lower_opts.data_model.unwrap_memory();
986 let align = dst_tys
987 .iter()
988 .map(|t| self.types.align(lower_mem_opts, t))
989 .max()
990 .unwrap_or(1);
991 let (addr, ty) = *param_locals.last().expect("no retptr");
992 assert_eq!(ty, lower_opts.data_model.unwrap_memory().ptr());
993 Destination::Memory(self.memory_operand(lower_opts, TempLocal::new(addr, ty), align))
994 };
995
996 let srcs = src
997 .record_field_srcs(self.types, src_tys.iter().copied())
998 .zip(src_tys.iter());
999 let dsts = dst
1000 .record_field_dsts(self.types, dst_tys.iter().copied())
1001 .zip(dst_tys.iter());
1002 for ((src, src_ty), (dst, dst_ty)) in srcs.zip(dsts) {
1003 self.translate(&src_ty, &src, &dst_ty, &dst);
1004 }
1005 }
1006
1007 fn translate(
1008 &mut self,
1009 src_ty: &InterfaceType,
1010 src: &Source<'_>,
1011 dst_ty: &InterfaceType,
1012 dst: &Destination,
1013 ) {
1014 if let Source::Memory(mem) = src {
1015 self.assert_aligned(src_ty, mem);
1016 }
1017 if let Destination::Memory(mem) = dst {
1018 self.assert_aligned(dst_ty, mem);
1019 }
1020
1021 let cost = match src_ty {
1051 InterfaceType::Bool
1055 | InterfaceType::U8
1056 | InterfaceType::S8
1057 | InterfaceType::U16
1058 | InterfaceType::S16
1059 | InterfaceType::U32
1060 | InterfaceType::S32
1061 | InterfaceType::U64
1062 | InterfaceType::S64
1063 | InterfaceType::Float32
1064 | InterfaceType::Float64 => 0,
1065
1066 InterfaceType::Char => 1,
1069
1070 InterfaceType::String => 40,
1073
1074 InterfaceType::List(_) => 40,
1077
1078 InterfaceType::Flags(i) => {
1079 let count = self.module.types[*i].names.len();
1080 match FlagsSize::from_count(count) {
1081 FlagsSize::Size0 => 0,
1082 FlagsSize::Size1 | FlagsSize::Size2 => 1,
1083 FlagsSize::Size4Plus(n) => n.into(),
1084 }
1085 }
1086
1087 InterfaceType::Record(i) => self.types[*i].fields.len(),
1088 InterfaceType::Tuple(i) => self.types[*i].types.len(),
1089 InterfaceType::Variant(i) => self.types[*i].cases.len(),
1090 InterfaceType::Enum(i) => self.types[*i].names.len(),
1091
1092 InterfaceType::Option(_) | InterfaceType::Result(_) => 2,
1094
1095 InterfaceType::Own(_)
1097 | InterfaceType::Borrow(_)
1098 | InterfaceType::Future(_)
1099 | InterfaceType::Stream(_)
1100 | InterfaceType::ErrorContext(_) => 1,
1101 };
1102
1103 match self.fuel.checked_sub(cost) {
1104 Some(n) => {
1110 self.fuel = n;
1111 match src_ty {
1112 InterfaceType::Bool => self.translate_bool(src, dst_ty, dst),
1113 InterfaceType::U8 => self.translate_u8(src, dst_ty, dst),
1114 InterfaceType::S8 => self.translate_s8(src, dst_ty, dst),
1115 InterfaceType::U16 => self.translate_u16(src, dst_ty, dst),
1116 InterfaceType::S16 => self.translate_s16(src, dst_ty, dst),
1117 InterfaceType::U32 => self.translate_u32(src, dst_ty, dst),
1118 InterfaceType::S32 => self.translate_s32(src, dst_ty, dst),
1119 InterfaceType::U64 => self.translate_u64(src, dst_ty, dst),
1120 InterfaceType::S64 => self.translate_s64(src, dst_ty, dst),
1121 InterfaceType::Float32 => self.translate_f32(src, dst_ty, dst),
1122 InterfaceType::Float64 => self.translate_f64(src, dst_ty, dst),
1123 InterfaceType::Char => self.translate_char(src, dst_ty, dst),
1124 InterfaceType::String => self.translate_string(src, dst_ty, dst),
1125 InterfaceType::List(t) => self.translate_list(*t, src, dst_ty, dst),
1126 InterfaceType::Record(t) => self.translate_record(*t, src, dst_ty, dst),
1127 InterfaceType::Flags(f) => self.translate_flags(*f, src, dst_ty, dst),
1128 InterfaceType::Tuple(t) => self.translate_tuple(*t, src, dst_ty, dst),
1129 InterfaceType::Variant(v) => self.translate_variant(*v, src, dst_ty, dst),
1130 InterfaceType::Enum(t) => self.translate_enum(*t, src, dst_ty, dst),
1131 InterfaceType::Option(t) => self.translate_option(*t, src, dst_ty, dst),
1132 InterfaceType::Result(t) => self.translate_result(*t, src, dst_ty, dst),
1133 InterfaceType::Own(t) => self.translate_own(*t, src, dst_ty, dst),
1134 InterfaceType::Borrow(t) => self.translate_borrow(*t, src, dst_ty, dst),
1135 InterfaceType::Future(t) => self.translate_future(*t, src, dst_ty, dst),
1136 InterfaceType::Stream(t) => self.translate_stream(*t, src, dst_ty, dst),
1137 InterfaceType::ErrorContext(t) => {
1138 self.translate_error_context(*t, src, dst_ty, dst)
1139 }
1140 }
1141 }
1142
1143 None => {
1149 let src_loc = match src {
1150 Source::Stack(stack) => {
1154 for (i, ty) in stack
1155 .opts
1156 .flat_types(src_ty, self.types)
1157 .unwrap()
1158 .iter()
1159 .enumerate()
1160 {
1161 let stack = stack.slice(i..i + 1);
1162 self.stack_get(&stack, (*ty).into());
1163 }
1164 HelperLocation::Stack
1165 }
1166 Source::Memory(mem) => {
1171 self.push_mem_addr(mem);
1172 HelperLocation::Memory
1173 }
1174 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1175 };
1176 let dst_loc = match dst {
1177 Destination::Stack(..) => HelperLocation::Stack,
1178 Destination::Memory(mem) => {
1179 self.push_mem_addr(mem);
1180 HelperLocation::Memory
1181 }
1182 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1183 };
1184 let helper = self.module.translate_helper(Helper {
1190 src: HelperType {
1191 ty: *src_ty,
1192 opts: *src.opts(),
1193 loc: src_loc,
1194 },
1195 dst: HelperType {
1196 ty: *dst_ty,
1197 opts: *dst.opts(),
1198 loc: dst_loc,
1199 },
1200 });
1201 self.flush_code();
1204 self.module.funcs[self.result].body.push(Body::Call(helper));
1205
1206 if let Destination::Stack(tys, opts) = dst {
1215 let flat = self
1216 .types
1217 .flatten_types(opts, usize::MAX, [*dst_ty])
1218 .unwrap();
1219 assert_eq!(flat.len(), tys.len());
1220 let locals = flat
1221 .iter()
1222 .rev()
1223 .map(|ty| self.local_set_new_tmp(*ty))
1224 .collect::<Vec<_>>();
1225 for (ty, local) in tys.iter().zip(locals.into_iter().rev()) {
1226 self.instruction(LocalGet(local.idx));
1227 self.stack_set(std::slice::from_ref(ty), local.ty);
1228 self.free_temp_local(local);
1229 }
1230 }
1231 }
1232 }
1233 }
1234
1235 fn push_mem_addr(&mut self, mem: &Memory<'_>) {
1236 self.instruction(LocalGet(mem.addr.idx));
1237 if mem.offset != 0 {
1238 self.ptr_uconst(mem.mem_opts(), mem.offset);
1239 self.ptr_add(mem.mem_opts());
1240 }
1241 }
1242
1243 fn translate_bool(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1244 assert!(matches!(dst_ty, InterfaceType::Bool));
1246 self.push_dst_addr(dst);
1247
1248 self.instruction(I32Const(1));
1251 self.instruction(I32Const(0));
1252 match src {
1253 Source::Memory(mem) => self.i32_load8u(mem),
1254 Source::Stack(stack) => self.stack_get(stack, ValType::I32),
1255 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1256 }
1257 self.instruction(Select);
1258
1259 match dst {
1260 Destination::Memory(mem) => self.i32_store8(mem),
1261 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1262 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1263 }
1264 }
1265
1266 fn translate_u8(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1267 assert!(matches!(dst_ty, InterfaceType::U8));
1269 self.convert_u8_mask(src, dst, 0xff);
1270 }
1271
1272 fn convert_u8_mask(&mut self, src: &Source<'_>, dst: &Destination<'_>, mask: u8) {
1273 self.push_dst_addr(dst);
1274 let mut needs_mask = true;
1275 match src {
1276 Source::Memory(mem) => {
1277 self.i32_load8u(mem);
1278 needs_mask = mask != 0xff;
1279 }
1280 Source::Stack(stack) => {
1281 self.stack_get(stack, ValType::I32);
1282 }
1283 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1284 }
1285 if needs_mask {
1286 self.instruction(I32Const(i32::from(mask)));
1287 self.instruction(I32And);
1288 }
1289 match dst {
1290 Destination::Memory(mem) => self.i32_store8(mem),
1291 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1292 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1293 }
1294 }
1295
1296 fn translate_s8(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1297 assert!(matches!(dst_ty, InterfaceType::S8));
1299 self.push_dst_addr(dst);
1300 match src {
1301 Source::Memory(mem) => self.i32_load8s(mem),
1302 Source::Stack(stack) => {
1303 self.stack_get(stack, ValType::I32);
1304 self.instruction(I32Extend8S);
1305 }
1306 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1307 }
1308 match dst {
1309 Destination::Memory(mem) => self.i32_store8(mem),
1310 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1311 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1312 }
1313 }
1314
1315 fn translate_u16(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1316 assert!(matches!(dst_ty, InterfaceType::U16));
1318 self.convert_u16_mask(src, dst, 0xffff);
1319 }
1320
1321 fn convert_u16_mask(&mut self, src: &Source<'_>, dst: &Destination<'_>, mask: u16) {
1322 self.push_dst_addr(dst);
1323 let mut needs_mask = true;
1324 match src {
1325 Source::Memory(mem) => {
1326 self.i32_load16u(mem);
1327 needs_mask = mask != 0xffff;
1328 }
1329 Source::Stack(stack) => {
1330 self.stack_get(stack, ValType::I32);
1331 }
1332 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1333 }
1334 if needs_mask {
1335 self.instruction(I32Const(i32::from(mask)));
1336 self.instruction(I32And);
1337 }
1338 match dst {
1339 Destination::Memory(mem) => self.i32_store16(mem),
1340 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1341 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1342 }
1343 }
1344
1345 fn translate_s16(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1346 assert!(matches!(dst_ty, InterfaceType::S16));
1348 self.push_dst_addr(dst);
1349 match src {
1350 Source::Memory(mem) => self.i32_load16s(mem),
1351 Source::Stack(stack) => {
1352 self.stack_get(stack, ValType::I32);
1353 self.instruction(I32Extend16S);
1354 }
1355 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1356 }
1357 match dst {
1358 Destination::Memory(mem) => self.i32_store16(mem),
1359 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1360 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1361 }
1362 }
1363
1364 fn translate_u32(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1365 assert!(matches!(dst_ty, InterfaceType::U32));
1367 self.convert_u32_mask(src, dst, 0xffffffff)
1368 }
1369
1370 fn convert_u32_mask(&mut self, src: &Source<'_>, dst: &Destination<'_>, mask: u32) {
1371 self.push_dst_addr(dst);
1372 match src {
1373 Source::Memory(mem) => self.i32_load(mem),
1374 Source::Stack(stack) => self.stack_get(stack, ValType::I32),
1375 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1376 }
1377 if mask != 0xffffffff {
1378 self.instruction(I32Const(mask as i32));
1379 self.instruction(I32And);
1380 }
1381 match dst {
1382 Destination::Memory(mem) => self.i32_store(mem),
1383 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1384 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1385 }
1386 }
1387
1388 fn translate_s32(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1389 assert!(matches!(dst_ty, InterfaceType::S32));
1391 self.push_dst_addr(dst);
1392 match src {
1393 Source::Memory(mem) => self.i32_load(mem),
1394 Source::Stack(stack) => self.stack_get(stack, ValType::I32),
1395 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1396 }
1397 match dst {
1398 Destination::Memory(mem) => self.i32_store(mem),
1399 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1400 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1401 }
1402 }
1403
1404 fn translate_u64(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1405 assert!(matches!(dst_ty, InterfaceType::U64));
1407 self.push_dst_addr(dst);
1408 match src {
1409 Source::Memory(mem) => self.i64_load(mem),
1410 Source::Stack(stack) => self.stack_get(stack, ValType::I64),
1411 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1412 }
1413 match dst {
1414 Destination::Memory(mem) => self.i64_store(mem),
1415 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I64),
1416 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1417 }
1418 }
1419
1420 fn translate_s64(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1421 assert!(matches!(dst_ty, InterfaceType::S64));
1423 self.push_dst_addr(dst);
1424 match src {
1425 Source::Memory(mem) => self.i64_load(mem),
1426 Source::Stack(stack) => self.stack_get(stack, ValType::I64),
1427 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1428 }
1429 match dst {
1430 Destination::Memory(mem) => self.i64_store(mem),
1431 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I64),
1432 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1433 }
1434 }
1435
1436 fn translate_f32(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1437 assert!(matches!(dst_ty, InterfaceType::Float32));
1439 self.push_dst_addr(dst);
1440 match src {
1441 Source::Memory(mem) => self.f32_load(mem),
1442 Source::Stack(stack) => self.stack_get(stack, ValType::F32),
1443 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1444 }
1445 match dst {
1446 Destination::Memory(mem) => self.f32_store(mem),
1447 Destination::Stack(stack, _) => self.stack_set(stack, ValType::F32),
1448 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1449 }
1450 }
1451
1452 fn translate_f64(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1453 assert!(matches!(dst_ty, InterfaceType::Float64));
1455 self.push_dst_addr(dst);
1456 match src {
1457 Source::Memory(mem) => self.f64_load(mem),
1458 Source::Stack(stack) => self.stack_get(stack, ValType::F64),
1459 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1460 }
1461 match dst {
1462 Destination::Memory(mem) => self.f64_store(mem),
1463 Destination::Stack(stack, _) => self.stack_set(stack, ValType::F64),
1464 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1465 }
1466 }
1467
1468 fn translate_char(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1469 assert!(matches!(dst_ty, InterfaceType::Char));
1470 match src {
1471 Source::Memory(mem) => self.i32_load(mem),
1472 Source::Stack(stack) => self.stack_get(stack, ValType::I32),
1473 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1474 }
1475 let local = self.local_set_new_tmp(ValType::I32);
1476
1477 self.instruction(Block(BlockType::Empty));
1493 self.instruction(Block(BlockType::Empty));
1494 self.instruction(LocalGet(local.idx));
1495 self.instruction(I32Const(0xd800));
1496 self.instruction(I32Xor);
1497 self.instruction(I32Const(-0x110000));
1498 self.instruction(I32Add);
1499 self.instruction(I32Const(-0x10f800));
1500 self.instruction(I32LtU);
1501 self.instruction(BrIf(0));
1502 self.instruction(LocalGet(local.idx));
1503 self.instruction(I32Const(0x110000));
1504 self.instruction(I32Ne);
1505 self.instruction(BrIf(1));
1506 self.instruction(End);
1507 self.trap(Trap::InvalidChar);
1508 self.instruction(End);
1509
1510 self.push_dst_addr(dst);
1511 self.instruction(LocalGet(local.idx));
1512 match dst {
1513 Destination::Memory(mem) => {
1514 self.i32_store(mem);
1515 }
1516 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1517 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1518 }
1519
1520 self.free_temp_local(local);
1521 }
1522
1523 fn translate_string(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1524 assert!(matches!(dst_ty, InterfaceType::String));
1525 let src_opts = src.opts();
1526 let dst_opts = dst.opts();
1527
1528 let src_mem_opts = match &src_opts.data_model {
1529 DataModel::Gc {} => todo!("CM+GC"),
1530 DataModel::LinearMemory(opts) => opts,
1531 };
1532 let dst_mem_opts = match &dst_opts.data_model {
1533 DataModel::Gc {} => todo!("CM+GC"),
1534 DataModel::LinearMemory(opts) => opts,
1535 };
1536
1537 match src {
1542 Source::Stack(s) => {
1543 assert_eq!(s.locals.len(), 2);
1544 self.stack_get(&s.slice(0..1), src_mem_opts.ptr());
1545 self.stack_get(&s.slice(1..2), src_mem_opts.ptr());
1546 }
1547 Source::Memory(mem) => {
1548 self.ptr_load(mem);
1549 self.ptr_load(&mem.bump(src_mem_opts.ptr_size().into()));
1550 }
1551 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1552 }
1553 let src_len = self.local_set_new_tmp(src_mem_opts.ptr());
1554 let src_ptr = self.local_set_new_tmp(src_mem_opts.ptr());
1555 let src_str = WasmString {
1556 ptr: src_ptr,
1557 len: src_len,
1558 opts: src_opts,
1559 };
1560
1561 let dst_str = match src_opts.string_encoding {
1562 StringEncoding::Utf8 => match dst_opts.string_encoding {
1563 StringEncoding::Utf8 => self.string_copy(&src_str, FE::Utf8, dst_opts, FE::Utf8),
1564 StringEncoding::Utf16 => self.string_utf8_to_utf16(&src_str, dst_opts),
1565 StringEncoding::CompactUtf16 => {
1566 self.string_to_compact(&src_str, FE::Utf8, dst_opts)
1567 }
1568 },
1569
1570 StringEncoding::Utf16 => {
1571 self.verify_aligned(src_mem_opts, src_str.ptr.idx, 2);
1572 match dst_opts.string_encoding {
1573 StringEncoding::Utf8 => {
1574 self.string_deflate_to_utf8(&src_str, FE::Utf16, dst_opts)
1575 }
1576 StringEncoding::Utf16 => {
1577 self.string_copy(&src_str, FE::Utf16, dst_opts, FE::Utf16)
1578 }
1579 StringEncoding::CompactUtf16 => {
1580 self.string_to_compact(&src_str, FE::Utf16, dst_opts)
1581 }
1582 }
1583 }
1584
1585 StringEncoding::CompactUtf16 => {
1586 self.verify_aligned(src_mem_opts, src_str.ptr.idx, 2);
1587
1588 self.instruction(LocalGet(src_str.len.idx));
1591 self.ptr_uconst(src_mem_opts, UTF16_TAG);
1592 self.ptr_and(src_mem_opts);
1593 self.ptr_if(src_mem_opts, BlockType::Empty);
1594
1595 self.instruction(LocalGet(src_str.len.idx));
1599 self.ptr_uconst(src_mem_opts, UTF16_TAG);
1600 self.ptr_xor(src_mem_opts);
1601 self.instruction(LocalSet(src_str.len.idx));
1602 let s1 = match dst_opts.string_encoding {
1603 StringEncoding::Utf8 => {
1604 self.string_deflate_to_utf8(&src_str, FE::Utf16, dst_opts)
1605 }
1606 StringEncoding::Utf16 => {
1607 self.string_copy(&src_str, FE::Utf16, dst_opts, FE::Utf16)
1608 }
1609 StringEncoding::CompactUtf16 => {
1610 self.string_compact_utf16_to_compact(&src_str, dst_opts)
1611 }
1612 };
1613
1614 self.instruction(Else);
1615
1616 let s2 = match dst_opts.string_encoding {
1620 StringEncoding::Utf16 => {
1621 self.string_copy(&src_str, FE::Latin1, dst_opts, FE::Utf16)
1622 }
1623 StringEncoding::Utf8 => {
1624 self.string_deflate_to_utf8(&src_str, FE::Latin1, dst_opts)
1625 }
1626 StringEncoding::CompactUtf16 => {
1627 self.string_copy(&src_str, FE::Latin1, dst_opts, FE::Latin1)
1628 }
1629 };
1630 self.instruction(LocalGet(s2.ptr.idx));
1633 self.instruction(LocalSet(s1.ptr.idx));
1634 self.instruction(LocalGet(s2.len.idx));
1635 self.instruction(LocalSet(s1.len.idx));
1636 self.instruction(End);
1637 self.free_temp_local(s2.ptr);
1638 self.free_temp_local(s2.len);
1639 s1
1640 }
1641 };
1642
1643 match dst {
1645 Destination::Stack(s, _) => {
1646 self.instruction(LocalGet(dst_str.ptr.idx));
1647 self.stack_set(&s[..1], dst_mem_opts.ptr());
1648 self.instruction(LocalGet(dst_str.len.idx));
1649 self.stack_set(&s[1..], dst_mem_opts.ptr());
1650 }
1651 Destination::Memory(mem) => {
1652 self.instruction(LocalGet(mem.addr.idx));
1653 self.instruction(LocalGet(dst_str.ptr.idx));
1654 self.ptr_store(mem);
1655 self.instruction(LocalGet(mem.addr.idx));
1656 self.instruction(LocalGet(dst_str.len.idx));
1657 self.ptr_store(&mem.bump(dst_mem_opts.ptr_size().into()));
1658 }
1659 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1660 }
1661
1662 self.free_temp_local(src_str.ptr);
1663 self.free_temp_local(src_str.len);
1664 self.free_temp_local(dst_str.ptr);
1665 self.free_temp_local(dst_str.len);
1666 }
1667
1668 fn string_copy<'c>(
1681 &mut self,
1682 src: &WasmString<'_>,
1683 src_enc: FE,
1684 dst_opts: &'c Options,
1685 dst_enc: FE,
1686 ) -> WasmString<'c> {
1687 assert!(dst_enc.width() >= src_enc.width());
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 (src_byte_len_tmp, src_byte_len) =
1703 self.source_string_byte_len(src, src_enc, src_mem_opts);
1704
1705 self.convert_src_len_to_dst(
1708 src.len.idx,
1709 src.opts.data_model.unwrap_memory().ptr(),
1710 dst_opts.data_model.unwrap_memory().ptr(),
1711 );
1712 let dst_len = self.local_tee_new_tmp(dst_opts.data_model.unwrap_memory().ptr());
1713 if dst_enc.width() > 1 {
1714 assert_eq!(dst_enc.width(), 2);
1715 self.ptr_uconst(dst_mem_opts, 1);
1716 self.ptr_shl(dst_mem_opts);
1717 }
1718 let dst_byte_len = self.local_set_new_tmp(dst_opts.data_model.unwrap_memory().ptr());
1719
1720 let dst = {
1723 let dst_mem = self.malloc(
1724 dst_opts,
1725 MallocSize::Local(dst_byte_len.idx),
1726 dst_enc.width().into(),
1727 );
1728 WasmString {
1729 ptr: dst_mem.addr,
1730 len: dst_len,
1731 opts: dst_opts,
1732 }
1733 };
1734
1735 self.validate_string_inbounds(src, src_byte_len);
1740 self.validate_string_inbounds(&dst, dst_byte_len.idx);
1741
1742 let op = if src_enc == dst_enc {
1746 Transcode::Copy(src_enc)
1747 } else {
1748 assert_eq!(src_enc, FE::Latin1);
1749 assert_eq!(dst_enc, FE::Utf16);
1750 Transcode::Latin1ToUtf16
1751 };
1752 let transcode = self.transcoder(src, &dst, op);
1753 self.instruction(LocalGet(src.ptr.idx));
1754 self.instruction(LocalGet(src.len.idx));
1755 self.instruction(LocalGet(dst.ptr.idx));
1756 self.instruction(Call(transcode.as_u32()));
1757
1758 self.free_temp_local(dst_byte_len);
1759 if let Some(tmp) = src_byte_len_tmp {
1760 self.free_temp_local(tmp);
1761 }
1762
1763 dst
1764 }
1765
1766 fn source_string_byte_len(
1774 &mut self,
1775 src: &WasmString<'_>,
1776 src_enc: FE,
1777 src_mem_opts: &LinearMemoryOptions,
1778 ) -> (Option<TempLocal>, u32) {
1779 self.validate_string_length(src, src_enc);
1780
1781 if src_enc.width() == 1 {
1782 (None, src.len.idx)
1783 } else {
1784 assert_eq!(src_enc.width(), 2);
1785
1786 self.instruction(LocalGet(src.len.idx));
1789 self.ptr_uconst(src_mem_opts, 1);
1790 self.ptr_shl(src_mem_opts);
1791 let tmp = self.local_set_new_tmp(src.opts.data_model.unwrap_memory().ptr());
1792
1793 let idx = tmp.idx;
1794 (Some(tmp), idx)
1795 }
1796 }
1797
1798 fn string_deflate_to_utf8<'c>(
1811 &mut self,
1812 src: &WasmString<'_>,
1813 src_enc: FE,
1814 dst_opts: &'c Options,
1815 ) -> WasmString<'c> {
1816 let src_mem_opts = match &src.opts.data_model {
1817 DataModel::Gc {} => todo!("CM+GC"),
1818 DataModel::LinearMemory(opts) => opts,
1819 };
1820 let dst_mem_opts = match &dst_opts.data_model {
1821 DataModel::Gc {} => todo!("CM+GC"),
1822 DataModel::LinearMemory(opts) => opts,
1823 };
1824
1825 self.validate_string_length(src, src_enc);
1826
1827 self.convert_src_len_to_dst(
1831 src.len.idx,
1832 src.opts.data_model.unwrap_memory().ptr(),
1833 dst_opts.data_model.unwrap_memory().ptr(),
1834 );
1835 let dst_len = self.local_tee_new_tmp(dst_opts.data_model.unwrap_memory().ptr());
1836 let dst_byte_len = self.local_set_new_tmp(dst_opts.data_model.unwrap_memory().ptr());
1837
1838 let dst = {
1839 let dst_mem = self.malloc(dst_opts, MallocSize::Local(dst_byte_len.idx), 1);
1840 WasmString {
1841 ptr: dst_mem.addr,
1842 len: dst_len,
1843 opts: dst_opts,
1844 }
1845 };
1846
1847 let mut src_byte_len_tmp = None;
1849 let src_byte_len = match src_enc {
1850 FE::Latin1 => src.len.idx,
1851 FE::Utf16 => {
1852 self.instruction(LocalGet(src.len.idx));
1853 self.ptr_uconst(src_mem_opts, 1);
1854 self.ptr_shl(src_mem_opts);
1855 let tmp = self.local_set_new_tmp(src.opts.data_model.unwrap_memory().ptr());
1856 let ret = tmp.idx;
1857 src_byte_len_tmp = Some(tmp);
1858 ret
1859 }
1860 FE::Utf8 => unreachable!(),
1861 };
1862 self.validate_string_inbounds(src, src_byte_len);
1863 self.validate_string_inbounds(&dst, dst_byte_len.idx);
1864
1865 let op = match src_enc {
1867 FE::Latin1 => Transcode::Latin1ToUtf8,
1868 FE::Utf16 => Transcode::Utf16ToUtf8,
1869 FE::Utf8 => unreachable!(),
1870 };
1871 let transcode = self.transcoder(src, &dst, op);
1872 self.instruction(LocalGet(src.ptr.idx));
1873 self.instruction(LocalGet(src.len.idx));
1874 self.instruction(LocalGet(dst.ptr.idx));
1875 self.instruction(LocalGet(dst_byte_len.idx));
1876 self.instruction(Call(transcode.as_u32()));
1877 self.instruction(LocalSet(dst.len.idx));
1878 let src_len_tmp = self.local_set_new_tmp(src.opts.data_model.unwrap_memory().ptr());
1879
1880 self.instruction(LocalGet(src_len_tmp.idx));
1884 self.instruction(LocalGet(src.len.idx));
1885 self.ptr_ne(src_mem_opts);
1886 self.instruction(If(BlockType::Empty));
1887
1888 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 {
1895 FE::Latin1 => 2,
1896 FE::Utf16 => 3,
1897 _ => unreachable!(),
1898 };
1899 self.validate_string_length_u8(src, factor);
1900 self.convert_src_len_to_dst(
1901 src.len.idx,
1902 src.opts.data_model.unwrap_memory().ptr(),
1903 dst_opts.data_model.unwrap_memory().ptr(),
1904 );
1905 self.ptr_uconst(dst_mem_opts, factor.into());
1906 self.ptr_mul(dst_mem_opts);
1907 self.instruction(LocalTee(dst_byte_len.idx));
1908 self.instruction(Call(dst_mem_opts.realloc.unwrap().as_u32()));
1909 self.instruction(LocalSet(dst.ptr.idx));
1910
1911 self.validate_string_inbounds(&dst, dst_byte_len.idx);
1913
1914 self.instruction(LocalGet(src.ptr.idx));
1919 self.instruction(LocalGet(src_len_tmp.idx));
1920 if let FE::Utf16 = src_enc {
1921 self.ptr_uconst(src_mem_opts, 1);
1922 self.ptr_shl(src_mem_opts);
1923 }
1924 self.ptr_add(src_mem_opts);
1925 self.instruction(LocalGet(src.len.idx));
1926 self.instruction(LocalGet(src_len_tmp.idx));
1927 self.ptr_sub(src_mem_opts);
1928 self.instruction(LocalGet(dst.ptr.idx));
1929 self.instruction(LocalGet(dst.len.idx));
1930 self.ptr_add(dst_mem_opts);
1931 self.instruction(LocalGet(dst_byte_len.idx));
1932 self.instruction(LocalGet(dst.len.idx));
1933 self.ptr_sub(dst_mem_opts);
1934 self.instruction(Call(transcode.as_u32()));
1935
1936 self.instruction(LocalGet(dst.len.idx));
1940 self.ptr_add(dst_mem_opts);
1941 self.instruction(LocalSet(dst.len.idx));
1942
1943 if self.module.debug {
1946 self.instruction(LocalGet(src.len.idx));
1947 self.instruction(LocalGet(src_len_tmp.idx));
1948 self.ptr_sub(src_mem_opts);
1949 self.ptr_ne(src_mem_opts);
1950 self.instruction(If(BlockType::Empty));
1951 self.trap(Trap::AssertFailed("should have finished encoding"));
1952 self.instruction(End);
1953 } else {
1954 self.instruction(Drop);
1955 }
1956
1957 self.instruction(LocalGet(dst.len.idx));
1959 self.instruction(LocalGet(dst_byte_len.idx));
1960 self.ptr_ne(dst_mem_opts);
1961 self.instruction(If(BlockType::Empty));
1962 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()));
1967 self.instruction(LocalSet(dst.ptr.idx));
1968 self.instruction(End);
1969
1970 if self.module.debug {
1973 self.instruction(Else);
1974
1975 self.instruction(LocalGet(dst.len.idx));
1976 self.instruction(LocalGet(dst_byte_len.idx));
1977 self.ptr_ne(dst_mem_opts);
1978 self.instruction(If(BlockType::Empty));
1979 self.trap(Trap::AssertFailed("should have finished encoding"));
1980 self.instruction(End);
1981 }
1982
1983 self.instruction(End); self.free_temp_local(src_len_tmp);
1986 self.free_temp_local(dst_byte_len);
1987 if let Some(tmp) = src_byte_len_tmp {
1988 self.free_temp_local(tmp);
1989 }
1990
1991 dst
1992 }
1993
1994 fn string_utf8_to_utf16<'c>(
2009 &mut self,
2010 src: &WasmString<'_>,
2011 dst_opts: &'c Options,
2012 ) -> WasmString<'c> {
2013 let src_mem_opts = match &src.opts.data_model {
2014 DataModel::Gc {} => todo!("CM+GC"),
2015 DataModel::LinearMemory(opts) => opts,
2016 };
2017 let dst_mem_opts = match &dst_opts.data_model {
2018 DataModel::Gc {} => todo!("CM+GC"),
2019 DataModel::LinearMemory(opts) => opts,
2020 };
2021
2022 self.validate_string_length(src, FE::Utf16);
2023 self.convert_src_len_to_dst(
2024 src.len.idx,
2025 src_mem_opts.ptr(),
2026 dst_opts.data_model.unwrap_memory().ptr(),
2027 );
2028 let dst_len = self.local_tee_new_tmp(dst_opts.data_model.unwrap_memory().ptr());
2029 self.ptr_uconst(dst_mem_opts, 1);
2030 self.ptr_shl(dst_mem_opts);
2031 let dst_byte_len = self.local_set_new_tmp(dst_opts.data_model.unwrap_memory().ptr());
2032 let dst = {
2033 let dst_mem = self.malloc(dst_opts, MallocSize::Local(dst_byte_len.idx), 2);
2034 WasmString {
2035 ptr: dst_mem.addr,
2036 len: dst_len,
2037 opts: dst_opts,
2038 }
2039 };
2040
2041 self.validate_string_inbounds(src, src.len.idx);
2042 self.validate_string_inbounds(&dst, dst_byte_len.idx);
2043
2044 let transcode = self.transcoder(src, &dst, Transcode::Utf8ToUtf16);
2045 self.instruction(LocalGet(src.ptr.idx));
2046 self.instruction(LocalGet(src.len.idx));
2047 self.instruction(LocalGet(dst.ptr.idx));
2048 self.instruction(Call(transcode.as_u32()));
2049 self.instruction(LocalSet(dst.len.idx));
2050
2051 self.convert_src_len_to_dst(src.len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2059 self.instruction(LocalGet(dst.len.idx));
2060 self.ptr_ne(dst_mem_opts);
2061 self.instruction(If(BlockType::Empty));
2062 self.instruction(LocalGet(dst.ptr.idx));
2063 self.instruction(LocalGet(dst_byte_len.idx));
2064 self.ptr_uconst(dst_mem_opts, 2);
2065 self.instruction(LocalGet(dst.len.idx));
2066 self.ptr_uconst(dst_mem_opts, 1);
2067 self.ptr_shl(dst_mem_opts);
2068 self.instruction(Call(match dst.opts.data_model {
2069 DataModel::Gc {} => todo!("CM+GC"),
2070 DataModel::LinearMemory(LinearMemoryOptions { realloc, .. }) => {
2071 realloc.unwrap().as_u32()
2072 }
2073 }));
2074 self.instruction(LocalSet(dst.ptr.idx));
2075 self.verify_aligned(dst_opts.data_model.unwrap_memory(), dst.ptr.idx, 2);
2076 self.instruction(End); self.free_temp_local(dst_byte_len);
2079
2080 dst
2081 }
2082
2083 fn string_compact_utf16_to_compact<'c>(
2097 &mut self,
2098 src: &WasmString<'_>,
2099 dst_opts: &'c Options,
2100 ) -> WasmString<'c> {
2101 let src_mem_opts = match &src.opts.data_model {
2102 DataModel::Gc {} => todo!("CM+GC"),
2103 DataModel::LinearMemory(opts) => opts,
2104 };
2105 let dst_mem_opts = match &dst_opts.data_model {
2106 DataModel::Gc {} => todo!("CM+GC"),
2107 DataModel::LinearMemory(opts) => opts,
2108 };
2109
2110 self.validate_string_length(src, FE::Utf16);
2111 self.convert_src_len_to_dst(src.len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2112 let dst_len = self.local_tee_new_tmp(dst_mem_opts.ptr());
2113 self.ptr_uconst(dst_mem_opts, 1);
2114 self.ptr_shl(dst_mem_opts);
2115 let dst_byte_len = self.local_set_new_tmp(dst_mem_opts.ptr());
2116 let dst = {
2117 let dst_mem = self.malloc(dst_opts, MallocSize::Local(dst_byte_len.idx), 2);
2118 WasmString {
2119 ptr: dst_mem.addr,
2120 len: dst_len,
2121 opts: dst_opts,
2122 }
2123 };
2124
2125 self.convert_src_len_to_dst(
2126 dst_byte_len.idx,
2127 dst.opts.data_model.unwrap_memory().ptr(),
2128 src_mem_opts.ptr(),
2129 );
2130 let src_byte_len = self.local_set_new_tmp(src_mem_opts.ptr());
2131
2132 self.validate_string_inbounds(src, src_byte_len.idx);
2133 self.validate_string_inbounds(&dst, dst_byte_len.idx);
2134
2135 let transcode = self.transcoder(src, &dst, Transcode::Utf16ToCompactProbablyUtf16);
2136 self.instruction(LocalGet(src.ptr.idx));
2137 self.instruction(LocalGet(src.len.idx));
2138 self.instruction(LocalGet(dst.ptr.idx));
2139 self.instruction(Call(transcode.as_u32()));
2140 self.instruction(LocalSet(dst.len.idx));
2141
2142 if self.module.debug {
2145 self.instruction(LocalGet(dst.len.idx));
2146 self.ptr_uconst(dst_mem_opts, !UTF16_TAG);
2147 self.ptr_and(dst_mem_opts);
2148 self.convert_src_len_to_dst(src.len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2149 self.ptr_ne(dst_mem_opts);
2150 self.instruction(If(BlockType::Empty));
2151 self.trap(Trap::AssertFailed("expected equal code units"));
2152 self.instruction(End);
2153 }
2154
2155 self.instruction(LocalGet(dst.len.idx));
2159 self.ptr_uconst(dst_mem_opts, UTF16_TAG);
2160 self.ptr_and(dst_mem_opts);
2161 self.ptr_br_if(dst_mem_opts, 0);
2162
2163 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()));
2169 self.instruction(LocalSet(dst.ptr.idx));
2170 self.verify_aligned(dst_opts.data_model.unwrap_memory(), dst.ptr.idx, 2);
2171
2172 self.free_temp_local(dst_byte_len);
2173 self.free_temp_local(src_byte_len);
2174
2175 dst
2176 }
2177
2178 fn string_to_compact<'c>(
2185 &mut self,
2186 src: &WasmString<'_>,
2187 src_enc: FE,
2188 dst_opts: &'c Options,
2189 ) -> WasmString<'c> {
2190 let src_mem_opts = match &src.opts.data_model {
2191 DataModel::Gc {} => todo!("CM+GC"),
2192 DataModel::LinearMemory(opts) => opts,
2193 };
2194 let dst_mem_opts = match &dst_opts.data_model {
2195 DataModel::Gc {} => todo!("CM+GC"),
2196 DataModel::LinearMemory(opts) => opts,
2197 };
2198
2199 let (src_byte_len_tmp, src_byte_len) =
2200 self.source_string_byte_len(src, src_enc, src_mem_opts);
2201
2202 self.convert_src_len_to_dst(src.len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2203 let dst_len = self.local_tee_new_tmp(dst_mem_opts.ptr());
2204 let dst_byte_len = self.local_set_new_tmp(dst_mem_opts.ptr());
2205 let dst = {
2206 let dst_mem = self.malloc(dst_opts, MallocSize::Local(dst_byte_len.idx), 2);
2207 WasmString {
2208 ptr: dst_mem.addr,
2209 len: dst_len,
2210 opts: dst_opts,
2211 }
2212 };
2213
2214 self.validate_string_inbounds(src, src_byte_len);
2215 self.validate_string_inbounds(&dst, dst_byte_len.idx);
2216
2217 let (latin1, utf16) = match src_enc {
2221 FE::Utf8 => (Transcode::Utf8ToLatin1, Transcode::Utf8ToCompactUtf16),
2222 FE::Utf16 => (Transcode::Utf16ToLatin1, Transcode::Utf16ToCompactUtf16),
2223 FE::Latin1 => unreachable!(),
2224 };
2225 let transcode_latin1 = self.transcoder(src, &dst, latin1);
2226 let transcode_utf16 = self.transcoder(src, &dst, utf16);
2227 self.instruction(LocalGet(src.ptr.idx));
2228 self.instruction(LocalGet(src.len.idx));
2229 self.instruction(LocalGet(dst.ptr.idx));
2230 self.instruction(Call(transcode_latin1.as_u32()));
2231 self.instruction(LocalSet(dst.len.idx));
2232 let src_len_tmp = self.local_set_new_tmp(src_mem_opts.ptr());
2233
2234 self.instruction(LocalGet(src_len_tmp.idx));
2237 self.instruction(LocalGet(src.len.idx));
2238 self.ptr_eq(src_mem_opts);
2239 self.instruction(If(BlockType::Empty)); self.instruction(LocalGet(dst_byte_len.idx));
2245 self.instruction(LocalGet(dst.len.idx));
2246 self.ptr_ne(dst_mem_opts);
2247 self.instruction(If(BlockType::Empty));
2248 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()));
2253 self.instruction(LocalSet(dst.ptr.idx));
2254 self.verify_aligned(dst_opts.data_model.unwrap_memory(), dst.ptr.idx, 2);
2255 self.instruction(End);
2256
2257 self.instruction(Else); if src_enc.width() == 1 {
2266 self.validate_string_length_u8(src, 2);
2267 }
2268
2269 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());
2275 self.ptr_uconst(dst_mem_opts, 1);
2276 self.ptr_shl(dst_mem_opts);
2277 self.instruction(LocalTee(dst_byte_len.idx));
2278 self.instruction(Call(dst_mem_opts.realloc.unwrap().as_u32()));
2279 self.instruction(LocalSet(dst.ptr.idx));
2280 self.verify_aligned(dst_opts.data_model.unwrap_memory(), dst.ptr.idx, 2);
2281 self.validate_string_inbounds(&dst, dst_byte_len.idx);
2282
2283 self.instruction(LocalGet(src.ptr.idx));
2287 self.instruction(LocalGet(src_len_tmp.idx));
2288 if let FE::Utf16 = src_enc {
2289 self.ptr_uconst(src_mem_opts, 1);
2290 self.ptr_shl(src_mem_opts);
2291 }
2292 self.ptr_add(src_mem_opts);
2293 self.instruction(LocalGet(src.len.idx));
2294 self.instruction(LocalGet(src_len_tmp.idx));
2295 self.ptr_sub(src_mem_opts);
2296 self.instruction(LocalGet(dst.ptr.idx));
2297 self.convert_src_len_to_dst(src.len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2298 self.instruction(LocalGet(dst.len.idx));
2299 self.instruction(Call(transcode_utf16.as_u32()));
2300 self.instruction(LocalSet(dst.len.idx));
2301
2302 self.instruction(LocalGet(dst.len.idx));
2310 self.convert_src_len_to_dst(src.len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2311 self.ptr_ne(dst_mem_opts);
2312 self.instruction(If(BlockType::Empty));
2313 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));
2317 self.ptr_uconst(dst_mem_opts, 1);
2318 self.ptr_shl(dst_mem_opts);
2319 self.instruction(Call(dst_mem_opts.realloc.unwrap().as_u32()));
2320 self.instruction(LocalSet(dst.ptr.idx));
2321 self.verify_aligned(dst_opts.data_model.unwrap_memory(), dst.ptr.idx, 2);
2322 self.instruction(End);
2323
2324 self.instruction(LocalGet(dst.len.idx));
2326 self.ptr_uconst(dst_mem_opts, UTF16_TAG);
2327 self.ptr_or(dst_mem_opts);
2328 self.instruction(LocalSet(dst.len.idx));
2329
2330 self.instruction(End); self.free_temp_local(src_len_tmp);
2333 self.free_temp_local(dst_byte_len);
2334 if let Some(tmp) = src_byte_len_tmp {
2335 self.free_temp_local(tmp);
2336 }
2337
2338 dst
2339 }
2340
2341 fn validate_string_length(&mut self, src: &WasmString<'_>, dst: FE) {
2342 self.validate_string_length_u8(src, dst.width())
2343 }
2344
2345 fn validate_string_length_u8(&mut self, s: &WasmString<'_>, dst: u8) {
2346 let mem_opts = match &s.opts.data_model {
2347 DataModel::Gc {} => todo!("CM+GC"),
2348 DataModel::LinearMemory(opts) => opts,
2349 };
2350
2351 self.instruction(LocalGet(s.len.idx));
2354 let max = MAX_STRING_BYTE_LENGTH / u32::from(dst);
2355 self.ptr_uconst(mem_opts, max);
2356 self.ptr_ge_u(mem_opts);
2357 self.instruction(If(BlockType::Empty));
2358 self.trap(Trap::StringLengthTooBig);
2359 self.instruction(End);
2360 }
2361
2362 fn transcoder(
2363 &mut self,
2364 src: &WasmString<'_>,
2365 dst: &WasmString<'_>,
2366 op: Transcode,
2367 ) -> FuncIndex {
2368 match (src.opts.data_model, dst.opts.data_model) {
2369 (DataModel::Gc {}, _) | (_, DataModel::Gc {}) => {
2370 todo!("CM+GC")
2371 }
2372 (
2373 DataModel::LinearMemory(LinearMemoryOptions {
2374 memory64: src64,
2375 memory: src_mem,
2376 realloc: _,
2377 }),
2378 DataModel::LinearMemory(LinearMemoryOptions {
2379 memory64: dst64,
2380 memory: dst_mem,
2381 realloc: _,
2382 }),
2383 ) => self.module.import_transcoder(Transcoder {
2384 from_memory: src_mem.unwrap(),
2385 from_memory64: src64,
2386 to_memory: dst_mem.unwrap(),
2387 to_memory64: dst64,
2388 op,
2389 }),
2390 }
2391 }
2392
2393 fn validate_string_inbounds(&mut self, s: &WasmString<'_>, byte_len: u32) {
2394 match &s.opts.data_model {
2395 DataModel::Gc {} => todo!("CM+GC"),
2396 DataModel::LinearMemory(opts) => {
2397 self.validate_memory_inbounds(opts, s.ptr.idx, byte_len, Trap::StringLengthOverflow)
2398 }
2399 }
2400 }
2401
2402 fn validate_memory_inbounds(
2403 &mut self,
2404 opts: &LinearMemoryOptions,
2405 ptr_local: u32,
2406 byte_len_local: u32,
2407 trap: Trap,
2408 ) {
2409 let extend_to_64 = |me: &mut Self| {
2410 if !opts.memory64 {
2411 me.instruction(I64ExtendI32U);
2412 }
2413 };
2414
2415 self.instruction(Block(BlockType::Empty));
2416 self.instruction(Block(BlockType::Empty));
2417
2418 self.instruction(MemorySize(opts.memory.unwrap().as_u32()));
2423 extend_to_64(self);
2424 self.instruction(I64Const(16));
2425 self.instruction(I64Shl);
2426
2427 self.instruction(LocalGet(ptr_local));
2432 extend_to_64(self);
2433 self.instruction(LocalGet(byte_len_local));
2434 extend_to_64(self);
2435 self.instruction(I64Add);
2436 if opts.memory64 {
2437 let tmp = self.local_tee_new_tmp(ValType::I64);
2438 self.instruction(LocalGet(ptr_local));
2439 self.ptr_lt_u(opts);
2440 self.instruction(BrIf(0));
2441 self.instruction(LocalGet(tmp.idx));
2442 self.free_temp_local(tmp);
2443 }
2444
2445 self.instruction(I64GeU);
2449 self.instruction(BrIf(1));
2450
2451 self.instruction(End);
2452 self.trap(trap);
2453 self.instruction(End);
2454 }
2455
2456 fn translate_list(
2457 &mut self,
2458 src_ty: TypeListIndex,
2459 src: &Source<'_>,
2460 dst_ty: &InterfaceType,
2461 dst: &Destination,
2462 ) {
2463 let src_mem_opts = match &src.opts().data_model {
2464 DataModel::Gc {} => todo!("CM+GC"),
2465 DataModel::LinearMemory(opts) => opts,
2466 };
2467 let dst_mem_opts = match &dst.opts().data_model {
2468 DataModel::Gc {} => todo!("CM+GC"),
2469 DataModel::LinearMemory(opts) => opts,
2470 };
2471
2472 let src_element_ty = &self.types[src_ty].element;
2473 let dst_element_ty = match dst_ty {
2474 InterfaceType::List(r) => &self.types[*r].element,
2475 _ => panic!("expected a list"),
2476 };
2477 let src_opts = src.opts();
2478 let dst_opts = dst.opts();
2479 let (src_size, src_align) = self.types.size_align(src_mem_opts, src_element_ty);
2480 let (dst_size, dst_align) = self.types.size_align(dst_mem_opts, dst_element_ty);
2481
2482 match src {
2487 Source::Stack(s) => {
2488 assert_eq!(s.locals.len(), 2);
2489 self.stack_get(&s.slice(0..1), src_mem_opts.ptr());
2490 self.stack_get(&s.slice(1..2), src_mem_opts.ptr());
2491 }
2492 Source::Memory(mem) => {
2493 self.ptr_load(mem);
2494 self.ptr_load(&mem.bump(src_mem_opts.ptr_size().into()));
2495 }
2496 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
2497 }
2498 let src_len = self.local_set_new_tmp(src_mem_opts.ptr());
2499 let src_ptr = self.local_set_new_tmp(src_mem_opts.ptr());
2500
2501 let src_mem = self.memory_operand(src_opts, src_ptr, src_align);
2504
2505 let src_byte_len = self.calculate_list_byte_len(src_mem_opts, src_len.idx, src_size);
2507 let dst_byte_len = if src_size == dst_size {
2508 self.convert_src_len_to_dst(src_byte_len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2509 self.local_set_new_tmp(dst_mem_opts.ptr())
2510 } else if src_mem_opts.ptr() == dst_mem_opts.ptr() {
2511 self.calculate_list_byte_len(dst_mem_opts, src_len.idx, dst_size)
2512 } else {
2513 self.convert_src_len_to_dst(src_byte_len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2514 let tmp = self.local_set_new_tmp(dst_mem_opts.ptr());
2515 let ret = self.calculate_list_byte_len(dst_mem_opts, tmp.idx, dst_size);
2516 self.free_temp_local(tmp);
2517 ret
2518 };
2519
2520 let dst_mem = self.malloc(dst_opts, MallocSize::Local(dst_byte_len.idx), dst_align);
2525
2526 self.validate_memory_inbounds(
2529 src_mem_opts,
2530 src_mem.addr.idx,
2531 src_byte_len.idx,
2532 Trap::ListByteLengthOverflow,
2533 );
2534 self.validate_memory_inbounds(
2535 dst_mem_opts,
2536 dst_mem.addr.idx,
2537 dst_byte_len.idx,
2538 Trap::ListByteLengthOverflow,
2539 );
2540
2541 self.free_temp_local(src_byte_len);
2542 self.free_temp_local(dst_byte_len);
2543
2544 if src_size > 0 || dst_size > 0 {
2548 self.instruction(Block(BlockType::Empty));
2551
2552 self.instruction(LocalGet(src_len.idx));
2554 let remaining = self.local_tee_new_tmp(src_mem_opts.ptr());
2555 self.ptr_eqz(src_mem_opts);
2556 self.instruction(BrIf(0));
2557
2558 self.instruction(LocalGet(src_mem.addr.idx));
2560 let cur_src_ptr = self.local_set_new_tmp(src_mem_opts.ptr());
2561 self.instruction(LocalGet(dst_mem.addr.idx));
2562 let cur_dst_ptr = self.local_set_new_tmp(dst_mem_opts.ptr());
2563
2564 self.instruction(Loop(BlockType::Empty));
2565
2566 let element_src = Source::Memory(Memory {
2568 opts: src_opts,
2569 offset: 0,
2570 addr: TempLocal::new(cur_src_ptr.idx, cur_src_ptr.ty),
2571 });
2572 let element_dst = Destination::Memory(Memory {
2573 opts: dst_opts,
2574 offset: 0,
2575 addr: TempLocal::new(cur_dst_ptr.idx, cur_dst_ptr.ty),
2576 });
2577 self.translate(src_element_ty, &element_src, dst_element_ty, &element_dst);
2578
2579 if src_size > 0 {
2581 self.instruction(LocalGet(cur_src_ptr.idx));
2582 self.ptr_uconst(src_mem_opts, src_size);
2583 self.ptr_add(src_mem_opts);
2584 self.instruction(LocalSet(cur_src_ptr.idx));
2585 }
2586 if dst_size > 0 {
2587 self.instruction(LocalGet(cur_dst_ptr.idx));
2588 self.ptr_uconst(dst_mem_opts, dst_size);
2589 self.ptr_add(dst_mem_opts);
2590 self.instruction(LocalSet(cur_dst_ptr.idx));
2591 }
2592
2593 self.instruction(LocalGet(remaining.idx));
2596 self.ptr_iconst(src_mem_opts, -1);
2597 self.ptr_add(src_mem_opts);
2598 self.instruction(LocalTee(remaining.idx));
2599 self.ptr_br_if(src_mem_opts, 0);
2600 self.instruction(End); self.instruction(End); self.free_temp_local(cur_dst_ptr);
2604 self.free_temp_local(cur_src_ptr);
2605 self.free_temp_local(remaining);
2606 }
2607
2608 match dst {
2610 Destination::Stack(s, _) => {
2611 self.instruction(LocalGet(dst_mem.addr.idx));
2612 self.stack_set(&s[..1], dst_mem_opts.ptr());
2613 self.convert_src_len_to_dst(src_len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2614 self.stack_set(&s[1..], dst_mem_opts.ptr());
2615 }
2616 Destination::Memory(mem) => {
2617 self.instruction(LocalGet(mem.addr.idx));
2618 self.instruction(LocalGet(dst_mem.addr.idx));
2619 self.ptr_store(mem);
2620 self.instruction(LocalGet(mem.addr.idx));
2621 self.convert_src_len_to_dst(src_len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2622 self.ptr_store(&mem.bump(dst_mem_opts.ptr_size().into()));
2623 }
2624 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
2625 }
2626
2627 self.free_temp_local(src_len);
2628 self.free_temp_local(src_mem.addr);
2629 self.free_temp_local(dst_mem.addr);
2630 }
2631
2632 fn calculate_list_byte_len(
2633 &mut self,
2634 opts: &LinearMemoryOptions,
2635 len_local: u32,
2636 elt_size: u32,
2637 ) -> TempLocal {
2638 if elt_size == 0 {
2641 self.ptr_uconst(opts, 0);
2642 return self.local_set_new_tmp(opts.ptr());
2643 }
2644
2645 if elt_size == 1 {
2653 if let ValType::I64 = opts.ptr() {
2654 self.instruction(LocalGet(len_local));
2655 self.instruction(I64Const(32));
2656 self.instruction(I64ShrU);
2657 self.instruction(I32WrapI64);
2658 self.instruction(If(BlockType::Empty));
2659 self.trap(Trap::ListByteLengthOverflow);
2660 self.instruction(End);
2661 }
2662 self.instruction(LocalGet(len_local));
2663 return self.local_set_new_tmp(opts.ptr());
2664 }
2665
2666 self.instruction(Block(BlockType::Empty));
2671 self.instruction(Block(BlockType::Empty));
2672 self.instruction(LocalGet(len_local));
2673 match opts.ptr() {
2674 ValType::I32 => self.instruction(I64ExtendI32U),
2678
2679 ValType::I64 => {
2683 self.instruction(I64Const(32));
2684 self.instruction(I64ShrU);
2685 self.instruction(I32WrapI64);
2686 self.instruction(BrIf(0));
2687 self.instruction(LocalGet(len_local));
2688 }
2689
2690 _ => unreachable!(),
2691 }
2692
2693 self.instruction(I64Const(elt_size.into()));
2702 self.instruction(I64Mul);
2703 let tmp = self.local_tee_new_tmp(ValType::I64);
2704 self.instruction(I64Const(32));
2707 self.instruction(I64ShrU);
2708 self.instruction(I64Eqz);
2709 self.instruction(BrIf(1));
2710 self.instruction(End);
2711 self.trap(Trap::ListByteLengthOverflow);
2712 self.instruction(End);
2713
2714 if opts.ptr() == ValType::I64 {
2718 tmp
2719 } else {
2720 self.instruction(LocalGet(tmp.idx));
2721 self.instruction(I32WrapI64);
2722 self.free_temp_local(tmp);
2723 self.local_set_new_tmp(ValType::I32)
2724 }
2725 }
2726
2727 fn convert_src_len_to_dst(
2728 &mut self,
2729 src_len_local: u32,
2730 src_ptr_ty: ValType,
2731 dst_ptr_ty: ValType,
2732 ) {
2733 self.instruction(LocalGet(src_len_local));
2734 match (src_ptr_ty, dst_ptr_ty) {
2735 (ValType::I32, ValType::I64) => self.instruction(I64ExtendI32U),
2736 (ValType::I64, ValType::I32) => self.instruction(I32WrapI64),
2737 (src, dst) => assert_eq!(src, dst),
2738 }
2739 }
2740
2741 fn translate_record(
2742 &mut self,
2743 src_ty: TypeRecordIndex,
2744 src: &Source<'_>,
2745 dst_ty: &InterfaceType,
2746 dst: &Destination,
2747 ) {
2748 let src_ty = &self.types[src_ty];
2749 let dst_ty = match dst_ty {
2750 InterfaceType::Record(r) => &self.types[*r],
2751 _ => panic!("expected a record"),
2752 };
2753
2754 assert_eq!(src_ty.fields.len(), dst_ty.fields.len());
2756
2757 let mut src_fields = HashMap::new();
2761 for (i, src) in src
2762 .record_field_srcs(self.types, src_ty.fields.iter().map(|f| f.ty))
2763 .enumerate()
2764 {
2765 let field = &src_ty.fields[i];
2766 src_fields.insert(&field.name, (src, &field.ty));
2767 }
2768
2769 for (i, dst) in dst
2778 .record_field_dsts(self.types, dst_ty.fields.iter().map(|f| f.ty))
2779 .enumerate()
2780 {
2781 let field = &dst_ty.fields[i];
2782 let (src, src_ty) = &src_fields[&field.name];
2783 self.translate(src_ty, src, &field.ty, &dst);
2784 }
2785 }
2786
2787 fn translate_flags(
2788 &mut self,
2789 src_ty: TypeFlagsIndex,
2790 src: &Source<'_>,
2791 dst_ty: &InterfaceType,
2792 dst: &Destination,
2793 ) {
2794 let src_ty = &self.types[src_ty];
2795 let dst_ty = match dst_ty {
2796 InterfaceType::Flags(r) => &self.types[*r],
2797 _ => panic!("expected a record"),
2798 };
2799
2800 assert_eq!(src_ty.names, dst_ty.names);
2808 let cnt = src_ty.names.len();
2809 match FlagsSize::from_count(cnt) {
2810 FlagsSize::Size0 => {}
2811 FlagsSize::Size1 => {
2812 let mask = if cnt == 8 { 0xff } else { (1 << cnt) - 1 };
2813 self.convert_u8_mask(src, dst, mask);
2814 }
2815 FlagsSize::Size2 => {
2816 let mask = if cnt == 16 { 0xffff } else { (1 << cnt) - 1 };
2817 self.convert_u16_mask(src, dst, mask);
2818 }
2819 FlagsSize::Size4Plus(n) => {
2820 let srcs = src.record_field_srcs(self.types, (0..n).map(|_| InterfaceType::U32));
2821 let dsts = dst.record_field_dsts(self.types, (0..n).map(|_| InterfaceType::U32));
2822 let n = usize::from(n);
2823 for (i, (src, dst)) in srcs.zip(dsts).enumerate() {
2824 let mask = if i == n - 1 && (cnt % 32 != 0) {
2825 (1 << (cnt % 32)) - 1
2826 } else {
2827 0xffffffff
2828 };
2829 self.convert_u32_mask(&src, &dst, mask);
2830 }
2831 }
2832 }
2833 }
2834
2835 fn translate_tuple(
2836 &mut self,
2837 src_ty: TypeTupleIndex,
2838 src: &Source<'_>,
2839 dst_ty: &InterfaceType,
2840 dst: &Destination,
2841 ) {
2842 let src_ty = &self.types[src_ty];
2843 let dst_ty = match dst_ty {
2844 InterfaceType::Tuple(t) => &self.types[*t],
2845 _ => panic!("expected a tuple"),
2846 };
2847
2848 assert_eq!(src_ty.types.len(), dst_ty.types.len());
2850
2851 let srcs = src
2852 .record_field_srcs(self.types, src_ty.types.iter().copied())
2853 .zip(src_ty.types.iter());
2854 let dsts = dst
2855 .record_field_dsts(self.types, dst_ty.types.iter().copied())
2856 .zip(dst_ty.types.iter());
2857 for ((src, src_ty), (dst, dst_ty)) in srcs.zip(dsts) {
2858 self.translate(src_ty, &src, dst_ty, &dst);
2859 }
2860 }
2861
2862 fn translate_variant(
2863 &mut self,
2864 src_ty: TypeVariantIndex,
2865 src: &Source<'_>,
2866 dst_ty: &InterfaceType,
2867 dst: &Destination,
2868 ) {
2869 let src_ty = &self.types[src_ty];
2870 let dst_ty = match dst_ty {
2871 InterfaceType::Variant(t) => &self.types[*t],
2872 _ => panic!("expected a variant"),
2873 };
2874
2875 let src_info = variant_info(self.types, src_ty.cases.iter().map(|(_, c)| c.as_ref()));
2876 let dst_info = variant_info(self.types, dst_ty.cases.iter().map(|(_, c)| c.as_ref()));
2877
2878 let iter = src_ty
2879 .cases
2880 .iter()
2881 .enumerate()
2882 .map(|(src_i, (src_case, src_case_ty))| {
2883 let dst_i = dst_ty
2884 .cases
2885 .iter()
2886 .position(|(c, _)| c == src_case)
2887 .unwrap();
2888 let dst_case_ty = &dst_ty.cases[dst_i];
2889 let src_i = u32::try_from(src_i).unwrap();
2890 let dst_i = u32::try_from(dst_i).unwrap();
2891 VariantCase {
2892 src_i,
2893 src_ty: src_case_ty.as_ref(),
2894 dst_i,
2895 dst_ty: dst_case_ty.as_ref(),
2896 }
2897 });
2898 self.convert_variant(src, &src_info, dst, &dst_info, iter);
2899 }
2900
2901 fn translate_enum(
2902 &mut self,
2903 src_ty: TypeEnumIndex,
2904 src: &Source<'_>,
2905 dst_ty: &InterfaceType,
2906 dst: &Destination,
2907 ) {
2908 let src_ty = &self.types[src_ty];
2909 let dst_ty = match dst_ty {
2910 InterfaceType::Enum(t) => &self.types[*t],
2911 _ => panic!("expected an option"),
2912 };
2913
2914 debug_assert_eq!(src_ty.info.size, dst_ty.info.size);
2915 debug_assert_eq!(src_ty.names.len(), dst_ty.names.len());
2916 debug_assert!(
2917 src_ty
2918 .names
2919 .iter()
2920 .zip(dst_ty.names.iter())
2921 .all(|(a, b)| a == b)
2922 );
2923
2924 match src {
2926 Source::Stack(s) => self.stack_get(&s.slice(0..1), ValType::I32),
2927 Source::Memory(mem) => match src_ty.info.size {
2928 DiscriminantSize::Size1 => self.i32_load8u(mem),
2929 DiscriminantSize::Size2 => self.i32_load16u(mem),
2930 DiscriminantSize::Size4 => self.i32_load(mem),
2931 },
2932 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
2933 }
2934 let tmp = self.local_tee_new_tmp(ValType::I32);
2935
2936 self.instruction(I32Const(i32::try_from(src_ty.names.len()).unwrap()));
2938 self.instruction(I32GtU);
2939 self.instruction(If(BlockType::Empty));
2940 self.trap(Trap::InvalidDiscriminant);
2941 self.instruction(End);
2942
2943 match dst {
2945 Destination::Stack(stack, _) => {
2946 self.local_get_tmp(&tmp);
2947 self.stack_set(&stack[..1], ValType::I32)
2948 }
2949 Destination::Memory(mem) => {
2950 self.push_dst_addr(dst);
2951 self.local_get_tmp(&tmp);
2952 match dst_ty.info.size {
2953 DiscriminantSize::Size1 => self.i32_store8(mem),
2954 DiscriminantSize::Size2 => self.i32_store16(mem),
2955 DiscriminantSize::Size4 => self.i32_store(mem),
2956 }
2957 }
2958 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
2959 }
2960 self.free_temp_local(tmp);
2961 }
2962
2963 fn translate_option(
2964 &mut self,
2965 src_ty: TypeOptionIndex,
2966 src: &Source<'_>,
2967 dst_ty: &InterfaceType,
2968 dst: &Destination,
2969 ) {
2970 let src_ty = &self.types[src_ty].ty;
2971 let dst_ty = match dst_ty {
2972 InterfaceType::Option(t) => &self.types[*t].ty,
2973 _ => panic!("expected an option"),
2974 };
2975 let src_ty = Some(src_ty);
2976 let dst_ty = Some(dst_ty);
2977
2978 let src_info = variant_info(self.types, [None, src_ty]);
2979 let dst_info = variant_info(self.types, [None, dst_ty]);
2980
2981 self.convert_variant(
2982 src,
2983 &src_info,
2984 dst,
2985 &dst_info,
2986 [
2987 VariantCase {
2988 src_i: 0,
2989 dst_i: 0,
2990 src_ty: None,
2991 dst_ty: None,
2992 },
2993 VariantCase {
2994 src_i: 1,
2995 dst_i: 1,
2996 src_ty,
2997 dst_ty,
2998 },
2999 ]
3000 .into_iter(),
3001 );
3002 }
3003
3004 fn translate_result(
3005 &mut self,
3006 src_ty: TypeResultIndex,
3007 src: &Source<'_>,
3008 dst_ty: &InterfaceType,
3009 dst: &Destination,
3010 ) {
3011 let src_ty = &self.types[src_ty];
3012 let dst_ty = match dst_ty {
3013 InterfaceType::Result(t) => &self.types[*t],
3014 _ => panic!("expected a result"),
3015 };
3016
3017 let src_info = variant_info(self.types, [src_ty.ok.as_ref(), src_ty.err.as_ref()]);
3018 let dst_info = variant_info(self.types, [dst_ty.ok.as_ref(), dst_ty.err.as_ref()]);
3019
3020 self.convert_variant(
3021 src,
3022 &src_info,
3023 dst,
3024 &dst_info,
3025 [
3026 VariantCase {
3027 src_i: 0,
3028 dst_i: 0,
3029 src_ty: src_ty.ok.as_ref(),
3030 dst_ty: dst_ty.ok.as_ref(),
3031 },
3032 VariantCase {
3033 src_i: 1,
3034 dst_i: 1,
3035 src_ty: src_ty.err.as_ref(),
3036 dst_ty: dst_ty.err.as_ref(),
3037 },
3038 ]
3039 .into_iter(),
3040 );
3041 }
3042
3043 fn convert_variant<'c>(
3044 &mut self,
3045 src: &Source<'_>,
3046 src_info: &VariantInfo,
3047 dst: &Destination,
3048 dst_info: &VariantInfo,
3049 src_cases: impl ExactSizeIterator<Item = VariantCase<'c>>,
3050 ) {
3051 let outer_block_ty = match dst {
3054 Destination::Stack(dst_flat, _) => match dst_flat.len() {
3055 0 => BlockType::Empty,
3056 1 => BlockType::Result(dst_flat[0]),
3057 _ => {
3058 let ty = self.module.core_types.function(&[], &dst_flat);
3059 BlockType::FunctionType(ty)
3060 }
3061 },
3062 Destination::Memory(_) => BlockType::Empty,
3063 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
3064 };
3065 self.instruction(Block(outer_block_ty));
3066
3067 let src_cases_len = src_cases.len();
3070 for _ in 0..src_cases_len - 1 {
3071 self.instruction(Block(BlockType::Empty));
3072 }
3073
3074 self.instruction(Block(BlockType::Empty));
3076
3077 self.instruction(Block(BlockType::Empty));
3080
3081 match src {
3083 Source::Stack(s) => self.stack_get(&s.slice(0..1), ValType::I32),
3084 Source::Memory(mem) => match src_info.size {
3085 DiscriminantSize::Size1 => self.i32_load8u(mem),
3086 DiscriminantSize::Size2 => self.i32_load16u(mem),
3087 DiscriminantSize::Size4 => self.i32_load(mem),
3088 },
3089 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
3090 }
3091
3092 let mut targets = Vec::new();
3095 for i in 0..src_cases_len {
3096 targets.push((i + 1) as u32);
3097 }
3098 self.instruction(BrTable(targets[..].into(), 0));
3099 self.instruction(End); self.trap(Trap::InvalidDiscriminant);
3102 self.instruction(End); let src_cases_len = u32::try_from(src_cases_len).unwrap();
3109 for case in src_cases {
3110 let VariantCase {
3111 src_i,
3112 src_ty,
3113 dst_i,
3114 dst_ty,
3115 } = case;
3116
3117 self.push_dst_addr(dst);
3120 self.instruction(I32Const(dst_i as i32));
3121 match dst {
3122 Destination::Stack(stack, _) => self.stack_set(&stack[..1], ValType::I32),
3123 Destination::Memory(mem) => match dst_info.size {
3124 DiscriminantSize::Size1 => self.i32_store8(mem),
3125 DiscriminantSize::Size2 => self.i32_store16(mem),
3126 DiscriminantSize::Size4 => self.i32_store(mem),
3127 },
3128 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
3129 }
3130
3131 let src_payload = src.payload_src(self.types, src_info, src_ty);
3132 let dst_payload = dst.payload_dst(self.types, dst_info, dst_ty);
3133
3134 match (src_ty, dst_ty) {
3137 (Some(src_ty), Some(dst_ty)) => {
3138 self.translate(src_ty, &src_payload, dst_ty, &dst_payload);
3139 }
3140 (None, None) => {}
3141 _ => unimplemented!(),
3142 }
3143
3144 if let Destination::Stack(payload_results, _) = dst_payload {
3151 if let Destination::Stack(dst_results, _) = dst {
3152 let remaining = &dst_results[1..][payload_results.len()..];
3153 for ty in remaining {
3154 match ty {
3155 ValType::I32 => self.instruction(I32Const(0)),
3156 ValType::I64 => self.instruction(I64Const(0)),
3157 ValType::F32 => self.instruction(F32Const(0.0.into())),
3158 ValType::F64 => self.instruction(F64Const(0.0.into())),
3159 _ => unreachable!(),
3160 }
3161 }
3162 }
3163 }
3164
3165 if src_i != src_cases_len - 1 {
3168 self.instruction(Br(src_cases_len - src_i - 1));
3169 }
3170 self.instruction(End); }
3172 }
3173
3174 fn translate_future(
3175 &mut self,
3176 src_ty: TypeFutureTableIndex,
3177 src: &Source<'_>,
3178 dst_ty: &InterfaceType,
3179 dst: &Destination,
3180 ) {
3181 let dst_ty = match dst_ty {
3182 InterfaceType::Future(t) => *t,
3183 _ => panic!("expected a `Future`"),
3184 };
3185 let transfer = self.module.import_future_transfer();
3186 self.translate_handle(src_ty.as_u32(), src, dst_ty.as_u32(), dst, transfer);
3187 }
3188
3189 fn translate_stream(
3190 &mut self,
3191 src_ty: TypeStreamTableIndex,
3192 src: &Source<'_>,
3193 dst_ty: &InterfaceType,
3194 dst: &Destination,
3195 ) {
3196 let dst_ty = match dst_ty {
3197 InterfaceType::Stream(t) => *t,
3198 _ => panic!("expected a `Stream`"),
3199 };
3200 let transfer = self.module.import_stream_transfer();
3201 self.translate_handle(src_ty.as_u32(), src, dst_ty.as_u32(), dst, transfer);
3202 }
3203
3204 fn translate_error_context(
3205 &mut self,
3206 src_ty: TypeComponentLocalErrorContextTableIndex,
3207 src: &Source<'_>,
3208 dst_ty: &InterfaceType,
3209 dst: &Destination,
3210 ) {
3211 let dst_ty = match dst_ty {
3212 InterfaceType::ErrorContext(t) => *t,
3213 _ => panic!("expected an `ErrorContext`"),
3214 };
3215 let transfer = self.module.import_error_context_transfer();
3216 self.translate_handle(src_ty.as_u32(), src, dst_ty.as_u32(), dst, transfer);
3217 }
3218
3219 fn translate_own(
3220 &mut self,
3221 src_ty: TypeResourceTableIndex,
3222 src: &Source<'_>,
3223 dst_ty: &InterfaceType,
3224 dst: &Destination,
3225 ) {
3226 let dst_ty = match dst_ty {
3227 InterfaceType::Own(t) => *t,
3228 _ => panic!("expected an `Own`"),
3229 };
3230 let transfer = self.module.import_resource_transfer_own();
3231 self.translate_handle(src_ty.as_u32(), src, dst_ty.as_u32(), dst, transfer);
3232 }
3233
3234 fn translate_borrow(
3235 &mut self,
3236 src_ty: TypeResourceTableIndex,
3237 src: &Source<'_>,
3238 dst_ty: &InterfaceType,
3239 dst: &Destination,
3240 ) {
3241 let dst_ty = match dst_ty {
3242 InterfaceType::Borrow(t) => *t,
3243 _ => panic!("expected an `Borrow`"),
3244 };
3245
3246 let transfer = self.module.import_resource_transfer_borrow();
3247 self.translate_handle(src_ty.as_u32(), src, dst_ty.as_u32(), dst, transfer);
3248 }
3249
3250 fn translate_handle(
3258 &mut self,
3259 src_ty: u32,
3260 src: &Source<'_>,
3261 dst_ty: u32,
3262 dst: &Destination,
3263 transfer: FuncIndex,
3264 ) {
3265 self.push_dst_addr(dst);
3266 match src {
3267 Source::Memory(mem) => self.i32_load(mem),
3268 Source::Stack(stack) => self.stack_get(stack, ValType::I32),
3269 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
3270 }
3271 self.instruction(I32Const(src_ty as i32));
3272 self.instruction(I32Const(dst_ty as i32));
3273 self.instruction(Call(transfer.as_u32()));
3274 match dst {
3275 Destination::Memory(mem) => self.i32_store(mem),
3276 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
3277 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
3278 }
3279 }
3280
3281 fn trap_if_not_flag(&mut self, flags_global: GlobalIndex, flag_to_test: i32, trap: Trap) {
3282 self.instruction(GlobalGet(flags_global.as_u32()));
3283 self.instruction(I32Const(flag_to_test));
3284 self.instruction(I32And);
3285 self.instruction(I32Eqz);
3286 self.instruction(If(BlockType::Empty));
3287 self.trap(trap);
3288 self.instruction(End);
3289 }
3290
3291 fn assert_not_flag(&mut self, flags_global: GlobalIndex, flag_to_test: i32, msg: &'static str) {
3292 self.instruction(GlobalGet(flags_global.as_u32()));
3293 self.instruction(I32Const(flag_to_test));
3294 self.instruction(I32And);
3295 self.instruction(If(BlockType::Empty));
3296 self.trap(Trap::AssertFailed(msg));
3297 self.instruction(End);
3298 }
3299
3300 fn set_flag(&mut self, flags_global: GlobalIndex, flag_to_set: i32, value: bool) {
3301 self.instruction(GlobalGet(flags_global.as_u32()));
3302 if value {
3303 self.instruction(I32Const(flag_to_set));
3304 self.instruction(I32Or);
3305 } else {
3306 self.instruction(I32Const(!flag_to_set));
3307 self.instruction(I32And);
3308 }
3309 self.instruction(GlobalSet(flags_global.as_u32()));
3310 }
3311
3312 fn verify_aligned(&mut self, opts: &LinearMemoryOptions, addr_local: u32, align: u32) {
3313 if align == 1 {
3316 return;
3317 }
3318 self.instruction(LocalGet(addr_local));
3319 assert!(align.is_power_of_two());
3320 self.ptr_uconst(opts, align - 1);
3321 self.ptr_and(opts);
3322 self.ptr_if(opts, BlockType::Empty);
3323 self.trap(Trap::UnalignedPointer);
3324 self.instruction(End);
3325 }
3326
3327 fn assert_aligned(&mut self, ty: &InterfaceType, mem: &Memory) {
3328 let mem_opts = mem.mem_opts();
3329 if !self.module.debug {
3330 return;
3331 }
3332 let align = self.types.align(mem_opts, ty);
3333 if align == 1 {
3334 return;
3335 }
3336 assert!(align.is_power_of_two());
3337 self.instruction(LocalGet(mem.addr.idx));
3338 self.ptr_uconst(mem_opts, mem.offset);
3339 self.ptr_add(mem_opts);
3340 self.ptr_uconst(mem_opts, align - 1);
3341 self.ptr_and(mem_opts);
3342 self.ptr_if(mem_opts, BlockType::Empty);
3343 self.trap(Trap::AssertFailed("pointer not aligned"));
3344 self.instruction(End);
3345 }
3346
3347 fn malloc<'c>(&mut self, opts: &'c Options, size: MallocSize, align: u32) -> Memory<'c> {
3348 match &opts.data_model {
3349 DataModel::Gc {} => todo!("CM+GC"),
3350 DataModel::LinearMemory(mem_opts) => {
3351 let realloc = mem_opts.realloc.unwrap();
3352 self.ptr_uconst(mem_opts, 0);
3353 self.ptr_uconst(mem_opts, 0);
3354 self.ptr_uconst(mem_opts, align);
3355 match size {
3356 MallocSize::Const(size) => self.ptr_uconst(mem_opts, size),
3357 MallocSize::Local(idx) => self.instruction(LocalGet(idx)),
3358 }
3359 self.instruction(Call(realloc.as_u32()));
3360 let addr = self.local_set_new_tmp(mem_opts.ptr());
3361 self.memory_operand(opts, addr, align)
3362 }
3363 }
3364 }
3365
3366 fn memory_operand<'c>(&mut self, opts: &'c Options, addr: TempLocal, align: u32) -> Memory<'c> {
3367 let ret = Memory {
3368 addr,
3369 offset: 0,
3370 opts,
3371 };
3372 self.verify_aligned(opts.data_model.unwrap_memory(), ret.addr.idx, align);
3373 ret
3374 }
3375
3376 fn local_tee_new_tmp(&mut self, ty: ValType) -> TempLocal {
3382 self.gen_temp_local(ty, LocalTee)
3383 }
3384
3385 fn local_set_new_tmp(&mut self, ty: ValType) -> TempLocal {
3388 self.gen_temp_local(ty, LocalSet)
3389 }
3390
3391 fn local_get_tmp(&mut self, local: &TempLocal) {
3392 self.instruction(LocalGet(local.idx));
3393 }
3394
3395 fn gen_temp_local(&mut self, ty: ValType, insn: fn(u32) -> Instruction<'static>) -> TempLocal {
3396 if let Some(idx) = self.free_locals.get_mut(&ty).and_then(|v| v.pop()) {
3399 self.instruction(insn(idx));
3400 return TempLocal {
3401 ty,
3402 idx,
3403 needs_free: true,
3404 };
3405 }
3406
3407 let locals = &mut self.module.funcs[self.result].locals;
3409 match locals.last_mut() {
3410 Some((cnt, prev_ty)) if ty == *prev_ty => *cnt += 1,
3411 _ => locals.push((1, ty)),
3412 }
3413 self.nlocals += 1;
3414 let idx = self.nlocals - 1;
3415 self.instruction(insn(idx));
3416 TempLocal {
3417 ty,
3418 idx,
3419 needs_free: true,
3420 }
3421 }
3422
3423 fn free_temp_local(&mut self, mut local: TempLocal) {
3426 assert!(local.needs_free);
3427 self.free_locals
3428 .entry(local.ty)
3429 .or_insert(Vec::new())
3430 .push(local.idx);
3431 local.needs_free = false;
3432 }
3433
3434 fn instruction(&mut self, instr: Instruction) {
3435 instr.encode(&mut self.code);
3436 }
3437
3438 fn trap(&mut self, trap: Trap) {
3439 self.traps.push((self.code.len(), trap));
3440 self.instruction(Unreachable);
3441 }
3442
3443 fn flush_code(&mut self) {
3448 if self.code.is_empty() {
3449 return;
3450 }
3451 self.module.funcs[self.result].body.push(Body::Raw(
3452 mem::take(&mut self.code),
3453 mem::take(&mut self.traps),
3454 ));
3455 }
3456
3457 fn finish(mut self) {
3458 self.instruction(End);
3461 self.flush_code();
3462
3463 self.module.funcs[self.result].filled_in = true;
3466 }
3467
3468 fn stack_get(&mut self, stack: &Stack<'_>, dst_ty: ValType) {
3476 assert_eq!(stack.locals.len(), 1);
3477 let (idx, src_ty) = stack.locals[0];
3478 self.instruction(LocalGet(idx));
3479 match (src_ty, dst_ty) {
3480 (ValType::I32, ValType::I32)
3481 | (ValType::I64, ValType::I64)
3482 | (ValType::F32, ValType::F32)
3483 | (ValType::F64, ValType::F64) => {}
3484
3485 (ValType::I32, ValType::F32) => self.instruction(F32ReinterpretI32),
3486 (ValType::I64, ValType::I32) => {
3487 self.assert_i64_upper_bits_not_set(idx);
3488 self.instruction(I32WrapI64);
3489 }
3490 (ValType::I64, ValType::F64) => self.instruction(F64ReinterpretI64),
3491 (ValType::I64, ValType::F32) => {
3492 self.assert_i64_upper_bits_not_set(idx);
3493 self.instruction(I32WrapI64);
3494 self.instruction(F32ReinterpretI32);
3495 }
3496
3497 (ValType::I32, ValType::I64)
3499 | (ValType::I32, ValType::F64)
3500 | (ValType::F32, ValType::I32)
3501 | (ValType::F32, ValType::I64)
3502 | (ValType::F32, ValType::F64)
3503 | (ValType::F64, ValType::I32)
3504 | (ValType::F64, ValType::I64)
3505 | (ValType::F64, ValType::F32)
3506
3507 | (ValType::Ref(_), _)
3509 | (_, ValType::Ref(_))
3510 | (ValType::V128, _)
3511 | (_, ValType::V128) => {
3512 panic!("cannot get {dst_ty:?} from {src_ty:?} local");
3513 }
3514 }
3515 }
3516
3517 fn assert_i64_upper_bits_not_set(&mut self, local: u32) {
3518 if !self.module.debug {
3519 return;
3520 }
3521 self.instruction(LocalGet(local));
3522 self.instruction(I64Const(32));
3523 self.instruction(I64ShrU);
3524 self.instruction(I32WrapI64);
3525 self.instruction(If(BlockType::Empty));
3526 self.trap(Trap::AssertFailed("upper bits are unexpectedly set"));
3527 self.instruction(End);
3528 }
3529
3530 fn stack_set(&mut self, dst_tys: &[ValType], src_ty: ValType) {
3536 assert_eq!(dst_tys.len(), 1);
3537 let dst_ty = dst_tys[0];
3538 match (src_ty, dst_ty) {
3539 (ValType::I32, ValType::I32)
3540 | (ValType::I64, ValType::I64)
3541 | (ValType::F32, ValType::F32)
3542 | (ValType::F64, ValType::F64) => {}
3543
3544 (ValType::F32, ValType::I32) => self.instruction(I32ReinterpretF32),
3545 (ValType::I32, ValType::I64) => self.instruction(I64ExtendI32U),
3546 (ValType::F64, ValType::I64) => self.instruction(I64ReinterpretF64),
3547 (ValType::F32, ValType::I64) => {
3548 self.instruction(I32ReinterpretF32);
3549 self.instruction(I64ExtendI32U);
3550 }
3551
3552 (ValType::I64, ValType::I32)
3554 | (ValType::F64, ValType::I32)
3555 | (ValType::I32, ValType::F32)
3556 | (ValType::I64, ValType::F32)
3557 | (ValType::F64, ValType::F32)
3558 | (ValType::I32, ValType::F64)
3559 | (ValType::I64, ValType::F64)
3560 | (ValType::F32, ValType::F64)
3561
3562 | (ValType::Ref(_), _)
3564 | (_, ValType::Ref(_))
3565 | (ValType::V128, _)
3566 | (_, ValType::V128) => {
3567 panic!("cannot get {dst_ty:?} from {src_ty:?} local");
3568 }
3569 }
3570 }
3571
3572 fn i32_load8u(&mut self, mem: &Memory) {
3573 self.instruction(LocalGet(mem.addr.idx));
3574 self.instruction(I32Load8U(mem.memarg(0)));
3575 }
3576
3577 fn i32_load8s(&mut self, mem: &Memory) {
3578 self.instruction(LocalGet(mem.addr.idx));
3579 self.instruction(I32Load8S(mem.memarg(0)));
3580 }
3581
3582 fn i32_load16u(&mut self, mem: &Memory) {
3583 self.instruction(LocalGet(mem.addr.idx));
3584 self.instruction(I32Load16U(mem.memarg(1)));
3585 }
3586
3587 fn i32_load16s(&mut self, mem: &Memory) {
3588 self.instruction(LocalGet(mem.addr.idx));
3589 self.instruction(I32Load16S(mem.memarg(1)));
3590 }
3591
3592 fn i32_load(&mut self, mem: &Memory) {
3593 self.instruction(LocalGet(mem.addr.idx));
3594 self.instruction(I32Load(mem.memarg(2)));
3595 }
3596
3597 fn i64_load(&mut self, mem: &Memory) {
3598 self.instruction(LocalGet(mem.addr.idx));
3599 self.instruction(I64Load(mem.memarg(3)));
3600 }
3601
3602 fn ptr_load(&mut self, mem: &Memory) {
3603 if mem.mem_opts().memory64 {
3604 self.i64_load(mem);
3605 } else {
3606 self.i32_load(mem);
3607 }
3608 }
3609
3610 fn ptr_add(&mut self, opts: &LinearMemoryOptions) {
3611 if opts.memory64 {
3612 self.instruction(I64Add);
3613 } else {
3614 self.instruction(I32Add);
3615 }
3616 }
3617
3618 fn ptr_sub(&mut self, opts: &LinearMemoryOptions) {
3619 if opts.memory64 {
3620 self.instruction(I64Sub);
3621 } else {
3622 self.instruction(I32Sub);
3623 }
3624 }
3625
3626 fn ptr_mul(&mut self, opts: &LinearMemoryOptions) {
3627 if opts.memory64 {
3628 self.instruction(I64Mul);
3629 } else {
3630 self.instruction(I32Mul);
3631 }
3632 }
3633
3634 fn ptr_ge_u(&mut self, opts: &LinearMemoryOptions) {
3635 if opts.memory64 {
3636 self.instruction(I64GeU);
3637 } else {
3638 self.instruction(I32GeU);
3639 }
3640 }
3641
3642 fn ptr_lt_u(&mut self, opts: &LinearMemoryOptions) {
3643 if opts.memory64 {
3644 self.instruction(I64LtU);
3645 } else {
3646 self.instruction(I32LtU);
3647 }
3648 }
3649
3650 fn ptr_shl(&mut self, opts: &LinearMemoryOptions) {
3651 if opts.memory64 {
3652 self.instruction(I64Shl);
3653 } else {
3654 self.instruction(I32Shl);
3655 }
3656 }
3657
3658 fn ptr_eqz(&mut self, opts: &LinearMemoryOptions) {
3659 if opts.memory64 {
3660 self.instruction(I64Eqz);
3661 } else {
3662 self.instruction(I32Eqz);
3663 }
3664 }
3665
3666 fn ptr_uconst(&mut self, opts: &LinearMemoryOptions, val: u32) {
3667 if opts.memory64 {
3668 self.instruction(I64Const(val.into()));
3669 } else {
3670 self.instruction(I32Const(val as i32));
3671 }
3672 }
3673
3674 fn ptr_iconst(&mut self, opts: &LinearMemoryOptions, val: i32) {
3675 if opts.memory64 {
3676 self.instruction(I64Const(val.into()));
3677 } else {
3678 self.instruction(I32Const(val));
3679 }
3680 }
3681
3682 fn ptr_eq(&mut self, opts: &LinearMemoryOptions) {
3683 if opts.memory64 {
3684 self.instruction(I64Eq);
3685 } else {
3686 self.instruction(I32Eq);
3687 }
3688 }
3689
3690 fn ptr_ne(&mut self, opts: &LinearMemoryOptions) {
3691 if opts.memory64 {
3692 self.instruction(I64Ne);
3693 } else {
3694 self.instruction(I32Ne);
3695 }
3696 }
3697
3698 fn ptr_and(&mut self, opts: &LinearMemoryOptions) {
3699 if opts.memory64 {
3700 self.instruction(I64And);
3701 } else {
3702 self.instruction(I32And);
3703 }
3704 }
3705
3706 fn ptr_or(&mut self, opts: &LinearMemoryOptions) {
3707 if opts.memory64 {
3708 self.instruction(I64Or);
3709 } else {
3710 self.instruction(I32Or);
3711 }
3712 }
3713
3714 fn ptr_xor(&mut self, opts: &LinearMemoryOptions) {
3715 if opts.memory64 {
3716 self.instruction(I64Xor);
3717 } else {
3718 self.instruction(I32Xor);
3719 }
3720 }
3721
3722 fn ptr_if(&mut self, opts: &LinearMemoryOptions, ty: BlockType) {
3723 if opts.memory64 {
3724 self.instruction(I64Const(0));
3725 self.instruction(I64Ne);
3726 }
3727 self.instruction(If(ty));
3728 }
3729
3730 fn ptr_br_if(&mut self, opts: &LinearMemoryOptions, depth: u32) {
3731 if opts.memory64 {
3732 self.instruction(I64Const(0));
3733 self.instruction(I64Ne);
3734 }
3735 self.instruction(BrIf(depth));
3736 }
3737
3738 fn f32_load(&mut self, mem: &Memory) {
3739 self.instruction(LocalGet(mem.addr.idx));
3740 self.instruction(F32Load(mem.memarg(2)));
3741 }
3742
3743 fn f64_load(&mut self, mem: &Memory) {
3744 self.instruction(LocalGet(mem.addr.idx));
3745 self.instruction(F64Load(mem.memarg(3)));
3746 }
3747
3748 fn push_dst_addr(&mut self, dst: &Destination) {
3749 if let Destination::Memory(mem) = dst {
3750 self.instruction(LocalGet(mem.addr.idx));
3751 }
3752 }
3753
3754 fn i32_store8(&mut self, mem: &Memory) {
3755 self.instruction(I32Store8(mem.memarg(0)));
3756 }
3757
3758 fn i32_store16(&mut self, mem: &Memory) {
3759 self.instruction(I32Store16(mem.memarg(1)));
3760 }
3761
3762 fn i32_store(&mut self, mem: &Memory) {
3763 self.instruction(I32Store(mem.memarg(2)));
3764 }
3765
3766 fn i64_store(&mut self, mem: &Memory) {
3767 self.instruction(I64Store(mem.memarg(3)));
3768 }
3769
3770 fn ptr_store(&mut self, mem: &Memory) {
3771 if mem.mem_opts().memory64 {
3772 self.i64_store(mem);
3773 } else {
3774 self.i32_store(mem);
3775 }
3776 }
3777
3778 fn f32_store(&mut self, mem: &Memory) {
3779 self.instruction(F32Store(mem.memarg(2)));
3780 }
3781
3782 fn f64_store(&mut self, mem: &Memory) {
3783 self.instruction(F64Store(mem.memarg(3)));
3784 }
3785}
3786
3787impl<'a> Source<'a> {
3788 fn record_field_srcs<'b>(
3795 &'b self,
3796 types: &'b ComponentTypesBuilder,
3797 fields: impl IntoIterator<Item = InterfaceType> + 'b,
3798 ) -> impl Iterator<Item = Source<'a>> + 'b
3799 where
3800 'a: 'b,
3801 {
3802 let mut offset = 0;
3803 fields.into_iter().map(move |ty| match self {
3804 Source::Memory(mem) => {
3805 let mem = next_field_offset(&mut offset, types, &ty, mem);
3806 Source::Memory(mem)
3807 }
3808 Source::Stack(stack) => {
3809 let cnt = types.flat_types(&ty).unwrap().len() as u32;
3810 offset += cnt;
3811 Source::Stack(stack.slice((offset - cnt) as usize..offset as usize))
3812 }
3813 Source::Struct(_) => todo!(),
3814 Source::Array(_) => todo!(),
3815 })
3816 }
3817
3818 fn payload_src(
3820 &self,
3821 types: &ComponentTypesBuilder,
3822 info: &VariantInfo,
3823 case: Option<&InterfaceType>,
3824 ) -> Source<'a> {
3825 match self {
3826 Source::Stack(s) => {
3827 let flat_len = match case {
3828 Some(case) => types.flat_types(case).unwrap().len(),
3829 None => 0,
3830 };
3831 Source::Stack(s.slice(1..s.locals.len()).slice(0..flat_len))
3832 }
3833 Source::Memory(mem) => {
3834 let mem = if mem.mem_opts().memory64 {
3835 mem.bump(info.payload_offset64)
3836 } else {
3837 mem.bump(info.payload_offset32)
3838 };
3839 Source::Memory(mem)
3840 }
3841 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
3842 }
3843 }
3844
3845 fn opts(&self) -> &'a Options {
3846 match self {
3847 Source::Stack(s) => s.opts,
3848 Source::Memory(mem) => mem.opts,
3849 Source::Struct(s) => s.opts,
3850 Source::Array(a) => a.opts,
3851 }
3852 }
3853}
3854
3855impl<'a> Destination<'a> {
3856 fn record_field_dsts<'b, I>(
3858 &'b self,
3859 types: &'b ComponentTypesBuilder,
3860 fields: I,
3861 ) -> impl Iterator<Item = Destination<'b>> + use<'b, I>
3862 where
3863 'a: 'b,
3864 I: IntoIterator<Item = InterfaceType> + 'b,
3865 {
3866 let mut offset = 0;
3867 fields.into_iter().map(move |ty| match self {
3868 Destination::Memory(mem) => {
3869 let mem = next_field_offset(&mut offset, types, &ty, mem);
3870 Destination::Memory(mem)
3871 }
3872 Destination::Stack(s, opts) => {
3873 let cnt = types.flat_types(&ty).unwrap().len() as u32;
3874 offset += cnt;
3875 Destination::Stack(&s[(offset - cnt) as usize..offset as usize], opts)
3876 }
3877 Destination::Struct(_) => todo!(),
3878 Destination::Array(_) => todo!(),
3879 })
3880 }
3881
3882 fn payload_dst(
3884 &self,
3885 types: &ComponentTypesBuilder,
3886 info: &VariantInfo,
3887 case: Option<&InterfaceType>,
3888 ) -> Destination<'_> {
3889 match self {
3890 Destination::Stack(s, opts) => {
3891 let flat_len = match case {
3892 Some(case) => types.flat_types(case).unwrap().len(),
3893 None => 0,
3894 };
3895 Destination::Stack(&s[1..][..flat_len], opts)
3896 }
3897 Destination::Memory(mem) => {
3898 let mem = if mem.mem_opts().memory64 {
3899 mem.bump(info.payload_offset64)
3900 } else {
3901 mem.bump(info.payload_offset32)
3902 };
3903 Destination::Memory(mem)
3904 }
3905 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
3906 }
3907 }
3908
3909 fn opts(&self) -> &'a Options {
3910 match self {
3911 Destination::Stack(_, opts) => opts,
3912 Destination::Memory(mem) => mem.opts,
3913 Destination::Struct(s) => s.opts,
3914 Destination::Array(a) => a.opts,
3915 }
3916 }
3917}
3918
3919fn next_field_offset<'a>(
3920 offset: &mut u32,
3921 types: &ComponentTypesBuilder,
3922 field: &InterfaceType,
3923 mem: &Memory<'a>,
3924) -> Memory<'a> {
3925 let abi = types.canonical_abi(field);
3926 let offset = if mem.mem_opts().memory64 {
3927 abi.next_field64(offset)
3928 } else {
3929 abi.next_field32(offset)
3930 };
3931 mem.bump(offset)
3932}
3933
3934impl<'a> Memory<'a> {
3935 fn memarg(&self, align: u32) -> MemArg {
3936 MemArg {
3937 offset: u64::from(self.offset),
3938 align,
3939 memory_index: self.mem_opts().memory.unwrap().as_u32(),
3940 }
3941 }
3942
3943 fn bump(&self, offset: u32) -> Memory<'a> {
3944 Memory {
3945 opts: self.opts,
3946 addr: TempLocal::new(self.addr.idx, self.addr.ty),
3947 offset: self.offset + offset,
3948 }
3949 }
3950}
3951
3952impl<'a> Stack<'a> {
3953 fn slice(&self, range: Range<usize>) -> Stack<'a> {
3954 Stack {
3955 locals: &self.locals[range],
3956 opts: self.opts,
3957 }
3958 }
3959}
3960
3961struct VariantCase<'a> {
3962 src_i: u32,
3963 src_ty: Option<&'a InterfaceType>,
3964 dst_i: u32,
3965 dst_ty: Option<&'a InterfaceType>,
3966}
3967
3968fn variant_info<'a, I>(types: &ComponentTypesBuilder, cases: I) -> VariantInfo
3969where
3970 I: IntoIterator<Item = Option<&'a InterfaceType>>,
3971 I::IntoIter: ExactSizeIterator,
3972{
3973 VariantInfo::new(
3974 cases
3975 .into_iter()
3976 .map(|ty| ty.map(|ty| types.canonical_abi(ty))),
3977 )
3978 .0
3979}
3980
3981enum MallocSize {
3982 Const(u32),
3983 Local(u32),
3984}
3985
3986struct WasmString<'a> {
3987 ptr: TempLocal,
3988 len: TempLocal,
3989 opts: &'a Options,
3990}
3991
3992struct TempLocal {
3993 idx: u32,
3994 ty: ValType,
3995 needs_free: bool,
3996}
3997
3998impl TempLocal {
3999 fn new(idx: u32, ty: ValType) -> TempLocal {
4000 TempLocal {
4001 idx,
4002 ty,
4003 needs_free: false,
4004 }
4005 }
4006}
4007
4008impl std::ops::Drop for TempLocal {
4009 fn drop(&mut self) {
4010 if self.needs_free {
4011 panic!("temporary local not free'd");
4012 }
4013 }
4014}
4015
4016impl From<FlatType> for ValType {
4017 fn from(ty: FlatType) -> ValType {
4018 match ty {
4019 FlatType::I32 => ValType::I32,
4020 FlatType::I64 => ValType::I64,
4021 FlatType::F32 => ValType::F32,
4022 FlatType::F64 => ValType::F64,
4023 }
4024 }
4025}