Merge remote-tracking branch 'origin/master' into feature/remote-code-load

This commit is contained in:
losfair
2019-05-14 15:46:15 +08:00
79 changed files with 1646 additions and 1299 deletions

View File

@ -17,30 +17,31 @@ use crate::{
};
use std::slice;
/// The `LocalBacking` "owns" the memory used by all the local resources of an Instance.
/// That is, local memories, tables, and globals (as well as some additional
/// data for the virtual call machinery).
#[derive(Debug)]
pub struct LocalBacking {
/// This is a map from the local resource index to actual memory,
/// table, and globals.
pub(crate) memories: BoxedMap<LocalMemoryIndex, Memory>,
pub(crate) tables: BoxedMap<LocalTableIndex, Table>,
pub(crate) globals: BoxedMap<LocalGlobalIndex, Global>,
/// This own the memory containing the pointers to the local memories.
/// While simplifying implementation, this adds indirection and may hurt
/// performance, especially on cache-starved systems.
pub(crate) vm_memories: BoxedMap<LocalMemoryIndex, *mut vm::LocalMemory>,
pub(crate) vm_tables: BoxedMap<LocalTableIndex, *mut vm::LocalTable>,
pub(crate) vm_globals: BoxedMap<LocalGlobalIndex, *mut vm::LocalGlobal>,
/// The dynamic sigindices are used to efficiently support caching and
/// the `call_indirect` wasm instruction. This field (and local_functions
/// as well) are subject to change.
pub(crate) dynamic_sigindices: BoxedMap<SigIndex, vm::SigId>,
pub(crate) local_functions: BoxedMap<LocalFuncIndex, *const vm::Func>,
}
// impl LocalBacking {
// pub fn memory(&mut self, local_memory_index: LocalMemoryIndex) -> &mut Memory {
// &mut self.memories[local_memory_index]
// }
// pub fn table(&mut self, local_table_index: LocalTableIndex) -> &mut TableBacking {
// &mut self.tables[local_table_index]
// }
// }
impl LocalBacking {
pub(crate) fn new(module: &ModuleInner, imports: &ImportBacking, vmctx: *mut vm::Ctx) -> Self {
let mut memories = Self::generate_memories(module);
@ -102,6 +103,9 @@ impl LocalBacking {
memories.into_boxed_map()
}
/// Initialize each locally-defined memory in the Module.
///
/// This involves copying in the data initializers.
fn finalize_memories(
module: &ModuleInner,
imports: &ImportBacking,
@ -174,6 +178,9 @@ impl LocalBacking {
tables.into_boxed_map()
}
/// This initializes all of the locally-defined tables in the Module, e.g.
/// putting all the table elements (function pointers)
/// in the right places.
#[allow(clippy::cast_ptr_alignment)]
fn finalize_tables(
module: &ModuleInner,

View File

@ -1,18 +1,19 @@
use crate::{
backend::RunnableModule,
backend::{sys::Memory, Backend, CacheGen, Compiler, CompilerConfig, Token},
backend::{Backend, CacheGen, Compiler, CompilerConfig, Token},
cache::{Artifact, Error as CacheError},
error::{CompileError, CompileResult},
module::{ModuleInfo, ModuleInner},
parse::LoadError,
structures::Map,
types::{FuncIndex, FuncSig, SigIndex},
};
use smallvec::SmallVec;
use std::fmt;
use std::fmt::Debug;
use std::marker::PhantomData;
use wasmparser::{Operator, Type as WpType};
#[derive(Debug)]
pub enum Event<'a, 'b> {
Internal(InternalEvent),
Wasm(&'b Operator<'a>),
@ -26,6 +27,18 @@ pub enum InternalEvent {
GetInternal(u32),
}
impl fmt::Debug for InternalEvent {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
InternalEvent::FunctionBegin(_) => write!(f, "FunctionBegin"),
InternalEvent::FunctionEnd => write!(f, "FunctionEnd"),
InternalEvent::Breakpoint(_) => write!(f, "Breakpoint"),
InternalEvent::SetInternal(_) => write!(f, "SetInternal"),
InternalEvent::GetInternal(_) => write!(f, "GetInternal"),
}
}
}
pub struct BkptInfo {}
pub trait ModuleCodeGenerator<FCG: FunctionCodeGenerator<E>, RM: RunnableModule, E: Debug> {
@ -35,7 +48,7 @@ pub trait ModuleCodeGenerator<FCG: FunctionCodeGenerator<E>, RM: RunnableModule,
/// Creates a new function and returns the function-scope code generator for it.
fn next_function(&mut self) -> Result<&mut FCG, E>;
fn finalize(self, module_info: &ModuleInfo) -> Result<RM, E>;
fn finalize(self, module_info: &ModuleInfo) -> Result<(RM, Box<dyn CacheGen>), E>;
fn feed_signatures(&mut self, signatures: Map<SigIndex, FuncSig>) -> Result<(), E>;
/// Sets function signatures.
@ -44,7 +57,8 @@ pub trait ModuleCodeGenerator<FCG: FunctionCodeGenerator<E>, RM: RunnableModule,
/// Adds an import function.
fn feed_import_function(&mut self) -> Result<(), E>;
fn feed_compiler_config(&mut self, config: &CompilerConfig) -> Result<(), E> { Ok(()) }
fn feed_compiler_config(&mut self, _config: &CompilerConfig) -> Result<(), E> { Ok(()) }
unsafe fn from_cache(cache: Artifact, _: Token) -> Result<ModuleInner, CacheError>;
}
pub struct StreamingCompiler<
@ -118,15 +132,6 @@ impl<
compiler_config: CompilerConfig,
_: Token,
) -> CompileResult<ModuleInner> {
struct Placeholder;
impl CacheGen for Placeholder {
fn generate_cache(&self) -> Result<(Box<[u8]>, Memory), CacheError> {
Err(CacheError::Unknown(
"the streaming compiler API doesn't support caching yet".to_string(),
))
}
}
let mut mcg = MCG::new();
let mut chain = (self.middleware_chain_generator)();
let info = crate::parse::read_module(
@ -136,22 +141,24 @@ impl<
&mut chain,
&compiler_config,
)?;
let exec_context = mcg
.finalize(&info)
.map_err(|x| CompileError::InternalError {
msg: format!("{:?}", x),
})?;
let (exec_context, cache_gen) =
mcg.finalize(&info)
.map_err(|x| CompileError::InternalError {
msg: format!("{:?}", x),
})?;
Ok(ModuleInner {
cache_gen: Box::new(Placeholder),
cache_gen,
runnable_module: Box::new(exec_context),
info: info,
info,
})
}
unsafe fn from_cache(&self, _artifact: Artifact, _: Token) -> Result<ModuleInner, CacheError> {
Err(CacheError::Unknown(
"the streaming compiler API doesn't support caching yet".to_string(),
))
unsafe fn from_cache(
&self,
artifact: Artifact,
token: Token,
) -> Result<ModuleInner, CacheError> {
MCG::from_cache(artifact, token)
}
}
@ -248,7 +255,7 @@ pub trait FunctionCodeGenerator<E: Debug> {
fn feed_local(&mut self, ty: WpType, n: usize) -> Result<(), E>;
/// Called before the first call to `feed_opcode`.
fn begin_body(&mut self) -> Result<(), E>;
fn begin_body(&mut self, module_info: &ModuleInfo) -> Result<(), E>;
/// Called for each operator.
fn feed_event(&mut self, op: Event, module_info: &ModuleInfo) -> Result<(), E>;

View File

@ -11,7 +11,7 @@ pub type ResolveResult<T> = std::result::Result<T, ResolveError>;
pub type ParseResult<T> = std::result::Result<T, ParseError>;
/// This is returned when the chosen compiler is unable to
/// successfully compile the provided webassembly module into
/// successfully compile the provided WebAssembly module into
/// a `Module`.
///
/// Comparing two `CompileError`s always evaluates to false.
@ -114,7 +114,7 @@ impl std::fmt::Display for LinkError {
impl std::error::Error for LinkError {}
/// This is the error type returned when calling
/// a webassembly function.
/// a WebAssembly function.
///
/// The main way to do this is `Instance.call`.
///
@ -270,7 +270,7 @@ impl std::error::Error for CreationError {}
/// The amalgamation of all errors that can occur
/// during the compilation, instantiation, or execution
/// of a webassembly module.
/// of a WebAssembly module.
///
/// Comparing two `Error`s always evaluates to false.
#[derive(Debug)]

View File

@ -12,7 +12,7 @@ use crate::{
typed_func::{Func, Wasm, WasmTrapInfo, WasmTypeList},
types::{FuncIndex, FuncSig, GlobalIndex, LocalOrImport, MemoryIndex, TableIndex, Type, Value},
vm,
loader::{self, Loader, Instance as _},
loader::Loader,
structures::TypedIndex,
};
use smallvec::{smallvec, SmallVec};
@ -288,7 +288,7 @@ impl Instance {
}
}
/// Call an exported webassembly function given the export name.
/// Call an exported WebAssembly function given the export name.
/// Pass arguments by wrapping each one in the [`Value`] enum.
/// The returned values are also each wrapped in a [`Value`].
///
@ -296,7 +296,7 @@ impl Instance {
///
/// # Note:
/// This returns `CallResult<Vec<Value>>` in order to support
/// the future multi-value returns webassembly feature.
/// the future multi-value returns WebAssembly feature.
///
/// # Usage:
/// ```
@ -627,7 +627,7 @@ pub struct DynFunc<'a> {
}
impl<'a> DynFunc<'a> {
/// Call an exported webassembly function safely.
/// Call an exported WebAssembly function safely.
///
/// Pass arguments by wrapping each one in the [`Value`] enum.
/// The returned values are also each wrapped in a [`Value`].
@ -636,7 +636,7 @@ impl<'a> DynFunc<'a> {
///
/// # Note:
/// This returns `CallResult<Vec<Value>>` in order to support
/// the future multi-value returns webassembly feature.
/// the future multi-value returns WebAssembly feature.
///
/// # Usage:
/// ```

View File

@ -1,3 +1,4 @@
#![deny(unused_imports, unused_variables, unused_unsafe, unreachable_patterns)]
#![cfg_attr(nightly, feature(unwind_attributes))]
#[cfg(test)]

View File

@ -9,7 +9,7 @@ use crate::{
types::Value,
};
use libc::{
c_char, mmap, mprotect, munmap, MAP_ANON, MAP_PRIVATE, PROT_EXEC, PROT_NONE, PROT_READ,
mmap, mprotect, munmap, MAP_ANON, MAP_PRIVATE, PROT_EXEC, PROT_READ,
PROT_WRITE,
};
@ -23,11 +23,11 @@ pub trait Loader {
pub trait Instance {
type Error: Debug;
fn call(&mut self, id: usize, args: &[Value]) -> Result<u64, Self::Error>;
fn read_memory(&mut self, offset: u32, len: u32) -> Result<Vec<u8>, Self::Error> {
fn read_memory(&mut self, _offset: u32, _len: u32) -> Result<Vec<u8>, Self::Error> {
unimplemented!()
}
fn write_memory(&mut self, offset: u32, len: u32, buf: &[u8]) -> Result<(), Self::Error> {
fn write_memory(&mut self, _offset: u32, _len: u32, _buf: &[u8]) -> Result<(), Self::Error> {
unimplemented!()
}
}
@ -38,7 +38,7 @@ impl Loader for LocalLoader {
type Instance = LocalInstance;
type Error = String;
fn load(&self, rm: &dyn RunnableModule, module: &ModuleInfo, ctx: &Ctx) -> Result<Self::Instance, Self::Error> {
fn load(&self, rm: &dyn RunnableModule, _module: &ModuleInfo, _ctx: &Ctx) -> Result<Self::Instance, Self::Error> {
let code = rm.get_code().unwrap();
let mut code_mem = CodeMemory::new(code.len());
code_mem[..code.len()].copy_from_slice(code);

View File

@ -11,7 +11,7 @@ use crate::{
/// This is an internal-only api.
///
/// A static memory allocates 6GB of *virtual* memory when created
/// in order to allow the webassembly module to contain no bounds-checks.
/// in order to allow the WebAssembly module to contain no bounds-checks.
///
/// Additionally, static memories stay at a single virtual address, so there is no need
/// to reload its address on each use.

View File

@ -246,7 +246,7 @@ pub fn read_module<
ParserState::CodeOperator(ref op) => {
if !body_begun {
body_begun = true;
fcg.begin_body()
fcg.begin_body(&info)
.map_err(|x| LoadError::Codegen(format!("{:?}", x)))?;
}
middlewares

View File

@ -23,10 +23,18 @@ struct GlobalSigRegistry {
sig_assoc: Map<SigIndex, Arc<FuncSig>>,
}
/// The `SigRegistry` represents a process-global map of function signatures
/// to signature indexes and vice versa (the map goes both ways).
///
/// This exists for two reasons:
/// 1. The `call_indirect` wasm instruction can compare two signature indices
/// to do signature validation very quickly.
/// 2. To intern function signatures, which may be expensive to create.
#[derive(Debug)]
pub struct SigRegistry;
impl SigRegistry {
/// Map a `FuncSig` to a global `SigIndex`.
pub fn lookup_sig_index<Sig>(&self, func_sig: Sig) -> SigIndex
where
Sig: Into<Arc<FuncSig>>,
@ -45,11 +53,15 @@ impl SigRegistry {
sig_index
}
/// Map a global `SigIndex` to an interned `FuncSig`.
pub fn lookup_signature(&self, sig_index: SigIndex) -> Arc<FuncSig> {
let global = (*GLOBAL_SIG_REGISTRY).read();
Arc::clone(&global.sig_assoc[sig_index])
}
/// Register a function signature with the global signature registry.
///
/// This will return an interned `FuncSig`.
pub fn lookup_signature_ref(&self, func_sig: &FuncSig) -> Arc<FuncSig> {
let mut global = (*GLOBAL_SIG_REGISTRY).write();
let global = &mut *global;

View File

@ -33,7 +33,13 @@ impl Memory {
let protect = protection.to_protect_const();
let ptr = unsafe { VirtualAlloc(ptr::null_mut(), size, MEM_RESERVE, protect) };
let flags = if protection == Protect::None {
MEM_RESERVE
} else {
MEM_RESERVE | MEM_COMMIT
};
let ptr = unsafe { VirtualAlloc(ptr::null_mut(), size, flags, protect) };
if ptr.is_null() {
Err("unable to allocate memory".to_string())
@ -229,3 +235,25 @@ fn round_up_to_page_size(size: usize, page_size: usize) -> usize {
fn round_down_to_page_size(size: usize, page_size: usize) -> usize {
size & !(page_size - 1)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn clone() {
// these should work
let _ = Memory::with_size_protect(200_000, Protect::Read)
.unwrap()
.clone();
let _ = Memory::with_size_protect(200_000, Protect::ReadWrite)
.unwrap()
.clone();
let _ = Memory::with_size_protect(200_000, Protect::ReadExec)
.unwrap()
.clone();
// this would cause segmentation fault as uncommited memory with no access
//let _ = Memory::with_size_protect(200_000, Protect::None).unwrap().clone();
}
}

View File

@ -247,7 +247,7 @@ impl<A: WasmExternType> WasmTypeList for (A,) {
type CStruct = S1<A>;
type RetArray = [u64; 1];
fn from_ret_array(array: Self::RetArray) -> Self {
(WasmExternType::from_native(NativeWasmType::from_bits(
(WasmExternType::from_native(NativeWasmType::from_binary(
array[0],
)),)
}
@ -274,7 +274,7 @@ impl<A: WasmExternType> WasmTypeList for (A,) {
ctx: *mut Ctx,
) -> Result<Rets, RuntimeError> {
let (a,) = self;
let args = [a.to_native().to_bits()];
let args = [a.to_native().to_binary()];
let mut rets = Rets::empty_ret_array();
let mut trap = WasmTrapInfo::Unknown;
let mut user_error = None;
@ -322,7 +322,7 @@ macro_rules! impl_traits {
fn from_ret_array(array: Self::RetArray) -> Self {
#[allow(non_snake_case)]
let [ $( $x ),* ] = array;
( $( WasmExternType::from_native(NativeWasmType::from_bits($x)) ),* )
( $( WasmExternType::from_native(NativeWasmType::from_binary($x)) ),* )
}
fn empty_ret_array() -> Self::RetArray {
[0; count_idents!( $( $x ),* )]
@ -344,7 +344,7 @@ macro_rules! impl_traits {
unsafe fn call<Rets: WasmTypeList>(self, f: NonNull<vm::Func>, wasm: Wasm, ctx: *mut Ctx) -> Result<Rets, RuntimeError> {
#[allow(unused_parens)]
let ( $( $x ),* ) = self;
let args = [ $( $x.to_native().to_bits() ),* ];
let args = [ $( $x.to_native().to_binary()),* ];
let mut rets = Rets::empty_ret_array();
let mut trap = WasmTrapInfo::Unknown;
let mut user_error = None;

View File

@ -85,44 +85,44 @@ where
Self: Sized,
{
const TYPE: Type;
fn from_bits(bits: u64) -> Self;
fn to_bits(self) -> u64;
fn from_binary(bits: u64) -> Self;
fn to_binary(self) -> u64;
}
unsafe impl NativeWasmType for i32 {
const TYPE: Type = Type::I32;
fn from_bits(bits: u64) -> Self {
fn from_binary(bits: u64) -> Self {
bits as _
}
fn to_bits(self) -> u64 {
fn to_binary(self) -> u64 {
self as _
}
}
unsafe impl NativeWasmType for i64 {
const TYPE: Type = Type::I64;
fn from_bits(bits: u64) -> Self {
fn from_binary(bits: u64) -> Self {
bits as _
}
fn to_bits(self) -> u64 {
fn to_binary(self) -> u64 {
self as _
}
}
unsafe impl NativeWasmType for f32 {
const TYPE: Type = Type::F32;
fn from_bits(bits: u64) -> Self {
bits as _
fn from_binary(bits: u64) -> Self {
f32::from_bits(bits as u32)
}
fn to_bits(self) -> u64 {
self as _
fn to_binary(self) -> u64 {
self.to_bits() as _
}
}
unsafe impl NativeWasmType for f64 {
const TYPE: Type = Type::F64;
fn from_bits(bits: u64) -> Self {
bits as _
fn from_binary(bits: u64) -> Self {
f64::from_bits(bits)
}
fn to_bits(self) -> u64 {
self as _
fn to_binary(self) -> u64 {
self.to_bits()
}
}
@ -410,7 +410,7 @@ pub trait LocalImport {
macro_rules! define_map_index {
($ty:ident) => {
#[derive(Serialize, Deserialize)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct $ty (u32);
impl TypedIndex for $ty {
#[doc(hidden)]
@ -525,3 +525,58 @@ where
}
}
}
#[cfg(test)]
mod tests {
use crate::types::NativeWasmType;
use crate::types::WasmExternType;
#[test]
fn test_native_types_round_trip() {
assert_eq!(
42i32,
i32::from_native(i32::from_binary((42i32).to_native().to_binary()))
);
assert_eq!(
-42i32,
i32::from_native(i32::from_binary((-42i32).to_native().to_binary()))
);
use std::i64;
let xi64 = i64::MAX;
assert_eq!(
xi64,
i64::from_native(i64::from_binary((xi64).to_native().to_binary()))
);
let yi64 = i64::MIN;
assert_eq!(
yi64,
i64::from_native(i64::from_binary((yi64).to_native().to_binary()))
);
assert_eq!(
16.5f32,
f32::from_native(f32::from_binary((16.5f32).to_native().to_binary()))
);
assert_eq!(
-16.5f32,
f32::from_native(f32::from_binary((-16.5f32).to_native().to_binary()))
);
use std::f64;
let xf64: f64 = f64::MAX;
assert_eq!(
xf64,
f64::from_native(f64::from_binary((xf64).to_native().to_binary()))
);
let yf64: f64 = f64::MIN;
assert_eq!(
yf64,
f64::from_native(f64::from_binary((yf64).to_native().to_binary()))
);
}
}

View File

@ -3,8 +3,7 @@ use crate::{
memory::{Memory, MemoryType},
module::{ModuleInfo, ModuleInner},
structures::TypedIndex,
types::{LocalOrImport, MemoryIndex, LocalMemoryIndex},
units::{Pages},
types::{LocalOrImport, MemoryIndex},
vmcalls,
};
use std::{ffi::c_void, mem, ptr};
@ -13,7 +12,16 @@ use hashbrown::HashMap;
/// The context of the currently running WebAssembly instance.
///
/// This is implicitly passed to every WebAssembly function.
/// Since this is per-instance, each field has a statically
/// (as in after compiling the wasm) known size, so no
/// runtime checks are necessary.
///
/// While the runtime currently just passes this around
/// as the first, implicit parameter of every function,
/// it may someday be pinned to a register (especially
/// on arm, which has a ton of registers) to reduce
/// register shuffling.
#[derive(Debug)]
#[repr(C)]
pub struct Ctx {
@ -22,11 +30,25 @@ pub struct Ctx {
pub(crate) local_functions: *const *const Func,
/// These are pointers to things that are known to be owned
/// by the owning `Instance`.
local_backing: *mut LocalBacking,
import_backing: *mut ImportBacking,
pub module: *const ModuleInner,
//// This is intended to be user-supplied, per-instance
/// contextual data. There are currently some issue with it,
/// notably that it cannot be set before running the `start`
/// function in a WebAssembly module.
///
/// [#219](https://github.com/wasmerio/wasmer/pull/219) fixes that
/// issue, as well as allowing the user to have *per-function*
/// context, instead of just per-instance.
pub data: *mut c_void,
/// If there's a function set in this field, it gets called
/// when the context is destructed, e.g. when an `Instance`
/// is dropped.
pub data_finalizer: Option<fn(data: *mut c_void)>,
}