Skip to content

Commit abc6aab

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 1fc502c commit abc6aab

4 files changed

Lines changed: 55 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(
18161817
&mut self,
18171818
track_scope: bool,
@@ -1838,6 +1839,7 @@ impl StoreOpaque {
18381839
/// This is used to update the current thread annotations within the store
18391840
/// to ensure that it reflects the guest task, not the host task, since
18401841
/// lowering may execute guest code.
1842+
#[inline]
18411843
pub fn host_task_reenter_caller(&mut self) -> Result<()> {
18421844
if !self.concurrency_support() {
18431845
return Ok(());
@@ -1854,6 +1856,7 @@ impl StoreOpaque {
18541856
/// Note that this isn't invoked when the host is invoked asynchronously and
18551857
/// the host isn't complete yet. In that situation the host task persists
18561858
/// and will be cleaned up separately in `subtask_drop`
1859+
#[inline]
18571860
pub(crate) fn host_task_delete(
18581861
&mut self,
18591862
task: Option<TableId<HostTask>>,
@@ -2355,6 +2358,7 @@ impl StoreOpaque {
23552358

23562359
/// Used by `ResourceTables` to record the scope of a borrow to get undone
23572360
/// in the future.
2361+
#[inline]
23582362
pub(crate) fn current_scope_id(&mut self) -> Result<Option<u32>> {
23592363
if !self.concurrency_support() {
23602364
return self.current_scope_id_not_concurrent();

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

Lines changed: 18 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,14 @@ 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(
399+
store.as_context_mut(),
400+
instance,
401+
ty,
402+
options,
403+
storage,
404+
track_scope,
405+
)?;
398406
true
399407
};
400408

@@ -417,15 +425,21 @@ where
417425
/// the `async` option when lowered. Note that the host function itself
418426
/// can still be async, in which case this will block here waiting for it
419427
/// to finish.
428+
#[inline]
420429
fn call_sync_lower(
421430
&self,
422431
mut store: StoreContextMut<'_, T>,
423432
instance: Instance,
424433
ty: TypeFuncIndex,
425434
options: OptionsIndex,
426435
storage: &mut [MaybeUninit<ValRaw>],
436+
track_scope: bool,
427437
) -> Result<()> {
428-
let mut lift = LiftContext::new(store.0.store_opaque_mut(), options, instance)?;
438+
let mut lift = if track_scope {
439+
LiftContext::new(store.0.store_opaque_mut(), options, instance)?
440+
} else {
441+
LiftContext::new_without_scope(store.0.store_opaque_mut(), options, instance)?
442+
};
429443
let (params, rest) = self.load_params(&mut lift, ty, MAX_FLAT_PARAMS, storage)?;
430444

431445
let ret = match self.run(store.as_context_mut(), params) {
@@ -533,6 +547,7 @@ where
533547
///
534548
/// This will internally decide the ABI source of the parameters and use
535549
/// `storage` appropriately.
550+
#[inline]
536551
fn load_params<'a>(
537552
&self,
538553
lift: &mut LiftContext<'_>,
@@ -568,6 +583,7 @@ where
568583
}
569584

570585
/// Stores the result `ret` into `dst` which is calculated per the ABI.
586+
#[inline]
571587
fn lower_result_and_exit_call(
572588
lower: &mut LowerContext<'_, T>,
573589
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)