use crate::component::*;
use crate::error::Result;
use crate::prelude::*;
use crate::{EntityIndex, EntityRef, ModuleInternedTypeIndex, PrimaryMap, WasmValType};
use cranelift_entity::packed_option::PackedOption;
use indexmap::IndexMap;
use info::LinearMemoryOptions;
use std::collections::HashMap;
use std::hash::Hash;
use std::ops::Index;
use wasmparser::component_types::ComponentCoreModuleTypeId;
#[derive(Default)]
pub struct ComponentDfg {
pub import_types: PrimaryMap<ImportIndex, (String, TypeDef)>,
pub imports: PrimaryMap<RuntimeImportIndex, (ImportIndex, Vec<String>)>,
pub exports: IndexMap<String, Export>,
pub trampolines: Intern<TrampolineIndex, (ModuleInternedTypeIndex, Trampoline)>,
pub unsafe_intrinsics: [PackedOption<ModuleInternedTypeIndex>; UnsafeIntrinsic::len() as usize],
pub reallocs: Intern<ReallocId, CoreDef>,
pub callbacks: Intern<CallbackId, CoreDef>,
pub post_returns: Intern<PostReturnId, CoreDef>,
pub memories: Intern<MemoryId, CoreExport<MemoryIndex>>,
pub tables: Intern<TableId, CoreExport<TableIndex>>,
pub adapters: Intern<AdapterId, Adapter>,
pub instances: PrimaryMap<InstanceId, Instance>,
pub num_runtime_component_instances: u32,
pub adapter_modules: PrimaryMap<AdapterModuleId, (StaticModuleIndex, Vec<CoreDef>)>,
pub adapter_partitionings: PrimaryMap<AdapterId, (AdapterModuleId, EntityIndex)>,
pub resources: PrimaryMap<DefinedResourceIndex, Resource>,
pub imported_resources: PrimaryMap<ResourceIndex, RuntimeImportIndex>,
pub num_future_tables: usize,
pub num_stream_tables: usize,
pub num_error_context_tables: usize,
pub side_effects: Vec<SideEffect>,
pub options: Intern<OptionsId, CanonicalOptions>,
}
pub enum SideEffect {
Instance(InstanceId, RuntimeComponentInstanceIndex),
Resource(DefinedResourceIndex),
}
#[derive(Clone, Copy, Default)]
pub enum AbstractInstantiations<'a> {
Many,
One(&'a [info::CoreDef]),
#[default]
None,
}
impl AbstractInstantiations<'_> {
pub fn join(&mut self, other: Self) {
*self = match (*self, other) {
(Self::Many, _) | (_, Self::Many) => Self::Many,
(Self::One(a), Self::One(b)) if a == b => Self::One(a),
(Self::One(_), Self::One(_)) => Self::Many,
(Self::One(a), Self::None) | (Self::None, Self::One(a)) => Self::One(a),
(Self::None, Self::None) => Self::None,
}
}
}
macro_rules! id {
($(pub struct $name:ident(u32);)*) => ($(
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq)]
#[expect(missing_docs, reason = "tedious to document")]
pub struct $name(u32);
cranelift_entity::entity_impl!($name);
)*)
}
id! {
pub struct InstanceId(u32);
pub struct MemoryId(u32);
pub struct TableId(u32);
pub struct ReallocId(u32);
pub struct CallbackId(u32);
pub struct AdapterId(u32);
pub struct PostReturnId(u32);
pub struct AdapterModuleId(u32);
pub struct OptionsId(u32);
}
#[expect(missing_docs, reason = "tedious to document variants")]
pub enum Instance {
Static(StaticModuleIndex, Box<[CoreDef]>),
Import(
RuntimeImportIndex,
IndexMap<String, IndexMap<String, CoreDef>>,
),
}
#[expect(missing_docs, reason = "tedious to document variants")]
pub enum Export {
LiftedFunction {
ty: TypeFuncIndex,
func: CoreDef,
options: OptionsId,
},
ModuleStatic {
ty: ComponentCoreModuleTypeId,
index: StaticModuleIndex,
},
ModuleImport {
ty: TypeModuleIndex,
import: RuntimeImportIndex,
},
Instance {
ty: TypeComponentInstanceIndex,
exports: IndexMap<String, Export>,
},
Type(TypeDef),
}
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
#[expect(missing_docs, reason = "tedious to document variants")]
pub enum CoreDef {
Export(CoreExport<EntityIndex>),
InstanceFlags(RuntimeComponentInstanceIndex),
Trampoline(TrampolineIndex),
UnsafeIntrinsic(ModuleInternedTypeIndex, UnsafeIntrinsic),
TaskMayBlock,
Adapter(AdapterId),
}
impl<T> From<CoreExport<T>> for CoreDef
where
EntityIndex: From<T>,
{
fn from(export: CoreExport<T>) -> CoreDef {
CoreDef::Export(export.map_index(|i| i.into()))
}
}
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
#[expect(missing_docs, reason = "self-describing fields")]
pub struct CoreExport<T> {
pub instance: InstanceId,
pub item: ExportItem<T>,
}
impl<T> CoreExport<T> {
#[expect(missing_docs, reason = "self-describing function")]
pub fn map_index<U>(self, f: impl FnOnce(T) -> U) -> CoreExport<U> {
CoreExport {
instance: self.instance,
item: match self.item {
ExportItem::Index(i) => ExportItem::Index(f(i)),
ExportItem::Name(s) => ExportItem::Name(s),
},
}
}
}
#[derive(Clone, PartialEq, Eq, Hash)]
#[expect(missing_docs, reason = "self-describing fields")]
pub enum Trampoline {
LowerImport {
import: RuntimeImportIndex,
options: OptionsId,
lower_ty: TypeFuncIndex,
},
Transcoder {
op: Transcode,
from: MemoryId,
from64: bool,
to: MemoryId,
to64: bool,
},
ResourceNew {
instance: RuntimeComponentInstanceIndex,
ty: TypeResourceTableIndex,
},
ResourceRep {
instance: RuntimeComponentInstanceIndex,
ty: TypeResourceTableIndex,
},
ResourceDrop {
instance: RuntimeComponentInstanceIndex,
ty: TypeResourceTableIndex,
},
BackpressureInc {
instance: RuntimeComponentInstanceIndex,
},
BackpressureDec {
instance: RuntimeComponentInstanceIndex,
},
TaskReturn {
instance: RuntimeComponentInstanceIndex,
results: TypeTupleIndex,
options: OptionsId,
},
TaskCancel {
instance: RuntimeComponentInstanceIndex,
},
WaitableSetNew {
instance: RuntimeComponentInstanceIndex,
},
WaitableSetWait {
instance: RuntimeComponentInstanceIndex,
options: OptionsId,
},
WaitableSetPoll {
instance: RuntimeComponentInstanceIndex,
options: OptionsId,
},
WaitableSetDrop {
instance: RuntimeComponentInstanceIndex,
},
WaitableJoin {
instance: RuntimeComponentInstanceIndex,
},
ThreadYield {
instance: RuntimeComponentInstanceIndex,
cancellable: bool,
},
SubtaskDrop {
instance: RuntimeComponentInstanceIndex,
},
SubtaskCancel {
instance: RuntimeComponentInstanceIndex,
async_: bool,
},
StreamNew {
instance: RuntimeComponentInstanceIndex,
ty: TypeStreamTableIndex,
},
StreamRead {
instance: RuntimeComponentInstanceIndex,
ty: TypeStreamTableIndex,
options: OptionsId,
},
StreamWrite {
instance: RuntimeComponentInstanceIndex,
ty: TypeStreamTableIndex,
options: OptionsId,
},
StreamCancelRead {
instance: RuntimeComponentInstanceIndex,
ty: TypeStreamTableIndex,
async_: bool,
},
StreamCancelWrite {
instance: RuntimeComponentInstanceIndex,
ty: TypeStreamTableIndex,
async_: bool,
},
StreamDropReadable {
instance: RuntimeComponentInstanceIndex,
ty: TypeStreamTableIndex,
},
StreamDropWritable {
instance: RuntimeComponentInstanceIndex,
ty: TypeStreamTableIndex,
},
FutureNew {
instance: RuntimeComponentInstanceIndex,
ty: TypeFutureTableIndex,
},
FutureRead {
instance: RuntimeComponentInstanceIndex,
ty: TypeFutureTableIndex,
options: OptionsId,
},
FutureWrite {
instance: RuntimeComponentInstanceIndex,
ty: TypeFutureTableIndex,
options: OptionsId,
},
FutureCancelRead {
instance: RuntimeComponentInstanceIndex,
ty: TypeFutureTableIndex,
async_: bool,
},
FutureCancelWrite {
instance: RuntimeComponentInstanceIndex,
ty: TypeFutureTableIndex,
async_: bool,
},
FutureDropReadable {
instance: RuntimeComponentInstanceIndex,
ty: TypeFutureTableIndex,
},
FutureDropWritable {
instance: RuntimeComponentInstanceIndex,
ty: TypeFutureTableIndex,
},
ErrorContextNew {
instance: RuntimeComponentInstanceIndex,
ty: TypeComponentLocalErrorContextTableIndex,
options: OptionsId,
},
ErrorContextDebugMessage {
instance: RuntimeComponentInstanceIndex,
ty: TypeComponentLocalErrorContextTableIndex,
options: OptionsId,
},
ErrorContextDrop {
instance: RuntimeComponentInstanceIndex,
ty: TypeComponentLocalErrorContextTableIndex,
},
ResourceTransferOwn,
ResourceTransferBorrow,
ResourceEnterCall,
ResourceExitCall,
PrepareCall {
memory: Option<MemoryId>,
},
SyncStartCall {
callback: Option<CallbackId>,
},
AsyncStartCall {
callback: Option<CallbackId>,
post_return: Option<PostReturnId>,
},
FutureTransfer,
StreamTransfer,
ErrorContextTransfer,
Trap,
EnterSyncCall,
ExitSyncCall,
ContextGet {
instance: RuntimeComponentInstanceIndex,
slot: u32,
},
ContextSet {
instance: RuntimeComponentInstanceIndex,
slot: u32,
},
ThreadIndex,
ThreadNewIndirect {
instance: RuntimeComponentInstanceIndex,
start_func_ty_idx: ComponentTypeIndex,
start_func_table_id: TableId,
},
ThreadSwitchTo {
instance: RuntimeComponentInstanceIndex,
cancellable: bool,
},
ThreadSuspend {
instance: RuntimeComponentInstanceIndex,
cancellable: bool,
},
ThreadResumeLater {
instance: RuntimeComponentInstanceIndex,
},
ThreadYieldTo {
instance: RuntimeComponentInstanceIndex,
cancellable: bool,
},
}
#[derive(Copy, Clone, Hash, Eq, PartialEq)]
#[expect(missing_docs, reason = "self-describing fields")]
pub struct FutureInfo {
pub instance: RuntimeComponentInstanceIndex,
pub payload_type: Option<InterfaceType>,
}
#[derive(Copy, Clone, Hash, Eq, PartialEq)]
#[expect(missing_docs, reason = "self-describing fields")]
pub struct StreamInfo {
pub instance: RuntimeComponentInstanceIndex,
pub payload_type: InterfaceType,
}
#[derive(Clone, Hash, Eq, PartialEq)]
#[expect(missing_docs, reason = "self-describing fields")]
pub enum CanonicalOptionsDataModel {
Gc {},
LinearMemory {
memory: Option<MemoryId>,
realloc: Option<ReallocId>,
},
}
#[derive(Clone, Hash, Eq, PartialEq)]
#[expect(missing_docs, reason = "self-describing fields")]
pub struct CanonicalOptions {
pub instance: RuntimeComponentInstanceIndex,
pub string_encoding: StringEncoding,
pub callback: Option<CallbackId>,
pub post_return: Option<PostReturnId>,
pub async_: bool,
pub cancellable: bool,
pub core_type: ModuleInternedTypeIndex,
pub data_model: CanonicalOptionsDataModel,
}
#[expect(missing_docs, reason = "self-describing fields")]
pub struct Resource {
pub rep: WasmValType,
pub dtor: Option<CoreDef>,
pub instance: RuntimeComponentInstanceIndex,
}
pub struct Intern<K: EntityRef, V> {
intern_map: HashMap<V, K>,
key_map: PrimaryMap<K, V>,
}
impl<K, V> Intern<K, V>
where
K: EntityRef,
{
pub fn push(&mut self, value: V) -> K
where
V: Hash + Eq + Clone,
{
*self
.intern_map
.entry(value.clone())
.or_insert_with(|| self.key_map.push(value))
}
pub fn iter(&self) -> impl Iterator<Item = (K, &V)> {
self.key_map.iter()
}
}
impl<K: EntityRef, V> Index<K> for Intern<K, V> {
type Output = V;
fn index(&self, key: K) -> &V {
&self.key_map[key]
}
}
impl<K: EntityRef, V> Default for Intern<K, V> {
fn default() -> Intern<K, V> {
Intern {
intern_map: HashMap::new(),
key_map: PrimaryMap::new(),
}
}
}
impl ComponentDfg {
pub fn finish(
self,
wasmtime_types: &mut ComponentTypesBuilder,
wasmparser_types: wasmparser::types::TypesRef<'_>,
) -> Result<ComponentTranslation> {
let mut linearize = LinearizeDfg {
dfg: &self,
initializers: Vec::new(),
runtime_memories: Default::default(),
runtime_tables: Default::default(),
runtime_post_return: Default::default(),
runtime_reallocs: Default::default(),
runtime_callbacks: Default::default(),
runtime_instances: Default::default(),
num_lowerings: 0,
unsafe_intrinsics: Default::default(),
trampolines: Default::default(),
trampoline_defs: Default::default(),
trampoline_map: Default::default(),
options: Default::default(),
options_map: Default::default(),
};
for item in linearize.dfg.side_effects.iter() {
linearize.side_effect(item);
}
let mut export_items = PrimaryMap::new();
let mut exports = NameMap::default();
for (name, export) in self.exports.iter() {
let export =
linearize.export(export, &mut export_items, wasmtime_types, wasmparser_types)?;
exports.insert(name, &mut NameMapNoIntern, false, export)?;
}
Ok(ComponentTranslation {
trampolines: linearize.trampoline_defs,
component: Component {
exports,
export_items,
initializers: linearize.initializers,
unsafe_intrinsics: linearize.unsafe_intrinsics,
trampolines: linearize.trampolines,
num_lowerings: linearize.num_lowerings,
options: linearize.options,
num_runtime_memories: linearize.runtime_memories.len() as u32,
num_runtime_tables: linearize.runtime_tables.len() as u32,
num_runtime_post_returns: linearize.runtime_post_return.len() as u32,
num_runtime_reallocs: linearize.runtime_reallocs.len() as u32,
num_runtime_callbacks: linearize.runtime_callbacks.len() as u32,
num_runtime_instances: linearize.runtime_instances.len() as u32,
imports: self.imports,
import_types: self.import_types,
num_runtime_component_instances: self.num_runtime_component_instances,
num_future_tables: self.num_future_tables,
num_stream_tables: self.num_stream_tables,
num_error_context_tables: self.num_error_context_tables,
num_resources: (self.resources.len() + self.imported_resources.len()) as u32,
imported_resources: self.imported_resources,
defined_resource_instances: self
.resources
.iter()
.map(|(_, r)| r.instance)
.collect(),
},
})
}
pub fn resource_index(&self, defined: DefinedResourceIndex) -> ResourceIndex {
ResourceIndex::from_u32(defined.as_u32() + (self.imported_resources.len() as u32))
}
}
struct LinearizeDfg<'a> {
dfg: &'a ComponentDfg,
initializers: Vec<GlobalInitializer>,
unsafe_intrinsics: [PackedOption<ModuleInternedTypeIndex>; UnsafeIntrinsic::len() as usize],
trampolines: PrimaryMap<TrampolineIndex, ModuleInternedTypeIndex>,
trampoline_defs: PrimaryMap<TrampolineIndex, info::Trampoline>,
options: PrimaryMap<OptionsIndex, info::CanonicalOptions>,
trampoline_map: HashMap<TrampolineIndex, TrampolineIndex>,
runtime_memories: HashMap<MemoryId, RuntimeMemoryIndex>,
runtime_tables: HashMap<TableId, RuntimeTableIndex>,
runtime_reallocs: HashMap<ReallocId, RuntimeReallocIndex>,
runtime_callbacks: HashMap<CallbackId, RuntimeCallbackIndex>,
runtime_post_return: HashMap<PostReturnId, RuntimePostReturnIndex>,
runtime_instances: HashMap<RuntimeInstance, RuntimeInstanceIndex>,
options_map: HashMap<OptionsId, OptionsIndex>,
num_lowerings: u32,
}
#[derive(Copy, Clone, Hash, Eq, PartialEq)]
enum RuntimeInstance {
Normal(InstanceId),
Adapter(AdapterModuleId),
}
impl LinearizeDfg<'_> {
fn side_effect(&mut self, effect: &SideEffect) {
match effect {
SideEffect::Instance(i, ci) => {
self.instantiate(*i, &self.dfg.instances[*i], *ci);
}
SideEffect::Resource(i) => {
self.resource(*i, &self.dfg.resources[*i]);
}
}
}
fn instantiate(
&mut self,
instance: InstanceId,
args: &Instance,
component_instance: RuntimeComponentInstanceIndex,
) {
log::trace!("creating instance {instance:?}");
let instantiation = match args {
Instance::Static(index, args) => InstantiateModule::Static(
*index,
args.iter().map(|def| self.core_def(def)).collect(),
),
Instance::Import(index, args) => InstantiateModule::Import(
*index,
args.iter()
.map(|(module, values)| {
let values = values
.iter()
.map(|(name, def)| (name.clone(), self.core_def(def)))
.collect();
(module.clone(), values)
})
.collect(),
),
};
let index = RuntimeInstanceIndex::new(self.runtime_instances.len());
self.initializers.push(GlobalInitializer::InstantiateModule(
instantiation,
Some(component_instance),
));
let prev = self
.runtime_instances
.insert(RuntimeInstance::Normal(instance), index);
assert!(prev.is_none());
}
fn resource(&mut self, index: DefinedResourceIndex, resource: &Resource) {
let dtor = resource.dtor.as_ref().map(|dtor| self.core_def(dtor));
self.initializers
.push(GlobalInitializer::Resource(info::Resource {
dtor,
index,
rep: resource.rep,
instance: resource.instance,
}));
}
fn export(
&mut self,
export: &Export,
items: &mut PrimaryMap<ExportIndex, info::Export>,
wasmtime_types: &mut ComponentTypesBuilder,
wasmparser_types: wasmparser::types::TypesRef<'_>,
) -> Result<ExportIndex> {
let item = match export {
Export::LiftedFunction { ty, func, options } => {
let func = self.core_def(func);
let options = self.options(*options);
info::Export::LiftedFunction {
ty: *ty,
func,
options,
}
}
Export::ModuleStatic { ty, index } => info::Export::ModuleStatic {
ty: wasmtime_types.convert_module(wasmparser_types, *ty)?,
index: *index,
},
Export::ModuleImport { ty, import } => info::Export::ModuleImport {
ty: *ty,
import: *import,
},
Export::Instance { ty, exports } => info::Export::Instance {
ty: *ty,
exports: {
let mut map = NameMap::default();
for (name, export) in exports {
let export =
self.export(export, items, wasmtime_types, wasmparser_types)?;
map.insert(name, &mut NameMapNoIntern, false, export)?;
}
map
},
},
Export::Type(def) => info::Export::Type(*def),
};
Ok(items.push(item))
}
fn options(&mut self, options: OptionsId) -> OptionsIndex {
self.intern_no_init(
options,
|me| &mut me.options_map,
|me, options| me.convert_options(options),
)
}
fn convert_options(&mut self, options: OptionsId) -> OptionsIndex {
let options = &self.dfg.options[options];
let data_model = match options.data_model {
CanonicalOptionsDataModel::Gc {} => info::CanonicalOptionsDataModel::Gc {},
CanonicalOptionsDataModel::LinearMemory { memory, realloc } => {
info::CanonicalOptionsDataModel::LinearMemory(LinearMemoryOptions {
memory: memory.map(|mem| self.runtime_memory(mem)),
realloc: realloc.map(|mem| self.runtime_realloc(mem)),
})
}
};
let callback = options.callback.map(|mem| self.runtime_callback(mem));
let post_return = options.post_return.map(|mem| self.runtime_post_return(mem));
let options = info::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,
};
self.options.push(options)
}
fn runtime_memory(&mut self, mem: MemoryId) -> RuntimeMemoryIndex {
self.intern(
mem,
|me| &mut me.runtime_memories,
|me, mem| me.core_export(&me.dfg.memories[mem]),
|index, export| GlobalInitializer::ExtractMemory(ExtractMemory { index, export }),
)
}
fn runtime_table(&mut self, table: TableId) -> RuntimeTableIndex {
self.intern(
table,
|me| &mut me.runtime_tables,
|me, table| me.core_export(&me.dfg.tables[table]),
|index, export| GlobalInitializer::ExtractTable(ExtractTable { index, export }),
)
}
fn runtime_realloc(&mut self, realloc: ReallocId) -> RuntimeReallocIndex {
self.intern(
realloc,
|me| &mut me.runtime_reallocs,
|me, realloc| me.core_def(&me.dfg.reallocs[realloc]),
|index, def| GlobalInitializer::ExtractRealloc(ExtractRealloc { index, def }),
)
}
fn runtime_callback(&mut self, callback: CallbackId) -> RuntimeCallbackIndex {
self.intern(
callback,
|me| &mut me.runtime_callbacks,
|me, callback| me.core_def(&me.dfg.callbacks[callback]),
|index, def| GlobalInitializer::ExtractCallback(ExtractCallback { index, def }),
)
}
fn runtime_post_return(&mut self, post_return: PostReturnId) -> RuntimePostReturnIndex {
self.intern(
post_return,
|me| &mut me.runtime_post_return,
|me, post_return| me.core_def(&me.dfg.post_returns[post_return]),
|index, def| GlobalInitializer::ExtractPostReturn(ExtractPostReturn { index, def }),
)
}
fn core_def(&mut self, def: &CoreDef) -> info::CoreDef {
match def {
CoreDef::Export(e) => info::CoreDef::Export(self.core_export(e)),
CoreDef::InstanceFlags(i) => info::CoreDef::InstanceFlags(*i),
CoreDef::Adapter(id) => info::CoreDef::Export(self.adapter(*id)),
CoreDef::Trampoline(index) => info::CoreDef::Trampoline(self.trampoline(*index)),
CoreDef::UnsafeIntrinsic(ty, i) => {
let index = usize::try_from(i.index()).unwrap();
if self.unsafe_intrinsics[index].is_none() {
self.unsafe_intrinsics[index] = Some(*ty).into();
}
info::CoreDef::UnsafeIntrinsic(*i)
}
CoreDef::TaskMayBlock => info::CoreDef::TaskMayBlock,
}
}
fn trampoline(&mut self, index: TrampolineIndex) -> TrampolineIndex {
if let Some(idx) = self.trampoline_map.get(&index) {
return *idx;
}
let (signature, trampoline) = &self.dfg.trampolines[index];
let trampoline = match trampoline {
Trampoline::LowerImport {
import,
options,
lower_ty,
} => {
let index = LoweredIndex::from_u32(self.num_lowerings);
self.num_lowerings += 1;
self.initializers.push(GlobalInitializer::LowerImport {
index,
import: *import,
});
info::Trampoline::LowerImport {
index,
options: self.options(*options),
lower_ty: *lower_ty,
}
}
Trampoline::Transcoder {
op,
from,
from64,
to,
to64,
} => info::Trampoline::Transcoder {
op: *op,
from: self.runtime_memory(*from),
from64: *from64,
to: self.runtime_memory(*to),
to64: *to64,
},
Trampoline::ResourceNew { instance, ty } => info::Trampoline::ResourceNew {
instance: *instance,
ty: *ty,
},
Trampoline::ResourceDrop { instance, ty } => info::Trampoline::ResourceDrop {
instance: *instance,
ty: *ty,
},
Trampoline::ResourceRep { instance, ty } => info::Trampoline::ResourceRep {
instance: *instance,
ty: *ty,
},
Trampoline::BackpressureInc { instance } => info::Trampoline::BackpressureInc {
instance: *instance,
},
Trampoline::BackpressureDec { instance } => info::Trampoline::BackpressureDec {
instance: *instance,
},
Trampoline::TaskReturn {
instance,
results,
options,
} => info::Trampoline::TaskReturn {
instance: *instance,
results: *results,
options: self.options(*options),
},
Trampoline::TaskCancel { instance } => info::Trampoline::TaskCancel {
instance: *instance,
},
Trampoline::WaitableSetNew { instance } => info::Trampoline::WaitableSetNew {
instance: *instance,
},
Trampoline::WaitableSetWait { instance, options } => {
info::Trampoline::WaitableSetWait {
instance: *instance,
options: self.options(*options),
}
}
Trampoline::WaitableSetPoll { instance, options } => {
info::Trampoline::WaitableSetPoll {
instance: *instance,
options: self.options(*options),
}
}
Trampoline::WaitableSetDrop { instance } => info::Trampoline::WaitableSetDrop {
instance: *instance,
},
Trampoline::WaitableJoin { instance } => info::Trampoline::WaitableJoin {
instance: *instance,
},
Trampoline::ThreadYield {
instance,
cancellable,
} => info::Trampoline::ThreadYield {
instance: *instance,
cancellable: *cancellable,
},
Trampoline::SubtaskDrop { instance } => info::Trampoline::SubtaskDrop {
instance: *instance,
},
Trampoline::SubtaskCancel { instance, async_ } => info::Trampoline::SubtaskCancel {
instance: *instance,
async_: *async_,
},
Trampoline::StreamNew { instance, ty } => info::Trampoline::StreamNew {
instance: *instance,
ty: *ty,
},
Trampoline::StreamRead {
instance,
ty,
options,
} => info::Trampoline::StreamRead {
instance: *instance,
ty: *ty,
options: self.options(*options),
},
Trampoline::StreamWrite {
instance,
ty,
options,
} => info::Trampoline::StreamWrite {
instance: *instance,
ty: *ty,
options: self.options(*options),
},
Trampoline::StreamCancelRead {
instance,
ty,
async_,
} => info::Trampoline::StreamCancelRead {
instance: *instance,
ty: *ty,
async_: *async_,
},
Trampoline::StreamCancelWrite {
instance,
ty,
async_,
} => info::Trampoline::StreamCancelWrite {
instance: *instance,
ty: *ty,
async_: *async_,
},
Trampoline::StreamDropReadable { instance, ty } => {
info::Trampoline::StreamDropReadable {
instance: *instance,
ty: *ty,
}
}
Trampoline::StreamDropWritable { instance, ty } => {
info::Trampoline::StreamDropWritable {
instance: *instance,
ty: *ty,
}
}
Trampoline::FutureNew { instance, ty } => info::Trampoline::FutureNew {
instance: *instance,
ty: *ty,
},
Trampoline::FutureRead {
instance,
ty,
options,
} => info::Trampoline::FutureRead {
instance: *instance,
ty: *ty,
options: self.options(*options),
},
Trampoline::FutureWrite {
instance,
ty,
options,
} => info::Trampoline::FutureWrite {
instance: *instance,
ty: *ty,
options: self.options(*options),
},
Trampoline::FutureCancelRead {
instance,
ty,
async_,
} => info::Trampoline::FutureCancelRead {
instance: *instance,
ty: *ty,
async_: *async_,
},
Trampoline::FutureCancelWrite {
instance,
ty,
async_,
} => info::Trampoline::FutureCancelWrite {
instance: *instance,
ty: *ty,
async_: *async_,
},
Trampoline::FutureDropReadable { instance, ty } => {
info::Trampoline::FutureDropReadable {
instance: *instance,
ty: *ty,
}
}
Trampoline::FutureDropWritable { instance, ty } => {
info::Trampoline::FutureDropWritable {
instance: *instance,
ty: *ty,
}
}
Trampoline::ErrorContextNew {
instance,
ty,
options,
} => info::Trampoline::ErrorContextNew {
instance: *instance,
ty: *ty,
options: self.options(*options),
},
Trampoline::ErrorContextDebugMessage {
instance,
ty,
options,
} => info::Trampoline::ErrorContextDebugMessage {
instance: *instance,
ty: *ty,
options: self.options(*options),
},
Trampoline::ErrorContextDrop { instance, ty } => info::Trampoline::ErrorContextDrop {
instance: *instance,
ty: *ty,
},
Trampoline::ResourceTransferOwn => info::Trampoline::ResourceTransferOwn,
Trampoline::ResourceTransferBorrow => info::Trampoline::ResourceTransferBorrow,
Trampoline::ResourceEnterCall => info::Trampoline::ResourceEnterCall,
Trampoline::ResourceExitCall => info::Trampoline::ResourceExitCall,
Trampoline::PrepareCall { memory } => info::Trampoline::PrepareCall {
memory: memory.map(|v| self.runtime_memory(v)),
},
Trampoline::SyncStartCall { callback } => info::Trampoline::SyncStartCall {
callback: callback.map(|v| self.runtime_callback(v)),
},
Trampoline::AsyncStartCall {
callback,
post_return,
} => info::Trampoline::AsyncStartCall {
callback: callback.map(|v| self.runtime_callback(v)),
post_return: post_return.map(|v| self.runtime_post_return(v)),
},
Trampoline::FutureTransfer => info::Trampoline::FutureTransfer,
Trampoline::StreamTransfer => info::Trampoline::StreamTransfer,
Trampoline::ErrorContextTransfer => info::Trampoline::ErrorContextTransfer,
Trampoline::Trap => info::Trampoline::Trap,
Trampoline::EnterSyncCall => info::Trampoline::EnterSyncCall,
Trampoline::ExitSyncCall => info::Trampoline::ExitSyncCall,
Trampoline::ContextGet { instance, slot } => info::Trampoline::ContextGet {
instance: *instance,
slot: *slot,
},
Trampoline::ContextSet { instance, slot } => info::Trampoline::ContextSet {
instance: *instance,
slot: *slot,
},
Trampoline::ThreadIndex => info::Trampoline::ThreadIndex,
Trampoline::ThreadNewIndirect {
instance,
start_func_ty_idx,
start_func_table_id,
} => info::Trampoline::ThreadNewIndirect {
instance: *instance,
start_func_ty_idx: *start_func_ty_idx,
start_func_table_idx: self.runtime_table(*start_func_table_id),
},
Trampoline::ThreadSwitchTo {
instance,
cancellable,
} => info::Trampoline::ThreadSwitchTo {
instance: *instance,
cancellable: *cancellable,
},
Trampoline::ThreadSuspend {
instance,
cancellable,
} => info::Trampoline::ThreadSuspend {
instance: *instance,
cancellable: *cancellable,
},
Trampoline::ThreadResumeLater { instance } => info::Trampoline::ThreadResumeLater {
instance: *instance,
},
Trampoline::ThreadYieldTo {
instance,
cancellable,
} => info::Trampoline::ThreadYieldTo {
instance: *instance,
cancellable: *cancellable,
},
};
let i1 = self.trampolines.push(*signature);
let i2 = self.trampoline_defs.push(trampoline);
assert_eq!(i1, i2);
self.trampoline_map.insert(index, i1);
i1
}
fn core_export<T>(&mut self, export: &CoreExport<T>) -> info::CoreExport<T>
where
T: Clone,
{
let instance = export.instance;
log::trace!("referencing export of {instance:?}");
info::CoreExport {
instance: self.runtime_instances[&RuntimeInstance::Normal(instance)],
item: export.item.clone(),
}
}
fn adapter(&mut self, adapter: AdapterId) -> info::CoreExport<EntityIndex> {
let (adapter_module, entity_index) = self.dfg.adapter_partitionings[adapter];
let instance = self.adapter_module(adapter_module);
info::CoreExport {
instance,
item: ExportItem::Index(entity_index),
}
}
fn adapter_module(&mut self, adapter_module: AdapterModuleId) -> RuntimeInstanceIndex {
self.intern(
RuntimeInstance::Adapter(adapter_module),
|me| &mut me.runtime_instances,
|me, _| {
log::debug!("instantiating {adapter_module:?}");
let (module_index, args) = &me.dfg.adapter_modules[adapter_module];
let args = args.iter().map(|arg| me.core_def(arg)).collect();
let instantiate = InstantiateModule::Static(*module_index, args);
GlobalInitializer::InstantiateModule(instantiate, None)
},
|_, init| init,
)
}
fn intern<K, V, T>(
&mut self,
key: K,
map: impl Fn(&mut Self) -> &mut HashMap<K, V>,
generate: impl FnOnce(&mut Self, K) -> T,
init: impl FnOnce(V, T) -> GlobalInitializer,
) -> V
where
K: Hash + Eq + Copy,
V: EntityRef,
{
self.intern_(key, map, generate, |me, key, val| {
me.initializers.push(init(key, val));
})
}
fn intern_no_init<K, V, T>(
&mut self,
key: K,
map: impl Fn(&mut Self) -> &mut HashMap<K, V>,
generate: impl FnOnce(&mut Self, K) -> T,
) -> V
where
K: Hash + Eq + Copy,
V: EntityRef,
{
self.intern_(key, map, generate, |_me, _key, _val| {})
}
fn intern_<K, V, T>(
&mut self,
key: K,
map: impl Fn(&mut Self) -> &mut HashMap<K, V>,
generate: impl FnOnce(&mut Self, K) -> T,
init: impl FnOnce(&mut Self, V, T),
) -> V
where
K: Hash + Eq + Copy,
V: EntityRef,
{
if let Some(val) = map(self).get(&key) {
return *val;
}
let tmp = generate(self, key);
let index = V::new(map(self).len());
init(self, index, tmp);
let prev = map(self).insert(key, index);
assert!(prev.is_none());
index
}
}