mirror of
https://github.com/mii443/wasmer.git
synced 2025-12-11 07:08:21 +00:00
Merge remote-tracking branch 'origin/master' into singlepass
This commit is contained in:
4
Cargo.lock
generated
4
Cargo.lock
generated
@@ -1224,9 +1224,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "smallvec"
|
name = "smallvec"
|
||||||
version = "1.3.0"
|
version = "1.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "05720e22615919e4734f6a99ceae50d00226c3c5aca406e102ebc33298214e0a"
|
checksum = "c7cb5678e1615754284ec264d9bb5b4c27d2018577fd90ac0ceb578591ed5ee4"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "stable_deref_trait"
|
name = "stable_deref_trait"
|
||||||
|
|||||||
32
Cargo.toml
32
Cargo.toml
@@ -20,16 +20,16 @@ publish = false
|
|||||||
autoexamples = false
|
autoexamples = false
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
wasmer = { path = "lib/api" }
|
wasmer = { version = "0.16.2", path = "lib/api" }
|
||||||
wasmer-compiler = { path = "lib/compiler" }
|
wasmer-compiler = { version = "0.16.2", path = "lib/compiler" }
|
||||||
wasmer-compiler-cranelift = { path = "lib/compiler-cranelift", optional = true }
|
wasmer-compiler-cranelift = { version = "0.16.2", path = "lib/compiler-cranelift", optional = true }
|
||||||
wasmer-compiler-singlepass = { path = "lib/compiler-singlepass", optional = true }
|
wasmer-compiler-singlepass = { version = "0.16.2", path = "lib/compiler-singlepass", optional = true }
|
||||||
wasmer-compiler-llvm = { path = "lib/compiler-llvm", optional = true }
|
wasmer-compiler-llvm = { version = "0.16.2", path = "lib/compiler-llvm", optional = true }
|
||||||
wasmer-jit = { path = "lib/jit" }
|
wasmer-jit = { version = "0.16.2", path = "lib/jit" }
|
||||||
wasmer-wasi = { path = "lib/wasi", optional = true }
|
wasmer-wasi = { version = "0.16.2", path = "lib/wasi", optional = true }
|
||||||
wasmer-wasi-experimental-io-devices = { path = "lib/wasi-experimental-io-devices", optional = true }
|
wasmer-wasi-experimental-io-devices = { version = "0.16.2", path = "lib/wasi-experimental-io-devices", optional = true }
|
||||||
wasmer-wast = { path = "tests/lib/wast", optional = true }
|
wasmer-wast = { version = "0.16.2", path = "tests/lib/wast", optional = true }
|
||||||
wasmer-cache = { path = "lib/cache", optional = true }
|
wasmer-cache = { version = "0.16.2", path = "lib/cache", optional = true }
|
||||||
atty = "0.2"
|
atty = "0.2"
|
||||||
anyhow = "1.0.28"
|
anyhow = "1.0.28"
|
||||||
structopt = { version = "0.3", features = ["suggestions"] }
|
structopt = { version = "0.3", features = ["suggestions"] }
|
||||||
@@ -47,19 +47,15 @@ rustc_version = "0.2"
|
|||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
anyhow = "1.0.28"
|
anyhow = "1.0.28"
|
||||||
test-utils = { path = "tests/lib/test-utils" }
|
test-utils = { path = "tests/lib/test-utils" }
|
||||||
wasmer = { path = "lib/api" }
|
|
||||||
wasmer-compiler = { path = "lib/compiler" }
|
|
||||||
wasmer-jit = { path = "lib/jit" }
|
|
||||||
wasmer-wast = { path = "tests/lib/wast" }
|
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
# Don't add the backend features in default, please add them on the Makefile
|
# Don't add the backend features in default, please add them on the Makefile
|
||||||
# since we might want to autoconfigure them depending on the availability on the host.
|
# since we might want to autoconfigure them depending on the availability on the host.
|
||||||
# default = ["wasi"]
|
|
||||||
default = ["wast", "wasi", "experimental-io-devices", "compiler-cranelift", "cache"]
|
default = ["wast", "wasi", "experimental-io-devices", "compiler-cranelift", "cache"]
|
||||||
cache = ["wasmer-cache"]
|
cache = ["wasmer-cache"]
|
||||||
wast = ["wasmer-wast"]
|
wast = ["wasmer-wast"]
|
||||||
wasi = ["wasmer-wasi"]
|
wasi = ["wasmer-wasi"]
|
||||||
|
compiler = ["wasmer-jit/compiler"]
|
||||||
experimental-io-devices = [
|
experimental-io-devices = [
|
||||||
"wasmer-wasi-experimental-io-devices"
|
"wasmer-wasi-experimental-io-devices"
|
||||||
]
|
]
|
||||||
@@ -67,14 +63,20 @@ compiler-singlepass = [
|
|||||||
"test-utils/compiler-singlepass",
|
"test-utils/compiler-singlepass",
|
||||||
"wasmer/compiler-singlepass",
|
"wasmer/compiler-singlepass",
|
||||||
"wasmer-compiler-singlepass",
|
"wasmer-compiler-singlepass",
|
||||||
|
"compiler",
|
||||||
]
|
]
|
||||||
compiler-cranelift = [
|
compiler-cranelift = [
|
||||||
"test-utils/compiler-cranelift",
|
"test-utils/compiler-cranelift",
|
||||||
"wasmer/compiler-cranelift",
|
"wasmer/compiler-cranelift",
|
||||||
"wasmer-compiler-cranelift",
|
"wasmer-compiler-cranelift",
|
||||||
|
"compiler",
|
||||||
]
|
]
|
||||||
compiler-llvm = [
|
compiler-llvm = [
|
||||||
"test-utils/compiler-llvm",
|
"test-utils/compiler-llvm",
|
||||||
"wasmer/compiler-llvm",
|
"wasmer/compiler-llvm",
|
||||||
"wasmer-compiler-llvm",
|
"wasmer-compiler-llvm",
|
||||||
|
"compiler",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# [profile.release]
|
||||||
|
# lto = "fat"
|
||||||
|
|||||||
@@ -38,14 +38,18 @@ maintenance = { status = "actively-developed" }
|
|||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["wat", "default-compiler-cranelift"]
|
default = ["wat", "default-compiler-cranelift"]
|
||||||
|
compiler = ["wasmer-jit/compiler"]
|
||||||
compiler-singlepass = [
|
compiler-singlepass = [
|
||||||
"wasmer-compiler-singlepass"
|
"wasmer-compiler-singlepass",
|
||||||
|
"compiler",
|
||||||
]
|
]
|
||||||
compiler-cranelift = [
|
compiler-cranelift = [
|
||||||
"wasmer-compiler-cranelift"
|
"wasmer-compiler-cranelift",
|
||||||
|
"compiler",
|
||||||
]
|
]
|
||||||
compiler-llvm = [
|
compiler-llvm = [
|
||||||
"wasmer-compiler-llvm"
|
"wasmer-compiler-llvm",
|
||||||
|
"compiler",
|
||||||
]
|
]
|
||||||
default-compiler-singlepass = [
|
default-compiler-singlepass = [
|
||||||
"compiler-singlepass"
|
"compiler-singlepass"
|
||||||
|
|||||||
@@ -231,7 +231,9 @@ fn set_table_item(
|
|||||||
impl Table {
|
impl Table {
|
||||||
pub fn new(store: &Store, ty: TableType, init: Val) -> Result<Table, RuntimeError> {
|
pub fn new(store: &Store, ty: TableType, init: Val) -> Result<Table, RuntimeError> {
|
||||||
let item = init.into_checked_anyfunc(store)?;
|
let item = init.into_checked_anyfunc(store)?;
|
||||||
let table = store.engine().tunables().create_table(ty);
|
let tunables = store.engine().tunables();
|
||||||
|
let table_plan = tunables.table_plan(ty);
|
||||||
|
let table = tunables.create_table(table_plan).unwrap();
|
||||||
|
|
||||||
let definition = table.vmtable();
|
let definition = table.vmtable();
|
||||||
for i in 0..definition.current_elements {
|
for i in 0..definition.current_elements {
|
||||||
@@ -345,7 +347,10 @@ pub struct Memory {
|
|||||||
|
|
||||||
impl Memory {
|
impl Memory {
|
||||||
pub fn new(store: &Store, ty: MemoryType) -> Memory {
|
pub fn new(store: &Store, ty: MemoryType) -> Memory {
|
||||||
let memory = store.engine().tunables().create_memory(ty).unwrap();
|
let tunables = store.engine().tunables();
|
||||||
|
let memory_plan = tunables.memory_plan(ty);
|
||||||
|
let memory = tunables.create_memory(memory_plan).unwrap();
|
||||||
|
|
||||||
let definition = memory.vmmemory();
|
let definition = memory.vmmemory();
|
||||||
|
|
||||||
Memory {
|
Memory {
|
||||||
|
|||||||
@@ -194,13 +194,15 @@ impl Extend<((String, String), Export)> for ImportObject {
|
|||||||
///
|
///
|
||||||
///
|
///
|
||||||
/// # Usage:
|
/// # Usage:
|
||||||
/// ```ignore
|
/// ```
|
||||||
/// use wasmer::{imports, func};
|
/// # use wasmer::{Func, Store};
|
||||||
|
/// # let store = Store::default();
|
||||||
|
/// use wasmer::imports;
|
||||||
///
|
///
|
||||||
/// let import_object = imports! {
|
/// let import_object = imports! {
|
||||||
/// "env" => {
|
/// "env" => {
|
||||||
/// "foo" => func!(foo),
|
/// "foo" => Func::new(&store, foo)
|
||||||
/// },
|
/// }
|
||||||
/// };
|
/// };
|
||||||
///
|
///
|
||||||
/// fn foo(n: i32) -> i32 {
|
/// fn foo(n: i32) -> i32 {
|
||||||
@@ -224,24 +226,8 @@ macro_rules! imports {
|
|||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generate an [`Namespace`] easily with the `namespace!` macro.
|
|
||||||
///
|
|
||||||
/// [`Namespace`]: struct.Namespace.html
|
|
||||||
///
|
|
||||||
///
|
|
||||||
/// # Usage:
|
|
||||||
/// ```ignore
|
|
||||||
/// use wasmer::{namespace, func};
|
|
||||||
///
|
|
||||||
/// let env = namespace! {
|
|
||||||
/// "foo" => func!(foo),
|
|
||||||
/// };
|
|
||||||
///
|
|
||||||
/// fn foo(n: i32) -> i32 {
|
|
||||||
/// n
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
|
#[doc(hidden)]
|
||||||
macro_rules! namespace {
|
macro_rules! namespace {
|
||||||
($( $imp_name:expr => $import_item:expr ),* $(,)? ) => {
|
($( $imp_name:expr => $import_item:expr ),* $(,)? ) => {
|
||||||
$crate::import_namespace!({ $( $imp_name => $import_item, )* })
|
$crate::import_namespace!({ $( $imp_name => $import_item, )* })
|
||||||
|
|||||||
@@ -27,7 +27,10 @@ pub use crate::types::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub use wasm_common::{ValueType, WasmExternType, WasmTypeList};
|
pub use wasm_common::{ValueType, WasmExternType, WasmTypeList};
|
||||||
pub use wasmer_compiler::{CompilerConfig, Features, Target};
|
#[cfg(feature = "compiler")]
|
||||||
|
pub use wasmer_compiler::CompilerConfig;
|
||||||
|
pub use wasmer_compiler::{Features, Target};
|
||||||
|
|
||||||
pub use wasmer_jit::{
|
pub use wasmer_jit::{
|
||||||
DeserializeError, InstantiationError, LinkError, RuntimeError, SerializeError,
|
DeserializeError, InstantiationError, LinkError, RuntimeError, SerializeError,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -184,7 +184,17 @@ impl Module {
|
|||||||
&self,
|
&self,
|
||||||
resolver: &dyn Resolver,
|
resolver: &dyn Resolver,
|
||||||
) -> Result<InstanceHandle, InstantiationError> {
|
) -> Result<InstanceHandle, InstantiationError> {
|
||||||
self.store.engine().instantiate(&self.compiled, resolver)
|
unsafe {
|
||||||
|
let instance_handle = self.store.engine().instantiate(&self.compiled, resolver)?;
|
||||||
|
|
||||||
|
// After the instance handle is created, we need to initialize
|
||||||
|
// the data, call the start function and so. However, if any
|
||||||
|
// of this steps traps, we still need to keep the instance alive
|
||||||
|
// as some of the Instance elements may have placed in other
|
||||||
|
// instance tables.
|
||||||
|
self.compiled.finish_instantiation(&instance_handle)?;
|
||||||
|
Ok(instance_handle)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the name of the current module.
|
/// Returns the name of the current module.
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
use wasmer_jit::Resolver;
|
|
||||||
use std::iter::FromIterator;
|
|
||||||
|
|
||||||
pub struct IndexResolver {
|
|
||||||
externs: Vec<Extern>,
|
|
||||||
}
|
|
||||||
impl Resolver for IndexResolver {
|
|
||||||
fn resolve(&self, index: u32, _module: &str, _name: &str) -> Option<Export> {
|
|
||||||
self.externs.get(index as usize).map(|extern_| extern_.to_export())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FromIterator<Extern> for IndexResolver {
|
|
||||||
fn from_iter<I: IntoIterator<Item = Extern>>(iter: I) -> Self {
|
|
||||||
let mut externs = Vec::new();
|
|
||||||
for extern_ in iter {
|
|
||||||
externs.push(extern_);
|
|
||||||
}
|
|
||||||
IndexResolver { externs }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
use crate::tunables::Tunables;
|
use crate::tunables::Tunables;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
#[cfg(feature = "compiler")]
|
||||||
use wasmer_compiler::CompilerConfig;
|
use wasmer_compiler::CompilerConfig;
|
||||||
use wasmer_jit::JITEngine;
|
use wasmer_jit::JITEngine;
|
||||||
|
|
||||||
|
|||||||
@@ -92,14 +92,12 @@ impl wasmer_jit::Tunables for Tunables {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Create a memory given a memory type
|
/// Create a memory given a memory type
|
||||||
fn create_memory(&self, memory_type: MemoryType) -> Result<LinearMemory, String> {
|
fn create_memory(&self, plan: MemoryPlan) -> Result<LinearMemory, String> {
|
||||||
let plan = self.memory_plan(memory_type);
|
|
||||||
LinearMemory::new(&plan)
|
LinearMemory::new(&plan)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a memory given a memory type
|
/// Create a memory given a memory type
|
||||||
fn create_table(&self, table_type: TableType) -> Table {
|
fn create_table(&self, plan: TablePlan) -> Result<Table, String> {
|
||||||
let plan = self.table_plan(table_type);
|
|
||||||
Table::new(&plan)
|
Table::new(&plan)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ hashbrown = { version = "0.7.2", optional = true }
|
|||||||
tracing = "0.1"
|
tracing = "0.1"
|
||||||
cranelift-codegen = { version = "0.62.0", default-features = false }
|
cranelift-codegen = { version = "0.62.0", default-features = false }
|
||||||
cranelift-frontend = { version = "0.62.0", default-features = false }
|
cranelift-frontend = { version = "0.62.0", default-features = false }
|
||||||
wasmer-compiler = { path = "../compiler", version = "0.16.2", default-features = false }
|
wasmer-compiler = { path = "../compiler", version = "0.16.2", features = ["translator"], default-features = false }
|
||||||
wasmer-runtime = { path = "../runtime", version = "0.16.2" }
|
wasmer-runtime = { path = "../runtime", version = "0.16.2" }
|
||||||
wasm-common = { path = "../wasm-common", version = "0.16.2", default-features = false }
|
wasm-common = { path = "../wasm-common", version = "0.16.2", default-features = false }
|
||||||
rayon = "1.3.0"
|
rayon = "1.3.0"
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ edition = "2018"
|
|||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
wasmer-compiler = { path = "../compiler", version = "0.16.2" }
|
wasmer-compiler = { path = "../compiler", version = "0.16.2", features = ["translator"] }
|
||||||
wasmer-runtime = { path = "../runtime", version = "0.16.2" }
|
wasmer-runtime = { path = "../runtime", version = "0.16.2" }
|
||||||
wasm-common = { path = "../wasm-common", version = "0.16.2" }
|
wasm-common = { path = "../wasm-common", version = "0.16.2" }
|
||||||
target-lexicon = { version = "0.10.0", default-features = false }
|
target-lexicon = { version = "0.10.0", default-features = false }
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ use wasm_common::{FuncIndex, FuncType, LocalFuncIndex, MemoryIndex, TableIndex};
|
|||||||
use wasmer_compiler::{
|
use wasmer_compiler::{
|
||||||
Compilation, CompileError, CompiledFunction, Compiler, CompilerConfig, CustomSection,
|
Compilation, CompileError, CompiledFunction, Compiler, CompilerConfig, CustomSection,
|
||||||
CustomSectionProtection, FunctionBody, FunctionBodyData, ModuleTranslationState, Relocation,
|
CustomSectionProtection, FunctionBody, FunctionBodyData, ModuleTranslationState, Relocation,
|
||||||
RelocationTarget, SectionIndex, Target, TrapInformation,
|
RelocationTarget, SectionBody, SectionIndex, Target, TrapInformation,
|
||||||
};
|
};
|
||||||
use wasmer_runtime::{MemoryPlan, Module, TablePlan, TrapCode};
|
use wasmer_runtime::{MemoryPlan, Module, TablePlan, TrapCode};
|
||||||
|
|
||||||
@@ -71,7 +71,7 @@ impl Compiler for LLVMCompiler {
|
|||||||
let mut used_readonly_section = false;
|
let mut used_readonly_section = false;
|
||||||
let mut readonly_section = CustomSection {
|
let mut readonly_section = CustomSection {
|
||||||
protection: CustomSectionProtection::Read,
|
protection: CustomSectionProtection::Read,
|
||||||
bytes: Vec::new(),
|
bytes: SectionBody::default(),
|
||||||
};
|
};
|
||||||
|
|
||||||
for (func_index, _) in &module.functions {
|
for (func_index, _) in &module.functions {
|
||||||
@@ -112,7 +112,7 @@ impl Compiler for LLVMCompiler {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
let offset = section.bytes.len() as i64;
|
let offset = section.bytes.len() as i64;
|
||||||
section.bytes.extend(&custom_section.bytes);
|
section.bytes.append(&custom_section.bytes);
|
||||||
// TODO: we're needlessly rescanning the whole list.
|
// TODO: we're needlessly rescanning the whole list.
|
||||||
for local_relocation in &local_relocations {
|
for local_relocation in &local_relocations {
|
||||||
if local_relocation.local_section_index == local_idx {
|
if local_relocation.local_section_index == local_idx {
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ use wasmer_compiler::{
|
|||||||
to_wasm_error, wasm_unsupported, Addend, CodeOffset, CompileError, CompiledFunction,
|
to_wasm_error, wasm_unsupported, Addend, CodeOffset, CompileError, CompiledFunction,
|
||||||
CompiledFunctionFrameInfo, CompiledFunctionUnwindInfo, CustomSection, CustomSectionProtection,
|
CompiledFunctionFrameInfo, CompiledFunctionUnwindInfo, CustomSection, CustomSectionProtection,
|
||||||
FunctionAddressMap, FunctionBody, FunctionBodyData, Relocation, RelocationKind,
|
FunctionAddressMap, FunctionBody, FunctionBodyData, Relocation, RelocationKind,
|
||||||
RelocationTarget, SourceLoc, WasmResult,
|
RelocationTarget, SectionBody, SourceLoc, WasmResult,
|
||||||
};
|
};
|
||||||
use wasmer_runtime::libcalls::LibCall;
|
use wasmer_runtime::libcalls::LibCall;
|
||||||
use wasmer_runtime::Module as WasmerCompilerModule;
|
use wasmer_runtime::Module as WasmerCompilerModule;
|
||||||
@@ -384,7 +384,7 @@ impl FuncTranslator {
|
|||||||
required_custom_sections.len(),
|
required_custom_sections.len(),
|
||||||
CustomSection {
|
CustomSection {
|
||||||
protection: CustomSectionProtection::Read,
|
protection: CustomSectionProtection::Read,
|
||||||
bytes: vec![],
|
bytes: SectionBody::default(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
for section in object.get_sections() {
|
for section in object.get_sections() {
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ edition = "2018"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
hashbrown = { version = "0.7.2", optional = true }
|
hashbrown = { version = "0.7.2", optional = true }
|
||||||
wasmer-compiler = { path = "../compiler", version = "0.16.2", default-features = false }
|
wasmer-compiler = { path = "../compiler", version = "0.16.2", features = ["translator"], default-features = false }
|
||||||
wasmer-runtime = { path = "../runtime", version = "0.16.2" }
|
wasmer-runtime = { path = "../runtime", version = "0.16.2" }
|
||||||
wasm-common = { path = "../wasm-common", version = "0.16.2", default-features = false }
|
wasm-common = { path = "../wasm-common", version = "0.16.2", default-features = false }
|
||||||
rayon = "1.3.0"
|
rayon = "1.3.0"
|
||||||
|
|||||||
@@ -26,6 +26,10 @@ raw-cpuid = "7.0.3"
|
|||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["std", "enable-serde"]
|
default = ["std", "enable-serde"]
|
||||||
|
# This feature is for compiler implementors, it enables using `Compiler` and
|
||||||
|
# `CompilerConfig`, as well as the included wasmparser.
|
||||||
|
# Disable this feature if you just want a headless engine.
|
||||||
|
translator = []
|
||||||
std = []
|
std = []
|
||||||
core = ["hashbrown"]
|
core = ["hashbrown"]
|
||||||
enable-serde = ["serde", "serde_bytes"]
|
enable-serde = ["serde", "serde_bytes"]
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
//! This module mainly outputs the `Compiler` trait that custom
|
//! This module mainly outputs the `Compiler` trait that custom
|
||||||
//! compilers will need to implement.
|
//! compilers will need to implement.
|
||||||
|
|
||||||
use crate::config::Target;
|
|
||||||
use crate::error::CompileError;
|
use crate::error::CompileError;
|
||||||
use crate::function::{Compilation, FunctionBody};
|
use crate::function::{Compilation, FunctionBody};
|
||||||
|
use crate::std::boxed::Box;
|
||||||
use crate::std::vec::Vec;
|
use crate::std::vec::Vec;
|
||||||
|
use crate::target::Target;
|
||||||
use crate::FunctionBodyData;
|
use crate::FunctionBodyData;
|
||||||
use crate::ModuleTranslationState;
|
use crate::ModuleTranslationState;
|
||||||
use wasm_common::entity::PrimaryMap;
|
use wasm_common::entity::PrimaryMap;
|
||||||
@@ -13,6 +14,22 @@ use wasmer_runtime::Module;
|
|||||||
use wasmer_runtime::{MemoryPlan, TablePlan};
|
use wasmer_runtime::{MemoryPlan, TablePlan};
|
||||||
use wasmparser::{validate, OperatorValidatorConfig, ValidatingParserConfig};
|
use wasmparser::{validate, OperatorValidatorConfig, ValidatingParserConfig};
|
||||||
|
|
||||||
|
/// The compiler configuration options.
|
||||||
|
///
|
||||||
|
/// This options must have WebAssembly `Features` and a specific
|
||||||
|
/// `Target` to compile to.
|
||||||
|
pub trait CompilerConfig {
|
||||||
|
/// Gets the WebAssembly features
|
||||||
|
fn features(&self) -> &Features;
|
||||||
|
|
||||||
|
/// Gets the target that we will use for compiling
|
||||||
|
/// the WebAssembly module
|
||||||
|
fn target(&self) -> &Target;
|
||||||
|
|
||||||
|
/// Gets the custom compiler config
|
||||||
|
fn compiler(&self) -> Box<dyn Compiler>;
|
||||||
|
}
|
||||||
|
|
||||||
/// An implementation of a Compiler from parsed WebAssembly module to Compiled native code.
|
/// An implementation of a Compiler from parsed WebAssembly module to Compiled native code.
|
||||||
pub trait Compiler {
|
pub trait Compiler {
|
||||||
/// Gets the target associated with this compiler
|
/// Gets the target associated with this compiler
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
use crate::std::string::String;
|
use crate::std::string::String;
|
||||||
use crate::translator::WasmError;
|
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
// Compilation Errors
|
// Compilation Errors
|
||||||
@@ -28,3 +27,39 @@ pub enum CompileError {
|
|||||||
#[error("Insufficient resources: {0}")]
|
#[error("Insufficient resources: {0}")]
|
||||||
Resource(String),
|
Resource(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A WebAssembly translation error.
|
||||||
|
///
|
||||||
|
/// When a WebAssembly function can't be translated, one of these error codes will be returned
|
||||||
|
/// to describe the failure.
|
||||||
|
#[derive(Error, Debug)]
|
||||||
|
pub enum WasmError {
|
||||||
|
/// The input WebAssembly code is invalid.
|
||||||
|
///
|
||||||
|
/// This error code is used by a WebAssembly translator when it encounters invalid WebAssembly
|
||||||
|
/// code. This should never happen for validated WebAssembly code.
|
||||||
|
#[error("Invalid input WebAssembly code at offset {offset}: {message}")]
|
||||||
|
InvalidWebAssembly {
|
||||||
|
/// A string describing the validation error.
|
||||||
|
message: String,
|
||||||
|
/// The bytecode offset where the error occurred.
|
||||||
|
offset: usize,
|
||||||
|
},
|
||||||
|
|
||||||
|
/// A feature used by the WebAssembly code is not supported by the embedding environment.
|
||||||
|
///
|
||||||
|
/// Embedding environments may have their own limitations and feature restrictions.
|
||||||
|
#[error("Unsupported feature: {0}")]
|
||||||
|
Unsupported(String),
|
||||||
|
|
||||||
|
/// An implementation limit was exceeded.
|
||||||
|
#[error("Implementation limit exceeded")]
|
||||||
|
ImplLimitExceeded,
|
||||||
|
|
||||||
|
/// A generic error.
|
||||||
|
#[error("{0}")]
|
||||||
|
Generic(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A convenient alias for a `Result` that uses `WasmError` as the error type.
|
||||||
|
pub type WasmResult<T> = Result<T, WasmError>;
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
//! * `jit`: to generate a JIT
|
//! * `jit`: to generate a JIT
|
||||||
//! * `obj`: to generate a native object
|
//! * `obj`: to generate a native object
|
||||||
|
|
||||||
use crate::section::{CustomSection, SectionIndex};
|
use crate::section::{CustomSection, SectionBody, SectionIndex};
|
||||||
use crate::std::vec::Vec;
|
use crate::std::vec::Vec;
|
||||||
use crate::trap::TrapInformation;
|
use crate::trap::TrapInformation;
|
||||||
use crate::{CompiledFunctionUnwindInfo, FunctionAddressMap, JumpTableOffsets, Relocation};
|
use crate::{CompiledFunctionUnwindInfo, FunctionAddressMap, JumpTableOffsets, Relocation};
|
||||||
@@ -130,6 +130,14 @@ impl Compilation {
|
|||||||
.map(|(_, func)| func.frame_info.clone())
|
.map(|(_, func)| func.frame_info.clone())
|
||||||
.collect::<PrimaryMap<LocalFuncIndex, _>>()
|
.collect::<PrimaryMap<LocalFuncIndex, _>>()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets custom section data.
|
||||||
|
pub fn get_custom_sections(&self) -> PrimaryMap<SectionIndex, SectionBody> {
|
||||||
|
self.custom_sections
|
||||||
|
.iter()
|
||||||
|
.map(|(_, section)| section.bytes.clone())
|
||||||
|
.collect::<PrimaryMap<SectionIndex, _>>()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> IntoIterator for &'a Compilation {
|
impl<'a> IntoIterator for &'a Compilation {
|
||||||
|
|||||||
@@ -38,41 +38,46 @@ use hashbrown::HashMap;
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
mod address_map;
|
mod address_map;
|
||||||
|
#[cfg(feature = "translator")]
|
||||||
mod compiler;
|
mod compiler;
|
||||||
mod config;
|
|
||||||
mod error;
|
mod error;
|
||||||
mod function;
|
mod function;
|
||||||
mod jump_table;
|
mod jump_table;
|
||||||
mod relocation;
|
mod relocation;
|
||||||
|
mod target;
|
||||||
mod trap;
|
mod trap;
|
||||||
mod unwind;
|
mod unwind;
|
||||||
|
#[cfg(feature = "translator")]
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod translator;
|
mod translator;
|
||||||
mod section;
|
mod section;
|
||||||
mod sourceloc;
|
mod sourceloc;
|
||||||
|
|
||||||
pub use crate::address_map::{FunctionAddressMap, InstructionAddressMap};
|
pub use crate::address_map::{FunctionAddressMap, InstructionAddressMap};
|
||||||
pub use crate::compiler::Compiler;
|
#[cfg(feature = "translator")]
|
||||||
pub use crate::config::{
|
pub use crate::compiler::{Compiler, CompilerConfig};
|
||||||
Architecture, CallingConvention, CompilerConfig, CpuFeature, Features, OperatingSystem, Target,
|
pub use crate::error::{CompileError, WasmError, WasmResult};
|
||||||
Triple,
|
|
||||||
};
|
|
||||||
pub use crate::error::CompileError;
|
|
||||||
pub use crate::function::{
|
pub use crate::function::{
|
||||||
Compilation, CompiledFunction, CompiledFunctionFrameInfo, CustomSections, FunctionBody,
|
Compilation, CompiledFunction, CompiledFunctionFrameInfo, CustomSections, FunctionBody,
|
||||||
Functions,
|
Functions,
|
||||||
};
|
};
|
||||||
pub use crate::jump_table::{JumpTable, JumpTableOffsets};
|
pub use crate::jump_table::{JumpTable, JumpTableOffsets};
|
||||||
pub use crate::relocation::{Relocation, RelocationKind, RelocationTarget, Relocations};
|
pub use crate::relocation::{Relocation, RelocationKind, RelocationTarget, Relocations};
|
||||||
pub use crate::section::{CustomSection, CustomSectionProtection, SectionIndex};
|
pub use crate::section::{CustomSection, CustomSectionProtection, SectionBody, SectionIndex};
|
||||||
pub use crate::sourceloc::SourceLoc;
|
pub use crate::sourceloc::SourceLoc;
|
||||||
|
pub use crate::target::{
|
||||||
|
Architecture, CallingConvention, CpuFeature, OperatingSystem, Target, Triple,
|
||||||
|
};
|
||||||
|
#[cfg(feature = "translator")]
|
||||||
pub use crate::translator::{
|
pub use crate::translator::{
|
||||||
to_wasm_error, translate_module, FunctionBodyData, ModuleEnvironment, ModuleTranslation,
|
to_wasm_error, translate_module, FunctionBodyData, ModuleEnvironment, ModuleTranslation,
|
||||||
ModuleTranslationState, WasmError, WasmResult,
|
ModuleTranslationState,
|
||||||
};
|
};
|
||||||
pub use crate::trap::TrapInformation;
|
pub use crate::trap::TrapInformation;
|
||||||
pub use crate::unwind::{CompiledFunctionUnwindInfo, FDERelocEntry, FunctionTableReloc};
|
pub use crate::unwind::{CompiledFunctionUnwindInfo, FDERelocEntry, FunctionTableReloc};
|
||||||
|
|
||||||
|
pub use wasm_common::Features;
|
||||||
|
|
||||||
/// wasmparser is exported as a module to slim compiler dependencies
|
/// wasmparser is exported as a module to slim compiler dependencies
|
||||||
pub mod wasmparser {
|
pub mod wasmparser {
|
||||||
pub use wasmparser::*;
|
pub use wasmparser::*;
|
||||||
|
|||||||
@@ -46,6 +46,31 @@ pub struct CustomSection {
|
|||||||
/// > (the start of the memory pointer).
|
/// > (the start of the memory pointer).
|
||||||
/// > We might need to create another field for alignment in case it's
|
/// > We might need to create another field for alignment in case it's
|
||||||
/// > needed in the future.
|
/// > needed in the future.
|
||||||
#[serde(with = "serde_bytes")]
|
pub bytes: SectionBody,
|
||||||
pub bytes: Vec<u8>,
|
}
|
||||||
|
|
||||||
|
/// The bytes in the section.
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Default)]
|
||||||
|
pub struct SectionBody(#[serde(with = "serde_bytes")] Vec<u8>);
|
||||||
|
|
||||||
|
impl SectionBody {
|
||||||
|
/// Extend the section with the bytes given.
|
||||||
|
pub fn extend(&mut self, contents: &[u8]) {
|
||||||
|
self.0.extend(contents);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Extends the section by appending bytes from another section.
|
||||||
|
pub fn append(&mut self, body: &SectionBody) {
|
||||||
|
self.0.extend(&body.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a raw pointer to the section's buffer.
|
||||||
|
pub fn as_ptr(&self) -> *const u8 {
|
||||||
|
self.0.as_ptr()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the length of this section in bytes.
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
self.0.len()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
//! The configuration for the
|
//! Target configuration
|
||||||
use crate::compiler::Compiler;
|
|
||||||
use crate::std::boxed::Box;
|
|
||||||
use enumset::{EnumSet, EnumSetType};
|
use enumset::{EnumSet, EnumSetType};
|
||||||
pub use target_lexicon::{Architecture, CallingConvention, OperatingSystem, Triple};
|
pub use target_lexicon::{Architecture, CallingConvention, OperatingSystem, Triple};
|
||||||
pub use wasm_common::Features;
|
|
||||||
|
|
||||||
|
use crate::std::boxed::Box;
|
||||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||||
use raw_cpuid::CpuId;
|
use raw_cpuid::CpuId;
|
||||||
|
|
||||||
@@ -140,19 +138,3 @@ impl Default for Target {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The compiler configuration options.
|
|
||||||
///
|
|
||||||
/// This options must have WebAssembly `Features` and a specific
|
|
||||||
/// `Target` to compile to.
|
|
||||||
pub trait CompilerConfig {
|
|
||||||
/// Gets the WebAssembly features
|
|
||||||
fn features(&self) -> &Features;
|
|
||||||
|
|
||||||
/// Gets the target that we will use for compiling
|
|
||||||
/// the WebAssembly module
|
|
||||||
fn target(&self) -> &Target;
|
|
||||||
|
|
||||||
/// Gets the custom compiler config
|
|
||||||
fn compiler(&self) -> Box<dyn Compiler>;
|
|
||||||
}
|
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
use super::error::{WasmError, WasmResult};
|
|
||||||
use super::module::translate_module;
|
use super::module::translate_module;
|
||||||
use super::state::ModuleTranslationState;
|
use super::state::ModuleTranslationState;
|
||||||
use crate::std::borrow::ToOwned;
|
use crate::std::borrow::ToOwned;
|
||||||
use crate::std::string::ToString;
|
use crate::std::string::ToString;
|
||||||
use crate::std::{boxed::Box, string::String, vec::Vec};
|
use crate::std::{boxed::Box, string::String, vec::Vec};
|
||||||
|
use crate::{WasmError, WasmResult};
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use wasm_common::entity::PrimaryMap;
|
use wasm_common::entity::PrimaryMap;
|
||||||
|
|||||||
@@ -1,39 +1,7 @@
|
|||||||
use crate::std::string::String;
|
use crate::WasmError;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use wasmparser::BinaryReaderError;
|
use wasmparser::BinaryReaderError;
|
||||||
|
|
||||||
/// A WebAssembly translation error.
|
|
||||||
///
|
|
||||||
/// When a WebAssembly function can't be translated, one of these error codes will be returned
|
|
||||||
/// to describe the failure.
|
|
||||||
#[derive(Error, Debug)]
|
|
||||||
pub enum WasmError {
|
|
||||||
/// The input WebAssembly code is invalid.
|
|
||||||
///
|
|
||||||
/// This error code is used by a WebAssembly translator when it encounters invalid WebAssembly
|
|
||||||
/// code. This should never happen for validated WebAssembly code.
|
|
||||||
#[error("Invalid input WebAssembly code at offset {offset}: {message}")]
|
|
||||||
InvalidWebAssembly {
|
|
||||||
/// A string describing the validation error.
|
|
||||||
message: String,
|
|
||||||
/// The bytecode offset where the error occurred.
|
|
||||||
offset: usize,
|
|
||||||
},
|
|
||||||
|
|
||||||
/// A feature used by the WebAssembly code is not supported by the embedding environment.
|
|
||||||
///
|
|
||||||
/// Embedding environments may have their own limitations and feature restrictions.
|
|
||||||
#[error("Unsupported feature: {0}")]
|
|
||||||
Unsupported(String),
|
|
||||||
|
|
||||||
/// An implementation limit was exceeded.
|
|
||||||
#[error("Implementation limit exceeded")]
|
|
||||||
ImplLimitExceeded,
|
|
||||||
|
|
||||||
/// A generic error.
|
|
||||||
#[error("{0}")]
|
|
||||||
Generic(String),
|
|
||||||
}
|
|
||||||
/// Return an `Err(WasmError::Unsupported(msg))` where `msg` the string built by calling `format!`
|
/// Return an `Err(WasmError::Unsupported(msg))` where `msg` the string built by calling `format!`
|
||||||
/// on the arguments to this macro.
|
/// on the arguments to this macro.
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
@@ -48,6 +16,3 @@ pub fn to_wasm_error(e: BinaryReaderError) -> WasmError {
|
|||||||
offset: e.offset(),
|
offset: e.offset(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A convenient alias for a `Result` that uses `WasmError` as the error type.
|
|
||||||
pub type WasmResult<T> = Result<T, WasmError>;
|
|
||||||
|
|||||||
@@ -13,6 +13,6 @@ mod error;
|
|||||||
mod sections;
|
mod sections;
|
||||||
|
|
||||||
pub use self::environ::{FunctionBodyData, ModuleEnvironment, ModuleTranslation};
|
pub use self::environ::{FunctionBodyData, ModuleEnvironment, ModuleTranslation};
|
||||||
pub use self::error::{to_wasm_error, WasmError, WasmResult};
|
pub use self::error::to_wasm_error;
|
||||||
pub use self::module::translate_module;
|
pub use self::module::translate_module;
|
||||||
pub use self::state::ModuleTranslationState;
|
pub use self::state::ModuleTranslationState;
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
//! Translation skeleton that traverses the whole WebAssembly module and call helper functions
|
//! Translation skeleton that traverses the whole WebAssembly module and call helper functions
|
||||||
//! to deal with each part of it.
|
//! to deal with each part of it.
|
||||||
use super::environ::ModuleEnvironment;
|
use super::environ::ModuleEnvironment;
|
||||||
use super::error::{to_wasm_error, WasmResult};
|
use super::error::to_wasm_error;
|
||||||
use super::sections::{
|
use super::sections::{
|
||||||
parse_code_section, parse_data_section, parse_element_section, parse_export_section,
|
parse_code_section, parse_data_section, parse_element_section, parse_export_section,
|
||||||
parse_function_section, parse_global_section, parse_import_section, parse_memory_section,
|
parse_function_section, parse_global_section, parse_import_section, parse_memory_section,
|
||||||
parse_name_section, parse_start_section, parse_table_section, parse_type_section,
|
parse_name_section, parse_start_section, parse_table_section, parse_type_section,
|
||||||
};
|
};
|
||||||
use super::state::ModuleTranslationState;
|
use super::state::ModuleTranslationState;
|
||||||
|
use crate::WasmResult;
|
||||||
use wasmparser::{CustomSectionContent, ModuleReader, SectionContent};
|
use wasmparser::{CustomSectionContent, ModuleReader, SectionContent};
|
||||||
|
|
||||||
/// Translate a sequence of bytes forming a valid Wasm binary into a
|
/// Translate a sequence of bytes forming a valid Wasm binary into a
|
||||||
|
|||||||
@@ -8,9 +8,10 @@
|
|||||||
//! is handled, according to the semantics of WebAssembly, to only specific expressions that are
|
//! is handled, according to the semantics of WebAssembly, to only specific expressions that are
|
||||||
//! interpreted on the fly.
|
//! interpreted on the fly.
|
||||||
use super::environ::ModuleEnvironment;
|
use super::environ::ModuleEnvironment;
|
||||||
use super::error::{to_wasm_error, WasmError, WasmResult};
|
use super::error::to_wasm_error;
|
||||||
use super::state::ModuleTranslationState;
|
use super::state::ModuleTranslationState;
|
||||||
use crate::{wasm_unsupported, HashMap};
|
use crate::{wasm_unsupported, HashMap};
|
||||||
|
use crate::{WasmError, WasmResult};
|
||||||
use core::convert::TryFrom;
|
use core::convert::TryFrom;
|
||||||
use std::boxed::Box;
|
use std::boxed::Box;
|
||||||
use std::vec::Vec;
|
use std::vec::Vec;
|
||||||
|
|||||||
@@ -29,5 +29,10 @@ lazy_static = "1.4"
|
|||||||
[target.'cfg(target_os = "windows")'.dependencies]
|
[target.'cfg(target_os = "windows")'.dependencies]
|
||||||
winapi = { version = "0.3.8", features = ["winnt", "impl-default"] }
|
winapi = { version = "0.3.8", features = ["winnt", "impl-default"] }
|
||||||
|
|
||||||
|
[features]
|
||||||
|
# Enable the `compiler` feature if you want the engine to compile
|
||||||
|
# and not be only on headless mode.
|
||||||
|
compiler = []
|
||||||
|
|
||||||
[badges]
|
[badges]
|
||||||
maintenance = { status = "actively-developed" }
|
maintenance = { status = "actively-developed" }
|
||||||
|
|||||||
@@ -9,11 +9,10 @@ use std::cell::RefCell;
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use wasm_common::entity::PrimaryMap;
|
use wasm_common::entity::PrimaryMap;
|
||||||
use wasm_common::{FuncType, LocalFuncIndex, MemoryIndex, TableIndex};
|
use wasm_common::{FuncType, LocalFuncIndex, MemoryIndex, SignatureIndex, TableIndex};
|
||||||
use wasmer_compiler::{
|
use wasmer_compiler::{Compilation, CompileError, FunctionBody, Target};
|
||||||
Compilation, CompileError, Compiler as BaseCompiler, CompilerConfig, FunctionBody,
|
#[cfg(feature = "compiler")]
|
||||||
FunctionBodyData, ModuleTranslationState, Target,
|
use wasmer_compiler::{Compiler, CompilerConfig};
|
||||||
};
|
|
||||||
use wasmer_runtime::{
|
use wasmer_runtime::{
|
||||||
InstanceHandle, MemoryPlan, Module, SignatureRegistry, TablePlan, VMFunctionBody,
|
InstanceHandle, MemoryPlan, Module, SignatureRegistry, TablePlan, VMFunctionBody,
|
||||||
VMSharedSignatureIndex, VMTrampoline,
|
VMSharedSignatureIndex, VMTrampoline,
|
||||||
@@ -29,7 +28,8 @@ pub struct JITEngine {
|
|||||||
impl JITEngine {
|
impl JITEngine {
|
||||||
const MAGIC_HEADER: &'static [u8] = b"\0wasmer-jit";
|
const MAGIC_HEADER: &'static [u8] = b"\0wasmer-jit";
|
||||||
|
|
||||||
/// Create a new JIT Engine given config
|
/// Create a new `JITEngine` with the given config
|
||||||
|
#[cfg(feature = "compiler")]
|
||||||
pub fn new<C: CompilerConfig>(config: &C, tunables: impl Tunables + 'static) -> Self
|
pub fn new<C: CompilerConfig>(config: &C, tunables: impl Tunables + 'static) -> Self
|
||||||
where
|
where
|
||||||
C: ?Sized,
|
C: ?Sized,
|
||||||
@@ -37,7 +37,33 @@ impl JITEngine {
|
|||||||
let compiler = config.compiler();
|
let compiler = config.compiler();
|
||||||
Self {
|
Self {
|
||||||
inner: Arc::new(RefCell::new(JITEngineInner {
|
inner: Arc::new(RefCell::new(JITEngineInner {
|
||||||
compiler,
|
compiler: Some(compiler),
|
||||||
|
trampolines: HashMap::new(),
|
||||||
|
code_memory: CodeMemory::new(),
|
||||||
|
signatures: SignatureRegistry::new(),
|
||||||
|
})),
|
||||||
|
tunables: Arc::new(Box::new(tunables)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a headless `JITEngine`
|
||||||
|
///
|
||||||
|
/// A headless engine is an engine without any compiler attached.
|
||||||
|
/// This is useful for assuring a minimal runtime for running
|
||||||
|
/// WebAssembly modules.
|
||||||
|
///
|
||||||
|
/// For example, for running in IoT devices where compilers are very
|
||||||
|
/// expensive, or also to optimize startup speed.
|
||||||
|
///
|
||||||
|
/// # Important
|
||||||
|
///
|
||||||
|
/// Headless engines can't compile or validate any modules,
|
||||||
|
/// they just take already processed Modules (via `Module::serialize`).
|
||||||
|
pub fn headless(tunables: impl Tunables + 'static) -> Self {
|
||||||
|
Self {
|
||||||
|
inner: Arc::new(RefCell::new(JITEngineInner {
|
||||||
|
#[cfg(feature = "compiler")]
|
||||||
|
compiler: None,
|
||||||
trampolines: HashMap::new(),
|
trampolines: HashMap::new(),
|
||||||
code_memory: CodeMemory::new(),
|
code_memory: CodeMemory::new(),
|
||||||
signatures: SignatureRegistry::new(),
|
signatures: SignatureRegistry::new(),
|
||||||
@@ -93,7 +119,7 @@ impl JITEngine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Instantiates a WebAssembly module
|
/// Instantiates a WebAssembly module
|
||||||
pub fn instantiate(
|
pub unsafe fn instantiate(
|
||||||
&self,
|
&self,
|
||||||
compiled_module: &CompiledModule,
|
compiled_module: &CompiledModule,
|
||||||
resolver: &dyn Resolver,
|
resolver: &dyn Resolver,
|
||||||
@@ -126,7 +152,8 @@ impl JITEngine {
|
|||||||
/// The inner contents of `JITEngine`
|
/// The inner contents of `JITEngine`
|
||||||
pub struct JITEngineInner {
|
pub struct JITEngineInner {
|
||||||
/// The compiler
|
/// The compiler
|
||||||
compiler: Box<dyn BaseCompiler>,
|
#[cfg(feature = "compiler")]
|
||||||
|
compiler: Option<Box<dyn Compiler>>,
|
||||||
/// Pointers to trampoline functions used to enter particular signatures
|
/// Pointers to trampoline functions used to enter particular signatures
|
||||||
trampolines: HashMap<VMSharedSignatureIndex, VMTrampoline>,
|
trampolines: HashMap<VMSharedSignatureIndex, VMTrampoline>,
|
||||||
/// The code memory is responsible of publishing the compiled
|
/// The code memory is responsible of publishing the compiled
|
||||||
@@ -139,38 +166,34 @@ pub struct JITEngineInner {
|
|||||||
|
|
||||||
impl JITEngineInner {
|
impl JITEngineInner {
|
||||||
/// Gets the compiler associated to this JIT
|
/// Gets the compiler associated to this JIT
|
||||||
pub fn compiler(&self) -> &dyn BaseCompiler {
|
#[cfg(feature = "compiler")]
|
||||||
&*self.compiler
|
pub fn compiler(&self) -> Result<&dyn Compiler, CompileError> {
|
||||||
|
if self.compiler.is_none() {
|
||||||
|
return Err(CompileError::Codegen("The JITEngine is operating in headless mode, so it can only execute already compiled Modules.".to_string()));
|
||||||
|
}
|
||||||
|
Ok(&**self.compiler.as_ref().unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Validate the module
|
/// Validate the module
|
||||||
|
#[cfg(feature = "compiler")]
|
||||||
pub fn validate<'data>(&self, data: &'data [u8]) -> Result<(), CompileError> {
|
pub fn validate<'data>(&self, data: &'data [u8]) -> Result<(), CompileError> {
|
||||||
self.compiler().validate_module(data)
|
self.compiler()?.validate_module(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Validate the module
|
||||||
|
#[cfg(not(feature = "compiler"))]
|
||||||
|
pub fn validate<'data>(&self, data: &'data [u8]) -> Result<(), CompileError> {
|
||||||
|
Err(CompileError::Validate(
|
||||||
|
"Validation is only enabled with the compiler feature".to_string(),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Compile the given function bodies.
|
/// Compile the given function bodies.
|
||||||
pub(crate) fn compile_module<'data>(
|
pub(crate) fn allocate<'data>(
|
||||||
&self,
|
|
||||||
module: &Module,
|
|
||||||
module_translation: &ModuleTranslationState,
|
|
||||||
function_body_inputs: PrimaryMap<LocalFuncIndex, FunctionBodyData<'data>>,
|
|
||||||
memory_plans: PrimaryMap<MemoryIndex, MemoryPlan>,
|
|
||||||
table_plans: PrimaryMap<TableIndex, TablePlan>,
|
|
||||||
) -> Result<Compilation, CompileError> {
|
|
||||||
self.compiler.compile_module(
|
|
||||||
module,
|
|
||||||
module_translation,
|
|
||||||
function_body_inputs,
|
|
||||||
memory_plans,
|
|
||||||
table_plans,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Compile the given function bodies.
|
|
||||||
pub(crate) fn compile<'data>(
|
|
||||||
&mut self,
|
&mut self,
|
||||||
module: &Module,
|
module: &Module,
|
||||||
functions: &PrimaryMap<LocalFuncIndex, FunctionBody>,
|
functions: &PrimaryMap<LocalFuncIndex, FunctionBody>,
|
||||||
|
trampolines: &PrimaryMap<SignatureIndex, FunctionBody>,
|
||||||
) -> Result<PrimaryMap<LocalFuncIndex, *mut [VMFunctionBody]>, CompileError> {
|
) -> Result<PrimaryMap<LocalFuncIndex, *mut [VMFunctionBody]>, CompileError> {
|
||||||
// Allocate all of the compiled functions into executable memory,
|
// Allocate all of the compiled functions into executable memory,
|
||||||
// copying over their contents.
|
// copying over their contents.
|
||||||
@@ -184,35 +207,27 @@ impl JITEngineInner {
|
|||||||
))
|
))
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
// Trampoline generation.
|
for (sig_index, compiled_function) in trampolines.iter() {
|
||||||
// We do it in two steps:
|
let func_type = module.signatures.get(sig_index).unwrap();
|
||||||
// 1. Generate only the trampolines for the signatures that are unique
|
let index = self.signatures.register(&func_type);
|
||||||
// 2. Push the compiled code to memory
|
if self.trampolines.contains_key(&index) {
|
||||||
let mut unique_signatures: HashMap<VMSharedSignatureIndex, FuncType> = HashMap::new();
|
// We don't need to allocate the trampoline in case
|
||||||
// for sig in module.exported_signatures() {
|
// it's signature is already allocated.
|
||||||
for sig in module.signatures.values() {
|
|
||||||
let index = self.signatures.register(&sig);
|
|
||||||
if unique_signatures.contains_key(&index) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
unique_signatures.insert(index, sig.clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
let compiled_trampolines = self
|
|
||||||
.compiler
|
|
||||||
.compile_wasm_trampolines(&unique_signatures.values().cloned().collect::<Vec<_>>())?;
|
|
||||||
|
|
||||||
for ((index, _), compiled_function) in
|
|
||||||
unique_signatures.iter().zip(compiled_trampolines.iter())
|
|
||||||
{
|
|
||||||
let ptr = self
|
let ptr = self
|
||||||
.code_memory
|
.code_memory
|
||||||
.allocate_for_function(&compiled_function)
|
.allocate_for_function(&compiled_function)
|
||||||
.map_err(|message| CompileError::Resource(message))?
|
.map_err(|message| {
|
||||||
|
CompileError::Resource(format!(
|
||||||
|
"failed to allocate memory for trampolines: {}",
|
||||||
|
message
|
||||||
|
))
|
||||||
|
})?
|
||||||
.as_ptr();
|
.as_ptr();
|
||||||
let trampoline =
|
let trampoline =
|
||||||
unsafe { std::mem::transmute::<*const VMFunctionBody, VMTrampoline>(ptr) };
|
unsafe { std::mem::transmute::<*const VMFunctionBody, VMTrampoline>(ptr) };
|
||||||
self.trampolines.insert(*index, trampoline);
|
self.trampolines.insert(index, trampoline);
|
||||||
}
|
}
|
||||||
Ok(allocated_functions)
|
Ok(allocated_functions)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,7 +48,5 @@ pub use crate::resolver::{resolve_imports, NullResolver, Resolver};
|
|||||||
pub use crate::trap::*;
|
pub use crate::trap::*;
|
||||||
pub use crate::tunables::Tunables;
|
pub use crate::tunables::Tunables;
|
||||||
|
|
||||||
pub use wasmer_compiler::CompilerConfig;
|
|
||||||
|
|
||||||
/// Version number of this crate.
|
/// Version number of this crate.
|
||||||
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
|
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||||
|
|||||||
@@ -3,7 +3,10 @@
|
|||||||
use std::ptr::write_unaligned;
|
use std::ptr::write_unaligned;
|
||||||
use wasm_common::entity::{EntityRef, PrimaryMap};
|
use wasm_common::entity::{EntityRef, PrimaryMap};
|
||||||
use wasm_common::LocalFuncIndex;
|
use wasm_common::LocalFuncIndex;
|
||||||
use wasmer_compiler::{JumpTable, JumpTableOffsets, RelocationKind, RelocationTarget, Relocations};
|
use wasmer_compiler::{
|
||||||
|
JumpTable, JumpTableOffsets, RelocationKind, RelocationTarget, Relocations, SectionBody,
|
||||||
|
SectionIndex,
|
||||||
|
};
|
||||||
use wasmer_runtime::Module;
|
use wasmer_runtime::Module;
|
||||||
use wasmer_runtime::VMFunctionBody;
|
use wasmer_runtime::VMFunctionBody;
|
||||||
|
|
||||||
@@ -15,6 +18,7 @@ pub fn link_module(
|
|||||||
allocated_functions: &PrimaryMap<LocalFuncIndex, *mut [VMFunctionBody]>,
|
allocated_functions: &PrimaryMap<LocalFuncIndex, *mut [VMFunctionBody]>,
|
||||||
jt_offsets: &PrimaryMap<LocalFuncIndex, JumpTableOffsets>,
|
jt_offsets: &PrimaryMap<LocalFuncIndex, JumpTableOffsets>,
|
||||||
relocations: Relocations,
|
relocations: Relocations,
|
||||||
|
allocated_sections: &PrimaryMap<SectionIndex, SectionBody>,
|
||||||
) {
|
) {
|
||||||
for (i, function_relocs) in relocations.into_iter() {
|
for (i, function_relocs) in relocations.into_iter() {
|
||||||
for r in function_relocs {
|
for r in function_relocs {
|
||||||
@@ -24,8 +28,8 @@ pub fn link_module(
|
|||||||
fatptr as *const VMFunctionBody as usize
|
fatptr as *const VMFunctionBody as usize
|
||||||
}
|
}
|
||||||
RelocationTarget::LibCall(libcall) => libcall.function_pointer(),
|
RelocationTarget::LibCall(libcall) => libcall.function_pointer(),
|
||||||
RelocationTarget::CustomSection(_custom_section) => {
|
RelocationTarget::CustomSection(custom_section) => {
|
||||||
unimplemented!("Custom Sections not yet implemented");
|
allocated_sections[custom_section].as_ptr() as usize
|
||||||
}
|
}
|
||||||
RelocationTarget::JumpTable(func_index, jt) => {
|
RelocationTarget::JumpTable(func_index, jt) => {
|
||||||
let offset = *jt_offsets
|
let offset = *jt_offsets
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
//! Define the `instantiate` function, which takes a byte array containing an
|
//! Define `CompiledModule` to allow compiling and instantiating to be
|
||||||
//! encoded wasm module and returns a live wasm instance. Also, define
|
//! done as separate steps.
|
||||||
//! `CompiledModule` to allow compiling and instantiating to be done as separate
|
|
||||||
//! steps.
|
|
||||||
|
|
||||||
use crate::engine::{JITEngine, JITEngineInner};
|
use crate::engine::{JITEngine, JITEngineInner};
|
||||||
use crate::error::{DeserializeError, SerializeError};
|
use crate::error::{DeserializeError, SerializeError};
|
||||||
@@ -14,6 +12,7 @@ use crate::serialize::{
|
|||||||
use crate::trap::register as register_frame_info;
|
use crate::trap::register as register_frame_info;
|
||||||
use crate::trap::GlobalFrameInfoRegistration;
|
use crate::trap::GlobalFrameInfoRegistration;
|
||||||
use crate::trap::RuntimeError;
|
use crate::trap::RuntimeError;
|
||||||
|
use crate::tunables::Tunables;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
@@ -23,6 +22,7 @@ use wasm_common::{
|
|||||||
MemoryIndex, OwnedDataInitializer, SignatureIndex, TableIndex,
|
MemoryIndex, OwnedDataInitializer, SignatureIndex, TableIndex,
|
||||||
};
|
};
|
||||||
use wasmer_compiler::CompileError;
|
use wasmer_compiler::CompileError;
|
||||||
|
#[cfg(feature = "compiler")]
|
||||||
use wasmer_compiler::ModuleEnvironment;
|
use wasmer_compiler::ModuleEnvironment;
|
||||||
use wasmer_runtime::{
|
use wasmer_runtime::{
|
||||||
InstanceHandle, LinearMemory, Module, SignatureRegistry, Table, VMFunctionBody,
|
InstanceHandle, LinearMemory, Module, SignatureRegistry, Table, VMFunctionBody,
|
||||||
@@ -42,6 +42,7 @@ pub struct CompiledModule {
|
|||||||
|
|
||||||
impl CompiledModule {
|
impl CompiledModule {
|
||||||
/// Compile a data buffer into a `CompiledModule`, which may then be instantiated.
|
/// Compile a data buffer into a `CompiledModule`, which may then be instantiated.
|
||||||
|
#[cfg(feature = "compiler")]
|
||||||
pub fn new(jit: &JITEngine, data: &[u8]) -> Result<Self, CompileError> {
|
pub fn new(jit: &JITEngine, data: &[u8]) -> Result<Self, CompileError> {
|
||||||
let environ = ModuleEnvironment::new();
|
let environ = ModuleEnvironment::new();
|
||||||
let mut jit_compiler = jit.compiler_mut();
|
let mut jit_compiler = jit.compiler_mut();
|
||||||
@@ -64,13 +65,29 @@ impl CompiledModule {
|
|||||||
.map(|(_index, table_type)| tunables.table_plan(*table_type))
|
.map(|(_index, table_type)| tunables.table_plan(*table_type))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let compilation = jit_compiler.compile_module(
|
let compiler = jit_compiler.compiler()?;
|
||||||
|
|
||||||
|
// Compile the Module
|
||||||
|
let compilation = compiler.compile_module(
|
||||||
&translation.module,
|
&translation.module,
|
||||||
translation.module_translation.as_ref().unwrap(),
|
translation.module_translation.as_ref().unwrap(),
|
||||||
translation.function_body_inputs,
|
translation.function_body_inputs,
|
||||||
memory_plans.clone(),
|
memory_plans.clone(),
|
||||||
table_plans.clone(),
|
table_plans.clone(),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
// Compile the trampolines
|
||||||
|
let func_types = translation
|
||||||
|
.module
|
||||||
|
.signatures
|
||||||
|
.values()
|
||||||
|
.cloned()
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
let trampolines = compiler
|
||||||
|
.compile_wasm_trampolines(&func_types)?
|
||||||
|
.into_iter()
|
||||||
|
.collect::<PrimaryMap<SignatureIndex, _>>();
|
||||||
|
|
||||||
let data_initializers = translation
|
let data_initializers = translation
|
||||||
.data_initializers
|
.data_initializers
|
||||||
.iter()
|
.iter()
|
||||||
@@ -89,10 +106,13 @@ impl CompiledModule {
|
|||||||
function_relocations: compilation.get_relocations(),
|
function_relocations: compilation.get_relocations(),
|
||||||
function_jt_offsets: compilation.get_jt_offsets(),
|
function_jt_offsets: compilation.get_jt_offsets(),
|
||||||
function_frame_info: frame_infos,
|
function_frame_info: frame_infos,
|
||||||
|
trampolines,
|
||||||
|
custom_sections: compilation.get_custom_sections(),
|
||||||
};
|
};
|
||||||
let serializable = SerializableModule {
|
let serializable = SerializableModule {
|
||||||
compilation: serializable_compilation,
|
compilation: serializable_compilation,
|
||||||
module: Arc::new(translation.module),
|
module: Arc::new(translation.module),
|
||||||
|
features: jit_compiler.compiler()?.features().clone(),
|
||||||
data_initializers,
|
data_initializers,
|
||||||
memory_plans,
|
memory_plans,
|
||||||
table_plans,
|
table_plans,
|
||||||
@@ -100,6 +120,14 @@ impl CompiledModule {
|
|||||||
Self::from_parts(&mut jit_compiler, serializable)
|
Self::from_parts(&mut jit_compiler, serializable)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Compile a data buffer into a `CompiledModule`, which may then be instantiated.
|
||||||
|
#[cfg(not(feature = "compiler"))]
|
||||||
|
pub fn new(jit: &JITEngine, data: &[u8]) -> Result<Self, CompileError> {
|
||||||
|
Err(CompileError::Codegen(
|
||||||
|
"Compilation is not enabled in the engine".to_string(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
/// Serialize a CompiledModule
|
/// Serialize a CompiledModule
|
||||||
pub fn serialize(&self) -> Result<Vec<u8>, SerializeError> {
|
pub fn serialize(&self) -> Result<Vec<u8>, SerializeError> {
|
||||||
// let mut s = flexbuffers::FlexbufferSerializer::new();
|
// let mut s = flexbuffers::FlexbufferSerializer::new();
|
||||||
@@ -126,9 +154,10 @@ impl CompiledModule {
|
|||||||
jit_compiler: &mut JITEngineInner,
|
jit_compiler: &mut JITEngineInner,
|
||||||
serializable: SerializableModule,
|
serializable: SerializableModule,
|
||||||
) -> Result<Self, CompileError> {
|
) -> Result<Self, CompileError> {
|
||||||
let finished_functions = jit_compiler.compile(
|
let finished_functions = jit_compiler.allocate(
|
||||||
&serializable.module,
|
&serializable.module,
|
||||||
&serializable.compilation.function_bodies,
|
&serializable.compilation.function_bodies,
|
||||||
|
&serializable.compilation.trampolines,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
link_module(
|
link_module(
|
||||||
@@ -136,6 +165,7 @@ impl CompiledModule {
|
|||||||
&finished_functions,
|
&finished_functions,
|
||||||
&serializable.compilation.function_jt_offsets,
|
&serializable.compilation.function_jt_offsets,
|
||||||
serializable.compilation.function_relocations.clone(),
|
serializable.compilation.function_relocations.clone(),
|
||||||
|
&serializable.compilation.custom_sections,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Compute indices into the shared signature table.
|
// Compute indices into the shared signature table.
|
||||||
@@ -170,10 +200,6 @@ impl CompiledModule {
|
|||||||
|
|
||||||
/// Crate an `Instance` from this `CompiledModule`.
|
/// Crate an `Instance` from this `CompiledModule`.
|
||||||
///
|
///
|
||||||
/// Note that if only one instance of this module is needed, it may be more
|
|
||||||
/// efficient to call the top-level `instantiate`, since that avoids copying
|
|
||||||
/// the data initializers.
|
|
||||||
///
|
|
||||||
/// # Unsafety
|
/// # Unsafety
|
||||||
///
|
///
|
||||||
/// See `InstanceHandle::new`
|
/// See `InstanceHandle::new`
|
||||||
@@ -184,17 +210,8 @@ impl CompiledModule {
|
|||||||
host_state: Box<dyn Any>,
|
host_state: Box<dyn Any>,
|
||||||
) -> Result<InstanceHandle, InstantiationError> {
|
) -> Result<InstanceHandle, InstantiationError> {
|
||||||
let jit_compiler = jit.compiler();
|
let jit_compiler = jit.compiler();
|
||||||
let is_bulk_memory: bool = jit_compiler.compiler().features().bulk_memory;
|
let tunables = jit.tunables();
|
||||||
let sig_registry: &SignatureRegistry = jit_compiler.signatures();
|
let sig_registry: &SignatureRegistry = jit_compiler.signatures();
|
||||||
let data_initializers = self
|
|
||||||
.serializable
|
|
||||||
.data_initializers
|
|
||||||
.iter()
|
|
||||||
.map(|init| DataInitializer {
|
|
||||||
location: init.location.clone(),
|
|
||||||
data: &*init.data,
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
let imports = resolve_imports(
|
let imports = resolve_imports(
|
||||||
&self.serializable.module,
|
&self.serializable.module,
|
||||||
&sig_registry,
|
&sig_registry,
|
||||||
@@ -204,10 +221,18 @@ impl CompiledModule {
|
|||||||
)
|
)
|
||||||
.map_err(InstantiationError::Link)?;
|
.map_err(InstantiationError::Link)?;
|
||||||
|
|
||||||
let finished_memories = create_memories(&self.serializable.module, self.memory_plans())
|
let finished_memories = tunables
|
||||||
.map_err(InstantiationError::Link)?;
|
.create_memories(&self.serializable.module, self.memory_plans())
|
||||||
let finished_tables = create_tables(&self.serializable.module, self.table_plans());
|
.map_err(InstantiationError::Link)?
|
||||||
let finished_globals = create_globals(&self.serializable.module);
|
.into_boxed_slice();
|
||||||
|
let finished_tables = tunables
|
||||||
|
.create_tables(&self.serializable.module, self.table_plans())
|
||||||
|
.map_err(InstantiationError::Link)?
|
||||||
|
.into_boxed_slice();
|
||||||
|
let finished_globals = tunables
|
||||||
|
.create_globals(&self.serializable.module)
|
||||||
|
.map_err(InstantiationError::Link)?
|
||||||
|
.into_boxed_slice();
|
||||||
|
|
||||||
// Register the frame info for the module
|
// Register the frame info for the module
|
||||||
self.register_frame_info();
|
self.register_frame_info();
|
||||||
@@ -219,14 +244,39 @@ impl CompiledModule {
|
|||||||
finished_tables,
|
finished_tables,
|
||||||
finished_globals,
|
finished_globals,
|
||||||
imports,
|
imports,
|
||||||
&data_initializers,
|
|
||||||
self.signatures.clone(),
|
self.signatures.clone(),
|
||||||
is_bulk_memory,
|
|
||||||
host_state,
|
host_state,
|
||||||
)
|
)
|
||||||
.map_err(|trap| InstantiationError::Start(RuntimeError::from_trap(trap)))
|
.map_err(|trap| InstantiationError::Start(RuntimeError::from_trap(trap)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Finish instantiation of a `InstanceHandle`
|
||||||
|
///
|
||||||
|
/// # Unsafety
|
||||||
|
///
|
||||||
|
/// See `InstanceHandle::finish_instantiation`
|
||||||
|
pub unsafe fn finish_instantiation(
|
||||||
|
&self,
|
||||||
|
handle: &InstanceHandle,
|
||||||
|
) -> Result<(), InstantiationError> {
|
||||||
|
let is_bulk_memory: bool = self.serializable.features.bulk_memory;
|
||||||
|
handle
|
||||||
|
.finish_instantiation(is_bulk_memory, &self.data_initializers())
|
||||||
|
.map_err(|trap| InstantiationError::Start(RuntimeError::from_trap(trap)))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns data initializers to pass to `InstanceHandle::initialize`
|
||||||
|
pub fn data_initializers(&self) -> Vec<DataInitializer<'_>> {
|
||||||
|
self.serializable
|
||||||
|
.data_initializers
|
||||||
|
.iter()
|
||||||
|
.map(|init| DataInitializer {
|
||||||
|
location: init.location.clone(),
|
||||||
|
data: &*init.data,
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
}
|
||||||
|
|
||||||
/// Return a reference-counting pointer to a module.
|
/// Return a reference-counting pointer to a module.
|
||||||
pub fn module(&self) -> &Arc<Module> {
|
pub fn module(&self) -> &Arc<Module> {
|
||||||
&self.serializable.module
|
&self.serializable.module
|
||||||
@@ -259,46 +309,3 @@ impl CompiledModule {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Allocate memory for just the memories of the current module.
|
|
||||||
fn create_memories(
|
|
||||||
module: &Module,
|
|
||||||
memory_plans: &PrimaryMap<MemoryIndex, MemoryPlan>,
|
|
||||||
) -> Result<BoxedSlice<LocalMemoryIndex, LinearMemory>, LinkError> {
|
|
||||||
let num_imports = module.num_imported_memories;
|
|
||||||
let mut memories: PrimaryMap<LocalMemoryIndex, _> =
|
|
||||||
PrimaryMap::with_capacity(module.memories.len() - num_imports);
|
|
||||||
for index in num_imports..module.memories.len() {
|
|
||||||
let plan = memory_plans[MemoryIndex::new(index)].clone();
|
|
||||||
memories.push(LinearMemory::new(&plan).map_err(LinkError::Resource)?);
|
|
||||||
}
|
|
||||||
Ok(memories.into_boxed_slice())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Allocate memory for just the tables of the current module.
|
|
||||||
fn create_tables(
|
|
||||||
module: &Module,
|
|
||||||
table_plans: &PrimaryMap<TableIndex, TablePlan>,
|
|
||||||
) -> BoxedSlice<LocalTableIndex, Table> {
|
|
||||||
let num_imports = module.num_imported_tables;
|
|
||||||
let mut tables: PrimaryMap<LocalTableIndex, _> =
|
|
||||||
PrimaryMap::with_capacity(module.tables.len() - num_imports);
|
|
||||||
for index in num_imports..module.tables.len() {
|
|
||||||
let plan = table_plans[TableIndex::new(index)].clone();
|
|
||||||
tables.push(Table::new(&plan));
|
|
||||||
}
|
|
||||||
tables.into_boxed_slice()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Allocate memory for just the globals of the current module,
|
|
||||||
/// with initializers applied.
|
|
||||||
fn create_globals(module: &Module) -> BoxedSlice<LocalGlobalIndex, VMGlobalDefinition> {
|
|
||||||
let num_imports = module.num_imported_globals;
|
|
||||||
let mut vmctx_globals = PrimaryMap::with_capacity(module.globals.len() - num_imports);
|
|
||||||
|
|
||||||
for _ in &module.globals.values().as_slice()[num_imports..] {
|
|
||||||
vmctx_globals.push(VMGlobalDefinition::new());
|
|
||||||
}
|
|
||||||
|
|
||||||
vmctx_globals.into_boxed_slice()
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
use crate::error::{ImportError, LinkError};
|
use crate::error::{ImportError, LinkError};
|
||||||
use more_asserts::assert_ge;
|
use more_asserts::assert_ge;
|
||||||
use std::collections::HashSet;
|
|
||||||
use wasm_common::entity::PrimaryMap;
|
use wasm_common::entity::PrimaryMap;
|
||||||
use wasm_common::{ExternType, ImportIndex, MemoryIndex, TableIndex};
|
use wasm_common::{ExternType, ImportIndex, MemoryIndex, TableIndex};
|
||||||
use wasmer_runtime::{
|
use wasmer_runtime::{
|
||||||
@@ -95,8 +94,6 @@ pub fn resolve_imports(
|
|||||||
memory_plans: &PrimaryMap<MemoryIndex, MemoryPlan>,
|
memory_plans: &PrimaryMap<MemoryIndex, MemoryPlan>,
|
||||||
_table_plans: &PrimaryMap<TableIndex, TablePlan>,
|
_table_plans: &PrimaryMap<TableIndex, TablePlan>,
|
||||||
) -> Result<Imports, LinkError> {
|
) -> Result<Imports, LinkError> {
|
||||||
let dependencies = HashSet::new();
|
|
||||||
|
|
||||||
let mut function_imports = PrimaryMap::with_capacity(module.num_imported_funcs);
|
let mut function_imports = PrimaryMap::with_capacity(module.num_imported_funcs);
|
||||||
let mut table_imports = PrimaryMap::with_capacity(module.num_imported_tables);
|
let mut table_imports = PrimaryMap::with_capacity(module.num_imported_tables);
|
||||||
let mut memory_imports = PrimaryMap::with_capacity(module.num_imported_memories);
|
let mut memory_imports = PrimaryMap::with_capacity(module.num_imported_memories);
|
||||||
@@ -125,16 +122,12 @@ pub fn resolve_imports(
|
|||||||
}
|
}
|
||||||
match resolved {
|
match resolved {
|
||||||
Export::Function(ref f) => {
|
Export::Function(ref f) => {
|
||||||
// TODO: Syrus - fix this
|
|
||||||
// dependencies.insert(unsafe { InstanceHandle::from_vmctx(f.vmctx) });
|
|
||||||
function_imports.push(VMFunctionImport {
|
function_imports.push(VMFunctionImport {
|
||||||
body: f.address,
|
body: f.address,
|
||||||
vmctx: f.vmctx,
|
vmctx: f.vmctx,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Export::Table(ref t) => {
|
Export::Table(ref t) => {
|
||||||
// TODO: Syrus - fix this
|
|
||||||
// dependencies.insert(unsafe { InstanceHandle::from_vmctx(t.vmctx) });
|
|
||||||
table_imports.push(VMTableImport {
|
table_imports.push(VMTableImport {
|
||||||
definition: t.definition,
|
definition: t.definition,
|
||||||
from: t.from,
|
from: t.from,
|
||||||
@@ -168,16 +161,13 @@ pub fn resolve_imports(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Syrus - fix this
|
|
||||||
// dependencies.insert(unsafe { InstanceHandle::from_vmctx(m.vmctx) });
|
|
||||||
memory_imports.push(VMMemoryImport {
|
memory_imports.push(VMMemoryImport {
|
||||||
definition: m.definition,
|
definition: m.definition,
|
||||||
from: m.from,
|
from: m.from,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Export::Global(ref g) => {
|
Export::Global(ref g) => {
|
||||||
// TODO: Syrus - fix this
|
|
||||||
// dependencies.insert(unsafe { InstanceHandle::from_vmctx(g.vmctx) });
|
|
||||||
global_imports.push(VMGlobalImport {
|
global_imports.push(VMGlobalImport {
|
||||||
definition: g.definition,
|
definition: g.definition,
|
||||||
});
|
});
|
||||||
@@ -186,7 +176,6 @@ pub fn resolve_imports(
|
|||||||
}
|
}
|
||||||
|
|
||||||
Ok(Imports::new(
|
Ok(Imports::new(
|
||||||
dependencies,
|
|
||||||
function_imports,
|
function_imports,
|
||||||
table_imports,
|
table_imports,
|
||||||
memory_imports,
|
memory_imports,
|
||||||
|
|||||||
@@ -3,11 +3,16 @@ use serde::ser::Serializer;
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use wasmer_compiler::{CompiledFunctionFrameInfo, FunctionBody, JumpTableOffsets, Relocation};
|
use wasmer_compiler::{
|
||||||
|
CompiledFunctionFrameInfo, FunctionBody, JumpTableOffsets, Relocation, SectionBody,
|
||||||
|
SectionIndex,
|
||||||
|
};
|
||||||
use wasmer_runtime::Module;
|
use wasmer_runtime::Module;
|
||||||
|
|
||||||
use wasm_common::entity::PrimaryMap;
|
use wasm_common::entity::PrimaryMap;
|
||||||
use wasm_common::{LocalFuncIndex, MemoryIndex, OwnedDataInitializer, TableIndex};
|
use wasm_common::{
|
||||||
|
Features, LocalFuncIndex, MemoryIndex, OwnedDataInitializer, SignatureIndex, TableIndex,
|
||||||
|
};
|
||||||
use wasmer_runtime::{MemoryPlan, TablePlan};
|
use wasmer_runtime::{MemoryPlan, TablePlan};
|
||||||
|
|
||||||
/// The compilation related data for a serialized modules
|
/// The compilation related data for a serialized modules
|
||||||
@@ -20,6 +25,8 @@ pub struct SerializableCompilation {
|
|||||||
// to allow lazy frame_info deserialization, we convert it to it's lazy binary
|
// to allow lazy frame_info deserialization, we convert it to it's lazy binary
|
||||||
// format upon serialization.
|
// format upon serialization.
|
||||||
pub function_frame_info: PrimaryMap<LocalFuncIndex, SerializableFunctionFrameInfo>,
|
pub function_frame_info: PrimaryMap<LocalFuncIndex, SerializableFunctionFrameInfo>,
|
||||||
|
pub trampolines: PrimaryMap<SignatureIndex, FunctionBody>,
|
||||||
|
pub custom_sections: PrimaryMap<SectionIndex, SectionBody>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Serializable struct that is able to serialize from and to
|
/// Serializable struct that is able to serialize from and to
|
||||||
@@ -27,6 +34,7 @@ pub struct SerializableCompilation {
|
|||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct SerializableModule {
|
pub struct SerializableModule {
|
||||||
pub compilation: SerializableCompilation,
|
pub compilation: SerializableCompilation,
|
||||||
|
pub features: Features,
|
||||||
pub module: Arc<Module>,
|
pub module: Arc<Module>,
|
||||||
pub data_initializers: Box<[OwnedDataInitializer]>,
|
pub data_initializers: Box<[OwnedDataInitializer]>,
|
||||||
// Plans for that module
|
// Plans for that module
|
||||||
|
|||||||
@@ -1,5 +1,10 @@
|
|||||||
use wasm_common::{MemoryType, TableType};
|
use crate::error::LinkError;
|
||||||
use wasmer_runtime::{LinearMemory, Table};
|
use wasm_common::entity::{EntityRef, PrimaryMap};
|
||||||
|
use wasm_common::{
|
||||||
|
GlobalIndex, LocalGlobalIndex, LocalMemoryIndex, LocalTableIndex, MemoryIndex, MemoryType,
|
||||||
|
TableIndex, TableType,
|
||||||
|
};
|
||||||
|
use wasmer_runtime::{LinearMemory, Module, Table, VMGlobalDefinition};
|
||||||
use wasmer_runtime::{MemoryPlan, TablePlan};
|
use wasmer_runtime::{MemoryPlan, TablePlan};
|
||||||
|
|
||||||
/// Tunables for an engine
|
/// Tunables for an engine
|
||||||
@@ -11,8 +16,56 @@ pub trait Tunables {
|
|||||||
fn table_plan(&self, table: TableType) -> TablePlan;
|
fn table_plan(&self, table: TableType) -> TablePlan;
|
||||||
|
|
||||||
/// Create a memory given a memory type
|
/// Create a memory given a memory type
|
||||||
fn create_memory(&self, memory_type: MemoryType) -> Result<LinearMemory, String>;
|
fn create_memory(&self, memory_type: MemoryPlan) -> Result<LinearMemory, String>;
|
||||||
|
|
||||||
/// Create a memory given a memory type
|
/// Create a memory given a memory type
|
||||||
fn create_table(&self, table_type: TableType) -> Table;
|
fn create_table(&self, table_type: TablePlan) -> Result<Table, String>;
|
||||||
|
|
||||||
|
/// Allocate memory for just the memories of the current module.
|
||||||
|
fn create_memories(
|
||||||
|
&self,
|
||||||
|
module: &Module,
|
||||||
|
memory_plans: &PrimaryMap<MemoryIndex, MemoryPlan>,
|
||||||
|
) -> Result<PrimaryMap<LocalMemoryIndex, LinearMemory>, LinkError> {
|
||||||
|
let num_imports = module.num_imported_memories;
|
||||||
|
let mut memories: PrimaryMap<LocalMemoryIndex, _> =
|
||||||
|
PrimaryMap::with_capacity(module.memories.len() - num_imports);
|
||||||
|
for index in num_imports..module.memories.len() {
|
||||||
|
let plan = memory_plans[MemoryIndex::new(index)].clone();
|
||||||
|
memories.push(self.create_memory(plan).map_err(LinkError::Resource)?);
|
||||||
|
}
|
||||||
|
Ok(memories)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Allocate memory for just the tables of the current module.
|
||||||
|
fn create_tables(
|
||||||
|
&self,
|
||||||
|
module: &Module,
|
||||||
|
table_plans: &PrimaryMap<TableIndex, TablePlan>,
|
||||||
|
) -> Result<PrimaryMap<LocalTableIndex, Table>, LinkError> {
|
||||||
|
let num_imports = module.num_imported_tables;
|
||||||
|
let mut tables: PrimaryMap<LocalTableIndex, _> =
|
||||||
|
PrimaryMap::with_capacity(module.tables.len() - num_imports);
|
||||||
|
for index in num_imports..module.tables.len() {
|
||||||
|
let plan = table_plans[TableIndex::new(index)].clone();
|
||||||
|
tables.push(self.create_table(plan).map_err(LinkError::Resource)?);
|
||||||
|
}
|
||||||
|
Ok(tables)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Allocate memory for just the globals of the current module,
|
||||||
|
/// with initializers applied.
|
||||||
|
fn create_globals(
|
||||||
|
&self,
|
||||||
|
module: &Module,
|
||||||
|
) -> Result<PrimaryMap<LocalGlobalIndex, VMGlobalDefinition>, LinkError> {
|
||||||
|
let num_imports = module.num_imported_globals;
|
||||||
|
let mut vmctx_globals = PrimaryMap::with_capacity(module.globals.len() - num_imports);
|
||||||
|
|
||||||
|
for _ in &module.globals.values().as_slice()[num_imports..] {
|
||||||
|
vmctx_globals.push(VMGlobalDefinition::new());
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(vmctx_globals)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
use crate::instance::InstanceHandle;
|
|
||||||
use crate::vmcontext::{VMFunctionImport, VMGlobalImport, VMMemoryImport, VMTableImport};
|
use crate::vmcontext::{VMFunctionImport, VMGlobalImport, VMMemoryImport, VMTableImport};
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use wasm_common::entity::{BoxedSlice, PrimaryMap};
|
use wasm_common::entity::{BoxedSlice, PrimaryMap};
|
||||||
@@ -7,9 +6,6 @@ use wasm_common::{FuncIndex, GlobalIndex, MemoryIndex, TableIndex};
|
|||||||
/// Resolved import pointers.
|
/// Resolved import pointers.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Imports {
|
pub struct Imports {
|
||||||
/// The set of instances that the imports depend on.
|
|
||||||
pub dependencies: HashSet<InstanceHandle>,
|
|
||||||
|
|
||||||
/// Resolved addresses for imported functions.
|
/// Resolved addresses for imported functions.
|
||||||
pub functions: BoxedSlice<FuncIndex, VMFunctionImport>,
|
pub functions: BoxedSlice<FuncIndex, VMFunctionImport>,
|
||||||
|
|
||||||
@@ -26,14 +22,12 @@ pub struct Imports {
|
|||||||
impl Imports {
|
impl Imports {
|
||||||
/// Construct a new `Imports` instance.
|
/// Construct a new `Imports` instance.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
dependencies: HashSet<InstanceHandle>,
|
|
||||||
function_imports: PrimaryMap<FuncIndex, VMFunctionImport>,
|
function_imports: PrimaryMap<FuncIndex, VMFunctionImport>,
|
||||||
table_imports: PrimaryMap<TableIndex, VMTableImport>,
|
table_imports: PrimaryMap<TableIndex, VMTableImport>,
|
||||||
memory_imports: PrimaryMap<MemoryIndex, VMMemoryImport>,
|
memory_imports: PrimaryMap<MemoryIndex, VMMemoryImport>,
|
||||||
global_imports: PrimaryMap<GlobalIndex, VMGlobalImport>,
|
global_imports: PrimaryMap<GlobalIndex, VMGlobalImport>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
dependencies,
|
|
||||||
functions: function_imports.into_boxed_slice(),
|
functions: function_imports.into_boxed_slice(),
|
||||||
tables: table_imports.into_boxed_slice(),
|
tables: table_imports.into_boxed_slice(),
|
||||||
memories: memory_imports.into_boxed_slice(),
|
memories: memory_imports.into_boxed_slice(),
|
||||||
@@ -44,7 +38,6 @@ impl Imports {
|
|||||||
/// Construct a new `Imports` instance with no imports.
|
/// Construct a new `Imports` instance with no imports.
|
||||||
pub fn none() -> Self {
|
pub fn none() -> Self {
|
||||||
Self {
|
Self {
|
||||||
dependencies: HashSet::new(),
|
|
||||||
functions: PrimaryMap::new().into_boxed_slice(),
|
functions: PrimaryMap::new().into_boxed_slice(),
|
||||||
tables: PrimaryMap::new().into_boxed_slice(),
|
tables: PrimaryMap::new().into_boxed_slice(),
|
||||||
memories: PrimaryMap::new().into_boxed_slice(),
|
memories: PrimaryMap::new().into_boxed_slice(),
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ cfg_if::cfg_if! {
|
|||||||
|
|
||||||
impl InstanceHandle {
|
impl InstanceHandle {
|
||||||
/// Set a custom signal handler
|
/// Set a custom signal handler
|
||||||
pub fn set_signal_handler<H>(&mut self, handler: H)
|
pub fn set_signal_handler<H>(&self, handler: H)
|
||||||
where
|
where
|
||||||
H: 'static + Fn(libc::c_int, *const libc::siginfo_t, *const libc::c_void) -> bool,
|
H: 'static + Fn(libc::c_int, *const libc::siginfo_t, *const libc::c_void) -> bool,
|
||||||
{
|
{
|
||||||
@@ -47,7 +47,7 @@ cfg_if::cfg_if! {
|
|||||||
|
|
||||||
impl InstanceHandle {
|
impl InstanceHandle {
|
||||||
/// Set a custom signal handler
|
/// Set a custom signal handler
|
||||||
pub fn set_signal_handler<H>(&mut self, handler: H)
|
pub fn set_signal_handler<H>(&self, handler: H)
|
||||||
where
|
where
|
||||||
H: 'static + Fn(winapi::um::winnt::PEXCEPTION_POINTERS) -> bool,
|
H: 'static + Fn(winapi::um::winnt::PEXCEPTION_POINTERS) -> bool,
|
||||||
{
|
{
|
||||||
@@ -62,14 +62,6 @@ cfg_if::cfg_if! {
|
|||||||
/// This is repr(C) to ensure that the vmctx field is last.
|
/// This is repr(C) to ensure that the vmctx field is last.
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub(crate) struct Instance {
|
pub(crate) struct Instance {
|
||||||
/// The number of references to this `Instance`.
|
|
||||||
refcount: Cell<usize>,
|
|
||||||
|
|
||||||
/// `Instance`s from which this `Instance` imports. These won't
|
|
||||||
/// create reference cycles because wasm instances can't cyclically
|
|
||||||
/// import from each other.
|
|
||||||
dependencies: HashSet<InstanceHandle>,
|
|
||||||
|
|
||||||
/// The `Module` this `Instance` was instantiated from.
|
/// The `Module` this `Instance` was instantiated from.
|
||||||
module: Arc<Module>,
|
module: Arc<Module>,
|
||||||
|
|
||||||
@@ -788,9 +780,7 @@ impl InstanceHandle {
|
|||||||
finished_tables: BoxedSlice<LocalTableIndex, Table>,
|
finished_tables: BoxedSlice<LocalTableIndex, Table>,
|
||||||
finished_globals: BoxedSlice<LocalGlobalIndex, VMGlobalDefinition>,
|
finished_globals: BoxedSlice<LocalGlobalIndex, VMGlobalDefinition>,
|
||||||
imports: Imports,
|
imports: Imports,
|
||||||
data_initializers: &[DataInitializer<'_>],
|
|
||||||
vmshared_signatures: BoxedSlice<SignatureIndex, VMSharedSignatureIndex>,
|
vmshared_signatures: BoxedSlice<SignatureIndex, VMSharedSignatureIndex>,
|
||||||
is_bulk_memory: bool,
|
|
||||||
host_state: Box<dyn Any>,
|
host_state: Box<dyn Any>,
|
||||||
) -> Result<Self, Trap> {
|
) -> Result<Self, Trap> {
|
||||||
let vmctx_tables = finished_tables
|
let vmctx_tables = finished_tables
|
||||||
@@ -813,8 +803,6 @@ impl InstanceHandle {
|
|||||||
|
|
||||||
let handle = {
|
let handle = {
|
||||||
let instance = Instance {
|
let instance = Instance {
|
||||||
refcount: Cell::new(1),
|
|
||||||
dependencies: imports.dependencies,
|
|
||||||
module,
|
module,
|
||||||
offsets,
|
offsets,
|
||||||
memories: finished_memories,
|
memories: finished_memories,
|
||||||
@@ -883,29 +871,42 @@ impl InstanceHandle {
|
|||||||
VMBuiltinFunctionsArray::initialized(),
|
VMBuiltinFunctionsArray::initialized(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Ensure that our signal handlers are ready for action.
|
||||||
|
init_traps();
|
||||||
|
|
||||||
|
// Perform infallible initialization in this constructor, while fallible
|
||||||
|
// initialization is deferred to the `initialize` method.
|
||||||
|
initialize_passive_elements(instance);
|
||||||
|
initialize_globals(instance);
|
||||||
|
|
||||||
|
Ok(handle)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Finishes the instantiation process started by `Instance::new`.
|
||||||
|
///
|
||||||
|
/// Only safe to call immediately after instantiation.
|
||||||
|
pub unsafe fn finish_instantiation(
|
||||||
|
&self,
|
||||||
|
is_bulk_memory: bool,
|
||||||
|
data_initializers: &[DataInitializer<'_>],
|
||||||
|
) -> Result<(), Trap> {
|
||||||
// Check initializer bounds before initializing anything. Only do this
|
// Check initializer bounds before initializing anything. Only do this
|
||||||
// when bulk memory is disabled, since the bulk memory proposal changes
|
// when bulk memory is disabled, since the bulk memory proposal changes
|
||||||
// instantiation such that the intermediate results of failed
|
// instantiation such that the intermediate results of failed
|
||||||
// initializations are visible.
|
// initializations are visible.
|
||||||
if !is_bulk_memory {
|
if !is_bulk_memory {
|
||||||
check_table_init_bounds(instance)?;
|
check_table_init_bounds(self.instance())?;
|
||||||
check_memory_init_bounds(instance, data_initializers)?;
|
check_memory_init_bounds(self.instance(), data_initializers)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply the initializers.
|
// Apply the initializers.
|
||||||
initialize_tables(instance)?;
|
initialize_tables(self.instance())?;
|
||||||
initialize_passive_elements(instance);
|
initialize_memories(self.instance(), data_initializers)?;
|
||||||
initialize_memories(instance, data_initializers)?;
|
|
||||||
initialize_globals(instance);
|
|
||||||
|
|
||||||
// Ensure that our signal handlers are ready for action.
|
|
||||||
init_traps();
|
|
||||||
|
|
||||||
// The WebAssembly spec specifies that the start function is
|
// The WebAssembly spec specifies that the start function is
|
||||||
// invoked automatically at instantiation time.
|
// invoked automatically at instantiation time.
|
||||||
instance.invoke_start_function()?;
|
self.instance().invoke_start_function()?;
|
||||||
|
Ok(())
|
||||||
Ok(handle)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new `InstanceHandle` pointing at the instance
|
/// Create a new `InstanceHandle` pointing at the instance
|
||||||
@@ -916,7 +917,6 @@ impl InstanceHandle {
|
|||||||
/// be a `VMContext` allocated as part of an `Instance`.
|
/// be a `VMContext` allocated as part of an `Instance`.
|
||||||
pub unsafe fn from_vmctx(vmctx: *mut VMContext) -> Self {
|
pub unsafe fn from_vmctx(vmctx: *mut VMContext) -> Self {
|
||||||
let instance = (&mut *vmctx).instance();
|
let instance = (&mut *vmctx).instance();
|
||||||
instance.refcount.set(instance.refcount.get() + 1);
|
|
||||||
Self {
|
Self {
|
||||||
instance: instance as *const Instance as *mut Instance,
|
instance: instance as *const Instance as *mut Instance,
|
||||||
}
|
}
|
||||||
@@ -1031,32 +1031,36 @@ impl InstanceHandle {
|
|||||||
pub(crate) fn instance(&self) -> &Instance {
|
pub(crate) fn instance(&self) -> &Instance {
|
||||||
unsafe { &*(self.instance as *const Instance) }
|
unsafe { &*(self.instance as *const Instance) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Deallocates memory associated with this instance.
|
||||||
|
///
|
||||||
|
/// Note that this is unsafe because there might be other handles to this
|
||||||
|
/// `InstanceHandle` elsewhere, and there's nothing preventing usage of
|
||||||
|
/// this handle after this function is called.
|
||||||
|
pub unsafe fn dealloc(&self) {
|
||||||
|
let instance = self.instance();
|
||||||
|
let layout = instance.alloc_layout();
|
||||||
|
ptr::drop_in_place(self.instance);
|
||||||
|
alloc::dealloc(self.instance.cast(), layout);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Clone for InstanceHandle {
|
impl Clone for InstanceHandle {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
let instance = self.instance();
|
|
||||||
instance.refcount.set(instance.refcount.get() + 1);
|
|
||||||
Self {
|
Self {
|
||||||
instance: self.instance,
|
instance: self.instance,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for InstanceHandle {
|
// TODO: uncomment this, as we need to store the handles
|
||||||
fn drop(&mut self) {
|
// in the store, and once the store is dropped, then the instances
|
||||||
let instance = self.instance();
|
// will too.
|
||||||
let count = instance.refcount.get();
|
// impl Drop for InstanceHandle {
|
||||||
instance.refcount.set(count - 1);
|
// fn drop(&mut self) {
|
||||||
if count == 1 {
|
// unsafe { self.dealloc() }
|
||||||
let layout = instance.alloc_layout();
|
// }
|
||||||
unsafe {
|
// }
|
||||||
ptr::drop_in_place(self.instance);
|
|
||||||
alloc::dealloc(self.instance.cast(), layout);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn check_table_init_bounds(instance: &Instance) -> Result<(), Trap> {
|
fn check_table_init_bounds(instance: &Instance) -> Result<(), Trap> {
|
||||||
let module = Arc::clone(&instance.module);
|
let module = Arc::clone(&instance.module);
|
||||||
|
|||||||
@@ -19,20 +19,22 @@ pub struct Table {
|
|||||||
|
|
||||||
impl Table {
|
impl Table {
|
||||||
/// Create a new table instance with specified minimum and maximum number of elements.
|
/// Create a new table instance with specified minimum and maximum number of elements.
|
||||||
pub fn new(plan: &TablePlan) -> Self {
|
pub fn new(plan: &TablePlan) -> Result<Self, String> {
|
||||||
match plan.table.ty {
|
match plan.table.ty {
|
||||||
Type::FuncRef => (),
|
Type::FuncRef => (),
|
||||||
ty => unimplemented!("tables of types other than anyfunc ({})", ty),
|
ty => return Err(format!("tables of types other than anyfunc ({})", ty)),
|
||||||
};
|
};
|
||||||
match plan.style {
|
match plan.style {
|
||||||
TableStyle::CallerChecksSignature => Self {
|
TableStyle::CallerChecksSignature => Ok(Self {
|
||||||
vec: RefCell::new(vec![
|
vec: RefCell::new(vec![
|
||||||
VMCallerCheckedAnyfunc::default();
|
VMCallerCheckedAnyfunc::default();
|
||||||
usize::try_from(plan.table.minimum).unwrap()
|
usize::try_from(plan.table.minimum).map_err(|_| {
|
||||||
|
"Table minimum is bigger than usize".to_string()
|
||||||
|
})?
|
||||||
]),
|
]),
|
||||||
maximum: plan.table.maximum,
|
maximum: plan.table.maximum,
|
||||||
plan: plan.clone(),
|
plan: plan.clone(),
|
||||||
},
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,12 @@
|
|||||||
|
#[cfg(feature = "enable-serde")]
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
/// Controls which experimental features will be enabled.
|
/// Controls which experimental features will be enabled.
|
||||||
/// Features usually have a corresponding [WebAssembly proposal].
|
/// Features usually have a corresponding [WebAssembly proposal].
|
||||||
///
|
///
|
||||||
/// [WebAssembly proposal]: https://github.com/WebAssembly/proposals
|
/// [WebAssembly proposal]: https://github.com/WebAssembly/proposals
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
|
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
|
||||||
pub struct Features {
|
pub struct Features {
|
||||||
/// Threads proposal should be enabled
|
/// Threads proposal should be enabled
|
||||||
pub threads: bool,
|
pub threads: bool,
|
||||||
|
|||||||
@@ -99,7 +99,8 @@ impl Run {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If WASI is enabled, try to execute it with it
|
// If WASI is enabled, try to execute it with it
|
||||||
if cfg!(feature = "wasi") {
|
#[cfg(feature = "wasi")]
|
||||||
|
{
|
||||||
let wasi_version = Wasi::get_version(&module);
|
let wasi_version = Wasi::get_version(&module);
|
||||||
if let Some(version) = wasi_version {
|
if let Some(version) = wasi_version {
|
||||||
let program_name = self
|
let program_name = self
|
||||||
@@ -129,9 +130,9 @@ impl Run {
|
|||||||
fn get_module(&self) -> Result<Module> {
|
fn get_module(&self) -> Result<Module> {
|
||||||
let contents = std::fs::read(self.path.clone())?;
|
let contents = std::fs::read(self.path.clone())?;
|
||||||
if Engine::is_deserializable(&contents) {
|
if Engine::is_deserializable(&contents) {
|
||||||
let (compiler_config, _compiler_name) = self.compiler.get_compiler_config()?;
|
// We get the tunables for the current host
|
||||||
let tunables = self.compiler.get_tunables(&*compiler_config);
|
let tunables = Tunables::default();
|
||||||
let engine = Engine::new(&*compiler_config, tunables);
|
let engine = Engine::headless(tunables);
|
||||||
let store = Store::new(&engine);
|
let store = Store::new(&engine);
|
||||||
let module = unsafe { Module::deserialize(&store, &contents)? };
|
let module = unsafe { Module::deserialize(&store, &contents)? };
|
||||||
return Ok(module);
|
return Ok(module);
|
||||||
|
|||||||
@@ -34,25 +34,6 @@ pub struct WasmFeatures {
|
|||||||
pub all: bool,
|
pub all: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, StructOpt)]
|
|
||||||
/// The compiler options
|
|
||||||
pub struct Compiler {
|
|
||||||
/// Use Singlepass compiler
|
|
||||||
#[structopt(long, conflicts_with_all = &["cranelift", "llvm"])]
|
|
||||||
singlepass: bool,
|
|
||||||
|
|
||||||
/// Use Cranelift compiler
|
|
||||||
#[structopt(long, conflicts_with_all = &["singlepass", "llvm"])]
|
|
||||||
cranelift: bool,
|
|
||||||
|
|
||||||
/// Use LLVM compiler
|
|
||||||
#[structopt(long, conflicts_with_all = &["singlepass", "cranelifft"])]
|
|
||||||
llvm: bool,
|
|
||||||
|
|
||||||
#[structopt(flatten)]
|
|
||||||
features: WasmFeatures,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the cache dir
|
/// Get the cache dir
|
||||||
pub fn get_cache_dir() -> PathBuf {
|
pub fn get_cache_dir() -> PathBuf {
|
||||||
match env::var("WASMER_CACHE_DIR") {
|
match env::var("WASMER_CACHE_DIR") {
|
||||||
|
|||||||
16
src/store.rs
16
src/store.rs
@@ -62,6 +62,7 @@ impl FromStr for Compiler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "compiler")]
|
||||||
impl StoreOptions {
|
impl StoreOptions {
|
||||||
fn get_compiler(&self) -> Result<Compiler> {
|
fn get_compiler(&self) -> Result<Compiler> {
|
||||||
if self.cranelift {
|
if self.cranelift {
|
||||||
@@ -91,6 +92,7 @@ impl StoreOptions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get the Compiler Config for the current options
|
/// Get the Compiler Config for the current options
|
||||||
|
#[allow(unused_variables)]
|
||||||
fn get_config(&self, compiler: Compiler) -> Result<Box<dyn CompilerConfig>> {
|
fn get_config(&self, compiler: Compiler) -> Result<Box<dyn CompilerConfig>> {
|
||||||
let config: Box<dyn CompilerConfig> = match compiler {
|
let config: Box<dyn CompilerConfig> = match compiler {
|
||||||
#[cfg(feature = "compiler-singlepass")]
|
#[cfg(feature = "compiler-singlepass")]
|
||||||
@@ -122,7 +124,7 @@ impl StoreOptions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get's the compiler config
|
/// Get's the compiler config
|
||||||
pub fn get_compiler_config(&self) -> Result<(Box<dyn CompilerConfig>, String)> {
|
fn get_compiler_config(&self) -> Result<(Box<dyn CompilerConfig>, String)> {
|
||||||
let compiler = self.get_compiler()?;
|
let compiler = self.get_compiler()?;
|
||||||
let compiler_name = compiler.to_string();
|
let compiler_name = compiler.to_string();
|
||||||
let compiler_config = self.get_config(compiler)?;
|
let compiler_config = self.get_config(compiler)?;
|
||||||
@@ -143,3 +145,15 @@ impl StoreOptions {
|
|||||||
Ok((store, compiler_name))
|
Ok((store, compiler_name))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "compiler"))]
|
||||||
|
impl StoreOptions {
|
||||||
|
/// Get the store (headless engine)
|
||||||
|
pub fn get_store(&self) -> Result<(Store, String)> {
|
||||||
|
// Get the tunables for the current host
|
||||||
|
let tunables = Tunables::default();
|
||||||
|
let engine = Engine::headless(tunables);
|
||||||
|
let store = Store::new(&engine);
|
||||||
|
Ok((store, "headless".to_string()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -15,12 +15,16 @@ wasmer-compiler-cranelift = { path = "../../../lib/compiler-cranelift", version
|
|||||||
wasmer-compiler-llvm = { path = "../../../lib/compiler-llvm", version = "0.16.2", optional = true }
|
wasmer-compiler-llvm = { path = "../../../lib/compiler-llvm", version = "0.16.2", optional = true }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
|
compiler = []
|
||||||
compiler-singlepass = [
|
compiler-singlepass = [
|
||||||
"wasmer-compiler-singlepass",
|
"wasmer-compiler-singlepass",
|
||||||
|
"compiler",
|
||||||
]
|
]
|
||||||
compiler-cranelift = [
|
compiler-cranelift = [
|
||||||
"wasmer-compiler-cranelift",
|
"wasmer-compiler-cranelift",
|
||||||
|
"compiler",
|
||||||
]
|
]
|
||||||
compiler-llvm = [
|
compiler-llvm = [
|
||||||
"wasmer-compiler-llvm",
|
"wasmer-compiler-llvm",
|
||||||
|
"compiler",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
#![cfg(feature = "compiler")]
|
||||||
|
|
||||||
use wasmer_compiler::{CompilerConfig, Features, Target};
|
use wasmer_compiler::{CompilerConfig, Features, Target};
|
||||||
|
|
||||||
pub fn get_compiler_config_from_str(
|
pub fn get_compiler_config_from_str(
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
#![cfg(feature = "compiler")]
|
||||||
|
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use test_utils::get_compiler_config_from_str;
|
use test_utils::get_compiler_config_from_str;
|
||||||
use wasmer::{Engine, Features, Store, Tunables};
|
use wasmer::{Engine, Features, Store, Tunables};
|
||||||
@@ -16,7 +18,10 @@ use wasmer_wast::Wast;
|
|||||||
include!(concat!(env!("OUT_DIR"), "/generated_spectests.rs"));
|
include!(concat!(env!("OUT_DIR"), "/generated_spectests.rs"));
|
||||||
|
|
||||||
fn run_wast(wast_path: &str, compiler: &str) -> anyhow::Result<()> {
|
fn run_wast(wast_path: &str, compiler: &str) -> anyhow::Result<()> {
|
||||||
println!("Running wast {} with {}", wast_path, compiler);
|
println!(
|
||||||
|
"Running wast `{}` with the {} compiler",
|
||||||
|
wast_path, compiler
|
||||||
|
);
|
||||||
let try_nan_canonicalization = wast_path.contains("nan-canonicalization");
|
let try_nan_canonicalization = wast_path.contains("nan-canonicalization");
|
||||||
let mut features = Features::default();
|
let mut features = Features::default();
|
||||||
if wast_path.contains("bulk-memory") {
|
if wast_path.contains("bulk-memory") {
|
||||||
|
|||||||
Reference in New Issue
Block a user