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, StringEncoding, Transcode, TypeComponentLocalErrorContextTableIndex,
22 TypeEnumIndex, TypeFixedLengthListIndex, TypeFlagsIndex, TypeFutureTableIndex, TypeListIndex,
23 TypeMapIndex, TypeOptionIndex, TypeRecordIndex, TypeResourceTableIndex, TypeResultIndex,
24 TypeStreamTableIndex, TypeTupleIndex, TypeVariantIndex, VariantInfo,
25};
26use crate::fact::signature::Signature;
27use crate::fact::transcode::Transcoder;
28use crate::fact::{
29 AdapterData, Body, Function, FunctionId, Helper, HelperLocation, HelperType,
30 LinearMemoryOptions, Module, Options,
31};
32use crate::prelude::*;
33use crate::{FuncIndex, GlobalIndex, IndexType, NUM_COMPONENT_CONTEXT_SLOTS, Trap};
34use std::collections::HashMap;
35use std::mem;
36use std::ops::Range;
37use wasm_encoder::{BlockType, Catch, Encode, Instruction, Instruction::*, MemArg, ValType};
38use wasmtime_component_util::{DiscriminantSize, FlagsSize};
39
40use super::DataModel;
41
42const MAX_STRING_BYTE_LENGTH: u32 = (1 << 31) - 1;
43const UTF16_TAG: u32 = 1 << 31;
44
45const INITIAL_FUEL: usize = 1_000;
48
49struct Compiler<'a, 'b> {
50 types: &'a ComponentTypesBuilder,
51 module: &'b mut Module<'a>,
52 result: FunctionId,
53
54 code: Vec<u8>,
56
57 nlocals: u32,
59
60 free_locals: HashMap<ValType, Vec<u32>>,
62
63 fuel: usize,
72
73 emit_resource_call: bool,
78}
79
80pub(super) fn compile(module: &mut Module<'_>, adapter: &AdapterData) {
81 fn compiler<'a, 'b>(
82 module: &'b mut Module<'a>,
83 adapter: &AdapterData,
84 ) -> (Compiler<'a, 'b>, Signature, Signature) {
85 let lower_sig = module.types.signature(&adapter.lower);
86 let lift_sig = module.types.signature(&adapter.lift);
87 let ty = module
88 .core_types
89 .function(&lower_sig.params, &lower_sig.results);
90 let result = module
91 .funcs
92 .push(Function::new(Some(adapter.name.clone()), ty));
93
94 let emit_resource_call = module.types.contains_borrow_resource(&adapter.lower);
99 assert_eq!(
100 emit_resource_call,
101 module.types.contains_borrow_resource(&adapter.lift)
102 );
103
104 (
105 Compiler::new(
106 module,
107 result,
108 lower_sig.params.len() as u32,
109 emit_resource_call,
110 ),
111 lower_sig,
112 lift_sig,
113 )
114 }
115
116 let async_start_adapter = |module: &mut Module| {
122 let sig = module
123 .types
124 .async_start_signature(&adapter.lower, &adapter.lift);
125 let ty = module.core_types.function(&sig.params, &sig.results);
126 let result = module.funcs.push(Function::new(
127 Some(format!("[async-start]{}", adapter.name)),
128 ty,
129 ));
130
131 Compiler::new(module, result, sig.params.len() as u32, false)
132 .compile_async_start_adapter(adapter, &sig);
133
134 result
135 };
136
137 let async_return_adapter = |module: &mut Module| {
146 let sig = module
147 .types
148 .async_return_signature(&adapter.lower, &adapter.lift);
149 let ty = module.core_types.function(&sig.params, &sig.results);
150 let result = module.funcs.push(Function::new(
151 Some(format!("[async-return]{}", adapter.name)),
152 ty,
153 ));
154
155 Compiler::new(module, result, sig.params.len() as u32, false)
156 .compile_async_return_adapter(adapter, &sig);
157
158 result
159 };
160
161 match (adapter.lower.options.async_, adapter.lift.options.async_) {
162 (false, false) => {
163 let (compiler, lower_sig, lift_sig) = compiler(module, adapter);
166 compiler.compile_sync_to_sync_adapter(adapter, &lower_sig, &lift_sig)
167 }
168 (true, true) => {
169 assert!(module.tunables.concurrency_support);
170
171 let start = async_start_adapter(module);
187 let return_ = async_return_adapter(module);
188 let (compiler, lower_sig, lift_sig) = compiler(module, adapter);
189 compiler.compile_async_to_async_adapter(
190 adapter,
191 start,
192 return_,
193 i32::try_from(lift_sig.params.len()).unwrap(),
194 &lower_sig,
195 );
196 }
197 (false, true) => {
198 assert!(module.tunables.concurrency_support);
199
200 let start = async_start_adapter(module);
213 let return_ = async_return_adapter(module);
214 let (compiler, lower_sig, lift_sig) = compiler(module, adapter);
215 compiler.compile_sync_to_async_adapter(
216 adapter,
217 start,
218 return_,
219 i32::try_from(lift_sig.params.len()).unwrap(),
220 &lower_sig,
221 );
222 }
223 (true, false) => {
224 assert!(module.tunables.concurrency_support);
225
226 let lift_sig = module.types.signature(&adapter.lift);
246 let start = async_start_adapter(module);
247 let return_ = async_return_adapter(module);
248 let (compiler, lower_sig, ..) = compiler(module, adapter);
249 compiler.compile_async_to_sync_adapter(
250 adapter,
251 start,
252 return_,
253 i32::try_from(lift_sig.params.len()).unwrap(),
254 i32::try_from(lift_sig.results.len()).unwrap(),
255 &lower_sig,
256 );
257 }
258 }
259}
260
261pub(super) fn compile_helper(module: &mut Module<'_>, result: FunctionId, helper: Helper) {
268 let mut nlocals = 0;
269 let src_flat;
270 let src = match helper.src.loc {
271 HelperLocation::Stack => {
276 src_flat = module
277 .types
278 .flatten_types(&helper.src.opts, usize::MAX, [helper.src.ty])
279 .unwrap()
280 .iter()
281 .enumerate()
282 .map(|(i, ty)| (i as u32, *ty))
283 .collect::<Vec<_>>();
284 nlocals += src_flat.len() as u32;
285 Source::Stack(Stack {
286 locals: &src_flat,
287 opts: &helper.src.opts,
288 })
289 }
290 HelperLocation::Memory => {
293 nlocals += 1;
294 Source::Memory(Memory {
295 opts: &helper.src.opts,
296 addr: TempLocal::new(0, helper.src.opts.data_model.unwrap_memory().ptr()),
297 offset: 0,
298 })
299 }
300 HelperLocation::StructField | HelperLocation::ArrayElement => todo!("CM+GC"),
301 };
302 let dst_flat;
303 let dst = match helper.dst.loc {
304 HelperLocation::Stack => {
307 dst_flat = module
308 .types
309 .flatten_types(&helper.dst.opts, usize::MAX, [helper.dst.ty])
310 .unwrap();
311 Destination::Stack(&dst_flat, &helper.dst.opts)
312 }
313 HelperLocation::Memory => {
316 nlocals += 1;
317 Destination::Memory(Memory {
318 opts: &helper.dst.opts,
319 addr: TempLocal::new(
320 nlocals - 1,
321 helper.dst.opts.data_model.unwrap_memory().ptr(),
322 ),
323 offset: 0,
324 })
325 }
326 HelperLocation::StructField | HelperLocation::ArrayElement => todo!("CM+GC"),
327 };
328 let mut compiler = Compiler {
329 types: module.types,
330 module,
331 code: Vec::new(),
332 nlocals,
333 free_locals: HashMap::new(),
334 result,
335 fuel: INITIAL_FUEL,
336 emit_resource_call: false,
339 };
340 compiler.translate(&helper.src.ty, &src, &helper.dst.ty, &dst);
341 compiler.finish();
342}
343
344enum Source<'a> {
347 Stack(Stack<'a>),
353
354 Memory(Memory<'a>),
357
358 #[allow(dead_code, reason = "CM+GC is still WIP")]
361 Struct(GcStruct<'a>),
362
363 #[allow(dead_code, reason = "CM+GC is still WIP")]
366 Array(GcArray<'a>),
367}
368
369enum Destination<'a> {
371 Stack(&'a [ValType], &'a Options),
377
378 Memory(Memory<'a>),
380
381 #[allow(dead_code, reason = "CM+GC is still WIP")]
384 Struct(GcStruct<'a>),
385
386 #[allow(dead_code, reason = "CM+GC is still WIP")]
389 Array(GcArray<'a>),
390}
391
392struct Stack<'a> {
393 locals: &'a [(u32, ValType)],
399 opts: &'a Options,
401}
402
403struct Memory<'a> {
405 opts: &'a Options,
407 addr: TempLocal,
410 offset: u32,
413}
414
415impl<'a> Memory<'a> {
416 fn mem_opts(&self) -> &'a LinearMemoryOptions {
417 self.opts.data_model.unwrap_memory()
418 }
419}
420
421struct GcStruct<'a> {
423 opts: &'a Options,
424 }
426
427struct GcArray<'a> {
429 opts: &'a Options,
430 }
432
433impl<'a, 'b> Compiler<'a, 'b> {
434 fn new(
435 module: &'b mut Module<'a>,
436 result: FunctionId,
437 nlocals: u32,
438 emit_resource_call: bool,
439 ) -> Self {
440 Self {
441 types: module.types,
442 module,
443 result,
444 code: Vec::new(),
445 nlocals,
446 free_locals: HashMap::new(),
447 fuel: INITIAL_FUEL,
448 emit_resource_call,
449 }
450 }
451
452 fn compile_async_to_async_adapter(
462 mut self,
463 adapter: &AdapterData,
464 start: FunctionId,
465 return_: FunctionId,
466 param_count: i32,
467 lower_sig: &Signature,
468 ) {
469 let start_call =
470 self.module
471 .import_async_start_call(&adapter.name, adapter.lift.options.callback, None);
472
473 self.call_prepare(adapter, start, return_, lower_sig, false);
474
475 self.module.exports.push((
484 adapter.callee.as_u32(),
485 format!("[adapter-callee]{}", adapter.name),
486 ));
487
488 self.instruction(RefFunc(adapter.callee.as_u32()));
489 self.instruction(I32Const(param_count));
490 self.instruction(I32Const(1));
494 self.instruction(I32Const(START_FLAG_ASYNC_CALLEE));
495 self.instruction(Call(start_call.as_u32()));
496
497 self.finish()
498 }
499
500 fn call_prepare(
513 &mut self,
514 adapter: &AdapterData,
515 start: FunctionId,
516 return_: FunctionId,
517 lower_sig: &Signature,
518 prepare_sync: bool,
519 ) {
520 let prepare = self.module.import_prepare_call(
521 &adapter.name,
522 &lower_sig.params,
523 match adapter.lift.options.data_model {
524 DataModel::Gc {} => todo!("CM+GC"),
525 DataModel::LinearMemory(LinearMemoryOptions { memory, .. }) => memory.map(|m| m.0),
526 },
527 );
528
529 self.flush_code();
530 self.module.funcs[self.result]
531 .body
532 .push(Body::RefFunc(start));
533 self.module.funcs[self.result]
534 .body
535 .push(Body::RefFunc(return_));
536 self.instruction(I32Const(
537 i32::try_from(adapter.lower.instance.as_u32()).unwrap(),
538 ));
539 self.instruction(I32Const(
540 i32::try_from(adapter.lift.instance.as_u32()).unwrap(),
541 ));
542 self.instruction(I32Const(
543 i32::try_from(self.types[adapter.lift.ty].results.as_u32()).unwrap(),
544 ));
545 self.instruction(I32Const(if self.types[adapter.lift.ty].async_ {
546 1
547 } else {
548 0
549 }));
550 self.instruction(I32Const(i32::from(
551 adapter.lift.options.string_encoding as u8,
552 )));
553
554 let result_types = &self.types[self.types[adapter.lower.ty].results].types;
557 if prepare_sync {
558 self.instruction(I32Const(
559 i32::try_from(
560 self.types
561 .flatten_types(
562 &adapter.lower.options,
563 usize::MAX,
564 result_types.iter().copied(),
565 )
566 .map(|v| v.len())
567 .unwrap_or(usize::try_from(i32::MAX).unwrap()),
568 )
569 .unwrap(),
570 ));
571 } else {
572 if result_types.len() > 0 {
573 self.instruction(I32Const(PREPARE_ASYNC_WITH_RESULT.cast_signed()));
574 } else {
575 self.instruction(I32Const(PREPARE_ASYNC_NO_RESULT.cast_signed()));
576 }
577 }
578
579 for index in 0..lower_sig.params.len() {
581 self.instruction(LocalGet(u32::try_from(index).unwrap()));
582 }
583 self.instruction(Call(prepare.as_u32()));
584 }
585
586 fn compile_sync_to_async_adapter(
596 mut self,
597 adapter: &AdapterData,
598 start: FunctionId,
599 return_: FunctionId,
600 lift_param_count: i32,
601 lower_sig: &Signature,
602 ) {
603 let start_call = self.module.import_sync_start_call(
604 &adapter.name,
605 adapter.lift.options.callback,
606 &lower_sig.results,
607 );
608
609 self.call_prepare(adapter, start, return_, lower_sig, true);
610
611 self.module.exports.push((
620 adapter.callee.as_u32(),
621 format!("[adapter-callee]{}", adapter.name),
622 ));
623
624 self.instruction(RefFunc(adapter.callee.as_u32()));
625 self.instruction(I32Const(lift_param_count));
626 self.instruction(Call(start_call.as_u32()));
627
628 self.finish()
629 }
630
631 fn compile_async_to_sync_adapter(
641 mut self,
642 adapter: &AdapterData,
643 start: FunctionId,
644 return_: FunctionId,
645 param_count: i32,
646 result_count: i32,
647 lower_sig: &Signature,
648 ) {
649 let start_call =
650 self.module
651 .import_async_start_call(&adapter.name, None, adapter.lift.post_return);
652
653 self.call_prepare(adapter, start, return_, lower_sig, false);
654
655 self.module.exports.push((
659 adapter.callee.as_u32(),
660 format!("[adapter-callee]{}", adapter.name),
661 ));
662
663 self.instruction(RefFunc(adapter.callee.as_u32()));
664 self.instruction(I32Const(param_count));
665 self.instruction(I32Const(result_count));
666 self.instruction(I32Const(0));
667 self.instruction(Call(start_call.as_u32()));
668
669 self.finish()
670 }
671
672 fn compile_async_start_adapter(mut self, adapter: &AdapterData, sig: &Signature) {
678 let param_locals = sig
684 .params
685 .iter()
686 .enumerate()
687 .map(|(i, ty)| (i as u32, *ty))
688 .collect::<Vec<_>>();
689
690 let saved = self.clear_may_leave(adapter.lift.flags);
691 self.translate_params(adapter, ¶m_locals);
692 self.restore_may_leave(adapter.lift.flags, saved);
693
694 self.finish();
695 }
696
697 fn compile_async_return_adapter(mut self, adapter: &AdapterData, sig: &Signature) {
706 let param_locals = sig
710 .params
711 .iter()
712 .enumerate()
713 .map(|(i, ty)| (i as u32, *ty))
714 .collect::<Vec<_>>();
715
716 let saved = self.clear_may_leave(adapter.lower.flags);
717 self.translate_results(adapter, ¶m_locals, ¶m_locals);
728 self.restore_may_leave(adapter.lower.flags, saved);
729
730 self.finish()
731 }
732
733 fn compile_sync_to_sync_adapter(
740 mut self,
741 adapter: &AdapterData,
742 lower_sig: &Signature,
743 lift_sig: &Signature,
744 ) {
745 self.enter_exception_barrier(&lower_sig.results);
746
747 let saved_lower_may_leave =
757 self.trap_if_not_may_leave(adapter.lower.flags, Trap::CannotLeaveComponent);
758
759 debug_assert!(
765 !(adapter.thread_transparent && self.emit_resource_call),
766 "resources are not thread transparent",
767 );
768 let needs_thread_state =
769 self.module.tunables.concurrency_support && !adapter.thread_transparent;
770
771 if needs_thread_state {
772 self.instruction(I32Const(if self.types[adapter.lift.ty].async_ {
781 1
782 } else {
783 0
784 }));
785 self.instruction(I32Const(
786 i32::try_from(adapter.lift.instance.as_u32()).unwrap(),
787 ));
788 let enter_sync_call = self.module.import_enter_sync_call();
789 self.instruction(Call(enter_sync_call.as_u32()));
790 } else if self.emit_resource_call {
791 assert!(!self.types[adapter.lift.ty].async_);
792 self.instruction(I32Const(0));
793 self.instruction(I32Const(
794 i32::try_from(adapter.lift.instance.as_u32()).unwrap(),
795 ));
796 let enter_sync_call = self.module.import_enter_sync_call();
797 self.instruction(Call(enter_sync_call.as_u32()));
798 }
799
800 let saved_lift_may_leave = self.clear_may_leave(adapter.lift.flags);
835 let param_locals = lower_sig
836 .params
837 .iter()
838 .enumerate()
839 .map(|(i, ty)| (i as u32, *ty))
840 .collect::<Vec<_>>();
841 self.translate_params(adapter, ¶m_locals);
842 self.restore_may_leave(adapter.lift.flags, saved_lift_may_leave);
843
844 self.instruction(Call(adapter.callee.as_u32()));
849
850 let mut result_locals = Vec::with_capacity(lift_sig.results.len());
851 let mut temps = Vec::new();
852 for ty in lift_sig.results.iter().rev() {
853 let local = self.local_set_new_tmp(*ty);
854 result_locals.push((local.idx, *ty));
855 temps.push(local);
856 }
857 result_locals.reverse();
858
859 let callee_context = if adapter.lift.post_return.is_some() {
863 self.save_context()
864 } else {
865 Vec::new()
866 };
867
868 if self.emit_resource_call || needs_thread_state {
885 let exit_sync_call = self.module.import_exit_sync_call();
886 self.instruction(Call(exit_sync_call.as_u32()));
887 }
888
889 self.set_may_leave_false(adapter.lower.flags);
895 self.translate_results(adapter, ¶m_locals, &result_locals);
896 self.restore_may_leave(adapter.lower.flags, saved_lower_may_leave);
897
898 if let Some(func) = adapter.lift.post_return {
904 let caller_context = self.save_context();
905 self.restore_context(callee_context);
906 for (result, _) in result_locals.iter() {
907 self.instruction(LocalGet(*result));
908 }
909 self.instruction(Call(func.as_u32()));
910 self.restore_context(caller_context);
911 } else {
912 assert!(callee_context.is_empty());
913 }
914
915 for tmp in temps {
916 self.free_temp_local(tmp);
917 }
918
919 self.exit_exception_barrier();
920
921 self.finish()
922 }
923
924 fn translate_params(&mut self, adapter: &AdapterData, param_locals: &[(u32, ValType)]) {
925 let src_tys = self.types[adapter.lower.ty].params;
926 let src_tys = self.types[src_tys]
927 .types
928 .iter()
929 .copied()
930 .collect::<Vec<_>>();
931 let dst_tys = self.types[adapter.lift.ty].params;
932 let dst_tys = self.types[dst_tys]
933 .types
934 .iter()
935 .copied()
936 .collect::<Vec<_>>();
937 let lift_opts = &adapter.lift.options;
938 let lower_opts = &adapter.lower.options;
939
940 assert_eq!(src_tys.len(), dst_tys.len());
942
943 let max_flat_params = if adapter.lower.options.async_ {
947 MAX_FLAT_ASYNC_PARAMS
948 } else {
949 MAX_FLAT_PARAMS
950 };
951 let src_flat =
952 self.types
953 .flatten_types(lower_opts, max_flat_params, src_tys.iter().copied());
954 let dst_flat =
955 self.types
956 .flatten_types(lift_opts, MAX_FLAT_PARAMS, dst_tys.iter().copied());
957
958 let src = if let Some(flat) = &src_flat {
959 Source::Stack(Stack {
960 locals: ¶m_locals[..flat.len()],
961 opts: lower_opts,
962 })
963 } else {
964 let lower_mem_opts = lower_opts.data_model.unwrap_memory();
968 let (addr, ty) = param_locals[0];
969 assert_eq!(ty, lower_mem_opts.ptr());
970 let abi = CanonicalAbiInfo::record(src_tys.iter().map(|t| self.types.canonical_abi(t)));
971 Source::Memory(self.memory_operand_abi(
972 lower_opts,
973 TempLocal::new(addr, ty),
974 &abi,
975 Trap::MemoryOutOfBounds,
976 ))
977 };
978
979 let dst = if let Some(flat) = &dst_flat {
980 Destination::Stack(flat, lift_opts)
981 } else {
982 let abi = CanonicalAbiInfo::record(dst_tys.iter().map(|t| self.types.canonical_abi(t)));
985 Destination::Memory(self.malloc_abi(lift_opts, &abi, Trap::MemoryOutOfBounds))
986 };
987
988 let srcs = src
989 .record_field_srcs(self.types, src_tys.iter().copied())
990 .zip(src_tys.iter());
991 let dsts = dst
992 .record_field_dsts(self.types, dst_tys.iter().copied())
993 .zip(dst_tys.iter());
994 for ((src, src_ty), (dst, dst_ty)) in srcs.zip(dsts) {
995 self.translate(&src_ty, &src, &dst_ty, &dst);
996 }
997
998 if let Destination::Memory(mem) = dst {
1002 self.instruction(LocalGet(mem.addr.idx));
1003 self.free_temp_local(mem.addr);
1004 }
1005 }
1006
1007 fn translate_results(
1008 &mut self,
1009 adapter: &AdapterData,
1010 param_locals: &[(u32, ValType)],
1011 result_locals: &[(u32, ValType)],
1012 ) {
1013 let src_tys = self.types[adapter.lift.ty].results;
1014 let src_tys = self.types[src_tys]
1015 .types
1016 .iter()
1017 .copied()
1018 .collect::<Vec<_>>();
1019 let dst_tys = self.types[adapter.lower.ty].results;
1020 let dst_tys = self.types[dst_tys]
1021 .types
1022 .iter()
1023 .copied()
1024 .collect::<Vec<_>>();
1025 let lift_opts = &adapter.lift.options;
1026 let lower_opts = &adapter.lower.options;
1027
1028 let src_flat = self
1029 .types
1030 .flatten_lifting_types(lift_opts, src_tys.iter().copied());
1031 let dst_flat = self
1032 .types
1033 .flatten_lowering_types(lower_opts, dst_tys.iter().copied());
1034
1035 let src = if src_flat.is_some() {
1036 Source::Stack(Stack {
1037 locals: result_locals,
1038 opts: lift_opts,
1039 })
1040 } else {
1041 let abi = CanonicalAbiInfo::record(src_tys.iter().map(|t| self.types.canonical_abi(t)));
1046 assert_eq!(
1047 result_locals.len(),
1048 if lower_opts.async_ || lift_opts.async_ {
1049 2
1050 } else {
1051 1
1052 }
1053 );
1054 let (addr, ty) = result_locals[0];
1055 assert_eq!(ty, lift_opts.data_model.unwrap_memory().ptr());
1056 Source::Memory(self.memory_operand_abi(
1057 lift_opts,
1058 TempLocal::new(addr, ty),
1059 &abi,
1060 Trap::MemoryOutOfBounds,
1061 ))
1062 };
1063
1064 let dst = if let Some(flat) = &dst_flat {
1065 Destination::Stack(flat, lower_opts)
1066 } else {
1067 let abi = CanonicalAbiInfo::record(dst_tys.iter().map(|t| self.types.canonical_abi(t)));
1071 let (addr, ty) = *param_locals.last().expect("no retptr");
1072 assert_eq!(ty, lower_opts.data_model.unwrap_memory().ptr());
1073 Destination::Memory(self.memory_operand_abi(
1074 lower_opts,
1075 TempLocal::new(addr, ty),
1076 &abi,
1077 Trap::MemoryOutOfBounds,
1078 ))
1079 };
1080
1081 let srcs = src
1082 .record_field_srcs(self.types, src_tys.iter().copied())
1083 .zip(src_tys.iter());
1084 let dsts = dst
1085 .record_field_dsts(self.types, dst_tys.iter().copied())
1086 .zip(dst_tys.iter());
1087 for ((src, src_ty), (dst, dst_ty)) in srcs.zip(dsts) {
1088 self.translate(&src_ty, &src, &dst_ty, &dst);
1089 }
1090 }
1091
1092 fn translate(
1093 &mut self,
1094 src_ty: &InterfaceType,
1095 src: &Source<'_>,
1096 dst_ty: &InterfaceType,
1097 dst: &Destination,
1098 ) {
1099 if let Source::Memory(mem) = src {
1100 self.assert_aligned(src_ty, mem);
1101 }
1102 if let Destination::Memory(mem) = dst {
1103 self.assert_aligned(dst_ty, mem);
1104 }
1105
1106 let cost = match src_ty {
1136 InterfaceType::Bool
1140 | InterfaceType::U8
1141 | InterfaceType::S8
1142 | InterfaceType::U16
1143 | InterfaceType::S16
1144 | InterfaceType::U32
1145 | InterfaceType::S32
1146 | InterfaceType::U64
1147 | InterfaceType::S64
1148 | InterfaceType::Float32
1149 | InterfaceType::Float64 => 0,
1150
1151 InterfaceType::Char => 1,
1154
1155 InterfaceType::String => 40,
1158
1159 InterfaceType::List(_) => 40,
1162 InterfaceType::Map(_) => 40,
1164
1165 InterfaceType::Flags(i) => {
1166 let count = self.module.types[*i].names.len();
1167 match FlagsSize::from_count(count) {
1168 FlagsSize::Size0 => 0,
1169 FlagsSize::Size1 | FlagsSize::Size2 => 1,
1170 FlagsSize::Size4Plus(n) => n.into(),
1171 }
1172 }
1173
1174 InterfaceType::Record(i) => self.types[*i].fields.len(),
1175 InterfaceType::Tuple(i) => self.types[*i].types.len(),
1176 InterfaceType::Variant(i) => self.types[*i].cases.len(),
1177 InterfaceType::Enum(i) => self.types[*i].names.len(),
1178
1179 InterfaceType::Option(_) | InterfaceType::Result(_) => 2,
1181
1182 InterfaceType::Own(_)
1184 | InterfaceType::Borrow(_)
1185 | InterfaceType::Future(_)
1186 | InterfaceType::Stream(_)
1187 | InterfaceType::ErrorContext(_) => 1,
1188 InterfaceType::FixedLengthList(i) => self.types[*i].size as usize,
1189 };
1190
1191 let remaining_fuel = if self.fuel == INITIAL_FUEL {
1198 Some(self.fuel.saturating_sub(cost))
1199 } else {
1200 self.fuel.checked_sub(cost)
1201 };
1202
1203 match remaining_fuel {
1204 Some(n) => {
1210 self.fuel = n;
1211 match src_ty {
1212 InterfaceType::Bool => self.translate_bool(src, dst_ty, dst),
1213 InterfaceType::U8 => self.translate_u8(src, dst_ty, dst),
1214 InterfaceType::S8 => self.translate_s8(src, dst_ty, dst),
1215 InterfaceType::U16 => self.translate_u16(src, dst_ty, dst),
1216 InterfaceType::S16 => self.translate_s16(src, dst_ty, dst),
1217 InterfaceType::U32 => self.translate_u32(src, dst_ty, dst),
1218 InterfaceType::S32 => self.translate_s32(src, dst_ty, dst),
1219 InterfaceType::U64 => self.translate_u64(src, dst_ty, dst),
1220 InterfaceType::S64 => self.translate_s64(src, dst_ty, dst),
1221 InterfaceType::Float32 => self.translate_f32(src, dst_ty, dst),
1222 InterfaceType::Float64 => self.translate_f64(src, dst_ty, dst),
1223 InterfaceType::Char => self.translate_char(src, dst_ty, dst),
1224 InterfaceType::String => self.translate_string(src, dst_ty, dst),
1225 InterfaceType::List(t) => self.translate_list(*t, src, dst_ty, dst),
1226 InterfaceType::Map(t) => self.translate_map(*t, src, dst_ty, dst),
1227 InterfaceType::Record(t) => self.translate_record(*t, src, dst_ty, dst),
1228 InterfaceType::Flags(f) => self.translate_flags(*f, src, dst_ty, dst),
1229 InterfaceType::Tuple(t) => self.translate_tuple(*t, src, dst_ty, dst),
1230 InterfaceType::Variant(v) => self.translate_variant(*v, src, dst_ty, dst),
1231 InterfaceType::Enum(t) => self.translate_enum(*t, src, dst_ty, dst),
1232 InterfaceType::Option(t) => self.translate_option(*t, src, dst_ty, dst),
1233 InterfaceType::Result(t) => self.translate_result(*t, src, dst_ty, dst),
1234 InterfaceType::Own(t) => self.translate_own(*t, src, dst_ty, dst),
1235 InterfaceType::Borrow(t) => self.translate_borrow(*t, src, dst_ty, dst),
1236 InterfaceType::Future(t) => self.translate_future(*t, src, dst_ty, dst),
1237 InterfaceType::Stream(t) => self.translate_stream(*t, src, dst_ty, dst),
1238 InterfaceType::ErrorContext(t) => {
1239 self.translate_error_context(*t, src, dst_ty, dst)
1240 }
1241 InterfaceType::FixedLengthList(t) => {
1242 self.translate_fixed_length_list(*t, src, dst_ty, dst);
1243 }
1244 }
1245 }
1246
1247 None => {
1253 let src_loc = match src {
1254 Source::Stack(stack) => {
1258 for (i, ty) in stack
1259 .opts
1260 .flat_types(src_ty, self.types)
1261 .unwrap()
1262 .iter()
1263 .enumerate()
1264 {
1265 let stack = stack.slice(i..i + 1);
1266 self.stack_get(&stack, (*ty).into());
1267 }
1268 HelperLocation::Stack
1269 }
1270 Source::Memory(mem) => {
1275 self.push_mem_addr(mem);
1276 HelperLocation::Memory
1277 }
1278 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1279 };
1280 let dst_loc = match dst {
1281 Destination::Stack(..) => HelperLocation::Stack,
1282 Destination::Memory(mem) => {
1283 self.push_mem_addr(mem);
1284 HelperLocation::Memory
1285 }
1286 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1287 };
1288 let helper = self.module.translate_helper(Helper {
1294 src: HelperType {
1295 ty: *src_ty,
1296 opts: *src.opts(),
1297 loc: src_loc,
1298 },
1299 dst: HelperType {
1300 ty: *dst_ty,
1301 opts: *dst.opts(),
1302 loc: dst_loc,
1303 },
1304 });
1305 self.flush_code();
1308 self.module.funcs[self.result].body.push(Body::Call(helper));
1309
1310 if let Destination::Stack(tys, opts) = dst {
1319 let flat = self
1320 .types
1321 .flatten_types(opts, usize::MAX, [*dst_ty])
1322 .unwrap();
1323 assert_eq!(flat.len(), tys.len());
1324 let locals = flat
1325 .iter()
1326 .rev()
1327 .map(|ty| self.local_set_new_tmp(*ty))
1328 .collect::<Vec<_>>();
1329 for (ty, local) in tys.iter().zip(locals.into_iter().rev()) {
1330 self.instruction(LocalGet(local.idx));
1331 self.stack_set(std::slice::from_ref(ty), local.ty);
1332 self.free_temp_local(local);
1333 }
1334 }
1335 }
1336 }
1337 }
1338
1339 fn push_mem_addr(&mut self, mem: &Memory<'_>) {
1340 self.instruction(LocalGet(mem.addr.idx));
1341 if mem.offset != 0 {
1342 self.ptr_uconst(mem.mem_opts(), mem.offset);
1343 self.ptr_add(mem.mem_opts());
1344 }
1345 }
1346
1347 fn translate_bool(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1348 assert!(matches!(dst_ty, InterfaceType::Bool));
1350 self.push_dst_addr(dst);
1351
1352 self.instruction(I32Const(1));
1355 self.instruction(I32Const(0));
1356 match src {
1357 Source::Memory(mem) => self.i32_load8u(mem),
1358 Source::Stack(stack) => self.stack_get(stack, ValType::I32),
1359 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1360 }
1361 self.instruction(Select);
1362
1363 match dst {
1364 Destination::Memory(mem) => self.i32_store8(mem),
1365 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1366 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1367 }
1368 }
1369
1370 fn translate_u8(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1371 assert!(matches!(dst_ty, InterfaceType::U8));
1373 self.convert_u8_mask(src, dst, 0xff);
1374 }
1375
1376 fn convert_u8_mask(&mut self, src: &Source<'_>, dst: &Destination<'_>, mask: u8) {
1377 self.push_dst_addr(dst);
1378 let mut needs_mask = true;
1379 match src {
1380 Source::Memory(mem) => {
1381 self.i32_load8u(mem);
1382 needs_mask = mask != 0xff;
1383 }
1384 Source::Stack(stack) => {
1385 self.stack_get(stack, ValType::I32);
1386 }
1387 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1388 }
1389 if needs_mask {
1390 self.instruction(I32Const(i32::from(mask)));
1391 self.instruction(I32And);
1392 }
1393 match dst {
1394 Destination::Memory(mem) => self.i32_store8(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_s8(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1401 assert!(matches!(dst_ty, InterfaceType::S8));
1403 self.push_dst_addr(dst);
1404 match src {
1405 Source::Memory(mem) => self.i32_load8s(mem),
1406 Source::Stack(stack) => {
1407 self.stack_get(stack, ValType::I32);
1408 self.instruction(I32Extend8S);
1409 }
1410 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1411 }
1412 match dst {
1413 Destination::Memory(mem) => self.i32_store8(mem),
1414 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1415 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1416 }
1417 }
1418
1419 fn translate_u16(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1420 assert!(matches!(dst_ty, InterfaceType::U16));
1422 self.convert_u16_mask(src, dst, 0xffff);
1423 }
1424
1425 fn convert_u16_mask(&mut self, src: &Source<'_>, dst: &Destination<'_>, mask: u16) {
1426 self.push_dst_addr(dst);
1427 let mut needs_mask = true;
1428 match src {
1429 Source::Memory(mem) => {
1430 self.i32_load16u(mem);
1431 needs_mask = mask != 0xffff;
1432 }
1433 Source::Stack(stack) => {
1434 self.stack_get(stack, ValType::I32);
1435 }
1436 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1437 }
1438 if needs_mask {
1439 self.instruction(I32Const(i32::from(mask)));
1440 self.instruction(I32And);
1441 }
1442 match dst {
1443 Destination::Memory(mem) => self.i32_store16(mem),
1444 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1445 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1446 }
1447 }
1448
1449 fn translate_s16(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1450 assert!(matches!(dst_ty, InterfaceType::S16));
1452 self.push_dst_addr(dst);
1453 match src {
1454 Source::Memory(mem) => self.i32_load16s(mem),
1455 Source::Stack(stack) => {
1456 self.stack_get(stack, ValType::I32);
1457 self.instruction(I32Extend16S);
1458 }
1459 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1460 }
1461 match dst {
1462 Destination::Memory(mem) => self.i32_store16(mem),
1463 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1464 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1465 }
1466 }
1467
1468 fn translate_u32(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1469 assert!(matches!(dst_ty, InterfaceType::U32));
1471 self.convert_u32_mask(src, dst, 0xffffffff)
1472 }
1473
1474 fn convert_u32_mask(&mut self, src: &Source<'_>, dst: &Destination<'_>, mask: u32) {
1475 self.push_dst_addr(dst);
1476 match src {
1477 Source::Memory(mem) => self.i32_load(mem),
1478 Source::Stack(stack) => self.stack_get(stack, ValType::I32),
1479 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1480 }
1481 if mask != 0xffffffff {
1482 self.instruction(I32Const(mask as i32));
1483 self.instruction(I32And);
1484 }
1485 match dst {
1486 Destination::Memory(mem) => self.i32_store(mem),
1487 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1488 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1489 }
1490 }
1491
1492 fn translate_s32(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1493 assert!(matches!(dst_ty, InterfaceType::S32));
1495 self.push_dst_addr(dst);
1496 match src {
1497 Source::Memory(mem) => self.i32_load(mem),
1498 Source::Stack(stack) => self.stack_get(stack, ValType::I32),
1499 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1500 }
1501 match dst {
1502 Destination::Memory(mem) => self.i32_store(mem),
1503 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1504 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1505 }
1506 }
1507
1508 fn translate_u64(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1509 assert!(matches!(dst_ty, InterfaceType::U64));
1511 self.push_dst_addr(dst);
1512 match src {
1513 Source::Memory(mem) => self.i64_load(mem),
1514 Source::Stack(stack) => self.stack_get(stack, ValType::I64),
1515 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1516 }
1517 match dst {
1518 Destination::Memory(mem) => self.i64_store(mem),
1519 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I64),
1520 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1521 }
1522 }
1523
1524 fn translate_s64(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1525 assert!(matches!(dst_ty, InterfaceType::S64));
1527 self.push_dst_addr(dst);
1528 match src {
1529 Source::Memory(mem) => self.i64_load(mem),
1530 Source::Stack(stack) => self.stack_get(stack, ValType::I64),
1531 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1532 }
1533 match dst {
1534 Destination::Memory(mem) => self.i64_store(mem),
1535 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I64),
1536 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1537 }
1538 }
1539
1540 fn translate_f32(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1541 assert!(matches!(dst_ty, InterfaceType::Float32));
1543 self.push_dst_addr(dst);
1544 match src {
1545 Source::Memory(mem) => self.f32_load(mem),
1546 Source::Stack(stack) => self.stack_get(stack, ValType::F32),
1547 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1548 }
1549 match dst {
1550 Destination::Memory(mem) => self.f32_store(mem),
1551 Destination::Stack(stack, _) => self.stack_set(stack, ValType::F32),
1552 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1553 }
1554 }
1555
1556 fn translate_f64(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1557 assert!(matches!(dst_ty, InterfaceType::Float64));
1559 self.push_dst_addr(dst);
1560 match src {
1561 Source::Memory(mem) => self.f64_load(mem),
1562 Source::Stack(stack) => self.stack_get(stack, ValType::F64),
1563 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1564 }
1565 match dst {
1566 Destination::Memory(mem) => self.f64_store(mem),
1567 Destination::Stack(stack, _) => self.stack_set(stack, ValType::F64),
1568 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1569 }
1570 }
1571
1572 fn translate_char(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1573 assert!(matches!(dst_ty, InterfaceType::Char));
1574 match src {
1575 Source::Memory(mem) => self.i32_load(mem),
1576 Source::Stack(stack) => self.stack_get(stack, ValType::I32),
1577 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1578 }
1579 let local = self.local_set_new_tmp(ValType::I32);
1580
1581 self.instruction(Block(BlockType::Empty));
1597 self.instruction(Block(BlockType::Empty));
1598 self.instruction(LocalGet(local.idx));
1599 self.instruction(I32Const(0xd800));
1600 self.instruction(I32Xor);
1601 self.instruction(I32Const(-0x110000));
1602 self.instruction(I32Add);
1603 self.instruction(I32Const(-0x10f800));
1604 self.instruction(I32LtU);
1605 self.instruction(BrIf(0));
1606 self.instruction(LocalGet(local.idx));
1607 self.instruction(I32Const(0x110000));
1608 self.instruction(I32Ne);
1609 self.instruction(BrIf(1));
1610 self.instruction(End);
1611 self.trap(Trap::InvalidChar);
1612 self.instruction(End);
1613
1614 self.push_dst_addr(dst);
1615 self.instruction(LocalGet(local.idx));
1616 match dst {
1617 Destination::Memory(mem) => {
1618 self.i32_store(mem);
1619 }
1620 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1621 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1622 }
1623
1624 self.free_temp_local(local);
1625 }
1626
1627 fn translate_string(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1628 assert!(matches!(dst_ty, InterfaceType::String));
1629 let src_opts = src.opts();
1630 let dst_opts = dst.opts();
1631
1632 let src_mem_opts = match &src_opts.data_model {
1633 DataModel::Gc {} => todo!("CM+GC"),
1634 DataModel::LinearMemory(opts) => opts,
1635 };
1636 let dst_mem_opts = match &dst_opts.data_model {
1637 DataModel::Gc {} => todo!("CM+GC"),
1638 DataModel::LinearMemory(opts) => opts,
1639 };
1640
1641 match src {
1646 Source::Stack(s) => {
1647 assert_eq!(s.locals.len(), 2);
1648 self.stack_get(&s.slice(0..1), src_mem_opts.ptr());
1649 self.stack_get(&s.slice(1..2), src_mem_opts.ptr());
1650 }
1651 Source::Memory(mem) => {
1652 self.ptr_load(mem);
1653 self.ptr_load(&mem.bump(src_mem_opts.ptr_size().into()));
1654 }
1655 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1656 }
1657 let src_len = self.local_set_new_tmp(src_mem_opts.ptr());
1658 let src_ptr = self.local_set_new_tmp(src_mem_opts.ptr());
1659 let src_str = WasmString {
1660 ptr: src_ptr,
1661 len: src_len,
1662 opts: src_opts,
1663 };
1664
1665 let dst_str = match src_opts.string_encoding {
1666 StringEncoding::Utf8 => {
1667 self.validate_guest_pointer(
1668 src_opts,
1669 &src_str.ptr,
1670 &AllocSize::Local(src_str.len.idx),
1671 1,
1672 Trap::StringOutOfBounds,
1673 );
1674 match dst_opts.string_encoding {
1675 StringEncoding::Utf8 => {
1676 self.string_copy(&src_str, FE::Utf8, dst_opts, FE::Utf8)
1677 }
1678 StringEncoding::Utf16 => self.string_utf8_to_utf16(&src_str, dst_opts),
1679 StringEncoding::CompactUtf16 => {
1680 self.string_to_compact(&src_str, FE::Utf8, dst_opts)
1681 }
1682 }
1683 }
1684
1685 StringEncoding::Utf16 => {
1686 self.validate_guest_pointer(
1687 src_opts,
1688 &src_str.ptr,
1689 &AllocSize::DoubleLocal(src_str.len.idx),
1690 2,
1691 Trap::StringOutOfBounds,
1692 );
1693 match dst_opts.string_encoding {
1694 StringEncoding::Utf8 => {
1695 self.string_deflate_to_utf8(&src_str, FE::Utf16, dst_opts)
1696 }
1697 StringEncoding::Utf16 => {
1698 self.string_copy(&src_str, FE::Utf16, dst_opts, FE::Utf16)
1699 }
1700 StringEncoding::CompactUtf16 => {
1701 self.string_to_compact(&src_str, FE::Utf16, dst_opts)
1702 }
1703 }
1704 }
1705
1706 StringEncoding::CompactUtf16 => {
1707 self.instruction(LocalGet(src_str.len.idx));
1710 self.ptr_uconst(src_mem_opts, UTF16_TAG);
1711 self.ptr_and(src_mem_opts);
1712 self.ptr_if(src_mem_opts, BlockType::Empty);
1713
1714 self.instruction(LocalGet(src_str.len.idx));
1718 self.ptr_uconst(src_mem_opts, UTF16_TAG);
1719 self.ptr_xor(src_mem_opts);
1720 self.instruction(LocalSet(src_str.len.idx));
1721
1722 self.validate_guest_pointer(
1726 src_opts,
1727 &src_str.ptr,
1728 &AllocSize::DoubleLocal(src_str.len.idx),
1729 2,
1730 Trap::StringOutOfBounds,
1731 );
1732
1733 let s1 = match dst_opts.string_encoding {
1734 StringEncoding::Utf8 => {
1735 self.string_deflate_to_utf8(&src_str, FE::Utf16, dst_opts)
1736 }
1737 StringEncoding::Utf16 => {
1738 self.string_copy(&src_str, FE::Utf16, dst_opts, FE::Utf16)
1739 }
1740 StringEncoding::CompactUtf16 => {
1741 self.string_compact_utf16_to_compact(&src_str, dst_opts)
1742 }
1743 };
1744
1745 self.instruction(Else);
1746
1747 self.validate_guest_pointer(
1750 src_opts,
1751 &src_str.ptr,
1752 &AllocSize::Local(src_str.len.idx),
1753 2,
1754 Trap::StringOutOfBounds,
1755 );
1756
1757 let s2 = match dst_opts.string_encoding {
1761 StringEncoding::Utf16 => {
1762 self.string_copy(&src_str, FE::Latin1, dst_opts, FE::Utf16)
1763 }
1764 StringEncoding::Utf8 => {
1765 self.string_deflate_to_utf8(&src_str, FE::Latin1, dst_opts)
1766 }
1767 StringEncoding::CompactUtf16 => {
1768 self.string_copy(&src_str, FE::Latin1, dst_opts, FE::Latin1)
1769 }
1770 };
1771 self.instruction(LocalGet(s2.ptr.idx));
1774 self.instruction(LocalSet(s1.ptr.idx));
1775 self.instruction(LocalGet(s2.len.idx));
1776 self.instruction(LocalSet(s1.len.idx));
1777 self.instruction(End);
1778 self.free_temp_local(s2.ptr);
1779 self.free_temp_local(s2.len);
1780 s1
1781 }
1782 };
1783
1784 match dst {
1786 Destination::Stack(s, _) => {
1787 self.instruction(LocalGet(dst_str.ptr.idx));
1788 self.stack_set(&s[..1], dst_mem_opts.ptr());
1789 self.instruction(LocalGet(dst_str.len.idx));
1790 self.stack_set(&s[1..], dst_mem_opts.ptr());
1791 }
1792 Destination::Memory(mem) => {
1793 self.instruction(LocalGet(mem.addr.idx));
1794 self.instruction(LocalGet(dst_str.ptr.idx));
1795 self.ptr_store(mem);
1796 self.instruction(LocalGet(mem.addr.idx));
1797 self.instruction(LocalGet(dst_str.len.idx));
1798 self.ptr_store(&mem.bump(dst_mem_opts.ptr_size().into()));
1799 }
1800 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1801 }
1802
1803 self.free_temp_local(src_str.ptr);
1804 self.free_temp_local(src_str.len);
1805 self.free_temp_local(dst_str.ptr);
1806 self.free_temp_local(dst_str.len);
1807 }
1808
1809 fn string_copy<'c>(
1822 &mut self,
1823 src: &WasmString<'_>,
1824 src_enc: FE,
1825 dst_opts: &'c Options,
1826 dst_enc: FE,
1827 ) -> WasmString<'c> {
1828 assert!(dst_enc.width() >= src_enc.width());
1829
1830 self.validate_string_length(src, dst_enc);
1835
1836 let src_mem_opts = {
1837 match &src.opts.data_model {
1838 DataModel::Gc {} => todo!("CM+GC"),
1839 DataModel::LinearMemory(opts) => opts,
1840 }
1841 };
1842 let dst_mem_opts = {
1843 match &dst_opts.data_model {
1844 DataModel::Gc {} => todo!("CM+GC"),
1845 DataModel::LinearMemory(opts) => opts,
1846 }
1847 };
1848
1849 self.convert_src_len_to_dst(src.len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
1852 let dst_len = self.local_tee_new_tmp(dst_mem_opts.ptr());
1853 if dst_enc.width() > 1 {
1854 assert_eq!(dst_enc.width(), 2);
1855 self.ptr_uconst(dst_mem_opts, 1);
1856 self.ptr_shl(dst_mem_opts);
1857 }
1858 let dst_byte_len = self.local_set_new_tmp(dst_mem_opts.ptr());
1859
1860 let dst = {
1863 let dst_mem = self.malloc(
1864 dst_opts,
1865 AllocSize::Local(dst_byte_len.idx),
1866 dst_enc.align().into(),
1867 Trap::StringOutOfBounds,
1868 );
1869 WasmString {
1870 ptr: dst_mem.addr,
1871 len: dst_len,
1872 opts: dst_opts,
1873 }
1874 };
1875
1876 let op = if src_enc == dst_enc {
1880 Transcode::Copy(src_enc)
1881 } else {
1882 assert_eq!(src_enc, FE::Latin1);
1883 assert_eq!(dst_enc, FE::Utf16);
1884 Transcode::Latin1ToUtf16
1885 };
1886 let transcode = self.transcoder(src, &dst, op);
1887 self.instruction(LocalGet(src.ptr.idx));
1888 self.instruction(LocalGet(src.len.idx));
1889 self.instruction(LocalGet(dst.ptr.idx));
1890 self.instruction(Call(transcode.as_u32()));
1891
1892 self.free_temp_local(dst_byte_len);
1893
1894 dst
1895 }
1896
1897 fn string_deflate_to_utf8<'c>(
1910 &mut self,
1911 src: &WasmString<'_>,
1912 src_enc: FE,
1913 dst_opts: &'c Options,
1914 ) -> WasmString<'c> {
1915 let src_mem_opts = match &src.opts.data_model {
1916 DataModel::Gc {} => todo!("CM+GC"),
1917 DataModel::LinearMemory(opts) => opts,
1918 };
1919 let dst_mem_opts = match &dst_opts.data_model {
1920 DataModel::Gc {} => todo!("CM+GC"),
1921 DataModel::LinearMemory(opts) => opts,
1922 };
1923
1924 self.validate_string_length(src, src_enc);
1925
1926 self.convert_src_len_to_dst(
1930 src.len.idx,
1931 src.opts.data_model.unwrap_memory().ptr(),
1932 dst_opts.data_model.unwrap_memory().ptr(),
1933 );
1934 let dst_len = self.local_tee_new_tmp(dst_opts.data_model.unwrap_memory().ptr());
1935 let dst_byte_len = self.local_set_new_tmp(dst_opts.data_model.unwrap_memory().ptr());
1936
1937 let dst = {
1938 let dst_mem = self.malloc(
1939 dst_opts,
1940 AllocSize::Local(dst_byte_len.idx),
1941 1,
1942 Trap::StringOutOfBounds,
1943 );
1944 WasmString {
1945 ptr: dst_mem.addr,
1946 len: dst_len,
1947 opts: dst_opts,
1948 }
1949 };
1950
1951 let op = match src_enc {
1953 FE::Latin1 => Transcode::Latin1ToUtf8,
1954 FE::Utf16 => Transcode::Utf16ToUtf8,
1955 FE::Utf8 => unreachable!(),
1956 };
1957 let transcode = self.transcoder(src, &dst, op);
1958 self.instruction(LocalGet(src.ptr.idx));
1959 self.instruction(LocalGet(src.len.idx));
1960 self.instruction(LocalGet(dst.ptr.idx));
1961 self.instruction(LocalGet(dst_byte_len.idx));
1962 self.instruction(I32Const(1)); self.instruction(Call(transcode.as_u32()));
1964 self.instruction(LocalSet(dst.len.idx));
1965 let src_len_tmp = self.local_set_new_tmp(src.opts.data_model.unwrap_memory().ptr());
1966
1967 self.instruction(LocalGet(src_len_tmp.idx));
1971 self.instruction(LocalGet(src.len.idx));
1972 self.ptr_ne(src_mem_opts);
1973 self.instruction(If(BlockType::Empty));
1974
1975 let factor = match src_enc {
1978 FE::Latin1 => 2,
1979 FE::Utf16 => 3,
1980 _ => unreachable!(),
1981 };
1982 self.validate_string_length_u8(src, factor);
1983 self.convert_src_len_to_dst(
1984 src.len.idx,
1985 src.opts.data_model.unwrap_memory().ptr(),
1986 dst_opts.data_model.unwrap_memory().ptr(),
1987 );
1988 self.ptr_uconst(dst_mem_opts, factor.into());
1989 self.ptr_mul(dst_mem_opts);
1990 let new_byte_len = self.local_set_new_tmp(dst_mem_opts.ptr());
1991
1992 self.realloc(
1996 dst_opts,
1997 &dst.ptr,
1998 AllocSize::Local(dst_byte_len.idx),
1999 AllocSize::Local(new_byte_len.idx),
2000 1,
2001 Trap::StringOutOfBounds,
2002 );
2003 self.instruction(LocalGet(new_byte_len.idx));
2004 self.instruction(LocalSet(dst_byte_len.idx));
2005 self.free_temp_local(new_byte_len);
2006
2007 self.instruction(LocalGet(src.ptr.idx));
2012 self.instruction(LocalGet(src_len_tmp.idx));
2013 if let FE::Utf16 = src_enc {
2014 self.ptr_uconst(src_mem_opts, 1);
2015 self.ptr_shl(src_mem_opts);
2016 }
2017 self.ptr_add(src_mem_opts);
2018 self.instruction(LocalGet(src.len.idx));
2019 self.instruction(LocalGet(src_len_tmp.idx));
2020 self.ptr_sub(src_mem_opts);
2021 self.instruction(LocalGet(dst.ptr.idx));
2022 self.instruction(LocalGet(dst.len.idx));
2023 self.ptr_add(dst_mem_opts);
2024 self.instruction(LocalGet(dst_byte_len.idx));
2025 self.instruction(LocalGet(dst.len.idx));
2026 self.ptr_sub(dst_mem_opts);
2027 self.instruction(I32Const(0)); self.instruction(Call(transcode.as_u32()));
2029
2030 self.instruction(LocalGet(dst.len.idx));
2034 self.ptr_add(dst_mem_opts);
2035 self.instruction(LocalSet(dst.len.idx));
2036
2037 if self.module.tunables.debug_adapter_modules {
2040 self.instruction(LocalGet(src.len.idx));
2041 self.instruction(LocalGet(src_len_tmp.idx));
2042 self.ptr_sub(src_mem_opts);
2043 self.ptr_ne(src_mem_opts);
2044 self.instruction(If(BlockType::Empty));
2045 self.trap(Trap::DebugAssertStringEncodingFinished);
2046 self.instruction(End);
2047 } else {
2048 self.instruction(Drop);
2049 }
2050
2051 self.instruction(LocalGet(dst.len.idx));
2053 self.instruction(LocalGet(dst_byte_len.idx));
2054 self.ptr_ne(dst_mem_opts);
2055 self.instruction(If(BlockType::Empty));
2056 self.realloc(
2057 dst_opts,
2058 &dst.ptr,
2059 AllocSize::Local(dst_byte_len.idx),
2060 AllocSize::Local(dst.len.idx),
2061 1,
2062 Trap::StringOutOfBounds,
2063 );
2064 self.instruction(End);
2065
2066 if self.module.tunables.debug_adapter_modules {
2069 self.instruction(Else);
2070
2071 self.instruction(LocalGet(dst.len.idx));
2072 self.instruction(LocalGet(dst_byte_len.idx));
2073 self.ptr_ne(dst_mem_opts);
2074 self.instruction(If(BlockType::Empty));
2075 self.trap(Trap::DebugAssertStringEncodingFinished);
2076 self.instruction(End);
2077 }
2078
2079 self.instruction(End); self.free_temp_local(src_len_tmp);
2082 self.free_temp_local(dst_byte_len);
2083
2084 dst
2085 }
2086
2087 fn string_utf8_to_utf16<'c>(
2102 &mut self,
2103 src: &WasmString<'_>,
2104 dst_opts: &'c Options,
2105 ) -> WasmString<'c> {
2106 let src_mem_opts = match &src.opts.data_model {
2107 DataModel::Gc {} => todo!("CM+GC"),
2108 DataModel::LinearMemory(opts) => opts,
2109 };
2110 let dst_mem_opts = match &dst_opts.data_model {
2111 DataModel::Gc {} => todo!("CM+GC"),
2112 DataModel::LinearMemory(opts) => opts,
2113 };
2114
2115 self.validate_string_length(src, FE::Utf16);
2116 self.convert_src_len_to_dst(
2117 src.len.idx,
2118 src_mem_opts.ptr(),
2119 dst_opts.data_model.unwrap_memory().ptr(),
2120 );
2121 let dst_len = self.local_tee_new_tmp(dst_opts.data_model.unwrap_memory().ptr());
2122 self.ptr_uconst(dst_mem_opts, 1);
2123 self.ptr_shl(dst_mem_opts);
2124 let dst_byte_len = self.local_set_new_tmp(dst_opts.data_model.unwrap_memory().ptr());
2125 let dst = {
2126 let dst_mem = self.malloc(
2127 dst_opts,
2128 AllocSize::Local(dst_byte_len.idx),
2129 2,
2130 Trap::StringOutOfBounds,
2131 );
2132 WasmString {
2133 ptr: dst_mem.addr,
2134 len: dst_len,
2135 opts: dst_opts,
2136 }
2137 };
2138
2139 let transcode = self.transcoder(src, &dst, Transcode::Utf8ToUtf16);
2140 self.instruction(LocalGet(src.ptr.idx));
2141 self.instruction(LocalGet(src.len.idx));
2142 self.instruction(LocalGet(dst.ptr.idx));
2143 self.instruction(Call(transcode.as_u32()));
2144 self.instruction(LocalSet(dst.len.idx));
2145
2146 self.convert_src_len_to_dst(src.len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2154 self.instruction(LocalGet(dst.len.idx));
2155 self.ptr_ne(dst_mem_opts);
2156 self.instruction(If(BlockType::Empty));
2157 self.realloc(
2158 dst.opts,
2159 &dst.ptr,
2160 AllocSize::Local(dst_byte_len.idx),
2161 AllocSize::DoubleLocal(dst.len.idx),
2162 2,
2163 Trap::StringOutOfBounds,
2164 );
2165 self.instruction(End); self.free_temp_local(dst_byte_len);
2168
2169 dst
2170 }
2171
2172 fn string_compact_utf16_to_compact<'c>(
2186 &mut self,
2187 src: &WasmString<'_>,
2188 dst_opts: &'c Options,
2189 ) -> WasmString<'c> {
2190 let src_mem_opts = match &src.opts.data_model {
2191 DataModel::Gc {} => todo!("CM+GC"),
2192 DataModel::LinearMemory(opts) => opts,
2193 };
2194 let dst_mem_opts = match &dst_opts.data_model {
2195 DataModel::Gc {} => todo!("CM+GC"),
2196 DataModel::LinearMemory(opts) => opts,
2197 };
2198
2199 self.validate_string_length(src, FE::Utf16);
2200 self.convert_src_len_to_dst(src.len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2201 let dst_len = self.local_tee_new_tmp(dst_mem_opts.ptr());
2202 self.ptr_uconst(dst_mem_opts, 1);
2203 self.ptr_shl(dst_mem_opts);
2204 let dst_byte_len = self.local_set_new_tmp(dst_mem_opts.ptr());
2205 let dst = {
2206 let dst_mem = self.malloc(
2207 dst_opts,
2208 AllocSize::Local(dst_byte_len.idx),
2209 2,
2210 Trap::StringOutOfBounds,
2211 );
2212 WasmString {
2213 ptr: dst_mem.addr,
2214 len: dst_len,
2215 opts: dst_opts,
2216 }
2217 };
2218
2219 self.convert_src_len_to_dst(
2220 dst_byte_len.idx,
2221 dst.opts.data_model.unwrap_memory().ptr(),
2222 src_mem_opts.ptr(),
2223 );
2224 let src_byte_len = self.local_set_new_tmp(src_mem_opts.ptr());
2225
2226 let transcode = self.transcoder(src, &dst, Transcode::Utf16ToCompactProbablyUtf16);
2227 self.instruction(LocalGet(src.ptr.idx));
2228 self.instruction(LocalGet(src.len.idx));
2229 self.instruction(LocalGet(dst.ptr.idx));
2230 self.instruction(Call(transcode.as_u32()));
2231 self.instruction(LocalSet(dst.len.idx));
2232
2233 if self.module.tunables.debug_adapter_modules {
2236 self.instruction(LocalGet(dst.len.idx));
2237 self.ptr_uconst(dst_mem_opts, !UTF16_TAG);
2238 self.ptr_and(dst_mem_opts);
2239 self.convert_src_len_to_dst(src.len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2240 self.ptr_ne(dst_mem_opts);
2241 self.instruction(If(BlockType::Empty));
2242 self.trap(Trap::DebugAssertEqualCodeUnits);
2243 self.instruction(End);
2244 }
2245
2246 self.instruction(LocalGet(dst.len.idx));
2250 self.ptr_uconst(dst_mem_opts, UTF16_TAG);
2251 self.ptr_and(dst_mem_opts);
2252 self.ptr_br_if(dst_mem_opts, 0);
2253
2254 self.realloc(
2256 dst.opts,
2257 &dst.ptr,
2258 AllocSize::Local(dst_byte_len.idx),
2259 AllocSize::Local(dst.len.idx),
2260 2,
2261 Trap::StringOutOfBounds,
2262 );
2263
2264 self.free_temp_local(dst_byte_len);
2265 self.free_temp_local(src_byte_len);
2266
2267 dst
2268 }
2269
2270 fn string_to_compact<'c>(
2277 &mut self,
2278 src: &WasmString<'_>,
2279 src_enc: FE,
2280 dst_opts: &'c Options,
2281 ) -> WasmString<'c> {
2282 let src_mem_opts = match &src.opts.data_model {
2283 DataModel::Gc {} => todo!("CM+GC"),
2284 DataModel::LinearMemory(opts) => opts,
2285 };
2286 let dst_mem_opts = match &dst_opts.data_model {
2287 DataModel::Gc {} => todo!("CM+GC"),
2288 DataModel::LinearMemory(opts) => opts,
2289 };
2290
2291 self.validate_string_length(src, src_enc);
2292
2293 self.convert_src_len_to_dst(src.len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2294 let dst_len = self.local_tee_new_tmp(dst_mem_opts.ptr());
2295 let dst_byte_len = self.local_set_new_tmp(dst_mem_opts.ptr());
2296 let dst = {
2297 let dst_mem = self.malloc(
2298 dst_opts,
2299 AllocSize::Local(dst_byte_len.idx),
2300 2,
2301 Trap::StringOutOfBounds,
2302 );
2303 WasmString {
2304 ptr: dst_mem.addr,
2305 len: dst_len,
2306 opts: dst_opts,
2307 }
2308 };
2309
2310 let (latin1, utf16) = match src_enc {
2314 FE::Utf8 => (Transcode::Utf8ToLatin1, Transcode::Utf8ToCompactUtf16),
2315 FE::Utf16 => (Transcode::Utf16ToLatin1, Transcode::Utf16ToCompactUtf16),
2316 FE::Latin1 => unreachable!(),
2317 };
2318 let transcode_latin1 = self.transcoder(src, &dst, latin1);
2319 let transcode_utf16 = self.transcoder(src, &dst, utf16);
2320 self.instruction(LocalGet(src.ptr.idx));
2321 self.instruction(LocalGet(src.len.idx));
2322 self.instruction(LocalGet(dst.ptr.idx));
2323 self.instruction(Call(transcode_latin1.as_u32()));
2324 self.instruction(LocalSet(dst.len.idx));
2325 let src_len_tmp = self.local_set_new_tmp(src_mem_opts.ptr());
2326
2327 self.instruction(LocalGet(src_len_tmp.idx));
2330 self.instruction(LocalGet(src.len.idx));
2331 self.ptr_eq(src_mem_opts);
2332 self.instruction(If(BlockType::Empty)); self.instruction(LocalGet(dst_byte_len.idx));
2338 self.instruction(LocalGet(dst.len.idx));
2339 self.ptr_ne(dst_mem_opts);
2340 self.instruction(If(BlockType::Empty));
2341 self.realloc(
2342 dst.opts,
2343 &dst.ptr,
2344 AllocSize::Local(dst_byte_len.idx),
2345 AllocSize::Local(dst.len.idx),
2346 2,
2347 Trap::StringOutOfBounds,
2348 );
2349 self.instruction(End);
2350
2351 self.instruction(Else); if src_enc.width() == 1 {
2360 self.validate_string_length_u8(src, 2);
2361 }
2362
2363 self.convert_src_len_to_dst(src.len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2366 self.ptr_uconst(dst_mem_opts, 1);
2367 self.ptr_shl(dst_mem_opts);
2368 let new_byte_len = self.local_set_new_tmp(dst_mem_opts.ptr());
2369 self.realloc(
2370 dst.opts,
2371 &dst.ptr,
2372 AllocSize::Local(dst_byte_len.idx),
2373 AllocSize::Local(new_byte_len.idx),
2374 2,
2375 Trap::StringOutOfBounds,
2376 );
2377 self.instruction(LocalGet(new_byte_len.idx));
2378 self.instruction(LocalSet(dst_byte_len.idx));
2379 self.free_temp_local(new_byte_len);
2380
2381 self.instruction(LocalGet(src.ptr.idx));
2385 self.instruction(LocalGet(src_len_tmp.idx));
2386 if let FE::Utf16 = src_enc {
2387 self.ptr_uconst(src_mem_opts, 1);
2388 self.ptr_shl(src_mem_opts);
2389 }
2390 self.ptr_add(src_mem_opts);
2391 self.instruction(LocalGet(src.len.idx));
2392 self.instruction(LocalGet(src_len_tmp.idx));
2393 self.ptr_sub(src_mem_opts);
2394 self.instruction(LocalGet(dst.ptr.idx));
2395 self.convert_src_len_to_dst(src.len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2396 self.instruction(LocalGet(dst.len.idx));
2397 self.instruction(Call(transcode_utf16.as_u32()));
2398 self.instruction(LocalSet(dst.len.idx));
2399
2400 self.instruction(LocalGet(dst.len.idx));
2408 self.convert_src_len_to_dst(src.len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2409 self.ptr_ne(dst_mem_opts);
2410 self.instruction(If(BlockType::Empty));
2411 self.realloc(
2412 dst.opts,
2413 &dst.ptr,
2414 AllocSize::Local(dst_byte_len.idx),
2415 AllocSize::DoubleLocal(dst.len.idx),
2416 2,
2417 Trap::StringOutOfBounds,
2418 );
2419 self.instruction(End);
2420
2421 self.instruction(LocalGet(dst.len.idx));
2423 self.ptr_uconst(dst_mem_opts, UTF16_TAG);
2424 self.ptr_or(dst_mem_opts);
2425 self.instruction(LocalSet(dst.len.idx));
2426
2427 self.instruction(End); self.free_temp_local(src_len_tmp);
2430 self.free_temp_local(dst_byte_len);
2431
2432 dst
2433 }
2434
2435 fn validate_string_length(&mut self, src: &WasmString<'_>, dst: FE) {
2436 self.validate_string_length_u8(src, dst.width())
2437 }
2438
2439 fn validate_string_length_u8(&mut self, s: &WasmString<'_>, dst: u8) {
2440 let mem_opts = match &s.opts.data_model {
2441 DataModel::Gc {} => todo!("CM+GC"),
2442 DataModel::LinearMemory(opts) => opts,
2443 };
2444
2445 self.instruction(LocalGet(s.len.idx));
2448 let max = MAX_STRING_BYTE_LENGTH / u32::from(dst);
2449 self.ptr_uconst(mem_opts, max);
2450 self.ptr_gt_u(mem_opts);
2451 self.instruction(If(BlockType::Empty));
2452 self.trap(Trap::StringOutOfBounds);
2453 self.instruction(End);
2454 }
2455
2456 fn transcoder(
2457 &mut self,
2458 src: &WasmString<'_>,
2459 dst: &WasmString<'_>,
2460 op: Transcode,
2461 ) -> FuncIndex {
2462 match (src.opts.data_model, dst.opts.data_model) {
2463 (DataModel::Gc {}, _) | (_, DataModel::Gc {}) => {
2464 todo!("CM+GC")
2465 }
2466 (
2467 DataModel::LinearMemory(LinearMemoryOptions {
2468 memory: Some((src_mem, src_ty)),
2469 realloc: _,
2470 }),
2471 DataModel::LinearMemory(LinearMemoryOptions {
2472 memory: Some((dst_mem, dst_ty)),
2473 realloc: _,
2474 }),
2475 ) => self.module.import_transcoder(Transcoder {
2476 from_memory: src_mem,
2477 from_memory64: src_ty.idx_type == IndexType::I64,
2478 to_memory: dst_mem,
2479 to_memory64: dst_ty.idx_type == IndexType::I64,
2480 op,
2481 }),
2482 (DataModel::LinearMemory(LinearMemoryOptions { memory: None, .. }), _)
2483 | (_, DataModel::LinearMemory(LinearMemoryOptions { memory: None, .. })) => {
2484 unreachable!()
2485 }
2486 }
2487 }
2488
2489 fn begin_translate_sequence<'c>(
2498 &mut self,
2499 src: &Source<'c>,
2500 dst: &Destination<'c>,
2501 src_element_size: u32,
2502 src_element_align: u32,
2503 dst_element_size: u32,
2504 dst_element_align: u32,
2505 ) -> SequenceTranslation<'c> {
2506 let src_mem_opts = match &src.opts().data_model {
2507 DataModel::Gc {} => todo!("CM+GC"),
2508 DataModel::LinearMemory(opts) => opts,
2509 };
2510 let dst_mem_opts = match &dst.opts().data_model {
2511 DataModel::Gc {} => todo!("CM+GC"),
2512 DataModel::LinearMemory(opts) => opts,
2513 };
2514
2515 let src_opts = src.opts();
2516 let dst_opts = dst.opts();
2517
2518 match src {
2523 Source::Stack(s) => {
2524 assert_eq!(s.locals.len(), 2);
2525 self.stack_get(&s.slice(0..1), src_mem_opts.ptr());
2526 self.stack_get(&s.slice(1..2), src_mem_opts.ptr());
2527 }
2528 Source::Memory(mem) => {
2529 self.ptr_load(mem);
2530 self.ptr_load(&mem.bump(src_mem_opts.ptr_size().into()));
2531 }
2532 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
2533 }
2534 let src_len = self.local_set_new_tmp(src_mem_opts.ptr());
2535 let src_ptr = self.local_set_new_tmp(src_mem_opts.ptr());
2536
2537 let src_byte_len =
2539 self.calculate_list_byte_len(src_mem_opts, src_len.idx, src_element_size);
2540 let dst_byte_len = if src_element_size == dst_element_size {
2541 self.convert_src_len_to_dst(src_byte_len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2542 self.local_set_new_tmp(dst_mem_opts.ptr())
2543 } else if src_mem_opts.ptr() == dst_mem_opts.ptr() {
2544 self.calculate_list_byte_len(dst_mem_opts, src_len.idx, dst_element_size)
2545 } else {
2546 self.convert_src_len_to_dst(src_len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2547 let tmp = self.local_set_new_tmp(dst_mem_opts.ptr());
2548 let ret = self.calculate_list_byte_len(dst_mem_opts, tmp.idx, dst_element_size);
2549 self.free_temp_local(tmp);
2550 ret
2551 };
2552
2553 let src_mem = self.memory_operand(
2556 src_opts,
2557 src_ptr,
2558 AllocSize::Local(src_byte_len.idx),
2559 src_element_align,
2560 Trap::ListOutOfBounds,
2561 );
2562
2563 let dst_mem = self.malloc(
2568 dst_opts,
2569 AllocSize::Local(dst_byte_len.idx),
2570 dst_element_align,
2571 Trap::ListOutOfBounds,
2572 );
2573
2574 self.free_temp_local(src_byte_len);
2575 self.free_temp_local(dst_byte_len);
2576
2577 let loop_state = if src_element_size > 0 || dst_element_size > 0 {
2581 self.instruction(Block(BlockType::Empty));
2582
2583 self.instruction(LocalGet(src_len.idx));
2585 let remaining = self.local_tee_new_tmp(src_mem_opts.ptr());
2586 self.ptr_eqz(src_mem_opts);
2587 self.instruction(BrIf(0));
2588
2589 self.instruction(LocalGet(src_mem.addr.idx));
2591 let cur_src_ptr = self.local_set_new_tmp(src_mem_opts.ptr());
2592 self.instruction(LocalGet(dst_mem.addr.idx));
2593 let cur_dst_ptr = self.local_set_new_tmp(dst_mem_opts.ptr());
2594
2595 self.instruction(Loop(BlockType::Empty));
2596
2597 Some(SequenceLoopState {
2598 remaining,
2599 cur_src_ptr,
2600 cur_dst_ptr,
2601 })
2602 } else {
2603 None
2604 };
2605
2606 SequenceTranslation {
2607 src_len,
2608 src_mem,
2609 dst_mem,
2610 src_opts,
2611 dst_opts,
2612 src_mem_opts,
2613 dst_mem_opts,
2614 loop_state,
2615 }
2616 }
2617
2618 fn end_translate_sequence(&mut self, seq: SequenceTranslation<'_>, dst: &Destination) {
2624 if let Some(loop_state) = seq.loop_state {
2625 self.instruction(LocalGet(loop_state.remaining.idx));
2628 self.ptr_iconst(seq.src_mem_opts, -1);
2629 self.ptr_add(seq.src_mem_opts);
2630 self.instruction(LocalTee(loop_state.remaining.idx));
2631 self.ptr_br_if(seq.src_mem_opts, 0);
2632 self.instruction(End); self.instruction(End); self.free_temp_local(loop_state.cur_dst_ptr);
2636 self.free_temp_local(loop_state.cur_src_ptr);
2637 self.free_temp_local(loop_state.remaining);
2638 }
2639
2640 match dst {
2642 Destination::Stack(s, _) => {
2643 self.instruction(LocalGet(seq.dst_mem.addr.idx));
2644 self.stack_set(&s[..1], seq.dst_mem_opts.ptr());
2645 self.convert_src_len_to_dst(
2646 seq.src_len.idx,
2647 seq.src_mem_opts.ptr(),
2648 seq.dst_mem_opts.ptr(),
2649 );
2650 self.stack_set(&s[1..], seq.dst_mem_opts.ptr());
2651 }
2652 Destination::Memory(mem) => {
2653 self.instruction(LocalGet(mem.addr.idx));
2654 self.instruction(LocalGet(seq.dst_mem.addr.idx));
2655 self.ptr_store(mem);
2656 self.instruction(LocalGet(mem.addr.idx));
2657 self.convert_src_len_to_dst(
2658 seq.src_len.idx,
2659 seq.src_mem_opts.ptr(),
2660 seq.dst_mem_opts.ptr(),
2661 );
2662 self.ptr_store(&mem.bump(seq.dst_mem_opts.ptr_size().into()));
2663 }
2664 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
2665 }
2666
2667 self.free_temp_local(seq.src_len);
2668 self.free_temp_local(seq.src_mem.addr);
2669 self.free_temp_local(seq.dst_mem.addr);
2670 }
2671
2672 fn translate_list(
2673 &mut self,
2674 src_ty: TypeListIndex,
2675 src: &Source<'_>,
2676 dst_ty: &InterfaceType,
2677 dst: &Destination,
2678 ) {
2679 let src_mem_opts = match &src.opts().data_model {
2680 DataModel::Gc {} => todo!("CM+GC"),
2681 DataModel::LinearMemory(opts) => opts,
2682 };
2683 let dst_mem_opts = match &dst.opts().data_model {
2684 DataModel::Gc {} => todo!("CM+GC"),
2685 DataModel::LinearMemory(opts) => opts,
2686 };
2687
2688 let src_element_ty = &self.types[src_ty].element;
2689 let dst_element_ty = match dst_ty {
2690 InterfaceType::List(r) => &self.types[*r].element,
2691 _ => panic!("expected a list"),
2692 };
2693 let (src_size, src_align) = self.types.size_align(src_mem_opts, src_element_ty);
2694 let (dst_size, dst_align) = self.types.size_align(dst_mem_opts, dst_element_ty);
2695
2696 let seq = self.begin_translate_sequence(src, dst, src_size, src_align, dst_size, dst_align);
2697
2698 if let Some(ref loop_state) = seq.loop_state {
2699 let element_src = Source::Memory(Memory {
2700 opts: seq.src_opts,
2701 offset: 0,
2702 addr: TempLocal::new(loop_state.cur_src_ptr.idx, loop_state.cur_src_ptr.ty),
2703 });
2704 let element_dst = Destination::Memory(Memory {
2705 opts: seq.dst_opts,
2706 offset: 0,
2707 addr: TempLocal::new(loop_state.cur_dst_ptr.idx, loop_state.cur_dst_ptr.ty),
2708 });
2709 self.translate(src_element_ty, &element_src, dst_element_ty, &element_dst);
2710
2711 if src_size > 0 {
2712 self.instruction(LocalGet(loop_state.cur_src_ptr.idx));
2713 self.ptr_uconst(src_mem_opts, src_size);
2714 self.ptr_add(src_mem_opts);
2715 self.instruction(LocalSet(loop_state.cur_src_ptr.idx));
2716 }
2717 if dst_size > 0 {
2718 self.instruction(LocalGet(loop_state.cur_dst_ptr.idx));
2719 self.ptr_uconst(dst_mem_opts, dst_size);
2720 self.ptr_add(dst_mem_opts);
2721 self.instruction(LocalSet(loop_state.cur_dst_ptr.idx));
2722 }
2723 }
2724
2725 self.end_translate_sequence(seq, dst);
2726 }
2727
2728 fn translate_map(
2734 &mut self,
2735 src_ty: TypeMapIndex,
2736 src: &Source<'_>,
2737 dst_ty: &InterfaceType,
2738 dst: &Destination,
2739 ) {
2740 let src_mem_opts = match &src.opts().data_model {
2741 DataModel::Gc {} => todo!("CM+GC"),
2742 DataModel::LinearMemory(opts) => opts,
2743 };
2744 let dst_mem_opts = match &dst.opts().data_model {
2745 DataModel::Gc {} => todo!("CM+GC"),
2746 DataModel::LinearMemory(opts) => opts,
2747 };
2748
2749 let src_map_ty = &self.types[src_ty];
2750 let dst_map_ty = match dst_ty {
2751 InterfaceType::Map(r) => &self.types[*r],
2752 _ => panic!("expected a map"),
2753 };
2754
2755 let src_key_abi = self.types.canonical_abi(&src_map_ty.key);
2757 let src_value_abi = self.types.canonical_abi(&src_map_ty.value);
2758 let src_entry_abi = CanonicalAbiInfo::record([src_key_abi, src_value_abi].into_iter());
2759 let (src_tuple_size, src_entry_align) = src_mem_opts.sizealign(&src_entry_abi);
2760 let src_value_offset = {
2761 let mut offset = 0u32;
2762 if src_mem_opts.memory64() {
2763 src_key_abi.next_field64(&mut offset);
2764 src_value_abi.next_field64(&mut offset)
2765 } else {
2766 src_key_abi.next_field32(&mut offset);
2767 src_value_abi.next_field32(&mut offset)
2768 }
2769 };
2770
2771 let dst_key_abi = self.types.canonical_abi(&dst_map_ty.key);
2772 let dst_value_abi = self.types.canonical_abi(&dst_map_ty.value);
2773 let dst_entry_abi = CanonicalAbiInfo::record([dst_key_abi, dst_value_abi].into_iter());
2774 let (dst_tuple_size, dst_entry_align) = dst_mem_opts.sizealign(&dst_entry_abi);
2775 let dst_value_offset = {
2776 let mut offset = 0u32;
2777 if dst_mem_opts.memory64() {
2778 dst_key_abi.next_field64(&mut offset);
2779 dst_value_abi.next_field64(&mut offset)
2780 } else {
2781 dst_key_abi.next_field32(&mut offset);
2782 dst_value_abi.next_field32(&mut offset)
2783 }
2784 };
2785
2786 let seq = self.begin_translate_sequence(
2787 src,
2788 dst,
2789 src_tuple_size,
2790 src_entry_align,
2791 dst_tuple_size,
2792 dst_entry_align,
2793 );
2794
2795 if let Some(ref loop_state) = seq.loop_state {
2796 let key_src = Source::Memory(Memory {
2797 opts: seq.src_opts,
2798 offset: 0,
2799 addr: TempLocal::new(loop_state.cur_src_ptr.idx, src_mem_opts.ptr()),
2800 });
2801 let key_dst = Destination::Memory(Memory {
2802 opts: seq.dst_opts,
2803 offset: 0,
2804 addr: TempLocal::new(loop_state.cur_dst_ptr.idx, dst_mem_opts.ptr()),
2805 });
2806 self.translate(&src_map_ty.key, &key_src, &dst_map_ty.key, &key_dst);
2807
2808 let value_src = Source::Memory(Memory {
2809 opts: seq.src_opts,
2810 offset: src_value_offset,
2811 addr: TempLocal::new(loop_state.cur_src_ptr.idx, src_mem_opts.ptr()),
2812 });
2813 let value_dst = Destination::Memory(Memory {
2814 opts: seq.dst_opts,
2815 offset: dst_value_offset,
2816 addr: TempLocal::new(loop_state.cur_dst_ptr.idx, dst_mem_opts.ptr()),
2817 });
2818 self.translate(&src_map_ty.value, &value_src, &dst_map_ty.value, &value_dst);
2819
2820 if src_tuple_size > 0 {
2822 self.instruction(LocalGet(loop_state.cur_src_ptr.idx));
2823 self.ptr_uconst(src_mem_opts, src_tuple_size);
2824 self.ptr_add(src_mem_opts);
2825 self.instruction(LocalSet(loop_state.cur_src_ptr.idx));
2826 }
2827 if dst_tuple_size > 0 {
2828 self.instruction(LocalGet(loop_state.cur_dst_ptr.idx));
2829 self.ptr_uconst(dst_mem_opts, dst_tuple_size);
2830 self.ptr_add(dst_mem_opts);
2831 self.instruction(LocalSet(loop_state.cur_dst_ptr.idx));
2832 }
2833 }
2834
2835 self.end_translate_sequence(seq, dst);
2836 }
2837
2838 fn calculate_list_byte_len(
2839 &mut self,
2840 opts: &LinearMemoryOptions,
2841 len_local: u32,
2842 elt_size: u32,
2843 ) -> TempLocal {
2844 if elt_size == 0 {
2847 self.ptr_uconst(opts, 0);
2848 return self.local_set_new_tmp(opts.ptr());
2849 }
2850
2851 if elt_size == 1 {
2859 if let ValType::I64 = opts.ptr() {
2860 self.instruction(LocalGet(len_local));
2861 self.instruction(I64Const(32));
2862 self.instruction(I64ShrU);
2863 self.instruction(I32WrapI64);
2864 self.instruction(If(BlockType::Empty));
2865 self.trap(Trap::ListOutOfBounds);
2866 self.instruction(End);
2867 }
2868 self.instruction(LocalGet(len_local));
2869 return self.local_set_new_tmp(opts.ptr());
2870 }
2871
2872 self.instruction(Block(BlockType::Empty));
2877 self.instruction(Block(BlockType::Empty));
2878 self.instruction(LocalGet(len_local));
2879 match opts.ptr() {
2880 ValType::I32 => self.instruction(I64ExtendI32U),
2884
2885 ValType::I64 => {
2889 self.instruction(I64Const(32));
2890 self.instruction(I64ShrU);
2891 self.instruction(I32WrapI64);
2892 self.instruction(BrIf(0));
2893 self.instruction(LocalGet(len_local));
2894 }
2895
2896 _ => unreachable!(),
2897 }
2898
2899 self.instruction(I64Const(elt_size.into()));
2908 self.instruction(I64Mul);
2909 let tmp = self.local_tee_new_tmp(ValType::I64);
2910 self.instruction(I64Const(32));
2913 self.instruction(I64ShrU);
2914 self.instruction(I64Eqz);
2915 self.instruction(BrIf(1));
2916 self.instruction(End);
2917 self.trap(Trap::ListOutOfBounds);
2918 self.instruction(End);
2919
2920 if opts.ptr() == ValType::I64 {
2924 tmp
2925 } else {
2926 self.instruction(LocalGet(tmp.idx));
2927 self.instruction(I32WrapI64);
2928 self.free_temp_local(tmp);
2929 self.local_set_new_tmp(ValType::I32)
2930 }
2931 }
2932
2933 fn convert_src_len_to_dst(
2934 &mut self,
2935 src_len_local: u32,
2936 src_ptr_ty: ValType,
2937 dst_ptr_ty: ValType,
2938 ) {
2939 self.instruction(LocalGet(src_len_local));
2940 match (src_ptr_ty, dst_ptr_ty) {
2941 (ValType::I32, ValType::I64) => self.instruction(I64ExtendI32U),
2942 (ValType::I64, ValType::I32) => self.instruction(I32WrapI64),
2943 (src, dst) => assert_eq!(src, dst),
2944 }
2945 }
2946
2947 fn translate_record(
2948 &mut self,
2949 src_ty: TypeRecordIndex,
2950 src: &Source<'_>,
2951 dst_ty: &InterfaceType,
2952 dst: &Destination,
2953 ) {
2954 let src_ty = &self.types[src_ty];
2955 let dst_ty = match dst_ty {
2956 InterfaceType::Record(r) => &self.types[*r],
2957 _ => panic!("expected a record"),
2958 };
2959
2960 assert_eq!(src_ty.fields.len(), dst_ty.fields.len());
2962
2963 let mut src_fields = HashMap::new();
2967 for (i, src) in src
2968 .record_field_srcs(self.types, src_ty.fields.iter().map(|f| f.ty))
2969 .enumerate()
2970 {
2971 let field = &src_ty.fields[i];
2972 src_fields.insert(&field.name, (src, &field.ty));
2973 }
2974
2975 for (i, dst) in dst
2984 .record_field_dsts(self.types, dst_ty.fields.iter().map(|f| f.ty))
2985 .enumerate()
2986 {
2987 let field = &dst_ty.fields[i];
2988 let (src, src_ty) = &src_fields[&field.name];
2989 self.translate(src_ty, src, &field.ty, &dst);
2990 }
2991 }
2992
2993 fn translate_flags(
2994 &mut self,
2995 src_ty: TypeFlagsIndex,
2996 src: &Source<'_>,
2997 dst_ty: &InterfaceType,
2998 dst: &Destination,
2999 ) {
3000 let src_ty = &self.types[src_ty];
3001 let dst_ty = match dst_ty {
3002 InterfaceType::Flags(r) => &self.types[*r],
3003 _ => panic!("expected a record"),
3004 };
3005
3006 assert_eq!(src_ty.names, dst_ty.names);
3014 let cnt = src_ty.names.len();
3015 match FlagsSize::from_count(cnt) {
3016 FlagsSize::Size0 => {}
3017 FlagsSize::Size1 => {
3018 let mask = if cnt == 8 { 0xff } else { (1 << cnt) - 1 };
3019 self.convert_u8_mask(src, dst, mask);
3020 }
3021 FlagsSize::Size2 => {
3022 let mask = if cnt == 16 { 0xffff } else { (1 << cnt) - 1 };
3023 self.convert_u16_mask(src, dst, mask);
3024 }
3025 FlagsSize::Size4Plus(n) => {
3026 let srcs = src.record_field_srcs(self.types, (0..n).map(|_| InterfaceType::U32));
3027 let dsts = dst.record_field_dsts(self.types, (0..n).map(|_| InterfaceType::U32));
3028 let n = usize::from(n);
3029 for (i, (src, dst)) in srcs.zip(dsts).enumerate() {
3030 let mask = if i == n - 1 && (cnt % 32 != 0) {
3031 (1 << (cnt % 32)) - 1
3032 } else {
3033 0xffffffff
3034 };
3035 self.convert_u32_mask(&src, &dst, mask);
3036 }
3037 }
3038 }
3039 }
3040
3041 fn translate_tuple(
3042 &mut self,
3043 src_ty: TypeTupleIndex,
3044 src: &Source<'_>,
3045 dst_ty: &InterfaceType,
3046 dst: &Destination,
3047 ) {
3048 let src_ty = &self.types[src_ty];
3049 let dst_ty = match dst_ty {
3050 InterfaceType::Tuple(t) => &self.types[*t],
3051 _ => panic!("expected a tuple"),
3052 };
3053
3054 assert_eq!(src_ty.types.len(), dst_ty.types.len());
3056
3057 let srcs = src
3058 .record_field_srcs(self.types, src_ty.types.iter().copied())
3059 .zip(src_ty.types.iter());
3060 let dsts = dst
3061 .record_field_dsts(self.types, dst_ty.types.iter().copied())
3062 .zip(dst_ty.types.iter());
3063 for ((src, src_ty), (dst, dst_ty)) in srcs.zip(dsts) {
3064 self.translate(src_ty, &src, dst_ty, &dst);
3065 }
3066 }
3067
3068 fn translate_fixed_length_list(
3069 &mut self,
3070 src_ty: TypeFixedLengthListIndex,
3071 src: &Source<'_>,
3072 dst_ty: &InterfaceType,
3073 dst: &Destination,
3074 ) {
3075 let src_ty = &self.types[src_ty];
3076 let dst_ty = match dst_ty {
3077 InterfaceType::FixedLengthList(t) => &self.types[*t],
3078 _ => panic!("expected a fixed size list"),
3079 };
3080
3081 assert_eq!(src_ty.size, dst_ty.size);
3083
3084 match (&src, &dst) {
3085 (Source::Memory(src_mem), Destination::Memory(dst_mem)) => {
3087 let src_mem_opts = match &src_mem.opts.data_model {
3088 DataModel::Gc {} => todo!("CM+GC"),
3089 DataModel::LinearMemory(opts) => opts,
3090 };
3091 let dst_mem_opts = match &dst_mem.opts.data_model {
3092 DataModel::Gc {} => todo!("CM+GC"),
3093 DataModel::LinearMemory(opts) => opts,
3094 };
3095 let src_element_bytes = self.types.size_align(src_mem_opts, &src_ty.element).0;
3096 let dst_element_bytes = self.types.size_align(dst_mem_opts, &dst_ty.element).0;
3097 assert_ne!(src_element_bytes, 0);
3098 assert_ne!(dst_element_bytes, 0);
3099
3100 self.instruction(LocalGet(src_mem.addr.idx));
3103 if src_mem.offset != 0 {
3104 self.ptr_uconst(src_mem_opts, src_mem.offset);
3105 self.ptr_add(src_mem_opts);
3106 }
3107 let cur_src_ptr = self.local_set_new_tmp(src_mem_opts.ptr());
3108 self.instruction(LocalGet(dst_mem.addr.idx));
3109 if dst_mem.offset != 0 {
3110 self.ptr_uconst(dst_mem_opts, dst_mem.offset);
3111 self.ptr_add(dst_mem_opts);
3112 }
3113 let cur_dst_ptr = self.local_set_new_tmp(dst_mem_opts.ptr());
3114
3115 self.instruction(I32Const(src_ty.size as i32));
3116 let remaining = self.local_set_new_tmp(ValType::I32);
3117
3118 self.instruction(Loop(BlockType::Empty));
3119
3120 let element_src = Source::Memory(Memory {
3122 opts: src_mem.opts,
3123 offset: 0,
3124 addr: TempLocal::new(cur_src_ptr.idx, cur_src_ptr.ty),
3125 });
3126 let element_dst = Destination::Memory(Memory {
3127 opts: dst_mem.opts,
3128 offset: 0,
3129 addr: TempLocal::new(cur_dst_ptr.idx, cur_dst_ptr.ty),
3130 });
3131 self.translate(&src_ty.element, &element_src, &dst_ty.element, &element_dst);
3132
3133 self.instruction(LocalGet(cur_src_ptr.idx));
3135 self.ptr_uconst(src_mem_opts, src_element_bytes);
3136 self.ptr_add(src_mem_opts);
3137 self.instruction(LocalSet(cur_src_ptr.idx));
3138 self.instruction(LocalGet(cur_dst_ptr.idx));
3139 self.ptr_uconst(dst_mem_opts, dst_element_bytes);
3140 self.ptr_add(dst_mem_opts);
3141 self.instruction(LocalSet(cur_dst_ptr.idx));
3142
3143 self.instruction(LocalGet(remaining.idx));
3146 self.ptr_iconst(src_mem_opts, -1);
3147 self.ptr_add(src_mem_opts);
3148 self.instruction(LocalTee(remaining.idx));
3149 self.ptr_br_if(src_mem_opts, 0);
3150 self.instruction(End); self.free_temp_local(cur_dst_ptr);
3153 self.free_temp_local(cur_src_ptr);
3154 self.free_temp_local(remaining);
3155 return;
3156 }
3157 (_, _) => {
3159 assert!(
3161 src_ty.size as usize <= MAX_FLAT_PARAMS
3162 && dst_ty.size as usize <= MAX_FLAT_PARAMS
3163 );
3164 let srcs =
3165 src.record_field_srcs(self.types, (0..src_ty.size).map(|_| src_ty.element));
3166 let dsts =
3167 dst.record_field_dsts(self.types, (0..dst_ty.size).map(|_| dst_ty.element));
3168 for (src, dst) in srcs.zip(dsts) {
3169 self.translate(&src_ty.element, &src, &dst_ty.element, &dst);
3170 }
3171 }
3172 }
3173 }
3174
3175 fn translate_variant(
3176 &mut self,
3177 src_ty: TypeVariantIndex,
3178 src: &Source<'_>,
3179 dst_ty: &InterfaceType,
3180 dst: &Destination,
3181 ) {
3182 let src_ty = &self.types[src_ty];
3183 let dst_ty = match dst_ty {
3184 InterfaceType::Variant(t) => &self.types[*t],
3185 _ => panic!("expected a variant"),
3186 };
3187
3188 let src_info = variant_info(self.types, src_ty.cases.iter().map(|(_, c)| c.as_ref()));
3189 let dst_info = variant_info(self.types, dst_ty.cases.iter().map(|(_, c)| c.as_ref()));
3190
3191 let iter = src_ty
3192 .cases
3193 .iter()
3194 .enumerate()
3195 .map(|(src_i, (src_case, src_case_ty))| {
3196 let dst_i = dst_ty
3197 .cases
3198 .iter()
3199 .position(|(c, _)| c == src_case)
3200 .unwrap();
3201 let dst_case_ty = &dst_ty.cases[dst_i];
3202 let src_i = u32::try_from(src_i).unwrap();
3203 let dst_i = u32::try_from(dst_i).unwrap();
3204 VariantCase {
3205 src_i,
3206 src_ty: src_case_ty.as_ref(),
3207 dst_i,
3208 dst_ty: dst_case_ty.as_ref(),
3209 }
3210 });
3211 self.convert_variant(src, &src_info, dst, &dst_info, iter);
3212 }
3213
3214 fn translate_enum(
3215 &mut self,
3216 src_ty: TypeEnumIndex,
3217 src: &Source<'_>,
3218 dst_ty: &InterfaceType,
3219 dst: &Destination,
3220 ) {
3221 let src_ty = &self.types[src_ty];
3222 let dst_ty = match dst_ty {
3223 InterfaceType::Enum(t) => &self.types[*t],
3224 _ => panic!("expected an option"),
3225 };
3226
3227 debug_assert_eq!(src_ty.info.size, dst_ty.info.size);
3228 debug_assert_eq!(src_ty.names.len(), dst_ty.names.len());
3229 debug_assert!(
3230 src_ty
3231 .names
3232 .iter()
3233 .zip(dst_ty.names.iter())
3234 .all(|(a, b)| a == b)
3235 );
3236
3237 match src {
3239 Source::Stack(s) => self.stack_get(&s.slice(0..1), ValType::I32),
3240 Source::Memory(mem) => match src_ty.info.size {
3241 DiscriminantSize::Size1 => self.i32_load8u(mem),
3242 DiscriminantSize::Size2 => self.i32_load16u(mem),
3243 DiscriminantSize::Size4 => self.i32_load(mem),
3244 },
3245 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
3246 }
3247 let tmp = self.local_tee_new_tmp(ValType::I32);
3248
3249 self.instruction(I32Const(i32::try_from(src_ty.names.len()).unwrap()));
3251 self.instruction(I32GeU);
3252 self.instruction(If(BlockType::Empty));
3253 self.trap(Trap::InvalidDiscriminant);
3254 self.instruction(End);
3255
3256 match dst {
3258 Destination::Stack(stack, _) => {
3259 self.local_get_tmp(&tmp);
3260 self.stack_set(&stack[..1], ValType::I32)
3261 }
3262 Destination::Memory(mem) => {
3263 self.push_dst_addr(dst);
3264 self.local_get_tmp(&tmp);
3265 match dst_ty.info.size {
3266 DiscriminantSize::Size1 => self.i32_store8(mem),
3267 DiscriminantSize::Size2 => self.i32_store16(mem),
3268 DiscriminantSize::Size4 => self.i32_store(mem),
3269 }
3270 }
3271 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
3272 }
3273 self.free_temp_local(tmp);
3274 }
3275
3276 fn translate_option(
3277 &mut self,
3278 src_ty: TypeOptionIndex,
3279 src: &Source<'_>,
3280 dst_ty: &InterfaceType,
3281 dst: &Destination,
3282 ) {
3283 let src_ty = &self.types[src_ty].ty;
3284 let dst_ty = match dst_ty {
3285 InterfaceType::Option(t) => &self.types[*t].ty,
3286 _ => panic!("expected an option"),
3287 };
3288 let src_ty = Some(src_ty);
3289 let dst_ty = Some(dst_ty);
3290
3291 let src_info = variant_info(self.types, [None, src_ty]);
3292 let dst_info = variant_info(self.types, [None, dst_ty]);
3293
3294 self.convert_variant(
3295 src,
3296 &src_info,
3297 dst,
3298 &dst_info,
3299 [
3300 VariantCase {
3301 src_i: 0,
3302 dst_i: 0,
3303 src_ty: None,
3304 dst_ty: None,
3305 },
3306 VariantCase {
3307 src_i: 1,
3308 dst_i: 1,
3309 src_ty,
3310 dst_ty,
3311 },
3312 ]
3313 .into_iter(),
3314 );
3315 }
3316
3317 fn translate_result(
3318 &mut self,
3319 src_ty: TypeResultIndex,
3320 src: &Source<'_>,
3321 dst_ty: &InterfaceType,
3322 dst: &Destination,
3323 ) {
3324 let src_ty = &self.types[src_ty];
3325 let dst_ty = match dst_ty {
3326 InterfaceType::Result(t) => &self.types[*t],
3327 _ => panic!("expected a result"),
3328 };
3329
3330 let src_info = variant_info(self.types, [src_ty.ok.as_ref(), src_ty.err.as_ref()]);
3331 let dst_info = variant_info(self.types, [dst_ty.ok.as_ref(), dst_ty.err.as_ref()]);
3332
3333 self.convert_variant(
3334 src,
3335 &src_info,
3336 dst,
3337 &dst_info,
3338 [
3339 VariantCase {
3340 src_i: 0,
3341 dst_i: 0,
3342 src_ty: src_ty.ok.as_ref(),
3343 dst_ty: dst_ty.ok.as_ref(),
3344 },
3345 VariantCase {
3346 src_i: 1,
3347 dst_i: 1,
3348 src_ty: src_ty.err.as_ref(),
3349 dst_ty: dst_ty.err.as_ref(),
3350 },
3351 ]
3352 .into_iter(),
3353 );
3354 }
3355
3356 fn convert_variant<'c>(
3357 &mut self,
3358 src: &Source<'_>,
3359 src_info: &VariantInfo,
3360 dst: &Destination,
3361 dst_info: &VariantInfo,
3362 src_cases: impl ExactSizeIterator<Item = VariantCase<'c>>,
3363 ) {
3364 let outer_block_ty = match dst {
3367 Destination::Stack(dst_flat, _) => match dst_flat.len() {
3368 0 => BlockType::Empty,
3369 1 => BlockType::Result(dst_flat[0]),
3370 _ => {
3371 let ty = self.module.core_types.function(&[], &dst_flat);
3372 BlockType::FunctionType(ty)
3373 }
3374 },
3375 Destination::Memory(_) => BlockType::Empty,
3376 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
3377 };
3378 self.instruction(Block(outer_block_ty));
3379
3380 let src_cases_len = src_cases.len();
3383 for _ in 0..src_cases_len - 1 {
3384 self.instruction(Block(BlockType::Empty));
3385 }
3386
3387 self.instruction(Block(BlockType::Empty));
3389
3390 self.instruction(Block(BlockType::Empty));
3393
3394 match src {
3396 Source::Stack(s) => self.stack_get(&s.slice(0..1), ValType::I32),
3397 Source::Memory(mem) => match src_info.size {
3398 DiscriminantSize::Size1 => self.i32_load8u(mem),
3399 DiscriminantSize::Size2 => self.i32_load16u(mem),
3400 DiscriminantSize::Size4 => self.i32_load(mem),
3401 },
3402 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
3403 }
3404
3405 let mut targets = Vec::new();
3408 for i in 0..src_cases_len {
3409 targets.push((i + 1) as u32);
3410 }
3411 self.instruction(BrTable(targets[..].into(), 0));
3412 self.instruction(End); self.trap(Trap::InvalidDiscriminant);
3415 self.instruction(End); let src_cases_len = u32::try_from(src_cases_len).unwrap();
3422 for case in src_cases {
3423 let VariantCase {
3424 src_i,
3425 src_ty,
3426 dst_i,
3427 dst_ty,
3428 } = case;
3429
3430 self.push_dst_addr(dst);
3433 self.instruction(I32Const(dst_i as i32));
3434 match dst {
3435 Destination::Stack(stack, _) => self.stack_set(&stack[..1], ValType::I32),
3436 Destination::Memory(mem) => match dst_info.size {
3437 DiscriminantSize::Size1 => self.i32_store8(mem),
3438 DiscriminantSize::Size2 => self.i32_store16(mem),
3439 DiscriminantSize::Size4 => self.i32_store(mem),
3440 },
3441 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
3442 }
3443
3444 let src_payload = src.payload_src(self.types, src_info, src_ty);
3445 let dst_payload = dst.payload_dst(self.types, dst_info, dst_ty);
3446
3447 match (src_ty, dst_ty) {
3450 (Some(src_ty), Some(dst_ty)) => {
3451 self.translate(src_ty, &src_payload, dst_ty, &dst_payload);
3452 }
3453 (None, None) => {}
3454 _ => unimplemented!(),
3455 }
3456
3457 if let Destination::Stack(payload_results, _) = dst_payload {
3464 if let Destination::Stack(dst_results, _) = dst {
3465 let remaining = &dst_results[1..][payload_results.len()..];
3466 for ty in remaining {
3467 match ty {
3468 ValType::I32 => self.instruction(I32Const(0)),
3469 ValType::I64 => self.instruction(I64Const(0)),
3470 ValType::F32 => self.instruction(F32Const(0.0.into())),
3471 ValType::F64 => self.instruction(F64Const(0.0.into())),
3472 _ => unreachable!(),
3473 }
3474 }
3475 }
3476 }
3477
3478 if src_i != src_cases_len - 1 {
3481 self.instruction(Br(src_cases_len - src_i - 1));
3482 }
3483 self.instruction(End); }
3485 }
3486
3487 fn translate_future(
3488 &mut self,
3489 src_ty: TypeFutureTableIndex,
3490 src: &Source<'_>,
3491 dst_ty: &InterfaceType,
3492 dst: &Destination,
3493 ) {
3494 let dst_ty = match dst_ty {
3495 InterfaceType::Future(t) => *t,
3496 _ => panic!("expected a `Future`"),
3497 };
3498 let transfer = self.module.import_future_transfer();
3499 self.translate_handle(src_ty.as_u32(), src, dst_ty.as_u32(), dst, transfer);
3500 }
3501
3502 fn translate_stream(
3503 &mut self,
3504 src_ty: TypeStreamTableIndex,
3505 src: &Source<'_>,
3506 dst_ty: &InterfaceType,
3507 dst: &Destination,
3508 ) {
3509 let dst_ty = match dst_ty {
3510 InterfaceType::Stream(t) => *t,
3511 _ => panic!("expected a `Stream`"),
3512 };
3513 let transfer = self.module.import_stream_transfer();
3514 self.translate_handle(src_ty.as_u32(), src, dst_ty.as_u32(), dst, transfer);
3515 }
3516
3517 fn translate_error_context(
3518 &mut self,
3519 src_ty: TypeComponentLocalErrorContextTableIndex,
3520 src: &Source<'_>,
3521 dst_ty: &InterfaceType,
3522 dst: &Destination,
3523 ) {
3524 let dst_ty = match dst_ty {
3525 InterfaceType::ErrorContext(t) => *t,
3526 _ => panic!("expected an `ErrorContext`"),
3527 };
3528 let transfer = self.module.import_error_context_transfer();
3529 self.translate_handle(src_ty.as_u32(), src, dst_ty.as_u32(), dst, transfer);
3530 }
3531
3532 fn translate_own(
3533 &mut self,
3534 src_ty: TypeResourceTableIndex,
3535 src: &Source<'_>,
3536 dst_ty: &InterfaceType,
3537 dst: &Destination,
3538 ) {
3539 let dst_ty = match dst_ty {
3540 InterfaceType::Own(t) => *t,
3541 _ => panic!("expected an `Own`"),
3542 };
3543 let transfer = self.module.import_resource_transfer_own();
3544 self.translate_handle(src_ty.as_u32(), src, dst_ty.as_u32(), dst, transfer);
3545 }
3546
3547 fn translate_borrow(
3548 &mut self,
3549 src_ty: TypeResourceTableIndex,
3550 src: &Source<'_>,
3551 dst_ty: &InterfaceType,
3552 dst: &Destination,
3553 ) {
3554 let dst_ty = match dst_ty {
3555 InterfaceType::Borrow(t) => *t,
3556 _ => panic!("expected an `Borrow`"),
3557 };
3558
3559 let transfer = self.module.import_resource_transfer_borrow();
3560 self.translate_handle(src_ty.as_u32(), src, dst_ty.as_u32(), dst, transfer);
3561 }
3562
3563 fn translate_handle(
3571 &mut self,
3572 src_ty: u32,
3573 src: &Source<'_>,
3574 dst_ty: u32,
3575 dst: &Destination,
3576 transfer: FuncIndex,
3577 ) {
3578 self.push_dst_addr(dst);
3579 match src {
3580 Source::Memory(mem) => self.i32_load(mem),
3581 Source::Stack(stack) => self.stack_get(stack, ValType::I32),
3582 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
3583 }
3584 self.instruction(I32Const(src_ty as i32));
3585 self.instruction(I32Const(dst_ty as i32));
3586 self.instruction(Call(transfer.as_u32()));
3587 match dst {
3588 Destination::Memory(mem) => self.i32_store(mem),
3589 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
3590 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
3591 }
3592 }
3593
3594 fn trap_if_not_may_leave(&mut self, flags_global: GlobalIndex, trap: Trap) -> TempLocal {
3601 self.instruction(Block(BlockType::Empty));
3602 self.instruction(GlobalGet(flags_global.as_u32()));
3603 let saved = self.local_tee_new_tmp(ValType::I32);
3606 self.instruction(BrIf(0));
3607 self.trap(trap);
3608 self.instruction(End);
3609 saved
3610 }
3611
3612 fn clear_may_leave(&mut self, flags_global: GlobalIndex) -> TempLocal {
3615 self.instruction(GlobalGet(flags_global.as_u32()));
3616 let saved = self.local_set_new_tmp(ValType::I32);
3617 self.set_may_leave_false(flags_global);
3618 saved
3619 }
3620
3621 fn set_may_leave_false(&mut self, flags_global: GlobalIndex) {
3626 self.instruction(I32Const(0));
3627 self.instruction(GlobalSet(flags_global.as_u32()));
3628 }
3629
3630 fn restore_may_leave(&mut self, flags_global: GlobalIndex, saved: TempLocal) {
3643 self.instruction(LocalGet(saved.idx));
3644 self.instruction(GlobalSet(flags_global.as_u32()));
3645 self.free_temp_local(saved);
3646 }
3647
3648 fn assert_aligned(&mut self, ty: &InterfaceType, mem: &Memory) {
3649 let mem_opts = mem.mem_opts();
3650 if !self.module.tunables.debug_adapter_modules {
3651 return;
3652 }
3653 let align = self.types.align(mem_opts, ty);
3654 if align == 1 {
3655 return;
3656 }
3657 assert!(align.is_power_of_two());
3658 self.instruction(LocalGet(mem.addr.idx));
3659 self.ptr_uconst(mem_opts, mem.offset);
3660 self.ptr_add(mem_opts);
3661 self.ptr_uconst(mem_opts, align - 1);
3662 self.ptr_and(mem_opts);
3663 self.ptr_if(mem_opts, BlockType::Empty);
3664 self.trap(Trap::DebugAssertPointerAligned);
3665 self.instruction(End);
3666 }
3667
3668 fn malloc_abi<'c>(
3674 &mut self,
3675 opts: &'c Options,
3676 abi: &CanonicalAbiInfo,
3677 oob_trap: Trap,
3678 ) -> Memory<'c> {
3679 match &opts.data_model {
3680 DataModel::Gc {} => todo!("CM+GC"),
3681 DataModel::LinearMemory(mem_opts) => {
3682 let (size, align) = mem_opts.sizealign(abi);
3683 let size = AllocSize::Const(size);
3684 self.malloc(opts, size, align, oob_trap)
3685 }
3686 }
3687 }
3688
3689 fn malloc<'c>(
3695 &mut self,
3696 opts: &'c Options,
3697 size: AllocSize,
3698 align: u32,
3699 oob_trap: Trap,
3700 ) -> Memory<'c> {
3701 match &opts.data_model {
3702 DataModel::Gc {} => todo!("CM+GC"),
3703 DataModel::LinearMemory(mem_opts) => {
3704 let realloc = mem_opts.realloc.unwrap();
3705 self.ptr_uconst(mem_opts, 0);
3706 self.ptr_uconst(mem_opts, 0);
3707 self.ptr_uconst(mem_opts, align);
3708 self.alloc_size(mem_opts, &size);
3709 self.call_realloc(realloc);
3710 let addr = self.local_set_new_tmp(mem_opts.ptr());
3711 self.memory_operand(opts, addr, size, align, oob_trap)
3712 }
3713 }
3714 }
3715
3716 fn realloc(
3722 &mut self,
3723 opts: &Options,
3724 ptr: &TempLocal,
3725 prev_size: AllocSize,
3726 size: AllocSize,
3727 align: u32,
3728 oob_trap: Trap,
3729 ) {
3730 match &opts.data_model {
3731 DataModel::Gc {} => todo!("CM+GC"),
3732 DataModel::LinearMemory(mem_opts) => {
3733 let realloc = mem_opts.realloc.unwrap();
3734 self.instruction(LocalGet(ptr.idx));
3735 self.alloc_size(mem_opts, &prev_size);
3736 self.ptr_uconst(mem_opts, align);
3737 self.alloc_size(mem_opts, &size);
3738 self.call_realloc(realloc);
3739 self.instruction(LocalSet(ptr.idx));
3740 self.validate_guest_pointer(opts, &ptr, &size, align, oob_trap)
3741 }
3742 }
3743 }
3744
3745 fn memory_operand_abi<'c>(
3748 &mut self,
3749 opts: &'c Options,
3750 addr: TempLocal,
3751 abi: &CanonicalAbiInfo,
3752 oob_trap: Trap,
3753 ) -> Memory<'c> {
3754 match &opts.data_model {
3755 DataModel::Gc {} => todo!("CM+GC"),
3756 DataModel::LinearMemory(mem_opts) => {
3757 let (size, align) = mem_opts.sizealign(abi);
3758 self.memory_operand(opts, addr, AllocSize::Const(size), align, oob_trap)
3759 }
3760 }
3761 }
3762
3763 fn memory_operand<'c>(
3766 &mut self,
3767 opts: &'c Options,
3768 addr: TempLocal,
3769 size: AllocSize,
3770 align: u32,
3771 oob_trap: Trap,
3772 ) -> Memory<'c> {
3773 self.validate_guest_pointer(opts, &addr, &size, align, oob_trap);
3774 Memory {
3775 addr,
3776 opts,
3777 offset: 0,
3778 }
3779 }
3780
3781 fn validate_guest_pointer(
3789 &mut self,
3790 opts: &Options,
3791 addr: &TempLocal,
3792 size: &AllocSize,
3793 align: u32,
3794 oob_trap: Trap,
3795 ) {
3796 let mem_opts = match &opts.data_model {
3797 DataModel::Gc {} => todo!("CM+GC"),
3798 DataModel::LinearMemory(mem_opts) => mem_opts,
3799 };
3800
3801 if align != 1 {
3804 self.instruction(LocalGet(addr.idx));
3805 assert!(align.is_power_of_two());
3806 self.ptr_uconst(mem_opts, align - 1);
3807 self.ptr_and(mem_opts);
3808 self.ptr_if(mem_opts, BlockType::Empty);
3809 self.trap(Trap::UnalignedPointer);
3810 self.instruction(End);
3811 }
3812
3813 let extend_to_64 = |me: &mut Self| {
3814 if !mem_opts.memory64() {
3815 me.instruction(I64ExtendI32U);
3816 }
3817 };
3818
3819 self.instruction(Block(BlockType::Empty));
3820 self.instruction(Block(BlockType::Empty));
3821 let (memory, ty) = mem_opts.memory.unwrap();
3822
3823 self.instruction(MemorySize(memory.as_u32()));
3828 extend_to_64(self);
3829 self.instruction(I64Const(ty.page_size_log2.into()));
3830 self.instruction(I64Shl);
3831
3832 self.instruction(LocalGet(addr.idx));
3837 extend_to_64(self);
3838 self.alloc_size(mem_opts, size);
3839 extend_to_64(self);
3840 self.instruction(I64Add);
3841 if mem_opts.memory64() {
3842 let tmp = self.local_tee_new_tmp(ValType::I64);
3843 self.instruction(LocalGet(addr.idx));
3844 self.ptr_lt_u(mem_opts);
3845 self.instruction(BrIf(0));
3846 self.instruction(LocalGet(tmp.idx));
3847 self.free_temp_local(tmp);
3848 }
3849
3850 self.instruction(I64GeU);
3854 self.instruction(BrIf(1));
3855
3856 self.instruction(End);
3857 self.trap(oob_trap);
3858 self.instruction(End);
3859 }
3860
3861 fn local_tee_new_tmp(&mut self, ty: ValType) -> TempLocal {
3867 self.gen_temp_local(ty, LocalTee)
3868 }
3869
3870 fn local_set_new_tmp(&mut self, ty: ValType) -> TempLocal {
3873 self.gen_temp_local(ty, LocalSet)
3874 }
3875
3876 fn local_get_tmp(&mut self, local: &TempLocal) {
3877 self.instruction(LocalGet(local.idx));
3878 }
3879
3880 fn gen_temp_local(&mut self, ty: ValType, insn: fn(u32) -> Instruction<'static>) -> TempLocal {
3881 if let Some(idx) = self.free_locals.get_mut(&ty).and_then(|v| v.pop()) {
3884 self.instruction(insn(idx));
3885 return TempLocal {
3886 ty,
3887 idx,
3888 needs_free: true,
3889 };
3890 }
3891
3892 let locals = &mut self.module.funcs[self.result].locals;
3894 match locals.last_mut() {
3895 Some((cnt, prev_ty)) if ty == *prev_ty => *cnt += 1,
3896 _ => locals.push((1, ty)),
3897 }
3898 self.nlocals += 1;
3899 let idx = self.nlocals - 1;
3900 self.instruction(insn(idx));
3901 TempLocal {
3902 ty,
3903 idx,
3904 needs_free: true,
3905 }
3906 }
3907
3908 fn free_temp_local(&mut self, mut local: TempLocal) {
3911 assert!(local.needs_free);
3912 self.free_locals
3913 .entry(local.ty)
3914 .or_insert(Vec::new())
3915 .push(local.idx);
3916 local.needs_free = false;
3917 }
3918
3919 fn save_context(&mut self) -> Vec<TempLocal> {
3922 if !self.module.tunables.concurrency_support {
3923 return Vec::new();
3924 }
3925 let mut saved = Vec::new();
3926 for slot in 0..NUM_COMPONENT_CONTEXT_SLOTS {
3927 let get = self.module.import_context_get(slot);
3928 self.instruction(Call(get.as_u32()));
3929 saved.push(self.local_set_new_tmp(ValType::I32));
3930 }
3931 saved
3932 }
3933
3934 fn clear_context(&mut self) {
3936 if !self.module.tunables.concurrency_support {
3937 return;
3938 }
3939 for slot in 0..NUM_COMPONENT_CONTEXT_SLOTS {
3940 let set = self.module.import_context_set(slot);
3941 self.instruction(I32Const(0));
3942 self.instruction(Call(set.as_u32()));
3943 }
3944 }
3945
3946 fn restore_context(&mut self, saved: Vec<TempLocal>) {
3949 for (slot, local) in saved.into_iter().enumerate() {
3950 let set = self.module.import_context_set(slot);
3951 self.instruction(LocalGet(local.idx));
3952 self.instruction(Call(set.as_u32()));
3953 self.free_temp_local(local);
3954 }
3955 }
3956
3957 fn call_realloc(&mut self, realloc: FuncIndex) {
3963 let saved = self.save_context();
3964 self.clear_context();
3965 self.instruction(Call(realloc.as_u32()));
3966 self.restore_context(saved);
3967 }
3968
3969 fn instruction(&mut self, instr: Instruction) {
3970 instr.encode(&mut self.code);
3971 }
3972
3973 fn trap(&mut self, trap: Trap) {
3974 let trap_func = self.module.import_trap(trap);
3975 self.instruction(Call(trap_func.as_u32()));
3976 self.instruction(Unreachable);
3977 }
3978
3979 fn enter_exception_barrier(&mut self, results: &[ValType]) {
4010 if !self.module.features.exceptions() {
4011 return;
4012 }
4013 let block_ty = match results.len() {
4014 0 => BlockType::Empty,
4015 1 => BlockType::Result(results[0]),
4016 _ => BlockType::FunctionType(self.module.core_types.function(&[], results)),
4017 };
4018 self.instruction(Block(block_ty));
4020 self.instruction(Block(BlockType::Empty));
4022 self.instruction(TryTable(block_ty, vec![Catch::All { label: 0 }].into()));
4023 }
4024
4025 fn exit_exception_barrier(&mut self) {
4030 if !self.module.features.exceptions() {
4031 return;
4032 }
4033 self.instruction(End);
4035 self.instruction(Br(1));
4037 self.instruction(End);
4039 self.trap(Trap::UncaughtException);
4040 self.instruction(End);
4042 }
4043
4044 fn flush_code(&mut self) {
4049 if self.code.is_empty() {
4050 return;
4051 }
4052 self.module.funcs[self.result]
4053 .body
4054 .push(Body::Raw(mem::take(&mut self.code)));
4055 }
4056
4057 fn finish(mut self) {
4058 self.instruction(End);
4061 self.flush_code();
4062
4063 self.module.funcs[self.result].filled_in = true;
4066 }
4067
4068 fn stack_get(&mut self, stack: &Stack<'_>, dst_ty: ValType) {
4076 assert_eq!(stack.locals.len(), 1);
4077 let (idx, src_ty) = stack.locals[0];
4078 self.instruction(LocalGet(idx));
4079 match (src_ty, dst_ty) {
4080 (ValType::I32, ValType::I32)
4081 | (ValType::I64, ValType::I64)
4082 | (ValType::F32, ValType::F32)
4083 | (ValType::F64, ValType::F64) => {}
4084
4085 (ValType::I32, ValType::F32) => self.instruction(F32ReinterpretI32),
4086 (ValType::I64, ValType::I32) => {
4087 self.assert_i64_upper_bits_not_set(idx);
4088 self.instruction(I32WrapI64);
4089 }
4090 (ValType::I64, ValType::F64) => self.instruction(F64ReinterpretI64),
4091 (ValType::I64, ValType::F32) => {
4092 self.assert_i64_upper_bits_not_set(idx);
4093 self.instruction(I32WrapI64);
4094 self.instruction(F32ReinterpretI32);
4095 }
4096
4097 (ValType::I32, ValType::I64)
4099 | (ValType::I32, ValType::F64)
4100 | (ValType::F32, ValType::I32)
4101 | (ValType::F32, ValType::I64)
4102 | (ValType::F32, ValType::F64)
4103 | (ValType::F64, ValType::I32)
4104 | (ValType::F64, ValType::I64)
4105 | (ValType::F64, ValType::F32)
4106
4107 | (ValType::Ref(_), _)
4109 | (_, ValType::Ref(_))
4110 | (ValType::V128, _)
4111 | (_, ValType::V128) => {
4112 panic!("cannot get {dst_ty:?} from {src_ty:?} local");
4113 }
4114 }
4115 }
4116
4117 fn assert_i64_upper_bits_not_set(&mut self, local: u32) {
4118 if !self.module.tunables.debug_adapter_modules {
4119 return;
4120 }
4121 self.instruction(LocalGet(local));
4122 self.instruction(I64Const(32));
4123 self.instruction(I64ShrU);
4124 self.instruction(I32WrapI64);
4125 self.instruction(If(BlockType::Empty));
4126 self.trap(Trap::DebugAssertUpperBitsUnset);
4127 self.instruction(End);
4128 }
4129
4130 fn stack_set(&mut self, dst_tys: &[ValType], src_ty: ValType) {
4136 assert_eq!(dst_tys.len(), 1);
4137 let dst_ty = dst_tys[0];
4138 match (src_ty, dst_ty) {
4139 (ValType::I32, ValType::I32)
4140 | (ValType::I64, ValType::I64)
4141 | (ValType::F32, ValType::F32)
4142 | (ValType::F64, ValType::F64) => {}
4143
4144 (ValType::F32, ValType::I32) => self.instruction(I32ReinterpretF32),
4145 (ValType::I32, ValType::I64) => self.instruction(I64ExtendI32U),
4146 (ValType::F64, ValType::I64) => self.instruction(I64ReinterpretF64),
4147 (ValType::F32, ValType::I64) => {
4148 self.instruction(I32ReinterpretF32);
4149 self.instruction(I64ExtendI32U);
4150 }
4151
4152 (ValType::I64, ValType::I32)
4154 | (ValType::F64, ValType::I32)
4155 | (ValType::I32, ValType::F32)
4156 | (ValType::I64, ValType::F32)
4157 | (ValType::F64, ValType::F32)
4158 | (ValType::I32, ValType::F64)
4159 | (ValType::I64, ValType::F64)
4160 | (ValType::F32, ValType::F64)
4161
4162 | (ValType::Ref(_), _)
4164 | (_, ValType::Ref(_))
4165 | (ValType::V128, _)
4166 | (_, ValType::V128) => {
4167 panic!("cannot get {dst_ty:?} from {src_ty:?} local");
4168 }
4169 }
4170 }
4171
4172 fn i32_load8u(&mut self, mem: &Memory) {
4173 self.instruction(LocalGet(mem.addr.idx));
4174 self.instruction(I32Load8U(mem.memarg(0)));
4175 }
4176
4177 fn i32_load8s(&mut self, mem: &Memory) {
4178 self.instruction(LocalGet(mem.addr.idx));
4179 self.instruction(I32Load8S(mem.memarg(0)));
4180 }
4181
4182 fn i32_load16u(&mut self, mem: &Memory) {
4183 self.instruction(LocalGet(mem.addr.idx));
4184 self.instruction(I32Load16U(mem.memarg(1)));
4185 }
4186
4187 fn i32_load16s(&mut self, mem: &Memory) {
4188 self.instruction(LocalGet(mem.addr.idx));
4189 self.instruction(I32Load16S(mem.memarg(1)));
4190 }
4191
4192 fn i32_load(&mut self, mem: &Memory) {
4193 self.instruction(LocalGet(mem.addr.idx));
4194 self.instruction(I32Load(mem.memarg(2)));
4195 }
4196
4197 fn i64_load(&mut self, mem: &Memory) {
4198 self.instruction(LocalGet(mem.addr.idx));
4199 self.instruction(I64Load(mem.memarg(3)));
4200 }
4201
4202 fn ptr_load(&mut self, mem: &Memory) {
4203 if mem.mem_opts().memory64() {
4204 self.i64_load(mem);
4205 } else {
4206 self.i32_load(mem);
4207 }
4208 }
4209
4210 fn ptr_add(&mut self, opts: &LinearMemoryOptions) {
4211 if opts.memory64() {
4212 self.instruction(I64Add);
4213 } else {
4214 self.instruction(I32Add);
4215 }
4216 }
4217
4218 fn ptr_sub(&mut self, opts: &LinearMemoryOptions) {
4219 if opts.memory64() {
4220 self.instruction(I64Sub);
4221 } else {
4222 self.instruction(I32Sub);
4223 }
4224 }
4225
4226 fn ptr_mul(&mut self, opts: &LinearMemoryOptions) {
4227 if opts.memory64() {
4228 self.instruction(I64Mul);
4229 } else {
4230 self.instruction(I32Mul);
4231 }
4232 }
4233
4234 fn ptr_gt_u(&mut self, opts: &LinearMemoryOptions) {
4235 if opts.memory64() {
4236 self.instruction(I64GtU);
4237 } else {
4238 self.instruction(I32GtU);
4239 }
4240 }
4241
4242 fn ptr_lt_u(&mut self, opts: &LinearMemoryOptions) {
4243 if opts.memory64() {
4244 self.instruction(I64LtU);
4245 } else {
4246 self.instruction(I32LtU);
4247 }
4248 }
4249
4250 fn ptr_shl(&mut self, opts: &LinearMemoryOptions) {
4251 if opts.memory64() {
4252 self.instruction(I64Shl);
4253 } else {
4254 self.instruction(I32Shl);
4255 }
4256 }
4257
4258 fn ptr_eqz(&mut self, opts: &LinearMemoryOptions) {
4259 if opts.memory64() {
4260 self.instruction(I64Eqz);
4261 } else {
4262 self.instruction(I32Eqz);
4263 }
4264 }
4265
4266 fn ptr_uconst(&mut self, opts: &LinearMemoryOptions, val: u32) {
4267 if opts.memory64() {
4268 self.instruction(I64Const(val.into()));
4269 } else {
4270 self.instruction(I32Const(val.cast_signed()));
4271 }
4272 }
4273
4274 fn ptr_iconst(&mut self, opts: &LinearMemoryOptions, val: i32) {
4275 if opts.memory64() {
4276 self.instruction(I64Const(val.into()));
4277 } else {
4278 self.instruction(I32Const(val));
4279 }
4280 }
4281
4282 fn ptr_eq(&mut self, opts: &LinearMemoryOptions) {
4283 if opts.memory64() {
4284 self.instruction(I64Eq);
4285 } else {
4286 self.instruction(I32Eq);
4287 }
4288 }
4289
4290 fn ptr_ne(&mut self, opts: &LinearMemoryOptions) {
4291 if opts.memory64() {
4292 self.instruction(I64Ne);
4293 } else {
4294 self.instruction(I32Ne);
4295 }
4296 }
4297
4298 fn ptr_and(&mut self, opts: &LinearMemoryOptions) {
4299 if opts.memory64() {
4300 self.instruction(I64And);
4301 } else {
4302 self.instruction(I32And);
4303 }
4304 }
4305
4306 fn ptr_or(&mut self, opts: &LinearMemoryOptions) {
4307 if opts.memory64() {
4308 self.instruction(I64Or);
4309 } else {
4310 self.instruction(I32Or);
4311 }
4312 }
4313
4314 fn ptr_xor(&mut self, opts: &LinearMemoryOptions) {
4315 if opts.memory64() {
4316 self.instruction(I64Xor);
4317 } else {
4318 self.instruction(I32Xor);
4319 }
4320 }
4321
4322 fn ptr_if(&mut self, opts: &LinearMemoryOptions, ty: BlockType) {
4323 if opts.memory64() {
4324 self.instruction(I64Const(0));
4325 self.instruction(I64Ne);
4326 }
4327 self.instruction(If(ty));
4328 }
4329
4330 fn ptr_br_if(&mut self, opts: &LinearMemoryOptions, depth: u32) {
4331 if opts.memory64() {
4332 self.instruction(I64Const(0));
4333 self.instruction(I64Ne);
4334 }
4335 self.instruction(BrIf(depth));
4336 }
4337
4338 fn f32_load(&mut self, mem: &Memory) {
4339 self.instruction(LocalGet(mem.addr.idx));
4340 self.instruction(F32Load(mem.memarg(2)));
4341 }
4342
4343 fn f64_load(&mut self, mem: &Memory) {
4344 self.instruction(LocalGet(mem.addr.idx));
4345 self.instruction(F64Load(mem.memarg(3)));
4346 }
4347
4348 fn push_dst_addr(&mut self, dst: &Destination) {
4349 if let Destination::Memory(mem) = dst {
4350 self.instruction(LocalGet(mem.addr.idx));
4351 }
4352 }
4353
4354 fn i32_store8(&mut self, mem: &Memory) {
4355 self.instruction(I32Store8(mem.memarg(0)));
4356 }
4357
4358 fn i32_store16(&mut self, mem: &Memory) {
4359 self.instruction(I32Store16(mem.memarg(1)));
4360 }
4361
4362 fn i32_store(&mut self, mem: &Memory) {
4363 self.instruction(I32Store(mem.memarg(2)));
4364 }
4365
4366 fn i64_store(&mut self, mem: &Memory) {
4367 self.instruction(I64Store(mem.memarg(3)));
4368 }
4369
4370 fn ptr_store(&mut self, mem: &Memory) {
4371 if mem.mem_opts().memory64() {
4372 self.i64_store(mem);
4373 } else {
4374 self.i32_store(mem);
4375 }
4376 }
4377
4378 fn f32_store(&mut self, mem: &Memory) {
4379 self.instruction(F32Store(mem.memarg(2)));
4380 }
4381
4382 fn f64_store(&mut self, mem: &Memory) {
4383 self.instruction(F64Store(mem.memarg(3)));
4384 }
4385
4386 fn alloc_size(&mut self, opts: &LinearMemoryOptions, size: &AllocSize) {
4389 match size {
4390 AllocSize::Const(size) => self.ptr_uconst(opts, *size),
4391 AllocSize::Local(idx) => self.instruction(LocalGet(*idx)),
4392 AllocSize::DoubleLocal(idx) => {
4393 self.instruction(LocalGet(*idx));
4394 self.ptr_uconst(opts, 1);
4395 self.ptr_shl(opts);
4396 }
4397 }
4398 }
4399}
4400
4401impl<'a> Source<'a> {
4402 fn record_field_srcs<'b>(
4409 &'b self,
4410 types: &'b ComponentTypesBuilder,
4411 fields: impl IntoIterator<Item = InterfaceType> + 'b,
4412 ) -> impl Iterator<Item = Source<'a>> + 'b
4413 where
4414 'a: 'b,
4415 {
4416 let mut offset = 0;
4417 fields.into_iter().map(move |ty| match self {
4418 Source::Memory(mem) => {
4419 let mem = next_field_offset(&mut offset, types, &ty, mem);
4420 Source::Memory(mem)
4421 }
4422 Source::Stack(stack) => {
4423 let cnt = types.flat_types(&ty).unwrap().len() as u32;
4424 offset += cnt;
4425 Source::Stack(stack.slice((offset - cnt) as usize..offset as usize))
4426 }
4427 Source::Struct(_) => todo!(),
4428 Source::Array(_) => todo!(),
4429 })
4430 }
4431
4432 fn payload_src(
4434 &self,
4435 types: &ComponentTypesBuilder,
4436 info: &VariantInfo,
4437 case: Option<&InterfaceType>,
4438 ) -> Source<'a> {
4439 match self {
4440 Source::Stack(s) => {
4441 let flat_len = match case {
4442 Some(case) => types.flat_types(case).unwrap().len(),
4443 None => 0,
4444 };
4445 Source::Stack(s.slice(1..s.locals.len()).slice(0..flat_len))
4446 }
4447 Source::Memory(mem) => {
4448 let mem = if mem.mem_opts().memory64() {
4449 mem.bump(info.payload_offset64)
4450 } else {
4451 mem.bump(info.payload_offset32)
4452 };
4453 Source::Memory(mem)
4454 }
4455 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
4456 }
4457 }
4458
4459 fn opts(&self) -> &'a Options {
4460 match self {
4461 Source::Stack(s) => s.opts,
4462 Source::Memory(mem) => mem.opts,
4463 Source::Struct(s) => s.opts,
4464 Source::Array(a) => a.opts,
4465 }
4466 }
4467}
4468
4469impl<'a> Destination<'a> {
4470 fn record_field_dsts<'b, I>(
4472 &'b self,
4473 types: &'b ComponentTypesBuilder,
4474 fields: I,
4475 ) -> impl Iterator<Item = Destination<'b>> + use<'b, I>
4476 where
4477 'a: 'b,
4478 I: IntoIterator<Item = InterfaceType> + 'b,
4479 {
4480 let mut offset = 0;
4481 fields.into_iter().map(move |ty| match self {
4482 Destination::Memory(mem) => {
4483 let mem = next_field_offset(&mut offset, types, &ty, mem);
4484 Destination::Memory(mem)
4485 }
4486 Destination::Stack(s, opts) => {
4487 let cnt = types.flat_types(&ty).unwrap().len() as u32;
4488 offset += cnt;
4489 Destination::Stack(&s[(offset - cnt) as usize..offset as usize], opts)
4490 }
4491 Destination::Struct(_) => todo!(),
4492 Destination::Array(_) => todo!(),
4493 })
4494 }
4495
4496 fn payload_dst(
4498 &self,
4499 types: &ComponentTypesBuilder,
4500 info: &VariantInfo,
4501 case: Option<&InterfaceType>,
4502 ) -> Destination<'_> {
4503 match self {
4504 Destination::Stack(s, opts) => {
4505 let flat_len = match case {
4506 Some(case) => types.flat_types(case).unwrap().len(),
4507 None => 0,
4508 };
4509 Destination::Stack(&s[1..][..flat_len], opts)
4510 }
4511 Destination::Memory(mem) => {
4512 let mem = if mem.mem_opts().memory64() {
4513 mem.bump(info.payload_offset64)
4514 } else {
4515 mem.bump(info.payload_offset32)
4516 };
4517 Destination::Memory(mem)
4518 }
4519 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
4520 }
4521 }
4522
4523 fn opts(&self) -> &'a Options {
4524 match self {
4525 Destination::Stack(_, opts) => opts,
4526 Destination::Memory(mem) => mem.opts,
4527 Destination::Struct(s) => s.opts,
4528 Destination::Array(a) => a.opts,
4529 }
4530 }
4531}
4532
4533fn next_field_offset<'a>(
4534 offset: &mut u32,
4535 types: &ComponentTypesBuilder,
4536 field: &InterfaceType,
4537 mem: &Memory<'a>,
4538) -> Memory<'a> {
4539 let abi = types.canonical_abi(field);
4540 let offset = if mem.mem_opts().memory64() {
4541 abi.next_field64(offset)
4542 } else {
4543 abi.next_field32(offset)
4544 };
4545 mem.bump(offset)
4546}
4547
4548impl<'a> Memory<'a> {
4549 fn memarg(&self, align: u32) -> MemArg {
4550 MemArg {
4551 offset: u64::from(self.offset),
4552 align,
4553 memory_index: self.mem_opts().memory.unwrap().0.as_u32(),
4554 }
4555 }
4556
4557 fn bump(&self, offset: u32) -> Memory<'a> {
4558 Memory {
4559 opts: self.opts,
4560 addr: TempLocal::new(self.addr.idx, self.addr.ty),
4561 offset: self.offset + offset,
4562 }
4563 }
4564}
4565
4566impl<'a> Stack<'a> {
4567 fn slice(&self, range: Range<usize>) -> Stack<'a> {
4568 Stack {
4569 locals: &self.locals[range],
4570 opts: self.opts,
4571 }
4572 }
4573}
4574
4575struct VariantCase<'a> {
4576 src_i: u32,
4577 src_ty: Option<&'a InterfaceType>,
4578 dst_i: u32,
4579 dst_ty: Option<&'a InterfaceType>,
4580}
4581
4582fn variant_info<'a, I>(types: &ComponentTypesBuilder, cases: I) -> VariantInfo
4583where
4584 I: IntoIterator<Item = Option<&'a InterfaceType>>,
4585 I::IntoIter: ExactSizeIterator,
4586{
4587 VariantInfo::new(
4588 cases
4589 .into_iter()
4590 .map(|ty| ty.map(|ty| types.canonical_abi(ty))),
4591 )
4592 .0
4593}
4594
4595struct SequenceLoopState {
4597 remaining: TempLocal,
4598 cur_src_ptr: TempLocal,
4599 cur_dst_ptr: TempLocal,
4600}
4601
4602struct SequenceTranslation<'a> {
4606 src_len: TempLocal,
4607 src_mem: Memory<'a>,
4608 dst_mem: Memory<'a>,
4609 src_opts: &'a Options,
4610 dst_opts: &'a Options,
4611 src_mem_opts: &'a LinearMemoryOptions,
4612 dst_mem_opts: &'a LinearMemoryOptions,
4613 loop_state: Option<SequenceLoopState>,
4614}
4615
4616enum AllocSize {
4617 Const(u32),
4618 Local(u32),
4619 DoubleLocal(u32),
4620}
4621
4622struct WasmString<'a> {
4623 ptr: TempLocal,
4624 len: TempLocal,
4625 opts: &'a Options,
4626}
4627
4628struct TempLocal {
4629 idx: u32,
4630 ty: ValType,
4631 needs_free: bool,
4632}
4633
4634impl TempLocal {
4635 fn new(idx: u32, ty: ValType) -> TempLocal {
4636 TempLocal {
4637 idx,
4638 ty,
4639 needs_free: false,
4640 }
4641 }
4642}
4643
4644impl std::ops::Drop for TempLocal {
4645 fn drop(&mut self) {
4646 if self.needs_free {
4647 panic!("temporary local not free'd");
4648 }
4649 }
4650}
4651
4652impl From<FlatType> for ValType {
4653 fn from(ty: FlatType) -> ValType {
4654 match ty {
4655 FlatType::I32 => ValType::I32,
4656 FlatType::I64 => ValType::I64,
4657 FlatType::F32 => ValType::F32,
4658 FlatType::F64 => ValType::F64,
4659 }
4660 }
4661}