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, 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 if adapter.lift.instance == adapter.lower.instance
120 || adapter.lower.ancestors.contains(&adapter.lift.instance)
121 || adapter.lift.ancestors.contains(&adapter.lower.instance)
122 {
123 let (mut compiler, _, _) = compiler(module, adapter);
124 compiler.trap(Trap::CannotEnterComponent);
125 compiler.finish();
126 return;
127 }
128
129 let async_start_adapter = |module: &mut Module| {
135 let sig = module
136 .types
137 .async_start_signature(&adapter.lower, &adapter.lift);
138 let ty = module.core_types.function(&sig.params, &sig.results);
139 let result = module.funcs.push(Function::new(
140 Some(format!("[async-start]{}", adapter.name)),
141 ty,
142 ));
143
144 Compiler::new(module, result, sig.params.len() as u32, false)
145 .compile_async_start_adapter(adapter, &sig);
146
147 result
148 };
149
150 let async_return_adapter = |module: &mut Module| {
159 let sig = module
160 .types
161 .async_return_signature(&adapter.lower, &adapter.lift);
162 let ty = module.core_types.function(&sig.params, &sig.results);
163 let result = module.funcs.push(Function::new(
164 Some(format!("[async-return]{}", adapter.name)),
165 ty,
166 ));
167
168 Compiler::new(module, result, sig.params.len() as u32, false)
169 .compile_async_return_adapter(adapter, &sig);
170
171 result
172 };
173
174 match (adapter.lower.options.async_, adapter.lift.options.async_) {
175 (false, false) => {
176 let (compiler, lower_sig, lift_sig) = compiler(module, adapter);
179 compiler.compile_sync_to_sync_adapter(adapter, &lower_sig, &lift_sig)
180 }
181 (true, true) => {
182 assert!(module.tunables.concurrency_support);
183
184 let start = async_start_adapter(module);
200 let return_ = async_return_adapter(module);
201 let (compiler, lower_sig, lift_sig) = compiler(module, adapter);
202 compiler.compile_async_to_async_adapter(
203 adapter,
204 start,
205 return_,
206 i32::try_from(lift_sig.params.len()).unwrap(),
207 &lower_sig,
208 );
209 }
210 (false, true) => {
211 assert!(module.tunables.concurrency_support);
212
213 let start = async_start_adapter(module);
226 let return_ = async_return_adapter(module);
227 let (compiler, lower_sig, lift_sig) = compiler(module, adapter);
228 compiler.compile_sync_to_async_adapter(
229 adapter,
230 start,
231 return_,
232 i32::try_from(lift_sig.params.len()).unwrap(),
233 &lower_sig,
234 );
235 }
236 (true, false) => {
237 assert!(module.tunables.concurrency_support);
238
239 let lift_sig = module.types.signature(&adapter.lift);
259 let start = async_start_adapter(module);
260 let return_ = async_return_adapter(module);
261 let (compiler, lower_sig, ..) = compiler(module, adapter);
262 compiler.compile_async_to_sync_adapter(
263 adapter,
264 start,
265 return_,
266 i32::try_from(lift_sig.params.len()).unwrap(),
267 i32::try_from(lift_sig.results.len()).unwrap(),
268 &lower_sig,
269 );
270 }
271 }
272}
273
274pub(super) fn compile_helper(module: &mut Module<'_>, result: FunctionId, helper: Helper) {
281 let mut nlocals = 0;
282 let src_flat;
283 let src = match helper.src.loc {
284 HelperLocation::Stack => {
289 src_flat = module
290 .types
291 .flatten_types(&helper.src.opts, usize::MAX, [helper.src.ty])
292 .unwrap()
293 .iter()
294 .enumerate()
295 .map(|(i, ty)| (i as u32, *ty))
296 .collect::<Vec<_>>();
297 nlocals += src_flat.len() as u32;
298 Source::Stack(Stack {
299 locals: &src_flat,
300 opts: &helper.src.opts,
301 })
302 }
303 HelperLocation::Memory => {
306 nlocals += 1;
307 Source::Memory(Memory {
308 opts: &helper.src.opts,
309 addr: TempLocal::new(0, helper.src.opts.data_model.unwrap_memory().ptr()),
310 offset: 0,
311 })
312 }
313 HelperLocation::StructField | HelperLocation::ArrayElement => todo!("CM+GC"),
314 };
315 let dst_flat;
316 let dst = match helper.dst.loc {
317 HelperLocation::Stack => {
320 dst_flat = module
321 .types
322 .flatten_types(&helper.dst.opts, usize::MAX, [helper.dst.ty])
323 .unwrap();
324 Destination::Stack(&dst_flat, &helper.dst.opts)
325 }
326 HelperLocation::Memory => {
329 nlocals += 1;
330 Destination::Memory(Memory {
331 opts: &helper.dst.opts,
332 addr: TempLocal::new(
333 nlocals - 1,
334 helper.dst.opts.data_model.unwrap_memory().ptr(),
335 ),
336 offset: 0,
337 })
338 }
339 HelperLocation::StructField | HelperLocation::ArrayElement => todo!("CM+GC"),
340 };
341 let mut compiler = Compiler {
342 types: module.types,
343 module,
344 code: Vec::new(),
345 nlocals,
346 free_locals: HashMap::new(),
347 result,
348 fuel: INITIAL_FUEL,
349 emit_resource_call: false,
352 };
353 compiler.translate(&helper.src.ty, &src, &helper.dst.ty, &dst);
354 compiler.finish();
355}
356
357enum Source<'a> {
360 Stack(Stack<'a>),
366
367 Memory(Memory<'a>),
370
371 #[allow(dead_code, reason = "CM+GC is still WIP")]
374 Struct(GcStruct<'a>),
375
376 #[allow(dead_code, reason = "CM+GC is still WIP")]
379 Array(GcArray<'a>),
380}
381
382enum Destination<'a> {
384 Stack(&'a [ValType], &'a Options),
390
391 Memory(Memory<'a>),
393
394 #[allow(dead_code, reason = "CM+GC is still WIP")]
397 Struct(GcStruct<'a>),
398
399 #[allow(dead_code, reason = "CM+GC is still WIP")]
402 Array(GcArray<'a>),
403}
404
405struct Stack<'a> {
406 locals: &'a [(u32, ValType)],
412 opts: &'a Options,
414}
415
416struct Memory<'a> {
418 opts: &'a Options,
420 addr: TempLocal,
423 offset: u32,
426}
427
428impl<'a> Memory<'a> {
429 fn mem_opts(&self) -> &'a LinearMemoryOptions {
430 self.opts.data_model.unwrap_memory()
431 }
432}
433
434struct GcStruct<'a> {
436 opts: &'a Options,
437 }
439
440struct GcArray<'a> {
442 opts: &'a Options,
443 }
445
446impl<'a, 'b> Compiler<'a, 'b> {
447 fn new(
448 module: &'b mut Module<'a>,
449 result: FunctionId,
450 nlocals: u32,
451 emit_resource_call: bool,
452 ) -> Self {
453 Self {
454 types: module.types,
455 module,
456 result,
457 code: Vec::new(),
458 nlocals,
459 free_locals: HashMap::new(),
460 fuel: INITIAL_FUEL,
461 emit_resource_call,
462 }
463 }
464
465 fn compile_async_to_async_adapter(
475 mut self,
476 adapter: &AdapterData,
477 start: FunctionId,
478 return_: FunctionId,
479 param_count: i32,
480 lower_sig: &Signature,
481 ) {
482 let start_call =
483 self.module
484 .import_async_start_call(&adapter.name, adapter.lift.options.callback, None);
485
486 self.call_prepare(adapter, start, return_, lower_sig, false);
487
488 self.module.exports.push((
497 adapter.callee.as_u32(),
498 format!("[adapter-callee]{}", adapter.name),
499 ));
500
501 self.instruction(RefFunc(adapter.callee.as_u32()));
502 self.instruction(I32Const(param_count));
503 self.instruction(I32Const(1));
507 self.instruction(I32Const(START_FLAG_ASYNC_CALLEE));
508 self.instruction(Call(start_call.as_u32()));
509
510 self.finish()
511 }
512
513 fn call_prepare(
526 &mut self,
527 adapter: &AdapterData,
528 start: FunctionId,
529 return_: FunctionId,
530 lower_sig: &Signature,
531 prepare_sync: bool,
532 ) {
533 let prepare = self.module.import_prepare_call(
534 &adapter.name,
535 &lower_sig.params,
536 match adapter.lift.options.data_model {
537 DataModel::Gc {} => todo!("CM+GC"),
538 DataModel::LinearMemory(LinearMemoryOptions { memory, .. }) => memory.map(|m| m.0),
539 },
540 );
541
542 self.flush_code();
543 self.module.funcs[self.result]
544 .body
545 .push(Body::RefFunc(start));
546 self.module.funcs[self.result]
547 .body
548 .push(Body::RefFunc(return_));
549 self.instruction(I32Const(
550 i32::try_from(adapter.lower.instance.as_u32()).unwrap(),
551 ));
552 self.instruction(I32Const(
553 i32::try_from(adapter.lift.instance.as_u32()).unwrap(),
554 ));
555 self.instruction(I32Const(
556 i32::try_from(self.types[adapter.lift.ty].results.as_u32()).unwrap(),
557 ));
558 self.instruction(I32Const(if self.types[adapter.lift.ty].async_ {
559 1
560 } else {
561 0
562 }));
563 self.instruction(I32Const(i32::from(
564 adapter.lift.options.string_encoding as u8,
565 )));
566
567 let result_types = &self.types[self.types[adapter.lower.ty].results].types;
570 if prepare_sync {
571 self.instruction(I32Const(
572 i32::try_from(
573 self.types
574 .flatten_types(
575 &adapter.lower.options,
576 usize::MAX,
577 result_types.iter().copied(),
578 )
579 .map(|v| v.len())
580 .unwrap_or(usize::try_from(i32::MAX).unwrap()),
581 )
582 .unwrap(),
583 ));
584 } else {
585 if result_types.len() > 0 {
586 self.instruction(I32Const(PREPARE_ASYNC_WITH_RESULT.cast_signed()));
587 } else {
588 self.instruction(I32Const(PREPARE_ASYNC_NO_RESULT.cast_signed()));
589 }
590 }
591
592 for index in 0..lower_sig.params.len() {
594 self.instruction(LocalGet(u32::try_from(index).unwrap()));
595 }
596 self.instruction(Call(prepare.as_u32()));
597 }
598
599 fn compile_sync_to_async_adapter(
609 mut self,
610 adapter: &AdapterData,
611 start: FunctionId,
612 return_: FunctionId,
613 lift_param_count: i32,
614 lower_sig: &Signature,
615 ) {
616 let start_call = self.module.import_sync_start_call(
617 &adapter.name,
618 adapter.lift.options.callback,
619 &lower_sig.results,
620 );
621
622 self.call_prepare(adapter, start, return_, lower_sig, true);
623
624 self.module.exports.push((
633 adapter.callee.as_u32(),
634 format!("[adapter-callee]{}", adapter.name),
635 ));
636
637 self.instruction(RefFunc(adapter.callee.as_u32()));
638 self.instruction(I32Const(lift_param_count));
639 self.instruction(Call(start_call.as_u32()));
640
641 self.finish()
642 }
643
644 fn compile_async_to_sync_adapter(
654 mut self,
655 adapter: &AdapterData,
656 start: FunctionId,
657 return_: FunctionId,
658 param_count: i32,
659 result_count: i32,
660 lower_sig: &Signature,
661 ) {
662 let start_call =
663 self.module
664 .import_async_start_call(&adapter.name, None, adapter.lift.post_return);
665
666 self.call_prepare(adapter, start, return_, lower_sig, false);
667
668 self.module.exports.push((
672 adapter.callee.as_u32(),
673 format!("[adapter-callee]{}", adapter.name),
674 ));
675
676 self.instruction(RefFunc(adapter.callee.as_u32()));
677 self.instruction(I32Const(param_count));
678 self.instruction(I32Const(result_count));
679 self.instruction(I32Const(0));
680 self.instruction(Call(start_call.as_u32()));
681
682 self.finish()
683 }
684
685 fn compile_async_start_adapter(mut self, adapter: &AdapterData, sig: &Signature) {
691 let param_locals = sig
697 .params
698 .iter()
699 .enumerate()
700 .map(|(i, ty)| (i as u32, *ty))
701 .collect::<Vec<_>>();
702
703 let saved = self.clear_may_leave(adapter.lift.flags);
704 self.translate_params(adapter, ¶m_locals);
705 self.restore_may_leave(adapter.lift.flags, saved);
706
707 self.finish();
708 }
709
710 fn compile_async_return_adapter(mut self, adapter: &AdapterData, sig: &Signature) {
719 let param_locals = sig
723 .params
724 .iter()
725 .enumerate()
726 .map(|(i, ty)| (i as u32, *ty))
727 .collect::<Vec<_>>();
728
729 let saved = self.clear_may_leave(adapter.lower.flags);
730 self.translate_results(adapter, ¶m_locals, ¶m_locals);
741 self.restore_may_leave(adapter.lower.flags, saved);
742
743 self.finish()
744 }
745
746 fn compile_sync_to_sync_adapter(
753 mut self,
754 adapter: &AdapterData,
755 lower_sig: &Signature,
756 lift_sig: &Signature,
757 ) {
758 self.enter_exception_barrier(&lower_sig.results);
759
760 let saved_lower_may_leave =
770 self.trap_if_not_may_leave(adapter.lower.flags, Trap::CannotLeaveComponent);
771
772 let old_task_may_block = if self.module.tunables.concurrency_support {
773 let task_may_block = self.module.import_task_may_block();
775 let old_task_may_block = if self.types[adapter.lift.ty].async_ {
776 self.instruction(GlobalGet(task_may_block.as_u32()));
777 self.instruction(I32Eqz);
778 self.instruction(If(BlockType::Empty));
779 self.trap(Trap::CannotBlockSyncTask);
780 self.instruction(End);
781 None
782 } else {
783 let task_may_block = self.module.import_task_may_block();
784 self.instruction(GlobalGet(task_may_block.as_u32()));
785 let old_task_may_block = self.local_set_new_tmp(ValType::I32);
786 self.instruction(I32Const(0));
787 self.instruction(GlobalSet(task_may_block.as_u32()));
788 Some(old_task_may_block)
789 };
790
791 self.instruction(I32Const(
800 i32::try_from(adapter.lower.instance.as_u32()).unwrap(),
801 ));
802 self.instruction(I32Const(if self.types[adapter.lift.ty].async_ {
803 1
804 } else {
805 0
806 }));
807 self.instruction(I32Const(
808 i32::try_from(adapter.lift.instance.as_u32()).unwrap(),
809 ));
810 let enter_sync_call = self.module.import_enter_sync_call();
811 self.instruction(Call(enter_sync_call.as_u32()));
812
813 old_task_may_block
814 } else if self.emit_resource_call {
815 assert!(!self.types[adapter.lift.ty].async_);
816 self.instruction(I32Const(
817 i32::try_from(adapter.lower.instance.as_u32()).unwrap(),
818 ));
819 self.instruction(I32Const(0));
820 self.instruction(I32Const(
821 i32::try_from(adapter.lift.instance.as_u32()).unwrap(),
822 ));
823 let enter_sync_call = self.module.import_enter_sync_call();
824 self.instruction(Call(enter_sync_call.as_u32()));
825 None
826 } else {
827 None
828 };
829
830 let saved_lift_may_leave = self.clear_may_leave(adapter.lift.flags);
865 let param_locals = lower_sig
866 .params
867 .iter()
868 .enumerate()
869 .map(|(i, ty)| (i as u32, *ty))
870 .collect::<Vec<_>>();
871 self.translate_params(adapter, ¶m_locals);
872 self.restore_may_leave(adapter.lift.flags, saved_lift_may_leave);
873
874 self.instruction(Call(adapter.callee.as_u32()));
878 let mut result_locals = Vec::with_capacity(lift_sig.results.len());
879 let mut temps = Vec::new();
880 for ty in lift_sig.results.iter().rev() {
881 let local = self.local_set_new_tmp(*ty);
882 result_locals.push((local.idx, *ty));
883 temps.push(local);
884 }
885 result_locals.reverse();
886
887 if self.emit_resource_call || self.module.tunables.concurrency_support {
904 let exit_sync_call = self.module.import_exit_sync_call();
905 self.instruction(Call(exit_sync_call.as_u32()));
906 }
907
908 self.set_may_leave_false(adapter.lower.flags);
914 self.translate_results(adapter, ¶m_locals, &result_locals);
915 self.restore_may_leave(adapter.lower.flags, saved_lower_may_leave);
916
917 if let Some(func) = adapter.lift.post_return {
920 for (result, _) in result_locals.iter() {
921 self.instruction(LocalGet(*result));
922 }
923 self.instruction(Call(func.as_u32()));
924 }
925
926 for tmp in temps {
927 self.free_temp_local(tmp);
928 }
929
930 if self.module.tunables.concurrency_support {
931 if let Some(old_task_may_block) = old_task_may_block {
933 let task_may_block = self.module.import_task_may_block();
934 self.instruction(LocalGet(old_task_may_block.idx));
935 self.instruction(GlobalSet(task_may_block.as_u32()));
936 self.free_temp_local(old_task_may_block);
937 }
938 }
939
940 self.exit_exception_barrier();
941
942 self.finish()
943 }
944
945 fn translate_params(&mut self, adapter: &AdapterData, param_locals: &[(u32, ValType)]) {
946 let src_tys = self.types[adapter.lower.ty].params;
947 let src_tys = self.types[src_tys]
948 .types
949 .iter()
950 .copied()
951 .collect::<Vec<_>>();
952 let dst_tys = self.types[adapter.lift.ty].params;
953 let dst_tys = self.types[dst_tys]
954 .types
955 .iter()
956 .copied()
957 .collect::<Vec<_>>();
958 let lift_opts = &adapter.lift.options;
959 let lower_opts = &adapter.lower.options;
960
961 assert_eq!(src_tys.len(), dst_tys.len());
963
964 let max_flat_params = if adapter.lower.options.async_ {
968 MAX_FLAT_ASYNC_PARAMS
969 } else {
970 MAX_FLAT_PARAMS
971 };
972 let src_flat =
973 self.types
974 .flatten_types(lower_opts, max_flat_params, src_tys.iter().copied());
975 let dst_flat =
976 self.types
977 .flatten_types(lift_opts, MAX_FLAT_PARAMS, dst_tys.iter().copied());
978
979 let src = if let Some(flat) = &src_flat {
980 Source::Stack(Stack {
981 locals: ¶m_locals[..flat.len()],
982 opts: lower_opts,
983 })
984 } else {
985 let lower_mem_opts = lower_opts.data_model.unwrap_memory();
989 let (addr, ty) = param_locals[0];
990 assert_eq!(ty, lower_mem_opts.ptr());
991 let abi = CanonicalAbiInfo::record(src_tys.iter().map(|t| self.types.canonical_abi(t)));
992 Source::Memory(self.memory_operand_abi(
993 lower_opts,
994 TempLocal::new(addr, ty),
995 &abi,
996 Trap::MemoryOutOfBounds,
997 ))
998 };
999
1000 let dst = if let Some(flat) = &dst_flat {
1001 Destination::Stack(flat, lift_opts)
1002 } else {
1003 let abi = CanonicalAbiInfo::record(dst_tys.iter().map(|t| self.types.canonical_abi(t)));
1006 Destination::Memory(self.malloc_abi(lift_opts, &abi, Trap::MemoryOutOfBounds))
1007 };
1008
1009 let srcs = src
1010 .record_field_srcs(self.types, src_tys.iter().copied())
1011 .zip(src_tys.iter());
1012 let dsts = dst
1013 .record_field_dsts(self.types, dst_tys.iter().copied())
1014 .zip(dst_tys.iter());
1015 for ((src, src_ty), (dst, dst_ty)) in srcs.zip(dsts) {
1016 self.translate(&src_ty, &src, &dst_ty, &dst);
1017 }
1018
1019 if let Destination::Memory(mem) = dst {
1023 self.instruction(LocalGet(mem.addr.idx));
1024 self.free_temp_local(mem.addr);
1025 }
1026 }
1027
1028 fn translate_results(
1029 &mut self,
1030 adapter: &AdapterData,
1031 param_locals: &[(u32, ValType)],
1032 result_locals: &[(u32, ValType)],
1033 ) {
1034 let src_tys = self.types[adapter.lift.ty].results;
1035 let src_tys = self.types[src_tys]
1036 .types
1037 .iter()
1038 .copied()
1039 .collect::<Vec<_>>();
1040 let dst_tys = self.types[adapter.lower.ty].results;
1041 let dst_tys = self.types[dst_tys]
1042 .types
1043 .iter()
1044 .copied()
1045 .collect::<Vec<_>>();
1046 let lift_opts = &adapter.lift.options;
1047 let lower_opts = &adapter.lower.options;
1048
1049 let src_flat = self
1050 .types
1051 .flatten_lifting_types(lift_opts, src_tys.iter().copied());
1052 let dst_flat = self
1053 .types
1054 .flatten_lowering_types(lower_opts, dst_tys.iter().copied());
1055
1056 let src = if src_flat.is_some() {
1057 Source::Stack(Stack {
1058 locals: result_locals,
1059 opts: lift_opts,
1060 })
1061 } else {
1062 let abi = CanonicalAbiInfo::record(src_tys.iter().map(|t| self.types.canonical_abi(t)));
1067 assert_eq!(
1068 result_locals.len(),
1069 if lower_opts.async_ || lift_opts.async_ {
1070 2
1071 } else {
1072 1
1073 }
1074 );
1075 let (addr, ty) = result_locals[0];
1076 assert_eq!(ty, lift_opts.data_model.unwrap_memory().ptr());
1077 Source::Memory(self.memory_operand_abi(
1078 lift_opts,
1079 TempLocal::new(addr, ty),
1080 &abi,
1081 Trap::MemoryOutOfBounds,
1082 ))
1083 };
1084
1085 let dst = if let Some(flat) = &dst_flat {
1086 Destination::Stack(flat, lower_opts)
1087 } else {
1088 let abi = CanonicalAbiInfo::record(dst_tys.iter().map(|t| self.types.canonical_abi(t)));
1092 let (addr, ty) = *param_locals.last().expect("no retptr");
1093 assert_eq!(ty, lower_opts.data_model.unwrap_memory().ptr());
1094 Destination::Memory(self.memory_operand_abi(
1095 lower_opts,
1096 TempLocal::new(addr, ty),
1097 &abi,
1098 Trap::MemoryOutOfBounds,
1099 ))
1100 };
1101
1102 let srcs = src
1103 .record_field_srcs(self.types, src_tys.iter().copied())
1104 .zip(src_tys.iter());
1105 let dsts = dst
1106 .record_field_dsts(self.types, dst_tys.iter().copied())
1107 .zip(dst_tys.iter());
1108 for ((src, src_ty), (dst, dst_ty)) in srcs.zip(dsts) {
1109 self.translate(&src_ty, &src, &dst_ty, &dst);
1110 }
1111 }
1112
1113 fn translate(
1114 &mut self,
1115 src_ty: &InterfaceType,
1116 src: &Source<'_>,
1117 dst_ty: &InterfaceType,
1118 dst: &Destination,
1119 ) {
1120 if let Source::Memory(mem) = src {
1121 self.assert_aligned(src_ty, mem);
1122 }
1123 if let Destination::Memory(mem) = dst {
1124 self.assert_aligned(dst_ty, mem);
1125 }
1126
1127 let cost = match src_ty {
1157 InterfaceType::Bool
1161 | InterfaceType::U8
1162 | InterfaceType::S8
1163 | InterfaceType::U16
1164 | InterfaceType::S16
1165 | InterfaceType::U32
1166 | InterfaceType::S32
1167 | InterfaceType::U64
1168 | InterfaceType::S64
1169 | InterfaceType::Float32
1170 | InterfaceType::Float64 => 0,
1171
1172 InterfaceType::Char => 1,
1175
1176 InterfaceType::String => 40,
1179
1180 InterfaceType::List(_) => 40,
1183 InterfaceType::Map(_) => 40,
1185
1186 InterfaceType::Flags(i) => {
1187 let count = self.module.types[*i].names.len();
1188 match FlagsSize::from_count(count) {
1189 FlagsSize::Size0 => 0,
1190 FlagsSize::Size1 | FlagsSize::Size2 => 1,
1191 FlagsSize::Size4Plus(n) => n.into(),
1192 }
1193 }
1194
1195 InterfaceType::Record(i) => self.types[*i].fields.len(),
1196 InterfaceType::Tuple(i) => self.types[*i].types.len(),
1197 InterfaceType::Variant(i) => self.types[*i].cases.len(),
1198 InterfaceType::Enum(i) => self.types[*i].names.len(),
1199
1200 InterfaceType::Option(_) | InterfaceType::Result(_) => 2,
1202
1203 InterfaceType::Own(_)
1205 | InterfaceType::Borrow(_)
1206 | InterfaceType::Future(_)
1207 | InterfaceType::Stream(_)
1208 | InterfaceType::ErrorContext(_) => 1,
1209 InterfaceType::FixedLengthList(i) => self.types[*i].size as usize,
1210 };
1211
1212 match self.fuel.checked_sub(cost) {
1213 Some(n) => {
1219 self.fuel = n;
1220 match src_ty {
1221 InterfaceType::Bool => self.translate_bool(src, dst_ty, dst),
1222 InterfaceType::U8 => self.translate_u8(src, dst_ty, dst),
1223 InterfaceType::S8 => self.translate_s8(src, dst_ty, dst),
1224 InterfaceType::U16 => self.translate_u16(src, dst_ty, dst),
1225 InterfaceType::S16 => self.translate_s16(src, dst_ty, dst),
1226 InterfaceType::U32 => self.translate_u32(src, dst_ty, dst),
1227 InterfaceType::S32 => self.translate_s32(src, dst_ty, dst),
1228 InterfaceType::U64 => self.translate_u64(src, dst_ty, dst),
1229 InterfaceType::S64 => self.translate_s64(src, dst_ty, dst),
1230 InterfaceType::Float32 => self.translate_f32(src, dst_ty, dst),
1231 InterfaceType::Float64 => self.translate_f64(src, dst_ty, dst),
1232 InterfaceType::Char => self.translate_char(src, dst_ty, dst),
1233 InterfaceType::String => self.translate_string(src, dst_ty, dst),
1234 InterfaceType::List(t) => self.translate_list(*t, src, dst_ty, dst),
1235 InterfaceType::Map(t) => self.translate_map(*t, src, dst_ty, dst),
1236 InterfaceType::Record(t) => self.translate_record(*t, src, dst_ty, dst),
1237 InterfaceType::Flags(f) => self.translate_flags(*f, src, dst_ty, dst),
1238 InterfaceType::Tuple(t) => self.translate_tuple(*t, src, dst_ty, dst),
1239 InterfaceType::Variant(v) => self.translate_variant(*v, src, dst_ty, dst),
1240 InterfaceType::Enum(t) => self.translate_enum(*t, src, dst_ty, dst),
1241 InterfaceType::Option(t) => self.translate_option(*t, src, dst_ty, dst),
1242 InterfaceType::Result(t) => self.translate_result(*t, src, dst_ty, dst),
1243 InterfaceType::Own(t) => self.translate_own(*t, src, dst_ty, dst),
1244 InterfaceType::Borrow(t) => self.translate_borrow(*t, src, dst_ty, dst),
1245 InterfaceType::Future(t) => self.translate_future(*t, src, dst_ty, dst),
1246 InterfaceType::Stream(t) => self.translate_stream(*t, src, dst_ty, dst),
1247 InterfaceType::ErrorContext(t) => {
1248 self.translate_error_context(*t, src, dst_ty, dst)
1249 }
1250 InterfaceType::FixedLengthList(t) => {
1251 self.translate_fixed_length_list(*t, src, dst_ty, dst);
1252 }
1253 }
1254 }
1255
1256 None => {
1262 let src_loc = match src {
1263 Source::Stack(stack) => {
1267 for (i, ty) in stack
1268 .opts
1269 .flat_types(src_ty, self.types)
1270 .unwrap()
1271 .iter()
1272 .enumerate()
1273 {
1274 let stack = stack.slice(i..i + 1);
1275 self.stack_get(&stack, (*ty).into());
1276 }
1277 HelperLocation::Stack
1278 }
1279 Source::Memory(mem) => {
1284 self.push_mem_addr(mem);
1285 HelperLocation::Memory
1286 }
1287 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1288 };
1289 let dst_loc = match dst {
1290 Destination::Stack(..) => HelperLocation::Stack,
1291 Destination::Memory(mem) => {
1292 self.push_mem_addr(mem);
1293 HelperLocation::Memory
1294 }
1295 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1296 };
1297 let helper = self.module.translate_helper(Helper {
1303 src: HelperType {
1304 ty: *src_ty,
1305 opts: *src.opts(),
1306 loc: src_loc,
1307 },
1308 dst: HelperType {
1309 ty: *dst_ty,
1310 opts: *dst.opts(),
1311 loc: dst_loc,
1312 },
1313 });
1314 self.flush_code();
1317 self.module.funcs[self.result].body.push(Body::Call(helper));
1318
1319 if let Destination::Stack(tys, opts) = dst {
1328 let flat = self
1329 .types
1330 .flatten_types(opts, usize::MAX, [*dst_ty])
1331 .unwrap();
1332 assert_eq!(flat.len(), tys.len());
1333 let locals = flat
1334 .iter()
1335 .rev()
1336 .map(|ty| self.local_set_new_tmp(*ty))
1337 .collect::<Vec<_>>();
1338 for (ty, local) in tys.iter().zip(locals.into_iter().rev()) {
1339 self.instruction(LocalGet(local.idx));
1340 self.stack_set(std::slice::from_ref(ty), local.ty);
1341 self.free_temp_local(local);
1342 }
1343 }
1344 }
1345 }
1346 }
1347
1348 fn push_mem_addr(&mut self, mem: &Memory<'_>) {
1349 self.instruction(LocalGet(mem.addr.idx));
1350 if mem.offset != 0 {
1351 self.ptr_uconst(mem.mem_opts(), mem.offset);
1352 self.ptr_add(mem.mem_opts());
1353 }
1354 }
1355
1356 fn translate_bool(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1357 assert!(matches!(dst_ty, InterfaceType::Bool));
1359 self.push_dst_addr(dst);
1360
1361 self.instruction(I32Const(1));
1364 self.instruction(I32Const(0));
1365 match src {
1366 Source::Memory(mem) => self.i32_load8u(mem),
1367 Source::Stack(stack) => self.stack_get(stack, ValType::I32),
1368 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1369 }
1370 self.instruction(Select);
1371
1372 match dst {
1373 Destination::Memory(mem) => self.i32_store8(mem),
1374 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1375 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1376 }
1377 }
1378
1379 fn translate_u8(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1380 assert!(matches!(dst_ty, InterfaceType::U8));
1382 self.convert_u8_mask(src, dst, 0xff);
1383 }
1384
1385 fn convert_u8_mask(&mut self, src: &Source<'_>, dst: &Destination<'_>, mask: u8) {
1386 self.push_dst_addr(dst);
1387 let mut needs_mask = true;
1388 match src {
1389 Source::Memory(mem) => {
1390 self.i32_load8u(mem);
1391 needs_mask = mask != 0xff;
1392 }
1393 Source::Stack(stack) => {
1394 self.stack_get(stack, ValType::I32);
1395 }
1396 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1397 }
1398 if needs_mask {
1399 self.instruction(I32Const(i32::from(mask)));
1400 self.instruction(I32And);
1401 }
1402 match dst {
1403 Destination::Memory(mem) => self.i32_store8(mem),
1404 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1405 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1406 }
1407 }
1408
1409 fn translate_s8(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1410 assert!(matches!(dst_ty, InterfaceType::S8));
1412 self.push_dst_addr(dst);
1413 match src {
1414 Source::Memory(mem) => self.i32_load8s(mem),
1415 Source::Stack(stack) => {
1416 self.stack_get(stack, ValType::I32);
1417 self.instruction(I32Extend8S);
1418 }
1419 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1420 }
1421 match dst {
1422 Destination::Memory(mem) => self.i32_store8(mem),
1423 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1424 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1425 }
1426 }
1427
1428 fn translate_u16(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1429 assert!(matches!(dst_ty, InterfaceType::U16));
1431 self.convert_u16_mask(src, dst, 0xffff);
1432 }
1433
1434 fn convert_u16_mask(&mut self, src: &Source<'_>, dst: &Destination<'_>, mask: u16) {
1435 self.push_dst_addr(dst);
1436 let mut needs_mask = true;
1437 match src {
1438 Source::Memory(mem) => {
1439 self.i32_load16u(mem);
1440 needs_mask = mask != 0xffff;
1441 }
1442 Source::Stack(stack) => {
1443 self.stack_get(stack, ValType::I32);
1444 }
1445 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1446 }
1447 if needs_mask {
1448 self.instruction(I32Const(i32::from(mask)));
1449 self.instruction(I32And);
1450 }
1451 match dst {
1452 Destination::Memory(mem) => self.i32_store16(mem),
1453 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1454 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1455 }
1456 }
1457
1458 fn translate_s16(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1459 assert!(matches!(dst_ty, InterfaceType::S16));
1461 self.push_dst_addr(dst);
1462 match src {
1463 Source::Memory(mem) => self.i32_load16s(mem),
1464 Source::Stack(stack) => {
1465 self.stack_get(stack, ValType::I32);
1466 self.instruction(I32Extend16S);
1467 }
1468 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1469 }
1470 match dst {
1471 Destination::Memory(mem) => self.i32_store16(mem),
1472 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1473 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1474 }
1475 }
1476
1477 fn translate_u32(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1478 assert!(matches!(dst_ty, InterfaceType::U32));
1480 self.convert_u32_mask(src, dst, 0xffffffff)
1481 }
1482
1483 fn convert_u32_mask(&mut self, src: &Source<'_>, dst: &Destination<'_>, mask: u32) {
1484 self.push_dst_addr(dst);
1485 match src {
1486 Source::Memory(mem) => self.i32_load(mem),
1487 Source::Stack(stack) => self.stack_get(stack, ValType::I32),
1488 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1489 }
1490 if mask != 0xffffffff {
1491 self.instruction(I32Const(mask as i32));
1492 self.instruction(I32And);
1493 }
1494 match dst {
1495 Destination::Memory(mem) => self.i32_store(mem),
1496 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1497 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1498 }
1499 }
1500
1501 fn translate_s32(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1502 assert!(matches!(dst_ty, InterfaceType::S32));
1504 self.push_dst_addr(dst);
1505 match src {
1506 Source::Memory(mem) => self.i32_load(mem),
1507 Source::Stack(stack) => self.stack_get(stack, ValType::I32),
1508 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1509 }
1510 match dst {
1511 Destination::Memory(mem) => self.i32_store(mem),
1512 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1513 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1514 }
1515 }
1516
1517 fn translate_u64(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1518 assert!(matches!(dst_ty, InterfaceType::U64));
1520 self.push_dst_addr(dst);
1521 match src {
1522 Source::Memory(mem) => self.i64_load(mem),
1523 Source::Stack(stack) => self.stack_get(stack, ValType::I64),
1524 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1525 }
1526 match dst {
1527 Destination::Memory(mem) => self.i64_store(mem),
1528 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I64),
1529 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1530 }
1531 }
1532
1533 fn translate_s64(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1534 assert!(matches!(dst_ty, InterfaceType::S64));
1536 self.push_dst_addr(dst);
1537 match src {
1538 Source::Memory(mem) => self.i64_load(mem),
1539 Source::Stack(stack) => self.stack_get(stack, ValType::I64),
1540 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1541 }
1542 match dst {
1543 Destination::Memory(mem) => self.i64_store(mem),
1544 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I64),
1545 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1546 }
1547 }
1548
1549 fn translate_f32(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1550 assert!(matches!(dst_ty, InterfaceType::Float32));
1552 self.push_dst_addr(dst);
1553 match src {
1554 Source::Memory(mem) => self.f32_load(mem),
1555 Source::Stack(stack) => self.stack_get(stack, ValType::F32),
1556 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1557 }
1558 match dst {
1559 Destination::Memory(mem) => self.f32_store(mem),
1560 Destination::Stack(stack, _) => self.stack_set(stack, ValType::F32),
1561 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1562 }
1563 }
1564
1565 fn translate_f64(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1566 assert!(matches!(dst_ty, InterfaceType::Float64));
1568 self.push_dst_addr(dst);
1569 match src {
1570 Source::Memory(mem) => self.f64_load(mem),
1571 Source::Stack(stack) => self.stack_get(stack, ValType::F64),
1572 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1573 }
1574 match dst {
1575 Destination::Memory(mem) => self.f64_store(mem),
1576 Destination::Stack(stack, _) => self.stack_set(stack, ValType::F64),
1577 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1578 }
1579 }
1580
1581 fn translate_char(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1582 assert!(matches!(dst_ty, InterfaceType::Char));
1583 match src {
1584 Source::Memory(mem) => self.i32_load(mem),
1585 Source::Stack(stack) => self.stack_get(stack, ValType::I32),
1586 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1587 }
1588 let local = self.local_set_new_tmp(ValType::I32);
1589
1590 self.instruction(Block(BlockType::Empty));
1606 self.instruction(Block(BlockType::Empty));
1607 self.instruction(LocalGet(local.idx));
1608 self.instruction(I32Const(0xd800));
1609 self.instruction(I32Xor);
1610 self.instruction(I32Const(-0x110000));
1611 self.instruction(I32Add);
1612 self.instruction(I32Const(-0x10f800));
1613 self.instruction(I32LtU);
1614 self.instruction(BrIf(0));
1615 self.instruction(LocalGet(local.idx));
1616 self.instruction(I32Const(0x110000));
1617 self.instruction(I32Ne);
1618 self.instruction(BrIf(1));
1619 self.instruction(End);
1620 self.trap(Trap::InvalidChar);
1621 self.instruction(End);
1622
1623 self.push_dst_addr(dst);
1624 self.instruction(LocalGet(local.idx));
1625 match dst {
1626 Destination::Memory(mem) => {
1627 self.i32_store(mem);
1628 }
1629 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1630 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1631 }
1632
1633 self.free_temp_local(local);
1634 }
1635
1636 fn translate_string(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1637 assert!(matches!(dst_ty, InterfaceType::String));
1638 let src_opts = src.opts();
1639 let dst_opts = dst.opts();
1640
1641 let src_mem_opts = match &src_opts.data_model {
1642 DataModel::Gc {} => todo!("CM+GC"),
1643 DataModel::LinearMemory(opts) => opts,
1644 };
1645 let dst_mem_opts = match &dst_opts.data_model {
1646 DataModel::Gc {} => todo!("CM+GC"),
1647 DataModel::LinearMemory(opts) => opts,
1648 };
1649
1650 match src {
1655 Source::Stack(s) => {
1656 assert_eq!(s.locals.len(), 2);
1657 self.stack_get(&s.slice(0..1), src_mem_opts.ptr());
1658 self.stack_get(&s.slice(1..2), src_mem_opts.ptr());
1659 }
1660 Source::Memory(mem) => {
1661 self.ptr_load(mem);
1662 self.ptr_load(&mem.bump(src_mem_opts.ptr_size().into()));
1663 }
1664 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1665 }
1666 let src_len = self.local_set_new_tmp(src_mem_opts.ptr());
1667 let src_ptr = self.local_set_new_tmp(src_mem_opts.ptr());
1668 let src_str = WasmString {
1669 ptr: src_ptr,
1670 len: src_len,
1671 opts: src_opts,
1672 };
1673
1674 let dst_str = match src_opts.string_encoding {
1675 StringEncoding::Utf8 => {
1676 self.validate_guest_pointer(
1677 src_opts,
1678 &src_str.ptr,
1679 &AllocSize::Local(src_str.len.idx),
1680 1,
1681 Trap::StringOutOfBounds,
1682 );
1683 match dst_opts.string_encoding {
1684 StringEncoding::Utf8 => {
1685 self.string_copy(&src_str, FE::Utf8, dst_opts, FE::Utf8)
1686 }
1687 StringEncoding::Utf16 => self.string_utf8_to_utf16(&src_str, dst_opts),
1688 StringEncoding::CompactUtf16 => {
1689 self.string_to_compact(&src_str, FE::Utf8, dst_opts)
1690 }
1691 }
1692 }
1693
1694 StringEncoding::Utf16 => {
1695 self.validate_guest_pointer(
1696 src_opts,
1697 &src_str.ptr,
1698 &AllocSize::DoubleLocal(src_str.len.idx),
1699 2,
1700 Trap::StringOutOfBounds,
1701 );
1702 match dst_opts.string_encoding {
1703 StringEncoding::Utf8 => {
1704 self.string_deflate_to_utf8(&src_str, FE::Utf16, dst_opts)
1705 }
1706 StringEncoding::Utf16 => {
1707 self.string_copy(&src_str, FE::Utf16, dst_opts, FE::Utf16)
1708 }
1709 StringEncoding::CompactUtf16 => {
1710 self.string_to_compact(&src_str, FE::Utf16, dst_opts)
1711 }
1712 }
1713 }
1714
1715 StringEncoding::CompactUtf16 => {
1716 self.instruction(LocalGet(src_str.len.idx));
1719 self.ptr_uconst(src_mem_opts, UTF16_TAG);
1720 self.ptr_and(src_mem_opts);
1721 self.ptr_if(src_mem_opts, BlockType::Empty);
1722
1723 self.instruction(LocalGet(src_str.len.idx));
1727 self.ptr_uconst(src_mem_opts, UTF16_TAG);
1728 self.ptr_xor(src_mem_opts);
1729 self.instruction(LocalSet(src_str.len.idx));
1730
1731 self.validate_guest_pointer(
1735 src_opts,
1736 &src_str.ptr,
1737 &AllocSize::DoubleLocal(src_str.len.idx),
1738 2,
1739 Trap::StringOutOfBounds,
1740 );
1741
1742 let s1 = match dst_opts.string_encoding {
1743 StringEncoding::Utf8 => {
1744 self.string_deflate_to_utf8(&src_str, FE::Utf16, dst_opts)
1745 }
1746 StringEncoding::Utf16 => {
1747 self.string_copy(&src_str, FE::Utf16, dst_opts, FE::Utf16)
1748 }
1749 StringEncoding::CompactUtf16 => {
1750 self.string_compact_utf16_to_compact(&src_str, dst_opts)
1751 }
1752 };
1753
1754 self.instruction(Else);
1755
1756 self.validate_guest_pointer(
1759 src_opts,
1760 &src_str.ptr,
1761 &AllocSize::Local(src_str.len.idx),
1762 2,
1763 Trap::StringOutOfBounds,
1764 );
1765
1766 let s2 = match dst_opts.string_encoding {
1770 StringEncoding::Utf16 => {
1771 self.string_copy(&src_str, FE::Latin1, dst_opts, FE::Utf16)
1772 }
1773 StringEncoding::Utf8 => {
1774 self.string_deflate_to_utf8(&src_str, FE::Latin1, dst_opts)
1775 }
1776 StringEncoding::CompactUtf16 => {
1777 self.string_copy(&src_str, FE::Latin1, dst_opts, FE::Latin1)
1778 }
1779 };
1780 self.instruction(LocalGet(s2.ptr.idx));
1783 self.instruction(LocalSet(s1.ptr.idx));
1784 self.instruction(LocalGet(s2.len.idx));
1785 self.instruction(LocalSet(s1.len.idx));
1786 self.instruction(End);
1787 self.free_temp_local(s2.ptr);
1788 self.free_temp_local(s2.len);
1789 s1
1790 }
1791 };
1792
1793 match dst {
1795 Destination::Stack(s, _) => {
1796 self.instruction(LocalGet(dst_str.ptr.idx));
1797 self.stack_set(&s[..1], dst_mem_opts.ptr());
1798 self.instruction(LocalGet(dst_str.len.idx));
1799 self.stack_set(&s[1..], dst_mem_opts.ptr());
1800 }
1801 Destination::Memory(mem) => {
1802 self.instruction(LocalGet(mem.addr.idx));
1803 self.instruction(LocalGet(dst_str.ptr.idx));
1804 self.ptr_store(mem);
1805 self.instruction(LocalGet(mem.addr.idx));
1806 self.instruction(LocalGet(dst_str.len.idx));
1807 self.ptr_store(&mem.bump(dst_mem_opts.ptr_size().into()));
1808 }
1809 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1810 }
1811
1812 self.free_temp_local(src_str.ptr);
1813 self.free_temp_local(src_str.len);
1814 self.free_temp_local(dst_str.ptr);
1815 self.free_temp_local(dst_str.len);
1816 }
1817
1818 fn string_copy<'c>(
1831 &mut self,
1832 src: &WasmString<'_>,
1833 src_enc: FE,
1834 dst_opts: &'c Options,
1835 dst_enc: FE,
1836 ) -> WasmString<'c> {
1837 assert!(dst_enc.width() >= src_enc.width());
1838
1839 self.validate_string_length(src, dst_enc);
1844
1845 let src_mem_opts = {
1846 match &src.opts.data_model {
1847 DataModel::Gc {} => todo!("CM+GC"),
1848 DataModel::LinearMemory(opts) => opts,
1849 }
1850 };
1851 let dst_mem_opts = {
1852 match &dst_opts.data_model {
1853 DataModel::Gc {} => todo!("CM+GC"),
1854 DataModel::LinearMemory(opts) => opts,
1855 }
1856 };
1857
1858 self.convert_src_len_to_dst(src.len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
1861 let dst_len = self.local_tee_new_tmp(dst_mem_opts.ptr());
1862 if dst_enc.width() > 1 {
1863 assert_eq!(dst_enc.width(), 2);
1864 self.ptr_uconst(dst_mem_opts, 1);
1865 self.ptr_shl(dst_mem_opts);
1866 }
1867 let dst_byte_len = self.local_set_new_tmp(dst_mem_opts.ptr());
1868
1869 let dst = {
1872 let dst_mem = self.malloc(
1873 dst_opts,
1874 AllocSize::Local(dst_byte_len.idx),
1875 dst_enc.align().into(),
1876 Trap::StringOutOfBounds,
1877 );
1878 WasmString {
1879 ptr: dst_mem.addr,
1880 len: dst_len,
1881 opts: dst_opts,
1882 }
1883 };
1884
1885 let op = if src_enc == dst_enc {
1889 Transcode::Copy(src_enc)
1890 } else {
1891 assert_eq!(src_enc, FE::Latin1);
1892 assert_eq!(dst_enc, FE::Utf16);
1893 Transcode::Latin1ToUtf16
1894 };
1895 let transcode = self.transcoder(src, &dst, op);
1896 self.instruction(LocalGet(src.ptr.idx));
1897 self.instruction(LocalGet(src.len.idx));
1898 self.instruction(LocalGet(dst.ptr.idx));
1899 self.instruction(Call(transcode.as_u32()));
1900
1901 self.free_temp_local(dst_byte_len);
1902
1903 dst
1904 }
1905
1906 fn string_deflate_to_utf8<'c>(
1919 &mut self,
1920 src: &WasmString<'_>,
1921 src_enc: FE,
1922 dst_opts: &'c Options,
1923 ) -> WasmString<'c> {
1924 let src_mem_opts = match &src.opts.data_model {
1925 DataModel::Gc {} => todo!("CM+GC"),
1926 DataModel::LinearMemory(opts) => opts,
1927 };
1928 let dst_mem_opts = match &dst_opts.data_model {
1929 DataModel::Gc {} => todo!("CM+GC"),
1930 DataModel::LinearMemory(opts) => opts,
1931 };
1932
1933 self.validate_string_length(src, src_enc);
1934
1935 self.convert_src_len_to_dst(
1939 src.len.idx,
1940 src.opts.data_model.unwrap_memory().ptr(),
1941 dst_opts.data_model.unwrap_memory().ptr(),
1942 );
1943 let dst_len = self.local_tee_new_tmp(dst_opts.data_model.unwrap_memory().ptr());
1944 let dst_byte_len = self.local_set_new_tmp(dst_opts.data_model.unwrap_memory().ptr());
1945
1946 let dst = {
1947 let dst_mem = self.malloc(
1948 dst_opts,
1949 AllocSize::Local(dst_byte_len.idx),
1950 1,
1951 Trap::StringOutOfBounds,
1952 );
1953 WasmString {
1954 ptr: dst_mem.addr,
1955 len: dst_len,
1956 opts: dst_opts,
1957 }
1958 };
1959
1960 let op = match src_enc {
1962 FE::Latin1 => Transcode::Latin1ToUtf8,
1963 FE::Utf16 => Transcode::Utf16ToUtf8,
1964 FE::Utf8 => unreachable!(),
1965 };
1966 let transcode = self.transcoder(src, &dst, op);
1967 self.instruction(LocalGet(src.ptr.idx));
1968 self.instruction(LocalGet(src.len.idx));
1969 self.instruction(LocalGet(dst.ptr.idx));
1970 self.instruction(LocalGet(dst_byte_len.idx));
1971 self.instruction(I32Const(1)); self.instruction(Call(transcode.as_u32()));
1973 self.instruction(LocalSet(dst.len.idx));
1974 let src_len_tmp = self.local_set_new_tmp(src.opts.data_model.unwrap_memory().ptr());
1975
1976 self.instruction(LocalGet(src_len_tmp.idx));
1980 self.instruction(LocalGet(src.len.idx));
1981 self.ptr_ne(src_mem_opts);
1982 self.instruction(If(BlockType::Empty));
1983
1984 let factor = match src_enc {
1987 FE::Latin1 => 2,
1988 FE::Utf16 => 3,
1989 _ => unreachable!(),
1990 };
1991 self.validate_string_length_u8(src, factor);
1992 self.convert_src_len_to_dst(
1993 src.len.idx,
1994 src.opts.data_model.unwrap_memory().ptr(),
1995 dst_opts.data_model.unwrap_memory().ptr(),
1996 );
1997 self.ptr_uconst(dst_mem_opts, factor.into());
1998 self.ptr_mul(dst_mem_opts);
1999 let new_byte_len = self.local_set_new_tmp(dst_mem_opts.ptr());
2000
2001 self.realloc(
2005 dst_opts,
2006 &dst.ptr,
2007 AllocSize::Local(dst_byte_len.idx),
2008 AllocSize::Local(new_byte_len.idx),
2009 1,
2010 Trap::StringOutOfBounds,
2011 );
2012 self.instruction(LocalGet(new_byte_len.idx));
2013 self.instruction(LocalSet(dst_byte_len.idx));
2014 self.free_temp_local(new_byte_len);
2015
2016 self.instruction(LocalGet(src.ptr.idx));
2021 self.instruction(LocalGet(src_len_tmp.idx));
2022 if let FE::Utf16 = src_enc {
2023 self.ptr_uconst(src_mem_opts, 1);
2024 self.ptr_shl(src_mem_opts);
2025 }
2026 self.ptr_add(src_mem_opts);
2027 self.instruction(LocalGet(src.len.idx));
2028 self.instruction(LocalGet(src_len_tmp.idx));
2029 self.ptr_sub(src_mem_opts);
2030 self.instruction(LocalGet(dst.ptr.idx));
2031 self.instruction(LocalGet(dst.len.idx));
2032 self.ptr_add(dst_mem_opts);
2033 self.instruction(LocalGet(dst_byte_len.idx));
2034 self.instruction(LocalGet(dst.len.idx));
2035 self.ptr_sub(dst_mem_opts);
2036 self.instruction(I32Const(0)); self.instruction(Call(transcode.as_u32()));
2038
2039 self.instruction(LocalGet(dst.len.idx));
2043 self.ptr_add(dst_mem_opts);
2044 self.instruction(LocalSet(dst.len.idx));
2045
2046 if self.module.tunables.debug_adapter_modules {
2049 self.instruction(LocalGet(src.len.idx));
2050 self.instruction(LocalGet(src_len_tmp.idx));
2051 self.ptr_sub(src_mem_opts);
2052 self.ptr_ne(src_mem_opts);
2053 self.instruction(If(BlockType::Empty));
2054 self.trap(Trap::DebugAssertStringEncodingFinished);
2055 self.instruction(End);
2056 } else {
2057 self.instruction(Drop);
2058 }
2059
2060 self.instruction(LocalGet(dst.len.idx));
2062 self.instruction(LocalGet(dst_byte_len.idx));
2063 self.ptr_ne(dst_mem_opts);
2064 self.instruction(If(BlockType::Empty));
2065 self.realloc(
2066 dst_opts,
2067 &dst.ptr,
2068 AllocSize::Local(dst_byte_len.idx),
2069 AllocSize::Local(dst.len.idx),
2070 1,
2071 Trap::StringOutOfBounds,
2072 );
2073 self.instruction(End);
2074
2075 if self.module.tunables.debug_adapter_modules {
2078 self.instruction(Else);
2079
2080 self.instruction(LocalGet(dst.len.idx));
2081 self.instruction(LocalGet(dst_byte_len.idx));
2082 self.ptr_ne(dst_mem_opts);
2083 self.instruction(If(BlockType::Empty));
2084 self.trap(Trap::DebugAssertStringEncodingFinished);
2085 self.instruction(End);
2086 }
2087
2088 self.instruction(End); self.free_temp_local(src_len_tmp);
2091 self.free_temp_local(dst_byte_len);
2092
2093 dst
2094 }
2095
2096 fn string_utf8_to_utf16<'c>(
2111 &mut self,
2112 src: &WasmString<'_>,
2113 dst_opts: &'c Options,
2114 ) -> WasmString<'c> {
2115 let src_mem_opts = match &src.opts.data_model {
2116 DataModel::Gc {} => todo!("CM+GC"),
2117 DataModel::LinearMemory(opts) => opts,
2118 };
2119 let dst_mem_opts = match &dst_opts.data_model {
2120 DataModel::Gc {} => todo!("CM+GC"),
2121 DataModel::LinearMemory(opts) => opts,
2122 };
2123
2124 self.validate_string_length(src, FE::Utf16);
2125 self.convert_src_len_to_dst(
2126 src.len.idx,
2127 src_mem_opts.ptr(),
2128 dst_opts.data_model.unwrap_memory().ptr(),
2129 );
2130 let dst_len = self.local_tee_new_tmp(dst_opts.data_model.unwrap_memory().ptr());
2131 self.ptr_uconst(dst_mem_opts, 1);
2132 self.ptr_shl(dst_mem_opts);
2133 let dst_byte_len = self.local_set_new_tmp(dst_opts.data_model.unwrap_memory().ptr());
2134 let dst = {
2135 let dst_mem = self.malloc(
2136 dst_opts,
2137 AllocSize::Local(dst_byte_len.idx),
2138 2,
2139 Trap::StringOutOfBounds,
2140 );
2141 WasmString {
2142 ptr: dst_mem.addr,
2143 len: dst_len,
2144 opts: dst_opts,
2145 }
2146 };
2147
2148 let transcode = self.transcoder(src, &dst, Transcode::Utf8ToUtf16);
2149 self.instruction(LocalGet(src.ptr.idx));
2150 self.instruction(LocalGet(src.len.idx));
2151 self.instruction(LocalGet(dst.ptr.idx));
2152 self.instruction(Call(transcode.as_u32()));
2153 self.instruction(LocalSet(dst.len.idx));
2154
2155 self.convert_src_len_to_dst(src.len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2163 self.instruction(LocalGet(dst.len.idx));
2164 self.ptr_ne(dst_mem_opts);
2165 self.instruction(If(BlockType::Empty));
2166 self.realloc(
2167 dst.opts,
2168 &dst.ptr,
2169 AllocSize::Local(dst_byte_len.idx),
2170 AllocSize::DoubleLocal(dst.len.idx),
2171 2,
2172 Trap::StringOutOfBounds,
2173 );
2174 self.instruction(End); self.free_temp_local(dst_byte_len);
2177
2178 dst
2179 }
2180
2181 fn string_compact_utf16_to_compact<'c>(
2195 &mut self,
2196 src: &WasmString<'_>,
2197 dst_opts: &'c Options,
2198 ) -> WasmString<'c> {
2199 let src_mem_opts = match &src.opts.data_model {
2200 DataModel::Gc {} => todo!("CM+GC"),
2201 DataModel::LinearMemory(opts) => opts,
2202 };
2203 let dst_mem_opts = match &dst_opts.data_model {
2204 DataModel::Gc {} => todo!("CM+GC"),
2205 DataModel::LinearMemory(opts) => opts,
2206 };
2207
2208 self.validate_string_length(src, FE::Utf16);
2209 self.convert_src_len_to_dst(src.len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2210 let dst_len = self.local_tee_new_tmp(dst_mem_opts.ptr());
2211 self.ptr_uconst(dst_mem_opts, 1);
2212 self.ptr_shl(dst_mem_opts);
2213 let dst_byte_len = self.local_set_new_tmp(dst_mem_opts.ptr());
2214 let dst = {
2215 let dst_mem = self.malloc(
2216 dst_opts,
2217 AllocSize::Local(dst_byte_len.idx),
2218 2,
2219 Trap::StringOutOfBounds,
2220 );
2221 WasmString {
2222 ptr: dst_mem.addr,
2223 len: dst_len,
2224 opts: dst_opts,
2225 }
2226 };
2227
2228 self.convert_src_len_to_dst(
2229 dst_byte_len.idx,
2230 dst.opts.data_model.unwrap_memory().ptr(),
2231 src_mem_opts.ptr(),
2232 );
2233 let src_byte_len = self.local_set_new_tmp(src_mem_opts.ptr());
2234
2235 let transcode = self.transcoder(src, &dst, Transcode::Utf16ToCompactProbablyUtf16);
2236 self.instruction(LocalGet(src.ptr.idx));
2237 self.instruction(LocalGet(src.len.idx));
2238 self.instruction(LocalGet(dst.ptr.idx));
2239 self.instruction(Call(transcode.as_u32()));
2240 self.instruction(LocalSet(dst.len.idx));
2241
2242 if self.module.tunables.debug_adapter_modules {
2245 self.instruction(LocalGet(dst.len.idx));
2246 self.ptr_uconst(dst_mem_opts, !UTF16_TAG);
2247 self.ptr_and(dst_mem_opts);
2248 self.convert_src_len_to_dst(src.len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2249 self.ptr_ne(dst_mem_opts);
2250 self.instruction(If(BlockType::Empty));
2251 self.trap(Trap::DebugAssertEqualCodeUnits);
2252 self.instruction(End);
2253 }
2254
2255 self.instruction(LocalGet(dst.len.idx));
2259 self.ptr_uconst(dst_mem_opts, UTF16_TAG);
2260 self.ptr_and(dst_mem_opts);
2261 self.ptr_br_if(dst_mem_opts, 0);
2262
2263 self.realloc(
2265 dst.opts,
2266 &dst.ptr,
2267 AllocSize::Local(dst_byte_len.idx),
2268 AllocSize::Local(dst.len.idx),
2269 2,
2270 Trap::StringOutOfBounds,
2271 );
2272
2273 self.free_temp_local(dst_byte_len);
2274 self.free_temp_local(src_byte_len);
2275
2276 dst
2277 }
2278
2279 fn string_to_compact<'c>(
2286 &mut self,
2287 src: &WasmString<'_>,
2288 src_enc: FE,
2289 dst_opts: &'c Options,
2290 ) -> WasmString<'c> {
2291 let src_mem_opts = match &src.opts.data_model {
2292 DataModel::Gc {} => todo!("CM+GC"),
2293 DataModel::LinearMemory(opts) => opts,
2294 };
2295 let dst_mem_opts = match &dst_opts.data_model {
2296 DataModel::Gc {} => todo!("CM+GC"),
2297 DataModel::LinearMemory(opts) => opts,
2298 };
2299
2300 self.validate_string_length(src, src_enc);
2301
2302 self.convert_src_len_to_dst(src.len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2303 let dst_len = self.local_tee_new_tmp(dst_mem_opts.ptr());
2304 let dst_byte_len = self.local_set_new_tmp(dst_mem_opts.ptr());
2305 let dst = {
2306 let dst_mem = self.malloc(
2307 dst_opts,
2308 AllocSize::Local(dst_byte_len.idx),
2309 2,
2310 Trap::StringOutOfBounds,
2311 );
2312 WasmString {
2313 ptr: dst_mem.addr,
2314 len: dst_len,
2315 opts: dst_opts,
2316 }
2317 };
2318
2319 let (latin1, utf16) = match src_enc {
2323 FE::Utf8 => (Transcode::Utf8ToLatin1, Transcode::Utf8ToCompactUtf16),
2324 FE::Utf16 => (Transcode::Utf16ToLatin1, Transcode::Utf16ToCompactUtf16),
2325 FE::Latin1 => unreachable!(),
2326 };
2327 let transcode_latin1 = self.transcoder(src, &dst, latin1);
2328 let transcode_utf16 = self.transcoder(src, &dst, utf16);
2329 self.instruction(LocalGet(src.ptr.idx));
2330 self.instruction(LocalGet(src.len.idx));
2331 self.instruction(LocalGet(dst.ptr.idx));
2332 self.instruction(Call(transcode_latin1.as_u32()));
2333 self.instruction(LocalSet(dst.len.idx));
2334 let src_len_tmp = self.local_set_new_tmp(src_mem_opts.ptr());
2335
2336 self.instruction(LocalGet(src_len_tmp.idx));
2339 self.instruction(LocalGet(src.len.idx));
2340 self.ptr_eq(src_mem_opts);
2341 self.instruction(If(BlockType::Empty)); self.instruction(LocalGet(dst_byte_len.idx));
2347 self.instruction(LocalGet(dst.len.idx));
2348 self.ptr_ne(dst_mem_opts);
2349 self.instruction(If(BlockType::Empty));
2350 self.realloc(
2351 dst.opts,
2352 &dst.ptr,
2353 AllocSize::Local(dst_byte_len.idx),
2354 AllocSize::Local(dst.len.idx),
2355 2,
2356 Trap::StringOutOfBounds,
2357 );
2358 self.instruction(End);
2359
2360 self.instruction(Else); if src_enc.width() == 1 {
2369 self.validate_string_length_u8(src, 2);
2370 }
2371
2372 self.convert_src_len_to_dst(src.len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2375 self.ptr_uconst(dst_mem_opts, 1);
2376 self.ptr_shl(dst_mem_opts);
2377 let new_byte_len = self.local_set_new_tmp(dst_mem_opts.ptr());
2378 self.realloc(
2379 dst.opts,
2380 &dst.ptr,
2381 AllocSize::Local(dst_byte_len.idx),
2382 AllocSize::Local(new_byte_len.idx),
2383 2,
2384 Trap::StringOutOfBounds,
2385 );
2386 self.instruction(LocalGet(new_byte_len.idx));
2387 self.instruction(LocalSet(dst_byte_len.idx));
2388 self.free_temp_local(new_byte_len);
2389
2390 self.instruction(LocalGet(src.ptr.idx));
2394 self.instruction(LocalGet(src_len_tmp.idx));
2395 if let FE::Utf16 = src_enc {
2396 self.ptr_uconst(src_mem_opts, 1);
2397 self.ptr_shl(src_mem_opts);
2398 }
2399 self.ptr_add(src_mem_opts);
2400 self.instruction(LocalGet(src.len.idx));
2401 self.instruction(LocalGet(src_len_tmp.idx));
2402 self.ptr_sub(src_mem_opts);
2403 self.instruction(LocalGet(dst.ptr.idx));
2404 self.convert_src_len_to_dst(src.len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2405 self.instruction(LocalGet(dst.len.idx));
2406 self.instruction(Call(transcode_utf16.as_u32()));
2407 self.instruction(LocalSet(dst.len.idx));
2408
2409 self.instruction(LocalGet(dst.len.idx));
2417 self.convert_src_len_to_dst(src.len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2418 self.ptr_ne(dst_mem_opts);
2419 self.instruction(If(BlockType::Empty));
2420 self.realloc(
2421 dst.opts,
2422 &dst.ptr,
2423 AllocSize::Local(dst_byte_len.idx),
2424 AllocSize::DoubleLocal(dst.len.idx),
2425 2,
2426 Trap::StringOutOfBounds,
2427 );
2428 self.instruction(End);
2429
2430 self.instruction(LocalGet(dst.len.idx));
2432 self.ptr_uconst(dst_mem_opts, UTF16_TAG);
2433 self.ptr_or(dst_mem_opts);
2434 self.instruction(LocalSet(dst.len.idx));
2435
2436 self.instruction(End); self.free_temp_local(src_len_tmp);
2439 self.free_temp_local(dst_byte_len);
2440
2441 dst
2442 }
2443
2444 fn validate_string_length(&mut self, src: &WasmString<'_>, dst: FE) {
2445 self.validate_string_length_u8(src, dst.width())
2446 }
2447
2448 fn validate_string_length_u8(&mut self, s: &WasmString<'_>, dst: u8) {
2449 let mem_opts = match &s.opts.data_model {
2450 DataModel::Gc {} => todo!("CM+GC"),
2451 DataModel::LinearMemory(opts) => opts,
2452 };
2453
2454 self.instruction(LocalGet(s.len.idx));
2457 let max = MAX_STRING_BYTE_LENGTH / u32::from(dst);
2458 self.ptr_uconst(mem_opts, max);
2459 self.ptr_gt_u(mem_opts);
2460 self.instruction(If(BlockType::Empty));
2461 self.trap(Trap::StringOutOfBounds);
2462 self.instruction(End);
2463 }
2464
2465 fn transcoder(
2466 &mut self,
2467 src: &WasmString<'_>,
2468 dst: &WasmString<'_>,
2469 op: Transcode,
2470 ) -> FuncIndex {
2471 match (src.opts.data_model, dst.opts.data_model) {
2472 (DataModel::Gc {}, _) | (_, DataModel::Gc {}) => {
2473 todo!("CM+GC")
2474 }
2475 (
2476 DataModel::LinearMemory(LinearMemoryOptions {
2477 memory: Some((src_mem, src_ty)),
2478 realloc: _,
2479 }),
2480 DataModel::LinearMemory(LinearMemoryOptions {
2481 memory: Some((dst_mem, dst_ty)),
2482 realloc: _,
2483 }),
2484 ) => self.module.import_transcoder(Transcoder {
2485 from_memory: src_mem,
2486 from_memory64: src_ty.idx_type == IndexType::I64,
2487 to_memory: dst_mem,
2488 to_memory64: dst_ty.idx_type == IndexType::I64,
2489 op,
2490 }),
2491 (DataModel::LinearMemory(LinearMemoryOptions { memory: None, .. }), _)
2492 | (_, DataModel::LinearMemory(LinearMemoryOptions { memory: None, .. })) => {
2493 unreachable!()
2494 }
2495 }
2496 }
2497
2498 fn begin_translate_sequence<'c>(
2507 &mut self,
2508 src: &Source<'c>,
2509 dst: &Destination<'c>,
2510 src_element_size: u32,
2511 src_element_align: u32,
2512 dst_element_size: u32,
2513 dst_element_align: u32,
2514 ) -> SequenceTranslation<'c> {
2515 let src_mem_opts = match &src.opts().data_model {
2516 DataModel::Gc {} => todo!("CM+GC"),
2517 DataModel::LinearMemory(opts) => opts,
2518 };
2519 let dst_mem_opts = match &dst.opts().data_model {
2520 DataModel::Gc {} => todo!("CM+GC"),
2521 DataModel::LinearMemory(opts) => opts,
2522 };
2523
2524 let src_opts = src.opts();
2525 let dst_opts = dst.opts();
2526
2527 match src {
2532 Source::Stack(s) => {
2533 assert_eq!(s.locals.len(), 2);
2534 self.stack_get(&s.slice(0..1), src_mem_opts.ptr());
2535 self.stack_get(&s.slice(1..2), src_mem_opts.ptr());
2536 }
2537 Source::Memory(mem) => {
2538 self.ptr_load(mem);
2539 self.ptr_load(&mem.bump(src_mem_opts.ptr_size().into()));
2540 }
2541 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
2542 }
2543 let src_len = self.local_set_new_tmp(src_mem_opts.ptr());
2544 let src_ptr = self.local_set_new_tmp(src_mem_opts.ptr());
2545
2546 let src_byte_len =
2548 self.calculate_list_byte_len(src_mem_opts, src_len.idx, src_element_size);
2549 let dst_byte_len = if src_element_size == dst_element_size {
2550 self.convert_src_len_to_dst(src_byte_len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2551 self.local_set_new_tmp(dst_mem_opts.ptr())
2552 } else if src_mem_opts.ptr() == dst_mem_opts.ptr() {
2553 self.calculate_list_byte_len(dst_mem_opts, src_len.idx, dst_element_size)
2554 } else {
2555 self.convert_src_len_to_dst(src_len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2556 let tmp = self.local_set_new_tmp(dst_mem_opts.ptr());
2557 let ret = self.calculate_list_byte_len(dst_mem_opts, tmp.idx, dst_element_size);
2558 self.free_temp_local(tmp);
2559 ret
2560 };
2561
2562 let src_mem = self.memory_operand(
2565 src_opts,
2566 src_ptr,
2567 AllocSize::Local(src_byte_len.idx),
2568 src_element_align,
2569 Trap::ListOutOfBounds,
2570 );
2571
2572 let dst_mem = self.malloc(
2577 dst_opts,
2578 AllocSize::Local(dst_byte_len.idx),
2579 dst_element_align,
2580 Trap::ListOutOfBounds,
2581 );
2582
2583 self.free_temp_local(src_byte_len);
2584 self.free_temp_local(dst_byte_len);
2585
2586 let loop_state = if src_element_size > 0 || dst_element_size > 0 {
2590 self.instruction(Block(BlockType::Empty));
2591
2592 self.instruction(LocalGet(src_len.idx));
2594 let remaining = self.local_tee_new_tmp(src_mem_opts.ptr());
2595 self.ptr_eqz(src_mem_opts);
2596 self.instruction(BrIf(0));
2597
2598 self.instruction(LocalGet(src_mem.addr.idx));
2600 let cur_src_ptr = self.local_set_new_tmp(src_mem_opts.ptr());
2601 self.instruction(LocalGet(dst_mem.addr.idx));
2602 let cur_dst_ptr = self.local_set_new_tmp(dst_mem_opts.ptr());
2603
2604 self.instruction(Loop(BlockType::Empty));
2605
2606 Some(SequenceLoopState {
2607 remaining,
2608 cur_src_ptr,
2609 cur_dst_ptr,
2610 })
2611 } else {
2612 None
2613 };
2614
2615 SequenceTranslation {
2616 src_len,
2617 src_mem,
2618 dst_mem,
2619 src_opts,
2620 dst_opts,
2621 src_mem_opts,
2622 dst_mem_opts,
2623 loop_state,
2624 }
2625 }
2626
2627 fn end_translate_sequence(&mut self, seq: SequenceTranslation<'_>, dst: &Destination) {
2633 if let Some(loop_state) = seq.loop_state {
2634 self.instruction(LocalGet(loop_state.remaining.idx));
2637 self.ptr_iconst(seq.src_mem_opts, -1);
2638 self.ptr_add(seq.src_mem_opts);
2639 self.instruction(LocalTee(loop_state.remaining.idx));
2640 self.ptr_br_if(seq.src_mem_opts, 0);
2641 self.instruction(End); self.instruction(End); self.free_temp_local(loop_state.cur_dst_ptr);
2645 self.free_temp_local(loop_state.cur_src_ptr);
2646 self.free_temp_local(loop_state.remaining);
2647 }
2648
2649 match dst {
2651 Destination::Stack(s, _) => {
2652 self.instruction(LocalGet(seq.dst_mem.addr.idx));
2653 self.stack_set(&s[..1], seq.dst_mem_opts.ptr());
2654 self.convert_src_len_to_dst(
2655 seq.src_len.idx,
2656 seq.src_mem_opts.ptr(),
2657 seq.dst_mem_opts.ptr(),
2658 );
2659 self.stack_set(&s[1..], seq.dst_mem_opts.ptr());
2660 }
2661 Destination::Memory(mem) => {
2662 self.instruction(LocalGet(mem.addr.idx));
2663 self.instruction(LocalGet(seq.dst_mem.addr.idx));
2664 self.ptr_store(mem);
2665 self.instruction(LocalGet(mem.addr.idx));
2666 self.convert_src_len_to_dst(
2667 seq.src_len.idx,
2668 seq.src_mem_opts.ptr(),
2669 seq.dst_mem_opts.ptr(),
2670 );
2671 self.ptr_store(&mem.bump(seq.dst_mem_opts.ptr_size().into()));
2672 }
2673 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
2674 }
2675
2676 self.free_temp_local(seq.src_len);
2677 self.free_temp_local(seq.src_mem.addr);
2678 self.free_temp_local(seq.dst_mem.addr);
2679 }
2680
2681 fn translate_list(
2682 &mut self,
2683 src_ty: TypeListIndex,
2684 src: &Source<'_>,
2685 dst_ty: &InterfaceType,
2686 dst: &Destination,
2687 ) {
2688 let src_mem_opts = match &src.opts().data_model {
2689 DataModel::Gc {} => todo!("CM+GC"),
2690 DataModel::LinearMemory(opts) => opts,
2691 };
2692 let dst_mem_opts = match &dst.opts().data_model {
2693 DataModel::Gc {} => todo!("CM+GC"),
2694 DataModel::LinearMemory(opts) => opts,
2695 };
2696
2697 let src_element_ty = &self.types[src_ty].element;
2698 let dst_element_ty = match dst_ty {
2699 InterfaceType::List(r) => &self.types[*r].element,
2700 _ => panic!("expected a list"),
2701 };
2702 let (src_size, src_align) = self.types.size_align(src_mem_opts, src_element_ty);
2703 let (dst_size, dst_align) = self.types.size_align(dst_mem_opts, dst_element_ty);
2704
2705 let seq = self.begin_translate_sequence(src, dst, src_size, src_align, dst_size, dst_align);
2706
2707 if let Some(ref loop_state) = seq.loop_state {
2708 let element_src = Source::Memory(Memory {
2709 opts: seq.src_opts,
2710 offset: 0,
2711 addr: TempLocal::new(loop_state.cur_src_ptr.idx, loop_state.cur_src_ptr.ty),
2712 });
2713 let element_dst = Destination::Memory(Memory {
2714 opts: seq.dst_opts,
2715 offset: 0,
2716 addr: TempLocal::new(loop_state.cur_dst_ptr.idx, loop_state.cur_dst_ptr.ty),
2717 });
2718 self.translate(src_element_ty, &element_src, dst_element_ty, &element_dst);
2719
2720 if src_size > 0 {
2721 self.instruction(LocalGet(loop_state.cur_src_ptr.idx));
2722 self.ptr_uconst(src_mem_opts, src_size);
2723 self.ptr_add(src_mem_opts);
2724 self.instruction(LocalSet(loop_state.cur_src_ptr.idx));
2725 }
2726 if dst_size > 0 {
2727 self.instruction(LocalGet(loop_state.cur_dst_ptr.idx));
2728 self.ptr_uconst(dst_mem_opts, dst_size);
2729 self.ptr_add(dst_mem_opts);
2730 self.instruction(LocalSet(loop_state.cur_dst_ptr.idx));
2731 }
2732 }
2733
2734 self.end_translate_sequence(seq, dst);
2735 }
2736
2737 fn translate_map(
2743 &mut self,
2744 src_ty: TypeMapIndex,
2745 src: &Source<'_>,
2746 dst_ty: &InterfaceType,
2747 dst: &Destination,
2748 ) {
2749 let src_mem_opts = match &src.opts().data_model {
2750 DataModel::Gc {} => todo!("CM+GC"),
2751 DataModel::LinearMemory(opts) => opts,
2752 };
2753 let dst_mem_opts = match &dst.opts().data_model {
2754 DataModel::Gc {} => todo!("CM+GC"),
2755 DataModel::LinearMemory(opts) => opts,
2756 };
2757
2758 let src_map_ty = &self.types[src_ty];
2759 let dst_map_ty = match dst_ty {
2760 InterfaceType::Map(r) => &self.types[*r],
2761 _ => panic!("expected a map"),
2762 };
2763
2764 let src_key_abi = self.types.canonical_abi(&src_map_ty.key);
2766 let src_value_abi = self.types.canonical_abi(&src_map_ty.value);
2767 let src_entry_abi = CanonicalAbiInfo::record([src_key_abi, src_value_abi].into_iter());
2768 let (src_tuple_size, src_entry_align) = src_mem_opts.sizealign(&src_entry_abi);
2769 let src_value_offset = {
2770 let mut offset = 0u32;
2771 if src_mem_opts.memory64() {
2772 src_key_abi.next_field64(&mut offset);
2773 src_value_abi.next_field64(&mut offset)
2774 } else {
2775 src_key_abi.next_field32(&mut offset);
2776 src_value_abi.next_field32(&mut offset)
2777 }
2778 };
2779
2780 let dst_key_abi = self.types.canonical_abi(&dst_map_ty.key);
2781 let dst_value_abi = self.types.canonical_abi(&dst_map_ty.value);
2782 let dst_entry_abi = CanonicalAbiInfo::record([dst_key_abi, dst_value_abi].into_iter());
2783 let (dst_tuple_size, dst_entry_align) = dst_mem_opts.sizealign(&dst_entry_abi);
2784 let dst_value_offset = {
2785 let mut offset = 0u32;
2786 if dst_mem_opts.memory64() {
2787 dst_key_abi.next_field64(&mut offset);
2788 dst_value_abi.next_field64(&mut offset)
2789 } else {
2790 dst_key_abi.next_field32(&mut offset);
2791 dst_value_abi.next_field32(&mut offset)
2792 }
2793 };
2794
2795 let seq = self.begin_translate_sequence(
2796 src,
2797 dst,
2798 src_tuple_size,
2799 src_entry_align,
2800 dst_tuple_size,
2801 dst_entry_align,
2802 );
2803
2804 if let Some(ref loop_state) = seq.loop_state {
2805 let key_src = Source::Memory(Memory {
2806 opts: seq.src_opts,
2807 offset: 0,
2808 addr: TempLocal::new(loop_state.cur_src_ptr.idx, src_mem_opts.ptr()),
2809 });
2810 let key_dst = Destination::Memory(Memory {
2811 opts: seq.dst_opts,
2812 offset: 0,
2813 addr: TempLocal::new(loop_state.cur_dst_ptr.idx, dst_mem_opts.ptr()),
2814 });
2815 self.translate(&src_map_ty.key, &key_src, &dst_map_ty.key, &key_dst);
2816
2817 let value_src = Source::Memory(Memory {
2818 opts: seq.src_opts,
2819 offset: src_value_offset,
2820 addr: TempLocal::new(loop_state.cur_src_ptr.idx, src_mem_opts.ptr()),
2821 });
2822 let value_dst = Destination::Memory(Memory {
2823 opts: seq.dst_opts,
2824 offset: dst_value_offset,
2825 addr: TempLocal::new(loop_state.cur_dst_ptr.idx, dst_mem_opts.ptr()),
2826 });
2827 self.translate(&src_map_ty.value, &value_src, &dst_map_ty.value, &value_dst);
2828
2829 if src_tuple_size > 0 {
2831 self.instruction(LocalGet(loop_state.cur_src_ptr.idx));
2832 self.ptr_uconst(src_mem_opts, src_tuple_size);
2833 self.ptr_add(src_mem_opts);
2834 self.instruction(LocalSet(loop_state.cur_src_ptr.idx));
2835 }
2836 if dst_tuple_size > 0 {
2837 self.instruction(LocalGet(loop_state.cur_dst_ptr.idx));
2838 self.ptr_uconst(dst_mem_opts, dst_tuple_size);
2839 self.ptr_add(dst_mem_opts);
2840 self.instruction(LocalSet(loop_state.cur_dst_ptr.idx));
2841 }
2842 }
2843
2844 self.end_translate_sequence(seq, dst);
2845 }
2846
2847 fn calculate_list_byte_len(
2848 &mut self,
2849 opts: &LinearMemoryOptions,
2850 len_local: u32,
2851 elt_size: u32,
2852 ) -> TempLocal {
2853 if elt_size == 0 {
2856 self.ptr_uconst(opts, 0);
2857 return self.local_set_new_tmp(opts.ptr());
2858 }
2859
2860 if elt_size == 1 {
2868 if let ValType::I64 = opts.ptr() {
2869 self.instruction(LocalGet(len_local));
2870 self.instruction(I64Const(32));
2871 self.instruction(I64ShrU);
2872 self.instruction(I32WrapI64);
2873 self.instruction(If(BlockType::Empty));
2874 self.trap(Trap::ListOutOfBounds);
2875 self.instruction(End);
2876 }
2877 self.instruction(LocalGet(len_local));
2878 return self.local_set_new_tmp(opts.ptr());
2879 }
2880
2881 self.instruction(Block(BlockType::Empty));
2886 self.instruction(Block(BlockType::Empty));
2887 self.instruction(LocalGet(len_local));
2888 match opts.ptr() {
2889 ValType::I32 => self.instruction(I64ExtendI32U),
2893
2894 ValType::I64 => {
2898 self.instruction(I64Const(32));
2899 self.instruction(I64ShrU);
2900 self.instruction(I32WrapI64);
2901 self.instruction(BrIf(0));
2902 self.instruction(LocalGet(len_local));
2903 }
2904
2905 _ => unreachable!(),
2906 }
2907
2908 self.instruction(I64Const(elt_size.into()));
2917 self.instruction(I64Mul);
2918 let tmp = self.local_tee_new_tmp(ValType::I64);
2919 self.instruction(I64Const(32));
2922 self.instruction(I64ShrU);
2923 self.instruction(I64Eqz);
2924 self.instruction(BrIf(1));
2925 self.instruction(End);
2926 self.trap(Trap::ListOutOfBounds);
2927 self.instruction(End);
2928
2929 if opts.ptr() == ValType::I64 {
2933 tmp
2934 } else {
2935 self.instruction(LocalGet(tmp.idx));
2936 self.instruction(I32WrapI64);
2937 self.free_temp_local(tmp);
2938 self.local_set_new_tmp(ValType::I32)
2939 }
2940 }
2941
2942 fn convert_src_len_to_dst(
2943 &mut self,
2944 src_len_local: u32,
2945 src_ptr_ty: ValType,
2946 dst_ptr_ty: ValType,
2947 ) {
2948 self.instruction(LocalGet(src_len_local));
2949 match (src_ptr_ty, dst_ptr_ty) {
2950 (ValType::I32, ValType::I64) => self.instruction(I64ExtendI32U),
2951 (ValType::I64, ValType::I32) => self.instruction(I32WrapI64),
2952 (src, dst) => assert_eq!(src, dst),
2953 }
2954 }
2955
2956 fn translate_record(
2957 &mut self,
2958 src_ty: TypeRecordIndex,
2959 src: &Source<'_>,
2960 dst_ty: &InterfaceType,
2961 dst: &Destination,
2962 ) {
2963 let src_ty = &self.types[src_ty];
2964 let dst_ty = match dst_ty {
2965 InterfaceType::Record(r) => &self.types[*r],
2966 _ => panic!("expected a record"),
2967 };
2968
2969 assert_eq!(src_ty.fields.len(), dst_ty.fields.len());
2971
2972 let mut src_fields = HashMap::new();
2976 for (i, src) in src
2977 .record_field_srcs(self.types, src_ty.fields.iter().map(|f| f.ty))
2978 .enumerate()
2979 {
2980 let field = &src_ty.fields[i];
2981 src_fields.insert(&field.name, (src, &field.ty));
2982 }
2983
2984 for (i, dst) in dst
2993 .record_field_dsts(self.types, dst_ty.fields.iter().map(|f| f.ty))
2994 .enumerate()
2995 {
2996 let field = &dst_ty.fields[i];
2997 let (src, src_ty) = &src_fields[&field.name];
2998 self.translate(src_ty, src, &field.ty, &dst);
2999 }
3000 }
3001
3002 fn translate_flags(
3003 &mut self,
3004 src_ty: TypeFlagsIndex,
3005 src: &Source<'_>,
3006 dst_ty: &InterfaceType,
3007 dst: &Destination,
3008 ) {
3009 let src_ty = &self.types[src_ty];
3010 let dst_ty = match dst_ty {
3011 InterfaceType::Flags(r) => &self.types[*r],
3012 _ => panic!("expected a record"),
3013 };
3014
3015 assert_eq!(src_ty.names, dst_ty.names);
3023 let cnt = src_ty.names.len();
3024 match FlagsSize::from_count(cnt) {
3025 FlagsSize::Size0 => {}
3026 FlagsSize::Size1 => {
3027 let mask = if cnt == 8 { 0xff } else { (1 << cnt) - 1 };
3028 self.convert_u8_mask(src, dst, mask);
3029 }
3030 FlagsSize::Size2 => {
3031 let mask = if cnt == 16 { 0xffff } else { (1 << cnt) - 1 };
3032 self.convert_u16_mask(src, dst, mask);
3033 }
3034 FlagsSize::Size4Plus(n) => {
3035 let srcs = src.record_field_srcs(self.types, (0..n).map(|_| InterfaceType::U32));
3036 let dsts = dst.record_field_dsts(self.types, (0..n).map(|_| InterfaceType::U32));
3037 let n = usize::from(n);
3038 for (i, (src, dst)) in srcs.zip(dsts).enumerate() {
3039 let mask = if i == n - 1 && (cnt % 32 != 0) {
3040 (1 << (cnt % 32)) - 1
3041 } else {
3042 0xffffffff
3043 };
3044 self.convert_u32_mask(&src, &dst, mask);
3045 }
3046 }
3047 }
3048 }
3049
3050 fn translate_tuple(
3051 &mut self,
3052 src_ty: TypeTupleIndex,
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::Tuple(t) => &self.types[*t],
3060 _ => panic!("expected a tuple"),
3061 };
3062
3063 assert_eq!(src_ty.types.len(), dst_ty.types.len());
3065
3066 let srcs = src
3067 .record_field_srcs(self.types, src_ty.types.iter().copied())
3068 .zip(src_ty.types.iter());
3069 let dsts = dst
3070 .record_field_dsts(self.types, dst_ty.types.iter().copied())
3071 .zip(dst_ty.types.iter());
3072 for ((src, src_ty), (dst, dst_ty)) in srcs.zip(dsts) {
3073 self.translate(src_ty, &src, dst_ty, &dst);
3074 }
3075 }
3076
3077 fn translate_fixed_length_list(
3078 &mut self,
3079 src_ty: TypeFixedLengthListIndex,
3080 src: &Source<'_>,
3081 dst_ty: &InterfaceType,
3082 dst: &Destination,
3083 ) {
3084 let src_ty = &self.types[src_ty];
3085 let dst_ty = match dst_ty {
3086 InterfaceType::FixedLengthList(t) => &self.types[*t],
3087 _ => panic!("expected a fixed size list"),
3088 };
3089
3090 assert_eq!(src_ty.size, dst_ty.size);
3092
3093 match (&src, &dst) {
3094 (Source::Memory(src_mem), Destination::Memory(dst_mem)) => {
3096 let src_mem_opts = match &src_mem.opts.data_model {
3097 DataModel::Gc {} => todo!("CM+GC"),
3098 DataModel::LinearMemory(opts) => opts,
3099 };
3100 let dst_mem_opts = match &dst_mem.opts.data_model {
3101 DataModel::Gc {} => todo!("CM+GC"),
3102 DataModel::LinearMemory(opts) => opts,
3103 };
3104 let src_element_bytes = self.types.size_align(src_mem_opts, &src_ty.element).0;
3105 let dst_element_bytes = self.types.size_align(dst_mem_opts, &dst_ty.element).0;
3106 assert_ne!(src_element_bytes, 0);
3107 assert_ne!(dst_element_bytes, 0);
3108
3109 self.instruction(LocalGet(src_mem.addr.idx));
3112 if src_mem.offset != 0 {
3113 self.ptr_uconst(src_mem_opts, src_mem.offset);
3114 self.ptr_add(src_mem_opts);
3115 }
3116 let cur_src_ptr = self.local_set_new_tmp(src_mem_opts.ptr());
3117 self.instruction(LocalGet(dst_mem.addr.idx));
3118 if dst_mem.offset != 0 {
3119 self.ptr_uconst(dst_mem_opts, dst_mem.offset);
3120 self.ptr_add(dst_mem_opts);
3121 }
3122 let cur_dst_ptr = self.local_set_new_tmp(dst_mem_opts.ptr());
3123
3124 self.instruction(I32Const(src_ty.size as i32));
3125 let remaining = self.local_set_new_tmp(ValType::I32);
3126
3127 self.instruction(Loop(BlockType::Empty));
3128
3129 let element_src = Source::Memory(Memory {
3131 opts: src_mem.opts,
3132 offset: 0,
3133 addr: TempLocal::new(cur_src_ptr.idx, cur_src_ptr.ty),
3134 });
3135 let element_dst = Destination::Memory(Memory {
3136 opts: dst_mem.opts,
3137 offset: 0,
3138 addr: TempLocal::new(cur_dst_ptr.idx, cur_dst_ptr.ty),
3139 });
3140 self.translate(&src_ty.element, &element_src, &dst_ty.element, &element_dst);
3141
3142 self.instruction(LocalGet(cur_src_ptr.idx));
3144 self.ptr_uconst(src_mem_opts, src_element_bytes);
3145 self.ptr_add(src_mem_opts);
3146 self.instruction(LocalSet(cur_src_ptr.idx));
3147 self.instruction(LocalGet(cur_dst_ptr.idx));
3148 self.ptr_uconst(dst_mem_opts, dst_element_bytes);
3149 self.ptr_add(dst_mem_opts);
3150 self.instruction(LocalSet(cur_dst_ptr.idx));
3151
3152 self.instruction(LocalGet(remaining.idx));
3155 self.ptr_iconst(src_mem_opts, -1);
3156 self.ptr_add(src_mem_opts);
3157 self.instruction(LocalTee(remaining.idx));
3158 self.ptr_br_if(src_mem_opts, 0);
3159 self.instruction(End); self.free_temp_local(cur_dst_ptr);
3162 self.free_temp_local(cur_src_ptr);
3163 self.free_temp_local(remaining);
3164 return;
3165 }
3166 (_, _) => {
3168 assert!(
3170 src_ty.size as usize <= MAX_FLAT_PARAMS
3171 && dst_ty.size as usize <= MAX_FLAT_PARAMS
3172 );
3173 let srcs =
3174 src.record_field_srcs(self.types, (0..src_ty.size).map(|_| src_ty.element));
3175 let dsts =
3176 dst.record_field_dsts(self.types, (0..dst_ty.size).map(|_| dst_ty.element));
3177 for (src, dst) in srcs.zip(dsts) {
3178 self.translate(&src_ty.element, &src, &dst_ty.element, &dst);
3179 }
3180 }
3181 }
3182 }
3183
3184 fn translate_variant(
3185 &mut self,
3186 src_ty: TypeVariantIndex,
3187 src: &Source<'_>,
3188 dst_ty: &InterfaceType,
3189 dst: &Destination,
3190 ) {
3191 let src_ty = &self.types[src_ty];
3192 let dst_ty = match dst_ty {
3193 InterfaceType::Variant(t) => &self.types[*t],
3194 _ => panic!("expected a variant"),
3195 };
3196
3197 let src_info = variant_info(self.types, src_ty.cases.iter().map(|(_, c)| c.as_ref()));
3198 let dst_info = variant_info(self.types, dst_ty.cases.iter().map(|(_, c)| c.as_ref()));
3199
3200 let iter = src_ty
3201 .cases
3202 .iter()
3203 .enumerate()
3204 .map(|(src_i, (src_case, src_case_ty))| {
3205 let dst_i = dst_ty
3206 .cases
3207 .iter()
3208 .position(|(c, _)| c == src_case)
3209 .unwrap();
3210 let dst_case_ty = &dst_ty.cases[dst_i];
3211 let src_i = u32::try_from(src_i).unwrap();
3212 let dst_i = u32::try_from(dst_i).unwrap();
3213 VariantCase {
3214 src_i,
3215 src_ty: src_case_ty.as_ref(),
3216 dst_i,
3217 dst_ty: dst_case_ty.as_ref(),
3218 }
3219 });
3220 self.convert_variant(src, &src_info, dst, &dst_info, iter);
3221 }
3222
3223 fn translate_enum(
3224 &mut self,
3225 src_ty: TypeEnumIndex,
3226 src: &Source<'_>,
3227 dst_ty: &InterfaceType,
3228 dst: &Destination,
3229 ) {
3230 let src_ty = &self.types[src_ty];
3231 let dst_ty = match dst_ty {
3232 InterfaceType::Enum(t) => &self.types[*t],
3233 _ => panic!("expected an option"),
3234 };
3235
3236 debug_assert_eq!(src_ty.info.size, dst_ty.info.size);
3237 debug_assert_eq!(src_ty.names.len(), dst_ty.names.len());
3238 debug_assert!(
3239 src_ty
3240 .names
3241 .iter()
3242 .zip(dst_ty.names.iter())
3243 .all(|(a, b)| a == b)
3244 );
3245
3246 match src {
3248 Source::Stack(s) => self.stack_get(&s.slice(0..1), ValType::I32),
3249 Source::Memory(mem) => match src_ty.info.size {
3250 DiscriminantSize::Size1 => self.i32_load8u(mem),
3251 DiscriminantSize::Size2 => self.i32_load16u(mem),
3252 DiscriminantSize::Size4 => self.i32_load(mem),
3253 },
3254 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
3255 }
3256 let tmp = self.local_tee_new_tmp(ValType::I32);
3257
3258 self.instruction(I32Const(i32::try_from(src_ty.names.len()).unwrap()));
3260 self.instruction(I32GeU);
3261 self.instruction(If(BlockType::Empty));
3262 self.trap(Trap::InvalidDiscriminant);
3263 self.instruction(End);
3264
3265 match dst {
3267 Destination::Stack(stack, _) => {
3268 self.local_get_tmp(&tmp);
3269 self.stack_set(&stack[..1], ValType::I32)
3270 }
3271 Destination::Memory(mem) => {
3272 self.push_dst_addr(dst);
3273 self.local_get_tmp(&tmp);
3274 match dst_ty.info.size {
3275 DiscriminantSize::Size1 => self.i32_store8(mem),
3276 DiscriminantSize::Size2 => self.i32_store16(mem),
3277 DiscriminantSize::Size4 => self.i32_store(mem),
3278 }
3279 }
3280 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
3281 }
3282 self.free_temp_local(tmp);
3283 }
3284
3285 fn translate_option(
3286 &mut self,
3287 src_ty: TypeOptionIndex,
3288 src: &Source<'_>,
3289 dst_ty: &InterfaceType,
3290 dst: &Destination,
3291 ) {
3292 let src_ty = &self.types[src_ty].ty;
3293 let dst_ty = match dst_ty {
3294 InterfaceType::Option(t) => &self.types[*t].ty,
3295 _ => panic!("expected an option"),
3296 };
3297 let src_ty = Some(src_ty);
3298 let dst_ty = Some(dst_ty);
3299
3300 let src_info = variant_info(self.types, [None, src_ty]);
3301 let dst_info = variant_info(self.types, [None, dst_ty]);
3302
3303 self.convert_variant(
3304 src,
3305 &src_info,
3306 dst,
3307 &dst_info,
3308 [
3309 VariantCase {
3310 src_i: 0,
3311 dst_i: 0,
3312 src_ty: None,
3313 dst_ty: None,
3314 },
3315 VariantCase {
3316 src_i: 1,
3317 dst_i: 1,
3318 src_ty,
3319 dst_ty,
3320 },
3321 ]
3322 .into_iter(),
3323 );
3324 }
3325
3326 fn translate_result(
3327 &mut self,
3328 src_ty: TypeResultIndex,
3329 src: &Source<'_>,
3330 dst_ty: &InterfaceType,
3331 dst: &Destination,
3332 ) {
3333 let src_ty = &self.types[src_ty];
3334 let dst_ty = match dst_ty {
3335 InterfaceType::Result(t) => &self.types[*t],
3336 _ => panic!("expected a result"),
3337 };
3338
3339 let src_info = variant_info(self.types, [src_ty.ok.as_ref(), src_ty.err.as_ref()]);
3340 let dst_info = variant_info(self.types, [dst_ty.ok.as_ref(), dst_ty.err.as_ref()]);
3341
3342 self.convert_variant(
3343 src,
3344 &src_info,
3345 dst,
3346 &dst_info,
3347 [
3348 VariantCase {
3349 src_i: 0,
3350 dst_i: 0,
3351 src_ty: src_ty.ok.as_ref(),
3352 dst_ty: dst_ty.ok.as_ref(),
3353 },
3354 VariantCase {
3355 src_i: 1,
3356 dst_i: 1,
3357 src_ty: src_ty.err.as_ref(),
3358 dst_ty: dst_ty.err.as_ref(),
3359 },
3360 ]
3361 .into_iter(),
3362 );
3363 }
3364
3365 fn convert_variant<'c>(
3366 &mut self,
3367 src: &Source<'_>,
3368 src_info: &VariantInfo,
3369 dst: &Destination,
3370 dst_info: &VariantInfo,
3371 src_cases: impl ExactSizeIterator<Item = VariantCase<'c>>,
3372 ) {
3373 let outer_block_ty = match dst {
3376 Destination::Stack(dst_flat, _) => match dst_flat.len() {
3377 0 => BlockType::Empty,
3378 1 => BlockType::Result(dst_flat[0]),
3379 _ => {
3380 let ty = self.module.core_types.function(&[], &dst_flat);
3381 BlockType::FunctionType(ty)
3382 }
3383 },
3384 Destination::Memory(_) => BlockType::Empty,
3385 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
3386 };
3387 self.instruction(Block(outer_block_ty));
3388
3389 let src_cases_len = src_cases.len();
3392 for _ in 0..src_cases_len - 1 {
3393 self.instruction(Block(BlockType::Empty));
3394 }
3395
3396 self.instruction(Block(BlockType::Empty));
3398
3399 self.instruction(Block(BlockType::Empty));
3402
3403 match src {
3405 Source::Stack(s) => self.stack_get(&s.slice(0..1), ValType::I32),
3406 Source::Memory(mem) => match src_info.size {
3407 DiscriminantSize::Size1 => self.i32_load8u(mem),
3408 DiscriminantSize::Size2 => self.i32_load16u(mem),
3409 DiscriminantSize::Size4 => self.i32_load(mem),
3410 },
3411 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
3412 }
3413
3414 let mut targets = Vec::new();
3417 for i in 0..src_cases_len {
3418 targets.push((i + 1) as u32);
3419 }
3420 self.instruction(BrTable(targets[..].into(), 0));
3421 self.instruction(End); self.trap(Trap::InvalidDiscriminant);
3424 self.instruction(End); let src_cases_len = u32::try_from(src_cases_len).unwrap();
3431 for case in src_cases {
3432 let VariantCase {
3433 src_i,
3434 src_ty,
3435 dst_i,
3436 dst_ty,
3437 } = case;
3438
3439 self.push_dst_addr(dst);
3442 self.instruction(I32Const(dst_i as i32));
3443 match dst {
3444 Destination::Stack(stack, _) => self.stack_set(&stack[..1], ValType::I32),
3445 Destination::Memory(mem) => match dst_info.size {
3446 DiscriminantSize::Size1 => self.i32_store8(mem),
3447 DiscriminantSize::Size2 => self.i32_store16(mem),
3448 DiscriminantSize::Size4 => self.i32_store(mem),
3449 },
3450 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
3451 }
3452
3453 let src_payload = src.payload_src(self.types, src_info, src_ty);
3454 let dst_payload = dst.payload_dst(self.types, dst_info, dst_ty);
3455
3456 match (src_ty, dst_ty) {
3459 (Some(src_ty), Some(dst_ty)) => {
3460 self.translate(src_ty, &src_payload, dst_ty, &dst_payload);
3461 }
3462 (None, None) => {}
3463 _ => unimplemented!(),
3464 }
3465
3466 if let Destination::Stack(payload_results, _) = dst_payload {
3473 if let Destination::Stack(dst_results, _) = dst {
3474 let remaining = &dst_results[1..][payload_results.len()..];
3475 for ty in remaining {
3476 match ty {
3477 ValType::I32 => self.instruction(I32Const(0)),
3478 ValType::I64 => self.instruction(I64Const(0)),
3479 ValType::F32 => self.instruction(F32Const(0.0.into())),
3480 ValType::F64 => self.instruction(F64Const(0.0.into())),
3481 _ => unreachable!(),
3482 }
3483 }
3484 }
3485 }
3486
3487 if src_i != src_cases_len - 1 {
3490 self.instruction(Br(src_cases_len - src_i - 1));
3491 }
3492 self.instruction(End); }
3494 }
3495
3496 fn translate_future(
3497 &mut self,
3498 src_ty: TypeFutureTableIndex,
3499 src: &Source<'_>,
3500 dst_ty: &InterfaceType,
3501 dst: &Destination,
3502 ) {
3503 let dst_ty = match dst_ty {
3504 InterfaceType::Future(t) => *t,
3505 _ => panic!("expected a `Future`"),
3506 };
3507 let transfer = self.module.import_future_transfer();
3508 self.translate_handle(src_ty.as_u32(), src, dst_ty.as_u32(), dst, transfer);
3509 }
3510
3511 fn translate_stream(
3512 &mut self,
3513 src_ty: TypeStreamTableIndex,
3514 src: &Source<'_>,
3515 dst_ty: &InterfaceType,
3516 dst: &Destination,
3517 ) {
3518 let dst_ty = match dst_ty {
3519 InterfaceType::Stream(t) => *t,
3520 _ => panic!("expected a `Stream`"),
3521 };
3522 let transfer = self.module.import_stream_transfer();
3523 self.translate_handle(src_ty.as_u32(), src, dst_ty.as_u32(), dst, transfer);
3524 }
3525
3526 fn translate_error_context(
3527 &mut self,
3528 src_ty: TypeComponentLocalErrorContextTableIndex,
3529 src: &Source<'_>,
3530 dst_ty: &InterfaceType,
3531 dst: &Destination,
3532 ) {
3533 let dst_ty = match dst_ty {
3534 InterfaceType::ErrorContext(t) => *t,
3535 _ => panic!("expected an `ErrorContext`"),
3536 };
3537 let transfer = self.module.import_error_context_transfer();
3538 self.translate_handle(src_ty.as_u32(), src, dst_ty.as_u32(), dst, transfer);
3539 }
3540
3541 fn translate_own(
3542 &mut self,
3543 src_ty: TypeResourceTableIndex,
3544 src: &Source<'_>,
3545 dst_ty: &InterfaceType,
3546 dst: &Destination,
3547 ) {
3548 let dst_ty = match dst_ty {
3549 InterfaceType::Own(t) => *t,
3550 _ => panic!("expected an `Own`"),
3551 };
3552 let transfer = self.module.import_resource_transfer_own();
3553 self.translate_handle(src_ty.as_u32(), src, dst_ty.as_u32(), dst, transfer);
3554 }
3555
3556 fn translate_borrow(
3557 &mut self,
3558 src_ty: TypeResourceTableIndex,
3559 src: &Source<'_>,
3560 dst_ty: &InterfaceType,
3561 dst: &Destination,
3562 ) {
3563 let dst_ty = match dst_ty {
3564 InterfaceType::Borrow(t) => *t,
3565 _ => panic!("expected an `Borrow`"),
3566 };
3567
3568 let transfer = self.module.import_resource_transfer_borrow();
3569 self.translate_handle(src_ty.as_u32(), src, dst_ty.as_u32(), dst, transfer);
3570 }
3571
3572 fn translate_handle(
3580 &mut self,
3581 src_ty: u32,
3582 src: &Source<'_>,
3583 dst_ty: u32,
3584 dst: &Destination,
3585 transfer: FuncIndex,
3586 ) {
3587 self.push_dst_addr(dst);
3588 match src {
3589 Source::Memory(mem) => self.i32_load(mem),
3590 Source::Stack(stack) => self.stack_get(stack, ValType::I32),
3591 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
3592 }
3593 self.instruction(I32Const(src_ty as i32));
3594 self.instruction(I32Const(dst_ty as i32));
3595 self.instruction(Call(transfer.as_u32()));
3596 match dst {
3597 Destination::Memory(mem) => self.i32_store(mem),
3598 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
3599 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
3600 }
3601 }
3602
3603 fn trap_if_not_may_leave(&mut self, flags_global: GlobalIndex, trap: Trap) -> TempLocal {
3610 self.instruction(Block(BlockType::Empty));
3611 self.instruction(GlobalGet(flags_global.as_u32()));
3612 let saved = self.local_tee_new_tmp(ValType::I32);
3615 self.instruction(BrIf(0));
3616 self.trap(trap);
3617 self.instruction(End);
3618 saved
3619 }
3620
3621 fn clear_may_leave(&mut self, flags_global: GlobalIndex) -> TempLocal {
3624 self.instruction(GlobalGet(flags_global.as_u32()));
3625 let saved = self.local_set_new_tmp(ValType::I32);
3626 self.set_may_leave_false(flags_global);
3627 saved
3628 }
3629
3630 fn set_may_leave_false(&mut self, flags_global: GlobalIndex) {
3635 self.instruction(I32Const(0));
3636 self.instruction(GlobalSet(flags_global.as_u32()));
3637 }
3638
3639 fn restore_may_leave(&mut self, flags_global: GlobalIndex, saved: TempLocal) {
3652 self.instruction(LocalGet(saved.idx));
3653 self.instruction(GlobalSet(flags_global.as_u32()));
3654 self.free_temp_local(saved);
3655 }
3656
3657 fn assert_aligned(&mut self, ty: &InterfaceType, mem: &Memory) {
3658 let mem_opts = mem.mem_opts();
3659 if !self.module.tunables.debug_adapter_modules {
3660 return;
3661 }
3662 let align = self.types.align(mem_opts, ty);
3663 if align == 1 {
3664 return;
3665 }
3666 assert!(align.is_power_of_two());
3667 self.instruction(LocalGet(mem.addr.idx));
3668 self.ptr_uconst(mem_opts, mem.offset);
3669 self.ptr_add(mem_opts);
3670 self.ptr_uconst(mem_opts, align - 1);
3671 self.ptr_and(mem_opts);
3672 self.ptr_if(mem_opts, BlockType::Empty);
3673 self.trap(Trap::DebugAssertPointerAligned);
3674 self.instruction(End);
3675 }
3676
3677 fn malloc_abi<'c>(
3683 &mut self,
3684 opts: &'c Options,
3685 abi: &CanonicalAbiInfo,
3686 oob_trap: Trap,
3687 ) -> Memory<'c> {
3688 match &opts.data_model {
3689 DataModel::Gc {} => todo!("CM+GC"),
3690 DataModel::LinearMemory(mem_opts) => {
3691 let (size, align) = mem_opts.sizealign(abi);
3692 let size = AllocSize::Const(size);
3693 self.malloc(opts, size, align, oob_trap)
3694 }
3695 }
3696 }
3697
3698 fn malloc<'c>(
3704 &mut self,
3705 opts: &'c Options,
3706 size: AllocSize,
3707 align: u32,
3708 oob_trap: Trap,
3709 ) -> Memory<'c> {
3710 match &opts.data_model {
3711 DataModel::Gc {} => todo!("CM+GC"),
3712 DataModel::LinearMemory(mem_opts) => {
3713 let realloc = mem_opts.realloc.unwrap();
3714 self.ptr_uconst(mem_opts, 0);
3715 self.ptr_uconst(mem_opts, 0);
3716 self.ptr_uconst(mem_opts, align);
3717 self.alloc_size(mem_opts, &size);
3718 self.instruction(Call(realloc.as_u32()));
3719 let addr = self.local_set_new_tmp(mem_opts.ptr());
3720 self.memory_operand(opts, addr, size, align, oob_trap)
3721 }
3722 }
3723 }
3724
3725 fn realloc(
3731 &mut self,
3732 opts: &Options,
3733 ptr: &TempLocal,
3734 prev_size: AllocSize,
3735 size: AllocSize,
3736 align: u32,
3737 oob_trap: Trap,
3738 ) {
3739 match &opts.data_model {
3740 DataModel::Gc {} => todo!("CM+GC"),
3741 DataModel::LinearMemory(mem_opts) => {
3742 let realloc = mem_opts.realloc.unwrap();
3743 self.instruction(LocalGet(ptr.idx));
3744 self.alloc_size(mem_opts, &prev_size);
3745 self.ptr_uconst(mem_opts, align);
3746 self.alloc_size(mem_opts, &size);
3747 self.instruction(Call(realloc.as_u32()));
3748 self.instruction(LocalSet(ptr.idx));
3749 self.validate_guest_pointer(opts, &ptr, &size, align, oob_trap)
3750 }
3751 }
3752 }
3753
3754 fn memory_operand_abi<'c>(
3757 &mut self,
3758 opts: &'c Options,
3759 addr: TempLocal,
3760 abi: &CanonicalAbiInfo,
3761 oob_trap: Trap,
3762 ) -> Memory<'c> {
3763 match &opts.data_model {
3764 DataModel::Gc {} => todo!("CM+GC"),
3765 DataModel::LinearMemory(mem_opts) => {
3766 let (size, align) = mem_opts.sizealign(abi);
3767 self.memory_operand(opts, addr, AllocSize::Const(size), align, oob_trap)
3768 }
3769 }
3770 }
3771
3772 fn memory_operand<'c>(
3775 &mut self,
3776 opts: &'c Options,
3777 addr: TempLocal,
3778 size: AllocSize,
3779 align: u32,
3780 oob_trap: Trap,
3781 ) -> Memory<'c> {
3782 self.validate_guest_pointer(opts, &addr, &size, align, oob_trap);
3783 Memory {
3784 addr,
3785 opts,
3786 offset: 0,
3787 }
3788 }
3789
3790 fn validate_guest_pointer(
3798 &mut self,
3799 opts: &Options,
3800 addr: &TempLocal,
3801 size: &AllocSize,
3802 align: u32,
3803 oob_trap: Trap,
3804 ) {
3805 let mem_opts = match &opts.data_model {
3806 DataModel::Gc {} => todo!("CM+GC"),
3807 DataModel::LinearMemory(mem_opts) => mem_opts,
3808 };
3809
3810 if align != 1 {
3813 self.instruction(LocalGet(addr.idx));
3814 assert!(align.is_power_of_two());
3815 self.ptr_uconst(mem_opts, align - 1);
3816 self.ptr_and(mem_opts);
3817 self.ptr_if(mem_opts, BlockType::Empty);
3818 self.trap(Trap::UnalignedPointer);
3819 self.instruction(End);
3820 }
3821
3822 let extend_to_64 = |me: &mut Self| {
3823 if !mem_opts.memory64() {
3824 me.instruction(I64ExtendI32U);
3825 }
3826 };
3827
3828 self.instruction(Block(BlockType::Empty));
3829 self.instruction(Block(BlockType::Empty));
3830 let (memory, ty) = mem_opts.memory.unwrap();
3831
3832 self.instruction(MemorySize(memory.as_u32()));
3837 extend_to_64(self);
3838 self.instruction(I64Const(ty.page_size_log2.into()));
3839 self.instruction(I64Shl);
3840
3841 self.instruction(LocalGet(addr.idx));
3846 extend_to_64(self);
3847 self.alloc_size(mem_opts, size);
3848 extend_to_64(self);
3849 self.instruction(I64Add);
3850 if mem_opts.memory64() {
3851 let tmp = self.local_tee_new_tmp(ValType::I64);
3852 self.instruction(LocalGet(addr.idx));
3853 self.ptr_lt_u(mem_opts);
3854 self.instruction(BrIf(0));
3855 self.instruction(LocalGet(tmp.idx));
3856 self.free_temp_local(tmp);
3857 }
3858
3859 self.instruction(I64GeU);
3863 self.instruction(BrIf(1));
3864
3865 self.instruction(End);
3866 self.trap(oob_trap);
3867 self.instruction(End);
3868 }
3869
3870 fn local_tee_new_tmp(&mut self, ty: ValType) -> TempLocal {
3876 self.gen_temp_local(ty, LocalTee)
3877 }
3878
3879 fn local_set_new_tmp(&mut self, ty: ValType) -> TempLocal {
3882 self.gen_temp_local(ty, LocalSet)
3883 }
3884
3885 fn local_get_tmp(&mut self, local: &TempLocal) {
3886 self.instruction(LocalGet(local.idx));
3887 }
3888
3889 fn gen_temp_local(&mut self, ty: ValType, insn: fn(u32) -> Instruction<'static>) -> TempLocal {
3890 if let Some(idx) = self.free_locals.get_mut(&ty).and_then(|v| v.pop()) {
3893 self.instruction(insn(idx));
3894 return TempLocal {
3895 ty,
3896 idx,
3897 needs_free: true,
3898 };
3899 }
3900
3901 let locals = &mut self.module.funcs[self.result].locals;
3903 match locals.last_mut() {
3904 Some((cnt, prev_ty)) if ty == *prev_ty => *cnt += 1,
3905 _ => locals.push((1, ty)),
3906 }
3907 self.nlocals += 1;
3908 let idx = self.nlocals - 1;
3909 self.instruction(insn(idx));
3910 TempLocal {
3911 ty,
3912 idx,
3913 needs_free: true,
3914 }
3915 }
3916
3917 fn free_temp_local(&mut self, mut local: TempLocal) {
3920 assert!(local.needs_free);
3921 self.free_locals
3922 .entry(local.ty)
3923 .or_insert(Vec::new())
3924 .push(local.idx);
3925 local.needs_free = false;
3926 }
3927
3928 fn instruction(&mut self, instr: Instruction) {
3929 instr.encode(&mut self.code);
3930 }
3931
3932 fn trap(&mut self, trap: Trap) {
3933 let trap_func = self.module.import_trap();
3934 self.instruction(I32Const(trap as i32));
3935 self.instruction(Call(trap_func.as_u32()));
3936 self.instruction(Unreachable);
3937 }
3938
3939 fn enter_exception_barrier(&mut self, results: &[ValType]) {
3970 if !self.module.features.exceptions() {
3971 return;
3972 }
3973 let block_ty = match results.len() {
3974 0 => BlockType::Empty,
3975 1 => BlockType::Result(results[0]),
3976 _ => BlockType::FunctionType(self.module.core_types.function(&[], results)),
3977 };
3978 self.instruction(Block(block_ty));
3980 self.instruction(Block(BlockType::Empty));
3982 self.instruction(TryTable(block_ty, vec![Catch::All { label: 0 }].into()));
3983 }
3984
3985 fn exit_exception_barrier(&mut self) {
3990 if !self.module.features.exceptions() {
3991 return;
3992 }
3993 self.instruction(End);
3995 self.instruction(Br(1));
3997 self.instruction(End);
3999 self.trap(Trap::UncaughtException);
4000 self.instruction(End);
4002 }
4003
4004 fn flush_code(&mut self) {
4009 if self.code.is_empty() {
4010 return;
4011 }
4012 self.module.funcs[self.result]
4013 .body
4014 .push(Body::Raw(mem::take(&mut self.code)));
4015 }
4016
4017 fn finish(mut self) {
4018 self.instruction(End);
4021 self.flush_code();
4022
4023 self.module.funcs[self.result].filled_in = true;
4026 }
4027
4028 fn stack_get(&mut self, stack: &Stack<'_>, dst_ty: ValType) {
4036 assert_eq!(stack.locals.len(), 1);
4037 let (idx, src_ty) = stack.locals[0];
4038 self.instruction(LocalGet(idx));
4039 match (src_ty, dst_ty) {
4040 (ValType::I32, ValType::I32)
4041 | (ValType::I64, ValType::I64)
4042 | (ValType::F32, ValType::F32)
4043 | (ValType::F64, ValType::F64) => {}
4044
4045 (ValType::I32, ValType::F32) => self.instruction(F32ReinterpretI32),
4046 (ValType::I64, ValType::I32) => {
4047 self.assert_i64_upper_bits_not_set(idx);
4048 self.instruction(I32WrapI64);
4049 }
4050 (ValType::I64, ValType::F64) => self.instruction(F64ReinterpretI64),
4051 (ValType::I64, ValType::F32) => {
4052 self.assert_i64_upper_bits_not_set(idx);
4053 self.instruction(I32WrapI64);
4054 self.instruction(F32ReinterpretI32);
4055 }
4056
4057 (ValType::I32, ValType::I64)
4059 | (ValType::I32, ValType::F64)
4060 | (ValType::F32, ValType::I32)
4061 | (ValType::F32, ValType::I64)
4062 | (ValType::F32, ValType::F64)
4063 | (ValType::F64, ValType::I32)
4064 | (ValType::F64, ValType::I64)
4065 | (ValType::F64, ValType::F32)
4066
4067 | (ValType::Ref(_), _)
4069 | (_, ValType::Ref(_))
4070 | (ValType::V128, _)
4071 | (_, ValType::V128) => {
4072 panic!("cannot get {dst_ty:?} from {src_ty:?} local");
4073 }
4074 }
4075 }
4076
4077 fn assert_i64_upper_bits_not_set(&mut self, local: u32) {
4078 if !self.module.tunables.debug_adapter_modules {
4079 return;
4080 }
4081 self.instruction(LocalGet(local));
4082 self.instruction(I64Const(32));
4083 self.instruction(I64ShrU);
4084 self.instruction(I32WrapI64);
4085 self.instruction(If(BlockType::Empty));
4086 self.trap(Trap::DebugAssertUpperBitsUnset);
4087 self.instruction(End);
4088 }
4089
4090 fn stack_set(&mut self, dst_tys: &[ValType], src_ty: ValType) {
4096 assert_eq!(dst_tys.len(), 1);
4097 let dst_ty = dst_tys[0];
4098 match (src_ty, dst_ty) {
4099 (ValType::I32, ValType::I32)
4100 | (ValType::I64, ValType::I64)
4101 | (ValType::F32, ValType::F32)
4102 | (ValType::F64, ValType::F64) => {}
4103
4104 (ValType::F32, ValType::I32) => self.instruction(I32ReinterpretF32),
4105 (ValType::I32, ValType::I64) => self.instruction(I64ExtendI32U),
4106 (ValType::F64, ValType::I64) => self.instruction(I64ReinterpretF64),
4107 (ValType::F32, ValType::I64) => {
4108 self.instruction(I32ReinterpretF32);
4109 self.instruction(I64ExtendI32U);
4110 }
4111
4112 (ValType::I64, ValType::I32)
4114 | (ValType::F64, ValType::I32)
4115 | (ValType::I32, ValType::F32)
4116 | (ValType::I64, ValType::F32)
4117 | (ValType::F64, ValType::F32)
4118 | (ValType::I32, ValType::F64)
4119 | (ValType::I64, ValType::F64)
4120 | (ValType::F32, ValType::F64)
4121
4122 | (ValType::Ref(_), _)
4124 | (_, ValType::Ref(_))
4125 | (ValType::V128, _)
4126 | (_, ValType::V128) => {
4127 panic!("cannot get {dst_ty:?} from {src_ty:?} local");
4128 }
4129 }
4130 }
4131
4132 fn i32_load8u(&mut self, mem: &Memory) {
4133 self.instruction(LocalGet(mem.addr.idx));
4134 self.instruction(I32Load8U(mem.memarg(0)));
4135 }
4136
4137 fn i32_load8s(&mut self, mem: &Memory) {
4138 self.instruction(LocalGet(mem.addr.idx));
4139 self.instruction(I32Load8S(mem.memarg(0)));
4140 }
4141
4142 fn i32_load16u(&mut self, mem: &Memory) {
4143 self.instruction(LocalGet(mem.addr.idx));
4144 self.instruction(I32Load16U(mem.memarg(1)));
4145 }
4146
4147 fn i32_load16s(&mut self, mem: &Memory) {
4148 self.instruction(LocalGet(mem.addr.idx));
4149 self.instruction(I32Load16S(mem.memarg(1)));
4150 }
4151
4152 fn i32_load(&mut self, mem: &Memory) {
4153 self.instruction(LocalGet(mem.addr.idx));
4154 self.instruction(I32Load(mem.memarg(2)));
4155 }
4156
4157 fn i64_load(&mut self, mem: &Memory) {
4158 self.instruction(LocalGet(mem.addr.idx));
4159 self.instruction(I64Load(mem.memarg(3)));
4160 }
4161
4162 fn ptr_load(&mut self, mem: &Memory) {
4163 if mem.mem_opts().memory64() {
4164 self.i64_load(mem);
4165 } else {
4166 self.i32_load(mem);
4167 }
4168 }
4169
4170 fn ptr_add(&mut self, opts: &LinearMemoryOptions) {
4171 if opts.memory64() {
4172 self.instruction(I64Add);
4173 } else {
4174 self.instruction(I32Add);
4175 }
4176 }
4177
4178 fn ptr_sub(&mut self, opts: &LinearMemoryOptions) {
4179 if opts.memory64() {
4180 self.instruction(I64Sub);
4181 } else {
4182 self.instruction(I32Sub);
4183 }
4184 }
4185
4186 fn ptr_mul(&mut self, opts: &LinearMemoryOptions) {
4187 if opts.memory64() {
4188 self.instruction(I64Mul);
4189 } else {
4190 self.instruction(I32Mul);
4191 }
4192 }
4193
4194 fn ptr_gt_u(&mut self, opts: &LinearMemoryOptions) {
4195 if opts.memory64() {
4196 self.instruction(I64GtU);
4197 } else {
4198 self.instruction(I32GtU);
4199 }
4200 }
4201
4202 fn ptr_lt_u(&mut self, opts: &LinearMemoryOptions) {
4203 if opts.memory64() {
4204 self.instruction(I64LtU);
4205 } else {
4206 self.instruction(I32LtU);
4207 }
4208 }
4209
4210 fn ptr_shl(&mut self, opts: &LinearMemoryOptions) {
4211 if opts.memory64() {
4212 self.instruction(I64Shl);
4213 } else {
4214 self.instruction(I32Shl);
4215 }
4216 }
4217
4218 fn ptr_eqz(&mut self, opts: &LinearMemoryOptions) {
4219 if opts.memory64() {
4220 self.instruction(I64Eqz);
4221 } else {
4222 self.instruction(I32Eqz);
4223 }
4224 }
4225
4226 fn ptr_uconst(&mut self, opts: &LinearMemoryOptions, val: u32) {
4227 if opts.memory64() {
4228 self.instruction(I64Const(val.into()));
4229 } else {
4230 self.instruction(I32Const(val.cast_signed()));
4231 }
4232 }
4233
4234 fn ptr_iconst(&mut self, opts: &LinearMemoryOptions, val: i32) {
4235 if opts.memory64() {
4236 self.instruction(I64Const(val.into()));
4237 } else {
4238 self.instruction(I32Const(val));
4239 }
4240 }
4241
4242 fn ptr_eq(&mut self, opts: &LinearMemoryOptions) {
4243 if opts.memory64() {
4244 self.instruction(I64Eq);
4245 } else {
4246 self.instruction(I32Eq);
4247 }
4248 }
4249
4250 fn ptr_ne(&mut self, opts: &LinearMemoryOptions) {
4251 if opts.memory64() {
4252 self.instruction(I64Ne);
4253 } else {
4254 self.instruction(I32Ne);
4255 }
4256 }
4257
4258 fn ptr_and(&mut self, opts: &LinearMemoryOptions) {
4259 if opts.memory64() {
4260 self.instruction(I64And);
4261 } else {
4262 self.instruction(I32And);
4263 }
4264 }
4265
4266 fn ptr_or(&mut self, opts: &LinearMemoryOptions) {
4267 if opts.memory64() {
4268 self.instruction(I64Or);
4269 } else {
4270 self.instruction(I32Or);
4271 }
4272 }
4273
4274 fn ptr_xor(&mut self, opts: &LinearMemoryOptions) {
4275 if opts.memory64() {
4276 self.instruction(I64Xor);
4277 } else {
4278 self.instruction(I32Xor);
4279 }
4280 }
4281
4282 fn ptr_if(&mut self, opts: &LinearMemoryOptions, ty: BlockType) {
4283 if opts.memory64() {
4284 self.instruction(I64Const(0));
4285 self.instruction(I64Ne);
4286 }
4287 self.instruction(If(ty));
4288 }
4289
4290 fn ptr_br_if(&mut self, opts: &LinearMemoryOptions, depth: u32) {
4291 if opts.memory64() {
4292 self.instruction(I64Const(0));
4293 self.instruction(I64Ne);
4294 }
4295 self.instruction(BrIf(depth));
4296 }
4297
4298 fn f32_load(&mut self, mem: &Memory) {
4299 self.instruction(LocalGet(mem.addr.idx));
4300 self.instruction(F32Load(mem.memarg(2)));
4301 }
4302
4303 fn f64_load(&mut self, mem: &Memory) {
4304 self.instruction(LocalGet(mem.addr.idx));
4305 self.instruction(F64Load(mem.memarg(3)));
4306 }
4307
4308 fn push_dst_addr(&mut self, dst: &Destination) {
4309 if let Destination::Memory(mem) = dst {
4310 self.instruction(LocalGet(mem.addr.idx));
4311 }
4312 }
4313
4314 fn i32_store8(&mut self, mem: &Memory) {
4315 self.instruction(I32Store8(mem.memarg(0)));
4316 }
4317
4318 fn i32_store16(&mut self, mem: &Memory) {
4319 self.instruction(I32Store16(mem.memarg(1)));
4320 }
4321
4322 fn i32_store(&mut self, mem: &Memory) {
4323 self.instruction(I32Store(mem.memarg(2)));
4324 }
4325
4326 fn i64_store(&mut self, mem: &Memory) {
4327 self.instruction(I64Store(mem.memarg(3)));
4328 }
4329
4330 fn ptr_store(&mut self, mem: &Memory) {
4331 if mem.mem_opts().memory64() {
4332 self.i64_store(mem);
4333 } else {
4334 self.i32_store(mem);
4335 }
4336 }
4337
4338 fn f32_store(&mut self, mem: &Memory) {
4339 self.instruction(F32Store(mem.memarg(2)));
4340 }
4341
4342 fn f64_store(&mut self, mem: &Memory) {
4343 self.instruction(F64Store(mem.memarg(3)));
4344 }
4345
4346 fn alloc_size(&mut self, opts: &LinearMemoryOptions, size: &AllocSize) {
4349 match size {
4350 AllocSize::Const(size) => self.ptr_uconst(opts, *size),
4351 AllocSize::Local(idx) => self.instruction(LocalGet(*idx)),
4352 AllocSize::DoubleLocal(idx) => {
4353 self.instruction(LocalGet(*idx));
4354 self.ptr_uconst(opts, 1);
4355 self.ptr_shl(opts);
4356 }
4357 }
4358 }
4359}
4360
4361impl<'a> Source<'a> {
4362 fn record_field_srcs<'b>(
4369 &'b self,
4370 types: &'b ComponentTypesBuilder,
4371 fields: impl IntoIterator<Item = InterfaceType> + 'b,
4372 ) -> impl Iterator<Item = Source<'a>> + 'b
4373 where
4374 'a: 'b,
4375 {
4376 let mut offset = 0;
4377 fields.into_iter().map(move |ty| match self {
4378 Source::Memory(mem) => {
4379 let mem = next_field_offset(&mut offset, types, &ty, mem);
4380 Source::Memory(mem)
4381 }
4382 Source::Stack(stack) => {
4383 let cnt = types.flat_types(&ty).unwrap().len() as u32;
4384 offset += cnt;
4385 Source::Stack(stack.slice((offset - cnt) as usize..offset as usize))
4386 }
4387 Source::Struct(_) => todo!(),
4388 Source::Array(_) => todo!(),
4389 })
4390 }
4391
4392 fn payload_src(
4394 &self,
4395 types: &ComponentTypesBuilder,
4396 info: &VariantInfo,
4397 case: Option<&InterfaceType>,
4398 ) -> Source<'a> {
4399 match self {
4400 Source::Stack(s) => {
4401 let flat_len = match case {
4402 Some(case) => types.flat_types(case).unwrap().len(),
4403 None => 0,
4404 };
4405 Source::Stack(s.slice(1..s.locals.len()).slice(0..flat_len))
4406 }
4407 Source::Memory(mem) => {
4408 let mem = if mem.mem_opts().memory64() {
4409 mem.bump(info.payload_offset64)
4410 } else {
4411 mem.bump(info.payload_offset32)
4412 };
4413 Source::Memory(mem)
4414 }
4415 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
4416 }
4417 }
4418
4419 fn opts(&self) -> &'a Options {
4420 match self {
4421 Source::Stack(s) => s.opts,
4422 Source::Memory(mem) => mem.opts,
4423 Source::Struct(s) => s.opts,
4424 Source::Array(a) => a.opts,
4425 }
4426 }
4427}
4428
4429impl<'a> Destination<'a> {
4430 fn record_field_dsts<'b, I>(
4432 &'b self,
4433 types: &'b ComponentTypesBuilder,
4434 fields: I,
4435 ) -> impl Iterator<Item = Destination<'b>> + use<'b, I>
4436 where
4437 'a: 'b,
4438 I: IntoIterator<Item = InterfaceType> + 'b,
4439 {
4440 let mut offset = 0;
4441 fields.into_iter().map(move |ty| match self {
4442 Destination::Memory(mem) => {
4443 let mem = next_field_offset(&mut offset, types, &ty, mem);
4444 Destination::Memory(mem)
4445 }
4446 Destination::Stack(s, opts) => {
4447 let cnt = types.flat_types(&ty).unwrap().len() as u32;
4448 offset += cnt;
4449 Destination::Stack(&s[(offset - cnt) as usize..offset as usize], opts)
4450 }
4451 Destination::Struct(_) => todo!(),
4452 Destination::Array(_) => todo!(),
4453 })
4454 }
4455
4456 fn payload_dst(
4458 &self,
4459 types: &ComponentTypesBuilder,
4460 info: &VariantInfo,
4461 case: Option<&InterfaceType>,
4462 ) -> Destination<'_> {
4463 match self {
4464 Destination::Stack(s, opts) => {
4465 let flat_len = match case {
4466 Some(case) => types.flat_types(case).unwrap().len(),
4467 None => 0,
4468 };
4469 Destination::Stack(&s[1..][..flat_len], opts)
4470 }
4471 Destination::Memory(mem) => {
4472 let mem = if mem.mem_opts().memory64() {
4473 mem.bump(info.payload_offset64)
4474 } else {
4475 mem.bump(info.payload_offset32)
4476 };
4477 Destination::Memory(mem)
4478 }
4479 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
4480 }
4481 }
4482
4483 fn opts(&self) -> &'a Options {
4484 match self {
4485 Destination::Stack(_, opts) => opts,
4486 Destination::Memory(mem) => mem.opts,
4487 Destination::Struct(s) => s.opts,
4488 Destination::Array(a) => a.opts,
4489 }
4490 }
4491}
4492
4493fn next_field_offset<'a>(
4494 offset: &mut u32,
4495 types: &ComponentTypesBuilder,
4496 field: &InterfaceType,
4497 mem: &Memory<'a>,
4498) -> Memory<'a> {
4499 let abi = types.canonical_abi(field);
4500 let offset = if mem.mem_opts().memory64() {
4501 abi.next_field64(offset)
4502 } else {
4503 abi.next_field32(offset)
4504 };
4505 mem.bump(offset)
4506}
4507
4508impl<'a> Memory<'a> {
4509 fn memarg(&self, align: u32) -> MemArg {
4510 MemArg {
4511 offset: u64::from(self.offset),
4512 align,
4513 memory_index: self.mem_opts().memory.unwrap().0.as_u32(),
4514 }
4515 }
4516
4517 fn bump(&self, offset: u32) -> Memory<'a> {
4518 Memory {
4519 opts: self.opts,
4520 addr: TempLocal::new(self.addr.idx, self.addr.ty),
4521 offset: self.offset + offset,
4522 }
4523 }
4524}
4525
4526impl<'a> Stack<'a> {
4527 fn slice(&self, range: Range<usize>) -> Stack<'a> {
4528 Stack {
4529 locals: &self.locals[range],
4530 opts: self.opts,
4531 }
4532 }
4533}
4534
4535struct VariantCase<'a> {
4536 src_i: u32,
4537 src_ty: Option<&'a InterfaceType>,
4538 dst_i: u32,
4539 dst_ty: Option<&'a InterfaceType>,
4540}
4541
4542fn variant_info<'a, I>(types: &ComponentTypesBuilder, cases: I) -> VariantInfo
4543where
4544 I: IntoIterator<Item = Option<&'a InterfaceType>>,
4545 I::IntoIter: ExactSizeIterator,
4546{
4547 VariantInfo::new(
4548 cases
4549 .into_iter()
4550 .map(|ty| ty.map(|ty| types.canonical_abi(ty))),
4551 )
4552 .0
4553}
4554
4555struct SequenceLoopState {
4557 remaining: TempLocal,
4558 cur_src_ptr: TempLocal,
4559 cur_dst_ptr: TempLocal,
4560}
4561
4562struct SequenceTranslation<'a> {
4566 src_len: TempLocal,
4567 src_mem: Memory<'a>,
4568 dst_mem: Memory<'a>,
4569 src_opts: &'a Options,
4570 dst_opts: &'a Options,
4571 src_mem_opts: &'a LinearMemoryOptions,
4572 dst_mem_opts: &'a LinearMemoryOptions,
4573 loop_state: Option<SequenceLoopState>,
4574}
4575
4576enum AllocSize {
4577 Const(u32),
4578 Local(u32),
4579 DoubleLocal(u32),
4580}
4581
4582struct WasmString<'a> {
4583 ptr: TempLocal,
4584 len: TempLocal,
4585 opts: &'a Options,
4586}
4587
4588struct TempLocal {
4589 idx: u32,
4590 ty: ValType,
4591 needs_free: bool,
4592}
4593
4594impl TempLocal {
4595 fn new(idx: u32, ty: ValType) -> TempLocal {
4596 TempLocal {
4597 idx,
4598 ty,
4599 needs_free: false,
4600 }
4601 }
4602}
4603
4604impl std::ops::Drop for TempLocal {
4605 fn drop(&mut self) {
4606 if self.needs_free {
4607 panic!("temporary local not free'd");
4608 }
4609 }
4610}
4611
4612impl From<FlatType> for ValType {
4613 fn from(ty: FlatType) -> ValType {
4614 match ty {
4615 FlatType::I32 => ValType::I32,
4616 FlatType::I64 => ValType::I64,
4617 FlatType::F32 => ValType::F32,
4618 FlatType::F64 => ValType::F64,
4619 }
4620 }
4621}