Skip to content

Commit cd4ec0e

Browse files
authored
Skip {enter,exit}-sync-call for "thread-transparent" adapters (#14270)
* Skip `{enter,exit}-sync-call` for "thread-transparent" adapters Today, every sync adapter calls `enter-sync-call`, then does its lifting and lowering of arguments and reesults, and then calls `exit-sync-call` afterwards. The `{enter,exit}-sync-call` helpers save and restore the old thread's TLS context and create the new thread's TLS context. For sync-to-sync calls, we inline these helpers and do their work lazily via the `VMDeferredThread` machinery. But even so, creating a lazy `VMDeferredThread` can be pretty expensive if the adapter's callee is just doing like a single load or store or has been boiled away into returning a constant value. Therefore, this commit introduces an analysis to find "thread-transparent" components. These are components that do not `canon lower` any component model intrinsic to access the thread state, and therefore *cannot* read or write that state. When we are compiling adapters whose callee is thread-transparent, we don't even need to `{enter,exit}-sync-call` at all because the callee will not read/write its thread state, so we don't need to save and restore the current thread state, we can just leave it in place. * Address review feedback * Address more review feedback
1 parent 774dec1 commit cd4ec0e

25 files changed

Lines changed: 1620 additions & 152 deletions

File tree

crates/cranelift/src/compiler/component.rs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1189,7 +1189,7 @@ impl<'a> TrampolineCompiler<'a> {
11891189
}
11901190

11911191
if self.compiler.tunables.concurrency_support {
1192-
Some(self.enter_sync_call_inline(instance, def.instance))
1192+
Some(self.enter_sync_call_inline(def.instance))
11931193
} else {
11941194
None
11951195
}
@@ -1286,14 +1286,9 @@ impl<'a> TrampolineCompiler<'a> {
12861286
/// otherwise do eagerly.
12871287
fn enter_sync_call_inline(
12881288
&mut self,
1289-
caller_instance: RuntimeComponentInstanceIndex,
12901289
callee_instance: RuntimeComponentInstanceIndex,
12911290
) -> ir::StackSlot {
12921291
let vmctx = self.caller_vmctx();
1293-
let caller_instance = self
1294-
.builder
1295-
.ins()
1296-
.iconst(ir::types::I32, i64::from(caller_instance.as_u32()));
12971292
let callee_async = self.builder.ins().iconst(ir::types::I32, 0);
12981293
let callee_instance = self
12991294
.builder
@@ -1304,7 +1299,6 @@ impl<'a> TrampolineCompiler<'a> {
13041299
&mut self.alias_regions,
13051300
vmctx,
13061301
crate::component_sync_call::EnterArgs {
1307-
caller_instance,
13081302
callee_async,
13091303
callee_instance,
13101304
},

crates/cranelift/src/component_sync_call.rs

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,6 @@ use wasmtime_environ::{GetPtrSize, NUM_COMPONENT_CONTEXT_SLOTS, PtrSize};
2929
/// `VMDeferredThread`, to be replayed by the host if it ever has to promote the
3030
/// deferred thread into a real one.
3131
pub struct EnterArgs {
32-
/// The component instance performing the call.
33-
pub caller_instance: ir::Value,
3432
/// Whether the callee is async-lifted, as an `i32` boolean.
3533
pub callee_async: ir::Value,
3634
/// The component instance being called into.
@@ -79,11 +77,6 @@ where
7977
.store(&mut builder.cursor(), slot_addr, parent);
8078

8179
// Record the deferred `enter_sync_call` arguments.
82-
alias_regions.vm_deferred_thread().caller_instance().store(
83-
&mut builder.cursor(),
84-
slot_addr,
85-
args.caller_instance,
86-
);
8780
alias_regions.vm_deferred_thread().callee_async().store(
8881
&mut builder.cursor(),
8982
slot_addr,

crates/cranelift/src/func_environ.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2078,18 +2078,17 @@ impl<'a, 'func, 'module_env> Call<'a, 'func, 'module_env> {
20782078
/// defers the heavyweight task bookkeeping the `enter_sync_call` libcall
20792079
/// would otherwise do eagerly.
20802080
///
2081-
/// `real_call_args` is `[callee_vmctx, caller_vmctx, caller_instance,
2082-
/// callee_async, callee_instance]`.
2081+
/// `real_call_args` is `[callee_vmctx, caller_vmctx, callee_async,
2082+
/// callee_instance]`.
20832083
fn lower_fact_enter_sync_call(&mut self, real_call_args: &[ir::Value]) -> CallRets {
20842084
let vmctx = self.env.vmctx_val(&mut self.builder.cursor());
20852085
let slot = crate::component_sync_call::enter(
20862086
self.builder,
20872087
&mut self.env.alias_regions,
20882088
vmctx,
20892089
crate::component_sync_call::EnterArgs {
2090-
caller_instance: real_call_args[2],
2091-
callee_async: real_call_args[3],
2092-
callee_instance: real_call_args[4],
2090+
callee_async: real_call_args[2],
2091+
callee_instance: real_call_args[3],
20932092
},
20942093
);
20952094

crates/environ/src/component.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,12 +69,16 @@ mod compiler;
6969
#[cfg(feature = "compile")]
7070
pub mod dfg;
7171
#[cfg(feature = "compile")]
72+
mod thread_transparency;
73+
#[cfg(feature = "compile")]
7274
mod translate;
7375
#[cfg(feature = "compile")]
7476
mod types_builder;
7577
#[cfg(feature = "compile")]
7678
pub use self::compiler::*;
7779
#[cfg(feature = "compile")]
80+
pub use self::thread_transparency::transparent_adapters;
81+
#[cfg(feature = "compile")]
7882
pub use self::translate::*;
7983
#[cfg(feature = "compile")]
8084
pub use self::types_builder::*;
@@ -97,7 +101,7 @@ macro_rules! foreach_builtin_component_function {
97101
resource_transfer_own(vmctx: vmctx, src_idx: u32, src_table: u32, dst_table: u32) -> u64;
98102
resource_transfer_borrow(vmctx: vmctx, src_idx: u32, src_table: u32, dst_table: u32) -> u64;
99103

100-
enter_sync_call(vmctx: vmctx, caller_instance: u32, callee_async: u32, callee_instance: u32) -> bool;
104+
enter_sync_call(vmctx: vmctx, callee_async: u32, callee_instance: u32) -> bool;
101105
exit_sync_call(vmctx: vmctx) -> bool;
102106

103107
#[cfg(feature = "component-model-async")]

crates/environ/src/component/dfg.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ use crate::component::*;
3131
use crate::error::Result;
3232
use crate::prelude::*;
3333
use crate::{EntityIndex, EntityRef, ModuleInternedTypeIndex, PrimaryMap, Trap, WasmValType};
34+
use cranelift_entity::EntitySet;
3435
use cranelift_entity::packed_option::PackedOption;
3536
use indexmap::IndexMap;
3637
use info::LinearMemoryOptions;
@@ -143,13 +144,17 @@ pub struct ComponentDfg {
143144
///
144145
/// Currently all side effects are either instantiating core wasm modules or
145146
/// declaring a resource. These side effects affect the dataflow processing
146-
/// of this component by idnicating what order operations should be
147+
/// of this component by indicating what order operations should be
147148
/// performed during instantiation.
148149
pub side_effects: Vec<SideEffect>,
149150

150151
/// Interned map of id-to-`CanonicalOptions`, or all sets-of-options used by
151152
/// this component.
152153
pub options: Intern<OptionsId, CanonicalOptions>,
154+
155+
/// The set of fused adapters which may skip their
156+
/// `{enter,exit}-sync-call` window.
157+
pub transparent_adapters: EntitySet<AdapterId>,
153158
}
154159

155160
/// Possible side effects that are possible with instantiating this component.

0 commit comments

Comments
 (0)