Swap code lazily when tiering up from singlepass to LLVM.

Does not handle long-running functions, but should work at least.
This commit is contained in:
losfair
2019-08-09 04:26:17 +08:00
parent 0d604b754b
commit c1619026d5
10 changed files with 350 additions and 94 deletions

View File

@ -151,6 +151,10 @@ pub trait RunnableModule: Send + Sync {
None
}
unsafe fn patch_local_function(&self, _idx: usize, _target_address: usize) -> bool {
false
}
/// A wasm trampoline contains the necessary data to dynamically call an exported wasm function.
/// Given a particular signature index, we are returned a trampoline that is matched with that
/// signature and an invoke function that can call the trampoline.
@ -167,6 +171,11 @@ pub trait RunnableModule: Send + Sync {
fn get_offsets(&self) -> Option<Vec<usize>> {
None
}
/// Returns the beginning offsets of all local functions.
fn get_local_function_offsets(&self) -> Option<Vec<usize>> {
None
}
}
pub trait CacheGen: Send + Sync {

View File

@ -17,7 +17,7 @@ use nix::sys::signal::{
SIGSEGV, SIGTRAP,
};
use std::any::Any;
use std::cell::UnsafeCell;
use std::cell::{Cell, UnsafeCell};
use std::ffi::c_void;
use std::process;
use std::sync::atomic::{AtomicBool, Ordering};
@ -41,6 +41,7 @@ struct UnwindInfo {
thread_local! {
static UNWIND: UnsafeCell<Option<UnwindInfo>> = UnsafeCell::new(None);
static CURRENT_CTX: UnsafeCell<*mut vm::Ctx> = UnsafeCell::new(::std::ptr::null_mut());
static WAS_SIGINT_TRIGGERED: Cell<bool> = Cell::new(false);
}
struct InterruptSignalMem(*mut u8);
@ -69,6 +70,10 @@ lazy_static! {
}
static INTERRUPT_SIGNAL_DELIVERED: AtomicBool = AtomicBool::new(false);
pub fn was_sigint_triggered_fault() -> bool {
WAS_SIGINT_TRIGGERED.with(|x| x.get())
}
pub unsafe fn with_ctx<R, F: FnOnce() -> R>(ctx: *mut vm::Ctx, cb: F) -> R {
let addr = CURRENT_CTX.with(|x| x.get());
let old = *addr;
@ -82,6 +87,17 @@ pub unsafe fn get_wasm_interrupt_signal_mem() -> *mut u8 {
INTERRUPT_SIGNAL_MEM.0
}
pub unsafe fn set_wasm_interrupt_on_ctx(ctx: *mut vm::Ctx) {
if mprotect(
(&*ctx).internal.interrupt_signal_mem as _,
INTERRUPT_SIGNAL_MEM_SIZE,
PROT_NONE,
) < 0
{
panic!("cannot set PROT_NONE on signal mem");
}
}
pub unsafe fn set_wasm_interrupt() {
let mem: *mut u8 = INTERRUPT_SIGNAL_MEM.0;
if mprotect(mem as _, INTERRUPT_SIGNAL_MEM_SIZE, PROT_NONE) < 0 {
@ -188,7 +204,7 @@ extern "C" fn signal_trap_handler(
let should_unwind = allocate_and_run(TRAP_STACK_SIZE, || {
let mut is_suspend_signal = false;
println!("SIGNAL: {:?} {:?}", Signal::from_c_int(signum), fault.faulting_addr);
WAS_SIGINT_TRIGGERED.with(|x| x.set(false));
match Signal::from_c_int(signum) {
Ok(SIGTRAP) => {
@ -215,7 +231,9 @@ extern "C" fn signal_trap_handler(
if fault.faulting_addr as usize == get_wasm_interrupt_signal_mem() as usize {
is_suspend_signal = true;
clear_wasm_interrupt();
INTERRUPT_SIGNAL_DELIVERED.store(false, Ordering::SeqCst);
if INTERRUPT_SIGNAL_DELIVERED.swap(false, Ordering::SeqCst) {
WAS_SIGINT_TRIGGERED.with(|x| x.set(true));
}
}
}
_ => {}

View File

@ -102,13 +102,20 @@ pub struct CodeMemory {
size: usize,
}
unsafe impl Send for CodeMemory {}
unsafe impl Sync for CodeMemory {}
#[cfg(not(unix))]
impl CodeMemory {
pub fn new(_size: usize) -> CodeMemory {
unimplemented!();
}
pub fn make_executable(&mut self) {
pub fn make_executable(&self) {
unimplemented!();
}
pub fn make_writable(&self) {
unimplemented!();
}
}
@ -139,11 +146,17 @@ impl CodeMemory {
}
}
pub fn make_executable(&mut self) {
pub fn make_executable(&self) {
if unsafe { mprotect(self.ptr as _, self.size, PROT_READ | PROT_EXEC) } != 0 {
panic!("cannot set code memory to executable");
}
}
pub fn make_writable(&self) {
if unsafe { mprotect(self.ptr as _, self.size, PROT_READ | PROT_WRITE) } != 0 {
panic!("cannot set code memory to writable");
}
}
}
#[cfg(unix)]

View File

@ -493,21 +493,21 @@ pub mod x64 {
stack[stack_offset] |= v;
}
},
MachineValue::WasmLocal(x) => {
match fsm.locals[x] {
WasmAbstractValue::Const(x) => {
assert!(x <= ::std::u32::MAX as u64);
stack[stack_offset] |= x;
}
WasmAbstractValue::Runtime => {
let v = f.locals[x].unwrap();
assert!(v <= ::std::u32::MAX as u64);
stack[stack_offset] |= v;
}
MachineValue::WasmLocal(x) => match fsm.locals[x] {
WasmAbstractValue::Const(x) => {
assert!(x <= ::std::u32::MAX as u64);
stack[stack_offset] |= x;
}
}
WasmAbstractValue::Runtime => {
let v = f.locals[x].unwrap();
assert!(v <= ::std::u32::MAX as u64);
stack[stack_offset] |= v;
}
},
MachineValue::VmctxDeref(ref seq) => {
stack[stack_offset] |= compute_vmctx_deref(vmctx as *const Ctx, seq) & (::std::u32::MAX as u64);
stack[stack_offset] |=
compute_vmctx_deref(vmctx as *const Ctx, seq)
& (::std::u32::MAX as u64);
}
MachineValue::Undefined => {}
_ => unimplemented!("TwoHalves.0"),
@ -524,21 +524,22 @@ pub mod x64 {
stack[stack_offset] |= v << 32;
}
},
MachineValue::WasmLocal(x) => {
match fsm.locals[x] {
WasmAbstractValue::Const(x) => {
assert!(x <= ::std::u32::MAX as u64);
stack[stack_offset] |= x << 32;
}
WasmAbstractValue::Runtime => {
let v = f.locals[x].unwrap();
assert!(v <= ::std::u32::MAX as u64);
stack[stack_offset] |= v << 32;
}
MachineValue::WasmLocal(x) => match fsm.locals[x] {
WasmAbstractValue::Const(x) => {
assert!(x <= ::std::u32::MAX as u64);
stack[stack_offset] |= x << 32;
}
}
WasmAbstractValue::Runtime => {
let v = f.locals[x].unwrap();
assert!(v <= ::std::u32::MAX as u64);
stack[stack_offset] |= v << 32;
}
},
MachineValue::VmctxDeref(ref seq) => {
stack[stack_offset] |= (compute_vmctx_deref(vmctx as *const Ctx, seq) & (::std::u32::MAX as u64)) << 32;
stack[stack_offset] |=
(compute_vmctx_deref(vmctx as *const Ctx, seq)
& (::std::u32::MAX as u64))
<< 32;
}
MachineValue::Undefined => {}
_ => unimplemented!("TwoHalves.1"),
@ -583,7 +584,6 @@ pub mod x64 {
stack_offset -= 1;
stack[stack_offset] = (code_base + activate_offset) as u64; // return address
println!("activating at {:?}", (code_base + activate_offset) as *const u8);
}
stack_offset -= 1;
@ -694,7 +694,6 @@ pub mod x64 {
catch_unsafe_unwind(
|| {
::std::intrinsics::breakpoint();
run_on_alternative_stack(
stack.as_mut_ptr().offset(stack.len() as isize),
stack.as_mut_ptr().offset(stack_offset as isize),