Skip to content

Commit 99ecf72

Browse files
authored
Debug: create private code memories per store when debugging is enabled. (#12051)
* Debug: create private code memories per store when debugging is enabled. This will allow patching code to implement e.g. breakpoints. (That is, for now the copies are redundant, but soon they will not be.) This change follows the discussion [here] and offline to define a few types that better encapsulate the distinction we want to enforce. Basically, there is almost never a bare `CodeMemory`; they are always wrapped in an `EngineCode` or `StoreCode`, the latter being a per-store instance of the former. Accessors are moved to the relevant place so that, for example, one cannot get a pointer to a Wasm function's body without being in the context of a `Store` where the containing module has been registered. The registry then returns a `ModuleWithCode` that boxes up a `Module` reference and `StoreCode` together for cases where we need both the metadata from the module and the raw code to derive something. The only case where we return raw code pointers to the `EngineCode` directly have to do with Wasm-to-array trampolines: in some cases, e.g. `InstancePre` pre-creating data structures with references to host functions, it breaks our expected performance characteristics to make the function pointers store-specific. This is fine as long as the Wasm-to-array trampolines never bake in direct calls to Wasm functions; the strong invariant is that Wasm functions never execute from `EngineCode` directly. Some parts of the component runtime would also have to be substantially refactored if we wanted to do away with this exception. The per-`Store` module registry is substantially refactored in this PR. I got rid of the modules-without-code distinction (the case where a module only has trampolines and no defined functions still works fine), and organized the BTreeMaps to key on start address rather than end address, which I find a little more intuitive (one then queries with the dual to the range -- 0-up-to-PC and last entry found). [here]: #12051 (review) * Review feedback: do not assume a reasonable code alignment; error when it cannot be known * Review feedback: fail properly in profiler when we are cloning code * Fix guest-profiler C API. * Review feedback: make private-code representation impossible in non-debugging-support builds. * Add TODO comment referencing issue for cloning only .text. * clang-format * Review feedback: add back Component::image_range. * Review feedback: error on registering profiling metadata when debug is enabled. * rustfmt * Remove early bail on profiling-data registration when debugging is enabled: this always happens so we cannot error out.
1 parent 9bb96d5 commit 99ecf72

File tree

28 files changed

+993
-458
lines changed

28 files changed

+993
-458
lines changed

crates/c-api/include/wasmtime/profiling.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ typedef struct wasmtime_guestprofiler_modules {
5656
/**
5757
* \brief Begin profiling a new guest.
5858
*
59+
* \param engine engine in which to perform the profiling
5960
* \param module_name name recorded in the profile
6061
* \param interval_nanos intended sampling interval in nanoseconds recorded in
6162
* the profile
@@ -71,8 +72,9 @@ typedef struct wasmtime_guestprofiler_modules {
7172
* https://docs.wasmtime.dev/api/wasmtime/struct.GuestProfiler.html#method.new
7273
*/
7374
WASM_API_EXTERN /* own */ wasmtime_guestprofiler_t *wasmtime_guestprofiler_new(
74-
const wasm_name_t *module_name, uint64_t interval_nanos,
75-
const wasmtime_guestprofiler_modules_t *modules, size_t modules_len);
75+
const wasm_engine_t *engine, const wasm_name_t *module_name,
76+
uint64_t interval_nanos, const wasmtime_guestprofiler_modules_t *modules,
77+
size_t modules_len);
7678

7779
/**
7880
* \brief Add a sample to the profile.

crates/c-api/src/profiling.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
use crate::{wasm_byte_vec_t, wasm_name_t, wasmtime_error_t, wasmtime_module_t, wasmtime_store_t};
1+
use crate::{
2+
wasm_byte_vec_t, wasm_engine_t, wasm_name_t, wasmtime_error_t, wasmtime_module_t,
3+
wasmtime_store_t,
4+
};
25
use std::slice;
36
use std::str::from_utf8;
47
use std::time::Duration;
@@ -18,6 +21,7 @@ pub struct wasmtime_guestprofiler_modules_t<'a> {
1821

1922
#[unsafe(no_mangle)]
2023
pub unsafe extern "C" fn wasmtime_guestprofiler_new(
24+
engine: &wasm_engine_t,
2125
module_name: &wasm_name_t,
2226
interval_nanos: u64,
2327
modules: *const wasmtime_guestprofiler_modules_t,
@@ -36,7 +40,13 @@ pub unsafe extern "C" fn wasmtime_guestprofiler_new(
3640
})
3741
.collect::<Vec<_>>();
3842
Box::new(wasmtime_guestprofiler_t {
39-
guest_profiler: GuestProfiler::new(module_name, Duration::from_nanos(interval_nanos), list),
43+
guest_profiler: GuestProfiler::new(
44+
&engine.engine,
45+
module_name,
46+
Duration::from_nanos(interval_nanos),
47+
list,
48+
)
49+
.unwrap(),
4050
})
4151
}
4252

crates/environ/src/key.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -515,4 +515,29 @@ impl FuncKey {
515515
_ => panic!("`FuncKey::unwrap_resource_drop_trampoline` called on {self:?}"),
516516
}
517517
}
518+
519+
/// Is this "Store-invariant"? This allows us to execute
520+
/// EngineCode directly rather than StoreCode.
521+
///
522+
/// Any function that is either directly from Wasm code, or calls
523+
/// it directly (not indirected through a runtime-provided
524+
/// function pointer), is "store-variant": we need to use a
525+
/// StoreCode-specific version of the code to hit any patching
526+
/// that our specific instantiations may have (due to debugging
527+
/// breakpoints, etc). Trampolines into the runtime cannot be
528+
/// patched and so can use EngineCode instead. This allows for
529+
/// less complex plumbing in some places where we can avoid
530+
/// looking up the StoreCode (or having access to the Store).
531+
pub fn is_store_invariant(&self) -> bool {
532+
match self {
533+
Self::DefinedWasmFunction(..) | Self::ArrayToWasmTrampoline(..) => false,
534+
Self::WasmToArrayTrampoline(..)
535+
| Self::WasmToBuiltinTrampoline(..)
536+
| Self::PulleyHostCall(..) => true,
537+
#[cfg(feature = "component-model")]
538+
Self::ComponentTrampoline(..)
539+
| Self::ResourceDropTrampoline
540+
| Self::UnsafeIntrinsic(..) => true,
541+
}
542+
}
518543
}

0 commit comments

Comments
 (0)