mirror of
https://github.com/fluencelabs/wasmer
synced 2024-12-13 22:25:40 +00:00
merge upstream/master into wasmer-private/feature/llvm-backend
This commit is contained in:
commit
4e198bca8b
@ -14,30 +14,36 @@ environment:
|
|||||||
|
|
||||||
cache:
|
cache:
|
||||||
- 'C:\Users\appveyor\.cargo'
|
- 'C:\Users\appveyor\.cargo'
|
||||||
|
- target
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe
|
# uncomment these lines if the cache is cleared, or if we must re-install rust for some reason
|
||||||
- rustup-init.exe -yv --default-host %target%
|
# - appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe
|
||||||
|
# - rustup-init.exe -yv --default-host %target%
|
||||||
- set PATH=%PATH%;%USERPROFILE%\.cargo\bin
|
- set PATH=%PATH%;%USERPROFILE%\.cargo\bin
|
||||||
|
- rustup default stable-%target%
|
||||||
|
- rustup update
|
||||||
- rustc -vV
|
- rustc -vV
|
||||||
- cargo -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:
|
build_script:
|
||||||
- cargo build --verbose
|
- cargo build --release --verbose
|
||||||
|
|
||||||
test_script:
|
test_script:
|
||||||
- set RUST_BACKTRACE=1
|
- cargo test --package wasmer-spectests
|
||||||
- cd ./lib/spectests && cargo test -- --test-threads 1 && cd ../..
|
|
||||||
|
|
||||||
before_deploy:
|
after_build:
|
||||||
- cd ./src/installer
|
- cd ./src/installer
|
||||||
- iscc wasmer.iss
|
- iscc wasmer.iss
|
||||||
- copy /y .\WasmerInstaller.exe ..\..\WasmerInstaller-%APPVEYOR_REPO_TAG_NAME%.exe
|
- copy /y .\WasmerInstaller.exe ..\..\WasmerInstaller-%APPVEYOR_REPO_TAG_NAME%.exe
|
||||||
- appveyor PushArtifact WasmerInstaller-%APPVEYOR_REPO_TAG_NAME%.exe
|
- appveyor PushArtifact ..\..\WasmerInstaller-%APPVEYOR_REPO_TAG_NAME%.exe
|
||||||
|
- cd ..\..\
|
||||||
artifacts:
|
|
||||||
- path: WasmerInstaller-%APPVEYOR_REPO_TAG_NAME%.exe
|
|
||||||
name: WasmerInstaller.exe
|
|
||||||
|
|
||||||
deploy:
|
deploy:
|
||||||
description: 'WasmerInstaller'
|
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]
|
[package]
|
||||||
name = "wasmer"
|
name = "wasmer"
|
||||||
version = "0.1.4"
|
version = "0.2.1"
|
||||||
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
|
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
repository = "https://github.com/wasmerio/wasmer"
|
repository = "https://github.com/wasmerio/wasmer"
|
||||||
@ -36,6 +36,6 @@ glob = "0.2.11"
|
|||||||
[features]
|
[features]
|
||||||
default = ["fast-tests"]
|
default = ["fast-tests"]
|
||||||
|
|
||||||
debug = []
|
debug = ["wasmer-clif-backend/debug", "wasmer-runtime-core/debug"]
|
||||||
# This feature will allow cargo test to run much faster
|
# This feature will allow cargo test to run much faster
|
||||||
fast-tests = []
|
fast-tests = []
|
||||||
|
5
Makefile
5
Makefile
@ -19,7 +19,7 @@ capi:
|
|||||||
# rm -rf artifacts
|
# rm -rf artifacts
|
||||||
|
|
||||||
build:
|
build:
|
||||||
cargo build
|
cargo build --features debug
|
||||||
|
|
||||||
install:
|
install:
|
||||||
cargo install --path .
|
cargo install --path .
|
||||||
@ -47,6 +47,9 @@ release:
|
|||||||
# brew install mingw-w64
|
# brew install mingw-w64
|
||||||
cargo build --release
|
cargo build --release
|
||||||
|
|
||||||
|
debug-release:
|
||||||
|
cargo build --release --features debug
|
||||||
|
|
||||||
debug-release:
|
debug-release:
|
||||||
cargo build --release --features "debug"
|
cargo build --release --features "debug"
|
||||||
|
|
||||||
|
@ -142,6 +142,14 @@ You can also run integration tests with:
|
|||||||
make integration-tests
|
make integration-tests
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Benchmarking
|
||||||
|
|
||||||
|
Benchmarks can be run with:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cargo bench --all
|
||||||
|
```
|
||||||
|
|
||||||
## Roadmap
|
## 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.
|
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"
|
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
|
# 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
|
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"
|
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]
|
[package]
|
||||||
name = "wasmer-clif-backend"
|
name = "wasmer-clif-backend"
|
||||||
version = "0.1.2"
|
version = "0.2.0"
|
||||||
description = "Wasmer runtime Cranelift compiler backend"
|
description = "Wasmer runtime Cranelift compiler backend"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
|
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
|
||||||
@ -8,7 +8,7 @@ repository = "https://github.com/wasmerio/wasmer"
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[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-native = "0.26.0"
|
||||||
cranelift-codegen = "0.26.0"
|
cranelift-codegen = "0.26.0"
|
||||||
cranelift-entity = "0.26.0"
|
cranelift-entity = "0.26.0"
|
||||||
@ -18,7 +18,8 @@ target-lexicon = "0.2.0"
|
|||||||
wasmparser = "0.23.0"
|
wasmparser = "0.23.0"
|
||||||
byteorder = "1"
|
byteorder = "1"
|
||||||
nix = "0.13.0"
|
nix = "0.13.0"
|
||||||
libc = "0.2.48"
|
libc = "0.2.49"
|
||||||
|
rayon = "1.0"
|
||||||
|
|
||||||
# Dependencies for caching.
|
# Dependencies for caching.
|
||||||
[dependencies.serde]
|
[dependencies.serde]
|
||||||
@ -32,7 +33,7 @@ version = "0.0.7"
|
|||||||
|
|
||||||
[target.'cfg(windows)'.dependencies]
|
[target.'cfg(windows)'.dependencies]
|
||||||
winapi = { version = "0.3", features = ["errhandlingapi", "minwindef", "minwinbase", "winnt"] }
|
winapi = { version = "0.3", 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]
|
[features]
|
||||||
debug = ["wasmer-runtime-core/debug"]
|
debug = ["wasmer-runtime-core/debug"]
|
||||||
|
@ -24,6 +24,7 @@ use wasmer_runtime_core::{
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate serde_derive;
|
extern crate serde_derive;
|
||||||
|
|
||||||
|
extern crate rayon;
|
||||||
extern crate serde;
|
extern crate serde;
|
||||||
|
|
||||||
use wasmparser::{self, WasmDecoder};
|
use wasmparser::{self, WasmDecoder};
|
||||||
|
@ -7,6 +7,7 @@ use crate::{
|
|||||||
},
|
},
|
||||||
signal::HandlerData,
|
signal::HandlerData,
|
||||||
};
|
};
|
||||||
|
use rayon::prelude::*;
|
||||||
|
|
||||||
use byteorder::{ByteOrder, LittleEndian};
|
use byteorder::{ByteOrder, LittleEndian};
|
||||||
use cranelift_codegen::{ir, isa, Context};
|
use cranelift_codegen::{ir, isa, Context};
|
||||||
@ -92,25 +93,44 @@ impl FuncResolverBuilder {
|
|||||||
function_bodies: Map<LocalFuncIndex, ir::Function>,
|
function_bodies: Map<LocalFuncIndex, ir::Function>,
|
||||||
info: &ModuleInfo,
|
info: &ModuleInfo,
|
||||||
) -> CompileResult<(Self, HandlerData)> {
|
) -> CompileResult<(Self, HandlerData)> {
|
||||||
let mut compiled_functions: Vec<Vec<u8>> = Vec::with_capacity(function_bodies.len());
|
let num_func_bodies = function_bodies.len();
|
||||||
let mut local_relocs = Map::with_capacity(function_bodies.len());
|
let mut local_relocs = Map::with_capacity(num_func_bodies);
|
||||||
let mut external_relocs = Map::new();
|
let mut external_relocs = Map::with_capacity(num_func_bodies);
|
||||||
|
|
||||||
let mut trap_sink = TrapSink::new();
|
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;
|
let mut total_size = 0;
|
||||||
|
// We separate into two iterators, one iterable and one into iterable
|
||||||
for (_, func) in function_bodies {
|
let (code_bufs, sinks): (Vec<Vec<u8>>, Vec<(RelocSink, LocalTrapSink)>) =
|
||||||
ctx.func = func;
|
compiled_functions.into_iter().unzip();
|
||||||
let mut code_buf = Vec::new();
|
for (code_buf, (reloc_sink, mut local_trap_sink)) in code_bufs.iter().zip(sinks.into_iter())
|
||||||
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();
|
|
||||||
|
|
||||||
// Clear the local trap sink and consolidate all trap info
|
// Clear the local trap sink and consolidate all trap info
|
||||||
// into a single location.
|
// into a single location.
|
||||||
trap_sink.drain_local(total_size, &mut local_trap_sink);
|
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.
|
// Round up each function's size to pointer alignment.
|
||||||
total_size += round_up(code_buf.len(), mem::size_of::<usize>());
|
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());
|
local_relocs.push(reloc_sink.local_relocs.into_boxed_slice());
|
||||||
external_relocs.push(reloc_sink.external_relocs.into_boxed_slice());
|
external_relocs.push(reloc_sink.external_relocs.into_boxed_slice());
|
||||||
}
|
}
|
||||||
@ -145,10 +164,10 @@ impl FuncResolverBuilder {
|
|||||||
*i = 0xCC;
|
*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;
|
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>());
|
let new_end = previous_end + round_up(compiled.len(), mem::size_of::<usize>());
|
||||||
unsafe {
|
unsafe {
|
||||||
memory.as_slice_mut()[previous_end..previous_end + compiled.len()]
|
memory.as_slice_mut()[previous_end..previous_end + compiled.len()]
|
||||||
|
@ -2,7 +2,7 @@ use crate::relocation::{TrapData, TrapSink};
|
|||||||
use crate::trampoline::Trampolines;
|
use crate::trampoline::Trampolines;
|
||||||
use hashbrown::HashSet;
|
use hashbrown::HashSet;
|
||||||
use libc::c_void;
|
use libc::c_void;
|
||||||
use std::{cell::Cell, sync::Arc};
|
use std::{any::Any, cell::Cell, sync::Arc};
|
||||||
use wasmer_runtime_core::{
|
use wasmer_runtime_core::{
|
||||||
backend::{ProtectedCaller, Token, UserTrapper},
|
backend::{ProtectedCaller, Token, UserTrapper},
|
||||||
error::RuntimeResult,
|
error::RuntimeResult,
|
||||||
@ -25,14 +25,14 @@ pub use self::unix::*;
|
|||||||
pub use self::windows::*;
|
pub use self::windows::*;
|
||||||
|
|
||||||
thread_local! {
|
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;
|
pub struct Trapper;
|
||||||
|
|
||||||
impl UserTrapper for Trapper {
|
impl UserTrapper for Trapper {
|
||||||
unsafe fn do_early_trap(&self, msg: String) -> ! {
|
unsafe fn do_early_trap(&self, data: Box<dyn Any>) -> ! {
|
||||||
TRAP_EARLY_DATA.with(|cell| cell.set(Some(msg)));
|
TRAP_EARLY_DATA.with(|cell| cell.set(Some(data)));
|
||||||
trigger_trap()
|
trigger_trap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -79,8 +79,8 @@ pub fn call_protected<T>(handler_data: &HandlerData, f: impl FnOnce() -> T) -> R
|
|||||||
if signum != 0 {
|
if signum != 0 {
|
||||||
*jmp_buf = prev_jmp_buf;
|
*jmp_buf = prev_jmp_buf;
|
||||||
|
|
||||||
if let Some(msg) = super::TRAP_EARLY_DATA.with(|cell| cell.replace(None)) {
|
if let Some(data) = super::TRAP_EARLY_DATA.with(|cell| cell.replace(None)) {
|
||||||
Err(RuntimeError::User { msg })
|
Err(RuntimeError::Panic { data })
|
||||||
} else {
|
} else {
|
||||||
let (faulting_addr, inst_ptr) = CAUGHT_ADDRESSES.with(|cell| cell.get());
|
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) {
|
Err(match Signal::from_c_int(signum) {
|
||||||
Ok(SIGILL) => match trapcode {
|
Ok(SIGILL) => match trapcode {
|
||||||
TrapCode::BadSignature => RuntimeError::IndirectCallSignature {
|
TrapCode::BadSignature => RuntimeError::Trap {
|
||||||
table: TableIndex::new(0),
|
msg: "incorrect call_indirect signature".into(),
|
||||||
},
|
},
|
||||||
TrapCode::IndirectCallToNull => RuntimeError::IndirectCallToNull {
|
TrapCode::IndirectCallToNull => RuntimeError::Trap {
|
||||||
table: TableIndex::new(0),
|
msg: "indirect call to null".into(),
|
||||||
},
|
},
|
||||||
TrapCode::HeapOutOfBounds => RuntimeError::OutOfBoundsAccess {
|
TrapCode::HeapOutOfBounds => RuntimeError::Trap {
|
||||||
memory: MemoryIndex::new(0),
|
msg: "memory out-of-bounds access".into(),
|
||||||
addr: None,
|
|
||||||
},
|
},
|
||||||
TrapCode::TableOutOfBounds => RuntimeError::TableOutOfBounds {
|
TrapCode::TableOutOfBounds => RuntimeError::Trap {
|
||||||
table: TableIndex::new(0),
|
msg: "table out-of-bounds access".into(),
|
||||||
},
|
},
|
||||||
_ => RuntimeError::Unknown {
|
_ => RuntimeError::Trap {
|
||||||
msg: "unknown trap".to_string(),
|
msg: "unknown trap".into(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Ok(SIGSEGV) | Ok(SIGBUS) => RuntimeError::OutOfBoundsAccess {
|
Ok(SIGSEGV) | Ok(SIGBUS) => RuntimeError::Trap {
|
||||||
memory: MemoryIndex::new(0),
|
msg: "memory out-of-bounds access".into(),
|
||||||
addr: None,
|
},
|
||||||
|
Ok(SIGFPE) => RuntimeError::Trap {
|
||||||
|
msg: "illegal arithmetic operation".into(),
|
||||||
},
|
},
|
||||||
Ok(SIGFPE) => RuntimeError::IllegalArithmeticOperation,
|
|
||||||
_ => unimplemented!(),
|
_ => unimplemented!(),
|
||||||
}
|
}
|
||||||
.into())
|
.into())
|
||||||
@ -126,8 +126,8 @@ pub fn call_protected<T>(handler_data: &HandlerData, f: impl FnOnce() -> T) -> R
|
|||||||
_ => "unkown trapped signal",
|
_ => "unkown trapped signal",
|
||||||
};
|
};
|
||||||
// When the trap-handler is fully implemented, this will return more information.
|
// When the trap-handler is fully implemented, this will return more information.
|
||||||
Err(RuntimeError::Unknown {
|
Err(RuntimeError::Trap {
|
||||||
msg: format!("trap at {:p} - {}", faulting_addr, signal),
|
msg: format!("unknown trap at {:p} - {}", faulting_addr, signal).into(),
|
||||||
}
|
}
|
||||||
.into())
|
.into())
|
||||||
}
|
}
|
||||||
|
@ -57,35 +57,34 @@ pub fn call_protected(
|
|||||||
}) = handler_data.lookup(instruction_pointer as _)
|
}) = handler_data.lookup(instruction_pointer as _)
|
||||||
{
|
{
|
||||||
Err(match signum as DWORD {
|
Err(match signum as DWORD {
|
||||||
EXCEPTION_ACCESS_VIOLATION => RuntimeError::OutOfBoundsAccess {
|
EXCEPTION_ACCESS_VIOLATION => RuntimeError::Trap {
|
||||||
memory: MemoryIndex::new(0),
|
msg: "memory out-of-bounds access".into(),
|
||||||
addr: None,
|
|
||||||
},
|
},
|
||||||
EXCEPTION_ILLEGAL_INSTRUCTION => match trapcode {
|
EXCEPTION_ILLEGAL_INSTRUCTION => match trapcode {
|
||||||
TrapCode::BadSignature => RuntimeError::IndirectCallSignature {
|
TrapCode::BadSignature => RuntimeError::Trap {
|
||||||
table: TableIndex::new(0),
|
msg: "incorrect call_indirect signature".into(),
|
||||||
},
|
},
|
||||||
TrapCode::IndirectCallToNull => RuntimeError::IndirectCallToNull {
|
TrapCode::IndirectCallToNull => RuntimeError::Trap {
|
||||||
table: TableIndex::new(0),
|
msg: "indirect call to null".into(),
|
||||||
},
|
},
|
||||||
TrapCode::HeapOutOfBounds => RuntimeError::OutOfBoundsAccess {
|
TrapCode::HeapOutOfBounds => RuntimeError::Trap {
|
||||||
memory: MemoryIndex::new(0),
|
msg: "memory out-of-bounds access".into(),
|
||||||
addr: None,
|
|
||||||
},
|
},
|
||||||
TrapCode::TableOutOfBounds => RuntimeError::TableOutOfBounds {
|
TrapCode::TableOutOfBounds => RuntimeError::Trap {
|
||||||
table: TableIndex::new(0),
|
msg: "table out-of-bounds access".into(),
|
||||||
},
|
},
|
||||||
_ => RuntimeError::Unknown {
|
_ => RuntimeError::Trap {
|
||||||
msg: "unknown trap".to_string(),
|
msg: "unknown trap".into(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
EXCEPTION_STACK_OVERFLOW => RuntimeError::Unknown {
|
EXCEPTION_STACK_OVERFLOW => RuntimeError::Trap {
|
||||||
msg: "unknown trap".to_string(),
|
msg: "stack overflow trap".into(),
|
||||||
},
|
},
|
||||||
EXCEPTION_INT_DIVIDE_BY_ZERO => RuntimeError::IllegalArithmeticOperation,
|
EXCEPTION_INT_DIVIDE_BY_ZERO | EXCEPTION_INT_OVERFLOW => RuntimeError::Trap {
|
||||||
EXCEPTION_INT_OVERFLOW => RuntimeError::IllegalArithmeticOperation,
|
msg: "illegal arithmetic operation".into(),
|
||||||
_ => RuntimeError::Unknown {
|
},
|
||||||
msg: "unknown trap".to_string(),
|
_ => RuntimeError::Trap {
|
||||||
|
msg: "unknown trap".into(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
.into())
|
.into())
|
||||||
@ -103,8 +102,8 @@ pub fn call_protected(
|
|||||||
_ => "unkown trapped signal",
|
_ => "unkown trapped signal",
|
||||||
};
|
};
|
||||||
|
|
||||||
Err(RuntimeError::Unknown {
|
Err(RuntimeError::Trap {
|
||||||
msg: format!("trap at {} - {}", exception_address, signal),
|
msg: format!("unknown trap at {} - {}", exception_address, signal).into(),
|
||||||
}
|
}
|
||||||
.into())
|
.into())
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "wasmer-emscripten"
|
name = "wasmer-emscripten"
|
||||||
version = "0.1.0"
|
version = "0.2.1"
|
||||||
description = "Wasmer runtime emscripten implementation library"
|
description = "Wasmer runtime emscripten implementation library"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
|
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
|
||||||
@ -9,9 +9,9 @@ edition = "2018"
|
|||||||
build = "build/mod.rs"
|
build = "build/mod.rs"
|
||||||
|
|
||||||
[dependencies]
|
[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"
|
lazy_static = "1.2.0"
|
||||||
libc = { git = "https://github.com/rust-lang/libc" }
|
libc = "0.2.49"
|
||||||
byteorder = "1"
|
byteorder = "1"
|
||||||
time = "0.1.41"
|
time = "0.1.41"
|
||||||
|
|
||||||
@ -19,7 +19,7 @@ time = "0.1.41"
|
|||||||
rand = "0.6"
|
rand = "0.6"
|
||||||
|
|
||||||
[dev-dependencies]
|
[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"
|
wabt = "0.7.2"
|
||||||
|
|
||||||
[build-dependencies]
|
[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),
|
"___syscall168" => func!(crate::syscalls::___syscall168),
|
||||||
"___syscall180" => func!(crate::syscalls::___syscall180),
|
"___syscall180" => func!(crate::syscalls::___syscall180),
|
||||||
"___syscall181" => func!(crate::syscalls::___syscall181),
|
"___syscall181" => func!(crate::syscalls::___syscall181),
|
||||||
|
"___syscall183" => func!(crate::syscalls::___syscall183),
|
||||||
"___syscall191" => func!(crate::syscalls::___syscall191),
|
"___syscall191" => func!(crate::syscalls::___syscall191),
|
||||||
"___syscall192" => func!(crate::syscalls::___syscall192),
|
"___syscall192" => func!(crate::syscalls::___syscall192),
|
||||||
"___syscall194" => func!(crate::syscalls::___syscall194),
|
"___syscall194" => func!(crate::syscalls::___syscall194),
|
||||||
|
@ -46,8 +46,13 @@ use std::slice;
|
|||||||
// Another conditional constant for name resolution: Macos et iOS use
|
// Another conditional constant for name resolution: Macos et iOS use
|
||||||
// SO_NOSIGPIPE as a setsockopt flag to disable SIGPIPE emission on socket.
|
// SO_NOSIGPIPE as a setsockopt flag to disable SIGPIPE emission on socket.
|
||||||
// Other platforms do otherwise.
|
// 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")]
|
#[cfg(target_os = "darwin")]
|
||||||
use libc::SO_NOSIGPIPE;
|
use libc::SO_NOSIGPIPE;
|
||||||
|
use std::ffi::CString;
|
||||||
|
|
||||||
#[cfg(not(target_os = "darwin"))]
|
#[cfg(not(target_os = "darwin"))]
|
||||||
const SO_NOSIGPIPE: c_int = 0;
|
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);
|
debug!("emscripten::___syscall3 (read) {}", which);
|
||||||
let fd: i32 = varargs.get(ctx);
|
let fd: i32 = varargs.get(ctx);
|
||||||
let buf: u32 = 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);
|
debug!("=> fd: {}, buf_offset: {}, count: {}", fd, buf, count);
|
||||||
let buf_addr = emscripten_memory_pointer!(ctx.memory(0), buf) as *mut c_void;
|
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);
|
debug!("=> ret: {}", ret);
|
||||||
ret as _
|
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);
|
debug!("emscripten::___syscall4 (write) {}", which);
|
||||||
let fd: i32 = varargs.get(ctx);
|
let fd: i32 = varargs.get(ctx);
|
||||||
let buf: u32 = 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);
|
debug!("=> fd: {}, buf: {}, count: {}", fd, buf, count);
|
||||||
let buf_addr = emscripten_memory_pointer!(ctx.memory(0), buf) as *const c_void;
|
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
|
/// close
|
||||||
@ -186,6 +191,25 @@ pub fn ___syscall110(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
|
|||||||
-1
|
-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
|
// mmap2
|
||||||
pub fn ___syscall192(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int {
|
pub fn ___syscall192(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int {
|
||||||
debug!("emscripten::___syscall192 (mmap2) {}", which);
|
debug!("emscripten::___syscall192 (mmap2) {}", which);
|
||||||
@ -217,10 +241,10 @@ pub fn ___syscall140(ctx: &mut Ctx, which: i32, mut varargs: VarArgs) -> i32 {
|
|||||||
// -> c_int
|
// -> c_int
|
||||||
debug!("emscripten::___syscall140 (lseek) {}", which);
|
debug!("emscripten::___syscall140 (lseek) {}", which);
|
||||||
let fd: i32 = varargs.get(ctx);
|
let fd: i32 = varargs.get(ctx);
|
||||||
let offset = varargs.get(ctx);
|
let offset: i32 = varargs.get(ctx);
|
||||||
let whence: i32 = varargs.get(ctx);
|
let whence: i32 = varargs.get(ctx);
|
||||||
debug!("=> fd: {}, offset: {}, whence = {}", fd, offset, whence);
|
debug!("=> fd: {}, offset: {}, whence = {}", fd, offset, whence);
|
||||||
unsafe { lseek(fd, offset, whence) as _ }
|
unsafe { lseek(fd, offset as _, whence) as _ }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// readv
|
/// readv
|
||||||
|
@ -54,6 +54,7 @@ mod test_funcptrfunc;
|
|||||||
mod test_funcs;
|
mod test_funcs;
|
||||||
mod test_functionpointer_libfunc_varargs;
|
mod test_functionpointer_libfunc_varargs;
|
||||||
mod test_fwrite_0;
|
mod test_fwrite_0;
|
||||||
|
mod test_getcwd;
|
||||||
mod test_getgep;
|
mod test_getgep;
|
||||||
mod test_getloadavg;
|
mod test_getloadavg;
|
||||||
mod test_getopt;
|
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]
|
[package]
|
||||||
name = "wasmer-runtime-c-api"
|
name = "wasmer-runtime-c-api"
|
||||||
version = "0.1.4"
|
version = "0.2.1"
|
||||||
description = "Wasmer c-api library"
|
description = "Wasmer c-api library"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
|
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
|
||||||
@ -9,8 +9,8 @@ edition = "2018"
|
|||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
wasmer-runtime = { path = "../runtime", version = "0.1.2" }
|
wasmer-runtime = { path = "../runtime", version = "0.2.1" }
|
||||||
wasmer-runtime-core = { path = "../runtime-core", version = "0.1.2" }
|
wasmer-runtime-core = { path = "../runtime-core", version = "0.2.1" }
|
||||||
libc = "0.2"
|
libc = "0.2"
|
||||||
|
|
||||||
[lib]
|
[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::{Ctx, Global, ImportObject, Instance, Memory, Module, Table, Value};
|
||||||
use wasmer_runtime_core::export::{Context, Export, FuncPointer};
|
use wasmer_runtime_core::export::{Context, Export, FuncPointer};
|
||||||
use wasmer_runtime_core::import::Namespace;
|
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::types::{ElementType, FuncSig, MemoryDescriptor, TableDescriptor, Type};
|
||||||
use wasmer_runtime_core::units::{Bytes, Pages};
|
use wasmer_runtime_core::units::{Bytes, Pages};
|
||||||
|
|
||||||
#[allow(non_camel_case_types)]
|
|
||||||
pub struct wasmer_import_object_t();
|
|
||||||
|
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
pub struct wasmer_module_t();
|
pub struct wasmer_module_t();
|
||||||
|
|
||||||
@ -78,7 +76,11 @@ pub struct wasmer_table_t();
|
|||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Clone)]
|
#[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)]
|
#[repr(C)]
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@ -96,14 +98,6 @@ pub struct wasmer_limit_option_t {
|
|||||||
pub some: uint32_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)]
|
#[repr(C)]
|
||||||
pub struct wasmer_import_t {
|
pub struct wasmer_import_t {
|
||||||
module_name: wasmer_byte_array,
|
module_name: wasmer_byte_array,
|
||||||
@ -112,6 +106,14 @@ pub struct wasmer_import_t {
|
|||||||
value: wasmer_import_export_value,
|
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)]
|
#[repr(C)]
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct wasmer_export_t;
|
pub struct wasmer_export_t;
|
||||||
@ -120,6 +122,14 @@ pub struct wasmer_export_t;
|
|||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct wasmer_exports_t;
|
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)]
|
#[repr(u32)]
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub enum wasmer_import_export_kind {
|
pub enum wasmer_import_export_kind {
|
||||||
@ -132,7 +142,7 @@ pub enum wasmer_import_export_kind {
|
|||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub union wasmer_import_export_value {
|
pub union wasmer_import_export_value {
|
||||||
func: *const wasmer_func_t,
|
func: *const wasmer_import_func_t,
|
||||||
table: *const wasmer_table_t,
|
table: *const wasmer_table_t,
|
||||||
memory: *const wasmer_memory_t,
|
memory: *const wasmer_memory_t,
|
||||||
global: *const wasmer_global_t,
|
global: *const wasmer_global_t,
|
||||||
@ -208,14 +218,13 @@ pub extern "C" fn wasmer_memory_grow(
|
|||||||
delta: uint32_t,
|
delta: uint32_t,
|
||||||
) -> wasmer_result_t {
|
) -> wasmer_result_t {
|
||||||
let memory = unsafe { &*(memory as *mut Memory) };
|
let memory = unsafe { &*(memory as *mut Memory) };
|
||||||
let maybe_delta = memory.grow(Pages(delta));
|
let delta_result = memory.grow(Pages(delta));
|
||||||
if let Some(_delta) = maybe_delta {
|
match delta_result {
|
||||||
wasmer_result_t::WASMER_OK
|
Ok(_) => wasmer_result_t::WASMER_OK,
|
||||||
} else {
|
Err(grow_error) => {
|
||||||
update_last_error(CApiError {
|
update_last_error(grow_error);
|
||||||
msg: "unable to grow memory".to_string(),
|
wasmer_result_t::WASMER_ERROR
|
||||||
});
|
}
|
||||||
wasmer_result_t::WASMER_ERROR
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -277,14 +286,13 @@ pub extern "C" fn wasmer_table_grow(
|
|||||||
delta: uint32_t,
|
delta: uint32_t,
|
||||||
) -> wasmer_result_t {
|
) -> wasmer_result_t {
|
||||||
let table = unsafe { &*(table as *mut Table) };
|
let table = unsafe { &*(table as *mut Table) };
|
||||||
let maybe_delta = table.grow(delta);
|
let delta_result = table.grow(delta);
|
||||||
if let Some(_delta) = maybe_delta {
|
match delta_result {
|
||||||
wasmer_result_t::WASMER_OK
|
Ok(_) => wasmer_result_t::WASMER_OK,
|
||||||
} else {
|
Err(grow_error) => {
|
||||||
update_last_error(CApiError {
|
update_last_error(grow_error);
|
||||||
msg: "unable to grow table".to_string(),
|
wasmer_result_t::WASMER_ERROR
|
||||||
});
|
}
|
||||||
wasmer_result_t::WASMER_ERROR
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -446,12 +454,24 @@ pub unsafe extern "C" fn wasmer_module_instantiate(
|
|||||||
.or_insert_with(|| Namespace::new());
|
.or_insert_with(|| Namespace::new());
|
||||||
|
|
||||||
let export = match import.tag {
|
let export = match import.tag {
|
||||||
wasmer_import_export_kind::WASM_MEMORY => import.value.memory as *mut Export,
|
wasmer_import_export_kind::WASM_MEMORY => {
|
||||||
wasmer_import_export_kind::WASM_FUNCTION => import.value.func as *mut Export,
|
let mem = import.value.memory as *mut Memory;
|
||||||
wasmer_import_export_kind::WASM_GLOBAL => import.value.global as *mut Export,
|
Export::Memory((&*mem).clone())
|
||||||
wasmer_import_export_kind::WASM_TABLE => import.value.table as *mut Export,
|
}
|
||||||
|
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() {
|
for (module_name, namespace) in namespaces.into_iter() {
|
||||||
import_object.register(module_name, namespace);
|
import_object.register(module_name, namespace);
|
||||||
@ -470,6 +490,91 @@ pub unsafe extern "C" fn wasmer_module_instantiate(
|
|||||||
wasmer_result_t::WASMER_OK
|
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
|
/// Frees memory for the given Module
|
||||||
#[allow(clippy::cast_ptr_alignment)]
|
#[allow(clippy::cast_ptr_alignment)]
|
||||||
#[no_mangle]
|
#[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.
|
/// Creates a new Instance from the given wasm bytes and imports.
|
||||||
///
|
///
|
||||||
/// Returns `wasmer_result_t::WASMER_OK` upon success.
|
/// Returns `wasmer_result_t::WASMER_OK` upon success.
|
||||||
@ -534,12 +818,24 @@ pub unsafe extern "C" fn wasmer_instantiate(
|
|||||||
.or_insert_with(|| Namespace::new());
|
.or_insert_with(|| Namespace::new());
|
||||||
|
|
||||||
let export = match import.tag {
|
let export = match import.tag {
|
||||||
wasmer_import_export_kind::WASM_MEMORY => import.value.memory as *mut Export,
|
wasmer_import_export_kind::WASM_MEMORY => {
|
||||||
wasmer_import_export_kind::WASM_FUNCTION => import.value.func as *mut Export,
|
let mem = import.value.memory as *mut Memory;
|
||||||
wasmer_import_export_kind::WASM_GLOBAL => import.value.global as *mut Export,
|
Export::Memory((&*mem).clone())
|
||||||
wasmer_import_export_kind::WASM_TABLE => import.value.table as *mut Export,
|
}
|
||||||
|
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() {
|
for (module_name, namespace) in namespaces.into_iter() {
|
||||||
import_object.register(module_name, namespace);
|
import_object.register(module_name, namespace);
|
||||||
@ -649,9 +945,16 @@ pub unsafe extern "C" fn wasmer_instance_exports(
|
|||||||
instance: *mut wasmer_instance_t,
|
instance: *mut wasmer_instance_t,
|
||||||
exports: *mut *mut wasmer_exports_t,
|
exports: *mut *mut wasmer_exports_t,
|
||||||
) {
|
) {
|
||||||
let mut instance = unsafe { &mut *(instance as *mut Instance) };
|
let mut instance_ref = unsafe { &mut *(instance as *mut Instance) };
|
||||||
let named_exports: Box<NamedExports> =
|
let mut exports_vec: Vec<NamedExport> = Vec::with_capacity(instance_ref.exports().count());
|
||||||
Box::new(NamedExports(instance.exports().map(|e| e.into()).collect()));
|
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 };
|
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]
|
#[no_mangle]
|
||||||
#[allow(clippy::cast_ptr_alignment)]
|
#[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),
|
func: extern "C" fn(data: *mut c_void),
|
||||||
params: *const wasmer_value_tag,
|
params: *const wasmer_value_tag,
|
||||||
params_len: c_int,
|
params_len: c_int,
|
||||||
returns: *const wasmer_value_tag,
|
returns: *const wasmer_value_tag,
|
||||||
returns_len: c_int,
|
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: &[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 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);
|
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,
|
ctx: Context::Internal,
|
||||||
signature: Arc::new(FuncSig::new(params, returns)),
|
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.
|
/// 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.
|
/// and `wasmer_last_error_message` to get an error message.
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
#[allow(clippy::cast_ptr_alignment)]
|
#[allow(clippy::cast_ptr_alignment)]
|
||||||
pub unsafe extern "C" fn wasmer_func_params_arity(
|
pub unsafe extern "C" fn wasmer_import_func_params(
|
||||||
func: *mut wasmer_func_t,
|
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_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,
|
|
||||||
params: *mut wasmer_value_tag,
|
params: *mut wasmer_value_tag,
|
||||||
params_len: c_int,
|
params_len: c_int,
|
||||||
) -> wasmer_result_t {
|
) -> wasmer_result_t {
|
||||||
@ -779,14 +1196,14 @@ pub unsafe extern "C" fn wasmer_func_params(
|
|||||||
wasmer_result_t::WASMER_OK
|
wasmer_result_t::WASMER_OK
|
||||||
} else {
|
} else {
|
||||||
update_last_error(CApiError {
|
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
|
wasmer_result_t::WASMER_ERROR
|
||||||
};
|
};
|
||||||
result
|
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.
|
/// 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.
|
/// and `wasmer_last_error_message` to get an error message.
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
#[allow(clippy::cast_ptr_alignment)]
|
#[allow(clippy::cast_ptr_alignment)]
|
||||||
pub unsafe extern "C" fn wasmer_func_returns(
|
pub unsafe extern "C" fn wasmer_import_func_returns(
|
||||||
func: *mut wasmer_func_t,
|
func: *mut wasmer_import_func_t,
|
||||||
returns: *mut wasmer_value_tag,
|
returns: *mut wasmer_value_tag,
|
||||||
returns_len: c_int,
|
returns_len: c_int,
|
||||||
) -> wasmer_result_t {
|
) -> wasmer_result_t {
|
||||||
@ -809,14 +1226,14 @@ pub unsafe extern "C" fn wasmer_func_returns(
|
|||||||
wasmer_result_t::WASMER_OK
|
wasmer_result_t::WASMER_OK
|
||||||
} else {
|
} else {
|
||||||
update_last_error(CApiError {
|
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
|
wasmer_result_t::WASMER_ERROR
|
||||||
};
|
};
|
||||||
result
|
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.
|
/// 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.
|
/// and `wasmer_last_error_message` to get an error message.
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
#[allow(clippy::cast_ptr_alignment)]
|
#[allow(clippy::cast_ptr_alignment)]
|
||||||
pub unsafe extern "C" fn wasmer_func_returns_arity(
|
pub unsafe extern "C" fn wasmer_import_func_returns_arity(
|
||||||
func: *mut wasmer_func_t,
|
func: *mut wasmer_import_func_t,
|
||||||
result: *mut uint32_t,
|
result: *mut uint32_t,
|
||||||
) -> wasmer_result_t {
|
) -> wasmer_result_t {
|
||||||
let mut export = unsafe { &*(func as *mut Export) };
|
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
|
wasmer_result_t::WASMER_OK
|
||||||
} else {
|
} else {
|
||||||
update_last_error(CApiError {
|
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
|
wasmer_result_t::WASMER_ERROR
|
||||||
};
|
};
|
||||||
@ -844,20 +1261,19 @@ pub unsafe extern "C" fn wasmer_func_returns_arity(
|
|||||||
/// Frees memory for the given Func
|
/// Frees memory for the given Func
|
||||||
#[allow(clippy::cast_ptr_alignment)]
|
#[allow(clippy::cast_ptr_alignment)]
|
||||||
#[no_mangle]
|
#[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() {
|
if !func.is_null() {
|
||||||
drop(unsafe { Box::from_raw(func as *mut Export) });
|
drop(unsafe { Box::from_raw(func as *mut Export) });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets func from wasm_export
|
/// Gets export func from export
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
#[allow(clippy::cast_ptr_alignment)]
|
#[allow(clippy::cast_ptr_alignment)]
|
||||||
pub unsafe extern "C" fn wasmer_export_to_func(
|
pub unsafe extern "C" fn wasmer_export_to_func(
|
||||||
export: *mut wasmer_export_t,
|
export: *mut wasmer_export_t,
|
||||||
) -> *const wasmer_func_t {
|
) -> *const wasmer_export_func_t {
|
||||||
let named_export = &*(export as *mut NamedExport);
|
export as *const wasmer_export_func_t
|
||||||
&named_export.export as *const Export as *const wasmer_func_t
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets name from wasmer_export
|
/// 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.
|
/// and `wasmer_last_error_message` to get an error message.
|
||||||
#[allow(clippy::cast_ptr_alignment)]
|
#[allow(clippy::cast_ptr_alignment)]
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn wasmer_func_call(
|
pub unsafe extern "C" fn wasmer_export_func_call(
|
||||||
func: *mut wasmer_func_t,
|
func: *mut wasmer_export_func_t,
|
||||||
params: *const wasmer_value_t,
|
params: *const wasmer_value_t,
|
||||||
params_len: c_int,
|
params_len: c_int,
|
||||||
results: *mut wasmer_value_t,
|
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: &[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 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);
|
let results: &mut [wasmer_value_t] = slice::from_raw_parts_mut(results, results_len as usize);
|
||||||
// TODO implement func.call
|
|
||||||
update_last_error(CApiError {
|
let instance = &*named_export.instance;
|
||||||
msg: "wasmer_func_call not yet implemented".to_string(),
|
let result = instance.call(&named_export.name, ¶ms[..]);
|
||||||
});
|
match result {
|
||||||
wasmer_result_t::WASMER_ERROR
|
Ok(results_vec) => {
|
||||||
// let result = instance.call(func_name_r, ¶ms[..]);
|
if results_vec.len() > 0 {
|
||||||
// Box::into_raw(export_func);
|
let ret = match results_vec[0] {
|
||||||
// match result {
|
Value::I32(x) => wasmer_value_t {
|
||||||
// Ok(results_vec) => {
|
tag: wasmer_value_tag::WASM_I32,
|
||||||
// if results_vec.len() > 0 {
|
value: wasmer_value { I32: x },
|
||||||
// let ret = match results_vec[0] {
|
},
|
||||||
// Value::I32(x) => wasmer_value_t {
|
Value::I64(x) => wasmer_value_t {
|
||||||
// tag: wasmer_value_tag::WASM_I32,
|
tag: wasmer_value_tag::WASM_I64,
|
||||||
// value: wasmer_value { I32: x },
|
value: wasmer_value { I64: x },
|
||||||
// },
|
},
|
||||||
// Value::I64(x) => wasmer_value_t {
|
Value::F32(x) => wasmer_value_t {
|
||||||
// tag: wasmer_value_tag::WASM_I64,
|
tag: wasmer_value_tag::WASM_F32,
|
||||||
// value: wasmer_value { I64: x },
|
value: wasmer_value { F32: x },
|
||||||
// },
|
},
|
||||||
// Value::F32(x) => wasmer_value_t {
|
Value::F64(x) => wasmer_value_t {
|
||||||
// tag: wasmer_value_tag::WASM_F32,
|
tag: wasmer_value_tag::WASM_F64,
|
||||||
// value: wasmer_value { F32: x },
|
value: wasmer_value { F64: x },
|
||||||
// },
|
},
|
||||||
// Value::F64(x) => wasmer_value_t {
|
};
|
||||||
// tag: wasmer_value_tag::WASM_F64,
|
results[0] = ret;
|
||||||
// value: wasmer_value { F64: x },
|
}
|
||||||
// },
|
wasmer_result_t::WASMER_OK
|
||||||
// };
|
}
|
||||||
// results[0] = ret;
|
Err(err) => {
|
||||||
// }
|
update_last_error(err);
|
||||||
// wasmer_result_t::WASMER_OK
|
wasmer_result_t::WASMER_ERROR
|
||||||
// }
|
}
|
||||||
// Err(err) => {
|
}
|
||||||
// update_last_error(err);
|
|
||||||
// wasmer_result_t::WASMER_ERROR
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the memory within the context at the index `memory_idx`.
|
/// 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 {
|
impl From<&wasmer_runtime::wasm::Type> for wasmer_value_tag {
|
||||||
fn from(ty: &Type) -> Self {
|
fn from(ty: &Type) -> Self {
|
||||||
match *ty {
|
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
|
// Error reporting
|
||||||
|
|
||||||
thread_local! {
|
thread_local! {
|
||||||
@ -1171,7 +1592,19 @@ impl fmt::Display for CApiError {
|
|||||||
|
|
||||||
impl Error for CApiError {}
|
impl Error for CApiError {}
|
||||||
|
|
||||||
|
struct NamedImportDescriptor {
|
||||||
|
module: String,
|
||||||
|
name: String,
|
||||||
|
kind: wasmer_import_export_kind,
|
||||||
|
}
|
||||||
|
|
||||||
struct NamedExport {
|
struct NamedExport {
|
||||||
name: String,
|
name: String,
|
||||||
export: Export,
|
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-globals
|
||||||
test-exports
|
test-exports
|
||||||
test-instantiate
|
test-instantiate
|
||||||
|
test-imports
|
||||||
test-import-function
|
test-import-function
|
||||||
test-memory
|
test-memory
|
||||||
|
test-module-imports
|
||||||
test-module
|
test-module
|
||||||
|
test-module-exports
|
||||||
test-tables
|
test-tables
|
||||||
test-validate
|
test-validate
|
||||||
rust-build
|
rust-build
|
@ -1,12 +1,15 @@
|
|||||||
cmake_minimum_required (VERSION 2.6)
|
cmake_minimum_required (VERSION 2.6)
|
||||||
project (WasmerCApiTests)
|
project (WasmerCApiTests)
|
||||||
|
|
||||||
|
add_executable(test-imports test-imports.c)
|
||||||
add_executable(test-exports test-exports.c)
|
add_executable(test-exports test-exports.c)
|
||||||
add_executable(test-globals test-globals.c)
|
add_executable(test-globals test-globals.c)
|
||||||
add_executable(test-instantiate test-instantiate.c)
|
add_executable(test-instantiate test-instantiate.c)
|
||||||
add_executable(test-import-function test-import-function.c)
|
add_executable(test-import-function test-import-function.c)
|
||||||
add_executable(test-memory test-memory.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 test-module.c)
|
||||||
|
add_executable(test-module-exports test-module-exports.c)
|
||||||
add_executable(test-validate test-validate.c)
|
add_executable(test-validate test-validate.c)
|
||||||
add_executable(test-tables test-tables.c)
|
add_executable(test-tables test-tables.c)
|
||||||
|
|
||||||
@ -19,6 +22,8 @@ if(NOT WASMER_LIB)
|
|||||||
message(FATAL_ERROR "wasmer library not found")
|
message(FATAL_ERROR "wasmer library not found")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
target_link_libraries(test-imports
|
||||||
|
general ${WASMER_LIB})
|
||||||
target_link_libraries(test-exports
|
target_link_libraries(test-exports
|
||||||
general ${WASMER_LIB})
|
general ${WASMER_LIB})
|
||||||
target_link_libraries(test-globals
|
target_link_libraries(test-globals
|
||||||
@ -29,20 +34,27 @@ target_link_libraries(test-import-function
|
|||||||
general ${WASMER_LIB})
|
general ${WASMER_LIB})
|
||||||
target_link_libraries(test-memory
|
target_link_libraries(test-memory
|
||||||
general ${WASMER_LIB})
|
general ${WASMER_LIB})
|
||||||
|
target_link_libraries(test-module-imports
|
||||||
|
general ${WASMER_LIB})
|
||||||
target_link_libraries(test-module
|
target_link_libraries(test-module
|
||||||
general ${WASMER_LIB})
|
general ${WASMER_LIB})
|
||||||
|
target_link_libraries(test-module-exports
|
||||||
|
general ${WASMER_LIB})
|
||||||
target_link_libraries(test-validate
|
target_link_libraries(test-validate
|
||||||
general ${WASMER_LIB})
|
general ${WASMER_LIB})
|
||||||
target_link_libraries(test-tables
|
target_link_libraries(test-tables
|
||||||
general ${WASMER_LIB})
|
general ${WASMER_LIB})
|
||||||
|
|
||||||
enable_testing()
|
enable_testing()
|
||||||
|
add_test(test-imports test-imports)
|
||||||
add_test(test-exports test-exports)
|
add_test(test-exports test-exports)
|
||||||
add_test(test-globals test-globals)
|
add_test(test-globals test-globals)
|
||||||
add_test(test-instantiate test-instantiate)
|
add_test(test-instantiate test-instantiate)
|
||||||
add_test(test-import-function test-import-function)
|
add_test(test-import-function test-import-function)
|
||||||
add_test(test-memory test-memory)
|
add_test(test-memory test-memory)
|
||||||
|
add_test(test-module-imports test-module-imports)
|
||||||
add_test(test-module test-module)
|
add_test(test-module test-module)
|
||||||
|
add_test(test-module-exports test-module-exports)
|
||||||
add_test(test-validate test-validate)
|
add_test(test-validate test-validate)
|
||||||
add_test(test-tables test-tables)
|
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);
|
wasmer_import_export_kind kind = wasmer_export_kind(export);
|
||||||
assert(kind == WASM_FUNCTION);
|
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);
|
wasmer_byte_array name_bytes = wasmer_export_name(export);
|
||||||
assert(name_bytes.bytes_len == 3);
|
assert(name_bytes.bytes_len == 3);
|
||||||
@ -42,40 +42,40 @@ int main()
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint32_t params_arity;
|
uint32_t params_arity;
|
||||||
wasmer_func_params_arity(func, ¶ms_arity);
|
wasmer_export_func_params_arity(func, ¶ms_arity);
|
||||||
assert(params_arity == 2);
|
assert(params_arity == 2);
|
||||||
|
|
||||||
wasmer_value_tag *params_sig = malloc(sizeof(wasmer_value_tag) * params_arity);
|
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[0] == WASM_I32);
|
||||||
assert(params_sig[1] == WASM_I32);
|
assert(params_sig[1] == WASM_I32);
|
||||||
free(params_sig);
|
free(params_sig);
|
||||||
|
|
||||||
uint32_t returns_arity;
|
uint32_t returns_arity;
|
||||||
wasmer_func_returns_arity(func, &returns_arity);
|
wasmer_export_func_returns_arity(func, &returns_arity);
|
||||||
assert(returns_arity == 1);
|
assert(returns_arity == 1);
|
||||||
|
|
||||||
wasmer_value_tag *returns_sig = malloc(sizeof(wasmer_value_tag) * returns_arity);
|
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);
|
assert(returns_sig[0] == WASM_I32);
|
||||||
free(returns_sig);
|
free(returns_sig);
|
||||||
|
|
||||||
|
|
||||||
// wasmer_value_t param_one;
|
wasmer_value_t param_one;
|
||||||
// param_one.tag = WASM_I32;
|
param_one.tag = WASM_I32;
|
||||||
// param_one.value.I32 = 7;
|
param_one.value.I32 = 7;
|
||||||
// wasmer_value_t param_two;
|
wasmer_value_t param_two;
|
||||||
// param_two.tag = WASM_I32;
|
param_two.tag = WASM_I32;
|
||||||
// param_two.value.I32 = 8;
|
param_two.value.I32 = 8;
|
||||||
// wasmer_value_t params[] = {param_one, param_two};
|
wasmer_value_t params[] = {param_one, param_two};
|
||||||
// wasmer_value_t result_one;
|
wasmer_value_t result_one;
|
||||||
// wasmer_value_t results[] = {result_one};
|
wasmer_value_t results[] = {result_one};
|
||||||
//
|
|
||||||
// wasmer_result_t call_result = wasmer_func_call(func, params, 2, results, 1);
|
wasmer_result_t call_result = wasmer_export_func_call(func, params, 2, results, 1);
|
||||||
// printf("Call result: %d\n", call_result);
|
printf("Call result: %d\n", call_result);
|
||||||
// printf("Result: %d\n", results[0].value.I32);
|
printf("Result: %d\n", results[0].value.I32);
|
||||||
// assert(results[0].value.I32 == 15);
|
assert(results[0].value.I32 == 15);
|
||||||
// assert(call_result == WASMER_OK);
|
assert(call_result == WASMER_OK);
|
||||||
|
|
||||||
|
|
||||||
printf("Destroy instance\n");
|
printf("Destroy instance\n");
|
||||||
|
@ -31,7 +31,7 @@ int main()
|
|||||||
wasmer_value_tag returns_sig[] = {};
|
wasmer_value_tag returns_sig[] = {};
|
||||||
|
|
||||||
printf("Creating new func\n");
|
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;
|
wasmer_import_t import;
|
||||||
|
|
||||||
char *module_name = "env";
|
char *module_name = "env";
|
||||||
@ -84,7 +84,7 @@ int main()
|
|||||||
assert(0 == strcmp(actual_str, "Hello, World!"));
|
assert(0 == strcmp(actual_str, "Hello, World!"));
|
||||||
|
|
||||||
printf("Destroying func\n");
|
printf("Destroying func\n");
|
||||||
wasmer_func_destroy(func);
|
wasmer_import_func_destroy(func);
|
||||||
printf("Destroy instance\n");
|
printf("Destroy instance\n");
|
||||||
wasmer_instance_destroy(instance);
|
wasmer_instance_destroy(instance);
|
||||||
return 0;
|
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);
|
wasmer_result_t grow_result = wasmer_memory_grow(memory, 2);
|
||||||
assert(grow_result == WASMER_OK);
|
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);
|
printf("Memory pages length: %d\n", new_len);
|
||||||
assert(new_len == 12);
|
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);
|
printf("Memory bytes length: %d\n", bytes_len);
|
||||||
assert(bytes_len == 12 * 65536);
|
assert(bytes_len == 12 * 65536);
|
||||||
|
|
||||||
// Err, grow beyond max
|
// Err, grow beyond max
|
||||||
wasmer_result_t grow_result2 = wasmer_memory_grow(memory, 10);
|
wasmer_result_t grow_result2 = wasmer_memory_grow(memory, 10);
|
||||||
@ -38,23 +38,26 @@ int main()
|
|||||||
char *error_str = malloc(error_len);
|
char *error_str = malloc(error_len);
|
||||||
wasmer_last_error_message(error_str, error_len);
|
wasmer_last_error_message(error_str, error_len);
|
||||||
printf("Error str: `%s`\n", error_str);
|
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);
|
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;
|
int error_len2 = wasmer_last_error_length();
|
||||||
// wasmer_limits_t bad_descriptor;
|
char *error_str2 = malloc(error_len2);
|
||||||
// bad_descriptor.min = 15;
|
wasmer_last_error_message(error_str2, error_len2);
|
||||||
// bad_descriptor.max = 10;
|
printf("Error str 2: `%s`\n", error_str2);
|
||||||
// wasmer_result_t bad_memory_result = wasmer_memory_new(&bad_memory, bad_descriptor);
|
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\""));
|
||||||
// printf("Bad memory result: %d\n", bad_memory_result);
|
free(error_str2);
|
||||||
// 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);
|
|
||||||
|
|
||||||
printf("Destroy memory\n");
|
printf("Destroy memory\n");
|
||||||
wasmer_memory_destroy(memory);
|
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;
|
wasmer_limits_t descriptor;
|
||||||
descriptor.min = 10;
|
descriptor.min = 10;
|
||||||
wasmer_limit_option_t max;
|
wasmer_limit_option_t max;
|
||||||
// max.has_some = false;
|
// max.has_some = false;
|
||||||
max.has_some = true;
|
max.has_some = true;
|
||||||
max.some = 15;
|
max.some = 15;
|
||||||
descriptor.max = max;
|
descriptor.max = max;
|
||||||
@ -21,26 +21,29 @@ int main()
|
|||||||
printf("Table length: %d\n", len);
|
printf("Table length: %d\n", len);
|
||||||
assert(len == 10);
|
assert(len == 10);
|
||||||
|
|
||||||
// wasmer_result_t grow_result1 = wasmer_table_grow(table, 5);
|
wasmer_result_t grow_result1 = wasmer_table_grow(table, 5);
|
||||||
// assert(grow_result1 == WASMER_OK);
|
assert(grow_result1 == WASMER_OK);
|
||||||
// uint32_t len_grow1 = wasmer_table_length(table);
|
uint32_t len_grow1 = wasmer_table_length(table);
|
||||||
// printf("Table length: %d\n", len_grow1);
|
printf("Table length: %d\n", len_grow1);
|
||||||
// assert(len_grow1 == 15);
|
assert(len_grow1 == 15);
|
||||||
|
|
||||||
// // Try to grow beyond max
|
// Try to grow beyond max
|
||||||
// wasmer_result_t grow_result2 = wasmer_table_grow(&table, 1);
|
wasmer_result_t grow_result2 = wasmer_table_grow(table, 1);
|
||||||
// assert(grow_result2 == WASMER_ERROR);
|
assert(grow_result2 == WASMER_ERROR);
|
||||||
// uint32_t len_grow2 = wasmer_table_length(table);
|
uint32_t len_grow2 = wasmer_table_length(table);
|
||||||
// printf("Table length: %d\n", len_grow2);
|
printf("Table length: %d\n", len_grow2);
|
||||||
// assert(len_grow2 == 15);
|
assert(len_grow2 == 15);
|
||||||
|
|
||||||
// wasmer_table_t *table_bad = NULL;
|
wasmer_table_t *table_bad = NULL;
|
||||||
// wasmer_limits_t bad_descriptor;
|
wasmer_limits_t bad_descriptor;
|
||||||
// bad_descriptor.min = 15;
|
bad_descriptor.min = 15;
|
||||||
// bad_descriptor.max = 10;
|
wasmer_limit_option_t max2;
|
||||||
// wasmer_result_t table_bad_result = wasmer_table_new(&table_bad, bad_descriptor);
|
max2.has_some = true;
|
||||||
// printf("Table result: %d\n", table_bad_result);
|
max2.some = 10;
|
||||||
// assert(table_result == WASMER_ERROR);
|
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");
|
printf("Destroy table\n");
|
||||||
wasmer_table_destroy(table);
|
wasmer_table_destroy(table);
|
||||||
|
@ -35,7 +35,7 @@ typedef struct wasmer_module_t wasmer_module_t;
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
||||||
} wasmer_export_t;
|
} wasmer_export_descriptor_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
const uint8_t *bytes;
|
const uint8_t *bytes;
|
||||||
@ -44,11 +44,11 @@ typedef struct {
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
||||||
} wasmer_func_t;
|
} wasmer_export_descriptors_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
||||||
} wasmer_exports_t;
|
} wasmer_export_func_t;
|
||||||
|
|
||||||
typedef union {
|
typedef union {
|
||||||
int32_t I32;
|
int32_t I32;
|
||||||
@ -64,6 +64,14 @@ typedef struct {
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
||||||
|
} wasmer_export_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
|
||||||
|
} wasmer_exports_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
|
||||||
} wasmer_global_t;
|
} wasmer_global_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -73,6 +81,18 @@ typedef struct {
|
|||||||
|
|
||||||
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;
|
} wasmer_memory_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -80,7 +100,7 @@ typedef struct {
|
|||||||
} wasmer_table_t;
|
} wasmer_table_t;
|
||||||
|
|
||||||
typedef union {
|
typedef union {
|
||||||
const wasmer_func_t *func;
|
const wasmer_import_func_t *func;
|
||||||
const wasmer_table_t *table;
|
const wasmer_table_t *table;
|
||||||
const wasmer_memory_t *memory;
|
const wasmer_memory_t *memory;
|
||||||
const wasmer_global_t *global;
|
const wasmer_global_t *global;
|
||||||
@ -113,6 +133,88 @@ wasmer_result_t wasmer_compile(wasmer_module_t **module,
|
|||||||
uint8_t *wasm_bytes,
|
uint8_t *wasm_bytes,
|
||||||
uint32_t wasm_bytes_len);
|
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
|
* 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_);
|
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
|
* 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);
|
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
|
* 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);
|
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.
|
* Calls an instances exported function by `name` with the provided parameters.
|
||||||
* Results are set using the provided `results` pointer.
|
* Results are set using the provided `results` pointer.
|
||||||
|
@ -30,7 +30,7 @@ struct wasmer_instance_t;
|
|||||||
|
|
||||||
struct wasmer_module_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;
|
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;
|
wasmer_value value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct wasmer_export_t {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
struct wasmer_exports_t {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
struct wasmer_global_t {
|
struct wasmer_global_t {
|
||||||
|
|
||||||
};
|
};
|
||||||
@ -68,6 +76,18 @@ struct wasmer_global_descriptor_t {
|
|||||||
wasmer_value_tag kind;
|
wasmer_value_tag kind;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct wasmer_import_descriptor_t {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
struct wasmer_import_descriptors_t {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
struct wasmer_import_func_t {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
struct wasmer_memory_t {
|
struct wasmer_memory_t {
|
||||||
|
|
||||||
};
|
};
|
||||||
@ -77,7 +97,7 @@ struct wasmer_table_t {
|
|||||||
};
|
};
|
||||||
|
|
||||||
union wasmer_import_export_value {
|
union wasmer_import_export_value {
|
||||||
const wasmer_func_t *func;
|
const wasmer_import_func_t *func;
|
||||||
const wasmer_table_t *table;
|
const wasmer_table_t *table;
|
||||||
const wasmer_memory_t *memory;
|
const wasmer_memory_t *memory;
|
||||||
const wasmer_global_t *global;
|
const wasmer_global_t *global;
|
||||||
@ -110,14 +130,74 @@ wasmer_result_t wasmer_compile(wasmer_module_t **module,
|
|||||||
uint8_t *wasm_bytes,
|
uint8_t *wasm_bytes,
|
||||||
uint32_t wasm_bytes_len);
|
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
|
/// Gets wasmer_export kind
|
||||||
wasmer_import_export_kind wasmer_export_kind(wasmer_export_t *export_);
|
wasmer_import_export_kind wasmer_export_kind(wasmer_export_t *export_);
|
||||||
|
|
||||||
/// Gets name from wasmer_export
|
/// Gets name from wasmer_export
|
||||||
wasmer_byte_array wasmer_export_name(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
|
/// Frees the memory for the given exports
|
||||||
void wasmer_exports_destroy(wasmer_exports_t *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
|
/// Gets the length of the exports
|
||||||
int wasmer_exports_len(wasmer_exports_t *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
|
/// Frees memory for the given Global
|
||||||
void wasmer_global_destroy(wasmer_global_t *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
|
/// Sets the value stored by the given Global
|
||||||
void wasmer_global_set(wasmer_global_t *global, wasmer_value_t value);
|
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.
|
/// Calls an instances exported function by `name` with the provided parameters.
|
||||||
/// Results are set using the provided `results` pointer.
|
/// Results are set using the provided `results` pointer.
|
||||||
/// Returns `wasmer_result_t::WASMER_OK` upon success.
|
/// Returns `wasmer_result_t::WASMER_OK` upon success.
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "wasmer-runtime-core"
|
name = "wasmer-runtime-core"
|
||||||
version = "0.1.2"
|
version = "0.2.1"
|
||||||
description = "Wasmer runtime core library"
|
description = "Wasmer runtime core library"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
|
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
|
||||||
@ -15,7 +15,7 @@ parking_lot = "0.7.1"
|
|||||||
lazy_static = "1.2.0"
|
lazy_static = "1.2.0"
|
||||||
indexmap = "1.0.2"
|
indexmap = "1.0.2"
|
||||||
errno = "0.2.4"
|
errno = "0.2.4"
|
||||||
libc = "0.2.48"
|
libc = "0.2.49"
|
||||||
hex = "0.3.2"
|
hex = "0.3.2"
|
||||||
|
|
||||||
# Dependencies for caching.
|
# Dependencies for caching.
|
||||||
@ -29,7 +29,9 @@ version = "1.0"
|
|||||||
version = "0.10"
|
version = "0.10"
|
||||||
[dependencies.serde-bench]
|
[dependencies.serde-bench]
|
||||||
version = "0.0.7"
|
version = "0.0.7"
|
||||||
[dependencies.sha2]
|
[dependencies.blake2b_simd]
|
||||||
|
version = "0.4.1"
|
||||||
|
[dependencies.digest]
|
||||||
version = "0.8.0"
|
version = "0.8.0"
|
||||||
[dependencies.hashbrown]
|
[dependencies.hashbrown]
|
||||||
version = "0.1"
|
version = "0.1"
|
||||||
@ -39,7 +41,6 @@ features = ["serde"]
|
|||||||
winapi = { version = "0.3", features = ["memoryapi"] }
|
winapi = { version = "0.3", features = ["memoryapi"] }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
wasmer-clif-backend = { path = "../clif-backend", version = "0.1.2" }
|
|
||||||
field-offset = "0.1.1"
|
field-offset = "0.1.1"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
|
@ -12,7 +12,7 @@ use crate::{
|
|||||||
module::ModuleInfo,
|
module::ModuleInfo,
|
||||||
sys::Memory,
|
sys::Memory,
|
||||||
};
|
};
|
||||||
use std::ptr::NonNull;
|
use std::{any::Any, ptr::NonNull};
|
||||||
|
|
||||||
pub mod sys {
|
pub mod sys {
|
||||||
pub use crate::sys::*;
|
pub use crate::sys::*;
|
||||||
@ -79,7 +79,7 @@ pub trait ProtectedCaller: Send + Sync {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub trait UserTrapper {
|
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 {
|
pub trait FuncResolver: Send + Sync {
|
||||||
|
@ -2,8 +2,8 @@ use crate::{
|
|||||||
module::{Module, ModuleInfo},
|
module::{Module, ModuleInfo},
|
||||||
sys::Memory,
|
sys::Memory,
|
||||||
};
|
};
|
||||||
use sha2::{Digest, Sha256};
|
use blake2b_simd::blake2bp;
|
||||||
use std::{io, mem, slice};
|
use std::{fmt, io, mem, slice};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum InvalidFileType {
|
pub enum InvalidFileType {
|
||||||
@ -33,7 +33,7 @@ impl From<io::Error> for Error {
|
|||||||
///
|
///
|
||||||
/// [`Cache`]: trait.Cache.html
|
/// [`Cache`]: trait.Cache.html
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||||
pub struct WasmHash([u8; 32]);
|
pub struct WasmHash([u8; 32], [u8; 32]);
|
||||||
|
|
||||||
impl WasmHash {
|
impl WasmHash {
|
||||||
/// Hash a wasm module.
|
/// Hash a wasm module.
|
||||||
@ -42,19 +42,31 @@ impl WasmHash {
|
|||||||
/// This does no verification that the supplied data
|
/// This does no verification that the supplied data
|
||||||
/// is, in fact, a wasm module.
|
/// is, in fact, a wasm module.
|
||||||
pub fn generate(wasm: &[u8]) -> Self {
|
pub fn generate(wasm: &[u8]) -> Self {
|
||||||
let mut array = [0u8; 32];
|
let mut first_part = [0u8; 32];
|
||||||
array.copy_from_slice(Sha256::digest(wasm).as_slice());
|
let mut second_part = [0u8; 32];
|
||||||
WasmHash(array)
|
|
||||||
|
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
|
/// Create the hexadecimal representation of the
|
||||||
/// stored hash.
|
/// stored hash.
|
||||||
pub fn encode(self) -> String {
|
pub fn encode(self) -> String {
|
||||||
hex::encode(self.0)
|
hex::encode(&self.into_array() as &[u8])
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn into_array(self) -> [u8; 32] {
|
pub(crate) fn into_array(self) -> [u8; 64] {
|
||||||
self.0
|
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.
|
/// The `wasmer-runtime` supplies a naive `FileSystemCache` api.
|
||||||
pub trait Cache {
|
pub trait Cache {
|
||||||
type LoadError;
|
type LoadError: fmt::Debug;
|
||||||
type StoreError;
|
type StoreError: fmt::Debug;
|
||||||
|
|
||||||
fn load(&self, key: WasmHash) -> Result<Module, Self::LoadError>;
|
fn load(&self, key: WasmHash) -> Result<Module, Self::LoadError>;
|
||||||
fn store(&mut self, key: WasmHash, module: Module) -> Result<(), Self::StoreError>;
|
fn store(&mut self, key: WasmHash, module: Module) -> Result<(), Self::StoreError>;
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
use crate::types::{
|
use crate::types::{
|
||||||
FuncSig, GlobalDescriptor, MemoryDescriptor, MemoryIndex, TableDescriptor, TableIndex, Type,
|
FuncSig, GlobalDescriptor, MemoryDescriptor, MemoryIndex, TableDescriptor, TableIndex, Type,
|
||||||
|
Value,
|
||||||
};
|
};
|
||||||
use core::borrow::Borrow;
|
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 Result<T> = std::result::Result<T, Error>;
|
||||||
pub type CompileResult<T> = std::result::Result<T, CompileError>;
|
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`.
|
/// The main way to do this is `Instance.call`.
|
||||||
///
|
///
|
||||||
/// Comparing two `RuntimeError`s always evaluates to false.
|
/// Comparing two `RuntimeError`s always evaluates to false.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug)]
|
||||||
pub enum RuntimeError {
|
pub enum RuntimeError {
|
||||||
OutOfBoundsAccess {
|
Trap { msg: Box<str> },
|
||||||
memory: MemoryIndex,
|
Exception { data: Box<[Value]> },
|
||||||
addr: Option<u32>,
|
Panic { data: Box<dyn Any> },
|
||||||
},
|
|
||||||
TableOutOfBounds {
|
|
||||||
table: TableIndex,
|
|
||||||
},
|
|
||||||
IndirectCallSignature {
|
|
||||||
table: TableIndex,
|
|
||||||
},
|
|
||||||
IndirectCallToNull {
|
|
||||||
table: TableIndex,
|
|
||||||
},
|
|
||||||
IllegalArithmeticOperation,
|
|
||||||
User {
|
|
||||||
msg: String,
|
|
||||||
},
|
|
||||||
Unknown {
|
|
||||||
msg: String,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for RuntimeError {
|
impl PartialEq for RuntimeError {
|
||||||
@ -153,30 +137,13 @@ impl PartialEq for RuntimeError {
|
|||||||
impl std::fmt::Display for RuntimeError {
|
impl std::fmt::Display for RuntimeError {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
RuntimeError::IndirectCallSignature { table } => write!(
|
RuntimeError::Trap { ref msg } => {
|
||||||
f,
|
write!(f, "WebAssembly trap occured during runtime: {}", msg)
|
||||||
"Indirect call signature error with Table Index \"{:?}\"",
|
|
||||||
table
|
|
||||||
),
|
|
||||||
RuntimeError::IndirectCallToNull { table } => {
|
|
||||||
write!(f, "Indirect call to null with table index \"{:?}\"", table)
|
|
||||||
}
|
}
|
||||||
RuntimeError::IllegalArithmeticOperation => write!(f, "Illegal arithmetic operation"),
|
RuntimeError::Exception { ref data } => {
|
||||||
RuntimeError::OutOfBoundsAccess { memory, addr } => match addr {
|
write!(f, "Uncaught WebAssembly exception: {:?}", data)
|
||||||
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::Unknown { msg } => {
|
RuntimeError::Panic { data: _ } => write!(f, "User-defined \"panic\""),
|
||||||
write!(f, "Unknown runtime error with message: \"{}\"", msg)
|
|
||||||
}
|
|
||||||
RuntimeError::User { msg } => write!(f, "User runtime error with message: \"{}\"", msg),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -232,7 +199,7 @@ impl std::error::Error for ResolveError {}
|
|||||||
/// be the `CallError::Runtime(RuntimeError)` variant.
|
/// be the `CallError::Runtime(RuntimeError)` variant.
|
||||||
///
|
///
|
||||||
/// Comparing two `CallError`s always evaluates to false.
|
/// Comparing two `CallError`s always evaluates to false.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug)]
|
||||||
pub enum CallError {
|
pub enum CallError {
|
||||||
Resolve(ResolveError),
|
Resolve(ResolveError),
|
||||||
Runtime(RuntimeError),
|
Runtime(RuntimeError),
|
||||||
@ -291,7 +258,7 @@ impl std::error::Error for CreationError {}
|
|||||||
/// of a webassembly module.
|
/// of a webassembly module.
|
||||||
///
|
///
|
||||||
/// Comparing two `Error`s always evaluates to false.
|
/// Comparing two `Error`s always evaluates to false.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
CompileError(CompileError),
|
CompileError(CompileError),
|
||||||
LinkError(Vec<LinkError>),
|
LinkError(Vec<LinkError>),
|
||||||
@ -357,8 +324,127 @@ impl From<ResolveError> for CallError {
|
|||||||
|
|
||||||
impl std::fmt::Display for Error {
|
impl std::fmt::Display for Error {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
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 {}
|
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::{
|
use crate::{
|
||||||
error::CreationError,
|
error::CreationError,
|
||||||
sys,
|
sys,
|
||||||
@ -14,9 +15,9 @@ pub const DYNAMIC_GUARD_SIZE: usize = 4096;
|
|||||||
/// when first created. Over time, as it grows, it may reallocate to
|
/// when first created. Over time, as it grows, it may reallocate to
|
||||||
/// a different location and size.
|
/// 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
|
/// 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
|
/// While, a dynamic memory could use a vector of some sort as its
|
||||||
/// backing memory, we use mmap (or the platform-equivalent) to allow
|
/// backing memory, we use mmap (or the platform-equivalent) to allow
|
||||||
@ -65,26 +66,29 @@ impl DynamicMemory {
|
|||||||
self.current
|
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) {
|
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 let Some(max) = self.max {
|
||||||
if new_pages > max {
|
if new_pages > max {
|
||||||
return None;
|
return Err(GrowError::ExceededMaxPagesForMemory(
|
||||||
|
new_pages.0 as usize,
|
||||||
|
max.0 as usize,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut new_memory =
|
let mut new_memory = sys::Memory::with_size(new_pages.bytes().0 + DYNAMIC_GUARD_SIZE)
|
||||||
sys::Memory::with_size(new_pages.bytes().0 + DYNAMIC_GUARD_SIZE).ok()?;
|
.map_err(|e| e.into())?;
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
new_memory
|
new_memory
|
||||||
.protect(0..new_pages.bytes().0, sys::Protect::ReadWrite)
|
.protect(0..new_pages.bytes().0, sys::Protect::ReadWrite)
|
||||||
.ok()?;
|
.map_err(|e| e.into())?;
|
||||||
|
|
||||||
new_memory.as_slice_mut()[..self.current.bytes().0]
|
new_memory.as_slice_mut()[..self.current.bytes().0]
|
||||||
.copy_from_slice(&self.memory.as_slice()[..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;
|
let old_pages = self.current;
|
||||||
self.current = new_pages;
|
self.current = new_pages;
|
||||||
Some(old_pages)
|
Ok(old_pages)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_slice(&self) -> &[u8] {
|
pub fn as_slice(&self) -> &[u8] {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
error::CreationError,
|
error::{CreationError, GrowError},
|
||||||
export::Export,
|
export::Export,
|
||||||
import::IsExport,
|
import::IsExport,
|
||||||
memory::dynamic::DYNAMIC_GUARD_SIZE,
|
memory::dynamic::DYNAMIC_GUARD_SIZE,
|
||||||
@ -89,8 +89,8 @@ impl Memory {
|
|||||||
self.desc
|
self.desc
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Grow this memory by the specfied number of pages.
|
/// Grow this memory by the specified number of pages.
|
||||||
pub fn grow(&self, delta: Pages) -> Option<Pages> {
|
pub fn grow(&self, delta: Pages) -> Result<Pages, GrowError> {
|
||||||
match &self.variant {
|
match &self.variant {
|
||||||
MemoryVariant::Unshared(unshared_mem) => unshared_mem.grow(delta),
|
MemoryVariant::Unshared(unshared_mem) => unshared_mem.grow(delta),
|
||||||
MemoryVariant::Shared(shared_mem) => shared_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 storage = self.internal.storage.borrow_mut();
|
||||||
|
|
||||||
let mut local = self.internal.local.get();
|
let mut local = self.internal.local.get();
|
||||||
@ -292,7 +292,7 @@ impl SharedMemory {
|
|||||||
Ok(Self { desc })
|
Ok(Self { desc })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn grow(&self, _delta: Pages) -> Option<Pages> {
|
pub fn grow(&self, _delta: Pages) -> Result<Pages, GrowError> {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
use crate::error::GrowError;
|
||||||
use crate::{
|
use crate::{
|
||||||
error::CreationError,
|
error::CreationError,
|
||||||
memory::static_::{SAFE_STATIC_GUARD_SIZE, SAFE_STATIC_HEAP_SIZE},
|
memory::static_::{SAFE_STATIC_GUARD_SIZE, SAFE_STATIC_HEAP_SIZE},
|
||||||
@ -61,27 +62,30 @@ impl StaticMemory {
|
|||||||
self.current
|
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) {
|
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 let Some(max) = self.max {
|
||||||
if new_pages > 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
|
self.memory
|
||||||
.protect(
|
.protect(
|
||||||
self.current.bytes().0..new_pages.bytes().0,
|
self.current.bytes().0..new_pages.bytes().0,
|
||||||
sys::Protect::ReadWrite,
|
sys::Protect::ReadWrite,
|
||||||
)
|
)
|
||||||
.ok()?;
|
.map_err(|e| e.into())
|
||||||
}
|
}?;
|
||||||
|
|
||||||
local.bound = new_pages.bytes().0;
|
local.bound = new_pages.bytes().0;
|
||||||
|
|
||||||
@ -89,7 +93,7 @@ impl StaticMemory {
|
|||||||
|
|
||||||
self.current = new_pages;
|
self.current = new_pages;
|
||||||
|
|
||||||
Some(old_pages)
|
Ok(old_pages)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_slice(&self) -> &[u8] {
|
pub fn as_slice(&self) -> &[u8] {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
backend::{Backend, FuncResolver, ProtectedCaller},
|
backend::{Backend, FuncResolver, ProtectedCaller},
|
||||||
cache::{Artifact, Error as CacheError, WasmHash},
|
cache::{Artifact, Error as CacheError},
|
||||||
error,
|
error,
|
||||||
import::ImportObject,
|
import::ImportObject,
|
||||||
structures::{Map, TypedIndex},
|
structures::{Map, TypedIndex},
|
||||||
|
@ -56,6 +56,10 @@ where
|
|||||||
pub fn into_boxed_map(self) -> BoxedMap<K, V> {
|
pub fn into_boxed_map(self) -> BoxedMap<K, V> {
|
||||||
BoxedMap::new(self.elems.into_boxed_slice())
|
BoxedMap::new(self.elems.into_boxed_slice())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn into_vec(self) -> Vec<V> {
|
||||||
|
self.elems
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<K, V> Map<K, V>
|
impl<K, V> Map<K, V>
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
use crate::error::MemoryCreationError;
|
||||||
|
use crate::error::MemoryProtectionError;
|
||||||
use errno;
|
use errno;
|
||||||
use nix::libc;
|
use nix::libc;
|
||||||
use page_size;
|
use page_size;
|
||||||
@ -16,13 +18,13 @@ pub struct Memory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl 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
|
where
|
||||||
P: AsRef<Path>,
|
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);
|
let raw_fd = RawFd::from_file(file);
|
||||||
|
|
||||||
@ -38,7 +40,10 @@ impl Memory {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if ptr == -1 as _ {
|
if ptr == -1 as _ {
|
||||||
Err(errno::errno().to_string())
|
Err(MemoryCreationError::VirtualMemoryAllocationFailed(
|
||||||
|
file_len as usize,
|
||||||
|
errno::errno().to_string(),
|
||||||
|
))
|
||||||
} else {
|
} else {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
ptr: ptr as *mut u8,
|
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 {
|
if size == 0 {
|
||||||
return Ok(Self {
|
return Ok(Self {
|
||||||
ptr: ptr::null_mut(),
|
ptr: ptr::null_mut(),
|
||||||
@ -108,7 +113,10 @@ impl Memory {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if ptr == -1 as _ {
|
if ptr == -1 as _ {
|
||||||
Err(errno::errno().to_string())
|
Err(MemoryCreationError::VirtualMemoryAllocationFailed(
|
||||||
|
size,
|
||||||
|
errno::errno().to_string(),
|
||||||
|
))
|
||||||
} else {
|
} else {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
ptr: ptr as *mut u8,
|
ptr: ptr as *mut u8,
|
||||||
@ -123,7 +131,7 @@ impl Memory {
|
|||||||
&mut self,
|
&mut self,
|
||||||
range: impl RangeBounds<usize>,
|
range: impl RangeBounds<usize>,
|
||||||
protection: Protect,
|
protection: Protect,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), MemoryProtectionError> {
|
||||||
let protect = protection.to_protect_const();
|
let protect = protection.to_protect_const();
|
||||||
|
|
||||||
let range_start = match range.start_bound() {
|
let range_start = match range.start_bound() {
|
||||||
@ -147,7 +155,11 @@ impl Memory {
|
|||||||
|
|
||||||
let success = libc::mprotect(start as _, size, protect as i32);
|
let success = libc::mprotect(start as _, size, protect as i32);
|
||||||
if success == -1 {
|
if success == -1 {
|
||||||
Err(errno::errno().to_string())
|
Err(MemoryProtectionError::ProtectionFailed(
|
||||||
|
start as usize,
|
||||||
|
size,
|
||||||
|
errno::errno().to_string(),
|
||||||
|
))
|
||||||
} else {
|
} else {
|
||||||
self.protection = protection;
|
self.protection = protection;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
use crate::error::MemoryCreationError;
|
||||||
|
use crate::error::MemoryProtectionError;
|
||||||
use page_size;
|
use page_size;
|
||||||
use std::ops::{Bound, RangeBounds};
|
use std::ops::{Bound, RangeBounds};
|
||||||
use std::{ptr, slice};
|
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 {
|
if size == 0 {
|
||||||
return Ok(Self {
|
return Ok(Self {
|
||||||
ptr: ptr::null_mut(),
|
ptr: ptr::null_mut(),
|
||||||
@ -58,7 +60,10 @@ impl Memory {
|
|||||||
let ptr = unsafe { VirtualAlloc(ptr::null_mut(), size, MEM_RESERVE, PAGE_NOACCESS) };
|
let ptr = unsafe { VirtualAlloc(ptr::null_mut(), size, MEM_RESERVE, PAGE_NOACCESS) };
|
||||||
|
|
||||||
if ptr.is_null() {
|
if ptr.is_null() {
|
||||||
Err("unable to allocate memory".to_string())
|
Err(MemoryCreationError::VirtualMemoryAllocationFailed(
|
||||||
|
size,
|
||||||
|
"unable to allocate memory".to_string(),
|
||||||
|
))
|
||||||
} else {
|
} else {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
ptr: ptr as *mut u8,
|
ptr: ptr as *mut u8,
|
||||||
@ -72,7 +77,7 @@ impl Memory {
|
|||||||
&mut self,
|
&mut self,
|
||||||
range: impl RangeBounds<usize>,
|
range: impl RangeBounds<usize>,
|
||||||
protect: Protect,
|
protect: Protect,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), MemoryProtectionError> {
|
||||||
let protect_const = protect.to_protect_const();
|
let protect_const = protect.to_protect_const();
|
||||||
|
|
||||||
let range_start = match range.start_bound() {
|
let range_start = match range.start_bound() {
|
||||||
@ -98,7 +103,11 @@ impl Memory {
|
|||||||
let ptr = VirtualAlloc(start as _, size, MEM_COMMIT, protect_const);
|
let ptr = VirtualAlloc(start as _, size, MEM_COMMIT, protect_const);
|
||||||
|
|
||||||
if ptr.is_null() {
|
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 {
|
} else {
|
||||||
self.protection = protect;
|
self.protection = protect;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -11,6 +11,7 @@ mod anyfunc;
|
|||||||
|
|
||||||
pub use self::anyfunc::Anyfunc;
|
pub use self::anyfunc::Anyfunc;
|
||||||
use self::anyfunc::AnyfuncTable;
|
use self::anyfunc::AnyfuncTable;
|
||||||
|
use crate::error::GrowError;
|
||||||
|
|
||||||
pub enum Element<'a> {
|
pub enum Element<'a> {
|
||||||
Anyfunc(Anyfunc<'a>),
|
Anyfunc(Anyfunc<'a>),
|
||||||
@ -108,15 +109,15 @@ impl Table {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Grow this table by `delta`.
|
/// 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 {
|
if delta == 0 {
|
||||||
return Some(self.size());
|
return Ok(self.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
match &mut *self.storage.borrow_mut() {
|
match &mut *self.storage.borrow_mut() {
|
||||||
(TableStorage::Anyfunc(ref mut anyfunc_table), ref mut local) => {
|
(TableStorage::Anyfunc(ref mut anyfunc_table), ref mut local) => anyfunc_table
|
||||||
anyfunc_table.grow(delta, local)
|
.grow(delta, local)
|
||||||
}
|
.ok_or(GrowError::TableGrowError),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ use crate::{
|
|||||||
types::{FuncSig, Type, WasmExternType},
|
types::{FuncSig, Type, WasmExternType},
|
||||||
vm::Ctx,
|
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! {
|
thread_local! {
|
||||||
pub static EARLY_TRAPPER: UnsafeCell<Option<Box<dyn UserTrapper>>> = UnsafeCell::new(None);
|
pub static EARLY_TRAPPER: UnsafeCell<Option<Box<dyn UserTrapper>>> = UnsafeCell::new(None);
|
||||||
@ -40,14 +40,14 @@ pub trait TrapEarly<Rets>
|
|||||||
where
|
where
|
||||||
Rets: WasmTypeList,
|
Rets: WasmTypeList,
|
||||||
{
|
{
|
||||||
fn report(self) -> Result<Rets, String>;
|
fn report(self) -> Result<Rets, Box<dyn Any>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Rets> TrapEarly<Rets> for Rets
|
impl<Rets> TrapEarly<Rets> for Rets
|
||||||
where
|
where
|
||||||
Rets: WasmTypeList,
|
Rets: WasmTypeList,
|
||||||
{
|
{
|
||||||
fn report(self) -> Result<Rets, String> {
|
fn report(self) -> Result<Rets, Box<dyn Any>> {
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -55,10 +55,10 @@ where
|
|||||||
impl<Rets, E> TrapEarly<Rets> for Result<Rets, E>
|
impl<Rets, E> TrapEarly<Rets> for Result<Rets, E>
|
||||||
where
|
where
|
||||||
Rets: WasmTypeList,
|
Rets: WasmTypeList,
|
||||||
E: fmt::Debug,
|
E: Any,
|
||||||
{
|
{
|
||||||
fn report(self) -> Result<Rets, String> {
|
fn report(self) -> Result<Rets, Box<dyn Any>> {
|
||||||
self.map_err(|err| format!("Error: {:?}", err))
|
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 {
|
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 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()
|
f( ctx $( ,$x )* ).report()
|
||||||
})) {
|
})) {
|
||||||
Ok(Ok(returns)) => return returns.into_c_struct(),
|
Ok(Ok(returns)) => return returns.into_c_struct(),
|
||||||
Ok(Err(err)) => err,
|
Ok(Err(err)) => err,
|
||||||
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()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
if let Some(early_trapper) = &*EARLY_TRAPPER.with(|ucell| ucell.get()) {
|
if let Some(early_trapper) = &*EARLY_TRAPPER.with(|ucell| ucell.get()) {
|
||||||
early_trapper.do_early_trap(msg)
|
early_trapper.do_early_trap(err)
|
||||||
} else {
|
} else {
|
||||||
eprintln!("panic handling not setup");
|
eprintln!("panic handling not setup");
|
||||||
std::process::exit(1)
|
std::process::exit(1)
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
use crate::error::PageError;
|
||||||
use std::{
|
use std::{
|
||||||
fmt,
|
fmt,
|
||||||
ops::{Add, Sub},
|
ops::{Add, Sub},
|
||||||
@ -11,12 +12,16 @@ const WASM_MAX_PAGES: usize = 65_536;
|
|||||||
pub struct Pages(pub u32);
|
pub struct Pages(pub u32);
|
||||||
|
|
||||||
impl Pages {
|
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);
|
let added = (self.0 as usize) + (rhs.0 as usize);
|
||||||
if added <= WASM_MAX_PAGES {
|
if added <= WASM_MAX_PAGES {
|
||||||
Some(Pages(added as u32))
|
Ok(Pages(added as u32))
|
||||||
} else {
|
} 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 local_memory = *ctx.memories.add(memory_index.index());
|
||||||
let memory = (*local_memory).memory as *mut StaticMemory;
|
let memory = (*local_memory).memory as *mut StaticMemory;
|
||||||
|
|
||||||
if let Some(old) = (*memory).grow(delta, &mut *local_memory) {
|
match (*memory).grow(delta, &mut *local_memory) {
|
||||||
old.0 as i32
|
Ok(old) => old.0 as i32,
|
||||||
} else {
|
Err(_) => -1,
|
||||||
-1
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,10 +44,9 @@ pub unsafe extern "C" fn local_dynamic_memory_grow(
|
|||||||
let local_memory = *ctx.memories.add(memory_index.index());
|
let local_memory = *ctx.memories.add(memory_index.index());
|
||||||
let memory = (*local_memory).memory as *mut DynamicMemory;
|
let memory = (*local_memory).memory as *mut DynamicMemory;
|
||||||
|
|
||||||
if let Some(old) = (*memory).grow(delta, &mut *local_memory) {
|
match (*memory).grow(delta, &mut *local_memory) {
|
||||||
old.0 as i32
|
Ok(old) => old.0 as i32,
|
||||||
} else {
|
Err(_) => -1,
|
||||||
-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 local_memory = *ctx.imported_memories.add(import_memory_index.index());
|
||||||
let memory = (*local_memory).memory as *mut StaticMemory;
|
let memory = (*local_memory).memory as *mut StaticMemory;
|
||||||
|
|
||||||
if let Some(old) = (*memory).grow(delta, &mut *local_memory) {
|
match (*memory).grow(delta, &mut *local_memory) {
|
||||||
old.0 as i32
|
Ok(old) => old.0 as i32,
|
||||||
} else {
|
Err(_) => -1,
|
||||||
-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 local_memory = *ctx.imported_memories.add(memory_index.index());
|
||||||
let memory = (*local_memory).memory as *mut DynamicMemory;
|
let memory = (*local_memory).memory as *mut DynamicMemory;
|
||||||
|
|
||||||
if let Some(old) = (*memory).grow(delta, &mut *local_memory) {
|
match (*memory).grow(delta, &mut *local_memory) {
|
||||||
old.0 as i32
|
Ok(old) => old.0 as i32,
|
||||||
} else {
|
Err(_) => -1,
|
||||||
-1
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "wasmer-runtime"
|
name = "wasmer-runtime"
|
||||||
version = "0.1.4"
|
version = "0.2.1"
|
||||||
description = "Wasmer runtime library"
|
description = "Wasmer runtime library"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
|
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
|
||||||
@ -14,11 +14,16 @@ memmap = "0.7.0"
|
|||||||
|
|
||||||
[dependencies.wasmer-runtime-core]
|
[dependencies.wasmer-runtime-core]
|
||||||
path = "../runtime-core"
|
path = "../runtime-core"
|
||||||
version = "0.1.2"
|
version = "0.2.1"
|
||||||
|
|
||||||
[dependencies.wasmer-clif-backend]
|
[dependencies.wasmer-clif-backend]
|
||||||
path = "../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]
|
[dependencies.wasmer-llvm-backend]
|
||||||
path = "../llvm-backend"
|
path = "../llvm-backend"
|
||||||
@ -26,5 +31,6 @@ path = "../llvm-backend"
|
|||||||
[features]
|
[features]
|
||||||
debug = ["wasmer-clif-backend/debug", "wasmer-runtime-core/debug"]
|
debug = ["wasmer-clif-backend/debug", "wasmer-runtime-core/debug"]
|
||||||
|
|
||||||
[dev-dependencies]
|
[[bench]]
|
||||||
wabt = "0.7.4"
|
name = "nginx"
|
||||||
|
harness = false
|
||||||
|
@ -51,7 +51,7 @@ fn main() -> error::Result<()> {
|
|||||||
// We're not importing anything, so make an empty import object.
|
// We're not importing anything, so make an empty import object.
|
||||||
let import_object = imports! {};
|
let import_object = imports! {};
|
||||||
|
|
||||||
let mut instance = instantiate(WASM, import_object)?;
|
let mut instance = instantiate(WASM, &import_object)?;
|
||||||
|
|
||||||
let values = instance
|
let values = instance
|
||||||
.func("add_one")?
|
.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]
|
[package]
|
||||||
name = "wasmer-spectests"
|
name = "wasmer-spectests"
|
||||||
version = "0.1.2"
|
version = "0.2.0"
|
||||||
description = "Wasmer spectests library"
|
description = "Wasmer spectests library"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
|
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
|
||||||
@ -9,13 +9,13 @@ edition = "2018"
|
|||||||
build = "build/mod.rs"
|
build = "build/mod.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
wasmer-runtime-core = { path = "../runtime-core" }
|
wasmer-runtime-core = { path = "../runtime-core", version = "0.2.0" }
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
wabt = "0.7.2"
|
wabt = "0.7.2"
|
||||||
|
|
||||||
[dev-dependencies]
|
[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" }
|
wasmer-llvm-backend = { path = "../llvm-backend", version = "0.1.0" }
|
||||||
wabt = "0.7.2"
|
wabt = "0.7.2"
|
||||||
|
|
||||||
|
@ -569,7 +569,7 @@ fn {}_assert_malformed() {{
|
|||||||
let assertion = if expected.len() > 0 && is_nan(&expected[0]) {
|
let assertion = if expected.len() > 0 && is_nan(&expected[0]) {
|
||||||
format!(
|
format!(
|
||||||
"let expected = {expected_result};
|
"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!((*result as {return_type}).is_nan());
|
||||||
assert_eq!((*result as {return_type}).is_sign_positive(), (expected as {return_type}).is_sign_positive());
|
assert_eq!((*result as {return_type}).is_sign_positive(), (expected as {return_type}).is_sign_positive());
|
||||||
}} else {{
|
}} else {{
|
||||||
|
@ -31,7 +31,7 @@ mod tests {
|
|||||||
|
|
||||||
match result {
|
match result {
|
||||||
Err(err) => match err {
|
Err(err) => match err {
|
||||||
CallError::Runtime(RuntimeError::Unknown { msg }) => {
|
CallError::Runtime(RuntimeError::Trap { msg }) => {
|
||||||
assert!(!msg.contains("segmentation violation"));
|
assert!(!msg.contains("segmentation violation"));
|
||||||
assert!(!msg.contains("bus error"));
|
assert!(!msg.contains("bus error"));
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "wasmer-win-exception-handler"
|
name = "wasmer-win-exception-handler"
|
||||||
version = "0.0.1"
|
version = "0.2.0"
|
||||||
description = "Wasmer runtime exception handling for Windows"
|
description = "Wasmer runtime exception handling for Windows"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
|
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
|
||||||
@ -8,9 +8,9 @@ repository = "https://github.com/wasmerio/wasmer"
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[target.'cfg(windows)'.dependencies]
|
[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"] }
|
winapi = { version = "0.3", features = ["winbase", "errhandlingapi", "minwindef", "minwinbase", "winnt"] }
|
||||||
libc = "0.2.48"
|
libc = "0.2.49"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
cmake = "0.1.35"
|
cmake = "0.1.35"
|
||||||
|
@ -10,6 +10,7 @@ __declspec(thread) DWORD64 caughtInstructionPointer;
|
|||||||
__declspec(thread) PVOID savedStackPointer;
|
__declspec(thread) PVOID savedStackPointer;
|
||||||
__declspec(thread) BOOL exceptionHandlerInstalled = FALSE;
|
__declspec(thread) BOOL exceptionHandlerInstalled = FALSE;
|
||||||
__declspec(thread) BOOL alreadyHandlingException = FALSE;
|
__declspec(thread) BOOL alreadyHandlingException = FALSE;
|
||||||
|
__declspec(thread) PVOID handle;
|
||||||
|
|
||||||
void longjmpOutOfHere() {
|
void longjmpOutOfHere() {
|
||||||
longjmp(jmpBuf, 1);
|
longjmp(jmpBuf, 1);
|
||||||
@ -38,6 +39,14 @@ exceptionHandler(struct _EXCEPTION_POINTERS *ExceptionInfo) {
|
|||||||
return EXCEPTION_CONTINUE_EXECUTION;
|
return EXCEPTION_CONTINUE_EXECUTION;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void removeExceptionHandler() {
|
||||||
|
if (exceptionHandlerInstalled == FALSE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
RemoveVectoredExceptionHandler(handle);
|
||||||
|
exceptionHandlerInstalled = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t callProtected(trampoline_t trampoline,
|
uint8_t callProtected(trampoline_t trampoline,
|
||||||
const struct wasmer_instance_context_t* ctx,
|
const struct wasmer_instance_context_t* ctx,
|
||||||
const struct func_t* func,
|
const struct func_t* func,
|
||||||
@ -48,7 +57,7 @@ uint8_t callProtected(trampoline_t trampoline,
|
|||||||
// install exception handler
|
// install exception handler
|
||||||
if (exceptionHandlerInstalled == FALSE) {
|
if (exceptionHandlerInstalled == FALSE) {
|
||||||
exceptionHandlerInstalled = TRUE;
|
exceptionHandlerInstalled = TRUE;
|
||||||
AddVectoredExceptionHandler(CALL_FIRST, exceptionHandler);
|
handle = AddVectoredExceptionHandler(CALL_FIRST, exceptionHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
// jmp jmp jmp!
|
// jmp jmp jmp!
|
||||||
@ -60,6 +69,8 @@ uint8_t callProtected(trampoline_t trampoline,
|
|||||||
out_result->code = 0;
|
out_result->code = 0;
|
||||||
out_result->exceptionAddress = 0;
|
out_result->exceptionAddress = 0;
|
||||||
out_result->instructionPointer = 0;
|
out_result->instructionPointer = 0;
|
||||||
|
|
||||||
|
removeExceptionHandler();
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,5 +81,6 @@ uint8_t callProtected(trampoline_t trampoline,
|
|||||||
caughtExceptionAddress = 0;
|
caughtExceptionAddress = 0;
|
||||||
caughtInstructionPointer = 0;
|
caughtInstructionPointer = 0;
|
||||||
|
|
||||||
|
removeExceptionHandler();
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
extern crate structopt;
|
extern crate structopt;
|
||||||
|
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::fs;
|
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
@ -14,7 +13,6 @@ use wasmer::webassembly::InstanceABI;
|
|||||||
use wasmer::*;
|
use wasmer::*;
|
||||||
use wasmer_emscripten;
|
use wasmer_emscripten;
|
||||||
use wasmer_runtime::cache::{Cache as BaseCache, FileSystemCache, WasmHash};
|
use wasmer_runtime::cache::{Cache as BaseCache, FileSystemCache, WasmHash};
|
||||||
use wasmer_runtime::error::CacheError;
|
|
||||||
|
|
||||||
#[derive(Debug, StructOpt)]
|
#[derive(Debug, StructOpt)]
|
||||||
#[structopt(name = "wasmer", about = "Wasm execution runtime.")]
|
#[structopt(name = "wasmer", about = "Wasm execution runtime.")]
|
||||||
@ -35,9 +33,6 @@ enum CLIOptions {
|
|||||||
|
|
||||||
#[derive(Debug, StructOpt)]
|
#[derive(Debug, StructOpt)]
|
||||||
struct Run {
|
struct Run {
|
||||||
#[structopt(short = "d", long = "debug")]
|
|
||||||
debug: bool,
|
|
||||||
|
|
||||||
// Disable the cache
|
// Disable the cache
|
||||||
#[structopt(long = "disable-cache")]
|
#[structopt(long = "disable-cache")]
|
||||||
disable_cache: bool,
|
disable_cache: bool,
|
||||||
@ -84,6 +79,12 @@ fn get_cache_dir() -> PathBuf {
|
|||||||
|
|
||||||
/// Execute a wasm/wat file
|
/// Execute a wasm/wat file
|
||||||
fn execute_wasm(options: &Run) -> Result<(), String> {
|
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 wasm_path = &options.path;
|
||||||
|
|
||||||
let mut wasm_binary: Vec<u8> = read_file_contents(wasm_path).map_err(|err| {
|
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))?;
|
.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
|
// If we have cache enabled
|
||||||
|
|
||||||
// We generate a hash for the given binary, so we can use it as key
|
// We generate a hash for the given binary, so we can use it as key
|
||||||
@ -188,8 +189,10 @@ fn main() {
|
|||||||
CLIOptions::SelfUpdate => {
|
CLIOptions::SelfUpdate => {
|
||||||
println!("Self update is not supported on Windows. Use install instructions on the Wasmer homepage: https://wasmer.io");
|
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 {
|
CLIOptions::Cache(cache) => match cache {
|
||||||
Cache::Clean => {
|
Cache::Clean => {
|
||||||
|
use std::fs;
|
||||||
let cache_dir = get_cache_dir();
|
let cache_dir = get_cache_dir();
|
||||||
fs::remove_dir_all(cache_dir.clone()).expect("Can't remove 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");
|
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());
|
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
|
OutputBaseFilename=WasmerInstaller
|
||||||
|
|
||||||
[Files]
|
[Files]
|
||||||
Source: "..\target\release\wasmer.exe"; DestDir: "{app}\bin"
|
Source: "..\..\target\release\wasmer.exe"; DestDir: "{app}\bin"
|
||||||
|
|
||||||
[Code]
|
[Code]
|
||||||
const EnvironmentKey = 'SYSTEM\CurrentControlSet\Control\Session Manager\Environment';
|
const EnvironmentKey = 'SYSTEM\CurrentControlSet\Control\Session Manager\Environment';
|
||||||
|
Loading…
Reference in New Issue
Block a user