1use crate::component::dfg::{AdapterId, ComponentDfg, CoreDef};
22use crate::component::{
23 AdapterOptions as AdapterOptionsDfg, CanonicalAbiInfo, ComponentTypesBuilder, FlatType,
24 InterfaceType, RuntimeComponentInstanceIndex, StringEncoding, Transcode, TypeFuncIndex,
25 UnsafeIntrinsic,
26};
27use crate::fact::transcode::Transcoder;
28use crate::prelude::*;
29use crate::{
30 EntityRef, FuncIndex, GlobalIndex, IndexType, Memory, MemoryIndex, ModuleInternedTypeIndex,
31 PrimaryMap, Trap, Tunables, WasmValType,
32};
33use std::collections::HashMap;
34use wasm_encoder::*;
35use wasmparser::WasmFeatures;
36
37mod core_types;
38mod signature;
39mod trampoline;
40mod transcode;
41
42pub static PREPARE_CALL_FIXED_PARAMS: &[ValType] = &[
48 ValType::FUNCREF, ValType::FUNCREF, ValType::I32, ValType::I32, ValType::I32, ValType::I32, ValType::I32, ValType::I32, ];
57
58pub struct Module<'a> {
60 tunables: &'a Tunables,
62 types: &'a ComponentTypesBuilder,
64
65 features: WasmFeatures,
67
68 core_types: core_types::CoreTypes,
70
71 core_imports: ImportSection,
75 imports: Vec<Import>,
78 imported: HashMap<CoreDef, usize>,
81 imported_transcoders: HashMap<Transcoder, FuncIndex>,
83
84 imported_resource_transfer_own: Option<FuncIndex>,
86 imported_resource_transfer_borrow: Option<FuncIndex>,
87
88 imported_start_calls: HashMap<(Option<FuncIndex>, Option<FuncIndex>, Vec<ValType>), FuncIndex>,
90
91 imported_future_transfer: Option<FuncIndex>,
94 imported_stream_transfer: Option<FuncIndex>,
95 imported_error_context_transfer: Option<FuncIndex>,
96
97 imported_enter_sync_call: Option<FuncIndex>,
98 imported_exit_sync_call: Option<FuncIndex>,
99
100 imported_unsafe_intrinsics: HashMap<UnsafeIntrinsic, FuncIndex>,
102
103 imported_traps: HashMap<Trap, FuncIndex>,
105
106 imported_funcs: PrimaryMap<FuncIndex, Option<CoreDef>>,
108 imported_memories: PrimaryMap<MemoryIndex, CoreDef>,
109 imported_globals: PrimaryMap<GlobalIndex, CoreDef>,
110
111 funcs: PrimaryMap<FunctionId, Function>,
112 helper_funcs: HashMap<Helper, FunctionId>,
113 helper_worklist: Vec<(FunctionId, Helper)>,
114
115 exports: Vec<(u32, String)>,
116}
117
118struct AdapterData {
119 name: String,
121 lift: AdapterOptions,
123 lower: AdapterOptions,
125 callee: FuncIndex,
128 thread_transparent: bool,
134}
135
136struct AdapterOptions {
141 instance: RuntimeComponentInstanceIndex,
144 ty: TypeFuncIndex,
146 flags: GlobalIndex,
149 post_return: Option<FuncIndex>,
151 options: Options,
153}
154
155#[derive(PartialEq, Eq, Hash, Copy, Clone)]
156struct LinearMemoryOptions {
158 memory: Option<(MemoryIndex, Memory)>,
161 realloc: Option<FuncIndex>,
164}
165
166impl LinearMemoryOptions {
167 fn ptr(&self) -> ValType {
168 if self.memory64() {
169 ValType::I64
170 } else {
171 ValType::I32
172 }
173 }
174
175 fn ptr_size(&self) -> u8 {
176 if self.memory64() { 8 } else { 4 }
177 }
178
179 fn memory64(&self) -> bool {
180 self.memory
181 .as_ref()
182 .map(|(_, ty)| ty.idx_type == IndexType::I64)
183 .unwrap_or(false)
184 }
185
186 fn sizealign(&self, abi: &CanonicalAbiInfo) -> (u32, u32) {
187 if self.memory64() {
188 (abi.size64, abi.align64)
189 } else {
190 (abi.size32, abi.align32)
191 }
192 }
193}
194
195#[derive(PartialEq, Eq, Hash, Copy, Clone)]
197enum DataModel {
198 Gc {},
199 LinearMemory(LinearMemoryOptions),
200}
201
202impl DataModel {
203 #[track_caller]
204 fn unwrap_memory(&self) -> &LinearMemoryOptions {
205 match self {
206 DataModel::Gc {} => panic!("`unwrap_memory` on GC"),
207 DataModel::LinearMemory(opts) => opts,
208 }
209 }
210}
211
212#[derive(PartialEq, Eq, Hash, Copy, Clone)]
217struct Options {
218 string_encoding: StringEncoding,
220 callback: Option<FuncIndex>,
221 async_: bool,
222 core_type: ModuleInternedTypeIndex,
223 data_model: DataModel,
224}
225
226#[derive(Copy, Clone, PartialEq, Eq, Hash)]
234struct Helper {
235 src: HelperType,
237 dst: HelperType,
239}
240
241#[derive(Copy, Clone, PartialEq, Eq, Hash)]
244struct HelperType {
245 ty: InterfaceType,
247 opts: Options,
249 loc: HelperLocation,
251}
252
253#[derive(Copy, Clone, PartialEq, Eq, Hash)]
256enum HelperLocation {
257 Stack,
259 Memory,
261 #[expect(dead_code, reason = "CM+GC is still WIP")]
263 StructField,
264 #[expect(dead_code, reason = "CM+GC is still WIP")]
266 ArrayElement,
267}
268
269impl<'a> Module<'a> {
270 pub fn new(
272 types: &'a ComponentTypesBuilder,
273 tunables: &'a Tunables,
274 features: WasmFeatures,
275 ) -> Module<'a> {
276 Module {
277 tunables,
278 types,
279 features,
280 core_types: Default::default(),
281 core_imports: Default::default(),
282 imported: Default::default(),
283 imports: Default::default(),
284 imported_transcoders: Default::default(),
285 imported_funcs: PrimaryMap::new(),
286 imported_memories: PrimaryMap::new(),
287 imported_globals: PrimaryMap::new(),
288 funcs: PrimaryMap::new(),
289 helper_funcs: HashMap::new(),
290 helper_worklist: Vec::new(),
291 imported_resource_transfer_own: None,
292 imported_resource_transfer_borrow: None,
293 imported_start_calls: HashMap::new(),
294 imported_future_transfer: None,
295 imported_stream_transfer: None,
296 imported_error_context_transfer: None,
297 imported_enter_sync_call: None,
298 imported_exit_sync_call: None,
299 imported_unsafe_intrinsics: HashMap::new(),
300 imported_traps: HashMap::new(),
301 exports: Vec::new(),
302 }
303 }
304
305 pub fn adapt(&mut self, name: &str, component: &ComponentDfg, adapter: AdapterId) {
311 let thread_transparent = component.transparent_adapters.contains(adapter);
312 let adapter = &component.adapters[adapter];
313
314 let mut lift = self.import_options(adapter.lift_ty, &adapter.lift_options);
317 let lower = self.import_options(adapter.lower_ty, &adapter.lower_options);
318
319 assert!(adapter.lower_options.post_return.is_none());
322
323 let signature = self.types.signature(&lift);
327 let ty = self
328 .core_types
329 .function(&signature.params, &signature.results);
330 let callee = self.import_func("callee", name, ty, adapter.func.clone());
331
332 lift.post_return = adapter.lift_options.post_return.as_ref().map(|func| {
335 let ty = self.core_types.function(&signature.results, &[]);
336 self.import_func("post_return", name, ty, func.clone())
337 });
338
339 trampoline::compile(
342 self,
343 &AdapterData {
344 name: name.to_string(),
345 lift,
346 lower,
347 callee,
348 thread_transparent,
349 },
350 );
351
352 while let Some((result, helper)) = self.helper_worklist.pop() {
353 trampoline::compile_helper(self, result, helper);
354 }
355 }
356
357 fn import_options(&mut self, ty: TypeFuncIndex, options: &AdapterOptionsDfg) -> AdapterOptions {
358 let AdapterOptionsDfg {
359 instance,
360 string_encoding,
361 post_return: _, callback,
363 async_,
364 core_type,
365 data_model,
366 } = options;
367
368 let flags = self.import_global(
369 "flags",
370 &format!("instance{}", instance.as_u32()),
371 GlobalType {
372 val_type: ValType::I32,
373 mutable: true,
374 shared: false,
375 },
376 CoreDef::InstanceFlags(*instance),
377 );
378
379 let data_model = match data_model {
380 crate::component::DataModel::Gc {} => DataModel::Gc {},
381 crate::component::DataModel::LinearMemory { memory, realloc } => {
382 let memory = memory.as_ref().map(|(memory, ty)| {
383 (
384 self.import_memory(
385 "memory",
386 &format!("m{}", self.imported_memories.len()),
387 MemoryType {
388 minimum: 0,
389 maximum: None,
390 shared: ty.shared,
391 memory64: ty.idx_type == IndexType::I64,
392 page_size_log2: if ty.page_size_log2 == 16 {
393 None
394 } else {
395 Some(ty.page_size_log2.into())
396 },
397 },
398 memory.clone().into(),
399 ),
400 *ty,
401 )
402 });
403 let realloc = realloc.as_ref().map(|func| {
404 let ptr = match memory.as_ref().unwrap().1.idx_type {
405 IndexType::I32 => ValType::I32,
406 IndexType::I64 => ValType::I64,
407 };
408 let ty = self.core_types.function(&[ptr, ptr, ptr, ptr], &[ptr]);
409 self.import_func(
410 "realloc",
411 &format!("f{}", self.imported_funcs.len()),
412 ty,
413 func.clone(),
414 )
415 });
416 DataModel::LinearMemory(LinearMemoryOptions { memory, realloc })
417 }
418 };
419
420 let callback = callback.as_ref().map(|func| {
421 let ty = self
422 .core_types
423 .function(&[ValType::I32, ValType::I32, ValType::I32], &[ValType::I32]);
424 self.import_func(
425 "callback",
426 &format!("f{}", self.imported_funcs.len()),
427 ty,
428 func.clone(),
429 )
430 });
431
432 AdapterOptions {
433 instance: *instance,
434 ty,
435 flags,
436 post_return: None,
437 options: Options {
438 string_encoding: *string_encoding,
439 callback,
440 async_: *async_,
441 core_type: *core_type,
442 data_model,
443 },
444 }
445 }
446
447 fn import_func(&mut self, module: &str, name: &str, ty: u32, def: CoreDef) -> FuncIndex {
448 self.import(module, name, EntityType::Function(ty), def, |m| {
449 &mut m.imported_funcs
450 })
451 }
452
453 fn import_global(
454 &mut self,
455 module: &str,
456 name: &str,
457 ty: GlobalType,
458 def: CoreDef,
459 ) -> GlobalIndex {
460 self.import(module, name, EntityType::Global(ty), def, |m| {
461 &mut m.imported_globals
462 })
463 }
464
465 fn import_memory(
466 &mut self,
467 module: &str,
468 name: &str,
469 ty: MemoryType,
470 def: CoreDef,
471 ) -> MemoryIndex {
472 self.import(module, name, EntityType::Memory(ty), def, |m| {
473 &mut m.imported_memories
474 })
475 }
476
477 fn import<K: EntityRef, V: From<CoreDef>>(
478 &mut self,
479 module: &str,
480 name: &str,
481 ty: EntityType,
482 def: CoreDef,
483 map: impl FnOnce(&mut Self) -> &mut PrimaryMap<K, V>,
484 ) -> K {
485 if let Some(prev) = self.imported.get(&def) {
486 return K::new(*prev);
487 }
488 let idx = map(self).push(def.clone().into());
489 self.core_imports.import(module, name, ty);
490 self.imported.insert(def.clone(), idx.index());
491 self.imports.push(Import::CoreDef(def));
492 idx
493 }
494
495 fn import_transcoder(&mut self, transcoder: transcode::Transcoder) -> FuncIndex {
496 *self
497 .imported_transcoders
498 .entry(transcoder)
499 .or_insert_with(|| {
500 let name = transcoder.name();
502 let ty = transcoder.ty(&mut self.core_types);
503 self.core_imports.import("transcode", &name, ty);
504
505 let from = self.imported_memories[transcoder.from_memory].clone();
508 let to = self.imported_memories[transcoder.to_memory].clone();
509 self.imports.push(Import::Transcode {
510 op: transcoder.op,
511 from,
512 from64: transcoder.from_memory64,
513 to,
514 to64: transcoder.to_memory64,
515 });
516
517 self.imported_funcs.push(None)
518 })
519 }
520
521 fn import_simple(
522 &mut self,
523 module: &str,
524 name: &str,
525 params: &[ValType],
526 results: &[ValType],
527 import: Import,
528 get: impl Fn(&mut Self) -> &mut Option<FuncIndex>,
529 ) -> FuncIndex {
530 self.import_simple_get_and_set(
531 module,
532 name,
533 params,
534 results,
535 import,
536 |me| *get(me),
537 |me, v| *get(me) = Some(v),
538 )
539 }
540
541 fn import_simple_get_and_set(
542 &mut self,
543 module: &str,
544 name: &str,
545 params: &[ValType],
546 results: &[ValType],
547 import: Import,
548 get: impl Fn(&mut Self) -> Option<FuncIndex>,
549 set: impl Fn(&mut Self, FuncIndex),
550 ) -> FuncIndex {
551 if let Some(idx) = get(self) {
552 return idx;
553 }
554 let ty = self.core_types.function(params, results);
555 let ty = EntityType::Function(ty);
556 self.core_imports.import(module, name, ty);
557
558 self.imports.push(import);
559 let idx = self.imported_funcs.push(None);
560 set(self, idx);
561 idx
562 }
563
564 fn import_prepare_call(
572 &mut self,
573 suffix: &str,
574 params: &[ValType],
575 memory: Option<MemoryIndex>,
576 ) -> FuncIndex {
577 let ty = self.core_types.function(
578 &PREPARE_CALL_FIXED_PARAMS
579 .iter()
580 .copied()
581 .chain(params.iter().copied())
582 .collect::<Vec<_>>(),
583 &[],
584 );
585 self.core_imports.import(
586 "sync",
587 &format!("[prepare-call]{suffix}"),
588 EntityType::Function(ty),
589 );
590 let import = Import::PrepareCall {
591 memory: memory.map(|v| self.imported_memories[v].clone()),
592 };
593 self.imports.push(import);
594 self.imported_funcs.push(None)
595 }
596
597 fn import_start_call(
609 &mut self,
610 suffix: &str,
611 callback: Option<FuncIndex>,
612 post_return: Option<FuncIndex>,
613 results: &[ValType],
614 ) -> FuncIndex {
615 let key = (callback, post_return, results.to_vec());
616 self.import_simple_get_and_set(
617 "async",
618 &format!("[start-call]{suffix}"),
619 &[ValType::FUNCREF, ValType::I32, ValType::I32, ValType::I32],
620 results,
621 Import::StartCall {
622 callback: callback
623 .map(|callback| self.imported_funcs.get(callback).unwrap().clone().unwrap()),
624 post_return: post_return.map(|post_return| {
625 self.imported_funcs
626 .get(post_return)
627 .unwrap()
628 .clone()
629 .unwrap()
630 }),
631 },
632 |me| me.imported_start_calls.get(&key).copied(),
633 |me, v| assert!(me.imported_start_calls.insert(key.clone(), v).is_none()),
634 )
635 }
636
637 fn import_future_transfer(&mut self) -> FuncIndex {
638 self.import_simple(
639 "future",
640 "transfer",
641 &[ValType::I32; 3],
642 &[ValType::I32],
643 Import::FutureTransfer,
644 |me| &mut me.imported_future_transfer,
645 )
646 }
647
648 fn import_stream_transfer(&mut self) -> FuncIndex {
649 self.import_simple(
650 "stream",
651 "transfer",
652 &[ValType::I32; 3],
653 &[ValType::I32],
654 Import::StreamTransfer,
655 |me| &mut me.imported_stream_transfer,
656 )
657 }
658
659 fn import_error_context_transfer(&mut self) -> FuncIndex {
660 self.import_simple(
661 "error-context",
662 "transfer",
663 &[ValType::I32; 3],
664 &[ValType::I32],
665 Import::ErrorContextTransfer,
666 |me| &mut me.imported_error_context_transfer,
667 )
668 }
669
670 fn import_resource_transfer_own(&mut self) -> FuncIndex {
671 self.import_simple(
672 "resource",
673 "transfer-own",
674 &[ValType::I32, ValType::I32, ValType::I32],
675 &[ValType::I32],
676 Import::ResourceTransferOwn,
677 |me| &mut me.imported_resource_transfer_own,
678 )
679 }
680
681 fn import_resource_transfer_borrow(&mut self) -> FuncIndex {
682 self.import_simple(
683 "resource",
684 "transfer-borrow",
685 &[ValType::I32, ValType::I32, ValType::I32],
686 &[ValType::I32],
687 Import::ResourceTransferBorrow,
688 |me| &mut me.imported_resource_transfer_borrow,
689 )
690 }
691
692 fn import_enter_sync_call(&mut self) -> FuncIndex {
693 self.import_simple(
694 "async",
695 "enter-sync-call",
696 &[ValType::I32; 2],
697 &[],
698 Import::EnterSyncCall,
699 |me| &mut me.imported_enter_sync_call,
700 )
701 }
702
703 fn import_exit_sync_call(&mut self) -> FuncIndex {
704 self.import_simple(
705 "async",
706 "exit-sync-call",
707 &[],
708 &[],
709 Import::ExitSyncCall,
710 |me| &mut me.imported_exit_sync_call,
711 )
712 }
713
714 fn import_context_get(&mut self, slot: usize) -> FuncIndex {
716 let intrinsic = match slot {
717 0 => UnsafeIntrinsic::ContextGetI32_0,
718 1 => UnsafeIntrinsic::ContextGetI32_1,
719 _ => unreachable!(),
720 };
721 self.import_unsafe_intrinsic(intrinsic, &format!("get{slot}"))
722 }
723
724 fn import_context_set(&mut self, slot: usize) -> FuncIndex {
726 let intrinsic = match slot {
727 0 => UnsafeIntrinsic::ContextSetI32_0,
728 1 => UnsafeIntrinsic::ContextSetI32_1,
729 _ => unreachable!(),
730 };
731 self.import_unsafe_intrinsic(intrinsic, &format!("set{slot}"))
732 }
733
734 fn import_unsafe_intrinsic(&mut self, intrinsic: UnsafeIntrinsic, name: &str) -> FuncIndex {
735 let map = |ty: &WasmValType| match ty {
736 crate::WasmValType::I32 => ValType::I32,
737 crate::WasmValType::I64 => ValType::I64,
738 crate::WasmValType::F32 => ValType::F32,
739 crate::WasmValType::F64 => ValType::F64,
740 crate::WasmValType::V128 => ValType::V128,
741 crate::WasmValType::Ref(_) => unreachable!(),
742 };
743 let params = intrinsic.core_params().iter().map(map).collect::<Vec<_>>();
744 let results = intrinsic.core_results().iter().map(map).collect::<Vec<_>>();
745
746 self.import_simple_get_and_set(
747 "context",
748 name,
749 ¶ms,
750 &results,
751 Import::UnsafeIntrinsic(intrinsic),
752 |me| me.imported_unsafe_intrinsics.get(&intrinsic).copied(),
753 |me, idx| {
754 me.imported_unsafe_intrinsics.insert(intrinsic, idx);
755 },
756 )
757 }
758
759 fn import_trap(&mut self, trap: Trap) -> FuncIndex {
760 let name = format!("trap{}", trap as u8);
761 self.import_simple_get_and_set(
762 "runtime",
763 &name,
764 &[],
765 &[],
766 Import::Trap(trap),
767 |me| me.imported_traps.get(&trap).copied(),
768 |me, idx| {
769 me.imported_traps.insert(trap, idx);
770 },
771 )
772 }
773
774 fn translate_helper(&mut self, helper: Helper) -> FunctionId {
775 *self.helper_funcs.entry(helper).or_insert_with(|| {
776 let ty = helper.core_type(self.types, &mut self.core_types);
779 let id = self.funcs.push(Function::new(None, ty));
780 self.helper_worklist.push((id, helper));
781 id
782 })
783 }
784
785 pub fn encode(&mut self) -> Vec<u8> {
787 let mut funcs = FunctionSection::new();
791 let mut exports = ExportSection::new();
792 let mut id_to_index = PrimaryMap::<FunctionId, FuncIndex>::new();
793 for (id, func) in self.funcs.iter() {
794 assert!(func.filled_in);
795 let idx = FuncIndex::from_u32(self.imported_funcs.next_key().as_u32() + id.as_u32());
796 let id2 = id_to_index.push(idx);
797 assert_eq!(id2, id);
798
799 funcs.function(func.ty);
800
801 if let Some(name) = &func.export {
802 exports.export(name, ExportKind::Func, idx.as_u32());
803 }
804 }
805 for (idx, name) in &self.exports {
806 exports.export(name, ExportKind::Func, *idx);
807 }
808
809 let mut code = CodeSection::new();
812 for (_, func) in self.funcs.iter() {
813 let mut body = Vec::new();
814
815 func.locals.len().encode(&mut body);
817 for (count, ty) in func.locals.iter() {
818 count.encode(&mut body);
819 ty.encode(&mut body);
820 }
821
822 for chunk in func.body.iter() {
827 match chunk {
828 Body::Raw(code) => {
829 body.extend_from_slice(code);
830 }
831 Body::Call(id) => {
832 Instruction::Call(id_to_index[*id].as_u32()).encode(&mut body);
833 }
834 Body::RefFunc(id) => {
835 Instruction::RefFunc(id_to_index[*id].as_u32()).encode(&mut body);
836 }
837 }
838 }
839 code.raw(&body);
840 }
841
842 let mut result = wasm_encoder::Module::new();
843 result.section(&self.core_types.section);
844 result.section(&self.core_imports);
845 result.section(&funcs);
846 result.section(&exports);
847 result.section(&code);
848 result.finish()
849 }
850
851 pub fn imports(&self) -> &[Import] {
854 &self.imports
855 }
856}
857
858#[derive(Clone)]
860pub enum Import {
861 CoreDef(CoreDef),
863 Transcode {
865 op: Transcode,
867 from: CoreDef,
869 from64: bool,
871 to: CoreDef,
873 to64: bool,
875 },
876 ResourceTransferOwn,
878 ResourceTransferBorrow,
880 PrepareCall {
883 memory: Option<CoreDef>,
887 },
888 StartCall {
891 callback: Option<CoreDef>,
893
894 post_return: Option<CoreDef>,
896 },
897 FutureTransfer,
900 StreamTransfer,
903 ErrorContextTransfer,
906 Trap(Trap),
908 EnterSyncCall,
912 ExitSyncCall,
915 UnsafeIntrinsic(UnsafeIntrinsic),
917}
918
919impl Options {
920 fn flat_types<'a>(
921 &self,
922 ty: &InterfaceType,
923 types: &'a ComponentTypesBuilder,
924 ) -> Option<&'a [FlatType]> {
925 let flat = types.flat_types(ty)?;
926 match self.data_model {
927 DataModel::Gc {} => todo!("CM+GC"),
928 DataModel::LinearMemory(mem_opts) => Some(if mem_opts.memory64() {
929 flat.memory64
930 } else {
931 flat.memory32
932 }),
933 }
934 }
935}
936
937#[derive(Debug, Copy, Clone, PartialEq, Eq)]
943struct FunctionId(u32);
944cranelift_entity::entity_impl!(FunctionId);
945
946struct Function {
951 filled_in: bool,
957
958 ty: u32,
961
962 locals: Vec<(u32, ValType)>,
965
966 export: Option<String>,
968
969 body: Vec<Body>,
974}
975
976enum Body {
998 Raw(Vec<u8>),
999 Call(FunctionId),
1000 RefFunc(FunctionId),
1001}
1002
1003impl Function {
1004 fn new(export: Option<String>, ty: u32) -> Function {
1005 Function {
1006 filled_in: false,
1007 ty,
1008 locals: Vec::new(),
1009 export,
1010 body: Vec::new(),
1011 }
1012 }
1013}
1014
1015impl Helper {
1016 fn core_type(
1017 &self,
1018 types: &ComponentTypesBuilder,
1019 core_types: &mut core_types::CoreTypes,
1020 ) -> u32 {
1021 let mut params = Vec::new();
1022 let mut results = Vec::new();
1023 self.src.push_flat(&mut params, types);
1027
1028 match self.dst.loc {
1032 HelperLocation::Stack => self.dst.push_flat(&mut results, types),
1033 HelperLocation::Memory => params.push(self.dst.opts.data_model.unwrap_memory().ptr()),
1034 HelperLocation::StructField | HelperLocation::ArrayElement => todo!("CM+GC"),
1035 }
1036
1037 core_types.function(¶ms, &results)
1038 }
1039}
1040
1041impl HelperType {
1042 fn push_flat(&self, dst: &mut Vec<ValType>, types: &ComponentTypesBuilder) {
1043 match self.loc {
1044 HelperLocation::Stack => {
1045 for ty in self.opts.flat_types(&self.ty, types).unwrap() {
1046 dst.push((*ty).into());
1047 }
1048 }
1049 HelperLocation::Memory => {
1050 dst.push(self.opts.data_model.unwrap_memory().ptr());
1051 }
1052 HelperLocation::StructField | HelperLocation::ArrayElement => todo!("CM+GC"),
1053 }
1054 }
1055}