diff --git a/cranelift/codegen/meta/src/cdsl/instructions.rs b/cranelift/codegen/meta/src/cdsl/instructions.rs index e57f20786819..22fb8a1b351a 100644 --- a/cranelift/codegen/meta/src/cdsl/instructions.rs +++ b/cranelift/codegen/meta/src/cdsl/instructions.rs @@ -131,7 +131,7 @@ pub(crate) struct InstructionBuilder { operands_in: Option>, operands_out: Option>, - // See Instruction comments for the meaning of these fields. + // See InstructionContent comments for the meaning of these fields. is_terminator: bool, is_branch: bool, is_call: bool, diff --git a/cranelift/codegen/meta/src/shared/instructions.rs b/cranelift/codegen/meta/src/shared/instructions.rs index 476a9375282e..40a3e69998e8 100644 --- a/cranelift/codegen/meta/src/shared/instructions.rs +++ b/cranelift/codegen/meta/src/shared/instructions.rs @@ -370,6 +370,73 @@ fn define_control_flow( .call() .branches(), ); + + ig.push( + Inst::new( + "interrupt_poll", + r#" + Load from a memory location to possibly trigger a resumeable + interruption. + + - Load a pointer-sized value from memory at `load_ptr`, and throw it + away. + - Keep `context` in a fixed register. + - Reserve a second register as scratch space. (Exact choices of + registers are ISA-specific; see each backend's `get_operands` for + which registers and the reasoning behind them.) + - Record the address of the load instruction in the binary's trap table. + + This instruction aids in implementing virtual-memory-triggered + interrupts, with the load trapping if the loaded location is + inaccessible. The trap handler can then take further action, first using + the trap table to confirm that this instruction was the cause. The + handler receives further arbitrary input in `context`. It can use the + second reserved register as scratch space: for example, to record the + original resumption address so it can arrange to "return to" a + trampoline first, which can ultimately then jump to the original + address. (Such gymnastics are necessary on platforms where signal + handlers cannot push stack frames directly.) It is expected that + execution will ultimately resume at the load, re-running it; care must + be taken to ensure it succeeds the second time, lest the whole process + repeat. This is where the output `next_load_ptr` comes in, carrying a + new location to load from. All current backends (x64 and aarch64) pin + `load_ptr` and `next_load_ptr` to the same register so a move from the + latter to the former does not even need to be emitted. + "#, + &formats.int_add_trap, + ) + .operands_in(&[ + Operand::new("load_ptr", iAddr).with_doc("memory location to load from"), + Operand::new("context", iAddr) + .with_doc("arbitrary address-sized context to pass to signal handler"), + Operand::new("code", &imm.trapcode) + .with_doc("trap code to record at the load's address"), + ]) + .operands_out(&[ + Operand::new("next_load_ptr", iAddr).with_doc("memory location to load from next time") + ]) + // As with `stack_switch`, this instruction is a call, in that "it + // continues execution elsewhere". See reasoning at + // https://github.com/bytecodealliance/wasmtime/pull/9078#issuecomment-2273869774. + .call() + .can_load() + // It may transfer control to something that may store. Declaring this + // makes us a memory fence. + .can_store() + // The universe of possible side effects is wide open. Control may never + // even return to this point. When this instruction is used to trigger + // preemption, we certainly do not want it hoisted or deduplicated via + // GVN. + .other_side_effects(), + // If `load` is not `can_trap()`, this isn't either. + // + // This cannot use `side_effects_idempotent()`: its purpose is to allow + // deduplication or LICM of redundant instructions. The decision made by + // `interrupt_poll` (implicitly, via trap) is determined by the flags on + // the page of memory loaded, which change at runtime, outside the + // purview of the compiler. Thus, the tuple formed by the instruction + // and its input operands is not sufficient to decide redundancy. + ); } #[inline(never)] diff --git a/cranelift/codegen/src/ir/instructions.rs b/cranelift/codegen/src/ir/instructions.rs index 408d4fbed6c1..81acba9e961e 100644 --- a/cranelift/codegen/src/ir/instructions.rs +++ b/cranelift/codegen/src/ir/instructions.rs @@ -643,9 +643,13 @@ impl InstructionData { Self::Ternary { opcode: Opcode::StackSwitch, .. + } + | Self::IntAddTrap { + opcode: Opcode::InterruptPoll, + .. } => { - // `StackSwitch` is not actually a call, but has the .call() side - // effect as it continues execution elsewhere. + // These instructions aren't actually calls, but they have the + // .call() side effect, as they continue execution elsewhere. CallInfo::NotACall } _ => { diff --git a/cranelift/codegen/src/isa/aarch64/inst.isle b/cranelift/codegen/src/isa/aarch64/inst.isle index ea1e985d981e..647597f6941c 100644 --- a/cranelift/codegen/src/isa/aarch64/inst.isle +++ b/cranelift/codegen/src/isa/aarch64/inst.isle @@ -1038,7 +1038,15 @@ ;; means that the internal codegen can't use these registers. (StackProbeLoop (start WritableReg) (end Reg) - (step Imm12)))) + (step Imm12)) + + ;; A load whose result is discarded; `context` is pinned to x0, `dst` + ;; to x9, and `next_load_ptr` to x10. + (InterruptPoll (dst WritableReg) + (load_ptr Reg) + (context Reg) + (trap_code TrapCode) + (next_load_ptr WritableReg)))) (spec (MInst.AluRRImmLogic alu_op size rd rn imml) (provide @@ -5849,6 +5857,7 @@ (attr f16const (tag TODO)) (attr fcvt_to_uint_sat (tag TODO)) (attr get_return_address (tag TODO)) +(attr interrupt_poll (tag TODO)) (attr lower_bmask (tag TODO)) (attr nop (tag TODO)) (attr invalid_reg (tag TODO)) diff --git a/cranelift/codegen/src/isa/aarch64/inst/emit.rs b/cranelift/codegen/src/isa/aarch64/inst/emit.rs index 66d6cd1fe0a7..b30c32c13fe5 100644 --- a/cranelift/codegen/src/isa/aarch64/inst/emit.rs +++ b/cranelift/codegen/src/isa/aarch64/inst/emit.rs @@ -3708,6 +3708,31 @@ impl MachInstEmit for Inst { .emit(sink, emit_info, state); sink.bind_label(loop_end, &mut state.ctrl_plane); } + + &Inst::InterruptPoll { + dst, + load_ptr, + trap_code, + .. + } => { + // Record the address of the load in the trap table so a signal + // handler can later distinguish whether a segfault is its + // fault. + sink.add_trap(trap_code); + + // Emit `ldr dst, [load_ptr]`. Reuse the `dst` address as the + // destination of the dead load, since we are clobbering it + // anyway. + Inst::ULoad64 { + rd: dst, + mem: AMode::UnsignedOffset { + rn: load_ptr, + uimm12: UImm12Scaled::zero(I64), + }, + flags: MemFlagsData::trusted(), + } + .emit(sink, emit_info, state); + } } let end_off = sink.cur_offset(); diff --git a/cranelift/codegen/src/isa/aarch64/inst/mod.rs b/cranelift/codegen/src/isa/aarch64/inst/mod.rs index 230cc2abb410..5b81f6b6c5c7 100644 --- a/cranelift/codegen/src/isa/aarch64/inst/mod.rs +++ b/cranelift/codegen/src/isa/aarch64/inst/mod.rs @@ -968,6 +968,37 @@ fn aarch64_get_operands(inst: &mut Inst, collector: &mut impl OperandVisitor) { collector.reg_early_def(start); collector.reg_use(end); } + Inst::InterruptPoll { + dst, + load_ptr, + context, + trap_code: _, + next_load_ptr, + } => { + // `load_ptr` is an input param. It is pinned to x10 so an update of + // `next_load_ptr` updates this as well. x10 is chosen because it is + // a caller-saved scratch reg with no special role. + collector.reg_fixed_use(load_ptr, regs::xreg(10)); + // Demand `context` (the vmctx) go into x0, where the signal + // handler can find it and hand it straight to + // `task_switch_trampoline` as its first argument. + collector.reg_fixed_use(context, regs::xreg(0)); + // Reserve x9 as a place for the signal handler to put the address + // at which to resume once the task switch is done. x9 is caller + // saved and has no special role. + // + // Define it, so we can use it as the destination of the dead + // load rather than consuming another arbitrary reg. + collector.reg_fixed_def(dst, regs::xreg(9)); + // `next_load_ptr` is pinned so embedders know where to write to + // fill it. It shares x10 with `load_ptr`, above, so filling this + // output means also filling in the (potential) next input, for + // efficiency. This also means that leaving x10 alone (in the + // common, non-trapping case), makes info conceptually flow in the + // other direction, piping the old but unchanging `load_ptr` through + // to the output. + collector.reg_fixed_def(next_load_ptr, regs::xreg(10)); + } } } @@ -3014,6 +3045,21 @@ impl Inst { let step = step.pretty_print(0); format!("stack_probe_loop {start}, {end}, {step}") } + &Inst::InterruptPoll { + dst, + load_ptr, + context, + trap_code, + next_load_ptr, + } => { + let dst = pretty_print_reg(dst.to_reg()); + let load_ptr = pretty_print_reg(load_ptr); + let context = pretty_print_reg(context); + let next_load_ptr = pretty_print_reg(next_load_ptr.to_reg()); + format!( + "{next_load_ptr} = interrupt_poll {dst}, {load_ptr}, {context} #trap={trap_code}" + ) + } } } } diff --git a/cranelift/codegen/src/isa/aarch64/lower.isle b/cranelift/codegen/src/isa/aarch64/lower.isle index de5a653354da..109ae02d5e0e 100644 --- a/cranelift/codegen/src/isa/aarch64/lower.isle +++ b/cranelift/codegen/src/isa/aarch64/lower.isle @@ -2560,6 +2560,20 @@ (rule (lower (symbol_value _ (symbol_value_data extname dist offset))) (load_ext_name (box_external_name extname) offset dist)) +;;;; Rules for `interrupt_poll` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (interrupt_poll _ load_ptr context trap_code)) + (let ((load_ptr Reg (put_in_reg load_ptr)) + (context Reg (put_in_reg context)) + (dst WritableReg (temp_writable_reg $I64)) + (next_load_ptr WritableReg (temp_writable_reg $I64)) + (_ Unit (emit (MInst.InterruptPoll dst + load_ptr + context + trap_code + next_load_ptr)))) + (output_reg next_load_ptr))) + ;;; Rules for `get_{frame,stack}_pointer` and `get_return_address` ;;;;;;;;;;;;; (rule (lower (get_frame_pointer _)) diff --git a/cranelift/codegen/src/isa/call_conv.rs b/cranelift/codegen/src/isa/call_conv.rs index 6b9e5538132e..0081afe86b0f 100644 --- a/cranelift/codegen/src/isa/call_conv.rs +++ b/cranelift/codegen/src/isa/call_conv.rs @@ -14,16 +14,21 @@ use serde_derive::{Deserialize, Serialize}; pub enum CallConv { /// Best performance, not ABI-stable. Fast, - /// Supports tail calls, not ABI-stable except for exception - /// payload registers. + /// Supports tail calls, not ABI-stable except as stated here. /// - /// On exception resume, a caller to a `tail`-convention function - /// assumes that the exception payload values are in the following - /// registers (per platform): + /// On exception resume, a caller to a `tail`-convention function assumes + /// that the exception payload values are in the following registers (per + /// platform): /// - x86-64: rax, rdx /// - aarch64: x0, x1 /// - riscv64: a0, a1 /// - pulley{32,64}: x0, x1 + /// + /// The `interrupt_call` instruction uses registers as follows: + /// - x86-64: context in rdi, load ptr and return value in r11, scratch in + /// r10 + /// - aarch64: context in x0, load ptr and return value in x10, scratch in + /// x9 // // Currently, this is basically sys-v except that callees pop stack // arguments, rather than callers. Expected to change even more in the diff --git a/cranelift/codegen/src/isa/x64/inst.isle b/cranelift/codegen/src/isa/x64/inst.isle index 6c1e9d1d7c2e..fa41bdca6e4f 100644 --- a/cranelift/codegen/src/isa/x64/inst.isle +++ b/cranelift/codegen/src/isa/x64/inst.isle @@ -52,7 +52,7 @@ ;; ========================================= ;; Stack manipulation. - ;; Emits a inline stack probe loop. + ;; Emits an inline stack probe loop. (StackProbeLoop (tmp WritableReg) (frame_size u32) (guard_size u32)) @@ -194,6 +194,14 @@ (offset i64) (distance RelocDistance)) + ;; A load whose result is discarded; `context` is pinned to rdi, `dst` + ;; to r10, and `load_ptr`/`next_load_ptr` share r11. + (InterruptPoll (dst WritableGpr) + (load_ptr Gpr) + (context Gpr) + (trap_code TrapCode) + (next_load_ptr WritableGpr)) + ;; ========================================= ;; Instructions pertaining to atomic memory accesses. diff --git a/cranelift/codegen/src/isa/x64/inst/emit.rs b/cranelift/codegen/src/isa/x64/inst/emit.rs index fb8cba43e086..042b022bc688 100644 --- a/cranelift/codegen/src/isa/x64/inst/emit.rs +++ b/cranelift/codegen/src/isa/x64/inst/emit.rs @@ -650,6 +650,23 @@ pub(crate) fn emit( } } + Inst::InterruptPoll { + dst, + load_ptr, + trap_code, + .. + } => { + // Record the address of load in the trap table so a signal handler + // can later distinguish whether a segfault is its fault. + sink.add_trap(*trap_code); + + let load_ptr_addr = SyntheticAmode::real(Amode::imm_reg(0, **load_ptr)); + // Since we're clobbering dst anyway to store the resume address, + // also use it as a destination for the dead load rather than + // sucking up another reg: + asm::inst::movq_rm::new(*dst, load_ptr_addr).emit(sink, info, state); + } + Inst::JmpKnown { dst } => uncond_jmp(sink, *dst), Inst::WinchJmpIf { cc, taken } => one_way_jmp(sink, *cc, *taken), diff --git a/cranelift/codegen/src/isa/x64/inst/mod.rs b/cranelift/codegen/src/isa/x64/inst/mod.rs index e758ee087cf0..5cbf00044784 100644 --- a/cranelift/codegen/src/isa/x64/inst/mod.rs +++ b/cranelift/codegen/src/isa/x64/inst/mod.rs @@ -96,6 +96,7 @@ impl Inst { | Inst::Args { .. } | Inst::Rets { .. } | Inst::StackSwitchBasic { .. } + | Inst::InterruptPoll { .. } | Inst::TrapIf { .. } | Inst::TrapIfAnd { .. } | Inst::TrapIfOr { .. } @@ -671,6 +672,22 @@ impl PrettyPrint for Inst { ) } + Inst::InterruptPoll { + dst, + load_ptr, + context, + trap_code, + next_load_ptr, + } => { + let dst = pretty_print_reg(*dst.to_reg(), 8); + let load_ptr = pretty_print_reg(**load_ptr, 8); + let context = pretty_print_reg(**context, 8); + let next_load_ptr = pretty_print_reg(*next_load_ptr.to_reg(), 8); + format!( + "{next_load_ptr} = interrupt_poll {dst}, {load_ptr}, {context} #trap={trap_code}" + ) + } + Inst::JmpKnown { dst } => { let op = ljustify("jmp".to_string()); let dst = dst.to_string(); @@ -1051,6 +1068,47 @@ fn x64_get_operands(inst: &mut Inst, collector: &mut impl OperandVisitor) { collector.reg_clobbers(clobbers); } + Inst::InterruptPoll { + dst, + load_ptr, + context, + trap_code: _, + next_load_ptr, + } => { + // `load_ptr` is an input param. It is pinned to r11 so an update of + // `next_load_ptr` updates this as well. r11 is chosen because it is + // a caller-saved reg not used for arg-passing in Linux/x64. + collector.reg_fixed_use(load_ptr, regs::r11()); + // Demand context (vmctx) go into RDI. + collector.reg_fixed_use(context, regs::rdi()); + // Reserve r10 as a place for a signal handler to stow the original + // resume address. This allows the handler to twiddle saved machine + // state to return to a custom trampoline when it exits, allowing it + // to accomplish things that are unsafe at interrupt time. The + // trampoline can jump to the address in r10 when done to resume. + // + // r10 is chosen because it is caller-saved and not used for + // arg passing in Linux/x64. It is used as "a static chain pointer + // in case of nested functions" according to SystemV, but Cranelift + // does not emit those. (Do take care if you are interacting with + // external ones.) It is also used to store the function stack limit + // in Cranelift, but the stack-limit check is confined to the + // function prologue and thus over by the time this instruction is + // used. + // + // Also def it so we can use it as the destination of the dead load + // rather than consuming another arbitrary reg. + collector.reg_fixed_def(dst, regs::r10()); + // `next_load_ptr` is pinned so embedders know where to write to + // fill it. It shares r11 with `load_ptr`, above, so filling this + // output means also filling in the (potential) next input, for + // efficiency. This also means that leaving r11 alone (in the + // common, non-trapping case), makes info conceptually flow in the + // other direction, piping the old but unchanging `load_ptr` through + // to the output. + collector.reg_fixed_def(next_load_ptr, regs::r11()); + } + Inst::ReturnCallKnown { info } => { let ReturnCallInfo { dest, uses, tmp, .. diff --git a/cranelift/codegen/src/isa/x64/lower.isle b/cranelift/codegen/src/isa/x64/lower.isle index 09adefd5aeb9..dd6d3594aec1 100644 --- a/cranelift/codegen/src/isa/x64/lower.isle +++ b/cranelift/codegen/src/isa/x64/lower.isle @@ -3620,6 +3620,20 @@ (in_payload0 Gpr (put_in_gpr in_payload0))) (x64_stack_switch_basic store_context_ptr load_context_ptr in_payload0))) +;;;; Rules for `interrupt_poll` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (interrupt_poll _ load_ptr context trap_code)) + (let ((load_ptr Gpr (put_in_gpr load_ptr)) + (context Gpr (put_in_gpr context)) + (dst WritableGpr (temp_writable_gpr)) + (next_load_ptr WritableGpr (temp_writable_gpr)) + (_ Unit (emit (MInst.InterruptPoll dst + load_ptr + context + trap_code + next_load_ptr)))) + (output_gpr next_load_ptr))) + ;;;; Rules for `get_{frame,stack}_pointer` and `get_return_address` ;;;;;;;;;;;; (rule (lower (get_frame_pointer _)) diff --git a/cranelift/codegen/src/machinst/buffer.rs b/cranelift/codegen/src/machinst/buffer.rs index c86a19b64438..f76c9761fc29 100644 --- a/cranelift/codegen/src/machinst/buffer.rs +++ b/cranelift/codegen/src/machinst/buffer.rs @@ -1802,7 +1802,7 @@ impl MachBuffer { }); } - /// Add a patchable call record at the current offset The actual + /// Add a patchable call record at the current offset. The actual /// call is expected to have been emitted; the VCodeInst trait /// specifies how to NOP it out, and we carry that information to /// the finalized Machbuffer. diff --git a/cranelift/codegen/src/verifier/mod.rs b/cranelift/codegen/src/verifier/mod.rs index 51485478e8b1..71baaf39c424 100644 --- a/cranelift/codegen/src/verifier/mod.rs +++ b/cranelift/codegen/src/verifier/mod.rs @@ -727,6 +727,19 @@ impl<'a> Verifier<'a> { self.verify_try_call_handler_index(inst, block, imm.into(), errors)?; } + IntAddTrap { + opcode: Opcode::InterruptPoll, + .. + } => { + if self.func.signature.call_conv != CallConv::Tail { + return errors.fatal(( + inst, + self.context(inst), + "`interrupt_poll` requires the `tail` calling convention", + )); + } + } + // Exhaustive list so we can't forget to add new formats AtomicCas { .. } | AtomicRmw { .. } diff --git a/cranelift/docs/ir.md b/cranelift/docs/ir.md index d5e56355f2b9..b86edcacefac 100644 --- a/cranelift/docs/ir.md +++ b/cranelift/docs/ir.md @@ -643,7 +643,7 @@ slot on the stack for its entire live range. Since the live range of an SSA value can be quite large, it is sometimes beneficial to split the live range into smaller parts. -A live range is split by creating new SSA values that are copies or the +A live range is split by creating new SSA values that are copies of the original value or each other. The copies are created by inserting `copy`, `spill`, or `fill` instructions, depending on whether the values are assigned to registers or stack slots. diff --git a/cranelift/filetests/filetests/verifier/interrupt-poll.clif b/cranelift/filetests/filetests/verifier/interrupt-poll.clif new file mode 100644 index 000000000000..406d5c03d7e5 --- /dev/null +++ b/cranelift/filetests/filetests/verifier/interrupt-poll.clif @@ -0,0 +1,13 @@ +test verifier + +function %tail(i64, i64) -> i64 tail { +block0(v0: i64, v1: i64): + v2 = interrupt_poll v0, v1, user3 + return v2 +} + +function %system_v(i64, i64) -> i64 system_v { +block0(v0: i64, v1: i64): + v2 = interrupt_poll v0, v1, user3 ; error: `interrupt_poll` requires the `tail` calling convention + return v2 +} diff --git a/cranelift/interpreter/src/step.rs b/cranelift/interpreter/src/step.rs index 9c57a92117b7..cad9149b32ed 100644 --- a/cranelift/interpreter/src/step.rs +++ b/cranelift/interpreter/src/step.rs @@ -1312,6 +1312,7 @@ where Opcode::X86Pmaddubsw => unimplemented!("X86Pmaddubsw"), Opcode::X86Cvtt2dq => unimplemented!("X86Cvtt2dq"), Opcode::StackSwitch => unimplemented!("StackSwitch"), + Opcode::InterruptPoll => unimplemented!("InterruptPoll"), Opcode::TryCall => unimplemented!("TryCall"), Opcode::TryCallIndirect => unimplemented!("TryCallIndirect"), diff --git a/crates/environ/src/compile/frame_table.rs b/crates/environ/src/compile/frame_table.rs index f3288f08f121..b2c47f87ee3f 100644 --- a/crates/environ/src/compile/frame_table.rs +++ b/crates/environ/src/compile/frame_table.rs @@ -330,7 +330,7 @@ impl FrameTableBuilder { .push(U32::new(LittleEndian, end)); } - /// Serialize the framd-table data section, taking a closure to + /// Serialize the frame-table data section, taking a closure to /// consume slices. pub fn serialize(&mut self, mut f: F) { // Pad `frame_descriptor_data` to a multiple of 4 bytes so diff --git a/crates/wasi-preview1-component-adapter/src/lib.rs b/crates/wasi-preview1-component-adapter/src/lib.rs index e070206d4f11..8b83b9c31a73 100644 --- a/crates/wasi-preview1-component-adapter/src/lib.rs +++ b/crates/wasi-preview1-component-adapter/src/lib.rs @@ -457,7 +457,7 @@ impl ImportAlloc { #[derive(Clone)] struct BumpAlloc { base: *mut u8, - len: usize, + len: usize, // remaining size available for allocation } impl BumpAlloc { diff --git a/crates/wasmtime/Cargo.toml b/crates/wasmtime/Cargo.toml index d1636ec04d11..5639b55088c7 100644 --- a/crates/wasmtime/Cargo.toml +++ b/crates/wasmtime/Cargo.toml @@ -372,7 +372,7 @@ wit-parser = ["dep:wit-parser", "component-model", "std"] # For platforms that Wasmtime does not have support for Wasmtime will disable # the use of virtual memory by default, for example allocating linear memories # with `malloc` instead. This feature can be used, for these platforms, to -# instead use a C API defined in `wasmtime-platform.h` instead. +# instead use a C API defined in `wasmtime-platform.h`. # # For some more information see # https://docs.wasmtime.dev/stability-platform-support.html#support-for-no_std diff --git a/crates/wasmtime/src/runtime/component/linker.rs b/crates/wasmtime/src/runtime/component/linker.rs index 77ef8612fe20..89cf2fd7f15a 100644 --- a/crates/wasmtime/src/runtime/component/linker.rs +++ b/crates/wasmtime/src/runtime/component/linker.rs @@ -172,7 +172,7 @@ impl Linker { imported_resources: try_new::>(TryPrimaryMap::new())?, }; - // Walk over the component's list of import names and use that to lookup + // Walk over the component's list of import names and use that to look up // the definition within this linker that it corresponds to. When found // perform a typecheck against the component's expected type. let env_component = component.env_component(); diff --git a/crates/wasmtime/src/runtime/fiber.rs b/crates/wasmtime/src/runtime/fiber.rs index 89c5d49b8258..727eebb2f8f1 100644 --- a/crates/wasmtime/src/runtime/fiber.rs +++ b/crates/wasmtime/src/runtime/fiber.rs @@ -418,7 +418,7 @@ pub(crate) struct StoreFiber<'a> { /// Note that using `StoreFiberYield` as the `Yield` type parameter allows /// the fiber to indicate whether it needs exclusive access to the store /// across suspend points (in which case it will pass `KeepStore` when - /// suspending , meaning the store must not be used at all until the fiber + /// suspending, meaning the store must not be used at all until the fiber /// is resumed again) or whether it is giving up exclusive access (in which /// case it will pass `ReleaseStore` when yielding, meaning exclusive access /// may be given to another fiber that runs concurrently. diff --git a/crates/wasmtime/src/runtime/vm/sys/unix/signals.rs b/crates/wasmtime/src/runtime/vm/sys/unix/signals.rs index 4f80189a915a..19bb3f66d95f 100644 --- a/crates/wasmtime/src/runtime/vm/sys/unix/signals.rs +++ b/crates/wasmtime/src/runtime/vm/sys/unix/signals.rs @@ -343,7 +343,7 @@ unsafe fn get_trap_registers(cx: *mut libc::c_void, _signum: libc::c_int) -> Tra } } -/// Updates the siginfo context stored in `cx` to resume to `handler` up on +/// Updates the siginfo context stored in `cx` to resume to `handler` upon /// resumption while returning from the signal handler. unsafe fn store_handler_in_ucontext(cx: *mut libc::c_void, handler: &Handler) { cfg_select! { diff --git a/crates/wasmtime/src/runtime/vm/traphandlers/backtrace.rs b/crates/wasmtime/src/runtime/vm/traphandlers/backtrace.rs index ce154cfed0af..8617159b9fbd 100644 --- a/crates/wasmtime/src/runtime/vm/traphandlers/backtrace.rs +++ b/crates/wasmtime/src/runtime/vm/traphandlers/backtrace.rs @@ -185,7 +185,7 @@ impl Backtrace { /// Walk the current Wasm stack, calling `f` for each frame we walk. /// - /// If Wasm hit a trap, and we calling this from the trap handler, then the + /// If Wasm hit a trap and we are calling this from the trap handler, then the /// Wasm exit trampoline didn't run, and we use the provided PC and FP /// instead of looking them up in `VMStoreContext`. ///