mirror of
https://github.com/mii443/wasmer.git
synced 2025-12-09 06:08:29 +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]]
|
||||
name = "smallvec"
|
||||
version = "1.3.0"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "05720e22615919e4734f6a99ceae50d00226c3c5aca406e102ebc33298214e0a"
|
||||
checksum = "c7cb5678e1615754284ec264d9bb5b4c27d2018577fd90ac0ceb578591ed5ee4"
|
||||
|
||||
[[package]]
|
||||
name = "stable_deref_trait"
|
||||
|
||||
32
Cargo.toml
32
Cargo.toml
@@ -20,16 +20,16 @@ publish = false
|
||||
autoexamples = false
|
||||
|
||||
[dependencies]
|
||||
wasmer = { path = "lib/api" }
|
||||
wasmer-compiler = { path = "lib/compiler" }
|
||||
wasmer-compiler-cranelift = { path = "lib/compiler-cranelift", optional = true }
|
||||
wasmer-compiler-singlepass = { path = "lib/compiler-singlepass", optional = true }
|
||||
wasmer-compiler-llvm = { path = "lib/compiler-llvm", optional = true }
|
||||
wasmer-jit = { path = "lib/jit" }
|
||||
wasmer-wasi = { path = "lib/wasi", optional = true }
|
||||
wasmer-wasi-experimental-io-devices = { path = "lib/wasi-experimental-io-devices", optional = true }
|
||||
wasmer-wast = { path = "tests/lib/wast", optional = true }
|
||||
wasmer-cache = { path = "lib/cache", optional = true }
|
||||
wasmer = { version = "0.16.2", path = "lib/api" }
|
||||
wasmer-compiler = { version = "0.16.2", path = "lib/compiler" }
|
||||
wasmer-compiler-cranelift = { version = "0.16.2", path = "lib/compiler-cranelift", optional = true }
|
||||
wasmer-compiler-singlepass = { version = "0.16.2", path = "lib/compiler-singlepass", optional = true }
|
||||
wasmer-compiler-llvm = { version = "0.16.2", path = "lib/compiler-llvm", optional = true }
|
||||
wasmer-jit = { version = "0.16.2", path = "lib/jit" }
|
||||
wasmer-wasi = { version = "0.16.2", path = "lib/wasi", optional = true }
|
||||
wasmer-wasi-experimental-io-devices = { version = "0.16.2", path = "lib/wasi-experimental-io-devices", optional = true }
|
||||
wasmer-wast = { version = "0.16.2", path = "tests/lib/wast", optional = true }
|
||||
wasmer-cache = { version = "0.16.2", path = "lib/cache", optional = true }
|
||||
atty = "0.2"
|
||||
anyhow = "1.0.28"
|
||||
structopt = { version = "0.3", features = ["suggestions"] }
|
||||
@@ -47,19 +47,15 @@ rustc_version = "0.2"
|
||||
[dev-dependencies]
|
||||
anyhow = "1.0.28"
|
||||
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]
|
||||
# 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.
|
||||
# default = ["wasi"]
|
||||
default = ["wast", "wasi", "experimental-io-devices", "compiler-cranelift", "cache"]
|
||||
cache = ["wasmer-cache"]
|
||||
wast = ["wasmer-wast"]
|
||||
wasi = ["wasmer-wasi"]
|
||||
compiler = ["wasmer-jit/compiler"]
|
||||
experimental-io-devices = [
|
||||
"wasmer-wasi-experimental-io-devices"
|
||||
]
|
||||
@@ -67,14 +63,20 @@ compiler-singlepass = [
|
||||
"test-utils/compiler-singlepass",
|
||||
"wasmer/compiler-singlepass",
|
||||
"wasmer-compiler-singlepass",
|
||||
"compiler",
|
||||
]
|
||||
compiler-cranelift = [
|
||||
"test-utils/compiler-cranelift",
|
||||
"wasmer/compiler-cranelift",
|
||||
"wasmer-compiler-cranelift",
|
||||
"compiler",
|
||||
]
|
||||
compiler-llvm = [
|
||||
"test-utils/compiler-llvm",
|
||||
"wasmer/compiler-llvm",
|
||||
"wasmer-compiler-llvm",
|
||||
"compiler",
|
||||
]
|
||||
|
||||
# [profile.release]
|
||||
# lto = "fat"
|
||||
|
||||
@@ -38,14 +38,18 @@ maintenance = { status = "actively-developed" }
|
||||
|
||||
[features]
|
||||
default = ["wat", "default-compiler-cranelift"]
|
||||
compiler = ["wasmer-jit/compiler"]
|
||||
compiler-singlepass = [
|
||||
"wasmer-compiler-singlepass"
|
||||
"wasmer-compiler-singlepass",
|
||||
"compiler",
|
||||
]
|
||||
compiler-cranelift = [
|
||||
"wasmer-compiler-cranelift"
|
||||
"wasmer-compiler-cranelift",
|
||||
"compiler",
|
||||
]
|
||||
compiler-llvm = [
|
||||
"wasmer-compiler-llvm"
|
||||
"wasmer-compiler-llvm",
|
||||
"compiler",
|
||||
]
|
||||
default-compiler-singlepass = [
|
||||
"compiler-singlepass"
|
||||
|
||||
@@ -231,7 +231,9 @@ fn set_table_item(
|
||||
impl Table {
|
||||
pub fn new(store: &Store, ty: TableType, init: Val) -> Result<Table, RuntimeError> {
|
||||
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();
|
||||
for i in 0..definition.current_elements {
|
||||
@@ -345,7 +347,10 @@ pub struct Memory {
|
||||
|
||||
impl 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();
|
||||
|
||||
Memory {
|
||||
|
||||
@@ -194,13 +194,15 @@ impl Extend<((String, String), Export)> for ImportObject {
|
||||
///
|
||||
///
|
||||
/// # Usage:
|
||||
/// ```ignore
|
||||
/// use wasmer::{imports, func};
|
||||
/// ```
|
||||
/// # use wasmer::{Func, Store};
|
||||
/// # let store = Store::default();
|
||||
/// use wasmer::imports;
|
||||
///
|
||||
/// let import_object = imports! {
|
||||
/// "env" => {
|
||||
/// "foo" => func!(foo),
|
||||
/// },
|
||||
/// "foo" => Func::new(&store, foo)
|
||||
/// }
|
||||
/// };
|
||||
///
|
||||
/// 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]
|
||||
#[doc(hidden)]
|
||||
macro_rules! namespace {
|
||||
($( $imp_name:expr => $import_item:expr ),* $(,)? ) => {
|
||||
$crate::import_namespace!({ $( $imp_name => $import_item, )* })
|
||||
|
||||
@@ -27,7 +27,10 @@ pub use crate::types::{
|
||||
};
|
||||
|
||||
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::{
|
||||
DeserializeError, InstantiationError, LinkError, RuntimeError, SerializeError,
|
||||
};
|
||||
|
||||
@@ -184,7 +184,17 @@ impl Module {
|
||||
&self,
|
||||
resolver: &dyn Resolver,
|
||||
) -> 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.
|
||||
|
||||
@@ -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 std::sync::Arc;
|
||||
#[cfg(feature = "compiler")]
|
||||
use wasmer_compiler::CompilerConfig;
|
||||
use wasmer_jit::JITEngine;
|
||||
|
||||
|
||||
@@ -92,14 +92,12 @@ impl wasmer_jit::Tunables for Tunables {
|
||||
}
|
||||
|
||||
/// Create a memory given a memory type
|
||||
fn create_memory(&self, memory_type: MemoryType) -> Result<LinearMemory, String> {
|
||||
let plan = self.memory_plan(memory_type);
|
||||
fn create_memory(&self, plan: MemoryPlan) -> Result<LinearMemory, String> {
|
||||
LinearMemory::new(&plan)
|
||||
}
|
||||
|
||||
/// Create a memory given a memory type
|
||||
fn create_table(&self, table_type: TableType) -> Table {
|
||||
let plan = self.table_plan(table_type);
|
||||
fn create_table(&self, plan: TablePlan) -> Result<Table, String> {
|
||||
Table::new(&plan)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ hashbrown = { version = "0.7.2", optional = true }
|
||||
tracing = "0.1"
|
||||
cranelift-codegen = { 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" }
|
||||
wasm-common = { path = "../wasm-common", version = "0.16.2", default-features = false }
|
||||
rayon = "1.3.0"
|
||||
|
||||
@@ -10,7 +10,7 @@ edition = "2018"
|
||||
readme = "README.md"
|
||||
|
||||
[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" }
|
||||
wasm-common = { path = "../wasm-common", version = "0.16.2" }
|
||||
target-lexicon = { version = "0.10.0", default-features = false }
|
||||
|
||||
@@ -12,7 +12,7 @@ use wasm_common::{FuncIndex, FuncType, LocalFuncIndex, MemoryIndex, TableIndex};
|
||||
use wasmer_compiler::{
|
||||
Compilation, CompileError, CompiledFunction, Compiler, CompilerConfig, CustomSection,
|
||||
CustomSectionProtection, FunctionBody, FunctionBodyData, ModuleTranslationState, Relocation,
|
||||
RelocationTarget, SectionIndex, Target, TrapInformation,
|
||||
RelocationTarget, SectionBody, SectionIndex, Target, TrapInformation,
|
||||
};
|
||||
use wasmer_runtime::{MemoryPlan, Module, TablePlan, TrapCode};
|
||||
|
||||
@@ -71,7 +71,7 @@ impl Compiler for LLVMCompiler {
|
||||
let mut used_readonly_section = false;
|
||||
let mut readonly_section = CustomSection {
|
||||
protection: CustomSectionProtection::Read,
|
||||
bytes: Vec::new(),
|
||||
bytes: SectionBody::default(),
|
||||
};
|
||||
|
||||
for (func_index, _) in &module.functions {
|
||||
@@ -112,7 +112,7 @@ impl Compiler for LLVMCompiler {
|
||||
}
|
||||
};
|
||||
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.
|
||||
for local_relocation in &local_relocations {
|
||||
if local_relocation.local_section_index == local_idx {
|
||||
|
||||
@@ -40,7 +40,7 @@ use wasmer_compiler::{
|
||||
to_wasm_error, wasm_unsupported, Addend, CodeOffset, CompileError, CompiledFunction,
|
||||
CompiledFunctionFrameInfo, CompiledFunctionUnwindInfo, CustomSection, CustomSectionProtection,
|
||||
FunctionAddressMap, FunctionBody, FunctionBodyData, Relocation, RelocationKind,
|
||||
RelocationTarget, SourceLoc, WasmResult,
|
||||
RelocationTarget, SectionBody, SourceLoc, WasmResult,
|
||||
};
|
||||
use wasmer_runtime::libcalls::LibCall;
|
||||
use wasmer_runtime::Module as WasmerCompilerModule;
|
||||
@@ -384,7 +384,7 @@ impl FuncTranslator {
|
||||
required_custom_sections.len(),
|
||||
CustomSection {
|
||||
protection: CustomSectionProtection::Read,
|
||||
bytes: vec![],
|
||||
bytes: SectionBody::default(),
|
||||
},
|
||||
);
|
||||
for section in object.get_sections() {
|
||||
|
||||
@@ -13,7 +13,7 @@ edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
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" }
|
||||
wasm-common = { path = "../wasm-common", version = "0.16.2", default-features = false }
|
||||
rayon = "1.3.0"
|
||||
|
||||
@@ -26,6 +26,10 @@ raw-cpuid = "7.0.3"
|
||||
|
||||
[features]
|
||||
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 = []
|
||||
core = ["hashbrown"]
|
||||
enable-serde = ["serde", "serde_bytes"]
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
//! This module mainly outputs the `Compiler` trait that custom
|
||||
//! compilers will need to implement.
|
||||
|
||||
use crate::config::Target;
|
||||
use crate::error::CompileError;
|
||||
use crate::function::{Compilation, FunctionBody};
|
||||
use crate::std::boxed::Box;
|
||||
use crate::std::vec::Vec;
|
||||
use crate::target::Target;
|
||||
use crate::FunctionBodyData;
|
||||
use crate::ModuleTranslationState;
|
||||
use wasm_common::entity::PrimaryMap;
|
||||
@@ -13,6 +14,22 @@ use wasmer_runtime::Module;
|
||||
use wasmer_runtime::{MemoryPlan, TablePlan};
|
||||
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.
|
||||
pub trait Compiler {
|
||||
/// Gets the target associated with this compiler
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
use crate::std::string::String;
|
||||
use crate::translator::WasmError;
|
||||
use thiserror::Error;
|
||||
|
||||
// Compilation Errors
|
||||
@@ -28,3 +27,39 @@ pub enum CompileError {
|
||||
#[error("Insufficient resources: {0}")]
|
||||
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
|
||||
//! * `obj`: to generate a native object
|
||||
|
||||
use crate::section::{CustomSection, SectionIndex};
|
||||
use crate::section::{CustomSection, SectionBody, SectionIndex};
|
||||
use crate::std::vec::Vec;
|
||||
use crate::trap::TrapInformation;
|
||||
use crate::{CompiledFunctionUnwindInfo, FunctionAddressMap, JumpTableOffsets, Relocation};
|
||||
@@ -130,6 +130,14 @@ impl Compilation {
|
||||
.map(|(_, func)| func.frame_info.clone())
|
||||
.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 {
|
||||
|
||||
@@ -38,41 +38,46 @@ use hashbrown::HashMap;
|
||||
use std::collections::HashMap;
|
||||
|
||||
mod address_map;
|
||||
#[cfg(feature = "translator")]
|
||||
mod compiler;
|
||||
mod config;
|
||||
mod error;
|
||||
mod function;
|
||||
mod jump_table;
|
||||
mod relocation;
|
||||
mod target;
|
||||
mod trap;
|
||||
mod unwind;
|
||||
#[cfg(feature = "translator")]
|
||||
#[macro_use]
|
||||
mod translator;
|
||||
mod section;
|
||||
mod sourceloc;
|
||||
|
||||
pub use crate::address_map::{FunctionAddressMap, InstructionAddressMap};
|
||||
pub use crate::compiler::Compiler;
|
||||
pub use crate::config::{
|
||||
Architecture, CallingConvention, CompilerConfig, CpuFeature, Features, OperatingSystem, Target,
|
||||
Triple,
|
||||
};
|
||||
pub use crate::error::CompileError;
|
||||
#[cfg(feature = "translator")]
|
||||
pub use crate::compiler::{Compiler, CompilerConfig};
|
||||
pub use crate::error::{CompileError, WasmError, WasmResult};
|
||||
pub use crate::function::{
|
||||
Compilation, CompiledFunction, CompiledFunctionFrameInfo, CustomSections, FunctionBody,
|
||||
Functions,
|
||||
};
|
||||
pub use crate::jump_table::{JumpTable, JumpTableOffsets};
|
||||
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::target::{
|
||||
Architecture, CallingConvention, CpuFeature, OperatingSystem, Target, Triple,
|
||||
};
|
||||
#[cfg(feature = "translator")]
|
||||
pub use crate::translator::{
|
||||
to_wasm_error, translate_module, FunctionBodyData, ModuleEnvironment, ModuleTranslation,
|
||||
ModuleTranslationState, WasmError, WasmResult,
|
||||
ModuleTranslationState,
|
||||
};
|
||||
pub use crate::trap::TrapInformation;
|
||||
pub use crate::unwind::{CompiledFunctionUnwindInfo, FDERelocEntry, FunctionTableReloc};
|
||||
|
||||
pub use wasm_common::Features;
|
||||
|
||||
/// wasmparser is exported as a module to slim compiler dependencies
|
||||
pub mod wasmparser {
|
||||
pub use wasmparser::*;
|
||||
|
||||
@@ -46,6 +46,31 @@ pub struct CustomSection {
|
||||
/// > (the start of the memory pointer).
|
||||
/// > We might need to create another field for alignment in case it's
|
||||
/// > needed in the future.
|
||||
#[serde(with = "serde_bytes")]
|
||||
pub bytes: Vec<u8>,
|
||||
pub bytes: SectionBody,
|
||||
}
|
||||
|
||||
/// 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
|
||||
use crate::compiler::Compiler;
|
||||
use crate::std::boxed::Box;
|
||||
//! Target configuration
|
||||
use enumset::{EnumSet, EnumSetType};
|
||||
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"))]
|
||||
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::state::ModuleTranslationState;
|
||||
use crate::std::borrow::ToOwned;
|
||||
use crate::std::string::ToString;
|
||||
use crate::std::{boxed::Box, string::String, vec::Vec};
|
||||
use crate::{WasmError, WasmResult};
|
||||
use std::convert::TryFrom;
|
||||
use std::sync::Arc;
|
||||
use wasm_common::entity::PrimaryMap;
|
||||
|
||||
@@ -1,39 +1,7 @@
|
||||
use crate::std::string::String;
|
||||
use crate::WasmError;
|
||||
use thiserror::Error;
|
||||
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!`
|
||||
/// on the arguments to this macro.
|
||||
#[macro_export]
|
||||
@@ -48,6 +16,3 @@ pub fn to_wasm_error(e: BinaryReaderError) -> WasmError {
|
||||
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;
|
||||
|
||||
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::state::ModuleTranslationState;
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
//! Translation skeleton that traverses the whole WebAssembly module and call helper functions
|
||||
//! to deal with each part of it.
|
||||
use super::environ::ModuleEnvironment;
|
||||
use super::error::{to_wasm_error, WasmResult};
|
||||
use super::error::to_wasm_error;
|
||||
use super::sections::{
|
||||
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_name_section, parse_start_section, parse_table_section, parse_type_section,
|
||||
};
|
||||
use super::state::ModuleTranslationState;
|
||||
use crate::WasmResult;
|
||||
use wasmparser::{CustomSectionContent, ModuleReader, SectionContent};
|
||||
|
||||
/// 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
|
||||
//! interpreted on the fly.
|
||||
use super::environ::ModuleEnvironment;
|
||||
use super::error::{to_wasm_error, WasmError, WasmResult};
|
||||
use super::error::to_wasm_error;
|
||||
use super::state::ModuleTranslationState;
|
||||
use crate::{wasm_unsupported, HashMap};
|
||||
use crate::{WasmError, WasmResult};
|
||||
use core::convert::TryFrom;
|
||||
use std::boxed::Box;
|
||||
use std::vec::Vec;
|
||||
|
||||
@@ -29,5 +29,10 @@ lazy_static = "1.4"
|
||||
[target.'cfg(target_os = "windows")'.dependencies]
|
||||
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]
|
||||
maintenance = { status = "actively-developed" }
|
||||
|
||||
@@ -9,11 +9,10 @@ use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use wasm_common::entity::PrimaryMap;
|
||||
use wasm_common::{FuncType, LocalFuncIndex, MemoryIndex, TableIndex};
|
||||
use wasmer_compiler::{
|
||||
Compilation, CompileError, Compiler as BaseCompiler, CompilerConfig, FunctionBody,
|
||||
FunctionBodyData, ModuleTranslationState, Target,
|
||||
};
|
||||
use wasm_common::{FuncType, LocalFuncIndex, MemoryIndex, SignatureIndex, TableIndex};
|
||||
use wasmer_compiler::{Compilation, CompileError, FunctionBody, Target};
|
||||
#[cfg(feature = "compiler")]
|
||||
use wasmer_compiler::{Compiler, CompilerConfig};
|
||||
use wasmer_runtime::{
|
||||
InstanceHandle, MemoryPlan, Module, SignatureRegistry, TablePlan, VMFunctionBody,
|
||||
VMSharedSignatureIndex, VMTrampoline,
|
||||
@@ -29,7 +28,8 @@ pub struct JITEngine {
|
||||
impl JITEngine {
|
||||
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
|
||||
where
|
||||
C: ?Sized,
|
||||
@@ -37,7 +37,33 @@ impl JITEngine {
|
||||
let compiler = config.compiler();
|
||||
Self {
|
||||
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(),
|
||||
code_memory: CodeMemory::new(),
|
||||
signatures: SignatureRegistry::new(),
|
||||
@@ -93,7 +119,7 @@ impl JITEngine {
|
||||
}
|
||||
|
||||
/// Instantiates a WebAssembly module
|
||||
pub fn instantiate(
|
||||
pub unsafe fn instantiate(
|
||||
&self,
|
||||
compiled_module: &CompiledModule,
|
||||
resolver: &dyn Resolver,
|
||||
@@ -126,7 +152,8 @@ impl JITEngine {
|
||||
/// The inner contents of `JITEngine`
|
||||
pub struct JITEngineInner {
|
||||
/// The compiler
|
||||
compiler: Box<dyn BaseCompiler>,
|
||||
#[cfg(feature = "compiler")]
|
||||
compiler: Option<Box<dyn Compiler>>,
|
||||
/// Pointers to trampoline functions used to enter particular signatures
|
||||
trampolines: HashMap<VMSharedSignatureIndex, VMTrampoline>,
|
||||
/// The code memory is responsible of publishing the compiled
|
||||
@@ -139,38 +166,34 @@ pub struct JITEngineInner {
|
||||
|
||||
impl JITEngineInner {
|
||||
/// Gets the compiler associated to this JIT
|
||||
pub fn compiler(&self) -> &dyn BaseCompiler {
|
||||
&*self.compiler
|
||||
#[cfg(feature = "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
|
||||
#[cfg(feature = "compiler")]
|
||||
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.
|
||||
pub(crate) fn compile_module<'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>(
|
||||
pub(crate) fn allocate<'data>(
|
||||
&mut self,
|
||||
module: &Module,
|
||||
functions: &PrimaryMap<LocalFuncIndex, FunctionBody>,
|
||||
trampolines: &PrimaryMap<SignatureIndex, FunctionBody>,
|
||||
) -> Result<PrimaryMap<LocalFuncIndex, *mut [VMFunctionBody]>, CompileError> {
|
||||
// Allocate all of the compiled functions into executable memory,
|
||||
// copying over their contents.
|
||||
@@ -184,35 +207,27 @@ impl JITEngineInner {
|
||||
))
|
||||
})?;
|
||||
|
||||
// Trampoline generation.
|
||||
// We do it in two steps:
|
||||
// 1. Generate only the trampolines for the signatures that are unique
|
||||
// 2. Push the compiled code to memory
|
||||
let mut unique_signatures: HashMap<VMSharedSignatureIndex, FuncType> = HashMap::new();
|
||||
// for sig in module.exported_signatures() {
|
||||
for sig in module.signatures.values() {
|
||||
let index = self.signatures.register(&sig);
|
||||
if unique_signatures.contains_key(&index) {
|
||||
for (sig_index, compiled_function) in trampolines.iter() {
|
||||
let func_type = module.signatures.get(sig_index).unwrap();
|
||||
let index = self.signatures.register(&func_type);
|
||||
if self.trampolines.contains_key(&index) {
|
||||
// We don't need to allocate the trampoline in case
|
||||
// it's signature is already allocated.
|
||||
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
|
||||
.code_memory
|
||||
.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();
|
||||
let trampoline =
|
||||
unsafe { std::mem::transmute::<*const VMFunctionBody, VMTrampoline>(ptr) };
|
||||
self.trampolines.insert(*index, trampoline);
|
||||
self.trampolines.insert(index, trampoline);
|
||||
}
|
||||
Ok(allocated_functions)
|
||||
}
|
||||
|
||||
@@ -48,7 +48,5 @@ pub use crate::resolver::{resolve_imports, NullResolver, Resolver};
|
||||
pub use crate::trap::*;
|
||||
pub use crate::tunables::Tunables;
|
||||
|
||||
pub use wasmer_compiler::CompilerConfig;
|
||||
|
||||
/// Version number of this crate.
|
||||
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||
|
||||
@@ -3,7 +3,10 @@
|
||||
use std::ptr::write_unaligned;
|
||||
use wasm_common::entity::{EntityRef, PrimaryMap};
|
||||
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::VMFunctionBody;
|
||||
|
||||
@@ -15,6 +18,7 @@ pub fn link_module(
|
||||
allocated_functions: &PrimaryMap<LocalFuncIndex, *mut [VMFunctionBody]>,
|
||||
jt_offsets: &PrimaryMap<LocalFuncIndex, JumpTableOffsets>,
|
||||
relocations: Relocations,
|
||||
allocated_sections: &PrimaryMap<SectionIndex, SectionBody>,
|
||||
) {
|
||||
for (i, function_relocs) in relocations.into_iter() {
|
||||
for r in function_relocs {
|
||||
@@ -24,8 +28,8 @@ pub fn link_module(
|
||||
fatptr as *const VMFunctionBody as usize
|
||||
}
|
||||
RelocationTarget::LibCall(libcall) => libcall.function_pointer(),
|
||||
RelocationTarget::CustomSection(_custom_section) => {
|
||||
unimplemented!("Custom Sections not yet implemented");
|
||||
RelocationTarget::CustomSection(custom_section) => {
|
||||
allocated_sections[custom_section].as_ptr() as usize
|
||||
}
|
||||
RelocationTarget::JumpTable(func_index, jt) => {
|
||||
let offset = *jt_offsets
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
//! Define the `instantiate` function, which takes a byte array containing an
|
||||
//! encoded wasm module and returns a live wasm instance. Also, define
|
||||
//! `CompiledModule` to allow compiling and instantiating to be done as separate
|
||||
//! steps.
|
||||
//! Define `CompiledModule` to allow compiling and instantiating to be
|
||||
//! done as separate steps.
|
||||
|
||||
use crate::engine::{JITEngine, JITEngineInner};
|
||||
use crate::error::{DeserializeError, SerializeError};
|
||||
@@ -14,6 +12,7 @@ use crate::serialize::{
|
||||
use crate::trap::register as register_frame_info;
|
||||
use crate::trap::GlobalFrameInfoRegistration;
|
||||
use crate::trap::RuntimeError;
|
||||
use crate::tunables::Tunables;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::any::Any;
|
||||
use std::sync::{Arc, Mutex};
|
||||
@@ -23,6 +22,7 @@ use wasm_common::{
|
||||
MemoryIndex, OwnedDataInitializer, SignatureIndex, TableIndex,
|
||||
};
|
||||
use wasmer_compiler::CompileError;
|
||||
#[cfg(feature = "compiler")]
|
||||
use wasmer_compiler::ModuleEnvironment;
|
||||
use wasmer_runtime::{
|
||||
InstanceHandle, LinearMemory, Module, SignatureRegistry, Table, VMFunctionBody,
|
||||
@@ -42,6 +42,7 @@ pub struct CompiledModule {
|
||||
|
||||
impl CompiledModule {
|
||||
/// 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> {
|
||||
let environ = ModuleEnvironment::new();
|
||||
let mut jit_compiler = jit.compiler_mut();
|
||||
@@ -64,13 +65,29 @@ impl CompiledModule {
|
||||
.map(|(_index, table_type)| tunables.table_plan(*table_type))
|
||||
.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.as_ref().unwrap(),
|
||||
translation.function_body_inputs,
|
||||
memory_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
|
||||
.data_initializers
|
||||
.iter()
|
||||
@@ -89,10 +106,13 @@ impl CompiledModule {
|
||||
function_relocations: compilation.get_relocations(),
|
||||
function_jt_offsets: compilation.get_jt_offsets(),
|
||||
function_frame_info: frame_infos,
|
||||
trampolines,
|
||||
custom_sections: compilation.get_custom_sections(),
|
||||
};
|
||||
let serializable = SerializableModule {
|
||||
compilation: serializable_compilation,
|
||||
module: Arc::new(translation.module),
|
||||
features: jit_compiler.compiler()?.features().clone(),
|
||||
data_initializers,
|
||||
memory_plans,
|
||||
table_plans,
|
||||
@@ -100,6 +120,14 @@ impl CompiledModule {
|
||||
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
|
||||
pub fn serialize(&self) -> Result<Vec<u8>, SerializeError> {
|
||||
// let mut s = flexbuffers::FlexbufferSerializer::new();
|
||||
@@ -126,9 +154,10 @@ impl CompiledModule {
|
||||
jit_compiler: &mut JITEngineInner,
|
||||
serializable: SerializableModule,
|
||||
) -> Result<Self, CompileError> {
|
||||
let finished_functions = jit_compiler.compile(
|
||||
let finished_functions = jit_compiler.allocate(
|
||||
&serializable.module,
|
||||
&serializable.compilation.function_bodies,
|
||||
&serializable.compilation.trampolines,
|
||||
)?;
|
||||
|
||||
link_module(
|
||||
@@ -136,6 +165,7 @@ impl CompiledModule {
|
||||
&finished_functions,
|
||||
&serializable.compilation.function_jt_offsets,
|
||||
serializable.compilation.function_relocations.clone(),
|
||||
&serializable.compilation.custom_sections,
|
||||
);
|
||||
|
||||
// Compute indices into the shared signature table.
|
||||
@@ -170,10 +200,6 @@ impl 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
|
||||
///
|
||||
/// See `InstanceHandle::new`
|
||||
@@ -184,17 +210,8 @@ impl CompiledModule {
|
||||
host_state: Box<dyn Any>,
|
||||
) -> Result<InstanceHandle, InstantiationError> {
|
||||
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 data_initializers = self
|
||||
.serializable
|
||||
.data_initializers
|
||||
.iter()
|
||||
.map(|init| DataInitializer {
|
||||
location: init.location.clone(),
|
||||
data: &*init.data,
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let imports = resolve_imports(
|
||||
&self.serializable.module,
|
||||
&sig_registry,
|
||||
@@ -204,10 +221,18 @@ impl CompiledModule {
|
||||
)
|
||||
.map_err(InstantiationError::Link)?;
|
||||
|
||||
let finished_memories = create_memories(&self.serializable.module, self.memory_plans())
|
||||
.map_err(InstantiationError::Link)?;
|
||||
let finished_tables = create_tables(&self.serializable.module, self.table_plans());
|
||||
let finished_globals = create_globals(&self.serializable.module);
|
||||
let finished_memories = tunables
|
||||
.create_memories(&self.serializable.module, self.memory_plans())
|
||||
.map_err(InstantiationError::Link)?
|
||||
.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
|
||||
self.register_frame_info();
|
||||
@@ -219,14 +244,39 @@ impl CompiledModule {
|
||||
finished_tables,
|
||||
finished_globals,
|
||||
imports,
|
||||
&data_initializers,
|
||||
self.signatures.clone(),
|
||||
is_bulk_memory,
|
||||
host_state,
|
||||
)
|
||||
.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.
|
||||
pub fn module(&self) -> &Arc<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 more_asserts::assert_ge;
|
||||
use std::collections::HashSet;
|
||||
use wasm_common::entity::PrimaryMap;
|
||||
use wasm_common::{ExternType, ImportIndex, MemoryIndex, TableIndex};
|
||||
use wasmer_runtime::{
|
||||
@@ -95,8 +94,6 @@ pub fn resolve_imports(
|
||||
memory_plans: &PrimaryMap<MemoryIndex, MemoryPlan>,
|
||||
_table_plans: &PrimaryMap<TableIndex, TablePlan>,
|
||||
) -> Result<Imports, LinkError> {
|
||||
let dependencies = HashSet::new();
|
||||
|
||||
let mut function_imports = PrimaryMap::with_capacity(module.num_imported_funcs);
|
||||
let mut table_imports = PrimaryMap::with_capacity(module.num_imported_tables);
|
||||
let mut memory_imports = PrimaryMap::with_capacity(module.num_imported_memories);
|
||||
@@ -125,16 +122,12 @@ pub fn resolve_imports(
|
||||
}
|
||||
match resolved {
|
||||
Export::Function(ref f) => {
|
||||
// TODO: Syrus - fix this
|
||||
// dependencies.insert(unsafe { InstanceHandle::from_vmctx(f.vmctx) });
|
||||
function_imports.push(VMFunctionImport {
|
||||
body: f.address,
|
||||
vmctx: f.vmctx,
|
||||
});
|
||||
}
|
||||
Export::Table(ref t) => {
|
||||
// TODO: Syrus - fix this
|
||||
// dependencies.insert(unsafe { InstanceHandle::from_vmctx(t.vmctx) });
|
||||
table_imports.push(VMTableImport {
|
||||
definition: t.definition,
|
||||
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 {
|
||||
definition: m.definition,
|
||||
from: m.from,
|
||||
});
|
||||
}
|
||||
|
||||
Export::Global(ref g) => {
|
||||
// TODO: Syrus - fix this
|
||||
// dependencies.insert(unsafe { InstanceHandle::from_vmctx(g.vmctx) });
|
||||
global_imports.push(VMGlobalImport {
|
||||
definition: g.definition,
|
||||
});
|
||||
@@ -186,7 +176,6 @@ pub fn resolve_imports(
|
||||
}
|
||||
|
||||
Ok(Imports::new(
|
||||
dependencies,
|
||||
function_imports,
|
||||
table_imports,
|
||||
memory_imports,
|
||||
|
||||
@@ -3,11 +3,16 @@ use serde::ser::Serializer;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
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 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};
|
||||
|
||||
/// 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
|
||||
// format upon serialization.
|
||||
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
|
||||
@@ -27,6 +34,7 @@ pub struct SerializableCompilation {
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct SerializableModule {
|
||||
pub compilation: SerializableCompilation,
|
||||
pub features: Features,
|
||||
pub module: Arc<Module>,
|
||||
pub data_initializers: Box<[OwnedDataInitializer]>,
|
||||
// Plans for that module
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
use wasm_common::{MemoryType, TableType};
|
||||
use wasmer_runtime::{LinearMemory, Table};
|
||||
use crate::error::LinkError;
|
||||
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};
|
||||
|
||||
/// Tunables for an engine
|
||||
@@ -11,8 +16,56 @@ pub trait Tunables {
|
||||
fn table_plan(&self, table: TableType) -> TablePlan;
|
||||
|
||||
/// 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
|
||||
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 std::collections::HashSet;
|
||||
use wasm_common::entity::{BoxedSlice, PrimaryMap};
|
||||
@@ -7,9 +6,6 @@ use wasm_common::{FuncIndex, GlobalIndex, MemoryIndex, TableIndex};
|
||||
/// Resolved import pointers.
|
||||
#[derive(Clone)]
|
||||
pub struct Imports {
|
||||
/// The set of instances that the imports depend on.
|
||||
pub dependencies: HashSet<InstanceHandle>,
|
||||
|
||||
/// Resolved addresses for imported functions.
|
||||
pub functions: BoxedSlice<FuncIndex, VMFunctionImport>,
|
||||
|
||||
@@ -26,14 +22,12 @@ pub struct Imports {
|
||||
impl Imports {
|
||||
/// Construct a new `Imports` instance.
|
||||
pub fn new(
|
||||
dependencies: HashSet<InstanceHandle>,
|
||||
function_imports: PrimaryMap<FuncIndex, VMFunctionImport>,
|
||||
table_imports: PrimaryMap<TableIndex, VMTableImport>,
|
||||
memory_imports: PrimaryMap<MemoryIndex, VMMemoryImport>,
|
||||
global_imports: PrimaryMap<GlobalIndex, VMGlobalImport>,
|
||||
) -> Self {
|
||||
Self {
|
||||
dependencies,
|
||||
functions: function_imports.into_boxed_slice(),
|
||||
tables: table_imports.into_boxed_slice(),
|
||||
memories: memory_imports.into_boxed_slice(),
|
||||
@@ -44,7 +38,6 @@ impl Imports {
|
||||
/// Construct a new `Imports` instance with no imports.
|
||||
pub fn none() -> Self {
|
||||
Self {
|
||||
dependencies: HashSet::new(),
|
||||
functions: PrimaryMap::new().into_boxed_slice(),
|
||||
tables: PrimaryMap::new().into_boxed_slice(),
|
||||
memories: PrimaryMap::new().into_boxed_slice(),
|
||||
|
||||
@@ -35,7 +35,7 @@ cfg_if::cfg_if! {
|
||||
|
||||
impl InstanceHandle {
|
||||
/// 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
|
||||
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 {
|
||||
/// 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
|
||||
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.
|
||||
#[repr(C)]
|
||||
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.
|
||||
module: Arc<Module>,
|
||||
|
||||
@@ -788,9 +780,7 @@ impl InstanceHandle {
|
||||
finished_tables: BoxedSlice<LocalTableIndex, Table>,
|
||||
finished_globals: BoxedSlice<LocalGlobalIndex, VMGlobalDefinition>,
|
||||
imports: Imports,
|
||||
data_initializers: &[DataInitializer<'_>],
|
||||
vmshared_signatures: BoxedSlice<SignatureIndex, VMSharedSignatureIndex>,
|
||||
is_bulk_memory: bool,
|
||||
host_state: Box<dyn Any>,
|
||||
) -> Result<Self, Trap> {
|
||||
let vmctx_tables = finished_tables
|
||||
@@ -813,8 +803,6 @@ impl InstanceHandle {
|
||||
|
||||
let handle = {
|
||||
let instance = Instance {
|
||||
refcount: Cell::new(1),
|
||||
dependencies: imports.dependencies,
|
||||
module,
|
||||
offsets,
|
||||
memories: finished_memories,
|
||||
@@ -883,29 +871,42 @@ impl InstanceHandle {
|
||||
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
|
||||
// when bulk memory is disabled, since the bulk memory proposal changes
|
||||
// instantiation such that the intermediate results of failed
|
||||
// initializations are visible.
|
||||
if !is_bulk_memory {
|
||||
check_table_init_bounds(instance)?;
|
||||
check_memory_init_bounds(instance, data_initializers)?;
|
||||
check_table_init_bounds(self.instance())?;
|
||||
check_memory_init_bounds(self.instance(), data_initializers)?;
|
||||
}
|
||||
|
||||
// Apply the initializers.
|
||||
initialize_tables(instance)?;
|
||||
initialize_passive_elements(instance);
|
||||
initialize_memories(instance, data_initializers)?;
|
||||
initialize_globals(instance);
|
||||
|
||||
// Ensure that our signal handlers are ready for action.
|
||||
init_traps();
|
||||
initialize_tables(self.instance())?;
|
||||
initialize_memories(self.instance(), data_initializers)?;
|
||||
|
||||
// The WebAssembly spec specifies that the start function is
|
||||
// invoked automatically at instantiation time.
|
||||
instance.invoke_start_function()?;
|
||||
|
||||
Ok(handle)
|
||||
self.instance().invoke_start_function()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Create a new `InstanceHandle` pointing at the instance
|
||||
@@ -916,7 +917,6 @@ impl InstanceHandle {
|
||||
/// be a `VMContext` allocated as part of an `Instance`.
|
||||
pub unsafe fn from_vmctx(vmctx: *mut VMContext) -> Self {
|
||||
let instance = (&mut *vmctx).instance();
|
||||
instance.refcount.set(instance.refcount.get() + 1);
|
||||
Self {
|
||||
instance: instance as *const Instance as *mut Instance,
|
||||
}
|
||||
@@ -1031,32 +1031,36 @@ impl InstanceHandle {
|
||||
pub(crate) fn instance(&self) -> &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 {
|
||||
fn clone(&self) -> Self {
|
||||
let instance = self.instance();
|
||||
instance.refcount.set(instance.refcount.get() + 1);
|
||||
Self {
|
||||
instance: self.instance,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for InstanceHandle {
|
||||
fn drop(&mut self) {
|
||||
let instance = self.instance();
|
||||
let count = instance.refcount.get();
|
||||
instance.refcount.set(count - 1);
|
||||
if count == 1 {
|
||||
let layout = instance.alloc_layout();
|
||||
unsafe {
|
||||
ptr::drop_in_place(self.instance);
|
||||
alloc::dealloc(self.instance.cast(), layout);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO: uncomment this, as we need to store the handles
|
||||
// in the store, and once the store is dropped, then the instances
|
||||
// will too.
|
||||
// impl Drop for InstanceHandle {
|
||||
// fn drop(&mut self) {
|
||||
// unsafe { self.dealloc() }
|
||||
// }
|
||||
// }
|
||||
|
||||
fn check_table_init_bounds(instance: &Instance) -> Result<(), Trap> {
|
||||
let module = Arc::clone(&instance.module);
|
||||
|
||||
@@ -19,20 +19,22 @@ pub struct Table {
|
||||
|
||||
impl Table {
|
||||
/// 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 {
|
||||
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 {
|
||||
TableStyle::CallerChecksSignature => Self {
|
||||
TableStyle::CallerChecksSignature => Ok(Self {
|
||||
vec: RefCell::new(vec![
|
||||
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,
|
||||
plan: plan.clone(),
|
||||
},
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
#[cfg(feature = "enable-serde")]
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// Controls which experimental features will be enabled.
|
||||
/// Features usually have a corresponding [WebAssembly proposal].
|
||||
///
|
||||
/// [WebAssembly proposal]: https://github.com/WebAssembly/proposals
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
|
||||
pub struct Features {
|
||||
/// Threads proposal should be enabled
|
||||
pub threads: bool,
|
||||
|
||||
@@ -99,7 +99,8 @@ impl Run {
|
||||
}
|
||||
|
||||
// If WASI is enabled, try to execute it with it
|
||||
if cfg!(feature = "wasi") {
|
||||
#[cfg(feature = "wasi")]
|
||||
{
|
||||
let wasi_version = Wasi::get_version(&module);
|
||||
if let Some(version) = wasi_version {
|
||||
let program_name = self
|
||||
@@ -129,9 +130,9 @@ impl Run {
|
||||
fn get_module(&self) -> Result<Module> {
|
||||
let contents = std::fs::read(self.path.clone())?;
|
||||
if Engine::is_deserializable(&contents) {
|
||||
let (compiler_config, _compiler_name) = self.compiler.get_compiler_config()?;
|
||||
let tunables = self.compiler.get_tunables(&*compiler_config);
|
||||
let engine = Engine::new(&*compiler_config, tunables);
|
||||
// We get the tunables for the current host
|
||||
let tunables = Tunables::default();
|
||||
let engine = Engine::headless(tunables);
|
||||
let store = Store::new(&engine);
|
||||
let module = unsafe { Module::deserialize(&store, &contents)? };
|
||||
return Ok(module);
|
||||
|
||||
@@ -34,25 +34,6 @@ pub struct WasmFeatures {
|
||||
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
|
||||
pub fn get_cache_dir() -> PathBuf {
|
||||
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 {
|
||||
fn get_compiler(&self) -> Result<Compiler> {
|
||||
if self.cranelift {
|
||||
@@ -91,6 +92,7 @@ impl StoreOptions {
|
||||
}
|
||||
|
||||
/// Get the Compiler Config for the current options
|
||||
#[allow(unused_variables)]
|
||||
fn get_config(&self, compiler: Compiler) -> Result<Box<dyn CompilerConfig>> {
|
||||
let config: Box<dyn CompilerConfig> = match compiler {
|
||||
#[cfg(feature = "compiler-singlepass")]
|
||||
@@ -122,7 +124,7 @@ impl StoreOptions {
|
||||
}
|
||||
|
||||
/// 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_name = compiler.to_string();
|
||||
let compiler_config = self.get_config(compiler)?;
|
||||
@@ -143,3 +145,15 @@ impl StoreOptions {
|
||||
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 }
|
||||
|
||||
[features]
|
||||
compiler = []
|
||||
compiler-singlepass = [
|
||||
"wasmer-compiler-singlepass",
|
||||
"compiler",
|
||||
]
|
||||
compiler-cranelift = [
|
||||
"wasmer-compiler-cranelift",
|
||||
"compiler",
|
||||
]
|
||||
compiler-llvm = [
|
||||
"wasmer-compiler-llvm",
|
||||
"compiler",
|
||||
]
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#![cfg(feature = "compiler")]
|
||||
|
||||
use wasmer_compiler::{CompilerConfig, Features, Target};
|
||||
|
||||
pub fn get_compiler_config_from_str(
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#![cfg(feature = "compiler")]
|
||||
|
||||
use std::path::Path;
|
||||
use test_utils::get_compiler_config_from_str;
|
||||
use wasmer::{Engine, Features, Store, Tunables};
|
||||
@@ -16,7 +18,10 @@ use wasmer_wast::Wast;
|
||||
include!(concat!(env!("OUT_DIR"), "/generated_spectests.rs"));
|
||||
|
||||
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 mut features = Features::default();
|
||||
if wast_path.contains("bulk-memory") {
|
||||
|
||||
Reference in New Issue
Block a user