mirror of
https://github.com/fluencelabs/wasmer
synced 2025-03-30 22:41:03 +00:00
Merge pull request #198 from wasmerio/feature/cache-rework
Redesign the exposed cache api.
This commit is contained in:
commit
1821eae995
9
Cargo.lock
generated
9
Cargo.lock
generated
@ -375,6 +375,11 @@ dependencies = [
|
|||||||
"unicode-segmentation 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"unicode-segmentation 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hex"
|
||||||
|
version = "0.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "humantime"
|
name = "humantime"
|
||||||
version = "1.2.0"
|
version = "1.2.0"
|
||||||
@ -1096,6 +1101,7 @@ name = "wasmer-runtime"
|
|||||||
version = "0.1.4"
|
version = "0.1.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"wasmer-clif-backend 0.1.2",
|
"wasmer-clif-backend 0.1.2",
|
||||||
"wasmer-runtime-core 0.1.2",
|
"wasmer-runtime-core 0.1.2",
|
||||||
]
|
]
|
||||||
@ -1117,10 +1123,10 @@ dependencies = [
|
|||||||
"errno 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"errno 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"field-offset 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"field-offset 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"hashbrown 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"hashbrown 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"nix 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"nix 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"page_size 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"page_size 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -1264,6 +1270,7 @@ dependencies = [
|
|||||||
"checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb"
|
"checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb"
|
||||||
"checksum hashbrown 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3bae29b6653b3412c2e71e9d486db9f9df5d701941d86683005efb9f2d28e3da"
|
"checksum hashbrown 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3bae29b6653b3412c2e71e9d486db9f9df5d701941d86683005efb9f2d28e3da"
|
||||||
"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205"
|
"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205"
|
||||||
|
"checksum hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77"
|
||||||
"checksum humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ca7e5f2e110db35f93b837c81797f3714500b81d517bf20c431b16d3ca4f114"
|
"checksum humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ca7e5f2e110db35f93b837c81797f3714500b81d517bf20c431b16d3ca4f114"
|
||||||
"checksum indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7e81a7c05f79578dbc15793d8b619db9ba32b4577003ef3af1a91c416798c58d"
|
"checksum indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7e81a7c05f79578dbc15793d8b619db9ba32b4577003ef3af1a91c416798c58d"
|
||||||
"checksum itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1306f3464951f30e30d12373d31c79fbd52d236e5e896fd92f96ec7babbbe60b"
|
"checksum itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1306f3464951f30e30d12373d31c79fbd52d236e5e896fd92f96ec7babbbe60b"
|
||||||
|
@ -23,24 +23,16 @@ libc = "0.2.48"
|
|||||||
# Dependencies for caching.
|
# Dependencies for caching.
|
||||||
[dependencies.serde]
|
[dependencies.serde]
|
||||||
version = "1.0"
|
version = "1.0"
|
||||||
optional = true
|
|
||||||
[dependencies.serde_derive]
|
[dependencies.serde_derive]
|
||||||
version = "1.0"
|
version = "1.0"
|
||||||
optional = true
|
|
||||||
[dependencies.serde_bytes]
|
[dependencies.serde_bytes]
|
||||||
version = "0.10"
|
version = "0.10"
|
||||||
optional = true
|
|
||||||
# [dependencies.bincode]
|
|
||||||
# version = "1.0.1"
|
|
||||||
# optional = true
|
|
||||||
[dependencies.serde-bench]
|
[dependencies.serde-bench]
|
||||||
version = "0.0.7"
|
version = "0.0.7"
|
||||||
optional = true
|
|
||||||
|
|
||||||
[target.'cfg(windows)'.dependencies]
|
[target.'cfg(windows)'.dependencies]
|
||||||
winapi = { version = "0.3", features = ["errhandlingapi", "minwindef", "minwinbase", "winnt"] }
|
winapi = { version = "0.3", features = ["errhandlingapi", "minwindef", "minwinbase", "winnt"] }
|
||||||
wasmer-win-exception-handler = { path = "../win-exception-handler", version = "0.0.1" }
|
wasmer-win-exception-handler = { path = "../win-exception-handler", version = "0.0.1" }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
cache = ["serde", "serde_derive", "serde_bytes", "serde-bench", "wasmer-runtime-core/cache"]
|
|
||||||
debug = ["wasmer-runtime-core/debug"]
|
debug = ["wasmer-runtime-core/debug"]
|
||||||
|
@ -1,16 +1,50 @@
|
|||||||
use crate::relocation::{ExternalRelocation, TrapSink};
|
use crate::relocation::{ExternalRelocation, TrapSink};
|
||||||
|
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
|
use std::sync::Arc;
|
||||||
use wasmer_runtime_core::{
|
use wasmer_runtime_core::{
|
||||||
backend::sys::Memory,
|
backend::{sys::Memory, CacheGen},
|
||||||
cache::{Cache, Error},
|
cache::{Artifact, Error},
|
||||||
module::ModuleInfo,
|
module::{ModuleInfo, ModuleInner},
|
||||||
structures::Map,
|
structures::Map,
|
||||||
types::{LocalFuncIndex, SigIndex},
|
types::{LocalFuncIndex, SigIndex},
|
||||||
};
|
};
|
||||||
|
|
||||||
use serde_bench::{deserialize, serialize};
|
use serde_bench::{deserialize, serialize};
|
||||||
|
|
||||||
|
pub struct CacheGenerator {
|
||||||
|
backend_cache: BackendCache,
|
||||||
|
memory: Arc<Memory>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CacheGenerator {
|
||||||
|
pub fn new(backend_cache: BackendCache, memory: Arc<Memory>) -> Self {
|
||||||
|
Self {
|
||||||
|
backend_cache,
|
||||||
|
memory,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CacheGen for CacheGenerator {
|
||||||
|
fn generate_cache(
|
||||||
|
&self,
|
||||||
|
module: &ModuleInner,
|
||||||
|
) -> Result<(Box<ModuleInfo>, Box<[u8]>, Memory), Error> {
|
||||||
|
let info = Box::new(module.info.clone());
|
||||||
|
|
||||||
|
// Clone the memory to a new location. This could take a long time,
|
||||||
|
// depending on the throughput of your memcpy implementation.
|
||||||
|
let compiled_code = (*self.memory).clone();
|
||||||
|
|
||||||
|
Ok((
|
||||||
|
info,
|
||||||
|
self.backend_cache.into_backend_data()?.into_boxed_slice(),
|
||||||
|
compiled_code,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct TrampolineCache {
|
pub struct TrampolineCache {
|
||||||
#[serde(with = "serde_bytes")]
|
#[serde(with = "serde_bytes")]
|
||||||
@ -22,24 +56,24 @@ pub struct TrampolineCache {
|
|||||||
pub struct BackendCache {
|
pub struct BackendCache {
|
||||||
pub external_relocs: Map<LocalFuncIndex, Box<[ExternalRelocation]>>,
|
pub external_relocs: Map<LocalFuncIndex, Box<[ExternalRelocation]>>,
|
||||||
pub offsets: Map<LocalFuncIndex, usize>,
|
pub offsets: Map<LocalFuncIndex, usize>,
|
||||||
pub trap_sink: TrapSink,
|
pub trap_sink: Arc<TrapSink>,
|
||||||
pub trampolines: TrampolineCache,
|
pub trampolines: TrampolineCache,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BackendCache {
|
impl BackendCache {
|
||||||
pub fn from_cache(cache: Cache) -> Result<(ModuleInfo, Memory, Self), Error> {
|
pub fn from_cache(cache: Artifact) -> Result<(ModuleInfo, Memory, Self), Error> {
|
||||||
let (info, backend_data, compiled_code) = cache.consume();
|
let (info, backend_data, compiled_code) = cache.consume();
|
||||||
|
|
||||||
let backend_cache = deserialize(backend_data.as_slice())
|
let backend_cache =
|
||||||
.map_err(|e| Error::DeserializeError(e.to_string()))?;
|
deserialize(&backend_data).map_err(|e| Error::DeserializeError(e.to_string()))?;
|
||||||
|
|
||||||
Ok((info, compiled_code, backend_cache))
|
Ok((info, compiled_code, backend_cache))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn into_backend_data(self) -> Result<Vec<u8>, Error> {
|
pub fn into_backend_data(&self) -> Result<Vec<u8>, Error> {
|
||||||
let mut buffer = Vec::new();
|
let mut buffer = Vec::new();
|
||||||
|
|
||||||
serialize(&mut buffer, &self).map_err(|e| Error::SerializeError(e.to_string()))?;
|
serialize(&mut buffer, self).map_err(|e| Error::SerializeError(e.to_string()))?;
|
||||||
|
|
||||||
Ok(buffer)
|
Ok(buffer)
|
||||||
}
|
}
|
||||||
|
@ -75,7 +75,7 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> {
|
|||||||
let vmctx = func.create_global_value(ir::GlobalValueData::VMContext);
|
let vmctx = func.create_global_value(ir::GlobalValueData::VMContext);
|
||||||
let ptr_type = self.pointer_type();
|
let ptr_type = self.pointer_type();
|
||||||
|
|
||||||
let local_global_addr = match global_index.local_or_import(self.env.module) {
|
let local_global_addr = match global_index.local_or_import(&self.env.module.info) {
|
||||||
LocalOrImport::Local(local_global_index) => {
|
LocalOrImport::Local(local_global_index) => {
|
||||||
let globals_base_addr = func.create_global_value(ir::GlobalValueData::Load {
|
let globals_base_addr = func.create_global_value(ir::GlobalValueData::Load {
|
||||||
base: vmctx,
|
base: vmctx,
|
||||||
@ -145,48 +145,49 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> {
|
|||||||
let vmctx = func.create_global_value(ir::GlobalValueData::VMContext);
|
let vmctx = func.create_global_value(ir::GlobalValueData::VMContext);
|
||||||
let ptr_type = self.pointer_type();
|
let ptr_type = self.pointer_type();
|
||||||
|
|
||||||
let (local_memory_ptr_ptr, description) = match mem_index.local_or_import(self.env.module) {
|
let (local_memory_ptr_ptr, description) =
|
||||||
LocalOrImport::Local(local_mem_index) => {
|
match mem_index.local_or_import(&self.env.module.info) {
|
||||||
let memories_base_addr = func.create_global_value(ir::GlobalValueData::Load {
|
LocalOrImport::Local(local_mem_index) => {
|
||||||
base: vmctx,
|
let memories_base_addr = func.create_global_value(ir::GlobalValueData::Load {
|
||||||
offset: (vm::Ctx::offset_memories() as i32).into(),
|
base: vmctx,
|
||||||
global_type: ptr_type,
|
offset: (vm::Ctx::offset_memories() as i32).into(),
|
||||||
readonly: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
let local_memory_ptr_offset =
|
|
||||||
local_mem_index.index() * mem::size_of::<*mut vm::LocalMemory>();
|
|
||||||
|
|
||||||
(
|
|
||||||
func.create_global_value(ir::GlobalValueData::IAddImm {
|
|
||||||
base: memories_base_addr,
|
|
||||||
offset: (local_memory_ptr_offset as i64).into(),
|
|
||||||
global_type: ptr_type,
|
global_type: ptr_type,
|
||||||
}),
|
readonly: true,
|
||||||
self.env.module.info.memories[local_mem_index],
|
});
|
||||||
)
|
|
||||||
}
|
|
||||||
LocalOrImport::Import(import_mem_index) => {
|
|
||||||
let memories_base_addr = func.create_global_value(ir::GlobalValueData::Load {
|
|
||||||
base: vmctx,
|
|
||||||
offset: (vm::Ctx::offset_imported_memories() as i32).into(),
|
|
||||||
global_type: ptr_type,
|
|
||||||
readonly: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
let local_memory_ptr_offset =
|
let local_memory_ptr_offset =
|
||||||
import_mem_index.index() * mem::size_of::<*mut vm::LocalMemory>();
|
local_mem_index.index() * mem::size_of::<*mut vm::LocalMemory>();
|
||||||
|
|
||||||
(
|
(
|
||||||
func.create_global_value(ir::GlobalValueData::IAddImm {
|
func.create_global_value(ir::GlobalValueData::IAddImm {
|
||||||
base: memories_base_addr,
|
base: memories_base_addr,
|
||||||
offset: (local_memory_ptr_offset as i64).into(),
|
offset: (local_memory_ptr_offset as i64).into(),
|
||||||
|
global_type: ptr_type,
|
||||||
|
}),
|
||||||
|
self.env.module.info.memories[local_mem_index],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
LocalOrImport::Import(import_mem_index) => {
|
||||||
|
let memories_base_addr = func.create_global_value(ir::GlobalValueData::Load {
|
||||||
|
base: vmctx,
|
||||||
|
offset: (vm::Ctx::offset_imported_memories() as i32).into(),
|
||||||
global_type: ptr_type,
|
global_type: ptr_type,
|
||||||
}),
|
readonly: true,
|
||||||
self.env.module.info.imported_memories[import_mem_index].1,
|
});
|
||||||
)
|
|
||||||
}
|
let local_memory_ptr_offset =
|
||||||
};
|
import_mem_index.index() * mem::size_of::<*mut vm::LocalMemory>();
|
||||||
|
|
||||||
|
(
|
||||||
|
func.create_global_value(ir::GlobalValueData::IAddImm {
|
||||||
|
base: memories_base_addr,
|
||||||
|
offset: (local_memory_ptr_offset as i64).into(),
|
||||||
|
global_type: ptr_type,
|
||||||
|
}),
|
||||||
|
self.env.module.info.imported_memories[import_mem_index].1,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let (local_memory_ptr, local_memory_base) = {
|
let (local_memory_ptr, local_memory_base) = {
|
||||||
let local_memory_ptr = func.create_global_value(ir::GlobalValueData::Load {
|
let local_memory_ptr = func.create_global_value(ir::GlobalValueData::Load {
|
||||||
@ -253,7 +254,8 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> {
|
|||||||
let vmctx = func.create_global_value(ir::GlobalValueData::VMContext);
|
let vmctx = func.create_global_value(ir::GlobalValueData::VMContext);
|
||||||
let ptr_type = self.pointer_type();
|
let ptr_type = self.pointer_type();
|
||||||
|
|
||||||
let (table_struct_ptr_ptr, description) = match table_index.local_or_import(self.env.module)
|
let (table_struct_ptr_ptr, description) = match table_index
|
||||||
|
.local_or_import(&self.env.module.info)
|
||||||
{
|
{
|
||||||
LocalOrImport::Local(local_table_index) => {
|
LocalOrImport::Local(local_table_index) => {
|
||||||
let tables_base = func.create_global_value(ir::GlobalValueData::Load {
|
let tables_base = func.create_global_value(ir::GlobalValueData::Load {
|
||||||
@ -476,7 +478,7 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> {
|
|||||||
) -> cranelift_wasm::WasmResult<ir::Inst> {
|
) -> cranelift_wasm::WasmResult<ir::Inst> {
|
||||||
let callee_index: FuncIndex = Converter(clif_callee_index).into();
|
let callee_index: FuncIndex = Converter(clif_callee_index).into();
|
||||||
|
|
||||||
match callee_index.local_or_import(self.env.module) {
|
match callee_index.local_or_import(&self.env.module.info) {
|
||||||
LocalOrImport::Local(_) => {
|
LocalOrImport::Local(_) => {
|
||||||
// this is an internal function
|
// this is an internal function
|
||||||
let vmctx = pos
|
let vmctx = pos
|
||||||
@ -568,18 +570,19 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> {
|
|||||||
|
|
||||||
let mem_index: MemoryIndex = Converter(clif_mem_index).into();
|
let mem_index: MemoryIndex = Converter(clif_mem_index).into();
|
||||||
|
|
||||||
let (namespace, mem_index, description) = match mem_index.local_or_import(self.env.module) {
|
let (namespace, mem_index, description) =
|
||||||
LocalOrImport::Local(local_mem_index) => (
|
match mem_index.local_or_import(&self.env.module.info) {
|
||||||
call_names::LOCAL_NAMESPACE,
|
LocalOrImport::Local(local_mem_index) => (
|
||||||
local_mem_index.index(),
|
call_names::LOCAL_NAMESPACE,
|
||||||
self.env.module.info.memories[local_mem_index],
|
local_mem_index.index(),
|
||||||
),
|
self.env.module.info.memories[local_mem_index],
|
||||||
LocalOrImport::Import(import_mem_index) => (
|
),
|
||||||
call_names::IMPORT_NAMESPACE,
|
LocalOrImport::Import(import_mem_index) => (
|
||||||
import_mem_index.index(),
|
call_names::IMPORT_NAMESPACE,
|
||||||
self.env.module.info.imported_memories[import_mem_index].1,
|
import_mem_index.index(),
|
||||||
),
|
self.env.module.info.imported_memories[import_mem_index].1,
|
||||||
};
|
),
|
||||||
|
};
|
||||||
|
|
||||||
let name_index = match description.memory_type() {
|
let name_index = match description.memory_type() {
|
||||||
MemoryType::Dynamic => call_names::DYNAMIC_MEM_GROW,
|
MemoryType::Dynamic => call_names::DYNAMIC_MEM_GROW,
|
||||||
@ -631,18 +634,19 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> {
|
|||||||
|
|
||||||
let mem_index: MemoryIndex = Converter(clif_mem_index).into();
|
let mem_index: MemoryIndex = Converter(clif_mem_index).into();
|
||||||
|
|
||||||
let (namespace, mem_index, description) = match mem_index.local_or_import(self.env.module) {
|
let (namespace, mem_index, description) =
|
||||||
LocalOrImport::Local(local_mem_index) => (
|
match mem_index.local_or_import(&self.env.module.info) {
|
||||||
call_names::LOCAL_NAMESPACE,
|
LocalOrImport::Local(local_mem_index) => (
|
||||||
local_mem_index.index(),
|
call_names::LOCAL_NAMESPACE,
|
||||||
self.env.module.info.memories[local_mem_index],
|
local_mem_index.index(),
|
||||||
),
|
self.env.module.info.memories[local_mem_index],
|
||||||
LocalOrImport::Import(import_mem_index) => (
|
),
|
||||||
call_names::IMPORT_NAMESPACE,
|
LocalOrImport::Import(import_mem_index) => (
|
||||||
import_mem_index.index(),
|
call_names::IMPORT_NAMESPACE,
|
||||||
self.env.module.info.imported_memories[import_mem_index].1,
|
import_mem_index.index(),
|
||||||
),
|
self.env.module.info.imported_memories[import_mem_index].1,
|
||||||
};
|
),
|
||||||
|
};
|
||||||
|
|
||||||
let name_index = match description.memory_type() {
|
let name_index = match description.memory_type() {
|
||||||
MemoryType::Dynamic => call_names::DYNAMIC_MEM_SIZE,
|
MemoryType::Dynamic => call_names::DYNAMIC_MEM_SIZE,
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
#[cfg(feature = "cache")]
|
|
||||||
mod cache;
|
mod cache;
|
||||||
mod func_env;
|
mod func_env;
|
||||||
mod libcalls;
|
mod libcalls;
|
||||||
@ -14,21 +13,17 @@ use cranelift_codegen::{
|
|||||||
settings::{self, Configurable},
|
settings::{self, Configurable},
|
||||||
};
|
};
|
||||||
use target_lexicon::Triple;
|
use target_lexicon::Triple;
|
||||||
#[cfg(feature = "cache")]
|
|
||||||
use wasmer_runtime_core::{
|
use wasmer_runtime_core::cache::{Artifact, Error as CacheError};
|
||||||
backend::sys::Memory,
|
|
||||||
cache::{Cache, Error as CacheError},
|
|
||||||
module::ModuleInfo,
|
|
||||||
};
|
|
||||||
use wasmer_runtime_core::{
|
use wasmer_runtime_core::{
|
||||||
backend::{Compiler, Token},
|
backend::{Compiler, Token},
|
||||||
error::{CompileError, CompileResult},
|
error::{CompileError, CompileResult},
|
||||||
module::ModuleInner,
|
module::ModuleInner,
|
||||||
};
|
};
|
||||||
#[cfg(feature = "cache")]
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate serde_derive;
|
extern crate serde_derive;
|
||||||
#[cfg(feature = "cache")]
|
|
||||||
extern crate serde;
|
extern crate serde;
|
||||||
|
|
||||||
use wasmparser::{self, WasmDecoder};
|
use wasmparser::{self, WasmDecoder};
|
||||||
@ -48,7 +43,7 @@ impl Compiler for CraneliftCompiler {
|
|||||||
|
|
||||||
let isa = get_isa();
|
let isa = get_isa();
|
||||||
|
|
||||||
let mut module = module::Module::empty();
|
let mut module = module::Module::new(wasm);
|
||||||
let module_env = module_env::ModuleEnv::new(&mut module, &*isa);
|
let module_env = module_env::ModuleEnv::new(&mut module, &*isa);
|
||||||
|
|
||||||
let func_bodies = module_env.translate(wasm)?;
|
let func_bodies = module_env.translate(wasm)?;
|
||||||
@ -57,41 +52,41 @@ impl Compiler for CraneliftCompiler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Create a wasmer Module from an already-compiled cache.
|
/// Create a wasmer Module from an already-compiled cache.
|
||||||
#[cfg(feature = "cache")]
|
|
||||||
unsafe fn from_cache(&self, cache: Cache, _: Token) -> Result<ModuleInner, CacheError> {
|
unsafe fn from_cache(&self, cache: Artifact, _: Token) -> Result<ModuleInner, CacheError> {
|
||||||
module::Module::from_cache(cache)
|
module::Module::from_cache(cache)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "cache")]
|
//
|
||||||
fn compile_to_backend_cache_data(
|
// fn compile_to_backend_cache_data(
|
||||||
&self,
|
// &self,
|
||||||
wasm: &[u8],
|
// wasm: &[u8],
|
||||||
_: Token,
|
// _: Token,
|
||||||
) -> CompileResult<(Box<ModuleInfo>, Vec<u8>, Memory)> {
|
// ) -> CompileResult<(Box<ModuleInfo>, Vec<u8>, Memory)> {
|
||||||
validate(wasm)?;
|
// validate(wasm)?;
|
||||||
|
|
||||||
let isa = get_isa();
|
// let isa = get_isa();
|
||||||
|
|
||||||
let mut module = module::Module::empty();
|
// let mut module = module::Module::new(wasm);
|
||||||
let module_env = module_env::ModuleEnv::new(&mut module, &*isa);
|
// let module_env = module_env::ModuleEnv::new(&mut module, &*isa);
|
||||||
|
|
||||||
let func_bodies = module_env.translate(wasm)?;
|
// let func_bodies = module_env.translate(wasm)?;
|
||||||
|
|
||||||
let (info, backend_cache, compiled_code) = module
|
// let (info, backend_cache, compiled_code) = module
|
||||||
.compile_to_backend_cache(&*isa, func_bodies)
|
// .compile_to_backend_cache(&*isa, func_bodies)
|
||||||
.map_err(|e| CompileError::InternalError {
|
// .map_err(|e| CompileError::InternalError {
|
||||||
msg: format!("{:?}", e),
|
// msg: format!("{:?}", e),
|
||||||
})?;
|
// })?;
|
||||||
|
|
||||||
let buffer =
|
// let buffer =
|
||||||
backend_cache
|
// backend_cache
|
||||||
.into_backend_data()
|
// .into_backend_data()
|
||||||
.map_err(|e| CompileError::InternalError {
|
// .map_err(|e| CompileError::InternalError {
|
||||||
msg: format!("{:?}", e),
|
// msg: format!("{:?}", e),
|
||||||
})?;
|
// })?;
|
||||||
|
|
||||||
Ok((Box::new(info), buffer, compiled_code))
|
// Ok((Box::new(info), buffer, compiled_code))
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_isa() -> Box<isa::TargetIsa> {
|
fn get_isa() -> Box<isa::TargetIsa> {
|
||||||
|
@ -1,178 +1,124 @@
|
|||||||
#[cfg(feature = "cache")]
|
use crate::cache::{BackendCache, CacheGenerator};
|
||||||
use crate::cache::BackendCache;
|
|
||||||
use crate::{resolver::FuncResolverBuilder, signal::Caller, trampoline::Trampolines};
|
use crate::{resolver::FuncResolverBuilder, signal::Caller, trampoline::Trampolines};
|
||||||
|
|
||||||
use cranelift_codegen::{ir, isa};
|
use cranelift_codegen::{ir, isa};
|
||||||
use cranelift_entity::EntityRef;
|
use cranelift_entity::EntityRef;
|
||||||
use cranelift_wasm;
|
use cranelift_wasm;
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
use std::{
|
use std::sync::Arc;
|
||||||
ops::{Deref, DerefMut},
|
|
||||||
ptr::NonNull,
|
use wasmer_runtime_core::cache::{Artifact, Error as CacheError, WasmHash};
|
||||||
};
|
|
||||||
#[cfg(feature = "cache")]
|
|
||||||
use wasmer_runtime_core::{
|
use wasmer_runtime_core::{
|
||||||
backend::sys::Memory,
|
backend::Backend,
|
||||||
cache::{Cache, Error as CacheError},
|
error::CompileResult,
|
||||||
};
|
|
||||||
use wasmer_runtime_core::{
|
|
||||||
backend::{Backend, FuncResolver, ProtectedCaller, Token, UserTrapper},
|
|
||||||
error::{CompileResult, RuntimeResult},
|
|
||||||
module::{ModuleInfo, ModuleInner, StringTable},
|
module::{ModuleInfo, ModuleInner, StringTable},
|
||||||
structures::{Map, TypedIndex},
|
structures::{Map, TypedIndex},
|
||||||
types::{
|
types::{
|
||||||
FuncIndex, FuncSig, GlobalIndex, LocalFuncIndex, MemoryIndex, SigIndex, TableIndex, Type,
|
FuncIndex, FuncSig, GlobalIndex, LocalFuncIndex, MemoryIndex, SigIndex, TableIndex, Type,
|
||||||
Value,
|
|
||||||
},
|
},
|
||||||
vm::{self, ImportBacking},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Placeholder;
|
|
||||||
|
|
||||||
impl FuncResolver for Placeholder {
|
|
||||||
fn get(
|
|
||||||
&self,
|
|
||||||
_module: &ModuleInner,
|
|
||||||
_local_func_index: LocalFuncIndex,
|
|
||||||
) -> Option<NonNull<vm::Func>> {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ProtectedCaller for Placeholder {
|
|
||||||
fn call(
|
|
||||||
&self,
|
|
||||||
_module: &ModuleInner,
|
|
||||||
_func_index: FuncIndex,
|
|
||||||
_params: &[Value],
|
|
||||||
_import_backing: &ImportBacking,
|
|
||||||
_vmctx: *mut vm::Ctx,
|
|
||||||
_: Token,
|
|
||||||
) -> RuntimeResult<Vec<Value>> {
|
|
||||||
Ok(vec![])
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_early_trapper(&self) -> Box<dyn UserTrapper> {
|
|
||||||
unimplemented!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// This contains all of the items in a `ModuleInner` except the `func_resolver`.
|
/// This contains all of the items in a `ModuleInner` except the `func_resolver`.
|
||||||
pub struct Module {
|
pub struct Module {
|
||||||
pub module: ModuleInner,
|
pub info: ModuleInfo,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Module {
|
impl Module {
|
||||||
pub fn empty() -> Self {
|
pub fn new(wasm: &[u8]) -> Self {
|
||||||
Self {
|
Self {
|
||||||
module: ModuleInner {
|
info: ModuleInfo {
|
||||||
// this is a placeholder
|
memories: Map::new(),
|
||||||
func_resolver: Box::new(Placeholder),
|
globals: Map::new(),
|
||||||
protected_caller: Box::new(Placeholder),
|
tables: Map::new(),
|
||||||
|
|
||||||
info: ModuleInfo {
|
imported_functions: Map::new(),
|
||||||
memories: Map::new(),
|
imported_memories: Map::new(),
|
||||||
globals: Map::new(),
|
imported_tables: Map::new(),
|
||||||
tables: Map::new(),
|
imported_globals: Map::new(),
|
||||||
|
|
||||||
imported_functions: Map::new(),
|
exports: HashMap::new(),
|
||||||
imported_memories: Map::new(),
|
|
||||||
imported_tables: Map::new(),
|
|
||||||
imported_globals: Map::new(),
|
|
||||||
|
|
||||||
exports: HashMap::new(),
|
data_initializers: Vec::new(),
|
||||||
|
elem_initializers: Vec::new(),
|
||||||
|
|
||||||
data_initializers: Vec::new(),
|
start_func: None,
|
||||||
elem_initializers: Vec::new(),
|
|
||||||
|
|
||||||
start_func: None,
|
func_assoc: Map::new(),
|
||||||
|
signatures: Map::new(),
|
||||||
|
backend: Backend::Cranelift,
|
||||||
|
|
||||||
func_assoc: Map::new(),
|
namespace_table: StringTable::new(),
|
||||||
signatures: Map::new(),
|
name_table: StringTable::new(),
|
||||||
backend: Backend::Cranelift,
|
|
||||||
|
|
||||||
namespace_table: StringTable::new(),
|
wasm_hash: WasmHash::generate(wasm),
|
||||||
name_table: StringTable::new(),
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn compile(
|
pub fn compile(
|
||||||
mut self,
|
self,
|
||||||
isa: &isa::TargetIsa,
|
isa: &isa::TargetIsa,
|
||||||
functions: Map<LocalFuncIndex, ir::Function>,
|
functions: Map<LocalFuncIndex, ir::Function>,
|
||||||
) -> CompileResult<ModuleInner> {
|
) -> CompileResult<ModuleInner> {
|
||||||
let (func_resolver_builder, handler_data) =
|
let (func_resolver_builder, handler_data) =
|
||||||
FuncResolverBuilder::new(isa, functions, &self.module.info)?;
|
FuncResolverBuilder::new(isa, functions, &self.info)?;
|
||||||
|
|
||||||
self.module.func_resolver =
|
let trampolines = Arc::new(Trampolines::new(isa, &self.info));
|
||||||
Box::new(func_resolver_builder.finalize(&self.module.info.signatures)?);
|
|
||||||
|
|
||||||
let trampolines = Trampolines::new(isa, &self.module.info);
|
let (func_resolver, backend_cache) = func_resolver_builder.finalize(
|
||||||
|
&self.info.signatures,
|
||||||
|
Arc::clone(&trampolines),
|
||||||
|
handler_data.clone(),
|
||||||
|
)?;
|
||||||
|
|
||||||
self.module.protected_caller =
|
let protected_caller = Caller::new(&self.info, handler_data, trampolines);
|
||||||
Box::new(Caller::new(&self.module.info, handler_data, trampolines));
|
|
||||||
|
|
||||||
Ok(self.module)
|
let cache_gen = Box::new(CacheGenerator::new(
|
||||||
|
backend_cache,
|
||||||
|
Arc::clone(&func_resolver.memory),
|
||||||
|
));
|
||||||
|
|
||||||
|
Ok(ModuleInner {
|
||||||
|
func_resolver: Box::new(func_resolver),
|
||||||
|
protected_caller: Box::new(protected_caller),
|
||||||
|
cache_gen,
|
||||||
|
|
||||||
|
info: self.info,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "cache")]
|
pub fn from_cache(cache: Artifact) -> Result<ModuleInner, CacheError> {
|
||||||
pub fn compile_to_backend_cache(
|
|
||||||
self,
|
|
||||||
isa: &isa::TargetIsa,
|
|
||||||
functions: Map<LocalFuncIndex, ir::Function>,
|
|
||||||
) -> CompileResult<(ModuleInfo, BackendCache, Memory)> {
|
|
||||||
let (func_resolver_builder, handler_data) =
|
|
||||||
FuncResolverBuilder::new(isa, functions, &self.module.info)?;
|
|
||||||
|
|
||||||
let trampolines = Trampolines::new(isa, &self.module.info);
|
|
||||||
|
|
||||||
let trampoline_cache = trampolines.to_trampoline_cache();
|
|
||||||
|
|
||||||
let (backend_cache, compiled_code) =
|
|
||||||
func_resolver_builder.to_backend_cache(trampoline_cache, handler_data);
|
|
||||||
|
|
||||||
Ok((self.module.info, backend_cache, compiled_code))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "cache")]
|
|
||||||
pub fn from_cache(cache: Cache) -> Result<ModuleInner, CacheError> {
|
|
||||||
let (info, compiled_code, backend_cache) = BackendCache::from_cache(cache)?;
|
let (info, compiled_code, backend_cache) = BackendCache::from_cache(cache)?;
|
||||||
|
|
||||||
let (func_resolver_builder, trampolines, handler_data) =
|
let (func_resolver_builder, trampolines, handler_data) =
|
||||||
FuncResolverBuilder::new_from_backend_cache(backend_cache, compiled_code, &info)?;
|
FuncResolverBuilder::new_from_backend_cache(backend_cache, compiled_code, &info)?;
|
||||||
|
|
||||||
let func_resolver = Box::new(
|
let (func_resolver, backend_cache) = func_resolver_builder
|
||||||
func_resolver_builder
|
.finalize(
|
||||||
.finalize(&info.signatures)
|
&info.signatures,
|
||||||
.map_err(|e| CacheError::Unknown(format!("{:?}", e)))?,
|
Arc::clone(&trampolines),
|
||||||
);
|
handler_data.clone(),
|
||||||
|
)
|
||||||
|
.map_err(|e| CacheError::Unknown(format!("{:?}", e)))?;
|
||||||
|
|
||||||
let protected_caller = Box::new(Caller::new(&info, handler_data, trampolines));
|
let protected_caller = Caller::new(&info, handler_data, trampolines);
|
||||||
|
|
||||||
|
let cache_gen = Box::new(CacheGenerator::new(
|
||||||
|
backend_cache,
|
||||||
|
Arc::clone(&func_resolver.memory),
|
||||||
|
));
|
||||||
|
|
||||||
Ok(ModuleInner {
|
Ok(ModuleInner {
|
||||||
func_resolver,
|
func_resolver: Box::new(func_resolver),
|
||||||
protected_caller,
|
protected_caller: Box::new(protected_caller),
|
||||||
|
cache_gen,
|
||||||
|
|
||||||
info,
|
info,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deref for Module {
|
|
||||||
type Target = ModuleInner;
|
|
||||||
|
|
||||||
fn deref(&self) -> &ModuleInner {
|
|
||||||
&self.module
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DerefMut for Module {
|
|
||||||
fn deref_mut(&mut self) -> &mut ModuleInner {
|
|
||||||
&mut self.module
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Converter<T>(pub T);
|
pub struct Converter<T>(pub T);
|
||||||
|
|
||||||
macro_rules! convert_clif_to_runtime_index {
|
macro_rules! convert_clif_to_runtime_index {
|
||||||
|
@ -139,7 +139,7 @@ impl<'module, 'isa, 'data> ModuleEnvironment<'data> for ModuleEnv<'module, 'isa>
|
|||||||
// assert!(!desc.mutable);
|
// assert!(!desc.mutable);
|
||||||
let global_index: GlobalIndex = Converter(global_index).into();
|
let global_index: GlobalIndex = Converter(global_index).into();
|
||||||
let imported_global_index = global_index
|
let imported_global_index = global_index
|
||||||
.local_or_import(self.module)
|
.local_or_import(&self.module.info)
|
||||||
.import()
|
.import()
|
||||||
.expect("invalid global initializer when declaring an imported global");
|
.expect("invalid global initializer when declaring an imported global");
|
||||||
Initializer::GetGlobal(imported_global_index)
|
Initializer::GetGlobal(imported_global_index)
|
||||||
@ -249,7 +249,7 @@ impl<'module, 'isa, 'data> ModuleEnvironment<'data> for ModuleEnv<'module, 'isa>
|
|||||||
let base = match base {
|
let base = match base {
|
||||||
Some(global_index) => {
|
Some(global_index) => {
|
||||||
let global_index: GlobalIndex = Converter(global_index).into();
|
let global_index: GlobalIndex = Converter(global_index).into();
|
||||||
Initializer::GetGlobal(match global_index.local_or_import(self.module) {
|
Initializer::GetGlobal(match global_index.local_or_import(&self.module.info) {
|
||||||
LocalOrImport::Import(imported_global_index) => imported_global_index,
|
LocalOrImport::Import(imported_global_index) => imported_global_index,
|
||||||
LocalOrImport::Local(_) => {
|
LocalOrImport::Local(_) => {
|
||||||
panic!("invalid global initializer when declaring an imported global")
|
panic!("invalid global initializer when declaring an imported global")
|
||||||
@ -319,7 +319,7 @@ impl<'module, 'isa, 'data> ModuleEnvironment<'data> for ModuleEnv<'module, 'isa>
|
|||||||
let base = match base {
|
let base = match base {
|
||||||
Some(global_index) => {
|
Some(global_index) => {
|
||||||
let global_index: GlobalIndex = Converter(global_index).into();
|
let global_index: GlobalIndex = Converter(global_index).into();
|
||||||
Initializer::GetGlobal(match global_index.local_or_import(self.module) {
|
Initializer::GetGlobal(match global_index.local_or_import(&self.module.info) {
|
||||||
LocalOrImport::Import(imported_global_index) => imported_global_index,
|
LocalOrImport::Import(imported_global_index) => imported_global_index,
|
||||||
LocalOrImport::Local(_) => {
|
LocalOrImport::Local(_) => {
|
||||||
panic!("invalid global initializer when declaring an imported global")
|
panic!("invalid global initializer when declaring an imported global")
|
||||||
@ -389,7 +389,7 @@ impl<'module, 'isa, 'data> ModuleEnvironment<'data> for ModuleEnv<'module, 'isa>
|
|||||||
let name = ir::ExternalName::user(0, func_index.index() as u32);
|
let name = ir::ExternalName::user(0, func_index.index() as u32);
|
||||||
|
|
||||||
let sig = func_env.generate_signature(
|
let sig = func_env.generate_signature(
|
||||||
self.get_func_type(Converter(func_index.convert_up(self.module)).into()),
|
self.get_func_type(Converter(func_index.convert_up(&self.module.info)).into()),
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut func = ir::Function::with_name_signature(name, sig);
|
let mut func = ir::Function::with_name_signature(name, sig);
|
||||||
|
@ -22,16 +22,14 @@ pub mod call_names {
|
|||||||
pub const DYNAMIC_MEM_SIZE: u32 = 5;
|
pub const DYNAMIC_MEM_SIZE: u32 = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))]
|
#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq)]
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
|
||||||
pub enum Reloc {
|
pub enum Reloc {
|
||||||
Abs8,
|
Abs8,
|
||||||
X86PCRel4,
|
X86PCRel4,
|
||||||
X86CallPCRel4,
|
X86CallPCRel4,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))]
|
#[derive(Serialize, Deserialize, Debug, Copy, Clone)]
|
||||||
#[derive(Debug, Copy, Clone)]
|
|
||||||
pub enum LibCall {
|
pub enum LibCall {
|
||||||
Probestack,
|
Probestack,
|
||||||
CeilF32,
|
CeilF32,
|
||||||
@ -44,8 +42,7 @@ pub enum LibCall {
|
|||||||
NearestF64,
|
NearestF64,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))]
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct ExternalRelocation {
|
pub struct ExternalRelocation {
|
||||||
/// The relocation code.
|
/// The relocation code.
|
||||||
pub reloc: Reloc,
|
pub reloc: Reloc,
|
||||||
@ -66,8 +63,7 @@ pub struct LocalRelocation {
|
|||||||
pub target: FuncIndex,
|
pub target: FuncIndex,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))]
|
#[derive(Serialize, Deserialize, Debug, Clone, Copy)]
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
pub enum VmCallKind {
|
pub enum VmCallKind {
|
||||||
StaticMemoryGrow,
|
StaticMemoryGrow,
|
||||||
StaticMemorySize,
|
StaticMemorySize,
|
||||||
@ -79,16 +75,14 @@ pub enum VmCallKind {
|
|||||||
DynamicMemorySize,
|
DynamicMemorySize,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))]
|
#[derive(Serialize, Deserialize, Debug, Clone, Copy)]
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
pub enum VmCall {
|
pub enum VmCall {
|
||||||
Local(VmCallKind),
|
Local(VmCallKind),
|
||||||
Import(VmCallKind),
|
Import(VmCallKind),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Specify the type of relocation
|
/// Specify the type of relocation
|
||||||
#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))]
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub enum RelocationType {
|
pub enum RelocationType {
|
||||||
Intrinsic(String),
|
Intrinsic(String),
|
||||||
LibCall(LibCall),
|
LibCall(LibCall),
|
||||||
@ -218,8 +212,7 @@ impl binemit::RelocSink for RelocSink {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))]
|
#[derive(Serialize, Deserialize, Debug, Clone, Copy)]
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
pub enum TrapCode {
|
pub enum TrapCode {
|
||||||
StackOverflow,
|
StackOverflow,
|
||||||
HeapOutOfBounds,
|
HeapOutOfBounds,
|
||||||
@ -244,8 +237,7 @@ impl RelocSink {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))]
|
#[derive(Serialize, Deserialize, Debug, Clone, Copy)]
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
pub struct TrapData {
|
pub struct TrapData {
|
||||||
pub trapcode: TrapCode,
|
pub trapcode: TrapCode,
|
||||||
pub srcloc: u32,
|
pub srcloc: u32,
|
||||||
@ -253,7 +245,7 @@ pub struct TrapData {
|
|||||||
|
|
||||||
/// Simple implementation of a TrapSink
|
/// Simple implementation of a TrapSink
|
||||||
/// that saves the info for later.
|
/// that saves the info for later.
|
||||||
#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct TrapSink {
|
pub struct TrapSink {
|
||||||
trap_datas: Vec<(usize, TrapData)>,
|
trap_datas: Vec<(usize, TrapData)>,
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,4 @@
|
|||||||
#[cfg(feature = "cache")]
|
use crate::{cache::BackendCache, trampoline::Trampolines};
|
||||||
use crate::{
|
|
||||||
cache::{BackendCache, TrampolineCache},
|
|
||||||
trampoline::Trampolines,
|
|
||||||
};
|
|
||||||
use crate::{
|
use crate::{
|
||||||
libcalls,
|
libcalls,
|
||||||
relocation::{
|
relocation::{
|
||||||
@ -19,7 +15,7 @@ use std::{
|
|||||||
ptr::{write_unaligned, NonNull},
|
ptr::{write_unaligned, NonNull},
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
};
|
};
|
||||||
#[cfg(feature = "cache")]
|
|
||||||
use wasmer_runtime_core::cache::Error as CacheError;
|
use wasmer_runtime_core::cache::Error as CacheError;
|
||||||
use wasmer_runtime_core::{
|
use wasmer_runtime_core::{
|
||||||
self,
|
self,
|
||||||
@ -42,21 +38,32 @@ extern "C" {
|
|||||||
pub fn __chkstk();
|
pub fn __chkstk();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn lookup_func(
|
||||||
|
map: &SliceMap<LocalFuncIndex, usize>,
|
||||||
|
memory: &Memory,
|
||||||
|
local_func_index: LocalFuncIndex,
|
||||||
|
) -> Option<NonNull<vm::Func>> {
|
||||||
|
let offset = *map.get(local_func_index)?;
|
||||||
|
let ptr = unsafe { memory.as_ptr().add(offset) };
|
||||||
|
|
||||||
|
NonNull::new(ptr).map(|nonnull| nonnull.cast())
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub struct FuncResolverBuilder {
|
pub struct FuncResolverBuilder {
|
||||||
resolver: FuncResolver,
|
map: Map<LocalFuncIndex, usize>,
|
||||||
|
memory: Memory,
|
||||||
local_relocs: Map<LocalFuncIndex, Box<[LocalRelocation]>>,
|
local_relocs: Map<LocalFuncIndex, Box<[LocalRelocation]>>,
|
||||||
external_relocs: Map<LocalFuncIndex, Box<[ExternalRelocation]>>,
|
external_relocs: Map<LocalFuncIndex, Box<[ExternalRelocation]>>,
|
||||||
import_len: usize,
|
import_len: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FuncResolverBuilder {
|
impl FuncResolverBuilder {
|
||||||
#[cfg(feature = "cache")]
|
|
||||||
pub fn new_from_backend_cache(
|
pub fn new_from_backend_cache(
|
||||||
backend_cache: BackendCache,
|
backend_cache: BackendCache,
|
||||||
mut code: Memory,
|
mut code: Memory,
|
||||||
info: &ModuleInfo,
|
info: &ModuleInfo,
|
||||||
) -> Result<(Self, Trampolines, HandlerData), CacheError> {
|
) -> Result<(Self, Arc<Trampolines>, HandlerData), CacheError> {
|
||||||
unsafe {
|
unsafe {
|
||||||
code.protect(.., Protect::ReadWrite)
|
code.protect(.., Protect::ReadWrite)
|
||||||
.map_err(|e| CacheError::Unknown(e.to_string()))?;
|
.map_err(|e| CacheError::Unknown(e.to_string()))?;
|
||||||
@ -67,37 +74,19 @@ impl FuncResolverBuilder {
|
|||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
Self {
|
Self {
|
||||||
resolver: FuncResolver {
|
map: backend_cache.offsets,
|
||||||
map: backend_cache.offsets,
|
memory: code,
|
||||||
memory: code,
|
|
||||||
},
|
|
||||||
local_relocs: Map::new(),
|
local_relocs: Map::new(),
|
||||||
external_relocs: backend_cache.external_relocs,
|
external_relocs: backend_cache.external_relocs,
|
||||||
import_len: info.imported_functions.len(),
|
import_len: info.imported_functions.len(),
|
||||||
},
|
},
|
||||||
Trampolines::from_trampoline_cache(backend_cache.trampolines),
|
Arc::new(Trampolines::from_trampoline_cache(
|
||||||
|
backend_cache.trampolines,
|
||||||
|
)),
|
||||||
handler_data,
|
handler_data,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "cache")]
|
|
||||||
pub fn to_backend_cache(
|
|
||||||
mut self,
|
|
||||||
trampolines: TrampolineCache,
|
|
||||||
handler_data: HandlerData,
|
|
||||||
) -> (BackendCache, Memory) {
|
|
||||||
self.relocate_locals();
|
|
||||||
(
|
|
||||||
BackendCache {
|
|
||||||
external_relocs: self.external_relocs,
|
|
||||||
offsets: self.resolver.map,
|
|
||||||
trap_sink: handler_data.trap_data,
|
|
||||||
trampolines,
|
|
||||||
},
|
|
||||||
self.resolver.memory,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new(
|
pub fn new(
|
||||||
isa: &isa::TargetIsa,
|
isa: &isa::TargetIsa,
|
||||||
function_bodies: Map<LocalFuncIndex, ir::Function>,
|
function_bodies: Map<LocalFuncIndex, ir::Function>,
|
||||||
@ -169,10 +158,12 @@ impl FuncResolverBuilder {
|
|||||||
previous_end = new_end;
|
previous_end = new_end;
|
||||||
}
|
}
|
||||||
|
|
||||||
let handler_data = HandlerData::new(trap_sink, memory.as_ptr() as _, memory.size());
|
let handler_data =
|
||||||
|
HandlerData::new(Arc::new(trap_sink), memory.as_ptr() as _, memory.size());
|
||||||
|
|
||||||
let mut func_resolver_builder = Self {
|
let mut func_resolver_builder = Self {
|
||||||
resolver: FuncResolver { map, memory },
|
map,
|
||||||
|
memory,
|
||||||
local_relocs,
|
local_relocs,
|
||||||
external_relocs,
|
external_relocs,
|
||||||
import_len: info.imported_functions.len(),
|
import_len: info.imported_functions.len(),
|
||||||
@ -187,12 +178,15 @@ impl FuncResolverBuilder {
|
|||||||
for (index, relocs) in self.local_relocs.iter() {
|
for (index, relocs) in self.local_relocs.iter() {
|
||||||
for ref reloc in relocs.iter() {
|
for ref reloc in relocs.iter() {
|
||||||
let local_func_index = LocalFuncIndex::new(reloc.target.index() - self.import_len);
|
let local_func_index = LocalFuncIndex::new(reloc.target.index() - self.import_len);
|
||||||
let target_func_address =
|
let target_func_address = lookup_func(&self.map, &self.memory, local_func_index)
|
||||||
self.resolver.lookup(local_func_index).unwrap().as_ptr() as usize;
|
.unwrap()
|
||||||
|
.as_ptr() as usize;
|
||||||
|
|
||||||
// We need the address of the current function
|
// We need the address of the current function
|
||||||
// because these calls are relative.
|
// because these calls are relative.
|
||||||
let func_addr = self.resolver.lookup(index).unwrap().as_ptr() as usize;
|
let func_addr = lookup_func(&self.map, &self.memory, index)
|
||||||
|
.unwrap()
|
||||||
|
.as_ptr() as usize;
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let reloc_address = func_addr + reloc.offset as usize;
|
let reloc_address = func_addr + reloc.offset as usize;
|
||||||
@ -209,7 +203,9 @@ impl FuncResolverBuilder {
|
|||||||
pub fn finalize(
|
pub fn finalize(
|
||||||
mut self,
|
mut self,
|
||||||
signatures: &SliceMap<SigIndex, Arc<FuncSig>>,
|
signatures: &SliceMap<SigIndex, Arc<FuncSig>>,
|
||||||
) -> CompileResult<FuncResolver> {
|
trampolines: Arc<Trampolines>,
|
||||||
|
handler_data: HandlerData,
|
||||||
|
) -> CompileResult<(FuncResolver, BackendCache)> {
|
||||||
for (index, relocs) in self.external_relocs.iter() {
|
for (index, relocs) in self.external_relocs.iter() {
|
||||||
for ref reloc in relocs.iter() {
|
for ref reloc in relocs.iter() {
|
||||||
let target_func_address: isize = match reloc.target {
|
let target_func_address: isize = match reloc.target {
|
||||||
@ -281,7 +277,9 @@ impl FuncResolverBuilder {
|
|||||||
|
|
||||||
// We need the address of the current function
|
// We need the address of the current function
|
||||||
// because some of these calls are relative.
|
// because some of these calls are relative.
|
||||||
let func_addr = self.resolver.lookup(index).unwrap().as_ptr();
|
let func_addr = lookup_func(&self.map, &self.memory, index)
|
||||||
|
.unwrap()
|
||||||
|
.as_ptr() as usize;
|
||||||
|
|
||||||
// Determine relocation type and apply relocation.
|
// Determine relocation type and apply relocation.
|
||||||
match reloc.reloc {
|
match reloc.reloc {
|
||||||
@ -289,9 +287,9 @@ impl FuncResolverBuilder {
|
|||||||
let ptr_to_write = (target_func_address as u64)
|
let ptr_to_write = (target_func_address as u64)
|
||||||
.checked_add(reloc.addend as u64)
|
.checked_add(reloc.addend as u64)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let empty_space_offset = self.resolver.map[index] + reloc.offset as usize;
|
let empty_space_offset = self.map[index] + reloc.offset as usize;
|
||||||
let ptr_slice = unsafe {
|
let ptr_slice = unsafe {
|
||||||
&mut self.resolver.memory.as_slice_mut()
|
&mut self.memory.as_slice_mut()
|
||||||
[empty_space_offset..empty_space_offset + 8]
|
[empty_space_offset..empty_space_offset + 8]
|
||||||
};
|
};
|
||||||
LittleEndian::write_u64(ptr_slice, ptr_to_write);
|
LittleEndian::write_u64(ptr_slice, ptr_to_write);
|
||||||
@ -309,29 +307,35 @@ impl FuncResolverBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
self.resolver
|
self.memory
|
||||||
.memory
|
|
||||||
.protect(.., Protect::ReadExec)
|
.protect(.., Protect::ReadExec)
|
||||||
.map_err(|e| CompileError::InternalError { msg: e.to_string() })?;
|
.map_err(|e| CompileError::InternalError { msg: e.to_string() })?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(self.resolver)
|
let backend_cache = BackendCache {
|
||||||
|
external_relocs: self.external_relocs.clone(),
|
||||||
|
offsets: self.map.clone(),
|
||||||
|
trap_sink: handler_data.trap_data,
|
||||||
|
trampolines: trampolines.to_trampoline_cache(),
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok((
|
||||||
|
FuncResolver {
|
||||||
|
map: self.map,
|
||||||
|
memory: Arc::new(self.memory),
|
||||||
|
},
|
||||||
|
backend_cache,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe impl Sync for FuncResolver {}
|
||||||
|
unsafe impl Send for FuncResolver {}
|
||||||
|
|
||||||
/// Resolves a function index to a function address.
|
/// Resolves a function index to a function address.
|
||||||
pub struct FuncResolver {
|
pub struct FuncResolver {
|
||||||
map: Map<LocalFuncIndex, usize>,
|
map: Map<LocalFuncIndex, usize>,
|
||||||
memory: Memory,
|
pub(crate) memory: Arc<Memory>,
|
||||||
}
|
|
||||||
|
|
||||||
impl FuncResolver {
|
|
||||||
fn lookup(&self, local_func_index: LocalFuncIndex) -> Option<NonNull<vm::Func>> {
|
|
||||||
let offset = *self.map.get(local_func_index)?;
|
|
||||||
let ptr = unsafe { self.memory.as_ptr().add(offset) };
|
|
||||||
|
|
||||||
NonNull::new(ptr).map(|nonnull| nonnull.cast())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implements FuncResolver trait.
|
// Implements FuncResolver trait.
|
||||||
@ -341,7 +345,7 @@ impl backend::FuncResolver for FuncResolver {
|
|||||||
_module: &wasmer_runtime_core::module::ModuleInner,
|
_module: &wasmer_runtime_core::module::ModuleInner,
|
||||||
index: LocalFuncIndex,
|
index: LocalFuncIndex,
|
||||||
) -> Option<NonNull<vm::Func>> {
|
) -> Option<NonNull<vm::Func>> {
|
||||||
self.lookup(index)
|
lookup_func(&self.map, &self.memory, index)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,11 +40,15 @@ impl UserTrapper for Trapper {
|
|||||||
pub struct Caller {
|
pub struct Caller {
|
||||||
func_export_set: HashSet<FuncIndex>,
|
func_export_set: HashSet<FuncIndex>,
|
||||||
handler_data: HandlerData,
|
handler_data: HandlerData,
|
||||||
trampolines: Trampolines,
|
trampolines: Arc<Trampolines>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Caller {
|
impl Caller {
|
||||||
pub fn new(module: &ModuleInfo, handler_data: HandlerData, trampolines: Trampolines) -> Self {
|
pub fn new(
|
||||||
|
module: &ModuleInfo,
|
||||||
|
handler_data: HandlerData,
|
||||||
|
trampolines: Arc<Trampolines>,
|
||||||
|
) -> Self {
|
||||||
let mut func_export_set = HashSet::new();
|
let mut func_export_set = HashSet::new();
|
||||||
for export_index in module.exports.values() {
|
for export_index in module.exports.values() {
|
||||||
if let ExportIndex::Func(func_index) = export_index {
|
if let ExportIndex::Func(func_index) = export_index {
|
||||||
@ -160,7 +164,7 @@ fn get_func_from_index(
|
|||||||
.get(func_index)
|
.get(func_index)
|
||||||
.expect("broken invariant, incorrect func index");
|
.expect("broken invariant, incorrect func index");
|
||||||
|
|
||||||
let (func_ptr, ctx) = match func_index.local_or_import(module) {
|
let (func_ptr, ctx) = match func_index.local_or_import(&module.info) {
|
||||||
LocalOrImport::Local(local_func_index) => (
|
LocalOrImport::Local(local_func_index) => (
|
||||||
module
|
module
|
||||||
.func_resolver
|
.func_resolver
|
||||||
@ -187,15 +191,16 @@ fn get_func_from_index(
|
|||||||
unsafe impl Send for HandlerData {}
|
unsafe impl Send for HandlerData {}
|
||||||
unsafe impl Sync for HandlerData {}
|
unsafe impl Sync for HandlerData {}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct HandlerData {
|
pub struct HandlerData {
|
||||||
pub trap_data: TrapSink,
|
pub trap_data: Arc<TrapSink>,
|
||||||
exec_buffer_ptr: *const c_void,
|
exec_buffer_ptr: *const c_void,
|
||||||
exec_buffer_size: usize,
|
exec_buffer_size: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HandlerData {
|
impl HandlerData {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
trap_data: TrapSink,
|
trap_data: Arc<TrapSink>,
|
||||||
exec_buffer_ptr: *const c_void,
|
exec_buffer_ptr: *const c_void,
|
||||||
exec_buffer_size: usize,
|
exec_buffer_size: usize,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
#[cfg(feature = "cache")]
|
|
||||||
use crate::cache::TrampolineCache;
|
use crate::cache::TrampolineCache;
|
||||||
use cranelift_codegen::{
|
use cranelift_codegen::{
|
||||||
binemit::{NullTrapSink, Reloc, RelocSink},
|
binemit::{NullTrapSink, Reloc, RelocSink},
|
||||||
@ -33,7 +32,6 @@ pub struct Trampolines {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Trampolines {
|
impl Trampolines {
|
||||||
#[cfg(feature = "cache")]
|
|
||||||
pub fn from_trampoline_cache(cache: TrampolineCache) -> Self {
|
pub fn from_trampoline_cache(cache: TrampolineCache) -> Self {
|
||||||
// pub struct TrampolineCache {
|
// pub struct TrampolineCache {
|
||||||
// #[serde(with = "serde_bytes")]
|
// #[serde(with = "serde_bytes")]
|
||||||
@ -57,8 +55,7 @@ impl Trampolines {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "cache")]
|
pub fn to_trampoline_cache(&self) -> TrampolineCache {
|
||||||
pub fn to_trampoline_cache(self) -> TrampolineCache {
|
|
||||||
let mut code = vec![0; self.memory.size()];
|
let mut code = vec![0; self.memory.size()];
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
@ -67,7 +64,7 @@ impl Trampolines {
|
|||||||
|
|
||||||
TrampolineCache {
|
TrampolineCache {
|
||||||
code,
|
code,
|
||||||
offsets: self.offsets,
|
offsets: self.offsets.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -249,13 +249,13 @@ impl EmscriptenGlobals {
|
|||||||
namespace_index,
|
namespace_index,
|
||||||
name_index,
|
name_index,
|
||||||
},
|
},
|
||||||
) in &module.0.info.imported_functions
|
) in &module.info().imported_functions
|
||||||
{
|
{
|
||||||
let namespace = module.0.info.namespace_table.get(*namespace_index);
|
let namespace = module.info().namespace_table.get(*namespace_index);
|
||||||
let name = module.0.info.name_table.get(*name_index);
|
let name = module.info().name_table.get(*name_index);
|
||||||
if name == "abortOnCannotGrowMemory" && namespace == "env" {
|
if name == "abortOnCannotGrowMemory" && namespace == "env" {
|
||||||
let sig_index = module.0.info.func_assoc[index.convert_up(&module.0)];
|
let sig_index = module.info().func_assoc[index.convert_up(module.info())];
|
||||||
let expected_sig = &module.0.info.signatures[sig_index];
|
let expected_sig = &module.info().signatures[sig_index];
|
||||||
if **expected_sig == *OLD_ABORT_ON_CANNOT_GROW_MEMORY_SIG {
|
if **expected_sig == *OLD_ABORT_ON_CANNOT_GROW_MEMORY_SIG {
|
||||||
use_old_abort_on_cannot_grow_memory = true;
|
use_old_abort_on_cannot_grow_memory = true;
|
||||||
}
|
}
|
||||||
|
@ -16,13 +16,12 @@ use wasmer_runtime_core::{
|
|||||||
|
|
||||||
/// We check if a provided module is an Emscripten generated one
|
/// We check if a provided module is an Emscripten generated one
|
||||||
pub fn is_emscripten_module(module: &Module) -> bool {
|
pub fn is_emscripten_module(module: &Module) -> bool {
|
||||||
for (_, import_name) in &module.0.info.imported_functions {
|
for (_, import_name) in &module.info().imported_functions {
|
||||||
let namespace = module
|
let namespace = module
|
||||||
.0
|
.info()
|
||||||
.info
|
|
||||||
.namespace_table
|
.namespace_table
|
||||||
.get(import_name.namespace_index);
|
.get(import_name.namespace_index);
|
||||||
let field = module.0.info.name_table.get(import_name.name_index);
|
let field = module.info().name_table.get(import_name.name_index);
|
||||||
if field == "_emscripten_memcpy_big" && namespace == "env" {
|
if field == "_emscripten_memcpy_big" && namespace == "env" {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -31,12 +30,12 @@ pub fn is_emscripten_module(module: &Module) -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_emscripten_table_size(module: &Module) -> (u32, Option<u32>) {
|
pub fn get_emscripten_table_size(module: &Module) -> (u32, Option<u32>) {
|
||||||
let (_, table) = &module.0.info.imported_tables[ImportedTableIndex::new(0)];
|
let (_, table) = &module.info().imported_tables[ImportedTableIndex::new(0)];
|
||||||
(table.minimum, table.maximum)
|
(table.minimum, table.maximum)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_emscripten_memory_size(module: &Module) -> (Pages, Option<Pages>) {
|
pub fn get_emscripten_memory_size(module: &Module) -> (Pages, Option<Pages>) {
|
||||||
let (_, memory) = &module.0.info.imported_memories[ImportedMemoryIndex::new(0)];
|
let (_, memory) = &module.info().imported_memories[ImportedMemoryIndex::new(0)];
|
||||||
(memory.minimum, memory.maximum)
|
(memory.minimum, memory.maximum)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,7 +8,6 @@ repository = "https://github.com/wasmerio/wasmer"
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
hashbrown = "0.1"
|
|
||||||
nix = "0.12.0"
|
nix = "0.12.0"
|
||||||
page_size = "0.4.1"
|
page_size = "0.4.1"
|
||||||
wasmparser = "0.23.0"
|
wasmparser = "0.23.0"
|
||||||
@ -17,26 +16,24 @@ lazy_static = "1.2.0"
|
|||||||
indexmap = "1.0.2"
|
indexmap = "1.0.2"
|
||||||
errno = "0.2.4"
|
errno = "0.2.4"
|
||||||
libc = "0.2.48"
|
libc = "0.2.48"
|
||||||
|
hex = "0.3.2"
|
||||||
|
|
||||||
# Dependencies for caching.
|
# Dependencies for caching.
|
||||||
[dependencies.serde]
|
[dependencies.serde]
|
||||||
version = "1.0"
|
version = "1.0"
|
||||||
optional = true
|
# This feature is required for serde to support serializing/deserializing reference counted pointers (e.g. Rc and Arc).
|
||||||
|
features = ["rc"]
|
||||||
[dependencies.serde_derive]
|
[dependencies.serde_derive]
|
||||||
version = "1.0"
|
version = "1.0"
|
||||||
optional = true
|
|
||||||
[dependencies.serde_bytes]
|
[dependencies.serde_bytes]
|
||||||
version = "0.10"
|
version = "0.10"
|
||||||
optional = true
|
|
||||||
[dependencies.serde-bench]
|
[dependencies.serde-bench]
|
||||||
version = "0.0.7"
|
version = "0.0.7"
|
||||||
optional = true
|
|
||||||
[dependencies.memmap]
|
|
||||||
version = "0.7.0"
|
|
||||||
optional = true
|
|
||||||
[dependencies.sha2]
|
[dependencies.sha2]
|
||||||
version = "0.8.0"
|
version = "0.8.0"
|
||||||
optional = true
|
[dependencies.hashbrown]
|
||||||
|
version = "0.1"
|
||||||
|
features = ["serde"]
|
||||||
|
|
||||||
[target.'cfg(windows)'.dependencies]
|
[target.'cfg(windows)'.dependencies]
|
||||||
winapi = { version = "0.3", features = ["memoryapi"] }
|
winapi = { version = "0.3", features = ["memoryapi"] }
|
||||||
@ -47,5 +44,4 @@ field-offset = "0.1.1"
|
|||||||
|
|
||||||
[features]
|
[features]
|
||||||
debug = []
|
debug = []
|
||||||
cache = ["serde/rc", "serde_derive", "serde_bytes", "hashbrown/serde", "serde-bench", "memmap", "sha2"]
|
|
||||||
|
|
||||||
|
@ -6,9 +6,9 @@ use crate::{
|
|||||||
types::{FuncIndex, LocalFuncIndex, Value},
|
types::{FuncIndex, LocalFuncIndex, Value},
|
||||||
vm,
|
vm,
|
||||||
};
|
};
|
||||||
#[cfg(feature = "cache")]
|
|
||||||
use crate::{
|
use crate::{
|
||||||
cache::{Cache, Error as CacheError},
|
cache::{Artifact, Error as CacheError},
|
||||||
module::ModuleInfo,
|
module::ModuleInfo,
|
||||||
sys::Memory,
|
sys::Memory,
|
||||||
};
|
};
|
||||||
@ -19,8 +19,7 @@ pub mod sys {
|
|||||||
}
|
}
|
||||||
pub use crate::sig_registry::SigRegistry;
|
pub use crate::sig_registry::SigRegistry;
|
||||||
|
|
||||||
#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))]
|
#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq)]
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
|
||||||
pub enum Backend {
|
pub enum Backend {
|
||||||
Cranelift,
|
Cranelift,
|
||||||
}
|
}
|
||||||
@ -43,15 +42,7 @@ pub trait Compiler {
|
|||||||
/// be called from inside the runtime.
|
/// be called from inside the runtime.
|
||||||
fn compile(&self, wasm: &[u8], _: Token) -> CompileResult<ModuleInner>;
|
fn compile(&self, wasm: &[u8], _: Token) -> CompileResult<ModuleInner>;
|
||||||
|
|
||||||
#[cfg(feature = "cache")]
|
unsafe fn from_cache(&self, cache: Artifact, _: Token) -> Result<ModuleInner, CacheError>;
|
||||||
unsafe fn from_cache(&self, cache: Cache, _: Token) -> Result<ModuleInner, CacheError>;
|
|
||||||
|
|
||||||
#[cfg(feature = "cache")]
|
|
||||||
fn compile_to_backend_cache_data(
|
|
||||||
&self,
|
|
||||||
wasm: &[u8],
|
|
||||||
_: Token,
|
|
||||||
) -> CompileResult<(Box<ModuleInfo>, Vec<u8>, Memory)>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The functionality exposed by this trait is expected to be used
|
/// The functionality exposed by this trait is expected to be used
|
||||||
@ -99,3 +90,10 @@ pub trait FuncResolver: Send + Sync {
|
|||||||
local_func_index: LocalFuncIndex,
|
local_func_index: LocalFuncIndex,
|
||||||
) -> Option<NonNull<vm::Func>>;
|
) -> Option<NonNull<vm::Func>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait CacheGen: Send + Sync {
|
||||||
|
fn generate_cache(
|
||||||
|
&self,
|
||||||
|
module: &ModuleInner,
|
||||||
|
) -> Result<(Box<ModuleInfo>, Box<[u8]>, Memory), CacheError>;
|
||||||
|
}
|
||||||
|
@ -91,7 +91,7 @@ impl LocalBacking {
|
|||||||
}
|
}
|
||||||
} as usize;
|
} as usize;
|
||||||
|
|
||||||
match init.memory_index.local_or_import(module) {
|
match init.memory_index.local_or_import(&module.info) {
|
||||||
LocalOrImport::Local(local_memory_index) => {
|
LocalOrImport::Local(local_memory_index) => {
|
||||||
let memory_desc = module.info.memories[local_memory_index];
|
let memory_desc = module.info.memories[local_memory_index];
|
||||||
let data_top = init_base + init.data.len();
|
let data_top = init_base + init.data.len();
|
||||||
@ -159,7 +159,7 @@ impl LocalBacking {
|
|||||||
}
|
}
|
||||||
} as usize;
|
} as usize;
|
||||||
|
|
||||||
match init.table_index.local_or_import(module) {
|
match init.table_index.local_or_import(&module.info) {
|
||||||
LocalOrImport::Local(local_table_index) => {
|
LocalOrImport::Local(local_table_index) => {
|
||||||
let table = &tables[local_table_index];
|
let table = &tables[local_table_index];
|
||||||
|
|
||||||
@ -177,7 +177,7 @@ impl LocalBacking {
|
|||||||
SigRegistry.lookup_sig_index(Arc::clone(&signature)).index() as u32,
|
SigRegistry.lookup_sig_index(Arc::clone(&signature)).index() as u32,
|
||||||
);
|
);
|
||||||
|
|
||||||
let (func, ctx) = match func_index.local_or_import(module) {
|
let (func, ctx) = match func_index.local_or_import(&module.info) {
|
||||||
LocalOrImport::Local(local_func_index) => (
|
LocalOrImport::Local(local_func_index) => (
|
||||||
module
|
module
|
||||||
.func_resolver
|
.func_resolver
|
||||||
@ -215,7 +215,7 @@ impl LocalBacking {
|
|||||||
SigRegistry.lookup_sig_index(Arc::clone(&signature)).index() as u32,
|
SigRegistry.lookup_sig_index(Arc::clone(&signature)).index() as u32,
|
||||||
);
|
);
|
||||||
|
|
||||||
let (func, ctx) = match func_index.local_or_import(module) {
|
let (func, ctx) = match func_index.local_or_import(&module.info) {
|
||||||
LocalOrImport::Local(local_func_index) => (
|
LocalOrImport::Local(local_func_index) => (
|
||||||
module
|
module
|
||||||
.func_resolver
|
.func_resolver
|
||||||
@ -364,7 +364,7 @@ fn import_functions(
|
|||||||
},
|
},
|
||||||
) in &module.info.imported_functions
|
) in &module.info.imported_functions
|
||||||
{
|
{
|
||||||
let sig_index = module.info.func_assoc[index.convert_up(module)];
|
let sig_index = module.info.func_assoc[index.convert_up(&module.info)];
|
||||||
let expected_sig = &module.info.signatures[sig_index];
|
let expected_sig = &module.info.signatures[sig_index];
|
||||||
|
|
||||||
let namespace = module.info.namespace_table.get(*namespace_index);
|
let namespace = module.info.namespace_table.get(*namespace_index);
|
||||||
|
@ -1,14 +1,9 @@
|
|||||||
use crate::{module::ModuleInfo, sys::Memory};
|
use crate::{
|
||||||
use memmap::Mmap;
|
module::{Module, ModuleInfo},
|
||||||
use serde_bench::{deserialize, serialize};
|
sys::Memory,
|
||||||
use sha2::{Digest, Sha256};
|
|
||||||
use std::{
|
|
||||||
fs::File,
|
|
||||||
io::{self, Seek, SeekFrom, Write},
|
|
||||||
mem,
|
|
||||||
path::Path,
|
|
||||||
slice,
|
|
||||||
};
|
};
|
||||||
|
use sha2::{Digest, Sha256};
|
||||||
|
use std::{io, mem, slice};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum InvalidFileType {
|
pub enum InvalidFileType {
|
||||||
@ -26,23 +21,81 @@ pub enum Error {
|
|||||||
InvalidatedCache,
|
InvalidatedCache,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<io::Error> for Error {
|
||||||
|
fn from(io_err: io::Error) -> Self {
|
||||||
|
Error::IoError(io_err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The hash of a wasm module.
|
||||||
|
///
|
||||||
|
/// Used as a key when loading and storing modules in a [`Cache`].
|
||||||
|
///
|
||||||
|
/// [`Cache`]: trait.Cache.html
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||||
|
pub struct WasmHash([u8; 32]);
|
||||||
|
|
||||||
|
impl WasmHash {
|
||||||
|
/// Hash a wasm module.
|
||||||
|
///
|
||||||
|
/// # Note:
|
||||||
|
/// This does no verification that the supplied data
|
||||||
|
/// is, in fact, a wasm module.
|
||||||
|
pub fn generate(wasm: &[u8]) -> Self {
|
||||||
|
let mut array = [0u8; 32];
|
||||||
|
array.copy_from_slice(Sha256::digest(wasm).as_slice());
|
||||||
|
WasmHash(array)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create the hexadecimal representation of the
|
||||||
|
/// stored hash.
|
||||||
|
pub fn encode(self) -> String {
|
||||||
|
hex::encode(self.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn into_array(self) -> [u8; 32] {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const CURRENT_CACHE_VERSION: u64 = 0;
|
const CURRENT_CACHE_VERSION: u64 = 0;
|
||||||
|
static WASMER_CACHE_MAGIC: [u8; 8] = *b"WASMER\0\0";
|
||||||
|
|
||||||
/// The header of a cache file.
|
/// The header of a cache file.
|
||||||
#[repr(C, packed)]
|
#[repr(C, packed)]
|
||||||
struct CacheHeader {
|
struct ArtifactHeader {
|
||||||
magic: [u8; 8], // [W, A, S, M, E, R, \0, \0]
|
magic: [u8; 8], // [W, A, S, M, E, R, \0, \0]
|
||||||
version: u64,
|
version: u64,
|
||||||
data_len: u64,
|
data_len: u64,
|
||||||
wasm_hash: [u8; 32], // Sha256 of the wasm in binary format.
|
wasm_hash: [u8; 32], // Sha256 of the wasm in binary format.
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CacheHeader {
|
impl ArtifactHeader {
|
||||||
pub fn read_from_slice(buffer: &[u8]) -> Result<(&CacheHeader, &[u8]), Error> {
|
pub fn read_from_slice(buffer: &[u8]) -> Result<(&Self, &[u8]), Error> {
|
||||||
if buffer.len() >= mem::size_of::<CacheHeader>() {
|
if buffer.len() >= mem::size_of::<ArtifactHeader>() {
|
||||||
if &buffer[..8] == "WASMER\0\0".as_bytes() {
|
if &buffer[..8] == &WASMER_CACHE_MAGIC {
|
||||||
let (header_slice, body_slice) = buffer.split_at(mem::size_of::<CacheHeader>());
|
let (header_slice, body_slice) = buffer.split_at(mem::size_of::<ArtifactHeader>());
|
||||||
let header = unsafe { &*(header_slice.as_ptr() as *const CacheHeader) };
|
let header = unsafe { &*(header_slice.as_ptr() as *const ArtifactHeader) };
|
||||||
|
|
||||||
|
if header.version == CURRENT_CACHE_VERSION {
|
||||||
|
Ok((header, body_slice))
|
||||||
|
} else {
|
||||||
|
Err(Error::InvalidatedCache)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Err(Error::InvalidFile(InvalidFileType::InvalidMagic))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Err(Error::InvalidFile(InvalidFileType::InvalidSize))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read_from_slice_mut(buffer: &mut [u8]) -> Result<(&mut Self, &mut [u8]), Error> {
|
||||||
|
if buffer.len() >= mem::size_of::<ArtifactHeader>() {
|
||||||
|
if &buffer[..8] == &WASMER_CACHE_MAGIC {
|
||||||
|
let (header_slice, body_slice) =
|
||||||
|
buffer.split_at_mut(mem::size_of::<ArtifactHeader>());
|
||||||
|
let header = unsafe { &mut *(header_slice.as_ptr() as *mut ArtifactHeader) };
|
||||||
|
|
||||||
if header.version == CURRENT_CACHE_VERSION {
|
if header.version == CURRENT_CACHE_VERSION {
|
||||||
Ok((header, body_slice))
|
Ok((header, body_slice))
|
||||||
@ -58,72 +111,53 @@ impl CacheHeader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_slice(&self) -> &[u8] {
|
pub fn as_slice(&self) -> &[u8] {
|
||||||
let ptr = self as *const CacheHeader as *const u8;
|
let ptr = self as *const ArtifactHeader as *const u8;
|
||||||
unsafe { slice::from_raw_parts(ptr, mem::size_of::<CacheHeader>()) }
|
unsafe { slice::from_raw_parts(ptr, mem::size_of::<ArtifactHeader>()) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
struct CacheInner {
|
struct ArtifactInner {
|
||||||
info: Box<ModuleInfo>,
|
info: Box<ModuleInfo>,
|
||||||
#[serde(with = "serde_bytes")]
|
#[serde(with = "serde_bytes")]
|
||||||
backend_metadata: Vec<u8>,
|
backend_metadata: Box<[u8]>,
|
||||||
compiled_code: Memory,
|
compiled_code: Memory,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Cache {
|
pub struct Artifact {
|
||||||
inner: CacheInner,
|
inner: ArtifactInner,
|
||||||
wasm_hash: Box<[u8; 32]>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Cache {
|
impl Artifact {
|
||||||
pub(crate) fn new(
|
pub(crate) fn from_parts(
|
||||||
wasm: &[u8],
|
|
||||||
info: Box<ModuleInfo>,
|
info: Box<ModuleInfo>,
|
||||||
backend_metadata: Vec<u8>,
|
backend_metadata: Box<[u8]>,
|
||||||
compiled_code: Memory,
|
compiled_code: Memory,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let wasm_hash = hash_data(wasm);
|
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
inner: CacheInner {
|
inner: ArtifactInner {
|
||||||
info,
|
info,
|
||||||
backend_metadata,
|
backend_metadata,
|
||||||
compiled_code,
|
compiled_code,
|
||||||
},
|
},
|
||||||
wasm_hash: Box::new(wasm_hash),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn open<P>(path: P) -> Result<Cache, Error>
|
pub fn deserialize(bytes: &[u8]) -> Result<Self, Error> {
|
||||||
where
|
let (_, body_slice) = ArtifactHeader::read_from_slice(bytes)?;
|
||||||
P: AsRef<Path>,
|
|
||||||
{
|
|
||||||
let file = File::open(path).map_err(|e| Error::IoError(e))?;
|
|
||||||
|
|
||||||
let mmap = unsafe { Mmap::map(&file).map_err(|e| Error::IoError(e))? };
|
let inner = serde_bench::deserialize(body_slice)
|
||||||
|
.map_err(|e| Error::DeserializeError(format!("{:#?}", e)))?;
|
||||||
|
|
||||||
let (header, body_slice) = CacheHeader::read_from_slice(&mmap[..])?;
|
Ok(Artifact { inner })
|
||||||
|
|
||||||
let inner =
|
|
||||||
deserialize(body_slice).map_err(|e| Error::DeserializeError(format!("{:#?}", e)))?;
|
|
||||||
|
|
||||||
Ok(Cache {
|
|
||||||
inner,
|
|
||||||
wasm_hash: Box::new(header.wasm_hash),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn info(&self) -> &ModuleInfo {
|
pub fn info(&self) -> &ModuleInfo {
|
||||||
&self.inner.info
|
&self.inner.info
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn wasm_hash(&self) -> &[u8; 32] {
|
|
||||||
&self.wasm_hash
|
|
||||||
}
|
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub fn consume(self) -> (ModuleInfo, Vec<u8>, Memory) {
|
pub fn consume(self) -> (ModuleInfo, Box<[u8]>, Memory) {
|
||||||
(
|
(
|
||||||
*self.inner.info,
|
*self.inner.info,
|
||||||
self.inner.backend_metadata,
|
self.inner.backend_metadata,
|
||||||
@ -131,51 +165,35 @@ impl Cache {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn store<P>(&self, path: P) -> Result<(), Error>
|
pub fn serialize(&self) -> Result<Vec<u8>, Error> {
|
||||||
where
|
let cache_header = ArtifactHeader {
|
||||||
P: AsRef<Path>,
|
magic: WASMER_CACHE_MAGIC,
|
||||||
{
|
|
||||||
let mut file = File::create(path).map_err(|e| Error::IoError(e))?;
|
|
||||||
|
|
||||||
let mut buffer = Vec::new();
|
|
||||||
|
|
||||||
serialize(&mut buffer, &self.inner).map_err(|e| Error::SerializeError(e.to_string()))?;
|
|
||||||
|
|
||||||
let data_len = buffer.len() as u64;
|
|
||||||
|
|
||||||
file.seek(SeekFrom::Start(mem::size_of::<CacheHeader>() as u64))
|
|
||||||
.map_err(|e| Error::IoError(e))?;
|
|
||||||
|
|
||||||
file.write(buffer.as_slice())
|
|
||||||
.map_err(|e| Error::IoError(e))?;
|
|
||||||
|
|
||||||
file.seek(SeekFrom::Start(0))
|
|
||||||
.map_err(|e| Error::Unknown(e.to_string()))?;
|
|
||||||
|
|
||||||
let wasm_hash = {
|
|
||||||
let mut array = [0u8; 32];
|
|
||||||
array.copy_from_slice(&*self.wasm_hash);
|
|
||||||
array
|
|
||||||
};
|
|
||||||
|
|
||||||
let cache_header = CacheHeader {
|
|
||||||
magic: [
|
|
||||||
'W' as u8, 'A' as u8, 'S' as u8, 'M' as u8, 'E' as u8, 'R' as u8, 0, 0,
|
|
||||||
],
|
|
||||||
version: CURRENT_CACHE_VERSION,
|
version: CURRENT_CACHE_VERSION,
|
||||||
data_len,
|
data_len: 0,
|
||||||
wasm_hash,
|
wasm_hash: self.inner.info.wasm_hash.into_array(),
|
||||||
};
|
};
|
||||||
|
|
||||||
file.write(cache_header.as_slice())
|
let mut buffer = cache_header.as_slice().to_vec();
|
||||||
.map_err(|e| Error::IoError(e))?;
|
|
||||||
|
|
||||||
Ok(())
|
serde_bench::serialize(&mut buffer, &self.inner)
|
||||||
|
.map_err(|e| Error::SerializeError(e.to_string()))?;
|
||||||
|
|
||||||
|
let data_len = (buffer.len() - mem::size_of::<ArtifactHeader>()) as u64;
|
||||||
|
|
||||||
|
let (header, _) = ArtifactHeader::read_from_slice_mut(&mut buffer)?;
|
||||||
|
header.data_len = data_len;
|
||||||
|
|
||||||
|
Ok(buffer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn hash_data(data: &[u8]) -> [u8; 32] {
|
/// A generic cache for storing and loading compiled wasm modules.
|
||||||
let mut array = [0u8; 32];
|
///
|
||||||
array.copy_from_slice(Sha256::digest(data).as_slice());
|
/// The `wasmer-runtime` supplies a naive `FileSystemCache` api.
|
||||||
array
|
pub trait Cache {
|
||||||
|
type LoadError;
|
||||||
|
type StoreError;
|
||||||
|
|
||||||
|
fn load(&self, key: WasmHash) -> Result<Module, Self::LoadError>;
|
||||||
|
fn store(&mut self, module: Module) -> Result<WasmHash, Self::StoreError>;
|
||||||
}
|
}
|
||||||
|
@ -121,14 +121,14 @@ impl Instance {
|
|||||||
})?;
|
})?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let ctx = match func_index.local_or_import(&*self.module) {
|
let ctx = match func_index.local_or_import(&self.module.info) {
|
||||||
LocalOrImport::Local(_) => self.inner.vmctx,
|
LocalOrImport::Local(_) => self.inner.vmctx,
|
||||||
LocalOrImport::Import(imported_func_index) => {
|
LocalOrImport::Import(imported_func_index) => {
|
||||||
self.inner.import_backing.vm_functions[imported_func_index].vmctx
|
self.inner.import_backing.vm_functions[imported_func_index].vmctx
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let func_ptr = match func_index.local_or_import(&self.module) {
|
let func_ptr = match func_index.local_or_import(&self.module.info) {
|
||||||
LocalOrImport::Local(local_func_index) => self
|
LocalOrImport::Local(local_func_index) => self
|
||||||
.module
|
.module
|
||||||
.func_resolver
|
.func_resolver
|
||||||
@ -288,7 +288,7 @@ impl Instance {
|
|||||||
})?
|
})?
|
||||||
}
|
}
|
||||||
|
|
||||||
let vmctx = match func_index.local_or_import(&self.module) {
|
let vmctx = match func_index.local_or_import(&self.module.info) {
|
||||||
LocalOrImport::Local(_) => self.inner.vmctx,
|
LocalOrImport::Local(_) => self.inner.vmctx,
|
||||||
LocalOrImport::Import(imported_func_index) => {
|
LocalOrImport::Import(imported_func_index) => {
|
||||||
self.inner.import_backing.vm_functions[imported_func_index].vmctx
|
self.inner.import_backing.vm_functions[imported_func_index].vmctx
|
||||||
@ -355,7 +355,7 @@ impl InstanceInner {
|
|||||||
.get(func_index)
|
.get(func_index)
|
||||||
.expect("broken invariant, incorrect func index");
|
.expect("broken invariant, incorrect func index");
|
||||||
|
|
||||||
let (func_ptr, ctx) = match func_index.local_or_import(module) {
|
let (func_ptr, ctx) = match func_index.local_or_import(&module.info) {
|
||||||
LocalOrImport::Local(local_func_index) => (
|
LocalOrImport::Local(local_func_index) => (
|
||||||
module
|
module
|
||||||
.func_resolver
|
.func_resolver
|
||||||
@ -384,7 +384,7 @@ impl InstanceInner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn get_memory_from_index(&self, module: &ModuleInner, mem_index: MemoryIndex) -> Memory {
|
fn get_memory_from_index(&self, module: &ModuleInner, mem_index: MemoryIndex) -> Memory {
|
||||||
match mem_index.local_or_import(module) {
|
match mem_index.local_or_import(&module.info) {
|
||||||
LocalOrImport::Local(local_mem_index) => self.backing.memories[local_mem_index].clone(),
|
LocalOrImport::Local(local_mem_index) => self.backing.memories[local_mem_index].clone(),
|
||||||
LocalOrImport::Import(imported_mem_index) => {
|
LocalOrImport::Import(imported_mem_index) => {
|
||||||
self.import_backing.memories[imported_mem_index].clone()
|
self.import_backing.memories[imported_mem_index].clone()
|
||||||
@ -393,7 +393,7 @@ impl InstanceInner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn get_global_from_index(&self, module: &ModuleInner, global_index: GlobalIndex) -> Global {
|
fn get_global_from_index(&self, module: &ModuleInner, global_index: GlobalIndex) -> Global {
|
||||||
match global_index.local_or_import(module) {
|
match global_index.local_or_import(&module.info) {
|
||||||
LocalOrImport::Local(local_global_index) => {
|
LocalOrImport::Local(local_global_index) => {
|
||||||
self.backing.globals[local_global_index].clone()
|
self.backing.globals[local_global_index].clone()
|
||||||
}
|
}
|
||||||
@ -404,7 +404,7 @@ impl InstanceInner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn get_table_from_index(&self, module: &ModuleInner, table_index: TableIndex) -> Table {
|
fn get_table_from_index(&self, module: &ModuleInner, table_index: TableIndex) -> Table {
|
||||||
match table_index.local_or_import(module) {
|
match table_index.local_or_import(&module.info) {
|
||||||
LocalOrImport::Local(local_table_index) => {
|
LocalOrImport::Local(local_table_index) => {
|
||||||
self.backing.tables[local_table_index].clone()
|
self.backing.tables[local_table_index].clone()
|
||||||
}
|
}
|
||||||
@ -462,7 +462,7 @@ impl<'a> DynFunc<'a> {
|
|||||||
})?
|
})?
|
||||||
}
|
}
|
||||||
|
|
||||||
let vmctx = match self.func_index.local_or_import(self.module) {
|
let vmctx = match self.func_index.local_or_import(&self.module.info) {
|
||||||
LocalOrImport::Local(_) => self.instance_inner.vmctx,
|
LocalOrImport::Local(_) => self.instance_inner.vmctx,
|
||||||
LocalOrImport::Import(imported_func_index) => {
|
LocalOrImport::Import(imported_func_index) => {
|
||||||
self.instance_inner.import_backing.vm_functions[imported_func_index].vmctx
|
self.instance_inner.import_backing.vm_functions[imported_func_index].vmctx
|
||||||
@ -488,7 +488,7 @@ impl<'a> DynFunc<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn raw(&self) -> *const vm::Func {
|
pub fn raw(&self) -> *const vm::Func {
|
||||||
match self.func_index.local_or_import(self.module) {
|
match self.func_index.local_or_import(&self.module.info) {
|
||||||
LocalOrImport::Local(local_func_index) => self
|
LocalOrImport::Local(local_func_index) => self
|
||||||
.module
|
.module
|
||||||
.func_resolver
|
.func_resolver
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate field_offset;
|
extern crate field_offset;
|
||||||
|
|
||||||
#[cfg(feature = "cache")]
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate serde_derive;
|
extern crate serde_derive;
|
||||||
|
|
||||||
@ -11,7 +10,7 @@ mod macros;
|
|||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub mod backend;
|
pub mod backend;
|
||||||
mod backing;
|
mod backing;
|
||||||
#[cfg(feature = "cache")]
|
|
||||||
pub mod cache;
|
pub mod cache;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod export;
|
pub mod export;
|
||||||
@ -44,8 +43,7 @@ pub use self::module::Module;
|
|||||||
pub use self::typed_func::Func;
|
pub use self::typed_func::Func;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
#[cfg(feature = "cache")]
|
use self::cache::{Artifact, Error as CacheError};
|
||||||
use self::cache::{Cache, Error as CacheError};
|
|
||||||
|
|
||||||
pub mod prelude {
|
pub mod prelude {
|
||||||
pub use crate::import::{ImportObject, Namespace};
|
pub use crate::import::{ImportObject, Namespace};
|
||||||
@ -90,21 +88,8 @@ pub fn validate(wasm: &[u8]) -> bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "cache")]
|
|
||||||
pub fn compile_to_cache_with(
|
|
||||||
wasm: &[u8],
|
|
||||||
compiler: &dyn backend::Compiler,
|
|
||||||
) -> CompileResult<Cache> {
|
|
||||||
let token = backend::Token::generate();
|
|
||||||
let (info, backend_metadata, compiled_code) =
|
|
||||||
compiler.compile_to_backend_cache_data(wasm, token)?;
|
|
||||||
|
|
||||||
Ok(Cache::new(wasm, info, backend_metadata, compiled_code))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "cache")]
|
|
||||||
pub unsafe fn load_cache_with(
|
pub unsafe fn load_cache_with(
|
||||||
cache: Cache,
|
cache: Artifact,
|
||||||
compiler: &dyn backend::Compiler,
|
compiler: &dyn backend::Compiler,
|
||||||
) -> std::result::Result<module::Module, CacheError> {
|
) -> std::result::Result<module::Module, CacheError> {
|
||||||
let token = backend::Token::generate();
|
let token = backend::Token::generate();
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
backend::{Backend, FuncResolver, ProtectedCaller},
|
backend::{Backend, FuncResolver, ProtectedCaller},
|
||||||
error::Result,
|
cache::{Artifact, Error as CacheError, WasmHash},
|
||||||
|
error,
|
||||||
import::ImportObject,
|
import::ImportObject,
|
||||||
structures::{Map, TypedIndex},
|
structures::{Map, TypedIndex},
|
||||||
typed_func::EARLY_TRAPPER,
|
typed_func::EARLY_TRAPPER,
|
||||||
@ -12,6 +13,8 @@ use crate::{
|
|||||||
},
|
},
|
||||||
Instance,
|
Instance,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use crate::backend::CacheGen;
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
@ -22,10 +25,12 @@ pub struct ModuleInner {
|
|||||||
pub func_resolver: Box<dyn FuncResolver>,
|
pub func_resolver: Box<dyn FuncResolver>,
|
||||||
pub protected_caller: Box<dyn ProtectedCaller>,
|
pub protected_caller: Box<dyn ProtectedCaller>,
|
||||||
|
|
||||||
|
pub cache_gen: Box<dyn CacheGen>,
|
||||||
|
|
||||||
pub info: ModuleInfo,
|
pub info: ModuleInfo,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))]
|
#[derive(Clone, Serialize, Deserialize)]
|
||||||
pub struct ModuleInfo {
|
pub struct ModuleInfo {
|
||||||
// This are strictly local and the typsystem ensures that.
|
// This are strictly local and the typsystem ensures that.
|
||||||
pub memories: Map<LocalMemoryIndex, MemoryDescriptor>,
|
pub memories: Map<LocalMemoryIndex, MemoryDescriptor>,
|
||||||
@ -51,6 +56,8 @@ pub struct ModuleInfo {
|
|||||||
|
|
||||||
pub namespace_table: StringTable<NamespaceIndex>,
|
pub namespace_table: StringTable<NamespaceIndex>,
|
||||||
pub name_table: StringTable<NameIndex>,
|
pub name_table: StringTable<NameIndex>,
|
||||||
|
|
||||||
|
pub wasm_hash: WasmHash,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A compiled WebAssembly module.
|
/// A compiled WebAssembly module.
|
||||||
@ -60,7 +67,9 @@ pub struct ModuleInfo {
|
|||||||
///
|
///
|
||||||
/// [`compile`]: fn.compile.html
|
/// [`compile`]: fn.compile.html
|
||||||
/// [`compile_with`]: fn.compile_with.html
|
/// [`compile_with`]: fn.compile_with.html
|
||||||
pub struct Module(#[doc(hidden)] pub Arc<ModuleInner>);
|
pub struct Module {
|
||||||
|
inner: Arc<ModuleInner>,
|
||||||
|
}
|
||||||
|
|
||||||
impl Module {
|
impl Module {
|
||||||
pub(crate) fn new(inner: Arc<ModuleInner>) -> Self {
|
pub(crate) fn new(inner: Arc<ModuleInner>) -> Self {
|
||||||
@ -68,7 +77,7 @@ impl Module {
|
|||||||
EARLY_TRAPPER
|
EARLY_TRAPPER
|
||||||
.with(|ucell| *ucell.get() = Some(inner.protected_caller.get_early_trapper()));
|
.with(|ucell| *ucell.get() = Some(inner.protected_caller.get_early_trapper()));
|
||||||
}
|
}
|
||||||
Module(inner)
|
Module { inner }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Instantiate a WebAssembly module with the provided [`ImportObject`].
|
/// Instantiate a WebAssembly module with the provided [`ImportObject`].
|
||||||
@ -93,23 +102,30 @@ impl Module {
|
|||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn instantiate(&self, import_object: &ImportObject) -> Result<Instance> {
|
pub fn instantiate(&self, import_object: &ImportObject) -> error::Result<Instance> {
|
||||||
Instance::new(Arc::clone(&self.0), import_object)
|
Instance::new(Arc::clone(&self.inner), import_object)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cache(&self) -> Result<Artifact, CacheError> {
|
||||||
|
let (info, backend_metadata, code) = self.inner.cache_gen.generate_cache(&self.inner)?;
|
||||||
|
Ok(Artifact::from_parts(info, backend_metadata, code))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn info(&self) -> &ModuleInfo {
|
||||||
|
&self.inner.info
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ModuleInner {}
|
impl ModuleInner {}
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))]
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct ImportName {
|
pub struct ImportName {
|
||||||
pub namespace_index: NamespaceIndex,
|
pub namespace_index: NamespaceIndex,
|
||||||
pub name_index: NameIndex,
|
pub name_index: NameIndex,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))]
|
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
||||||
pub enum ExportIndex {
|
pub enum ExportIndex {
|
||||||
Func(FuncIndex),
|
Func(FuncIndex),
|
||||||
Memory(MemoryIndex),
|
Memory(MemoryIndex),
|
||||||
@ -118,8 +134,7 @@ pub enum ExportIndex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A data initializer for linear memory.
|
/// A data initializer for linear memory.
|
||||||
#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))]
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct DataInitializer {
|
pub struct DataInitializer {
|
||||||
/// The index of the memory to initialize.
|
/// The index of the memory to initialize.
|
||||||
pub memory_index: MemoryIndex,
|
pub memory_index: MemoryIndex,
|
||||||
@ -131,8 +146,7 @@ pub struct DataInitializer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A WebAssembly table initializer.
|
/// A WebAssembly table initializer.
|
||||||
#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))]
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct TableInitializer {
|
pub struct TableInitializer {
|
||||||
/// The index of a table to initialize.
|
/// The index of a table to initialize.
|
||||||
pub table_index: TableIndex,
|
pub table_index: TableIndex,
|
||||||
@ -193,8 +207,7 @@ impl<K: TypedIndex> StringTableBuilder<K> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))]
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct StringTable<K: TypedIndex> {
|
pub struct StringTable<K: TypedIndex> {
|
||||||
table: Map<K, (u32, u32)>,
|
table: Map<K, (u32, u32)>,
|
||||||
buffer: String,
|
buffer: String,
|
||||||
@ -217,8 +230,7 @@ impl<K: TypedIndex> StringTable<K> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))]
|
#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
|
||||||
pub struct NamespaceIndex(u32);
|
pub struct NamespaceIndex(u32);
|
||||||
|
|
||||||
impl TypedIndex for NamespaceIndex {
|
impl TypedIndex for NamespaceIndex {
|
||||||
@ -233,8 +245,7 @@ impl TypedIndex for NamespaceIndex {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))]
|
#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
|
||||||
pub struct NameIndex(u32);
|
pub struct NameIndex(u32);
|
||||||
|
|
||||||
impl TypedIndex for NameIndex {
|
impl TypedIndex for NameIndex {
|
||||||
|
@ -8,8 +8,7 @@ use std::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
/// Dense item map
|
/// Dense item map
|
||||||
#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))]
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct Map<K, V>
|
pub struct Map<K, V>
|
||||||
where
|
where
|
||||||
K: TypedIndex,
|
K: TypedIndex,
|
||||||
|
@ -10,18 +10,16 @@ pub use self::unix::*;
|
|||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
pub use self::windows::*;
|
pub use self::windows::*;
|
||||||
|
|
||||||
#[cfg(feature = "cache")]
|
|
||||||
use serde::{
|
use serde::{
|
||||||
de::{self, SeqAccess, Visitor},
|
de::{self, SeqAccess, Visitor},
|
||||||
ser::SerializeStruct,
|
ser::SerializeStruct,
|
||||||
Deserialize, Deserializer, Serialize, Serializer,
|
Deserialize, Deserializer, Serialize, Serializer,
|
||||||
};
|
};
|
||||||
#[cfg(feature = "cache")]
|
|
||||||
use serde_bytes::Bytes;
|
use serde_bytes::Bytes;
|
||||||
#[cfg(feature = "cache")]
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
#[cfg(feature = "cache")]
|
|
||||||
impl Serialize for Memory {
|
impl Serialize for Memory {
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
where
|
where
|
||||||
@ -36,7 +34,6 @@ impl Serialize for Memory {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "cache")]
|
|
||||||
impl<'de> Deserialize<'de> for Memory {
|
impl<'de> Deserialize<'de> for Memory {
|
||||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
where
|
where
|
||||||
|
@ -205,8 +205,28 @@ impl Drop for Memory {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))]
|
impl Clone for Memory {
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
fn clone(&self) -> Self {
|
||||||
|
let temp_protection = if self.protection.is_writable() {
|
||||||
|
self.protection
|
||||||
|
} else {
|
||||||
|
Protect::ReadWrite
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut new = Memory::with_size_protect(self.size, temp_protection).unwrap();
|
||||||
|
unsafe {
|
||||||
|
new.as_slice_mut().copy_from_slice(self.as_slice());
|
||||||
|
|
||||||
|
if temp_protection != self.protection {
|
||||||
|
new.protect(.., self.protection).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
new
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq)]
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub enum Protect {
|
pub enum Protect {
|
||||||
None,
|
None,
|
||||||
|
@ -156,8 +156,28 @@ impl Drop for Memory {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))]
|
impl Clone for Memory {
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
fn clone(&self) -> Self {
|
||||||
|
let temp_protection = if self.protection.is_writable() {
|
||||||
|
self.protection
|
||||||
|
} else {
|
||||||
|
Protect::ReadWrite
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut new = Memory::with_size_protect(self.size, temp_protection).unwrap();
|
||||||
|
unsafe {
|
||||||
|
new.as_slice_mut().copy_from_slice(self.as_slice());
|
||||||
|
|
||||||
|
if temp_protection != self.protection {
|
||||||
|
new.protect(.., self.protection).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
new
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq)]
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub enum Protect {
|
pub enum Protect {
|
||||||
None,
|
None,
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
use crate::{memory::MemoryType, module::ModuleInner, structures::TypedIndex, units::Pages};
|
use crate::{memory::MemoryType, module::ModuleInfo, structures::TypedIndex, units::Pages};
|
||||||
use std::{borrow::Cow, mem};
|
use std::{borrow::Cow, mem};
|
||||||
|
|
||||||
/// Represents a WebAssembly type.
|
/// Represents a WebAssembly type.
|
||||||
#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))]
|
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
|
||||||
pub enum Type {
|
pub enum Type {
|
||||||
/// The `i32` type.
|
/// The `i32` type.
|
||||||
I32,
|
I32,
|
||||||
@ -25,8 +24,7 @@ impl std::fmt::Display for Type {
|
|||||||
///
|
///
|
||||||
/// As the number of types in WebAssembly expand,
|
/// As the number of types in WebAssembly expand,
|
||||||
/// this structure will expand as well.
|
/// this structure will expand as well.
|
||||||
#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))]
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
|
||||||
pub enum Value {
|
pub enum Value {
|
||||||
/// The `i32` type.
|
/// The `i32` type.
|
||||||
I32(i32),
|
I32(i32),
|
||||||
@ -171,15 +169,13 @@ impl ValueType for f64 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))]
|
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
||||||
pub enum ElementType {
|
pub enum ElementType {
|
||||||
/// Any wasm function.
|
/// Any wasm function.
|
||||||
Anyfunc,
|
Anyfunc,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))]
|
#[derive(Serialize, Deserialize, Debug, Clone, Copy)]
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
pub struct TableDescriptor {
|
pub struct TableDescriptor {
|
||||||
/// Type of data stored in this table.
|
/// Type of data stored in this table.
|
||||||
pub element: ElementType,
|
pub element: ElementType,
|
||||||
@ -203,8 +199,7 @@ impl TableDescriptor {
|
|||||||
/// A const value initializer.
|
/// A const value initializer.
|
||||||
/// Over time, this will be able to represent more and more
|
/// Over time, this will be able to represent more and more
|
||||||
/// complex expressions.
|
/// complex expressions.
|
||||||
#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))]
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
|
||||||
pub enum Initializer {
|
pub enum Initializer {
|
||||||
/// Corresponds to a `const.*` instruction.
|
/// Corresponds to a `const.*` instruction.
|
||||||
Const(Value),
|
Const(Value),
|
||||||
@ -212,24 +207,21 @@ pub enum Initializer {
|
|||||||
GetGlobal(ImportedGlobalIndex),
|
GetGlobal(ImportedGlobalIndex),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))]
|
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
||||||
pub struct GlobalDescriptor {
|
pub struct GlobalDescriptor {
|
||||||
pub mutable: bool,
|
pub mutable: bool,
|
||||||
pub ty: Type,
|
pub ty: Type,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A wasm global.
|
/// A wasm global.
|
||||||
#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))]
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct GlobalInit {
|
pub struct GlobalInit {
|
||||||
pub desc: GlobalDescriptor,
|
pub desc: GlobalDescriptor,
|
||||||
pub init: Initializer,
|
pub init: Initializer,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A wasm memory.
|
/// A wasm memory.
|
||||||
#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))]
|
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
||||||
pub struct MemoryDescriptor {
|
pub struct MemoryDescriptor {
|
||||||
/// The minimum number of allowed pages.
|
/// The minimum number of allowed pages.
|
||||||
pub minimum: Pages,
|
pub minimum: Pages,
|
||||||
@ -261,8 +253,7 @@ impl MemoryDescriptor {
|
|||||||
|
|
||||||
/// The signature of a function that is either implemented
|
/// The signature of a function that is either implemented
|
||||||
/// in a wasm module or exposed to wasm by the host.
|
/// in a wasm module or exposed to wasm by the host.
|
||||||
#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))]
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
|
||||||
pub struct FuncSig {
|
pub struct FuncSig {
|
||||||
params: Cow<'static, [Type]>,
|
params: Cow<'static, [Type]>,
|
||||||
returns: Cow<'static, [Type]>,
|
returns: Cow<'static, [Type]>,
|
||||||
@ -324,7 +315,7 @@ pub trait LocalImport {
|
|||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
macro_rules! define_map_index {
|
macro_rules! define_map_index {
|
||||||
($ty:ident) => {
|
($ty:ident) => {
|
||||||
#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))]
|
#[derive(Serialize, Deserialize)]
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct $ty (u32);
|
pub struct $ty (u32);
|
||||||
impl TypedIndex for $ty {
|
impl TypedIndex for $ty {
|
||||||
@ -364,23 +355,23 @@ define_map_index![
|
|||||||
macro_rules! define_local_or_import {
|
macro_rules! define_local_or_import {
|
||||||
($ty:ident, $local_ty:ident, $imported_ty:ident, $imports:ident) => {
|
($ty:ident, $local_ty:ident, $imported_ty:ident, $imports:ident) => {
|
||||||
impl $ty {
|
impl $ty {
|
||||||
pub fn local_or_import(self, module: &ModuleInner) -> LocalOrImport<$ty> {
|
pub fn local_or_import(self, info: &ModuleInfo) -> LocalOrImport<$ty> {
|
||||||
if self.index() < module.info.$imports.len() {
|
if self.index() < info.$imports.len() {
|
||||||
LocalOrImport::Import(<Self as LocalImport>::Import::new(self.index()))
|
LocalOrImport::Import(<Self as LocalImport>::Import::new(self.index()))
|
||||||
} else {
|
} else {
|
||||||
LocalOrImport::Local(<Self as LocalImport>::Local::new(self.index() - module.info.$imports.len()))
|
LocalOrImport::Local(<Self as LocalImport>::Local::new(self.index() - info.$imports.len()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl $local_ty {
|
impl $local_ty {
|
||||||
pub fn convert_up(self, module: &ModuleInner) -> $ty {
|
pub fn convert_up(self, info: &ModuleInfo) -> $ty {
|
||||||
$ty ((self.index() + module.info.$imports.len()) as u32)
|
$ty ((self.index() + info.$imports.len()) as u32)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl $imported_ty {
|
impl $imported_ty {
|
||||||
pub fn convert_up(self, _module: &ModuleInner) -> $ty {
|
pub fn convert_up(self, _info: &ModuleInfo) -> $ty {
|
||||||
$ty (self.index() as u32)
|
$ty (self.index() as u32)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -400,8 +391,7 @@ define_local_or_import![
|
|||||||
(GlobalIndex | (LocalGlobalIndex, ImportedGlobalIndex): imported_globals),
|
(GlobalIndex | (LocalGlobalIndex, ImportedGlobalIndex): imported_globals),
|
||||||
];
|
];
|
||||||
|
|
||||||
#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))]
|
#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
|
||||||
pub struct SigIndex(u32);
|
pub struct SigIndex(u32);
|
||||||
impl TypedIndex for SigIndex {
|
impl TypedIndex for SigIndex {
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
|
@ -7,8 +7,7 @@ const WASM_PAGE_SIZE: usize = 65_536;
|
|||||||
const WASM_MAX_PAGES: usize = 65_536;
|
const WASM_MAX_PAGES: usize = 65_536;
|
||||||
|
|
||||||
/// Units of WebAssembly pages (as specified to be 65,536 bytes).
|
/// Units of WebAssembly pages (as specified to be 65,536 bytes).
|
||||||
#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))]
|
#[derive(Serialize, Deserialize, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
|
||||||
pub struct Pages(pub u32);
|
pub struct Pages(pub u32);
|
||||||
|
|
||||||
impl Pages {
|
impl Pages {
|
||||||
@ -33,8 +32,7 @@ impl fmt::Debug for Pages {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Units of WebAssembly memory in terms of 8-bit bytes.
|
/// Units of WebAssembly memory in terms of 8-bit bytes.
|
||||||
#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))]
|
#[derive(Serialize, Deserialize, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
|
||||||
pub struct Bytes(pub usize);
|
pub struct Bytes(pub usize);
|
||||||
|
|
||||||
impl fmt::Debug for Bytes {
|
impl fmt::Debug for Bytes {
|
||||||
|
@ -116,7 +116,7 @@ impl Ctx {
|
|||||||
pub fn memory(&self, mem_index: u32) -> &Memory {
|
pub fn memory(&self, mem_index: u32) -> &Memory {
|
||||||
let module = unsafe { &*self.module };
|
let module = unsafe { &*self.module };
|
||||||
let mem_index = MemoryIndex::new(mem_index as usize);
|
let mem_index = MemoryIndex::new(mem_index as usize);
|
||||||
match mem_index.local_or_import(module) {
|
match mem_index.local_or_import(&module.info) {
|
||||||
LocalOrImport::Local(local_mem_index) => unsafe {
|
LocalOrImport::Local(local_mem_index) => unsafe {
|
||||||
let local_backing = &*self.local_backing;
|
let local_backing = &*self.local_backing;
|
||||||
&local_backing.memories[local_mem_index]
|
&local_backing.memories[local_mem_index]
|
||||||
@ -494,7 +494,10 @@ mod vm_ctx_tests {
|
|||||||
|
|
||||||
fn generate_module() -> ModuleInner {
|
fn generate_module() -> ModuleInner {
|
||||||
use super::Func;
|
use super::Func;
|
||||||
use crate::backend::{Backend, FuncResolver, ProtectedCaller, Token, UserTrapper};
|
use crate::backend::{
|
||||||
|
sys::Memory, Backend, CacheGen, FuncResolver, ProtectedCaller, Token, UserTrapper,
|
||||||
|
};
|
||||||
|
use crate::cache::{Error as CacheError, WasmHash};
|
||||||
use crate::error::RuntimeResult;
|
use crate::error::RuntimeResult;
|
||||||
use crate::types::{FuncIndex, LocalFuncIndex, Value};
|
use crate::types::{FuncIndex, LocalFuncIndex, Value};
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
@ -525,10 +528,19 @@ mod vm_ctx_tests {
|
|||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl CacheGen for Placeholder {
|
||||||
|
fn generate_cache(
|
||||||
|
&self,
|
||||||
|
module: &ModuleInner,
|
||||||
|
) -> Result<(Box<ModuleInfo>, Box<[u8]>, Memory), CacheError> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ModuleInner {
|
ModuleInner {
|
||||||
func_resolver: Box::new(Placeholder),
|
func_resolver: Box::new(Placeholder),
|
||||||
protected_caller: Box::new(Placeholder),
|
protected_caller: Box::new(Placeholder),
|
||||||
|
cache_gen: Box::new(Placeholder),
|
||||||
info: ModuleInfo {
|
info: ModuleInfo {
|
||||||
memories: Map::new(),
|
memories: Map::new(),
|
||||||
globals: Map::new(),
|
globals: Map::new(),
|
||||||
@ -553,6 +565,8 @@ mod vm_ctx_tests {
|
|||||||
|
|
||||||
namespace_table: StringTable::new(),
|
namespace_table: StringTable::new(),
|
||||||
name_table: StringTable::new(),
|
name_table: StringTable::new(),
|
||||||
|
|
||||||
|
wasm_hash: WasmHash::generate(&[]),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,12 +9,16 @@ edition = "2018"
|
|||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
wasmer-runtime-core = { path = "../runtime-core", version = "0.1.2" }
|
|
||||||
wasmer-clif-backend = { path = "../clif-backend", version = "0.1.2", optional = true }
|
|
||||||
lazy_static = "1.2.0"
|
lazy_static = "1.2.0"
|
||||||
|
memmap = "0.7.0"
|
||||||
|
|
||||||
|
[dependencies.wasmer-runtime-core]
|
||||||
|
path = "../runtime-core"
|
||||||
|
version = "0.1.2"
|
||||||
|
|
||||||
|
[dependencies.wasmer-clif-backend]
|
||||||
|
path = "../clif-backend"
|
||||||
|
version = "0.1.2"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["default-compiler", "cache"]
|
|
||||||
default-compiler = ["wasmer-clif-backend/cache", "wasmer-runtime-core/cache"]
|
|
||||||
cache = ["default-compiler"]
|
|
||||||
debug = ["wasmer-clif-backend/debug", "wasmer-runtime-core/debug"]
|
debug = ["wasmer-clif-backend/debug", "wasmer-runtime-core/debug"]
|
||||||
|
@ -1,128 +1,109 @@
|
|||||||
use crate::Module;
|
use crate::Module;
|
||||||
use std::path::Path;
|
use memmap::Mmap;
|
||||||
use wasmer_runtime_core::cache::{hash_data, Cache as CoreCache};
|
use std::{
|
||||||
|
fs::{create_dir_all, File},
|
||||||
|
io::{self, Write},
|
||||||
|
path::PathBuf,
|
||||||
|
};
|
||||||
|
|
||||||
pub use wasmer_runtime_core::cache::Error;
|
use wasmer_runtime_core::cache::Error as CacheError;
|
||||||
|
pub use wasmer_runtime_core::cache::{Artifact, Cache, WasmHash};
|
||||||
|
|
||||||
/// On-disk storage of compiled WebAssembly.
|
/// Representation of a directory that contains compiled wasm artifacts.
|
||||||
///
|
///
|
||||||
/// A `Cache` can be used to quickly reload already
|
/// The `FileSystemCache` type implements the [`Cache`] trait, which allows it to be used
|
||||||
/// compiled WebAssembly from a previous execution
|
/// generically when some sort of cache is required.
|
||||||
/// during which the wasm was explicitly compiled
|
///
|
||||||
/// as a `Cache`.
|
/// [`Cache`]: trait.Cache.html
|
||||||
///
|
///
|
||||||
/// # Usage:
|
/// # Usage:
|
||||||
///
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use wasmer_runtime::cache::{Cache, FileSystemCache};
|
||||||
|
///
|
||||||
|
/// # use wasmer_runtime::{Module, error::CacheError};
|
||||||
|
/// fn store_and_load_module(module: Module) -> Result<Module, CacheError> {
|
||||||
|
/// // Create a new file system cache.
|
||||||
|
/// // This is unsafe because we can't ensure that the artifact wasn't
|
||||||
|
/// // corrupted or tampered with.
|
||||||
|
/// let mut fs_cache = unsafe { FileSystemCache::new("some/directory/goes/here")? };
|
||||||
|
/// // Store a module into the cache.
|
||||||
|
/// // The returned `key` is equivalent to `module.info().wasm_hash`.
|
||||||
|
/// let key = fs_cache.store(module)?;
|
||||||
|
/// // Load the module back from the cache with the `key`.
|
||||||
|
/// fs_cache.load(key)
|
||||||
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
/// use wasmer_runtime::{compile_cache, Cache};
|
pub struct FileSystemCache {
|
||||||
///
|
path: PathBuf,
|
||||||
/// # use wasmer_runtime::error::{CompileResult, CacheError};
|
}
|
||||||
/// # fn make_cache(wasm: &[u8]) -> CompileResult<()> {
|
|
||||||
/// // Make a cache.
|
|
||||||
/// let cache = compile_cache(wasm)?;
|
|
||||||
///
|
|
||||||
/// # Ok(())
|
|
||||||
/// # }
|
|
||||||
/// # fn usage_cache(cache: Cache) -> Result<(), CacheError> {
|
|
||||||
/// // Store the cache in a file.
|
|
||||||
/// cache.store("some_cache_file")?;
|
|
||||||
///
|
|
||||||
/// // Load the cache.
|
|
||||||
/// let cache = Cache::load("some_cache_file")?;
|
|
||||||
/// let module = unsafe { cache.into_module()? };
|
|
||||||
/// # Ok(())
|
|
||||||
/// # }
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// # Performance Characteristics:
|
|
||||||
///
|
|
||||||
/// Loading caches from files has been optimized for latency.
|
|
||||||
/// There is still more work to do that will reduce
|
|
||||||
/// loading time, especially for very large modules,
|
|
||||||
/// but it will require signifigant internal work.
|
|
||||||
///
|
|
||||||
/// # Drawbacks:
|
|
||||||
///
|
|
||||||
/// Due to internal shortcomings, you cannot convert
|
|
||||||
/// a module into a `Cache`. This means that compiling
|
|
||||||
/// into a `Cache` and then converting into a module
|
|
||||||
/// has more overhead than directly compiling
|
|
||||||
/// into a [`Module`].
|
|
||||||
///
|
|
||||||
/// [`Module`]: struct.Module.html
|
|
||||||
pub struct Cache(pub(crate) CoreCache);
|
|
||||||
|
|
||||||
impl Cache {
|
impl FileSystemCache {
|
||||||
/// Load a `Cache` from the file specified by `path`.
|
/// Construct a new `FileSystemCache` around the specified directory.
|
||||||
///
|
///
|
||||||
/// # Usage:
|
/// # Note:
|
||||||
///
|
/// This method is unsafe because there's no way to ensure the artifacts
|
||||||
/// ```
|
/// stored in this cache haven't been corrupted or tampered with.
|
||||||
/// use wasmer_runtime::Cache;
|
pub unsafe fn new<P: Into<PathBuf>>(path: P) -> io::Result<Self> {
|
||||||
/// # use wasmer_runtime::error::CacheError;
|
let path: PathBuf = path.into();
|
||||||
///
|
|
||||||
/// # fn load_cache() -> Result<(), CacheError> {
|
|
||||||
/// let cache = Cache::load("some_file.cache")?;
|
|
||||||
/// # Ok(())
|
|
||||||
/// # }
|
|
||||||
/// ```
|
|
||||||
pub fn load<P: AsRef<Path>>(path: P) -> Result<Self, Error> {
|
|
||||||
CoreCache::open(path).map(|core_cache| Cache(core_cache))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Convert a `Cache` into a [`Module`].
|
if path.exists() {
|
||||||
///
|
let metadata = path.metadata()?;
|
||||||
/// [`Module`]: struct.Module.html
|
if metadata.is_dir() {
|
||||||
///
|
if !metadata.permissions().readonly() {
|
||||||
/// # Usage:
|
Ok(Self { path })
|
||||||
///
|
} else {
|
||||||
/// ```
|
// This directory is readonly.
|
||||||
/// use wasmer_runtime::Cache;
|
Err(io::Error::new(
|
||||||
///
|
io::ErrorKind::PermissionDenied,
|
||||||
/// # use wasmer_runtime::error::CacheError;
|
format!("the supplied path is readonly: {}", path.display()),
|
||||||
/// # fn cache2module(cache: Cache) -> Result<(), CacheError> {
|
))
|
||||||
/// let module = unsafe { cache.into_module()? };
|
}
|
||||||
/// # Ok(())
|
} else {
|
||||||
/// # }
|
// This path points to a file.
|
||||||
/// ```
|
Err(io::Error::new(
|
||||||
///
|
io::ErrorKind::PermissionDenied,
|
||||||
/// # Notes:
|
format!(
|
||||||
///
|
"the supplied path already points to a file: {}",
|
||||||
/// This method is unsafe because the runtime cannot confirm
|
path.display()
|
||||||
/// that this cache was not tampered with or corrupted.
|
),
|
||||||
pub unsafe fn into_module(self) -> Result<Module, Error> {
|
))
|
||||||
let default_compiler = super::default_compiler();
|
}
|
||||||
|
} else {
|
||||||
wasmer_runtime_core::load_cache_with(self.0, default_compiler)
|
// Create the directory and any parent directories if they don't yet exist.
|
||||||
}
|
create_dir_all(&path)?;
|
||||||
|
Ok(Self { path })
|
||||||
/// Compare the Sha256 hash of the wasm this cache was build
|
}
|
||||||
/// from with some other WebAssembly.
|
}
|
||||||
///
|
}
|
||||||
/// The main use-case for this is invalidating old caches.
|
|
||||||
pub fn compare_wasm(&self, wasm: &[u8]) -> bool {
|
impl Cache for FileSystemCache {
|
||||||
let param_wasm_hash = hash_data(wasm);
|
type LoadError = CacheError;
|
||||||
self.0.wasm_hash() as &[u8] == ¶m_wasm_hash as &[u8]
|
type StoreError = CacheError;
|
||||||
}
|
|
||||||
|
fn load(&self, key: WasmHash) -> Result<Module, CacheError> {
|
||||||
/// Store this cache in a file.
|
let filename = key.encode();
|
||||||
///
|
let mut new_path_buf = self.path.clone();
|
||||||
/// # Notes:
|
new_path_buf.push(filename);
|
||||||
///
|
let file = File::open(new_path_buf)?;
|
||||||
/// If a file exists at the specified path, it will be overwritten.
|
let mmap = unsafe { Mmap::map(&file)? };
|
||||||
///
|
|
||||||
/// # Usage:
|
let serialized_cache = Artifact::deserialize(&mmap[..])?;
|
||||||
///
|
unsafe { wasmer_runtime_core::load_cache_with(serialized_cache, super::default_compiler()) }
|
||||||
/// ```
|
}
|
||||||
/// use wasmer_runtime::Cache;
|
|
||||||
///
|
fn store(&mut self, module: Module) -> Result<WasmHash, CacheError> {
|
||||||
/// # use wasmer_runtime::error::CacheError;
|
let key = module.info().wasm_hash;
|
||||||
/// # fn store_cache(cache: Cache) -> Result<(), CacheError> {
|
let filename = key.encode();
|
||||||
/// cache.store("some_file.cache")?;
|
let mut new_path_buf = self.path.clone();
|
||||||
/// # Ok(())
|
new_path_buf.push(filename);
|
||||||
/// # }
|
|
||||||
/// ```
|
let serialized_cache = module.cache()?;
|
||||||
pub fn store<P: AsRef<Path>>(&self, path: P) -> Result<(), Error> {
|
let buffer = serialized_cache.serialize()?;
|
||||||
self.0.store(path)
|
|
||||||
|
let mut file = File::create(new_path_buf)?;
|
||||||
|
file.write_all(&buffer)?;
|
||||||
|
|
||||||
|
Ok(key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -99,8 +99,7 @@ pub mod wasm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub mod error {
|
pub mod error {
|
||||||
#[cfg(feature = "cache")]
|
pub use wasmer_runtime_core::cache::Error as CacheError;
|
||||||
pub use super::cache::Error as CacheError;
|
|
||||||
pub use wasmer_runtime_core::error::*;
|
pub use wasmer_runtime_core::error::*;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,15 +108,10 @@ pub mod units {
|
|||||||
pub use wasmer_runtime_core::units::{Bytes, Pages};
|
pub use wasmer_runtime_core::units::{Bytes, Pages};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "cache")]
|
pub mod cache;
|
||||||
mod cache;
|
|
||||||
|
|
||||||
#[cfg(feature = "default-compiler")]
|
|
||||||
use wasmer_runtime_core::backend::Compiler;
|
use wasmer_runtime_core::backend::Compiler;
|
||||||
|
|
||||||
#[cfg(feature = "cache")]
|
|
||||||
pub use self::cache::Cache;
|
|
||||||
|
|
||||||
/// Compile WebAssembly binary code into a [`Module`].
|
/// Compile WebAssembly binary code into a [`Module`].
|
||||||
/// This function is useful if it is necessary to
|
/// This function is useful if it is necessary to
|
||||||
/// compile a module before it can be instantiated
|
/// compile a module before it can be instantiated
|
||||||
@ -131,7 +125,6 @@ pub use self::cache::Cache;
|
|||||||
/// binary code of the wasm module you want to compile.
|
/// binary code of the wasm module you want to compile.
|
||||||
/// # Errors:
|
/// # Errors:
|
||||||
/// If the operation fails, the function returns `Err(error::CompileError::...)`.
|
/// If the operation fails, the function returns `Err(error::CompileError::...)`.
|
||||||
#[cfg(feature = "default-compiler")]
|
|
||||||
pub fn compile(wasm: &[u8]) -> error::CompileResult<Module> {
|
pub fn compile(wasm: &[u8]) -> error::CompileResult<Module> {
|
||||||
wasmer_runtime_core::compile_with(&wasm[..], default_compiler())
|
wasmer_runtime_core::compile_with(&wasm[..], default_compiler())
|
||||||
}
|
}
|
||||||
@ -154,38 +147,11 @@ pub fn compile(wasm: &[u8]) -> error::CompileResult<Module> {
|
|||||||
/// `error::CompileError`, `error::LinkError`, or
|
/// `error::CompileError`, `error::LinkError`, or
|
||||||
/// `error::RuntimeError` (all combined into an `error::Error`),
|
/// `error::RuntimeError` (all combined into an `error::Error`),
|
||||||
/// depending on the cause of the failure.
|
/// depending on the cause of the failure.
|
||||||
#[cfg(feature = "default-compiler")]
|
|
||||||
pub fn instantiate(wasm: &[u8], import_object: &ImportObject) -> error::Result<Instance> {
|
pub fn instantiate(wasm: &[u8], import_object: &ImportObject) -> error::Result<Instance> {
|
||||||
let module = compile(wasm)?;
|
let module = compile(wasm)?;
|
||||||
module.instantiate(import_object)
|
module.instantiate(import_object)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Compile wasm into a [`Cache`] that can be stored to a file or
|
|
||||||
/// converted into [`Module`].
|
|
||||||
///
|
|
||||||
/// [`Cache`]: struct.Cache.html
|
|
||||||
/// [`Module`]: struct.Module.html
|
|
||||||
///
|
|
||||||
/// # Usage:
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # use wasmer_runtime::error::CompileResult;
|
|
||||||
/// use wasmer_runtime::compile_cache;
|
|
||||||
///
|
|
||||||
/// # fn make_cache(wasm: &[u8]) -> CompileResult<()> {
|
|
||||||
/// let cache = compile_cache(wasm)?;
|
|
||||||
/// # Ok(())
|
|
||||||
/// # }
|
|
||||||
/// ```
|
|
||||||
#[cfg(feature = "cache")]
|
|
||||||
pub fn compile_cache(wasm: &[u8]) -> error::CompileResult<Cache> {
|
|
||||||
let default_compiler = default_compiler();
|
|
||||||
|
|
||||||
wasmer_runtime_core::compile_to_cache_with(wasm, default_compiler)
|
|
||||||
.map(|core_cache| Cache(core_cache))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "default-compiler")]
|
|
||||||
fn default_compiler() -> &'static dyn Compiler {
|
fn default_compiler() -> &'static dyn Compiler {
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use wasmer_clif_backend::CraneliftCompiler;
|
use wasmer_clif_backend::CraneliftCompiler;
|
||||||
|
@ -19,5 +19,5 @@ wasmer-clif-backend = { path = "../clif-backend", version = "0.1.2" }
|
|||||||
wabt = "0.7.2"
|
wabt = "0.7.2"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["fast-tests", "wasmer-runtime-core/cache", "wasmer-clif-backend/cache"]
|
default = ["fast-tests"]
|
||||||
fast-tests = []
|
fast-tests = []
|
Loading…
x
Reference in New Issue
Block a user