mirror of
https://github.com/fluencelabs/wasmer
synced 2025-06-18 03:11:21 +00:00
Merge branch 'master' into feat-runtime-core-value-try-from
This commit is contained in:
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
## **[Unreleased]**
|
## **[Unreleased]**
|
||||||
|
|
||||||
|
- [#1228](https://github.com/wasmerio/wasmer/pull/1228) Singlepass cleanup: Resolve several FIXMEs and remove protect_unix.
|
||||||
- [#1218](https://github.com/wasmerio/wasmer/pull/1218) Enable Cranelift verifier in debug mode. Fix bug with table indices being the wrong type.
|
- [#1218](https://github.com/wasmerio/wasmer/pull/1218) Enable Cranelift verifier in debug mode. Fix bug with table indices being the wrong type.
|
||||||
- [#787](https://github.com/wasmerio/wasmer/pull/787) New crate `wasmer-interface-types` to implement WebAssembly Interface Types.
|
- [#787](https://github.com/wasmerio/wasmer/pull/787) New crate `wasmer-interface-types` to implement WebAssembly Interface Types.
|
||||||
- [#1213](https://github.com/wasmerio/wasmer/pull/1213) Fixed WASI `fdstat` to detect `isatty` properly.
|
- [#1213](https://github.com/wasmerio/wasmer/pull/1213) Fixed WASI `fdstat` to detect `isatty` properly.
|
||||||
|
@ -1 +0,0 @@
|
|||||||
<meta http-equiv="refresh" content="0; url=rust/wasmer_runtime/index.html">
|
|
32
lib/interface-types/README.md
Normal file
32
lib/interface-types/README.md
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
<p align="center">
|
||||||
|
<a href="https://wasmer.io" target="_blank" rel="noopener noreferrer">
|
||||||
|
<img width="300" src="https://raw.githubusercontent.com/wasmerio/wasmer/master/logo.png" alt="Wasmer logo">
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<a href="https://dev.azure.com/wasmerio/wasmer/_build/latest?definitionId=3&branchName=master">
|
||||||
|
<img src="https://img.shields.io/azure-devops/build/wasmerio/wasmer/3.svg?style=flat-square" alt="Build Status">
|
||||||
|
</a>
|
||||||
|
<a href="https://github.com/wasmerio/wasmer/blob/master/LICENSE">
|
||||||
|
<img src="https://img.shields.io/github/license/wasmerio/wasmer.svg?style=flat-square" alt="License">
|
||||||
|
</a>
|
||||||
|
<a href="https://spectrum.chat/wasmer">
|
||||||
|
<img src="https://withspectrum.github.io/badge/badge.svg" alt="Join the Wasmer Community">
|
||||||
|
</a>
|
||||||
|
<a href="https://crates.io/crates/wasmer-interface-types">
|
||||||
|
<img src="https://img.shields.io/crates/d/wasmer-interface-types.svg?style=flat-square" alt="Number of downloads from crates.io">
|
||||||
|
</a>
|
||||||
|
<a href="https://docs.rs/wasmer-interface-types">
|
||||||
|
<img src="https://docs.rs/wasmer-interface-types/badge.svg" alt="Read our API documentation">
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
# Wasmer Interface Types
|
||||||
|
|
||||||
|
Wasmer is a standalone JIT WebAssembly runtime, aiming to be fully
|
||||||
|
compatible with WASI, Emscripten, Rust and Go. [Learn
|
||||||
|
more](https://github.com/wasmerio/wasmer).
|
||||||
|
|
||||||
|
This crate is an implementation of [the living WebAssembly Interface
|
||||||
|
Types standard](https://github.com/WebAssembly/interface-types).
|
@ -51,6 +51,8 @@ pub struct Wasm {
|
|||||||
pub(crate) invoke_env: Option<NonNull<c_void>>,
|
pub(crate) invoke_env: Option<NonNull<c_void>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Kind for Wasm {}
|
||||||
|
|
||||||
impl Wasm {
|
impl Wasm {
|
||||||
/// Create new `Wasm` from given parts.
|
/// Create new `Wasm` from given parts.
|
||||||
pub unsafe fn from_raw_parts(
|
pub unsafe fn from_raw_parts(
|
||||||
@ -70,7 +72,6 @@ impl Wasm {
|
|||||||
/// by the host.
|
/// by the host.
|
||||||
pub struct Host(());
|
pub struct Host(());
|
||||||
|
|
||||||
impl Kind for Wasm {}
|
|
||||||
impl Kind for Host {}
|
impl Kind for Host {}
|
||||||
|
|
||||||
/// Represents a list of WebAssembly values.
|
/// Represents a list of WebAssembly values.
|
||||||
@ -110,14 +111,15 @@ pub trait WasmTypeList {
|
|||||||
Rets: 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
|
/// without a `vm::Ctx` argument. See the `ExplicitVmCtx` and the
|
||||||
/// `ImplicitVmCtx` structures.
|
/// `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`
|
/// trait system to automatically generate an appropriate `wrap`
|
||||||
/// function.
|
/// function.
|
||||||
pub trait ExternalFunctionKind {}
|
#[doc(hidden)]
|
||||||
|
pub trait HostFunctionKind {}
|
||||||
|
|
||||||
/// This empty structure indicates that an external function must
|
/// This empty structure indicates that an external function must
|
||||||
/// contain an explicit `vm::Ctx` argument (at first position).
|
/// contain an explicit `vm::Ctx` argument (at first position).
|
||||||
@ -127,8 +129,11 @@ pub trait ExternalFunctionKind {}
|
|||||||
/// x + 1
|
/// x + 1
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
#[doc(hidden)]
|
||||||
pub struct ExplicitVmCtx {}
|
pub struct ExplicitVmCtx {}
|
||||||
|
|
||||||
|
impl HostFunctionKind for ExplicitVmCtx {}
|
||||||
|
|
||||||
/// This empty structure indicates that an external function has no
|
/// This empty structure indicates that an external function has no
|
||||||
/// `vm::Ctx` argument (at first position). Its signature is:
|
/// `vm::Ctx` argument (at first position). Its signature is:
|
||||||
///
|
///
|
||||||
@ -139,14 +144,13 @@ pub struct ExplicitVmCtx {}
|
|||||||
/// ```
|
/// ```
|
||||||
pub struct ImplicitVmCtx {}
|
pub struct ImplicitVmCtx {}
|
||||||
|
|
||||||
impl ExternalFunctionKind for ExplicitVmCtx {}
|
impl HostFunctionKind for ImplicitVmCtx {}
|
||||||
impl ExternalFunctionKind for ImplicitVmCtx {}
|
|
||||||
|
|
||||||
/// Represents a function that can be converted to a `vm::Func`
|
/// Represents a function that can be converted to a `vm::Func`
|
||||||
/// (function pointer) that can be called within WebAssembly.
|
/// (function pointer) that can be called within WebAssembly.
|
||||||
pub trait ExternalFunction<Kind, Args, Rets>
|
pub trait HostFunction<Kind, Args, Rets>
|
||||||
where
|
where
|
||||||
Kind: ExternalFunctionKind,
|
Kind: HostFunctionKind,
|
||||||
Args: WasmTypeList,
|
Args: WasmTypeList,
|
||||||
Rets: WasmTypeList,
|
Rets: WasmTypeList,
|
||||||
{
|
{
|
||||||
@ -227,8 +231,8 @@ where
|
|||||||
/// Creates a new `Func`.
|
/// Creates a new `Func`.
|
||||||
pub fn new<F, Kind>(func: F) -> Func<'a, Args, Rets, Host>
|
pub fn new<F, Kind>(func: F) -> Func<'a, Args, Rets, Host>
|
||||||
where
|
where
|
||||||
Kind: ExternalFunctionKind,
|
Kind: HostFunctionKind,
|
||||||
F: ExternalFunction<Kind, Args, Rets>,
|
F: HostFunction<Kind, Args, Rets>,
|
||||||
{
|
{
|
||||||
let (func, func_env) = func.to_raw();
|
let (func, func_env) = func.to_raw();
|
||||||
|
|
||||||
@ -310,6 +314,7 @@ macro_rules! impl_traits {
|
|||||||
where
|
where
|
||||||
$( $x: WasmExternType ),*;
|
$( $x: WasmExternType ),*;
|
||||||
|
|
||||||
|
#[allow(unused_parens)]
|
||||||
impl< $( $x ),* > WasmTypeList for ( $( $x ),* )
|
impl< $( $x ),* > WasmTypeList for ( $( $x ),* )
|
||||||
where
|
where
|
||||||
$( $x: WasmExternType ),*
|
$( $x: WasmExternType ),*
|
||||||
@ -380,7 +385,8 @@ macro_rules! impl_traits {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
where
|
||||||
$( $x: WasmExternType, )*
|
$( $x: WasmExternType, )*
|
||||||
Rets: WasmTypeList,
|
Rets: WasmTypeList,
|
||||||
@ -495,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
|
where
|
||||||
$( $x: WasmExternType, )*
|
$( $x: WasmExternType, )*
|
||||||
Rets: WasmTypeList,
|
Rets: WasmTypeList,
|
||||||
@ -607,6 +614,7 @@ macro_rules! impl_traits {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(unused_parens)]
|
||||||
impl<'a $( , $x )*, Rets> Func<'a, ( $( $x ),* ), Rets, Wasm>
|
impl<'a $( , $x )*, Rets> Func<'a, ( $( $x ),* ), Rets, Wasm>
|
||||||
where
|
where
|
||||||
$( $x: WasmExternType, )*
|
$( $x: WasmExternType, )*
|
||||||
|
@ -101,44 +101,57 @@ where
|
|||||||
{
|
{
|
||||||
/// Type for this `NativeWasmType`.
|
/// Type for this `NativeWasmType`.
|
||||||
const TYPE: Type;
|
const TYPE: Type;
|
||||||
|
|
||||||
/// Convert from u64 bites to self.
|
/// Convert from u64 bites to self.
|
||||||
fn from_binary(bits: u64) -> Self;
|
fn from_binary(bits: u64) -> Self;
|
||||||
|
|
||||||
/// Convert self to u64 binary representation.
|
/// Convert self to u64 binary representation.
|
||||||
fn to_binary(self) -> u64;
|
fn to_binary(self) -> u64;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl NativeWasmType for i32 {
|
unsafe impl NativeWasmType for i32 {
|
||||||
const TYPE: Type = Type::I32;
|
const TYPE: Type = Type::I32;
|
||||||
|
|
||||||
fn from_binary(bits: u64) -> Self {
|
fn from_binary(bits: u64) -> Self {
|
||||||
bits as _
|
bits as _
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_binary(self) -> u64 {
|
fn to_binary(self) -> u64 {
|
||||||
self as _
|
self as _
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl NativeWasmType for i64 {
|
unsafe impl NativeWasmType for i64 {
|
||||||
const TYPE: Type = Type::I64;
|
const TYPE: Type = Type::I64;
|
||||||
|
|
||||||
fn from_binary(bits: u64) -> Self {
|
fn from_binary(bits: u64) -> Self {
|
||||||
bits as _
|
bits as _
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_binary(self) -> u64 {
|
fn to_binary(self) -> u64 {
|
||||||
self as _
|
self as _
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl NativeWasmType for f32 {
|
unsafe impl NativeWasmType for f32 {
|
||||||
const TYPE: Type = Type::F32;
|
const TYPE: Type = Type::F32;
|
||||||
|
|
||||||
fn from_binary(bits: u64) -> Self {
|
fn from_binary(bits: u64) -> Self {
|
||||||
f32::from_bits(bits as u32)
|
f32::from_bits(bits as u32)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_binary(self) -> u64 {
|
fn to_binary(self) -> u64 {
|
||||||
self.to_bits() as _
|
self.to_bits() as _
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl NativeWasmType for f64 {
|
unsafe impl NativeWasmType for f64 {
|
||||||
const TYPE: Type = Type::F64;
|
const TYPE: Type = Type::F64;
|
||||||
|
|
||||||
fn from_binary(bits: u64) -> Self {
|
fn from_binary(bits: u64) -> Self {
|
||||||
f64::from_bits(bits)
|
f64::from_bits(bits)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_binary(self) -> u64 {
|
fn to_binary(self) -> u64 {
|
||||||
self.to_bits()
|
self.to_bits()
|
||||||
}
|
}
|
||||||
@ -151,103 +164,41 @@ where
|
|||||||
{
|
{
|
||||||
/// Native wasm type for this `WasmExternType`.
|
/// Native wasm type for this `WasmExternType`.
|
||||||
type Native: NativeWasmType;
|
type Native: NativeWasmType;
|
||||||
|
|
||||||
/// Convert from given `Native` type to self.
|
/// Convert from given `Native` type to self.
|
||||||
fn from_native(native: Self::Native) -> Self;
|
fn from_native(native: Self::Native) -> Self;
|
||||||
|
|
||||||
/// Convert self to `Native` type.
|
/// Convert self to `Native` type.
|
||||||
fn to_native(self) -> Self::Native;
|
fn to_native(self) -> Self::Native;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl WasmExternType for i8 {
|
macro_rules! wasm_extern_type {
|
||||||
type Native = i32;
|
($type:ty => $native_type:ty) => {
|
||||||
fn from_native(native: Self::Native) -> Self {
|
unsafe impl WasmExternType for $type {
|
||||||
native as _
|
type Native = $native_type;
|
||||||
}
|
|
||||||
fn to_native(self) -> Self::Native {
|
fn from_native(native: Self::Native) -> Self {
|
||||||
self as _
|
native as _
|
||||||
}
|
}
|
||||||
}
|
|
||||||
unsafe impl WasmExternType for u8 {
|
fn to_native(self) -> Self::Native {
|
||||||
type Native = i32;
|
self as _
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
// pub trait IntegerAtomic
|
||||||
// where
|
// where
|
||||||
// Self: Sized
|
// Self: Sized
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
use crate::emitter_x64::*;
|
use crate::emitter_x64::*;
|
||||||
use crate::machine::*;
|
use crate::machine::*;
|
||||||
use crate::protect_unix;
|
|
||||||
#[cfg(target_arch = "aarch64")]
|
#[cfg(target_arch = "aarch64")]
|
||||||
use dynasmrt::aarch64::Assembler;
|
use dynasmrt::aarch64::Assembler;
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
@ -28,7 +27,7 @@ use wasmer_runtime_core::{
|
|||||||
},
|
},
|
||||||
cache::{Artifact, Error as CacheError},
|
cache::{Artifact, Error as CacheError},
|
||||||
codegen::*,
|
codegen::*,
|
||||||
fault::raw::register_preservation_trampoline,
|
fault::{self, raw::register_preservation_trampoline},
|
||||||
loader::CodeMemory,
|
loader::CodeMemory,
|
||||||
memory::MemoryType,
|
memory::MemoryType,
|
||||||
module::{ModuleInfo, ModuleInner},
|
module::{ModuleInfo, ModuleInner},
|
||||||
@ -369,6 +368,11 @@ impl RunnableModule for X64ExecutionContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn get_trampoline(&self, _: &ModuleInfo, sig_index: SigIndex) -> Option<Wasm> {
|
fn get_trampoline(&self, _: &ModuleInfo, sig_index: SigIndex) -> Option<Wasm> {
|
||||||
|
// Correctly unwinding from `catch_unsafe_unwind` on hardware exceptions depends
|
||||||
|
// on the signal handlers being installed. Here we call `ensure_sighandler` "statically"
|
||||||
|
// outside `invoke()`.
|
||||||
|
fault::ensure_sighandler();
|
||||||
|
|
||||||
unsafe extern "C" fn invoke(
|
unsafe extern "C" fn invoke(
|
||||||
_trampoline: Trampoline,
|
_trampoline: Trampoline,
|
||||||
ctx: *mut vm::Ctx,
|
ctx: *mut vm::Ctx,
|
||||||
@ -383,8 +387,9 @@ impl RunnableModule for X64ExecutionContext {
|
|||||||
let args =
|
let args =
|
||||||
slice::from_raw_parts(args, num_params_plus_one.unwrap().as_ptr() as usize - 1);
|
slice::from_raw_parts(args, num_params_plus_one.unwrap().as_ptr() as usize - 1);
|
||||||
|
|
||||||
let ret = match protect_unix::call_protected(
|
let ret = match fault::catch_unsafe_unwind(
|
||||||
|| {
|
|| {
|
||||||
|
// Puts the arguments onto the stack and calls Wasm entry.
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
{
|
{
|
||||||
let args_reverse: SmallVec<[u64; 8]> = args.iter().cloned().rev().collect();
|
let args_reverse: SmallVec<[u64; 8]> = args.iter().cloned().rev().collect();
|
||||||
@ -395,6 +400,9 @@ impl RunnableModule for X64ExecutionContext {
|
|||||||
func.as_ptr(),
|
func.as_ptr(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: Currently we are doing a hack here to convert between native aarch64 and
|
||||||
|
// "emulated" x86 ABIs. Ideally, this should be done using handwritten assembly.
|
||||||
#[cfg(target_arch = "aarch64")]
|
#[cfg(target_arch = "aarch64")]
|
||||||
{
|
{
|
||||||
struct CallCtx<'a> {
|
struct CallCtx<'a> {
|
||||||
@ -519,7 +527,7 @@ impl RunnableModule for X64ExecutionContext {
|
|||||||
true
|
true
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
*error_out = Some(err.0);
|
*error_out = Some(err);
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -545,8 +553,7 @@ impl RunnableModule for X64ExecutionContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn do_early_trap(&self, data: Box<dyn Any + Send>) -> ! {
|
unsafe fn do_early_trap(&self, data: Box<dyn Any + Send>) -> ! {
|
||||||
protect_unix::TRAP_EARLY_DATA.with(|x| x.set(Some(data)));
|
fault::begin_unsafe_unwind(data);
|
||||||
protect_unix::trigger_trap();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_code(&self) -> Option<&[u8]> {
|
fn get_code(&self) -> Option<&[u8]> {
|
||||||
@ -1686,14 +1693,11 @@ impl X64FunctionCode {
|
|||||||
Location::GPR(GPR::RSP),
|
Location::GPR(GPR::RSP),
|
||||||
);
|
);
|
||||||
|
|
||||||
// FIXME: Possible dynasm bug. This is a workaround.
|
|
||||||
// Using RSP as the source/destination operand of a `mov` instruction produces invalid code.
|
|
||||||
a.emit_mov(Size::S64, Location::GPR(GPR::RSP), Location::GPR(GPR::RCX));
|
|
||||||
for (i, r) in used_xmms.iter().enumerate() {
|
for (i, r) in used_xmms.iter().enumerate() {
|
||||||
a.emit_mov(
|
a.emit_mov(
|
||||||
Size::S64,
|
Size::S64,
|
||||||
Location::XMM(*r),
|
Location::XMM(*r),
|
||||||
Location::Memory(GPR::RCX, (i * 8) as i32),
|
Location::Memory(GPR::RSP, (i * 8) as i32),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
for r in used_xmms.iter().rev() {
|
for r in used_xmms.iter().rev() {
|
||||||
@ -1771,37 +1775,26 @@ impl X64FunctionCode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
match *param {
|
match *param {
|
||||||
// Dynasm bug: RSP in memory operand does not work
|
Location::Imm64(_) => {
|
||||||
Location::Imm64(_) | Location::XMM(_) => {
|
// Dummy value slot to be filled with `mov`.
|
||||||
|
a.emit_push(Size::S64, Location::GPR(GPR::RAX));
|
||||||
|
|
||||||
|
// Use R10 as the temporary register here, since it is callee-saved and not
|
||||||
|
// used by the callback `cb`.
|
||||||
|
a.emit_mov(Size::S64, *param, Location::GPR(GPR::R10));
|
||||||
a.emit_mov(
|
a.emit_mov(
|
||||||
Size::S64,
|
Size::S64,
|
||||||
Location::GPR(GPR::RAX),
|
Location::GPR(GPR::R10),
|
||||||
Location::XMM(XMM::XMM0),
|
Location::Memory(GPR::RSP, 0),
|
||||||
);
|
|
||||||
a.emit_mov(
|
|
||||||
Size::S64,
|
|
||||||
Location::GPR(GPR::RCX),
|
|
||||||
Location::XMM(XMM::XMM1),
|
|
||||||
);
|
|
||||||
a.emit_sub(Size::S64, Location::Imm32(8), Location::GPR(GPR::RSP));
|
|
||||||
a.emit_mov(Size::S64, Location::GPR(GPR::RSP), Location::GPR(GPR::RCX));
|
|
||||||
a.emit_mov(Size::S64, *param, Location::GPR(GPR::RAX));
|
|
||||||
a.emit_mov(
|
|
||||||
Size::S64,
|
|
||||||
Location::GPR(GPR::RAX),
|
|
||||||
Location::Memory(GPR::RCX, 0),
|
|
||||||
);
|
|
||||||
a.emit_mov(
|
|
||||||
Size::S64,
|
|
||||||
Location::XMM(XMM::XMM0),
|
|
||||||
Location::GPR(GPR::RAX),
|
|
||||||
);
|
|
||||||
a.emit_mov(
|
|
||||||
Size::S64,
|
|
||||||
Location::XMM(XMM::XMM1),
|
|
||||||
Location::GPR(GPR::RCX),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
Location::XMM(_) => {
|
||||||
|
// Dummy value slot to be filled with `mov`.
|
||||||
|
a.emit_push(Size::S64, Location::GPR(GPR::RAX));
|
||||||
|
|
||||||
|
// XMM registers can be directly stored to memory.
|
||||||
|
a.emit_mov(Size::S64, *param, Location::Memory(GPR::RSP, 0));
|
||||||
|
}
|
||||||
_ => a.emit_push(Size::S64, *param),
|
_ => a.emit_push(Size::S64, *param),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1873,12 +1866,10 @@ impl X64FunctionCode {
|
|||||||
|
|
||||||
// Restore XMMs.
|
// Restore XMMs.
|
||||||
if used_xmms.len() > 0 {
|
if used_xmms.len() > 0 {
|
||||||
// FIXME: Possible dynasm bug. This is a workaround.
|
|
||||||
a.emit_mov(Size::S64, Location::GPR(GPR::RSP), Location::GPR(GPR::RDX));
|
|
||||||
for (i, r) in used_xmms.iter().enumerate() {
|
for (i, r) in used_xmms.iter().enumerate() {
|
||||||
a.emit_mov(
|
a.emit_mov(
|
||||||
Size::S64,
|
Size::S64,
|
||||||
Location::Memory(GPR::RDX, (i * 8) as i32),
|
Location::Memory(GPR::RSP, (i * 8) as i32),
|
||||||
Location::XMM(*r),
|
Location::XMM(*r),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,6 @@ extern crate smallvec;
|
|||||||
mod codegen_x64;
|
mod codegen_x64;
|
||||||
mod emitter_x64;
|
mod emitter_x64;
|
||||||
mod machine;
|
mod machine;
|
||||||
pub mod protect_unix;
|
|
||||||
#[cfg(target_arch = "aarch64")]
|
#[cfg(target_arch = "aarch64")]
|
||||||
mod translator_aarch64;
|
mod translator_aarch64;
|
||||||
|
|
||||||
|
@ -1,49 +0,0 @@
|
|||||||
//! Installing signal handlers allows us to handle traps and out-of-bounds memory
|
|
||||||
//! accesses that occur when runniing WebAssembly.
|
|
||||||
//!
|
|
||||||
//! This code is inspired by: https://github.com/pepyakin/wasmtime/commit/625a2b6c0815b21996e111da51b9664feb174622
|
|
||||||
//!
|
|
||||||
//! When a WebAssembly module triggers any traps, we perform recovery here.
|
|
||||||
//!
|
|
||||||
//! This module uses TLS (thread-local storage) to track recovery information. Since the four signals we're handling
|
|
||||||
//! are very special, the async signal unsafety of Rust's TLS implementation generally does not affect the correctness here
|
|
||||||
//! unless you have memory unsafety elsewhere in your code.
|
|
||||||
//!
|
|
||||||
use std::any::Any;
|
|
||||||
use std::cell::Cell;
|
|
||||||
use wasmer_runtime_core::codegen::BreakpointMap;
|
|
||||||
use wasmer_runtime_core::fault::{begin_unsafe_unwind, catch_unsafe_unwind, ensure_sighandler};
|
|
||||||
|
|
||||||
thread_local! {
|
|
||||||
pub static TRAP_EARLY_DATA: Cell<Option<Box<dyn Any + Send>>> = Cell::new(None);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub unsafe fn trigger_trap() -> ! {
|
|
||||||
begin_unsafe_unwind(Box::new(()));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct CallProtError(pub Box<dyn Any + Send>);
|
|
||||||
|
|
||||||
pub fn call_protected<T>(
|
|
||||||
f: impl FnOnce() -> T,
|
|
||||||
breakpoints: Option<BreakpointMap>,
|
|
||||||
) -> Result<T, CallProtError> {
|
|
||||||
ensure_sighandler();
|
|
||||||
unsafe {
|
|
||||||
let ret = catch_unsafe_unwind(|| f(), breakpoints);
|
|
||||||
match ret {
|
|
||||||
Ok(x) => Ok(x),
|
|
||||||
Err(e) => Err(CallProtError(
|
|
||||||
if let Some(data) = TRAP_EARLY_DATA.with(|cell| cell.replace(None)) {
|
|
||||||
data
|
|
||||||
} else {
|
|
||||||
e
|
|
||||||
},
|
|
||||||
)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub unsafe fn throw(payload: Box<dyn Any + Send>) -> ! {
|
|
||||||
begin_unsafe_unwind(payload);
|
|
||||||
}
|
|
@ -5,7 +5,8 @@
|
|||||||
unused_mut,
|
unused_mut,
|
||||||
unused_variables,
|
unused_variables,
|
||||||
unused_unsafe,
|
unused_unsafe,
|
||||||
unreachable_patterns
|
unreachable_patterns,
|
||||||
|
clippy::missing_safety_doc
|
||||||
)]
|
)]
|
||||||
#![doc(html_favicon_url = "https://wasmer.io/static/icons/favicon.ico")]
|
#![doc(html_favicon_url = "https://wasmer.io/static/icons/favicon.ico")]
|
||||||
#![doc(html_logo_url = "https://avatars3.githubusercontent.com/u/44205449?s=200&v=4")]
|
#![doc(html_logo_url = "https://avatars3.githubusercontent.com/u/44205449?s=200&v=4")]
|
||||||
|
@ -36,7 +36,7 @@ use wasmer_runtime_core::vm::Ctx;
|
|||||||
/// the fd value of the virtual root
|
/// the fd value of the virtual root
|
||||||
pub const VIRTUAL_ROOT_FD: __wasi_fd_t = 3;
|
pub const VIRTUAL_ROOT_FD: __wasi_fd_t = 3;
|
||||||
/// all the rights enabled
|
/// all the rights enabled
|
||||||
pub const ALL_RIGHTS: __wasi_rights_t = 0x1FFFFFFF;
|
pub const ALL_RIGHTS: __wasi_rights_t = 0x1FFF_FFFF;
|
||||||
const STDIN_DEFAULT_RIGHTS: __wasi_rights_t = __WASI_RIGHT_FD_DATASYNC
|
const STDIN_DEFAULT_RIGHTS: __wasi_rights_t = __WASI_RIGHT_FD_DATASYNC
|
||||||
| __WASI_RIGHT_FD_READ
|
| __WASI_RIGHT_FD_READ
|
||||||
| __WASI_RIGHT_FD_SYNC
|
| __WASI_RIGHT_FD_SYNC
|
||||||
@ -52,7 +52,10 @@ const STDOUT_DEFAULT_RIGHTS: __wasi_rights_t = __WASI_RIGHT_FD_DATASYNC
|
|||||||
const STDERR_DEFAULT_RIGHTS: __wasi_rights_t = STDOUT_DEFAULT_RIGHTS;
|
const STDERR_DEFAULT_RIGHTS: __wasi_rights_t = STDOUT_DEFAULT_RIGHTS;
|
||||||
|
|
||||||
/// Get WasiState from a Ctx
|
/// Get WasiState from a Ctx
|
||||||
/// This function is unsafe because it must be called on a WASI Ctx
|
///
|
||||||
|
/// # Safety
|
||||||
|
/// - This function must be called on a `Ctx` that was created with `WasiState`
|
||||||
|
/// in the data field
|
||||||
pub unsafe fn get_wasi_state(ctx: &mut Ctx) -> &mut WasiState {
|
pub unsafe fn get_wasi_state(ctx: &mut Ctx) -> &mut WasiState {
|
||||||
&mut *(ctx.data as *mut WasiState)
|
&mut *(ctx.data as *mut WasiState)
|
||||||
}
|
}
|
||||||
@ -186,7 +189,7 @@ impl WasiFs {
|
|||||||
for dir in preopened_dirs {
|
for dir in preopened_dirs {
|
||||||
debug!("Attempting to preopen {}", &dir.to_string_lossy());
|
debug!("Attempting to preopen {}", &dir.to_string_lossy());
|
||||||
// TODO: think about this
|
// TODO: think about this
|
||||||
let default_rights = 0x1FFFFFFF; // all rights
|
let default_rights = ALL_RIGHTS;
|
||||||
let cur_dir_metadata = dir.metadata().map_err(|e| {
|
let cur_dir_metadata = dir.metadata().map_err(|e| {
|
||||||
format!(
|
format!(
|
||||||
"Could not get metadata for file {:?}: {}",
|
"Could not get metadata for file {:?}: {}",
|
||||||
@ -236,7 +239,7 @@ impl WasiFs {
|
|||||||
for (alias, real_dir) in mapped_dirs {
|
for (alias, real_dir) in mapped_dirs {
|
||||||
debug!("Attempting to open {:?} at {}", real_dir, alias);
|
debug!("Attempting to open {:?} at {}", real_dir, alias);
|
||||||
// TODO: think about this
|
// TODO: think about this
|
||||||
let default_rights = 0x1FFFFFFF; // all rights
|
let default_rights = ALL_RIGHTS;
|
||||||
let cur_dir_metadata = real_dir.metadata().map_err(|e| {
|
let cur_dir_metadata = real_dir.metadata().map_err(|e| {
|
||||||
format!(
|
format!(
|
||||||
"Could not get metadata for file {:?}: {}",
|
"Could not get metadata for file {:?}: {}",
|
||||||
@ -428,7 +431,7 @@ impl WasiFs {
|
|||||||
|
|
||||||
// create virtual root
|
// create virtual root
|
||||||
let root_inode = {
|
let root_inode = {
|
||||||
let all_rights = 0x1FFFFFFF;
|
let all_rights = ALL_RIGHTS;
|
||||||
// TODO: make this a list of positive rigths instead of negative ones
|
// TODO: make this a list of positive rigths instead of negative ones
|
||||||
// root gets all right for now
|
// root gets all right for now
|
||||||
let root_rights = all_rights
|
let root_rights = all_rights
|
||||||
@ -525,10 +528,15 @@ impl WasiFs {
|
|||||||
next
|
next
|
||||||
}
|
}
|
||||||
|
|
||||||
/// like create dir all, but it also opens it
|
/// This function is like create dir all, but it also opens it.
|
||||||
/// Function is unsafe because it may break invariants and hasn't been tested.
|
/// Function is unsafe because it may break invariants and hasn't been tested.
|
||||||
/// This is an experimental function and may be removed
|
/// This is an experimental function and may be removed
|
||||||
// dead code because this is an API for external use
|
///
|
||||||
|
/// # Safety
|
||||||
|
/// - Virtual directories created with this function must not conflict with
|
||||||
|
/// the standard operation of the WASI filesystem. This is vague and
|
||||||
|
/// unlikely in pratice. Join the discussion at https://github.com/wasmerio/wasmer/issues/1219
|
||||||
|
/// for what the newer, safer WASI FS APIs should look like.
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub unsafe fn open_dir_all(
|
pub unsafe fn open_dir_all(
|
||||||
&mut self,
|
&mut self,
|
||||||
@ -1161,7 +1169,7 @@ impl WasiFs {
|
|||||||
stat.st_ino = self.get_next_inode_index();
|
stat.st_ino = self.get_next_inode_index();
|
||||||
|
|
||||||
Ok(self.inodes.insert(InodeVal {
|
Ok(self.inodes.insert(InodeVal {
|
||||||
stat: stat,
|
stat,
|
||||||
is_preopened,
|
is_preopened,
|
||||||
name,
|
name,
|
||||||
kind,
|
kind,
|
||||||
@ -1210,10 +1218,14 @@ impl WasiFs {
|
|||||||
Ok(idx)
|
Ok(idx)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This function is unsafe because it's the caller's responsibility to ensure that
|
/// Low level function to remove an inode, that is it deletes the WASI FS's
|
||||||
/// all refences to the given inode have been removed from the filesystem
|
/// knowledge of a file.
|
||||||
///
|
///
|
||||||
/// returns the inode if it existed and was removed
|
/// This function returns the inode if it existed and was removed.
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
/// - The caller must ensure that all references to the specified inode have
|
||||||
|
/// been removed from the filesystem.
|
||||||
pub unsafe fn remove_inode(&mut self, inode: Inode) -> Option<InodeVal> {
|
pub unsafe fn remove_inode(&mut self, inode: Inode) -> Option<InodeVal> {
|
||||||
self.inodes.remove(inode)
|
self.inodes.remove(inode)
|
||||||
}
|
}
|
||||||
|
@ -434,7 +434,7 @@ impl<'de> Deserialize<'de> for HostFile {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const FIELDS: &'static [&'static str] = &["host_path", "flags"];
|
const FIELDS: &[&str] = &["host_path", "flags"];
|
||||||
deserializer.deserialize_struct("HostFile", FIELDS, HostFileVisitor)
|
deserializer.deserialize_struct("HostFile", FIELDS, HostFileVisitor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#![allow(non_camel_case_types)]
|
#![allow(non_camel_case_types, clippy::identity_op)]
|
||||||
|
|
||||||
use crate::ptr::{Array, WasmPtr};
|
use crate::ptr::{Array, WasmPtr};
|
||||||
use byteorder::{ReadBytesExt, WriteBytesExt, LE};
|
use byteorder::{ReadBytesExt, WriteBytesExt, LE};
|
||||||
|
@ -30,10 +30,10 @@ pub enum WasiVersion {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Namespace for the `Snapshot0` version.
|
/// Namespace for the `Snapshot0` version.
|
||||||
const SNAPSHOT0_NAMESPACE: &'static str = "wasi_unstable";
|
const SNAPSHOT0_NAMESPACE: &str = "wasi_unstable";
|
||||||
|
|
||||||
/// Namespace for the `Snapshot1` version.
|
/// Namespace for the `Snapshot1` version.
|
||||||
const SNAPSHOT1_NAMESPACE: &'static str = "wasi_snapshot_preview1";
|
const SNAPSHOT1_NAMESPACE: &str = "wasi_snapshot_preview1";
|
||||||
|
|
||||||
/// Detect the version of WASI being used based on the import
|
/// Detect the version of WASI being used based on the import
|
||||||
/// namespaces.
|
/// namespaces.
|
||||||
|
Reference in New Issue
Block a user