1use crate::component::{
19 CanonicalAbiInfo, ComponentTypesBuilder, FixedEncoding as FE, FlatType, InterfaceType,
20 MAX_FLAT_ASYNC_PARAMS, MAX_FLAT_PARAMS, PREPARE_ASYNC_NO_RESULT, PREPARE_ASYNC_WITH_RESULT,
21 START_FLAG_ASYNC_CALLEE, START_FLAG_ASYNC_CALLER, StringEncoding, Transcode,
22 TypeComponentLocalErrorContextTableIndex, TypeEnumIndex, TypeFixedLengthListIndex,
23 TypeFlagsIndex, TypeFutureTableIndex, TypeListIndex, TypeMapIndex, TypeOptionIndex,
24 TypeRecordIndex, TypeResourceTableIndex, TypeResultIndex, TypeStreamTableIndex, TypeTupleIndex,
25 TypeVariantIndex, VariantInfo,
26};
27use crate::fact::signature::Signature;
28use crate::fact::transcode::Transcoder;
29use crate::fact::{
30 AdapterData, Body, Function, FunctionId, Helper, HelperLocation, HelperType,
31 LinearMemoryOptions, Module, Options,
32};
33use crate::prelude::*;
34use crate::{FuncIndex, GlobalIndex, IndexType, NUM_COMPONENT_CONTEXT_SLOTS, Trap};
35use std::collections::HashMap;
36use std::mem;
37use std::ops::Range;
38use wasm_encoder::{BlockType, Catch, Encode, Instruction, Instruction::*, MemArg, ValType};
39use wasmtime_component_util::{DiscriminantSize, FlagsSize};
40
41use super::DataModel;
42
43const MAX_STRING_BYTE_LENGTH: u32 = (1 << 31) - 1;
44const UTF16_TAG: u32 = 1 << 31;
45
46const INITIAL_FUEL: usize = 1_000;
49
50struct Compiler<'a, 'b> {
51 types: &'a ComponentTypesBuilder,
52 module: &'b mut Module<'a>,
53 result: FunctionId,
54
55 code: Vec<u8>,
57
58 nlocals: u32,
60
61 free_locals: HashMap<ValType, Vec<u32>>,
63
64 fuel: usize,
73
74 emit_resource_call: bool,
79}
80
81pub(super) fn compile(module: &mut Module<'_>, adapter: &AdapterData) {
82 fn compiler<'a, 'b>(
83 module: &'b mut Module<'a>,
84 adapter: &AdapterData,
85 ) -> (Compiler<'a, 'b>, Signature, Signature) {
86 let lower_sig = module.types.signature(&adapter.lower);
87 let lift_sig = module.types.signature(&adapter.lift);
88 let ty = module
89 .core_types
90 .function(&lower_sig.params, &lower_sig.results);
91 let result = module
92 .funcs
93 .push(Function::new(Some(adapter.name.clone()), ty));
94
95 let emit_resource_call = module.types.contains_borrow_resource(&adapter.lower);
100 assert_eq!(
101 emit_resource_call,
102 module.types.contains_borrow_resource(&adapter.lift)
103 );
104
105 (
106 Compiler::new(
107 module,
108 result,
109 lower_sig.params.len() as u32,
110 emit_resource_call,
111 ),
112 lower_sig,
113 lift_sig,
114 )
115 }
116
117 if adapter.lift.instance == adapter.lower.instance {
123 let (mut compiler, _, _) = compiler(module, adapter);
124 compiler.trap(Trap::CannotEnterComponent);
125 compiler.finish();
126 return;
127 }
128
129 let async_start_adapter = |module: &mut Module| {
135 let sig = module
136 .types
137 .async_start_signature(&adapter.lower, &adapter.lift);
138 let ty = module.core_types.function(&sig.params, &sig.results);
139 let result = module.funcs.push(Function::new(
140 Some(format!("[async-start]{}", adapter.name)),
141 ty,
142 ));
143
144 Compiler::new(module, result, sig.params.len() as u32, false)
145 .compile_async_start_adapter(adapter, &sig);
146
147 result
148 };
149
150 let async_return_adapter = |module: &mut Module| {
159 let sig = module
160 .types
161 .async_return_signature(&adapter.lower, &adapter.lift);
162 let ty = module.core_types.function(&sig.params, &sig.results);
163 let result = module.funcs.push(Function::new(
164 Some(format!("[async-return]{}", adapter.name)),
165 ty,
166 ));
167
168 Compiler::new(module, result, sig.params.len() as u32, false)
169 .compile_async_return_adapter(adapter, &sig);
170
171 result
172 };
173
174 let lower_async = adapter.lower.options.async_;
175 let lift_async = adapter.lift.options.async_;
176 if !lower_async && !lift_async && !module.types[adapter.lift.ty].async_ {
177 let (compiler, lower_sig, lift_sig) = compiler(module, adapter);
180 compiler.compile_sync_to_sync_adapter(adapter, &lower_sig, &lift_sig);
181 return;
182 }
183
184 assert!(module.tunables.concurrency_support);
185
186 let start = async_start_adapter(module);
209 let return_ = async_return_adapter(module);
210 let (compiler, lower_sig, lift_sig) = compiler(module, adapter);
211 compiler.compile_host_mediated_adapter(adapter, start, return_, &lower_sig, &lift_sig);
212}
213
214pub(super) fn compile_helper(module: &mut Module<'_>, result: FunctionId, helper: Helper) {
221 let mut nlocals = 0;
222 let src_flat;
223 let src = match helper.src.loc {
224 HelperLocation::Stack => {
229 src_flat = module
230 .types
231 .flatten_types(&helper.src.opts, usize::MAX, [helper.src.ty])
232 .unwrap()
233 .iter()
234 .enumerate()
235 .map(|(i, ty)| (i as u32, *ty))
236 .collect::<Vec<_>>();
237 nlocals += src_flat.len() as u32;
238 Source::Stack(Stack {
239 locals: &src_flat,
240 opts: &helper.src.opts,
241 })
242 }
243 HelperLocation::Memory => {
246 nlocals += 1;
247 Source::Memory(Memory {
248 opts: &helper.src.opts,
249 addr: TempLocal::new(0, helper.src.opts.data_model.unwrap_memory().ptr()),
250 offset: 0,
251 })
252 }
253 HelperLocation::StructField | HelperLocation::ArrayElement => todo!("CM+GC"),
254 };
255 let dst_flat;
256 let dst = match helper.dst.loc {
257 HelperLocation::Stack => {
260 dst_flat = module
261 .types
262 .flatten_types(&helper.dst.opts, usize::MAX, [helper.dst.ty])
263 .unwrap();
264 Destination::Stack(&dst_flat, &helper.dst.opts)
265 }
266 HelperLocation::Memory => {
269 nlocals += 1;
270 Destination::Memory(Memory {
271 opts: &helper.dst.opts,
272 addr: TempLocal::new(
273 nlocals - 1,
274 helper.dst.opts.data_model.unwrap_memory().ptr(),
275 ),
276 offset: 0,
277 })
278 }
279 HelperLocation::StructField | HelperLocation::ArrayElement => todo!("CM+GC"),
280 };
281 let mut compiler = Compiler {
282 types: module.types,
283 module,
284 code: Vec::new(),
285 nlocals,
286 free_locals: HashMap::new(),
287 result,
288 fuel: INITIAL_FUEL,
289 emit_resource_call: false,
292 };
293 compiler.translate(&helper.src.ty, &src, &helper.dst.ty, &dst);
294 compiler.finish();
295}
296
297enum Source<'a> {
300 Stack(Stack<'a>),
306
307 Memory(Memory<'a>),
310
311 #[allow(dead_code, reason = "CM+GC is still WIP")]
314 Struct(GcStruct<'a>),
315
316 #[allow(dead_code, reason = "CM+GC is still WIP")]
319 Array(GcArray<'a>),
320}
321
322enum Destination<'a> {
324 Stack(&'a [ValType], &'a Options),
330
331 Memory(Memory<'a>),
333
334 #[allow(dead_code, reason = "CM+GC is still WIP")]
337 Struct(GcStruct<'a>),
338
339 #[allow(dead_code, reason = "CM+GC is still WIP")]
342 Array(GcArray<'a>),
343}
344
345struct Stack<'a> {
346 locals: &'a [(u32, ValType)],
352 opts: &'a Options,
354}
355
356struct Memory<'a> {
358 opts: &'a Options,
360 addr: TempLocal,
363 offset: u32,
366}
367
368impl<'a> Memory<'a> {
369 fn mem_opts(&self) -> &'a LinearMemoryOptions {
370 self.opts.data_model.unwrap_memory()
371 }
372}
373
374struct GcStruct<'a> {
376 opts: &'a Options,
377 }
379
380struct GcArray<'a> {
382 opts: &'a Options,
383 }
385
386impl<'a, 'b> Compiler<'a, 'b> {
387 fn new(
388 module: &'b mut Module<'a>,
389 result: FunctionId,
390 nlocals: u32,
391 emit_resource_call: bool,
392 ) -> Self {
393 Self {
394 types: module.types,
395 module,
396 result,
397 code: Vec::new(),
398 nlocals,
399 free_locals: HashMap::new(),
400 fuel: INITIAL_FUEL,
401 emit_resource_call,
402 }
403 }
404
405 fn compile_host_mediated_adapter(
419 mut self,
420 adapter: &AdapterData,
421 start: FunctionId,
422 return_: FunctionId,
423 lower_sig: &Signature,
424 lift_sig: &Signature,
425 ) {
426 let async_caller = adapter.lower.options.async_;
427 let start_call = self.module.import_start_call(
428 &adapter.name,
429 adapter.lift.options.callback,
430 adapter.lift.post_return,
431 if async_caller {
432 &[ValType::I32]
433 } else {
434 &lower_sig.results
435 },
436 );
437
438 self.call_prepare(adapter, start, return_, lower_sig, !async_caller);
439
440 self.module.exports.push((
449 adapter.callee.as_u32(),
450 format!("[adapter-callee]{}", adapter.name),
451 ));
452
453 let mut flags = 0;
454 if async_caller {
455 flags |= START_FLAG_ASYNC_CALLER;
456 }
457 if adapter.lift.options.async_ {
458 flags |= START_FLAG_ASYNC_CALLEE;
459 }
460
461 self.instruction(RefFunc(adapter.callee.as_u32()));
462 self.instruction(I32Const(i32::try_from(lift_sig.params.len()).unwrap()));
463 self.instruction(I32Const(i32::try_from(lift_sig.results.len()).unwrap()));
464 self.instruction(I32Const(flags));
465 self.instruction(Call(start_call.as_u32()));
466
467 self.finish()
468 }
469
470 fn call_prepare(
483 &mut self,
484 adapter: &AdapterData,
485 start: FunctionId,
486 return_: FunctionId,
487 lower_sig: &Signature,
488 prepare_sync: bool,
489 ) {
490 let saved = self.trap_if_not_may_leave(adapter.lower.flags, Trap::CannotLeaveComponent);
493 self.free_temp_local(saved);
494
495 let prepare = self.module.import_prepare_call(
496 &adapter.name,
497 &lower_sig.params,
498 match adapter.lift.options.data_model {
499 DataModel::Gc {} => todo!("CM+GC"),
500 DataModel::LinearMemory(LinearMemoryOptions { memory, .. }) => memory.map(|m| m.0),
501 },
502 );
503
504 self.flush_code();
505 self.module.funcs[self.result]
506 .body
507 .push(Body::RefFunc(start));
508 self.module.funcs[self.result]
509 .body
510 .push(Body::RefFunc(return_));
511 self.instruction(I32Const(
512 i32::try_from(adapter.lower.instance.as_u32()).unwrap(),
513 ));
514 self.instruction(I32Const(
515 i32::try_from(adapter.lift.instance.as_u32()).unwrap(),
516 ));
517 self.instruction(I32Const(
518 i32::try_from(self.types[adapter.lift.ty].results.as_u32()).unwrap(),
519 ));
520 self.instruction(I32Const(if self.types[adapter.lift.ty].async_ {
521 1
522 } else {
523 0
524 }));
525 self.instruction(I32Const(i32::from(
526 adapter.lift.options.string_encoding as u8,
527 )));
528
529 let result_types = &self.types[self.types[adapter.lower.ty].results].types;
532 if prepare_sync {
533 self.instruction(I32Const(
534 i32::try_from(
535 self.types
536 .flatten_types(
537 &adapter.lower.options,
538 usize::MAX,
539 result_types.iter().copied(),
540 )
541 .map(|v| v.len())
542 .unwrap_or(usize::try_from(i32::MAX).unwrap()),
543 )
544 .unwrap(),
545 ));
546 } else {
547 if result_types.len() > 0 {
548 self.instruction(I32Const(PREPARE_ASYNC_WITH_RESULT.cast_signed()));
549 } else {
550 self.instruction(I32Const(PREPARE_ASYNC_NO_RESULT.cast_signed()));
551 }
552 }
553
554 for index in 0..lower_sig.params.len() {
556 self.instruction(LocalGet(u32::try_from(index).unwrap()));
557 }
558 self.instruction(Call(prepare.as_u32()));
559 }
560
561 fn compile_async_start_adapter(mut self, adapter: &AdapterData, sig: &Signature) {
567 let param_locals = sig
573 .params
574 .iter()
575 .enumerate()
576 .map(|(i, ty)| (i as u32, *ty))
577 .collect::<Vec<_>>();
578
579 let saved = self.clear_may_leave(adapter.lift.flags);
580 self.translate_params(adapter, ¶m_locals);
581 self.restore_may_leave(adapter.lift.flags, saved);
582
583 self.finish();
584 }
585
586 fn compile_async_return_adapter(mut self, adapter: &AdapterData, sig: &Signature) {
595 let param_locals = sig
599 .params
600 .iter()
601 .enumerate()
602 .map(|(i, ty)| (i as u32, *ty))
603 .collect::<Vec<_>>();
604
605 let saved = self.clear_may_leave(adapter.lower.flags);
606 self.translate_results(adapter, ¶m_locals, ¶m_locals);
617 self.restore_may_leave(adapter.lower.flags, saved);
618
619 self.finish()
620 }
621
622 fn compile_sync_to_sync_adapter(
629 mut self,
630 adapter: &AdapterData,
631 lower_sig: &Signature,
632 lift_sig: &Signature,
633 ) {
634 self.enter_exception_barrier(&lower_sig.results);
635
636 let saved_lower_may_leave =
646 self.trap_if_not_may_leave(adapter.lower.flags, Trap::CannotLeaveComponent);
647
648 debug_assert!(
654 !(adapter.thread_transparent && self.emit_resource_call),
655 "resources are not thread transparent",
656 );
657 let needs_thread_state =
658 self.module.tunables.concurrency_support && !adapter.thread_transparent;
659
660 if needs_thread_state {
661 self.instruction(I32Const(if self.types[adapter.lift.ty].async_ {
670 1
671 } else {
672 0
673 }));
674 self.instruction(I32Const(
675 i32::try_from(adapter.lift.instance.as_u32()).unwrap(),
676 ));
677 let enter_sync_call = self.module.import_enter_sync_call();
678 self.instruction(Call(enter_sync_call.as_u32()));
679 } else if self.emit_resource_call {
680 assert!(!self.types[adapter.lift.ty].async_);
681 self.instruction(I32Const(0));
682 self.instruction(I32Const(
683 i32::try_from(adapter.lift.instance.as_u32()).unwrap(),
684 ));
685 let enter_sync_call = self.module.import_enter_sync_call();
686 self.instruction(Call(enter_sync_call.as_u32()));
687 }
688
689 let saved_lift_may_leave = self.clear_may_leave(adapter.lift.flags);
724 let param_locals = lower_sig
725 .params
726 .iter()
727 .enumerate()
728 .map(|(i, ty)| (i as u32, *ty))
729 .collect::<Vec<_>>();
730 self.translate_params(adapter, ¶m_locals);
731 self.restore_may_leave(adapter.lift.flags, saved_lift_may_leave);
732
733 self.instruction(Call(adapter.callee.as_u32()));
738
739 let mut result_locals = Vec::with_capacity(lift_sig.results.len());
740 let mut temps = Vec::new();
741 for ty in lift_sig.results.iter().rev() {
742 let local = self.local_set_new_tmp(*ty);
743 result_locals.push((local.idx, *ty));
744 temps.push(local);
745 }
746 result_locals.reverse();
747
748 let callee_context = if adapter.lift.post_return.is_some() {
752 self.save_context()
753 } else {
754 Vec::new()
755 };
756
757 if self.emit_resource_call || needs_thread_state {
774 let exit_sync_call = self.module.import_exit_sync_call();
775 self.instruction(Call(exit_sync_call.as_u32()));
776 }
777
778 self.set_may_leave_false(adapter.lower.flags);
784 self.translate_results(adapter, ¶m_locals, &result_locals);
785 self.restore_may_leave(adapter.lower.flags, saved_lower_may_leave);
786
787 if let Some(func) = adapter.lift.post_return {
794 let caller_context = self.save_context();
795 self.restore_context(callee_context);
796 let saved_lift_may_leave = self.clear_may_leave(adapter.lift.flags);
797 for (result, _) in result_locals.iter() {
798 self.instruction(LocalGet(*result));
799 }
800 self.instruction(Call(func.as_u32()));
801 self.restore_may_leave(adapter.lift.flags, saved_lift_may_leave);
802 self.restore_context(caller_context);
803 } else {
804 assert!(callee_context.is_empty());
805 }
806
807 for tmp in temps {
808 self.free_temp_local(tmp);
809 }
810
811 self.exit_exception_barrier();
812
813 self.finish()
814 }
815
816 fn translate_params(&mut self, adapter: &AdapterData, param_locals: &[(u32, ValType)]) {
817 let src_tys = self.types[adapter.lower.ty].params;
818 let src_tys = self.types[src_tys]
819 .types
820 .iter()
821 .copied()
822 .collect::<Vec<_>>();
823 let dst_tys = self.types[adapter.lift.ty].params;
824 let dst_tys = self.types[dst_tys]
825 .types
826 .iter()
827 .copied()
828 .collect::<Vec<_>>();
829 let lift_opts = &adapter.lift.options;
830 let lower_opts = &adapter.lower.options;
831
832 assert_eq!(src_tys.len(), dst_tys.len());
834
835 let max_flat_params = if adapter.lower.options.async_ {
839 MAX_FLAT_ASYNC_PARAMS
840 } else {
841 MAX_FLAT_PARAMS
842 };
843 let src_flat =
844 self.types
845 .flatten_types(lower_opts, max_flat_params, src_tys.iter().copied());
846 let dst_flat =
847 self.types
848 .flatten_types(lift_opts, MAX_FLAT_PARAMS, dst_tys.iter().copied());
849
850 let src = if let Some(flat) = &src_flat {
851 Source::Stack(Stack {
852 locals: ¶m_locals[..flat.len()],
853 opts: lower_opts,
854 })
855 } else {
856 let lower_mem_opts = lower_opts.data_model.unwrap_memory();
860 let (addr, ty) = param_locals[0];
861 assert_eq!(ty, lower_mem_opts.ptr());
862 let abi = CanonicalAbiInfo::record(src_tys.iter().map(|t| self.types.canonical_abi(t)));
863 Source::Memory(self.memory_operand_abi(
864 lower_opts,
865 TempLocal::new(addr, ty),
866 &abi,
867 Trap::MemoryOutOfBounds,
868 ))
869 };
870
871 let dst = if let Some(flat) = &dst_flat {
872 Destination::Stack(flat, lift_opts)
873 } else {
874 let abi = CanonicalAbiInfo::record(dst_tys.iter().map(|t| self.types.canonical_abi(t)));
877 Destination::Memory(self.malloc_abi(lift_opts, &abi, Trap::MemoryOutOfBounds))
878 };
879
880 let srcs = src
881 .record_field_srcs(self.types, src_tys.iter().copied())
882 .zip(src_tys.iter());
883 let dsts = dst
884 .record_field_dsts(self.types, dst_tys.iter().copied())
885 .zip(dst_tys.iter());
886 for ((src, src_ty), (dst, dst_ty)) in srcs.zip(dsts) {
887 self.translate(&src_ty, &src, &dst_ty, &dst);
888 }
889
890 if let Destination::Memory(mem) = dst {
894 self.instruction(LocalGet(mem.addr.idx));
895 self.free_temp_local(mem.addr);
896 }
897 }
898
899 fn translate_results(
900 &mut self,
901 adapter: &AdapterData,
902 param_locals: &[(u32, ValType)],
903 result_locals: &[(u32, ValType)],
904 ) {
905 let src_tys = self.types[adapter.lift.ty].results;
906 let src_tys = self.types[src_tys]
907 .types
908 .iter()
909 .copied()
910 .collect::<Vec<_>>();
911 let dst_tys = self.types[adapter.lower.ty].results;
912 let dst_tys = self.types[dst_tys]
913 .types
914 .iter()
915 .copied()
916 .collect::<Vec<_>>();
917 let lift_opts = &adapter.lift.options;
918 let lower_opts = &adapter.lower.options;
919
920 let src_flat = self
921 .types
922 .flatten_lifting_types(lift_opts, src_tys.iter().copied());
923 let dst_flat = self
924 .types
925 .flatten_lowering_types(lower_opts, dst_tys.iter().copied());
926
927 let src = if src_flat.is_some() {
928 Source::Stack(Stack {
929 locals: result_locals,
930 opts: lift_opts,
931 })
932 } else {
933 let abi = CanonicalAbiInfo::record(src_tys.iter().map(|t| self.types.canonical_abi(t)));
938 assert_eq!(
939 result_locals.len(),
940 if lower_opts.async_ || lift_opts.async_ || self.types[adapter.lift.ty].async_ {
941 2
942 } else {
943 1
944 }
945 );
946 let (addr, ty) = result_locals[0];
947 assert_eq!(ty, lift_opts.data_model.unwrap_memory().ptr());
948 Source::Memory(self.memory_operand_abi(
949 lift_opts,
950 TempLocal::new(addr, ty),
951 &abi,
952 Trap::MemoryOutOfBounds,
953 ))
954 };
955
956 let dst = if let Some(flat) = &dst_flat {
957 Destination::Stack(flat, lower_opts)
958 } else {
959 let abi = CanonicalAbiInfo::record(dst_tys.iter().map(|t| self.types.canonical_abi(t)));
963 let (addr, ty) = *param_locals.last().expect("no retptr");
964 assert_eq!(ty, lower_opts.data_model.unwrap_memory().ptr());
965 Destination::Memory(self.memory_operand_abi(
966 lower_opts,
967 TempLocal::new(addr, ty),
968 &abi,
969 Trap::MemoryOutOfBounds,
970 ))
971 };
972
973 let srcs = src
974 .record_field_srcs(self.types, src_tys.iter().copied())
975 .zip(src_tys.iter());
976 let dsts = dst
977 .record_field_dsts(self.types, dst_tys.iter().copied())
978 .zip(dst_tys.iter());
979 for ((src, src_ty), (dst, dst_ty)) in srcs.zip(dsts) {
980 self.translate(&src_ty, &src, &dst_ty, &dst);
981 }
982 }
983
984 fn translate(
985 &mut self,
986 src_ty: &InterfaceType,
987 src: &Source<'_>,
988 dst_ty: &InterfaceType,
989 dst: &Destination,
990 ) {
991 if let Source::Memory(mem) = src {
992 self.assert_aligned(src_ty, mem);
993 }
994 if let Destination::Memory(mem) = dst {
995 self.assert_aligned(dst_ty, mem);
996 }
997
998 let cost = match src_ty {
1028 InterfaceType::Bool
1032 | InterfaceType::U8
1033 | InterfaceType::S8
1034 | InterfaceType::U16
1035 | InterfaceType::S16
1036 | InterfaceType::U32
1037 | InterfaceType::S32
1038 | InterfaceType::U64
1039 | InterfaceType::S64
1040 | InterfaceType::Float32
1041 | InterfaceType::Float64 => 0,
1042
1043 InterfaceType::Char => 1,
1046
1047 InterfaceType::String => 40,
1050
1051 InterfaceType::List(_) => 40,
1054 InterfaceType::Map(_) => 40,
1056
1057 InterfaceType::Flags(i) => {
1058 let count = self.module.types[*i].names.len();
1059 match FlagsSize::from_count(count) {
1060 FlagsSize::Size0 => 0,
1061 FlagsSize::Size1 | FlagsSize::Size2 => 1,
1062 FlagsSize::Size4Plus(n) => n.into(),
1063 }
1064 }
1065
1066 InterfaceType::Record(i) => self.types[*i].fields.len(),
1067 InterfaceType::Tuple(i) => self.types[*i].types.len(),
1068 InterfaceType::Variant(i) => self.types[*i].cases.len(),
1069 InterfaceType::Enum(i) => self.types[*i].names.len(),
1070
1071 InterfaceType::Option(_) | InterfaceType::Result(_) => 2,
1073
1074 InterfaceType::Own(_)
1076 | InterfaceType::Borrow(_)
1077 | InterfaceType::Future(_)
1078 | InterfaceType::Stream(_)
1079 | InterfaceType::ErrorContext(_) => 1,
1080 InterfaceType::FixedLengthList(i) => self.types[*i].size as usize,
1081 };
1082
1083 let remaining_fuel = if self.fuel == INITIAL_FUEL {
1090 Some(self.fuel.saturating_sub(cost))
1091 } else {
1092 self.fuel.checked_sub(cost)
1093 };
1094
1095 match remaining_fuel {
1096 Some(n) => {
1102 self.fuel = n;
1103 match src_ty {
1104 InterfaceType::Bool => self.translate_bool(src, dst_ty, dst),
1105 InterfaceType::U8 => self.translate_u8(src, dst_ty, dst),
1106 InterfaceType::S8 => self.translate_s8(src, dst_ty, dst),
1107 InterfaceType::U16 => self.translate_u16(src, dst_ty, dst),
1108 InterfaceType::S16 => self.translate_s16(src, dst_ty, dst),
1109 InterfaceType::U32 => self.translate_u32(src, dst_ty, dst),
1110 InterfaceType::S32 => self.translate_s32(src, dst_ty, dst),
1111 InterfaceType::U64 => self.translate_u64(src, dst_ty, dst),
1112 InterfaceType::S64 => self.translate_s64(src, dst_ty, dst),
1113 InterfaceType::Float32 => self.translate_f32(src, dst_ty, dst),
1114 InterfaceType::Float64 => self.translate_f64(src, dst_ty, dst),
1115 InterfaceType::Char => self.translate_char(src, dst_ty, dst),
1116 InterfaceType::String => self.translate_string(src, dst_ty, dst),
1117 InterfaceType::List(t) => self.translate_list(*t, src, dst_ty, dst),
1118 InterfaceType::Map(t) => self.translate_map(*t, src, dst_ty, dst),
1119 InterfaceType::Record(t) => self.translate_record(*t, src, dst_ty, dst),
1120 InterfaceType::Flags(f) => self.translate_flags(*f, src, dst_ty, dst),
1121 InterfaceType::Tuple(t) => self.translate_tuple(*t, src, dst_ty, dst),
1122 InterfaceType::Variant(v) => self.translate_variant(*v, src, dst_ty, dst),
1123 InterfaceType::Enum(t) => self.translate_enum(*t, src, dst_ty, dst),
1124 InterfaceType::Option(t) => self.translate_option(*t, src, dst_ty, dst),
1125 InterfaceType::Result(t) => self.translate_result(*t, src, dst_ty, dst),
1126 InterfaceType::Own(t) => self.translate_own(*t, src, dst_ty, dst),
1127 InterfaceType::Borrow(t) => self.translate_borrow(*t, src, dst_ty, dst),
1128 InterfaceType::Future(t) => self.translate_future(*t, src, dst_ty, dst),
1129 InterfaceType::Stream(t) => self.translate_stream(*t, src, dst_ty, dst),
1130 InterfaceType::ErrorContext(t) => {
1131 self.translate_error_context(*t, src, dst_ty, dst)
1132 }
1133 InterfaceType::FixedLengthList(t) => {
1134 self.translate_fixed_length_list(*t, src, dst_ty, dst);
1135 }
1136 }
1137 }
1138
1139 None => {
1145 let src_loc = match src {
1146 Source::Stack(stack) => {
1150 for (i, ty) in stack
1151 .opts
1152 .flat_types(src_ty, self.types)
1153 .unwrap()
1154 .iter()
1155 .enumerate()
1156 {
1157 let stack = stack.slice(i..i + 1);
1158 self.stack_get(&stack, (*ty).into());
1159 }
1160 HelperLocation::Stack
1161 }
1162 Source::Memory(mem) => {
1167 self.push_mem_addr(mem);
1168 HelperLocation::Memory
1169 }
1170 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1171 };
1172 let dst_loc = match dst {
1173 Destination::Stack(..) => HelperLocation::Stack,
1174 Destination::Memory(mem) => {
1175 self.push_mem_addr(mem);
1176 HelperLocation::Memory
1177 }
1178 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1179 };
1180 let helper = self.module.translate_helper(Helper {
1186 src: HelperType {
1187 ty: *src_ty,
1188 opts: *src.opts(),
1189 loc: src_loc,
1190 },
1191 dst: HelperType {
1192 ty: *dst_ty,
1193 opts: *dst.opts(),
1194 loc: dst_loc,
1195 },
1196 });
1197 self.flush_code();
1200 self.module.funcs[self.result].body.push(Body::Call(helper));
1201
1202 if let Destination::Stack(tys, opts) = dst {
1211 let flat = self
1212 .types
1213 .flatten_types(opts, usize::MAX, [*dst_ty])
1214 .unwrap();
1215 assert_eq!(flat.len(), tys.len());
1216 let locals = flat
1217 .iter()
1218 .rev()
1219 .map(|ty| self.local_set_new_tmp(*ty))
1220 .collect::<Vec<_>>();
1221 for (ty, local) in tys.iter().zip(locals.into_iter().rev()) {
1222 self.instruction(LocalGet(local.idx));
1223 self.stack_set(std::slice::from_ref(ty), local.ty);
1224 self.free_temp_local(local);
1225 }
1226 }
1227 }
1228 }
1229 }
1230
1231 fn push_mem_addr(&mut self, mem: &Memory<'_>) {
1232 self.instruction(LocalGet(mem.addr.idx));
1233 if mem.offset != 0 {
1234 self.ptr_uconst(mem.mem_opts(), mem.offset);
1235 self.ptr_add(mem.mem_opts());
1236 }
1237 }
1238
1239 fn translate_bool(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1240 assert!(matches!(dst_ty, InterfaceType::Bool));
1242 self.push_dst_addr(dst);
1243
1244 self.instruction(I32Const(1));
1247 self.instruction(I32Const(0));
1248 match src {
1249 Source::Memory(mem) => self.i32_load8u(mem),
1250 Source::Stack(stack) => self.stack_get(stack, ValType::I32),
1251 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1252 }
1253 self.instruction(Select);
1254
1255 match dst {
1256 Destination::Memory(mem) => self.i32_store8(mem),
1257 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1258 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1259 }
1260 }
1261
1262 fn translate_u8(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1263 assert!(matches!(dst_ty, InterfaceType::U8));
1265 self.convert_u8_mask(src, dst, 0xff);
1266 }
1267
1268 fn convert_u8_mask(&mut self, src: &Source<'_>, dst: &Destination<'_>, mask: u8) {
1269 self.push_dst_addr(dst);
1270 let mut needs_mask = true;
1271 match src {
1272 Source::Memory(mem) => {
1273 self.i32_load8u(mem);
1274 needs_mask = mask != 0xff;
1275 }
1276 Source::Stack(stack) => {
1277 self.stack_get(stack, ValType::I32);
1278 }
1279 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1280 }
1281 if needs_mask {
1282 self.instruction(I32Const(i32::from(mask)));
1283 self.instruction(I32And);
1284 }
1285 match dst {
1286 Destination::Memory(mem) => self.i32_store8(mem),
1287 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1288 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1289 }
1290 }
1291
1292 fn translate_s8(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1293 assert!(matches!(dst_ty, InterfaceType::S8));
1295 self.push_dst_addr(dst);
1296 match src {
1297 Source::Memory(mem) => self.i32_load8s(mem),
1298 Source::Stack(stack) => {
1299 self.stack_get(stack, ValType::I32);
1300 self.instruction(I32Extend8S);
1301 }
1302 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1303 }
1304 match dst {
1305 Destination::Memory(mem) => self.i32_store8(mem),
1306 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1307 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1308 }
1309 }
1310
1311 fn translate_u16(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1312 assert!(matches!(dst_ty, InterfaceType::U16));
1314 self.convert_u16_mask(src, dst, 0xffff);
1315 }
1316
1317 fn convert_u16_mask(&mut self, src: &Source<'_>, dst: &Destination<'_>, mask: u16) {
1318 self.push_dst_addr(dst);
1319 let mut needs_mask = true;
1320 match src {
1321 Source::Memory(mem) => {
1322 self.i32_load16u(mem);
1323 needs_mask = mask != 0xffff;
1324 }
1325 Source::Stack(stack) => {
1326 self.stack_get(stack, ValType::I32);
1327 }
1328 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1329 }
1330 if needs_mask {
1331 self.instruction(I32Const(i32::from(mask)));
1332 self.instruction(I32And);
1333 }
1334 match dst {
1335 Destination::Memory(mem) => self.i32_store16(mem),
1336 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1337 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1338 }
1339 }
1340
1341 fn translate_s16(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1342 assert!(matches!(dst_ty, InterfaceType::S16));
1344 self.push_dst_addr(dst);
1345 match src {
1346 Source::Memory(mem) => self.i32_load16s(mem),
1347 Source::Stack(stack) => {
1348 self.stack_get(stack, ValType::I32);
1349 self.instruction(I32Extend16S);
1350 }
1351 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1352 }
1353 match dst {
1354 Destination::Memory(mem) => self.i32_store16(mem),
1355 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1356 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1357 }
1358 }
1359
1360 fn translate_u32(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1361 assert!(matches!(dst_ty, InterfaceType::U32));
1363 self.convert_u32_mask(src, dst, 0xffffffff)
1364 }
1365
1366 fn convert_u32_mask(&mut self, src: &Source<'_>, dst: &Destination<'_>, mask: u32) {
1367 self.push_dst_addr(dst);
1368 match src {
1369 Source::Memory(mem) => self.i32_load(mem),
1370 Source::Stack(stack) => self.stack_get(stack, ValType::I32),
1371 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1372 }
1373 if mask != 0xffffffff {
1374 self.instruction(I32Const(mask as i32));
1375 self.instruction(I32And);
1376 }
1377 match dst {
1378 Destination::Memory(mem) => self.i32_store(mem),
1379 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1380 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1381 }
1382 }
1383
1384 fn translate_s32(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1385 assert!(matches!(dst_ty, InterfaceType::S32));
1387 self.push_dst_addr(dst);
1388 match src {
1389 Source::Memory(mem) => self.i32_load(mem),
1390 Source::Stack(stack) => self.stack_get(stack, ValType::I32),
1391 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1392 }
1393 match dst {
1394 Destination::Memory(mem) => self.i32_store(mem),
1395 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1396 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1397 }
1398 }
1399
1400 fn translate_u64(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1401 assert!(matches!(dst_ty, InterfaceType::U64));
1403 self.push_dst_addr(dst);
1404 match src {
1405 Source::Memory(mem) => self.i64_load(mem),
1406 Source::Stack(stack) => self.stack_get(stack, ValType::I64),
1407 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1408 }
1409 match dst {
1410 Destination::Memory(mem) => self.i64_store(mem),
1411 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I64),
1412 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1413 }
1414 }
1415
1416 fn translate_s64(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1417 assert!(matches!(dst_ty, InterfaceType::S64));
1419 self.push_dst_addr(dst);
1420 match src {
1421 Source::Memory(mem) => self.i64_load(mem),
1422 Source::Stack(stack) => self.stack_get(stack, ValType::I64),
1423 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1424 }
1425 match dst {
1426 Destination::Memory(mem) => self.i64_store(mem),
1427 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I64),
1428 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1429 }
1430 }
1431
1432 fn translate_f32(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1433 assert!(matches!(dst_ty, InterfaceType::Float32));
1435 self.push_dst_addr(dst);
1436 match src {
1437 Source::Memory(mem) => self.f32_load(mem),
1438 Source::Stack(stack) => self.stack_get(stack, ValType::F32),
1439 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1440 }
1441 match dst {
1442 Destination::Memory(mem) => self.f32_store(mem),
1443 Destination::Stack(stack, _) => self.stack_set(stack, ValType::F32),
1444 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1445 }
1446 }
1447
1448 fn translate_f64(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1449 assert!(matches!(dst_ty, InterfaceType::Float64));
1451 self.push_dst_addr(dst);
1452 match src {
1453 Source::Memory(mem) => self.f64_load(mem),
1454 Source::Stack(stack) => self.stack_get(stack, ValType::F64),
1455 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1456 }
1457 match dst {
1458 Destination::Memory(mem) => self.f64_store(mem),
1459 Destination::Stack(stack, _) => self.stack_set(stack, ValType::F64),
1460 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1461 }
1462 }
1463
1464 fn translate_char(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1465 assert!(matches!(dst_ty, InterfaceType::Char));
1466 match src {
1467 Source::Memory(mem) => self.i32_load(mem),
1468 Source::Stack(stack) => self.stack_get(stack, ValType::I32),
1469 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1470 }
1471 let local = self.local_set_new_tmp(ValType::I32);
1472
1473 self.instruction(Block(BlockType::Empty));
1489 self.instruction(Block(BlockType::Empty));
1490 self.instruction(LocalGet(local.idx));
1491 self.instruction(I32Const(0xd800));
1492 self.instruction(I32Xor);
1493 self.instruction(I32Const(-0x110000));
1494 self.instruction(I32Add);
1495 self.instruction(I32Const(-0x10f800));
1496 self.instruction(I32LtU);
1497 self.instruction(BrIf(0));
1498 self.instruction(LocalGet(local.idx));
1499 self.instruction(I32Const(0x110000));
1500 self.instruction(I32Ne);
1501 self.instruction(BrIf(1));
1502 self.instruction(End);
1503 self.trap(Trap::InvalidChar);
1504 self.instruction(End);
1505
1506 self.push_dst_addr(dst);
1507 self.instruction(LocalGet(local.idx));
1508 match dst {
1509 Destination::Memory(mem) => {
1510 self.i32_store(mem);
1511 }
1512 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1513 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1514 }
1515
1516 self.free_temp_local(local);
1517 }
1518
1519 fn translate_string(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1520 assert!(matches!(dst_ty, InterfaceType::String));
1521 let src_opts = src.opts();
1522 let dst_opts = dst.opts();
1523
1524 let src_mem_opts = match &src_opts.data_model {
1525 DataModel::Gc {} => todo!("CM+GC"),
1526 DataModel::LinearMemory(opts) => opts,
1527 };
1528 let dst_mem_opts = match &dst_opts.data_model {
1529 DataModel::Gc {} => todo!("CM+GC"),
1530 DataModel::LinearMemory(opts) => opts,
1531 };
1532
1533 match src {
1538 Source::Stack(s) => {
1539 assert_eq!(s.locals.len(), 2);
1540 self.stack_get(&s.slice(0..1), src_mem_opts.ptr());
1541 self.stack_get(&s.slice(1..2), src_mem_opts.ptr());
1542 }
1543 Source::Memory(mem) => {
1544 self.ptr_load(mem);
1545 self.ptr_load(&mem.bump(src_mem_opts.ptr_size().into()));
1546 }
1547 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1548 }
1549 let src_len = self.local_set_new_tmp(src_mem_opts.ptr());
1550 let src_ptr = self.local_set_new_tmp(src_mem_opts.ptr());
1551 let src_str = WasmString {
1552 ptr: src_ptr,
1553 len: src_len,
1554 opts: src_opts,
1555 };
1556
1557 let dst_str = match src_opts.string_encoding {
1558 StringEncoding::Utf8 => {
1559 self.validate_guest_pointer(
1560 src_opts,
1561 &src_str.ptr,
1562 &AllocSize::Local(src_str.len.idx),
1563 1,
1564 Trap::StringOutOfBounds,
1565 );
1566 match dst_opts.string_encoding {
1567 StringEncoding::Utf8 => {
1568 self.string_copy(&src_str, FE::Utf8, dst_opts, FE::Utf8)
1569 }
1570 StringEncoding::Utf16 => self.string_utf8_to_utf16(&src_str, dst_opts),
1571 StringEncoding::CompactUtf16 => {
1572 self.string_to_compact(&src_str, FE::Utf8, dst_opts)
1573 }
1574 }
1575 }
1576
1577 StringEncoding::Utf16 => {
1578 self.validate_guest_pointer(
1579 src_opts,
1580 &src_str.ptr,
1581 &AllocSize::DoubleLocal(src_str.len.idx),
1582 2,
1583 Trap::StringOutOfBounds,
1584 );
1585 match dst_opts.string_encoding {
1586 StringEncoding::Utf8 => {
1587 self.string_deflate_to_utf8(&src_str, FE::Utf16, dst_opts)
1588 }
1589 StringEncoding::Utf16 => {
1590 self.string_copy(&src_str, FE::Utf16, dst_opts, FE::Utf16)
1591 }
1592 StringEncoding::CompactUtf16 => {
1593 self.string_to_compact(&src_str, FE::Utf16, dst_opts)
1594 }
1595 }
1596 }
1597
1598 StringEncoding::CompactUtf16 => {
1599 self.instruction(LocalGet(src_str.len.idx));
1602 self.ptr_uconst(src_mem_opts, UTF16_TAG);
1603 self.ptr_and(src_mem_opts);
1604 self.ptr_if(src_mem_opts, BlockType::Empty);
1605
1606 self.instruction(LocalGet(src_str.len.idx));
1610 self.ptr_uconst(src_mem_opts, UTF16_TAG);
1611 self.ptr_xor(src_mem_opts);
1612 self.instruction(LocalSet(src_str.len.idx));
1613
1614 self.validate_guest_pointer(
1618 src_opts,
1619 &src_str.ptr,
1620 &AllocSize::DoubleLocal(src_str.len.idx),
1621 2,
1622 Trap::StringOutOfBounds,
1623 );
1624
1625 let s1 = match dst_opts.string_encoding {
1626 StringEncoding::Utf8 => {
1627 self.string_deflate_to_utf8(&src_str, FE::Utf16, dst_opts)
1628 }
1629 StringEncoding::Utf16 => {
1630 self.string_copy(&src_str, FE::Utf16, dst_opts, FE::Utf16)
1631 }
1632 StringEncoding::CompactUtf16 => {
1633 self.string_compact_utf16_to_compact(&src_str, dst_opts)
1634 }
1635 };
1636
1637 self.instruction(Else);
1638
1639 self.validate_guest_pointer(
1642 src_opts,
1643 &src_str.ptr,
1644 &AllocSize::Local(src_str.len.idx),
1645 2,
1646 Trap::StringOutOfBounds,
1647 );
1648
1649 let s2 = match dst_opts.string_encoding {
1653 StringEncoding::Utf16 => {
1654 self.string_copy(&src_str, FE::Latin1, dst_opts, FE::Utf16)
1655 }
1656 StringEncoding::Utf8 => {
1657 self.string_deflate_to_utf8(&src_str, FE::Latin1, dst_opts)
1658 }
1659 StringEncoding::CompactUtf16 => {
1660 self.string_copy(&src_str, FE::Latin1, dst_opts, FE::Latin1)
1661 }
1662 };
1663 self.instruction(LocalGet(s2.ptr.idx));
1666 self.instruction(LocalSet(s1.ptr.idx));
1667 self.instruction(LocalGet(s2.len.idx));
1668 self.instruction(LocalSet(s1.len.idx));
1669 self.instruction(End);
1670 self.free_temp_local(s2.ptr);
1671 self.free_temp_local(s2.len);
1672 s1
1673 }
1674 };
1675
1676 match dst {
1678 Destination::Stack(s, _) => {
1679 self.instruction(LocalGet(dst_str.ptr.idx));
1680 self.stack_set(&s[..1], dst_mem_opts.ptr());
1681 self.instruction(LocalGet(dst_str.len.idx));
1682 self.stack_set(&s[1..], dst_mem_opts.ptr());
1683 }
1684 Destination::Memory(mem) => {
1685 self.instruction(LocalGet(mem.addr.idx));
1686 self.instruction(LocalGet(dst_str.ptr.idx));
1687 self.ptr_store(mem);
1688 self.instruction(LocalGet(mem.addr.idx));
1689 self.instruction(LocalGet(dst_str.len.idx));
1690 self.ptr_store(&mem.bump(dst_mem_opts.ptr_size().into()));
1691 }
1692 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1693 }
1694
1695 self.free_temp_local(src_str.ptr);
1696 self.free_temp_local(src_str.len);
1697 self.free_temp_local(dst_str.ptr);
1698 self.free_temp_local(dst_str.len);
1699 }
1700
1701 fn string_copy<'c>(
1714 &mut self,
1715 src: &WasmString<'_>,
1716 src_enc: FE,
1717 dst_opts: &'c Options,
1718 dst_enc: FE,
1719 ) -> WasmString<'c> {
1720 assert!(dst_enc.width() >= src_enc.width());
1721
1722 self.validate_string_length(src, dst_enc);
1727
1728 let src_mem_opts = {
1729 match &src.opts.data_model {
1730 DataModel::Gc {} => todo!("CM+GC"),
1731 DataModel::LinearMemory(opts) => opts,
1732 }
1733 };
1734 let dst_mem_opts = {
1735 match &dst_opts.data_model {
1736 DataModel::Gc {} => todo!("CM+GC"),
1737 DataModel::LinearMemory(opts) => opts,
1738 }
1739 };
1740
1741 self.convert_src_len_to_dst(src.len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
1744 let dst_len = self.local_tee_new_tmp(dst_mem_opts.ptr());
1745 if dst_enc.width() > 1 {
1746 assert_eq!(dst_enc.width(), 2);
1747 self.ptr_uconst(dst_mem_opts, 1);
1748 self.ptr_shl(dst_mem_opts);
1749 }
1750 let dst_byte_len = self.local_set_new_tmp(dst_mem_opts.ptr());
1751
1752 let dst = {
1755 let dst_mem = self.malloc(
1756 dst_opts,
1757 AllocSize::Local(dst_byte_len.idx),
1758 dst_enc.align().into(),
1759 Trap::StringOutOfBounds,
1760 );
1761 WasmString {
1762 ptr: dst_mem.addr,
1763 len: dst_len,
1764 opts: dst_opts,
1765 }
1766 };
1767
1768 let op = if src_enc == dst_enc {
1772 Transcode::Copy(src_enc)
1773 } else {
1774 assert_eq!(src_enc, FE::Latin1);
1775 assert_eq!(dst_enc, FE::Utf16);
1776 Transcode::Latin1ToUtf16
1777 };
1778 let transcode = self.transcoder(src, &dst, op);
1779 self.instruction(LocalGet(src.ptr.idx));
1780 self.instruction(LocalGet(src.len.idx));
1781 self.instruction(LocalGet(dst.ptr.idx));
1782 self.instruction(Call(transcode.as_u32()));
1783
1784 self.free_temp_local(dst_byte_len);
1785
1786 dst
1787 }
1788
1789 fn string_deflate_to_utf8<'c>(
1802 &mut self,
1803 src: &WasmString<'_>,
1804 src_enc: FE,
1805 dst_opts: &'c Options,
1806 ) -> WasmString<'c> {
1807 let src_mem_opts = match &src.opts.data_model {
1808 DataModel::Gc {} => todo!("CM+GC"),
1809 DataModel::LinearMemory(opts) => opts,
1810 };
1811 let dst_mem_opts = match &dst_opts.data_model {
1812 DataModel::Gc {} => todo!("CM+GC"),
1813 DataModel::LinearMemory(opts) => opts,
1814 };
1815
1816 self.validate_string_length(src, src_enc);
1817
1818 self.convert_src_len_to_dst(
1822 src.len.idx,
1823 src.opts.data_model.unwrap_memory().ptr(),
1824 dst_opts.data_model.unwrap_memory().ptr(),
1825 );
1826 let dst_len = self.local_tee_new_tmp(dst_opts.data_model.unwrap_memory().ptr());
1827 let dst_byte_len = self.local_set_new_tmp(dst_opts.data_model.unwrap_memory().ptr());
1828
1829 let dst = {
1830 let dst_mem = self.malloc(
1831 dst_opts,
1832 AllocSize::Local(dst_byte_len.idx),
1833 1,
1834 Trap::StringOutOfBounds,
1835 );
1836 WasmString {
1837 ptr: dst_mem.addr,
1838 len: dst_len,
1839 opts: dst_opts,
1840 }
1841 };
1842
1843 let op = match src_enc {
1845 FE::Latin1 => Transcode::Latin1ToUtf8,
1846 FE::Utf16 => Transcode::Utf16ToUtf8,
1847 FE::Utf8 => unreachable!(),
1848 };
1849 let transcode = self.transcoder(src, &dst, op);
1850 self.instruction(LocalGet(src.ptr.idx));
1851 self.instruction(LocalGet(src.len.idx));
1852 self.instruction(LocalGet(dst.ptr.idx));
1853 self.instruction(LocalGet(dst_byte_len.idx));
1854 self.instruction(I32Const(1)); self.instruction(Call(transcode.as_u32()));
1856 self.instruction(LocalSet(dst.len.idx));
1857 let src_len_tmp = self.local_set_new_tmp(src.opts.data_model.unwrap_memory().ptr());
1858
1859 self.instruction(LocalGet(src_len_tmp.idx));
1863 self.instruction(LocalGet(src.len.idx));
1864 self.ptr_ne(src_mem_opts);
1865 self.instruction(If(BlockType::Empty));
1866
1867 let factor = match src_enc {
1870 FE::Latin1 => 2,
1871 FE::Utf16 => 3,
1872 _ => unreachable!(),
1873 };
1874 self.validate_string_length_u8(src, factor);
1875 self.convert_src_len_to_dst(
1876 src.len.idx,
1877 src.opts.data_model.unwrap_memory().ptr(),
1878 dst_opts.data_model.unwrap_memory().ptr(),
1879 );
1880 self.ptr_uconst(dst_mem_opts, factor.into());
1881 self.ptr_mul(dst_mem_opts);
1882 let new_byte_len = self.local_set_new_tmp(dst_mem_opts.ptr());
1883
1884 self.realloc(
1888 dst_opts,
1889 &dst.ptr,
1890 AllocSize::Local(dst_byte_len.idx),
1891 AllocSize::Local(new_byte_len.idx),
1892 1,
1893 Trap::StringOutOfBounds,
1894 );
1895 self.instruction(LocalGet(new_byte_len.idx));
1896 self.instruction(LocalSet(dst_byte_len.idx));
1897 self.free_temp_local(new_byte_len);
1898
1899 self.instruction(LocalGet(src.ptr.idx));
1904 self.instruction(LocalGet(src_len_tmp.idx));
1905 if let FE::Utf16 = src_enc {
1906 self.ptr_uconst(src_mem_opts, 1);
1907 self.ptr_shl(src_mem_opts);
1908 }
1909 self.ptr_add(src_mem_opts);
1910 self.instruction(LocalGet(src.len.idx));
1911 self.instruction(LocalGet(src_len_tmp.idx));
1912 self.ptr_sub(src_mem_opts);
1913 self.instruction(LocalGet(dst.ptr.idx));
1914 self.instruction(LocalGet(dst.len.idx));
1915 self.ptr_add(dst_mem_opts);
1916 self.instruction(LocalGet(dst_byte_len.idx));
1917 self.instruction(LocalGet(dst.len.idx));
1918 self.ptr_sub(dst_mem_opts);
1919 self.instruction(I32Const(0)); self.instruction(Call(transcode.as_u32()));
1921
1922 self.instruction(LocalGet(dst.len.idx));
1926 self.ptr_add(dst_mem_opts);
1927 self.instruction(LocalSet(dst.len.idx));
1928
1929 if self.module.tunables.debug_adapter_modules {
1932 self.instruction(LocalGet(src.len.idx));
1933 self.instruction(LocalGet(src_len_tmp.idx));
1934 self.ptr_sub(src_mem_opts);
1935 self.ptr_ne(src_mem_opts);
1936 self.instruction(If(BlockType::Empty));
1937 self.trap(Trap::DebugAssertStringEncodingFinished);
1938 self.instruction(End);
1939 } else {
1940 self.instruction(Drop);
1941 }
1942
1943 self.instruction(LocalGet(dst.len.idx));
1945 self.instruction(LocalGet(dst_byte_len.idx));
1946 self.ptr_ne(dst_mem_opts);
1947 self.instruction(If(BlockType::Empty));
1948 self.realloc(
1949 dst_opts,
1950 &dst.ptr,
1951 AllocSize::Local(dst_byte_len.idx),
1952 AllocSize::Local(dst.len.idx),
1953 1,
1954 Trap::StringOutOfBounds,
1955 );
1956 self.instruction(End);
1957
1958 if self.module.tunables.debug_adapter_modules {
1961 self.instruction(Else);
1962
1963 self.instruction(LocalGet(dst.len.idx));
1964 self.instruction(LocalGet(dst_byte_len.idx));
1965 self.ptr_ne(dst_mem_opts);
1966 self.instruction(If(BlockType::Empty));
1967 self.trap(Trap::DebugAssertStringEncodingFinished);
1968 self.instruction(End);
1969 }
1970
1971 self.instruction(End); self.free_temp_local(src_len_tmp);
1974 self.free_temp_local(dst_byte_len);
1975
1976 dst
1977 }
1978
1979 fn string_utf8_to_utf16<'c>(
1994 &mut self,
1995 src: &WasmString<'_>,
1996 dst_opts: &'c Options,
1997 ) -> WasmString<'c> {
1998 let src_mem_opts = match &src.opts.data_model {
1999 DataModel::Gc {} => todo!("CM+GC"),
2000 DataModel::LinearMemory(opts) => opts,
2001 };
2002 let dst_mem_opts = match &dst_opts.data_model {
2003 DataModel::Gc {} => todo!("CM+GC"),
2004 DataModel::LinearMemory(opts) => opts,
2005 };
2006
2007 self.validate_string_length(src, FE::Utf16);
2008 self.convert_src_len_to_dst(
2009 src.len.idx,
2010 src_mem_opts.ptr(),
2011 dst_opts.data_model.unwrap_memory().ptr(),
2012 );
2013 let dst_len = self.local_tee_new_tmp(dst_opts.data_model.unwrap_memory().ptr());
2014 self.ptr_uconst(dst_mem_opts, 1);
2015 self.ptr_shl(dst_mem_opts);
2016 let dst_byte_len = self.local_set_new_tmp(dst_opts.data_model.unwrap_memory().ptr());
2017 let dst = {
2018 let dst_mem = self.malloc(
2019 dst_opts,
2020 AllocSize::Local(dst_byte_len.idx),
2021 2,
2022 Trap::StringOutOfBounds,
2023 );
2024 WasmString {
2025 ptr: dst_mem.addr,
2026 len: dst_len,
2027 opts: dst_opts,
2028 }
2029 };
2030
2031 let transcode = self.transcoder(src, &dst, Transcode::Utf8ToUtf16);
2032 self.instruction(LocalGet(src.ptr.idx));
2033 self.instruction(LocalGet(src.len.idx));
2034 self.instruction(LocalGet(dst.ptr.idx));
2035 self.instruction(Call(transcode.as_u32()));
2036 self.instruction(LocalSet(dst.len.idx));
2037
2038 self.convert_src_len_to_dst(src.len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2046 self.instruction(LocalGet(dst.len.idx));
2047 self.ptr_ne(dst_mem_opts);
2048 self.instruction(If(BlockType::Empty));
2049 self.realloc(
2050 dst.opts,
2051 &dst.ptr,
2052 AllocSize::Local(dst_byte_len.idx),
2053 AllocSize::DoubleLocal(dst.len.idx),
2054 2,
2055 Trap::StringOutOfBounds,
2056 );
2057 self.instruction(End); self.free_temp_local(dst_byte_len);
2060
2061 dst
2062 }
2063
2064 fn string_compact_utf16_to_compact<'c>(
2078 &mut self,
2079 src: &WasmString<'_>,
2080 dst_opts: &'c Options,
2081 ) -> WasmString<'c> {
2082 let src_mem_opts = match &src.opts.data_model {
2083 DataModel::Gc {} => todo!("CM+GC"),
2084 DataModel::LinearMemory(opts) => opts,
2085 };
2086 let dst_mem_opts = match &dst_opts.data_model {
2087 DataModel::Gc {} => todo!("CM+GC"),
2088 DataModel::LinearMemory(opts) => opts,
2089 };
2090
2091 self.validate_string_length(src, FE::Utf16);
2092 self.convert_src_len_to_dst(src.len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2093 let dst_len = self.local_tee_new_tmp(dst_mem_opts.ptr());
2094 self.ptr_uconst(dst_mem_opts, 1);
2095 self.ptr_shl(dst_mem_opts);
2096 let dst_byte_len = self.local_set_new_tmp(dst_mem_opts.ptr());
2097 let dst = {
2098 let dst_mem = self.malloc(
2099 dst_opts,
2100 AllocSize::Local(dst_byte_len.idx),
2101 2,
2102 Trap::StringOutOfBounds,
2103 );
2104 WasmString {
2105 ptr: dst_mem.addr,
2106 len: dst_len,
2107 opts: dst_opts,
2108 }
2109 };
2110
2111 self.convert_src_len_to_dst(
2112 dst_byte_len.idx,
2113 dst.opts.data_model.unwrap_memory().ptr(),
2114 src_mem_opts.ptr(),
2115 );
2116 let src_byte_len = self.local_set_new_tmp(src_mem_opts.ptr());
2117
2118 let transcode = self.transcoder(src, &dst, Transcode::Utf16ToCompactProbablyUtf16);
2119 self.instruction(LocalGet(src.ptr.idx));
2120 self.instruction(LocalGet(src.len.idx));
2121 self.instruction(LocalGet(dst.ptr.idx));
2122 self.instruction(Call(transcode.as_u32()));
2123 self.instruction(LocalSet(dst.len.idx));
2124
2125 if self.module.tunables.debug_adapter_modules {
2128 self.instruction(LocalGet(dst.len.idx));
2129 self.ptr_uconst(dst_mem_opts, !UTF16_TAG);
2130 self.ptr_and(dst_mem_opts);
2131 self.convert_src_len_to_dst(src.len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2132 self.ptr_ne(dst_mem_opts);
2133 self.instruction(If(BlockType::Empty));
2134 self.trap(Trap::DebugAssertEqualCodeUnits);
2135 self.instruction(End);
2136 }
2137
2138 self.instruction(LocalGet(dst.len.idx));
2142 self.ptr_uconst(dst_mem_opts, UTF16_TAG);
2143 self.ptr_and(dst_mem_opts);
2144 self.ptr_br_if(dst_mem_opts, 0);
2145
2146 self.realloc(
2148 dst.opts,
2149 &dst.ptr,
2150 AllocSize::Local(dst_byte_len.idx),
2151 AllocSize::Local(dst.len.idx),
2152 2,
2153 Trap::StringOutOfBounds,
2154 );
2155
2156 self.free_temp_local(dst_byte_len);
2157 self.free_temp_local(src_byte_len);
2158
2159 dst
2160 }
2161
2162 fn string_to_compact<'c>(
2169 &mut self,
2170 src: &WasmString<'_>,
2171 src_enc: FE,
2172 dst_opts: &'c Options,
2173 ) -> WasmString<'c> {
2174 let src_mem_opts = match &src.opts.data_model {
2175 DataModel::Gc {} => todo!("CM+GC"),
2176 DataModel::LinearMemory(opts) => opts,
2177 };
2178 let dst_mem_opts = match &dst_opts.data_model {
2179 DataModel::Gc {} => todo!("CM+GC"),
2180 DataModel::LinearMemory(opts) => opts,
2181 };
2182
2183 self.validate_string_length(src, src_enc);
2184
2185 self.convert_src_len_to_dst(src.len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2186 let dst_len = self.local_tee_new_tmp(dst_mem_opts.ptr());
2187 let dst_byte_len = self.local_set_new_tmp(dst_mem_opts.ptr());
2188 let dst = {
2189 let dst_mem = self.malloc(
2190 dst_opts,
2191 AllocSize::Local(dst_byte_len.idx),
2192 2,
2193 Trap::StringOutOfBounds,
2194 );
2195 WasmString {
2196 ptr: dst_mem.addr,
2197 len: dst_len,
2198 opts: dst_opts,
2199 }
2200 };
2201
2202 let (latin1, utf16) = match src_enc {
2206 FE::Utf8 => (Transcode::Utf8ToLatin1, Transcode::Utf8ToCompactUtf16),
2207 FE::Utf16 => (Transcode::Utf16ToLatin1, Transcode::Utf16ToCompactUtf16),
2208 FE::Latin1 => unreachable!(),
2209 };
2210 let transcode_latin1 = self.transcoder(src, &dst, latin1);
2211 let transcode_utf16 = self.transcoder(src, &dst, utf16);
2212 self.instruction(LocalGet(src.ptr.idx));
2213 self.instruction(LocalGet(src.len.idx));
2214 self.instruction(LocalGet(dst.ptr.idx));
2215 self.instruction(Call(transcode_latin1.as_u32()));
2216 self.instruction(LocalSet(dst.len.idx));
2217 let src_len_tmp = self.local_set_new_tmp(src_mem_opts.ptr());
2218
2219 self.instruction(LocalGet(src_len_tmp.idx));
2222 self.instruction(LocalGet(src.len.idx));
2223 self.ptr_eq(src_mem_opts);
2224 self.instruction(If(BlockType::Empty)); self.instruction(LocalGet(dst_byte_len.idx));
2230 self.instruction(LocalGet(dst.len.idx));
2231 self.ptr_ne(dst_mem_opts);
2232 self.instruction(If(BlockType::Empty));
2233 self.realloc(
2234 dst.opts,
2235 &dst.ptr,
2236 AllocSize::Local(dst_byte_len.idx),
2237 AllocSize::Local(dst.len.idx),
2238 2,
2239 Trap::StringOutOfBounds,
2240 );
2241 self.instruction(End);
2242
2243 self.instruction(Else); if src_enc.width() == 1 {
2252 self.validate_string_length_u8(src, 2);
2253 }
2254
2255 self.convert_src_len_to_dst(src.len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2258 self.ptr_uconst(dst_mem_opts, 1);
2259 self.ptr_shl(dst_mem_opts);
2260 let new_byte_len = self.local_set_new_tmp(dst_mem_opts.ptr());
2261 self.realloc(
2262 dst.opts,
2263 &dst.ptr,
2264 AllocSize::Local(dst_byte_len.idx),
2265 AllocSize::Local(new_byte_len.idx),
2266 2,
2267 Trap::StringOutOfBounds,
2268 );
2269 self.instruction(LocalGet(new_byte_len.idx));
2270 self.instruction(LocalSet(dst_byte_len.idx));
2271 self.free_temp_local(new_byte_len);
2272
2273 self.instruction(LocalGet(src.ptr.idx));
2277 self.instruction(LocalGet(src_len_tmp.idx));
2278 if let FE::Utf16 = src_enc {
2279 self.ptr_uconst(src_mem_opts, 1);
2280 self.ptr_shl(src_mem_opts);
2281 }
2282 self.ptr_add(src_mem_opts);
2283 self.instruction(LocalGet(src.len.idx));
2284 self.instruction(LocalGet(src_len_tmp.idx));
2285 self.ptr_sub(src_mem_opts);
2286 self.instruction(LocalGet(dst.ptr.idx));
2287 self.convert_src_len_to_dst(src.len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2288 self.instruction(LocalGet(dst.len.idx));
2289 self.instruction(Call(transcode_utf16.as_u32()));
2290 self.instruction(LocalSet(dst.len.idx));
2291
2292 self.instruction(LocalGet(dst.len.idx));
2300 self.convert_src_len_to_dst(src.len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2301 self.ptr_ne(dst_mem_opts);
2302 self.instruction(If(BlockType::Empty));
2303 self.realloc(
2304 dst.opts,
2305 &dst.ptr,
2306 AllocSize::Local(dst_byte_len.idx),
2307 AllocSize::DoubleLocal(dst.len.idx),
2308 2,
2309 Trap::StringOutOfBounds,
2310 );
2311 self.instruction(End);
2312
2313 self.instruction(LocalGet(dst.len.idx));
2315 self.ptr_uconst(dst_mem_opts, UTF16_TAG);
2316 self.ptr_or(dst_mem_opts);
2317 self.instruction(LocalSet(dst.len.idx));
2318
2319 self.instruction(End); self.free_temp_local(src_len_tmp);
2322 self.free_temp_local(dst_byte_len);
2323
2324 dst
2325 }
2326
2327 fn validate_string_length(&mut self, src: &WasmString<'_>, dst: FE) {
2328 self.validate_string_length_u8(src, dst.width())
2329 }
2330
2331 fn validate_string_length_u8(&mut self, s: &WasmString<'_>, dst: u8) {
2332 let mem_opts = match &s.opts.data_model {
2333 DataModel::Gc {} => todo!("CM+GC"),
2334 DataModel::LinearMemory(opts) => opts,
2335 };
2336
2337 self.instruction(LocalGet(s.len.idx));
2340 let max = MAX_STRING_BYTE_LENGTH / u32::from(dst);
2341 self.ptr_uconst(mem_opts, max);
2342 self.ptr_gt_u(mem_opts);
2343 self.instruction(If(BlockType::Empty));
2344 self.trap(Trap::StringOutOfBounds);
2345 self.instruction(End);
2346 }
2347
2348 fn transcoder(
2349 &mut self,
2350 src: &WasmString<'_>,
2351 dst: &WasmString<'_>,
2352 op: Transcode,
2353 ) -> FuncIndex {
2354 match (src.opts.data_model, dst.opts.data_model) {
2355 (DataModel::Gc {}, _) | (_, DataModel::Gc {}) => {
2356 todo!("CM+GC")
2357 }
2358 (
2359 DataModel::LinearMemory(LinearMemoryOptions {
2360 memory: Some((src_mem, src_ty)),
2361 realloc: _,
2362 }),
2363 DataModel::LinearMemory(LinearMemoryOptions {
2364 memory: Some((dst_mem, dst_ty)),
2365 realloc: _,
2366 }),
2367 ) => self.module.import_transcoder(Transcoder {
2368 from_memory: src_mem,
2369 from_memory64: src_ty.idx_type == IndexType::I64,
2370 to_memory: dst_mem,
2371 to_memory64: dst_ty.idx_type == IndexType::I64,
2372 op,
2373 }),
2374 (DataModel::LinearMemory(LinearMemoryOptions { memory: None, .. }), _)
2375 | (_, DataModel::LinearMemory(LinearMemoryOptions { memory: None, .. })) => {
2376 unreachable!()
2377 }
2378 }
2379 }
2380
2381 fn begin_translate_sequence<'c>(
2390 &mut self,
2391 src: &Source<'c>,
2392 dst: &Destination<'c>,
2393 src_element_size: u32,
2394 src_element_align: u32,
2395 dst_element_size: u32,
2396 dst_element_align: u32,
2397 ) -> SequenceTranslation<'c> {
2398 let src_mem_opts = match &src.opts().data_model {
2399 DataModel::Gc {} => todo!("CM+GC"),
2400 DataModel::LinearMemory(opts) => opts,
2401 };
2402 let dst_mem_opts = match &dst.opts().data_model {
2403 DataModel::Gc {} => todo!("CM+GC"),
2404 DataModel::LinearMemory(opts) => opts,
2405 };
2406
2407 let src_opts = src.opts();
2408 let dst_opts = dst.opts();
2409
2410 match src {
2415 Source::Stack(s) => {
2416 assert_eq!(s.locals.len(), 2);
2417 self.stack_get(&s.slice(0..1), src_mem_opts.ptr());
2418 self.stack_get(&s.slice(1..2), src_mem_opts.ptr());
2419 }
2420 Source::Memory(mem) => {
2421 self.ptr_load(mem);
2422 self.ptr_load(&mem.bump(src_mem_opts.ptr_size().into()));
2423 }
2424 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
2425 }
2426 let src_len = self.local_set_new_tmp(src_mem_opts.ptr());
2427 let src_ptr = self.local_set_new_tmp(src_mem_opts.ptr());
2428
2429 let src_byte_len =
2431 self.calculate_list_byte_len(src_mem_opts, src_len.idx, src_element_size);
2432 let dst_byte_len = if src_element_size == dst_element_size {
2433 self.convert_src_len_to_dst(src_byte_len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2434 self.local_set_new_tmp(dst_mem_opts.ptr())
2435 } else if src_mem_opts.ptr() == dst_mem_opts.ptr() {
2436 self.calculate_list_byte_len(dst_mem_opts, src_len.idx, dst_element_size)
2437 } else {
2438 self.convert_src_len_to_dst(src_len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2439 let tmp = self.local_set_new_tmp(dst_mem_opts.ptr());
2440 let ret = self.calculate_list_byte_len(dst_mem_opts, tmp.idx, dst_element_size);
2441 self.free_temp_local(tmp);
2442 ret
2443 };
2444
2445 let src_mem = self.memory_operand(
2448 src_opts,
2449 src_ptr,
2450 AllocSize::Local(src_byte_len.idx),
2451 src_element_align,
2452 Trap::ListOutOfBounds,
2453 );
2454
2455 let dst_mem = self.malloc(
2460 dst_opts,
2461 AllocSize::Local(dst_byte_len.idx),
2462 dst_element_align,
2463 Trap::ListOutOfBounds,
2464 );
2465
2466 self.free_temp_local(src_byte_len);
2467 self.free_temp_local(dst_byte_len);
2468
2469 let loop_state = if src_element_size > 0 || dst_element_size > 0 {
2473 self.instruction(Block(BlockType::Empty));
2474
2475 self.instruction(LocalGet(src_len.idx));
2477 let remaining = self.local_tee_new_tmp(src_mem_opts.ptr());
2478 self.ptr_eqz(src_mem_opts);
2479 self.instruction(BrIf(0));
2480
2481 self.instruction(LocalGet(src_mem.addr.idx));
2483 let cur_src_ptr = self.local_set_new_tmp(src_mem_opts.ptr());
2484 self.instruction(LocalGet(dst_mem.addr.idx));
2485 let cur_dst_ptr = self.local_set_new_tmp(dst_mem_opts.ptr());
2486
2487 self.instruction(Loop(BlockType::Empty));
2488
2489 Some(SequenceLoopState {
2490 remaining,
2491 cur_src_ptr,
2492 cur_dst_ptr,
2493 })
2494 } else {
2495 None
2496 };
2497
2498 SequenceTranslation {
2499 src_len,
2500 src_mem,
2501 dst_mem,
2502 src_opts,
2503 dst_opts,
2504 src_mem_opts,
2505 dst_mem_opts,
2506 loop_state,
2507 }
2508 }
2509
2510 fn end_translate_sequence(&mut self, seq: SequenceTranslation<'_>, dst: &Destination) {
2516 if let Some(loop_state) = seq.loop_state {
2517 self.instruction(LocalGet(loop_state.remaining.idx));
2520 self.ptr_iconst(seq.src_mem_opts, -1);
2521 self.ptr_add(seq.src_mem_opts);
2522 self.instruction(LocalTee(loop_state.remaining.idx));
2523 self.ptr_br_if(seq.src_mem_opts, 0);
2524 self.instruction(End); self.instruction(End); self.free_temp_local(loop_state.cur_dst_ptr);
2528 self.free_temp_local(loop_state.cur_src_ptr);
2529 self.free_temp_local(loop_state.remaining);
2530 }
2531
2532 match dst {
2534 Destination::Stack(s, _) => {
2535 self.instruction(LocalGet(seq.dst_mem.addr.idx));
2536 self.stack_set(&s[..1], seq.dst_mem_opts.ptr());
2537 self.convert_src_len_to_dst(
2538 seq.src_len.idx,
2539 seq.src_mem_opts.ptr(),
2540 seq.dst_mem_opts.ptr(),
2541 );
2542 self.stack_set(&s[1..], seq.dst_mem_opts.ptr());
2543 }
2544 Destination::Memory(mem) => {
2545 self.instruction(LocalGet(mem.addr.idx));
2546 self.instruction(LocalGet(seq.dst_mem.addr.idx));
2547 self.ptr_store(mem);
2548 self.instruction(LocalGet(mem.addr.idx));
2549 self.convert_src_len_to_dst(
2550 seq.src_len.idx,
2551 seq.src_mem_opts.ptr(),
2552 seq.dst_mem_opts.ptr(),
2553 );
2554 self.ptr_store(&mem.bump(seq.dst_mem_opts.ptr_size().into()));
2555 }
2556 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
2557 }
2558
2559 self.free_temp_local(seq.src_len);
2560 self.free_temp_local(seq.src_mem.addr);
2561 self.free_temp_local(seq.dst_mem.addr);
2562 }
2563
2564 fn translate_list(
2565 &mut self,
2566 src_ty: TypeListIndex,
2567 src: &Source<'_>,
2568 dst_ty: &InterfaceType,
2569 dst: &Destination,
2570 ) {
2571 let src_mem_opts = match &src.opts().data_model {
2572 DataModel::Gc {} => todo!("CM+GC"),
2573 DataModel::LinearMemory(opts) => opts,
2574 };
2575 let dst_mem_opts = match &dst.opts().data_model {
2576 DataModel::Gc {} => todo!("CM+GC"),
2577 DataModel::LinearMemory(opts) => opts,
2578 };
2579
2580 let src_element_ty = &self.types[src_ty].element;
2581 let dst_element_ty = match dst_ty {
2582 InterfaceType::List(r) => &self.types[*r].element,
2583 _ => panic!("expected a list"),
2584 };
2585 let (src_size, src_align) = self.types.size_align(src_mem_opts, src_element_ty);
2586 let (dst_size, dst_align) = self.types.size_align(dst_mem_opts, dst_element_ty);
2587
2588 let seq = self.begin_translate_sequence(src, dst, src_size, src_align, dst_size, dst_align);
2589
2590 if let Some(ref loop_state) = seq.loop_state {
2591 let element_src = Source::Memory(Memory {
2592 opts: seq.src_opts,
2593 offset: 0,
2594 addr: TempLocal::new(loop_state.cur_src_ptr.idx, loop_state.cur_src_ptr.ty),
2595 });
2596 let element_dst = Destination::Memory(Memory {
2597 opts: seq.dst_opts,
2598 offset: 0,
2599 addr: TempLocal::new(loop_state.cur_dst_ptr.idx, loop_state.cur_dst_ptr.ty),
2600 });
2601 self.translate(src_element_ty, &element_src, dst_element_ty, &element_dst);
2602
2603 if src_size > 0 {
2604 self.instruction(LocalGet(loop_state.cur_src_ptr.idx));
2605 self.ptr_uconst(src_mem_opts, src_size);
2606 self.ptr_add(src_mem_opts);
2607 self.instruction(LocalSet(loop_state.cur_src_ptr.idx));
2608 }
2609 if dst_size > 0 {
2610 self.instruction(LocalGet(loop_state.cur_dst_ptr.idx));
2611 self.ptr_uconst(dst_mem_opts, dst_size);
2612 self.ptr_add(dst_mem_opts);
2613 self.instruction(LocalSet(loop_state.cur_dst_ptr.idx));
2614 }
2615 }
2616
2617 self.end_translate_sequence(seq, dst);
2618 }
2619
2620 fn translate_map(
2626 &mut self,
2627 src_ty: TypeMapIndex,
2628 src: &Source<'_>,
2629 dst_ty: &InterfaceType,
2630 dst: &Destination,
2631 ) {
2632 let src_mem_opts = match &src.opts().data_model {
2633 DataModel::Gc {} => todo!("CM+GC"),
2634 DataModel::LinearMemory(opts) => opts,
2635 };
2636 let dst_mem_opts = match &dst.opts().data_model {
2637 DataModel::Gc {} => todo!("CM+GC"),
2638 DataModel::LinearMemory(opts) => opts,
2639 };
2640
2641 let src_map_ty = &self.types[src_ty];
2642 let dst_map_ty = match dst_ty {
2643 InterfaceType::Map(r) => &self.types[*r],
2644 _ => panic!("expected a map"),
2645 };
2646
2647 let src_key_abi = self.types.canonical_abi(&src_map_ty.key);
2649 let src_value_abi = self.types.canonical_abi(&src_map_ty.value);
2650 let src_entry_abi = CanonicalAbiInfo::record([src_key_abi, src_value_abi].into_iter());
2651 let (src_tuple_size, src_entry_align) = src_mem_opts.sizealign(&src_entry_abi);
2652 let src_value_offset = {
2653 let mut offset = 0u32;
2654 if src_mem_opts.memory64() {
2655 src_key_abi.next_field64(&mut offset);
2656 src_value_abi.next_field64(&mut offset)
2657 } else {
2658 src_key_abi.next_field32(&mut offset);
2659 src_value_abi.next_field32(&mut offset)
2660 }
2661 };
2662
2663 let dst_key_abi = self.types.canonical_abi(&dst_map_ty.key);
2664 let dst_value_abi = self.types.canonical_abi(&dst_map_ty.value);
2665 let dst_entry_abi = CanonicalAbiInfo::record([dst_key_abi, dst_value_abi].into_iter());
2666 let (dst_tuple_size, dst_entry_align) = dst_mem_opts.sizealign(&dst_entry_abi);
2667 let dst_value_offset = {
2668 let mut offset = 0u32;
2669 if dst_mem_opts.memory64() {
2670 dst_key_abi.next_field64(&mut offset);
2671 dst_value_abi.next_field64(&mut offset)
2672 } else {
2673 dst_key_abi.next_field32(&mut offset);
2674 dst_value_abi.next_field32(&mut offset)
2675 }
2676 };
2677
2678 let seq = self.begin_translate_sequence(
2679 src,
2680 dst,
2681 src_tuple_size,
2682 src_entry_align,
2683 dst_tuple_size,
2684 dst_entry_align,
2685 );
2686
2687 if let Some(ref loop_state) = seq.loop_state {
2688 let key_src = Source::Memory(Memory {
2689 opts: seq.src_opts,
2690 offset: 0,
2691 addr: TempLocal::new(loop_state.cur_src_ptr.idx, src_mem_opts.ptr()),
2692 });
2693 let key_dst = Destination::Memory(Memory {
2694 opts: seq.dst_opts,
2695 offset: 0,
2696 addr: TempLocal::new(loop_state.cur_dst_ptr.idx, dst_mem_opts.ptr()),
2697 });
2698 self.translate(&src_map_ty.key, &key_src, &dst_map_ty.key, &key_dst);
2699
2700 let value_src = Source::Memory(Memory {
2701 opts: seq.src_opts,
2702 offset: src_value_offset,
2703 addr: TempLocal::new(loop_state.cur_src_ptr.idx, src_mem_opts.ptr()),
2704 });
2705 let value_dst = Destination::Memory(Memory {
2706 opts: seq.dst_opts,
2707 offset: dst_value_offset,
2708 addr: TempLocal::new(loop_state.cur_dst_ptr.idx, dst_mem_opts.ptr()),
2709 });
2710 self.translate(&src_map_ty.value, &value_src, &dst_map_ty.value, &value_dst);
2711
2712 if src_tuple_size > 0 {
2714 self.instruction(LocalGet(loop_state.cur_src_ptr.idx));
2715 self.ptr_uconst(src_mem_opts, src_tuple_size);
2716 self.ptr_add(src_mem_opts);
2717 self.instruction(LocalSet(loop_state.cur_src_ptr.idx));
2718 }
2719 if dst_tuple_size > 0 {
2720 self.instruction(LocalGet(loop_state.cur_dst_ptr.idx));
2721 self.ptr_uconst(dst_mem_opts, dst_tuple_size);
2722 self.ptr_add(dst_mem_opts);
2723 self.instruction(LocalSet(loop_state.cur_dst_ptr.idx));
2724 }
2725 }
2726
2727 self.end_translate_sequence(seq, dst);
2728 }
2729
2730 fn calculate_list_byte_len(
2731 &mut self,
2732 opts: &LinearMemoryOptions,
2733 len_local: u32,
2734 elt_size: u32,
2735 ) -> TempLocal {
2736 if elt_size == 0 {
2739 self.ptr_uconst(opts, 0);
2740 return self.local_set_new_tmp(opts.ptr());
2741 }
2742
2743 if elt_size == 1 {
2751 if let ValType::I64 = opts.ptr() {
2752 self.instruction(LocalGet(len_local));
2753 self.instruction(I64Const(32));
2754 self.instruction(I64ShrU);
2755 self.instruction(I32WrapI64);
2756 self.instruction(If(BlockType::Empty));
2757 self.trap(Trap::ListOutOfBounds);
2758 self.instruction(End);
2759 }
2760 self.instruction(LocalGet(len_local));
2761 return self.local_set_new_tmp(opts.ptr());
2762 }
2763
2764 self.instruction(Block(BlockType::Empty));
2769 self.instruction(Block(BlockType::Empty));
2770 self.instruction(LocalGet(len_local));
2771 match opts.ptr() {
2772 ValType::I32 => self.instruction(I64ExtendI32U),
2776
2777 ValType::I64 => {
2781 self.instruction(I64Const(32));
2782 self.instruction(I64ShrU);
2783 self.instruction(I32WrapI64);
2784 self.instruction(BrIf(0));
2785 self.instruction(LocalGet(len_local));
2786 }
2787
2788 _ => unreachable!(),
2789 }
2790
2791 self.instruction(I64Const(elt_size.into()));
2800 self.instruction(I64Mul);
2801 let tmp = self.local_tee_new_tmp(ValType::I64);
2802 self.instruction(I64Const(32));
2805 self.instruction(I64ShrU);
2806 self.instruction(I64Eqz);
2807 self.instruction(BrIf(1));
2808 self.instruction(End);
2809 self.trap(Trap::ListOutOfBounds);
2810 self.instruction(End);
2811
2812 if opts.ptr() == ValType::I64 {
2816 tmp
2817 } else {
2818 self.instruction(LocalGet(tmp.idx));
2819 self.instruction(I32WrapI64);
2820 self.free_temp_local(tmp);
2821 self.local_set_new_tmp(ValType::I32)
2822 }
2823 }
2824
2825 fn convert_src_len_to_dst(
2826 &mut self,
2827 src_len_local: u32,
2828 src_ptr_ty: ValType,
2829 dst_ptr_ty: ValType,
2830 ) {
2831 self.instruction(LocalGet(src_len_local));
2832 match (src_ptr_ty, dst_ptr_ty) {
2833 (ValType::I32, ValType::I64) => self.instruction(I64ExtendI32U),
2834 (ValType::I64, ValType::I32) => self.instruction(I32WrapI64),
2835 (src, dst) => assert_eq!(src, dst),
2836 }
2837 }
2838
2839 fn translate_record(
2840 &mut self,
2841 src_ty: TypeRecordIndex,
2842 src: &Source<'_>,
2843 dst_ty: &InterfaceType,
2844 dst: &Destination,
2845 ) {
2846 let src_ty = &self.types[src_ty];
2847 let dst_ty = match dst_ty {
2848 InterfaceType::Record(r) => &self.types[*r],
2849 _ => panic!("expected a record"),
2850 };
2851
2852 assert_eq!(src_ty.fields.len(), dst_ty.fields.len());
2854
2855 let mut src_fields = HashMap::new();
2859 for (i, src) in src
2860 .record_field_srcs(self.types, src_ty.fields.iter().map(|f| f.ty))
2861 .enumerate()
2862 {
2863 let field = &src_ty.fields[i];
2864 src_fields.insert(&field.name, (src, &field.ty));
2865 }
2866
2867 for (i, dst) in dst
2876 .record_field_dsts(self.types, dst_ty.fields.iter().map(|f| f.ty))
2877 .enumerate()
2878 {
2879 let field = &dst_ty.fields[i];
2880 let (src, src_ty) = &src_fields[&field.name];
2881 self.translate(src_ty, src, &field.ty, &dst);
2882 }
2883 }
2884
2885 fn translate_flags(
2886 &mut self,
2887 src_ty: TypeFlagsIndex,
2888 src: &Source<'_>,
2889 dst_ty: &InterfaceType,
2890 dst: &Destination,
2891 ) {
2892 let src_ty = &self.types[src_ty];
2893 let dst_ty = match dst_ty {
2894 InterfaceType::Flags(r) => &self.types[*r],
2895 _ => panic!("expected a record"),
2896 };
2897
2898 assert_eq!(src_ty.names, dst_ty.names);
2906 let cnt = src_ty.names.len();
2907 match FlagsSize::from_count(cnt) {
2908 FlagsSize::Size0 => {}
2909 FlagsSize::Size1 => {
2910 let mask = if cnt == 8 { 0xff } else { (1 << cnt) - 1 };
2911 self.convert_u8_mask(src, dst, mask);
2912 }
2913 FlagsSize::Size2 => {
2914 let mask = if cnt == 16 { 0xffff } else { (1 << cnt) - 1 };
2915 self.convert_u16_mask(src, dst, mask);
2916 }
2917 FlagsSize::Size4Plus(n) => {
2918 let srcs = src.record_field_srcs(self.types, (0..n).map(|_| InterfaceType::U32));
2919 let dsts = dst.record_field_dsts(self.types, (0..n).map(|_| InterfaceType::U32));
2920 let n = usize::from(n);
2921 for (i, (src, dst)) in srcs.zip(dsts).enumerate() {
2922 let mask = if i == n - 1 && (cnt % 32 != 0) {
2923 (1 << (cnt % 32)) - 1
2924 } else {
2925 0xffffffff
2926 };
2927 self.convert_u32_mask(&src, &dst, mask);
2928 }
2929 }
2930 }
2931 }
2932
2933 fn translate_tuple(
2934 &mut self,
2935 src_ty: TypeTupleIndex,
2936 src: &Source<'_>,
2937 dst_ty: &InterfaceType,
2938 dst: &Destination,
2939 ) {
2940 let src_ty = &self.types[src_ty];
2941 let dst_ty = match dst_ty {
2942 InterfaceType::Tuple(t) => &self.types[*t],
2943 _ => panic!("expected a tuple"),
2944 };
2945
2946 assert_eq!(src_ty.types.len(), dst_ty.types.len());
2948
2949 let srcs = src
2950 .record_field_srcs(self.types, src_ty.types.iter().copied())
2951 .zip(src_ty.types.iter());
2952 let dsts = dst
2953 .record_field_dsts(self.types, dst_ty.types.iter().copied())
2954 .zip(dst_ty.types.iter());
2955 for ((src, src_ty), (dst, dst_ty)) in srcs.zip(dsts) {
2956 self.translate(src_ty, &src, dst_ty, &dst);
2957 }
2958 }
2959
2960 fn translate_fixed_length_list(
2961 &mut self,
2962 src_ty: TypeFixedLengthListIndex,
2963 src: &Source<'_>,
2964 dst_ty: &InterfaceType,
2965 dst: &Destination,
2966 ) {
2967 let src_ty = &self.types[src_ty];
2968 let dst_ty = match dst_ty {
2969 InterfaceType::FixedLengthList(t) => &self.types[*t],
2970 _ => panic!("expected a fixed size list"),
2971 };
2972
2973 assert_eq!(src_ty.size, dst_ty.size);
2975
2976 match (&src, &dst) {
2977 (Source::Memory(src_mem), Destination::Memory(dst_mem)) => {
2979 let src_mem_opts = match &src_mem.opts.data_model {
2980 DataModel::Gc {} => todo!("CM+GC"),
2981 DataModel::LinearMemory(opts) => opts,
2982 };
2983 let dst_mem_opts = match &dst_mem.opts.data_model {
2984 DataModel::Gc {} => todo!("CM+GC"),
2985 DataModel::LinearMemory(opts) => opts,
2986 };
2987 let src_element_bytes = self.types.size_align(src_mem_opts, &src_ty.element).0;
2988 let dst_element_bytes = self.types.size_align(dst_mem_opts, &dst_ty.element).0;
2989 assert_ne!(src_element_bytes, 0);
2990 assert_ne!(dst_element_bytes, 0);
2991
2992 self.instruction(LocalGet(src_mem.addr.idx));
2995 if src_mem.offset != 0 {
2996 self.ptr_uconst(src_mem_opts, src_mem.offset);
2997 self.ptr_add(src_mem_opts);
2998 }
2999 let cur_src_ptr = self.local_set_new_tmp(src_mem_opts.ptr());
3000 self.instruction(LocalGet(dst_mem.addr.idx));
3001 if dst_mem.offset != 0 {
3002 self.ptr_uconst(dst_mem_opts, dst_mem.offset);
3003 self.ptr_add(dst_mem_opts);
3004 }
3005 let cur_dst_ptr = self.local_set_new_tmp(dst_mem_opts.ptr());
3006
3007 self.instruction(I32Const(src_ty.size as i32));
3008 let remaining = self.local_set_new_tmp(ValType::I32);
3009
3010 self.instruction(Loop(BlockType::Empty));
3011
3012 let element_src = Source::Memory(Memory {
3014 opts: src_mem.opts,
3015 offset: 0,
3016 addr: TempLocal::new(cur_src_ptr.idx, cur_src_ptr.ty),
3017 });
3018 let element_dst = Destination::Memory(Memory {
3019 opts: dst_mem.opts,
3020 offset: 0,
3021 addr: TempLocal::new(cur_dst_ptr.idx, cur_dst_ptr.ty),
3022 });
3023 self.translate(&src_ty.element, &element_src, &dst_ty.element, &element_dst);
3024
3025 self.instruction(LocalGet(cur_src_ptr.idx));
3027 self.ptr_uconst(src_mem_opts, src_element_bytes);
3028 self.ptr_add(src_mem_opts);
3029 self.instruction(LocalSet(cur_src_ptr.idx));
3030 self.instruction(LocalGet(cur_dst_ptr.idx));
3031 self.ptr_uconst(dst_mem_opts, dst_element_bytes);
3032 self.ptr_add(dst_mem_opts);
3033 self.instruction(LocalSet(cur_dst_ptr.idx));
3034
3035 self.instruction(LocalGet(remaining.idx));
3038 self.ptr_iconst(src_mem_opts, -1);
3039 self.ptr_add(src_mem_opts);
3040 self.instruction(LocalTee(remaining.idx));
3041 self.ptr_br_if(src_mem_opts, 0);
3042 self.instruction(End); self.free_temp_local(cur_dst_ptr);
3045 self.free_temp_local(cur_src_ptr);
3046 self.free_temp_local(remaining);
3047 return;
3048 }
3049 (_, _) => {
3051 assert!(
3053 src_ty.size as usize <= MAX_FLAT_PARAMS
3054 && dst_ty.size as usize <= MAX_FLAT_PARAMS
3055 );
3056 let srcs =
3057 src.record_field_srcs(self.types, (0..src_ty.size).map(|_| src_ty.element));
3058 let dsts =
3059 dst.record_field_dsts(self.types, (0..dst_ty.size).map(|_| dst_ty.element));
3060 for (src, dst) in srcs.zip(dsts) {
3061 self.translate(&src_ty.element, &src, &dst_ty.element, &dst);
3062 }
3063 }
3064 }
3065 }
3066
3067 fn translate_variant(
3068 &mut self,
3069 src_ty: TypeVariantIndex,
3070 src: &Source<'_>,
3071 dst_ty: &InterfaceType,
3072 dst: &Destination,
3073 ) {
3074 let src_ty = &self.types[src_ty];
3075 let dst_ty = match dst_ty {
3076 InterfaceType::Variant(t) => &self.types[*t],
3077 _ => panic!("expected a variant"),
3078 };
3079
3080 let src_info = variant_info(self.types, src_ty.cases.iter().map(|(_, c)| c.as_ref()));
3081 let dst_info = variant_info(self.types, dst_ty.cases.iter().map(|(_, c)| c.as_ref()));
3082
3083 let iter = src_ty
3084 .cases
3085 .iter()
3086 .enumerate()
3087 .map(|(src_i, (src_case, src_case_ty))| {
3088 let dst_i = dst_ty
3089 .cases
3090 .iter()
3091 .position(|(c, _)| c == src_case)
3092 .unwrap();
3093 let dst_case_ty = &dst_ty.cases[dst_i];
3094 let src_i = u32::try_from(src_i).unwrap();
3095 let dst_i = u32::try_from(dst_i).unwrap();
3096 VariantCase {
3097 src_i,
3098 src_ty: src_case_ty.as_ref(),
3099 dst_i,
3100 dst_ty: dst_case_ty.as_ref(),
3101 }
3102 });
3103 self.convert_variant(src, &src_info, dst, &dst_info, iter);
3104 }
3105
3106 fn translate_enum(
3107 &mut self,
3108 src_ty: TypeEnumIndex,
3109 src: &Source<'_>,
3110 dst_ty: &InterfaceType,
3111 dst: &Destination,
3112 ) {
3113 let src_ty = &self.types[src_ty];
3114 let dst_ty = match dst_ty {
3115 InterfaceType::Enum(t) => &self.types[*t],
3116 _ => panic!("expected an option"),
3117 };
3118
3119 debug_assert_eq!(src_ty.info.size, dst_ty.info.size);
3120 debug_assert_eq!(src_ty.names.len(), dst_ty.names.len());
3121 debug_assert!(
3122 src_ty
3123 .names
3124 .iter()
3125 .zip(dst_ty.names.iter())
3126 .all(|(a, b)| a == b)
3127 );
3128
3129 match src {
3131 Source::Stack(s) => self.stack_get(&s.slice(0..1), ValType::I32),
3132 Source::Memory(mem) => match src_ty.info.size {
3133 DiscriminantSize::Size1 => self.i32_load8u(mem),
3134 DiscriminantSize::Size2 => self.i32_load16u(mem),
3135 DiscriminantSize::Size4 => self.i32_load(mem),
3136 },
3137 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
3138 }
3139 let tmp = self.local_tee_new_tmp(ValType::I32);
3140
3141 self.instruction(I32Const(i32::try_from(src_ty.names.len()).unwrap()));
3143 self.instruction(I32GeU);
3144 self.instruction(If(BlockType::Empty));
3145 self.trap(Trap::InvalidDiscriminant);
3146 self.instruction(End);
3147
3148 match dst {
3150 Destination::Stack(stack, _) => {
3151 self.local_get_tmp(&tmp);
3152 self.stack_set(&stack[..1], ValType::I32)
3153 }
3154 Destination::Memory(mem) => {
3155 self.push_dst_addr(dst);
3156 self.local_get_tmp(&tmp);
3157 match dst_ty.info.size {
3158 DiscriminantSize::Size1 => self.i32_store8(mem),
3159 DiscriminantSize::Size2 => self.i32_store16(mem),
3160 DiscriminantSize::Size4 => self.i32_store(mem),
3161 }
3162 }
3163 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
3164 }
3165 self.free_temp_local(tmp);
3166 }
3167
3168 fn translate_option(
3169 &mut self,
3170 src_ty: TypeOptionIndex,
3171 src: &Source<'_>,
3172 dst_ty: &InterfaceType,
3173 dst: &Destination,
3174 ) {
3175 let src_ty = &self.types[src_ty].ty;
3176 let dst_ty = match dst_ty {
3177 InterfaceType::Option(t) => &self.types[*t].ty,
3178 _ => panic!("expected an option"),
3179 };
3180 let src_ty = Some(src_ty);
3181 let dst_ty = Some(dst_ty);
3182
3183 let src_info = variant_info(self.types, [None, src_ty]);
3184 let dst_info = variant_info(self.types, [None, dst_ty]);
3185
3186 self.convert_variant(
3187 src,
3188 &src_info,
3189 dst,
3190 &dst_info,
3191 [
3192 VariantCase {
3193 src_i: 0,
3194 dst_i: 0,
3195 src_ty: None,
3196 dst_ty: None,
3197 },
3198 VariantCase {
3199 src_i: 1,
3200 dst_i: 1,
3201 src_ty,
3202 dst_ty,
3203 },
3204 ]
3205 .into_iter(),
3206 );
3207 }
3208
3209 fn translate_result(
3210 &mut self,
3211 src_ty: TypeResultIndex,
3212 src: &Source<'_>,
3213 dst_ty: &InterfaceType,
3214 dst: &Destination,
3215 ) {
3216 let src_ty = &self.types[src_ty];
3217 let dst_ty = match dst_ty {
3218 InterfaceType::Result(t) => &self.types[*t],
3219 _ => panic!("expected a result"),
3220 };
3221
3222 let src_info = variant_info(self.types, [src_ty.ok.as_ref(), src_ty.err.as_ref()]);
3223 let dst_info = variant_info(self.types, [dst_ty.ok.as_ref(), dst_ty.err.as_ref()]);
3224
3225 self.convert_variant(
3226 src,
3227 &src_info,
3228 dst,
3229 &dst_info,
3230 [
3231 VariantCase {
3232 src_i: 0,
3233 dst_i: 0,
3234 src_ty: src_ty.ok.as_ref(),
3235 dst_ty: dst_ty.ok.as_ref(),
3236 },
3237 VariantCase {
3238 src_i: 1,
3239 dst_i: 1,
3240 src_ty: src_ty.err.as_ref(),
3241 dst_ty: dst_ty.err.as_ref(),
3242 },
3243 ]
3244 .into_iter(),
3245 );
3246 }
3247
3248 fn convert_variant<'c>(
3249 &mut self,
3250 src: &Source<'_>,
3251 src_info: &VariantInfo,
3252 dst: &Destination,
3253 dst_info: &VariantInfo,
3254 src_cases: impl ExactSizeIterator<Item = VariantCase<'c>>,
3255 ) {
3256 let outer_block_ty = match dst {
3259 Destination::Stack(dst_flat, _) => match dst_flat.len() {
3260 0 => BlockType::Empty,
3261 1 => BlockType::Result(dst_flat[0]),
3262 _ => {
3263 let ty = self.module.core_types.function(&[], &dst_flat);
3264 BlockType::FunctionType(ty)
3265 }
3266 },
3267 Destination::Memory(_) => BlockType::Empty,
3268 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
3269 };
3270 self.instruction(Block(outer_block_ty));
3271
3272 let src_cases_len = src_cases.len();
3275 for _ in 0..src_cases_len - 1 {
3276 self.instruction(Block(BlockType::Empty));
3277 }
3278
3279 self.instruction(Block(BlockType::Empty));
3281
3282 self.instruction(Block(BlockType::Empty));
3285
3286 match src {
3288 Source::Stack(s) => self.stack_get(&s.slice(0..1), ValType::I32),
3289 Source::Memory(mem) => match src_info.size {
3290 DiscriminantSize::Size1 => self.i32_load8u(mem),
3291 DiscriminantSize::Size2 => self.i32_load16u(mem),
3292 DiscriminantSize::Size4 => self.i32_load(mem),
3293 },
3294 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
3295 }
3296
3297 let mut targets = Vec::new();
3300 for i in 0..src_cases_len {
3301 targets.push((i + 1) as u32);
3302 }
3303 self.instruction(BrTable(targets[..].into(), 0));
3304 self.instruction(End); self.trap(Trap::InvalidDiscriminant);
3307 self.instruction(End); let src_cases_len = u32::try_from(src_cases_len).unwrap();
3314 for case in src_cases {
3315 let VariantCase {
3316 src_i,
3317 src_ty,
3318 dst_i,
3319 dst_ty,
3320 } = case;
3321
3322 self.push_dst_addr(dst);
3325 self.instruction(I32Const(dst_i as i32));
3326 match dst {
3327 Destination::Stack(stack, _) => self.stack_set(&stack[..1], ValType::I32),
3328 Destination::Memory(mem) => match dst_info.size {
3329 DiscriminantSize::Size1 => self.i32_store8(mem),
3330 DiscriminantSize::Size2 => self.i32_store16(mem),
3331 DiscriminantSize::Size4 => self.i32_store(mem),
3332 },
3333 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
3334 }
3335
3336 let src_payload = src.payload_src(self.types, src_info, src_ty);
3337 let dst_payload = dst.payload_dst(self.types, dst_info, dst_ty);
3338
3339 match (src_ty, dst_ty) {
3342 (Some(src_ty), Some(dst_ty)) => {
3343 self.translate(src_ty, &src_payload, dst_ty, &dst_payload);
3344 }
3345 (None, None) => {}
3346 _ => unimplemented!(),
3347 }
3348
3349 if let Destination::Stack(payload_results, _) = dst_payload {
3356 if let Destination::Stack(dst_results, _) = dst {
3357 let remaining = &dst_results[1..][payload_results.len()..];
3358 for ty in remaining {
3359 match ty {
3360 ValType::I32 => self.instruction(I32Const(0)),
3361 ValType::I64 => self.instruction(I64Const(0)),
3362 ValType::F32 => self.instruction(F32Const(0.0.into())),
3363 ValType::F64 => self.instruction(F64Const(0.0.into())),
3364 _ => unreachable!(),
3365 }
3366 }
3367 }
3368 }
3369
3370 if src_i != src_cases_len - 1 {
3373 self.instruction(Br(src_cases_len - src_i - 1));
3374 }
3375 self.instruction(End); }
3377 }
3378
3379 fn translate_future(
3380 &mut self,
3381 src_ty: TypeFutureTableIndex,
3382 src: &Source<'_>,
3383 dst_ty: &InterfaceType,
3384 dst: &Destination,
3385 ) {
3386 let dst_ty = match dst_ty {
3387 InterfaceType::Future(t) => *t,
3388 _ => panic!("expected a `Future`"),
3389 };
3390 let transfer = self.module.import_future_transfer();
3391 self.translate_handle(src_ty.as_u32(), src, dst_ty.as_u32(), dst, transfer);
3392 }
3393
3394 fn translate_stream(
3395 &mut self,
3396 src_ty: TypeStreamTableIndex,
3397 src: &Source<'_>,
3398 dst_ty: &InterfaceType,
3399 dst: &Destination,
3400 ) {
3401 let dst_ty = match dst_ty {
3402 InterfaceType::Stream(t) => *t,
3403 _ => panic!("expected a `Stream`"),
3404 };
3405 let transfer = self.module.import_stream_transfer();
3406 self.translate_handle(src_ty.as_u32(), src, dst_ty.as_u32(), dst, transfer);
3407 }
3408
3409 fn translate_error_context(
3410 &mut self,
3411 src_ty: TypeComponentLocalErrorContextTableIndex,
3412 src: &Source<'_>,
3413 dst_ty: &InterfaceType,
3414 dst: &Destination,
3415 ) {
3416 let dst_ty = match dst_ty {
3417 InterfaceType::ErrorContext(t) => *t,
3418 _ => panic!("expected an `ErrorContext`"),
3419 };
3420 let transfer = self.module.import_error_context_transfer();
3421 self.translate_handle(src_ty.as_u32(), src, dst_ty.as_u32(), dst, transfer);
3422 }
3423
3424 fn translate_own(
3425 &mut self,
3426 src_ty: TypeResourceTableIndex,
3427 src: &Source<'_>,
3428 dst_ty: &InterfaceType,
3429 dst: &Destination,
3430 ) {
3431 let dst_ty = match dst_ty {
3432 InterfaceType::Own(t) => *t,
3433 _ => panic!("expected an `Own`"),
3434 };
3435 let transfer = self.module.import_resource_transfer_own();
3436 self.translate_handle(src_ty.as_u32(), src, dst_ty.as_u32(), dst, transfer);
3437 }
3438
3439 fn translate_borrow(
3440 &mut self,
3441 src_ty: TypeResourceTableIndex,
3442 src: &Source<'_>,
3443 dst_ty: &InterfaceType,
3444 dst: &Destination,
3445 ) {
3446 let dst_ty = match dst_ty {
3447 InterfaceType::Borrow(t) => *t,
3448 _ => panic!("expected an `Borrow`"),
3449 };
3450
3451 let transfer = self.module.import_resource_transfer_borrow();
3452 self.translate_handle(src_ty.as_u32(), src, dst_ty.as_u32(), dst, transfer);
3453 }
3454
3455 fn translate_handle(
3463 &mut self,
3464 src_ty: u32,
3465 src: &Source<'_>,
3466 dst_ty: u32,
3467 dst: &Destination,
3468 transfer: FuncIndex,
3469 ) {
3470 self.push_dst_addr(dst);
3471 match src {
3472 Source::Memory(mem) => self.i32_load(mem),
3473 Source::Stack(stack) => self.stack_get(stack, ValType::I32),
3474 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
3475 }
3476 self.instruction(I32Const(src_ty as i32));
3477 self.instruction(I32Const(dst_ty as i32));
3478 self.instruction(Call(transfer.as_u32()));
3479 match dst {
3480 Destination::Memory(mem) => self.i32_store(mem),
3481 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
3482 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
3483 }
3484 }
3485
3486 fn trap_if_not_may_leave(&mut self, flags_global: GlobalIndex, trap: Trap) -> TempLocal {
3493 self.instruction(Block(BlockType::Empty));
3494 self.instruction(GlobalGet(flags_global.as_u32()));
3495 let saved = self.local_tee_new_tmp(ValType::I32);
3498 self.instruction(BrIf(0));
3499 self.trap(trap);
3500 self.instruction(End);
3501 saved
3502 }
3503
3504 fn clear_may_leave(&mut self, flags_global: GlobalIndex) -> TempLocal {
3507 self.instruction(GlobalGet(flags_global.as_u32()));
3508 let saved = self.local_set_new_tmp(ValType::I32);
3509 self.set_may_leave_false(flags_global);
3510 saved
3511 }
3512
3513 fn set_may_leave_false(&mut self, flags_global: GlobalIndex) {
3518 self.instruction(I32Const(0));
3519 self.instruction(GlobalSet(flags_global.as_u32()));
3520 }
3521
3522 fn restore_may_leave(&mut self, flags_global: GlobalIndex, saved: TempLocal) {
3535 self.instruction(LocalGet(saved.idx));
3536 self.instruction(GlobalSet(flags_global.as_u32()));
3537 self.free_temp_local(saved);
3538 }
3539
3540 fn assert_aligned(&mut self, ty: &InterfaceType, mem: &Memory) {
3541 let mem_opts = mem.mem_opts();
3542 if !self.module.tunables.debug_adapter_modules {
3543 return;
3544 }
3545 let align = self.types.align(mem_opts, ty);
3546 if align == 1 {
3547 return;
3548 }
3549 assert!(align.is_power_of_two());
3550 self.instruction(LocalGet(mem.addr.idx));
3551 self.ptr_uconst(mem_opts, mem.offset);
3552 self.ptr_add(mem_opts);
3553 self.ptr_uconst(mem_opts, align - 1);
3554 self.ptr_and(mem_opts);
3555 self.ptr_if(mem_opts, BlockType::Empty);
3556 self.trap(Trap::DebugAssertPointerAligned);
3557 self.instruction(End);
3558 }
3559
3560 fn malloc_abi<'c>(
3566 &mut self,
3567 opts: &'c Options,
3568 abi: &CanonicalAbiInfo,
3569 oob_trap: Trap,
3570 ) -> Memory<'c> {
3571 match &opts.data_model {
3572 DataModel::Gc {} => todo!("CM+GC"),
3573 DataModel::LinearMemory(mem_opts) => {
3574 let (size, align) = mem_opts.sizealign(abi);
3575 let size = AllocSize::Const(size);
3576 self.malloc(opts, size, align, oob_trap)
3577 }
3578 }
3579 }
3580
3581 fn malloc<'c>(
3587 &mut self,
3588 opts: &'c Options,
3589 size: AllocSize,
3590 align: u32,
3591 oob_trap: Trap,
3592 ) -> Memory<'c> {
3593 match &opts.data_model {
3594 DataModel::Gc {} => todo!("CM+GC"),
3595 DataModel::LinearMemory(mem_opts) => {
3596 let realloc = mem_opts.realloc.unwrap();
3597 self.ptr_uconst(mem_opts, 0);
3598 self.ptr_uconst(mem_opts, 0);
3599 self.ptr_uconst(mem_opts, align);
3600 self.alloc_size(mem_opts, &size);
3601 self.call_realloc(realloc);
3602 let addr = self.local_set_new_tmp(mem_opts.ptr());
3603 self.memory_operand(opts, addr, size, align, oob_trap)
3604 }
3605 }
3606 }
3607
3608 fn realloc(
3614 &mut self,
3615 opts: &Options,
3616 ptr: &TempLocal,
3617 prev_size: AllocSize,
3618 size: AllocSize,
3619 align: u32,
3620 oob_trap: Trap,
3621 ) {
3622 match &opts.data_model {
3623 DataModel::Gc {} => todo!("CM+GC"),
3624 DataModel::LinearMemory(mem_opts) => {
3625 let realloc = mem_opts.realloc.unwrap();
3626 self.instruction(LocalGet(ptr.idx));
3627 self.alloc_size(mem_opts, &prev_size);
3628 self.ptr_uconst(mem_opts, align);
3629 self.alloc_size(mem_opts, &size);
3630 self.call_realloc(realloc);
3631 self.instruction(LocalSet(ptr.idx));
3632 self.validate_guest_pointer(opts, &ptr, &size, align, oob_trap)
3633 }
3634 }
3635 }
3636
3637 fn memory_operand_abi<'c>(
3640 &mut self,
3641 opts: &'c Options,
3642 addr: TempLocal,
3643 abi: &CanonicalAbiInfo,
3644 oob_trap: Trap,
3645 ) -> Memory<'c> {
3646 match &opts.data_model {
3647 DataModel::Gc {} => todo!("CM+GC"),
3648 DataModel::LinearMemory(mem_opts) => {
3649 let (size, align) = mem_opts.sizealign(abi);
3650 self.memory_operand(opts, addr, AllocSize::Const(size), align, oob_trap)
3651 }
3652 }
3653 }
3654
3655 fn memory_operand<'c>(
3658 &mut self,
3659 opts: &'c Options,
3660 addr: TempLocal,
3661 size: AllocSize,
3662 align: u32,
3663 oob_trap: Trap,
3664 ) -> Memory<'c> {
3665 self.validate_guest_pointer(opts, &addr, &size, align, oob_trap);
3666 Memory {
3667 addr,
3668 opts,
3669 offset: 0,
3670 }
3671 }
3672
3673 fn validate_guest_pointer(
3681 &mut self,
3682 opts: &Options,
3683 addr: &TempLocal,
3684 size: &AllocSize,
3685 align: u32,
3686 oob_trap: Trap,
3687 ) {
3688 let mem_opts = match &opts.data_model {
3689 DataModel::Gc {} => todo!("CM+GC"),
3690 DataModel::LinearMemory(mem_opts) => mem_opts,
3691 };
3692
3693 if align != 1 {
3696 self.instruction(LocalGet(addr.idx));
3697 assert!(align.is_power_of_two());
3698 self.ptr_uconst(mem_opts, align - 1);
3699 self.ptr_and(mem_opts);
3700 self.ptr_if(mem_opts, BlockType::Empty);
3701 self.trap(Trap::UnalignedPointer);
3702 self.instruction(End);
3703 }
3704
3705 let extend_to_64 = |me: &mut Self| {
3706 if !mem_opts.memory64() {
3707 me.instruction(I64ExtendI32U);
3708 }
3709 };
3710
3711 self.instruction(Block(BlockType::Empty));
3712 self.instruction(Block(BlockType::Empty));
3713 let (memory, ty) = mem_opts.memory.unwrap();
3714
3715 self.instruction(MemorySize(memory.as_u32()));
3720 extend_to_64(self);
3721 self.instruction(I64Const(ty.page_size_log2.into()));
3722 self.instruction(I64Shl);
3723
3724 self.instruction(LocalGet(addr.idx));
3729 extend_to_64(self);
3730 self.alloc_size(mem_opts, size);
3731 extend_to_64(self);
3732 self.instruction(I64Add);
3733 if mem_opts.memory64() {
3734 let tmp = self.local_tee_new_tmp(ValType::I64);
3735 self.instruction(LocalGet(addr.idx));
3736 self.ptr_lt_u(mem_opts);
3737 self.instruction(BrIf(0));
3738 self.instruction(LocalGet(tmp.idx));
3739 self.free_temp_local(tmp);
3740 }
3741
3742 self.instruction(I64GeU);
3746 self.instruction(BrIf(1));
3747
3748 self.instruction(End);
3749 self.trap(oob_trap);
3750 self.instruction(End);
3751 }
3752
3753 fn local_tee_new_tmp(&mut self, ty: ValType) -> TempLocal {
3759 self.gen_temp_local(ty, LocalTee)
3760 }
3761
3762 fn local_set_new_tmp(&mut self, ty: ValType) -> TempLocal {
3765 self.gen_temp_local(ty, LocalSet)
3766 }
3767
3768 fn local_get_tmp(&mut self, local: &TempLocal) {
3769 self.instruction(LocalGet(local.idx));
3770 }
3771
3772 fn gen_temp_local(&mut self, ty: ValType, insn: fn(u32) -> Instruction<'static>) -> TempLocal {
3773 if let Some(idx) = self.free_locals.get_mut(&ty).and_then(|v| v.pop()) {
3776 self.instruction(insn(idx));
3777 return TempLocal {
3778 ty,
3779 idx,
3780 needs_free: true,
3781 };
3782 }
3783
3784 let locals = &mut self.module.funcs[self.result].locals;
3786 match locals.last_mut() {
3787 Some((cnt, prev_ty)) if ty == *prev_ty => *cnt += 1,
3788 _ => locals.push((1, ty)),
3789 }
3790 self.nlocals += 1;
3791 let idx = self.nlocals - 1;
3792 self.instruction(insn(idx));
3793 TempLocal {
3794 ty,
3795 idx,
3796 needs_free: true,
3797 }
3798 }
3799
3800 fn free_temp_local(&mut self, mut local: TempLocal) {
3803 assert!(local.needs_free);
3804 self.free_locals
3805 .entry(local.ty)
3806 .or_insert(Vec::new())
3807 .push(local.idx);
3808 local.needs_free = false;
3809 }
3810
3811 fn save_context(&mut self) -> Vec<TempLocal> {
3814 if !self.module.tunables.concurrency_support {
3815 return Vec::new();
3816 }
3817 let mut saved = Vec::new();
3818 for slot in 0..NUM_COMPONENT_CONTEXT_SLOTS {
3819 let get = self.module.import_context_get(slot);
3820 self.instruction(Call(get.as_u32()));
3821 saved.push(self.local_set_new_tmp(ValType::I32));
3822 }
3823 saved
3824 }
3825
3826 fn clear_context(&mut self) {
3828 if !self.module.tunables.concurrency_support {
3829 return;
3830 }
3831 for slot in 0..NUM_COMPONENT_CONTEXT_SLOTS {
3832 let set = self.module.import_context_set(slot);
3833 self.instruction(I32Const(0));
3834 self.instruction(Call(set.as_u32()));
3835 }
3836 }
3837
3838 fn restore_context(&mut self, saved: Vec<TempLocal>) {
3841 for (slot, local) in saved.into_iter().enumerate() {
3842 let set = self.module.import_context_set(slot);
3843 self.instruction(LocalGet(local.idx));
3844 self.instruction(Call(set.as_u32()));
3845 self.free_temp_local(local);
3846 }
3847 }
3848
3849 fn call_realloc(&mut self, realloc: FuncIndex) {
3855 let saved = self.save_context();
3856 self.clear_context();
3857 self.instruction(Call(realloc.as_u32()));
3858 self.restore_context(saved);
3859 }
3860
3861 fn instruction(&mut self, instr: Instruction) {
3862 instr.encode(&mut self.code);
3863 }
3864
3865 fn trap(&mut self, trap: Trap) {
3866 let trap_func = self.module.import_trap(trap);
3867 self.instruction(Call(trap_func.as_u32()));
3868 self.instruction(Unreachable);
3869 }
3870
3871 fn enter_exception_barrier(&mut self, results: &[ValType]) {
3902 if !self.module.features.exceptions() {
3903 return;
3904 }
3905 let block_ty = match results.len() {
3906 0 => BlockType::Empty,
3907 1 => BlockType::Result(results[0]),
3908 _ => BlockType::FunctionType(self.module.core_types.function(&[], results)),
3909 };
3910 self.instruction(Block(block_ty));
3912 self.instruction(Block(BlockType::Empty));
3914 self.instruction(TryTable(block_ty, vec![Catch::All { label: 0 }].into()));
3915 }
3916
3917 fn exit_exception_barrier(&mut self) {
3922 if !self.module.features.exceptions() {
3923 return;
3924 }
3925 self.instruction(End);
3927 self.instruction(Br(1));
3929 self.instruction(End);
3931 self.trap(Trap::UncaughtException);
3932 self.instruction(End);
3934 }
3935
3936 fn flush_code(&mut self) {
3941 if self.code.is_empty() {
3942 return;
3943 }
3944 self.module.funcs[self.result]
3945 .body
3946 .push(Body::Raw(mem::take(&mut self.code)));
3947 }
3948
3949 fn finish(mut self) {
3950 self.instruction(End);
3953 self.flush_code();
3954
3955 self.module.funcs[self.result].filled_in = true;
3958 }
3959
3960 fn stack_get(&mut self, stack: &Stack<'_>, dst_ty: ValType) {
3968 assert_eq!(stack.locals.len(), 1);
3969 let (idx, src_ty) = stack.locals[0];
3970 self.instruction(LocalGet(idx));
3971 match (src_ty, dst_ty) {
3972 (ValType::I32, ValType::I32)
3973 | (ValType::I64, ValType::I64)
3974 | (ValType::F32, ValType::F32)
3975 | (ValType::F64, ValType::F64) => {}
3976
3977 (ValType::I32, ValType::F32) => self.instruction(F32ReinterpretI32),
3978 (ValType::I64, ValType::I32) => {
3979 self.assert_i64_upper_bits_not_set(idx);
3980 self.instruction(I32WrapI64);
3981 }
3982 (ValType::I64, ValType::F64) => self.instruction(F64ReinterpretI64),
3983 (ValType::I64, ValType::F32) => {
3984 self.assert_i64_upper_bits_not_set(idx);
3985 self.instruction(I32WrapI64);
3986 self.instruction(F32ReinterpretI32);
3987 }
3988
3989 (ValType::I32, ValType::I64)
3991 | (ValType::I32, ValType::F64)
3992 | (ValType::F32, ValType::I32)
3993 | (ValType::F32, ValType::I64)
3994 | (ValType::F32, ValType::F64)
3995 | (ValType::F64, ValType::I32)
3996 | (ValType::F64, ValType::I64)
3997 | (ValType::F64, ValType::F32)
3998
3999 | (ValType::Ref(_), _)
4001 | (_, ValType::Ref(_))
4002 | (ValType::V128, _)
4003 | (_, ValType::V128) => {
4004 panic!("cannot get {dst_ty:?} from {src_ty:?} local");
4005 }
4006 }
4007 }
4008
4009 fn assert_i64_upper_bits_not_set(&mut self, local: u32) {
4010 if !self.module.tunables.debug_adapter_modules {
4011 return;
4012 }
4013 self.instruction(LocalGet(local));
4014 self.instruction(I64Const(32));
4015 self.instruction(I64ShrU);
4016 self.instruction(I32WrapI64);
4017 self.instruction(If(BlockType::Empty));
4018 self.trap(Trap::DebugAssertUpperBitsUnset);
4019 self.instruction(End);
4020 }
4021
4022 fn stack_set(&mut self, dst_tys: &[ValType], src_ty: ValType) {
4028 assert_eq!(dst_tys.len(), 1);
4029 let dst_ty = dst_tys[0];
4030 match (src_ty, dst_ty) {
4031 (ValType::I32, ValType::I32)
4032 | (ValType::I64, ValType::I64)
4033 | (ValType::F32, ValType::F32)
4034 | (ValType::F64, ValType::F64) => {}
4035
4036 (ValType::F32, ValType::I32) => self.instruction(I32ReinterpretF32),
4037 (ValType::I32, ValType::I64) => self.instruction(I64ExtendI32U),
4038 (ValType::F64, ValType::I64) => self.instruction(I64ReinterpretF64),
4039 (ValType::F32, ValType::I64) => {
4040 self.instruction(I32ReinterpretF32);
4041 self.instruction(I64ExtendI32U);
4042 }
4043
4044 (ValType::I64, ValType::I32)
4046 | (ValType::F64, ValType::I32)
4047 | (ValType::I32, ValType::F32)
4048 | (ValType::I64, ValType::F32)
4049 | (ValType::F64, ValType::F32)
4050 | (ValType::I32, ValType::F64)
4051 | (ValType::I64, ValType::F64)
4052 | (ValType::F32, ValType::F64)
4053
4054 | (ValType::Ref(_), _)
4056 | (_, ValType::Ref(_))
4057 | (ValType::V128, _)
4058 | (_, ValType::V128) => {
4059 panic!("cannot get {dst_ty:?} from {src_ty:?} local");
4060 }
4061 }
4062 }
4063
4064 fn i32_load8u(&mut self, mem: &Memory) {
4065 self.instruction(LocalGet(mem.addr.idx));
4066 self.instruction(I32Load8U(mem.memarg(0)));
4067 }
4068
4069 fn i32_load8s(&mut self, mem: &Memory) {
4070 self.instruction(LocalGet(mem.addr.idx));
4071 self.instruction(I32Load8S(mem.memarg(0)));
4072 }
4073
4074 fn i32_load16u(&mut self, mem: &Memory) {
4075 self.instruction(LocalGet(mem.addr.idx));
4076 self.instruction(I32Load16U(mem.memarg(1)));
4077 }
4078
4079 fn i32_load16s(&mut self, mem: &Memory) {
4080 self.instruction(LocalGet(mem.addr.idx));
4081 self.instruction(I32Load16S(mem.memarg(1)));
4082 }
4083
4084 fn i32_load(&mut self, mem: &Memory) {
4085 self.instruction(LocalGet(mem.addr.idx));
4086 self.instruction(I32Load(mem.memarg(2)));
4087 }
4088
4089 fn i64_load(&mut self, mem: &Memory) {
4090 self.instruction(LocalGet(mem.addr.idx));
4091 self.instruction(I64Load(mem.memarg(3)));
4092 }
4093
4094 fn ptr_load(&mut self, mem: &Memory) {
4095 if mem.mem_opts().memory64() {
4096 self.i64_load(mem);
4097 } else {
4098 self.i32_load(mem);
4099 }
4100 }
4101
4102 fn ptr_add(&mut self, opts: &LinearMemoryOptions) {
4103 if opts.memory64() {
4104 self.instruction(I64Add);
4105 } else {
4106 self.instruction(I32Add);
4107 }
4108 }
4109
4110 fn ptr_sub(&mut self, opts: &LinearMemoryOptions) {
4111 if opts.memory64() {
4112 self.instruction(I64Sub);
4113 } else {
4114 self.instruction(I32Sub);
4115 }
4116 }
4117
4118 fn ptr_mul(&mut self, opts: &LinearMemoryOptions) {
4119 if opts.memory64() {
4120 self.instruction(I64Mul);
4121 } else {
4122 self.instruction(I32Mul);
4123 }
4124 }
4125
4126 fn ptr_gt_u(&mut self, opts: &LinearMemoryOptions) {
4127 if opts.memory64() {
4128 self.instruction(I64GtU);
4129 } else {
4130 self.instruction(I32GtU);
4131 }
4132 }
4133
4134 fn ptr_lt_u(&mut self, opts: &LinearMemoryOptions) {
4135 if opts.memory64() {
4136 self.instruction(I64LtU);
4137 } else {
4138 self.instruction(I32LtU);
4139 }
4140 }
4141
4142 fn ptr_shl(&mut self, opts: &LinearMemoryOptions) {
4143 if opts.memory64() {
4144 self.instruction(I64Shl);
4145 } else {
4146 self.instruction(I32Shl);
4147 }
4148 }
4149
4150 fn ptr_eqz(&mut self, opts: &LinearMemoryOptions) {
4151 if opts.memory64() {
4152 self.instruction(I64Eqz);
4153 } else {
4154 self.instruction(I32Eqz);
4155 }
4156 }
4157
4158 fn ptr_uconst(&mut self, opts: &LinearMemoryOptions, val: u32) {
4159 if opts.memory64() {
4160 self.instruction(I64Const(val.into()));
4161 } else {
4162 self.instruction(I32Const(val.cast_signed()));
4163 }
4164 }
4165
4166 fn ptr_iconst(&mut self, opts: &LinearMemoryOptions, val: i32) {
4167 if opts.memory64() {
4168 self.instruction(I64Const(val.into()));
4169 } else {
4170 self.instruction(I32Const(val));
4171 }
4172 }
4173
4174 fn ptr_eq(&mut self, opts: &LinearMemoryOptions) {
4175 if opts.memory64() {
4176 self.instruction(I64Eq);
4177 } else {
4178 self.instruction(I32Eq);
4179 }
4180 }
4181
4182 fn ptr_ne(&mut self, opts: &LinearMemoryOptions) {
4183 if opts.memory64() {
4184 self.instruction(I64Ne);
4185 } else {
4186 self.instruction(I32Ne);
4187 }
4188 }
4189
4190 fn ptr_and(&mut self, opts: &LinearMemoryOptions) {
4191 if opts.memory64() {
4192 self.instruction(I64And);
4193 } else {
4194 self.instruction(I32And);
4195 }
4196 }
4197
4198 fn ptr_or(&mut self, opts: &LinearMemoryOptions) {
4199 if opts.memory64() {
4200 self.instruction(I64Or);
4201 } else {
4202 self.instruction(I32Or);
4203 }
4204 }
4205
4206 fn ptr_xor(&mut self, opts: &LinearMemoryOptions) {
4207 if opts.memory64() {
4208 self.instruction(I64Xor);
4209 } else {
4210 self.instruction(I32Xor);
4211 }
4212 }
4213
4214 fn ptr_if(&mut self, opts: &LinearMemoryOptions, ty: BlockType) {
4215 if opts.memory64() {
4216 self.instruction(I64Const(0));
4217 self.instruction(I64Ne);
4218 }
4219 self.instruction(If(ty));
4220 }
4221
4222 fn ptr_br_if(&mut self, opts: &LinearMemoryOptions, depth: u32) {
4223 if opts.memory64() {
4224 self.instruction(I64Const(0));
4225 self.instruction(I64Ne);
4226 }
4227 self.instruction(BrIf(depth));
4228 }
4229
4230 fn f32_load(&mut self, mem: &Memory) {
4231 self.instruction(LocalGet(mem.addr.idx));
4232 self.instruction(F32Load(mem.memarg(2)));
4233 }
4234
4235 fn f64_load(&mut self, mem: &Memory) {
4236 self.instruction(LocalGet(mem.addr.idx));
4237 self.instruction(F64Load(mem.memarg(3)));
4238 }
4239
4240 fn push_dst_addr(&mut self, dst: &Destination) {
4241 if let Destination::Memory(mem) = dst {
4242 self.instruction(LocalGet(mem.addr.idx));
4243 }
4244 }
4245
4246 fn i32_store8(&mut self, mem: &Memory) {
4247 self.instruction(I32Store8(mem.memarg(0)));
4248 }
4249
4250 fn i32_store16(&mut self, mem: &Memory) {
4251 self.instruction(I32Store16(mem.memarg(1)));
4252 }
4253
4254 fn i32_store(&mut self, mem: &Memory) {
4255 self.instruction(I32Store(mem.memarg(2)));
4256 }
4257
4258 fn i64_store(&mut self, mem: &Memory) {
4259 self.instruction(I64Store(mem.memarg(3)));
4260 }
4261
4262 fn ptr_store(&mut self, mem: &Memory) {
4263 if mem.mem_opts().memory64() {
4264 self.i64_store(mem);
4265 } else {
4266 self.i32_store(mem);
4267 }
4268 }
4269
4270 fn f32_store(&mut self, mem: &Memory) {
4271 self.instruction(F32Store(mem.memarg(2)));
4272 }
4273
4274 fn f64_store(&mut self, mem: &Memory) {
4275 self.instruction(F64Store(mem.memarg(3)));
4276 }
4277
4278 fn alloc_size(&mut self, opts: &LinearMemoryOptions, size: &AllocSize) {
4281 match size {
4282 AllocSize::Const(size) => self.ptr_uconst(opts, *size),
4283 AllocSize::Local(idx) => self.instruction(LocalGet(*idx)),
4284 AllocSize::DoubleLocal(idx) => {
4285 self.instruction(LocalGet(*idx));
4286 self.ptr_uconst(opts, 1);
4287 self.ptr_shl(opts);
4288 }
4289 }
4290 }
4291}
4292
4293impl<'a> Source<'a> {
4294 fn record_field_srcs<'b>(
4301 &'b self,
4302 types: &'b ComponentTypesBuilder,
4303 fields: impl IntoIterator<Item = InterfaceType> + 'b,
4304 ) -> impl Iterator<Item = Source<'a>> + 'b
4305 where
4306 'a: 'b,
4307 {
4308 let mut offset = 0;
4309 fields.into_iter().map(move |ty| match self {
4310 Source::Memory(mem) => {
4311 let mem = next_field_offset(&mut offset, types, &ty, mem);
4312 Source::Memory(mem)
4313 }
4314 Source::Stack(stack) => {
4315 let cnt = types.flat_types(&ty).unwrap().len() as u32;
4316 offset += cnt;
4317 Source::Stack(stack.slice((offset - cnt) as usize..offset as usize))
4318 }
4319 Source::Struct(_) => todo!(),
4320 Source::Array(_) => todo!(),
4321 })
4322 }
4323
4324 fn payload_src(
4326 &self,
4327 types: &ComponentTypesBuilder,
4328 info: &VariantInfo,
4329 case: Option<&InterfaceType>,
4330 ) -> Source<'a> {
4331 match self {
4332 Source::Stack(s) => {
4333 let flat_len = match case {
4334 Some(case) => types.flat_types(case).unwrap().len(),
4335 None => 0,
4336 };
4337 Source::Stack(s.slice(1..s.locals.len()).slice(0..flat_len))
4338 }
4339 Source::Memory(mem) => {
4340 let mem = if mem.mem_opts().memory64() {
4341 mem.bump(info.payload_offset64)
4342 } else {
4343 mem.bump(info.payload_offset32)
4344 };
4345 Source::Memory(mem)
4346 }
4347 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
4348 }
4349 }
4350
4351 fn opts(&self) -> &'a Options {
4352 match self {
4353 Source::Stack(s) => s.opts,
4354 Source::Memory(mem) => mem.opts,
4355 Source::Struct(s) => s.opts,
4356 Source::Array(a) => a.opts,
4357 }
4358 }
4359}
4360
4361impl<'a> Destination<'a> {
4362 fn record_field_dsts<'b, I>(
4364 &'b self,
4365 types: &'b ComponentTypesBuilder,
4366 fields: I,
4367 ) -> impl Iterator<Item = Destination<'b>> + use<'b, I>
4368 where
4369 'a: 'b,
4370 I: IntoIterator<Item = InterfaceType> + 'b,
4371 {
4372 let mut offset = 0;
4373 fields.into_iter().map(move |ty| match self {
4374 Destination::Memory(mem) => {
4375 let mem = next_field_offset(&mut offset, types, &ty, mem);
4376 Destination::Memory(mem)
4377 }
4378 Destination::Stack(s, opts) => {
4379 let cnt = types.flat_types(&ty).unwrap().len() as u32;
4380 offset += cnt;
4381 Destination::Stack(&s[(offset - cnt) as usize..offset as usize], opts)
4382 }
4383 Destination::Struct(_) => todo!(),
4384 Destination::Array(_) => todo!(),
4385 })
4386 }
4387
4388 fn payload_dst(
4390 &self,
4391 types: &ComponentTypesBuilder,
4392 info: &VariantInfo,
4393 case: Option<&InterfaceType>,
4394 ) -> Destination<'_> {
4395 match self {
4396 Destination::Stack(s, opts) => {
4397 let flat_len = match case {
4398 Some(case) => types.flat_types(case).unwrap().len(),
4399 None => 0,
4400 };
4401 Destination::Stack(&s[1..][..flat_len], opts)
4402 }
4403 Destination::Memory(mem) => {
4404 let mem = if mem.mem_opts().memory64() {
4405 mem.bump(info.payload_offset64)
4406 } else {
4407 mem.bump(info.payload_offset32)
4408 };
4409 Destination::Memory(mem)
4410 }
4411 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
4412 }
4413 }
4414
4415 fn opts(&self) -> &'a Options {
4416 match self {
4417 Destination::Stack(_, opts) => opts,
4418 Destination::Memory(mem) => mem.opts,
4419 Destination::Struct(s) => s.opts,
4420 Destination::Array(a) => a.opts,
4421 }
4422 }
4423}
4424
4425fn next_field_offset<'a>(
4426 offset: &mut u32,
4427 types: &ComponentTypesBuilder,
4428 field: &InterfaceType,
4429 mem: &Memory<'a>,
4430) -> Memory<'a> {
4431 let abi = types.canonical_abi(field);
4432 let offset = if mem.mem_opts().memory64() {
4433 abi.next_field64(offset)
4434 } else {
4435 abi.next_field32(offset)
4436 };
4437 mem.bump(offset)
4438}
4439
4440impl<'a> Memory<'a> {
4441 fn memarg(&self, align: u32) -> MemArg {
4442 MemArg {
4443 offset: u64::from(self.offset),
4444 align,
4445 memory_index: self.mem_opts().memory.unwrap().0.as_u32(),
4446 }
4447 }
4448
4449 fn bump(&self, offset: u32) -> Memory<'a> {
4450 Memory {
4451 opts: self.opts,
4452 addr: TempLocal::new(self.addr.idx, self.addr.ty),
4453 offset: self.offset + offset,
4454 }
4455 }
4456}
4457
4458impl<'a> Stack<'a> {
4459 fn slice(&self, range: Range<usize>) -> Stack<'a> {
4460 Stack {
4461 locals: &self.locals[range],
4462 opts: self.opts,
4463 }
4464 }
4465}
4466
4467struct VariantCase<'a> {
4468 src_i: u32,
4469 src_ty: Option<&'a InterfaceType>,
4470 dst_i: u32,
4471 dst_ty: Option<&'a InterfaceType>,
4472}
4473
4474fn variant_info<'a, I>(types: &ComponentTypesBuilder, cases: I) -> VariantInfo
4475where
4476 I: IntoIterator<Item = Option<&'a InterfaceType>>,
4477 I::IntoIter: ExactSizeIterator,
4478{
4479 VariantInfo::new(
4480 cases
4481 .into_iter()
4482 .map(|ty| ty.map(|ty| types.canonical_abi(ty))),
4483 )
4484 .0
4485}
4486
4487struct SequenceLoopState {
4489 remaining: TempLocal,
4490 cur_src_ptr: TempLocal,
4491 cur_dst_ptr: TempLocal,
4492}
4493
4494struct SequenceTranslation<'a> {
4498 src_len: TempLocal,
4499 src_mem: Memory<'a>,
4500 dst_mem: Memory<'a>,
4501 src_opts: &'a Options,
4502 dst_opts: &'a Options,
4503 src_mem_opts: &'a LinearMemoryOptions,
4504 dst_mem_opts: &'a LinearMemoryOptions,
4505 loop_state: Option<SequenceLoopState>,
4506}
4507
4508enum AllocSize {
4509 Const(u32),
4510 Local(u32),
4511 DoubleLocal(u32),
4512}
4513
4514struct WasmString<'a> {
4515 ptr: TempLocal,
4516 len: TempLocal,
4517 opts: &'a Options,
4518}
4519
4520struct TempLocal {
4521 idx: u32,
4522 ty: ValType,
4523 needs_free: bool,
4524}
4525
4526impl TempLocal {
4527 fn new(idx: u32, ty: ValType) -> TempLocal {
4528 TempLocal {
4529 idx,
4530 ty,
4531 needs_free: false,
4532 }
4533 }
4534}
4535
4536impl std::ops::Drop for TempLocal {
4537 fn drop(&mut self) {
4538 if self.needs_free {
4539 panic!("temporary local not free'd");
4540 }
4541 }
4542}
4543
4544impl From<FlatType> for ValType {
4545 fn from(ty: FlatType) -> ValType {
4546 match ty {
4547 FlatType::I32 => ValType::I32,
4548 FlatType::I64 => ValType::I64,
4549 FlatType::F32 => ValType::F32,
4550 FlatType::F64 => ValType::F64,
4551 }
4552 }
4553}