Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 20 additions & 4 deletions crates/cranelift/src/compiler/component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -664,6 +664,22 @@ impl<'a> TrampolineCompiler<'a> {
|_, _| {},
);
}
Trampoline::SyncToSyncEnterCall => {
self.translate_libcall(
host::sync_to_sync_enter_call,
TrapSentinel::NegativeOne,
WasmArgs::InRegisters,
|_, _| {},
);
}
Trampoline::SyncToSyncExitCall => {
self.translate_libcall(
host::sync_to_sync_exit_call,
TrapSentinel::Falsy,
WasmArgs::InRegisters,
|_, _| {},
);
}
Trampoline::PrepareCall { memory } => {
self.translate_libcall(
host::prepare_call,
Expand All @@ -675,7 +691,7 @@ impl<'a> TrampolineCompiler<'a> {
},
);
}
Trampoline::SyncStartCall { callback } => {
Trampoline::SyncToAsyncStartCall { callback } => {
let pointer_type = self.isa.pointer_type();
let (values_vec_ptr, len) = self.compiler.allocate_stack_array_and_spill_args(
&WasmFuncType::new(
Expand All @@ -687,7 +703,7 @@ impl<'a> TrampolineCompiler<'a> {
);
let values_vec_len = self.builder.ins().iconst(pointer_type, i64::from(len));
self.translate_libcall(
host::sync_start,
host::sync_to_async_start,
HostResult::MultiValue {
ptr: Some(values_vec_ptr),
len: Some(values_vec_len),
Expand All @@ -701,12 +717,12 @@ impl<'a> TrampolineCompiler<'a> {
},
);
}
Trampoline::AsyncStartCall {
Trampoline::AsyncToAnyStartCall {
callback,
post_return,
} => {
self.translate_libcall(
host::async_start,
host::async_to_any_start,
TrapSentinel::NegativeOne,
WasmArgs::InRegisters,
|me, params| {
Expand Down
8 changes: 2 additions & 6 deletions crates/environ/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ component-model = [
"dep:semver",
"wasmparser/component-model",
]
component-model-async = ['component-model']
demangle = ['std', 'dep:rustc-demangle', 'dep:cpp_demangle']
gc = []
gc-drc = ["gc"]
Expand All @@ -74,9 +75,4 @@ compile = [
stack-switching = []
threads = ['std']
wmemcheck = ['std']
std = [
'anyhow/std',
'object/std',
'wasmparser/std',
'indexmap/std',
]
std = ['anyhow/std', 'object/std', 'wasmparser/std', 'indexmap/std']
16 changes: 14 additions & 2 deletions crates/environ/src/component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,18 @@ macro_rules! foreach_builtin_component_function {
resource_enter_call(vmctx: vmctx);
resource_exit_call(vmctx: vmctx) -> bool;

// Returns an `Option<(u32,u32)>` where `None` is "no thread to restore"
// and `Some((task,thread))` is "restore this thread after the sync call".
// The option is encoded as a 64-bit integer where the low bit is Some/None,
// bits 1-32 are the thread ID and bits 33-64 are the task ID.
#[cfg(feature = "component-model-async")]
sync_to_sync_enter_call(
vmctx: vmctx,
caller_instance: u32,
callee_instance: u32) -> u64;
#[cfg(feature = "component-model-async")]
sync_to_sync_exit_call(vmctx: vmctx, callee_instance: u32, old_thread: u64) -> bool;

#[cfg(feature = "component-model-async")]
backpressure_set(vmctx: vmctx, caller_instance: u32, enabled: u32) -> bool;
#[cfg(feature = "component-model-async")]
Expand Down Expand Up @@ -138,9 +150,9 @@ macro_rules! foreach_builtin_component_function {
storage_len: size
) -> bool;
#[cfg(feature = "component-model-async")]
sync_start(vmctx: vmctx, callback: ptr_u8, storage: ptr_u8, storage_len: size, callee: ptr_u8, param_count: u32) -> bool;
sync_to_async_start(vmctx: vmctx, callback: ptr_u8, storage: ptr_u8, storage_len: size, callee: ptr_u8, param_count: u32) -> bool;
#[cfg(feature = "component-model-async")]
async_start(vmctx: vmctx, callback: ptr_u8, post_return: ptr_u8, callee: ptr_u8, param_count: u32, result_count: u32, flags: u32) -> u64;
async_to_any_start(vmctx: vmctx, callback: ptr_u8, post_return: ptr_u8, callee: ptr_u8, param_count: u32, result_count: u32, flags: u32) -> u64;
#[cfg(feature = "component-model-async")]
future_new(vmctx: vmctx, caller_instance: u32, ty: u32) -> u64;
#[cfg(feature = "component-model-async")]
Expand Down
53 changes: 37 additions & 16 deletions crates/environ/src/component/dfg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -229,10 +229,15 @@ id! {
/// Same as `info::InstantiateModule`
#[expect(missing_docs, reason = "tedious to document variants")]
pub enum Instance {
Static(StaticModuleIndex, Box<[CoreDef]>),
Static(
StaticModuleIndex,
Box<[CoreDef]>,
RuntimeComponentInstanceIndex,
),
Import(
RuntimeImportIndex,
IndexMap<String, IndexMap<String, CoreDef>>,
RuntimeComponentInstanceIndex,
),
}

Expand Down Expand Up @@ -276,7 +281,7 @@ pub enum CoreDef {
/// During translation into `info::CoreDef` this variant is erased and
/// replaced by `info::CoreDef::Export` since adapters are always
/// represented as the exports of a core wasm instance.
Adapter(AdapterId),
Adapter(AdapterId, RuntimeComponentInstanceIndex),
}

impl<T> From<CoreExport<T>> for CoreDef
Expand Down Expand Up @@ -465,13 +470,15 @@ pub enum Trampoline {
ResourceTransferBorrow,
ResourceEnterCall,
ResourceExitCall,
SyncToSyncEnterCall,
SyncToSyncExitCall,
PrepareCall {
memory: Option<MemoryId>,
},
SyncStartCall {
SyncToAsyncStartCall {
callback: Option<CallbackId>,
},
AsyncStartCall {
AsyncToAnyStartCall {
callback: Option<CallbackId>,
post_return: Option<PostReturnId>,
},
Expand Down Expand Up @@ -735,11 +742,12 @@ impl LinearizeDfg<'_> {
fn instantiate(&mut self, instance: InstanceId, args: &Instance) {
log::trace!("creating instance {instance:?}");
let instantiation = match args {
Instance::Static(index, args) => InstantiateModule::Static(
Instance::Static(index, args, component_instance) => InstantiateModule::Static(
*index,
args.iter().map(|def| self.core_def(def)).collect(),
*component_instance,
),
Instance::Import(index, args) => InstantiateModule::Import(
Instance::Import(index, args, component_instance) => InstantiateModule::Import(
*index,
args.iter()
.map(|(module, values)| {
Expand All @@ -750,6 +758,7 @@ impl LinearizeDfg<'_> {
(module.clone(), values)
})
.collect(),
*component_instance,
),
};
let index = RuntimeInstanceIndex::new(self.runtime_instances.len());
Expand Down Expand Up @@ -897,7 +906,7 @@ impl LinearizeDfg<'_> {
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::Adapter(id, instance) => info::CoreDef::Export(self.adapter(*id, *instance)),
CoreDef::Trampoline(index) => info::CoreDef::Trampoline(self.trampoline(*index)),
CoreDef::UnsafeIntrinsic(ty, i) => {
let index = usize::try_from(i.index()).unwrap();
Expand Down Expand Up @@ -1144,16 +1153,20 @@ impl LinearizeDfg<'_> {
Trampoline::ResourceTransferBorrow => info::Trampoline::ResourceTransferBorrow,
Trampoline::ResourceEnterCall => info::Trampoline::ResourceEnterCall,
Trampoline::ResourceExitCall => info::Trampoline::ResourceExitCall,
Trampoline::SyncToSyncEnterCall => info::Trampoline::SyncToSyncEnterCall,
Trampoline::SyncToSyncExitCall => info::Trampoline::SyncToSyncExitCall,
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 {
Trampoline::SyncToAsyncStartCall { callback } => {
info::Trampoline::SyncToAsyncStartCall {
callback: callback.map(|v| self.runtime_callback(v)),
}
}
Trampoline::AsyncToAnyStartCall {
callback,
post_return,
} => info::Trampoline::AsyncStartCall {
} => info::Trampoline::AsyncToAnyStartCall {
callback: callback.map(|v| self.runtime_callback(v)),
post_return: post_return.map(|v| self.runtime_post_return(v)),
},
Expand Down Expand Up @@ -1222,13 +1235,17 @@ impl LinearizeDfg<'_> {
}
}

fn adapter(&mut self, adapter: AdapterId) -> info::CoreExport<EntityIndex> {
fn adapter(
&mut self,
adapter: AdapterId,
instance: RuntimeComponentInstanceIndex,
) -> info::CoreExport<EntityIndex> {
let (adapter_module, entity_index) = self.dfg.adapter_partitionings[adapter];

// Instantiates the adapter module if it hasn't already been
// instantiated or otherwise returns the index that the module was
// already instantiated at.
let instance = self.adapter_module(adapter_module);
let instance = self.adapter_module(adapter_module, instance);

// This adapter is always an export of the instance.
info::CoreExport {
Expand All @@ -1237,15 +1254,19 @@ impl LinearizeDfg<'_> {
}
}

fn adapter_module(&mut self, adapter_module: AdapterModuleId) -> RuntimeInstanceIndex {
fn adapter_module(
&mut self,
adapter_module: AdapterModuleId,
instance: RuntimeComponentInstanceIndex,
) -> 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);
let instantiate = InstantiateModule::Static(*module_index, args, instance);
GlobalInitializer::InstantiateModule(instantiate)
},
|_, init| init,
Expand Down
26 changes: 20 additions & 6 deletions crates/environ/src/component/info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,11 @@ pub enum InstantiateModule {
/// order of imports required is statically known and can be pre-calculated
/// to avoid string lookups related to names at runtime, represented by the
/// flat list of arguments here.
Static(StaticModuleIndex, Box<[CoreDef]>),
Static(
StaticModuleIndex,
Box<[CoreDef]>,
RuntimeComponentInstanceIndex,
),

/// An imported module is being instantiated.
///
Expand All @@ -366,6 +370,7 @@ pub enum InstantiateModule {
Import(
RuntimeImportIndex,
IndexMap<String, IndexMap<String, CoreDef>>,
RuntimeComponentInstanceIndex,
),
}

Expand Down Expand Up @@ -1058,6 +1063,13 @@ pub enum Trampoline {
/// Same as `ResourceEnterCall` except for when exiting a call.
ResourceExitCall,

/// An intrinsic used by FACT-generated modules which indicates that a call
/// is being entered and thread/resource-related metadata needs to be configured.
SyncToSyncEnterCall,

/// Same as `SyncToSyncEnterCall` except for when exiting a call.
SyncToSyncExitCall,

/// An intrinsic used by FACT-generated modules to prepare a call involving
/// an async-lowered import and/or an async-lifted export.
PrepareCall {
Expand All @@ -1069,19 +1081,19 @@ pub enum Trampoline {

/// An intrinsic used by FACT-generated modules to start a call involving a
/// sync-lowered import and async-lifted export.
SyncStartCall {
SyncToAsyncStartCall {
/// The callee's callback function, if any.
callback: Option<RuntimeCallbackIndex>,
},

/// An intrinsic used by FACT-generated modules to start a call involving
/// an async-lowered import function.
///
/// Note that `AsyncPrepareCall` and `AsyncStartCall` could theoretically be
/// Note that `PrepareCall` and `AsyncToAnyStartCall` could theoretically be
/// combined into a single `AsyncCall` intrinsic, but we separate them to
/// allow the FACT-generated module to optionally call the callee directly
/// without an intermediate host stack frame.
AsyncStartCall {
AsyncToAnyStartCall {
/// The callee's callback, if any.
callback: Option<RuntimeCallbackIndex>,
/// The callee's post-return function, if any.
Expand Down Expand Up @@ -1236,9 +1248,11 @@ impl Trampoline {
ResourceTransferBorrow => format!("component-resource-transfer-borrow"),
ResourceEnterCall => format!("component-resource-enter-call"),
ResourceExitCall => format!("component-resource-exit-call"),
SyncToSyncEnterCall => format!("component-sync-to-sync-enter-call"),
SyncToSyncExitCall => format!("component-sync-to-sync-exit-call"),
PrepareCall { .. } => format!("component-prepare-call"),
SyncStartCall { .. } => format!("component-sync-start-call"),
AsyncStartCall { .. } => format!("component-async-start-call"),
SyncToAsyncStartCall { .. } => format!("component-sync-to-async-start-call"),
AsyncToAnyStartCall { .. } => format!("component-async-to-any-start-call"),
FutureTransfer => format!("future-transfer"),
StreamTransfer => format!("stream-transfer"),
ErrorContextTransfer => format!("error-context-transfer"),
Expand Down
2 changes: 1 addition & 1 deletion crates/environ/src/component/translate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -559,7 +559,7 @@ impl<'a, 'data> Translator<'a, 'data> {
for init in &translation.component.initializers {
match init {
GlobalInitializer::InstantiateModule(instantiation) => match instantiation {
InstantiateModule::Static(module, args) => {
InstantiateModule::Static(module, args, _) => {
instantiations[*module].join(AbstractInstantiations::One(&*args));
instance_to_module.push(Some(*module).into());
}
Expand Down
16 changes: 9 additions & 7 deletions crates/environ/src/component/translate/adapt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -325,18 +325,20 @@ fn fact_import_to_core_def(
}
fact::Import::ResourceEnterCall => simple_intrinsic(dfg::Trampoline::ResourceEnterCall),
fact::Import::ResourceExitCall => simple_intrinsic(dfg::Trampoline::ResourceExitCall),
fact::Import::SyncToSyncEnterCall => simple_intrinsic(dfg::Trampoline::SyncToSyncEnterCall),
fact::Import::SyncToSyncExitCall => simple_intrinsic(dfg::Trampoline::SyncToSyncExitCall),
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 {
fact::Import::SyncToAsyncStartCall { callback } => {
simple_intrinsic(dfg::Trampoline::SyncToAsyncStartCall {
callback: callback.clone().map(|v| dfg.callbacks.push(v)),
})
}
fact::Import::AsyncStartCall {
fact::Import::AsyncToAnyStartCall {
callback,
post_return,
} => simple_intrinsic(dfg::Trampoline::AsyncStartCall {
} => simple_intrinsic(dfg::Trampoline::AsyncToAnyStartCall {
callback: callback.clone().map(|v| dfg.callbacks.push(v)),
post_return: post_return.clone().map(|v| dfg.post_returns.push(v)),
}),
Expand Down Expand Up @@ -430,7 +432,7 @@ impl PartitionAdapterModules {
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) => {
dfg::CoreDef::Adapter(id, _) => {
// If this adapter is already defined then we can safely depend
// on it with no consequences.
if self.defined_items.contains(&Def::Adapter(*id)) {
Expand Down Expand Up @@ -482,12 +484,12 @@ impl PartitionAdapterModules {
// then the instances own arguments are recursively visited to find
// transitive dependencies on adapters.
match &dfg.instances[instance] {
dfg::Instance::Static(_, args) => {
dfg::Instance::Static(_, args, _) => {
for arg in args.iter() {
self.core_def(dfg, arg);
}
}
dfg::Instance::Import(_, args) => {
dfg::Instance::Import(_, args, _) => {
for (_, values) in args {
for (_, def) in values {
self.core_def(dfg, def);
Expand Down
Loading
Loading