alexcrichton opened PR #12550 from alexcrichton:remove-call-contexts to bytecodealliance:main:
This commit is a somewhat deep refactoring of how the state of
borrow<T>is managed for both the host and the guest with respect to
async tasks. This additionally refactors how some async task management
is done for host-called functions.The fundamental problem being tackled here is https://github.com/bytecodealliance/wasmtime/issues/12510. In that issue it
was discovered that the wayCallContext, the borrow tracking mechanism
in Wasmtime, is managed is incompatible with async tasks. Specifically
the previous assumption of the scope being mutated for a borrow is
somewhere on the call stack is no longer true. It's possible for an
async task to be suspended, for example, and then a sibling task drops a
borrow which should update the scope of the suspended task. There were a
number of other small issues I noticed here and there which this PR
additionally has tests for, all of which failed before this change and
pass afterwards.The manner in which borrow state is manipulated is a pretty old part of
the component model implementation dating back to the original
implementation of resources. I decided to forgo any possible quick fix
and have attempted to more deeply refactor and integrate async tasks
into all of this infrastructure. A list of the changes made here are:
The
CallContextsstructure, a stack ofCallContext, was removed.
Tasks now directly store aCallContextwhich is the source of truth
for borrow tracking for that call, and it does not move from this
location. The storeCallContextsis now deleted in favor of updating
theOption<ConcurrentState>in the store to be anenumof either
concurrent state or a stack. In this manner the old stack-based
structure is still used sometimes, but it's impossible to reach when
concurrency is enabled.Entry to the host from guests now reliably pushes a
HostTaskinto
the store. Previously where a frame were always pushed into a
CallContextaHostTaskis pushed into the store. This is still
expected to be a bit too expensive for cheap host calls, but it
doesn't meaningfully change the performance profile of before.The
resource_enter_callandresource_exit_calllibcalls have been
removed. These are now folded into theenter_sync_calland
exit_sync_calllibcalls. Emission of these hooks has been updated
accordingly. The concept of entering a call more generally has been
removed. This is more formally known in the async world as a task
starting, so the task creation is now responsible for the demarcation
of entering a call. Additionally this means that the concept of
exiting a call has somewhat gone away. Instead this method was renamed
tovalidate_scope_exitwhich double-checks that a borrow-scope can
be exited but doesn't actually remove the task. Task removal is
deferred to preexisting mechanisms.Management of a
GuestTask's previousOption<CallContext>field,
for example taking/restoring and pushing/popping ontoCallContexts
is now all gone. All related code is outright deleted as the
GuestTask's now non-optionalCallContextfield is the source of truth.The
ConcurrentStatestructure now stores aCurrentThreadenum
instead ofOption<QualifiedThreadId>. This represents how the
currently executing thread could be a host thread, not just a guest
thread, which is required for borrow-tracking.
HostTaskcreation inpoll_and_blockandfirst_poll, the two main
entrypoints of async host tasks when called by the guest, is now
externalized from these functions. Instead these functions assume that
the currently running thread is already aHostTaskof some kind.In
poll_and_blockthe host's result is no longer stored in the guest
task but in the host task instead.Overall this enables the
*.wasttest for https://github.com/bytecodealliance/wasmtime/issues/12510 to fix the original
issue. This then adds new tests to ensure that cleanup of various
constructs happens appropriately, such as cancelling a host task should
clean up its associated resources. Additionally synchronously calling an
async host task no longer leaks resources in aStoreand should
properly clean up everything.There is still more work to do in this area (e.g. https://github.com/bytecodealliance/wasmtime/issues/12544) but that's
going to be deferred to a future PR at this point.Closes https://github.com/bytecodealliance/wasmtime/issues/12510
Depends on https://github.com/bytecodealliance/wasmtime/pull/12545, https://github.com/bytecodealliance/wasmtime/pull/12546, https://github.com/bytecodealliance/wasmtime/pull/12547, https://github.com/bytecodealliance/wasmtime/pull/12548, and https://github.com/bytecodealliance/wasmtime/pull/12549
alexcrichton requested wasmtime-core-reviewers for a review on PR #12550.
alexcrichton requested fitzgen for a review on PR #12550.
alexcrichton requested wasmtime-compiler-reviewers for a review on PR #12550.
alexcrichton updated PR #12550.
github-actions[bot] added the label wasmtime:api on PR #12550.
alexcrichton updated PR #12550.
alexcrichton edited PR #12550:
This commit is a somewhat deep refactoring of how the state of
borrow<T>is managed for both the host and the guest with respect to
async tasks. This additionally refactors how some async task management
is done for host-called functions.The fundamental problem being tackled here is https://github.com/bytecodealliance/wasmtime/issues/12510. In that issue it
was discovered that the wayCallContext, the borrow tracking mechanism
in Wasmtime, is managed is incompatible with async tasks. Specifically
the previous assumption of the scope being mutated for a borrow is
somewhere on the call stack is no longer true. It's possible for an
async task to be suspended, for example, and then a sibling task drops a
borrow which should update the scope of the suspended task. There were a
number of other small issues I noticed here and there which this PR
additionally has tests for, all of which failed before this change and
pass afterwards.The manner in which borrow state is manipulated is a pretty old part of
the component model implementation dating back to the original
implementation of resources. I decided to forgo any possible quick fix
and have attempted to more deeply refactor and integrate async tasks
into all of this infrastructure. A list of the changes made here are:
The
CallContextsstructure, a stack ofCallContext, was removed.
Tasks now directly store aCallContextwhich is the source of truth
for borrow tracking for that call, and it does not move from this
location. The storeCallContextsis now deleted in favor of updating
theOption<ConcurrentState>in the store to be anenumof either
concurrent state or a stack. In this manner the old stack-based
structure is still used sometimes, but it's impossible to reach when
concurrency is enabled.Entry to the host from guests now reliably pushes a
HostTaskinto
the store. Previously where a frame were always pushed into a
CallContextaHostTaskis pushed into the store. This is still
expected to be a bit too expensive for cheap host calls, but it
doesn't meaningfully change the performance profile of before.The
resource_enter_callandresource_exit_calllibcalls have been
removed. These are now folded into theenter_sync_calland
exit_sync_calllibcalls. Emission of these hooks has been updated
accordingly. The concept of entering a call more generally has been
removed. This is more formally known in the async world as a task
starting, so the task creation is now responsible for the demarcation
of entering a call. Additionally this means that the concept of
exiting a call has somewhat gone away. Instead this method was renamed
tovalidate_scope_exitwhich double-checks that a borrow-scope can
be exited but doesn't actually remove the task. Task removal is
deferred to preexisting mechanisms.Management of a
GuestTask's previousOption<CallContext>field,
for example taking/restoring and pushing/popping ontoCallContexts
is now all gone. All related code is outright deleted as the
GuestTask's now non-optionalCallContextfield is the source of truth.The
ConcurrentStatestructure now stores aCurrentThreadenum
instead ofOption<QualifiedThreadId>. This represents how the
currently executing thread could be a host thread, not just a guest
thread, which is required for borrow-tracking.
HostTaskcreation inpoll_and_blockandfirst_poll, the two main
entrypoints of async host tasks when called by the guest, is now
externalized from these functions. Instead these functions assume that
the currently running thread is already aHostTaskof some kind.In
poll_and_blockthe host's result is no longer stored in the guest
task but in the host task instead.Overall this enables the
*.wasttest for https://github.com/bytecodealliance/wasmtime/issues/12510 to fix the original
issue. This then adds new tests to ensure that cleanup of various
constructs happens appropriately, such as cancelling a host task should
clean up its associated resources. Additionally synchronously calling an
async host task no longer leaks resources in aStoreand should
properly clean up everything.There is still more work to do in this area (e.g. https://github.com/bytecodealliance/wasmtime/issues/12544) but that's
going to be deferred to a future PR at this point.Closes https://github.com/bytecodealliance/wasmtime/issues/12510
~~Depends on https://github.com/bytecodealliance/wasmtime/pull/12545, https://github.com/bytecodealliance/wasmtime/pull/12546, https://github.com/bytecodealliance/wasmtime/pull/12547, https://github.com/bytecodealliance/wasmtime/pull/12548, and https://github.com/bytecodealliance/wasmtime/pull/12549~~
fitzgen submitted PR review:
I'm not too familiar with the CM async stuff, but this LGTM in general. If you want more detailed feedback, flag another reviewer :)
alexcrichton requested dicej for a review on PR #12550.
dicej created PR review comment:
Consider renaming
expected_caller_instancetoexpected_callerhere since it's no longer an instance.
dicej created PR review comment:
As above, consider renaming this to
expected_caller.
dicej submitted PR review.
alexcrichton updated PR #12550.
alexcrichton has enabled auto merge for PR #12550.
alexcrichton added PR #12550 Refactor borrow state tracking for async tasks to the merge queue.
alexcrichton merged PR #12550.
alexcrichton removed PR #12550 Refactor borrow state tracking for async tasks from the merge queue.
Last updated: Feb 24 2026 at 04:36 UTC