mirror of
https://github.com/fluencelabs/wasmer
synced 2025-06-20 20:26:32 +00:00
Merge remote-tracking branch 'origin/master' into feature/remote-code-load
This commit is contained in:
@ -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,
|
||||
|
@ -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>;
|
||||
|
@ -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)]
|
||||
|
@ -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:
|
||||
/// ```
|
||||
|
@ -1,3 +1,4 @@
|
||||
#![deny(unused_imports, unused_variables, unused_unsafe, unreachable_patterns)]
|
||||
#![cfg_attr(nightly, feature(unwind_attributes))]
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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()))
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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)>,
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user