Merge branch 'master' into feature/debug-prototype2

This commit is contained in:
Mark McCaskey
2020-02-19 16:13:35 -08:00
committed by GitHub
95 changed files with 6423 additions and 790 deletions

View File

@ -13,6 +13,7 @@ use crate::{
module::ModuleInfo,
sys::Memory,
};
use std::fmt;
use std::{any::Any, ptr::NonNull};
use std::collections::HashMap;
@ -109,9 +110,28 @@ impl BackendCompilerConfig {
pub struct CompilerConfig {
/// Symbol information generated from emscripten; used for more detailed debug messages
pub symbol_map: Option<HashMap<u32, String>>,
/// How to make the decision whether to emit bounds checks for memory accesses.
pub memory_bound_check_mode: MemoryBoundCheckMode,
/// Whether to generate explicit native stack checks against `stack_lower_bound` in `InternalCtx`.
///
/// Usually it's adequate to use hardware memory protection mechanisms such as `mprotect` on Unix to
/// prevent stack overflow. But for low-level environments, e.g. the kernel, faults are generally
/// not expected and relying on hardware memory protection would add too much complexity.
pub enforce_stack_check: bool,
/// Whether to enable state tracking. Necessary for managed mode.
pub track_state: bool,
/// Whether to enable full preemption checkpoint generation.
///
/// This inserts checkpoints at critical locations such as loop backedges and function calls,
/// allowing preemptive unwinding/task switching.
///
/// When enabled there can be a small amount of runtime performance overhead.
pub full_preemption: bool,
pub features: Features,
// Target info. Presently only supported by LLVM.
@ -150,13 +170,36 @@ impl ExceptionTable {
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)]
pub enum ExceptionCode {
/// An `unreachable` opcode was executed.
Unreachable,
Unreachable = 0,
/// Call indirect incorrect signature trap.
IncorrectCallIndirectSignature = 1,
/// Memory out of bounds trap.
MemoryOutOfBounds = 2,
/// Call indirect out of bounds trap.
CallIndirectOOB = 3,
/// An arithmetic exception, e.g. divided by zero.
Arithmetic,
IllegalArithmetic = 4,
/// Misaligned atomic access trap.
MisalignedAtomicAccess = 5,
}
/// Memory access exception, e.g. misaligned/out-of-bound read/write.
Memory,
impl fmt::Display for ExceptionCode {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"{}",
match self {
ExceptionCode::Unreachable => "unreachable",
ExceptionCode::IncorrectCallIndirectSignature => {
"incorrect `call_indirect` signature"
}
ExceptionCode::MemoryOutOfBounds => "memory out-of-bounds access",
ExceptionCode::CallIndirectOOB => "`call_indirect` out-of-bounds",
ExceptionCode::IllegalArithmetic => "illegal arithmetic operation",
ExceptionCode::MisalignedAtomicAccess => "misaligned atomic access",
}
)
}
}
pub trait Compiler {

View File

@ -179,18 +179,7 @@ impl std::error::Error for LinkError {}
/// The main way to do this is `Instance.call`.
///
/// Comparing two `RuntimeError`s always evaluates to false.
pub enum RuntimeError {
/// Trap.
Trap {
/// Trap message.
msg: Box<str>,
},
/// Error.
Error {
/// Error data.
data: Box<dyn Any + Send>,
},
}
pub struct RuntimeError(pub Box<dyn Any + Send>);
impl PartialEq for RuntimeError {
fn eq(&self, _other: &RuntimeError) -> bool {
@ -200,21 +189,15 @@ impl PartialEq for RuntimeError {
impl std::fmt::Display for RuntimeError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
RuntimeError::Trap { ref msg } => {
write!(f, "WebAssembly trap occurred during runtime: {}", msg)
}
RuntimeError::Error { data } => {
if let Some(s) = data.downcast_ref::<String>() {
write!(f, "\"{}\"", s)
} else if let Some(s) = data.downcast_ref::<&str>() {
write!(f, "\"{}\"", s)
} else if let Some(exc_code) = data.downcast_ref::<ExceptionCode>() {
write!(f, "Caught exception of type \"{:?}\".", exc_code)
} else {
write!(f, "unknown error")
}
}
let data = &*self.0;
if let Some(s) = data.downcast_ref::<String>() {
write!(f, "\"{}\"", s)
} else if let Some(s) = data.downcast_ref::<&str>() {
write!(f, "\"{}\"", s)
} else if let Some(exc_code) = data.downcast_ref::<ExceptionCode>() {
write!(f, "Caught exception of type \"{:?}\".", exc_code)
} else {
write!(f, "unknown error")
}
}
}

View File

@ -500,6 +500,249 @@ impl FaultInfo {
}
}
#[cfg(all(target_os = "freebsd", target_arch = "aarch64"))]
/// Get fault info from siginfo and ucontext.
pub unsafe fn get_fault_info(siginfo: *const c_void, ucontext: *mut c_void) -> FaultInfo {
#[repr(C)]
pub struct ucontext_t {
uc_sigmask: libc::sigset_t,
uc_mcontext: mcontext_t,
uc_link: *mut ucontext_t,
uc_stack: libc::stack_t,
uc_flags: i32,
__spare__: [i32; 4],
}
#[repr(C)]
pub struct gpregs {
gp_x: [u64; 30],
gp_lr: u64,
gp_sp: u64,
gp_elr: u64,
gp_spsr: u64,
gp_pad: i32,
};
#[repr(C)]
pub struct fpregs {
fp_q: [u128; 32],
fp_sr: u32,
fp_cr: u32,
fp_flags: i32,
fp_pad: i32,
};
#[repr(C)]
pub struct mcontext_t {
mc_gpregs: gpregs,
mc_fpregs: fpregs,
mc_flags: i32,
mc_pad: i32,
mc_spare: [u64; 8],
}
let siginfo = siginfo as *const siginfo_t;
let si_addr = (*siginfo).si_addr;
let ucontext = ucontext as *mut ucontext_t;
let gregs = &(*ucontext).uc_mcontext.mc_gpregs;
let mut known_registers: [Option<u64>; 32] = [None; 32];
known_registers[X64Register::GPR(GPR::R15).to_index().0] = Some(gregs.gp_x[15] as _);
known_registers[X64Register::GPR(GPR::R14).to_index().0] = Some(gregs.gp_x[14] as _);
known_registers[X64Register::GPR(GPR::R13).to_index().0] = Some(gregs.gp_x[13] as _);
known_registers[X64Register::GPR(GPR::R12).to_index().0] = Some(gregs.gp_x[12] as _);
known_registers[X64Register::GPR(GPR::R11).to_index().0] = Some(gregs.gp_x[11] as _);
known_registers[X64Register::GPR(GPR::R10).to_index().0] = Some(gregs.gp_x[10] as _);
known_registers[X64Register::GPR(GPR::R9).to_index().0] = Some(gregs.gp_x[9] as _);
known_registers[X64Register::GPR(GPR::R8).to_index().0] = Some(gregs.gp_x[8] as _);
known_registers[X64Register::GPR(GPR::RSI).to_index().0] = Some(gregs.gp_x[6] as _);
known_registers[X64Register::GPR(GPR::RDI).to_index().0] = Some(gregs.gp_x[7] as _);
known_registers[X64Register::GPR(GPR::RDX).to_index().0] = Some(gregs.gp_x[2] as _);
known_registers[X64Register::GPR(GPR::RCX).to_index().0] = Some(gregs.gp_x[1] as _);
known_registers[X64Register::GPR(GPR::RBX).to_index().0] = Some(gregs.gp_x[3] as _);
known_registers[X64Register::GPR(GPR::RAX).to_index().0] = Some(gregs.gp_x[0] as _);
known_registers[X64Register::GPR(GPR::RBP).to_index().0] = Some(gregs.gp_x[5] as _);
known_registers[X64Register::GPR(GPR::RSP).to_index().0] = Some(gregs.gp_x[28] as _);
FaultInfo {
faulting_addr: si_addr as usize as _,
ip: std::mem::transmute::<&mut u64, &'static Cell<usize>>(
&mut (*ucontext).uc_mcontext.mc_gpregs.gp_elr,
),
known_registers,
}
}
#[cfg(all(target_os = "freebsd", target_arch = "x86_64"))]
/// Get fault info from siginfo and ucontext.
pub unsafe fn get_fault_info(siginfo: *const c_void, ucontext: *mut c_void) -> FaultInfo {
use crate::state::x64::XMM;
#[repr(C)]
pub struct ucontext_t {
uc_sigmask: libc::sigset_t,
uc_mcontext: mcontext_t,
uc_link: *mut ucontext_t,
uc_stack: libc::stack_t,
uc_flags: i32,
__spare__: [i32; 4],
}
#[repr(C)]
pub struct mcontext_t {
mc_onstack: u64,
mc_rdi: u64,
mc_rsi: u64,
mc_rdx: u64,
mc_rcx: u64,
mc_r8: u64,
mc_r9: u64,
mc_rax: u64,
mc_rbx: u64,
mc_rbp: u64,
mc_r10: u64,
mc_r11: u64,
mc_r12: u64,
mc_r13: u64,
mc_r14: u64,
mc_r15: u64,
mc_trapno: u32,
mc_fs: u16,
mc_gs: u16,
mc_addr: u64,
mc_flags: u32,
mc_es: u16,
mc_ds: u16,
mc_err: u64,
mc_rip: u64,
mc_cs: u64,
mc_rflags: u64,
mc_rsp: u64,
mc_ss: u64,
mc_len: i64,
mc_fpformat: i64,
mc_ownedfp: i64,
mc_savefpu: *const savefpu,
mc_fpstate: [i64; 63], // mc_fpstate[0] is a pointer to savefpu
mc_fsbase: u64,
mc_gsbase: u64,
mc_xfpustate: u64,
mc_xfpustate_len: u64,
mc_spare: [i64; 4],
}
#[repr(C)]
pub struct xmmacc {
element: [u32; 4],
}
#[repr(C)]
pub struct __envxmm64 {
en_cw: u16,
en_sw: u16,
en_tw: u8,
en_zero: u8,
en_opcode: u16,
en_rip: u64,
en_rdp: u64,
en_mxcsr: u32,
en_mxcsr_mask: u32,
}
#[repr(C)]
pub struct fpacc87 {
fp_bytes: [u8; 10],
}
#[repr(C)]
pub struct sv_fp {
fp_acc: fpacc87,
fp_pad: [u8; 6],
}
#[repr(C, align(16))]
pub struct savefpu {
sv_env: __envxmm64,
sv_fp_t: [sv_fp; 8],
sv_xmm: [xmmacc; 16],
sv_pad: [u8; 96],
}
let siginfo = siginfo as *const siginfo_t;
let si_addr = (*siginfo).si_addr;
let ucontext = ucontext as *mut ucontext_t;
let gregs = &mut (*ucontext).uc_mcontext;
fn read_xmm(reg: &xmmacc) -> u64 {
(reg.element[0] as u64) | ((reg.element[1] as u64) << 32)
}
let mut known_registers: [Option<u64>; 32] = [None; 32];
known_registers[X64Register::GPR(GPR::R15).to_index().0] = Some(gregs.mc_r15);
known_registers[X64Register::GPR(GPR::R14).to_index().0] = Some(gregs.mc_r14);
known_registers[X64Register::GPR(GPR::R13).to_index().0] = Some(gregs.mc_r13);
known_registers[X64Register::GPR(GPR::R12).to_index().0] = Some(gregs.mc_r12);
known_registers[X64Register::GPR(GPR::R11).to_index().0] = Some(gregs.mc_r11);
known_registers[X64Register::GPR(GPR::R10).to_index().0] = Some(gregs.mc_r10);
known_registers[X64Register::GPR(GPR::R9).to_index().0] = Some(gregs.mc_r9);
known_registers[X64Register::GPR(GPR::R8).to_index().0] = Some(gregs.mc_r8);
known_registers[X64Register::GPR(GPR::RSI).to_index().0] = Some(gregs.mc_rsi);
known_registers[X64Register::GPR(GPR::RDI).to_index().0] = Some(gregs.mc_rdi);
known_registers[X64Register::GPR(GPR::RDX).to_index().0] = Some(gregs.mc_rdx);
known_registers[X64Register::GPR(GPR::RCX).to_index().0] = Some(gregs.mc_rcx);
known_registers[X64Register::GPR(GPR::RBX).to_index().0] = Some(gregs.mc_rbx);
known_registers[X64Register::GPR(GPR::RAX).to_index().0] = Some(gregs.mc_rax);
known_registers[X64Register::GPR(GPR::RBP).to_index().0] = Some(gregs.mc_rbp);
known_registers[X64Register::GPR(GPR::RSP).to_index().0] = Some(gregs.mc_rsp);
// https://lists.freebsd.org/pipermail/freebsd-arch/2011-December/012077.html
// https://people.freebsd.org/~kib/misc/defer_sig.c
const _MC_HASFPXSTATE: u32 = 0x4;
if (gregs.mc_flags & _MC_HASFPXSTATE) == 0 {
// XXX mc_fpstate[0] is actually a pointer to a struct savefpu
let fpregs = &*(*ucontext).uc_mcontext.mc_savefpu;
known_registers[X64Register::XMM(XMM::XMM0).to_index().0] =
Some(read_xmm(&fpregs.sv_xmm[0]));
known_registers[X64Register::XMM(XMM::XMM1).to_index().0] =
Some(read_xmm(&fpregs.sv_xmm[1]));
known_registers[X64Register::XMM(XMM::XMM2).to_index().0] =
Some(read_xmm(&fpregs.sv_xmm[2]));
known_registers[X64Register::XMM(XMM::XMM3).to_index().0] =
Some(read_xmm(&fpregs.sv_xmm[3]));
known_registers[X64Register::XMM(XMM::XMM4).to_index().0] =
Some(read_xmm(&fpregs.sv_xmm[4]));
known_registers[X64Register::XMM(XMM::XMM5).to_index().0] =
Some(read_xmm(&fpregs.sv_xmm[5]));
known_registers[X64Register::XMM(XMM::XMM6).to_index().0] =
Some(read_xmm(&fpregs.sv_xmm[6]));
known_registers[X64Register::XMM(XMM::XMM7).to_index().0] =
Some(read_xmm(&fpregs.sv_xmm[7]));
known_registers[X64Register::XMM(XMM::XMM8).to_index().0] =
Some(read_xmm(&fpregs.sv_xmm[8]));
known_registers[X64Register::XMM(XMM::XMM9).to_index().0] =
Some(read_xmm(&fpregs.sv_xmm[9]));
known_registers[X64Register::XMM(XMM::XMM10).to_index().0] =
Some(read_xmm(&fpregs.sv_xmm[10]));
known_registers[X64Register::XMM(XMM::XMM11).to_index().0] =
Some(read_xmm(&fpregs.sv_xmm[11]));
known_registers[X64Register::XMM(XMM::XMM12).to_index().0] =
Some(read_xmm(&fpregs.sv_xmm[12]));
known_registers[X64Register::XMM(XMM::XMM13).to_index().0] =
Some(read_xmm(&fpregs.sv_xmm[13]));
known_registers[X64Register::XMM(XMM::XMM14).to_index().0] =
Some(read_xmm(&fpregs.sv_xmm[14]));
known_registers[X64Register::XMM(XMM::XMM15).to_index().0] =
Some(read_xmm(&fpregs.sv_xmm[15]));
}
FaultInfo {
faulting_addr: si_addr,
ip: std::mem::transmute::<&mut u64, &'static Cell<usize>>(
&mut (*ucontext).uc_mcontext.mc_rip,
),
known_registers,
}
}
#[cfg(all(target_os = "linux", target_arch = "aarch64"))]
/// Get fault info from siginfo and ucontext.
pub unsafe fn get_fault_info(siginfo: *const c_void, ucontext: *mut c_void) -> FaultInfo {

View File

@ -1,5 +1,5 @@
//! The global module contains the implementation data structures and helper functions used to
//! manipulate and access a wasm globals.
//! The global module contains data structures and helper functions used to
//! manipulate and access Wasm globals.
use crate::{
export::Export,
import::IsExport,
@ -11,7 +11,7 @@ use std::{
sync::{Arc, Mutex},
};
/// Container with a descriptor and a reference to a global value.
/// A handle to a Wasm Global
pub struct Global {
desc: GlobalDescriptor,
storage: Arc<Mutex<vm::LocalGlobal>>,

View File

@ -13,7 +13,7 @@ use crate::{
sig_registry::SigRegistry,
structures::TypedIndex,
table::Table,
typed_func::{Func, Wasm, WasmTrapInfo, WasmTypeList},
typed_func::{Func, Wasm, WasmTypeList},
types::{FuncIndex, FuncSig, GlobalIndex, LocalOrImport, MemoryIndex, TableIndex, Type, Value},
vm::{self, InternalField},
};
@ -674,8 +674,7 @@ pub(crate) fn call_func_with_index_inner(
} = wasm;
let run_wasm = |result_space: *mut u64| unsafe {
let mut trap_info = WasmTrapInfo::Unknown;
let mut user_error = None;
let mut error_out = None;
let success = invoke(
trampoline,
@ -683,21 +682,16 @@ pub(crate) fn call_func_with_index_inner(
func_ptr,
raw_args.as_ptr(),
result_space,
&mut trap_info,
&mut user_error,
&mut error_out,
invoke_env,
);
if success {
Ok(())
} else {
if let Some(data) = user_error {
Err(RuntimeError::Error { data })
} else {
Err(RuntimeError::Trap {
msg: trap_info.to_string().into(),
})
}
Err(error_out
.map(RuntimeError)
.unwrap_or_else(|| RuntimeError(Box::new("invoke(): Unknown error".to_string()))))
}
};

View File

@ -1,15 +1,15 @@
//! Wasmer Runtime Core Library
//!
//! The runtime core library provides common data structures which are shared by compiler backends
//! to implement a Web Assembly runtime.
//! This crate provides common data structures which are shared by compiler backends
//! to implement a WebAssembly runtime.
//!
//! The runtime core also provides an API for users who use wasmer as an embedded wasm runtime which
//! This crate also provides an API for users who use wasmer as an embedded wasm runtime which
//! allows operations like compiling, instantiating, providing imports, access exports, memories,
//! and tables for example.
//!
//! The runtime core library is recommended to be used by only power users who wish to customize the
//! wasmer runtime. Most wasmer users should prefer the API which is re-exported by the wasmer
//! runtime library which provides common defaults and a friendly API.
//! Most wasmer users should prefer the API which is re-exported by the `wasmer-runtime`
//! library by default. This crate provides additional APIs which may be useful to users
//! that wish to customize the wasmer runtime.
//!
#![deny(

View File

@ -88,7 +88,7 @@ impl Instance for LocalInstance {
}
}
let offset = self.offsets[id];
let addr: *const u8 = unsafe { self.code.as_ptr().offset(offset as isize) };
let addr: *const u8 = unsafe { self.code.as_ptr().add(offset) };
use std::mem::transmute;
Ok(unsafe {
match args_u64.len() {

View File

@ -109,7 +109,7 @@ impl Memory {
}
/// Return a "view" of the currently accessible memory. By
/// default, the view is unsyncronized, using regular memory
/// default, the view is unsynchronized, using regular memory
/// accesses. You can force a memory view to use atomic accesses
/// by calling the [`atomically`] method.
///

View File

@ -82,7 +82,9 @@ impl<'a, T: Atomic> MemoryView<'a, T> {
impl<'a, T> Deref for MemoryView<'a, T, NonAtomically> {
type Target = [Cell<T>];
fn deref(&self) -> &[Cell<T>] {
unsafe { slice::from_raw_parts(self.ptr as *const Cell<T>, self.length) }
let mut_slice: &mut [T] = unsafe { slice::from_raw_parts_mut(self.ptr, self.length) };
let cell_slice: &Cell<[T]> = Cell::from_mut(mut_slice);
cell_slice.as_slice_of_cells()
}
}

View File

@ -11,52 +11,12 @@ use std::{
any::Any,
convert::Infallible,
ffi::c_void,
fmt,
marker::PhantomData,
mem, panic,
ptr::{self, NonNull},
sync::Arc,
};
/// Wasm trap info.
#[repr(C)]
pub enum WasmTrapInfo {
/// Unreachable trap.
Unreachable = 0,
/// Call indirect incorrect signature trap.
IncorrectCallIndirectSignature = 1,
/// Memory out of bounds trap.
MemoryOutOfBounds = 2,
/// Call indirect out of bounds trap.
CallIndirectOOB = 3,
/// Illegal arithmetic trap.
IllegalArithmetic = 4,
/// Misaligned atomic access trap.
MisalignedAtomicAccess = 5,
/// Unknown trap.
Unknown,
}
impl fmt::Display for WasmTrapInfo {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"{}",
match self {
WasmTrapInfo::Unreachable => "unreachable",
WasmTrapInfo::IncorrectCallIndirectSignature => {
"incorrect `call_indirect` signature"
}
WasmTrapInfo::MemoryOutOfBounds => "memory out-of-bounds access",
WasmTrapInfo::CallIndirectOOB => "`call_indirect` out-of-bounds",
WasmTrapInfo::IllegalArithmetic => "illegal arithmetic operation",
WasmTrapInfo::MisalignedAtomicAccess => "misaligned atomic access",
WasmTrapInfo::Unknown => "unknown",
}
)
}
}
/// This is just an empty trait to constrict that types that
/// can be put into the third/fourth (depending if you include lifetimes)
/// of the `Func` struct.
@ -77,8 +37,7 @@ pub type Invoke = unsafe extern "C" fn(
func: NonNull<vm::Func>,
args: *const u64,
rets: *mut u64,
trap_info: *mut WasmTrapInfo,
user_error: *mut Option<Box<dyn Any + Send>>,
error_out: *mut Option<Box<dyn Any + Send>>,
extra: Option<NonNull<c_void>>,
) -> bool;
@ -92,6 +51,8 @@ pub struct Wasm {
pub(crate) invoke_env: Option<NonNull<c_void>>,
}
impl Kind for Wasm {}
impl Wasm {
/// Create new `Wasm` from given parts.
pub unsafe fn from_raw_parts(
@ -111,7 +72,6 @@ impl Wasm {
/// by the host.
pub struct Host(());
impl Kind for Wasm {}
impl Kind for Host {}
/// Represents a list of WebAssembly values.
@ -140,7 +100,7 @@ pub trait WasmTypeList {
/// This method is used to distribute the values onto a function,
/// e.g. `(1, 2).call(func, …)`. This form is unlikely to be used
/// directly in the code, see the `Func:call` implementation.
/// directly in the code, see the `Func::call` implementation.
unsafe fn call<Rets>(
self,
f: NonNull<vm::Func>,
@ -151,14 +111,15 @@ pub trait WasmTypeList {
Rets: WasmTypeList;
}
/// Empty trait to specify the kind of `ExternalFunction`: With or
/// Empty trait to specify the kind of `HostFunction`: With or
/// without a `vm::Ctx` argument. See the `ExplicitVmCtx` and the
/// `ImplicitVmCtx` structures.
///
/// This type is never aimed to be used by a user. It is used by the
/// This trait is never aimed to be used by a user. It is used by the
/// trait system to automatically generate an appropriate `wrap`
/// function.
pub trait ExternalFunctionKind {}
#[doc(hidden)]
pub trait HostFunctionKind {}
/// This empty structure indicates that an external function must
/// contain an explicit `vm::Ctx` argument (at first position).
@ -168,8 +129,11 @@ pub trait ExternalFunctionKind {}
/// x + 1
/// }
/// ```
#[doc(hidden)]
pub struct ExplicitVmCtx {}
impl HostFunctionKind for ExplicitVmCtx {}
/// This empty structure indicates that an external function has no
/// `vm::Ctx` argument (at first position). Its signature is:
///
@ -180,18 +144,17 @@ pub struct ExplicitVmCtx {}
/// ```
pub struct ImplicitVmCtx {}
impl ExternalFunctionKind for ExplicitVmCtx {}
impl ExternalFunctionKind for ImplicitVmCtx {}
impl HostFunctionKind for ImplicitVmCtx {}
/// Represents a function that can be converted to a `vm::Func`
/// (function pointer) that can be called within WebAssembly.
pub trait ExternalFunction<Kind, Args, Rets>
pub trait HostFunction<Kind, Args, Rets>
where
Kind: ExternalFunctionKind,
Kind: HostFunctionKind,
Args: WasmTypeList,
Rets: WasmTypeList,
{
/// Conver to function pointer.
/// Convert to function pointer.
fn to_raw(self) -> (NonNull<vm::Func>, Option<NonNull<vm::FuncEnv>>);
}
@ -268,8 +231,8 @@ where
/// Creates a new `Func`.
pub fn new<F, Kind>(func: F) -> Func<'a, Args, Rets, Host>
where
Kind: ExternalFunctionKind,
F: ExternalFunction<Kind, Args, Rets>,
Kind: HostFunctionKind,
F: HostFunction<Kind, Args, Rets>,
{
let (func, func_env) = func.to_raw();
@ -351,6 +314,7 @@ macro_rules! impl_traits {
where
$( $x: WasmExternType ),*;
#[allow(unused_parens)]
impl< $( $x ),* > WasmTypeList for ( $( $x ),* )
where
$( $x: WasmExternType ),*
@ -401,8 +365,7 @@ macro_rules! impl_traits {
let ( $( $x ),* ) = self;
let args = [ $( $x.to_native().to_binary()),* ];
let mut rets = Rets::empty_ret_array();
let mut trap = WasmTrapInfo::Unknown;
let mut user_error = None;
let mut error_out = None;
if (wasm.invoke)(
wasm.trampoline,
@ -410,22 +373,20 @@ macro_rules! impl_traits {
f,
args.as_ptr(),
rets.as_mut().as_mut_ptr(),
&mut trap,
&mut user_error,
&mut error_out,
wasm.invoke_env
) {
Ok(Rets::from_ret_array(rets))
} else {
if let Some(data) = user_error {
Err(RuntimeError::Error { data })
} else {
Err(RuntimeError::Trap { msg: trap.to_string().into() })
}
Err(error_out.map(RuntimeError).unwrap_or_else(|| {
RuntimeError(Box::new("invoke(): Unknown error".to_string()))
}))
}
}
}
impl< $( $x, )* Rets, Trap, FN > ExternalFunction<ExplicitVmCtx, ( $( $x ),* ), Rets> for FN
#[allow(unused_parens)]
impl< $( $x, )* Rets, Trap, FN > HostFunction<ExplicitVmCtx, ( $( $x ),* ), Rets> for FN
where
$( $x: WasmExternType, )*
Rets: WasmTypeList,
@ -540,7 +501,8 @@ macro_rules! impl_traits {
}
}
impl< $( $x, )* Rets, Trap, FN > ExternalFunction<ImplicitVmCtx, ( $( $x ),* ), Rets> for FN
#[allow(unused_parens)]
impl< $( $x, )* Rets, Trap, FN > HostFunction<ImplicitVmCtx, ( $( $x ),* ), Rets> for FN
where
$( $x: WasmExternType, )*
Rets: WasmTypeList,
@ -652,13 +614,14 @@ macro_rules! impl_traits {
}
}
#[allow(unused_parens)]
impl<'a $( , $x )*, Rets> Func<'a, ( $( $x ),* ), Rets, Wasm>
where
$( $x: WasmExternType, )*
Rets: WasmTypeList,
{
/// Call the typed func and return results.
#[allow(non_snake_case)]
#[allow(non_snake_case, clippy::too_many_arguments)]
pub fn call(&self, $( $x: $x, )* ) -> Result<Rets, RuntimeError> {
#[allow(unused_parens)]
unsafe {

View File

@ -2,7 +2,7 @@
//! convert to other represenations.
use crate::{memory::MemoryType, module::ModuleInfo, structures::TypedIndex, units::Pages};
use std::borrow::Cow;
use std::{borrow::Cow, convert::TryFrom};
/// Represents a WebAssembly type.
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Hash)]
@ -67,35 +67,32 @@ impl Value {
}
}
impl From<i32> for Value {
fn from(i: i32) -> Self {
Value::I32(i)
}
macro_rules! value_conversions {
($native_type:ty, $value_variant:ident) => {
impl From<$native_type> for Value {
fn from(n: $native_type) -> Self {
Self::$value_variant(n)
}
}
impl TryFrom<&Value> for $native_type {
type Error = &'static str;
fn try_from(value: &Value) -> Result<Self, Self::Error> {
match value {
Value::$value_variant(value) => Ok(*value),
_ => Err("Invalid cast."),
}
}
}
};
}
impl From<i64> for Value {
fn from(i: i64) -> Self {
Value::I64(i)
}
}
impl From<f32> for Value {
fn from(f: f32) -> Self {
Value::F32(f)
}
}
impl From<f64> for Value {
fn from(f: f64) -> Self {
Value::F64(f)
}
}
impl From<u128> for Value {
fn from(v: u128) -> Self {
Value::V128(v)
}
}
value_conversions!(i32, I32);
value_conversions!(i64, I64);
value_conversions!(f32, F32);
value_conversions!(f64, F64);
value_conversions!(u128, V128);
/// Represents a native wasm type.
pub unsafe trait NativeWasmType: Copy + Into<Value>
@ -104,44 +101,57 @@ where
{
/// Type for this `NativeWasmType`.
const TYPE: Type;
/// Convert from u64 bites to self.
fn from_binary(bits: u64) -> Self;
/// Convert self to u64 binary representation.
fn to_binary(self) -> u64;
}
unsafe impl NativeWasmType for i32 {
const TYPE: Type = Type::I32;
fn from_binary(bits: u64) -> Self {
bits as _
}
fn to_binary(self) -> u64 {
self as _
}
}
unsafe impl NativeWasmType for i64 {
const TYPE: Type = Type::I64;
fn from_binary(bits: u64) -> Self {
bits as _
}
fn to_binary(self) -> u64 {
self as _
}
}
unsafe impl NativeWasmType for f32 {
const TYPE: Type = Type::F32;
fn from_binary(bits: u64) -> Self {
f32::from_bits(bits as u32)
}
fn to_binary(self) -> u64 {
self.to_bits() as _
}
}
unsafe impl NativeWasmType for f64 {
const TYPE: Type = Type::F64;
fn from_binary(bits: u64) -> Self {
f64::from_bits(bits)
}
fn to_binary(self) -> u64 {
self.to_bits()
}
@ -154,103 +164,41 @@ where
{
/// Native wasm type for this `WasmExternType`.
type Native: NativeWasmType;
/// Convert from given `Native` type to self.
fn from_native(native: Self::Native) -> Self;
/// Convert self to `Native` type.
fn to_native(self) -> Self::Native;
}
unsafe impl WasmExternType for i8 {
type Native = i32;
fn from_native(native: Self::Native) -> Self {
native as _
}
fn to_native(self) -> Self::Native {
self as _
}
}
unsafe impl WasmExternType for u8 {
type Native = i32;
fn from_native(native: Self::Native) -> Self {
native as _
}
fn to_native(self) -> Self::Native {
self as _
}
}
unsafe impl WasmExternType for i16 {
type Native = i32;
fn from_native(native: Self::Native) -> Self {
native as _
}
fn to_native(self) -> Self::Native {
self as _
}
}
unsafe impl WasmExternType for u16 {
type Native = i32;
fn from_native(native: Self::Native) -> Self {
native as _
}
fn to_native(self) -> Self::Native {
self as _
}
}
unsafe impl WasmExternType for i32 {
type Native = i32;
fn from_native(native: Self::Native) -> Self {
native
}
fn to_native(self) -> Self::Native {
self
}
}
unsafe impl WasmExternType for u32 {
type Native = i32;
fn from_native(native: Self::Native) -> Self {
native as _
}
fn to_native(self) -> Self::Native {
self as _
}
}
unsafe impl WasmExternType for i64 {
type Native = i64;
fn from_native(native: Self::Native) -> Self {
native
}
fn to_native(self) -> Self::Native {
self
}
}
unsafe impl WasmExternType for u64 {
type Native = i64;
fn from_native(native: Self::Native) -> Self {
native as _
}
fn to_native(self) -> Self::Native {
self as _
}
}
unsafe impl WasmExternType for f32 {
type Native = f32;
fn from_native(native: Self::Native) -> Self {
native
}
fn to_native(self) -> Self::Native {
self
}
}
unsafe impl WasmExternType for f64 {
type Native = f64;
fn from_native(native: Self::Native) -> Self {
native
}
fn to_native(self) -> Self::Native {
self
}
macro_rules! wasm_extern_type {
($type:ty => $native_type:ty) => {
unsafe impl WasmExternType for $type {
type Native = $native_type;
fn from_native(native: Self::Native) -> Self {
native as _
}
fn to_native(self) -> Self::Native {
self as _
}
}
};
}
wasm_extern_type!(i8 => i32);
wasm_extern_type!(u8 => i32);
wasm_extern_type!(i16 => i32);
wasm_extern_type!(u16 => i32);
wasm_extern_type!(i32 => i32);
wasm_extern_type!(u32 => i32);
wasm_extern_type!(i64 => i64);
wasm_extern_type!(u64 => i64);
wasm_extern_type!(f32 => f32);
wasm_extern_type!(f64 => f64);
// pub trait IntegerAtomic
// where
// Self: Sized