1use crate::component::{
19 CanonicalAbiInfo, ComponentTypesBuilder, FLAG_MAY_ENTER, FLAG_MAY_LEAVE, FixedEncoding as FE,
20 FlatType, InterfaceType, MAX_FLAT_ASYNC_PARAMS, MAX_FLAT_PARAMS, PREPARE_ASYNC_NO_RESULT,
21 PREPARE_ASYNC_WITH_RESULT, START_FLAG_ASYNC_CALLEE, StringEncoding, Transcode,
22 TypeComponentLocalErrorContextTableIndex, TypeEnumIndex, TypeFlagsIndex, TypeFutureTableIndex,
23 TypeListIndex, TypeOptionIndex, TypeRecordIndex, TypeResourceTableIndex, TypeResultIndex,
24 TypeStreamTableIndex, TypeTupleIndex, TypeVariantIndex, VariantInfo,
25};
26use crate::fact::signature::Signature;
27use crate::fact::transcode::Transcoder;
28use crate::fact::traps::Trap;
29use crate::fact::{
30 AdapterData, Body, Function, FunctionId, Helper, HelperLocation, HelperType,
31 LinearMemoryOptions, Module, Options,
32};
33use crate::prelude::*;
34use crate::{FuncIndex, GlobalIndex};
35use cranelift_entity::Signed;
36use std::collections::HashMap;
37use std::mem;
38use std::ops::Range;
39use wasm_encoder::{BlockType, Encode, Instruction, Instruction::*, MemArg, ValType};
40use wasmtime_component_util::{DiscriminantSize, FlagsSize};
41
42use super::DataModel;
43
44const MAX_STRING_BYTE_LENGTH: u32 = 1 << 31;
45const UTF16_TAG: u32 = 1 << 31;
46
47const INITIAL_FUEL: usize = 1_000;
50
51struct Compiler<'a, 'b> {
52 types: &'a ComponentTypesBuilder,
53 module: &'b mut Module<'a>,
54 result: FunctionId,
55
56 code: Vec<u8>,
58
59 nlocals: u32,
61
62 free_locals: HashMap<ValType, Vec<u32>>,
64
65 traps: Vec<(usize, Trap)>,
69
70 fuel: usize,
79
80 emit_resource_call: bool,
85}
86
87pub(super) fn compile(module: &mut Module<'_>, adapter: &AdapterData) {
88 fn compiler<'a, 'b>(
89 module: &'b mut Module<'a>,
90 adapter: &AdapterData,
91 ) -> (Compiler<'a, 'b>, Signature, Signature) {
92 let lower_sig = module.types.signature(&adapter.lower);
93 let lift_sig = module.types.signature(&adapter.lift);
94 let ty = module
95 .core_types
96 .function(&lower_sig.params, &lower_sig.results);
97 let result = module
98 .funcs
99 .push(Function::new(Some(adapter.name.clone()), ty));
100
101 let emit_resource_call = module.types.contains_borrow_resource(&adapter.lower);
106 assert_eq!(
107 emit_resource_call,
108 module.types.contains_borrow_resource(&adapter.lift)
109 );
110
111 (
112 Compiler::new(
113 module,
114 result,
115 lower_sig.params.len() as u32,
116 emit_resource_call,
117 ),
118 lower_sig,
119 lift_sig,
120 )
121 }
122
123 let async_start_adapter = |module: &mut Module| {
129 let sig = module
130 .types
131 .async_start_signature(&adapter.lower, &adapter.lift);
132 let ty = module.core_types.function(&sig.params, &sig.results);
133 let result = module.funcs.push(Function::new(
134 Some(format!("[async-start]{}", adapter.name)),
135 ty,
136 ));
137
138 Compiler::new(module, result, sig.params.len() as u32, false)
139 .compile_async_start_adapter(adapter, &sig);
140
141 result
142 };
143
144 let async_return_adapter = |module: &mut Module| {
153 let sig = module
154 .types
155 .async_return_signature(&adapter.lower, &adapter.lift);
156 let ty = module.core_types.function(&sig.params, &sig.results);
157 let result = module.funcs.push(Function::new(
158 Some(format!("[async-return]{}", adapter.name)),
159 ty,
160 ));
161
162 Compiler::new(module, result, sig.params.len() as u32, false)
163 .compile_async_return_adapter(adapter, &sig);
164
165 result
166 };
167
168 match (adapter.lower.options.async_, adapter.lift.options.async_) {
169 (false, false) => {
170 let (compiler, lower_sig, lift_sig) = compiler(module, adapter);
173 compiler.compile_sync_to_sync_adapter(adapter, &lower_sig, &lift_sig)
174 }
175 (true, true) => {
176 let start = async_start_adapter(module);
192 let return_ = async_return_adapter(module);
193 let (compiler, lower_sig, lift_sig) = compiler(module, adapter);
194 compiler.compile_async_to_async_adapter(
195 adapter,
196 start,
197 return_,
198 i32::try_from(lift_sig.params.len()).unwrap(),
199 &lower_sig,
200 );
201 }
202 (false, true) => {
203 let start = async_start_adapter(module);
216 let return_ = async_return_adapter(module);
217 let (compiler, lower_sig, lift_sig) = compiler(module, adapter);
218 compiler.compile_sync_to_async_adapter(
219 adapter,
220 start,
221 return_,
222 i32::try_from(lift_sig.params.len()).unwrap(),
223 &lower_sig,
224 );
225 }
226 (true, false) => {
227 let lift_sig = module.types.signature(&adapter.lift);
247 let start = async_start_adapter(module);
248 let return_ = async_return_adapter(module);
249 let (compiler, lower_sig, ..) = compiler(module, adapter);
250 compiler.compile_async_to_sync_adapter(
251 adapter,
252 start,
253 return_,
254 i32::try_from(lift_sig.params.len()).unwrap(),
255 i32::try_from(lift_sig.results.len()).unwrap(),
256 &lower_sig,
257 );
258 }
259 }
260}
261
262pub(super) fn compile_helper(module: &mut Module<'_>, result: FunctionId, helper: Helper) {
269 let mut nlocals = 0;
270 let src_flat;
271 let src = match helper.src.loc {
272 HelperLocation::Stack => {
277 src_flat = module
278 .types
279 .flatten_types(&helper.src.opts, usize::MAX, [helper.src.ty])
280 .unwrap()
281 .iter()
282 .enumerate()
283 .map(|(i, ty)| (i as u32, *ty))
284 .collect::<Vec<_>>();
285 nlocals += src_flat.len() as u32;
286 Source::Stack(Stack {
287 locals: &src_flat,
288 opts: &helper.src.opts,
289 })
290 }
291 HelperLocation::Memory => {
294 nlocals += 1;
295 Source::Memory(Memory {
296 opts: &helper.src.opts,
297 addr: TempLocal::new(0, helper.src.opts.data_model.unwrap_memory().ptr()),
298 offset: 0,
299 })
300 }
301 HelperLocation::StructField | HelperLocation::ArrayElement => todo!("CM+GC"),
302 };
303 let dst_flat;
304 let dst = match helper.dst.loc {
305 HelperLocation::Stack => {
308 dst_flat = module
309 .types
310 .flatten_types(&helper.dst.opts, usize::MAX, [helper.dst.ty])
311 .unwrap();
312 Destination::Stack(&dst_flat, &helper.dst.opts)
313 }
314 HelperLocation::Memory => {
317 nlocals += 1;
318 Destination::Memory(Memory {
319 opts: &helper.dst.opts,
320 addr: TempLocal::new(
321 nlocals - 1,
322 helper.dst.opts.data_model.unwrap_memory().ptr(),
323 ),
324 offset: 0,
325 })
326 }
327 HelperLocation::StructField | HelperLocation::ArrayElement => todo!("CM+GC"),
328 };
329 let mut compiler = Compiler {
330 types: module.types,
331 module,
332 code: Vec::new(),
333 nlocals,
334 free_locals: HashMap::new(),
335 traps: Vec::new(),
336 result,
337 fuel: INITIAL_FUEL,
338 emit_resource_call: false,
341 };
342 compiler.translate(&helper.src.ty, &src, &helper.dst.ty, &dst);
343 compiler.finish();
344}
345
346enum Source<'a> {
349 Stack(Stack<'a>),
355
356 Memory(Memory<'a>),
359
360 #[allow(dead_code, reason = "CM+GC is still WIP")]
363 Struct(GcStruct<'a>),
364
365 #[allow(dead_code, reason = "CM+GC is still WIP")]
368 Array(GcArray<'a>),
369}
370
371enum Destination<'a> {
373 Stack(&'a [ValType], &'a Options),
379
380 Memory(Memory<'a>),
382
383 #[allow(dead_code, reason = "CM+GC is still WIP")]
386 Struct(GcStruct<'a>),
387
388 #[allow(dead_code, reason = "CM+GC is still WIP")]
391 Array(GcArray<'a>),
392}
393
394struct Stack<'a> {
395 locals: &'a [(u32, ValType)],
401 opts: &'a Options,
403}
404
405struct Memory<'a> {
407 opts: &'a Options,
409 addr: TempLocal,
412 offset: u32,
415}
416
417impl<'a> Memory<'a> {
418 fn mem_opts(&self) -> &'a LinearMemoryOptions {
419 self.opts.data_model.unwrap_memory()
420 }
421}
422
423struct GcStruct<'a> {
425 opts: &'a Options,
426 }
428
429struct GcArray<'a> {
431 opts: &'a Options,
432 }
434
435impl<'a, 'b> Compiler<'a, 'b> {
436 fn new(
437 module: &'b mut Module<'a>,
438 result: FunctionId,
439 nlocals: u32,
440 emit_resource_call: bool,
441 ) -> Self {
442 Self {
443 types: module.types,
444 module,
445 result,
446 code: Vec::new(),
447 nlocals,
448 free_locals: HashMap::new(),
449 traps: Vec::new(),
450 fuel: INITIAL_FUEL,
451 emit_resource_call,
452 }
453 }
454
455 fn compile_async_to_async_adapter(
465 mut self,
466 adapter: &AdapterData,
467 start: FunctionId,
468 return_: FunctionId,
469 param_count: i32,
470 lower_sig: &Signature,
471 ) {
472 let start_call =
473 self.module
474 .import_async_start_call(&adapter.name, adapter.lift.options.callback, None);
475
476 self.call_prepare(adapter, start, return_, lower_sig, false);
477
478 self.module.exports.push((
487 adapter.callee.as_u32(),
488 format!("[adapter-callee]{}", adapter.name),
489 ));
490
491 self.instruction(RefFunc(adapter.callee.as_u32()));
492 self.instruction(I32Const(param_count));
493 self.instruction(I32Const(1));
497 self.instruction(I32Const(START_FLAG_ASYNC_CALLEE));
498 self.instruction(Call(start_call.as_u32()));
499
500 self.finish()
501 }
502
503 fn call_prepare(
516 &mut self,
517 adapter: &AdapterData,
518 start: FunctionId,
519 return_: FunctionId,
520 lower_sig: &Signature,
521 prepare_sync: bool,
522 ) {
523 let prepare = self.module.import_prepare_call(
524 &adapter.name,
525 &lower_sig.params,
526 match adapter.lift.options.data_model {
527 DataModel::Gc {} => todo!("CM+GC"),
528 DataModel::LinearMemory(LinearMemoryOptions { memory, .. }) => memory,
529 },
530 );
531
532 self.flush_code();
533 self.module.funcs[self.result]
534 .body
535 .push(Body::RefFunc(start));
536 self.module.funcs[self.result]
537 .body
538 .push(Body::RefFunc(return_));
539 self.instruction(I32Const(
540 i32::try_from(adapter.lower.instance.as_u32()).unwrap(),
541 ));
542 self.instruction(I32Const(
543 i32::try_from(adapter.lift.instance.as_u32()).unwrap(),
544 ));
545 self.instruction(I32Const(
546 i32::try_from(self.types[adapter.lift.ty].results.as_u32()).unwrap(),
547 ));
548 self.instruction(I32Const(i32::from(
549 adapter.lift.options.string_encoding as u8,
550 )));
551
552 let result_types = &self.types[self.types[adapter.lower.ty].results].types;
555 if prepare_sync {
556 self.instruction(I32Const(
557 i32::try_from(
558 self.types
559 .flatten_types(
560 &adapter.lower.options,
561 usize::MAX,
562 result_types.iter().copied(),
563 )
564 .map(|v| v.len())
565 .unwrap_or(usize::try_from(i32::MAX).unwrap()),
566 )
567 .unwrap(),
568 ));
569 } else {
570 if result_types.len() > 0 {
571 self.instruction(I32Const(PREPARE_ASYNC_WITH_RESULT.signed()));
572 } else {
573 self.instruction(I32Const(PREPARE_ASYNC_NO_RESULT.signed()));
574 }
575 }
576
577 for index in 0..lower_sig.params.len() {
579 self.instruction(LocalGet(u32::try_from(index).unwrap()));
580 }
581 self.instruction(Call(prepare.as_u32()));
582 }
583
584 fn compile_sync_to_async_adapter(
594 mut self,
595 adapter: &AdapterData,
596 start: FunctionId,
597 return_: FunctionId,
598 lift_param_count: i32,
599 lower_sig: &Signature,
600 ) {
601 let start_call = self.module.import_sync_start_call(
602 &adapter.name,
603 adapter.lift.options.callback,
604 &lower_sig.results,
605 );
606
607 self.call_prepare(adapter, start, return_, lower_sig, true);
608
609 self.module.exports.push((
618 adapter.callee.as_u32(),
619 format!("[adapter-callee]{}", adapter.name),
620 ));
621
622 self.instruction(RefFunc(adapter.callee.as_u32()));
623 self.instruction(I32Const(lift_param_count));
624 self.instruction(Call(start_call.as_u32()));
625
626 self.finish()
627 }
628
629 fn compile_async_to_sync_adapter(
639 mut self,
640 adapter: &AdapterData,
641 start: FunctionId,
642 return_: FunctionId,
643 param_count: i32,
644 result_count: i32,
645 lower_sig: &Signature,
646 ) {
647 let start_call =
648 self.module
649 .import_async_start_call(&adapter.name, None, adapter.lift.post_return);
650
651 self.call_prepare(adapter, start, return_, lower_sig, false);
652
653 self.module.exports.push((
657 adapter.callee.as_u32(),
658 format!("[adapter-callee]{}", adapter.name),
659 ));
660
661 self.instruction(RefFunc(adapter.callee.as_u32()));
662 self.instruction(I32Const(param_count));
663 self.instruction(I32Const(result_count));
664 self.instruction(I32Const(0));
665 self.instruction(Call(start_call.as_u32()));
666
667 self.finish()
668 }
669
670 fn compile_async_start_adapter(mut self, adapter: &AdapterData, sig: &Signature) {
676 let param_locals = sig
677 .params
678 .iter()
679 .enumerate()
680 .map(|(i, ty)| (i as u32, *ty))
681 .collect::<Vec<_>>();
682
683 self.set_flag(adapter.lift.flags, FLAG_MAY_LEAVE, false);
684 self.translate_params(adapter, ¶m_locals);
685 self.set_flag(adapter.lift.flags, FLAG_MAY_LEAVE, true);
686
687 self.finish();
688 }
689
690 fn compile_async_return_adapter(mut self, adapter: &AdapterData, sig: &Signature) {
699 let param_locals = sig
700 .params
701 .iter()
702 .enumerate()
703 .map(|(i, ty)| (i as u32, *ty))
704 .collect::<Vec<_>>();
705
706 self.set_flag(adapter.lower.flags, FLAG_MAY_LEAVE, false);
707 self.translate_results(adapter, ¶m_locals, ¶m_locals);
718 self.set_flag(adapter.lower.flags, FLAG_MAY_LEAVE, true);
719
720 self.finish()
721 }
722
723 fn compile_sync_to_sync_adapter(
730 mut self,
731 adapter: &AdapterData,
732 lower_sig: &Signature,
733 lift_sig: &Signature,
734 ) {
735 self.trap_if_not_flag(adapter.lower.flags, FLAG_MAY_LEAVE, Trap::CannotLeave);
741 if adapter.called_as_export {
742 self.trap_if_not_flag(adapter.lift.flags, FLAG_MAY_ENTER, Trap::CannotEnter);
743 self.set_flag(adapter.lift.flags, FLAG_MAY_ENTER, false);
744 } else if self.module.debug {
745 self.assert_not_flag(
746 adapter.lift.flags,
747 FLAG_MAY_ENTER,
748 "may_enter should be unset",
749 );
750 }
751
752 if self.emit_resource_call {
753 let enter = self.module.import_resource_enter_call();
754 self.instruction(Call(enter.as_u32()));
755 }
756
757 self.set_flag(adapter.lift.flags, FLAG_MAY_LEAVE, false);
770 let param_locals = lower_sig
771 .params
772 .iter()
773 .enumerate()
774 .map(|(i, ty)| (i as u32, *ty))
775 .collect::<Vec<_>>();
776 self.translate_params(adapter, ¶m_locals);
777 self.set_flag(adapter.lift.flags, FLAG_MAY_LEAVE, true);
778
779 self.instruction(Call(adapter.callee.as_u32()));
783 let mut result_locals = Vec::with_capacity(lift_sig.results.len());
784 let mut temps = Vec::new();
785 for ty in lift_sig.results.iter().rev() {
786 let local = self.local_set_new_tmp(*ty);
787 result_locals.push((local.idx, *ty));
788 temps.push(local);
789 }
790 result_locals.reverse();
791
792 self.set_flag(adapter.lower.flags, FLAG_MAY_LEAVE, false);
801 self.translate_results(adapter, ¶m_locals, &result_locals);
802 self.set_flag(adapter.lower.flags, FLAG_MAY_LEAVE, true);
803
804 if let Some(func) = adapter.lift.post_return {
807 for (result, _) in result_locals.iter() {
808 self.instruction(LocalGet(*result));
809 }
810 self.instruction(Call(func.as_u32()));
811 }
812 if adapter.called_as_export {
813 self.set_flag(adapter.lift.flags, FLAG_MAY_ENTER, true);
814 }
815
816 for tmp in temps {
817 self.free_temp_local(tmp);
818 }
819
820 if self.emit_resource_call {
821 let exit = self.module.import_resource_exit_call();
822 self.instruction(Call(exit.as_u32()));
823 }
824
825 self.finish()
826 }
827
828 fn translate_params(&mut self, adapter: &AdapterData, param_locals: &[(u32, ValType)]) {
829 let src_tys = self.types[adapter.lower.ty].params;
830 let src_tys = self.types[src_tys]
831 .types
832 .iter()
833 .copied()
834 .collect::<Vec<_>>();
835 let dst_tys = self.types[adapter.lift.ty].params;
836 let dst_tys = self.types[dst_tys]
837 .types
838 .iter()
839 .copied()
840 .collect::<Vec<_>>();
841 let lift_opts = &adapter.lift.options;
842 let lower_opts = &adapter.lower.options;
843
844 assert_eq!(src_tys.len(), dst_tys.len());
846
847 let max_flat_params = if adapter.lower.options.async_ {
851 MAX_FLAT_ASYNC_PARAMS
852 } else {
853 MAX_FLAT_PARAMS
854 };
855 let src_flat =
856 self.types
857 .flatten_types(lower_opts, max_flat_params, src_tys.iter().copied());
858 let dst_flat =
859 self.types
860 .flatten_types(lift_opts, MAX_FLAT_PARAMS, dst_tys.iter().copied());
861
862 let src = if let Some(flat) = &src_flat {
863 Source::Stack(Stack {
864 locals: ¶m_locals[..flat.len()],
865 opts: lower_opts,
866 })
867 } else {
868 let lower_mem_opts = lower_opts.data_model.unwrap_memory();
872 let (addr, ty) = param_locals[0];
873 assert_eq!(ty, lower_mem_opts.ptr());
874 let align = src_tys
875 .iter()
876 .map(|t| self.types.align(lower_mem_opts, t))
877 .max()
878 .unwrap_or(1);
879 Source::Memory(self.memory_operand(lower_opts, TempLocal::new(addr, ty), align))
880 };
881
882 let dst = if let Some(flat) = &dst_flat {
883 Destination::Stack(flat, lift_opts)
884 } else {
885 let abi = CanonicalAbiInfo::record(dst_tys.iter().map(|t| self.types.canonical_abi(t)));
886 match lift_opts.data_model {
887 DataModel::Gc {} => todo!("CM+GC"),
888 DataModel::LinearMemory(LinearMemoryOptions { memory64, .. }) => {
889 let (size, align) = if memory64 {
890 (abi.size64, abi.align64)
891 } else {
892 (abi.size32, abi.align32)
893 };
894
895 let size = MallocSize::Const(size);
898 Destination::Memory(self.malloc(lift_opts, size, align))
899 }
900 }
901 };
902
903 let srcs = src
904 .record_field_srcs(self.types, src_tys.iter().copied())
905 .zip(src_tys.iter());
906 let dsts = dst
907 .record_field_dsts(self.types, dst_tys.iter().copied())
908 .zip(dst_tys.iter());
909 for ((src, src_ty), (dst, dst_ty)) in srcs.zip(dsts) {
910 self.translate(&src_ty, &src, &dst_ty, &dst);
911 }
912
913 if let Destination::Memory(mem) = dst {
917 self.instruction(LocalGet(mem.addr.idx));
918 self.free_temp_local(mem.addr);
919 }
920 }
921
922 fn translate_results(
923 &mut self,
924 adapter: &AdapterData,
925 param_locals: &[(u32, ValType)],
926 result_locals: &[(u32, ValType)],
927 ) {
928 let src_tys = self.types[adapter.lift.ty].results;
929 let src_tys = self.types[src_tys]
930 .types
931 .iter()
932 .copied()
933 .collect::<Vec<_>>();
934 let dst_tys = self.types[adapter.lower.ty].results;
935 let dst_tys = self.types[dst_tys]
936 .types
937 .iter()
938 .copied()
939 .collect::<Vec<_>>();
940 let lift_opts = &adapter.lift.options;
941 let lower_opts = &adapter.lower.options;
942
943 let src_flat = self
944 .types
945 .flatten_lifting_types(lift_opts, src_tys.iter().copied());
946 let dst_flat = self
947 .types
948 .flatten_lowering_types(lower_opts, dst_tys.iter().copied());
949
950 let src = if src_flat.is_some() {
951 Source::Stack(Stack {
952 locals: result_locals,
953 opts: lift_opts,
954 })
955 } else {
956 let lift_mem_opts = lift_opts.data_model.unwrap_memory();
961 let align = src_tys
962 .iter()
963 .map(|t| self.types.align(lift_mem_opts, t))
964 .max()
965 .unwrap_or(1);
966 assert_eq!(
967 result_locals.len(),
968 if lower_opts.async_ || lift_opts.async_ {
969 2
970 } else {
971 1
972 }
973 );
974 let (addr, ty) = result_locals[0];
975 assert_eq!(ty, lift_opts.data_model.unwrap_memory().ptr());
976 Source::Memory(self.memory_operand(lift_opts, TempLocal::new(addr, ty), align))
977 };
978
979 let dst = if let Some(flat) = &dst_flat {
980 Destination::Stack(flat, lower_opts)
981 } else {
982 let lower_mem_opts = lower_opts.data_model.unwrap_memory();
986 let align = dst_tys
987 .iter()
988 .map(|t| self.types.align(lower_mem_opts, t))
989 .max()
990 .unwrap_or(1);
991 let (addr, ty) = *param_locals.last().expect("no retptr");
992 assert_eq!(ty, lower_opts.data_model.unwrap_memory().ptr());
993 Destination::Memory(self.memory_operand(lower_opts, TempLocal::new(addr, ty), align))
994 };
995
996 let srcs = src
997 .record_field_srcs(self.types, src_tys.iter().copied())
998 .zip(src_tys.iter());
999 let dsts = dst
1000 .record_field_dsts(self.types, dst_tys.iter().copied())
1001 .zip(dst_tys.iter());
1002 for ((src, src_ty), (dst, dst_ty)) in srcs.zip(dsts) {
1003 self.translate(&src_ty, &src, &dst_ty, &dst);
1004 }
1005 }
1006
1007 fn translate(
1008 &mut self,
1009 src_ty: &InterfaceType,
1010 src: &Source<'_>,
1011 dst_ty: &InterfaceType,
1012 dst: &Destination,
1013 ) {
1014 if let Source::Memory(mem) = src {
1015 self.assert_aligned(src_ty, mem);
1016 }
1017 if let Destination::Memory(mem) = dst {
1018 self.assert_aligned(dst_ty, mem);
1019 }
1020
1021 let cost = match src_ty {
1051 InterfaceType::Bool
1055 | InterfaceType::U8
1056 | InterfaceType::S8
1057 | InterfaceType::U16
1058 | InterfaceType::S16
1059 | InterfaceType::U32
1060 | InterfaceType::S32
1061 | InterfaceType::U64
1062 | InterfaceType::S64
1063 | InterfaceType::Float32
1064 | InterfaceType::Float64 => 0,
1065
1066 InterfaceType::Char => 1,
1069
1070 InterfaceType::String => 40,
1073
1074 InterfaceType::List(_) => 40,
1077
1078 InterfaceType::Flags(i) => {
1079 let count = self.module.types[*i].names.len();
1080 match FlagsSize::from_count(count) {
1081 FlagsSize::Size0 => 0,
1082 FlagsSize::Size1 | FlagsSize::Size2 => 1,
1083 FlagsSize::Size4Plus(n) => n.into(),
1084 }
1085 }
1086
1087 InterfaceType::Record(i) => self.types[*i].fields.len(),
1088 InterfaceType::Tuple(i) => self.types[*i].types.len(),
1089 InterfaceType::Variant(i) => self.types[*i].cases.len(),
1090 InterfaceType::Enum(i) => self.types[*i].names.len(),
1091
1092 InterfaceType::Option(_) | InterfaceType::Result(_) => 2,
1094
1095 InterfaceType::Own(_)
1097 | InterfaceType::Borrow(_)
1098 | InterfaceType::Future(_)
1099 | InterfaceType::Stream(_)
1100 | InterfaceType::ErrorContext(_) => 1,
1101 };
1102
1103 match self.fuel.checked_sub(cost) {
1104 Some(n) => {
1110 self.fuel = n;
1111 match src_ty {
1112 InterfaceType::Bool => self.translate_bool(src, dst_ty, dst),
1113 InterfaceType::U8 => self.translate_u8(src, dst_ty, dst),
1114 InterfaceType::S8 => self.translate_s8(src, dst_ty, dst),
1115 InterfaceType::U16 => self.translate_u16(src, dst_ty, dst),
1116 InterfaceType::S16 => self.translate_s16(src, dst_ty, dst),
1117 InterfaceType::U32 => self.translate_u32(src, dst_ty, dst),
1118 InterfaceType::S32 => self.translate_s32(src, dst_ty, dst),
1119 InterfaceType::U64 => self.translate_u64(src, dst_ty, dst),
1120 InterfaceType::S64 => self.translate_s64(src, dst_ty, dst),
1121 InterfaceType::Float32 => self.translate_f32(src, dst_ty, dst),
1122 InterfaceType::Float64 => self.translate_f64(src, dst_ty, dst),
1123 InterfaceType::Char => self.translate_char(src, dst_ty, dst),
1124 InterfaceType::String => self.translate_string(src, dst_ty, dst),
1125 InterfaceType::List(t) => self.translate_list(*t, src, dst_ty, dst),
1126 InterfaceType::Record(t) => self.translate_record(*t, src, dst_ty, dst),
1127 InterfaceType::Flags(f) => self.translate_flags(*f, src, dst_ty, dst),
1128 InterfaceType::Tuple(t) => self.translate_tuple(*t, src, dst_ty, dst),
1129 InterfaceType::Variant(v) => self.translate_variant(*v, src, dst_ty, dst),
1130 InterfaceType::Enum(t) => self.translate_enum(*t, src, dst_ty, dst),
1131 InterfaceType::Option(t) => self.translate_option(*t, src, dst_ty, dst),
1132 InterfaceType::Result(t) => self.translate_result(*t, src, dst_ty, dst),
1133 InterfaceType::Own(t) => self.translate_own(*t, src, dst_ty, dst),
1134 InterfaceType::Borrow(t) => self.translate_borrow(*t, src, dst_ty, dst),
1135 InterfaceType::Future(t) => self.translate_future(*t, src, dst_ty, dst),
1136 InterfaceType::Stream(t) => self.translate_stream(*t, src, dst_ty, dst),
1137 InterfaceType::ErrorContext(t) => {
1138 self.translate_error_context(*t, src, dst_ty, dst)
1139 }
1140 }
1141 }
1142
1143 None => {
1149 let src_loc = match src {
1150 Source::Stack(stack) => {
1154 for (i, ty) in stack
1155 .opts
1156 .flat_types(src_ty, self.types)
1157 .unwrap()
1158 .iter()
1159 .enumerate()
1160 {
1161 let stack = stack.slice(i..i + 1);
1162 self.stack_get(&stack, (*ty).into());
1163 }
1164 HelperLocation::Stack
1165 }
1166 Source::Memory(mem) => {
1171 self.push_mem_addr(mem);
1172 HelperLocation::Memory
1173 }
1174 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1175 };
1176 let dst_loc = match dst {
1177 Destination::Stack(..) => HelperLocation::Stack,
1178 Destination::Memory(mem) => {
1179 self.push_mem_addr(mem);
1180 HelperLocation::Memory
1181 }
1182 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1183 };
1184 let helper = self.module.translate_helper(Helper {
1190 src: HelperType {
1191 ty: *src_ty,
1192 opts: *src.opts(),
1193 loc: src_loc,
1194 },
1195 dst: HelperType {
1196 ty: *dst_ty,
1197 opts: *dst.opts(),
1198 loc: dst_loc,
1199 },
1200 });
1201 self.flush_code();
1204 self.module.funcs[self.result].body.push(Body::Call(helper));
1205
1206 if let Destination::Stack(tys, opts) = dst {
1215 let flat = self
1216 .types
1217 .flatten_types(opts, usize::MAX, [*dst_ty])
1218 .unwrap();
1219 assert_eq!(flat.len(), tys.len());
1220 let locals = flat
1221 .iter()
1222 .rev()
1223 .map(|ty| self.local_set_new_tmp(*ty))
1224 .collect::<Vec<_>>();
1225 for (ty, local) in tys.iter().zip(locals.into_iter().rev()) {
1226 self.instruction(LocalGet(local.idx));
1227 self.stack_set(std::slice::from_ref(ty), local.ty);
1228 self.free_temp_local(local);
1229 }
1230 }
1231 }
1232 }
1233 }
1234
1235 fn push_mem_addr(&mut self, mem: &Memory<'_>) {
1236 self.instruction(LocalGet(mem.addr.idx));
1237 if mem.offset != 0 {
1238 self.ptr_uconst(mem.mem_opts(), mem.offset);
1239 self.ptr_add(mem.mem_opts());
1240 }
1241 }
1242
1243 fn translate_bool(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1244 assert!(matches!(dst_ty, InterfaceType::Bool));
1246 self.push_dst_addr(dst);
1247
1248 self.instruction(I32Const(1));
1251 self.instruction(I32Const(0));
1252 match src {
1253 Source::Memory(mem) => self.i32_load8u(mem),
1254 Source::Stack(stack) => self.stack_get(stack, ValType::I32),
1255 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1256 }
1257 self.instruction(Select);
1258
1259 match dst {
1260 Destination::Memory(mem) => self.i32_store8(mem),
1261 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1262 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1263 }
1264 }
1265
1266 fn translate_u8(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1267 assert!(matches!(dst_ty, InterfaceType::U8));
1269 self.convert_u8_mask(src, dst, 0xff);
1270 }
1271
1272 fn convert_u8_mask(&mut self, src: &Source<'_>, dst: &Destination<'_>, mask: u8) {
1273 self.push_dst_addr(dst);
1274 let mut needs_mask = true;
1275 match src {
1276 Source::Memory(mem) => {
1277 self.i32_load8u(mem);
1278 needs_mask = mask != 0xff;
1279 }
1280 Source::Stack(stack) => {
1281 self.stack_get(stack, ValType::I32);
1282 }
1283 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1284 }
1285 if needs_mask {
1286 self.instruction(I32Const(i32::from(mask)));
1287 self.instruction(I32And);
1288 }
1289 match dst {
1290 Destination::Memory(mem) => self.i32_store8(mem),
1291 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1292 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1293 }
1294 }
1295
1296 fn translate_s8(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1297 assert!(matches!(dst_ty, InterfaceType::S8));
1299 self.push_dst_addr(dst);
1300 match src {
1301 Source::Memory(mem) => self.i32_load8s(mem),
1302 Source::Stack(stack) => {
1303 self.stack_get(stack, ValType::I32);
1304 self.instruction(I32Extend8S);
1305 }
1306 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1307 }
1308 match dst {
1309 Destination::Memory(mem) => self.i32_store8(mem),
1310 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1311 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1312 }
1313 }
1314
1315 fn translate_u16(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1316 assert!(matches!(dst_ty, InterfaceType::U16));
1318 self.convert_u16_mask(src, dst, 0xffff);
1319 }
1320
1321 fn convert_u16_mask(&mut self, src: &Source<'_>, dst: &Destination<'_>, mask: u16) {
1322 self.push_dst_addr(dst);
1323 let mut needs_mask = true;
1324 match src {
1325 Source::Memory(mem) => {
1326 self.i32_load16u(mem);
1327 needs_mask = mask != 0xffff;
1328 }
1329 Source::Stack(stack) => {
1330 self.stack_get(stack, ValType::I32);
1331 }
1332 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1333 }
1334 if needs_mask {
1335 self.instruction(I32Const(i32::from(mask)));
1336 self.instruction(I32And);
1337 }
1338 match dst {
1339 Destination::Memory(mem) => self.i32_store16(mem),
1340 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1341 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1342 }
1343 }
1344
1345 fn translate_s16(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1346 assert!(matches!(dst_ty, InterfaceType::S16));
1348 self.push_dst_addr(dst);
1349 match src {
1350 Source::Memory(mem) => self.i32_load16s(mem),
1351 Source::Stack(stack) => {
1352 self.stack_get(stack, ValType::I32);
1353 self.instruction(I32Extend16S);
1354 }
1355 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1356 }
1357 match dst {
1358 Destination::Memory(mem) => self.i32_store16(mem),
1359 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1360 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1361 }
1362 }
1363
1364 fn translate_u32(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1365 assert!(matches!(dst_ty, InterfaceType::U32));
1367 self.convert_u32_mask(src, dst, 0xffffffff)
1368 }
1369
1370 fn convert_u32_mask(&mut self, src: &Source<'_>, dst: &Destination<'_>, mask: u32) {
1371 self.push_dst_addr(dst);
1372 match src {
1373 Source::Memory(mem) => self.i32_load(mem),
1374 Source::Stack(stack) => self.stack_get(stack, ValType::I32),
1375 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1376 }
1377 if mask != 0xffffffff {
1378 self.instruction(I32Const(mask as i32));
1379 self.instruction(I32And);
1380 }
1381 match dst {
1382 Destination::Memory(mem) => self.i32_store(mem),
1383 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1384 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1385 }
1386 }
1387
1388 fn translate_s32(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1389 assert!(matches!(dst_ty, InterfaceType::S32));
1391 self.push_dst_addr(dst);
1392 match src {
1393 Source::Memory(mem) => self.i32_load(mem),
1394 Source::Stack(stack) => self.stack_get(stack, ValType::I32),
1395 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1396 }
1397 match dst {
1398 Destination::Memory(mem) => self.i32_store(mem),
1399 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1400 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1401 }
1402 }
1403
1404 fn translate_u64(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1405 assert!(matches!(dst_ty, InterfaceType::U64));
1407 self.push_dst_addr(dst);
1408 match src {
1409 Source::Memory(mem) => self.i64_load(mem),
1410 Source::Stack(stack) => self.stack_get(stack, ValType::I64),
1411 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1412 }
1413 match dst {
1414 Destination::Memory(mem) => self.i64_store(mem),
1415 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I64),
1416 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1417 }
1418 }
1419
1420 fn translate_s64(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1421 assert!(matches!(dst_ty, InterfaceType::S64));
1423 self.push_dst_addr(dst);
1424 match src {
1425 Source::Memory(mem) => self.i64_load(mem),
1426 Source::Stack(stack) => self.stack_get(stack, ValType::I64),
1427 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1428 }
1429 match dst {
1430 Destination::Memory(mem) => self.i64_store(mem),
1431 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I64),
1432 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1433 }
1434 }
1435
1436 fn translate_f32(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1437 assert!(matches!(dst_ty, InterfaceType::Float32));
1439 self.push_dst_addr(dst);
1440 match src {
1441 Source::Memory(mem) => self.f32_load(mem),
1442 Source::Stack(stack) => self.stack_get(stack, ValType::F32),
1443 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1444 }
1445 match dst {
1446 Destination::Memory(mem) => self.f32_store(mem),
1447 Destination::Stack(stack, _) => self.stack_set(stack, ValType::F32),
1448 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1449 }
1450 }
1451
1452 fn translate_f64(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1453 assert!(matches!(dst_ty, InterfaceType::Float64));
1455 self.push_dst_addr(dst);
1456 match src {
1457 Source::Memory(mem) => self.f64_load(mem),
1458 Source::Stack(stack) => self.stack_get(stack, ValType::F64),
1459 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1460 }
1461 match dst {
1462 Destination::Memory(mem) => self.f64_store(mem),
1463 Destination::Stack(stack, _) => self.stack_set(stack, ValType::F64),
1464 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1465 }
1466 }
1467
1468 fn translate_char(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1469 assert!(matches!(dst_ty, InterfaceType::Char));
1470 match src {
1471 Source::Memory(mem) => self.i32_load(mem),
1472 Source::Stack(stack) => self.stack_get(stack, ValType::I32),
1473 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1474 }
1475 let local = self.local_set_new_tmp(ValType::I32);
1476
1477 self.instruction(Block(BlockType::Empty));
1493 self.instruction(Block(BlockType::Empty));
1494 self.instruction(LocalGet(local.idx));
1495 self.instruction(I32Const(0xd800));
1496 self.instruction(I32Xor);
1497 self.instruction(I32Const(-0x110000));
1498 self.instruction(I32Add);
1499 self.instruction(I32Const(-0x10f800));
1500 self.instruction(I32LtU);
1501 self.instruction(BrIf(0));
1502 self.instruction(LocalGet(local.idx));
1503 self.instruction(I32Const(0x110000));
1504 self.instruction(I32Ne);
1505 self.instruction(BrIf(1));
1506 self.instruction(End);
1507 self.trap(Trap::InvalidChar);
1508 self.instruction(End);
1509
1510 self.push_dst_addr(dst);
1511 self.instruction(LocalGet(local.idx));
1512 match dst {
1513 Destination::Memory(mem) => {
1514 self.i32_store(mem);
1515 }
1516 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
1517 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1518 }
1519
1520 self.free_temp_local(local);
1521 }
1522
1523 fn translate_string(&mut self, src: &Source<'_>, dst_ty: &InterfaceType, dst: &Destination) {
1524 assert!(matches!(dst_ty, InterfaceType::String));
1525 let src_opts = src.opts();
1526 let dst_opts = dst.opts();
1527
1528 let src_mem_opts = match &src_opts.data_model {
1529 DataModel::Gc {} => todo!("CM+GC"),
1530 DataModel::LinearMemory(opts) => opts,
1531 };
1532 let dst_mem_opts = match &dst_opts.data_model {
1533 DataModel::Gc {} => todo!("CM+GC"),
1534 DataModel::LinearMemory(opts) => opts,
1535 };
1536
1537 match src {
1542 Source::Stack(s) => {
1543 assert_eq!(s.locals.len(), 2);
1544 self.stack_get(&s.slice(0..1), src_mem_opts.ptr());
1545 self.stack_get(&s.slice(1..2), src_mem_opts.ptr());
1546 }
1547 Source::Memory(mem) => {
1548 self.ptr_load(mem);
1549 self.ptr_load(&mem.bump(src_mem_opts.ptr_size().into()));
1550 }
1551 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
1552 }
1553 let src_len = self.local_set_new_tmp(src_mem_opts.ptr());
1554 let src_ptr = self.local_set_new_tmp(src_mem_opts.ptr());
1555 let src_str = WasmString {
1556 ptr: src_ptr,
1557 len: src_len,
1558 opts: src_opts,
1559 };
1560
1561 let dst_str = match src_opts.string_encoding {
1562 StringEncoding::Utf8 => match dst_opts.string_encoding {
1563 StringEncoding::Utf8 => self.string_copy(&src_str, FE::Utf8, dst_opts, FE::Utf8),
1564 StringEncoding::Utf16 => self.string_utf8_to_utf16(&src_str, dst_opts),
1565 StringEncoding::CompactUtf16 => {
1566 self.string_to_compact(&src_str, FE::Utf8, dst_opts)
1567 }
1568 },
1569
1570 StringEncoding::Utf16 => {
1571 self.verify_aligned(src_mem_opts, src_str.ptr.idx, 2);
1572 match dst_opts.string_encoding {
1573 StringEncoding::Utf8 => {
1574 self.string_deflate_to_utf8(&src_str, FE::Utf16, dst_opts)
1575 }
1576 StringEncoding::Utf16 => {
1577 self.string_copy(&src_str, FE::Utf16, dst_opts, FE::Utf16)
1578 }
1579 StringEncoding::CompactUtf16 => {
1580 self.string_to_compact(&src_str, FE::Utf16, dst_opts)
1581 }
1582 }
1583 }
1584
1585 StringEncoding::CompactUtf16 => {
1586 self.verify_aligned(src_mem_opts, src_str.ptr.idx, 2);
1587
1588 self.instruction(LocalGet(src_str.len.idx));
1591 self.ptr_uconst(src_mem_opts, UTF16_TAG);
1592 self.ptr_and(src_mem_opts);
1593 self.ptr_if(src_mem_opts, BlockType::Empty);
1594
1595 self.instruction(LocalGet(src_str.len.idx));
1599 self.ptr_uconst(src_mem_opts, UTF16_TAG);
1600 self.ptr_xor(src_mem_opts);
1601 self.instruction(LocalSet(src_str.len.idx));
1602 let s1 = match dst_opts.string_encoding {
1603 StringEncoding::Utf8 => {
1604 self.string_deflate_to_utf8(&src_str, FE::Utf16, dst_opts)
1605 }
1606 StringEncoding::Utf16 => {
1607 self.string_copy(&src_str, FE::Utf16, dst_opts, FE::Utf16)
1608 }
1609 StringEncoding::CompactUtf16 => {
1610 self.string_compact_utf16_to_compact(&src_str, dst_opts)
1611 }
1612 };
1613
1614 self.instruction(Else);
1615
1616 let s2 = match dst_opts.string_encoding {
1620 StringEncoding::Utf16 => {
1621 self.string_copy(&src_str, FE::Latin1, dst_opts, FE::Utf16)
1622 }
1623 StringEncoding::Utf8 => {
1624 self.string_deflate_to_utf8(&src_str, FE::Latin1, dst_opts)
1625 }
1626 StringEncoding::CompactUtf16 => {
1627 self.string_copy(&src_str, FE::Latin1, dst_opts, FE::Latin1)
1628 }
1629 };
1630 self.instruction(LocalGet(s2.ptr.idx));
1633 self.instruction(LocalSet(s1.ptr.idx));
1634 self.instruction(LocalGet(s2.len.idx));
1635 self.instruction(LocalSet(s1.len.idx));
1636 self.instruction(End);
1637 self.free_temp_local(s2.ptr);
1638 self.free_temp_local(s2.len);
1639 s1
1640 }
1641 };
1642
1643 match dst {
1645 Destination::Stack(s, _) => {
1646 self.instruction(LocalGet(dst_str.ptr.idx));
1647 self.stack_set(&s[..1], dst_mem_opts.ptr());
1648 self.instruction(LocalGet(dst_str.len.idx));
1649 self.stack_set(&s[1..], dst_mem_opts.ptr());
1650 }
1651 Destination::Memory(mem) => {
1652 self.instruction(LocalGet(mem.addr.idx));
1653 self.instruction(LocalGet(dst_str.ptr.idx));
1654 self.ptr_store(mem);
1655 self.instruction(LocalGet(mem.addr.idx));
1656 self.instruction(LocalGet(dst_str.len.idx));
1657 self.ptr_store(&mem.bump(dst_mem_opts.ptr_size().into()));
1658 }
1659 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
1660 }
1661
1662 self.free_temp_local(src_str.ptr);
1663 self.free_temp_local(src_str.len);
1664 self.free_temp_local(dst_str.ptr);
1665 self.free_temp_local(dst_str.len);
1666 }
1667
1668 fn string_copy<'c>(
1681 &mut self,
1682 src: &WasmString<'_>,
1683 src_enc: FE,
1684 dst_opts: &'c Options,
1685 dst_enc: FE,
1686 ) -> WasmString<'c> {
1687 assert!(dst_enc.width() >= src_enc.width());
1688 self.validate_string_length(src, dst_enc);
1689
1690 let src_mem_opts = {
1691 match &src.opts.data_model {
1692 DataModel::Gc {} => todo!("CM+GC"),
1693 DataModel::LinearMemory(opts) => opts,
1694 }
1695 };
1696 let dst_mem_opts = {
1697 match &dst_opts.data_model {
1698 DataModel::Gc {} => todo!("CM+GC"),
1699 DataModel::LinearMemory(opts) => opts,
1700 }
1701 };
1702
1703 let mut src_byte_len_tmp = None;
1707 let src_byte_len = if src_enc.width() == 1 {
1708 src.len.idx
1709 } else {
1710 assert_eq!(src_enc.width(), 2);
1711 self.instruction(LocalGet(src.len.idx));
1712 self.ptr_uconst(src_mem_opts, 1);
1713 self.ptr_shl(src_mem_opts);
1714 let tmp = self.local_set_new_tmp(src.opts.data_model.unwrap_memory().ptr());
1715 let ret = tmp.idx;
1716 src_byte_len_tmp = Some(tmp);
1717 ret
1718 };
1719
1720 self.convert_src_len_to_dst(
1723 src.len.idx,
1724 src.opts.data_model.unwrap_memory().ptr(),
1725 dst_opts.data_model.unwrap_memory().ptr(),
1726 );
1727 let dst_len = self.local_tee_new_tmp(dst_opts.data_model.unwrap_memory().ptr());
1728 if dst_enc.width() > 1 {
1729 assert_eq!(dst_enc.width(), 2);
1730 self.ptr_uconst(dst_mem_opts, 1);
1731 self.ptr_shl(dst_mem_opts);
1732 }
1733 let dst_byte_len = self.local_set_new_tmp(dst_opts.data_model.unwrap_memory().ptr());
1734
1735 let dst = {
1738 let dst_mem = self.malloc(
1739 dst_opts,
1740 MallocSize::Local(dst_byte_len.idx),
1741 dst_enc.width().into(),
1742 );
1743 WasmString {
1744 ptr: dst_mem.addr,
1745 len: dst_len,
1746 opts: dst_opts,
1747 }
1748 };
1749
1750 self.validate_string_inbounds(src, src_byte_len);
1755 self.validate_string_inbounds(&dst, dst_byte_len.idx);
1756
1757 let op = if src_enc == dst_enc {
1761 Transcode::Copy(src_enc)
1762 } else {
1763 assert_eq!(src_enc, FE::Latin1);
1764 assert_eq!(dst_enc, FE::Utf16);
1765 Transcode::Latin1ToUtf16
1766 };
1767 let transcode = self.transcoder(src, &dst, op);
1768 self.instruction(LocalGet(src.ptr.idx));
1769 self.instruction(LocalGet(src.len.idx));
1770 self.instruction(LocalGet(dst.ptr.idx));
1771 self.instruction(Call(transcode.as_u32()));
1772
1773 self.free_temp_local(dst_byte_len);
1774 if let Some(tmp) = src_byte_len_tmp {
1775 self.free_temp_local(tmp);
1776 }
1777
1778 dst
1779 }
1780 fn string_deflate_to_utf8<'c>(
1793 &mut self,
1794 src: &WasmString<'_>,
1795 src_enc: FE,
1796 dst_opts: &'c Options,
1797 ) -> WasmString<'c> {
1798 let src_mem_opts = match &src.opts.data_model {
1799 DataModel::Gc {} => todo!("CM+GC"),
1800 DataModel::LinearMemory(opts) => opts,
1801 };
1802 let dst_mem_opts = match &dst_opts.data_model {
1803 DataModel::Gc {} => todo!("CM+GC"),
1804 DataModel::LinearMemory(opts) => opts,
1805 };
1806
1807 self.validate_string_length(src, src_enc);
1808
1809 self.convert_src_len_to_dst(
1813 src.len.idx,
1814 src.opts.data_model.unwrap_memory().ptr(),
1815 dst_opts.data_model.unwrap_memory().ptr(),
1816 );
1817 let dst_len = self.local_tee_new_tmp(dst_opts.data_model.unwrap_memory().ptr());
1818 let dst_byte_len = self.local_set_new_tmp(dst_opts.data_model.unwrap_memory().ptr());
1819
1820 let dst = {
1821 let dst_mem = self.malloc(dst_opts, MallocSize::Local(dst_byte_len.idx), 1);
1822 WasmString {
1823 ptr: dst_mem.addr,
1824 len: dst_len,
1825 opts: dst_opts,
1826 }
1827 };
1828
1829 let mut src_byte_len_tmp = None;
1831 let src_byte_len = match src_enc {
1832 FE::Latin1 => src.len.idx,
1833 FE::Utf16 => {
1834 self.instruction(LocalGet(src.len.idx));
1835 self.ptr_uconst(src_mem_opts, 1);
1836 self.ptr_shl(src_mem_opts);
1837 let tmp = self.local_set_new_tmp(src.opts.data_model.unwrap_memory().ptr());
1838 let ret = tmp.idx;
1839 src_byte_len_tmp = Some(tmp);
1840 ret
1841 }
1842 FE::Utf8 => unreachable!(),
1843 };
1844 self.validate_string_inbounds(src, src_byte_len);
1845 self.validate_string_inbounds(&dst, dst_byte_len.idx);
1846
1847 let op = match src_enc {
1849 FE::Latin1 => Transcode::Latin1ToUtf8,
1850 FE::Utf16 => Transcode::Utf16ToUtf8,
1851 FE::Utf8 => unreachable!(),
1852 };
1853 let transcode = self.transcoder(src, &dst, op);
1854 self.instruction(LocalGet(src.ptr.idx));
1855 self.instruction(LocalGet(src.len.idx));
1856 self.instruction(LocalGet(dst.ptr.idx));
1857 self.instruction(LocalGet(dst_byte_len.idx));
1858 self.instruction(Call(transcode.as_u32()));
1859 self.instruction(LocalSet(dst.len.idx));
1860 let src_len_tmp = self.local_set_new_tmp(src.opts.data_model.unwrap_memory().ptr());
1861
1862 self.instruction(LocalGet(src_len_tmp.idx));
1866 self.instruction(LocalGet(src.len.idx));
1867 self.ptr_ne(src_mem_opts);
1868 self.instruction(If(BlockType::Empty));
1869
1870 self.instruction(LocalGet(dst.ptr.idx)); self.instruction(LocalGet(dst_byte_len.idx)); self.ptr_uconst(dst_mem_opts, 1); let factor = match src_enc {
1877 FE::Latin1 => 2,
1878 FE::Utf16 => 3,
1879 _ => unreachable!(),
1880 };
1881 self.validate_string_length_u8(src, factor);
1882 self.convert_src_len_to_dst(
1883 src.len.idx,
1884 src.opts.data_model.unwrap_memory().ptr(),
1885 dst_opts.data_model.unwrap_memory().ptr(),
1886 );
1887 self.ptr_uconst(dst_mem_opts, factor.into());
1888 self.ptr_mul(dst_mem_opts);
1889 self.instruction(LocalTee(dst_byte_len.idx));
1890 self.instruction(Call(dst_mem_opts.realloc.unwrap().as_u32()));
1891 self.instruction(LocalSet(dst.ptr.idx));
1892
1893 self.validate_string_inbounds(&dst, dst_byte_len.idx);
1895
1896 self.instruction(LocalGet(src.ptr.idx));
1901 self.instruction(LocalGet(src_len_tmp.idx));
1902 if let FE::Utf16 = src_enc {
1903 self.ptr_uconst(src_mem_opts, 1);
1904 self.ptr_shl(src_mem_opts);
1905 }
1906 self.ptr_add(src_mem_opts);
1907 self.instruction(LocalGet(src.len.idx));
1908 self.instruction(LocalGet(src_len_tmp.idx));
1909 self.ptr_sub(src_mem_opts);
1910 self.instruction(LocalGet(dst.ptr.idx));
1911 self.instruction(LocalGet(dst.len.idx));
1912 self.ptr_add(dst_mem_opts);
1913 self.instruction(LocalGet(dst_byte_len.idx));
1914 self.instruction(LocalGet(dst.len.idx));
1915 self.ptr_sub(dst_mem_opts);
1916 self.instruction(Call(transcode.as_u32()));
1917
1918 self.instruction(LocalGet(dst.len.idx));
1922 self.ptr_add(dst_mem_opts);
1923 self.instruction(LocalSet(dst.len.idx));
1924
1925 if self.module.debug {
1928 self.instruction(LocalGet(src.len.idx));
1929 self.instruction(LocalGet(src_len_tmp.idx));
1930 self.ptr_sub(src_mem_opts);
1931 self.ptr_ne(src_mem_opts);
1932 self.instruction(If(BlockType::Empty));
1933 self.trap(Trap::AssertFailed("should have finished encoding"));
1934 self.instruction(End);
1935 } else {
1936 self.instruction(Drop);
1937 }
1938
1939 self.instruction(LocalGet(dst.len.idx));
1941 self.instruction(LocalGet(dst_byte_len.idx));
1942 self.ptr_ne(dst_mem_opts);
1943 self.instruction(If(BlockType::Empty));
1944 self.instruction(LocalGet(dst.ptr.idx)); self.instruction(LocalGet(dst_byte_len.idx)); self.ptr_uconst(dst_mem_opts, 1); self.instruction(LocalGet(dst.len.idx)); self.instruction(Call(dst_mem_opts.realloc.unwrap().as_u32()));
1949 self.instruction(LocalSet(dst.ptr.idx));
1950 self.instruction(End);
1951
1952 if self.module.debug {
1955 self.instruction(Else);
1956
1957 self.instruction(LocalGet(dst.len.idx));
1958 self.instruction(LocalGet(dst_byte_len.idx));
1959 self.ptr_ne(dst_mem_opts);
1960 self.instruction(If(BlockType::Empty));
1961 self.trap(Trap::AssertFailed("should have finished encoding"));
1962 self.instruction(End);
1963 }
1964
1965 self.instruction(End); self.free_temp_local(src_len_tmp);
1968 self.free_temp_local(dst_byte_len);
1969 if let Some(tmp) = src_byte_len_tmp {
1970 self.free_temp_local(tmp);
1971 }
1972
1973 dst
1974 }
1975
1976 fn string_utf8_to_utf16<'c>(
1991 &mut self,
1992 src: &WasmString<'_>,
1993 dst_opts: &'c Options,
1994 ) -> WasmString<'c> {
1995 let src_mem_opts = match &src.opts.data_model {
1996 DataModel::Gc {} => todo!("CM+GC"),
1997 DataModel::LinearMemory(opts) => opts,
1998 };
1999 let dst_mem_opts = match &dst_opts.data_model {
2000 DataModel::Gc {} => todo!("CM+GC"),
2001 DataModel::LinearMemory(opts) => opts,
2002 };
2003
2004 self.validate_string_length(src, FE::Utf16);
2005 self.convert_src_len_to_dst(
2006 src.len.idx,
2007 src_mem_opts.ptr(),
2008 dst_opts.data_model.unwrap_memory().ptr(),
2009 );
2010 let dst_len = self.local_tee_new_tmp(dst_opts.data_model.unwrap_memory().ptr());
2011 self.ptr_uconst(dst_mem_opts, 1);
2012 self.ptr_shl(dst_mem_opts);
2013 let dst_byte_len = self.local_set_new_tmp(dst_opts.data_model.unwrap_memory().ptr());
2014 let dst = {
2015 let dst_mem = self.malloc(dst_opts, MallocSize::Local(dst_byte_len.idx), 2);
2016 WasmString {
2017 ptr: dst_mem.addr,
2018 len: dst_len,
2019 opts: dst_opts,
2020 }
2021 };
2022
2023 self.validate_string_inbounds(src, src.len.idx);
2024 self.validate_string_inbounds(&dst, dst_byte_len.idx);
2025
2026 let transcode = self.transcoder(src, &dst, Transcode::Utf8ToUtf16);
2027 self.instruction(LocalGet(src.ptr.idx));
2028 self.instruction(LocalGet(src.len.idx));
2029 self.instruction(LocalGet(dst.ptr.idx));
2030 self.instruction(Call(transcode.as_u32()));
2031 self.instruction(LocalSet(dst.len.idx));
2032
2033 self.convert_src_len_to_dst(src.len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2041 self.instruction(LocalGet(dst.len.idx));
2042 self.ptr_ne(dst_mem_opts);
2043 self.instruction(If(BlockType::Empty));
2044 self.instruction(LocalGet(dst.ptr.idx));
2045 self.instruction(LocalGet(dst_byte_len.idx));
2046 self.ptr_uconst(dst_mem_opts, 2);
2047 self.instruction(LocalGet(dst.len.idx));
2048 self.ptr_uconst(dst_mem_opts, 1);
2049 self.ptr_shl(dst_mem_opts);
2050 self.instruction(Call(match dst.opts.data_model {
2051 DataModel::Gc {} => todo!("CM+GC"),
2052 DataModel::LinearMemory(LinearMemoryOptions { realloc, .. }) => {
2053 realloc.unwrap().as_u32()
2054 }
2055 }));
2056 self.instruction(LocalSet(dst.ptr.idx));
2057 self.instruction(End); self.free_temp_local(dst_byte_len);
2060
2061 dst
2062 }
2063
2064 fn string_compact_utf16_to_compact<'c>(
2078 &mut self,
2079 src: &WasmString<'_>,
2080 dst_opts: &'c Options,
2081 ) -> WasmString<'c> {
2082 let src_mem_opts = match &src.opts.data_model {
2083 DataModel::Gc {} => todo!("CM+GC"),
2084 DataModel::LinearMemory(opts) => opts,
2085 };
2086 let dst_mem_opts = match &dst_opts.data_model {
2087 DataModel::Gc {} => todo!("CM+GC"),
2088 DataModel::LinearMemory(opts) => opts,
2089 };
2090
2091 self.validate_string_length(src, FE::Utf16);
2092 self.convert_src_len_to_dst(src.len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2093 let dst_len = self.local_tee_new_tmp(dst_mem_opts.ptr());
2094 self.ptr_uconst(dst_mem_opts, 1);
2095 self.ptr_shl(dst_mem_opts);
2096 let dst_byte_len = self.local_set_new_tmp(dst_mem_opts.ptr());
2097 let dst = {
2098 let dst_mem = self.malloc(dst_opts, MallocSize::Local(dst_byte_len.idx), 2);
2099 WasmString {
2100 ptr: dst_mem.addr,
2101 len: dst_len,
2102 opts: dst_opts,
2103 }
2104 };
2105
2106 self.convert_src_len_to_dst(
2107 dst_byte_len.idx,
2108 dst.opts.data_model.unwrap_memory().ptr(),
2109 src_mem_opts.ptr(),
2110 );
2111 let src_byte_len = self.local_set_new_tmp(src_mem_opts.ptr());
2112
2113 self.validate_string_inbounds(src, src_byte_len.idx);
2114 self.validate_string_inbounds(&dst, dst_byte_len.idx);
2115
2116 let transcode = self.transcoder(src, &dst, Transcode::Utf16ToCompactProbablyUtf16);
2117 self.instruction(LocalGet(src.ptr.idx));
2118 self.instruction(LocalGet(src.len.idx));
2119 self.instruction(LocalGet(dst.ptr.idx));
2120 self.instruction(Call(transcode.as_u32()));
2121 self.instruction(LocalSet(dst.len.idx));
2122
2123 if self.module.debug {
2126 self.instruction(LocalGet(dst.len.idx));
2127 self.ptr_uconst(dst_mem_opts, !UTF16_TAG);
2128 self.ptr_and(dst_mem_opts);
2129 self.convert_src_len_to_dst(src.len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2130 self.ptr_ne(dst_mem_opts);
2131 self.instruction(If(BlockType::Empty));
2132 self.trap(Trap::AssertFailed("expected equal code units"));
2133 self.instruction(End);
2134 }
2135
2136 self.instruction(LocalGet(dst.len.idx));
2140 self.ptr_uconst(dst_mem_opts, UTF16_TAG);
2141 self.ptr_and(dst_mem_opts);
2142 self.ptr_br_if(dst_mem_opts, 0);
2143
2144 self.instruction(LocalGet(dst.ptr.idx)); self.instruction(LocalGet(dst_byte_len.idx)); self.ptr_uconst(dst_mem_opts, 2); self.instruction(LocalGet(dst.len.idx)); self.instruction(Call(dst_mem_opts.realloc.unwrap().as_u32()));
2150 self.instruction(LocalSet(dst.ptr.idx));
2151
2152 self.free_temp_local(dst_byte_len);
2153 self.free_temp_local(src_byte_len);
2154
2155 dst
2156 }
2157
2158 fn string_to_compact<'c>(
2165 &mut self,
2166 src: &WasmString<'_>,
2167 src_enc: FE,
2168 dst_opts: &'c Options,
2169 ) -> WasmString<'c> {
2170 let src_mem_opts = match &src.opts.data_model {
2171 DataModel::Gc {} => todo!("CM+GC"),
2172 DataModel::LinearMemory(opts) => opts,
2173 };
2174 let dst_mem_opts = match &dst_opts.data_model {
2175 DataModel::Gc {} => todo!("CM+GC"),
2176 DataModel::LinearMemory(opts) => opts,
2177 };
2178
2179 self.validate_string_length(src, src_enc);
2180 self.convert_src_len_to_dst(src.len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2181 let dst_len = self.local_tee_new_tmp(dst_mem_opts.ptr());
2182 let dst_byte_len = self.local_set_new_tmp(dst_mem_opts.ptr());
2183 let dst = {
2184 let dst_mem = self.malloc(dst_opts, MallocSize::Local(dst_byte_len.idx), 2);
2185 WasmString {
2186 ptr: dst_mem.addr,
2187 len: dst_len,
2188 opts: dst_opts,
2189 }
2190 };
2191
2192 self.validate_string_inbounds(src, src.len.idx);
2193 self.validate_string_inbounds(&dst, dst_byte_len.idx);
2194
2195 let (latin1, utf16) = match src_enc {
2199 FE::Utf8 => (Transcode::Utf8ToLatin1, Transcode::Utf8ToCompactUtf16),
2200 FE::Utf16 => (Transcode::Utf16ToLatin1, Transcode::Utf16ToCompactUtf16),
2201 FE::Latin1 => unreachable!(),
2202 };
2203 let transcode_latin1 = self.transcoder(src, &dst, latin1);
2204 let transcode_utf16 = self.transcoder(src, &dst, utf16);
2205 self.instruction(LocalGet(src.ptr.idx));
2206 self.instruction(LocalGet(src.len.idx));
2207 self.instruction(LocalGet(dst.ptr.idx));
2208 self.instruction(Call(transcode_latin1.as_u32()));
2209 self.instruction(LocalSet(dst.len.idx));
2210 let src_len_tmp = self.local_set_new_tmp(src_mem_opts.ptr());
2211
2212 self.instruction(LocalGet(src_len_tmp.idx));
2215 self.instruction(LocalGet(src.len.idx));
2216 self.ptr_eq(src_mem_opts);
2217 self.instruction(If(BlockType::Empty)); self.instruction(LocalGet(dst_byte_len.idx));
2223 self.instruction(LocalGet(dst.len.idx));
2224 self.ptr_ne(dst_mem_opts);
2225 self.instruction(If(BlockType::Empty));
2226 self.instruction(LocalGet(dst.ptr.idx)); self.instruction(LocalGet(dst_byte_len.idx)); self.ptr_uconst(dst_mem_opts, 2); self.instruction(LocalGet(dst.len.idx)); self.instruction(Call(dst_mem_opts.realloc.unwrap().as_u32()));
2231 self.instruction(LocalSet(dst.ptr.idx));
2232 self.instruction(End);
2233
2234 self.instruction(Else); if src_enc.width() == 1 {
2243 self.validate_string_length_u8(src, 2);
2244 }
2245
2246 self.instruction(LocalGet(dst.ptr.idx)); self.instruction(LocalGet(dst_byte_len.idx)); self.ptr_uconst(dst_mem_opts, 2); self.convert_src_len_to_dst(src.len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2252 self.ptr_uconst(dst_mem_opts, 1);
2253 self.ptr_shl(dst_mem_opts);
2254 self.instruction(LocalTee(dst_byte_len.idx));
2255 self.instruction(Call(dst_mem_opts.realloc.unwrap().as_u32()));
2256 self.instruction(LocalSet(dst.ptr.idx));
2257
2258 self.instruction(LocalGet(src.ptr.idx));
2262 self.instruction(LocalGet(src_len_tmp.idx));
2263 if let FE::Utf16 = src_enc {
2264 self.ptr_uconst(src_mem_opts, 1);
2265 self.ptr_shl(src_mem_opts);
2266 }
2267 self.ptr_add(src_mem_opts);
2268 self.instruction(LocalGet(src.len.idx));
2269 self.instruction(LocalGet(src_len_tmp.idx));
2270 self.ptr_sub(src_mem_opts);
2271 self.instruction(LocalGet(dst.ptr.idx));
2272 self.convert_src_len_to_dst(src.len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2273 self.instruction(LocalGet(dst.len.idx));
2274 self.instruction(Call(transcode_utf16.as_u32()));
2275 self.instruction(LocalSet(dst.len.idx));
2276
2277 self.instruction(LocalGet(dst.len.idx));
2285 self.convert_src_len_to_dst(src.len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2286 self.ptr_ne(dst_mem_opts);
2287 self.instruction(If(BlockType::Empty));
2288 self.instruction(LocalGet(dst.ptr.idx)); self.instruction(LocalGet(dst_byte_len.idx)); self.ptr_uconst(dst_mem_opts, 2); self.instruction(LocalGet(dst.len.idx));
2292 self.ptr_uconst(dst_mem_opts, 1);
2293 self.ptr_shl(dst_mem_opts);
2294 self.instruction(Call(dst_mem_opts.realloc.unwrap().as_u32()));
2295 self.instruction(LocalSet(dst.ptr.idx));
2296 self.instruction(End);
2297
2298 self.instruction(LocalGet(dst.len.idx));
2300 self.ptr_uconst(dst_mem_opts, UTF16_TAG);
2301 self.ptr_or(dst_mem_opts);
2302 self.instruction(LocalSet(dst.len.idx));
2303
2304 self.instruction(End); self.free_temp_local(src_len_tmp);
2307 self.free_temp_local(dst_byte_len);
2308
2309 dst
2310 }
2311
2312 fn validate_string_length(&mut self, src: &WasmString<'_>, dst: FE) {
2313 self.validate_string_length_u8(src, dst.width())
2314 }
2315
2316 fn validate_string_length_u8(&mut self, s: &WasmString<'_>, dst: u8) {
2317 let mem_opts = match &s.opts.data_model {
2318 DataModel::Gc {} => todo!("CM+GC"),
2319 DataModel::LinearMemory(opts) => opts,
2320 };
2321
2322 self.instruction(LocalGet(s.len.idx));
2325 let max = MAX_STRING_BYTE_LENGTH / u32::from(dst);
2326 self.ptr_uconst(mem_opts, max);
2327 self.ptr_ge_u(mem_opts);
2328 self.instruction(If(BlockType::Empty));
2329 self.trap(Trap::StringLengthTooBig);
2330 self.instruction(End);
2331 }
2332
2333 fn transcoder(
2334 &mut self,
2335 src: &WasmString<'_>,
2336 dst: &WasmString<'_>,
2337 op: Transcode,
2338 ) -> FuncIndex {
2339 match (src.opts.data_model, dst.opts.data_model) {
2340 (DataModel::Gc {}, _) | (_, DataModel::Gc {}) => {
2341 todo!("CM+GC")
2342 }
2343 (
2344 DataModel::LinearMemory(LinearMemoryOptions {
2345 memory64: src64,
2346 memory: src_mem,
2347 realloc: _,
2348 }),
2349 DataModel::LinearMemory(LinearMemoryOptions {
2350 memory64: dst64,
2351 memory: dst_mem,
2352 realloc: _,
2353 }),
2354 ) => self.module.import_transcoder(Transcoder {
2355 from_memory: src_mem.unwrap(),
2356 from_memory64: src64,
2357 to_memory: dst_mem.unwrap(),
2358 to_memory64: dst64,
2359 op,
2360 }),
2361 }
2362 }
2363
2364 fn validate_string_inbounds(&mut self, s: &WasmString<'_>, byte_len: u32) {
2365 match &s.opts.data_model {
2366 DataModel::Gc {} => todo!("CM+GC"),
2367 DataModel::LinearMemory(opts) => {
2368 self.validate_memory_inbounds(opts, s.ptr.idx, byte_len, Trap::StringLengthOverflow)
2369 }
2370 }
2371 }
2372
2373 fn validate_memory_inbounds(
2374 &mut self,
2375 opts: &LinearMemoryOptions,
2376 ptr_local: u32,
2377 byte_len_local: u32,
2378 trap: Trap,
2379 ) {
2380 let extend_to_64 = |me: &mut Self| {
2381 if !opts.memory64 {
2382 me.instruction(I64ExtendI32U);
2383 }
2384 };
2385
2386 self.instruction(Block(BlockType::Empty));
2387 self.instruction(Block(BlockType::Empty));
2388
2389 self.instruction(MemorySize(opts.memory.unwrap().as_u32()));
2394 extend_to_64(self);
2395 self.instruction(I64Const(16));
2396 self.instruction(I64Shl);
2397
2398 self.instruction(LocalGet(ptr_local));
2403 extend_to_64(self);
2404 self.instruction(LocalGet(byte_len_local));
2405 extend_to_64(self);
2406 self.instruction(I64Add);
2407 if opts.memory64 {
2408 let tmp = self.local_tee_new_tmp(ValType::I64);
2409 self.instruction(LocalGet(ptr_local));
2410 self.ptr_lt_u(opts);
2411 self.instruction(BrIf(0));
2412 self.instruction(LocalGet(tmp.idx));
2413 self.free_temp_local(tmp);
2414 }
2415
2416 self.instruction(I64GeU);
2420 self.instruction(BrIf(1));
2421
2422 self.instruction(End);
2423 self.trap(trap);
2424 self.instruction(End);
2425 }
2426
2427 fn translate_list(
2428 &mut self,
2429 src_ty: TypeListIndex,
2430 src: &Source<'_>,
2431 dst_ty: &InterfaceType,
2432 dst: &Destination,
2433 ) {
2434 let src_mem_opts = match &src.opts().data_model {
2435 DataModel::Gc {} => todo!("CM+GC"),
2436 DataModel::LinearMemory(opts) => opts,
2437 };
2438 let dst_mem_opts = match &dst.opts().data_model {
2439 DataModel::Gc {} => todo!("CM+GC"),
2440 DataModel::LinearMemory(opts) => opts,
2441 };
2442
2443 let src_element_ty = &self.types[src_ty].element;
2444 let dst_element_ty = match dst_ty {
2445 InterfaceType::List(r) => &self.types[*r].element,
2446 _ => panic!("expected a list"),
2447 };
2448 let src_opts = src.opts();
2449 let dst_opts = dst.opts();
2450 let (src_size, src_align) = self.types.size_align(src_mem_opts, src_element_ty);
2451 let (dst_size, dst_align) = self.types.size_align(dst_mem_opts, dst_element_ty);
2452
2453 match src {
2458 Source::Stack(s) => {
2459 assert_eq!(s.locals.len(), 2);
2460 self.stack_get(&s.slice(0..1), src_mem_opts.ptr());
2461 self.stack_get(&s.slice(1..2), src_mem_opts.ptr());
2462 }
2463 Source::Memory(mem) => {
2464 self.ptr_load(mem);
2465 self.ptr_load(&mem.bump(src_mem_opts.ptr_size().into()));
2466 }
2467 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
2468 }
2469 let src_len = self.local_set_new_tmp(src_mem_opts.ptr());
2470 let src_ptr = self.local_set_new_tmp(src_mem_opts.ptr());
2471
2472 let src_mem = self.memory_operand(src_opts, src_ptr, src_align);
2475
2476 let src_byte_len = self.calculate_list_byte_len(src_mem_opts, src_len.idx, src_size);
2478 let dst_byte_len = if src_size == dst_size {
2479 self.convert_src_len_to_dst(src_byte_len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2480 self.local_set_new_tmp(dst_mem_opts.ptr())
2481 } else if src_mem_opts.ptr() == dst_mem_opts.ptr() {
2482 self.calculate_list_byte_len(dst_mem_opts, src_len.idx, dst_size)
2483 } else {
2484 self.convert_src_len_to_dst(src_byte_len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2485 let tmp = self.local_set_new_tmp(dst_mem_opts.ptr());
2486 let ret = self.calculate_list_byte_len(dst_mem_opts, tmp.idx, dst_size);
2487 self.free_temp_local(tmp);
2488 ret
2489 };
2490
2491 let dst_mem = self.malloc(dst_opts, MallocSize::Local(dst_byte_len.idx), dst_align);
2496
2497 self.validate_memory_inbounds(
2500 src_mem_opts,
2501 src_mem.addr.idx,
2502 src_byte_len.idx,
2503 Trap::ListByteLengthOverflow,
2504 );
2505 self.validate_memory_inbounds(
2506 dst_mem_opts,
2507 dst_mem.addr.idx,
2508 dst_byte_len.idx,
2509 Trap::ListByteLengthOverflow,
2510 );
2511
2512 self.free_temp_local(src_byte_len);
2513 self.free_temp_local(dst_byte_len);
2514
2515 if src_size > 0 || dst_size > 0 {
2519 self.instruction(Block(BlockType::Empty));
2522
2523 self.instruction(LocalGet(src_len.idx));
2525 let remaining = self.local_tee_new_tmp(src_mem_opts.ptr());
2526 self.ptr_eqz(src_mem_opts);
2527 self.instruction(BrIf(0));
2528
2529 self.instruction(LocalGet(src_mem.addr.idx));
2531 let cur_src_ptr = self.local_set_new_tmp(src_mem_opts.ptr());
2532 self.instruction(LocalGet(dst_mem.addr.idx));
2533 let cur_dst_ptr = self.local_set_new_tmp(dst_mem_opts.ptr());
2534
2535 self.instruction(Loop(BlockType::Empty));
2536
2537 let element_src = Source::Memory(Memory {
2539 opts: src_opts,
2540 offset: 0,
2541 addr: TempLocal::new(cur_src_ptr.idx, cur_src_ptr.ty),
2542 });
2543 let element_dst = Destination::Memory(Memory {
2544 opts: dst_opts,
2545 offset: 0,
2546 addr: TempLocal::new(cur_dst_ptr.idx, cur_dst_ptr.ty),
2547 });
2548 self.translate(src_element_ty, &element_src, dst_element_ty, &element_dst);
2549
2550 if src_size > 0 {
2552 self.instruction(LocalGet(cur_src_ptr.idx));
2553 self.ptr_uconst(src_mem_opts, src_size);
2554 self.ptr_add(src_mem_opts);
2555 self.instruction(LocalSet(cur_src_ptr.idx));
2556 }
2557 if dst_size > 0 {
2558 self.instruction(LocalGet(cur_dst_ptr.idx));
2559 self.ptr_uconst(dst_mem_opts, dst_size);
2560 self.ptr_add(dst_mem_opts);
2561 self.instruction(LocalSet(cur_dst_ptr.idx));
2562 }
2563
2564 self.instruction(LocalGet(remaining.idx));
2567 self.ptr_iconst(src_mem_opts, -1);
2568 self.ptr_add(src_mem_opts);
2569 self.instruction(LocalTee(remaining.idx));
2570 self.ptr_br_if(src_mem_opts, 0);
2571 self.instruction(End); self.instruction(End); self.free_temp_local(cur_dst_ptr);
2575 self.free_temp_local(cur_src_ptr);
2576 self.free_temp_local(remaining);
2577 }
2578
2579 match dst {
2581 Destination::Stack(s, _) => {
2582 self.instruction(LocalGet(dst_mem.addr.idx));
2583 self.stack_set(&s[..1], dst_mem_opts.ptr());
2584 self.convert_src_len_to_dst(src_len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2585 self.stack_set(&s[1..], dst_mem_opts.ptr());
2586 }
2587 Destination::Memory(mem) => {
2588 self.instruction(LocalGet(mem.addr.idx));
2589 self.instruction(LocalGet(dst_mem.addr.idx));
2590 self.ptr_store(mem);
2591 self.instruction(LocalGet(mem.addr.idx));
2592 self.convert_src_len_to_dst(src_len.idx, src_mem_opts.ptr(), dst_mem_opts.ptr());
2593 self.ptr_store(&mem.bump(dst_mem_opts.ptr_size().into()));
2594 }
2595 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
2596 }
2597
2598 self.free_temp_local(src_len);
2599 self.free_temp_local(src_mem.addr);
2600 self.free_temp_local(dst_mem.addr);
2601 }
2602
2603 fn calculate_list_byte_len(
2604 &mut self,
2605 opts: &LinearMemoryOptions,
2606 len_local: u32,
2607 elt_size: u32,
2608 ) -> TempLocal {
2609 if elt_size == 0 {
2612 self.ptr_uconst(opts, 0);
2613 return self.local_set_new_tmp(opts.ptr());
2614 }
2615
2616 if elt_size == 1 {
2624 if let ValType::I64 = opts.ptr() {
2625 self.instruction(LocalGet(len_local));
2626 self.instruction(I64Const(32));
2627 self.instruction(I64ShrU);
2628 self.instruction(I32WrapI64);
2629 self.instruction(If(BlockType::Empty));
2630 self.trap(Trap::ListByteLengthOverflow);
2631 self.instruction(End);
2632 }
2633 self.instruction(LocalGet(len_local));
2634 return self.local_set_new_tmp(opts.ptr());
2635 }
2636
2637 self.instruction(Block(BlockType::Empty));
2642 self.instruction(Block(BlockType::Empty));
2643 self.instruction(LocalGet(len_local));
2644 match opts.ptr() {
2645 ValType::I32 => self.instruction(I64ExtendI32U),
2649
2650 ValType::I64 => {
2654 self.instruction(I64Const(32));
2655 self.instruction(I64ShrU);
2656 self.instruction(I32WrapI64);
2657 self.instruction(BrIf(0));
2658 self.instruction(LocalGet(len_local));
2659 }
2660
2661 _ => unreachable!(),
2662 }
2663
2664 self.instruction(I64Const(elt_size.into()));
2673 self.instruction(I64Mul);
2674 let tmp = self.local_tee_new_tmp(ValType::I64);
2675 self.instruction(I64Const(32));
2678 self.instruction(I64ShrU);
2679 self.instruction(I64Eqz);
2680 self.instruction(BrIf(1));
2681 self.instruction(End);
2682 self.trap(Trap::ListByteLengthOverflow);
2683 self.instruction(End);
2684
2685 if opts.ptr() == ValType::I64 {
2689 tmp
2690 } else {
2691 self.instruction(LocalGet(tmp.idx));
2692 self.instruction(I32WrapI64);
2693 self.free_temp_local(tmp);
2694 self.local_set_new_tmp(ValType::I32)
2695 }
2696 }
2697
2698 fn convert_src_len_to_dst(
2699 &mut self,
2700 src_len_local: u32,
2701 src_ptr_ty: ValType,
2702 dst_ptr_ty: ValType,
2703 ) {
2704 self.instruction(LocalGet(src_len_local));
2705 match (src_ptr_ty, dst_ptr_ty) {
2706 (ValType::I32, ValType::I64) => self.instruction(I64ExtendI32U),
2707 (ValType::I64, ValType::I32) => self.instruction(I32WrapI64),
2708 (src, dst) => assert_eq!(src, dst),
2709 }
2710 }
2711
2712 fn translate_record(
2713 &mut self,
2714 src_ty: TypeRecordIndex,
2715 src: &Source<'_>,
2716 dst_ty: &InterfaceType,
2717 dst: &Destination,
2718 ) {
2719 let src_ty = &self.types[src_ty];
2720 let dst_ty = match dst_ty {
2721 InterfaceType::Record(r) => &self.types[*r],
2722 _ => panic!("expected a record"),
2723 };
2724
2725 assert_eq!(src_ty.fields.len(), dst_ty.fields.len());
2727
2728 let mut src_fields = HashMap::new();
2732 for (i, src) in src
2733 .record_field_srcs(self.types, src_ty.fields.iter().map(|f| f.ty))
2734 .enumerate()
2735 {
2736 let field = &src_ty.fields[i];
2737 src_fields.insert(&field.name, (src, &field.ty));
2738 }
2739
2740 for (i, dst) in dst
2749 .record_field_dsts(self.types, dst_ty.fields.iter().map(|f| f.ty))
2750 .enumerate()
2751 {
2752 let field = &dst_ty.fields[i];
2753 let (src, src_ty) = &src_fields[&field.name];
2754 self.translate(src_ty, src, &field.ty, &dst);
2755 }
2756 }
2757
2758 fn translate_flags(
2759 &mut self,
2760 src_ty: TypeFlagsIndex,
2761 src: &Source<'_>,
2762 dst_ty: &InterfaceType,
2763 dst: &Destination,
2764 ) {
2765 let src_ty = &self.types[src_ty];
2766 let dst_ty = match dst_ty {
2767 InterfaceType::Flags(r) => &self.types[*r],
2768 _ => panic!("expected a record"),
2769 };
2770
2771 assert_eq!(src_ty.names, dst_ty.names);
2779 let cnt = src_ty.names.len();
2780 match FlagsSize::from_count(cnt) {
2781 FlagsSize::Size0 => {}
2782 FlagsSize::Size1 => {
2783 let mask = if cnt == 8 { 0xff } else { (1 << cnt) - 1 };
2784 self.convert_u8_mask(src, dst, mask);
2785 }
2786 FlagsSize::Size2 => {
2787 let mask = if cnt == 16 { 0xffff } else { (1 << cnt) - 1 };
2788 self.convert_u16_mask(src, dst, mask);
2789 }
2790 FlagsSize::Size4Plus(n) => {
2791 let srcs = src.record_field_srcs(self.types, (0..n).map(|_| InterfaceType::U32));
2792 let dsts = dst.record_field_dsts(self.types, (0..n).map(|_| InterfaceType::U32));
2793 let n = usize::from(n);
2794 for (i, (src, dst)) in srcs.zip(dsts).enumerate() {
2795 let mask = if i == n - 1 && (cnt % 32 != 0) {
2796 (1 << (cnt % 32)) - 1
2797 } else {
2798 0xffffffff
2799 };
2800 self.convert_u32_mask(&src, &dst, mask);
2801 }
2802 }
2803 }
2804 }
2805
2806 fn translate_tuple(
2807 &mut self,
2808 src_ty: TypeTupleIndex,
2809 src: &Source<'_>,
2810 dst_ty: &InterfaceType,
2811 dst: &Destination,
2812 ) {
2813 let src_ty = &self.types[src_ty];
2814 let dst_ty = match dst_ty {
2815 InterfaceType::Tuple(t) => &self.types[*t],
2816 _ => panic!("expected a tuple"),
2817 };
2818
2819 assert_eq!(src_ty.types.len(), dst_ty.types.len());
2821
2822 let srcs = src
2823 .record_field_srcs(self.types, src_ty.types.iter().copied())
2824 .zip(src_ty.types.iter());
2825 let dsts = dst
2826 .record_field_dsts(self.types, dst_ty.types.iter().copied())
2827 .zip(dst_ty.types.iter());
2828 for ((src, src_ty), (dst, dst_ty)) in srcs.zip(dsts) {
2829 self.translate(src_ty, &src, dst_ty, &dst);
2830 }
2831 }
2832
2833 fn translate_variant(
2834 &mut self,
2835 src_ty: TypeVariantIndex,
2836 src: &Source<'_>,
2837 dst_ty: &InterfaceType,
2838 dst: &Destination,
2839 ) {
2840 let src_ty = &self.types[src_ty];
2841 let dst_ty = match dst_ty {
2842 InterfaceType::Variant(t) => &self.types[*t],
2843 _ => panic!("expected a variant"),
2844 };
2845
2846 let src_info = variant_info(self.types, src_ty.cases.iter().map(|(_, c)| c.as_ref()));
2847 let dst_info = variant_info(self.types, dst_ty.cases.iter().map(|(_, c)| c.as_ref()));
2848
2849 let iter = src_ty
2850 .cases
2851 .iter()
2852 .enumerate()
2853 .map(|(src_i, (src_case, src_case_ty))| {
2854 let dst_i = dst_ty
2855 .cases
2856 .iter()
2857 .position(|(c, _)| c == src_case)
2858 .unwrap();
2859 let dst_case_ty = &dst_ty.cases[dst_i];
2860 let src_i = u32::try_from(src_i).unwrap();
2861 let dst_i = u32::try_from(dst_i).unwrap();
2862 VariantCase {
2863 src_i,
2864 src_ty: src_case_ty.as_ref(),
2865 dst_i,
2866 dst_ty: dst_case_ty.as_ref(),
2867 }
2868 });
2869 self.convert_variant(src, &src_info, dst, &dst_info, iter);
2870 }
2871
2872 fn translate_enum(
2873 &mut self,
2874 src_ty: TypeEnumIndex,
2875 src: &Source<'_>,
2876 dst_ty: &InterfaceType,
2877 dst: &Destination,
2878 ) {
2879 let src_ty = &self.types[src_ty];
2880 let dst_ty = match dst_ty {
2881 InterfaceType::Enum(t) => &self.types[*t],
2882 _ => panic!("expected an option"),
2883 };
2884
2885 debug_assert_eq!(src_ty.info.size, dst_ty.info.size);
2886 debug_assert_eq!(src_ty.names.len(), dst_ty.names.len());
2887 debug_assert!(
2888 src_ty
2889 .names
2890 .iter()
2891 .zip(dst_ty.names.iter())
2892 .all(|(a, b)| a == b)
2893 );
2894
2895 match src {
2897 Source::Stack(s) => self.stack_get(&s.slice(0..1), ValType::I32),
2898 Source::Memory(mem) => match src_ty.info.size {
2899 DiscriminantSize::Size1 => self.i32_load8u(mem),
2900 DiscriminantSize::Size2 => self.i32_load16u(mem),
2901 DiscriminantSize::Size4 => self.i32_load(mem),
2902 },
2903 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
2904 }
2905 let tmp = self.local_tee_new_tmp(ValType::I32);
2906
2907 self.instruction(I32Const(i32::try_from(src_ty.names.len()).unwrap()));
2909 self.instruction(I32GtU);
2910 self.instruction(If(BlockType::Empty));
2911 self.trap(Trap::InvalidDiscriminant);
2912 self.instruction(End);
2913
2914 match dst {
2916 Destination::Stack(stack, _) => {
2917 self.local_get_tmp(&tmp);
2918 self.stack_set(&stack[..1], ValType::I32)
2919 }
2920 Destination::Memory(mem) => {
2921 self.push_dst_addr(dst);
2922 self.local_get_tmp(&tmp);
2923 match dst_ty.info.size {
2924 DiscriminantSize::Size1 => self.i32_store8(mem),
2925 DiscriminantSize::Size2 => self.i32_store16(mem),
2926 DiscriminantSize::Size4 => self.i32_store(mem),
2927 }
2928 }
2929 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
2930 }
2931 self.free_temp_local(tmp);
2932 }
2933
2934 fn translate_option(
2935 &mut self,
2936 src_ty: TypeOptionIndex,
2937 src: &Source<'_>,
2938 dst_ty: &InterfaceType,
2939 dst: &Destination,
2940 ) {
2941 let src_ty = &self.types[src_ty].ty;
2942 let dst_ty = match dst_ty {
2943 InterfaceType::Option(t) => &self.types[*t].ty,
2944 _ => panic!("expected an option"),
2945 };
2946 let src_ty = Some(src_ty);
2947 let dst_ty = Some(dst_ty);
2948
2949 let src_info = variant_info(self.types, [None, src_ty]);
2950 let dst_info = variant_info(self.types, [None, dst_ty]);
2951
2952 self.convert_variant(
2953 src,
2954 &src_info,
2955 dst,
2956 &dst_info,
2957 [
2958 VariantCase {
2959 src_i: 0,
2960 dst_i: 0,
2961 src_ty: None,
2962 dst_ty: None,
2963 },
2964 VariantCase {
2965 src_i: 1,
2966 dst_i: 1,
2967 src_ty,
2968 dst_ty,
2969 },
2970 ]
2971 .into_iter(),
2972 );
2973 }
2974
2975 fn translate_result(
2976 &mut self,
2977 src_ty: TypeResultIndex,
2978 src: &Source<'_>,
2979 dst_ty: &InterfaceType,
2980 dst: &Destination,
2981 ) {
2982 let src_ty = &self.types[src_ty];
2983 let dst_ty = match dst_ty {
2984 InterfaceType::Result(t) => &self.types[*t],
2985 _ => panic!("expected a result"),
2986 };
2987
2988 let src_info = variant_info(self.types, [src_ty.ok.as_ref(), src_ty.err.as_ref()]);
2989 let dst_info = variant_info(self.types, [dst_ty.ok.as_ref(), dst_ty.err.as_ref()]);
2990
2991 self.convert_variant(
2992 src,
2993 &src_info,
2994 dst,
2995 &dst_info,
2996 [
2997 VariantCase {
2998 src_i: 0,
2999 dst_i: 0,
3000 src_ty: src_ty.ok.as_ref(),
3001 dst_ty: dst_ty.ok.as_ref(),
3002 },
3003 VariantCase {
3004 src_i: 1,
3005 dst_i: 1,
3006 src_ty: src_ty.err.as_ref(),
3007 dst_ty: dst_ty.err.as_ref(),
3008 },
3009 ]
3010 .into_iter(),
3011 );
3012 }
3013
3014 fn convert_variant<'c>(
3015 &mut self,
3016 src: &Source<'_>,
3017 src_info: &VariantInfo,
3018 dst: &Destination,
3019 dst_info: &VariantInfo,
3020 src_cases: impl ExactSizeIterator<Item = VariantCase<'c>>,
3021 ) {
3022 let outer_block_ty = match dst {
3025 Destination::Stack(dst_flat, _) => match dst_flat.len() {
3026 0 => BlockType::Empty,
3027 1 => BlockType::Result(dst_flat[0]),
3028 _ => {
3029 let ty = self.module.core_types.function(&[], &dst_flat);
3030 BlockType::FunctionType(ty)
3031 }
3032 },
3033 Destination::Memory(_) => BlockType::Empty,
3034 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
3035 };
3036 self.instruction(Block(outer_block_ty));
3037
3038 let src_cases_len = src_cases.len();
3041 for _ in 0..src_cases_len - 1 {
3042 self.instruction(Block(BlockType::Empty));
3043 }
3044
3045 self.instruction(Block(BlockType::Empty));
3047
3048 self.instruction(Block(BlockType::Empty));
3051
3052 match src {
3054 Source::Stack(s) => self.stack_get(&s.slice(0..1), ValType::I32),
3055 Source::Memory(mem) => match src_info.size {
3056 DiscriminantSize::Size1 => self.i32_load8u(mem),
3057 DiscriminantSize::Size2 => self.i32_load16u(mem),
3058 DiscriminantSize::Size4 => self.i32_load(mem),
3059 },
3060 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
3061 }
3062
3063 let mut targets = Vec::new();
3066 for i in 0..src_cases_len {
3067 targets.push((i + 1) as u32);
3068 }
3069 self.instruction(BrTable(targets[..].into(), 0));
3070 self.instruction(End); self.trap(Trap::InvalidDiscriminant);
3073 self.instruction(End); let src_cases_len = u32::try_from(src_cases_len).unwrap();
3080 for case in src_cases {
3081 let VariantCase {
3082 src_i,
3083 src_ty,
3084 dst_i,
3085 dst_ty,
3086 } = case;
3087
3088 self.push_dst_addr(dst);
3091 self.instruction(I32Const(dst_i as i32));
3092 match dst {
3093 Destination::Stack(stack, _) => self.stack_set(&stack[..1], ValType::I32),
3094 Destination::Memory(mem) => match dst_info.size {
3095 DiscriminantSize::Size1 => self.i32_store8(mem),
3096 DiscriminantSize::Size2 => self.i32_store16(mem),
3097 DiscriminantSize::Size4 => self.i32_store(mem),
3098 },
3099 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
3100 }
3101
3102 let src_payload = src.payload_src(self.types, src_info, src_ty);
3103 let dst_payload = dst.payload_dst(self.types, dst_info, dst_ty);
3104
3105 match (src_ty, dst_ty) {
3108 (Some(src_ty), Some(dst_ty)) => {
3109 self.translate(src_ty, &src_payload, dst_ty, &dst_payload);
3110 }
3111 (None, None) => {}
3112 _ => unimplemented!(),
3113 }
3114
3115 if let Destination::Stack(payload_results, _) = dst_payload {
3122 if let Destination::Stack(dst_results, _) = dst {
3123 let remaining = &dst_results[1..][payload_results.len()..];
3124 for ty in remaining {
3125 match ty {
3126 ValType::I32 => self.instruction(I32Const(0)),
3127 ValType::I64 => self.instruction(I64Const(0)),
3128 ValType::F32 => self.instruction(F32Const(0.0.into())),
3129 ValType::F64 => self.instruction(F64Const(0.0.into())),
3130 _ => unreachable!(),
3131 }
3132 }
3133 }
3134 }
3135
3136 if src_i != src_cases_len - 1 {
3139 self.instruction(Br(src_cases_len - src_i - 1));
3140 }
3141 self.instruction(End); }
3143 }
3144
3145 fn translate_future(
3146 &mut self,
3147 src_ty: TypeFutureTableIndex,
3148 src: &Source<'_>,
3149 dst_ty: &InterfaceType,
3150 dst: &Destination,
3151 ) {
3152 let dst_ty = match dst_ty {
3153 InterfaceType::Future(t) => *t,
3154 _ => panic!("expected a `Future`"),
3155 };
3156 let transfer = self.module.import_future_transfer();
3157 self.translate_handle(src_ty.as_u32(), src, dst_ty.as_u32(), dst, transfer);
3158 }
3159
3160 fn translate_stream(
3161 &mut self,
3162 src_ty: TypeStreamTableIndex,
3163 src: &Source<'_>,
3164 dst_ty: &InterfaceType,
3165 dst: &Destination,
3166 ) {
3167 let dst_ty = match dst_ty {
3168 InterfaceType::Stream(t) => *t,
3169 _ => panic!("expected a `Stream`"),
3170 };
3171 let transfer = self.module.import_stream_transfer();
3172 self.translate_handle(src_ty.as_u32(), src, dst_ty.as_u32(), dst, transfer);
3173 }
3174
3175 fn translate_error_context(
3176 &mut self,
3177 src_ty: TypeComponentLocalErrorContextTableIndex,
3178 src: &Source<'_>,
3179 dst_ty: &InterfaceType,
3180 dst: &Destination,
3181 ) {
3182 let dst_ty = match dst_ty {
3183 InterfaceType::ErrorContext(t) => *t,
3184 _ => panic!("expected an `ErrorContext`"),
3185 };
3186 let transfer = self.module.import_error_context_transfer();
3187 self.translate_handle(src_ty.as_u32(), src, dst_ty.as_u32(), dst, transfer);
3188 }
3189
3190 fn translate_own(
3191 &mut self,
3192 src_ty: TypeResourceTableIndex,
3193 src: &Source<'_>,
3194 dst_ty: &InterfaceType,
3195 dst: &Destination,
3196 ) {
3197 let dst_ty = match dst_ty {
3198 InterfaceType::Own(t) => *t,
3199 _ => panic!("expected an `Own`"),
3200 };
3201 let transfer = self.module.import_resource_transfer_own();
3202 self.translate_handle(src_ty.as_u32(), src, dst_ty.as_u32(), dst, transfer);
3203 }
3204
3205 fn translate_borrow(
3206 &mut self,
3207 src_ty: TypeResourceTableIndex,
3208 src: &Source<'_>,
3209 dst_ty: &InterfaceType,
3210 dst: &Destination,
3211 ) {
3212 let dst_ty = match dst_ty {
3213 InterfaceType::Borrow(t) => *t,
3214 _ => panic!("expected an `Borrow`"),
3215 };
3216
3217 let transfer = self.module.import_resource_transfer_borrow();
3218 self.translate_handle(src_ty.as_u32(), src, dst_ty.as_u32(), dst, transfer);
3219 }
3220
3221 fn translate_handle(
3229 &mut self,
3230 src_ty: u32,
3231 src: &Source<'_>,
3232 dst_ty: u32,
3233 dst: &Destination,
3234 transfer: FuncIndex,
3235 ) {
3236 self.push_dst_addr(dst);
3237 match src {
3238 Source::Memory(mem) => self.i32_load(mem),
3239 Source::Stack(stack) => self.stack_get(stack, ValType::I32),
3240 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
3241 }
3242 self.instruction(I32Const(src_ty as i32));
3243 self.instruction(I32Const(dst_ty as i32));
3244 self.instruction(Call(transfer.as_u32()));
3245 match dst {
3246 Destination::Memory(mem) => self.i32_store(mem),
3247 Destination::Stack(stack, _) => self.stack_set(stack, ValType::I32),
3248 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
3249 }
3250 }
3251
3252 fn trap_if_not_flag(&mut self, flags_global: GlobalIndex, flag_to_test: i32, trap: Trap) {
3253 self.instruction(GlobalGet(flags_global.as_u32()));
3254 self.instruction(I32Const(flag_to_test));
3255 self.instruction(I32And);
3256 self.instruction(I32Eqz);
3257 self.instruction(If(BlockType::Empty));
3258 self.trap(trap);
3259 self.instruction(End);
3260 }
3261
3262 fn assert_not_flag(&mut self, flags_global: GlobalIndex, flag_to_test: i32, msg: &'static str) {
3263 self.instruction(GlobalGet(flags_global.as_u32()));
3264 self.instruction(I32Const(flag_to_test));
3265 self.instruction(I32And);
3266 self.instruction(If(BlockType::Empty));
3267 self.trap(Trap::AssertFailed(msg));
3268 self.instruction(End);
3269 }
3270
3271 fn set_flag(&mut self, flags_global: GlobalIndex, flag_to_set: i32, value: bool) {
3272 self.instruction(GlobalGet(flags_global.as_u32()));
3273 if value {
3274 self.instruction(I32Const(flag_to_set));
3275 self.instruction(I32Or);
3276 } else {
3277 self.instruction(I32Const(!flag_to_set));
3278 self.instruction(I32And);
3279 }
3280 self.instruction(GlobalSet(flags_global.as_u32()));
3281 }
3282
3283 fn verify_aligned(&mut self, opts: &LinearMemoryOptions, addr_local: u32, align: u32) {
3284 if align == 1 {
3287 return;
3288 }
3289 self.instruction(LocalGet(addr_local));
3290 assert!(align.is_power_of_two());
3291 self.ptr_uconst(opts, align - 1);
3292 self.ptr_and(opts);
3293 self.ptr_if(opts, BlockType::Empty);
3294 self.trap(Trap::UnalignedPointer);
3295 self.instruction(End);
3296 }
3297
3298 fn assert_aligned(&mut self, ty: &InterfaceType, mem: &Memory) {
3299 let mem_opts = mem.mem_opts();
3300 if !self.module.debug {
3301 return;
3302 }
3303 let align = self.types.align(mem_opts, ty);
3304 if align == 1 {
3305 return;
3306 }
3307 assert!(align.is_power_of_two());
3308 self.instruction(LocalGet(mem.addr.idx));
3309 self.ptr_uconst(mem_opts, mem.offset);
3310 self.ptr_add(mem_opts);
3311 self.ptr_uconst(mem_opts, align - 1);
3312 self.ptr_and(mem_opts);
3313 self.ptr_if(mem_opts, BlockType::Empty);
3314 self.trap(Trap::AssertFailed("pointer not aligned"));
3315 self.instruction(End);
3316 }
3317
3318 fn malloc<'c>(&mut self, opts: &'c Options, size: MallocSize, align: u32) -> Memory<'c> {
3319 match &opts.data_model {
3320 DataModel::Gc {} => todo!("CM+GC"),
3321 DataModel::LinearMemory(mem_opts) => {
3322 let realloc = mem_opts.realloc.unwrap();
3323 self.ptr_uconst(mem_opts, 0);
3324 self.ptr_uconst(mem_opts, 0);
3325 self.ptr_uconst(mem_opts, align);
3326 match size {
3327 MallocSize::Const(size) => self.ptr_uconst(mem_opts, size),
3328 MallocSize::Local(idx) => self.instruction(LocalGet(idx)),
3329 }
3330 self.instruction(Call(realloc.as_u32()));
3331 let addr = self.local_set_new_tmp(mem_opts.ptr());
3332 self.memory_operand(opts, addr, align)
3333 }
3334 }
3335 }
3336
3337 fn memory_operand<'c>(&mut self, opts: &'c Options, addr: TempLocal, align: u32) -> Memory<'c> {
3338 let ret = Memory {
3339 addr,
3340 offset: 0,
3341 opts,
3342 };
3343 self.verify_aligned(opts.data_model.unwrap_memory(), ret.addr.idx, align);
3344 ret
3345 }
3346
3347 fn local_tee_new_tmp(&mut self, ty: ValType) -> TempLocal {
3353 self.gen_temp_local(ty, LocalTee)
3354 }
3355
3356 fn local_set_new_tmp(&mut self, ty: ValType) -> TempLocal {
3359 self.gen_temp_local(ty, LocalSet)
3360 }
3361
3362 fn local_get_tmp(&mut self, local: &TempLocal) {
3363 self.instruction(LocalGet(local.idx));
3364 }
3365
3366 fn gen_temp_local(&mut self, ty: ValType, insn: fn(u32) -> Instruction<'static>) -> TempLocal {
3367 if let Some(idx) = self.free_locals.get_mut(&ty).and_then(|v| v.pop()) {
3370 self.instruction(insn(idx));
3371 return TempLocal {
3372 ty,
3373 idx,
3374 needs_free: true,
3375 };
3376 }
3377
3378 let locals = &mut self.module.funcs[self.result].locals;
3380 match locals.last_mut() {
3381 Some((cnt, prev_ty)) if ty == *prev_ty => *cnt += 1,
3382 _ => locals.push((1, ty)),
3383 }
3384 self.nlocals += 1;
3385 let idx = self.nlocals - 1;
3386 self.instruction(insn(idx));
3387 TempLocal {
3388 ty,
3389 idx,
3390 needs_free: true,
3391 }
3392 }
3393
3394 fn free_temp_local(&mut self, mut local: TempLocal) {
3397 assert!(local.needs_free);
3398 self.free_locals
3399 .entry(local.ty)
3400 .or_insert(Vec::new())
3401 .push(local.idx);
3402 local.needs_free = false;
3403 }
3404
3405 fn instruction(&mut self, instr: Instruction) {
3406 instr.encode(&mut self.code);
3407 }
3408
3409 fn trap(&mut self, trap: Trap) {
3410 self.traps.push((self.code.len(), trap));
3411 self.instruction(Unreachable);
3412 }
3413
3414 fn flush_code(&mut self) {
3419 if self.code.is_empty() {
3420 return;
3421 }
3422 self.module.funcs[self.result].body.push(Body::Raw(
3423 mem::take(&mut self.code),
3424 mem::take(&mut self.traps),
3425 ));
3426 }
3427
3428 fn finish(mut self) {
3429 self.instruction(End);
3432 self.flush_code();
3433
3434 self.module.funcs[self.result].filled_in = true;
3437 }
3438
3439 fn stack_get(&mut self, stack: &Stack<'_>, dst_ty: ValType) {
3447 assert_eq!(stack.locals.len(), 1);
3448 let (idx, src_ty) = stack.locals[0];
3449 self.instruction(LocalGet(idx));
3450 match (src_ty, dst_ty) {
3451 (ValType::I32, ValType::I32)
3452 | (ValType::I64, ValType::I64)
3453 | (ValType::F32, ValType::F32)
3454 | (ValType::F64, ValType::F64) => {}
3455
3456 (ValType::I32, ValType::F32) => self.instruction(F32ReinterpretI32),
3457 (ValType::I64, ValType::I32) => {
3458 self.assert_i64_upper_bits_not_set(idx);
3459 self.instruction(I32WrapI64);
3460 }
3461 (ValType::I64, ValType::F64) => self.instruction(F64ReinterpretI64),
3462 (ValType::I64, ValType::F32) => {
3463 self.assert_i64_upper_bits_not_set(idx);
3464 self.instruction(I32WrapI64);
3465 self.instruction(F32ReinterpretI32);
3466 }
3467
3468 (ValType::I32, ValType::I64)
3470 | (ValType::I32, ValType::F64)
3471 | (ValType::F32, ValType::I32)
3472 | (ValType::F32, ValType::I64)
3473 | (ValType::F32, ValType::F64)
3474 | (ValType::F64, ValType::I32)
3475 | (ValType::F64, ValType::I64)
3476 | (ValType::F64, ValType::F32)
3477
3478 | (ValType::Ref(_), _)
3480 | (_, ValType::Ref(_))
3481 | (ValType::V128, _)
3482 | (_, ValType::V128) => {
3483 panic!("cannot get {dst_ty:?} from {src_ty:?} local");
3484 }
3485 }
3486 }
3487
3488 fn assert_i64_upper_bits_not_set(&mut self, local: u32) {
3489 if !self.module.debug {
3490 return;
3491 }
3492 self.instruction(LocalGet(local));
3493 self.instruction(I64Const(32));
3494 self.instruction(I64ShrU);
3495 self.instruction(I32WrapI64);
3496 self.instruction(If(BlockType::Empty));
3497 self.trap(Trap::AssertFailed("upper bits are unexpectedly set"));
3498 self.instruction(End);
3499 }
3500
3501 fn stack_set(&mut self, dst_tys: &[ValType], src_ty: ValType) {
3507 assert_eq!(dst_tys.len(), 1);
3508 let dst_ty = dst_tys[0];
3509 match (src_ty, dst_ty) {
3510 (ValType::I32, ValType::I32)
3511 | (ValType::I64, ValType::I64)
3512 | (ValType::F32, ValType::F32)
3513 | (ValType::F64, ValType::F64) => {}
3514
3515 (ValType::F32, ValType::I32) => self.instruction(I32ReinterpretF32),
3516 (ValType::I32, ValType::I64) => self.instruction(I64ExtendI32U),
3517 (ValType::F64, ValType::I64) => self.instruction(I64ReinterpretF64),
3518 (ValType::F32, ValType::I64) => {
3519 self.instruction(I32ReinterpretF32);
3520 self.instruction(I64ExtendI32U);
3521 }
3522
3523 (ValType::I64, ValType::I32)
3525 | (ValType::F64, ValType::I32)
3526 | (ValType::I32, ValType::F32)
3527 | (ValType::I64, ValType::F32)
3528 | (ValType::F64, ValType::F32)
3529 | (ValType::I32, ValType::F64)
3530 | (ValType::I64, ValType::F64)
3531 | (ValType::F32, ValType::F64)
3532
3533 | (ValType::Ref(_), _)
3535 | (_, ValType::Ref(_))
3536 | (ValType::V128, _)
3537 | (_, ValType::V128) => {
3538 panic!("cannot get {dst_ty:?} from {src_ty:?} local");
3539 }
3540 }
3541 }
3542
3543 fn i32_load8u(&mut self, mem: &Memory) {
3544 self.instruction(LocalGet(mem.addr.idx));
3545 self.instruction(I32Load8U(mem.memarg(0)));
3546 }
3547
3548 fn i32_load8s(&mut self, mem: &Memory) {
3549 self.instruction(LocalGet(mem.addr.idx));
3550 self.instruction(I32Load8S(mem.memarg(0)));
3551 }
3552
3553 fn i32_load16u(&mut self, mem: &Memory) {
3554 self.instruction(LocalGet(mem.addr.idx));
3555 self.instruction(I32Load16U(mem.memarg(1)));
3556 }
3557
3558 fn i32_load16s(&mut self, mem: &Memory) {
3559 self.instruction(LocalGet(mem.addr.idx));
3560 self.instruction(I32Load16S(mem.memarg(1)));
3561 }
3562
3563 fn i32_load(&mut self, mem: &Memory) {
3564 self.instruction(LocalGet(mem.addr.idx));
3565 self.instruction(I32Load(mem.memarg(2)));
3566 }
3567
3568 fn i64_load(&mut self, mem: &Memory) {
3569 self.instruction(LocalGet(mem.addr.idx));
3570 self.instruction(I64Load(mem.memarg(3)));
3571 }
3572
3573 fn ptr_load(&mut self, mem: &Memory) {
3574 if mem.mem_opts().memory64 {
3575 self.i64_load(mem);
3576 } else {
3577 self.i32_load(mem);
3578 }
3579 }
3580
3581 fn ptr_add(&mut self, opts: &LinearMemoryOptions) {
3582 if opts.memory64 {
3583 self.instruction(I64Add);
3584 } else {
3585 self.instruction(I32Add);
3586 }
3587 }
3588
3589 fn ptr_sub(&mut self, opts: &LinearMemoryOptions) {
3590 if opts.memory64 {
3591 self.instruction(I64Sub);
3592 } else {
3593 self.instruction(I32Sub);
3594 }
3595 }
3596
3597 fn ptr_mul(&mut self, opts: &LinearMemoryOptions) {
3598 if opts.memory64 {
3599 self.instruction(I64Mul);
3600 } else {
3601 self.instruction(I32Mul);
3602 }
3603 }
3604
3605 fn ptr_ge_u(&mut self, opts: &LinearMemoryOptions) {
3606 if opts.memory64 {
3607 self.instruction(I64GeU);
3608 } else {
3609 self.instruction(I32GeU);
3610 }
3611 }
3612
3613 fn ptr_lt_u(&mut self, opts: &LinearMemoryOptions) {
3614 if opts.memory64 {
3615 self.instruction(I64LtU);
3616 } else {
3617 self.instruction(I32LtU);
3618 }
3619 }
3620
3621 fn ptr_shl(&mut self, opts: &LinearMemoryOptions) {
3622 if opts.memory64 {
3623 self.instruction(I64Shl);
3624 } else {
3625 self.instruction(I32Shl);
3626 }
3627 }
3628
3629 fn ptr_eqz(&mut self, opts: &LinearMemoryOptions) {
3630 if opts.memory64 {
3631 self.instruction(I64Eqz);
3632 } else {
3633 self.instruction(I32Eqz);
3634 }
3635 }
3636
3637 fn ptr_uconst(&mut self, opts: &LinearMemoryOptions, val: u32) {
3638 if opts.memory64 {
3639 self.instruction(I64Const(val.into()));
3640 } else {
3641 self.instruction(I32Const(val as i32));
3642 }
3643 }
3644
3645 fn ptr_iconst(&mut self, opts: &LinearMemoryOptions, val: i32) {
3646 if opts.memory64 {
3647 self.instruction(I64Const(val.into()));
3648 } else {
3649 self.instruction(I32Const(val));
3650 }
3651 }
3652
3653 fn ptr_eq(&mut self, opts: &LinearMemoryOptions) {
3654 if opts.memory64 {
3655 self.instruction(I64Eq);
3656 } else {
3657 self.instruction(I32Eq);
3658 }
3659 }
3660
3661 fn ptr_ne(&mut self, opts: &LinearMemoryOptions) {
3662 if opts.memory64 {
3663 self.instruction(I64Ne);
3664 } else {
3665 self.instruction(I32Ne);
3666 }
3667 }
3668
3669 fn ptr_and(&mut self, opts: &LinearMemoryOptions) {
3670 if opts.memory64 {
3671 self.instruction(I64And);
3672 } else {
3673 self.instruction(I32And);
3674 }
3675 }
3676
3677 fn ptr_or(&mut self, opts: &LinearMemoryOptions) {
3678 if opts.memory64 {
3679 self.instruction(I64Or);
3680 } else {
3681 self.instruction(I32Or);
3682 }
3683 }
3684
3685 fn ptr_xor(&mut self, opts: &LinearMemoryOptions) {
3686 if opts.memory64 {
3687 self.instruction(I64Xor);
3688 } else {
3689 self.instruction(I32Xor);
3690 }
3691 }
3692
3693 fn ptr_if(&mut self, opts: &LinearMemoryOptions, ty: BlockType) {
3694 if opts.memory64 {
3695 self.instruction(I64Const(0));
3696 self.instruction(I64Ne);
3697 }
3698 self.instruction(If(ty));
3699 }
3700
3701 fn ptr_br_if(&mut self, opts: &LinearMemoryOptions, depth: u32) {
3702 if opts.memory64 {
3703 self.instruction(I64Const(0));
3704 self.instruction(I64Ne);
3705 }
3706 self.instruction(BrIf(depth));
3707 }
3708
3709 fn f32_load(&mut self, mem: &Memory) {
3710 self.instruction(LocalGet(mem.addr.idx));
3711 self.instruction(F32Load(mem.memarg(2)));
3712 }
3713
3714 fn f64_load(&mut self, mem: &Memory) {
3715 self.instruction(LocalGet(mem.addr.idx));
3716 self.instruction(F64Load(mem.memarg(3)));
3717 }
3718
3719 fn push_dst_addr(&mut self, dst: &Destination) {
3720 if let Destination::Memory(mem) = dst {
3721 self.instruction(LocalGet(mem.addr.idx));
3722 }
3723 }
3724
3725 fn i32_store8(&mut self, mem: &Memory) {
3726 self.instruction(I32Store8(mem.memarg(0)));
3727 }
3728
3729 fn i32_store16(&mut self, mem: &Memory) {
3730 self.instruction(I32Store16(mem.memarg(1)));
3731 }
3732
3733 fn i32_store(&mut self, mem: &Memory) {
3734 self.instruction(I32Store(mem.memarg(2)));
3735 }
3736
3737 fn i64_store(&mut self, mem: &Memory) {
3738 self.instruction(I64Store(mem.memarg(3)));
3739 }
3740
3741 fn ptr_store(&mut self, mem: &Memory) {
3742 if mem.mem_opts().memory64 {
3743 self.i64_store(mem);
3744 } else {
3745 self.i32_store(mem);
3746 }
3747 }
3748
3749 fn f32_store(&mut self, mem: &Memory) {
3750 self.instruction(F32Store(mem.memarg(2)));
3751 }
3752
3753 fn f64_store(&mut self, mem: &Memory) {
3754 self.instruction(F64Store(mem.memarg(3)));
3755 }
3756}
3757
3758impl<'a> Source<'a> {
3759 fn record_field_srcs<'b>(
3766 &'b self,
3767 types: &'b ComponentTypesBuilder,
3768 fields: impl IntoIterator<Item = InterfaceType> + 'b,
3769 ) -> impl Iterator<Item = Source<'a>> + 'b
3770 where
3771 'a: 'b,
3772 {
3773 let mut offset = 0;
3774 fields.into_iter().map(move |ty| match self {
3775 Source::Memory(mem) => {
3776 let mem = next_field_offset(&mut offset, types, &ty, mem);
3777 Source::Memory(mem)
3778 }
3779 Source::Stack(stack) => {
3780 let cnt = types.flat_types(&ty).unwrap().len() as u32;
3781 offset += cnt;
3782 Source::Stack(stack.slice((offset - cnt) as usize..offset as usize))
3783 }
3784 Source::Struct(_) => todo!(),
3785 Source::Array(_) => todo!(),
3786 })
3787 }
3788
3789 fn payload_src(
3791 &self,
3792 types: &ComponentTypesBuilder,
3793 info: &VariantInfo,
3794 case: Option<&InterfaceType>,
3795 ) -> Source<'a> {
3796 match self {
3797 Source::Stack(s) => {
3798 let flat_len = match case {
3799 Some(case) => types.flat_types(case).unwrap().len(),
3800 None => 0,
3801 };
3802 Source::Stack(s.slice(1..s.locals.len()).slice(0..flat_len))
3803 }
3804 Source::Memory(mem) => {
3805 let mem = if mem.mem_opts().memory64 {
3806 mem.bump(info.payload_offset64)
3807 } else {
3808 mem.bump(info.payload_offset32)
3809 };
3810 Source::Memory(mem)
3811 }
3812 Source::Struct(_) | Source::Array(_) => todo!("CM+GC"),
3813 }
3814 }
3815
3816 fn opts(&self) -> &'a Options {
3817 match self {
3818 Source::Stack(s) => s.opts,
3819 Source::Memory(mem) => mem.opts,
3820 Source::Struct(s) => s.opts,
3821 Source::Array(a) => a.opts,
3822 }
3823 }
3824}
3825
3826impl<'a> Destination<'a> {
3827 fn record_field_dsts<'b, I>(
3829 &'b self,
3830 types: &'b ComponentTypesBuilder,
3831 fields: I,
3832 ) -> impl Iterator<Item = Destination<'b>> + use<'b, I>
3833 where
3834 'a: 'b,
3835 I: IntoIterator<Item = InterfaceType> + 'b,
3836 {
3837 let mut offset = 0;
3838 fields.into_iter().map(move |ty| match self {
3839 Destination::Memory(mem) => {
3840 let mem = next_field_offset(&mut offset, types, &ty, mem);
3841 Destination::Memory(mem)
3842 }
3843 Destination::Stack(s, opts) => {
3844 let cnt = types.flat_types(&ty).unwrap().len() as u32;
3845 offset += cnt;
3846 Destination::Stack(&s[(offset - cnt) as usize..offset as usize], opts)
3847 }
3848 Destination::Struct(_) => todo!(),
3849 Destination::Array(_) => todo!(),
3850 })
3851 }
3852
3853 fn payload_dst(
3855 &self,
3856 types: &ComponentTypesBuilder,
3857 info: &VariantInfo,
3858 case: Option<&InterfaceType>,
3859 ) -> Destination<'_> {
3860 match self {
3861 Destination::Stack(s, opts) => {
3862 let flat_len = match case {
3863 Some(case) => types.flat_types(case).unwrap().len(),
3864 None => 0,
3865 };
3866 Destination::Stack(&s[1..][..flat_len], opts)
3867 }
3868 Destination::Memory(mem) => {
3869 let mem = if mem.mem_opts().memory64 {
3870 mem.bump(info.payload_offset64)
3871 } else {
3872 mem.bump(info.payload_offset32)
3873 };
3874 Destination::Memory(mem)
3875 }
3876 Destination::Struct(_) | Destination::Array(_) => todo!("CM+GC"),
3877 }
3878 }
3879
3880 fn opts(&self) -> &'a Options {
3881 match self {
3882 Destination::Stack(_, opts) => opts,
3883 Destination::Memory(mem) => mem.opts,
3884 Destination::Struct(s) => s.opts,
3885 Destination::Array(a) => a.opts,
3886 }
3887 }
3888}
3889
3890fn next_field_offset<'a>(
3891 offset: &mut u32,
3892 types: &ComponentTypesBuilder,
3893 field: &InterfaceType,
3894 mem: &Memory<'a>,
3895) -> Memory<'a> {
3896 let abi = types.canonical_abi(field);
3897 let offset = if mem.mem_opts().memory64 {
3898 abi.next_field64(offset)
3899 } else {
3900 abi.next_field32(offset)
3901 };
3902 mem.bump(offset)
3903}
3904
3905impl<'a> Memory<'a> {
3906 fn memarg(&self, align: u32) -> MemArg {
3907 MemArg {
3908 offset: u64::from(self.offset),
3909 align,
3910 memory_index: self.mem_opts().memory.unwrap().as_u32(),
3911 }
3912 }
3913
3914 fn bump(&self, offset: u32) -> Memory<'a> {
3915 Memory {
3916 opts: self.opts,
3917 addr: TempLocal::new(self.addr.idx, self.addr.ty),
3918 offset: self.offset + offset,
3919 }
3920 }
3921}
3922
3923impl<'a> Stack<'a> {
3924 fn slice(&self, range: Range<usize>) -> Stack<'a> {
3925 Stack {
3926 locals: &self.locals[range],
3927 opts: self.opts,
3928 }
3929 }
3930}
3931
3932struct VariantCase<'a> {
3933 src_i: u32,
3934 src_ty: Option<&'a InterfaceType>,
3935 dst_i: u32,
3936 dst_ty: Option<&'a InterfaceType>,
3937}
3938
3939fn variant_info<'a, I>(types: &ComponentTypesBuilder, cases: I) -> VariantInfo
3940where
3941 I: IntoIterator<Item = Option<&'a InterfaceType>>,
3942 I::IntoIter: ExactSizeIterator,
3943{
3944 VariantInfo::new(
3945 cases
3946 .into_iter()
3947 .map(|ty| ty.map(|ty| types.canonical_abi(ty))),
3948 )
3949 .0
3950}
3951
3952enum MallocSize {
3953 Const(u32),
3954 Local(u32),
3955}
3956
3957struct WasmString<'a> {
3958 ptr: TempLocal,
3959 len: TempLocal,
3960 opts: &'a Options,
3961}
3962
3963struct TempLocal {
3964 idx: u32,
3965 ty: ValType,
3966 needs_free: bool,
3967}
3968
3969impl TempLocal {
3970 fn new(idx: u32, ty: ValType) -> TempLocal {
3971 TempLocal {
3972 idx,
3973 ty,
3974 needs_free: false,
3975 }
3976 }
3977}
3978
3979impl std::ops::Drop for TempLocal {
3980 fn drop(&mut self) {
3981 if self.needs_free {
3982 panic!("temporary local not free'd");
3983 }
3984 }
3985}
3986
3987impl From<FlatType> for ValType {
3988 fn from(ty: FlatType) -> ValType {
3989 match ty {
3990 FlatType::I32 => ValType::I32,
3991 FlatType::I64 => ValType::I64,
3992 FlatType::F32 => ValType::F32,
3993 FlatType::F64 => ValType::F64,
3994 }
3995 }
3996}