erikrose opened PR #14579 from erikrose:interrupt-poll-instruction to bytecodealliance:main:
This is the first step toward implementing MMU-triggered interruption of Wasm (originally suggested in #1749). It's the first little PR broken off the large #12990 for ease of review.
This PR introduces a Cranelift instruction that facilitates resumeable preemptions: in this case, with MMU-based Wasm interruption in mind. However, the same technique is used by HotSpot for stop-the-world GC, so there is potential for other applications.
The original name for this instruction was
dead_load_with_context. At the time, that was sufficiently descriptive. However, since then, we've added…
- Reserving a second register as scratch space for trampolining
- Returning a new ptr to load from
Thus, it's become specialized enough to the task of implementing virtual-memory-triggered interruption mechanisms that it makes sense to rename it with that in mind.
erikrose updated PR #14579.
erikrose updated PR #14579.
github-actions[bot] added the label cranelift on PR #14579.
github-actions[bot] added the label cranelift:area:aarch64 on PR #14579.
github-actions[bot] added the label cranelift:area:x64 on PR #14579.
github-actions[bot] added the label cranelift:area:machinst on PR #14579.
github-actions[bot] added the label cranelift:docs on PR #14579.
github-actions[bot] added the label cranelift:meta on PR #14579.
github-actions[bot] added the label wasmtime:api on PR #14579.
erikrose edited PR #14579:
This is the first step toward implementing MMU-triggered interruption of Wasm (originally suggested in #1749). It's the first little PR broken off the large #12990 for ease of review.
This PR introduces a Cranelift instruction that facilitates resumeable preemptions: in this case, with MMU-based Wasm interruption in mind. However, the same technique is used by HotSpot for stop-the-world GC, so there is potential for other applications.
The original name for this instruction was
dead_load_with_context. At the time, that was sufficiently descriptive. However, since then, we've added…
- Reserving a second register as scratch space for trampolining
- Returning a new ptr to load from
Thus, it's become specialized enough to the task of implementing virtual-memory-triggered interruption mechanisms that it makes sense to rename it with that in mind.
erikrose updated PR #14579.
erikrose edited PR #14579:
This is the first step toward implementing MMU-triggered interruption of Wasm (originally suggested in #1749). It's the first little PR broken off the large #12990 for ease of review.
This PR introduces a Cranelift instruction that facilitates resumeable preemptions: in this case, with MMU-based Wasm interruption in mind. However, the same technique is used by HotSpot for stop-the-world GC, so there is potential for other applications.
The original name for this instruction was
dead_load_with_context. At the time, that was sufficiently descriptive. However, since then, we've added…
- Reserving a second register as scratch space for trampolining
- Returning a new ptr to load from
Thus, it's become specialized enough to the task of implementing virtual-memory-triggered interruption mechanisms that it makes sense to rename it with that in mind. Other names I considered include "preempt_poll" (but it ultimately functions cooperatively, so nah), "yield_poll" (too tightly coupled to the one use case I'm chasing right now), and "probe" instead of "poll". HotSpot uses "poll" for their mechanism, so that'll be familiar to some, and it carries a little bit more meaning (repeatedly doing something).
erikrose edited PR #14579:
This is the first step toward implementing MMU-triggered interruption of Wasm (originally suggested in #1749). It's the first little PR broken off the large #12990 for ease of review.
This PR introduces a Cranelift instruction that facilitates resumeable preemptions: in this case, with MMU-based Wasm interruption in mind. However, the same technique is used by HotSpot for stop-the-world GC, so there is potential for other applications.
The original name for this instruction was
dead_load_with_context. At the time, that was sufficiently descriptive. However, since then, we've added…
- Reserving a second register as scratch space for trampolining
- Returning a new ptr to load from next time
Thus, it's become specialized enough to the task of implementing virtual-memory-triggered interruption mechanisms that it makes sense to rename it with that in mind. Other names I considered include "preempt_poll" (but it ultimately functions cooperatively, so nah), "yield_poll" (too tightly coupled to the one use case I'm chasing right now), and "probe" instead of "poll". HotSpot uses "poll" for their mechanism, so that'll be familiar to some, and it carries a little bit more meaning (repeatedly doing something).
erikrose edited PR #14579:
This is the first step toward implementing MMU-triggered interruption of Wasm (originally suggested in #1749). It's the first little PR broken off the large #12990 for ease of review.
This PR introduces a Cranelift instruction that facilitates resumeable preemptions: in this case, with MMU-based Wasm interruption in mind. However, the same technique is used by HotSpot for stop-the-world GC, so there is potential for other applications.
The original name for this instruction was
dead_load_with_context. At the time, that was sufficiently descriptive. However, since then, we've added…
- Reserving a second register as scratch space for trampolining
- Returning a new ptr to load from next time
Thus, it's become specialized enough to the task of implementing virtual-memory-triggered interruption mechanisms that it makes sense to rename it with that in mind. Other names I considered include "preempt_poll" (but it ultimately functions cooperatively, so nah), "yield_poll" (too tightly coupled to the one use case I'm chasing right now), and "probe" instead of "poll". HotSpot uses "poll" for their mechanism, so that'll be familiar to some, and it usefully suggests that it will have to be done repeatedly in the usual case.
erikrose edited PR #14579:
This is the first step toward implementing MMU-triggered interruption of Wasm (originally suggested in #1749). It's the first little PR broken off the large #12990 for ease of review.
This PR introduces a Cranelift instruction that facilitates resumeable preemptions: in this case, with MMU-based Wasm interruption in mind. However, the same technique is used by HotSpot for stop-the-world GC, so there is potential for other applications.
The original name for this instruction was
dead_load_with_context. At the time, that was sufficiently descriptive. However, since then, we've added…
- Reserving a second register as scratch space for trampolining
- Returning a new ptr to load from next time
Thus, it's become specialized enough to the task of implementing virtual-memory-triggered interruption mechanisms that it makes sense to rename it with that in mind. Other names I considered include "preempt_poll" (but it ultimately functions cooperatively, so nah), "yield_poll" (too tightly coupled to the one use case I'm chasing right now), and "probe" instead of "poll". HotSpot uses "poll" for their mechanism, so that'll be familiar to some, and it usefully suggests that it will have to be done repeatedly in the usual case.
I recommend reviewing this commit-by-commit.
erikrose has marked PR #14579 as ready for review.
erikrose requested alexcrichton for a review on PR #14579.
erikrose requested wasmtime-compiler-reviewers for a review on PR #14579.
erikrose requested wasmtime-wasi-reviewers for a review on PR #14579.
erikrose requested wasmtime-core-reviewers for a review on PR #14579.
fitzgen requested cfallin for a review on PR #14579.
erikrose updated PR #14579.
erikrose edited PR #14579:
This is the first step toward implementing MMU-triggered interruption of Wasm (originally suggested in #1749). It's the first little PR broken off the large #12990 for ease of review.
This PR introduces a Cranelift instruction that facilitates resumeable preemptions: in this case, with MMU-based Wasm interruption in mind. However, the same technique is used by HotSpot for stop-the-world GC, so there is potential for other applications. A good place to start is this description.
The original name for this instruction was
dead_load_with_context. At the time, that was sufficiently descriptive. However, since then, we've added…
- Reserving a second register as scratch space for trampolining
- Returning a new ptr to load from next time
Thus, it's become specialized enough to the task of implementing virtual-memory-triggered interruption mechanisms that it makes sense to rename it with that in mind. Other names I considered include "preempt_poll" (but it ultimately functions cooperatively, so nah), "yield_poll" (too tightly coupled to the one use case I'm chasing right now), and "probe" instead of "poll". HotSpot uses "poll" for their mechanism, so that'll be familiar to some, and it usefully suggests that it will have to be done repeatedly in the usual case.
I recommend reviewing this commit-by-commit.
:memo: cfallin submitted PR review:
Thanks -- a bunch of comments on how this is documented/described below (but that's the main task here, to define a clean semantics for the IR operator). Overall shape seems fine.
:speech_balloon: cfallin created PR review comment:
"All current backends (x64 and aarch64)" seems wrong here, since Cranelift has more backends than that.
Also I don't think we want to specify details of the register allocation here, unless we want that to become part of the instruction definition/contract.
Finally this description should say more about
next_load_ptr's semantics. When resuming, is that pointer then loaded instead? Or is it just the output (defined value) of this instruction, to be used however the user of this instruction wants?In other words: let's think carefully about defining this as an instruction with well-defined semantics, rather than describing the whole machinery (instruction and its "canonical use") in this one comment.
It might help to define this with pseudocode. Is something like this correct?:
ABI-defined context reg := context <discard> := memory[load_ptr] result := ABI-defined next-load-ptr reg
:speech_balloon: cfallin created PR review comment:
Don't say
task_switch_trampolinehere -- Cranelift should not know or care about (or depend on) the particular way that Wasmtime uses this instruction.
:speech_balloon: cfallin created PR review comment:
I'm not sure I understand this comment -- what do you mean by "conceptually flow in the other direction"?
:speech_balloon: cfallin created PR review comment:
Let's fix the indentation here.
:speech_balloon: cfallin created PR review comment:
Another thought: to clarify the interface between the different moving parts and decouple the instruction from the use-case, it might help to rename the ABI regs. Maybe "context input" and "context output" (for
contextandnext_load_ptrrespectively)?
:speech_balloon: cfallin created PR review comment:
Finally: what do the semantics say about
next_load_ptrif the load doesn't trap? Is the value justload_ptr?So then is it something like this?
ABI-defined context reg := context ABI-defined next-load-ptr reg := load_ptr <discard> := memory[load_ptr] result := ABI-defined next-load-ptr reg
:speech_balloon: cfallin created PR review comment:
Similar comment here as in the aarch64 case.
:speech_balloon: cfallin created PR review comment:
This test only tests the IR verifier; let's add compile tests for x64 and aarch64 to lock down the lowerings (so we see if they change/break later) as well.
:speech_balloon: cfallin created PR review comment:
Not just "for efficiency" but necessary for the instruction semantics to be coherent, right? Otherwise nothing would write the "result" (defined SSA value) of the instruction in the non-trapping case.
:memo: erikrose submitted PR review.
:speech_balloon: erikrose created PR review comment:
It's an implementation note, attempting to get across that, if the embedder doesn't write anything to x10,
next_load_ptrwill be identical do it by dint of register pinning.
erikrose updated PR #14579.
:memo: erikrose submitted PR review.
:speech_balloon: erikrose created PR review comment:
"All current backends (x64 and aarch64)" seems wrong here, since Cranelift has more backends than that.
I probably should have said "All current implementations [of this instruction]".
Also I don't think we want to specify details of the register allocation here, unless we want that to become part of the instruction definition/contract.
It's true that we shouldn't name specific registers here in the
meta, but the specific registers per ISA are definitely part of the contract; else interrupt handlers wouldn't be able to communicate viacontext, change the default return value innext_load_ptr, or know which register they could tromp on as scratch space. This is why I added the requirement of theTailcalling convention, as you suggested earlier.So then is it something like this?
Yes, that last block captures it nicely. By your saying
result :=the reg and notload_ptritself, it leaves room for an interrupt handler to scribble on the reg and thus the result.I've revised my comment to incorporate this concise pseudocode while also preserving the bits about a scratch register and trap table provisions. Let me know what you think.
it might help to rename the ABI regs. Maybe "context input" and "context output" (for context and next_load_ptr respectively)?
Unless you feel very strongly about it, I think "next_load_ptr", in its relationship to "load_ptr", is a useful signal to callers. Both current implementations of the instruction take care to put the result in the same reg as
load_ptr, facilitating an efficient polling loop (saving a move) even if the ptr changes sometimes. The current naming leads an attentive reader down that path. (Or at least I intend it to! Maybe it needs more verbiage. As a reader, what do you think?) Of course, callers are always free to use things in unanticipated ways. I've always tried to avoid terms like context, tool, resource, info, data, etc. unless there's really no semantic to reach for.
:speech_balloon: erikrose edited PR review comment.
:memo: erikrose submitted PR review.
:speech_balloon: erikrose created PR review comment:
Whoops; forgot to update Saúl's code when I exorcised that from mine!
:memo: erikrose submitted PR review.
:speech_balloon: erikrose created PR review comment:
It's both: if it weren't done with a shared pinning (for efficiency), the other choice would have been for the instruction to stick the result in a dynamically chosen writable GPR and then emit a move to x10.
erikrose updated PR #14579.
:memo: erikrose submitted PR review.
:speech_balloon: erikrose created PR review comment:
Good call. (On the One Big PR, I had disas tests that locked them down, but that was on the wasm side of the fence.) Added filetests in af24bbc894. This also surfaced a weird arg ordering in the pretty printer that differed from the CLIF order. Fixed that, and added labels for the args while I was at it.
:thumbs_up: cfallin submitted PR review:
OK, I think this is good to go with the following changes to comments addressed. Thanks for your patience!
:speech_balloon: cfallin created PR review comment:
(And same followup as above: "in the other direction" is extremely unclear and needs to be reworked somehow.
:speech_balloon: cfallin created PR review comment:
OK, I still don't get the "flow in the other direction" though. That to me reads like outputs are being copied to inputs, or something like that. (To be clear, my quibble with all of this is unclear/ambiguous writing -- I understand what's going on, but I want to make sure we describe it clearly.)
Why not say "
next_load_ptrtakes on the value ofload_ptrunless a signal handler invoked at the load overwrites it. We constrainnext_load_ptrto the same register so this dataflow happens without a move."?
:speech_balloon: cfallin created PR review comment:
s/semantic/semantics/
(In CS/PL lingo at least, we always say "the semantics", which is a mass/uncountable noun, like "the physics" or "the mathematics", and often/usually behaves as a singular -- "the semantics of this operator is ...")
:memo: cfallin submitted PR review.
:speech_balloon: cfallin created PR review comment:
OK, this is fine-ish, I think. It still feels a little prescriptive to me ("this is the one way this instruction must be used" rather than just providing a building block) but it documents everything that needs documenting, I think.
erikrose updated PR #14579.
cfallin commented on PR #14579:
Thanks for the followup commit -- I see it addressed the aarch64 instance of "in the other direction" but not the x64 one. Happy to merge once that's fixed too!
erikrose updated PR #14579.
erikrose commented on PR #14579:
Oof, I must have tripped over an unsaved buffer. Fixed in 7a6de! Feel free to squash away the thrashing on landing. Thanks again for your patient review!
cfallin has enabled auto merge for PR #14579.
cfallin added PR #14579 Add interrupt_poll Cranelift instruction. to the merge queue
github-merge-queue[bot] removed PR #14579 Add interrupt_poll Cranelift instruction. from the merge queue
erikrose updated PR #14579.
cfallin has enabled auto merge for PR #14579.
cfallin added PR #14579 Add interrupt_poll Cranelift instruction. to the merge queue
:check: cfallin merged PR #14579.
cfallin removed PR #14579 Add interrupt_poll Cranelift instruction. from the merge queue
Last updated: Oct 31 2026 at 23:03 UTC