Merge master into feature/llvm-backend

This commit is contained in:
Lachlan Sneff 2019-02-14 15:47:28 -08:00
commit 2d87f64f82
55 changed files with 815 additions and 1693 deletions

View File

@ -1,151 +1,47 @@
# This appveyor build file is heavily inspired by uutils/coreutils
# https://raw.githubusercontent.com/uutils/coreutils/d0db7bbaa46dabf65b71e3e33b1ed7595aaacc56/.appveyor.yml
branches:
except:
- master
version: "{build} ~ {branch}" version: "{build} ~ {branch}"
os: Visual Studio 2017 os: Visual Studio 2017
matrix: # Do not build feature branch with open Pull Requests
allow_failures: skip_branch_with_pr: true
- 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:
- path: target\%TARGET%\debug\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% - cd ./lib/spectests && cargo test -- --test-threads 1 && cd ../..
before_deploy:
- cd installer
- iscc wasmer.iss
- copy /y .\WasmerInstaller.exe ..\WasmerInstaller-%APPVEYOR_REPO_TAG_NAME%.exe
- appveyor PushArtifact WasmerInstaller-%APPVEYOR_REPO_TAG_NAME%.exe
artifacts:
- path: WasmerInstaller-%APPVEYOR_REPO_TAG_NAME%.exe
name: WasmerInstaller.exe
deploy:
description: 'WasmerInstaller'
artifact: /.*\.exe/
auth_token:
secure: CaKtncy7S1PWxzDUQ0p2264pe3HwxzDn5VIyRizDaa72/SVfskNcoMjwwRh0ut22
provider: GitHub
on:
branch: master
appveyor_repo_tag: true

View File

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

1173
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -27,7 +27,7 @@ wasmer-runtime-core = { path = "lib/runtime-core" }
wasmer-emscripten = { path = "lib/emscripten" } wasmer-emscripten = { path = "lib/emscripten" }
[workspace] [workspace]
members = ["lib/clif-backend", "lib/runtime", "lib/runtime-core", "lib/emscripten", "lib/spectests", "lib/llvm-backend"] members = ["lib/clif-backend", "lib/runtime", "lib/runtime-core", "lib/emscripten", "lib/spectests", "lib/win-exception-handler", "lib/llvm-backend"]
[build-dependencies] [build-dependencies]
wabt = "0.7.2" wabt = "0.7.2"

View File

@ -23,7 +23,7 @@ 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:

View File

@ -47,10 +47,10 @@ Wasmer is structured into different directories:
Building wasmer requires [rustup](https://rustup.rs/). Building wasmer requires [rustup](https://rustup.rs/).
To install on Windows, download and run [`rustup-init.exe`](https://win.rustup.rs/) To build on Windows, download and run [`rustup-init.exe`](https://win.rustup.rs/)
then follow the onscreen instructions. then follow the onscreen instructions.
To install on other systems, run: To build on other systems, run:
```sh ```sh
curl https://sh.rustup.rs -sSf | sh curl https://sh.rustup.rs -sSf | sh
@ -86,8 +86,8 @@ sudo apt install cmake
#### Windows (MSVC) #### Windows (MSVC)
Right now Windows support is _highly experimental_. Windows support is _highly experimental_. Only simple wasm programs may be run, and no syscalls are allowed. This means
We are working on this so Wasmer can soon be released for Windows. nginx and lua do not work on Windows. See [this issue for ongoing Emscripten syscall polyfills for Windows](https://github.com/wasmerio/wasmer/pull/176).
1. Install Python for Windows (https://www.python.org/downloads/release/python-2714/). The Windows x86-64 MSI installer is fine. 1. Install Python for Windows (https://www.python.org/downloads/release/python-2714/). The Windows x86-64 MSI installer is fine.
You should change the installation to install the "Add python.exe to Path" feature. You should change the installation to install the "Add python.exe to Path" feature.
@ -95,6 +95,8 @@ We are working on this so Wasmer can soon be released for Windows.
2. Install Git for Windows (https://git-scm.com/download/win). DO allow it to add git.exe to the PATH (default 2. Install Git for Windows (https://git-scm.com/download/win). DO allow it to add git.exe to the PATH (default
settings for the installer are fine). settings for the installer are fine).
3. Install CMake (https://cmake.org/download/). Ensure CMake is in the PATH.
## Building ## Building
Wasmer is built with [Cargo](https://crates.io/), the Rust package manager. Wasmer is built with [Cargo](https://crates.io/), the Rust package manager.

71
installer/wasmer.iss Normal file
View File

@ -0,0 +1,71 @@
[Setup]
AppName=Wasmer
AppVersion=1.5
DefaultDirName={pf}\Wasmer
DefaultGroupName=Wasmer
Compression=lzma2
SolidCompression=yes
OutputDir=.\
DisableProgramGroupPage=yes
ChangesEnvironment=yes
OutputBaseFilename=WasmerInstaller
[Files]
Source: "..\target\release\wasmer.exe"; DestDir: "{app}\bin"
[Code]
const EnvironmentKey = 'SYSTEM\CurrentControlSet\Control\Session Manager\Environment';
procedure EnvAddPath(Path: string);
var
Paths: string;
begin
{ Retrieve current path (use empty string if entry not exists) }
if not RegQueryStringValue(HKEY_LOCAL_MACHINE, EnvironmentKey, 'Path', Paths)
then Paths := '';
{ Skip if string already found in path }
if Pos(';' + Uppercase(Path) + ';', ';' + Uppercase(Paths) + ';') > 0 then exit;
{ App string to the end of the path variable }
Paths := Paths + ';'+ Path +';'
{ Overwrite (or create if missing) path environment variable }
if RegWriteStringValue(HKEY_LOCAL_MACHINE, EnvironmentKey, 'Path', Paths)
then Log(Format('The [%s] added to PATH: [%s]', [Path, Paths]))
else Log(Format('Error while adding the [%s] to PATH: [%s]', [Path, Paths]));
end;
procedure EnvRemovePath(Path: string);
var
Paths: string;
P: Integer;
begin
{ Skip if registry entry not exists }
if not RegQueryStringValue(HKEY_LOCAL_MACHINE, EnvironmentKey, 'Path', Paths) then
exit;
{ Skip if string not found in path }
P := Pos(';' + Uppercase(Path) + ';', ';' + Uppercase(Paths) + ';');
if P = 0 then exit;
{ Update path variable }
Delete(Paths, P - 1, Length(Path) + 1);
{ Overwrite path environment variable }
if RegWriteStringValue(HKEY_LOCAL_MACHINE, EnvironmentKey, 'Path', Paths)
then Log(Format('The [%s] removed from PATH: [%s]', [Path, Paths]))
else Log(Format('Error while removing the [%s] from PATH: [%s]', [Path, Paths]));
end;
procedure CurStepChanged(CurStep: TSetupStep);
begin
if CurStep = ssPostInstall
then EnvAddPath(ExpandConstant('{app}') +'\bin');
end;
procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
begin
if CurUninstallStep = usPostUninstall
then EnvRemovePath(ExpandConstant('{app}') +'\bin');
end;

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

View File

@ -37,6 +37,10 @@ optional = true
version = "0.0.7" version = "0.0.7"
optional = true optional = true
[target.'cfg(windows)'.dependencies]
winapi = { version = "0.3", features = ["errhandlingapi", "minwindef", "minwinbase", "winnt"] }
wasmer-win-exception-handler = { path = "../win-exception-handler", version = "0.0.1" }
[features] [features]
cache = ["serde", "serde_derive", "serde_bytes", "serde-bench", "wasmer-runtime-core/cache"] cache = ["serde", "serde_derive", "serde_bytes", "serde-bench", "wasmer-runtime-core/cache"]
debug = ["wasmer-runtime-core/debug"] debug = ["wasmer-runtime-core/debug"]

View File

@ -32,10 +32,10 @@ impl<'env, 'module, 'isa> FuncEnv<'env, 'module, 'isa> {
let mut signature = self.env.signatures[Converter(clif_sig_index).into()].clone(); let mut signature = self.env.signatures[Converter(clif_sig_index).into()].clone();
// Add the vmctx parameter type to it // Add the vmctx parameter type to it
signature.params.push(ir::AbiParam::special( signature.params.insert(
self.pointer_type(), 0,
ir::ArgumentPurpose::VMContext, ir::AbiParam::special(self.pointer_type(), ir::ArgumentPurpose::VMContext),
)); );
// Return signature // Return signature
signature signature
@ -461,8 +461,8 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> {
// Build a value list for the indirect call instruction containing the call_args // Build a value list for the indirect call instruction containing the call_args
// and the vmctx parameter. // and the vmctx parameter.
let mut args = Vec::with_capacity(call_args.len() + 1); let mut args = Vec::with_capacity(call_args.len() + 1);
args.extend(call_args.iter().cloned());
args.push(vmctx_ptr); args.push(vmctx_ptr);
args.extend(call_args.iter().cloned());
Ok(pos.ins().call_indirect(sig_ref, func_ptr, &args)) Ok(pos.ins().call_indirect(sig_ref, func_ptr, &args))
} }
@ -487,8 +487,8 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> {
.expect("missing vmctx parameter"); .expect("missing vmctx parameter");
let mut args = Vec::with_capacity(call_args.len() + 1); let mut args = Vec::with_capacity(call_args.len() + 1);
args.extend(call_args.iter().cloned());
args.push(vmctx); args.push(vmctx);
args.extend(call_args.iter().cloned());
Ok(pos.ins().call(callee, &args)) Ok(pos.ins().call(callee, &args))
} }
@ -534,8 +534,8 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> {
let sig_ref = pos.func.dfg.ext_funcs[callee].signature; let sig_ref = pos.func.dfg.ext_funcs[callee].signature;
let mut args = Vec::with_capacity(call_args.len() + 1); let mut args = Vec::with_capacity(call_args.len() + 1);
args.extend(call_args.iter().cloned());
args.push(imported_vmctx_addr); args.push(imported_vmctx_addr);
args.extend(call_args.iter().cloned());
Ok(pos Ok(pos
.ins() .ins()
@ -561,9 +561,9 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> {
let signature = pos.func.import_signature(ir::Signature { let signature = pos.func.import_signature(ir::Signature {
call_conv: self.target_config().default_call_conv, call_conv: self.target_config().default_call_conv,
params: vec![ params: vec![
ir::AbiParam::new(ir::types::I32),
ir::AbiParam::new(ir::types::I32),
ir::AbiParam::special(self.pointer_type(), ir::ArgumentPurpose::VMContext), ir::AbiParam::special(self.pointer_type(), ir::ArgumentPurpose::VMContext),
ir::AbiParam::new(ir::types::I32),
ir::AbiParam::new(ir::types::I32),
], ],
returns: vec![ir::AbiParam::new(ir::types::I32)], returns: vec![ir::AbiParam::new(ir::types::I32)],
}); });
@ -607,7 +607,7 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> {
let call_inst = pos let call_inst = pos
.ins() .ins()
.call(mem_grow_func, &[const_mem_index, by_value, vmctx]); .call(mem_grow_func, &[vmctx, const_mem_index, by_value]);
Ok(*pos.func.dfg.inst_results(call_inst).first().unwrap()) Ok(*pos.func.dfg.inst_results(call_inst).first().unwrap())
} }
@ -626,8 +626,8 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> {
let signature = pos.func.import_signature(ir::Signature { let signature = pos.func.import_signature(ir::Signature {
call_conv: self.target_config().default_call_conv, call_conv: self.target_config().default_call_conv,
params: vec![ params: vec![
ir::AbiParam::new(ir::types::I32),
ir::AbiParam::special(self.pointer_type(), ir::ArgumentPurpose::VMContext), ir::AbiParam::special(self.pointer_type(), ir::ArgumentPurpose::VMContext),
ir::AbiParam::new(ir::types::I32),
], ],
returns: vec![ir::AbiParam::new(ir::types::I32)], returns: vec![ir::AbiParam::new(ir::types::I32)],
}); });
@ -668,7 +668,7 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> {
.special_param(ir::ArgumentPurpose::VMContext) .special_param(ir::ArgumentPurpose::VMContext)
.expect("missing vmctx parameter"); .expect("missing vmctx parameter");
let call_inst = pos.ins().call(mem_grow_func, &[const_mem_index, vmctx]); let call_inst = pos.ins().call(mem_grow_func, &[vmctx, const_mem_index]);
Ok(*pos.func.dfg.inst_results(call_inst).first().unwrap()) Ok(*pos.func.dfg.inst_results(call_inst).first().unwrap())
} }

View File

@ -416,8 +416,8 @@ impl<'module, 'isa, 'data> ModuleEnvironment<'data> for ModuleEnv<'module, 'isa>
let signature = pos.func.import_signature(ir::Signature { let signature = pos.func.import_signature(ir::Signature {
call_conv: self.target_config().default_call_conv, call_conv: self.target_config().default_call_conv,
params: vec![ params: vec![
ir::AbiParam::new(ir::types::I32),
ir::AbiParam::special(ir::types::I64, ir::ArgumentPurpose::VMContext), ir::AbiParam::special(ir::types::I64, ir::ArgumentPurpose::VMContext),
ir::AbiParam::new(ir::types::I32),
], ],
returns: vec![], returns: vec![],
}); });
@ -454,8 +454,8 @@ impl<'module, 'isa, 'data> ModuleEnvironment<'data> for ModuleEnv<'module, 'isa>
let signature = pos.func.import_signature(ir::Signature { let signature = pos.func.import_signature(ir::Signature {
call_conv: self.target_config().default_call_conv, call_conv: self.target_config().default_call_conv,
params: vec![ params: vec![
ir::AbiParam::new(ir::types::I32),
ir::AbiParam::special(ir::types::I64, ir::ArgumentPurpose::VMContext), ir::AbiParam::special(ir::types::I64, ir::ArgumentPurpose::VMContext),
ir::AbiParam::new(ir::types::I32),
], ],
returns: vec![], returns: vec![],
}); });
@ -473,8 +473,8 @@ impl<'module, 'isa, 'data> ModuleEnvironment<'data> for ModuleEnv<'module, 'isa>
let signature = pos.func.import_signature(ir::Signature { let signature = pos.func.import_signature(ir::Signature {
call_conv: self.target_config().default_call_conv, call_conv: self.target_config().default_call_conv,
params: vec![ params: vec![
ir::AbiParam::new(ir::types::I64),
ir::AbiParam::special(ir::types::I64, ir::ArgumentPurpose::VMContext), ir::AbiParam::special(ir::types::I64, ir::ArgumentPurpose::VMContext),
ir::AbiParam::new(ir::types::I64),
], ],
returns: vec![], returns: vec![],
}); });
@ -492,8 +492,8 @@ impl<'module, 'isa, 'data> ModuleEnvironment<'data> for ModuleEnv<'module, 'isa>
let signature = pos.func.import_signature(ir::Signature { let signature = pos.func.import_signature(ir::Signature {
call_conv: self.target_config().default_call_conv, call_conv: self.target_config().default_call_conv,
params: vec![ params: vec![
ir::AbiParam::new(ir::types::F32),
ir::AbiParam::special(ir::types::I64, ir::ArgumentPurpose::VMContext), ir::AbiParam::special(ir::types::I64, ir::ArgumentPurpose::VMContext),
ir::AbiParam::new(ir::types::F32),
], ],
returns: vec![], returns: vec![],
}); });
@ -511,8 +511,8 @@ impl<'module, 'isa, 'data> ModuleEnvironment<'data> for ModuleEnv<'module, 'isa>
let signature = pos.func.import_signature(ir::Signature { let signature = pos.func.import_signature(ir::Signature {
call_conv: self.target_config().default_call_conv, call_conv: self.target_config().default_call_conv,
params: vec![ params: vec![
ir::AbiParam::new(ir::types::F64),
ir::AbiParam::special(ir::types::I64, ir::ArgumentPurpose::VMContext), ir::AbiParam::special(ir::types::I64, ir::ArgumentPurpose::VMContext),
ir::AbiParam::new(ir::types::F64),
], ],
returns: vec![], returns: vec![],
}); });
@ -533,14 +533,14 @@ impl<'module, 'isa, 'data> ModuleEnvironment<'data> for ModuleEnv<'module, 'isa>
let func_index = pos.ins().iconst(ir::types::I32, func_index.index() as i64); let func_index = pos.ins().iconst(ir::types::I32, func_index.index() as i64);
pos.ins().call(start_debug, &[func_index, vmctx]); pos.ins().call(start_debug, &[vmctx, func_index]);
for param in new_ebb_params.iter().cloned() { for param in new_ebb_params.iter().cloned() {
match pos.func.dfg.value_type(param) { match pos.func.dfg.value_type(param) {
ir::types::I32 => pos.ins().call(i32_print, &[param, vmctx]), ir::types::I32 => pos.ins().call(i32_print, &[vmctx, param]),
ir::types::I64 => pos.ins().call(i64_print, &[param, vmctx]), ir::types::I64 => pos.ins().call(i64_print, &[vmctx, param]),
ir::types::F32 => pos.ins().call(f32_print, &[param, vmctx]), ir::types::F32 => pos.ins().call(f32_print, &[vmctx, param]),
ir::types::F64 => pos.ins().call(f64_print, &[param, vmctx]), ir::types::F64 => pos.ins().call(f64_print, &[vmctx, param]),
_ => unimplemented!(), _ => unimplemented!(),
}; };
} }

View File

@ -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"))]
LibCall::Probestack => __chkstk as isize,
#[cfg(not(target_os = "windows"))]
LibCall::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,
@ -340,21 +350,21 @@ fn round_up(n: usize, multiple: usize) -> usize {
(n + multiple - 1) & !(multiple - 1) (n + multiple - 1) & !(multiple - 1)
} }
extern "C" fn i32_print(n: i32) { extern "C" fn i32_print(_ctx: &mut vm::Ctx, n: i32) {
print!(" i32: {},", n); print!(" i32: {},", n);
} }
extern "C" fn i64_print(n: i64) { extern "C" fn i64_print(_ctx: &mut vm::Ctx, n: i64) {
print!(" i64: {},", n); print!(" i64: {},", n);
} }
extern "C" fn f32_print(n: f32) { extern "C" fn f32_print(_ctx: &mut vm::Ctx, n: f32) {
print!(" f32: {},", n); print!(" f32: {},", n);
} }
extern "C" fn f64_print(n: f64) { extern "C" fn f64_print(_ctx: &mut vm::Ctx, n: f64) {
print!(" f64: {},", n); print!(" f64: {},", n);
} }
extern "C" fn start_debug(func_index: u32) { extern "C" fn start_debug(_ctx: &mut vm::Ctx, func_index: u32) {
print!("func ({}), args: [", func_index); print!("func ({}), args: [", func_index);
} }
extern "C" fn end_debug() { extern "C" fn end_debug(_ctx: &mut vm::Ctx) {
println!(" ]"); println!(" ]");
} }

View File

@ -110,6 +110,7 @@ impl ProtectedCaller for Caller {
.lookup(sig_index) .lookup(sig_index)
.expect("that trampoline doesn't exist"); .expect("that trampoline doesn't exist");
#[cfg(not(target_os = "windows"))]
call_protected(&self.handler_data, || unsafe { call_protected(&self.handler_data, || unsafe {
// Leap of faith. // Leap of faith.
trampoline( trampoline(
@ -120,6 +121,17 @@ impl ProtectedCaller for Caller {
); );
})?; })?;
// the trampoline is called from C on windows
#[cfg(target_os = "windows")]
call_protected(
&self.handler_data,
trampoline,
vmctx_ptr,
func_ptr,
param_vec.as_ptr(),
return_vec.as_mut_ptr(),
)?;
Ok(return_vec Ok(return_vec
.iter() .iter()
.zip(signature.returns().iter()) .zip(signature.returns().iter())

View File

@ -1,6 +1,116 @@
use crate::relocation::{TrapCode, TrapData};
use crate::signal::HandlerData; use crate::signal::HandlerData;
use wasmer_runtime_core::error::RuntimeResult; use crate::trampoline::Trampoline;
use std::cell::Cell;
use std::ffi::c_void;
use std::ptr;
use wasmer_runtime_core::vm::Ctx;
use wasmer_runtime_core::vm::Func;
use wasmer_runtime_core::{
error::{RuntimeError, RuntimeResult},
structures::TypedIndex,
types::{MemoryIndex, TableIndex},
};
use wasmer_win_exception_handler::CallProtectedData;
pub use wasmer_win_exception_handler::_call_protected;
use winapi::shared::minwindef::DWORD;
use winapi::um::minwinbase::{
EXCEPTION_ACCESS_VIOLATION, EXCEPTION_FLT_DENORMAL_OPERAND, EXCEPTION_FLT_DIVIDE_BY_ZERO,
EXCEPTION_FLT_INEXACT_RESULT, EXCEPTION_FLT_INVALID_OPERATION, EXCEPTION_FLT_OVERFLOW,
EXCEPTION_FLT_STACK_CHECK, EXCEPTION_FLT_UNDERFLOW, EXCEPTION_ILLEGAL_INSTRUCTION,
EXCEPTION_INT_DIVIDE_BY_ZERO, EXCEPTION_INT_OVERFLOW, EXCEPTION_STACK_OVERFLOW,
};
pub fn call_protected<T>(handler_data: &HandlerData, f: impl FnOnce() -> T) -> RuntimeResult<T> { thread_local! {
unimplemented!("TODO"); pub static CURRENT_EXECUTABLE_BUFFER: Cell<*const c_void> = Cell::new(ptr::null());
}
pub fn call_protected(
handler_data: &HandlerData,
trampoline: Trampoline,
ctx: *mut Ctx,
func: *const Func,
param_vec: *const u64,
return_vec: *mut u64,
) -> RuntimeResult<()> {
// TODO: trap early
// user code error
// if let Some(msg) = super::TRAP_EARLY_DATA.with(|cell| cell.replace(None)) {
// return Err(RuntimeError::User { msg });
// }
let result = _call_protected(trampoline, ctx, func, param_vec, return_vec);
if let Ok(_) = result {
return Ok(());
}
let CallProtectedData {
code: signum,
exceptionAddress: exception_address,
instructionPointer: instruction_pointer,
} = result.unwrap_err();
if let Some(TrapData {
trapcode,
srcloc: _,
}) = handler_data.lookup(instruction_pointer as _)
{
Err(match signum as DWORD {
EXCEPTION_ACCESS_VIOLATION => RuntimeError::OutOfBoundsAccess {
memory: MemoryIndex::new(0),
addr: None,
},
EXCEPTION_ILLEGAL_INSTRUCTION => 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(),
},
},
EXCEPTION_STACK_OVERFLOW => RuntimeError::Unknown {
msg: "unknown trap".to_string(),
},
EXCEPTION_INT_DIVIDE_BY_ZERO => RuntimeError::IllegalArithmeticOperation,
EXCEPTION_INT_OVERFLOW => RuntimeError::IllegalArithmeticOperation,
_ => RuntimeError::Unknown {
msg: "unknown trap".to_string(),
},
}
.into())
} else {
let signal = match signum as DWORD {
EXCEPTION_FLT_DENORMAL_OPERAND
| EXCEPTION_FLT_DIVIDE_BY_ZERO
| EXCEPTION_FLT_INEXACT_RESULT
| EXCEPTION_FLT_INVALID_OPERATION
| EXCEPTION_FLT_OVERFLOW
| EXCEPTION_FLT_STACK_CHECK
| EXCEPTION_FLT_UNDERFLOW => "floating-point exception",
EXCEPTION_ILLEGAL_INSTRUCTION => "illegal instruction",
EXCEPTION_ACCESS_VIOLATION => "segmentation violation",
_ => "unkown trapped signal",
};
Err(RuntimeError::Unknown {
msg: format!("trap at {} - {}", exception_address, signal),
}
.into())
}
}
pub unsafe fn trigger_trap() -> ! {
// TODO
unimplemented!();
} }

View File

@ -7,6 +7,7 @@ use cranelift_codegen::{
isa, Context, isa, Context,
}; };
use hashbrown::HashMap; use hashbrown::HashMap;
use std::ffi::c_void;
use std::{iter, mem}; use std::{iter, mem};
use wasmer_runtime_core::{ use wasmer_runtime_core::{
backend::sys::{Memory, Protect}, backend::sys::{Memory, Protect},
@ -23,6 +24,9 @@ impl RelocSink for NullRelocSink {
fn reloc_jt(&mut self, _: u32, _: Reloc, _: ir::JumpTable) {} fn reloc_jt(&mut self, _: u32, _: Reloc, _: ir::JumpTable) {}
} }
pub type Trampoline =
unsafe extern "C" fn(*mut vm::Ctx, *const vm::Func, *const u64, *mut u64) -> c_void;
pub struct Trampolines { pub struct Trampolines {
memory: Memory, memory: Memory,
offsets: HashMap<SigIndex, usize>, offsets: HashMap<SigIndex, usize>,
@ -138,10 +142,7 @@ impl Trampolines {
} }
} }
pub fn lookup( pub fn lookup(&self, sig_index: SigIndex) -> Option<Trampoline> {
&self,
sig_index: SigIndex,
) -> Option<unsafe extern "C" fn(*mut vm::Ctx, *const vm::Func, *const u64, *mut u64)> {
let offset = *self.offsets.get(&sig_index)?; let offset = *self.offsets.get(&sig_index)?;
let ptr = unsafe { self.memory.as_ptr().add(offset) }; let ptr = unsafe { self.memory.as_ptr().add(offset) };
@ -169,6 +170,7 @@ fn generate_func(func_sig: &FuncSig) -> ir::Function {
let mut pos = FuncCursor::new(&mut func).at_first_insertion_point(entry_ebb); let mut pos = FuncCursor::new(&mut func).at_first_insertion_point(entry_ebb);
let mut args_vec = Vec::with_capacity(func_sig.params().len() + 1); let mut args_vec = Vec::with_capacity(func_sig.params().len() + 1);
args_vec.push(vmctx_ptr);
for (index, wasm_ty) in func_sig.params().iter().enumerate() { for (index, wasm_ty) in func_sig.params().iter().enumerate() {
let mem_flags = ir::MemFlags::trusted(); let mem_flags = ir::MemFlags::trusted();
@ -180,7 +182,6 @@ fn generate_func(func_sig: &FuncSig) -> ir::Function {
); );
args_vec.push(val); args_vec.push(val);
} }
args_vec.push(vmctx_ptr);
let call_inst = pos.ins().call_indirect(export_sig_ref, func_ptr, &args_vec); let call_inst = pos.ins().call_indirect(export_sig_ref, func_ptr, &args_vec);
@ -212,7 +213,9 @@ fn wasm_ty_to_clif(ty: Type) -> ir::types::Type {
} }
fn generate_trampoline_signature() -> ir::Signature { fn generate_trampoline_signature() -> ir::Signature {
let mut sig = ir::Signature::new(isa::CallConv::SystemV); let isa = super::get_isa();
let call_convention = isa.default_call_conv();
let mut sig = ir::Signature::new(call_convention);
let ptr_param = ir::AbiParam { let ptr_param = ir::AbiParam {
value_type: ir::types::I64, value_type: ir::types::I64,
@ -227,23 +230,24 @@ fn generate_trampoline_signature() -> ir::Signature {
} }
fn generate_export_signature(func_sig: &FuncSig) -> ir::Signature { fn generate_export_signature(func_sig: &FuncSig) -> ir::Signature {
let mut export_clif_sig = ir::Signature::new(isa::CallConv::SystemV); let isa = super::get_isa();
let call_convention = isa.default_call_conv();
let mut export_clif_sig = ir::Signature::new(call_convention);
export_clif_sig.params = func_sig let func_sig_iter = func_sig.params().iter().map(|wasm_ty| ir::AbiParam {
.params()
.iter()
.map(|wasm_ty| ir::AbiParam {
value_type: wasm_ty_to_clif(*wasm_ty), value_type: wasm_ty_to_clif(*wasm_ty),
purpose: ir::ArgumentPurpose::Normal, purpose: ir::ArgumentPurpose::Normal,
extension: ir::ArgumentExtension::None, extension: ir::ArgumentExtension::None,
location: ir::ArgumentLoc::Unassigned, location: ir::ArgumentLoc::Unassigned,
}) });
.chain(iter::once(ir::AbiParam {
export_clif_sig.params = iter::once(ir::AbiParam {
value_type: ir::types::I64, value_type: ir::types::I64,
purpose: ir::ArgumentPurpose::VMContext, purpose: ir::ArgumentPurpose::VMContext,
extension: ir::ArgumentExtension::None, extension: ir::ArgumentExtension::None,
location: ir::ArgumentLoc::Unassigned, location: ir::ArgumentLoc::Unassigned,
})) })
.chain(func_sig_iter)
.collect(); .collect();
export_clif_sig.returns = func_sig export_clif_sig.returns = func_sig

View File

@ -10,7 +10,7 @@
``` ```
- **abort** ✅ 🔥 &nbsp;&nbsp;&nbsp;&nbsp;[:top:](#host-apis) - **abort** ✅ 🔥 &nbsp;&nbsp;&nbsp;&nbsp;[:top:](#host-apis)
```rust ```rust
fn abort(message: u32, ctx: &mut Ctx) fn abort(ctx: &mut Ctx, message: u32, )
``` ```
- **abort_on_cannot_grow_memory**&nbsp;&nbsp;&nbsp;&nbsp;[:top:](#host-apis) - **abort_on_cannot_grow_memory**&nbsp;&nbsp;&nbsp;&nbsp;[:top:](#host-apis)
```rust ```rust
@ -28,11 +28,11 @@
- **\_getenv** ✅ &nbsp;&nbsp;&nbsp;&nbsp;[:top:](#host-apis) - **\_getenv** ✅ &nbsp;&nbsp;&nbsp;&nbsp;[:top:](#host-apis)
```rust ```rust
fn _getenv(name: c_int, ctx: &mut Ctx) fn _getenv(ctx: &mut Ctx, name: c_int, )
``` ```
- **\_putenv** ✅ &nbsp;&nbsp;&nbsp;&nbsp;[:top:](#host-apis) - **\_putenv** ✅ &nbsp;&nbsp;&nbsp;&nbsp;[:top:](#host-apis)
```rust ```rust
fn _putenv(name: c_int, ctx: &mut Ctx) fn _putenv(ctx: &mut Ctx, name: c_int, )
``` ```
- **\_setenv** ✅ &nbsp;&nbsp;&nbsp;&nbsp;[:top:](#host-apis) - **\_setenv** ✅ &nbsp;&nbsp;&nbsp;&nbsp;[:top:](#host-apis)
```rust ```rust
@ -40,7 +40,7 @@
``` ```
- **\_unsetenv** ✅ &nbsp;&nbsp;&nbsp;&nbsp;[:top:](#host-apis) - **\_unsetenv** ✅ &nbsp;&nbsp;&nbsp;&nbsp;[:top:](#host-apis)
```rust ```rust
fn _unsetenv(name: c_int, ctx: &mut Ctx) fn _unsetenv(ctx: &mut Ctx, name: c_int, )
``` ```
###### THREAD ###### THREAD
@ -70,7 +70,7 @@
- **\_emscripten_memcpy_big** ✅ 🔥 &nbsp;&nbsp;&nbsp;&nbsp;[:top:](#host-apis) - **\_emscripten_memcpy_big** ✅ 🔥 &nbsp;&nbsp;&nbsp;&nbsp;[:top:](#host-apis)
```rust ```rust
fn _emscripten_memcpy_big(dest: u32, src: u32, len: u32, ctx: &mut Ctx) -> u32 fn _emscripten_memcpy_big(ctx: &mut Ctx, dest: u32, src: u32, len: u32, ) -> u32
``` ```
- **enlarge_memory**&nbsp;&nbsp;&nbsp;&nbsp;[:top:](#host-apis) - **enlarge_memory**&nbsp;&nbsp;&nbsp;&nbsp;[:top:](#host-apis)
```rust ```rust
@ -78,7 +78,7 @@
``` ```
- **get_total_memory**&nbsp;&nbsp;&nbsp;&nbsp;[:top:](#host-apis) - **get_total_memory**&nbsp;&nbsp;&nbsp;&nbsp;[:top:](#host-apis)
```rust ```rust
fn get_total_memory(ctx: &mut Ctx) -> u32 fn get_total_memory(ctx: &mut Ctx, ) -> u32
``` ```
###### TIMING ###### TIMING
@ -337,7 +337,7 @@
``` ```
- **open** (\_\_\_syscall5) ✅ ❗️ 🔥 &nbsp;&nbsp;&nbsp;&nbsp;[:top:](#host-apis) - **open** (\_\_\_syscall5) ✅ ❗️ 🔥 &nbsp;&nbsp;&nbsp;&nbsp;[:top:](#host-apis)
```rust ```rust
fn open(path: u32, flags: c_int, mode: c_int, ctx: &mut Ctx) -> c_int fn open(ctx: &mut Ctx, path: u32, flags: c_int, mode: c_int, ) -> c_int
``` ```
- **openat** (\_\_\_syscall295) &nbsp;&nbsp;&nbsp;&nbsp;[:top:](#host-apis) - **openat** (\_\_\_syscall295) &nbsp;&nbsp;&nbsp;&nbsp;[:top:](#host-apis)
```rust ```rust
@ -385,7 +385,7 @@
``` ```
- **read** (\_\_\_syscall3) ✅ ❗️ &nbsp;&nbsp;&nbsp;&nbsp;[:top:](#host-apis) - **read** (\_\_\_syscall3) ✅ ❗️ &nbsp;&nbsp;&nbsp;&nbsp;[:top:](#host-apis)
```rust ```rust
fn read(fd: c_int, buf: u32, count: size_t, ctx: &mut Ctx) -> ssize_t fn read(ctx: &mut Ctx, fd: c_int, buf: u32, count: size_t, ) -> ssize_t
``` ```
- **readlink** (\_\_\_syscall85) &nbsp;&nbsp;&nbsp;&nbsp;[:top:](#host-apis) - **readlink** (\_\_\_syscall85) &nbsp;&nbsp;&nbsp;&nbsp;[:top:](#host-apis)
```rust ```rust

View File

@ -14,16 +14,16 @@ use crate::{allocate_on_stack, EmscriptenData};
use std::os::raw::c_int; use std::os::raw::c_int;
use wasmer_runtime_core::vm::Ctx; use wasmer_runtime_core::vm::Ctx;
pub fn _getaddrinfo(_one: i32, _two: i32, _three: i32, _four: i32, _ctx: &mut Ctx) -> i32 { pub fn _getaddrinfo(_ctx: &mut Ctx, _one: i32, _two: i32, _three: i32, _four: i32) -> i32 {
debug!("emscripten::_getaddrinfo"); debug!("emscripten::_getaddrinfo");
-1 -1
} }
pub fn call_malloc(size: u32, ctx: &mut Ctx) -> u32 { pub fn call_malloc(ctx: &mut Ctx, size: u32) -> u32 {
get_emscripten_data(ctx).malloc.call(size).unwrap() get_emscripten_data(ctx).malloc.call(size).unwrap()
} }
pub fn call_memalign(alignment: u32, size: u32, ctx: &mut Ctx) -> u32 { pub fn call_memalign(ctx: &mut Ctx, alignment: u32, size: u32) -> u32 {
if let Some(memalign) = &get_emscripten_data(ctx).memalign { if let Some(memalign) = &get_emscripten_data(ctx).memalign {
memalign.call(alignment, size).unwrap() memalign.call(alignment, size).unwrap()
} else { } else {
@ -31,7 +31,7 @@ pub fn call_memalign(alignment: u32, size: u32, ctx: &mut Ctx) -> u32 {
} }
} }
pub fn call_memset(pointer: u32, value: u32, size: u32, ctx: &mut Ctx) -> u32 { pub fn call_memset(ctx: &mut Ctx, pointer: u32, value: u32, size: u32) -> u32 {
get_emscripten_data(ctx) get_emscripten_data(ctx)
.memset .memset
.call(pointer, value, size) .call(pointer, value, size)
@ -48,16 +48,16 @@ pub fn _getpagesize(_ctx: &mut Ctx) -> u32 {
} }
#[allow(clippy::cast_ptr_alignment)] #[allow(clippy::cast_ptr_alignment)]
pub fn ___build_environment(environ: c_int, ctx: &mut Ctx) { pub fn ___build_environment(ctx: &mut Ctx, environ: c_int) {
debug!("emscripten::___build_environment {}", environ); debug!("emscripten::___build_environment {}", environ);
const MAX_ENV_VALUES: u32 = 64; const MAX_ENV_VALUES: u32 = 64;
const TOTAL_ENV_SIZE: u32 = 1024; const TOTAL_ENV_SIZE: u32 = 1024;
let environment = emscripten_memory_pointer!(ctx.memory(0), environ) as *mut c_int; let environment = emscripten_memory_pointer!(ctx.memory(0), environ) as *mut c_int;
unsafe { unsafe {
let (pool_offset, _pool_slice): (u32, &mut [u8]) = let (pool_offset, _pool_slice): (u32, &mut [u8]) =
allocate_on_stack(TOTAL_ENV_SIZE as u32, ctx); allocate_on_stack(ctx, TOTAL_ENV_SIZE as u32);
let (env_offset, _env_slice): (u32, &mut [u8]) = let (env_offset, _env_slice): (u32, &mut [u8]) =
allocate_on_stack((MAX_ENV_VALUES * 4) as u32, ctx); allocate_on_stack(ctx, (MAX_ENV_VALUES * 4) as u32);
let env_ptr = emscripten_memory_pointer!(ctx.memory(0), env_offset) as *mut c_int; let env_ptr = emscripten_memory_pointer!(ctx.memory(0), env_offset) as *mut c_int;
let mut _pool_ptr = emscripten_memory_pointer!(ctx.memory(0), pool_offset) as *mut c_int; let mut _pool_ptr = emscripten_memory_pointer!(ctx.memory(0), pool_offset) as *mut c_int;
*env_ptr = pool_offset as i32; *env_ptr = pool_offset as i32;
@ -70,7 +70,7 @@ pub fn ___build_environment(environ: c_int, ctx: &mut Ctx) {
// }; // };
} }
pub fn ___assert_fail(a: c_int, b: c_int, c: c_int, d: c_int, _ctx: &mut Ctx) { pub fn ___assert_fail(_ctx: &mut Ctx, a: c_int, b: c_int, c: c_int, d: c_int) {
debug!("emscripten::___assert_fail {} {} {} {}", a, b, c, d); debug!("emscripten::___assert_fail {} {} {} {}", a, b, c, d);
// TODO: Implement like emscripten expects regarding memory/page size // TODO: Implement like emscripten expects regarding memory/page size
// TODO raise an error // TODO raise an error

View File

@ -1,20 +1,19 @@
/// 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]
/// emscripten: _getenv // (name: *const char) -> *const c_char; /// emscripten: _getenv // (name: *const char) -> *const c_char;
pub fn _getenv(name: i32, ctx: &mut Ctx) -> u32 { pub fn _getenv(ctx: &mut Ctx, name: i32) -> u32 {
debug!("emscripten::_getenv"); debug!("emscripten::_getenv");
let name_addr = emscripten_memory_pointer!(ctx.memory(0), name) as *const c_char; let name_addr = emscripten_memory_pointer!(ctx.memory(0), name) as *const c_char;
@ -30,7 +29,7 @@ pub fn _getenv(name: i32, ctx: &mut Ctx) -> u32 {
} }
/// emscripten: _setenv // (name: *const char, name: *const value, overwrite: int); /// emscripten: _setenv // (name: *const char, name: *const value, overwrite: int);
pub fn _setenv(name: c_int, value: c_int, overwrite: c_int, ctx: &mut Ctx) -> c_int { pub fn _setenv(ctx: &mut Ctx, name: c_int, value: c_int, overwrite: c_int) -> c_int {
debug!("emscripten::_setenv"); debug!("emscripten::_setenv");
let name_addr = emscripten_memory_pointer!(ctx.memory(0), name) as *const c_char; let name_addr = emscripten_memory_pointer!(ctx.memory(0), name) as *const c_char;
@ -43,7 +42,7 @@ pub fn _setenv(name: c_int, value: c_int, overwrite: c_int, ctx: &mut Ctx) -> c_
} }
/// emscripten: _putenv // (name: *const char); /// emscripten: _putenv // (name: *const char);
pub fn _putenv(name: c_int, ctx: &mut Ctx) -> c_int { pub fn _putenv(ctx: &mut Ctx, name: c_int) -> c_int {
debug!("emscripten::_putenv"); debug!("emscripten::_putenv");
let name_addr = emscripten_memory_pointer!(ctx.memory(0), name) as *const c_char; let name_addr = emscripten_memory_pointer!(ctx.memory(0), name) as *const c_char;
@ -54,7 +53,7 @@ pub fn _putenv(name: c_int, ctx: &mut Ctx) -> c_int {
} }
/// emscripten: _unsetenv // (name: *const char); /// emscripten: _unsetenv // (name: *const char);
pub fn _unsetenv(name: c_int, ctx: &mut Ctx) -> c_int { pub fn _unsetenv(ctx: &mut Ctx, name: c_int) -> c_int {
debug!("emscripten::_unsetenv"); debug!("emscripten::_unsetenv");
let name_addr = emscripten_memory_pointer!(ctx.memory(0), name) as *const c_char; let name_addr = emscripten_memory_pointer!(ctx.memory(0), name) as *const c_char;
@ -65,7 +64,7 @@ pub fn _unsetenv(name: c_int, ctx: &mut Ctx) -> c_int {
} }
#[allow(clippy::cast_ptr_alignment)] #[allow(clippy::cast_ptr_alignment)]
pub fn _getpwnam(name_ptr: c_int, ctx: &mut Ctx) -> c_int { pub fn _getpwnam(ctx: &mut Ctx, name_ptr: c_int) -> c_int {
debug!("emscripten::_getpwnam {}", name_ptr); debug!("emscripten::_getpwnam {}", name_ptr);
#[repr(C)] #[repr(C)]
@ -86,7 +85,7 @@ pub fn _getpwnam(name_ptr: c_int, ctx: &mut Ctx) -> c_int {
unsafe { unsafe {
let passwd = &*libc_getpwnam(name.as_ptr()); let passwd = &*libc_getpwnam(name.as_ptr());
let passwd_struct_offset = call_malloc(mem::size_of::<GuestPasswd>() as _, ctx); let passwd_struct_offset = call_malloc(ctx, mem::size_of::<GuestPasswd>() as _);
let passwd_struct_ptr = let passwd_struct_ptr =
emscripten_memory_pointer!(ctx.memory(0), passwd_struct_offset) as *mut GuestPasswd; emscripten_memory_pointer!(ctx.memory(0), passwd_struct_offset) as *mut GuestPasswd;
@ -103,7 +102,7 @@ pub fn _getpwnam(name_ptr: c_int, ctx: &mut Ctx) -> c_int {
} }
#[allow(clippy::cast_ptr_alignment)] #[allow(clippy::cast_ptr_alignment)]
pub fn _getgrnam(name_ptr: c_int, ctx: &mut Ctx) -> c_int { pub fn _getgrnam(ctx: &mut Ctx, name_ptr: c_int) -> c_int {
debug!("emscripten::_getgrnam {}", name_ptr); debug!("emscripten::_getgrnam {}", name_ptr);
#[repr(C)] #[repr(C)]
@ -121,7 +120,7 @@ pub fn _getgrnam(name_ptr: c_int, ctx: &mut Ctx) -> c_int {
unsafe { unsafe {
let group = &*libc_getgrnam(name.as_ptr()); let group = &*libc_getgrnam(name.as_ptr());
let group_struct_offset = call_malloc(mem::size_of::<GuestGroup>() as _, ctx); let group_struct_offset = call_malloc(ctx, mem::size_of::<GuestGroup>() as _);
let group_struct_ptr = let group_struct_ptr =
emscripten_memory_pointer!(ctx.memory(0), group_struct_offset) as *mut GuestGroup; emscripten_memory_pointer!(ctx.memory(0), group_struct_offset) as *mut GuestGroup;
@ -134,7 +133,7 @@ pub fn _getgrnam(name_ptr: c_int, ctx: &mut Ctx) -> c_int {
} }
} }
pub fn _sysconf(name: c_int, _ctx: &mut Ctx) -> i32 { pub fn _sysconf(_ctx: &mut Ctx, name: c_int) -> i32 {
debug!("emscripten::_sysconf {}", name); debug!("emscripten::_sysconf {}", name);
// TODO: Implement like emscripten expects regarding memory/page size // TODO: Implement like emscripten expects regarding memory/page size
unsafe { sysconf(name) as i32 } // TODO review i64 unsafe { sysconf(name) as i32 } // TODO review i64

View File

@ -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;
@ -17,7 +16,7 @@ extern "C" {
// #[no_mangle] // #[no_mangle]
/// emscripten: _getenv // (name: *const char) -> *const c_char; /// emscripten: _getenv // (name: *const char) -> *const c_char;
pub fn _getenv(name: u32, ctx: &mut Ctx) -> u32 { pub fn _getenv(ctx: &mut Ctx, name: u32) -> u32 {
debug!("emscripten::_getenv"); debug!("emscripten::_getenv");
let name_string = read_string_from_wasm(ctx.memory(0), name); let name_string = read_string_from_wasm(ctx.memory(0), name);
debug!("=> name({:?})", name_string); debug!("=> name({:?})", name_string);
@ -29,7 +28,7 @@ pub fn _getenv(name: u32, ctx: &mut Ctx) -> u32 {
} }
/// emscripten: _setenv // (name: *const char, name: *const value, overwrite: int); /// emscripten: _setenv // (name: *const char, name: *const value, overwrite: int);
pub fn _setenv(name: u32, value: u32, overwrite: u32, ctx: &mut Ctx) -> c_int { pub fn _setenv(ctx: &mut Ctx, name: u32, value: u32, overwrite: u32) -> c_int {
debug!("emscripten::_setenv"); debug!("emscripten::_setenv");
let name_addr = emscripten_memory_pointer!(ctx.memory(0), name); let name_addr = emscripten_memory_pointer!(ctx.memory(0), name);
let value_addr = emscripten_memory_pointer!(ctx.memory(0), value); let value_addr = emscripten_memory_pointer!(ctx.memory(0), value);
@ -45,7 +44,7 @@ pub fn _setenv(name: u32, value: u32, overwrite: u32, ctx: &mut Ctx) -> c_int {
} }
/// emscripten: _putenv // (name: *const char); /// emscripten: _putenv // (name: *const char);
pub fn _putenv(name: c_int, ctx: &mut Ctx) -> c_int { pub fn _putenv(ctx: &mut Ctx, name: c_int) -> c_int {
debug!("emscripten::_putenv"); debug!("emscripten::_putenv");
let name_addr = emscripten_memory_pointer!(ctx.memory(0), name) as *const c_char; let name_addr = emscripten_memory_pointer!(ctx.memory(0), name) as *const c_char;
@ -55,7 +54,7 @@ pub fn _putenv(name: c_int, ctx: &mut Ctx) -> c_int {
} }
/// emscripten: _unsetenv // (name: *const char); /// emscripten: _unsetenv // (name: *const char);
pub fn _unsetenv(name: u32, ctx: &mut Ctx) -> c_int { pub fn _unsetenv(ctx: &mut Ctx, name: u32) -> c_int {
debug!("emscripten::_unsetenv"); debug!("emscripten::_unsetenv");
let name_addr = emscripten_memory_pointer!(ctx.memory(0), name); let name_addr = emscripten_memory_pointer!(ctx.memory(0), name);
let name = read_string_from_wasm(ctx.memory(0), name); let name = read_string_from_wasm(ctx.memory(0), name);
@ -68,7 +67,7 @@ pub fn _unsetenv(name: u32, ctx: &mut Ctx) -> c_int {
} }
#[allow(clippy::cast_ptr_alignment)] #[allow(clippy::cast_ptr_alignment)]
pub fn _getpwnam(name_ptr: c_int, ctx: &mut Ctx) -> c_int { pub fn _getpwnam(ctx: &mut Ctx, name_ptr: c_int) -> c_int {
debug!("emscripten::_getpwnam {}", name_ptr); debug!("emscripten::_getpwnam {}", name_ptr);
#[repr(C)] #[repr(C)]
@ -84,7 +83,7 @@ pub fn _getpwnam(name_ptr: c_int, ctx: &mut Ctx) -> c_int {
// stub this in windows as it is not valid // stub this in windows as it is not valid
unsafe { unsafe {
let passwd_struct_offset = call_malloc(mem::size_of::<GuestPasswd>() as _, ctx); let passwd_struct_offset = call_malloc(ctx, mem::size_of::<GuestPasswd>() as _);
let passwd_struct_ptr = let passwd_struct_ptr =
emscripten_memory_pointer!(ctx.memory(0), passwd_struct_offset) as *mut GuestPasswd; emscripten_memory_pointer!(ctx.memory(0), passwd_struct_offset) as *mut GuestPasswd;
(*passwd_struct_ptr).pw_name = 0; (*passwd_struct_ptr).pw_name = 0;
@ -100,7 +99,7 @@ pub fn _getpwnam(name_ptr: c_int, ctx: &mut Ctx) -> c_int {
} }
#[allow(clippy::cast_ptr_alignment)] #[allow(clippy::cast_ptr_alignment)]
pub fn _getgrnam(name_ptr: c_int, ctx: &mut Ctx) -> c_int { pub fn _getgrnam(ctx: &mut Ctx, name_ptr: c_int) -> c_int {
debug!("emscripten::_getgrnam {}", name_ptr); debug!("emscripten::_getgrnam {}", name_ptr);
#[repr(C)] #[repr(C)]
@ -113,7 +112,7 @@ pub fn _getgrnam(name_ptr: c_int, ctx: &mut Ctx) -> c_int {
// stub the group struct as it is not supported on windows // stub the group struct as it is not supported on windows
unsafe { unsafe {
let group_struct_offset = call_malloc(mem::size_of::<GuestGroup>() as _, ctx); let group_struct_offset = call_malloc(ctx, mem::size_of::<GuestGroup>() as _);
let group_struct_ptr = let group_struct_ptr =
emscripten_memory_pointer!(ctx.memory(0), group_struct_offset) as *mut GuestGroup; emscripten_memory_pointer!(ctx.memory(0), group_struct_offset) as *mut GuestGroup;
(*group_struct_ptr).gr_name = 0; (*group_struct_ptr).gr_name = 0;
@ -124,7 +123,7 @@ pub fn _getgrnam(name_ptr: c_int, ctx: &mut Ctx) -> c_int {
} }
} }
pub fn _sysconf(name: c_int, _ctx: &mut Ctx) -> c_long { pub fn _sysconf(_ctx: &mut Ctx, name: c_int) -> c_long {
debug!("emscripten::_sysconf {}", name); debug!("emscripten::_sysconf {}", name);
// stub because sysconf is not valid on windows // stub because sysconf is not valid on windows
0 0

View File

@ -1,7 +1,7 @@
// use std::collections::HashMap; // use std::collections::HashMap;
use wasmer_runtime_core::vm::Ctx; use wasmer_runtime_core::vm::Ctx;
pub fn ___seterrno(value: i32, _ctx: &mut Ctx) { pub fn ___seterrno(_ctx: &mut Ctx, value: i32) {
debug!("emscripten::___seterrno {}", value); debug!("emscripten::___seterrno {}", value);
// TODO: Incomplete impl // TODO: Incomplete impl
eprintln!("failed to set errno!"); eprintln!("failed to set errno!");

View File

@ -3,14 +3,14 @@ use super::process::_abort;
use wasmer_runtime_core::vm::Ctx; use wasmer_runtime_core::vm::Ctx;
/// emscripten: ___cxa_allocate_exception /// emscripten: ___cxa_allocate_exception
pub fn ___cxa_allocate_exception(size: u32, ctx: &mut Ctx) -> u32 { pub fn ___cxa_allocate_exception(ctx: &mut Ctx, size: u32) -> u32 {
debug!("emscripten::___cxa_allocate_exception"); debug!("emscripten::___cxa_allocate_exception");
env::call_malloc(size as _, ctx) env::call_malloc(ctx, size as _)
} }
/// emscripten: ___cxa_throw /// emscripten: ___cxa_throw
/// TODO: We don't have support for exceptions yet /// TODO: We don't have support for exceptions yet
pub fn ___cxa_throw(_ptr: u32, _ty: u32, _destructor: u32, ctx: &mut Ctx) { pub fn ___cxa_throw(ctx: &mut Ctx, _ptr: u32, _ty: u32, _destructor: u32) {
debug!("emscripten::___cxa_throw"); debug!("emscripten::___cxa_throw");
_abort(ctx); _abort(ctx);
} }

View File

@ -3,12 +3,12 @@ use libc::printf as _printf;
use wasmer_runtime_core::vm::Ctx; use wasmer_runtime_core::vm::Ctx;
/// putchar /// putchar
pub fn putchar(chr: i32, ctx: &mut Ctx) { pub fn putchar(ctx: &mut Ctx, chr: i32) {
unsafe { libc::putchar(chr) }; unsafe { libc::putchar(chr) };
} }
/// printf /// printf
pub fn printf(memory_offset: i32, extra: i32, ctx: &mut Ctx) -> i32 { pub fn printf(ctx: &mut Ctx, memory_offset: i32, extra: i32) -> 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 _;

View File

@ -5,25 +5,26 @@ 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(ctx: &mut Ctx, chr: i32) {
unsafe { libc::putchar(chr) }; unsafe { libc::putchar(chr) };
} }
/// printf /// printf
pub fn printf(memory_offset: i32, extra: i32, ctx: &mut Ctx) -> i32 { pub fn printf(ctx: &mut Ctx, memory_offset: i32, extra: i32) -> 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
} }

View File

@ -4,29 +4,28 @@ use std::cell::UnsafeCell;
use wasmer_runtime_core::vm::Ctx; use wasmer_runtime_core::vm::Ctx;
/// setjmp /// setjmp
pub fn __setjmp(env_addr: u32, ctx: &mut Ctx) -> c_int { pub fn __setjmp(ctx: &mut Ctx, env_addr: u32) -> 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 3value 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
} }
} }
/// longjmp /// longjmp
#[allow(unreachable_code)] #[allow(unreachable_code)]
pub fn __longjmp(env_addr: u32, val: c_int, ctx: &mut Ctx) { pub fn __longjmp(ctx: &mut Ctx, env_addr: u32, val: c_int) {
debug!("emscripten::__longjmp (longmp)"); debug!("emscripten::__longjmp (longmp)");
unsafe { unsafe {
// We retrieve the jump index from the env address // We retrieve the jump index from the env address

View File

@ -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,
}; };
@ -141,7 +132,7 @@ pub fn run_emscripten_instance(
let num_params = main_func.signature().params().len(); let num_params = main_func.signature().params().len();
let _result = match num_params { let _result = match num_params {
2 => { 2 => {
let (argc, argv) = store_module_arguments(path, args, instance.context_mut()); let (argc, argv) = store_module_arguments(instance.context_mut(), path, args);
instance.call("_main", &[Value::I32(argc as i32), Value::I32(argv as i32)])?; instance.call("_main", &[Value::I32(argc as i32), Value::I32(argv as i32)])?;
} }
0 => { 0 => {
@ -158,17 +149,17 @@ pub fn run_emscripten_instance(
Ok(()) Ok(())
} }
fn store_module_arguments(path: &str, args: Vec<&str>, ctx: &mut Ctx) -> (u32, u32) { fn store_module_arguments(ctx: &mut Ctx, path: &str, args: Vec<&str>) -> (u32, u32) {
let argc = args.len() + 1; let argc = args.len() + 1;
let mut args_slice = vec![0; argc]; let mut args_slice = vec![0; argc];
args_slice[0] = unsafe { allocate_cstr_on_stack(path, ctx).0 }; args_slice[0] = unsafe { allocate_cstr_on_stack(ctx, path).0 };
for (slot, arg) in args_slice[1..argc].iter_mut().zip(args.iter()) { for (slot, arg) in args_slice[1..argc].iter_mut().zip(args.iter()) {
*slot = unsafe { allocate_cstr_on_stack(&arg, ctx).0 }; *slot = unsafe { allocate_cstr_on_stack(ctx, &arg).0 };
} }
let (argv_offset, argv_slice): (_, &mut [u32]) = let (argv_offset, argv_slice): (_, &mut [u32]) =
unsafe { allocate_on_stack(((argc + 1) * 4) as u32, ctx) }; unsafe { allocate_on_stack(ctx, ((argc + 1) * 4) as u32) };
assert!(!argv_slice.is_empty()); assert!(!argv_slice.is_empty());
for (slot, arg) in argv_slice[0..argc].iter_mut().zip(args_slice.iter()) { for (slot, arg) in argv_slice[0..argc].iter_mut().zip(args_slice.iter()) {
*slot = *arg *slot = *arg

View File

@ -3,19 +3,19 @@ use wasmer_runtime_core::vm::Ctx;
// TODO: Need to implement. // TODO: Need to implement.
/// emscripten: dlopen(filename: *const c_char, flag: c_int) -> *mut c_void /// emscripten: dlopen(filename: *const c_char, flag: c_int) -> *mut c_void
pub fn _dlopen(_filename: u32, _flag: u32, _ctx: &mut Ctx) -> i32 { pub fn _dlopen(_ctx: &mut Ctx, _filename: u32, _flag: u32) -> i32 {
debug!("emscripten::_dlopen"); debug!("emscripten::_dlopen");
-1 -1
} }
/// emscripten: dlclose(handle: *mut c_void) -> c_int /// emscripten: dlclose(handle: *mut c_void) -> c_int
pub fn _dlclose(_filename: u32, _ctx: &mut Ctx) -> i32 { pub fn _dlclose(_ctx: &mut Ctx, _filename: u32) -> i32 {
debug!("emscripten::_dlclose"); debug!("emscripten::_dlclose");
-1 -1
} }
/// emscripten: dlsym(handle: *mut c_void, symbol: *const c_char) -> *mut c_void /// emscripten: dlsym(handle: *mut c_void, symbol: *const c_char) -> *mut c_void
pub fn _dlsym(_filepath: u32, _symbol: u32, _ctx: &mut Ctx) -> i32 { pub fn _dlsym(_ctx: &mut Ctx, _filepath: u32, _symbol: u32) -> i32 {
debug!("emscripten::_dlsym"); debug!("emscripten::_dlsym");
-1 -1
} }

View File

@ -2,16 +2,16 @@ use libc::c_int;
use wasmer_runtime_core::vm::Ctx; use wasmer_runtime_core::vm::Ctx;
// NOTE: Not implemented by Emscripten // NOTE: Not implemented by Emscripten
pub fn ___lock(what: c_int, _ctx: &mut Ctx) { pub fn ___lock(_ctx: &mut Ctx, what: c_int) {
debug!("emscripten::___lock {}", what); debug!("emscripten::___lock {}", what);
} }
// NOTE: Not implemented by Emscripten // NOTE: Not implemented by Emscripten
pub fn ___unlock(what: c_int, _ctx: &mut Ctx) { pub fn ___unlock(_ctx: &mut Ctx, what: c_int) {
debug!("emscripten::___unlock {}", what); debug!("emscripten::___unlock {}", what);
} }
// NOTE: Not implemented by Emscripten // NOTE: Not implemented by Emscripten
pub fn ___wait(_which: u32, _varargs: u32, _three: u32, _four: u32, _ctx: &mut Ctx) { pub fn ___wait(_ctx: &mut Ctx, _which: u32, _varargs: u32, _three: u32, _four: u32) {
debug!("emscripten::___wait"); debug!("emscripten::___wait");
} }

View File

@ -1,23 +1,23 @@
use wasmer_runtime_core::vm::Ctx; use wasmer_runtime_core::vm::Ctx;
/// emscripten: _llvm_log10_f64 /// emscripten: _llvm_log10_f64
pub fn _llvm_log10_f64(value: f64, _ctx: &mut Ctx) -> f64 { pub fn _llvm_log10_f64(_ctx: &mut Ctx, value: f64) -> f64 {
debug!("emscripten::_llvm_log10_f64"); debug!("emscripten::_llvm_log10_f64");
value.log10() value.log10()
} }
/// emscripten: _llvm_log2_f64 /// emscripten: _llvm_log2_f64
pub fn _llvm_log2_f64(value: f64, _ctx: &mut Ctx) -> f64 { pub fn _llvm_log2_f64(_ctx: &mut Ctx, value: f64) -> f64 {
debug!("emscripten::_llvm_log2_f64"); debug!("emscripten::_llvm_log2_f64");
value.log2() value.log2()
} }
pub fn _llvm_log10_f32(_value: f64, _ctx: &mut Ctx) -> f64 { pub fn _llvm_log10_f32(_ctx: &mut Ctx, _value: f64) -> f64 {
debug!("emscripten::_llvm_log10_f32"); debug!("emscripten::_llvm_log10_f32");
-1.0 -1.0
} }
pub fn _llvm_log2_f32(_value: f64, _ctx: &mut Ctx) -> f64 { pub fn _llvm_log2_f32(_ctx: &mut Ctx, _value: f64) -> f64 {
debug!("emscripten::_llvm_log10_f32"); debug!("emscripten::_llvm_log10_f32");
-1.0 -1.0
} }
@ -28,12 +28,12 @@ pub fn _emscripten_random(_ctx: &mut Ctx) -> f64 {
} }
// emscripten: f64-rem // emscripten: f64-rem
pub fn f64_rem(x: f64, y: f64, _ctx: &mut Ctx) -> f64 { pub fn f64_rem(_ctx: &mut Ctx, x: f64, y: f64) -> f64 {
debug!("emscripten::f64-rem"); debug!("emscripten::f64-rem");
x % y x % y
} }
// emscripten: global.Math pow // emscripten: global.Math pow
pub fn pow(x: f64, y: f64, _ctx: &mut Ctx) -> f64 { pub fn pow(_ctx: &mut Ctx, x: f64, y: f64) -> f64 {
x.powf(y) x.powf(y)
} }

View File

@ -3,7 +3,7 @@ use libc::{c_int, c_void, memcpy, size_t};
use wasmer_runtime_core::vm::Ctx; use wasmer_runtime_core::vm::Ctx;
/// emscripten: _emscripten_memcpy_big /// emscripten: _emscripten_memcpy_big
pub fn _emscripten_memcpy_big(dest: u32, src: u32, len: u32, ctx: &mut Ctx) -> u32 { pub fn _emscripten_memcpy_big(ctx: &mut Ctx, dest: u32, src: u32, len: u32) -> u32 {
debug!( debug!(
"emscripten::_emscripten_memcpy_big {}, {}, {}", "emscripten::_emscripten_memcpy_big {}, {}, {}",
dest, src, len dest, src, len
@ -35,12 +35,12 @@ pub fn enlarge_memory(_ctx: &mut Ctx) -> u32 {
/// emscripten: abortOnCannotGrowMemory /// emscripten: abortOnCannotGrowMemory
pub fn abort_on_cannot_grow_memory(ctx: &mut Ctx) -> u32 { pub fn abort_on_cannot_grow_memory(ctx: &mut Ctx) -> u32 {
debug!("emscripten::abort_on_cannot_grow_memory"); debug!("emscripten::abort_on_cannot_grow_memory");
abort_with_message("Cannot enlarge memory arrays!", ctx); abort_with_message(ctx, "Cannot enlarge memory arrays!");
0 0
} }
/// emscripten: ___map_file /// emscripten: ___map_file
pub fn ___map_file(_one: u32, _two: u32, _ctx: &mut Ctx) -> c_int { pub fn ___map_file(_ctx: &mut Ctx, _one: u32, _two: u32) -> c_int {
debug!("emscripten::___map_file"); debug!("emscripten::___map_file");
// NOTE: TODO: Em returns -1 here as well. May need to implement properly // NOTE: TODO: Em returns -1 here as well. May need to implement properly
-1 -1

View File

@ -1,67 +1,67 @@
use super::process::abort_with_message; use super::process::abort_with_message;
use wasmer_runtime_core::vm::Ctx; use wasmer_runtime_core::vm::Ctx;
pub fn nullfunc_i(x: u32, ctx: &mut Ctx) { pub fn nullfunc_i(ctx: &mut Ctx, x: u32) {
debug!("emscripten::nullfunc_i {}", x); debug!("emscripten::nullfunc_i {}", x);
abort_with_message("Invalid function pointer called with signature 'i'. Perhaps this is an invalid value (e.g. caused by calling a virtual method on a NULL pointer)? Or calling a function with an incorrect type, which will fail? (it is worth building your source files with -Werror (warnings are errors), as warnings can indicate undefined behavior which can cause this)", ctx); abort_with_message(ctx, "Invalid function pointer called with signature 'i'. Perhaps this is an invalid value (e.g. caused by calling a virtual method on a NULL pointer)? Or calling a function with an incorrect type, which will fail? (it is worth building your source files with -Werror (warnings are errors), as warnings can indicate undefined behavior which can cause this)");
} }
pub fn nullfunc_ii(x: u32, ctx: &mut Ctx) { pub fn nullfunc_ii(ctx: &mut Ctx, x: u32) {
debug!("emscripten::nullfunc_ii {}", x); debug!("emscripten::nullfunc_ii {}", x);
abort_with_message("Invalid function pointer called with signature 'ii'. Perhaps this is an invalid value (e.g. caused by calling a virtual method on a NULL pointer)? Or calling a function with an incorrect type, which will fail? (it is worth building your source files with -Werror (warnings are errors), as warnings can indicate undefined behavior which can cause this)", ctx); abort_with_message(ctx, "Invalid function pointer called with signature 'ii'. Perhaps this is an invalid value (e.g. caused by calling a virtual method on a NULL pointer)? Or calling a function with an incorrect type, which will fail? (it is worth building your source files with -Werror (warnings are errors), as warnings can indicate undefined behavior which can cause this)");
} }
pub fn nullfunc_iii(x: u32, ctx: &mut Ctx) { pub fn nullfunc_iii(ctx: &mut Ctx, x: u32) {
debug!("emscripten::nullfunc_iii {}", x); debug!("emscripten::nullfunc_iii {}", x);
abort_with_message("Invalid function pointer called with signature 'iii'. Perhaps this is an invalid value (e.g. caused by calling a virtual method on a NULL pointer)? Or calling a function with an incorrect type, which will fail? (it is worth building your source files with -Werror (warnings are errors), as warnings can indicate undefined behavior which can cause this)", ctx); abort_with_message(ctx, "Invalid function pointer called with signature 'iii'. Perhaps this is an invalid value (e.g. caused by calling a virtual method on a NULL pointer)? Or calling a function with an incorrect type, which will fail? (it is worth building your source files with -Werror (warnings are errors), as warnings can indicate undefined behavior which can cause this)");
} }
pub fn nullfunc_iiii(x: u32, ctx: &mut Ctx) { pub fn nullfunc_iiii(ctx: &mut Ctx, x: u32) {
debug!("emscripten::nullfunc_iiii {}", x); debug!("emscripten::nullfunc_iiii {}", x);
abort_with_message("Invalid function pointer called with signature 'iiii'. Perhaps this is an invalid value (e.g. caused by calling a virtual method on a NULL pointer)? Or calling a function with an incorrect type, which will fail? (it is worth building your source files with -Werror (warnings are errors), as warnings can indicate undefined behavior which can cause this)", ctx); abort_with_message(ctx, "Invalid function pointer called with signature 'iiii'. Perhaps this is an invalid value (e.g. caused by calling a virtual method on a NULL pointer)? Or calling a function with an incorrect type, which will fail? (it is worth building your source files with -Werror (warnings are errors), as warnings can indicate undefined behavior which can cause this)");
} }
pub fn nullfunc_iiiii(x: u32, ctx: &mut Ctx) { pub fn nullfunc_iiiii(ctx: &mut Ctx, x: u32) {
debug!("emscripten::nullfunc_iiiii {}", x); debug!("emscripten::nullfunc_iiiii {}", x);
abort_with_message("Invalid function pointer called with signature 'iiiii'. Perhaps this is an invalid value (e.g. caused by calling a virtual method on a NULL pointer)? Or calling a function with an incorrect type, which will fail? (it is worth building your source files with -Werror (warnings are errors), as warnings can indicate undefined behavior which can cause this)", ctx); abort_with_message(ctx, "Invalid function pointer called with signature 'iiiii'. Perhaps this is an invalid value (e.g. caused by calling a virtual method on a NULL pointer)? Or calling a function with an incorrect type, which will fail? (it is worth building your source files with -Werror (warnings are errors), as warnings can indicate undefined behavior which can cause this)");
} }
pub fn nullfunc_iiiiii(x: u32, ctx: &mut Ctx) { pub fn nullfunc_iiiiii(ctx: &mut Ctx, x: u32) {
debug!("emscripten::nullfunc_iiiiii {}", x); debug!("emscripten::nullfunc_iiiiii {}", x);
abort_with_message("Invalid function pointer called with signature 'iiiiii'. Perhaps this is an invalid value (e.g. caused by calling a virtual method on a NULL pointer)? Or calling a function with an incorrect type, which will fail? (it is worth building your source files with -Werror (warnings are errors), as warnings can indicate undefined behavior which can cause this)", ctx); abort_with_message(ctx, "Invalid function pointer called with signature 'iiiiii'. Perhaps this is an invalid value (e.g. caused by calling a virtual method on a NULL pointer)? Or calling a function with an incorrect type, which will fail? (it is worth building your source files with -Werror (warnings are errors), as warnings can indicate undefined behavior which can cause this)");
} }
pub fn nullfunc_v(x: u32, ctx: &mut Ctx) { pub fn nullfunc_v(ctx: &mut Ctx, x: u32) {
debug!("emscripten::nullfunc_v {}", x); debug!("emscripten::nullfunc_v {}", x);
abort_with_message("Invalid function pointer called with signature 'v'. Perhaps this is an invalid value (e.g. caused by calling a virtual method on a NULL pointer)? Or calling a function with an incorrect type, which will fail? (it is worth building your source files with -Werror (warnings are errors), as warnings can indicate undefined behavior which can cause this)", ctx); abort_with_message(ctx, "Invalid function pointer called with signature 'v'. Perhaps this is an invalid value (e.g. caused by calling a virtual method on a NULL pointer)? Or calling a function with an incorrect type, which will fail? (it is worth building your source files with -Werror (warnings are errors), as warnings can indicate undefined behavior which can cause this)");
} }
pub fn nullfunc_vi(x: u32, ctx: &mut Ctx) { pub fn nullfunc_vi(ctx: &mut Ctx, x: u32) {
debug!("emscripten::nullfunc_vi {}", x); debug!("emscripten::nullfunc_vi {}", x);
abort_with_message("Invalid function pointer called with signature 'vi'. Perhaps this is an invalid value (e.g. caused by calling a virtual method on a NULL pointer)? Or calling a function with an incorrect type, which will fail? (it is worth building your source files with -Werror (warnings are errors), as warnings can indicate undefined behavior which can cause this)", ctx); abort_with_message(ctx, "Invalid function pointer called with signature 'vi'. Perhaps this is an invalid value (e.g. caused by calling a virtual method on a NULL pointer)? Or calling a function with an incorrect type, which will fail? (it is worth building your source files with -Werror (warnings are errors), as warnings can indicate undefined behavior which can cause this)");
} }
pub fn nullfunc_vii(x: u32, ctx: &mut Ctx) { pub fn nullfunc_vii(ctx: &mut Ctx, x: u32) {
debug!("emscripten::nullfunc_vii {}", x); debug!("emscripten::nullfunc_vii {}", x);
abort_with_message("Invalid function pointer called with signature 'vii'. Perhaps this is an invalid value (e.g. caused by calling a virtual method on a NULL pointer)? Or calling a function with an incorrect type, which will fail? (it is worth building your source files with -Werror (warnings are errors), as warnings can indicate undefined behavior which can cause this)", ctx); abort_with_message(ctx, "Invalid function pointer called with signature 'vii'. Perhaps this is an invalid value (e.g. caused by calling a virtual method on a NULL pointer)? Or calling a function with an incorrect type, which will fail? (it is worth building your source files with -Werror (warnings are errors), as warnings can indicate undefined behavior which can cause this)");
} }
pub fn nullfunc_viii(x: u32, ctx: &mut Ctx) { pub fn nullfunc_viii(ctx: &mut Ctx, x: u32) {
debug!("emscripten::nullfunc_viii {}", x); debug!("emscripten::nullfunc_viii {}", x);
abort_with_message("Invalid function pointer called with signature 'viii'. Perhaps this is an invalid value (e.g. caused by calling a virtual method on a NULL pointer)? Or calling a function with an incorrect type, which will fail? (it is worth building your source files with -Werror (warnings are errors), as warnings can indicate undefined behavior which can cause this)", ctx); abort_with_message(ctx, "Invalid function pointer called with signature 'viii'. Perhaps this is an invalid value (e.g. caused by calling a virtual method on a NULL pointer)? Or calling a function with an incorrect type, which will fail? (it is worth building your source files with -Werror (warnings are errors), as warnings can indicate undefined behavior which can cause this)");
} }
pub fn nullfunc_viiii(x: u32, ctx: &mut Ctx) { pub fn nullfunc_viiii(ctx: &mut Ctx, x: u32) {
debug!("emscripten::nullfunc_viiii {}", x); debug!("emscripten::nullfunc_viiii {}", x);
abort_with_message("Invalid function pointer called with signature 'viiii'. Perhaps this is an invalid value (e.g. caused by calling a virtual method on a NULL pointer)? Or calling a function with an incorrect type, which will fail? (it is worth building your source files with -Werror (warnings are errors), as warnings can indicate undefined behavior which can cause this)", ctx); abort_with_message(ctx, "Invalid function pointer called with signature 'viiii'. Perhaps this is an invalid value (e.g. caused by calling a virtual method on a NULL pointer)? Or calling a function with an incorrect type, which will fail? (it is worth building your source files with -Werror (warnings are errors), as warnings can indicate undefined behavior which can cause this)");
} }
pub fn nullfunc_viiiii(_x: u32, ctx: &mut Ctx) { pub fn nullfunc_viiiii(ctx: &mut Ctx, _x: u32) {
debug!("emscripten::nullfunc_viiiii"); debug!("emscripten::nullfunc_viiiii");
abort_with_message("Invalid function pointer called with signature 'viiiii'. Perhaps this is an invalid value (e.g. caused by calling a virtual method on a NULL pointer)? Or calling a function with an incorrect type, which will fail? (it is worth building your source files with -Werror (warnings are errors), as warnings can indicate undefined behavior which can cause this)", ctx); abort_with_message(ctx, "Invalid function pointer called with signature 'viiiii'. Perhaps this is an invalid value (e.g. caused by calling a virtual method on a NULL pointer)? Or calling a function with an incorrect type, which will fail? (it is worth building your source files with -Werror (warnings are errors), as warnings can indicate undefined behavior which can cause this)");
} }
pub fn nullfunc_viiiiii(_x: u32, ctx: &mut Ctx) { pub fn nullfunc_viiiiii(ctx: &mut Ctx, _x: u32) {
debug!("emscripten::nullfunc_viiiiii"); debug!("emscripten::nullfunc_viiiiii");
abort_with_message("Invalid function pointer called with signature 'viiiiii'. Perhaps this is an invalid value (e.g. caused by calling a virtual method on a NULL pointer)? Or calling a function with an incorrect type, which will fail? (it is worth building your source files with -Werror (warnings are errors), as warnings can indicate undefined behavior which can cause this)", ctx); abort_with_message(ctx, "Invalid function pointer called with signature 'viiiiii'. Perhaps this is an invalid value (e.g. caused by calling a virtual method on a NULL pointer)? Or calling a function with an incorrect type, which will fail? (it is worth building your source files with -Werror (warnings are errors), as warnings can indicate undefined behavior which can cause this)");
} }

View File

@ -9,7 +9,7 @@ type pid_t = c_int;
use std::ffi::CStr; use std::ffi::CStr;
use wasmer_runtime_core::vm::Ctx; use wasmer_runtime_core::vm::Ctx;
pub fn abort_with_message(message: &str, ctx: &mut Ctx) { pub fn abort_with_message(ctx: &mut Ctx, message: &str) {
debug!("emscripten::abort_with_message"); debug!("emscripten::abort_with_message");
println!("{}", message); println!("{}", message);
_abort(ctx); _abort(ctx);
@ -34,19 +34,19 @@ pub fn _endgrent(_ctx: &mut Ctx) {
debug!("emscripten::_endgrent"); debug!("emscripten::_endgrent");
} }
pub fn _execve(_one: i32, _two: i32, _three: i32, _ctx: &mut Ctx) -> i32 { pub fn _execve(_ctx: &mut Ctx, _one: i32, _two: i32, _three: i32) -> i32 {
debug!("emscripten::_execve"); debug!("emscripten::_execve");
-1 -1
} }
#[allow(unreachable_code)] #[allow(unreachable_code)]
pub fn _exit(status: c_int, _ctx: &mut Ctx) { pub fn _exit(_ctx: &mut Ctx, status: c_int) {
// -> ! // -> !
debug!("emscripten::_exit {}", status); debug!("emscripten::_exit {}", status);
unsafe { exit(status) } unsafe { exit(status) }
} }
pub fn em_abort(message: u32, ctx: &mut Ctx) { pub fn em_abort(ctx: &mut Ctx, message: u32) {
debug!("emscripten::em_abort {}", message); debug!("emscripten::em_abort {}", message);
let message_addr = emscripten_memory_pointer!(ctx.memory(0), message) as *mut c_char; let message_addr = emscripten_memory_pointer!(ctx.memory(0), message) as *mut c_char;
unsafe { unsafe {
@ -54,11 +54,11 @@ pub fn em_abort(message: u32, ctx: &mut Ctx) {
.to_str() .to_str()
.unwrap_or("Unexpected abort"); .unwrap_or("Unexpected abort");
abort_with_message(message, ctx); abort_with_message(ctx, message);
} }
} }
pub fn _kill(_one: i32, _two: i32, _ctx: &mut Ctx) -> i32 { pub fn _kill(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
debug!("emscripten::_kill"); debug!("emscripten::_kill");
-1 -1
} }
@ -73,26 +73,26 @@ pub fn _llvm_stacksave(_ctx: &mut Ctx) -> i32 {
-1 -1
} }
pub fn _llvm_stackrestore(_one: i32, _ctx: &mut Ctx) { pub fn _llvm_stackrestore(_ctx: &mut Ctx, _one: i32) {
debug!("emscripten::_llvm_stackrestore"); debug!("emscripten::_llvm_stackrestore");
} }
pub fn _raise(_one: i32, _ctx: &mut Ctx) -> i32 { pub fn _raise(_ctx: &mut Ctx, _one: i32) -> i32 {
debug!("emscripten::_raise"); debug!("emscripten::_raise");
-1 -1
} }
pub fn _sem_init(_one: i32, _two: i32, _three: i32, _ctx: &mut Ctx) -> i32 { pub fn _sem_init(_ctx: &mut Ctx, _one: i32, _two: i32, _three: i32) -> i32 {
debug!("emscripten::_sem_init"); debug!("emscripten::_sem_init");
-1 -1
} }
pub fn _sem_post(_one: i32, _ctx: &mut Ctx) -> i32 { pub fn _sem_post(_ctx: &mut Ctx, _one: i32) -> i32 {
debug!("emscripten::_sem_post"); debug!("emscripten::_sem_post");
-1 -1
} }
pub fn _sem_wait(_one: i32, _ctx: &mut Ctx) -> i32 { pub fn _sem_wait(_ctx: &mut Ctx, _one: i32) -> i32 {
debug!("emscripten::_sem_post"); debug!("emscripten::_sem_post");
-1 -1
} }
@ -107,53 +107,53 @@ pub fn _setgrent(_ctx: &mut Ctx) {
debug!("emscripten::_setgrent"); debug!("emscripten::_setgrent");
} }
pub fn _setgroups(_one: i32, _two: i32, _ctx: &mut Ctx) -> i32 { pub fn _setgroups(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
debug!("emscripten::_setgroups"); debug!("emscripten::_setgroups");
-1 -1
} }
pub fn _setitimer(_one: i32, _two: i32, _three: i32, _ctx: &mut Ctx) -> i32 { pub fn _setitimer(_ctx: &mut Ctx, _one: i32, _two: i32, _three: i32) -> i32 {
debug!("emscripten::_setitimer"); debug!("emscripten::_setitimer");
-1 -1
} }
pub fn _usleep(_one: i32, _ctx: &mut Ctx) -> i32 { pub fn _usleep(_ctx: &mut Ctx, _one: i32) -> i32 {
debug!("emscripten::_usleep"); debug!("emscripten::_usleep");
-1 -1
} }
pub fn _utimes(_one: i32, _two: i32, _ctx: &mut Ctx) -> i32 { pub fn _utimes(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
debug!("emscripten::_utimes"); debug!("emscripten::_utimes");
-1 -1
} }
pub fn _waitpid(_one: i32, _two: i32, _three: i32, _ctx: &mut Ctx) -> i32 { pub fn _waitpid(_ctx: &mut Ctx, _one: i32, _two: i32, _three: i32) -> i32 {
debug!("emscripten::_waitpid"); debug!("emscripten::_waitpid");
-1 -1
} }
pub fn abort_stack_overflow(_what: c_int, ctx: &mut Ctx) { pub fn abort_stack_overflow(ctx: &mut Ctx, _what: c_int) {
debug!("emscripten::abort_stack_overflow"); debug!("emscripten::abort_stack_overflow");
// TODO: Message incomplete. Need to finish em runtime data first // TODO: Message incomplete. Need to finish em runtime data first
abort_with_message( abort_with_message(
"Stack overflow! Attempted to allocate some bytes on the stack",
ctx, ctx,
"Stack overflow! Attempted to allocate some bytes on the stack",
); );
} }
pub fn _llvm_trap(ctx: &mut Ctx) { pub fn _llvm_trap(ctx: &mut Ctx) {
debug!("emscripten::_llvm_trap"); debug!("emscripten::_llvm_trap");
abort_with_message("abort!", ctx); abort_with_message(ctx, "abort!");
} }
pub fn _system(_one: i32, _ctx: &mut Ctx) -> c_int { pub fn _system(_ctx: &mut Ctx, _one: i32) -> c_int {
debug!("emscripten::_system"); debug!("emscripten::_system");
// TODO: May need to change this Em impl to a working version // TODO: May need to change this Em impl to a working version
eprintln!("Can't call external programs"); eprintln!("Can't call external programs");
return EAGAIN; return EAGAIN;
} }
pub fn _popen(_one: i32, _two: i32, _ctx: &mut Ctx) -> c_int { pub fn _popen(_ctx: &mut Ctx, _one: i32, _two: i32) -> c_int {
debug!("emscripten::_popen"); debug!("emscripten::_popen");
// TODO: May need to change this Em impl to a working version // TODO: May need to change this Em impl to a working version
eprintln!("Missing function: popen"); eprintln!("Missing function: popen");

View File

@ -2,7 +2,7 @@
use wasmer_runtime_core::vm::Ctx; use wasmer_runtime_core::vm::Ctx;
#[allow(clippy::cast_ptr_alignment)] #[allow(clippy::cast_ptr_alignment)]
pub fn _sigemptyset(set: u32, ctx: &mut Ctx) -> i32 { pub fn _sigemptyset(ctx: &mut Ctx, set: u32) -> i32 {
debug!("emscripten::_sigemptyset"); debug!("emscripten::_sigemptyset");
let set_addr = emscripten_memory_pointer!(ctx.memory(0), set) as *mut u32; let set_addr = emscripten_memory_pointer!(ctx.memory(0), set) as *mut u32;
unsafe { unsafe {
@ -11,13 +11,13 @@ pub fn _sigemptyset(set: u32, ctx: &mut Ctx) -> i32 {
0 0
} }
pub fn _sigaction(signum: u32, act: u32, oldact: u32, _ctx: &mut Ctx) -> i32 { pub fn _sigaction(_ctx: &mut Ctx, signum: u32, act: u32, oldact: u32) -> i32 {
debug!("emscripten::_sigaction {}, {}, {}", signum, act, oldact); debug!("emscripten::_sigaction {}, {}, {}", signum, act, oldact);
0 0
} }
#[allow(clippy::cast_ptr_alignment)] #[allow(clippy::cast_ptr_alignment)]
pub fn _sigaddset(set: u32, signum: u32, ctx: &mut Ctx) -> i32 { pub fn _sigaddset(ctx: &mut Ctx, set: u32, signum: u32) -> i32 {
debug!("emscripten::_sigaddset {}, {}", set, signum); debug!("emscripten::_sigaddset {}, {}", set, signum);
let set_addr = emscripten_memory_pointer!(ctx.memory(0), set) as *mut u32; let set_addr = emscripten_memory_pointer!(ctx.memory(0), set) as *mut u32;
unsafe { unsafe {
@ -26,17 +26,17 @@ pub fn _sigaddset(set: u32, signum: u32, ctx: &mut Ctx) -> i32 {
0 0
} }
pub fn _sigsuspend(_one: i32, _ctx: &mut Ctx) -> i32 { pub fn _sigsuspend(_ctx: &mut Ctx, _one: i32) -> i32 {
debug!("emscripten::_sigsuspend"); debug!("emscripten::_sigsuspend");
-1 -1
} }
pub fn _sigprocmask(_one: i32, _two: i32, _three: i32, _ctx: &mut Ctx) -> i32 { pub fn _sigprocmask(_ctx: &mut Ctx, _one: i32, _two: i32, _three: i32) -> i32 {
debug!("emscripten::_sigprocmask"); debug!("emscripten::_sigprocmask");
0 0
} }
pub fn _signal(sig: u32, _two: i32, _ctx: &mut Ctx) -> i32 { pub fn _signal(_ctx: &mut Ctx, sig: u32, _two: i32) -> i32 {
debug!("emscripten::_signal ({})", sig); debug!("emscripten::_signal ({})", sig);
0 0
} }

View File

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

View File

@ -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;
@ -70,7 +52,7 @@ use libc::SO_NOSIGPIPE;
const SO_NOSIGPIPE: c_int = 0; const SO_NOSIGPIPE: c_int = 0;
/// exit /// exit
pub fn ___syscall1(which: c_int, mut varargs: VarArgs, ctx: &mut Ctx) { pub fn ___syscall1(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) {
debug!("emscripten::___syscall1 (exit) {}", which); debug!("emscripten::___syscall1 (exit) {}", which);
let status: i32 = varargs.get(ctx); let status: i32 = varargs.get(ctx);
unsafe { unsafe {
@ -79,7 +61,7 @@ pub fn ___syscall1(which: c_int, mut varargs: VarArgs, ctx: &mut Ctx) {
} }
/// read /// read
pub fn ___syscall3(which: i32, mut varargs: VarArgs, ctx: &mut Ctx) -> i32 { pub fn ___syscall3(ctx: &mut Ctx, which: i32, mut varargs: VarArgs) -> i32 {
// -> ssize_t // -> ssize_t
debug!("emscripten::___syscall3 (read) {}", which); debug!("emscripten::___syscall3 (read) {}", which);
let fd: i32 = varargs.get(ctx); let fd: i32 = varargs.get(ctx);
@ -93,7 +75,7 @@ pub fn ___syscall3(which: i32, mut varargs: VarArgs, ctx: &mut Ctx) -> i32 {
} }
/// write /// write
pub fn ___syscall4(which: c_int, mut varargs: VarArgs, ctx: &mut Ctx) -> c_int { 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);
@ -104,7 +86,7 @@ pub fn ___syscall4(which: c_int, mut varargs: VarArgs, ctx: &mut Ctx) -> c_int {
} }
/// open /// open
pub fn ___syscall5(which: c_int, mut varargs: VarArgs, ctx: &mut Ctx) -> c_int { pub fn ___syscall5(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall5 (open) {}", which); debug!("emscripten::___syscall5 (open) {}", which);
let pathname: u32 = varargs.get(ctx); let pathname: u32 = varargs.get(ctx);
let flags: i32 = varargs.get(ctx); let flags: i32 = varargs.get(ctx);
@ -120,7 +102,7 @@ pub fn ___syscall5(which: c_int, mut varargs: VarArgs, ctx: &mut Ctx) -> c_int {
} }
/// close /// close
pub fn ___syscall6(which: c_int, mut varargs: VarArgs, ctx: &mut Ctx) -> c_int { pub fn ___syscall6(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall6 (close) {}", which); debug!("emscripten::___syscall6 (close) {}", which);
let fd: i32 = varargs.get(ctx); let fd: i32 = varargs.get(ctx);
debug!("fd: {}", fd); debug!("fd: {}", fd);
@ -128,7 +110,7 @@ pub fn ___syscall6(which: c_int, mut varargs: VarArgs, ctx: &mut Ctx) -> c_int {
} }
// chdir // chdir
pub fn ___syscall12(which: c_int, mut varargs: VarArgs, ctx: &mut Ctx) -> c_int { pub fn ___syscall12(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall12 (chdir) {}", which); debug!("emscripten::___syscall12 (chdir) {}", which);
let path_addr: i32 = varargs.get(ctx); let path_addr: i32 = varargs.get(ctx);
unsafe { unsafe {
@ -140,42 +122,42 @@ pub fn ___syscall12(which: c_int, mut varargs: VarArgs, ctx: &mut Ctx) -> c_int
} }
} }
pub fn ___syscall10(_one: i32, _two: i32, _ctx: &mut Ctx) -> i32 { pub fn ___syscall10(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall10"); debug!("emscripten::___syscall10");
-1 -1
} }
pub fn ___syscall15(_one: i32, _two: i32, _ctx: &mut Ctx) -> i32 { pub fn ___syscall15(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall15"); debug!("emscripten::___syscall15");
-1 -1
} }
// getpid // getpid
pub fn ___syscall20(_one: i32, _two: i32, _ctx: &mut Ctx) -> i32 { pub fn ___syscall20(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall20 (getpid)"); debug!("emscripten::___syscall20 (getpid)");
unsafe { getpid() } unsafe { getpid() }
} }
pub fn ___syscall38(_one: i32, _two: i32, _ctx: &mut Ctx) -> i32 { pub fn ___syscall38(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall38"); debug!("emscripten::___syscall38");
-1 -1
} }
// rmdir // rmdir
pub fn ___syscall40(_which: c_int, mut varargs: VarArgs, ctx: &mut Ctx) -> c_int { pub fn ___syscall40(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall40 (rmdir)"); debug!("emscripten::___syscall40 (rmdir)");
let pathname: u32 = varargs.get(ctx); let pathname: u32 = varargs.get(ctx);
let pathname_addr = emscripten_memory_pointer!(ctx.memory(0), pathname) as *const i8; let pathname_addr = emscripten_memory_pointer!(ctx.memory(0), pathname) as *const i8;
unsafe { rmdir(pathname_addr) } unsafe { rmdir(pathname_addr) }
} }
pub fn ___syscall60(_one: i32, _two: i32, _ctx: &mut Ctx) -> i32 { pub fn ___syscall60(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall60"); debug!("emscripten::___syscall60");
-1 -1
} }
// dup2 // dup2
pub fn ___syscall63(which: c_int, mut varargs: VarArgs, ctx: &mut Ctx) -> c_int { pub fn ___syscall63(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall63 (dup2) {}", which); debug!("emscripten::___syscall63 (dup2) {}", which);
let src: i32 = varargs.get(ctx); let src: i32 = varargs.get(ctx);
@ -185,43 +167,43 @@ pub fn ___syscall63(which: c_int, mut varargs: VarArgs, ctx: &mut Ctx) -> c_int
} }
// getppid // getppid
pub fn ___syscall64(_one: i32, _two: i32, _ctx: &mut Ctx) -> i32 { pub fn ___syscall64(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall64 (getppid)"); debug!("emscripten::___syscall64 (getppid)");
unsafe { getpid() } unsafe { getpid() }
} }
pub fn ___syscall66(_one: i32, _two: i32, _ctx: &mut Ctx) -> i32 { pub fn ___syscall66(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall66"); debug!("emscripten::___syscall66");
-1 -1
} }
pub fn ___syscall75(_one: i32, _two: i32, _ctx: &mut Ctx) -> i32 { pub fn ___syscall75(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall75"); debug!("emscripten::___syscall75");
-1 -1
} }
pub fn ___syscall85(_one: i32, _two: i32, _ctx: &mut Ctx) -> i32 { pub fn ___syscall85(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall85"); debug!("emscripten::___syscall85");
-1 -1
} }
pub fn ___syscall91(_one: i32, _two: i32, _ctx: &mut Ctx) -> i32 { pub fn ___syscall91(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall91"); debug!("emscripten::___syscall91");
-1 -1
} }
pub fn ___syscall97(_one: i32, _two: i32, _ctx: &mut Ctx) -> i32 { pub fn ___syscall97(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall97"); debug!("emscripten::___syscall97");
-1 -1
} }
pub fn ___syscall110(_one: i32, _two: i32, _ctx: &mut Ctx) -> i32 { pub fn ___syscall110(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall110"); debug!("emscripten::___syscall110");
-1 -1
} }
// mmap2 // mmap2
pub fn ___syscall192(which: c_int, mut varargs: VarArgs, ctx: &mut Ctx) -> 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);
let addr: i32 = varargs.get(ctx); let addr: i32 = varargs.get(ctx);
let len: u32 = varargs.get(ctx); let len: u32 = varargs.get(ctx);
@ -235,11 +217,11 @@ pub fn ___syscall192(which: c_int, mut varargs: VarArgs, ctx: &mut Ctx) -> c_int
); );
if fd == -1 { if fd == -1 {
let ptr = env::call_memalign(16384, len, ctx); let ptr = env::call_memalign(ctx, 16384, len);
if ptr == 0 { if ptr == 0 {
return -1; return -1;
} }
env::call_memset(ptr, 0, len, ctx); env::call_memset(ctx, ptr, 0, len);
ptr as _ ptr as _
} else { } else {
-1 -1
@ -247,7 +229,7 @@ pub fn ___syscall192(which: c_int, mut varargs: VarArgs, ctx: &mut Ctx) -> c_int
} }
/// lseek /// lseek
pub fn ___syscall140(which: i32, mut varargs: VarArgs, ctx: &mut Ctx) -> i32 { 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);
@ -259,7 +241,7 @@ pub fn ___syscall140(which: i32, mut varargs: VarArgs, ctx: &mut Ctx) -> i32 {
/// readv /// readv
#[allow(clippy::cast_ptr_alignment)] #[allow(clippy::cast_ptr_alignment)]
pub fn ___syscall145(which: c_int, mut varargs: VarArgs, ctx: &mut Ctx) -> i32 { pub fn ___syscall145(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> i32 {
// -> ssize_t // -> ssize_t
debug!("emscripten::___syscall145 (readv) {}", which); debug!("emscripten::___syscall145 (readv) {}", which);
// let fd: i32 = varargs.get(ctx); // let fd: i32 = varargs.get(ctx);
@ -302,7 +284,7 @@ pub fn ___syscall145(which: c_int, mut varargs: VarArgs, ctx: &mut Ctx) -> i32 {
// writev // writev
#[allow(clippy::cast_ptr_alignment)] #[allow(clippy::cast_ptr_alignment)]
pub fn ___syscall146(which: i32, mut varargs: VarArgs, ctx: &mut Ctx) -> i32 { pub fn ___syscall146(ctx: &mut Ctx, which: i32, mut varargs: VarArgs) -> i32 {
// -> ssize_t // -> ssize_t
debug!("emscripten::___syscall146 (writev) {}", which); debug!("emscripten::___syscall146 (writev) {}", which);
let fd: i32 = varargs.get(ctx); let fd: i32 = varargs.get(ctx);
@ -336,33 +318,33 @@ pub fn ___syscall146(which: i32, mut varargs: VarArgs, ctx: &mut Ctx) -> i32 {
} }
} }
pub fn ___syscall168(_one: i32, _two: i32, _ctx: &mut Ctx) -> i32 { pub fn ___syscall168(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall168"); debug!("emscripten::___syscall168");
-1 -1
} }
pub fn ___syscall191(_one: i32, _two: i32, _ctx: &mut Ctx) -> i32 { pub fn ___syscall191(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall191 - stub"); debug!("emscripten::___syscall191 - stub");
-1 -1
} }
pub fn ___syscall194(_one: i32, _two: i32, _ctx: &mut Ctx) -> i32 { pub fn ___syscall194(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall194 - stub"); debug!("emscripten::___syscall194 - stub");
-1 -1
} }
pub fn ___syscall196(_one: i32, _two: i32, _ctx: &mut Ctx) -> i32 { pub fn ___syscall196(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall194 - stub"); debug!("emscripten::___syscall194 - stub");
-1 -1
} }
pub fn ___syscall199(_one: i32, _two: i32, _ctx: &mut Ctx) -> i32 { pub fn ___syscall199(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall199 - stub"); debug!("emscripten::___syscall199 - stub");
-1 -1
} }
// stat64 // stat64
pub fn ___syscall195(which: c_int, mut varargs: VarArgs, ctx: &mut Ctx) -> c_int { pub fn ___syscall195(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall195 (stat64) {}", which); debug!("emscripten::___syscall195 (stat64) {}", which);
let pathname: u32 = varargs.get(ctx); let pathname: u32 = varargs.get(ctx);
let buf: u32 = varargs.get(ctx); let buf: u32 = varargs.get(ctx);
@ -382,7 +364,7 @@ pub fn ___syscall195(which: c_int, mut varargs: VarArgs, ctx: &mut Ctx) -> c_int
} }
// fstat64 // fstat64
pub fn ___syscall197(which: c_int, mut varargs: VarArgs, ctx: &mut Ctx) -> c_int { pub fn ___syscall197(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall197 (fstat64) {}", which); debug!("emscripten::___syscall197 (fstat64) {}", which);
let fd: c_int = varargs.get(ctx); let fd: c_int = varargs.get(ctx);
let buf: u32 = varargs.get(ctx); let buf: u32 = varargs.get(ctx);
@ -400,13 +382,13 @@ pub fn ___syscall197(which: c_int, mut varargs: VarArgs, ctx: &mut Ctx) -> c_int
0 0
} }
pub fn ___syscall220(_one: i32, _two: i32, _ctx: &mut Ctx) -> i32 { pub fn ___syscall220(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall220"); debug!("emscripten::___syscall220");
-1 -1
} }
// fcntl64 // fcntl64
pub fn ___syscall221(which: c_int, mut varargs: VarArgs, ctx: &mut Ctx) -> c_int { pub fn ___syscall221(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall221 (fcntl64) {}", which); debug!("emscripten::___syscall221 (fcntl64) {}", which);
// fcntl64 // fcntl64
let _fd: i32 = varargs.get(ctx); let _fd: i32 = varargs.get(ctx);
@ -417,33 +399,33 @@ pub fn ___syscall221(which: c_int, mut varargs: VarArgs, ctx: &mut Ctx) -> c_int
} }
} }
pub fn ___syscall268(_one: i32, _two: i32, _ctx: &mut Ctx) -> i32 { pub fn ___syscall268(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall268"); debug!("emscripten::___syscall268");
-1 -1
} }
pub fn ___syscall272(_one: i32, _two: i32, _ctx: &mut Ctx) -> i32 { pub fn ___syscall272(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall272"); debug!("emscripten::___syscall272");
-1 -1
} }
pub fn ___syscall295(_one: i32, _two: i32, _ctx: &mut Ctx) -> i32 { pub fn ___syscall295(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall295"); debug!("emscripten::___syscall295");
-1 -1
} }
pub fn ___syscall300(_one: i32, _two: i32, _ctx: &mut Ctx) -> i32 { pub fn ___syscall300(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall300"); debug!("emscripten::___syscall300");
-1 -1
} }
pub fn ___syscall334(_one: i32, _two: i32, _ctx: &mut Ctx) -> i32 { pub fn ___syscall334(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall334"); debug!("emscripten::___syscall334");
-1 -1
} }
// prlimit64 // prlimit64
pub fn ___syscall340(which: c_int, mut varargs: VarArgs, ctx: &mut Ctx) -> c_int { pub fn ___syscall340(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall340 (prlimit64), {}", which); debug!("emscripten::___syscall340 (prlimit64), {}", which);
// NOTE: Doesn't really matter. Wasm modules cannot exceed WASM_PAGE_SIZE anyway. // NOTE: Doesn't really matter. Wasm modules cannot exceed WASM_PAGE_SIZE anyway.
let _pid: i32 = varargs.get(ctx); let _pid: i32 = varargs.get(ctx);

View File

@ -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")]
@ -94,7 +77,7 @@ use libc::SO_NOSIGPIPE;
const SO_NOSIGPIPE: c_int = 0; const SO_NOSIGPIPE: c_int = 0;
// chown // chown
pub fn ___syscall212(which: c_int, mut varargs: VarArgs, ctx: &mut Ctx) -> c_int { pub fn ___syscall212(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall212 (chown) {}", which); debug!("emscripten::___syscall212 (chown) {}", which);
let pathname: u32 = varargs.get(ctx); let pathname: u32 = varargs.get(ctx);
@ -107,7 +90,7 @@ pub fn ___syscall212(which: c_int, mut varargs: VarArgs, ctx: &mut Ctx) -> c_int
} }
// mkdir // mkdir
pub fn ___syscall39(which: c_int, mut varargs: VarArgs, ctx: &mut Ctx) -> c_int { pub fn ___syscall39(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall39 (mkdir) {}", which); debug!("emscripten::___syscall39 (mkdir) {}", which);
let pathname: u32 = varargs.get(ctx); let pathname: u32 = varargs.get(ctx);
let mode: u32 = varargs.get(ctx); let mode: u32 = varargs.get(ctx);
@ -116,7 +99,7 @@ pub fn ___syscall39(which: c_int, mut varargs: VarArgs, ctx: &mut Ctx) -> c_int
} }
// getgid // getgid
pub fn ___syscall201(_one: i32, _two: i32, _ctx: &mut Ctx) -> i32 { pub fn ___syscall201(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall201 (getgid)"); debug!("emscripten::___syscall201 (getgid)");
unsafe { unsafe {
// Maybe fix: Emscripten returns 0 always // Maybe fix: Emscripten returns 0 always
@ -125,7 +108,7 @@ pub fn ___syscall201(_one: i32, _two: i32, _ctx: &mut Ctx) -> i32 {
} }
// getgid32 // getgid32
pub fn ___syscall202(_one: i32, _two: i32, _ctx: &mut Ctx) -> i32 { pub fn ___syscall202(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
// gid_t // gid_t
debug!("emscripten::___syscall202 (getgid32)"); debug!("emscripten::___syscall202 (getgid32)");
unsafe { unsafe {
@ -135,7 +118,7 @@ pub fn ___syscall202(_one: i32, _two: i32, _ctx: &mut Ctx) -> i32 {
} }
/// dup3 /// dup3
pub fn ___syscall330(_which: c_int, mut varargs: VarArgs, ctx: &mut Ctx) -> pid_t { pub fn ___syscall330(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> pid_t {
// Implementation based on description at https://linux.die.net/man/2/dup3 // Implementation based on description at https://linux.die.net/man/2/dup3
debug!("emscripten::___syscall330 (dup3)"); debug!("emscripten::___syscall330 (dup3)");
let oldfd: c_int = varargs.get(ctx); let oldfd: c_int = varargs.get(ctx);
@ -169,7 +152,7 @@ pub fn ___syscall330(_which: c_int, mut varargs: VarArgs, ctx: &mut Ctx) -> pid_
} }
/// ioctl /// ioctl
pub fn ___syscall54(which: c_int, mut varargs: VarArgs, ctx: &mut Ctx) -> c_int { pub fn ___syscall54(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall54 (ioctl) {}", which); debug!("emscripten::___syscall54 (ioctl) {}", which);
let fd: i32 = varargs.get(ctx); let fd: i32 = varargs.get(ctx);
let request: u32 = varargs.get(ctx); let request: u32 = varargs.get(ctx);
@ -212,7 +195,7 @@ pub fn ___syscall54(which: c_int, mut varargs: VarArgs, ctx: &mut Ctx) -> c_int
// socketcall // socketcall
#[allow(clippy::cast_ptr_alignment)] #[allow(clippy::cast_ptr_alignment)]
pub fn ___syscall102(which: c_int, mut varargs: VarArgs, ctx: &mut Ctx) -> c_int { pub fn ___syscall102(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall102 (socketcall) {}", which); debug!("emscripten::___syscall102 (socketcall) {}", which);
let call: u32 = varargs.get(ctx); let call: u32 = varargs.get(ctx);
let mut socket_varargs: VarArgs = varargs.get(ctx); let mut socket_varargs: VarArgs = varargs.get(ctx);
@ -464,7 +447,7 @@ pub fn ___syscall102(which: c_int, mut varargs: VarArgs, ctx: &mut Ctx) -> c_int
} }
// pread // pread
pub fn ___syscall180(which: c_int, mut varargs: VarArgs, ctx: &mut Ctx) -> c_int { pub fn ___syscall180(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall180 (pread) {}", which); debug!("emscripten::___syscall180 (pread) {}", 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);
@ -481,7 +464,7 @@ pub fn ___syscall180(which: c_int, mut varargs: VarArgs, ctx: &mut Ctx) -> c_int
} }
// pwrite // pwrite
pub fn ___syscall181(which: c_int, mut varargs: VarArgs, ctx: &mut Ctx) -> c_int { pub fn ___syscall181(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall181 (pwrite) {}", which); debug!("emscripten::___syscall181 (pwrite) {}", 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);
@ -503,7 +486,7 @@ pub fn ___syscall181(which: c_int, mut varargs: VarArgs, ctx: &mut Ctx) -> c_int
/// wait4 /// wait4
#[allow(clippy::cast_ptr_alignment)] #[allow(clippy::cast_ptr_alignment)]
pub fn ___syscall114(_which: c_int, mut varargs: VarArgs, ctx: &mut Ctx) -> pid_t { pub fn ___syscall114(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> pid_t {
debug!("emscripten::___syscall114 (wait4)"); debug!("emscripten::___syscall114 (wait4)");
let pid: pid_t = varargs.get(ctx); let pid: pid_t = varargs.get(ctx);
let status: u32 = varargs.get(ctx); let status: u32 = varargs.get(ctx);
@ -521,7 +504,7 @@ pub fn ___syscall114(_which: c_int, mut varargs: VarArgs, ctx: &mut Ctx) -> pid_
// select // select
#[allow(clippy::cast_ptr_alignment)] #[allow(clippy::cast_ptr_alignment)]
pub fn ___syscall142(which: c_int, mut varargs: VarArgs, ctx: &mut Ctx) -> c_int { pub fn ___syscall142(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall142 (newselect) {}", which); debug!("emscripten::___syscall142 (newselect) {}", which);
let nfds: i32 = varargs.get(ctx); let nfds: i32 = varargs.get(ctx);
@ -540,7 +523,7 @@ pub fn ___syscall142(which: c_int, mut varargs: VarArgs, ctx: &mut Ctx) -> c_int
} }
// setpgid // setpgid
pub fn ___syscall57(which: c_int, mut varargs: VarArgs, ctx: &mut Ctx) -> c_int { pub fn ___syscall57(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall57 (setpgid) {}", which); debug!("emscripten::___syscall57 (setpgid) {}", which);
let pid: i32 = varargs.get(ctx); let pid: i32 = varargs.get(ctx);
let pgid: i32 = varargs.get(ctx); let pgid: i32 = varargs.get(ctx);
@ -549,7 +532,7 @@ pub fn ___syscall57(which: c_int, mut varargs: VarArgs, ctx: &mut Ctx) -> c_int
/// uname /// uname
// NOTE: Wondering if we should return custom utsname, like Emscripten. // NOTE: Wondering if we should return custom utsname, like Emscripten.
pub fn ___syscall122(which: c_int, mut varargs: VarArgs, ctx: &mut Ctx) -> c_int { pub fn ___syscall122(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall122 (uname) {}", which); debug!("emscripten::___syscall122 (uname) {}", which);
let buf: u32 = varargs.get(ctx); let buf: u32 = varargs.get(ctx);
debug!("=> buf: {}", buf); debug!("=> buf: {}", buf);

View File

@ -6,13 +6,13 @@ use wasmer_runtime_core::vm::Ctx;
type pid_t = c_int; type pid_t = c_int;
// chown // chown
pub fn ___syscall212(which: c_int, mut varargs: VarArgs, ctx: &mut Ctx) -> c_int { pub fn ___syscall212(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall212 (chown) {}", which); debug!("emscripten::___syscall212 (chown) {}", which);
-1 -1
} }
// mkdir // mkdir
pub fn ___syscall39(which: c_int, mut varargs: VarArgs, ctx: &mut Ctx) -> c_int { pub fn ___syscall39(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall39 (mkdir) {}", which); debug!("emscripten::___syscall39 (mkdir) {}", which);
let pathname: u32 = varargs.get(ctx); let pathname: u32 = varargs.get(ctx);
let mode: u32 = varargs.get(ctx); let mode: u32 = varargs.get(ctx);
@ -21,72 +21,72 @@ pub fn ___syscall39(which: c_int, mut varargs: VarArgs, ctx: &mut Ctx) -> c_int
} }
// getgid // getgid
pub fn ___syscall201(_one: i32, _two: i32, _ctx: &mut Ctx) -> i32 { pub fn ___syscall201(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall201 (getgid)"); debug!("emscripten::___syscall201 (getgid)");
-1 -1
} }
// getgid32 // getgid32
pub fn ___syscall202(_one: i32, _two: i32, _ctx: &mut Ctx) -> i32 { pub fn ___syscall202(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
// gid_t // gid_t
debug!("emscripten::___syscall202 (getgid32)"); debug!("emscripten::___syscall202 (getgid32)");
-1 -1
} }
/// dup3 /// dup3
pub fn ___syscall330(_which: c_int, mut varargs: VarArgs, ctx: &mut Ctx) -> pid_t { pub fn ___syscall330(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> pid_t {
debug!("emscripten::___syscall330 (dup3)"); debug!("emscripten::___syscall330 (dup3)");
-1 -1
} }
/// ioctl /// ioctl
pub fn ___syscall54(which: c_int, mut varargs: VarArgs, ctx: &mut Ctx) -> c_int { pub fn ___syscall54(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall54 (ioctl) {}", which); debug!("emscripten::___syscall54 (ioctl) {}", which);
-1 -1
} }
// socketcall // socketcall
#[allow(clippy::cast_ptr_alignment)] #[allow(clippy::cast_ptr_alignment)]
pub fn ___syscall102(which: c_int, mut varargs: VarArgs, ctx: &mut Ctx) -> c_int { pub fn ___syscall102(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall102 (socketcall) {}", which); debug!("emscripten::___syscall102 (socketcall) {}", which);
-1 -1
} }
// pread // pread
pub fn ___syscall180(which: c_int, mut varargs: VarArgs, ctx: &mut Ctx) -> c_int { pub fn ___syscall180(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall180 (pread) {}", which); debug!("emscripten::___syscall180 (pread) {}", which);
-1 -1
} }
// pwrite // pwrite
pub fn ___syscall181(which: c_int, mut varargs: VarArgs, ctx: &mut Ctx) -> c_int { pub fn ___syscall181(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall181 (pwrite) {}", which); debug!("emscripten::___syscall181 (pwrite) {}", which);
-1 -1
} }
/// wait4 /// wait4
#[allow(clippy::cast_ptr_alignment)] #[allow(clippy::cast_ptr_alignment)]
pub fn ___syscall114(_which: c_int, mut varargs: VarArgs, ctx: &mut Ctx) -> pid_t { pub fn ___syscall114(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> pid_t {
debug!("emscripten::___syscall114 (wait4)"); debug!("emscripten::___syscall114 (wait4)");
-1 -1
} }
// select // select
#[allow(clippy::cast_ptr_alignment)] #[allow(clippy::cast_ptr_alignment)]
pub fn ___syscall142(which: c_int, mut varargs: VarArgs, ctx: &mut Ctx) -> c_int { pub fn ___syscall142(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall142 (newselect) {}", which); debug!("emscripten::___syscall142 (newselect) {}", which);
-1 -1
} }
// setpgid // setpgid
pub fn ___syscall57(which: c_int, mut varargs: VarArgs, ctx: &mut Ctx) -> c_int { pub fn ___syscall57(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall57 (setpgid) {}", which); debug!("emscripten::___syscall57 (setpgid) {}", which);
-1 -1
} }
/// uname /// uname
// NOTE: Wondering if we should return custom utsname, like Emscripten. // NOTE: Wondering if we should return custom utsname, like Emscripten.
pub fn ___syscall122(which: c_int, mut varargs: VarArgs, ctx: &mut Ctx) -> c_int { pub fn ___syscall122(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall122 (uname) {}", which); debug!("emscripten::___syscall122 (uname) {}", which);
-1 -1
} }

View File

@ -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;
@ -39,7 +41,7 @@ const CLOCK_MONOTONIC_COARSE: clockid_t = 6;
/// emscripten: _gettimeofday /// emscripten: _gettimeofday
#[allow(clippy::cast_ptr_alignment)] #[allow(clippy::cast_ptr_alignment)]
pub fn _gettimeofday(tp: c_int, tz: c_int, ctx: &mut Ctx) -> c_int { pub fn _gettimeofday(ctx: &mut Ctx, tp: c_int, tz: c_int) -> c_int {
debug!("emscripten::_gettimeofday {} {}", tp, tz); debug!("emscripten::_gettimeofday {} {}", tp, tz);
#[repr(C)] #[repr(C)]
struct GuestTimeVal { struct GuestTimeVal {
@ -64,7 +66,7 @@ pub fn _gettimeofday(tp: c_int, tz: c_int, ctx: &mut Ctx) -> c_int {
/// emscripten: _clock_gettime /// emscripten: _clock_gettime
#[allow(clippy::cast_ptr_alignment)] #[allow(clippy::cast_ptr_alignment)]
pub fn _clock_gettime(clk_id: clockid_t, tp: c_int, ctx: &mut Ctx) -> c_int { pub fn _clock_gettime(ctx: &mut Ctx, clk_id: clockid_t, tp: c_int) -> c_int {
debug!("emscripten::_clock_gettime {} {}", clk_id, tp); debug!("emscripten::_clock_gettime {} {}", clk_id, tp);
// debug!("Memory {:?}", ctx.memory(0)[..]); // debug!("Memory {:?}", ctx.memory(0)[..]);
#[repr(C)] #[repr(C)]
@ -95,9 +97,9 @@ pub fn _clock_gettime(clk_id: clockid_t, tp: c_int, ctx: &mut Ctx) -> c_int {
} }
/// emscripten: ___clock_gettime /// emscripten: ___clock_gettime
pub fn ___clock_gettime(clk_id: clockid_t, tp: c_int, ctx: &mut Ctx) -> c_int { pub fn ___clock_gettime(ctx: &mut Ctx, clk_id: clockid_t, tp: c_int) -> c_int {
debug!("emscripten::___clock_gettime {} {}", clk_id, tp); debug!("emscripten::___clock_gettime {} {}", clk_id, tp);
_clock_gettime(clk_id, tp, ctx) _clock_gettime(ctx, clk_id, tp)
} }
/// emscripten: _clock /// emscripten: _clock
@ -107,22 +109,22 @@ pub fn _clock(_ctx: &mut Ctx) -> c_int {
} }
/// emscripten: _difftime /// emscripten: _difftime
pub fn _difftime(t0: u32, t1: u32, _ctx: &mut Ctx) -> f64 { pub fn _difftime(_ctx: &mut Ctx, t0: u32, t1: u32) -> f64 {
debug!("emscripten::_difftime"); debug!("emscripten::_difftime");
(t0 - t1) as _ (t0 - t1) as _
} }
pub fn _gmtime_r(_one: i32, _two: i32, _ctx: &mut Ctx) -> i32 { pub fn _gmtime_r(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
debug!("emscripten::_gmtime_r"); debug!("emscripten::_gmtime_r");
-1 -1
} }
pub fn _mktime(_one: i32, _ctx: &mut Ctx) -> i32 { pub fn _mktime(_ctx: &mut Ctx, _one: i32) -> i32 {
debug!("emscripten::_mktime"); debug!("emscripten::_mktime");
-1 -1
} }
pub fn _gmtime(_one: i32, _ctx: &mut Ctx) -> i32 { pub fn _gmtime(_ctx: &mut Ctx, _one: i32) -> i32 {
debug!("emscripten::_gmtime"); debug!("emscripten::_gmtime");
-1 -1
} }
@ -149,7 +151,7 @@ pub fn _tvset(_ctx: &mut Ctx) {
/// formats time as a C string /// formats time as a C string
#[allow(clippy::cast_ptr_alignment)] #[allow(clippy::cast_ptr_alignment)]
unsafe fn fmt_time(time: u32, ctx: &mut Ctx) -> *const c_char { unsafe fn fmt_time(ctx: &mut Ctx, time: u32) -> *const c_char {
let date = &*(emscripten_memory_pointer!(ctx.memory(0), time) as *mut guest_tm); let date = &*(emscripten_memory_pointer!(ctx.memory(0), time) as *mut guest_tm);
let days = vec!["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]; let days = vec!["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
@ -174,11 +176,11 @@ unsafe fn fmt_time(time: u32, ctx: &mut Ctx) -> *const c_char {
} }
/// emscripten: _asctime /// emscripten: _asctime
pub fn _asctime(time: u32, ctx: &mut Ctx) -> u32 { pub fn _asctime(ctx: &mut Ctx, time: u32) -> u32 {
debug!("emscripten::_asctime {}", time); debug!("emscripten::_asctime {}", time);
unsafe { unsafe {
let time_str_ptr = fmt_time(time, ctx); let time_str_ptr = fmt_time(ctx, time);
copy_cstr_into_wasm(ctx, time_str_ptr) copy_cstr_into_wasm(ctx, time_str_ptr)
// let c_str = emscripten_memory_pointer!(ctx.memory(0), res) as *mut i8; // let c_str = emscripten_memory_pointer!(ctx.memory(0), res) as *mut i8;
@ -188,7 +190,7 @@ pub fn _asctime(time: u32, ctx: &mut Ctx) -> u32 {
} }
/// emscripten: _asctime_r /// emscripten: _asctime_r
pub fn _asctime_r(time: u32, buf: u32, ctx: &mut Ctx) -> u32 { pub fn _asctime_r(ctx: &mut Ctx, time: u32, buf: u32) -> u32 {
debug!("emscripten::_asctime_r {}, {}", time, buf); debug!("emscripten::_asctime_r {}, {}", time, buf);
unsafe { unsafe {
@ -196,8 +198,8 @@ pub fn _asctime_r(time: u32, buf: u32, ctx: &mut Ctx) -> u32 {
// to write out more than 26 bytes (including the null terminator). // to write out more than 26 bytes (including the null terminator).
// See http://pubs.opengroup.org/onlinepubs/9699919799/functions/asctime.html // See http://pubs.opengroup.org/onlinepubs/9699919799/functions/asctime.html
// Our undefined behavior is to truncate the write to at most 26 bytes, including null terminator. // Our undefined behavior is to truncate the write to at most 26 bytes, including null terminator.
let time_str_ptr = fmt_time(time, ctx); let time_str_ptr = fmt_time(ctx, time);
write_to_buf(time_str_ptr, buf, 26, ctx) write_to_buf(ctx, time_str_ptr, buf, 26)
// let c_str = emscripten_memory_pointer!(ctx.memory(0), res) as *mut i8; // let c_str = emscripten_memory_pointer!(ctx.memory(0), res) as *mut i8;
// use std::ffi::CStr; // use std::ffi::CStr;
@ -207,7 +209,7 @@ pub fn _asctime_r(time: u32, buf: u32, ctx: &mut Ctx) -> u32 {
/// emscripten: _localtime /// emscripten: _localtime
#[allow(clippy::cast_ptr_alignment)] #[allow(clippy::cast_ptr_alignment)]
pub fn _localtime(time_p: u32, ctx: &mut Ctx) -> c_int { pub fn _localtime(ctx: &mut Ctx, time_p: u32) -> c_int {
debug!("emscripten::_localtime {}", time_p); debug!("emscripten::_localtime {}", time_p);
// NOTE: emscripten seems to want tzset() called in this function // NOTE: emscripten seems to want tzset() called in this function
// https://stackoverflow.com/questions/19170721/real-time-awareness-of-timezone-change-in-localtime-vs-localtime-r // https://stackoverflow.com/questions/19170721/real-time-awareness-of-timezone-change-in-localtime-vs-localtime-r
@ -220,7 +222,7 @@ pub fn _localtime(time_p: u32, ctx: &mut Ctx) -> c_int {
let result_tm = time::at(timespec); let result_tm = time::at(timespec);
unsafe { unsafe {
let tm_struct_offset = env::call_malloc(mem::size_of::<guest_tm>() as _, ctx); let tm_struct_offset = env::call_malloc(ctx, mem::size_of::<guest_tm>() as _);
let tm_struct_ptr = let tm_struct_ptr =
emscripten_memory_pointer!(ctx.memory(0), tm_struct_offset) as *mut guest_tm; emscripten_memory_pointer!(ctx.memory(0), tm_struct_offset) as *mut guest_tm;
// debug!( // debug!(
@ -245,7 +247,7 @@ pub fn _localtime(time_p: u32, ctx: &mut Ctx) -> c_int {
} }
/// emscripten: _localtime_r /// emscripten: _localtime_r
#[allow(clippy::cast_ptr_alignment)] #[allow(clippy::cast_ptr_alignment)]
pub fn _localtime_r(time_p: u32, result: u32, ctx: &mut Ctx) -> c_int { pub fn _localtime_r(ctx: &mut Ctx, time_p: u32, result: u32) -> c_int {
debug!("emscripten::_localtime_r {}", time_p); debug!("emscripten::_localtime_r {}", time_p);
// NOTE: emscripten seems to want tzset() called in this function // NOTE: emscripten seems to want tzset() called in this function
@ -282,7 +284,7 @@ pub fn _localtime_r(time_p: u32, result: u32, ctx: &mut Ctx) -> c_int {
/// emscripten: _time /// emscripten: _time
#[allow(clippy::cast_ptr_alignment)] #[allow(clippy::cast_ptr_alignment)]
pub fn _time(time_p: u32, ctx: &mut Ctx) -> i32 { pub fn _time(ctx: &mut Ctx, time_p: u32) -> i32 {
debug!("emscripten::_time {}", time_p); debug!("emscripten::_time {}", time_p);
unsafe { unsafe {
@ -293,11 +295,11 @@ pub fn _time(time_p: u32, ctx: &mut Ctx) -> i32 {
/// emscripten: _strftime /// emscripten: _strftime
pub fn _strftime( pub fn _strftime(
_ctx: &mut Ctx,
s_ptr: c_int, s_ptr: c_int,
maxsize: u32, maxsize: u32,
format_ptr: c_int, format_ptr: c_int,
tm_ptr: c_int, tm_ptr: c_int,
_ctx: &mut Ctx,
) -> i32 { ) -> i32 {
debug!( debug!(
"emscripten::_strftime {} {} {} {}", "emscripten::_strftime {} {} {} {}",

View File

@ -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::{
@ -42,7 +40,7 @@ pub fn get_emscripten_memory_size(module: &Module) -> (Pages, Option<Pages>) {
(memory.minimum, memory.maximum) (memory.minimum, memory.maximum)
} }
pub unsafe fn write_to_buf(string: *const c_char, buf: u32, max: u32, ctx: &mut Ctx) -> u32 { pub unsafe fn write_to_buf(ctx: &mut Ctx, string: *const c_char, buf: u32, max: u32) -> u32 {
let buf_addr = emscripten_memory_pointer!(ctx.memory(0), buf) as *mut c_char; let buf_addr = emscripten_memory_pointer!(ctx.memory(0), buf) as *mut c_char;
for i in 0..max { for i in 0..max {
@ -56,7 +54,7 @@ pub unsafe fn write_to_buf(string: *const c_char, buf: u32, max: u32, ctx: &mut
pub unsafe fn copy_cstr_into_wasm(ctx: &mut Ctx, cstr: *const c_char) -> u32 { pub unsafe fn copy_cstr_into_wasm(ctx: &mut Ctx, cstr: *const c_char) -> u32 {
let s = CStr::from_ptr(cstr).to_str().unwrap(); let s = CStr::from_ptr(cstr).to_str().unwrap();
let cstr_len = s.len(); let cstr_len = s.len();
let space_offset = env::call_malloc((cstr_len as u32) + 1, ctx); let space_offset = env::call_malloc(ctx, (cstr_len as u32) + 1);
let raw_memory = emscripten_memory_pointer!(ctx.memory(0), space_offset) as *mut c_char; let raw_memory = emscripten_memory_pointer!(ctx.memory(0), space_offset) as *mut c_char;
let slice = slice::from_raw_parts_mut(raw_memory, cstr_len); let slice = slice::from_raw_parts_mut(raw_memory, cstr_len);
@ -71,7 +69,7 @@ pub unsafe fn copy_cstr_into_wasm(ctx: &mut Ctx, cstr: *const c_char) -> u32 {
space_offset space_offset
} }
pub unsafe fn allocate_on_stack<'a, T: Copy>(count: u32, ctx: &'a mut Ctx) -> (u32, &'a mut [T]) { pub unsafe fn allocate_on_stack<'a, T: Copy>(ctx: &'a mut Ctx, count: u32) -> (u32, &'a mut [T]) {
let offset = get_emscripten_data(ctx) let offset = get_emscripten_data(ctx)
.stack_alloc .stack_alloc
.call(count * (size_of::<T>() as u32)) .call(count * (size_of::<T>() as u32))
@ -82,8 +80,8 @@ pub unsafe fn allocate_on_stack<'a, T: Copy>(count: u32, ctx: &'a mut Ctx) -> (u
(offset, slice) (offset, slice)
} }
pub unsafe fn allocate_cstr_on_stack<'a>(s: &str, ctx: &'a mut Ctx) -> (u32, &'a [u8]) { pub unsafe fn allocate_cstr_on_stack<'a>(ctx: &'a mut Ctx, s: &str) -> (u32, &'a [u8]) {
let (offset, slice) = allocate_on_stack((s.len() + 1) as u32, ctx); let (offset, slice) = allocate_on_stack(ctx, (s.len() + 1) as u32);
use std::iter; use std::iter;
for (byte, loc) in s.bytes().chain(iter::once(0)).zip(slice.iter_mut()) { for (byte, loc) in s.bytes().chain(iter::once(0)).zip(slice.iter_mut()) {

View File

@ -32,7 +32,7 @@ impl IsExport for Export {
/// }, /// },
/// }; /// };
/// ///
/// fn foo(n: i32, _: &mut Ctx) -> i32 { /// fn foo(_: &mut Ctx, n: i32) -> i32 {
/// n /// n
/// } /// }
/// ``` /// ```

View File

@ -38,7 +38,7 @@ macro_rules! func {
/// }, /// },
/// }; /// };
/// ///
/// fn foo(n: i32, _: &mut Ctx) -> i32 { /// fn foo(_: &mut Ctx, n: i32) -> i32 {
/// n /// n
/// } /// }
/// ``` /// ```

View File

@ -150,7 +150,8 @@ impl Drop for Memory {
fn drop(&mut self) { fn drop(&mut self) {
if !self.ptr.is_null() { if !self.ptr.is_null() {
let success = unsafe { VirtualFree(self.ptr as _, self.size, MEM_DECOMMIT) }; let success = unsafe { VirtualFree(self.ptr as _, self.size, MEM_DECOMMIT) };
assert_eq!(success, 0, "failed to unmap memory: {}", errno::errno()); // If the function succeeds, the return value is nonzero.
assert_eq!(success, 1, "failed to unmap memory: {}", errno::errno());
} }
} }
} }

View File

@ -138,9 +138,9 @@ impl<A: WasmExternType> WasmTypeList for (A,) {
} }
#[allow(non_snake_case)] #[allow(non_snake_case)]
unsafe fn call<Rets: WasmTypeList>(self, f: *const (), ctx: *mut Ctx) -> Rets { unsafe fn call<Rets: WasmTypeList>(self, f: *const (), ctx: *mut Ctx) -> Rets {
let f: extern "C" fn(A, *mut Ctx) -> Rets = mem::transmute(f); let f: extern "C" fn(*mut Ctx, A) -> Rets = mem::transmute(f);
let (a,) = self; let (a,) = self;
f(a, ctx) f(ctx, a)
} }
} }
@ -175,24 +175,24 @@ macro_rules! impl_traits {
} }
#[allow(non_snake_case)] #[allow(non_snake_case)]
unsafe fn call<Rets: WasmTypeList>(self, f: *const (), ctx: *mut Ctx) -> Rets { unsafe fn call<Rets: WasmTypeList>(self, f: *const (), ctx: *mut Ctx) -> Rets {
let f: extern fn( $( $x, )* *mut Ctx) -> Rets::CStruct = mem::transmute(f); let f: extern fn(*mut Ctx $( ,$x )*) -> Rets::CStruct = mem::transmute(f);
#[allow(unused_parens)] #[allow(unused_parens)]
let ( $( $x ),* ) = self; let ( $( $x ),* ) = self;
let c_struct = f( $( $x, )* ctx); let c_struct = f(ctx $( ,$x )*);
Rets::from_c_struct(c_struct) Rets::from_c_struct(c_struct)
} }
} }
impl< $( $x: WasmExternType, )* Rets: WasmTypeList, Trap: TrapEarly<Rets>, FN: Fn( $( $x, )* &mut Ctx) -> Trap> ExternalFunction<($( $x ),*), Rets> for FN { impl< $( $x: WasmExternType, )* Rets: WasmTypeList, Trap: TrapEarly<Rets>, FN: Fn( &mut Ctx $( ,$x )* ) -> 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, Trap: TrapEarly<Rets>, FN: Fn( $( $x, )* &mut Ctx) -> Trap>( $( $x: $x, )* ctx: &mut Ctx) -> 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 msg = match panic::catch_unwind(panic::AssertUnwindSafe(|| {
f( $( $x, )* ctx).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,
@ -271,7 +271,7 @@ mod tests {
use super::*; use super::*;
#[test] #[test]
fn test_call() { fn test_call() {
fn foo(a: i32, b: i32, _ctx: &mut Ctx) -> (i32, i32) { fn foo(_ctx: &mut Ctx, a: i32, b: i32) -> (i32, i32) {
(a, b) (a, b)
} }
@ -282,7 +282,7 @@ mod tests {
fn test_imports() { fn test_imports() {
use crate::{func, imports}; use crate::{func, imports};
fn foo(a: i32, _ctx: &mut Ctx) -> i32 { fn foo(_ctx: &mut Ctx, a: i32) -> i32 {
a a
} }

View File

@ -169,6 +169,7 @@ enum InnerFunc {}
/// Used to provide type safety (ish) for passing around function pointers. /// Used to provide type safety (ish) for passing around function pointers.
/// The typesystem ensures this cannot be dereferenced since an /// The typesystem ensures this cannot be dereferenced since an
/// empty enum cannot actually exist. /// empty enum cannot actually exist.
#[repr(C)]
pub struct Func(InnerFunc); pub struct Func(InnerFunc);
/// An imported function, which contains the vmctx that owns this function. /// An imported function, which contains the vmctx that owns this function.

View File

@ -13,9 +13,9 @@ use crate::{
// +****************************+ // +****************************+
pub unsafe extern "C" fn local_static_memory_grow( pub unsafe extern "C" fn local_static_memory_grow(
ctx: &mut vm::Ctx,
memory_index: LocalMemoryIndex, memory_index: LocalMemoryIndex,
delta: Pages, delta: Pages,
ctx: &mut vm::Ctx,
) -> i32 { ) -> i32 {
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;
@ -28,8 +28,8 @@ pub unsafe extern "C" fn local_static_memory_grow(
} }
pub unsafe extern "C" fn local_static_memory_size( pub unsafe extern "C" fn local_static_memory_size(
memory_index: LocalMemoryIndex,
ctx: &vm::Ctx, ctx: &vm::Ctx,
memory_index: LocalMemoryIndex,
) -> Pages { ) -> Pages {
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;
@ -38,9 +38,9 @@ pub unsafe extern "C" fn local_static_memory_size(
} }
pub unsafe extern "C" fn local_dynamic_memory_grow( pub unsafe extern "C" fn local_dynamic_memory_grow(
ctx: &mut vm::Ctx,
memory_index: LocalMemoryIndex, memory_index: LocalMemoryIndex,
delta: Pages, delta: Pages,
ctx: &mut vm::Ctx,
) -> i32 { ) -> i32 {
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;
@ -53,8 +53,8 @@ pub unsafe extern "C" fn local_dynamic_memory_grow(
} }
pub unsafe extern "C" fn local_dynamic_memory_size( pub unsafe extern "C" fn local_dynamic_memory_size(
memory_index: LocalMemoryIndex,
ctx: &vm::Ctx, ctx: &vm::Ctx,
memory_index: LocalMemoryIndex,
) -> Pages { ) -> Pages {
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;
@ -67,9 +67,9 @@ pub unsafe extern "C" fn local_dynamic_memory_size(
// +****************************+ // +****************************+
pub unsafe extern "C" fn imported_static_memory_grow( pub unsafe extern "C" fn imported_static_memory_grow(
ctx: &mut vm::Ctx,
import_memory_index: ImportedMemoryIndex, import_memory_index: ImportedMemoryIndex,
delta: Pages, delta: Pages,
ctx: &mut vm::Ctx,
) -> i32 { ) -> i32 {
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;
@ -82,8 +82,8 @@ pub unsafe extern "C" fn imported_static_memory_grow(
} }
pub unsafe extern "C" fn imported_static_memory_size( pub unsafe extern "C" fn imported_static_memory_size(
import_memory_index: ImportedMemoryIndex,
ctx: &vm::Ctx, ctx: &vm::Ctx,
import_memory_index: ImportedMemoryIndex,
) -> Pages { ) -> Pages {
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;
@ -92,9 +92,9 @@ pub unsafe extern "C" fn imported_static_memory_size(
} }
pub unsafe extern "C" fn imported_dynamic_memory_grow( pub unsafe extern "C" fn imported_dynamic_memory_grow(
ctx: &mut vm::Ctx,
memory_index: ImportedMemoryIndex, memory_index: ImportedMemoryIndex,
delta: Pages, delta: Pages,
ctx: &mut vm::Ctx,
) -> i32 { ) -> i32 {
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;
@ -107,8 +107,8 @@ pub unsafe extern "C" fn imported_dynamic_memory_grow(
} }
pub unsafe extern "C" fn imported_dynamic_memory_size( pub unsafe extern "C" fn imported_dynamic_memory_size(
memory_index: ImportedMemoryIndex,
ctx: &vm::Ctx, ctx: &vm::Ctx,
memory_index: ImportedMemoryIndex,
) -> Pages { ) -> Pages {
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;
@ -121,9 +121,9 @@ pub unsafe extern "C" fn imported_dynamic_memory_size(
// +****************************+ // +****************************+
pub unsafe extern "C" fn local_table_grow( pub unsafe extern "C" fn local_table_grow(
ctx: &mut vm::Ctx,
table_index: LocalTableIndex, table_index: LocalTableIndex,
delta: u32, delta: u32,
ctx: &mut vm::Ctx,
) -> i32 { ) -> i32 {
let _ = table_index; let _ = table_index;
let _ = delta; let _ = delta;
@ -131,7 +131,7 @@ pub unsafe extern "C" fn local_table_grow(
unimplemented!() unimplemented!()
} }
pub unsafe extern "C" fn local_table_size(table_index: LocalTableIndex, ctx: &vm::Ctx) -> u32 { pub unsafe extern "C" fn local_table_size(ctx: &vm::Ctx, table_index: LocalTableIndex) -> u32 {
let _ = table_index; let _ = table_index;
let _ = ctx; let _ = ctx;
unimplemented!() unimplemented!()

View File

@ -1,8 +1,6 @@
use std::fs::remove_file;
use wabt::wat2wasm; use wabt::wat2wasm;
use wasmer_clif_backend::CraneliftCompiler; use wasmer_clif_backend::CraneliftCompiler;
use wasmer_runtime_core::{ use wasmer_runtime_core::{
cache::Cache,
error, error,
global::Global, global::Global,
memory::Memory, memory::Memory,
@ -15,7 +13,6 @@ use wasmer_runtime_core::{
static EXAMPLE_WASM: &'static [u8] = include_bytes!("simple.wasm"); static EXAMPLE_WASM: &'static [u8] = include_bytes!("simple.wasm");
fn main() -> error::Result<()> { fn main() -> error::Result<()> {
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");
let inner_module = wasmer_runtime_core::compile_with(&wasm_binary, &CraneliftCompiler::new())?; let inner_module = wasmer_runtime_core::compile_with(&wasm_binary, &CraneliftCompiler::new())?;
@ -61,7 +58,7 @@ fn main() -> error::Result<()> {
Ok(()) Ok(())
} }
fn print_num(n: i32, ctx: &mut vm::Ctx) -> Result<i32, ()> { fn print_num(ctx: &mut vm::Ctx, n: i32) -> Result<i32, ()> {
println!("print_num({})", n); println!("print_num({})", n);
let memory: &Memory = ctx.memory(0); let memory: &Memory = ctx.memory(0);

View File

@ -0,0 +1,18 @@
[package]
name = "wasmer-win-exception-handler"
version = "0.0.1"
description = "Wasmer runtime exception handling for Windows"
license = "MIT"
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
repository = "https://github.com/wasmerio/wasmer"
edition = "2018"
[target.'cfg(windows)'.dependencies]
wasmer-runtime-core = { path = "../runtime-core", version = "0.1.2" }
winapi = { version = "0.3", features = ["winbase", "errhandlingapi", "minwindef", "minwinbase", "winnt"] }
libc = "0.2.48"
[build-dependencies]
cmake = "0.1.35"
bindgen = "0.46.0"
regex = "1.0.6"

View File

@ -0,0 +1,11 @@
use cmake::Config;
fn main() {
#[cfg(target_os = "windows")]
{
let project_name = "exception_handling";
let dst = Config::new(project_name).build();
println!("cargo:rustc-link-search=native={}", dst.display());
println!("cargo:rustc-link-lib=static={}", project_name);
}
}

View File

@ -0,0 +1 @@
cmake-build-*

View File

@ -0,0 +1,6 @@
cmake_minimum_required(VERSION 3.0)
project(exception_handling C)
add_library(exception_handling STATIC exception_handling.c)
install(TARGETS exception_handling DESTINATION .)

View File

@ -0,0 +1,74 @@
#include <windows.h>
#include <setjmp.h>
#include "exception_handling.h"
#define CALL_FIRST 1
__declspec(thread) jmp_buf jmpBuf;
__declspec(thread) PVOID caughtExceptionAddress;
__declspec(thread) DWORD64 caughtInstructionPointer;
__declspec(thread) PVOID savedStackPointer;
__declspec(thread) BOOL exceptionHandlerInstalled = FALSE;
__declspec(thread) BOOL alreadyHandlingException = FALSE;
void longjmpOutOfHere() {
longjmp(jmpBuf, 1);
}
/// Get the current address that we use to jmp, the no inline is important
static __declspec(noinline) void *get_callee_frame_address(void) {
return _AddressOfReturnAddress();
}
static LONG WINAPI
exceptionHandler(struct _EXCEPTION_POINTERS *ExceptionInfo) {
EXCEPTION_RECORD* pExceptionRecord = ExceptionInfo->ExceptionRecord;
PCONTEXT pCONTEXT = ExceptionInfo->ContextRecord;
caughtExceptionAddress = pExceptionRecord->ExceptionAddress;
caughtInstructionPointer = pCONTEXT->Rip;
if (alreadyHandlingException == TRUE) {
return EXCEPTION_CONTINUE_SEARCH;
}
alreadyHandlingException = TRUE;
// Basically, here, we coerce the os to resume us into a context that calls `longjmp` instead of just continuing.
// Presumably, we cannot `longjmp` out of the signal/exception context, like we can on unix.
pCONTEXT->Rip = (uintptr_t)(&longjmpOutOfHere);
pCONTEXT->Rsp = (uintptr_t)(savedStackPointer);
return EXCEPTION_CONTINUE_EXECUTION;
}
uint8_t callProtected(trampoline_t trampoline,
const struct wasmer_instance_context_t* ctx,
const struct func_t* func,
const uint64_t* param_vec,
uint64_t* return_vec,
struct call_protected_result_t* out_result) {
// install exception handler
if (exceptionHandlerInstalled == FALSE) {
exceptionHandlerInstalled = TRUE;
AddVectoredExceptionHandler(CALL_FIRST, exceptionHandler);
}
// jmp jmp jmp!
int signum = setjmp(jmpBuf);
if (signum == 0) {
// save the stack pointer
savedStackPointer = get_callee_frame_address();
trampoline(ctx, func, param_vec, return_vec);
out_result->code = 0;
out_result->exceptionAddress = 0;
out_result->instructionPointer = 0;
return TRUE;
}
out_result->code = (uint64_t)signum;
out_result->exceptionAddress = (uint64_t)caughtExceptionAddress;
out_result->instructionPointer = caughtInstructionPointer;
caughtExceptionAddress = 0;
caughtInstructionPointer = 0;
return FALSE;
}

View File

@ -0,0 +1,25 @@
#ifndef WASMER_EXCEPTION_HANDLING_H
#define WASMER_EXCEPTION_HANDLING_H
#include <stdint.h>
struct func_t;
struct wasmer_instance_context_t;
typedef void(*trampoline_t)(struct wasmer_instance_context_t*, const struct func_t*, const uint64_t*, uint64_t*);
struct call_protected_result_t {
uint64_t code;
uint64_t exceptionAddress;
uint64_t instructionPointer;
};
uint8_t callProtected(
trampoline_t trampoline,
const struct wasmer_instance_context_t* ctx,
const struct func_t* func,
const uint64_t* param_vec,
uint64_t* return_vec,
struct call_protected_result_t* out_result);
#endif //WASMER_EXCEPTION_HANDLING_H

View File

@ -0,0 +1,53 @@
use std::ffi::c_void;
use wasmer_runtime_core::vm::{Ctx, Func};
type Trampoline = unsafe extern "C" fn(*mut Ctx, *const Func, *const u64, *mut u64) -> c_void;
type CallProtectedResult = Result<(), CallProtectedData>;
#[repr(C)]
pub struct CallProtectedData {
pub code: u64,
pub exceptionAddress: u64,
pub instructionPointer: u64,
}
extern "C" {
#[link_name = "callProtected"]
pub fn __call_protected(
trampoline: Trampoline,
ctx: *mut Ctx,
func: *const Func,
param_vec: *const u64,
return_vec: *mut u64,
out_result: *mut CallProtectedData,
) -> u8;
}
pub fn _call_protected(
trampoline: Trampoline,
ctx: *mut Ctx,
func: *const Func,
param_vec: *const u64,
return_vec: *mut u64,
) -> CallProtectedResult {
let mut out_result = CallProtectedData {
code: 0,
exceptionAddress: 0,
instructionPointer: 0,
};
let result = unsafe {
__call_protected(
trampoline,
ctx,
func,
param_vec,
return_vec,
&mut out_result,
)
};
if result == 1 {
Ok(())
} else {
Err(out_result)
}
}

View File

@ -0,0 +1,5 @@
#[cfg(windows)]
mod exception_handling;
#[cfg(windows)]
pub use self::exception_handling::*;

View File

@ -69,7 +69,7 @@ fn execute_wasm(options: &Run) -> Result<(), String> {
let module = webassembly::compile(&wasm_binary[..]) let module = webassembly::compile(&wasm_binary[..])
.map_err(|e| format!("Can't compile module: {:?}", e))?; .map_err(|e| format!("Can't compile module: {:?}", e))?;
let (_abi, import_object, em_globals) = if wasmer_emscripten::is_emscripten_module(&module) { let (_abi, import_object, _em_globals) = if wasmer_emscripten::is_emscripten_module(&module) {
let mut emscripten_globals = wasmer_emscripten::EmscriptenGlobals::new(&module); let mut emscripten_globals = wasmer_emscripten::EmscriptenGlobals::new(&module);
( (
InstanceABI::Emscripten, InstanceABI::Emscripten,
@ -113,6 +113,11 @@ fn main() {
let options = CLIOptions::from_args(); let options = CLIOptions::from_args();
match options { match options {
CLIOptions::Run(options) => run(options), CLIOptions::Run(options) => run(options),
#[cfg(not(target_os = "windows"))]
CLIOptions::SelfUpdate => update::self_update(), CLIOptions::SelfUpdate => update::self_update(),
#[cfg(target_os = "windows")]
CLIOptions::SelfUpdate => {
println!("Self update is not supported on Windows. Use install instructions on the Wasmer homepage: https://wasmer.io");
}
} }
} }