1use crate::component::{
19 CanonicalAbiInfo, ComponentTypesBuilder, FLAG_MAY_LEAVE, FixedEncoding as FE, FlatType,
20 InterfaceType, MAX_FLAT_ASYNC_PARAMS, MAX_FLAT_PARAMS, PREPARE_ASYNC_NO_RESULT,
21 PREPARE_ASYNC_WITH_RESULT, START_FLAG_ASYNC_CALLEE, StringEncoding, Transcode,
22 TypeComponentLocalErrorContextTableIndex, TypeEnumIndex, TypeFixedLengthListIndex,
23 TypeFlagsIndex, TypeFutureTableIndex, TypeListIndex, TypeMapIndex, TypeOptionIndex,
24 TypeRecordIndex, TypeResourceTableIndex, TypeResultIndex, TypeStreamTableIndex, TypeTupleIndex,
25 TypeVariantIndex, VariantInfo,
26};
27use crate::fact::signature::Signature;
28use crate::fact::transcode::Transcoder;
29use crate::fact::{
30 AdapterData, Body, Function, FunctionId, Helper, HelperLocation, HelperType,
31 LinearMemoryOptions, Module, Options,
32};
33use crate::prelude::*;
34use crate::{FuncIndex, GlobalIndex, Trap};
35use std::collections::HashMap;
36use std::mem;
37use std::ops::Range;
38use wasm_encoder::{BlockType, Encode, Instruction, Instruction::*, MemArg, ValType};
39use wasmtime_component_util::{DiscriminantSize, FlagsSize};
40
41use super::DataModel;
42
43const MAX_STRING_BYTE_LENGTH: u32 = 1 << 31;
44const UTF16_TAG: u32 = 1 << 31;
45
46const INITIAL_FUEL: usize = 1_000;
49
50struct Compiler<'a, 'b> {
51 types: &'a ComponentTypesBuilder,
52 module: &'b mut Module<'a>,
53 result: FunctionId,
54
55 code: Vec<u8>,
57
58 nlocals: u32,
60
61 free_locals: HashMap<ValType, Vec<u32>>,
63
64 fuel: usize,
73
74 emit_resource_call: bool,
79}
80
81pub(super) fn compile(module: &mut Module<'_>, adapter: &AdapterData) {
82 fn compiler<'a, 'b>(
83 module: &'b mut Module<'a>,
84 adapter: &AdapterData,
85 ) -> (Compiler<'a, 'b>, Signature, Signature) {
86 let lower_sig = module.types.signature(&adapter.lower);
87 let lift_sig = module.types.signature(&adapter.lift);
88 let ty = module
89 .core_types
90 .function(&lower_sig.params, &lower_sig.results);
91 let result = module
92 .funcs
93 .push(Function::new(Some(adapter.name.clone()), ty));
94
95 let emit_resource_call = module.types.contains_borrow_resource(&adapter.lower);
100 assert_eq!(
101 emit_resource_call,
102 module.types.contains_borrow_resource(&adapter.lift)
103 );
104
105 (
106 Compiler::new(
107 module,
108 result,
109 lower_sig.params.len() as u32,
110 emit_resource_call,
111 ),
112 lower_sig,
113 lift_sig,
114 )
115 }
116
117 if adapter.lift.instance == adapter.lower.instance
121 || adapter.lower.ancestors.contains(&adapter.lift.instance)
122 || adapter.lift.ancestors.contains(&adapter.lower.instance)
123 {
124 let (mut compiler, _, _) = compiler(module, adapter);
125 compiler.trap(Trap::CannotEnterComponent);
126 compiler.finish();
127 return;
128 }
129
130 let async_start_adapter = |module: &mut Module| {
136 let sig = module
137 .types
138 .async_start_signature(&adapter.lower, &adapter.lift);
139 let ty = module.core_types.function(&sig.params, &sig.results);
140 let result = module.funcs.push(Function::new(
141 Some(format!("[async-start]{}", adapter.name)),
142 ty,
143 ));
144
145 Compiler::new(module, result, sig.params.len() as u32, false)
146 .compile_async_start_adapter(adapter, &sig);
147
148 result
149 };
150
151 let async_return_adapter = |module: &mut Module| {
160 let sig = module
161 .types
162 .async_return_signature(&adapter.lower, &adapter.lift);
163 let ty = module.core_types.function(&sig.params, &sig.results);
164 let result = module.funcs.push(Function::new(
165 Some(format!("[async-return]{}", adapter.name)),
166 ty,
167 ));
168
169 Compiler::new(module, result, sig.params.len() as u32, false)
170 .compile_async_return_adapter(adapter, &sig);
171
172 result
173 };
174
175 match (adapter.lower.options.async_, adapter.lift.options.async_) {
176 (false, false) => {
177 let (compiler, lower_sig, lift_sig) = compiler(module, adapter);
180 compiler.compile_sync_to_sync_adapter(adapter, &lower_sig, &lift_sig)
181 }
182 (true, true) => {
183 assert!(module.tunables.concurrency_support);
184
185 let start = async_start_adapter(module);
201 let return_ = async_return_adapter(module);
202 let (compiler, lower_sig, lift_sig) = compiler(module, adapter);
203 compiler.compile_async_to_async_adapter(
204 adapter,
205 start,
206 return_,
207 i32::try_from(lift_sig.params.len()).unwrap(),
208 &lower_sig,
209 );
210 }
211 (false, true) => {
212 assert!(module.tunables.concurrency_support);
213
214 let start = async_start_adapter(module);
227 let return_ = async_return_adapter(module);
228 let (compiler, lower_sig, lift_sig) = compiler(module, adapter);
229 compiler.compile_sync_to_async_adapter(
230 adapter,
231 start,
232 return_,
233 i32::try_from(lift_sig.params.len()).unwrap(),
234 &lower_sig,
235 );
236 }
237 (true, false) => {
238 assert!(module.tunables.concurrency_support);
239
240 let lift_sig = module.types.signature(&adapter.lift);
260 let start = async_start_adapter(module);
261 let return_ = async_return_adapter(module);
262 let (compiler, lower_sig, ..) = compiler(module, adapter);
263 compiler.compile_async_to_sync_adapter(
264 adapter,
265 start,
266 return_,
267 i32::try_from(lift_sig.params.len()).unwrap(),
268 i32::try_from(lift_sig.results.len()).unwrap(),
269 &lower_sig,
270 );
271 }
272 }
273}
274
275pub(super) fn compile_helper(module: &mut Module<'_>, result: FunctionId, helper: Helper) {
282 let mut nlocals = 0;
283 let src_flat;
284 let src = match helper.src.loc {
285 HelperLocation::Stack => {
290 src_flat = module
291 .types
292 .flatten_types(&helper.src.opts, usize::MAX, [helper.src.ty])
293 .unwrap()
294 .iter()
295 .enumerate()
296 .map(|(i, ty)| (i as u32, *ty))
297 .collect::<Vec<_>>();
298 nlocals += src_flat.len() as u32;
299 Source::Stack(Stack {
300 locals: &src_flat,
301 opts: &helper.src.opts,
302 })
303 }
304 HelperLocation::Memory => {
307 nlocals += 1;
308 Source::Memory(Memory {
309 opts: &helper.src.opts,
310 addr: TempLocal::new(0, helper.src.opts.data_model.unwrap_memory().ptr()),
311 offset: 0,
312 })
313 }
314 HelperLocation::StructField | HelperLocation::ArrayElement => todo!("CM+GC"),
315 };
316 let dst_flat;
317 let dst = match helper.dst.loc {
318 HelperLocation::Stack => {
321 dst_flat = module
322 .types
323 .flatten_types(&helper.dst.opts, usize::MAX, [helper.dst.ty])
324 .unwrap();
325 Destination::Stack(&dst_flat, &helper.dst.opts)
326 }
327 HelperLocation::Memory => {
330 nlocals += 1;
331 Destination::Memory(Memory {
332 opts: &helper.dst.opts,
333 addr: TempLocal::new(
334 nlocals - 1,
335 helper.dst.opts.data_model.unwrap_memory().ptr(),
336 ),
337 offset: 0,
338 })
339 }
340 HelperLocation::StructField | HelperLocation::ArrayElement => todo!("CM+GC"),
341 };
342 let mut compiler = Compiler {
343 types: module.types,
344 module,
345 code: Vec::new(),
346 nlocals,
347 free_locals: HashMap::new(),
348 result,
349 fuel: INITIAL_FUEL,
350 emit_resource_call: false,
353 };
354 compiler.translate(&helper.src.ty, &src, &helper.dst.ty, &dst);
355 compiler.finish();
356}
357
358enum Source<'a> {
361 Stack(Stack<'a>),
367
368 Memory(Memory<'a>),
371
372 #[allow(dead_code, reason = "CM+GC is still WIP")]
375 Struct(GcStruct<'a>),
376
377 #[allow(dead_code, reason = "CM+GC is still WIP")]
380 Array(GcArray<'a>),
381}
382
383enum Destination<'a> {
385 Stack(&'a [ValType], &'a Options),
391
392 Memory(Memory<'a>),
394
395 #[allow(dead_code, reason = "CM+GC is still WIP")]
398 Struct(GcStruct<'a>),
399
400 #[allow(dead_code, reason = "CM+GC is still WIP")]
403 Array(GcArray<'a>),
404}
405
406struct Stack<'a> {
407 locals: &'a [(u32, ValType)],
413 opts: &'a Options,
415}
416
417struct Memory<'a> {
419 opts: &'a Options,
421 addr: TempLocal,
424 offset: u32,
427}
428
429impl<'a> Memory<'a> {
430 fn mem_opts(&self) -> &'a LinearMemoryOptions {
431 self.opts.data_model.unwrap_memory()
432 }
433}
434
435struct GcStruct<'a> {
437 opts: &'a Options,
438 }
440
441struct GcArray<'a> {
443 opts: &'a Options,
444 }
446
447impl<'a, 'b> Compiler<'a, 'b> {
448 fn new(
449 module: &'b mut Module<'a>,
450 result: FunctionId,
451 nlocals: u32,
452 emit_resource_call: bool,
453 ) -> Self {
454 Self {
455 types: module.types,
456 module,
457 result,
458 code: Vec::new(),
459 nlocals,
460 free_locals: HashMap::new(),
461 fuel: INITIAL_FUEL,
462 emit_resource_call,
463 }
464 }
465
466 fn compile_async_to_async_adapter(
476 mut self,
477 adapter: &AdapterData,
478 start: FunctionId,
479 return_: FunctionId,
480 param_count: i32,
481 lower_sig: &Signature,
482 ) {
483 let start_call =
484 self.module
485 .import_async_start_call(&adapter.name, adapter.lift.options.callback, None);
486
487 self.call_prepare(adapter, start, return_, lower_sig, false);
488
489 self.module.exports.push((
498 adapter.callee.as_u32(),
499 format!("[adapter-callee]{}", adapter.name),
500 ));
501
502 self.instruction(RefFunc(adapter.callee.as_u32()));
503 self.instruction(I32Const(param_count));
504 self.instruction(I32Const(1));
508 self.instruction(I32Const(START_FLAG_ASYNC_CALLEE));
509 self.instruction(Call(start_call.as_u32()));
510
511 self.finish()
512 }
513
514 fn call_prepare(
527 &mut self,
528 adapter: &AdapterData,
529 start: FunctionId,
530 return_: FunctionId,
531 lower_sig: &Signature,
532 prepare_sync: bool,
533 ) {
534 let prepare = self.module.import_prepare_call(
535 &adapter.name,
536 &lower_sig.params,
537 match adapter.lift.options.data_model {
538 DataModel::Gc {} => todo!("CM+GC"),
539 DataModel::LinearMemory(LinearMemoryOptions { memory, .. }) => memory,
540 },
541 );
542
543 self.flush_code();
544 self.module.funcs[self.result]
545 .body
546 .push(Body::RefFunc(start));
547 self.module.funcs[self.result]
548 .body
549 .push(Body::RefFunc(return_));
550 self.instruction(I32Const(
551 i32::try_from(adapter.lower.instance.as_u32()).unwrap(),
552 ));
553 self.instruction(I32Const(
554 i32::try_from(adapter.lift.instance.as_u32()).unwrap(),
555 ));
556 self.instruction(I32Const(
557 i32::try_from(self.types[adapter.lift.ty].results.as_u32()).unwrap(),
558 ));
559 self.instruction(I32Const(if self.types[adapter.lift.ty].async_ {
560 1
561 } else {
562 0
563 }));
564 self.instruction(I32Const(i32::from(
565 adapter.lift.options.string_encoding as u8,
566 )));
567
568 let result_types = &self.types[self.types[adapter.lower.ty].results].types;
571 if prepare_sync {
572 self.instruction(I32Const(
573 i32::try_from(
574 self.types
575 .flatten_types(
576 &adapter.lower.options,
577 usize::MAX,
578 result_types.iter().copied(),
579 )
580 .map(|v| v.len())
581 .unwrap_or(usize::try_from(i32::MAX).unwrap()),
582 )
583 .unwrap(),
584 ));
585 } else {
586 if result_types.len() > 0 {
587 self.instruction(I32Const(PREPARE_ASYNC_WITH_RESULT.cast_signed()));
588 } else {
589 self.instruction(I32Const(PREPARE_ASYNC_NO_RESULT.cast_signed()));
590 }
591 }
592
593 for index in 0..lower_sig.params.len() {
595 self.instruction(LocalGet(u32::try_from(index).unwrap()));
596 }
597 self.instruction(Call(prepare.as_u32()));
598 }
599
600 fn compile_sync_to_async_adapter(
610 mut self,
611 adapter: &AdapterData,
612 start: FunctionId,
613 return_: FunctionId,
614 lift_param_count: i32,
615 lower_sig: &Signature,
616 ) {
617 let start_call = self.module.import_sync_start_call(
618 &adapter.name,
619 adapter.lift.options.callback,
620 &lower_sig.results,
621 );
622
623 self.call_prepare(adapter, start, return_, lower_sig, true);
624
625 self.module.exports.push((
634 adapter.callee.as_u32(),
635 format!("[adapter-callee]{}", adapter.name),
636 ));
637
638 self.instruction(RefFunc(adapter.callee.as_u32()));
639 self.instruction(I32Const(lift_param_count));
640 self.instruction(Call(start_call.as_u32()));
641
642 self.finish()
643 }
644
645 fn compile_async_to_sync_adapter(
655 mut self,
656 adapter: &AdapterData,
657 start: FunctionId,
658 return_: FunctionId,
659 param_count: i32,
660 result_count: i32,
661 lower_sig: &Signature,
662 ) {
663 let start_call =
664 self.module
665 .import_async_start_call(&adapter.name, None, adapter.lift.post_return);
666
667 self.call_prepare(adapter, start, return_, lower_sig, false);
668
669 self.module.exports.push((
673 adapter.callee.as_u32(),
674 format!("[adapter-callee]{}", adapter.name),
675 ));
676
677 self.instruction(RefFunc(adapter.callee.as_u32()));
678 self.instruction(I32Const(param_count));
679 self.instruction(I32Const(result_count));
680 self.instruction(I32Const(0));
681 self.instruction(Call(start_call.as_u32()));
682
683 self.finish()
684 }
685
686 fn compile_async_start_adapter(mut self, adapter: &AdapterData, sig: &Signature) {
692 let param_locals = sig
693 .params
694 .iter()
695 .enumerate()
696 .map(|(i, ty)| (i as u32, *ty))
697 .collect::<Vec<_>>();
698
699 self.set_flag(adapter.lift.flags, FLAG_MAY_LEAVE, false);
700 self.translate_params(adapter, ¶m_locals);
701 self.set_flag(adapter.lift.flags, FLAG_MAY_LEAVE, true);
702
703 self.finish();
704 }
705
706 fn compile_async_return_adapter(mut self, adapter: &AdapterData, sig: &Signature) {
715 let param_locals = sig
716 .params
717 .iter()
718 .enumerate()
719 .map(|(i, ty)| (i as u32, *ty))
720 .collect::<Vec<_>>();
721
722 self.set_flag(adapter.lower.flags, FLAG_MAY_LEAVE, false);
723 self.translate_results(adapter, ¶m_locals, ¶m_locals);
734 self.set_flag(adapter.lower.flags, FLAG_MAY_LEAVE, true);
735
736 self.finish()
737 }
738
739 fn compile_sync_to_sync_adapter(
746 mut self,
747 adapter: &AdapterData,
748 lower_sig: &Signature,
749 lift_sig: &Signature,
750 ) {
751 self.trap_if_not_flag(
757 adapter.lower.flags,
758 FLAG_MAY_LEAVE,
759 Trap::CannotLeaveComponent,
760 );
761
762 let old_task_may_block = if self.module.tunables.concurrency_support {
763 let task_may_block = self.module.import_task_may_block();
765 let old_task_may_block = if self.types[adapter.lift.ty].async_ {
766 self.instruction(GlobalGet(task_may_block.as_u32()));
767 self.instruction(I32Eqz);
768 self.instruction(If(BlockType::Empty));
769 self.trap(Trap::CannotBlockSyncTask);
770 self.instruction(End);
771 None
772 } else {
773 let task_may_block = self.module.import_task_may_block();
774 self.instruction(GlobalGet(task_may_block.as_u32()));
775 let old_task_may_block = self.local_set_new_tmp(ValType::I32);
776 self.instruction(I32Const(0));
777 self.instruction(GlobalSet(task_may_block.as_u32()));
778 Some(old_task_may_block)
779 };
780
781 self.instruction(I32Const(
786 i32::try_from(adapter.lower.instance.as_u32()).unwrap(),
787 ));
788 self.instruction(I32Const(if self.types[adapter.lift.ty].async_ {
789 1
790 } else {
791 0
792 }));
793 self.instruction(I32Const(
794 i32::try_from(adapter.lift.instance.as_u32()).unwrap(),
795 ));
796 let enter_sync_call = self.module.import_enter_sync_call();
797 self.instruction(Call(enter_sync_call.as_u32()));
798
799 old_task_may_block
800 } else if self.emit_resource_call {
801 let enter_sync_call = self.module.import_enter_sync_call();
802 self.instruction(Call(enter_sync_call.as_u32()));
803 None
804 } else {
805 None
806 };
807
808 self.set_flag(adapter.lift.flags, FLAG_MAY_LEAVE, false);
821 let param_locals = lower_sig
822 .params
823 .iter()
824 .enumerate()
825 .map(|(i, ty)| (i as u32, *ty))
826 .collect::<Vec<_>>();
827 self.translate_params(adapter, ¶m_locals);
828 self.set_flag(adapter.lift.flags, FLAG_MAY_LEAVE, true);
829
830 self.instruction(Call(adapter.callee.as_u32()));
834 let mut result_locals = Vec::with_capacity(lift_sig.results.len());
835 let mut temps = Vec::new();
836 for ty in lift_sig.results.iter().rev() {
837 let local = self.local_set_new_tmp(*ty);
838 result_locals.push((local.idx, *ty));
839 temps.push(local);
840 }
841 result_locals.reverse();
842
843 if self.emit_resource_call || self.module.tunables.concurrency_support {
858 let exit_sync_call = self.module.import_exit_sync_call();
859 self.instruction(Call(exit_sync_call.as_u32()));
860 }
861
862 self.set_flag(adapter.lower.flags, FLAG_MAY_LEAVE, false);
871 self.translate_results(adapter, ¶m_locals, &result_locals);
872 self.set_flag(adapter.lower.flags, FLAG_MAY_LEAVE, true);
873
874 if let Some(func) = adapter.lift.post_return {
877 for (result, _) in result_locals.iter() {
878 self.instruction(LocalGet(*result));
879 }
880 self.instruction(Call(func.as_u32()));
881 }
882
883 for tmp in temps {
884 self.free_temp_local(tmp);
885 }
886
887 if self.module.tunables.concurrency_support {
888 if let Some(old_task_may_block) = old_task_may_block {
890 let task_may_block = self.module.import_task_may_block();
891 self.instruction(LocalGet(old_task_may_block.idx));
892 self.instruction(GlobalSet(task_may_block.as_u32()));
893 self.free_temp_local(old_task_may_block);
894 }
895 }
896
897 self.finish()
898 }
899
900 fn translate_params(&mut self, adapter: &AdapterData, param_locals: &[(u32, ValType)]) {
901 let src_tys = self.types[adapter.lower.ty].params;
902 let src_tys = self.types[src_tys]
903 .types
904 .iter()
905 .copied()
906 .collect::<Vec<_>>();
907 let dst_tys = self.types[adapter.lift.ty].params;
908 let dst_tys = self.types[dst_tys]
909 .types
910 .iter()
911 .copied()
912 .collect::<Vec<_>>();
913 let lift_opts = &adapter.lift.options;
914 let lower_opts = &adapter.lower.options;
915
916 assert_eq!(src_tys.len(), dst_tys.len());
918
919 let max_flat_params = if adapter.lower.options.async_ {
923 MAX_FLAT_ASYNC_PARAMS
924 } else {
925 MAX_FLAT_PARAMS
926 };
927 let src_flat =
928 self.types
929 .flatten_types(lower_opts, max_flat_params, src_tys.iter().copied());
930 let dst_flat =
931 self.types
932 .flatten_types(lift_opts, MAX_FLAT_PARAMS, dst_tys.iter().copied());
933
934 let src = if let Some(flat) = &src_flat {
935 Source::Stack(Stack {
936 locals: ¶m_locals[..flat.len()],
937 opts: lower_opts,
938 })
939 } else {
940 let lower_mem_opts = lower_opts.data_model.unwrap_memory();
944 let (addr, ty) = param_locals[0];
945 assert_eq!(ty, lower_mem_opts.ptr());
946 let align = src_tys
947 .iter()
948 .map(|t| self.types.align(lower_mem_opts, t))
949 .max()
950 .unwrap_or(1);
951 Source::Memory(self.memory_operand(lower_opts, TempLocal::new(addr, ty), align))
952 };
953
954 let dst = if let Some(flat) = &dst_flat {
955 Destination::Stack(flat, lift_opts)
956 } else {
957 let abi = CanonicalAbiInfo::record(dst_tys.iter().map(|t| self.types.canonical_abi(t)));
958 match lift_opts.data_model {
959 DataModel::Gc {} => todo!("CM+GC"),
960 DataModel::LinearMemory(LinearMemoryOptions { memory64, .. }) => {
961 let (size, align) = if memory64 {
962 (abi.size64, abi.align64)
963 } else {
964 (abi.size32, abi.align32)
965 };
966
967 let size = MallocSize::Const(size);
970 Destination::Memory(self.malloc(lift_opts, size, align))
971 }
972 }
973 };
974
975 let srcs = src
976 .record_field_srcs(self.types, src_tys.iter().copied())
977 .zip(src_tys.iter());
978 let dsts = dst
979 .record_field_dsts(self.types, dst_tys.iter().copied())
980 .zip(dst_tys.iter());
981 for ((src, src_ty), (dst, dst_ty)) in srcs.zip(dsts) {
982 self.translate(&src_ty, &src, &dst_ty, &dst);
983 }
984
985 if let Destination::Memory(mem) = dst {
989 self.instruction(LocalGet(mem.addr.idx));
990 self.free_temp_local(mem.addr);
991 }
992 }
993
994 fn translate_results(
995 &mut self,
996 adapter: &AdapterData,
997 param_locals: &[(u32, ValType)],
998 result_locals: &[(u32, ValType)],
999 ) {
1000 let src_tys = self.types[adapter.lift.ty].results;
1001 let src_tys = self.types[src_tys]
1002 .types
1003 .iter()
1004 .copied()
1005 .collect::<Vec<_>>();
1006 let dst_tys = self.types[adapter.lower.ty].results;
1007 let dst_tys = self.types[dst_tys]
1008 .types
1009 .iter()
1010 .copied()
1011 .collect::<Vec<_>>();
1012 let lift_opts = &adapter.lift.options;
1013 let lower_opts = &adapter.lower.options;
1014
1015 let src_flat = self
1016 .types
1017 .flatten_lifting_types(lift_opts, src_tys.iter().copied());
1018 let dst_flat = self
1019 .types
1020 .flatten_lowering_types(lower_opts, dst_tys.iter().copied());
1021
1022 let src = if src_flat.is_some() {
1023 Source::Stack(Stack {
1024 locals: result_locals,
1025 opts: lift_opts,
1026 })
1027 } else {
1028 let lift_mem_opts = lift_opts.data_model.unwrap_memory();
1033 let align = src_tys
1034 .iter()
1035 .map(|t| self.types.align(lift_mem_opts, t))
1036 .max()
1037 .unwrap_or(1);
1038 assert_eq!(
1039 result_locals.len(),
1040 if lower_opts.async_ || lift_opts.async_ {
1041 2
1042 } else {
1043 1
1044 }
1045 );
1046 let (addr, ty) = result_locals[0];
1047 assert_eq!(ty, lift_opts.data_model.unwrap_memory().ptr());
1048 Source::Memory(self.memory_operand(lift_opts, TempLocal::new(addr, ty), align))
1049 };
1050
1051 let dst = if let Some(flat) = &dst_flat {
1052 Destination::Stack(flat, lower_opts)
1053 } else {
1054 let lower_mem_opts = lower_opts.data_model.unwrap_memory();
1058 let align = dst_tys
1059 .iter()
1060 .map(|t| self.types.align(lower_mem_opts, t))
1061 .max()
1062 .unwrap_or(1);
1063 let (addr, ty) = *param_locals.last().expect("no retptr");
1064 assert_eq!(ty, lower_opts.data_model.unwrap_memory().ptr());
1065 Destination::Memory(self.memory_operand(lower_opts, TempLocal::new(addr, ty), align))
1066 };
1067
1068 let srcs = src
1069 .record_field_srcs(self.types, src_tys.iter().copied())
1070 .zip(src_tys.iter());
1071 let dsts = dst
1072 .record_field_dsts(self.types, dst_tys.iter().copied())
1073 .zip(dst_tys.iter());
1074 for ((src, src_ty), (dst, dst_ty)) in srcs.zip(dsts) {
1075 self.translate(&src_ty, &src, &dst_ty, &dst);
1076 }
1077 }
1078
1079 fn translate(
1080 &mut self,
1081 src_ty: &InterfaceType,
1082 src: &Source<'_>,
1083 dst_ty: &InterfaceType,
1084 dst: &Destination,
1085 ) {
1086 if let Source::Memory(mem) = src {
1087 self.assert_aligned(src_ty, mem);
1088 }
1089 if let Destination::Memory(mem) = dst {
1090 self.assert_aligned(dst_ty, mem);
1091 }
1092
1093 let cost = match src_ty {
1123 InterfaceType::Bool
1127 | InterfaceType::U8
1128 | InterfaceType::S8
1129 | InterfaceType::U16
1130 | InterfaceType::S16
1131 | InterfaceType::U32
1132 | InterfaceType::S32
1133 | InterfaceType::U64
1134 | InterfaceType::S64
1135 | InterfaceType::Float32
1136 | InterfaceType::Float64 => 0,
1137
1138 InterfaceType::Char => 1,
1141
1142 InterfaceType::String => 40,
1145
1146 InterfaceType::List(_) => 40,
1149 InterfaceType::Map(_) => 40,
1151
1152 InterfaceType::Flags(i) => {
1153 let count = self.module.types[*i].names.len();
1154 match FlagsSize::from_count(count) {
1155 FlagsSize::Size0 => 0,
1156 FlagsSize::Size1 | FlagsSize::Size2 => 1,
1157 FlagsSize::Size4Plus(n) => n.into(),
1158 }
1159 }
1160
1161 InterfaceType::Record(i) => self.types[*i].fields.len(),
1162 InterfaceType::Tuple(i) => self.types[*i].types.len(),
1163 InterfaceType::Variant(i) => self.types[*i].cases.len(),
1164 InterfaceType::Enum(i) => self.types[*i].names.len(),
1165
1166 InterfaceType::Option(_) | InterfaceType::Result(_) => 2,
1168
1169 InterfaceType::Own(_)
1171 | InterfaceType::Borrow(_)
1172 | InterfaceType::Future(_)
1173 | InterfaceType::Stream(_)
1174 | InterfaceType::ErrorContext(_) => 1,
1175 InterfaceType::FixedLengthList(i) => self.types[*i].size as usize,
1176 };
1177
1178 match self.fuel.checked_sub(cost) {
1179 Some(n) => {
1185 self.fuel = n;
1186 match src_ty {
1187 InterfaceType::Bool => self.translate_bool(src, dst_ty, dst),
1188 InterfaceType::U8 => self.translate_u8(src, dst_ty, dst),
1189 InterfaceType::S8 => self.translate_s8(src, dst_ty, dst),
1190 InterfaceType::U16 => self.translate_u16(src, dst_ty, dst),
1191 InterfaceType::S16 => self.translate_s16(src, dst_ty, dst),
1192 InterfaceType::U32 => self.translate_u32(src, dst_ty, dst),
1193 InterfaceType::S32 => self.translate_s32(src, dst_ty, dst),
1194 InterfaceType::U64 => self.translate_u64(src, dst_ty, dst),
1195 InterfaceType::S64 => self.translate_s64(src, dst_ty, dst),
1196 InterfaceType::Float32 => self.translate_f32(src, dst_ty, dst),
1197 InterfaceType::Float64 => self.translate_f64(src, dst_ty, dst),
1198 InterfaceType::Char => self.translate_char(src, dst_ty, dst),
1199 InterfaceType::String => self.translate_string(src, dst_ty, dst),
1200 InterfaceType::List(t) => self.translate_list(*t, src, dst_ty, dst),
1201 InterfaceType::Map(t) => self.translate_map(*t, src, dst_ty, dst),
1202 InterfaceType::Record(t) => self.translate_record(*t, src, dst_ty, dst),
1203 InterfaceType::Flags(f) => self.translate_flags(*f, src, dst_ty, dst),
1204 InterfaceType::Tuple(t) => self.translate_tuple(*t, src, dst_ty, dst),
1205 InterfaceType::Variant(v) => self.translate_variant(*v, src, dst_ty, dst),
1206 InterfaceType::Enum(t) => self.translate_enum(*t, src, dst_ty, dst),
1207 InterfaceType::Option(t) => self.translate_option(*t, src, dst_ty, dst),
1208 InterfaceType::Result(t) => self.translate_result(*t, src, dst_ty, dst),
1209 InterfaceType::Own(t) => self.translate_own(*t, src, dst_ty, dst),
1210 InterfaceType::Borrow(t) => self.translate_borrow(*t, src, dst_ty, dst),
1211 InterfaceType::Future(t) => self.translate_future(*t, src, dst_ty, dst),
1212 InterfaceType::Stream(t) => self.translate_stream(*t, src, dst_ty, dst),
1213 InterfaceType::ErrorContext(t) => {
1214 self.translate_error_context(*t, src, dst_ty, dst)
1215 }
1216 InterfaceType::FixedLengthList(t) => {
1217 self.translate_fixed_length_list(*t, src, dst_ty, dst);
1218 }
1219 }
1220 }
1221
1222 None => {
1228 let src_loc = match src {
1229 Source::Stack(stack) => {
1233 for (i, ty) in stack
1234 .opts
1235 .flat_types(src_ty, self.types)
1236 .unwrap()
1237 .iter()
1238 .enumerate()
1239 {
1240 let stack = stack.slice(i..i + 1);
1241 self.stack_get(&stack, (*ty).into());
1242 }
1243 HelperLocation::Stack
1244 }
1245 Source::Memory(mem) => {
1250 self.push_mem_addr(mem);
1251 HelperLocation::Memory
1252 }
1253 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1254 };
1255 let dst_loc = match dst {
1256 Destination::Stack(..) => HelperLocation::Stack,
1257 Destination::Memory(mem) => {
1258 self.push_mem_addr(mem);
1259 HelperLocation::Memory
1260 }
1261 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1262 };
1263 let helper = self.module.translate_helper(Helper {
1269 src: HelperType {
1270 ty: *src_ty,
1271 opts: *src.opts(),
1272 loc: src_loc,
1273 },
1274 dst: HelperType {
1275 ty: *dst_ty,
1276 opts: *dst.opts(),
1277 loc: dst_loc,
1278 },
1279 });
1280 self.flush_code();
1283 self.module.funcs[self.result].body.push(Body::Call(helper));
1284
1285 if let Destination::Stack(tys, opts) = dst {
1294 let flat = self
1295 .types
1296 .flatten_types(opts, usize::MAX, [*dst_ty])
1297 .unwrap();
1298 assert_eq!(flat.len(), tys.len());
1299 let locals = flat
1300 .iter()
1301 .rev()
1302 .map(|ty| self.local_set_new_tmp(*ty))
1303 .collect::<Vec<_>>();
1304 for (ty, local) in tys.iter().zip(locals.into_iter().rev()) {
1305 self.instruction(LocalGet(local.idx));
1306 self.stack_set(std::slice::from_ref(ty), local.ty);
1307 self.free_temp_local(local);
1308 }
1309 }
1310 }
1311 }
1312 }
1313
1314 fn push_mem_addr(&mut self, mem: &Memory<'_>) {
1315 self.instruction(LocalGet(mem.addr.idx));
1316 if mem.offset != 0 {
1317 self.ptr_uconst(mem.mem_opts(), mem.offset);
1318 self.ptr_add(mem.mem_opts());
1319 }
1320 }
1321
1322 fn translate_bool(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1323 assert!(matches!(dst_ty, InterfaceType::Bool));
1325 self.push_dst_addr(dst);
1326
1327 self.instruction(I32Const(1));
1330 self.instruction(I32Const(0));
1331 match src {
1332 Source::Memory(mem) => self.i32_load8u(mem),
1333 Source::Stack(stack) => self.stack_get(stack, ValType::I32),
1334 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1335 }
1336 self.instruction(Select);
1337
1338 match dst {
1339 Destination::Memory(mem) => self.i32_store8(mem),
1340 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1341 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1342 }
1343 }
1344
1345 fn translate_u8(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1346 assert!(matches!(dst_ty, InterfaceType::U8));
1348 self.convert_u8_mask(src, dst, 0xff);
1349 }
1350
1351 fn convert_u8_mask(&mut self, src: &Source<'_>, dst: &Destination<'_>, mask: u8) {
1352 self.push_dst_addr(dst);
1353 let mut needs_mask = true;
1354 match src {
1355 Source::Memory(mem) => {
1356 self.i32_load8u(mem);
1357 needs_mask = mask != 0xff;
1358 }
1359 Source::Stack(stack) => {
1360 self.stack_get(stack, ValType::I32);
1361 }
1362 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1363 }
1364 if needs_mask {
1365 self.instruction(I32Const(i32::from(mask)));
1366 self.instruction(I32And);
1367 }
1368 match dst {
1369 Destination::Memory(mem) => self.i32_store8(mem),
1370 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1371 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1372 }
1373 }
1374
1375 fn translate_s8(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1376 assert!(matches!(dst_ty, InterfaceType::S8));
1378 self.push_dst_addr(dst);
1379 match src {
1380 Source::Memory(mem) => self.i32_load8s(mem),
1381 Source::Stack(stack) => {
1382 self.stack_get(stack, ValType::I32);
1383 self.instruction(I32Extend8S);
1384 }
1385 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1386 }
1387 match dst {
1388 Destination::Memory(mem) => self.i32_store8(mem),
1389 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1390 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1391 }
1392 }
1393
1394 fn translate_u16(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1395 assert!(matches!(dst_ty, InterfaceType::U16));
1397 self.convert_u16_mask(src, dst, 0xffff);
1398 }
1399
1400 fn convert_u16_mask(&mut self, src: &Source<'_>, dst: &Destination<'_>, mask: u16) {
1401 self.push_dst_addr(dst);
1402 let mut needs_mask = true;
1403 match src {
1404 Source::Memory(mem) => {
1405 self.i32_load16u(mem);
1406 needs_mask = mask != 0xffff;
1407 }
1408 Source::Stack(stack) => {
1409 self.stack_get(stack, ValType::I32);
1410 }
1411 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1412 }
1413 if needs_mask {
1414 self.instruction(I32Const(i32::from(mask)));
1415 self.instruction(I32And);
1416 }
1417 match dst {
1418 Destination::Memory(mem) => self.i32_store16(mem),
1419 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1420 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1421 }
1422 }
1423
1424 fn translate_s16(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1425 assert!(matches!(dst_ty, InterfaceType::S16));
1427 self.push_dst_addr(dst);
1428 match src {
1429 Source::Memory(mem) => self.i32_load16s(mem),
1430 Source::Stack(stack) => {
1431 self.stack_get(stack, ValType::I32);
1432 self.instruction(I32Extend16S);
1433 }
1434 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1435 }
1436 match dst {
1437 Destination::Memory(mem) => self.i32_store16(mem),
1438 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1439 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1440 }
1441 }
1442
1443 fn translate_u32(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1444 assert!(matches!(dst_ty, InterfaceType::U32));
1446 self.convert_u32_mask(src, dst, 0xffffffff)
1447 }
1448
1449 fn convert_u32_mask(&mut self, src: &Source<'_>, dst: &Destination<'_>, mask: u32) {
1450 self.push_dst_addr(dst);
1451 match src {
1452 Source::Memory(mem) => self.i32_load(mem),
1453 Source::Stack(stack) => self.stack_get(stack, ValType::I32),
1454 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1455 }
1456 if mask != 0xffffffff {
1457 self.instruction(I32Const(mask as i32));
1458 self.instruction(I32And);
1459 }
1460 match dst {
1461 Destination::Memory(mem) => self.i32_store(mem),
1462 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1463 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1464 }
1465 }
1466
1467 fn translate_s32(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1468 assert!(matches!(dst_ty, InterfaceType::S32));
1470 self.push_dst_addr(dst);
1471 match src {
1472 Source::Memory(mem) => self.i32_load(mem),
1473 Source::Stack(stack) => self.stack_get(stack, ValType::I32),
1474 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1475 }
1476 match dst {
1477 Destination::Memory(mem) => self.i32_store(mem),
1478 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1479 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1480 }
1481 }
1482
1483 fn translate_u64(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1484 assert!(matches!(dst_ty, InterfaceType::U64));
1486 self.push_dst_addr(dst);
1487 match src {
1488 Source::Memory(mem) => self.i64_load(mem),
1489 Source::Stack(stack) => self.stack_get(stack, ValType::I64),
1490 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1491 }
1492 match dst {
1493 Destination::Memory(mem) => self.i64_store(mem),
1494 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I64),
1495 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1496 }
1497 }
1498
1499 fn translate_s64(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1500 assert!(matches!(dst_ty, InterfaceType::S64));
1502 self.push_dst_addr(dst);
1503 match src {
1504 Source::Memory(mem) => self.i64_load(mem),
1505 Source::Stack(stack) => self.stack_get(stack, ValType::I64),
1506 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1507 }
1508 match dst {
1509 Destination::Memory(mem) => self.i64_store(mem),
1510 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I64),
1511 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1512 }
1513 }
1514
1515 fn translate_f32(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1516 assert!(matches!(dst_ty, InterfaceType::Float32));
1518 self.push_dst_addr(dst);
1519 match src {
1520 Source::Memory(mem) => self.f32_load(mem),
1521 Source::Stack(stack) => self.stack_get(stack, ValType::F32),
1522 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1523 }
1524 match dst {
1525 Destination::Memory(mem) => self.f32_store(mem),
1526 Destination::Stack(stack, _) => self.stack_set(stack, ValType::F32),
1527 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1528 }
1529 }
1530
1531 fn translate_f64(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1532 assert!(matches!(dst_ty, InterfaceType::Float64));
1534 self.push_dst_addr(dst);
1535 match src {
1536 Source::Memory(mem) => self.f64_load(mem),
1537 Source::Stack(stack) => self.stack_get(stack, ValType::F64),
1538 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1539 }
1540 match dst {
1541 Destination::Memory(mem) => self.f64_store(mem),
1542 Destination::Stack(stack, _) => self.stack_set(stack, ValType::F64),
1543 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1544 }
1545 }
1546
1547 fn translate_char(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1548 assert!(matches!(dst_ty, InterfaceType::Char));
1549 match src {
1550 Source::Memory(mem) => self.i32_load(mem),
1551 Source::Stack(stack) => self.stack_get(stack, ValType::I32),
1552 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1553 }
1554 let local = self.local_set_new_tmp(ValType::I32);
1555
1556 self.instruction(Block(BlockType::Empty));
1572 self.instruction(Block(BlockType::Empty));
1573 self.instruction(LocalGet(local.idx));
1574 self.instruction(I32Const(0xd800));
1575 self.instruction(I32Xor);
1576 self.instruction(I32Const(-0x110000));
1577 self.instruction(I32Add);
1578 self.instruction(I32Const(-0x10f800));
1579 self.instruction(I32LtU);
1580 self.instruction(BrIf(0));
1581 self.instruction(LocalGet(local.idx));
1582 self.instruction(I32Const(0x110000));
1583 self.instruction(I32Ne);
1584 self.instruction(BrIf(1));
1585 self.instruction(End);
1586 self.trap(Trap::InvalidChar);
1587 self.instruction(End);
1588
1589 self.push_dst_addr(dst);
1590 self.instruction(LocalGet(local.idx));
1591 match dst {
1592 Destination::Memory(mem) => {
1593 self.i32_store(mem);
1594 }
1595 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1596 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1597 }
1598
1599 self.free_temp_local(local);
1600 }
1601
1602 fn translate_string(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1603 assert!(matches!(dst_ty, InterfaceType::String));
1604 let src_opts = src.opts();
1605 let dst_opts = dst.opts();
1606
1607 let src_mem_opts = match &src_opts.data_model {
1608 DataModel::Gc {} => todo!("CM+GC"),
1609 DataModel::LinearMemory(opts) => opts,
1610 };
1611 let dst_mem_opts = match &dst_opts.data_model {
1612 DataModel::Gc {} => todo!("CM+GC"),
1613 DataModel::LinearMemory(opts) => opts,
1614 };
1615
1616 match src {
1621 Source::Stack(s) => {
1622 assert_eq!(s.locals.len(), 2);
1623 self.stack_get(&s.slice(0..1), src_mem_opts.ptr());
1624 self.stack_get(&s.slice(1..2), src_mem_opts.ptr());
1625 }
1626 Source::Memory(mem) => {
1627 self.ptr_load(mem);
1628 self.ptr_load(&mem.bump(src_mem_opts.ptr_size().into()));
1629 }
1630 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1631 }
1632 let src_len = self.local_set_new_tmp(src_mem_opts.ptr());
1633 let src_ptr = self.local_set_new_tmp(src_mem_opts.ptr());
1634 let src_str = WasmString {
1635 ptr: src_ptr,
1636 len: src_len,
1637 opts: src_opts,
1638 };
1639
1640 let dst_str = match src_opts.string_encoding {
1641 StringEncoding::Utf8 => match dst_opts.string_encoding {
1642 StringEncoding::Utf8 => self.string_copy(&src_str, FE::Utf8, dst_opts, FE::Utf8),
1643 StringEncoding::Utf16 => self.string_utf8_to_utf16(&src_str, dst_opts),
1644 StringEncoding::CompactUtf16 => {
1645 self.string_to_compact(&src_str, FE::Utf8, dst_opts)
1646 }
1647 },
1648
1649 StringEncoding::Utf16 => {
1650 self.verify_aligned(src_mem_opts, src_str.ptr.idx, 2);
1651 match dst_opts.string_encoding {
1652 StringEncoding::Utf8 => {
1653 self.string_deflate_to_utf8(&src_str, FE::Utf16, dst_opts)
1654 }
1655 StringEncoding::Utf16 => {
1656 self.string_copy(&src_str, FE::Utf16, dst_opts, FE::Utf16)
1657 }
1658 StringEncoding::CompactUtf16 => {
1659 self.string_to_compact(&src_str, FE::Utf16, dst_opts)
1660 }
1661 }
1662 }
1663
1664 StringEncoding::CompactUtf16 => {
1665 self.verify_aligned(src_mem_opts, src_str.ptr.idx, 2);
1666
1667 self.instruction(LocalGet(src_str.len.idx));
1670 self.ptr_uconst(src_mem_opts, UTF16_TAG);
1671 self.ptr_and(src_mem_opts);
1672 self.ptr_if(src_mem_opts, BlockType::Empty);
1673
1674 self.instruction(LocalGet(src_str.len.idx));
1678 self.ptr_uconst(src_mem_opts, UTF16_TAG);
1679 self.ptr_xor(src_mem_opts);
1680 self.instruction(LocalSet(src_str.len.idx));
1681 let s1 = match dst_opts.string_encoding {
1682 StringEncoding::Utf8 => {
1683 self.string_deflate_to_utf8(&src_str, FE::Utf16, dst_opts)
1684 }
1685 StringEncoding::Utf16 => {
1686 self.string_copy(&src_str, FE::Utf16, dst_opts, FE::Utf16)
1687 }
1688 StringEncoding::CompactUtf16 => {
1689 self.string_compact_utf16_to_compact(&src_str, dst_opts)
1690 }
1691 };
1692
1693 self.instruction(Else);
1694
1695 let s2 = match dst_opts.string_encoding {
1699 StringEncoding::Utf16 => {
1700 self.string_copy(&src_str, FE::Latin1, dst_opts, FE::Utf16)
1701 }
1702 StringEncoding::Utf8 => {
1703 self.string_deflate_to_utf8(&src_str, FE::Latin1, dst_opts)
1704 }
1705 StringEncoding::CompactUtf16 => {
1706 self.string_copy(&src_str, FE::Latin1, dst_opts, FE::Latin1)
1707 }
1708 };
1709 self.instruction(LocalGet(s2.ptr.idx));
1712 self.instruction(LocalSet(s1.ptr.idx));
1713 self.instruction(LocalGet(s2.len.idx));
1714 self.instruction(LocalSet(s1.len.idx));
1715 self.instruction(End);
1716 self.free_temp_local(s2.ptr);
1717 self.free_temp_local(s2.len);
1718 s1
1719 }
1720 };
1721
1722 match dst {
1724 Destination::Stack(s, _) => {
1725 self.instruction(LocalGet(dst_str.ptr.idx));
1726 self.stack_set(&s[..1], dst_mem_opts.ptr());
1727 self.instruction(LocalGet(dst_str.len.idx));
1728 self.stack_set(&s[1..], dst_mem_opts.ptr());
1729 }
1730 Destination::Memory(mem) => {
1731 self.instruction(LocalGet(mem.addr.idx));
1732 self.instruction(LocalGet(dst_str.ptr.idx));
1733 self.ptr_store(mem);
1734 self.instruction(LocalGet(mem.addr.idx));
1735 self.instruction(LocalGet(dst_str.len.idx));
1736 self.ptr_store(&mem.bump(dst_mem_opts.ptr_size().into()));
1737 }
1738 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1739 }
1740
1741 self.free_temp_local(src_str.ptr);
1742 self.free_temp_local(src_str.len);
1743 self.free_temp_local(dst_str.ptr);
1744 self.free_temp_local(dst_str.len);
1745 }
1746
1747 fn string_copy<'c>(
1760 &mut self,
1761 src: &WasmString<'_>,
1762 src_enc: FE,
1763 dst_opts: &'c Options,
1764 dst_enc: FE,
1765 ) -> WasmString<'c> {
1766 assert!(dst_enc.width() >= src_enc.width());
1767 self.validate_string_length(src, dst_enc);
1768
1769 let src_mem_opts = {
1770 match &src.opts.data_model {
1771 DataModel::Gc {} => todo!("CM+GC"),
1772 DataModel::LinearMemory(opts) => opts,
1773 }
1774 };
1775 let dst_mem_opts = {
1776 match &dst_opts.data_model {
1777 DataModel::Gc {} => todo!("CM+GC"),
1778 DataModel::LinearMemory(opts) => opts,
1779 }
1780 };
1781
1782 let mut src_byte_len_tmp = None;
1786 let src_byte_len = if src_enc.width() == 1 {
1787 src.len.idx
1788 } else {
1789 assert_eq!(src_enc.width(), 2);
1790 self.instruction(LocalGet(src.len.idx));
1791 self.ptr_uconst(src_mem_opts, 1);
1792 self.ptr_shl(src_mem_opts);
1793 let tmp = self.local_set_new_tmp(src.opts.data_model.unwrap_memory().ptr());
1794 let ret = tmp.idx;
1795 src_byte_len_tmp = Some(tmp);
1796 ret
1797 };
1798
1799 self.convert_src_len_to_dst(
1802 src.len.idx,
1803 src.opts.data_model.unwrap_memory().ptr(),
1804 dst_opts.data_model.unwrap_memory().ptr(),
1805 );
1806 let dst_len = self.local_tee_new_tmp(dst_opts.data_model.unwrap_memory().ptr());
1807 if dst_enc.width() > 1 {
1808 assert_eq!(dst_enc.width(), 2);
1809 self.ptr_uconst(dst_mem_opts, 1);
1810 self.ptr_shl(dst_mem_opts);
1811 }
1812 let dst_byte_len = self.local_set_new_tmp(dst_opts.data_model.unwrap_memory().ptr());
1813
1814 let dst = {
1817 let dst_mem = self.malloc(
1818 dst_opts,
1819 MallocSize::Local(dst_byte_len.idx),
1820 dst_enc.width().into(),
1821 );
1822 WasmString {
1823 ptr: dst_mem.addr,
1824 len: dst_len,
1825 opts: dst_opts,
1826 }
1827 };
1828
1829 self.validate_string_inbounds(src, src_byte_len);
1834 self.validate_string_inbounds(&dst, dst_byte_len.idx);
1835
1836 let op = if src_enc == dst_enc {
1840 Transcode::Copy(src_enc)
1841 } else {
1842 assert_eq!(src_enc, FE::Latin1);
1843 assert_eq!(dst_enc, FE::Utf16);
1844 Transcode::Latin1ToUtf16
1845 };
1846 let transcode = self.transcoder(src, &dst, op);
1847 self.instruction(LocalGet(src.ptr.idx));
1848 self.instruction(LocalGet(src.len.idx));
1849 self.instruction(LocalGet(dst.ptr.idx));
1850 self.instruction(Call(transcode.as_u32()));
1851
1852 self.free_temp_local(dst_byte_len);
1853 if let Some(tmp) = src_byte_len_tmp {
1854 self.free_temp_local(tmp);
1855 }
1856
1857 dst
1858 }
1859 fn string_deflate_to_utf8<'c>(
1872 &mut self,
1873 src: &WasmString<'_>,
1874 src_enc: FE,
1875 dst_opts: &'c Options,
1876 ) -> WasmString<'c> {
1877 let src_mem_opts = match &src.opts.data_model {
1878 DataModel::Gc {} => todo!("CM+GC"),
1879 DataModel::LinearMemory(opts) => opts,
1880 };
1881 let dst_mem_opts = match &dst_opts.data_model {
1882 DataModel::Gc {} => todo!("CM+GC"),
1883 DataModel::LinearMemory(opts) => opts,
1884 };
1885
1886 self.validate_string_length(src, src_enc);
1887
1888 self.convert_src_len_to_dst(
1892 src.len.idx,
1893 src.opts.data_model.unwrap_memory().ptr(),
1894 dst_opts.data_model.unwrap_memory().ptr(),
1895 );
1896 let dst_len = self.local_tee_new_tmp(dst_opts.data_model.unwrap_memory().ptr());
1897 let dst_byte_len = self.local_set_new_tmp(dst_opts.data_model.unwrap_memory().ptr());
1898
1899 let dst = {
1900 let dst_mem = self.malloc(dst_opts, MallocSize::Local(dst_byte_len.idx), 1);
1901 WasmString {
1902 ptr: dst_mem.addr,
1903 len: dst_len,
1904 opts: dst_opts,
1905 }
1906 };
1907
1908 let mut src_byte_len_tmp = None;
1910 let src_byte_len = match src_enc {
1911 FE::Latin1 => src.len.idx,
1912 FE::Utf16 => {
1913 self.instruction(LocalGet(src.len.idx));
1914 self.ptr_uconst(src_mem_opts, 1);
1915 self.ptr_shl(src_mem_opts);
1916 let tmp = self.local_set_new_tmp(src.opts.data_model.unwrap_memory().ptr());
1917 let ret = tmp.idx;
1918 src_byte_len_tmp = Some(tmp);
1919 ret
1920 }
1921 FE::Utf8 => unreachable!(),
1922 };
1923 self.validate_string_inbounds(src, src_byte_len);
1924 self.validate_string_inbounds(&dst, dst_byte_len.idx);
1925
1926 let op = match src_enc {
1928 FE::Latin1 => Transcode::Latin1ToUtf8,
1929 FE::Utf16 => Transcode::Utf16ToUtf8,
1930 FE::Utf8 => unreachable!(),
1931 };
1932 let transcode = self.transcoder(src, &dst, op);
1933 self.instruction(LocalGet(src.ptr.idx));
1934 self.instruction(LocalGet(src.len.idx));
1935 self.instruction(LocalGet(dst.ptr.idx));
1936 self.instruction(LocalGet(dst_byte_len.idx));
1937 self.instruction(Call(transcode.as_u32()));
1938 self.instruction(LocalSet(dst.len.idx));
1939 let src_len_tmp = self.local_set_new_tmp(src.opts.data_model.unwrap_memory().ptr());
1940
1941 self.instruction(LocalGet(src_len_tmp.idx));
1945 self.instruction(LocalGet(src.len.idx));
1946 self.ptr_ne(src_mem_opts);
1947 self.instruction(If(BlockType::Empty));
1948
1949 self.instruction(LocalGet(dst.ptr.idx)); self.instruction(LocalGet(dst_byte_len.idx)); self.ptr_uconst(dst_mem_opts, 1); let factor = match src_enc {
1956 FE::Latin1 => 2,
1957 FE::Utf16 => 3,
1958 _ => unreachable!(),
1959 };
1960 self.validate_string_length_u8(src, factor);
1961 self.convert_src_len_to_dst(
1962 src.len.idx,
1963 src.opts.data_model.unwrap_memory().ptr(),
1964 dst_opts.data_model.unwrap_memory().ptr(),
1965 );
1966 self.ptr_uconst(dst_mem_opts, factor.into());
1967 self.ptr_mul(dst_mem_opts);
1968 self.instruction(LocalTee(dst_byte_len.idx));
1969 self.instruction(Call(dst_mem_opts.realloc.unwrap().as_u32()));
1970 self.instruction(LocalSet(dst.ptr.idx));
1971
1972 self.validate_string_inbounds(&dst, dst_byte_len.idx);
1974
1975 self.instruction(LocalGet(src.ptr.idx));
1980 self.instruction(LocalGet(src_len_tmp.idx));
1981 if let FE::Utf16 = src_enc {
1982 self.ptr_uconst(src_mem_opts, 1);
1983 self.ptr_shl(src_mem_opts);
1984 }
1985 self.ptr_add(src_mem_opts);
1986 self.instruction(LocalGet(src.len.idx));
1987 self.instruction(LocalGet(src_len_tmp.idx));
1988 self.ptr_sub(src_mem_opts);
1989 self.instruction(LocalGet(dst.ptr.idx));
1990 self.instruction(LocalGet(dst.len.idx));
1991 self.ptr_add(dst_mem_opts);
1992 self.instruction(LocalGet(dst_byte_len.idx));
1993 self.instruction(LocalGet(dst.len.idx));
1994 self.ptr_sub(dst_mem_opts);
1995 self.instruction(Call(transcode.as_u32()));
1996
1997 self.instruction(LocalGet(dst.len.idx));
2001 self.ptr_add(dst_mem_opts);
2002 self.instruction(LocalSet(dst.len.idx));
2003
2004 if self.module.tunables.debug_adapter_modules {
2007 self.instruction(LocalGet(src.len.idx));
2008 self.instruction(LocalGet(src_len_tmp.idx));
2009 self.ptr_sub(src_mem_opts);
2010 self.ptr_ne(src_mem_opts);
2011 self.instruction(If(BlockType::Empty));
2012 self.trap(Trap::DebugAssertStringEncodingFinished);
2013 self.instruction(End);
2014 } else {
2015 self.instruction(Drop);
2016 }
2017
2018 self.instruction(LocalGet(dst.len.idx));
2020 self.instruction(LocalGet(dst_byte_len.idx));
2021 self.ptr_ne(dst_mem_opts);
2022 self.instruction(If(BlockType::Empty));
2023 self.instruction(LocalGet(dst.ptr.idx)); self.instruction(LocalGet(dst_byte_len.idx)); self.ptr_uconst(dst_mem_opts, 1); self.instruction(LocalGet(dst.len.idx)); self.instruction(Call(dst_mem_opts.realloc.unwrap().as_u32()));
2028 self.instruction(LocalSet(dst.ptr.idx));
2029 self.instruction(End);
2030
2031 if self.module.tunables.debug_adapter_modules {
2034 self.instruction(Else);
2035
2036 self.instruction(LocalGet(dst.len.idx));
2037 self.instruction(LocalGet(dst_byte_len.idx));
2038 self.ptr_ne(dst_mem_opts);
2039 self.instruction(If(BlockType::Empty));
2040 self.trap(Trap::DebugAssertStringEncodingFinished);
2041 self.instruction(End);
2042 }
2043
2044 self.instruction(End); self.free_temp_local(src_len_tmp);
2047 self.free_temp_local(dst_byte_len);
2048 if let Some(tmp) = src_byte_len_tmp {
2049 self.free_temp_local(tmp);
2050 }
2051
2052 dst
2053 }
2054
2055 fn string_utf8_to_utf16<'c>(
2070 &mut self,
2071 src: &WasmString<'_>,
2072 dst_opts: &'c Options,
2073 ) -> WasmString<'c> {
2074 let src_mem_opts = match &src.opts.data_model {
2075 DataModel::Gc {} => todo!("CM+GC"),
2076 DataModel::LinearMemory(opts) => opts,
2077 };
2078 let dst_mem_opts = match &dst_opts.data_model {
2079 DataModel::Gc {} => todo!("CM+GC"),
2080 DataModel::LinearMemory(opts) => opts,
2081 };
2082
2083 self.validate_string_length(src, FE::Utf16);
2084 self.convert_src_len_to_dst(
2085 src.len.idx,
2086 src_mem_opts.ptr(),
2087 dst_opts.data_model.unwrap_memory().ptr(),
2088 );
2089 let dst_len = self.local_tee_new_tmp(dst_opts.data_model.unwrap_memory().ptr());
2090 self.ptr_uconst(dst_mem_opts, 1);
2091 self.ptr_shl(dst_mem_opts);
2092 let dst_byte_len = self.local_set_new_tmp(dst_opts.data_model.unwrap_memory().ptr());
2093 let dst = {
2094 let dst_mem = self.malloc(dst_opts, MallocSize::Local(dst_byte_len.idx), 2);
2095 WasmString {
2096 ptr: dst_mem.addr,
2097 len: dst_len,
2098 opts: dst_opts,
2099 }
2100 };
2101
2102 self.validate_string_inbounds(src, src.len.idx);
2103 self.validate_string_inbounds(&dst, dst_byte_len.idx);
2104
2105 let transcode = self.transcoder(src, &dst, Transcode::Utf8ToUtf16);
2106 self.instruction(LocalGet(src.ptr.idx));
2107 self.instruction(LocalGet(src.len.idx));
2108 self.instruction(LocalGet(dst.ptr.idx));
2109 self.instruction(Call(transcode.as_u32()));
2110 self.instruction(LocalSet(dst.len.idx));
2111
2112 self.convert_src_len_to_dst(src.len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2120 self.instruction(LocalGet(dst.len.idx));
2121 self.ptr_ne(dst_mem_opts);
2122 self.instruction(If(BlockType::Empty));
2123 self.instruction(LocalGet(dst.ptr.idx));
2124 self.instruction(LocalGet(dst_byte_len.idx));
2125 self.ptr_uconst(dst_mem_opts, 2);
2126 self.instruction(LocalGet(dst.len.idx));
2127 self.ptr_uconst(dst_mem_opts, 1);
2128 self.ptr_shl(dst_mem_opts);
2129 self.instruction(Call(match dst.opts.data_model {
2130 DataModel::Gc {} => todo!("CM+GC"),
2131 DataModel::LinearMemory(LinearMemoryOptions { realloc, .. }) => {
2132 realloc.unwrap().as_u32()
2133 }
2134 }));
2135 self.instruction(LocalSet(dst.ptr.idx));
2136 self.instruction(End); self.free_temp_local(dst_byte_len);
2139
2140 dst
2141 }
2142
2143 fn string_compact_utf16_to_compact<'c>(
2157 &mut self,
2158 src: &WasmString<'_>,
2159 dst_opts: &'c Options,
2160 ) -> WasmString<'c> {
2161 let src_mem_opts = match &src.opts.data_model {
2162 DataModel::Gc {} => todo!("CM+GC"),
2163 DataModel::LinearMemory(opts) => opts,
2164 };
2165 let dst_mem_opts = match &dst_opts.data_model {
2166 DataModel::Gc {} => todo!("CM+GC"),
2167 DataModel::LinearMemory(opts) => opts,
2168 };
2169
2170 self.validate_string_length(src, FE::Utf16);
2171 self.convert_src_len_to_dst(src.len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2172 let dst_len = self.local_tee_new_tmp(dst_mem_opts.ptr());
2173 self.ptr_uconst(dst_mem_opts, 1);
2174 self.ptr_shl(dst_mem_opts);
2175 let dst_byte_len = self.local_set_new_tmp(dst_mem_opts.ptr());
2176 let dst = {
2177 let dst_mem = self.malloc(dst_opts, MallocSize::Local(dst_byte_len.idx), 2);
2178 WasmString {
2179 ptr: dst_mem.addr,
2180 len: dst_len,
2181 opts: dst_opts,
2182 }
2183 };
2184
2185 self.convert_src_len_to_dst(
2186 dst_byte_len.idx,
2187 dst.opts.data_model.unwrap_memory().ptr(),
2188 src_mem_opts.ptr(),
2189 );
2190 let src_byte_len = self.local_set_new_tmp(src_mem_opts.ptr());
2191
2192 self.validate_string_inbounds(src, src_byte_len.idx);
2193 self.validate_string_inbounds(&dst, dst_byte_len.idx);
2194
2195 let transcode = self.transcoder(src, &dst, Transcode::Utf16ToCompactProbablyUtf16);
2196 self.instruction(LocalGet(src.ptr.idx));
2197 self.instruction(LocalGet(src.len.idx));
2198 self.instruction(LocalGet(dst.ptr.idx));
2199 self.instruction(Call(transcode.as_u32()));
2200 self.instruction(LocalSet(dst.len.idx));
2201
2202 if self.module.tunables.debug_adapter_modules {
2205 self.instruction(LocalGet(dst.len.idx));
2206 self.ptr_uconst(dst_mem_opts, !UTF16_TAG);
2207 self.ptr_and(dst_mem_opts);
2208 self.convert_src_len_to_dst(src.len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2209 self.ptr_ne(dst_mem_opts);
2210 self.instruction(If(BlockType::Empty));
2211 self.trap(Trap::DebugAssertEqualCodeUnits);
2212 self.instruction(End);
2213 }
2214
2215 self.instruction(LocalGet(dst.len.idx));
2219 self.ptr_uconst(dst_mem_opts, UTF16_TAG);
2220 self.ptr_and(dst_mem_opts);
2221 self.ptr_br_if(dst_mem_opts, 0);
2222
2223 self.instruction(LocalGet(dst.ptr.idx)); self.instruction(LocalGet(dst_byte_len.idx)); self.ptr_uconst(dst_mem_opts, 2); self.instruction(LocalGet(dst.len.idx)); self.instruction(Call(dst_mem_opts.realloc.unwrap().as_u32()));
2229 self.instruction(LocalSet(dst.ptr.idx));
2230
2231 self.free_temp_local(dst_byte_len);
2232 self.free_temp_local(src_byte_len);
2233
2234 dst
2235 }
2236
2237 fn string_to_compact<'c>(
2244 &mut self,
2245 src: &WasmString<'_>,
2246 src_enc: FE,
2247 dst_opts: &'c Options,
2248 ) -> WasmString<'c> {
2249 let src_mem_opts = match &src.opts.data_model {
2250 DataModel::Gc {} => todo!("CM+GC"),
2251 DataModel::LinearMemory(opts) => opts,
2252 };
2253 let dst_mem_opts = match &dst_opts.data_model {
2254 DataModel::Gc {} => todo!("CM+GC"),
2255 DataModel::LinearMemory(opts) => opts,
2256 };
2257
2258 self.validate_string_length(src, src_enc);
2259 self.convert_src_len_to_dst(src.len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2260 let dst_len = self.local_tee_new_tmp(dst_mem_opts.ptr());
2261 let dst_byte_len = self.local_set_new_tmp(dst_mem_opts.ptr());
2262 let dst = {
2263 let dst_mem = self.malloc(dst_opts, MallocSize::Local(dst_byte_len.idx), 2);
2264 WasmString {
2265 ptr: dst_mem.addr,
2266 len: dst_len,
2267 opts: dst_opts,
2268 }
2269 };
2270
2271 self.validate_string_inbounds(src, src.len.idx);
2272 self.validate_string_inbounds(&dst, dst_byte_len.idx);
2273
2274 let (latin1, utf16) = match src_enc {
2278 FE::Utf8 => (Transcode::Utf8ToLatin1, Transcode::Utf8ToCompactUtf16),
2279 FE::Utf16 => (Transcode::Utf16ToLatin1, Transcode::Utf16ToCompactUtf16),
2280 FE::Latin1 => unreachable!(),
2281 };
2282 let transcode_latin1 = self.transcoder(src, &dst, latin1);
2283 let transcode_utf16 = self.transcoder(src, &dst, utf16);
2284 self.instruction(LocalGet(src.ptr.idx));
2285 self.instruction(LocalGet(src.len.idx));
2286 self.instruction(LocalGet(dst.ptr.idx));
2287 self.instruction(Call(transcode_latin1.as_u32()));
2288 self.instruction(LocalSet(dst.len.idx));
2289 let src_len_tmp = self.local_set_new_tmp(src_mem_opts.ptr());
2290
2291 self.instruction(LocalGet(src_len_tmp.idx));
2294 self.instruction(LocalGet(src.len.idx));
2295 self.ptr_eq(src_mem_opts);
2296 self.instruction(If(BlockType::Empty)); self.instruction(LocalGet(dst_byte_len.idx));
2302 self.instruction(LocalGet(dst.len.idx));
2303 self.ptr_ne(dst_mem_opts);
2304 self.instruction(If(BlockType::Empty));
2305 self.instruction(LocalGet(dst.ptr.idx)); self.instruction(LocalGet(dst_byte_len.idx)); self.ptr_uconst(dst_mem_opts, 2); self.instruction(LocalGet(dst.len.idx)); self.instruction(Call(dst_mem_opts.realloc.unwrap().as_u32()));
2310 self.instruction(LocalSet(dst.ptr.idx));
2311 self.instruction(End);
2312
2313 self.instruction(Else); if src_enc.width() == 1 {
2322 self.validate_string_length_u8(src, 2);
2323 }
2324
2325 self.instruction(LocalGet(dst.ptr.idx)); self.instruction(LocalGet(dst_byte_len.idx)); self.ptr_uconst(dst_mem_opts, 2); self.convert_src_len_to_dst(src.len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2331 self.ptr_uconst(dst_mem_opts, 1);
2332 self.ptr_shl(dst_mem_opts);
2333 self.instruction(LocalTee(dst_byte_len.idx));
2334 self.instruction(Call(dst_mem_opts.realloc.unwrap().as_u32()));
2335 self.instruction(LocalSet(dst.ptr.idx));
2336
2337 self.instruction(LocalGet(src.ptr.idx));
2341 self.instruction(LocalGet(src_len_tmp.idx));
2342 if let FE::Utf16 = src_enc {
2343 self.ptr_uconst(src_mem_opts, 1);
2344 self.ptr_shl(src_mem_opts);
2345 }
2346 self.ptr_add(src_mem_opts);
2347 self.instruction(LocalGet(src.len.idx));
2348 self.instruction(LocalGet(src_len_tmp.idx));
2349 self.ptr_sub(src_mem_opts);
2350 self.instruction(LocalGet(dst.ptr.idx));
2351 self.convert_src_len_to_dst(src.len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2352 self.instruction(LocalGet(dst.len.idx));
2353 self.instruction(Call(transcode_utf16.as_u32()));
2354 self.instruction(LocalSet(dst.len.idx));
2355
2356 self.instruction(LocalGet(dst.len.idx));
2364 self.convert_src_len_to_dst(src.len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2365 self.ptr_ne(dst_mem_opts);
2366 self.instruction(If(BlockType::Empty));
2367 self.instruction(LocalGet(dst.ptr.idx)); self.instruction(LocalGet(dst_byte_len.idx)); self.ptr_uconst(dst_mem_opts, 2); self.instruction(LocalGet(dst.len.idx));
2371 self.ptr_uconst(dst_mem_opts, 1);
2372 self.ptr_shl(dst_mem_opts);
2373 self.instruction(Call(dst_mem_opts.realloc.unwrap().as_u32()));
2374 self.instruction(LocalSet(dst.ptr.idx));
2375 self.instruction(End);
2376
2377 self.instruction(LocalGet(dst.len.idx));
2379 self.ptr_uconst(dst_mem_opts, UTF16_TAG);
2380 self.ptr_or(dst_mem_opts);
2381 self.instruction(LocalSet(dst.len.idx));
2382
2383 self.instruction(End); self.free_temp_local(src_len_tmp);
2386 self.free_temp_local(dst_byte_len);
2387
2388 dst
2389 }
2390
2391 fn validate_string_length(&mut self, src: &WasmString<'_>, dst: FE) {
2392 self.validate_string_length_u8(src, dst.width())
2393 }
2394
2395 fn validate_string_length_u8(&mut self, s: &WasmString<'_>, dst: u8) {
2396 let mem_opts = match &s.opts.data_model {
2397 DataModel::Gc {} => todo!("CM+GC"),
2398 DataModel::LinearMemory(opts) => opts,
2399 };
2400
2401 self.instruction(LocalGet(s.len.idx));
2404 let max = MAX_STRING_BYTE_LENGTH / u32::from(dst);
2405 self.ptr_uconst(mem_opts, max);
2406 self.ptr_ge_u(mem_opts);
2407 self.instruction(If(BlockType::Empty));
2408 self.trap(Trap::StringOutOfBounds);
2409 self.instruction(End);
2410 }
2411
2412 fn transcoder(
2413 &mut self,
2414 src: &WasmString<'_>,
2415 dst: &WasmString<'_>,
2416 op: Transcode,
2417 ) -> FuncIndex {
2418 match (src.opts.data_model, dst.opts.data_model) {
2419 (DataModel::Gc {}, _) | (_, DataModel::Gc {}) => {
2420 todo!("CM+GC")
2421 }
2422 (
2423 DataModel::LinearMemory(LinearMemoryOptions {
2424 memory64: src64,
2425 memory: src_mem,
2426 realloc: _,
2427 }),
2428 DataModel::LinearMemory(LinearMemoryOptions {
2429 memory64: dst64,
2430 memory: dst_mem,
2431 realloc: _,
2432 }),
2433 ) => self.module.import_transcoder(Transcoder {
2434 from_memory: src_mem.unwrap(),
2435 from_memory64: src64,
2436 to_memory: dst_mem.unwrap(),
2437 to_memory64: dst64,
2438 op,
2439 }),
2440 }
2441 }
2442
2443 fn validate_string_inbounds(&mut self, s: &WasmString<'_>, byte_len: u32) {
2444 match &s.opts.data_model {
2445 DataModel::Gc {} => todo!("CM+GC"),
2446 DataModel::LinearMemory(opts) => {
2447 self.validate_memory_inbounds(opts, s.ptr.idx, byte_len, Trap::StringOutOfBounds)
2448 }
2449 }
2450 }
2451
2452 fn validate_memory_inbounds(
2453 &mut self,
2454 opts: &LinearMemoryOptions,
2455 ptr_local: u32,
2456 byte_len_local: u32,
2457 trap: Trap,
2458 ) {
2459 let extend_to_64 = |me: &mut Self| {
2460 if !opts.memory64 {
2461 me.instruction(I64ExtendI32U);
2462 }
2463 };
2464
2465 self.instruction(Block(BlockType::Empty));
2466 self.instruction(Block(BlockType::Empty));
2467
2468 self.instruction(MemorySize(opts.memory.unwrap().as_u32()));
2473 extend_to_64(self);
2474 self.instruction(I64Const(16));
2475 self.instruction(I64Shl);
2476
2477 self.instruction(LocalGet(ptr_local));
2482 extend_to_64(self);
2483 self.instruction(LocalGet(byte_len_local));
2484 extend_to_64(self);
2485 self.instruction(I64Add);
2486 if opts.memory64 {
2487 let tmp = self.local_tee_new_tmp(ValType::I64);
2488 self.instruction(LocalGet(ptr_local));
2489 self.ptr_lt_u(opts);
2490 self.instruction(BrIf(0));
2491 self.instruction(LocalGet(tmp.idx));
2492 self.free_temp_local(tmp);
2493 }
2494
2495 self.instruction(I64GeU);
2499 self.instruction(BrIf(1));
2500
2501 self.instruction(End);
2502 self.trap(trap);
2503 self.instruction(End);
2504 }
2505
2506 fn begin_translate_sequence<'c>(
2515 &mut self,
2516 src: &Source<'c>,
2517 dst: &Destination<'c>,
2518 src_element_size: u32,
2519 src_element_align: u32,
2520 dst_element_size: u32,
2521 dst_element_align: u32,
2522 ) -> SequenceTranslation<'c> {
2523 let src_mem_opts = match &src.opts().data_model {
2524 DataModel::Gc {} => todo!("CM+GC"),
2525 DataModel::LinearMemory(opts) => opts,
2526 };
2527 let dst_mem_opts = match &dst.opts().data_model {
2528 DataModel::Gc {} => todo!("CM+GC"),
2529 DataModel::LinearMemory(opts) => opts,
2530 };
2531
2532 let src_opts = src.opts();
2533 let dst_opts = dst.opts();
2534
2535 match src {
2540 Source::Stack(s) => {
2541 assert_eq!(s.locals.len(), 2);
2542 self.stack_get(&s.slice(0..1), src_mem_opts.ptr());
2543 self.stack_get(&s.slice(1..2), src_mem_opts.ptr());
2544 }
2545 Source::Memory(mem) => {
2546 self.ptr_load(mem);
2547 self.ptr_load(&mem.bump(src_mem_opts.ptr_size().into()));
2548 }
2549 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
2550 }
2551 let src_len = self.local_set_new_tmp(src_mem_opts.ptr());
2552 let src_ptr = self.local_set_new_tmp(src_mem_opts.ptr());
2553
2554 let src_mem = self.memory_operand(src_opts, src_ptr, src_element_align);
2557
2558 let src_byte_len =
2560 self.calculate_list_byte_len(src_mem_opts, src_len.idx, src_element_size);
2561 let dst_byte_len = if src_element_size == dst_element_size {
2562 self.convert_src_len_to_dst(src_byte_len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2563 self.local_set_new_tmp(dst_mem_opts.ptr())
2564 } else if src_mem_opts.ptr() == dst_mem_opts.ptr() {
2565 self.calculate_list_byte_len(dst_mem_opts, src_len.idx, dst_element_size)
2566 } else {
2567 self.convert_src_len_to_dst(src_byte_len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2568 let tmp = self.local_set_new_tmp(dst_mem_opts.ptr());
2569 let ret = self.calculate_list_byte_len(dst_mem_opts, tmp.idx, dst_element_size);
2570 self.free_temp_local(tmp);
2571 ret
2572 };
2573
2574 let dst_mem = self.malloc(
2579 dst_opts,
2580 MallocSize::Local(dst_byte_len.idx),
2581 dst_element_align,
2582 );
2583
2584 self.validate_memory_inbounds(
2587 src_mem_opts,
2588 src_mem.addr.idx,
2589 src_byte_len.idx,
2590 Trap::ListOutOfBounds,
2591 );
2592 self.validate_memory_inbounds(
2593 dst_mem_opts,
2594 dst_mem.addr.idx,
2595 dst_byte_len.idx,
2596 Trap::ListOutOfBounds,
2597 );
2598
2599 self.free_temp_local(src_byte_len);
2600 self.free_temp_local(dst_byte_len);
2601
2602 let loop_state = if src_element_size > 0 || dst_element_size > 0 {
2606 self.instruction(Block(BlockType::Empty));
2607
2608 self.instruction(LocalGet(src_len.idx));
2610 let remaining = self.local_tee_new_tmp(src_mem_opts.ptr());
2611 self.ptr_eqz(src_mem_opts);
2612 self.instruction(BrIf(0));
2613
2614 self.instruction(LocalGet(src_mem.addr.idx));
2616 let cur_src_ptr = self.local_set_new_tmp(src_mem_opts.ptr());
2617 self.instruction(LocalGet(dst_mem.addr.idx));
2618 let cur_dst_ptr = self.local_set_new_tmp(dst_mem_opts.ptr());
2619
2620 self.instruction(Loop(BlockType::Empty));
2621
2622 Some(SequenceLoopState {
2623 remaining,
2624 cur_src_ptr,
2625 cur_dst_ptr,
2626 })
2627 } else {
2628 None
2629 };
2630
2631 SequenceTranslation {
2632 src_len,
2633 src_mem,
2634 dst_mem,
2635 src_opts,
2636 dst_opts,
2637 src_mem_opts,
2638 dst_mem_opts,
2639 loop_state,
2640 }
2641 }
2642
2643 fn end_translate_sequence(&mut self, seq: SequenceTranslation<'_>, dst: &Destination) {
2649 if let Some(loop_state) = seq.loop_state {
2650 self.instruction(LocalGet(loop_state.remaining.idx));
2653 self.ptr_iconst(seq.src_mem_opts, -1);
2654 self.ptr_add(seq.src_mem_opts);
2655 self.instruction(LocalTee(loop_state.remaining.idx));
2656 self.ptr_br_if(seq.src_mem_opts, 0);
2657 self.instruction(End); self.instruction(End); self.free_temp_local(loop_state.cur_dst_ptr);
2661 self.free_temp_local(loop_state.cur_src_ptr);
2662 self.free_temp_local(loop_state.remaining);
2663 }
2664
2665 match dst {
2667 Destination::Stack(s, _) => {
2668 self.instruction(LocalGet(seq.dst_mem.addr.idx));
2669 self.stack_set(&s[..1], seq.dst_mem_opts.ptr());
2670 self.convert_src_len_to_dst(
2671 seq.src_len.idx,
2672 seq.src_mem_opts.ptr(),
2673 seq.dst_mem_opts.ptr(),
2674 );
2675 self.stack_set(&s[1..], seq.dst_mem_opts.ptr());
2676 }
2677 Destination::Memory(mem) => {
2678 self.instruction(LocalGet(mem.addr.idx));
2679 self.instruction(LocalGet(seq.dst_mem.addr.idx));
2680 self.ptr_store(mem);
2681 self.instruction(LocalGet(mem.addr.idx));
2682 self.convert_src_len_to_dst(
2683 seq.src_len.idx,
2684 seq.src_mem_opts.ptr(),
2685 seq.dst_mem_opts.ptr(),
2686 );
2687 self.ptr_store(&mem.bump(seq.dst_mem_opts.ptr_size().into()));
2688 }
2689 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
2690 }
2691
2692 self.free_temp_local(seq.src_len);
2693 self.free_temp_local(seq.src_mem.addr);
2694 self.free_temp_local(seq.dst_mem.addr);
2695 }
2696
2697 fn translate_list(
2698 &mut self,
2699 src_ty: TypeListIndex,
2700 src: &Source<'_>,
2701 dst_ty: &InterfaceType,
2702 dst: &Destination,
2703 ) {
2704 let src_mem_opts = match &src.opts().data_model {
2705 DataModel::Gc {} => todo!("CM+GC"),
2706 DataModel::LinearMemory(opts) => opts,
2707 };
2708 let dst_mem_opts = match &dst.opts().data_model {
2709 DataModel::Gc {} => todo!("CM+GC"),
2710 DataModel::LinearMemory(opts) => opts,
2711 };
2712
2713 let src_element_ty = &self.types[src_ty].element;
2714 let dst_element_ty = match dst_ty {
2715 InterfaceType::List(r) => &self.types[*r].element,
2716 _ => panic!("expected a list"),
2717 };
2718 let (src_size, src_align) = self.types.size_align(src_mem_opts, src_element_ty);
2719 let (dst_size, dst_align) = self.types.size_align(dst_mem_opts, dst_element_ty);
2720
2721 let seq = self.begin_translate_sequence(src, dst, src_size, src_align, dst_size, dst_align);
2722
2723 if let Some(ref loop_state) = seq.loop_state {
2724 let element_src = Source::Memory(Memory {
2725 opts: seq.src_opts,
2726 offset: 0,
2727 addr: TempLocal::new(loop_state.cur_src_ptr.idx, loop_state.cur_src_ptr.ty),
2728 });
2729 let element_dst = Destination::Memory(Memory {
2730 opts: seq.dst_opts,
2731 offset: 0,
2732 addr: TempLocal::new(loop_state.cur_dst_ptr.idx, loop_state.cur_dst_ptr.ty),
2733 });
2734 self.translate(src_element_ty, &element_src, dst_element_ty, &element_dst);
2735
2736 if src_size > 0 {
2737 self.instruction(LocalGet(loop_state.cur_src_ptr.idx));
2738 self.ptr_uconst(src_mem_opts, src_size);
2739 self.ptr_add(src_mem_opts);
2740 self.instruction(LocalSet(loop_state.cur_src_ptr.idx));
2741 }
2742 if dst_size > 0 {
2743 self.instruction(LocalGet(loop_state.cur_dst_ptr.idx));
2744 self.ptr_uconst(dst_mem_opts, dst_size);
2745 self.ptr_add(dst_mem_opts);
2746 self.instruction(LocalSet(loop_state.cur_dst_ptr.idx));
2747 }
2748 }
2749
2750 self.end_translate_sequence(seq, dst);
2751 }
2752
2753 fn translate_map(
2759 &mut self,
2760 src_ty: TypeMapIndex,
2761 src: &Source<'_>,
2762 dst_ty: &InterfaceType,
2763 dst: &Destination,
2764 ) {
2765 let src_mem_opts = match &src.opts().data_model {
2766 DataModel::Gc {} => todo!("CM+GC"),
2767 DataModel::LinearMemory(opts) => opts,
2768 };
2769 let dst_mem_opts = match &dst.opts().data_model {
2770 DataModel::Gc {} => todo!("CM+GC"),
2771 DataModel::LinearMemory(opts) => opts,
2772 };
2773
2774 let src_map_ty = &self.types[src_ty];
2775 let dst_map_ty = match dst_ty {
2776 InterfaceType::Map(r) => &self.types[*r],
2777 _ => panic!("expected a map"),
2778 };
2779
2780 let src_key_abi = self.types.canonical_abi(&src_map_ty.key);
2782 let src_value_abi = self.types.canonical_abi(&src_map_ty.value);
2783 let src_entry_abi = CanonicalAbiInfo::record([src_key_abi, src_value_abi].into_iter());
2784 let (_, src_key_align) = self.types.size_align(src_mem_opts, &src_map_ty.key);
2785 let (_, src_value_align) = self.types.size_align(src_mem_opts, &src_map_ty.value);
2786 let (src_tuple_size, src_entry_align) = if src_mem_opts.memory64 {
2787 (src_entry_abi.size64, src_entry_abi.align64)
2788 } else {
2789 (src_entry_abi.size32, src_entry_abi.align32)
2790 };
2791 let src_value_offset = {
2792 let mut offset = 0u32;
2793 if src_mem_opts.memory64 {
2794 src_key_abi.next_field64(&mut offset);
2795 src_value_abi.next_field64(&mut offset)
2796 } else {
2797 src_key_abi.next_field32(&mut offset);
2798 src_value_abi.next_field32(&mut offset)
2799 }
2800 };
2801
2802 let dst_key_abi = self.types.canonical_abi(&dst_map_ty.key);
2803 let dst_value_abi = self.types.canonical_abi(&dst_map_ty.value);
2804 let dst_entry_abi = CanonicalAbiInfo::record([dst_key_abi, dst_value_abi].into_iter());
2805 let (_, dst_key_align) = self.types.size_align(dst_mem_opts, &dst_map_ty.key);
2806 let (_, dst_value_align) = self.types.size_align(dst_mem_opts, &dst_map_ty.value);
2807 let (dst_tuple_size, dst_entry_align) = if dst_mem_opts.memory64 {
2808 (dst_entry_abi.size64, dst_entry_abi.align64)
2809 } else {
2810 (dst_entry_abi.size32, dst_entry_abi.align32)
2811 };
2812 let dst_value_offset = {
2813 let mut offset = 0u32;
2814 if dst_mem_opts.memory64 {
2815 dst_key_abi.next_field64(&mut offset);
2816 dst_value_abi.next_field64(&mut offset)
2817 } else {
2818 dst_key_abi.next_field32(&mut offset);
2819 dst_value_abi.next_field32(&mut offset)
2820 }
2821 };
2822
2823 let seq = self.begin_translate_sequence(
2824 src,
2825 dst,
2826 src_tuple_size,
2827 src_entry_align,
2828 dst_tuple_size,
2829 dst_entry_align,
2830 );
2831
2832 if let Some(ref loop_state) = seq.loop_state {
2833 let key_src = Source::Memory(self.memory_operand(
2834 seq.src_opts,
2835 TempLocal {
2836 idx: loop_state.cur_src_ptr.idx,
2837 ty: src_mem_opts.ptr(),
2838 needs_free: false,
2839 },
2840 src_key_align,
2841 ));
2842 let key_dst = Destination::Memory(self.memory_operand(
2843 seq.dst_opts,
2844 TempLocal {
2845 idx: loop_state.cur_dst_ptr.idx,
2846 ty: dst_mem_opts.ptr(),
2847 needs_free: false,
2848 },
2849 dst_key_align,
2850 ));
2851 self.translate(&src_map_ty.key, &key_src, &dst_map_ty.key, &key_dst);
2852
2853 if src_value_offset > 0 {
2854 self.instruction(LocalGet(loop_state.cur_src_ptr.idx));
2855 self.ptr_uconst(src_mem_opts, src_value_offset);
2856 self.ptr_add(src_mem_opts);
2857 self.instruction(LocalSet(loop_state.cur_src_ptr.idx));
2858 }
2859 if dst_value_offset > 0 {
2860 self.instruction(LocalGet(loop_state.cur_dst_ptr.idx));
2861 self.ptr_uconst(dst_mem_opts, dst_value_offset);
2862 self.ptr_add(dst_mem_opts);
2863 self.instruction(LocalSet(loop_state.cur_dst_ptr.idx));
2864 }
2865
2866 let value_src = Source::Memory(self.memory_operand(
2867 seq.src_opts,
2868 TempLocal {
2869 idx: loop_state.cur_src_ptr.idx,
2870 ty: src_mem_opts.ptr(),
2871 needs_free: false,
2872 },
2873 src_value_align,
2874 ));
2875 let value_dst = Destination::Memory(self.memory_operand(
2876 seq.dst_opts,
2877 TempLocal {
2878 idx: loop_state.cur_dst_ptr.idx,
2879 ty: dst_mem_opts.ptr(),
2880 needs_free: false,
2881 },
2882 dst_value_align,
2883 ));
2884 self.translate(&src_map_ty.value, &value_src, &dst_map_ty.value, &value_dst);
2885
2886 let src_advance_to_next = src_tuple_size - src_value_offset;
2888 if src_advance_to_next > 0 {
2889 self.instruction(LocalGet(loop_state.cur_src_ptr.idx));
2890 self.ptr_uconst(src_mem_opts, src_advance_to_next);
2891 self.ptr_add(src_mem_opts);
2892 self.instruction(LocalSet(loop_state.cur_src_ptr.idx));
2893 }
2894 let dst_advance_to_next = dst_tuple_size - dst_value_offset;
2895 if dst_advance_to_next > 0 {
2896 self.instruction(LocalGet(loop_state.cur_dst_ptr.idx));
2897 self.ptr_uconst(dst_mem_opts, dst_advance_to_next);
2898 self.ptr_add(dst_mem_opts);
2899 self.instruction(LocalSet(loop_state.cur_dst_ptr.idx));
2900 }
2901 }
2902
2903 self.end_translate_sequence(seq, dst);
2904 }
2905
2906 fn calculate_list_byte_len(
2907 &mut self,
2908 opts: &LinearMemoryOptions,
2909 len_local: u32,
2910 elt_size: u32,
2911 ) -> TempLocal {
2912 if elt_size == 0 {
2915 self.ptr_uconst(opts, 0);
2916 return self.local_set_new_tmp(opts.ptr());
2917 }
2918
2919 if elt_size == 1 {
2927 if let ValType::I64 = opts.ptr() {
2928 self.instruction(LocalGet(len_local));
2929 self.instruction(I64Const(32));
2930 self.instruction(I64ShrU);
2931 self.instruction(I32WrapI64);
2932 self.instruction(If(BlockType::Empty));
2933 self.trap(Trap::ListOutOfBounds);
2934 self.instruction(End);
2935 }
2936 self.instruction(LocalGet(len_local));
2937 return self.local_set_new_tmp(opts.ptr());
2938 }
2939
2940 self.instruction(Block(BlockType::Empty));
2945 self.instruction(Block(BlockType::Empty));
2946 self.instruction(LocalGet(len_local));
2947 match opts.ptr() {
2948 ValType::I32 => self.instruction(I64ExtendI32U),
2952
2953 ValType::I64 => {
2957 self.instruction(I64Const(32));
2958 self.instruction(I64ShrU);
2959 self.instruction(I32WrapI64);
2960 self.instruction(BrIf(0));
2961 self.instruction(LocalGet(len_local));
2962 }
2963
2964 _ => unreachable!(),
2965 }
2966
2967 self.instruction(I64Const(elt_size.into()));
2976 self.instruction(I64Mul);
2977 let tmp = self.local_tee_new_tmp(ValType::I64);
2978 self.instruction(I64Const(32));
2981 self.instruction(I64ShrU);
2982 self.instruction(I64Eqz);
2983 self.instruction(BrIf(1));
2984 self.instruction(End);
2985 self.trap(Trap::ListOutOfBounds);
2986 self.instruction(End);
2987
2988 if opts.ptr() == ValType::I64 {
2992 tmp
2993 } else {
2994 self.instruction(LocalGet(tmp.idx));
2995 self.instruction(I32WrapI64);
2996 self.free_temp_local(tmp);
2997 self.local_set_new_tmp(ValType::I32)
2998 }
2999 }
3000
3001 fn convert_src_len_to_dst(
3002 &mut self,
3003 src_len_local: u32,
3004 src_ptr_ty: ValType,
3005 dst_ptr_ty: ValType,
3006 ) {
3007 self.instruction(LocalGet(src_len_local));
3008 match (src_ptr_ty, dst_ptr_ty) {
3009 (ValType::I32, ValType::I64) => self.instruction(I64ExtendI32U),
3010 (ValType::I64, ValType::I32) => self.instruction(I32WrapI64),
3011 (src, dst) => assert_eq!(src, dst),
3012 }
3013 }
3014
3015 fn translate_record(
3016 &mut self,
3017 src_ty: TypeRecordIndex,
3018 src: &Source<'_>,
3019 dst_ty: &InterfaceType,
3020 dst: &Destination,
3021 ) {
3022 let src_ty = &self.types[src_ty];
3023 let dst_ty = match dst_ty {
3024 InterfaceType::Record(r) => &self.types[*r],
3025 _ => panic!("expected a record"),
3026 };
3027
3028 assert_eq!(src_ty.fields.len(), dst_ty.fields.len());
3030
3031 let mut src_fields = HashMap::new();
3035 for (i, src) in src
3036 .record_field_srcs(self.types, src_ty.fields.iter().map(|f| f.ty))
3037 .enumerate()
3038 {
3039 let field = &src_ty.fields[i];
3040 src_fields.insert(&field.name, (src, &field.ty));
3041 }
3042
3043 for (i, dst) in dst
3052 .record_field_dsts(self.types, dst_ty.fields.iter().map(|f| f.ty))
3053 .enumerate()
3054 {
3055 let field = &dst_ty.fields[i];
3056 let (src, src_ty) = &src_fields[&field.name];
3057 self.translate(src_ty, src, &field.ty, &dst);
3058 }
3059 }
3060
3061 fn translate_flags(
3062 &mut self,
3063 src_ty: TypeFlagsIndex,
3064 src: &Source<'_>,
3065 dst_ty: &InterfaceType,
3066 dst: &Destination,
3067 ) {
3068 let src_ty = &self.types[src_ty];
3069 let dst_ty = match dst_ty {
3070 InterfaceType::Flags(r) => &self.types[*r],
3071 _ => panic!("expected a record"),
3072 };
3073
3074 assert_eq!(src_ty.names, dst_ty.names);
3082 let cnt = src_ty.names.len();
3083 match FlagsSize::from_count(cnt) {
3084 FlagsSize::Size0 => {}
3085 FlagsSize::Size1 => {
3086 let mask = if cnt == 8 { 0xff } else { (1 << cnt) - 1 };
3087 self.convert_u8_mask(src, dst, mask);
3088 }
3089 FlagsSize::Size2 => {
3090 let mask = if cnt == 16 { 0xffff } else { (1 << cnt) - 1 };
3091 self.convert_u16_mask(src, dst, mask);
3092 }
3093 FlagsSize::Size4Plus(n) => {
3094 let srcs = src.record_field_srcs(self.types, (0..n).map(|_| InterfaceType::U32));
3095 let dsts = dst.record_field_dsts(self.types, (0..n).map(|_| InterfaceType::U32));
3096 let n = usize::from(n);
3097 for (i, (src, dst)) in srcs.zip(dsts).enumerate() {
3098 let mask = if i == n - 1 && (cnt % 32 != 0) {
3099 (1 << (cnt % 32)) - 1
3100 } else {
3101 0xffffffff
3102 };
3103 self.convert_u32_mask(&src, &dst, mask);
3104 }
3105 }
3106 }
3107 }
3108
3109 fn translate_tuple(
3110 &mut self,
3111 src_ty: TypeTupleIndex,
3112 src: &Source<'_>,
3113 dst_ty: &InterfaceType,
3114 dst: &Destination,
3115 ) {
3116 let src_ty = &self.types[src_ty];
3117 let dst_ty = match dst_ty {
3118 InterfaceType::Tuple(t) => &self.types[*t],
3119 _ => panic!("expected a tuple"),
3120 };
3121
3122 assert_eq!(src_ty.types.len(), dst_ty.types.len());
3124
3125 let srcs = src
3126 .record_field_srcs(self.types, src_ty.types.iter().copied())
3127 .zip(src_ty.types.iter());
3128 let dsts = dst
3129 .record_field_dsts(self.types, dst_ty.types.iter().copied())
3130 .zip(dst_ty.types.iter());
3131 for ((src, src_ty), (dst, dst_ty)) in srcs.zip(dsts) {
3132 self.translate(src_ty, &src, dst_ty, &dst);
3133 }
3134 }
3135
3136 fn translate_fixed_length_list(
3137 &mut self,
3138 src_ty: TypeFixedLengthListIndex,
3139 src: &Source<'_>,
3140 dst_ty: &InterfaceType,
3141 dst: &Destination,
3142 ) {
3143 let src_ty = &self.types[src_ty];
3144 let dst_ty = match dst_ty {
3145 InterfaceType::FixedLengthList(t) => &self.types[*t],
3146 _ => panic!("expected a fixed size list"),
3147 };
3148
3149 assert_eq!(src_ty.size, dst_ty.size);
3151
3152 match (&src, &dst) {
3153 (Source::Memory(src_mem), Destination::Memory(dst_mem)) => {
3155 let src_mem_opts = match &src_mem.opts.data_model {
3156 DataModel::Gc {} => todo!("CM+GC"),
3157 DataModel::LinearMemory(opts) => opts,
3158 };
3159 let dst_mem_opts = match &dst_mem.opts.data_model {
3160 DataModel::Gc {} => todo!("CM+GC"),
3161 DataModel::LinearMemory(opts) => opts,
3162 };
3163 let src_element_bytes = self.types.size_align(src_mem_opts, &src_ty.element).0;
3164 let dst_element_bytes = self.types.size_align(dst_mem_opts, &dst_ty.element).0;
3165 assert_ne!(src_element_bytes, 0);
3166 assert_ne!(dst_element_bytes, 0);
3167
3168 self.instruction(LocalGet(src_mem.addr.idx));
3171 if src_mem.offset != 0 {
3172 self.ptr_uconst(src_mem_opts, src_mem.offset);
3173 self.ptr_add(src_mem_opts);
3174 }
3175 let cur_src_ptr = self.local_set_new_tmp(src_mem_opts.ptr());
3176 self.instruction(LocalGet(dst_mem.addr.idx));
3177 if dst_mem.offset != 0 {
3178 self.ptr_uconst(dst_mem_opts, dst_mem.offset);
3179 self.ptr_add(dst_mem_opts);
3180 }
3181 let cur_dst_ptr = self.local_set_new_tmp(dst_mem_opts.ptr());
3182
3183 self.instruction(I32Const(src_ty.size as i32));
3184 let remaining = self.local_set_new_tmp(ValType::I32);
3185
3186 self.instruction(Loop(BlockType::Empty));
3187
3188 let element_src = Source::Memory(Memory {
3190 opts: src_mem.opts,
3191 offset: 0,
3192 addr: TempLocal::new(cur_src_ptr.idx, cur_src_ptr.ty),
3193 });
3194 let element_dst = Destination::Memory(Memory {
3195 opts: dst_mem.opts,
3196 offset: 0,
3197 addr: TempLocal::new(cur_dst_ptr.idx, cur_dst_ptr.ty),
3198 });
3199 self.translate(&src_ty.element, &element_src, &dst_ty.element, &element_dst);
3200
3201 self.instruction(LocalGet(cur_src_ptr.idx));
3203 self.ptr_uconst(src_mem_opts, src_element_bytes);
3204 self.ptr_add(src_mem_opts);
3205 self.instruction(LocalSet(cur_src_ptr.idx));
3206 self.instruction(LocalGet(cur_dst_ptr.idx));
3207 self.ptr_uconst(dst_mem_opts, dst_element_bytes);
3208 self.ptr_add(dst_mem_opts);
3209 self.instruction(LocalSet(cur_dst_ptr.idx));
3210
3211 self.instruction(LocalGet(remaining.idx));
3214 self.ptr_iconst(src_mem_opts, -1);
3215 self.ptr_add(src_mem_opts);
3216 self.instruction(LocalTee(remaining.idx));
3217 self.ptr_br_if(src_mem_opts, 0);
3218 self.instruction(End); self.free_temp_local(cur_dst_ptr);
3221 self.free_temp_local(cur_src_ptr);
3222 self.free_temp_local(remaining);
3223 return;
3224 }
3225 (_, _) => {
3227 assert!(
3229 src_ty.size as usize <= MAX_FLAT_PARAMS
3230 && dst_ty.size as usize <= MAX_FLAT_PARAMS
3231 );
3232 let srcs =
3233 src.record_field_srcs(self.types, (0..src_ty.size).map(|_| src_ty.element));
3234 let dsts =
3235 dst.record_field_dsts(self.types, (0..dst_ty.size).map(|_| dst_ty.element));
3236 for (src, dst) in srcs.zip(dsts) {
3237 self.translate(&src_ty.element, &src, &dst_ty.element, &dst);
3238 }
3239 }
3240 }
3241 }
3242
3243 fn translate_variant(
3244 &mut self,
3245 src_ty: TypeVariantIndex,
3246 src: &Source<'_>,
3247 dst_ty: &InterfaceType,
3248 dst: &Destination,
3249 ) {
3250 let src_ty = &self.types[src_ty];
3251 let dst_ty = match dst_ty {
3252 InterfaceType::Variant(t) => &self.types[*t],
3253 _ => panic!("expected a variant"),
3254 };
3255
3256 let src_info = variant_info(self.types, src_ty.cases.iter().map(|(_, c)| c.as_ref()));
3257 let dst_info = variant_info(self.types, dst_ty.cases.iter().map(|(_, c)| c.as_ref()));
3258
3259 let iter = src_ty
3260 .cases
3261 .iter()
3262 .enumerate()
3263 .map(|(src_i, (src_case, src_case_ty))| {
3264 let dst_i = dst_ty
3265 .cases
3266 .iter()
3267 .position(|(c, _)| c == src_case)
3268 .unwrap();
3269 let dst_case_ty = &dst_ty.cases[dst_i];
3270 let src_i = u32::try_from(src_i).unwrap();
3271 let dst_i = u32::try_from(dst_i).unwrap();
3272 VariantCase {
3273 src_i,
3274 src_ty: src_case_ty.as_ref(),
3275 dst_i,
3276 dst_ty: dst_case_ty.as_ref(),
3277 }
3278 });
3279 self.convert_variant(src, &src_info, dst, &dst_info, iter);
3280 }
3281
3282 fn translate_enum(
3283 &mut self,
3284 src_ty: TypeEnumIndex,
3285 src: &Source<'_>,
3286 dst_ty: &InterfaceType,
3287 dst: &Destination,
3288 ) {
3289 let src_ty = &self.types[src_ty];
3290 let dst_ty = match dst_ty {
3291 InterfaceType::Enum(t) => &self.types[*t],
3292 _ => panic!("expected an option"),
3293 };
3294
3295 debug_assert_eq!(src_ty.info.size, dst_ty.info.size);
3296 debug_assert_eq!(src_ty.names.len(), dst_ty.names.len());
3297 debug_assert!(
3298 src_ty
3299 .names
3300 .iter()
3301 .zip(dst_ty.names.iter())
3302 .all(|(a, b)| a == b)
3303 );
3304
3305 match src {
3307 Source::Stack(s) => self.stack_get(&s.slice(0..1), ValType::I32),
3308 Source::Memory(mem) => match src_ty.info.size {
3309 DiscriminantSize::Size1 => self.i32_load8u(mem),
3310 DiscriminantSize::Size2 => self.i32_load16u(mem),
3311 DiscriminantSize::Size4 => self.i32_load(mem),
3312 },
3313 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
3314 }
3315 let tmp = self.local_tee_new_tmp(ValType::I32);
3316
3317 self.instruction(I32Const(i32::try_from(src_ty.names.len()).unwrap()));
3319 self.instruction(I32GeU);
3320 self.instruction(If(BlockType::Empty));
3321 self.trap(Trap::InvalidDiscriminant);
3322 self.instruction(End);
3323
3324 match dst {
3326 Destination::Stack(stack, _) => {
3327 self.local_get_tmp(&tmp);
3328 self.stack_set(&stack[..1], ValType::I32)
3329 }
3330 Destination::Memory(mem) => {
3331 self.push_dst_addr(dst);
3332 self.local_get_tmp(&tmp);
3333 match dst_ty.info.size {
3334 DiscriminantSize::Size1 => self.i32_store8(mem),
3335 DiscriminantSize::Size2 => self.i32_store16(mem),
3336 DiscriminantSize::Size4 => self.i32_store(mem),
3337 }
3338 }
3339 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
3340 }
3341 self.free_temp_local(tmp);
3342 }
3343
3344 fn translate_option(
3345 &mut self,
3346 src_ty: TypeOptionIndex,
3347 src: &Source<'_>,
3348 dst_ty: &InterfaceType,
3349 dst: &Destination,
3350 ) {
3351 let src_ty = &self.types[src_ty].ty;
3352 let dst_ty = match dst_ty {
3353 InterfaceType::Option(t) => &self.types[*t].ty,
3354 _ => panic!("expected an option"),
3355 };
3356 let src_ty = Some(src_ty);
3357 let dst_ty = Some(dst_ty);
3358
3359 let src_info = variant_info(self.types, [None, src_ty]);
3360 let dst_info = variant_info(self.types, [None, dst_ty]);
3361
3362 self.convert_variant(
3363 src,
3364 &src_info,
3365 dst,
3366 &dst_info,
3367 [
3368 VariantCase {
3369 src_i: 0,
3370 dst_i: 0,
3371 src_ty: None,
3372 dst_ty: None,
3373 },
3374 VariantCase {
3375 src_i: 1,
3376 dst_i: 1,
3377 src_ty,
3378 dst_ty,
3379 },
3380 ]
3381 .into_iter(),
3382 );
3383 }
3384
3385 fn translate_result(
3386 &mut self,
3387 src_ty: TypeResultIndex,
3388 src: &Source<'_>,
3389 dst_ty: &InterfaceType,
3390 dst: &Destination,
3391 ) {
3392 let src_ty = &self.types[src_ty];
3393 let dst_ty = match dst_ty {
3394 InterfaceType::Result(t) => &self.types[*t],
3395 _ => panic!("expected a result"),
3396 };
3397
3398 let src_info = variant_info(self.types, [src_ty.ok.as_ref(), src_ty.err.as_ref()]);
3399 let dst_info = variant_info(self.types, [dst_ty.ok.as_ref(), dst_ty.err.as_ref()]);
3400
3401 self.convert_variant(
3402 src,
3403 &src_info,
3404 dst,
3405 &dst_info,
3406 [
3407 VariantCase {
3408 src_i: 0,
3409 dst_i: 0,
3410 src_ty: src_ty.ok.as_ref(),
3411 dst_ty: dst_ty.ok.as_ref(),
3412 },
3413 VariantCase {
3414 src_i: 1,
3415 dst_i: 1,
3416 src_ty: src_ty.err.as_ref(),
3417 dst_ty: dst_ty.err.as_ref(),
3418 },
3419 ]
3420 .into_iter(),
3421 );
3422 }
3423
3424 fn convert_variant<'c>(
3425 &mut self,
3426 src: &Source<'_>,
3427 src_info: &VariantInfo,
3428 dst: &Destination,
3429 dst_info: &VariantInfo,
3430 src_cases: impl ExactSizeIterator<Item = VariantCase<'c>>,
3431 ) {
3432 let outer_block_ty = match dst {
3435 Destination::Stack(dst_flat, _) => match dst_flat.len() {
3436 0 => BlockType::Empty,
3437 1 => BlockType::Result(dst_flat[0]),
3438 _ => {
3439 let ty = self.module.core_types.function(&[], &dst_flat);
3440 BlockType::FunctionType(ty)
3441 }
3442 },
3443 Destination::Memory(_) => BlockType::Empty,
3444 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
3445 };
3446 self.instruction(Block(outer_block_ty));
3447
3448 let src_cases_len = src_cases.len();
3451 for _ in 0..src_cases_len - 1 {
3452 self.instruction(Block(BlockType::Empty));
3453 }
3454
3455 self.instruction(Block(BlockType::Empty));
3457
3458 self.instruction(Block(BlockType::Empty));
3461
3462 match src {
3464 Source::Stack(s) => self.stack_get(&s.slice(0..1), ValType::I32),
3465 Source::Memory(mem) => match src_info.size {
3466 DiscriminantSize::Size1 => self.i32_load8u(mem),
3467 DiscriminantSize::Size2 => self.i32_load16u(mem),
3468 DiscriminantSize::Size4 => self.i32_load(mem),
3469 },
3470 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
3471 }
3472
3473 let mut targets = Vec::new();
3476 for i in 0..src_cases_len {
3477 targets.push((i + 1) as u32);
3478 }
3479 self.instruction(BrTable(targets[..].into(), 0));
3480 self.instruction(End); self.trap(Trap::InvalidDiscriminant);
3483 self.instruction(End); let src_cases_len = u32::try_from(src_cases_len).unwrap();
3490 for case in src_cases {
3491 let VariantCase {
3492 src_i,
3493 src_ty,
3494 dst_i,
3495 dst_ty,
3496 } = case;
3497
3498 self.push_dst_addr(dst);
3501 self.instruction(I32Const(dst_i as i32));
3502 match dst {
3503 Destination::Stack(stack, _) => self.stack_set(&stack[..1], ValType::I32),
3504 Destination::Memory(mem) => match dst_info.size {
3505 DiscriminantSize::Size1 => self.i32_store8(mem),
3506 DiscriminantSize::Size2 => self.i32_store16(mem),
3507 DiscriminantSize::Size4 => self.i32_store(mem),
3508 },
3509 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
3510 }
3511
3512 let src_payload = src.payload_src(self.types, src_info, src_ty);
3513 let dst_payload = dst.payload_dst(self.types, dst_info, dst_ty);
3514
3515 match (src_ty, dst_ty) {
3518 (Some(src_ty), Some(dst_ty)) => {
3519 self.translate(src_ty, &src_payload, dst_ty, &dst_payload);
3520 }
3521 (None, None) => {}
3522 _ => unimplemented!(),
3523 }
3524
3525 if let Destination::Stack(payload_results, _) = dst_payload {
3532 if let Destination::Stack(dst_results, _) = dst {
3533 let remaining = &dst_results[1..][payload_results.len()..];
3534 for ty in remaining {
3535 match ty {
3536 ValType::I32 => self.instruction(I32Const(0)),
3537 ValType::I64 => self.instruction(I64Const(0)),
3538 ValType::F32 => self.instruction(F32Const(0.0.into())),
3539 ValType::F64 => self.instruction(F64Const(0.0.into())),
3540 _ => unreachable!(),
3541 }
3542 }
3543 }
3544 }
3545
3546 if src_i != src_cases_len - 1 {
3549 self.instruction(Br(src_cases_len - src_i - 1));
3550 }
3551 self.instruction(End); }
3553 }
3554
3555 fn translate_future(
3556 &mut self,
3557 src_ty: TypeFutureTableIndex,
3558 src: &Source<'_>,
3559 dst_ty: &InterfaceType,
3560 dst: &Destination,
3561 ) {
3562 let dst_ty = match dst_ty {
3563 InterfaceType::Future(t) => *t,
3564 _ => panic!("expected a `Future`"),
3565 };
3566 let transfer = self.module.import_future_transfer();
3567 self.translate_handle(src_ty.as_u32(), src, dst_ty.as_u32(), dst, transfer);
3568 }
3569
3570 fn translate_stream(
3571 &mut self,
3572 src_ty: TypeStreamTableIndex,
3573 src: &Source<'_>,
3574 dst_ty: &InterfaceType,
3575 dst: &Destination,
3576 ) {
3577 let dst_ty = match dst_ty {
3578 InterfaceType::Stream(t) => *t,
3579 _ => panic!("expected a `Stream`"),
3580 };
3581 let transfer = self.module.import_stream_transfer();
3582 self.translate_handle(src_ty.as_u32(), src, dst_ty.as_u32(), dst, transfer);
3583 }
3584
3585 fn translate_error_context(
3586 &mut self,
3587 src_ty: TypeComponentLocalErrorContextTableIndex,
3588 src: &Source<'_>,
3589 dst_ty: &InterfaceType,
3590 dst: &Destination,
3591 ) {
3592 let dst_ty = match dst_ty {
3593 InterfaceType::ErrorContext(t) => *t,
3594 _ => panic!("expected an `ErrorContext`"),
3595 };
3596 let transfer = self.module.import_error_context_transfer();
3597 self.translate_handle(src_ty.as_u32(), src, dst_ty.as_u32(), dst, transfer);
3598 }
3599
3600 fn translate_own(
3601 &mut self,
3602 src_ty: TypeResourceTableIndex,
3603 src: &Source<'_>,
3604 dst_ty: &InterfaceType,
3605 dst: &Destination,
3606 ) {
3607 let dst_ty = match dst_ty {
3608 InterfaceType::Own(t) => *t,
3609 _ => panic!("expected an `Own`"),
3610 };
3611 let transfer = self.module.import_resource_transfer_own();
3612 self.translate_handle(src_ty.as_u32(), src, dst_ty.as_u32(), dst, transfer);
3613 }
3614
3615 fn translate_borrow(
3616 &mut self,
3617 src_ty: TypeResourceTableIndex,
3618 src: &Source<'_>,
3619 dst_ty: &InterfaceType,
3620 dst: &Destination,
3621 ) {
3622 let dst_ty = match dst_ty {
3623 InterfaceType::Borrow(t) => *t,
3624 _ => panic!("expected an `Borrow`"),
3625 };
3626
3627 let transfer = self.module.import_resource_transfer_borrow();
3628 self.translate_handle(src_ty.as_u32(), src, dst_ty.as_u32(), dst, transfer);
3629 }
3630
3631 fn translate_handle(
3639 &mut self,
3640 src_ty: u32,
3641 src: &Source<'_>,
3642 dst_ty: u32,
3643 dst: &Destination,
3644 transfer: FuncIndex,
3645 ) {
3646 self.push_dst_addr(dst);
3647 match src {
3648 Source::Memory(mem) => self.i32_load(mem),
3649 Source::Stack(stack) => self.stack_get(stack, ValType::I32),
3650 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
3651 }
3652 self.instruction(I32Const(src_ty as i32));
3653 self.instruction(I32Const(dst_ty as i32));
3654 self.instruction(Call(transfer.as_u32()));
3655 match dst {
3656 Destination::Memory(mem) => self.i32_store(mem),
3657 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
3658 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
3659 }
3660 }
3661
3662 fn trap_if_not_flag(&mut self, flags_global: GlobalIndex, flag_to_test: i32, trap: Trap) {
3663 self.instruction(GlobalGet(flags_global.as_u32()));
3664 self.instruction(I32Const(flag_to_test));
3665 self.instruction(I32And);
3666 self.instruction(I32Eqz);
3667 self.instruction(If(BlockType::Empty));
3668 self.trap(trap);
3669 self.instruction(End);
3670 }
3671
3672 fn set_flag(&mut self, flags_global: GlobalIndex, flag_to_set: i32, value: bool) {
3673 self.instruction(GlobalGet(flags_global.as_u32()));
3674 if value {
3675 self.instruction(I32Const(flag_to_set));
3676 self.instruction(I32Or);
3677 } else {
3678 self.instruction(I32Const(!flag_to_set));
3679 self.instruction(I32And);
3680 }
3681 self.instruction(GlobalSet(flags_global.as_u32()));
3682 }
3683
3684 fn verify_aligned(&mut self, opts: &LinearMemoryOptions, addr_local: u32, align: u32) {
3685 if align == 1 {
3688 return;
3689 }
3690 self.instruction(LocalGet(addr_local));
3691 assert!(align.is_power_of_two());
3692 self.ptr_uconst(opts, align - 1);
3693 self.ptr_and(opts);
3694 self.ptr_if(opts, BlockType::Empty);
3695 self.trap(Trap::UnalignedPointer);
3696 self.instruction(End);
3697 }
3698
3699 fn assert_aligned(&mut self, ty: &InterfaceType, mem: &Memory) {
3700 let mem_opts = mem.mem_opts();
3701 if !self.module.tunables.debug_adapter_modules {
3702 return;
3703 }
3704 let align = self.types.align(mem_opts, ty);
3705 if align == 1 {
3706 return;
3707 }
3708 assert!(align.is_power_of_two());
3709 self.instruction(LocalGet(mem.addr.idx));
3710 self.ptr_uconst(mem_opts, mem.offset);
3711 self.ptr_add(mem_opts);
3712 self.ptr_uconst(mem_opts, align - 1);
3713 self.ptr_and(mem_opts);
3714 self.ptr_if(mem_opts, BlockType::Empty);
3715 self.trap(Trap::DebugAssertPointerAligned);
3716 self.instruction(End);
3717 }
3718
3719 fn malloc<'c>(&mut self, opts: &'c Options, size: MallocSize, align: u32) -> Memory<'c> {
3720 match &opts.data_model {
3721 DataModel::Gc {} => todo!("CM+GC"),
3722 DataModel::LinearMemory(mem_opts) => {
3723 let realloc = mem_opts.realloc.unwrap();
3724 self.ptr_uconst(mem_opts, 0);
3725 self.ptr_uconst(mem_opts, 0);
3726 self.ptr_uconst(mem_opts, align);
3727 match size {
3728 MallocSize::Const(size) => self.ptr_uconst(mem_opts, size),
3729 MallocSize::Local(idx) => self.instruction(LocalGet(idx)),
3730 }
3731 self.instruction(Call(realloc.as_u32()));
3732 let addr = self.local_set_new_tmp(mem_opts.ptr());
3733 self.memory_operand(opts, addr, align)
3734 }
3735 }
3736 }
3737
3738 fn memory_operand<'c>(&mut self, opts: &'c Options, addr: TempLocal, align: u32) -> Memory<'c> {
3739 let ret = Memory {
3740 addr,
3741 offset: 0,
3742 opts,
3743 };
3744 self.verify_aligned(opts.data_model.unwrap_memory(), ret.addr.idx, align);
3745 ret
3746 }
3747
3748 fn local_tee_new_tmp(&mut self, ty: ValType) -> TempLocal {
3754 self.gen_temp_local(ty, LocalTee)
3755 }
3756
3757 fn local_set_new_tmp(&mut self, ty: ValType) -> TempLocal {
3760 self.gen_temp_local(ty, LocalSet)
3761 }
3762
3763 fn local_get_tmp(&mut self, local: &TempLocal) {
3764 self.instruction(LocalGet(local.idx));
3765 }
3766
3767 fn gen_temp_local(&mut self, ty: ValType, insn: fn(u32) -> Instruction<'static>) -> TempLocal {
3768 if let Some(idx) = self.free_locals.get_mut(&ty).and_then(|v| v.pop()) {
3771 self.instruction(insn(idx));
3772 return TempLocal {
3773 ty,
3774 idx,
3775 needs_free: true,
3776 };
3777 }
3778
3779 let locals = &mut self.module.funcs[self.result].locals;
3781 match locals.last_mut() {
3782 Some((cnt, prev_ty)) if ty == *prev_ty => *cnt += 1,
3783 _ => locals.push((1, ty)),
3784 }
3785 self.nlocals += 1;
3786 let idx = self.nlocals - 1;
3787 self.instruction(insn(idx));
3788 TempLocal {
3789 ty,
3790 idx,
3791 needs_free: true,
3792 }
3793 }
3794
3795 fn free_temp_local(&mut self, mut local: TempLocal) {
3798 assert!(local.needs_free);
3799 self.free_locals
3800 .entry(local.ty)
3801 .or_insert(Vec::new())
3802 .push(local.idx);
3803 local.needs_free = false;
3804 }
3805
3806 fn instruction(&mut self, instr: Instruction) {
3807 instr.encode(&mut self.code);
3808 }
3809
3810 fn trap(&mut self, trap: Trap) {
3811 let trap_func = self.module.import_trap();
3812 self.instruction(I32Const(trap as i32));
3813 self.instruction(Call(trap_func.as_u32()));
3814 self.instruction(Unreachable);
3815 }
3816
3817 fn flush_code(&mut self) {
3822 if self.code.is_empty() {
3823 return;
3824 }
3825 self.module.funcs[self.result]
3826 .body
3827 .push(Body::Raw(mem::take(&mut self.code)));
3828 }
3829
3830 fn finish(mut self) {
3831 self.instruction(End);
3834 self.flush_code();
3835
3836 self.module.funcs[self.result].filled_in = true;
3839 }
3840
3841 fn stack_get(&mut self, stack: &Stack<'_>, dst_ty: ValType) {
3849 assert_eq!(stack.locals.len(), 1);
3850 let (idx, src_ty) = stack.locals[0];
3851 self.instruction(LocalGet(idx));
3852 match (src_ty, dst_ty) {
3853 (ValType::I32, ValType::I32)
3854 | (ValType::I64, ValType::I64)
3855 | (ValType::F32, ValType::F32)
3856 | (ValType::F64, ValType::F64) => {}
3857
3858 (ValType::I32, ValType::F32) => self.instruction(F32ReinterpretI32),
3859 (ValType::I64, ValType::I32) => {
3860 self.assert_i64_upper_bits_not_set(idx);
3861 self.instruction(I32WrapI64);
3862 }
3863 (ValType::I64, ValType::F64) => self.instruction(F64ReinterpretI64),
3864 (ValType::I64, ValType::F32) => {
3865 self.assert_i64_upper_bits_not_set(idx);
3866 self.instruction(I32WrapI64);
3867 self.instruction(F32ReinterpretI32);
3868 }
3869
3870 (ValType::I32, ValType::I64)
3872 | (ValType::I32, ValType::F64)
3873 | (ValType::F32, ValType::I32)
3874 | (ValType::F32, ValType::I64)
3875 | (ValType::F32, ValType::F64)
3876 | (ValType::F64, ValType::I32)
3877 | (ValType::F64, ValType::I64)
3878 | (ValType::F64, ValType::F32)
3879
3880 | (ValType::Ref(_), _)
3882 | (_, ValType::Ref(_))
3883 | (ValType::V128, _)
3884 | (_, ValType::V128) => {
3885 panic!("cannot get {dst_ty:?} from {src_ty:?} local");
3886 }
3887 }
3888 }
3889
3890 fn assert_i64_upper_bits_not_set(&mut self, local: u32) {
3891 if !self.module.tunables.debug_adapter_modules {
3892 return;
3893 }
3894 self.instruction(LocalGet(local));
3895 self.instruction(I64Const(32));
3896 self.instruction(I64ShrU);
3897 self.instruction(I32WrapI64);
3898 self.instruction(If(BlockType::Empty));
3899 self.trap(Trap::DebugAssertUpperBitsUnset);
3900 self.instruction(End);
3901 }
3902
3903 fn stack_set(&mut self, dst_tys: &[ValType], src_ty: ValType) {
3909 assert_eq!(dst_tys.len(), 1);
3910 let dst_ty = dst_tys[0];
3911 match (src_ty, dst_ty) {
3912 (ValType::I32, ValType::I32)
3913 | (ValType::I64, ValType::I64)
3914 | (ValType::F32, ValType::F32)
3915 | (ValType::F64, ValType::F64) => {}
3916
3917 (ValType::F32, ValType::I32) => self.instruction(I32ReinterpretF32),
3918 (ValType::I32, ValType::I64) => self.instruction(I64ExtendI32U),
3919 (ValType::F64, ValType::I64) => self.instruction(I64ReinterpretF64),
3920 (ValType::F32, ValType::I64) => {
3921 self.instruction(I32ReinterpretF32);
3922 self.instruction(I64ExtendI32U);
3923 }
3924
3925 (ValType::I64, ValType::I32)
3927 | (ValType::F64, ValType::I32)
3928 | (ValType::I32, ValType::F32)
3929 | (ValType::I64, ValType::F32)
3930 | (ValType::F64, ValType::F32)
3931 | (ValType::I32, ValType::F64)
3932 | (ValType::I64, ValType::F64)
3933 | (ValType::F32, ValType::F64)
3934
3935 | (ValType::Ref(_), _)
3937 | (_, ValType::Ref(_))
3938 | (ValType::V128, _)
3939 | (_, ValType::V128) => {
3940 panic!("cannot get {dst_ty:?} from {src_ty:?} local");
3941 }
3942 }
3943 }
3944
3945 fn i32_load8u(&mut self, mem: &Memory) {
3946 self.instruction(LocalGet(mem.addr.idx));
3947 self.instruction(I32Load8U(mem.memarg(0)));
3948 }
3949
3950 fn i32_load8s(&mut self, mem: &Memory) {
3951 self.instruction(LocalGet(mem.addr.idx));
3952 self.instruction(I32Load8S(mem.memarg(0)));
3953 }
3954
3955 fn i32_load16u(&mut self, mem: &Memory) {
3956 self.instruction(LocalGet(mem.addr.idx));
3957 self.instruction(I32Load16U(mem.memarg(1)));
3958 }
3959
3960 fn i32_load16s(&mut self, mem: &Memory) {
3961 self.instruction(LocalGet(mem.addr.idx));
3962 self.instruction(I32Load16S(mem.memarg(1)));
3963 }
3964
3965 fn i32_load(&mut self, mem: &Memory) {
3966 self.instruction(LocalGet(mem.addr.idx));
3967 self.instruction(I32Load(mem.memarg(2)));
3968 }
3969
3970 fn i64_load(&mut self, mem: &Memory) {
3971 self.instruction(LocalGet(mem.addr.idx));
3972 self.instruction(I64Load(mem.memarg(3)));
3973 }
3974
3975 fn ptr_load(&mut self, mem: &Memory) {
3976 if mem.mem_opts().memory64 {
3977 self.i64_load(mem);
3978 } else {
3979 self.i32_load(mem);
3980 }
3981 }
3982
3983 fn ptr_add(&mut self, opts: &LinearMemoryOptions) {
3984 if opts.memory64 {
3985 self.instruction(I64Add);
3986 } else {
3987 self.instruction(I32Add);
3988 }
3989 }
3990
3991 fn ptr_sub(&mut self, opts: &LinearMemoryOptions) {
3992 if opts.memory64 {
3993 self.instruction(I64Sub);
3994 } else {
3995 self.instruction(I32Sub);
3996 }
3997 }
3998
3999 fn ptr_mul(&mut self, opts: &LinearMemoryOptions) {
4000 if opts.memory64 {
4001 self.instruction(I64Mul);
4002 } else {
4003 self.instruction(I32Mul);
4004 }
4005 }
4006
4007 fn ptr_ge_u(&mut self, opts: &LinearMemoryOptions) {
4008 if opts.memory64 {
4009 self.instruction(I64GeU);
4010 } else {
4011 self.instruction(I32GeU);
4012 }
4013 }
4014
4015 fn ptr_lt_u(&mut self, opts: &LinearMemoryOptions) {
4016 if opts.memory64 {
4017 self.instruction(I64LtU);
4018 } else {
4019 self.instruction(I32LtU);
4020 }
4021 }
4022
4023 fn ptr_shl(&mut self, opts: &LinearMemoryOptions) {
4024 if opts.memory64 {
4025 self.instruction(I64Shl);
4026 } else {
4027 self.instruction(I32Shl);
4028 }
4029 }
4030
4031 fn ptr_eqz(&mut self, opts: &LinearMemoryOptions) {
4032 if opts.memory64 {
4033 self.instruction(I64Eqz);
4034 } else {
4035 self.instruction(I32Eqz);
4036 }
4037 }
4038
4039 fn ptr_uconst(&mut self, opts: &LinearMemoryOptions, val: u32) {
4040 if opts.memory64 {
4041 self.instruction(I64Const(val.into()));
4042 } else {
4043 self.instruction(I32Const(val as i32));
4044 }
4045 }
4046
4047 fn ptr_iconst(&mut self, opts: &LinearMemoryOptions, val: i32) {
4048 if opts.memory64 {
4049 self.instruction(I64Const(val.into()));
4050 } else {
4051 self.instruction(I32Const(val));
4052 }
4053 }
4054
4055 fn ptr_eq(&mut self, opts: &LinearMemoryOptions) {
4056 if opts.memory64 {
4057 self.instruction(I64Eq);
4058 } else {
4059 self.instruction(I32Eq);
4060 }
4061 }
4062
4063 fn ptr_ne(&mut self, opts: &LinearMemoryOptions) {
4064 if opts.memory64 {
4065 self.instruction(I64Ne);
4066 } else {
4067 self.instruction(I32Ne);
4068 }
4069 }
4070
4071 fn ptr_and(&mut self, opts: &LinearMemoryOptions) {
4072 if opts.memory64 {
4073 self.instruction(I64And);
4074 } else {
4075 self.instruction(I32And);
4076 }
4077 }
4078
4079 fn ptr_or(&mut self, opts: &LinearMemoryOptions) {
4080 if opts.memory64 {
4081 self.instruction(I64Or);
4082 } else {
4083 self.instruction(I32Or);
4084 }
4085 }
4086
4087 fn ptr_xor(&mut self, opts: &LinearMemoryOptions) {
4088 if opts.memory64 {
4089 self.instruction(I64Xor);
4090 } else {
4091 self.instruction(I32Xor);
4092 }
4093 }
4094
4095 fn ptr_if(&mut self, opts: &LinearMemoryOptions, ty: BlockType) {
4096 if opts.memory64 {
4097 self.instruction(I64Const(0));
4098 self.instruction(I64Ne);
4099 }
4100 self.instruction(If(ty));
4101 }
4102
4103 fn ptr_br_if(&mut self, opts: &LinearMemoryOptions, depth: u32) {
4104 if opts.memory64 {
4105 self.instruction(I64Const(0));
4106 self.instruction(I64Ne);
4107 }
4108 self.instruction(BrIf(depth));
4109 }
4110
4111 fn f32_load(&mut self, mem: &Memory) {
4112 self.instruction(LocalGet(mem.addr.idx));
4113 self.instruction(F32Load(mem.memarg(2)));
4114 }
4115
4116 fn f64_load(&mut self, mem: &Memory) {
4117 self.instruction(LocalGet(mem.addr.idx));
4118 self.instruction(F64Load(mem.memarg(3)));
4119 }
4120
4121 fn push_dst_addr(&mut self, dst: &Destination) {
4122 if let Destination::Memory(mem) = dst {
4123 self.instruction(LocalGet(mem.addr.idx));
4124 }
4125 }
4126
4127 fn i32_store8(&mut self, mem: &Memory) {
4128 self.instruction(I32Store8(mem.memarg(0)));
4129 }
4130
4131 fn i32_store16(&mut self, mem: &Memory) {
4132 self.instruction(I32Store16(mem.memarg(1)));
4133 }
4134
4135 fn i32_store(&mut self, mem: &Memory) {
4136 self.instruction(I32Store(mem.memarg(2)));
4137 }
4138
4139 fn i64_store(&mut self, mem: &Memory) {
4140 self.instruction(I64Store(mem.memarg(3)));
4141 }
4142
4143 fn ptr_store(&mut self, mem: &Memory) {
4144 if mem.mem_opts().memory64 {
4145 self.i64_store(mem);
4146 } else {
4147 self.i32_store(mem);
4148 }
4149 }
4150
4151 fn f32_store(&mut self, mem: &Memory) {
4152 self.instruction(F32Store(mem.memarg(2)));
4153 }
4154
4155 fn f64_store(&mut self, mem: &Memory) {
4156 self.instruction(F64Store(mem.memarg(3)));
4157 }
4158}
4159
4160impl<'a> Source<'a> {
4161 fn record_field_srcs<'b>(
4168 &'b self,
4169 types: &'b ComponentTypesBuilder,
4170 fields: impl IntoIterator<Item = InterfaceType> + 'b,
4171 ) -> impl Iterator<Item = Source<'a>> + 'b
4172 where
4173 'a: 'b,
4174 {
4175 let mut offset = 0;
4176 fields.into_iter().map(move |ty| match self {
4177 Source::Memory(mem) => {
4178 let mem = next_field_offset(&mut offset, types, &ty, mem);
4179 Source::Memory(mem)
4180 }
4181 Source::Stack(stack) => {
4182 let cnt = types.flat_types(&ty).unwrap().len() as u32;
4183 offset += cnt;
4184 Source::Stack(stack.slice((offset - cnt) as usize..offset as usize))
4185 }
4186 Source::Struct(_) => todo!(),
4187 Source::Array(_) => todo!(),
4188 })
4189 }
4190
4191 fn payload_src(
4193 &self,
4194 types: &ComponentTypesBuilder,
4195 info: &VariantInfo,
4196 case: Option<&InterfaceType>,
4197 ) -> Source<'a> {
4198 match self {
4199 Source::Stack(s) => {
4200 let flat_len = match case {
4201 Some(case) => types.flat_types(case).unwrap().len(),
4202 None => 0,
4203 };
4204 Source::Stack(s.slice(1..s.locals.len()).slice(0..flat_len))
4205 }
4206 Source::Memory(mem) => {
4207 let mem = if mem.mem_opts().memory64 {
4208 mem.bump(info.payload_offset64)
4209 } else {
4210 mem.bump(info.payload_offset32)
4211 };
4212 Source::Memory(mem)
4213 }
4214 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
4215 }
4216 }
4217
4218 fn opts(&self) -> &'a Options {
4219 match self {
4220 Source::Stack(s) => s.opts,
4221 Source::Memory(mem) => mem.opts,
4222 Source::Struct(s) => s.opts,
4223 Source::Array(a) => a.opts,
4224 }
4225 }
4226}
4227
4228impl<'a> Destination<'a> {
4229 fn record_field_dsts<'b, I>(
4231 &'b self,
4232 types: &'b ComponentTypesBuilder,
4233 fields: I,
4234 ) -> impl Iterator<Item = Destination<'b>> + use<'b, I>
4235 where
4236 'a: 'b,
4237 I: IntoIterator<Item = InterfaceType> + 'b,
4238 {
4239 let mut offset = 0;
4240 fields.into_iter().map(move |ty| match self {
4241 Destination::Memory(mem) => {
4242 let mem = next_field_offset(&mut offset, types, &ty, mem);
4243 Destination::Memory(mem)
4244 }
4245 Destination::Stack(s, opts) => {
4246 let cnt = types.flat_types(&ty).unwrap().len() as u32;
4247 offset += cnt;
4248 Destination::Stack(&s[(offset - cnt) as usize..offset as usize], opts)
4249 }
4250 Destination::Struct(_) => todo!(),
4251 Destination::Array(_) => todo!(),
4252 })
4253 }
4254
4255 fn payload_dst(
4257 &self,
4258 types: &ComponentTypesBuilder,
4259 info: &VariantInfo,
4260 case: Option<&InterfaceType>,
4261 ) -> Destination<'_> {
4262 match self {
4263 Destination::Stack(s, opts) => {
4264 let flat_len = match case {
4265 Some(case) => types.flat_types(case).unwrap().len(),
4266 None => 0,
4267 };
4268 Destination::Stack(&s[1..][..flat_len], opts)
4269 }
4270 Destination::Memory(mem) => {
4271 let mem = if mem.mem_opts().memory64 {
4272 mem.bump(info.payload_offset64)
4273 } else {
4274 mem.bump(info.payload_offset32)
4275 };
4276 Destination::Memory(mem)
4277 }
4278 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
4279 }
4280 }
4281
4282 fn opts(&self) -> &'a Options {
4283 match self {
4284 Destination::Stack(_, opts) => opts,
4285 Destination::Memory(mem) => mem.opts,
4286 Destination::Struct(s) => s.opts,
4287 Destination::Array(a) => a.opts,
4288 }
4289 }
4290}
4291
4292fn next_field_offset<'a>(
4293 offset: &mut u32,
4294 types: &ComponentTypesBuilder,
4295 field: &InterfaceType,
4296 mem: &Memory<'a>,
4297) -> Memory<'a> {
4298 let abi = types.canonical_abi(field);
4299 let offset = if mem.mem_opts().memory64 {
4300 abi.next_field64(offset)
4301 } else {
4302 abi.next_field32(offset)
4303 };
4304 mem.bump(offset)
4305}
4306
4307impl<'a> Memory<'a> {
4308 fn memarg(&self, align: u32) -> MemArg {
4309 MemArg {
4310 offset: u64::from(self.offset),
4311 align,
4312 memory_index: self.mem_opts().memory.unwrap().as_u32(),
4313 }
4314 }
4315
4316 fn bump(&self, offset: u32) -> Memory<'a> {
4317 Memory {
4318 opts: self.opts,
4319 addr: TempLocal::new(self.addr.idx, self.addr.ty),
4320 offset: self.offset + offset,
4321 }
4322 }
4323}
4324
4325impl<'a> Stack<'a> {
4326 fn slice(&self, range: Range<usize>) -> Stack<'a> {
4327 Stack {
4328 locals: &self.locals[range],
4329 opts: self.opts,
4330 }
4331 }
4332}
4333
4334struct VariantCase<'a> {
4335 src_i: u32,
4336 src_ty: Option<&'a InterfaceType>,
4337 dst_i: u32,
4338 dst_ty: Option<&'a InterfaceType>,
4339}
4340
4341fn variant_info<'a, I>(types: &ComponentTypesBuilder, cases: I) -> VariantInfo
4342where
4343 I: IntoIterator<Item = Option<&'a InterfaceType>>,
4344 I::IntoIter: ExactSizeIterator,
4345{
4346 VariantInfo::new(
4347 cases
4348 .into_iter()
4349 .map(|ty| ty.map(|ty| types.canonical_abi(ty))),
4350 )
4351 .0
4352}
4353
4354struct SequenceLoopState {
4356 remaining: TempLocal,
4357 cur_src_ptr: TempLocal,
4358 cur_dst_ptr: TempLocal,
4359}
4360
4361struct SequenceTranslation<'a> {
4365 src_len: TempLocal,
4366 src_mem: Memory<'a>,
4367 dst_mem: Memory<'a>,
4368 src_opts: &'a Options,
4369 dst_opts: &'a Options,
4370 src_mem_opts: &'a LinearMemoryOptions,
4371 dst_mem_opts: &'a LinearMemoryOptions,
4372 loop_state: Option<SequenceLoopState>,
4373}
4374
4375enum MallocSize {
4376 Const(u32),
4377 Local(u32),
4378}
4379
4380struct WasmString<'a> {
4381 ptr: TempLocal,
4382 len: TempLocal,
4383 opts: &'a Options,
4384}
4385
4386struct TempLocal {
4387 idx: u32,
4388 ty: ValType,
4389 needs_free: bool,
4390}
4391
4392impl TempLocal {
4393 fn new(idx: u32, ty: ValType) -> TempLocal {
4394 TempLocal {
4395 idx,
4396 ty,
4397 needs_free: false,
4398 }
4399 }
4400}
4401
4402impl std::ops::Drop for TempLocal {
4403 fn drop(&mut self) {
4404 if self.needs_free {
4405 panic!("temporary local not free'd");
4406 }
4407 }
4408}
4409
4410impl From<FlatType> for ValType {
4411 fn from(ty: FlatType) -> ValType {
4412 match ty {
4413 FlatType::I32 => ValType::I32,
4414 FlatType::I64 => ValType::I64,
4415 FlatType::F32 => ValType::F32,
4416 FlatType::F64 => ValType::F64,
4417 }
4418 }
4419}