Skip to content

Commit d37fb2f

Browse files
committed
Skip scope resolution in LiftContext if possible
Extends skipping scope resolution introduced in the previous commit to also cover the LiftContext used in sync calls. Plus, inline a bunch of single-instantiation generics. Relative to the previous commit, this reduces call overhead by another 31% for sync calls (46ns to 32ns), with async calls unchanged (both measured in a Linux VM on an M5 Max MBP).
1 parent 7b8d68d commit d37fb2f

4 files changed

Lines changed: 48 additions & 3 deletions

File tree

crates/wasmtime/src/runtime/component/concurrent.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1812,6 +1812,7 @@ impl StoreOpaque {
18121812
/// relatively expensive table manipulations. This would ideally be
18131813
/// optimized to avoid the full allocation of a `HostTask` in at least some
18141814
/// situations.
1815+
#[inline]
18151816
pub(crate) fn host_task_create(&mut self, track_scope: bool) -> Result<Option<TableId<HostTask>>> {
18161817
if !self.concurrency_support() {
18171818
// Resource-borrow scope tracking is only needed when the
@@ -1835,6 +1836,7 @@ impl StoreOpaque {
18351836
/// This is used to update the current thread annotations within the store
18361837
/// to ensure that it reflects the guest task, not the host task, since
18371838
/// lowering may execute guest code.
1839+
#[inline]
18381840
pub fn host_task_reenter_caller(&mut self) -> Result<()> {
18391841
if !self.concurrency_support() {
18401842
return Ok(());
@@ -1851,6 +1853,7 @@ impl StoreOpaque {
18511853
/// Note that this isn't invoked when the host is invoked asynchronously and
18521854
/// the host isn't complete yet. In that situation the host task persists
18531855
/// and will be cleaned up separately in `subtask_drop`
1856+
#[inline]
18541857
pub(crate) fn host_task_delete(
18551858
&mut self,
18561859
task: Option<TableId<HostTask>>,
@@ -2352,6 +2355,7 @@ impl StoreOpaque {
23522355

23532356
/// Used by `ResourceTables` to record the scope of a borrow to get undone
23542357
/// in the future.
2358+
#[inline]
23552359
pub(crate) fn current_scope_id(&mut self) -> Result<Option<u32>> {
23562360
if !self.concurrency_support() {
23572361
return self.current_scope_id_not_concurrent();

crates/wasmtime/src/runtime/component/func/host.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,7 @@ where
359359

360360
/// "Rust" entrypoint after panic-handling infrastructure is set up and raw
361361
/// arguments are translated to Rust types.
362+
#[inline]
362363
fn entrypoint(
363364
&self,
364365
mut store: StoreContextMut<'_, T>,
@@ -394,7 +395,7 @@ where
394395
when `component-model-async` feature disabled"
395396
);
396397
} else {
397-
self.call_sync_lower(store.as_context_mut(), instance, ty, options, storage)?;
398+
self.call_sync_lower(store.as_context_mut(), instance, ty, options, storage, track_scope)?;
398399
true
399400
};
400401

@@ -417,15 +418,21 @@ where
417418
/// the `async` option when lowered. Note that the host function itself
418419
/// can still be async, in which case this will block here waiting for it
419420
/// to finish.
421+
#[inline]
420422
fn call_sync_lower(
421423
&self,
422424
mut store: StoreContextMut<'_, T>,
423425
instance: Instance,
424426
ty: TypeFuncIndex,
425427
options: OptionsIndex,
426428
storage: &mut [MaybeUninit<ValRaw>],
429+
track_scope: bool,
427430
) -> Result<()> {
428-
let mut lift = LiftContext::new(store.0.store_opaque_mut(), options, instance)?;
431+
let mut lift = if track_scope {
432+
LiftContext::new(store.0.store_opaque_mut(), options, instance)?
433+
} else {
434+
LiftContext::new_without_scope(store.0.store_opaque_mut(), options, instance)?
435+
};
429436
let (params, rest) = self.load_params(&mut lift, ty, MAX_FLAT_PARAMS, storage)?;
430437

431438
let ret = match self.run(store.as_context_mut(), params) {
@@ -533,6 +540,7 @@ where
533540
///
534541
/// This will internally decide the ABI source of the parameters and use
535542
/// `storage` appropriately.
543+
#[inline]
536544
fn load_params<'a>(
537545
&self,
538546
lift: &mut LiftContext<'_>,
@@ -568,6 +576,7 @@ where
568576
}
569577

570578
/// Stores the result `ret` into `dst` which is calculated per the ABI.
579+
#[inline]
571580
fn lower_result_and_exit_call(
572581
lower: &mut LowerContext<'_, T>,
573582
ty: TypeFuncIndex,

crates/wasmtime/src/runtime/component/func/options.rs

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -338,10 +338,36 @@ impl<'a> LiftContext<'a> {
338338
store: &'a mut StoreOpaque,
339339
options: OptionsIndex,
340340
instance_handle: Instance,
341+
) -> Result<LiftContext<'a>> {
342+
Self::new_impl(store, options, instance_handle, true)
343+
}
344+
345+
/// Same as [`Self::new`] but without resolving the current resource
346+
/// scope, for calls whose signature statically cannot contain `borrow`
347+
/// handles (the only consumers of the scope id).
348+
#[inline]
349+
pub(crate) fn new_without_scope(
350+
store: &'a mut StoreOpaque,
351+
options: OptionsIndex,
352+
instance_handle: Instance,
353+
) -> Result<LiftContext<'a>> {
354+
Self::new_impl(store, options, instance_handle, false)
355+
}
356+
357+
#[inline]
358+
fn new_impl(
359+
store: &'a mut StoreOpaque,
360+
options: OptionsIndex,
361+
instance_handle: Instance,
362+
want_scope: bool,
341363
) -> Result<LiftContext<'a>> {
342364
let store_id = store.id();
343365
let hostcall_fuel = store.hostcall_fuel();
344-
let current_scope_id = store.current_scope_id()?;
366+
let current_scope_id = if want_scope {
367+
store.current_scope_id()?
368+
} else {
369+
None
370+
};
345371
// From `&mut StoreOpaque` provided the goal here is to project out
346372
// three different disjoint fields owned by the store: memory,
347373
// `CallContexts`, and `HandleTable`. There's no native API for that

crates/wasmtime/src/runtime/component/store.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,7 @@ impl StoreComponentInstanceId {
218218
/// # Panics
219219
///
220220
/// Panics if `self` does not belong to `store`.
221+
#[inline]
221222
pub(crate) fn get<'a>(&self, store: &'a StoreOpaque) -> &'a ComponentInstance {
222223
self.assert_belongs_to(store.id());
223224
store.component_instance(self.instance)
@@ -228,6 +229,7 @@ impl StoreComponentInstanceId {
228229
/// # Panics
229230
///
230231
/// Panics if `self` does not belong to `store`.
232+
#[inline]
231233
pub(crate) fn get_mut<'a>(&self, store: &'a mut StoreOpaque) -> Pin<&'a mut ComponentInstance> {
232234
self.from_data_get_mut(store.store_data_mut())
233235
}
@@ -356,6 +358,7 @@ impl StoreOpaque {
356358
support
357359
}
358360

361+
#[inline]
359362
pub(crate) fn lift_context_parts(
360363
&mut self,
361364
instance: Instance,
@@ -420,6 +423,7 @@ impl StoreOpaque {
420423
))
421424
}
422425

426+
#[inline]
423427
pub(crate) fn enter_call_not_concurrent(&mut self) -> Result<()> {
424428
let state = match &mut self.component_data_mut().task_state {
425429
ComponentTaskState::NotConcurrent(state) => state,
@@ -430,6 +434,7 @@ impl StoreOpaque {
430434
Ok(())
431435
}
432436

437+
#[inline]
433438
pub(crate) fn exit_call_not_concurrent(&mut self) {
434439
let state = match &mut self.component_data_mut().task_state {
435440
ComponentTaskState::NotConcurrent(state) => state,
@@ -459,6 +464,7 @@ impl StoreOpaque {
459464
}
460465
}
461466

467+
#[inline]
462468
pub(crate) fn current_scope_id_not_concurrent(&mut self) -> Result<Option<u32>> {
463469
match &mut self.component_data_mut().task_state {
464470
ComponentTaskState::NotConcurrent(state) => match state.scopes.len().checked_sub(1) {

0 commit comments

Comments
 (0)