Skip to content

Commit 952627a

Browse files
committed
Initial factoring out of replay driver
Things left to complete: * Core wasm support * Improved error handling * Wasmtime CLI integration
1 parent b15ae6d commit 952627a

File tree

18 files changed

+397
-158
lines changed

18 files changed

+397
-158
lines changed

crates/cli-flags/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1027,7 +1027,7 @@ impl CommonOptions {
10271027
_v => (),
10281028
_ => err,
10291029
}
1030-
config.recording(true);
1030+
config.rr(wasmtime::RRConfig::Recording);
10311031
},
10321032
_ => err,
10331033
}

crates/wasmtime/src/config.rs

Lines changed: 26 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,17 @@ impl ModuleVersionStrategy {
110110
}
111111
}
112112

113+
/// Configuration for record/replay
114+
#[derive(Clone)]
115+
pub enum RRConfig {
116+
/// Recording on store is enabled
117+
Recording,
118+
/// Replaying on store is enabled
119+
Replaying,
120+
/// No record/replay is enabled
121+
None,
122+
}
123+
113124
/// Global configuration options used to create an [`Engine`](crate::Engine)
114125
/// and customize its behavior.
115126
///
@@ -175,9 +186,7 @@ pub struct Config {
175186
pub(crate) macos_use_mach_ports: bool,
176187
pub(crate) detect_host_feature: Option<fn(&str) -> Option<bool>>,
177188
#[cfg(feature = "rr")]
178-
pub(crate) record_support: bool,
179-
#[cfg(feature = "rr")]
180-
pub(crate) replay_support: bool,
189+
pub(crate) rr_config: RRConfig,
181190
}
182191

183192
/// User-provided configuration for the compiler.
@@ -287,9 +296,7 @@ impl Config {
287296
#[cfg(not(feature = "std"))]
288297
detect_host_feature: None,
289298
#[cfg(feature = "rr")]
290-
record_support: false,
291-
#[cfg(feature = "rr")]
292-
replay_support: false,
299+
rr_config: RRConfig::None,
293300
};
294301
#[cfg(any(feature = "cranelift", feature = "winch"))]
295302
{
@@ -2705,11 +2712,9 @@ impl Config {
27052712
self
27062713
}
27072714

2708-
/// Enforce deterministic execution configurations. Currently, means the following:
2715+
/// Enforce deterministic execution configurations. Currently, this means the following:
27092716
/// * Enabling NaN canonicalization with [`Config::cranelift_nan_canonicalization`]
27102717
/// * Enabling deterministic relaxed SIMD with [`Config::relaxed_simd_deterministic`]
2711-
///
2712-
/// Required for faithful record/replay execution.
27132718
#[inline]
27142719
pub fn enforce_determinism(&mut self) -> &mut Self {
27152720
#[cfg(any(feature = "cranelift", feature = "winch"))]
@@ -2718,56 +2723,29 @@ impl Config {
27182723
self
27192724
}
27202725

2721-
/// Remove determinstic execution enforcements (if any) applied
2722-
/// by [`Config::enforce_determinism`].
2723-
#[inline]
2724-
pub fn remove_determinism_enforcement(&mut self) -> &mut Self {
2725-
#[cfg(any(feature = "cranelift", feature = "winch"))]
2726-
self.cranelift_nan_canonicalization(false);
2727-
self.relaxed_simd_deterministic(false);
2728-
self
2729-
}
2730-
2731-
/// Enable execution trace recording with the provided configuration.
2726+
/// Enable execution trace recording or replaying to the configuration
27322727
///
2733-
/// This method implicitly enforces determinism (see [`Config::enforce_determinism`]
2734-
/// for details).
2728+
/// When either recording/replaying are enabled, determinism is implicitly
2729+
/// enforced (see [`Config::enforce_determinism`] for details)
27352730
#[cfg(feature = "rr")]
27362731
#[inline]
2737-
pub fn recording(&mut self, enable: bool) -> &mut Self {
2738-
if enable {
2739-
self.enforce_determinism();
2740-
} else {
2741-
self.remove_determinism_enforcement();
2742-
}
2743-
self.record_support = enable;
2744-
self
2745-
}
2746-
2747-
/// Enable execution trace replaying with the provided configuration.
2748-
///
2749-
/// This method implicitly enforces determinism (see [`Config::enforce_determinism`]
2750-
/// for details).
2751-
#[cfg(feature = "rr")]
2752-
#[inline]
2753-
pub fn replaying(&mut self, enable: bool) -> &mut Self {
2754-
if enable {
2755-
self.enforce_determinism();
2756-
} else {
2757-
self.remove_determinism_enforcement();
2732+
pub fn rr(&mut self, cfg: RRConfig) -> &mut Self {
2733+
self.rr_config = cfg;
2734+
match self.rr_config {
2735+
RRConfig::Recording | RRConfig::Replaying => self.enforce_determinism(),
2736+
_ => self,
27582737
}
2759-
self.replay_support = enable;
2760-
self
27612738
}
27622739

27632740
/// Evaluates to true if current configuration must respect
27642741
/// deterministic execution in its configuration.
2765-
///
2766-
/// Required for faithful record/replay execution.
27672742
#[cfg(feature = "rr")]
27682743
#[inline]
27692744
pub fn is_determinism_enforced(&mut self) -> bool {
2770-
self.record_support || self.replay_support
2745+
match self.rr_config {
2746+
RRConfig::Recording | RRConfig::Replaying => true,
2747+
RRConfig::None => false,
2748+
}
27712749
}
27722750
}
27732751

crates/wasmtime/src/engine.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
use crate::Config;
2+
#[cfg(feature = "rr")]
3+
use crate::RRConfig;
24
use crate::prelude::*;
35
#[cfg(feature = "runtime")]
46
pub use crate::runtime::code_memory::CustomCodeMemory;
@@ -258,7 +260,20 @@ impl Engine {
258260
#[cfg(feature = "rr")]
259261
#[inline]
260262
pub fn is_recording(&self) -> bool {
261-
self.config().record_support
263+
match self.config().rr_config {
264+
RRConfig::Recording => true,
265+
_ => false,
266+
}
267+
}
268+
269+
/// Returns whether the engine is configured to support execution replaying
270+
#[cfg(feature = "rr")]
271+
#[inline]
272+
pub fn is_replaying(&self) -> bool {
273+
match self.config().rr_config {
274+
RRConfig::Replaying => true,
275+
_ => false,
276+
}
262277
}
263278

264279
/// Detects whether the bytes provided are a precompiled object produced by

crates/wasmtime/src/runtime.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,9 @@ pub use memory::*;
8888
pub use module::{Module, ModuleExport};
8989
pub use resources::*;
9090
#[cfg(feature = "rr")]
91-
pub use rr::{RecordSettings, RecordWriter, ReplayReader, ReplaySettings};
91+
pub use rr::{
92+
RecordSettings, RecordWriter, ReplayEnvironment, ReplayInstance, ReplayReader, ReplaySettings,
93+
};
9294
#[cfg(all(feature = "async", feature = "call-hook"))]
9395
pub use store::CallHookHandler;
9496
pub use store::{

crates/wasmtime/src/runtime/component/func.rs

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -534,7 +534,7 @@ impl Func {
534534
/// `LowerParams` and `LowerReturn` type. They must match the type of `self`
535535
/// for the params/results that are going to be produced. Additionally
536536
/// these types must be representable with a sequence of `ValRaw` values.
537-
unsafe fn call_raw<T, Return, LowerParams, LowerReturn>(
537+
pub(crate) unsafe fn call_raw<T, Return, LowerParams, LowerReturn>(
538538
&self,
539539
mut store: StoreContextMut<'_, T>,
540540
lower: impl FnOnce(
@@ -548,6 +548,19 @@ impl Func {
548548
LowerParams: Copy,
549549
LowerReturn: Copy,
550550
{
551+
#[cfg(feature = "rr-component")]
552+
{
553+
use crate::rr::component_events::WasmFuncBeginEvent;
554+
555+
let component = *self.instance.id().get(store.0).component().checksum();
556+
let instance = self.instance.id().instance();
557+
let func_idx = self.index;
558+
store.0.record_event(|| WasmFuncBeginEvent {
559+
component,
560+
instance,
561+
func_idx,
562+
})?;
563+
}
551564
let export = self.lifted_core_func(store.0);
552565

553566
#[repr(C)]
@@ -592,12 +605,11 @@ impl Func {
592605
))
593606
.unwrap();
594607

595-
component_hooks::record_replay_wasm_func(
608+
component_hooks::record_and_replay_validate_wasm_func(
596609
|store| crate::Func::call_unchecked_raw(store, export, params_and_returns),
597610
params_and_returns.as_ref(),
598-
self.index,
599611
self.abi_info(store.0).2,
600-
self.instance.id(),
612+
self.instance.id().get(store.0).component().types().clone(),
601613
&mut store,
602614
)?;
603615
}
@@ -810,7 +822,7 @@ impl Func {
810822
Ok(())
811823
}
812824

813-
fn lift_results<'a, 'b>(
825+
pub(crate) fn lift_results<'a, 'b>(
814826
cx: &'a mut LiftContext<'b>,
815827
results_ty: InterfaceType,
816828
src: &'a [ValRaw],
@@ -875,7 +887,7 @@ impl Func {
875887
/// The `lower` closure provided should perform the actual lowering and
876888
/// return the result of the lowering operation which is then returned from
877889
/// this function as well.
878-
fn with_lower_context<T>(
890+
pub(crate) fn with_lower_context<T>(
879891
self,
880892
mut store: StoreContextMut<T>,
881893
may_enter: bool,

crates/wasmtime/src/runtime/component/func/host.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ where
257257

258258
let types = vminstance.component().types().clone();
259259

260-
rr::component_hooks::record_replay_host_func_entry(storage, &types, &ty, store.0)?;
260+
rr::component_hooks::record_and_replay_validate_host_func_entry(storage, &types, &ty, store.0)?;
261261

262262
let func_ty = &types[ty];
263263
let param_tys = InterfaceType::Tuple(func_ty.params);
@@ -813,7 +813,7 @@ where
813813

814814
let types = instance.id().get(store.0).component().types().clone();
815815

816-
rr::component_hooks::record_replay_host_func_entry(storage, &types, &ty, store.0)?;
816+
rr::component_hooks::record_and_replay_validate_host_func_entry(storage, &types, &ty, store.0)?;
817817

818818
let func_ty = &types[ty];
819819
let param_tys = &types[func_ty.params];

crates/wasmtime/src/runtime/component/instance.rs

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -902,6 +902,13 @@ impl<'a> Instantiator<'a> {
902902
store.store_data_mut().component_instance_mut(self.id)
903903
}
904904

905+
/// Convenience helper to return the instance ID of the `ComponentInstance` that's
906+
/// being instantiated
907+
#[cfg(feature = "rr-component")]
908+
fn id(&self) -> ComponentInstanceId {
909+
self.id
910+
}
911+
905912
// NB: This method is only intended to be called during the instantiation
906913
// process because the `Arc::get_mut` here is fallible and won't generally
907914
// succeed once the instance has been handed to the embedder. Before that
@@ -1016,23 +1023,18 @@ impl<T: 'static> InstancePre<T> {
10161023

10171024
fn instantiate_impl(&self, mut store: impl AsContextMut<Data = T>) -> Result<Instance> {
10181025
let mut store = store.as_context_mut();
1019-
#[cfg(feature = "rr-component")]
1020-
{
1021-
use crate::rr::{Validate, component_events::InstantiationEvent};
1022-
store
1023-
.0
1024-
.record_event(|| InstantiationEvent::from_component(&self.component))?;
1025-
// This is a required validation check for functional correctness, so don't use
1026-
// [`StoreOpaque::next_replay_event_validation`]
1027-
store.0.next_replay_event_and(|event: InstantiationEvent| {
1028-
event.validate(&InstantiationEvent::from_component(&self.component))
1029-
})?;
1030-
}
10311026
store
10321027
.engine()
10331028
.allocator()
10341029
.increment_component_instance_count()?;
10351030
let mut instantiator = Instantiator::new(&self.component, store.0, &self.imports);
1031+
#[cfg(feature = "rr-component")]
1032+
{
1033+
use crate::rr::component_events::InstantiationEvent;
1034+
store.0.record_event(|| {
1035+
InstantiationEvent(*self.component.checksum(), instantiator.id())
1036+
})?;
1037+
}
10361038
instantiator.run(&mut store).map_err(|e| {
10371039
store
10381040
.engine()

crates/wasmtime/src/runtime/component/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ mod linker;
112112
mod matching;
113113
mod resource_table;
114114
mod resources;
115-
mod storage;
115+
pub(crate) mod storage;
116116
pub(crate) mod store;
117117
pub mod types;
118118
mod values;

crates/wasmtime/src/runtime/component/store.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,15 @@ use crate::store::{StoreData, StoreId, StoreOpaque};
33
#[cfg(feature = "component-model-async")]
44
use alloc::vec::Vec;
55
use core::pin::Pin;
6+
use serde::{Deserialize, Serialize};
67
use wasmtime_environ::PrimaryMap;
78

89
#[derive(Default)]
910
pub struct ComponentStoreData {
1011
instances: PrimaryMap<ComponentInstanceId, Option<OwnedComponentInstance>>,
1112
}
1213

13-
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
14+
#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Ord, PartialOrd)]
1415
pub struct ComponentInstanceId(u32);
1516
wasmtime_environ::entity_impl!(ComponentInstanceId);
1617

crates/wasmtime/src/runtime/func.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2366,7 +2366,7 @@ impl HostContext {
23662366
let func = &state.func;
23672367

23682368
let func_type_index = state._ty.index();
2369-
let (params_size, results_size) = {
2369+
let (flat_size_params, flat_size_results) = {
23702370
let type_index = state._ty.index();
23712371
let wasm_func_subtype = caller.engine().signatures().borrow(type_index).unwrap();
23722372
let wasm_func_type = wasm_func_subtype.unwrap_func();
@@ -2383,13 +2383,13 @@ impl HostContext {
23832383
.collect::<Vec<_>>(),
23842384
)
23852385
};
2386-
let (num_params, num_results) = (params_size.len(), results_size.len());
2386+
let (num_params, num_results) = (flat_size_params.len(), flat_size_results.len());
23872387

23882388
// Record/replay(validation) of the raw parameter arguments
23892389
// Don't need auto-assert GC store here since we aren't using P, just raw args
23902390
rr::core_hooks::record_replay_host_func_entry(
23912391
unsafe { &args.as_ref()[..num_params] },
2392-
params_size.as_slice(),
2392+
flat_size_params.as_slice(),
23932393
&func_type_index,
23942394
caller.store.0,
23952395
)?;
@@ -2435,7 +2435,7 @@ impl HostContext {
24352435
// Record the return values
24362436
rr::core_hooks::record_host_func_return(
24372437
unsafe { &args.as_ref()[..num_results] },
2438-
results_size.as_slice(),
2438+
flat_size_results.as_slice(),
24392439
&func_type_index,
24402440
caller.store.0,
24412441
)?;

0 commit comments

Comments
 (0)