diff --git a/README.md b/README.md index ac3c2f7..9b4c685 100644 --- a/README.md +++ b/README.md @@ -55,21 +55,23 @@ somethingWasmRuntime target/tco-threads/wasm32-wasip1-threads/release/chiwawa.wa ``` ## Tracing -Tracing requires the `trace` feature to be enabled at compile time. Stack the -feature onto a build alias to keep the per-dispatch-mode output directory: +Tracing requires the `trace` feature to be enabled at compile time. It is +performed only by the loop dispatcher (non-`tco`), the same as statistics: the +tail-call dispatcher has no central loop to hook, so `--trace` is ignored with a +warning under `tco`. ```bash # Build with trace feature on top of the loop dispatcher cargo build-legacy --features trace -# Or with the tail-call dispatcher -cargo build-tco --features trace # TRACE_EVENTS = (all,store,load,call,branch) -# TRACE_RESOURCE = (regs,memory,locals,globals,pc) +# TRACE_RESOURCE = (regs,locals,globals,pc) somethingWasmRuntime target/legacy/wasm32-wasip1/release/chiwawa.wasm test.wasm --trace --trace-events [...] --trace-resource [...] ``` -If `--trace` is used without the feature enabled, a warning is displayed and the flag is ignored. +If `--trace` is used without the feature enabled, a warning is displayed and the +flag is ignored. The same applies when `--trace` is combined with the `tco` +feature. ## Statistics diff --git a/src/execution/dispatch_loop.rs b/src/execution/dispatch_loop.rs index ac09e96..f28ed2f 100644 --- a/src/execution/dispatch_loop.rs +++ b/src/execution/dispatch_loop.rs @@ -49,6 +49,18 @@ pub fn execute_instructions(state: &mut VmState) -> Outcome { unsafe { (*state.stats).record_instruction(idx) }; } + #[cfg(feature = "trace")] + if !state.tracer.is_null() { + let ip = state.pc; + let idx = state.current_instr().handler_index(); + let locals = unsafe { std::slice::from_raw_parts(state.locals, state.locals_len) }; + let reg_file = state.reg_file(); + let globals = &state.module().global_addrs; + unsafe { + (*state.tracer).trace_instruction(ip, idx, reg_file, locals, globals); + } + } + let h = unsafe { *state.handlers.add(state.pc) }; match h(state) { Outcome::Continue => continue, diff --git a/src/execution/runtime.rs b/src/execution/runtime.rs index 2f17075..301e8f1 100644 --- a/src/execution/runtime.rs +++ b/src/execution/runtime.rs @@ -177,6 +177,14 @@ impl Runtime { .as_mut() .map_or(std::ptr::null_mut(), |s| s as *mut ExecutionStats); + #[cfg(feature = "trace")] + let tracer_ptr = self + .tracer + .as_mut() + .map_or(std::ptr::null_mut(), |t| t as *mut Tracer); + #[cfg(feature = "trace")] + let locals_len = frame_stack.frame.locals.len(); + let mut state = VmState { reg_file: reg_file_ptr, locals: locals_ptr, @@ -195,6 +203,10 @@ impl Runtime { checkpoint_poll_counter: 0, #[cfg(feature = "stats")] stats: stats_ptr, + #[cfg(feature = "trace")] + tracer: tracer_ptr, + #[cfg(feature = "trace")] + locals_len, }; let outcome = dispatch::execute_instructions(&mut state); diff --git a/src/execution/state.rs b/src/execution/state.rs index 158621d..b44fda4 100644 --- a/src/execution/state.rs +++ b/src/execution/state.rs @@ -67,9 +67,18 @@ pub struct VmState { /// Incremented by `migration::poll_checkpoint` pub checkpoint_poll_counter: u32, - /// Execution statistics sink (loop dispatcher only) + /// Execution statistics (loop dispatcher only) #[cfg(feature = "stats")] pub stats: *mut crate::execution::stats::ExecutionStats, + + /// Execution tracer (loop dispatcher only) + #[cfg(feature = "trace")] + pub tracer: *mut crate::execution::trace::Tracer, + + /// Number of locals in the current frame. + /// Needed because `locals` is a raw pointer with no length; + #[cfg(feature = "trace")] + pub locals_len: usize, } impl VmState { diff --git a/src/main.rs b/src/main.rs index b21032a..77b94a2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -153,6 +153,14 @@ fn main() -> Result<()> { eprintln!(" Rebuild with: cargo build --features trace"); } + // Warn if --trace is combined with the tco feature: the tail-call + // dispatcher has no central loop to hook, so tracing is unsupported there. + #[cfg(all(feature = "trace", feature = "tco"))] + if cli.enable_trace { + eprintln!("Warning: --trace is ignored because the 'tco' feature is enabled."); + eprintln!(" Tracing is only performed by the non-tco dispatcher."); + } + let mut module = Module::new("test"); let _ = parser::parse_bytecode(&mut module, &cli.wasm_file); let imports: ImportObjects = FxHashMap::default();