Merge branch 'master' into feature/more-wasi-syscalls

This commit is contained in:
Mark McCaskey 2019-08-05 09:55:40 +09:00 committed by GitHub
commit 09acf3e581
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
72 changed files with 1499 additions and 887 deletions

View File

@ -5,6 +5,7 @@ All PRs to the Wasmer repository must add to this file.
Blocks of changes will separated by version increments.
## **[Unreleased]**
- [#609](https://github.com/wasmerio/wasmer/issues/609) Update dependencies
## 0.6.0 - 2019-07-31
- [#603](https://github.com/wasmerio/wasmer/pull/603) Update Wapm-cli, bump version numbers

578
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -19,11 +19,10 @@ include = [
]
[dependencies]
byteorder = "1.3.1"
byteorder = "1.3.2"
errno = "0.2.4"
structopt = "0.2.11"
structopt = "0.2.18"
wabt = "0.9.0"
hashbrown = "0.1.8"
wasmer-clif-backend = { path = "lib/clif-backend" }
wasmer-singlepass-backend = { path = "lib/singlepass-backend", optional = true }
wasmer-middleware-common = { path = "lib/middleware-common" }
@ -62,7 +61,7 @@ members = [
[build-dependencies]
wabt = "0.9.0"
glob = "0.2.11"
glob = "0.3.0"
rustc_version = "0.2.3"
[features]

View File

@ -84,7 +84,7 @@ singlepass: spectests-singlepass emtests-singlepass middleware-singlepass wasite
cranelift: spectests-cranelift emtests-cranelift middleware-cranelift wasitests-cranelift
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

View File

@ -15,26 +15,26 @@ cranelift-codegen = { version = "0.31" }
cranelift-entity = { version = "0.31" }
cranelift-frontend = { package = "wasmer-clif-fork-frontend", version = "0.33" }
cranelift-wasm = { package = "wasmer-clif-fork-wasm", version = "0.33" }
hashbrown = "0.1"
target-lexicon = "0.4.0"
wasmparser = "0.35.1"
byteorder = "1"
nix = "0.14.0"
libc = "0.2.49"
rayon = "1.0"
byteorder = "1.3.2"
nix = "0.14.1"
libc = "0.2.60"
rayon = "1.1.0"
# Dependencies for caching.
[dependencies.serde]
version = "1.0"
version = "1.0.98"
features = ["rc"]
[dependencies.serde_derive]
version = "1.0"
version = "1.0.98"
[dependencies.serde_bytes]
version = "0.10"
version = "0.11.1"
[dependencies.serde-bench]
version = "0.0.7"
[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" }
[features]

View File

@ -1,6 +1,6 @@
use crate::relocation::{ExternalRelocation, TrapSink};
use hashbrown::HashMap;
use std::collections::HashMap;
use std::sync::Arc;
use wasmer_runtime_core::{
backend::{sys::Memory, CacheGen},

View File

@ -89,10 +89,12 @@ impl ModuleCodeGenerator<CraneliftFunctionCodeGenerator, Caller, CodegenError>
func,
func_translator,
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(),
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");
@ -391,10 +393,8 @@ pub struct CraneliftFunctionCodeGenerator {
func: Function,
func_translator: FuncTranslator,
next_local: usize,
pub clif_signatures: Map<SigIndex, ir::Signature>,
module_info: Arc<RwLock<ModuleInfo>>,
target_config: isa::TargetFrontendConfig,
position: Position,
func_env: FunctionEnvironment,
}
pub struct FunctionEnvironment {
@ -1138,11 +1138,6 @@ impl FunctionCodeGenerator<CodegenError> for CraneliftFunctionCodeGenerator {
//let builder = self.builder.as_mut().unwrap();
//let func_environment = FuncEnv::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() {
return Ok(());
@ -1154,7 +1149,7 @@ impl FunctionCodeGenerator<CodegenError> for CraneliftFunctionCodeGenerator {
&mut self.position,
);
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(())
}

View File

@ -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 code;
mod libcalls;

View File

@ -5,7 +5,7 @@ use cranelift_codegen::{
ir::{self, InstBuilder},
isa, Context,
};
use hashbrown::HashMap;
use std::collections::HashMap;
use std::{iter, mem, ptr::NonNull};
use wasmer_runtime_core::{
backend::sys::{Memory, Protect},

View File

@ -8,4 +8,4 @@ edition = "2018"
repository = "https://github.com/wasmerio/wasmer"
[dependencies]
libc = "0.2.49"
libc = "0.2.60"

View File

@ -20,7 +20,7 @@ wabt = "0.9.0"
wasmer-dev-utils = { path = "../dev-utils", version = "0.6.0"}
[build-dependencies]
glob = "0.2.11"
glob = "0.3.0"
[features]
clif = []

View File

@ -8,15 +8,14 @@ repository = "https://github.com/wasmerio/wasmer"
edition = "2018"
[dependencies]
byteorder = "1"
hashbrown = "0.1"
lazy_static = "1.2.0"
libc = "0.2.49"
time = "0.1.41"
byteorder = "1.3.2"
lazy_static = "1.3.0"
libc = "0.2.60"
time = "0.1.42"
wasmer-runtime-core = { path = "../runtime-core", version = "0.6.0" }
[target.'cfg(windows)'.dependencies]
rand = "0.6"
rand = "0.7.0"
[features]
debug = ["wasmer-runtime-core/debug"]

View File

@ -30,6 +30,7 @@ pub fn call_malloc(ctx: &mut Ctx, size: u32) -> u32 {
.unwrap()
}
#[warn(dead_code)]
pub fn call_malloc_with_cast<T: Copy, Ty>(ctx: &mut Ctx, size: u32) -> WasmPtr<T, Ty> {
WasmPtr::new(call_malloc(ctx, size))
}

View File

@ -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]
extern crate wasmer_runtime_core;
use hashbrown::HashMap;
use lazy_static::lazy_static;
use std::cell::UnsafeCell;
use std::collections::HashMap;
use std::path::PathBuf;
use std::{f64, ffi::c_void};
use wasmer_runtime_core::{
@ -25,11 +30,11 @@ use wasmer_runtime_core::{
};
#[cfg(unix)]
use ::libc::DIR as libcDIR;
use ::libc::DIR as LibcDir;
// We use a placeholder for windows
#[cfg(not(unix))]
type libcDIR = u8;
type LibcDir = u8;
#[macro_use]
mod macros;
@ -93,7 +98,7 @@ pub struct EmscriptenData<'a> {
pub memset: Option<Func<'a, (u32, u32, u32), u32>>,
pub stack_alloc: Option<Func<'a, u32, u32>>,
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_ii: Option<Func<'a, (i32, i32), i32>>,

View File

@ -5,5 +5,5 @@ authors = ["Heyang Zhou <zhy20000919@hotmail.com>"]
edition = "2018"
[dependencies]
libc = "0.2.49"
libc = "0.2.60"
wasmer-runtime-core = { path = "../runtime-core" }

View File

@ -8,12 +8,11 @@ readme = "README.md"
[dependencies]
wasmer-runtime-core = { path = "../runtime-core", version = "0.6.0" }
wasmparser = "0.35.1"
hashbrown = "0.1.8"
smallvec = "0.6.8"
goblin = "0.0.20"
libc = "0.2.49"
nix = "0.14.0"
capstone = { version = "0.5.0", optional = true }
smallvec = "0.6.10"
goblin = "0.0.24"
libc = "0.2.60"
nix = "0.14.1"
capstone = { version = "0.6.0", optional = true }
[dependencies.inkwell]
git = "https://github.com/wasmerio/inkwell"
@ -22,12 +21,12 @@ default-features = false
features = ["llvm8-0", "target-x86"]
[target.'cfg(windows)'.dependencies]
winapi = { version = "0.3", features = ["memoryapi"] }
winapi = { version = "0.3.7", features = ["memoryapi"] }
[build-dependencies]
cc = "1.0"
lazy_static = "1.2.0"
regex = "1.1.0"
lazy_static = "1.3.0"
regex = "1.2.0"
semver = "0.9"
rustc_version = "0.2.3"

View File

@ -7,201 +7,214 @@ extern "C" void __deregister_frame(uint8_t *);
struct MemoryManager : llvm::RuntimeDyld::MemoryManager {
public:
MemoryManager(callbacks_t callbacks) : callbacks(callbacks) {}
MemoryManager(callbacks_t callbacks) : callbacks(callbacks) {}
virtual ~MemoryManager() override {
deregisterEHFrames();
// Deallocate all of the allocated memory.
callbacks.dealloc_memory(code_section.base, code_section.size);
callbacks.dealloc_memory(read_section.base, read_section.size);
callbacks.dealloc_memory(readwrite_section.base, readwrite_section.size);
virtual ~MemoryManager() override {
deregisterEHFrames();
// Deallocate all of the allocated memory.
callbacks.dealloc_memory(code_section.base, code_section.size);
callbacks.dealloc_memory(read_section.base, read_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 {
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 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;
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* allocate_bump(Section& section, uintptr_t& bump_ptr, size_t size, size_t align) {
auto aligner = [](uintptr_t& ptr, size_t align) {
ptr = (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;
// Align the bump pointer to the requires alignment.
aligner(bump_ptr, align);
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;
auto ret_ptr = bump_ptr;
bump_ptr += size;
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;
}
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;
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;
auto read_result = callbacks.protect_memory(
read_section.base, read_section.size, mem_protect_t::PROTECT_READ);
if (read_result != RESULT_OK) {
return 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 &section, 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 {
public:
SymbolLookup(callbacks_t callbacks) : callbacks(callbacks) {}
SymbolLookup(callbacks_t callbacks) : callbacks(callbacks) {}
void lookup(const LookupSet& symbols, OnResolvedFunction OnResolved) {
LookupResult result;
void lookup(const LookupSet &symbols, OnResolvedFunction OnResolved) {
LookupResult result;
for (auto symbol : symbols) {
result.emplace(symbol, symbol_lookup(symbol));
}
OnResolved(result);
for (auto symbol : symbols) {
result.emplace(symbol, symbol_lookup(symbol));
}
llvm::Expected<LookupSet> getResponsibilitySet(const LookupSet &Symbols) {
const std::set<llvm::StringRef> empty;
return empty;
}
OnResolved(result);
}
llvm::Expected<LookupSet> getResponsibilitySet(const LookupSet &Symbols) {
const std::set<llvm::StringRef> empty;
return empty;
}
private:
llvm::JITEvaluatedSymbol symbol_lookup(llvm::StringRef name) {
uint64_t addr = callbacks.lookup_vm_symbol(name.data(), name.size());
llvm::JITEvaluatedSymbol symbol_lookup(llvm::StringRef name) {
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(
const uint8_t *object_start,
size_t object_size,
callbacks_t callbacks
) : memory_manager(std::unique_ptr<MemoryManager>(new MemoryManager(callbacks)))
{
WasmModule::WasmModule(const uint8_t *object_start, size_t object_size,
callbacks_t callbacks)
: memory_manager(
std::unique_ptr<MemoryManager>(new MemoryManager(callbacks))) {
if (auto created_object_file = llvm::object::ObjectFile::createObjectFile(llvm::MemoryBufferRef(
llvm::StringRef((const char *)object_start, object_size), "object"
))) {
object_file = cantFail(std::move(created_object_file));
SymbolLookup symbol_resolver(callbacks);
runtime_dyld = std::unique_ptr<llvm::RuntimeDyld>(new llvm::RuntimeDyld(*memory_manager, symbol_resolver));
if (auto created_object_file =
llvm::object::ObjectFile::createObjectFile(llvm::MemoryBufferRef(
llvm::StringRef((const char *)object_start, object_size),
"object"))) {
object_file = cantFail(std::move(created_object_file));
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->finalizeWithMemoryManagerLocking();
runtime_dyld->loadObject(*object_file);
runtime_dyld->finalizeWithMemoryManagerLocking();
if (runtime_dyld->hasError()) {
_init_failed = true;
return;
}
} else {
_init_failed = true;
if (runtime_dyld->hasError()) {
_init_failed = true;
return;
}
} else {
_init_failed = true;
}
}
void* WasmModule::get_func(llvm::StringRef name) const {
auto symbol = runtime_dyld->getSymbol(name);
return (void*)symbol.getAddress();
void *WasmModule::get_func(llvm::StringRef name) const {
auto symbol = runtime_dyld->getSymbol(name);
return (void *)symbol.getAddress();
}

View File

@ -1,236 +1,220 @@
#include <cstddef>
#include <cstdint>
#include <llvm/ExecutionEngine/RuntimeDyld.h>
#include <exception>
#include <iostream>
#include <sstream>
#include <exception>
typedef enum
{
PROTECT_NONE,
PROTECT_READ,
PROTECT_READ_WRITE,
PROTECT_READ_EXECUTE,
#include <llvm/ExecutionEngine/RuntimeDyld.h>
typedef enum {
PROTECT_NONE,
PROTECT_READ,
PROTECT_READ_WRITE,
PROTECT_READ_EXECUTE,
} mem_protect_t;
typedef enum
{
RESULT_OK,
RESULT_ALLOCATE_FAILURE,
RESULT_PROTECT_FAILURE,
RESULT_DEALLOC_FAILURE,
RESULT_OBJECT_LOAD_FAILURE,
typedef enum {
RESULT_OK,
RESULT_ALLOCATE_FAILURE,
RESULT_PROTECT_FAILURE,
RESULT_DEALLOC_FAILURE,
RESULT_OBJECT_LOAD_FAILURE,
} 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 (*protect_memory_t)(uint8_t *ptr, size_t size, mem_protect_t protect);
typedef result_t (*alloc_memory_t)(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 uintptr_t (*lookup_vm_symbol_t)(const char *name_ptr, size_t length);
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 struct
{
/* Memory management. */
alloc_memory_t alloc_memory;
protect_memory_t protect_memory;
dealloc_memory_t dealloc_memory;
typedef struct {
/* Memory management. */
alloc_memory_t alloc_memory;
protect_memory_t protect_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;
typedef struct
{
size_t data, vtable;
typedef struct {
size_t data, vtable;
} box_any_t;
struct WasmException
{
public:
virtual std::string description() const noexcept = 0;
struct WasmException {
public:
virtual std::string description() const noexcept = 0;
};
struct UncatchableException : WasmException
{
public:
virtual std::string description() const noexcept override
{
return "Uncatchable exception";
}
struct UncatchableException : WasmException {
public:
virtual std::string description() const noexcept override {
return "Uncatchable exception";
}
};
struct UserException : UncatchableException
{
public:
UserException(size_t data, size_t vtable) : error_data({ data, vtable }) {}
struct UserException : UncatchableException {
public:
UserException(size_t data, size_t vtable) : error_data({data, vtable}) {}
virtual std::string description() const noexcept override
{
return "user exception";
}
virtual std::string description() const noexcept override {
return "user exception";
}
// The parts of a `Box<dyn Any>`.
box_any_t error_data;
// The parts of a `Box<dyn Any>`.
box_any_t error_data;
};
struct WasmTrap : UncatchableException
{
public:
enum Type
{
Unreachable = 0,
IncorrectCallIndirectSignature = 1,
MemoryOutOfBounds = 2,
CallIndirectOOB = 3,
IllegalArithmetic = 4,
Unknown,
};
struct BreakpointException : UncatchableException {
public:
BreakpointException(uintptr_t callback) : callback(callback) {}
WasmTrap(Type type) : type(type) {}
virtual std::string description() const noexcept override {
return "breakpoint 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;
}
uintptr_t callback;
};
struct CatchableException : WasmException
{
public:
CatchableException(uint32_t type_id, uint32_t value_num) : type_id(type_id), value_num(value_num) {}
struct WasmTrap : UncatchableException {
public:
enum Type {
Unreachable = 0,
IncorrectCallIndirectSignature = 1,
MemoryOutOfBounds = 2,
CallIndirectOOB = 3,
IllegalArithmetic = 4,
Unknown,
};
virtual std::string description() const noexcept override
{
return "catchable exception";
WasmTrap(Type type) : type(type) {}
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;
}
uint32_t type_id, value_num;
uint64_t values[1];
return out;
}
};
struct WasmModule
{
public:
WasmModule(
const uint8_t *object_start,
size_t object_size,
callbacks_t callbacks);
struct CatchableException : WasmException {
public:
CatchableException(uint32_t type_id, uint32_t value_num)
: type_id(type_id), value_num(value_num) {}
void *get_func(llvm::StringRef name) const;
virtual std::string description() const noexcept override {
return "catchable exception";
}
bool _init_failed = false;
private:
std::unique_ptr<llvm::RuntimeDyld::MemoryManager> memory_manager;
std::unique_ptr<llvm::object::ObjectFile> object_file;
std::unique_ptr<llvm::RuntimeDyld> runtime_dyld;
uint32_t type_id, value_num;
uint64_t values[1];
};
extern "C"
{
result_t module_load(const uint8_t *mem_ptr, size_t mem_size, callbacks_t callbacks, WasmModule **module_out)
{
*module_out = new WasmModule(mem_ptr, mem_size, callbacks);
struct WasmModule {
public:
WasmModule(const uint8_t *object_start, size_t object_size,
callbacks_t callbacks);
if ((*module_out)->_init_failed) {
return RESULT_OBJECT_LOAD_FAILURE;
}
void *get_func(llvm::StringRef name) const;
return RESULT_OK;
}
bool _init_failed = false;
[[noreturn]] void throw_trap(WasmTrap::Type ty) {
throw WasmTrap(ty);
}
private:
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)
{
delete module;
}
extern "C" {
void callback_trampoline(void *, void *);
// 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);
}
result_t module_load(const uint8_t *mem_ptr, size_t mem_size,
callbacks_t callbacks, WasmModule **module_out) {
*module_out = new WasmModule(mem_ptr, mem_size, callbacks);
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) 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;
}
}
if ((*module_out)->_init_failed) {
return RESULT_OBJECT_LOAD_FAILURE;
}
void *get_func_symbol(WasmModule *module, const char *name)
{
return module->get_func(llvm::StringRef(name));
}
}
return RESULT_OK;
}
[[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));
}
}

View File

@ -39,7 +39,8 @@ extern "C" {
fn module_delete(module: *mut LLVMModule);
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,
/// 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.exception.trap") => throw_trap as _,
fn_name!("vm.breakpoint") => throw_breakpoint as _,
_ => ptr::null(),
}

View File

@ -496,6 +496,21 @@ pub struct CodegenError {
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 {
context: Option<Context>,
builder: Option<Builder>,
@ -612,7 +627,14 @@ impl FunctionCodeGenerator<CodegenError> for LLVMFunctionCodeGenerator {
InternalEvent::FunctionBegin(_) | InternalEvent::FunctionEnd => {
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(());
}
InternalEvent::GetInternal(idx) => {

View File

@ -1,4 +1,3 @@
use hashbrown::HashMap;
use inkwell::{
builder::Builder,
context::Context,
@ -9,6 +8,7 @@ use inkwell::{
values::{BasicValue, BasicValueEnum, FloatValue, FunctionValue, IntValue, PointerValue},
AddressSpace,
};
use std::collections::HashMap;
use std::marker::PhantomData;
use wasmer_runtime_core::{
memory::MemoryType,
@ -147,6 +147,7 @@ pub struct Intrinsics {
pub memory_size_shared_import: FunctionValue,
pub throw_trap: FunctionValue,
pub throw_breakpoint: FunctionValue,
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);
let ret_i1_take_i1_i1 = i1_ty.fn_type(&[i1_ty_basic, i1_ty_basic], false);
Self {
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),
@ -525,6 +525,11 @@ impl Intrinsics {
void_ty.fn_type(&[i32_ty_basic], false),
None,
),
throw_breakpoint: module.add_function(
"vm.breakpoint",
void_ty.fn_type(&[i64_ty_basic], false),
None,
),
ctx_ptr_ty,
}
}

View File

@ -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))]
mod backend;

View File

@ -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 metering;

View File

@ -129,7 +129,7 @@ pub fn set_points_used_ctx(ctx: &mut Ctx, value: u64) {
ctx.set_internal(&INTERNAL_FIELD, value);
}
#[cfg(all(test, feature = "singlepass"))]
#[cfg(all(test, any(feature = "singlepass", feature = "llvm")))]
mod tests {
use super::*;
use wabt::wat2wasm;
@ -247,7 +247,7 @@ mod tests {
// verify it returns the correct value
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);
}
@ -276,7 +276,7 @@ mod tests {
_ => 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.
}

View File

@ -8,12 +8,11 @@ repository = "https://github.com/wasmerio/wasmer"
edition = "2018"
[dependencies]
libc = "0.2.50"
libc = "0.2.60"
wasmer-runtime-core = { path = "../runtime-core" }
hashbrown = "0.1"
failure = "0.1"
tar = "0.4"
wasmparser = "0.34.0"
wasmparser = "0.35.1"
zstd = "0.4"
# [target.'cfg(unix)'.dependencies.zbox]

View File

@ -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"))]
#[macro_use]
extern crate failure;

View File

@ -1,7 +1,7 @@
use crate::vfs::file_like::FileLike;
use crate::vfs::vfs_header::{header_from_bytes, ArchiveType, CompressionType};
use crate::vfs::virtual_file::VirtualFile;
use hashbrown::HashMap;
use std::collections::HashMap;
use std::cell::RefCell;
use std::io;
use std::io::Read;

View File

@ -12,7 +12,7 @@ readme = "README.md"
crate-type = ["cdylib", "rlib", "staticlib"]
[dependencies]
libc = "0.2"
libc = "0.2.60"
[dependencies.wasmer-runtime]
path = "../runtime"
@ -27,4 +27,4 @@ debug = ["wasmer-runtime/debug"]
llvm = ["wasmer-runtime/llvm"]
[build-dependencies]
cbindgen = "0.8"
cbindgen = "0.9.0"

View File

@ -10,9 +10,10 @@ use crate::{
};
use libc::c_uint;
use std::{ffi::c_void, ptr, slice, sync::Arc};
use wasmer_runtime::Module;
use wasmer_runtime::{Global, Memory, Module, Table};
use wasmer_runtime_core::{
export::{Context, Export, FuncPointer},
import::ImportObject,
module::ImportName,
types::{FuncSig, Type},
};
@ -25,6 +26,9 @@ pub struct wasmer_import_t {
pub value: wasmer_import_export_value,
}
#[repr(C)]
pub struct wasmer_import_object_t;
#[repr(C)]
#[derive(Clone)]
pub struct wasmer_import_func_t;
@ -37,6 +41,83 @@ pub struct wasmer_import_descriptor_t;
#[derive(Clone)]
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
///
/// 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 {
module: String,
name: String,

View File

@ -3,15 +3,19 @@
use crate::{
error::{update_last_error, CApiError},
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,
module::wasmer_module_t,
value::{wasmer_value, wasmer_value_t, wasmer_value_tag},
wasmer_result_t,
};
use libc::{c_char, c_int, c_void};
use std::{collections::HashMap, ffi::CStr, slice};
use wasmer_runtime::{Ctx, Global, ImportObject, Instance, Memory, Table, Value};
use wasmer_runtime_core::{export::Export, import::Namespace};
use wasmer_runtime::{Ctx, Global, Instance, Memory, Module, Table, Value};
use wasmer_runtime_core::{
export::Export,
import::{ImportObject, Namespace},
};
#[repr(C)]
pub struct wasmer_instance_t;
@ -108,6 +112,45 @@ pub unsafe extern "C" fn wasmer_instantiate(
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.
/// Results are set using the provided `results` pointer.
///

View File

@ -80,8 +80,13 @@
//!
//! [wasmer_h]: ./wasmer.h
//! [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_core;

View File

@ -22,4 +22,6 @@ test-module-exports
test-module-imports
test-module-serialize
test-tables
test-validate
test-validate
test-context
test-module-import-instantiate

View File

@ -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-tables test-tables.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(
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_compile_options(test-validate PRIVATE ${COMPILER_OPTIONS})
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)

Binary file not shown.

View 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))

View File

@ -4,19 +4,17 @@ use std::process::Command;
fn test_c_api() {
let project_tests_dir = concat!(env!("CARGO_MANIFEST_DIR"), "/tests");
run_command("cmake", project_tests_dir, Some("."));
run_command("make", project_tests_dir, Some("-Wdev -Werror=dev"));
run_command("make", project_tests_dir, Some("test"));
run_command("cmake", project_tests_dir, vec!["."]);
run_command("make", project_tests_dir, vec!["-Wdev", "-Werror=dev"]);
run_command("make", project_tests_dir, vec!["test", "ARGS=\"-V\""]);
}
fn run_command(command_str: &str, dir: &str, arg: Option<&str>) {
println!("Running command: `{}` arg: {:?}", command_str, arg);
fn run_command(command_str: &str, dir: &str, args: Vec<&str>) {
println!("Running command: `{}` args: {:?}", command_str, args);
let mut command = Command::new(command_str);
if let Some(a) = arg {
command.arg(a);
}
command.args(&args);
command.current_dir(dir);

View 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;
}

View File

@ -42,8 +42,9 @@ int main()
assert(export_length == 5);
// 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);
printf("Wasmer import export kind: %d (Memory is %d)\n", kind, WASM_MEMORY);
assert(kind == WASM_MEMORY);
wasmer_byte_array export_name = wasmer_export_name(export);

View 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;
}

View File

@ -95,11 +95,7 @@ typedef struct {
typedef struct {
} wasmer_instance_t;
typedef struct {
} wasmer_instance_context_t;
} wasmer_import_object_t;
typedef struct {
@ -119,6 +115,14 @@ typedef struct {
wasmer_import_export_value value;
} wasmer_import_t;
typedef struct {
} wasmer_instance_t;
typedef struct {
} wasmer_instance_context_t;
typedef struct {
bool has_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,
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.
* 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);
/**
* 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`.
* 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);
/**
* 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.
* Returns `wasmer_result_t::WASMER_OK` upon success.

View File

@ -91,11 +91,7 @@ struct wasmer_import_func_t {
};
struct wasmer_instance_t {
};
struct wasmer_instance_context_t {
struct wasmer_import_object_t {
};
@ -117,6 +113,14 @@ struct wasmer_import_t {
wasmer_import_export_value value;
};
struct wasmer_instance_t {
};
struct wasmer_instance_context_t {
};
struct wasmer_limit_option_t {
bool has_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,
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.
/// Results are set using the provided `results` pointer.
/// 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.
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`.
/// The index is always 0 until multiple memories are supported.
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
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.
/// Returns `wasmer_result_t::WASMER_OK` upon success.
/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`

View File

@ -8,46 +8,46 @@ repository = "https://github.com/wasmerio/wasmer"
edition = "2018"
[dependencies]
nix = "0.14.0"
nix = "0.14.1"
page_size = "0.4.1"
wasmparser = "0.35.1"
parking_lot = "0.7.1"
lazy_static = "1.2.0"
indexmap = "1.0.2"
parking_lot = "0.9.0"
lazy_static = "1.3.0"
errno = "0.2.4"
libc = "0.2.49"
libc = "0.2.60"
hex = "0.3.2"
smallvec = "0.6.9"
smallvec = "0.6.10"
bincode = "1.1"
colored = "1.8"
[dependencies.indexmap]
version = "1.0.2"
features = ["serde-1"]
# Dependencies for caching.
[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).
features = ["rc"]
[dependencies.serde_derive]
version = "1.0"
version = "1.0.98"
[dependencies.serde_bytes]
version = "0.10"
version = "0.11.1"
[dependencies.serde-bench]
version = "0.0.7"
[dependencies.blake2b_simd]
version = "0.4.1"
version = "0.5.5"
[dependencies.digest]
version = "0.8.0"
[dependencies.hashbrown]
version = "0.1"
features = ["serde"]
version = "0.8.1"
[target.'cfg(windows)'.dependencies]
winapi = { version = "0.3", features = ["memoryapi"] }
winapi = { version = "0.3.7", features = ["memoryapi"] }
[dev-dependencies]
field-offset = "0.1.1"
[build-dependencies]
blake2b_simd = "0.4.1"
blake2b_simd = "0.5.5"
rustc_version = "0.2.3"
cc = "1.0"

View File

@ -15,7 +15,7 @@ use crate::{
};
use std::{any::Any, ptr::NonNull};
use hashbrown::HashMap;
use std::collections::HashMap;
pub mod sys {
pub use crate::sys::*;

View File

@ -146,7 +146,7 @@ pub fn validating_parser_config(features: &Features) -> wasmparser::ValidatingPa
enable_bulk_memory: false,
enable_multi_value: false,
},
mutable_global_imports: false,
mutable_global_imports: true,
}
}

View File

@ -134,7 +134,7 @@ impl std::fmt::Display for RuntimeError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
RuntimeError::Trap { ref msg } => {
write!(f, "WebAssembly trap occured during runtime: {}", msg)
write!(f, "WebAssembly trap occurred during runtime: {}", msg)
}
RuntimeError::Error { data } => {
if let Some(s) = data.downcast_ref::<String>() {

View File

@ -2,7 +2,7 @@ use crate::{
global::Global, instance::InstanceInner, memory::Memory, module::ExportIndex,
module::ModuleInner, table::Table, types::FuncSig, vm,
};
use hashbrown::hash_map;
use indexmap::map::Iter as IndexMapIter;
use std::sync::Arc;
#[derive(Debug, Copy, Clone)]
@ -41,7 +41,7 @@ impl FuncPointer {
pub struct ExportIter<'a> {
inner: &'a InstanceInner,
iter: hash_map::Iter<'a, String, ExportIndex>,
iter: IndexMapIter<'a, String, ExportIndex>,
module: &'a ModuleInner,
}

View File

@ -1,6 +1,6 @@
use crate::export::Export;
use hashbrown::{hash_map::Entry, HashMap};
use std::collections::VecDeque;
use std::collections::{hash_map::Entry, HashMap};
use std::{
cell::{Ref, RefCell},
ffi::c_void,
@ -51,7 +51,7 @@ pub struct ImportObject {
}
impl ImportObject {
/// Create a new `ImportObject`.
/// Create a new `ImportObject`.
pub fn new() -> Self {
Self {
map: Rc::new(RefCell::new(HashMap::new())),

View File

@ -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(test)]
@ -134,7 +140,7 @@ pub fn validate_and_report_errors_with_features(
enable_reference_types: false,
enable_threads: false,
},
mutable_global_imports: false,
mutable_global_imports: true,
};
let mut parser = wasmparser::ValidatingParser::new(wasm, Some(config));
loop {

View File

@ -14,8 +14,8 @@ use crate::{
};
use crate::backend::CacheGen;
use hashbrown::HashMap;
use indexmap::IndexMap;
use std::collections::HashMap;
use std::sync::Arc;
/// 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_globals: Map<ImportedGlobalIndex, (ImportName, GlobalDescriptor)>,
pub exports: HashMap<String, ExportIndex>,
pub exports: IndexMap<String, ExportIndex>,
pub data_initializers: Vec<DataInitializer>,
pub elem_initializers: Vec<TableInitializer>,

View File

@ -14,7 +14,7 @@ use crate::{
},
units::Pages,
};
use hashbrown::HashMap;
use std::collections::HashMap;
use std::fmt::Debug;
use std::sync::{Arc, RwLock};
use wasmparser::{

View File

@ -2,9 +2,9 @@ use crate::{
structures::Map,
types::{FuncSig, SigIndex},
};
use hashbrown::HashMap;
use lazy_static::lazy_static;
use parking_lot::RwLock;
use std::collections::HashMap;
use std::sync::Arc;
lazy_static! {

View File

@ -100,6 +100,7 @@ pub struct InstanceImage {
}
impl ModuleStateMap {
#[warn(dead_code)]
fn lookup_call_ip(&self, ip: usize, base: usize) -> Option<(&FunctionStateMap, MachineState)> {
if ip < base || ip - base >= self.total_size {
None
@ -123,6 +124,7 @@ impl ModuleStateMap {
}
}
#[warn(dead_code)]
fn lookup_trappable_ip(
&self,
ip: usize,
@ -150,6 +152,7 @@ impl ModuleStateMap {
}
}
#[warn(dead_code)]
fn lookup_loop_ip(&self, ip: usize, base: usize) -> Option<(&FunctionStateMap, MachineState)> {
if ip < base || ip - base >= self.total_size {
None

View File

@ -16,7 +16,7 @@ use serde::{
Deserialize, Deserializer, Serialize, Serializer,
};
use serde_bytes::Bytes;
use serde_bytes::{ByteBuf, Bytes};
use std::fmt;
@ -56,7 +56,7 @@ impl<'de> Deserialize<'de> for Memory {
.next_element()?
.ok_or_else(|| de::Error::invalid_length(0, &self))?;
let bytes: Bytes = seq
let bytes: ByteBuf = seq
.next_element()?
.ok_or_else(|| de::Error::invalid_length(1, &self))?;

View File

@ -14,7 +14,7 @@ use std::{
sync::Once,
};
use hashbrown::HashMap;
use std::collections::HashMap;
/// The context of the currently running WebAssembly instance.
///
@ -850,8 +850,9 @@ mod vm_ctx_tests {
use crate::cache::Error as CacheError;
use crate::typed_func::Wasm;
use crate::types::{LocalFuncIndex, SigIndex};
use hashbrown::HashMap;
use indexmap::IndexMap;
use std::any::Any;
use std::collections::HashMap;
use std::ptr::NonNull;
struct Placeholder;
impl RunnableModule for Placeholder {
@ -890,7 +891,7 @@ mod vm_ctx_tests {
imported_tables: Map::new(),
imported_globals: Map::new(),
exports: HashMap::new(),
exports: IndexMap::new(),
data_initializers: Vec::new(),
elem_initializers: Vec::new(),

View File

@ -10,7 +10,7 @@ readme = "README.md"
[dependencies]
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"
[dependencies.wasmer-runtime-core]
@ -23,7 +23,7 @@ version = "0.6.0"
optional = true
[dev-dependencies]
tempfile = "3.0.7"
tempfile = "3.1.0"
criterion = "0.2"
wabt = "0.9.0"

View File

@ -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
//! in your application easy, efficient, and safe.
//!

View File

@ -13,10 +13,9 @@ wasmer-runtime-core = { path = "../runtime-core", version = "0.6.0" }
wasmparser = "0.35.1"
dynasm = "0.3.2"
dynasmrt = "0.3.1"
lazy_static = "1.2.0"
byteorder = "1"
nix = "0.14.0"
libc = "0.2.49"
smallvec = "0.6.9"
hashbrown = "0.1"
lazy_static = "1.3.0"
byteorder = "1.3.2"
nix = "0.14.1"
libc = "0.2.60"
smallvec = "0.6.10"
colored = "1.8"

View File

@ -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)]
#[cfg(not(any(

View File

@ -132,7 +132,7 @@ fn get_compiler() -> impl Compiler {
CraneliftCompiler::new()
}
pub fn generate_imports() -> ImportObject {
pub fn generate_imports(extra_imports: Vec<(String, Instance)>) -> ImportObject {
let mut features = wabt::Features::new();
features.enable_simd();
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");
let mut imports = ImportObject::new();
imports.register("spectest", instance);
for (name, instance) in extra_imports {
imports.register(name, instance);
}
imports
}
@ -303,6 +306,8 @@ struct WastTestGenerator {
script_parser: ScriptParser,
module_calls: HashMap<i32, Vec<String>>,
buffer: String,
modules_by_name: HashMap<String, i32>,
registered_modules: Vec<(i32, String)>,
}
impl WastTestGenerator {
@ -322,6 +327,8 @@ impl WastTestGenerator {
script_parser: script,
buffer: buffer,
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);
}
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 mut features = Features::new();
features.enable_simd();
@ -409,7 +416,9 @@ fn test_module_{}() {{
println!(\"{{}}\", module_str);
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\");
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",
self.last_module,
// 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("\\", "\\\\")
.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(),
);
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) {
@ -763,11 +785,8 @@ fn {}() {{
} => {
// Do nothing for now
}
CommandKind::Register {
name: _,
as_name: _,
} => {
// Do nothing for now
CommandKind::Register { name, as_name } => {
self.visit_register_module(name.as_ref().unwrap(), as_name);
}
CommandKind::PerformAction(action) => {
self.visit_perform_action(action);

View File

@ -25,7 +25,7 @@ Currently supported command assertions:
- [x] `assert_malformed` _fully implemented_
- [ ] `assert_uninstantiable` _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_
### Covered spec tests
@ -86,6 +86,7 @@ The following spec tests are currently covered:
- [x] return.wast
- [x] select.wast
- [x] set_local.wast
- [x] simd.wast
- [ ] skip-stack-guard-page.wast
- [x] stack.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:
- `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:
- `call_indirect.wast`

View File

@ -47,31 +47,27 @@
(data (i32.const 1) "h")
)
;; SKIP_MUTABLE_GLOBALS
;; (module
;; (global (import "spectest" "global_i32") i32)
;; (memory 1)
;; (data (get_global 0) "a")
;; )
;; SKIP_MUTABLE_GLOBALS
;; (module
;; (global (import "spectest" "global_i32") i32)
;; (import "spectest" "memory" (memory 1))
;; (data (get_global 0) "a")
;; )
(module
(global (import "spectest" "global_i32") i32)
(memory 1)
(data (get_global 0) "a")
)
(module
(global (import "spectest" "global_i32") i32)
(import "spectest" "memory" (memory 1))
(data (get_global 0) "a")
)
;; SKIP_MUTABLE_GLOBALS
;; (module
;; (global $g (import "spectest" "global_i32") i32)
;; (memory 1)
;; (data (get_global $g) "a")
;; )
;; SKIP_MUTABLE_GLOBALS
;; (module
;; (global $g (import "spectest" "global_i32") i32)
;; (import "spectest" "memory" (memory 1))
;; (data (get_global $g) "a")
;; )
(module
(global $g (import "spectest" "global_i32") i32)
(memory 1)
(data (get_global $g) "a")
)
(module
(global $g (import "spectest" "global_i32") i32)
(import "spectest" "memory" (memory 1))
(data (get_global $g) "a")
)
;; 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)))
@ -138,19 +134,17 @@
(data (i32.const 0) "a")
)
;; SKIP_MUTABLE_GLOBALS
;; (module
;; (global (import "spectest" "global_i32") i32)
;; (import "spectest" "memory" (memory 0))
;; (data (get_global 0) "a")
;; )
(module
(global (import "spectest" "global_i32") i32)
(import "spectest" "memory" (memory 0))
(data (get_global 0) "a")
)
;; SKIP_MUTABLE_GLOBALS
;; (module
;; (global (import "spectest" "global_i32") i32)
;; (import "spectest" "memory" (memory 0 3))
;; (data (get_global 0) "a")
;; )
(module
(global (import "spectest" "global_i32") i32)
(import "spectest" "memory" (memory 0 3))
(data (get_global 0) "a")
)
(module
(import "spectest" "memory" (memory 0))

View File

@ -246,11 +246,9 @@
)
;; 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
(module (global f32 (f32.neg (f32.const 0))))

View File

@ -9,49 +9,48 @@
;; v128 globals
;; wasmer silently doesn't implement (register) yet
;;(module $M
;; (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))
;;)
;;(register "M" $M)
(module $M
(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))
)
(register "M" $M)
(module
;; (global $a (import "M" "a") v128)
;; (global $b (import "M" "b") (mut v128))
;; (global $c v128 (global.get $a))
(global $a (import "M" "a") v128)
(global $b (import "M" "b") (mut v128))
(global $c v128 (global.get $a))
(global $d v128 (v128.const i32x4 8 9 10 11))
;; (global $e (mut v128) (global.get $a))
;; (global $f (mut v128) (v128.const i32x4 12 13 14 15))
(global $e (mut v128) (global.get $a))
(global $f (mut v128) (v128.const i32x4 12 13 14 15))
;; (func (export "get-a") (result v128) (global.get $a))
;; (func (export "get-b") (result v128) (global.get $b))
;; (func (export "get-c") (result v128) (global.get $c))
(func (export "get-a") (result v128) (global.get $a))
(func (export "get-b") (result v128) (global.get $b))
(func (export "get-c") (result v128) (global.get $c))
(func (export "get-d") (result v128) (global.get $d))
;; (func (export "get-e") (result v128) (global.get $e))
;; (func (export "get-f") (result v128) (global.get $f))
(func (export "get-e") (result v128) (global.get $e))
(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-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-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-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-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-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-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-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-e") (v128.const f32x4 0.0 1.0 2.0 3.0))
(assert_return (invoke "get-f") (v128.const i32x4 12 13 14 15))
;;(invoke "set-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))
;;(assert_return (invoke "get-e") (v128.const f64x2 -nan:0x3 +inf))
;;
;;(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))
(invoke "set-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))
(assert_return (invoke "get-e") (v128.const f64x2 -nan:0x3 +inf))
(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_invalid (module (global v128 (i32.const 0))) "invalid initializer expression")
(assert_invalid (module (global v128 (i64.const 0))) "invalid initializer expression")

View File

@ -17,7 +17,7 @@ wasmer-llvm-backend = { path = "../llvm-backend", version = "0.6.0", optional =
[build-dependencies]
glob = "0.2.11"
glob = "0.3.0"
[dev-dependencies]
wasmer-clif-backend = { path = "../clif-backend", version = "0.6.0" }

View File

@ -9,13 +9,12 @@ edition = "2018"
[dependencies]
wasmer-runtime-core = { path = "../runtime-core", version = "0.6.0" }
libc = "0.2.50"
rand = "0.6.5"
libc = "0.2.60"
rand = "0.7.0"
# wasmer-runtime-abi = { path = "../runtime-abi" }
hashbrown = "0.1.8"
generational-arena = "0.2.2"
log = "0.4.6"
byteorder = "1.3.1"
log = "0.4.8"
byteorder = "1.3.2"
[target.'cfg(windows)'.dependencies]
winapi = "0.3"
winapi = "0.3.7"

View File

@ -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")]
extern crate winapi;

View File

@ -8,7 +8,7 @@
use crate::syscalls::types::*;
use generational_arena::Arena;
pub use generational_arena::Index as Inode;
use hashbrown::hash_map::HashMap;
use std::collections::HashMap;
use std::{
borrow::Borrow,
cell::Cell,

View File

@ -9,10 +9,10 @@ edition = "2018"
[target.'cfg(windows)'.dependencies]
wasmer-runtime-core = { path = "../runtime-core", version = "0.6.0" }
winapi = { version = "0.3", features = ["winbase", "errhandlingapi", "minwindef", "minwinbase", "winnt"] }
libc = "0.2.49"
winapi = { version = "0.3.7", features = ["winbase", "errhandlingapi", "minwindef", "minwinbase", "winnt"] }
libc = "0.2.60"
[build-dependencies]
cmake = "0.1.35"
bindgen = "0.46.0"
regex = "1.0.6"
cmake = "0.1.40"
bindgen = "0.51.0"
regex = "1.2.0"

View File

@ -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)]
mod exception_handling;

View File

@ -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 structopt;

View File

@ -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;
use std::env;
@ -10,7 +15,7 @@ use std::path::PathBuf;
use std::process::exit;
use std::str::FromStr;
use hashbrown::HashMap;
use std::collections::HashMap;
use structopt::StructOpt;
use wasmer::*;

View File

@ -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]
extern crate wasmer_runtime_core;
// extern crate wasmer_emscripten;