mirror of
https://github.com/fluencelabs/wasmer
synced 2024-12-14 06:35:40 +00:00
Merge branch 'master' into feature/more-wasi-syscalls
This commit is contained in:
commit
09acf3e581
@ -5,6 +5,7 @@ All PRs to the Wasmer repository must add to this file.
|
|||||||
Blocks of changes will separated by version increments.
|
Blocks of changes will separated by version increments.
|
||||||
|
|
||||||
## **[Unreleased]**
|
## **[Unreleased]**
|
||||||
|
- [#609](https://github.com/wasmerio/wasmer/issues/609) Update dependencies
|
||||||
|
|
||||||
## 0.6.0 - 2019-07-31
|
## 0.6.0 - 2019-07-31
|
||||||
- [#603](https://github.com/wasmerio/wasmer/pull/603) Update Wapm-cli, bump version numbers
|
- [#603](https://github.com/wasmerio/wasmer/pull/603) Update Wapm-cli, bump version numbers
|
||||||
|
578
Cargo.lock
generated
578
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -19,11 +19,10 @@ include = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
byteorder = "1.3.1"
|
byteorder = "1.3.2"
|
||||||
errno = "0.2.4"
|
errno = "0.2.4"
|
||||||
structopt = "0.2.11"
|
structopt = "0.2.18"
|
||||||
wabt = "0.9.0"
|
wabt = "0.9.0"
|
||||||
hashbrown = "0.1.8"
|
|
||||||
wasmer-clif-backend = { path = "lib/clif-backend" }
|
wasmer-clif-backend = { path = "lib/clif-backend" }
|
||||||
wasmer-singlepass-backend = { path = "lib/singlepass-backend", optional = true }
|
wasmer-singlepass-backend = { path = "lib/singlepass-backend", optional = true }
|
||||||
wasmer-middleware-common = { path = "lib/middleware-common" }
|
wasmer-middleware-common = { path = "lib/middleware-common" }
|
||||||
@ -62,7 +61,7 @@ members = [
|
|||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
wabt = "0.9.0"
|
wabt = "0.9.0"
|
||||||
glob = "0.2.11"
|
glob = "0.3.0"
|
||||||
rustc_version = "0.2.3"
|
rustc_version = "0.2.3"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
|
2
Makefile
2
Makefile
@ -84,7 +84,7 @@ singlepass: spectests-singlepass emtests-singlepass middleware-singlepass wasite
|
|||||||
cranelift: spectests-cranelift emtests-cranelift middleware-cranelift wasitests-cranelift
|
cranelift: spectests-cranelift emtests-cranelift middleware-cranelift wasitests-cranelift
|
||||||
cargo test -p wasmer-clif-backend --release
|
cargo test -p wasmer-clif-backend --release
|
||||||
|
|
||||||
llvm: spectests-llvm emtests-llvm middleware-llvm wasitests-llvm
|
llvm: spectests-llvm emtests-llvm wasitests-llvm
|
||||||
cargo test -p wasmer-llvm-backend --release
|
cargo test -p wasmer-llvm-backend --release
|
||||||
|
|
||||||
|
|
||||||
|
@ -15,26 +15,26 @@ cranelift-codegen = { version = "0.31" }
|
|||||||
cranelift-entity = { version = "0.31" }
|
cranelift-entity = { version = "0.31" }
|
||||||
cranelift-frontend = { package = "wasmer-clif-fork-frontend", version = "0.33" }
|
cranelift-frontend = { package = "wasmer-clif-fork-frontend", version = "0.33" }
|
||||||
cranelift-wasm = { package = "wasmer-clif-fork-wasm", version = "0.33" }
|
cranelift-wasm = { package = "wasmer-clif-fork-wasm", version = "0.33" }
|
||||||
hashbrown = "0.1"
|
|
||||||
target-lexicon = "0.4.0"
|
target-lexicon = "0.4.0"
|
||||||
wasmparser = "0.35.1"
|
wasmparser = "0.35.1"
|
||||||
byteorder = "1"
|
byteorder = "1.3.2"
|
||||||
nix = "0.14.0"
|
nix = "0.14.1"
|
||||||
libc = "0.2.49"
|
libc = "0.2.60"
|
||||||
rayon = "1.0"
|
rayon = "1.1.0"
|
||||||
|
|
||||||
# Dependencies for caching.
|
# Dependencies for caching.
|
||||||
[dependencies.serde]
|
[dependencies.serde]
|
||||||
version = "1.0"
|
version = "1.0.98"
|
||||||
|
features = ["rc"]
|
||||||
[dependencies.serde_derive]
|
[dependencies.serde_derive]
|
||||||
version = "1.0"
|
version = "1.0.98"
|
||||||
[dependencies.serde_bytes]
|
[dependencies.serde_bytes]
|
||||||
version = "0.10"
|
version = "0.11.1"
|
||||||
[dependencies.serde-bench]
|
[dependencies.serde-bench]
|
||||||
version = "0.0.7"
|
version = "0.0.7"
|
||||||
|
|
||||||
[target.'cfg(windows)'.dependencies]
|
[target.'cfg(windows)'.dependencies]
|
||||||
winapi = { version = "0.3", features = ["errhandlingapi", "minwindef", "minwinbase", "winnt"] }
|
winapi = { version = "0.3.7", features = ["errhandlingapi", "minwindef", "minwinbase", "winnt"] }
|
||||||
wasmer-win-exception-handler = { path = "../win-exception-handler", version = "0.6.0" }
|
wasmer-win-exception-handler = { path = "../win-exception-handler", version = "0.6.0" }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use crate::relocation::{ExternalRelocation, TrapSink};
|
use crate::relocation::{ExternalRelocation, TrapSink};
|
||||||
|
|
||||||
use hashbrown::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use wasmer_runtime_core::{
|
use wasmer_runtime_core::{
|
||||||
backend::{sys::Memory, CacheGen},
|
backend::{sys::Memory, CacheGen},
|
||||||
|
@ -89,10 +89,12 @@ impl ModuleCodeGenerator<CraneliftFunctionCodeGenerator, Caller, CodegenError>
|
|||||||
func,
|
func,
|
||||||
func_translator,
|
func_translator,
|
||||||
next_local: 0,
|
next_local: 0,
|
||||||
clif_signatures: self.clif_signatures.clone(),
|
|
||||||
module_info: Arc::clone(&module_info),
|
|
||||||
target_config: self.isa.frontend_config().clone(),
|
|
||||||
position: Position::default(),
|
position: Position::default(),
|
||||||
|
func_env: FunctionEnvironment {
|
||||||
|
module_info: Arc::clone(&module_info),
|
||||||
|
target_config: self.isa.frontend_config().clone(),
|
||||||
|
clif_signatures: self.clif_signatures.clone(),
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
debug_assert_eq!(func_env.func.dfg.num_ebbs(), 0, "Function must be empty");
|
debug_assert_eq!(func_env.func.dfg.num_ebbs(), 0, "Function must be empty");
|
||||||
@ -391,10 +393,8 @@ pub struct CraneliftFunctionCodeGenerator {
|
|||||||
func: Function,
|
func: Function,
|
||||||
func_translator: FuncTranslator,
|
func_translator: FuncTranslator,
|
||||||
next_local: usize,
|
next_local: usize,
|
||||||
pub clif_signatures: Map<SigIndex, ir::Signature>,
|
|
||||||
module_info: Arc<RwLock<ModuleInfo>>,
|
|
||||||
target_config: isa::TargetFrontendConfig,
|
|
||||||
position: Position,
|
position: Position,
|
||||||
|
func_env: FunctionEnvironment,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct FunctionEnvironment {
|
pub struct FunctionEnvironment {
|
||||||
@ -1138,11 +1138,6 @@ impl FunctionCodeGenerator<CodegenError> for CraneliftFunctionCodeGenerator {
|
|||||||
//let builder = self.builder.as_mut().unwrap();
|
//let builder = self.builder.as_mut().unwrap();
|
||||||
//let func_environment = FuncEnv::new();
|
//let func_environment = FuncEnv::new();
|
||||||
//let state = TranslationState::new();
|
//let state = TranslationState::new();
|
||||||
let mut function_environment = FunctionEnvironment {
|
|
||||||
module_info: Arc::clone(&self.module_info),
|
|
||||||
target_config: self.target_config.clone(),
|
|
||||||
clif_signatures: self.clif_signatures.clone(),
|
|
||||||
};
|
|
||||||
|
|
||||||
if self.func_translator.state.control_stack.is_empty() {
|
if self.func_translator.state.control_stack.is_empty() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
@ -1154,7 +1149,7 @@ impl FunctionCodeGenerator<CodegenError> for CraneliftFunctionCodeGenerator {
|
|||||||
&mut self.position,
|
&mut self.position,
|
||||||
);
|
);
|
||||||
let state = &mut self.func_translator.state;
|
let state = &mut self.func_translator.state;
|
||||||
translate_operator(op, &mut builder, state, &mut function_environment)?;
|
translate_operator(op, &mut builder, state, &mut self.func_env)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,10 @@
|
|||||||
#![deny(unused_imports, unused_variables, unused_unsafe, unreachable_patterns)]
|
#![deny(
|
||||||
|
dead_code,
|
||||||
|
unused_imports,
|
||||||
|
unused_variables,
|
||||||
|
unused_unsafe,
|
||||||
|
unreachable_patterns
|
||||||
|
)]
|
||||||
mod cache;
|
mod cache;
|
||||||
mod code;
|
mod code;
|
||||||
mod libcalls;
|
mod libcalls;
|
||||||
|
@ -5,7 +5,7 @@ use cranelift_codegen::{
|
|||||||
ir::{self, InstBuilder},
|
ir::{self, InstBuilder},
|
||||||
isa, Context,
|
isa, Context,
|
||||||
};
|
};
|
||||||
use hashbrown::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::{iter, mem, ptr::NonNull};
|
use std::{iter, mem, ptr::NonNull};
|
||||||
use wasmer_runtime_core::{
|
use wasmer_runtime_core::{
|
||||||
backend::sys::{Memory, Protect},
|
backend::sys::{Memory, Protect},
|
||||||
|
@ -8,4 +8,4 @@ edition = "2018"
|
|||||||
repository = "https://github.com/wasmerio/wasmer"
|
repository = "https://github.com/wasmerio/wasmer"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
libc = "0.2.49"
|
libc = "0.2.60"
|
||||||
|
@ -20,7 +20,7 @@ wabt = "0.9.0"
|
|||||||
wasmer-dev-utils = { path = "../dev-utils", version = "0.6.0"}
|
wasmer-dev-utils = { path = "../dev-utils", version = "0.6.0"}
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
glob = "0.2.11"
|
glob = "0.3.0"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
clif = []
|
clif = []
|
||||||
|
@ -8,15 +8,14 @@ repository = "https://github.com/wasmerio/wasmer"
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
byteorder = "1"
|
byteorder = "1.3.2"
|
||||||
hashbrown = "0.1"
|
lazy_static = "1.3.0"
|
||||||
lazy_static = "1.2.0"
|
libc = "0.2.60"
|
||||||
libc = "0.2.49"
|
time = "0.1.42"
|
||||||
time = "0.1.41"
|
|
||||||
wasmer-runtime-core = { path = "../runtime-core", version = "0.6.0" }
|
wasmer-runtime-core = { path = "../runtime-core", version = "0.6.0" }
|
||||||
|
|
||||||
[target.'cfg(windows)'.dependencies]
|
[target.'cfg(windows)'.dependencies]
|
||||||
rand = "0.6"
|
rand = "0.7.0"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
debug = ["wasmer-runtime-core/debug"]
|
debug = ["wasmer-runtime-core/debug"]
|
||||||
|
1
lib/emscripten/src/env/mod.rs
vendored
1
lib/emscripten/src/env/mod.rs
vendored
@ -30,6 +30,7 @@ pub fn call_malloc(ctx: &mut Ctx, size: u32) -> u32 {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[warn(dead_code)]
|
||||||
pub fn call_malloc_with_cast<T: Copy, Ty>(ctx: &mut Ctx, size: u32) -> WasmPtr<T, Ty> {
|
pub fn call_malloc_with_cast<T: Copy, Ty>(ctx: &mut Ctx, size: u32) -> WasmPtr<T, Ty> {
|
||||||
WasmPtr::new(call_malloc(ctx, size))
|
WasmPtr::new(call_malloc(ctx, size))
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,16 @@
|
|||||||
#![deny(unused_imports, unused_variables, unused_unsafe, unreachable_patterns)]
|
#![deny(
|
||||||
|
dead_code,
|
||||||
|
unused_imports,
|
||||||
|
unused_variables,
|
||||||
|
unused_unsafe,
|
||||||
|
unreachable_patterns
|
||||||
|
)]
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate wasmer_runtime_core;
|
extern crate wasmer_runtime_core;
|
||||||
|
|
||||||
use hashbrown::HashMap;
|
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use std::cell::UnsafeCell;
|
use std::cell::UnsafeCell;
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::{f64, ffi::c_void};
|
use std::{f64, ffi::c_void};
|
||||||
use wasmer_runtime_core::{
|
use wasmer_runtime_core::{
|
||||||
@ -25,11 +30,11 @@ use wasmer_runtime_core::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
use ::libc::DIR as libcDIR;
|
use ::libc::DIR as LibcDir;
|
||||||
|
|
||||||
// We use a placeholder for windows
|
// We use a placeholder for windows
|
||||||
#[cfg(not(unix))]
|
#[cfg(not(unix))]
|
||||||
type libcDIR = u8;
|
type LibcDir = u8;
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod macros;
|
mod macros;
|
||||||
@ -93,7 +98,7 @@ pub struct EmscriptenData<'a> {
|
|||||||
pub memset: Option<Func<'a, (u32, u32, u32), u32>>,
|
pub memset: Option<Func<'a, (u32, u32, u32), u32>>,
|
||||||
pub stack_alloc: Option<Func<'a, u32, u32>>,
|
pub stack_alloc: Option<Func<'a, u32, u32>>,
|
||||||
pub jumps: Vec<UnsafeCell<[u32; 27]>>,
|
pub jumps: Vec<UnsafeCell<[u32; 27]>>,
|
||||||
pub opened_dirs: HashMap<i32, Box<*mut libcDIR>>,
|
pub opened_dirs: HashMap<i32, Box<*mut LibcDir>>,
|
||||||
|
|
||||||
pub dyn_call_i: Option<Func<'a, i32, i32>>,
|
pub dyn_call_i: Option<Func<'a, i32, i32>>,
|
||||||
pub dyn_call_ii: Option<Func<'a, (i32, i32), i32>>,
|
pub dyn_call_ii: Option<Func<'a, (i32, i32), i32>>,
|
||||||
|
@ -5,5 +5,5 @@ authors = ["Heyang Zhou <zhy20000919@hotmail.com>"]
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
libc = "0.2.49"
|
libc = "0.2.60"
|
||||||
wasmer-runtime-core = { path = "../runtime-core" }
|
wasmer-runtime-core = { path = "../runtime-core" }
|
||||||
|
@ -8,12 +8,11 @@ readme = "README.md"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
wasmer-runtime-core = { path = "../runtime-core", version = "0.6.0" }
|
wasmer-runtime-core = { path = "../runtime-core", version = "0.6.0" }
|
||||||
wasmparser = "0.35.1"
|
wasmparser = "0.35.1"
|
||||||
hashbrown = "0.1.8"
|
smallvec = "0.6.10"
|
||||||
smallvec = "0.6.8"
|
goblin = "0.0.24"
|
||||||
goblin = "0.0.20"
|
libc = "0.2.60"
|
||||||
libc = "0.2.49"
|
nix = "0.14.1"
|
||||||
nix = "0.14.0"
|
capstone = { version = "0.6.0", optional = true }
|
||||||
capstone = { version = "0.5.0", optional = true }
|
|
||||||
|
|
||||||
[dependencies.inkwell]
|
[dependencies.inkwell]
|
||||||
git = "https://github.com/wasmerio/inkwell"
|
git = "https://github.com/wasmerio/inkwell"
|
||||||
@ -22,12 +21,12 @@ default-features = false
|
|||||||
features = ["llvm8-0", "target-x86"]
|
features = ["llvm8-0", "target-x86"]
|
||||||
|
|
||||||
[target.'cfg(windows)'.dependencies]
|
[target.'cfg(windows)'.dependencies]
|
||||||
winapi = { version = "0.3", features = ["memoryapi"] }
|
winapi = { version = "0.3.7", features = ["memoryapi"] }
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
cc = "1.0"
|
cc = "1.0"
|
||||||
lazy_static = "1.2.0"
|
lazy_static = "1.3.0"
|
||||||
regex = "1.1.0"
|
regex = "1.2.0"
|
||||||
semver = "0.9"
|
semver = "0.9"
|
||||||
rustc_version = "0.2.3"
|
rustc_version = "0.2.3"
|
||||||
|
|
||||||
|
@ -7,201 +7,214 @@ extern "C" void __deregister_frame(uint8_t *);
|
|||||||
|
|
||||||
struct MemoryManager : llvm::RuntimeDyld::MemoryManager {
|
struct MemoryManager : llvm::RuntimeDyld::MemoryManager {
|
||||||
public:
|
public:
|
||||||
MemoryManager(callbacks_t callbacks) : callbacks(callbacks) {}
|
MemoryManager(callbacks_t callbacks) : callbacks(callbacks) {}
|
||||||
|
|
||||||
virtual ~MemoryManager() override {
|
virtual ~MemoryManager() override {
|
||||||
deregisterEHFrames();
|
deregisterEHFrames();
|
||||||
// Deallocate all of the allocated memory.
|
// Deallocate all of the allocated memory.
|
||||||
callbacks.dealloc_memory(code_section.base, code_section.size);
|
callbacks.dealloc_memory(code_section.base, code_section.size);
|
||||||
callbacks.dealloc_memory(read_section.base, read_section.size);
|
callbacks.dealloc_memory(read_section.base, read_section.size);
|
||||||
callbacks.dealloc_memory(readwrite_section.base, readwrite_section.size);
|
callbacks.dealloc_memory(readwrite_section.base, readwrite_section.size);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual uint8_t *allocateCodeSection(uintptr_t size, unsigned alignment,
|
||||||
|
unsigned section_id,
|
||||||
|
llvm::StringRef section_name) override {
|
||||||
|
return allocate_bump(code_section, code_bump_ptr, size, alignment);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual uint8_t *allocateDataSection(uintptr_t size, unsigned alignment,
|
||||||
|
unsigned section_id,
|
||||||
|
llvm::StringRef section_name,
|
||||||
|
bool read_only) override {
|
||||||
|
// Allocate from the read-only section or the read-write section, depending
|
||||||
|
// on if this allocation should be read-only or not.
|
||||||
|
if (read_only) {
|
||||||
|
return allocate_bump(read_section, read_bump_ptr, size, alignment);
|
||||||
|
} else {
|
||||||
|
return allocate_bump(readwrite_section, readwrite_bump_ptr, size,
|
||||||
|
alignment);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
virtual uint8_t* allocateCodeSection(uintptr_t size, unsigned alignment, unsigned section_id, llvm::StringRef section_name) override {
|
virtual void reserveAllocationSpace(uintptr_t code_size, uint32_t code_align,
|
||||||
return allocate_bump(code_section, code_bump_ptr, size, alignment);
|
uintptr_t read_data_size,
|
||||||
}
|
uint32_t read_data_align,
|
||||||
|
uintptr_t read_write_data_size,
|
||||||
virtual uint8_t* allocateDataSection(uintptr_t size, unsigned alignment, unsigned section_id, llvm::StringRef section_name, bool read_only) override {
|
uint32_t read_write_data_align) override {
|
||||||
// Allocate from the read-only section or the read-write section, depending on if this allocation
|
auto aligner = [](uintptr_t ptr, size_t align) {
|
||||||
// should be read-only or not.
|
if (ptr == 0) {
|
||||||
if (read_only) {
|
return align;
|
||||||
return allocate_bump(read_section, read_bump_ptr, size, alignment);
|
}
|
||||||
} else {
|
return (ptr + align - 1) & ~(align - 1);
|
||||||
return allocate_bump(readwrite_section, readwrite_bump_ptr, size, alignment);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void reserveAllocationSpace(
|
|
||||||
uintptr_t code_size,
|
|
||||||
uint32_t code_align,
|
|
||||||
uintptr_t read_data_size,
|
|
||||||
uint32_t read_data_align,
|
|
||||||
uintptr_t read_write_data_size,
|
|
||||||
uint32_t read_write_data_align
|
|
||||||
) override {
|
|
||||||
auto aligner = [](uintptr_t ptr, size_t align) {
|
|
||||||
if (ptr == 0) {
|
|
||||||
return align;
|
|
||||||
}
|
|
||||||
return (ptr + align - 1) & ~(align - 1);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
uint8_t *code_ptr_out = nullptr;
|
|
||||||
size_t code_size_out = 0;
|
|
||||||
auto code_result = callbacks.alloc_memory(aligner(code_size, 4096), PROTECT_READ_WRITE, &code_ptr_out, &code_size_out);
|
|
||||||
assert(code_result == RESULT_OK);
|
|
||||||
code_section = Section { code_ptr_out, code_size_out };
|
|
||||||
code_bump_ptr = (uintptr_t)code_ptr_out;
|
|
||||||
|
|
||||||
uint8_t *read_ptr_out = nullptr;
|
|
||||||
size_t read_size_out = 0;
|
|
||||||
auto read_result = callbacks.alloc_memory(aligner(read_data_size, 4096), PROTECT_READ_WRITE, &read_ptr_out, &read_size_out);
|
|
||||||
assert(read_result == RESULT_OK);
|
|
||||||
read_section = Section { read_ptr_out, read_size_out };
|
|
||||||
read_bump_ptr = (uintptr_t)read_ptr_out;
|
|
||||||
|
|
||||||
uint8_t *readwrite_ptr_out = nullptr;
|
|
||||||
size_t readwrite_size_out = 0;
|
|
||||||
auto readwrite_result = callbacks.alloc_memory(aligner(read_write_data_size, 4096), PROTECT_READ_WRITE, &readwrite_ptr_out, &readwrite_size_out);
|
|
||||||
assert(readwrite_result == RESULT_OK);
|
|
||||||
readwrite_section = Section { readwrite_ptr_out, readwrite_size_out };
|
|
||||||
readwrite_bump_ptr = (uintptr_t)readwrite_ptr_out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Turn on the `reserveAllocationSpace` callback. */
|
|
||||||
virtual bool needsToReserveAllocationSpace() override {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void registerEHFrames(uint8_t* addr, uint64_t LoadAddr, size_t size) override {
|
|
||||||
// We don't know yet how to do this on Windows, so we hide this on compilation
|
|
||||||
// so we can compile and pass spectests on unix systems
|
|
||||||
#ifndef _WIN32
|
|
||||||
eh_frame_ptr = addr;
|
|
||||||
eh_frame_size = size;
|
|
||||||
eh_frames_registered = true;
|
|
||||||
callbacks.visit_fde(addr, size, __register_frame);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void deregisterEHFrames() override {
|
|
||||||
// We don't know yet how to do this on Windows, so we hide this on compilation
|
|
||||||
// so we can compile and pass spectests on unix systems
|
|
||||||
#ifndef _WIN32
|
|
||||||
if (eh_frames_registered) {
|
|
||||||
callbacks.visit_fde(eh_frame_ptr, eh_frame_size, __deregister_frame);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual bool finalizeMemory(std::string *ErrMsg = nullptr) override {
|
|
||||||
auto code_result = callbacks.protect_memory(code_section.base, code_section.size, mem_protect_t::PROTECT_READ_EXECUTE);
|
|
||||||
if (code_result != RESULT_OK) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto read_result = callbacks.protect_memory(read_section.base, read_section.size, mem_protect_t::PROTECT_READ);
|
|
||||||
if (read_result != RESULT_OK) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The readwrite section is already mapped as read-write.
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void notifyObjectLoaded(llvm::RuntimeDyld &RTDyld, const llvm::object::ObjectFile &Obj) override {}
|
|
||||||
private:
|
|
||||||
struct Section {
|
|
||||||
uint8_t* base;
|
|
||||||
size_t size;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
uint8_t* allocate_bump(Section& section, uintptr_t& bump_ptr, size_t size, size_t align) {
|
uint8_t *code_ptr_out = nullptr;
|
||||||
auto aligner = [](uintptr_t& ptr, size_t align) {
|
size_t code_size_out = 0;
|
||||||
ptr = (ptr + align - 1) & ~(align - 1);
|
auto code_result =
|
||||||
};
|
callbacks.alloc_memory(aligner(code_size, 4096), PROTECT_READ_WRITE,
|
||||||
|
&code_ptr_out, &code_size_out);
|
||||||
|
assert(code_result == RESULT_OK);
|
||||||
|
code_section = Section{code_ptr_out, code_size_out};
|
||||||
|
code_bump_ptr = (uintptr_t)code_ptr_out;
|
||||||
|
|
||||||
// Align the bump pointer to the requires alignment.
|
uint8_t *read_ptr_out = nullptr;
|
||||||
aligner(bump_ptr, align);
|
size_t read_size_out = 0;
|
||||||
|
auto read_result = callbacks.alloc_memory(aligner(read_data_size, 4096),
|
||||||
|
PROTECT_READ_WRITE, &read_ptr_out,
|
||||||
|
&read_size_out);
|
||||||
|
assert(read_result == RESULT_OK);
|
||||||
|
read_section = Section{read_ptr_out, read_size_out};
|
||||||
|
read_bump_ptr = (uintptr_t)read_ptr_out;
|
||||||
|
|
||||||
auto ret_ptr = bump_ptr;
|
uint8_t *readwrite_ptr_out = nullptr;
|
||||||
bump_ptr += size;
|
size_t readwrite_size_out = 0;
|
||||||
|
auto readwrite_result = callbacks.alloc_memory(
|
||||||
|
aligner(read_write_data_size, 4096), PROTECT_READ_WRITE,
|
||||||
|
&readwrite_ptr_out, &readwrite_size_out);
|
||||||
|
assert(readwrite_result == RESULT_OK);
|
||||||
|
readwrite_section = Section{readwrite_ptr_out, readwrite_size_out};
|
||||||
|
readwrite_bump_ptr = (uintptr_t)readwrite_ptr_out;
|
||||||
|
}
|
||||||
|
|
||||||
assert(bump_ptr <= (uintptr_t)section.base + section.size);
|
/* Turn on the `reserveAllocationSpace` callback. */
|
||||||
|
virtual bool needsToReserveAllocationSpace() override { return true; }
|
||||||
|
|
||||||
return (uint8_t*)ret_ptr;
|
virtual void registerEHFrames(uint8_t *addr, uint64_t LoadAddr,
|
||||||
|
size_t size) override {
|
||||||
|
// We don't know yet how to do this on Windows, so we hide this on compilation
|
||||||
|
// so we can compile and pass spectests on unix systems
|
||||||
|
#ifndef _WIN32
|
||||||
|
eh_frame_ptr = addr;
|
||||||
|
eh_frame_size = size;
|
||||||
|
eh_frames_registered = true;
|
||||||
|
callbacks.visit_fde(addr, size, __register_frame);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void deregisterEHFrames() override {
|
||||||
|
// We don't know yet how to do this on Windows, so we hide this on compilation
|
||||||
|
// so we can compile and pass spectests on unix systems
|
||||||
|
#ifndef _WIN32
|
||||||
|
if (eh_frames_registered) {
|
||||||
|
callbacks.visit_fde(eh_frame_ptr, eh_frame_size, __deregister_frame);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool finalizeMemory(std::string *ErrMsg = nullptr) override {
|
||||||
|
auto code_result =
|
||||||
|
callbacks.protect_memory(code_section.base, code_section.size,
|
||||||
|
mem_protect_t::PROTECT_READ_EXECUTE);
|
||||||
|
if (code_result != RESULT_OK) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Section code_section, read_section, readwrite_section;
|
auto read_result = callbacks.protect_memory(
|
||||||
uintptr_t code_bump_ptr, read_bump_ptr, readwrite_bump_ptr;
|
read_section.base, read_section.size, mem_protect_t::PROTECT_READ);
|
||||||
uint8_t* eh_frame_ptr;
|
if (read_result != RESULT_OK) {
|
||||||
size_t eh_frame_size;
|
return false;
|
||||||
bool eh_frames_registered = false;
|
}
|
||||||
|
|
||||||
callbacks_t callbacks;
|
// The readwrite section is already mapped as read-write.
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void
|
||||||
|
notifyObjectLoaded(llvm::RuntimeDyld &RTDyld,
|
||||||
|
const llvm::object::ObjectFile &Obj) override {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct Section {
|
||||||
|
uint8_t *base;
|
||||||
|
size_t size;
|
||||||
|
};
|
||||||
|
|
||||||
|
uint8_t *allocate_bump(Section §ion, uintptr_t &bump_ptr, size_t size,
|
||||||
|
size_t align) {
|
||||||
|
auto aligner = [](uintptr_t &ptr, size_t align) {
|
||||||
|
ptr = (ptr + align - 1) & ~(align - 1);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Align the bump pointer to the requires alignment.
|
||||||
|
aligner(bump_ptr, align);
|
||||||
|
|
||||||
|
auto ret_ptr = bump_ptr;
|
||||||
|
bump_ptr += size;
|
||||||
|
|
||||||
|
assert(bump_ptr <= (uintptr_t)section.base + section.size);
|
||||||
|
|
||||||
|
return (uint8_t *)ret_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Section code_section, read_section, readwrite_section;
|
||||||
|
uintptr_t code_bump_ptr, read_bump_ptr, readwrite_bump_ptr;
|
||||||
|
uint8_t *eh_frame_ptr;
|
||||||
|
size_t eh_frame_size;
|
||||||
|
bool eh_frames_registered = false;
|
||||||
|
|
||||||
|
callbacks_t callbacks;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SymbolLookup : llvm::JITSymbolResolver {
|
struct SymbolLookup : llvm::JITSymbolResolver {
|
||||||
public:
|
public:
|
||||||
SymbolLookup(callbacks_t callbacks) : callbacks(callbacks) {}
|
SymbolLookup(callbacks_t callbacks) : callbacks(callbacks) {}
|
||||||
|
|
||||||
void lookup(const LookupSet& symbols, OnResolvedFunction OnResolved) {
|
void lookup(const LookupSet &symbols, OnResolvedFunction OnResolved) {
|
||||||
LookupResult result;
|
LookupResult result;
|
||||||
|
|
||||||
for (auto symbol : symbols) {
|
for (auto symbol : symbols) {
|
||||||
result.emplace(symbol, symbol_lookup(symbol));
|
result.emplace(symbol, symbol_lookup(symbol));
|
||||||
}
|
|
||||||
|
|
||||||
OnResolved(result);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
llvm::Expected<LookupSet> getResponsibilitySet(const LookupSet &Symbols) {
|
OnResolved(result);
|
||||||
const std::set<llvm::StringRef> empty;
|
}
|
||||||
return empty;
|
|
||||||
}
|
llvm::Expected<LookupSet> getResponsibilitySet(const LookupSet &Symbols) {
|
||||||
|
const std::set<llvm::StringRef> empty;
|
||||||
|
return empty;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
llvm::JITEvaluatedSymbol symbol_lookup(llvm::StringRef name) {
|
llvm::JITEvaluatedSymbol symbol_lookup(llvm::StringRef name) {
|
||||||
uint64_t addr = callbacks.lookup_vm_symbol(name.data(), name.size());
|
uint64_t addr = callbacks.lookup_vm_symbol(name.data(), name.size());
|
||||||
|
|
||||||
return llvm::JITEvaluatedSymbol(addr, llvm::JITSymbolFlags::None);
|
return llvm::JITEvaluatedSymbol(addr, llvm::JITSymbolFlags::None);
|
||||||
}
|
}
|
||||||
|
|
||||||
callbacks_t callbacks;
|
callbacks_t callbacks;
|
||||||
};
|
};
|
||||||
|
|
||||||
WasmModule::WasmModule(
|
WasmModule::WasmModule(const uint8_t *object_start, size_t object_size,
|
||||||
const uint8_t *object_start,
|
callbacks_t callbacks)
|
||||||
size_t object_size,
|
: memory_manager(
|
||||||
callbacks_t callbacks
|
std::unique_ptr<MemoryManager>(new MemoryManager(callbacks))) {
|
||||||
) : memory_manager(std::unique_ptr<MemoryManager>(new MemoryManager(callbacks)))
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
if (auto created_object_file = llvm::object::ObjectFile::createObjectFile(llvm::MemoryBufferRef(
|
if (auto created_object_file =
|
||||||
llvm::StringRef((const char *)object_start, object_size), "object"
|
llvm::object::ObjectFile::createObjectFile(llvm::MemoryBufferRef(
|
||||||
))) {
|
llvm::StringRef((const char *)object_start, object_size),
|
||||||
object_file = cantFail(std::move(created_object_file));
|
"object"))) {
|
||||||
SymbolLookup symbol_resolver(callbacks);
|
object_file = cantFail(std::move(created_object_file));
|
||||||
runtime_dyld = std::unique_ptr<llvm::RuntimeDyld>(new llvm::RuntimeDyld(*memory_manager, symbol_resolver));
|
SymbolLookup symbol_resolver(callbacks);
|
||||||
|
runtime_dyld = std::unique_ptr<llvm::RuntimeDyld>(
|
||||||
|
new llvm::RuntimeDyld(*memory_manager, symbol_resolver));
|
||||||
|
|
||||||
runtime_dyld->setProcessAllSections(true);
|
runtime_dyld->setProcessAllSections(true);
|
||||||
|
|
||||||
runtime_dyld->loadObject(*object_file);
|
runtime_dyld->loadObject(*object_file);
|
||||||
runtime_dyld->finalizeWithMemoryManagerLocking();
|
runtime_dyld->finalizeWithMemoryManagerLocking();
|
||||||
|
|
||||||
if (runtime_dyld->hasError()) {
|
if (runtime_dyld->hasError()) {
|
||||||
_init_failed = true;
|
_init_failed = true;
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
} else {
|
|
||||||
_init_failed = true;
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
_init_failed = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void* WasmModule::get_func(llvm::StringRef name) const {
|
void *WasmModule::get_func(llvm::StringRef name) const {
|
||||||
auto symbol = runtime_dyld->getSymbol(name);
|
auto symbol = runtime_dyld->getSymbol(name);
|
||||||
return (void*)symbol.getAddress();
|
return (void *)symbol.getAddress();
|
||||||
}
|
}
|
||||||
|
@ -1,236 +1,220 @@
|
|||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <llvm/ExecutionEngine/RuntimeDyld.h>
|
#include <exception>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <exception>
|
|
||||||
|
|
||||||
typedef enum
|
#include <llvm/ExecutionEngine/RuntimeDyld.h>
|
||||||
{
|
|
||||||
PROTECT_NONE,
|
typedef enum {
|
||||||
PROTECT_READ,
|
PROTECT_NONE,
|
||||||
PROTECT_READ_WRITE,
|
PROTECT_READ,
|
||||||
PROTECT_READ_EXECUTE,
|
PROTECT_READ_WRITE,
|
||||||
|
PROTECT_READ_EXECUTE,
|
||||||
} mem_protect_t;
|
} mem_protect_t;
|
||||||
|
|
||||||
typedef enum
|
typedef enum {
|
||||||
{
|
RESULT_OK,
|
||||||
RESULT_OK,
|
RESULT_ALLOCATE_FAILURE,
|
||||||
RESULT_ALLOCATE_FAILURE,
|
RESULT_PROTECT_FAILURE,
|
||||||
RESULT_PROTECT_FAILURE,
|
RESULT_DEALLOC_FAILURE,
|
||||||
RESULT_DEALLOC_FAILURE,
|
RESULT_OBJECT_LOAD_FAILURE,
|
||||||
RESULT_OBJECT_LOAD_FAILURE,
|
|
||||||
} result_t;
|
} result_t;
|
||||||
|
|
||||||
typedef result_t (*alloc_memory_t)(size_t size, mem_protect_t protect, uint8_t **ptr_out, size_t *size_out);
|
typedef result_t (*alloc_memory_t)(size_t size, mem_protect_t protect,
|
||||||
typedef result_t (*protect_memory_t)(uint8_t *ptr, size_t size, mem_protect_t protect);
|
uint8_t **ptr_out, size_t *size_out);
|
||||||
|
typedef result_t (*protect_memory_t)(uint8_t *ptr, size_t size,
|
||||||
|
mem_protect_t protect);
|
||||||
typedef result_t (*dealloc_memory_t)(uint8_t *ptr, size_t size);
|
typedef result_t (*dealloc_memory_t)(uint8_t *ptr, size_t size);
|
||||||
typedef uintptr_t (*lookup_vm_symbol_t)(const char *name_ptr, size_t length);
|
typedef uintptr_t (*lookup_vm_symbol_t)(const char *name_ptr, size_t length);
|
||||||
typedef void (*fde_visitor_t)(uint8_t *fde);
|
typedef void (*fde_visitor_t)(uint8_t *fde);
|
||||||
typedef result_t (*visit_fde_t)(uint8_t *fde, size_t size, fde_visitor_t visitor);
|
typedef result_t (*visit_fde_t)(uint8_t *fde, size_t size,
|
||||||
|
fde_visitor_t visitor);
|
||||||
|
|
||||||
typedef void (*trampoline_t)(void *, void *, void *, void *);
|
typedef void (*trampoline_t)(void *, void *, void *, void *);
|
||||||
|
|
||||||
typedef struct
|
typedef struct {
|
||||||
{
|
/* Memory management. */
|
||||||
/* Memory management. */
|
alloc_memory_t alloc_memory;
|
||||||
alloc_memory_t alloc_memory;
|
protect_memory_t protect_memory;
|
||||||
protect_memory_t protect_memory;
|
dealloc_memory_t dealloc_memory;
|
||||||
dealloc_memory_t dealloc_memory;
|
|
||||||
|
|
||||||
lookup_vm_symbol_t lookup_vm_symbol;
|
lookup_vm_symbol_t lookup_vm_symbol;
|
||||||
|
|
||||||
visit_fde_t visit_fde;
|
visit_fde_t visit_fde;
|
||||||
} callbacks_t;
|
} callbacks_t;
|
||||||
|
|
||||||
typedef struct
|
typedef struct {
|
||||||
{
|
size_t data, vtable;
|
||||||
size_t data, vtable;
|
|
||||||
} box_any_t;
|
} box_any_t;
|
||||||
|
|
||||||
struct WasmException
|
struct WasmException {
|
||||||
{
|
public:
|
||||||
public:
|
virtual std::string description() const noexcept = 0;
|
||||||
virtual std::string description() const noexcept = 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct UncatchableException : WasmException
|
struct UncatchableException : WasmException {
|
||||||
{
|
public:
|
||||||
public:
|
virtual std::string description() const noexcept override {
|
||||||
virtual std::string description() const noexcept override
|
return "Uncatchable exception";
|
||||||
{
|
}
|
||||||
return "Uncatchable exception";
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct UserException : UncatchableException
|
struct UserException : UncatchableException {
|
||||||
{
|
public:
|
||||||
public:
|
UserException(size_t data, size_t vtable) : error_data({data, vtable}) {}
|
||||||
UserException(size_t data, size_t vtable) : error_data({ data, vtable }) {}
|
|
||||||
|
|
||||||
virtual std::string description() const noexcept override
|
virtual std::string description() const noexcept override {
|
||||||
{
|
return "user exception";
|
||||||
return "user exception";
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// The parts of a `Box<dyn Any>`.
|
// The parts of a `Box<dyn Any>`.
|
||||||
box_any_t error_data;
|
box_any_t error_data;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct WasmTrap : UncatchableException
|
struct BreakpointException : UncatchableException {
|
||||||
{
|
public:
|
||||||
public:
|
BreakpointException(uintptr_t callback) : callback(callback) {}
|
||||||
enum Type
|
|
||||||
{
|
|
||||||
Unreachable = 0,
|
|
||||||
IncorrectCallIndirectSignature = 1,
|
|
||||||
MemoryOutOfBounds = 2,
|
|
||||||
CallIndirectOOB = 3,
|
|
||||||
IllegalArithmetic = 4,
|
|
||||||
Unknown,
|
|
||||||
};
|
|
||||||
|
|
||||||
WasmTrap(Type type) : type(type) {}
|
virtual std::string description() const noexcept override {
|
||||||
|
return "breakpoint exception";
|
||||||
|
}
|
||||||
|
|
||||||
virtual std::string description() const noexcept override
|
uintptr_t callback;
|
||||||
{
|
|
||||||
std::ostringstream ss;
|
|
||||||
ss
|
|
||||||
<< "WebAssembly trap:" << '\n'
|
|
||||||
<< " - type: " << type << '\n';
|
|
||||||
|
|
||||||
return ss.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
Type type;
|
|
||||||
|
|
||||||
private:
|
|
||||||
friend std::ostream &operator<<(std::ostream &out, const Type &ty)
|
|
||||||
{
|
|
||||||
switch (ty)
|
|
||||||
{
|
|
||||||
case Type::Unreachable:
|
|
||||||
out << "unreachable";
|
|
||||||
break;
|
|
||||||
case Type::IncorrectCallIndirectSignature:
|
|
||||||
out << "incorrect call_indirect signature";
|
|
||||||
break;
|
|
||||||
case Type::MemoryOutOfBounds:
|
|
||||||
out << "memory access out-of-bounds";
|
|
||||||
break;
|
|
||||||
case Type::CallIndirectOOB:
|
|
||||||
out << "call_indirect out-of-bounds";
|
|
||||||
break;
|
|
||||||
case Type::IllegalArithmetic:
|
|
||||||
out << "illegal arithmetic operation";
|
|
||||||
break;
|
|
||||||
case Type::Unknown:
|
|
||||||
default:
|
|
||||||
out << "unknown";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CatchableException : WasmException
|
struct WasmTrap : UncatchableException {
|
||||||
{
|
public:
|
||||||
public:
|
enum Type {
|
||||||
CatchableException(uint32_t type_id, uint32_t value_num) : type_id(type_id), value_num(value_num) {}
|
Unreachable = 0,
|
||||||
|
IncorrectCallIndirectSignature = 1,
|
||||||
|
MemoryOutOfBounds = 2,
|
||||||
|
CallIndirectOOB = 3,
|
||||||
|
IllegalArithmetic = 4,
|
||||||
|
Unknown,
|
||||||
|
};
|
||||||
|
|
||||||
virtual std::string description() const noexcept override
|
WasmTrap(Type type) : type(type) {}
|
||||||
{
|
|
||||||
return "catchable exception";
|
virtual std::string description() const noexcept override {
|
||||||
|
std::ostringstream ss;
|
||||||
|
ss << "WebAssembly trap:" << '\n' << " - type: " << type << '\n';
|
||||||
|
|
||||||
|
return ss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
Type type;
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend std::ostream &operator<<(std::ostream &out, const Type &ty) {
|
||||||
|
switch (ty) {
|
||||||
|
case Type::Unreachable:
|
||||||
|
out << "unreachable";
|
||||||
|
break;
|
||||||
|
case Type::IncorrectCallIndirectSignature:
|
||||||
|
out << "incorrect call_indirect signature";
|
||||||
|
break;
|
||||||
|
case Type::MemoryOutOfBounds:
|
||||||
|
out << "memory access out-of-bounds";
|
||||||
|
break;
|
||||||
|
case Type::CallIndirectOOB:
|
||||||
|
out << "call_indirect out-of-bounds";
|
||||||
|
break;
|
||||||
|
case Type::IllegalArithmetic:
|
||||||
|
out << "illegal arithmetic operation";
|
||||||
|
break;
|
||||||
|
case Type::Unknown:
|
||||||
|
default:
|
||||||
|
out << "unknown";
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
return out;
|
||||||
uint32_t type_id, value_num;
|
}
|
||||||
uint64_t values[1];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct WasmModule
|
struct CatchableException : WasmException {
|
||||||
{
|
public:
|
||||||
public:
|
CatchableException(uint32_t type_id, uint32_t value_num)
|
||||||
WasmModule(
|
: type_id(type_id), value_num(value_num) {}
|
||||||
const uint8_t *object_start,
|
|
||||||
size_t object_size,
|
|
||||||
callbacks_t callbacks);
|
|
||||||
|
|
||||||
void *get_func(llvm::StringRef name) const;
|
virtual std::string description() const noexcept override {
|
||||||
|
return "catchable exception";
|
||||||
|
}
|
||||||
|
|
||||||
bool _init_failed = false;
|
uint32_t type_id, value_num;
|
||||||
private:
|
uint64_t values[1];
|
||||||
std::unique_ptr<llvm::RuntimeDyld::MemoryManager> memory_manager;
|
|
||||||
std::unique_ptr<llvm::object::ObjectFile> object_file;
|
|
||||||
std::unique_ptr<llvm::RuntimeDyld> runtime_dyld;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern "C"
|
struct WasmModule {
|
||||||
{
|
public:
|
||||||
result_t module_load(const uint8_t *mem_ptr, size_t mem_size, callbacks_t callbacks, WasmModule **module_out)
|
WasmModule(const uint8_t *object_start, size_t object_size,
|
||||||
{
|
callbacks_t callbacks);
|
||||||
*module_out = new WasmModule(mem_ptr, mem_size, callbacks);
|
|
||||||
|
|
||||||
if ((*module_out)->_init_failed) {
|
void *get_func(llvm::StringRef name) const;
|
||||||
return RESULT_OBJECT_LOAD_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return RESULT_OK;
|
bool _init_failed = false;
|
||||||
}
|
|
||||||
|
|
||||||
[[noreturn]] void throw_trap(WasmTrap::Type ty) {
|
private:
|
||||||
throw WasmTrap(ty);
|
std::unique_ptr<llvm::RuntimeDyld::MemoryManager> memory_manager;
|
||||||
}
|
std::unique_ptr<llvm::object::ObjectFile> object_file;
|
||||||
|
std::unique_ptr<llvm::RuntimeDyld> runtime_dyld;
|
||||||
|
};
|
||||||
|
|
||||||
void module_delete(WasmModule *module)
|
extern "C" {
|
||||||
{
|
void callback_trampoline(void *, void *);
|
||||||
delete module;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Throw a fat pointer that's assumed to be `*mut dyn Any` on the rust
|
result_t module_load(const uint8_t *mem_ptr, size_t mem_size,
|
||||||
// side.
|
callbacks_t callbacks, WasmModule **module_out) {
|
||||||
[[noreturn]] void throw_any(size_t data, size_t vtable) {
|
*module_out = new WasmModule(mem_ptr, mem_size, callbacks);
|
||||||
throw UserException(data, vtable);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool invoke_trampoline(
|
if ((*module_out)->_init_failed) {
|
||||||
trampoline_t trampoline,
|
return RESULT_OBJECT_LOAD_FAILURE;
|
||||||
void *ctx,
|
}
|
||||||
void *func,
|
|
||||||
void *params,
|
|
||||||
void *results,
|
|
||||||
WasmTrap::Type *trap_out,
|
|
||||||
box_any_t *user_error,
|
|
||||||
void *invoke_env) throw()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
trampoline(ctx, func, params, results);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
catch (const WasmTrap &e)
|
|
||||||
{
|
|
||||||
*trap_out = e.type;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
catch (const UserException &e)
|
|
||||||
{
|
|
||||||
*user_error = e.error_data;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
catch (const WasmException &e)
|
|
||||||
{
|
|
||||||
*trap_out = WasmTrap::Type::Unknown;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
catch (...)
|
|
||||||
{
|
|
||||||
*trap_out = WasmTrap::Type::Unknown;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void *get_func_symbol(WasmModule *module, const char *name)
|
return RESULT_OK;
|
||||||
{
|
}
|
||||||
return module->get_func(llvm::StringRef(name));
|
|
||||||
}
|
[[noreturn]] void throw_trap(WasmTrap::Type ty) { throw WasmTrap(ty); }
|
||||||
}
|
|
||||||
|
void module_delete(WasmModule *module) { delete module; }
|
||||||
|
|
||||||
|
// Throw a fat pointer that's assumed to be `*mut dyn Any` on the rust
|
||||||
|
// side.
|
||||||
|
[[noreturn]] void throw_any(size_t data, size_t vtable) {
|
||||||
|
throw UserException(data, vtable);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Throw a pointer that's assumed to be codegen::BreakpointHandler on the
|
||||||
|
// rust side.
|
||||||
|
[[noreturn]] void throw_breakpoint(uintptr_t callback) {
|
||||||
|
throw BreakpointException(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool invoke_trampoline(trampoline_t trampoline, void *ctx, void *func,
|
||||||
|
void *params, void *results, WasmTrap::Type *trap_out,
|
||||||
|
box_any_t *user_error, void *invoke_env) noexcept {
|
||||||
|
try {
|
||||||
|
trampoline(ctx, func, params, results);
|
||||||
|
return true;
|
||||||
|
} catch (const WasmTrap &e) {
|
||||||
|
*trap_out = e.type;
|
||||||
|
return false;
|
||||||
|
} catch (const UserException &e) {
|
||||||
|
*user_error = e.error_data;
|
||||||
|
return false;
|
||||||
|
} catch (const BreakpointException &e) {
|
||||||
|
callback_trampoline(user_error, (void *)e.callback);
|
||||||
|
return false;
|
||||||
|
} catch (const WasmException &e) {
|
||||||
|
*trap_out = WasmTrap::Type::Unknown;
|
||||||
|
return false;
|
||||||
|
} catch (...) {
|
||||||
|
*trap_out = WasmTrap::Type::Unknown;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void *get_func_symbol(WasmModule *module, const char *name) {
|
||||||
|
return module->get_func(llvm::StringRef(name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -39,7 +39,8 @@ extern "C" {
|
|||||||
fn module_delete(module: *mut LLVMModule);
|
fn module_delete(module: *mut LLVMModule);
|
||||||
fn get_func_symbol(module: *mut LLVMModule, name: *const c_char) -> *const vm::Func;
|
fn get_func_symbol(module: *mut LLVMModule, name: *const c_char) -> *const vm::Func;
|
||||||
|
|
||||||
fn throw_trap(ty: i32);
|
fn throw_trap(ty: i32) -> !;
|
||||||
|
fn throw_breakpoint(ty: i64) -> !;
|
||||||
|
|
||||||
/// This should be the same as spliting up the fat pointer into two arguments,
|
/// This should be the same as spliting up the fat pointer into two arguments,
|
||||||
/// but this is cleaner, I think?
|
/// but this is cleaner, I think?
|
||||||
@ -103,6 +104,7 @@ fn get_callbacks() -> Callbacks {
|
|||||||
fn_name!("vm.memory.size.static.local") => vmcalls::local_static_memory_size as _,
|
fn_name!("vm.memory.size.static.local") => vmcalls::local_static_memory_size as _,
|
||||||
|
|
||||||
fn_name!("vm.exception.trap") => throw_trap as _,
|
fn_name!("vm.exception.trap") => throw_trap as _,
|
||||||
|
fn_name!("vm.breakpoint") => throw_breakpoint as _,
|
||||||
|
|
||||||
_ => ptr::null(),
|
_ => ptr::null(),
|
||||||
}
|
}
|
||||||
|
@ -496,6 +496,21 @@ pub struct CodegenError {
|
|||||||
pub message: String,
|
pub message: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This is only called by C++ code, the 'pub' + '#[no_mangle]' combination
|
||||||
|
// prevents unused function elimination.
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn callback_trampoline(
|
||||||
|
b: *mut Option<Box<dyn std::any::Any>>,
|
||||||
|
callback: *mut BreakpointHandler,
|
||||||
|
) {
|
||||||
|
let callback = Box::from_raw(callback);
|
||||||
|
let result: Result<(), Box<dyn std::any::Any>> = callback(BreakpointInfo { fault: None });
|
||||||
|
match result {
|
||||||
|
Ok(()) => *b = None,
|
||||||
|
Err(e) => *b = Some(e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct LLVMModuleCodeGenerator {
|
pub struct LLVMModuleCodeGenerator {
|
||||||
context: Option<Context>,
|
context: Option<Context>,
|
||||||
builder: Option<Builder>,
|
builder: Option<Builder>,
|
||||||
@ -612,7 +627,14 @@ impl FunctionCodeGenerator<CodegenError> for LLVMFunctionCodeGenerator {
|
|||||||
InternalEvent::FunctionBegin(_) | InternalEvent::FunctionEnd => {
|
InternalEvent::FunctionBegin(_) | InternalEvent::FunctionEnd => {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
InternalEvent::Breakpoint(_callback) => {
|
InternalEvent::Breakpoint(callback) => {
|
||||||
|
let raw = Box::into_raw(Box::new(callback)) as u64;
|
||||||
|
let callback = intrinsics.i64_ty.const_int(raw, false);
|
||||||
|
builder.build_call(
|
||||||
|
intrinsics.throw_breakpoint,
|
||||||
|
&[callback.as_basic_value_enum()],
|
||||||
|
"",
|
||||||
|
);
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
InternalEvent::GetInternal(idx) => {
|
InternalEvent::GetInternal(idx) => {
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
use hashbrown::HashMap;
|
|
||||||
use inkwell::{
|
use inkwell::{
|
||||||
builder::Builder,
|
builder::Builder,
|
||||||
context::Context,
|
context::Context,
|
||||||
@ -9,6 +8,7 @@ use inkwell::{
|
|||||||
values::{BasicValue, BasicValueEnum, FloatValue, FunctionValue, IntValue, PointerValue},
|
values::{BasicValue, BasicValueEnum, FloatValue, FunctionValue, IntValue, PointerValue},
|
||||||
AddressSpace,
|
AddressSpace,
|
||||||
};
|
};
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use wasmer_runtime_core::{
|
use wasmer_runtime_core::{
|
||||||
memory::MemoryType,
|
memory::MemoryType,
|
||||||
@ -147,6 +147,7 @@ pub struct Intrinsics {
|
|||||||
pub memory_size_shared_import: FunctionValue,
|
pub memory_size_shared_import: FunctionValue,
|
||||||
|
|
||||||
pub throw_trap: FunctionValue,
|
pub throw_trap: FunctionValue,
|
||||||
|
pub throw_breakpoint: FunctionValue,
|
||||||
|
|
||||||
pub ctx_ptr_ty: PointerType,
|
pub ctx_ptr_ty: PointerType,
|
||||||
}
|
}
|
||||||
@ -309,7 +310,6 @@ impl Intrinsics {
|
|||||||
i32_ty.fn_type(&[ctx_ptr_ty.as_basic_type_enum(), i32_ty_basic], false);
|
i32_ty.fn_type(&[ctx_ptr_ty.as_basic_type_enum(), i32_ty_basic], false);
|
||||||
|
|
||||||
let ret_i1_take_i1_i1 = i1_ty.fn_type(&[i1_ty_basic, i1_ty_basic], false);
|
let ret_i1_take_i1_i1 = i1_ty.fn_type(&[i1_ty_basic, i1_ty_basic], false);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
ctlz_i32: module.add_function("llvm.ctlz.i32", ret_i32_take_i32_i1, None),
|
ctlz_i32: module.add_function("llvm.ctlz.i32", ret_i32_take_i32_i1, None),
|
||||||
ctlz_i64: module.add_function("llvm.ctlz.i64", ret_i64_take_i64_i1, None),
|
ctlz_i64: module.add_function("llvm.ctlz.i64", ret_i64_take_i64_i1, None),
|
||||||
@ -525,6 +525,11 @@ impl Intrinsics {
|
|||||||
void_ty.fn_type(&[i32_ty_basic], false),
|
void_ty.fn_type(&[i32_ty_basic], false),
|
||||||
None,
|
None,
|
||||||
),
|
),
|
||||||
|
throw_breakpoint: module.add_function(
|
||||||
|
"vm.breakpoint",
|
||||||
|
void_ty.fn_type(&[i64_ty_basic], false),
|
||||||
|
None,
|
||||||
|
),
|
||||||
ctx_ptr_ty,
|
ctx_ptr_ty,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,10 @@
|
|||||||
#![deny(unused_imports, unused_variables, unused_unsafe, unreachable_patterns)]
|
#![deny(
|
||||||
|
dead_code,
|
||||||
|
unused_imports,
|
||||||
|
unused_variables,
|
||||||
|
unused_unsafe,
|
||||||
|
unreachable_patterns
|
||||||
|
)]
|
||||||
#![cfg_attr(nightly, feature(unwind_attributes))]
|
#![cfg_attr(nightly, feature(unwind_attributes))]
|
||||||
|
|
||||||
mod backend;
|
mod backend;
|
||||||
|
@ -1,4 +1,9 @@
|
|||||||
#![deny(unused_imports, unused_variables, unused_unsafe, unreachable_patterns)]
|
#![deny(
|
||||||
|
dead_code,
|
||||||
|
unused_imports,
|
||||||
|
unused_variables,
|
||||||
|
unused_unsafe,
|
||||||
|
unreachable_patterns
|
||||||
|
)]
|
||||||
pub mod call_trace;
|
pub mod call_trace;
|
||||||
pub mod metering;
|
pub mod metering;
|
||||||
|
@ -129,7 +129,7 @@ pub fn set_points_used_ctx(ctx: &mut Ctx, value: u64) {
|
|||||||
ctx.set_internal(&INTERNAL_FIELD, value);
|
ctx.set_internal(&INTERNAL_FIELD, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(all(test, feature = "singlepass"))]
|
#[cfg(all(test, any(feature = "singlepass", feature = "llvm")))]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use wabt::wat2wasm;
|
use wabt::wat2wasm;
|
||||||
@ -247,7 +247,7 @@ mod tests {
|
|||||||
// verify it returns the correct value
|
// verify it returns the correct value
|
||||||
assert_eq!(value, 7);
|
assert_eq!(value, 7);
|
||||||
|
|
||||||
// verify is uses the correct number of points
|
// verify it used the correct number of points
|
||||||
assert_eq!(get_points_used(&instance), 74);
|
assert_eq!(get_points_used(&instance), 74);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -276,7 +276,7 @@ mod tests {
|
|||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
|
|
||||||
// verify is uses the correct number of points
|
// verify it used the correct number of points
|
||||||
assert_eq!(get_points_used(&instance), 109); // Used points will be slightly more than `limit` because of the way we do gas checking.
|
assert_eq!(get_points_used(&instance), 109); // Used points will be slightly more than `limit` because of the way we do gas checking.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,12 +8,11 @@ repository = "https://github.com/wasmerio/wasmer"
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
libc = "0.2.50"
|
libc = "0.2.60"
|
||||||
wasmer-runtime-core = { path = "../runtime-core" }
|
wasmer-runtime-core = { path = "../runtime-core" }
|
||||||
hashbrown = "0.1"
|
|
||||||
failure = "0.1"
|
failure = "0.1"
|
||||||
tar = "0.4"
|
tar = "0.4"
|
||||||
wasmparser = "0.34.0"
|
wasmparser = "0.35.1"
|
||||||
zstd = "0.4"
|
zstd = "0.4"
|
||||||
|
|
||||||
# [target.'cfg(unix)'.dependencies.zbox]
|
# [target.'cfg(unix)'.dependencies.zbox]
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
#![deny(unused_imports, unused_variables, unused_unsafe, unreachable_patterns)]
|
#![deny(dead_code, unused_imports, unused_variables, unused_unsafe, unreachable_patterns)]
|
||||||
|
|
||||||
#[cfg(not(target_os = "windows"))]
|
#[cfg(not(target_os = "windows"))]
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate failure;
|
extern crate failure;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use crate::vfs::file_like::FileLike;
|
use crate::vfs::file_like::FileLike;
|
||||||
use crate::vfs::vfs_header::{header_from_bytes, ArchiveType, CompressionType};
|
use crate::vfs::vfs_header::{header_from_bytes, ArchiveType, CompressionType};
|
||||||
use crate::vfs::virtual_file::VirtualFile;
|
use crate::vfs::virtual_file::VirtualFile;
|
||||||
use hashbrown::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
|
@ -12,7 +12,7 @@ readme = "README.md"
|
|||||||
crate-type = ["cdylib", "rlib", "staticlib"]
|
crate-type = ["cdylib", "rlib", "staticlib"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
libc = "0.2"
|
libc = "0.2.60"
|
||||||
|
|
||||||
[dependencies.wasmer-runtime]
|
[dependencies.wasmer-runtime]
|
||||||
path = "../runtime"
|
path = "../runtime"
|
||||||
@ -27,4 +27,4 @@ debug = ["wasmer-runtime/debug"]
|
|||||||
llvm = ["wasmer-runtime/llvm"]
|
llvm = ["wasmer-runtime/llvm"]
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
cbindgen = "0.8"
|
cbindgen = "0.9.0"
|
||||||
|
@ -10,9 +10,10 @@ use crate::{
|
|||||||
};
|
};
|
||||||
use libc::c_uint;
|
use libc::c_uint;
|
||||||
use std::{ffi::c_void, ptr, slice, sync::Arc};
|
use std::{ffi::c_void, ptr, slice, sync::Arc};
|
||||||
use wasmer_runtime::Module;
|
use wasmer_runtime::{Global, Memory, Module, Table};
|
||||||
use wasmer_runtime_core::{
|
use wasmer_runtime_core::{
|
||||||
export::{Context, Export, FuncPointer},
|
export::{Context, Export, FuncPointer},
|
||||||
|
import::ImportObject,
|
||||||
module::ImportName,
|
module::ImportName,
|
||||||
types::{FuncSig, Type},
|
types::{FuncSig, Type},
|
||||||
};
|
};
|
||||||
@ -25,6 +26,9 @@ pub struct wasmer_import_t {
|
|||||||
pub value: wasmer_import_export_value,
|
pub value: wasmer_import_export_value,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct wasmer_import_object_t;
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct wasmer_import_func_t;
|
pub struct wasmer_import_func_t;
|
||||||
@ -37,6 +41,83 @@ pub struct wasmer_import_descriptor_t;
|
|||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct wasmer_import_descriptors_t;
|
pub struct wasmer_import_descriptors_t;
|
||||||
|
|
||||||
|
/// Creates a new empty import object.
|
||||||
|
/// See also `wasmer_import_object_append`
|
||||||
|
#[allow(clippy::cast_ptr_alignment)]
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn wasmer_import_object_new() -> *mut wasmer_import_object_t {
|
||||||
|
let import_object = Box::new(ImportObject::new());
|
||||||
|
|
||||||
|
Box::into_raw(import_object) as *mut wasmer_import_object_t
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Extends an existing import object with new imports
|
||||||
|
#[allow(clippy::cast_ptr_alignment)]
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn wasmer_import_object_extend(
|
||||||
|
import_object: *mut wasmer_import_object_t,
|
||||||
|
imports: *mut wasmer_import_t,
|
||||||
|
imports_len: c_uint,
|
||||||
|
) -> wasmer_result_t {
|
||||||
|
let import_object: &mut ImportObject = &mut *(import_object as *mut ImportObject);
|
||||||
|
|
||||||
|
let mut extensions: Vec<(String, String, Export)> = Vec::new();
|
||||||
|
|
||||||
|
let imports: &[wasmer_import_t] = slice::from_raw_parts(imports, imports_len as usize);
|
||||||
|
for import in imports {
|
||||||
|
let module_name = slice::from_raw_parts(
|
||||||
|
import.module_name.bytes,
|
||||||
|
import.module_name.bytes_len as usize,
|
||||||
|
);
|
||||||
|
let module_name = if let Ok(s) = std::str::from_utf8(module_name) {
|
||||||
|
s
|
||||||
|
} else {
|
||||||
|
update_last_error(CApiError {
|
||||||
|
msg: "error converting module name to string".to_string(),
|
||||||
|
});
|
||||||
|
return wasmer_result_t::WASMER_ERROR;
|
||||||
|
};
|
||||||
|
let import_name = slice::from_raw_parts(
|
||||||
|
import.import_name.bytes,
|
||||||
|
import.import_name.bytes_len as usize,
|
||||||
|
);
|
||||||
|
let import_name = if let Ok(s) = std::str::from_utf8(import_name) {
|
||||||
|
s
|
||||||
|
} else {
|
||||||
|
update_last_error(CApiError {
|
||||||
|
msg: "error converting import_name to string".to_string(),
|
||||||
|
});
|
||||||
|
return wasmer_result_t::WASMER_ERROR;
|
||||||
|
};
|
||||||
|
|
||||||
|
let export = match import.tag {
|
||||||
|
wasmer_import_export_kind::WASM_MEMORY => {
|
||||||
|
let mem = import.value.memory as *mut Memory;
|
||||||
|
Export::Memory((&*mem).clone())
|
||||||
|
}
|
||||||
|
wasmer_import_export_kind::WASM_FUNCTION => {
|
||||||
|
let func_export = import.value.func as *mut Export;
|
||||||
|
(&*func_export).clone()
|
||||||
|
}
|
||||||
|
wasmer_import_export_kind::WASM_GLOBAL => {
|
||||||
|
let global = import.value.global as *mut Global;
|
||||||
|
Export::Global((&*global).clone())
|
||||||
|
}
|
||||||
|
wasmer_import_export_kind::WASM_TABLE => {
|
||||||
|
let table = import.value.table as *mut Table;
|
||||||
|
Export::Table((&*table).clone())
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let extension = (module_name.to_string(), import_name.to_string(), export);
|
||||||
|
extensions.push(extension)
|
||||||
|
}
|
||||||
|
|
||||||
|
import_object.extend(extensions);
|
||||||
|
|
||||||
|
return wasmer_result_t::WASMER_OK;
|
||||||
|
}
|
||||||
|
|
||||||
/// Gets import descriptors for the given module
|
/// Gets import descriptors for the given module
|
||||||
///
|
///
|
||||||
/// The caller owns the object and should call `wasmer_import_descriptors_destroy` to free it.
|
/// The caller owns the object and should call `wasmer_import_descriptors_destroy` to free it.
|
||||||
@ -352,6 +433,14 @@ pub extern "C" fn wasmer_import_func_destroy(func: *mut wasmer_import_func_t) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Frees memory of the given ImportObject
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn wasmer_import_object_destroy(import_object: *mut wasmer_import_object_t) {
|
||||||
|
if !import_object.is_null() {
|
||||||
|
unsafe { Box::from_raw(import_object as *mut ImportObject) };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct NamedImportDescriptor {
|
struct NamedImportDescriptor {
|
||||||
module: String,
|
module: String,
|
||||||
name: String,
|
name: String,
|
||||||
|
@ -3,15 +3,19 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
error::{update_last_error, CApiError},
|
error::{update_last_error, CApiError},
|
||||||
export::{wasmer_exports_t, wasmer_import_export_kind, NamedExport, NamedExports},
|
export::{wasmer_exports_t, wasmer_import_export_kind, NamedExport, NamedExports},
|
||||||
import::wasmer_import_t,
|
import::{wasmer_import_object_t, wasmer_import_t},
|
||||||
memory::wasmer_memory_t,
|
memory::wasmer_memory_t,
|
||||||
|
module::wasmer_module_t,
|
||||||
value::{wasmer_value, wasmer_value_t, wasmer_value_tag},
|
value::{wasmer_value, wasmer_value_t, wasmer_value_tag},
|
||||||
wasmer_result_t,
|
wasmer_result_t,
|
||||||
};
|
};
|
||||||
use libc::{c_char, c_int, c_void};
|
use libc::{c_char, c_int, c_void};
|
||||||
use std::{collections::HashMap, ffi::CStr, slice};
|
use std::{collections::HashMap, ffi::CStr, slice};
|
||||||
use wasmer_runtime::{Ctx, Global, ImportObject, Instance, Memory, Table, Value};
|
use wasmer_runtime::{Ctx, Global, Instance, Memory, Module, Table, Value};
|
||||||
use wasmer_runtime_core::{export::Export, import::Namespace};
|
use wasmer_runtime_core::{
|
||||||
|
export::Export,
|
||||||
|
import::{ImportObject, Namespace},
|
||||||
|
};
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct wasmer_instance_t;
|
pub struct wasmer_instance_t;
|
||||||
@ -108,6 +112,45 @@ pub unsafe extern "C" fn wasmer_instantiate(
|
|||||||
wasmer_result_t::WASMER_OK
|
wasmer_result_t::WASMER_OK
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Given:
|
||||||
|
/// * A prepared `wasmer` import-object
|
||||||
|
/// * A compiled wasmer module
|
||||||
|
///
|
||||||
|
/// Instantiates a wasmer instance
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn wasmer_module_import_instantiate(
|
||||||
|
instance: *mut *mut wasmer_instance_t,
|
||||||
|
module: *const wasmer_module_t,
|
||||||
|
import_object: *const wasmer_import_object_t,
|
||||||
|
) -> wasmer_result_t {
|
||||||
|
let import_object: &ImportObject = &*(import_object as *const ImportObject);
|
||||||
|
let module: &Module = &*(module as *const Module);
|
||||||
|
|
||||||
|
let new_instance: Instance = match module.instantiate(import_object) {
|
||||||
|
Ok(instance) => instance,
|
||||||
|
Err(error) => {
|
||||||
|
update_last_error(error);
|
||||||
|
return wasmer_result_t::WASMER_ERROR;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
*instance = Box::into_raw(Box::new(new_instance)) as *mut wasmer_instance_t;
|
||||||
|
|
||||||
|
return wasmer_result_t::WASMER_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Extracts the instance's context and returns it.
|
||||||
|
#[allow(clippy::cast_ptr_alignment)]
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn wasmer_instance_context_get(
|
||||||
|
instance: *mut wasmer_instance_t,
|
||||||
|
) -> *const wasmer_instance_context_t {
|
||||||
|
let instance_ref = &*(instance as *const Instance);
|
||||||
|
|
||||||
|
let ctx: *const Ctx = instance_ref.context() as *const _;
|
||||||
|
|
||||||
|
ctx as *const wasmer_instance_context_t
|
||||||
|
}
|
||||||
|
|
||||||
/// Calls an instances exported function by `name` with the provided parameters.
|
/// Calls an instances exported function by `name` with the provided parameters.
|
||||||
/// Results are set using the provided `results` pointer.
|
/// Results are set using the provided `results` pointer.
|
||||||
///
|
///
|
||||||
|
@ -80,8 +80,13 @@
|
|||||||
//!
|
//!
|
||||||
//! [wasmer_h]: ./wasmer.h
|
//! [wasmer_h]: ./wasmer.h
|
||||||
//! [wasmer_hh]: ./wasmer.hh
|
//! [wasmer_hh]: ./wasmer.hh
|
||||||
#![deny(unused_imports, unused_variables, unused_unsafe, unreachable_patterns)]
|
#![deny(
|
||||||
|
dead_code,
|
||||||
|
unused_imports,
|
||||||
|
unused_variables,
|
||||||
|
unused_unsafe,
|
||||||
|
unreachable_patterns
|
||||||
|
)]
|
||||||
extern crate wasmer_runtime;
|
extern crate wasmer_runtime;
|
||||||
extern crate wasmer_runtime_core;
|
extern crate wasmer_runtime_core;
|
||||||
|
|
||||||
|
4
lib/runtime-c-api/tests/.gitignore
vendored
4
lib/runtime-c-api/tests/.gitignore
vendored
@ -22,4 +22,6 @@ test-module-exports
|
|||||||
test-module-imports
|
test-module-imports
|
||||||
test-module-serialize
|
test-module-serialize
|
||||||
test-tables
|
test-tables
|
||||||
test-validate
|
test-validate
|
||||||
|
test-context
|
||||||
|
test-module-import-instantiate
|
||||||
|
@ -14,6 +14,8 @@ add_executable(test-module-imports test-module-imports.c)
|
|||||||
add_executable(test-module-serialize test-module-serialize.c)
|
add_executable(test-module-serialize test-module-serialize.c)
|
||||||
add_executable(test-tables test-tables.c)
|
add_executable(test-tables test-tables.c)
|
||||||
add_executable(test-validate test-validate.c)
|
add_executable(test-validate test-validate.c)
|
||||||
|
add_executable(test-context test-context.c)
|
||||||
|
add_executable(test-module-import-instantiate test-module-import-instantiate.c)
|
||||||
|
|
||||||
find_library(
|
find_library(
|
||||||
WASMER_LIB NAMES libwasmer_runtime_c_api.dylib libwasmer_runtime_c_api.so libwasmer_runtime_c_api.dll
|
WASMER_LIB NAMES libwasmer_runtime_c_api.dylib libwasmer_runtime_c_api.so libwasmer_runtime_c_api.dll
|
||||||
@ -87,3 +89,11 @@ add_test(test-tables test-tables)
|
|||||||
target_link_libraries(test-validate general ${WASMER_LIB})
|
target_link_libraries(test-validate general ${WASMER_LIB})
|
||||||
target_compile_options(test-validate PRIVATE ${COMPILER_OPTIONS})
|
target_compile_options(test-validate PRIVATE ${COMPILER_OPTIONS})
|
||||||
add_test(test-validate test-validate)
|
add_test(test-validate test-validate)
|
||||||
|
|
||||||
|
target_link_libraries(test-context general ${WASMER_LIB})
|
||||||
|
target_compile_options(test-context PRIVATE ${COMPILER_OPTIONS})
|
||||||
|
add_test(test-context test-context)
|
||||||
|
|
||||||
|
target_link_libraries(test-module-import-instantiate general ${WASMER_LIB})
|
||||||
|
target_compile_options(test-module-import-instantiate PRIVATE ${COMPILER_OPTIONS})
|
||||||
|
add_test(test-module-import-instantiate test-module-import-instantiate)
|
||||||
|
BIN
lib/runtime-c-api/tests/assets/inc.wasm
Normal file
BIN
lib/runtime-c-api/tests/assets/inc.wasm
Normal file
Binary file not shown.
12
lib/runtime-c-api/tests/assets/inc.wast
Normal file
12
lib/runtime-c-api/tests/assets/inc.wast
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
(module
|
||||||
|
(func $inc (import "env" "inc"))
|
||||||
|
(func $mul (import "env" "mul"))
|
||||||
|
(func $get (import "env" "get") (result i32))
|
||||||
|
|
||||||
|
(func (export "inc_and_get") (result i32)
|
||||||
|
call $inc
|
||||||
|
call $get)
|
||||||
|
|
||||||
|
(func (export "mul_and_get") (result i32)
|
||||||
|
call $mul
|
||||||
|
call $get))
|
@ -4,19 +4,17 @@ use std::process::Command;
|
|||||||
fn test_c_api() {
|
fn test_c_api() {
|
||||||
let project_tests_dir = concat!(env!("CARGO_MANIFEST_DIR"), "/tests");
|
let project_tests_dir = concat!(env!("CARGO_MANIFEST_DIR"), "/tests");
|
||||||
|
|
||||||
run_command("cmake", project_tests_dir, Some("."));
|
run_command("cmake", project_tests_dir, vec!["."]);
|
||||||
run_command("make", project_tests_dir, Some("-Wdev -Werror=dev"));
|
run_command("make", project_tests_dir, vec!["-Wdev", "-Werror=dev"]);
|
||||||
run_command("make", project_tests_dir, Some("test"));
|
run_command("make", project_tests_dir, vec!["test", "ARGS=\"-V\""]);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_command(command_str: &str, dir: &str, arg: Option<&str>) {
|
fn run_command(command_str: &str, dir: &str, args: Vec<&str>) {
|
||||||
println!("Running command: `{}` arg: {:?}", command_str, arg);
|
println!("Running command: `{}` args: {:?}", command_str, args);
|
||||||
|
|
||||||
let mut command = Command::new(command_str);
|
let mut command = Command::new(command_str);
|
||||||
|
|
||||||
if let Some(a) = arg {
|
command.args(&args);
|
||||||
command.arg(a);
|
|
||||||
}
|
|
||||||
|
|
||||||
command.current_dir(dir);
|
command.current_dir(dir);
|
||||||
|
|
||||||
|
137
lib/runtime-c-api/tests/test-context.c
Normal file
137
lib/runtime-c-api/tests/test-context.c
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include "../wasmer.h"
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int32_t amount;
|
||||||
|
int32_t value;
|
||||||
|
} counter_data;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t* bytes;
|
||||||
|
long bytes_len;
|
||||||
|
} wasm_file_t;
|
||||||
|
|
||||||
|
wasm_file_t read_wasm_file(const char* file_name) {
|
||||||
|
wasm_file_t wasm_file;
|
||||||
|
|
||||||
|
FILE *file = fopen(file_name, "r");
|
||||||
|
fseek(file, 0, SEEK_END);
|
||||||
|
wasm_file.bytes_len = ftell(file);
|
||||||
|
|
||||||
|
wasm_file.bytes = malloc(wasm_file.bytes_len);
|
||||||
|
fseek(file, 0, SEEK_SET);
|
||||||
|
fread(wasm_file.bytes, 1, wasm_file.bytes_len, file);
|
||||||
|
fclose(file);
|
||||||
|
|
||||||
|
return wasm_file;
|
||||||
|
}
|
||||||
|
|
||||||
|
void inc_counter(wasmer_instance_context_t *ctx) {
|
||||||
|
counter_data* data = (counter_data*)wasmer_instance_context_data_get(ctx);
|
||||||
|
data->value = data->value + data->amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mul_counter(wasmer_instance_context_t *ctx) {
|
||||||
|
counter_data* data = (counter_data*)wasmer_instance_context_data_get(ctx);
|
||||||
|
data->value = data->value * data->amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t get_counter(wasmer_instance_context_t *ctx) {
|
||||||
|
counter_data* data = (counter_data*)wasmer_instance_context_data_get(ctx);
|
||||||
|
return data->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
counter_data *init_counter(int32_t value, int32_t amount) {
|
||||||
|
counter_data* counter = malloc(sizeof(counter_data));
|
||||||
|
counter->value = value;
|
||||||
|
counter->amount = amount;
|
||||||
|
return counter;
|
||||||
|
}
|
||||||
|
|
||||||
|
void assert_counter(wasmer_instance_t *instance, int32_t expected) {
|
||||||
|
wasmer_value_t result_one;
|
||||||
|
wasmer_value_t params[] = {};
|
||||||
|
wasmer_value_t results[] = {result_one};
|
||||||
|
|
||||||
|
wasmer_result_t call1_result = wasmer_instance_call(instance, "inc_and_get", params, 0, results, 1);
|
||||||
|
printf("Call result: %d\n", call1_result);
|
||||||
|
printf("Result: %d\n", results[0].value.I32);
|
||||||
|
assert(results[0].value.I32 == expected);
|
||||||
|
assert(call1_result == WASMER_OK);
|
||||||
|
|
||||||
|
const wasmer_instance_context_t *ctx = wasmer_instance_context_get(instance);
|
||||||
|
counter_data *cd = (counter_data*)wasmer_instance_context_data_get(ctx);
|
||||||
|
assert(cd->value == expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
wasmer_import_t create_import(char* module_name, char* import_name, wasmer_import_func_t *func) {
|
||||||
|
wasmer_import_t import;
|
||||||
|
wasmer_byte_array module_name_bytes;
|
||||||
|
wasmer_byte_array import_name_bytes;
|
||||||
|
|
||||||
|
module_name_bytes.bytes = (const uint8_t *) module_name;
|
||||||
|
module_name_bytes.bytes_len = strlen(module_name);
|
||||||
|
|
||||||
|
import_name_bytes.bytes = (const uint8_t *) import_name;
|
||||||
|
import_name_bytes.bytes_len = strlen(import_name);
|
||||||
|
|
||||||
|
import.module_name = module_name_bytes;
|
||||||
|
import.import_name = import_name_bytes;
|
||||||
|
|
||||||
|
import.tag = WASM_FUNCTION;
|
||||||
|
import.value.func = func;
|
||||||
|
|
||||||
|
return import;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
// Prepare Imports
|
||||||
|
wasmer_value_tag inc_params_sig[] = {};
|
||||||
|
wasmer_value_tag inc_returns_sig[] = {};
|
||||||
|
wasmer_import_func_t *inc_func = wasmer_import_func_new((void (*)(void *)) inc_counter, inc_params_sig, 0, inc_returns_sig, 0);
|
||||||
|
wasmer_import_t inc_import = create_import("env", "inc", inc_func);
|
||||||
|
|
||||||
|
wasmer_value_tag mul_params_sig[] = {};
|
||||||
|
wasmer_value_tag mul_returns_sig[] = {};
|
||||||
|
wasmer_import_func_t *mul_func = wasmer_import_func_new((void (*)(void *)) mul_counter, mul_params_sig, 0, mul_returns_sig, 0);
|
||||||
|
wasmer_import_t mul_import = create_import("env", "mul", mul_func);
|
||||||
|
|
||||||
|
wasmer_value_tag get_params_sig[] = {};
|
||||||
|
wasmer_value_tag get_returns_sig[] = {WASM_I32};
|
||||||
|
wasmer_import_func_t *get_func = wasmer_import_func_new((void (*)(void *)) get_counter, get_params_sig, 0, get_returns_sig, 1);
|
||||||
|
wasmer_import_t get_import = create_import("env", "get", get_func);
|
||||||
|
|
||||||
|
wasmer_import_t imports[] = {inc_import, mul_import, get_import};
|
||||||
|
|
||||||
|
// Read the wasm file
|
||||||
|
wasm_file_t wasm_file = read_wasm_file("assets/inc.wasm");
|
||||||
|
|
||||||
|
// Instantiate instance
|
||||||
|
printf("Instantiating\n");
|
||||||
|
wasmer_instance_t *instance = NULL;
|
||||||
|
wasmer_result_t instantiate_res = wasmer_instantiate(&instance, wasm_file.bytes, wasm_file.bytes_len, imports, 3);
|
||||||
|
printf("Compile result: %d\n", instantiate_res);
|
||||||
|
assert(instantiate_res == WASMER_OK);
|
||||||
|
|
||||||
|
// Init counter
|
||||||
|
counter_data *counter = init_counter(2, 5);
|
||||||
|
wasmer_instance_context_data_set(instance, counter);
|
||||||
|
|
||||||
|
// Run `instance.inc_and_get` and assert
|
||||||
|
assert_counter(instance, 7);
|
||||||
|
assert_counter(instance, 12);
|
||||||
|
assert_counter(instance, 17);
|
||||||
|
|
||||||
|
// Clear resources
|
||||||
|
wasmer_import_func_destroy(inc_func);
|
||||||
|
wasmer_import_func_destroy(get_func);
|
||||||
|
wasmer_instance_destroy(instance);
|
||||||
|
free(counter);
|
||||||
|
free(wasm_file.bytes);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
@ -42,8 +42,9 @@ int main()
|
|||||||
assert(export_length == 5);
|
assert(export_length == 5);
|
||||||
|
|
||||||
// Get the `memory` export.
|
// Get the `memory` export.
|
||||||
wasmer_export_t *export = wasmer_exports_get(exports, 1);
|
wasmer_export_t *export = wasmer_exports_get(exports, 0);
|
||||||
wasmer_import_export_kind kind = wasmer_export_kind(export);
|
wasmer_import_export_kind kind = wasmer_export_kind(export);
|
||||||
|
printf("Wasmer import export kind: %d (Memory is %d)\n", kind, WASM_MEMORY);
|
||||||
assert(kind == WASM_MEMORY);
|
assert(kind == WASM_MEMORY);
|
||||||
|
|
||||||
wasmer_byte_array export_name = wasmer_export_name(export);
|
wasmer_byte_array export_name = wasmer_export_name(export);
|
||||||
|
149
lib/runtime-c-api/tests/test-module-import-instantiate.c
Normal file
149
lib/runtime-c-api/tests/test-module-import-instantiate.c
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include "../wasmer.h"
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int32_t amount;
|
||||||
|
int32_t value;
|
||||||
|
} counter_data;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t* bytes;
|
||||||
|
long bytes_len;
|
||||||
|
} wasm_file_t;
|
||||||
|
|
||||||
|
wasm_file_t read_wasm_file(const char* file_name) {
|
||||||
|
wasm_file_t wasm_file;
|
||||||
|
|
||||||
|
FILE *file = fopen(file_name, "r");
|
||||||
|
fseek(file, 0, SEEK_END);
|
||||||
|
wasm_file.bytes_len = ftell(file);
|
||||||
|
|
||||||
|
wasm_file.bytes = malloc(wasm_file.bytes_len);
|
||||||
|
fseek(file, 0, SEEK_SET);
|
||||||
|
fread(wasm_file.bytes, 1, wasm_file.bytes_len, file);
|
||||||
|
fclose(file);
|
||||||
|
|
||||||
|
return wasm_file;
|
||||||
|
}
|
||||||
|
|
||||||
|
void inc_counter(wasmer_instance_context_t *ctx) {
|
||||||
|
counter_data* data = (counter_data*)wasmer_instance_context_data_get(ctx);
|
||||||
|
data->value = data->value + data->amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mul_counter(wasmer_instance_context_t *ctx) {
|
||||||
|
counter_data* data = (counter_data*)wasmer_instance_context_data_get(ctx);
|
||||||
|
data->value = data->value * data->amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t get_counter(wasmer_instance_context_t *ctx) {
|
||||||
|
counter_data* data = (counter_data*)wasmer_instance_context_data_get(ctx);
|
||||||
|
return data->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
counter_data *init_counter(int32_t value, int32_t amount) {
|
||||||
|
counter_data* counter = malloc(sizeof(counter_data));
|
||||||
|
counter->value = value;
|
||||||
|
counter->amount = amount;
|
||||||
|
return counter;
|
||||||
|
}
|
||||||
|
|
||||||
|
wasmer_import_t create_import(char* module_name, char* import_name, wasmer_import_func_t *func) {
|
||||||
|
wasmer_import_t import;
|
||||||
|
wasmer_byte_array module_name_bytes;
|
||||||
|
wasmer_byte_array import_name_bytes;
|
||||||
|
|
||||||
|
module_name_bytes.bytes = (const uint8_t *) module_name;
|
||||||
|
module_name_bytes.bytes_len = strlen(module_name);
|
||||||
|
|
||||||
|
import_name_bytes.bytes = (const uint8_t *) import_name;
|
||||||
|
import_name_bytes.bytes_len = strlen(import_name);
|
||||||
|
|
||||||
|
import.module_name = module_name_bytes;
|
||||||
|
import.import_name = import_name_bytes;
|
||||||
|
|
||||||
|
import.tag = WASM_FUNCTION;
|
||||||
|
import.value.func = func;
|
||||||
|
|
||||||
|
return import;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
// Prepare Imports
|
||||||
|
wasmer_value_tag inc_params_sig[] = {};
|
||||||
|
wasmer_value_tag inc_returns_sig[] = {};
|
||||||
|
wasmer_import_func_t *inc_func = wasmer_import_func_new((void (*)(void *)) inc_counter, inc_params_sig, 0, inc_returns_sig, 0);
|
||||||
|
wasmer_import_t inc_import = create_import("env", "inc", inc_func);
|
||||||
|
|
||||||
|
wasmer_value_tag mul_params_sig[] = {};
|
||||||
|
wasmer_value_tag mul_returns_sig[] = {};
|
||||||
|
wasmer_import_func_t *mul_func = wasmer_import_func_new((void (*)(void *)) mul_counter, mul_params_sig, 0, mul_returns_sig, 0);
|
||||||
|
wasmer_import_t mul_import = create_import("env", "mul", mul_func);
|
||||||
|
|
||||||
|
wasmer_value_tag get_params_sig[] = {};
|
||||||
|
wasmer_value_tag get_returns_sig[] = {WASM_I32};
|
||||||
|
wasmer_import_func_t *get_func = wasmer_import_func_new((void (*)(void *)) get_counter, get_params_sig, 0, get_returns_sig, 1);
|
||||||
|
wasmer_import_t get_import = create_import("env", "get", get_func);
|
||||||
|
|
||||||
|
// Read the wasm file
|
||||||
|
wasm_file_t wasm_file = read_wasm_file("assets/inc.wasm");
|
||||||
|
|
||||||
|
// Compile module
|
||||||
|
wasmer_module_t *module = NULL;
|
||||||
|
wasmer_result_t compile_res = wasmer_compile(&module, wasm_file.bytes, wasm_file.bytes_len);
|
||||||
|
assert(compile_res == WASMER_OK);
|
||||||
|
|
||||||
|
// Prepare Import Object
|
||||||
|
wasmer_import_object_t *import_object = wasmer_import_object_new();
|
||||||
|
|
||||||
|
// First, we import `inc_counter` and `mul_counter`
|
||||||
|
wasmer_import_t imports[] = {inc_import, mul_import};
|
||||||
|
wasmer_result_t extend_res = wasmer_import_object_extend(import_object, imports, 2);
|
||||||
|
assert(extend_res == WASMER_OK);
|
||||||
|
|
||||||
|
// Now, we'll import `inc_counter` and `mul_counter`
|
||||||
|
wasmer_import_t more_imports[] = {get_import};
|
||||||
|
wasmer_result_t extend_res2 = wasmer_import_object_extend(import_object, more_imports, 1);
|
||||||
|
assert(extend_res2 == WASMER_OK);
|
||||||
|
|
||||||
|
// Same `wasmer_import_object_extend` as the first, doesn't affect anything
|
||||||
|
wasmer_result_t extend_res3 = wasmer_import_object_extend(import_object, imports, 2);
|
||||||
|
assert(extend_res3 == WASMER_OK);
|
||||||
|
|
||||||
|
// Instantiate instance
|
||||||
|
printf("Instantiating\n");
|
||||||
|
wasmer_instance_t *instance = NULL;
|
||||||
|
wasmer_result_t instantiate_res = wasmer_module_import_instantiate(&instance, module, import_object);
|
||||||
|
printf("Compile result: %d\n", instantiate_res);
|
||||||
|
assert(instantiate_res == WASMER_OK);
|
||||||
|
|
||||||
|
// Init counter
|
||||||
|
counter_data *counter = init_counter(2, 5);
|
||||||
|
wasmer_instance_context_data_set(instance, counter);
|
||||||
|
|
||||||
|
wasmer_value_t result_one;
|
||||||
|
wasmer_value_t params[] = {};
|
||||||
|
wasmer_value_t results[] = {result_one};
|
||||||
|
|
||||||
|
wasmer_result_t call1_result = wasmer_instance_call(instance, "inc_and_get", params, 0, results, 1);
|
||||||
|
printf("Call result: %d\n", call1_result);
|
||||||
|
printf("Result: %d\n", results[0].value.I32);
|
||||||
|
|
||||||
|
wasmer_result_t call2_result = wasmer_instance_call(instance, "mul_and_get", params, 0, results, 1);
|
||||||
|
printf("Call result: %d\n", call2_result);
|
||||||
|
printf("Result: %d\n", results[0].value.I32);
|
||||||
|
|
||||||
|
// Clear resources
|
||||||
|
wasmer_import_func_destroy(inc_func);
|
||||||
|
wasmer_import_func_destroy(mul_func);
|
||||||
|
wasmer_import_func_destroy(get_func);
|
||||||
|
wasmer_instance_destroy(instance);
|
||||||
|
free(counter);
|
||||||
|
free(wasm_file.bytes);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
@ -95,11 +95,7 @@ typedef struct {
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
||||||
} wasmer_instance_t;
|
} wasmer_import_object_t;
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
|
|
||||||
} wasmer_instance_context_t;
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
||||||
@ -119,6 +115,14 @@ typedef struct {
|
|||||||
wasmer_import_export_value value;
|
wasmer_import_export_value value;
|
||||||
} wasmer_import_t;
|
} wasmer_import_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
|
||||||
|
} wasmer_instance_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
|
||||||
|
} wasmer_instance_context_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
bool has_some;
|
bool has_some;
|
||||||
uint32_t some;
|
uint32_t some;
|
||||||
@ -392,6 +396,24 @@ wasmer_result_t wasmer_import_func_returns(const wasmer_import_func_t *func,
|
|||||||
wasmer_result_t wasmer_import_func_returns_arity(const wasmer_import_func_t *func,
|
wasmer_result_t wasmer_import_func_returns_arity(const wasmer_import_func_t *func,
|
||||||
uint32_t *result);
|
uint32_t *result);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Frees memory of the given ImportObject
|
||||||
|
*/
|
||||||
|
void wasmer_import_object_destroy(wasmer_import_object_t *import_object);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extends an existing import object with new imports
|
||||||
|
*/
|
||||||
|
wasmer_result_t wasmer_import_object_extend(wasmer_import_object_t *import_object,
|
||||||
|
wasmer_import_t *imports,
|
||||||
|
unsigned int imports_len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new empty import object.
|
||||||
|
* See also `wasmer_import_object_append`
|
||||||
|
*/
|
||||||
|
wasmer_import_object_t *wasmer_import_object_new(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calls an instances exported function by `name` with the provided parameters.
|
* Calls an instances exported function by `name` with the provided parameters.
|
||||||
* Results are set using the provided `results` pointer.
|
* Results are set using the provided `results` pointer.
|
||||||
@ -417,6 +439,11 @@ void *wasmer_instance_context_data_get(const wasmer_instance_context_t *ctx);
|
|||||||
*/
|
*/
|
||||||
void wasmer_instance_context_data_set(wasmer_instance_t *instance, void *data_ptr);
|
void wasmer_instance_context_data_set(wasmer_instance_t *instance, void *data_ptr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts the instance's context and returns it.
|
||||||
|
*/
|
||||||
|
const wasmer_instance_context_t *wasmer_instance_context_get(wasmer_instance_t *instance);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the memory within the context at the index `memory_idx`.
|
* Gets the memory within the context at the index `memory_idx`.
|
||||||
* The index is always 0 until multiple memories are supported.
|
* The index is always 0 until multiple memories are supported.
|
||||||
@ -526,6 +553,16 @@ wasmer_result_t wasmer_module_deserialize(wasmer_module_t **module,
|
|||||||
*/
|
*/
|
||||||
void wasmer_module_destroy(wasmer_module_t *module);
|
void wasmer_module_destroy(wasmer_module_t *module);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given:
|
||||||
|
* A prepared `wasmer svm` import-object
|
||||||
|
* A compiled wasmer module
|
||||||
|
* Instantiates a wasmer instance
|
||||||
|
*/
|
||||||
|
wasmer_result_t wasmer_module_import_instantiate(wasmer_instance_t **instance,
|
||||||
|
const wasmer_module_t *module,
|
||||||
|
const wasmer_import_object_t *import_object);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new Instance from the given module and imports.
|
* Creates a new Instance from the given module and imports.
|
||||||
* Returns `wasmer_result_t::WASMER_OK` upon success.
|
* Returns `wasmer_result_t::WASMER_OK` upon success.
|
||||||
|
@ -91,11 +91,7 @@ struct wasmer_import_func_t {
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct wasmer_instance_t {
|
struct wasmer_import_object_t {
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
struct wasmer_instance_context_t {
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -117,6 +113,14 @@ struct wasmer_import_t {
|
|||||||
wasmer_import_export_value value;
|
wasmer_import_export_value value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct wasmer_instance_t {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
struct wasmer_instance_context_t {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
struct wasmer_limit_option_t {
|
struct wasmer_limit_option_t {
|
||||||
bool has_some;
|
bool has_some;
|
||||||
uint32_t some;
|
uint32_t some;
|
||||||
@ -318,6 +322,18 @@ wasmer_result_t wasmer_import_func_returns(const wasmer_import_func_t *func,
|
|||||||
wasmer_result_t wasmer_import_func_returns_arity(const wasmer_import_func_t *func,
|
wasmer_result_t wasmer_import_func_returns_arity(const wasmer_import_func_t *func,
|
||||||
uint32_t *result);
|
uint32_t *result);
|
||||||
|
|
||||||
|
/// Frees memory of the given ImportObject
|
||||||
|
void wasmer_import_object_destroy(wasmer_import_object_t *import_object);
|
||||||
|
|
||||||
|
/// Extends an existing import object with new imports
|
||||||
|
wasmer_result_t wasmer_import_object_extend(wasmer_import_object_t *import_object,
|
||||||
|
wasmer_import_t *imports,
|
||||||
|
unsigned int imports_len);
|
||||||
|
|
||||||
|
/// Creates a new empty import object.
|
||||||
|
/// See also `wasmer_import_object_append`
|
||||||
|
wasmer_import_object_t *wasmer_import_object_new();
|
||||||
|
|
||||||
/// Calls an instances exported function by `name` with the provided parameters.
|
/// Calls an instances exported function by `name` with the provided parameters.
|
||||||
/// Results are set using the provided `results` pointer.
|
/// Results are set using the provided `results` pointer.
|
||||||
/// Returns `wasmer_result_t::WASMER_OK` upon success.
|
/// Returns `wasmer_result_t::WASMER_OK` upon success.
|
||||||
@ -337,6 +353,9 @@ void *wasmer_instance_context_data_get(const wasmer_instance_context_t *ctx);
|
|||||||
/// passed to all imported function for instance.
|
/// passed to all imported function for instance.
|
||||||
void wasmer_instance_context_data_set(wasmer_instance_t *instance, void *data_ptr);
|
void wasmer_instance_context_data_set(wasmer_instance_t *instance, void *data_ptr);
|
||||||
|
|
||||||
|
/// Extracts the instance's context and returns it.
|
||||||
|
const wasmer_instance_context_t *wasmer_instance_context_get(wasmer_instance_t *instance);
|
||||||
|
|
||||||
/// Gets the memory within the context at the index `memory_idx`.
|
/// Gets the memory within the context at the index `memory_idx`.
|
||||||
/// The index is always 0 until multiple memories are supported.
|
/// The index is always 0 until multiple memories are supported.
|
||||||
const wasmer_memory_t *wasmer_instance_context_memory(const wasmer_instance_context_t *ctx,
|
const wasmer_memory_t *wasmer_instance_context_memory(const wasmer_instance_context_t *ctx,
|
||||||
@ -418,6 +437,14 @@ wasmer_result_t wasmer_module_deserialize(wasmer_module_t **module,
|
|||||||
/// Frees memory for the given Module
|
/// Frees memory for the given Module
|
||||||
void wasmer_module_destroy(wasmer_module_t *module);
|
void wasmer_module_destroy(wasmer_module_t *module);
|
||||||
|
|
||||||
|
/// Given:
|
||||||
|
/// A prepared `wasmer svm` import-object
|
||||||
|
/// A compiled wasmer module
|
||||||
|
/// Instantiates a wasmer instance
|
||||||
|
wasmer_result_t wasmer_module_import_instantiate(wasmer_instance_t **instance,
|
||||||
|
const wasmer_module_t *module,
|
||||||
|
const wasmer_import_object_t *import_object);
|
||||||
|
|
||||||
/// Creates a new Instance from the given module and imports.
|
/// Creates a new Instance from the given module and imports.
|
||||||
/// Returns `wasmer_result_t::WASMER_OK` upon success.
|
/// Returns `wasmer_result_t::WASMER_OK` upon success.
|
||||||
/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
|
/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
|
||||||
|
@ -8,46 +8,46 @@ repository = "https://github.com/wasmerio/wasmer"
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
nix = "0.14.0"
|
nix = "0.14.1"
|
||||||
page_size = "0.4.1"
|
page_size = "0.4.1"
|
||||||
wasmparser = "0.35.1"
|
wasmparser = "0.35.1"
|
||||||
parking_lot = "0.7.1"
|
parking_lot = "0.9.0"
|
||||||
lazy_static = "1.2.0"
|
lazy_static = "1.3.0"
|
||||||
indexmap = "1.0.2"
|
|
||||||
errno = "0.2.4"
|
errno = "0.2.4"
|
||||||
libc = "0.2.49"
|
libc = "0.2.60"
|
||||||
hex = "0.3.2"
|
hex = "0.3.2"
|
||||||
smallvec = "0.6.9"
|
smallvec = "0.6.10"
|
||||||
bincode = "1.1"
|
bincode = "1.1"
|
||||||
colored = "1.8"
|
colored = "1.8"
|
||||||
|
|
||||||
|
[dependencies.indexmap]
|
||||||
|
version = "1.0.2"
|
||||||
|
features = ["serde-1"]
|
||||||
|
|
||||||
# Dependencies for caching.
|
# Dependencies for caching.
|
||||||
[dependencies.serde]
|
[dependencies.serde]
|
||||||
version = "1.0"
|
version = "1.0.98"
|
||||||
# This feature is required for serde to support serializing/deserializing reference counted pointers (e.g. Rc and Arc).
|
# This feature is required for serde to support serializing/deserializing reference counted pointers (e.g. Rc and Arc).
|
||||||
features = ["rc"]
|
features = ["rc"]
|
||||||
[dependencies.serde_derive]
|
[dependencies.serde_derive]
|
||||||
version = "1.0"
|
version = "1.0.98"
|
||||||
[dependencies.serde_bytes]
|
[dependencies.serde_bytes]
|
||||||
version = "0.10"
|
version = "0.11.1"
|
||||||
[dependencies.serde-bench]
|
[dependencies.serde-bench]
|
||||||
version = "0.0.7"
|
version = "0.0.7"
|
||||||
[dependencies.blake2b_simd]
|
[dependencies.blake2b_simd]
|
||||||
version = "0.4.1"
|
version = "0.5.5"
|
||||||
[dependencies.digest]
|
[dependencies.digest]
|
||||||
version = "0.8.0"
|
version = "0.8.1"
|
||||||
[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.7", features = ["memoryapi"] }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
field-offset = "0.1.1"
|
field-offset = "0.1.1"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
blake2b_simd = "0.4.1"
|
blake2b_simd = "0.5.5"
|
||||||
rustc_version = "0.2.3"
|
rustc_version = "0.2.3"
|
||||||
cc = "1.0"
|
cc = "1.0"
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ use crate::{
|
|||||||
};
|
};
|
||||||
use std::{any::Any, ptr::NonNull};
|
use std::{any::Any, ptr::NonNull};
|
||||||
|
|
||||||
use hashbrown::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
pub mod sys {
|
pub mod sys {
|
||||||
pub use crate::sys::*;
|
pub use crate::sys::*;
|
||||||
|
@ -146,7 +146,7 @@ pub fn validating_parser_config(features: &Features) -> wasmparser::ValidatingPa
|
|||||||
enable_bulk_memory: false,
|
enable_bulk_memory: false,
|
||||||
enable_multi_value: false,
|
enable_multi_value: false,
|
||||||
},
|
},
|
||||||
mutable_global_imports: false,
|
mutable_global_imports: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,7 +134,7 @@ impl std::fmt::Display for RuntimeError {
|
|||||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
RuntimeError::Trap { ref msg } => {
|
RuntimeError::Trap { ref msg } => {
|
||||||
write!(f, "WebAssembly trap occured during runtime: {}", msg)
|
write!(f, "WebAssembly trap occurred during runtime: {}", msg)
|
||||||
}
|
}
|
||||||
RuntimeError::Error { data } => {
|
RuntimeError::Error { data } => {
|
||||||
if let Some(s) = data.downcast_ref::<String>() {
|
if let Some(s) = data.downcast_ref::<String>() {
|
||||||
|
@ -2,7 +2,7 @@ use crate::{
|
|||||||
global::Global, instance::InstanceInner, memory::Memory, module::ExportIndex,
|
global::Global, instance::InstanceInner, memory::Memory, module::ExportIndex,
|
||||||
module::ModuleInner, table::Table, types::FuncSig, vm,
|
module::ModuleInner, table::Table, types::FuncSig, vm,
|
||||||
};
|
};
|
||||||
use hashbrown::hash_map;
|
use indexmap::map::Iter as IndexMapIter;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
@ -41,7 +41,7 @@ impl FuncPointer {
|
|||||||
|
|
||||||
pub struct ExportIter<'a> {
|
pub struct ExportIter<'a> {
|
||||||
inner: &'a InstanceInner,
|
inner: &'a InstanceInner,
|
||||||
iter: hash_map::Iter<'a, String, ExportIndex>,
|
iter: IndexMapIter<'a, String, ExportIndex>,
|
||||||
module: &'a ModuleInner,
|
module: &'a ModuleInner,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use crate::export::Export;
|
use crate::export::Export;
|
||||||
use hashbrown::{hash_map::Entry, HashMap};
|
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
|
use std::collections::{hash_map::Entry, HashMap};
|
||||||
use std::{
|
use std::{
|
||||||
cell::{Ref, RefCell},
|
cell::{Ref, RefCell},
|
||||||
ffi::c_void,
|
ffi::c_void,
|
||||||
@ -51,7 +51,7 @@ pub struct ImportObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ImportObject {
|
impl ImportObject {
|
||||||
/// Create a new `ImportObject`.
|
/// Create a new `ImportObject`.
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
map: Rc::new(RefCell::new(HashMap::new())),
|
map: Rc::new(RefCell::new(HashMap::new())),
|
||||||
|
@ -1,4 +1,10 @@
|
|||||||
#![deny(unused_imports, unused_variables, unused_unsafe, unreachable_patterns)]
|
#![deny(
|
||||||
|
dead_code,
|
||||||
|
unused_imports,
|
||||||
|
unused_variables,
|
||||||
|
unused_unsafe,
|
||||||
|
unreachable_patterns
|
||||||
|
)]
|
||||||
#![cfg_attr(nightly, feature(unwind_attributes))]
|
#![cfg_attr(nightly, feature(unwind_attributes))]
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@ -134,7 +140,7 @@ pub fn validate_and_report_errors_with_features(
|
|||||||
enable_reference_types: false,
|
enable_reference_types: false,
|
||||||
enable_threads: false,
|
enable_threads: false,
|
||||||
},
|
},
|
||||||
mutable_global_imports: false,
|
mutable_global_imports: true,
|
||||||
};
|
};
|
||||||
let mut parser = wasmparser::ValidatingParser::new(wasm, Some(config));
|
let mut parser = wasmparser::ValidatingParser::new(wasm, Some(config));
|
||||||
loop {
|
loop {
|
||||||
|
@ -14,8 +14,8 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crate::backend::CacheGen;
|
use crate::backend::CacheGen;
|
||||||
use hashbrown::HashMap;
|
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// This is used to instantiate a new WebAssembly module.
|
/// This is used to instantiate a new WebAssembly module.
|
||||||
@ -40,7 +40,7 @@ pub struct ModuleInfo {
|
|||||||
pub imported_tables: Map<ImportedTableIndex, (ImportName, TableDescriptor)>,
|
pub imported_tables: Map<ImportedTableIndex, (ImportName, TableDescriptor)>,
|
||||||
pub imported_globals: Map<ImportedGlobalIndex, (ImportName, GlobalDescriptor)>,
|
pub imported_globals: Map<ImportedGlobalIndex, (ImportName, GlobalDescriptor)>,
|
||||||
|
|
||||||
pub exports: HashMap<String, ExportIndex>,
|
pub exports: IndexMap<String, ExportIndex>,
|
||||||
|
|
||||||
pub data_initializers: Vec<DataInitializer>,
|
pub data_initializers: Vec<DataInitializer>,
|
||||||
pub elem_initializers: Vec<TableInitializer>,
|
pub elem_initializers: Vec<TableInitializer>,
|
||||||
|
@ -14,7 +14,7 @@ use crate::{
|
|||||||
},
|
},
|
||||||
units::Pages,
|
units::Pages,
|
||||||
};
|
};
|
||||||
use hashbrown::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::sync::{Arc, RwLock};
|
use std::sync::{Arc, RwLock};
|
||||||
use wasmparser::{
|
use wasmparser::{
|
||||||
|
@ -2,9 +2,9 @@ use crate::{
|
|||||||
structures::Map,
|
structures::Map,
|
||||||
types::{FuncSig, SigIndex},
|
types::{FuncSig, SigIndex},
|
||||||
};
|
};
|
||||||
use hashbrown::HashMap;
|
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
|
@ -100,6 +100,7 @@ pub struct InstanceImage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ModuleStateMap {
|
impl ModuleStateMap {
|
||||||
|
#[warn(dead_code)]
|
||||||
fn lookup_call_ip(&self, ip: usize, base: usize) -> Option<(&FunctionStateMap, MachineState)> {
|
fn lookup_call_ip(&self, ip: usize, base: usize) -> Option<(&FunctionStateMap, MachineState)> {
|
||||||
if ip < base || ip - base >= self.total_size {
|
if ip < base || ip - base >= self.total_size {
|
||||||
None
|
None
|
||||||
@ -123,6 +124,7 @@ impl ModuleStateMap {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[warn(dead_code)]
|
||||||
fn lookup_trappable_ip(
|
fn lookup_trappable_ip(
|
||||||
&self,
|
&self,
|
||||||
ip: usize,
|
ip: usize,
|
||||||
@ -150,6 +152,7 @@ impl ModuleStateMap {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[warn(dead_code)]
|
||||||
fn lookup_loop_ip(&self, ip: usize, base: usize) -> Option<(&FunctionStateMap, MachineState)> {
|
fn lookup_loop_ip(&self, ip: usize, base: usize) -> Option<(&FunctionStateMap, MachineState)> {
|
||||||
if ip < base || ip - base >= self.total_size {
|
if ip < base || ip - base >= self.total_size {
|
||||||
None
|
None
|
||||||
|
@ -16,7 +16,7 @@ use serde::{
|
|||||||
Deserialize, Deserializer, Serialize, Serializer,
|
Deserialize, Deserializer, Serialize, Serializer,
|
||||||
};
|
};
|
||||||
|
|
||||||
use serde_bytes::Bytes;
|
use serde_bytes::{ByteBuf, Bytes};
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
@ -56,7 +56,7 @@ impl<'de> Deserialize<'de> for Memory {
|
|||||||
.next_element()?
|
.next_element()?
|
||||||
.ok_or_else(|| de::Error::invalid_length(0, &self))?;
|
.ok_or_else(|| de::Error::invalid_length(0, &self))?;
|
||||||
|
|
||||||
let bytes: Bytes = seq
|
let bytes: ByteBuf = seq
|
||||||
.next_element()?
|
.next_element()?
|
||||||
.ok_or_else(|| de::Error::invalid_length(1, &self))?;
|
.ok_or_else(|| de::Error::invalid_length(1, &self))?;
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ use std::{
|
|||||||
sync::Once,
|
sync::Once,
|
||||||
};
|
};
|
||||||
|
|
||||||
use hashbrown::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
/// The context of the currently running WebAssembly instance.
|
/// The context of the currently running WebAssembly instance.
|
||||||
///
|
///
|
||||||
@ -850,8 +850,9 @@ mod vm_ctx_tests {
|
|||||||
use crate::cache::Error as CacheError;
|
use crate::cache::Error as CacheError;
|
||||||
use crate::typed_func::Wasm;
|
use crate::typed_func::Wasm;
|
||||||
use crate::types::{LocalFuncIndex, SigIndex};
|
use crate::types::{LocalFuncIndex, SigIndex};
|
||||||
use hashbrown::HashMap;
|
use indexmap::IndexMap;
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::ptr::NonNull;
|
use std::ptr::NonNull;
|
||||||
struct Placeholder;
|
struct Placeholder;
|
||||||
impl RunnableModule for Placeholder {
|
impl RunnableModule for Placeholder {
|
||||||
@ -890,7 +891,7 @@ mod vm_ctx_tests {
|
|||||||
imported_tables: Map::new(),
|
imported_tables: Map::new(),
|
||||||
imported_globals: Map::new(),
|
imported_globals: Map::new(),
|
||||||
|
|
||||||
exports: HashMap::new(),
|
exports: IndexMap::new(),
|
||||||
|
|
||||||
data_initializers: Vec::new(),
|
data_initializers: Vec::new(),
|
||||||
elem_initializers: Vec::new(),
|
elem_initializers: Vec::new(),
|
||||||
|
@ -10,7 +10,7 @@ readme = "README.md"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.6.0", optional = true }
|
wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.6.0", optional = true }
|
||||||
lazy_static = "1.2.0"
|
lazy_static = "1.3.0"
|
||||||
memmap = "0.7.0"
|
memmap = "0.7.0"
|
||||||
|
|
||||||
[dependencies.wasmer-runtime-core]
|
[dependencies.wasmer-runtime-core]
|
||||||
@ -23,7 +23,7 @@ version = "0.6.0"
|
|||||||
optional = true
|
optional = true
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
tempfile = "3.0.7"
|
tempfile = "3.1.0"
|
||||||
criterion = "0.2"
|
criterion = "0.2"
|
||||||
wabt = "0.9.0"
|
wabt = "0.9.0"
|
||||||
|
|
||||||
|
@ -1,5 +1,10 @@
|
|||||||
#![deny(unused_imports, unused_variables, unused_unsafe, unreachable_patterns)]
|
#![deny(
|
||||||
|
dead_code,
|
||||||
|
unused_imports,
|
||||||
|
unused_variables,
|
||||||
|
unused_unsafe,
|
||||||
|
unreachable_patterns
|
||||||
|
)]
|
||||||
//! Wasmer-runtime is a library that makes embedding WebAssembly
|
//! Wasmer-runtime is a library that makes embedding WebAssembly
|
||||||
//! in your application easy, efficient, and safe.
|
//! in your application easy, efficient, and safe.
|
||||||
//!
|
//!
|
||||||
|
@ -13,10 +13,9 @@ wasmer-runtime-core = { path = "../runtime-core", version = "0.6.0" }
|
|||||||
wasmparser = "0.35.1"
|
wasmparser = "0.35.1"
|
||||||
dynasm = "0.3.2"
|
dynasm = "0.3.2"
|
||||||
dynasmrt = "0.3.1"
|
dynasmrt = "0.3.1"
|
||||||
lazy_static = "1.2.0"
|
lazy_static = "1.3.0"
|
||||||
byteorder = "1"
|
byteorder = "1.3.2"
|
||||||
nix = "0.14.0"
|
nix = "0.14.1"
|
||||||
libc = "0.2.49"
|
libc = "0.2.60"
|
||||||
smallvec = "0.6.9"
|
smallvec = "0.6.10"
|
||||||
hashbrown = "0.1"
|
|
||||||
colored = "1.8"
|
colored = "1.8"
|
||||||
|
@ -1,4 +1,10 @@
|
|||||||
#![deny(unused_imports, unused_variables, unused_unsafe, unreachable_patterns)]
|
#![deny(
|
||||||
|
dead_code,
|
||||||
|
unused_imports,
|
||||||
|
unused_variables,
|
||||||
|
unused_unsafe,
|
||||||
|
unreachable_patterns
|
||||||
|
)]
|
||||||
#![feature(proc_macro_hygiene)]
|
#![feature(proc_macro_hygiene)]
|
||||||
|
|
||||||
#[cfg(not(any(
|
#[cfg(not(any(
|
||||||
|
@ -132,7 +132,7 @@ fn get_compiler() -> impl Compiler {
|
|||||||
CraneliftCompiler::new()
|
CraneliftCompiler::new()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate_imports() -> ImportObject {
|
pub fn generate_imports(extra_imports: Vec<(String, Instance)>) -> ImportObject {
|
||||||
let mut features = wabt::Features::new();
|
let mut features = wabt::Features::new();
|
||||||
features.enable_simd();
|
features.enable_simd();
|
||||||
let wasm_binary = wat2wasm_with_features(IMPORT_MODULE.as_bytes(), features).expect("WAST not valid or malformed");
|
let wasm_binary = wat2wasm_with_features(IMPORT_MODULE.as_bytes(), features).expect("WAST not valid or malformed");
|
||||||
@ -143,6 +143,9 @@ pub fn generate_imports() -> ImportObject {
|
|||||||
.expect("WASM can't be instantiated");
|
.expect("WASM can't be instantiated");
|
||||||
let mut imports = ImportObject::new();
|
let mut imports = ImportObject::new();
|
||||||
imports.register("spectest", instance);
|
imports.register("spectest", instance);
|
||||||
|
for (name, instance) in extra_imports {
|
||||||
|
imports.register(name, instance);
|
||||||
|
}
|
||||||
imports
|
imports
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -303,6 +306,8 @@ struct WastTestGenerator {
|
|||||||
script_parser: ScriptParser,
|
script_parser: ScriptParser,
|
||||||
module_calls: HashMap<i32, Vec<String>>,
|
module_calls: HashMap<i32, Vec<String>>,
|
||||||
buffer: String,
|
buffer: String,
|
||||||
|
modules_by_name: HashMap<String, i32>,
|
||||||
|
registered_modules: Vec<(i32, String)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WastTestGenerator {
|
impl WastTestGenerator {
|
||||||
@ -322,6 +327,8 @@ impl WastTestGenerator {
|
|||||||
script_parser: script,
|
script_parser: script,
|
||||||
buffer: buffer,
|
buffer: buffer,
|
||||||
module_calls: HashMap::new(),
|
module_calls: HashMap::new(),
|
||||||
|
modules_by_name: HashMap::new(),
|
||||||
|
registered_modules: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -392,7 +399,7 @@ fn test_module_{}() {{
|
|||||||
self.module_calls.remove(&module);
|
self.module_calls.remove(&module);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_module(&mut self, module: &ModuleBinary, _name: &Option<String>) {
|
fn visit_module(&mut self, module: &ModuleBinary, name: &Option<String>) {
|
||||||
let wasm_binary: Vec<u8> = module.clone().into_vec();
|
let wasm_binary: Vec<u8> = module.clone().into_vec();
|
||||||
let mut features = Features::new();
|
let mut features = Features::new();
|
||||||
features.enable_simd();
|
features.enable_simd();
|
||||||
@ -409,7 +416,9 @@ fn test_module_{}() {{
|
|||||||
println!(\"{{}}\", module_str);
|
println!(\"{{}}\", module_str);
|
||||||
let wasm_binary = wat2wasm(module_str.as_bytes()).expect(\"WAST not valid or malformed\");
|
let wasm_binary = wat2wasm(module_str.as_bytes()).expect(\"WAST not valid or malformed\");
|
||||||
let module = wasmer_runtime_core::compile_with_config(&wasm_binary[..], &get_compiler(), CompilerConfig {{ features: Features {{ simd: true }}, ..Default::default() }}).expect(\"WASM can't be compiled\");
|
let module = wasmer_runtime_core::compile_with_config(&wasm_binary[..], &get_compiler(), CompilerConfig {{ features: Features {{ simd: true }}, ..Default::default() }}).expect(\"WASM can't be compiled\");
|
||||||
module.instantiate(&generate_imports()).expect(\"WASM can't be instantiated\")
|
let mut extra_imports = Vec::new();
|
||||||
|
{}
|
||||||
|
module.instantiate(&generate_imports(extra_imports)).expect(\"WASM can't be instantiated\")
|
||||||
}}\n",
|
}}\n",
|
||||||
self.last_module,
|
self.last_module,
|
||||||
// We do this to ident four spaces, so it looks aligned to the function body
|
// We do this to ident four spaces, so it looks aligned to the function body
|
||||||
@ -417,9 +426,22 @@ fn test_module_{}() {{
|
|||||||
.replace("\n", "\n ")
|
.replace("\n", "\n ")
|
||||||
.replace("\\", "\\\\")
|
.replace("\\", "\\\\")
|
||||||
.replace("\"", "\\\""),
|
.replace("\"", "\\\""),
|
||||||
|
self.registered_modules.iter().map(|(number, name)| format!("extra_imports.push((String::from(\"{}\"), create_module_{}()));", name, number)).fold(String::from(""), |acc, x| format!("{}{}\n", acc, x)),
|
||||||
)
|
)
|
||||||
.as_str(),
|
.as_str(),
|
||||||
);
|
);
|
||||||
|
if let Some(name) = name {
|
||||||
|
self.record_named_module(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn record_named_module(&mut self, name: &String) {
|
||||||
|
self.modules_by_name.insert(name.clone(), self.last_module);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_register_module(&mut self, name: &String, as_name: &String) {
|
||||||
|
self.registered_modules
|
||||||
|
.push((*self.modules_by_name.get(name).unwrap(), as_name.clone()));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_assert_invalid(&mut self, module: &ModuleBinary) {
|
fn visit_assert_invalid(&mut self, module: &ModuleBinary) {
|
||||||
@ -763,11 +785,8 @@ fn {}() {{
|
|||||||
} => {
|
} => {
|
||||||
// Do nothing for now
|
// Do nothing for now
|
||||||
}
|
}
|
||||||
CommandKind::Register {
|
CommandKind::Register { name, as_name } => {
|
||||||
name: _,
|
self.visit_register_module(name.as_ref().unwrap(), as_name);
|
||||||
as_name: _,
|
|
||||||
} => {
|
|
||||||
// Do nothing for now
|
|
||||||
}
|
}
|
||||||
CommandKind::PerformAction(action) => {
|
CommandKind::PerformAction(action) => {
|
||||||
self.visit_perform_action(action);
|
self.visit_perform_action(action);
|
||||||
|
5
lib/spectests/spectests/README.md
vendored
5
lib/spectests/spectests/README.md
vendored
@ -25,7 +25,7 @@ Currently supported command assertions:
|
|||||||
- [x] `assert_malformed` _fully implemented_
|
- [x] `assert_malformed` _fully implemented_
|
||||||
- [ ] `assert_uninstantiable` _not implemented yet_
|
- [ ] `assert_uninstantiable` _not implemented yet_
|
||||||
- [ ] `assert_exhaustion` _not implemented yet_
|
- [ ] `assert_exhaustion` _not implemented yet_
|
||||||
- [ ] `register` _not implemented yet_
|
- [x] `register` _fully implemented_
|
||||||
- [x] `perform_action` _partially implemented, only function invocations for now_
|
- [x] `perform_action` _partially implemented, only function invocations for now_
|
||||||
|
|
||||||
### Covered spec tests
|
### Covered spec tests
|
||||||
@ -86,6 +86,7 @@ The following spec tests are currently covered:
|
|||||||
- [x] return.wast
|
- [x] return.wast
|
||||||
- [x] select.wast
|
- [x] select.wast
|
||||||
- [x] set_local.wast
|
- [x] set_local.wast
|
||||||
|
- [x] simd.wast
|
||||||
- [ ] skip-stack-guard-page.wast
|
- [ ] skip-stack-guard-page.wast
|
||||||
- [x] stack.wast
|
- [x] stack.wast
|
||||||
- [x] start.wast
|
- [x] start.wast
|
||||||
@ -108,8 +109,6 @@ The following spec tests are currently covered:
|
|||||||
|
|
||||||
There are some cases that we decided to skip for now to accelerate the release schedule:
|
There are some cases that we decided to skip for now to accelerate the release schedule:
|
||||||
|
|
||||||
- `SKIP_MUTABLE_GLOBALS`: Right now the Wasm parser can't validate a module with imported/exported `mut` globals. We decided to skip the tests until Cranelift and wasmparser can handle this (see [original spec proposal](https://github.com/WebAssembly/mutable-global)). Spec tests affected:
|
|
||||||
- `globals.wast`
|
|
||||||
- `SKIP_CALL_INDIRECT_TYPE_MISMATCH`: we implemented traps in a fast way. We haven't yet covered the type mismatch on `call_indirect`. Specs affected:
|
- `SKIP_CALL_INDIRECT_TYPE_MISMATCH`: we implemented traps in a fast way. We haven't yet covered the type mismatch on `call_indirect`. Specs affected:
|
||||||
|
|
||||||
- `call_indirect.wast`
|
- `call_indirect.wast`
|
||||||
|
66
lib/spectests/spectests/data.wast
vendored
66
lib/spectests/spectests/data.wast
vendored
@ -47,31 +47,27 @@
|
|||||||
(data (i32.const 1) "h")
|
(data (i32.const 1) "h")
|
||||||
)
|
)
|
||||||
|
|
||||||
;; SKIP_MUTABLE_GLOBALS
|
(module
|
||||||
;; (module
|
(global (import "spectest" "global_i32") i32)
|
||||||
;; (global (import "spectest" "global_i32") i32)
|
(memory 1)
|
||||||
;; (memory 1)
|
(data (get_global 0) "a")
|
||||||
;; (data (get_global 0) "a")
|
)
|
||||||
;; )
|
(module
|
||||||
;; SKIP_MUTABLE_GLOBALS
|
(global (import "spectest" "global_i32") i32)
|
||||||
;; (module
|
(import "spectest" "memory" (memory 1))
|
||||||
;; (global (import "spectest" "global_i32") i32)
|
(data (get_global 0) "a")
|
||||||
;; (import "spectest" "memory" (memory 1))
|
)
|
||||||
;; (data (get_global 0) "a")
|
|
||||||
;; )
|
|
||||||
|
|
||||||
;; SKIP_MUTABLE_GLOBALS
|
(module
|
||||||
;; (module
|
(global $g (import "spectest" "global_i32") i32)
|
||||||
;; (global $g (import "spectest" "global_i32") i32)
|
(memory 1)
|
||||||
;; (memory 1)
|
(data (get_global $g) "a")
|
||||||
;; (data (get_global $g) "a")
|
)
|
||||||
;; )
|
(module
|
||||||
;; SKIP_MUTABLE_GLOBALS
|
(global $g (import "spectest" "global_i32") i32)
|
||||||
;; (module
|
(import "spectest" "memory" (memory 1))
|
||||||
;; (global $g (import "spectest" "global_i32") i32)
|
(data (get_global $g) "a")
|
||||||
;; (import "spectest" "memory" (memory 1))
|
)
|
||||||
;; (data (get_global $g) "a")
|
|
||||||
;; )
|
|
||||||
|
|
||||||
;; Use of internal globals in constant expressions is not allowed in MVP.
|
;; Use of internal globals in constant expressions is not allowed in MVP.
|
||||||
;; (module (memory 1) (data (get_global 0) "a") (global i32 (i32.const 0)))
|
;; (module (memory 1) (data (get_global 0) "a") (global i32 (i32.const 0)))
|
||||||
@ -138,19 +134,17 @@
|
|||||||
(data (i32.const 0) "a")
|
(data (i32.const 0) "a")
|
||||||
)
|
)
|
||||||
|
|
||||||
;; SKIP_MUTABLE_GLOBALS
|
(module
|
||||||
;; (module
|
(global (import "spectest" "global_i32") i32)
|
||||||
;; (global (import "spectest" "global_i32") i32)
|
(import "spectest" "memory" (memory 0))
|
||||||
;; (import "spectest" "memory" (memory 0))
|
(data (get_global 0) "a")
|
||||||
;; (data (get_global 0) "a")
|
)
|
||||||
;; )
|
|
||||||
|
|
||||||
;; SKIP_MUTABLE_GLOBALS
|
(module
|
||||||
;; (module
|
(global (import "spectest" "global_i32") i32)
|
||||||
;; (global (import "spectest" "global_i32") i32)
|
(import "spectest" "memory" (memory 0 3))
|
||||||
;; (import "spectest" "memory" (memory 0 3))
|
(data (get_global 0) "a")
|
||||||
;; (data (get_global 0) "a")
|
)
|
||||||
;; )
|
|
||||||
|
|
||||||
(module
|
(module
|
||||||
(import "spectest" "memory" (memory 0))
|
(import "spectest" "memory" (memory 0))
|
||||||
|
6
lib/spectests/spectests/globals.wast
vendored
6
lib/spectests/spectests/globals.wast
vendored
@ -246,11 +246,9 @@
|
|||||||
)
|
)
|
||||||
|
|
||||||
;; mutable globals can be exported
|
;; mutable globals can be exported
|
||||||
;; SKIP_MUTABLE_GLOBALS
|
(module (global (mut f32) (f32.const 0)) (export "a" (global 0)))
|
||||||
;; (module (global (mut f32) (f32.const 0)) (export "a" (global 0)))
|
|
||||||
|
|
||||||
;; SKIP_MUTABLE_GLOBALS
|
(module (global (export "a") (mut f32) (f32.const 0)))
|
||||||
;; (module (global (export "a") (mut f32) (f32.const 0)))
|
|
||||||
|
|
||||||
(assert_invalid
|
(assert_invalid
|
||||||
(module (global f32 (f32.neg (f32.const 0))))
|
(module (global f32 (f32.neg (f32.const 0))))
|
||||||
|
65
lib/spectests/spectests/simd.wast
vendored
65
lib/spectests/spectests/simd.wast
vendored
@ -9,49 +9,48 @@
|
|||||||
|
|
||||||
;; v128 globals
|
;; v128 globals
|
||||||
|
|
||||||
;; wasmer silently doesn't implement (register) yet
|
(module $M
|
||||||
;;(module $M
|
(global (export "a") v128 (v128.const f32x4 0.0 1.0 2.0 3.0))
|
||||||
;; (global (export "a") v128 (v128.const f32x4 0.0 1.0 2.0 3.0))
|
(global (export "b") (mut v128) (v128.const f32x4 4.0 5.0 6.0 7.0))
|
||||||
;; (global (export "b") (mut v128) (v128.const f32x4 4.0 5.0 6.0 7.0))
|
)
|
||||||
;;)
|
(register "M" $M)
|
||||||
;;(register "M" $M)
|
|
||||||
|
|
||||||
(module
|
(module
|
||||||
;; (global $a (import "M" "a") v128)
|
(global $a (import "M" "a") v128)
|
||||||
;; (global $b (import "M" "b") (mut v128))
|
(global $b (import "M" "b") (mut v128))
|
||||||
|
|
||||||
;; (global $c v128 (global.get $a))
|
(global $c v128 (global.get $a))
|
||||||
(global $d v128 (v128.const i32x4 8 9 10 11))
|
(global $d v128 (v128.const i32x4 8 9 10 11))
|
||||||
;; (global $e (mut v128) (global.get $a))
|
(global $e (mut v128) (global.get $a))
|
||||||
;; (global $f (mut v128) (v128.const i32x4 12 13 14 15))
|
(global $f (mut v128) (v128.const i32x4 12 13 14 15))
|
||||||
|
|
||||||
;; (func (export "get-a") (result v128) (global.get $a))
|
(func (export "get-a") (result v128) (global.get $a))
|
||||||
;; (func (export "get-b") (result v128) (global.get $b))
|
(func (export "get-b") (result v128) (global.get $b))
|
||||||
;; (func (export "get-c") (result v128) (global.get $c))
|
(func (export "get-c") (result v128) (global.get $c))
|
||||||
(func (export "get-d") (result v128) (global.get $d))
|
(func (export "get-d") (result v128) (global.get $d))
|
||||||
;; (func (export "get-e") (result v128) (global.get $e))
|
(func (export "get-e") (result v128) (global.get $e))
|
||||||
;; (func (export "get-f") (result v128) (global.get $f))
|
(func (export "get-f") (result v128) (global.get $f))
|
||||||
|
|
||||||
;; (func (export "set-b") (param $value v128) (global.set $b (local.get $value)))
|
(func (export "set-b") (param $value v128) (global.set $b (local.get $value)))
|
||||||
;; (func (export "set-e") (param $value v128) (global.set $e (local.get $value)))
|
(func (export "set-e") (param $value v128) (global.set $e (local.get $value)))
|
||||||
;; (func (export "set-f") (param $value v128) (global.set $f (local.get $value)))
|
(func (export "set-f") (param $value v128) (global.set $f (local.get $value)))
|
||||||
)
|
)
|
||||||
|
|
||||||
;;(assert_return (invoke "get-a") (v128.const f32x4 0.0 1.0 2.0 3.0))
|
(assert_return (invoke "get-a") (v128.const f32x4 0.0 1.0 2.0 3.0))
|
||||||
;;(assert_return (invoke "get-b") (v128.const f32x4 4.0 5.0 6.0 7.0))
|
(assert_return (invoke "get-b") (v128.const f32x4 4.0 5.0 6.0 7.0))
|
||||||
;;(assert_return (invoke "get-c") (v128.const f32x4 0.0 1.0 2.0 3.0))
|
(assert_return (invoke "get-c") (v128.const f32x4 0.0 1.0 2.0 3.0))
|
||||||
(assert_return (invoke "get-d") (v128.const i32x4 8 9 10 11))
|
(assert_return (invoke "get-d") (v128.const i32x4 8 9 10 11))
|
||||||
;;(assert_return (invoke "get-e") (v128.const f32x4 0.0 1.0 2.0 3.0))
|
(assert_return (invoke "get-e") (v128.const f32x4 0.0 1.0 2.0 3.0))
|
||||||
;;(assert_return (invoke "get-f") (v128.const i32x4 12 13 14 15))
|
(assert_return (invoke "get-f") (v128.const i32x4 12 13 14 15))
|
||||||
|
|
||||||
;;(invoke "set-b" (v128.const f64x2 nan:0x1 nan:0x2))
|
(invoke "set-b" (v128.const f64x2 nan:0x1 nan:0x2))
|
||||||
;;(assert_return (invoke "get-b") (v128.const f64x2 nan:0x1 nan:0x2))
|
(assert_return (invoke "get-b") (v128.const f64x2 nan:0x1 nan:0x2))
|
||||||
;;
|
|
||||||
;;(invoke "set-e" (v128.const f64x2 -nan:0x3 +inf))
|
(invoke "set-e" (v128.const f64x2 -nan:0x3 +inf))
|
||||||
;;(assert_return (invoke "get-e") (v128.const f64x2 -nan:0x3 +inf))
|
(assert_return (invoke "get-e") (v128.const f64x2 -nan:0x3 +inf))
|
||||||
;;
|
|
||||||
;;(invoke "set-f" (v128.const f32x4 -inf +3.14 10.0e30 +nan:0x42))
|
(invoke "set-f" (v128.const f32x4 -inf +3.14 10.0e30 +nan:0x42))
|
||||||
;;(assert_return (invoke "get-f") (v128.const f32x4 -inf +3.14 10.0e30 +nan:0x42))
|
(assert_return (invoke "get-f") (v128.const f32x4 -inf +3.14 10.0e30 +nan:0x42))
|
||||||
|
|
||||||
(assert_invalid (module (global v128 (i32.const 0))) "invalid initializer expression")
|
(assert_invalid (module (global v128 (i32.const 0))) "invalid initializer expression")
|
||||||
(assert_invalid (module (global v128 (i64.const 0))) "invalid initializer expression")
|
(assert_invalid (module (global v128 (i64.const 0))) "invalid initializer expression")
|
||||||
|
@ -17,7 +17,7 @@ wasmer-llvm-backend = { path = "../llvm-backend", version = "0.6.0", optional =
|
|||||||
|
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
glob = "0.2.11"
|
glob = "0.3.0"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
wasmer-clif-backend = { path = "../clif-backend", version = "0.6.0" }
|
wasmer-clif-backend = { path = "../clif-backend", version = "0.6.0" }
|
||||||
|
@ -9,13 +9,12 @@ edition = "2018"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
wasmer-runtime-core = { path = "../runtime-core", version = "0.6.0" }
|
wasmer-runtime-core = { path = "../runtime-core", version = "0.6.0" }
|
||||||
libc = "0.2.50"
|
libc = "0.2.60"
|
||||||
rand = "0.6.5"
|
rand = "0.7.0"
|
||||||
# wasmer-runtime-abi = { path = "../runtime-abi" }
|
# wasmer-runtime-abi = { path = "../runtime-abi" }
|
||||||
hashbrown = "0.1.8"
|
|
||||||
generational-arena = "0.2.2"
|
generational-arena = "0.2.2"
|
||||||
log = "0.4.6"
|
log = "0.4.8"
|
||||||
byteorder = "1.3.1"
|
byteorder = "1.3.2"
|
||||||
|
|
||||||
[target.'cfg(windows)'.dependencies]
|
[target.'cfg(windows)'.dependencies]
|
||||||
winapi = "0.3"
|
winapi = "0.3.7"
|
||||||
|
@ -1,5 +1,10 @@
|
|||||||
#![deny(unused_imports, unused_variables, unused_unsafe, unreachable_patterns)]
|
#![deny(
|
||||||
|
dead_code,
|
||||||
|
unused_imports,
|
||||||
|
unused_variables,
|
||||||
|
unused_unsafe,
|
||||||
|
unreachable_patterns
|
||||||
|
)]
|
||||||
#[cfg(target = "windows")]
|
#[cfg(target = "windows")]
|
||||||
extern crate winapi;
|
extern crate winapi;
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
use crate::syscalls::types::*;
|
use crate::syscalls::types::*;
|
||||||
use generational_arena::Arena;
|
use generational_arena::Arena;
|
||||||
pub use generational_arena::Index as Inode;
|
pub use generational_arena::Index as Inode;
|
||||||
use hashbrown::hash_map::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::{
|
use std::{
|
||||||
borrow::Borrow,
|
borrow::Borrow,
|
||||||
cell::Cell,
|
cell::Cell,
|
||||||
|
@ -9,10 +9,10 @@ edition = "2018"
|
|||||||
|
|
||||||
[target.'cfg(windows)'.dependencies]
|
[target.'cfg(windows)'.dependencies]
|
||||||
wasmer-runtime-core = { path = "../runtime-core", version = "0.6.0" }
|
wasmer-runtime-core = { path = "../runtime-core", version = "0.6.0" }
|
||||||
winapi = { version = "0.3", features = ["winbase", "errhandlingapi", "minwindef", "minwinbase", "winnt"] }
|
winapi = { version = "0.3.7", features = ["winbase", "errhandlingapi", "minwindef", "minwinbase", "winnt"] }
|
||||||
libc = "0.2.49"
|
libc = "0.2.60"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
cmake = "0.1.35"
|
cmake = "0.1.40"
|
||||||
bindgen = "0.46.0"
|
bindgen = "0.51.0"
|
||||||
regex = "1.0.6"
|
regex = "1.2.0"
|
||||||
|
@ -1,5 +1,10 @@
|
|||||||
#![deny(unused_imports, unused_variables, unused_unsafe, unreachable_patterns)]
|
#![deny(
|
||||||
|
dead_code,
|
||||||
|
unused_imports,
|
||||||
|
unused_variables,
|
||||||
|
unused_unsafe,
|
||||||
|
unreachable_patterns
|
||||||
|
)]
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
mod exception_handling;
|
mod exception_handling;
|
||||||
|
|
||||||
|
@ -1,5 +1,10 @@
|
|||||||
#![deny(unused_imports, unused_variables, unused_unsafe, unreachable_patterns)]
|
#![deny(
|
||||||
|
dead_code,
|
||||||
|
unused_imports,
|
||||||
|
unused_variables,
|
||||||
|
unused_unsafe,
|
||||||
|
unreachable_patterns
|
||||||
|
)]
|
||||||
extern crate byteorder;
|
extern crate byteorder;
|
||||||
extern crate structopt;
|
extern crate structopt;
|
||||||
|
|
||||||
|
@ -1,5 +1,10 @@
|
|||||||
#![deny(unused_imports, unused_variables, unused_unsafe, unreachable_patterns)]
|
#![deny(
|
||||||
|
dead_code,
|
||||||
|
unused_imports,
|
||||||
|
unused_variables,
|
||||||
|
unused_unsafe,
|
||||||
|
unreachable_patterns
|
||||||
|
)]
|
||||||
extern crate structopt;
|
extern crate structopt;
|
||||||
|
|
||||||
use std::env;
|
use std::env;
|
||||||
@ -10,7 +15,7 @@ use std::path::PathBuf;
|
|||||||
use std::process::exit;
|
use std::process::exit;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
use hashbrown::HashMap;
|
use std::collections::HashMap;
|
||||||
use structopt::StructOpt;
|
use structopt::StructOpt;
|
||||||
|
|
||||||
use wasmer::*;
|
use wasmer::*;
|
||||||
|
@ -1,5 +1,10 @@
|
|||||||
#![deny(unused_imports, unused_variables, unused_unsafe, unreachable_patterns)]
|
#![deny(
|
||||||
|
dead_code,
|
||||||
|
unused_imports,
|
||||||
|
unused_variables,
|
||||||
|
unused_unsafe,
|
||||||
|
unreachable_patterns
|
||||||
|
)]
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate wasmer_runtime_core;
|
extern crate wasmer_runtime_core;
|
||||||
// extern crate wasmer_emscripten;
|
// extern crate wasmer_emscripten;
|
||||||
|
Loading…
Reference in New Issue
Block a user