1use crate::component::*;
31use crate::error::Result;
32use crate::prelude::*;
33use crate::{
34 EntityIndex, EntityRef, ModuleInternedTypeIndex, PanicOnOom as _, PrimaryMap, Trap, WasmValType,
35};
36use cranelift_entity::EntitySet;
37use cranelift_entity::packed_option::PackedOption;
38use indexmap::IndexMap;
39use info::LinearMemoryOptions;
40use std::collections::HashMap;
41use std::hash::Hash;
42use std::ops::Index;
43use wasmparser::component_types::ComponentCoreModuleTypeId;
44
45#[derive(Default)]
47pub struct ComponentDfg {
48 pub import_types: PrimaryMap<ImportIndex, (String, ComponentExtern)>,
50
51 pub imports: PrimaryMap<RuntimeImportIndex, (ImportIndex, Vec<String>)>,
53
54 pub exports: IndexMap<String, (Export, ComponentExternData)>,
56
57 pub trampolines: Intern<TrampolineIndex, (ModuleInternedTypeIndex, Trampoline)>,
60
61 pub unsafe_intrinsics: [PackedOption<ModuleInternedTypeIndex>; UnsafeIntrinsic::len() as usize],
64
65 pub reallocs: Intern<ReallocId, CoreDef>,
68
69 pub callbacks: Intern<CallbackId, CoreDef>,
71
72 pub post_returns: Intern<PostReturnId, CoreDef>,
74
75 pub memories: Intern<MemoryId, CoreExport<MemoryIndex>>,
77
78 pub tables: Intern<TableId, CoreExport<TableIndex>>,
80
81 pub adapters: Intern<AdapterId, Adapter>,
87
88 pub instances: PrimaryMap<InstanceId, Instance>,
95
96 pub num_runtime_component_instances: u32,
99
100 pub adapter_modules: PrimaryMap<AdapterModuleId, (StaticModuleIndex, Vec<CoreDef>)>,
110
111 pub adapter_partitionings: PrimaryMap<AdapterId, (AdapterModuleId, EntityIndex)>,
122
123 pub resources: PrimaryMap<DefinedResourceIndex, Resource>,
129
130 pub imported_resources: PrimaryMap<ResourceIndex, RuntimeImportIndex>,
134
135 pub num_future_tables: usize,
137
138 pub num_stream_tables: usize,
140
141 pub num_error_context_tables: usize,
144
145 pub side_effects: Vec<SideEffect>,
152
153 pub options: Intern<OptionsId, CanonicalOptions>,
156
157 pub transparent_adapters: EntitySet<AdapterId>,
160}
161
162pub enum SideEffect {
164 Instance(InstanceId, RuntimeComponentInstanceIndex),
171
172 Resource(DefinedResourceIndex),
179}
180
181#[derive(Clone, Copy, Default)]
187pub enum AbstractInstantiations<'a> {
188 Many,
190
191 One(&'a [info::CoreDef]),
194
195 #[default]
197 None,
198}
199
200impl AbstractInstantiations<'_> {
201 pub fn join(&mut self, other: Self) {
205 *self = match (*self, other) {
206 (Self::Many, _) | (_, Self::Many) => Self::Many,
207 (Self::One(a), Self::One(b)) if a == b => Self::One(a),
208 (Self::One(_), Self::One(_)) => Self::Many,
209 (Self::One(a), Self::None) | (Self::None, Self::One(a)) => Self::One(a),
210 (Self::None, Self::None) => Self::None,
211 }
212 }
213}
214
215macro_rules! id {
216 ($(pub struct $name:ident(u32);)*) => ($(
217 #[derive(Debug, Copy, Clone, Hash, Eq, PartialEq)]
218 #[expect(missing_docs, reason = "tedious to document")]
219 pub struct $name(u32);
220 cranelift_entity::entity_impl!($name);
221 )*)
222}
223
224id! {
225 pub struct InstanceId(u32);
226 pub struct MemoryId(u32);
227 pub struct TableId(u32);
228 pub struct ReallocId(u32);
229 pub struct CallbackId(u32);
230 pub struct AdapterId(u32);
231 pub struct PostReturnId(u32);
232 pub struct AdapterModuleId(u32);
233 pub struct OptionsId(u32);
234}
235
236#[expect(missing_docs, reason = "tedious to document variants")]
238pub enum Instance {
239 Static(StaticModuleIndex, Box<[CoreDef]>),
240 Import(
241 RuntimeImportIndex,
242 IndexMap<String, IndexMap<String, CoreDef>>,
243 ),
244}
245
246#[expect(missing_docs, reason = "tedious to document variants")]
248pub enum Export {
249 LiftedFunction {
250 ty: TypeFuncIndex,
251 func: CoreDef,
252 options: OptionsId,
253 },
254 ModuleStatic {
255 ty: ComponentCoreModuleTypeId,
256 index: StaticModuleIndex,
257 },
258 ModuleImport {
259 ty: TypeModuleIndex,
260 import: RuntimeImportIndex,
261 },
262 Instance {
263 ty: TypeComponentInstanceIndex,
264 exports: IndexMap<String, (Export, ComponentExternData)>,
265 },
266 Type(TypeDef),
267}
268
269#[derive(Debug, Clone, Hash, Eq, PartialEq)]
271#[expect(missing_docs, reason = "tedious to document variants")]
272pub enum CoreDef {
273 Export(CoreExport<EntityIndex>),
274 InstanceFlags(RuntimeComponentInstanceIndex),
275 Trampoline(TrampolineIndex),
276 UnsafeIntrinsic(ModuleInternedTypeIndex, UnsafeIntrinsic),
277
278 Adapter(AdapterId),
287}
288
289impl<T> From<CoreExport<T>> for CoreDef
290where
291 EntityIndex: From<T>,
292{
293 fn from(export: CoreExport<T>) -> CoreDef {
294 CoreDef::Export(export.map_index(|i| i.into()))
295 }
296}
297
298#[derive(Debug, Clone, Hash, Eq, PartialEq)]
300#[expect(missing_docs, reason = "self-describing fields")]
301pub struct CoreExport<T> {
302 pub instance: InstanceId,
303 pub item: ExportItem<T>,
304}
305
306#[derive(Debug, Clone, Hash, Eq, PartialEq)]
308#[expect(missing_docs, reason = "self-describing variants")]
309pub enum ExportItem<T> {
310 Index(T),
311 Name(String),
312}
313
314impl<T> CoreExport<T> {
315 #[expect(missing_docs, reason = "self-describing function")]
316 pub fn map_index<U>(self, f: impl FnOnce(T) -> U) -> CoreExport<U> {
317 CoreExport {
318 instance: self.instance,
319 item: match self.item {
320 ExportItem::Index(i) => ExportItem::Index(f(i)),
321 ExportItem::Name(s) => ExportItem::Name(s),
322 },
323 }
324 }
325}
326
327#[derive(Clone, PartialEq, Eq, Hash)]
329#[expect(missing_docs, reason = "self-describing fields")]
330pub enum Trampoline {
331 LowerImport {
332 import: RuntimeImportIndex,
333 options: OptionsId,
334 lower_ty: TypeFuncIndex,
335 },
336 Transcoder {
337 op: Transcode,
338 from: MemoryId,
339 from64: bool,
340 to: MemoryId,
341 to64: bool,
342 },
343 ResourceNew {
344 instance: RuntimeComponentInstanceIndex,
345 ty: TypeResourceTableIndex,
346 },
347 ResourceRep {
348 instance: RuntimeComponentInstanceIndex,
349 ty: TypeResourceTableIndex,
350 },
351 ResourceDrop {
352 instance: RuntimeComponentInstanceIndex,
353 ty: TypeResourceTableIndex,
354 },
355 BackpressureInc {
356 instance: RuntimeComponentInstanceIndex,
357 },
358 BackpressureDec {
359 instance: RuntimeComponentInstanceIndex,
360 },
361 TaskReturn {
362 instance: RuntimeComponentInstanceIndex,
363 results: TypeTupleIndex,
364 options: OptionsId,
365 },
366 TaskCancel {
367 instance: RuntimeComponentInstanceIndex,
368 },
369 WaitableSetNew {
370 instance: RuntimeComponentInstanceIndex,
371 },
372 WaitableSetWait {
373 instance: RuntimeComponentInstanceIndex,
374 options: OptionsId,
375 },
376 WaitableSetPoll {
377 instance: RuntimeComponentInstanceIndex,
378 options: OptionsId,
379 },
380 WaitableSetDrop {
381 instance: RuntimeComponentInstanceIndex,
382 },
383 WaitableJoin {
384 instance: RuntimeComponentInstanceIndex,
385 },
386 SubtaskDrop {
387 instance: RuntimeComponentInstanceIndex,
388 },
389 SubtaskCancel {
390 instance: RuntimeComponentInstanceIndex,
391 async_: bool,
392 },
393 StreamNew {
394 instance: RuntimeComponentInstanceIndex,
395 ty: TypeStreamTableIndex,
396 },
397 StreamRead {
398 instance: RuntimeComponentInstanceIndex,
399 ty: TypeStreamTableIndex,
400 options: OptionsId,
401 },
402 StreamWrite {
403 instance: RuntimeComponentInstanceIndex,
404 ty: TypeStreamTableIndex,
405 options: OptionsId,
406 },
407 StreamCancelRead {
408 instance: RuntimeComponentInstanceIndex,
409 ty: TypeStreamTableIndex,
410 async_: bool,
411 },
412 StreamCancelWrite {
413 instance: RuntimeComponentInstanceIndex,
414 ty: TypeStreamTableIndex,
415 async_: bool,
416 },
417 StreamDropReadable {
418 instance: RuntimeComponentInstanceIndex,
419 ty: TypeStreamTableIndex,
420 },
421 StreamDropWritable {
422 instance: RuntimeComponentInstanceIndex,
423 ty: TypeStreamTableIndex,
424 },
425 FutureNew {
426 instance: RuntimeComponentInstanceIndex,
427 ty: TypeFutureTableIndex,
428 },
429 FutureRead {
430 instance: RuntimeComponentInstanceIndex,
431 ty: TypeFutureTableIndex,
432 options: OptionsId,
433 },
434 FutureWrite {
435 instance: RuntimeComponentInstanceIndex,
436 ty: TypeFutureTableIndex,
437 options: OptionsId,
438 },
439 FutureCancelRead {
440 instance: RuntimeComponentInstanceIndex,
441 ty: TypeFutureTableIndex,
442 async_: bool,
443 },
444 FutureCancelWrite {
445 instance: RuntimeComponentInstanceIndex,
446 ty: TypeFutureTableIndex,
447 async_: bool,
448 },
449 FutureDropReadable {
450 instance: RuntimeComponentInstanceIndex,
451 ty: TypeFutureTableIndex,
452 },
453 FutureDropWritable {
454 instance: RuntimeComponentInstanceIndex,
455 ty: TypeFutureTableIndex,
456 },
457 ErrorContextNew {
458 instance: RuntimeComponentInstanceIndex,
459 ty: TypeComponentLocalErrorContextTableIndex,
460 options: OptionsId,
461 },
462 ErrorContextDebugMessage {
463 instance: RuntimeComponentInstanceIndex,
464 ty: TypeComponentLocalErrorContextTableIndex,
465 options: OptionsId,
466 },
467 ErrorContextDrop {
468 instance: RuntimeComponentInstanceIndex,
469 ty: TypeComponentLocalErrorContextTableIndex,
470 },
471 ResourceTransferOwn,
472 ResourceTransferBorrow,
473 ResourceTransferBorrowToOwner,
474 PrepareCall {
475 memory: Option<MemoryId>,
476 },
477 StartCall {
478 callback: Option<CallbackId>,
479 post_return: Option<PostReturnId>,
480 },
481 FutureTransfer,
482 StreamTransfer,
483 ErrorContextTransfer,
484 Trap(Trap),
485 HostcallFuel,
486 EnterSyncCall,
487 ExitSyncCall,
488 ThreadIndex {
489 instance: RuntimeComponentInstanceIndex,
490 },
491 ThreadNewIndirect {
492 instance: RuntimeComponentInstanceIndex,
493 start_func_ty_idx: ModuleInternedTypeIndex,
494 start_func_table_id: TableId,
495 },
496 ThreadResumeLater {
497 instance: RuntimeComponentInstanceIndex,
498 },
499 ThreadSuspend {
500 instance: RuntimeComponentInstanceIndex,
501 },
502 ThreadYield {
503 instance: RuntimeComponentInstanceIndex,
504 },
505 ThreadSuspendThenResume {
506 instance: RuntimeComponentInstanceIndex,
507 },
508 ThreadYieldThenResume {
509 instance: RuntimeComponentInstanceIndex,
510 },
511 ThreadSuspendThenPromote {
512 instance: RuntimeComponentInstanceIndex,
513 },
514 ThreadYieldThenPromote {
515 instance: RuntimeComponentInstanceIndex,
516 },
517}
518
519#[derive(Copy, Clone, Hash, Eq, PartialEq)]
520#[expect(missing_docs, reason = "self-describing fields")]
521pub struct FutureInfo {
522 pub instance: RuntimeComponentInstanceIndex,
523 pub payload_type: Option<InterfaceType>,
524}
525
526#[derive(Copy, Clone, Hash, Eq, PartialEq)]
527#[expect(missing_docs, reason = "self-describing fields")]
528pub struct StreamInfo {
529 pub instance: RuntimeComponentInstanceIndex,
530 pub payload_type: InterfaceType,
531}
532
533#[derive(Clone, Hash, Eq, PartialEq)]
535#[expect(missing_docs, reason = "self-describing fields")]
536pub enum CanonicalOptionsDataModel {
537 Gc {},
538 LinearMemory {
539 memory: Option<MemoryId>,
540 realloc: Option<ReallocId>,
541 },
542}
543
544#[derive(Clone, Hash, Eq, PartialEq)]
546#[expect(missing_docs, reason = "self-describing fields")]
547pub struct CanonicalOptions {
548 pub instance: RuntimeComponentInstanceIndex,
549 pub string_encoding: StringEncoding,
550 pub callback: Option<CallbackId>,
551 pub post_return: Option<PostReturnId>,
552 pub async_: bool,
553 pub core_type: ModuleInternedTypeIndex,
554 pub data_model: CanonicalOptionsDataModel,
555}
556
557#[expect(missing_docs, reason = "self-describing fields")]
559pub struct Resource {
560 pub rep: WasmValType,
561 pub dtor: Option<CoreDef>,
562 pub instance: RuntimeComponentInstanceIndex,
563}
564
565pub struct Intern<K: EntityRef, V> {
571 intern_map: HashMap<V, K>,
572 key_map: PrimaryMap<K, V>,
573}
574
575impl<K, V> Intern<K, V>
576where
577 K: EntityRef,
578{
579 pub fn push(&mut self, value: V) -> K
586 where
587 V: Hash + Eq + Clone,
588 {
589 *self
590 .intern_map
591 .entry(value.clone())
592 .or_insert_with(|| self.key_map.push(value))
593 }
594
595 pub fn iter(&self) -> impl Iterator<Item = (K, &V)> {
597 self.key_map.iter()
598 }
599}
600
601impl<K: EntityRef, V> Index<K> for Intern<K, V> {
602 type Output = V;
603 fn index(&self, key: K) -> &V {
604 &self.key_map[key]
605 }
606}
607
608impl<K: EntityRef, V> Default for Intern<K, V> {
609 fn default() -> Intern<K, V> {
610 Intern {
611 intern_map: HashMap::new(),
612 key_map: PrimaryMap::new(),
613 }
614 }
615}
616
617impl ComponentDfg {
618 pub fn finish(
621 self,
622 wasmtime_types: &mut ComponentTypesBuilder,
623 wasmparser_types: wasmparser::types::TypesRef<'_>,
624 ) -> Result<ComponentTranslation> {
625 let mut linearize = LinearizeDfg {
626 dfg: &self,
627 initializers: Vec::new(),
628 runtime_memories: Default::default(),
629 runtime_tables: Default::default(),
630 runtime_post_return: Default::default(),
631 runtime_reallocs: Default::default(),
632 runtime_callbacks: Default::default(),
633 runtime_instances: Default::default(),
634 num_lowerings: 0,
635 unsafe_intrinsics: Default::default(),
636 trampolines: Default::default(),
637 trampoline_defs: Default::default(),
638 trampoline_map: Default::default(),
639 options: Default::default(),
640 options_map: Default::default(),
641 };
642
643 for item in linearize.dfg.side_effects.iter() {
647 linearize.side_effect(item);
648 }
649
650 let mut export_items = PrimaryMap::new();
653 let mut exports = NameMap::default();
654 for (name, (export, data)) in self.exports.iter() {
655 let export =
656 linearize.export(export, &mut export_items, wasmtime_types, wasmparser_types)?;
657 exports.insert(
658 name,
659 &mut NameMapNoIntern,
660 false,
661 (export, data.try_clone()?),
662 )?;
663 }
664
665 Ok(ComponentTranslation {
670 trampolines: linearize.trampoline_defs,
671 component: Component {
672 exports,
673 export_items: export_items.into(),
674 initializers: linearize.initializers.into(),
675 unsafe_intrinsics: linearize.unsafe_intrinsics,
676 trampolines: linearize.trampolines.into(),
677 num_lowerings: linearize.num_lowerings,
678 options: linearize.options.into(),
679
680 num_runtime_memories: linearize.runtime_memories.len() as u32,
681 num_runtime_tables: linearize.runtime_tables.len() as u32,
682 num_runtime_post_returns: linearize.runtime_post_return.len() as u32,
683 num_runtime_reallocs: linearize.runtime_reallocs.len() as u32,
684 num_runtime_callbacks: linearize.runtime_callbacks.len() as u32,
685 num_runtime_instances: linearize.runtime_instances.len() as u32,
686 imports: self
687 .imports
688 .into_iter()
689 .map(|(_, (import, path))| {
690 let path = path.into_iter().map(TryString::from).try_collect()?;
691 Ok((import, path))
692 })
693 .try_collect::<_, OutOfMemory>()?,
694 import_types: self
695 .import_types
696 .into_iter()
697 .map(|(_, (name, ty))| (TryString::from(name), ty))
698 .try_collect()?,
699 num_runtime_component_instances: self.num_runtime_component_instances,
700 num_future_tables: self.num_future_tables,
701 num_stream_tables: self.num_stream_tables,
702 num_error_context_tables: self.num_error_context_tables,
703 num_resources: (self.resources.len() + self.imported_resources.len()) as u32,
704 imported_resources: self.imported_resources.into(),
705 defined_resource_instances: self
706 .resources
707 .iter()
708 .map(|(_, r)| r.instance)
709 .try_collect()?,
710 },
711 })
712 }
713
714 pub fn resource_index(&self, defined: DefinedResourceIndex) -> ResourceIndex {
717 ResourceIndex::from_u32(defined.as_u32() + (self.imported_resources.len() as u32))
718 }
719
720 pub fn defined_resource_index(&self, idx: ResourceIndex) -> Option<DefinedResourceIndex> {
723 let idx = idx
724 .as_u32()
725 .checked_sub(u32::try_from(self.imported_resources.len()).unwrap())?;
726 Some(DefinedResourceIndex::from_u32(idx))
727 }
728
729 pub fn defined_resource_instance(
732 &self,
733 idx: ResourceIndex,
734 ) -> Option<RuntimeComponentInstanceIndex> {
735 Some(self.resources[self.defined_resource_index(idx)?].instance)
736 }
737}
738
739struct LinearizeDfg<'a> {
740 dfg: &'a ComponentDfg,
741 initializers: Vec<GlobalInitializer>,
742 unsafe_intrinsics: [PackedOption<ModuleInternedTypeIndex>; UnsafeIntrinsic::len() as usize],
743 trampolines: PrimaryMap<TrampolineIndex, ModuleInternedTypeIndex>,
744 trampoline_defs: PrimaryMap<TrampolineIndex, info::Trampoline>,
745 options: PrimaryMap<OptionsIndex, info::CanonicalOptions>,
746 trampoline_map: HashMap<TrampolineIndex, TrampolineIndex>,
747 runtime_memories: HashMap<MemoryId, RuntimeMemoryIndex>,
748 runtime_tables: HashMap<TableId, RuntimeTableIndex>,
749 runtime_reallocs: HashMap<ReallocId, RuntimeReallocIndex>,
750 runtime_callbacks: HashMap<CallbackId, RuntimeCallbackIndex>,
751 runtime_post_return: HashMap<PostReturnId, RuntimePostReturnIndex>,
752 runtime_instances: HashMap<RuntimeInstance, RuntimeInstanceIndex>,
753 options_map: HashMap<OptionsId, OptionsIndex>,
754 num_lowerings: u32,
755}
756
757#[derive(Copy, Clone, Hash, Eq, PartialEq)]
758enum RuntimeInstance {
759 Normal(InstanceId),
760 Adapter(AdapterModuleId),
761}
762
763impl LinearizeDfg<'_> {
764 fn side_effect(&mut self, effect: &SideEffect) {
765 match effect {
766 SideEffect::Instance(i, ci) => {
767 self.instantiate(*i, &self.dfg.instances[*i], *ci);
768 }
769 SideEffect::Resource(i) => {
770 self.resource(*i, &self.dfg.resources[*i]);
771 }
772 }
773 }
774
775 fn instantiate(
776 &mut self,
777 instance: InstanceId,
778 args: &Instance,
779 component_instance: RuntimeComponentInstanceIndex,
780 ) {
781 log::trace!("creating instance {instance:?}");
782 let instantiation = match args {
783 Instance::Static(index, args) => InstantiateModule::Static(
784 *index,
785 args.iter()
786 .map(|def| self.core_def(def))
787 .try_collect()
788 .panic_on_oom(),
789 ),
790 Instance::Import(index, args) => InstantiateModule::Import(
791 *index,
792 args.iter()
793 .map(|(module, values)| {
794 let values = values
795 .iter()
796 .map(|(name, def)| {
797 Ok((TryString::try_from(name.as_str())?, self.core_def(def)))
798 })
799 .try_collect::<_, OutOfMemory>()?;
800 Ok((TryString::try_from(module.as_str())?, values))
801 })
802 .try_collect::<_, OutOfMemory>()
803 .panic_on_oom(),
804 ),
805 };
806 let index = RuntimeInstanceIndex::new(self.runtime_instances.len());
807 self.initializers.push(GlobalInitializer::InstantiateModule(
808 instantiation,
809 Some(component_instance),
810 ));
811 let prev = self
812 .runtime_instances
813 .insert(RuntimeInstance::Normal(instance), index);
814 assert!(prev.is_none());
815 }
816
817 fn resource(&mut self, index: DefinedResourceIndex, resource: &Resource) {
818 let dtor = resource.dtor.as_ref().map(|dtor| self.core_def(dtor));
819 self.initializers
820 .push(GlobalInitializer::Resource(info::Resource {
821 dtor,
822 index,
823 rep: resource.rep,
824 instance: resource.instance,
825 }));
826 }
827
828 fn export(
829 &mut self,
830 export: &Export,
831 items: &mut PrimaryMap<ExportIndex, info::Export>,
832 wasmtime_types: &mut ComponentTypesBuilder,
833 wasmparser_types: wasmparser::types::TypesRef<'_>,
834 ) -> Result<ExportIndex> {
835 let item = match export {
836 Export::LiftedFunction { ty, func, options } => {
837 let func = self.core_def(func);
838 let options = self.options(*options);
839 info::Export::LiftedFunction {
840 ty: *ty,
841 func,
842 options,
843 }
844 }
845 Export::ModuleStatic { ty, index } => info::Export::ModuleStatic {
846 ty: wasmtime_types.convert_module(wasmparser_types, *ty)?,
847 index: *index,
848 },
849 Export::ModuleImport { ty, import } => info::Export::ModuleImport {
850 ty: *ty,
851 import: *import,
852 },
853 Export::Instance { ty, exports } => info::Export::Instance {
854 ty: *ty,
855 exports: {
856 let mut map = NameMap::default();
857 for (name, (export, data)) in exports {
858 let export =
859 self.export(export, items, wasmtime_types, wasmparser_types)?;
860 map.insert(
861 name,
862 &mut NameMapNoIntern,
863 false,
864 (export, data.try_clone()?),
865 )?;
866 }
867 map
868 },
869 },
870 Export::Type(def) => info::Export::Type(*def),
871 };
872 Ok(items.push(item))
873 }
874
875 fn options(&mut self, options: OptionsId) -> OptionsIndex {
876 self.intern_no_init(
877 options,
878 |me| &mut me.options_map,
879 |me, options| me.convert_options(options),
880 )
881 }
882
883 fn convert_options(&mut self, options: OptionsId) -> OptionsIndex {
884 let options = &self.dfg.options[options];
885 let data_model = match options.data_model {
886 CanonicalOptionsDataModel::Gc {} => info::CanonicalOptionsDataModel::Gc {},
887 CanonicalOptionsDataModel::LinearMemory { memory, realloc } => {
888 info::CanonicalOptionsDataModel::LinearMemory(LinearMemoryOptions {
889 memory: memory.map(|mem| self.runtime_memory(mem)),
890 realloc: realloc.map(|mem| self.runtime_realloc(mem)),
891 })
892 }
893 };
894 let callback = options.callback.map(|mem| self.runtime_callback(mem));
895 let post_return = options.post_return.map(|mem| self.runtime_post_return(mem));
896 let options = info::CanonicalOptions {
897 instance: options.instance,
898 string_encoding: options.string_encoding,
899 callback,
900 post_return,
901 async_: options.async_,
902 core_type: options.core_type,
903 data_model,
904 };
905 self.options.push(options)
906 }
907
908 fn runtime_memory(&mut self, mem: MemoryId) -> RuntimeMemoryIndex {
909 self.intern(
910 mem,
911 |me| &mut me.runtime_memories,
912 |me, mem| me.core_export(&me.dfg.memories[mem]),
913 |index, export| GlobalInitializer::ExtractMemory(ExtractMemory { index, export }),
914 )
915 }
916
917 fn runtime_table(&mut self, table: TableId) -> RuntimeTableIndex {
918 self.intern(
919 table,
920 |me| &mut me.runtime_tables,
921 |me, table| me.core_export(&me.dfg.tables[table]),
922 |index, export| GlobalInitializer::ExtractTable(ExtractTable { index, export }),
923 )
924 }
925
926 fn runtime_realloc(&mut self, realloc: ReallocId) -> RuntimeReallocIndex {
927 self.intern(
928 realloc,
929 |me| &mut me.runtime_reallocs,
930 |me, realloc| me.core_def(&me.dfg.reallocs[realloc]),
931 |index, def| GlobalInitializer::ExtractRealloc(ExtractRealloc { index, def }),
932 )
933 }
934
935 fn runtime_callback(&mut self, callback: CallbackId) -> RuntimeCallbackIndex {
936 self.intern(
937 callback,
938 |me| &mut me.runtime_callbacks,
939 |me, callback| me.core_def(&me.dfg.callbacks[callback]),
940 |index, def| GlobalInitializer::ExtractCallback(ExtractCallback { index, def }),
941 )
942 }
943
944 fn runtime_post_return(&mut self, post_return: PostReturnId) -> RuntimePostReturnIndex {
945 self.intern(
946 post_return,
947 |me| &mut me.runtime_post_return,
948 |me, post_return| me.core_def(&me.dfg.post_returns[post_return]),
949 |index, def| GlobalInitializer::ExtractPostReturn(ExtractPostReturn { index, def }),
950 )
951 }
952
953 fn core_def(&mut self, def: &CoreDef) -> info::CoreDef {
954 match def {
955 CoreDef::Export(e) => info::CoreDef::Export(self.core_export(e)),
956 CoreDef::InstanceFlags(i) => info::CoreDef::InstanceFlags(*i),
957 CoreDef::Adapter(id) => info::CoreDef::Export(self.adapter(*id)),
958 CoreDef::Trampoline(index) => info::CoreDef::Trampoline(self.trampoline(*index)),
959 CoreDef::UnsafeIntrinsic(ty, i) => {
960 let index = usize::try_from(i.index()).unwrap();
961 if self.unsafe_intrinsics[index].is_none() {
962 self.unsafe_intrinsics[index] = Some(*ty).into();
963 }
964 info::CoreDef::UnsafeIntrinsic(*i)
965 }
966 }
967 }
968
969 fn trampoline(&mut self, index: TrampolineIndex) -> TrampolineIndex {
970 if let Some(idx) = self.trampoline_map.get(&index) {
971 return *idx;
972 }
973 let (signature, trampoline) = &self.dfg.trampolines[index];
974 let trampoline = match trampoline {
975 Trampoline::LowerImport {
976 import,
977 options,
978 lower_ty,
979 } => {
980 let index = LoweredIndex::from_u32(self.num_lowerings);
981 self.num_lowerings += 1;
982 self.initializers.push(GlobalInitializer::LowerImport {
983 index,
984 import: *import,
985 });
986 info::Trampoline::LowerImport {
987 index,
988 options: self.options(*options),
989 lower_ty: *lower_ty,
990 }
991 }
992 Trampoline::Transcoder {
993 op,
994 from,
995 from64,
996 to,
997 to64,
998 } => info::Trampoline::Transcoder {
999 op: *op,
1000 from: self.runtime_memory(*from),
1001 from64: *from64,
1002 to: self.runtime_memory(*to),
1003 to64: *to64,
1004 },
1005 Trampoline::ResourceNew { instance, ty } => info::Trampoline::ResourceNew {
1006 instance: *instance,
1007 ty: *ty,
1008 },
1009 Trampoline::ResourceDrop { instance, ty } => info::Trampoline::ResourceDrop {
1010 instance: *instance,
1011 ty: *ty,
1012 },
1013 Trampoline::ResourceRep { instance, ty } => info::Trampoline::ResourceRep {
1014 instance: *instance,
1015 ty: *ty,
1016 },
1017 Trampoline::BackpressureInc { instance } => info::Trampoline::BackpressureInc {
1018 instance: *instance,
1019 },
1020 Trampoline::BackpressureDec { instance } => info::Trampoline::BackpressureDec {
1021 instance: *instance,
1022 },
1023 Trampoline::TaskReturn {
1024 instance,
1025 results,
1026 options,
1027 } => info::Trampoline::TaskReturn {
1028 instance: *instance,
1029 results: *results,
1030 options: self.options(*options),
1031 },
1032 Trampoline::TaskCancel { instance } => info::Trampoline::TaskCancel {
1033 instance: *instance,
1034 },
1035 Trampoline::WaitableSetNew { instance } => info::Trampoline::WaitableSetNew {
1036 instance: *instance,
1037 },
1038 Trampoline::WaitableSetWait { instance, options } => {
1039 info::Trampoline::WaitableSetWait {
1040 instance: *instance,
1041 options: self.options(*options),
1042 }
1043 }
1044 Trampoline::WaitableSetPoll { instance, options } => {
1045 info::Trampoline::WaitableSetPoll {
1046 instance: *instance,
1047 options: self.options(*options),
1048 }
1049 }
1050 Trampoline::WaitableSetDrop { instance } => info::Trampoline::WaitableSetDrop {
1051 instance: *instance,
1052 },
1053 Trampoline::WaitableJoin { instance } => info::Trampoline::WaitableJoin {
1054 instance: *instance,
1055 },
1056 Trampoline::SubtaskDrop { instance } => info::Trampoline::SubtaskDrop {
1057 instance: *instance,
1058 },
1059 Trampoline::SubtaskCancel { instance, async_ } => info::Trampoline::SubtaskCancel {
1060 instance: *instance,
1061 async_: *async_,
1062 },
1063 Trampoline::StreamNew { instance, ty } => info::Trampoline::StreamNew {
1064 instance: *instance,
1065 ty: *ty,
1066 },
1067 Trampoline::StreamRead {
1068 instance,
1069 ty,
1070 options,
1071 } => info::Trampoline::StreamRead {
1072 instance: *instance,
1073 ty: *ty,
1074 options: self.options(*options),
1075 },
1076 Trampoline::StreamWrite {
1077 instance,
1078 ty,
1079 options,
1080 } => info::Trampoline::StreamWrite {
1081 instance: *instance,
1082 ty: *ty,
1083 options: self.options(*options),
1084 },
1085 Trampoline::StreamCancelRead {
1086 instance,
1087 ty,
1088 async_,
1089 } => info::Trampoline::StreamCancelRead {
1090 instance: *instance,
1091 ty: *ty,
1092 async_: *async_,
1093 },
1094 Trampoline::StreamCancelWrite {
1095 instance,
1096 ty,
1097 async_,
1098 } => info::Trampoline::StreamCancelWrite {
1099 instance: *instance,
1100 ty: *ty,
1101 async_: *async_,
1102 },
1103 Trampoline::StreamDropReadable { instance, ty } => {
1104 info::Trampoline::StreamDropReadable {
1105 instance: *instance,
1106 ty: *ty,
1107 }
1108 }
1109 Trampoline::StreamDropWritable { instance, ty } => {
1110 info::Trampoline::StreamDropWritable {
1111 instance: *instance,
1112 ty: *ty,
1113 }
1114 }
1115 Trampoline::FutureNew { instance, ty } => info::Trampoline::FutureNew {
1116 instance: *instance,
1117 ty: *ty,
1118 },
1119 Trampoline::FutureRead {
1120 instance,
1121 ty,
1122 options,
1123 } => info::Trampoline::FutureRead {
1124 instance: *instance,
1125 ty: *ty,
1126 options: self.options(*options),
1127 },
1128 Trampoline::FutureWrite {
1129 instance,
1130 ty,
1131 options,
1132 } => info::Trampoline::FutureWrite {
1133 instance: *instance,
1134 ty: *ty,
1135 options: self.options(*options),
1136 },
1137 Trampoline::FutureCancelRead {
1138 instance,
1139 ty,
1140 async_,
1141 } => info::Trampoline::FutureCancelRead {
1142 instance: *instance,
1143 ty: *ty,
1144 async_: *async_,
1145 },
1146 Trampoline::FutureCancelWrite {
1147 instance,
1148 ty,
1149 async_,
1150 } => info::Trampoline::FutureCancelWrite {
1151 instance: *instance,
1152 ty: *ty,
1153 async_: *async_,
1154 },
1155 Trampoline::FutureDropReadable { instance, ty } => {
1156 info::Trampoline::FutureDropReadable {
1157 instance: *instance,
1158 ty: *ty,
1159 }
1160 }
1161 Trampoline::FutureDropWritable { instance, ty } => {
1162 info::Trampoline::FutureDropWritable {
1163 instance: *instance,
1164 ty: *ty,
1165 }
1166 }
1167 Trampoline::ErrorContextNew {
1168 instance,
1169 ty,
1170 options,
1171 } => info::Trampoline::ErrorContextNew {
1172 instance: *instance,
1173 ty: *ty,
1174 options: self.options(*options),
1175 },
1176 Trampoline::ErrorContextDebugMessage {
1177 instance,
1178 ty,
1179 options,
1180 } => info::Trampoline::ErrorContextDebugMessage {
1181 instance: *instance,
1182 ty: *ty,
1183 options: self.options(*options),
1184 },
1185 Trampoline::ErrorContextDrop { instance, ty } => info::Trampoline::ErrorContextDrop {
1186 instance: *instance,
1187 ty: *ty,
1188 },
1189 Trampoline::ResourceTransferOwn => info::Trampoline::ResourceTransferOwn,
1190 Trampoline::ResourceTransferBorrow => info::Trampoline::ResourceTransferBorrow,
1191 Trampoline::ResourceTransferBorrowToOwner => {
1192 info::Trampoline::ResourceTransferBorrowToOwner
1193 }
1194 Trampoline::PrepareCall { memory } => info::Trampoline::PrepareCall {
1195 memory: memory.map(|v| self.runtime_memory(v)),
1196 },
1197 Trampoline::StartCall {
1198 callback,
1199 post_return,
1200 } => info::Trampoline::StartCall {
1201 callback: callback.map(|v| self.runtime_callback(v)),
1202 post_return: post_return.map(|v| self.runtime_post_return(v)),
1203 },
1204 Trampoline::FutureTransfer => info::Trampoline::FutureTransfer,
1205 Trampoline::StreamTransfer => info::Trampoline::StreamTransfer,
1206 Trampoline::ErrorContextTransfer => info::Trampoline::ErrorContextTransfer,
1207 Trampoline::Trap(trap) => info::Trampoline::Trap(*trap),
1208 Trampoline::HostcallFuel => info::Trampoline::HostcallFuel,
1209 Trampoline::EnterSyncCall => info::Trampoline::EnterSyncCall,
1210 Trampoline::ExitSyncCall => info::Trampoline::ExitSyncCall,
1211 Trampoline::ThreadIndex { instance } => info::Trampoline::ThreadIndex {
1212 instance: *instance,
1213 },
1214 Trampoline::ThreadNewIndirect {
1215 instance,
1216 start_func_ty_idx,
1217 start_func_table_id,
1218 } => info::Trampoline::ThreadNewIndirect {
1219 instance: *instance,
1220 start_func_ty_idx: *start_func_ty_idx,
1221 start_func_table_idx: self.runtime_table(*start_func_table_id),
1222 },
1223 Trampoline::ThreadResumeLater { instance } => info::Trampoline::ThreadResumeLater {
1224 instance: *instance,
1225 },
1226 Trampoline::ThreadSuspend { instance } => info::Trampoline::ThreadSuspend {
1227 instance: *instance,
1228 },
1229 Trampoline::ThreadYield { instance } => info::Trampoline::ThreadYield {
1230 instance: *instance,
1231 },
1232 Trampoline::ThreadSuspendThenResume { instance } => {
1233 info::Trampoline::ThreadSuspendThenResume {
1234 instance: *instance,
1235 }
1236 }
1237 Trampoline::ThreadYieldThenResume { instance } => {
1238 info::Trampoline::ThreadYieldThenResume {
1239 instance: *instance,
1240 }
1241 }
1242 Trampoline::ThreadSuspendThenPromote { instance } => {
1243 info::Trampoline::ThreadSuspendThenPromote {
1244 instance: *instance,
1245 }
1246 }
1247 Trampoline::ThreadYieldThenPromote { instance } => {
1248 info::Trampoline::ThreadYieldThenPromote {
1249 instance: *instance,
1250 }
1251 }
1252 };
1253 let i1 = self.trampolines.push(*signature);
1254 let i2 = self.trampoline_defs.push(trampoline);
1255 assert_eq!(i1, i2);
1256 self.trampoline_map.insert(index, i1);
1257 i1
1258 }
1259
1260 fn core_export<T>(&mut self, export: &CoreExport<T>) -> info::CoreExport<T>
1261 where
1262 T: Clone,
1263 {
1264 let instance = export.instance;
1265 log::trace!("referencing export of {instance:?}");
1266 info::CoreExport {
1267 instance: self.runtime_instances[&RuntimeInstance::Normal(instance)],
1268 item: match &export.item {
1269 ExportItem::Index(i) => info::ExportItem::Index(i.clone()),
1270 ExportItem::Name(name) => info::ExportItem::Name(name.clone().into()),
1271 },
1272 }
1273 }
1274
1275 fn adapter(&mut self, adapter: AdapterId) -> info::CoreExport<EntityIndex> {
1276 let (adapter_module, entity_index) = self.dfg.adapter_partitionings[adapter];
1277
1278 let instance = self.adapter_module(adapter_module);
1282
1283 info::CoreExport {
1285 instance,
1286 item: info::ExportItem::Index(entity_index),
1287 }
1288 }
1289
1290 fn adapter_module(&mut self, adapter_module: AdapterModuleId) -> RuntimeInstanceIndex {
1291 self.intern(
1292 RuntimeInstance::Adapter(adapter_module),
1293 |me| &mut me.runtime_instances,
1294 |me, _| {
1295 log::debug!("instantiating {adapter_module:?}");
1296 let (module_index, args) = &me.dfg.adapter_modules[adapter_module];
1297 let args = args
1298 .iter()
1299 .map(|arg| me.core_def(arg))
1300 .try_collect()
1301 .panic_on_oom();
1302 let instantiate = InstantiateModule::Static(*module_index, args);
1303 GlobalInitializer::InstantiateModule(instantiate, None)
1304 },
1305 |_, init| init,
1306 )
1307 }
1308
1309 fn intern<K, V, T>(
1324 &mut self,
1325 key: K,
1326 map: impl Fn(&mut Self) -> &mut HashMap<K, V>,
1327 generate: impl FnOnce(&mut Self, K) -> T,
1328 init: impl FnOnce(V, T) -> GlobalInitializer,
1329 ) -> V
1330 where
1331 K: Hash + Eq + Copy,
1332 V: EntityRef,
1333 {
1334 self.intern_(key, map, generate, |me, key, val| {
1335 me.initializers.push(init(key, val));
1336 })
1337 }
1338
1339 fn intern_no_init<K, V, T>(
1340 &mut self,
1341 key: K,
1342 map: impl Fn(&mut Self) -> &mut HashMap<K, V>,
1343 generate: impl FnOnce(&mut Self, K) -> T,
1344 ) -> V
1345 where
1346 K: Hash + Eq + Copy,
1347 V: EntityRef,
1348 {
1349 self.intern_(key, map, generate, |_me, _key, _val| {})
1350 }
1351
1352 fn intern_<K, V, T>(
1353 &mut self,
1354 key: K,
1355 map: impl Fn(&mut Self) -> &mut HashMap<K, V>,
1356 generate: impl FnOnce(&mut Self, K) -> T,
1357 init: impl FnOnce(&mut Self, V, T),
1358 ) -> V
1359 where
1360 K: Hash + Eq + Copy,
1361 V: EntityRef,
1362 {
1363 if let Some(val) = map(self).get(&key) {
1364 return *val;
1365 }
1366 let tmp = generate(self, key);
1367 let index = V::new(map(self).len());
1368 init(self, index, tmp);
1369 let prev = map(self).insert(key, index);
1370 assert!(prev.is_none());
1371 index
1372 }
1373}