Skip to content

Commit 6778b4f

Browse files
authored
Update comment on stack overflow checking (#4290)
* Update comment on stack overflow checking This commit moves the top-level comment in `crates/cranelift/src/lib.rs` into the location where the global value for the stack limit is generated. Stack overflow checking is pretty localized nowadays so there's not much need to have it at the top of the crate and most of the words there were just adapted to this new location. Closes #4286 * Review comments
1 parent b48b10b commit 6778b4f

File tree

2 files changed

+30
-52
lines changed

2 files changed

+30
-52
lines changed

crates/cranelift/src/compiler.rs

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -152,19 +152,38 @@ impl wasmtime_environ::Compiler for Compiler {
152152

153153
let mut func_env = FuncEnvironment::new(isa, translation, types, tunables);
154154

155-
// We use these as constant offsets below in
156-
// `stack_limit_from_arguments`, so assert their values here. This
157-
// allows the closure below to get coerced to a function pointer, as
158-
// needed by `ir::Function`.
155+
// The `stack_limit` global value below is the implementation of stack
156+
// overflow checks in Wasmtime.
159157
//
160-
// Otherwise our stack limit is specially calculated from the vmctx
161-
// argument, where we need to load the `*const VMRuntimeLimits`
162-
// pointer, and then from that pointer we need to load the stack
163-
// limit itself. Note that manual register allocation is needed here
164-
// too due to how late in the process this codegen happens.
158+
// The Wasm spec defines that stack overflows will raise a trap, and
159+
// there's also an added constraint where as an embedder you frequently
160+
// are running host-provided code called from wasm. WebAssembly and
161+
// native code currently share the same call stack, so Wasmtime needs to
162+
// make sure that host-provided code will have enough call-stack
163+
// available to it.
165164
//
166-
// For more information about interrupts and stack checks, see the
167-
// top of this file.
165+
// The way that stack overflow is handled here is by adding a prologue
166+
// check to all functions for how much native stack is remaining. The
167+
// `VMContext` pointer is the first argument to all functions, and the
168+
// first field of this structure is `*const VMRuntimeLimits` and the
169+
// first field of that is the stack limit. Note that the stack limit in
170+
// this case means "if the stack pointer goes below this, trap". Each
171+
// function which consumes stack space or isn't a leaf function starts
172+
// off by loading the stack limit, checking it against the stack
173+
// pointer, and optionally traps.
174+
//
175+
// This manual check allows the embedder to give wasm a relatively
176+
// precise amount of stack allocation. Using this scheme we reserve a
177+
// chunk of stack for wasm code relative from where wasm code was
178+
// called. This ensures that native code called by wasm should have
179+
// native stack space to run, and the numbers of stack spaces here
180+
// should all be configurable for various embeddings.
181+
//
182+
// Note that this check is independent of each thread's stack guard page
183+
// here. If the stack guard page is reached that's still considered an
184+
// abort for the whole program since the runtime limits configured by
185+
// the embedder should cause wasm to trap before it reaches that
186+
// (ensuring the host has enough space as well for its functionality).
168187
let vmctx = context
169188
.func
170189
.create_global_value(ir::GlobalValueData::VMContext);

crates/cranelift/src/lib.rs

Lines changed: 0 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -3,47 +3,6 @@
33
//! This crate provides an implementation of the `wasmtime_environ::Compiler`
44
//! and `wasmtime_environ::CompilerBuilder` traits.
55
6-
// # How does Wasmtime prevent stack overflow?
7-
//
8-
// A few locations throughout the codebase link to this file to explain stack
9-
// overflow. To start off, let's take a look at stack overflow. Wasm code is
10-
// well-defined to have stack overflow being recoverable and raising a trap, so
11-
// we need to handle this somehow! There's also an added constraint where as an
12-
// embedder you frequently are running host-provided code called from wasm.
13-
// WebAssembly and native code currently share the same call stack, so you want
14-
// to make sure that your host-provided code will have enough call-stack
15-
// available to it.
16-
//
17-
// Given all that, the way that stack overflow is handled is by adding a
18-
// prologue check to all JIT functions for how much native stack is remaining.
19-
// The `VMContext` pointer is the first argument to all functions, and the first
20-
// field of this structure is `*const VMRuntimeLimits` and the first field of
21-
// that is the stack limit. Note that the stack limit in this case means "if the
22-
// stack pointer goes below this, trap". Each JIT function which consumes stack
23-
// space or isn't a leaf function starts off by loading the stack limit,
24-
// checking it against the stack pointer, and optionally traps.
25-
//
26-
// This manual check allows the embedder (us) to give wasm a relatively precise
27-
// amount of stack allocation. Using this scheme we reserve a chunk of stack
28-
// for wasm code relative from where wasm code was called. This ensures that
29-
// native code called by wasm should have native stack space to run, and the
30-
// numbers of stack spaces here should all be configurable for various
31-
// embeddings.
32-
//
33-
// Note that we do not consider each thread's stack guard page here. It's
34-
// considered that if you hit that you still abort the whole program. This
35-
// shouldn't happen most of the time because wasm is always stack-bound and
36-
// it's up to the embedder to bound its own native stack.
37-
//
38-
// So all-in-all, that's how we implement stack checks. Note that stack checks
39-
// cannot be disabled because it's a feature of core wasm semantics. This means
40-
// that all functions almost always have a stack check prologue, and it's up to
41-
// us to optimize away that cost as much as we can.
42-
//
43-
// For more information about the tricky bits of managing the reserved stack
44-
// size of wasm, see the implementation in `traphandlers.rs` in the
45-
// `update_stack_limit` function.
46-
476
use cranelift_codegen::binemit;
487
use cranelift_codegen::ir;
498
use cranelift_codegen::isa::{unwind::UnwindInfo, CallConv, TargetIsa};

0 commit comments

Comments
 (0)