@@ -16,6 +16,8 @@ use std::io::BufReader;
1616use std:: path:: { Path , PathBuf } ;
1717use std:: sync:: { Arc , Mutex } ;
1818use std:: thread;
19+ #[ cfg( feature = "rr" ) ]
20+ use tokio:: time:: error:: Elapsed ;
1921use wasi_common:: sync:: { Dir , TcpListener , WasiCtxBuilder , ambient_authority} ;
2022#[ cfg( feature = "rr" ) ]
2123use wasmtime:: ReplayEnvironment ;
@@ -101,16 +103,16 @@ impl RunCommand {
101103 ) -> Result < ( ) > {
102104 self . run . common . init_logging ( ) ?;
103105
104- let mut config = self . run . common . config ( None ) ?;
106+ #[ cfg( feature = "rr" ) ]
107+ let is_replaying = replay_opts. is_some ( ) ;
105108 #[ cfg( not( feature = "rr" ) ) ]
109+ let is_replaying = false ;
110+
111+ let mut config = self . run . common . config ( None ) ?;
106112 config. async_support ( true ) ;
107113 #[ cfg( feature = "rr" ) ]
108- if replay_opts. is_some ( ) {
109- // Replay does not support async yet
110- config. async_support ( false ) ;
114+ if is_replaying {
111115 config. rr ( wasmtime:: RRConfig :: Replaying ) ;
112- } else {
113- config. async_support ( true ) ;
114116 }
115117
116118 if self . run . common . wasm . timeout . is_some ( ) {
@@ -173,13 +175,7 @@ impl RunCommand {
173175 } ;
174176
175177 let mut store = Store :: new ( & engine, host) ;
176- #[ cfg( not( feature = "rr" ) ) ]
177178 self . populate_with_wasi ( & mut linker, & mut store, & main) ?;
178- // For replay, we don't populate WASI
179- #[ cfg( feature = "rr" ) ]
180- if !replay_opts. is_some ( ) {
181- self . populate_with_wasi ( & mut linker, & mut store, & main) ?;
182- }
183179
184180 store. data_mut ( ) . limits = self . run . store_limits ( ) ;
185181 store. limiter ( |t| & mut t. limits ) ;
@@ -192,32 +188,6 @@ impl RunCommand {
192188
193189 #[ cfg( feature = "rr" ) ]
194190 {
195- // If this is a replay run, skip to replay setup and run to completion
196- //
197- // Note: Right now, replay doesn't inherit any store settings listed
198- // above. This will have to change in the future. In general, replays will
199- // need an "almost exact" superset of the run configurations, but with
200- // certain different options (e.g. fuel consumption).
201- if let Some ( opts) = replay_opts {
202- let settings = ReplaySettings {
203- validate : opts. validate ,
204- deser_buffer_size : opts. deser_buffer_size ,
205- ..Default :: default ( )
206- } ;
207-
208- let mut renv = ReplayEnvironment :: new ( & engine, settings) ;
209- match main {
210- RunTarget :: Core ( m) => {
211- renv. add_module ( m) ;
212- }
213- RunTarget :: Component ( c) => {
214- renv. add_component ( c) ;
215- }
216- }
217- let mut instance = renv. instantiate ( BufReader :: new ( fs:: File :: open ( opts. trace ) ?) ) ?;
218- return instance. run_to_completion ( ) ;
219- }
220-
221191 // Recording settings for this execution's store
222192 let record = & self . run . common . record ;
223193 if let Some ( path) = & record. path {
@@ -251,61 +221,133 @@ impl RunCommand {
251221 . wasm
252222 . timeout
253223 . unwrap_or ( std:: time:: Duration :: MAX ) ;
254- let result = runtime. block_on ( async {
255- tokio:: time:: timeout ( dur, async {
256- let mut profiled_modules: Vec < ( String , Module ) > = Vec :: new ( ) ;
257- if let RunTarget :: Core ( m) = & main {
258- profiled_modules. push ( ( "" . to_string ( ) , m. clone ( ) ) ) ;
259- }
260224
261- // Load the preload wasm modules.
262- for ( name, path) in self . preloads . iter ( ) {
263- // Read the wasm module binary either as `*.wat` or a raw binary
264- let preload_target = self . run . load_module ( & engine, path) ?;
265- let preload_module = match preload_target {
266- RunTarget :: Core ( m) => m,
267- #[ cfg( feature = "component-model" ) ]
268- RunTarget :: Component ( _) => {
269- bail ! ( "components cannot be loaded with `--preload`" )
270- }
271- } ;
272- profiled_modules. push ( ( name. to_string ( ) , preload_module. clone ( ) ) ) ;
273-
274- // Add the module's functions to the linker.
275- match & mut linker {
276- #[ cfg( feature = "cranelift" ) ]
277- CliLinker :: Core ( linker) => {
278- linker
279- . module_async ( & mut store, name, & preload_module)
280- . await
281- . context ( format ! (
282- "failed to process preload `{}` at `{}`" ,
283- name,
284- path. display( )
285- ) ) ?;
286- }
287- #[ cfg( not( feature = "cranelift" ) ) ]
288- CliLinker :: Core ( _) => {
289- bail ! ( "support for --preload disabled at compile time" ) ;
290- }
291- #[ cfg( feature = "component-model" ) ]
292- CliLinker :: Component ( _) => {
293- bail ! ( "--preload cannot be used with components" ) ;
225+ let result = if is_replaying {
226+ // Note: While replaying, we need to retrieveIn general, replays will need an "almost exact" superset of
227+ // the run configurations, but with potentially certain different options (e.g. fuel consumption).
228+ #[ cfg( feature = "rr" ) ]
229+ {
230+ struct OkReplayT ( Store < Host > ) ;
231+ struct ErrReplayT ( Error , Store < Host > ) ;
232+ let opts = replay_opts. unwrap ( ) ;
233+ let settings = ReplaySettings {
234+ validate : opts. validate ,
235+ deser_buffer_size : opts. deser_buffer_size ,
236+ ..Default :: default ( )
237+ } ;
238+
239+ let mut renv = ReplayEnvironment :: new ( & engine, settings) ;
240+ match & main {
241+ RunTarget :: Core ( m) => {
242+ renv. add_module ( m. clone ( ) ) ;
243+ }
244+ RunTarget :: Component ( c) => {
245+ renv. add_component ( c. clone ( ) ) ;
246+ }
247+ }
248+ let mut replay_instance = renv. instantiate_with_store (
249+ || store,
250+ BufReader :: new ( fs:: File :: open ( opts. trace ) ?) ,
251+ ) ?;
252+
253+ let result_replay_run: Result < Result < OkReplayT , ErrReplayT > , Elapsed > = runtime
254+ . block_on ( async {
255+ tokio:: time:: timeout ( dur, async {
256+ let res = replay_instance. run_to_completion_async ( ) . await ;
257+ match res {
258+ Ok ( _) => Ok ( OkReplayT ( replay_instance. extract_store ( ) ) ) ,
259+ Err ( e) => Err ( ErrReplayT ( e, replay_instance. extract_store ( ) ) ) ,
260+ }
261+ } )
262+ . await
263+ } ) ;
264+ match result_replay_run {
265+ Ok ( Ok ( OkReplayT ( s) ) ) => {
266+ store = s;
267+ Ok ( Ok ( ( ) ) )
268+ }
269+ Ok ( Err ( ErrReplayT ( e, s) ) ) => {
270+ store = s;
271+ Ok ( Err ( e) )
272+ }
273+ Err ( elapsed) => {
274+ eprintln ! (
275+ "Error: {:?}" ,
276+ Err :: <( ) , Error >( anyhow:: Error :: from( wasmtime:: Trap :: Interrupt ) )
277+ . with_context( || format!( "timed out after {elapsed}" ) )
278+ ) ;
279+ cfg_if:: cfg_if! {
280+ if #[ cfg( unix) ] {
281+ std:: process:: exit( rustix:: process:: EXIT_SIGNALED_SIGABRT ) ;
282+ } else if #[ cfg( windows) ] {
283+ // https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/abort?view=vs-2019
284+ std:: process:: exit( 3 ) ;
285+ }
294286 }
295287 }
296288 }
289+ }
290+ #[ cfg( not( feature = "rr" ) ) ]
291+ {
292+ unreachable ! ( "should be unreachable when `rr` feature is disabled" ) ;
293+ }
294+ } else {
295+ runtime. block_on ( async {
296+ tokio:: time:: timeout ( dur, async {
297+ let mut profiled_modules: Vec < ( String , Module ) > = Vec :: new ( ) ;
298+ if let RunTarget :: Core ( m) = & main {
299+ profiled_modules. push ( ( "" . to_string ( ) , m. clone ( ) ) ) ;
300+ }
297301
298- self . load_main_module ( & mut store, & mut linker, & main, profiled_modules)
299- . await
300- . with_context ( || {
301- format ! (
302- "failed to run main module `{}`" ,
303- self . module_and_args[ 0 ] . to_string_lossy( )
304- )
305- } )
302+ // Load the preload wasm modules.
303+ for ( name, path) in self . preloads . iter ( ) {
304+ // Read the wasm module binary either as `*.wat` or a raw binary
305+ let preload_target = self . run . load_module ( & engine, path) ?;
306+ let preload_module = match preload_target {
307+ RunTarget :: Core ( m) => m,
308+ #[ cfg( feature = "component-model" ) ]
309+ RunTarget :: Component ( _) => {
310+ bail ! ( "components cannot be loaded with `--preload`" )
311+ }
312+ } ;
313+ profiled_modules. push ( ( name. to_string ( ) , preload_module. clone ( ) ) ) ;
314+
315+ // Add the module's functions to the linker.
316+ match & mut linker {
317+ #[ cfg( feature = "cranelift" ) ]
318+ CliLinker :: Core ( linker) => {
319+ linker
320+ . module_async ( & mut store, name, & preload_module)
321+ . await
322+ . context ( format ! (
323+ "failed to process preload `{}` at `{}`" ,
324+ name,
325+ path. display( )
326+ ) ) ?;
327+ }
328+ #[ cfg( not( feature = "cranelift" ) ) ]
329+ CliLinker :: Core ( _) => {
330+ bail ! ( "support for --preload disabled at compile time" ) ;
331+ }
332+ #[ cfg( feature = "component-model" ) ]
333+ CliLinker :: Component ( _) => {
334+ bail ! ( "--preload cannot be used with components" ) ;
335+ }
336+ }
337+ }
338+
339+ self . load_main_module ( & mut store, & mut linker, & main, profiled_modules)
340+ . await
341+ . with_context ( || {
342+ format ! (
343+ "failed to run main module `{}`" ,
344+ self . module_and_args[ 0 ] . to_string_lossy( )
345+ )
346+ } )
347+ } )
348+ . await
306349 } )
307- . await
308- } ) ;
350+ } ;
309351
310352 // Load the main wasm module.
311353 match result. unwrap_or_else ( |elapsed| {
0 commit comments