use crate::component::translate::*;
use crate::{EntityType, IndexType};
use core::str::FromStr;
use std::borrow::Cow;
use wasmparser::component_types::{ComponentAnyTypeId, ComponentCoreModuleTypeId};
pub(super) fn run(
types: &mut ComponentTypesBuilder,
result: &Translation<'_>,
nested_modules: &PrimaryMap<StaticModuleIndex, ModuleTranslation<'_>>,
nested_components: &PrimaryMap<StaticComponentIndex, Translation<'_>>,
) -> Result<dfg::ComponentDfg> {
let mut inliner = Inliner {
nested_modules,
nested_components,
result: Default::default(),
import_path_interner: Default::default(),
runtime_instances: PrimaryMap::default(),
};
let index = RuntimeComponentInstanceIndex::from_u32(0);
let mut args = HashMap::with_capacity(result.exports.len());
let mut path = Vec::new();
types.resources_mut().set_current_instance(index);
let types_ref = result.types_ref();
for init in result.initializers.iter() {
let (name, ty) = match *init {
LocalInitializer::Import(name, ty) => (name, ty),
_ => continue,
};
let index = inliner.result.import_types.next_key();
types.resources_mut().register_component_entity_type(
&types_ref,
ty,
&mut path,
&mut |path| {
let index = inliner.runtime_import(&ImportPath {
index,
path: path.iter().copied().map(Into::into).collect(),
});
inliner.result.imported_resources.push(index)
},
);
let ty = types.convert_component_entity_type(types_ref, ty)?;
if let TypeDef::Interface(_) = ty {
continue;
}
let index = inliner.result.import_types.push((name.0.to_string(), ty));
let path = ImportPath::root(index);
args.insert(name.0, ComponentItemDef::from_import(path, ty)?);
}
inliner.result.num_runtime_component_instances += 1;
let frame = InlinerFrame::new(index, result, ComponentClosure::default(), args, None);
let resources_snapshot = types.resources_mut().clone();
let mut frames = vec![(frame, resources_snapshot)];
let exports = inliner.run(types, &mut frames)?;
assert!(frames.is_empty());
let mut export_map = Default::default();
for (name, def) in exports {
inliner.record_export(name, def, types, &mut export_map)?;
}
inliner.result.exports = export_map;
inliner.result.num_future_tables = types.num_future_tables();
inliner.result.num_stream_tables = types.num_stream_tables();
inliner.result.num_error_context_tables = types.num_error_context_tables();
Ok(inliner.result)
}
struct Inliner<'a> {
nested_modules: &'a PrimaryMap<StaticModuleIndex, ModuleTranslation<'a>>,
nested_components: &'a PrimaryMap<StaticComponentIndex, Translation<'a>>,
result: dfg::ComponentDfg,
import_path_interner: HashMap<ImportPath<'a>, RuntimeImportIndex>,
runtime_instances: PrimaryMap<dfg::InstanceId, InstanceModule>,
}
struct InlinerFrame<'a> {
instance: RuntimeComponentInstanceIndex,
initializers: std::slice::Iter<'a, LocalInitializer<'a>>,
translation: &'a Translation<'a>,
closure: ComponentClosure<'a>,
args: HashMap<&'a str, ComponentItemDef<'a>>,
funcs: PrimaryMap<FuncIndex, (ModuleInternedTypeIndex, dfg::CoreDef)>,
memories: PrimaryMap<MemoryIndex, dfg::CoreExport<EntityIndex>>,
tables: PrimaryMap<TableIndex, dfg::CoreExport<EntityIndex>>,
globals: PrimaryMap<GlobalIndex, dfg::CoreExport<EntityIndex>>,
tags: PrimaryMap<TagIndex, dfg::CoreExport<EntityIndex>>,
modules: PrimaryMap<ModuleIndex, ModuleDef<'a>>,
component_funcs: PrimaryMap<ComponentFuncIndex, ComponentFuncDef<'a>>,
module_instances: PrimaryMap<ModuleInstanceIndex, ModuleInstanceDef<'a>>,
component_instances: PrimaryMap<ComponentInstanceIndex, ComponentInstanceDef<'a>>,
components: PrimaryMap<ComponentIndex, ComponentDef<'a>>,
instance_ty: Option<ComponentInstanceTypeId>,
}
#[derive(Default, Clone)]
struct ComponentClosure<'a> {
modules: PrimaryMap<ModuleUpvarIndex, ModuleDef<'a>>,
components: PrimaryMap<ComponentUpvarIndex, ComponentDef<'a>>,
}
#[derive(Clone, PartialEq, Hash, Eq)]
struct ImportPath<'a> {
index: ImportIndex,
path: Vec<Cow<'a, str>>,
}
#[derive(Clone)]
enum ComponentItemDef<'a> {
Component(ComponentDef<'a>),
Instance(ComponentInstanceDef<'a>),
Func(ComponentFuncDef<'a>),
Module(ModuleDef<'a>),
Type(TypeDef),
}
#[derive(Clone)]
enum ModuleDef<'a> {
Static(StaticModuleIndex, ComponentCoreModuleTypeId),
Import(ImportPath<'a>, TypeModuleIndex),
}
enum ModuleInstanceDef<'a> {
Instantiated(dfg::InstanceId, ModuleIndex),
Synthetic(&'a HashMap<&'a str, EntityIndex>),
}
#[derive(Clone)]
enum ComponentFuncDef<'a> {
UnsafeIntrinsic(UnsafeIntrinsic),
Import(ImportPath<'a>),
Lifted {
ty: TypeFuncIndex,
func: dfg::CoreDef,
options: AdapterOptions,
},
}
#[derive(Clone)]
enum ComponentInstanceDef<'a> {
Intrinsics,
Import(ImportPath<'a>, TypeComponentInstanceIndex),
Items(
IndexMap<&'a str, ComponentItemDef<'a>>,
TypeComponentInstanceIndex,
),
}
#[derive(Clone)]
struct ComponentDef<'a> {
index: StaticComponentIndex,
closure: ComponentClosure<'a>,
}
impl<'a> Inliner<'a> {
fn run(
&mut self,
types: &mut ComponentTypesBuilder,
frames: &mut Vec<(InlinerFrame<'a>, ResourcesBuilder)>,
) -> Result<IndexMap<&'a str, ComponentItemDef<'a>>> {
loop {
let (frame, _) = frames.last_mut().unwrap();
types.resources_mut().set_current_instance(frame.instance);
match frame.initializers.next() {
Some(init) => match self.initializer(frames, types, init)? {
Some(new_frame) => {
frames.push((new_frame, types.resources_mut().clone()));
}
None => {}
},
None => {
let exports = frame
.translation
.exports
.iter()
.map(|(name, item)| Ok((*name, frame.item(*item, types)?)))
.collect::<Result<_>>()?;
let instance_ty = frame.instance_ty;
let (_, snapshot) = frames.pop().unwrap();
*types.resources_mut() = snapshot;
match frames.last_mut() {
Some((parent, _)) => {
parent.finish_instantiate(exports, instance_ty.unwrap(), types)?;
}
None => break Ok(exports),
}
}
}
}
}
fn initializer(
&mut self,
frames: &mut Vec<(InlinerFrame<'a>, ResourcesBuilder)>,
types: &mut ComponentTypesBuilder,
initializer: &'a LocalInitializer,
) -> Result<Option<InlinerFrame<'a>>> {
use LocalInitializer::*;
let (frame, _) = frames.last_mut().unwrap();
match initializer {
Import(name, ty) => {
let arg = match frame.args.get(name.0) {
Some(arg) => arg,
None => {
match ty {
ComponentEntityType::Type {
created: ComponentAnyTypeId::Resource(_),
..
} => unreachable!(),
ComponentEntityType::Type { .. } => {}
_ => unreachable!(),
}
return Ok(None);
}
};
let mut path = Vec::new();
let (resources, types) = types.resources_mut_and_types();
resources.register_component_entity_type(
&frame.translation.types_ref(),
*ty,
&mut path,
&mut |path| arg.lookup_resource(path, types),
);
frame.push_item(arg.clone());
}
IntrinsicsImport => {
frame
.component_instances
.push(ComponentInstanceDef::Intrinsics);
}
Lower {
func,
options,
lower_ty,
} => {
let lower_ty =
types.convert_component_func_type(frame.translation.types_ref(), *lower_ty)?;
let options_lower = self.adapter_options(frames, types, options);
let (frame, _) = frames.last_mut().unwrap();
let lower_core_type = options_lower.core_type;
let func = match &frame.component_funcs[*func] {
ComponentFuncDef::Import(path) => {
let import = self.runtime_import(path);
let options = self.canonical_options(options_lower);
let index = self.result.trampolines.push((
lower_core_type,
dfg::Trampoline::LowerImport {
import,
options,
lower_ty,
},
));
dfg::CoreDef::Trampoline(index)
}
ComponentFuncDef::Lifted {
ty: lift_ty,
func,
options: options_lift,
} => {
let adapter_idx = self.result.adapters.push(Adapter {
lift_ty: *lift_ty,
lift_options: options_lift.clone(),
lower_ty,
lower_options: options_lower,
func: func.clone(),
});
dfg::CoreDef::Adapter(adapter_idx)
}
ComponentFuncDef::UnsafeIntrinsic(intrinsic) => {
dfg::CoreDef::UnsafeIntrinsic(options.core_type, *intrinsic)
}
};
frame.funcs.push((lower_core_type, func));
}
Lift(ty, func, options) => {
let ty = types.convert_component_func_type(frame.translation.types_ref(), *ty)?;
let options = self.adapter_options(frames, types, options);
let (frame, _) = frames.last_mut().unwrap();
let func = frame.funcs[*func].1.clone();
frame
.component_funcs
.push(ComponentFuncDef::Lifted { ty, func, options });
}
Resource(ty, rep, dtor) => {
let idx = self.result.resources.push(dfg::Resource {
rep: *rep,
dtor: dtor.map(|i| frame.funcs[i].1.clone()),
instance: frame.instance,
});
self.result
.side_effects
.push(dfg::SideEffect::Resource(idx));
let idx = self.result.resource_index(idx);
types.resources_mut().register_resource(ty.resource(), idx);
}
ResourceNew(id, ty) => {
let id = types.resource_id(id.resource());
let index = self.result.trampolines.push((
*ty,
dfg::Trampoline::ResourceNew {
instance: frame.instance,
ty: id,
},
));
frame.funcs.push((*ty, dfg::CoreDef::Trampoline(index)));
}
ResourceRep(id, ty) => {
let id = types.resource_id(id.resource());
let index = self.result.trampolines.push((
*ty,
dfg::Trampoline::ResourceRep {
instance: frame.instance,
ty: id,
},
));
frame.funcs.push((*ty, dfg::CoreDef::Trampoline(index)));
}
ResourceDrop(id, ty) => {
let id = types.resource_id(id.resource());
let index = self.result.trampolines.push((
*ty,
dfg::Trampoline::ResourceDrop {
instance: frame.instance,
ty: id,
},
));
frame.funcs.push((*ty, dfg::CoreDef::Trampoline(index)));
}
BackpressureInc { func } => {
let index = self.result.trampolines.push((
*func,
dfg::Trampoline::BackpressureInc {
instance: frame.instance,
},
));
frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));
}
BackpressureDec { func } => {
let index = self.result.trampolines.push((
*func,
dfg::Trampoline::BackpressureDec {
instance: frame.instance,
},
));
frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));
}
TaskReturn { result, options } => {
let results = result
.iter()
.map(|ty| types.valtype(frame.translation.types_ref(), ty))
.collect::<Result<_>>()?;
let results = types.new_tuple_type(results);
let func = options.core_type;
let options = self.adapter_options(frames, types, options);
let (frame, _) = frames.last_mut().unwrap();
let options = self.canonical_options(options);
let index = self.result.trampolines.push((
func,
dfg::Trampoline::TaskReturn {
instance: frame.instance,
results,
options,
},
));
frame.funcs.push((func, dfg::CoreDef::Trampoline(index)));
}
TaskCancel { func } => {
let index = self.result.trampolines.push((
*func,
dfg::Trampoline::TaskCancel {
instance: frame.instance,
},
));
frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));
}
WaitableSetNew { func } => {
let index = self.result.trampolines.push((
*func,
dfg::Trampoline::WaitableSetNew {
instance: frame.instance,
},
));
frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));
}
WaitableSetWait { options } => {
let func = options.core_type;
let options = self.adapter_options(frames, types, options);
let (frame, _) = frames.last_mut().unwrap();
let options = self.canonical_options(options);
let index = self.result.trampolines.push((
func,
dfg::Trampoline::WaitableSetWait {
instance: frame.instance,
options,
},
));
frame.funcs.push((func, dfg::CoreDef::Trampoline(index)));
}
WaitableSetPoll { options } => {
let func = options.core_type;
let options = self.adapter_options(frames, types, options);
let (frame, _) = frames.last_mut().unwrap();
let options = self.canonical_options(options);
let index = self.result.trampolines.push((
func,
dfg::Trampoline::WaitableSetPoll {
instance: frame.instance,
options,
},
));
frame.funcs.push((func, dfg::CoreDef::Trampoline(index)));
}
WaitableSetDrop { func } => {
let index = self.result.trampolines.push((
*func,
dfg::Trampoline::WaitableSetDrop {
instance: frame.instance,
},
));
frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));
}
WaitableJoin { func } => {
let index = self.result.trampolines.push((
*func,
dfg::Trampoline::WaitableJoin {
instance: frame.instance,
},
));
frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));
}
ThreadYield { func, cancellable } => {
let index = self.result.trampolines.push((
*func,
dfg::Trampoline::ThreadYield {
instance: frame.instance,
cancellable: *cancellable,
},
));
frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));
}
SubtaskDrop { func } => {
let index = self.result.trampolines.push((
*func,
dfg::Trampoline::SubtaskDrop {
instance: frame.instance,
},
));
frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));
}
SubtaskCancel { func, async_ } => {
let index = self.result.trampolines.push((
*func,
dfg::Trampoline::SubtaskCancel {
instance: frame.instance,
async_: *async_,
},
));
frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));
}
StreamNew { ty, func } => {
let InterfaceType::Stream(ty) =
types.defined_type(frame.translation.types_ref(), *ty)?
else {
unreachable!()
};
let index = self.result.trampolines.push((
*func,
dfg::Trampoline::StreamNew {
instance: frame.instance,
ty,
},
));
frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));
}
StreamRead { ty, options } => {
let InterfaceType::Stream(ty) =
types.defined_type(frame.translation.types_ref(), *ty)?
else {
unreachable!()
};
let func = options.core_type;
let options = self.adapter_options(frames, types, options);
let (frame, _) = frames.last_mut().unwrap();
let options = self.canonical_options(options);
let index = self.result.trampolines.push((
func,
dfg::Trampoline::StreamRead {
instance: frame.instance,
ty,
options,
},
));
frame.funcs.push((func, dfg::CoreDef::Trampoline(index)));
}
StreamWrite { ty, options } => {
let InterfaceType::Stream(ty) =
types.defined_type(frame.translation.types_ref(), *ty)?
else {
unreachable!()
};
let func = options.core_type;
let options = self.adapter_options(frames, types, options);
let (frame, _) = frames.last_mut().unwrap();
let options = self.canonical_options(options);
let index = self.result.trampolines.push((
func,
dfg::Trampoline::StreamWrite {
instance: frame.instance,
ty,
options,
},
));
frame.funcs.push((func, dfg::CoreDef::Trampoline(index)));
}
StreamCancelRead { ty, func, async_ } => {
let InterfaceType::Stream(ty) =
types.defined_type(frame.translation.types_ref(), *ty)?
else {
unreachable!()
};
let index = self.result.trampolines.push((
*func,
dfg::Trampoline::StreamCancelRead {
instance: frame.instance,
ty,
async_: *async_,
},
));
frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));
}
StreamCancelWrite { ty, func, async_ } => {
let InterfaceType::Stream(ty) =
types.defined_type(frame.translation.types_ref(), *ty)?
else {
unreachable!()
};
let index = self.result.trampolines.push((
*func,
dfg::Trampoline::StreamCancelWrite {
instance: frame.instance,
ty,
async_: *async_,
},
));
frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));
}
StreamDropReadable { ty, func } => {
let InterfaceType::Stream(ty) =
types.defined_type(frame.translation.types_ref(), *ty)?
else {
unreachable!()
};
let index = self.result.trampolines.push((
*func,
dfg::Trampoline::StreamDropReadable {
instance: frame.instance,
ty,
},
));
frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));
}
StreamDropWritable { ty, func } => {
let InterfaceType::Stream(ty) =
types.defined_type(frame.translation.types_ref(), *ty)?
else {
unreachable!()
};
let index = self.result.trampolines.push((
*func,
dfg::Trampoline::StreamDropWritable {
instance: frame.instance,
ty,
},
));
frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));
}
FutureNew { ty, func } => {
let InterfaceType::Future(ty) =
types.defined_type(frame.translation.types_ref(), *ty)?
else {
unreachable!()
};
let index = self.result.trampolines.push((
*func,
dfg::Trampoline::FutureNew {
instance: frame.instance,
ty,
},
));
frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));
}
FutureRead { ty, options } => {
let InterfaceType::Future(ty) =
types.defined_type(frame.translation.types_ref(), *ty)?
else {
unreachable!()
};
let func = options.core_type;
let options = self.adapter_options(frames, types, options);
let (frame, _) = frames.last_mut().unwrap();
let options = self.canonical_options(options);
let index = self.result.trampolines.push((
func,
dfg::Trampoline::FutureRead {
instance: frame.instance,
ty,
options,
},
));
frame.funcs.push((func, dfg::CoreDef::Trampoline(index)));
}
FutureWrite { ty, options } => {
let InterfaceType::Future(ty) =
types.defined_type(frame.translation.types_ref(), *ty)?
else {
unreachable!()
};
let func = options.core_type;
let options = self.adapter_options(frames, types, options);
let (frame, _) = frames.last_mut().unwrap();
let options = self.canonical_options(options);
let index = self.result.trampolines.push((
func,
dfg::Trampoline::FutureWrite {
instance: frame.instance,
ty,
options,
},
));
frame.funcs.push((func, dfg::CoreDef::Trampoline(index)));
}
FutureCancelRead { ty, func, async_ } => {
let InterfaceType::Future(ty) =
types.defined_type(frame.translation.types_ref(), *ty)?
else {
unreachable!()
};
let index = self.result.trampolines.push((
*func,
dfg::Trampoline::FutureCancelRead {
instance: frame.instance,
ty,
async_: *async_,
},
));
frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));
}
FutureCancelWrite { ty, func, async_ } => {
let InterfaceType::Future(ty) =
types.defined_type(frame.translation.types_ref(), *ty)?
else {
unreachable!()
};
let index = self.result.trampolines.push((
*func,
dfg::Trampoline::FutureCancelWrite {
instance: frame.instance,
ty,
async_: *async_,
},
));
frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));
}
FutureDropReadable { ty, func } => {
let InterfaceType::Future(ty) =
types.defined_type(frame.translation.types_ref(), *ty)?
else {
unreachable!()
};
let index = self.result.trampolines.push((
*func,
dfg::Trampoline::FutureDropReadable {
instance: frame.instance,
ty,
},
));
frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));
}
FutureDropWritable { ty, func } => {
let InterfaceType::Future(ty) =
types.defined_type(frame.translation.types_ref(), *ty)?
else {
unreachable!()
};
let index = self.result.trampolines.push((
*func,
dfg::Trampoline::FutureDropWritable {
instance: frame.instance,
ty,
},
));
frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));
}
ErrorContextNew { options } => {
let ty = types.error_context_table_type()?;
let func = options.core_type;
let options = self.adapter_options(frames, types, options);
let (frame, _) = frames.last_mut().unwrap();
let options = self.canonical_options(options);
let index = self.result.trampolines.push((
func,
dfg::Trampoline::ErrorContextNew {
instance: frame.instance,
ty,
options,
},
));
frame.funcs.push((func, dfg::CoreDef::Trampoline(index)));
}
ErrorContextDebugMessage { options } => {
let ty = types.error_context_table_type()?;
let func = options.core_type;
let options = self.adapter_options(frames, types, options);
let (frame, _) = frames.last_mut().unwrap();
let options = self.canonical_options(options);
let index = self.result.trampolines.push((
func,
dfg::Trampoline::ErrorContextDebugMessage {
instance: frame.instance,
ty,
options,
},
));
frame.funcs.push((func, dfg::CoreDef::Trampoline(index)));
}
ErrorContextDrop { func } => {
let ty = types.error_context_table_type()?;
let index = self.result.trampolines.push((
*func,
dfg::Trampoline::ErrorContextDrop {
instance: frame.instance,
ty,
},
));
frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));
}
ContextGet { func, i } => {
let index = self.result.trampolines.push((
*func,
dfg::Trampoline::ContextGet {
instance: frame.instance,
slot: *i,
},
));
frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));
}
ContextSet { func, i } => {
let index = self.result.trampolines.push((
*func,
dfg::Trampoline::ContextSet {
instance: frame.instance,
slot: *i,
},
));
frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));
}
ThreadIndex { func } => {
let index = self
.result
.trampolines
.push((*func, dfg::Trampoline::ThreadIndex));
frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));
}
ThreadNewIndirect {
func,
start_func_table_index,
start_func_ty,
} => {
let table_export = frame.tables[*start_func_table_index]
.clone()
.map_index(|i| match i {
EntityIndex::Table(i) => i,
_ => unreachable!(),
});
let table_id = self.result.tables.push(table_export);
let index = self.result.trampolines.push((
*func,
dfg::Trampoline::ThreadNewIndirect {
instance: frame.instance,
start_func_ty_idx: *start_func_ty,
start_func_table_id: table_id,
},
));
frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));
}
ThreadSwitchTo { func, cancellable } => {
let index = self.result.trampolines.push((
*func,
dfg::Trampoline::ThreadSwitchTo {
instance: frame.instance,
cancellable: *cancellable,
},
));
frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));
}
ThreadSuspend { func, cancellable } => {
let index = self.result.trampolines.push((
*func,
dfg::Trampoline::ThreadSuspend {
instance: frame.instance,
cancellable: *cancellable,
},
));
frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));
}
ThreadResumeLater { func } => {
let index = self.result.trampolines.push((
*func,
dfg::Trampoline::ThreadResumeLater {
instance: frame.instance,
},
));
frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));
}
ThreadYieldTo { func, cancellable } => {
let index = self.result.trampolines.push((
*func,
dfg::Trampoline::ThreadYieldTo {
instance: frame.instance,
cancellable: *cancellable,
},
));
frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));
}
ModuleStatic(idx, ty) => {
frame.modules.push(ModuleDef::Static(*idx, *ty));
}
ModuleInstantiate(module, args) => {
let (instance_module, init) = match &frame.modules[*module] {
ModuleDef::Static(idx, _ty) => {
let mut defs = Vec::new();
for (module, name, _ty) in self.nested_modules[*idx].module.imports() {
let instance = args[module];
defs.push(
self.core_def_of_module_instance_export(frame, instance, name),
);
}
(
InstanceModule::Static(*idx),
dfg::Instance::Static(*idx, defs.into()),
)
}
ModuleDef::Import(path, ty) => {
let mut defs = IndexMap::new();
for ((module, name), _) in types[*ty].imports.iter() {
let instance = args[module.as_str()];
let def =
self.core_def_of_module_instance_export(frame, instance, name);
defs.entry(module.to_string())
.or_insert(IndexMap::new())
.insert(name.to_string(), def);
}
let index = self.runtime_import(path);
(
InstanceModule::Import(*ty),
dfg::Instance::Import(index, defs),
)
}
};
let instance = self.result.instances.push(init);
let instance2 = self.runtime_instances.push(instance_module);
assert_eq!(instance, instance2);
self.result
.side_effects
.push(dfg::SideEffect::Instance(instance, frame.instance));
frame
.module_instances
.push(ModuleInstanceDef::Instantiated(instance, *module));
}
ModuleSynthetic(map) => {
frame
.module_instances
.push(ModuleInstanceDef::Synthetic(map));
}
ComponentStatic(index, vars) => {
frame.components.push(ComponentDef {
index: *index,
closure: ComponentClosure {
modules: vars
.modules
.iter()
.map(|(_, m)| frame.closed_over_module(m))
.collect(),
components: vars
.components
.iter()
.map(|(_, m)| frame.closed_over_component(m))
.collect(),
},
});
}
ComponentInstantiate(component, args, ty) => {
let component: &ComponentDef<'a> = &frame.components[*component];
let index = RuntimeComponentInstanceIndex::from_u32(
self.result.num_runtime_component_instances,
);
self.result.num_runtime_component_instances += 1;
let frame = InlinerFrame::new(
index,
&self.nested_components[component.index],
component.closure.clone(),
args.iter()
.map(|(name, item)| Ok((*name, frame.item(*item, types)?)))
.collect::<Result<_>>()?,
Some(*ty),
);
return Ok(Some(frame));
}
ComponentSynthetic(map, ty) => {
let items = map
.iter()
.map(|(name, index)| Ok((*name, frame.item(*index, types)?)))
.collect::<Result<_>>()?;
let types_ref = frame.translation.types_ref();
let ty = types.convert_instance(types_ref, *ty)?;
frame
.component_instances
.push(ComponentInstanceDef::Items(items, ty));
}
AliasExportFunc(instance, name) => {
let (ty, def) = match &frame.module_instances[*instance] {
ModuleInstanceDef::Instantiated(instance, module) => {
let (ty, item) = match &frame.modules[*module] {
ModuleDef::Static(idx, _ty) => {
let entity = self.nested_modules[*idx].module.exports[*name];
let ty = match entity {
EntityIndex::Function(f) => {
self.nested_modules[*idx].module.functions[f]
.signature
.unwrap_module_type_index()
}
_ => unreachable!(),
};
(ty, ExportItem::Index(entity))
}
ModuleDef::Import(_path, module_ty) => {
let module_ty = &types.component_types()[*module_ty];
let entity_ty = &module_ty.exports[&**name];
let ty = entity_ty.unwrap_func().unwrap_module_type_index();
(ty, ExportItem::Name((*name).to_string()))
}
};
let def = dfg::CoreExport {
instance: *instance,
item,
}
.into();
(ty, def)
}
ModuleInstanceDef::Synthetic(instance) => match instance[*name] {
EntityIndex::Function(i) => frame.funcs[i].clone(),
_ => unreachable!(),
},
};
frame.funcs.push((ty, def));
}
AliasExportTable(instance, name) => {
frame.tables.push(
match self.core_def_of_module_instance_export(frame, *instance, *name) {
dfg::CoreDef::Export(e) => e,
_ => unreachable!(),
},
);
}
AliasExportGlobal(instance, name) => {
frame.globals.push(
match self.core_def_of_module_instance_export(frame, *instance, *name) {
dfg::CoreDef::Export(e) => e,
_ => unreachable!(),
},
);
}
AliasExportMemory(instance, name) => {
frame.memories.push(
match self.core_def_of_module_instance_export(frame, *instance, *name) {
dfg::CoreDef::Export(e) => e,
_ => unreachable!(),
},
);
}
AliasExportTag(instance, name) => {
frame.tags.push(
match self.core_def_of_module_instance_export(frame, *instance, *name) {
dfg::CoreDef::Export(e) => e,
_ => unreachable!(),
},
);
}
AliasComponentExport(instance, name) => {
match &frame.component_instances[*instance] {
ComponentInstanceDef::Intrinsics => {
frame.push_item(ComponentItemDef::Func(ComponentFuncDef::UnsafeIntrinsic(
UnsafeIntrinsic::from_str(name)?,
)));
}
ComponentInstanceDef::Import(path, ty) => {
let path = path.push(*name);
let def = ComponentItemDef::from_import(path, types[*ty].exports[*name])?;
frame.push_item(def);
}
ComponentInstanceDef::Items(map, _) => frame.push_item(map[*name].clone()),
}
}
AliasModule(idx) => {
frame.modules.push(frame.closed_over_module(idx));
}
AliasComponent(idx) => {
frame.components.push(frame.closed_over_component(idx));
}
Export(item) => match item {
ComponentItem::Func(i) => {
frame
.component_funcs
.push(frame.component_funcs[*i].clone());
}
ComponentItem::Module(i) => {
frame.modules.push(frame.modules[*i].clone());
}
ComponentItem::Component(i) => {
frame.components.push(frame.components[*i].clone());
}
ComponentItem::ComponentInstance(i) => {
frame
.component_instances
.push(frame.component_instances[*i].clone());
}
ComponentItem::Type(_) => {}
},
}
Ok(None)
}
fn runtime_import(&mut self, path: &ImportPath<'a>) -> RuntimeImportIndex {
*self
.import_path_interner
.entry(path.clone())
.or_insert_with(|| {
self.result.imports.push((
path.index,
path.path.iter().map(|s| s.to_string()).collect(),
))
})
}
fn core_def_of_module_instance_export(
&self,
frame: &InlinerFrame<'a>,
instance: ModuleInstanceIndex,
name: &'a str,
) -> dfg::CoreDef {
match &frame.module_instances[instance] {
ModuleInstanceDef::Instantiated(instance, module) => {
let item = match frame.modules[*module] {
ModuleDef::Static(idx, _ty) => {
let entity = self.nested_modules[idx].module.exports[name];
ExportItem::Index(entity)
}
ModuleDef::Import(..) => ExportItem::Name(name.to_string()),
};
dfg::CoreExport {
instance: *instance,
item,
}
.into()
}
ModuleInstanceDef::Synthetic(instance) => match instance[name] {
EntityIndex::Function(i) => frame.funcs[i].1.clone(),
EntityIndex::Table(i) => frame.tables[i].clone().into(),
EntityIndex::Global(i) => frame.globals[i].clone().into(),
EntityIndex::Memory(i) => frame.memories[i].clone().into(),
EntityIndex::Tag(i) => frame.tags[i].clone().into(),
},
}
}
fn memory(
&mut self,
frame: &InlinerFrame<'a>,
types: &ComponentTypesBuilder,
memory: MemoryIndex,
) -> (dfg::CoreExport<MemoryIndex>, bool) {
let memory = frame.memories[memory].clone().map_index(|i| match i {
EntityIndex::Memory(i) => i,
_ => unreachable!(),
});
let memory64 = match &self.runtime_instances[memory.instance] {
InstanceModule::Static(idx) => match &memory.item {
ExportItem::Index(i) => {
let ty = &self.nested_modules[*idx].module.memories[*i];
match ty.idx_type {
IndexType::I32 => false,
IndexType::I64 => true,
}
}
ExportItem::Name(_) => unreachable!(),
},
InstanceModule::Import(ty) => match &memory.item {
ExportItem::Name(name) => match types[*ty].exports[name] {
EntityType::Memory(m) => match m.idx_type {
IndexType::I32 => false,
IndexType::I64 => true,
},
_ => unreachable!(),
},
ExportItem::Index(_) => unreachable!(),
},
};
(memory, memory64)
}
fn adapter_options(
&mut self,
frames: &mut Vec<(InlinerFrame<'a>, ResourcesBuilder)>,
types: &ComponentTypesBuilder,
options: &LocalCanonicalOptions,
) -> AdapterOptions {
let (frame, _) = frames.last_mut().unwrap();
let data_model = match options.data_model {
LocalDataModel::Gc {} => DataModel::Gc {},
LocalDataModel::LinearMemory { memory, realloc } => {
let (memory, memory64) = memory
.map(|i| {
let (memory, memory64) = self.memory(frame, types, i);
(Some(memory), memory64)
})
.unwrap_or((None, false));
let realloc = realloc.map(|i| frame.funcs[i].1.clone());
DataModel::LinearMemory {
memory,
memory64,
realloc,
}
}
};
let callback = options.callback.map(|i| frame.funcs[i].1.clone());
let post_return = options.post_return.map(|i| frame.funcs[i].1.clone());
AdapterOptions {
instance: frame.instance,
ancestors: frames
.iter()
.rev()
.skip(1)
.map(|(frame, _)| frame.instance)
.collect(),
string_encoding: options.string_encoding,
callback,
post_return,
async_: options.async_,
cancellable: options.cancellable,
core_type: options.core_type,
data_model,
}
}
fn canonical_options(&mut self, options: AdapterOptions) -> dfg::OptionsId {
let data_model = match options.data_model {
DataModel::Gc {} => dfg::CanonicalOptionsDataModel::Gc {},
DataModel::LinearMemory {
memory,
memory64: _,
realloc,
} => dfg::CanonicalOptionsDataModel::LinearMemory {
memory: memory.map(|export| self.result.memories.push(export)),
realloc: realloc.map(|def| self.result.reallocs.push(def)),
},
};
let callback = options.callback.map(|def| self.result.callbacks.push(def));
let post_return = options
.post_return
.map(|def| self.result.post_returns.push(def));
self.result.options.push(dfg::CanonicalOptions {
instance: options.instance,
string_encoding: options.string_encoding,
callback,
post_return,
async_: options.async_,
cancellable: options.cancellable,
core_type: options.core_type,
data_model,
})
}
fn record_export(
&mut self,
name: &str,
def: ComponentItemDef<'a>,
types: &'a ComponentTypesBuilder,
map: &mut IndexMap<String, dfg::Export>,
) -> Result<()> {
let export = match def {
ComponentItemDef::Module(module) => match module {
ModuleDef::Static(index, ty) => dfg::Export::ModuleStatic { ty, index },
ModuleDef::Import(path, ty) => dfg::Export::ModuleImport {
ty,
import: self.runtime_import(&path),
},
},
ComponentItemDef::Func(func) => match func {
ComponentFuncDef::Lifted { ty, func, options } => {
let options = self.canonical_options(options);
dfg::Export::LiftedFunction { ty, func, options }
}
ComponentFuncDef::Import(_) => {
bail!(
"component export `{name}` is a reexport of an imported function which is not implemented"
)
}
ComponentFuncDef::UnsafeIntrinsic(_) => {
bail!(
"component export `{name}` is a reexport of an intrinsic function which is not supported"
)
}
},
ComponentItemDef::Instance(instance) => {
let mut exports = IndexMap::new();
match instance {
ComponentInstanceDef::Intrinsics => {
bail!(
"component export `{name}` is a reexport of the intrinsics instance which is not supported"
)
}
ComponentInstanceDef::Import(path, ty) => {
for (name, ty) in types[ty].exports.iter() {
let path = path.push(name);
let def = ComponentItemDef::from_import(path, *ty)?;
self.record_export(name, def, types, &mut exports)?;
}
dfg::Export::Instance { ty, exports }
}
ComponentInstanceDef::Items(map, ty) => {
for (name, def) in map {
self.record_export(name, def, types, &mut exports)?;
}
dfg::Export::Instance { ty, exports }
}
}
}
ComponentItemDef::Component(_) => {
bail!("exporting a component from the root component is not supported")
}
ComponentItemDef::Type(def) => dfg::Export::Type(def),
};
map.insert(name.to_string(), export);
Ok(())
}
}
impl<'a> InlinerFrame<'a> {
fn new(
instance: RuntimeComponentInstanceIndex,
translation: &'a Translation<'a>,
closure: ComponentClosure<'a>,
args: HashMap<&'a str, ComponentItemDef<'a>>,
instance_ty: Option<ComponentInstanceTypeId>,
) -> Self {
InlinerFrame {
instance,
translation,
closure,
args,
instance_ty,
initializers: translation.initializers.iter(),
funcs: Default::default(),
memories: Default::default(),
tables: Default::default(),
globals: Default::default(),
tags: Default::default(),
component_instances: Default::default(),
component_funcs: Default::default(),
module_instances: Default::default(),
components: Default::default(),
modules: Default::default(),
}
}
fn item(
&self,
index: ComponentItem,
types: &mut ComponentTypesBuilder,
) -> Result<ComponentItemDef<'a>> {
Ok(match index {
ComponentItem::Func(i) => ComponentItemDef::Func(self.component_funcs[i].clone()),
ComponentItem::Component(i) => ComponentItemDef::Component(self.components[i].clone()),
ComponentItem::ComponentInstance(i) => {
ComponentItemDef::Instance(self.component_instances[i].clone())
}
ComponentItem::Module(i) => ComponentItemDef::Module(self.modules[i].clone()),
ComponentItem::Type(t) => {
let types_ref = self.translation.types_ref();
ComponentItemDef::Type(types.convert_type(types_ref, t)?)
}
})
}
fn push_item(&mut self, item: ComponentItemDef<'a>) {
match item {
ComponentItemDef::Func(i) => {
self.component_funcs.push(i);
}
ComponentItemDef::Module(i) => {
self.modules.push(i);
}
ComponentItemDef::Component(i) => {
self.components.push(i);
}
ComponentItemDef::Instance(i) => {
self.component_instances.push(i);
}
ComponentItemDef::Type(_ty) => {}
}
}
fn closed_over_module(&self, index: &ClosedOverModule) -> ModuleDef<'a> {
match *index {
ClosedOverModule::Local(i) => self.modules[i].clone(),
ClosedOverModule::Upvar(i) => self.closure.modules[i].clone(),
}
}
fn closed_over_component(&self, index: &ClosedOverComponent) -> ComponentDef<'a> {
match *index {
ClosedOverComponent::Local(i) => self.components[i].clone(),
ClosedOverComponent::Upvar(i) => self.closure.components[i].clone(),
}
}
fn finish_instantiate(
&mut self,
exports: IndexMap<&'a str, ComponentItemDef<'a>>,
ty: ComponentInstanceTypeId,
types: &mut ComponentTypesBuilder,
) -> Result<()> {
let types_ref = self.translation.types_ref();
{
let (resources, types) = types.resources_mut_and_types();
let mut path = Vec::new();
resources.register_component_entity_type(
&types_ref,
ComponentEntityType::Instance(ty),
&mut path,
&mut |path| match path {
[] => unreachable!(),
[name, rest @ ..] => exports[name].lookup_resource(rest, types),
},
);
}
let ty = types.convert_instance(types_ref, ty)?;
let def = ComponentInstanceDef::Items(exports, ty);
let arg = ComponentItemDef::Instance(def);
self.push_item(arg);
Ok(())
}
}
impl<'a> ImportPath<'a> {
fn root(index: ImportIndex) -> ImportPath<'a> {
ImportPath {
index,
path: Vec::new(),
}
}
fn push(&self, s: impl Into<Cow<'a, str>>) -> ImportPath<'a> {
let mut new = self.clone();
new.path.push(s.into());
new
}
}
impl<'a> ComponentItemDef<'a> {
fn from_import(path: ImportPath<'a>, ty: TypeDef) -> Result<ComponentItemDef<'a>> {
let item = match ty {
TypeDef::Module(ty) => ComponentItemDef::Module(ModuleDef::Import(path, ty)),
TypeDef::ComponentInstance(ty) => {
ComponentItemDef::Instance(ComponentInstanceDef::Import(path, ty))
}
TypeDef::ComponentFunc(_ty) => ComponentItemDef::Func(ComponentFuncDef::Import(path)),
TypeDef::Component(_ty) => bail!("root-level component imports are not supported"),
TypeDef::Interface(_) | TypeDef::Resource(_) => ComponentItemDef::Type(ty),
TypeDef::CoreFunc(_) => unreachable!(),
};
Ok(item)
}
fn lookup_resource(&self, path: &[&str], types: &ComponentTypes) -> ResourceIndex {
let mut cur = self.clone();
for element in path.iter().copied() {
let instance = match cur {
ComponentItemDef::Instance(def) => def,
_ => unreachable!(),
};
cur = match instance {
ComponentInstanceDef::Items(names, _) => names[element].clone(),
ComponentInstanceDef::Import(path, ty) => {
ComponentItemDef::from_import(path.push(element), types[ty].exports[element])
.unwrap()
}
ComponentInstanceDef::Intrinsics => {
unreachable!("intrinsics do not define resources")
}
};
}
match cur {
ComponentItemDef::Type(TypeDef::Resource(idx)) => types[idx].unwrap_concrete_ty(),
_ => unreachable!(),
}
}
}
#[derive(Clone, Copy)]
enum InstanceModule {
Static(StaticModuleIndex),
Import(TypeModuleIndex),
}