Files
wasmer/lib/runtime-core/src/suspend.rs
2019-06-26 11:28:46 +08:00

109 lines
3.2 KiB
Rust

use crate::import::{ImportObject, Namespace};
use crate::trampoline::{CallContext, TrampolineBuffer, TrampolineBufferBuilder};
use crate::vm::Ctx;
use bincode::serialize;
use std::ffi::c_void;
use std::fs::File;
use std::io::Write;
use std::rc::Rc;
pub struct SuspendConfig {
pub image_path: String,
}
struct ImportContext {
next: Option<(*mut c_void, fn(*mut c_void))>,
trampolines: Rc<TrampolineBuffer>,
config: Rc<SuspendConfig>,
}
impl ImportContext {
fn new(trampolines: Rc<TrampolineBuffer>, config: Rc<SuspendConfig>) -> ImportContext {
ImportContext {
trampolines,
next: None,
config,
}
}
}
fn destroy_import_context(x: *mut c_void) {
unsafe {
let ctx = Box::from_raw(x as *mut ImportContext);
if let Some(x) = ctx.next {
(x.1)(x.0);
}
}
}
pub fn patch_import_object(x: &mut ImportObject, config: SuspendConfig) {
let config = Rc::new(config);
let mut builder = TrampolineBufferBuilder::new();
let config_ptr: &SuspendConfig = &*config;
let idx = builder.add_context_rsp_state_preserving_trampoline(
suspend,
config_ptr as *const SuspendConfig as *const CallContext,
);
let trampolines = builder.build();
let suspend_indirect: fn(&mut Ctx) =
unsafe { ::std::mem::transmute(trampolines.get_trampoline(idx)) };
let trampolines = Rc::new(trampolines);
// FIXME: Memory leak!
::std::mem::forget(ImportContext::new(trampolines.clone(), config.clone()));
let mut ns = Namespace::new();
ns.insert("suspend", func!(suspend_indirect));
x.register("wasmer_suspend", ns);
}
unsafe extern "C" fn suspend(
ctx: &mut Ctx,
config_ptr_raw: *const CallContext,
mut stack: *const u64,
) {
use crate::state::x64::{build_instance_image, read_stack, X64Register, GPR};
{
let config = &*(config_ptr_raw as *const SuspendConfig);
let msm = (*ctx.module)
.runnable_module
.get_module_state_map()
.unwrap();
let code_base = (*ctx.module).runnable_module.get_code().unwrap().as_ptr() as usize;
let mut known_registers: [Option<u64>; 24] = [None; 24];
let r15 = *stack;
let r14 = *stack.offset(1);
let r13 = *stack.offset(2);
let r12 = *stack.offset(3);
let rbx = *stack.offset(4);
stack = stack.offset(5);
known_registers[X64Register::GPR(GPR::R15).to_index().0] = Some(r15);
known_registers[X64Register::GPR(GPR::R14).to_index().0] = Some(r14);
known_registers[X64Register::GPR(GPR::R13).to_index().0] = Some(r13);
known_registers[X64Register::GPR(GPR::R12).to_index().0] = Some(r12);
known_registers[X64Register::GPR(GPR::RBX).to_index().0] = Some(rbx);
let es_image = read_stack(&msm, code_base, stack, known_registers, None);
{
use colored::*;
eprintln!("\n{}", "Suspending instance.".green().bold());
}
es_image.print_backtrace_if_needed();
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();
}
::std::process::exit(0);
}