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_async_start_calls: HashMap<(Option<FuncIndex>, Option<FuncIndex>), 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_async_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_sync_start_call(
609 &mut self,
610 suffix: &str,
611 callback: Option<FuncIndex>,
612 results: &[ValType],
613 ) -> FuncIndex {
614 let ty = self
615 .core_types
616 .function(&[ValType::FUNCREF, ValType::I32], results);
617 self.core_imports.import(
618 "sync",
619 &format!("[start-call]{suffix}"),
620 EntityType::Function(ty),
621 );
622 let import = Import::SyncStartCall {
623 callback: callback
624 .map(|callback| self.imported_funcs.get(callback).unwrap().clone().unwrap()),
625 };
626 self.imports.push(import);
627 self.imported_funcs.push(None)
628 }
629
630 fn import_async_start_call(
639 &mut self,
640 suffix: &str,
641 callback: Option<FuncIndex>,
642 post_return: Option<FuncIndex>,
643 ) -> FuncIndex {
644 self.import_simple_get_and_set(
645 "async",
646 &format!("[start-call]{suffix}"),
647 &[ValType::FUNCREF, ValType::I32, ValType::I32, ValType::I32],
648 &[ValType::I32],
649 Import::AsyncStartCall {
650 callback: callback
651 .map(|callback| self.imported_funcs.get(callback).unwrap().clone().unwrap()),
652 post_return: post_return.map(|post_return| {
653 self.imported_funcs
654 .get(post_return)
655 .unwrap()
656 .clone()
657 .unwrap()
658 }),
659 },
660 |me| {
661 me.imported_async_start_calls
662 .get(&(callback, post_return))
663 .copied()
664 },
665 |me, v| {
666 assert!(
667 me.imported_async_start_calls
668 .insert((callback, post_return), v)
669 .is_none()
670 )
671 },
672 )
673 }
674
675 fn import_future_transfer(&mut self) -> FuncIndex {
676 self.import_simple(
677 "future",
678 "transfer",
679 &[ValType::I32; 3],
680 &[ValType::I32],
681 Import::FutureTransfer,
682 |me| &mut me.imported_future_transfer,
683 )
684 }
685
686 fn import_stream_transfer(&mut self) -> FuncIndex {
687 self.import_simple(
688 "stream",
689 "transfer",
690 &[ValType::I32; 3],
691 &[ValType::I32],
692 Import::StreamTransfer,
693 |me| &mut me.imported_stream_transfer,
694 )
695 }
696
697 fn import_error_context_transfer(&mut self) -> FuncIndex {
698 self.import_simple(
699 "error-context",
700 "transfer",
701 &[ValType::I32; 3],
702 &[ValType::I32],
703 Import::ErrorContextTransfer,
704 |me| &mut me.imported_error_context_transfer,
705 )
706 }
707
708 fn import_resource_transfer_own(&mut self) -> FuncIndex {
709 self.import_simple(
710 "resource",
711 "transfer-own",
712 &[ValType::I32, ValType::I32, ValType::I32],
713 &[ValType::I32],
714 Import::ResourceTransferOwn,
715 |me| &mut me.imported_resource_transfer_own,
716 )
717 }
718
719 fn import_resource_transfer_borrow(&mut self) -> FuncIndex {
720 self.import_simple(
721 "resource",
722 "transfer-borrow",
723 &[ValType::I32, ValType::I32, ValType::I32],
724 &[ValType::I32],
725 Import::ResourceTransferBorrow,
726 |me| &mut me.imported_resource_transfer_borrow,
727 )
728 }
729
730 fn import_enter_sync_call(&mut self) -> FuncIndex {
731 self.import_simple(
732 "async",
733 "enter-sync-call",
734 &[ValType::I32; 2],
735 &[],
736 Import::EnterSyncCall,
737 |me| &mut me.imported_enter_sync_call,
738 )
739 }
740
741 fn import_exit_sync_call(&mut self) -> FuncIndex {
742 self.import_simple(
743 "async",
744 "exit-sync-call",
745 &[],
746 &[],
747 Import::ExitSyncCall,
748 |me| &mut me.imported_exit_sync_call,
749 )
750 }
751
752 fn import_context_get(&mut self, slot: usize) -> FuncIndex {
754 let intrinsic = match slot {
755 0 => UnsafeIntrinsic::ContextGetI32_0,
756 1 => UnsafeIntrinsic::ContextGetI32_1,
757 _ => unreachable!(),
758 };
759 self.import_unsafe_intrinsic(intrinsic, &format!("get{slot}"))
760 }
761
762 fn import_context_set(&mut self, slot: usize) -> FuncIndex {
764 let intrinsic = match slot {
765 0 => UnsafeIntrinsic::ContextSetI32_0,
766 1 => UnsafeIntrinsic::ContextSetI32_1,
767 _ => unreachable!(),
768 };
769 self.import_unsafe_intrinsic(intrinsic, &format!("set{slot}"))
770 }
771
772 fn import_unsafe_intrinsic(&mut self, intrinsic: UnsafeIntrinsic, name: &str) -> FuncIndex {
773 let map = |ty: &WasmValType| match ty {
774 crate::WasmValType::I32 => ValType::I32,
775 crate::WasmValType::I64 => ValType::I64,
776 crate::WasmValType::F32 => ValType::F32,
777 crate::WasmValType::F64 => ValType::F64,
778 crate::WasmValType::V128 => ValType::V128,
779 crate::WasmValType::Ref(_) => unreachable!(),
780 };
781 let params = intrinsic.core_params().iter().map(map).collect::<Vec<_>>();
782 let results = intrinsic.core_results().iter().map(map).collect::<Vec<_>>();
783
784 self.import_simple_get_and_set(
785 "context",
786 name,
787 ¶ms,
788 &results,
789 Import::UnsafeIntrinsic(intrinsic),
790 |me| me.imported_unsafe_intrinsics.get(&intrinsic).copied(),
791 |me, idx| {
792 me.imported_unsafe_intrinsics.insert(intrinsic, idx);
793 },
794 )
795 }
796
797 fn import_trap(&mut self, trap: Trap) -> FuncIndex {
798 let name = format!("trap{}", trap as u8);
799 self.import_simple_get_and_set(
800 "runtime",
801 &name,
802 &[],
803 &[],
804 Import::Trap(trap),
805 |me| me.imported_traps.get(&trap).copied(),
806 |me, idx| {
807 me.imported_traps.insert(trap, idx);
808 },
809 )
810 }
811
812 fn translate_helper(&mut self, helper: Helper) -> FunctionId {
813 *self.helper_funcs.entry(helper).or_insert_with(|| {
814 let ty = helper.core_type(self.types, &mut self.core_types);
817 let id = self.funcs.push(Function::new(None, ty));
818 self.helper_worklist.push((id, helper));
819 id
820 })
821 }
822
823 pub fn encode(&mut self) -> Vec<u8> {
825 let mut funcs = FunctionSection::new();
829 let mut exports = ExportSection::new();
830 let mut id_to_index = PrimaryMap::<FunctionId, FuncIndex>::new();
831 for (id, func) in self.funcs.iter() {
832 assert!(func.filled_in);
833 let idx = FuncIndex::from_u32(self.imported_funcs.next_key().as_u32() + id.as_u32());
834 let id2 = id_to_index.push(idx);
835 assert_eq!(id2, id);
836
837 funcs.function(func.ty);
838
839 if let Some(name) = &func.export {
840 exports.export(name, ExportKind::Func, idx.as_u32());
841 }
842 }
843 for (idx, name) in &self.exports {
844 exports.export(name, ExportKind::Func, *idx);
845 }
846
847 let mut code = CodeSection::new();
850 for (_, func) in self.funcs.iter() {
851 let mut body = Vec::new();
852
853 func.locals.len().encode(&mut body);
855 for (count, ty) in func.locals.iter() {
856 count.encode(&mut body);
857 ty.encode(&mut body);
858 }
859
860 for chunk in func.body.iter() {
865 match chunk {
866 Body::Raw(code) => {
867 body.extend_from_slice(code);
868 }
869 Body::Call(id) => {
870 Instruction::Call(id_to_index[*id].as_u32()).encode(&mut body);
871 }
872 Body::RefFunc(id) => {
873 Instruction::RefFunc(id_to_index[*id].as_u32()).encode(&mut body);
874 }
875 }
876 }
877 code.raw(&body);
878 }
879
880 let mut result = wasm_encoder::Module::new();
881 result.section(&self.core_types.section);
882 result.section(&self.core_imports);
883 result.section(&funcs);
884 result.section(&exports);
885 result.section(&code);
886 result.finish()
887 }
888
889 pub fn imports(&self) -> &[Import] {
892 &self.imports
893 }
894}
895
896#[derive(Clone)]
898pub enum Import {
899 CoreDef(CoreDef),
901 Transcode {
903 op: Transcode,
905 from: CoreDef,
907 from64: bool,
909 to: CoreDef,
911 to64: bool,
913 },
914 ResourceTransferOwn,
916 ResourceTransferBorrow,
918 PrepareCall {
921 memory: Option<CoreDef>,
925 },
926 SyncStartCall {
929 callback: Option<CoreDef>,
931 },
932 AsyncStartCall {
935 callback: Option<CoreDef>,
937
938 post_return: Option<CoreDef>,
940 },
941 FutureTransfer,
944 StreamTransfer,
947 ErrorContextTransfer,
950 Trap(Trap),
952 EnterSyncCall,
956 ExitSyncCall,
959 UnsafeIntrinsic(UnsafeIntrinsic),
961}
962
963impl Options {
964 fn flat_types<'a>(
965 &self,
966 ty: &InterfaceType,
967 types: &'a ComponentTypesBuilder,
968 ) -> Option<&'a [FlatType]> {
969 let flat = types.flat_types(ty)?;
970 match self.data_model {
971 DataModel::Gc {} => todo!("CM+GC"),
972 DataModel::LinearMemory(mem_opts) => Some(if mem_opts.memory64() {
973 flat.memory64
974 } else {
975 flat.memory32
976 }),
977 }
978 }
979}
980
981#[derive(Debug, Copy, Clone, PartialEq, Eq)]
987struct FunctionId(u32);
988cranelift_entity::entity_impl!(FunctionId);
989
990struct Function {
995 filled_in: bool,
1001
1002 ty: u32,
1005
1006 locals: Vec<(u32, ValType)>,
1009
1010 export: Option<String>,
1012
1013 body: Vec<Body>,
1018}
1019
1020enum Body {
1042 Raw(Vec<u8>),
1043 Call(FunctionId),
1044 RefFunc(FunctionId),
1045}
1046
1047impl Function {
1048 fn new(export: Option<String>, ty: u32) -> Function {
1049 Function {
1050 filled_in: false,
1051 ty,
1052 locals: Vec::new(),
1053 export,
1054 body: Vec::new(),
1055 }
1056 }
1057}
1058
1059impl Helper {
1060 fn core_type(
1061 &self,
1062 types: &ComponentTypesBuilder,
1063 core_types: &mut core_types::CoreTypes,
1064 ) -> u32 {
1065 let mut params = Vec::new();
1066 let mut results = Vec::new();
1067 self.src.push_flat(&mut params, types);
1071
1072 match self.dst.loc {
1076 HelperLocation::Stack => self.dst.push_flat(&mut results, types),
1077 HelperLocation::Memory => params.push(self.dst.opts.data_model.unwrap_memory().ptr()),
1078 HelperLocation::StructField | HelperLocation::ArrayElement => todo!("CM+GC"),
1079 }
1080
1081 core_types.function(¶ms, &results)
1082 }
1083}
1084
1085impl HelperType {
1086 fn push_flat(&self, dst: &mut Vec<ValType>, types: &ComponentTypesBuilder) {
1087 match self.loc {
1088 HelperLocation::Stack => {
1089 for ty in self.opts.flat_types(&self.ty, types).unwrap() {
1090 dst.push((*ty).into());
1091 }
1092 }
1093 HelperLocation::Memory => {
1094 dst.push(self.opts.data_model.unwrap_memory().ptr());
1095 }
1096 HelperLocation::StructField | HelperLocation::ArrayElement => todo!("CM+GC"),
1097 }
1098 }
1099}