mirror of
https://github.com/fluencelabs/wasmer
synced 2025-06-24 14:11:32 +00:00
Merge remote-tracking branch 'private/master' into feature/dynasm-backend
This commit is contained in:
137
.appveyor.yml
137
.appveyor.yml
@ -1,6 +1,3 @@
|
|||||||
# This appveyor build file is heavily inspired by uutils/coreutils
|
|
||||||
# https://raw.githubusercontent.com/uutils/coreutils/d0db7bbaa46dabf65b71e3e33b1ed7595aaacc56/.appveyor.yml
|
|
||||||
|
|
||||||
branches:
|
branches:
|
||||||
except:
|
except:
|
||||||
- master
|
- master
|
||||||
@ -9,143 +6,27 @@ version: "{build} ~ {branch}"
|
|||||||
|
|
||||||
os: Visual Studio 2017
|
os: Visual Studio 2017
|
||||||
|
|
||||||
matrix:
|
|
||||||
allow_failures:
|
|
||||||
- CHANNEL: stable
|
|
||||||
# - ABI: gnu
|
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
matrix:
|
matrix:
|
||||||
# minimum version
|
|
||||||
# - CHANNEL: 1.31.0
|
|
||||||
# ARCH: i686
|
|
||||||
# ABI: msvc
|
|
||||||
# # "msvc" ABI
|
|
||||||
# - CHANNEL: stable
|
|
||||||
# ARCH: i686
|
|
||||||
# ABI: msvc
|
|
||||||
# - CHANNEL: stable
|
|
||||||
# ARCH: x86_64
|
|
||||||
# ABI: msvc
|
|
||||||
# - CHANNEL: beta
|
|
||||||
# ARCH: i686
|
|
||||||
# ABI: msvc
|
|
||||||
# - CHANNEL: beta
|
|
||||||
# ARCH: x86_64
|
|
||||||
# ABI: msvc
|
|
||||||
# - CHANNEL: nightly
|
|
||||||
# ARCH: i686
|
|
||||||
# ABI: msvc
|
|
||||||
# - CHANNEL: nightly
|
|
||||||
# ARCH: x86_64
|
|
||||||
# ABI: msvc
|
|
||||||
# # "gnu" ABI
|
|
||||||
# - CHANNEL: stable
|
|
||||||
# ARCH: i686
|
|
||||||
# ABI: gnu
|
|
||||||
# - CHANNEL: stable
|
|
||||||
# ARCH: x86_64
|
|
||||||
# ABI: gnu
|
|
||||||
# - CHANNEL: beta
|
|
||||||
# ARCH: i686
|
|
||||||
# ABI: gnu
|
|
||||||
# - CHANNEL: beta
|
|
||||||
# ARCH: x86_64
|
|
||||||
# ABI: gnu
|
|
||||||
# - CHANNEL: nightly
|
|
||||||
# ARCH: i686
|
|
||||||
# ABI: gnu
|
|
||||||
# - CHANNEL: nightly
|
|
||||||
# ARCH: x86_64
|
|
||||||
# ABI: gnu
|
|
||||||
# * specific gnu compilers
|
|
||||||
# - CHANNEL: stable
|
|
||||||
# ARCH: i686
|
|
||||||
# ABI: gnu
|
|
||||||
# MINGW_URL: https://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win32/Personal%20Builds/mingw-builds/4.9.2/threads-win32/dwarf/i686-4.9.2-release-win32-dwarf-rt_v4-rev4.7z/download
|
|
||||||
# MINGW_ARCHIVE: i686-4.9.2-release-win32-dwarf-rt_v4-rev4.7z
|
|
||||||
- CHANNEL: stable
|
- CHANNEL: stable
|
||||||
ARCH: x86_64
|
ARCH: x86_64
|
||||||
ABI: gnu
|
ABI: msvc
|
||||||
MINGW_URL: https://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win64/Personal%20Builds/mingw-builds/7.3.0/threads-posix/seh/x86_64-7.3.0-release-posix-seh-rt_v5-rev0.7z/download#mingw-w64-x86_64-7.3.0-posix-seh.7z
|
TARGET: x86_64-pc-windows-msvc
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- echo %PATH%
|
- appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe
|
||||||
# force branch checkout (if knowable), then reset to the specific commit ## (can be needed for accurate code coverage info)
|
- rustup-init.exe -yv --default-host %target%
|
||||||
# * this allows later apps to see the branch name using standard `git branch` operations, yet always builds the correct specific commit
|
- set PATH=%PATH%;%USERPROFILE%\.cargo\bin
|
||||||
# * ref: <https://github.com/appveyor/ci/issues/1606>[`@`](https://archive.is/RVpnF)
|
|
||||||
- if DEFINED APPVEYOR_REPO_BRANCH if /I "%APPVEYOR_REPO_SCM%"=="git" ( git checkout "%APPVEYOR_REPO_BRANCH%" & git reset --hard "%APPVEYOR_REPO_COMMIT%" )
|
|
||||||
# ensure CWD is project main directory
|
|
||||||
- cd "%APPVEYOR_BUILD_FOLDER%"
|
|
||||||
# create a working area
|
|
||||||
- ps: if ( ! $env:CI_TEMP_DIR ) { $env:CI_TEMP_DIR = "${env:TEMP}\${env:APPVEYOR_JOB_ID}" ; mkdir -force $env:CI_TEMP_DIR | out-null }
|
|
||||||
|
|
||||||
# rust installation
|
|
||||||
- set "TARGET=%ARCH%-pc-windows-%ABI%"
|
|
||||||
# * install `rust` via `rustup`
|
|
||||||
- appveyor DownloadFile "https://win.rustup.rs/" -FileName "%CI_TEMP_DIR%\rustup-init.exe"
|
|
||||||
- call "%CI_TEMP_DIR%\rustup-init.exe" -y --default-toolchain %CHANNEL% --default-host %TARGET% --no-modify-path >NUL
|
|
||||||
- set "PATH=%PATH%;%USERPROFILE%\.cargo\bin"
|
|
||||||
- ps: $env:TOOLCHAIN = $(rustup show active-toolchain)
|
|
||||||
- rename "C:\Program Files\Git\usr\bin\sh.exe" sh2.exe
|
|
||||||
# * set RUST_BACKTRACE for enhanced error messages
|
|
||||||
- set RUST_BACKTRACE=1
|
|
||||||
# * show versions
|
|
||||||
- rustc -vV
|
- rustc -vV
|
||||||
- cargo -vV
|
- cargo -vV
|
||||||
|
|
||||||
# finalize FEATURES
|
|
||||||
- if /i "%CHANNEL%"=="nightly" set "FEATURES=nightly"
|
|
||||||
|
|
||||||
# "gnu" ABI setup
|
|
||||||
# * use the system MinGW/MSYS if we can
|
|
||||||
- if /i "%ABI%"=="gnu" set MSYS_BINDIR=C:\msys64\usr\bin
|
|
||||||
- if /i "%ABI%"=="gnu" if /i "%ARCH%"=="i686" set "MSYS_BITS=32"
|
|
||||||
- if /i "%ABI%"=="gnu" if /i "%ARCH%"=="x86_64" set "MSYS_BITS=64"
|
|
||||||
- if defined MSYS_BITS set "MSYS_MINGWDIR=C:\msys64\mingw%MSYS_BITS%"
|
|
||||||
- if defined MSYS_MINGWDIR set "MSYS_BINDIR=C:\msys64\usr\bin"
|
|
||||||
## * workaround for rust-lang/rust#47048 / rust-lang/rust#53454 ## !maint: remove when resolved
|
|
||||||
- if /i "%ABI%"=="gnu" if /i "%ARCH%"=="i686" if not DEFINED MINGW_URL set "MINGW_URL=https://downloads.sourceforge.net/project/mingw-w64/Toolchains targetting Win32/Personal Builds/mingw-builds/8.1.0/threads-posix/dwarf/i686-8.1.0-release-posix-dwarf-rt_v6-rev0.7z"
|
|
||||||
- if /i "%ABI%"=="gnu" if /i "%ARCH%"=="x86_64" if not DEFINED MINGW_URL set "MINGW_URL=https://downloads.sourceforge.net/project/mingw-w64/Toolchains targetting Win64/Personal Builds/mingw-builds/8.1.0/threads-posix/seh/x86_64-8.1.0-release-posix-seh-rt_v6-rev0.7z"
|
|
||||||
##
|
|
||||||
# * specific MinGW, if specified
|
|
||||||
- ps: if ( ! $env:MINGW_ARCHIVE -and $env:MINGW_URL ) { $env:MINGW_ARCHIVE = $($([URI]$env:MINGW_URL).fragment).TrimStart('#') }
|
|
||||||
- ps: if ( ! $env:MINGW_ARCHIVE -and $env:MINGW_URL ) { $env:MINGW_ARCHIVE = $([URI]$env:MINGW_URL).segments[-1] }
|
|
||||||
- if defined MINGW_ARCHIVE curl --insecure -fsSL "%MINGW_URL%" -o "%CI_TEMP_DIR%\%MINGW_ARCHIVE%"
|
|
||||||
- if defined MINGW_ARCHIVE mkdir "%CI_TEMP_DIR%\MinGW" >NUL
|
|
||||||
- if defined MINGW_ARCHIVE 7z x -y "%CI_TEMP_DIR%\%MINGW_ARCHIVE%" -o"%CI_TEMP_DIR%\MinGW" >NUL
|
|
||||||
- if defined MINGW_ARCHIVE set "MSYS_MINGWDIR=%CI_TEMP_DIR%\MinGW\mingw%MSYS_BITS%"
|
|
||||||
- if defined MINGW_ARCHIVE set "MSYS_BINDIR=%MSYS_MINGWDIR%\bin"
|
|
||||||
# * MinGW/MSYS PATH setup
|
|
||||||
- if defined MSYS_MINGWDIR set PATH=%MSYS_MINGWDIR%\%ARCH%-w64-mingw32\bin;%MSYS_BINDIR%;%PATH%
|
|
||||||
## * workaround for rust-lang/rust#47048 / rust-lang/rust#53454 ## !maint: remove when resolved
|
|
||||||
# ** ref: <https://github.com/rust-lang/rust/issues/47048>, <https://github.com/rust-lang/rust/issues/53454>
|
|
||||||
# ** egs: <https://github.com/pkgw/tectonic/commit/29686db533d8732d7d97fc94270ed33b77f29295>, <https://github.com/rukai/PF_Sandbox/blob/e842613cf9ff102dfb3fbd87381319e6e6dfe3ae/appveyor.yml>
|
|
||||||
- if /i "%ABI%"=="gnu" rustup install %CHANNEL%-%ARCH%-pc-windows-msvc
|
|
||||||
- if /i "%ABI%"=="gnu" rustup default %CHANNEL%-%ARCH%-pc-windows-msvc
|
|
||||||
- if /i "%ABI%"=="gnu" rustup target add %TARGET%
|
|
||||||
- if /i "%ABI%"=="gnu" rustup show
|
|
||||||
- if /i "%ABI%"=="gnu" rustc -vV
|
|
||||||
- ps: $env:TOOLCHAIN = $(rustup show active-toolchain)
|
|
||||||
# ** copy libs from gcc toolchain to rust toolchain (more specifically, "crt2.o" and "dllcrt2.o" are needed)
|
|
||||||
- if defined MSYS_MINGWDIR copy /y "%MSYS_MINGWDIR%\%ARCH%-w64-mingw32\lib\*.o" "%USERPROFILE%\.rustup\toolchains\%TOOLCHAIN%\lib\rustlib\%TARGET%\lib" >NUL
|
|
||||||
##
|
|
||||||
- if /i "%ABI%"=="gnu" where gcc
|
|
||||||
- if /i "%ABI%"=="gnu" gcc --version
|
|
||||||
|
|
||||||
# "msvc" ABI setup
|
|
||||||
- if /i "%ABI%" == "msvc" if /i "%ARCH%" == "i686" call "%VS140COMNTOOLS%\..\..\VC\vcvarsall.bat"
|
|
||||||
- if /i "%ABI%" == "msvc" if /i "%ARCH%" == "x86_64" call "C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\SetEnv.cmd" /x64
|
|
||||||
- if /i "%ABI%" == "msvc" if /i "%ARCH%" == "x86_64" call "%VS140COMNTOOLS%\..\..\VC\vcvarsall.bat" x86_amd64
|
|
||||||
|
|
||||||
artifacts:
|
artifacts:
|
||||||
- path: target\%TARGET%\debug\wasmer.exe
|
- path: target\debug\wasmer.exe
|
||||||
name: wasmer.exe
|
name: wasmer.exe
|
||||||
|
|
||||||
build_script:
|
build_script:
|
||||||
- set BUILD_CMD=cargo +%TOOLCHAIN% build --target=%TARGET%
|
- cargo build --verbose
|
||||||
- echo [ %BUILD_CMD% ] & %BUILD_CMD%
|
|
||||||
|
|
||||||
test_script:
|
test_script:
|
||||||
- set TEST_CMD=cargo +%TOOLCHAIN% test --target=%TARGET% --no-fail-fast
|
- set RUST_BACKTRACE=1
|
||||||
- echo [ %TEST_CMD% ] & %TEST_CMD%
|
- cargo test --verbose
|
||||||
|
@ -42,6 +42,7 @@ jobs:
|
|||||||
command: |
|
command: |
|
||||||
sudo apt-get install -y cmake
|
sudo apt-get install -y cmake
|
||||||
- run: make test
|
- run: make test
|
||||||
|
- run: make integration-tests
|
||||||
- save_cache:
|
- save_cache:
|
||||||
paths:
|
paths:
|
||||||
- /usr/local/cargo/registry
|
- /usr/local/cargo/registry
|
||||||
|
4
Makefile
4
Makefile
@ -23,8 +23,8 @@ install:
|
|||||||
|
|
||||||
integration-tests: release
|
integration-tests: release
|
||||||
echo "Running Integration Tests"
|
echo "Running Integration Tests"
|
||||||
# Commented for now until we fix emscripten
|
./integration_tests/lua/test.sh
|
||||||
# ./integration_tests/nginx/test.sh
|
./integration_tests/nginx/test.sh
|
||||||
|
|
||||||
lint:
|
lint:
|
||||||
cargo fmt --all -- --check
|
cargo fmt --all -- --check
|
||||||
|
9
integration_tests/lua/README.md
Normal file
9
integration_tests/lua/README.md
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
# `lua` integration test
|
||||||
|
|
||||||
|
|
||||||
|
This starts wasmer with the lua wasm file. The test asserts on
|
||||||
|
the output of wasmer. Run test with:
|
||||||
|
|
||||||
|
```
|
||||||
|
> ./integration_tests/lua/test.sh
|
||||||
|
```
|
15
integration_tests/lua/test.sh
Executable file
15
integration_tests/lua/test.sh
Executable file
@ -0,0 +1,15 @@
|
|||||||
|
#! /bin/bash
|
||||||
|
|
||||||
|
nohup ./target/release/wasmer run examples/lua.wasm &
|
||||||
|
sleep 3s
|
||||||
|
|
||||||
|
if grep "Lua 5.4.0 Copyright (C) 1994-2018 Lua.org, PUC-Rio" ./nohup.out
|
||||||
|
then
|
||||||
|
echo "lua integration test succeeded"
|
||||||
|
rm ./nohup.out
|
||||||
|
exit 0
|
||||||
|
else
|
||||||
|
echo "lua integration test failed"
|
||||||
|
rm ./nohup.out
|
||||||
|
exit -1
|
||||||
|
fi
|
@ -16,7 +16,7 @@ use wasmer_runtime_core::{
|
|||||||
cache::{Cache, Error as CacheError},
|
cache::{Cache, Error as CacheError},
|
||||||
};
|
};
|
||||||
use wasmer_runtime_core::{
|
use wasmer_runtime_core::{
|
||||||
backend::{Backend, FuncResolver, ProtectedCaller, Token},
|
backend::{Backend, FuncResolver, ProtectedCaller, Token, UserTrapper},
|
||||||
error::{CompileResult, RuntimeResult},
|
error::{CompileResult, RuntimeResult},
|
||||||
module::{ModuleInfo, ModuleInner, StringTable},
|
module::{ModuleInfo, ModuleInner, StringTable},
|
||||||
structures::{Map, TypedIndex},
|
structures::{Map, TypedIndex},
|
||||||
@ -51,6 +51,10 @@ impl ProtectedCaller for Placeholder {
|
|||||||
) -> RuntimeResult<Vec<Value>> {
|
) -> RuntimeResult<Vec<Value>> {
|
||||||
Ok(vec![])
|
Ok(vec![])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_early_trapper(&self) -> Box<dyn UserTrapper> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This contains all of the items in a `ModuleInner` except the `func_resolver`.
|
/// This contains all of the items in a `ModuleInner` except the `func_resolver`.
|
||||||
|
@ -35,6 +35,13 @@ use wasmer_runtime_core::{
|
|||||||
vm, vmcalls,
|
vm, vmcalls,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#[cfg(not(target_os = "windows"))]
|
||||||
|
pub fn __rust_probestack();
|
||||||
|
#[cfg(all(target_os = "windows", target_pointer_width = "64"))]
|
||||||
|
pub fn __chkstk();
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub struct FuncResolverBuilder {
|
pub struct FuncResolverBuilder {
|
||||||
resolver: FuncResolver,
|
resolver: FuncResolver,
|
||||||
@ -215,7 +222,10 @@ impl FuncResolverBuilder {
|
|||||||
LibCall::FloorF64 => libcalls::floorf64 as isize,
|
LibCall::FloorF64 => libcalls::floorf64 as isize,
|
||||||
LibCall::TruncF64 => libcalls::truncf64 as isize,
|
LibCall::TruncF64 => libcalls::truncf64 as isize,
|
||||||
LibCall::NearestF64 => libcalls::nearbyintf64 as isize,
|
LibCall::NearestF64 => libcalls::nearbyintf64 as isize,
|
||||||
LibCall::Probestack => libcalls::__rust_probestack as isize,
|
#[cfg(all(target_pointer_width = "64", target_os = "windows"))]
|
||||||
|
Probestack => __chkstk as isize,
|
||||||
|
#[cfg(not(target_os = "windows"))]
|
||||||
|
Probestack => __rust_probestack as isize,
|
||||||
},
|
},
|
||||||
RelocationType::Intrinsic(ref name) => match name.as_str() {
|
RelocationType::Intrinsic(ref name) => match name.as_str() {
|
||||||
"i32print" => i32_print as isize,
|
"i32print" => i32_print as isize,
|
||||||
|
@ -2,9 +2,9 @@ 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::sync::Arc;
|
use std::{cell::Cell, sync::Arc};
|
||||||
use wasmer_runtime_core::{
|
use wasmer_runtime_core::{
|
||||||
backend::{ProtectedCaller, Token},
|
backend::{ProtectedCaller, Token, UserTrapper},
|
||||||
error::RuntimeResult,
|
error::RuntimeResult,
|
||||||
export::Context,
|
export::Context,
|
||||||
module::{ExportIndex, ModuleInfo, ModuleInner},
|
module::{ExportIndex, ModuleInfo, ModuleInner},
|
||||||
@ -24,6 +24,19 @@ pub use self::unix::*;
|
|||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
pub use self::windows::*;
|
pub use self::windows::*;
|
||||||
|
|
||||||
|
thread_local! {
|
||||||
|
pub static TRAP_EARLY_DATA: Cell<Option<String>> = Cell::new(None);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Trapper;
|
||||||
|
|
||||||
|
impl UserTrapper for Trapper {
|
||||||
|
unsafe fn do_early_trap(&self, msg: String) -> ! {
|
||||||
|
TRAP_EARLY_DATA.with(|cell| cell.set(Some(msg)));
|
||||||
|
trigger_trap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Caller {
|
pub struct Caller {
|
||||||
func_export_set: HashSet<FuncIndex>,
|
func_export_set: HashSet<FuncIndex>,
|
||||||
handler_data: HandlerData,
|
handler_data: HandlerData,
|
||||||
@ -118,6 +131,10 @@ impl ProtectedCaller for Caller {
|
|||||||
})
|
})
|
||||||
.collect())
|
.collect())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_early_trapper(&self) -> Box<dyn UserTrapper> {
|
||||||
|
Box::new(Trapper)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_func_from_index(
|
fn get_func_from_index(
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
//! are very special, the async signal unsafety of Rust's TLS implementation generally does not affect the correctness here
|
//! are very special, the async signal unsafety of Rust's TLS implementation generally does not affect the correctness here
|
||||||
//! unless you have memory unsafety elsewhere in your code.
|
//! unless you have memory unsafety elsewhere in your code.
|
||||||
//!
|
//!
|
||||||
use crate::relocation::{TrapCode, TrapData, TrapSink};
|
use crate::relocation::{TrapCode, TrapData};
|
||||||
use crate::signal::HandlerData;
|
use crate::signal::HandlerData;
|
||||||
use libc::{c_int, c_void, siginfo_t};
|
use libc::{c_int, c_void, siginfo_t};
|
||||||
use nix::sys::signal::{
|
use nix::sys::signal::{
|
||||||
@ -60,6 +60,12 @@ thread_local! {
|
|||||||
pub static CURRENT_EXECUTABLE_BUFFER: Cell<*const c_void> = Cell::new(ptr::null());
|
pub static CURRENT_EXECUTABLE_BUFFER: Cell<*const c_void> = Cell::new(ptr::null());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub unsafe fn trigger_trap() -> ! {
|
||||||
|
let jmp_buf = SETJMP_BUFFER.with(|buf| buf.get());
|
||||||
|
|
||||||
|
longjmp(jmp_buf as *mut c_void, 0)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn call_protected<T>(handler_data: &HandlerData, f: impl FnOnce() -> T) -> RuntimeResult<T> {
|
pub fn call_protected<T>(handler_data: &HandlerData, f: impl FnOnce() -> T) -> RuntimeResult<T> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let jmp_buf = SETJMP_BUFFER.with(|buf| buf.get());
|
let jmp_buf = SETJMP_BUFFER.with(|buf| buf.get());
|
||||||
@ -72,54 +78,59 @@ pub fn call_protected<T>(handler_data: &HandlerData, f: impl FnOnce() -> T) -> R
|
|||||||
let signum = setjmp(jmp_buf as *mut _);
|
let signum = setjmp(jmp_buf as *mut _);
|
||||||
if signum != 0 {
|
if signum != 0 {
|
||||||
*jmp_buf = prev_jmp_buf;
|
*jmp_buf = prev_jmp_buf;
|
||||||
let (faulting_addr, inst_ptr) = CAUGHT_ADDRESSES.with(|cell| cell.get());
|
|
||||||
|
|
||||||
if let Some(TrapData {
|
if let Some(msg) = super::TRAP_EARLY_DATA.with(|cell| cell.replace(None)) {
|
||||||
trapcode,
|
Err(RuntimeError::User { msg })
|
||||||
srcloc: _,
|
} else {
|
||||||
}) = handler_data.lookup(inst_ptr)
|
let (faulting_addr, inst_ptr) = CAUGHT_ADDRESSES.with(|cell| cell.get());
|
||||||
{
|
|
||||||
Err(match Signal::from_c_int(signum) {
|
if let Some(TrapData {
|
||||||
Ok(SIGILL) => match trapcode {
|
trapcode,
|
||||||
TrapCode::BadSignature => RuntimeError::IndirectCallSignature {
|
srcloc: _,
|
||||||
table: TableIndex::new(0),
|
}) = handler_data.lookup(inst_ptr)
|
||||||
|
{
|
||||||
|
Err(match Signal::from_c_int(signum) {
|
||||||
|
Ok(SIGILL) => match trapcode {
|
||||||
|
TrapCode::BadSignature => RuntimeError::IndirectCallSignature {
|
||||||
|
table: TableIndex::new(0),
|
||||||
|
},
|
||||||
|
TrapCode::IndirectCallToNull => RuntimeError::IndirectCallToNull {
|
||||||
|
table: TableIndex::new(0),
|
||||||
|
},
|
||||||
|
TrapCode::HeapOutOfBounds => RuntimeError::OutOfBoundsAccess {
|
||||||
|
memory: MemoryIndex::new(0),
|
||||||
|
addr: None,
|
||||||
|
},
|
||||||
|
TrapCode::TableOutOfBounds => RuntimeError::TableOutOfBounds {
|
||||||
|
table: TableIndex::new(0),
|
||||||
|
},
|
||||||
|
_ => RuntimeError::Unknown {
|
||||||
|
msg: "unknown trap".to_string(),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
TrapCode::IndirectCallToNull => RuntimeError::IndirectCallToNull {
|
Ok(SIGSEGV) | Ok(SIGBUS) => RuntimeError::OutOfBoundsAccess {
|
||||||
table: TableIndex::new(0),
|
|
||||||
},
|
|
||||||
TrapCode::HeapOutOfBounds => RuntimeError::OutOfBoundsAccess {
|
|
||||||
memory: MemoryIndex::new(0),
|
memory: MemoryIndex::new(0),
|
||||||
addr: None,
|
addr: None,
|
||||||
},
|
},
|
||||||
TrapCode::TableOutOfBounds => RuntimeError::TableOutOfBounds {
|
Ok(SIGFPE) => RuntimeError::IllegalArithmeticOperation,
|
||||||
table: TableIndex::new(0),
|
_ => unimplemented!(),
|
||||||
},
|
}
|
||||||
_ => RuntimeError::Unknown {
|
.into())
|
||||||
msg: "unknown trap".to_string(),
|
} else {
|
||||||
},
|
let signal = match Signal::from_c_int(signum) {
|
||||||
},
|
Ok(SIGFPE) => "floating-point exception",
|
||||||
Ok(SIGSEGV) | Ok(SIGBUS) => RuntimeError::OutOfBoundsAccess {
|
Ok(SIGILL) => "illegal instruction",
|
||||||
memory: MemoryIndex::new(0),
|
Ok(SIGSEGV) => "segmentation violation",
|
||||||
addr: None,
|
Ok(SIGBUS) => "bus error",
|
||||||
},
|
Err(_) => "error while getting the Signal",
|
||||||
Ok(SIGFPE) => RuntimeError::IllegalArithmeticOperation,
|
_ => "unkown trapped signal",
|
||||||
_ => unimplemented!(),
|
};
|
||||||
|
// When the trap-handler is fully implemented, this will return more information.
|
||||||
|
Err(RuntimeError::Unknown {
|
||||||
|
msg: format!("trap at {:p} - {}", faulting_addr, signal),
|
||||||
|
}
|
||||||
|
.into())
|
||||||
}
|
}
|
||||||
.into())
|
|
||||||
} else {
|
|
||||||
let signal = match Signal::from_c_int(signum) {
|
|
||||||
Ok(SIGFPE) => "floating-point exception",
|
|
||||||
Ok(SIGILL) => "illegal instruction",
|
|
||||||
Ok(SIGSEGV) => "segmentation violation",
|
|
||||||
Ok(SIGBUS) => "bus error",
|
|
||||||
Err(_) => "error while getting the Signal",
|
|
||||||
_ => "unkown trapped signal",
|
|
||||||
};
|
|
||||||
// When the trap-handler is fully implemented, this will return more information.
|
|
||||||
Err(RuntimeError::Unknown {
|
|
||||||
msg: format!("trap at {:p} - {}", faulting_addr, signal),
|
|
||||||
}
|
|
||||||
.into())
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let ret = f(); // TODO: Switch stack?
|
let ret = f(); // TODO: Switch stack?
|
||||||
|
@ -4,3 +4,7 @@ use wasmer_runtime_core::error::RuntimeResult;
|
|||||||
pub fn call_protected<T>(handler_data: &HandlerData, f: impl FnOnce() -> T) -> RuntimeResult<T> {
|
pub fn call_protected<T>(handler_data: &HandlerData, f: impl FnOnce() -> T) -> RuntimeResult<T> {
|
||||||
unimplemented!("TODO");
|
unimplemented!("TODO");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub unsafe fn trigger_trap() -> ! {
|
||||||
|
unimplemented!("TODO");
|
||||||
|
}
|
||||||
|
1
lib/emscripten/emtests/ignores.txt
vendored
1
lib/emscripten/emtests/ignores.txt
vendored
@ -1,7 +1,6 @@
|
|||||||
test_ccall
|
test_ccall
|
||||||
test_demangle_stacks
|
test_demangle_stacks
|
||||||
emscripten_get_compiler_setting
|
emscripten_get_compiler_setting
|
||||||
env
|
|
||||||
fs_exports
|
fs_exports
|
||||||
getvalue_setvalue
|
getvalue_setvalue
|
||||||
legacy_exported_runtime_numbers
|
legacy_exported_runtime_numbers
|
||||||
|
7
lib/emscripten/src/env/unix/mod.rs
vendored
7
lib/emscripten/src/env/unix/mod.rs
vendored
@ -1,15 +1,14 @@
|
|||||||
/// NOTE: These syscalls only support wasm_32 for now because they take u32 offset
|
/// NOTE: These syscalls only support wasm_32 for now because they take u32 offset
|
||||||
use libc::{
|
use libc::{
|
||||||
c_int, c_long, getenv, getgrnam as libc_getgrnam, getpwnam as libc_getpwnam, putenv, setenv,
|
c_int, getenv, getgrnam as libc_getgrnam, getpwnam as libc_getpwnam, putenv, setenv, sysconf,
|
||||||
sysconf, unsetenv,
|
unsetenv,
|
||||||
};
|
};
|
||||||
use std::ffi::CStr;
|
use std::ffi::CStr;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::os::raw::c_char;
|
use std::os::raw::c_char;
|
||||||
|
|
||||||
use crate::env::call_malloc;
|
use crate::env::call_malloc;
|
||||||
use crate::utils::{allocate_on_stack, copy_cstr_into_wasm, copy_terminated_array_of_cstrs};
|
use crate::utils::{copy_cstr_into_wasm, copy_terminated_array_of_cstrs};
|
||||||
use crate::EmscriptenData;
|
|
||||||
use wasmer_runtime_core::vm::Ctx;
|
use wasmer_runtime_core::vm::Ctx;
|
||||||
|
|
||||||
// #[no_mangle]
|
// #[no_mangle]
|
||||||
|
1
lib/emscripten/src/env/windows/mod.rs
vendored
1
lib/emscripten/src/env/windows/mod.rs
vendored
@ -9,7 +9,6 @@ use crate::env::call_malloc;
|
|||||||
use crate::utils::{copy_cstr_into_wasm, read_string_from_wasm};
|
use crate::utils::{copy_cstr_into_wasm, read_string_from_wasm};
|
||||||
use wasmer_runtime_core::vm::Ctx;
|
use wasmer_runtime_core::vm::Ctx;
|
||||||
|
|
||||||
#[link(name = "c")]
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#[link_name = "_putenv"]
|
#[link_name = "_putenv"]
|
||||||
pub fn putenv(s: *const c_char) -> c_int;
|
pub fn putenv(s: *const c_char) -> c_int;
|
||||||
|
@ -5,14 +5,14 @@ use wasmer_runtime_core::vm::Ctx;
|
|||||||
// this cfg_attr will try to link with the legacy lib that does not inline printf
|
// this cfg_attr will try to link with the legacy lib that does not inline printf
|
||||||
// this will allow for compiliation, but will produce a linker error if there is a problem
|
// this will allow for compiliation, but will produce a linker error if there is a problem
|
||||||
// finding printf.
|
// finding printf.
|
||||||
#[cfg_attr(
|
//#[cfg_attr(
|
||||||
all(windows, target_env = "msvc"),
|
// all(windows, target_env = "msvc"),
|
||||||
link(name = "legacy_stdio_definitions", kind = "static-nobundle")
|
// link(name = "legacy_stdio_definitions", kind = "static-nobundle")
|
||||||
)]
|
//)]
|
||||||
extern "C" {
|
//extern "C" {
|
||||||
#[link_name = "printf"]
|
// #[link_name = "printf"]
|
||||||
pub fn _printf(s: *const c_char, ...) -> c_int;
|
// pub fn _printf(s: *const c_char, ...) -> c_int;
|
||||||
}
|
//}
|
||||||
|
|
||||||
/// putchar
|
/// putchar
|
||||||
pub fn putchar(chr: i32, ctx: &mut Ctx) {
|
pub fn putchar(chr: i32, ctx: &mut Ctx) {
|
||||||
@ -22,8 +22,9 @@ pub fn putchar(chr: i32, ctx: &mut Ctx) {
|
|||||||
/// printf
|
/// printf
|
||||||
pub fn printf(memory_offset: i32, extra: i32, ctx: &mut Ctx) -> i32 {
|
pub fn printf(memory_offset: i32, extra: i32, ctx: &mut Ctx) -> i32 {
|
||||||
debug!("emscripten::printf {}, {}", memory_offset, extra);
|
debug!("emscripten::printf {}, {}", memory_offset, extra);
|
||||||
unsafe {
|
// unsafe {
|
||||||
let addr = emscripten_memory_pointer!(ctx.memory(0), memory_offset) as _;
|
// let addr = emscripten_memory_pointer!(ctx.memory(0), memory_offset) as _;
|
||||||
_printf(addr, extra)
|
// _printf(addr, extra)
|
||||||
}
|
// }
|
||||||
|
-1
|
||||||
}
|
}
|
||||||
|
@ -7,20 +7,19 @@ use wasmer_runtime_core::vm::Ctx;
|
|||||||
pub fn __setjmp(env_addr: u32, ctx: &mut Ctx) -> c_int {
|
pub fn __setjmp(env_addr: u32, ctx: &mut Ctx) -> c_int {
|
||||||
debug!("emscripten::__setjmp (setjmp)");
|
debug!("emscripten::__setjmp (setjmp)");
|
||||||
unsafe {
|
unsafe {
|
||||||
unimplemented!()
|
// Rather than using the env as the holder of the jump buffer pointer,
|
||||||
// // Rather than using the env as the holder of the jump buffer pointer,
|
// we use the environment address to store the index relative to jumps
|
||||||
// // we use the environment address to store the index relative to jumps
|
// so the address of the jump it's outside the wasm memory itself.
|
||||||
// // so the address of the jump it's outside the wasm memory itself.
|
let jump_index = emscripten_memory_pointer!(ctx.memory(0), env_addr) as *mut i8;
|
||||||
// let jump_index = ctx.memory(0).as_ptr().add(env_addr as usize) as *mut i8;
|
// We create the jump buffer outside of the wasm memory
|
||||||
// // We create the jump buffer outside of the wasm memory
|
let jump_buf: UnsafeCell<[u32; 27]> = UnsafeCell::new([0; 27]);
|
||||||
// let jump_buf: UnsafeCell<[c_int; 27]> = UnsafeCell::new([0; 27]);
|
let jumps = &mut get_emscripten_data(ctx).jumps;
|
||||||
// let jumps = &mut get_emscripten_data(ctx).jumps;
|
let result = setjmp(jump_buf.get() as _);
|
||||||
// let result = setjmp(jump_buf.get() as _);
|
// We set the jump index to be the last value of jumps
|
||||||
// // We set the jump index to be the last value of jumps
|
*jump_index = jumps.len() as _;
|
||||||
// *jump_index = jumps.len() as _;
|
// We hold the reference of the jump buffer
|
||||||
// // We hold the reference of the jump buffer
|
jumps.push(jump_buf);
|
||||||
// jumps.push(jump_buf);
|
result
|
||||||
// result
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,29 +1,20 @@
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate wasmer_runtime_core;
|
extern crate wasmer_runtime_core;
|
||||||
|
|
||||||
use byteorder::{ByteOrder, LittleEndian};
|
|
||||||
use libc::c_int;
|
|
||||||
use std::cell::UnsafeCell;
|
use std::cell::UnsafeCell;
|
||||||
use std::{f64, ffi::c_void, fmt, mem, ptr};
|
use std::{f64, ffi::c_void};
|
||||||
use wasmer_runtime_core::{
|
use wasmer_runtime_core::{
|
||||||
error::CallResult,
|
error::CallResult,
|
||||||
export::{Context, Export, FuncPointer},
|
export::Export,
|
||||||
func,
|
func,
|
||||||
global::Global,
|
global::Global,
|
||||||
import::{ImportObject, Namespace},
|
import::ImportObject,
|
||||||
imports,
|
imports,
|
||||||
memory::Memory,
|
memory::Memory,
|
||||||
table::Table,
|
table::Table,
|
||||||
types::{
|
types::{ElementType, MemoryDescriptor, TableDescriptor, Value},
|
||||||
ElementType, FuncSig, GlobalDescriptor, MemoryDescriptor, TableDescriptor,
|
|
||||||
Type::{self, *},
|
|
||||||
Value,
|
|
||||||
},
|
|
||||||
units::Pages,
|
units::Pages,
|
||||||
vm::Ctx,
|
vm::Ctx,
|
||||||
vm::LocalGlobal,
|
|
||||||
vm::LocalMemory,
|
|
||||||
vm::LocalTable,
|
|
||||||
Func, Instance, Module,
|
Func, Instance, Module,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -52,7 +43,7 @@ mod time;
|
|||||||
mod utils;
|
mod utils;
|
||||||
mod varargs;
|
mod varargs;
|
||||||
|
|
||||||
pub use self::storage::align_memory;
|
pub use self::storage::{align_memory, static_alloc};
|
||||||
pub use self::utils::{
|
pub use self::utils::{
|
||||||
allocate_cstr_on_stack, allocate_on_stack, get_emscripten_memory_size,
|
allocate_cstr_on_stack, allocate_on_stack, get_emscripten_memory_size,
|
||||||
get_emscripten_table_size, is_emscripten_module,
|
get_emscripten_table_size, is_emscripten_module,
|
||||||
@ -70,7 +61,7 @@ const STATIC_BUMP: u32 = 215_536;
|
|||||||
// Then the stack.
|
// Then the stack.
|
||||||
// Then 'dynamic' memory for sbrk.
|
// Then 'dynamic' memory for sbrk.
|
||||||
const GLOBAL_BASE: u32 = 1024;
|
const GLOBAL_BASE: u32 = 1024;
|
||||||
const STATIC_BASE: i32 = GLOBAL_BASE as i32;
|
const STATIC_BASE: u32 = GLOBAL_BASE;
|
||||||
|
|
||||||
fn stacktop(static_bump: u32) -> u32 {
|
fn stacktop(static_bump: u32) -> u32 {
|
||||||
align_memory(dynamictop_ptr(static_bump) + 4)
|
align_memory(dynamictop_ptr(static_bump) + 4)
|
||||||
@ -121,15 +112,6 @@ impl<'a> EmscriptenData<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// impl<'a> fmt::Debug for EmscriptenData<'a> {
|
|
||||||
// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
// f.debug_struct("EmscriptenData")
|
|
||||||
// .field("malloc", &(self.malloc as usize))
|
|
||||||
// .field("free", &(self.free as usize))
|
|
||||||
// .finish()
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
pub fn run_emscripten_instance(
|
pub fn run_emscripten_instance(
|
||||||
_module: &Module,
|
_module: &Module,
|
||||||
instance: &mut Instance,
|
instance: &mut Instance,
|
||||||
@ -187,71 +169,28 @@ fn store_module_arguments(path: &str, args: Vec<&str>, ctx: &mut Ctx) -> (u32, u
|
|||||||
(argc as u32, argv_offset)
|
(argc as u32, argv_offset)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn emscripten_set_up_memory(memory: &mut Memory) {
|
pub fn emscripten_set_up_memory(memory: &Memory, globals: &EmscriptenGlobalsData) {
|
||||||
let dynamictop_ptr = dynamictop_ptr(STATIC_BUMP) as usize;
|
let dynamictop_ptr = globals.dynamictop_ptr;
|
||||||
let dynamictop_ptr_offset = dynamictop_ptr + mem::size_of::<u32>();
|
let stack_max = globals.stack_max;
|
||||||
|
|
||||||
// println!("value = {:?}");
|
let dynamic_base = align_memory(stack_max);
|
||||||
|
|
||||||
// We avoid failures of setting the u32 in our memory if it's out of bounds
|
memory.view::<u32>()[(dynamictop_ptr / 4) as usize].set(dynamic_base);
|
||||||
unimplemented!()
|
|
||||||
// if dynamictop_ptr_offset > memory.len() {
|
|
||||||
// return; // TODO: We should panic instead?
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // debug!("###### dynamic_base = {:?}", dynamic_base(STATIC_BUMP));
|
|
||||||
// // debug!("###### dynamictop_ptr = {:?}", dynamictop_ptr);
|
|
||||||
// // debug!("###### dynamictop_ptr_offset = {:?}", dynamictop_ptr_offset);
|
|
||||||
//
|
|
||||||
// let mem = &mut memory[dynamictop_ptr..dynamictop_ptr_offset];
|
|
||||||
// LittleEndian::write_u32(mem, dynamic_base(STATIC_BUMP));
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! mock_external {
|
|
||||||
($namespace:ident, $name:ident) => {{
|
|
||||||
fn _mocked_fn() -> i32 {
|
|
||||||
debug!("emscripten::{} <mock>", stringify!($name));
|
|
||||||
-1
|
|
||||||
}
|
|
||||||
|
|
||||||
$namespace.insert(
|
|
||||||
stringify!($name),
|
|
||||||
Export::Function {
|
|
||||||
func: unsafe { FuncPointer::new(_mocked_fn as _) },
|
|
||||||
ctx: Context::Internal,
|
|
||||||
signature: FuncSig {
|
|
||||||
params: vec![],
|
|
||||||
returns: vec![I32],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! global {
|
|
||||||
($value:expr) => {{
|
|
||||||
unsafe {
|
|
||||||
GlobalPointer::new(
|
|
||||||
// NOTE: Taking a shortcut here. LocalGlobal is a struct containing just u64.
|
|
||||||
std::mem::transmute::<&u64, *mut LocalGlobal>(&$value),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct EmscriptenGlobalsData {
|
pub struct EmscriptenGlobalsData {
|
||||||
abort: u64,
|
abort: u64,
|
||||||
// Env namespace
|
// Env namespace
|
||||||
stacktop: u64,
|
stacktop: u32,
|
||||||
stack_max: u64,
|
stack_max: u32,
|
||||||
dynamictop_ptr: u64,
|
dynamictop_ptr: u32,
|
||||||
memory_base: u64,
|
memory_base: u32,
|
||||||
table_base: u64,
|
table_base: u32,
|
||||||
temp_double_ptr: u64,
|
temp_double_ptr: u32,
|
||||||
|
|
||||||
// Global namespace
|
// Global namespace
|
||||||
infinity: u64,
|
infinity: f64,
|
||||||
nan: u64,
|
nan: f64,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct EmscriptenGlobals {
|
pub struct EmscriptenGlobals {
|
||||||
@ -265,7 +204,7 @@ pub struct EmscriptenGlobals {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl EmscriptenGlobals {
|
impl EmscriptenGlobals {
|
||||||
pub fn new(module: &Module) -> Self {
|
pub fn new(module: &Module /*, static_bump: u32 */) -> Self {
|
||||||
let (table_min, table_max) = get_emscripten_table_size(&module);
|
let (table_min, table_max) = get_emscripten_table_size(&module);
|
||||||
let (memory_min, memory_max) = get_emscripten_memory_size(&module);
|
let (memory_min, memory_max) = get_emscripten_memory_size(&module);
|
||||||
|
|
||||||
@ -275,7 +214,7 @@ impl EmscriptenGlobals {
|
|||||||
maximum: memory_max,
|
maximum: memory_max,
|
||||||
shared: false,
|
shared: false,
|
||||||
};
|
};
|
||||||
let mut memory = Memory::new(memory_type).unwrap();
|
let memory = Memory::new(memory_type).unwrap();
|
||||||
|
|
||||||
let table_type = TableDescriptor {
|
let table_type = TableDescriptor {
|
||||||
element: ElementType::Anyfunc,
|
element: ElementType::Anyfunc,
|
||||||
@ -284,24 +223,38 @@ impl EmscriptenGlobals {
|
|||||||
};
|
};
|
||||||
let mut table = Table::new(table_type).unwrap();
|
let mut table = Table::new(table_type).unwrap();
|
||||||
|
|
||||||
let memory_base = STATIC_BASE as u64;
|
let data = {
|
||||||
let table_base = 0 as u64;
|
let static_bump = STATIC_BUMP;
|
||||||
let temp_double_ptr = 0 as u64;
|
|
||||||
let data = EmscriptenGlobalsData {
|
|
||||||
abort: 0, // TODO review usage
|
|
||||||
// env
|
|
||||||
stacktop: stacktop(STATIC_BUMP) as _,
|
|
||||||
stack_max: stack_max(STATIC_BUMP) as _,
|
|
||||||
dynamictop_ptr: dynamictop_ptr(STATIC_BUMP) as _,
|
|
||||||
memory_base: memory_base,
|
|
||||||
table_base: table_base,
|
|
||||||
temp_double_ptr: temp_double_ptr,
|
|
||||||
|
|
||||||
// global
|
let mut STATIC_TOP = STATIC_BASE + static_bump;
|
||||||
infinity: std::f64::INFINITY.to_bits() as _,
|
|
||||||
nan: std::f64::NAN.to_bits() as _,
|
let memory_base = STATIC_BASE;
|
||||||
|
let table_base = 0;
|
||||||
|
|
||||||
|
let temp_double_ptr = STATIC_TOP;
|
||||||
|
STATIC_TOP += 16;
|
||||||
|
|
||||||
|
let dynamictop_ptr = static_alloc(&mut STATIC_TOP, 4);
|
||||||
|
|
||||||
|
let stacktop = align_memory(STATIC_TOP);
|
||||||
|
let stack_max = stacktop + TOTAL_STACK;
|
||||||
|
|
||||||
|
EmscriptenGlobalsData {
|
||||||
|
abort: 0,
|
||||||
|
stacktop,
|
||||||
|
stack_max,
|
||||||
|
dynamictop_ptr,
|
||||||
|
memory_base,
|
||||||
|
table_base,
|
||||||
|
temp_double_ptr,
|
||||||
|
|
||||||
|
infinity: std::f64::INFINITY,
|
||||||
|
nan: std::f64::NAN,
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
emscripten_set_up_memory(&memory, &data);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
data,
|
data,
|
||||||
memory,
|
memory,
|
||||||
@ -313,38 +266,21 @@ impl EmscriptenGlobals {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate_emscripten_env(globals: &mut EmscriptenGlobals) -> ImportObject {
|
pub fn generate_emscripten_env(globals: &mut EmscriptenGlobals) -> ImportObject {
|
||||||
// use crate::varargs::VarArgs;
|
imports! {
|
||||||
// let mut imports = ImportObject::new();
|
|
||||||
// let mut env_namespace = Namespace::new();
|
|
||||||
// let mut asm_namespace = Namespace::new();
|
|
||||||
// let mut global_namespace = Namespace::new();
|
|
||||||
// let mut global_math_namespace = Namespace::new();
|
|
||||||
|
|
||||||
// // Add globals.
|
|
||||||
// // NOTE: There is really no need for checks, these globals should always be available.
|
|
||||||
|
|
||||||
// // We generate a fake Context that traps on access
|
|
||||||
// let null_ctx = Context::External(ptr::null_mut());
|
|
||||||
|
|
||||||
// env_namespace.insert("memory".to_string(), Export::Memory(globals.memory.clone()));
|
|
||||||
|
|
||||||
// env_namespace.insert("table".to_string(), Export::Table(globals.table.clone()));
|
|
||||||
|
|
||||||
let import_object = imports! {
|
|
||||||
"env" => {
|
"env" => {
|
||||||
"memory" => Export::Memory(globals.memory.clone()),
|
"memory" => Export::Memory(globals.memory.clone()),
|
||||||
"table" => Export::Table(globals.table.clone()),
|
"table" => Export::Table(globals.table.clone()),
|
||||||
|
|
||||||
// Globals
|
// Globals
|
||||||
"STACKTOP" => Global::new(Value::I32(stacktop(STATIC_BUMP) as i32)),
|
"STACKTOP" => Global::new(Value::I32(globals.data.stacktop as i32)),
|
||||||
"STACK_MAX" => Global::new(Value::I32(stack_max(STATIC_BUMP) as i32)),
|
"STACK_MAX" => Global::new(Value::I32(globals.data.stack_max as i32)),
|
||||||
"DYNAMICTOP_PTR" => Global::new(Value::I32(dynamictop_ptr(STATIC_BUMP) as i32)),
|
"DYNAMICTOP_PTR" => Global::new(Value::I32(globals.data.dynamictop_ptr as i32)),
|
||||||
"tableBase" => Global::new(Value::I32(0)),
|
"tableBase" => Global::new(Value::I32(globals.data.table_base as i32)),
|
||||||
"__table_base" => Global::new(Value::I32(0)),
|
"__table_base" => Global::new(Value::I32(globals.data.table_base as i32)),
|
||||||
"ABORT" => Global::new(Value::I32(0)),
|
"ABORT" => Global::new(Value::I32(globals.data.abort as i32)),
|
||||||
"memoryBase" => Global::new(Value::I32(STATIC_BASE)),
|
"memoryBase" => Global::new(Value::I32(globals.data.memory_base as i32)),
|
||||||
"__memory_base" => Global::new(Value::I32(STATIC_BASE)),
|
"__memory_base" => Global::new(Value::I32(globals.data.memory_base as i32)),
|
||||||
"tempDoublePtr" => Global::new(Value::I32(0)),
|
"tempDoublePtr" => Global::new(Value::I32(globals.data.temp_double_ptr as i32)),
|
||||||
|
|
||||||
// IO
|
// IO
|
||||||
"printf" => func!(crate::io::printf),
|
"printf" => func!(crate::io::printf),
|
||||||
@ -528,18 +464,7 @@ pub fn generate_emscripten_env(globals: &mut EmscriptenGlobals) -> ImportObject
|
|||||||
"asm2wasm" => {
|
"asm2wasm" => {
|
||||||
"f64-rem" => func!(crate::math::f64_rem),
|
"f64-rem" => func!(crate::math::f64_rem),
|
||||||
},
|
},
|
||||||
};
|
}
|
||||||
// mock_external!(env_namespace, _sched_yield);
|
|
||||||
// mock_external!(env_namespace, _llvm_stacksave);
|
|
||||||
// mock_external!(env_namespace, _getgrent);
|
|
||||||
// mock_external!(env_namespace, _dlerror);
|
|
||||||
|
|
||||||
// imports.register("env", env_namespace);
|
|
||||||
// imports.register("asm2wasm", asm_namespace);
|
|
||||||
// imports.register("global", global_namespace);
|
|
||||||
// imports.register("global.Math", global_math_namespace);
|
|
||||||
|
|
||||||
import_object
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The current version of this crate
|
/// The current version of this crate
|
||||||
|
@ -11,6 +11,16 @@ pub struct StdioCapturer {
|
|||||||
stderr_reader: libc::c_int,
|
stderr_reader: libc::c_int,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(target_os = "windows"))]
|
||||||
|
use libc::{STDERR_FILENO, STDOUT_FILENO};
|
||||||
|
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
const STDIN_FILENO: libc::c_int = 0;
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
const STDOUT_FILENO: libc::c_int = 1;
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
const STDERR_FILENO: libc::c_int = 2;
|
||||||
|
|
||||||
// Implementation inspired in
|
// Implementation inspired in
|
||||||
// https://github.com/rust-lang/rust/blob/7d52cbce6db83e4fc2d8706b4e4b9c7da76cbcf8/src/test/run-pass/issues/issue-30490.rs
|
// https://github.com/rust-lang/rust/blob/7d52cbce6db83e4fc2d8706b4e4b9c7da76cbcf8/src/test/run-pass/issues/issue-30490.rs
|
||||||
// Currently only works in Unix systems (Mac, Linux)
|
// Currently only works in Unix systems (Mac, Linux)
|
||||||
@ -30,14 +40,14 @@ impl StdioCapturer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let stdout_backup = unsafe { libc::dup(libc::STDOUT_FILENO) };
|
let stdout_backup = unsafe { libc::dup(STDOUT_FILENO) };
|
||||||
let stderr_backup = unsafe { libc::dup(libc::STDERR_FILENO) };
|
let stderr_backup = unsafe { libc::dup(STDERR_FILENO) };
|
||||||
|
|
||||||
let (stdout_reader, stdout_writer) = Self::pipe();
|
let (stdout_reader, stdout_writer) = Self::pipe();
|
||||||
let (stderr_reader, stderr_writer) = Self::pipe();
|
let (stderr_reader, stderr_writer) = Self::pipe();
|
||||||
|
|
||||||
assert!(unsafe { libc::dup2(stdout_writer, libc::STDOUT_FILENO) } > -1);
|
assert!(unsafe { libc::dup2(stdout_writer, STDOUT_FILENO) } > -1);
|
||||||
assert!(unsafe { libc::dup2(stderr_writer, libc::STDERR_FILENO) } > -1);
|
assert!(unsafe { libc::dup2(stderr_writer, STDERR_FILENO) } > -1);
|
||||||
|
|
||||||
// Make sure we close any duplicates of the writer end of the pipe,
|
// Make sure we close any duplicates of the writer end of the pipe,
|
||||||
// otherwise we can get stuck reading from the pipe which has open
|
// otherwise we can get stuck reading from the pipe which has open
|
||||||
@ -57,8 +67,8 @@ impl StdioCapturer {
|
|||||||
// The Stdio passed into the Command took over (and closed) std{out, err}
|
// The Stdio passed into the Command took over (and closed) std{out, err}
|
||||||
// so we should restore them as they were.
|
// so we should restore them as they were.
|
||||||
|
|
||||||
assert!(unsafe { libc::dup2(self.stdout_backup, libc::STDOUT_FILENO) } > -1);
|
assert!(unsafe { libc::dup2(self.stdout_backup, STDOUT_FILENO) } > -1);
|
||||||
assert!(unsafe { libc::dup2(self.stderr_backup, libc::STDERR_FILENO) } > -1);
|
assert!(unsafe { libc::dup2(self.stderr_backup, STDERR_FILENO) } > -1);
|
||||||
|
|
||||||
let fd = FileDescriptor::new(self.stdout_reader);
|
let fd = FileDescriptor::new(self.stdout_reader);
|
||||||
let mut reader = BufReader::new(fd);
|
let mut reader = BufReader::new(fd);
|
||||||
|
@ -4,14 +4,9 @@ pub fn align_memory(ptr: u32) -> u32 {
|
|||||||
(ptr + 15) & !15
|
(ptr + 15) & !15
|
||||||
}
|
}
|
||||||
|
|
||||||
// pub fn static_alloc(size: u32, static_top: &mut u32, memory: &Memory) -> u32 {
|
pub fn static_alloc(static_top: &mut u32, size: u32) -> u32 {
|
||||||
// let old_static_top = *static_top;
|
let old_static_top = *static_top;
|
||||||
// let total_memory = memory.maximum_size() * Memory::PAGE_SIZE;
|
// NOTE: The `4294967280` is a u32 conversion of -16 as gotten from emscripten.
|
||||||
// // NOTE: The `4294967280` is a u32 conversion of -16 as gotten from emscripten.
|
*static_top = (*static_top + size + 15) & 4294967280;
|
||||||
// *static_top = (*static_top + size + 15) & 4294967280;
|
old_static_top
|
||||||
// assert!(
|
}
|
||||||
// *static_top < total_memory,
|
|
||||||
// "not enough memory for static allocation - increase total_memory!"
|
|
||||||
// );
|
|
||||||
// old_static_top
|
|
||||||
// }
|
|
||||||
|
@ -16,48 +16,30 @@ use byteorder::{ByteOrder, LittleEndian};
|
|||||||
/// NOTE: TODO: These syscalls only support wasm_32 for now because they assume offsets are u32
|
/// NOTE: TODO: These syscalls only support wasm_32 for now because they assume offsets are u32
|
||||||
/// Syscall list: https://www.cs.utexas.edu/~bismith/test/syscalls/syscalls32.html
|
/// Syscall list: https://www.cs.utexas.edu/~bismith/test/syscalls/syscalls32.html
|
||||||
use libc::{
|
use libc::{
|
||||||
accept,
|
|
||||||
bind,
|
|
||||||
// ENOTTY,
|
// ENOTTY,
|
||||||
c_char,
|
|
||||||
c_int,
|
c_int,
|
||||||
c_void,
|
c_void,
|
||||||
chdir,
|
chdir,
|
||||||
// fcntl, setsockopt, getppid
|
// fcntl, setsockopt, getppid
|
||||||
close,
|
close,
|
||||||
connect,
|
|
||||||
dup2,
|
dup2,
|
||||||
exit,
|
exit,
|
||||||
fstat,
|
fstat,
|
||||||
getpeername,
|
|
||||||
getpid,
|
getpid,
|
||||||
getsockname,
|
|
||||||
getsockopt,
|
|
||||||
// iovec,
|
// iovec,
|
||||||
listen,
|
|
||||||
lseek,
|
lseek,
|
||||||
mkdir,
|
|
||||||
off_t,
|
|
||||||
open,
|
open,
|
||||||
read,
|
read,
|
||||||
// readv,
|
// readv,
|
||||||
recvfrom,
|
|
||||||
rmdir,
|
rmdir,
|
||||||
// writev,
|
// writev,
|
||||||
sendto,
|
|
||||||
setsockopt,
|
|
||||||
sockaddr,
|
|
||||||
socket,
|
|
||||||
ssize_t,
|
|
||||||
stat,
|
stat,
|
||||||
write,
|
write,
|
||||||
EINVAL,
|
|
||||||
// sockaddr_in,
|
// sockaddr_in,
|
||||||
};
|
};
|
||||||
use wasmer_runtime_core::vm::Ctx;
|
use wasmer_runtime_core::vm::Ctx;
|
||||||
|
|
||||||
use super::env;
|
use super::env;
|
||||||
use std::mem;
|
|
||||||
use std::slice;
|
use std::slice;
|
||||||
// use std::sys::fd::FileDesc;
|
// use std::sys::fd::FileDesc;
|
||||||
|
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
use crate::varargs::VarArgs;
|
use crate::varargs::VarArgs;
|
||||||
use byteorder::{ByteOrder, LittleEndian};
|
|
||||||
/// NOTE: TODO: These syscalls only support wasm_32 for now because they assume offsets are u32
|
/// NOTE: TODO: These syscalls only support wasm_32 for now because they assume offsets are u32
|
||||||
/// Syscall list: https://www.cs.utexas.edu/~bismith/test/syscalls/syscalls32.html
|
/// Syscall list: https://www.cs.utexas.edu/~bismith/test/syscalls/syscalls32.html
|
||||||
use libc::{
|
use libc::{
|
||||||
@ -9,39 +8,28 @@ use libc::{
|
|||||||
c_char,
|
c_char,
|
||||||
c_int,
|
c_int,
|
||||||
c_void,
|
c_void,
|
||||||
chdir,
|
|
||||||
chown,
|
chown,
|
||||||
// fcntl, setsockopt, getppid
|
// fcntl, setsockopt, getppid
|
||||||
close,
|
|
||||||
connect,
|
connect,
|
||||||
dup2,
|
dup2,
|
||||||
exit,
|
|
||||||
fcntl,
|
fcntl,
|
||||||
fstat,
|
|
||||||
getgid,
|
getgid,
|
||||||
getpeername,
|
getpeername,
|
||||||
getpid,
|
|
||||||
getsockname,
|
getsockname,
|
||||||
getsockopt,
|
getsockopt,
|
||||||
gid_t,
|
|
||||||
in_addr_t,
|
in_addr_t,
|
||||||
in_port_t,
|
in_port_t,
|
||||||
ioctl,
|
ioctl,
|
||||||
// iovec,
|
// iovec,
|
||||||
listen,
|
listen,
|
||||||
lseek,
|
|
||||||
mkdir,
|
mkdir,
|
||||||
msghdr,
|
msghdr,
|
||||||
off_t,
|
|
||||||
open,
|
|
||||||
pid_t,
|
pid_t,
|
||||||
pread,
|
pread,
|
||||||
pwrite,
|
pwrite,
|
||||||
read,
|
|
||||||
// readv,
|
// readv,
|
||||||
recvfrom,
|
recvfrom,
|
||||||
recvmsg,
|
recvmsg,
|
||||||
rmdir,
|
|
||||||
// ENOTTY,
|
// ENOTTY,
|
||||||
rusage,
|
rusage,
|
||||||
sa_family_t,
|
sa_family_t,
|
||||||
@ -54,11 +42,8 @@ use libc::{
|
|||||||
sockaddr,
|
sockaddr,
|
||||||
socket,
|
socket,
|
||||||
socklen_t,
|
socklen_t,
|
||||||
ssize_t,
|
|
||||||
stat,
|
|
||||||
uname,
|
uname,
|
||||||
utsname,
|
utsname,
|
||||||
write,
|
|
||||||
EINVAL,
|
EINVAL,
|
||||||
// sockaddr_in,
|
// sockaddr_in,
|
||||||
FIOCLEX,
|
FIOCLEX,
|
||||||
@ -71,9 +56,7 @@ use libc::{
|
|||||||
};
|
};
|
||||||
use wasmer_runtime_core::vm::Ctx;
|
use wasmer_runtime_core::vm::Ctx;
|
||||||
|
|
||||||
use super::env;
|
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::slice;
|
|
||||||
|
|
||||||
// Linking to functions that are not provided by rust libc
|
// Linking to functions that are not provided by rust libc
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
|
@ -1,16 +1,18 @@
|
|||||||
use super::utils::{copy_cstr_into_wasm, write_to_buf};
|
use super::utils::{copy_cstr_into_wasm, write_to_buf};
|
||||||
use libc::{c_char, c_int, time_t};
|
use libc::{c_char, c_int};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::time::SystemTime;
|
use std::time::SystemTime;
|
||||||
|
|
||||||
#[cfg(not(target_os = "windows"))]
|
#[cfg(not(target_os = "windows"))]
|
||||||
use libc::{clockid_t, time as libc_time};
|
use libc::{clockid_t, time as libc_time};
|
||||||
|
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
use libc::time_t;
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
type clockid_t = c_int;
|
type clockid_t = c_int;
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
#[link(name = "c")]
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#[link_name = "time"]
|
#[link_name = "time"]
|
||||||
pub fn libc_time(s: *const time_t) -> time_t;
|
pub fn libc_time(s: *const time_t) -> time_t;
|
||||||
|
@ -2,10 +2,8 @@ use super::env;
|
|||||||
use super::env::get_emscripten_data;
|
use super::env::get_emscripten_data;
|
||||||
use libc::stat;
|
use libc::stat;
|
||||||
use std::ffi::CStr;
|
use std::ffi::CStr;
|
||||||
use std::ffi::CString;
|
|
||||||
use std::mem::size_of;
|
use std::mem::size_of;
|
||||||
use std::os::raw::c_char;
|
use std::os::raw::c_char;
|
||||||
use std::os::raw::c_int;
|
|
||||||
use std::slice;
|
use std::slice;
|
||||||
use wasmer_runtime_core::memory::Memory;
|
use wasmer_runtime_core::memory::Memory;
|
||||||
use wasmer_runtime_core::{
|
use wasmer_runtime_core::{
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
#[test]
|
#[test]
|
||||||
#[ignore]
|
|
||||||
fn test_env() {
|
fn test_env() {
|
||||||
assert_emscripten_output!(
|
assert_emscripten_output!(
|
||||||
"../../emtests/env.wasm",
|
"../../emtests/env.wasm",
|
||||||
|
@ -83,6 +83,12 @@ pub trait ProtectedCaller: Send + Sync {
|
|||||||
vmctx: *mut vm::Ctx,
|
vmctx: *mut vm::Ctx,
|
||||||
_: Token,
|
_: Token,
|
||||||
) -> RuntimeResult<Vec<Value>>;
|
) -> RuntimeResult<Vec<Value>>;
|
||||||
|
|
||||||
|
fn get_early_trapper(&self) -> Box<dyn UserTrapper>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait UserTrapper {
|
||||||
|
unsafe fn do_early_trap(&self, msg: String) -> !;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait FuncResolver: Send + Sync {
|
pub trait FuncResolver: Send + Sync {
|
||||||
|
@ -106,6 +106,9 @@ pub enum RuntimeError {
|
|||||||
table: TableIndex,
|
table: TableIndex,
|
||||||
},
|
},
|
||||||
IllegalArithmeticOperation,
|
IllegalArithmeticOperation,
|
||||||
|
User {
|
||||||
|
msg: String,
|
||||||
|
},
|
||||||
Unknown {
|
Unknown {
|
||||||
msg: String,
|
msg: String,
|
||||||
},
|
},
|
||||||
|
@ -7,7 +7,6 @@ use crate::{
|
|||||||
import::{ImportObject, LikeNamespace},
|
import::{ImportObject, LikeNamespace},
|
||||||
memory::Memory,
|
memory::Memory,
|
||||||
module::{ExportIndex, Module, ModuleInner},
|
module::{ExportIndex, Module, ModuleInner},
|
||||||
sig_registry::SigRegistry,
|
|
||||||
table::Table,
|
table::Table,
|
||||||
typed_func::{Func, Safe, WasmTypeList},
|
typed_func::{Func, Safe, WasmTypeList},
|
||||||
types::{FuncIndex, FuncSig, GlobalIndex, LocalOrImport, MemoryIndex, TableIndex, Value},
|
types::{FuncIndex, FuncSig, GlobalIndex, LocalOrImport, MemoryIndex, TableIndex, Value},
|
||||||
|
@ -3,6 +3,7 @@ use crate::{
|
|||||||
error::Result,
|
error::Result,
|
||||||
import::ImportObject,
|
import::ImportObject,
|
||||||
structures::{Map, TypedIndex},
|
structures::{Map, TypedIndex},
|
||||||
|
typed_func::EARLY_TRAPPER,
|
||||||
types::{
|
types::{
|
||||||
FuncIndex, FuncSig, GlobalDescriptor, GlobalIndex, GlobalInit, ImportedFuncIndex,
|
FuncIndex, FuncSig, GlobalDescriptor, GlobalIndex, GlobalInit, ImportedFuncIndex,
|
||||||
ImportedGlobalIndex, ImportedMemoryIndex, ImportedTableIndex, Initializer,
|
ImportedGlobalIndex, ImportedMemoryIndex, ImportedTableIndex, Initializer,
|
||||||
@ -63,6 +64,10 @@ pub struct Module(#[doc(hidden)] pub Arc<ModuleInner>);
|
|||||||
|
|
||||||
impl Module {
|
impl Module {
|
||||||
pub(crate) fn new(inner: Arc<ModuleInner>) -> Self {
|
pub(crate) fn new(inner: Arc<ModuleInner>) -> Self {
|
||||||
|
unsafe {
|
||||||
|
EARLY_TRAPPER
|
||||||
|
.with(|ucell| *ucell.get() = Some(inner.protected_caller.get_early_trapper()));
|
||||||
|
}
|
||||||
Module(inner)
|
Module(inner)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,6 +18,32 @@ pub struct Memory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Memory {
|
impl Memory {
|
||||||
|
pub fn with_size_protect(size: usize, protection: Protect) -> Result<Self, String> {
|
||||||
|
if size == 0 {
|
||||||
|
return Ok(Self {
|
||||||
|
ptr: ptr::null_mut(),
|
||||||
|
size: 0,
|
||||||
|
protection,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let size = round_up_to_page_size(size, page_size::get());
|
||||||
|
|
||||||
|
let protect = protection.to_protect_const();
|
||||||
|
|
||||||
|
let ptr = unsafe { VirtualAlloc(ptr::null_mut(), size, MEM_RESERVE, protect) };
|
||||||
|
|
||||||
|
if ptr.is_null() {
|
||||||
|
Err("unable to allocate memory".to_string())
|
||||||
|
} else {
|
||||||
|
Ok(Self {
|
||||||
|
ptr: ptr as *mut u8,
|
||||||
|
size,
|
||||||
|
protection,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn with_size(size: usize) -> Result<Self, String> {
|
pub fn with_size(size: usize) -> Result<Self, String> {
|
||||||
if size == 0 {
|
if size == 0 {
|
||||||
return Ok(Self {
|
return Ok(Self {
|
||||||
|
@ -1,11 +1,16 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
|
backend::UserTrapper,
|
||||||
error::RuntimeError,
|
error::RuntimeError,
|
||||||
export::{Context, Export, FuncPointer},
|
export::{Context, Export, FuncPointer},
|
||||||
import::IsExport,
|
import::IsExport,
|
||||||
types::{FuncSig, Type, WasmExternType},
|
types::{FuncSig, Type, WasmExternType},
|
||||||
vm::Ctx,
|
vm::Ctx,
|
||||||
};
|
};
|
||||||
use std::{marker::PhantomData, mem, ptr, sync::Arc};
|
use std::{cell::UnsafeCell, fmt, marker::PhantomData, mem, panic, ptr, sync::Arc};
|
||||||
|
|
||||||
|
thread_local! {
|
||||||
|
pub static EARLY_TRAPPER: UnsafeCell<Option<Box<dyn UserTrapper>>> = UnsafeCell::new(None);
|
||||||
|
}
|
||||||
|
|
||||||
pub trait Safeness {}
|
pub trait Safeness {}
|
||||||
pub struct Safe;
|
pub struct Safe;
|
||||||
@ -28,9 +33,44 @@ where
|
|||||||
Args: WasmTypeList,
|
Args: WasmTypeList,
|
||||||
Rets: WasmTypeList,
|
Rets: WasmTypeList,
|
||||||
{
|
{
|
||||||
fn to_raw(self) -> *const ();
|
fn to_raw(&self) -> *const ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait TrapEarly<Rets>
|
||||||
|
where
|
||||||
|
Rets: WasmTypeList,
|
||||||
|
{
|
||||||
|
fn report(self) -> Result<Rets, String>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Rets> TrapEarly<Rets> for Rets
|
||||||
|
where
|
||||||
|
Rets: WasmTypeList,
|
||||||
|
{
|
||||||
|
fn report(self) -> Result<Rets, String> {
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Rets, E> TrapEarly<Rets> for Result<Rets, E>
|
||||||
|
where
|
||||||
|
Rets: WasmTypeList,
|
||||||
|
E: fmt::Debug,
|
||||||
|
{
|
||||||
|
fn report(self) -> Result<Rets, String> {
|
||||||
|
self.map_err(|err| format!("Error: {:?}", err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// pub fn Func<'a, Args, Rets, F>(f: F) -> Func<'a, Args, Rets, Unsafe>
|
||||||
|
// where
|
||||||
|
// Args: WasmTypeList,
|
||||||
|
// Rets: WasmTypeList,
|
||||||
|
// F: ExternalFunction<Args, Rets>
|
||||||
|
// {
|
||||||
|
// Func::new(f)
|
||||||
|
// }
|
||||||
|
|
||||||
pub struct Func<'a, Args = (), Rets = (), Safety: Safeness = Safe> {
|
pub struct Func<'a, Args = (), Rets = (), Safety: Safeness = Safe> {
|
||||||
f: *const (),
|
f: *const (),
|
||||||
ctx: *mut Ctx,
|
ctx: *mut Ctx,
|
||||||
@ -143,18 +183,41 @@ macro_rules! impl_traits {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl< $( $x: WasmExternType, )* Rets: WasmTypeList, FN: Fn( $( $x, )* &mut Ctx) -> Rets> ExternalFunction<($( $x ),*), Rets> for FN {
|
impl< $( $x: WasmExternType, )* Rets: WasmTypeList, Trap: TrapEarly<Rets>, FN: Fn( $( $x, )* &mut Ctx) -> Trap> ExternalFunction<($( $x ),*), Rets> for FN {
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
fn to_raw(self) -> *const () {
|
fn to_raw(&self) -> *const () {
|
||||||
assert_eq!(mem::size_of::<Self>(), 0, "you cannot use a closure that captures state for `Func`.");
|
assert_eq!(mem::size_of::<Self>(), 0, "you cannot use a closure that captures state for `Func`.");
|
||||||
|
|
||||||
extern fn wrap<$( $x: WasmExternType, )* Rets: WasmTypeList, FN: Fn( $( $x, )* &mut Ctx) -> Rets>( $( $x: $x, )* ctx: &mut Ctx) -> Rets::CStruct {
|
extern fn wrap<$( $x: WasmExternType, )* Rets: WasmTypeList, Trap: TrapEarly<Rets>, FN: Fn( $( $x, )* &mut Ctx) -> Trap>( $( $x: $x, )* ctx: &mut Ctx) -> Rets::CStruct {
|
||||||
let f: FN = unsafe { mem::transmute_copy(&()) };
|
let f: FN = unsafe { mem::transmute_copy(&()) };
|
||||||
let rets = f( $( $x, )* ctx);
|
|
||||||
rets.into_c_struct()
|
let msg = match panic::catch_unwind(panic::AssertUnwindSafe(|| {
|
||||||
|
f( $( $x, )* ctx).report()
|
||||||
|
})) {
|
||||||
|
Ok(Ok(returns)) => return returns.into_c_struct(),
|
||||||
|
Ok(Err(err)) => err,
|
||||||
|
Err(err) => {
|
||||||
|
if let Some(s) = err.downcast_ref::<&str>() {
|
||||||
|
s.to_string()
|
||||||
|
} else if let Some(s) = err.downcast_ref::<String>() {
|
||||||
|
s.clone()
|
||||||
|
} else {
|
||||||
|
"a panic occurred, but no additional information is available".to_string()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
if let Some(early_trapper) = &*EARLY_TRAPPER.with(|ucell| ucell.get()) {
|
||||||
|
early_trapper.do_early_trap(msg)
|
||||||
|
} else {
|
||||||
|
eprintln!("panic handling not setup");
|
||||||
|
std::process::exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
wrap::<$( $x, )* Rets, Self> as *const ()
|
wrap::<$( $x, )* Rets, Trap, Self> as *const ()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -493,7 +493,7 @@ mod vm_ctx_tests {
|
|||||||
|
|
||||||
fn generate_module() -> ModuleInner {
|
fn generate_module() -> ModuleInner {
|
||||||
use super::Func;
|
use super::Func;
|
||||||
use crate::backend::{Backend, FuncResolver, ProtectedCaller, Token};
|
use crate::backend::{Backend, FuncResolver, ProtectedCaller, Token, UserTrapper};
|
||||||
use crate::error::RuntimeResult;
|
use crate::error::RuntimeResult;
|
||||||
use crate::types::{FuncIndex, LocalFuncIndex, Value};
|
use crate::types::{FuncIndex, LocalFuncIndex, Value};
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
@ -520,6 +520,9 @@ mod vm_ctx_tests {
|
|||||||
) -> RuntimeResult<Vec<Value>> {
|
) -> RuntimeResult<Vec<Value>> {
|
||||||
Ok(vec![])
|
Ok(vec![])
|
||||||
}
|
}
|
||||||
|
fn get_early_trapper(&self) -> Box<dyn UserTrapper> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ModuleInner {
|
ModuleInner {
|
||||||
|
@ -3,7 +3,7 @@ use wabt::wat2wasm;
|
|||||||
use wasmer_clif_backend::CraneliftCompiler;
|
use wasmer_clif_backend::CraneliftCompiler;
|
||||||
use wasmer_runtime_core::{
|
use wasmer_runtime_core::{
|
||||||
cache::Cache,
|
cache::Cache,
|
||||||
error::Result,
|
error,
|
||||||
global::Global,
|
global::Global,
|
||||||
memory::Memory,
|
memory::Memory,
|
||||||
prelude::*,
|
prelude::*,
|
||||||
@ -14,7 +14,7 @@ use wasmer_runtime_core::{
|
|||||||
|
|
||||||
static EXAMPLE_WASM: &'static [u8] = include_bytes!("simple.wasm");
|
static EXAMPLE_WASM: &'static [u8] = include_bytes!("simple.wasm");
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> error::Result<()> {
|
||||||
let compiler = CraneliftCompiler::new();
|
let compiler = CraneliftCompiler::new();
|
||||||
let wasm_binary = wat2wasm(IMPORT_MODULE.as_bytes()).expect("WAST not valid or malformed");
|
let wasm_binary = wat2wasm(IMPORT_MODULE.as_bytes()).expect("WAST not valid or malformed");
|
||||||
|
|
||||||
@ -61,14 +61,14 @@ fn main() -> Result<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_num(n: i32, ctx: &mut vm::Ctx) -> i32 {
|
fn print_num(n: i32, ctx: &mut vm::Ctx) -> Result<i32, ()> {
|
||||||
println!("print_num({})", n);
|
println!("print_num({})", n);
|
||||||
|
|
||||||
let memory: &Memory = ctx.memory(0);
|
let memory: &Memory = ctx.memory(0);
|
||||||
|
|
||||||
let a: i32 = memory.view()[0].get();
|
let a: i32 = memory.view()[0].get();
|
||||||
|
|
||||||
a + n + 1
|
Ok(a + n + 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
static IMPORT_MODULE: &str = r#"
|
static IMPORT_MODULE: &str = r#"
|
||||||
|
Reference in New Issue
Block a user