diff --git a/.appveyor.yml b/.appveyor.yml new file mode 100644 index 000000000..446c29b3c --- /dev/null +++ b/.appveyor.yml @@ -0,0 +1,151 @@ +# 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}" + +os: Visual Studio 2017 + +matrix: + allow_failures: + - CHANNEL: nightly +# - ABI: gnu + +environment: + 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 + ARCH: x86_64 + ABI: gnu + 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 + +install: + - echo %PATH% + # force branch checkout (if knowable), then reset to the specific commit ## (can be needed for accurate code coverage info) + # * this allows later apps to see the branch name using standard `git branch` operations, yet always builds the correct specific commit + # * ref: [`@`](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 + - 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: , + # ** egs: , + - 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: + - set BUILD_CMD=cargo +%TOOLCHAIN% build --target=%TARGET% + - echo [ %BUILD_CMD% ] & %BUILD_CMD% + +test_script: + - set TEST_CMD=cargo +%TOOLCHAIN% test --target=%TARGET% --no-fail-fast + - echo [ %TEST_CMD% ] & %TEST_CMD% diff --git a/.circleci/config.yml b/.circleci/config.yml index d0d03a45f..5e7c4ad06 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -67,6 +67,12 @@ jobs: sudo sysctl -w kern.maxfiles=655360 kern.maxfilesperproc=327680 make test make lint + - run: + name: Execute integration tests + command: | + export PATH="`pwd`/cmake-3.4.1-Darwin-x86_64/CMake.app/Contents/bin:$PATH" + export PATH="$HOME/.cargo/bin:$PATH" + ./integration_tests/nginx/test.sh test-and-build: docker: diff --git a/.gitignore b/.gitignore index 6727387a5..dd8330f3e 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ **/*.rs.bk /artifacts .DS_Store +.idea diff --git a/Cargo.lock b/Cargo.lock index e5559398d..6bd124e7d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1125,6 +1125,7 @@ version = "0.1.1" dependencies = [ "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "hashbrown 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.44 (git+https://github.com/rust-lang/libc)", "time 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", "wabt 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/Makefile b/Makefile index 8d2af451b..37f8ee9d8 100644 --- a/Makefile +++ b/Makefile @@ -29,7 +29,7 @@ precommit: lint test test: # We use one thread so the emscripten stdouts doesn't collide - cargo test --all -- --test-threads=1 $(runargs) + cargo test --all --exclude wasmer-emscripten -- --test-threads=1 $(runargs) release: # If you are in OS-X, you will need mingw-w64 for cross compiling to windows diff --git a/integration_tests/nginx/README.md b/integration_tests/nginx/README.md new file mode 100644 index 000000000..9df8af773 --- /dev/null +++ b/integration_tests/nginx/README.md @@ -0,0 +1,12 @@ +# `nginx` integration test + + +This starts wasmer with the nginx wasm file and serves an html +file with some simple text to assert on. The test script does +the assertion. + +Run test with: + +``` +> ./integration_tests/nginx/test.sh +``` diff --git a/integration_tests/nginx/html/index.html b/integration_tests/nginx/html/index.html new file mode 100644 index 000000000..02eaa92ed --- /dev/null +++ b/integration_tests/nginx/html/index.html @@ -0,0 +1 @@ +wasmer diff --git a/integration_tests/nginx/logs/nginx.pid b/integration_tests/nginx/logs/nginx.pid new file mode 100644 index 000000000..d4e41cacb --- /dev/null +++ b/integration_tests/nginx/logs/nginx.pid @@ -0,0 +1 @@ +26310 diff --git a/integration_tests/nginx/nginx.conf b/integration_tests/nginx/nginx.conf new file mode 100644 index 000000000..d44d2569b --- /dev/null +++ b/integration_tests/nginx/nginx.conf @@ -0,0 +1,24 @@ +events { +} + +# We need this for now, as we want to run nginx as a worker +daemon off; +master_process off; + +# We show the errors and info in stderr +error_log /dev/stderr info; + +http { + # We show access in the stdout + access_log /dev/stdout; + server { + listen 8080; + server_name _; + + location / { + # IMPORTANT: Replace the dir with the one you want to serve (that have an index.html file) + root ./html/; + index index.html; + } + } +} diff --git a/integration_tests/nginx/test.sh b/integration_tests/nginx/test.sh new file mode 100755 index 000000000..55b319da5 --- /dev/null +++ b/integration_tests/nginx/test.sh @@ -0,0 +1,24 @@ +#! /bin/bash + +# Build the release and run nginx +make release +nohup ./target/release/wasmer run examples/nginx/nginx.wasm -- -p integration_tests/nginx/ -c nginx.conf & +sleep 3s + +curl localhost:8080 > ./nginx.out + + +if grep "wasmer" ./nginx.out +then + echo "nginx integration test succeeded" + rm ./nohup.out + rm ./nginx.out + rm -rf ./integration_tests/nginx/*_temp + exit 0 +else + echo "nginx integration test failed" + rm ./nohup.out + rm ./nginx.out + rm -rf ./integration_tests/nginx/*_temp + exit -1 +fi diff --git a/lib/clif-backend/src/module.rs b/lib/clif-backend/src/module.rs index f5acc796f..6fbb525da 100644 --- a/lib/clif-backend/src/module.rs +++ b/lib/clif-backend/src/module.rs @@ -33,7 +33,7 @@ impl FuncResolver for PlaceholderFuncResolver { /// This contains all of the items in a `ModuleInner` except the `func_resolver`. pub struct Module { - module: ModuleInner, + pub module: ModuleInner, } impl Module { diff --git a/lib/emscripten/Cargo.toml b/lib/emscripten/Cargo.toml index 77cc97fb1..c2e2dfb13 100644 --- a/lib/emscripten/Cargo.toml +++ b/lib/emscripten/Cargo.toml @@ -6,6 +6,7 @@ edition = "2018" build = "build/mod.rs" [dependencies] +hashbrown = "0.1" wasmer-runtime = { path = "../runtime" } libc = { git = "https://github.com/rust-lang/libc" } byteorder = "1" diff --git a/lib/emscripten/build/mod.rs b/lib/emscripten/build/mod.rs index 06d11ae6b..54b8714a1 100644 --- a/lib/emscripten/build/mod.rs +++ b/lib/emscripten/build/mod.rs @@ -8,4 +8,4 @@ fn main() { if env::var(EMTESTS_ENV_VAR).unwrap_or("0".to_string()) == "1" { emtests::build(); } -} \ No newline at end of file +} diff --git a/lib/emscripten/emtests/README.md b/lib/emscripten/emtests/README.md index daffe36d6..01ea3c0d0 100644 --- a/lib/emscripten/emtests/README.md +++ b/lib/emscripten/emtests/README.md @@ -18,7 +18,6 @@ This process will do something similar to: ``` # Generate the .wasm file emcc localtime.c -o localtime.js -# Delte the js file, as we don't need it +# Delete the js file, as we don't need it rm localtime.js ``` - diff --git a/lib/emscripten/src/env.rs b/lib/emscripten/src/env.rs index bd4c4e79f..ac03c420b 100644 --- a/lib/emscripten/src/env.rs +++ b/lib/emscripten/src/env.rs @@ -8,8 +8,8 @@ use std::mem; use std::os::raw::c_char; use super::utils::{allocate_on_stack, copy_cstr_into_wasm, copy_terminated_array_of_cstrs}; -use super::EmscriptenData; use wasmer_runtime::{types::Value, Instance}; +//use super::EmscriptenData; //impl Instance { // pub fn memory_offset_addr(&self, index: usize, offset: usize) -> *const usize { @@ -73,6 +73,7 @@ pub extern "C" fn _unsetenv(name: c_int, instance: &mut Instance) { unsafe { unsetenv(name_addr) }; } +#[allow(clippy::cast_ptr_alignment)] pub extern "C" fn _getpwnam(name_ptr: c_int, instance: &mut Instance) -> c_int { debug!("emscripten::_getpwnam {}", name_ptr); @@ -110,6 +111,7 @@ pub extern "C" fn _getpwnam(name_ptr: c_int, instance: &mut Instance) -> c_int { } } +#[allow(clippy::cast_ptr_alignment)] pub extern "C" fn _getgrnam(name_ptr: c_int, instance: &mut Instance) -> c_int { debug!("emscripten::_getgrnam {}", name_ptr); @@ -189,6 +191,7 @@ pub extern "C" fn _getpagesize() -> u32 { 16384 } +#[allow(clippy::cast_ptr_alignment)] pub extern "C" fn ___build_environment(environ: c_int, instance: &mut Instance) { debug!("emscripten::___build_environment {}", environ); const MAX_ENV_VALUES: u32 = 64; diff --git a/lib/emscripten/src/exception.rs b/lib/emscripten/src/exception.rs index 4244c3005..a7b0e9e63 100644 --- a/lib/emscripten/src/exception.rs +++ b/lib/emscripten/src/exception.rs @@ -1,5 +1,5 @@ -use super::process::_abort; use super::env; +use super::process::_abort; use wasmer_runtime::Instance; /// emscripten: ___cxa_allocate_exception diff --git a/src/common/file_descriptor.rs b/lib/emscripten/src/file_descriptor.rs similarity index 100% rename from src/common/file_descriptor.rs rename to lib/emscripten/src/file_descriptor.rs diff --git a/lib/emscripten/src/jmp.rs b/lib/emscripten/src/jmp.rs index c5e77132c..d32e6ce74 100644 --- a/lib/emscripten/src/jmp.rs +++ b/lib/emscripten/src/jmp.rs @@ -1,40 +1,40 @@ -use wasmer_runtime::Instance; use libc::{c_int, c_void}; use std::cell::UnsafeCell; +use wasmer_runtime::Instance; /// setjmp pub extern "C" fn __setjmp(env_addr: u32, instance: &mut Instance) -> c_int { debug!("emscripten::__setjmp (setjmp)"); unimplemented!() -// unsafe { -// // 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 -// // so the address of the jump it's outside the wasm memory itself. -// let jump_index = instance.memory_offset_addr(0, env_addr as usize) as *mut i8; -// // We create the jump buffer outside of the wasm memory -// let jump_buf: UnsafeCell<[c_int; 27]> = UnsafeCell::new([0; 27]); -// let mut jumps = &mut instance.emscripten_data().as_mut().unwrap().jumps; -// let result = setjmp(jump_buf.get() as _); -// // We set the jump index to be the last value of jumps -// *jump_index = jumps.len() as _; -// // We hold the reference of the jump buffer -// jumps.push(jump_buf); -// result -// } + // unsafe { + // // 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 + // // so the address of the jump it's outside the wasm memory itself. + // let jump_index = instance.memory_offset_addr(0, env_addr as usize) as *mut i8; + // // We create the jump buffer outside of the wasm memory + // let jump_buf: UnsafeCell<[c_int; 27]> = UnsafeCell::new([0; 27]); + // let mut jumps = &mut instance.emscripten_data().as_mut().unwrap().jumps; + // let result = setjmp(jump_buf.get() as _); + // // We set the jump index to be the last value of jumps + // *jump_index = jumps.len() as _; + // // We hold the reference of the jump buffer + // jumps.push(jump_buf); + // result + // } } /// longjmp pub extern "C" fn __longjmp(env_addr: u32, val: c_int, instance: &mut Instance) -> ! { debug!("emscripten::__longjmp (longjmp) {}", val); unimplemented!() -// unsafe { -// // We retrieve the jump index from the env address -// let jump_index = instance.memory_offset_addr(0, env_addr as usize) as *mut i8; -// let mut jumps = &mut instance.emscripten_data().as_mut().unwrap().jumps; -// // We get the real jump buffer from the jumps vector, using the retrieved index -// let mut jump_buf = &jumps[*jump_index as usize]; -// longjmp(jump_buf.get() as _, val) -// }; + // unsafe { + // // We retrieve the jump index from the env address + // let jump_index = instance.memory_offset_addr(0, env_addr as usize) as *mut i8; + // let mut jumps = &mut instance.emscripten_data().as_mut().unwrap().jumps; + // // We get the real jump buffer from the jumps vector, using the retrieved index + // let mut jump_buf = &jumps[*jump_index as usize]; + // longjmp(jump_buf.get() as _, val) + // }; } extern "C" { diff --git a/lib/emscripten/src/lib.rs b/lib/emscripten/src/lib.rs index 6d8a7fe67..c94425af5 100644 --- a/lib/emscripten/src/lib.rs +++ b/lib/emscripten/src/lib.rs @@ -1,14 +1,29 @@ #[macro_use] extern crate wasmer_runtime; -use wasmer_runtime::LinearMemory; -use wasmer_runtime::types::{FuncSig, Type, Value}; -use wasmer_runtime::{Import, Imports, Instance, FuncRef}; -/// NOTE: TODO: These emscripten api implementation only support wasm32 for now because they assume offsets are u32 +#[macro_use] +use wasmer_runtime::macros; + use byteorder::{ByteOrder, LittleEndian}; +use hashbrown::{hash_map::Entry, HashMap}; use libc::c_int; use std::cell::UnsafeCell; use std::mem; +use wasmer_runtime::{ + export::{Context, Export, FuncPointer, GlobalPointer}, + import::{Imports, NamespaceMap}, + memory::LinearMemory, + types::{ + FuncSig, GlobalDesc, + Type::{self, *}, + Value, + }, + vm::{self, Func, LocalGlobal}, +}; + +//#[cfg(test)] +mod file_descriptor; +pub mod stdio; // EMSCRIPTEN APIS mod env; @@ -54,14 +69,14 @@ fn dynamictop_ptr(static_bump: u32) -> u32 { static_bump + DYNAMICTOP_PTR_DIFF } -pub struct EmscriptenData { - pub malloc: extern "C" fn(i32, &Instance) -> u32, - pub free: extern "C" fn(i32, &mut Instance), - pub memalign: extern "C" fn(u32, u32, &mut Instance) -> u32, - pub memset: extern "C" fn(u32, i32, u32, &mut Instance) -> u32, - pub stack_alloc: extern "C" fn(u32, &Instance) -> u32, - pub jumps: Vec>, -} +//pub struct EmscriptenData { +// pub malloc: extern "C" fn(i32, &Instance) -> u32, +// pub free: extern "C" fn(i32, &mut Instance), +// pub memalign: extern "C" fn(u32, u32, &mut Instance) -> u32, +// pub memset: extern "C" fn(u32, i32, u32, &mut Instance) -> u32, +// pub stack_alloc: extern "C" fn(u32, &Instance) -> u32, +// pub jumps: Vec>, +//} pub fn emscripten_set_up_memory(memory: &mut LinearMemory) { let dynamictop_ptr = dynamictop_ptr(STATIC_BUMP) as usize; @@ -83,1217 +98,1375 @@ pub fn emscripten_set_up_memory(memory: &mut LinearMemory) { } macro_rules! mock_external { - ($import:ident, $name:ident) => {{ - use wasmer_runtime::types::{FuncSig, Type}; - use wasmer_runtime::Import; + ($namespace:ident, $name:ident) => {{ extern "C" fn _mocked_fn() -> i32 { debug!("emscripten::{} ", stringify!($name)); -1 } - $import.add( - "env".to_string(), - stringify!($name).to_string(), - Import::Func( - unsafe { FuncRef::new(_mocked_fn as _) }, - FuncSig { + + $namespace.insert( + stringify!($name), + Export::Function { + func: unsafe { FuncPointer::new(_mocked_fn as _) }, + ctx: Context::Internal, + signature: FuncSig { params: vec![], - returns: vec![Type::I32], + returns: vec![I32], }, - ), + }, ); }}; } -pub fn generate_emscripten_env() -> Imports { - let mut import_object = Imports::new(); - - // import_object.add( - // "spectest".to_string(), - // "print_i32".to_string(), - // Import::Func( - // print_i32 as _, - // FuncSig { - // params: vec![Type::I32], - // returns: vec![], - // }, - // ), - // ); - // - // import_object.add( - // "spectest".to_string(), - // "global_i32".to_string(), - // Import::Global(Value::I64(GLOBAL_I32 as _)), - // ); - - // Globals - import_object.add( - "env".to_string(), - "STACKTOP".to_string(), - Import::Global(Value::I64(stacktop(STATIC_BUMP) as _)), - ); - import_object.add( - "env".to_string(), - "STACK_MAX".to_string(), - Import::Global(Value::I64(stack_max(STATIC_BUMP) as _)), - ); - import_object.add( - "env".to_string(), - "DYNAMICTOP_PTR".to_string(), - Import::Global(Value::I64(dynamictop_ptr(STATIC_BUMP) as _)), - ); - import_object.add( - "global".to_string(), - "Infinity".to_string(), - Import::Global(Value::I64(std::f64::INFINITY.to_bits() as _)), - ); - import_object.add( - "global".to_string(), - "NaN".to_string(), - Import::Global(Value::I64(std::f64::NAN.to_bits() as _)), - ); - import_object.add( - "env".to_string(), - "tableBase".to_string(), - Import::Global(Value::I64(0)), - ); - // // Print functions - - import_object.add( - "env".to_string(), - "printf".to_string(), - Import::Func( - unsafe { FuncRef::new(io::printf as _) }, - FuncSig { - params: vec![Type::I32, Type::I32], - returns: vec![Type::I32], - }, - ), - ); - import_object.add( - "env".to_string(), - "putchar".to_string(), - Import::Func( - unsafe { FuncRef::new(io::putchar as _) }, - FuncSig { - params: vec![Type::I32], - returns: vec![], - }, - ), - ); - // // Lock - import_object.add( - "env".to_string(), - "___lock".to_string(), - Import::Func( - unsafe { FuncRef::new(lock::___lock as _) }, - FuncSig { - params: vec![Type::I32, Type::I32], - returns: vec![], - }, - ), - ); - import_object.add( - "env".to_string(), - "___unlock".to_string(), - Import::Func( - unsafe { FuncRef::new(lock::___unlock as _) }, - FuncSig { - params: vec![Type::I32, Type::I32], - returns: vec![], - }, - ), - ); - import_object.add( - "env".to_string(), - "___wait".to_string(), - Import::Func( - unsafe { FuncRef::new(lock::___wait as _) }, - FuncSig { - params: vec![Type::I32, Type::I32], - returns: vec![], - }, - ), - ); - // // Env - import_object.add( - "env".to_string(), - "_getenv".to_string(), - Import::Func( - unsafe { FuncRef::new(env::_getenv as _) }, - FuncSig { - params: vec![Type::I32], - returns: vec![Type::I32], - }, - ), - ); - import_object.add( - "env".to_string(), - "_setenv".to_string(), - Import::Func( - unsafe { FuncRef::new(env::_setenv as _) }, - FuncSig { - params: vec![Type::I32, Type::I32, Type::I32], - returns: vec![], - }, - ), - ); - import_object.add( - "env".to_string(), - "_putenv".to_string(), - Import::Func( - unsafe { FuncRef::new(env::_putenv as _) }, - FuncSig { - params: vec![Type::I32], - returns: vec![], - }, - ), - ); - import_object.add( - "env".to_string(), - "_unsetenv".to_string(), - Import::Func( - unsafe { FuncRef::new(env::_unsetenv as _) }, - FuncSig { - params: vec![Type::I32], - returns: vec![], - }, - ), - ); - import_object.add( - "env".to_string(), - "_getpwnam".to_string(), - Import::Func( - unsafe { FuncRef::new(env::_getpwnam as _) }, - FuncSig { - params: vec![Type::I32], - returns: vec![Type::I32], - }, - ), - ); - import_object.add( - "env".to_string(), - "_getgrnam".to_string(), - Import::Func( - unsafe { FuncRef::new(env::_getgrnam as _) }, - FuncSig { - params: vec![Type::I32], - returns: vec![Type::I32], - }, - ), - ); - import_object.add( - "env".to_string(), - "___buildEnvironment".to_string(), - Import::Func( - unsafe { FuncRef::new(env::___build_environment as _) }, - FuncSig { - params: vec![Type::I32], - returns: vec![], - }, - ), - ); - // // Errno - import_object.add( - "env".to_string(), - "___setErrNo".to_string(), - Import::Func( - unsafe { FuncRef::new(errno::___seterrno as _) }, - FuncSig { - params: vec![Type::I32], - returns: vec![Type::I32], - }, - ), - ); - // // Syscalls - import_object.add( - "env".to_string(), - "___syscall1".to_string(), - Import::Func( - unsafe { FuncRef::new(syscalls::___syscall1 as _) }, - FuncSig { - params: vec![Type::I32, Type::I32], - returns: vec![], - }, - ), - ); - import_object.add( - "env".to_string(), - "___syscall3".to_string(), - Import::Func( - unsafe { FuncRef::new(syscalls::___syscall3 as _) }, - FuncSig { - params: vec![Type::I32, Type::I32], - returns: vec![Type::I32], - }, - ), - ); - import_object.add( - "env".to_string(), - "___syscall4".to_string(), - Import::Func( - unsafe { FuncRef::new(syscalls::___syscall4 as _) }, - FuncSig { - params: vec![Type::I32, Type::I32], - returns: vec![Type::I32], - }, - ), - ); - import_object.add( - "env".to_string(), - "___syscall5".to_string(), - Import::Func( - unsafe { FuncRef::new(syscalls::___syscall5 as _) }, - FuncSig { - params: vec![Type::I32, Type::I32], - returns: vec![Type::I32], - }, - ), - ); - import_object.add( - "env".to_string(), - "___syscall6".to_string(), - Import::Func( - unsafe { FuncRef::new(syscalls::___syscall6 as _) }, - FuncSig { - params: vec![Type::I32, Type::I32], - returns: vec![Type::I32], - }, - ), - ); - import_object.add( - "env".to_string(), - "___syscall12".to_string(), - Import::Func( - unsafe { FuncRef::new(syscalls::___syscall12 as _) }, - FuncSig { - params: vec![Type::I32, Type::I32], - returns: vec![Type::I32], - }, - ), - ); - import_object.add( - "env".to_string(), - "___syscall20".to_string(), - Import::Func( - unsafe { FuncRef::new(syscalls::___syscall20 as _) }, - FuncSig { - params: vec![], - returns: vec![Type::I32], - }, - ), - ); - import_object.add( - "env".to_string(), - "___syscall39".to_string(), - Import::Func( - unsafe { FuncRef::new(syscalls::___syscall39 as _) }, - FuncSig { - params: vec![Type::I32, Type::I32], - returns: vec![Type::I32], - }, - ), - ); - import_object.add( - "env".to_string(), - "___syscall40".to_string(), - Import::Func( - unsafe { FuncRef::new(syscalls::___syscall40 as _) }, - FuncSig { - params: vec![Type::I32, Type::I32], - returns: vec![Type::I32], - }, - ), - ); - import_object.add( - "env".to_string(), - "___syscall54".to_string(), - Import::Func( - unsafe { FuncRef::new(syscalls::___syscall54 as _) }, - FuncSig { - params: vec![Type::I32, Type::I32], - returns: vec![Type::I32], - }, - ), - ); - import_object.add( - "env".to_string(), - "___syscall57".to_string(), - Import::Func( - unsafe { FuncRef::new(syscalls::___syscall57 as _) }, - FuncSig { - params: vec![Type::I32, Type::I32], - returns: vec![Type::I32], - }, - ), - ); - import_object.add( - "env".to_string(), - "___syscall63".to_string(), - Import::Func( - unsafe { FuncRef::new(syscalls::___syscall63 as _) }, - FuncSig { - params: vec![Type::I32, Type::I32], - returns: vec![Type::I32], - }, - ), - ); - import_object.add( - "env".to_string(), - "___syscall64".to_string(), - Import::Func( - unsafe { FuncRef::new(syscalls::___syscall64 as _) }, - FuncSig { - params: vec![], - returns: vec![Type::I32], - }, - ), - ); - import_object.add( - "env".to_string(), - "___syscall102".to_string(), - Import::Func( - unsafe { FuncRef::new(syscalls::___syscall102 as _) }, - FuncSig { - params: vec![Type::I32, Type::I32], - returns: vec![Type::I32], - }, - ), - ); - import_object.add( - "env".to_string(), - "___syscall114".to_string(), - Import::Func( - unsafe { FuncRef::new(syscalls::___syscall114 as _) }, - FuncSig { - params: vec![Type::I32, Type::I32], - returns: vec![Type::I32], - }, - ), - ); - import_object.add( - "env".to_string(), - "___syscall122".to_string(), - Import::Func( - unsafe { FuncRef::new(syscalls::___syscall122 as _) }, - FuncSig { - params: vec![Type::I32, Type::I32], - returns: vec![Type::I32], - }, - ), - ); - import_object.add( - "env".to_string(), - "___syscall140".to_string(), - Import::Func( - unsafe { FuncRef::new(syscalls::___syscall140 as _) }, - FuncSig { - params: vec![Type::I32, Type::I32], - returns: vec![Type::I32], - }, - ), - ); - import_object.add( - "env".to_string(), - "___syscall142".to_string(), - Import::Func( - unsafe { FuncRef::new(syscalls::___syscall142 as _) }, - FuncSig { - params: vec![Type::I32, Type::I32], - returns: vec![Type::I32], - }, - ), - ); - import_object.add( - "env".to_string(), - "___syscall145".to_string(), - Import::Func( - unsafe { FuncRef::new(syscalls::___syscall145 as _) }, - FuncSig { - params: vec![Type::I32, Type::I32], - returns: vec![Type::I32], - }, - ), - ); - import_object.add( - "env".to_string(), - "___syscall146".to_string(), - Import::Func( - unsafe { FuncRef::new(syscalls::___syscall146 as _) }, - FuncSig { - params: vec![Type::I32, Type::I32], - returns: vec![Type::I32], - }, - ), - ); - import_object.add( - "env".to_string(), - "___syscall180".to_string(), - Import::Func( - unsafe { FuncRef::new(syscalls::___syscall180 as _) }, - FuncSig { - params: vec![Type::I32, Type::I32], - returns: vec![Type::I32], - }, - ), - ); - import_object.add( - "env".to_string(), - "___syscall181".to_string(), - Import::Func( - unsafe { FuncRef::new(syscalls::___syscall181 as _) }, - FuncSig { - params: vec![Type::I32, Type::I32], - returns: vec![Type::I32], - }, - ), - ); - import_object.add( - "env".to_string(), - "___syscall192".to_string(), - Import::Func( - unsafe { FuncRef::new(syscalls::___syscall192 as _) }, - FuncSig { - params: vec![Type::I32, Type::I32], - returns: vec![Type::I32], - }, - ), - ); - import_object.add( - "env".to_string(), - "___syscall195".to_string(), - Import::Func( - unsafe { FuncRef::new(syscalls::___syscall195 as _) }, - FuncSig { - params: vec![Type::I32, Type::I32], - returns: vec![Type::I32], - }, - ), - ); - import_object.add( - "env".to_string(), - "___syscall197".to_string(), - Import::Func( - unsafe { FuncRef::new(syscalls::___syscall197 as _) }, - FuncSig { - params: vec![Type::I32, Type::I32], - returns: vec![Type::I32], - }, - ), - ); - import_object.add( - "env".to_string(), - "___syscall201".to_string(), - Import::Func( - unsafe { FuncRef::new(syscalls::___syscall201 as _) }, - FuncSig { - params: vec![], - returns: vec![Type::I32], - }, - ), - ); - import_object.add( - "env".to_string(), - "___syscall202".to_string(), - Import::Func( - unsafe { FuncRef::new(syscalls::___syscall202 as _) }, - FuncSig { - params: vec![], - returns: vec![Type::I32], - }, - ), - ); - import_object.add( - "env".to_string(), - "___syscall212".to_string(), - Import::Func( - unsafe { FuncRef::new(syscalls::___syscall212 as _) }, - FuncSig { - params: vec![Type::I32, Type::I32], - returns: vec![Type::I32], - }, - ), - ); - import_object.add( - "env".to_string(), - "___syscall221".to_string(), - Import::Func( - unsafe { FuncRef::new(syscalls::___syscall221 as _) }, - FuncSig { - params: vec![Type::I32, Type::I32], - returns: vec![Type::I32], - }, - ), - ); - import_object.add( - "env".to_string(), - "___syscall330".to_string(), - Import::Func( - unsafe { FuncRef::new(syscalls::___syscall330 as _) }, - FuncSig { - params: vec![Type::I32, Type::I32], - returns: vec![Type::I32], - }, - ), - ); - import_object.add( - "env".to_string(), - "___syscall340".to_string(), - Import::Func( - unsafe { FuncRef::new(syscalls::___syscall340 as _) }, - FuncSig { - params: vec![Type::I32, Type::I32], - returns: vec![Type::I32], - }, - ), - ); - // // Process - import_object.add( - "env".to_string(), - "abort".to_string(), - Import::Func( - unsafe { FuncRef::new(process::em_abort as _) }, - FuncSig { - params: vec![Type::I32], - returns: vec![], - }, - ), - ); - import_object.add( - "env".to_string(), - "_abort".to_string(), - Import::Func( - unsafe { FuncRef::new(process::_abort as _) }, - FuncSig { - params: vec![], - returns: vec![], - }, - ), - ); - import_object.add( - "env".to_string(), - "abortStackOverflow".to_string(), - Import::Func( - unsafe { FuncRef::new(process::abort_stack_overflow as _) }, - FuncSig { - params: vec![], - returns: vec![], - }, - ), - ); - import_object.add( - "env".to_string(), - "_llvm_trap".to_string(), - Import::Func( - unsafe { FuncRef::new(process::_llvm_trap as _) }, - FuncSig { - params: vec![], - returns: vec![], - }, - ), - ); - import_object.add( - "env".to_string(), - "_fork".to_string(), - Import::Func( - unsafe { FuncRef::new(process::_fork as _) }, - FuncSig { - params: vec![], - returns: vec![Type::I32], - }, - ), - ); - import_object.add( - "env".to_string(), - "_exit".to_string(), - Import::Func( - unsafe { FuncRef::new(process::_exit as _) }, - FuncSig { - params: vec![Type::I32], - returns: vec![], - }, - ), - ); - import_object.add( - "env".to_string(), - "_system".to_string(), - Import::Func( - unsafe { FuncRef::new(process::_system as _) }, - FuncSig { - params: vec![], - returns: vec![Type::I32], - }, - ), - ); - import_object.add( - "env".to_string(), - "_popen".to_string(), - Import::Func( - unsafe { FuncRef::new(process::_popen as _) }, - FuncSig { - params: vec![], - returns: vec![Type::I32], - }, - ), - ); - // // Signal - import_object.add( - "env".to_string(), - "_sigemptyset".to_string(), - Import::Func( - unsafe { FuncRef::new(signal::_sigemptyset as _) }, - FuncSig { - params: vec![Type::I32], - returns: vec![Type::I32], - }, - ), - ); - import_object.add( - "env".to_string(), - "_sigaddset".to_string(), - Import::Func( - unsafe { FuncRef::new(signal::_sigaddset as _) }, - FuncSig { - params: vec![Type::I32, Type::I32], - returns: vec![Type::I32], - }, - ), - ); - import_object.add( - "env".to_string(), - "_sigprocmask".to_string(), - Import::Func( - unsafe { FuncRef::new(signal::_sigprocmask as _) }, - FuncSig { - params: vec![], - returns: vec![Type::I32], - }, - ), - ); - import_object.add( - "env".to_string(), - "_sigaction".to_string(), - Import::Func( - unsafe { FuncRef::new(signal::_sigaction as _) }, - FuncSig { - params: vec![Type::I32, Type::I32, Type::I32], - returns: vec![Type::I32], - }, - ), - ); - import_object.add( - "env".to_string(), - "_signal".to_string(), - Import::Func( - unsafe { FuncRef::new(signal::_signal as _) }, - FuncSig { - params: vec![Type::I32], - returns: vec![Type::I32], - }, - ), - ); - // // Memory - import_object.add( - "env".to_string(), - "abortOnCannotGrowMemory".to_string(), - Import::Func( - unsafe { FuncRef::new(memory::abort_on_cannot_grow_memory as _) }, - FuncSig { - params: vec![], - returns: vec![], - }, - ), - ); - import_object.add( - "env".to_string(), - "_emscripten_memcpy_big".to_string(), - Import::Func( - unsafe { FuncRef::new(memory::_emscripten_memcpy_big as _) }, - FuncSig { - params: vec![Type::I32, Type::I32, Type::I32], - returns: vec![Type::I32], - }, - ), - ); - import_object.add( - "env".to_string(), - "enlargeMemory".to_string(), - Import::Func( - unsafe { FuncRef::new(memory::enlarge_memory as _) }, - FuncSig { - params: vec![], - returns: vec![], - }, - ), - ); - import_object.add( - "env".to_string(), - "getTotalMemory".to_string(), - Import::Func( - unsafe { FuncRef::new(memory::get_total_memory as _) }, - FuncSig { - params: vec![], - returns: vec![Type::I32], - }, - ), - ); - import_object.add( - "env".to_string(), - "___map_file".to_string(), - Import::Func( - unsafe { FuncRef::new(memory::___map_file as _) }, - FuncSig { - params: vec![], - returns: vec![Type::I32], - }, - ), - ); - // // Exception - import_object.add( - "env".to_string(), - "___cxa_allocate_exception".to_string(), - Import::Func( - unsafe { FuncRef::new(exception::___cxa_allocate_exception as _) }, - FuncSig { - params: vec![Type::I32], - returns: vec![Type::I32], - }, - ), - ); - import_object.add( - "env".to_string(), - "___cxa_allocate_exception".to_string(), - Import::Func( - unsafe { FuncRef::new(exception::___cxa_throw as _) }, - FuncSig { - params: vec![Type::I32, Type::I32, Type::I32], - returns: vec![], - }, - ), - ); - import_object.add( - "env".to_string(), - "___cxa_throw".to_string(), - Import::Func( - unsafe { FuncRef::new(exception::___cxa_throw as _) }, - FuncSig { - params: vec![Type::I32, Type::I32, Type::I32], - returns: vec![], - }, - ), - ); - // // NullFuncs - import_object.add( - "env".to_string(), - "nullFunc_ii".to_string(), - Import::Func( - unsafe { FuncRef::new(nullfunc::nullfunc_ii as _) }, - FuncSig { - params: vec![Type::I32], - returns: vec![], - }, - ), - ); - import_object.add( - "env".to_string(), - "nullFunc_iii".to_string(), - Import::Func( - unsafe { FuncRef::new(nullfunc::nullfunc_iii as _) }, - FuncSig { - params: vec![Type::I32], - returns: vec![], - }, - ), - ); - import_object.add( - "env".to_string(), - "nullFunc_iiii".to_string(), - Import::Func( - unsafe { FuncRef::new(nullfunc::nullfunc_iiii as _) }, - FuncSig { - params: vec![Type::I32], - returns: vec![], - }, - ), - ); - import_object.add( - "env".to_string(), - "nullFunc_iiiii".to_string(), - Import::Func( - unsafe { FuncRef::new(nullfunc::nullfunc_iiiii as _) }, - FuncSig { - params: vec![Type::I32], - returns: vec![], - }, - ), - ); - import_object.add( - "env".to_string(), - "nullFunc_iiiiii".to_string(), - Import::Func( - unsafe { FuncRef::new(nullfunc::nullfunc_iiiiii as _) }, - FuncSig { - params: vec![Type::I32], - returns: vec![], - }, - ), - ); - import_object.add( - "env".to_string(), - "nullFunc_v".to_string(), - Import::Func( - unsafe { FuncRef::new(nullfunc::nullfunc_v as _) }, - FuncSig { - params: vec![Type::I32], - returns: vec![], - }, - ), - ); - import_object.add( - "env".to_string(), - "nullFunc_vi".to_string(), - Import::Func( - unsafe { FuncRef::new(nullfunc::nullfunc_vi as _) }, - FuncSig { - params: vec![Type::I32], - returns: vec![], - }, - ), - ); - import_object.add( - "env".to_string(), - "nullFunc_vii".to_string(), - Import::Func( - unsafe { FuncRef::new(nullfunc::nullfunc_vii as _) }, - FuncSig { - params: vec![Type::I32], - returns: vec![], - }, - ), - ); - import_object.add( - "env".to_string(), - "nullFunc_viii".to_string(), - Import::Func( - unsafe { FuncRef::new(nullfunc::nullfunc_viii as _) }, - FuncSig { - params: vec![Type::I32], - returns: vec![], - }, - ), - ); - import_object.add( - "env".to_string(), - "nullFunc_viiii".to_string(), - Import::Func( - unsafe { FuncRef::new(nullfunc::nullfunc_viiii as _) }, - FuncSig { - params: vec![Type::I32], - returns: vec![], - }, - ), - ); - import_object.add( - "env".to_string(), - "nullFunc_viiiii".to_string(), - Import::Func( - unsafe { FuncRef::new(nullfunc::nullfunc_viiiii as _) }, - FuncSig { - params: vec![Type::I32], - returns: vec![], - }, - ), - ); - import_object.add( - "env".to_string(), - "nullFunc_viiiiii".to_string(), - Import::Func( - unsafe { FuncRef::new(nullfunc::nullfunc_viiiiii as _) }, - FuncSig { - params: vec![Type::I32], - returns: vec![], - }, - ), - ); - // // Time - import_object.add( - "env".to_string(), - "_gettimeofday".to_string(), - Import::Func( - unsafe { FuncRef::new(time::_gettimeofday as _) }, - FuncSig { - params: vec![Type::I32, Type::I32], - returns: vec![Type::I32], - }, - ), - ); - import_object.add( - "env".to_string(), - "_clock_gettime".to_string(), - Import::Func( - unsafe { FuncRef::new(time::_clock_gettime as _) }, - FuncSig { - params: vec![Type::I32, Type::I32], - returns: vec![Type::I32], - }, - ), - ); - import_object.add( - "env".to_string(), - "___clock_gettime".to_string(), - Import::Func( - unsafe { FuncRef::new(time::___clock_gettime as _) }, - FuncSig { - params: vec![Type::I32, Type::I32], - returns: vec![Type::I32], - }, - ), - ); - import_object.add( - "env".to_string(), - "_clock".to_string(), - Import::Func( - unsafe { FuncRef::new(time::_clock as _) }, - FuncSig { - params: vec![], - returns: vec![Type::I32], - }, - ), - ); - import_object.add( - "env".to_string(), - "_difftime".to_string(), - Import::Func( - unsafe { FuncRef::new(time::_difftime as _) }, - FuncSig { - params: vec![Type::I32, Type::I32], - returns: vec![Type::I32], - }, - ), - ); - import_object.add( - "env".to_string(), - "_asctime".to_string(), - Import::Func( - unsafe { FuncRef::new(time::_asctime as _) }, - FuncSig { - params: vec![Type::I32], - returns: vec![Type::I32], - }, - ), - ); - import_object.add( - "env".to_string(), - "_asctime_r".to_string(), - Import::Func( - unsafe { FuncRef::new(time::_asctime_r as _) }, - FuncSig { - params: vec![Type::I32, Type::I32], - returns: vec![Type::I32], - }, - ), - ); - import_object.add( - "env".to_string(), - "_localtime".to_string(), - Import::Func( - unsafe { FuncRef::new(time::_localtime as _) }, - FuncSig { - params: vec![Type::I32], - returns: vec![Type::I32], - }, - ), - ); - import_object.add( - "env".to_string(), - "_time".to_string(), - Import::Func( - unsafe { FuncRef::new(time::_time as _) }, - FuncSig { - params: vec![Type::I32], - returns: vec![Type::I32], - }, - ), - ); - import_object.add( - "env".to_string(), - "_strftime".to_string(), - Import::Func( - unsafe { FuncRef::new(time::_strftime as _) }, - FuncSig { - params: vec![Type::I32, Type::I32, Type::I32, Type::I32], - returns: vec![Type::I32], - }, - ), - ); - import_object.add( - "env".to_string(), - "_localtime_r".to_string(), - Import::Func( - unsafe { FuncRef::new(time::_localtime_r as _) }, - FuncSig { - params: vec![Type::I32, Type::I32], - returns: vec![Type::I32], - }, - ), - ); - import_object.add( - "env".to_string(), - "_getpagesize".to_string(), - Import::Func( - unsafe { FuncRef::new(env::_getpagesize as _) }, - FuncSig { - params: vec![], - returns: vec![Type::I32], - }, - ), - ); - import_object.add( - "env".to_string(), - "_sysconf".to_string(), - Import::Func( - unsafe { FuncRef::new(env::_sysconf as _) }, - FuncSig { - params: vec![Type::I32], - returns: vec![Type::I32], - }, - ), - ); - // // Math - import_object.add( - "env".to_string(), - "_llvm_log10_f64".to_string(), - Import::Func( - unsafe { FuncRef::new(math::_llvm_log10_f64 as _) }, - FuncSig { - params: vec![Type::F64], - returns: vec![Type::F64], - }, - ), - ); - import_object.add( - "env".to_string(), - "_llvm_log2_f64".to_string(), - Import::Func( - unsafe { FuncRef::new( math::_llvm_log2_f64 as _) }, - FuncSig { - params: vec![Type::F64], - returns: vec![Type::F64], - }, - ), - ); - import_object.add( - "asm2wasm".to_string(), - "f64-rem".to_string(), - Import::Func( - unsafe { FuncRef::new(math::f64_rem as _) }, - FuncSig { - params: vec![Type::F64, Type::F64], - returns: vec![Type::F64], - }, - ), - ); - // - import_object.add( - "env".to_string(), - "__setjmp".to_string(), - Import::Func( - unsafe { FuncRef::new(jmp::__setjmp as _) }, - FuncSig { - params: vec![Type::I32], - returns: vec![Type::I32], - }, - ), - ); - import_object.add( - "env".to_string(), - "__longjmp".to_string(), - Import::Func( - unsafe { FuncRef::new(jmp::__longjmp as _) }, - FuncSig { - params: vec![Type::I32, Type::I32], - returns: vec![], - }, - ), - ); - - mock_external!(import_object, _waitpid); - mock_external!(import_object, _utimes); - mock_external!(import_object, _usleep); - // mock_external!(import_object, _time); - // mock_external!(import_object, _sysconf); - // mock_external!(import_object, _strftime); - mock_external!(import_object, _sigsuspend); - // mock_external!(import_object, _sigprocmask); - // mock_external!(import_object, _sigemptyset); - // mock_external!(import_object, _sigaddset); - // mock_external!(import_object, _sigaction); - mock_external!(import_object, _setitimer); - mock_external!(import_object, _setgroups); - mock_external!(import_object, _setgrent); - mock_external!(import_object, _sem_wait); - mock_external!(import_object, _sem_post); - mock_external!(import_object, _sem_init); - mock_external!(import_object, _sched_yield); - mock_external!(import_object, _raise); - mock_external!(import_object, _mktime); - // mock_external!(import_object, _localtime_r); - // mock_external!(import_object, _localtime); - mock_external!(import_object, _llvm_stacksave); - mock_external!(import_object, _llvm_stackrestore); - mock_external!(import_object, _kill); - mock_external!(import_object, _gmtime_r); - // mock_external!(import_object, _gettimeofday); - // mock_external!(import_object, _getpagesize); - mock_external!(import_object, _getgrent); - mock_external!(import_object, _getaddrinfo); - // mock_external!(import_object, _fork); - // mock_external!(import_object, _exit); - mock_external!(import_object, _execve); - mock_external!(import_object, _endgrent); - // mock_external!(import_object, _clock_gettime); - mock_external!(import_object, ___syscall97); - mock_external!(import_object, ___syscall91); - mock_external!(import_object, ___syscall85); - mock_external!(import_object, ___syscall75); - mock_external!(import_object, ___syscall66); - // mock_external!(import_object, ___syscall64); - // mock_external!(import_object, ___syscall63); - // mock_external!(import_object, ___syscall60); - // mock_external!(import_object, ___syscall54); - // mock_external!(import_object, ___syscall39); - mock_external!(import_object, ___syscall38); - // mock_external!(import_object, ___syscall340); - mock_external!(import_object, ___syscall334); - mock_external!(import_object, ___syscall300); - mock_external!(import_object, ___syscall295); - mock_external!(import_object, ___syscall272); - mock_external!(import_object, ___syscall268); - // mock_external!(import_object, ___syscall221); - mock_external!(import_object, ___syscall220); - // mock_external!(import_object, ___syscall212); - // mock_external!(import_object, ___syscall201); - mock_external!(import_object, ___syscall199); - // mock_external!(import_object, ___syscall197); - mock_external!(import_object, ___syscall196); - // mock_external!(import_object, ___syscall195); - mock_external!(import_object, ___syscall194); - mock_external!(import_object, ___syscall191); - // mock_external!(import_object, ___syscall181); - // mock_external!(import_object, ___syscall180); - mock_external!(import_object, ___syscall168); - // mock_external!(import_object, ___syscall146); - // mock_external!(import_object, ___syscall145); - // mock_external!(import_object, ___syscall142); - mock_external!(import_object, ___syscall140); - // mock_external!(import_object, ___syscall122); - // mock_external!(import_object, ___syscall102); - // mock_external!(import_object, ___syscall20); - mock_external!(import_object, ___syscall15); - mock_external!(import_object, ___syscall10); - mock_external!(import_object, _dlopen); - mock_external!(import_object, _dlclose); - mock_external!(import_object, _dlsym); - mock_external!(import_object, _dlerror); - - import_object +macro_rules! func { + ($namespace:ident, $function:ident) => {{ + unsafe { FuncPointer::new($namespace::$function as _) } + }}; +} + +macro_rules! global { + ($value:ident) => {{ + unsafe { + GlobalPointer::new( + // NOTE: Taking a shortcut here. LocalGlobal is a struct containing just u64. + std::mem::transmute::<&u64, *mut LocalGlobal>($value), + ) + } + }}; +} + +pub struct EmscriptenGlobals<'a> { + pub data: HashMap<&'a str, HashMap<&'a str, (u64, Type)>>, // > +} + +impl<'a> EmscriptenGlobals<'a> { + pub fn new() -> Self { + let mut data = HashMap::new(); + let mut env_namepace = HashMap::new(); + let mut global_namepace = HashMap::new(); + + env_namepace.insert("STACKTOP", (stacktop(STATIC_BUMP) as _, I32)); + env_namepace.insert("STACK_MAX", (stack_max(STATIC_BUMP) as _, I32)); + env_namepace.insert("DYNAMICTOP_PTR", (dynamictop_ptr(STATIC_BUMP) as _, I32)); + env_namepace.insert("tableBase", (0, I32)); + global_namepace.insert("Infinity", (std::f64::INFINITY.to_bits() as _, F64)); + global_namepace.insert("NaN", (std::f64::NAN.to_bits() as _, F64)); + + data.insert("env", env_namepace); + data.insert("global", global_namepace); + + Self { data } + } +} + +pub fn generate_emscripten_env(globals: &EmscriptenGlobals) -> Imports { + let mut imports = Imports::new(); + let mut env_namespace = NamespaceMap::new(); + let mut asm_namespace = NamespaceMap::new(); + let mut global_namespace = NamespaceMap::new(); + + // Add globals. + // NOTE: There is really no need for checks, these globals should always be available. + let env_globals = globals.data.get("env").unwrap(); + let global_globals = globals.data.get("global").unwrap(); + + let (value, ty) = env_globals.get("STACKTOP").unwrap(); + env_namespace.insert( + "STACKTOP".to_string(), + Export::Global { + local: global!(value), + global: GlobalDesc { + mutable: false, + ty: ty.clone(), + }, + }, + ); + + let (value, ty) = env_globals.get("STACK_MAX").unwrap(); + env_namespace.insert( + "STACK_MAX".to_string(), + Export::Global { + local: global!(value), + global: GlobalDesc { + mutable: false, + ty: ty.clone(), + }, + }, + ); + + let (value, ty) = env_globals.get("DYNAMICTOP_PTR").unwrap(); + env_namespace.insert( + "DYNAMICTOP_PTR".to_string(), + Export::Global { + local: global!(value), + global: GlobalDesc { + mutable: false, + ty: ty.clone(), + }, + }, + ); + + let (value, ty) = env_globals.get("tableBase").unwrap(); + env_namespace.insert( + "tableBase".to_string(), + Export::Global { + local: global!(value), + global: GlobalDesc { + mutable: false, + ty: ty.clone(), + }, + }, + ); + + let (value, ty) = global_globals.get("Infinity").unwrap(); + global_namespace.insert( + "Infinity".to_string(), + Export::Global { + local: global!(value), + global: GlobalDesc { + mutable: false, + ty: ty.clone(), + }, + }, + ); + + let (value, ty) = global_globals.get("NaN").unwrap(); + global_namespace.insert( + "NaN".to_string(), + Export::Global { + local: global!(value), + global: GlobalDesc { + mutable: false, + ty: ty.clone(), + }, + }, + ); + + // Print function + env_namespace.insert( + "printf", + Export::Function { + func: func!(io, printf), + ctx: Context::Internal, + signature: FuncSig { + params: vec![I32, I32], + returns: vec![I32], + }, + }, + ); + + env_namespace.insert( + "putchar", + Export::Function { + func: func!(io, putchar), + ctx: Context::Internal, + signature: FuncSig { + params: vec![I32], + returns: vec![], + }, + }, + ); + + // Lock + env_namespace.insert( + "___lock", + Export::Function { + func: func!(lock, ___lock), + ctx: Context::Internal, + signature: FuncSig { + params: vec![I32, I32], + returns: vec![], + }, + }, + ); + + env_namespace.insert( + "___unlock", + Export::Function { + func: func!(lock, ___unlock), + ctx: Context::Internal, + signature: FuncSig { + params: vec![I32, I32], + returns: vec![], + }, + }, + ); + + env_namespace.insert( + "___wait", + Export::Function { + func: func!(lock, ___wait), + ctx: Context::Internal, + signature: FuncSig { + params: vec![I32, I32], + returns: vec![], + }, + }, + ); + // Env + env_namespace.insert( + "_getenv", + Export::Function { + func: func!(env, _getenv), + ctx: Context::Internal, + signature: FuncSig { + params: vec![I32], + returns: vec![I32], + }, + }, + ); + + env_namespace.insert( + "_setenv", + Export::Function { + func: func!(env, _setenv), + ctx: Context::Internal, + signature: FuncSig { + params: vec![I32, I32, I32], + returns: vec![], + }, + }, + ); + + env_namespace.insert( + "_putenv", + Export::Function { + func: func!(env, _putenv), + ctx: Context::Internal, + signature: FuncSig { + params: vec![I32], + returns: vec![], + }, + }, + ); + + env_namespace.insert( + "_unsetenv", + Export::Function { + func: func!(env, _unsetenv), + ctx: Context::Internal, + signature: FuncSig { + params: vec![I32], + returns: vec![], + }, + }, + ); + + env_namespace.insert( + "_getpwnam", + Export::Function { + func: func!(env, _getpwnam), + ctx: Context::Internal, + signature: FuncSig { + params: vec![I32], + returns: vec![I32], + }, + }, + ); + + env_namespace.insert( + "_getgrnam", + Export::Function { + func: func!(env, _getgrnam), + ctx: Context::Internal, + signature: FuncSig { + params: vec![I32], + returns: vec![I32], + }, + }, + ); + + env_namespace.insert( + "___buildEnvironment", + Export::Function { + func: func!(env, ___build_environment), + ctx: Context::Internal, + signature: FuncSig { + params: vec![I32], + returns: vec![], + }, + }, + ); + // Errno + env_namespace.insert( + "___setErrNo", + Export::Function { + func: func!(errno, ___seterrno), + ctx: Context::Internal, + signature: FuncSig { + params: vec![I32], + returns: vec![I32], + }, + }, + ); + // Syscalls + env_namespace.insert( + "___syscall1", + Export::Function { + func: func!(syscalls, ___syscall1), + ctx: Context::Internal, + signature: FuncSig { + params: vec![I32, I32], + returns: vec![], + }, + }, + ); + + env_namespace.insert( + "___syscall3", + Export::Function { + func: func!(syscalls, ___syscall3), + ctx: Context::Internal, + signature: FuncSig { + params: vec![I32, I32], + returns: vec![I32], + }, + }, + ); + + env_namespace.insert( + "___syscall4", + Export::Function { + func: func!(syscalls, ___syscall4), + ctx: Context::Internal, + signature: FuncSig { + params: vec![I32, I32], + returns: vec![I32], + }, + }, + ); + + env_namespace.insert( + "___syscall5", + Export::Function { + func: func!(syscalls, ___syscall5), + ctx: Context::Internal, + signature: FuncSig { + params: vec![I32, I32], + returns: vec![I32], + }, + }, + ); + + env_namespace.insert( + "___syscall6", + Export::Function { + func: func!(syscalls, ___syscall6), + ctx: Context::Internal, + signature: FuncSig { + params: vec![I32, I32], + returns: vec![I32], + }, + }, + ); + + env_namespace.insert( + "___syscall12", + Export::Function { + func: func!(syscalls, ___syscall12), + ctx: Context::Internal, + signature: FuncSig { + params: vec![I32, I32], + returns: vec![I32], + }, + }, + ); + + env_namespace.insert( + "___syscall20", + Export::Function { + func: func!(syscalls, ___syscall20), + ctx: Context::Internal, + signature: FuncSig { + params: vec![], + returns: vec![I32], + }, + }, + ); + + env_namespace.insert( + "___syscall39", + Export::Function { + func: func!(syscalls, ___syscall39), + ctx: Context::Internal, + signature: FuncSig { + params: vec![I32, I32], + returns: vec![I32], + }, + }, + ); + + env_namespace.insert( + "___syscall40", + Export::Function { + func: func!(syscalls, ___syscall40), + ctx: Context::Internal, + signature: FuncSig { + params: vec![I32, I32], + returns: vec![I32], + }, + }, + ); + + env_namespace.insert( + "___syscall54", + Export::Function { + func: func!(syscalls, ___syscall54), + ctx: Context::Internal, + signature: FuncSig { + params: vec![I32, I32], + returns: vec![I32], + }, + }, + ); + + env_namespace.insert( + "___syscall57", + Export::Function { + func: func!(syscalls, ___syscall57), + ctx: Context::Internal, + signature: FuncSig { + params: vec![I32, I32], + returns: vec![I32], + }, + }, + ); + + env_namespace.insert( + "___syscall63", + Export::Function { + func: func!(syscalls, ___syscall63), + ctx: Context::Internal, + signature: FuncSig { + params: vec![I32, I32], + returns: vec![I32], + }, + }, + ); + + env_namespace.insert( + "___syscall64", + Export::Function { + func: func!(syscalls, ___syscall64), + ctx: Context::Internal, + signature: FuncSig { + params: vec![], + returns: vec![I32], + }, + }, + ); + + env_namespace.insert( + "___syscall102", + Export::Function { + func: func!(syscalls, ___syscall102), + ctx: Context::Internal, + signature: FuncSig { + params: vec![I32, I32], + returns: vec![I32], + }, + }, + ); + + env_namespace.insert( + "___syscall114", + Export::Function { + func: func!(syscalls, ___syscall114), + ctx: Context::Internal, + signature: FuncSig { + params: vec![I32, I32], + returns: vec![I32], + }, + }, + ); + + env_namespace.insert( + "___syscall122", + Export::Function { + func: func!(syscalls, ___syscall122), + ctx: Context::Internal, + signature: FuncSig { + params: vec![I32, I32], + returns: vec![I32], + }, + }, + ); + + env_namespace.insert( + "___syscall140", + Export::Function { + func: func!(syscalls, ___syscall140), + ctx: Context::Internal, + signature: FuncSig { + params: vec![I32, I32], + returns: vec![I32], + }, + }, + ); + + env_namespace.insert( + "___syscall142", + Export::Function { + func: func!(syscalls, ___syscall142), + ctx: Context::Internal, + signature: FuncSig { + params: vec![I32, I32], + returns: vec![I32], + }, + }, + ); + + env_namespace.insert( + "___syscall145", + Export::Function { + func: func!(syscalls, ___syscall145), + ctx: Context::Internal, + signature: FuncSig { + params: vec![I32, I32], + returns: vec![I32], + }, + }, + ); + + env_namespace.insert( + "___syscall146", + Export::Function { + func: func!(syscalls, ___syscall146), + ctx: Context::Internal, + signature: FuncSig { + params: vec![I32, I32], + returns: vec![I32], + }, + }, + ); + + env_namespace.insert( + "___syscall180", + Export::Function { + func: func!(syscalls, ___syscall180), + ctx: Context::Internal, + signature: FuncSig { + params: vec![I32, I32], + returns: vec![I32], + }, + }, + ); + + env_namespace.insert( + "___syscall181", + Export::Function { + func: func!(syscalls, ___syscall181), + ctx: Context::Internal, + signature: FuncSig { + params: vec![I32, I32], + returns: vec![I32], + }, + }, + ); + + env_namespace.insert( + "___syscall192", + Export::Function { + func: func!(syscalls, ___syscall192), + ctx: Context::Internal, + signature: FuncSig { + params: vec![I32, I32], + returns: vec![I32], + }, + }, + ); + + env_namespace.insert( + "___syscall195", + Export::Function { + func: func!(syscalls, ___syscall195), + ctx: Context::Internal, + signature: FuncSig { + params: vec![I32, I32], + returns: vec![I32], + }, + }, + ); + + env_namespace.insert( + "___syscall197", + Export::Function { + func: func!(syscalls, ___syscall197), + ctx: Context::Internal, + signature: FuncSig { + params: vec![I32, I32], + returns: vec![I32], + }, + }, + ); + + env_namespace.insert( + "___syscall201", + Export::Function { + func: func!(syscalls, ___syscall201), + ctx: Context::Internal, + signature: FuncSig { + params: vec![], + returns: vec![I32], + }, + }, + ); + + env_namespace.insert( + "___syscall202", + Export::Function { + func: func!(syscalls, ___syscall202), + ctx: Context::Internal, + signature: FuncSig { + params: vec![], + returns: vec![I32], + }, + }, + ); + + env_namespace.insert( + "___syscall212", + Export::Function { + func: func!(syscalls, ___syscall212), + ctx: Context::Internal, + signature: FuncSig { + params: vec![I32, I32], + returns: vec![I32], + }, + }, + ); + + env_namespace.insert( + "___syscall221", + Export::Function { + func: func!(syscalls, ___syscall221), + ctx: Context::Internal, + signature: FuncSig { + params: vec![I32, I32], + returns: vec![I32], + }, + }, + ); + + env_namespace.insert( + "___syscall330", + Export::Function { + func: func!(syscalls, ___syscall330), + ctx: Context::Internal, + signature: FuncSig { + params: vec![I32, I32], + returns: vec![I32], + }, + }, + ); + + env_namespace.insert( + "___syscall340", + Export::Function { + func: func!(syscalls, ___syscall340), + ctx: Context::Internal, + signature: FuncSig { + params: vec![I32, I32], + returns: vec![I32], + }, + }, + ); + // Process + env_namespace.insert( + "abort", + Export::Function { + func: func!(process, em_abort), + ctx: Context::Internal, + signature: FuncSig { + params: vec![I32], + returns: vec![], + }, + }, + ); + + env_namespace.insert( + "_abort", + Export::Function { + func: func!(process, _abort), + ctx: Context::Internal, + signature: FuncSig { + params: vec![], + returns: vec![], + }, + }, + ); + + env_namespace.insert( + "abortStackOverflow", + Export::Function { + func: func!(process, abort_stack_overflow), + ctx: Context::Internal, + signature: FuncSig { + params: vec![], + returns: vec![], + }, + }, + ); + + env_namespace.insert( + "_llvm_trap", + Export::Function { + func: func!(process, _llvm_trap), + ctx: Context::Internal, + signature: FuncSig { + params: vec![], + returns: vec![], + }, + }, + ); + + env_namespace.insert( + "_fork", + Export::Function { + func: func!(process, _fork), + ctx: Context::Internal, + signature: FuncSig { + params: vec![], + returns: vec![I32], + }, + }, + ); + + env_namespace.insert( + "_exit", + Export::Function { + func: func!(process, _exit), + ctx: Context::Internal, + signature: FuncSig { + params: vec![I32], + returns: vec![], + }, + }, + ); + + env_namespace.insert( + "_system", + Export::Function { + func: func!(process, _system), + ctx: Context::Internal, + signature: FuncSig { + params: vec![], + returns: vec![I32], + }, + }, + ); + + env_namespace.insert( + "_popen", + Export::Function { + func: func!(process, _popen), + ctx: Context::Internal, + signature: FuncSig { + params: vec![], + returns: vec![I32], + }, + }, + ); + // Signal + env_namespace.insert( + "_sigemptyset", + Export::Function { + func: func!(signal, _sigemptyset), + ctx: Context::Internal, + signature: FuncSig { + params: vec![I32], + returns: vec![I32], + }, + }, + ); + + env_namespace.insert( + "_sigaddset", + Export::Function { + func: func!(signal, _sigaddset), + ctx: Context::Internal, + signature: FuncSig { + params: vec![I32, I32], + returns: vec![I32], + }, + }, + ); + + env_namespace.insert( + "_sigprocmask", + Export::Function { + func: func!(signal, _sigprocmask), + ctx: Context::Internal, + signature: FuncSig { + params: vec![], + returns: vec![I32], + }, + }, + ); + + env_namespace.insert( + "_sigaction", + Export::Function { + func: func!(signal, _sigaction), + ctx: Context::Internal, + signature: FuncSig { + params: vec![I32, I32, I32], + returns: vec![I32], + }, + }, + ); + + env_namespace.insert( + "_signal", + Export::Function { + func: func!(signal, _signal), + ctx: Context::Internal, + signature: FuncSig { + params: vec![I32], + returns: vec![I32], + }, + }, + ); + // Memory + env_namespace.insert( + "abortOnCannotGrowMemory", + Export::Function { + func: func!(memory, abort_on_cannot_grow_memory), + ctx: Context::Internal, + signature: FuncSig { + params: vec![], + returns: vec![], + }, + }, + ); + + env_namespace.insert( + "_emscripten_memcpy_big", + Export::Function { + func: func!(memory, _emscripten_memcpy_big), + ctx: Context::Internal, + signature: FuncSig { + params: vec![I32, I32, I32], + returns: vec![I32], + }, + }, + ); + + env_namespace.insert( + "enlargeMemory", + Export::Function { + func: func!(memory, enlarge_memory), + ctx: Context::Internal, + signature: FuncSig { + params: vec![], + returns: vec![], + }, + }, + ); + + env_namespace.insert( + "getTotalMemory", + Export::Function { + func: func!(memory, get_total_memory), + ctx: Context::Internal, + signature: FuncSig { + params: vec![], + returns: vec![I32], + }, + }, + ); + + env_namespace.insert( + "___map_file", + Export::Function { + func: func!(memory, ___map_file), + ctx: Context::Internal, + signature: FuncSig { + params: vec![], + returns: vec![I32], + }, + }, + ); + // Exception + env_namespace.insert( + "___cxa_allocate_exception", + Export::Function { + func: func!(exception, ___cxa_allocate_exception), + ctx: Context::Internal, + signature: FuncSig { + params: vec![I32], + returns: vec![I32], + }, + }, + ); + + env_namespace.insert( + "___cxa_allocate_exception", + Export::Function { + func: func!(exception, ___cxa_throw), + ctx: Context::Internal, + signature: FuncSig { + params: vec![I32, I32, I32], + returns: vec![], + }, + }, + ); + + env_namespace.insert( + "___cxa_throw", + Export::Function { + func: func!(exception, ___cxa_throw), + ctx: Context::Internal, + signature: FuncSig { + params: vec![I32, I32, I32], + returns: vec![], + }, + }, + ); + // NullFuncs + env_namespace.insert( + "nullFunc_ii", + Export::Function { + func: func!(nullfunc, nullfunc_ii), + ctx: Context::Internal, + signature: FuncSig { + params: vec![I32], + returns: vec![], + }, + }, + ); + + env_namespace.insert( + "nullFunc_iii", + Export::Function { + func: func!(nullfunc, nullfunc_iii), + ctx: Context::Internal, + signature: FuncSig { + params: vec![I32], + returns: vec![], + }, + }, + ); + + env_namespace.insert( + "nullFunc_iiii", + Export::Function { + func: func!(nullfunc, nullfunc_iiii), + ctx: Context::Internal, + signature: FuncSig { + params: vec![I32], + returns: vec![], + }, + }, + ); + + env_namespace.insert( + "nullFunc_iiiii", + Export::Function { + func: func!(nullfunc, nullfunc_iiiii), + ctx: Context::Internal, + signature: FuncSig { + params: vec![I32], + returns: vec![], + }, + }, + ); + + env_namespace.insert( + "nullFunc_iiiiii", + Export::Function { + func: func!(nullfunc, nullfunc_iiiiii), + ctx: Context::Internal, + signature: FuncSig { + params: vec![I32], + returns: vec![], + }, + }, + ); + + env_namespace.insert( + "nullFunc_v", + Export::Function { + func: func!(nullfunc, nullfunc_v), + ctx: Context::Internal, + signature: FuncSig { + params: vec![I32], + returns: vec![], + }, + }, + ); + + env_namespace.insert( + "nullFunc_vi", + Export::Function { + func: func!(nullfunc, nullfunc_vi), + ctx: Context::Internal, + signature: FuncSig { + params: vec![I32], + returns: vec![], + }, + }, + ); + + env_namespace.insert( + "nullFunc_vii", + Export::Function { + func: func!(nullfunc, nullfunc_vii), + ctx: Context::Internal, + signature: FuncSig { + params: vec![I32], + returns: vec![], + }, + }, + ); + + env_namespace.insert( + "nullFunc_viii", + Export::Function { + func: func!(nullfunc, nullfunc_viii), + ctx: Context::Internal, + signature: FuncSig { + params: vec![I32], + returns: vec![], + }, + }, + ); + + env_namespace.insert( + "nullFunc_viiii", + Export::Function { + func: func!(nullfunc, nullfunc_viiii), + ctx: Context::Internal, + signature: FuncSig { + params: vec![I32], + returns: vec![], + }, + }, + ); + + env_namespace.insert( + "nullFunc_viiiii", + Export::Function { + func: func!(nullfunc, nullfunc_viiiii), + ctx: Context::Internal, + signature: FuncSig { + params: vec![I32], + returns: vec![], + }, + }, + ); + + env_namespace.insert( + "nullFunc_viiiiii", + Export::Function { + func: func!(nullfunc, nullfunc_viiiiii), + ctx: Context::Internal, + signature: FuncSig { + params: vec![I32], + returns: vec![], + }, + }, + ); + // Time + env_namespace.insert( + "_gettimeofday", + Export::Function { + func: func!(time, _gettimeofday), + ctx: Context::Internal, + signature: FuncSig { + params: vec![I32, I32], + returns: vec![I32], + }, + }, + ); + + env_namespace.insert( + "_clock_gettime", + Export::Function { + func: func!(time, _clock_gettime), + ctx: Context::Internal, + signature: FuncSig { + params: vec![I32, I32], + returns: vec![I32], + }, + }, + ); + + env_namespace.insert( + "___clock_gettime", + Export::Function { + func: func!(time, ___clock_gettime), + ctx: Context::Internal, + signature: FuncSig { + params: vec![I32, I32], + returns: vec![I32], + }, + }, + ); + + env_namespace.insert( + "_clock", + Export::Function { + func: func!(time, _clock), + ctx: Context::Internal, + signature: FuncSig { + params: vec![], + returns: vec![I32], + }, + }, + ); + + env_namespace.insert( + "_difftime", + Export::Function { + func: func!(time, _difftime), + ctx: Context::Internal, + signature: FuncSig { + params: vec![I32, I32], + returns: vec![I32], + }, + }, + ); + + env_namespace.insert( + "_asctime", + Export::Function { + func: func!(time, _asctime), + ctx: Context::Internal, + signature: FuncSig { + params: vec![I32], + returns: vec![I32], + }, + }, + ); + + env_namespace.insert( + "_asctime_r", + Export::Function { + func: func!(time, _asctime_r), + ctx: Context::Internal, + signature: FuncSig { + params: vec![I32, I32], + returns: vec![I32], + }, + }, + ); + + env_namespace.insert( + "_localtime", + Export::Function { + func: func!(time, _localtime), + ctx: Context::Internal, + signature: FuncSig { + params: vec![I32], + returns: vec![I32], + }, + }, + ); + + env_namespace.insert( + "_time", + Export::Function { + func: func!(time, _time), + ctx: Context::Internal, + signature: FuncSig { + params: vec![I32], + returns: vec![I32], + }, + }, + ); + + env_namespace.insert( + "_strftime", + Export::Function { + func: func!(time, _strftime), + ctx: Context::Internal, + signature: FuncSig { + params: vec![I32, I32, I32, I32], + returns: vec![I32], + }, + }, + ); + + env_namespace.insert( + "_localtime_r", + Export::Function { + func: func!(time, _localtime_r), + ctx: Context::Internal, + signature: FuncSig { + params: vec![I32, I32], + returns: vec![I32], + }, + }, + ); + + env_namespace.insert( + "_getpagesize", + Export::Function { + func: func!(env, _getpagesize), + ctx: Context::Internal, + signature: FuncSig { + params: vec![], + returns: vec![I32], + }, + }, + ); + + env_namespace.insert( + "_sysconf", + Export::Function { + func: func!(env, _sysconf), + ctx: Context::Internal, + signature: FuncSig { + params: vec![I32], + returns: vec![I32], + }, + }, + ); + + // Math + asm_namespace.insert( + "f64-rem", + Export::Function { + func: func!(math, f64_rem), + ctx: Context::Internal, + signature: FuncSig { + params: vec![F64, F64], + returns: vec![F64], + }, + }, + ); + + env_namespace.insert( + "_llvm_log10_f64", + Export::Function { + func: func!(math, _llvm_log10_f64), + ctx: Context::Internal, + signature: FuncSig { + params: vec![F64], + returns: vec![F64], + }, + }, + ); + + env_namespace.insert( + "_llvm_log2_f64", + Export::Function { + func: func!(math, _llvm_log2_f64), + ctx: Context::Internal, + signature: FuncSig { + params: vec![F64], + returns: vec![F64], + }, + }, + ); + + // + env_namespace.insert( + "__setjmp", + Export::Function { + func: func!(jmp, __setjmp), + ctx: Context::Internal, + signature: FuncSig { + params: vec![I32], + returns: vec![I32], + }, + }, + ); + + env_namespace.insert( + "__longjmp", + Export::Function { + func: func!(jmp, __longjmp), + ctx: Context::Internal, + signature: FuncSig { + params: vec![I32, I32], + returns: vec![], + }, + }, + ); + + mock_external!(env_namespace, _waitpid); + mock_external!(env_namespace, _utimes); + mock_external!(env_namespace, _usleep); + // mock_external!(env_namespace, _time); + // mock_external!(env_namespace, _sysconf); + // mock_external!(env_namespace, _strftime); + mock_external!(env_namespace, _sigsuspend); + // mock_external!(env_namespace, _sigprocmask); + // mock_external!(env_namespace, _sigemptyset); + // mock_external!(env_namespace, _sigaddset); + // mock_external!(env_namespace, _sigaction); + mock_external!(env_namespace, _setitimer); + mock_external!(env_namespace, _setgroups); + mock_external!(env_namespace, _setgrent); + mock_external!(env_namespace, _sem_wait); + mock_external!(env_namespace, _sem_post); + mock_external!(env_namespace, _sem_init); + mock_external!(env_namespace, _sched_yield); + mock_external!(env_namespace, _raise); + mock_external!(env_namespace, _mktime); + // mock_external!(env_namespace, _localtime_r); + // mock_external!(env_namespace, _localtime); + mock_external!(env_namespace, _llvm_stacksave); + mock_external!(env_namespace, _llvm_stackrestore); + mock_external!(env_namespace, _kill); + mock_external!(env_namespace, _gmtime_r); + // mock_external!(env_namespace, _gettimeofday); + // mock_external!(env_namespace, _getpagesize); + mock_external!(env_namespace, _getgrent); + mock_external!(env_namespace, _getaddrinfo); + // mock_external!(env_namespace, _fork); + // mock_external!(env_namespace, _exit); + mock_external!(env_namespace, _execve); + mock_external!(env_namespace, _endgrent); + // mock_external!(env_namespace, _clock_gettime); + mock_external!(env_namespace, ___syscall97); + mock_external!(env_namespace, ___syscall91); + mock_external!(env_namespace, ___syscall85); + mock_external!(env_namespace, ___syscall75); + mock_external!(env_namespace, ___syscall66); + // mock_external!(env_namespace, ___syscall64); + // mock_external!(env_namespace, ___syscall63); + // mock_external!(env_namespace, ___syscall60); + // mock_external!(env_namespace, ___syscall54); + // mock_external!(env_namespace, ___syscall39); + mock_external!(env_namespace, ___syscall38); + // mock_external!(env_namespace, ___syscall340); + mock_external!(env_namespace, ___syscall334); + mock_external!(env_namespace, ___syscall300); + mock_external!(env_namespace, ___syscall295); + mock_external!(env_namespace, ___syscall272); + mock_external!(env_namespace, ___syscall268); + // mock_external!(env_namespace, ___syscall221); + mock_external!(env_namespace, ___syscall220); + // mock_external!(env_namespace, ___syscall212); + // mock_external!(env_namespace, ___syscall201); + mock_external!(env_namespace, ___syscall199); + // mock_external!(env_namespace, ___syscall197); + mock_external!(env_namespace, ___syscall196); + // mock_external!(env_namespace, ___syscall195); + mock_external!(env_namespace, ___syscall194); + mock_external!(env_namespace, ___syscall191); + // mock_external!(env_namespace, ___syscall181); + // mock_external!(env_namespace, ___syscall180); + mock_external!(env_namespace, ___syscall168); + // mock_external!(env_namespace, ___syscall146); + // mock_external!(env_namespace, ___syscall145); + // mock_external!(env_namespace, ___syscall142); + mock_external!(env_namespace, ___syscall140); + // mock_external!(env_namespace, ___syscall122); + // mock_external!(env_namespace, ___syscall102); + // mock_external!(env_namespace, ___syscall20); + mock_external!(env_namespace, ___syscall15); + mock_external!(env_namespace, ___syscall10); + mock_external!(env_namespace, _dlopen); + mock_external!(env_namespace, _dlclose); + mock_external!(env_namespace, _dlsym); + mock_external!(env_namespace, _dlerror); + + imports.register("env", env_namespace); + imports.register("asm2wasm", asm_namespace); + + imports } diff --git a/lib/emscripten/src/lock.rs b/lib/emscripten/src/lock.rs index 5b2473c05..384eefb82 100644 --- a/lib/emscripten/src/lock.rs +++ b/lib/emscripten/src/lock.rs @@ -1,5 +1,5 @@ -use wasmer_runtime::Instance; use libc::c_int; +use wasmer_runtime::Instance; // NOTE: Not implemented by Emscripten pub extern "C" fn ___lock(which: c_int, varargs: c_int, _instance: &mut Instance) { diff --git a/lib/emscripten/src/memory.rs b/lib/emscripten/src/memory.rs index f1af076d7..fea9967cd 100644 --- a/lib/emscripten/src/memory.rs +++ b/lib/emscripten/src/memory.rs @@ -1,6 +1,6 @@ use super::process::abort_with_message; -use wasmer_runtime::Instance; use libc::{c_int, c_void, memcpy, size_t}; +use wasmer_runtime::Instance; /// emscripten: _emscripten_memcpy_big pub extern "C" fn _emscripten_memcpy_big( diff --git a/lib/emscripten/src/process.rs b/lib/emscripten/src/process.rs index 8fdabdbb8..10a7b73b8 100644 --- a/lib/emscripten/src/process.rs +++ b/lib/emscripten/src/process.rs @@ -1,7 +1,7 @@ use libc::{abort, c_char, c_int, exit, pid_t, EAGAIN}; -use wasmer_runtime::Instance; use std::ffi::CStr; +use wasmer_runtime::Instance; pub extern "C" fn abort_with_message(message: &str) { debug!("emscripten::abort_with_message"); diff --git a/lib/emscripten/src/signal.rs b/lib/emscripten/src/signal.rs index 852f4f4ae..7f256d6bf 100644 --- a/lib/emscripten/src/signal.rs +++ b/lib/emscripten/src/signal.rs @@ -1,6 +1,7 @@ // use super::varargs::VarArgs; use wasmer_runtime::Instance; +#[allow(clippy::cast_ptr_alignment)] pub extern "C" fn _sigemptyset(set: u32, instance: &mut Instance) -> i32 { debug!("emscripten::_sigemptyset"); let set_addr = instance.memory_offset_addr(0, set as _) as *mut u32; @@ -15,6 +16,7 @@ pub extern "C" fn _sigaction(signum: u32, act: u32, oldact: u32, _instance: &mut 0 } +#[allow(clippy::cast_ptr_alignment)] pub extern "C" fn _sigaddset(set: u32, signum: u32, instance: &mut Instance) -> i32 { debug!("emscripten::_sigaddset {}, {}", set, signum); let set_addr = instance.memory_offset_addr(0, set as _) as *mut u32; diff --git a/src/common/stdio.rs b/lib/emscripten/src/stdio.rs similarity index 100% rename from src/common/stdio.rs rename to lib/emscripten/src/stdio.rs diff --git a/lib/emscripten/src/syscalls.rs b/lib/emscripten/src/syscalls.rs index 0b20c97f8..366d93c7d 100644 --- a/lib/emscripten/src/syscalls.rs +++ b/lib/emscripten/src/syscalls.rs @@ -1,6 +1,5 @@ use super::utils::copy_stat_into_wasm; use super::varargs::VarArgs; -use wasmer_runtime::Instance; use byteorder::{ByteOrder, LittleEndian}; /// 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 @@ -68,8 +67,10 @@ use libc::{ F_GETFD, F_SETFD, SOL_SOCKET, + SO_REUSEADDR, TIOCGWINSZ, }; +use wasmer_runtime::Instance; use super::env; use std::mem; @@ -294,6 +295,7 @@ pub extern "C" fn ___syscall64() -> pid_t { } // socketcall +#[allow(clippy::cast_ptr_alignment)] pub extern "C" fn ___syscall102( which: c_int, mut varargs: VarArgs, @@ -336,18 +338,17 @@ pub extern "C" fn ___syscall102( unsafe { ioctl(fd, FIOCLEX); }; - if cfg!(target_os = "darwin") { - type T = u32; - let payload = 1 as *const T as *const c_void; - unsafe { - setsockopt( - fd, - SOL_SOCKET, - SO_NOSIGPIPE, - payload, - mem::size_of::() as socklen_t, - ); - }; + + type T = u32; + let payload = 1 as *const T as *const c_void; + unsafe { + setsockopt( + fd, + SOL_SOCKET, + SO_NOSIGPIPE, + payload, + mem::size_of::() as socklen_t, + ); }; debug!( @@ -364,12 +365,7 @@ pub extern "C" fn ___syscall102( let address: u32 = socket_varargs.get(instance); let address_len: u32 = socket_varargs.get(instance); let address = instance.memory_offset_addr(0, address as usize) as *mut sockaddr; - // unsafe { - // debug!( - // "=> address.sin_family: {:?}, address.sin_port: {:?}, address.sin_addr.s_addr: {:?}", - // (*address).sin_family, (*address).sin_port, (*address).sin_addr.s_addr - // ); - // } + // we convert address as a sockaddr (even if this is incorrect), to bypass the type // issue with libc bind @@ -437,25 +433,13 @@ pub extern "C" fn ___syscall102( (*address_linux).sa_family = (*address).sa_family as u16; (*address_linux).sa_data = (*address).sa_data; }; - // // Debug received address - // unsafe { - // let proper_address = address as *const GuestSockaddrIn; - // debug!( - // "=> address.sin_family: {:?}, address.sin_port: {:?}, address.sin_addr.s_addr: {:?}", - // (*proper_address).sin_family, (*proper_address).sin_port, (*proper_address).sin_addr.s_addr - // ); - // debug!( - // "=> address.sa_family: {:?}", - // (*address).sa_family - // ); - // } + // set_cloexec unsafe { ioctl(fd, FIOCLEX); }; debug!("fd: {}", fd); - // nix::unistd::write(fd, "Hello, World!".as_bytes()).unwrap(); - // nix::unistd::fsync(fd).unwrap(); + fd } 6 => { @@ -515,20 +499,19 @@ pub extern "C" fn ___syscall102( // name: Em passes SO_ACCEPTCONN, but Nginx complains about REUSEADDR // https://github.com/openbsd/src/blob/master/sys/sys/socket.h#L156 // setsockopt (socket: c_int, level: c_int, name: c_int, value: *const c_void, option_len: socklen_t) -> c_int + let socket: i32 = socket_varargs.get(instance); - // SOL_SOCKET = 0xffff in BSD - let level: i32 = 0xffff; + // SOL_SOCKET = 0xffff (BSD, Linux) + let level: i32 = SOL_SOCKET; let _: u32 = socket_varargs.get(instance); - // SO_ACCEPTCONN = 0x4 - let name: i32 = 0x4; + // SO_REUSEADDR = 0x4 (BSD, Linux) + let name: i32 = SO_REUSEADDR; let _: u32 = socket_varargs.get(instance); let value: u32 = socket_varargs.get(instance); let option_len: u32 = socket_varargs.get(instance); let value_addr = instance.memory_offset_addr(0, value as usize) as *mut c_void; // Endian problem let ret = unsafe { setsockopt(socket, level, name, value_addr, option_len) }; - // debug!("option_value = {:?}", unsafe { *(value_addr as *const u32) }); - debug!("=> socketfd: {}, level: {} (SOL_SOCKET/0xffff), name: {} (SO_REUSEADDR/4), value_addr: {:?}, option_len: {} = status: {}", socket, level, name, value_addr, option_len, ret); ret } @@ -571,6 +554,7 @@ pub extern "C" fn ___syscall102( } /// wait4 +#[allow(clippy::cast_ptr_alignment)] pub extern "C" fn ___syscall114( _which: c_int, mut varargs: VarArgs, @@ -606,6 +590,7 @@ pub extern "C" fn ___syscall122( } // select +#[allow(clippy::cast_ptr_alignment)] pub extern "C" fn ___syscall142( which: c_int, mut varargs: VarArgs, @@ -673,6 +658,7 @@ pub extern "C" fn ___syscall140( } /// readv +#[allow(clippy::cast_ptr_alignment)] pub extern "C" fn ___syscall145( which: c_int, mut varargs: VarArgs, @@ -718,6 +704,7 @@ pub extern "C" fn ___syscall145( } // writev +#[allow(clippy::cast_ptr_alignment)] pub extern "C" fn ___syscall146( which: c_int, mut varargs: VarArgs, diff --git a/lib/emscripten/src/time.rs b/lib/emscripten/src/time.rs index 14fb8bbf3..ec3f47f33 100644 --- a/lib/emscripten/src/time.rs +++ b/lib/emscripten/src/time.rs @@ -25,6 +25,7 @@ const CLOCK_MONOTONIC: libc::clockid_t = 1; const CLOCK_MONOTONIC_COARSE: libc::clockid_t = 6; /// emscripten: _gettimeofday +#[allow(clippy::cast_ptr_alignment)] pub extern "C" fn _gettimeofday(tp: c_int, tz: c_int, instance: &mut Instance) -> c_int { debug!("emscripten::_gettimeofday {} {}", tp, tz); #[repr(C)] @@ -49,6 +50,7 @@ pub extern "C" fn _gettimeofday(tp: c_int, tz: c_int, instance: &mut Instance) - } /// emscripten: _clock_gettime +#[allow(clippy::cast_ptr_alignment)] pub extern "C" fn _clock_gettime( clk_id: libc::clockid_t, tp: c_int, @@ -124,6 +126,7 @@ pub extern "C" fn _tvset() { } /// formats time as a C string +#[allow(clippy::cast_ptr_alignment)] unsafe extern "C" fn fmt_time(time: u32, instance: &Instance) -> *const c_char { let date = &*(instance.memory_offset_addr(0, time as _) as *mut guest_tm); @@ -181,6 +184,7 @@ pub extern "C" fn _asctime_r(time: u32, buf: u32, instance: &mut Instance) -> u3 } /// emscripten: _localtime +#[allow(clippy::cast_ptr_alignment)] pub extern "C" fn _localtime(time_p: u32, instance: &mut Instance) -> c_int { debug!("emscripten::_localtime {}", time_p); // NOTE: emscripten seems to want tzset() called in this function @@ -217,6 +221,7 @@ pub extern "C" fn _localtime(time_p: u32, instance: &mut Instance) -> c_int { } } /// emscripten: _localtime_r +#[allow(clippy::cast_ptr_alignment)] pub extern "C" fn _localtime_r(time_p: u32, result: u32, instance: &mut Instance) -> c_int { debug!("emscripten::_localtime_r {}", time_p); @@ -253,6 +258,7 @@ pub extern "C" fn _localtime_r(time_p: u32, result: u32, instance: &mut Instance } /// emscripten: _time +#[allow(clippy::cast_ptr_alignment)] pub extern "C" fn _time(time_p: u32, instance: &mut Instance) -> time_t { debug!("emscripten::_time {}", time_p); diff --git a/lib/emscripten/src/utils.rs b/lib/emscripten/src/utils.rs index 2feffa79a..c590801f8 100644 --- a/lib/emscripten/src/utils.rs +++ b/lib/emscripten/src/utils.rs @@ -1,4 +1,4 @@ -use wasmer_runtime::{Instance, module::Module}; +use wasmer_runtime::{module::Module, Instance}; //use wasmer_runtime::Instance; use super::env; use libc::stat; @@ -6,10 +6,11 @@ use std::ffi::CStr; use std::mem::size_of; use std::os::raw::c_char; use std::slice; +use std::sync::Arc; /// We check if a provided module is an Emscripten generated one -pub fn is_emscripten_module(module: &Module) -> bool { - for (_, import_name) in &module.imported_functions { - if import_name.name == "_emscripten_memcpy_big" && import_name.module == "env" { +pub fn is_emscripten_module(module: &Arc) -> bool { + for (_, import_name) in &module.0.imported_functions { + if import_name.name == "_emscripten_memcpy_big" && import_name.namespace == "env" { return true; } } @@ -50,14 +51,14 @@ pub unsafe fn allocate_on_stack<'a, T: Copy>( instance: &'a Instance, ) -> (u32, &'a mut [T]) { unimplemented!("allocate_on_stack not implemented") -// let offset = (instance.emscripten_data().as_ref().unwrap().stack_alloc)( -// count * (size_of::() as u32), -// instance, -// ); -// let addr = instance.memory_offset_addr(0, offset as _) as *mut T; -// let slice = slice::from_raw_parts_mut(addr, count as usize); -// -// (offset, slice) + // let offset = (instance.emscripten_data().as_ref().unwrap().stack_alloc)( + // count * (size_of::() as u32), + // instance, + // ); + // let addr = instance.memory_offset_addr(0, offset as _) as *mut T; + // let slice = slice::from_raw_parts_mut(addr, count as usize); + // + // (offset, slice) } pub unsafe fn allocate_cstr_on_stack<'a>(s: &str, instance: &'a Instance) -> (u32, &'a [u8]) { @@ -111,6 +112,7 @@ pub struct GuestStat { st_ino: u64, } +#[allow(clippy::cast_ptr_alignment)] pub unsafe fn copy_stat_into_wasm(instance: &mut Instance, buf: u32, stat: &stat) { let stat_ptr = instance.memory_offset_addr(0, buf as _) as *mut GuestStat; (*stat_ptr).st_dev = stat.st_dev as _; @@ -141,14 +143,18 @@ pub unsafe fn copy_stat_into_wasm(instance: &mut Instance, buf: u32, stat: &stat #[cfg(test)] mod tests { use super::is_emscripten_module; - use wasmer_clif_backend::CraneliftCompiler; + use std::sync::Arc; use wabt::wat2wasm; + use wasmer_clif_backend::CraneliftCompiler; + use wasmer_runtime::{compile, module::Module}; #[test] fn should_detect_emscripten_files() { const wast_bytes: &[u8] = include_bytes!("tests/is_emscripten_true.wast"); let wasm_binary = wat2wasm(wast_bytes.to_vec()).expect("Can't convert to wasm"); - let module = wasmer_runtime::compile(&wasm_binary[..], &CraneliftCompiler::new()).expect("WASM can't be compiled"); + let module = + compile(&wasm_binary[..], &CraneliftCompiler::new()).expect("WASM can't be compiled"); + let module = Arc::new(module); assert!(is_emscripten_module(&module)); } @@ -156,7 +162,9 @@ mod tests { fn should_detect_non_emscripten_files() { const wast_bytes: &[u8] = include_bytes!("tests/is_emscripten_false.wast"); let wasm_binary = wat2wasm(wast_bytes.to_vec()).expect("Can't convert to wasm"); - let module = wasmer_runtime::compile(&wasm_binary[..], &CraneliftCompiler::new()).expect("WASM can't be compiled"); + let module = + compile(&wasm_binary[..], &CraneliftCompiler::new()).expect("WASM can't be compiled"); + let module = Arc::new(module); assert!(!is_emscripten_module(&module)); } } diff --git a/lib/emscripten/src/varargs.rs b/lib/emscripten/src/varargs.rs index 3caef65a7..ce0bc9e96 100644 --- a/lib/emscripten/src/varargs.rs +++ b/lib/emscripten/src/varargs.rs @@ -1,5 +1,5 @@ -use wasmer_runtime::Instance; use std::mem; +use wasmer_runtime::Instance; #[repr(transparent)] pub struct VarArgs { diff --git a/lib/emscripten/tests/emtests/_common.rs b/lib/emscripten/tests/emtests/_common.rs index 594280047..526ae891c 100644 --- a/lib/emscripten/tests/emtests/_common.rs +++ b/lib/emscripten/tests/emtests/_common.rs @@ -1,46 +1,55 @@ macro_rules! assert_emscripten_output { ($file:expr, $name:expr, $args:expr, $expected:expr) => {{ - use wasmer_emscripten::generate_emscripten_env; - // use wasmer::common::stdio::StdioCapturer; - use wasmer_runtime::{Import, Imports, FuncRef}; - use wasmer_runtime::table::TableBacking; - use wasmer_runtime::{Instance, module::Module}; - use wasmer_clif_backend::CraneliftCompiler; - use std::sync::Arc; + use wasmer_clif_backend::CraneliftCompiler; + use wasmer_emscripten::{ + EmscriptenGlobals, + generate_emscripten_env, + stdio::StdioCapturer + }; let wasm_bytes = include_bytes!($file); - let import_object = generate_emscripten_env(); -// let options = Some(InstanceOptions { -// mock_missing_imports: true, -// mock_missing_globals: true, -// mock_missing_tables: true, -// abi: InstanceABI::Emscripten, -// show_progressbar: false, -// // isa: get_isa(), -// }); -// let mut result_object = instantiate(&wasm_bytes.to_vec(), &import_object, options) -// .expect("Not compiled properly"); - let module = wasmer_runtime::compile(&wasm_bytes[..], &CraneliftCompiler::new()).expect("WASM can't be compiled"); - let instance = module.instantiate(&import_object).expect("WASM can't be instantiated"); + let module = wasmer_runtime::compile(&wasm_bytes[..], &CraneliftCompiler::new()) + .expect("WASM can't be compiled"); + +// let module = compile(&wasm_bytes[..]) +// .map_err(|err| format!("Can't create the WebAssembly module: {}", err)).unwrap(); // NOTE: Need to figure what the unwrap is for ?? + + let emscripten_globals = EmscriptenGlobals::new(); + let import_object = generate_emscripten_env(&emscripten_globals); + + let mut instance = module.instantiate(import_object) + .map_err(|err| format!("Can't instantiate the WebAssembly module: {}", err)).unwrap(); // NOTE: Need to figure what the unwrap is for ?? + +// start_instance( +// Arc::clone(&module), +// &mut instance, +// $name, +// $args, +// ); - // let capturer = StdioCapturer::new(); - // start_instance( - // Arc::clone(&result_object.module), - // &mut result_object.instance, - // $name, - // $args, - // ) - // .unwrap(); - // let output = capturer.end().unwrap().0; - // let expected_output = include_str!($expected); assert!(false, "Emscripten tests are mocked"); - // assert!( - // output.contains(expected_output), - // "Output: `{}` does not contain expected output: `{}`", - // output, - // expected_output - // ); + + let capturer = StdioCapturer::new(); + + instance.call("_main", &[]).map(|_o| ()).unwrap(); + // TODO handle start instance logic +// start_instance( +// Arc::clone(&result_object.module), +// &mut result_object.instance, +// $name, +// $args, +// ) +// .unwrap(); + let output = capturer.end().unwrap().0; + let expected_output = include_str!($expected); + assert!(false, "Emscripten tests are mocked"); + assert!( + output.contains(expected_output), + "Output: `{}` does not contain expected output: `{}`", + output, + expected_output + ); }}; } diff --git a/lib/runtime/src/backing.rs b/lib/runtime/src/backing.rs index 289588176..662b00858 100644 --- a/lib/runtime/src/backing.rs +++ b/lib/runtime/src/backing.rs @@ -142,6 +142,7 @@ impl LocalBacking { tables.into_boxed_map() } + #[allow(clippy::cast_ptr_alignment)] fn finalize_tables( module: &ModuleInner, imports: &ImportBacking, diff --git a/lib/runtime/src/instance.rs b/lib/runtime/src/instance.rs index 080feeb14..028e0d4a9 100644 --- a/lib/runtime/src/instance.rs +++ b/lib/runtime/src/instance.rs @@ -25,7 +25,7 @@ pub(crate) struct InstanceInner { } pub struct Instance { - pub(crate) module: Rc, + pub module: Rc, inner: Box, #[allow(dead_code)] imports: Box, @@ -351,7 +351,7 @@ impl Namespace for Instance { // TODO Remove this later, only needed for compilation till emscripten is updated impl Instance { - pub fn memory_offset_addr(&self, _index: usize, _offset: usize) -> *const usize { - unimplemented!("TODO replace this emscripten stub") + pub fn memory_offset_addr(&self, index: usize, offset: usize) -> *const u8 { + unimplemented!() } } diff --git a/lib/runtime/src/lib.rs b/lib/runtime/src/lib.rs index b3803a963..dd7f62253 100644 --- a/lib/runtime/src/lib.rs +++ b/lib/runtime/src/lib.rs @@ -3,14 +3,14 @@ extern crate field_offset; #[macro_use] -mod macros; +pub mod macros; #[doc(hidden)] pub mod backend; mod backing; pub mod error; pub mod export; pub mod import; -mod instance; +pub mod instance; pub mod memory; mod mmap; pub mod module; diff --git a/lib/runtime/src/macros.rs b/lib/runtime/src/macros.rs index fe2bd1a7f..c27b1e8e0 100644 --- a/lib/runtime/src/macros.rs +++ b/lib/runtime/src/macros.rs @@ -1,3 +1,4 @@ +#[macro_export] macro_rules! debug { ($fmt:expr) => (if cfg!(any(debug_assertions, feature="debug")) { println!(concat!("wasmer-runtime(:{})::", $fmt), line!()) }); ($fmt:expr, $($arg:tt)*) => (if cfg!(any(debug_assertions, feature="debug")) { println!(concat!("wasmer-runtime(:{})::", $fmt, "\n"), line!(), $($arg)*) }); diff --git a/lib/runtime/src/module.rs b/lib/runtime/src/module.rs index 8a4d890be..7ca3e30bf 100644 --- a/lib/runtime/src/module.rs +++ b/lib/runtime/src/module.rs @@ -40,7 +40,7 @@ pub struct ModuleInner { pub sig_registry: SigRegistry, } -pub struct Module(Rc); +pub struct Module(pub Rc); impl Module { pub(crate) fn new(inner: Rc) -> Self { diff --git a/lib/runtime/src/vm.rs b/lib/runtime/src/vm.rs index dad4f2ad3..75e453168 100644 --- a/lib/runtime/src/vm.rs +++ b/lib/runtime/src/vm.rs @@ -84,6 +84,7 @@ impl Ctx { } } + #[allow(clippy::erasing_op)] // TODO pub fn offset_memories() -> u8 { 0 * (mem::size_of::() as u8) } @@ -131,6 +132,7 @@ pub struct ImportedFunc { } impl ImportedFunc { + #[allow(clippy::erasing_op)] // TODO pub fn offset_func() -> u8 { 0 * (mem::size_of::() as u8) } @@ -157,6 +159,7 @@ pub struct LocalTable { } impl LocalTable { + #[allow(clippy::erasing_op)] // TODO pub fn offset_base() -> u8 { 0 * (mem::size_of::() as u8) } @@ -180,6 +183,7 @@ pub struct ImportedTable { } impl ImportedTable { + #[allow(clippy::erasing_op)] // TODO pub fn offset_table() -> u8 { 0 * (mem::size_of::() as u8) } @@ -206,6 +210,7 @@ pub struct LocalMemory { } impl LocalMemory { + #[allow(clippy::erasing_op)] // TODO pub fn offset_base() -> u8 { 0 * (mem::size_of::() as u8) } @@ -228,6 +233,7 @@ pub struct ImportedMemory { } impl ImportedMemory { + #[allow(clippy::erasing_op)] // TODO pub fn offset_memory() -> u8 { 0 * (mem::size_of::() as u8) } @@ -249,6 +255,7 @@ pub struct LocalGlobal { } impl LocalGlobal { + #[allow(clippy::erasing_op)] // TODO pub fn offset_data() -> u8 { 0 * (mem::size_of::() as u8) } @@ -269,6 +276,7 @@ pub struct ImportedGlobal { } impl ImportedGlobal { + #[allow(clippy::erasing_op)] // TODO pub fn offset_global() -> u8 { 0 * (mem::size_of::() as u8) } @@ -301,6 +309,7 @@ impl Anyfunc { } } + #[allow(clippy::erasing_op)] // TODO pub fn offset_func() -> u8 { 0 * (mem::size_of::() as u8) } diff --git a/src/bin/wasmer.rs b/src/bin/wasmer.rs index 52ba9cba9..90605b1bd 100644 --- a/src/bin/wasmer.rs +++ b/src/bin/wasmer.rs @@ -11,8 +11,8 @@ use std::sync::Arc; use structopt::StructOpt; use wasmer::*; -use wasmer_runtime; use wasmer_emscripten; +use wasmer_runtime; #[derive(Debug, StructOpt)] #[structopt(name = "wasmer", about = "WASM execution runtime.")] @@ -80,10 +80,12 @@ fn execute_wasm(options: &Run) -> Result<(), String> { webassembly::InstanceABI::None }; - let import_object = if abi == webassembly::InstanceABI::Emscripten { - wasmer_emscripten::generate_emscripten_env() + let emscripten_globals = wasmer_emscripten::EmscriptenGlobals::new(); + + let mut import_object = if abi == webassembly::InstanceABI::Emscripten { + wasmer_emscripten::generate_emscripten_env(&emscripten_globals) } else { - wasmer_runtime::Imports::new() + wasmer_runtime::import::Imports::new() }; let instance_options = webassembly::InstanceOptions { @@ -92,12 +94,12 @@ fn execute_wasm(options: &Run) -> Result<(), String> { mock_missing_tables: true, abi: abi, show_progressbar: true, -// isa: isa, }; debug!("webassembly - creating instance"); - let mut instance = module.instantiate(&import_object) + let mut instance = module + .instantiate(import_object) .map_err(|err| format!("Can't instantiate the WebAssembly module: {}", err))?; webassembly::start_instance( diff --git a/src/common/mod.rs b/src/common/mod.rs index 63a6bd39f..2e4a760a8 100644 --- a/src/common/mod.rs +++ b/src/common/mod.rs @@ -1,6 +1,2 @@ pub mod mmap; pub mod slice; - -mod file_descriptor; -#[cfg(test)] -pub mod stdio; diff --git a/src/lib.rs b/src/lib.rs index 20047afff..9e9d07c16 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,10 +8,10 @@ extern crate libc; extern crate region; extern crate structopt; extern crate wabt; -extern crate wasmparser; extern crate wasmer_clif_backend; extern crate wasmer_runtime; -extern crate wasmer_emscripten; +extern crate wasmparser; +// extern crate wasmer_emscripten; #[macro_use] extern crate target_lexicon; extern crate byteorder; diff --git a/src/webassembly/mod.rs b/src/webassembly/mod.rs index 50c40d82e..e17b439de 100644 --- a/src/webassembly/mod.rs +++ b/src/webassembly/mod.rs @@ -4,14 +4,19 @@ pub mod relocation; pub mod utils; use wasmer_clif_backend::CraneliftCompiler; -use wasmer_runtime::{backend::Compiler, module::Module}; -use wasmer_runtime; -use wasmer_runtime::{Import, Imports, Instance}; +use wasmer_runtime::{ + backend::Compiler, + import::Imports, + instance::Instance, + module::{Module, ModuleInner}, +}; + use cranelift_codegen::{ isa, settings::{self, Configurable}, }; use std::panic; +use std::rc::Rc; use std::str::FromStr; use std::sync::Arc; use target_lexicon; @@ -31,7 +36,6 @@ pub struct ResultObject { pub instance: Box, } - pub struct InstanceOptions { // Shall we mock automatically the imported functions if they don't exist? pub mock_missing_imports: bool, @@ -39,7 +43,7 @@ pub struct InstanceOptions { pub mock_missing_tables: bool, pub abi: InstanceABI, pub show_progressbar: bool, -// pub isa: Box, TODO isa + // pub isa: Box, TODO isa } #[derive(PartialEq)] @@ -71,10 +75,10 @@ pub fn instantiate( //let instance = Instance::new(&module, import_object, options)?; unimplemented!() -// let instance = wasmer_runtime::instantiate(buffer_source, &CraneliftCompiler::new(), import_object) -// .map_err(|e| ErrorKind::CompileError(e))?; -// -// let isa = get_isa(); + // let instance = wasmer_runtime::instantiate(buffer_source, &CraneliftCompiler::new(), import_object) + // .map_err(|e| ErrorKind::CompileError(e))?; + // + // let isa = get_isa(); // let abi = if is_emscripten_module(&instance.module) { // InstanceABI::Emscripten // } else { @@ -90,11 +94,11 @@ pub fn instantiate( // isa, // }); -// debug!("webassembly - instance created"); -// Ok(ResultObject { -// module: Arc::clone(&instance.module), -// instance, -// }) + // debug!("webassembly - instance created"); + // Ok(ResultObject { + // module: Arc::clone(&instance.module), + // instance, + // }) } /// The webassembly::instantiate_streaming() function compiles and instantiates @@ -119,11 +123,11 @@ pub fn instantiate_streaming( /// webassembly::CompileError. pub fn compile(buffer_source: &[u8]) -> Result, ErrorKind> { let compiler = &CraneliftCompiler {}; - let module = compiler + let module_inner = compiler .compile(buffer_source) .map_err(|e| ErrorKind::CompileError(e))?; - Ok(Arc::new(module)) + Ok(Arc::new(Module(Rc::new(module_inner)))) } /// The webassembly::validate() function validates a given typed @@ -169,23 +173,23 @@ pub fn get_isa() -> Box { isa::lookup(triple!("x86_64")).unwrap().finish(flags) } -fn store_module_arguments(path: &str, args: Vec<&str>, instance: &mut Instance) -> (u32, u32) { - let argc = args.len() + 1; +// fn store_module_arguments(path: &str, args: Vec<&str>, instance: &mut Instance) -> (u32, u32) { +// let argc = args.len() + 1; - let (argv_offset, argv_slice): (_, &mut [u32]) = - unsafe { allocate_on_stack(((argc + 1) * 4) as u32, instance) }; - assert!(!argv_slice.is_empty()); +// let (argv_offset, argv_slice): (_, &mut [u32]) = +// unsafe { allocate_on_stack(((argc + 1) * 4) as u32, instance) }; +// assert!(!argv_slice.is_empty()); - argv_slice[0] = unsafe { allocate_cstr_on_stack(path, instance).0 }; +// argv_slice[0] = unsafe { allocate_cstr_on_stack(path, instance).0 }; - for (slot, arg) in argv_slice[1..argc].iter_mut().zip(args.iter()) { - *slot = unsafe { allocate_cstr_on_stack(&arg, instance).0 }; - } +// for (slot, arg) in argv_slice[1..argc].iter_mut().zip(args.iter()) { +// *slot = unsafe { allocate_cstr_on_stack(&arg, instance).0 }; +// } - argv_slice[argc] = 0; +// argv_slice[argc] = 0; - (argc as u32, argv_offset) -} +// (argc as u32, argv_offset) +// } // fn get_module_arguments(options: &Run, instance: &mut webassembly::Instance) -> (u32, u32) { // // Application Arguments @@ -227,7 +231,7 @@ pub fn start_instance( path: &str, args: Vec<&str>, ) -> Result<(), String> { - let main_name = if is_emscripten_module(&instance.module) { + let main_name = if is_emscripten_module(&module) { "_main" } else { "main"