1use crate::component::dfg::CoreDef;
22use crate::component::{
23 Adapter, AdapterOptions as AdapterOptionsDfg, CanonicalAbiInfo, ComponentTypesBuilder,
24 FlatType, InterfaceType, RuntimeComponentInstanceIndex, StringEncoding, Transcode,
25 TypeFuncIndex, 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 task_may_block: Option<GlobalIndex>,
118}
119
120struct AdapterData {
121 name: String,
123 lift: AdapterOptions,
125 lower: AdapterOptions,
127 callee: FuncIndex,
130}
131
132struct AdapterOptions {
137 instance: RuntimeComponentInstanceIndex,
140 ancestors: Vec<RuntimeComponentInstanceIndex>,
143 ty: TypeFuncIndex,
145 flags: GlobalIndex,
148 post_return: Option<FuncIndex>,
150 options: Options,
152}
153
154#[derive(PartialEq, Eq, Hash, Copy, Clone)]
155struct LinearMemoryOptions {
157 memory: Option<(MemoryIndex, Memory)>,
160 realloc: Option<FuncIndex>,
163}
164
165impl LinearMemoryOptions {
166 fn ptr(&self) -> ValType {
167 if self.memory64() {
168 ValType::I64
169 } else {
170 ValType::I32
171 }
172 }
173
174 fn ptr_size(&self) -> u8 {
175 if self.memory64() { 8 } else { 4 }
176 }
177
178 fn memory64(&self) -> bool {
179 self.memory
180 .as_ref()
181 .map(|(_, ty)| ty.idx_type == IndexType::I64)
182 .unwrap_or(false)
183 }
184
185 fn sizealign(&self, abi: &CanonicalAbiInfo) -> (u32, u32) {
186 if self.memory64() {
187 (abi.size64, abi.align64)
188 } else {
189 (abi.size32, abi.align32)
190 }
191 }
192}
193
194#[derive(PartialEq, Eq, Hash, Copy, Clone)]
196enum DataModel {
197 Gc {},
198 LinearMemory(LinearMemoryOptions),
199}
200
201impl DataModel {
202 #[track_caller]
203 fn unwrap_memory(&self) -> &LinearMemoryOptions {
204 match self {
205 DataModel::Gc {} => panic!("`unwrap_memory` on GC"),
206 DataModel::LinearMemory(opts) => opts,
207 }
208 }
209}
210
211#[derive(PartialEq, Eq, Hash, Copy, Clone)]
216struct Options {
217 string_encoding: StringEncoding,
219 callback: Option<FuncIndex>,
220 async_: bool,
221 core_type: ModuleInternedTypeIndex,
222 data_model: DataModel,
223}
224
225#[derive(Copy, Clone, PartialEq, Eq, Hash)]
233struct Helper {
234 src: HelperType,
236 dst: HelperType,
238}
239
240#[derive(Copy, Clone, PartialEq, Eq, Hash)]
243struct HelperType {
244 ty: InterfaceType,
246 opts: Options,
248 loc: HelperLocation,
250}
251
252#[derive(Copy, Clone, PartialEq, Eq, Hash)]
255enum HelperLocation {
256 Stack,
258 Memory,
260 #[expect(dead_code, reason = "CM+GC is still WIP")]
262 StructField,
263 #[expect(dead_code, reason = "CM+GC is still WIP")]
265 ArrayElement,
266}
267
268impl<'a> Module<'a> {
269 pub fn new(
271 types: &'a ComponentTypesBuilder,
272 tunables: &'a Tunables,
273 features: WasmFeatures,
274 ) -> Module<'a> {
275 Module {
276 tunables,
277 types,
278 features,
279 core_types: Default::default(),
280 core_imports: Default::default(),
281 imported: Default::default(),
282 imports: Default::default(),
283 imported_transcoders: Default::default(),
284 imported_funcs: PrimaryMap::new(),
285 imported_memories: PrimaryMap::new(),
286 imported_globals: PrimaryMap::new(),
287 funcs: PrimaryMap::new(),
288 helper_funcs: HashMap::new(),
289 helper_worklist: Vec::new(),
290 imported_resource_transfer_own: None,
291 imported_resource_transfer_borrow: None,
292 imported_async_start_calls: HashMap::new(),
293 imported_future_transfer: None,
294 imported_stream_transfer: None,
295 imported_error_context_transfer: None,
296 imported_enter_sync_call: None,
297 imported_exit_sync_call: None,
298 imported_unsafe_intrinsics: HashMap::new(),
299 imported_traps: HashMap::new(),
300 exports: Vec::new(),
301 task_may_block: None,
302 }
303 }
304
305 pub fn adapt(&mut self, name: &str, adapter: &Adapter) {
310 let mut lift = self.import_options(adapter.lift_ty, &adapter.lift_options);
313 let lower = self.import_options(adapter.lower_ty, &adapter.lower_options);
314
315 assert!(adapter.lower_options.post_return.is_none());
318
319 let signature = self.types.signature(&lift);
323 let ty = self
324 .core_types
325 .function(&signature.params, &signature.results);
326 let callee = self.import_func("callee", name, ty, adapter.func.clone());
327
328 lift.post_return = adapter.lift_options.post_return.as_ref().map(|func| {
331 let ty = self.core_types.function(&signature.results, &[]);
332 self.import_func("post_return", name, ty, func.clone())
333 });
334
335 trampoline::compile(
338 self,
339 &AdapterData {
340 name: name.to_string(),
341 lift,
342 lower,
343 callee,
344 },
345 );
346
347 while let Some((result, helper)) = self.helper_worklist.pop() {
348 trampoline::compile_helper(self, result, helper);
349 }
350 }
351
352 fn import_options(&mut self, ty: TypeFuncIndex, options: &AdapterOptionsDfg) -> AdapterOptions {
353 let AdapterOptionsDfg {
354 instance,
355 ancestors,
356 string_encoding,
357 post_return: _, callback,
359 async_,
360 core_type,
361 data_model,
362 cancellable,
363 } = options;
364 assert!(!cancellable);
365
366 let flags = self.import_global(
367 "flags",
368 &format!("instance{}", instance.as_u32()),
369 GlobalType {
370 val_type: ValType::I32,
371 mutable: true,
372 shared: false,
373 },
374 CoreDef::InstanceFlags(*instance),
375 );
376
377 let data_model = match data_model {
378 crate::component::DataModel::Gc {} => DataModel::Gc {},
379 crate::component::DataModel::LinearMemory { memory, realloc } => {
380 let memory = memory.as_ref().map(|(memory, ty)| {
381 (
382 self.import_memory(
383 "memory",
384 &format!("m{}", self.imported_memories.len()),
385 MemoryType {
386 minimum: 0,
387 maximum: None,
388 shared: ty.shared,
389 memory64: ty.idx_type == IndexType::I64,
390 page_size_log2: if ty.page_size_log2 == 16 {
391 None
392 } else {
393 Some(ty.page_size_log2.into())
394 },
395 },
396 memory.clone().into(),
397 ),
398 *ty,
399 )
400 });
401 let realloc = realloc.as_ref().map(|func| {
402 let ptr = match memory.as_ref().unwrap().1.idx_type {
403 IndexType::I32 => ValType::I32,
404 IndexType::I64 => ValType::I64,
405 };
406 let ty = self.core_types.function(&[ptr, ptr, ptr, ptr], &[ptr]);
407 self.import_func(
408 "realloc",
409 &format!("f{}", self.imported_funcs.len()),
410 ty,
411 func.clone(),
412 )
413 });
414 DataModel::LinearMemory(LinearMemoryOptions { memory, realloc })
415 }
416 };
417
418 let callback = callback.as_ref().map(|func| {
419 let ty = self
420 .core_types
421 .function(&[ValType::I32, ValType::I32, ValType::I32], &[ValType::I32]);
422 self.import_func(
423 "callback",
424 &format!("f{}", self.imported_funcs.len()),
425 ty,
426 func.clone(),
427 )
428 });
429
430 AdapterOptions {
431 instance: *instance,
432 ancestors: ancestors.clone(),
433 ty,
434 flags,
435 post_return: None,
436 options: Options {
437 string_encoding: *string_encoding,
438 callback,
439 async_: *async_,
440 core_type: *core_type,
441 data_model,
442 },
443 }
444 }
445
446 fn import_func(&mut self, module: &str, name: &str, ty: u32, def: CoreDef) -> FuncIndex {
447 self.import(module, name, EntityType::Function(ty), def, |m| {
448 &mut m.imported_funcs
449 })
450 }
451
452 fn import_global(
453 &mut self,
454 module: &str,
455 name: &str,
456 ty: GlobalType,
457 def: CoreDef,
458 ) -> GlobalIndex {
459 self.import(module, name, EntityType::Global(ty), def, |m| {
460 &mut m.imported_globals
461 })
462 }
463
464 fn import_memory(
465 &mut self,
466 module: &str,
467 name: &str,
468 ty: MemoryType,
469 def: CoreDef,
470 ) -> MemoryIndex {
471 self.import(module, name, EntityType::Memory(ty), def, |m| {
472 &mut m.imported_memories
473 })
474 }
475
476 fn import<K: EntityRef, V: From<CoreDef>>(
477 &mut self,
478 module: &str,
479 name: &str,
480 ty: EntityType,
481 def: CoreDef,
482 map: impl FnOnce(&mut Self) -> &mut PrimaryMap<K, V>,
483 ) -> K {
484 if let Some(prev) = self.imported.get(&def) {
485 return K::new(*prev);
486 }
487 let idx = map(self).push(def.clone().into());
488 self.core_imports.import(module, name, ty);
489 self.imported.insert(def.clone(), idx.index());
490 self.imports.push(Import::CoreDef(def));
491 idx
492 }
493
494 fn import_task_may_block(&mut self) -> GlobalIndex {
495 if let Some(task_may_block) = self.task_may_block {
496 task_may_block
497 } else {
498 let task_may_block = self.import_global(
499 "instance",
500 "task_may_block",
501 GlobalType {
502 val_type: ValType::I32,
503 mutable: true,
504 shared: false,
505 },
506 CoreDef::TaskMayBlock,
507 );
508 self.task_may_block = Some(task_may_block);
509 task_may_block
510 }
511 }
512
513 fn import_transcoder(&mut self, transcoder: transcode::Transcoder) -> FuncIndex {
514 *self
515 .imported_transcoders
516 .entry(transcoder)
517 .or_insert_with(|| {
518 let name = transcoder.name();
520 let ty = transcoder.ty(&mut self.core_types);
521 self.core_imports.import("transcode", &name, ty);
522
523 let from = self.imported_memories[transcoder.from_memory].clone();
526 let to = self.imported_memories[transcoder.to_memory].clone();
527 self.imports.push(Import::Transcode {
528 op: transcoder.op,
529 from,
530 from64: transcoder.from_memory64,
531 to,
532 to64: transcoder.to_memory64,
533 });
534
535 self.imported_funcs.push(None)
536 })
537 }
538
539 fn import_simple(
540 &mut self,
541 module: &str,
542 name: &str,
543 params: &[ValType],
544 results: &[ValType],
545 import: Import,
546 get: impl Fn(&mut Self) -> &mut Option<FuncIndex>,
547 ) -> FuncIndex {
548 self.import_simple_get_and_set(
549 module,
550 name,
551 params,
552 results,
553 import,
554 |me| *get(me),
555 |me, v| *get(me) = Some(v),
556 )
557 }
558
559 fn import_simple_get_and_set(
560 &mut self,
561 module: &str,
562 name: &str,
563 params: &[ValType],
564 results: &[ValType],
565 import: Import,
566 get: impl Fn(&mut Self) -> Option<FuncIndex>,
567 set: impl Fn(&mut Self, FuncIndex),
568 ) -> FuncIndex {
569 if let Some(idx) = get(self) {
570 return idx;
571 }
572 let ty = self.core_types.function(params, results);
573 let ty = EntityType::Function(ty);
574 self.core_imports.import(module, name, ty);
575
576 self.imports.push(import);
577 let idx = self.imported_funcs.push(None);
578 set(self, idx);
579 idx
580 }
581
582 fn import_prepare_call(
590 &mut self,
591 suffix: &str,
592 params: &[ValType],
593 memory: Option<MemoryIndex>,
594 ) -> FuncIndex {
595 let ty = self.core_types.function(
596 &PREPARE_CALL_FIXED_PARAMS
597 .iter()
598 .copied()
599 .chain(params.iter().copied())
600 .collect::<Vec<_>>(),
601 &[],
602 );
603 self.core_imports.import(
604 "sync",
605 &format!("[prepare-call]{suffix}"),
606 EntityType::Function(ty),
607 );
608 let import = Import::PrepareCall {
609 memory: memory.map(|v| self.imported_memories[v].clone()),
610 };
611 self.imports.push(import);
612 self.imported_funcs.push(None)
613 }
614
615 fn import_sync_start_call(
627 &mut self,
628 suffix: &str,
629 callback: Option<FuncIndex>,
630 results: &[ValType],
631 ) -> FuncIndex {
632 let ty = self
633 .core_types
634 .function(&[ValType::FUNCREF, ValType::I32], results);
635 self.core_imports.import(
636 "sync",
637 &format!("[start-call]{suffix}"),
638 EntityType::Function(ty),
639 );
640 let import = Import::SyncStartCall {
641 callback: callback
642 .map(|callback| self.imported_funcs.get(callback).unwrap().clone().unwrap()),
643 };
644 self.imports.push(import);
645 self.imported_funcs.push(None)
646 }
647
648 fn import_async_start_call(
657 &mut self,
658 suffix: &str,
659 callback: Option<FuncIndex>,
660 post_return: Option<FuncIndex>,
661 ) -> FuncIndex {
662 self.import_simple_get_and_set(
663 "async",
664 &format!("[start-call]{suffix}"),
665 &[ValType::FUNCREF, ValType::I32, ValType::I32, ValType::I32],
666 &[ValType::I32],
667 Import::AsyncStartCall {
668 callback: callback
669 .map(|callback| self.imported_funcs.get(callback).unwrap().clone().unwrap()),
670 post_return: post_return.map(|post_return| {
671 self.imported_funcs
672 .get(post_return)
673 .unwrap()
674 .clone()
675 .unwrap()
676 }),
677 },
678 |me| {
679 me.imported_async_start_calls
680 .get(&(callback, post_return))
681 .copied()
682 },
683 |me, v| {
684 assert!(
685 me.imported_async_start_calls
686 .insert((callback, post_return), v)
687 .is_none()
688 )
689 },
690 )
691 }
692
693 fn import_future_transfer(&mut self) -> FuncIndex {
694 self.import_simple(
695 "future",
696 "transfer",
697 &[ValType::I32; 3],
698 &[ValType::I32],
699 Import::FutureTransfer,
700 |me| &mut me.imported_future_transfer,
701 )
702 }
703
704 fn import_stream_transfer(&mut self) -> FuncIndex {
705 self.import_simple(
706 "stream",
707 "transfer",
708 &[ValType::I32; 3],
709 &[ValType::I32],
710 Import::StreamTransfer,
711 |me| &mut me.imported_stream_transfer,
712 )
713 }
714
715 fn import_error_context_transfer(&mut self) -> FuncIndex {
716 self.import_simple(
717 "error-context",
718 "transfer",
719 &[ValType::I32; 3],
720 &[ValType::I32],
721 Import::ErrorContextTransfer,
722 |me| &mut me.imported_error_context_transfer,
723 )
724 }
725
726 fn import_resource_transfer_own(&mut self) -> FuncIndex {
727 self.import_simple(
728 "resource",
729 "transfer-own",
730 &[ValType::I32, ValType::I32, ValType::I32],
731 &[ValType::I32],
732 Import::ResourceTransferOwn,
733 |me| &mut me.imported_resource_transfer_own,
734 )
735 }
736
737 fn import_resource_transfer_borrow(&mut self) -> FuncIndex {
738 self.import_simple(
739 "resource",
740 "transfer-borrow",
741 &[ValType::I32, ValType::I32, ValType::I32],
742 &[ValType::I32],
743 Import::ResourceTransferBorrow,
744 |me| &mut me.imported_resource_transfer_borrow,
745 )
746 }
747
748 fn import_enter_sync_call(&mut self) -> FuncIndex {
749 self.import_simple(
750 "async",
751 "enter-sync-call",
752 &[ValType::I32; 3],
753 &[],
754 Import::EnterSyncCall,
755 |me| &mut me.imported_enter_sync_call,
756 )
757 }
758
759 fn import_exit_sync_call(&mut self) -> FuncIndex {
760 self.import_simple(
761 "async",
762 "exit-sync-call",
763 &[],
764 &[],
765 Import::ExitSyncCall,
766 |me| &mut me.imported_exit_sync_call,
767 )
768 }
769
770 fn import_context_get(&mut self, slot: usize) -> FuncIndex {
772 let intrinsic = match slot {
773 0 => UnsafeIntrinsic::ContextGetI32_0,
774 1 => UnsafeIntrinsic::ContextGetI32_1,
775 _ => unreachable!(),
776 };
777 self.import_unsafe_intrinsic(intrinsic, &format!("get{slot}"))
778 }
779
780 fn import_context_set(&mut self, slot: usize) -> FuncIndex {
782 let intrinsic = match slot {
783 0 => UnsafeIntrinsic::ContextSetI32_0,
784 1 => UnsafeIntrinsic::ContextSetI32_1,
785 _ => unreachable!(),
786 };
787 self.import_unsafe_intrinsic(intrinsic, &format!("set{slot}"))
788 }
789
790 fn import_unsafe_intrinsic(&mut self, intrinsic: UnsafeIntrinsic, name: &str) -> FuncIndex {
791 let map = |ty: &WasmValType| match ty {
792 crate::WasmValType::I32 => ValType::I32,
793 crate::WasmValType::I64 => ValType::I64,
794 crate::WasmValType::F32 => ValType::F32,
795 crate::WasmValType::F64 => ValType::F64,
796 crate::WasmValType::V128 => ValType::V128,
797 crate::WasmValType::Ref(_) => unreachable!(),
798 };
799 let params = intrinsic.core_params().iter().map(map).collect::<Vec<_>>();
800 let results = intrinsic.core_results().iter().map(map).collect::<Vec<_>>();
801
802 self.import_simple_get_and_set(
803 "context",
804 name,
805 ¶ms,
806 &results,
807 Import::UnsafeIntrinsic(intrinsic),
808 |me| me.imported_unsafe_intrinsics.get(&intrinsic).copied(),
809 |me, idx| {
810 me.imported_unsafe_intrinsics.insert(intrinsic, idx);
811 },
812 )
813 }
814
815 fn import_trap(&mut self, trap: Trap) -> FuncIndex {
816 let name = format!("trap{}", trap as u8);
817 self.import_simple_get_and_set(
818 "runtime",
819 &name,
820 &[],
821 &[],
822 Import::Trap(trap),
823 |me| me.imported_traps.get(&trap).copied(),
824 |me, idx| {
825 me.imported_traps.insert(trap, idx);
826 },
827 )
828 }
829
830 fn translate_helper(&mut self, helper: Helper) -> FunctionId {
831 *self.helper_funcs.entry(helper).or_insert_with(|| {
832 let ty = helper.core_type(self.types, &mut self.core_types);
835 let id = self.funcs.push(Function::new(None, ty));
836 self.helper_worklist.push((id, helper));
837 id
838 })
839 }
840
841 pub fn encode(&mut self) -> Vec<u8> {
843 let mut funcs = FunctionSection::new();
847 let mut exports = ExportSection::new();
848 let mut id_to_index = PrimaryMap::<FunctionId, FuncIndex>::new();
849 for (id, func) in self.funcs.iter() {
850 assert!(func.filled_in);
851 let idx = FuncIndex::from_u32(self.imported_funcs.next_key().as_u32() + id.as_u32());
852 let id2 = id_to_index.push(idx);
853 assert_eq!(id2, id);
854
855 funcs.function(func.ty);
856
857 if let Some(name) = &func.export {
858 exports.export(name, ExportKind::Func, idx.as_u32());
859 }
860 }
861 for (idx, name) in &self.exports {
862 exports.export(name, ExportKind::Func, *idx);
863 }
864
865 let mut code = CodeSection::new();
868 for (_, func) in self.funcs.iter() {
869 let mut body = Vec::new();
870
871 func.locals.len().encode(&mut body);
873 for (count, ty) in func.locals.iter() {
874 count.encode(&mut body);
875 ty.encode(&mut body);
876 }
877
878 for chunk in func.body.iter() {
883 match chunk {
884 Body::Raw(code) => {
885 body.extend_from_slice(code);
886 }
887 Body::Call(id) => {
888 Instruction::Call(id_to_index[*id].as_u32()).encode(&mut body);
889 }
890 Body::RefFunc(id) => {
891 Instruction::RefFunc(id_to_index[*id].as_u32()).encode(&mut body);
892 }
893 }
894 }
895 code.raw(&body);
896 }
897
898 let mut result = wasm_encoder::Module::new();
899 result.section(&self.core_types.section);
900 result.section(&self.core_imports);
901 result.section(&funcs);
902 result.section(&exports);
903 result.section(&code);
904 result.finish()
905 }
906
907 pub fn imports(&self) -> &[Import] {
910 &self.imports
911 }
912}
913
914#[derive(Clone)]
916pub enum Import {
917 CoreDef(CoreDef),
919 Transcode {
921 op: Transcode,
923 from: CoreDef,
925 from64: bool,
927 to: CoreDef,
929 to64: bool,
931 },
932 ResourceTransferOwn,
934 ResourceTransferBorrow,
936 PrepareCall {
939 memory: Option<CoreDef>,
943 },
944 SyncStartCall {
947 callback: Option<CoreDef>,
949 },
950 AsyncStartCall {
953 callback: Option<CoreDef>,
955
956 post_return: Option<CoreDef>,
958 },
959 FutureTransfer,
962 StreamTransfer,
965 ErrorContextTransfer,
968 Trap(Trap),
970 EnterSyncCall,
974 ExitSyncCall,
977 UnsafeIntrinsic(UnsafeIntrinsic),
979}
980
981impl Options {
982 fn flat_types<'a>(
983 &self,
984 ty: &InterfaceType,
985 types: &'a ComponentTypesBuilder,
986 ) -> Option<&'a [FlatType]> {
987 let flat = types.flat_types(ty)?;
988 match self.data_model {
989 DataModel::Gc {} => todo!("CM+GC"),
990 DataModel::LinearMemory(mem_opts) => Some(if mem_opts.memory64() {
991 flat.memory64
992 } else {
993 flat.memory32
994 }),
995 }
996 }
997}
998
999#[derive(Debug, Copy, Clone, PartialEq, Eq)]
1005struct FunctionId(u32);
1006cranelift_entity::entity_impl!(FunctionId);
1007
1008struct Function {
1013 filled_in: bool,
1019
1020 ty: u32,
1023
1024 locals: Vec<(u32, ValType)>,
1027
1028 export: Option<String>,
1030
1031 body: Vec<Body>,
1036}
1037
1038enum Body {
1060 Raw(Vec<u8>),
1061 Call(FunctionId),
1062 RefFunc(FunctionId),
1063}
1064
1065impl Function {
1066 fn new(export: Option<String>, ty: u32) -> Function {
1067 Function {
1068 filled_in: false,
1069 ty,
1070 locals: Vec::new(),
1071 export,
1072 body: Vec::new(),
1073 }
1074 }
1075}
1076
1077impl Helper {
1078 fn core_type(
1079 &self,
1080 types: &ComponentTypesBuilder,
1081 core_types: &mut core_types::CoreTypes,
1082 ) -> u32 {
1083 let mut params = Vec::new();
1084 let mut results = Vec::new();
1085 self.src.push_flat(&mut params, types);
1089
1090 match self.dst.loc {
1094 HelperLocation::Stack => self.dst.push_flat(&mut results, types),
1095 HelperLocation::Memory => params.push(self.dst.opts.data_model.unwrap_memory().ptr()),
1096 HelperLocation::StructField | HelperLocation::ArrayElement => todo!("CM+GC"),
1097 }
1098
1099 core_types.function(¶ms, &results)
1100 }
1101}
1102
1103impl HelperType {
1104 fn push_flat(&self, dst: &mut Vec<ValType>, types: &ComponentTypesBuilder) {
1105 match self.loc {
1106 HelperLocation::Stack => {
1107 for ty in self.opts.flat_types(&self.ty, types).unwrap() {
1108 dst.push((*ty).into());
1109 }
1110 }
1111 HelperLocation::Memory => {
1112 dst.push(self.opts.data_model.unwrap_memory().ptr());
1113 }
1114 HelperLocation::StructField | HelperLocation::ArrayElement => todo!("CM+GC"),
1115 }
1116 }
1117}