diff --git a/lib/runtime-core/image-loading.s b/lib/runtime-core/image-loading.s index a664e2199..122c16505 100644 --- a/lib/runtime-core/image-loading.s +++ b/lib/runtime-core/image-loading.s @@ -20,7 +20,6 @@ popq %r12 popq %r13 popq %r14 popq %r15 -int $0x3 retq _run_on_wasm_stack.returning: diff --git a/lib/runtime-core/src/state.rs b/lib/runtime-core/src/state.rs index 1d8c24d10..f4b202990 100644 --- a/lib/runtime-core/src/state.rs +++ b/lib/runtime-core/src/state.rs @@ -74,10 +74,17 @@ pub struct WasmFunctionStateDump { } #[derive(Clone, Debug, Serialize, Deserialize)] -pub struct InstanceImage { +pub struct ExecutionStateImage { pub frames: Vec, } +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct InstanceImage { + pub memory: Option>, + pub globals: Vec, + pub execution_state: ExecutionStateImage, +} + impl ModuleStateMap { fn lookup_call_ip(&self, ip: usize, base: usize) -> Option<(&FunctionStateMap, MachineState)> { if ip < base || ip - base >= self.total_size { @@ -218,8 +225,8 @@ impl MachineStateDiff { } } -impl InstanceImage { - pub fn from_bytes(input: &[u8]) -> Option { +impl ExecutionStateImage { + pub fn from_bytes(input: &[u8]) -> Option { use bincode::deserialize; match deserialize(input) { Ok(x) => Some(x), @@ -235,6 +242,8 @@ pub mod x64 { } use super::*; use crate::vm::Ctx; + use crate::types::LocalGlobalIndex; + use crate::structures::TypedIndex; pub fn new_machine_state() -> MachineState { MachineState { @@ -276,7 +285,7 @@ pub mod x64 { let local_functions_vec: Vec<&FunctionStateMap> = msm.local_functions.iter().map(|(k, v)| v).collect(); // Bottom to top - for f in image.frames.iter().rev() { + for f in image.execution_state.frames.iter().rev() { let fsm = local_functions_vec[f.local_function_id]; let call_begin_offset = fsm.wasm_offset_to_target_offset[f.wasm_inst_offset]; let (after_call_inst, diff_id) = fsm.call_offsets.range((Included(&call_begin_offset), Unbounded)).next().map(|(k, v)| (*k, *v)).expect("instruction offset not found in call offsets"); @@ -389,9 +398,50 @@ pub mod x64 { stack_offset -= 1; stack[stack_offset] = stack.as_ptr().offset(last_stack_offset as isize) as usize as u64; // rbp + if let Some(ref memory) = image.memory { + assert!(vmctx.internal.memory_bound <= memory.len()); + + if vmctx.internal.memory_bound < memory.len() { + let grow: unsafe extern "C" fn (ctx: &mut Ctx, memory_index: usize, delta: usize) = ::std::mem::transmute((*vmctx.internal.intrinsics).memory_grow); + grow(vmctx, 0, (memory.len() - vmctx.internal.memory_bound) / 65536); + assert_eq!(vmctx.internal.memory_bound, memory.len()); + } + + ::std::slice::from_raw_parts_mut(vmctx.internal.memory_base, vmctx.internal.memory_bound).copy_from_slice(memory); + } + + let globals_len = (*vmctx.module).info.globals.len(); + for i in 0..globals_len { + (*(*vmctx.local_backing).globals[LocalGlobalIndex::new(i)].vm_local_global()).data = image.globals[i]; + } + run_on_wasm_stack(stack.as_mut_ptr().offset(stack.len() as isize), stack.as_mut_ptr().offset(stack_offset as isize)) } + pub fn build_instance_image( + vmctx: &mut Ctx, + execution_state: ExecutionStateImage, + ) -> InstanceImage { + unsafe { + let memory = if vmctx.internal.memory_base.is_null() { + None + } else { + Some(::std::slice::from_raw_parts(vmctx.internal.memory_base, vmctx.internal.memory_bound).to_vec()) + }; + + // FIXME: Imported globals + let globals_len = (*vmctx.module).info.globals.len(); + let globals: Vec = (0..globals_len).map(|i| (*vmctx.local_backing).globals[LocalGlobalIndex::new(i)].get().to_u64()).collect(); + + InstanceImage { + memory: memory, + globals: globals, + execution_state: execution_state, + } + } + + } + #[warn(unused_variables)] pub unsafe fn read_stack( msm: &ModuleStateMap, @@ -399,7 +449,7 @@ pub mod x64 { mut stack: *const u64, initially_known_registers: [Option; 24], mut initial_address: Option, - ) -> InstanceImage { + ) -> ExecutionStateImage { let mut known_registers: [Option; 24] = initially_known_registers; let mut results: Vec = vec![]; @@ -414,7 +464,7 @@ pub mod x64 { .or_else(|| msm.lookup_trappable_ip(ret_addr as usize, code_base)) { Some(x) => x, - _ => return InstanceImage { + _ => return ExecutionStateImage { frames: results, } }; @@ -444,6 +494,8 @@ pub mod x64 { MachineValue::WasmStack(idx) => { if let Some(v) = known_registers[i] { wasm_stack[idx] = Some(v); + } else { + eprintln!("BUG: Register {} for WebAssembly stack slot {} has unknown value.", i, idx); } } MachineValue::WasmLocal(idx) => { diff --git a/lib/runtime-core/src/suspend.rs b/lib/runtime-core/src/suspend.rs index ccf768065..a3ecf36a6 100644 --- a/lib/runtime-core/src/suspend.rs +++ b/lib/runtime-core/src/suspend.rs @@ -58,7 +58,7 @@ pub fn patch_import_object(x: &mut ImportObject, config: SuspendConfig) { } unsafe extern "C" fn suspend(ctx: &mut Ctx, config_ptr_raw: *const CallContext, mut stack: *const u64) { - use crate::state::x64::{X64Register, GPR, read_stack}; + use crate::state::x64::{X64Register, GPR, read_stack, build_instance_image}; { let config = &*(config_ptr_raw as *const SuspendConfig); @@ -84,12 +84,12 @@ unsafe extern "C" fn suspend(ctx: &mut Ctx, config_ptr_raw: *const CallContext, known_registers[X64Register::GPR(GPR::R12).to_index().0] = Some(r12); known_registers[X64Register::GPR(GPR::RBX).to_index().0] = Some(rbx); - let image = read_stack(&msm, code_base, stack, known_registers, None); + let es_image = read_stack(&msm, code_base, stack, known_registers, None); + let image = build_instance_image(ctx, es_image); let image_bin = serialize(&image).unwrap(); let mut f = File::create(&config.image_path).unwrap(); f.write_all(&image_bin).unwrap(); - println!("{:?}", image); } - panic!("suspended"); + ::std::process::exit(0); } diff --git a/lib/runtime-core/src/vm.rs b/lib/runtime-core/src/vm.rs index a84551449..1bba38801 100644 --- a/lib/runtime-core/src/vm.rs +++ b/lib/runtime-core/src/vm.rs @@ -38,8 +38,8 @@ pub struct Ctx { /// These are pointers to things that are known to be owned /// by the owning `Instance`. - local_backing: *mut LocalBacking, - import_backing: *mut ImportBacking, + pub local_backing: *mut LocalBacking, + pub import_backing: *mut ImportBacking, pub module: *const ModuleInner, //// This is intended to be user-supplied, per-instance diff --git a/src/bin/wasmer.rs b/src/bin/wasmer.rs index 81d3ecaee..992fc5035 100644 --- a/src/bin/wasmer.rs +++ b/src/bin/wasmer.rs @@ -112,11 +112,11 @@ struct Run { )] loader: Option, - #[structopt(long = "suspend-to")] - suspend_to: Option, + #[structopt(long = "suspend-file")] + suspend_file: Option, - #[structopt(long = "restore-from")] - restore_from: Option, + #[structopt(long = "resume")] + resume: bool, #[structopt(long = "command-name", hidden = true)] command_name: Option, @@ -508,7 +508,7 @@ fn execute_wasm(options: &Run) -> Result<(), String> { mapped_dirs, ); - if let Some(ref name) = options.suspend_to { + if let Some(ref name) = options.suspend_file { use wasmer_runtime_core::suspend::{SuspendConfig, patch_import_object}; patch_import_object(&mut import_object, SuspendConfig { image_path: name.clone(), @@ -519,35 +519,39 @@ fn execute_wasm(options: &Run) -> Result<(), String> { .instantiate(&import_object) .map_err(|e| format!("Can't instantiate module: {:?}", e))?; - if let Some(ref name) = options.restore_from { - use wasmer_singlepass_backend::protect_unix::call_protected; - use wasmer_runtime_core::state::x64::invoke_call_return_on_stack_raw_image; + if let Some(ref name) = options.suspend_file { + if options.resume { + use wasmer_singlepass_backend::protect_unix::call_protected; + use wasmer_runtime_core::state::x64::invoke_call_return_on_stack_raw_image; - let mut file = File::open(name).expect("cannot open image file"); - let mut image: Vec = vec![]; - file.read_to_end(&mut image).unwrap(); + let mut file = File::open(name).expect("cannot open image file"); + let mut image: Vec = vec![]; + file.read_to_end(&mut image).unwrap(); - let msm = instance.module.runnable_module.get_module_state_map().unwrap(); - let code_base = instance.module.runnable_module.get_code().unwrap().as_ptr() as usize; - call_protected(|| { - unsafe { invoke_call_return_on_stack_raw_image(&msm, code_base, &image, instance.context_mut()); } - }).map_err(|_| "ERROR").unwrap(); - } else { - let start: Func<(), ()> = instance.func("_start").map_err(|e| format!("{:?}", e))?; + let msm = instance.module.runnable_module.get_module_state_map().unwrap(); + let code_base = instance.module.runnable_module.get_code().unwrap().as_ptr() as usize; + call_protected(|| { + unsafe { invoke_call_return_on_stack_raw_image(&msm, code_base, &image, instance.context_mut()); } + }).map_err(|_| "ERROR").unwrap(); - let result = start.call(); + return Ok(()) + } + } - if let Err(ref err) = result { - match err { - RuntimeError::Trap { msg } => panic!("wasm trap occured: {}", msg), - RuntimeError::Error { data } => { - if let Some(error_code) = data.downcast_ref::() { - std::process::exit(error_code.code as i32) - } + let start: Func<(), ()> = instance.func("_start").map_err(|e| format!("{:?}", e))?; + + let result = start.call(); + + if let Err(ref err) = result { + match err { + RuntimeError::Trap { msg } => panic!("wasm trap occured: {}", msg), + RuntimeError::Error { data } => { + if let Some(error_code) = data.downcast_ref::() { + std::process::exit(error_code.code as i32) } } - panic!("error: {:?}", err) } + panic!("error: {:?}", err) } } else { let import_object = wasmer_runtime_core::import::ImportObject::new();