@@ -41,6 +41,7 @@ pub struct WasmSandbox {
4141 // Snapshot of state of an initial WasmSandbox (runtime loaded, but no guest module code loaded).
4242 // Used for LoadedWasmSandbox to be able restore state back to WasmSandbox
4343 snapshot : Option < Arc < Snapshot > > ,
44+ needs_restore : bool ,
4445}
4546
4647const MAPPED_BINARY_VA : u64 = 0x1_0000_0000u64 ;
@@ -56,6 +57,7 @@ impl WasmSandbox {
5657 Ok ( WasmSandbox {
5758 inner : Some ( inner) ,
5859 snapshot : Some ( snapshot) ,
60+ needs_restore : false ,
5961 } )
6062 }
6163
@@ -64,24 +66,41 @@ impl WasmSandbox {
6466 /// the snapshot has already been created in that case.
6567 /// Expects a snapshot of the state where wasm runtime is loaded, but no guest module code is loaded.
6668 pub ( super ) fn new_from_loaded (
67- mut loaded : MultiUseSandbox ,
69+ loaded : MultiUseSandbox ,
6870 snapshot : Arc < Snapshot > ,
6971 ) -> Result < Self > {
70- loaded. restore ( snapshot. clone ( ) ) ?;
7172 metrics:: gauge!( METRIC_ACTIVE_WASM_SANDBOXES ) . increment ( 1 ) ;
7273 metrics:: counter!( METRIC_TOTAL_WASM_SANDBOXES ) . increment ( 1 ) ;
7374 Ok ( WasmSandbox {
7475 inner : Some ( loaded) ,
7576 snapshot : Some ( snapshot) ,
77+ needs_restore : true ,
7678 } )
7779 }
7880
81+ fn restore_if_needed ( & mut self ) -> Result < ( ) > {
82+ if self . needs_restore {
83+ self . inner
84+ . as_mut ( )
85+ . ok_or ( new_error ! ( "WasmSandbox is none" ) ) ?
86+ . restore (
87+ self . snapshot
88+ . as_ref ( )
89+ . ok_or ( new_error ! ( "Snapshot is none" ) ) ?
90+ . clone ( ) ,
91+ ) ?;
92+ self . needs_restore = false ;
93+ }
94+ Ok ( ( ) )
95+ }
96+
7997 /// Load a Wasm module at the given path into the sandbox and return a `LoadedWasmSandbox`
8098 /// able to execute code in the loaded Wasm Module.
8199 ///
82100 /// Before you can call guest functions in the sandbox, you must call
83101 /// this function and use the returned value to call guest functions.
84102 pub fn load_module ( mut self , file : impl AsRef < Path > ) -> Result < LoadedWasmSandbox > {
103+ self . restore_if_needed ( ) ?;
85104 let inner = self
86105 . inner
87106 . as_mut ( )
@@ -97,6 +116,18 @@ impl WasmSandbox {
97116 self . finalize_module_load ( )
98117 }
99118
119+ /// Load a Wasm module by restoring a Hyperlight snapshot taken
120+ /// from a `LoadedWasmSandbox`.
121+ pub fn load_from_snapshot ( mut self , snapshot : Arc < Snapshot > ) -> Result < LoadedWasmSandbox > {
122+ let sb = self
123+ . inner
124+ . as_mut ( )
125+ . ok_or_else ( || new_error ! ( "WasmSandbox is None" ) ) ?;
126+ sb. restore ( snapshot) ?;
127+
128+ self . finalize_module_load ( )
129+ }
130+
100131 /// Load a Wasm module that is currently present in a buffer in
101132 /// host memory, by mapping the host memory directly into the
102133 /// sandbox.
@@ -114,6 +145,7 @@ impl WasmSandbox {
114145 base : * mut libc:: c_void ,
115146 len : usize ,
116147 ) -> Result < LoadedWasmSandbox > {
148+ self . restore_if_needed ( ) ?;
117149 let inner = self
118150 . inner
119151 . as_mut ( )
@@ -142,6 +174,7 @@ impl WasmSandbox {
142174 /// Before you can call guest functions in the sandbox, you must call
143175 /// this function and use the returned value to call guest functions.
144176 pub fn load_module_from_buffer ( mut self , buffer : & [ u8 ] ) -> Result < LoadedWasmSandbox > {
177+ self . restore_if_needed ( ) ?;
145178 let inner = self
146179 . inner
147180 . as_mut ( )
@@ -473,6 +506,46 @@ mod tests {
473506 }
474507 }
475508
509+ #[ test]
510+ fn test_load_from_snapshot ( ) {
511+ let mut sandbox = SandboxBuilder :: new ( ) . build ( ) . unwrap ( ) ;
512+ sandbox
513+ . register (
514+ "GetTimeSinceBootMicrosecond" ,
515+ get_time_since_boot_microsecond,
516+ )
517+ . unwrap ( ) ;
518+ let sb = sandbox. load_runtime ( ) . unwrap ( ) ;
519+
520+ let helloworld_wasm = get_test_file_path ( "HelloWorld.aot" ) . unwrap ( ) ;
521+ let runwasm_wasm = get_test_file_path ( "RunWasm.aot" ) . unwrap ( ) ;
522+
523+ // load one module, and make sure that a function in it
524+ // can be called
525+ let mut lb1 = sb. load_module ( helloworld_wasm) . unwrap ( ) ;
526+ let result: i32 = lb1
527+ . call_guest_function ( "HelloWorld" , "Message from Rust Test" . to_string ( ) )
528+ . unwrap ( ) ;
529+ assert_eq ! ( result, 0 ) ;
530+ let snapshot = lb1. snapshot ( ) . unwrap ( ) ;
531+
532+ // load another module, and make sure that a function in
533+ // it can be called
534+ let sb = lb1. unload_module ( ) . unwrap ( ) ;
535+ let mut lb2 = sb. load_module ( runwasm_wasm) . unwrap ( ) ;
536+ let result: i32 = lb2. call_guest_function ( "CalcFib" , 10i32 ) . unwrap ( ) ;
537+ assert_eq ! ( result, 55 ) ;
538+
539+ // reload the first module via snapshot, and make sure the
540+ // original function can be called again
541+ let sb = lb2. unload_module ( ) . unwrap ( ) ;
542+ let mut lb3 = sb. load_from_snapshot ( snapshot) . unwrap ( ) ;
543+ let result: i32 = lb3
544+ . call_guest_function ( "HelloWorld" , "Message from Rust Test" . to_string ( ) )
545+ . unwrap ( ) ;
546+ assert_eq ! ( result, 0 ) ;
547+ }
548+
476549 #[ test]
477550 fn test_load_module_buffer ( ) {
478551 let sandboxes = get_test_wasm_sandboxes ( ) . unwrap ( ) ;
0 commit comments