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