Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduced EngineRef and AsEngineRef trait #3378

Merged
merged 11 commits into from
Nov 30, 2022
47 changes: 47 additions & 0 deletions lib/api/src/js/engineref.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
use crate::Tunables;
use wasmer_compiler::Engine;

/// A temporary handle to an [`Engine`] and [`Tunables`].
/// EngineRef can be used to build a [`Module`]
/// It can be created directly with an [`Engine`] and [`Tunables`]
/// Or from anything implementing [`AsEngineRef`]
/// like from [`Store`] typicaly
pub struct EngineRef<'a> {
/// The inner engine
pub(crate) inner: &'a Engine,
/// optionnal tunnables
pub(crate) tunables: &'a dyn Tunables,
}

impl<'a> EngineRef<'a> {
/// Get inner [`Engine`]
pub fn engine(&self) -> &Engine {
self.inner
}
/// Get the [`Tunables`]
pub fn tunables(&self) -> &dyn Tunables {
self.tunables
}
/// Create an EngineRef from an Engine and Tunables
pub fn new(engine: &'a Engine, tunables: &'a dyn Tunables) -> Self {
EngineRef {
inner: engine,
tunables,
}
}
}

/// Helper trait for a value that is convertible to a [`EngineRef`].
pub trait AsEngineRef {
/// Returns a `EngineRef` pointing to the underlying context.
fn as_engine_ref(&self) -> EngineRef<'_>;
}

impl AsEngineRef for EngineRef<'_> {
fn as_engine_ref(&self) -> EngineRef<'_> {
EngineRef {
inner: self.inner,
tunables: self.tunables,
}
}
}
2 changes: 2 additions & 0 deletions lib/api/src/js/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ mod lib {
}
}

mod engineref;
pub(crate) mod error;
mod export;
mod exports;
Expand All @@ -43,6 +44,7 @@ mod types;
mod value;
mod wasm_bindgen_polyfill;

pub use crate::js::engineref::{AsEngineRef, EngineRef};
pub use crate::js::error::{DeserializeError, InstantiationError, SerializeError};
pub use crate::js::export::Export;
pub use crate::js::exports::{ExportError, Exportable, Exports, ExportsIterator};
Expand Down
36 changes: 36 additions & 0 deletions lib/api/src/js/store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,42 @@ impl<T: AsStoreMut> AsStoreMut for &'_ mut T {
}
}

impl AsEngineRef for Store {
fn as_engine_ref(&self) -> EngineRef<'_> {
EngineRef {
inner: &self.engine,
tunables: self.inner.tunables.as_ref(),
}
}
}

impl AsEngineRef for &Store {
fn as_engine_ref(&self) -> EngineRef<'_> {
EngineRef {
inner: &self.engine,
tunables: self.inner.tunables.as_ref(),
}
}
}

impl AsEngineRef for StoreRef<'_> {
fn as_engine_ref(&self) -> EngineRef<'_> {
EngineRef {
inner: &self.inner.engine,
tunables: self.inner.tunables.as_ref(),
}
}
}

impl AsEngineRef for StoreMut<'_> {
fn as_engine_ref(&self) -> EngineRef<'_> {
EngineRef {
inner: &self.inner.engine,
tunables: self.inner.tunables.as_ref(),
}
}
}

pub use objects::*;

mod objects {
Expand Down
47 changes: 47 additions & 0 deletions lib/api/src/sys/engineref.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
use crate::Tunables;
use wasmer_compiler::Engine;

/// A temporary handle to an [`Engine`] and [`Tunables`].
/// EngineRef can be used to build a [`Module`]
/// It can be created directly with an [`Engine`] and [`Tunables`]
/// Or from anything implementing [`AsEngineRef`]
/// like from [`Store`] typicaly
pub struct EngineRef<'a> {
/// The inner engine
pub(crate) inner: &'a Engine,
/// optionnal tunnables
pub(crate) tunables: &'a dyn Tunables,
}

impl<'a> EngineRef<'a> {
/// Get inner [`Engine`]
pub fn engine(&self) -> &Engine {
self.inner
}
/// Get the [`Tunables`]
pub fn tunables(&self) -> &dyn Tunables {
self.tunables
}
/// Create an EngineRef from an Engine and Tunables
pub fn new(engine: &'a Engine, tunables: &'a dyn Tunables) -> Self {
EngineRef {
inner: engine,
tunables,
}
}
}

/// Helper trait for a value that is convertible to a [`EngineRef`].
pub trait AsEngineRef {
/// Returns a `EngineRef` pointing to the underlying context.
fn as_engine_ref(&self) -> EngineRef<'_>;
}

impl AsEngineRef for EngineRef<'_> {
fn as_engine_ref(&self) -> EngineRef<'_> {
EngineRef {
inner: self.inner,
tunables: self.tunables,
}
}
}
2 changes: 2 additions & 0 deletions lib/api/src/sys/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
mod engineref;
mod exports;
mod extern_ref;
mod externals;
Expand All @@ -13,6 +14,7 @@ mod store;
mod tunables;
mod value;

pub use crate::sys::engineref::{AsEngineRef, EngineRef};
pub use crate::sys::exports::{ExportError, Exportable, Exports, ExportsIterator};
pub use crate::sys::extern_ref::ExternRef;
pub use crate::sys::externals::{
Expand Down
31 changes: 16 additions & 15 deletions lib/api/src/sys/module.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::sys::InstantiationError;
use crate::AsEngineRef;
use crate::AsStoreMut;
use crate::AsStoreRef;
use bytes::Bytes;
Expand Down Expand Up @@ -159,27 +160,27 @@ impl Module {
/// # }
/// ```
#[allow(unreachable_code)]
pub fn new(store: &impl AsStoreRef, bytes: impl AsRef<[u8]>) -> Result<Self, CompileError> {
pub fn new(engine: &impl AsEngineRef, bytes: impl AsRef<[u8]>) -> Result<Self, CompileError> {
#[cfg(feature = "wat")]
let bytes = wat::parse_bytes(bytes.as_ref()).map_err(|e| {
CompileError::Wasm(WasmError::Generic(format!(
"Error when converting wat: {}",
e
)))
})?;
Self::from_binary(store, bytes.as_ref())
Self::from_binary(engine, bytes.as_ref())
}

#[cfg(feature = "compiler")]
/// Creates a new WebAssembly module from a file path.
pub fn from_file(
store: &impl AsStoreRef,
engine: &impl AsEngineRef,
file: impl AsRef<Path>,
) -> Result<Self, IoCompileError> {
let file_ref = file.as_ref();
let canonical = file_ref.canonicalize()?;
let wasm_bytes = std::fs::read(file_ref)?;
let mut module = Self::new(store, &wasm_bytes)?;
let mut module = Self::new(engine, &wasm_bytes)?;
// Set the module name to the absolute path of the filename.
// This is useful for debugging the stack traces.
let filename = canonical.as_path().to_str().unwrap();
Expand All @@ -193,9 +194,9 @@ impl Module {
/// Opposed to [`Module::new`], this function is not compatible with
/// the WebAssembly text format (if the "wat" feature is enabled for
/// this crate).
pub fn from_binary(store: &impl AsStoreRef, binary: &[u8]) -> Result<Self, CompileError> {
Self::validate(store, binary)?;
unsafe { Self::from_binary_unchecked(store, binary) }
pub fn from_binary(engine: &impl AsEngineRef, binary: &[u8]) -> Result<Self, CompileError> {
Self::validate(engine, binary)?;
unsafe { Self::from_binary_unchecked(engine, binary) }
}

#[cfg(feature = "compiler")]
Expand All @@ -207,10 +208,10 @@ impl Module {
/// in environments where the WebAssembly modules are trusted and validated
/// beforehand.
pub unsafe fn from_binary_unchecked(
store: &impl AsStoreRef,
engine: &impl AsEngineRef,
binary: &[u8],
) -> Result<Self, CompileError> {
let module = Self::compile(store, binary)?;
let module = Self::compile(engine, binary)?;
Ok(module)
}

Expand All @@ -221,16 +222,16 @@ impl Module {
/// This validation is normally pretty fast and checks the enabled
/// WebAssembly features in the Store Engine to assure deterministic
/// validation of the Module.
pub fn validate(store: &impl AsStoreRef, binary: &[u8]) -> Result<(), CompileError> {
store.as_store_ref().engine().validate(binary)
pub fn validate(engine: &impl AsEngineRef, binary: &[u8]) -> Result<(), CompileError> {
engine.as_engine_ref().engine().validate(binary)
}

#[cfg(feature = "compiler")]
fn compile(store: &impl AsStoreRef, binary: &[u8]) -> Result<Self, CompileError> {
let artifact = store
.as_store_ref()
fn compile(engine: &impl AsEngineRef, binary: &[u8]) -> Result<Self, CompileError> {
let artifact = engine
.as_engine_ref()
.engine()
.compile(binary, store.as_store_ref().tunables())?;
.compile(binary, engine.as_engine_ref().tunables())?;
Ok(Self::from_artifact(artifact))
}

Expand Down
37 changes: 37 additions & 0 deletions lib/api/src/sys/store.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::sys::engineref::{AsEngineRef, EngineRef};
use crate::sys::tunables::BaseTunables;
use std::fmt;
use std::sync::{Arc, RwLock};
Expand Down Expand Up @@ -202,6 +203,42 @@ impl AsStoreMut for Store {
}
}

impl AsEngineRef for Store {
fn as_engine_ref(&self) -> EngineRef<'_> {
EngineRef {
inner: &self.engine,
tunables: self.inner.tunables.as_ref(),
}
}
}

impl AsEngineRef for &Store {
fn as_engine_ref(&self) -> EngineRef<'_> {
EngineRef {
inner: &self.engine,
tunables: self.inner.tunables.as_ref(),
}
}
}

impl AsEngineRef for StoreRef<'_> {
fn as_engine_ref(&self) -> EngineRef<'_> {
EngineRef {
inner: &self.inner.engine,
tunables: self.inner.tunables.as_ref(),
}
}
}

impl AsEngineRef for StoreMut<'_> {
fn as_engine_ref(&self) -> EngineRef<'_> {
EngineRef {
inner: &self.inner.engine,
tunables: self.inner.tunables.as_ref(),
}
}
}

impl fmt::Debug for Store {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Store").finish()
Expand Down
58 changes: 58 additions & 0 deletions lib/types/src/basetunables.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
use crate::units::Pages;
use crate::compilation::target::{PointerWidth, Target};

/// Tunable parameters for WebAssembly compilation.
/// This is the reference implementation of the `Tunables` trait,
/// used by default.
///
/// You can use this as a template for creating a custom Tunables
/// implementation or use composition to wrap your Tunables around
/// this one. The later approach is demonstrated in the
/// tunables-limit-memory example.
#[derive(Clone)]
pub struct BaseTunables {
/// For static heaps, the size in wasm pages of the heap protected by bounds checking.
pub static_memory_bound: Pages,

/// The size in bytes of the offset guard for static heaps.
pub static_memory_offset_guard_size: u64,

/// The size in bytes of the offset guard for dynamic heaps.
pub dynamic_memory_offset_guard_size: u64,
}
ptitSeb marked this conversation as resolved.
Show resolved Hide resolved

impl BaseTunables {
/// Get the `BaseTunables` for a specific Target
pub fn for_target(target: &Target) -> Self {
let triple = target.triple();
let pointer_width: PointerWidth = triple.pointer_width().unwrap();
let (static_memory_bound, static_memory_offset_guard_size): (Pages, u64) =
match pointer_width {
PointerWidth::U16 => (0x400.into(), 0x1000),
PointerWidth::U32 => (0x4000.into(), 0x1_0000),
// Static Memory Bound:
// Allocating 4 GiB of address space let us avoid the
// need for explicit bounds checks.
// Static Memory Guard size:
// Allocating 2 GiB of address space lets us translate wasm
// offsets into x86 offsets as aggressively as we can.
PointerWidth::U64 => (0x1_0000.into(), 0x8000_0000),
};

// Allocate a small guard to optimize common cases but without
// wasting too much memory.
// The Windows memory manager seems more laxed than the other ones
// And a guard of just 1 page may not be enough is some borderline cases
// So using 2 pages for guard on this platform
#[cfg(target_os = "windows")]
let dynamic_memory_offset_guard_size: u64 = 0x2_0000;
#[cfg(not(target_os = "windows"))]
let dynamic_memory_offset_guard_size: u64 = 0x1_0000;

Self {
static_memory_bound,
static_memory_offset_guard_size,
dynamic_memory_offset_guard_size,
}
}
}