Merge master into feature/llvm-backend

This commit is contained in:
Lachlan Sneff
2019-02-14 15:47:28 -08:00
55 changed files with 815 additions and 1693 deletions

View File

@ -32,10 +32,10 @@ impl<'env, 'module, 'isa> FuncEnv<'env, 'module, 'isa> {
let mut signature = self.env.signatures[Converter(clif_sig_index).into()].clone();
// Add the vmctx parameter type to it
signature.params.push(ir::AbiParam::special(
self.pointer_type(),
ir::ArgumentPurpose::VMContext,
));
signature.params.insert(
0,
ir::AbiParam::special(self.pointer_type(), ir::ArgumentPurpose::VMContext),
);
// Return signature
signature
@ -461,8 +461,8 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> {
// Build a value list for the indirect call instruction containing the call_args
// and the vmctx parameter.
let mut args = Vec::with_capacity(call_args.len() + 1);
args.extend(call_args.iter().cloned());
args.push(vmctx_ptr);
args.extend(call_args.iter().cloned());
Ok(pos.ins().call_indirect(sig_ref, func_ptr, &args))
}
@ -487,8 +487,8 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> {
.expect("missing vmctx parameter");
let mut args = Vec::with_capacity(call_args.len() + 1);
args.extend(call_args.iter().cloned());
args.push(vmctx);
args.extend(call_args.iter().cloned());
Ok(pos.ins().call(callee, &args))
}
@ -534,8 +534,8 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> {
let sig_ref = pos.func.dfg.ext_funcs[callee].signature;
let mut args = Vec::with_capacity(call_args.len() + 1);
args.extend(call_args.iter().cloned());
args.push(imported_vmctx_addr);
args.extend(call_args.iter().cloned());
Ok(pos
.ins()
@ -561,9 +561,9 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> {
let signature = pos.func.import_signature(ir::Signature {
call_conv: self.target_config().default_call_conv,
params: vec![
ir::AbiParam::new(ir::types::I32),
ir::AbiParam::new(ir::types::I32),
ir::AbiParam::special(self.pointer_type(), ir::ArgumentPurpose::VMContext),
ir::AbiParam::new(ir::types::I32),
ir::AbiParam::new(ir::types::I32),
],
returns: vec![ir::AbiParam::new(ir::types::I32)],
});
@ -607,7 +607,7 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> {
let call_inst = pos
.ins()
.call(mem_grow_func, &[const_mem_index, by_value, vmctx]);
.call(mem_grow_func, &[vmctx, const_mem_index, by_value]);
Ok(*pos.func.dfg.inst_results(call_inst).first().unwrap())
}
@ -626,8 +626,8 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> {
let signature = pos.func.import_signature(ir::Signature {
call_conv: self.target_config().default_call_conv,
params: vec![
ir::AbiParam::new(ir::types::I32),
ir::AbiParam::special(self.pointer_type(), ir::ArgumentPurpose::VMContext),
ir::AbiParam::new(ir::types::I32),
],
returns: vec![ir::AbiParam::new(ir::types::I32)],
});
@ -668,7 +668,7 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> {
.special_param(ir::ArgumentPurpose::VMContext)
.expect("missing vmctx parameter");
let call_inst = pos.ins().call(mem_grow_func, &[const_mem_index, vmctx]);
let call_inst = pos.ins().call(mem_grow_func, &[vmctx, const_mem_index]);
Ok(*pos.func.dfg.inst_results(call_inst).first().unwrap())
}

View File

@ -416,8 +416,8 @@ impl<'module, 'isa, 'data> ModuleEnvironment<'data> for ModuleEnv<'module, 'isa>
let signature = pos.func.import_signature(ir::Signature {
call_conv: self.target_config().default_call_conv,
params: vec![
ir::AbiParam::new(ir::types::I32),
ir::AbiParam::special(ir::types::I64, ir::ArgumentPurpose::VMContext),
ir::AbiParam::new(ir::types::I32),
],
returns: vec![],
});
@ -454,8 +454,8 @@ impl<'module, 'isa, 'data> ModuleEnvironment<'data> for ModuleEnv<'module, 'isa>
let signature = pos.func.import_signature(ir::Signature {
call_conv: self.target_config().default_call_conv,
params: vec![
ir::AbiParam::new(ir::types::I32),
ir::AbiParam::special(ir::types::I64, ir::ArgumentPurpose::VMContext),
ir::AbiParam::new(ir::types::I32),
],
returns: vec![],
});
@ -473,8 +473,8 @@ impl<'module, 'isa, 'data> ModuleEnvironment<'data> for ModuleEnv<'module, 'isa>
let signature = pos.func.import_signature(ir::Signature {
call_conv: self.target_config().default_call_conv,
params: vec![
ir::AbiParam::new(ir::types::I64),
ir::AbiParam::special(ir::types::I64, ir::ArgumentPurpose::VMContext),
ir::AbiParam::new(ir::types::I64),
],
returns: vec![],
});
@ -492,8 +492,8 @@ impl<'module, 'isa, 'data> ModuleEnvironment<'data> for ModuleEnv<'module, 'isa>
let signature = pos.func.import_signature(ir::Signature {
call_conv: self.target_config().default_call_conv,
params: vec![
ir::AbiParam::new(ir::types::F32),
ir::AbiParam::special(ir::types::I64, ir::ArgumentPurpose::VMContext),
ir::AbiParam::new(ir::types::F32),
],
returns: vec![],
});
@ -511,8 +511,8 @@ impl<'module, 'isa, 'data> ModuleEnvironment<'data> for ModuleEnv<'module, 'isa>
let signature = pos.func.import_signature(ir::Signature {
call_conv: self.target_config().default_call_conv,
params: vec![
ir::AbiParam::new(ir::types::F64),
ir::AbiParam::special(ir::types::I64, ir::ArgumentPurpose::VMContext),
ir::AbiParam::new(ir::types::F64),
],
returns: vec![],
});
@ -533,14 +533,14 @@ impl<'module, 'isa, 'data> ModuleEnvironment<'data> for ModuleEnv<'module, 'isa>
let func_index = pos.ins().iconst(ir::types::I32, func_index.index() as i64);
pos.ins().call(start_debug, &[func_index, vmctx]);
pos.ins().call(start_debug, &[vmctx, func_index]);
for param in new_ebb_params.iter().cloned() {
match pos.func.dfg.value_type(param) {
ir::types::I32 => pos.ins().call(i32_print, &[param, vmctx]),
ir::types::I64 => pos.ins().call(i64_print, &[param, vmctx]),
ir::types::F32 => pos.ins().call(f32_print, &[param, vmctx]),
ir::types::F64 => pos.ins().call(f64_print, &[param, vmctx]),
ir::types::I32 => pos.ins().call(i32_print, &[vmctx, param]),
ir::types::I64 => pos.ins().call(i64_print, &[vmctx, param]),
ir::types::F32 => pos.ins().call(f32_print, &[vmctx, param]),
ir::types::F64 => pos.ins().call(f64_print, &[vmctx, param]),
_ => unimplemented!(),
};
}

View File

@ -35,6 +35,13 @@ use wasmer_runtime_core::{
vm, vmcalls,
};
extern "C" {
#[cfg(not(target_os = "windows"))]
pub fn __rust_probestack();
#[cfg(all(target_os = "windows", target_pointer_width = "64"))]
pub fn __chkstk();
}
#[allow(dead_code)]
pub struct FuncResolverBuilder {
resolver: FuncResolver,
@ -215,7 +222,10 @@ impl FuncResolverBuilder {
LibCall::FloorF64 => libcalls::floorf64 as isize,
LibCall::TruncF64 => libcalls::truncf64 as isize,
LibCall::NearestF64 => libcalls::nearbyintf64 as isize,
LibCall::Probestack => libcalls::__rust_probestack as isize,
#[cfg(all(target_pointer_width = "64", target_os = "windows"))]
LibCall::Probestack => __chkstk as isize,
#[cfg(not(target_os = "windows"))]
LibCall::Probestack => __rust_probestack as isize,
},
RelocationType::Intrinsic(ref name) => match name.as_str() {
"i32print" => i32_print as isize,
@ -340,21 +350,21 @@ fn round_up(n: usize, multiple: usize) -> usize {
(n + multiple - 1) & !(multiple - 1)
}
extern "C" fn i32_print(n: i32) {
extern "C" fn i32_print(_ctx: &mut vm::Ctx, n: i32) {
print!(" i32: {},", n);
}
extern "C" fn i64_print(n: i64) {
extern "C" fn i64_print(_ctx: &mut vm::Ctx, n: i64) {
print!(" i64: {},", n);
}
extern "C" fn f32_print(n: f32) {
extern "C" fn f32_print(_ctx: &mut vm::Ctx, n: f32) {
print!(" f32: {},", n);
}
extern "C" fn f64_print(n: f64) {
extern "C" fn f64_print(_ctx: &mut vm::Ctx, n: f64) {
print!(" f64: {},", n);
}
extern "C" fn start_debug(func_index: u32) {
extern "C" fn start_debug(_ctx: &mut vm::Ctx, func_index: u32) {
print!("func ({}), args: [", func_index);
}
extern "C" fn end_debug() {
extern "C" fn end_debug(_ctx: &mut vm::Ctx) {
println!(" ]");
}

View File

@ -110,6 +110,7 @@ impl ProtectedCaller for Caller {
.lookup(sig_index)
.expect("that trampoline doesn't exist");
#[cfg(not(target_os = "windows"))]
call_protected(&self.handler_data, || unsafe {
// Leap of faith.
trampoline(
@ -120,6 +121,17 @@ impl ProtectedCaller for Caller {
);
})?;
// the trampoline is called from C on windows
#[cfg(target_os = "windows")]
call_protected(
&self.handler_data,
trampoline,
vmctx_ptr,
func_ptr,
param_vec.as_ptr(),
return_vec.as_mut_ptr(),
)?;
Ok(return_vec
.iter()
.zip(signature.returns().iter())

View File

@ -1,6 +1,116 @@
use crate::relocation::{TrapCode, TrapData};
use crate::signal::HandlerData;
use wasmer_runtime_core::error::RuntimeResult;
use crate::trampoline::Trampoline;
use std::cell::Cell;
use std::ffi::c_void;
use std::ptr;
use wasmer_runtime_core::vm::Ctx;
use wasmer_runtime_core::vm::Func;
use wasmer_runtime_core::{
error::{RuntimeError, RuntimeResult},
structures::TypedIndex,
types::{MemoryIndex, TableIndex},
};
use wasmer_win_exception_handler::CallProtectedData;
pub use wasmer_win_exception_handler::_call_protected;
use winapi::shared::minwindef::DWORD;
use winapi::um::minwinbase::{
EXCEPTION_ACCESS_VIOLATION, EXCEPTION_FLT_DENORMAL_OPERAND, EXCEPTION_FLT_DIVIDE_BY_ZERO,
EXCEPTION_FLT_INEXACT_RESULT, EXCEPTION_FLT_INVALID_OPERATION, EXCEPTION_FLT_OVERFLOW,
EXCEPTION_FLT_STACK_CHECK, EXCEPTION_FLT_UNDERFLOW, EXCEPTION_ILLEGAL_INSTRUCTION,
EXCEPTION_INT_DIVIDE_BY_ZERO, EXCEPTION_INT_OVERFLOW, EXCEPTION_STACK_OVERFLOW,
};
pub fn call_protected<T>(handler_data: &HandlerData, f: impl FnOnce() -> T) -> RuntimeResult<T> {
unimplemented!("TODO");
thread_local! {
pub static CURRENT_EXECUTABLE_BUFFER: Cell<*const c_void> = Cell::new(ptr::null());
}
pub fn call_protected(
handler_data: &HandlerData,
trampoline: Trampoline,
ctx: *mut Ctx,
func: *const Func,
param_vec: *const u64,
return_vec: *mut u64,
) -> RuntimeResult<()> {
// TODO: trap early
// user code error
// if let Some(msg) = super::TRAP_EARLY_DATA.with(|cell| cell.replace(None)) {
// return Err(RuntimeError::User { msg });
// }
let result = _call_protected(trampoline, ctx, func, param_vec, return_vec);
if let Ok(_) = result {
return Ok(());
}
let CallProtectedData {
code: signum,
exceptionAddress: exception_address,
instructionPointer: instruction_pointer,
} = result.unwrap_err();
if let Some(TrapData {
trapcode,
srcloc: _,
}) = handler_data.lookup(instruction_pointer as _)
{
Err(match signum as DWORD {
EXCEPTION_ACCESS_VIOLATION => RuntimeError::OutOfBoundsAccess {
memory: MemoryIndex::new(0),
addr: None,
},
EXCEPTION_ILLEGAL_INSTRUCTION => match trapcode {
TrapCode::BadSignature => RuntimeError::IndirectCallSignature {
table: TableIndex::new(0),
},
TrapCode::IndirectCallToNull => RuntimeError::IndirectCallToNull {
table: TableIndex::new(0),
},
TrapCode::HeapOutOfBounds => RuntimeError::OutOfBoundsAccess {
memory: MemoryIndex::new(0),
addr: None,
},
TrapCode::TableOutOfBounds => RuntimeError::TableOutOfBounds {
table: TableIndex::new(0),
},
_ => RuntimeError::Unknown {
msg: "unknown trap".to_string(),
},
},
EXCEPTION_STACK_OVERFLOW => RuntimeError::Unknown {
msg: "unknown trap".to_string(),
},
EXCEPTION_INT_DIVIDE_BY_ZERO => RuntimeError::IllegalArithmeticOperation,
EXCEPTION_INT_OVERFLOW => RuntimeError::IllegalArithmeticOperation,
_ => RuntimeError::Unknown {
msg: "unknown trap".to_string(),
},
}
.into())
} else {
let signal = match signum as DWORD {
EXCEPTION_FLT_DENORMAL_OPERAND
| EXCEPTION_FLT_DIVIDE_BY_ZERO
| EXCEPTION_FLT_INEXACT_RESULT
| EXCEPTION_FLT_INVALID_OPERATION
| EXCEPTION_FLT_OVERFLOW
| EXCEPTION_FLT_STACK_CHECK
| EXCEPTION_FLT_UNDERFLOW => "floating-point exception",
EXCEPTION_ILLEGAL_INSTRUCTION => "illegal instruction",
EXCEPTION_ACCESS_VIOLATION => "segmentation violation",
_ => "unkown trapped signal",
};
Err(RuntimeError::Unknown {
msg: format!("trap at {} - {}", exception_address, signal),
}
.into())
}
}
pub unsafe fn trigger_trap() -> ! {
// TODO
unimplemented!();
}

View File

@ -7,6 +7,7 @@ use cranelift_codegen::{
isa, Context,
};
use hashbrown::HashMap;
use std::ffi::c_void;
use std::{iter, mem};
use wasmer_runtime_core::{
backend::sys::{Memory, Protect},
@ -23,6 +24,9 @@ impl RelocSink for NullRelocSink {
fn reloc_jt(&mut self, _: u32, _: Reloc, _: ir::JumpTable) {}
}
pub type Trampoline =
unsafe extern "C" fn(*mut vm::Ctx, *const vm::Func, *const u64, *mut u64) -> c_void;
pub struct Trampolines {
memory: Memory,
offsets: HashMap<SigIndex, usize>,
@ -138,10 +142,7 @@ impl Trampolines {
}
}
pub fn lookup(
&self,
sig_index: SigIndex,
) -> Option<unsafe extern "C" fn(*mut vm::Ctx, *const vm::Func, *const u64, *mut u64)> {
pub fn lookup(&self, sig_index: SigIndex) -> Option<Trampoline> {
let offset = *self.offsets.get(&sig_index)?;
let ptr = unsafe { self.memory.as_ptr().add(offset) };
@ -169,6 +170,7 @@ fn generate_func(func_sig: &FuncSig) -> ir::Function {
let mut pos = FuncCursor::new(&mut func).at_first_insertion_point(entry_ebb);
let mut args_vec = Vec::with_capacity(func_sig.params().len() + 1);
args_vec.push(vmctx_ptr);
for (index, wasm_ty) in func_sig.params().iter().enumerate() {
let mem_flags = ir::MemFlags::trusted();
@ -180,7 +182,6 @@ fn generate_func(func_sig: &FuncSig) -> ir::Function {
);
args_vec.push(val);
}
args_vec.push(vmctx_ptr);
let call_inst = pos.ins().call_indirect(export_sig_ref, func_ptr, &args_vec);
@ -212,7 +213,9 @@ fn wasm_ty_to_clif(ty: Type) -> ir::types::Type {
}
fn generate_trampoline_signature() -> ir::Signature {
let mut sig = ir::Signature::new(isa::CallConv::SystemV);
let isa = super::get_isa();
let call_convention = isa.default_call_conv();
let mut sig = ir::Signature::new(call_convention);
let ptr_param = ir::AbiParam {
value_type: ir::types::I64,
@ -227,24 +230,25 @@ fn generate_trampoline_signature() -> ir::Signature {
}
fn generate_export_signature(func_sig: &FuncSig) -> ir::Signature {
let mut export_clif_sig = ir::Signature::new(isa::CallConv::SystemV);
let isa = super::get_isa();
let call_convention = isa.default_call_conv();
let mut export_clif_sig = ir::Signature::new(call_convention);
export_clif_sig.params = func_sig
.params()
.iter()
.map(|wasm_ty| ir::AbiParam {
value_type: wasm_ty_to_clif(*wasm_ty),
purpose: ir::ArgumentPurpose::Normal,
extension: ir::ArgumentExtension::None,
location: ir::ArgumentLoc::Unassigned,
})
.chain(iter::once(ir::AbiParam {
value_type: ir::types::I64,
purpose: ir::ArgumentPurpose::VMContext,
extension: ir::ArgumentExtension::None,
location: ir::ArgumentLoc::Unassigned,
}))
.collect();
let func_sig_iter = func_sig.params().iter().map(|wasm_ty| ir::AbiParam {
value_type: wasm_ty_to_clif(*wasm_ty),
purpose: ir::ArgumentPurpose::Normal,
extension: ir::ArgumentExtension::None,
location: ir::ArgumentLoc::Unassigned,
});
export_clif_sig.params = iter::once(ir::AbiParam {
value_type: ir::types::I64,
purpose: ir::ArgumentPurpose::VMContext,
extension: ir::ArgumentExtension::None,
location: ir::ArgumentLoc::Unassigned,
})
.chain(func_sig_iter)
.collect();
export_clif_sig.returns = func_sig
.returns()