This function is called to update and save state when WebAssembly is entered within the `Store`. This updates various fields such as: The stack limit. This is what ensures that we limit the stack space allocated by WebAssembly code and it's relative to the initial stack pointer that called into wasm. It also saves the different last_wasm_* values in the `VMStoreContext`.
(
store: &mut StoreContextMut<'_, T>,
initial_stack_information: *mut VMCommonStackInformation,
)
| 1515 | /// |
| 1516 | /// It also saves the different last_wasm_* values in the `VMStoreContext`. |
| 1517 | pub fn enter_wasm<T>( |
| 1518 | store: &mut StoreContextMut<'_, T>, |
| 1519 | initial_stack_information: *mut VMCommonStackInformation, |
| 1520 | ) -> Self { |
| 1521 | let stack_limit; |
| 1522 | |
| 1523 | // If this is a recursive call, e.g. our stack limit is already set, then |
| 1524 | // we may be able to skip this function. |
| 1525 | // |
| 1526 | // For synchronous stores there's nothing else to do because all wasm calls |
| 1527 | // happen synchronously and on the same stack. This means that the previous |
| 1528 | // stack limit will suffice for the next recursive call. |
| 1529 | // |
| 1530 | // For asynchronous stores then each call happens on a separate native |
| 1531 | // stack. This means that the previous stack limit is no longer relevant |
| 1532 | // because we're on a separate stack. |
| 1533 | if unsafe { *store.0.vm_store_context().stack_limit.get() } != usize::MAX |
| 1534 | && !store.0.can_block() |
| 1535 | { |
| 1536 | stack_limit = None; |
| 1537 | } |
| 1538 | // Ignore this stack pointer business on miri since we can't execute wasm |
| 1539 | // anyway and the concept of a stack pointer on miri is a bit nebulous |
| 1540 | // regardless. |
| 1541 | else if cfg!(miri) { |
| 1542 | stack_limit = None; |
| 1543 | } else { |
| 1544 | // When Cranelift has support for the host then we might be running native |
| 1545 | // compiled code meaning we need to read the actual stack pointer. If |
| 1546 | // Cranelift can't be used though then we're guaranteed to be running pulley |
| 1547 | // in which case this stack pointer isn't actually used as Pulley has custom |
| 1548 | // mechanisms for stack overflow. |
| 1549 | #[cfg(has_host_compiler_backend)] |
| 1550 | let stack_pointer = crate::runtime::vm::get_stack_pointer(); |
| 1551 | #[cfg(not(has_host_compiler_backend))] |
| 1552 | let stack_pointer = { |
| 1553 | use wasmtime_environ::TripleExt; |
| 1554 | debug_assert!(store.engine().target().is_pulley()); |
| 1555 | usize::MAX |
| 1556 | }; |
| 1557 | |
| 1558 | // Determine the stack pointer where, after which, any wasm code will |
| 1559 | // immediately trap. This is checked on the entry to all wasm functions. |
| 1560 | // |
| 1561 | // Note that this isn't 100% precise. We are requested to give wasm |
| 1562 | // `max_wasm_stack` bytes, but what we're actually doing is giving wasm |
| 1563 | // probably a little less than `max_wasm_stack` because we're |
| 1564 | // calculating the limit relative to this function's approximate stack |
| 1565 | // pointer. Wasm will be executed on a frame beneath this one (or next |
| 1566 | // to it). In any case it's expected to be at most a few hundred bytes |
| 1567 | // of slop one way or another. When wasm is typically given a MB or so |
| 1568 | // (a million bytes) the slop shouldn't matter too much. |
| 1569 | // |
| 1570 | // After we've got the stack limit then we store it into the `stack_limit` |
| 1571 | // variable. |
| 1572 | // |
| 1573 | // Also note that `saturating_sub` is used here since if the user |
| 1574 | // said that the function gets nigh-infinite stack well then by |
nothing calls this directly
no test coverage detected