1use crate::component::{
19 CanonicalAbiInfo, ComponentTypesBuilder, FixedEncoding as FE, FlatType, InterfaceType,
20 MAX_FLAT_ASYNC_PARAMS, MAX_FLAT_PARAMS, PREPARE_ASYNC_NO_RESULT, PREPARE_ASYNC_WITH_RESULT,
21 START_FLAG_ASYNC_CALLEE, START_FLAG_ASYNC_CALLER, StringEncoding, Transcode,
22 TypeComponentLocalErrorContextTableIndex, TypeEnumIndex, TypeFixedLengthListIndex,
23 TypeFlagsIndex, TypeFutureTableIndex, TypeListIndex, TypeMapIndex, TypeOptionIndex,
24 TypeRecordIndex, TypeResourceTableIndex, TypeResultIndex, TypeStreamTableIndex, TypeTupleIndex,
25 TypeVariantIndex, VariantInfo,
26};
27use crate::fact::signature::Signature;
28use crate::fact::transcode::Transcoder;
29use crate::fact::{
30 AdapterData, Body, Function, FunctionId, Helper, HelperLocation, HelperType,
31 LinearMemoryOptions, Module, Options,
32};
33use crate::prelude::*;
34use crate::{FuncIndex, GlobalIndex, IndexType, NUM_COMPONENT_CONTEXT_SLOTS, Trap};
35use std::collections::HashMap;
36use std::mem;
37use std::ops::Range;
38use wasm_encoder::{
39 BlockType, Catch, Encode, Instruction, Instruction::*, MemArg, MemArgTarget, ValType,
40};
41use wasmtime_component_util::{DiscriminantSize, FlagsSize};
42
43use super::DataModel;
44
45const MAX_STRING_BYTE_LENGTH: u32 = (1 << 31) - 1;
46const UTF16_TAG: u32 = 1 << 31;
47
48const INITIAL_FUEL: usize = 1_000;
51
52struct Compiler<'a, 'b> {
53 types: &'a ComponentTypesBuilder,
54 module: &'b mut Module<'a>,
55 result: FunctionId,
56
57 code: Vec<u8>,
59
60 nlocals: u32,
62
63 free_locals: HashMap<ValType, Vec<u32>>,
65
66 fuel: usize,
75
76 emit_resource_call: bool,
81}
82
83pub(super) fn compile(module: &mut Module<'_>, adapter: &AdapterData) {
84 fn compiler<'a, 'b>(
85 module: &'b mut Module<'a>,
86 adapter: &AdapterData,
87 ) -> (Compiler<'a, 'b>, Signature, Signature) {
88 let lower_sig = module.types.signature(&adapter.lower);
89 let lift_sig = module.types.signature(&adapter.lift);
90 let ty = module
91 .core_types
92 .function(&lower_sig.params, &lower_sig.results);
93 let result = module
94 .funcs
95 .push(Function::new(Some(adapter.name.clone()), ty));
96
97 let emit_resource_call = module.types.contains_borrow_resource(&adapter.lower);
102 assert_eq!(
103 emit_resource_call,
104 module.types.contains_borrow_resource(&adapter.lift)
105 );
106
107 (
108 Compiler::new(
109 module,
110 result,
111 lower_sig.params.len() as u32,
112 emit_resource_call,
113 ),
114 lower_sig,
115 lift_sig,
116 )
117 }
118
119 if adapter.lift.instance == adapter.lower.instance {
125 let (mut compiler, _, _) = compiler(module, adapter);
126 compiler.trap(Trap::CannotEnterComponent);
127 compiler.finish();
128 return;
129 }
130
131 let async_start_adapter = |module: &mut Module| {
137 let sig = module
138 .types
139 .async_start_signature(&adapter.lower, &adapter.lift);
140 let ty = module.core_types.function(&sig.params, &sig.results);
141 let result = module.funcs.push(Function::new(
142 Some(format!("[async-start]{}", adapter.name)),
143 ty,
144 ));
145
146 Compiler::new(module, result, sig.params.len() as u32, false)
147 .compile_async_start_adapter(adapter, &sig);
148
149 result
150 };
151
152 let async_return_adapter = |module: &mut Module| {
161 let sig = module
162 .types
163 .async_return_signature(&adapter.lower, &adapter.lift);
164 let ty = module.core_types.function(&sig.params, &sig.results);
165 let result = module.funcs.push(Function::new(
166 Some(format!("[async-return]{}", adapter.name)),
167 ty,
168 ));
169
170 Compiler::new(module, result, sig.params.len() as u32, false)
171 .compile_async_return_adapter(adapter, &sig);
172
173 result
174 };
175
176 let lower_async = adapter.lower.options.async_;
177 let lift_async = adapter.lift.options.async_;
178 if !lower_async && !lift_async && !module.types[adapter.lift.ty].async_ {
179 let (compiler, lower_sig, lift_sig) = compiler(module, adapter);
182 compiler.compile_sync_to_sync_adapter(adapter, &lower_sig, &lift_sig);
183 return;
184 }
185
186 assert!(module.tunables.concurrency_support);
187
188 let start = async_start_adapter(module);
211 let return_ = async_return_adapter(module);
212 let (compiler, lower_sig, lift_sig) = compiler(module, adapter);
213 compiler.compile_host_mediated_adapter(adapter, start, return_, &lower_sig, &lift_sig);
214}
215
216pub(super) fn compile_helper(module: &mut Module<'_>, result: FunctionId, helper: Helper) {
223 let mut nlocals = 0;
224 let src_flat;
225 let src = match helper.src.loc {
226 HelperLocation::Stack => {
231 src_flat = module
232 .types
233 .flatten_types(&helper.src.opts, usize::MAX, [helper.src.ty])
234 .unwrap()
235 .iter()
236 .enumerate()
237 .map(|(i, ty)| (i as u32, *ty))
238 .collect::<Vec<_>>();
239 nlocals += src_flat.len() as u32;
240 Source::Stack(Stack {
241 locals: &src_flat,
242 opts: &helper.src.opts,
243 })
244 }
245 HelperLocation::Memory => {
248 nlocals += 1;
249 Source::Memory(Memory {
250 opts: &helper.src.opts,
251 addr: TempLocal::new(0, helper.src.opts.data_model.unwrap_memory().ptr()),
252 offset: 0,
253 })
254 }
255 HelperLocation::StructField | HelperLocation::ArrayElement => todo!("CM+GC"),
256 };
257 let dst_flat;
258 let dst = match helper.dst.loc {
259 HelperLocation::Stack => {
262 dst_flat = module
263 .types
264 .flatten_types(&helper.dst.opts, usize::MAX, [helper.dst.ty])
265 .unwrap();
266 Destination::Stack(&dst_flat, &helper.dst.opts)
267 }
268 HelperLocation::Memory => {
271 nlocals += 1;
272 Destination::Memory(Memory {
273 opts: &helper.dst.opts,
274 addr: TempLocal::new(
275 nlocals - 1,
276 helper.dst.opts.data_model.unwrap_memory().ptr(),
277 ),
278 offset: 0,
279 })
280 }
281 HelperLocation::StructField | HelperLocation::ArrayElement => todo!("CM+GC"),
282 };
283 let mut compiler = Compiler {
284 types: module.types,
285 module,
286 code: Vec::new(),
287 nlocals,
288 free_locals: HashMap::new(),
289 result,
290 fuel: INITIAL_FUEL,
291 emit_resource_call: false,
294 };
295 compiler.translate(&helper.src.ty, &src, &helper.dst.ty, &dst);
296 compiler.finish();
297}
298
299enum Source<'a> {
302 Stack(Stack<'a>),
308
309 Memory(Memory<'a>),
312
313 #[allow(dead_code, reason = "CM+GC is still WIP")]
316 Struct(GcStruct<'a>),
317
318 #[allow(dead_code, reason = "CM+GC is still WIP")]
321 Array(GcArray<'a>),
322}
323
324enum Destination<'a> {
326 Stack(&'a [ValType], &'a Options),
332
333 Memory(Memory<'a>),
335
336 #[allow(dead_code, reason = "CM+GC is still WIP")]
339 Struct(GcStruct<'a>),
340
341 #[allow(dead_code, reason = "CM+GC is still WIP")]
344 Array(GcArray<'a>),
345}
346
347struct Stack<'a> {
348 locals: &'a [(u32, ValType)],
354 opts: &'a Options,
356}
357
358struct Memory<'a> {
360 opts: &'a Options,
362 addr: TempLocal,
365 offset: u32,
368}
369
370impl<'a> Memory<'a> {
371 fn mem_opts(&self) -> &'a LinearMemoryOptions {
372 self.opts.data_model.unwrap_memory()
373 }
374}
375
376struct GcStruct<'a> {
378 opts: &'a Options,
379 }
381
382struct GcArray<'a> {
384 opts: &'a Options,
385 }
387
388impl<'a, 'b> Compiler<'a, 'b> {
389 fn new(
390 module: &'b mut Module<'a>,
391 result: FunctionId,
392 nlocals: u32,
393 emit_resource_call: bool,
394 ) -> Self {
395 Self {
396 types: module.types,
397 module,
398 result,
399 code: Vec::new(),
400 nlocals,
401 free_locals: HashMap::new(),
402 fuel: INITIAL_FUEL,
403 emit_resource_call,
404 }
405 }
406
407 fn compile_host_mediated_adapter(
421 mut self,
422 adapter: &AdapterData,
423 start: FunctionId,
424 return_: FunctionId,
425 lower_sig: &Signature,
426 lift_sig: &Signature,
427 ) {
428 let async_caller = adapter.lower.options.async_;
429 let start_call = self.module.import_start_call(
430 &adapter.name,
431 adapter.lift.options.callback,
432 adapter.lift.post_return,
433 if async_caller {
434 &[ValType::I32]
435 } else {
436 &lower_sig.results
437 },
438 );
439
440 self.call_prepare(adapter, start, return_, lower_sig, !async_caller);
441
442 self.module.exports.push((
451 adapter.callee.as_u32(),
452 format!("[adapter-callee]{}", adapter.name),
453 ));
454
455 let mut flags = 0;
456 if async_caller {
457 flags |= START_FLAG_ASYNC_CALLER;
458 }
459 if adapter.lift.options.async_ {
460 flags |= START_FLAG_ASYNC_CALLEE;
461 }
462
463 self.instruction(RefFunc(adapter.callee.as_u32()));
464 self.instruction(I32Const(i32::try_from(lift_sig.params.len()).unwrap()));
465 self.instruction(I32Const(i32::try_from(lift_sig.results.len()).unwrap()));
466 self.instruction(I32Const(flags));
467 self.instruction(Call(start_call.as_u32()));
468
469 self.finish()
470 }
471
472 fn call_prepare(
485 &mut self,
486 adapter: &AdapterData,
487 start: FunctionId,
488 return_: FunctionId,
489 lower_sig: &Signature,
490 prepare_sync: bool,
491 ) {
492 let saved = self.trap_if_not_may_leave(adapter.lower.flags, Trap::CannotLeaveComponent);
495 self.free_temp_local(saved);
496
497 let prepare = self.module.import_prepare_call(
498 &adapter.name,
499 &lower_sig.params,
500 match adapter.lift.options.data_model {
501 DataModel::Gc {} => todo!("CM+GC"),
502 DataModel::LinearMemory(LinearMemoryOptions { memory, .. }) => memory.map(|m| m.0),
503 },
504 );
505
506 self.push_body(Body::RefFunc(start));
507 self.push_body(Body::RefFunc(return_));
508 self.instruction(I32Const(
509 i32::try_from(adapter.lower.instance.as_u32()).unwrap(),
510 ));
511 self.instruction(I32Const(
512 i32::try_from(adapter.lift.instance.as_u32()).unwrap(),
513 ));
514 self.instruction(I32Const(
515 i32::try_from(self.types[adapter.lift.ty].results.as_u32()).unwrap(),
516 ));
517 self.instruction(I32Const(if self.types[adapter.lift.ty].async_ {
518 1
519 } else {
520 0
521 }));
522 self.instruction(I32Const(i32::from(
523 adapter.lift.options.string_encoding as u8,
524 )));
525
526 let result_types = &self.types[self.types[adapter.lower.ty].results].types;
529 if prepare_sync {
530 self.instruction(I32Const(
531 i32::try_from(
532 self.types
533 .flatten_types(
534 &adapter.lower.options,
535 usize::MAX,
536 result_types.iter().copied(),
537 )
538 .map(|v| v.len())
539 .unwrap_or(usize::try_from(i32::MAX).unwrap()),
540 )
541 .unwrap(),
542 ));
543 } else {
544 if result_types.len() > 0 {
545 self.instruction(I32Const(PREPARE_ASYNC_WITH_RESULT.cast_signed()));
546 } else {
547 self.instruction(I32Const(PREPARE_ASYNC_NO_RESULT.cast_signed()));
548 }
549 }
550
551 for index in 0..lower_sig.params.len() {
553 self.instruction(LocalGet(u32::try_from(index).unwrap()));
554 }
555 self.instruction(Call(prepare.as_u32()));
556 }
557
558 fn compile_async_start_adapter(mut self, adapter: &AdapterData, sig: &Signature) {
564 let param_locals = sig
570 .params
571 .iter()
572 .enumerate()
573 .map(|(i, ty)| (i as u32, *ty))
574 .collect::<Vec<_>>();
575
576 let saved = self.clear_may_leave(adapter.lift.flags);
577 self.translate_params(adapter, ¶m_locals);
578 self.restore_may_leave(adapter.lift.flags, saved);
579
580 self.finish();
581 }
582
583 fn compile_async_return_adapter(mut self, adapter: &AdapterData, sig: &Signature) {
592 let param_locals = sig
596 .params
597 .iter()
598 .enumerate()
599 .map(|(i, ty)| (i as u32, *ty))
600 .collect::<Vec<_>>();
601
602 let saved = self.clear_may_leave(adapter.lower.flags);
603 self.translate_results(adapter, ¶m_locals, ¶m_locals);
614 self.restore_may_leave(adapter.lower.flags, saved);
615
616 self.finish()
617 }
618
619 fn compile_sync_to_sync_adapter(
626 mut self,
627 adapter: &AdapterData,
628 lower_sig: &Signature,
629 lift_sig: &Signature,
630 ) {
631 self.enter_exception_barrier(&lower_sig.results);
632
633 let saved_lower_may_leave =
643 self.trap_if_not_may_leave(adapter.lower.flags, Trap::CannotLeaveComponent);
644
645 debug_assert!(
651 !(adapter.thread_transparent && self.emit_resource_call),
652 "resources are not thread transparent",
653 );
654 let needs_thread_state =
655 self.module.tunables.concurrency_support && !adapter.thread_transparent;
656
657 if needs_thread_state {
658 self.instruction(I32Const(if self.types[adapter.lift.ty].async_ {
667 1
668 } else {
669 0
670 }));
671 self.instruction(I32Const(
672 i32::try_from(adapter.lift.instance.as_u32()).unwrap(),
673 ));
674 let enter_sync_call = self.module.import_enter_sync_call();
675 self.instruction(Call(enter_sync_call.as_u32()));
676 } else if self.emit_resource_call {
677 assert!(!self.types[adapter.lift.ty].async_);
678 self.instruction(I32Const(0));
679 self.instruction(I32Const(
680 i32::try_from(adapter.lift.instance.as_u32()).unwrap(),
681 ));
682 let enter_sync_call = self.module.import_enter_sync_call();
683 self.instruction(Call(enter_sync_call.as_u32()));
684 }
685
686 let saved_lift_may_leave = self.clear_may_leave(adapter.lift.flags);
721 let param_locals = lower_sig
722 .params
723 .iter()
724 .enumerate()
725 .map(|(i, ty)| (i as u32, *ty))
726 .collect::<Vec<_>>();
727 self.translate_params(adapter, ¶m_locals);
728 self.restore_may_leave(adapter.lift.flags, saved_lift_may_leave);
729
730 self.instruction(Call(adapter.callee.as_u32()));
735
736 let mut result_locals = Vec::with_capacity(lift_sig.results.len());
737 let mut temps = Vec::new();
738 for ty in lift_sig.results.iter().rev() {
739 let local = self.local_set_new_tmp(*ty);
740 result_locals.push((local.idx, *ty));
741 temps.push(local);
742 }
743 result_locals.reverse();
744
745 let callee_context = if adapter.lift.post_return.is_some() {
749 self.save_context()
750 } else {
751 Vec::new()
752 };
753
754 if self.emit_resource_call || needs_thread_state {
771 let exit_sync_call = self.module.import_exit_sync_call();
772 self.instruction(Call(exit_sync_call.as_u32()));
773 }
774
775 self.set_may_leave_false(adapter.lower.flags);
781 self.translate_results(adapter, ¶m_locals, &result_locals);
782 self.restore_may_leave(adapter.lower.flags, saved_lower_may_leave);
783
784 if let Some(func) = adapter.lift.post_return {
791 let caller_context = self.save_context();
792 self.restore_context(callee_context);
793 let saved_lift_may_leave = self.clear_may_leave(adapter.lift.flags);
794 for (result, _) in result_locals.iter() {
795 self.instruction(LocalGet(*result));
796 }
797 self.instruction(Call(func.as_u32()));
798 self.restore_may_leave(adapter.lift.flags, saved_lift_may_leave);
799 self.restore_context(caller_context);
800 } else {
801 assert!(callee_context.is_empty());
802 }
803
804 for tmp in temps {
805 self.free_temp_local(tmp);
806 }
807
808 self.exit_exception_barrier();
809
810 self.finish()
811 }
812
813 fn translate_params(&mut self, adapter: &AdapterData, param_locals: &[(u32, ValType)]) {
814 let src_tys = self.types[adapter.lower.ty].params;
815 let src_tys = self.types[src_tys]
816 .types
817 .iter()
818 .copied()
819 .collect::<Vec<_>>();
820 self.init_hostcall_fuel(&src_tys);
821 let dst_tys = self.types[adapter.lift.ty].params;
822 let dst_tys = self.types[dst_tys]
823 .types
824 .iter()
825 .copied()
826 .collect::<Vec<_>>();
827 let lift_opts = &adapter.lift.options;
828 let lower_opts = &adapter.lower.options;
829
830 assert_eq!(src_tys.len(), dst_tys.len());
832
833 let max_flat_params = match lower_opts.data_model {
837 DataModel::Gc {} => usize::MAX,
841 DataModel::LinearMemory(_) if adapter.lower.options.async_ => MAX_FLAT_ASYNC_PARAMS,
842 DataModel::LinearMemory(_) => MAX_FLAT_PARAMS,
843 };
844 let src_flat =
845 self.types
846 .flatten_types(lower_opts, max_flat_params, src_tys.iter().copied());
847 let max_dst_flat_params = match lift_opts.data_model {
848 DataModel::Gc {} => usize::MAX,
849 DataModel::LinearMemory(_) => MAX_FLAT_PARAMS,
850 };
851 let dst_flat =
852 self.types
853 .flatten_types(lift_opts, max_dst_flat_params, dst_tys.iter().copied());
854
855 let src = if let Some(flat) = &src_flat {
856 Source::Stack(Stack {
857 locals: ¶m_locals[..flat.len()],
858 opts: lower_opts,
859 })
860 } else {
861 let lower_mem_opts = lower_opts.data_model.unwrap_memory();
865 let (addr, ty) = param_locals[0];
866 assert_eq!(ty, lower_mem_opts.ptr());
867 let abi = CanonicalAbiInfo::record(src_tys.iter().map(|t| self.types.canonical_abi(t)));
868 Source::Memory(self.memory_operand_abi(
869 lower_opts,
870 TempLocal::new(addr, ty),
871 &abi,
872 Trap::MemoryOutOfBounds,
873 ))
874 };
875
876 let dst = if let Some(flat) = &dst_flat {
877 Destination::Stack(flat, lift_opts)
878 } else {
879 let abi = CanonicalAbiInfo::record(dst_tys.iter().map(|t| self.types.canonical_abi(t)));
882 Destination::Memory(self.malloc_abi(lift_opts, &abi, Trap::MemoryOutOfBounds))
883 };
884
885 let srcs = src
886 .record_field_srcs(self.types, src_tys.iter().copied())
887 .zip(src_tys.iter());
888 let dsts = dst
889 .record_field_dsts(self.types, dst_tys.iter().copied())
890 .zip(dst_tys.iter());
891 for ((src, src_ty), (dst, dst_ty)) in srcs.zip(dsts) {
892 self.translate(&src_ty, &src, &dst_ty, &dst);
893 }
894
895 if let Destination::Memory(mem) = dst {
899 self.instruction(LocalGet(mem.addr.idx));
900 self.free_temp_local(mem.addr);
901 }
902 }
903
904 fn translate_results(
905 &mut self,
906 adapter: &AdapterData,
907 param_locals: &[(u32, ValType)],
908 result_locals: &[(u32, ValType)],
909 ) {
910 let src_tys = self.types[adapter.lift.ty].results;
911 let src_tys = self.types[src_tys]
912 .types
913 .iter()
914 .copied()
915 .collect::<Vec<_>>();
916 self.init_hostcall_fuel(&src_tys);
917 let dst_tys = self.types[adapter.lower.ty].results;
918 let dst_tys = self.types[dst_tys]
919 .types
920 .iter()
921 .copied()
922 .collect::<Vec<_>>();
923 let lift_opts = &adapter.lift.options;
924 let lower_opts = &adapter.lower.options;
925
926 let src_flat = self
927 .types
928 .flatten_lifting_types(lift_opts, src_tys.iter().copied());
929 let dst_flat = self
930 .types
931 .flatten_lowering_types(lower_opts, dst_tys.iter().copied());
932
933 let src = if src_flat.is_some() {
934 Source::Stack(Stack {
935 locals: result_locals,
936 opts: lift_opts,
937 })
938 } else {
939 let abi = CanonicalAbiInfo::record(src_tys.iter().map(|t| self.types.canonical_abi(t)));
944 assert_eq!(
945 result_locals.len(),
946 if lower_opts.async_ || lift_opts.async_ || self.types[adapter.lift.ty].async_ {
947 2
948 } else {
949 1
950 }
951 );
952 let (addr, ty) = result_locals[0];
953 assert_eq!(ty, lift_opts.data_model.unwrap_memory().ptr());
954 Source::Memory(self.memory_operand_abi(
955 lift_opts,
956 TempLocal::new(addr, ty),
957 &abi,
958 Trap::MemoryOutOfBounds,
959 ))
960 };
961
962 let dst = if let Some(flat) = &dst_flat {
963 Destination::Stack(flat, lower_opts)
964 } else {
965 let abi = CanonicalAbiInfo::record(dst_tys.iter().map(|t| self.types.canonical_abi(t)));
969 let (addr, ty) = *param_locals.last().expect("no retptr");
970 assert_eq!(ty, lower_opts.data_model.unwrap_memory().ptr());
971 Destination::Memory(self.memory_operand_abi(
972 lower_opts,
973 TempLocal::new(addr, ty),
974 &abi,
975 Trap::MemoryOutOfBounds,
976 ))
977 };
978
979 let srcs = src
980 .record_field_srcs(self.types, src_tys.iter().copied())
981 .zip(src_tys.iter());
982 let dsts = dst
983 .record_field_dsts(self.types, dst_tys.iter().copied())
984 .zip(dst_tys.iter());
985 for ((src, src_ty), (dst, dst_ty)) in srcs.zip(dsts) {
986 self.translate(&src_ty, &src, &dst_ty, &dst);
987 }
988 }
989
990 fn translate(
991 &mut self,
992 src_ty: &InterfaceType,
993 src: &Source<'_>,
994 dst_ty: &InterfaceType,
995 dst: &Destination,
996 ) {
997 if let Source::Memory(mem) = src {
998 self.assert_aligned(src_ty, mem);
999 }
1000 if let Destination::Memory(mem) = dst {
1001 self.assert_aligned(dst_ty, mem);
1002 }
1003
1004 let cost = match src_ty {
1034 InterfaceType::Bool
1038 | InterfaceType::U8
1039 | InterfaceType::S8
1040 | InterfaceType::U16
1041 | InterfaceType::S16
1042 | InterfaceType::U32
1043 | InterfaceType::S32
1044 | InterfaceType::U64
1045 | InterfaceType::S64
1046 | InterfaceType::Float32
1047 | InterfaceType::Float64 => 0,
1048
1049 InterfaceType::Char => 1,
1052
1053 InterfaceType::String => 40,
1056
1057 InterfaceType::List(_) => 40,
1060 InterfaceType::Map(_) => 40,
1062
1063 InterfaceType::Flags(i) => {
1064 let count = self.module.types[*i].names.len();
1065 match FlagsSize::from_count(count) {
1066 FlagsSize::Size0 => 0,
1067 FlagsSize::Size1 | FlagsSize::Size2 => 1,
1068 FlagsSize::Size4Plus(n) => n.into(),
1069 }
1070 }
1071
1072 InterfaceType::Record(i) => self.types[*i].fields.len(),
1073 InterfaceType::Tuple(i) => self.types[*i].types.len(),
1074 InterfaceType::Variant(i) => self.types[*i].cases.len(),
1075 InterfaceType::Enum(i) => self.types[*i].names.len(),
1076
1077 InterfaceType::Option(_) | InterfaceType::Result(_) => 2,
1079
1080 InterfaceType::Own(_)
1082 | InterfaceType::Borrow(_)
1083 | InterfaceType::Future(_)
1084 | InterfaceType::Stream(_)
1085 | InterfaceType::ErrorContext(_) => 1,
1086 InterfaceType::FixedLengthList(i) => self.types[*i].size as usize,
1087 };
1088
1089 let remaining_fuel = if self.fuel == INITIAL_FUEL {
1096 Some(self.fuel.saturating_sub(cost))
1097 } else {
1098 self.fuel.checked_sub(cost)
1099 };
1100
1101 match remaining_fuel {
1102 Some(n) => {
1108 self.fuel = n;
1109 match src_ty {
1110 InterfaceType::Bool => self.translate_bool(src, dst_ty, dst),
1111 InterfaceType::U8 => self.translate_u8(src, dst_ty, dst),
1112 InterfaceType::S8 => self.translate_s8(src, dst_ty, dst),
1113 InterfaceType::U16 => self.translate_u16(src, dst_ty, dst),
1114 InterfaceType::S16 => self.translate_s16(src, dst_ty, dst),
1115 InterfaceType::U32 => self.translate_u32(src, dst_ty, dst),
1116 InterfaceType::S32 => self.translate_s32(src, dst_ty, dst),
1117 InterfaceType::U64 => self.translate_u64(src, dst_ty, dst),
1118 InterfaceType::S64 => self.translate_s64(src, dst_ty, dst),
1119 InterfaceType::Float32 => self.translate_f32(src, dst_ty, dst),
1120 InterfaceType::Float64 => self.translate_f64(src, dst_ty, dst),
1121 InterfaceType::Char => self.translate_char(src, dst_ty, dst),
1122 InterfaceType::String => self.translate_string(src, dst_ty, dst),
1123 InterfaceType::List(t) => self.translate_list(*t, src, dst_ty, dst),
1124 InterfaceType::Map(t) => self.translate_map(*t, src, dst_ty, dst),
1125 InterfaceType::Record(t) => self.translate_record(*t, src, dst_ty, dst),
1126 InterfaceType::Flags(f) => self.translate_flags(*f, src, dst_ty, dst),
1127 InterfaceType::Tuple(t) => self.translate_tuple(*t, src, dst_ty, dst),
1128 InterfaceType::Variant(v) => self.translate_variant(*v, src, dst_ty, dst),
1129 InterfaceType::Enum(t) => self.translate_enum(*t, src, dst_ty, dst),
1130 InterfaceType::Option(t) => self.translate_option(*t, src, dst_ty, dst),
1131 InterfaceType::Result(t) => self.translate_result(*t, src, dst_ty, dst),
1132 InterfaceType::Own(t) => self.translate_own(*t, src, dst_ty, dst),
1133 InterfaceType::Borrow(t) => self.translate_borrow(*t, src, dst_ty, dst),
1134 InterfaceType::Future(t) => self.translate_future(*t, src, dst_ty, dst),
1135 InterfaceType::Stream(t) => self.translate_stream(*t, src, dst_ty, dst),
1136 InterfaceType::ErrorContext(t) => {
1137 self.translate_error_context(*t, src, dst_ty, dst)
1138 }
1139 InterfaceType::FixedLengthList(t) => {
1140 self.translate_fixed_length_list(*t, src, dst_ty, dst);
1141 }
1142 }
1143 }
1144
1145 None => {
1151 let src_loc = match src {
1152 Source::Stack(stack) => {
1156 for (i, ty) in stack
1157 .opts
1158 .flat_types(src_ty, self.types)
1159 .unwrap()
1160 .iter()
1161 .enumerate()
1162 {
1163 let stack = stack.slice(i..i + 1);
1164 self.stack_get(&stack, (*ty).into());
1165 }
1166 HelperLocation::Stack
1167 }
1168 Source::Memory(mem) => {
1173 self.push_mem_addr(mem);
1174 HelperLocation::Memory
1175 }
1176 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1177 };
1178 let dst_loc = match dst {
1179 Destination::Stack(..) => HelperLocation::Stack,
1180 Destination::Memory(mem) => {
1181 self.push_mem_addr(mem);
1182 HelperLocation::Memory
1183 }
1184 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1185 };
1186 let helper = self.module.translate_helper(Helper {
1192 src: HelperType {
1193 ty: *src_ty,
1194 opts: *src.opts(),
1195 loc: src_loc,
1196 },
1197 dst: HelperType {
1198 ty: *dst_ty,
1199 opts: *dst.opts(),
1200 loc: dst_loc,
1201 },
1202 });
1203 self.push_body(Body::Call(helper));
1206
1207 if let Destination::Stack(tys, opts) = dst {
1216 let flat = self
1217 .types
1218 .flatten_types(opts, usize::MAX, [*dst_ty])
1219 .unwrap();
1220 assert_eq!(flat.len(), tys.len());
1221 let locals = flat
1222 .iter()
1223 .rev()
1224 .map(|ty| self.local_set_new_tmp(*ty))
1225 .collect::<Vec<_>>();
1226 for (ty, local) in tys.iter().zip(locals.into_iter().rev()) {
1227 self.instruction(LocalGet(local.idx));
1228 self.stack_set(std::slice::from_ref(ty), local.ty);
1229 self.free_temp_local(local);
1230 }
1231 }
1232 }
1233 }
1234 }
1235
1236 fn push_mem_addr(&mut self, mem: &Memory<'_>) {
1237 self.instruction(LocalGet(mem.addr.idx));
1238 if mem.offset != 0 {
1239 self.ptr_uconst(mem.mem_opts(), mem.offset);
1240 self.ptr_add(mem.mem_opts());
1241 }
1242 }
1243
1244 fn translate_bool(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1245 assert!(matches!(dst_ty, InterfaceType::Bool));
1247 self.push_dst_addr(dst);
1248
1249 self.instruction(I32Const(1));
1252 self.instruction(I32Const(0));
1253 match src {
1254 Source::Memory(mem) => self.i32_load8u(mem),
1255 Source::Stack(stack) => self.stack_get(stack, ValType::I32),
1256 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1257 }
1258 self.instruction(Select);
1259
1260 match dst {
1261 Destination::Memory(mem) => self.i32_store8(mem),
1262 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1263 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1264 }
1265 }
1266
1267 fn translate_u8(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1268 assert!(matches!(dst_ty, InterfaceType::U8));
1270 self.convert_u8_mask(src, dst, 0xff);
1271 }
1272
1273 fn convert_u8_mask(&mut self, src: &Source<'_>, dst: &Destination<'_>, mask: u8) {
1274 self.push_dst_addr(dst);
1275 let mut needs_mask = true;
1276 match src {
1277 Source::Memory(mem) => {
1278 self.i32_load8u(mem);
1279 needs_mask = mask != 0xff;
1280 }
1281 Source::Stack(stack) => {
1282 self.stack_get(stack, ValType::I32);
1283 }
1284 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1285 }
1286 if needs_mask {
1287 self.instruction(I32Const(i32::from(mask)));
1288 self.instruction(I32And);
1289 }
1290 match dst {
1291 Destination::Memory(mem) => self.i32_store8(mem),
1292 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1293 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1294 }
1295 }
1296
1297 fn translate_s8(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1298 assert!(matches!(dst_ty, InterfaceType::S8));
1300 self.push_dst_addr(dst);
1301 match src {
1302 Source::Memory(mem) => self.i32_load8s(mem),
1303 Source::Stack(stack) => {
1304 self.stack_get(stack, ValType::I32);
1305 self.instruction(I32Extend8S);
1306 }
1307 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1308 }
1309 match dst {
1310 Destination::Memory(mem) => self.i32_store8(mem),
1311 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1312 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1313 }
1314 }
1315
1316 fn translate_u16(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1317 assert!(matches!(dst_ty, InterfaceType::U16));
1319 self.convert_u16_mask(src, dst, 0xffff);
1320 }
1321
1322 fn convert_u16_mask(&mut self, src: &Source<'_>, dst: &Destination<'_>, mask: u16) {
1323 self.push_dst_addr(dst);
1324 let mut needs_mask = true;
1325 match src {
1326 Source::Memory(mem) => {
1327 self.i32_load16u(mem);
1328 needs_mask = mask != 0xffff;
1329 }
1330 Source::Stack(stack) => {
1331 self.stack_get(stack, ValType::I32);
1332 }
1333 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1334 }
1335 if needs_mask {
1336 self.instruction(I32Const(i32::from(mask)));
1337 self.instruction(I32And);
1338 }
1339 match dst {
1340 Destination::Memory(mem) => self.i32_store16(mem),
1341 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1342 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1343 }
1344 }
1345
1346 fn translate_s16(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1347 assert!(matches!(dst_ty, InterfaceType::S16));
1349 self.push_dst_addr(dst);
1350 match src {
1351 Source::Memory(mem) => self.i32_load16s(mem),
1352 Source::Stack(stack) => {
1353 self.stack_get(stack, ValType::I32);
1354 self.instruction(I32Extend16S);
1355 }
1356 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1357 }
1358 match dst {
1359 Destination::Memory(mem) => self.i32_store16(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_u32(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1366 assert!(matches!(dst_ty, InterfaceType::U32));
1368 self.convert_u32_mask(src, dst, 0xffffffff)
1369 }
1370
1371 fn convert_u32_mask(&mut self, src: &Source<'_>, dst: &Destination<'_>, mask: u32) {
1372 self.push_dst_addr(dst);
1373 match src {
1374 Source::Memory(mem) => self.i32_load(mem),
1375 Source::Stack(stack) => self.stack_get(stack, ValType::I32),
1376 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1377 }
1378 if mask != 0xffffffff {
1379 self.instruction(I32Const(mask as i32));
1380 self.instruction(I32And);
1381 }
1382 match dst {
1383 Destination::Memory(mem) => self.i32_store(mem),
1384 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1385 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1386 }
1387 }
1388
1389 fn translate_s32(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1390 assert!(matches!(dst_ty, InterfaceType::S32));
1392 self.push_dst_addr(dst);
1393 match src {
1394 Source::Memory(mem) => self.i32_load(mem),
1395 Source::Stack(stack) => self.stack_get(stack, ValType::I32),
1396 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1397 }
1398 match dst {
1399 Destination::Memory(mem) => self.i32_store(mem),
1400 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1401 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1402 }
1403 }
1404
1405 fn translate_u64(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1406 assert!(matches!(dst_ty, InterfaceType::U64));
1408 self.push_dst_addr(dst);
1409 match src {
1410 Source::Memory(mem) => self.i64_load(mem),
1411 Source::Stack(stack) => self.stack_get(stack, ValType::I64),
1412 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1413 }
1414 match dst {
1415 Destination::Memory(mem) => self.i64_store(mem),
1416 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I64),
1417 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1418 }
1419 }
1420
1421 fn translate_s64(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1422 assert!(matches!(dst_ty, InterfaceType::S64));
1424 self.push_dst_addr(dst);
1425 match src {
1426 Source::Memory(mem) => self.i64_load(mem),
1427 Source::Stack(stack) => self.stack_get(stack, ValType::I64),
1428 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1429 }
1430 match dst {
1431 Destination::Memory(mem) => self.i64_store(mem),
1432 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I64),
1433 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1434 }
1435 }
1436
1437 fn translate_f32(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1438 assert!(matches!(dst_ty, InterfaceType::Float32));
1440 self.push_dst_addr(dst);
1441 match src {
1442 Source::Memory(mem) => self.f32_load(mem),
1443 Source::Stack(stack) => self.stack_get(stack, ValType::F32),
1444 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1445 }
1446 match dst {
1447 Destination::Memory(mem) => self.f32_store(mem),
1448 Destination::Stack(stack, _) => self.stack_set(stack, ValType::F32),
1449 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1450 }
1451 }
1452
1453 fn translate_f64(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1454 assert!(matches!(dst_ty, InterfaceType::Float64));
1456 self.push_dst_addr(dst);
1457 match src {
1458 Source::Memory(mem) => self.f64_load(mem),
1459 Source::Stack(stack) => self.stack_get(stack, ValType::F64),
1460 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1461 }
1462 match dst {
1463 Destination::Memory(mem) => self.f64_store(mem),
1464 Destination::Stack(stack, _) => self.stack_set(stack, ValType::F64),
1465 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1466 }
1467 }
1468
1469 fn translate_char(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1470 assert!(matches!(dst_ty, InterfaceType::Char));
1471 match src {
1472 Source::Memory(mem) => self.i32_load(mem),
1473 Source::Stack(stack) => self.stack_get(stack, ValType::I32),
1474 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1475 }
1476 let local = self.local_set_new_tmp(ValType::I32);
1477
1478 self.instruction(Block(BlockType::Empty));
1494 self.instruction(Block(BlockType::Empty));
1495 self.instruction(LocalGet(local.idx));
1496 self.instruction(I32Const(0xd800));
1497 self.instruction(I32Xor);
1498 self.instruction(I32Const(-0x110000));
1499 self.instruction(I32Add);
1500 self.instruction(I32Const(-0x10f800));
1501 self.instruction(I32LtU);
1502 self.instruction(BrIf(0));
1503 self.instruction(LocalGet(local.idx));
1504 self.instruction(I32Const(0x110000));
1505 self.instruction(I32Ne);
1506 self.instruction(BrIf(1));
1507 self.instruction(End);
1508 self.trap(Trap::InvalidChar);
1509 self.instruction(End);
1510
1511 self.push_dst_addr(dst);
1512 self.instruction(LocalGet(local.idx));
1513 match dst {
1514 Destination::Memory(mem) => {
1515 self.i32_store(mem);
1516 }
1517 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1518 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1519 }
1520
1521 self.free_temp_local(local);
1522 }
1523
1524 fn translate_string(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1525 assert!(matches!(dst_ty, InterfaceType::String));
1526 let src_opts = src.opts();
1527 let dst_opts = dst.opts();
1528
1529 let src_mem_opts = match &src_opts.data_model {
1530 DataModel::Gc {} => todo!("CM+GC"),
1531 DataModel::LinearMemory(opts) => opts,
1532 };
1533 let dst_mem_opts = match &dst_opts.data_model {
1534 DataModel::Gc {} => todo!("CM+GC"),
1535 DataModel::LinearMemory(opts) => opts,
1536 };
1537
1538 match src {
1543 Source::Stack(s) => {
1544 assert_eq!(s.locals.len(), 2);
1545 self.stack_get(&s.slice(0..1), src_mem_opts.ptr());
1546 self.stack_get(&s.slice(1..2), src_mem_opts.ptr());
1547 }
1548 Source::Memory(mem) => {
1549 self.ptr_load(mem);
1550 self.ptr_load(&mem.bump(src_mem_opts.ptr_size().into()));
1551 }
1552 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1553 }
1554 let src_len = self.local_set_new_tmp(src_mem_opts.ptr());
1555 let src_ptr = self.local_set_new_tmp(src_mem_opts.ptr());
1556 let src_str = WasmString {
1557 ptr: src_ptr,
1558 len: src_len,
1559 opts: src_opts,
1560 };
1561
1562 let dst_str = match src_opts.string_encoding {
1563 StringEncoding::Utf8 => {
1564 self.validate_guest_pointer(
1565 src_opts,
1566 &src_str.ptr,
1567 &AllocSize::Local(src_str.len.idx),
1568 1,
1569 Trap::StringOutOfBounds,
1570 );
1571 match dst_opts.string_encoding {
1572 StringEncoding::Utf8 => {
1573 self.string_copy(&src_str, FE::Utf8, dst_opts, FE::Utf8)
1574 }
1575 StringEncoding::Utf16 => self.string_utf8_to_utf16(&src_str, dst_opts),
1576 StringEncoding::CompactUtf16 => {
1577 self.string_to_compact(&src_str, FE::Utf8, dst_opts)
1578 }
1579 }
1580 }
1581
1582 StringEncoding::Utf16 => {
1583 self.validate_guest_pointer(
1584 src_opts,
1585 &src_str.ptr,
1586 &AllocSize::DoubleLocal(src_str.len.idx),
1587 2,
1588 Trap::StringOutOfBounds,
1589 );
1590 match dst_opts.string_encoding {
1591 StringEncoding::Utf8 => {
1592 self.string_deflate_to_utf8(&src_str, FE::Utf16, dst_opts)
1593 }
1594 StringEncoding::Utf16 => {
1595 self.string_copy(&src_str, FE::Utf16, dst_opts, FE::Utf16)
1596 }
1597 StringEncoding::CompactUtf16 => {
1598 self.string_to_compact(&src_str, FE::Utf16, dst_opts)
1599 }
1600 }
1601 }
1602
1603 StringEncoding::CompactUtf16 => {
1604 self.instruction(LocalGet(src_str.len.idx));
1607 self.ptr_uconst(src_mem_opts, UTF16_TAG);
1608 self.ptr_and(src_mem_opts);
1609 self.ptr_if(src_mem_opts, BlockType::Empty);
1610
1611 self.instruction(LocalGet(src_str.len.idx));
1615 self.ptr_uconst(src_mem_opts, UTF16_TAG);
1616 self.ptr_xor(src_mem_opts);
1617 self.instruction(LocalSet(src_str.len.idx));
1618
1619 self.validate_guest_pointer(
1623 src_opts,
1624 &src_str.ptr,
1625 &AllocSize::DoubleLocal(src_str.len.idx),
1626 2,
1627 Trap::StringOutOfBounds,
1628 );
1629
1630 let s1 = match dst_opts.string_encoding {
1631 StringEncoding::Utf8 => {
1632 self.string_deflate_to_utf8(&src_str, FE::Utf16, dst_opts)
1633 }
1634 StringEncoding::Utf16 => {
1635 self.string_copy(&src_str, FE::Utf16, dst_opts, FE::Utf16)
1636 }
1637 StringEncoding::CompactUtf16 => {
1638 self.string_compact_utf16_to_compact(&src_str, dst_opts)
1639 }
1640 };
1641
1642 self.instruction(Else);
1643
1644 self.validate_guest_pointer(
1647 src_opts,
1648 &src_str.ptr,
1649 &AllocSize::Local(src_str.len.idx),
1650 2,
1651 Trap::StringOutOfBounds,
1652 );
1653
1654 let s2 = match dst_opts.string_encoding {
1658 StringEncoding::Utf16 => {
1659 self.string_copy(&src_str, FE::Latin1, dst_opts, FE::Utf16)
1660 }
1661 StringEncoding::Utf8 => {
1662 self.string_deflate_to_utf8(&src_str, FE::Latin1, dst_opts)
1663 }
1664 StringEncoding::CompactUtf16 => {
1665 self.string_copy(&src_str, FE::Latin1, dst_opts, FE::Latin1)
1666 }
1667 };
1668 self.instruction(LocalGet(s2.ptr.idx));
1671 self.instruction(LocalSet(s1.ptr.idx));
1672 self.instruction(LocalGet(s2.len.idx));
1673 self.instruction(LocalSet(s1.len.idx));
1674 self.instruction(End);
1675 self.free_temp_local(s2.ptr);
1676 self.free_temp_local(s2.len);
1677 s1
1678 }
1679 };
1680
1681 match dst {
1683 Destination::Stack(s, _) => {
1684 self.instruction(LocalGet(dst_str.ptr.idx));
1685 self.stack_set(&s[..1], dst_mem_opts.ptr());
1686 self.instruction(LocalGet(dst_str.len.idx));
1687 self.stack_set(&s[1..], dst_mem_opts.ptr());
1688 }
1689 Destination::Memory(mem) => {
1690 self.instruction(LocalGet(mem.addr.idx));
1691 self.instruction(LocalGet(dst_str.ptr.idx));
1692 self.ptr_store(mem);
1693 self.instruction(LocalGet(mem.addr.idx));
1694 self.instruction(LocalGet(dst_str.len.idx));
1695 self.ptr_store(&mem.bump(dst_mem_opts.ptr_size().into()));
1696 }
1697 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1698 }
1699
1700 self.free_temp_local(src_str.ptr);
1701 self.free_temp_local(src_str.len);
1702 self.free_temp_local(dst_str.ptr);
1703 self.free_temp_local(dst_str.len);
1704 }
1705
1706 fn init_hostcall_fuel(&mut self, tys: &[InterfaceType]) {
1713 if !tys.iter().any(|ty| self.types.ty_contains_string(ty)) {
1714 return;
1715 }
1716 self.module.hostcall_fuel_global = true;
1717 let hostcall_fuel = self.module.import_hostcall_fuel();
1718 self.instruction(Call(hostcall_fuel.as_u32()));
1719 self.push_body(Body::HostcallFuelGlobalSet);
1720 }
1721
1722 fn consume_hostcall_fuel(&mut self, src: &WasmString<'_>, enc: FE) {
1726 self.instruction(LocalGet(src.len.idx));
1727 if src.len.ty == ValType::I32 {
1728 self.instruction(I64ExtendI32U);
1729 }
1730 if enc.width() > 1 {
1731 self.instruction(I64Const(i64::from(enc.width())));
1732 self.instruction(I64Mul);
1733 }
1734 let bytes = self.local_set_new_tmp(ValType::I64);
1735
1736 self.instruction(LocalGet(bytes.idx));
1737 self.push_body(Body::HostcallFuelGlobalGet);
1738 self.instruction(I64GtU);
1739 self.instruction(If(BlockType::Empty));
1740 self.trap(Trap::HostcallFuelExhausted);
1741 self.instruction(End);
1742
1743 self.push_body(Body::HostcallFuelGlobalGet);
1744 self.instruction(LocalGet(bytes.idx));
1745 self.instruction(I64Sub);
1746 self.push_body(Body::HostcallFuelGlobalSet);
1747
1748 self.free_temp_local(bytes);
1749 }
1750
1751 fn string_copy<'c>(
1764 &mut self,
1765 src: &WasmString<'_>,
1766 src_enc: FE,
1767 dst_opts: &'c Options,
1768 dst_enc: FE,
1769 ) -> WasmString<'c> {
1770 assert!(dst_enc.width() >= src_enc.width());
1771
1772 self.validate_string_length(src, dst_enc);
1777
1778 let src_mem_opts = {
1779 match &src.opts.data_model {
1780 DataModel::Gc {} => todo!("CM+GC"),
1781 DataModel::LinearMemory(opts) => opts,
1782 }
1783 };
1784 let dst_mem_opts = {
1785 match &dst_opts.data_model {
1786 DataModel::Gc {} => todo!("CM+GC"),
1787 DataModel::LinearMemory(opts) => opts,
1788 }
1789 };
1790
1791 self.convert_src_len_to_dst(src.len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
1794 let dst_len = self.local_tee_new_tmp(dst_mem_opts.ptr());
1795 if dst_enc.width() > 1 {
1796 assert_eq!(dst_enc.width(), 2);
1797 self.ptr_uconst(dst_mem_opts, 1);
1798 self.ptr_shl(dst_mem_opts);
1799 }
1800 let dst_byte_len = self.local_set_new_tmp(dst_mem_opts.ptr());
1801
1802 let dst = {
1805 let dst_mem = self.malloc(
1806 dst_opts,
1807 AllocSize::Local(dst_byte_len.idx),
1808 dst_enc.align().into(),
1809 Trap::StringOutOfBounds,
1810 );
1811 WasmString {
1812 ptr: dst_mem.addr,
1813 len: dst_len,
1814 opts: dst_opts,
1815 }
1816 };
1817
1818 let op = if src_enc == dst_enc {
1822 Transcode::Copy(src_enc)
1823 } else {
1824 assert_eq!(src_enc, FE::Latin1);
1825 assert_eq!(dst_enc, FE::Utf16);
1826 Transcode::Latin1ToUtf16
1827 };
1828 let transcode = self.transcoder(src, &dst, op);
1829 self.instruction(LocalGet(src.ptr.idx));
1830 self.instruction(LocalGet(src.len.idx));
1831 self.instruction(LocalGet(dst.ptr.idx));
1832 self.instruction(Call(transcode.as_u32()));
1833
1834 self.free_temp_local(dst_byte_len);
1835
1836 dst
1837 }
1838
1839 fn string_deflate_to_utf8<'c>(
1852 &mut self,
1853 src: &WasmString<'_>,
1854 src_enc: FE,
1855 dst_opts: &'c Options,
1856 ) -> WasmString<'c> {
1857 let src_mem_opts = match &src.opts.data_model {
1858 DataModel::Gc {} => todo!("CM+GC"),
1859 DataModel::LinearMemory(opts) => opts,
1860 };
1861 let dst_mem_opts = match &dst_opts.data_model {
1862 DataModel::Gc {} => todo!("CM+GC"),
1863 DataModel::LinearMemory(opts) => opts,
1864 };
1865
1866 self.validate_string_length(src, src_enc);
1867
1868 self.convert_src_len_to_dst(
1872 src.len.idx,
1873 src.opts.data_model.unwrap_memory().ptr(),
1874 dst_opts.data_model.unwrap_memory().ptr(),
1875 );
1876 let dst_len = self.local_tee_new_tmp(dst_opts.data_model.unwrap_memory().ptr());
1877 let dst_byte_len = self.local_set_new_tmp(dst_opts.data_model.unwrap_memory().ptr());
1878
1879 let dst = {
1880 let dst_mem = self.malloc(
1881 dst_opts,
1882 AllocSize::Local(dst_byte_len.idx),
1883 1,
1884 Trap::StringOutOfBounds,
1885 );
1886 WasmString {
1887 ptr: dst_mem.addr,
1888 len: dst_len,
1889 opts: dst_opts,
1890 }
1891 };
1892
1893 let op = match src_enc {
1895 FE::Latin1 => Transcode::Latin1ToUtf8,
1896 FE::Utf16 => Transcode::Utf16ToUtf8,
1897 FE::Utf8 => unreachable!(),
1898 };
1899 let transcode = self.transcoder(src, &dst, op);
1900 self.instruction(LocalGet(src.ptr.idx));
1901 self.instruction(LocalGet(src.len.idx));
1902 self.instruction(LocalGet(dst.ptr.idx));
1903 self.instruction(LocalGet(dst_byte_len.idx));
1904 self.instruction(I32Const(1)); self.instruction(Call(transcode.as_u32()));
1906 self.instruction(LocalSet(dst.len.idx));
1907 let src_len_tmp = self.local_set_new_tmp(src.opts.data_model.unwrap_memory().ptr());
1908
1909 self.instruction(LocalGet(src_len_tmp.idx));
1913 self.instruction(LocalGet(src.len.idx));
1914 self.ptr_ne(src_mem_opts);
1915 self.instruction(If(BlockType::Empty));
1916
1917 let factor = match src_enc {
1920 FE::Latin1 => 2,
1921 FE::Utf16 => 3,
1922 _ => unreachable!(),
1923 };
1924 self.validate_string_length_u8(src, factor);
1925 self.convert_src_len_to_dst(
1926 src.len.idx,
1927 src.opts.data_model.unwrap_memory().ptr(),
1928 dst_opts.data_model.unwrap_memory().ptr(),
1929 );
1930 self.ptr_uconst(dst_mem_opts, factor.into());
1931 self.ptr_mul(dst_mem_opts);
1932 let new_byte_len = self.local_set_new_tmp(dst_mem_opts.ptr());
1933
1934 self.realloc(
1938 dst_opts,
1939 &dst.ptr,
1940 AllocSize::Local(dst_byte_len.idx),
1941 AllocSize::Local(new_byte_len.idx),
1942 1,
1943 Trap::StringOutOfBounds,
1944 );
1945 self.instruction(LocalGet(new_byte_len.idx));
1946 self.instruction(LocalSet(dst_byte_len.idx));
1947 self.free_temp_local(new_byte_len);
1948
1949 self.instruction(LocalGet(src.ptr.idx));
1954 self.instruction(LocalGet(src_len_tmp.idx));
1955 if let FE::Utf16 = src_enc {
1956 self.ptr_uconst(src_mem_opts, 1);
1957 self.ptr_shl(src_mem_opts);
1958 }
1959 self.ptr_add(src_mem_opts);
1960 self.instruction(LocalGet(src.len.idx));
1961 self.instruction(LocalGet(src_len_tmp.idx));
1962 self.ptr_sub(src_mem_opts);
1963 self.instruction(LocalGet(dst.ptr.idx));
1964 self.instruction(LocalGet(dst.len.idx));
1965 self.ptr_add(dst_mem_opts);
1966 self.instruction(LocalGet(dst_byte_len.idx));
1967 self.instruction(LocalGet(dst.len.idx));
1968 self.ptr_sub(dst_mem_opts);
1969 self.instruction(I32Const(0)); self.instruction(Call(transcode.as_u32()));
1971
1972 self.instruction(LocalGet(dst.len.idx));
1976 self.ptr_add(dst_mem_opts);
1977 self.instruction(LocalSet(dst.len.idx));
1978
1979 if self.module.tunables.debug_adapter_modules {
1982 self.instruction(LocalGet(src.len.idx));
1983 self.instruction(LocalGet(src_len_tmp.idx));
1984 self.ptr_sub(src_mem_opts);
1985 self.ptr_ne(src_mem_opts);
1986 self.instruction(If(BlockType::Empty));
1987 self.trap(Trap::DebugAssertStringEncodingFinished);
1988 self.instruction(End);
1989 } else {
1990 self.instruction(Drop);
1991 }
1992
1993 self.instruction(LocalGet(dst.len.idx));
1995 self.instruction(LocalGet(dst_byte_len.idx));
1996 self.ptr_ne(dst_mem_opts);
1997 self.instruction(If(BlockType::Empty));
1998 self.realloc(
1999 dst_opts,
2000 &dst.ptr,
2001 AllocSize::Local(dst_byte_len.idx),
2002 AllocSize::Local(dst.len.idx),
2003 1,
2004 Trap::StringOutOfBounds,
2005 );
2006 self.instruction(End);
2007
2008 if self.module.tunables.debug_adapter_modules {
2011 self.instruction(Else);
2012
2013 self.instruction(LocalGet(dst.len.idx));
2014 self.instruction(LocalGet(dst_byte_len.idx));
2015 self.ptr_ne(dst_mem_opts);
2016 self.instruction(If(BlockType::Empty));
2017 self.trap(Trap::DebugAssertStringEncodingFinished);
2018 self.instruction(End);
2019 }
2020
2021 self.instruction(End); self.free_temp_local(src_len_tmp);
2024 self.free_temp_local(dst_byte_len);
2025
2026 dst
2027 }
2028
2029 fn string_utf8_to_utf16<'c>(
2044 &mut self,
2045 src: &WasmString<'_>,
2046 dst_opts: &'c Options,
2047 ) -> WasmString<'c> {
2048 let src_mem_opts = match &src.opts.data_model {
2049 DataModel::Gc {} => todo!("CM+GC"),
2050 DataModel::LinearMemory(opts) => opts,
2051 };
2052 let dst_mem_opts = match &dst_opts.data_model {
2053 DataModel::Gc {} => todo!("CM+GC"),
2054 DataModel::LinearMemory(opts) => opts,
2055 };
2056
2057 self.validate_string_length(src, FE::Utf16);
2058 self.convert_src_len_to_dst(
2059 src.len.idx,
2060 src_mem_opts.ptr(),
2061 dst_opts.data_model.unwrap_memory().ptr(),
2062 );
2063 let dst_len = self.local_tee_new_tmp(dst_opts.data_model.unwrap_memory().ptr());
2064 self.ptr_uconst(dst_mem_opts, 1);
2065 self.ptr_shl(dst_mem_opts);
2066 let dst_byte_len = self.local_set_new_tmp(dst_opts.data_model.unwrap_memory().ptr());
2067 let dst = {
2068 let dst_mem = self.malloc(
2069 dst_opts,
2070 AllocSize::Local(dst_byte_len.idx),
2071 2,
2072 Trap::StringOutOfBounds,
2073 );
2074 WasmString {
2075 ptr: dst_mem.addr,
2076 len: dst_len,
2077 opts: dst_opts,
2078 }
2079 };
2080
2081 let transcode = self.transcoder(src, &dst, Transcode::Utf8ToUtf16);
2082 self.instruction(LocalGet(src.ptr.idx));
2083 self.instruction(LocalGet(src.len.idx));
2084 self.instruction(LocalGet(dst.ptr.idx));
2085 self.instruction(Call(transcode.as_u32()));
2086 self.instruction(LocalSet(dst.len.idx));
2087
2088 self.convert_src_len_to_dst(src.len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2096 self.instruction(LocalGet(dst.len.idx));
2097 self.ptr_ne(dst_mem_opts);
2098 self.instruction(If(BlockType::Empty));
2099 self.realloc(
2100 dst.opts,
2101 &dst.ptr,
2102 AllocSize::Local(dst_byte_len.idx),
2103 AllocSize::DoubleLocal(dst.len.idx),
2104 2,
2105 Trap::StringOutOfBounds,
2106 );
2107 self.instruction(End); self.free_temp_local(dst_byte_len);
2110
2111 dst
2112 }
2113
2114 fn string_compact_utf16_to_compact<'c>(
2128 &mut self,
2129 src: &WasmString<'_>,
2130 dst_opts: &'c Options,
2131 ) -> WasmString<'c> {
2132 let src_mem_opts = match &src.opts.data_model {
2133 DataModel::Gc {} => todo!("CM+GC"),
2134 DataModel::LinearMemory(opts) => opts,
2135 };
2136 let dst_mem_opts = match &dst_opts.data_model {
2137 DataModel::Gc {} => todo!("CM+GC"),
2138 DataModel::LinearMemory(opts) => opts,
2139 };
2140
2141 self.validate_string_length(src, FE::Utf16);
2142 self.convert_src_len_to_dst(src.len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2143 let dst_len = self.local_tee_new_tmp(dst_mem_opts.ptr());
2144 self.ptr_uconst(dst_mem_opts, 1);
2145 self.ptr_shl(dst_mem_opts);
2146 let dst_byte_len = self.local_set_new_tmp(dst_mem_opts.ptr());
2147 let dst = {
2148 let dst_mem = self.malloc(
2149 dst_opts,
2150 AllocSize::Local(dst_byte_len.idx),
2151 2,
2152 Trap::StringOutOfBounds,
2153 );
2154 WasmString {
2155 ptr: dst_mem.addr,
2156 len: dst_len,
2157 opts: dst_opts,
2158 }
2159 };
2160
2161 self.convert_src_len_to_dst(
2162 dst_byte_len.idx,
2163 dst.opts.data_model.unwrap_memory().ptr(),
2164 src_mem_opts.ptr(),
2165 );
2166 let src_byte_len = self.local_set_new_tmp(src_mem_opts.ptr());
2167
2168 let transcode = self.transcoder(src, &dst, Transcode::Utf16ToCompactProbablyUtf16);
2169 self.instruction(LocalGet(src.ptr.idx));
2170 self.instruction(LocalGet(src.len.idx));
2171 self.instruction(LocalGet(dst.ptr.idx));
2172 self.instruction(Call(transcode.as_u32()));
2173 self.instruction(LocalSet(dst.len.idx));
2174
2175 if self.module.tunables.debug_adapter_modules {
2178 self.instruction(LocalGet(dst.len.idx));
2179 self.ptr_uconst(dst_mem_opts, !UTF16_TAG);
2180 self.ptr_and(dst_mem_opts);
2181 self.convert_src_len_to_dst(src.len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2182 self.ptr_ne(dst_mem_opts);
2183 self.instruction(If(BlockType::Empty));
2184 self.trap(Trap::DebugAssertEqualCodeUnits);
2185 self.instruction(End);
2186 }
2187
2188 self.instruction(LocalGet(dst.len.idx));
2192 self.ptr_uconst(dst_mem_opts, UTF16_TAG);
2193 self.ptr_and(dst_mem_opts);
2194 self.ptr_br_if(dst_mem_opts, 0);
2195
2196 self.realloc(
2198 dst.opts,
2199 &dst.ptr,
2200 AllocSize::Local(dst_byte_len.idx),
2201 AllocSize::Local(dst.len.idx),
2202 2,
2203 Trap::StringOutOfBounds,
2204 );
2205
2206 self.free_temp_local(dst_byte_len);
2207 self.free_temp_local(src_byte_len);
2208
2209 dst
2210 }
2211
2212 fn string_to_compact<'c>(
2219 &mut self,
2220 src: &WasmString<'_>,
2221 src_enc: FE,
2222 dst_opts: &'c Options,
2223 ) -> WasmString<'c> {
2224 let src_mem_opts = match &src.opts.data_model {
2225 DataModel::Gc {} => todo!("CM+GC"),
2226 DataModel::LinearMemory(opts) => opts,
2227 };
2228 let dst_mem_opts = match &dst_opts.data_model {
2229 DataModel::Gc {} => todo!("CM+GC"),
2230 DataModel::LinearMemory(opts) => opts,
2231 };
2232
2233 self.validate_string_length(src, src_enc);
2234
2235 self.convert_src_len_to_dst(src.len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2236 let dst_len = self.local_tee_new_tmp(dst_mem_opts.ptr());
2237 let dst_byte_len = self.local_set_new_tmp(dst_mem_opts.ptr());
2238 let dst = {
2239 let dst_mem = self.malloc(
2240 dst_opts,
2241 AllocSize::Local(dst_byte_len.idx),
2242 2,
2243 Trap::StringOutOfBounds,
2244 );
2245 WasmString {
2246 ptr: dst_mem.addr,
2247 len: dst_len,
2248 opts: dst_opts,
2249 }
2250 };
2251
2252 let (latin1, utf16) = match src_enc {
2256 FE::Utf8 => (Transcode::Utf8ToLatin1, Transcode::Utf8ToCompactUtf16),
2257 FE::Utf16 => (Transcode::Utf16ToLatin1, Transcode::Utf16ToCompactUtf16),
2258 FE::Latin1 => unreachable!(),
2259 };
2260 let transcode_latin1 = self.transcoder(src, &dst, latin1);
2261 let transcode_utf16 = self.transcoder(src, &dst, utf16);
2262 self.instruction(LocalGet(src.ptr.idx));
2263 self.instruction(LocalGet(src.len.idx));
2264 self.instruction(LocalGet(dst.ptr.idx));
2265 self.instruction(Call(transcode_latin1.as_u32()));
2266 self.instruction(LocalSet(dst.len.idx));
2267 let src_len_tmp = self.local_set_new_tmp(src_mem_opts.ptr());
2268
2269 self.instruction(LocalGet(src_len_tmp.idx));
2272 self.instruction(LocalGet(src.len.idx));
2273 self.ptr_eq(src_mem_opts);
2274 self.instruction(If(BlockType::Empty)); self.instruction(LocalGet(dst_byte_len.idx));
2280 self.instruction(LocalGet(dst.len.idx));
2281 self.ptr_ne(dst_mem_opts);
2282 self.instruction(If(BlockType::Empty));
2283 self.realloc(
2284 dst.opts,
2285 &dst.ptr,
2286 AllocSize::Local(dst_byte_len.idx),
2287 AllocSize::Local(dst.len.idx),
2288 2,
2289 Trap::StringOutOfBounds,
2290 );
2291 self.instruction(End);
2292
2293 self.instruction(Else); if src_enc.width() == 1 {
2302 self.validate_string_length_u8(src, 2);
2303 }
2304
2305 self.convert_src_len_to_dst(src.len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2308 self.ptr_uconst(dst_mem_opts, 1);
2309 self.ptr_shl(dst_mem_opts);
2310 let new_byte_len = self.local_set_new_tmp(dst_mem_opts.ptr());
2311 self.realloc(
2312 dst.opts,
2313 &dst.ptr,
2314 AllocSize::Local(dst_byte_len.idx),
2315 AllocSize::Local(new_byte_len.idx),
2316 2,
2317 Trap::StringOutOfBounds,
2318 );
2319 self.instruction(LocalGet(new_byte_len.idx));
2320 self.instruction(LocalSet(dst_byte_len.idx));
2321 self.free_temp_local(new_byte_len);
2322
2323 self.instruction(LocalGet(src.ptr.idx));
2327 self.instruction(LocalGet(src_len_tmp.idx));
2328 if let FE::Utf16 = src_enc {
2329 self.ptr_uconst(src_mem_opts, 1);
2330 self.ptr_shl(src_mem_opts);
2331 }
2332 self.ptr_add(src_mem_opts);
2333 self.instruction(LocalGet(src.len.idx));
2334 self.instruction(LocalGet(src_len_tmp.idx));
2335 self.ptr_sub(src_mem_opts);
2336 self.instruction(LocalGet(dst.ptr.idx));
2337 self.convert_src_len_to_dst(src.len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2338 self.instruction(LocalGet(dst.len.idx));
2339 self.instruction(Call(transcode_utf16.as_u32()));
2340 self.instruction(LocalSet(dst.len.idx));
2341
2342 self.instruction(LocalGet(dst.len.idx));
2350 self.convert_src_len_to_dst(src.len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2351 self.ptr_ne(dst_mem_opts);
2352 self.instruction(If(BlockType::Empty));
2353 self.realloc(
2354 dst.opts,
2355 &dst.ptr,
2356 AllocSize::Local(dst_byte_len.idx),
2357 AllocSize::DoubleLocal(dst.len.idx),
2358 2,
2359 Trap::StringOutOfBounds,
2360 );
2361 self.instruction(End);
2362
2363 self.instruction(LocalGet(dst.len.idx));
2365 self.ptr_uconst(dst_mem_opts, UTF16_TAG);
2366 self.ptr_or(dst_mem_opts);
2367 self.instruction(LocalSet(dst.len.idx));
2368
2369 self.instruction(End); self.free_temp_local(src_len_tmp);
2372 self.free_temp_local(dst_byte_len);
2373
2374 dst
2375 }
2376
2377 fn validate_string_length(&mut self, src: &WasmString<'_>, dst: FE) {
2378 self.validate_string_length_u8(src, dst.width());
2379 self.consume_hostcall_fuel(src, dst);
2380 }
2381
2382 fn validate_string_length_u8(&mut self, s: &WasmString<'_>, dst: u8) {
2383 let mem_opts = match &s.opts.data_model {
2384 DataModel::Gc {} => todo!("CM+GC"),
2385 DataModel::LinearMemory(opts) => opts,
2386 };
2387
2388 self.instruction(LocalGet(s.len.idx));
2391 let max = MAX_STRING_BYTE_LENGTH / u32::from(dst);
2392 self.ptr_uconst(mem_opts, max);
2393 self.ptr_gt_u(mem_opts);
2394 self.instruction(If(BlockType::Empty));
2395 self.trap(Trap::StringOutOfBounds);
2396 self.instruction(End);
2397 }
2398
2399 fn transcoder(
2400 &mut self,
2401 src: &WasmString<'_>,
2402 dst: &WasmString<'_>,
2403 op: Transcode,
2404 ) -> FuncIndex {
2405 match (src.opts.data_model, dst.opts.data_model) {
2406 (DataModel::Gc {}, _) | (_, DataModel::Gc {}) => {
2407 todo!("CM+GC")
2408 }
2409 (
2410 DataModel::LinearMemory(LinearMemoryOptions {
2411 memory: Some((src_mem, src_ty)),
2412 realloc: _,
2413 }),
2414 DataModel::LinearMemory(LinearMemoryOptions {
2415 memory: Some((dst_mem, dst_ty)),
2416 realloc: _,
2417 }),
2418 ) => self.module.import_transcoder(Transcoder {
2419 from_memory: src_mem,
2420 from_memory64: src_ty.idx_type == IndexType::I64,
2421 to_memory: dst_mem,
2422 to_memory64: dst_ty.idx_type == IndexType::I64,
2423 op,
2424 }),
2425 (DataModel::LinearMemory(LinearMemoryOptions { memory: None, .. }), _)
2426 | (_, DataModel::LinearMemory(LinearMemoryOptions { memory: None, .. })) => {
2427 unreachable!()
2428 }
2429 }
2430 }
2431
2432 fn begin_translate_sequence<'c>(
2441 &mut self,
2442 src: &Source<'c>,
2443 dst: &Destination<'c>,
2444 src_element_size: u32,
2445 src_element_align: u32,
2446 dst_element_size: u32,
2447 dst_element_align: u32,
2448 ) -> SequenceTranslation<'c> {
2449 let src_mem_opts = match &src.opts().data_model {
2450 DataModel::Gc {} => todo!("CM+GC"),
2451 DataModel::LinearMemory(opts) => opts,
2452 };
2453 let dst_mem_opts = match &dst.opts().data_model {
2454 DataModel::Gc {} => todo!("CM+GC"),
2455 DataModel::LinearMemory(opts) => opts,
2456 };
2457
2458 let src_opts = src.opts();
2459 let dst_opts = dst.opts();
2460
2461 match src {
2466 Source::Stack(s) => {
2467 assert_eq!(s.locals.len(), 2);
2468 self.stack_get(&s.slice(0..1), src_mem_opts.ptr());
2469 self.stack_get(&s.slice(1..2), src_mem_opts.ptr());
2470 }
2471 Source::Memory(mem) => {
2472 self.ptr_load(mem);
2473 self.ptr_load(&mem.bump(src_mem_opts.ptr_size().into()));
2474 }
2475 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
2476 }
2477 let src_len = self.local_set_new_tmp(src_mem_opts.ptr());
2478 let src_ptr = self.local_set_new_tmp(src_mem_opts.ptr());
2479
2480 let src_byte_len =
2482 self.calculate_list_byte_len(src_mem_opts, src_len.idx, src_element_size);
2483 let dst_byte_len = if src_element_size == dst_element_size {
2484 self.convert_src_len_to_dst(src_byte_len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2485 self.local_set_new_tmp(dst_mem_opts.ptr())
2486 } else if src_mem_opts.ptr() == dst_mem_opts.ptr() {
2487 self.calculate_list_byte_len(dst_mem_opts, src_len.idx, dst_element_size)
2488 } else {
2489 self.convert_src_len_to_dst(src_len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2490 let tmp = self.local_set_new_tmp(dst_mem_opts.ptr());
2491 let ret = self.calculate_list_byte_len(dst_mem_opts, tmp.idx, dst_element_size);
2492 self.free_temp_local(tmp);
2493 ret
2494 };
2495
2496 let src_mem = self.memory_operand(
2499 src_opts,
2500 src_ptr,
2501 AllocSize::Local(src_byte_len.idx),
2502 src_element_align,
2503 Trap::ListOutOfBounds,
2504 );
2505
2506 let dst_mem = self.malloc(
2511 dst_opts,
2512 AllocSize::Local(dst_byte_len.idx),
2513 dst_element_align,
2514 Trap::ListOutOfBounds,
2515 );
2516
2517 self.free_temp_local(src_byte_len);
2518 self.free_temp_local(dst_byte_len);
2519
2520 let loop_state = if src_element_size > 0 || dst_element_size > 0 {
2524 self.instruction(Block(BlockType::Empty));
2525
2526 self.instruction(LocalGet(src_len.idx));
2528 let remaining = self.local_tee_new_tmp(src_mem_opts.ptr());
2529 self.ptr_eqz(src_mem_opts);
2530 self.instruction(BrIf(0));
2531
2532 self.instruction(LocalGet(src_mem.addr.idx));
2534 let cur_src_ptr = self.local_set_new_tmp(src_mem_opts.ptr());
2535 self.instruction(LocalGet(dst_mem.addr.idx));
2536 let cur_dst_ptr = self.local_set_new_tmp(dst_mem_opts.ptr());
2537
2538 self.instruction(Loop(BlockType::Empty));
2539
2540 Some(SequenceLoopState {
2541 remaining,
2542 cur_src_ptr,
2543 cur_dst_ptr,
2544 })
2545 } else {
2546 None
2547 };
2548
2549 SequenceTranslation {
2550 src_len,
2551 src_mem,
2552 dst_mem,
2553 src_opts,
2554 dst_opts,
2555 src_mem_opts,
2556 dst_mem_opts,
2557 loop_state,
2558 }
2559 }
2560
2561 fn end_translate_sequence(&mut self, seq: SequenceTranslation<'_>, dst: &Destination) {
2567 if let Some(loop_state) = seq.loop_state {
2568 self.instruction(LocalGet(loop_state.remaining.idx));
2571 self.ptr_iconst(seq.src_mem_opts, -1);
2572 self.ptr_add(seq.src_mem_opts);
2573 self.instruction(LocalTee(loop_state.remaining.idx));
2574 self.ptr_br_if(seq.src_mem_opts, 0);
2575 self.instruction(End); self.instruction(End); self.free_temp_local(loop_state.cur_dst_ptr);
2579 self.free_temp_local(loop_state.cur_src_ptr);
2580 self.free_temp_local(loop_state.remaining);
2581 }
2582
2583 match dst {
2585 Destination::Stack(s, _) => {
2586 self.instruction(LocalGet(seq.dst_mem.addr.idx));
2587 self.stack_set(&s[..1], seq.dst_mem_opts.ptr());
2588 self.convert_src_len_to_dst(
2589 seq.src_len.idx,
2590 seq.src_mem_opts.ptr(),
2591 seq.dst_mem_opts.ptr(),
2592 );
2593 self.stack_set(&s[1..], seq.dst_mem_opts.ptr());
2594 }
2595 Destination::Memory(mem) => {
2596 self.instruction(LocalGet(mem.addr.idx));
2597 self.instruction(LocalGet(seq.dst_mem.addr.idx));
2598 self.ptr_store(mem);
2599 self.instruction(LocalGet(mem.addr.idx));
2600 self.convert_src_len_to_dst(
2601 seq.src_len.idx,
2602 seq.src_mem_opts.ptr(),
2603 seq.dst_mem_opts.ptr(),
2604 );
2605 self.ptr_store(&mem.bump(seq.dst_mem_opts.ptr_size().into()));
2606 }
2607 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
2608 }
2609
2610 self.free_temp_local(seq.src_len);
2611 self.free_temp_local(seq.src_mem.addr);
2612 self.free_temp_local(seq.dst_mem.addr);
2613 }
2614
2615 fn translate_list(
2616 &mut self,
2617 src_ty: TypeListIndex,
2618 src: &Source<'_>,
2619 dst_ty: &InterfaceType,
2620 dst: &Destination,
2621 ) {
2622 let src_mem_opts = match &src.opts().data_model {
2623 DataModel::Gc {} => todo!("CM+GC"),
2624 DataModel::LinearMemory(opts) => opts,
2625 };
2626 let dst_mem_opts = match &dst.opts().data_model {
2627 DataModel::Gc {} => todo!("CM+GC"),
2628 DataModel::LinearMemory(opts) => opts,
2629 };
2630
2631 let src_element_ty = &self.types[src_ty].element;
2632 let dst_element_ty = match dst_ty {
2633 InterfaceType::List(r) => &self.types[*r].element,
2634 _ => panic!("expected a list"),
2635 };
2636 let (src_size, src_align) = self.types.size_align(src_mem_opts, src_element_ty);
2637 let (dst_size, dst_align) = self.types.size_align(dst_mem_opts, dst_element_ty);
2638
2639 let seq = self.begin_translate_sequence(src, dst, src_size, src_align, dst_size, dst_align);
2640
2641 if let Some(ref loop_state) = seq.loop_state {
2642 let element_src = Source::Memory(Memory {
2643 opts: seq.src_opts,
2644 offset: 0,
2645 addr: TempLocal::new(loop_state.cur_src_ptr.idx, loop_state.cur_src_ptr.ty),
2646 });
2647 let element_dst = Destination::Memory(Memory {
2648 opts: seq.dst_opts,
2649 offset: 0,
2650 addr: TempLocal::new(loop_state.cur_dst_ptr.idx, loop_state.cur_dst_ptr.ty),
2651 });
2652 self.translate(src_element_ty, &element_src, dst_element_ty, &element_dst);
2653
2654 if src_size > 0 {
2655 self.instruction(LocalGet(loop_state.cur_src_ptr.idx));
2656 self.ptr_uconst(src_mem_opts, src_size);
2657 self.ptr_add(src_mem_opts);
2658 self.instruction(LocalSet(loop_state.cur_src_ptr.idx));
2659 }
2660 if dst_size > 0 {
2661 self.instruction(LocalGet(loop_state.cur_dst_ptr.idx));
2662 self.ptr_uconst(dst_mem_opts, dst_size);
2663 self.ptr_add(dst_mem_opts);
2664 self.instruction(LocalSet(loop_state.cur_dst_ptr.idx));
2665 }
2666 }
2667
2668 self.end_translate_sequence(seq, dst);
2669 }
2670
2671 fn translate_map(
2677 &mut self,
2678 src_ty: TypeMapIndex,
2679 src: &Source<'_>,
2680 dst_ty: &InterfaceType,
2681 dst: &Destination,
2682 ) {
2683 let src_mem_opts = match &src.opts().data_model {
2684 DataModel::Gc {} => todo!("CM+GC"),
2685 DataModel::LinearMemory(opts) => opts,
2686 };
2687 let dst_mem_opts = match &dst.opts().data_model {
2688 DataModel::Gc {} => todo!("CM+GC"),
2689 DataModel::LinearMemory(opts) => opts,
2690 };
2691
2692 let src_map_ty = &self.types[src_ty];
2693 let dst_map_ty = match dst_ty {
2694 InterfaceType::Map(r) => &self.types[*r],
2695 _ => panic!("expected a map"),
2696 };
2697
2698 let src_key_abi = self.types.canonical_abi(&src_map_ty.key);
2700 let src_value_abi = self.types.canonical_abi(&src_map_ty.value);
2701 let src_entry_abi = CanonicalAbiInfo::record([src_key_abi, src_value_abi].into_iter());
2702 let (src_tuple_size, src_entry_align) = src_mem_opts.sizealign(&src_entry_abi);
2703 let src_value_offset = {
2704 let mut offset = 0u32;
2705 if src_mem_opts.memory64() {
2706 src_key_abi.next_field64(&mut offset);
2707 src_value_abi.next_field64(&mut offset)
2708 } else {
2709 src_key_abi.next_field32(&mut offset);
2710 src_value_abi.next_field32(&mut offset)
2711 }
2712 };
2713
2714 let dst_key_abi = self.types.canonical_abi(&dst_map_ty.key);
2715 let dst_value_abi = self.types.canonical_abi(&dst_map_ty.value);
2716 let dst_entry_abi = CanonicalAbiInfo::record([dst_key_abi, dst_value_abi].into_iter());
2717 let (dst_tuple_size, dst_entry_align) = dst_mem_opts.sizealign(&dst_entry_abi);
2718 let dst_value_offset = {
2719 let mut offset = 0u32;
2720 if dst_mem_opts.memory64() {
2721 dst_key_abi.next_field64(&mut offset);
2722 dst_value_abi.next_field64(&mut offset)
2723 } else {
2724 dst_key_abi.next_field32(&mut offset);
2725 dst_value_abi.next_field32(&mut offset)
2726 }
2727 };
2728
2729 let seq = self.begin_translate_sequence(
2730 src,
2731 dst,
2732 src_tuple_size,
2733 src_entry_align,
2734 dst_tuple_size,
2735 dst_entry_align,
2736 );
2737
2738 if let Some(ref loop_state) = seq.loop_state {
2739 let key_src = Source::Memory(Memory {
2740 opts: seq.src_opts,
2741 offset: 0,
2742 addr: TempLocal::new(loop_state.cur_src_ptr.idx, src_mem_opts.ptr()),
2743 });
2744 let key_dst = Destination::Memory(Memory {
2745 opts: seq.dst_opts,
2746 offset: 0,
2747 addr: TempLocal::new(loop_state.cur_dst_ptr.idx, dst_mem_opts.ptr()),
2748 });
2749 self.translate(&src_map_ty.key, &key_src, &dst_map_ty.key, &key_dst);
2750
2751 let value_src = Source::Memory(Memory {
2752 opts: seq.src_opts,
2753 offset: src_value_offset,
2754 addr: TempLocal::new(loop_state.cur_src_ptr.idx, src_mem_opts.ptr()),
2755 });
2756 let value_dst = Destination::Memory(Memory {
2757 opts: seq.dst_opts,
2758 offset: dst_value_offset,
2759 addr: TempLocal::new(loop_state.cur_dst_ptr.idx, dst_mem_opts.ptr()),
2760 });
2761 self.translate(&src_map_ty.value, &value_src, &dst_map_ty.value, &value_dst);
2762
2763 if src_tuple_size > 0 {
2765 self.instruction(LocalGet(loop_state.cur_src_ptr.idx));
2766 self.ptr_uconst(src_mem_opts, src_tuple_size);
2767 self.ptr_add(src_mem_opts);
2768 self.instruction(LocalSet(loop_state.cur_src_ptr.idx));
2769 }
2770 if dst_tuple_size > 0 {
2771 self.instruction(LocalGet(loop_state.cur_dst_ptr.idx));
2772 self.ptr_uconst(dst_mem_opts, dst_tuple_size);
2773 self.ptr_add(dst_mem_opts);
2774 self.instruction(LocalSet(loop_state.cur_dst_ptr.idx));
2775 }
2776 }
2777
2778 self.end_translate_sequence(seq, dst);
2779 }
2780
2781 fn calculate_list_byte_len(
2782 &mut self,
2783 opts: &LinearMemoryOptions,
2784 len_local: u32,
2785 elt_size: u32,
2786 ) -> TempLocal {
2787 if elt_size == 0 {
2790 self.ptr_uconst(opts, 0);
2791 return self.local_set_new_tmp(opts.ptr());
2792 }
2793
2794 if elt_size == 1 {
2802 if let ValType::I64 = opts.ptr() {
2803 self.instruction(LocalGet(len_local));
2804 self.instruction(I64Const(32));
2805 self.instruction(I64ShrU);
2806 self.instruction(I32WrapI64);
2807 self.instruction(If(BlockType::Empty));
2808 self.trap(Trap::ListOutOfBounds);
2809 self.instruction(End);
2810 }
2811 self.instruction(LocalGet(len_local));
2812 return self.local_set_new_tmp(opts.ptr());
2813 }
2814
2815 self.instruction(Block(BlockType::Empty));
2820 self.instruction(Block(BlockType::Empty));
2821 self.instruction(LocalGet(len_local));
2822 match opts.ptr() {
2823 ValType::I32 => self.instruction(I64ExtendI32U),
2827
2828 ValType::I64 => {
2832 self.instruction(I64Const(32));
2833 self.instruction(I64ShrU);
2834 self.instruction(I32WrapI64);
2835 self.instruction(BrIf(0));
2836 self.instruction(LocalGet(len_local));
2837 }
2838
2839 _ => unreachable!(),
2840 }
2841
2842 self.instruction(I64Const(elt_size.into()));
2851 self.instruction(I64Mul);
2852 let tmp = self.local_tee_new_tmp(ValType::I64);
2853 self.instruction(I64Const(32));
2856 self.instruction(I64ShrU);
2857 self.instruction(I64Eqz);
2858 self.instruction(BrIf(1));
2859 self.instruction(End);
2860 self.trap(Trap::ListOutOfBounds);
2861 self.instruction(End);
2862
2863 if opts.ptr() == ValType::I64 {
2867 tmp
2868 } else {
2869 self.instruction(LocalGet(tmp.idx));
2870 self.instruction(I32WrapI64);
2871 self.free_temp_local(tmp);
2872 self.local_set_new_tmp(ValType::I32)
2873 }
2874 }
2875
2876 fn convert_src_len_to_dst(
2877 &mut self,
2878 src_len_local: u32,
2879 src_ptr_ty: ValType,
2880 dst_ptr_ty: ValType,
2881 ) {
2882 self.instruction(LocalGet(src_len_local));
2883 match (src_ptr_ty, dst_ptr_ty) {
2884 (ValType::I32, ValType::I64) => self.instruction(I64ExtendI32U),
2885 (ValType::I64, ValType::I32) => self.instruction(I32WrapI64),
2886 (src, dst) => assert_eq!(src, dst),
2887 }
2888 }
2889
2890 fn translate_record(
2891 &mut self,
2892 src_ty: TypeRecordIndex,
2893 src: &Source<'_>,
2894 dst_ty: &InterfaceType,
2895 dst: &Destination,
2896 ) {
2897 let src_ty = &self.types[src_ty];
2898 let dst_ty = match dst_ty {
2899 InterfaceType::Record(r) => &self.types[*r],
2900 _ => panic!("expected a record"),
2901 };
2902
2903 assert_eq!(src_ty.fields.len(), dst_ty.fields.len());
2905
2906 let mut src_fields = HashMap::new();
2910 for (i, src) in src
2911 .record_field_srcs(self.types, src_ty.fields.iter().map(|f| f.ty))
2912 .enumerate()
2913 {
2914 let field = &src_ty.fields[i];
2915 src_fields.insert(&field.name, (src, &field.ty));
2916 }
2917
2918 for (i, dst) in dst
2927 .record_field_dsts(self.types, dst_ty.fields.iter().map(|f| f.ty))
2928 .enumerate()
2929 {
2930 let field = &dst_ty.fields[i];
2931 let (src, src_ty) = &src_fields[&field.name];
2932 self.translate(src_ty, src, &field.ty, &dst);
2933 }
2934 }
2935
2936 fn translate_flags(
2937 &mut self,
2938 src_ty: TypeFlagsIndex,
2939 src: &Source<'_>,
2940 dst_ty: &InterfaceType,
2941 dst: &Destination,
2942 ) {
2943 let src_ty = &self.types[src_ty];
2944 let dst_ty = match dst_ty {
2945 InterfaceType::Flags(r) => &self.types[*r],
2946 _ => panic!("expected a record"),
2947 };
2948
2949 assert_eq!(src_ty.names, dst_ty.names);
2957 let cnt = src_ty.names.len();
2958 match FlagsSize::from_count(cnt) {
2959 FlagsSize::Size0 => {}
2960 FlagsSize::Size1 => {
2961 let mask = if cnt == 8 { 0xff } else { (1 << cnt) - 1 };
2962 self.convert_u8_mask(src, dst, mask);
2963 }
2964 FlagsSize::Size2 => {
2965 let mask = if cnt == 16 { 0xffff } else { (1 << cnt) - 1 };
2966 self.convert_u16_mask(src, dst, mask);
2967 }
2968 FlagsSize::Size4Plus(n) => {
2969 let srcs = src.record_field_srcs(self.types, (0..n).map(|_| InterfaceType::U32));
2970 let dsts = dst.record_field_dsts(self.types, (0..n).map(|_| InterfaceType::U32));
2971 let n = usize::from(n);
2972 for (i, (src, dst)) in srcs.zip(dsts).enumerate() {
2973 let mask = if i == n - 1 && (cnt % 32 != 0) {
2974 (1 << (cnt % 32)) - 1
2975 } else {
2976 0xffffffff
2977 };
2978 self.convert_u32_mask(&src, &dst, mask);
2979 }
2980 }
2981 }
2982 }
2983
2984 fn translate_tuple(
2985 &mut self,
2986 src_ty: TypeTupleIndex,
2987 src: &Source<'_>,
2988 dst_ty: &InterfaceType,
2989 dst: &Destination,
2990 ) {
2991 let src_ty = &self.types[src_ty];
2992 let dst_ty = match dst_ty {
2993 InterfaceType::Tuple(t) => &self.types[*t],
2994 _ => panic!("expected a tuple"),
2995 };
2996
2997 assert_eq!(src_ty.types.len(), dst_ty.types.len());
2999
3000 let srcs = src
3001 .record_field_srcs(self.types, src_ty.types.iter().copied())
3002 .zip(src_ty.types.iter());
3003 let dsts = dst
3004 .record_field_dsts(self.types, dst_ty.types.iter().copied())
3005 .zip(dst_ty.types.iter());
3006 for ((src, src_ty), (dst, dst_ty)) in srcs.zip(dsts) {
3007 self.translate(src_ty, &src, dst_ty, &dst);
3008 }
3009 }
3010
3011 fn translate_fixed_length_list(
3012 &mut self,
3013 src_ty: TypeFixedLengthListIndex,
3014 src: &Source<'_>,
3015 dst_ty: &InterfaceType,
3016 dst: &Destination,
3017 ) {
3018 let src_ty = &self.types[src_ty];
3019 let dst_ty = match dst_ty {
3020 InterfaceType::FixedLengthList(t) => &self.types[*t],
3021 _ => panic!("expected a fixed size list"),
3022 };
3023
3024 assert_eq!(src_ty.size, dst_ty.size);
3026
3027 match (&src, &dst) {
3028 (Source::Memory(src_mem), Destination::Memory(dst_mem)) => {
3030 let src_mem_opts = match &src_mem.opts.data_model {
3031 DataModel::Gc {} => todo!("CM+GC"),
3032 DataModel::LinearMemory(opts) => opts,
3033 };
3034 let dst_mem_opts = match &dst_mem.opts.data_model {
3035 DataModel::Gc {} => todo!("CM+GC"),
3036 DataModel::LinearMemory(opts) => opts,
3037 };
3038 let src_element_bytes = self.types.size_align(src_mem_opts, &src_ty.element).0;
3039 let dst_element_bytes = self.types.size_align(dst_mem_opts, &dst_ty.element).0;
3040 assert_ne!(src_element_bytes, 0);
3041 assert_ne!(dst_element_bytes, 0);
3042
3043 self.instruction(LocalGet(src_mem.addr.idx));
3046 if src_mem.offset != 0 {
3047 self.ptr_uconst(src_mem_opts, src_mem.offset);
3048 self.ptr_add(src_mem_opts);
3049 }
3050 let cur_src_ptr = self.local_set_new_tmp(src_mem_opts.ptr());
3051 self.instruction(LocalGet(dst_mem.addr.idx));
3052 if dst_mem.offset != 0 {
3053 self.ptr_uconst(dst_mem_opts, dst_mem.offset);
3054 self.ptr_add(dst_mem_opts);
3055 }
3056 let cur_dst_ptr = self.local_set_new_tmp(dst_mem_opts.ptr());
3057
3058 self.instruction(I32Const(src_ty.size as i32));
3059 let remaining = self.local_set_new_tmp(ValType::I32);
3060
3061 self.instruction(Loop(BlockType::Empty));
3062
3063 let element_src = Source::Memory(Memory {
3065 opts: src_mem.opts,
3066 offset: 0,
3067 addr: TempLocal::new(cur_src_ptr.idx, cur_src_ptr.ty),
3068 });
3069 let element_dst = Destination::Memory(Memory {
3070 opts: dst_mem.opts,
3071 offset: 0,
3072 addr: TempLocal::new(cur_dst_ptr.idx, cur_dst_ptr.ty),
3073 });
3074 self.translate(&src_ty.element, &element_src, &dst_ty.element, &element_dst);
3075
3076 self.instruction(LocalGet(cur_src_ptr.idx));
3078 self.ptr_uconst(src_mem_opts, src_element_bytes);
3079 self.ptr_add(src_mem_opts);
3080 self.instruction(LocalSet(cur_src_ptr.idx));
3081 self.instruction(LocalGet(cur_dst_ptr.idx));
3082 self.ptr_uconst(dst_mem_opts, dst_element_bytes);
3083 self.ptr_add(dst_mem_opts);
3084 self.instruction(LocalSet(cur_dst_ptr.idx));
3085
3086 self.instruction(LocalGet(remaining.idx));
3089 self.ptr_iconst(src_mem_opts, -1);
3090 self.ptr_add(src_mem_opts);
3091 self.instruction(LocalTee(remaining.idx));
3092 self.ptr_br_if(src_mem_opts, 0);
3093 self.instruction(End); self.free_temp_local(cur_dst_ptr);
3096 self.free_temp_local(cur_src_ptr);
3097 self.free_temp_local(remaining);
3098 return;
3099 }
3100 (_, _) => {
3102 assert!(
3104 src_ty.size as usize <= MAX_FLAT_PARAMS
3105 && dst_ty.size as usize <= MAX_FLAT_PARAMS
3106 );
3107 let srcs =
3108 src.record_field_srcs(self.types, (0..src_ty.size).map(|_| src_ty.element));
3109 let dsts =
3110 dst.record_field_dsts(self.types, (0..dst_ty.size).map(|_| dst_ty.element));
3111 for (src, dst) in srcs.zip(dsts) {
3112 self.translate(&src_ty.element, &src, &dst_ty.element, &dst);
3113 }
3114 }
3115 }
3116 }
3117
3118 fn translate_variant(
3119 &mut self,
3120 src_ty: TypeVariantIndex,
3121 src: &Source<'_>,
3122 dst_ty: &InterfaceType,
3123 dst: &Destination,
3124 ) {
3125 let src_ty = &self.types[src_ty];
3126 let dst_ty = match dst_ty {
3127 InterfaceType::Variant(t) => &self.types[*t],
3128 _ => panic!("expected a variant"),
3129 };
3130
3131 let src_info = variant_info(self.types, src_ty.cases.iter().map(|(_, c)| c.as_ref()));
3132 let dst_info = variant_info(self.types, dst_ty.cases.iter().map(|(_, c)| c.as_ref()));
3133
3134 let iter = src_ty
3135 .cases
3136 .iter()
3137 .enumerate()
3138 .map(|(src_i, (src_case, src_case_ty))| {
3139 let dst_i = dst_ty
3140 .cases
3141 .iter()
3142 .position(|(c, _)| c == src_case)
3143 .unwrap();
3144 let dst_case_ty = &dst_ty.cases[dst_i];
3145 let src_i = u32::try_from(src_i).unwrap();
3146 let dst_i = u32::try_from(dst_i).unwrap();
3147 VariantCase {
3148 src_i,
3149 src_ty: src_case_ty.as_ref(),
3150 dst_i,
3151 dst_ty: dst_case_ty.as_ref(),
3152 }
3153 });
3154 self.convert_variant(src, &src_info, dst, &dst_info, iter);
3155 }
3156
3157 fn translate_enum(
3158 &mut self,
3159 src_ty: TypeEnumIndex,
3160 src: &Source<'_>,
3161 dst_ty: &InterfaceType,
3162 dst: &Destination,
3163 ) {
3164 let src_ty = &self.types[src_ty];
3165 let dst_ty = match dst_ty {
3166 InterfaceType::Enum(t) => &self.types[*t],
3167 _ => panic!("expected an option"),
3168 };
3169
3170 debug_assert_eq!(src_ty.info.size, dst_ty.info.size);
3171 debug_assert_eq!(src_ty.names.len(), dst_ty.names.len());
3172 debug_assert!(
3173 src_ty
3174 .names
3175 .iter()
3176 .zip(dst_ty.names.iter())
3177 .all(|(a, b)| a == b)
3178 );
3179
3180 match src {
3182 Source::Stack(s) => self.stack_get(&s.slice(0..1), ValType::I32),
3183 Source::Memory(mem) => match src_ty.info.size {
3184 DiscriminantSize::Size1 => self.i32_load8u(mem),
3185 DiscriminantSize::Size2 => self.i32_load16u(mem),
3186 DiscriminantSize::Size4 => self.i32_load(mem),
3187 },
3188 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
3189 }
3190 let tmp = self.local_tee_new_tmp(ValType::I32);
3191
3192 self.instruction(I32Const(i32::try_from(src_ty.names.len()).unwrap()));
3194 self.instruction(I32GeU);
3195 self.instruction(If(BlockType::Empty));
3196 self.trap(Trap::InvalidDiscriminant);
3197 self.instruction(End);
3198
3199 match dst {
3201 Destination::Stack(stack, _) => {
3202 self.local_get_tmp(&tmp);
3203 self.stack_set(&stack[..1], ValType::I32)
3204 }
3205 Destination::Memory(mem) => {
3206 self.push_dst_addr(dst);
3207 self.local_get_tmp(&tmp);
3208 match dst_ty.info.size {
3209 DiscriminantSize::Size1 => self.i32_store8(mem),
3210 DiscriminantSize::Size2 => self.i32_store16(mem),
3211 DiscriminantSize::Size4 => self.i32_store(mem),
3212 }
3213 }
3214 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
3215 }
3216 self.free_temp_local(tmp);
3217 }
3218
3219 fn translate_option(
3220 &mut self,
3221 src_ty: TypeOptionIndex,
3222 src: &Source<'_>,
3223 dst_ty: &InterfaceType,
3224 dst: &Destination,
3225 ) {
3226 let src_ty = &self.types[src_ty].ty;
3227 let dst_ty = match dst_ty {
3228 InterfaceType::Option(t) => &self.types[*t].ty,
3229 _ => panic!("expected an option"),
3230 };
3231 let src_ty = Some(src_ty);
3232 let dst_ty = Some(dst_ty);
3233
3234 let src_info = variant_info(self.types, [None, src_ty]);
3235 let dst_info = variant_info(self.types, [None, dst_ty]);
3236
3237 self.convert_variant(
3238 src,
3239 &src_info,
3240 dst,
3241 &dst_info,
3242 [
3243 VariantCase {
3244 src_i: 0,
3245 dst_i: 0,
3246 src_ty: None,
3247 dst_ty: None,
3248 },
3249 VariantCase {
3250 src_i: 1,
3251 dst_i: 1,
3252 src_ty,
3253 dst_ty,
3254 },
3255 ]
3256 .into_iter(),
3257 );
3258 }
3259
3260 fn translate_result(
3261 &mut self,
3262 src_ty: TypeResultIndex,
3263 src: &Source<'_>,
3264 dst_ty: &InterfaceType,
3265 dst: &Destination,
3266 ) {
3267 let src_ty = &self.types[src_ty];
3268 let dst_ty = match dst_ty {
3269 InterfaceType::Result(t) => &self.types[*t],
3270 _ => panic!("expected a result"),
3271 };
3272
3273 let src_info = variant_info(self.types, [src_ty.ok.as_ref(), src_ty.err.as_ref()]);
3274 let dst_info = variant_info(self.types, [dst_ty.ok.as_ref(), dst_ty.err.as_ref()]);
3275
3276 self.convert_variant(
3277 src,
3278 &src_info,
3279 dst,
3280 &dst_info,
3281 [
3282 VariantCase {
3283 src_i: 0,
3284 dst_i: 0,
3285 src_ty: src_ty.ok.as_ref(),
3286 dst_ty: dst_ty.ok.as_ref(),
3287 },
3288 VariantCase {
3289 src_i: 1,
3290 dst_i: 1,
3291 src_ty: src_ty.err.as_ref(),
3292 dst_ty: dst_ty.err.as_ref(),
3293 },
3294 ]
3295 .into_iter(),
3296 );
3297 }
3298
3299 fn convert_variant<'c>(
3300 &mut self,
3301 src: &Source<'_>,
3302 src_info: &VariantInfo,
3303 dst: &Destination,
3304 dst_info: &VariantInfo,
3305 src_cases: impl ExactSizeIterator<Item = VariantCase<'c>>,
3306 ) {
3307 let outer_block_ty = match dst {
3310 Destination::Stack(dst_flat, _) => match dst_flat.len() {
3311 0 => BlockType::Empty,
3312 1 => BlockType::Result(dst_flat[0]),
3313 _ => {
3314 let ty = self.module.core_types.function(&[], &dst_flat);
3315 BlockType::FunctionType(ty)
3316 }
3317 },
3318 Destination::Memory(_) => BlockType::Empty,
3319 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
3320 };
3321 self.instruction(Block(outer_block_ty));
3322
3323 let src_cases_len = src_cases.len();
3326 for _ in 0..src_cases_len - 1 {
3327 self.instruction(Block(BlockType::Empty));
3328 }
3329
3330 self.instruction(Block(BlockType::Empty));
3332
3333 self.instruction(Block(BlockType::Empty));
3336
3337 match src {
3339 Source::Stack(s) => self.stack_get(&s.slice(0..1), ValType::I32),
3340 Source::Memory(mem) => match src_info.size {
3341 DiscriminantSize::Size1 => self.i32_load8u(mem),
3342 DiscriminantSize::Size2 => self.i32_load16u(mem),
3343 DiscriminantSize::Size4 => self.i32_load(mem),
3344 },
3345 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
3346 }
3347
3348 let mut targets = Vec::new();
3351 for i in 0..src_cases_len {
3352 targets.push((i + 1) as u32);
3353 }
3354 self.instruction(BrTable(targets[..].into(), 0));
3355 self.instruction(End); self.trap(Trap::InvalidDiscriminant);
3358 self.instruction(End); let src_cases_len = u32::try_from(src_cases_len).unwrap();
3365 for case in src_cases {
3366 let VariantCase {
3367 src_i,
3368 src_ty,
3369 dst_i,
3370 dst_ty,
3371 } = case;
3372
3373 self.push_dst_addr(dst);
3376 self.instruction(I32Const(dst_i as i32));
3377 match dst {
3378 Destination::Stack(stack, _) => self.stack_set(&stack[..1], ValType::I32),
3379 Destination::Memory(mem) => match dst_info.size {
3380 DiscriminantSize::Size1 => self.i32_store8(mem),
3381 DiscriminantSize::Size2 => self.i32_store16(mem),
3382 DiscriminantSize::Size4 => self.i32_store(mem),
3383 },
3384 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
3385 }
3386
3387 let src_payload = src.payload_src(self.types, src_info, src_ty);
3388 let dst_payload = dst.payload_dst(self.types, dst_info, dst_ty);
3389
3390 match (src_ty, dst_ty) {
3393 (Some(src_ty), Some(dst_ty)) => {
3394 self.translate(src_ty, &src_payload, dst_ty, &dst_payload);
3395 }
3396 (None, None) => {}
3397 _ => unimplemented!(),
3398 }
3399
3400 if let Destination::Stack(payload_results, _) = dst_payload {
3407 if let Destination::Stack(dst_results, _) = dst {
3408 let remaining = &dst_results[1..][payload_results.len()..];
3409 for ty in remaining {
3410 match ty {
3411 ValType::I32 => self.instruction(I32Const(0)),
3412 ValType::I64 => self.instruction(I64Const(0)),
3413 ValType::F32 => self.instruction(F32Const(0.0.into())),
3414 ValType::F64 => self.instruction(F64Const(0.0.into())),
3415 _ => unreachable!(),
3416 }
3417 }
3418 }
3419 }
3420
3421 if src_i != src_cases_len - 1 {
3424 self.instruction(Br(src_cases_len - src_i - 1));
3425 }
3426 self.instruction(End); }
3428 }
3429
3430 fn translate_future(
3431 &mut self,
3432 src_ty: TypeFutureTableIndex,
3433 src: &Source<'_>,
3434 dst_ty: &InterfaceType,
3435 dst: &Destination,
3436 ) {
3437 let dst_ty = match dst_ty {
3438 InterfaceType::Future(t) => *t,
3439 _ => panic!("expected a `Future`"),
3440 };
3441 let transfer = self.module.import_future_transfer();
3442 self.translate_handle(src_ty.as_u32(), src, Some(dst_ty.as_u32()), dst, transfer);
3443 }
3444
3445 fn translate_stream(
3446 &mut self,
3447 src_ty: TypeStreamTableIndex,
3448 src: &Source<'_>,
3449 dst_ty: &InterfaceType,
3450 dst: &Destination,
3451 ) {
3452 let dst_ty = match dst_ty {
3453 InterfaceType::Stream(t) => *t,
3454 _ => panic!("expected a `Stream`"),
3455 };
3456 let transfer = self.module.import_stream_transfer();
3457 self.translate_handle(src_ty.as_u32(), src, Some(dst_ty.as_u32()), dst, transfer);
3458 }
3459
3460 fn translate_error_context(
3461 &mut self,
3462 src_ty: TypeComponentLocalErrorContextTableIndex,
3463 src: &Source<'_>,
3464 dst_ty: &InterfaceType,
3465 dst: &Destination,
3466 ) {
3467 let dst_ty = match dst_ty {
3468 InterfaceType::ErrorContext(t) => *t,
3469 _ => panic!("expected an `ErrorContext`"),
3470 };
3471 let transfer = self.module.import_error_context_transfer();
3472 self.translate_handle(src_ty.as_u32(), src, Some(dst_ty.as_u32()), dst, transfer);
3473 }
3474
3475 fn translate_own(
3476 &mut self,
3477 src_ty: TypeResourceTableIndex,
3478 src: &Source<'_>,
3479 dst_ty: &InterfaceType,
3480 dst: &Destination,
3481 ) {
3482 let dst_ty = match dst_ty {
3483 InterfaceType::Own(t) => *t,
3484 _ => panic!("expected an `Own`"),
3485 };
3486 let transfer = self.module.import_resource_transfer_own();
3487 self.translate_handle(src_ty.as_u32(), src, Some(dst_ty.as_u32()), dst, transfer);
3488 }
3489
3490 fn translate_borrow(
3491 &mut self,
3492 src_ty: TypeResourceTableIndex,
3493 src: &Source<'_>,
3494 dst_ty: &InterfaceType,
3495 dst: &Destination,
3496 ) {
3497 let dst_ty = match dst_ty {
3498 InterfaceType::Borrow(t) => *t,
3499 _ => panic!("expected an `Borrow`"),
3500 };
3501
3502 let (transfer, dst_ty) = if self.module.resource_owned_by_own_instance(dst_ty) {
3503 (self.module.import_resource_transfer_borrow_to_owner(), None)
3504 } else {
3505 (
3506 self.module.import_resource_transfer_borrow(),
3507 Some(dst_ty.as_u32()),
3508 )
3509 };
3510 self.translate_handle(src_ty.as_u32(), src, dst_ty, dst, transfer);
3511 }
3512
3513 fn translate_handle(
3521 &mut self,
3522 src_ty: u32,
3523 src: &Source<'_>,
3524 dst_ty: Option<u32>,
3525 dst: &Destination,
3526 transfer: FuncIndex,
3527 ) {
3528 self.push_dst_addr(dst);
3529 match src {
3530 Source::Memory(mem) => self.i32_load(mem),
3531 Source::Stack(stack) => self.stack_get(stack, ValType::I32),
3532 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
3533 }
3534 self.instruction(I32Const(src_ty as i32));
3535 if let Some(dst_ty) = dst_ty {
3536 self.instruction(I32Const(dst_ty as i32));
3537 }
3538 self.instruction(Call(transfer.as_u32()));
3539 match dst {
3540 Destination::Memory(mem) => self.i32_store(mem),
3541 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
3542 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
3543 }
3544 }
3545
3546 fn trap_if_not_may_leave(&mut self, flags_global: GlobalIndex, trap: Trap) -> TempLocal {
3553 self.instruction(Block(BlockType::Empty));
3554 self.instruction(GlobalGet(flags_global.as_u32()));
3555 let saved = self.local_tee_new_tmp(ValType::I32);
3558 self.instruction(BrIf(0));
3559 self.trap(trap);
3560 self.instruction(End);
3561 saved
3562 }
3563
3564 fn clear_may_leave(&mut self, flags_global: GlobalIndex) -> TempLocal {
3567 self.instruction(GlobalGet(flags_global.as_u32()));
3568 let saved = self.local_set_new_tmp(ValType::I32);
3569 self.set_may_leave_false(flags_global);
3570 saved
3571 }
3572
3573 fn set_may_leave_false(&mut self, flags_global: GlobalIndex) {
3578 self.instruction(I32Const(0));
3579 self.instruction(GlobalSet(flags_global.as_u32()));
3580 }
3581
3582 fn restore_may_leave(&mut self, flags_global: GlobalIndex, saved: TempLocal) {
3595 self.instruction(LocalGet(saved.idx));
3596 self.instruction(GlobalSet(flags_global.as_u32()));
3597 self.free_temp_local(saved);
3598 }
3599
3600 fn assert_aligned(&mut self, ty: &InterfaceType, mem: &Memory) {
3601 let mem_opts = mem.mem_opts();
3602 if !self.module.tunables.debug_adapter_modules {
3603 return;
3604 }
3605 let align = self.types.align(mem_opts, ty);
3606 if align == 1 {
3607 return;
3608 }
3609 assert!(align.is_power_of_two());
3610 self.instruction(LocalGet(mem.addr.idx));
3611 self.ptr_uconst(mem_opts, mem.offset);
3612 self.ptr_add(mem_opts);
3613 self.ptr_uconst(mem_opts, align - 1);
3614 self.ptr_and(mem_opts);
3615 self.ptr_if(mem_opts, BlockType::Empty);
3616 self.trap(Trap::DebugAssertPointerAligned);
3617 self.instruction(End);
3618 }
3619
3620 fn malloc_abi<'c>(
3626 &mut self,
3627 opts: &'c Options,
3628 abi: &CanonicalAbiInfo,
3629 oob_trap: Trap,
3630 ) -> Memory<'c> {
3631 match &opts.data_model {
3632 DataModel::Gc {} => todo!("CM+GC"),
3633 DataModel::LinearMemory(mem_opts) => {
3634 let (size, align) = mem_opts.sizealign(abi);
3635 let size = AllocSize::Const(size);
3636 self.malloc(opts, size, align, oob_trap)
3637 }
3638 }
3639 }
3640
3641 fn malloc<'c>(
3647 &mut self,
3648 opts: &'c Options,
3649 size: AllocSize,
3650 align: u32,
3651 oob_trap: Trap,
3652 ) -> Memory<'c> {
3653 match &opts.data_model {
3654 DataModel::Gc {} => todo!("CM+GC"),
3655 DataModel::LinearMemory(mem_opts) => {
3656 let realloc = mem_opts.realloc.unwrap();
3657 self.ptr_uconst(mem_opts, 0);
3658 self.ptr_uconst(mem_opts, 0);
3659 self.ptr_uconst(mem_opts, align);
3660 self.alloc_size(mem_opts, &size);
3661 self.call_realloc(realloc);
3662 let addr = self.local_set_new_tmp(mem_opts.ptr());
3663 self.memory_operand(opts, addr, size, align, oob_trap)
3664 }
3665 }
3666 }
3667
3668 fn realloc(
3674 &mut self,
3675 opts: &Options,
3676 ptr: &TempLocal,
3677 prev_size: AllocSize,
3678 size: AllocSize,
3679 align: u32,
3680 oob_trap: Trap,
3681 ) {
3682 match &opts.data_model {
3683 DataModel::Gc {} => todo!("CM+GC"),
3684 DataModel::LinearMemory(mem_opts) => {
3685 let realloc = mem_opts.realloc.unwrap();
3686 self.instruction(LocalGet(ptr.idx));
3687 self.alloc_size(mem_opts, &prev_size);
3688 self.ptr_uconst(mem_opts, align);
3689 self.alloc_size(mem_opts, &size);
3690 self.call_realloc(realloc);
3691 self.instruction(LocalSet(ptr.idx));
3692 self.validate_guest_pointer(opts, &ptr, &size, align, oob_trap)
3693 }
3694 }
3695 }
3696
3697 fn memory_operand_abi<'c>(
3700 &mut self,
3701 opts: &'c Options,
3702 addr: TempLocal,
3703 abi: &CanonicalAbiInfo,
3704 oob_trap: Trap,
3705 ) -> Memory<'c> {
3706 match &opts.data_model {
3707 DataModel::Gc {} => todo!("CM+GC"),
3708 DataModel::LinearMemory(mem_opts) => {
3709 let (size, align) = mem_opts.sizealign(abi);
3710 self.memory_operand(opts, addr, AllocSize::Const(size), align, oob_trap)
3711 }
3712 }
3713 }
3714
3715 fn memory_operand<'c>(
3718 &mut self,
3719 opts: &'c Options,
3720 addr: TempLocal,
3721 size: AllocSize,
3722 align: u32,
3723 oob_trap: Trap,
3724 ) -> Memory<'c> {
3725 self.validate_guest_pointer(opts, &addr, &size, align, oob_trap);
3726 Memory {
3727 addr,
3728 opts,
3729 offset: 0,
3730 }
3731 }
3732
3733 fn validate_guest_pointer(
3741 &mut self,
3742 opts: &Options,
3743 addr: &TempLocal,
3744 size: &AllocSize,
3745 align: u32,
3746 oob_trap: Trap,
3747 ) {
3748 let mem_opts = match &opts.data_model {
3749 DataModel::Gc {} => todo!("CM+GC"),
3750 DataModel::LinearMemory(mem_opts) => mem_opts,
3751 };
3752
3753 if align != 1 {
3756 self.instruction(LocalGet(addr.idx));
3757 assert!(align.is_power_of_two());
3758 self.ptr_uconst(mem_opts, align - 1);
3759 self.ptr_and(mem_opts);
3760 self.ptr_if(mem_opts, BlockType::Empty);
3761 self.trap(Trap::UnalignedPointer);
3762 self.instruction(End);
3763 }
3764
3765 let extend_to_64 = |me: &mut Self| {
3766 if !mem_opts.memory64() {
3767 me.instruction(I64ExtendI32U);
3768 }
3769 };
3770
3771 self.instruction(Block(BlockType::Empty));
3772 self.instruction(Block(BlockType::Empty));
3773 let (memory, ty) = mem_opts.memory.unwrap();
3774
3775 self.instruction(MemorySize(memory.as_u32()));
3780 extend_to_64(self);
3781 self.instruction(I64Const(ty.page_size_log2.into()));
3782 self.instruction(I64Shl);
3783
3784 self.instruction(LocalGet(addr.idx));
3789 extend_to_64(self);
3790 self.alloc_size(mem_opts, size);
3791 extend_to_64(self);
3792 self.instruction(I64Add);
3793 if mem_opts.memory64() {
3794 let tmp = self.local_tee_new_tmp(ValType::I64);
3795 self.instruction(LocalGet(addr.idx));
3796 self.ptr_lt_u(mem_opts);
3797 self.instruction(BrIf(0));
3798 self.instruction(LocalGet(tmp.idx));
3799 self.free_temp_local(tmp);
3800 }
3801
3802 self.instruction(I64GeU);
3806 self.instruction(BrIf(1));
3807
3808 self.instruction(End);
3809 self.trap(oob_trap);
3810 self.instruction(End);
3811 }
3812
3813 fn local_tee_new_tmp(&mut self, ty: ValType) -> TempLocal {
3819 self.gen_temp_local(ty, LocalTee)
3820 }
3821
3822 fn local_set_new_tmp(&mut self, ty: ValType) -> TempLocal {
3825 self.gen_temp_local(ty, LocalSet)
3826 }
3827
3828 fn local_get_tmp(&mut self, local: &TempLocal) {
3829 self.instruction(LocalGet(local.idx));
3830 }
3831
3832 fn gen_temp_local(&mut self, ty: ValType, insn: fn(u32) -> Instruction<'static>) -> TempLocal {
3833 if let Some(idx) = self.free_locals.get_mut(&ty).and_then(|v| v.pop()) {
3836 self.instruction(insn(idx));
3837 return TempLocal {
3838 ty,
3839 idx,
3840 needs_free: true,
3841 };
3842 }
3843
3844 let locals = &mut self.module.funcs[self.result].locals;
3846 match locals.last_mut() {
3847 Some((cnt, prev_ty)) if ty == *prev_ty => *cnt += 1,
3848 _ => locals.push((1, ty)),
3849 }
3850 self.nlocals += 1;
3851 let idx = self.nlocals - 1;
3852 self.instruction(insn(idx));
3853 TempLocal {
3854 ty,
3855 idx,
3856 needs_free: true,
3857 }
3858 }
3859
3860 fn free_temp_local(&mut self, mut local: TempLocal) {
3863 assert!(local.needs_free);
3864 self.free_locals
3865 .entry(local.ty)
3866 .or_insert(Vec::new())
3867 .push(local.idx);
3868 local.needs_free = false;
3869 }
3870
3871 fn save_context(&mut self) -> Vec<TempLocal> {
3874 if !self.module.tunables.concurrency_support {
3875 return Vec::new();
3876 }
3877 let mut saved = Vec::new();
3878 for slot in 0..NUM_COMPONENT_CONTEXT_SLOTS {
3879 let get = self.module.import_context_get(slot);
3880 self.instruction(Call(get.as_u32()));
3881 saved.push(self.local_set_new_tmp(ValType::I32));
3882 }
3883 saved
3884 }
3885
3886 fn clear_context(&mut self) {
3888 if !self.module.tunables.concurrency_support {
3889 return;
3890 }
3891 for slot in 0..NUM_COMPONENT_CONTEXT_SLOTS {
3892 let set = self.module.import_context_set(slot);
3893 self.instruction(I32Const(0));
3894 self.instruction(Call(set.as_u32()));
3895 }
3896 }
3897
3898 fn restore_context(&mut self, saved: Vec<TempLocal>) {
3901 for (slot, local) in saved.into_iter().enumerate() {
3902 let set = self.module.import_context_set(slot);
3903 self.instruction(LocalGet(local.idx));
3904 self.instruction(Call(set.as_u32()));
3905 self.free_temp_local(local);
3906 }
3907 }
3908
3909 fn call_realloc(&mut self, realloc: FuncIndex) {
3915 let saved = self.save_context();
3916 self.clear_context();
3917 self.instruction(Call(realloc.as_u32()));
3918 self.restore_context(saved);
3919 }
3920
3921 fn instruction(&mut self, instr: Instruction) {
3922 instr.encode(&mut self.code);
3923 }
3924
3925 fn trap(&mut self, trap: Trap) {
3926 let trap_func = self.module.import_trap(trap);
3927 self.instruction(Call(trap_func.as_u32()));
3928 self.instruction(Unreachable);
3929 }
3930
3931 fn enter_exception_barrier(&mut self, results: &[ValType]) {
3962 if !self.module.features.exceptions() {
3963 return;
3964 }
3965 let block_ty = match results.len() {
3966 0 => BlockType::Empty,
3967 1 => BlockType::Result(results[0]),
3968 _ => BlockType::FunctionType(self.module.core_types.function(&[], results)),
3969 };
3970 self.instruction(Block(block_ty));
3972 self.instruction(Block(BlockType::Empty));
3974 self.instruction(TryTable(block_ty, vec![Catch::All { label: 0 }].into()));
3975 }
3976
3977 fn exit_exception_barrier(&mut self) {
3982 if !self.module.features.exceptions() {
3983 return;
3984 }
3985 self.instruction(End);
3987 self.instruction(Br(1));
3989 self.instruction(End);
3991 self.trap(Trap::UncaughtException);
3992 self.instruction(End);
3994 }
3995
3996 fn push_body(&mut self, body: Body) {
3998 self.flush_code();
3999 self.module.funcs[self.result].body.push(body);
4000 }
4001
4002 fn flush_code(&mut self) {
4007 if self.code.is_empty() {
4008 return;
4009 }
4010 self.module.funcs[self.result]
4011 .body
4012 .push(Body::Raw(mem::take(&mut self.code)));
4013 }
4014
4015 fn finish(mut self) {
4016 self.instruction(End);
4019 self.flush_code();
4020
4021 self.module.funcs[self.result].filled_in = true;
4024 }
4025
4026 fn stack_get(&mut self, stack: &Stack<'_>, dst_ty: ValType) {
4034 assert_eq!(stack.locals.len(), 1);
4035 let (idx, src_ty) = stack.locals[0];
4036 self.instruction(LocalGet(idx));
4037 match (src_ty, dst_ty) {
4038 (ValType::I32, ValType::I32)
4039 | (ValType::I64, ValType::I64)
4040 | (ValType::F32, ValType::F32)
4041 | (ValType::F64, ValType::F64) => {}
4042
4043 (ValType::I32, ValType::F32) => self.instruction(F32ReinterpretI32),
4044 (ValType::I64, ValType::I32) => {
4045 self.assert_i64_upper_bits_not_set(idx);
4046 self.instruction(I32WrapI64);
4047 }
4048 (ValType::I64, ValType::F64) => self.instruction(F64ReinterpretI64),
4049 (ValType::I64, ValType::F32) => {
4050 self.assert_i64_upper_bits_not_set(idx);
4051 self.instruction(I32WrapI64);
4052 self.instruction(F32ReinterpretI32);
4053 }
4054
4055 (ValType::I32, ValType::I64)
4057 | (ValType::I32, ValType::F64)
4058 | (ValType::F32, ValType::I32)
4059 | (ValType::F32, ValType::I64)
4060 | (ValType::F32, ValType::F64)
4061 | (ValType::F64, ValType::I32)
4062 | (ValType::F64, ValType::I64)
4063 | (ValType::F64, ValType::F32)
4064
4065 | (ValType::Ref(_), _)
4067 | (_, ValType::Ref(_))
4068 | (ValType::V128, _)
4069 | (_, ValType::V128) => {
4070 panic!("cannot get {dst_ty:?} from {src_ty:?} local");
4071 }
4072 }
4073 }
4074
4075 fn assert_i64_upper_bits_not_set(&mut self, local: u32) {
4076 if !self.module.tunables.debug_adapter_modules {
4077 return;
4078 }
4079 self.instruction(LocalGet(local));
4080 self.instruction(I64Const(32));
4081 self.instruction(I64ShrU);
4082 self.instruction(I32WrapI64);
4083 self.instruction(If(BlockType::Empty));
4084 self.trap(Trap::DebugAssertUpperBitsUnset);
4085 self.instruction(End);
4086 }
4087
4088 fn stack_set(&mut self, dst_tys: &[ValType], src_ty: ValType) {
4094 assert_eq!(dst_tys.len(), 1);
4095 let dst_ty = dst_tys[0];
4096 match (src_ty, dst_ty) {
4097 (ValType::I32, ValType::I32)
4098 | (ValType::I64, ValType::I64)
4099 | (ValType::F32, ValType::F32)
4100 | (ValType::F64, ValType::F64) => {}
4101
4102 (ValType::F32, ValType::I32) => self.instruction(I32ReinterpretF32),
4103 (ValType::I32, ValType::I64) => self.instruction(I64ExtendI32U),
4104 (ValType::F64, ValType::I64) => self.instruction(I64ReinterpretF64),
4105 (ValType::F32, ValType::I64) => {
4106 self.instruction(I32ReinterpretF32);
4107 self.instruction(I64ExtendI32U);
4108 }
4109
4110 (ValType::I64, ValType::I32)
4112 | (ValType::F64, ValType::I32)
4113 | (ValType::I32, ValType::F32)
4114 | (ValType::I64, ValType::F32)
4115 | (ValType::F64, ValType::F32)
4116 | (ValType::I32, ValType::F64)
4117 | (ValType::I64, ValType::F64)
4118 | (ValType::F32, ValType::F64)
4119
4120 | (ValType::Ref(_), _)
4122 | (_, ValType::Ref(_))
4123 | (ValType::V128, _)
4124 | (_, ValType::V128) => {
4125 panic!("cannot get {dst_ty:?} from {src_ty:?} local");
4126 }
4127 }
4128 }
4129
4130 fn i32_load8u(&mut self, mem: &Memory) {
4131 self.instruction(LocalGet(mem.addr.idx));
4132 self.instruction(I32Load8U(mem.memarg(0)));
4133 }
4134
4135 fn i32_load8s(&mut self, mem: &Memory) {
4136 self.instruction(LocalGet(mem.addr.idx));
4137 self.instruction(I32Load8S(mem.memarg(0)));
4138 }
4139
4140 fn i32_load16u(&mut self, mem: &Memory) {
4141 self.instruction(LocalGet(mem.addr.idx));
4142 self.instruction(I32Load16U(mem.memarg(1)));
4143 }
4144
4145 fn i32_load16s(&mut self, mem: &Memory) {
4146 self.instruction(LocalGet(mem.addr.idx));
4147 self.instruction(I32Load16S(mem.memarg(1)));
4148 }
4149
4150 fn i32_load(&mut self, mem: &Memory) {
4151 self.instruction(LocalGet(mem.addr.idx));
4152 self.instruction(I32Load(mem.memarg(2)));
4153 }
4154
4155 fn i64_load(&mut self, mem: &Memory) {
4156 self.instruction(LocalGet(mem.addr.idx));
4157 self.instruction(I64Load(mem.memarg(3)));
4158 }
4159
4160 fn ptr_load(&mut self, mem: &Memory) {
4161 if mem.mem_opts().memory64() {
4162 self.i64_load(mem);
4163 } else {
4164 self.i32_load(mem);
4165 }
4166 }
4167
4168 fn ptr_add(&mut self, opts: &LinearMemoryOptions) {
4169 if opts.memory64() {
4170 self.instruction(I64Add);
4171 } else {
4172 self.instruction(I32Add);
4173 }
4174 }
4175
4176 fn ptr_sub(&mut self, opts: &LinearMemoryOptions) {
4177 if opts.memory64() {
4178 self.instruction(I64Sub);
4179 } else {
4180 self.instruction(I32Sub);
4181 }
4182 }
4183
4184 fn ptr_mul(&mut self, opts: &LinearMemoryOptions) {
4185 if opts.memory64() {
4186 self.instruction(I64Mul);
4187 } else {
4188 self.instruction(I32Mul);
4189 }
4190 }
4191
4192 fn ptr_gt_u(&mut self, opts: &LinearMemoryOptions) {
4193 if opts.memory64() {
4194 self.instruction(I64GtU);
4195 } else {
4196 self.instruction(I32GtU);
4197 }
4198 }
4199
4200 fn ptr_lt_u(&mut self, opts: &LinearMemoryOptions) {
4201 if opts.memory64() {
4202 self.instruction(I64LtU);
4203 } else {
4204 self.instruction(I32LtU);
4205 }
4206 }
4207
4208 fn ptr_shl(&mut self, opts: &LinearMemoryOptions) {
4209 if opts.memory64() {
4210 self.instruction(I64Shl);
4211 } else {
4212 self.instruction(I32Shl);
4213 }
4214 }
4215
4216 fn ptr_eqz(&mut self, opts: &LinearMemoryOptions) {
4217 if opts.memory64() {
4218 self.instruction(I64Eqz);
4219 } else {
4220 self.instruction(I32Eqz);
4221 }
4222 }
4223
4224 fn ptr_uconst(&mut self, opts: &LinearMemoryOptions, val: u32) {
4225 if opts.memory64() {
4226 self.instruction(I64Const(val.into()));
4227 } else {
4228 self.instruction(I32Const(val.cast_signed()));
4229 }
4230 }
4231
4232 fn ptr_iconst(&mut self, opts: &LinearMemoryOptions, val: i32) {
4233 if opts.memory64() {
4234 self.instruction(I64Const(val.into()));
4235 } else {
4236 self.instruction(I32Const(val));
4237 }
4238 }
4239
4240 fn ptr_eq(&mut self, opts: &LinearMemoryOptions) {
4241 if opts.memory64() {
4242 self.instruction(I64Eq);
4243 } else {
4244 self.instruction(I32Eq);
4245 }
4246 }
4247
4248 fn ptr_ne(&mut self, opts: &LinearMemoryOptions) {
4249 if opts.memory64() {
4250 self.instruction(I64Ne);
4251 } else {
4252 self.instruction(I32Ne);
4253 }
4254 }
4255
4256 fn ptr_and(&mut self, opts: &LinearMemoryOptions) {
4257 if opts.memory64() {
4258 self.instruction(I64And);
4259 } else {
4260 self.instruction(I32And);
4261 }
4262 }
4263
4264 fn ptr_or(&mut self, opts: &LinearMemoryOptions) {
4265 if opts.memory64() {
4266 self.instruction(I64Or);
4267 } else {
4268 self.instruction(I32Or);
4269 }
4270 }
4271
4272 fn ptr_xor(&mut self, opts: &LinearMemoryOptions) {
4273 if opts.memory64() {
4274 self.instruction(I64Xor);
4275 } else {
4276 self.instruction(I32Xor);
4277 }
4278 }
4279
4280 fn ptr_if(&mut self, opts: &LinearMemoryOptions, ty: BlockType) {
4281 if opts.memory64() {
4282 self.instruction(I64Const(0));
4283 self.instruction(I64Ne);
4284 }
4285 self.instruction(If(ty));
4286 }
4287
4288 fn ptr_br_if(&mut self, opts: &LinearMemoryOptions, depth: u32) {
4289 if opts.memory64() {
4290 self.instruction(I64Const(0));
4291 self.instruction(I64Ne);
4292 }
4293 self.instruction(BrIf(depth));
4294 }
4295
4296 fn f32_load(&mut self, mem: &Memory) {
4297 self.instruction(LocalGet(mem.addr.idx));
4298 self.instruction(F32Load(mem.memarg(2)));
4299 }
4300
4301 fn f64_load(&mut self, mem: &Memory) {
4302 self.instruction(LocalGet(mem.addr.idx));
4303 self.instruction(F64Load(mem.memarg(3)));
4304 }
4305
4306 fn push_dst_addr(&mut self, dst: &Destination) {
4307 if let Destination::Memory(mem) = dst {
4308 self.instruction(LocalGet(mem.addr.idx));
4309 }
4310 }
4311
4312 fn i32_store8(&mut self, mem: &Memory) {
4313 self.instruction(I32Store8(mem.memarg(0)));
4314 }
4315
4316 fn i32_store16(&mut self, mem: &Memory) {
4317 self.instruction(I32Store16(mem.memarg(1)));
4318 }
4319
4320 fn i32_store(&mut self, mem: &Memory) {
4321 self.instruction(I32Store(mem.memarg(2)));
4322 }
4323
4324 fn i64_store(&mut self, mem: &Memory) {
4325 self.instruction(I64Store(mem.memarg(3)));
4326 }
4327
4328 fn ptr_store(&mut self, mem: &Memory) {
4329 if mem.mem_opts().memory64() {
4330 self.i64_store(mem);
4331 } else {
4332 self.i32_store(mem);
4333 }
4334 }
4335
4336 fn f32_store(&mut self, mem: &Memory) {
4337 self.instruction(F32Store(mem.memarg(2)));
4338 }
4339
4340 fn f64_store(&mut self, mem: &Memory) {
4341 self.instruction(F64Store(mem.memarg(3)));
4342 }
4343
4344 fn alloc_size(&mut self, opts: &LinearMemoryOptions, size: &AllocSize) {
4347 match size {
4348 AllocSize::Const(size) => self.ptr_uconst(opts, *size),
4349 AllocSize::Local(idx) => self.instruction(LocalGet(*idx)),
4350 AllocSize::DoubleLocal(idx) => {
4351 self.instruction(LocalGet(*idx));
4352 self.ptr_uconst(opts, 1);
4353 self.ptr_shl(opts);
4354 }
4355 }
4356 }
4357}
4358
4359impl<'a> Source<'a> {
4360 fn record_field_srcs<'b>(
4367 &'b self,
4368 types: &'b ComponentTypesBuilder,
4369 fields: impl IntoIterator<Item = InterfaceType> + 'b,
4370 ) -> impl Iterator<Item = Source<'a>> + 'b
4371 where
4372 'a: 'b,
4373 {
4374 let mut offset = 0;
4375 fields.into_iter().map(move |ty| match self {
4376 Source::Memory(mem) => {
4377 let mem = next_field_offset(&mut offset, types, &ty, mem);
4378 Source::Memory(mem)
4379 }
4380 Source::Stack(stack) => {
4381 let cnt = types.flat_types(&ty).unwrap().len() as u32;
4382 offset += cnt;
4383 Source::Stack(stack.slice((offset - cnt) as usize..offset as usize))
4384 }
4385 Source::Struct(_) => todo!(),
4386 Source::Array(_) => todo!(),
4387 })
4388 }
4389
4390 fn payload_src(
4392 &self,
4393 types: &ComponentTypesBuilder,
4394 info: &VariantInfo,
4395 case: Option<&InterfaceType>,
4396 ) -> Source<'a> {
4397 match self {
4398 Source::Stack(s) => {
4399 let flat_len = match case {
4400 Some(case) => types.flat_types(case).unwrap().len(),
4401 None => 0,
4402 };
4403 Source::Stack(s.slice(1..s.locals.len()).slice(0..flat_len))
4404 }
4405 Source::Memory(mem) => {
4406 let mem = if mem.mem_opts().memory64() {
4407 mem.bump(info.payload_offset64)
4408 } else {
4409 mem.bump(info.payload_offset32)
4410 };
4411 Source::Memory(mem)
4412 }
4413 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
4414 }
4415 }
4416
4417 fn opts(&self) -> &'a Options {
4418 match self {
4419 Source::Stack(s) => s.opts,
4420 Source::Memory(mem) => mem.opts,
4421 Source::Struct(s) => s.opts,
4422 Source::Array(a) => a.opts,
4423 }
4424 }
4425}
4426
4427impl<'a> Destination<'a> {
4428 fn record_field_dsts<'b, I>(
4430 &'b self,
4431 types: &'b ComponentTypesBuilder,
4432 fields: I,
4433 ) -> impl Iterator<Item = Destination<'b>> + use<'b, I>
4434 where
4435 'a: 'b,
4436 I: IntoIterator<Item = InterfaceType> + 'b,
4437 {
4438 let mut offset = 0;
4439 fields.into_iter().map(move |ty| match self {
4440 Destination::Memory(mem) => {
4441 let mem = next_field_offset(&mut offset, types, &ty, mem);
4442 Destination::Memory(mem)
4443 }
4444 Destination::Stack(s, opts) => {
4445 let cnt = types.flat_types(&ty).unwrap().len() as u32;
4446 offset += cnt;
4447 Destination::Stack(&s[(offset - cnt) as usize..offset as usize], opts)
4448 }
4449 Destination::Struct(_) => todo!(),
4450 Destination::Array(_) => todo!(),
4451 })
4452 }
4453
4454 fn payload_dst(
4456 &self,
4457 types: &ComponentTypesBuilder,
4458 info: &VariantInfo,
4459 case: Option<&InterfaceType>,
4460 ) -> Destination<'_> {
4461 match self {
4462 Destination::Stack(s, opts) => {
4463 let flat_len = match case {
4464 Some(case) => types.flat_types(case).unwrap().len(),
4465 None => 0,
4466 };
4467 Destination::Stack(&s[1..][..flat_len], opts)
4468 }
4469 Destination::Memory(mem) => {
4470 let mem = if mem.mem_opts().memory64() {
4471 mem.bump(info.payload_offset64)
4472 } else {
4473 mem.bump(info.payload_offset32)
4474 };
4475 Destination::Memory(mem)
4476 }
4477 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
4478 }
4479 }
4480
4481 fn opts(&self) -> &'a Options {
4482 match self {
4483 Destination::Stack(_, opts) => opts,
4484 Destination::Memory(mem) => mem.opts,
4485 Destination::Struct(s) => s.opts,
4486 Destination::Array(a) => a.opts,
4487 }
4488 }
4489}
4490
4491fn next_field_offset<'a>(
4492 offset: &mut u32,
4493 types: &ComponentTypesBuilder,
4494 field: &InterfaceType,
4495 mem: &Memory<'a>,
4496) -> Memory<'a> {
4497 let abi = types.canonical_abi(field);
4498 let offset = if mem.mem_opts().memory64() {
4499 abi.next_field64(offset)
4500 } else {
4501 abi.next_field32(offset)
4502 };
4503 mem.bump(offset)
4504}
4505
4506impl<'a> Memory<'a> {
4507 fn memarg(&self, align: u32) -> MemArg {
4508 MemArg {
4509 offset: u64::from(self.offset),
4510 align,
4511 target: MemArgTarget::Memory(self.mem_opts().memory.unwrap().0.as_u32()),
4512 ordering: None,
4513 }
4514 }
4515
4516 fn bump(&self, offset: u32) -> Memory<'a> {
4517 Memory {
4518 opts: self.opts,
4519 addr: TempLocal::new(self.addr.idx, self.addr.ty),
4520 offset: self.offset + offset,
4521 }
4522 }
4523}
4524
4525impl<'a> Stack<'a> {
4526 fn slice(&self, range: Range<usize>) -> Stack<'a> {
4527 Stack {
4528 locals: &self.locals[range],
4529 opts: self.opts,
4530 }
4531 }
4532}
4533
4534struct VariantCase<'a> {
4535 src_i: u32,
4536 src_ty: Option<&'a InterfaceType>,
4537 dst_i: u32,
4538 dst_ty: Option<&'a InterfaceType>,
4539}
4540
4541fn variant_info<'a, I>(types: &ComponentTypesBuilder, cases: I) -> VariantInfo
4542where
4543 I: IntoIterator<Item = Option<&'a InterfaceType>>,
4544 I::IntoIter: ExactSizeIterator,
4545{
4546 VariantInfo::new(
4547 cases
4548 .into_iter()
4549 .map(|ty| ty.map(|ty| types.canonical_abi(ty))),
4550 )
4551 .0
4552}
4553
4554struct SequenceLoopState {
4556 remaining: TempLocal,
4557 cur_src_ptr: TempLocal,
4558 cur_dst_ptr: TempLocal,
4559}
4560
4561struct SequenceTranslation<'a> {
4565 src_len: TempLocal,
4566 src_mem: Memory<'a>,
4567 dst_mem: Memory<'a>,
4568 src_opts: &'a Options,
4569 dst_opts: &'a Options,
4570 src_mem_opts: &'a LinearMemoryOptions,
4571 dst_mem_opts: &'a LinearMemoryOptions,
4572 loop_state: Option<SequenceLoopState>,
4573}
4574
4575enum AllocSize {
4576 Const(u32),
4577 Local(u32),
4578 DoubleLocal(u32),
4579}
4580
4581struct WasmString<'a> {
4582 ptr: TempLocal,
4583 len: TempLocal,
4584 opts: &'a Options,
4585}
4586
4587struct TempLocal {
4588 idx: u32,
4589 ty: ValType,
4590 needs_free: bool,
4591}
4592
4593impl TempLocal {
4594 fn new(idx: u32, ty: ValType) -> TempLocal {
4595 TempLocal {
4596 idx,
4597 ty,
4598 needs_free: false,
4599 }
4600 }
4601}
4602
4603impl std::ops::Drop for TempLocal {
4604 fn drop(&mut self) {
4605 if self.needs_free {
4606 panic!("temporary local not free'd");
4607 }
4608 }
4609}
4610
4611impl From<FlatType> for ValType {
4612 fn from(ty: FlatType) -> ValType {
4613 match ty {
4614 FlatType::I32 => ValType::I32,
4615 FlatType::I64 => ValType::I64,
4616 FlatType::F32 => ValType::F32,
4617 FlatType::F64 => ValType::F64,
4618 }
4619 }
4620}