use crate::EntityType;
use crate::component::translate::*;
use crate::fact;
use std::collections::HashSet;
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
pub struct Adapter {
pub lift_ty: TypeFuncIndex,
pub lift_options: AdapterOptions,
pub lower_ty: TypeFuncIndex,
pub lower_options: AdapterOptions,
pub func: dfg::CoreDef,
}
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
pub enum DataModel {
Gc {},
LinearMemory {
memory: Option<dfg::CoreExport<MemoryIndex>>,
memory64: bool,
realloc: Option<dfg::CoreDef>,
},
}
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
pub struct AdapterOptions {
pub instance: RuntimeComponentInstanceIndex,
pub ancestors: Vec<RuntimeComponentInstanceIndex>,
pub string_encoding: StringEncoding,
pub callback: Option<dfg::CoreDef>,
pub post_return: Option<dfg::CoreDef>,
pub async_: bool,
pub cancellable: bool,
pub core_type: ModuleInternedTypeIndex,
pub data_model: DataModel,
}
impl<'data> Translator<'_, 'data> {
pub(super) fn partition_adapter_modules(&mut self, component: &mut dfg::ComponentDfg) {
let mut state = PartitionAdapterModules::default();
for (id, adapter) in component.adapters.iter() {
state.adapter(component, id, adapter);
}
state.finish_adapter_module();
for (module_id, adapter_module) in state.adapter_modules.iter() {
let mut module = fact::Module::new(self.types.types(), self.tunables);
let mut names = Vec::with_capacity(adapter_module.adapters.len());
for adapter in adapter_module.adapters.iter() {
let name = format!("adapter{}", adapter.as_u32());
module.adapt(&name, &component.adapters[*adapter]);
names.push(name);
}
let wasm = module.encode();
let imports = module.imports().to_vec();
let wasm = &*self.scope_vec.push(wasm);
if log::log_enabled!(log::Level::Trace) {
match wasmprinter::print_bytes(wasm) {
Ok(s) => log::trace!("generated adapter module:\n{s}"),
Err(e) => log::trace!("failed to print adapter module: {e}"),
}
}
self.validator.reset();
let static_module_index = self.static_modules.next_key();
let translation = ModuleEnvironment::new(
self.tunables,
&mut self.validator,
self.types.module_types_builder(),
static_module_index,
)
.translate(Parser::new(0), wasm)
.expect("invalid adapter module generated");
for (adapter, name) in adapter_module.adapters.iter().zip(&names) {
let index = translation.module.exports[name];
let i = component.adapter_partitionings.push((module_id, index));
assert_eq!(i, *adapter);
}
assert_eq!(imports.len(), translation.module.imports().len());
let args = imports
.iter()
.zip(translation.module.imports())
.map(|(arg, (_, _, ty))| fact_import_to_core_def(component, arg, ty))
.collect::<Vec<_>>();
let static_module_index2 = self.static_modules.push(translation);
assert_eq!(static_module_index, static_module_index2);
let id = component.adapter_modules.push((static_module_index, args));
assert_eq!(id, module_id);
}
}
}
fn fact_import_to_core_def(
dfg: &mut dfg::ComponentDfg,
import: &fact::Import,
ty: EntityType,
) -> dfg::CoreDef {
fn unwrap_memory(def: &dfg::CoreDef) -> dfg::CoreExport<MemoryIndex> {
match def {
dfg::CoreDef::Export(e) => e.clone().map_index(|i| match i {
EntityIndex::Memory(i) => i,
_ => unreachable!(),
}),
_ => unreachable!(),
}
}
let mut simple_intrinsic = |trampoline: dfg::Trampoline| {
let signature = ty.unwrap_func();
let index = dfg
.trampolines
.push((signature.unwrap_module_type_index(), trampoline));
dfg::CoreDef::Trampoline(index)
};
match import {
fact::Import::CoreDef(def) => def.clone(),
fact::Import::Transcode {
op,
from,
from64,
to,
to64,
} => {
let from = dfg.memories.push(unwrap_memory(from));
let to = dfg.memories.push(unwrap_memory(to));
let signature = ty.unwrap_func();
let index = dfg.trampolines.push((
signature.unwrap_module_type_index(),
dfg::Trampoline::Transcoder {
op: *op,
from,
from64: *from64,
to,
to64: *to64,
},
));
dfg::CoreDef::Trampoline(index)
}
fact::Import::ResourceTransferOwn => simple_intrinsic(dfg::Trampoline::ResourceTransferOwn),
fact::Import::ResourceTransferBorrow => {
simple_intrinsic(dfg::Trampoline::ResourceTransferBorrow)
}
fact::Import::ResourceEnterCall => simple_intrinsic(dfg::Trampoline::ResourceEnterCall),
fact::Import::ResourceExitCall => simple_intrinsic(dfg::Trampoline::ResourceExitCall),
fact::Import::PrepareCall { memory } => simple_intrinsic(dfg::Trampoline::PrepareCall {
memory: memory.as_ref().map(|v| dfg.memories.push(unwrap_memory(v))),
}),
fact::Import::SyncStartCall { callback } => {
simple_intrinsic(dfg::Trampoline::SyncStartCall {
callback: callback.clone().map(|v| dfg.callbacks.push(v)),
})
}
fact::Import::AsyncStartCall {
callback,
post_return,
} => simple_intrinsic(dfg::Trampoline::AsyncStartCall {
callback: callback.clone().map(|v| dfg.callbacks.push(v)),
post_return: post_return.clone().map(|v| dfg.post_returns.push(v)),
}),
fact::Import::FutureTransfer => simple_intrinsic(dfg::Trampoline::FutureTransfer),
fact::Import::StreamTransfer => simple_intrinsic(dfg::Trampoline::StreamTransfer),
fact::Import::ErrorContextTransfer => {
simple_intrinsic(dfg::Trampoline::ErrorContextTransfer)
}
fact::Import::Trap => simple_intrinsic(dfg::Trampoline::Trap),
fact::Import::EnterSyncCall => simple_intrinsic(dfg::Trampoline::EnterSyncCall),
fact::Import::ExitSyncCall => simple_intrinsic(dfg::Trampoline::ExitSyncCall),
}
}
#[derive(Default)]
struct PartitionAdapterModules {
next_module: AdapterModuleInProgress,
defined_items: HashSet<Def>,
adapter_modules: PrimaryMap<dfg::AdapterModuleId, AdapterModuleInProgress>,
}
#[derive(Default)]
struct AdapterModuleInProgress {
adapters: Vec<dfg::AdapterId>,
}
#[derive(Copy, Clone, Hash, Eq, PartialEq)]
enum Def {
Adapter(dfg::AdapterId),
Instance(dfg::InstanceId),
}
impl PartitionAdapterModules {
fn adapter(&mut self, dfg: &dfg::ComponentDfg, id: dfg::AdapterId, adapter: &Adapter) {
self.adapter_options(dfg, &adapter.lift_options);
self.adapter_options(dfg, &adapter.lower_options);
self.core_def(dfg, &adapter.func);
log::debug!("adding {id:?} to adapter module");
self.next_module.adapters.push(id);
}
fn adapter_options(&mut self, dfg: &dfg::ComponentDfg, options: &AdapterOptions) {
if let Some(def) = &options.callback {
self.core_def(dfg, def);
}
if let Some(def) = &options.post_return {
self.core_def(dfg, def);
}
match &options.data_model {
DataModel::Gc {} => {
}
DataModel::LinearMemory {
memory,
memory64: _,
realloc,
} => {
if let Some(memory) = memory {
self.core_export(dfg, memory);
}
if let Some(def) = realloc {
self.core_def(dfg, def);
}
}
}
}
fn core_def(&mut self, dfg: &dfg::ComponentDfg, def: &dfg::CoreDef) {
match def {
dfg::CoreDef::Export(e) => self.core_export(dfg, e),
dfg::CoreDef::Adapter(id) => {
if self.defined_items.contains(&Def::Adapter(*id)) {
log::debug!("using existing adapter {id:?} ");
return;
}
log::debug!("splitting module needing {id:?} ");
self.finish_adapter_module();
assert!(self.defined_items.contains(&Def::Adapter(*id)));
}
dfg::CoreDef::Trampoline(_)
| dfg::CoreDef::InstanceFlags(_)
| dfg::CoreDef::UnsafeIntrinsic(..)
| dfg::CoreDef::TaskMayBlock => {}
}
}
fn core_export<T>(&mut self, dfg: &dfg::ComponentDfg, export: &dfg::CoreExport<T>) {
let mut instance = export.instance;
while self.defined_items.insert(Def::Instance(instance)) {
self.instance(dfg, instance);
if instance.as_u32() == 0 {
break;
}
instance = dfg::InstanceId::from_u32(instance.as_u32() - 1);
}
}
fn instance(&mut self, dfg: &dfg::ComponentDfg, instance: dfg::InstanceId) {
log::debug!("visiting instance {instance:?}");
match &dfg.instances[instance] {
dfg::Instance::Static(_, args) => {
for arg in args.iter() {
self.core_def(dfg, arg);
}
}
dfg::Instance::Import(_, args) => {
for (_, values) in args {
for (_, def) in values {
self.core_def(dfg, def);
}
}
}
}
}
fn finish_adapter_module(&mut self) {
if self.next_module.adapters.is_empty() {
return;
}
let module = mem::take(&mut self.next_module);
for adapter in module.adapters.iter() {
let inserted = self.defined_items.insert(Def::Adapter(*adapter));
assert!(inserted);
}
let idx = self.adapter_modules.push(module);
log::debug!("finishing adapter module {idx:?}");
}
}