mirror of
https://github.com/fluencelabs/wasmer
synced 2024-12-13 06:15:33 +00:00
merge upstream/master into wasmer-private/feature/llvm-backend
This commit is contained in:
commit
4e198bca8b
@ -14,30 +14,36 @@ environment:
|
||||
|
||||
cache:
|
||||
- 'C:\Users\appveyor\.cargo'
|
||||
- target
|
||||
|
||||
install:
|
||||
- appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe
|
||||
- rustup-init.exe -yv --default-host %target%
|
||||
# uncomment these lines if the cache is cleared, or if we must re-install rust for some reason
|
||||
# - appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe
|
||||
# - rustup-init.exe -yv --default-host %target%
|
||||
- set PATH=%PATH%;%USERPROFILE%\.cargo\bin
|
||||
- rustup default stable-%target%
|
||||
- rustup update
|
||||
- rustc -vV
|
||||
- cargo -vV
|
||||
# Install InnoSetup
|
||||
- appveyor-retry appveyor DownloadFile https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror/2017-08-22-is.exe
|
||||
- 2017-08-22-is.exe /VERYSILENT /SUPPRESSMSGBOXES /NORESTART /SP-
|
||||
- set PATH="C:\Program Files (x86)\Inno Setup 5";%PATH%
|
||||
# uncomment to RDP to appveyor
|
||||
# - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
|
||||
|
||||
build_script:
|
||||
- cargo build --verbose
|
||||
- cargo build --release --verbose
|
||||
|
||||
test_script:
|
||||
- set RUST_BACKTRACE=1
|
||||
- cd ./lib/spectests && cargo test -- --test-threads 1 && cd ../..
|
||||
- cargo test --package wasmer-spectests
|
||||
|
||||
before_deploy:
|
||||
after_build:
|
||||
- cd ./src/installer
|
||||
- iscc wasmer.iss
|
||||
- copy /y .\WasmerInstaller.exe ..\..\WasmerInstaller-%APPVEYOR_REPO_TAG_NAME%.exe
|
||||
- appveyor PushArtifact WasmerInstaller-%APPVEYOR_REPO_TAG_NAME%.exe
|
||||
|
||||
artifacts:
|
||||
- path: WasmerInstaller-%APPVEYOR_REPO_TAG_NAME%.exe
|
||||
name: WasmerInstaller.exe
|
||||
- appveyor PushArtifact ..\..\WasmerInstaller-%APPVEYOR_REPO_TAG_NAME%.exe
|
||||
- cd ..\..\
|
||||
|
||||
deploy:
|
||||
description: 'WasmerInstaller'
|
||||
|
1514
Cargo.lock
generated
1514
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "wasmer"
|
||||
version = "0.1.4"
|
||||
version = "0.2.1"
|
||||
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
|
||||
edition = "2018"
|
||||
repository = "https://github.com/wasmerio/wasmer"
|
||||
@ -36,6 +36,6 @@ glob = "0.2.11"
|
||||
[features]
|
||||
default = ["fast-tests"]
|
||||
|
||||
debug = []
|
||||
debug = ["wasmer-clif-backend/debug", "wasmer-runtime-core/debug"]
|
||||
# This feature will allow cargo test to run much faster
|
||||
fast-tests = []
|
||||
|
5
Makefile
5
Makefile
@ -19,7 +19,7 @@ capi:
|
||||
# rm -rf artifacts
|
||||
|
||||
build:
|
||||
cargo build
|
||||
cargo build --features debug
|
||||
|
||||
install:
|
||||
cargo install --path .
|
||||
@ -47,6 +47,9 @@ release:
|
||||
# brew install mingw-w64
|
||||
cargo build --release
|
||||
|
||||
debug-release:
|
||||
cargo build --release --features debug
|
||||
|
||||
debug-release:
|
||||
cargo build --release --features "debug"
|
||||
|
||||
|
@ -142,6 +142,14 @@ You can also run integration tests with:
|
||||
make integration-tests
|
||||
```
|
||||
|
||||
## Benchmarking
|
||||
|
||||
Benchmarks can be run with:
|
||||
|
||||
```sh
|
||||
cargo bench --all
|
||||
```
|
||||
|
||||
## Roadmap
|
||||
|
||||
Wasmer is an open project guided by strong principles, aiming to be modular, flexible and fast. It is open to the community to help set its direction.
|
||||
|
26
examples/nginx/LICENSE
Normal file
26
examples/nginx/LICENSE
Normal file
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2019 Igor Sysoev
|
||||
* Copyright (C) 2011-2019 Nginx, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
@ -133,7 +133,7 @@ wasmer_link() {
|
||||
SOURCE_STR="# Wasmer config\nexport WASMER_DIR=\"\$HOME/.wasmer\"\nexport WASMER_CACHE_DIR=\"\$WASMER_DIR/cache\"\nexport PATH=\"\$HOME/.wasmer/bin:\$PATH\"\n"
|
||||
|
||||
# We create the wasmer.sh file
|
||||
echo "$SOURCE_STR" > "$HOME/.wasmer/wasmer.sh"
|
||||
printf "$SOURCE_STR" > "$HOME/.wasmer/wasmer.sh"
|
||||
|
||||
if [ -z "${WASMER_PROFILE-}" ] ; then
|
||||
printf "${red}Profile not found. Tried:\n* ${WASMER_PROFILE} (as defined in \$PROFILE)\n* ~/.bashrc\n* ~/.bash_profile\n* ~/.zshrc\n* ~/.profile.\n"
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "wasmer-clif-backend"
|
||||
version = "0.1.2"
|
||||
version = "0.2.0"
|
||||
description = "Wasmer runtime Cranelift compiler backend"
|
||||
license = "MIT"
|
||||
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
|
||||
@ -8,7 +8,7 @@ repository = "https://github.com/wasmerio/wasmer"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
wasmer-runtime-core = { path = "../runtime-core", version = "0.1.2" }
|
||||
wasmer-runtime-core = { path = "../runtime-core", version = "0.2.0" }
|
||||
cranelift-native = "0.26.0"
|
||||
cranelift-codegen = "0.26.0"
|
||||
cranelift-entity = "0.26.0"
|
||||
@ -18,7 +18,8 @@ target-lexicon = "0.2.0"
|
||||
wasmparser = "0.23.0"
|
||||
byteorder = "1"
|
||||
nix = "0.13.0"
|
||||
libc = "0.2.48"
|
||||
libc = "0.2.49"
|
||||
rayon = "1.0"
|
||||
|
||||
# Dependencies for caching.
|
||||
[dependencies.serde]
|
||||
@ -32,7 +33,7 @@ version = "0.0.7"
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
winapi = { version = "0.3", features = ["errhandlingapi", "minwindef", "minwinbase", "winnt"] }
|
||||
wasmer-win-exception-handler = { path = "../win-exception-handler", version = "0.0.1" }
|
||||
wasmer-win-exception-handler = { path = "../win-exception-handler", version = "0.2.0" }
|
||||
|
||||
[features]
|
||||
debug = ["wasmer-runtime-core/debug"]
|
||||
|
@ -24,6 +24,7 @@ use wasmer_runtime_core::{
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
|
||||
extern crate rayon;
|
||||
extern crate serde;
|
||||
|
||||
use wasmparser::{self, WasmDecoder};
|
||||
|
@ -7,6 +7,7 @@ use crate::{
|
||||
},
|
||||
signal::HandlerData,
|
||||
};
|
||||
use rayon::prelude::*;
|
||||
|
||||
use byteorder::{ByteOrder, LittleEndian};
|
||||
use cranelift_codegen::{ir, isa, Context};
|
||||
@ -92,25 +93,44 @@ impl FuncResolverBuilder {
|
||||
function_bodies: Map<LocalFuncIndex, ir::Function>,
|
||||
info: &ModuleInfo,
|
||||
) -> CompileResult<(Self, HandlerData)> {
|
||||
let mut compiled_functions: Vec<Vec<u8>> = Vec::with_capacity(function_bodies.len());
|
||||
let mut local_relocs = Map::with_capacity(function_bodies.len());
|
||||
let mut external_relocs = Map::new();
|
||||
let num_func_bodies = function_bodies.len();
|
||||
let mut local_relocs = Map::with_capacity(num_func_bodies);
|
||||
let mut external_relocs = Map::with_capacity(num_func_bodies);
|
||||
|
||||
let mut trap_sink = TrapSink::new();
|
||||
let mut local_trap_sink = LocalTrapSink::new();
|
||||
|
||||
let mut ctx = Context::new();
|
||||
let compiled_functions: Result<Vec<(Vec<u8>, (RelocSink, LocalTrapSink))>, CompileError> =
|
||||
function_bodies
|
||||
.into_vec()
|
||||
.par_iter()
|
||||
.map_init(
|
||||
|| Context::new(),
|
||||
|ctx, func| {
|
||||
let mut code_buf = Vec::new();
|
||||
ctx.func = func.to_owned();
|
||||
let mut reloc_sink = RelocSink::new();
|
||||
let mut local_trap_sink = LocalTrapSink::new();
|
||||
|
||||
ctx.compile_and_emit(
|
||||
isa,
|
||||
&mut code_buf,
|
||||
&mut reloc_sink,
|
||||
&mut local_trap_sink,
|
||||
)
|
||||
.map_err(|e| CompileError::InternalError { msg: e.to_string() })?;
|
||||
ctx.clear();
|
||||
Ok((code_buf, (reloc_sink, local_trap_sink)))
|
||||
},
|
||||
)
|
||||
.collect();
|
||||
|
||||
let compiled_functions = compiled_functions?;
|
||||
let mut total_size = 0;
|
||||
|
||||
for (_, func) in function_bodies {
|
||||
ctx.func = func;
|
||||
let mut code_buf = Vec::new();
|
||||
let mut reloc_sink = RelocSink::new();
|
||||
|
||||
ctx.compile_and_emit(isa, &mut code_buf, &mut reloc_sink, &mut local_trap_sink)
|
||||
.map_err(|e| CompileError::InternalError { msg: e.to_string() })?;
|
||||
ctx.clear();
|
||||
|
||||
// We separate into two iterators, one iterable and one into iterable
|
||||
let (code_bufs, sinks): (Vec<Vec<u8>>, Vec<(RelocSink, LocalTrapSink)>) =
|
||||
compiled_functions.into_iter().unzip();
|
||||
for (code_buf, (reloc_sink, mut local_trap_sink)) in code_bufs.iter().zip(sinks.into_iter())
|
||||
{
|
||||
// Clear the local trap sink and consolidate all trap info
|
||||
// into a single location.
|
||||
trap_sink.drain_local(total_size, &mut local_trap_sink);
|
||||
@ -118,7 +138,6 @@ impl FuncResolverBuilder {
|
||||
// Round up each function's size to pointer alignment.
|
||||
total_size += round_up(code_buf.len(), mem::size_of::<usize>());
|
||||
|
||||
compiled_functions.push(code_buf);
|
||||
local_relocs.push(reloc_sink.local_relocs.into_boxed_slice());
|
||||
external_relocs.push(reloc_sink.external_relocs.into_boxed_slice());
|
||||
}
|
||||
@ -145,10 +164,10 @@ impl FuncResolverBuilder {
|
||||
*i = 0xCC;
|
||||
}
|
||||
|
||||
let mut map = Map::with_capacity(compiled_functions.len());
|
||||
let mut map = Map::with_capacity(num_func_bodies);
|
||||
|
||||
let mut previous_end = 0;
|
||||
for compiled in compiled_functions.iter() {
|
||||
for compiled in code_bufs.iter() {
|
||||
let new_end = previous_end + round_up(compiled.len(), mem::size_of::<usize>());
|
||||
unsafe {
|
||||
memory.as_slice_mut()[previous_end..previous_end + compiled.len()]
|
||||
|
@ -2,7 +2,7 @@ use crate::relocation::{TrapData, TrapSink};
|
||||
use crate::trampoline::Trampolines;
|
||||
use hashbrown::HashSet;
|
||||
use libc::c_void;
|
||||
use std::{cell::Cell, sync::Arc};
|
||||
use std::{any::Any, cell::Cell, sync::Arc};
|
||||
use wasmer_runtime_core::{
|
||||
backend::{ProtectedCaller, Token, UserTrapper},
|
||||
error::RuntimeResult,
|
||||
@ -25,14 +25,14 @@ pub use self::unix::*;
|
||||
pub use self::windows::*;
|
||||
|
||||
thread_local! {
|
||||
pub static TRAP_EARLY_DATA: Cell<Option<String>> = Cell::new(None);
|
||||
pub static TRAP_EARLY_DATA: Cell<Option<Box<dyn Any>>> = Cell::new(None);
|
||||
}
|
||||
|
||||
pub struct Trapper;
|
||||
|
||||
impl UserTrapper for Trapper {
|
||||
unsafe fn do_early_trap(&self, msg: String) -> ! {
|
||||
TRAP_EARLY_DATA.with(|cell| cell.set(Some(msg)));
|
||||
unsafe fn do_early_trap(&self, data: Box<dyn Any>) -> ! {
|
||||
TRAP_EARLY_DATA.with(|cell| cell.set(Some(data)));
|
||||
trigger_trap()
|
||||
}
|
||||
}
|
||||
|
@ -79,8 +79,8 @@ pub fn call_protected<T>(handler_data: &HandlerData, f: impl FnOnce() -> T) -> R
|
||||
if signum != 0 {
|
||||
*jmp_buf = prev_jmp_buf;
|
||||
|
||||
if let Some(msg) = super::TRAP_EARLY_DATA.with(|cell| cell.replace(None)) {
|
||||
Err(RuntimeError::User { msg })
|
||||
if let Some(data) = super::TRAP_EARLY_DATA.with(|cell| cell.replace(None)) {
|
||||
Err(RuntimeError::Panic { data })
|
||||
} else {
|
||||
let (faulting_addr, inst_ptr) = CAUGHT_ADDRESSES.with(|cell| cell.get());
|
||||
|
||||
@ -91,28 +91,28 @@ pub fn call_protected<T>(handler_data: &HandlerData, f: impl FnOnce() -> T) -> R
|
||||
{
|
||||
Err(match Signal::from_c_int(signum) {
|
||||
Ok(SIGILL) => match trapcode {
|
||||
TrapCode::BadSignature => RuntimeError::IndirectCallSignature {
|
||||
table: TableIndex::new(0),
|
||||
TrapCode::BadSignature => RuntimeError::Trap {
|
||||
msg: "incorrect call_indirect signature".into(),
|
||||
},
|
||||
TrapCode::IndirectCallToNull => RuntimeError::IndirectCallToNull {
|
||||
table: TableIndex::new(0),
|
||||
TrapCode::IndirectCallToNull => RuntimeError::Trap {
|
||||
msg: "indirect call to null".into(),
|
||||
},
|
||||
TrapCode::HeapOutOfBounds => RuntimeError::OutOfBoundsAccess {
|
||||
memory: MemoryIndex::new(0),
|
||||
addr: None,
|
||||
TrapCode::HeapOutOfBounds => RuntimeError::Trap {
|
||||
msg: "memory out-of-bounds access".into(),
|
||||
},
|
||||
TrapCode::TableOutOfBounds => RuntimeError::TableOutOfBounds {
|
||||
table: TableIndex::new(0),
|
||||
TrapCode::TableOutOfBounds => RuntimeError::Trap {
|
||||
msg: "table out-of-bounds access".into(),
|
||||
},
|
||||
_ => RuntimeError::Unknown {
|
||||
msg: "unknown trap".to_string(),
|
||||
_ => RuntimeError::Trap {
|
||||
msg: "unknown trap".into(),
|
||||
},
|
||||
},
|
||||
Ok(SIGSEGV) | Ok(SIGBUS) => RuntimeError::OutOfBoundsAccess {
|
||||
memory: MemoryIndex::new(0),
|
||||
addr: None,
|
||||
Ok(SIGSEGV) | Ok(SIGBUS) => RuntimeError::Trap {
|
||||
msg: "memory out-of-bounds access".into(),
|
||||
},
|
||||
Ok(SIGFPE) => RuntimeError::Trap {
|
||||
msg: "illegal arithmetic operation".into(),
|
||||
},
|
||||
Ok(SIGFPE) => RuntimeError::IllegalArithmeticOperation,
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
.into())
|
||||
@ -126,8 +126,8 @@ pub fn call_protected<T>(handler_data: &HandlerData, f: impl FnOnce() -> T) -> R
|
||||
_ => "unkown trapped signal",
|
||||
};
|
||||
// When the trap-handler is fully implemented, this will return more information.
|
||||
Err(RuntimeError::Unknown {
|
||||
msg: format!("trap at {:p} - {}", faulting_addr, signal),
|
||||
Err(RuntimeError::Trap {
|
||||
msg: format!("unknown trap at {:p} - {}", faulting_addr, signal).into(),
|
||||
}
|
||||
.into())
|
||||
}
|
||||
|
@ -57,35 +57,34 @@ pub fn call_protected(
|
||||
}) = handler_data.lookup(instruction_pointer as _)
|
||||
{
|
||||
Err(match signum as DWORD {
|
||||
EXCEPTION_ACCESS_VIOLATION => RuntimeError::OutOfBoundsAccess {
|
||||
memory: MemoryIndex::new(0),
|
||||
addr: None,
|
||||
EXCEPTION_ACCESS_VIOLATION => RuntimeError::Trap {
|
||||
msg: "memory out-of-bounds access".into(),
|
||||
},
|
||||
EXCEPTION_ILLEGAL_INSTRUCTION => match trapcode {
|
||||
TrapCode::BadSignature => RuntimeError::IndirectCallSignature {
|
||||
table: TableIndex::new(0),
|
||||
TrapCode::BadSignature => RuntimeError::Trap {
|
||||
msg: "incorrect call_indirect signature".into(),
|
||||
},
|
||||
TrapCode::IndirectCallToNull => RuntimeError::IndirectCallToNull {
|
||||
table: TableIndex::new(0),
|
||||
TrapCode::IndirectCallToNull => RuntimeError::Trap {
|
||||
msg: "indirect call to null".into(),
|
||||
},
|
||||
TrapCode::HeapOutOfBounds => RuntimeError::OutOfBoundsAccess {
|
||||
memory: MemoryIndex::new(0),
|
||||
addr: None,
|
||||
TrapCode::HeapOutOfBounds => RuntimeError::Trap {
|
||||
msg: "memory out-of-bounds access".into(),
|
||||
},
|
||||
TrapCode::TableOutOfBounds => RuntimeError::TableOutOfBounds {
|
||||
table: TableIndex::new(0),
|
||||
TrapCode::TableOutOfBounds => RuntimeError::Trap {
|
||||
msg: "table out-of-bounds access".into(),
|
||||
},
|
||||
_ => RuntimeError::Unknown {
|
||||
msg: "unknown trap".to_string(),
|
||||
_ => RuntimeError::Trap {
|
||||
msg: "unknown trap".into(),
|
||||
},
|
||||
},
|
||||
EXCEPTION_STACK_OVERFLOW => RuntimeError::Unknown {
|
||||
msg: "unknown trap".to_string(),
|
||||
EXCEPTION_STACK_OVERFLOW => RuntimeError::Trap {
|
||||
msg: "stack overflow trap".into(),
|
||||
},
|
||||
EXCEPTION_INT_DIVIDE_BY_ZERO => RuntimeError::IllegalArithmeticOperation,
|
||||
EXCEPTION_INT_OVERFLOW => RuntimeError::IllegalArithmeticOperation,
|
||||
_ => RuntimeError::Unknown {
|
||||
msg: "unknown trap".to_string(),
|
||||
EXCEPTION_INT_DIVIDE_BY_ZERO | EXCEPTION_INT_OVERFLOW => RuntimeError::Trap {
|
||||
msg: "illegal arithmetic operation".into(),
|
||||
},
|
||||
_ => RuntimeError::Trap {
|
||||
msg: "unknown trap".into(),
|
||||
},
|
||||
}
|
||||
.into())
|
||||
@ -103,8 +102,8 @@ pub fn call_protected(
|
||||
_ => "unkown trapped signal",
|
||||
};
|
||||
|
||||
Err(RuntimeError::Unknown {
|
||||
msg: format!("trap at {} - {}", exception_address, signal),
|
||||
Err(RuntimeError::Trap {
|
||||
msg: format!("unknown trap at {} - {}", exception_address, signal).into(),
|
||||
}
|
||||
.into())
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "wasmer-emscripten"
|
||||
version = "0.1.0"
|
||||
version = "0.2.1"
|
||||
description = "Wasmer runtime emscripten implementation library"
|
||||
license = "MIT"
|
||||
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
|
||||
@ -9,9 +9,9 @@ edition = "2018"
|
||||
build = "build/mod.rs"
|
||||
|
||||
[dependencies]
|
||||
wasmer-runtime-core = { path = "../runtime-core", version = "0.1.0" }
|
||||
wasmer-runtime-core = { path = "../runtime-core", version = "0.2.1" }
|
||||
lazy_static = "1.2.0"
|
||||
libc = { git = "https://github.com/rust-lang/libc" }
|
||||
libc = "0.2.49"
|
||||
byteorder = "1"
|
||||
time = "0.1.41"
|
||||
|
||||
@ -19,7 +19,7 @@ time = "0.1.41"
|
||||
rand = "0.6"
|
||||
|
||||
[dev-dependencies]
|
||||
wasmer-clif-backend = { path = "../clif-backend", version = "0.1.0" }
|
||||
wasmer-clif-backend = { path = "../clif-backend", version = "0.2.0" }
|
||||
wabt = "0.7.2"
|
||||
|
||||
[build-dependencies]
|
||||
|
10
lib/emscripten/emtests/test_getcwd.c
vendored
Normal file
10
lib/emscripten/emtests/test_getcwd.c
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int main() {
|
||||
const unsigned int size = 256;
|
||||
char cwd[size] = {};
|
||||
char* buf = getcwd(cwd, size);
|
||||
printf("getcwd\n");
|
||||
return 0;
|
||||
}
|
1
lib/emscripten/emtests/test_getcwd.out
vendored
Normal file
1
lib/emscripten/emtests/test_getcwd.out
vendored
Normal file
@ -0,0 +1 @@
|
||||
getcwd
|
BIN
lib/emscripten/emtests/test_getcwd.wasm
vendored
Normal file
BIN
lib/emscripten/emtests/test_getcwd.wasm
vendored
Normal file
Binary file not shown.
@ -502,6 +502,7 @@ pub fn generate_emscripten_env(globals: &mut EmscriptenGlobals) -> ImportObject
|
||||
"___syscall168" => func!(crate::syscalls::___syscall168),
|
||||
"___syscall180" => func!(crate::syscalls::___syscall180),
|
||||
"___syscall181" => func!(crate::syscalls::___syscall181),
|
||||
"___syscall183" => func!(crate::syscalls::___syscall183),
|
||||
"___syscall191" => func!(crate::syscalls::___syscall191),
|
||||
"___syscall192" => func!(crate::syscalls::___syscall192),
|
||||
"___syscall194" => func!(crate::syscalls::___syscall194),
|
||||
|
@ -46,8 +46,13 @@ use std::slice;
|
||||
// Another conditional constant for name resolution: Macos et iOS use
|
||||
// SO_NOSIGPIPE as a setsockopt flag to disable SIGPIPE emission on socket.
|
||||
// Other platforms do otherwise.
|
||||
use crate::env::get_emscripten_data;
|
||||
use crate::utils::copy_cstr_into_wasm;
|
||||
use crate::utils::read_string_from_wasm;
|
||||
#[cfg(target_os = "darwin")]
|
||||
use libc::SO_NOSIGPIPE;
|
||||
use std::ffi::CString;
|
||||
|
||||
#[cfg(not(target_os = "darwin"))]
|
||||
const SO_NOSIGPIPE: c_int = 0;
|
||||
|
||||
@ -66,10 +71,10 @@ pub fn ___syscall3(ctx: &mut Ctx, which: i32, mut varargs: VarArgs) -> i32 {
|
||||
debug!("emscripten::___syscall3 (read) {}", which);
|
||||
let fd: i32 = varargs.get(ctx);
|
||||
let buf: u32 = varargs.get(ctx);
|
||||
let count = varargs.get(ctx);
|
||||
let count: i32 = varargs.get(ctx);
|
||||
debug!("=> fd: {}, buf_offset: {}, count: {}", fd, buf, count);
|
||||
let buf_addr = emscripten_memory_pointer!(ctx.memory(0), buf) as *mut c_void;
|
||||
let ret = unsafe { read(fd, buf_addr, count) };
|
||||
let ret = unsafe { read(fd, buf_addr, count as _) };
|
||||
debug!("=> ret: {}", ret);
|
||||
ret as _
|
||||
}
|
||||
@ -79,10 +84,10 @@ pub fn ___syscall4(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int {
|
||||
debug!("emscripten::___syscall4 (write) {}", which);
|
||||
let fd: i32 = varargs.get(ctx);
|
||||
let buf: u32 = varargs.get(ctx);
|
||||
let count = varargs.get(ctx);
|
||||
let count: i32 = varargs.get(ctx);
|
||||
debug!("=> fd: {}, buf: {}, count: {}", fd, buf, count);
|
||||
let buf_addr = emscripten_memory_pointer!(ctx.memory(0), buf) as *const c_void;
|
||||
unsafe { write(fd, buf_addr, count) as i32 }
|
||||
unsafe { write(fd, buf_addr, count as _) as i32 }
|
||||
}
|
||||
|
||||
/// close
|
||||
@ -186,6 +191,25 @@ pub fn ___syscall110(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
|
||||
-1
|
||||
}
|
||||
|
||||
// getcwd
|
||||
pub fn ___syscall183(ctx: &mut Ctx, buf_offset: u32, _size: u32) -> u32 {
|
||||
debug!("emscripten::___syscall183");
|
||||
use std::env;
|
||||
let path = env::current_dir();
|
||||
let path_string = path.unwrap().display().to_string();
|
||||
let len = path_string.len();
|
||||
unsafe {
|
||||
let pointer_to_buffer =
|
||||
emscripten_memory_pointer!(ctx.memory(0), buf_offset) as *mut libc::c_char;
|
||||
let slice = slice::from_raw_parts_mut(pointer_to_buffer, len.clone());
|
||||
for (byte, loc) in path_string.bytes().zip(slice.iter_mut()) {
|
||||
*loc = byte as _;
|
||||
}
|
||||
*pointer_to_buffer.add(len.clone()) = 0;
|
||||
}
|
||||
buf_offset
|
||||
}
|
||||
|
||||
// mmap2
|
||||
pub fn ___syscall192(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int {
|
||||
debug!("emscripten::___syscall192 (mmap2) {}", which);
|
||||
@ -217,10 +241,10 @@ pub fn ___syscall140(ctx: &mut Ctx, which: i32, mut varargs: VarArgs) -> i32 {
|
||||
// -> c_int
|
||||
debug!("emscripten::___syscall140 (lseek) {}", which);
|
||||
let fd: i32 = varargs.get(ctx);
|
||||
let offset = varargs.get(ctx);
|
||||
let offset: i32 = varargs.get(ctx);
|
||||
let whence: i32 = varargs.get(ctx);
|
||||
debug!("=> fd: {}, offset: {}, whence = {}", fd, offset, whence);
|
||||
unsafe { lseek(fd, offset, whence) as _ }
|
||||
unsafe { lseek(fd, offset as _, whence) as _ }
|
||||
}
|
||||
|
||||
/// readv
|
||||
|
@ -54,6 +54,7 @@ mod test_funcptrfunc;
|
||||
mod test_funcs;
|
||||
mod test_functionpointer_libfunc_varargs;
|
||||
mod test_fwrite_0;
|
||||
mod test_getcwd;
|
||||
mod test_getgep;
|
||||
mod test_getloadavg;
|
||||
mod test_getopt;
|
||||
|
9
lib/emscripten/tests/emtests/test_getcwd.rs
Normal file
9
lib/emscripten/tests/emtests/test_getcwd.rs
Normal file
@ -0,0 +1,9 @@
|
||||
#[test]
|
||||
fn test_getcwd() {
|
||||
assert_emscripten_output!(
|
||||
"../../emtests/test_getcwd.wasm",
|
||||
"getcwd",
|
||||
vec![],
|
||||
"../../emtests/test_getcwd.out"
|
||||
);
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "wasmer-runtime-c-api"
|
||||
version = "0.1.4"
|
||||
version = "0.2.1"
|
||||
description = "Wasmer c-api library"
|
||||
license = "MIT"
|
||||
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
|
||||
@ -9,8 +9,8 @@ edition = "2018"
|
||||
readme = "README.md"
|
||||
|
||||
[dependencies]
|
||||
wasmer-runtime = { path = "../runtime", version = "0.1.2" }
|
||||
wasmer-runtime-core = { path = "../runtime-core", version = "0.1.2" }
|
||||
wasmer-runtime = { path = "../runtime", version = "0.2.1" }
|
||||
wasmer-runtime-core = { path = "../runtime-core", version = "0.2.1" }
|
||||
libc = "0.2"
|
||||
|
||||
[lib]
|
||||
|
@ -13,12 +13,10 @@ use std::{ffi::c_void, ptr};
|
||||
use wasmer_runtime::{Ctx, Global, ImportObject, Instance, Memory, Module, Table, Value};
|
||||
use wasmer_runtime_core::export::{Context, Export, FuncPointer};
|
||||
use wasmer_runtime_core::import::Namespace;
|
||||
use wasmer_runtime_core::module::{ExportIndex, ImportName};
|
||||
use wasmer_runtime_core::types::{ElementType, FuncSig, MemoryDescriptor, TableDescriptor, Type};
|
||||
use wasmer_runtime_core::units::{Bytes, Pages};
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
pub struct wasmer_import_object_t();
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
pub struct wasmer_module_t();
|
||||
|
||||
@ -78,7 +76,11 @@ pub struct wasmer_table_t();
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone)]
|
||||
pub struct wasmer_func_t();
|
||||
pub struct wasmer_import_func_t();
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone)]
|
||||
pub struct wasmer_export_func_t();
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone)]
|
||||
@ -96,14 +98,6 @@ pub struct wasmer_limit_option_t {
|
||||
pub some: uint32_t,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct wasmer_func_signature {
|
||||
pub params: *const wasmer_value_tag,
|
||||
pub params_len: c_int,
|
||||
pub returns: *const wasmer_value_tag,
|
||||
pub returns_len: c_int,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct wasmer_import_t {
|
||||
module_name: wasmer_byte_array,
|
||||
@ -112,6 +106,14 @@ pub struct wasmer_import_t {
|
||||
value: wasmer_import_export_value,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone)]
|
||||
pub struct wasmer_import_descriptor_t;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone)]
|
||||
pub struct wasmer_import_descriptors_t;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone)]
|
||||
pub struct wasmer_export_t;
|
||||
@ -120,6 +122,14 @@ pub struct wasmer_export_t;
|
||||
#[derive(Clone)]
|
||||
pub struct wasmer_exports_t;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone)]
|
||||
pub struct wasmer_export_descriptor_t;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone)]
|
||||
pub struct wasmer_export_descriptors_t;
|
||||
|
||||
#[repr(u32)]
|
||||
#[derive(Clone)]
|
||||
pub enum wasmer_import_export_kind {
|
||||
@ -132,7 +142,7 @@ pub enum wasmer_import_export_kind {
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub union wasmer_import_export_value {
|
||||
func: *const wasmer_func_t,
|
||||
func: *const wasmer_import_func_t,
|
||||
table: *const wasmer_table_t,
|
||||
memory: *const wasmer_memory_t,
|
||||
global: *const wasmer_global_t,
|
||||
@ -208,14 +218,13 @@ pub extern "C" fn wasmer_memory_grow(
|
||||
delta: uint32_t,
|
||||
) -> wasmer_result_t {
|
||||
let memory = unsafe { &*(memory as *mut Memory) };
|
||||
let maybe_delta = memory.grow(Pages(delta));
|
||||
if let Some(_delta) = maybe_delta {
|
||||
wasmer_result_t::WASMER_OK
|
||||
} else {
|
||||
update_last_error(CApiError {
|
||||
msg: "unable to grow memory".to_string(),
|
||||
});
|
||||
wasmer_result_t::WASMER_ERROR
|
||||
let delta_result = memory.grow(Pages(delta));
|
||||
match delta_result {
|
||||
Ok(_) => wasmer_result_t::WASMER_OK,
|
||||
Err(grow_error) => {
|
||||
update_last_error(grow_error);
|
||||
wasmer_result_t::WASMER_ERROR
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -277,14 +286,13 @@ pub extern "C" fn wasmer_table_grow(
|
||||
delta: uint32_t,
|
||||
) -> wasmer_result_t {
|
||||
let table = unsafe { &*(table as *mut Table) };
|
||||
let maybe_delta = table.grow(delta);
|
||||
if let Some(_delta) = maybe_delta {
|
||||
wasmer_result_t::WASMER_OK
|
||||
} else {
|
||||
update_last_error(CApiError {
|
||||
msg: "unable to grow table".to_string(),
|
||||
});
|
||||
wasmer_result_t::WASMER_ERROR
|
||||
let delta_result = table.grow(delta);
|
||||
match delta_result {
|
||||
Ok(_) => wasmer_result_t::WASMER_OK,
|
||||
Err(grow_error) => {
|
||||
update_last_error(grow_error);
|
||||
wasmer_result_t::WASMER_ERROR
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -446,12 +454,24 @@ pub unsafe extern "C" fn wasmer_module_instantiate(
|
||||
.or_insert_with(|| Namespace::new());
|
||||
|
||||
let export = match import.tag {
|
||||
wasmer_import_export_kind::WASM_MEMORY => import.value.memory as *mut Export,
|
||||
wasmer_import_export_kind::WASM_FUNCTION => import.value.func as *mut Export,
|
||||
wasmer_import_export_kind::WASM_GLOBAL => import.value.global as *mut Export,
|
||||
wasmer_import_export_kind::WASM_TABLE => import.value.table as *mut Export,
|
||||
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())
|
||||
}
|
||||
};
|
||||
namespace.insert(import_name, unsafe { (&*export).clone() });
|
||||
namespace.insert(import_name, export);
|
||||
}
|
||||
for (module_name, namespace) in namespaces.into_iter() {
|
||||
import_object.register(module_name, namespace);
|
||||
@ -470,6 +490,91 @@ pub unsafe extern "C" fn wasmer_module_instantiate(
|
||||
wasmer_result_t::WASMER_OK
|
||||
}
|
||||
|
||||
/// Gets export descriptors for the given module
|
||||
///
|
||||
/// The caller owns the object and should call `wasmer_export_descriptors_destroy` to free it.
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasmer_export_descriptors(
|
||||
module: *mut wasmer_module_t,
|
||||
export_descriptors: *mut *mut wasmer_export_descriptors_t,
|
||||
) {
|
||||
let mut module = unsafe { &*(module as *mut Module) };
|
||||
|
||||
let named_export_descriptors: Box<NamedExportDescriptors> = Box::new(NamedExportDescriptors(
|
||||
module.info().exports.iter().map(|e| e.into()).collect(),
|
||||
));
|
||||
unsafe {
|
||||
*export_descriptors =
|
||||
Box::into_raw(named_export_descriptors) as *mut wasmer_export_descriptors_t
|
||||
};
|
||||
}
|
||||
|
||||
pub struct NamedExportDescriptors(Vec<NamedExportDescriptor>);
|
||||
|
||||
/// Frees the memory for the given export descriptors
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasmer_export_descriptors_destroy(
|
||||
export_descriptors: *mut wasmer_export_descriptors_t,
|
||||
) {
|
||||
if !export_descriptors.is_null() {
|
||||
drop(unsafe { Box::from_raw(export_descriptors as *mut NamedExportDescriptors) });
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets the length of the export descriptors
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasmer_export_descriptors_len(
|
||||
exports: *mut wasmer_export_descriptors_t,
|
||||
) -> c_int {
|
||||
if exports.is_null() {
|
||||
return 0;
|
||||
}
|
||||
(*(exports as *mut NamedExportDescriptors)).0.len() as c_int
|
||||
}
|
||||
|
||||
/// Gets export descriptor by index
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasmer_export_descriptors_get(
|
||||
export_descriptors: *mut wasmer_export_descriptors_t,
|
||||
idx: c_int,
|
||||
) -> *mut wasmer_export_descriptor_t {
|
||||
if export_descriptors.is_null() {
|
||||
return ptr::null_mut();
|
||||
}
|
||||
let mut named_export_descriptors =
|
||||
unsafe { &mut *(export_descriptors as *mut NamedExportDescriptors) };
|
||||
let ptr = &mut (*named_export_descriptors).0[idx as usize] as *mut NamedExportDescriptor
|
||||
as *mut wasmer_export_descriptor_t;
|
||||
ptr
|
||||
}
|
||||
|
||||
/// Gets name for the export descriptor
|
||||
#[no_mangle]
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
pub unsafe extern "C" fn wasmer_export_descriptor_name(
|
||||
export_descriptor: *mut wasmer_export_descriptor_t,
|
||||
) -> wasmer_byte_array {
|
||||
let named_export_descriptor = &*(export_descriptor as *mut NamedExportDescriptor);
|
||||
wasmer_byte_array {
|
||||
bytes: named_export_descriptor.name.as_ptr(),
|
||||
bytes_len: named_export_descriptor.name.len() as u32,
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets export descriptor kind
|
||||
#[no_mangle]
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
pub unsafe extern "C" fn wasmer_export_descriptor_kind(
|
||||
export: *mut wasmer_export_descriptor_t,
|
||||
) -> wasmer_import_export_kind {
|
||||
let named_export_descriptor = &*(export as *mut NamedExportDescriptor);
|
||||
named_export_descriptor.kind.clone()
|
||||
}
|
||||
|
||||
/// Frees memory for the given Module
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
#[no_mangle]
|
||||
@ -479,6 +584,185 @@ pub extern "C" fn wasmer_module_destroy(module: *mut wasmer_module_t) {
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets import descriptors for the given module
|
||||
///
|
||||
/// The caller owns the object and should call `wasmer_import_descriptors_destroy` to free it.
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasmer_import_descriptors(
|
||||
module: *mut wasmer_module_t,
|
||||
import_descriptors: *mut *mut wasmer_import_descriptors_t,
|
||||
) {
|
||||
let mut module = unsafe { &*(module as *mut Module) };
|
||||
let total_imports = module.info().imported_functions.len()
|
||||
+ module.info().imported_tables.len()
|
||||
+ module.info().imported_globals.len()
|
||||
+ module.info().imported_memories.len();
|
||||
let mut descriptors: Vec<NamedImportDescriptor> = Vec::with_capacity(total_imports);
|
||||
|
||||
for (
|
||||
index,
|
||||
ImportName {
|
||||
namespace_index,
|
||||
name_index,
|
||||
},
|
||||
) in &module.info().imported_functions
|
||||
{
|
||||
let namespace = module.info().namespace_table.get(*namespace_index);
|
||||
let name = module.info().name_table.get(*name_index);
|
||||
descriptors.push(NamedImportDescriptor {
|
||||
module: namespace.to_string(),
|
||||
name: name.to_string(),
|
||||
kind: wasmer_import_export_kind::WASM_FUNCTION,
|
||||
});
|
||||
}
|
||||
|
||||
for (
|
||||
index,
|
||||
(
|
||||
ImportName {
|
||||
namespace_index,
|
||||
name_index,
|
||||
},
|
||||
_,
|
||||
),
|
||||
) in &module.info().imported_tables
|
||||
{
|
||||
let namespace = module.info().namespace_table.get(*namespace_index);
|
||||
let name = module.info().name_table.get(*name_index);
|
||||
descriptors.push(NamedImportDescriptor {
|
||||
module: namespace.to_string(),
|
||||
name: name.to_string(),
|
||||
kind: wasmer_import_export_kind::WASM_TABLE,
|
||||
});
|
||||
}
|
||||
|
||||
for (
|
||||
index,
|
||||
(
|
||||
ImportName {
|
||||
namespace_index,
|
||||
name_index,
|
||||
},
|
||||
_,
|
||||
),
|
||||
) in &module.info().imported_globals
|
||||
{
|
||||
let namespace = module.info().namespace_table.get(*namespace_index);
|
||||
let name = module.info().name_table.get(*name_index);
|
||||
descriptors.push(NamedImportDescriptor {
|
||||
module: namespace.to_string(),
|
||||
name: name.to_string(),
|
||||
kind: wasmer_import_export_kind::WASM_GLOBAL,
|
||||
});
|
||||
}
|
||||
|
||||
for (
|
||||
index,
|
||||
(
|
||||
ImportName {
|
||||
namespace_index,
|
||||
name_index,
|
||||
},
|
||||
_,
|
||||
),
|
||||
) in &module.info().imported_memories
|
||||
{
|
||||
let namespace = module.info().namespace_table.get(*namespace_index);
|
||||
let name = module.info().name_table.get(*name_index);
|
||||
descriptors.push(NamedImportDescriptor {
|
||||
module: namespace.to_string(),
|
||||
name: name.to_string(),
|
||||
kind: wasmer_import_export_kind::WASM_MEMORY,
|
||||
});
|
||||
}
|
||||
|
||||
let named_import_descriptors: Box<NamedImportDescriptors> =
|
||||
Box::new(NamedImportDescriptors(descriptors));
|
||||
unsafe {
|
||||
*import_descriptors =
|
||||
Box::into_raw(named_import_descriptors) as *mut wasmer_import_descriptors_t
|
||||
};
|
||||
}
|
||||
|
||||
pub struct NamedImportDescriptors(Vec<NamedImportDescriptor>);
|
||||
|
||||
/// Frees the memory for the given import descriptors
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasmer_import_descriptors_destroy(
|
||||
import_descriptors: *mut wasmer_import_descriptors_t,
|
||||
) {
|
||||
if !import_descriptors.is_null() {
|
||||
drop(unsafe { Box::from_raw(import_descriptors as *mut NamedImportDescriptors) });
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets the length of the import descriptors
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasmer_import_descriptors_len(
|
||||
exports: *mut wasmer_import_descriptors_t,
|
||||
) -> c_int {
|
||||
if exports.is_null() {
|
||||
return 0;
|
||||
}
|
||||
(*(exports as *mut NamedImportDescriptors)).0.len() as c_int
|
||||
}
|
||||
|
||||
/// Gets import descriptor by index
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasmer_import_descriptors_get(
|
||||
import_descriptors: *mut wasmer_import_descriptors_t,
|
||||
idx: c_int,
|
||||
) -> *mut wasmer_import_descriptor_t {
|
||||
if import_descriptors.is_null() {
|
||||
return ptr::null_mut();
|
||||
}
|
||||
let mut named_import_descriptors =
|
||||
unsafe { &mut *(import_descriptors as *mut NamedImportDescriptors) };
|
||||
let ptr = &mut (*named_import_descriptors).0[idx as usize] as *mut NamedImportDescriptor
|
||||
as *mut wasmer_import_descriptor_t;
|
||||
ptr
|
||||
}
|
||||
|
||||
/// Gets name for the import descriptor
|
||||
#[no_mangle]
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
pub unsafe extern "C" fn wasmer_import_descriptor_name(
|
||||
import_descriptor: *mut wasmer_import_descriptor_t,
|
||||
) -> wasmer_byte_array {
|
||||
let named_import_descriptor = &*(import_descriptor as *mut NamedImportDescriptor);
|
||||
wasmer_byte_array {
|
||||
bytes: named_import_descriptor.name.as_ptr(),
|
||||
bytes_len: named_import_descriptor.name.len() as u32,
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets module name for the import descriptor
|
||||
#[no_mangle]
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
pub unsafe extern "C" fn wasmer_import_descriptor_module_name(
|
||||
import_descriptor: *mut wasmer_import_descriptor_t,
|
||||
) -> wasmer_byte_array {
|
||||
let named_import_descriptor = &*(import_descriptor as *mut NamedImportDescriptor);
|
||||
wasmer_byte_array {
|
||||
bytes: named_import_descriptor.module.as_ptr(),
|
||||
bytes_len: named_import_descriptor.module.len() as u32,
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets export descriptor kind
|
||||
#[no_mangle]
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
pub unsafe extern "C" fn wasmer_import_descriptor_kind(
|
||||
export: *mut wasmer_import_descriptor_t,
|
||||
) -> wasmer_import_export_kind {
|
||||
let named_import_descriptor = &*(export as *mut NamedImportDescriptor);
|
||||
named_import_descriptor.kind.clone()
|
||||
}
|
||||
|
||||
/// Creates a new Instance from the given wasm bytes and imports.
|
||||
///
|
||||
/// Returns `wasmer_result_t::WASMER_OK` upon success.
|
||||
@ -534,12 +818,24 @@ pub unsafe extern "C" fn wasmer_instantiate(
|
||||
.or_insert_with(|| Namespace::new());
|
||||
|
||||
let export = match import.tag {
|
||||
wasmer_import_export_kind::WASM_MEMORY => import.value.memory as *mut Export,
|
||||
wasmer_import_export_kind::WASM_FUNCTION => import.value.func as *mut Export,
|
||||
wasmer_import_export_kind::WASM_GLOBAL => import.value.global as *mut Export,
|
||||
wasmer_import_export_kind::WASM_TABLE => import.value.table as *mut Export,
|
||||
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())
|
||||
}
|
||||
};
|
||||
namespace.insert(import_name, unsafe { (&*export).clone() });
|
||||
namespace.insert(import_name, unsafe { export });
|
||||
}
|
||||
for (module_name, namespace) in namespaces.into_iter() {
|
||||
import_object.register(module_name, namespace);
|
||||
@ -649,9 +945,16 @@ pub unsafe extern "C" fn wasmer_instance_exports(
|
||||
instance: *mut wasmer_instance_t,
|
||||
exports: *mut *mut wasmer_exports_t,
|
||||
) {
|
||||
let mut instance = unsafe { &mut *(instance as *mut Instance) };
|
||||
let named_exports: Box<NamedExports> =
|
||||
Box::new(NamedExports(instance.exports().map(|e| e.into()).collect()));
|
||||
let mut instance_ref = unsafe { &mut *(instance as *mut Instance) };
|
||||
let mut exports_vec: Vec<NamedExport> = Vec::with_capacity(instance_ref.exports().count());
|
||||
for (name, export) in instance_ref.exports() {
|
||||
exports_vec.push(NamedExport {
|
||||
name: name.clone(),
|
||||
export: export.clone(),
|
||||
instance: instance as *mut Instance,
|
||||
});
|
||||
}
|
||||
let named_exports: Box<NamedExports> = Box::new(NamedExports(exports_vec));
|
||||
unsafe { *exports = Box::into_raw(named_exports) as *mut wasmer_exports_t };
|
||||
}
|
||||
|
||||
@ -706,18 +1009,157 @@ pub unsafe extern "C" fn wasmer_export_kind(
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates new func
|
||||
/// Sets the result parameter to the arity of the params of the wasmer_export_func_t
|
||||
///
|
||||
/// The caller owns the object and should call `wasmer_func_destroy` to free it.
|
||||
/// Returns `wasmer_result_t::WASMER_OK` upon success.
|
||||
///
|
||||
/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
|
||||
/// and `wasmer_last_error_message` to get an error message.
|
||||
#[no_mangle]
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
pub unsafe extern "C" fn wasmer_func_new(
|
||||
pub unsafe extern "C" fn wasmer_export_func_params_arity(
|
||||
func: *mut wasmer_export_func_t,
|
||||
result: *mut uint32_t,
|
||||
) -> wasmer_result_t {
|
||||
let mut named_export = unsafe { &*(func as *mut NamedExport) };
|
||||
let mut export = &named_export.export;
|
||||
let result = if let Export::Function { ref signature, .. } = *export {
|
||||
unsafe { *result = signature.params().len() as uint32_t };
|
||||
wasmer_result_t::WASMER_OK
|
||||
} else {
|
||||
update_last_error(CApiError {
|
||||
msg: "func ptr error in wasmer_export_func_params_arity".to_string(),
|
||||
});
|
||||
wasmer_result_t::WASMER_ERROR
|
||||
};
|
||||
result
|
||||
}
|
||||
|
||||
/// Sets the params buffer to the parameter types of the given wasmer_export_func_t
|
||||
///
|
||||
/// Returns `wasmer_result_t::WASMER_OK` upon success.
|
||||
///
|
||||
/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
|
||||
/// and `wasmer_last_error_message` to get an error message.
|
||||
#[no_mangle]
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
pub unsafe extern "C" fn wasmer_export_func_params(
|
||||
func: *mut wasmer_export_func_t,
|
||||
params: *mut wasmer_value_tag,
|
||||
params_len: c_int,
|
||||
) -> wasmer_result_t {
|
||||
let mut named_export = unsafe { &*(func as *mut NamedExport) };
|
||||
let mut export = &named_export.export;
|
||||
let result = if let Export::Function { ref signature, .. } = *export {
|
||||
let params: &mut [wasmer_value_tag] =
|
||||
slice::from_raw_parts_mut(params, params_len as usize);
|
||||
for (i, item) in signature.params().iter().enumerate() {
|
||||
params[i] = item.into();
|
||||
}
|
||||
wasmer_result_t::WASMER_OK
|
||||
} else {
|
||||
update_last_error(CApiError {
|
||||
msg: "func ptr error in wasmer_export_func_params".to_string(),
|
||||
});
|
||||
wasmer_result_t::WASMER_ERROR
|
||||
};
|
||||
result
|
||||
}
|
||||
|
||||
/// Sets the returns buffer to the parameter types of the given wasmer_export_func_t
|
||||
///
|
||||
/// Returns `wasmer_result_t::WASMER_OK` upon success.
|
||||
///
|
||||
/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
|
||||
/// and `wasmer_last_error_message` to get an error message.
|
||||
#[no_mangle]
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
pub unsafe extern "C" fn wasmer_export_func_returns(
|
||||
func: *mut wasmer_export_func_t,
|
||||
returns: *mut wasmer_value_tag,
|
||||
returns_len: c_int,
|
||||
) -> wasmer_result_t {
|
||||
let mut named_export = unsafe { &*(func as *mut NamedExport) };
|
||||
let mut export = &named_export.export;
|
||||
let result = if let Export::Function { ref signature, .. } = *export {
|
||||
let returns: &mut [wasmer_value_tag] =
|
||||
slice::from_raw_parts_mut(returns, returns_len as usize);
|
||||
for (i, item) in signature.returns().iter().enumerate() {
|
||||
returns[i] = item.into();
|
||||
}
|
||||
wasmer_result_t::WASMER_OK
|
||||
} else {
|
||||
update_last_error(CApiError {
|
||||
msg: "func ptr error in wasmer_export_func_returns".to_string(),
|
||||
});
|
||||
wasmer_result_t::WASMER_ERROR
|
||||
};
|
||||
result
|
||||
}
|
||||
|
||||
/// Sets the result parameter to the arity of the returns of the wasmer_export_func_t
|
||||
///
|
||||
/// Returns `wasmer_result_t::WASMER_OK` upon success.
|
||||
///
|
||||
/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
|
||||
/// and `wasmer_last_error_message` to get an error message.
|
||||
#[no_mangle]
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
pub unsafe extern "C" fn wasmer_export_func_returns_arity(
|
||||
func: *mut wasmer_export_func_t,
|
||||
result: *mut uint32_t,
|
||||
) -> wasmer_result_t {
|
||||
let mut named_export = unsafe { &*(func as *mut NamedExport) };
|
||||
let mut export = &named_export.export;
|
||||
let result = if let Export::Function { ref signature, .. } = *export {
|
||||
unsafe { *result = signature.returns().len() as uint32_t };
|
||||
wasmer_result_t::WASMER_OK
|
||||
} else {
|
||||
update_last_error(CApiError {
|
||||
msg: "func ptr error in wasmer_export_func_results_arity".to_string(),
|
||||
});
|
||||
wasmer_result_t::WASMER_ERROR
|
||||
};
|
||||
result
|
||||
}
|
||||
|
||||
/// Sets the result parameter to the arity of the params of the wasmer_import_func_t
|
||||
///
|
||||
/// Returns `wasmer_result_t::WASMER_OK` upon success.
|
||||
///
|
||||
/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
|
||||
/// and `wasmer_last_error_message` to get an error message.
|
||||
#[no_mangle]
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
pub unsafe extern "C" fn wasmer_import_func_params_arity(
|
||||
func: *mut wasmer_import_func_t,
|
||||
result: *mut uint32_t,
|
||||
) -> wasmer_result_t {
|
||||
let mut export = unsafe { &mut *(func as *mut Export) };
|
||||
let result = if let Export::Function { ref signature, .. } = *export {
|
||||
unsafe { *result = signature.params().len() as uint32_t };
|
||||
wasmer_result_t::WASMER_OK
|
||||
} else {
|
||||
update_last_error(CApiError {
|
||||
msg: "func ptr error in wasmer_import_func_params_arity".to_string(),
|
||||
});
|
||||
wasmer_result_t::WASMER_ERROR
|
||||
};
|
||||
result
|
||||
}
|
||||
|
||||
/// Creates new func
|
||||
///
|
||||
/// The caller owns the object and should call `wasmer_import_func_destroy` to free it.
|
||||
#[no_mangle]
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
pub unsafe extern "C" fn wasmer_import_func_new(
|
||||
func: extern "C" fn(data: *mut c_void),
|
||||
params: *const wasmer_value_tag,
|
||||
params_len: c_int,
|
||||
returns: *const wasmer_value_tag,
|
||||
returns_len: c_int,
|
||||
) -> *const wasmer_func_t {
|
||||
) -> *const wasmer_import_func_t {
|
||||
let params: &[wasmer_value_tag] = slice::from_raw_parts(params, params_len as usize);
|
||||
let params: Vec<Type> = params.iter().cloned().map(|x| x.into()).collect();
|
||||
let returns: &[wasmer_value_tag] = slice::from_raw_parts(returns, returns_len as usize);
|
||||
@ -728,10 +1170,10 @@ pub unsafe extern "C" fn wasmer_func_new(
|
||||
ctx: Context::Internal,
|
||||
signature: Arc::new(FuncSig::new(params, returns)),
|
||||
});
|
||||
Box::into_raw(export) as *mut wasmer_func_t
|
||||
Box::into_raw(export) as *mut wasmer_import_func_t
|
||||
}
|
||||
|
||||
/// Sets the result parameter to the arity of the params of the wasmer_func_t
|
||||
/// Sets the params buffer to the parameter types of the given wasmer_import_func_t
|
||||
///
|
||||
/// Returns `wasmer_result_t::WASMER_OK` upon success.
|
||||
///
|
||||
@ -739,33 +1181,8 @@ pub unsafe extern "C" fn wasmer_func_new(
|
||||
/// and `wasmer_last_error_message` to get an error message.
|
||||
#[no_mangle]
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
pub unsafe extern "C" fn wasmer_func_params_arity(
|
||||
func: *mut wasmer_func_t,
|
||||
result: *mut uint32_t,
|
||||
) -> wasmer_result_t {
|
||||
let mut export = unsafe { &mut *(func as *mut Export) };
|
||||
let result = if let Export::Function { ref signature, .. } = *export {
|
||||
unsafe { *result = signature.params().len() as uint32_t };
|
||||
wasmer_result_t::WASMER_OK
|
||||
} else {
|
||||
update_last_error(CApiError {
|
||||
msg: "func ptr error in wasmer_func_params_arity".to_string(),
|
||||
});
|
||||
wasmer_result_t::WASMER_ERROR
|
||||
};
|
||||
result
|
||||
}
|
||||
|
||||
/// Sets the params buffer to the parameter types of the given wasmer_func_t
|
||||
///
|
||||
/// Returns `wasmer_result_t::WASMER_OK` upon success.
|
||||
///
|
||||
/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
|
||||
/// and `wasmer_last_error_message` to get an error message.
|
||||
#[no_mangle]
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
pub unsafe extern "C" fn wasmer_func_params(
|
||||
func: *mut wasmer_func_t,
|
||||
pub unsafe extern "C" fn wasmer_import_func_params(
|
||||
func: *mut wasmer_import_func_t,
|
||||
params: *mut wasmer_value_tag,
|
||||
params_len: c_int,
|
||||
) -> wasmer_result_t {
|
||||
@ -779,14 +1196,14 @@ pub unsafe extern "C" fn wasmer_func_params(
|
||||
wasmer_result_t::WASMER_OK
|
||||
} else {
|
||||
update_last_error(CApiError {
|
||||
msg: "func ptr error in wasmer_func_params".to_string(),
|
||||
msg: "func ptr error in wasmer_import_func_params".to_string(),
|
||||
});
|
||||
wasmer_result_t::WASMER_ERROR
|
||||
};
|
||||
result
|
||||
}
|
||||
|
||||
/// Sets the returns buffer to the parameter types of the given wasmer_func_t
|
||||
/// Sets the returns buffer to the parameter types of the given wasmer_import_func_t
|
||||
///
|
||||
/// Returns `wasmer_result_t::WASMER_OK` upon success.
|
||||
///
|
||||
@ -794,8 +1211,8 @@ pub unsafe extern "C" fn wasmer_func_params(
|
||||
/// and `wasmer_last_error_message` to get an error message.
|
||||
#[no_mangle]
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
pub unsafe extern "C" fn wasmer_func_returns(
|
||||
func: *mut wasmer_func_t,
|
||||
pub unsafe extern "C" fn wasmer_import_func_returns(
|
||||
func: *mut wasmer_import_func_t,
|
||||
returns: *mut wasmer_value_tag,
|
||||
returns_len: c_int,
|
||||
) -> wasmer_result_t {
|
||||
@ -809,14 +1226,14 @@ pub unsafe extern "C" fn wasmer_func_returns(
|
||||
wasmer_result_t::WASMER_OK
|
||||
} else {
|
||||
update_last_error(CApiError {
|
||||
msg: "func ptr error in wasmer_func_returns".to_string(),
|
||||
msg: "func ptr error in wasmer_import_func_returns".to_string(),
|
||||
});
|
||||
wasmer_result_t::WASMER_ERROR
|
||||
};
|
||||
result
|
||||
}
|
||||
|
||||
/// Sets the result parameter to the arity of the returns of the wasmer_func_t
|
||||
/// Sets the result parameter to the arity of the returns of the wasmer_import_func_t
|
||||
///
|
||||
/// Returns `wasmer_result_t::WASMER_OK` upon success.
|
||||
///
|
||||
@ -824,8 +1241,8 @@ pub unsafe extern "C" fn wasmer_func_returns(
|
||||
/// and `wasmer_last_error_message` to get an error message.
|
||||
#[no_mangle]
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
pub unsafe extern "C" fn wasmer_func_returns_arity(
|
||||
func: *mut wasmer_func_t,
|
||||
pub unsafe extern "C" fn wasmer_import_func_returns_arity(
|
||||
func: *mut wasmer_import_func_t,
|
||||
result: *mut uint32_t,
|
||||
) -> wasmer_result_t {
|
||||
let mut export = unsafe { &*(func as *mut Export) };
|
||||
@ -834,7 +1251,7 @@ pub unsafe extern "C" fn wasmer_func_returns_arity(
|
||||
wasmer_result_t::WASMER_OK
|
||||
} else {
|
||||
update_last_error(CApiError {
|
||||
msg: "func ptr error in wasmer_func_results_arity".to_string(),
|
||||
msg: "func ptr error in wasmer_import_func_results_arity".to_string(),
|
||||
});
|
||||
wasmer_result_t::WASMER_ERROR
|
||||
};
|
||||
@ -844,20 +1261,19 @@ pub unsafe extern "C" fn wasmer_func_returns_arity(
|
||||
/// Frees memory for the given Func
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
#[no_mangle]
|
||||
pub extern "C" fn wasmer_func_destroy(func: *mut wasmer_func_t) {
|
||||
pub extern "C" fn wasmer_import_func_destroy(func: *mut wasmer_import_func_t) {
|
||||
if !func.is_null() {
|
||||
drop(unsafe { Box::from_raw(func as *mut Export) });
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets func from wasm_export
|
||||
/// Gets export func from export
|
||||
#[no_mangle]
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
pub unsafe extern "C" fn wasmer_export_to_func(
|
||||
export: *mut wasmer_export_t,
|
||||
) -> *const wasmer_func_t {
|
||||
let named_export = &*(export as *mut NamedExport);
|
||||
&named_export.export as *const Export as *const wasmer_func_t
|
||||
) -> *const wasmer_export_func_t {
|
||||
export as *const wasmer_export_func_t
|
||||
}
|
||||
|
||||
/// Gets name from wasmer_export
|
||||
@ -880,8 +1296,8 @@ pub unsafe extern "C" fn wasmer_export_name(export: *mut wasmer_export_t) -> was
|
||||
/// and `wasmer_last_error_message` to get an error message.
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasmer_func_call(
|
||||
func: *mut wasmer_func_t,
|
||||
pub unsafe extern "C" fn wasmer_export_func_call(
|
||||
func: *mut wasmer_export_func_t,
|
||||
params: *const wasmer_value_t,
|
||||
params_len: c_int,
|
||||
results: *mut wasmer_value_t,
|
||||
@ -903,46 +1319,42 @@ pub unsafe extern "C" fn wasmer_func_call(
|
||||
let params: &[wasmer_value_t] = slice::from_raw_parts(params, params_len as usize);
|
||||
let params: Vec<Value> = params.iter().cloned().map(|x| x.into()).collect();
|
||||
|
||||
let export_func = unsafe { &*(func as *mut Export) };
|
||||
let named_export = unsafe { &*(func as *mut NamedExport) };
|
||||
|
||||
let results: &mut [wasmer_value_t] = slice::from_raw_parts_mut(results, results_len as usize);
|
||||
// TODO implement func.call
|
||||
update_last_error(CApiError {
|
||||
msg: "wasmer_func_call not yet implemented".to_string(),
|
||||
});
|
||||
wasmer_result_t::WASMER_ERROR
|
||||
// let result = instance.call(func_name_r, ¶ms[..]);
|
||||
// Box::into_raw(export_func);
|
||||
// match result {
|
||||
// Ok(results_vec) => {
|
||||
// if results_vec.len() > 0 {
|
||||
// let ret = match results_vec[0] {
|
||||
// Value::I32(x) => wasmer_value_t {
|
||||
// tag: wasmer_value_tag::WASM_I32,
|
||||
// value: wasmer_value { I32: x },
|
||||
// },
|
||||
// Value::I64(x) => wasmer_value_t {
|
||||
// tag: wasmer_value_tag::WASM_I64,
|
||||
// value: wasmer_value { I64: x },
|
||||
// },
|
||||
// Value::F32(x) => wasmer_value_t {
|
||||
// tag: wasmer_value_tag::WASM_F32,
|
||||
// value: wasmer_value { F32: x },
|
||||
// },
|
||||
// Value::F64(x) => wasmer_value_t {
|
||||
// tag: wasmer_value_tag::WASM_F64,
|
||||
// value: wasmer_value { F64: x },
|
||||
// },
|
||||
// };
|
||||
// results[0] = ret;
|
||||
// }
|
||||
// wasmer_result_t::WASMER_OK
|
||||
// }
|
||||
// Err(err) => {
|
||||
// update_last_error(err);
|
||||
// wasmer_result_t::WASMER_ERROR
|
||||
// }
|
||||
// }
|
||||
|
||||
let instance = &*named_export.instance;
|
||||
let result = instance.call(&named_export.name, ¶ms[..]);
|
||||
match result {
|
||||
Ok(results_vec) => {
|
||||
if results_vec.len() > 0 {
|
||||
let ret = match results_vec[0] {
|
||||
Value::I32(x) => wasmer_value_t {
|
||||
tag: wasmer_value_tag::WASM_I32,
|
||||
value: wasmer_value { I32: x },
|
||||
},
|
||||
Value::I64(x) => wasmer_value_t {
|
||||
tag: wasmer_value_tag::WASM_I64,
|
||||
value: wasmer_value { I64: x },
|
||||
},
|
||||
Value::F32(x) => wasmer_value_t {
|
||||
tag: wasmer_value_tag::WASM_F32,
|
||||
value: wasmer_value { F32: x },
|
||||
},
|
||||
Value::F64(x) => wasmer_value_t {
|
||||
tag: wasmer_value_tag::WASM_F64,
|
||||
value: wasmer_value { F64: x },
|
||||
},
|
||||
};
|
||||
results[0] = ret;
|
||||
}
|
||||
wasmer_result_t::WASMER_OK
|
||||
}
|
||||
Err(err) => {
|
||||
update_last_error(err);
|
||||
wasmer_result_t::WASMER_ERROR
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets the memory within the context at the index `memory_idx`.
|
||||
@ -1060,12 +1472,6 @@ impl From<wasmer_value_tag> for Type {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<(std::string::String, wasmer_runtime_core::export::Export)> for NamedExport {
|
||||
fn from((name, export): (String, Export)) -> Self {
|
||||
NamedExport { name, export }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&wasmer_runtime::wasm::Type> for wasmer_value_tag {
|
||||
fn from(ty: &Type) -> Self {
|
||||
match *ty {
|
||||
@ -1077,6 +1483,21 @@ impl From<&wasmer_runtime::wasm::Type> for wasmer_value_tag {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<(&std::string::String, &ExportIndex)> for NamedExportDescriptor {
|
||||
fn from((name, export_index): (&String, &ExportIndex)) -> Self {
|
||||
let kind = match *export_index {
|
||||
ExportIndex::Memory(_) => wasmer_import_export_kind::WASM_MEMORY,
|
||||
ExportIndex::Global(_) => wasmer_import_export_kind::WASM_GLOBAL,
|
||||
ExportIndex::Table(_) => wasmer_import_export_kind::WASM_TABLE,
|
||||
ExportIndex::Func(_) => wasmer_import_export_kind::WASM_FUNCTION,
|
||||
};
|
||||
NamedExportDescriptor {
|
||||
name: name.clone(),
|
||||
kind,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Error reporting
|
||||
|
||||
thread_local! {
|
||||
@ -1171,7 +1592,19 @@ impl fmt::Display for CApiError {
|
||||
|
||||
impl Error for CApiError {}
|
||||
|
||||
struct NamedImportDescriptor {
|
||||
module: String,
|
||||
name: String,
|
||||
kind: wasmer_import_export_kind,
|
||||
}
|
||||
|
||||
struct NamedExport {
|
||||
name: String,
|
||||
export: Export,
|
||||
instance: *mut Instance,
|
||||
}
|
||||
|
||||
struct NamedExportDescriptor {
|
||||
name: String,
|
||||
kind: wasmer_import_export_kind,
|
||||
}
|
||||
|
3
lib/runtime-c-api/tests/.gitignore
vendored
3
lib/runtime-c-api/tests/.gitignore
vendored
@ -12,9 +12,12 @@ _deps
|
||||
test-globals
|
||||
test-exports
|
||||
test-instantiate
|
||||
test-imports
|
||||
test-import-function
|
||||
test-memory
|
||||
test-module-imports
|
||||
test-module
|
||||
test-module-exports
|
||||
test-tables
|
||||
test-validate
|
||||
rust-build
|
@ -1,12 +1,15 @@
|
||||
cmake_minimum_required (VERSION 2.6)
|
||||
project (WasmerCApiTests)
|
||||
|
||||
add_executable(test-imports test-imports.c)
|
||||
add_executable(test-exports test-exports.c)
|
||||
add_executable(test-globals test-globals.c)
|
||||
add_executable(test-instantiate test-instantiate.c)
|
||||
add_executable(test-import-function test-import-function.c)
|
||||
add_executable(test-memory test-memory.c)
|
||||
add_executable(test-module-imports test-module-imports.c)
|
||||
add_executable(test-module test-module.c)
|
||||
add_executable(test-module-exports test-module-exports.c)
|
||||
add_executable(test-validate test-validate.c)
|
||||
add_executable(test-tables test-tables.c)
|
||||
|
||||
@ -19,6 +22,8 @@ if(NOT WASMER_LIB)
|
||||
message(FATAL_ERROR "wasmer library not found")
|
||||
endif()
|
||||
|
||||
target_link_libraries(test-imports
|
||||
general ${WASMER_LIB})
|
||||
target_link_libraries(test-exports
|
||||
general ${WASMER_LIB})
|
||||
target_link_libraries(test-globals
|
||||
@ -29,20 +34,27 @@ target_link_libraries(test-import-function
|
||||
general ${WASMER_LIB})
|
||||
target_link_libraries(test-memory
|
||||
general ${WASMER_LIB})
|
||||
target_link_libraries(test-module-imports
|
||||
general ${WASMER_LIB})
|
||||
target_link_libraries(test-module
|
||||
general ${WASMER_LIB})
|
||||
target_link_libraries(test-module-exports
|
||||
general ${WASMER_LIB})
|
||||
target_link_libraries(test-validate
|
||||
general ${WASMER_LIB})
|
||||
target_link_libraries(test-tables
|
||||
general ${WASMER_LIB})
|
||||
|
||||
enable_testing()
|
||||
add_test(test-imports test-imports)
|
||||
add_test(test-exports test-exports)
|
||||
add_test(test-globals test-globals)
|
||||
add_test(test-instantiate test-instantiate)
|
||||
add_test(test-import-function test-import-function)
|
||||
add_test(test-memory test-memory)
|
||||
add_test(test-module-imports test-module-imports)
|
||||
add_test(test-module test-module)
|
||||
add_test(test-module-exports test-module-exports)
|
||||
add_test(test-validate test-validate)
|
||||
add_test(test-tables test-tables)
|
||||
|
||||
|
BIN
lib/runtime-c-api/tests/hello_wasm.wasm
Normal file
BIN
lib/runtime-c-api/tests/hello_wasm.wasm
Normal file
Binary file not shown.
@ -31,7 +31,7 @@ int main()
|
||||
|
||||
wasmer_import_export_kind kind = wasmer_export_kind(export);
|
||||
assert(kind == WASM_FUNCTION);
|
||||
wasmer_func_t *func = wasmer_export_to_func(export);
|
||||
wasmer_export_func_t *func = wasmer_export_to_func(export);
|
||||
|
||||
wasmer_byte_array name_bytes = wasmer_export_name(export);
|
||||
assert(name_bytes.bytes_len == 3);
|
||||
@ -42,40 +42,40 @@ int main()
|
||||
}
|
||||
|
||||
uint32_t params_arity;
|
||||
wasmer_func_params_arity(func, ¶ms_arity);
|
||||
wasmer_export_func_params_arity(func, ¶ms_arity);
|
||||
assert(params_arity == 2);
|
||||
|
||||
wasmer_value_tag *params_sig = malloc(sizeof(wasmer_value_tag) * params_arity);
|
||||
wasmer_func_params(func, params_sig , params_arity);
|
||||
wasmer_export_func_params(func, params_sig , params_arity);
|
||||
assert(params_sig[0] == WASM_I32);
|
||||
assert(params_sig[1] == WASM_I32);
|
||||
free(params_sig);
|
||||
|
||||
uint32_t returns_arity;
|
||||
wasmer_func_returns_arity(func, &returns_arity);
|
||||
wasmer_export_func_returns_arity(func, &returns_arity);
|
||||
assert(returns_arity == 1);
|
||||
|
||||
wasmer_value_tag *returns_sig = malloc(sizeof(wasmer_value_tag) * returns_arity);
|
||||
wasmer_func_returns(func, returns_sig , returns_arity);
|
||||
wasmer_export_func_returns(func, returns_sig , returns_arity);
|
||||
assert(returns_sig[0] == WASM_I32);
|
||||
free(returns_sig);
|
||||
|
||||
|
||||
// wasmer_value_t param_one;
|
||||
// param_one.tag = WASM_I32;
|
||||
// param_one.value.I32 = 7;
|
||||
// wasmer_value_t param_two;
|
||||
// param_two.tag = WASM_I32;
|
||||
// param_two.value.I32 = 8;
|
||||
// wasmer_value_t params[] = {param_one, param_two};
|
||||
// wasmer_value_t result_one;
|
||||
// wasmer_value_t results[] = {result_one};
|
||||
//
|
||||
// wasmer_result_t call_result = wasmer_func_call(func, params, 2, results, 1);
|
||||
// printf("Call result: %d\n", call_result);
|
||||
// printf("Result: %d\n", results[0].value.I32);
|
||||
// assert(results[0].value.I32 == 15);
|
||||
// assert(call_result == WASMER_OK);
|
||||
wasmer_value_t param_one;
|
||||
param_one.tag = WASM_I32;
|
||||
param_one.value.I32 = 7;
|
||||
wasmer_value_t param_two;
|
||||
param_two.tag = WASM_I32;
|
||||
param_two.value.I32 = 8;
|
||||
wasmer_value_t params[] = {param_one, param_two};
|
||||
wasmer_value_t result_one;
|
||||
wasmer_value_t results[] = {result_one};
|
||||
|
||||
wasmer_result_t call_result = wasmer_export_func_call(func, params, 2, results, 1);
|
||||
printf("Call result: %d\n", call_result);
|
||||
printf("Result: %d\n", results[0].value.I32);
|
||||
assert(results[0].value.I32 == 15);
|
||||
assert(call_result == WASMER_OK);
|
||||
|
||||
|
||||
printf("Destroy instance\n");
|
||||
|
@ -31,7 +31,7 @@ int main()
|
||||
wasmer_value_tag returns_sig[] = {};
|
||||
|
||||
printf("Creating new func\n");
|
||||
wasmer_func_t *func = wasmer_func_new(print_str, params_sig, 2, returns_sig, 0);
|
||||
wasmer_import_func_t *func = wasmer_import_func_new(print_str, params_sig, 2, returns_sig, 0);
|
||||
wasmer_import_t import;
|
||||
|
||||
char *module_name = "env";
|
||||
@ -84,7 +84,7 @@ int main()
|
||||
assert(0 == strcmp(actual_str, "Hello, World!"));
|
||||
|
||||
printf("Destroying func\n");
|
||||
wasmer_func_destroy(func);
|
||||
wasmer_import_func_destroy(func);
|
||||
printf("Destroy instance\n");
|
||||
wasmer_instance_destroy(instance);
|
||||
return 0;
|
||||
|
154
lib/runtime-c-api/tests/test-imports.c
Normal file
154
lib/runtime-c-api/tests/test-imports.c
Normal file
@ -0,0 +1,154 @@
|
||||
#include <stdio.h>
|
||||
#include "../wasmer.h"
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
|
||||
static print_str_called = false;
|
||||
|
||||
// Host function that will be imported into the Web Assembly Instance
|
||||
void print_str(wasmer_instance_context_t *ctx, int32_t ptr, int32_t len)
|
||||
{
|
||||
print_str_called = true;
|
||||
wasmer_memory_t *memory = wasmer_instance_context_memory(ctx, 0);
|
||||
uint32_t mem_len = wasmer_memory_length(memory);
|
||||
uint8_t *mem_bytes = wasmer_memory_data(memory);
|
||||
printf("%.*s", len, mem_bytes + ptr);
|
||||
}
|
||||
|
||||
// Use the last_error API to retrieve error messages
|
||||
void print_wasmer_error()
|
||||
{
|
||||
int error_len = wasmer_last_error_length();
|
||||
printf("Error len: `%d`\n", error_len);
|
||||
char *error_str = malloc(error_len);
|
||||
wasmer_last_error_message(error_str, error_len);
|
||||
printf("Error str: `%s`\n", error_str);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
// Create a new func to hold the parameter and signature
|
||||
// of our `print_str` host function
|
||||
wasmer_value_tag params_sig[] = {WASM_I32, WASM_I32};
|
||||
wasmer_value_tag returns_sig[] = {};
|
||||
wasmer_import_func_t *func = wasmer_import_func_new(print_str, params_sig, 2, returns_sig, 0);
|
||||
|
||||
// Create module name for our imports
|
||||
// represented in bytes for UTF-8 compatability
|
||||
char *module_name = "env";
|
||||
wasmer_byte_array module_name_bytes;
|
||||
module_name_bytes.bytes = module_name;
|
||||
module_name_bytes.bytes_len = strlen(module_name);
|
||||
|
||||
// Define a function import
|
||||
char *import_name = "_print_str";
|
||||
wasmer_byte_array import_name_bytes;
|
||||
import_name_bytes.bytes = import_name;
|
||||
import_name_bytes.bytes_len = strlen(import_name);
|
||||
wasmer_import_t func_import;
|
||||
func_import.module_name = module_name_bytes;
|
||||
func_import.import_name = import_name_bytes;
|
||||
func_import.tag = WASM_FUNCTION;
|
||||
func_import.value.func = func;
|
||||
|
||||
// Define a memory import
|
||||
char *import_memory_name = "memory";
|
||||
wasmer_byte_array import_memory_name_bytes;
|
||||
import_memory_name_bytes.bytes = import_memory_name;
|
||||
import_memory_name_bytes.bytes_len = strlen(import_memory_name);
|
||||
wasmer_import_t memory_import;
|
||||
memory_import.module_name = module_name_bytes;
|
||||
memory_import.import_name = import_memory_name_bytes;
|
||||
memory_import.tag = WASM_MEMORY;
|
||||
wasmer_memory_t *memory = NULL;
|
||||
wasmer_limits_t descriptor;
|
||||
descriptor.min = 256;
|
||||
wasmer_limit_option_t max;
|
||||
max.has_some = true;
|
||||
max.some = 256;
|
||||
descriptor.max = max;
|
||||
wasmer_result_t memory_result = wasmer_memory_new(&memory, descriptor);
|
||||
if (memory_result != WASMER_OK)
|
||||
{
|
||||
print_wasmer_error();
|
||||
}
|
||||
memory_import.value.memory = memory;
|
||||
|
||||
// Define a global import
|
||||
char *import_global_name = "__memory_base";
|
||||
wasmer_byte_array import_global_name_bytes;
|
||||
import_global_name_bytes.bytes = import_global_name;
|
||||
import_global_name_bytes.bytes_len = strlen(import_global_name);
|
||||
wasmer_import_t global_import;
|
||||
global_import.module_name = module_name_bytes;
|
||||
global_import.import_name = import_global_name_bytes;
|
||||
global_import.tag = WASM_GLOBAL;
|
||||
wasmer_value_t val;
|
||||
val.tag = WASM_I32;
|
||||
val.value.I32 = 1024;
|
||||
wasmer_global_t *global = wasmer_global_new(val, false);
|
||||
global_import.value.global = global;
|
||||
|
||||
// Define a table import
|
||||
char *import_table_name = "table";
|
||||
wasmer_byte_array import_table_name_bytes;
|
||||
import_table_name_bytes.bytes = import_table_name;
|
||||
import_table_name_bytes.bytes_len = strlen(import_table_name);
|
||||
wasmer_import_t table_import;
|
||||
table_import.module_name = module_name_bytes;
|
||||
table_import.import_name = import_table_name_bytes;
|
||||
table_import.tag = WASM_TABLE;
|
||||
wasmer_table_t *table = NULL;
|
||||
wasmer_limits_t table_descriptor;
|
||||
table_descriptor.min = 256;
|
||||
wasmer_limit_option_t table_max;
|
||||
table_max.has_some = true;
|
||||
table_max.some = 256;
|
||||
table_descriptor.max = table_max;
|
||||
wasmer_result_t table_result = wasmer_table_new(&table, table_descriptor);
|
||||
if (table_result != WASMER_OK)
|
||||
{
|
||||
print_wasmer_error();
|
||||
}
|
||||
table_import.value.table = table;
|
||||
|
||||
// Define an array containing our imports
|
||||
wasmer_import_t imports[] = {func_import, global_import, memory_import, table_import};
|
||||
|
||||
// Read the wasm file bytes
|
||||
FILE *file = fopen("hello_wasm.wasm", "r");
|
||||
fseek(file, 0, SEEK_END);
|
||||
long len = ftell(file);
|
||||
uint8_t *bytes = malloc(len);
|
||||
fseek(file, 0, SEEK_SET);
|
||||
fread(bytes, 1, len, file);
|
||||
fclose(file);
|
||||
|
||||
// Creates a WebAssembly Instance from wasm bytes and imports
|
||||
wasmer_instance_t *instance = NULL;
|
||||
wasmer_result_t compile_result = wasmer_instantiate(&instance, bytes, len, imports, 3);
|
||||
printf("Compile result: %d\n", compile_result);
|
||||
if (compile_result != WASMER_OK)
|
||||
{
|
||||
print_wasmer_error();
|
||||
}
|
||||
assert(compile_result == WASMER_OK);
|
||||
|
||||
// Call the exported "hello_wasm" function of our instance
|
||||
wasmer_value_t params[] = {};
|
||||
wasmer_value_t result_one;
|
||||
wasmer_value_t results[] = {result_one};
|
||||
wasmer_result_t call_result = wasmer_instance_call(instance, "_hello_wasm", params, 0, results, 1);
|
||||
printf("Call result: %d\n", call_result);
|
||||
assert(call_result == WASMER_OK);
|
||||
assert(print_str_called);
|
||||
|
||||
// Use *_destroy methods to cleanup as specified in the header documentation
|
||||
wasmer_import_func_destroy(func);
|
||||
wasmer_global_destroy(global);
|
||||
wasmer_memory_destroy(memory);
|
||||
wasmer_table_destroy(table);
|
||||
wasmer_instance_destroy(instance);
|
||||
|
||||
return 0;
|
||||
}
|
@ -23,13 +23,13 @@ int main()
|
||||
wasmer_result_t grow_result = wasmer_memory_grow(memory, 2);
|
||||
assert(grow_result == WASMER_OK);
|
||||
|
||||
uint32_t new_len = wasmer_memory_length(memory);
|
||||
uint32_t new_len = wasmer_memory_length(memory);
|
||||
printf("Memory pages length: %d\n", new_len);
|
||||
assert(new_len == 12);
|
||||
|
||||
uint32_t bytes_len = wasmer_memory_data_length(memory);
|
||||
uint32_t bytes_len = wasmer_memory_data_length(memory);
|
||||
printf("Memory bytes length: %d\n", bytes_len);
|
||||
assert(bytes_len == 12 * 65536);
|
||||
assert(bytes_len == 12 * 65536);
|
||||
|
||||
// Err, grow beyond max
|
||||
wasmer_result_t grow_result2 = wasmer_memory_grow(memory, 10);
|
||||
@ -38,23 +38,26 @@ int main()
|
||||
char *error_str = malloc(error_len);
|
||||
wasmer_last_error_message(error_str, error_len);
|
||||
printf("Error str: `%s`\n", error_str);
|
||||
assert(0 == strcmp(error_str, "unable to grow memory"));
|
||||
assert(0 == strcmp(error_str, "Failed to add pages because would exceed maximum number of pages for the memory. Left: 22, Added: 15"));
|
||||
free(error_str);
|
||||
|
||||
wasmer_memory_t *bad_memory = NULL;
|
||||
wasmer_limits_t bad_descriptor;
|
||||
bad_descriptor.min = 15;
|
||||
wasmer_limit_option_t max2;
|
||||
max2.has_some = true;
|
||||
max2.some = 10;
|
||||
bad_descriptor.max = max2;
|
||||
wasmer_result_t bad_memory_result = wasmer_memory_new(&bad_memory, bad_descriptor);
|
||||
printf("Bad memory result: %d\n", bad_memory_result);
|
||||
assert(bad_memory_result == WASMER_ERROR);
|
||||
|
||||
// wasmer_memory_t *bad_memory = NULL;
|
||||
// wasmer_limits_t bad_descriptor;
|
||||
// bad_descriptor.min = 15;
|
||||
// bad_descriptor.max = 10;
|
||||
// wasmer_result_t bad_memory_result = wasmer_memory_new(&bad_memory, bad_descriptor);
|
||||
// printf("Bad memory result: %d\n", bad_memory_result);
|
||||
// assert(memory_result == WASMER_MEMORY_ERROR);
|
||||
//
|
||||
// int error_len = wasmer_last_error_length();
|
||||
// char *error_str = malloc(error_len);
|
||||
// wasmer_last_error_message(error_str, error_len);
|
||||
// assert(0 == strcmp(error_str, "Creation error"));
|
||||
// free(error_str);
|
||||
int error_len2 = wasmer_last_error_length();
|
||||
char *error_str2 = malloc(error_len2);
|
||||
wasmer_last_error_message(error_str2, error_len2);
|
||||
printf("Error str 2: `%s`\n", error_str2);
|
||||
assert(0 == strcmp(error_str2, "Unable to create because the supplied descriptor is invalid: \"Max number of memory pages is less than the minimum number of pages\""));
|
||||
free(error_str2);
|
||||
|
||||
printf("Destroy memory\n");
|
||||
wasmer_memory_destroy(memory);
|
||||
|
53
lib/runtime-c-api/tests/test-module-exports.c
Normal file
53
lib/runtime-c-api/tests/test-module-exports.c
Normal file
@ -0,0 +1,53 @@
|
||||
#include <stdio.h>
|
||||
#include "../wasmer.h"
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
// Read the wasm file bytes
|
||||
FILE *file = fopen("sum.wasm", "r");
|
||||
fseek(file, 0, SEEK_END);
|
||||
long len = ftell(file);
|
||||
uint8_t *bytes = malloc(len);
|
||||
fseek(file, 0, SEEK_SET);
|
||||
fread(bytes, 1, len, file);
|
||||
fclose(file);
|
||||
|
||||
wasmer_module_t *module = NULL;
|
||||
wasmer_result_t compile_result = wasmer_compile(&module, bytes, len);
|
||||
printf("Compile result: %d\n", compile_result);
|
||||
assert(compile_result == WASMER_OK);
|
||||
|
||||
wasmer_import_t imports[] = {};
|
||||
wasmer_instance_t *instance = NULL;
|
||||
wasmer_result_t instantiate_result = wasmer_module_instantiate(module, &instance, imports, 0);
|
||||
printf("Instantiate result: %d\n", compile_result);
|
||||
assert(instantiate_result == WASMER_OK);
|
||||
|
||||
wasmer_export_descriptors_t *exports = NULL;
|
||||
wasmer_export_descriptors(module, &exports);
|
||||
|
||||
int exports_len = wasmer_export_descriptors_len(exports);
|
||||
printf("exports_len: %d\n", exports_len);
|
||||
assert(exports_len == 1);
|
||||
|
||||
wasmer_export_descriptor_t *export = wasmer_export_descriptors_get(exports, 0);
|
||||
|
||||
wasmer_import_export_kind kind = wasmer_export_descriptor_kind(export);
|
||||
assert(kind == WASM_FUNCTION);
|
||||
|
||||
wasmer_byte_array name_bytes = wasmer_export_descriptor_name(export);
|
||||
assert(name_bytes.bytes_len == 3);
|
||||
char expected[] = {'s', 'u', 'm'};
|
||||
for(int idx = 0; idx < 3; idx++){
|
||||
printf("%c\n", name_bytes.bytes[idx]);
|
||||
assert(name_bytes.bytes[idx] == expected[idx]);
|
||||
}
|
||||
|
||||
printf("Destroy module\n");
|
||||
wasmer_module_destroy(module);
|
||||
printf("Destroy exports\n");
|
||||
wasmer_export_descriptors_destroy(exports);
|
||||
return 0;
|
||||
}
|
56
lib/runtime-c-api/tests/test-module-imports.c
Normal file
56
lib/runtime-c-api/tests/test-module-imports.c
Normal file
@ -0,0 +1,56 @@
|
||||
#include <stdio.h>
|
||||
#include "../wasmer.h"
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
// Read the wasm file bytes
|
||||
FILE *file = fopen("wasm_sample_app.wasm", "r");
|
||||
fseek(file, 0, SEEK_END);
|
||||
long len = ftell(file);
|
||||
uint8_t *bytes = malloc(len);
|
||||
fseek(file, 0, SEEK_SET);
|
||||
fread(bytes, 1, len, file);
|
||||
fclose(file);
|
||||
|
||||
wasmer_module_t *module = NULL;
|
||||
wasmer_result_t compile_result = wasmer_compile(&module, bytes, len);
|
||||
printf("Compile result: %d\n", compile_result);
|
||||
assert(compile_result == WASMER_OK);
|
||||
|
||||
wasmer_import_descriptors_t *imports = NULL;
|
||||
wasmer_import_descriptors(module, &imports);
|
||||
|
||||
int imports_len = wasmer_import_descriptors_len(imports);
|
||||
printf("imports_len: %d\n", imports_len);
|
||||
assert(imports_len == 1);
|
||||
|
||||
wasmer_import_descriptor_t *import = wasmer_import_descriptors_get(imports, 0);
|
||||
|
||||
wasmer_import_export_kind kind = wasmer_import_descriptor_kind(import);
|
||||
assert(kind == WASM_FUNCTION);
|
||||
|
||||
wasmer_byte_array name_bytes = wasmer_import_descriptor_name(import);
|
||||
assert(name_bytes.bytes_len == 9);
|
||||
char expected[] = {'p', 'r', 'i', 'n', 't', '_', 's', 't', 'r'};
|
||||
|
||||
for(int idx = 0; idx < 9; idx++){
|
||||
printf("%c\n", name_bytes.bytes[idx]);
|
||||
assert(name_bytes.bytes[idx] == expected[idx]);
|
||||
}
|
||||
|
||||
wasmer_byte_array module_name_bytes = wasmer_import_descriptor_module_name(import);
|
||||
assert(module_name_bytes.bytes_len == 3);
|
||||
char module_expected[] = {'e', 'n', 'v'};
|
||||
for(int idx = 0; idx < 3; idx++){
|
||||
printf("%c\n", module_name_bytes.bytes[idx]);
|
||||
assert(module_name_bytes.bytes[idx] == module_expected[idx]);
|
||||
}
|
||||
|
||||
printf("Destroy module\n");
|
||||
wasmer_module_destroy(module);
|
||||
printf("Destroy imports\n");
|
||||
wasmer_import_descriptors_destroy(imports);
|
||||
return 0;
|
||||
}
|
@ -9,7 +9,7 @@ int main()
|
||||
wasmer_limits_t descriptor;
|
||||
descriptor.min = 10;
|
||||
wasmer_limit_option_t max;
|
||||
// max.has_some = false;
|
||||
// max.has_some = false;
|
||||
max.has_some = true;
|
||||
max.some = 15;
|
||||
descriptor.max = max;
|
||||
@ -21,26 +21,29 @@ int main()
|
||||
printf("Table length: %d\n", len);
|
||||
assert(len == 10);
|
||||
|
||||
// wasmer_result_t grow_result1 = wasmer_table_grow(table, 5);
|
||||
// assert(grow_result1 == WASMER_OK);
|
||||
// uint32_t len_grow1 = wasmer_table_length(table);
|
||||
// printf("Table length: %d\n", len_grow1);
|
||||
// assert(len_grow1 == 15);
|
||||
wasmer_result_t grow_result1 = wasmer_table_grow(table, 5);
|
||||
assert(grow_result1 == WASMER_OK);
|
||||
uint32_t len_grow1 = wasmer_table_length(table);
|
||||
printf("Table length: %d\n", len_grow1);
|
||||
assert(len_grow1 == 15);
|
||||
|
||||
// // Try to grow beyond max
|
||||
// wasmer_result_t grow_result2 = wasmer_table_grow(&table, 1);
|
||||
// assert(grow_result2 == WASMER_ERROR);
|
||||
// uint32_t len_grow2 = wasmer_table_length(table);
|
||||
// printf("Table length: %d\n", len_grow2);
|
||||
// assert(len_grow2 == 15);
|
||||
// Try to grow beyond max
|
||||
wasmer_result_t grow_result2 = wasmer_table_grow(table, 1);
|
||||
assert(grow_result2 == WASMER_ERROR);
|
||||
uint32_t len_grow2 = wasmer_table_length(table);
|
||||
printf("Table length: %d\n", len_grow2);
|
||||
assert(len_grow2 == 15);
|
||||
|
||||
// wasmer_table_t *table_bad = NULL;
|
||||
// wasmer_limits_t bad_descriptor;
|
||||
// bad_descriptor.min = 15;
|
||||
// bad_descriptor.max = 10;
|
||||
// wasmer_result_t table_bad_result = wasmer_table_new(&table_bad, bad_descriptor);
|
||||
// printf("Table result: %d\n", table_bad_result);
|
||||
// assert(table_result == WASMER_ERROR);
|
||||
wasmer_table_t *table_bad = NULL;
|
||||
wasmer_limits_t bad_descriptor;
|
||||
bad_descriptor.min = 15;
|
||||
wasmer_limit_option_t max2;
|
||||
max2.has_some = true;
|
||||
max2.some = 10;
|
||||
bad_descriptor.max = max2;
|
||||
wasmer_result_t table_bad_result = wasmer_table_new(&table_bad, bad_descriptor);
|
||||
printf("Table result: %d\n", table_bad_result);
|
||||
assert(table_bad_result == WASMER_ERROR);
|
||||
|
||||
printf("Destroy table\n");
|
||||
wasmer_table_destroy(table);
|
||||
|
@ -35,7 +35,7 @@ typedef struct wasmer_module_t wasmer_module_t;
|
||||
|
||||
typedef struct {
|
||||
|
||||
} wasmer_export_t;
|
||||
} wasmer_export_descriptor_t;
|
||||
|
||||
typedef struct {
|
||||
const uint8_t *bytes;
|
||||
@ -44,11 +44,11 @@ typedef struct {
|
||||
|
||||
typedef struct {
|
||||
|
||||
} wasmer_func_t;
|
||||
} wasmer_export_descriptors_t;
|
||||
|
||||
typedef struct {
|
||||
|
||||
} wasmer_exports_t;
|
||||
} wasmer_export_func_t;
|
||||
|
||||
typedef union {
|
||||
int32_t I32;
|
||||
@ -64,6 +64,14 @@ typedef struct {
|
||||
|
||||
typedef struct {
|
||||
|
||||
} wasmer_export_t;
|
||||
|
||||
typedef struct {
|
||||
|
||||
} wasmer_exports_t;
|
||||
|
||||
typedef struct {
|
||||
|
||||
} wasmer_global_t;
|
||||
|
||||
typedef struct {
|
||||
@ -73,6 +81,18 @@ typedef struct {
|
||||
|
||||
typedef struct {
|
||||
|
||||
} wasmer_import_descriptor_t;
|
||||
|
||||
typedef struct {
|
||||
|
||||
} wasmer_import_descriptors_t;
|
||||
|
||||
typedef struct {
|
||||
|
||||
} wasmer_import_func_t;
|
||||
|
||||
typedef struct {
|
||||
|
||||
} wasmer_memory_t;
|
||||
|
||||
typedef struct {
|
||||
@ -80,7 +100,7 @@ typedef struct {
|
||||
} wasmer_table_t;
|
||||
|
||||
typedef union {
|
||||
const wasmer_func_t *func;
|
||||
const wasmer_import_func_t *func;
|
||||
const wasmer_table_t *table;
|
||||
const wasmer_memory_t *memory;
|
||||
const wasmer_global_t *global;
|
||||
@ -113,6 +133,88 @@ wasmer_result_t wasmer_compile(wasmer_module_t **module,
|
||||
uint8_t *wasm_bytes,
|
||||
uint32_t wasm_bytes_len);
|
||||
|
||||
/**
|
||||
* Gets export descriptor kind
|
||||
*/
|
||||
wasmer_import_export_kind wasmer_export_descriptor_kind(wasmer_export_descriptor_t *export_);
|
||||
|
||||
/**
|
||||
* Gets name for the export descriptor
|
||||
*/
|
||||
wasmer_byte_array wasmer_export_descriptor_name(wasmer_export_descriptor_t *export_descriptor);
|
||||
|
||||
/**
|
||||
* Gets export descriptors for the given module
|
||||
* The caller owns the object and should call `wasmer_export_descriptors_destroy` to free it.
|
||||
*/
|
||||
void wasmer_export_descriptors(wasmer_module_t *module,
|
||||
wasmer_export_descriptors_t **export_descriptors);
|
||||
|
||||
/**
|
||||
* Frees the memory for the given export descriptors
|
||||
*/
|
||||
void wasmer_export_descriptors_destroy(wasmer_export_descriptors_t *export_descriptors);
|
||||
|
||||
/**
|
||||
* Gets export descriptor by index
|
||||
*/
|
||||
wasmer_export_descriptor_t *wasmer_export_descriptors_get(wasmer_export_descriptors_t *export_descriptors,
|
||||
int idx);
|
||||
|
||||
/**
|
||||
* Gets the length of the export descriptors
|
||||
*/
|
||||
int wasmer_export_descriptors_len(wasmer_export_descriptors_t *exports);
|
||||
|
||||
/**
|
||||
* Calls a `func` with the provided parameters.
|
||||
* Results are set using the provided `results` pointer.
|
||||
* Returns `wasmer_result_t::WASMER_OK` upon success.
|
||||
* Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
|
||||
* and `wasmer_last_error_message` to get an error message.
|
||||
*/
|
||||
wasmer_result_t wasmer_export_func_call(wasmer_export_func_t *func,
|
||||
const wasmer_value_t *params,
|
||||
int params_len,
|
||||
wasmer_value_t *results,
|
||||
int results_len);
|
||||
|
||||
/**
|
||||
* Sets the params buffer to the parameter types of the given wasmer_export_func_t
|
||||
* Returns `wasmer_result_t::WASMER_OK` upon success.
|
||||
* Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
|
||||
* and `wasmer_last_error_message` to get an error message.
|
||||
*/
|
||||
wasmer_result_t wasmer_export_func_params(wasmer_export_func_t *func,
|
||||
wasmer_value_tag *params,
|
||||
int params_len);
|
||||
|
||||
/**
|
||||
* Sets the result parameter to the arity of the params of the wasmer_export_func_t
|
||||
* Returns `wasmer_result_t::WASMER_OK` upon success.
|
||||
* Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
|
||||
* and `wasmer_last_error_message` to get an error message.
|
||||
*/
|
||||
wasmer_result_t wasmer_export_func_params_arity(wasmer_export_func_t *func, uint32_t *result);
|
||||
|
||||
/**
|
||||
* Sets the returns buffer to the parameter types of the given wasmer_export_func_t
|
||||
* Returns `wasmer_result_t::WASMER_OK` upon success.
|
||||
* Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
|
||||
* and `wasmer_last_error_message` to get an error message.
|
||||
*/
|
||||
wasmer_result_t wasmer_export_func_returns(wasmer_export_func_t *func,
|
||||
wasmer_value_tag *returns,
|
||||
int returns_len);
|
||||
|
||||
/**
|
||||
* Sets the result parameter to the arity of the returns of the wasmer_export_func_t
|
||||
* Returns `wasmer_result_t::WASMER_OK` upon success.
|
||||
* Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
|
||||
* and `wasmer_last_error_message` to get an error message.
|
||||
*/
|
||||
wasmer_result_t wasmer_export_func_returns_arity(wasmer_export_func_t *func, uint32_t *result);
|
||||
|
||||
/**
|
||||
* Gets wasmer_export kind
|
||||
*/
|
||||
@ -124,9 +226,9 @@ wasmer_import_export_kind wasmer_export_kind(wasmer_export_t *export_);
|
||||
wasmer_byte_array wasmer_export_name(wasmer_export_t *export_);
|
||||
|
||||
/**
|
||||
* Gets func from wasm_export
|
||||
* Gets export func from export
|
||||
*/
|
||||
const wasmer_func_t *wasmer_export_to_func(wasmer_export_t *export_);
|
||||
const wasmer_export_func_t *wasmer_export_to_func(wasmer_export_t *export_);
|
||||
|
||||
/**
|
||||
* Frees the memory for the given exports
|
||||
@ -143,68 +245,6 @@ wasmer_export_t *wasmer_exports_get(wasmer_exports_t *exports, int idx);
|
||||
*/
|
||||
int wasmer_exports_len(wasmer_exports_t *exports);
|
||||
|
||||
/**
|
||||
* Calls a `func` with the provided parameters.
|
||||
* Results are set using the provided `results` pointer.
|
||||
* Returns `wasmer_result_t::WASMER_OK` upon success.
|
||||
* Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
|
||||
* and `wasmer_last_error_message` to get an error message.
|
||||
*/
|
||||
wasmer_result_t wasmer_func_call(wasmer_func_t *func,
|
||||
const wasmer_value_t *params,
|
||||
int params_len,
|
||||
wasmer_value_t *results,
|
||||
int results_len);
|
||||
|
||||
/**
|
||||
* Frees memory for the given Func
|
||||
*/
|
||||
void wasmer_func_destroy(wasmer_func_t *func);
|
||||
|
||||
/**
|
||||
* Creates new func
|
||||
* The caller owns the object and should call `wasmer_func_destroy` to free it.
|
||||
*/
|
||||
const wasmer_func_t *wasmer_func_new(void (*func)(void *data),
|
||||
const wasmer_value_tag *params,
|
||||
int params_len,
|
||||
const wasmer_value_tag *returns,
|
||||
int returns_len);
|
||||
|
||||
/**
|
||||
* Sets the params buffer to the parameter types of the given wasmer_func_t
|
||||
* Returns `wasmer_result_t::WASMER_OK` upon success.
|
||||
* Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
|
||||
* and `wasmer_last_error_message` to get an error message.
|
||||
*/
|
||||
wasmer_result_t wasmer_func_params(wasmer_func_t *func, wasmer_value_tag *params, int params_len);
|
||||
|
||||
/**
|
||||
* Sets the result parameter to the arity of the params of the wasmer_func_t
|
||||
* Returns `wasmer_result_t::WASMER_OK` upon success.
|
||||
* Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
|
||||
* and `wasmer_last_error_message` to get an error message.
|
||||
*/
|
||||
wasmer_result_t wasmer_func_params_arity(wasmer_func_t *func, uint32_t *result);
|
||||
|
||||
/**
|
||||
* Sets the returns buffer to the parameter types of the given wasmer_func_t
|
||||
* Returns `wasmer_result_t::WASMER_OK` upon success.
|
||||
* Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
|
||||
* and `wasmer_last_error_message` to get an error message.
|
||||
*/
|
||||
wasmer_result_t wasmer_func_returns(wasmer_func_t *func,
|
||||
wasmer_value_tag *returns,
|
||||
int returns_len);
|
||||
|
||||
/**
|
||||
* Sets the result parameter to the arity of the returns of the wasmer_func_t
|
||||
* Returns `wasmer_result_t::WASMER_OK` upon success.
|
||||
* Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
|
||||
* and `wasmer_last_error_message` to get an error message.
|
||||
*/
|
||||
wasmer_result_t wasmer_func_returns_arity(wasmer_func_t *func, uint32_t *result);
|
||||
|
||||
/**
|
||||
* Frees memory for the given Global
|
||||
*/
|
||||
@ -231,6 +271,95 @@ wasmer_global_t *wasmer_global_new(wasmer_value_t value, bool mutable_);
|
||||
*/
|
||||
void wasmer_global_set(wasmer_global_t *global, wasmer_value_t value);
|
||||
|
||||
/**
|
||||
* Gets export descriptor kind
|
||||
*/
|
||||
wasmer_import_export_kind wasmer_import_descriptor_kind(wasmer_import_descriptor_t *export_);
|
||||
|
||||
/**
|
||||
* Gets module name for the import descriptor
|
||||
*/
|
||||
wasmer_byte_array wasmer_import_descriptor_module_name(wasmer_import_descriptor_t *import_descriptor);
|
||||
|
||||
/**
|
||||
* Gets name for the import descriptor
|
||||
*/
|
||||
wasmer_byte_array wasmer_import_descriptor_name(wasmer_import_descriptor_t *import_descriptor);
|
||||
|
||||
/**
|
||||
* Gets import descriptors for the given module
|
||||
* The caller owns the object and should call `wasmer_import_descriptors_destroy` to free it.
|
||||
*/
|
||||
void wasmer_import_descriptors(wasmer_module_t *module,
|
||||
wasmer_import_descriptors_t **import_descriptors);
|
||||
|
||||
/**
|
||||
* Frees the memory for the given import descriptors
|
||||
*/
|
||||
void wasmer_import_descriptors_destroy(wasmer_import_descriptors_t *import_descriptors);
|
||||
|
||||
/**
|
||||
* Gets import descriptor by index
|
||||
*/
|
||||
wasmer_import_descriptor_t *wasmer_import_descriptors_get(wasmer_import_descriptors_t *import_descriptors,
|
||||
int idx);
|
||||
|
||||
/**
|
||||
* Gets the length of the import descriptors
|
||||
*/
|
||||
int wasmer_import_descriptors_len(wasmer_import_descriptors_t *exports);
|
||||
|
||||
/**
|
||||
* Frees memory for the given Func
|
||||
*/
|
||||
void wasmer_import_func_destroy(wasmer_import_func_t *func);
|
||||
|
||||
/**
|
||||
* Creates new func
|
||||
* The caller owns the object and should call `wasmer_import_func_destroy` to free it.
|
||||
*/
|
||||
const wasmer_import_func_t *wasmer_import_func_new(void (*func)(void *data),
|
||||
const wasmer_value_tag *params,
|
||||
int params_len,
|
||||
const wasmer_value_tag *returns,
|
||||
int returns_len);
|
||||
|
||||
/**
|
||||
* Sets the params buffer to the parameter types of the given wasmer_import_func_t
|
||||
* Returns `wasmer_result_t::WASMER_OK` upon success.
|
||||
* Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
|
||||
* and `wasmer_last_error_message` to get an error message.
|
||||
*/
|
||||
wasmer_result_t wasmer_import_func_params(wasmer_import_func_t *func,
|
||||
wasmer_value_tag *params,
|
||||
int params_len);
|
||||
|
||||
/**
|
||||
* Sets the result parameter to the arity of the params of the wasmer_import_func_t
|
||||
* Returns `wasmer_result_t::WASMER_OK` upon success.
|
||||
* Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
|
||||
* and `wasmer_last_error_message` to get an error message.
|
||||
*/
|
||||
wasmer_result_t wasmer_import_func_params_arity(wasmer_import_func_t *func, uint32_t *result);
|
||||
|
||||
/**
|
||||
* Sets the returns buffer to the parameter types of the given wasmer_import_func_t
|
||||
* Returns `wasmer_result_t::WASMER_OK` upon success.
|
||||
* Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
|
||||
* and `wasmer_last_error_message` to get an error message.
|
||||
*/
|
||||
wasmer_result_t wasmer_import_func_returns(wasmer_import_func_t *func,
|
||||
wasmer_value_tag *returns,
|
||||
int returns_len);
|
||||
|
||||
/**
|
||||
* Sets the result parameter to the arity of the returns of the wasmer_import_func_t
|
||||
* Returns `wasmer_result_t::WASMER_OK` upon success.
|
||||
* Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
|
||||
* and `wasmer_last_error_message` to get an error message.
|
||||
*/
|
||||
wasmer_result_t wasmer_import_func_returns_arity(wasmer_import_func_t *func, uint32_t *result);
|
||||
|
||||
/**
|
||||
* Calls an instances exported function by `name` with the provided parameters.
|
||||
* Results are set using the provided `results` pointer.
|
||||
|
@ -30,7 +30,7 @@ struct wasmer_instance_t;
|
||||
|
||||
struct wasmer_module_t;
|
||||
|
||||
struct wasmer_export_t {
|
||||
struct wasmer_export_descriptor_t {
|
||||
|
||||
};
|
||||
|
||||
@ -39,11 +39,11 @@ struct wasmer_byte_array {
|
||||
uint32_t bytes_len;
|
||||
};
|
||||
|
||||
struct wasmer_func_t {
|
||||
struct wasmer_export_descriptors_t {
|
||||
|
||||
};
|
||||
|
||||
struct wasmer_exports_t {
|
||||
struct wasmer_export_func_t {
|
||||
|
||||
};
|
||||
|
||||
@ -59,6 +59,14 @@ struct wasmer_value_t {
|
||||
wasmer_value value;
|
||||
};
|
||||
|
||||
struct wasmer_export_t {
|
||||
|
||||
};
|
||||
|
||||
struct wasmer_exports_t {
|
||||
|
||||
};
|
||||
|
||||
struct wasmer_global_t {
|
||||
|
||||
};
|
||||
@ -68,6 +76,18 @@ struct wasmer_global_descriptor_t {
|
||||
wasmer_value_tag kind;
|
||||
};
|
||||
|
||||
struct wasmer_import_descriptor_t {
|
||||
|
||||
};
|
||||
|
||||
struct wasmer_import_descriptors_t {
|
||||
|
||||
};
|
||||
|
||||
struct wasmer_import_func_t {
|
||||
|
||||
};
|
||||
|
||||
struct wasmer_memory_t {
|
||||
|
||||
};
|
||||
@ -77,7 +97,7 @@ struct wasmer_table_t {
|
||||
};
|
||||
|
||||
union wasmer_import_export_value {
|
||||
const wasmer_func_t *func;
|
||||
const wasmer_import_func_t *func;
|
||||
const wasmer_table_t *table;
|
||||
const wasmer_memory_t *memory;
|
||||
const wasmer_global_t *global;
|
||||
@ -110,14 +130,74 @@ wasmer_result_t wasmer_compile(wasmer_module_t **module,
|
||||
uint8_t *wasm_bytes,
|
||||
uint32_t wasm_bytes_len);
|
||||
|
||||
/// Gets export descriptor kind
|
||||
wasmer_import_export_kind wasmer_export_descriptor_kind(wasmer_export_descriptor_t *export_);
|
||||
|
||||
/// Gets name for the export descriptor
|
||||
wasmer_byte_array wasmer_export_descriptor_name(wasmer_export_descriptor_t *export_descriptor);
|
||||
|
||||
/// Gets export descriptors for the given module
|
||||
/// The caller owns the object and should call `wasmer_export_descriptors_destroy` to free it.
|
||||
void wasmer_export_descriptors(wasmer_module_t *module,
|
||||
wasmer_export_descriptors_t **export_descriptors);
|
||||
|
||||
/// Frees the memory for the given export descriptors
|
||||
void wasmer_export_descriptors_destroy(wasmer_export_descriptors_t *export_descriptors);
|
||||
|
||||
/// Gets export descriptor by index
|
||||
wasmer_export_descriptor_t *wasmer_export_descriptors_get(wasmer_export_descriptors_t *export_descriptors,
|
||||
int idx);
|
||||
|
||||
/// Gets the length of the export descriptors
|
||||
int wasmer_export_descriptors_len(wasmer_export_descriptors_t *exports);
|
||||
|
||||
/// Calls a `func` with the provided parameters.
|
||||
/// Results are set using the provided `results` pointer.
|
||||
/// Returns `wasmer_result_t::WASMER_OK` upon success.
|
||||
/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
|
||||
/// and `wasmer_last_error_message` to get an error message.
|
||||
wasmer_result_t wasmer_export_func_call(wasmer_export_func_t *func,
|
||||
const wasmer_value_t *params,
|
||||
int params_len,
|
||||
wasmer_value_t *results,
|
||||
int results_len);
|
||||
|
||||
/// Sets the params buffer to the parameter types of the given wasmer_export_func_t
|
||||
/// Returns `wasmer_result_t::WASMER_OK` upon success.
|
||||
/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
|
||||
/// and `wasmer_last_error_message` to get an error message.
|
||||
wasmer_result_t wasmer_export_func_params(wasmer_export_func_t *func,
|
||||
wasmer_value_tag *params,
|
||||
int params_len);
|
||||
|
||||
/// Sets the result parameter to the arity of the params of the wasmer_export_func_t
|
||||
/// Returns `wasmer_result_t::WASMER_OK` upon success.
|
||||
/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
|
||||
/// and `wasmer_last_error_message` to get an error message.
|
||||
wasmer_result_t wasmer_export_func_params_arity(wasmer_export_func_t *func, uint32_t *result);
|
||||
|
||||
/// Sets the returns buffer to the parameter types of the given wasmer_export_func_t
|
||||
/// Returns `wasmer_result_t::WASMER_OK` upon success.
|
||||
/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
|
||||
/// and `wasmer_last_error_message` to get an error message.
|
||||
wasmer_result_t wasmer_export_func_returns(wasmer_export_func_t *func,
|
||||
wasmer_value_tag *returns,
|
||||
int returns_len);
|
||||
|
||||
/// Sets the result parameter to the arity of the returns of the wasmer_export_func_t
|
||||
/// Returns `wasmer_result_t::WASMER_OK` upon success.
|
||||
/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
|
||||
/// and `wasmer_last_error_message` to get an error message.
|
||||
wasmer_result_t wasmer_export_func_returns_arity(wasmer_export_func_t *func, uint32_t *result);
|
||||
|
||||
/// Gets wasmer_export kind
|
||||
wasmer_import_export_kind wasmer_export_kind(wasmer_export_t *export_);
|
||||
|
||||
/// Gets name from wasmer_export
|
||||
wasmer_byte_array wasmer_export_name(wasmer_export_t *export_);
|
||||
|
||||
/// Gets func from wasm_export
|
||||
const wasmer_func_t *wasmer_export_to_func(wasmer_export_t *export_);
|
||||
/// Gets export func from export
|
||||
const wasmer_export_func_t *wasmer_export_to_func(wasmer_export_t *export_);
|
||||
|
||||
/// Frees the memory for the given exports
|
||||
void wasmer_exports_destroy(wasmer_exports_t *exports);
|
||||
@ -128,54 +208,6 @@ wasmer_export_t *wasmer_exports_get(wasmer_exports_t *exports, int idx);
|
||||
/// Gets the length of the exports
|
||||
int wasmer_exports_len(wasmer_exports_t *exports);
|
||||
|
||||
/// Calls a `func` with the provided parameters.
|
||||
/// Results are set using the provided `results` pointer.
|
||||
/// Returns `wasmer_result_t::WASMER_OK` upon success.
|
||||
/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
|
||||
/// and `wasmer_last_error_message` to get an error message.
|
||||
wasmer_result_t wasmer_func_call(wasmer_func_t *func,
|
||||
const wasmer_value_t *params,
|
||||
int params_len,
|
||||
wasmer_value_t *results,
|
||||
int results_len);
|
||||
|
||||
/// Frees memory for the given Func
|
||||
void wasmer_func_destroy(wasmer_func_t *func);
|
||||
|
||||
/// Creates new func
|
||||
/// The caller owns the object and should call `wasmer_func_destroy` to free it.
|
||||
const wasmer_func_t *wasmer_func_new(void (*func)(void *data),
|
||||
const wasmer_value_tag *params,
|
||||
int params_len,
|
||||
const wasmer_value_tag *returns,
|
||||
int returns_len);
|
||||
|
||||
/// Sets the params buffer to the parameter types of the given wasmer_func_t
|
||||
/// Returns `wasmer_result_t::WASMER_OK` upon success.
|
||||
/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
|
||||
/// and `wasmer_last_error_message` to get an error message.
|
||||
wasmer_result_t wasmer_func_params(wasmer_func_t *func, wasmer_value_tag *params, int params_len);
|
||||
|
||||
/// Sets the result parameter to the arity of the params of the wasmer_func_t
|
||||
/// Returns `wasmer_result_t::WASMER_OK` upon success.
|
||||
/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
|
||||
/// and `wasmer_last_error_message` to get an error message.
|
||||
wasmer_result_t wasmer_func_params_arity(wasmer_func_t *func, uint32_t *result);
|
||||
|
||||
/// Sets the returns buffer to the parameter types of the given wasmer_func_t
|
||||
/// Returns `wasmer_result_t::WASMER_OK` upon success.
|
||||
/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
|
||||
/// and `wasmer_last_error_message` to get an error message.
|
||||
wasmer_result_t wasmer_func_returns(wasmer_func_t *func,
|
||||
wasmer_value_tag *returns,
|
||||
int returns_len);
|
||||
|
||||
/// Sets the result parameter to the arity of the returns of the wasmer_func_t
|
||||
/// Returns `wasmer_result_t::WASMER_OK` upon success.
|
||||
/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
|
||||
/// and `wasmer_last_error_message` to get an error message.
|
||||
wasmer_result_t wasmer_func_returns_arity(wasmer_func_t *func, uint32_t *result);
|
||||
|
||||
/// Frees memory for the given Global
|
||||
void wasmer_global_destroy(wasmer_global_t *global);
|
||||
|
||||
@ -192,6 +224,69 @@ wasmer_global_t *wasmer_global_new(wasmer_value_t value, bool mutable_);
|
||||
/// Sets the value stored by the given Global
|
||||
void wasmer_global_set(wasmer_global_t *global, wasmer_value_t value);
|
||||
|
||||
/// Gets export descriptor kind
|
||||
wasmer_import_export_kind wasmer_import_descriptor_kind(wasmer_import_descriptor_t *export_);
|
||||
|
||||
/// Gets module name for the import descriptor
|
||||
wasmer_byte_array wasmer_import_descriptor_module_name(wasmer_import_descriptor_t *import_descriptor);
|
||||
|
||||
/// Gets name for the import descriptor
|
||||
wasmer_byte_array wasmer_import_descriptor_name(wasmer_import_descriptor_t *import_descriptor);
|
||||
|
||||
/// Gets import descriptors for the given module
|
||||
/// The caller owns the object and should call `wasmer_import_descriptors_destroy` to free it.
|
||||
void wasmer_import_descriptors(wasmer_module_t *module,
|
||||
wasmer_import_descriptors_t **import_descriptors);
|
||||
|
||||
/// Frees the memory for the given import descriptors
|
||||
void wasmer_import_descriptors_destroy(wasmer_import_descriptors_t *import_descriptors);
|
||||
|
||||
/// Gets import descriptor by index
|
||||
wasmer_import_descriptor_t *wasmer_import_descriptors_get(wasmer_import_descriptors_t *import_descriptors,
|
||||
int idx);
|
||||
|
||||
/// Gets the length of the import descriptors
|
||||
int wasmer_import_descriptors_len(wasmer_import_descriptors_t *exports);
|
||||
|
||||
/// Frees memory for the given Func
|
||||
void wasmer_import_func_destroy(wasmer_import_func_t *func);
|
||||
|
||||
/// Creates new func
|
||||
/// The caller owns the object and should call `wasmer_import_func_destroy` to free it.
|
||||
const wasmer_import_func_t *wasmer_import_func_new(void (*func)(void *data),
|
||||
const wasmer_value_tag *params,
|
||||
int params_len,
|
||||
const wasmer_value_tag *returns,
|
||||
int returns_len);
|
||||
|
||||
/// Sets the params buffer to the parameter types of the given wasmer_import_func_t
|
||||
/// Returns `wasmer_result_t::WASMER_OK` upon success.
|
||||
/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
|
||||
/// and `wasmer_last_error_message` to get an error message.
|
||||
wasmer_result_t wasmer_import_func_params(wasmer_import_func_t *func,
|
||||
wasmer_value_tag *params,
|
||||
int params_len);
|
||||
|
||||
/// Sets the result parameter to the arity of the params of the wasmer_import_func_t
|
||||
/// Returns `wasmer_result_t::WASMER_OK` upon success.
|
||||
/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
|
||||
/// and `wasmer_last_error_message` to get an error message.
|
||||
wasmer_result_t wasmer_import_func_params_arity(wasmer_import_func_t *func, uint32_t *result);
|
||||
|
||||
/// Sets the returns buffer to the parameter types of the given wasmer_import_func_t
|
||||
/// Returns `wasmer_result_t::WASMER_OK` upon success.
|
||||
/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
|
||||
/// and `wasmer_last_error_message` to get an error message.
|
||||
wasmer_result_t wasmer_import_func_returns(wasmer_import_func_t *func,
|
||||
wasmer_value_tag *returns,
|
||||
int returns_len);
|
||||
|
||||
/// Sets the result parameter to the arity of the returns of the wasmer_import_func_t
|
||||
/// Returns `wasmer_result_t::WASMER_OK` upon success.
|
||||
/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
|
||||
/// and `wasmer_last_error_message` to get an error message.
|
||||
wasmer_result_t wasmer_import_func_returns_arity(wasmer_import_func_t *func, uint32_t *result);
|
||||
|
||||
/// 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.
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "wasmer-runtime-core"
|
||||
version = "0.1.2"
|
||||
version = "0.2.1"
|
||||
description = "Wasmer runtime core library"
|
||||
license = "MIT"
|
||||
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
|
||||
@ -15,7 +15,7 @@ parking_lot = "0.7.1"
|
||||
lazy_static = "1.2.0"
|
||||
indexmap = "1.0.2"
|
||||
errno = "0.2.4"
|
||||
libc = "0.2.48"
|
||||
libc = "0.2.49"
|
||||
hex = "0.3.2"
|
||||
|
||||
# Dependencies for caching.
|
||||
@ -29,7 +29,9 @@ version = "1.0"
|
||||
version = "0.10"
|
||||
[dependencies.serde-bench]
|
||||
version = "0.0.7"
|
||||
[dependencies.sha2]
|
||||
[dependencies.blake2b_simd]
|
||||
version = "0.4.1"
|
||||
[dependencies.digest]
|
||||
version = "0.8.0"
|
||||
[dependencies.hashbrown]
|
||||
version = "0.1"
|
||||
@ -39,7 +41,6 @@ features = ["serde"]
|
||||
winapi = { version = "0.3", features = ["memoryapi"] }
|
||||
|
||||
[dev-dependencies]
|
||||
wasmer-clif-backend = { path = "../clif-backend", version = "0.1.2" }
|
||||
field-offset = "0.1.1"
|
||||
|
||||
[features]
|
||||
|
@ -12,7 +12,7 @@ use crate::{
|
||||
module::ModuleInfo,
|
||||
sys::Memory,
|
||||
};
|
||||
use std::ptr::NonNull;
|
||||
use std::{any::Any, ptr::NonNull};
|
||||
|
||||
pub mod sys {
|
||||
pub use crate::sys::*;
|
||||
@ -79,7 +79,7 @@ pub trait ProtectedCaller: Send + Sync {
|
||||
}
|
||||
|
||||
pub trait UserTrapper {
|
||||
unsafe fn do_early_trap(&self, msg: String) -> !;
|
||||
unsafe fn do_early_trap(&self, data: Box<dyn Any>) -> !;
|
||||
}
|
||||
|
||||
pub trait FuncResolver: Send + Sync {
|
||||
|
@ -2,8 +2,8 @@ use crate::{
|
||||
module::{Module, ModuleInfo},
|
||||
sys::Memory,
|
||||
};
|
||||
use sha2::{Digest, Sha256};
|
||||
use std::{io, mem, slice};
|
||||
use blake2b_simd::blake2bp;
|
||||
use std::{fmt, io, mem, slice};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum InvalidFileType {
|
||||
@ -33,7 +33,7 @@ impl From<io::Error> for Error {
|
||||
///
|
||||
/// [`Cache`]: trait.Cache.html
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
pub struct WasmHash([u8; 32]);
|
||||
pub struct WasmHash([u8; 32], [u8; 32]);
|
||||
|
||||
impl WasmHash {
|
||||
/// Hash a wasm module.
|
||||
@ -42,19 +42,31 @@ impl WasmHash {
|
||||
/// This does no verification that the supplied data
|
||||
/// is, in fact, a wasm module.
|
||||
pub fn generate(wasm: &[u8]) -> Self {
|
||||
let mut array = [0u8; 32];
|
||||
array.copy_from_slice(Sha256::digest(wasm).as_slice());
|
||||
WasmHash(array)
|
||||
let mut first_part = [0u8; 32];
|
||||
let mut second_part = [0u8; 32];
|
||||
|
||||
let mut state = blake2bp::State::new();
|
||||
state.update(wasm);
|
||||
|
||||
let hasher = state.finalize();
|
||||
let generic_array = hasher.as_bytes();
|
||||
|
||||
first_part.copy_from_slice(&generic_array[0..32]);
|
||||
second_part.copy_from_slice(&generic_array[32..64]);
|
||||
WasmHash(first_part, second_part)
|
||||
}
|
||||
|
||||
/// Create the hexadecimal representation of the
|
||||
/// stored hash.
|
||||
pub fn encode(self) -> String {
|
||||
hex::encode(self.0)
|
||||
hex::encode(&self.into_array() as &[u8])
|
||||
}
|
||||
|
||||
pub(crate) fn into_array(self) -> [u8; 32] {
|
||||
self.0
|
||||
pub(crate) fn into_array(self) -> [u8; 64] {
|
||||
let mut total = [0u8; 64];
|
||||
total[0..32].copy_from_slice(&self.0);
|
||||
total[32..64].copy_from_slice(&self.1);
|
||||
total
|
||||
}
|
||||
}
|
||||
|
||||
@ -189,8 +201,8 @@ impl Artifact {
|
||||
///
|
||||
/// The `wasmer-runtime` supplies a naive `FileSystemCache` api.
|
||||
pub trait Cache {
|
||||
type LoadError;
|
||||
type StoreError;
|
||||
type LoadError: fmt::Debug;
|
||||
type StoreError: fmt::Debug;
|
||||
|
||||
fn load(&self, key: WasmHash) -> Result<Module, Self::LoadError>;
|
||||
fn store(&mut self, key: WasmHash, module: Module) -> Result<(), Self::StoreError>;
|
||||
|
@ -1,8 +1,9 @@
|
||||
use crate::types::{
|
||||
FuncSig, GlobalDescriptor, MemoryDescriptor, MemoryIndex, TableDescriptor, TableIndex, Type,
|
||||
Value,
|
||||
};
|
||||
use core::borrow::Borrow;
|
||||
use std::sync::Arc;
|
||||
use std::{any::Any, sync::Arc};
|
||||
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
pub type CompileResult<T> = std::result::Result<T, CompileError>;
|
||||
@ -120,28 +121,11 @@ impl std::error::Error for LinkError {}
|
||||
/// The main way to do this is `Instance.call`.
|
||||
///
|
||||
/// Comparing two `RuntimeError`s always evaluates to false.
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug)]
|
||||
pub enum RuntimeError {
|
||||
OutOfBoundsAccess {
|
||||
memory: MemoryIndex,
|
||||
addr: Option<u32>,
|
||||
},
|
||||
TableOutOfBounds {
|
||||
table: TableIndex,
|
||||
},
|
||||
IndirectCallSignature {
|
||||
table: TableIndex,
|
||||
},
|
||||
IndirectCallToNull {
|
||||
table: TableIndex,
|
||||
},
|
||||
IllegalArithmeticOperation,
|
||||
User {
|
||||
msg: String,
|
||||
},
|
||||
Unknown {
|
||||
msg: String,
|
||||
},
|
||||
Trap { msg: Box<str> },
|
||||
Exception { data: Box<[Value]> },
|
||||
Panic { data: Box<dyn Any> },
|
||||
}
|
||||
|
||||
impl PartialEq for RuntimeError {
|
||||
@ -153,30 +137,13 @@ impl PartialEq for RuntimeError {
|
||||
impl std::fmt::Display for RuntimeError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
match self {
|
||||
RuntimeError::IndirectCallSignature { table } => write!(
|
||||
f,
|
||||
"Indirect call signature error with Table Index \"{:?}\"",
|
||||
table
|
||||
),
|
||||
RuntimeError::IndirectCallToNull { table } => {
|
||||
write!(f, "Indirect call to null with table index \"{:?}\"", table)
|
||||
RuntimeError::Trap { ref msg } => {
|
||||
write!(f, "WebAssembly trap occured during runtime: {}", msg)
|
||||
}
|
||||
RuntimeError::IllegalArithmeticOperation => write!(f, "Illegal arithmetic operation"),
|
||||
RuntimeError::OutOfBoundsAccess { memory, addr } => match addr {
|
||||
Some(addr) => write!(
|
||||
f,
|
||||
"Out-of-bounds access with memory index {:?} and address {}",
|
||||
memory, addr
|
||||
),
|
||||
None => write!(f, "Out-of-bounds access with memory index {:?}", memory),
|
||||
},
|
||||
RuntimeError::TableOutOfBounds { table } => {
|
||||
write!(f, "Table out of bounds with table index \"{:?}\"", table)
|
||||
RuntimeError::Exception { ref data } => {
|
||||
write!(f, "Uncaught WebAssembly exception: {:?}", data)
|
||||
}
|
||||
RuntimeError::Unknown { msg } => {
|
||||
write!(f, "Unknown runtime error with message: \"{}\"", msg)
|
||||
}
|
||||
RuntimeError::User { msg } => write!(f, "User runtime error with message: \"{}\"", msg),
|
||||
RuntimeError::Panic { data: _ } => write!(f, "User-defined \"panic\""),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -232,7 +199,7 @@ impl std::error::Error for ResolveError {}
|
||||
/// be the `CallError::Runtime(RuntimeError)` variant.
|
||||
///
|
||||
/// Comparing two `CallError`s always evaluates to false.
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug)]
|
||||
pub enum CallError {
|
||||
Resolve(ResolveError),
|
||||
Runtime(RuntimeError),
|
||||
@ -291,7 +258,7 @@ impl std::error::Error for CreationError {}
|
||||
/// of a webassembly module.
|
||||
///
|
||||
/// Comparing two `Error`s always evaluates to false.
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
CompileError(CompileError),
|
||||
LinkError(Vec<LinkError>),
|
||||
@ -357,8 +324,127 @@ impl From<ResolveError> for CallError {
|
||||
|
||||
impl std::fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(f, "{}", self)
|
||||
match self {
|
||||
Error::CompileError(err) => write!(f, "compile error: {}", err),
|
||||
Error::LinkError(errs) => {
|
||||
if errs.len() == 1 {
|
||||
write!(f, "link error: {}", errs[0])
|
||||
} else {
|
||||
write!(f, "{} link errors:", errs.len())?;
|
||||
for (i, err) in errs.iter().enumerate() {
|
||||
write!(f, " ({} of {}) {}", i + 1, errs.len(), err)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
Error::RuntimeError(err) => write!(f, "runtime error: {}", err),
|
||||
Error::ResolveError(err) => write!(f, "resolve error: {}", err),
|
||||
Error::CallError(err) => write!(f, "call error: {}", err),
|
||||
Error::CreationError(err) => write!(f, "creation error: {}", err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for Error {}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum GrowError {
|
||||
MemoryGrowError,
|
||||
TableGrowError,
|
||||
ExceededMaxPages(PageError),
|
||||
ExceededMaxPagesForMemory(usize, usize),
|
||||
CouldNotProtectMemory(MemoryProtectionError),
|
||||
CouldNotCreateMemory(MemoryCreationError),
|
||||
}
|
||||
|
||||
impl std::fmt::Display for GrowError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
match self {
|
||||
GrowError::MemoryGrowError => write!(f, "Unable to grow memory"),
|
||||
GrowError::TableGrowError => write!(f, "Unable to grow table"),
|
||||
GrowError::ExceededMaxPages(e) => write!(f, "Grow Error: {}", e),
|
||||
GrowError::ExceededMaxPagesForMemory(left, added) => write!(f, "Failed to add pages because would exceed maximum number of pages for the memory. Left: {}, Added: {}", left, added),
|
||||
GrowError::CouldNotCreateMemory(e) => write!(f, "Grow Error: {}", e),
|
||||
GrowError::CouldNotProtectMemory(e) => write!(f, "Grow Error: {}", e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for GrowError {}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum PageError {
|
||||
// left, right, added
|
||||
ExceededMaxPages(usize, usize, usize),
|
||||
}
|
||||
|
||||
impl std::fmt::Display for PageError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
match self {
|
||||
PageError::ExceededMaxPages(left, right, added) => write!(f, "Failed to add pages because would exceed maximum number of pages. Left: {}, Right: {}, Pages added: {}", left, right, added),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl std::error::Error for PageError {}
|
||||
|
||||
impl Into<GrowError> for PageError {
|
||||
fn into(self) -> GrowError {
|
||||
GrowError::ExceededMaxPages(self)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum MemoryCreationError {
|
||||
VirtualMemoryAllocationFailed(usize, String),
|
||||
CouldNotCreateMemoryFromFile(std::io::Error),
|
||||
}
|
||||
|
||||
impl std::fmt::Display for MemoryCreationError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
match self {
|
||||
MemoryCreationError::VirtualMemoryAllocationFailed(size, msg) => write!(
|
||||
f,
|
||||
"Allocation virtual memory with size {} failed. \nErrno message: {}",
|
||||
size, msg
|
||||
),
|
||||
MemoryCreationError::CouldNotCreateMemoryFromFile(e) => write!(f, "IO Error: {}", e),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl std::error::Error for MemoryCreationError {}
|
||||
|
||||
impl Into<GrowError> for MemoryCreationError {
|
||||
fn into(self) -> GrowError {
|
||||
GrowError::CouldNotCreateMemory(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<std::io::Error> for MemoryCreationError {
|
||||
fn from(io_error: std::io::Error) -> Self {
|
||||
MemoryCreationError::CouldNotCreateMemoryFromFile(io_error)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum MemoryProtectionError {
|
||||
ProtectionFailed(usize, usize, String),
|
||||
}
|
||||
|
||||
impl std::fmt::Display for MemoryProtectionError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
match self {
|
||||
MemoryProtectionError::ProtectionFailed(start, size, msg) => write!(
|
||||
f,
|
||||
"Allocation virtual memory starting at {} with size {} failed. \nErrno message: {}",
|
||||
start, size, msg
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl std::error::Error for MemoryProtectionError {}
|
||||
|
||||
impl Into<GrowError> for MemoryProtectionError {
|
||||
fn into(self) -> GrowError {
|
||||
GrowError::CouldNotProtectMemory(self)
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
use crate::error::GrowError;
|
||||
use crate::{
|
||||
error::CreationError,
|
||||
sys,
|
||||
@ -14,9 +15,9 @@ pub const DYNAMIC_GUARD_SIZE: usize = 4096;
|
||||
/// when first created. Over time, as it grows, it may reallocate to
|
||||
/// a different location and size.
|
||||
///
|
||||
/// Dynamic memories are signifigantly faster to create than static
|
||||
/// Dynamic memories are significantly faster to create than static
|
||||
/// memories and use much less virtual memory, however, they require
|
||||
/// the webassembly module to bounds-check memory accesses.
|
||||
/// the WebAssembly module to bounds-check memory accesses.
|
||||
///
|
||||
/// While, a dynamic memory could use a vector of some sort as its
|
||||
/// backing memory, we use mmap (or the platform-equivalent) to allow
|
||||
@ -65,26 +66,29 @@ impl DynamicMemory {
|
||||
self.current
|
||||
}
|
||||
|
||||
pub fn grow(&mut self, delta: Pages, local: &mut vm::LocalMemory) -> Option<Pages> {
|
||||
pub fn grow(&mut self, delta: Pages, local: &mut vm::LocalMemory) -> Result<Pages, GrowError> {
|
||||
if delta == Pages(0) {
|
||||
return Some(self.current);
|
||||
return Ok(self.current);
|
||||
}
|
||||
|
||||
let new_pages = self.current.checked_add(delta)?;
|
||||
let new_pages = self.current.checked_add(delta).map_err(|e| e.into())?;
|
||||
|
||||
if let Some(max) = self.max {
|
||||
if new_pages > max {
|
||||
return None;
|
||||
return Err(GrowError::ExceededMaxPagesForMemory(
|
||||
new_pages.0 as usize,
|
||||
max.0 as usize,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
let mut new_memory =
|
||||
sys::Memory::with_size(new_pages.bytes().0 + DYNAMIC_GUARD_SIZE).ok()?;
|
||||
let mut new_memory = sys::Memory::with_size(new_pages.bytes().0 + DYNAMIC_GUARD_SIZE)
|
||||
.map_err(|e| e.into())?;
|
||||
|
||||
unsafe {
|
||||
new_memory
|
||||
.protect(0..new_pages.bytes().0, sys::Protect::ReadWrite)
|
||||
.ok()?;
|
||||
.map_err(|e| e.into())?;
|
||||
|
||||
new_memory.as_slice_mut()[..self.current.bytes().0]
|
||||
.copy_from_slice(&self.memory.as_slice()[..self.current.bytes().0]);
|
||||
@ -97,7 +101,7 @@ impl DynamicMemory {
|
||||
|
||||
let old_pages = self.current;
|
||||
self.current = new_pages;
|
||||
Some(old_pages)
|
||||
Ok(old_pages)
|
||||
}
|
||||
|
||||
pub fn as_slice(&self) -> &[u8] {
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::{
|
||||
error::CreationError,
|
||||
error::{CreationError, GrowError},
|
||||
export::Export,
|
||||
import::IsExport,
|
||||
memory::dynamic::DYNAMIC_GUARD_SIZE,
|
||||
@ -89,8 +89,8 @@ impl Memory {
|
||||
self.desc
|
||||
}
|
||||
|
||||
/// Grow this memory by the specfied number of pages.
|
||||
pub fn grow(&self, delta: Pages) -> Option<Pages> {
|
||||
/// Grow this memory by the specified number of pages.
|
||||
pub fn grow(&self, delta: Pages) -> Result<Pages, GrowError> {
|
||||
match &self.variant {
|
||||
MemoryVariant::Unshared(unshared_mem) => unshared_mem.grow(delta),
|
||||
MemoryVariant::Shared(shared_mem) => shared_mem.grow(delta),
|
||||
@ -244,7 +244,7 @@ impl UnsharedMemory {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn grow(&self, delta: Pages) -> Option<Pages> {
|
||||
pub fn grow(&self, delta: Pages) -> Result<Pages, GrowError> {
|
||||
let mut storage = self.internal.storage.borrow_mut();
|
||||
|
||||
let mut local = self.internal.local.get();
|
||||
@ -292,7 +292,7 @@ impl SharedMemory {
|
||||
Ok(Self { desc })
|
||||
}
|
||||
|
||||
pub fn grow(&self, _delta: Pages) -> Option<Pages> {
|
||||
pub fn grow(&self, _delta: Pages) -> Result<Pages, GrowError> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
use crate::error::GrowError;
|
||||
use crate::{
|
||||
error::CreationError,
|
||||
memory::static_::{SAFE_STATIC_GUARD_SIZE, SAFE_STATIC_HEAP_SIZE},
|
||||
@ -61,27 +62,30 @@ impl StaticMemory {
|
||||
self.current
|
||||
}
|
||||
|
||||
pub fn grow(&mut self, delta: Pages, local: &mut vm::LocalMemory) -> Option<Pages> {
|
||||
pub fn grow(&mut self, delta: Pages, local: &mut vm::LocalMemory) -> Result<Pages, GrowError> {
|
||||
if delta == Pages(0) {
|
||||
return Some(self.current);
|
||||
return Ok(self.current);
|
||||
}
|
||||
|
||||
let new_pages = self.current.checked_add(delta)?;
|
||||
let new_pages = self.current.checked_add(delta).map_err(|e| e.into())?;
|
||||
|
||||
if let Some(max) = self.max {
|
||||
if new_pages > max {
|
||||
return None;
|
||||
return Err(GrowError::ExceededMaxPagesForMemory(
|
||||
new_pages.0 as usize,
|
||||
max.0 as usize,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
unsafe {
|
||||
let _ = unsafe {
|
||||
self.memory
|
||||
.protect(
|
||||
self.current.bytes().0..new_pages.bytes().0,
|
||||
sys::Protect::ReadWrite,
|
||||
)
|
||||
.ok()?;
|
||||
}
|
||||
.map_err(|e| e.into())
|
||||
}?;
|
||||
|
||||
local.bound = new_pages.bytes().0;
|
||||
|
||||
@ -89,7 +93,7 @@ impl StaticMemory {
|
||||
|
||||
self.current = new_pages;
|
||||
|
||||
Some(old_pages)
|
||||
Ok(old_pages)
|
||||
}
|
||||
|
||||
pub fn as_slice(&self) -> &[u8] {
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::{
|
||||
backend::{Backend, FuncResolver, ProtectedCaller},
|
||||
cache::{Artifact, Error as CacheError, WasmHash},
|
||||
cache::{Artifact, Error as CacheError},
|
||||
error,
|
||||
import::ImportObject,
|
||||
structures::{Map, TypedIndex},
|
||||
|
@ -56,6 +56,10 @@ where
|
||||
pub fn into_boxed_map(self) -> BoxedMap<K, V> {
|
||||
BoxedMap::new(self.elems.into_boxed_slice())
|
||||
}
|
||||
|
||||
pub fn into_vec(self) -> Vec<V> {
|
||||
self.elems
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V> Map<K, V>
|
||||
|
@ -1,3 +1,5 @@
|
||||
use crate::error::MemoryCreationError;
|
||||
use crate::error::MemoryProtectionError;
|
||||
use errno;
|
||||
use nix::libc;
|
||||
use page_size;
|
||||
@ -16,13 +18,13 @@ pub struct Memory {
|
||||
}
|
||||
|
||||
impl Memory {
|
||||
pub fn from_file_path<P>(path: P, protection: Protect) -> Result<Self, String>
|
||||
pub fn from_file_path<P>(path: P, protection: Protect) -> Result<Self, MemoryCreationError>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
let file = File::open(path).map_err(|e| e.to_string())?;
|
||||
let file = File::open(path)?;
|
||||
|
||||
let file_len = file.metadata().map_err(|e| e.to_string())?.len();
|
||||
let file_len = file.metadata()?.len();
|
||||
|
||||
let raw_fd = RawFd::from_file(file);
|
||||
|
||||
@ -38,7 +40,10 @@ impl Memory {
|
||||
};
|
||||
|
||||
if ptr == -1 as _ {
|
||||
Err(errno::errno().to_string())
|
||||
Err(MemoryCreationError::VirtualMemoryAllocationFailed(
|
||||
file_len as usize,
|
||||
errno::errno().to_string(),
|
||||
))
|
||||
} else {
|
||||
Ok(Self {
|
||||
ptr: ptr as *mut u8,
|
||||
@ -84,7 +89,7 @@ impl Memory {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_size(size: usize) -> Result<Self, String> {
|
||||
pub fn with_size(size: usize) -> Result<Self, MemoryCreationError> {
|
||||
if size == 0 {
|
||||
return Ok(Self {
|
||||
ptr: ptr::null_mut(),
|
||||
@ -108,7 +113,10 @@ impl Memory {
|
||||
};
|
||||
|
||||
if ptr == -1 as _ {
|
||||
Err(errno::errno().to_string())
|
||||
Err(MemoryCreationError::VirtualMemoryAllocationFailed(
|
||||
size,
|
||||
errno::errno().to_string(),
|
||||
))
|
||||
} else {
|
||||
Ok(Self {
|
||||
ptr: ptr as *mut u8,
|
||||
@ -123,7 +131,7 @@ impl Memory {
|
||||
&mut self,
|
||||
range: impl RangeBounds<usize>,
|
||||
protection: Protect,
|
||||
) -> Result<(), String> {
|
||||
) -> Result<(), MemoryProtectionError> {
|
||||
let protect = protection.to_protect_const();
|
||||
|
||||
let range_start = match range.start_bound() {
|
||||
@ -147,7 +155,11 @@ impl Memory {
|
||||
|
||||
let success = libc::mprotect(start as _, size, protect as i32);
|
||||
if success == -1 {
|
||||
Err(errno::errno().to_string())
|
||||
Err(MemoryProtectionError::ProtectionFailed(
|
||||
start as usize,
|
||||
size,
|
||||
errno::errno().to_string(),
|
||||
))
|
||||
} else {
|
||||
self.protection = protection;
|
||||
Ok(())
|
||||
|
@ -1,3 +1,5 @@
|
||||
use crate::error::MemoryCreationError;
|
||||
use crate::error::MemoryProtectionError;
|
||||
use page_size;
|
||||
use std::ops::{Bound, RangeBounds};
|
||||
use std::{ptr, slice};
|
||||
@ -44,7 +46,7 @@ impl Memory {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_size(size: usize) -> Result<Self, String> {
|
||||
pub fn with_size(size: usize) -> Result<Self, MemoryCreationError> {
|
||||
if size == 0 {
|
||||
return Ok(Self {
|
||||
ptr: ptr::null_mut(),
|
||||
@ -58,7 +60,10 @@ impl Memory {
|
||||
let ptr = unsafe { VirtualAlloc(ptr::null_mut(), size, MEM_RESERVE, PAGE_NOACCESS) };
|
||||
|
||||
if ptr.is_null() {
|
||||
Err("unable to allocate memory".to_string())
|
||||
Err(MemoryCreationError::VirtualMemoryAllocationFailed(
|
||||
size,
|
||||
"unable to allocate memory".to_string(),
|
||||
))
|
||||
} else {
|
||||
Ok(Self {
|
||||
ptr: ptr as *mut u8,
|
||||
@ -72,7 +77,7 @@ impl Memory {
|
||||
&mut self,
|
||||
range: impl RangeBounds<usize>,
|
||||
protect: Protect,
|
||||
) -> Result<(), String> {
|
||||
) -> Result<(), MemoryProtectionError> {
|
||||
let protect_const = protect.to_protect_const();
|
||||
|
||||
let range_start = match range.start_bound() {
|
||||
@ -98,7 +103,11 @@ impl Memory {
|
||||
let ptr = VirtualAlloc(start as _, size, MEM_COMMIT, protect_const);
|
||||
|
||||
if ptr.is_null() {
|
||||
Err("unable to protect memory".to_string())
|
||||
Err(MemoryProtectionError::ProtectionFailed(
|
||||
start as usize,
|
||||
size,
|
||||
"unable to protect memory".to_string(),
|
||||
))
|
||||
} else {
|
||||
self.protection = protect;
|
||||
Ok(())
|
||||
|
@ -11,6 +11,7 @@ mod anyfunc;
|
||||
|
||||
pub use self::anyfunc::Anyfunc;
|
||||
use self::anyfunc::AnyfuncTable;
|
||||
use crate::error::GrowError;
|
||||
|
||||
pub enum Element<'a> {
|
||||
Anyfunc(Anyfunc<'a>),
|
||||
@ -108,15 +109,15 @@ impl Table {
|
||||
}
|
||||
|
||||
/// Grow this table by `delta`.
|
||||
pub fn grow(&self, delta: u32) -> Option<u32> {
|
||||
pub fn grow(&self, delta: u32) -> Result<u32, GrowError> {
|
||||
if delta == 0 {
|
||||
return Some(self.size());
|
||||
return Ok(self.size());
|
||||
}
|
||||
|
||||
match &mut *self.storage.borrow_mut() {
|
||||
(TableStorage::Anyfunc(ref mut anyfunc_table), ref mut local) => {
|
||||
anyfunc_table.grow(delta, local)
|
||||
}
|
||||
(TableStorage::Anyfunc(ref mut anyfunc_table), ref mut local) => anyfunc_table
|
||||
.grow(delta, local)
|
||||
.ok_or(GrowError::TableGrowError),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6,7 +6,7 @@ use crate::{
|
||||
types::{FuncSig, Type, WasmExternType},
|
||||
vm::Ctx,
|
||||
};
|
||||
use std::{cell::UnsafeCell, fmt, marker::PhantomData, mem, panic, ptr, sync::Arc};
|
||||
use std::{any::Any, cell::UnsafeCell, fmt, marker::PhantomData, mem, panic, ptr, sync::Arc};
|
||||
|
||||
thread_local! {
|
||||
pub static EARLY_TRAPPER: UnsafeCell<Option<Box<dyn UserTrapper>>> = UnsafeCell::new(None);
|
||||
@ -40,14 +40,14 @@ pub trait TrapEarly<Rets>
|
||||
where
|
||||
Rets: WasmTypeList,
|
||||
{
|
||||
fn report(self) -> Result<Rets, String>;
|
||||
fn report(self) -> Result<Rets, Box<dyn Any>>;
|
||||
}
|
||||
|
||||
impl<Rets> TrapEarly<Rets> for Rets
|
||||
where
|
||||
Rets: WasmTypeList,
|
||||
{
|
||||
fn report(self) -> Result<Rets, String> {
|
||||
fn report(self) -> Result<Rets, Box<dyn Any>> {
|
||||
Ok(self)
|
||||
}
|
||||
}
|
||||
@ -55,10 +55,10 @@ where
|
||||
impl<Rets, E> TrapEarly<Rets> for Result<Rets, E>
|
||||
where
|
||||
Rets: WasmTypeList,
|
||||
E: fmt::Debug,
|
||||
E: Any,
|
||||
{
|
||||
fn report(self) -> Result<Rets, String> {
|
||||
self.map_err(|err| format!("Error: {:?}", err))
|
||||
fn report(self) -> Result<Rets, Box<dyn Any>> {
|
||||
self.map_err(|err| Box::new(err) as Box<dyn Any>)
|
||||
}
|
||||
}
|
||||
|
||||
@ -191,25 +191,17 @@ macro_rules! impl_traits {
|
||||
extern fn wrap<$( $x: WasmExternType, )* Rets: WasmTypeList, Trap: TrapEarly<Rets>, FN: Fn( &mut Ctx $( ,$x )* ) -> Trap>( ctx: &mut Ctx $( ,$x: $x )* ) -> Rets::CStruct {
|
||||
let f: FN = unsafe { mem::transmute_copy(&()) };
|
||||
|
||||
let msg = match panic::catch_unwind(panic::AssertUnwindSafe(|| {
|
||||
let err = match panic::catch_unwind(panic::AssertUnwindSafe(|| {
|
||||
f( ctx $( ,$x )* ).report()
|
||||
})) {
|
||||
Ok(Ok(returns)) => return returns.into_c_struct(),
|
||||
Ok(Err(err)) => err,
|
||||
Err(err) => {
|
||||
if let Some(s) = err.downcast_ref::<&str>() {
|
||||
s.to_string()
|
||||
} else if let Some(s) = err.downcast_ref::<String>() {
|
||||
s.clone()
|
||||
} else {
|
||||
"a panic occurred, but no additional information is available".to_string()
|
||||
}
|
||||
},
|
||||
Err(err) => err,
|
||||
};
|
||||
|
||||
unsafe {
|
||||
if let Some(early_trapper) = &*EARLY_TRAPPER.with(|ucell| ucell.get()) {
|
||||
early_trapper.do_early_trap(msg)
|
||||
early_trapper.do_early_trap(err)
|
||||
} else {
|
||||
eprintln!("panic handling not setup");
|
||||
std::process::exit(1)
|
||||
|
@ -1,3 +1,4 @@
|
||||
use crate::error::PageError;
|
||||
use std::{
|
||||
fmt,
|
||||
ops::{Add, Sub},
|
||||
@ -11,12 +12,16 @@ const WASM_MAX_PAGES: usize = 65_536;
|
||||
pub struct Pages(pub u32);
|
||||
|
||||
impl Pages {
|
||||
pub fn checked_add(self, rhs: Pages) -> Option<Pages> {
|
||||
pub fn checked_add(self, rhs: Pages) -> Result<Pages, PageError> {
|
||||
let added = (self.0 as usize) + (rhs.0 as usize);
|
||||
if added <= WASM_MAX_PAGES {
|
||||
Some(Pages(added as u32))
|
||||
Ok(Pages(added as u32))
|
||||
} else {
|
||||
None
|
||||
Err(PageError::ExceededMaxPages(
|
||||
self.0 as usize,
|
||||
rhs.0 as usize,
|
||||
added,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -20,10 +20,9 @@ pub unsafe extern "C" fn local_static_memory_grow(
|
||||
let local_memory = *ctx.memories.add(memory_index.index());
|
||||
let memory = (*local_memory).memory as *mut StaticMemory;
|
||||
|
||||
if let Some(old) = (*memory).grow(delta, &mut *local_memory) {
|
||||
old.0 as i32
|
||||
} else {
|
||||
-1
|
||||
match (*memory).grow(delta, &mut *local_memory) {
|
||||
Ok(old) => old.0 as i32,
|
||||
Err(_) => -1,
|
||||
}
|
||||
}
|
||||
|
||||
@ -45,10 +44,9 @@ pub unsafe extern "C" fn local_dynamic_memory_grow(
|
||||
let local_memory = *ctx.memories.add(memory_index.index());
|
||||
let memory = (*local_memory).memory as *mut DynamicMemory;
|
||||
|
||||
if let Some(old) = (*memory).grow(delta, &mut *local_memory) {
|
||||
old.0 as i32
|
||||
} else {
|
||||
-1
|
||||
match (*memory).grow(delta, &mut *local_memory) {
|
||||
Ok(old) => old.0 as i32,
|
||||
Err(_) => -1,
|
||||
}
|
||||
}
|
||||
|
||||
@ -74,10 +72,9 @@ pub unsafe extern "C" fn imported_static_memory_grow(
|
||||
let local_memory = *ctx.imported_memories.add(import_memory_index.index());
|
||||
let memory = (*local_memory).memory as *mut StaticMemory;
|
||||
|
||||
if let Some(old) = (*memory).grow(delta, &mut *local_memory) {
|
||||
old.0 as i32
|
||||
} else {
|
||||
-1
|
||||
match (*memory).grow(delta, &mut *local_memory) {
|
||||
Ok(old) => old.0 as i32,
|
||||
Err(_) => -1,
|
||||
}
|
||||
}
|
||||
|
||||
@ -99,10 +96,9 @@ pub unsafe extern "C" fn imported_dynamic_memory_grow(
|
||||
let local_memory = *ctx.imported_memories.add(memory_index.index());
|
||||
let memory = (*local_memory).memory as *mut DynamicMemory;
|
||||
|
||||
if let Some(old) = (*memory).grow(delta, &mut *local_memory) {
|
||||
old.0 as i32
|
||||
} else {
|
||||
-1
|
||||
match (*memory).grow(delta, &mut *local_memory) {
|
||||
Ok(old) => old.0 as i32,
|
||||
Err(_) => -1,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "wasmer-runtime"
|
||||
version = "0.1.4"
|
||||
version = "0.2.1"
|
||||
description = "Wasmer runtime library"
|
||||
license = "MIT"
|
||||
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
|
||||
@ -14,11 +14,16 @@ memmap = "0.7.0"
|
||||
|
||||
[dependencies.wasmer-runtime-core]
|
||||
path = "../runtime-core"
|
||||
version = "0.1.2"
|
||||
version = "0.2.1"
|
||||
|
||||
[dependencies.wasmer-clif-backend]
|
||||
path = "../clif-backend"
|
||||
version = "0.1.2"
|
||||
version = "0.2.0"
|
||||
|
||||
[dev-dependencies]
|
||||
tempfile = "3.0.7"
|
||||
criterion = "0.2"
|
||||
wabt = "0.7.4"
|
||||
|
||||
[dependencies.wasmer-llvm-backend]
|
||||
path = "../llvm-backend"
|
||||
@ -26,5 +31,6 @@ path = "../llvm-backend"
|
||||
[features]
|
||||
debug = ["wasmer-clif-backend/debug", "wasmer-runtime-core/debug"]
|
||||
|
||||
[dev-dependencies]
|
||||
wabt = "0.7.4"
|
||||
[[bench]]
|
||||
name = "nginx"
|
||||
harness = false
|
||||
|
@ -51,7 +51,7 @@ fn main() -> error::Result<()> {
|
||||
// We're not importing anything, so make an empty import object.
|
||||
let import_object = imports! {};
|
||||
|
||||
let mut instance = instantiate(WASM, import_object)?;
|
||||
let mut instance = instantiate(WASM, &import_object)?;
|
||||
|
||||
let values = instance
|
||||
.func("add_one")?
|
||||
|
53
lib/runtime/benches/nginx.rs
Normal file
53
lib/runtime/benches/nginx.rs
Normal file
@ -0,0 +1,53 @@
|
||||
#[macro_use]
|
||||
extern crate criterion;
|
||||
use criterion::Criterion;
|
||||
use tempfile::tempdir;
|
||||
use wasmer_runtime::{
|
||||
cache::{Cache, FileSystemCache, WasmHash},
|
||||
compile, validate,
|
||||
};
|
||||
|
||||
static NGINX_WASM: &'static [u8] = include_bytes!("../../../examples/nginx/nginx.wasm");
|
||||
|
||||
fn compile_module() {
|
||||
compile(NGINX_WASM).unwrap();
|
||||
}
|
||||
|
||||
fn load_module(hash: WasmHash, cache: &impl Cache) {
|
||||
cache.load(hash).expect("could not load module");
|
||||
}
|
||||
|
||||
fn hashing_benchmark(c: &mut Criterion) {
|
||||
c.bench_function("nginx HASH", |b| b.iter(|| WasmHash::generate(NGINX_WASM)));
|
||||
}
|
||||
|
||||
fn validate_benchmark(c: &mut Criterion) {
|
||||
c.bench_function("nginx validate", |b| b.iter(|| validate(NGINX_WASM)));
|
||||
}
|
||||
|
||||
fn compile_benchmark(c: &mut Criterion) {
|
||||
c.bench_function("nginx compile", |b| b.iter(|| compile_module()));
|
||||
}
|
||||
|
||||
fn load_benchmark(c: &mut Criterion) {
|
||||
c.bench_function("nginx load", |b| {
|
||||
let tempdir = tempdir().unwrap();
|
||||
let mut cache = unsafe {
|
||||
FileSystemCache::new(tempdir.path()).expect("unable to create file system cache")
|
||||
};
|
||||
let module = compile(NGINX_WASM).unwrap();
|
||||
let wasm_hash = WasmHash::generate(NGINX_WASM);
|
||||
cache
|
||||
.store(wasm_hash, module)
|
||||
.expect("unable to store into cache");
|
||||
|
||||
b.iter(|| load_module(wasm_hash, &cache))
|
||||
});
|
||||
}
|
||||
|
||||
criterion_group! {
|
||||
name = benches;
|
||||
config = Criterion::default().sample_size(10);
|
||||
targets = validate_benchmark, hashing_benchmark, compile_benchmark, load_benchmark
|
||||
}
|
||||
criterion_main!(benches);
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "wasmer-spectests"
|
||||
version = "0.1.2"
|
||||
version = "0.2.0"
|
||||
description = "Wasmer spectests library"
|
||||
license = "MIT"
|
||||
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
|
||||
@ -9,13 +9,13 @@ edition = "2018"
|
||||
build = "build/mod.rs"
|
||||
|
||||
[dependencies]
|
||||
wasmer-runtime-core = { path = "../runtime-core" }
|
||||
wasmer-runtime-core = { path = "../runtime-core", version = "0.2.0" }
|
||||
|
||||
[build-dependencies]
|
||||
wabt = "0.7.2"
|
||||
|
||||
[dev-dependencies]
|
||||
wasmer-clif-backend = { path = "../clif-backend", version = "0.1.2" }
|
||||
wasmer-clif-backend = { path = "../clif-backend", version = "0.2.0" }
|
||||
wasmer-llvm-backend = { path = "../llvm-backend", version = "0.1.0" }
|
||||
wabt = "0.7.2"
|
||||
|
||||
|
@ -569,7 +569,7 @@ fn {}_assert_malformed() {{
|
||||
let assertion = if expected.len() > 0 && is_nan(&expected[0]) {
|
||||
format!(
|
||||
"let expected = {expected_result};
|
||||
if let {return_type_destructure} = result.clone().unwrap().first().unwrap() {{
|
||||
if let {return_type_destructure} = result.as_ref().unwrap().first().unwrap() {{
|
||||
assert!((*result as {return_type}).is_nan());
|
||||
assert_eq!((*result as {return_type}).is_sign_positive(), (expected as {return_type}).is_sign_positive());
|
||||
}} else {{
|
||||
|
@ -31,7 +31,7 @@ mod tests {
|
||||
|
||||
match result {
|
||||
Err(err) => match err {
|
||||
CallError::Runtime(RuntimeError::Unknown { msg }) => {
|
||||
CallError::Runtime(RuntimeError::Trap { msg }) => {
|
||||
assert!(!msg.contains("segmentation violation"));
|
||||
assert!(!msg.contains("bus error"));
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "wasmer-win-exception-handler"
|
||||
version = "0.0.1"
|
||||
version = "0.2.0"
|
||||
description = "Wasmer runtime exception handling for Windows"
|
||||
license = "MIT"
|
||||
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
|
||||
@ -8,9 +8,9 @@ repository = "https://github.com/wasmerio/wasmer"
|
||||
edition = "2018"
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
wasmer-runtime-core = { path = "../runtime-core", version = "0.1.2" }
|
||||
wasmer-runtime-core = { path = "../runtime-core", version = "0.2.0" }
|
||||
winapi = { version = "0.3", features = ["winbase", "errhandlingapi", "minwindef", "minwinbase", "winnt"] }
|
||||
libc = "0.2.48"
|
||||
libc = "0.2.49"
|
||||
|
||||
[build-dependencies]
|
||||
cmake = "0.1.35"
|
||||
|
@ -10,6 +10,7 @@ __declspec(thread) DWORD64 caughtInstructionPointer;
|
||||
__declspec(thread) PVOID savedStackPointer;
|
||||
__declspec(thread) BOOL exceptionHandlerInstalled = FALSE;
|
||||
__declspec(thread) BOOL alreadyHandlingException = FALSE;
|
||||
__declspec(thread) PVOID handle;
|
||||
|
||||
void longjmpOutOfHere() {
|
||||
longjmp(jmpBuf, 1);
|
||||
@ -38,6 +39,14 @@ exceptionHandler(struct _EXCEPTION_POINTERS *ExceptionInfo) {
|
||||
return EXCEPTION_CONTINUE_EXECUTION;
|
||||
}
|
||||
|
||||
static void removeExceptionHandler() {
|
||||
if (exceptionHandlerInstalled == FALSE) {
|
||||
return;
|
||||
}
|
||||
RemoveVectoredExceptionHandler(handle);
|
||||
exceptionHandlerInstalled = FALSE;
|
||||
}
|
||||
|
||||
uint8_t callProtected(trampoline_t trampoline,
|
||||
const struct wasmer_instance_context_t* ctx,
|
||||
const struct func_t* func,
|
||||
@ -48,7 +57,7 @@ uint8_t callProtected(trampoline_t trampoline,
|
||||
// install exception handler
|
||||
if (exceptionHandlerInstalled == FALSE) {
|
||||
exceptionHandlerInstalled = TRUE;
|
||||
AddVectoredExceptionHandler(CALL_FIRST, exceptionHandler);
|
||||
handle = AddVectoredExceptionHandler(CALL_FIRST, exceptionHandler);
|
||||
}
|
||||
|
||||
// jmp jmp jmp!
|
||||
@ -60,6 +69,8 @@ uint8_t callProtected(trampoline_t trampoline,
|
||||
out_result->code = 0;
|
||||
out_result->exceptionAddress = 0;
|
||||
out_result->instructionPointer = 0;
|
||||
|
||||
removeExceptionHandler();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@ -70,5 +81,6 @@ uint8_t callProtected(trampoline_t trampoline,
|
||||
caughtExceptionAddress = 0;
|
||||
caughtInstructionPointer = 0;
|
||||
|
||||
removeExceptionHandler();
|
||||
return FALSE;
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
extern crate structopt;
|
||||
|
||||
use std::env;
|
||||
use std::fs;
|
||||
use std::fs::File;
|
||||
use std::io;
|
||||
use std::io::Read;
|
||||
@ -14,7 +13,6 @@ use wasmer::webassembly::InstanceABI;
|
||||
use wasmer::*;
|
||||
use wasmer_emscripten;
|
||||
use wasmer_runtime::cache::{Cache as BaseCache, FileSystemCache, WasmHash};
|
||||
use wasmer_runtime::error::CacheError;
|
||||
|
||||
#[derive(Debug, StructOpt)]
|
||||
#[structopt(name = "wasmer", about = "Wasm execution runtime.")]
|
||||
@ -35,9 +33,6 @@ enum CLIOptions {
|
||||
|
||||
#[derive(Debug, StructOpt)]
|
||||
struct Run {
|
||||
#[structopt(short = "d", long = "debug")]
|
||||
debug: bool,
|
||||
|
||||
// Disable the cache
|
||||
#[structopt(long = "disable-cache")]
|
||||
disable_cache: bool,
|
||||
@ -84,6 +79,12 @@ fn get_cache_dir() -> PathBuf {
|
||||
|
||||
/// Execute a wasm/wat file
|
||||
fn execute_wasm(options: &Run) -> Result<(), String> {
|
||||
// force disable caching on windows
|
||||
#[cfg(target_os = "windows")]
|
||||
let disable_cache = true;
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
let disable_cache = options.disable_cache;
|
||||
|
||||
let wasm_path = &options.path;
|
||||
|
||||
let mut wasm_binary: Vec<u8> = read_file_contents(wasm_path).map_err(|err| {
|
||||
@ -99,7 +100,7 @@ fn execute_wasm(options: &Run) -> Result<(), String> {
|
||||
.map_err(|e| format!("Can't convert from wast to wasm: {:?}", e))?;
|
||||
}
|
||||
|
||||
let module = if !options.disable_cache {
|
||||
let module = if !disable_cache {
|
||||
// If we have cache enabled
|
||||
|
||||
// We generate a hash for the given binary, so we can use it as key
|
||||
@ -188,8 +189,10 @@ fn main() {
|
||||
CLIOptions::SelfUpdate => {
|
||||
println!("Self update is not supported on Windows. Use install instructions on the Wasmer homepage: https://wasmer.io");
|
||||
}
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
CLIOptions::Cache(cache) => match cache {
|
||||
Cache::Clean => {
|
||||
use std::fs;
|
||||
let cache_dir = get_cache_dir();
|
||||
fs::remove_dir_all(cache_dir.clone()).expect("Can't remove cache dir");
|
||||
fs::create_dir(cache_dir.clone()).expect("Can't create cache dir");
|
||||
@ -198,5 +201,9 @@ fn main() {
|
||||
println!("{}", get_cache_dir().to_string_lossy());
|
||||
}
|
||||
},
|
||||
#[cfg(target_os = "windows")]
|
||||
CLIOptions::Cache(_) => {
|
||||
println!("Caching is disabled for Windows.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ ChangesEnvironment=yes
|
||||
OutputBaseFilename=WasmerInstaller
|
||||
|
||||
[Files]
|
||||
Source: "..\target\release\wasmer.exe"; DestDir: "{app}\bin"
|
||||
Source: "..\..\target\release\wasmer.exe"; DestDir: "{app}\bin"
|
||||
|
||||
[Code]
|
||||
const EnvironmentKey = 'SYSTEM\CurrentControlSet\Control\Session Manager\Environment';
|
||||
|
Loading…
Reference in New Issue
Block a user