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, TypeOptionIndex, TypeRecordIndex,
24 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 self.set_flag(adapter.lower.flags, FLAG_MAY_LEAVE, false);
852 self.translate_results(adapter, ¶m_locals, &result_locals);
853 self.set_flag(adapter.lower.flags, FLAG_MAY_LEAVE, true);
854
855 if let Some(func) = adapter.lift.post_return {
858 for (result, _) in result_locals.iter() {
859 self.instruction(LocalGet(*result));
860 }
861 self.instruction(Call(func.as_u32()));
862 }
863
864 for tmp in temps {
865 self.free_temp_local(tmp);
866 }
867
868 if self.emit_resource_call || self.module.tunables.concurrency_support {
869 let exit_sync_call = self.module.import_exit_sync_call();
873 self.instruction(Call(exit_sync_call.as_u32()));
874 }
875
876 if self.module.tunables.concurrency_support {
877 if let Some(old_task_may_block) = old_task_may_block {
879 let task_may_block = self.module.import_task_may_block();
880 self.instruction(LocalGet(old_task_may_block.idx));
881 self.instruction(GlobalSet(task_may_block.as_u32()));
882 self.free_temp_local(old_task_may_block);
883 }
884 }
885
886 self.finish()
887 }
888
889 fn translate_params(&mut self, adapter: &AdapterData, param_locals: &[(u32, ValType)]) {
890 let src_tys = self.types[adapter.lower.ty].params;
891 let src_tys = self.types[src_tys]
892 .types
893 .iter()
894 .copied()
895 .collect::<Vec<_>>();
896 let dst_tys = self.types[adapter.lift.ty].params;
897 let dst_tys = self.types[dst_tys]
898 .types
899 .iter()
900 .copied()
901 .collect::<Vec<_>>();
902 let lift_opts = &adapter.lift.options;
903 let lower_opts = &adapter.lower.options;
904
905 assert_eq!(src_tys.len(), dst_tys.len());
907
908 let max_flat_params = if adapter.lower.options.async_ {
912 MAX_FLAT_ASYNC_PARAMS
913 } else {
914 MAX_FLAT_PARAMS
915 };
916 let src_flat =
917 self.types
918 .flatten_types(lower_opts, max_flat_params, src_tys.iter().copied());
919 let dst_flat =
920 self.types
921 .flatten_types(lift_opts, MAX_FLAT_PARAMS, dst_tys.iter().copied());
922
923 let src = if let Some(flat) = &src_flat {
924 Source::Stack(Stack {
925 locals: ¶m_locals[..flat.len()],
926 opts: lower_opts,
927 })
928 } else {
929 let lower_mem_opts = lower_opts.data_model.unwrap_memory();
933 let (addr, ty) = param_locals[0];
934 assert_eq!(ty, lower_mem_opts.ptr());
935 let align = src_tys
936 .iter()
937 .map(|t| self.types.align(lower_mem_opts, t))
938 .max()
939 .unwrap_or(1);
940 Source::Memory(self.memory_operand(lower_opts, TempLocal::new(addr, ty), align))
941 };
942
943 let dst = if let Some(flat) = &dst_flat {
944 Destination::Stack(flat, lift_opts)
945 } else {
946 let abi = CanonicalAbiInfo::record(dst_tys.iter().map(|t| self.types.canonical_abi(t)));
947 match lift_opts.data_model {
948 DataModel::Gc {} => todo!("CM+GC"),
949 DataModel::LinearMemory(LinearMemoryOptions { memory64, .. }) => {
950 let (size, align) = if memory64 {
951 (abi.size64, abi.align64)
952 } else {
953 (abi.size32, abi.align32)
954 };
955
956 let size = MallocSize::Const(size);
959 Destination::Memory(self.malloc(lift_opts, size, align))
960 }
961 }
962 };
963
964 let srcs = src
965 .record_field_srcs(self.types, src_tys.iter().copied())
966 .zip(src_tys.iter());
967 let dsts = dst
968 .record_field_dsts(self.types, dst_tys.iter().copied())
969 .zip(dst_tys.iter());
970 for ((src, src_ty), (dst, dst_ty)) in srcs.zip(dsts) {
971 self.translate(&src_ty, &src, &dst_ty, &dst);
972 }
973
974 if let Destination::Memory(mem) = dst {
978 self.instruction(LocalGet(mem.addr.idx));
979 self.free_temp_local(mem.addr);
980 }
981 }
982
983 fn translate_results(
984 &mut self,
985 adapter: &AdapterData,
986 param_locals: &[(u32, ValType)],
987 result_locals: &[(u32, ValType)],
988 ) {
989 let src_tys = self.types[adapter.lift.ty].results;
990 let src_tys = self.types[src_tys]
991 .types
992 .iter()
993 .copied()
994 .collect::<Vec<_>>();
995 let dst_tys = self.types[adapter.lower.ty].results;
996 let dst_tys = self.types[dst_tys]
997 .types
998 .iter()
999 .copied()
1000 .collect::<Vec<_>>();
1001 let lift_opts = &adapter.lift.options;
1002 let lower_opts = &adapter.lower.options;
1003
1004 let src_flat = self
1005 .types
1006 .flatten_lifting_types(lift_opts, src_tys.iter().copied());
1007 let dst_flat = self
1008 .types
1009 .flatten_lowering_types(lower_opts, dst_tys.iter().copied());
1010
1011 let src = if src_flat.is_some() {
1012 Source::Stack(Stack {
1013 locals: result_locals,
1014 opts: lift_opts,
1015 })
1016 } else {
1017 let lift_mem_opts = lift_opts.data_model.unwrap_memory();
1022 let align = src_tys
1023 .iter()
1024 .map(|t| self.types.align(lift_mem_opts, t))
1025 .max()
1026 .unwrap_or(1);
1027 assert_eq!(
1028 result_locals.len(),
1029 if lower_opts.async_ || lift_opts.async_ {
1030 2
1031 } else {
1032 1
1033 }
1034 );
1035 let (addr, ty) = result_locals[0];
1036 assert_eq!(ty, lift_opts.data_model.unwrap_memory().ptr());
1037 Source::Memory(self.memory_operand(lift_opts, TempLocal::new(addr, ty), align))
1038 };
1039
1040 let dst = if let Some(flat) = &dst_flat {
1041 Destination::Stack(flat, lower_opts)
1042 } else {
1043 let lower_mem_opts = lower_opts.data_model.unwrap_memory();
1047 let align = dst_tys
1048 .iter()
1049 .map(|t| self.types.align(lower_mem_opts, t))
1050 .max()
1051 .unwrap_or(1);
1052 let (addr, ty) = *param_locals.last().expect("no retptr");
1053 assert_eq!(ty, lower_opts.data_model.unwrap_memory().ptr());
1054 Destination::Memory(self.memory_operand(lower_opts, TempLocal::new(addr, ty), align))
1055 };
1056
1057 let srcs = src
1058 .record_field_srcs(self.types, src_tys.iter().copied())
1059 .zip(src_tys.iter());
1060 let dsts = dst
1061 .record_field_dsts(self.types, dst_tys.iter().copied())
1062 .zip(dst_tys.iter());
1063 for ((src, src_ty), (dst, dst_ty)) in srcs.zip(dsts) {
1064 self.translate(&src_ty, &src, &dst_ty, &dst);
1065 }
1066 }
1067
1068 fn translate(
1069 &mut self,
1070 src_ty: &InterfaceType,
1071 src: &Source<'_>,
1072 dst_ty: &InterfaceType,
1073 dst: &Destination,
1074 ) {
1075 if let Source::Memory(mem) = src {
1076 self.assert_aligned(src_ty, mem);
1077 }
1078 if let Destination::Memory(mem) = dst {
1079 self.assert_aligned(dst_ty, mem);
1080 }
1081
1082 let cost = match src_ty {
1112 InterfaceType::Bool
1116 | InterfaceType::U8
1117 | InterfaceType::S8
1118 | InterfaceType::U16
1119 | InterfaceType::S16
1120 | InterfaceType::U32
1121 | InterfaceType::S32
1122 | InterfaceType::U64
1123 | InterfaceType::S64
1124 | InterfaceType::Float32
1125 | InterfaceType::Float64 => 0,
1126
1127 InterfaceType::Char => 1,
1130
1131 InterfaceType::String => 40,
1134
1135 InterfaceType::List(_) => 40,
1138
1139 InterfaceType::Flags(i) => {
1140 let count = self.module.types[*i].names.len();
1141 match FlagsSize::from_count(count) {
1142 FlagsSize::Size0 => 0,
1143 FlagsSize::Size1 | FlagsSize::Size2 => 1,
1144 FlagsSize::Size4Plus(n) => n.into(),
1145 }
1146 }
1147
1148 InterfaceType::Record(i) => self.types[*i].fields.len(),
1149 InterfaceType::Tuple(i) => self.types[*i].types.len(),
1150 InterfaceType::Variant(i) => self.types[*i].cases.len(),
1151 InterfaceType::Enum(i) => self.types[*i].names.len(),
1152
1153 InterfaceType::Option(_) | InterfaceType::Result(_) => 2,
1155
1156 InterfaceType::Own(_)
1158 | InterfaceType::Borrow(_)
1159 | InterfaceType::Future(_)
1160 | InterfaceType::Stream(_)
1161 | InterfaceType::ErrorContext(_) => 1,
1162 InterfaceType::FixedLengthList(i) => self.types[*i].size as usize,
1163 };
1164
1165 match self.fuel.checked_sub(cost) {
1166 Some(n) => {
1172 self.fuel = n;
1173 match src_ty {
1174 InterfaceType::Bool => self.translate_bool(src, dst_ty, dst),
1175 InterfaceType::U8 => self.translate_u8(src, dst_ty, dst),
1176 InterfaceType::S8 => self.translate_s8(src, dst_ty, dst),
1177 InterfaceType::U16 => self.translate_u16(src, dst_ty, dst),
1178 InterfaceType::S16 => self.translate_s16(src, dst_ty, dst),
1179 InterfaceType::U32 => self.translate_u32(src, dst_ty, dst),
1180 InterfaceType::S32 => self.translate_s32(src, dst_ty, dst),
1181 InterfaceType::U64 => self.translate_u64(src, dst_ty, dst),
1182 InterfaceType::S64 => self.translate_s64(src, dst_ty, dst),
1183 InterfaceType::Float32 => self.translate_f32(src, dst_ty, dst),
1184 InterfaceType::Float64 => self.translate_f64(src, dst_ty, dst),
1185 InterfaceType::Char => self.translate_char(src, dst_ty, dst),
1186 InterfaceType::String => self.translate_string(src, dst_ty, dst),
1187 InterfaceType::List(t) => self.translate_list(*t, src, dst_ty, dst),
1188 InterfaceType::Record(t) => self.translate_record(*t, src, dst_ty, dst),
1189 InterfaceType::Flags(f) => self.translate_flags(*f, src, dst_ty, dst),
1190 InterfaceType::Tuple(t) => self.translate_tuple(*t, src, dst_ty, dst),
1191 InterfaceType::Variant(v) => self.translate_variant(*v, src, dst_ty, dst),
1192 InterfaceType::Enum(t) => self.translate_enum(*t, src, dst_ty, dst),
1193 InterfaceType::Option(t) => self.translate_option(*t, src, dst_ty, dst),
1194 InterfaceType::Result(t) => self.translate_result(*t, src, dst_ty, dst),
1195 InterfaceType::Own(t) => self.translate_own(*t, src, dst_ty, dst),
1196 InterfaceType::Borrow(t) => self.translate_borrow(*t, src, dst_ty, dst),
1197 InterfaceType::Future(t) => self.translate_future(*t, src, dst_ty, dst),
1198 InterfaceType::Stream(t) => self.translate_stream(*t, src, dst_ty, dst),
1199 InterfaceType::ErrorContext(t) => {
1200 self.translate_error_context(*t, src, dst_ty, dst)
1201 }
1202 InterfaceType::FixedLengthList(t) => {
1203 self.translate_fixed_length_list(*t, src, dst_ty, dst);
1204 }
1205 }
1206 }
1207
1208 None => {
1214 let src_loc = match src {
1215 Source::Stack(stack) => {
1219 for (i, ty) in stack
1220 .opts
1221 .flat_types(src_ty, self.types)
1222 .unwrap()
1223 .iter()
1224 .enumerate()
1225 {
1226 let stack = stack.slice(i..i + 1);
1227 self.stack_get(&stack, (*ty).into());
1228 }
1229 HelperLocation::Stack
1230 }
1231 Source::Memory(mem) => {
1236 self.push_mem_addr(mem);
1237 HelperLocation::Memory
1238 }
1239 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1240 };
1241 let dst_loc = match dst {
1242 Destination::Stack(..) => HelperLocation::Stack,
1243 Destination::Memory(mem) => {
1244 self.push_mem_addr(mem);
1245 HelperLocation::Memory
1246 }
1247 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1248 };
1249 let helper = self.module.translate_helper(Helper {
1255 src: HelperType {
1256 ty: *src_ty,
1257 opts: *src.opts(),
1258 loc: src_loc,
1259 },
1260 dst: HelperType {
1261 ty: *dst_ty,
1262 opts: *dst.opts(),
1263 loc: dst_loc,
1264 },
1265 });
1266 self.flush_code();
1269 self.module.funcs[self.result].body.push(Body::Call(helper));
1270
1271 if let Destination::Stack(tys, opts) = dst {
1280 let flat = self
1281 .types
1282 .flatten_types(opts, usize::MAX, [*dst_ty])
1283 .unwrap();
1284 assert_eq!(flat.len(), tys.len());
1285 let locals = flat
1286 .iter()
1287 .rev()
1288 .map(|ty| self.local_set_new_tmp(*ty))
1289 .collect::<Vec<_>>();
1290 for (ty, local) in tys.iter().zip(locals.into_iter().rev()) {
1291 self.instruction(LocalGet(local.idx));
1292 self.stack_set(std::slice::from_ref(ty), local.ty);
1293 self.free_temp_local(local);
1294 }
1295 }
1296 }
1297 }
1298 }
1299
1300 fn push_mem_addr(&mut self, mem: &Memory<'_>) {
1301 self.instruction(LocalGet(mem.addr.idx));
1302 if mem.offset != 0 {
1303 self.ptr_uconst(mem.mem_opts(), mem.offset);
1304 self.ptr_add(mem.mem_opts());
1305 }
1306 }
1307
1308 fn translate_bool(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1309 assert!(matches!(dst_ty, InterfaceType::Bool));
1311 self.push_dst_addr(dst);
1312
1313 self.instruction(I32Const(1));
1316 self.instruction(I32Const(0));
1317 match src {
1318 Source::Memory(mem) => self.i32_load8u(mem),
1319 Source::Stack(stack) => self.stack_get(stack, ValType::I32),
1320 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1321 }
1322 self.instruction(Select);
1323
1324 match dst {
1325 Destination::Memory(mem) => self.i32_store8(mem),
1326 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1327 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1328 }
1329 }
1330
1331 fn translate_u8(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1332 assert!(matches!(dst_ty, InterfaceType::U8));
1334 self.convert_u8_mask(src, dst, 0xff);
1335 }
1336
1337 fn convert_u8_mask(&mut self, src: &Source<'_>, dst: &Destination<'_>, mask: u8) {
1338 self.push_dst_addr(dst);
1339 let mut needs_mask = true;
1340 match src {
1341 Source::Memory(mem) => {
1342 self.i32_load8u(mem);
1343 needs_mask = mask != 0xff;
1344 }
1345 Source::Stack(stack) => {
1346 self.stack_get(stack, ValType::I32);
1347 }
1348 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1349 }
1350 if needs_mask {
1351 self.instruction(I32Const(i32::from(mask)));
1352 self.instruction(I32And);
1353 }
1354 match dst {
1355 Destination::Memory(mem) => self.i32_store8(mem),
1356 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1357 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1358 }
1359 }
1360
1361 fn translate_s8(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1362 assert!(matches!(dst_ty, InterfaceType::S8));
1364 self.push_dst_addr(dst);
1365 match src {
1366 Source::Memory(mem) => self.i32_load8s(mem),
1367 Source::Stack(stack) => {
1368 self.stack_get(stack, ValType::I32);
1369 self.instruction(I32Extend8S);
1370 }
1371 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1372 }
1373 match dst {
1374 Destination::Memory(mem) => self.i32_store8(mem),
1375 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1376 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1377 }
1378 }
1379
1380 fn translate_u16(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1381 assert!(matches!(dst_ty, InterfaceType::U16));
1383 self.convert_u16_mask(src, dst, 0xffff);
1384 }
1385
1386 fn convert_u16_mask(&mut self, src: &Source<'_>, dst: &Destination<'_>, mask: u16) {
1387 self.push_dst_addr(dst);
1388 let mut needs_mask = true;
1389 match src {
1390 Source::Memory(mem) => {
1391 self.i32_load16u(mem);
1392 needs_mask = mask != 0xffff;
1393 }
1394 Source::Stack(stack) => {
1395 self.stack_get(stack, ValType::I32);
1396 }
1397 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1398 }
1399 if needs_mask {
1400 self.instruction(I32Const(i32::from(mask)));
1401 self.instruction(I32And);
1402 }
1403 match dst {
1404 Destination::Memory(mem) => self.i32_store16(mem),
1405 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1406 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1407 }
1408 }
1409
1410 fn translate_s16(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1411 assert!(matches!(dst_ty, InterfaceType::S16));
1413 self.push_dst_addr(dst);
1414 match src {
1415 Source::Memory(mem) => self.i32_load16s(mem),
1416 Source::Stack(stack) => {
1417 self.stack_get(stack, ValType::I32);
1418 self.instruction(I32Extend16S);
1419 }
1420 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1421 }
1422 match dst {
1423 Destination::Memory(mem) => self.i32_store16(mem),
1424 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1425 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1426 }
1427 }
1428
1429 fn translate_u32(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1430 assert!(matches!(dst_ty, InterfaceType::U32));
1432 self.convert_u32_mask(src, dst, 0xffffffff)
1433 }
1434
1435 fn convert_u32_mask(&mut self, src: &Source<'_>, dst: &Destination<'_>, mask: u32) {
1436 self.push_dst_addr(dst);
1437 match src {
1438 Source::Memory(mem) => self.i32_load(mem),
1439 Source::Stack(stack) => self.stack_get(stack, ValType::I32),
1440 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1441 }
1442 if mask != 0xffffffff {
1443 self.instruction(I32Const(mask as i32));
1444 self.instruction(I32And);
1445 }
1446 match dst {
1447 Destination::Memory(mem) => self.i32_store(mem),
1448 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1449 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1450 }
1451 }
1452
1453 fn translate_s32(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1454 assert!(matches!(dst_ty, InterfaceType::S32));
1456 self.push_dst_addr(dst);
1457 match src {
1458 Source::Memory(mem) => self.i32_load(mem),
1459 Source::Stack(stack) => self.stack_get(stack, ValType::I32),
1460 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1461 }
1462 match dst {
1463 Destination::Memory(mem) => self.i32_store(mem),
1464 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1465 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1466 }
1467 }
1468
1469 fn translate_u64(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1470 assert!(matches!(dst_ty, InterfaceType::U64));
1472 self.push_dst_addr(dst);
1473 match src {
1474 Source::Memory(mem) => self.i64_load(mem),
1475 Source::Stack(stack) => self.stack_get(stack, ValType::I64),
1476 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1477 }
1478 match dst {
1479 Destination::Memory(mem) => self.i64_store(mem),
1480 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I64),
1481 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1482 }
1483 }
1484
1485 fn translate_s64(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1486 assert!(matches!(dst_ty, InterfaceType::S64));
1488 self.push_dst_addr(dst);
1489 match src {
1490 Source::Memory(mem) => self.i64_load(mem),
1491 Source::Stack(stack) => self.stack_get(stack, ValType::I64),
1492 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1493 }
1494 match dst {
1495 Destination::Memory(mem) => self.i64_store(mem),
1496 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I64),
1497 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1498 }
1499 }
1500
1501 fn translate_f32(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1502 assert!(matches!(dst_ty, InterfaceType::Float32));
1504 self.push_dst_addr(dst);
1505 match src {
1506 Source::Memory(mem) => self.f32_load(mem),
1507 Source::Stack(stack) => self.stack_get(stack, ValType::F32),
1508 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1509 }
1510 match dst {
1511 Destination::Memory(mem) => self.f32_store(mem),
1512 Destination::Stack(stack, _) => self.stack_set(stack, ValType::F32),
1513 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1514 }
1515 }
1516
1517 fn translate_f64(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1518 assert!(matches!(dst_ty, InterfaceType::Float64));
1520 self.push_dst_addr(dst);
1521 match src {
1522 Source::Memory(mem) => self.f64_load(mem),
1523 Source::Stack(stack) => self.stack_get(stack, ValType::F64),
1524 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1525 }
1526 match dst {
1527 Destination::Memory(mem) => self.f64_store(mem),
1528 Destination::Stack(stack, _) => self.stack_set(stack, ValType::F64),
1529 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1530 }
1531 }
1532
1533 fn translate_char(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1534 assert!(matches!(dst_ty, InterfaceType::Char));
1535 match src {
1536 Source::Memory(mem) => self.i32_load(mem),
1537 Source::Stack(stack) => self.stack_get(stack, ValType::I32),
1538 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1539 }
1540 let local = self.local_set_new_tmp(ValType::I32);
1541
1542 self.instruction(Block(BlockType::Empty));
1558 self.instruction(Block(BlockType::Empty));
1559 self.instruction(LocalGet(local.idx));
1560 self.instruction(I32Const(0xd800));
1561 self.instruction(I32Xor);
1562 self.instruction(I32Const(-0x110000));
1563 self.instruction(I32Add);
1564 self.instruction(I32Const(-0x10f800));
1565 self.instruction(I32LtU);
1566 self.instruction(BrIf(0));
1567 self.instruction(LocalGet(local.idx));
1568 self.instruction(I32Const(0x110000));
1569 self.instruction(I32Ne);
1570 self.instruction(BrIf(1));
1571 self.instruction(End);
1572 self.trap(Trap::InvalidChar);
1573 self.instruction(End);
1574
1575 self.push_dst_addr(dst);
1576 self.instruction(LocalGet(local.idx));
1577 match dst {
1578 Destination::Memory(mem) => {
1579 self.i32_store(mem);
1580 }
1581 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1582 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1583 }
1584
1585 self.free_temp_local(local);
1586 }
1587
1588 fn translate_string(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1589 assert!(matches!(dst_ty, InterfaceType::String));
1590 let src_opts = src.opts();
1591 let dst_opts = dst.opts();
1592
1593 let src_mem_opts = match &src_opts.data_model {
1594 DataModel::Gc {} => todo!("CM+GC"),
1595 DataModel::LinearMemory(opts) => opts,
1596 };
1597 let dst_mem_opts = match &dst_opts.data_model {
1598 DataModel::Gc {} => todo!("CM+GC"),
1599 DataModel::LinearMemory(opts) => opts,
1600 };
1601
1602 match src {
1607 Source::Stack(s) => {
1608 assert_eq!(s.locals.len(), 2);
1609 self.stack_get(&s.slice(0..1), src_mem_opts.ptr());
1610 self.stack_get(&s.slice(1..2), src_mem_opts.ptr());
1611 }
1612 Source::Memory(mem) => {
1613 self.ptr_load(mem);
1614 self.ptr_load(&mem.bump(src_mem_opts.ptr_size().into()));
1615 }
1616 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1617 }
1618 let src_len = self.local_set_new_tmp(src_mem_opts.ptr());
1619 let src_ptr = self.local_set_new_tmp(src_mem_opts.ptr());
1620 let src_str = WasmString {
1621 ptr: src_ptr,
1622 len: src_len,
1623 opts: src_opts,
1624 };
1625
1626 let dst_str = match src_opts.string_encoding {
1627 StringEncoding::Utf8 => match dst_opts.string_encoding {
1628 StringEncoding::Utf8 => self.string_copy(&src_str, FE::Utf8, dst_opts, FE::Utf8),
1629 StringEncoding::Utf16 => self.string_utf8_to_utf16(&src_str, dst_opts),
1630 StringEncoding::CompactUtf16 => {
1631 self.string_to_compact(&src_str, FE::Utf8, dst_opts)
1632 }
1633 },
1634
1635 StringEncoding::Utf16 => {
1636 self.verify_aligned(src_mem_opts, src_str.ptr.idx, 2);
1637 match dst_opts.string_encoding {
1638 StringEncoding::Utf8 => {
1639 self.string_deflate_to_utf8(&src_str, FE::Utf16, dst_opts)
1640 }
1641 StringEncoding::Utf16 => {
1642 self.string_copy(&src_str, FE::Utf16, dst_opts, FE::Utf16)
1643 }
1644 StringEncoding::CompactUtf16 => {
1645 self.string_to_compact(&src_str, FE::Utf16, dst_opts)
1646 }
1647 }
1648 }
1649
1650 StringEncoding::CompactUtf16 => {
1651 self.verify_aligned(src_mem_opts, src_str.ptr.idx, 2);
1652
1653 self.instruction(LocalGet(src_str.len.idx));
1656 self.ptr_uconst(src_mem_opts, UTF16_TAG);
1657 self.ptr_and(src_mem_opts);
1658 self.ptr_if(src_mem_opts, BlockType::Empty);
1659
1660 self.instruction(LocalGet(src_str.len.idx));
1664 self.ptr_uconst(src_mem_opts, UTF16_TAG);
1665 self.ptr_xor(src_mem_opts);
1666 self.instruction(LocalSet(src_str.len.idx));
1667 let s1 = match dst_opts.string_encoding {
1668 StringEncoding::Utf8 => {
1669 self.string_deflate_to_utf8(&src_str, FE::Utf16, dst_opts)
1670 }
1671 StringEncoding::Utf16 => {
1672 self.string_copy(&src_str, FE::Utf16, dst_opts, FE::Utf16)
1673 }
1674 StringEncoding::CompactUtf16 => {
1675 self.string_compact_utf16_to_compact(&src_str, dst_opts)
1676 }
1677 };
1678
1679 self.instruction(Else);
1680
1681 let s2 = match dst_opts.string_encoding {
1685 StringEncoding::Utf16 => {
1686 self.string_copy(&src_str, FE::Latin1, dst_opts, FE::Utf16)
1687 }
1688 StringEncoding::Utf8 => {
1689 self.string_deflate_to_utf8(&src_str, FE::Latin1, dst_opts)
1690 }
1691 StringEncoding::CompactUtf16 => {
1692 self.string_copy(&src_str, FE::Latin1, dst_opts, FE::Latin1)
1693 }
1694 };
1695 self.instruction(LocalGet(s2.ptr.idx));
1698 self.instruction(LocalSet(s1.ptr.idx));
1699 self.instruction(LocalGet(s2.len.idx));
1700 self.instruction(LocalSet(s1.len.idx));
1701 self.instruction(End);
1702 self.free_temp_local(s2.ptr);
1703 self.free_temp_local(s2.len);
1704 s1
1705 }
1706 };
1707
1708 match dst {
1710 Destination::Stack(s, _) => {
1711 self.instruction(LocalGet(dst_str.ptr.idx));
1712 self.stack_set(&s[..1], dst_mem_opts.ptr());
1713 self.instruction(LocalGet(dst_str.len.idx));
1714 self.stack_set(&s[1..], dst_mem_opts.ptr());
1715 }
1716 Destination::Memory(mem) => {
1717 self.instruction(LocalGet(mem.addr.idx));
1718 self.instruction(LocalGet(dst_str.ptr.idx));
1719 self.ptr_store(mem);
1720 self.instruction(LocalGet(mem.addr.idx));
1721 self.instruction(LocalGet(dst_str.len.idx));
1722 self.ptr_store(&mem.bump(dst_mem_opts.ptr_size().into()));
1723 }
1724 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1725 }
1726
1727 self.free_temp_local(src_str.ptr);
1728 self.free_temp_local(src_str.len);
1729 self.free_temp_local(dst_str.ptr);
1730 self.free_temp_local(dst_str.len);
1731 }
1732
1733 fn string_copy<'c>(
1746 &mut self,
1747 src: &WasmString<'_>,
1748 src_enc: FE,
1749 dst_opts: &'c Options,
1750 dst_enc: FE,
1751 ) -> WasmString<'c> {
1752 assert!(dst_enc.width() >= src_enc.width());
1753 self.validate_string_length(src, dst_enc);
1754
1755 let src_mem_opts = {
1756 match &src.opts.data_model {
1757 DataModel::Gc {} => todo!("CM+GC"),
1758 DataModel::LinearMemory(opts) => opts,
1759 }
1760 };
1761 let dst_mem_opts = {
1762 match &dst_opts.data_model {
1763 DataModel::Gc {} => todo!("CM+GC"),
1764 DataModel::LinearMemory(opts) => opts,
1765 }
1766 };
1767
1768 let mut src_byte_len_tmp = None;
1772 let src_byte_len = if src_enc.width() == 1 {
1773 src.len.idx
1774 } else {
1775 assert_eq!(src_enc.width(), 2);
1776 self.instruction(LocalGet(src.len.idx));
1777 self.ptr_uconst(src_mem_opts, 1);
1778 self.ptr_shl(src_mem_opts);
1779 let tmp = self.local_set_new_tmp(src.opts.data_model.unwrap_memory().ptr());
1780 let ret = tmp.idx;
1781 src_byte_len_tmp = Some(tmp);
1782 ret
1783 };
1784
1785 self.convert_src_len_to_dst(
1788 src.len.idx,
1789 src.opts.data_model.unwrap_memory().ptr(),
1790 dst_opts.data_model.unwrap_memory().ptr(),
1791 );
1792 let dst_len = self.local_tee_new_tmp(dst_opts.data_model.unwrap_memory().ptr());
1793 if dst_enc.width() > 1 {
1794 assert_eq!(dst_enc.width(), 2);
1795 self.ptr_uconst(dst_mem_opts, 1);
1796 self.ptr_shl(dst_mem_opts);
1797 }
1798 let dst_byte_len = self.local_set_new_tmp(dst_opts.data_model.unwrap_memory().ptr());
1799
1800 let dst = {
1803 let dst_mem = self.malloc(
1804 dst_opts,
1805 MallocSize::Local(dst_byte_len.idx),
1806 dst_enc.width().into(),
1807 );
1808 WasmString {
1809 ptr: dst_mem.addr,
1810 len: dst_len,
1811 opts: dst_opts,
1812 }
1813 };
1814
1815 self.validate_string_inbounds(src, src_byte_len);
1820 self.validate_string_inbounds(&dst, dst_byte_len.idx);
1821
1822 let op = if src_enc == dst_enc {
1826 Transcode::Copy(src_enc)
1827 } else {
1828 assert_eq!(src_enc, FE::Latin1);
1829 assert_eq!(dst_enc, FE::Utf16);
1830 Transcode::Latin1ToUtf16
1831 };
1832 let transcode = self.transcoder(src, &dst, op);
1833 self.instruction(LocalGet(src.ptr.idx));
1834 self.instruction(LocalGet(src.len.idx));
1835 self.instruction(LocalGet(dst.ptr.idx));
1836 self.instruction(Call(transcode.as_u32()));
1837
1838 self.free_temp_local(dst_byte_len);
1839 if let Some(tmp) = src_byte_len_tmp {
1840 self.free_temp_local(tmp);
1841 }
1842
1843 dst
1844 }
1845 fn string_deflate_to_utf8<'c>(
1858 &mut self,
1859 src: &WasmString<'_>,
1860 src_enc: FE,
1861 dst_opts: &'c Options,
1862 ) -> WasmString<'c> {
1863 let src_mem_opts = match &src.opts.data_model {
1864 DataModel::Gc {} => todo!("CM+GC"),
1865 DataModel::LinearMemory(opts) => opts,
1866 };
1867 let dst_mem_opts = match &dst_opts.data_model {
1868 DataModel::Gc {} => todo!("CM+GC"),
1869 DataModel::LinearMemory(opts) => opts,
1870 };
1871
1872 self.validate_string_length(src, src_enc);
1873
1874 self.convert_src_len_to_dst(
1878 src.len.idx,
1879 src.opts.data_model.unwrap_memory().ptr(),
1880 dst_opts.data_model.unwrap_memory().ptr(),
1881 );
1882 let dst_len = self.local_tee_new_tmp(dst_opts.data_model.unwrap_memory().ptr());
1883 let dst_byte_len = self.local_set_new_tmp(dst_opts.data_model.unwrap_memory().ptr());
1884
1885 let dst = {
1886 let dst_mem = self.malloc(dst_opts, MallocSize::Local(dst_byte_len.idx), 1);
1887 WasmString {
1888 ptr: dst_mem.addr,
1889 len: dst_len,
1890 opts: dst_opts,
1891 }
1892 };
1893
1894 let mut src_byte_len_tmp = None;
1896 let src_byte_len = match src_enc {
1897 FE::Latin1 => src.len.idx,
1898 FE::Utf16 => {
1899 self.instruction(LocalGet(src.len.idx));
1900 self.ptr_uconst(src_mem_opts, 1);
1901 self.ptr_shl(src_mem_opts);
1902 let tmp = self.local_set_new_tmp(src.opts.data_model.unwrap_memory().ptr());
1903 let ret = tmp.idx;
1904 src_byte_len_tmp = Some(tmp);
1905 ret
1906 }
1907 FE::Utf8 => unreachable!(),
1908 };
1909 self.validate_string_inbounds(src, src_byte_len);
1910 self.validate_string_inbounds(&dst, dst_byte_len.idx);
1911
1912 let op = match src_enc {
1914 FE::Latin1 => Transcode::Latin1ToUtf8,
1915 FE::Utf16 => Transcode::Utf16ToUtf8,
1916 FE::Utf8 => unreachable!(),
1917 };
1918 let transcode = self.transcoder(src, &dst, op);
1919 self.instruction(LocalGet(src.ptr.idx));
1920 self.instruction(LocalGet(src.len.idx));
1921 self.instruction(LocalGet(dst.ptr.idx));
1922 self.instruction(LocalGet(dst_byte_len.idx));
1923 self.instruction(Call(transcode.as_u32()));
1924 self.instruction(LocalSet(dst.len.idx));
1925 let src_len_tmp = self.local_set_new_tmp(src.opts.data_model.unwrap_memory().ptr());
1926
1927 self.instruction(LocalGet(src_len_tmp.idx));
1931 self.instruction(LocalGet(src.len.idx));
1932 self.ptr_ne(src_mem_opts);
1933 self.instruction(If(BlockType::Empty));
1934
1935 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 {
1942 FE::Latin1 => 2,
1943 FE::Utf16 => 3,
1944 _ => unreachable!(),
1945 };
1946 self.validate_string_length_u8(src, factor);
1947 self.convert_src_len_to_dst(
1948 src.len.idx,
1949 src.opts.data_model.unwrap_memory().ptr(),
1950 dst_opts.data_model.unwrap_memory().ptr(),
1951 );
1952 self.ptr_uconst(dst_mem_opts, factor.into());
1953 self.ptr_mul(dst_mem_opts);
1954 self.instruction(LocalTee(dst_byte_len.idx));
1955 self.instruction(Call(dst_mem_opts.realloc.unwrap().as_u32()));
1956 self.instruction(LocalSet(dst.ptr.idx));
1957
1958 self.validate_string_inbounds(&dst, dst_byte_len.idx);
1960
1961 self.instruction(LocalGet(src.ptr.idx));
1966 self.instruction(LocalGet(src_len_tmp.idx));
1967 if let FE::Utf16 = src_enc {
1968 self.ptr_uconst(src_mem_opts, 1);
1969 self.ptr_shl(src_mem_opts);
1970 }
1971 self.ptr_add(src_mem_opts);
1972 self.instruction(LocalGet(src.len.idx));
1973 self.instruction(LocalGet(src_len_tmp.idx));
1974 self.ptr_sub(src_mem_opts);
1975 self.instruction(LocalGet(dst.ptr.idx));
1976 self.instruction(LocalGet(dst.len.idx));
1977 self.ptr_add(dst_mem_opts);
1978 self.instruction(LocalGet(dst_byte_len.idx));
1979 self.instruction(LocalGet(dst.len.idx));
1980 self.ptr_sub(dst_mem_opts);
1981 self.instruction(Call(transcode.as_u32()));
1982
1983 self.instruction(LocalGet(dst.len.idx));
1987 self.ptr_add(dst_mem_opts);
1988 self.instruction(LocalSet(dst.len.idx));
1989
1990 if self.module.tunables.debug_adapter_modules {
1993 self.instruction(LocalGet(src.len.idx));
1994 self.instruction(LocalGet(src_len_tmp.idx));
1995 self.ptr_sub(src_mem_opts);
1996 self.ptr_ne(src_mem_opts);
1997 self.instruction(If(BlockType::Empty));
1998 self.trap(Trap::DebugAssertStringEncodingFinished);
1999 self.instruction(End);
2000 } else {
2001 self.instruction(Drop);
2002 }
2003
2004 self.instruction(LocalGet(dst.len.idx));
2006 self.instruction(LocalGet(dst_byte_len.idx));
2007 self.ptr_ne(dst_mem_opts);
2008 self.instruction(If(BlockType::Empty));
2009 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()));
2014 self.instruction(LocalSet(dst.ptr.idx));
2015 self.instruction(End);
2016
2017 if self.module.tunables.debug_adapter_modules {
2020 self.instruction(Else);
2021
2022 self.instruction(LocalGet(dst.len.idx));
2023 self.instruction(LocalGet(dst_byte_len.idx));
2024 self.ptr_ne(dst_mem_opts);
2025 self.instruction(If(BlockType::Empty));
2026 self.trap(Trap::DebugAssertStringEncodingFinished);
2027 self.instruction(End);
2028 }
2029
2030 self.instruction(End); self.free_temp_local(src_len_tmp);
2033 self.free_temp_local(dst_byte_len);
2034 if let Some(tmp) = src_byte_len_tmp {
2035 self.free_temp_local(tmp);
2036 }
2037
2038 dst
2039 }
2040
2041 fn string_utf8_to_utf16<'c>(
2056 &mut self,
2057 src: &WasmString<'_>,
2058 dst_opts: &'c Options,
2059 ) -> WasmString<'c> {
2060 let src_mem_opts = match &src.opts.data_model {
2061 DataModel::Gc {} => todo!("CM+GC"),
2062 DataModel::LinearMemory(opts) => opts,
2063 };
2064 let dst_mem_opts = match &dst_opts.data_model {
2065 DataModel::Gc {} => todo!("CM+GC"),
2066 DataModel::LinearMemory(opts) => opts,
2067 };
2068
2069 self.validate_string_length(src, FE::Utf16);
2070 self.convert_src_len_to_dst(
2071 src.len.idx,
2072 src_mem_opts.ptr(),
2073 dst_opts.data_model.unwrap_memory().ptr(),
2074 );
2075 let dst_len = self.local_tee_new_tmp(dst_opts.data_model.unwrap_memory().ptr());
2076 self.ptr_uconst(dst_mem_opts, 1);
2077 self.ptr_shl(dst_mem_opts);
2078 let dst_byte_len = self.local_set_new_tmp(dst_opts.data_model.unwrap_memory().ptr());
2079 let dst = {
2080 let dst_mem = self.malloc(dst_opts, MallocSize::Local(dst_byte_len.idx), 2);
2081 WasmString {
2082 ptr: dst_mem.addr,
2083 len: dst_len,
2084 opts: dst_opts,
2085 }
2086 };
2087
2088 self.validate_string_inbounds(src, src.len.idx);
2089 self.validate_string_inbounds(&dst, dst_byte_len.idx);
2090
2091 let transcode = self.transcoder(src, &dst, Transcode::Utf8ToUtf16);
2092 self.instruction(LocalGet(src.ptr.idx));
2093 self.instruction(LocalGet(src.len.idx));
2094 self.instruction(LocalGet(dst.ptr.idx));
2095 self.instruction(Call(transcode.as_u32()));
2096 self.instruction(LocalSet(dst.len.idx));
2097
2098 self.convert_src_len_to_dst(src.len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2106 self.instruction(LocalGet(dst.len.idx));
2107 self.ptr_ne(dst_mem_opts);
2108 self.instruction(If(BlockType::Empty));
2109 self.instruction(LocalGet(dst.ptr.idx));
2110 self.instruction(LocalGet(dst_byte_len.idx));
2111 self.ptr_uconst(dst_mem_opts, 2);
2112 self.instruction(LocalGet(dst.len.idx));
2113 self.ptr_uconst(dst_mem_opts, 1);
2114 self.ptr_shl(dst_mem_opts);
2115 self.instruction(Call(match dst.opts.data_model {
2116 DataModel::Gc {} => todo!("CM+GC"),
2117 DataModel::LinearMemory(LinearMemoryOptions { realloc, .. }) => {
2118 realloc.unwrap().as_u32()
2119 }
2120 }));
2121 self.instruction(LocalSet(dst.ptr.idx));
2122 self.instruction(End); self.free_temp_local(dst_byte_len);
2125
2126 dst
2127 }
2128
2129 fn string_compact_utf16_to_compact<'c>(
2143 &mut self,
2144 src: &WasmString<'_>,
2145 dst_opts: &'c Options,
2146 ) -> WasmString<'c> {
2147 let src_mem_opts = match &src.opts.data_model {
2148 DataModel::Gc {} => todo!("CM+GC"),
2149 DataModel::LinearMemory(opts) => opts,
2150 };
2151 let dst_mem_opts = match &dst_opts.data_model {
2152 DataModel::Gc {} => todo!("CM+GC"),
2153 DataModel::LinearMemory(opts) => opts,
2154 };
2155
2156 self.validate_string_length(src, FE::Utf16);
2157 self.convert_src_len_to_dst(src.len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2158 let dst_len = self.local_tee_new_tmp(dst_mem_opts.ptr());
2159 self.ptr_uconst(dst_mem_opts, 1);
2160 self.ptr_shl(dst_mem_opts);
2161 let dst_byte_len = self.local_set_new_tmp(dst_mem_opts.ptr());
2162 let dst = {
2163 let dst_mem = self.malloc(dst_opts, MallocSize::Local(dst_byte_len.idx), 2);
2164 WasmString {
2165 ptr: dst_mem.addr,
2166 len: dst_len,
2167 opts: dst_opts,
2168 }
2169 };
2170
2171 self.convert_src_len_to_dst(
2172 dst_byte_len.idx,
2173 dst.opts.data_model.unwrap_memory().ptr(),
2174 src_mem_opts.ptr(),
2175 );
2176 let src_byte_len = self.local_set_new_tmp(src_mem_opts.ptr());
2177
2178 self.validate_string_inbounds(src, src_byte_len.idx);
2179 self.validate_string_inbounds(&dst, dst_byte_len.idx);
2180
2181 let transcode = self.transcoder(src, &dst, Transcode::Utf16ToCompactProbablyUtf16);
2182 self.instruction(LocalGet(src.ptr.idx));
2183 self.instruction(LocalGet(src.len.idx));
2184 self.instruction(LocalGet(dst.ptr.idx));
2185 self.instruction(Call(transcode.as_u32()));
2186 self.instruction(LocalSet(dst.len.idx));
2187
2188 if self.module.tunables.debug_adapter_modules {
2191 self.instruction(LocalGet(dst.len.idx));
2192 self.ptr_uconst(dst_mem_opts, !UTF16_TAG);
2193 self.ptr_and(dst_mem_opts);
2194 self.convert_src_len_to_dst(src.len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2195 self.ptr_ne(dst_mem_opts);
2196 self.instruction(If(BlockType::Empty));
2197 self.trap(Trap::DebugAssertEqualCodeUnits);
2198 self.instruction(End);
2199 }
2200
2201 self.instruction(LocalGet(dst.len.idx));
2205 self.ptr_uconst(dst_mem_opts, UTF16_TAG);
2206 self.ptr_and(dst_mem_opts);
2207 self.ptr_br_if(dst_mem_opts, 0);
2208
2209 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()));
2215 self.instruction(LocalSet(dst.ptr.idx));
2216
2217 self.free_temp_local(dst_byte_len);
2218 self.free_temp_local(src_byte_len);
2219
2220 dst
2221 }
2222
2223 fn string_to_compact<'c>(
2230 &mut self,
2231 src: &WasmString<'_>,
2232 src_enc: FE,
2233 dst_opts: &'c Options,
2234 ) -> WasmString<'c> {
2235 let src_mem_opts = match &src.opts.data_model {
2236 DataModel::Gc {} => todo!("CM+GC"),
2237 DataModel::LinearMemory(opts) => opts,
2238 };
2239 let dst_mem_opts = match &dst_opts.data_model {
2240 DataModel::Gc {} => todo!("CM+GC"),
2241 DataModel::LinearMemory(opts) => opts,
2242 };
2243
2244 self.validate_string_length(src, src_enc);
2245 self.convert_src_len_to_dst(src.len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2246 let dst_len = self.local_tee_new_tmp(dst_mem_opts.ptr());
2247 let dst_byte_len = self.local_set_new_tmp(dst_mem_opts.ptr());
2248 let dst = {
2249 let dst_mem = self.malloc(dst_opts, MallocSize::Local(dst_byte_len.idx), 2);
2250 WasmString {
2251 ptr: dst_mem.addr,
2252 len: dst_len,
2253 opts: dst_opts,
2254 }
2255 };
2256
2257 self.validate_string_inbounds(src, src.len.idx);
2258 self.validate_string_inbounds(&dst, dst_byte_len.idx);
2259
2260 let (latin1, utf16) = match src_enc {
2264 FE::Utf8 => (Transcode::Utf8ToLatin1, Transcode::Utf8ToCompactUtf16),
2265 FE::Utf16 => (Transcode::Utf16ToLatin1, Transcode::Utf16ToCompactUtf16),
2266 FE::Latin1 => unreachable!(),
2267 };
2268 let transcode_latin1 = self.transcoder(src, &dst, latin1);
2269 let transcode_utf16 = self.transcoder(src, &dst, utf16);
2270 self.instruction(LocalGet(src.ptr.idx));
2271 self.instruction(LocalGet(src.len.idx));
2272 self.instruction(LocalGet(dst.ptr.idx));
2273 self.instruction(Call(transcode_latin1.as_u32()));
2274 self.instruction(LocalSet(dst.len.idx));
2275 let src_len_tmp = self.local_set_new_tmp(src_mem_opts.ptr());
2276
2277 self.instruction(LocalGet(src_len_tmp.idx));
2280 self.instruction(LocalGet(src.len.idx));
2281 self.ptr_eq(src_mem_opts);
2282 self.instruction(If(BlockType::Empty)); self.instruction(LocalGet(dst_byte_len.idx));
2288 self.instruction(LocalGet(dst.len.idx));
2289 self.ptr_ne(dst_mem_opts);
2290 self.instruction(If(BlockType::Empty));
2291 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()));
2296 self.instruction(LocalSet(dst.ptr.idx));
2297 self.instruction(End);
2298
2299 self.instruction(Else); if src_enc.width() == 1 {
2308 self.validate_string_length_u8(src, 2);
2309 }
2310
2311 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());
2317 self.ptr_uconst(dst_mem_opts, 1);
2318 self.ptr_shl(dst_mem_opts);
2319 self.instruction(LocalTee(dst_byte_len.idx));
2320 self.instruction(Call(dst_mem_opts.realloc.unwrap().as_u32()));
2321 self.instruction(LocalSet(dst.ptr.idx));
2322
2323 self.instruction(LocalGet(src.ptr.idx));
2327 self.instruction(LocalGet(src_len_tmp.idx));
2328 if let FE::Utf16 = src_enc {
2329 self.ptr_uconst(src_mem_opts, 1);
2330 self.ptr_shl(src_mem_opts);
2331 }
2332 self.ptr_add(src_mem_opts);
2333 self.instruction(LocalGet(src.len.idx));
2334 self.instruction(LocalGet(src_len_tmp.idx));
2335 self.ptr_sub(src_mem_opts);
2336 self.instruction(LocalGet(dst.ptr.idx));
2337 self.convert_src_len_to_dst(src.len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2338 self.instruction(LocalGet(dst.len.idx));
2339 self.instruction(Call(transcode_utf16.as_u32()));
2340 self.instruction(LocalSet(dst.len.idx));
2341
2342 self.instruction(LocalGet(dst.len.idx));
2350 self.convert_src_len_to_dst(src.len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2351 self.ptr_ne(dst_mem_opts);
2352 self.instruction(If(BlockType::Empty));
2353 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));
2357 self.ptr_uconst(dst_mem_opts, 1);
2358 self.ptr_shl(dst_mem_opts);
2359 self.instruction(Call(dst_mem_opts.realloc.unwrap().as_u32()));
2360 self.instruction(LocalSet(dst.ptr.idx));
2361 self.instruction(End);
2362
2363 self.instruction(LocalGet(dst.len.idx));
2365 self.ptr_uconst(dst_mem_opts, UTF16_TAG);
2366 self.ptr_or(dst_mem_opts);
2367 self.instruction(LocalSet(dst.len.idx));
2368
2369 self.instruction(End); self.free_temp_local(src_len_tmp);
2372 self.free_temp_local(dst_byte_len);
2373
2374 dst
2375 }
2376
2377 fn validate_string_length(&mut self, src: &WasmString<'_>, dst: FE) {
2378 self.validate_string_length_u8(src, dst.width())
2379 }
2380
2381 fn validate_string_length_u8(&mut self, s: &WasmString<'_>, dst: u8) {
2382 let mem_opts = match &s.opts.data_model {
2383 DataModel::Gc {} => todo!("CM+GC"),
2384 DataModel::LinearMemory(opts) => opts,
2385 };
2386
2387 self.instruction(LocalGet(s.len.idx));
2390 let max = MAX_STRING_BYTE_LENGTH / u32::from(dst);
2391 self.ptr_uconst(mem_opts, max);
2392 self.ptr_ge_u(mem_opts);
2393 self.instruction(If(BlockType::Empty));
2394 self.trap(Trap::StringOutOfBounds);
2395 self.instruction(End);
2396 }
2397
2398 fn transcoder(
2399 &mut self,
2400 src: &WasmString<'_>,
2401 dst: &WasmString<'_>,
2402 op: Transcode,
2403 ) -> FuncIndex {
2404 match (src.opts.data_model, dst.opts.data_model) {
2405 (DataModel::Gc {}, _) | (_, DataModel::Gc {}) => {
2406 todo!("CM+GC")
2407 }
2408 (
2409 DataModel::LinearMemory(LinearMemoryOptions {
2410 memory64: src64,
2411 memory: src_mem,
2412 realloc: _,
2413 }),
2414 DataModel::LinearMemory(LinearMemoryOptions {
2415 memory64: dst64,
2416 memory: dst_mem,
2417 realloc: _,
2418 }),
2419 ) => self.module.import_transcoder(Transcoder {
2420 from_memory: src_mem.unwrap(),
2421 from_memory64: src64,
2422 to_memory: dst_mem.unwrap(),
2423 to_memory64: dst64,
2424 op,
2425 }),
2426 }
2427 }
2428
2429 fn validate_string_inbounds(&mut self, s: &WasmString<'_>, byte_len: u32) {
2430 match &s.opts.data_model {
2431 DataModel::Gc {} => todo!("CM+GC"),
2432 DataModel::LinearMemory(opts) => {
2433 self.validate_memory_inbounds(opts, s.ptr.idx, byte_len, Trap::StringOutOfBounds)
2434 }
2435 }
2436 }
2437
2438 fn validate_memory_inbounds(
2439 &mut self,
2440 opts: &LinearMemoryOptions,
2441 ptr_local: u32,
2442 byte_len_local: u32,
2443 trap: Trap,
2444 ) {
2445 let extend_to_64 = |me: &mut Self| {
2446 if !opts.memory64 {
2447 me.instruction(I64ExtendI32U);
2448 }
2449 };
2450
2451 self.instruction(Block(BlockType::Empty));
2452 self.instruction(Block(BlockType::Empty));
2453
2454 self.instruction(MemorySize(opts.memory.unwrap().as_u32()));
2459 extend_to_64(self);
2460 self.instruction(I64Const(16));
2461 self.instruction(I64Shl);
2462
2463 self.instruction(LocalGet(ptr_local));
2468 extend_to_64(self);
2469 self.instruction(LocalGet(byte_len_local));
2470 extend_to_64(self);
2471 self.instruction(I64Add);
2472 if opts.memory64 {
2473 let tmp = self.local_tee_new_tmp(ValType::I64);
2474 self.instruction(LocalGet(ptr_local));
2475 self.ptr_lt_u(opts);
2476 self.instruction(BrIf(0));
2477 self.instruction(LocalGet(tmp.idx));
2478 self.free_temp_local(tmp);
2479 }
2480
2481 self.instruction(I64GeU);
2485 self.instruction(BrIf(1));
2486
2487 self.instruction(End);
2488 self.trap(trap);
2489 self.instruction(End);
2490 }
2491
2492 fn translate_list(
2493 &mut self,
2494 src_ty: TypeListIndex,
2495 src: &Source<'_>,
2496 dst_ty: &InterfaceType,
2497 dst: &Destination,
2498 ) {
2499 let src_mem_opts = match &src.opts().data_model {
2500 DataModel::Gc {} => todo!("CM+GC"),
2501 DataModel::LinearMemory(opts) => opts,
2502 };
2503 let dst_mem_opts = match &dst.opts().data_model {
2504 DataModel::Gc {} => todo!("CM+GC"),
2505 DataModel::LinearMemory(opts) => opts,
2506 };
2507
2508 let src_element_ty = &self.types[src_ty].element;
2509 let dst_element_ty = match dst_ty {
2510 InterfaceType::List(r) => &self.types[*r].element,
2511 _ => panic!("expected a list"),
2512 };
2513 let src_opts = src.opts();
2514 let dst_opts = dst.opts();
2515 let (src_size, src_align) = self.types.size_align(src_mem_opts, src_element_ty);
2516 let (dst_size, dst_align) = self.types.size_align(dst_mem_opts, dst_element_ty);
2517
2518 match src {
2523 Source::Stack(s) => {
2524 assert_eq!(s.locals.len(), 2);
2525 self.stack_get(&s.slice(0..1), src_mem_opts.ptr());
2526 self.stack_get(&s.slice(1..2), src_mem_opts.ptr());
2527 }
2528 Source::Memory(mem) => {
2529 self.ptr_load(mem);
2530 self.ptr_load(&mem.bump(src_mem_opts.ptr_size().into()));
2531 }
2532 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
2533 }
2534 let src_len = self.local_set_new_tmp(src_mem_opts.ptr());
2535 let src_ptr = self.local_set_new_tmp(src_mem_opts.ptr());
2536
2537 let src_mem = self.memory_operand(src_opts, src_ptr, src_align);
2540
2541 let src_byte_len = self.calculate_list_byte_len(src_mem_opts, src_len.idx, src_size);
2543 let dst_byte_len = if src_size == dst_size {
2544 self.convert_src_len_to_dst(src_byte_len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2545 self.local_set_new_tmp(dst_mem_opts.ptr())
2546 } else if src_mem_opts.ptr() == dst_mem_opts.ptr() {
2547 self.calculate_list_byte_len(dst_mem_opts, src_len.idx, dst_size)
2548 } else {
2549 self.convert_src_len_to_dst(src_byte_len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2550 let tmp = self.local_set_new_tmp(dst_mem_opts.ptr());
2551 let ret = self.calculate_list_byte_len(dst_mem_opts, tmp.idx, dst_size);
2552 self.free_temp_local(tmp);
2553 ret
2554 };
2555
2556 let dst_mem = self.malloc(dst_opts, MallocSize::Local(dst_byte_len.idx), dst_align);
2561
2562 self.validate_memory_inbounds(
2565 src_mem_opts,
2566 src_mem.addr.idx,
2567 src_byte_len.idx,
2568 Trap::ListOutOfBounds,
2569 );
2570 self.validate_memory_inbounds(
2571 dst_mem_opts,
2572 dst_mem.addr.idx,
2573 dst_byte_len.idx,
2574 Trap::ListOutOfBounds,
2575 );
2576
2577 self.free_temp_local(src_byte_len);
2578 self.free_temp_local(dst_byte_len);
2579
2580 if src_size > 0 || dst_size > 0 {
2584 self.instruction(Block(BlockType::Empty));
2587
2588 self.instruction(LocalGet(src_len.idx));
2590 let remaining = self.local_tee_new_tmp(src_mem_opts.ptr());
2591 self.ptr_eqz(src_mem_opts);
2592 self.instruction(BrIf(0));
2593
2594 self.instruction(LocalGet(src_mem.addr.idx));
2596 let cur_src_ptr = self.local_set_new_tmp(src_mem_opts.ptr());
2597 self.instruction(LocalGet(dst_mem.addr.idx));
2598 let cur_dst_ptr = self.local_set_new_tmp(dst_mem_opts.ptr());
2599
2600 self.instruction(Loop(BlockType::Empty));
2601
2602 let element_src = Source::Memory(Memory {
2604 opts: src_opts,
2605 offset: 0,
2606 addr: TempLocal::new(cur_src_ptr.idx, cur_src_ptr.ty),
2607 });
2608 let element_dst = Destination::Memory(Memory {
2609 opts: dst_opts,
2610 offset: 0,
2611 addr: TempLocal::new(cur_dst_ptr.idx, cur_dst_ptr.ty),
2612 });
2613 self.translate(src_element_ty, &element_src, dst_element_ty, &element_dst);
2614
2615 if src_size > 0 {
2617 self.instruction(LocalGet(cur_src_ptr.idx));
2618 self.ptr_uconst(src_mem_opts, src_size);
2619 self.ptr_add(src_mem_opts);
2620 self.instruction(LocalSet(cur_src_ptr.idx));
2621 }
2622 if dst_size > 0 {
2623 self.instruction(LocalGet(cur_dst_ptr.idx));
2624 self.ptr_uconst(dst_mem_opts, dst_size);
2625 self.ptr_add(dst_mem_opts);
2626 self.instruction(LocalSet(cur_dst_ptr.idx));
2627 }
2628
2629 self.instruction(LocalGet(remaining.idx));
2632 self.ptr_iconst(src_mem_opts, -1);
2633 self.ptr_add(src_mem_opts);
2634 self.instruction(LocalTee(remaining.idx));
2635 self.ptr_br_if(src_mem_opts, 0);
2636 self.instruction(End); self.instruction(End); self.free_temp_local(cur_dst_ptr);
2640 self.free_temp_local(cur_src_ptr);
2641 self.free_temp_local(remaining);
2642 }
2643
2644 match dst {
2646 Destination::Stack(s, _) => {
2647 self.instruction(LocalGet(dst_mem.addr.idx));
2648 self.stack_set(&s[..1], dst_mem_opts.ptr());
2649 self.convert_src_len_to_dst(src_len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2650 self.stack_set(&s[1..], dst_mem_opts.ptr());
2651 }
2652 Destination::Memory(mem) => {
2653 self.instruction(LocalGet(mem.addr.idx));
2654 self.instruction(LocalGet(dst_mem.addr.idx));
2655 self.ptr_store(mem);
2656 self.instruction(LocalGet(mem.addr.idx));
2657 self.convert_src_len_to_dst(src_len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2658 self.ptr_store(&mem.bump(dst_mem_opts.ptr_size().into()));
2659 }
2660 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
2661 }
2662
2663 self.free_temp_local(src_len);
2664 self.free_temp_local(src_mem.addr);
2665 self.free_temp_local(dst_mem.addr);
2666 }
2667
2668 fn calculate_list_byte_len(
2669 &mut self,
2670 opts: &LinearMemoryOptions,
2671 len_local: u32,
2672 elt_size: u32,
2673 ) -> TempLocal {
2674 if elt_size == 0 {
2677 self.ptr_uconst(opts, 0);
2678 return self.local_set_new_tmp(opts.ptr());
2679 }
2680
2681 if elt_size == 1 {
2689 if let ValType::I64 = opts.ptr() {
2690 self.instruction(LocalGet(len_local));
2691 self.instruction(I64Const(32));
2692 self.instruction(I64ShrU);
2693 self.instruction(I32WrapI64);
2694 self.instruction(If(BlockType::Empty));
2695 self.trap(Trap::ListOutOfBounds);
2696 self.instruction(End);
2697 }
2698 self.instruction(LocalGet(len_local));
2699 return self.local_set_new_tmp(opts.ptr());
2700 }
2701
2702 self.instruction(Block(BlockType::Empty));
2707 self.instruction(Block(BlockType::Empty));
2708 self.instruction(LocalGet(len_local));
2709 match opts.ptr() {
2710 ValType::I32 => self.instruction(I64ExtendI32U),
2714
2715 ValType::I64 => {
2719 self.instruction(I64Const(32));
2720 self.instruction(I64ShrU);
2721 self.instruction(I32WrapI64);
2722 self.instruction(BrIf(0));
2723 self.instruction(LocalGet(len_local));
2724 }
2725
2726 _ => unreachable!(),
2727 }
2728
2729 self.instruction(I64Const(elt_size.into()));
2738 self.instruction(I64Mul);
2739 let tmp = self.local_tee_new_tmp(ValType::I64);
2740 self.instruction(I64Const(32));
2743 self.instruction(I64ShrU);
2744 self.instruction(I64Eqz);
2745 self.instruction(BrIf(1));
2746 self.instruction(End);
2747 self.trap(Trap::ListOutOfBounds);
2748 self.instruction(End);
2749
2750 if opts.ptr() == ValType::I64 {
2754 tmp
2755 } else {
2756 self.instruction(LocalGet(tmp.idx));
2757 self.instruction(I32WrapI64);
2758 self.free_temp_local(tmp);
2759 self.local_set_new_tmp(ValType::I32)
2760 }
2761 }
2762
2763 fn convert_src_len_to_dst(
2764 &mut self,
2765 src_len_local: u32,
2766 src_ptr_ty: ValType,
2767 dst_ptr_ty: ValType,
2768 ) {
2769 self.instruction(LocalGet(src_len_local));
2770 match (src_ptr_ty, dst_ptr_ty) {
2771 (ValType::I32, ValType::I64) => self.instruction(I64ExtendI32U),
2772 (ValType::I64, ValType::I32) => self.instruction(I32WrapI64),
2773 (src, dst) => assert_eq!(src, dst),
2774 }
2775 }
2776
2777 fn translate_record(
2778 &mut self,
2779 src_ty: TypeRecordIndex,
2780 src: &Source<'_>,
2781 dst_ty: &InterfaceType,
2782 dst: &Destination,
2783 ) {
2784 let src_ty = &self.types[src_ty];
2785 let dst_ty = match dst_ty {
2786 InterfaceType::Record(r) => &self.types[*r],
2787 _ => panic!("expected a record"),
2788 };
2789
2790 assert_eq!(src_ty.fields.len(), dst_ty.fields.len());
2792
2793 let mut src_fields = HashMap::new();
2797 for (i, src) in src
2798 .record_field_srcs(self.types, src_ty.fields.iter().map(|f| f.ty))
2799 .enumerate()
2800 {
2801 let field = &src_ty.fields[i];
2802 src_fields.insert(&field.name, (src, &field.ty));
2803 }
2804
2805 for (i, dst) in dst
2814 .record_field_dsts(self.types, dst_ty.fields.iter().map(|f| f.ty))
2815 .enumerate()
2816 {
2817 let field = &dst_ty.fields[i];
2818 let (src, src_ty) = &src_fields[&field.name];
2819 self.translate(src_ty, src, &field.ty, &dst);
2820 }
2821 }
2822
2823 fn translate_flags(
2824 &mut self,
2825 src_ty: TypeFlagsIndex,
2826 src: &Source<'_>,
2827 dst_ty: &InterfaceType,
2828 dst: &Destination,
2829 ) {
2830 let src_ty = &self.types[src_ty];
2831 let dst_ty = match dst_ty {
2832 InterfaceType::Flags(r) => &self.types[*r],
2833 _ => panic!("expected a record"),
2834 };
2835
2836 assert_eq!(src_ty.names, dst_ty.names);
2844 let cnt = src_ty.names.len();
2845 match FlagsSize::from_count(cnt) {
2846 FlagsSize::Size0 => {}
2847 FlagsSize::Size1 => {
2848 let mask = if cnt == 8 { 0xff } else { (1 << cnt) - 1 };
2849 self.convert_u8_mask(src, dst, mask);
2850 }
2851 FlagsSize::Size2 => {
2852 let mask = if cnt == 16 { 0xffff } else { (1 << cnt) - 1 };
2853 self.convert_u16_mask(src, dst, mask);
2854 }
2855 FlagsSize::Size4Plus(n) => {
2856 let srcs = src.record_field_srcs(self.types, (0..n).map(|_| InterfaceType::U32));
2857 let dsts = dst.record_field_dsts(self.types, (0..n).map(|_| InterfaceType::U32));
2858 let n = usize::from(n);
2859 for (i, (src, dst)) in srcs.zip(dsts).enumerate() {
2860 let mask = if i == n - 1 && (cnt % 32 != 0) {
2861 (1 << (cnt % 32)) - 1
2862 } else {
2863 0xffffffff
2864 };
2865 self.convert_u32_mask(&src, &dst, mask);
2866 }
2867 }
2868 }
2869 }
2870
2871 fn translate_tuple(
2872 &mut self,
2873 src_ty: TypeTupleIndex,
2874 src: &Source<'_>,
2875 dst_ty: &InterfaceType,
2876 dst: &Destination,
2877 ) {
2878 let src_ty = &self.types[src_ty];
2879 let dst_ty = match dst_ty {
2880 InterfaceType::Tuple(t) => &self.types[*t],
2881 _ => panic!("expected a tuple"),
2882 };
2883
2884 assert_eq!(src_ty.types.len(), dst_ty.types.len());
2886
2887 let srcs = src
2888 .record_field_srcs(self.types, src_ty.types.iter().copied())
2889 .zip(src_ty.types.iter());
2890 let dsts = dst
2891 .record_field_dsts(self.types, dst_ty.types.iter().copied())
2892 .zip(dst_ty.types.iter());
2893 for ((src, src_ty), (dst, dst_ty)) in srcs.zip(dsts) {
2894 self.translate(src_ty, &src, dst_ty, &dst);
2895 }
2896 }
2897
2898 fn translate_fixed_length_list(
2899 &mut self,
2900 src_ty: TypeFixedLengthListIndex,
2901 src: &Source<'_>,
2902 dst_ty: &InterfaceType,
2903 dst: &Destination,
2904 ) {
2905 let src_ty = &self.types[src_ty];
2906 let dst_ty = match dst_ty {
2907 InterfaceType::FixedLengthList(t) => &self.types[*t],
2908 _ => panic!("expected a fixed size list"),
2909 };
2910
2911 assert_eq!(src_ty.size, dst_ty.size);
2913
2914 match (&src, &dst) {
2915 (Source::Memory(src_mem), Destination::Memory(dst_mem)) => {
2917 let src_mem_opts = match &src_mem.opts.data_model {
2918 DataModel::Gc {} => todo!("CM+GC"),
2919 DataModel::LinearMemory(opts) => opts,
2920 };
2921 let dst_mem_opts = match &dst_mem.opts.data_model {
2922 DataModel::Gc {} => todo!("CM+GC"),
2923 DataModel::LinearMemory(opts) => opts,
2924 };
2925 let src_element_bytes = self.types.size_align(src_mem_opts, &src_ty.element).0;
2926 let dst_element_bytes = self.types.size_align(dst_mem_opts, &dst_ty.element).0;
2927 assert_ne!(src_element_bytes, 0);
2928 assert_ne!(dst_element_bytes, 0);
2929
2930 self.instruction(LocalGet(src_mem.addr.idx));
2933 if src_mem.offset != 0 {
2934 self.ptr_uconst(src_mem_opts, src_mem.offset);
2935 self.ptr_add(src_mem_opts);
2936 }
2937 let cur_src_ptr = self.local_set_new_tmp(src_mem_opts.ptr());
2938 self.instruction(LocalGet(dst_mem.addr.idx));
2939 if dst_mem.offset != 0 {
2940 self.ptr_uconst(dst_mem_opts, dst_mem.offset);
2941 self.ptr_add(dst_mem_opts);
2942 }
2943 let cur_dst_ptr = self.local_set_new_tmp(dst_mem_opts.ptr());
2944
2945 self.instruction(I32Const(src_ty.size as i32));
2946 let remaining = self.local_set_new_tmp(ValType::I32);
2947
2948 self.instruction(Loop(BlockType::Empty));
2949
2950 let element_src = Source::Memory(Memory {
2952 opts: src_mem.opts,
2953 offset: 0,
2954 addr: TempLocal::new(cur_src_ptr.idx, cur_src_ptr.ty),
2955 });
2956 let element_dst = Destination::Memory(Memory {
2957 opts: dst_mem.opts,
2958 offset: 0,
2959 addr: TempLocal::new(cur_dst_ptr.idx, cur_dst_ptr.ty),
2960 });
2961 self.translate(&src_ty.element, &element_src, &dst_ty.element, &element_dst);
2962
2963 self.instruction(LocalGet(cur_src_ptr.idx));
2965 self.ptr_uconst(src_mem_opts, src_element_bytes);
2966 self.ptr_add(src_mem_opts);
2967 self.instruction(LocalSet(cur_src_ptr.idx));
2968 self.instruction(LocalGet(cur_dst_ptr.idx));
2969 self.ptr_uconst(dst_mem_opts, dst_element_bytes);
2970 self.ptr_add(dst_mem_opts);
2971 self.instruction(LocalSet(cur_dst_ptr.idx));
2972
2973 self.instruction(LocalGet(remaining.idx));
2976 self.ptr_iconst(src_mem_opts, -1);
2977 self.ptr_add(src_mem_opts);
2978 self.instruction(LocalTee(remaining.idx));
2979 self.ptr_br_if(src_mem_opts, 0);
2980 self.instruction(End); self.free_temp_local(cur_dst_ptr);
2983 self.free_temp_local(cur_src_ptr);
2984 self.free_temp_local(remaining);
2985 return;
2986 }
2987 (_, _) => {
2989 assert!(
2991 src_ty.size as usize <= MAX_FLAT_PARAMS
2992 && dst_ty.size as usize <= MAX_FLAT_PARAMS
2993 );
2994 let srcs =
2995 src.record_field_srcs(self.types, (0..src_ty.size).map(|_| src_ty.element));
2996 let dsts =
2997 dst.record_field_dsts(self.types, (0..dst_ty.size).map(|_| dst_ty.element));
2998 for (src, dst) in srcs.zip(dsts) {
2999 self.translate(&src_ty.element, &src, &dst_ty.element, &dst);
3000 }
3001 }
3002 }
3003 }
3004
3005 fn translate_variant(
3006 &mut self,
3007 src_ty: TypeVariantIndex,
3008 src: &Source<'_>,
3009 dst_ty: &InterfaceType,
3010 dst: &Destination,
3011 ) {
3012 let src_ty = &self.types[src_ty];
3013 let dst_ty = match dst_ty {
3014 InterfaceType::Variant(t) => &self.types[*t],
3015 _ => panic!("expected a variant"),
3016 };
3017
3018 let src_info = variant_info(self.types, src_ty.cases.iter().map(|(_, c)| c.as_ref()));
3019 let dst_info = variant_info(self.types, dst_ty.cases.iter().map(|(_, c)| c.as_ref()));
3020
3021 let iter = src_ty
3022 .cases
3023 .iter()
3024 .enumerate()
3025 .map(|(src_i, (src_case, src_case_ty))| {
3026 let dst_i = dst_ty
3027 .cases
3028 .iter()
3029 .position(|(c, _)| c == src_case)
3030 .unwrap();
3031 let dst_case_ty = &dst_ty.cases[dst_i];
3032 let src_i = u32::try_from(src_i).unwrap();
3033 let dst_i = u32::try_from(dst_i).unwrap();
3034 VariantCase {
3035 src_i,
3036 src_ty: src_case_ty.as_ref(),
3037 dst_i,
3038 dst_ty: dst_case_ty.as_ref(),
3039 }
3040 });
3041 self.convert_variant(src, &src_info, dst, &dst_info, iter);
3042 }
3043
3044 fn translate_enum(
3045 &mut self,
3046 src_ty: TypeEnumIndex,
3047 src: &Source<'_>,
3048 dst_ty: &InterfaceType,
3049 dst: &Destination,
3050 ) {
3051 let src_ty = &self.types[src_ty];
3052 let dst_ty = match dst_ty {
3053 InterfaceType::Enum(t) => &self.types[*t],
3054 _ => panic!("expected an option"),
3055 };
3056
3057 debug_assert_eq!(src_ty.info.size, dst_ty.info.size);
3058 debug_assert_eq!(src_ty.names.len(), dst_ty.names.len());
3059 debug_assert!(
3060 src_ty
3061 .names
3062 .iter()
3063 .zip(dst_ty.names.iter())
3064 .all(|(a, b)| a == b)
3065 );
3066
3067 match src {
3069 Source::Stack(s) => self.stack_get(&s.slice(0..1), ValType::I32),
3070 Source::Memory(mem) => match src_ty.info.size {
3071 DiscriminantSize::Size1 => self.i32_load8u(mem),
3072 DiscriminantSize::Size2 => self.i32_load16u(mem),
3073 DiscriminantSize::Size4 => self.i32_load(mem),
3074 },
3075 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
3076 }
3077 let tmp = self.local_tee_new_tmp(ValType::I32);
3078
3079 self.instruction(I32Const(i32::try_from(src_ty.names.len()).unwrap()));
3081 self.instruction(I32GeU);
3082 self.instruction(If(BlockType::Empty));
3083 self.trap(Trap::InvalidDiscriminant);
3084 self.instruction(End);
3085
3086 match dst {
3088 Destination::Stack(stack, _) => {
3089 self.local_get_tmp(&tmp);
3090 self.stack_set(&stack[..1], ValType::I32)
3091 }
3092 Destination::Memory(mem) => {
3093 self.push_dst_addr(dst);
3094 self.local_get_tmp(&tmp);
3095 match dst_ty.info.size {
3096 DiscriminantSize::Size1 => self.i32_store8(mem),
3097 DiscriminantSize::Size2 => self.i32_store16(mem),
3098 DiscriminantSize::Size4 => self.i32_store(mem),
3099 }
3100 }
3101 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
3102 }
3103 self.free_temp_local(tmp);
3104 }
3105
3106 fn translate_option(
3107 &mut self,
3108 src_ty: TypeOptionIndex,
3109 src: &Source<'_>,
3110 dst_ty: &InterfaceType,
3111 dst: &Destination,
3112 ) {
3113 let src_ty = &self.types[src_ty].ty;
3114 let dst_ty = match dst_ty {
3115 InterfaceType::Option(t) => &self.types[*t].ty,
3116 _ => panic!("expected an option"),
3117 };
3118 let src_ty = Some(src_ty);
3119 let dst_ty = Some(dst_ty);
3120
3121 let src_info = variant_info(self.types, [None, src_ty]);
3122 let dst_info = variant_info(self.types, [None, dst_ty]);
3123
3124 self.convert_variant(
3125 src,
3126 &src_info,
3127 dst,
3128 &dst_info,
3129 [
3130 VariantCase {
3131 src_i: 0,
3132 dst_i: 0,
3133 src_ty: None,
3134 dst_ty: None,
3135 },
3136 VariantCase {
3137 src_i: 1,
3138 dst_i: 1,
3139 src_ty,
3140 dst_ty,
3141 },
3142 ]
3143 .into_iter(),
3144 );
3145 }
3146
3147 fn translate_result(
3148 &mut self,
3149 src_ty: TypeResultIndex,
3150 src: &Source<'_>,
3151 dst_ty: &InterfaceType,
3152 dst: &Destination,
3153 ) {
3154 let src_ty = &self.types[src_ty];
3155 let dst_ty = match dst_ty {
3156 InterfaceType::Result(t) => &self.types[*t],
3157 _ => panic!("expected a result"),
3158 };
3159
3160 let src_info = variant_info(self.types, [src_ty.ok.as_ref(), src_ty.err.as_ref()]);
3161 let dst_info = variant_info(self.types, [dst_ty.ok.as_ref(), dst_ty.err.as_ref()]);
3162
3163 self.convert_variant(
3164 src,
3165 &src_info,
3166 dst,
3167 &dst_info,
3168 [
3169 VariantCase {
3170 src_i: 0,
3171 dst_i: 0,
3172 src_ty: src_ty.ok.as_ref(),
3173 dst_ty: dst_ty.ok.as_ref(),
3174 },
3175 VariantCase {
3176 src_i: 1,
3177 dst_i: 1,
3178 src_ty: src_ty.err.as_ref(),
3179 dst_ty: dst_ty.err.as_ref(),
3180 },
3181 ]
3182 .into_iter(),
3183 );
3184 }
3185
3186 fn convert_variant<'c>(
3187 &mut self,
3188 src: &Source<'_>,
3189 src_info: &VariantInfo,
3190 dst: &Destination,
3191 dst_info: &VariantInfo,
3192 src_cases: impl ExactSizeIterator<Item = VariantCase<'c>>,
3193 ) {
3194 let outer_block_ty = match dst {
3197 Destination::Stack(dst_flat, _) => match dst_flat.len() {
3198 0 => BlockType::Empty,
3199 1 => BlockType::Result(dst_flat[0]),
3200 _ => {
3201 let ty = self.module.core_types.function(&[], &dst_flat);
3202 BlockType::FunctionType(ty)
3203 }
3204 },
3205 Destination::Memory(_) => BlockType::Empty,
3206 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
3207 };
3208 self.instruction(Block(outer_block_ty));
3209
3210 let src_cases_len = src_cases.len();
3213 for _ in 0..src_cases_len - 1 {
3214 self.instruction(Block(BlockType::Empty));
3215 }
3216
3217 self.instruction(Block(BlockType::Empty));
3219
3220 self.instruction(Block(BlockType::Empty));
3223
3224 match src {
3226 Source::Stack(s) => self.stack_get(&s.slice(0..1), ValType::I32),
3227 Source::Memory(mem) => match src_info.size {
3228 DiscriminantSize::Size1 => self.i32_load8u(mem),
3229 DiscriminantSize::Size2 => self.i32_load16u(mem),
3230 DiscriminantSize::Size4 => self.i32_load(mem),
3231 },
3232 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
3233 }
3234
3235 let mut targets = Vec::new();
3238 for i in 0..src_cases_len {
3239 targets.push((i + 1) as u32);
3240 }
3241 self.instruction(BrTable(targets[..].into(), 0));
3242 self.instruction(End); self.trap(Trap::InvalidDiscriminant);
3245 self.instruction(End); let src_cases_len = u32::try_from(src_cases_len).unwrap();
3252 for case in src_cases {
3253 let VariantCase {
3254 src_i,
3255 src_ty,
3256 dst_i,
3257 dst_ty,
3258 } = case;
3259
3260 self.push_dst_addr(dst);
3263 self.instruction(I32Const(dst_i as i32));
3264 match dst {
3265 Destination::Stack(stack, _) => self.stack_set(&stack[..1], ValType::I32),
3266 Destination::Memory(mem) => match dst_info.size {
3267 DiscriminantSize::Size1 => self.i32_store8(mem),
3268 DiscriminantSize::Size2 => self.i32_store16(mem),
3269 DiscriminantSize::Size4 => self.i32_store(mem),
3270 },
3271 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
3272 }
3273
3274 let src_payload = src.payload_src(self.types, src_info, src_ty);
3275 let dst_payload = dst.payload_dst(self.types, dst_info, dst_ty);
3276
3277 match (src_ty, dst_ty) {
3280 (Some(src_ty), Some(dst_ty)) => {
3281 self.translate(src_ty, &src_payload, dst_ty, &dst_payload);
3282 }
3283 (None, None) => {}
3284 _ => unimplemented!(),
3285 }
3286
3287 if let Destination::Stack(payload_results, _) = dst_payload {
3294 if let Destination::Stack(dst_results, _) = dst {
3295 let remaining = &dst_results[1..][payload_results.len()..];
3296 for ty in remaining {
3297 match ty {
3298 ValType::I32 => self.instruction(I32Const(0)),
3299 ValType::I64 => self.instruction(I64Const(0)),
3300 ValType::F32 => self.instruction(F32Const(0.0.into())),
3301 ValType::F64 => self.instruction(F64Const(0.0.into())),
3302 _ => unreachable!(),
3303 }
3304 }
3305 }
3306 }
3307
3308 if src_i != src_cases_len - 1 {
3311 self.instruction(Br(src_cases_len - src_i - 1));
3312 }
3313 self.instruction(End); }
3315 }
3316
3317 fn translate_future(
3318 &mut self,
3319 src_ty: TypeFutureTableIndex,
3320 src: &Source<'_>,
3321 dst_ty: &InterfaceType,
3322 dst: &Destination,
3323 ) {
3324 let dst_ty = match dst_ty {
3325 InterfaceType::Future(t) => *t,
3326 _ => panic!("expected a `Future`"),
3327 };
3328 let transfer = self.module.import_future_transfer();
3329 self.translate_handle(src_ty.as_u32(), src, dst_ty.as_u32(), dst, transfer);
3330 }
3331
3332 fn translate_stream(
3333 &mut self,
3334 src_ty: TypeStreamTableIndex,
3335 src: &Source<'_>,
3336 dst_ty: &InterfaceType,
3337 dst: &Destination,
3338 ) {
3339 let dst_ty = match dst_ty {
3340 InterfaceType::Stream(t) => *t,
3341 _ => panic!("expected a `Stream`"),
3342 };
3343 let transfer = self.module.import_stream_transfer();
3344 self.translate_handle(src_ty.as_u32(), src, dst_ty.as_u32(), dst, transfer);
3345 }
3346
3347 fn translate_error_context(
3348 &mut self,
3349 src_ty: TypeComponentLocalErrorContextTableIndex,
3350 src: &Source<'_>,
3351 dst_ty: &InterfaceType,
3352 dst: &Destination,
3353 ) {
3354 let dst_ty = match dst_ty {
3355 InterfaceType::ErrorContext(t) => *t,
3356 _ => panic!("expected an `ErrorContext`"),
3357 };
3358 let transfer = self.module.import_error_context_transfer();
3359 self.translate_handle(src_ty.as_u32(), src, dst_ty.as_u32(), dst, transfer);
3360 }
3361
3362 fn translate_own(
3363 &mut self,
3364 src_ty: TypeResourceTableIndex,
3365 src: &Source<'_>,
3366 dst_ty: &InterfaceType,
3367 dst: &Destination,
3368 ) {
3369 let dst_ty = match dst_ty {
3370 InterfaceType::Own(t) => *t,
3371 _ => panic!("expected an `Own`"),
3372 };
3373 let transfer = self.module.import_resource_transfer_own();
3374 self.translate_handle(src_ty.as_u32(), src, dst_ty.as_u32(), dst, transfer);
3375 }
3376
3377 fn translate_borrow(
3378 &mut self,
3379 src_ty: TypeResourceTableIndex,
3380 src: &Source<'_>,
3381 dst_ty: &InterfaceType,
3382 dst: &Destination,
3383 ) {
3384 let dst_ty = match dst_ty {
3385 InterfaceType::Borrow(t) => *t,
3386 _ => panic!("expected an `Borrow`"),
3387 };
3388
3389 let transfer = self.module.import_resource_transfer_borrow();
3390 self.translate_handle(src_ty.as_u32(), src, dst_ty.as_u32(), dst, transfer);
3391 }
3392
3393 fn translate_handle(
3401 &mut self,
3402 src_ty: u32,
3403 src: &Source<'_>,
3404 dst_ty: u32,
3405 dst: &Destination,
3406 transfer: FuncIndex,
3407 ) {
3408 self.push_dst_addr(dst);
3409 match src {
3410 Source::Memory(mem) => self.i32_load(mem),
3411 Source::Stack(stack) => self.stack_get(stack, ValType::I32),
3412 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
3413 }
3414 self.instruction(I32Const(src_ty as i32));
3415 self.instruction(I32Const(dst_ty as i32));
3416 self.instruction(Call(transfer.as_u32()));
3417 match dst {
3418 Destination::Memory(mem) => self.i32_store(mem),
3419 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
3420 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
3421 }
3422 }
3423
3424 fn trap_if_not_flag(&mut self, flags_global: GlobalIndex, flag_to_test: i32, trap: Trap) {
3425 self.instruction(GlobalGet(flags_global.as_u32()));
3426 self.instruction(I32Const(flag_to_test));
3427 self.instruction(I32And);
3428 self.instruction(I32Eqz);
3429 self.instruction(If(BlockType::Empty));
3430 self.trap(trap);
3431 self.instruction(End);
3432 }
3433
3434 fn set_flag(&mut self, flags_global: GlobalIndex, flag_to_set: i32, value: bool) {
3435 self.instruction(GlobalGet(flags_global.as_u32()));
3436 if value {
3437 self.instruction(I32Const(flag_to_set));
3438 self.instruction(I32Or);
3439 } else {
3440 self.instruction(I32Const(!flag_to_set));
3441 self.instruction(I32And);
3442 }
3443 self.instruction(GlobalSet(flags_global.as_u32()));
3444 }
3445
3446 fn verify_aligned(&mut self, opts: &LinearMemoryOptions, addr_local: u32, align: u32) {
3447 if align == 1 {
3450 return;
3451 }
3452 self.instruction(LocalGet(addr_local));
3453 assert!(align.is_power_of_two());
3454 self.ptr_uconst(opts, align - 1);
3455 self.ptr_and(opts);
3456 self.ptr_if(opts, BlockType::Empty);
3457 self.trap(Trap::UnalignedPointer);
3458 self.instruction(End);
3459 }
3460
3461 fn assert_aligned(&mut self, ty: &InterfaceType, mem: &Memory) {
3462 let mem_opts = mem.mem_opts();
3463 if !self.module.tunables.debug_adapter_modules {
3464 return;
3465 }
3466 let align = self.types.align(mem_opts, ty);
3467 if align == 1 {
3468 return;
3469 }
3470 assert!(align.is_power_of_two());
3471 self.instruction(LocalGet(mem.addr.idx));
3472 self.ptr_uconst(mem_opts, mem.offset);
3473 self.ptr_add(mem_opts);
3474 self.ptr_uconst(mem_opts, align - 1);
3475 self.ptr_and(mem_opts);
3476 self.ptr_if(mem_opts, BlockType::Empty);
3477 self.trap(Trap::DebugAssertPointerAligned);
3478 self.instruction(End);
3479 }
3480
3481 fn malloc<'c>(&mut self, opts: &'c Options, size: MallocSize, align: u32) -> Memory<'c> {
3482 match &opts.data_model {
3483 DataModel::Gc {} => todo!("CM+GC"),
3484 DataModel::LinearMemory(mem_opts) => {
3485 let realloc = mem_opts.realloc.unwrap();
3486 self.ptr_uconst(mem_opts, 0);
3487 self.ptr_uconst(mem_opts, 0);
3488 self.ptr_uconst(mem_opts, align);
3489 match size {
3490 MallocSize::Const(size) => self.ptr_uconst(mem_opts, size),
3491 MallocSize::Local(idx) => self.instruction(LocalGet(idx)),
3492 }
3493 self.instruction(Call(realloc.as_u32()));
3494 let addr = self.local_set_new_tmp(mem_opts.ptr());
3495 self.memory_operand(opts, addr, align)
3496 }
3497 }
3498 }
3499
3500 fn memory_operand<'c>(&mut self, opts: &'c Options, addr: TempLocal, align: u32) -> Memory<'c> {
3501 let ret = Memory {
3502 addr,
3503 offset: 0,
3504 opts,
3505 };
3506 self.verify_aligned(opts.data_model.unwrap_memory(), ret.addr.idx, align);
3507 ret
3508 }
3509
3510 fn local_tee_new_tmp(&mut self, ty: ValType) -> TempLocal {
3516 self.gen_temp_local(ty, LocalTee)
3517 }
3518
3519 fn local_set_new_tmp(&mut self, ty: ValType) -> TempLocal {
3522 self.gen_temp_local(ty, LocalSet)
3523 }
3524
3525 fn local_get_tmp(&mut self, local: &TempLocal) {
3526 self.instruction(LocalGet(local.idx));
3527 }
3528
3529 fn gen_temp_local(&mut self, ty: ValType, insn: fn(u32) -> Instruction<'static>) -> TempLocal {
3530 if let Some(idx) = self.free_locals.get_mut(&ty).and_then(|v| v.pop()) {
3533 self.instruction(insn(idx));
3534 return TempLocal {
3535 ty,
3536 idx,
3537 needs_free: true,
3538 };
3539 }
3540
3541 let locals = &mut self.module.funcs[self.result].locals;
3543 match locals.last_mut() {
3544 Some((cnt, prev_ty)) if ty == *prev_ty => *cnt += 1,
3545 _ => locals.push((1, ty)),
3546 }
3547 self.nlocals += 1;
3548 let idx = self.nlocals - 1;
3549 self.instruction(insn(idx));
3550 TempLocal {
3551 ty,
3552 idx,
3553 needs_free: true,
3554 }
3555 }
3556
3557 fn free_temp_local(&mut self, mut local: TempLocal) {
3560 assert!(local.needs_free);
3561 self.free_locals
3562 .entry(local.ty)
3563 .or_insert(Vec::new())
3564 .push(local.idx);
3565 local.needs_free = false;
3566 }
3567
3568 fn instruction(&mut self, instr: Instruction) {
3569 instr.encode(&mut self.code);
3570 }
3571
3572 fn trap(&mut self, trap: Trap) {
3573 let trap_func = self.module.import_trap();
3574 self.instruction(I32Const(trap as i32));
3575 self.instruction(Call(trap_func.as_u32()));
3576 self.instruction(Unreachable);
3577 }
3578
3579 fn flush_code(&mut self) {
3584 if self.code.is_empty() {
3585 return;
3586 }
3587 self.module.funcs[self.result]
3588 .body
3589 .push(Body::Raw(mem::take(&mut self.code)));
3590 }
3591
3592 fn finish(mut self) {
3593 self.instruction(End);
3596 self.flush_code();
3597
3598 self.module.funcs[self.result].filled_in = true;
3601 }
3602
3603 fn stack_get(&mut self, stack: &Stack<'_>, dst_ty: ValType) {
3611 assert_eq!(stack.locals.len(), 1);
3612 let (idx, src_ty) = stack.locals[0];
3613 self.instruction(LocalGet(idx));
3614 match (src_ty, dst_ty) {
3615 (ValType::I32, ValType::I32)
3616 | (ValType::I64, ValType::I64)
3617 | (ValType::F32, ValType::F32)
3618 | (ValType::F64, ValType::F64) => {}
3619
3620 (ValType::I32, ValType::F32) => self.instruction(F32ReinterpretI32),
3621 (ValType::I64, ValType::I32) => {
3622 self.assert_i64_upper_bits_not_set(idx);
3623 self.instruction(I32WrapI64);
3624 }
3625 (ValType::I64, ValType::F64) => self.instruction(F64ReinterpretI64),
3626 (ValType::I64, ValType::F32) => {
3627 self.assert_i64_upper_bits_not_set(idx);
3628 self.instruction(I32WrapI64);
3629 self.instruction(F32ReinterpretI32);
3630 }
3631
3632 (ValType::I32, ValType::I64)
3634 | (ValType::I32, ValType::F64)
3635 | (ValType::F32, ValType::I32)
3636 | (ValType::F32, ValType::I64)
3637 | (ValType::F32, ValType::F64)
3638 | (ValType::F64, ValType::I32)
3639 | (ValType::F64, ValType::I64)
3640 | (ValType::F64, ValType::F32)
3641
3642 | (ValType::Ref(_), _)
3644 | (_, ValType::Ref(_))
3645 | (ValType::V128, _)
3646 | (_, ValType::V128) => {
3647 panic!("cannot get {dst_ty:?} from {src_ty:?} local");
3648 }
3649 }
3650 }
3651
3652 fn assert_i64_upper_bits_not_set(&mut self, local: u32) {
3653 if !self.module.tunables.debug_adapter_modules {
3654 return;
3655 }
3656 self.instruction(LocalGet(local));
3657 self.instruction(I64Const(32));
3658 self.instruction(I64ShrU);
3659 self.instruction(I32WrapI64);
3660 self.instruction(If(BlockType::Empty));
3661 self.trap(Trap::DebugAssertUpperBitsUnset);
3662 self.instruction(End);
3663 }
3664
3665 fn stack_set(&mut self, dst_tys: &[ValType], src_ty: ValType) {
3671 assert_eq!(dst_tys.len(), 1);
3672 let dst_ty = dst_tys[0];
3673 match (src_ty, dst_ty) {
3674 (ValType::I32, ValType::I32)
3675 | (ValType::I64, ValType::I64)
3676 | (ValType::F32, ValType::F32)
3677 | (ValType::F64, ValType::F64) => {}
3678
3679 (ValType::F32, ValType::I32) => self.instruction(I32ReinterpretF32),
3680 (ValType::I32, ValType::I64) => self.instruction(I64ExtendI32U),
3681 (ValType::F64, ValType::I64) => self.instruction(I64ReinterpretF64),
3682 (ValType::F32, ValType::I64) => {
3683 self.instruction(I32ReinterpretF32);
3684 self.instruction(I64ExtendI32U);
3685 }
3686
3687 (ValType::I64, ValType::I32)
3689 | (ValType::F64, ValType::I32)
3690 | (ValType::I32, ValType::F32)
3691 | (ValType::I64, ValType::F32)
3692 | (ValType::F64, ValType::F32)
3693 | (ValType::I32, ValType::F64)
3694 | (ValType::I64, ValType::F64)
3695 | (ValType::F32, ValType::F64)
3696
3697 | (ValType::Ref(_), _)
3699 | (_, ValType::Ref(_))
3700 | (ValType::V128, _)
3701 | (_, ValType::V128) => {
3702 panic!("cannot get {dst_ty:?} from {src_ty:?} local");
3703 }
3704 }
3705 }
3706
3707 fn i32_load8u(&mut self, mem: &Memory) {
3708 self.instruction(LocalGet(mem.addr.idx));
3709 self.instruction(I32Load8U(mem.memarg(0)));
3710 }
3711
3712 fn i32_load8s(&mut self, mem: &Memory) {
3713 self.instruction(LocalGet(mem.addr.idx));
3714 self.instruction(I32Load8S(mem.memarg(0)));
3715 }
3716
3717 fn i32_load16u(&mut self, mem: &Memory) {
3718 self.instruction(LocalGet(mem.addr.idx));
3719 self.instruction(I32Load16U(mem.memarg(1)));
3720 }
3721
3722 fn i32_load16s(&mut self, mem: &Memory) {
3723 self.instruction(LocalGet(mem.addr.idx));
3724 self.instruction(I32Load16S(mem.memarg(1)));
3725 }
3726
3727 fn i32_load(&mut self, mem: &Memory) {
3728 self.instruction(LocalGet(mem.addr.idx));
3729 self.instruction(I32Load(mem.memarg(2)));
3730 }
3731
3732 fn i64_load(&mut self, mem: &Memory) {
3733 self.instruction(LocalGet(mem.addr.idx));
3734 self.instruction(I64Load(mem.memarg(3)));
3735 }
3736
3737 fn ptr_load(&mut self, mem: &Memory) {
3738 if mem.mem_opts().memory64 {
3739 self.i64_load(mem);
3740 } else {
3741 self.i32_load(mem);
3742 }
3743 }
3744
3745 fn ptr_add(&mut self, opts: &LinearMemoryOptions) {
3746 if opts.memory64 {
3747 self.instruction(I64Add);
3748 } else {
3749 self.instruction(I32Add);
3750 }
3751 }
3752
3753 fn ptr_sub(&mut self, opts: &LinearMemoryOptions) {
3754 if opts.memory64 {
3755 self.instruction(I64Sub);
3756 } else {
3757 self.instruction(I32Sub);
3758 }
3759 }
3760
3761 fn ptr_mul(&mut self, opts: &LinearMemoryOptions) {
3762 if opts.memory64 {
3763 self.instruction(I64Mul);
3764 } else {
3765 self.instruction(I32Mul);
3766 }
3767 }
3768
3769 fn ptr_ge_u(&mut self, opts: &LinearMemoryOptions) {
3770 if opts.memory64 {
3771 self.instruction(I64GeU);
3772 } else {
3773 self.instruction(I32GeU);
3774 }
3775 }
3776
3777 fn ptr_lt_u(&mut self, opts: &LinearMemoryOptions) {
3778 if opts.memory64 {
3779 self.instruction(I64LtU);
3780 } else {
3781 self.instruction(I32LtU);
3782 }
3783 }
3784
3785 fn ptr_shl(&mut self, opts: &LinearMemoryOptions) {
3786 if opts.memory64 {
3787 self.instruction(I64Shl);
3788 } else {
3789 self.instruction(I32Shl);
3790 }
3791 }
3792
3793 fn ptr_eqz(&mut self, opts: &LinearMemoryOptions) {
3794 if opts.memory64 {
3795 self.instruction(I64Eqz);
3796 } else {
3797 self.instruction(I32Eqz);
3798 }
3799 }
3800
3801 fn ptr_uconst(&mut self, opts: &LinearMemoryOptions, val: u32) {
3802 if opts.memory64 {
3803 self.instruction(I64Const(val.into()));
3804 } else {
3805 self.instruction(I32Const(val as i32));
3806 }
3807 }
3808
3809 fn ptr_iconst(&mut self, opts: &LinearMemoryOptions, val: i32) {
3810 if opts.memory64 {
3811 self.instruction(I64Const(val.into()));
3812 } else {
3813 self.instruction(I32Const(val));
3814 }
3815 }
3816
3817 fn ptr_eq(&mut self, opts: &LinearMemoryOptions) {
3818 if opts.memory64 {
3819 self.instruction(I64Eq);
3820 } else {
3821 self.instruction(I32Eq);
3822 }
3823 }
3824
3825 fn ptr_ne(&mut self, opts: &LinearMemoryOptions) {
3826 if opts.memory64 {
3827 self.instruction(I64Ne);
3828 } else {
3829 self.instruction(I32Ne);
3830 }
3831 }
3832
3833 fn ptr_and(&mut self, opts: &LinearMemoryOptions) {
3834 if opts.memory64 {
3835 self.instruction(I64And);
3836 } else {
3837 self.instruction(I32And);
3838 }
3839 }
3840
3841 fn ptr_or(&mut self, opts: &LinearMemoryOptions) {
3842 if opts.memory64 {
3843 self.instruction(I64Or);
3844 } else {
3845 self.instruction(I32Or);
3846 }
3847 }
3848
3849 fn ptr_xor(&mut self, opts: &LinearMemoryOptions) {
3850 if opts.memory64 {
3851 self.instruction(I64Xor);
3852 } else {
3853 self.instruction(I32Xor);
3854 }
3855 }
3856
3857 fn ptr_if(&mut self, opts: &LinearMemoryOptions, ty: BlockType) {
3858 if opts.memory64 {
3859 self.instruction(I64Const(0));
3860 self.instruction(I64Ne);
3861 }
3862 self.instruction(If(ty));
3863 }
3864
3865 fn ptr_br_if(&mut self, opts: &LinearMemoryOptions, depth: u32) {
3866 if opts.memory64 {
3867 self.instruction(I64Const(0));
3868 self.instruction(I64Ne);
3869 }
3870 self.instruction(BrIf(depth));
3871 }
3872
3873 fn f32_load(&mut self, mem: &Memory) {
3874 self.instruction(LocalGet(mem.addr.idx));
3875 self.instruction(F32Load(mem.memarg(2)));
3876 }
3877
3878 fn f64_load(&mut self, mem: &Memory) {
3879 self.instruction(LocalGet(mem.addr.idx));
3880 self.instruction(F64Load(mem.memarg(3)));
3881 }
3882
3883 fn push_dst_addr(&mut self, dst: &Destination) {
3884 if let Destination::Memory(mem) = dst {
3885 self.instruction(LocalGet(mem.addr.idx));
3886 }
3887 }
3888
3889 fn i32_store8(&mut self, mem: &Memory) {
3890 self.instruction(I32Store8(mem.memarg(0)));
3891 }
3892
3893 fn i32_store16(&mut self, mem: &Memory) {
3894 self.instruction(I32Store16(mem.memarg(1)));
3895 }
3896
3897 fn i32_store(&mut self, mem: &Memory) {
3898 self.instruction(I32Store(mem.memarg(2)));
3899 }
3900
3901 fn i64_store(&mut self, mem: &Memory) {
3902 self.instruction(I64Store(mem.memarg(3)));
3903 }
3904
3905 fn ptr_store(&mut self, mem: &Memory) {
3906 if mem.mem_opts().memory64 {
3907 self.i64_store(mem);
3908 } else {
3909 self.i32_store(mem);
3910 }
3911 }
3912
3913 fn f32_store(&mut self, mem: &Memory) {
3914 self.instruction(F32Store(mem.memarg(2)));
3915 }
3916
3917 fn f64_store(&mut self, mem: &Memory) {
3918 self.instruction(F64Store(mem.memarg(3)));
3919 }
3920}
3921
3922impl<'a> Source<'a> {
3923 fn record_field_srcs<'b>(
3930 &'b self,
3931 types: &'b ComponentTypesBuilder,
3932 fields: impl IntoIterator<Item = InterfaceType> + 'b,
3933 ) -> impl Iterator<Item = Source<'a>> + 'b
3934 where
3935 'a: 'b,
3936 {
3937 let mut offset = 0;
3938 fields.into_iter().map(move |ty| match self {
3939 Source::Memory(mem) => {
3940 let mem = next_field_offset(&mut offset, types, &ty, mem);
3941 Source::Memory(mem)
3942 }
3943 Source::Stack(stack) => {
3944 let cnt = types.flat_types(&ty).unwrap().len() as u32;
3945 offset += cnt;
3946 Source::Stack(stack.slice((offset - cnt) as usize..offset as usize))
3947 }
3948 Source::Struct(_) => todo!(),
3949 Source::Array(_) => todo!(),
3950 })
3951 }
3952
3953 fn payload_src(
3955 &self,
3956 types: &ComponentTypesBuilder,
3957 info: &VariantInfo,
3958 case: Option<&InterfaceType>,
3959 ) -> Source<'a> {
3960 match self {
3961 Source::Stack(s) => {
3962 let flat_len = match case {
3963 Some(case) => types.flat_types(case).unwrap().len(),
3964 None => 0,
3965 };
3966 Source::Stack(s.slice(1..s.locals.len()).slice(0..flat_len))
3967 }
3968 Source::Memory(mem) => {
3969 let mem = if mem.mem_opts().memory64 {
3970 mem.bump(info.payload_offset64)
3971 } else {
3972 mem.bump(info.payload_offset32)
3973 };
3974 Source::Memory(mem)
3975 }
3976 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
3977 }
3978 }
3979
3980 fn opts(&self) -> &'a Options {
3981 match self {
3982 Source::Stack(s) => s.opts,
3983 Source::Memory(mem) => mem.opts,
3984 Source::Struct(s) => s.opts,
3985 Source::Array(a) => a.opts,
3986 }
3987 }
3988}
3989
3990impl<'a> Destination<'a> {
3991 fn record_field_dsts<'b, I>(
3993 &'b self,
3994 types: &'b ComponentTypesBuilder,
3995 fields: I,
3996 ) -> impl Iterator<Item = Destination<'b>> + use<'b, I>
3997 where
3998 'a: 'b,
3999 I: IntoIterator<Item = InterfaceType> + 'b,
4000 {
4001 let mut offset = 0;
4002 fields.into_iter().map(move |ty| match self {
4003 Destination::Memory(mem) => {
4004 let mem = next_field_offset(&mut offset, types, &ty, mem);
4005 Destination::Memory(mem)
4006 }
4007 Destination::Stack(s, opts) => {
4008 let cnt = types.flat_types(&ty).unwrap().len() as u32;
4009 offset += cnt;
4010 Destination::Stack(&s[(offset - cnt) as usize..offset as usize], opts)
4011 }
4012 Destination::Struct(_) => todo!(),
4013 Destination::Array(_) => todo!(),
4014 })
4015 }
4016
4017 fn payload_dst(
4019 &self,
4020 types: &ComponentTypesBuilder,
4021 info: &VariantInfo,
4022 case: Option<&InterfaceType>,
4023 ) -> Destination<'_> {
4024 match self {
4025 Destination::Stack(s, opts) => {
4026 let flat_len = match case {
4027 Some(case) => types.flat_types(case).unwrap().len(),
4028 None => 0,
4029 };
4030 Destination::Stack(&s[1..][..flat_len], opts)
4031 }
4032 Destination::Memory(mem) => {
4033 let mem = if mem.mem_opts().memory64 {
4034 mem.bump(info.payload_offset64)
4035 } else {
4036 mem.bump(info.payload_offset32)
4037 };
4038 Destination::Memory(mem)
4039 }
4040 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
4041 }
4042 }
4043
4044 fn opts(&self) -> &'a Options {
4045 match self {
4046 Destination::Stack(_, opts) => opts,
4047 Destination::Memory(mem) => mem.opts,
4048 Destination::Struct(s) => s.opts,
4049 Destination::Array(a) => a.opts,
4050 }
4051 }
4052}
4053
4054fn next_field_offset<'a>(
4055 offset: &mut u32,
4056 types: &ComponentTypesBuilder,
4057 field: &InterfaceType,
4058 mem: &Memory<'a>,
4059) -> Memory<'a> {
4060 let abi = types.canonical_abi(field);
4061 let offset = if mem.mem_opts().memory64 {
4062 abi.next_field64(offset)
4063 } else {
4064 abi.next_field32(offset)
4065 };
4066 mem.bump(offset)
4067}
4068
4069impl<'a> Memory<'a> {
4070 fn memarg(&self, align: u32) -> MemArg {
4071 MemArg {
4072 offset: u64::from(self.offset),
4073 align,
4074 memory_index: self.mem_opts().memory.unwrap().as_u32(),
4075 }
4076 }
4077
4078 fn bump(&self, offset: u32) -> Memory<'a> {
4079 Memory {
4080 opts: self.opts,
4081 addr: TempLocal::new(self.addr.idx, self.addr.ty),
4082 offset: self.offset + offset,
4083 }
4084 }
4085}
4086
4087impl<'a> Stack<'a> {
4088 fn slice(&self, range: Range<usize>) -> Stack<'a> {
4089 Stack {
4090 locals: &self.locals[range],
4091 opts: self.opts,
4092 }
4093 }
4094}
4095
4096struct VariantCase<'a> {
4097 src_i: u32,
4098 src_ty: Option<&'a InterfaceType>,
4099 dst_i: u32,
4100 dst_ty: Option<&'a InterfaceType>,
4101}
4102
4103fn variant_info<'a, I>(types: &ComponentTypesBuilder, cases: I) -> VariantInfo
4104where
4105 I: IntoIterator<Item = Option<&'a InterfaceType>>,
4106 I::IntoIter: ExactSizeIterator,
4107{
4108 VariantInfo::new(
4109 cases
4110 .into_iter()
4111 .map(|ty| ty.map(|ty| types.canonical_abi(ty))),
4112 )
4113 .0
4114}
4115
4116enum MallocSize {
4117 Const(u32),
4118 Local(u32),
4119}
4120
4121struct WasmString<'a> {
4122 ptr: TempLocal,
4123 len: TempLocal,
4124 opts: &'a Options,
4125}
4126
4127struct TempLocal {
4128 idx: u32,
4129 ty: ValType,
4130 needs_free: bool,
4131}
4132
4133impl TempLocal {
4134 fn new(idx: u32, ty: ValType) -> TempLocal {
4135 TempLocal {
4136 idx,
4137 ty,
4138 needs_free: false,
4139 }
4140 }
4141}
4142
4143impl std::ops::Drop for TempLocal {
4144 fn drop(&mut self) {
4145 if self.needs_free {
4146 panic!("temporary local not free'd");
4147 }
4148 }
4149}
4150
4151impl From<FlatType> for ValType {
4152 fn from(ty: FlatType) -> ValType {
4153 match ty {
4154 FlatType::I32 => ValType::I32,
4155 FlatType::I64 => ValType::I64,
4156 FlatType::F32 => ValType::F32,
4157 FlatType::F64 => ValType::F64,
4158 }
4159 }
4160}