@@ -43,25 +43,73 @@ impl ReplayEnvironment {
4343 }
4444
4545 /// Instantiate a new [`ReplayInstance`] using a [`ReplayReader`] in context of this environment
46- pub fn instantiate ( & self , reader : impl ReplayReader + ' static ) -> Result < ReplayInstance < ( ) > > {
47- let store = Store :: new ( & self . engine , ( ) ) ;
48- ReplayInstance :: < ( ) > :: from_environment_and_store ( self . clone ( ) , store, reader)
46+ pub fn instantiate ( & self , reader : impl ReplayReader + ' static ) -> Result < ReplayInstance > {
47+ self . instantiate_with ( reader, |_| Ok ( ( ) ) , |_| Ok ( ( ) ) , |_| Ok ( ( ) ) )
4948 }
5049
51- /// Like [`Self::instantiate`] but allows providing a custom [`Store`] generator
52- pub fn instantiate_with_store < T > (
50+ /// Like [`Self::instantiate`] but allows providing a custom modifier functions for
51+ /// [`Store`], [`crate::Linker`], and [`component::Linker`] within the replay
52+ pub fn instantiate_with (
5353 & self ,
54- store_gen : impl FnOnce ( ) -> Store < T > ,
5554 reader : impl ReplayReader + ' static ,
56- ) -> Result < ReplayInstance < T > > {
57- ReplayInstance :: from_environment_and_store ( self . clone ( ) , store_gen ( ) , reader)
55+ store_fn : impl FnOnce ( & mut Store < ReplayHostContext > ) -> Result < ( ) > ,
56+ module_linker_fn : impl FnOnce ( & mut crate :: Linker < ReplayHostContext > ) -> Result < ( ) > ,
57+ component_linker_fn : impl FnOnce ( & mut component:: Linker < ReplayHostContext > ) -> Result < ( ) > ,
58+ ) -> Result < ReplayInstance > {
59+ let mut store = Store :: new (
60+ & self . engine ,
61+ ReplayHostContext {
62+ module_instances : BTreeMap :: new ( ) ,
63+ } ,
64+ ) ;
65+ store_fn ( & mut store) ?;
66+ store. init_replaying ( reader, self . settings . clone ( ) ) ?;
67+
68+ ReplayInstance :: from_environment_and_store (
69+ self . clone ( ) ,
70+ store,
71+ module_linker_fn,
72+ component_linker_fn,
73+ )
74+ }
75+ }
76+
77+ /// The host context tied to the store during replay.
78+ ///
79+ /// This context encapsulates the state from the replay environment that are
80+ /// required to be accessible within the Store. This is an opaque type from the
81+ /// public API perspective.
82+ pub struct ReplayHostContext {
83+ /// A tracker of instantiated modules.
84+ ///
85+ /// Core wasm modules can be re-entrant and invoke methods from other instances, and this
86+ /// needs to be accessible within host functions
87+ module_instances : BTreeMap < InstanceId , crate :: Instance > ,
88+ }
89+
90+ impl ReplayHostContext {
91+ /// Insert a module instance into the context's tracking map.
92+ fn insert_module_instance ( & mut self , id : InstanceId , instance : crate :: Instance ) {
93+ self . module_instances . insert ( id, instance) ;
94+ }
95+
96+ /// Get a module instance from the context's tracking map
97+ ///
98+ /// This is necessary for core wasm to identify re-entrant calls during replay.
99+ pub ( crate ) fn get_module_instance (
100+ & self ,
101+ id : InstanceId ,
102+ ) -> Result < & crate :: Instance , ReplayError > {
103+ self . module_instances
104+ . get ( & id)
105+ . ok_or ( ReplayError :: MissingModuleInstance ( id. as_u32 ( ) ) )
58106 }
59107}
60108
61- /// A [`ReplayInstance`] is an object providing a opaquely managed, replayable [`Store`]
109+ /// A [`ReplayInstance`] is an object providing a opaquely managed, replayable [`Store`].
62110///
63111/// Debugger capabilities in the future will interact with this object for
64- /// inserting breakpoints, snapshotting, and restoring state
112+ /// inserting breakpoints, snapshotting, and restoring state.
65113///
66114/// # Example
67115///
@@ -122,32 +170,36 @@ impl ReplayEnvironment {
122170/// # Ok(())
123171/// # }
124172/// ```
125- pub struct ReplayInstance < T : ' static > {
173+ pub struct ReplayInstance {
126174 env : Arc < ReplayEnvironment > ,
127- store : Store < T > ,
128- component_linker : component:: Linker < T > ,
129- module_linker : crate :: Linker < T > ,
175+ store : Store < ReplayHostContext > ,
176+ component_linker : component:: Linker < ReplayHostContext > ,
177+ module_linker : crate :: Linker < ReplayHostContext > ,
130178 module_instances : BTreeMap < InstanceId , crate :: Instance > ,
131179 component_instances : BTreeMap < ComponentInstanceId , component:: Instance > ,
132180}
133181
134- impl < T : ' static > ReplayInstance < T > {
182+ impl ReplayInstance {
135183 fn from_environment_and_store (
136184 env : ReplayEnvironment ,
137- mut store : Store < T > ,
138- reader : impl ReplayReader + ' static ,
185+ store : Store < ReplayHostContext > ,
186+ module_linker_fn : impl FnOnce ( & mut crate :: Linker < ReplayHostContext > ) -> Result < ( ) > ,
187+ component_linker_fn : impl FnOnce ( & mut component:: Linker < ReplayHostContext > ) -> Result < ( ) > ,
139188 ) -> Result < Self > {
140189 let env = Arc :: new ( env) ;
141- store. init_replaying ( reader, env. settings . clone ( ) ) ?;
142- let mut module_linker = crate :: Linker :: < T > :: new ( & env. engine ) ;
190+ let mut module_linker = crate :: Linker :: < ReplayHostContext > :: new ( & env. engine ) ;
143191 // Replays shouldn't use any imports, so stub them all out as traps
144192 for module in env. modules . values ( ) {
145193 module_linker. define_unknown_imports_as_traps ( module) ?;
146194 }
147- let mut component_linker = component:: Linker :: < T > :: new ( & env. engine ) ;
195+ module_linker_fn ( & mut module_linker) ?;
196+
197+ let mut component_linker = component:: Linker :: < ReplayHostContext > :: new ( & env. engine ) ;
148198 for component in env. components . values ( ) {
149199 component_linker. define_unknown_imports_as_traps ( component) ?;
150200 }
201+ component_linker_fn ( & mut component_linker) ?;
202+
151203 Ok ( Self {
152204 env,
153205 store,
@@ -158,23 +210,23 @@ impl<T: 'static> ReplayInstance<T> {
158210 } )
159211 }
160212
161- /// Obtain a reference to the internal [`Store`]
162- pub fn store ( & self ) -> & Store < T > {
213+ /// Obtain a reference to the internal [`Store`].
214+ pub fn store ( & self ) -> & Store < ReplayHostContext > {
163215 & self . store
164216 }
165217
166- /// Consume the [`ReplayInstance`] and extract the internal [`Store`]
167- pub fn extract_store ( self ) -> Store < T > {
218+ /// Consume the [`ReplayInstance`] and extract the internal [`Store`].
219+ pub fn extract_store ( self ) -> Store < ReplayHostContext > {
168220 self . store
169221 }
170222
171- /// Run a single top-level event from the instance
223+ /// Run a single top-level event from the instance.
172224 ///
173225 /// "Top-level" events are those explicitly invoked events, namely:
174226 /// * Instantiation events (component/module)
175227 /// * Wasm function begin events (`ComponentWasmFuncBegin` for components and `CoreWasmFuncEntry` for core)
176228 ///
177- /// All other events are transparently dispatched under the context of these top-level events
229+ /// All other events are transparently dispatched under the context of these top-level events.
178230 fn run_single_top_level_event ( & mut self , rr_event : RREvent ) -> Result < ( ) > {
179231 match rr_event {
180232 RREvent :: ComponentInstantiation ( event) => {
@@ -281,7 +333,12 @@ impl<T: 'static> ReplayInstance<T> {
281333 instance : instance. id ( ) ,
282334 } ) ?;
283335
336+ // Insert into host context tracking as well
284337 self . module_instances . insert ( instance. id ( ) , instance) ;
338+ self . store
339+ . as_context_mut ( )
340+ . data_mut ( )
341+ . insert_module_instance ( instance. id ( ) , instance) ;
285342 }
286343 RREvent :: CoreWasmFuncEntry ( event) => {
287344 // Grab the correct module instance
@@ -321,12 +378,9 @@ impl<T: 'static> ReplayInstance<T> {
321378 Ok ( ( ) )
322379 }
323380
324- /// Exactly like [`Self::run_single_top_level_event`] but uses async stores and calls
381+ /// Exactly like [`Self::run_single_top_level_event`] but uses async stores and calls.
325382 #[ cfg( feature = "async" ) ]
326- async fn run_single_top_level_event_async ( & mut self , rr_event : RREvent ) -> Result < ( ) >
327- where
328- T : Send ,
329- {
383+ async fn run_single_top_level_event_async ( & mut self , rr_event : RREvent ) -> Result < ( ) > {
330384 match rr_event {
331385 RREvent :: ComponentInstantiation ( event) => {
332386 // Find matching component from environment to instantiate
@@ -441,6 +495,10 @@ impl<T: 'static> ReplayInstance<T> {
441495 } ) ?;
442496
443497 self . module_instances . insert ( instance. id ( ) , instance) ;
498+ self . store
499+ . as_context_mut ( )
500+ . data_mut ( )
501+ . insert_module_instance ( instance. id ( ) , instance) ;
444502 }
445503 RREvent :: CoreWasmFuncEntry ( event) => {
446504 // Grab the correct module instance
@@ -500,10 +558,7 @@ impl<T: 'static> ReplayInstance<T> {
500558
501559 /// Exactly like [`Self::run_to_completion`] but uses async stores and calls
502560 #[ cfg( feature = "async" ) ]
503- pub async fn run_to_completion_async ( & mut self ) -> Result < ( ) >
504- where
505- T : Send ,
506- {
561+ pub async fn run_to_completion_async ( & mut self ) -> Result < ( ) > {
507562 while let Some ( rr_event) = self
508563 . store
509564 . as_context_mut ( )
0 commit comments