mirror of
https://github.com/fluencelabs/wasmer
synced 2025-06-24 06:01:33 +00:00
Merge master into feature/llvm-backend
This commit is contained in:
@ -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())
|
||||
}
|
||||
|
@ -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!(),
|
||||
};
|
||||
}
|
||||
|
@ -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!(" ]");
|
||||
}
|
||||
|
@ -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())
|
||||
|
@ -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!();
|
||||
}
|
||||
|
@ -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()
|
||||
|
Reference in New Issue
Block a user