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 if self.module.tunables.concurrency_support {
760 self.instruction(I32Const(
769 i32::try_from(adapter.lower.instance.as_u32()).unwrap(),
770 ));
771 self.instruction(I32Const(if self.types[adapter.lift.ty].async_ {
772 1
773 } else {
774 0
775 }));
776 self.instruction(I32Const(
777 i32::try_from(adapter.lift.instance.as_u32()).unwrap(),
778 ));
779 let enter_sync_call = self.module.import_enter_sync_call();
780 self.instruction(Call(enter_sync_call.as_u32()));
781 } else if self.emit_resource_call {
782 assert!(!self.types[adapter.lift.ty].async_);
783 self.instruction(I32Const(
784 i32::try_from(adapter.lower.instance.as_u32()).unwrap(),
785 ));
786 self.instruction(I32Const(0));
787 self.instruction(I32Const(
788 i32::try_from(adapter.lift.instance.as_u32()).unwrap(),
789 ));
790 let enter_sync_call = self.module.import_enter_sync_call();
791 self.instruction(Call(enter_sync_call.as_u32()));
792 }
793
794 let saved_lift_may_leave = self.clear_may_leave(adapter.lift.flags);
829 let param_locals = lower_sig
830 .params
831 .iter()
832 .enumerate()
833 .map(|(i, ty)| (i as u32, *ty))
834 .collect::<Vec<_>>();
835 self.translate_params(adapter, ¶m_locals);
836 self.restore_may_leave(adapter.lift.flags, saved_lift_may_leave);
837
838 self.instruction(Call(adapter.callee.as_u32()));
843
844 let mut result_locals = Vec::with_capacity(lift_sig.results.len());
845 let mut temps = Vec::new();
846 for ty in lift_sig.results.iter().rev() {
847 let local = self.local_set_new_tmp(*ty);
848 result_locals.push((local.idx, *ty));
849 temps.push(local);
850 }
851 result_locals.reverse();
852
853 let callee_context = if adapter.lift.post_return.is_some() {
857 self.save_context()
858 } else {
859 Vec::new()
860 };
861
862 if self.emit_resource_call || self.module.tunables.concurrency_support {
879 let exit_sync_call = self.module.import_exit_sync_call();
880 self.instruction(Call(exit_sync_call.as_u32()));
881 }
882
883 self.set_may_leave_false(adapter.lower.flags);
889 self.translate_results(adapter, ¶m_locals, &result_locals);
890 self.restore_may_leave(adapter.lower.flags, saved_lower_may_leave);
891
892 if let Some(func) = adapter.lift.post_return {
898 let caller_context = self.save_context();
899 self.restore_context(callee_context);
900 for (result, _) in result_locals.iter() {
901 self.instruction(LocalGet(*result));
902 }
903 self.instruction(Call(func.as_u32()));
904 self.restore_context(caller_context);
905 } else {
906 assert!(callee_context.is_empty());
907 }
908
909 for tmp in temps {
910 self.free_temp_local(tmp);
911 }
912
913 self.exit_exception_barrier();
914
915 self.finish()
916 }
917
918 fn translate_params(&mut self, adapter: &AdapterData, param_locals: &[(u32, ValType)]) {
919 let src_tys = self.types[adapter.lower.ty].params;
920 let src_tys = self.types[src_tys]
921 .types
922 .iter()
923 .copied()
924 .collect::<Vec<_>>();
925 let dst_tys = self.types[adapter.lift.ty].params;
926 let dst_tys = self.types[dst_tys]
927 .types
928 .iter()
929 .copied()
930 .collect::<Vec<_>>();
931 let lift_opts = &adapter.lift.options;
932 let lower_opts = &adapter.lower.options;
933
934 assert_eq!(src_tys.len(), dst_tys.len());
936
937 let max_flat_params = if adapter.lower.options.async_ {
941 MAX_FLAT_ASYNC_PARAMS
942 } else {
943 MAX_FLAT_PARAMS
944 };
945 let src_flat =
946 self.types
947 .flatten_types(lower_opts, max_flat_params, src_tys.iter().copied());
948 let dst_flat =
949 self.types
950 .flatten_types(lift_opts, MAX_FLAT_PARAMS, dst_tys.iter().copied());
951
952 let src = if let Some(flat) = &src_flat {
953 Source::Stack(Stack {
954 locals: ¶m_locals[..flat.len()],
955 opts: lower_opts,
956 })
957 } else {
958 let lower_mem_opts = lower_opts.data_model.unwrap_memory();
962 let (addr, ty) = param_locals[0];
963 assert_eq!(ty, lower_mem_opts.ptr());
964 let abi = CanonicalAbiInfo::record(src_tys.iter().map(|t| self.types.canonical_abi(t)));
965 Source::Memory(self.memory_operand_abi(
966 lower_opts,
967 TempLocal::new(addr, ty),
968 &abi,
969 Trap::MemoryOutOfBounds,
970 ))
971 };
972
973 let dst = if let Some(flat) = &dst_flat {
974 Destination::Stack(flat, lift_opts)
975 } else {
976 let abi = CanonicalAbiInfo::record(dst_tys.iter().map(|t| self.types.canonical_abi(t)));
979 Destination::Memory(self.malloc_abi(lift_opts, &abi, Trap::MemoryOutOfBounds))
980 };
981
982 let srcs = src
983 .record_field_srcs(self.types, src_tys.iter().copied())
984 .zip(src_tys.iter());
985 let dsts = dst
986 .record_field_dsts(self.types, dst_tys.iter().copied())
987 .zip(dst_tys.iter());
988 for ((src, src_ty), (dst, dst_ty)) in srcs.zip(dsts) {
989 self.translate(&src_ty, &src, &dst_ty, &dst);
990 }
991
992 if let Destination::Memory(mem) = dst {
996 self.instruction(LocalGet(mem.addr.idx));
997 self.free_temp_local(mem.addr);
998 }
999 }
1000
1001 fn translate_results(
1002 &mut self,
1003 adapter: &AdapterData,
1004 param_locals: &[(u32, ValType)],
1005 result_locals: &[(u32, ValType)],
1006 ) {
1007 let src_tys = self.types[adapter.lift.ty].results;
1008 let src_tys = self.types[src_tys]
1009 .types
1010 .iter()
1011 .copied()
1012 .collect::<Vec<_>>();
1013 let dst_tys = self.types[adapter.lower.ty].results;
1014 let dst_tys = self.types[dst_tys]
1015 .types
1016 .iter()
1017 .copied()
1018 .collect::<Vec<_>>();
1019 let lift_opts = &adapter.lift.options;
1020 let lower_opts = &adapter.lower.options;
1021
1022 let src_flat = self
1023 .types
1024 .flatten_lifting_types(lift_opts, src_tys.iter().copied());
1025 let dst_flat = self
1026 .types
1027 .flatten_lowering_types(lower_opts, dst_tys.iter().copied());
1028
1029 let src = if src_flat.is_some() {
1030 Source::Stack(Stack {
1031 locals: result_locals,
1032 opts: lift_opts,
1033 })
1034 } else {
1035 let abi = CanonicalAbiInfo::record(src_tys.iter().map(|t| self.types.canonical_abi(t)));
1040 assert_eq!(
1041 result_locals.len(),
1042 if lower_opts.async_ || lift_opts.async_ {
1043 2
1044 } else {
1045 1
1046 }
1047 );
1048 let (addr, ty) = result_locals[0];
1049 assert_eq!(ty, lift_opts.data_model.unwrap_memory().ptr());
1050 Source::Memory(self.memory_operand_abi(
1051 lift_opts,
1052 TempLocal::new(addr, ty),
1053 &abi,
1054 Trap::MemoryOutOfBounds,
1055 ))
1056 };
1057
1058 let dst = if let Some(flat) = &dst_flat {
1059 Destination::Stack(flat, lower_opts)
1060 } else {
1061 let abi = CanonicalAbiInfo::record(dst_tys.iter().map(|t| self.types.canonical_abi(t)));
1065 let (addr, ty) = *param_locals.last().expect("no retptr");
1066 assert_eq!(ty, lower_opts.data_model.unwrap_memory().ptr());
1067 Destination::Memory(self.memory_operand_abi(
1068 lower_opts,
1069 TempLocal::new(addr, ty),
1070 &abi,
1071 Trap::MemoryOutOfBounds,
1072 ))
1073 };
1074
1075 let srcs = src
1076 .record_field_srcs(self.types, src_tys.iter().copied())
1077 .zip(src_tys.iter());
1078 let dsts = dst
1079 .record_field_dsts(self.types, dst_tys.iter().copied())
1080 .zip(dst_tys.iter());
1081 for ((src, src_ty), (dst, dst_ty)) in srcs.zip(dsts) {
1082 self.translate(&src_ty, &src, &dst_ty, &dst);
1083 }
1084 }
1085
1086 fn translate(
1087 &mut self,
1088 src_ty: &InterfaceType,
1089 src: &Source<'_>,
1090 dst_ty: &InterfaceType,
1091 dst: &Destination,
1092 ) {
1093 if let Source::Memory(mem) = src {
1094 self.assert_aligned(src_ty, mem);
1095 }
1096 if let Destination::Memory(mem) = dst {
1097 self.assert_aligned(dst_ty, mem);
1098 }
1099
1100 let cost = match src_ty {
1130 InterfaceType::Bool
1134 | InterfaceType::U8
1135 | InterfaceType::S8
1136 | InterfaceType::U16
1137 | InterfaceType::S16
1138 | InterfaceType::U32
1139 | InterfaceType::S32
1140 | InterfaceType::U64
1141 | InterfaceType::S64
1142 | InterfaceType::Float32
1143 | InterfaceType::Float64 => 0,
1144
1145 InterfaceType::Char => 1,
1148
1149 InterfaceType::String => 40,
1152
1153 InterfaceType::List(_) => 40,
1156 InterfaceType::Map(_) => 40,
1158
1159 InterfaceType::Flags(i) => {
1160 let count = self.module.types[*i].names.len();
1161 match FlagsSize::from_count(count) {
1162 FlagsSize::Size0 => 0,
1163 FlagsSize::Size1 | FlagsSize::Size2 => 1,
1164 FlagsSize::Size4Plus(n) => n.into(),
1165 }
1166 }
1167
1168 InterfaceType::Record(i) => self.types[*i].fields.len(),
1169 InterfaceType::Tuple(i) => self.types[*i].types.len(),
1170 InterfaceType::Variant(i) => self.types[*i].cases.len(),
1171 InterfaceType::Enum(i) => self.types[*i].names.len(),
1172
1173 InterfaceType::Option(_) | InterfaceType::Result(_) => 2,
1175
1176 InterfaceType::Own(_)
1178 | InterfaceType::Borrow(_)
1179 | InterfaceType::Future(_)
1180 | InterfaceType::Stream(_)
1181 | InterfaceType::ErrorContext(_) => 1,
1182 InterfaceType::FixedLengthList(i) => self.types[*i].size as usize,
1183 };
1184
1185 match self.fuel.checked_sub(cost) {
1186 Some(n) => {
1192 self.fuel = n;
1193 match src_ty {
1194 InterfaceType::Bool => self.translate_bool(src, dst_ty, dst),
1195 InterfaceType::U8 => self.translate_u8(src, dst_ty, dst),
1196 InterfaceType::S8 => self.translate_s8(src, dst_ty, dst),
1197 InterfaceType::U16 => self.translate_u16(src, dst_ty, dst),
1198 InterfaceType::S16 => self.translate_s16(src, dst_ty, dst),
1199 InterfaceType::U32 => self.translate_u32(src, dst_ty, dst),
1200 InterfaceType::S32 => self.translate_s32(src, dst_ty, dst),
1201 InterfaceType::U64 => self.translate_u64(src, dst_ty, dst),
1202 InterfaceType::S64 => self.translate_s64(src, dst_ty, dst),
1203 InterfaceType::Float32 => self.translate_f32(src, dst_ty, dst),
1204 InterfaceType::Float64 => self.translate_f64(src, dst_ty, dst),
1205 InterfaceType::Char => self.translate_char(src, dst_ty, dst),
1206 InterfaceType::String => self.translate_string(src, dst_ty, dst),
1207 InterfaceType::List(t) => self.translate_list(*t, src, dst_ty, dst),
1208 InterfaceType::Map(t) => self.translate_map(*t, src, dst_ty, dst),
1209 InterfaceType::Record(t) => self.translate_record(*t, src, dst_ty, dst),
1210 InterfaceType::Flags(f) => self.translate_flags(*f, src, dst_ty, dst),
1211 InterfaceType::Tuple(t) => self.translate_tuple(*t, src, dst_ty, dst),
1212 InterfaceType::Variant(v) => self.translate_variant(*v, src, dst_ty, dst),
1213 InterfaceType::Enum(t) => self.translate_enum(*t, src, dst_ty, dst),
1214 InterfaceType::Option(t) => self.translate_option(*t, src, dst_ty, dst),
1215 InterfaceType::Result(t) => self.translate_result(*t, src, dst_ty, dst),
1216 InterfaceType::Own(t) => self.translate_own(*t, src, dst_ty, dst),
1217 InterfaceType::Borrow(t) => self.translate_borrow(*t, src, dst_ty, dst),
1218 InterfaceType::Future(t) => self.translate_future(*t, src, dst_ty, dst),
1219 InterfaceType::Stream(t) => self.translate_stream(*t, src, dst_ty, dst),
1220 InterfaceType::ErrorContext(t) => {
1221 self.translate_error_context(*t, src, dst_ty, dst)
1222 }
1223 InterfaceType::FixedLengthList(t) => {
1224 self.translate_fixed_length_list(*t, src, dst_ty, dst);
1225 }
1226 }
1227 }
1228
1229 None => {
1235 let src_loc = match src {
1236 Source::Stack(stack) => {
1240 for (i, ty) in stack
1241 .opts
1242 .flat_types(src_ty, self.types)
1243 .unwrap()
1244 .iter()
1245 .enumerate()
1246 {
1247 let stack = stack.slice(i..i + 1);
1248 self.stack_get(&stack, (*ty).into());
1249 }
1250 HelperLocation::Stack
1251 }
1252 Source::Memory(mem) => {
1257 self.push_mem_addr(mem);
1258 HelperLocation::Memory
1259 }
1260 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1261 };
1262 let dst_loc = match dst {
1263 Destination::Stack(..) => HelperLocation::Stack,
1264 Destination::Memory(mem) => {
1265 self.push_mem_addr(mem);
1266 HelperLocation::Memory
1267 }
1268 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1269 };
1270 let helper = self.module.translate_helper(Helper {
1276 src: HelperType {
1277 ty: *src_ty,
1278 opts: *src.opts(),
1279 loc: src_loc,
1280 },
1281 dst: HelperType {
1282 ty: *dst_ty,
1283 opts: *dst.opts(),
1284 loc: dst_loc,
1285 },
1286 });
1287 self.flush_code();
1290 self.module.funcs[self.result].body.push(Body::Call(helper));
1291
1292 if let Destination::Stack(tys, opts) = dst {
1301 let flat = self
1302 .types
1303 .flatten_types(opts, usize::MAX, [*dst_ty])
1304 .unwrap();
1305 assert_eq!(flat.len(), tys.len());
1306 let locals = flat
1307 .iter()
1308 .rev()
1309 .map(|ty| self.local_set_new_tmp(*ty))
1310 .collect::<Vec<_>>();
1311 for (ty, local) in tys.iter().zip(locals.into_iter().rev()) {
1312 self.instruction(LocalGet(local.idx));
1313 self.stack_set(std::slice::from_ref(ty), local.ty);
1314 self.free_temp_local(local);
1315 }
1316 }
1317 }
1318 }
1319 }
1320
1321 fn push_mem_addr(&mut self, mem: &Memory<'_>) {
1322 self.instruction(LocalGet(mem.addr.idx));
1323 if mem.offset != 0 {
1324 self.ptr_uconst(mem.mem_opts(), mem.offset);
1325 self.ptr_add(mem.mem_opts());
1326 }
1327 }
1328
1329 fn translate_bool(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1330 assert!(matches!(dst_ty, InterfaceType::Bool));
1332 self.push_dst_addr(dst);
1333
1334 self.instruction(I32Const(1));
1337 self.instruction(I32Const(0));
1338 match src {
1339 Source::Memory(mem) => self.i32_load8u(mem),
1340 Source::Stack(stack) => self.stack_get(stack, ValType::I32),
1341 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1342 }
1343 self.instruction(Select);
1344
1345 match dst {
1346 Destination::Memory(mem) => self.i32_store8(mem),
1347 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1348 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1349 }
1350 }
1351
1352 fn translate_u8(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1353 assert!(matches!(dst_ty, InterfaceType::U8));
1355 self.convert_u8_mask(src, dst, 0xff);
1356 }
1357
1358 fn convert_u8_mask(&mut self, src: &Source<'_>, dst: &Destination<'_>, mask: u8) {
1359 self.push_dst_addr(dst);
1360 let mut needs_mask = true;
1361 match src {
1362 Source::Memory(mem) => {
1363 self.i32_load8u(mem);
1364 needs_mask = mask != 0xff;
1365 }
1366 Source::Stack(stack) => {
1367 self.stack_get(stack, ValType::I32);
1368 }
1369 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1370 }
1371 if needs_mask {
1372 self.instruction(I32Const(i32::from(mask)));
1373 self.instruction(I32And);
1374 }
1375 match dst {
1376 Destination::Memory(mem) => self.i32_store8(mem),
1377 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1378 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1379 }
1380 }
1381
1382 fn translate_s8(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1383 assert!(matches!(dst_ty, InterfaceType::S8));
1385 self.push_dst_addr(dst);
1386 match src {
1387 Source::Memory(mem) => self.i32_load8s(mem),
1388 Source::Stack(stack) => {
1389 self.stack_get(stack, ValType::I32);
1390 self.instruction(I32Extend8S);
1391 }
1392 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1393 }
1394 match dst {
1395 Destination::Memory(mem) => self.i32_store8(mem),
1396 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1397 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1398 }
1399 }
1400
1401 fn translate_u16(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1402 assert!(matches!(dst_ty, InterfaceType::U16));
1404 self.convert_u16_mask(src, dst, 0xffff);
1405 }
1406
1407 fn convert_u16_mask(&mut self, src: &Source<'_>, dst: &Destination<'_>, mask: u16) {
1408 self.push_dst_addr(dst);
1409 let mut needs_mask = true;
1410 match src {
1411 Source::Memory(mem) => {
1412 self.i32_load16u(mem);
1413 needs_mask = mask != 0xffff;
1414 }
1415 Source::Stack(stack) => {
1416 self.stack_get(stack, ValType::I32);
1417 }
1418 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1419 }
1420 if needs_mask {
1421 self.instruction(I32Const(i32::from(mask)));
1422 self.instruction(I32And);
1423 }
1424 match dst {
1425 Destination::Memory(mem) => self.i32_store16(mem),
1426 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1427 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1428 }
1429 }
1430
1431 fn translate_s16(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1432 assert!(matches!(dst_ty, InterfaceType::S16));
1434 self.push_dst_addr(dst);
1435 match src {
1436 Source::Memory(mem) => self.i32_load16s(mem),
1437 Source::Stack(stack) => {
1438 self.stack_get(stack, ValType::I32);
1439 self.instruction(I32Extend16S);
1440 }
1441 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1442 }
1443 match dst {
1444 Destination::Memory(mem) => self.i32_store16(mem),
1445 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1446 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1447 }
1448 }
1449
1450 fn translate_u32(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1451 assert!(matches!(dst_ty, InterfaceType::U32));
1453 self.convert_u32_mask(src, dst, 0xffffffff)
1454 }
1455
1456 fn convert_u32_mask(&mut self, src: &Source<'_>, dst: &Destination<'_>, mask: u32) {
1457 self.push_dst_addr(dst);
1458 match src {
1459 Source::Memory(mem) => self.i32_load(mem),
1460 Source::Stack(stack) => self.stack_get(stack, ValType::I32),
1461 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1462 }
1463 if mask != 0xffffffff {
1464 self.instruction(I32Const(mask as i32));
1465 self.instruction(I32And);
1466 }
1467 match dst {
1468 Destination::Memory(mem) => self.i32_store(mem),
1469 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1470 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1471 }
1472 }
1473
1474 fn translate_s32(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1475 assert!(matches!(dst_ty, InterfaceType::S32));
1477 self.push_dst_addr(dst);
1478 match src {
1479 Source::Memory(mem) => self.i32_load(mem),
1480 Source::Stack(stack) => self.stack_get(stack, ValType::I32),
1481 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1482 }
1483 match dst {
1484 Destination::Memory(mem) => self.i32_store(mem),
1485 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1486 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1487 }
1488 }
1489
1490 fn translate_u64(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1491 assert!(matches!(dst_ty, InterfaceType::U64));
1493 self.push_dst_addr(dst);
1494 match src {
1495 Source::Memory(mem) => self.i64_load(mem),
1496 Source::Stack(stack) => self.stack_get(stack, ValType::I64),
1497 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1498 }
1499 match dst {
1500 Destination::Memory(mem) => self.i64_store(mem),
1501 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I64),
1502 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1503 }
1504 }
1505
1506 fn translate_s64(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1507 assert!(matches!(dst_ty, InterfaceType::S64));
1509 self.push_dst_addr(dst);
1510 match src {
1511 Source::Memory(mem) => self.i64_load(mem),
1512 Source::Stack(stack) => self.stack_get(stack, ValType::I64),
1513 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1514 }
1515 match dst {
1516 Destination::Memory(mem) => self.i64_store(mem),
1517 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I64),
1518 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1519 }
1520 }
1521
1522 fn translate_f32(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1523 assert!(matches!(dst_ty, InterfaceType::Float32));
1525 self.push_dst_addr(dst);
1526 match src {
1527 Source::Memory(mem) => self.f32_load(mem),
1528 Source::Stack(stack) => self.stack_get(stack, ValType::F32),
1529 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1530 }
1531 match dst {
1532 Destination::Memory(mem) => self.f32_store(mem),
1533 Destination::Stack(stack, _) => self.stack_set(stack, ValType::F32),
1534 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1535 }
1536 }
1537
1538 fn translate_f64(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1539 assert!(matches!(dst_ty, InterfaceType::Float64));
1541 self.push_dst_addr(dst);
1542 match src {
1543 Source::Memory(mem) => self.f64_load(mem),
1544 Source::Stack(stack) => self.stack_get(stack, ValType::F64),
1545 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1546 }
1547 match dst {
1548 Destination::Memory(mem) => self.f64_store(mem),
1549 Destination::Stack(stack, _) => self.stack_set(stack, ValType::F64),
1550 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1551 }
1552 }
1553
1554 fn translate_char(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1555 assert!(matches!(dst_ty, InterfaceType::Char));
1556 match src {
1557 Source::Memory(mem) => self.i32_load(mem),
1558 Source::Stack(stack) => self.stack_get(stack, ValType::I32),
1559 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1560 }
1561 let local = self.local_set_new_tmp(ValType::I32);
1562
1563 self.instruction(Block(BlockType::Empty));
1579 self.instruction(Block(BlockType::Empty));
1580 self.instruction(LocalGet(local.idx));
1581 self.instruction(I32Const(0xd800));
1582 self.instruction(I32Xor);
1583 self.instruction(I32Const(-0x110000));
1584 self.instruction(I32Add);
1585 self.instruction(I32Const(-0x10f800));
1586 self.instruction(I32LtU);
1587 self.instruction(BrIf(0));
1588 self.instruction(LocalGet(local.idx));
1589 self.instruction(I32Const(0x110000));
1590 self.instruction(I32Ne);
1591 self.instruction(BrIf(1));
1592 self.instruction(End);
1593 self.trap(Trap::InvalidChar);
1594 self.instruction(End);
1595
1596 self.push_dst_addr(dst);
1597 self.instruction(LocalGet(local.idx));
1598 match dst {
1599 Destination::Memory(mem) => {
1600 self.i32_store(mem);
1601 }
1602 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1603 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1604 }
1605
1606 self.free_temp_local(local);
1607 }
1608
1609 fn translate_string(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1610 assert!(matches!(dst_ty, InterfaceType::String));
1611 let src_opts = src.opts();
1612 let dst_opts = dst.opts();
1613
1614 let src_mem_opts = match &src_opts.data_model {
1615 DataModel::Gc {} => todo!("CM+GC"),
1616 DataModel::LinearMemory(opts) => opts,
1617 };
1618 let dst_mem_opts = match &dst_opts.data_model {
1619 DataModel::Gc {} => todo!("CM+GC"),
1620 DataModel::LinearMemory(opts) => opts,
1621 };
1622
1623 match src {
1628 Source::Stack(s) => {
1629 assert_eq!(s.locals.len(), 2);
1630 self.stack_get(&s.slice(0..1), src_mem_opts.ptr());
1631 self.stack_get(&s.slice(1..2), src_mem_opts.ptr());
1632 }
1633 Source::Memory(mem) => {
1634 self.ptr_load(mem);
1635 self.ptr_load(&mem.bump(src_mem_opts.ptr_size().into()));
1636 }
1637 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1638 }
1639 let src_len = self.local_set_new_tmp(src_mem_opts.ptr());
1640 let src_ptr = self.local_set_new_tmp(src_mem_opts.ptr());
1641 let src_str = WasmString {
1642 ptr: src_ptr,
1643 len: src_len,
1644 opts: src_opts,
1645 };
1646
1647 let dst_str = match src_opts.string_encoding {
1648 StringEncoding::Utf8 => {
1649 self.validate_guest_pointer(
1650 src_opts,
1651 &src_str.ptr,
1652 &AllocSize::Local(src_str.len.idx),
1653 1,
1654 Trap::StringOutOfBounds,
1655 );
1656 match dst_opts.string_encoding {
1657 StringEncoding::Utf8 => {
1658 self.string_copy(&src_str, FE::Utf8, dst_opts, FE::Utf8)
1659 }
1660 StringEncoding::Utf16 => self.string_utf8_to_utf16(&src_str, dst_opts),
1661 StringEncoding::CompactUtf16 => {
1662 self.string_to_compact(&src_str, FE::Utf8, dst_opts)
1663 }
1664 }
1665 }
1666
1667 StringEncoding::Utf16 => {
1668 self.validate_guest_pointer(
1669 src_opts,
1670 &src_str.ptr,
1671 &AllocSize::DoubleLocal(src_str.len.idx),
1672 2,
1673 Trap::StringOutOfBounds,
1674 );
1675 match dst_opts.string_encoding {
1676 StringEncoding::Utf8 => {
1677 self.string_deflate_to_utf8(&src_str, FE::Utf16, dst_opts)
1678 }
1679 StringEncoding::Utf16 => {
1680 self.string_copy(&src_str, FE::Utf16, dst_opts, FE::Utf16)
1681 }
1682 StringEncoding::CompactUtf16 => {
1683 self.string_to_compact(&src_str, FE::Utf16, dst_opts)
1684 }
1685 }
1686 }
1687
1688 StringEncoding::CompactUtf16 => {
1689 self.instruction(LocalGet(src_str.len.idx));
1692 self.ptr_uconst(src_mem_opts, UTF16_TAG);
1693 self.ptr_and(src_mem_opts);
1694 self.ptr_if(src_mem_opts, BlockType::Empty);
1695
1696 self.instruction(LocalGet(src_str.len.idx));
1700 self.ptr_uconst(src_mem_opts, UTF16_TAG);
1701 self.ptr_xor(src_mem_opts);
1702 self.instruction(LocalSet(src_str.len.idx));
1703
1704 self.validate_guest_pointer(
1708 src_opts,
1709 &src_str.ptr,
1710 &AllocSize::DoubleLocal(src_str.len.idx),
1711 2,
1712 Trap::StringOutOfBounds,
1713 );
1714
1715 let s1 = match dst_opts.string_encoding {
1716 StringEncoding::Utf8 => {
1717 self.string_deflate_to_utf8(&src_str, FE::Utf16, dst_opts)
1718 }
1719 StringEncoding::Utf16 => {
1720 self.string_copy(&src_str, FE::Utf16, dst_opts, FE::Utf16)
1721 }
1722 StringEncoding::CompactUtf16 => {
1723 self.string_compact_utf16_to_compact(&src_str, dst_opts)
1724 }
1725 };
1726
1727 self.instruction(Else);
1728
1729 self.validate_guest_pointer(
1732 src_opts,
1733 &src_str.ptr,
1734 &AllocSize::Local(src_str.len.idx),
1735 2,
1736 Trap::StringOutOfBounds,
1737 );
1738
1739 let s2 = match dst_opts.string_encoding {
1743 StringEncoding::Utf16 => {
1744 self.string_copy(&src_str, FE::Latin1, dst_opts, FE::Utf16)
1745 }
1746 StringEncoding::Utf8 => {
1747 self.string_deflate_to_utf8(&src_str, FE::Latin1, dst_opts)
1748 }
1749 StringEncoding::CompactUtf16 => {
1750 self.string_copy(&src_str, FE::Latin1, dst_opts, FE::Latin1)
1751 }
1752 };
1753 self.instruction(LocalGet(s2.ptr.idx));
1756 self.instruction(LocalSet(s1.ptr.idx));
1757 self.instruction(LocalGet(s2.len.idx));
1758 self.instruction(LocalSet(s1.len.idx));
1759 self.instruction(End);
1760 self.free_temp_local(s2.ptr);
1761 self.free_temp_local(s2.len);
1762 s1
1763 }
1764 };
1765
1766 match dst {
1768 Destination::Stack(s, _) => {
1769 self.instruction(LocalGet(dst_str.ptr.idx));
1770 self.stack_set(&s[..1], dst_mem_opts.ptr());
1771 self.instruction(LocalGet(dst_str.len.idx));
1772 self.stack_set(&s[1..], dst_mem_opts.ptr());
1773 }
1774 Destination::Memory(mem) => {
1775 self.instruction(LocalGet(mem.addr.idx));
1776 self.instruction(LocalGet(dst_str.ptr.idx));
1777 self.ptr_store(mem);
1778 self.instruction(LocalGet(mem.addr.idx));
1779 self.instruction(LocalGet(dst_str.len.idx));
1780 self.ptr_store(&mem.bump(dst_mem_opts.ptr_size().into()));
1781 }
1782 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1783 }
1784
1785 self.free_temp_local(src_str.ptr);
1786 self.free_temp_local(src_str.len);
1787 self.free_temp_local(dst_str.ptr);
1788 self.free_temp_local(dst_str.len);
1789 }
1790
1791 fn string_copy<'c>(
1804 &mut self,
1805 src: &WasmString<'_>,
1806 src_enc: FE,
1807 dst_opts: &'c Options,
1808 dst_enc: FE,
1809 ) -> WasmString<'c> {
1810 assert!(dst_enc.width() >= src_enc.width());
1811
1812 self.validate_string_length(src, dst_enc);
1817
1818 let src_mem_opts = {
1819 match &src.opts.data_model {
1820 DataModel::Gc {} => todo!("CM+GC"),
1821 DataModel::LinearMemory(opts) => opts,
1822 }
1823 };
1824 let dst_mem_opts = {
1825 match &dst_opts.data_model {
1826 DataModel::Gc {} => todo!("CM+GC"),
1827 DataModel::LinearMemory(opts) => opts,
1828 }
1829 };
1830
1831 self.convert_src_len_to_dst(src.len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
1834 let dst_len = self.local_tee_new_tmp(dst_mem_opts.ptr());
1835 if dst_enc.width() > 1 {
1836 assert_eq!(dst_enc.width(), 2);
1837 self.ptr_uconst(dst_mem_opts, 1);
1838 self.ptr_shl(dst_mem_opts);
1839 }
1840 let dst_byte_len = self.local_set_new_tmp(dst_mem_opts.ptr());
1841
1842 let dst = {
1845 let dst_mem = self.malloc(
1846 dst_opts,
1847 AllocSize::Local(dst_byte_len.idx),
1848 dst_enc.align().into(),
1849 Trap::StringOutOfBounds,
1850 );
1851 WasmString {
1852 ptr: dst_mem.addr,
1853 len: dst_len,
1854 opts: dst_opts,
1855 }
1856 };
1857
1858 let op = if src_enc == dst_enc {
1862 Transcode::Copy(src_enc)
1863 } else {
1864 assert_eq!(src_enc, FE::Latin1);
1865 assert_eq!(dst_enc, FE::Utf16);
1866 Transcode::Latin1ToUtf16
1867 };
1868 let transcode = self.transcoder(src, &dst, op);
1869 self.instruction(LocalGet(src.ptr.idx));
1870 self.instruction(LocalGet(src.len.idx));
1871 self.instruction(LocalGet(dst.ptr.idx));
1872 self.instruction(Call(transcode.as_u32()));
1873
1874 self.free_temp_local(dst_byte_len);
1875
1876 dst
1877 }
1878
1879 fn string_deflate_to_utf8<'c>(
1892 &mut self,
1893 src: &WasmString<'_>,
1894 src_enc: FE,
1895 dst_opts: &'c Options,
1896 ) -> WasmString<'c> {
1897 let src_mem_opts = match &src.opts.data_model {
1898 DataModel::Gc {} => todo!("CM+GC"),
1899 DataModel::LinearMemory(opts) => opts,
1900 };
1901 let dst_mem_opts = match &dst_opts.data_model {
1902 DataModel::Gc {} => todo!("CM+GC"),
1903 DataModel::LinearMemory(opts) => opts,
1904 };
1905
1906 self.validate_string_length(src, src_enc);
1907
1908 self.convert_src_len_to_dst(
1912 src.len.idx,
1913 src.opts.data_model.unwrap_memory().ptr(),
1914 dst_opts.data_model.unwrap_memory().ptr(),
1915 );
1916 let dst_len = self.local_tee_new_tmp(dst_opts.data_model.unwrap_memory().ptr());
1917 let dst_byte_len = self.local_set_new_tmp(dst_opts.data_model.unwrap_memory().ptr());
1918
1919 let dst = {
1920 let dst_mem = self.malloc(
1921 dst_opts,
1922 AllocSize::Local(dst_byte_len.idx),
1923 1,
1924 Trap::StringOutOfBounds,
1925 );
1926 WasmString {
1927 ptr: dst_mem.addr,
1928 len: dst_len,
1929 opts: dst_opts,
1930 }
1931 };
1932
1933 let op = match src_enc {
1935 FE::Latin1 => Transcode::Latin1ToUtf8,
1936 FE::Utf16 => Transcode::Utf16ToUtf8,
1937 FE::Utf8 => unreachable!(),
1938 };
1939 let transcode = self.transcoder(src, &dst, op);
1940 self.instruction(LocalGet(src.ptr.idx));
1941 self.instruction(LocalGet(src.len.idx));
1942 self.instruction(LocalGet(dst.ptr.idx));
1943 self.instruction(LocalGet(dst_byte_len.idx));
1944 self.instruction(I32Const(1)); self.instruction(Call(transcode.as_u32()));
1946 self.instruction(LocalSet(dst.len.idx));
1947 let src_len_tmp = self.local_set_new_tmp(src.opts.data_model.unwrap_memory().ptr());
1948
1949 self.instruction(LocalGet(src_len_tmp.idx));
1953 self.instruction(LocalGet(src.len.idx));
1954 self.ptr_ne(src_mem_opts);
1955 self.instruction(If(BlockType::Empty));
1956
1957 let factor = match src_enc {
1960 FE::Latin1 => 2,
1961 FE::Utf16 => 3,
1962 _ => unreachable!(),
1963 };
1964 self.validate_string_length_u8(src, factor);
1965 self.convert_src_len_to_dst(
1966 src.len.idx,
1967 src.opts.data_model.unwrap_memory().ptr(),
1968 dst_opts.data_model.unwrap_memory().ptr(),
1969 );
1970 self.ptr_uconst(dst_mem_opts, factor.into());
1971 self.ptr_mul(dst_mem_opts);
1972 let new_byte_len = self.local_set_new_tmp(dst_mem_opts.ptr());
1973
1974 self.realloc(
1978 dst_opts,
1979 &dst.ptr,
1980 AllocSize::Local(dst_byte_len.idx),
1981 AllocSize::Local(new_byte_len.idx),
1982 1,
1983 Trap::StringOutOfBounds,
1984 );
1985 self.instruction(LocalGet(new_byte_len.idx));
1986 self.instruction(LocalSet(dst_byte_len.idx));
1987 self.free_temp_local(new_byte_len);
1988
1989 self.instruction(LocalGet(src.ptr.idx));
1994 self.instruction(LocalGet(src_len_tmp.idx));
1995 if let FE::Utf16 = src_enc {
1996 self.ptr_uconst(src_mem_opts, 1);
1997 self.ptr_shl(src_mem_opts);
1998 }
1999 self.ptr_add(src_mem_opts);
2000 self.instruction(LocalGet(src.len.idx));
2001 self.instruction(LocalGet(src_len_tmp.idx));
2002 self.ptr_sub(src_mem_opts);
2003 self.instruction(LocalGet(dst.ptr.idx));
2004 self.instruction(LocalGet(dst.len.idx));
2005 self.ptr_add(dst_mem_opts);
2006 self.instruction(LocalGet(dst_byte_len.idx));
2007 self.instruction(LocalGet(dst.len.idx));
2008 self.ptr_sub(dst_mem_opts);
2009 self.instruction(I32Const(0)); self.instruction(Call(transcode.as_u32()));
2011
2012 self.instruction(LocalGet(dst.len.idx));
2016 self.ptr_add(dst_mem_opts);
2017 self.instruction(LocalSet(dst.len.idx));
2018
2019 if self.module.tunables.debug_adapter_modules {
2022 self.instruction(LocalGet(src.len.idx));
2023 self.instruction(LocalGet(src_len_tmp.idx));
2024 self.ptr_sub(src_mem_opts);
2025 self.ptr_ne(src_mem_opts);
2026 self.instruction(If(BlockType::Empty));
2027 self.trap(Trap::DebugAssertStringEncodingFinished);
2028 self.instruction(End);
2029 } else {
2030 self.instruction(Drop);
2031 }
2032
2033 self.instruction(LocalGet(dst.len.idx));
2035 self.instruction(LocalGet(dst_byte_len.idx));
2036 self.ptr_ne(dst_mem_opts);
2037 self.instruction(If(BlockType::Empty));
2038 self.realloc(
2039 dst_opts,
2040 &dst.ptr,
2041 AllocSize::Local(dst_byte_len.idx),
2042 AllocSize::Local(dst.len.idx),
2043 1,
2044 Trap::StringOutOfBounds,
2045 );
2046 self.instruction(End);
2047
2048 if self.module.tunables.debug_adapter_modules {
2051 self.instruction(Else);
2052
2053 self.instruction(LocalGet(dst.len.idx));
2054 self.instruction(LocalGet(dst_byte_len.idx));
2055 self.ptr_ne(dst_mem_opts);
2056 self.instruction(If(BlockType::Empty));
2057 self.trap(Trap::DebugAssertStringEncodingFinished);
2058 self.instruction(End);
2059 }
2060
2061 self.instruction(End); self.free_temp_local(src_len_tmp);
2064 self.free_temp_local(dst_byte_len);
2065
2066 dst
2067 }
2068
2069 fn string_utf8_to_utf16<'c>(
2084 &mut self,
2085 src: &WasmString<'_>,
2086 dst_opts: &'c Options,
2087 ) -> WasmString<'c> {
2088 let src_mem_opts = match &src.opts.data_model {
2089 DataModel::Gc {} => todo!("CM+GC"),
2090 DataModel::LinearMemory(opts) => opts,
2091 };
2092 let dst_mem_opts = match &dst_opts.data_model {
2093 DataModel::Gc {} => todo!("CM+GC"),
2094 DataModel::LinearMemory(opts) => opts,
2095 };
2096
2097 self.validate_string_length(src, FE::Utf16);
2098 self.convert_src_len_to_dst(
2099 src.len.idx,
2100 src_mem_opts.ptr(),
2101 dst_opts.data_model.unwrap_memory().ptr(),
2102 );
2103 let dst_len = self.local_tee_new_tmp(dst_opts.data_model.unwrap_memory().ptr());
2104 self.ptr_uconst(dst_mem_opts, 1);
2105 self.ptr_shl(dst_mem_opts);
2106 let dst_byte_len = self.local_set_new_tmp(dst_opts.data_model.unwrap_memory().ptr());
2107 let dst = {
2108 let dst_mem = self.malloc(
2109 dst_opts,
2110 AllocSize::Local(dst_byte_len.idx),
2111 2,
2112 Trap::StringOutOfBounds,
2113 );
2114 WasmString {
2115 ptr: dst_mem.addr,
2116 len: dst_len,
2117 opts: dst_opts,
2118 }
2119 };
2120
2121 let transcode = self.transcoder(src, &dst, Transcode::Utf8ToUtf16);
2122 self.instruction(LocalGet(src.ptr.idx));
2123 self.instruction(LocalGet(src.len.idx));
2124 self.instruction(LocalGet(dst.ptr.idx));
2125 self.instruction(Call(transcode.as_u32()));
2126 self.instruction(LocalSet(dst.len.idx));
2127
2128 self.convert_src_len_to_dst(src.len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2136 self.instruction(LocalGet(dst.len.idx));
2137 self.ptr_ne(dst_mem_opts);
2138 self.instruction(If(BlockType::Empty));
2139 self.realloc(
2140 dst.opts,
2141 &dst.ptr,
2142 AllocSize::Local(dst_byte_len.idx),
2143 AllocSize::DoubleLocal(dst.len.idx),
2144 2,
2145 Trap::StringOutOfBounds,
2146 );
2147 self.instruction(End); self.free_temp_local(dst_byte_len);
2150
2151 dst
2152 }
2153
2154 fn string_compact_utf16_to_compact<'c>(
2168 &mut self,
2169 src: &WasmString<'_>,
2170 dst_opts: &'c Options,
2171 ) -> WasmString<'c> {
2172 let src_mem_opts = match &src.opts.data_model {
2173 DataModel::Gc {} => todo!("CM+GC"),
2174 DataModel::LinearMemory(opts) => opts,
2175 };
2176 let dst_mem_opts = match &dst_opts.data_model {
2177 DataModel::Gc {} => todo!("CM+GC"),
2178 DataModel::LinearMemory(opts) => opts,
2179 };
2180
2181 self.validate_string_length(src, FE::Utf16);
2182 self.convert_src_len_to_dst(src.len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2183 let dst_len = self.local_tee_new_tmp(dst_mem_opts.ptr());
2184 self.ptr_uconst(dst_mem_opts, 1);
2185 self.ptr_shl(dst_mem_opts);
2186 let dst_byte_len = self.local_set_new_tmp(dst_mem_opts.ptr());
2187 let dst = {
2188 let dst_mem = self.malloc(
2189 dst_opts,
2190 AllocSize::Local(dst_byte_len.idx),
2191 2,
2192 Trap::StringOutOfBounds,
2193 );
2194 WasmString {
2195 ptr: dst_mem.addr,
2196 len: dst_len,
2197 opts: dst_opts,
2198 }
2199 };
2200
2201 self.convert_src_len_to_dst(
2202 dst_byte_len.idx,
2203 dst.opts.data_model.unwrap_memory().ptr(),
2204 src_mem_opts.ptr(),
2205 );
2206 let src_byte_len = self.local_set_new_tmp(src_mem_opts.ptr());
2207
2208 let transcode = self.transcoder(src, &dst, Transcode::Utf16ToCompactProbablyUtf16);
2209 self.instruction(LocalGet(src.ptr.idx));
2210 self.instruction(LocalGet(src.len.idx));
2211 self.instruction(LocalGet(dst.ptr.idx));
2212 self.instruction(Call(transcode.as_u32()));
2213 self.instruction(LocalSet(dst.len.idx));
2214
2215 if self.module.tunables.debug_adapter_modules {
2218 self.instruction(LocalGet(dst.len.idx));
2219 self.ptr_uconst(dst_mem_opts, !UTF16_TAG);
2220 self.ptr_and(dst_mem_opts);
2221 self.convert_src_len_to_dst(src.len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2222 self.ptr_ne(dst_mem_opts);
2223 self.instruction(If(BlockType::Empty));
2224 self.trap(Trap::DebugAssertEqualCodeUnits);
2225 self.instruction(End);
2226 }
2227
2228 self.instruction(LocalGet(dst.len.idx));
2232 self.ptr_uconst(dst_mem_opts, UTF16_TAG);
2233 self.ptr_and(dst_mem_opts);
2234 self.ptr_br_if(dst_mem_opts, 0);
2235
2236 self.realloc(
2238 dst.opts,
2239 &dst.ptr,
2240 AllocSize::Local(dst_byte_len.idx),
2241 AllocSize::Local(dst.len.idx),
2242 2,
2243 Trap::StringOutOfBounds,
2244 );
2245
2246 self.free_temp_local(dst_byte_len);
2247 self.free_temp_local(src_byte_len);
2248
2249 dst
2250 }
2251
2252 fn string_to_compact<'c>(
2259 &mut self,
2260 src: &WasmString<'_>,
2261 src_enc: FE,
2262 dst_opts: &'c Options,
2263 ) -> WasmString<'c> {
2264 let src_mem_opts = match &src.opts.data_model {
2265 DataModel::Gc {} => todo!("CM+GC"),
2266 DataModel::LinearMemory(opts) => opts,
2267 };
2268 let dst_mem_opts = match &dst_opts.data_model {
2269 DataModel::Gc {} => todo!("CM+GC"),
2270 DataModel::LinearMemory(opts) => opts,
2271 };
2272
2273 self.validate_string_length(src, src_enc);
2274
2275 self.convert_src_len_to_dst(src.len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2276 let dst_len = self.local_tee_new_tmp(dst_mem_opts.ptr());
2277 let dst_byte_len = self.local_set_new_tmp(dst_mem_opts.ptr());
2278 let dst = {
2279 let dst_mem = self.malloc(
2280 dst_opts,
2281 AllocSize::Local(dst_byte_len.idx),
2282 2,
2283 Trap::StringOutOfBounds,
2284 );
2285 WasmString {
2286 ptr: dst_mem.addr,
2287 len: dst_len,
2288 opts: dst_opts,
2289 }
2290 };
2291
2292 let (latin1, utf16) = match src_enc {
2296 FE::Utf8 => (Transcode::Utf8ToLatin1, Transcode::Utf8ToCompactUtf16),
2297 FE::Utf16 => (Transcode::Utf16ToLatin1, Transcode::Utf16ToCompactUtf16),
2298 FE::Latin1 => unreachable!(),
2299 };
2300 let transcode_latin1 = self.transcoder(src, &dst, latin1);
2301 let transcode_utf16 = self.transcoder(src, &dst, utf16);
2302 self.instruction(LocalGet(src.ptr.idx));
2303 self.instruction(LocalGet(src.len.idx));
2304 self.instruction(LocalGet(dst.ptr.idx));
2305 self.instruction(Call(transcode_latin1.as_u32()));
2306 self.instruction(LocalSet(dst.len.idx));
2307 let src_len_tmp = self.local_set_new_tmp(src_mem_opts.ptr());
2308
2309 self.instruction(LocalGet(src_len_tmp.idx));
2312 self.instruction(LocalGet(src.len.idx));
2313 self.ptr_eq(src_mem_opts);
2314 self.instruction(If(BlockType::Empty)); self.instruction(LocalGet(dst_byte_len.idx));
2320 self.instruction(LocalGet(dst.len.idx));
2321 self.ptr_ne(dst_mem_opts);
2322 self.instruction(If(BlockType::Empty));
2323 self.realloc(
2324 dst.opts,
2325 &dst.ptr,
2326 AllocSize::Local(dst_byte_len.idx),
2327 AllocSize::Local(dst.len.idx),
2328 2,
2329 Trap::StringOutOfBounds,
2330 );
2331 self.instruction(End);
2332
2333 self.instruction(Else); if src_enc.width() == 1 {
2342 self.validate_string_length_u8(src, 2);
2343 }
2344
2345 self.convert_src_len_to_dst(src.len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2348 self.ptr_uconst(dst_mem_opts, 1);
2349 self.ptr_shl(dst_mem_opts);
2350 let new_byte_len = self.local_set_new_tmp(dst_mem_opts.ptr());
2351 self.realloc(
2352 dst.opts,
2353 &dst.ptr,
2354 AllocSize::Local(dst_byte_len.idx),
2355 AllocSize::Local(new_byte_len.idx),
2356 2,
2357 Trap::StringOutOfBounds,
2358 );
2359 self.instruction(LocalGet(new_byte_len.idx));
2360 self.instruction(LocalSet(dst_byte_len.idx));
2361 self.free_temp_local(new_byte_len);
2362
2363 self.instruction(LocalGet(src.ptr.idx));
2367 self.instruction(LocalGet(src_len_tmp.idx));
2368 if let FE::Utf16 = src_enc {
2369 self.ptr_uconst(src_mem_opts, 1);
2370 self.ptr_shl(src_mem_opts);
2371 }
2372 self.ptr_add(src_mem_opts);
2373 self.instruction(LocalGet(src.len.idx));
2374 self.instruction(LocalGet(src_len_tmp.idx));
2375 self.ptr_sub(src_mem_opts);
2376 self.instruction(LocalGet(dst.ptr.idx));
2377 self.convert_src_len_to_dst(src.len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2378 self.instruction(LocalGet(dst.len.idx));
2379 self.instruction(Call(transcode_utf16.as_u32()));
2380 self.instruction(LocalSet(dst.len.idx));
2381
2382 self.instruction(LocalGet(dst.len.idx));
2390 self.convert_src_len_to_dst(src.len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2391 self.ptr_ne(dst_mem_opts);
2392 self.instruction(If(BlockType::Empty));
2393 self.realloc(
2394 dst.opts,
2395 &dst.ptr,
2396 AllocSize::Local(dst_byte_len.idx),
2397 AllocSize::DoubleLocal(dst.len.idx),
2398 2,
2399 Trap::StringOutOfBounds,
2400 );
2401 self.instruction(End);
2402
2403 self.instruction(LocalGet(dst.len.idx));
2405 self.ptr_uconst(dst_mem_opts, UTF16_TAG);
2406 self.ptr_or(dst_mem_opts);
2407 self.instruction(LocalSet(dst.len.idx));
2408
2409 self.instruction(End); self.free_temp_local(src_len_tmp);
2412 self.free_temp_local(dst_byte_len);
2413
2414 dst
2415 }
2416
2417 fn validate_string_length(&mut self, src: &WasmString<'_>, dst: FE) {
2418 self.validate_string_length_u8(src, dst.width())
2419 }
2420
2421 fn validate_string_length_u8(&mut self, s: &WasmString<'_>, dst: u8) {
2422 let mem_opts = match &s.opts.data_model {
2423 DataModel::Gc {} => todo!("CM+GC"),
2424 DataModel::LinearMemory(opts) => opts,
2425 };
2426
2427 self.instruction(LocalGet(s.len.idx));
2430 let max = MAX_STRING_BYTE_LENGTH / u32::from(dst);
2431 self.ptr_uconst(mem_opts, max);
2432 self.ptr_gt_u(mem_opts);
2433 self.instruction(If(BlockType::Empty));
2434 self.trap(Trap::StringOutOfBounds);
2435 self.instruction(End);
2436 }
2437
2438 fn transcoder(
2439 &mut self,
2440 src: &WasmString<'_>,
2441 dst: &WasmString<'_>,
2442 op: Transcode,
2443 ) -> FuncIndex {
2444 match (src.opts.data_model, dst.opts.data_model) {
2445 (DataModel::Gc {}, _) | (_, DataModel::Gc {}) => {
2446 todo!("CM+GC")
2447 }
2448 (
2449 DataModel::LinearMemory(LinearMemoryOptions {
2450 memory: Some((src_mem, src_ty)),
2451 realloc: _,
2452 }),
2453 DataModel::LinearMemory(LinearMemoryOptions {
2454 memory: Some((dst_mem, dst_ty)),
2455 realloc: _,
2456 }),
2457 ) => self.module.import_transcoder(Transcoder {
2458 from_memory: src_mem,
2459 from_memory64: src_ty.idx_type == IndexType::I64,
2460 to_memory: dst_mem,
2461 to_memory64: dst_ty.idx_type == IndexType::I64,
2462 op,
2463 }),
2464 (DataModel::LinearMemory(LinearMemoryOptions { memory: None, .. }), _)
2465 | (_, DataModel::LinearMemory(LinearMemoryOptions { memory: None, .. })) => {
2466 unreachable!()
2467 }
2468 }
2469 }
2470
2471 fn begin_translate_sequence<'c>(
2480 &mut self,
2481 src: &Source<'c>,
2482 dst: &Destination<'c>,
2483 src_element_size: u32,
2484 src_element_align: u32,
2485 dst_element_size: u32,
2486 dst_element_align: u32,
2487 ) -> SequenceTranslation<'c> {
2488 let src_mem_opts = match &src.opts().data_model {
2489 DataModel::Gc {} => todo!("CM+GC"),
2490 DataModel::LinearMemory(opts) => opts,
2491 };
2492 let dst_mem_opts = match &dst.opts().data_model {
2493 DataModel::Gc {} => todo!("CM+GC"),
2494 DataModel::LinearMemory(opts) => opts,
2495 };
2496
2497 let src_opts = src.opts();
2498 let dst_opts = dst.opts();
2499
2500 match src {
2505 Source::Stack(s) => {
2506 assert_eq!(s.locals.len(), 2);
2507 self.stack_get(&s.slice(0..1), src_mem_opts.ptr());
2508 self.stack_get(&s.slice(1..2), src_mem_opts.ptr());
2509 }
2510 Source::Memory(mem) => {
2511 self.ptr_load(mem);
2512 self.ptr_load(&mem.bump(src_mem_opts.ptr_size().into()));
2513 }
2514 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
2515 }
2516 let src_len = self.local_set_new_tmp(src_mem_opts.ptr());
2517 let src_ptr = self.local_set_new_tmp(src_mem_opts.ptr());
2518
2519 let src_byte_len =
2521 self.calculate_list_byte_len(src_mem_opts, src_len.idx, src_element_size);
2522 let dst_byte_len = if src_element_size == dst_element_size {
2523 self.convert_src_len_to_dst(src_byte_len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2524 self.local_set_new_tmp(dst_mem_opts.ptr())
2525 } else if src_mem_opts.ptr() == dst_mem_opts.ptr() {
2526 self.calculate_list_byte_len(dst_mem_opts, src_len.idx, dst_element_size)
2527 } else {
2528 self.convert_src_len_to_dst(src_len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2529 let tmp = self.local_set_new_tmp(dst_mem_opts.ptr());
2530 let ret = self.calculate_list_byte_len(dst_mem_opts, tmp.idx, dst_element_size);
2531 self.free_temp_local(tmp);
2532 ret
2533 };
2534
2535 let src_mem = self.memory_operand(
2538 src_opts,
2539 src_ptr,
2540 AllocSize::Local(src_byte_len.idx),
2541 src_element_align,
2542 Trap::ListOutOfBounds,
2543 );
2544
2545 let dst_mem = self.malloc(
2550 dst_opts,
2551 AllocSize::Local(dst_byte_len.idx),
2552 dst_element_align,
2553 Trap::ListOutOfBounds,
2554 );
2555
2556 self.free_temp_local(src_byte_len);
2557 self.free_temp_local(dst_byte_len);
2558
2559 let loop_state = if src_element_size > 0 || dst_element_size > 0 {
2563 self.instruction(Block(BlockType::Empty));
2564
2565 self.instruction(LocalGet(src_len.idx));
2567 let remaining = self.local_tee_new_tmp(src_mem_opts.ptr());
2568 self.ptr_eqz(src_mem_opts);
2569 self.instruction(BrIf(0));
2570
2571 self.instruction(LocalGet(src_mem.addr.idx));
2573 let cur_src_ptr = self.local_set_new_tmp(src_mem_opts.ptr());
2574 self.instruction(LocalGet(dst_mem.addr.idx));
2575 let cur_dst_ptr = self.local_set_new_tmp(dst_mem_opts.ptr());
2576
2577 self.instruction(Loop(BlockType::Empty));
2578
2579 Some(SequenceLoopState {
2580 remaining,
2581 cur_src_ptr,
2582 cur_dst_ptr,
2583 })
2584 } else {
2585 None
2586 };
2587
2588 SequenceTranslation {
2589 src_len,
2590 src_mem,
2591 dst_mem,
2592 src_opts,
2593 dst_opts,
2594 src_mem_opts,
2595 dst_mem_opts,
2596 loop_state,
2597 }
2598 }
2599
2600 fn end_translate_sequence(&mut self, seq: SequenceTranslation<'_>, dst: &Destination) {
2606 if let Some(loop_state) = seq.loop_state {
2607 self.instruction(LocalGet(loop_state.remaining.idx));
2610 self.ptr_iconst(seq.src_mem_opts, -1);
2611 self.ptr_add(seq.src_mem_opts);
2612 self.instruction(LocalTee(loop_state.remaining.idx));
2613 self.ptr_br_if(seq.src_mem_opts, 0);
2614 self.instruction(End); self.instruction(End); self.free_temp_local(loop_state.cur_dst_ptr);
2618 self.free_temp_local(loop_state.cur_src_ptr);
2619 self.free_temp_local(loop_state.remaining);
2620 }
2621
2622 match dst {
2624 Destination::Stack(s, _) => {
2625 self.instruction(LocalGet(seq.dst_mem.addr.idx));
2626 self.stack_set(&s[..1], seq.dst_mem_opts.ptr());
2627 self.convert_src_len_to_dst(
2628 seq.src_len.idx,
2629 seq.src_mem_opts.ptr(),
2630 seq.dst_mem_opts.ptr(),
2631 );
2632 self.stack_set(&s[1..], seq.dst_mem_opts.ptr());
2633 }
2634 Destination::Memory(mem) => {
2635 self.instruction(LocalGet(mem.addr.idx));
2636 self.instruction(LocalGet(seq.dst_mem.addr.idx));
2637 self.ptr_store(mem);
2638 self.instruction(LocalGet(mem.addr.idx));
2639 self.convert_src_len_to_dst(
2640 seq.src_len.idx,
2641 seq.src_mem_opts.ptr(),
2642 seq.dst_mem_opts.ptr(),
2643 );
2644 self.ptr_store(&mem.bump(seq.dst_mem_opts.ptr_size().into()));
2645 }
2646 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
2647 }
2648
2649 self.free_temp_local(seq.src_len);
2650 self.free_temp_local(seq.src_mem.addr);
2651 self.free_temp_local(seq.dst_mem.addr);
2652 }
2653
2654 fn translate_list(
2655 &mut self,
2656 src_ty: TypeListIndex,
2657 src: &Source<'_>,
2658 dst_ty: &InterfaceType,
2659 dst: &Destination,
2660 ) {
2661 let src_mem_opts = match &src.opts().data_model {
2662 DataModel::Gc {} => todo!("CM+GC"),
2663 DataModel::LinearMemory(opts) => opts,
2664 };
2665 let dst_mem_opts = match &dst.opts().data_model {
2666 DataModel::Gc {} => todo!("CM+GC"),
2667 DataModel::LinearMemory(opts) => opts,
2668 };
2669
2670 let src_element_ty = &self.types[src_ty].element;
2671 let dst_element_ty = match dst_ty {
2672 InterfaceType::List(r) => &self.types[*r].element,
2673 _ => panic!("expected a list"),
2674 };
2675 let (src_size, src_align) = self.types.size_align(src_mem_opts, src_element_ty);
2676 let (dst_size, dst_align) = self.types.size_align(dst_mem_opts, dst_element_ty);
2677
2678 let seq = self.begin_translate_sequence(src, dst, src_size, src_align, dst_size, dst_align);
2679
2680 if let Some(ref loop_state) = seq.loop_state {
2681 let element_src = Source::Memory(Memory {
2682 opts: seq.src_opts,
2683 offset: 0,
2684 addr: TempLocal::new(loop_state.cur_src_ptr.idx, loop_state.cur_src_ptr.ty),
2685 });
2686 let element_dst = Destination::Memory(Memory {
2687 opts: seq.dst_opts,
2688 offset: 0,
2689 addr: TempLocal::new(loop_state.cur_dst_ptr.idx, loop_state.cur_dst_ptr.ty),
2690 });
2691 self.translate(src_element_ty, &element_src, dst_element_ty, &element_dst);
2692
2693 if src_size > 0 {
2694 self.instruction(LocalGet(loop_state.cur_src_ptr.idx));
2695 self.ptr_uconst(src_mem_opts, src_size);
2696 self.ptr_add(src_mem_opts);
2697 self.instruction(LocalSet(loop_state.cur_src_ptr.idx));
2698 }
2699 if dst_size > 0 {
2700 self.instruction(LocalGet(loop_state.cur_dst_ptr.idx));
2701 self.ptr_uconst(dst_mem_opts, dst_size);
2702 self.ptr_add(dst_mem_opts);
2703 self.instruction(LocalSet(loop_state.cur_dst_ptr.idx));
2704 }
2705 }
2706
2707 self.end_translate_sequence(seq, dst);
2708 }
2709
2710 fn translate_map(
2716 &mut self,
2717 src_ty: TypeMapIndex,
2718 src: &Source<'_>,
2719 dst_ty: &InterfaceType,
2720 dst: &Destination,
2721 ) {
2722 let src_mem_opts = match &src.opts().data_model {
2723 DataModel::Gc {} => todo!("CM+GC"),
2724 DataModel::LinearMemory(opts) => opts,
2725 };
2726 let dst_mem_opts = match &dst.opts().data_model {
2727 DataModel::Gc {} => todo!("CM+GC"),
2728 DataModel::LinearMemory(opts) => opts,
2729 };
2730
2731 let src_map_ty = &self.types[src_ty];
2732 let dst_map_ty = match dst_ty {
2733 InterfaceType::Map(r) => &self.types[*r],
2734 _ => panic!("expected a map"),
2735 };
2736
2737 let src_key_abi = self.types.canonical_abi(&src_map_ty.key);
2739 let src_value_abi = self.types.canonical_abi(&src_map_ty.value);
2740 let src_entry_abi = CanonicalAbiInfo::record([src_key_abi, src_value_abi].into_iter());
2741 let (src_tuple_size, src_entry_align) = src_mem_opts.sizealign(&src_entry_abi);
2742 let src_value_offset = {
2743 let mut offset = 0u32;
2744 if src_mem_opts.memory64() {
2745 src_key_abi.next_field64(&mut offset);
2746 src_value_abi.next_field64(&mut offset)
2747 } else {
2748 src_key_abi.next_field32(&mut offset);
2749 src_value_abi.next_field32(&mut offset)
2750 }
2751 };
2752
2753 let dst_key_abi = self.types.canonical_abi(&dst_map_ty.key);
2754 let dst_value_abi = self.types.canonical_abi(&dst_map_ty.value);
2755 let dst_entry_abi = CanonicalAbiInfo::record([dst_key_abi, dst_value_abi].into_iter());
2756 let (dst_tuple_size, dst_entry_align) = dst_mem_opts.sizealign(&dst_entry_abi);
2757 let dst_value_offset = {
2758 let mut offset = 0u32;
2759 if dst_mem_opts.memory64() {
2760 dst_key_abi.next_field64(&mut offset);
2761 dst_value_abi.next_field64(&mut offset)
2762 } else {
2763 dst_key_abi.next_field32(&mut offset);
2764 dst_value_abi.next_field32(&mut offset)
2765 }
2766 };
2767
2768 let seq = self.begin_translate_sequence(
2769 src,
2770 dst,
2771 src_tuple_size,
2772 src_entry_align,
2773 dst_tuple_size,
2774 dst_entry_align,
2775 );
2776
2777 if let Some(ref loop_state) = seq.loop_state {
2778 let key_src = Source::Memory(Memory {
2779 opts: seq.src_opts,
2780 offset: 0,
2781 addr: TempLocal::new(loop_state.cur_src_ptr.idx, src_mem_opts.ptr()),
2782 });
2783 let key_dst = Destination::Memory(Memory {
2784 opts: seq.dst_opts,
2785 offset: 0,
2786 addr: TempLocal::new(loop_state.cur_dst_ptr.idx, dst_mem_opts.ptr()),
2787 });
2788 self.translate(&src_map_ty.key, &key_src, &dst_map_ty.key, &key_dst);
2789
2790 let value_src = Source::Memory(Memory {
2791 opts: seq.src_opts,
2792 offset: src_value_offset,
2793 addr: TempLocal::new(loop_state.cur_src_ptr.idx, src_mem_opts.ptr()),
2794 });
2795 let value_dst = Destination::Memory(Memory {
2796 opts: seq.dst_opts,
2797 offset: dst_value_offset,
2798 addr: TempLocal::new(loop_state.cur_dst_ptr.idx, dst_mem_opts.ptr()),
2799 });
2800 self.translate(&src_map_ty.value, &value_src, &dst_map_ty.value, &value_dst);
2801
2802 if src_tuple_size > 0 {
2804 self.instruction(LocalGet(loop_state.cur_src_ptr.idx));
2805 self.ptr_uconst(src_mem_opts, src_tuple_size);
2806 self.ptr_add(src_mem_opts);
2807 self.instruction(LocalSet(loop_state.cur_src_ptr.idx));
2808 }
2809 if dst_tuple_size > 0 {
2810 self.instruction(LocalGet(loop_state.cur_dst_ptr.idx));
2811 self.ptr_uconst(dst_mem_opts, dst_tuple_size);
2812 self.ptr_add(dst_mem_opts);
2813 self.instruction(LocalSet(loop_state.cur_dst_ptr.idx));
2814 }
2815 }
2816
2817 self.end_translate_sequence(seq, dst);
2818 }
2819
2820 fn calculate_list_byte_len(
2821 &mut self,
2822 opts: &LinearMemoryOptions,
2823 len_local: u32,
2824 elt_size: u32,
2825 ) -> TempLocal {
2826 if elt_size == 0 {
2829 self.ptr_uconst(opts, 0);
2830 return self.local_set_new_tmp(opts.ptr());
2831 }
2832
2833 if elt_size == 1 {
2841 if let ValType::I64 = opts.ptr() {
2842 self.instruction(LocalGet(len_local));
2843 self.instruction(I64Const(32));
2844 self.instruction(I64ShrU);
2845 self.instruction(I32WrapI64);
2846 self.instruction(If(BlockType::Empty));
2847 self.trap(Trap::ListOutOfBounds);
2848 self.instruction(End);
2849 }
2850 self.instruction(LocalGet(len_local));
2851 return self.local_set_new_tmp(opts.ptr());
2852 }
2853
2854 self.instruction(Block(BlockType::Empty));
2859 self.instruction(Block(BlockType::Empty));
2860 self.instruction(LocalGet(len_local));
2861 match opts.ptr() {
2862 ValType::I32 => self.instruction(I64ExtendI32U),
2866
2867 ValType::I64 => {
2871 self.instruction(I64Const(32));
2872 self.instruction(I64ShrU);
2873 self.instruction(I32WrapI64);
2874 self.instruction(BrIf(0));
2875 self.instruction(LocalGet(len_local));
2876 }
2877
2878 _ => unreachable!(),
2879 }
2880
2881 self.instruction(I64Const(elt_size.into()));
2890 self.instruction(I64Mul);
2891 let tmp = self.local_tee_new_tmp(ValType::I64);
2892 self.instruction(I64Const(32));
2895 self.instruction(I64ShrU);
2896 self.instruction(I64Eqz);
2897 self.instruction(BrIf(1));
2898 self.instruction(End);
2899 self.trap(Trap::ListOutOfBounds);
2900 self.instruction(End);
2901
2902 if opts.ptr() == ValType::I64 {
2906 tmp
2907 } else {
2908 self.instruction(LocalGet(tmp.idx));
2909 self.instruction(I32WrapI64);
2910 self.free_temp_local(tmp);
2911 self.local_set_new_tmp(ValType::I32)
2912 }
2913 }
2914
2915 fn convert_src_len_to_dst(
2916 &mut self,
2917 src_len_local: u32,
2918 src_ptr_ty: ValType,
2919 dst_ptr_ty: ValType,
2920 ) {
2921 self.instruction(LocalGet(src_len_local));
2922 match (src_ptr_ty, dst_ptr_ty) {
2923 (ValType::I32, ValType::I64) => self.instruction(I64ExtendI32U),
2924 (ValType::I64, ValType::I32) => self.instruction(I32WrapI64),
2925 (src, dst) => assert_eq!(src, dst),
2926 }
2927 }
2928
2929 fn translate_record(
2930 &mut self,
2931 src_ty: TypeRecordIndex,
2932 src: &Source<'_>,
2933 dst_ty: &InterfaceType,
2934 dst: &Destination,
2935 ) {
2936 let src_ty = &self.types[src_ty];
2937 let dst_ty = match dst_ty {
2938 InterfaceType::Record(r) => &self.types[*r],
2939 _ => panic!("expected a record"),
2940 };
2941
2942 assert_eq!(src_ty.fields.len(), dst_ty.fields.len());
2944
2945 let mut src_fields = HashMap::new();
2949 for (i, src) in src
2950 .record_field_srcs(self.types, src_ty.fields.iter().map(|f| f.ty))
2951 .enumerate()
2952 {
2953 let field = &src_ty.fields[i];
2954 src_fields.insert(&field.name, (src, &field.ty));
2955 }
2956
2957 for (i, dst) in dst
2966 .record_field_dsts(self.types, dst_ty.fields.iter().map(|f| f.ty))
2967 .enumerate()
2968 {
2969 let field = &dst_ty.fields[i];
2970 let (src, src_ty) = &src_fields[&field.name];
2971 self.translate(src_ty, src, &field.ty, &dst);
2972 }
2973 }
2974
2975 fn translate_flags(
2976 &mut self,
2977 src_ty: TypeFlagsIndex,
2978 src: &Source<'_>,
2979 dst_ty: &InterfaceType,
2980 dst: &Destination,
2981 ) {
2982 let src_ty = &self.types[src_ty];
2983 let dst_ty = match dst_ty {
2984 InterfaceType::Flags(r) => &self.types[*r],
2985 _ => panic!("expected a record"),
2986 };
2987
2988 assert_eq!(src_ty.names, dst_ty.names);
2996 let cnt = src_ty.names.len();
2997 match FlagsSize::from_count(cnt) {
2998 FlagsSize::Size0 => {}
2999 FlagsSize::Size1 => {
3000 let mask = if cnt == 8 { 0xff } else { (1 << cnt) - 1 };
3001 self.convert_u8_mask(src, dst, mask);
3002 }
3003 FlagsSize::Size2 => {
3004 let mask = if cnt == 16 { 0xffff } else { (1 << cnt) - 1 };
3005 self.convert_u16_mask(src, dst, mask);
3006 }
3007 FlagsSize::Size4Plus(n) => {
3008 let srcs = src.record_field_srcs(self.types, (0..n).map(|_| InterfaceType::U32));
3009 let dsts = dst.record_field_dsts(self.types, (0..n).map(|_| InterfaceType::U32));
3010 let n = usize::from(n);
3011 for (i, (src, dst)) in srcs.zip(dsts).enumerate() {
3012 let mask = if i == n - 1 && (cnt % 32 != 0) {
3013 (1 << (cnt % 32)) - 1
3014 } else {
3015 0xffffffff
3016 };
3017 self.convert_u32_mask(&src, &dst, mask);
3018 }
3019 }
3020 }
3021 }
3022
3023 fn translate_tuple(
3024 &mut self,
3025 src_ty: TypeTupleIndex,
3026 src: &Source<'_>,
3027 dst_ty: &InterfaceType,
3028 dst: &Destination,
3029 ) {
3030 let src_ty = &self.types[src_ty];
3031 let dst_ty = match dst_ty {
3032 InterfaceType::Tuple(t) => &self.types[*t],
3033 _ => panic!("expected a tuple"),
3034 };
3035
3036 assert_eq!(src_ty.types.len(), dst_ty.types.len());
3038
3039 let srcs = src
3040 .record_field_srcs(self.types, src_ty.types.iter().copied())
3041 .zip(src_ty.types.iter());
3042 let dsts = dst
3043 .record_field_dsts(self.types, dst_ty.types.iter().copied())
3044 .zip(dst_ty.types.iter());
3045 for ((src, src_ty), (dst, dst_ty)) in srcs.zip(dsts) {
3046 self.translate(src_ty, &src, dst_ty, &dst);
3047 }
3048 }
3049
3050 fn translate_fixed_length_list(
3051 &mut self,
3052 src_ty: TypeFixedLengthListIndex,
3053 src: &Source<'_>,
3054 dst_ty: &InterfaceType,
3055 dst: &Destination,
3056 ) {
3057 let src_ty = &self.types[src_ty];
3058 let dst_ty = match dst_ty {
3059 InterfaceType::FixedLengthList(t) => &self.types[*t],
3060 _ => panic!("expected a fixed size list"),
3061 };
3062
3063 assert_eq!(src_ty.size, dst_ty.size);
3065
3066 match (&src, &dst) {
3067 (Source::Memory(src_mem), Destination::Memory(dst_mem)) => {
3069 let src_mem_opts = match &src_mem.opts.data_model {
3070 DataModel::Gc {} => todo!("CM+GC"),
3071 DataModel::LinearMemory(opts) => opts,
3072 };
3073 let dst_mem_opts = match &dst_mem.opts.data_model {
3074 DataModel::Gc {} => todo!("CM+GC"),
3075 DataModel::LinearMemory(opts) => opts,
3076 };
3077 let src_element_bytes = self.types.size_align(src_mem_opts, &src_ty.element).0;
3078 let dst_element_bytes = self.types.size_align(dst_mem_opts, &dst_ty.element).0;
3079 assert_ne!(src_element_bytes, 0);
3080 assert_ne!(dst_element_bytes, 0);
3081
3082 self.instruction(LocalGet(src_mem.addr.idx));
3085 if src_mem.offset != 0 {
3086 self.ptr_uconst(src_mem_opts, src_mem.offset);
3087 self.ptr_add(src_mem_opts);
3088 }
3089 let cur_src_ptr = self.local_set_new_tmp(src_mem_opts.ptr());
3090 self.instruction(LocalGet(dst_mem.addr.idx));
3091 if dst_mem.offset != 0 {
3092 self.ptr_uconst(dst_mem_opts, dst_mem.offset);
3093 self.ptr_add(dst_mem_opts);
3094 }
3095 let cur_dst_ptr = self.local_set_new_tmp(dst_mem_opts.ptr());
3096
3097 self.instruction(I32Const(src_ty.size as i32));
3098 let remaining = self.local_set_new_tmp(ValType::I32);
3099
3100 self.instruction(Loop(BlockType::Empty));
3101
3102 let element_src = Source::Memory(Memory {
3104 opts: src_mem.opts,
3105 offset: 0,
3106 addr: TempLocal::new(cur_src_ptr.idx, cur_src_ptr.ty),
3107 });
3108 let element_dst = Destination::Memory(Memory {
3109 opts: dst_mem.opts,
3110 offset: 0,
3111 addr: TempLocal::new(cur_dst_ptr.idx, cur_dst_ptr.ty),
3112 });
3113 self.translate(&src_ty.element, &element_src, &dst_ty.element, &element_dst);
3114
3115 self.instruction(LocalGet(cur_src_ptr.idx));
3117 self.ptr_uconst(src_mem_opts, src_element_bytes);
3118 self.ptr_add(src_mem_opts);
3119 self.instruction(LocalSet(cur_src_ptr.idx));
3120 self.instruction(LocalGet(cur_dst_ptr.idx));
3121 self.ptr_uconst(dst_mem_opts, dst_element_bytes);
3122 self.ptr_add(dst_mem_opts);
3123 self.instruction(LocalSet(cur_dst_ptr.idx));
3124
3125 self.instruction(LocalGet(remaining.idx));
3128 self.ptr_iconst(src_mem_opts, -1);
3129 self.ptr_add(src_mem_opts);
3130 self.instruction(LocalTee(remaining.idx));
3131 self.ptr_br_if(src_mem_opts, 0);
3132 self.instruction(End); self.free_temp_local(cur_dst_ptr);
3135 self.free_temp_local(cur_src_ptr);
3136 self.free_temp_local(remaining);
3137 return;
3138 }
3139 (_, _) => {
3141 assert!(
3143 src_ty.size as usize <= MAX_FLAT_PARAMS
3144 && dst_ty.size as usize <= MAX_FLAT_PARAMS
3145 );
3146 let srcs =
3147 src.record_field_srcs(self.types, (0..src_ty.size).map(|_| src_ty.element));
3148 let dsts =
3149 dst.record_field_dsts(self.types, (0..dst_ty.size).map(|_| dst_ty.element));
3150 for (src, dst) in srcs.zip(dsts) {
3151 self.translate(&src_ty.element, &src, &dst_ty.element, &dst);
3152 }
3153 }
3154 }
3155 }
3156
3157 fn translate_variant(
3158 &mut self,
3159 src_ty: TypeVariantIndex,
3160 src: &Source<'_>,
3161 dst_ty: &InterfaceType,
3162 dst: &Destination,
3163 ) {
3164 let src_ty = &self.types[src_ty];
3165 let dst_ty = match dst_ty {
3166 InterfaceType::Variant(t) => &self.types[*t],
3167 _ => panic!("expected a variant"),
3168 };
3169
3170 let src_info = variant_info(self.types, src_ty.cases.iter().map(|(_, c)| c.as_ref()));
3171 let dst_info = variant_info(self.types, dst_ty.cases.iter().map(|(_, c)| c.as_ref()));
3172
3173 let iter = src_ty
3174 .cases
3175 .iter()
3176 .enumerate()
3177 .map(|(src_i, (src_case, src_case_ty))| {
3178 let dst_i = dst_ty
3179 .cases
3180 .iter()
3181 .position(|(c, _)| c == src_case)
3182 .unwrap();
3183 let dst_case_ty = &dst_ty.cases[dst_i];
3184 let src_i = u32::try_from(src_i).unwrap();
3185 let dst_i = u32::try_from(dst_i).unwrap();
3186 VariantCase {
3187 src_i,
3188 src_ty: src_case_ty.as_ref(),
3189 dst_i,
3190 dst_ty: dst_case_ty.as_ref(),
3191 }
3192 });
3193 self.convert_variant(src, &src_info, dst, &dst_info, iter);
3194 }
3195
3196 fn translate_enum(
3197 &mut self,
3198 src_ty: TypeEnumIndex,
3199 src: &Source<'_>,
3200 dst_ty: &InterfaceType,
3201 dst: &Destination,
3202 ) {
3203 let src_ty = &self.types[src_ty];
3204 let dst_ty = match dst_ty {
3205 InterfaceType::Enum(t) => &self.types[*t],
3206 _ => panic!("expected an option"),
3207 };
3208
3209 debug_assert_eq!(src_ty.info.size, dst_ty.info.size);
3210 debug_assert_eq!(src_ty.names.len(), dst_ty.names.len());
3211 debug_assert!(
3212 src_ty
3213 .names
3214 .iter()
3215 .zip(dst_ty.names.iter())
3216 .all(|(a, b)| a == b)
3217 );
3218
3219 match src {
3221 Source::Stack(s) => self.stack_get(&s.slice(0..1), ValType::I32),
3222 Source::Memory(mem) => match src_ty.info.size {
3223 DiscriminantSize::Size1 => self.i32_load8u(mem),
3224 DiscriminantSize::Size2 => self.i32_load16u(mem),
3225 DiscriminantSize::Size4 => self.i32_load(mem),
3226 },
3227 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
3228 }
3229 let tmp = self.local_tee_new_tmp(ValType::I32);
3230
3231 self.instruction(I32Const(i32::try_from(src_ty.names.len()).unwrap()));
3233 self.instruction(I32GeU);
3234 self.instruction(If(BlockType::Empty));
3235 self.trap(Trap::InvalidDiscriminant);
3236 self.instruction(End);
3237
3238 match dst {
3240 Destination::Stack(stack, _) => {
3241 self.local_get_tmp(&tmp);
3242 self.stack_set(&stack[..1], ValType::I32)
3243 }
3244 Destination::Memory(mem) => {
3245 self.push_dst_addr(dst);
3246 self.local_get_tmp(&tmp);
3247 match dst_ty.info.size {
3248 DiscriminantSize::Size1 => self.i32_store8(mem),
3249 DiscriminantSize::Size2 => self.i32_store16(mem),
3250 DiscriminantSize::Size4 => self.i32_store(mem),
3251 }
3252 }
3253 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
3254 }
3255 self.free_temp_local(tmp);
3256 }
3257
3258 fn translate_option(
3259 &mut self,
3260 src_ty: TypeOptionIndex,
3261 src: &Source<'_>,
3262 dst_ty: &InterfaceType,
3263 dst: &Destination,
3264 ) {
3265 let src_ty = &self.types[src_ty].ty;
3266 let dst_ty = match dst_ty {
3267 InterfaceType::Option(t) => &self.types[*t].ty,
3268 _ => panic!("expected an option"),
3269 };
3270 let src_ty = Some(src_ty);
3271 let dst_ty = Some(dst_ty);
3272
3273 let src_info = variant_info(self.types, [None, src_ty]);
3274 let dst_info = variant_info(self.types, [None, dst_ty]);
3275
3276 self.convert_variant(
3277 src,
3278 &src_info,
3279 dst,
3280 &dst_info,
3281 [
3282 VariantCase {
3283 src_i: 0,
3284 dst_i: 0,
3285 src_ty: None,
3286 dst_ty: None,
3287 },
3288 VariantCase {
3289 src_i: 1,
3290 dst_i: 1,
3291 src_ty,
3292 dst_ty,
3293 },
3294 ]
3295 .into_iter(),
3296 );
3297 }
3298
3299 fn translate_result(
3300 &mut self,
3301 src_ty: TypeResultIndex,
3302 src: &Source<'_>,
3303 dst_ty: &InterfaceType,
3304 dst: &Destination,
3305 ) {
3306 let src_ty = &self.types[src_ty];
3307 let dst_ty = match dst_ty {
3308 InterfaceType::Result(t) => &self.types[*t],
3309 _ => panic!("expected a result"),
3310 };
3311
3312 let src_info = variant_info(self.types, [src_ty.ok.as_ref(), src_ty.err.as_ref()]);
3313 let dst_info = variant_info(self.types, [dst_ty.ok.as_ref(), dst_ty.err.as_ref()]);
3314
3315 self.convert_variant(
3316 src,
3317 &src_info,
3318 dst,
3319 &dst_info,
3320 [
3321 VariantCase {
3322 src_i: 0,
3323 dst_i: 0,
3324 src_ty: src_ty.ok.as_ref(),
3325 dst_ty: dst_ty.ok.as_ref(),
3326 },
3327 VariantCase {
3328 src_i: 1,
3329 dst_i: 1,
3330 src_ty: src_ty.err.as_ref(),
3331 dst_ty: dst_ty.err.as_ref(),
3332 },
3333 ]
3334 .into_iter(),
3335 );
3336 }
3337
3338 fn convert_variant<'c>(
3339 &mut self,
3340 src: &Source<'_>,
3341 src_info: &VariantInfo,
3342 dst: &Destination,
3343 dst_info: &VariantInfo,
3344 src_cases: impl ExactSizeIterator<Item = VariantCase<'c>>,
3345 ) {
3346 let outer_block_ty = match dst {
3349 Destination::Stack(dst_flat, _) => match dst_flat.len() {
3350 0 => BlockType::Empty,
3351 1 => BlockType::Result(dst_flat[0]),
3352 _ => {
3353 let ty = self.module.core_types.function(&[], &dst_flat);
3354 BlockType::FunctionType(ty)
3355 }
3356 },
3357 Destination::Memory(_) => BlockType::Empty,
3358 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
3359 };
3360 self.instruction(Block(outer_block_ty));
3361
3362 let src_cases_len = src_cases.len();
3365 for _ in 0..src_cases_len - 1 {
3366 self.instruction(Block(BlockType::Empty));
3367 }
3368
3369 self.instruction(Block(BlockType::Empty));
3371
3372 self.instruction(Block(BlockType::Empty));
3375
3376 match src {
3378 Source::Stack(s) => self.stack_get(&s.slice(0..1), ValType::I32),
3379 Source::Memory(mem) => match src_info.size {
3380 DiscriminantSize::Size1 => self.i32_load8u(mem),
3381 DiscriminantSize::Size2 => self.i32_load16u(mem),
3382 DiscriminantSize::Size4 => self.i32_load(mem),
3383 },
3384 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
3385 }
3386
3387 let mut targets = Vec::new();
3390 for i in 0..src_cases_len {
3391 targets.push((i + 1) as u32);
3392 }
3393 self.instruction(BrTable(targets[..].into(), 0));
3394 self.instruction(End); self.trap(Trap::InvalidDiscriminant);
3397 self.instruction(End); let src_cases_len = u32::try_from(src_cases_len).unwrap();
3404 for case in src_cases {
3405 let VariantCase {
3406 src_i,
3407 src_ty,
3408 dst_i,
3409 dst_ty,
3410 } = case;
3411
3412 self.push_dst_addr(dst);
3415 self.instruction(I32Const(dst_i as i32));
3416 match dst {
3417 Destination::Stack(stack, _) => self.stack_set(&stack[..1], ValType::I32),
3418 Destination::Memory(mem) => match dst_info.size {
3419 DiscriminantSize::Size1 => self.i32_store8(mem),
3420 DiscriminantSize::Size2 => self.i32_store16(mem),
3421 DiscriminantSize::Size4 => self.i32_store(mem),
3422 },
3423 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
3424 }
3425
3426 let src_payload = src.payload_src(self.types, src_info, src_ty);
3427 let dst_payload = dst.payload_dst(self.types, dst_info, dst_ty);
3428
3429 match (src_ty, dst_ty) {
3432 (Some(src_ty), Some(dst_ty)) => {
3433 self.translate(src_ty, &src_payload, dst_ty, &dst_payload);
3434 }
3435 (None, None) => {}
3436 _ => unimplemented!(),
3437 }
3438
3439 if let Destination::Stack(payload_results, _) = dst_payload {
3446 if let Destination::Stack(dst_results, _) = dst {
3447 let remaining = &dst_results[1..][payload_results.len()..];
3448 for ty in remaining {
3449 match ty {
3450 ValType::I32 => self.instruction(I32Const(0)),
3451 ValType::I64 => self.instruction(I64Const(0)),
3452 ValType::F32 => self.instruction(F32Const(0.0.into())),
3453 ValType::F64 => self.instruction(F64Const(0.0.into())),
3454 _ => unreachable!(),
3455 }
3456 }
3457 }
3458 }
3459
3460 if src_i != src_cases_len - 1 {
3463 self.instruction(Br(src_cases_len - src_i - 1));
3464 }
3465 self.instruction(End); }
3467 }
3468
3469 fn translate_future(
3470 &mut self,
3471 src_ty: TypeFutureTableIndex,
3472 src: &Source<'_>,
3473 dst_ty: &InterfaceType,
3474 dst: &Destination,
3475 ) {
3476 let dst_ty = match dst_ty {
3477 InterfaceType::Future(t) => *t,
3478 _ => panic!("expected a `Future`"),
3479 };
3480 let transfer = self.module.import_future_transfer();
3481 self.translate_handle(src_ty.as_u32(), src, dst_ty.as_u32(), dst, transfer);
3482 }
3483
3484 fn translate_stream(
3485 &mut self,
3486 src_ty: TypeStreamTableIndex,
3487 src: &Source<'_>,
3488 dst_ty: &InterfaceType,
3489 dst: &Destination,
3490 ) {
3491 let dst_ty = match dst_ty {
3492 InterfaceType::Stream(t) => *t,
3493 _ => panic!("expected a `Stream`"),
3494 };
3495 let transfer = self.module.import_stream_transfer();
3496 self.translate_handle(src_ty.as_u32(), src, dst_ty.as_u32(), dst, transfer);
3497 }
3498
3499 fn translate_error_context(
3500 &mut self,
3501 src_ty: TypeComponentLocalErrorContextTableIndex,
3502 src: &Source<'_>,
3503 dst_ty: &InterfaceType,
3504 dst: &Destination,
3505 ) {
3506 let dst_ty = match dst_ty {
3507 InterfaceType::ErrorContext(t) => *t,
3508 _ => panic!("expected an `ErrorContext`"),
3509 };
3510 let transfer = self.module.import_error_context_transfer();
3511 self.translate_handle(src_ty.as_u32(), src, dst_ty.as_u32(), dst, transfer);
3512 }
3513
3514 fn translate_own(
3515 &mut self,
3516 src_ty: TypeResourceTableIndex,
3517 src: &Source<'_>,
3518 dst_ty: &InterfaceType,
3519 dst: &Destination,
3520 ) {
3521 let dst_ty = match dst_ty {
3522 InterfaceType::Own(t) => *t,
3523 _ => panic!("expected an `Own`"),
3524 };
3525 let transfer = self.module.import_resource_transfer_own();
3526 self.translate_handle(src_ty.as_u32(), src, dst_ty.as_u32(), dst, transfer);
3527 }
3528
3529 fn translate_borrow(
3530 &mut self,
3531 src_ty: TypeResourceTableIndex,
3532 src: &Source<'_>,
3533 dst_ty: &InterfaceType,
3534 dst: &Destination,
3535 ) {
3536 let dst_ty = match dst_ty {
3537 InterfaceType::Borrow(t) => *t,
3538 _ => panic!("expected an `Borrow`"),
3539 };
3540
3541 let transfer = self.module.import_resource_transfer_borrow();
3542 self.translate_handle(src_ty.as_u32(), src, dst_ty.as_u32(), dst, transfer);
3543 }
3544
3545 fn translate_handle(
3553 &mut self,
3554 src_ty: u32,
3555 src: &Source<'_>,
3556 dst_ty: u32,
3557 dst: &Destination,
3558 transfer: FuncIndex,
3559 ) {
3560 self.push_dst_addr(dst);
3561 match src {
3562 Source::Memory(mem) => self.i32_load(mem),
3563 Source::Stack(stack) => self.stack_get(stack, ValType::I32),
3564 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
3565 }
3566 self.instruction(I32Const(src_ty as i32));
3567 self.instruction(I32Const(dst_ty as i32));
3568 self.instruction(Call(transfer.as_u32()));
3569 match dst {
3570 Destination::Memory(mem) => self.i32_store(mem),
3571 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
3572 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
3573 }
3574 }
3575
3576 fn trap_if_not_may_leave(&mut self, flags_global: GlobalIndex, trap: Trap) -> TempLocal {
3583 self.instruction(Block(BlockType::Empty));
3584 self.instruction(GlobalGet(flags_global.as_u32()));
3585 let saved = self.local_tee_new_tmp(ValType::I32);
3588 self.instruction(BrIf(0));
3589 self.trap(trap);
3590 self.instruction(End);
3591 saved
3592 }
3593
3594 fn clear_may_leave(&mut self, flags_global: GlobalIndex) -> TempLocal {
3597 self.instruction(GlobalGet(flags_global.as_u32()));
3598 let saved = self.local_set_new_tmp(ValType::I32);
3599 self.set_may_leave_false(flags_global);
3600 saved
3601 }
3602
3603 fn set_may_leave_false(&mut self, flags_global: GlobalIndex) {
3608 self.instruction(I32Const(0));
3609 self.instruction(GlobalSet(flags_global.as_u32()));
3610 }
3611
3612 fn restore_may_leave(&mut self, flags_global: GlobalIndex, saved: TempLocal) {
3625 self.instruction(LocalGet(saved.idx));
3626 self.instruction(GlobalSet(flags_global.as_u32()));
3627 self.free_temp_local(saved);
3628 }
3629
3630 fn assert_aligned(&mut self, ty: &InterfaceType, mem: &Memory) {
3631 let mem_opts = mem.mem_opts();
3632 if !self.module.tunables.debug_adapter_modules {
3633 return;
3634 }
3635 let align = self.types.align(mem_opts, ty);
3636 if align == 1 {
3637 return;
3638 }
3639 assert!(align.is_power_of_two());
3640 self.instruction(LocalGet(mem.addr.idx));
3641 self.ptr_uconst(mem_opts, mem.offset);
3642 self.ptr_add(mem_opts);
3643 self.ptr_uconst(mem_opts, align - 1);
3644 self.ptr_and(mem_opts);
3645 self.ptr_if(mem_opts, BlockType::Empty);
3646 self.trap(Trap::DebugAssertPointerAligned);
3647 self.instruction(End);
3648 }
3649
3650 fn malloc_abi<'c>(
3656 &mut self,
3657 opts: &'c Options,
3658 abi: &CanonicalAbiInfo,
3659 oob_trap: Trap,
3660 ) -> Memory<'c> {
3661 match &opts.data_model {
3662 DataModel::Gc {} => todo!("CM+GC"),
3663 DataModel::LinearMemory(mem_opts) => {
3664 let (size, align) = mem_opts.sizealign(abi);
3665 let size = AllocSize::Const(size);
3666 self.malloc(opts, size, align, oob_trap)
3667 }
3668 }
3669 }
3670
3671 fn malloc<'c>(
3677 &mut self,
3678 opts: &'c Options,
3679 size: AllocSize,
3680 align: u32,
3681 oob_trap: Trap,
3682 ) -> Memory<'c> {
3683 match &opts.data_model {
3684 DataModel::Gc {} => todo!("CM+GC"),
3685 DataModel::LinearMemory(mem_opts) => {
3686 let realloc = mem_opts.realloc.unwrap();
3687 self.ptr_uconst(mem_opts, 0);
3688 self.ptr_uconst(mem_opts, 0);
3689 self.ptr_uconst(mem_opts, align);
3690 self.alloc_size(mem_opts, &size);
3691 self.call_realloc(realloc);
3692 let addr = self.local_set_new_tmp(mem_opts.ptr());
3693 self.memory_operand(opts, addr, size, align, oob_trap)
3694 }
3695 }
3696 }
3697
3698 fn realloc(
3704 &mut self,
3705 opts: &Options,
3706 ptr: &TempLocal,
3707 prev_size: AllocSize,
3708 size: AllocSize,
3709 align: u32,
3710 oob_trap: Trap,
3711 ) {
3712 match &opts.data_model {
3713 DataModel::Gc {} => todo!("CM+GC"),
3714 DataModel::LinearMemory(mem_opts) => {
3715 let realloc = mem_opts.realloc.unwrap();
3716 self.instruction(LocalGet(ptr.idx));
3717 self.alloc_size(mem_opts, &prev_size);
3718 self.ptr_uconst(mem_opts, align);
3719 self.alloc_size(mem_opts, &size);
3720 self.call_realloc(realloc);
3721 self.instruction(LocalSet(ptr.idx));
3722 self.validate_guest_pointer(opts, &ptr, &size, align, oob_trap)
3723 }
3724 }
3725 }
3726
3727 fn memory_operand_abi<'c>(
3730 &mut self,
3731 opts: &'c Options,
3732 addr: TempLocal,
3733 abi: &CanonicalAbiInfo,
3734 oob_trap: Trap,
3735 ) -> Memory<'c> {
3736 match &opts.data_model {
3737 DataModel::Gc {} => todo!("CM+GC"),
3738 DataModel::LinearMemory(mem_opts) => {
3739 let (size, align) = mem_opts.sizealign(abi);
3740 self.memory_operand(opts, addr, AllocSize::Const(size), align, oob_trap)
3741 }
3742 }
3743 }
3744
3745 fn memory_operand<'c>(
3748 &mut self,
3749 opts: &'c Options,
3750 addr: TempLocal,
3751 size: AllocSize,
3752 align: u32,
3753 oob_trap: Trap,
3754 ) -> Memory<'c> {
3755 self.validate_guest_pointer(opts, &addr, &size, align, oob_trap);
3756 Memory {
3757 addr,
3758 opts,
3759 offset: 0,
3760 }
3761 }
3762
3763 fn validate_guest_pointer(
3771 &mut self,
3772 opts: &Options,
3773 addr: &TempLocal,
3774 size: &AllocSize,
3775 align: u32,
3776 oob_trap: Trap,
3777 ) {
3778 let mem_opts = match &opts.data_model {
3779 DataModel::Gc {} => todo!("CM+GC"),
3780 DataModel::LinearMemory(mem_opts) => mem_opts,
3781 };
3782
3783 if align != 1 {
3786 self.instruction(LocalGet(addr.idx));
3787 assert!(align.is_power_of_two());
3788 self.ptr_uconst(mem_opts, align - 1);
3789 self.ptr_and(mem_opts);
3790 self.ptr_if(mem_opts, BlockType::Empty);
3791 self.trap(Trap::UnalignedPointer);
3792 self.instruction(End);
3793 }
3794
3795 let extend_to_64 = |me: &mut Self| {
3796 if !mem_opts.memory64() {
3797 me.instruction(I64ExtendI32U);
3798 }
3799 };
3800
3801 self.instruction(Block(BlockType::Empty));
3802 self.instruction(Block(BlockType::Empty));
3803 let (memory, ty) = mem_opts.memory.unwrap();
3804
3805 self.instruction(MemorySize(memory.as_u32()));
3810 extend_to_64(self);
3811 self.instruction(I64Const(ty.page_size_log2.into()));
3812 self.instruction(I64Shl);
3813
3814 self.instruction(LocalGet(addr.idx));
3819 extend_to_64(self);
3820 self.alloc_size(mem_opts, size);
3821 extend_to_64(self);
3822 self.instruction(I64Add);
3823 if mem_opts.memory64() {
3824 let tmp = self.local_tee_new_tmp(ValType::I64);
3825 self.instruction(LocalGet(addr.idx));
3826 self.ptr_lt_u(mem_opts);
3827 self.instruction(BrIf(0));
3828 self.instruction(LocalGet(tmp.idx));
3829 self.free_temp_local(tmp);
3830 }
3831
3832 self.instruction(I64GeU);
3836 self.instruction(BrIf(1));
3837
3838 self.instruction(End);
3839 self.trap(oob_trap);
3840 self.instruction(End);
3841 }
3842
3843 fn local_tee_new_tmp(&mut self, ty: ValType) -> TempLocal {
3849 self.gen_temp_local(ty, LocalTee)
3850 }
3851
3852 fn local_set_new_tmp(&mut self, ty: ValType) -> TempLocal {
3855 self.gen_temp_local(ty, LocalSet)
3856 }
3857
3858 fn local_get_tmp(&mut self, local: &TempLocal) {
3859 self.instruction(LocalGet(local.idx));
3860 }
3861
3862 fn gen_temp_local(&mut self, ty: ValType, insn: fn(u32) -> Instruction<'static>) -> TempLocal {
3863 if let Some(idx) = self.free_locals.get_mut(&ty).and_then(|v| v.pop()) {
3866 self.instruction(insn(idx));
3867 return TempLocal {
3868 ty,
3869 idx,
3870 needs_free: true,
3871 };
3872 }
3873
3874 let locals = &mut self.module.funcs[self.result].locals;
3876 match locals.last_mut() {
3877 Some((cnt, prev_ty)) if ty == *prev_ty => *cnt += 1,
3878 _ => locals.push((1, ty)),
3879 }
3880 self.nlocals += 1;
3881 let idx = self.nlocals - 1;
3882 self.instruction(insn(idx));
3883 TempLocal {
3884 ty,
3885 idx,
3886 needs_free: true,
3887 }
3888 }
3889
3890 fn free_temp_local(&mut self, mut local: TempLocal) {
3893 assert!(local.needs_free);
3894 self.free_locals
3895 .entry(local.ty)
3896 .or_insert(Vec::new())
3897 .push(local.idx);
3898 local.needs_free = false;
3899 }
3900
3901 fn save_context(&mut self) -> Vec<TempLocal> {
3904 if !self.module.tunables.concurrency_support {
3905 return Vec::new();
3906 }
3907 let mut saved = Vec::new();
3908 for slot in 0..NUM_COMPONENT_CONTEXT_SLOTS {
3909 let get = self.module.import_context_get(slot);
3910 self.instruction(Call(get.as_u32()));
3911 saved.push(self.local_set_new_tmp(ValType::I32));
3912 }
3913 saved
3914 }
3915
3916 fn clear_context(&mut self) {
3918 if !self.module.tunables.concurrency_support {
3919 return;
3920 }
3921 for slot in 0..NUM_COMPONENT_CONTEXT_SLOTS {
3922 let set = self.module.import_context_set(slot);
3923 self.instruction(I32Const(0));
3924 self.instruction(Call(set.as_u32()));
3925 }
3926 }
3927
3928 fn restore_context(&mut self, saved: Vec<TempLocal>) {
3931 for (slot, local) in saved.into_iter().enumerate() {
3932 let set = self.module.import_context_set(slot);
3933 self.instruction(LocalGet(local.idx));
3934 self.instruction(Call(set.as_u32()));
3935 self.free_temp_local(local);
3936 }
3937 }
3938
3939 fn call_realloc(&mut self, realloc: FuncIndex) {
3945 let saved = self.save_context();
3946 self.clear_context();
3947 self.instruction(Call(realloc.as_u32()));
3948 self.restore_context(saved);
3949 }
3950
3951 fn instruction(&mut self, instr: Instruction) {
3952 instr.encode(&mut self.code);
3953 }
3954
3955 fn trap(&mut self, trap: Trap) {
3956 let trap_func = self.module.import_trap(trap);
3957 self.instruction(Call(trap_func.as_u32()));
3958 self.instruction(Unreachable);
3959 }
3960
3961 fn enter_exception_barrier(&mut self, results: &[ValType]) {
3992 if !self.module.features.exceptions() {
3993 return;
3994 }
3995 let block_ty = match results.len() {
3996 0 => BlockType::Empty,
3997 1 => BlockType::Result(results[0]),
3998 _ => BlockType::FunctionType(self.module.core_types.function(&[], results)),
3999 };
4000 self.instruction(Block(block_ty));
4002 self.instruction(Block(BlockType::Empty));
4004 self.instruction(TryTable(block_ty, vec![Catch::All { label: 0 }].into()));
4005 }
4006
4007 fn exit_exception_barrier(&mut self) {
4012 if !self.module.features.exceptions() {
4013 return;
4014 }
4015 self.instruction(End);
4017 self.instruction(Br(1));
4019 self.instruction(End);
4021 self.trap(Trap::UncaughtException);
4022 self.instruction(End);
4024 }
4025
4026 fn flush_code(&mut self) {
4031 if self.code.is_empty() {
4032 return;
4033 }
4034 self.module.funcs[self.result]
4035 .body
4036 .push(Body::Raw(mem::take(&mut self.code)));
4037 }
4038
4039 fn finish(mut self) {
4040 self.instruction(End);
4043 self.flush_code();
4044
4045 self.module.funcs[self.result].filled_in = true;
4048 }
4049
4050 fn stack_get(&mut self, stack: &Stack<'_>, dst_ty: ValType) {
4058 assert_eq!(stack.locals.len(), 1);
4059 let (idx, src_ty) = stack.locals[0];
4060 self.instruction(LocalGet(idx));
4061 match (src_ty, dst_ty) {
4062 (ValType::I32, ValType::I32)
4063 | (ValType::I64, ValType::I64)
4064 | (ValType::F32, ValType::F32)
4065 | (ValType::F64, ValType::F64) => {}
4066
4067 (ValType::I32, ValType::F32) => self.instruction(F32ReinterpretI32),
4068 (ValType::I64, ValType::I32) => {
4069 self.assert_i64_upper_bits_not_set(idx);
4070 self.instruction(I32WrapI64);
4071 }
4072 (ValType::I64, ValType::F64) => self.instruction(F64ReinterpretI64),
4073 (ValType::I64, ValType::F32) => {
4074 self.assert_i64_upper_bits_not_set(idx);
4075 self.instruction(I32WrapI64);
4076 self.instruction(F32ReinterpretI32);
4077 }
4078
4079 (ValType::I32, ValType::I64)
4081 | (ValType::I32, ValType::F64)
4082 | (ValType::F32, ValType::I32)
4083 | (ValType::F32, ValType::I64)
4084 | (ValType::F32, ValType::F64)
4085 | (ValType::F64, ValType::I32)
4086 | (ValType::F64, ValType::I64)
4087 | (ValType::F64, ValType::F32)
4088
4089 | (ValType::Ref(_), _)
4091 | (_, ValType::Ref(_))
4092 | (ValType::V128, _)
4093 | (_, ValType::V128) => {
4094 panic!("cannot get {dst_ty:?} from {src_ty:?} local");
4095 }
4096 }
4097 }
4098
4099 fn assert_i64_upper_bits_not_set(&mut self, local: u32) {
4100 if !self.module.tunables.debug_adapter_modules {
4101 return;
4102 }
4103 self.instruction(LocalGet(local));
4104 self.instruction(I64Const(32));
4105 self.instruction(I64ShrU);
4106 self.instruction(I32WrapI64);
4107 self.instruction(If(BlockType::Empty));
4108 self.trap(Trap::DebugAssertUpperBitsUnset);
4109 self.instruction(End);
4110 }
4111
4112 fn stack_set(&mut self, dst_tys: &[ValType], src_ty: ValType) {
4118 assert_eq!(dst_tys.len(), 1);
4119 let dst_ty = dst_tys[0];
4120 match (src_ty, dst_ty) {
4121 (ValType::I32, ValType::I32)
4122 | (ValType::I64, ValType::I64)
4123 | (ValType::F32, ValType::F32)
4124 | (ValType::F64, ValType::F64) => {}
4125
4126 (ValType::F32, ValType::I32) => self.instruction(I32ReinterpretF32),
4127 (ValType::I32, ValType::I64) => self.instruction(I64ExtendI32U),
4128 (ValType::F64, ValType::I64) => self.instruction(I64ReinterpretF64),
4129 (ValType::F32, ValType::I64) => {
4130 self.instruction(I32ReinterpretF32);
4131 self.instruction(I64ExtendI32U);
4132 }
4133
4134 (ValType::I64, ValType::I32)
4136 | (ValType::F64, ValType::I32)
4137 | (ValType::I32, ValType::F32)
4138 | (ValType::I64, ValType::F32)
4139 | (ValType::F64, ValType::F32)
4140 | (ValType::I32, ValType::F64)
4141 | (ValType::I64, ValType::F64)
4142 | (ValType::F32, ValType::F64)
4143
4144 | (ValType::Ref(_), _)
4146 | (_, ValType::Ref(_))
4147 | (ValType::V128, _)
4148 | (_, ValType::V128) => {
4149 panic!("cannot get {dst_ty:?} from {src_ty:?} local");
4150 }
4151 }
4152 }
4153
4154 fn i32_load8u(&mut self, mem: &Memory) {
4155 self.instruction(LocalGet(mem.addr.idx));
4156 self.instruction(I32Load8U(mem.memarg(0)));
4157 }
4158
4159 fn i32_load8s(&mut self, mem: &Memory) {
4160 self.instruction(LocalGet(mem.addr.idx));
4161 self.instruction(I32Load8S(mem.memarg(0)));
4162 }
4163
4164 fn i32_load16u(&mut self, mem: &Memory) {
4165 self.instruction(LocalGet(mem.addr.idx));
4166 self.instruction(I32Load16U(mem.memarg(1)));
4167 }
4168
4169 fn i32_load16s(&mut self, mem: &Memory) {
4170 self.instruction(LocalGet(mem.addr.idx));
4171 self.instruction(I32Load16S(mem.memarg(1)));
4172 }
4173
4174 fn i32_load(&mut self, mem: &Memory) {
4175 self.instruction(LocalGet(mem.addr.idx));
4176 self.instruction(I32Load(mem.memarg(2)));
4177 }
4178
4179 fn i64_load(&mut self, mem: &Memory) {
4180 self.instruction(LocalGet(mem.addr.idx));
4181 self.instruction(I64Load(mem.memarg(3)));
4182 }
4183
4184 fn ptr_load(&mut self, mem: &Memory) {
4185 if mem.mem_opts().memory64() {
4186 self.i64_load(mem);
4187 } else {
4188 self.i32_load(mem);
4189 }
4190 }
4191
4192 fn ptr_add(&mut self, opts: &LinearMemoryOptions) {
4193 if opts.memory64() {
4194 self.instruction(I64Add);
4195 } else {
4196 self.instruction(I32Add);
4197 }
4198 }
4199
4200 fn ptr_sub(&mut self, opts: &LinearMemoryOptions) {
4201 if opts.memory64() {
4202 self.instruction(I64Sub);
4203 } else {
4204 self.instruction(I32Sub);
4205 }
4206 }
4207
4208 fn ptr_mul(&mut self, opts: &LinearMemoryOptions) {
4209 if opts.memory64() {
4210 self.instruction(I64Mul);
4211 } else {
4212 self.instruction(I32Mul);
4213 }
4214 }
4215
4216 fn ptr_gt_u(&mut self, opts: &LinearMemoryOptions) {
4217 if opts.memory64() {
4218 self.instruction(I64GtU);
4219 } else {
4220 self.instruction(I32GtU);
4221 }
4222 }
4223
4224 fn ptr_lt_u(&mut self, opts: &LinearMemoryOptions) {
4225 if opts.memory64() {
4226 self.instruction(I64LtU);
4227 } else {
4228 self.instruction(I32LtU);
4229 }
4230 }
4231
4232 fn ptr_shl(&mut self, opts: &LinearMemoryOptions) {
4233 if opts.memory64() {
4234 self.instruction(I64Shl);
4235 } else {
4236 self.instruction(I32Shl);
4237 }
4238 }
4239
4240 fn ptr_eqz(&mut self, opts: &LinearMemoryOptions) {
4241 if opts.memory64() {
4242 self.instruction(I64Eqz);
4243 } else {
4244 self.instruction(I32Eqz);
4245 }
4246 }
4247
4248 fn ptr_uconst(&mut self, opts: &LinearMemoryOptions, val: u32) {
4249 if opts.memory64() {
4250 self.instruction(I64Const(val.into()));
4251 } else {
4252 self.instruction(I32Const(val.cast_signed()));
4253 }
4254 }
4255
4256 fn ptr_iconst(&mut self, opts: &LinearMemoryOptions, val: i32) {
4257 if opts.memory64() {
4258 self.instruction(I64Const(val.into()));
4259 } else {
4260 self.instruction(I32Const(val));
4261 }
4262 }
4263
4264 fn ptr_eq(&mut self, opts: &LinearMemoryOptions) {
4265 if opts.memory64() {
4266 self.instruction(I64Eq);
4267 } else {
4268 self.instruction(I32Eq);
4269 }
4270 }
4271
4272 fn ptr_ne(&mut self, opts: &LinearMemoryOptions) {
4273 if opts.memory64() {
4274 self.instruction(I64Ne);
4275 } else {
4276 self.instruction(I32Ne);
4277 }
4278 }
4279
4280 fn ptr_and(&mut self, opts: &LinearMemoryOptions) {
4281 if opts.memory64() {
4282 self.instruction(I64And);
4283 } else {
4284 self.instruction(I32And);
4285 }
4286 }
4287
4288 fn ptr_or(&mut self, opts: &LinearMemoryOptions) {
4289 if opts.memory64() {
4290 self.instruction(I64Or);
4291 } else {
4292 self.instruction(I32Or);
4293 }
4294 }
4295
4296 fn ptr_xor(&mut self, opts: &LinearMemoryOptions) {
4297 if opts.memory64() {
4298 self.instruction(I64Xor);
4299 } else {
4300 self.instruction(I32Xor);
4301 }
4302 }
4303
4304 fn ptr_if(&mut self, opts: &LinearMemoryOptions, ty: BlockType) {
4305 if opts.memory64() {
4306 self.instruction(I64Const(0));
4307 self.instruction(I64Ne);
4308 }
4309 self.instruction(If(ty));
4310 }
4311
4312 fn ptr_br_if(&mut self, opts: &LinearMemoryOptions, depth: u32) {
4313 if opts.memory64() {
4314 self.instruction(I64Const(0));
4315 self.instruction(I64Ne);
4316 }
4317 self.instruction(BrIf(depth));
4318 }
4319
4320 fn f32_load(&mut self, mem: &Memory) {
4321 self.instruction(LocalGet(mem.addr.idx));
4322 self.instruction(F32Load(mem.memarg(2)));
4323 }
4324
4325 fn f64_load(&mut self, mem: &Memory) {
4326 self.instruction(LocalGet(mem.addr.idx));
4327 self.instruction(F64Load(mem.memarg(3)));
4328 }
4329
4330 fn push_dst_addr(&mut self, dst: &Destination) {
4331 if let Destination::Memory(mem) = dst {
4332 self.instruction(LocalGet(mem.addr.idx));
4333 }
4334 }
4335
4336 fn i32_store8(&mut self, mem: &Memory) {
4337 self.instruction(I32Store8(mem.memarg(0)));
4338 }
4339
4340 fn i32_store16(&mut self, mem: &Memory) {
4341 self.instruction(I32Store16(mem.memarg(1)));
4342 }
4343
4344 fn i32_store(&mut self, mem: &Memory) {
4345 self.instruction(I32Store(mem.memarg(2)));
4346 }
4347
4348 fn i64_store(&mut self, mem: &Memory) {
4349 self.instruction(I64Store(mem.memarg(3)));
4350 }
4351
4352 fn ptr_store(&mut self, mem: &Memory) {
4353 if mem.mem_opts().memory64() {
4354 self.i64_store(mem);
4355 } else {
4356 self.i32_store(mem);
4357 }
4358 }
4359
4360 fn f32_store(&mut self, mem: &Memory) {
4361 self.instruction(F32Store(mem.memarg(2)));
4362 }
4363
4364 fn f64_store(&mut self, mem: &Memory) {
4365 self.instruction(F64Store(mem.memarg(3)));
4366 }
4367
4368 fn alloc_size(&mut self, opts: &LinearMemoryOptions, size: &AllocSize) {
4371 match size {
4372 AllocSize::Const(size) => self.ptr_uconst(opts, *size),
4373 AllocSize::Local(idx) => self.instruction(LocalGet(*idx)),
4374 AllocSize::DoubleLocal(idx) => {
4375 self.instruction(LocalGet(*idx));
4376 self.ptr_uconst(opts, 1);
4377 self.ptr_shl(opts);
4378 }
4379 }
4380 }
4381}
4382
4383impl<'a> Source<'a> {
4384 fn record_field_srcs<'b>(
4391 &'b self,
4392 types: &'b ComponentTypesBuilder,
4393 fields: impl IntoIterator<Item = InterfaceType> + 'b,
4394 ) -> impl Iterator<Item = Source<'a>> + 'b
4395 where
4396 'a: 'b,
4397 {
4398 let mut offset = 0;
4399 fields.into_iter().map(move |ty| match self {
4400 Source::Memory(mem) => {
4401 let mem = next_field_offset(&mut offset, types, &ty, mem);
4402 Source::Memory(mem)
4403 }
4404 Source::Stack(stack) => {
4405 let cnt = types.flat_types(&ty).unwrap().len() as u32;
4406 offset += cnt;
4407 Source::Stack(stack.slice((offset - cnt) as usize..offset as usize))
4408 }
4409 Source::Struct(_) => todo!(),
4410 Source::Array(_) => todo!(),
4411 })
4412 }
4413
4414 fn payload_src(
4416 &self,
4417 types: &ComponentTypesBuilder,
4418 info: &VariantInfo,
4419 case: Option<&InterfaceType>,
4420 ) -> Source<'a> {
4421 match self {
4422 Source::Stack(s) => {
4423 let flat_len = match case {
4424 Some(case) => types.flat_types(case).unwrap().len(),
4425 None => 0,
4426 };
4427 Source::Stack(s.slice(1..s.locals.len()).slice(0..flat_len))
4428 }
4429 Source::Memory(mem) => {
4430 let mem = if mem.mem_opts().memory64() {
4431 mem.bump(info.payload_offset64)
4432 } else {
4433 mem.bump(info.payload_offset32)
4434 };
4435 Source::Memory(mem)
4436 }
4437 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
4438 }
4439 }
4440
4441 fn opts(&self) -> &'a Options {
4442 match self {
4443 Source::Stack(s) => s.opts,
4444 Source::Memory(mem) => mem.opts,
4445 Source::Struct(s) => s.opts,
4446 Source::Array(a) => a.opts,
4447 }
4448 }
4449}
4450
4451impl<'a> Destination<'a> {
4452 fn record_field_dsts<'b, I>(
4454 &'b self,
4455 types: &'b ComponentTypesBuilder,
4456 fields: I,
4457 ) -> impl Iterator<Item = Destination<'b>> + use<'b, I>
4458 where
4459 'a: 'b,
4460 I: IntoIterator<Item = InterfaceType> + 'b,
4461 {
4462 let mut offset = 0;
4463 fields.into_iter().map(move |ty| match self {
4464 Destination::Memory(mem) => {
4465 let mem = next_field_offset(&mut offset, types, &ty, mem);
4466 Destination::Memory(mem)
4467 }
4468 Destination::Stack(s, opts) => {
4469 let cnt = types.flat_types(&ty).unwrap().len() as u32;
4470 offset += cnt;
4471 Destination::Stack(&s[(offset - cnt) as usize..offset as usize], opts)
4472 }
4473 Destination::Struct(_) => todo!(),
4474 Destination::Array(_) => todo!(),
4475 })
4476 }
4477
4478 fn payload_dst(
4480 &self,
4481 types: &ComponentTypesBuilder,
4482 info: &VariantInfo,
4483 case: Option<&InterfaceType>,
4484 ) -> Destination<'_> {
4485 match self {
4486 Destination::Stack(s, opts) => {
4487 let flat_len = match case {
4488 Some(case) => types.flat_types(case).unwrap().len(),
4489 None => 0,
4490 };
4491 Destination::Stack(&s[1..][..flat_len], opts)
4492 }
4493 Destination::Memory(mem) => {
4494 let mem = if mem.mem_opts().memory64() {
4495 mem.bump(info.payload_offset64)
4496 } else {
4497 mem.bump(info.payload_offset32)
4498 };
4499 Destination::Memory(mem)
4500 }
4501 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
4502 }
4503 }
4504
4505 fn opts(&self) -> &'a Options {
4506 match self {
4507 Destination::Stack(_, opts) => opts,
4508 Destination::Memory(mem) => mem.opts,
4509 Destination::Struct(s) => s.opts,
4510 Destination::Array(a) => a.opts,
4511 }
4512 }
4513}
4514
4515fn next_field_offset<'a>(
4516 offset: &mut u32,
4517 types: &ComponentTypesBuilder,
4518 field: &InterfaceType,
4519 mem: &Memory<'a>,
4520) -> Memory<'a> {
4521 let abi = types.canonical_abi(field);
4522 let offset = if mem.mem_opts().memory64() {
4523 abi.next_field64(offset)
4524 } else {
4525 abi.next_field32(offset)
4526 };
4527 mem.bump(offset)
4528}
4529
4530impl<'a> Memory<'a> {
4531 fn memarg(&self, align: u32) -> MemArg {
4532 MemArg {
4533 offset: u64::from(self.offset),
4534 align,
4535 memory_index: self.mem_opts().memory.unwrap().0.as_u32(),
4536 }
4537 }
4538
4539 fn bump(&self, offset: u32) -> Memory<'a> {
4540 Memory {
4541 opts: self.opts,
4542 addr: TempLocal::new(self.addr.idx, self.addr.ty),
4543 offset: self.offset + offset,
4544 }
4545 }
4546}
4547
4548impl<'a> Stack<'a> {
4549 fn slice(&self, range: Range<usize>) -> Stack<'a> {
4550 Stack {
4551 locals: &self.locals[range],
4552 opts: self.opts,
4553 }
4554 }
4555}
4556
4557struct VariantCase<'a> {
4558 src_i: u32,
4559 src_ty: Option<&'a InterfaceType>,
4560 dst_i: u32,
4561 dst_ty: Option<&'a InterfaceType>,
4562}
4563
4564fn variant_info<'a, I>(types: &ComponentTypesBuilder, cases: I) -> VariantInfo
4565where
4566 I: IntoIterator<Item = Option<&'a InterfaceType>>,
4567 I::IntoIter: ExactSizeIterator,
4568{
4569 VariantInfo::new(
4570 cases
4571 .into_iter()
4572 .map(|ty| ty.map(|ty| types.canonical_abi(ty))),
4573 )
4574 .0
4575}
4576
4577struct SequenceLoopState {
4579 remaining: TempLocal,
4580 cur_src_ptr: TempLocal,
4581 cur_dst_ptr: TempLocal,
4582}
4583
4584struct SequenceTranslation<'a> {
4588 src_len: TempLocal,
4589 src_mem: Memory<'a>,
4590 dst_mem: Memory<'a>,
4591 src_opts: &'a Options,
4592 dst_opts: &'a Options,
4593 src_mem_opts: &'a LinearMemoryOptions,
4594 dst_mem_opts: &'a LinearMemoryOptions,
4595 loop_state: Option<SequenceLoopState>,
4596}
4597
4598enum AllocSize {
4599 Const(u32),
4600 Local(u32),
4601 DoubleLocal(u32),
4602}
4603
4604struct WasmString<'a> {
4605 ptr: TempLocal,
4606 len: TempLocal,
4607 opts: &'a Options,
4608}
4609
4610struct TempLocal {
4611 idx: u32,
4612 ty: ValType,
4613 needs_free: bool,
4614}
4615
4616impl TempLocal {
4617 fn new(idx: u32, ty: ValType) -> TempLocal {
4618 TempLocal {
4619 idx,
4620 ty,
4621 needs_free: false,
4622 }
4623 }
4624}
4625
4626impl std::ops::Drop for TempLocal {
4627 fn drop(&mut self) {
4628 if self.needs_free {
4629 panic!("temporary local not free'd");
4630 }
4631 }
4632}
4633
4634impl From<FlatType> for ValType {
4635 fn from(ty: FlatType) -> ValType {
4636 match ty {
4637 FlatType::I32 => ValType::I32,
4638 FlatType::I64 => ValType::I64,
4639 FlatType::F32 => ValType::F32,
4640 FlatType::F64 => ValType::F64,
4641 }
4642 }
4643}