1use crate::component::*;
31use crate::prelude::*;
32use crate::{EntityIndex, EntityRef, PrimaryMap, WasmValType};
33use anyhow::Result;
34use indexmap::IndexMap;
35use std::collections::HashMap;
36use std::hash::Hash;
37use std::ops::Index;
38use wasmparser::types::ComponentCoreModuleTypeId;
39use wasmtime_types::ModuleInternedTypeIndex;
40
41#[derive(Default)]
42#[allow(missing_docs)]
43pub struct ComponentDfg {
44 pub import_types: PrimaryMap<ImportIndex, (String, TypeDef)>,
46
47 pub imports: PrimaryMap<RuntimeImportIndex, (ImportIndex, Vec<String>)>,
49
50 pub exports: IndexMap<String, Export>,
52
53 pub trampolines: Intern<TrampolineIndex, (ModuleInternedTypeIndex, Trampoline)>,
56
57 pub reallocs: Intern<ReallocId, CoreDef>,
60
61 pub post_returns: Intern<PostReturnId, CoreDef>,
63
64 pub memories: Intern<MemoryId, CoreExport<MemoryIndex>>,
66
67 pub adapters: Intern<AdapterId, Adapter>,
73
74 pub instances: PrimaryMap<InstanceId, Instance>,
81
82 pub num_runtime_component_instances: u32,
85
86 pub adapter_modules: PrimaryMap<AdapterModuleId, (StaticModuleIndex, Vec<CoreDef>)>,
96
97 pub adapter_paritionings: PrimaryMap<AdapterId, (AdapterModuleId, EntityIndex)>,
108
109 pub resources: PrimaryMap<DefinedResourceIndex, Resource>,
115
116 pub imported_resources: PrimaryMap<ResourceIndex, RuntimeImportIndex>,
120
121 pub num_resource_tables: usize,
125
126 pub side_effects: Vec<SideEffect>,
133}
134
135pub enum SideEffect {
137 Instance(InstanceId),
144
145 Resource(DefinedResourceIndex),
152}
153
154macro_rules! id {
155 ($(pub struct $name:ident(u32);)*) => ($(
156 #[derive(Debug, Copy, Clone, Hash, Eq, PartialEq)]
157 #[allow(missing_docs)]
158 pub struct $name(u32);
159 cranelift_entity::entity_impl!($name);
160 )*)
161}
162
163id! {
164 pub struct InstanceId(u32);
165 pub struct MemoryId(u32);
166 pub struct ReallocId(u32);
167 pub struct AdapterId(u32);
168 pub struct PostReturnId(u32);
169 pub struct AdapterModuleId(u32);
170}
171
172#[allow(missing_docs)]
174pub enum Instance {
175 Static(StaticModuleIndex, Box<[CoreDef]>),
176 Import(
177 RuntimeImportIndex,
178 IndexMap<String, IndexMap<String, CoreDef>>,
179 ),
180}
181
182#[allow(missing_docs)]
184pub enum Export {
185 LiftedFunction {
186 ty: TypeFuncIndex,
187 func: CoreDef,
188 options: CanonicalOptions,
189 },
190 ModuleStatic {
191 ty: ComponentCoreModuleTypeId,
192 index: StaticModuleIndex,
193 },
194 ModuleImport {
195 ty: TypeModuleIndex,
196 import: RuntimeImportIndex,
197 },
198 Instance {
199 ty: TypeComponentInstanceIndex,
200 exports: IndexMap<String, Export>,
201 },
202 Type(TypeDef),
203}
204
205#[derive(Debug, Clone, Hash, Eq, PartialEq)]
207#[allow(missing_docs)]
208pub enum CoreDef {
209 Export(CoreExport<EntityIndex>),
210 InstanceFlags(RuntimeComponentInstanceIndex),
211 Trampoline(TrampolineIndex),
212 Adapter(AdapterId),
221}
222
223impl<T> From<CoreExport<T>> for CoreDef
224where
225 EntityIndex: From<T>,
226{
227 fn from(export: CoreExport<T>) -> CoreDef {
228 CoreDef::Export(export.map_index(|i| i.into()))
229 }
230}
231
232#[derive(Debug, Clone, Hash, Eq, PartialEq)]
234#[allow(missing_docs)]
235pub struct CoreExport<T> {
236 pub instance: InstanceId,
237 pub item: ExportItem<T>,
238}
239
240impl<T> CoreExport<T> {
241 #[allow(missing_docs)]
242 pub fn map_index<U>(self, f: impl FnOnce(T) -> U) -> CoreExport<U> {
243 CoreExport {
244 instance: self.instance,
245 item: match self.item {
246 ExportItem::Index(i) => ExportItem::Index(f(i)),
247 ExportItem::Name(s) => ExportItem::Name(s),
248 },
249 }
250 }
251}
252
253#[derive(Clone, PartialEq, Eq, Hash)]
255#[allow(missing_docs)]
256pub enum Trampoline {
257 LowerImport {
258 import: RuntimeImportIndex,
259 options: CanonicalOptions,
260 lower_ty: TypeFuncIndex,
261 },
262 Transcoder {
263 op: Transcode,
264 from: MemoryId,
265 from64: bool,
266 to: MemoryId,
267 to64: bool,
268 },
269 AlwaysTrap,
270 ResourceNew(TypeResourceTableIndex),
271 ResourceRep(TypeResourceTableIndex),
272 ResourceDrop(TypeResourceTableIndex),
273 ResourceTransferOwn,
274 ResourceTransferBorrow,
275 ResourceEnterCall,
276 ResourceExitCall,
277}
278
279#[derive(Clone, Hash, Eq, PartialEq)]
281#[allow(missing_docs)]
282pub struct CanonicalOptions {
283 pub instance: RuntimeComponentInstanceIndex,
284 pub string_encoding: StringEncoding,
285 pub memory: Option<MemoryId>,
286 pub realloc: Option<ReallocId>,
287 pub post_return: Option<PostReturnId>,
288}
289
290#[allow(missing_docs)]
292pub struct Resource {
293 pub rep: WasmValType,
294 pub dtor: Option<CoreDef>,
295 pub instance: RuntimeComponentInstanceIndex,
296}
297
298pub struct Intern<K: EntityRef, V> {
304 intern_map: HashMap<V, K>,
305 key_map: PrimaryMap<K, V>,
306}
307
308impl<K, V> Intern<K, V>
309where
310 K: EntityRef,
311{
312 pub fn push(&mut self, value: V) -> K
319 where
320 V: Hash + Eq + Clone,
321 {
322 *self
323 .intern_map
324 .entry(value.clone())
325 .or_insert_with(|| self.key_map.push(value))
326 }
327
328 pub fn iter(&self) -> impl Iterator<Item = (K, &V)> {
330 self.key_map.iter()
331 }
332}
333
334impl<K: EntityRef, V> Index<K> for Intern<K, V> {
335 type Output = V;
336 fn index(&self, key: K) -> &V {
337 &self.key_map[key]
338 }
339}
340
341impl<K: EntityRef, V> Default for Intern<K, V> {
342 fn default() -> Intern<K, V> {
343 Intern {
344 intern_map: HashMap::new(),
345 key_map: PrimaryMap::new(),
346 }
347 }
348}
349
350impl ComponentDfg {
351 pub fn finish(
354 self,
355 wasmtime_types: &mut ComponentTypesBuilder,
356 wasmparser_types: wasmparser::types::TypesRef<'_>,
357 ) -> Result<ComponentTranslation> {
358 let mut linearize = LinearizeDfg {
359 dfg: &self,
360 initializers: Vec::new(),
361 runtime_memories: Default::default(),
362 runtime_post_return: Default::default(),
363 runtime_reallocs: Default::default(),
364 runtime_instances: Default::default(),
365 num_lowerings: 0,
366 trampolines: Default::default(),
367 trampoline_defs: Default::default(),
368 trampoline_map: Default::default(),
369 };
370
371 for item in linearize.dfg.side_effects.iter() {
375 linearize.side_effect(item);
376 }
377
378 let mut export_items = PrimaryMap::new();
381 let mut exports = NameMap::default();
382 for (name, export) in self.exports.iter() {
383 let export =
384 linearize.export(export, &mut export_items, wasmtime_types, wasmparser_types)?;
385 exports.insert(name, &mut NameMapNoIntern, false, export)?;
386 }
387
388 Ok(ComponentTranslation {
393 trampolines: linearize.trampoline_defs,
394 component: Component {
395 exports,
396 export_items,
397 initializers: linearize.initializers,
398 trampolines: linearize.trampolines,
399 num_lowerings: linearize.num_lowerings,
400
401 num_runtime_memories: linearize.runtime_memories.len() as u32,
402 num_runtime_post_returns: linearize.runtime_post_return.len() as u32,
403 num_runtime_reallocs: linearize.runtime_reallocs.len() as u32,
404 num_runtime_instances: linearize.runtime_instances.len() as u32,
405 imports: self.imports,
406 import_types: self.import_types,
407 num_runtime_component_instances: self.num_runtime_component_instances,
408 num_resource_tables: self.num_resource_tables,
409 num_resources: (self.resources.len() + self.imported_resources.len()) as u32,
410 imported_resources: self.imported_resources,
411 defined_resource_instances: self
412 .resources
413 .iter()
414 .map(|(_, r)| r.instance)
415 .collect(),
416 },
417 })
418 }
419
420 pub fn resource_index(&self, defined: DefinedResourceIndex) -> ResourceIndex {
423 ResourceIndex::from_u32(defined.as_u32() + (self.imported_resources.len() as u32))
424 }
425}
426
427struct LinearizeDfg<'a> {
428 dfg: &'a ComponentDfg,
429 initializers: Vec<GlobalInitializer>,
430 trampolines: PrimaryMap<TrampolineIndex, ModuleInternedTypeIndex>,
431 trampoline_defs: PrimaryMap<TrampolineIndex, info::Trampoline>,
432 trampoline_map: HashMap<TrampolineIndex, TrampolineIndex>,
433 runtime_memories: HashMap<MemoryId, RuntimeMemoryIndex>,
434 runtime_reallocs: HashMap<ReallocId, RuntimeReallocIndex>,
435 runtime_post_return: HashMap<PostReturnId, RuntimePostReturnIndex>,
436 runtime_instances: HashMap<RuntimeInstance, RuntimeInstanceIndex>,
437 num_lowerings: u32,
438}
439
440#[derive(Copy, Clone, Hash, Eq, PartialEq)]
441enum RuntimeInstance {
442 Normal(InstanceId),
443 Adapter(AdapterModuleId),
444}
445
446impl LinearizeDfg<'_> {
447 fn side_effect(&mut self, effect: &SideEffect) {
448 match effect {
449 SideEffect::Instance(i) => {
450 self.instantiate(*i, &self.dfg.instances[*i]);
451 }
452 SideEffect::Resource(i) => {
453 self.resource(*i, &self.dfg.resources[*i]);
454 }
455 }
456 }
457
458 fn instantiate(&mut self, instance: InstanceId, args: &Instance) {
459 log::trace!("creating instance {instance:?}");
460 let instantiation = match args {
461 Instance::Static(index, args) => InstantiateModule::Static(
462 *index,
463 args.iter().map(|def| self.core_def(def)).collect(),
464 ),
465 Instance::Import(index, args) => InstantiateModule::Import(
466 *index,
467 args.iter()
468 .map(|(module, values)| {
469 let values = values
470 .iter()
471 .map(|(name, def)| (name.clone(), self.core_def(def)))
472 .collect();
473 (module.clone(), values)
474 })
475 .collect(),
476 ),
477 };
478 let index = RuntimeInstanceIndex::new(self.runtime_instances.len());
479 self.initializers
480 .push(GlobalInitializer::InstantiateModule(instantiation));
481 let prev = self
482 .runtime_instances
483 .insert(RuntimeInstance::Normal(instance), index);
484 assert!(prev.is_none());
485 }
486
487 fn resource(&mut self, index: DefinedResourceIndex, resource: &Resource) {
488 let dtor = resource.dtor.as_ref().map(|dtor| self.core_def(dtor));
489 self.initializers
490 .push(GlobalInitializer::Resource(info::Resource {
491 dtor,
492 index,
493 rep: resource.rep,
494 instance: resource.instance,
495 }));
496 }
497
498 fn export(
499 &mut self,
500 export: &Export,
501 items: &mut PrimaryMap<ExportIndex, info::Export>,
502 wasmtime_types: &mut ComponentTypesBuilder,
503 wasmparser_types: wasmparser::types::TypesRef<'_>,
504 ) -> Result<ExportIndex> {
505 let item = match export {
506 Export::LiftedFunction { ty, func, options } => {
507 let func = self.core_def(func);
508 let options = self.options(options);
509 info::Export::LiftedFunction {
510 ty: *ty,
511 func,
512 options,
513 }
514 }
515 Export::ModuleStatic { ty, index } => info::Export::ModuleStatic {
516 ty: wasmtime_types.convert_module(wasmparser_types, *ty)?,
517 index: *index,
518 },
519 Export::ModuleImport { ty, import } => info::Export::ModuleImport {
520 ty: *ty,
521 import: *import,
522 },
523 Export::Instance { ty, exports } => info::Export::Instance {
524 ty: *ty,
525 exports: {
526 let mut map = NameMap::default();
527 for (name, export) in exports {
528 let export =
529 self.export(export, items, wasmtime_types, wasmparser_types)?;
530 map.insert(name, &mut NameMapNoIntern, false, export)?;
531 }
532 map
533 },
534 },
535 Export::Type(def) => info::Export::Type(*def),
536 };
537 Ok(items.push(item))
538 }
539
540 fn options(&mut self, options: &CanonicalOptions) -> info::CanonicalOptions {
541 let memory = options.memory.map(|mem| self.runtime_memory(mem));
542 let realloc = options.realloc.map(|mem| self.runtime_realloc(mem));
543 let post_return = options.post_return.map(|mem| self.runtime_post_return(mem));
544 info::CanonicalOptions {
545 instance: options.instance,
546 string_encoding: options.string_encoding,
547 memory,
548 realloc,
549 post_return,
550 }
551 }
552
553 fn runtime_memory(&mut self, mem: MemoryId) -> RuntimeMemoryIndex {
554 self.intern(
555 mem,
556 |me| &mut me.runtime_memories,
557 |me, mem| me.core_export(&me.dfg.memories[mem]),
558 |index, export| GlobalInitializer::ExtractMemory(ExtractMemory { index, export }),
559 )
560 }
561
562 fn runtime_realloc(&mut self, realloc: ReallocId) -> RuntimeReallocIndex {
563 self.intern(
564 realloc,
565 |me| &mut me.runtime_reallocs,
566 |me, realloc| me.core_def(&me.dfg.reallocs[realloc]),
567 |index, def| GlobalInitializer::ExtractRealloc(ExtractRealloc { index, def }),
568 )
569 }
570
571 fn runtime_post_return(&mut self, post_return: PostReturnId) -> RuntimePostReturnIndex {
572 self.intern(
573 post_return,
574 |me| &mut me.runtime_post_return,
575 |me, post_return| me.core_def(&me.dfg.post_returns[post_return]),
576 |index, def| GlobalInitializer::ExtractPostReturn(ExtractPostReturn { index, def }),
577 )
578 }
579
580 fn core_def(&mut self, def: &CoreDef) -> info::CoreDef {
581 match def {
582 CoreDef::Export(e) => info::CoreDef::Export(self.core_export(e)),
583 CoreDef::InstanceFlags(i) => info::CoreDef::InstanceFlags(*i),
584 CoreDef::Adapter(id) => info::CoreDef::Export(self.adapter(*id)),
585 CoreDef::Trampoline(index) => info::CoreDef::Trampoline(self.trampoline(*index)),
586 }
587 }
588
589 fn trampoline(&mut self, index: TrampolineIndex) -> TrampolineIndex {
590 if let Some(idx) = self.trampoline_map.get(&index) {
591 return *idx;
592 }
593 let (signature, trampoline) = &self.dfg.trampolines[index];
594 let trampoline = match trampoline {
595 Trampoline::LowerImport {
596 import,
597 options,
598 lower_ty,
599 } => {
600 let index = LoweredIndex::from_u32(self.num_lowerings);
601 self.num_lowerings += 1;
602 self.initializers.push(GlobalInitializer::LowerImport {
603 index,
604 import: *import,
605 });
606 info::Trampoline::LowerImport {
607 index,
608 options: self.options(options),
609 lower_ty: *lower_ty,
610 }
611 }
612 Trampoline::Transcoder {
613 op,
614 from,
615 from64,
616 to,
617 to64,
618 } => info::Trampoline::Transcoder {
619 op: *op,
620 from: self.runtime_memory(*from),
621 from64: *from64,
622 to: self.runtime_memory(*to),
623 to64: *to64,
624 },
625 Trampoline::AlwaysTrap => info::Trampoline::AlwaysTrap,
626 Trampoline::ResourceNew(ty) => info::Trampoline::ResourceNew(*ty),
627 Trampoline::ResourceDrop(ty) => info::Trampoline::ResourceDrop(*ty),
628 Trampoline::ResourceRep(ty) => info::Trampoline::ResourceRep(*ty),
629 Trampoline::ResourceTransferOwn => info::Trampoline::ResourceTransferOwn,
630 Trampoline::ResourceTransferBorrow => info::Trampoline::ResourceTransferBorrow,
631 Trampoline::ResourceEnterCall => info::Trampoline::ResourceEnterCall,
632 Trampoline::ResourceExitCall => info::Trampoline::ResourceExitCall,
633 };
634 let i1 = self.trampolines.push(*signature);
635 let i2 = self.trampoline_defs.push(trampoline);
636 assert_eq!(i1, i2);
637 self.trampoline_map.insert(index, i1);
638 i1
639 }
640
641 fn core_export<T>(&mut self, export: &CoreExport<T>) -> info::CoreExport<T>
642 where
643 T: Clone,
644 {
645 let instance = export.instance;
646 log::trace!("referencing export of {instance:?}");
647 info::CoreExport {
648 instance: self.runtime_instances[&RuntimeInstance::Normal(instance)],
649 item: export.item.clone(),
650 }
651 }
652
653 fn adapter(&mut self, adapter: AdapterId) -> info::CoreExport<EntityIndex> {
654 let (adapter_module, entity_index) = self.dfg.adapter_paritionings[adapter];
655
656 let instance = self.adapter_module(adapter_module);
660
661 info::CoreExport {
663 instance,
664 item: ExportItem::Index(entity_index),
665 }
666 }
667
668 fn adapter_module(&mut self, adapter_module: AdapterModuleId) -> RuntimeInstanceIndex {
669 self.intern(
670 RuntimeInstance::Adapter(adapter_module),
671 |me| &mut me.runtime_instances,
672 |me, _| {
673 log::debug!("instantiating {adapter_module:?}");
674 let (module_index, args) = &me.dfg.adapter_modules[adapter_module];
675 let args = args.iter().map(|arg| me.core_def(arg)).collect();
676 let instantiate = InstantiateModule::Static(*module_index, args);
677 GlobalInitializer::InstantiateModule(instantiate)
678 },
679 |_, init| init,
680 )
681 }
682
683 fn intern<K, V, T>(
698 &mut self,
699 key: K,
700 map: impl Fn(&mut Self) -> &mut HashMap<K, V>,
701 gen: impl FnOnce(&mut Self, K) -> T,
702 init: impl FnOnce(V, T) -> GlobalInitializer,
703 ) -> V
704 where
705 K: Hash + Eq + Copy,
706 V: EntityRef,
707 {
708 if let Some(val) = map(self).get(&key) {
709 return *val;
710 }
711 let tmp = gen(self, key);
712 let index = V::new(map(self).len());
713 self.initializers.push(init(index, tmp));
714 let prev = map(self).insert(key, index);
715 assert!(prev.is_none());
716 index
717 }
718}