Merge remote-tracking branch 'origin/master' into middleware

This commit is contained in:
losfair
2020-06-17 00:52:20 +08:00
143 changed files with 3449 additions and 2396 deletions

1
.gitignore vendored
View File

@@ -8,6 +8,7 @@ api-docs-repo/
/package/
/dist/
/wapm-cli/
/src/windows-installer/WasmerInstaller.exe
# Generated by tests on Android
/avd

135
Cargo.lock generated
View File

@@ -12,7 +12,7 @@ version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a49806b9dadc843c61e7c97e72490ad7f7220ae249012fbda9ad0609457c0543"
dependencies = [
"gimli 0.21.0",
"gimli",
]
[[package]]
@@ -279,27 +279,28 @@ checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
[[package]]
name = "cranelift-bforest"
version = "0.62.0"
version = "0.65.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "306270b2299cdd5e9736ff48047257d0e846e3bb724766bb6917e66a7c294a90"
checksum = "d9413a2c6bdb01ab8acc867421bd7343ddea491d015453f4e56f4f60c816d120"
dependencies = [
"cranelift-entity",
]
[[package]]
name = "cranelift-codegen"
version = "0.62.0"
version = "0.65.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6d697c867ac38f39bd69b67fa96ac1ac18a0e3ac641e878569f716343851f2b"
checksum = "f28d389588c2375bb95292e0bc6cbf010e7f30fb4e9734738b576521b737826a"
dependencies = [
"byteorder",
"cranelift-bforest",
"cranelift-codegen-meta",
"cranelift-codegen-shared",
"cranelift-entity",
"gimli 0.20.0",
"gimli",
"hashbrown",
"log",
"regalloc",
"serde",
"smallvec",
"target-lexicon",
@@ -308,9 +309,9 @@ dependencies = [
[[package]]
name = "cranelift-codegen-meta"
version = "0.62.0"
version = "0.65.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2404d7d75c8f343343a86cee4229e058925e64d40bfa2ecdab1f2242a0e1a7e1"
checksum = "74dd3cf6f107c1df4c2b8aab91ec4181aee7ff17289673fcbec63325e7e40a83"
dependencies = [
"cranelift-codegen-shared",
"cranelift-entity",
@@ -318,24 +319,24 @@ dependencies = [
[[package]]
name = "cranelift-codegen-shared"
version = "0.62.0"
version = "0.65.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "454e53d0b552b34b57f1efc333d638520e91fdc129258fc219fc1a50ffc4d07b"
checksum = "efaf050fab2dbf324544489443ff3cc8c67c9420c8902ec6628bd906bd7393e9"
[[package]]
name = "cranelift-entity"
version = "0.62.0"
version = "0.65.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d36cd0c5bd5de48d222b2bea101b828c208e7a392503f81e5dbaa79000ba04f2"
checksum = "f07eb8aa0a5da94b56339e4e3052c496a3df4354357cd5da8c7b02c6e8f1dc1d"
dependencies = [
"serde",
]
[[package]]
name = "cranelift-frontend"
version = "0.62.0"
version = "0.65.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70179dbdc8cad1bdff62dbceb06979cd1e923e218818ed3989adf253d5c7e2ac"
checksum = "0f6fe1d3e968576f4b60d23f40ee90281f8de2cdf23d2110f3b0296ff420555e"
dependencies = [
"cranelift-codegen",
"hashbrown",
@@ -344,6 +345,15 @@ dependencies = [
"target-lexicon",
]
[[package]]
name = "crc32fast"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1"
dependencies = [
"cfg-if",
]
[[package]]
name = "criterion"
version = "0.3.2"
@@ -609,19 +619,10 @@ dependencies = [
]
[[package]]
name = "faerie"
version = "0.15.0"
name = "fallible-iterator"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfef65b0e94693295c5d2fe2506f0ee6f43465342d4b5331659936aee8b16084"
dependencies = [
"goblin 0.1.3",
"indexmap",
"log",
"scroll",
"string-interner",
"target-lexicon",
"thiserror",
]
checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7"
[[package]]
name = "fnv"
@@ -676,21 +677,16 @@ dependencies = [
"syn",
]
[[package]]
name = "gimli"
version = "0.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81dd6190aad0f05ddbbf3245c54ed14ca4aa6dd32f22312b70d8f168c3e3e633"
dependencies = [
"byteorder",
"indexmap",
]
[[package]]
name = "gimli"
version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bcc8e0c9bce37868955864dbecd2b1ab2bdf967e6f28066d65aaac620444b65c"
dependencies = [
"fallible-iterator",
"indexmap",
"stable_deref_trait",
]
[[package]]
name = "glob"
@@ -698,17 +694,6 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
[[package]]
name = "goblin"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3081214398d39e4bd7f2c1975f0488ed04614ffdd976c6fc7a0708278552c0da"
dependencies = [
"log",
"plain",
"scroll",
]
[[package]]
name = "goblin"
version = "0.2.3"
@@ -1098,6 +1083,10 @@ name = "object"
version = "0.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9cbca9424c482ee628fa549d9c812e2cd22f1180b9222c9200fdfa6eb31aecb2"
dependencies = [
"crc32fast",
"indexmap",
]
[[package]]
name = "once_cell"
@@ -1480,6 +1469,17 @@ version = "0.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d813022b2e00774a48eaf43caaa3c20b45f040ba8cbf398e2e8911a06668dbe6"
[[package]]
name = "regalloc"
version = "0.0.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c03092d79e0fd610932d89ed53895a38c0dd3bcd317a0046e69940de32f1d95"
dependencies = [
"log",
"rustc-hash",
"smallvec",
]
[[package]]
name = "regex"
version = "1.3.9"
@@ -1693,15 +1693,6 @@ version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8"
[[package]]
name = "string-interner"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd710eadff449a1531351b0e43eb81ea404336fa2f56c777427ab0e32a4cf183"
dependencies = [
"serde",
]
[[package]]
name = "strsim"
version = "0.8.0"
@@ -2115,6 +2106,7 @@ dependencies = [
"wasmer-compiler-cranelift",
"wasmer-compiler-llvm",
"wasmer-compiler-singlepass",
"wasmer-emscripten",
"wasmer-engine",
"wasmer-engine-dummy",
"wasmer-engine-jit",
@@ -2137,6 +2129,14 @@ dependencies = [
"thiserror",
"wasm-common",
"wasmer",
"wasmer-compiler",
"wasmer-compiler-cranelift",
"wasmer-compiler-llvm",
"wasmer-compiler-singlepass",
"wasmer-emscripten",
"wasmer-engine",
"wasmer-engine-jit",
"wasmer-engine-native",
"wasmer-wasi",
]
@@ -2174,6 +2174,7 @@ version = "1.0.0-alpha.1"
dependencies = [
"cranelift-codegen",
"cranelift-frontend",
"gimli",
"hashbrown",
"lazy_static",
"more-asserts",
@@ -2192,7 +2193,7 @@ version = "1.0.0-alpha.1"
dependencies = [
"byteorder",
"cc",
"goblin 0.2.3",
"goblin",
"inkwell",
"itertools",
"lazy_static",
@@ -2226,6 +2227,19 @@ dependencies = [
"wasmer-runtime",
]
[[package]]
name = "wasmer-emscripten"
version = "1.0.0-alpha.1"
dependencies = [
"byteorder",
"getrandom",
"lazy_static",
"libc",
"log",
"time",
"wasmer",
]
[[package]]
name = "wasmer-engine"
version = "1.0.0-alpha.1"
@@ -2264,6 +2278,7 @@ name = "wasmer-engine-jit"
version = "1.0.0-alpha.1"
dependencies = [
"bincode",
"cfg-if",
"region",
"serde",
"serde_bytes",
@@ -2280,9 +2295,9 @@ version = "1.0.0-alpha.1"
dependencies = [
"bincode",
"cfg-if",
"faerie",
"leb128",
"libloading 0.6.2",
"object",
"serde",
"serde_bytes",
"tempfile",
@@ -2353,9 +2368,9 @@ dependencies = [
[[package]]
name = "wasmparser"
version = "0.51.4"
version = "0.57.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aeb1956b19469d1c5e63e459d29e7b5aa0f558d9f16fcef09736f8a265e6c10a"
checksum = "32fddd575d477c6e9702484139cf9f23dcd554b06d185ed0f56c857dd3a47aa6"
[[package]]
name = "wast"

View File

@@ -30,7 +30,7 @@ wasmer-compiler = { version = "1.0.0-alpha.1", path = "lib/compiler" }
wasmer-compiler-cranelift = { version = "1.0.0-alpha.1", path = "lib/compiler-cranelift", optional = true }
wasmer-compiler-singlepass = { version = "1.0.0-alpha.1", path = "lib/compiler-singlepass", optional = true }
wasmer-compiler-llvm = { version = "1.0.0-alpha.1", path = "lib/compiler-llvm", optional = true }
#wasmer-emscripten = { version = "1.0.0-alpha.1", path = "lib/emscripten", optional = true }
wasmer-emscripten = { version = "1.0.0-alpha.1", path = "lib/emscripten", optional = true }
wasmer-engine = { version = "1.0.0-alpha.1", path = "lib/engine" }
wasmer-engine-jit = { version = "1.0.0-alpha.1", path = "lib/engine-jit", optional = true }
wasmer-engine-native = { version = "1.0.0-alpha.1", path = "lib/engine-native", optional = true }
@@ -71,7 +71,15 @@ wasmer-engine-dummy = { path = "tests/lib/engine-dummy" }
[features]
# Don't add the compiler features in default, please add them on the Makefile
# since we might want to autoconfigure them depending on the availability on the host.
default = ["wat", "wast", "wasi", "cache", "jit", "native"]
default = [
"wat",
"wast",
"jit",
"native",
"cache",
"wasi",
"emscripten",
]
engine = []
jit = [
"wasmer-engine-jit",
@@ -84,9 +92,12 @@ native = [
cache = ["wasmer-cache"]
wast = ["wasmer-wast"]
wasi = ["wasmer-wasi"]
#emscripten = ["wasmer-emscripten"]
emscripten = ["wasmer-emscripten"]
wat = ["wasmer/wat"]
compiler = ["wasmer-engine-jit/compiler", "wasmer-engine-native/compiler"]
compiler = [
"wasmer-engine-jit/compiler",
"wasmer-engine-native/compiler"
]
experimental-io-devices = [
"wasmer-wasi-experimental-io-devices",
"wasi"

View File

@@ -81,15 +81,15 @@ build-capi: build-capi-cranelift
build-capi-singlepass:
cargo build --manifest-path lib/c-api/Cargo.toml --release \
--no-default-features --features singlepass-backend,wasi
--no-default-features --features jit,singlepass,wasi
build-capi-cranelift:
cargo build --manifest-path lib/c-api/Cargo.toml --release \
--no-default-features --features cranelift-backend,wasi
--no-default-features --features jit,cranelift,wasi
build-capi-llvm:
cargo build --manifest-path lib/c-api/Cargo.toml --release \
--no-default-features --features llvm-backend,wasi
--no-default-features --features jit,llvm,wasi
###########
@@ -114,15 +114,15 @@ test-packages:
test-capi-singlepass: build-capi-singlepass
cargo test --manifest-path lib/c-api/Cargo.toml --release \
--no-default-features --features singlepass,wasi
--no-default-features --features jit,singlepass,wasi -- --nocapture
test-capi-cranelift: build-capi-cranelift
cargo test --manifest-path lib/c-api/Cargo.toml --release \
--no-default-features --features cranelift,wasi -- --nocapture --test-threads=1
--no-default-features --features jit,cranelift,wasi -- --nocapture
test-capi-llvm: build-capi-llvm
cargo test --manifest-path lib/c-api/Cargo.toml --release \
--no-default-features --features llvm,wasi
--no-default-features --features jit,llvm,wasi -- --nocapture
test-capi: test-capi-singlepass test-capi-cranelift test-capi-llvm test-capi-emscripten
@@ -163,12 +163,12 @@ ifeq ($(OS), Windows_NT)
else
ifeq ($(UNAME_S), Darwin)
cp target/release/libwasmer_c_api.dylib package/lib/libwasmer.dylib
cp target/release/libwasmer_c_api.a package/lib/libwasmer.a
# cp target/release/libwasmer_c_api.a package/lib/libwasmer.a
# Fix the rpath for the dylib
install_name_tool -id "@rpath/libwasmer.dylib" package/lib/libwasmer.dylib
else
cp target/release/libwasmer_c_api.so package/lib/libwasmer.so
cp target/release/libwasmer_c_api.a package/lib/libwasmer.a
# cp target/release/libwasmer_c_api.a package/lib/libwasmer.a
endif
endif

View File

@@ -9,7 +9,7 @@ use std::cmp::max;
use wasm_common::{HostFunction, WasmTypeList, WithEnv, WithoutEnv};
use wasmer_runtime::{
wasmer_call_trampoline, Export, ExportFunction, VMCallerCheckedAnyfunc, VMContext,
VMDynamicFunctionImportContext, VMFunctionBody, VMFunctionKind, VMTrampoline,
VMDynamicFunctionContext, VMFunctionBody, VMFunctionKind, VMTrampoline,
};
/// A function defined in the Wasm module
@@ -19,13 +19,20 @@ pub struct WasmFunctionDefinition {
pub(crate) trampoline: VMTrampoline,
}
/// A function defined in the Host
#[derive(Clone, PartialEq)]
pub struct HostFunctionDefinition {
/// If the host function has a custom environment attached
pub(crate) has_env: bool,
}
/// The inner helper
#[derive(Clone, PartialEq)]
pub enum FunctionDefinition {
/// A function defined in the Wasm side
Wasm(WasmFunctionDefinition),
/// A function defined in the Host side
Host,
Host(HostFunctionDefinition),
}
/// A WebAssembly `function`.
@@ -57,7 +64,7 @@ impl Function {
Self {
store: store.clone(),
owned_by_store: true,
definition: FunctionDefinition::Host,
definition: FunctionDefinition::Host(HostFunctionDefinition { has_env: false }),
exported: ExportFunction {
address,
vmctx,
@@ -72,17 +79,19 @@ impl Function {
where
F: Fn(&[Val]) -> Result<Vec<Val>, RuntimeError> + 'static,
{
let dynamic_ctx =
VMDynamicFunctionImportContext::from_context(VMDynamicFunctionWithoutEnv {
let dynamic_ctx = VMDynamicFunctionContext::from_context(VMDynamicFunctionWithoutEnv {
func: Box::new(func),
function_type: ty.clone(),
});
// We don't yet have the address with the Wasm ABI signature.
// The engine linker will replace the address with one pointing to a
// generated dynamic trampoline.
let address = std::ptr::null() as *const VMFunctionBody;
let vmctx = Box::into_raw(Box::new(dynamic_ctx)) as *mut VMContext;
Self {
store: store.clone(),
owned_by_store: true,
definition: FunctionDefinition::Host,
definition: FunctionDefinition::Host(HostFunctionDefinition { has_env: false }),
exported: ExportFunction {
address,
kind: VMFunctionKind::Dynamic,
@@ -98,17 +107,20 @@ impl Function {
F: Fn(&mut Env, &[Val]) -> Result<Vec<Val>, RuntimeError> + 'static,
Env: Sized,
{
let dynamic_ctx = VMDynamicFunctionImportContext::from_context(VMDynamicFunctionWithEnv {
let dynamic_ctx = VMDynamicFunctionContext::from_context(VMDynamicFunctionWithEnv {
env,
func: Box::new(func),
function_type: ty.clone(),
});
// We don't yet have the address with the Wasm ABI signature.
// The engine linker will replace the address with one pointing to a
// generated dynamic trampoline.
let address = std::ptr::null() as *const VMFunctionBody;
let vmctx = Box::into_raw(Box::new(dynamic_ctx)) as *mut VMContext;
Self {
store: store.clone(),
owned_by_store: true,
definition: FunctionDefinition::Host,
definition: FunctionDefinition::Host(HostFunctionDefinition { has_env: true }),
exported: ExportFunction {
address,
kind: VMFunctionKind::Dynamic,
@@ -142,7 +154,7 @@ impl Function {
Self {
store: store.clone(),
owned_by_store: true,
definition: FunctionDefinition::Host,
definition: FunctionDefinition::Host(HostFunctionDefinition { has_env: true }),
exported: ExportFunction {
address,
kind: VMFunctionKind::Static,
@@ -330,12 +342,12 @@ impl std::fmt::Debug for Function {
}
/// This trait is one that all dynamic functions must fulfill.
trait VMDynamicFunction {
pub(crate) trait VMDynamicFunction {
fn call(&self, args: &[Val]) -> Result<Vec<Val>, RuntimeError>;
fn function_type(&self) -> &FunctionType;
}
struct VMDynamicFunctionWithoutEnv {
pub(crate) struct VMDynamicFunctionWithoutEnv {
#[allow(clippy::type_complexity)]
func: Box<dyn Fn(&[Val]) -> Result<Vec<Val>, RuntimeError> + 'static>,
function_type: FunctionType,
@@ -350,7 +362,7 @@ impl VMDynamicFunction for VMDynamicFunctionWithoutEnv {
}
}
struct VMDynamicFunctionWithEnv<Env>
pub(crate) struct VMDynamicFunctionWithEnv<Env>
where
Env: Sized,
{
@@ -372,13 +384,13 @@ where
}
}
trait VMDynamicFunctionImportCall<T: VMDynamicFunction> {
trait VMDynamicFunctionCall<T: VMDynamicFunction> {
fn from_context(ctx: T) -> Self;
fn address_ptr() -> *const VMFunctionBody;
unsafe fn func_wrapper(&self, values_vec: *mut i128);
}
impl<T: VMDynamicFunction> VMDynamicFunctionImportCall<T> for VMDynamicFunctionImportContext<T> {
impl<T: VMDynamicFunction> VMDynamicFunctionCall<T> for VMDynamicFunctionContext<T> {
fn from_context(ctx: T) -> Self {
Self {
address: Self::address_ptr(),
@@ -393,8 +405,8 @@ impl<T: VMDynamicFunction> VMDynamicFunctionImportCall<T> for VMDynamicFunctionI
// This function wraps our func, to make it compatible with the
// reverse trampoline signature
unsafe fn func_wrapper(
// Note: we use the trick that the first param to this function is the `VMDynamicFunctionImportContext`
// itself, so rather than doing `dynamic_ctx: &VMDynamicFunctionImportContext<T>`, we simplify it a bit
// Note: we use the trick that the first param to this function is the `VMDynamicFunctionContext`
// itself, so rather than doing `dynamic_ctx: &VMDynamicFunctionContext<T>`, we simplify it a bit
&self,
values_vec: *mut i128,
) {

View File

@@ -1,7 +1,7 @@
use crate::exports::{ExportError, Exportable};
use crate::externals::Extern;
use crate::store::Store;
use crate::types::{Val, ValAnyFunc};
use crate::types::{Val, ValFuncRef};
use crate::RuntimeError;
use crate::TableType;
use wasmer_runtime::{Export, ExportTable, Table as RuntimeTable, VMCallerCheckedAnyfunc};
@@ -70,7 +70,7 @@ impl Table {
/// Retrieves an element of the table at the provided `index`.
pub fn get(&self, index: u32) -> Option<Val> {
let item = self.table().get(index)?;
Some(ValAnyFunc::from_checked_anyfunc(item, &self.store))
Some(ValFuncRef::from_checked_anyfunc(item, &self.store))
}
/// Sets an element `val` in the Table at the provided `index`.

View File

@@ -27,14 +27,17 @@ pub use crate::ptr::{Array, Item, WasmPtr};
pub use crate::store::{Store, StoreObject};
pub use crate::tunables::Tunables;
pub use crate::types::{
AnyRef, ExportType, ExternType, FunctionType, GlobalType, HostInfo, HostRef, ImportType,
ExportType, ExternRef, ExternType, FunctionType, GlobalType, HostInfo, HostRef, ImportType,
MemoryType, Mutability, TableType, Val, ValType,
};
pub use crate::types::{Val as Value, ValType as Type};
pub use crate::utils::is_wasm;
pub use target_lexicon::{Architecture, CallingConvention, OperatingSystem, Triple, HOST};
pub use wasm_common::{Bytes, Pages, ValueType, WasmExternType, WasmTypeList};
pub use wasm_common::{
Bytes, GlobalInit, Pages, ValueType, WasmExternType, WasmTypeList, WASM_MAX_PAGES,
WASM_MIN_PAGES, WASM_PAGE_SIZE,
};
#[cfg(feature = "compiler")]
pub use wasmer_compiler::CompilerConfig;
pub use wasmer_compiler::{CpuFeature, Features, Target};

View File

@@ -1,20 +1,26 @@
// Native Funcs
// use wasmer_runtime::ExportFunction;
//! Native Functions.
//!
//! This module creates the helper `NativeFunc` that let us call WebAssembly
//! functions with the native ABI, that is:
//!
//! ```ignore
//! let add_one = instance.exports.get_function("func_name")?;
//! let add_one_native: NativeFunc<i32, i32> = add_one.native().unwrap();
//! ```
use std::marker::PhantomData;
use crate::externals::function::{FunctionDefinition, WasmFunctionDefinition};
use crate::externals::function::{
FunctionDefinition, HostFunctionDefinition, VMDynamicFunction, VMDynamicFunctionWithEnv,
VMDynamicFunctionWithoutEnv, WasmFunctionDefinition,
};
use crate::{Function, FunctionType, RuntimeError, Store};
use std::panic::{catch_unwind, AssertUnwindSafe};
use wasm_common::{NativeWasmType, WasmExternType, WasmTypeList};
use wasmer_runtime::{
wasmer_call_trampoline, ExportFunction, VMContext, VMFunctionBody, VMFunctionKind,
ExportFunction, VMContext, VMDynamicFunctionContext, VMFunctionBody, VMFunctionKind,
};
#[derive(Clone)]
pub struct UnprovidedArgs;
#[derive(Clone)]
pub struct UnprovidedRets;
pub struct NativeFunc<'a, Args = UnprovidedArgs, Rets = UnprovidedRets> {
pub struct NativeFunc<'a, Args = (), Rets = ()> {
definition: FunctionDefinition,
store: Store,
address: *const VMFunctionBody,
@@ -86,16 +92,40 @@ where
}
}
/// Marker trait to make Rust happy: required to allow `NativeFunc<i32>` work.
/// without this trait, the singleton case looks like a generic impl in the macro
/// expansion and Rust will not compile this code because it's a potential duplicate
/// with all the existing tuples for which this is also being implemented.
pub unsafe trait WasmExternTypeInner: Copy + WasmExternType
where
Self: Sized,
{
}
unsafe impl WasmExternTypeInner for i8 {}
unsafe impl WasmExternTypeInner for u8 {}
unsafe impl WasmExternTypeInner for i16 {}
unsafe impl WasmExternTypeInner for u16 {}
unsafe impl WasmExternTypeInner for i32 {}
unsafe impl WasmExternTypeInner for u32 {}
unsafe impl WasmExternTypeInner for i64 {}
unsafe impl WasmExternTypeInner for u64 {}
unsafe impl WasmExternTypeInner for f32 {}
unsafe impl WasmExternTypeInner for f64 {}
macro_rules! impl_native_traits {
( $( $x:ident ),* ) => {
#[allow(unused_parens, non_snake_case)]
impl<'a $( , $x )*, Rets> NativeFunc<'a, ( $( $x, )* ), Rets>
impl<'a $( , $x )*, Rets> NativeFunc<'a, ( $( $x ),* ), Rets>
where
$( $x: WasmExternType, )*
$( $x: WasmExternType + WasmExternTypeInner, )*
Rets: WasmTypeList,
{
/// Call the typed func and return results.
pub fn call(&self, $( $x: $x, )* ) -> Result<Rets, RuntimeError> {
match self.definition {
FunctionDefinition::Wasm(WasmFunctionDefinition {
trampoline
}) => {
// TODO: when `const fn` related features mature more, we can declare a single array
// of the correct size here.
let mut params_list = [ $( $x.to_native().to_binary() ),* ];
@@ -112,13 +142,8 @@ macro_rules! impl_native_traits {
}
rets_list.as_mut()
};
match self.definition {
FunctionDefinition::Wasm(WasmFunctionDefinition {
trampoline
}) => {
unsafe {
wasmer_call_trampoline(
wasmer_runtime::wasmer_call_trampoline(
self.vmctx,
trampoline,
self.address,
@@ -137,18 +162,52 @@ macro_rules! impl_native_traits {
num_rets);
}
}
return Ok(Rets::from_array(rets_list_array));
}
FunctionDefinition::Host => {
if self.arg_kind == VMFunctionKind::Static {
unsafe {
let f = std::mem::transmute::<_, unsafe fn( *mut VMContext, $( $x, )*) -> Rets>(self.address);
Ok(Rets::from_array(rets_list_array))
// TODO: When the Host ABI and Wasm ABI are the same, we could do this instead:
// but we can't currently detect whether that's safe.
//
// let results = unsafe {
// wasmer_runtime::catch_traps_with_result(self.vmctx, || {
// let f = std::mem::transmute::<_, unsafe extern "C" fn( *mut VMContext, $( $x, )*) -> Rets::CStruct>(self.address);
// // We always pass the vmctx
// f( self.vmctx, $( $x, )* )
// }).map_err(RuntimeError::from_trap)?
// };
// Ok(Rets::from_c_struct(results))
let results = f( self.vmctx, $( $x, )* );
return Ok(results);
}
FunctionDefinition::Host(HostFunctionDefinition {
has_env
}) => {
match self.arg_kind {
VMFunctionKind::Static => {
let results = catch_unwind(AssertUnwindSafe(|| unsafe {
let f = std::mem::transmute::<_, unsafe extern "C" fn( *mut VMContext, $( $x, )*) -> Rets::CStruct>(self.address);
// We always pass the vmctx
f( self.vmctx, $( $x, )* )
})).map_err(|e| RuntimeError::new(format!("{:?}", e)))?;
Ok(Rets::from_c_struct(results))
},
VMFunctionKind::Dynamic => {
let params_list = [ $( $x.to_native().to_value() ),* ];
let results = if !has_env {
type VMContextWithoutEnv = VMDynamicFunctionContext<VMDynamicFunctionWithoutEnv>;
let ctx = self.vmctx as *mut VMContextWithoutEnv;
unsafe { (*ctx).ctx.call(&params_list)? }
} else {
todo!("dynamic host functions not yet implemented")
type VMContextWithEnv = VMDynamicFunctionContext<VMDynamicFunctionWithEnv<std::ffi::c_void>>;
let ctx = self.vmctx as *mut VMContextWithEnv;
unsafe { (*ctx).ctx.call(&params_list)? }
};
let mut rets_list_array = Rets::empty_array();
let mut_rets = rets_list_array.as_mut() as *mut [i128] as *mut i128;
for (i, ret) in results.iter().enumerate() {
unsafe {
ret.write_value_to(mut_rets.add(i));
}
}
Ok(Rets::from_array(rets_list_array))
}
}
},
}
@@ -158,7 +217,6 @@ macro_rules! impl_native_traits {
};
}
// impl_native_traits!();
impl_native_traits!();
impl_native_traits!(A1);
impl_native_traits!(A1, A2);
@@ -186,5 +244,3 @@ impl_native_traits!(
impl_native_traits!(
A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20
);
// impl_native_traits!(A1, A2, A3);

View File

@@ -1,3 +1,9 @@
//! Ordered Resolvers are a custom kind of [`Resolver`] that retrieves
//! `Export`s based on the index of the import, and not the module or name.
//!
//! This resolver is used in the Wasm-C-API as the imports are provided
//! by index and not by module and name.
use std::iter::FromIterator;
use wasmer_engine::Resolver;
@@ -5,8 +11,11 @@ use crate::exports::Exportable;
use crate::Extern;
use wasmer_runtime::Export;
/// An `OrderedResolver` stores all the `externs` provided to an Instance
/// in a Vec, so we can retrieve them later based on index.
#[derive(Clone)]
pub struct OrderedResolver {
/// The externs to be resolved by inddex
externs: Vec<Extern>,
}
impl Resolver for OrderedResolver {

View File

@@ -4,7 +4,7 @@ use crate::RuntimeError;
use std::ptr;
use wasm_common::Value;
pub use wasm_common::{
AnyRef, ExportType, ExternType, FunctionType, GlobalType, HostInfo, HostRef, ImportType,
ExportType, ExternRef, ExternType, FunctionType, GlobalType, HostInfo, HostRef, ImportType,
MemoryType, Mutability, TableType, Type as ValType,
};
@@ -14,8 +14,8 @@ impl StoreObject for Val {
fn comes_from_same_store(&self, store: &Store) -> bool {
match self {
Val::FuncRef(f) => Store::same(store, f.store()),
Val::AnyRef(AnyRef::Ref(_)) | Val::AnyRef(AnyRef::Other(_)) => false,
Val::AnyRef(AnyRef::Null) => true,
Val::ExternRef(ExternRef::Ref(_)) | Val::ExternRef(ExternRef::Other(_)) => false,
Val::ExternRef(ExternRef::Null) => true,
Val::I32(_) | Val::I64(_) | Val::F32(_) | Val::F64(_) | Val::V128(_) => true,
}
}
@@ -28,8 +28,8 @@ impl From<Function> for Val {
}
/// It provides useful functions for converting back and forth
/// from [`Val`] into `AnyFunc`.
pub trait ValAnyFunc {
/// from [`Val`] into `FuncRef`.
pub trait ValFuncRef {
fn into_checked_anyfunc(
&self,
store: &Store,
@@ -38,7 +38,7 @@ pub trait ValAnyFunc {
fn from_checked_anyfunc(item: wasmer_runtime::VMCallerCheckedAnyfunc, store: &Store) -> Self;
}
impl ValAnyFunc for Val {
impl ValFuncRef for Val {
fn into_checked_anyfunc(
&self,
store: &Store,
@@ -47,7 +47,7 @@ impl ValAnyFunc for Val {
return Err(RuntimeError::new("cross-`Store` values are not supported"));
}
Ok(match self {
Val::AnyRef(AnyRef::Null) => wasmer_runtime::VMCallerCheckedAnyfunc {
Val::ExternRef(ExternRef::Null) => wasmer_runtime::VMCallerCheckedAnyfunc {
func_ptr: ptr::null(),
type_index: wasmer_runtime::VMSharedSignatureIndex::default(),
vmctx: ptr::null_mut(),
@@ -59,7 +59,7 @@ impl ValAnyFunc for Val {
fn from_checked_anyfunc(item: wasmer_runtime::VMCallerCheckedAnyfunc, store: &Store) -> Val {
if item.type_index == wasmer_runtime::VMSharedSignatureIndex::default() {
return Val::AnyRef(AnyRef::Null);
return Val::ExternRef(ExternRef::Null);
}
let signature = store
.engine()

View File

@@ -72,11 +72,11 @@ fn table_new() -> Result<()> {
// Anyrefs not yet supported
// let table_type = TableType {
// ty: Type::AnyRef,
// ty: Type::ExternRef,
// minimum: 0,
// maximum: None,
// };
// let table = Table::new(&store, table_type, Value::AnyRef(AnyRef::Null))?;
// let table = Table::new(&store, table_type, Value::ExternRef(ExternRef::Null))?;
// assert_eq!(*table.ty(), table_type);
Ok(())

View File

@@ -15,6 +15,17 @@ readme = "README.md"
crate-type = ["cdylib", "staticlib"]
[dependencies]
wasmer = { version = "1.0.0-alpha.1", path = "../api", default-features = false }
wasmer-compiler = { version = "1.0.0-alpha.1", path = "../compiler" }
wasmer-compiler-cranelift = { version = "1.0.0-alpha.1", path = "../compiler-cranelift", optional = true }
wasmer-compiler-singlepass = { version = "1.0.0-alpha.1", path = "../compiler-singlepass", optional = true }
wasmer-compiler-llvm = { version = "1.0.0-alpha.1", path = "../compiler-llvm", optional = true }
wasmer-emscripten = { version = "1.0.0-alpha.1", path = "../emscripten", optional = true }
wasmer-engine = { version = "1.0.0-alpha.1", path = "../engine" }
wasmer-engine-jit = { version = "1.0.0-alpha.1", path = "../engine-jit", optional = true }
wasmer-engine-native = { version = "1.0.0-alpha.1", path = "../engine-native", optional = true }
wasmer-wasi = { version = "1.0.0-alpha.1", path = "../wasi", optional = true }
wasm-common = { version = "1.0.0-alpha.1", path = "../wasm-common" }
cfg-if = "0.1"
lazy_static = "1"
libc = { version = "0.2", default-features = false }
@@ -25,37 +36,42 @@ paste = "0.1"
# Commented out for now until we can find a solution to the exported function problem
# wasmer-wasm-c-api = { version = "1.0.0-alpha.1", path = "crates/wasm-c-api" }
[dependencies.wasmer]
default-features = false
features = ["compiler", "engine", "jit"]
path = "../api"
version = "1.0.0-alpha.1"
[dependencies.wasm-common]
default-features = false
path = "../wasm-common"
version = "1.0.0-alpha.1"
[dependencies.wasmer-wasi]
default-features = false
path = "../wasi"
version = "1.0.0-alpha.1"
optional = true
#[dependencies.wasmer-emscripten]
#path = "../emscripten"
#version = "1.0.0-alpha.1"
#optional = true
[features]
default = ["cranelift-backend", "wasi"]
singlepass = ["wasmer/singlepass"]
cranelift = ["wasmer/cranelift"]
llvm = ["wasmer/llvm"]
default = [
"cranelift",
"wasi",
]
wasi = ["wasmer-wasi"]
engine = []
jit = [
"wasmer-engine-jit",
"engine",
]
native = [
"wasmer-engine-native",
"engine",
]
compiler = [
"wasmer-engine-jit/compiler",
"wasmer-engine-native/compiler"
]
singlepass = [
"wasmer-compiler-singlepass",
"compiler",
]
cranelift = [
"wasmer-compiler-cranelift",
"compiler",
]
llvm = [
"wasmer-compiler-llvm",
"compiler",
]
#emscripten = ["wasmer-emscripten"]
# used to avoid generating standard Wasm C API types in our header files
ignore-wasm-c-api = []
# This is for compatibility for old usage
singlepass-backend = ["singlepass"]
cranelift-backend = ["cranelift"]

View File

@@ -514,7 +514,7 @@ pub unsafe extern "C" fn wasmer_export_func_call(
value: wasmer_value { F64: x },
},
Val::V128(_) => unimplemented!("returning V128 type"),
Val::AnyRef(_) => unimplemented!("returning AnyRef type"),
Val::ExternRef(_) => unimplemented!("returning ExternRef type"),
Val::FuncRef(_) => unimplemented!("returning FuncRef type"),
};
results[0] = ret;

View File

@@ -370,7 +370,7 @@ pub unsafe extern "C" fn wasmer_instance_call(
value: wasmer_value { F64: x },
},
Val::V128(_) => unimplemented!("calling function with V128 parameter"),
Val::AnyRef(_) => unimplemented!("returning AnyRef type"),
Val::ExternRef(_) => unimplemented!("returning ExternRef type"),
Val::FuncRef(_) => unimplemented!("returning FuncRef type"),
};
results[0] = ret;

View File

@@ -94,6 +94,7 @@
unreachable_patterns
)]
#[allow(unused_imports)]
#[macro_use]
extern crate cfg_if;
#[macro_use]
@@ -193,7 +194,8 @@ pub(crate) unsafe fn get_slice_checked<'a, T>(ptr: *const T, len: usize) -> &'a
}
lazy_static! {
pub(crate) static ref GLOBAL_STORE: wasmer::Store = wasmer::Store::default();
pub(crate) static ref GLOBAL_STORE: wasmer::Store =
wasmer::Store::new(crate::wasm_c_api::wasm_engine_new().inner);
}
pub(crate) fn get_global_store() -> &'static wasmer::Store {

View File

@@ -2,7 +2,7 @@
use crate::{error::update_last_error, wasmer_limits_t, wasmer_result_t};
use std::ptr::NonNull;
use wasmer::{AnyRef, Table, TableType, Val, ValType};
use wasmer::{ExternRef, Table, TableType, Val, ValType};
#[repr(C)]
#[derive(Clone)]
@@ -16,8 +16,8 @@ fn get_default_table_value(table_type: ValType) -> Val {
ValType::F32 => Val::F32(0.),
ValType::F64 => Val::F64(0.),
ValType::V128 => Val::V128(0),
ValType::AnyRef => Val::AnyRef(AnyRef::null()),
ValType::FuncRef => Val::AnyRef(AnyRef::null()),
ValType::ExternRef => Val::ExternRef(ExternRef::null()),
ValType::FuncRef => Val::ExternRef(ExternRef::null()),
}
}

View File

@@ -116,8 +116,8 @@ impl From<Val> for wasmer_value_t {
value: wasmer_value { F64: x },
},
Val::V128(_) => unimplemented!("V128 not supported in C API"),
Val::AnyRef(_) => unimplemented!("AnyRef not supported in C API"),
Val::FuncRef(_) => unimplemented!("AnyFunc not supported in C API"),
Val::ExternRef(_) => unimplemented!("ExternRef not supported in C API"),
Val::FuncRef(_) => unimplemented!("FuncRef not supported in C API"),
}
}
}
@@ -131,7 +131,7 @@ impl From<ValType> for wasmer_value_tag {
ValType::F32 => wasmer_value_tag::WASM_F32,
ValType::F64 => wasmer_value_tag::WASM_F64,
ValType::V128 => unreachable!("V128 not supported in C API"),
ValType::AnyRef => unimplemented!("AnyRef not supported in C API"),
ValType::ExternRef => unimplemented!("ExternRef not supported in C API"),
ValType::FuncRef => unimplemented!("FuncRef not supported in C API"),
}
}
@@ -158,7 +158,7 @@ impl From<&ValType> for wasmer_value_tag {
ValType::F32 => wasmer_value_tag::WASM_F32,
ValType::F64 => wasmer_value_tag::WASM_F64,
ValType::V128 => unimplemented!("V128 not supported in C API"),
ValType::AnyRef => unimplemented!("AnyRef not supported in C API"),
ValType::ExternRef => unimplemented!("ExternRef not supported in C API"),
ValType::FuncRef => unimplemented!("FuncRef not supported in C API"),
}
}

View File

@@ -7,11 +7,15 @@ use std::ptr::{self, NonNull};
use std::slice;
use std::sync::Arc;
#[cfg(feature = "engine")]
use wasmer::Tunables;
use wasmer::{
CompilerConfig, Engine, ExportType, Extern, ExternType, Function, FunctionType, Global,
GlobalType, Instance, JITEngine, Memory, MemoryType, Module, Mutability, OrderedResolver,
Pages, RuntimeError, Store, Table, TableType, Tunables, Val, ValType,
Engine, ExportType, Extern, ExternType, Function, FunctionType, Global, GlobalType, Instance,
Memory, MemoryType, Module, Mutability, OrderedResolver, Pages, RuntimeError, Store, Table,
TableType, Val, ValType,
};
#[cfg(feature = "jit")]
use wasmer_engine_jit::JITEngine;
use crate::error::update_last_error;
@@ -44,29 +48,50 @@ pub extern "C" fn wasm_config_new() -> *mut wasm_config_t {
#[repr(C)]
pub struct wasm_engine_t {
inner: Arc<dyn Engine + Send + Sync>,
pub(crate) inner: Arc<dyn Engine + Send + Sync>,
}
fn get_default_compiler_config() -> Box<dyn CompilerConfig> {
cfg_if! {
if #[cfg(all(feature = "jit", feature = "compiler"))] {
// Compiler JIT
use wasmer_compiler::CompilerConfig;
fn get_default_compiler_config() -> Box<dyn CompilerConfig> {
cfg_if! {
if #[cfg(feature = "cranelift")] {
Box::new(wasmer::CraneliftConfig::default())
Box::new(wasmer_compiler_cranelift::CraneliftConfig::default())
} else if #[cfg(feature = "llvm")] {
Box::new(wasmer::LLVMConfig::default())
Box::new(wasmer_compiler_llvm::LLVMConfig::default())
} else if #[cfg(feature = "singlepass")] {
Box::new(wasmer::SinglepassConfig::default())
Box::new(wasmer_compiler_singlepass::SinglepassConfig::default())
} else {
compile_error!("Please enable one of the compiler backends")
}
}
}
}
#[no_mangle]
pub extern "C" fn wasm_engine_new() -> Box<wasm_engine_t> {
#[no_mangle]
pub extern "C" fn wasm_engine_new() -> Box<wasm_engine_t> {
let compiler_config: Box<dyn CompilerConfig> = get_default_compiler_config();
let tunables = Tunables::default();
let engine: Arc<dyn Engine + Send + Sync> = Arc::new(JITEngine::new(compiler_config, tunables));
Box::new(wasm_engine_t { inner: engine })
}
}
else if #[cfg(feature = "jit")] {
// Headless JIT
#[no_mangle]
pub extern "C" fn wasm_engine_new() -> Box<wasm_engine_t> {
let tunables = Tunables::default();
let engine: Arc<dyn Engine + Send + Sync> = Arc::new(JITEngine::headless(tunables));
Box::new(wasm_engine_t { inner: engine })
}
}
else {
#[no_mangle]
pub extern "C" fn wasm_engine_new() -> Box<wasm_engine_t> {
unimplemented!("The JITEngine is not attached");
}
}
}
#[no_mangle]
@@ -467,7 +492,7 @@ impl From<wasm_valkind_enum> for ValType {
WASM_I64 => ValType::I64,
WASM_F32 => ValType::F32,
WASM_F64 => ValType::F64,
WASM_ANYREF => ValType::AnyRef,
WASM_ANYREF => ValType::ExternRef,
WASM_FUNCREF => ValType::FuncRef,
}
}
@@ -507,7 +532,7 @@ impl From<ValType> for wasm_valkind_enum {
ValType::F32 => Self::WASM_F32,
ValType::F64 => Self::WASM_F64,
ValType::V128 => todo!("no v128 type in Wasm C API yet!"),
ValType::AnyRef => Self::WASM_ANYREF,
ValType::ExternRef => Self::WASM_ANYREF,
ValType::FuncRef => Self::WASM_FUNCREF,
}
}
@@ -966,7 +991,7 @@ pub unsafe extern "C" fn wasm_table_grow(
) -> bool {
// TODO: maybe need to look at result to return `true`; also maybe report error here
//wasm_table.inner.grow(delta, init).is_ok()
todo!("Blocked on transforming AnyRef into a val type")
todo!("Blocked on transforming ExternRef into a val type")
}
macro_rules! wasm_declare_own {
@@ -1118,7 +1143,7 @@ macro_rules! wasm_declare_ref_base {
pub type wasm_byte_t = u8;
wasm_declare_vec!(byte);
// opaque type over `AnyRef`?
// opaque type over `ExternRef`?
#[allow(non_camel_case_types)]
pub struct wasm_ref_t;

View File

@@ -31,6 +31,7 @@ use wasmer::{DeserializeError, Module, SerializeError, Store};
/// ```
pub struct FileSystemCache {
path: PathBuf,
ext: Option<String>,
}
impl FileSystemCache {
@@ -41,7 +42,7 @@ impl FileSystemCache {
let metadata = path.metadata()?;
if metadata.is_dir() {
if !metadata.permissions().readonly() {
Ok(Self { path })
Ok(Self { path, ext: None })
} else {
// This directory is readonly.
Err(io::Error::new(
@@ -62,9 +63,17 @@ impl FileSystemCache {
} else {
// Create the directory and any parent directories if they don't yet exist.
create_dir_all(&path)?;
Ok(Self { path })
Ok(Self { path, ext: None })
}
}
/// Set the extension for this cached file.
///
/// This is needed for loading native files from Windows, as otherwise
/// loading the library will fail (it requires a `.dll` extension)
pub fn set_cache_extension(&mut self, ext: Option<impl ToString>) {
self.ext = ext.map(|ext| ext.to_string());
}
}
impl Cache for FileSystemCache {
@@ -72,20 +81,25 @@ impl Cache for FileSystemCache {
type SerializeError = SerializeError;
unsafe fn load(&self, store: &Store, key: WasmHash) -> Result<Module, Self::DeserializeError> {
let filename = key.to_string();
let mut new_path_buf = self.path.clone();
new_path_buf.push(filename);
Module::deserialize_from_file(&store, new_path_buf)
let filename = if let Some(ref ext) = self.ext {
format!("{}.{}", key.to_string(), ext)
} else {
key.to_string()
};
let path = self.path.join(filename);
Module::deserialize_from_file(&store, path)
}
fn store(&mut self, key: WasmHash, module: &Module) -> Result<(), Self::SerializeError> {
let filename = key.to_string();
let mut new_path_buf = self.path.clone();
let filename = if let Some(ref ext) = self.ext {
format!("{}.{}", key.to_string(), ext)
} else {
key.to_string()
};
let path = self.path.join(filename);
let mut file = File::create(path)?;
let buffer = module.serialize()?;
new_path_buf.push(filename);
let mut file = File::create(new_path_buf)?;
file.write_all(&buffer)?;
Ok(())

View File

@@ -15,17 +15,18 @@ edition = "2018"
wasmer-compiler = { path = "../compiler", version = "1.0.0-alpha.1", features = ["translator"], default-features = false }
wasmer-runtime = { path = "../runtime", version = "1.0.0-alpha.1" }
wasm-common = { path = "../wasm-common", version = "1.0.0-alpha.1", default-features = false }
cranelift-codegen = { version = "0.62", default-features = false }
cranelift-frontend = { version = "0.62", default-features = false }
cranelift-codegen = { version = "0.65", default-features = false }
cranelift-frontend = { version = "0.65", default-features = false }
tracing = "0.1"
hashbrown = { version = "0.7", optional = true }
rayon = "1.3"
serde = { version = "1.0", features = ["derive"] }
more-asserts = "0.2"
gimli = { version = "0.21", optional = true }
[dev-dependencies]
target-lexicon = { version = "0.10", default-features = false }
cranelift-codegen = { version = "0.62", features = ["enable-serde", "all-arch"] }
cranelift-codegen = { version = "0.65", features = ["enable-serde", "all-arch"] }
lazy_static = "1.4"
[badges]
@@ -33,7 +34,7 @@ maintenance = { status = "actively-developed" }
[features]
default = ["std", "enable-serde", "unwind"]
unwind = ["cranelift-codegen/unwind"]
unwind = ["cranelift-codegen/unwind", "gimli"]
enable-serde = ["wasmer-compiler/enable-serde", "cranelift-codegen/enable-serde", "wasm-common/enable-serde"]
std = ["cranelift-codegen/std", "cranelift-frontend/std", "wasmer-compiler/std", "wasm-common/std"]
core = ["hashbrown", "cranelift-codegen/core", "cranelift-frontend/core"]

View File

@@ -3,6 +3,10 @@
This is the `wasmer-compiler-cranelift` crate, which contains a
compiler implementation based on Cranelift.
We recommend using this compiler only for development proposes.
For production we recommend using `wasmer-compiler-llvm` as it offers
a much better runtime speed (50% faster on average).
### Acknowledgments
This project borrowed some of the function lowering from [cranelift-wasm](https://crates.io/crates/cranelift-wasm).

View File

@@ -2,29 +2,34 @@
use crate::address_map::get_function_address_map;
use crate::config::CraneliftConfig;
#[cfg(feature = "unwind")]
use crate::dwarf::WriterRelocate;
use crate::func_environ::{get_func_name, FuncEnvironment};
use crate::sink::{RelocSink, TrapSink};
use crate::trampoline::{
make_trampoline_dynamic_function, make_trampoline_function_call, FunctionBuilderContext,
};
use crate::translator::{
compiled_function_unwind_info, signature_to_cranelift_ir, transform_jump_table, FuncTranslator,
compiled_function_unwind_info, signature_to_cranelift_ir, transform_jump_table,
CraneliftUnwindInfo, FuncTranslator,
};
use cranelift_codegen::ir;
use cranelift_codegen::print_errors::pretty_error;
use cranelift_codegen::{binemit, isa, Context};
#[cfg(feature = "unwind")]
use gimli::write::{Address, EhFrame, FrameTable};
use rayon::prelude::{IntoParallelRefIterator, ParallelIterator};
use wasm_common::entity::PrimaryMap;
use wasm_common::entity::{EntityRef, PrimaryMap};
use wasm_common::{
Features, FunctionIndex, FunctionType, LocalFunctionIndex, MemoryIndex, SignatureIndex,
TableIndex,
};
use wasmer_compiler::CompileError;
use wasmer_compiler::{CallingConvention, CompilerConfig, ModuleTranslationState, Target};
use wasmer_compiler::{
Compilation, CompiledFunction, CompiledFunctionFrameInfo, Compiler, FunctionBody,
FunctionBodyData,
Compilation, CompiledFunction, CompiledFunctionFrameInfo, CompiledFunctionUnwindInfo, Compiler,
Dwarf, FunctionBody, FunctionBodyData, SectionIndex,
};
use wasmer_compiler::{CompilerConfig, ModuleTranslationState, Target};
use wasmer_runtime::{MemoryPlan, ModuleInfo, TablePlan};
/// A compiler that compiles a WebAssembly module with Cranelift, translating the Wasm to Cranelift IR,
@@ -84,6 +89,26 @@ impl Compiler for CraneliftCompiler {
.map(|(_sig_index, func_type)| signature_to_cranelift_ir(func_type, frontend_config))
.collect::<PrimaryMap<SignatureIndex, ir::Signature>>();
// Generate the frametable
#[cfg(feature = "unwind")]
let dwarf_frametable = {
use std::sync::{Arc, Mutex};
match self.target().triple().default_calling_convention() {
Ok(CallingConvention::SystemV) => {
match isa.create_systemv_cie() {
Some(cie) => {
let mut dwarf_frametable = FrameTable::default();
let cie_id = dwarf_frametable.add_cie(cie);
Some((Arc::new(Mutex::new(dwarf_frametable)), cie_id))
}
// Even though we are in a SystemV system, Cranelift doesn't support it
None => None,
}
}
_ => None,
}
};
let functions = function_body_inputs
.into_iter()
.collect::<Vec<(LocalFunctionIndex, &FunctionBodyData<'_>)>>()
@@ -100,7 +125,6 @@ impl Compiler for CraneliftCompiler {
);
context.func.name = get_func_name(func_index);
context.func.signature = signatures[module.functions[func_index]].clone();
context.func.collect_frame_layout_info();
// if generate_debug_info {
// context.func.collect_debug_info();
// }
@@ -131,7 +155,32 @@ impl Compiler for CraneliftCompiler {
CompileError::Codegen(pretty_error(&context.func, Some(isa), error))
})?;
let unwind_info = compiled_function_unwind_info(isa, &context);
let unwind_info = match compiled_function_unwind_info(isa, &context)? {
#[cfg(feature = "unwind")]
CraneliftUnwindInfo::FDE(fde) => {
if let Some((dwarf_frametable, cie_id)) = &dwarf_frametable {
dwarf_frametable
.lock()
.expect("Can't write into DWARF frametable")
.add_fde(
*cie_id,
fde.to_fde(Address::Symbol {
// The symbol is the kind of relocation.
// "0" is used for functions
symbol: WriterRelocate::FUNCTION_SYMBOL,
// We use the addend as a way to specify the
// function index
addend: i.index() as _,
}),
);
// The unwind information is inserted into the dwarf section
Some(CompiledFunctionUnwindInfo::Dwarf)
} else {
None
}
}
other => other.maybe_into_to_windows_unwind(),
};
let address_map = get_function_address_map(&context, input, code_buf.len(), isa);
@@ -155,9 +204,31 @@ impl Compiler for CraneliftCompiler {
.into_iter()
.collect::<PrimaryMap<LocalFunctionIndex, _>>();
let custom_sections = PrimaryMap::new();
#[cfg(feature = "unwind")]
let (custom_sections, dwarf) = {
let mut custom_sections = PrimaryMap::new();
let dwarf = if let Some((dwarf_frametable, _cie_id)) = dwarf_frametable {
let mut eh_frame = EhFrame(WriterRelocate::new(
self.target().triple().endianness().ok(),
));
dwarf_frametable
.lock()
.unwrap()
.write_eh_frame(&mut eh_frame)
.unwrap();
Ok(Compilation::new(functions, custom_sections))
let eh_frame_section = eh_frame.0.into_section();
custom_sections.push(eh_frame_section);
Some(Dwarf::new(SectionIndex::new(0)))
} else {
None
};
(custom_sections, dwarf)
};
#[cfg(not(feature = "unwind"))]
let (custom_sections, dwarf) = (PrimaryMap::new(), None);
Ok(Compilation::new(functions, custom_sections, dwarf))
}
fn compile_function_call_trampolines(

View File

@@ -1,21 +0,0 @@
use cranelift_codegen::isa::CallConv;
use serde::{Deserialize, Serialize};
use wasm_common::entity::PrimaryMap;
use wasm_common::LocalFunctionIndex;
pub use cranelift_codegen::ir::FrameLayoutChange;
/// Frame layout information: call convention and
/// registers save/restore commands.
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
pub struct FrameLayout {
/// Call convention.
pub call_conv: CallConv,
/// Frame default/initial commands.
pub initial_commands: Box<[FrameLayoutChange]>,
/// Frame commands at specific offset.
pub commands: Box<[(usize, FrameLayoutChange)]>,
}
/// Functions frame layouts.
pub type FrameLayouts = PrimaryMap<LocalFunctionIndex, FrameLayout>;

View File

@@ -1,5 +1,3 @@
mod address_map;
mod frame_layout;
pub use self::address_map::{ModuleInfoMemoryOffset, ModuleInfoVmctxInfo, ValueLabelsRanges};
pub use self::frame_layout::{FrameLayout, FrameLayoutChange, FrameLayouts};

View File

@@ -0,0 +1,102 @@
use gimli::write::{Address, EndianVec, Result, Writer};
use gimli::{RunTimeEndian, SectionId};
use wasm_common::entity::EntityRef;
use wasm_common::LocalFunctionIndex;
use wasmer_compiler::{CustomSection, CustomSectionProtection, SectionBody};
use wasmer_compiler::{Endianness, Relocation, RelocationKind, RelocationTarget};
#[derive(Clone, Debug)]
pub struct WriterRelocate {
pub relocs: Vec<Relocation>,
writer: EndianVec<RunTimeEndian>,
}
impl WriterRelocate {
pub const FUNCTION_SYMBOL: usize = 0;
pub fn new(endianness: Option<Endianness>) -> Self {
let endianness = match endianness {
Some(Endianness::Little) => RunTimeEndian::Little,
Some(Endianness::Big) => RunTimeEndian::Big,
// We autodetect it, based on the host
None => RunTimeEndian::default(),
};
WriterRelocate {
relocs: Vec::new(),
writer: EndianVec::new(endianness),
}
}
pub fn into_section(mut self) -> CustomSection {
// GCC expects a terminating "empty" length, so write a 0 length at the end of the table.
self.writer.write_u32(0).unwrap();
let data = self.writer.into_vec();
CustomSection {
protection: CustomSectionProtection::Read,
bytes: SectionBody::new_with_vec(data),
relocations: self.relocs,
}
}
}
impl Writer for WriterRelocate {
type Endian = RunTimeEndian;
fn endian(&self) -> Self::Endian {
self.writer.endian()
}
fn len(&self) -> usize {
self.writer.len()
}
fn write(&mut self, bytes: &[u8]) -> Result<()> {
self.writer.write(bytes)
}
fn write_at(&mut self, offset: usize, bytes: &[u8]) -> Result<()> {
self.writer.write_at(offset, bytes)
}
fn write_address(&mut self, address: Address, size: u8) -> Result<()> {
match address {
Address::Constant(val) => self.write_udata(val, size),
Address::Symbol { symbol, addend } => {
// Is a function relocation
if symbol == Self::FUNCTION_SYMBOL {
// We use the addend to detect the function index
let function_index = LocalFunctionIndex::new(addend as _);
let reloc_target = RelocationTarget::LocalFunc(function_index);
let offset = self.len() as u32;
let kind = match size {
8 => RelocationKind::Abs8,
_ => unimplemented!("dwarf relocation size not yet supported: {}", size),
};
let addend = 0;
self.relocs.push(Relocation {
kind,
reloc_target,
offset,
addend,
});
self.write_udata(addend as u64, size)
} else {
unreachable!("Symbol {} in DWARF not recognized", symbol);
}
}
}
}
fn write_offset(&mut self, _val: usize, _section: SectionId, _size: u8) -> Result<()> {
unimplemented!("write_offset not yet implemented");
}
fn write_offset_at(
&mut self,
_offset: usize,
_val: usize,
_section: SectionId,
_size: u8,
) -> Result<()> {
unimplemented!("write_offset_at not yet implemented");
}
}

View File

@@ -1,3 +1,6 @@
// This file contains code from external sources.
// Attributions: https://github.com/wasmerio/wasmer-reborn/blob/master/ATTRIBUTIONS.md
use crate::translator::{
type_to_irtype, FuncEnvironment as BaseFuncEnvironment, GlobalVariable, TargetEnvironment,
};
@@ -536,7 +539,7 @@ impl<'module_environment> BaseFuncEnvironment for FuncEnvironment<'module_enviro
fn translate_table_grow(
&mut self,
_: cranelift_codegen::cursor::FuncCursor<'_>,
_: u32,
_: TableIndex,
_: ir::Value,
_: ir::Value,
) -> WasmResult<ir::Value> {
@@ -548,7 +551,7 @@ impl<'module_environment> BaseFuncEnvironment for FuncEnvironment<'module_enviro
fn translate_table_get(
&mut self,
_: cranelift_codegen::cursor::FuncCursor<'_>,
_: u32,
_: TableIndex,
_: ir::Value,
) -> WasmResult<ir::Value> {
Err(WasmError::Unsupported(
@@ -559,7 +562,7 @@ impl<'module_environment> BaseFuncEnvironment for FuncEnvironment<'module_enviro
fn translate_table_set(
&mut self,
_: cranelift_codegen::cursor::FuncCursor<'_>,
_: u32,
_: TableIndex,
_: ir::Value,
_: ir::Value,
) -> WasmResult<()> {
@@ -571,7 +574,7 @@ impl<'module_environment> BaseFuncEnvironment for FuncEnvironment<'module_enviro
fn translate_table_fill(
&mut self,
_: cranelift_codegen::cursor::FuncCursor<'_>,
_: u32,
_: TableIndex,
_: ir::Value,
_: ir::Value,
_: ir::Value,

View File

@@ -49,6 +49,8 @@ mod address_map;
mod compiler;
mod config;
mod debug;
#[cfg(feature = "unwind")]
mod dwarf;
mod func_environ;
mod sink;
mod trampoline;
@@ -56,7 +58,6 @@ mod translator;
pub use crate::compiler::CraneliftCompiler;
pub use crate::config::CraneliftConfig;
pub use crate::debug::{FrameLayout, FrameLayoutChange, FrameLayouts};
pub use crate::debug::{ModuleInfoMemoryOffset, ModuleInfoVmctxInfo, ValueLabelsRanges};
pub use crate::trampoline::make_trampoline_function_call;

View File

@@ -32,6 +32,7 @@ impl<'a> binemit::RelocSink for RelocSink<'a> {
fn reloc_external(
&mut self,
offset: binemit::CodeOffset,
_source_loc: ir::SourceLoc,
reloc: binemit::Reloc,
name: &ExternalName,
addend: binemit::Addend,
@@ -125,7 +126,6 @@ fn translate_ir_trapcode(trap: ir::TrapCode) -> TrapCode {
ir::TrapCode::StackOverflow => TrapCode::StackOverflow,
ir::TrapCode::HeapOutOfBounds => TrapCode::HeapAccessOutOfBounds,
ir::TrapCode::TableOutOfBounds => TrapCode::TableAccessOutOfBounds,
ir::TrapCode::OutOfBounds => TrapCode::OutOfBounds,
ir::TrapCode::IndirectCallToNull => TrapCode::IndirectCallToNull,
ir::TrapCode::BadSignature => TrapCode::BadSignature,
ir::TrapCode::IntegerOverflow => TrapCode::IntegerOverflow,

View File

@@ -1,3 +1,6 @@
// This file contains code from external sources.
// Attributions: https://github.com/wasmerio/wasmer-reborn/blob/master/ATTRIBUTIONS.md
//! A trampoline generator for calling dynamic host functions from Wasm.
use super::binemit::TrampolineRelocSink;
@@ -118,7 +121,7 @@ pub fn make_trampoline_dynamic_function(
)
.map_err(|error| CompileError::Codegen(pretty_error(&context.func, Some(isa), error)))?;
let unwind_info = compiled_function_unwind_info(isa, &context);
let unwind_info = compiled_function_unwind_info(isa, &context)?.maybe_into_to_windows_unwind();
Ok(FunctionBody {
body: code_buf,

View File

@@ -1,3 +1,6 @@
// This file contains code from external sources.
// Attributions: https://github.com/wasmerio/wasmer-reborn/blob/master/ATTRIBUTIONS.md
//! A trampoline generator for calling Wasm functions easily.
//!
//! That way, you can start calling Wasm functions doing things like:
@@ -44,7 +47,6 @@ pub fn make_trampoline_function_call(
let mut context = Context::new();
context.func = ir::Function::with_name_signature(ir::ExternalName::user(0, 0), wrapper_sig);
context.func.collect_frame_layout_info();
let value_size = mem::size_of::<u128>();
{
@@ -118,7 +120,7 @@ pub fn make_trampoline_function_call(
)
.map_err(|error| CompileError::Codegen(pretty_error(&context.func, Some(isa), error)))?;
let unwind_info = compiled_function_unwind_info(isa, &context);
let unwind_info = compiled_function_unwind_info(isa, &context)?.maybe_into_to_windows_unwind();
Ok(FunctionBody {
body: code_buf,

View File

@@ -38,6 +38,7 @@ pub mod binemit {
fn reloc_external(
&mut self,
_offset: binemit::CodeOffset,
_source_loc: ir::SourceLoc,
_reloc: binemit::Reloc,
_name: &ir::ExternalName,
_addend: binemit::Addend,

View File

@@ -1,3 +1,6 @@
// This file contains code from external sources.
// Attributions: https://github.com/wasmerio/wasmer-reborn/blob/master/ATTRIBUTIONS.md
//! This module contains the bulk of the interesting code performing the translation between
//! WebAssembly bytecode and Cranelift IR.
//!
@@ -27,6 +30,8 @@ use super::func_environ::{FuncEnvironment, GlobalVariable, ReturnMode};
use super::func_state::{ControlStackFrame, ElseData, FuncTranslationState};
use super::translation_utils::{block_with_params, f32_translation, f64_translation};
use crate::{hash_map, HashMap};
use core::cmp;
use core::convert::TryFrom;
use core::{i32, u32};
use cranelift_codegen::ir::condcodes::{FloatCC, IntCC};
use cranelift_codegen::ir::immediates::Offset32;
@@ -123,7 +128,11 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
GlobalVariable::Memory { gv, offset, ty } => {
let addr = builder.ins().global_value(environ.pointer_type(), gv);
let flags = ir::MemFlags::trusted();
let val = state.pop1();
let mut val = state.pop1();
// Ensure SIMD values are cast to their default Cranelift type, I8x16.
if ty.is_vector() {
val = optionally_bitcast_vector(val, I8X16, builder);
}
debug_assert_eq!(ty, builder.func.dfg.value_type(val));
builder.ins().store(flags, val, addr, offset);
}
@@ -355,7 +364,7 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
// We signal that all the code that follows until the next End is unreachable
frame.set_branched_to_exit();
let return_count = if frame.is_loop() {
0
frame.num_param_values()
} else {
frame.num_return_values()
};
@@ -652,57 +661,48 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
} => {
translate_load(*offset, ir::Opcode::Load, I8X16, builder, state, environ)?;
}
Operator::I16x8Load8x8S { .. }
| Operator::I16x8Load8x8U { .. }
| Operator::I32x4Load16x4S { .. }
| Operator::I32x4Load16x4U { .. }
| Operator::I64x2Load32x2S { .. }
| Operator::I64x2Load32x2U { .. } => {
return Err(wasm_unsupported!("proposed SIMD operator {:?}", op));
Operator::I16x8Load8x8S {
memarg: MemoryImmediate { flags: _, offset },
} => {
let (flags, base, offset) = prepare_load(*offset, 8, builder, state, environ)?;
let loaded = builder.ins().sload8x8(flags, base, offset);
state.push1(loaded);
}
Operator::I16x8Load8x8U {
memarg: MemoryImmediate { flags: _, offset },
} => {
let (flags, base, offset) = prepare_load(*offset, 8, builder, state, environ)?;
let loaded = builder.ins().uload8x8(flags, base, offset);
state.push1(loaded);
}
Operator::I32x4Load16x4S {
memarg: MemoryImmediate { flags: _, offset },
} => {
let (flags, base, offset) = prepare_load(*offset, 8, builder, state, environ)?;
let loaded = builder.ins().sload16x4(flags, base, offset);
state.push1(loaded);
}
Operator::I32x4Load16x4U {
memarg: MemoryImmediate { flags: _, offset },
} => {
let (flags, base, offset) = prepare_load(*offset, 8, builder, state, environ)?;
let loaded = builder.ins().uload16x4(flags, base, offset);
state.push1(loaded);
}
Operator::I64x2Load32x2S {
memarg: MemoryImmediate { flags: _, offset },
} => {
let (flags, base, offset) = prepare_load(*offset, 8, builder, state, environ)?;
let loaded = builder.ins().sload32x2(flags, base, offset);
state.push1(loaded);
}
Operator::I64x2Load32x2U {
memarg: MemoryImmediate { flags: _, offset },
} => {
let (flags, base, offset) = prepare_load(*offset, 8, builder, state, environ)?;
let loaded = builder.ins().uload32x2(flags, base, offset);
state.push1(loaded);
}
// Enable with new version of Cranelift
// Operator::I16x8Load8x8S {
// memarg: MemoryImmediate { flags: _, offset },
// } => {
// let (flags, base, offset) = prepare_load(*offset, builder, state, environ)?;
// let loaded = builder.ins().sload8x8(flags, base, offset);
// state.push1(loaded);
// }
// Operator::I16x8Load8x8U {
// memarg: MemoryImmediate { flags: _, offset },
// } => {
// let (flags, base, offset) = prepare_load(*offset, builder, state, environ)?;
// let loaded = builder.ins().uload8x8(flags, base, offset);
// state.push1(loaded);
// }
// Operator::I32x4Load16x4S {
// memarg: MemoryImmediate { flags: _, offset },
// } => {
// let (flags, base, offset) = prepare_load(*offset, builder, state, environ)?;
// let loaded = builder.ins().sload16x4(flags, base, offset);
// state.push1(loaded);
// }
// Operator::I32x4Load16x4U {
// memarg: MemoryImmediate { flags: _, offset },
// } => {
// let (flags, base, offset) = prepare_load(*offset, builder, state, environ)?;
// let loaded = builder.ins().uload16x4(flags, base, offset);
// state.push1(loaded);
// }
// Operator::I64x2Load32x2S {
// memarg: MemoryImmediate { flags: _, offset },
// } => {
// let (flags, base, offset) = prepare_load(*offset, builder, state, environ)?;
// let loaded = builder.ins().sload32x2(flags, base, offset);
// state.push1(loaded);
// }
// Operator::I64x2Load32x2U {
// memarg: MemoryImmediate { flags: _, offset },
// } => {
// let (flags, base, offset) = prepare_load(*offset, builder, state, environ)?;
// let loaded = builder.ins().uload32x2(flags, base, offset);
// state.push1(loaded);
// }
/****************************** Store instructions ***********************************
* Wasm specifies an integer alignment flag but we drop it in Cranelift.
* The memory base address is provided by the environment.
@@ -1042,8 +1042,8 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
Operator::F32Le | Operator::F64Le => {
translate_fcmp(FloatCC::LessThanOrEqual, builder, state)
}
Operator::RefNull => state.push1(builder.ins().null(environ.reference_type())),
Operator::RefIsNull => {
Operator::RefNull { ty: _ } => state.push1(builder.ins().null(environ.reference_type())),
Operator::RefIsNull { ty: _ } => {
let arg = state.pop1();
let val = builder.ins().is_null(arg);
let val_int = builder.ins().bint(I32, val);
@@ -1174,23 +1174,26 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
)?);
}
Operator::TableGrow { table } => {
let table_index = TableIndex::from_u32(*table);
let delta = state.pop1();
let init_value = state.pop1();
state.push1(environ.translate_table_grow(
builder.cursor(),
*table,
table_index,
delta,
init_value,
)?);
}
Operator::TableGet { table } => {
let table_index = TableIndex::from_u32(*table);
let index = state.pop1();
state.push1(environ.translate_table_get(builder.cursor(), *table, index)?);
state.push1(environ.translate_table_get(builder.cursor(), table_index, index)?);
}
Operator::TableSet { table } => {
let table_index = TableIndex::from_u32(*table);
let value = state.pop1();
let index = state.pop1();
environ.translate_table_set(builder.cursor(), *table, value, index)?;
environ.translate_table_set(builder.cursor(), table_index, value, index)?;
}
Operator::TableCopy {
dst_table: dst_table_index,
@@ -1213,10 +1216,11 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
)?;
}
Operator::TableFill { table } => {
let table_index = TableIndex::from_u32(*table);
let len = state.pop1();
let val = state.pop1();
let dest = state.pop1();
environ.translate_table_fill(builder.cursor(), *table, dest, val, len)?;
environ.translate_table_fill(builder.cursor(), table_index, dest, val, len)?;
}
Operator::TableInit {
segment,
@@ -1272,7 +1276,7 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
} => {
// TODO: For spec compliance, this is initially implemented as a combination of `load +
// splat` but could be implemented eventually as a single instruction (`load_splat`).
// See https://github.com/wasmerio/wasmer/issues/1175.
// See https://github.com/bytecodealliance/wasmtime/issues/1175.
translate_load(
*offset,
ir::Opcode::Load,
@@ -1291,8 +1295,11 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
}
Operator::I8x16ExtractLaneU { lane } | Operator::I16x8ExtractLaneU { lane } => {
let vector = pop1_with_bitcast(state, type_of(op), builder);
state.push1(builder.ins().extractlane(vector, lane.clone()));
// on x86, PEXTRB zeroes the upper bits of the destination register of extractlane so uextend is elided; of course, this depends on extractlane being legalized to a PEXTRB
let extracted = builder.ins().extractlane(vector, lane.clone());
state.push1(builder.ins().uextend(I32, extracted));
// On x86, PEXTRB zeroes the upper bits of the destination register of extractlane so
// uextend could be elided; for now, uextend is needed for Cranelift's type checks to
// work.
}
Operator::I32x4ExtractLane { lane }
| Operator::I64x2ExtractLane { lane }
@@ -1306,7 +1313,7 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
let ty = type_of(op);
let reduced = builder.ins().ireduce(ty.lane_type(), replacement);
let vector = optionally_bitcast_vector(vector, ty, builder);
state.push1(builder.ins().insertlane(vector, *lane, reduced))
state.push1(builder.ins().insertlane(vector, reduced, *lane))
}
Operator::I32x4ReplaceLane { lane }
| Operator::I64x2ReplaceLane { lane }
@@ -1314,7 +1321,7 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
| Operator::F64x2ReplaceLane { lane } => {
let (vector, replacement) = state.pop2();
let vector = optionally_bitcast_vector(vector, type_of(op), builder);
state.push1(builder.ins().insertlane(vector, *lane, replacement))
state.push1(builder.ins().insertlane(vector, replacement, *lane))
}
Operator::V8x16Shuffle { lanes, .. } => {
let (a, b) = pop2_with_bitcast(state, I8X16, builder);
@@ -1379,7 +1386,7 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
let a = pop1_with_bitcast(state, type_of(op), builder);
state.push1(builder.ins().ineg(a))
}
Operator::I16x8Mul | Operator::I32x4Mul => {
Operator::I16x8Mul | Operator::I32x4Mul | Operator::I64x2Mul => {
let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
state.push1(builder.ins().imul(a, b))
}
@@ -1403,28 +1410,28 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
let a = state.pop1();
state.push1(builder.ins().bnot(a));
}
Operator::I16x8Shl | Operator::I32x4Shl | Operator::I64x2Shl => {
Operator::I8x16Shl | Operator::I16x8Shl | Operator::I32x4Shl | Operator::I64x2Shl => {
let (a, b) = state.pop2();
let bitcast_a = optionally_bitcast_vector(a, type_of(op), builder);
let bitwidth = i64::from(builder.func.dfg.value_type(a).bits());
let bitwidth = i64::from(type_of(op).lane_bits());
// The spec expects to shift with `b mod lanewidth`; so, e.g., for 16 bit lane-width
// we do `b AND 15`; this means fewer instructions than `iconst + urem`.
let b_mod_bitwidth = builder.ins().band_imm(b, bitwidth - 1);
state.push1(builder.ins().ishl(bitcast_a, b_mod_bitwidth))
}
Operator::I16x8ShrU | Operator::I32x4ShrU | Operator::I64x2ShrU => {
Operator::I8x16ShrU | Operator::I16x8ShrU | Operator::I32x4ShrU | Operator::I64x2ShrU => {
let (a, b) = state.pop2();
let bitcast_a = optionally_bitcast_vector(a, type_of(op), builder);
let bitwidth = i64::from(builder.func.dfg.value_type(a).bits());
let bitwidth = i64::from(type_of(op).lane_bits());
// The spec expects to shift with `b mod lanewidth`; so, e.g., for 16 bit lane-width
// we do `b AND 15`; this means fewer instructions than `iconst + urem`.
let b_mod_bitwidth = builder.ins().band_imm(b, bitwidth - 1);
state.push1(builder.ins().ushr(bitcast_a, b_mod_bitwidth))
}
Operator::I16x8ShrS | Operator::I32x4ShrS => {
Operator::I8x16ShrS | Operator::I16x8ShrS | Operator::I32x4ShrS | Operator::I64x2ShrS => {
let (a, b) = state.pop2();
let bitcast_a = optionally_bitcast_vector(a, type_of(op), builder);
let bitwidth = i64::from(builder.func.dfg.value_type(a).bits());
let bitwidth = i64::from(type_of(op).lane_bits());
// The spec expects to shift with `b mod lanewidth`; so, e.g., for 16 bit lane-width
// we do `b AND 15`; this means fewer instructions than `iconst + urem`.
let b_mod_bitwidth = builder.ins().band_imm(b, bitwidth - 1);
@@ -1439,18 +1446,12 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
// operands must match (hence the bitcast).
state.push1(builder.ins().bitselect(bitcast_c, bitcast_a, bitcast_b))
}
Operator::I8x16AnyTrue
| Operator::I16x8AnyTrue
| Operator::I32x4AnyTrue
| Operator::I64x2AnyTrue => {
Operator::I8x16AnyTrue | Operator::I16x8AnyTrue | Operator::I32x4AnyTrue => {
let a = pop1_with_bitcast(state, type_of(op), builder);
let bool_result = builder.ins().vany_true(a);
state.push1(builder.ins().bint(I32, bool_result))
}
Operator::I8x16AllTrue
| Operator::I16x8AllTrue
| Operator::I32x4AllTrue
| Operator::I64x2AllTrue => {
Operator::I8x16AllTrue | Operator::I16x8AllTrue | Operator::I32x4AllTrue => {
let a = pop1_with_bitcast(state, type_of(op), builder);
let bool_result = builder.ins().vall_true(a);
state.push1(builder.ins().bint(I32, bool_result))
@@ -1546,19 +1547,15 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
let a = pop1_with_bitcast(state, I32X4, builder);
state.push1(builder.ins().fcvt_from_sint(F32X4, a))
}
Operator::I8x16Shl
| Operator::I8x16ShrS
| Operator::I8x16ShrU
| Operator::I8x16Mul
| Operator::I64x2Mul
| Operator::I64x2ShrS
| Operator::I32x4TruncSatF32x4S
Operator::F32x4ConvertI32x4U => {
let a = pop1_with_bitcast(state, I32X4, builder);
state.push1(builder.ins().fcvt_from_uint(F32X4, a))
}
Operator::I32x4TruncSatF32x4S
| Operator::I32x4TruncSatF32x4U
| Operator::I64x2TruncSatF64x2S
| Operator::I64x2TruncSatF64x2U
| Operator::F32x4ConvertI32x4U
| Operator::F64x2ConvertI64x2S
| Operator::F64x2ConvertI64x2U { .. }
| Operator::I8x16Abs
| Operator::I16x8Abs
| Operator::I32x4Abs
| Operator::I8x16NarrowI16x8S { .. }
| Operator::I8x16NarrowI16x8U { .. }
| Operator::I16x8NarrowI32x4S { .. }
@@ -1573,6 +1570,10 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
| Operator::I32x4WidenHighI16x8U { .. } => {
return Err(wasm_unsupported!("proposed SIMD operator {:?}", op));
}
Operator::ReturnCall { .. } | Operator::ReturnCallIndirect { .. } => {
return Err(wasm_unsupported!("proposed tail-call operator {:?}", op));
}
};
Ok(())
}
@@ -1710,25 +1711,70 @@ fn get_heap_addr(
heap: ir::Heap,
addr32: ir::Value,
offset: u32,
width: u32,
addr_ty: Type,
builder: &mut FunctionBuilder,
) -> (ir::Value, i32) {
use core::cmp::min;
let mut adjusted_offset = u64::from(offset);
let offset_guard_size: u64 = builder.func.heaps[heap].offset_guard_size.into();
// Generate `heap_addr` instructions that are friendly to CSE by checking offsets that are
// multiples of the offset-guard size. Add one to make sure that we check the pointer itself
// is in bounds.
if offset_guard_size != 0 {
adjusted_offset = adjusted_offset / offset_guard_size * offset_guard_size;
}
// For accesses on the outer skirts of the offset-guard pages, we expect that we get a trap
// even if the access goes beyond the offset-guard pages. This is because the first byte
// pointed to is inside the offset-guard pages.
let check_size = min(u64::from(u32::MAX), 1 + adjusted_offset) as u32;
// How exactly the bounds check is performed here and what it's performed
// on is a bit tricky. Generally we want to rely on access violations (e.g.
// segfaults) to generate traps since that means we don't have to bounds
// check anything explicitly.
//
// If we don't have a guard page of unmapped memory, though, then we can't
// rely on this trapping behavior through segfaults. Instead we need to
// bounds-check the entire memory access here which is everything from
// `addr32 + offset` to `addr32 + offset + width` (not inclusive). In this
// scenario our adjusted offset that we're checking is `offset + width`.
//
// If we have a guard page, however, then we can perform a further
// optimization of the generated code by only checking multiples of the
// offset-guard size to be more CSE-friendly. Knowing that we have at least
// 1 page of a guard page we're then able to disregard the `width` since we
// know it's always less than one page. Our bounds check will be for the
// first byte which will either succeed and be guaranteed to fault if it's
// actually out of bounds, or the bounds check itself will fail. In any case
// we assert that the width is reasonably small for now so this assumption
// can be adjusted in the future if we get larger widths.
//
// Put another way we can say, where `y < offset_guard_size`:
//
// n * offset_guard_size + y = offset
//
// We'll then pass `n * offset_guard_size` as the bounds check value. If
// this traps then our `offset` would have trapped anyway. If this check
// passes we know
//
// addr32 + n * offset_guard_size < bound
//
// which means
//
// addr32 + n * offset_guard_size + y < bound + offset_guard_size
//
// because `y < offset_guard_size`, which then means:
//
// addr32 + offset < bound + offset_guard_size
//
// Since we know that that guard size bytes are all unmapped we're
// guaranteed that `offset` and the `width` bytes after it are either
// in-bounds or will hit the guard page, meaning we'll get the desired
// semantics we want.
//
// As one final comment on the bits with the guard size here, another goal
// of this is to hit an optimization in `heap_addr` where if the heap size
// minus the offset is >= 4GB then bounds checks are 100% eliminated. This
// means that with huge guard regions (e.g. our 2GB default) most adjusted
// offsets we're checking here are zero. This means that we'll hit the fast
// path and emit zero conditional traps for bounds checks
let adjusted_offset = if offset_guard_size == 0 {
u64::from(offset) + u64::from(width)
} else {
assert!(width < 1024);
cmp::max(u64::from(offset) / offset_guard_size * offset_guard_size, 1)
};
debug_assert!(adjusted_offset > 0); // want to bounds check at least 1 byte
let check_size = u32::try_from(adjusted_offset).unwrap_or(u32::MAX);
let base = builder.ins().heap_addr(addr_ty, heap, addr32, check_size);
// Native load/store instructions take a signed `Offset32` immediate, so adjust the base
@@ -1745,6 +1791,7 @@ fn get_heap_addr(
/// Prepare for a load; factors out common functionality between load and load_extend operations.
fn prepare_load<FE: FuncEnvironment + ?Sized>(
offset: u32,
loaded_bytes: u32,
builder: &mut FunctionBuilder,
state: &mut FuncTranslationState,
environ: &mut FE,
@@ -1753,7 +1800,14 @@ fn prepare_load<FE: FuncEnvironment + ?Sized>(
// We don't yet support multiple linear memories.
let heap = state.get_heap(builder.func, 0, environ)?;
let (base, offset) = get_heap_addr(heap, addr32, offset, environ.pointer_type(), builder);
let (base, offset) = get_heap_addr(
heap,
addr32,
offset,
loaded_bytes,
environ.pointer_type(),
builder,
);
// Note that we don't set `is_aligned` here, even if the load instruction's
// alignment immediate says it's aligned, because WebAssembly's immediate
@@ -1772,7 +1826,13 @@ fn translate_load<FE: FuncEnvironment + ?Sized>(
state: &mut FuncTranslationState,
environ: &mut FE,
) -> WasmResult<()> {
let (flags, base, offset) = prepare_load(offset, builder, state, environ)?;
let (flags, base, offset) = prepare_load(
offset,
mem_op_size(opcode, result_ty),
builder,
state,
environ,
)?;
let (load, dfg) = builder.ins().Load(opcode, result_ty, flags, offset, base);
state.push1(dfg.first_result(load));
Ok(())
@@ -1791,7 +1851,14 @@ fn translate_store<FE: FuncEnvironment + ?Sized>(
// We don't yet support multiple linear memories.
let heap = state.get_heap(builder.func, 0, environ)?;
let (base, offset) = get_heap_addr(heap, addr32, offset, environ.pointer_type(), builder);
let (base, offset) = get_heap_addr(
heap,
addr32,
offset,
mem_op_size(opcode, val_ty),
environ.pointer_type(),
builder,
);
// See the comments in `translate_load` about the flags.
let flags = MemFlags::new();
builder
@@ -1800,6 +1867,16 @@ fn translate_store<FE: FuncEnvironment + ?Sized>(
Ok(())
}
fn mem_op_size(opcode: ir::Opcode, ty: Type) -> u32 {
match opcode {
ir::Opcode::Istore8 | ir::Opcode::Sload8 | ir::Opcode::Uload8 => 1,
ir::Opcode::Istore16 | ir::Opcode::Sload16 | ir::Opcode::Uload16 => 2,
ir::Opcode::Istore32 | ir::Opcode::Sload32 | ir::Opcode::Uload32 => 4,
ir::Opcode::Store | ir::Opcode::Load => ty.bytes(),
_ => panic!("unknown size of mem op for {:?}", opcode),
}
}
fn translate_icmp(cc: IntCC, builder: &mut FunctionBuilder, state: &mut FuncTranslationState) {
let (arg0, arg1) = state.pop2();
let val = builder.ins().icmp(cc, arg0, arg1);
@@ -1922,8 +1999,7 @@ fn type_of(operator: &Operator) -> Type {
| Operator::I8x16MinU
| Operator::I8x16MaxS
| Operator::I8x16MaxU
| Operator::I8x16RoundingAverageU
| Operator::I8x16Mul => I8X16,
| Operator::I8x16RoundingAverageU => I8X16,
Operator::I16x8Splat
| Operator::V16x8LoadSplat { .. }
@@ -1994,15 +2070,12 @@ fn type_of(operator: &Operator) -> Type {
| Operator::I64x2ExtractLane { .. }
| Operator::I64x2ReplaceLane { .. }
| Operator::I64x2Neg
| Operator::I64x2AnyTrue
| Operator::I64x2AllTrue
| Operator::I64x2Shl
| Operator::I64x2ShrS
| Operator::I64x2ShrU
| Operator::I64x2Add
| Operator::I64x2Sub
| Operator::F64x2ConvertI64x2S
| Operator::F64x2ConvertI64x2U => I64X2,
| Operator::I64x2Mul => I64X2,
Operator::F32x4Splat
| Operator::F32x4ExtractLane { .. }
@@ -2042,9 +2115,7 @@ fn type_of(operator: &Operator) -> Type {
| Operator::F64x2Mul
| Operator::F64x2Div
| Operator::F64x2Min
| Operator::F64x2Max
| Operator::I64x2TruncSatF64x2S
| Operator::I64x2TruncSatF64x2U => F64X2,
| Operator::F64x2Max => F64X2,
_ => unimplemented!(
"Currently only SIMD instructions are mapped to their return type; the \

View File

@@ -1,3 +1,6 @@
// This file contains code from external sources.
// Attributions: https://github.com/wasmerio/wasmer-reborn/blob/master/ATTRIBUTIONS.md
//! All the runtime support necessary for the wasm to cranelift translation is formalized by the
//! traits `FunctionEnvironment`.
@@ -279,7 +282,7 @@ pub trait FuncEnvironment: TargetEnvironment {
fn translate_table_grow(
&mut self,
pos: FuncCursor,
table_index: u32,
table_index: TableIndex,
delta: ir::Value,
init_value: ir::Value,
) -> WasmResult<ir::Value>;
@@ -288,7 +291,7 @@ pub trait FuncEnvironment: TargetEnvironment {
fn translate_table_get(
&mut self,
pos: FuncCursor,
table_index: u32,
table_index: TableIndex,
index: ir::Value,
) -> WasmResult<ir::Value>;
@@ -296,7 +299,7 @@ pub trait FuncEnvironment: TargetEnvironment {
fn translate_table_set(
&mut self,
pos: FuncCursor,
table_index: u32,
table_index: TableIndex,
value: ir::Value,
index: ir::Value,
) -> WasmResult<()>;
@@ -319,7 +322,7 @@ pub trait FuncEnvironment: TargetEnvironment {
fn translate_table_fill(
&mut self,
pos: FuncCursor,
table_index: u32,
table_index: TableIndex,
dst: ir::Value,
val: ir::Value,
len: ir::Value,

View File

@@ -1,3 +1,6 @@
// This file contains code from external sources.
// Attributions: https://github.com/wasmerio/wasmer-reborn/blob/master/ATTRIBUTIONS.md
//! WebAssembly module and function translation state.
//!
//! The `ModuleTranslationState` struct defined in this module is used to keep track of data about

View File

@@ -1,4 +1,7 @@
//! Stand-alone WebAssembly to Cranelift IR translator.
// This file contains code from external sources.
// Attributions: https://github.com/wasmerio/wasmer-reborn/blob/master/ATTRIBUTIONS.md
//! Standalone WebAssembly to Cranelift IR translator.
//!
//! This module defines the `FuncTranslator` type which can translate a single WebAssembly
//! function to Cranelift IR guided by a `FuncEnvironment` which provides information about the
@@ -206,9 +209,8 @@ fn declare_locals<FE: FuncEnvironment + ?Sized>(
let constant_handle = builder.func.dfg.constants.insert([0; 16].to_vec().into());
builder.ins().vconst(ir::types::I8X16, constant_handle)
}
NullRef => builder.ins().null(environ.reference_type()),
AnyRef => builder.ins().null(environ.reference_type()),
AnyFunc => builder.ins().null(environ.reference_type()),
ExternRef => builder.ins().null(environ.reference_type()),
FuncRef => builder.ins().null(environ.reference_type()),
ty => return Err(wasm_unsupported!("unsupported local type {:?}", ty)),
};

View File

@@ -14,4 +14,4 @@ pub use self::translation_utils::{
get_vmctx_value_label, irlibcall_to_libcall, irreloc_to_relocationkind,
signature_to_cranelift_ir, transform_jump_table, type_to_irtype,
};
pub use self::unwind::compiled_function_unwind_info;
pub(crate) use self::unwind::{compiled_function_unwind_info, CraneliftUnwindInfo};

View File

@@ -58,7 +58,7 @@ pub fn type_to_irtype(ty: Type, target_config: TargetFrontendConfig) -> WasmResu
Type::F32 => Ok(ir::types::F32),
Type::F64 => Ok(ir::types::F64),
Type::V128 => Ok(ir::types::I8X16),
Type::AnyRef | Type::FuncRef => reference_type(target_config),
Type::ExternRef | Type::FuncRef => reference_type(target_config),
// ty => Err(wasm_unsupported!("type_to_type: wasm type {:?}", ty)),
}
}
@@ -113,7 +113,7 @@ pub fn block_with_params<PE: TargetEnvironment + ?Sized>(
wasmparser::Type::F64 => {
builder.append_block_param(block, ir::types::F64);
}
wasmparser::Type::AnyRef | wasmparser::Type::AnyFunc | wasmparser::Type::NullRef => {
wasmparser::Type::ExternRef | wasmparser::Type::FuncRef => {
builder.append_block_param(block, environ.reference_type());
}
wasmparser::Type::V128 => {

View File

@@ -1,66 +1,54 @@
//! A `Compilation` contains the compiled function bodies for a WebAssembly
//! module.
use cranelift_codegen::isa::unwind::systemv::UnwindInfo as DwarfFDE;
use cranelift_codegen::isa::unwind::UnwindInfo;
use cranelift_codegen::print_errors::pretty_error;
use cranelift_codegen::{isa, Context};
use wasmer_compiler::{CompiledFunctionUnwindInfo, FDERelocEntry};
use wasmer_compiler::{CompileError, CompiledFunctionUnwindInfo};
/// Constructs unwind info object from Cranelift IR
pub fn compiled_function_unwind_info(
isa: &dyn isa::TargetIsa,
context: &Context,
) -> Option<CompiledFunctionUnwindInfo> {
use cranelift_codegen::binemit::{FrameUnwindKind, FrameUnwindOffset, FrameUnwindSink, Reloc};
use cranelift_codegen::isa::CallConv;
/// Cranelift specific unwind info
pub(crate) enum CraneliftUnwindInfo {
/// Windows Unwind info
WindowsX64(Vec<u8>),
/// Dwarf FDE
FDE(DwarfFDE),
/// No Unwind info attached
None,
}
struct Sink(Vec<u8>, usize, Vec<FDERelocEntry>);
impl FrameUnwindSink for Sink {
fn len(&self) -> FrameUnwindOffset {
self.0.len()
impl CraneliftUnwindInfo {
/// Transform the `CraneliftUnwindInfo` to the Windows format.
///
/// We skip the DWARF as it is not needed for trampolines (which are the
/// main users of this function)
pub fn maybe_into_to_windows_unwind(self) -> Option<CompiledFunctionUnwindInfo> {
match self {
CraneliftUnwindInfo::WindowsX64(unwind_info) => {
Some(CompiledFunctionUnwindInfo::WindowsX64(unwind_info))
}
fn bytes(&mut self, b: &[u8]) {
self.0.extend_from_slice(b);
_ => None,
}
fn reserve(&mut self, len: usize) {
self.0.reserve(len)
}
fn reloc(&mut self, r: Reloc, off: FrameUnwindOffset) {
self.2.push(FDERelocEntry(
0,
off,
match r {
Reloc::Abs4 => 4,
Reloc::Abs8 => 8,
_ => {
panic!("unexpected reloc type");
}
},
))
}
fn set_entry_offset(&mut self, off: FrameUnwindOffset) {
self.1 = off;
}
}
let kind = match context.func.signature.call_conv {
CallConv::SystemV | CallConv::Fast | CallConv::Cold => FrameUnwindKind::Libunwind,
CallConv::WindowsFastcall => FrameUnwindKind::Fastcall,
_ => {
return None;
}
};
let mut sink = Sink(Vec::new(), 0, Vec::new());
context.emit_unwind_info(isa, kind, &mut sink);
let Sink(data, offset, relocs) = sink;
if data.is_empty() {
return None;
}
match kind {
FrameUnwindKind::Fastcall => Some(CompiledFunctionUnwindInfo::Windows(data)),
FrameUnwindKind::Libunwind => Some(CompiledFunctionUnwindInfo::FrameLayout(
data, offset, relocs,
)),
}
}
/// Constructs unwind info object from Cranelift IR
pub(crate) fn compiled_function_unwind_info(
isa: &dyn isa::TargetIsa,
context: &Context,
) -> Result<CraneliftUnwindInfo, CompileError> {
let unwind_info = context
.create_unwind_info(isa)
.map_err(|error| CompileError::Codegen(pretty_error(&context.func, Some(isa), error)))?;
match unwind_info {
Some(UnwindInfo::WindowsX64(unwind)) => {
let size = unwind.emit_size();
let mut data: Vec<u8> = vec![0; size];
unwind.emit(&mut data[..]);
Ok(CraneliftUnwindInfo::WindowsX64(data))
}
Some(UnwindInfo::SystemV(unwind)) => Ok(CraneliftUnwindInfo::FDE(unwind)),
None => Ok(CraneliftUnwindInfo::None),
}
}

View File

@@ -2,3 +2,27 @@
This is the `wasmer-compiler-llvm` crate, which contains a
compiler implementation based on LLVM.
We recommend using LLVM as the default compiler when running WebAssembly
files on any **production** system, as it offers maximum peformance near
to native speeds.
## Requirements
The llvm compiler requires a valid installation of LLVM in your system.
It currently requires **LLVM 10**.
You can install LLVM easily on your debian-like system via this command:
```bash
bash -c "$(wget -O - https://apt.llvm.org/llvm.sh)"
```
Or in macOS:
```bash
brew install llvm
```
Or via any of the [pre-built binaries that LLVM offers](https://releases.llvm.org/download.html).

View File

@@ -112,7 +112,7 @@ impl Compiler for LLVMCompiler {
})
.collect::<PrimaryMap<LocalFunctionIndex, _>>();
Ok(Compilation::new(functions, module_custom_sections))
Ok(Compilation::new(functions, module_custom_sections, None))
}
fn compile_function_call_trampolines(

View File

@@ -63,7 +63,7 @@ pub fn func_type_to_llvm<'ctx>(
Type::I32 | Type::F32 => 32,
Type::I64 | Type::F64 => 64,
Type::V128 => 128,
Type::AnyRef => unimplemented!("anyref in the llvm backend"),
Type::ExternRef => unimplemented!("externref in the llvm backend"),
Type::FuncRef => unimplemented!("funcref in the llvm backend"),
})
.collect::<Vec<i32>>();
@@ -300,7 +300,7 @@ pub fn rets_from_call<'ctx>(
assert!(value.get_type() == intrinsics.i128_ty.as_basic_type_enum());
value
}
Type::AnyRef => unimplemented!("anyref in the llvm backend"),
Type::ExternRef => unimplemented!("externref in the llvm backend"),
Type::FuncRef => unimplemented!("funcref in the llvm backend"),
}
};
@@ -331,7 +331,7 @@ pub fn rets_from_call<'ctx>(
Type::I32 | Type::F32 => 32,
Type::I64 | Type::F64 => 64,
Type::V128 => 128,
Type::AnyRef => unimplemented!("anyref in the llvm backend"),
Type::ExternRef => unimplemented!("externref in the llvm backend"),
Type::FuncRef => unimplemented!("funcref in the llvm backend"),
})
.collect::<Vec<i32>>();

View File

@@ -2617,14 +2617,14 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> {
let res = self.builder.build_int_mul(v1, v2, "");
self.state.push1(res);
}
Operator::I8x16Mul => {
let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?;
let (v1, _) = self.v128_into_i8x16(v1, i1);
let (v2, _) = self.v128_into_i8x16(v2, i2);
let res = self.builder.build_int_mul(v1, v2, "");
let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, "");
self.state.push1(res);
}
// Operator::I8x16Mul => {
// let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?;
// let (v1, _) = self.v128_into_i8x16(v1, i1);
// let (v2, _) = self.v128_into_i8x16(v2, i2);
// let res = self.builder.build_int_mul(v1, v2, "");
// let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, "");
// self.state.push1(res);
// }
Operator::I16x8Mul => {
let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?;
let (v1, _) = self.v128_into_i16x8(v1, i1);
@@ -4964,36 +4964,36 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> {
);
self.state.push1(res);
}
Operator::I64x2TruncSatF64x2S => {
let (v, i) = self.state.pop1_extra()?;
let v = self.apply_pending_canonicalization(v, i);
let v = v.into_int_value();
let res = self.trunc_sat(
self.intrinsics.f64x2_ty,
self.intrinsics.i64x2_ty,
std::i64::MIN as u64,
std::i64::MAX as u64,
std::i64::MIN as u64,
std::i64::MAX as u64,
v,
);
self.state.push1(res);
}
Operator::I64x2TruncSatF64x2U => {
let (v, i) = self.state.pop1_extra()?;
let v = self.apply_pending_canonicalization(v, i);
let v = v.into_int_value();
let res = self.trunc_sat(
self.intrinsics.f64x2_ty,
self.intrinsics.i64x2_ty,
std::u64::MIN,
std::u64::MAX,
std::u64::MIN,
std::u64::MAX,
v,
);
self.state.push1(res);
}
// Operator::I64x2TruncSatF64x2S => {
// let (v, i) = self.state.pop1_extra()?;
// let v = self.apply_pending_canonicalization(v, i);
// let v = v.into_int_value();
// let res = self.trunc_sat(
// self.intrinsics.f64x2_ty,
// self.intrinsics.i64x2_ty,
// std::i64::MIN as u64,
// std::i64::MAX as u64,
// std::i64::MIN as u64,
// std::i64::MAX as u64,
// v,
// );
// self.state.push1(res);
// }
// Operator::I64x2TruncSatF64x2U => {
// let (v, i) = self.state.pop1_extra()?;
// let v = self.apply_pending_canonicalization(v, i);
// let v = v.into_int_value();
// let res = self.trunc_sat(
// self.intrinsics.f64x2_ty,
// self.intrinsics.i64x2_ty,
// std::u64::MIN,
// std::u64::MAX,
// std::u64::MIN,
// std::u64::MAX,
// v,
// );
// self.state.push1(res);
// }
Operator::I32TruncF32S => {
let v1 = self.state.pop1()?.into_float_value();
self.trap_if_not_representable_as_int(
@@ -5276,30 +5276,30 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> {
let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, "");
self.state.push1(res);
}
Operator::F64x2ConvertI64x2S => {
let v = self.state.pop1()?;
let v = self
.builder
.build_bitcast(v, self.intrinsics.i64x2_ty, "")
.into_vector_value();
let res = self
.builder
.build_signed_int_to_float(v, self.intrinsics.f64x2_ty, "");
let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, "");
self.state.push1(res);
}
Operator::F64x2ConvertI64x2U => {
let v = self.state.pop1()?;
let v = self
.builder
.build_bitcast(v, self.intrinsics.i64x2_ty, "")
.into_vector_value();
let res = self
.builder
.build_unsigned_int_to_float(v, self.intrinsics.f64x2_ty, "");
let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, "");
self.state.push1(res);
}
// Operator::F64x2ConvertI64x2S => {
// let v = self.state.pop1()?;
// let v = self
// .builder
// .build_bitcast(v, self.intrinsics.i64x2_ty, "")
// .into_vector_value();
// let res = self
// .builder
// .build_signed_int_to_float(v, self.intrinsics.f64x2_ty, "");
// let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, "");
// self.state.push1(res);
// }
// Operator::F64x2ConvertI64x2U => {
// let v = self.state.pop1()?;
// let v = self
// .builder
// .build_bitcast(v, self.intrinsics.i64x2_ty, "")
// .into_vector_value();
// let res = self
// .builder
// .build_unsigned_int_to_float(v, self.intrinsics.f64x2_ty, "");
// let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, "");
// self.state.push1(res);
// }
Operator::I32ReinterpretF32 => {
let (v, i) = self.state.pop1_extra()?;
let v = self.apply_pending_canonicalization(v, i);
@@ -5880,10 +5880,8 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> {
let res = self.builder.build_not(v, "");
self.state.push1(res);
}
Operator::I8x16AnyTrue
| Operator::I16x8AnyTrue
| Operator::I32x4AnyTrue
| Operator::I64x2AnyTrue => {
Operator::I8x16AnyTrue | Operator::I16x8AnyTrue | Operator::I32x4AnyTrue => {
// | Operator::I64x2AnyTrue
// Skip canonicalization, it never changes non-zero values to zero or vice versa.
let v = self.state.pop1()?.into_int_value();
let res = self.builder.build_int_compare(
@@ -5900,15 +5898,13 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> {
ExtraInfo::arithmetic_f32() | ExtraInfo::arithmetic_f64(),
);
}
Operator::I8x16AllTrue
| Operator::I16x8AllTrue
| Operator::I32x4AllTrue
| Operator::I64x2AllTrue => {
Operator::I8x16AllTrue | Operator::I16x8AllTrue | Operator::I32x4AllTrue => {
// | Operator::I64x2AllTrue
let vec_ty = match op {
Operator::I8x16AllTrue => self.intrinsics.i8x16_ty,
Operator::I16x8AllTrue => self.intrinsics.i16x8_ty,
Operator::I32x4AllTrue => self.intrinsics.i32x4_ty,
Operator::I64x2AllTrue => self.intrinsics.i64x2_ty,
// Operator::I64x2AllTrue => self.intrinsics.i64x2_ty,
_ => unreachable!(),
};
let (v, i) = self.state.pop1_extra()?;

View File

@@ -8,5 +8,11 @@ is not prone to JIT bombs and also offers great compilation performance
orders of magnitude faster than `wasmer-compiler-cranelift` and
`wasmer-compiler-llvm`, however with a bit slower runtime speed.
> Note: this crate requires on Rust nightly to be compiled, as depends on
`dynasm-rs` and that crate can only be compiled in Nigthly.
The fact that singlepass is not prone to JIT bombs and offers a very
predictable compilation speed makes it ideal for **blockchains** and other
systems where fast and consistent compilation times are very critical.
## Requirements
At the moment, this crate depends on Rust nightly to be compiled, as it uses
`dynasm-rs` which can only be compiled in Nightly.

View File

@@ -8201,8 +8201,8 @@ fn type_to_wp_type(ty: Type) -> WpType {
Type::F32 => WpType::F32,
Type::F64 => WpType::F64,
Type::V128 => WpType::V128,
Type::AnyRef => WpType::AnyRef,
Type::FuncRef => WpType::AnyFunc, // TODO: AnyFunc or Func?
Type::ExternRef => WpType::ExternRef,
Type::FuncRef => WpType::FuncRef, // TODO: FuncRef or Func?
}
}

View File

@@ -120,7 +120,7 @@ impl Compiler for SinglepassCompiler {
.into_iter()
.collect::<PrimaryMap<LocalFunctionIndex, CompiledFunction>>();
Ok(Compilation::new(functions, import_trampolines))
Ok(Compilation::new(functions, import_trampolines, None))
}
fn compile_function_call_trampolines(

View File

@@ -13,7 +13,7 @@ edition = "2018"
[dependencies]
wasmer-runtime = { path = "../runtime", version = "1.0.0-alpha.1" }
wasm-common = { path = "../wasm-common", version = "1.0.0-alpha.1" }
wasmparser = { version = "0.51", optional = true, default-features = false }
wasmparser = { version = "0.57", optional = true, default-features = false }
target-lexicon = { version = "0.10", default-features = false }
enumset = "1.0"
hashbrown = { version = "0.7", optional = true }

View File

@@ -62,6 +62,7 @@ pub trait Compiler {
enable_threads: features.threads,
enable_reference_types: features.reference_types,
enable_bulk_memory: features.bulk_memory,
enable_tail_call: false,
enable_simd: features.simd,
enable_multi_value: features.multi_value,
},

View File

@@ -1,3 +1,6 @@
// This file contains code from external sources.
// Attributions: https://github.com/wasmerio/wasmer-reborn/blob/master/ATTRIBUTIONS.md
//! A `Compilation` contains the compiled function bodies for a WebAssembly
//! module (`CompiledFunction`).
//!
@@ -70,6 +73,28 @@ pub type Functions = PrimaryMap<LocalFunctionIndex, CompiledFunction>;
/// The custom sections for a Compilation.
pub type CustomSections = PrimaryMap<SectionIndex, CustomSection>;
/// The DWARF information for this Compilation.
///
/// It is used for retrieving the unwind information once an exception
/// happens.
/// In the future this structure may also hold other information useful
/// for debugging.
#[cfg_attr(feature = "enable-serde", derive(Deserialize, Serialize))]
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct Dwarf {
/// The section index in the [`Compilation`] that corresponds to the exception frames.
/// More info:
/// https://refspecs.linuxfoundation.org/LSB_3.0.0/LSB-PDA/LSB-PDA/ehframechpt.html
pub eh_frame: SectionIndex,
}
impl Dwarf {
/// Creates a `Dwarf` struct with the corresponding indices for its sections
pub fn new(eh_frame: SectionIndex) -> Self {
Self { eh_frame }
}
}
/// The result of compiling a WebAssembly module's functions.
#[cfg_attr(feature = "enable-serde", derive(Deserialize, Serialize))]
#[derive(Debug, PartialEq, Eq)]
@@ -80,14 +105,21 @@ pub struct Compilation {
/// It will hold the data, for example, for constants used in a
/// function, global variables, rodata_64, hot/cold function partitioning, ...
custom_sections: CustomSections,
/// Section ids corresponding to the Dwarf debug info
debug: Option<Dwarf>,
}
impl Compilation {
/// Creates a compilation artifact from a contiguous function buffer and a set of ranges
pub fn new(functions: Functions, custom_sections: CustomSections) -> Self {
pub fn new(
functions: Functions,
custom_sections: CustomSections,
debug: Option<Dwarf>,
) -> Self {
Self {
functions,
custom_sections,
debug,
}
}
@@ -150,6 +182,11 @@ impl Compilation {
.map(|(_, section)| section.relocations.clone())
.collect::<PrimaryMap<SectionIndex, _>>()
}
/// Returns the Dwarf info.
pub fn get_debug(&self) -> Option<Dwarf> {
self.debug.clone()
}
}
impl<'a> IntoIterator for &'a Compilation {

View File

@@ -72,7 +72,7 @@ pub use crate::address_map::{FunctionAddressMap, InstructionAddressMap};
pub use crate::compiler::{Compiler, CompilerConfig};
pub use crate::error::{CompileError, WasmError, WasmResult};
pub use crate::function::{
Compilation, CompiledFunction, CompiledFunctionFrameInfo, CustomSections, FunctionBody,
Compilation, CompiledFunction, CompiledFunctionFrameInfo, CustomSections, Dwarf, FunctionBody,
Functions,
};
pub use crate::jump_table::{JumpTable, JumpTableOffsets};
@@ -80,8 +80,8 @@ pub use crate::relocation::{Relocation, RelocationKind, RelocationTarget, Reloca
pub use crate::section::{CustomSection, CustomSectionProtection, SectionBody, SectionIndex};
pub use crate::sourceloc::SourceLoc;
pub use crate::target::{
Architecture, BinaryFormat, CallingConvention, CpuFeature, OperatingSystem,
ParseCpuFeatureError, Target, Triple,
Architecture, BinaryFormat, CallingConvention, CpuFeature, Endianness, OperatingSystem,
ParseCpuFeatureError, PointerWidth, Target, Triple,
};
#[cfg(feature = "translator")]
pub use crate::translator::{
@@ -90,7 +90,7 @@ pub use crate::translator::{
ModuleEnvironment, ModuleInfoTranslation, ModuleTranslationState,
};
pub use crate::trap::TrapInformation;
pub use crate::unwind::{CompiledFunctionUnwindInfo, FDERelocEntry, FunctionTableReloc};
pub use crate::unwind::CompiledFunctionUnwindInfo;
pub use wasm_common::Features;

View File

@@ -1,3 +1,6 @@
// This file contains code from external sources.
// Attributions: https://github.com/wasmerio/wasmer-reborn/blob/master/ATTRIBUTIONS.md
//! Source locations.
//!
//! A [`SourceLoc`] determines the position of a certain instruction

View File

@@ -2,7 +2,10 @@
use enumset::{EnumSet, EnumSetType};
use std::str::FromStr;
use std::string::ToString;
pub use target_lexicon::{Architecture, BinaryFormat, CallingConvention, OperatingSystem, Triple};
pub use target_lexicon::{
Architecture, BinaryFormat, CallingConvention, Endianness, OperatingSystem, PointerWidth,
Triple,
};
use thiserror::Error;
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]

View File

@@ -1,3 +1,6 @@
// This file contains code from external sources.
// Attributions: https://github.com/wasmerio/wasmer-reborn/blob/master/ATTRIBUTIONS.md
use super::module::translate_module;
use super::state::ModuleTranslationState;
use crate::lib::std::borrow::ToOwned;

View File

@@ -1,3 +1,6 @@
// This file contains code from external sources.
// Attributions: https://github.com/wasmerio/wasmer-reborn/blob/master/ATTRIBUTIONS.md
//! Translation skeleton that traverses the whole WebAssembly module and call helper functions
//! to deal with each part of it.
use super::environ::ModuleEnvironment;

View File

@@ -1,3 +1,6 @@
// This file contains code from external sources.
// Attributions: https://github.com/wasmerio/wasmer-reborn/blob/master/ATTRIBUTIONS.md
//! Helper functions to gather information for each of the non-function sections of a
//! WebAssembly module.
//!
@@ -39,8 +42,8 @@ pub fn wptype_to_type(ty: wasmparser::Type) -> WasmResult<Type> {
wasmparser::Type::F32 => Ok(Type::F32),
wasmparser::Type::F64 => Ok(Type::F64),
wasmparser::Type::V128 => Ok(Type::V128),
wasmparser::Type::AnyRef => Ok(Type::AnyRef),
wasmparser::Type::AnyFunc => Ok(Type::FuncRef),
wasmparser::Type::ExternRef => Ok(Type::ExternRef),
wasmparser::Type::FuncRef => Ok(Type::FuncRef),
ty => Err(wasm_unsupported!(
"wptype_to_type: wasmparser type {:?}",
ty
@@ -59,11 +62,7 @@ pub fn parse_type_section(
for entry in types {
match entry.map_err(to_wasm_error)? {
WPFunctionType {
form: wasmparser::Type::Func,
params,
returns,
} => {
WPFunctionType { params, returns } => {
let sig_params: Vec<Type> = params
.iter()
.map(|ty| {
@@ -82,12 +81,6 @@ pub fn parse_type_section(
environ.declare_signature(sig)?;
module_translation_state.wasm_types.push((params, returns));
}
ty => {
return Err(wasm_unsupported!(
"unsupported type in type section: {:?}",
ty
))
}
}
}
Ok(())
@@ -238,7 +231,7 @@ pub fn parse_global_section(
Operator::V128Const { value } => {
GlobalInit::V128Const(V128::from(value.bytes().to_vec().as_slice()))
}
Operator::RefNull => GlobalInit::RefNullConst,
Operator::RefNull { ty: _ } => GlobalInit::RefNullConst,
Operator::RefFunc { function_index } => {
GlobalInit::RefFunc(FunctionIndex::from_u32(function_index))
}
@@ -309,7 +302,7 @@ fn read_elems(items: &ElementItems) -> WasmResult<Box<[FunctionIndex]>> {
let mut elems = Vec::with_capacity(usize::try_from(items_reader.get_count()).unwrap());
for item in items_reader {
let elem = match item.map_err(to_wasm_error)? {
ElementItem::Null => FunctionIndex::reserved_value(),
ElementItem::Null(_ty) => FunctionIndex::reserved_value(),
ElementItem::Func(index) => FunctionIndex::from_u32(index),
};
elems.push(elem);
@@ -326,7 +319,7 @@ pub fn parse_element_section<'data>(
for (index, entry) in elements.into_iter().enumerate() {
let Element { kind, items, ty } = entry.map_err(to_wasm_error)?;
if ty != wasmparser::Type::AnyFunc {
if ty != wasmparser::Type::FuncRef {
return Err(wasm_unsupported!(
"unsupported table element type: {:?}",
ty

View File

@@ -1,3 +1,6 @@
// This file contains code from external sources.
// Attributions: https://github.com/wasmerio/wasmer-reborn/blob/master/ATTRIBUTIONS.md
use crate::{wasm_unsupported, WasmResult};
use std::boxed::Box;
use wasm_common::entity::PrimaryMap;
@@ -42,9 +45,8 @@ impl ModuleTranslationState {
wasmparser::Type::F32 => (&[], &[wasmparser::Type::F32]),
wasmparser::Type::F64 => (&[], &[wasmparser::Type::F64]),
wasmparser::Type::V128 => (&[], &[wasmparser::Type::V128]),
wasmparser::Type::AnyRef => (&[], &[wasmparser::Type::AnyRef]),
wasmparser::Type::AnyFunc => (&[], &[wasmparser::Type::AnyFunc]),
wasmparser::Type::NullRef => (&[], &[wasmparser::Type::NullRef]),
wasmparser::Type::ExternRef => (&[], &[wasmparser::Type::ExternRef]),
wasmparser::Type::FuncRef => (&[], &[wasmparser::Type::FuncRef]),
wasmparser::Type::EmptyBlockType => (&[], &[]),
ty => return Err(wasm_unsupported!("blocktype_params_results: type {:?}", ty)),
},

View File

@@ -6,25 +6,9 @@
//!
//! More info: https://en.wikipedia.org/wiki/Call_stack
use crate::lib::std::vec::Vec;
use crate::{Addend, CodeOffset};
#[cfg(feature = "enable-serde")]
use serde::{Deserialize, Serialize};
/// Relocation Entry data
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FDERelocEntry(pub i64, pub usize, pub u8);
/// Relocation entry for unwind info.
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FunctionTableReloc {
/// Entry offest in the code block.
pub offset: CodeOffset,
/// Entry addend relative to the code block.
pub addend: Addend,
}
/// Compiled function unwind information.
///
/// > Note: Windows OS have a different way of representing the [unwind info],
@@ -36,45 +20,8 @@ pub struct FunctionTableReloc {
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum CompiledFunctionUnwindInfo {
/// Windows UNWIND_INFO.
Windows(Vec<u8>),
WindowsX64(Vec<u8>),
/// Unix frame layout info.
FrameLayout(Vec<u8>, usize, Vec<FDERelocEntry>),
}
impl CompiledFunctionUnwindInfo {
/// Retuns true is no unwind info data.
pub fn is_empty(&self) -> bool {
match self {
Self::Windows(d) => d.is_empty(),
Self::FrameLayout(c, _, _) => c.is_empty(),
}
}
/// Returns size of serilized unwind info.
pub fn len(&self) -> usize {
match self {
Self::Windows(d) => d.len(),
Self::FrameLayout(c, _, _) => c.len(),
}
}
/// Serializes data into byte array.
pub fn serialize(&self, dest: &mut [u8], relocs: &mut Vec<FunctionTableReloc>) {
match self {
Self::Windows(d) => {
dest.copy_from_slice(d);
}
Self::FrameLayout(code, _fde_offset, r) => {
dest.copy_from_slice(code);
r.iter().for_each(move |r| {
assert_eq!(r.2, 8);
relocs.push(FunctionTableReloc {
offset: r.1 as _,
addend: r.0,
})
});
}
}
}
/// The unwind info is added to the Dwarf section in `Compilation`.
Dwarf,
}

View File

@@ -15,7 +15,7 @@ lazy_static = "1.4"
libc = "0.2.60"
log = "0.4"
time = "0.1"
wasmer-runtime-core = { path = "../runtime-core", version = "1.0.0-alpha.1" }
wasmer = { path = "../api", version = "1.0.0-alpha.1" }
[target.'cfg(windows)'.dependencies]
getrandom = "0.1"

View File

@@ -1,9 +1,9 @@
use crate::emscripten_target;
use wasmer_runtime_core::vm::Ctx;
use crate::EmEnv;
///emscripten: _llvm_bswap_i64
pub fn _llvm_bswap_i64(_ctx: &mut Ctx, _low: i32, high: i32) -> i32 {
pub fn _llvm_bswap_i64(ctx: &mut EmEnv, _low: i32, high: i32) -> i32 {
debug!("emscripten::_llvm_bswap_i64");
emscripten_target::setTempRet0(_ctx, _low.swap_bytes());
emscripten_target::setTempRet0(ctx, _low.swap_bytes());
high.swap_bytes()
}

View File

@@ -1,35 +1,35 @@
#![allow(non_snake_case)]
use crate::env::get_emscripten_data;
use crate::EmEnv;
#[cfg(target_os = "linux")]
use libc::getdtablesize;
use wasmer_runtime_core::vm::Ctx;
pub fn asm_const_i(_ctx: &mut Ctx, _val: i32) -> i32 {
pub fn asm_const_i(_ctx: &mut EmEnv, _val: i32) -> i32 {
debug!("emscripten::asm_const_i: {}", _val);
0
}
pub fn exit_with_live_runtime(_ctx: &mut Ctx) {
pub fn exit_with_live_runtime(_ctx: &mut EmEnv) {
debug!("emscripten::exit_with_live_runtime");
}
pub fn setTempRet0(ctx: &mut Ctx, val: i32) {
pub fn setTempRet0(ctx: &mut EmEnv, val: i32) {
trace!("emscripten::setTempRet0: {}", val);
get_emscripten_data(ctx).temp_ret_0 = val;
}
pub fn getTempRet0(ctx: &mut Ctx) -> i32 {
pub fn getTempRet0(ctx: &mut EmEnv) -> i32 {
trace!("emscripten::getTempRet0");
get_emscripten_data(ctx).temp_ret_0
}
pub fn _alarm(_ctx: &mut Ctx, _seconds: u32) -> i32 {
pub fn _alarm(_ctx: &mut EmEnv, _seconds: u32) -> i32 {
debug!("emscripten::_alarm({})", _seconds);
0
}
pub fn _atexit(_ctx: &mut Ctx, _func: i32) -> i32 {
pub fn _atexit(_ctx: &mut EmEnv, _func: i32) -> i32 {
debug!("emscripten::_atexit");
// TODO: implement atexit properly
// __ATEXIT__.unshift({
@@ -38,38 +38,38 @@ pub fn _atexit(_ctx: &mut Ctx, _func: i32) -> i32 {
// });
0
}
pub fn __Unwind_Backtrace(_ctx: &mut Ctx, _a: i32, _b: i32) -> i32 {
pub fn __Unwind_Backtrace(_ctx: &mut EmEnv, _a: i32, _b: i32) -> i32 {
debug!("emscripten::__Unwind_Backtrace");
0
}
pub fn __Unwind_FindEnclosingFunction(_ctx: &mut Ctx, _a: i32) -> i32 {
pub fn __Unwind_FindEnclosingFunction(_ctx: &mut EmEnv, _a: i32) -> i32 {
debug!("emscripten::__Unwind_FindEnclosingFunction");
0
}
pub fn __Unwind_GetIPInfo(_ctx: &mut Ctx, _a: i32, _b: i32) -> i32 {
pub fn __Unwind_GetIPInfo(_ctx: &mut EmEnv, _a: i32, _b: i32) -> i32 {
debug!("emscripten::__Unwind_GetIPInfo");
0
}
pub fn ___cxa_find_matching_catch_2(_ctx: &mut Ctx) -> i32 {
pub fn ___cxa_find_matching_catch_2(_ctx: &mut EmEnv) -> i32 {
debug!("emscripten::___cxa_find_matching_catch_2");
0
}
pub fn ___cxa_find_matching_catch_3(_ctx: &mut Ctx, _a: i32) -> i32 {
pub fn ___cxa_find_matching_catch_3(_ctx: &mut EmEnv, _a: i32) -> i32 {
debug!("emscripten::___cxa_find_matching_catch_3");
0
}
pub fn ___cxa_free_exception(_ctx: &mut Ctx, _a: i32) {
pub fn ___cxa_free_exception(_ctx: &mut EmEnv, _a: i32) {
debug!("emscripten::___cxa_free_exception");
}
pub fn ___resumeException(_ctx: &mut Ctx, _a: i32) {
pub fn ___resumeException(_ctx: &mut EmEnv, _a: i32) {
debug!("emscripten::___resumeException");
}
pub fn _dladdr(_ctx: &mut Ctx, _a: i32, _b: i32) -> i32 {
pub fn _dladdr(_ctx: &mut EmEnv, _a: i32, _b: i32) -> i32 {
debug!("emscripten::_dladdr");
0
}
pub fn ___gxx_personality_v0(
_ctx: &mut Ctx,
_ctx: &mut EmEnv,
_a: i32,
_b: i32,
_c: i32,
@@ -82,25 +82,25 @@ pub fn ___gxx_personality_v0(
}
#[cfg(target_os = "linux")]
pub fn _getdtablesize(_ctx: &mut Ctx) -> i32 {
pub fn _getdtablesize(_ctx: &mut EmEnv) -> i32 {
debug!("emscripten::getdtablesize");
unsafe { getdtablesize() }
}
#[cfg(not(target_os = "linux"))]
pub fn _getdtablesize(_ctx: &mut Ctx) -> i32 {
pub fn _getdtablesize(_ctx: &mut EmEnv) -> i32 {
debug!("emscripten::getdtablesize");
-1
}
pub fn _gethostbyaddr(_ctx: &mut Ctx, _addr: i32, _addrlen: i32, _atype: i32) -> i32 {
pub fn _gethostbyaddr(_ctx: &mut EmEnv, _addr: i32, _addrlen: i32, _atype: i32) -> i32 {
debug!("emscripten::gethostbyaddr");
0
}
pub fn _gethostbyname(_ctx: &mut Ctx, _name: i32) -> i32 {
pub fn _gethostbyname(_ctx: &mut EmEnv, _name: i32) -> i32 {
debug!("emscripten::gethostbyname_r");
0
}
pub fn _gethostbyname_r(
_ctx: &mut Ctx,
_ctx: &mut EmEnv,
_name: i32,
_ret: i32,
_buf: i32,
@@ -112,12 +112,12 @@ pub fn _gethostbyname_r(
0
}
// NOTE: php.js has proper impl; libc has proper impl for linux
pub fn _getloadavg(_ctx: &mut Ctx, _loadavg: i32, _nelem: i32) -> i32 {
pub fn _getloadavg(_ctx: &mut EmEnv, _loadavg: i32, _nelem: i32) -> i32 {
debug!("emscripten::getloadavg");
0
}
pub fn _getnameinfo(
_ctx: &mut Ctx,
_ctx: &mut EmEnv,
_addr: i32,
_addrlen: i32,
_host: i32,
@@ -170,61 +170,61 @@ macro_rules! invoke_no_return {
}
// Invoke functions
pub fn invoke_i(ctx: &mut Ctx, index: i32) -> i32 {
pub fn invoke_i(ctx: &mut EmEnv, index: i32) -> i32 {
debug!("emscripten::invoke_i");
invoke!(ctx, dyn_call_i, index)
}
pub fn invoke_ii(ctx: &mut Ctx, index: i32, a1: i32) -> i32 {
pub fn invoke_ii(ctx: &mut EmEnv, index: i32, a1: i32) -> i32 {
debug!("emscripten::invoke_ii");
invoke!(ctx, dyn_call_ii, index, a1)
}
pub fn invoke_iii(ctx: &mut Ctx, index: i32, a1: i32, a2: i32) -> i32 {
pub fn invoke_iii(ctx: &mut EmEnv, index: i32, a1: i32, a2: i32) -> i32 {
debug!("emscripten::invoke_iii");
invoke!(ctx, dyn_call_iii, index, a1, a2)
}
pub fn invoke_iiii(ctx: &mut Ctx, index: i32, a1: i32, a2: i32, a3: i32) -> i32 {
pub fn invoke_iiii(ctx: &mut EmEnv, index: i32, a1: i32, a2: i32, a3: i32) -> i32 {
debug!("emscripten::invoke_iiii");
invoke!(ctx, dyn_call_iiii, index, a1, a2, a3)
}
pub fn invoke_iifi(ctx: &mut Ctx, index: i32, a1: i32, a2: f64, a3: i32) -> i32 {
pub fn invoke_iifi(ctx: &mut EmEnv, index: i32, a1: i32, a2: f64, a3: i32) -> i32 {
debug!("emscripten::invoke_iifi");
invoke!(ctx, dyn_call_iifi, index, a1, a2, a3)
}
pub fn invoke_v(ctx: &mut Ctx, index: i32) {
pub fn invoke_v(ctx: &mut EmEnv, index: i32) {
debug!("emscripten::invoke_v");
invoke_no_return!(ctx, dyn_call_v, index);
}
pub fn invoke_vi(ctx: &mut Ctx, index: i32, a1: i32) {
pub fn invoke_vi(ctx: &mut EmEnv, index: i32, a1: i32) {
debug!("emscripten::invoke_vi");
invoke_no_return!(ctx, dyn_call_vi, index, a1);
}
pub fn invoke_vii(ctx: &mut Ctx, index: i32, a1: i32, a2: i32) {
pub fn invoke_vii(ctx: &mut EmEnv, index: i32, a1: i32, a2: i32) {
debug!("emscripten::invoke_vii");
invoke_no_return!(ctx, dyn_call_vii, index, a1, a2);
}
pub fn invoke_viii(ctx: &mut Ctx, index: i32, a1: i32, a2: i32, a3: i32) {
pub fn invoke_viii(ctx: &mut EmEnv, index: i32, a1: i32, a2: i32, a3: i32) {
debug!("emscripten::invoke_viii");
invoke_no_return!(ctx, dyn_call_viii, index, a1, a2, a3);
}
pub fn invoke_viiii(ctx: &mut Ctx, index: i32, a1: i32, a2: i32, a3: i32, a4: i32) {
pub fn invoke_viiii(ctx: &mut EmEnv, index: i32, a1: i32, a2: i32, a3: i32, a4: i32) {
debug!("emscripten::invoke_viiii");
invoke_no_return!(ctx, dyn_call_viiii, index, a1, a2, a3, a4);
}
pub fn invoke_dii(ctx: &mut Ctx, index: i32, a1: i32, a2: i32) -> f64 {
pub fn invoke_dii(ctx: &mut EmEnv, index: i32, a1: i32, a2: i32) -> f64 {
debug!("emscripten::invoke_dii");
invoke!(ctx, dyn_call_dii, index, a1, a2)
}
pub fn invoke_diiii(ctx: &mut Ctx, index: i32, a1: i32, a2: i32, a3: i32, a4: i32) -> f64 {
pub fn invoke_diiii(ctx: &mut EmEnv, index: i32, a1: i32, a2: i32, a3: i32, a4: i32) -> f64 {
debug!("emscripten::invoke_diiii");
invoke!(ctx, dyn_call_diiii, index, a1, a2, a3, a4)
}
pub fn invoke_iiiii(ctx: &mut Ctx, index: i32, a1: i32, a2: i32, a3: i32, a4: i32) -> i32 {
pub fn invoke_iiiii(ctx: &mut EmEnv, index: i32, a1: i32, a2: i32, a3: i32, a4: i32) -> i32 {
debug!("emscripten::invoke_iiiii");
invoke!(ctx, dyn_call_iiiii, index, a1, a2, a3, a4)
}
pub fn invoke_iiiiii(
ctx: &mut Ctx,
ctx: &mut EmEnv,
index: i32,
a1: i32,
a2: i32,
@@ -236,7 +236,7 @@ pub fn invoke_iiiiii(
invoke!(ctx, dyn_call_iiiiii, index, a1, a2, a3, a4, a5)
}
pub fn invoke_iiiiiii(
ctx: &mut Ctx,
ctx: &mut EmEnv,
index: i32,
a1: i32,
a2: i32,
@@ -249,7 +249,7 @@ pub fn invoke_iiiiiii(
invoke!(ctx, dyn_call_iiiiiii, index, a1, a2, a3, a4, a5, a6)
}
pub fn invoke_iiiiiiii(
ctx: &mut Ctx,
ctx: &mut EmEnv,
index: i32,
a1: i32,
a2: i32,
@@ -263,7 +263,7 @@ pub fn invoke_iiiiiiii(
invoke!(ctx, dyn_call_iiiiiiii, index, a1, a2, a3, a4, a5, a6, a7)
}
pub fn invoke_iiiiiiiii(
ctx: &mut Ctx,
ctx: &mut EmEnv,
index: i32,
a1: i32,
a2: i32,
@@ -290,7 +290,7 @@ pub fn invoke_iiiiiiiii(
)
}
pub fn invoke_iiiiiiiiii(
ctx: &mut Ctx,
ctx: &mut EmEnv,
index: i32,
a1: i32,
a2: i32,
@@ -319,7 +319,7 @@ pub fn invoke_iiiiiiiiii(
)
}
pub fn invoke_iiiiiiiiiii(
ctx: &mut Ctx,
ctx: &mut EmEnv,
index: i32,
a1: i32,
a2: i32,
@@ -349,16 +349,16 @@ pub fn invoke_iiiiiiiiiii(
a10
)
}
pub fn invoke_vd(ctx: &mut Ctx, index: i32, a1: f64) {
pub fn invoke_vd(ctx: &mut EmEnv, index: i32, a1: f64) {
debug!("emscripten::invoke_vd");
invoke_no_return!(ctx, dyn_call_vd, index, a1)
}
pub fn invoke_viiiii(ctx: &mut Ctx, index: i32, a1: i32, a2: i32, a3: i32, a4: i32, a5: i32) {
pub fn invoke_viiiii(ctx: &mut EmEnv, index: i32, a1: i32, a2: i32, a3: i32, a4: i32, a5: i32) {
debug!("emscripten::invoke_viiiii");
invoke_no_return!(ctx, dyn_call_viiiii, index, a1, a2, a3, a4, a5)
}
pub fn invoke_viiiiii(
ctx: &mut Ctx,
ctx: &mut EmEnv,
index: i32,
a1: i32,
a2: i32,
@@ -371,7 +371,7 @@ pub fn invoke_viiiiii(
invoke_no_return!(ctx, dyn_call_viiiiii, index, a1, a2, a3, a4, a5, a6)
}
pub fn invoke_viiiiiii(
ctx: &mut Ctx,
ctx: &mut EmEnv,
index: i32,
a1: i32,
a2: i32,
@@ -385,7 +385,7 @@ pub fn invoke_viiiiiii(
invoke_no_return!(ctx, dyn_call_viiiiiii, index, a1, a2, a3, a4, a5, a6, a7)
}
pub fn invoke_viiiiiiii(
ctx: &mut Ctx,
ctx: &mut EmEnv,
index: i32,
a1: i32,
a2: i32,
@@ -412,7 +412,7 @@ pub fn invoke_viiiiiiii(
)
}
pub fn invoke_viiiiiiiii(
ctx: &mut Ctx,
ctx: &mut EmEnv,
index: i32,
a1: i32,
a2: i32,
@@ -441,7 +441,7 @@ pub fn invoke_viiiiiiiii(
)
}
pub fn invoke_viiiiiiiiii(
ctx: &mut Ctx,
ctx: &mut EmEnv,
index: i32,
a1: i32,
a2: i32,
@@ -472,23 +472,23 @@ pub fn invoke_viiiiiiiiii(
)
}
pub fn invoke_iij(ctx: &mut Ctx, index: i32, a1: i32, a2: i32, a3: i32) -> i32 {
pub fn invoke_iij(ctx: &mut EmEnv, index: i32, a1: i32, a2: i32, a3: i32) -> i32 {
debug!("emscripten::invoke_iij");
invoke!(ctx, dyn_call_iij, index, a1, a2, a3)
}
pub fn invoke_iji(ctx: &mut Ctx, index: i32, a1: i32, a2: i32, a3: i32) -> i32 {
pub fn invoke_iji(ctx: &mut EmEnv, index: i32, a1: i32, a2: i32, a3: i32) -> i32 {
debug!("emscripten::invoke_iji");
invoke!(ctx, dyn_call_iji, index, a1, a2, a3)
}
pub fn invoke_iiji(ctx: &mut Ctx, index: i32, a1: i32, a2: i32, a3: i32, a4: i32) -> i32 {
pub fn invoke_iiji(ctx: &mut EmEnv, index: i32, a1: i32, a2: i32, a3: i32, a4: i32) -> i32 {
debug!("emscripten::invoke_iiji");
invoke!(ctx, dyn_call_iiji, index, a1, a2, a3, a4)
}
pub fn invoke_iiijj(
ctx: &mut Ctx,
ctx: &mut EmEnv,
index: i32,
a1: i32,
a2: i32,
@@ -500,7 +500,7 @@ pub fn invoke_iiijj(
debug!("emscripten::invoke_iiijj");
invoke!(ctx, dyn_call_iiijj, index, a1, a2, a3, a4, a5, a6)
}
pub fn invoke_j(ctx: &mut Ctx, index: i32) -> i32 {
pub fn invoke_j(ctx: &mut EmEnv, index: i32) -> i32 {
debug!("emscripten::invoke_j");
if let Some(dyn_call_j) = &get_emscripten_data(ctx).dyn_call_j {
dyn_call_j.call(index).unwrap()
@@ -508,7 +508,7 @@ pub fn invoke_j(ctx: &mut Ctx, index: i32) -> i32 {
panic!("dyn_call_j is set to None");
}
}
pub fn invoke_ji(ctx: &mut Ctx, index: i32, a1: i32) -> i32 {
pub fn invoke_ji(ctx: &mut EmEnv, index: i32, a1: i32) -> i32 {
debug!("emscripten::invoke_ji");
if let Some(dyn_call_ji) = &get_emscripten_data(ctx).dyn_call_ji {
dyn_call_ji.call(index, a1).unwrap()
@@ -516,7 +516,7 @@ pub fn invoke_ji(ctx: &mut Ctx, index: i32, a1: i32) -> i32 {
panic!("dyn_call_ji is set to None");
}
}
pub fn invoke_jii(ctx: &mut Ctx, index: i32, a1: i32, a2: i32) -> i32 {
pub fn invoke_jii(ctx: &mut EmEnv, index: i32, a1: i32, a2: i32) -> i32 {
debug!("emscripten::invoke_jii");
if let Some(dyn_call_jii) = &get_emscripten_data(ctx).dyn_call_jii {
dyn_call_jii.call(index, a1, a2).unwrap()
@@ -525,7 +525,7 @@ pub fn invoke_jii(ctx: &mut Ctx, index: i32, a1: i32, a2: i32) -> i32 {
}
}
pub fn invoke_jij(ctx: &mut Ctx, index: i32, a1: i32, a2: i32, a3: i32) -> i32 {
pub fn invoke_jij(ctx: &mut EmEnv, index: i32, a1: i32, a2: i32, a3: i32) -> i32 {
debug!("emscripten::invoke_jij");
if let Some(dyn_call_jij) = &get_emscripten_data(ctx).dyn_call_jij {
dyn_call_jij.call(index, a1, a2, a3).unwrap()
@@ -533,7 +533,7 @@ pub fn invoke_jij(ctx: &mut Ctx, index: i32, a1: i32, a2: i32, a3: i32) -> i32 {
panic!("dyn_call_jij is set to None");
}
}
pub fn invoke_jjj(ctx: &mut Ctx, index: i32, a1: i32, a2: i32, a3: i32, a4: i32) -> i32 {
pub fn invoke_jjj(ctx: &mut EmEnv, index: i32, a1: i32, a2: i32, a3: i32, a4: i32) -> i32 {
debug!("emscripten::invoke_jjj");
if let Some(dyn_call_jjj) = &get_emscripten_data(ctx).dyn_call_jjj {
dyn_call_jjj.call(index, a1, a2, a3, a4).unwrap()
@@ -541,7 +541,7 @@ pub fn invoke_jjj(ctx: &mut Ctx, index: i32, a1: i32, a2: i32, a3: i32, a4: i32)
panic!("dyn_call_jjj is set to None");
}
}
pub fn invoke_viiij(ctx: &mut Ctx, index: i32, a1: i32, a2: i32, a3: i32, a4: i32, a5: i32) {
pub fn invoke_viiij(ctx: &mut EmEnv, index: i32, a1: i32, a2: i32, a3: i32, a4: i32, a5: i32) {
debug!("emscripten::invoke_viiij");
if let Some(dyn_call_viiij) = &get_emscripten_data(ctx).dyn_call_viiij {
dyn_call_viiij.call(index, a1, a2, a3, a4, a5).unwrap();
@@ -550,7 +550,7 @@ pub fn invoke_viiij(ctx: &mut Ctx, index: i32, a1: i32, a2: i32, a3: i32, a4: i3
}
}
pub fn invoke_viiijiiii(
ctx: &mut Ctx,
ctx: &mut EmEnv,
index: i32,
a1: i32,
a2: i32,
@@ -572,7 +572,7 @@ pub fn invoke_viiijiiii(
}
}
pub fn invoke_viiijiiiiii(
ctx: &mut Ctx,
ctx: &mut EmEnv,
index: i32,
a1: i32,
a2: i32,
@@ -595,7 +595,7 @@ pub fn invoke_viiijiiiiii(
panic!("dyn_call_viiijiiiiii is set to None");
}
}
pub fn invoke_viij(ctx: &mut Ctx, index: i32, a1: i32, a2: i32, a3: i32, a4: i32) {
pub fn invoke_viij(ctx: &mut EmEnv, index: i32, a1: i32, a2: i32, a3: i32, a4: i32) {
debug!("emscripten::invoke_viij");
if let Some(dyn_call_viij) = &get_emscripten_data(ctx).dyn_call_viij {
dyn_call_viij.call(index, a1, a2, a3, a4).unwrap();
@@ -603,7 +603,7 @@ pub fn invoke_viij(ctx: &mut Ctx, index: i32, a1: i32, a2: i32, a3: i32, a4: i32
panic!("dyn_call_viij is set to None");
}
}
pub fn invoke_viiji(ctx: &mut Ctx, index: i32, a1: i32, a2: i32, a3: i32, a4: i32, a5: i32) {
pub fn invoke_viiji(ctx: &mut EmEnv, index: i32, a1: i32, a2: i32, a3: i32, a4: i32, a5: i32) {
debug!("emscripten::invoke_viiji");
if let Some(dyn_call_viiji) = &get_emscripten_data(ctx).dyn_call_viiji {
dyn_call_viiji.call(index, a1, a2, a3, a4, a5).unwrap();
@@ -612,7 +612,7 @@ pub fn invoke_viiji(ctx: &mut Ctx, index: i32, a1: i32, a2: i32, a3: i32, a4: i3
}
}
pub fn invoke_viijiii(
ctx: &mut Ctx,
ctx: &mut EmEnv,
index: i32,
a1: i32,
a2: i32,
@@ -632,7 +632,7 @@ pub fn invoke_viijiii(
}
}
pub fn invoke_viijj(
ctx: &mut Ctx,
ctx: &mut EmEnv,
index: i32,
a1: i32,
a2: i32,
@@ -648,7 +648,7 @@ pub fn invoke_viijj(
panic!("dyn_call_viijj is set to None");
}
}
pub fn invoke_vj(ctx: &mut Ctx, index: i32, a1: i32, a2: i32) {
pub fn invoke_vj(ctx: &mut EmEnv, index: i32, a1: i32, a2: i32) {
debug!("emscripten::invoke_vj");
if let Some(dyn_call_vj) = &get_emscripten_data(ctx).dyn_call_vj {
dyn_call_vj.call(index, a1, a2).unwrap();
@@ -656,11 +656,11 @@ pub fn invoke_vj(ctx: &mut Ctx, index: i32, a1: i32, a2: i32) {
panic!("dyn_call_vj is set to None");
}
}
pub fn invoke_vjji(ctx: &mut Ctx, index: i32, a1: i32, a2: i32, a3: i32, a4: i32, a5: i32) {
pub fn invoke_vjji(ctx: &mut EmEnv, index: i32, a1: i32, a2: i32, a3: i32, a4: i32, a5: i32) {
debug!("emscripten::invoke_vjji");
invoke_no_return!(ctx, dyn_call_vjji, index, a1, a2, a3, a4, a5)
}
pub fn invoke_vij(ctx: &mut Ctx, index: i32, a1: i32, a2: i32, a3: i32) {
pub fn invoke_vij(ctx: &mut EmEnv, index: i32, a1: i32, a2: i32, a3: i32) {
debug!("emscripten::invoke_vij");
if let Some(dyn_call_vij) = &get_emscripten_data(ctx).dyn_call_vij {
dyn_call_vij.call(index, a1, a2, a3).unwrap();
@@ -668,7 +668,7 @@ pub fn invoke_vij(ctx: &mut Ctx, index: i32, a1: i32, a2: i32, a3: i32) {
panic!("dyn_call_vij is set to None");
}
}
pub fn invoke_viji(ctx: &mut Ctx, index: i32, a1: i32, a2: i32, a3: i32, a4: i32) {
pub fn invoke_viji(ctx: &mut EmEnv, index: i32, a1: i32, a2: i32, a3: i32, a4: i32) {
debug!("emscripten::invoke_viji");
if let Some(dyn_call_viji) = &get_emscripten_data(ctx).dyn_call_viji {
dyn_call_viji.call(index, a1, a2, a3, a4).unwrap()
@@ -677,7 +677,7 @@ pub fn invoke_viji(ctx: &mut Ctx, index: i32, a1: i32, a2: i32, a3: i32, a4: i32
}
}
pub fn invoke_vijiii(
ctx: &mut Ctx,
ctx: &mut EmEnv,
index: i32,
a1: i32,
a2: i32,
@@ -693,7 +693,7 @@ pub fn invoke_vijiii(
panic!("dyn_call_vijiii is set to None");
}
}
pub fn invoke_vijj(ctx: &mut Ctx, index: i32, a1: i32, a2: i32, a3: i32, a4: i32, a5: i32) {
pub fn invoke_vijj(ctx: &mut EmEnv, index: i32, a1: i32, a2: i32, a3: i32, a4: i32, a5: i32) {
debug!("emscripten::invoke_vijj");
if let Some(dyn_call_vijj) = &get_emscripten_data(ctx).dyn_call_vijj {
dyn_call_vijj.call(index, a1, a2, a3, a4, a5).unwrap()
@@ -701,20 +701,20 @@ pub fn invoke_vijj(ctx: &mut Ctx, index: i32, a1: i32, a2: i32, a3: i32, a4: i32
panic!("dyn_call_vijj is set to None");
}
}
pub fn invoke_vidd(ctx: &mut Ctx, index: i32, a1: i32, a2: f64, a3: f64) {
pub fn invoke_vidd(ctx: &mut EmEnv, index: i32, a1: i32, a2: f64, a3: f64) {
debug!("emscripten::invoke_viid");
invoke_no_return!(ctx, dyn_call_vidd, index, a1, a2, a3);
}
pub fn invoke_viid(ctx: &mut Ctx, index: i32, a1: i32, a2: i32, a3: f64) {
pub fn invoke_viid(ctx: &mut EmEnv, index: i32, a1: i32, a2: i32, a3: f64) {
debug!("emscripten::invoke_viid");
invoke_no_return!(ctx, dyn_call_viid, index, a1, a2, a3);
}
pub fn invoke_viidii(ctx: &mut Ctx, index: i32, a1: i32, a2: i32, a3: f64, a4: i32, a5: i32) {
pub fn invoke_viidii(ctx: &mut EmEnv, index: i32, a1: i32, a2: i32, a3: f64, a4: i32, a5: i32) {
debug!("emscripten::invoke_viidii");
invoke_no_return!(ctx, dyn_call_viidii, index, a1, a2, a3, a4, a5);
}
pub fn invoke_viidddddddd(
ctx: &mut Ctx,
ctx: &mut EmEnv,
index: i32,
a1: i32,
a2: i32,

View File

@@ -19,9 +19,11 @@ use crate::{
};
use std::os::raw::c_int;
use wasmer_runtime_core::{types::ValueType, vm::Ctx};
pub fn call_malloc(ctx: &mut Ctx, size: u32) -> u32 {
use crate::EmEnv;
use wasmer::ValueType;
pub fn call_malloc(ctx: &mut EmEnv, size: u32) -> u32 {
get_emscripten_data(ctx)
.malloc
.as_ref()
@@ -31,11 +33,11 @@ pub fn call_malloc(ctx: &mut Ctx, size: u32) -> u32 {
}
#[warn(dead_code)]
pub fn call_malloc_with_cast<T: Copy, Ty>(ctx: &mut Ctx, size: u32) -> WasmPtr<T, Ty> {
pub fn call_malloc_with_cast<T: Copy, Ty>(ctx: &mut EmEnv, size: u32) -> WasmPtr<T, Ty> {
WasmPtr::new(call_malloc(ctx, size))
}
pub fn call_memalign(ctx: &mut Ctx, alignment: u32, size: u32) -> u32 {
pub fn call_memalign(ctx: &mut EmEnv, alignment: u32, size: u32) -> u32 {
if let Some(memalign) = &get_emscripten_data(ctx).memalign {
memalign.call(alignment, size).unwrap()
} else {
@@ -43,7 +45,7 @@ pub fn call_memalign(ctx: &mut Ctx, alignment: u32, size: u32) -> u32 {
}
}
pub fn call_memset(ctx: &mut Ctx, pointer: u32, value: u32, size: u32) -> u32 {
pub fn call_memset(ctx: &mut EmEnv, pointer: u32, value: u32, size: u32) -> u32 {
get_emscripten_data(ctx)
.memset
.as_ref()
@@ -52,16 +54,16 @@ pub fn call_memset(ctx: &mut Ctx, pointer: u32, value: u32, size: u32) -> u32 {
.unwrap()
}
pub(crate) fn get_emscripten_data(ctx: &mut Ctx) -> &mut EmscriptenData {
unsafe { &mut *(ctx.data as *mut EmscriptenData) }
pub(crate) fn get_emscripten_data<'a>(ctx: &'a mut EmEnv) -> &'a mut EmscriptenData<'static> {
unsafe { &mut *ctx.data }
}
pub fn _getpagesize(_ctx: &mut Ctx) -> u32 {
pub fn _getpagesize(_ctx: &mut EmEnv) -> u32 {
debug!("emscripten::_getpagesize");
16384
}
pub fn _times(ctx: &mut Ctx, buffer: u32) -> u32 {
pub fn _times(ctx: &mut EmEnv, buffer: u32) -> u32 {
if buffer != 0 {
call_memset(ctx, buffer, 0, 16);
}
@@ -69,7 +71,7 @@ pub fn _times(ctx: &mut Ctx, buffer: u32) -> u32 {
}
#[allow(clippy::cast_ptr_alignment)]
pub fn ___build_environment(ctx: &mut Ctx, environ: c_int) {
pub fn ___build_environment(ctx: &mut EmEnv, environ: c_int) {
debug!("emscripten::___build_environment {}", environ);
const MAX_ENV_VALUES: u32 = 64;
const TOTAL_ENV_SIZE: u32 = 1024;
@@ -121,13 +123,13 @@ pub fn ___build_environment(ctx: &mut Ctx, environ: c_int) {
}
}
pub fn ___assert_fail(_ctx: &mut Ctx, _a: c_int, _b: c_int, _c: c_int, _d: c_int) {
pub fn ___assert_fail(_ctx: &mut EmEnv, _a: c_int, _b: c_int, _c: c_int, _d: c_int) {
debug!("emscripten::___assert_fail {} {} {} {}", _a, _b, _c, _d);
// TODO: Implement like emscripten expects regarding memory/page size
// TODO raise an error
}
pub fn _pathconf(ctx: &mut Ctx, path_addr: c_int, name: c_int) -> c_int {
pub fn _pathconf(ctx: &mut EmEnv, path_addr: c_int, name: c_int) -> c_int {
debug!(
"emscripten::_pathconf {} {} - UNIMPLEMENTED",
path_addr, name
@@ -148,7 +150,7 @@ pub fn _pathconf(ctx: &mut Ctx, path_addr: c_int, name: c_int) -> c_int {
}
}
pub fn _fpathconf(_ctx: &mut Ctx, _fildes: c_int, name: c_int) -> c_int {
pub fn _fpathconf(_ctx: &mut EmEnv, _fildes: c_int, name: c_int) -> c_int {
debug!("emscripten::_fpathconf {} {}", _fildes, name);
match name {
0 => 32000,

View File

@@ -11,11 +11,11 @@ use std::os::raw::c_char;
use crate::env::{call_malloc, call_malloc_with_cast, EmAddrInfo, EmSockAddr};
use crate::ptr::{Array, WasmPtr};
use crate::utils::{copy_cstr_into_wasm, copy_terminated_array_of_cstrs};
use wasmer_runtime_core::vm::Ctx;
use crate::EmEnv;
// #[no_mangle]
/// emscripten: _getenv // (name: *const char) -> *const c_char;
pub fn _getenv(ctx: &mut Ctx, name: i32) -> u32 {
pub fn _getenv(ctx: &mut EmEnv, name: i32) -> u32 {
debug!("emscripten::_getenv");
let name_addr = emscripten_memory_pointer!(ctx.memory(0), name) as *const c_char;
@@ -31,7 +31,7 @@ pub fn _getenv(ctx: &mut Ctx, name: i32) -> u32 {
}
/// emscripten: _setenv // (name: *const char, name: *const value, overwrite: int);
pub fn _setenv(ctx: &mut Ctx, name: c_int, value: c_int, overwrite: c_int) -> c_int {
pub fn _setenv(ctx: &mut EmEnv, name: c_int, value: c_int, overwrite: c_int) -> c_int {
debug!("emscripten::_setenv");
let name_addr = emscripten_memory_pointer!(ctx.memory(0), name) as *const c_char;
@@ -44,7 +44,7 @@ pub fn _setenv(ctx: &mut Ctx, name: c_int, value: c_int, overwrite: c_int) -> c_
}
/// emscripten: _putenv // (name: *const char);
pub fn _putenv(ctx: &mut Ctx, name: c_int) -> c_int {
pub fn _putenv(ctx: &mut EmEnv, name: c_int) -> c_int {
debug!("emscripten::_putenv");
let name_addr = emscripten_memory_pointer!(ctx.memory(0), name) as *const c_char;
@@ -55,7 +55,7 @@ pub fn _putenv(ctx: &mut Ctx, name: c_int) -> c_int {
}
/// emscripten: _unsetenv // (name: *const char);
pub fn _unsetenv(ctx: &mut Ctx, name: c_int) -> c_int {
pub fn _unsetenv(ctx: &mut EmEnv, name: c_int) -> c_int {
debug!("emscripten::_unsetenv");
let name_addr = emscripten_memory_pointer!(ctx.memory(0), name) as *const c_char;
@@ -66,7 +66,7 @@ pub fn _unsetenv(ctx: &mut Ctx, name: c_int) -> c_int {
}
#[allow(clippy::cast_ptr_alignment)]
pub fn _getpwnam(ctx: &mut Ctx, name_ptr: c_int) -> c_int {
pub fn _getpwnam(ctx: &mut EmEnv, name_ptr: c_int) -> c_int {
debug!("emscripten::_getpwnam {}", name_ptr);
#[cfg(feature = "debug")]
let _ = name_ptr;
@@ -106,7 +106,7 @@ pub fn _getpwnam(ctx: &mut Ctx, name_ptr: c_int) -> c_int {
}
#[allow(clippy::cast_ptr_alignment)]
pub fn _getgrnam(ctx: &mut Ctx, name_ptr: c_int) -> c_int {
pub fn _getgrnam(ctx: &mut EmEnv, name_ptr: c_int) -> c_int {
debug!("emscripten::_getgrnam {}", name_ptr);
#[repr(C)]
@@ -137,14 +137,14 @@ pub fn _getgrnam(ctx: &mut Ctx, name_ptr: c_int) -> c_int {
}
}
pub fn _sysconf(_ctx: &mut Ctx, name: c_int) -> i32 {
pub fn _sysconf(_ctx: &mut EmEnv, name: c_int) -> i32 {
debug!("emscripten::_sysconf {}", name);
// TODO: Implement like emscripten expects regarding memory/page size
unsafe { sysconf(name) as i32 } // TODO review i64
}
// this may be a memory leak, probably not though because emscripten does the same thing
pub fn _gai_strerror(ctx: &mut Ctx, ecode: i32) -> i32 {
pub fn _gai_strerror(ctx: &mut EmEnv, ecode: i32) -> i32 {
debug!("emscripten::_gai_strerror({})", ecode);
let cstr = unsafe { std::ffi::CStr::from_ptr(libc::gai_strerror(ecode)) };
@@ -164,7 +164,7 @@ pub fn _gai_strerror(ctx: &mut Ctx, ecode: i32) -> i32 {
}
pub fn _getaddrinfo(
ctx: &mut Ctx,
ctx: &mut EmEnv,
node_ptr: WasmPtr<c_char>,
service_str_ptr: WasmPtr<c_char>,
hints_ptr: WasmPtr<EmAddrInfo>,

View File

@@ -8,7 +8,7 @@ use std::os::raw::c_char;
use crate::env::{call_malloc, EmAddrInfo};
use crate::ptr::WasmPtr;
use crate::utils::{copy_cstr_into_wasm, read_string_from_wasm};
use wasmer_runtime_core::vm::Ctx;
use crate::EmEnv;
extern "C" {
#[link_name = "_putenv"]
@@ -17,7 +17,7 @@ extern "C" {
// #[no_mangle]
/// emscripten: _getenv // (name: *const char) -> *const c_char;
pub fn _getenv(ctx: &mut Ctx, name: u32) -> u32 {
pub fn _getenv(ctx: &mut EmEnv, name: u32) -> u32 {
debug!("emscripten::_getenv");
let name_string = read_string_from_wasm(ctx.memory(0), name);
debug!("=> name({:?})", name_string);
@@ -29,7 +29,7 @@ pub fn _getenv(ctx: &mut Ctx, name: u32) -> u32 {
}
/// emscripten: _setenv // (name: *const char, name: *const value, overwrite: int);
pub fn _setenv(ctx: &mut Ctx, name: u32, value: u32, _overwrite: u32) -> c_int {
pub fn _setenv(ctx: &mut EmEnv, name: u32, value: u32, _overwrite: u32) -> c_int {
debug!("emscripten::_setenv");
// setenv does not exist on windows, so we hack it with _putenv
let name = read_string_from_wasm(ctx.memory(0), name);
@@ -43,7 +43,7 @@ pub fn _setenv(ctx: &mut Ctx, name: u32, value: u32, _overwrite: u32) -> c_int {
}
/// emscripten: _putenv // (name: *const char);
pub fn _putenv(ctx: &mut Ctx, name: c_int) -> c_int {
pub fn _putenv(ctx: &mut EmEnv, name: c_int) -> c_int {
debug!("emscripten::_putenv");
let name_addr = emscripten_memory_pointer!(ctx.memory(0), name) as *const c_char;
debug!("=> name({:?})", unsafe {
@@ -53,7 +53,7 @@ pub fn _putenv(ctx: &mut Ctx, name: c_int) -> c_int {
}
/// emscripten: _unsetenv // (name: *const char);
pub fn _unsetenv(ctx: &mut Ctx, name: u32) -> c_int {
pub fn _unsetenv(ctx: &mut EmEnv, name: u32) -> c_int {
debug!("emscripten::_unsetenv");
let name = read_string_from_wasm(ctx.memory(0), name);
// no unsetenv on windows, so use putenv with an empty value
@@ -65,7 +65,7 @@ pub fn _unsetenv(ctx: &mut Ctx, name: u32) -> c_int {
}
#[allow(clippy::cast_ptr_alignment)]
pub fn _getpwnam(ctx: &mut Ctx, name_ptr: c_int) -> c_int {
pub fn _getpwnam(ctx: &mut EmEnv, name_ptr: c_int) -> c_int {
debug!("emscripten::_getpwnam {}", name_ptr);
#[cfg(not(feature = "debug"))]
let _ = name_ptr;
@@ -99,7 +99,7 @@ pub fn _getpwnam(ctx: &mut Ctx, name_ptr: c_int) -> c_int {
}
#[allow(clippy::cast_ptr_alignment)]
pub fn _getgrnam(ctx: &mut Ctx, name_ptr: c_int) -> c_int {
pub fn _getgrnam(ctx: &mut EmEnv, name_ptr: c_int) -> c_int {
debug!("emscripten::_getgrnam {}", name_ptr);
#[cfg(not(feature = "debug"))]
let _ = name_ptr;
@@ -125,7 +125,7 @@ pub fn _getgrnam(ctx: &mut Ctx, name_ptr: c_int) -> c_int {
}
}
pub fn _sysconf(_ctx: &mut Ctx, name: c_int) -> c_long {
pub fn _sysconf(_ctx: &mut EmEnv, name: c_int) -> c_long {
debug!("emscripten::_sysconf {}", name);
#[cfg(not(feature = "debug"))]
let _ = name;
@@ -133,13 +133,13 @@ pub fn _sysconf(_ctx: &mut Ctx, name: c_int) -> c_long {
0
}
pub fn _gai_strerror(_ctx: &mut Ctx, _ecode: i32) -> i32 {
pub fn _gai_strerror(_ctx: &mut EmEnv, _ecode: i32) -> i32 {
debug!("emscripten::_gai_strerror({}) - stub", _ecode);
-1
}
pub fn _getaddrinfo(
_ctx: &mut Ctx,
_ctx: &mut EmEnv,
_node_ptr: WasmPtr<c_char>,
_service_str_ptr: WasmPtr<c_char>,
_hints_ptr: WasmPtr<EmAddrInfo>,

View File

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

View File

@@ -1,56 +1,56 @@
use super::env;
use super::process::_abort;
use wasmer_runtime_core::vm::Ctx;
use crate::EmEnv;
/// emscripten: ___cxa_allocate_exception
pub fn ___cxa_allocate_exception(ctx: &mut Ctx, size: u32) -> u32 {
pub fn ___cxa_allocate_exception(ctx: &mut EmEnv, size: u32) -> u32 {
debug!("emscripten::___cxa_allocate_exception");
env::call_malloc(ctx, size as _)
}
pub fn ___cxa_current_primary_exception(_ctx: &mut Ctx) -> u32 {
pub fn ___cxa_current_primary_exception(_ctx: &mut EmEnv) -> u32 {
debug!("emscripten::___cxa_current_primary_exception");
unimplemented!("emscripten::___cxa_current_primary_exception")
}
pub fn ___cxa_decrement_exception_refcount(_ctx: &mut Ctx, _a: u32) {
pub fn ___cxa_decrement_exception_refcount(_ctx: &mut EmEnv, _a: u32) {
debug!("emscripten::___cxa_decrement_exception_refcount({})", _a);
unimplemented!("emscripten::___cxa_decrement_exception_refcount({})", _a)
}
pub fn ___cxa_increment_exception_refcount(_ctx: &mut Ctx, _a: u32) {
pub fn ___cxa_increment_exception_refcount(_ctx: &mut EmEnv, _a: u32) {
debug!("emscripten::___cxa_increment_exception_refcount({})", _a);
unimplemented!("emscripten::___cxa_increment_exception_refcount({})", _a)
}
pub fn ___cxa_rethrow_primary_exception(_ctx: &mut Ctx, _a: u32) {
pub fn ___cxa_rethrow_primary_exception(_ctx: &mut EmEnv, _a: u32) {
debug!("emscripten::___cxa_rethrow_primary_exception({})", _a);
unimplemented!("emscripten::___cxa_rethrow_primary_exception({})", _a)
}
/// emscripten: ___cxa_throw
/// TODO: We don't have support for exceptions yet
pub fn ___cxa_throw(ctx: &mut Ctx, _ptr: u32, _ty: u32, _destructor: u32) {
pub fn ___cxa_throw(ctx: &mut EmEnv, _ptr: u32, _ty: u32, _destructor: u32) {
debug!("emscripten::___cxa_throw");
eprintln!("Throwing exceptions not yet implemented: aborting!");
_abort(ctx);
}
pub fn ___cxa_begin_catch(_ctx: &mut Ctx, _exception_object_ptr: u32) -> i32 {
pub fn ___cxa_begin_catch(_ctx: &mut EmEnv, _exception_object_ptr: u32) -> i32 {
debug!("emscripten::___cxa_begin_catch");
-1
}
pub fn ___cxa_end_catch(_ctx: &mut Ctx) {
pub fn ___cxa_end_catch(_ctx: &mut EmEnv) {
debug!("emscripten::___cxa_end_catch");
}
pub fn ___cxa_uncaught_exception(_ctx: &mut Ctx) -> i32 {
pub fn ___cxa_uncaught_exception(_ctx: &mut EmEnv) -> i32 {
debug!("emscripten::___cxa_uncaught_exception");
-1
}
pub fn ___cxa_pure_virtual(_ctx: &mut Ctx) {
pub fn ___cxa_pure_virtual(_ctx: &mut EmEnv) {
debug!("emscripten::___cxa_pure_virtual");
// ABORT = true
panic!("Pure virtual function called!");

View File

@@ -1,10 +1,10 @@
use crate::varargs::VarArgs;
use crate::EmEnv;
use libc::execvp as libc_execvp;
use std::cell::Cell;
use std::ffi::CString;
use wasmer_runtime_core::vm::Ctx;
pub fn execvp(ctx: &mut Ctx, command_name_offset: u32, argv_offset: u32) -> i32 {
pub fn execvp(ctx: &mut EmEnv, command_name_offset: u32, argv_offset: u32) -> i32 {
// a single reference to re-use
let emscripten_memory = ctx.memory(0);
@@ -41,13 +41,13 @@ pub fn execvp(ctx: &mut Ctx, command_name_offset: u32, argv_offset: u32) -> i32
}
/// execl
pub fn execl(_ctx: &mut Ctx, _path_ptr: i32, _arg0_ptr: i32, _varargs: VarArgs) -> i32 {
pub fn execl(_ctx: &mut EmEnv, _path_ptr: i32, _arg0_ptr: i32, _varargs: VarArgs) -> i32 {
debug!("emscripten::execl");
-1
}
/// execle
pub fn execle(_ctx: &mut Ctx, _path_ptr: i32, _arg0_ptr: i32, _varargs: VarArgs) -> i32 {
pub fn execle(_ctx: &mut EmEnv, _path_ptr: i32, _arg0_ptr: i32, _varargs: VarArgs) -> i32 {
debug!("emscripten::execle");
-1
}

View File

@@ -1,7 +1,7 @@
use wasmer_runtime_core::vm::Ctx;
use crate::EmEnv;
// __exit
pub fn exit(_ctx: &mut Ctx, value: i32) {
pub fn exit(_ctx: &mut EmEnv, value: i32) {
debug!("emscripten::exit {}", value);
::std::process::exit(value);
}

View File

@@ -1,6 +1,6 @@
use wasmer_runtime_core::vm::Ctx;
use crate::EmEnv;
pub fn addr(_ctx: &mut Ctx, _cp: i32) -> i32 {
pub fn addr(_ctx: &mut EmEnv, _cp: i32) -> i32 {
debug!("inet::addr({})", _cp);
0
}

View File

@@ -10,22 +10,22 @@ pub use self::unix::*;
#[cfg(windows)]
pub use self::windows::*;
use wasmer_runtime_core::vm::Ctx;
use crate::EmEnv;
/// getprotobyname
pub fn getprotobyname(_ctx: &mut Ctx, _name_ptr: i32) -> i32 {
pub fn getprotobyname(_ctx: &mut EmEnv, _name_ptr: i32) -> i32 {
debug!("emscripten::getprotobyname");
unimplemented!("emscripten::getprotobyname")
}
/// getprotobynumber
pub fn getprotobynumber(_ctx: &mut Ctx, _one: i32) -> i32 {
pub fn getprotobynumber(_ctx: &mut EmEnv, _one: i32) -> i32 {
debug!("emscripten::getprotobynumber");
unimplemented!("emscripten::getprotobynumber")
}
/// sigdelset
pub fn sigdelset(ctx: &mut Ctx, set: i32, signum: i32) -> i32 {
pub fn sigdelset(ctx: &mut EmEnv, set: i32, signum: i32) -> i32 {
debug!("emscripten::sigdelset");
let memory = ctx.memory(0);
#[allow(clippy::cast_ptr_alignment)]
@@ -37,7 +37,7 @@ pub fn sigdelset(ctx: &mut Ctx, set: i32, signum: i32) -> i32 {
}
/// sigfillset
pub fn sigfillset(ctx: &mut Ctx, set: i32) -> i32 {
pub fn sigfillset(ctx: &mut EmEnv, set: i32) -> i32 {
debug!("emscripten::sigfillset");
let memory = ctx.memory(0);
#[allow(clippy::cast_ptr_alignment)]
@@ -51,13 +51,13 @@ pub fn sigfillset(ctx: &mut Ctx, set: i32) -> i32 {
}
/// tzset
pub fn tzset(_ctx: &mut Ctx) {
pub fn tzset(_ctx: &mut EmEnv) {
debug!("emscripten::tzset - stub");
//unimplemented!("emscripten::tzset - stub")
}
/// strptime
pub fn strptime(_ctx: &mut Ctx, _one: i32, _two: i32, _three: i32) -> i32 {
pub fn strptime(_ctx: &mut EmEnv, _one: i32, _two: i32, _three: i32) -> i32 {
debug!("emscripten::strptime");
unimplemented!("emscripten::strptime")
}

View File

@@ -3,15 +3,15 @@ use super::super::utils::copy_cstr_into_wasm;
use libc::{chroot as _chroot, getpwuid as _getpwuid, printf as _printf};
use std::mem;
use wasmer_runtime_core::vm::Ctx;
use crate::EmEnv;
/// putchar
pub fn putchar(_ctx: &mut Ctx, chr: i32) {
pub fn putchar(_ctx: &mut EmEnv, chr: i32) {
unsafe { libc::putchar(chr) };
}
/// printf
pub fn printf(ctx: &mut Ctx, memory_offset: i32, extra: i32) -> i32 {
pub fn printf(ctx: &mut EmEnv, memory_offset: i32, extra: i32) -> i32 {
debug!("emscripten::printf {}, {}", memory_offset, extra);
unsafe {
let addr = emscripten_memory_pointer!(ctx.memory(0), memory_offset) as _;
@@ -20,7 +20,7 @@ pub fn printf(ctx: &mut Ctx, memory_offset: i32, extra: i32) -> i32 {
}
/// chroot
pub fn chroot(ctx: &mut Ctx, name_ptr: i32) -> i32 {
pub fn chroot(ctx: &mut EmEnv, name_ptr: i32) -> i32 {
debug!("emscripten::chroot");
let name = emscripten_memory_pointer!(ctx.memory(0), name_ptr) as *const i8;
unsafe { _chroot(name as *const _) }
@@ -28,7 +28,7 @@ pub fn chroot(ctx: &mut Ctx, name_ptr: i32) -> i32 {
/// getpwuid
#[allow(clippy::cast_ptr_alignment)]
pub fn getpwuid(ctx: &mut Ctx, uid: i32) -> i32 {
pub fn getpwuid(ctx: &mut EmEnv, uid: i32) -> i32 {
debug!("emscripten::getpwuid {}", uid);
#[repr(C)]

View File

@@ -1,4 +1,4 @@
use wasmer_runtime_core::vm::Ctx;
use crate::EmEnv;
// This may be problematic for msvc which uses inline functions for the printf family
// this cfg_attr will try to link with the legacy lib that does not inline printf
@@ -14,12 +14,12 @@ use wasmer_runtime_core::vm::Ctx;
//}
/// putchar
pub fn putchar(_ctx: &mut Ctx, chr: i32) {
pub fn putchar(_ctx: &mut EmEnv, chr: i32) {
unsafe { libc::putchar(chr) };
}
/// printf
pub fn printf(_ctx: &mut Ctx, memory_offset: i32, extra: i32) -> i32 {
pub fn printf(_ctx: &mut EmEnv, memory_offset: i32, extra: i32) -> i32 {
debug!("emscripten::printf {}, {}", memory_offset, extra);
#[cfg(not(feature = "debug"))]
{
@@ -34,13 +34,13 @@ pub fn printf(_ctx: &mut Ctx, memory_offset: i32, extra: i32) -> i32 {
}
/// chroot
pub fn chroot(_ctx: &mut Ctx, _name_ptr: i32) -> i32 {
pub fn chroot(_ctx: &mut EmEnv, _name_ptr: i32) -> i32 {
debug!("emscripten::chroot");
unimplemented!("emscripten::chroot")
}
/// getpwuid
pub fn getpwuid(_ctx: &mut Ctx, _uid: i32) -> i32 {
pub fn getpwuid(_ctx: &mut EmEnv, _uid: i32) -> i32 {
debug!("emscripten::getpwuid");
unimplemented!("emscripten::getpwuid")
}

View File

@@ -2,10 +2,14 @@ use super::env::get_emscripten_data;
use super::process::abort_with_message;
use libc::c_int;
// use std::cell::UnsafeCell;
use wasmer_runtime_core::vm::Ctx;
use crate::EmEnv;
use std::error::Error;
use std::fmt;
use wasmer::RuntimeError;
/// setjmp
pub fn __setjmp(ctx: &mut Ctx, _env_addr: u32) -> c_int {
pub fn __setjmp(ctx: &mut EmEnv, _env_addr: u32) -> c_int {
debug!("emscripten::__setjmp (setjmp)");
abort_with_message(ctx, "missing function: _setjmp");
unreachable!()
@@ -28,7 +32,7 @@ pub fn __setjmp(ctx: &mut Ctx, _env_addr: u32) -> c_int {
/// longjmp
#[allow(unreachable_code)]
pub fn __longjmp(ctx: &mut Ctx, _env_addr: u32, _val: c_int) {
pub fn __longjmp(ctx: &mut EmEnv, _env_addr: u32, _val: c_int) {
debug!("emscripten::__longjmp (longmp)");
abort_with_message(ctx, "missing function: _longjmp");
// unsafe {
@@ -41,9 +45,21 @@ pub fn __longjmp(ctx: &mut Ctx, _env_addr: u32, _val: c_int) {
// };
}
#[derive(Copy, Clone, Debug)]
pub struct LongJumpRet;
impl fmt::Display for LongJumpRet {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "LongJumpRet")
}
}
impl Error for LongJumpRet {}
/// _longjmp
// This function differs from the js implementation, it should return Result<(), &'static str>
pub fn _longjmp(ctx: &mut Ctx, env_addr: i32, val: c_int) -> Result<(), ()> {
#[allow(unreachable_code)]
pub fn _longjmp(ctx: &mut EmEnv, env_addr: i32, val: c_int) {
let val = if val == 0 { 1 } else { val };
get_emscripten_data(ctx)
.set_threw
@@ -52,7 +68,8 @@ pub fn _longjmp(ctx: &mut Ctx, env_addr: i32, val: c_int) -> Result<(), ()> {
.call(env_addr, val)
.expect("set_threw failed to call");
// TODO: return Err("longjmp")
Err(())
RuntimeError::raise(Box::new(LongJumpRet));
unreachable!();
}
// extern "C" {

File diff suppressed because it is too large Load Diff

View File

@@ -1,78 +1,76 @@
extern crate libc;
extern crate wasmer_runtime_core;
use crate::EmEnv;
#[cfg(unix)]
use std::convert::TryInto;
use wasmer_runtime_core::vm::Ctx;
pub fn current_sigrtmax(_ctx: &mut Ctx) -> i32 {
pub fn current_sigrtmax() -> i32 {
debug!("emscripten::current_sigrtmax");
0
}
pub fn current_sigrtmin(_ctx: &mut Ctx) -> i32 {
pub fn current_sigrtmin() -> i32 {
debug!("emscripten::current_sigrtmin");
0
}
pub fn endpwent(_ctx: &mut Ctx) {
pub fn endpwent() {
debug!("emscripten::endpwent");
}
pub fn execv(_ctx: &mut Ctx, _a: i32, _b: i32) -> i32 {
pub fn execv(_a: i32, _b: i32) -> i32 {
debug!("emscripten::execv");
0
}
pub fn fexecve(_ctx: &mut Ctx, _a: i32, _b: i32, _c: i32) -> i32 {
pub fn fexecve(_a: i32, _b: i32, _c: i32) -> i32 {
debug!("emscripten::fexecve");
0
}
pub fn fpathconf(_ctx: &mut Ctx, _a: i32, _b: i32) -> i32 {
pub fn fpathconf(_a: i32, _b: i32) -> i32 {
debug!("emscripten::fpathconf");
0
}
pub fn getitimer(_ctx: &mut Ctx, _a: i32, _b: i32) -> i32 {
pub fn getitimer(_a: i32, _b: i32) -> i32 {
debug!("emscripten::getitimer");
0
}
pub fn getpwent(_ctx: &mut Ctx) -> i32 {
pub fn getpwent() -> i32 {
debug!("emscripten::getpwent");
0
}
pub fn killpg(_ctx: &mut Ctx, _a: i32, _b: i32) -> i32 {
pub fn killpg(_a: i32, _b: i32) -> i32 {
debug!("emscripten::killpg");
0
}
#[cfg(unix)]
pub fn pathconf(ctx: &mut Ctx, path_ptr: i32, name: i32) -> i32 {
pub fn pathconf(ctx: &mut EmEnv, path_ptr: i32, name: i32) -> i32 {
debug!("emscripten::pathconf");
let path = emscripten_memory_pointer!(ctx.memory(0), path_ptr) as *const i8;
unsafe { libc::pathconf(path as *const _, name).try_into().unwrap() }
}
#[cfg(not(unix))]
pub fn pathconf(_ctx: &mut Ctx, _path_ptr: i32, _name: i32) -> i32 {
pub fn pathconf(_ctx: &mut EmEnv, _path_ptr: i32, _name: i32) -> i32 {
debug!("emscripten::pathconf");
0
}
pub fn setpwent(_ctx: &mut Ctx) {
pub fn setpwent() {
debug!("emscripten::setpwent");
}
pub fn sigismember(_ctx: &mut Ctx, _a: i32, _b: i32) -> i32 {
pub fn sigismember(_a: i32, _b: i32) -> i32 {
debug!("emscripten::sigismember");
0
}
pub fn sigpending(_ctx: &mut Ctx, _a: i32) -> i32 {
pub fn sigpending(_a: i32) -> i32 {
debug!("emscripten::sigpending");
0
}

View File

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

View File

@@ -1,22 +1,22 @@
use crate::EmEnv;
use libc::c_int;
use wasmer_runtime_core::vm::Ctx;
// NOTE: Not implemented by Emscripten
pub fn ___lock(_ctx: &mut Ctx, _what: c_int) {
pub fn ___lock(_ctx: &mut EmEnv, _what: c_int) {
debug!("emscripten::___lock {}", _what);
}
// NOTE: Not implemented by Emscripten
pub fn ___unlock(_ctx: &mut Ctx, _what: c_int) {
pub fn ___unlock(_ctx: &mut EmEnv, _what: c_int) {
debug!("emscripten::___unlock {}", _what);
}
// NOTE: Not implemented by Emscripten
pub fn ___wait(_ctx: &mut Ctx, _which: u32, _varargs: u32, _three: u32, _four: u32) {
pub fn ___wait(_ctx: &mut EmEnv, _which: u32, _varargs: u32, _three: u32, _four: u32) {
debug!("emscripten::___wait");
}
pub fn _flock(_ctx: &mut Ctx, _fd: u32, _op: u32) -> u32 {
pub fn _flock(_ctx: &mut EmEnv, _fd: u32, _op: u32) -> u32 {
debug!("emscripten::_flock");
0
}

View File

@@ -1,110 +1,110 @@
use wasmer_runtime_core::vm::Ctx;
use crate::EmEnv;
pub fn _llvm_copysign_f32(_ctx: &mut Ctx, x: f64, y: f64) -> f64 {
pub fn _llvm_copysign_f32(x: f64, y: f64) -> f64 {
x.copysign(y)
}
pub fn _llvm_copysign_f64(_ctx: &mut Ctx, x: f64, y: f64) -> f64 {
pub fn _llvm_copysign_f64(x: f64, y: f64) -> f64 {
x.copysign(y)
}
/// emscripten: _llvm_log10_f64
pub fn _llvm_log10_f64(_ctx: &mut Ctx, value: f64) -> f64 {
pub fn _llvm_log10_f64(value: f64) -> f64 {
debug!("emscripten::_llvm_log10_f64");
value.log10()
}
/// emscripten: _llvm_log2_f64
pub fn _llvm_log2_f64(_ctx: &mut Ctx, value: f64) -> f64 {
pub fn _llvm_log2_f64(value: f64) -> f64 {
debug!("emscripten::_llvm_log2_f64");
value.log2()
}
/// emscripten: _llvm_sin_f64
pub fn _llvm_sin_f64(_ctx: &mut Ctx, value: f64) -> f64 {
pub fn _llvm_sin_f64(value: f64) -> f64 {
debug!("emscripten::_llvm_sin_f64");
value.sin()
}
/// emscripten: _llvm_cos_f64
pub fn _llvm_cos_f64(_ctx: &mut Ctx, value: f64) -> f64 {
pub fn _llvm_cos_f64(value: f64) -> f64 {
debug!("emscripten::_llvm_cos_f64");
value.cos()
}
pub fn _llvm_log10_f32(_ctx: &mut Ctx, _value: f64) -> f64 {
pub fn _llvm_log10_f32(_value: f64) -> f64 {
debug!("emscripten::_llvm_log10_f32");
-1.0
}
pub fn _llvm_log2_f32(_ctx: &mut Ctx, _value: f64) -> f64 {
pub fn _llvm_log2_f32(_value: f64) -> f64 {
debug!("emscripten::_llvm_log10_f32");
-1.0
}
pub fn _llvm_exp2_f32(_ctx: &mut Ctx, value: f32) -> f32 {
pub fn _llvm_exp2_f32(value: f32) -> f32 {
debug!("emscripten::_llvm_exp2_f32");
2f32.powf(value)
}
pub fn _llvm_exp2_f64(_ctx: &mut Ctx, value: f64) -> f64 {
pub fn _llvm_exp2_f64(value: f64) -> f64 {
debug!("emscripten::_llvm_exp2_f64");
2f64.powf(value)
}
pub fn _llvm_trunc_f64(_ctx: &mut Ctx, value: f64) -> f64 {
pub fn _llvm_trunc_f64(value: f64) -> f64 {
debug!("emscripten::_llvm_trunc_f64");
value.trunc()
}
pub fn _llvm_fma_f64(_ctx: &mut Ctx, value: f64, a: f64, b: f64) -> f64 {
pub fn _llvm_fma_f64(value: f64, a: f64, b: f64) -> f64 {
debug!("emscripten::_llvm_fma_f64");
value.mul_add(a, b)
}
pub fn _emscripten_random(_ctx: &mut Ctx) -> f64 {
pub fn _emscripten_random(_ctx: &mut EmEnv) -> f64 {
debug!("emscripten::_emscripten_random");
-1.0
}
// emscripten: asm2wasm.f64-rem
pub fn f64_rem(_ctx: &mut Ctx, x: f64, y: f64) -> f64 {
pub fn f64_rem(x: f64, y: f64) -> f64 {
debug!("emscripten::f64-rem");
x % y
}
// emscripten: global.Math pow
pub fn pow(_ctx: &mut Ctx, x: f64, y: f64) -> f64 {
pub fn pow(x: f64, y: f64) -> f64 {
x.powf(y)
}
// emscripten: global.Math exp
pub fn exp(_ctx: &mut Ctx, value: f64) -> f64 {
pub fn exp(value: f64) -> f64 {
value.exp()
}
// emscripten: global.Math log
pub fn log(_ctx: &mut Ctx, value: f64) -> f64 {
pub fn log(value: f64) -> f64 {
value.ln()
}
// emscripten: global.Math sqrt
pub fn sqrt(_ctx: &mut Ctx, value: f64) -> f64 {
pub fn sqrt(value: f64) -> f64 {
value.sqrt()
}
// emscripten: global.Math floor
pub fn floor(_ctx: &mut Ctx, value: f64) -> f64 {
pub fn floor(value: f64) -> f64 {
value.floor()
}
// emscripten: global.Math fabs
pub fn fabs(_ctx: &mut Ctx, value: f64) -> f64 {
pub fn fabs(value: f64) -> f64 {
value.abs()
}
// emscripten: asm2wasm.f64-to-int
pub fn f64_to_int(_ctx: &mut Ctx, value: f64) -> i32 {
pub fn f64_to_int(value: f64) -> i32 {
debug!("emscripten::f64_to_int {}", value);
value as i32
}

View File

@@ -1,13 +1,12 @@
use super::env::get_emscripten_data;
use super::process::abort_with_message;
use crate::EmEnv;
use libc::{c_int, c_void, memcpy, size_t};
use wasmer_runtime_core::{
units::{Pages, WASM_MAX_PAGES, WASM_MIN_PAGES, WASM_PAGE_SIZE},
vm::Ctx,
};
// TODO: investigate max pages etc. probably in Wasm Common, maybe reexport
use wasmer::{Pages, WASM_MAX_PAGES, WASM_MIN_PAGES, WASM_PAGE_SIZE};
/// emscripten: _emscripten_memcpy_big
pub fn _emscripten_memcpy_big(ctx: &mut Ctx, dest: u32, src: u32, len: u32) -> u32 {
pub fn _emscripten_memcpy_big(ctx: &mut EmEnv, dest: u32, src: u32, len: u32) -> u32 {
debug!(
"emscripten::_emscripten_memcpy_big {}, {}, {}",
dest, src, len
@@ -21,7 +20,7 @@ pub fn _emscripten_memcpy_big(ctx: &mut Ctx, dest: u32, src: u32, len: u32) -> u
}
/// emscripten: _emscripten_get_heap_size
pub fn _emscripten_get_heap_size(ctx: &mut Ctx) -> u32 {
pub fn _emscripten_get_heap_size(ctx: &mut EmEnv) -> u32 {
trace!("emscripten::_emscripten_get_heap_size");
let result = ctx.memory(0).size().bytes().0 as u32;
trace!("=> {}", result);
@@ -39,20 +38,23 @@ fn align_up(mut val: usize, multiple: usize) -> usize {
/// emscripten: _emscripten_resize_heap
/// Note: this function only allows growing the size of heap
pub fn _emscripten_resize_heap(ctx: &mut Ctx, requested_size: u32) -> u32 {
pub fn _emscripten_resize_heap(ctx: &mut EmEnv, requested_size: u32) -> u32 {
debug!("emscripten::_emscripten_resize_heap {}", requested_size);
let current_memory_pages = ctx.memory(0).size();
let current_memory = current_memory_pages.bytes().0 as u32;
// implementation from emscripten
let mut new_size = usize::max(current_memory as usize, WASM_MIN_PAGES * WASM_PAGE_SIZE);
let mut new_size = usize::max(
current_memory as usize,
WASM_MIN_PAGES as usize * WASM_PAGE_SIZE,
);
while new_size < requested_size as usize {
if new_size <= 0x2000_0000 {
new_size = align_up(new_size * 2, WASM_PAGE_SIZE);
} else {
new_size = usize::min(
align_up((3 * new_size + 0x8000_0000) / 4, WASM_PAGE_SIZE),
WASM_PAGE_SIZE * WASM_MAX_PAGES,
WASM_PAGE_SIZE * WASM_MAX_PAGES as usize,
);
}
}
@@ -67,7 +69,7 @@ pub fn _emscripten_resize_heap(ctx: &mut Ctx, requested_size: u32) -> u32 {
}
/// emscripten: sbrk
pub fn sbrk(ctx: &mut Ctx, increment: i32) -> i32 {
pub fn sbrk(ctx: &mut EmEnv, increment: i32) -> i32 {
debug!("emscripten::sbrk");
// let old_dynamic_top = 0;
// let new_dynamic_top = 0;
@@ -95,7 +97,7 @@ pub fn sbrk(ctx: &mut Ctx, increment: i32) -> i32 {
}
/// emscripten: getTotalMemory
pub fn get_total_memory(_ctx: &mut Ctx) -> u32 {
pub fn get_total_memory(_ctx: &mut EmEnv) -> u32 {
debug!("emscripten::get_total_memory");
// instance.memories[0].current_pages()
// TODO: Fix implementation
@@ -103,7 +105,7 @@ pub fn get_total_memory(_ctx: &mut Ctx) -> u32 {
}
/// emscripten: enlargeMemory
pub fn enlarge_memory(_ctx: &mut Ctx) -> u32 {
pub fn enlarge_memory(_ctx: &mut EmEnv) -> u32 {
debug!("emscripten::enlarge_memory");
// instance.memories[0].grow(100);
// TODO: Fix implementation
@@ -111,7 +113,7 @@ pub fn enlarge_memory(_ctx: &mut Ctx) -> u32 {
}
/// emscripten: abortOnCannotGrowMemory
pub fn abort_on_cannot_grow_memory(ctx: &mut Ctx, _requested_size: u32) -> u32 {
pub fn abort_on_cannot_grow_memory(ctx: &mut EmEnv, _requested_size: u32) -> u32 {
debug!(
"emscripten::abort_on_cannot_grow_memory {}",
_requested_size
@@ -121,32 +123,32 @@ pub fn abort_on_cannot_grow_memory(ctx: &mut Ctx, _requested_size: u32) -> u32 {
}
/// emscripten: abortOnCannotGrowMemory
pub fn abort_on_cannot_grow_memory_old(ctx: &mut Ctx) -> u32 {
pub fn abort_on_cannot_grow_memory_old(ctx: &mut EmEnv) -> u32 {
debug!("emscripten::abort_on_cannot_grow_memory");
abort_with_message(ctx, "Cannot enlarge memory arrays!");
0
}
/// emscripten: segfault
pub fn segfault(ctx: &mut Ctx) {
pub fn segfault(ctx: &mut EmEnv) {
debug!("emscripten::segfault");
abort_with_message(ctx, "segmentation fault");
}
/// emscripten: alignfault
pub fn alignfault(ctx: &mut Ctx) {
pub fn alignfault(ctx: &mut EmEnv) {
debug!("emscripten::alignfault");
abort_with_message(ctx, "alignment fault");
}
/// emscripten: ftfault
pub fn ftfault(ctx: &mut Ctx) {
pub fn ftfault(ctx: &mut EmEnv) {
debug!("emscripten::ftfault");
abort_with_message(ctx, "Function table mask error");
}
/// emscripten: ___map_file
pub fn ___map_file(_ctx: &mut Ctx, _one: u32, _two: u32) -> c_int {
pub fn ___map_file(_ctx: &mut EmEnv, _one: u32, _two: u32) -> c_int {
debug!("emscripten::___map_file");
// NOTE: TODO: Em returns -1 here as well. May need to implement properly
-1

View File

@@ -5,35 +5,35 @@ type PidT = libc::pid_t;
#[cfg(target_os = "windows")]
type PidT = c_int;
use wasmer_runtime_core::vm::Ctx;
use crate::EmEnv;
pub fn abort_with_message(ctx: &mut Ctx, message: &str) {
pub fn abort_with_message(ctx: &mut EmEnv, message: &str) {
debug!("emscripten::abort_with_message");
println!("{}", message);
_abort(ctx);
}
/// The name of this call is `abort` but we want to avoid conflicts with libc::abort
pub fn em_abort(ctx: &mut Ctx, arg: u32) {
pub fn em_abort(ctx: &mut EmEnv, arg: u32) {
debug!("emscripten::abort");
eprintln!("Program aborted with value {}", arg);
_abort(ctx);
}
pub fn _abort(_ctx: &mut Ctx) {
pub fn _abort(_ctx: &mut EmEnv) {
debug!("emscripten::_abort");
unsafe {
abort();
}
}
pub fn _prctl(ctx: &mut Ctx, _a: i32, _b: i32) -> i32 {
pub fn _prctl(ctx: &mut EmEnv, _a: i32, _b: i32) -> i32 {
debug!("emscripten::_prctl");
abort_with_message(ctx, "missing function: prctl");
-1
}
pub fn _fork(_ctx: &mut Ctx) -> PidT {
pub fn _fork(_ctx: &mut EmEnv) -> PidT {
debug!("emscripten::_fork");
// unsafe {
// fork()
@@ -41,132 +41,132 @@ pub fn _fork(_ctx: &mut Ctx) -> PidT {
-1
}
pub fn _endgrent(_ctx: &mut Ctx) {
pub fn _endgrent(_ctx: &mut EmEnv) {
debug!("emscripten::_endgrent");
}
pub fn _execve(_ctx: &mut Ctx, _one: i32, _two: i32, _three: i32) -> i32 {
pub fn _execve(_ctx: &mut EmEnv, _one: i32, _two: i32, _three: i32) -> i32 {
debug!("emscripten::_execve");
-1
}
#[allow(unreachable_code)]
pub fn _exit(_ctx: &mut Ctx, status: c_int) {
pub fn _exit(_ctx: &mut EmEnv, status: c_int) {
// -> !
debug!("emscripten::_exit {}", status);
unsafe { exit(status) }
}
pub fn _kill(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
pub fn _kill(_ctx: &mut EmEnv, _one: i32, _two: i32) -> i32 {
debug!("emscripten::_kill");
-1
}
pub fn _sched_yield(_ctx: &mut Ctx) -> i32 {
pub fn _sched_yield(_ctx: &mut EmEnv) -> i32 {
debug!("emscripten::_sched_yield");
-1
}
pub fn _llvm_stacksave(_ctx: &mut Ctx) -> i32 {
pub fn _llvm_stacksave(_ctx: &mut EmEnv) -> i32 {
debug!("emscripten::_llvm_stacksave");
-1
}
pub fn _llvm_stackrestore(_ctx: &mut Ctx, _one: i32) {
pub fn _llvm_stackrestore(_ctx: &mut EmEnv, _one: i32) {
debug!("emscripten::_llvm_stackrestore");
}
pub fn _raise(_ctx: &mut Ctx, _one: i32) -> i32 {
pub fn _raise(_ctx: &mut EmEnv, _one: i32) -> i32 {
debug!("emscripten::_raise");
-1
}
pub fn _sem_init(_ctx: &mut Ctx, _one: i32, _two: i32, _three: i32) -> i32 {
pub fn _sem_init(_ctx: &mut EmEnv, _one: i32, _two: i32, _three: i32) -> i32 {
debug!("emscripten::_sem_init: {}, {}, {}", _one, _two, _three);
0
}
pub fn _sem_destroy(_ctx: &mut Ctx, _one: i32) -> i32 {
pub fn _sem_destroy(_ctx: &mut EmEnv, _one: i32) -> i32 {
debug!("emscripten::_sem_destroy");
0
}
pub fn _sem_post(_ctx: &mut Ctx, _one: i32) -> i32 {
pub fn _sem_post(_ctx: &mut EmEnv, _one: i32) -> i32 {
debug!("emscripten::_sem_post");
-1
}
pub fn _sem_wait(_ctx: &mut Ctx, _one: i32) -> i32 {
pub fn _sem_wait(_ctx: &mut EmEnv, _one: i32) -> i32 {
debug!("emscripten::_sem_post");
-1
}
#[allow(clippy::cast_ptr_alignment)]
pub fn _getgrent(_ctx: &mut Ctx) -> c_int {
pub fn _getgrent(_ctx: &mut EmEnv) -> c_int {
debug!("emscripten::_getgrent");
-1
}
pub fn _setgrent(_ctx: &mut Ctx) {
pub fn _setgrent(_ctx: &mut EmEnv) {
debug!("emscripten::_setgrent");
}
pub fn _setgroups(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
pub fn _setgroups(_ctx: &mut EmEnv, _one: i32, _two: i32) -> i32 {
debug!("emscripten::_setgroups");
-1
}
pub fn _setitimer(_ctx: &mut Ctx, _one: i32, _two: i32, _three: i32) -> i32 {
pub fn _setitimer(_ctx: &mut EmEnv, _one: i32, _two: i32, _three: i32) -> i32 {
debug!("emscripten::_setitimer");
-1
}
pub fn _usleep(_ctx: &mut Ctx, _one: i32) -> i32 {
pub fn _usleep(_ctx: &mut EmEnv, _one: i32) -> i32 {
debug!("emscripten::_usleep");
-1
}
pub fn _nanosleep(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
pub fn _nanosleep(_ctx: &mut EmEnv, _one: i32, _two: i32) -> i32 {
debug!("emscripten::_nanosleep");
-1
}
pub fn _utime(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
pub fn _utime(_ctx: &mut EmEnv, _one: i32, _two: i32) -> i32 {
debug!("emscripten::_utime");
-1
}
pub fn _utimes(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
pub fn _utimes(_ctx: &mut EmEnv, _one: i32, _two: i32) -> i32 {
debug!("emscripten::_utimes");
-1
}
pub fn _wait(_ctx: &mut Ctx, _one: i32) -> i32 {
pub fn _wait(_ctx: &mut EmEnv, _one: i32) -> i32 {
debug!("emscripten::_wait");
-1
}
pub fn _wait3(_ctx: &mut Ctx, _one: i32, _two: i32, _three: i32) -> i32 {
pub fn _wait3(_ctx: &mut EmEnv, _one: i32, _two: i32, _three: i32) -> i32 {
debug!("emscripten::_wait3");
-1
}
pub fn _wait4(_ctx: &mut Ctx, _one: i32, _two: i32, _three: i32, _d: i32) -> i32 {
pub fn _wait4(_ctx: &mut EmEnv, _one: i32, _two: i32, _three: i32, _d: i32) -> i32 {
debug!("emscripten::_wait4");
-1
}
pub fn _waitid(_ctx: &mut Ctx, _one: i32, _two: i32, _three: i32, _d: i32) -> i32 {
pub fn _waitid(_ctx: &mut EmEnv, _one: i32, _two: i32, _three: i32, _d: i32) -> i32 {
debug!("emscripten::_waitid");
-1
}
pub fn _waitpid(_ctx: &mut Ctx, _one: i32, _two: i32, _three: i32) -> i32 {
pub fn _waitpid(_ctx: &mut EmEnv, _one: i32, _two: i32, _three: i32) -> i32 {
debug!("emscripten::_waitpid");
-1
}
pub fn abort_stack_overflow(ctx: &mut Ctx, _what: c_int) {
pub fn abort_stack_overflow(ctx: &mut EmEnv, _what: c_int) {
debug!("emscripten::abort_stack_overflow");
// TODO: Message incomplete. Need to finish em runtime data first
abort_with_message(
@@ -175,24 +175,24 @@ pub fn abort_stack_overflow(ctx: &mut Ctx, _what: c_int) {
);
}
pub fn _llvm_trap(ctx: &mut Ctx) {
pub fn _llvm_trap(ctx: &mut EmEnv) {
debug!("emscripten::_llvm_trap");
abort_with_message(ctx, "abort!");
}
pub fn _llvm_eh_typeid_for(_ctx: &mut Ctx, _type_info_addr: u32) -> i32 {
pub fn _llvm_eh_typeid_for(_ctx: &mut EmEnv, _type_info_addr: u32) -> i32 {
debug!("emscripten::_llvm_eh_typeid_for");
-1
}
pub fn _system(_ctx: &mut Ctx, _one: i32) -> c_int {
pub fn _system(_ctx: &mut EmEnv, _one: i32) -> c_int {
debug!("emscripten::_system");
// TODO: May need to change this Em impl to a working version
eprintln!("Can't call external programs");
EAGAIN
}
pub fn _popen(_ctx: &mut Ctx, _one: i32, _two: i32) -> c_int {
pub fn _popen(_ctx: &mut EmEnv, _one: i32, _two: i32) -> c_int {
debug!("emscripten::_popen");
// TODO: May need to change this Em impl to a working version
eprintln!("Missing function: popen");

View File

@@ -1,12 +1,12 @@
use wasmer_runtime_core::vm::Ctx;
use crate::EmEnv;
pub fn _pthread_attr_destroy(_ctx: &mut Ctx, _a: i32) -> i32 {
pub fn _pthread_attr_destroy(_ctx: &mut EmEnv, _a: i32) -> i32 {
trace!("emscripten::_pthread_attr_destroy");
0
}
pub fn _pthread_attr_getstack(
_ctx: &mut Ctx,
_ctx: &mut EmEnv,
_stackaddr: i32,
_stacksize: i32,
_other: i32,
@@ -23,175 +23,175 @@ pub fn _pthread_attr_getstack(
0
}
pub fn _pthread_attr_init(_ctx: &mut Ctx, _a: i32) -> i32 {
pub fn _pthread_attr_init(_ctx: &mut EmEnv, _a: i32) -> i32 {
trace!("emscripten::_pthread_attr_init({})", _a);
0
}
pub fn _pthread_attr_setstacksize(_ctx: &mut Ctx, _a: i32, _b: i32) -> i32 {
pub fn _pthread_attr_setstacksize(_ctx: &mut EmEnv, _a: i32, _b: i32) -> i32 {
trace!("emscripten::_pthread_attr_setstacksize");
0
}
pub fn _pthread_cleanup_pop(_ctx: &mut Ctx, _a: i32) -> () {
pub fn _pthread_cleanup_pop(_ctx: &mut EmEnv, _a: i32) -> () {
trace!("emscripten::_pthread_cleanup_pop");
}
pub fn _pthread_cleanup_push(_ctx: &mut Ctx, _a: i32, _b: i32) -> () {
pub fn _pthread_cleanup_push(_ctx: &mut EmEnv, _a: i32, _b: i32) -> () {
trace!("emscripten::_pthread_cleanup_push");
}
pub fn _pthread_cond_destroy(_ctx: &mut Ctx, _a: i32) -> i32 {
pub fn _pthread_cond_destroy(_ctx: &mut EmEnv, _a: i32) -> i32 {
trace!("emscripten::_pthread_cond_destroy");
0
}
pub fn _pthread_cond_init(_ctx: &mut Ctx, _a: i32, _b: i32) -> i32 {
pub fn _pthread_cond_init(_ctx: &mut EmEnv, _a: i32, _b: i32) -> i32 {
trace!("emscripten::_pthread_cond_init");
0
}
pub fn _pthread_cond_signal(_ctx: &mut Ctx, _a: i32) -> i32 {
pub fn _pthread_cond_signal(_ctx: &mut EmEnv, _a: i32) -> i32 {
trace!("emscripten::_pthread_cond_signal");
0
}
pub fn _pthread_cond_timedwait(_ctx: &mut Ctx, _a: i32, _b: i32, _c: i32) -> i32 {
pub fn _pthread_cond_timedwait(_ctx: &mut EmEnv, _a: i32, _b: i32, _c: i32) -> i32 {
trace!("emscripten::_pthread_cond_timedwait");
0
}
pub fn _pthread_cond_wait(_ctx: &mut Ctx, _a: i32, _b: i32) -> i32 {
pub fn _pthread_cond_wait(_ctx: &mut EmEnv, _a: i32, _b: i32) -> i32 {
trace!("emscripten::_pthread_cond_wait");
0
}
pub fn _pthread_condattr_destroy(_ctx: &mut Ctx, _a: i32) -> i32 {
pub fn _pthread_condattr_destroy(_ctx: &mut EmEnv, _a: i32) -> i32 {
trace!("emscripten::_pthread_condattr_destroy");
0
}
pub fn _pthread_condattr_init(_ctx: &mut Ctx, _a: i32) -> i32 {
pub fn _pthread_condattr_init(_ctx: &mut EmEnv, _a: i32) -> i32 {
trace!("emscripten::_pthread_condattr_init");
0
}
pub fn _pthread_condattr_setclock(_ctx: &mut Ctx, _a: i32, _b: i32) -> i32 {
pub fn _pthread_condattr_setclock(_ctx: &mut EmEnv, _a: i32, _b: i32) -> i32 {
trace!("emscripten::_pthread_condattr_setclock");
0
}
pub fn _pthread_create(_ctx: &mut Ctx, _a: i32, _b: i32, _c: i32, _d: i32) -> i32 {
pub fn _pthread_create(_ctx: &mut EmEnv, _a: i32, _b: i32, _c: i32, _d: i32) -> i32 {
trace!("emscripten::_pthread_create");
// 11 seems to mean "no"
11
}
pub fn _pthread_detach(_ctx: &mut Ctx, _a: i32) -> i32 {
pub fn _pthread_detach(_ctx: &mut EmEnv, _a: i32) -> i32 {
trace!("emscripten::_pthread_detach");
0
}
pub fn _pthread_equal(_ctx: &mut Ctx, _a: i32, _b: i32) -> i32 {
pub fn _pthread_equal(_ctx: &mut EmEnv, _a: i32, _b: i32) -> i32 {
trace!("emscripten::_pthread_equal");
0
}
pub fn _pthread_exit(_ctx: &mut Ctx, _a: i32) -> () {
pub fn _pthread_exit(_ctx: &mut EmEnv, _a: i32) -> () {
trace!("emscripten::_pthread_exit");
}
pub fn _pthread_getattr_np(_ctx: &mut Ctx, _thread: i32, _attr: i32) -> i32 {
pub fn _pthread_getattr_np(_ctx: &mut EmEnv, _thread: i32, _attr: i32) -> i32 {
trace!("emscripten::_pthread_getattr_np({}, {})", _thread, _attr);
0
}
pub fn _pthread_getspecific(_ctx: &mut Ctx, _a: i32) -> i32 {
pub fn _pthread_getspecific(_ctx: &mut EmEnv, _a: i32) -> i32 {
trace!("emscripten::_pthread_getspecific");
0
}
pub fn _pthread_join(_ctx: &mut Ctx, _a: i32, _b: i32) -> i32 {
pub fn _pthread_join(_ctx: &mut EmEnv, _a: i32, _b: i32) -> i32 {
trace!("emscripten::_pthread_join");
0
}
pub fn _pthread_self(_ctx: &mut Ctx) -> i32 {
pub fn _pthread_self(_ctx: &mut EmEnv) -> i32 {
trace!("emscripten::_pthread_self");
0
}
pub fn _pthread_key_create(_ctx: &mut Ctx, _a: i32, _b: i32) -> i32 {
pub fn _pthread_key_create(_ctx: &mut EmEnv, _a: i32, _b: i32) -> i32 {
trace!("emscripten::_pthread_key_create");
0
}
pub fn _pthread_mutex_destroy(_ctx: &mut Ctx, _a: i32) -> i32 {
pub fn _pthread_mutex_destroy(_ctx: &mut EmEnv, _a: i32) -> i32 {
trace!("emscripten::_pthread_mutex_destroy");
0
}
pub fn _pthread_mutex_init(_ctx: &mut Ctx, _a: i32, _b: i32) -> i32 {
pub fn _pthread_mutex_init(_ctx: &mut EmEnv, _a: i32, _b: i32) -> i32 {
trace!("emscripten::_pthread_mutex_init");
0
}
pub fn _pthread_mutexattr_destroy(_ctx: &mut Ctx, _a: i32) -> i32 {
pub fn _pthread_mutexattr_destroy(_ctx: &mut EmEnv, _a: i32) -> i32 {
trace!("emscripten::_pthread_mutexattr_destroy");
0
}
pub fn _pthread_mutexattr_init(_ctx: &mut Ctx, _a: i32) -> i32 {
pub fn _pthread_mutexattr_init(_ctx: &mut EmEnv, _a: i32) -> i32 {
trace!("emscripten::_pthread_mutexattr_init");
0
}
pub fn _pthread_mutexattr_settype(_ctx: &mut Ctx, _a: i32, _b: i32) -> i32 {
pub fn _pthread_mutexattr_settype(_ctx: &mut EmEnv, _a: i32, _b: i32) -> i32 {
trace!("emscripten::_pthread_mutexattr_settype");
0
}
pub fn _pthread_once(_ctx: &mut Ctx, _a: i32, _b: i32) -> i32 {
pub fn _pthread_once(_ctx: &mut EmEnv, _a: i32, _b: i32) -> i32 {
trace!("emscripten::_pthread_once");
0
}
pub fn _pthread_rwlock_destroy(_ctx: &mut Ctx, _rwlock: i32) -> i32 {
pub fn _pthread_rwlock_destroy(_ctx: &mut EmEnv, _rwlock: i32) -> i32 {
trace!("emscripten::_pthread_rwlock_destroy({})", _rwlock);
0
}
pub fn _pthread_rwlock_init(_ctx: &mut Ctx, _rwlock: i32, _attr: i32) -> i32 {
pub fn _pthread_rwlock_init(_ctx: &mut EmEnv, _rwlock: i32, _attr: i32) -> i32 {
trace!("emscripten::_pthread_rwlock_init({}, {})", _rwlock, _attr);
0
}
pub fn _pthread_rwlock_rdlock(_ctx: &mut Ctx, _a: i32) -> i32 {
pub fn _pthread_rwlock_rdlock(_ctx: &mut EmEnv, _a: i32) -> i32 {
trace!("emscripten::_pthread_rwlock_rdlock");
0
}
pub fn _pthread_rwlock_unlock(_ctx: &mut Ctx, _a: i32) -> i32 {
pub fn _pthread_rwlock_unlock(_ctx: &mut EmEnv, _a: i32) -> i32 {
trace!("emscripten::_pthread_rwlock_unlock");
0
}
pub fn _pthread_rwlock_wrlock(_ctx: &mut Ctx, _rwlock: i32) -> i32 {
pub fn _pthread_rwlock_wrlock(_ctx: &mut EmEnv, _rwlock: i32) -> i32 {
trace!("emscripten::_pthread_rwlock_wrlock({})", _rwlock);
0
}
pub fn _pthread_setcancelstate(_ctx: &mut Ctx, _a: i32, _b: i32) -> i32 {
pub fn _pthread_setcancelstate(_ctx: &mut EmEnv, _a: i32, _b: i32) -> i32 {
trace!("emscripten::_pthread_setcancelstate");
0
}
pub fn _pthread_setspecific(_ctx: &mut Ctx, _a: i32, _b: i32) -> i32 {
pub fn _pthread_setspecific(_ctx: &mut EmEnv, _a: i32, _b: i32) -> i32 {
trace!("emscripten::_pthread_setspecific");
0
}
pub fn _pthread_sigmask(_ctx: &mut Ctx, _a: i32, _b: i32, _c: i32) -> i32 {
pub fn _pthread_sigmask(_ctx: &mut EmEnv, _a: i32, _b: i32, _c: i32) -> i32 {
trace!("emscripten::_pthread_sigmask");
0
}

View File

@@ -6,14 +6,10 @@
#![allow(dead_code)]
use std::{cell::Cell, fmt};
pub use wasmer_runtime_core::memory::ptr::Array;
use wasmer_runtime_core::{
memory::{ptr, Memory},
types::{ValueType, WasmExternType},
};
pub use wasmer::{Array, Memory, ValueType, WasmExternType};
#[repr(transparent)]
pub struct WasmPtr<T: Copy, Ty = ptr::Item>(ptr::WasmPtr<T, Ty>);
pub struct WasmPtr<T: Copy, Ty = wasmer::Item>(wasmer::WasmPtr<T, Ty>);
unsafe impl<T: Copy, Ty> ValueType for WasmPtr<T, Ty> {}
impl<T: Copy, Ty> Copy for WasmPtr<T, Ty> {}
@@ -31,13 +27,13 @@ impl<T: Copy, Ty> fmt::Debug for WasmPtr<T, Ty> {
}
unsafe impl<T: Copy, Ty> WasmExternType for WasmPtr<T, Ty> {
type Native = <ptr::WasmPtr<T, Ty> as WasmExternType>::Native;
type Native = <wasmer::WasmPtr<T, Ty> as WasmExternType>::Native;
fn to_native(self) -> Self::Native {
self.0.to_native()
}
fn from_native(n: Self::Native) -> Self {
Self(ptr::WasmPtr::from_native(n))
Self(wasmer::WasmPtr::from_native(n))
}
}
@@ -52,7 +48,7 @@ impl<T: Copy, Ty> Eq for WasmPtr<T, Ty> {}
impl<T: Copy, Ty> WasmPtr<T, Ty> {
#[inline(always)]
pub fn new(offset: u32) -> Self {
Self(ptr::WasmPtr::new(offset))
Self(wasmer::WasmPtr::new(offset))
}
#[inline(always)]
@@ -61,7 +57,7 @@ impl<T: Copy, Ty> WasmPtr<T, Ty> {
}
}
impl<T: Copy + ValueType> WasmPtr<T, ptr::Item> {
impl<T: Copy + ValueType> WasmPtr<T, wasmer::Item> {
#[inline(always)]
pub fn deref<'a>(self, memory: &'a Memory) -> Option<&'a Cell<T>> {
if self.0.offset() == 0 {
@@ -81,7 +77,7 @@ impl<T: Copy + ValueType> WasmPtr<T, ptr::Item> {
}
}
impl<T: Copy + ValueType> WasmPtr<T, ptr::Array> {
impl<T: Copy + ValueType> WasmPtr<T, wasmer::Array> {
#[inline(always)]
pub fn deref<'a>(self, memory: &'a Memory, index: u32, length: u32) -> Option<&'a [Cell<T>]> {
if self.0.offset() == 0 {

View File

@@ -1,8 +1,8 @@
// use super::varargs::VarArgs;
use wasmer_runtime_core::vm::Ctx;
use crate::EmEnv;
#[allow(clippy::cast_ptr_alignment)]
pub fn _sigemptyset(ctx: &mut Ctx, set: u32) -> i32 {
pub fn _sigemptyset(ctx: &mut EmEnv, set: u32) -> i32 {
debug!("emscripten::_sigemptyset");
let set_addr = emscripten_memory_pointer!(ctx.memory(0), set) as *mut u32;
unsafe {
@@ -11,18 +11,18 @@ pub fn _sigemptyset(ctx: &mut Ctx, set: u32) -> i32 {
0
}
pub fn _sigaction(_ctx: &mut Ctx, _signum: u32, _act: u32, _oldact: u32) -> i32 {
pub fn _sigaction(_ctx: &mut EmEnv, _signum: u32, _act: u32, _oldact: u32) -> i32 {
debug!("emscripten::_sigaction {}, {}, {}", _signum, _act, _oldact);
0
}
pub fn _siginterrupt(_ctx: &mut Ctx, _a: u32, _b: u32) -> i32 {
pub fn _siginterrupt(_ctx: &mut EmEnv, _a: u32, _b: u32) -> i32 {
debug!("emscripten::_siginterrupt {}, {}", _a, _b);
0
}
#[allow(clippy::cast_ptr_alignment)]
pub fn _sigaddset(ctx: &mut Ctx, set: u32, signum: u32) -> i32 {
pub fn _sigaddset(ctx: &mut EmEnv, set: u32, signum: u32) -> i32 {
debug!("emscripten::_sigaddset {}, {}", set, signum);
let set_addr = emscripten_memory_pointer!(ctx.memory(0), set) as *mut u32;
unsafe {
@@ -31,17 +31,17 @@ pub fn _sigaddset(ctx: &mut Ctx, set: u32, signum: u32) -> i32 {
0
}
pub fn _sigsuspend(_ctx: &mut Ctx, _one: i32) -> i32 {
pub fn _sigsuspend(_ctx: &mut EmEnv, _one: i32) -> i32 {
debug!("emscripten::_sigsuspend");
-1
}
pub fn _sigprocmask(_ctx: &mut Ctx, _one: i32, _two: i32, _three: i32) -> i32 {
pub fn _sigprocmask(_ctx: &mut EmEnv, _one: i32, _two: i32, _three: i32) -> i32 {
debug!("emscripten::_sigprocmask");
0
}
pub fn _signal(_ctx: &mut Ctx, _sig: u32, _two: i32) -> i32 {
pub fn _signal(_ctx: &mut EmEnv, _sig: u32, _two: i32) -> i32 {
debug!("emscripten::_signal ({})", _sig);
0
}

View File

@@ -13,6 +13,7 @@ pub use self::windows::*;
use crate::{
ptr::{Array, WasmPtr},
utils::{copy_stat_into_wasm, get_cstr_path, get_current_directory},
EmEnv,
};
use super::varargs::VarArgs;
@@ -43,7 +44,6 @@ use libc::{
write,
// ENOTTY,
};
use wasmer_runtime_core::vm::Ctx;
use super::env;
use std::cell::Cell;
@@ -52,7 +52,7 @@ use std::io::Error;
use std::slice;
/// exit
pub fn ___syscall1(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) {
pub fn ___syscall1(ctx: &mut EmEnv, _which: c_int, mut varargs: VarArgs) {
debug!("emscripten::___syscall1 (exit) {}", _which);
let status: i32 = varargs.get(ctx);
unsafe {
@@ -61,7 +61,7 @@ pub fn ___syscall1(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) {
}
/// read
pub fn ___syscall3(ctx: &mut Ctx, _which: i32, mut varargs: VarArgs) -> i32 {
pub fn ___syscall3(ctx: &mut EmEnv, _which: i32, mut varargs: VarArgs) -> i32 {
// -> ssize_t
debug!("emscripten::___syscall3 (read) {}", _which);
let fd: i32 = varargs.get(ctx);
@@ -75,7 +75,7 @@ pub fn ___syscall3(ctx: &mut Ctx, _which: i32, mut varargs: VarArgs) -> i32 {
}
/// write
pub fn ___syscall4(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
pub fn ___syscall4(ctx: &mut EmEnv, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall4 (write) {}", _which);
let fd: i32 = varargs.get(ctx);
let buf: i32 = varargs.get(ctx);
@@ -86,7 +86,7 @@ pub fn ___syscall4(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int
}
/// close
pub fn ___syscall6(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
pub fn ___syscall6(ctx: &mut EmEnv, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall6 (close) {}", _which);
let fd: i32 = varargs.get(ctx);
debug!("fd: {}", fd);
@@ -94,7 +94,7 @@ pub fn ___syscall6(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int
}
// chdir
pub fn ___syscall12(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
pub fn ___syscall12(ctx: &mut EmEnv, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall12 (chdir) {}", _which);
let path_ptr = varargs.get_str(ctx);
let real_path_owned = get_cstr_path(ctx, path_ptr as *const _);
@@ -112,59 +112,59 @@ pub fn ___syscall12(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int
ret
}
pub fn ___syscall10(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
pub fn ___syscall10(_ctx: &mut EmEnv, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall10");
-1
}
pub fn ___syscall14(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
pub fn ___syscall14(_ctx: &mut EmEnv, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall14");
-1
}
pub fn ___syscall15(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
pub fn ___syscall15(_ctx: &mut EmEnv, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall15");
-1
}
// getpid
pub fn ___syscall20(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
pub fn ___syscall20(_ctx: &mut EmEnv, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall20 (getpid)");
unsafe { getpid() }
}
pub fn ___syscall21(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
pub fn ___syscall21(_ctx: &mut EmEnv, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall21");
-1
}
pub fn ___syscall25(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
pub fn ___syscall25(_ctx: &mut EmEnv, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall25");
-1
}
pub fn ___syscall29(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
pub fn ___syscall29(_ctx: &mut EmEnv, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall29");
-1
}
pub fn ___syscall32(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
pub fn ___syscall32(_ctx: &mut EmEnv, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall32");
-1
}
pub fn ___syscall33(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
pub fn ___syscall33(_ctx: &mut EmEnv, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall33");
-1
}
pub fn ___syscall36(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
pub fn ___syscall36(_ctx: &mut EmEnv, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall36");
-1
}
// rename
pub fn ___syscall38(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> i32 {
pub fn ___syscall38(ctx: &mut EmEnv, _which: c_int, mut varargs: VarArgs) -> i32 {
debug!("emscripten::___syscall38 (rename)");
let old_path = varargs.get_str(ctx);
let new_path = varargs.get_str(ctx);
@@ -191,7 +191,7 @@ pub fn ___syscall38(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> i32 {
}
// rmdir
pub fn ___syscall40(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
pub fn ___syscall40(ctx: &mut EmEnv, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall40 (rmdir)");
let pathname_addr = varargs.get_str(ctx);
let real_path_owned = get_cstr_path(ctx, pathname_addr as *const _);
@@ -204,7 +204,7 @@ pub fn ___syscall40(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int
}
// pipe
pub fn ___syscall42(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
pub fn ___syscall42(ctx: &mut EmEnv, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall42 (pipe)");
// offset to a file descriptor, which contains a read end and write end, 2 integers
let fd_offset: u32 = varargs.get(ctx);
@@ -232,28 +232,28 @@ pub fn ___syscall42(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int
result
}
pub fn ___syscall51(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
pub fn ___syscall51(_ctx: &mut EmEnv, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall51");
-1
}
pub fn ___syscall52(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
pub fn ___syscall52(_ctx: &mut EmEnv, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall52");
-1
}
pub fn ___syscall53(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
pub fn ___syscall53(_ctx: &mut EmEnv, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall53");
-1
}
pub fn ___syscall60(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
pub fn ___syscall60(_ctx: &mut EmEnv, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall60");
-1
}
// dup2
pub fn ___syscall63(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
pub fn ___syscall63(ctx: &mut EmEnv, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall63 (dup2) {}", _which);
let src: i32 = varargs.get(ctx);
@@ -263,93 +263,93 @@ pub fn ___syscall63(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int
}
// getppid
pub fn ___syscall64(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
pub fn ___syscall64(_ctx: &mut EmEnv, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall64 (getppid)");
unsafe { getpid() }
}
pub fn ___syscall66(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
pub fn ___syscall66(_ctx: &mut EmEnv, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall66");
-1
}
pub fn ___syscall75(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
pub fn ___syscall75(_ctx: &mut EmEnv, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall75");
-1
}
pub fn ___syscall91(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
pub fn ___syscall91(_ctx: &mut EmEnv, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall91 - stub");
0
}
pub fn ___syscall96(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
pub fn ___syscall96(_ctx: &mut EmEnv, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall96");
-1
}
pub fn ___syscall97(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
pub fn ___syscall97(_ctx: &mut EmEnv, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall97");
-1
}
pub fn ___syscall110(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
pub fn ___syscall110(_ctx: &mut EmEnv, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall110");
-1
}
pub fn ___syscall121(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
pub fn ___syscall121(_ctx: &mut EmEnv, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall121");
-1
}
pub fn ___syscall125(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
pub fn ___syscall125(_ctx: &mut EmEnv, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall125");
-1
}
pub fn ___syscall133(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
pub fn ___syscall133(_ctx: &mut EmEnv, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall133");
-1
}
pub fn ___syscall144(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
pub fn ___syscall144(_ctx: &mut EmEnv, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall144");
-1
}
pub fn ___syscall147(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
pub fn ___syscall147(_ctx: &mut EmEnv, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall147");
-1
}
pub fn ___syscall150(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
pub fn ___syscall150(_ctx: &mut EmEnv, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall150");
-1
}
pub fn ___syscall151(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
pub fn ___syscall151(_ctx: &mut EmEnv, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall151");
-1
}
pub fn ___syscall152(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
pub fn ___syscall152(_ctx: &mut EmEnv, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall152");
-1
}
pub fn ___syscall153(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
pub fn ___syscall153(_ctx: &mut EmEnv, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall153");
-1
}
pub fn ___syscall163(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
pub fn ___syscall163(_ctx: &mut EmEnv, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall163");
-1
}
// getcwd
pub fn ___syscall183(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> i32 {
pub fn ___syscall183(ctx: &mut EmEnv, _which: c_int, mut varargs: VarArgs) -> i32 {
debug!("emscripten::___syscall183");
let buf_offset: WasmPtr<libc::c_char, Array> = varargs.get(ctx);
let _size: c_int = varargs.get(ctx);
@@ -366,7 +366,7 @@ pub fn ___syscall183(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> i32
}
// mmap2
pub fn ___syscall192(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
pub fn ___syscall192(ctx: &mut EmEnv, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall192 (mmap2) {}", _which);
let _addr: i32 = varargs.get(ctx);
let len: u32 = varargs.get(ctx);
@@ -401,7 +401,7 @@ pub fn ___syscall192(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in
}
/// lseek
pub fn ___syscall140(ctx: &mut Ctx, _which: i32, mut varargs: VarArgs) -> i32 {
pub fn ___syscall140(ctx: &mut EmEnv, _which: i32, mut varargs: VarArgs) -> i32 {
// -> c_int
debug!("emscripten::___syscall140 (lseek) {}", _which);
let fd: i32 = varargs.get(ctx);
@@ -429,7 +429,7 @@ pub fn ___syscall140(ctx: &mut Ctx, _which: i32, mut varargs: VarArgs) -> i32 {
/// readv
#[allow(clippy::cast_ptr_alignment)]
pub fn ___syscall145(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> i32 {
pub fn ___syscall145(ctx: &mut EmEnv, _which: c_int, mut varargs: VarArgs) -> i32 {
// -> ssize_t
debug!("emscripten::___syscall145 (readv) {}", _which);
@@ -466,7 +466,7 @@ pub fn ___syscall145(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> i32
// writev
#[allow(clippy::cast_ptr_alignment)]
pub fn ___syscall146(ctx: &mut Ctx, _which: i32, mut varargs: VarArgs) -> i32 {
pub fn ___syscall146(ctx: &mut EmEnv, _which: i32, mut varargs: VarArgs) -> i32 {
// -> ssize_t
debug!("emscripten::___syscall146 (writev) {}", _which);
let fd: i32 = varargs.get(ctx);
@@ -507,7 +507,7 @@ pub fn ___syscall146(ctx: &mut Ctx, _which: i32, mut varargs: VarArgs) -> i32 {
ret as _
}
pub fn ___syscall191(ctx: &mut Ctx, _which: i32, mut varargs: VarArgs) -> i32 {
pub fn ___syscall191(ctx: &mut EmEnv, _which: i32, mut varargs: VarArgs) -> i32 {
let _resource: i32 = varargs.get(ctx);
debug!(
"emscripten::___syscall191 - mostly stub, resource: {}",
@@ -524,13 +524,13 @@ pub fn ___syscall191(ctx: &mut Ctx, _which: i32, mut varargs: VarArgs) -> i32 {
0
}
pub fn ___syscall193(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
pub fn ___syscall193(_ctx: &mut EmEnv, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall193");
-1
}
// stat64
pub fn ___syscall195(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
pub fn ___syscall195(ctx: &mut EmEnv, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall195 (stat64) {}", _which);
let pathname_addr = varargs.get_str(ctx);
let buf: u32 = varargs.get(ctx);
@@ -561,7 +561,7 @@ pub fn ___syscall195(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in
}
// fstat64
pub fn ___syscall197(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
pub fn ___syscall197(ctx: &mut EmEnv, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall197 (fstat64) {}", _which);
let fd: c_int = varargs.get(ctx);
@@ -580,129 +580,129 @@ pub fn ___syscall197(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in
0
}
pub fn ___syscall209(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
pub fn ___syscall209(_ctx: &mut EmEnv, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall209");
-1
}
pub fn ___syscall211(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
pub fn ___syscall211(_ctx: &mut EmEnv, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall211");
-1
}
pub fn ___syscall218(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
pub fn ___syscall218(_ctx: &mut EmEnv, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall218");
-1
}
pub fn ___syscall268(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
pub fn ___syscall268(_ctx: &mut EmEnv, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall268");
-1
}
pub fn ___syscall269(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
pub fn ___syscall269(_ctx: &mut EmEnv, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall269");
-1
}
pub fn ___syscall272(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
pub fn ___syscall272(_ctx: &mut EmEnv, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall272");
-1
}
pub fn ___syscall295(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
pub fn ___syscall295(_ctx: &mut EmEnv, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall295");
-1
}
pub fn ___syscall296(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
pub fn ___syscall296(_ctx: &mut EmEnv, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall296");
-1
}
pub fn ___syscall297(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
pub fn ___syscall297(_ctx: &mut EmEnv, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall297");
-1
}
pub fn ___syscall298(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
pub fn ___syscall298(_ctx: &mut EmEnv, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall298");
-1
}
pub fn ___syscall300(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
pub fn ___syscall300(_ctx: &mut EmEnv, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall300");
-1
}
pub fn ___syscall301(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
pub fn ___syscall301(_ctx: &mut EmEnv, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall301");
-1
}
pub fn ___syscall302(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
pub fn ___syscall302(_ctx: &mut EmEnv, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall302");
-1
}
pub fn ___syscall303(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
pub fn ___syscall303(_ctx: &mut EmEnv, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall303");
-1
}
pub fn ___syscall304(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
pub fn ___syscall304(_ctx: &mut EmEnv, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall304");
-1
}
pub fn ___syscall305(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
pub fn ___syscall305(_ctx: &mut EmEnv, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall305");
-1
}
pub fn ___syscall306(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
pub fn ___syscall306(_ctx: &mut EmEnv, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall306");
-1
}
pub fn ___syscall307(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
pub fn ___syscall307(_ctx: &mut EmEnv, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall307");
-1
}
pub fn ___syscall308(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
pub fn ___syscall308(_ctx: &mut EmEnv, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall308");
-1
}
// utimensat
pub fn ___syscall320(_ctx: &mut Ctx, _which: c_int, mut _varargs: VarArgs) -> c_int {
pub fn ___syscall320(_ctx: &mut EmEnv, _which: c_int, mut _varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall320 (utimensat), {}", _which);
0
}
pub fn ___syscall331(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
pub fn ___syscall331(_ctx: &mut EmEnv, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall331");
-1
}
pub fn ___syscall333(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
pub fn ___syscall333(_ctx: &mut EmEnv, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall333");
-1
}
pub fn ___syscall334(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
pub fn ___syscall334(_ctx: &mut EmEnv, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall334");
-1
}
pub fn ___syscall337(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
pub fn ___syscall337(_ctx: &mut EmEnv, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall337");
-1
}
// prlimit64
pub fn ___syscall340(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
pub fn ___syscall340(ctx: &mut EmEnv, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall340 (prlimit64), {}", _which);
// NOTE: Doesn't really matter. Wasm modules cannot exceed WASM_PAGE_SIZE anyway.
let _pid: i32 = varargs.get(ctx);
@@ -728,7 +728,7 @@ pub fn ___syscall340(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in
0
}
pub fn ___syscall345(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
pub fn ___syscall345(_ctx: &mut EmEnv, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall345");
-1
}

View File

@@ -112,10 +112,10 @@ fn translate_ioctl(wasm_ioctl: u32) -> c_ulong {
#[allow(unused_imports)]
use std::ffi::CStr;
use wasmer_runtime_core::vm::Ctx;
use crate::env::EmSockAddr;
use crate::utils::{self, get_cstr_path};
use crate::EmEnv;
#[allow(unused_imports)]
use std::io::Error;
use std::mem;
@@ -156,7 +156,7 @@ use libc::SO_NOSIGPIPE;
const SO_NOSIGPIPE: c_int = 0;
/// open
pub fn ___syscall5(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
pub fn ___syscall5(ctx: &mut EmEnv, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall5 (open) {}", _which);
let pathname_addr = varargs.get_str(ctx);
let flags: i32 = varargs.get(ctx);
@@ -180,7 +180,7 @@ pub fn ___syscall5(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int
}
/// link
pub fn ___syscall9(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
pub fn ___syscall9(ctx: &mut EmEnv, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall9 (link) {}", _which);
let oldname_ptr = varargs.get_str(ctx);
@@ -196,7 +196,7 @@ pub fn ___syscall9(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int
}
/// getrusage
pub fn ___syscall77(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
pub fn ___syscall77(ctx: &mut EmEnv, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall77 (getrusage) {}", _which);
let resource: c_int = varargs.get(ctx);
@@ -208,7 +208,7 @@ pub fn ___syscall77(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int
}
/// symlink
pub fn ___syscall83(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
pub fn ___syscall83(ctx: &mut EmEnv, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall83 (symlink) {}", _which);
let path1 = varargs.get_str(ctx);
@@ -236,7 +236,7 @@ pub fn ___syscall83(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int
}
/// readlink
pub fn ___syscall85(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> i32 {
pub fn ___syscall85(ctx: &mut EmEnv, _which: c_int, mut varargs: VarArgs) -> i32 {
debug!("emscripten::___syscall85 (readlink)");
let pathname_addr = varargs.get_str(ctx);
let buf = varargs.get_str(ctx);
@@ -265,7 +265,7 @@ pub fn ___syscall85(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> i32 {
}
/// ftruncate64
pub fn ___syscall194(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
pub fn ___syscall194(ctx: &mut EmEnv, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall194 (ftruncate64) {}", _which);
let _fd: c_int = varargs.get(ctx);
let _length: i64 = varargs.get(ctx);
@@ -282,7 +282,7 @@ pub fn ___syscall194(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in
}
/// lchown
pub fn ___syscall198(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
pub fn ___syscall198(ctx: &mut EmEnv, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall198 (lchown) {}", _which);
let path_ptr = varargs.get_str(ctx);
let real_path_owned = utils::get_cstr_path(ctx, path_ptr as *const _);
@@ -305,7 +305,7 @@ pub fn ___syscall198(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in
}
/// getgroups
pub fn ___syscall205(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
pub fn ___syscall205(ctx: &mut EmEnv, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall205 (getgroups) {}", _which);
let ngroups_max: c_int = varargs.get(ctx);
let groups: c_int = varargs.get(ctx);
@@ -322,7 +322,7 @@ pub fn ___syscall205(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in
}
// chown
pub fn ___syscall212(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
pub fn ___syscall212(ctx: &mut EmEnv, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall212 (chown) {}", _which);
let pathname_addr = varargs.get_str(ctx);
@@ -339,7 +339,7 @@ pub fn ___syscall212(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in
}
/// madvise
pub fn ___syscall219(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
pub fn ___syscall219(ctx: &mut EmEnv, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall212 (chown) {}", _which);
let addr_ptr: c_int = varargs.get(ctx);
@@ -352,7 +352,7 @@ pub fn ___syscall219(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in
}
/// access
pub fn ___syscall33(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
pub fn ___syscall33(ctx: &mut EmEnv, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall33 (access) {}", _which);
let path = varargs.get_str(ctx);
let real_path_owned = utils::get_cstr_path(ctx, path as *const _);
@@ -373,14 +373,14 @@ pub fn ___syscall33(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int
}
/// nice
pub fn ___syscall34(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
pub fn ___syscall34(ctx: &mut EmEnv, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall34 (nice) {}", _which);
let inc_r: c_int = varargs.get(ctx);
unsafe { nice(inc_r) }
}
// mkdir
pub fn ___syscall39(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
pub fn ___syscall39(ctx: &mut EmEnv, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall39 (mkdir) {}", _which);
let pathname_addr = varargs.get_str(ctx);
let real_path_owned = utils::get_cstr_path(ctx, pathname_addr as *const _);
@@ -394,20 +394,20 @@ pub fn ___syscall39(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int
}
/// dup
pub fn ___syscall41(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
pub fn ___syscall41(ctx: &mut EmEnv, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall41 (dup) {}", _which);
let fd: c_int = varargs.get(ctx);
unsafe { dup(fd) }
}
/// getgid32
pub fn ___syscall200(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
pub fn ___syscall200(_ctx: &mut EmEnv, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall200 (getgid32)");
unsafe { getgid() as i32 }
}
// geteuid32
pub fn ___syscall201(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
pub fn ___syscall201(_ctx: &mut EmEnv, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall201 (geteuid32)");
unsafe {
// Maybe fix: Emscripten returns 0 always
@@ -416,7 +416,7 @@ pub fn ___syscall201(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
}
// getegid32
pub fn ___syscall202(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
pub fn ___syscall202(_ctx: &mut EmEnv, _one: i32, _two: i32) -> i32 {
// gid_t
debug!("emscripten::___syscall202 (getegid32)");
unsafe {
@@ -426,7 +426,7 @@ pub fn ___syscall202(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
}
/// fchown
pub fn ___syscall207(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
pub fn ___syscall207(ctx: &mut EmEnv, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall207 (fchown) {}", _which);
let fd: c_int = varargs.get(ctx);
let owner: uid_t = varargs.get(ctx);
@@ -435,7 +435,7 @@ pub fn ___syscall207(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in
}
/// dup3
pub fn ___syscall330(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> pid_t {
pub fn ___syscall330(ctx: &mut EmEnv, _which: c_int, mut varargs: VarArgs) -> pid_t {
// Implementation based on description at https://linux.die.net/man/2/dup3
debug!("emscripten::___syscall330 (dup3)");
let oldfd: c_int = varargs.get(ctx);
@@ -469,7 +469,7 @@ pub fn ___syscall330(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> pid_
}
/// ioctl
pub fn ___syscall54(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
pub fn ___syscall54(ctx: &mut EmEnv, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall54 (ioctl) {}", _which);
let fd: i32 = varargs.get(ctx);
@@ -511,7 +511,7 @@ const SOCK_CLOEXC: i32 = 0x80000;
// socketcall
#[allow(clippy::cast_ptr_alignment)]
pub fn ___syscall102(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
pub fn ___syscall102(ctx: &mut EmEnv, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall102 (socketcall) {}", _which);
let call: u32 = varargs.get(ctx);
let mut socket_varargs: VarArgs = varargs.get(ctx);
@@ -829,7 +829,7 @@ fn translate_socket_name_flag(name: i32) -> i32 {
}
/// getpgid
pub fn ___syscall132(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
pub fn ___syscall132(ctx: &mut EmEnv, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall132 (getpgid)");
let pid: pid_t = varargs.get(ctx);
@@ -850,10 +850,10 @@ pub struct EmPollFd {
pub revents: i16,
}
unsafe impl wasmer_runtime_core::types::ValueType for EmPollFd {}
unsafe impl wasmer::ValueType for EmPollFd {}
/// poll
pub fn ___syscall168(ctx: &mut Ctx, _which: i32, mut varargs: VarArgs) -> i32 {
pub fn ___syscall168(ctx: &mut EmEnv, _which: i32, mut varargs: VarArgs) -> i32 {
debug!("emscripten::___syscall168(poll)");
let fds: WasmPtr<EmPollFd> = varargs.get(ctx);
let nfds: u32 = varargs.get(ctx);
@@ -873,7 +873,7 @@ pub fn ___syscall168(ctx: &mut Ctx, _which: i32, mut varargs: VarArgs) -> i32 {
}
// pread
pub fn ___syscall180(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
pub fn ___syscall180(ctx: &mut EmEnv, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall180 (pread) {}", _which);
let fd: i32 = varargs.get(ctx);
let buf: u32 = varargs.get(ctx);
@@ -890,7 +890,7 @@ pub fn ___syscall180(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in
}
// pwrite
pub fn ___syscall181(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
pub fn ___syscall181(ctx: &mut EmEnv, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall181 (pwrite) {}", _which);
let fd: i32 = varargs.get(ctx);
let buf: u32 = varargs.get(ctx);
@@ -911,7 +911,7 @@ pub fn ___syscall181(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in
}
/// fchmod
pub fn ___syscall94(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
pub fn ___syscall94(ctx: &mut EmEnv, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall118 (fchmod) {}", _which);
let fd: c_int = varargs.get(ctx);
let mode: mode_t = varargs.get(ctx);
@@ -920,7 +920,7 @@ pub fn ___syscall94(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int
/// wait4
#[allow(clippy::cast_ptr_alignment)]
pub fn ___syscall114(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> pid_t {
pub fn ___syscall114(ctx: &mut EmEnv, _which: c_int, mut varargs: VarArgs) -> pid_t {
debug!("emscripten::___syscall114 (wait4)");
let pid: pid_t = varargs.get(ctx);
let status: u32 = varargs.get(ctx);
@@ -938,7 +938,7 @@ pub fn ___syscall114(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> pid_
}
/// fsync
pub fn ___syscall118(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
pub fn ___syscall118(ctx: &mut EmEnv, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall118 (fsync) {}", _which);
let fd: c_int = varargs.get(ctx);
unsafe { fsync(fd) }
@@ -946,7 +946,7 @@ pub fn ___syscall118(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in
// select
#[allow(clippy::cast_ptr_alignment)]
pub fn ___syscall142(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
pub fn ___syscall142(ctx: &mut EmEnv, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall142 (newselect) {}", _which);
let nfds: i32 = varargs.get(ctx);
@@ -968,7 +968,7 @@ pub fn ___syscall142(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in
}
/// fdatasync
pub fn ___syscall148(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
pub fn ___syscall148(ctx: &mut EmEnv, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall148 (fdatasync) {}", _which);
let fd: i32 = varargs.get(ctx);
@@ -977,7 +977,7 @@ pub fn ___syscall148(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in
}
// setpgid
pub fn ___syscall57(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
pub fn ___syscall57(ctx: &mut EmEnv, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall57 (setpgid) {}", _which);
let pid: i32 = varargs.get(ctx);
@@ -993,7 +993,7 @@ pub fn ___syscall57(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int
/// uname
// NOTE: Wondering if we should return custom utsname, like Emscripten.
pub fn ___syscall122(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
pub fn ___syscall122(ctx: &mut EmEnv, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall122 (uname) {}", _which);
let buf: u32 = varargs.get(ctx);
debug!("=> buf: {}", buf);
@@ -1002,7 +1002,7 @@ pub fn ___syscall122(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in
}
/// lstat64
pub fn ___syscall196(ctx: &mut Ctx, _which: i32, mut varargs: VarArgs) -> i32 {
pub fn ___syscall196(ctx: &mut EmEnv, _which: i32, mut varargs: VarArgs) -> i32 {
debug!("emscripten::___syscall196 (lstat64) {}", _which);
let path = varargs.get_str(ctx);
let real_path_owned = utils::get_cstr_path(ctx, path as *const _);
@@ -1035,7 +1035,7 @@ pub fn ___syscall196(ctx: &mut Ctx, _which: i32, mut varargs: VarArgs) -> i32 {
}
// getuid
pub fn ___syscall199(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
pub fn ___syscall199(_ctx: &mut EmEnv, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall199 (getuid)");
let uid = unsafe { getuid() as _ };
debug!(" => {}", uid);
@@ -1045,7 +1045,7 @@ pub fn ___syscall199(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
// getdents
// dirent structure is
// i64, i64, u16 (280), i8, [i8; 256]
pub fn ___syscall220(ctx: &mut Ctx, _which: i32, mut varargs: VarArgs) -> i32 {
pub fn ___syscall220(ctx: &mut EmEnv, _which: i32, mut varargs: VarArgs) -> i32 {
use super::super::env::get_emscripten_data;
let fd: i32 = varargs.get(ctx);
@@ -1109,7 +1109,7 @@ pub fn ___syscall220(ctx: &mut Ctx, _which: i32, mut varargs: VarArgs) -> i32 {
}
// fcntl64
pub fn ___syscall221(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
pub fn ___syscall221(ctx: &mut EmEnv, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall221 (fcntl64) {}", _which);
let fd: i32 = varargs.get(ctx);
let cmd: i32 = varargs.get(ctx);
@@ -1127,7 +1127,7 @@ pub fn ___syscall221(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in
}
/// fallocate
pub fn ___syscall324(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
pub fn ___syscall324(ctx: &mut EmEnv, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall324 (fallocate) {}", _which);
let _fd: c_int = varargs.get(ctx);
let _mode: c_int = varargs.get(ctx);

View File

@@ -1,5 +1,6 @@
use crate::utils::{copy_cstr_into_wasm, get_cstr_path};
use crate::varargs::VarArgs;
use crate::EmEnv;
use libc::mkdir;
use libc::open;
use std::env;
@@ -7,13 +8,12 @@ use std::ffi::CString;
use std::fs::File;
use std::io::Write;
use std::os::raw::c_int;
use wasmer_runtime_core::vm::Ctx;
#[allow(non_camel_case_types)]
type pid_t = c_int;
/// open
pub fn ___syscall5(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int {
pub fn ___syscall5(ctx: &mut EmEnv, which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall5 (open) {}", which);
#[cfg(not(feature = "debug"))]
let _ = which;
@@ -64,19 +64,19 @@ pub fn ___syscall5(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int {
}
/// link
pub fn ___syscall9(_ctx: &mut Ctx, _which: c_int, mut _varargs: VarArgs) -> c_int {
pub fn ___syscall9(_ctx: &mut EmEnv, _which: c_int, mut _varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall9 (link) {}", _which);
unimplemented!("emscripten::___syscall9 (link) {}", _which);
}
/// ftruncate64
pub fn ___syscall194(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
pub fn ___syscall194(_ctx: &mut EmEnv, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall194 - stub");
unimplemented!("emscripten::___syscall194 - stub")
}
// chown
pub fn ___syscall212(_ctx: &mut Ctx, which: c_int, mut _varargs: VarArgs) -> c_int {
pub fn ___syscall212(_ctx: &mut EmEnv, which: c_int, mut _varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall212 (chown) {}", which);
#[cfg(not(feature = "debug"))]
let _ = which;
@@ -84,19 +84,19 @@ pub fn ___syscall212(_ctx: &mut Ctx, which: c_int, mut _varargs: VarArgs) -> c_i
}
/// access
pub fn ___syscall33(_ctx: &mut Ctx, _which: c_int, mut _varargs: VarArgs) -> c_int {
pub fn ___syscall33(_ctx: &mut EmEnv, _which: c_int, mut _varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall33 (access) {}", _which);
unimplemented!("emscripten::___syscall33 (access) {}", _which);
}
/// nice
pub fn ___syscall34(_ctx: &mut Ctx, _which: c_int, mut _varargs: VarArgs) -> c_int {
pub fn ___syscall34(_ctx: &mut EmEnv, _which: c_int, mut _varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall34 (nice) {}", _which);
unimplemented!("emscripten::___syscall34 (nice) {}", _which);
}
// mkdir
pub fn ___syscall39(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int {
pub fn ___syscall39(ctx: &mut EmEnv, which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall39 (mkdir) {}", which);
#[cfg(not(feature = "debug"))]
let _ = which;
@@ -111,80 +111,80 @@ pub fn ___syscall39(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int
}
/// dup
pub fn ___syscall41(_ctx: &mut Ctx, _which: c_int, _varargs: VarArgs) -> c_int {
pub fn ___syscall41(_ctx: &mut EmEnv, _which: c_int, _varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall41 (dup) {}", _which);
unimplemented!("emscripten::___syscall41 (dup) {}", _which);
}
/// getrusage
pub fn ___syscall77(_ctx: &mut Ctx, _which: c_int, _varargs: VarArgs) -> c_int {
pub fn ___syscall77(_ctx: &mut EmEnv, _which: c_int, _varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall77 (getrusage) {}", _which);
unimplemented!("emscripten::___syscall77 (getrusage) {}", _which);
}
/// symlink
pub fn ___syscall83(_ctx: &mut Ctx, _which: c_int, _varargs: VarArgs) -> c_int {
pub fn ___syscall83(_ctx: &mut EmEnv, _which: c_int, _varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall83 (symlink) {}", _which);
unimplemented!("emscripten::___syscall83 (symlink) {}", _which);
}
/// readlink
pub fn ___syscall85(_ctx: &mut Ctx, _which: c_int, _varargs: VarArgs) -> c_int {
pub fn ___syscall85(_ctx: &mut EmEnv, _which: c_int, _varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall85 (readlink) {}", _which);
-1
}
/// getpgid
pub fn ___syscall132(_ctx: &mut Ctx, _which: c_int, mut _varargs: VarArgs) -> c_int {
pub fn ___syscall132(_ctx: &mut EmEnv, _which: c_int, mut _varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall132 (getpgid)");
-1
}
/// lchown
pub fn ___syscall198(_ctx: &mut Ctx, _which: c_int, _varargs: VarArgs) -> c_int {
pub fn ___syscall198(_ctx: &mut EmEnv, _which: c_int, _varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall198 (lchown) {}", _which);
unimplemented!("emscripten::___syscall198 (lchown) {}", _which);
}
/// getgid32
pub fn ___syscall200(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
pub fn ___syscall200(_ctx: &mut EmEnv, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall200 (getgid32)");
unimplemented!("emscripten::___syscall200 (getgid32)");
}
// geteuid32
pub fn ___syscall201(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
pub fn ___syscall201(_ctx: &mut EmEnv, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall201 (geteuid32)");
unimplemented!("emscripten::___syscall201 (geteuid32)");
}
// getegid32
pub fn ___syscall202(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
pub fn ___syscall202(_ctx: &mut EmEnv, _one: i32, _two: i32) -> i32 {
// gid_t
debug!("emscripten::___syscall202 (getegid32)");
unimplemented!("emscripten::___syscall202 (getegid32)");
}
/// getgroups
pub fn ___syscall205(_ctx: &mut Ctx, _which: c_int, _varargs: VarArgs) -> c_int {
pub fn ___syscall205(_ctx: &mut EmEnv, _which: c_int, _varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall205 (getgroups) {}", _which);
unimplemented!("emscripten::___syscall205 (getgroups) {}", _which);
}
/// madvise
pub fn ___syscall219(_ctx: &mut Ctx, _which: c_int, _varargs: VarArgs) -> c_int {
pub fn ___syscall219(_ctx: &mut EmEnv, _which: c_int, _varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall212 (chown) {}", _which);
unimplemented!("emscripten::___syscall212 (chown) {}", _which);
}
/// dup3
pub fn ___syscall330(_ctx: &mut Ctx, _which: c_int, mut _varargs: VarArgs) -> pid_t {
pub fn ___syscall330(_ctx: &mut EmEnv, _which: c_int, mut _varargs: VarArgs) -> pid_t {
debug!("emscripten::___syscall330 (dup3)");
-1
}
/// ioctl
pub fn ___syscall54(_ctx: &mut Ctx, which: c_int, mut _varargs: VarArgs) -> c_int {
pub fn ___syscall54(_ctx: &mut EmEnv, which: c_int, mut _varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall54 (ioctl) {}", which);
#[cfg(not(feature = "debug"))]
let _ = which;
@@ -192,14 +192,14 @@ pub fn ___syscall54(_ctx: &mut Ctx, which: c_int, mut _varargs: VarArgs) -> c_in
}
/// fchmod
pub fn ___syscall94(_ctx: &mut Ctx, _which: c_int, _varargs: VarArgs) -> c_int {
pub fn ___syscall94(_ctx: &mut EmEnv, _which: c_int, _varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall118 (fchmod) {}", _which);
unimplemented!("emscripten::___syscall118 (fchmod) {}", _which);
}
// socketcall
#[allow(clippy::cast_ptr_alignment)]
pub fn ___syscall102(_ctx: &mut Ctx, which: c_int, mut _varargs: VarArgs) -> c_int {
pub fn ___syscall102(_ctx: &mut EmEnv, which: c_int, mut _varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall102 (socketcall) {}", which);
#[cfg(not(feature = "debug"))]
let _ = which;
@@ -207,13 +207,13 @@ pub fn ___syscall102(_ctx: &mut Ctx, which: c_int, mut _varargs: VarArgs) -> c_i
}
/// fsync
pub fn ___syscall118(_ctx: &mut Ctx, _which: c_int, _varargs: VarArgs) -> c_int {
pub fn ___syscall118(_ctx: &mut EmEnv, _which: c_int, _varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall118 (fsync) {}", _which);
unimplemented!("emscripten::___syscall118 (fsync) {}", _which);
}
// pread
pub fn ___syscall180(_ctx: &mut Ctx, which: c_int, mut _varargs: VarArgs) -> c_int {
pub fn ___syscall180(_ctx: &mut EmEnv, which: c_int, mut _varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall180 (pread) {}", which);
#[cfg(not(feature = "debug"))]
let _ = which;
@@ -221,7 +221,7 @@ pub fn ___syscall180(_ctx: &mut Ctx, which: c_int, mut _varargs: VarArgs) -> c_i
}
// pwrite
pub fn ___syscall181(_ctx: &mut Ctx, which: c_int, mut _varargs: VarArgs) -> c_int {
pub fn ___syscall181(_ctx: &mut EmEnv, which: c_int, mut _varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall181 (pwrite) {}", which);
#[cfg(not(feature = "debug"))]
let _ = which;
@@ -230,14 +230,14 @@ pub fn ___syscall181(_ctx: &mut Ctx, which: c_int, mut _varargs: VarArgs) -> c_i
/// wait4
#[allow(clippy::cast_ptr_alignment)]
pub fn ___syscall114(_ctx: &mut Ctx, _which: c_int, mut _varargs: VarArgs) -> pid_t {
pub fn ___syscall114(_ctx: &mut EmEnv, _which: c_int, mut _varargs: VarArgs) -> pid_t {
debug!("emscripten::___syscall114 (wait4)");
-1
}
// select
#[allow(clippy::cast_ptr_alignment)]
pub fn ___syscall142(_ctx: &mut Ctx, which: c_int, mut _varargs: VarArgs) -> c_int {
pub fn ___syscall142(_ctx: &mut EmEnv, which: c_int, mut _varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall142 (newselect) {}", which);
#[cfg(not(feature = "debug"))]
let _ = which;
@@ -245,13 +245,13 @@ pub fn ___syscall142(_ctx: &mut Ctx, which: c_int, mut _varargs: VarArgs) -> c_i
}
/// fdatasync
pub fn ___syscall148(_ctx: &mut Ctx, _which: c_int, _varargs: VarArgs) -> c_int {
pub fn ___syscall148(_ctx: &mut EmEnv, _which: c_int, _varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall148 (fdatasync) {}", _which);
unimplemented!("emscripten::___syscall148 (fdatasync) {}", _which);
}
// setpgid
pub fn ___syscall57(_ctx: &mut Ctx, which: c_int, mut _varargs: VarArgs) -> c_int {
pub fn ___syscall57(_ctx: &mut EmEnv, which: c_int, mut _varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall57 (setpgid) {}", which);
#[cfg(not(feature = "debug"))]
let _ = which;
@@ -260,7 +260,7 @@ pub fn ___syscall57(_ctx: &mut Ctx, which: c_int, mut _varargs: VarArgs) -> c_in
/// uname
// NOTE: Wondering if we should return custom utsname, like Emscripten.
pub fn ___syscall122(_ctx: &mut Ctx, which: c_int, mut _varargs: VarArgs) -> c_int {
pub fn ___syscall122(_ctx: &mut EmEnv, which: c_int, mut _varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall122 (uname) {}", which);
#[cfg(not(feature = "debug"))]
let _ = which;
@@ -268,43 +268,43 @@ pub fn ___syscall122(_ctx: &mut Ctx, which: c_int, mut _varargs: VarArgs) -> c_i
}
/// poll
pub fn ___syscall168(_ctx: &mut Ctx, _which: i32, _varargs: VarArgs) -> i32 {
pub fn ___syscall168(_ctx: &mut EmEnv, _which: i32, _varargs: VarArgs) -> i32 {
debug!("emscripten::___syscall168(poll) - stub");
-1
}
/// lstat64
pub fn ___syscall196(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
pub fn ___syscall196(_ctx: &mut EmEnv, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall196 (lstat64) - stub");
-1
}
// getuid
pub fn ___syscall199(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
pub fn ___syscall199(_ctx: &mut EmEnv, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall199 (getuid)");
-1
}
// getdents
pub fn ___syscall220(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
pub fn ___syscall220(_ctx: &mut EmEnv, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall220");
-1
}
// fcntl64
pub fn ___syscall221(_ctx: &mut Ctx, _which: c_int, mut _varargs: VarArgs) -> c_int {
pub fn ___syscall221(_ctx: &mut EmEnv, _which: c_int, mut _varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall221 (fcntl64) {}", _which);
-1
}
/// fchown
pub fn ___syscall207(_ctx: &mut Ctx, _which: c_int, _varargs: VarArgs) -> c_int {
pub fn ___syscall207(_ctx: &mut EmEnv, _which: c_int, _varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall207 (fchown) {}", _which);
unimplemented!("emscripten::___syscall207 (fchown) {}", _which)
}
/// fallocate
pub fn ___syscall324(_ctx: &mut Ctx, _which: c_int, _varargs: VarArgs) -> c_int {
pub fn ___syscall324(_ctx: &mut EmEnv, _which: c_int, _varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall324 (fallocate) {}", _which);
unimplemented!("emscripten::___syscall324 (fallocate) {}", _which)
}

View File

@@ -1,5 +1,5 @@
use super::utils::{copy_cstr_into_wasm, write_to_buf};
use crate::allocate_on_stack;
use crate::{allocate_on_stack, EmEnv};
use libc::{c_char, c_int};
// use libc::{c_char, c_int, clock_getres, clock_settime};
use std::mem;
@@ -26,7 +26,6 @@ extern "C" {
use time;
use super::env;
use wasmer_runtime_core::vm::Ctx;
#[cfg(any(target_os = "linux", target_os = "android"))]
use libc::{CLOCK_MONOTONIC, CLOCK_MONOTONIC_COARSE, CLOCK_REALTIME};
@@ -53,7 +52,7 @@ const CLOCK_MONOTONIC_COARSE: clockid_t = 6;
/// emscripten: _gettimeofday
#[allow(clippy::cast_ptr_alignment)]
pub fn _gettimeofday(ctx: &mut Ctx, tp: c_int, tz: c_int) -> c_int {
pub fn _gettimeofday(ctx: &mut EmEnv, tp: c_int, tz: c_int) -> c_int {
debug!("emscripten::_gettimeofday {} {}", tp, tz);
#[repr(C)]
struct GuestTimeVal {
@@ -76,7 +75,7 @@ pub fn _gettimeofday(ctx: &mut Ctx, tp: c_int, tz: c_int) -> c_int {
0
}
pub fn _clock_getres(_ctx: &mut Ctx, _clk_id: i32, _tp: i32) -> i32 {
pub fn _clock_getres(_ctx: &mut EmEnv, _clk_id: i32, _tp: i32) -> i32 {
debug!("emscripten::_clock_getres");
// clock_getres(clk_id, tp)
0
@@ -84,7 +83,7 @@ pub fn _clock_getres(_ctx: &mut Ctx, _clk_id: i32, _tp: i32) -> i32 {
/// emscripten: _clock_gettime
#[allow(clippy::cast_ptr_alignment)]
pub fn _clock_gettime(ctx: &mut Ctx, clk_id: clockid_t, tp: c_int) -> c_int {
pub fn _clock_gettime(ctx: &mut EmEnv, clk_id: clockid_t, tp: c_int) -> c_int {
debug!("emscripten::_clock_gettime {} {}", clk_id, tp);
// debug!("Memory {:?}", ctx.memory(0)[..]);
#[repr(C)]
@@ -116,41 +115,41 @@ pub fn _clock_gettime(ctx: &mut Ctx, clk_id: clockid_t, tp: c_int) -> c_int {
0
}
pub fn _clock_settime(_ctx: &mut Ctx, _clk_id: i32, _tp: i32) -> i32 {
pub fn _clock_settime(_ctx: &mut EmEnv, _clk_id: i32, _tp: i32) -> i32 {
debug!("emscripten::_clock_settime");
// clock_settime(clk_id, tp)
0
}
/// emscripten: ___clock_gettime
pub fn ___clock_gettime(ctx: &mut Ctx, clk_id: clockid_t, tp: c_int) -> c_int {
pub fn ___clock_gettime(ctx: &mut EmEnv, clk_id: clockid_t, tp: c_int) -> c_int {
debug!("emscripten::___clock_gettime {} {}", clk_id, tp);
_clock_gettime(ctx, clk_id, tp)
}
/// emscripten: _clock
pub fn _clock(_ctx: &mut Ctx) -> c_int {
pub fn _clock(_ctx: &mut EmEnv) -> c_int {
debug!("emscripten::_clock");
0 // TODO: unimplemented
}
/// emscripten: _difftime
pub fn _difftime(_ctx: &mut Ctx, t0: u32, t1: u32) -> f64 {
pub fn _difftime(_ctx: &mut EmEnv, t0: u32, t1: u32) -> f64 {
debug!("emscripten::_difftime");
(t0 - t1) as _
}
pub fn _gmtime_r(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
pub fn _gmtime_r(_ctx: &mut EmEnv, _one: i32, _two: i32) -> i32 {
debug!("emscripten::_gmtime_r");
-1
}
pub fn _mktime(_ctx: &mut Ctx, _one: i32) -> i32 {
pub fn _mktime(_ctx: &mut EmEnv, _one: i32) -> i32 {
debug!("emscripten::_mktime");
-1
}
pub fn _gmtime(_ctx: &mut Ctx, _one: i32) -> i32 {
pub fn _gmtime(_ctx: &mut EmEnv, _one: i32) -> i32 {
debug!("emscripten::_gmtime");
-1
}
@@ -171,13 +170,13 @@ struct guest_tm {
}
/// emscripten: _tvset
pub fn _tvset(_ctx: &mut Ctx) {
pub fn _tvset(_ctx: &mut EmEnv) {
debug!("emscripten::_tvset UNIMPLEMENTED");
}
/// formats time as a C string
#[allow(clippy::cast_ptr_alignment)]
unsafe fn fmt_time(ctx: &mut Ctx, time: u32) -> *const c_char {
unsafe fn fmt_time(ctx: &mut EmEnv, time: u32) -> *const c_char {
let date = &*(emscripten_memory_pointer!(ctx.memory(0), time) as *mut guest_tm);
let days = vec!["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
@@ -202,7 +201,7 @@ unsafe fn fmt_time(ctx: &mut Ctx, time: u32) -> *const c_char {
}
/// emscripten: _asctime
pub fn _asctime(ctx: &mut Ctx, time: u32) -> u32 {
pub fn _asctime(ctx: &mut EmEnv, time: u32) -> u32 {
debug!("emscripten::_asctime {}", time);
unsafe {
@@ -216,7 +215,7 @@ pub fn _asctime(ctx: &mut Ctx, time: u32) -> u32 {
}
/// emscripten: _asctime_r
pub fn _asctime_r(ctx: &mut Ctx, time: u32, buf: u32) -> u32 {
pub fn _asctime_r(ctx: &mut EmEnv, time: u32, buf: u32) -> u32 {
debug!("emscripten::_asctime_r {}, {}", time, buf);
unsafe {
@@ -235,7 +234,7 @@ pub fn _asctime_r(ctx: &mut Ctx, time: u32, buf: u32) -> u32 {
/// emscripten: _localtime
#[allow(clippy::cast_ptr_alignment)]
pub fn _localtime(ctx: &mut Ctx, time_p: u32) -> c_int {
pub fn _localtime(ctx: &mut EmEnv, time_p: u32) -> c_int {
debug!("emscripten::_localtime {}", time_p);
// NOTE: emscripten seems to want tzset() called in this function
// https://stackoverflow.com/questions/19170721/real-time-awareness-of-timezone-change-in-localtime-vs-localtime-r
@@ -273,7 +272,7 @@ pub fn _localtime(ctx: &mut Ctx, time_p: u32) -> c_int {
}
/// emscripten: _localtime_r
#[allow(clippy::cast_ptr_alignment)]
pub fn _localtime_r(ctx: &mut Ctx, time_p: u32, result: u32) -> c_int {
pub fn _localtime_r(ctx: &mut EmEnv, time_p: u32, result: u32) -> c_int {
debug!("emscripten::_localtime_r {}", time_p);
// NOTE: emscripten seems to want tzset() called in this function
@@ -310,7 +309,7 @@ pub fn _localtime_r(ctx: &mut Ctx, time_p: u32, result: u32) -> c_int {
/// emscripten: _time
#[allow(clippy::cast_ptr_alignment)]
pub fn _time(ctx: &mut Ctx, time_p: u32) -> i32 {
pub fn _time(ctx: &mut EmEnv, time_p: u32) -> i32 {
debug!("emscripten::_time {}", time_p);
unsafe {
@@ -319,7 +318,7 @@ pub fn _time(ctx: &mut Ctx, time_p: u32) -> i32 {
}
}
pub fn _ctime_r(ctx: &mut Ctx, time_p: u32, buf: u32) -> u32 {
pub fn _ctime_r(ctx: &mut EmEnv, time_p: u32, buf: u32) -> u32 {
debug!("emscripten::_ctime_r {} {}", time_p, buf);
// var stack = stackSave();
@@ -330,7 +329,7 @@ pub fn _ctime_r(ctx: &mut Ctx, time_p: u32, buf: u32) -> u32 {
rv
}
pub fn _ctime(ctx: &mut Ctx, time_p: u32) -> u32 {
pub fn _ctime(ctx: &mut EmEnv, time_p: u32) -> u32 {
debug!("emscripten::_ctime {}", time_p);
let tm_current = 2414544;
_ctime_r(ctx, time_p, tm_current)
@@ -339,7 +338,7 @@ pub fn _ctime(ctx: &mut Ctx, time_p: u32) -> u32 {
/// emscripten: _timegm
#[cfg(not(target_os = "windows"))]
#[allow(clippy::cast_ptr_alignment)]
pub fn _timegm(ctx: &mut Ctx, time_ptr: u32) -> i32 {
pub fn _timegm(ctx: &mut EmEnv, time_ptr: u32) -> i32 {
debug!("emscripten::_timegm {}", time_ptr);
unsafe {
@@ -379,7 +378,7 @@ pub fn _timegm(ctx: &mut Ctx, time_ptr: u32) -> i32 {
}
#[cfg(target_os = "windows")]
pub fn _timegm(_ctx: &mut Ctx, _time_ptr: c_int) -> i32 {
pub fn _timegm(_ctx: &mut EmEnv, _time_ptr: c_int) -> i32 {
debug!(
"emscripten::_timegm - UNIMPLEMENTED IN WINDOWS {}",
_time_ptr
@@ -389,7 +388,7 @@ pub fn _timegm(_ctx: &mut Ctx, _time_ptr: c_int) -> i32 {
/// emscripten: _strftime
pub fn _strftime(
ctx: &mut Ctx,
ctx: &mut EmEnv,
s_ptr: c_int,
maxsize: u32,
format_ptr: c_int,
@@ -449,7 +448,7 @@ pub fn _strftime(
/// emscripten: _strftime_l
pub fn _strftime_l(
ctx: &mut Ctx,
ctx: &mut EmEnv,
s_ptr: c_int,
maxsize: u32,
format_ptr: c_int,

View File

@@ -1,20 +1,20 @@
use wasmer_runtime_core::vm::Ctx;
use crate::EmEnv;
pub fn _getcontext(_ctx: &mut Ctx, _ucp: i32) -> i32 {
pub fn _getcontext(_ctx: &mut EmEnv, _ucp: i32) -> i32 {
debug!("emscripten::_getcontext({})", _ucp);
0
}
pub fn _makecontext(_ctx: &mut Ctx, _ucp: i32, _func: i32, _argc: i32, _argv: i32) {
pub fn _makecontext(_ctx: &mut EmEnv, _ucp: i32, _func: i32, _argc: i32, _argv: i32) {
debug!(
"emscripten::_makecontext({}, {}, {}, {})",
_ucp, _func, _argc, _argv
);
}
pub fn _setcontext(_ctx: &mut Ctx, _ucp: i32) -> i32 {
pub fn _setcontext(_ctx: &mut EmEnv, _ucp: i32) -> i32 {
debug!("emscripten::_setcontext({})", _ucp);
0
}
pub fn _swapcontext(_ctx: &mut Ctx, _oucp: i32, _ucp: i32) -> i32 {
pub fn _swapcontext(_ctx: &mut EmEnv, _oucp: i32, _ucp: i32) -> i32 {
debug!("emscripten::_swapcontext({}, {})", _oucp, _ucp);
0
}

View File

@@ -1,6 +1,6 @@
use wasmer_runtime_core::vm::Ctx;
use crate::EmEnv;
pub fn confstr(_ctx: &mut Ctx, _name: i32, _buf_pointer: i32, _len: i32) -> i32 {
pub fn confstr(_ctx: &mut EmEnv, _name: i32, _buf_pointer: i32, _len: i32) -> i32 {
debug!("unistd::confstr({}, {}, {})", _name, _buf_pointer, _len);
0
}

View File

@@ -1,33 +1,24 @@
use super::env;
use super::env::get_emscripten_data;
use crate::storage::align_memory;
use crate::EmEnv;
use libc::stat;
use std::ffi::CStr;
use std::mem::size_of;
use std::os::raw::c_char;
use std::path::PathBuf;
use std::slice;
use wasmer_runtime_core::memory::Memory;
use wasmer_runtime_core::{
module::Module,
structures::TypedIndex,
types::{ImportedMemoryIndex, ImportedTableIndex},
units::Pages,
vm::Ctx,
};
use wasmer::{GlobalInit, Memory, Module, Pages};
/// We check if a provided module is an Emscripten generated one
pub fn is_emscripten_module(module: &Module) -> bool {
for (_, import_name) in &module.info().imported_functions {
let namespace = module
.info()
.namespace_table
.get(import_name.namespace_index);
let field = module.info().name_table.get(import_name.name_index);
if (field == "_emscripten_memcpy_big"
|| field == "emscripten_memcpy_big"
|| field == "__map_file")
&& namespace == "env"
for import in module.imports().functions() {
let name = import.name();
let module = import.module();
if (name == "_emscripten_memcpy_big"
|| name == "emscripten_memcpy_big"
|| name == "__map_file")
&& module == "env"
{
return true;
}
@@ -36,19 +27,21 @@ pub fn is_emscripten_module(module: &Module) -> bool {
}
pub fn get_emscripten_table_size(module: &Module) -> Result<(u32, Option<u32>), String> {
if module.info().imported_tables.len() == 0 {
if let Some(import) = module.imports().tables().next() {
let ty = import.ty();
Ok((ty.minimum, ty.maximum))
} else {
return Err("Emscripten requires at least one imported table".to_string());
}
let (_, table) = &module.info().imported_tables[ImportedTableIndex::new(0)];
Ok((table.minimum, table.maximum))
}
pub fn get_emscripten_memory_size(module: &Module) -> Result<(Pages, Option<Pages>, bool), String> {
if module.info().imported_memories.len() == 0 {
if let Some(import) = module.imports().memories().next() {
let ty = import.ty();
Ok((ty.minimum, ty.maximum, ty.shared))
} else {
return Err("Emscripten requires at least one imported memory".to_string());
}
let (_, memory) = &module.info().imported_memories[ImportedMemoryIndex::new(0)];
Ok((memory.minimum, memory.maximum, memory.shared))
}
/// Reads values written by `-s EMIT_EMSCRIPTEN_METADATA=1`
@@ -56,14 +49,20 @@ pub fn get_emscripten_memory_size(module: &Module) -> Result<(Pages, Option<Page
/// Last export: Dynamic Base
/// Second-to-Last export: Dynamic top pointer
pub fn get_emscripten_metadata(module: &Module) -> Result<Option<(u32, u32)>, String> {
let max_idx = match module.info().globals.iter().map(|(k, _)| k).max() {
let max_idx = match module
.info()
.global_initializers
.iter()
.map(|(k, _)| k)
.max()
{
Some(x) => x,
None => return Ok(None),
};
let snd_max_idx = match module
.info()
.globals
.global_initializers
.iter()
.map(|(k, _)| k)
.filter(|k| *k != max_idx)
@@ -73,19 +72,9 @@ pub fn get_emscripten_metadata(module: &Module) -> Result<Option<(u32, u32)>, St
None => return Ok(None),
};
use wasmer_runtime_core::types::{GlobalInit, Initializer::Const, Value::I32};
if let (
GlobalInit {
init: Const(I32(dynamic_base)),
..
},
GlobalInit {
init: Const(I32(dynamictop_ptr)),
..
},
) = (
&module.info().globals[max_idx],
&module.info().globals[snd_max_idx],
if let (GlobalInit::I32Const(dynamic_base), GlobalInit::I32Const(dynamictop_ptr)) = (
&module.info().global_initializers[max_idx],
&module.info().global_initializers[snd_max_idx],
) {
let dynamic_base = (*dynamic_base as u32).checked_sub(32).ok_or(format!(
"emscripten unexpected dynamic_base {}",
@@ -104,7 +93,7 @@ pub fn get_emscripten_metadata(module: &Module) -> Result<Option<(u32, u32)>, St
}
}
pub unsafe fn write_to_buf(ctx: &mut Ctx, string: *const c_char, buf: u32, max: u32) -> u32 {
pub unsafe fn write_to_buf(ctx: &mut EmEnv, string: *const c_char, buf: u32, max: u32) -> u32 {
let buf_addr = emscripten_memory_pointer!(ctx.memory(0), buf) as *mut c_char;
for i in 0..max {
@@ -115,7 +104,7 @@ pub unsafe fn write_to_buf(ctx: &mut Ctx, string: *const c_char, buf: u32, max:
}
/// This function expects nullbyte to be appended.
pub unsafe fn copy_cstr_into_wasm(ctx: &mut Ctx, cstr: *const c_char) -> u32 {
pub unsafe fn copy_cstr_into_wasm(ctx: &mut EmEnv, cstr: *const c_char) -> u32 {
let s = CStr::from_ptr(cstr).to_str().unwrap();
let cstr_len = s.len();
let space_offset = env::call_malloc(ctx, (cstr_len as u32) + 1);
@@ -133,7 +122,7 @@ pub unsafe fn copy_cstr_into_wasm(ctx: &mut Ctx, cstr: *const c_char) -> u32 {
space_offset
}
pub unsafe fn allocate_on_stack<'a, T: Copy>(ctx: &'a mut Ctx, count: u32) -> (u32, &'a mut [T]) {
pub unsafe fn allocate_on_stack<'a, T: Copy>(ctx: &'a mut EmEnv, count: u32) -> (u32, &'a mut [T]) {
let offset = get_emscripten_data(ctx)
.stack_alloc
.as_ref()
@@ -146,7 +135,7 @@ pub unsafe fn allocate_on_stack<'a, T: Copy>(ctx: &'a mut Ctx, count: u32) -> (u
(offset, slice)
}
pub unsafe fn allocate_cstr_on_stack<'a>(ctx: &'a mut Ctx, s: &str) -> (u32, &'a [u8]) {
pub unsafe fn allocate_cstr_on_stack<'a>(ctx: &'a mut EmEnv, s: &str) -> (u32, &'a [u8]) {
let (offset, slice) = allocate_on_stack(ctx, (s.len() + 1) as u32);
use std::iter;
@@ -158,7 +147,7 @@ pub unsafe fn allocate_cstr_on_stack<'a>(ctx: &'a mut Ctx, s: &str) -> (u32, &'a
}
#[cfg(not(target_os = "windows"))]
pub unsafe fn copy_terminated_array_of_cstrs(_ctx: &mut Ctx, cstrs: *mut *mut c_char) -> u32 {
pub unsafe fn copy_terminated_array_of_cstrs(_ctx: &mut EmEnv, cstrs: *mut *mut c_char) -> u32 {
let _total_num = {
let mut ptr = cstrs;
let mut counter = 0;
@@ -196,7 +185,7 @@ pub struct GuestStat {
}
#[allow(clippy::cast_ptr_alignment)]
pub unsafe fn copy_stat_into_wasm(ctx: &mut Ctx, buf: u32, stat: &stat) {
pub unsafe fn copy_stat_into_wasm(ctx: &mut EmEnv, buf: u32, stat: &stat) {
let stat_ptr = emscripten_memory_pointer!(ctx.memory(0), buf) as *mut GuestStat;
(*stat_ptr).st_dev = stat.st_dev as _;
(*stat_ptr).__st_dev_padding = 0;
@@ -235,7 +224,7 @@ pub fn read_string_from_wasm(memory: &Memory, offset: u32) -> String {
/// This function trys to find an entry in mapdir
/// translating paths into their correct value
pub fn get_cstr_path(ctx: &mut Ctx, path: *const i8) -> Option<std::ffi::CString> {
pub fn get_cstr_path(ctx: &mut EmEnv, path: *const i8) -> Option<std::ffi::CString> {
use std::collections::VecDeque;
let path_str =
@@ -271,7 +260,7 @@ pub fn get_cstr_path(ctx: &mut Ctx, path: *const i8) -> Option<std::ffi::CString
/// gets the current directory
/// handles mapdir logic
pub fn get_current_directory(ctx: &mut Ctx) -> Option<PathBuf> {
pub fn get_current_directory(ctx: &mut EmEnv) -> Option<PathBuf> {
if let Some(val) = get_emscripten_data(ctx).mapped_dirs.get(".") {
return Some(val.clone());
}

View File

@@ -1,5 +1,6 @@
use crate::EmEnv;
use std::mem;
use wasmer_runtime_core::{types::WasmExternType, vm::Ctx};
use wasmer::WasmExternType;
// use std::ffi::CStr;
use std::os::raw::c_char;
@@ -10,14 +11,14 @@ pub struct VarArgs {
}
impl VarArgs {
pub fn get<T: Sized>(&mut self, ctx: &mut Ctx) -> T {
pub fn get<T: Sized>(&mut self, ctx: &mut EmEnv) -> T {
let ptr = emscripten_memory_pointer!(ctx.memory(0), self.pointer);
self.pointer += mem::size_of::<T>() as u32;
unsafe { (ptr as *const T).read() }
}
// pub fn getStr<'a>(&mut self, ctx: &mut Ctx) -> &'a CStr {
pub fn get_str(&mut self, ctx: &mut Ctx) -> *const c_char {
pub fn get_str(&mut self, ctx: &mut EmEnv) -> *const c_char {
let ptr_addr: u32 = self.get(ctx);
let ptr = emscripten_memory_pointer!(ctx.memory(0), ptr_addr) as *const c_char;
ptr

View File

@@ -20,6 +20,7 @@ region = "2.1"
serde = { version = "1.0", features = ["derive", "rc"] }
serde_bytes = { version = "0.11" }
bincode = "1.2"
cfg-if = "0.1"
[target.'cfg(target_os = "windows")'.dependencies]
winapi = { version = "0.3", features = ["winnt", "impl-default"] }

View File

@@ -6,6 +6,7 @@ use crate::link::link_module;
#[cfg(feature = "compiler")]
use crate::serialize::SerializableCompilation;
use crate::serialize::SerializableModule;
use crate::unwind::UnwindRegistry;
use std::sync::{Arc, Mutex};
use wasm_common::entity::{BoxedSlice, PrimaryMap};
use wasm_common::{
@@ -14,7 +15,7 @@ use wasm_common::{
};
#[cfg(feature = "compiler")]
use wasmer_compiler::ModuleEnvironment;
use wasmer_compiler::{CompileError, Features};
use wasmer_compiler::{CompileError, Features, Triple};
use wasmer_engine::{
register_frame_info, Artifact, DeserializeError, GlobalFrameInfoRegistration, SerializeError,
};
@@ -24,10 +25,10 @@ use wasmer_runtime::{MemoryPlan, ModuleInfo, TablePlan, VMFunctionBody, VMShared
/// A compiled wasm module, ready to be instantiated.
pub struct JITArtifact {
_unwind_registry: Arc<UnwindRegistry>,
serializable: SerializableModule,
finished_functions: BoxedSlice<LocalFunctionIndex, *mut [VMFunctionBody]>,
finished_dynamic_function_trampolines: BoxedSlice<FunctionIndex, *const VMFunctionBody>,
finished_dynamic_function_trampolines: BoxedSlice<FunctionIndex, *mut [VMFunctionBody]>,
signatures: BoxedSlice<SignatureIndex, VMSharedSignatureIndex>,
frame_info_registration: Mutex<Option<GlobalFrameInfoRegistration>>,
}
@@ -119,6 +120,7 @@ impl JITArtifact {
dynamic_function_trampolines,
custom_sections: compilation.get_custom_sections(),
custom_section_relocations: compilation.get_custom_section_relocations(),
debug: compilation.get_debug(),
};
let serializable = SerializableModule {
compilation: serializable_compilation,
@@ -163,7 +165,13 @@ impl JITArtifact {
inner_jit: &mut JITEngineInner,
serializable: SerializableModule,
) -> Result<Self, CompileError> {
let (finished_functions, finished_dynamic_function_trampolines) = inner_jit.allocate(
let mut unwind_registry = UnwindRegistry::new();
let (
finished_functions,
_finished_function_call_trampolines,
finished_dynamic_function_trampolines,
) = inner_jit.allocate(
&mut unwind_registry,
&serializable.module,
&serializable.compilation.function_bodies,
&serializable.compilation.function_call_trampolines,
@@ -192,15 +200,38 @@ impl JITArtifact {
.collect::<PrimaryMap<_, _>>()
};
let eh_frame = match &serializable.compilation.debug {
Some(debug) => {
let eh_frame_section_size = serializable.compilation.custom_sections
[debug.eh_frame]
.bytes
.len();
let eh_frame_section_pointer = custom_sections[debug.eh_frame];
Some(unsafe {
std::slice::from_raw_parts(eh_frame_section_pointer, eh_frame_section_size)
})
}
None => None,
};
// Make all code compiled thus far executable.
inner_jit.publish_compiled_code();
unwind_registry.publish(eh_frame).map_err(|e| {
CompileError::Resource(format!("Error while publishing the unwind code: {}", e))
})?;
let unwind_registry = Arc::new(unwind_registry);
// Save the unwind registry into CodeMemory, so it can survive longer than
// the Module.
inner_jit.publish_unwind_registry(unwind_registry.clone());
let finished_functions = finished_functions.into_boxed_slice();
let finished_dynamic_function_trampolines =
finished_dynamic_function_trampolines.into_boxed_slice();
let signatures = signatures.into_boxed_slice();
Ok(Self {
_unwind_registry: unwind_registry,
serializable,
finished_functions,
finished_dynamic_function_trampolines,
@@ -208,6 +239,12 @@ impl JITArtifact {
frame_info_registration: Mutex::new(None),
})
}
/// Get the default extension when serializing this artifact
pub fn get_default_extension(_triple: &Triple) -> &'static str {
// `.wjit` is the default extension for all the triples
"wjit"
}
}
impl Artifact for JITArtifact {
@@ -259,9 +296,10 @@ impl Artifact for JITArtifact {
&self.finished_functions
}
// TODO: return *const instead of *mut
fn finished_dynamic_function_trampolines(
&self,
) -> &BoxedSlice<FunctionIndex, *const VMFunctionBody> {
) -> &BoxedSlice<FunctionIndex, *mut [VMFunctionBody]> {
&self.finished_dynamic_function_trampolines
}

View File

@@ -1,10 +1,14 @@
// This file contains code from external sources.
// Attributions: https://github.com/wasmerio/wasmer-reborn/blob/master/ATTRIBUTIONS.md
//! Memory management for executable code.
use crate::function_table::FunctionTable;
use crate::unwind::UnwindRegistry;
use region;
use std::mem::ManuallyDrop;
use std::sync::Arc;
use std::{cmp, mem};
use wasm_common::entity::PrimaryMap;
use wasm_common::LocalFunctionIndex;
use wasmer_compiler::{FunctionBody, SectionBody};
use wasm_common::entity::{EntityRef, PrimaryMap};
use wasmer_compiler::{CompiledFunctionUnwindInfo, FunctionBody, SectionBody};
use wasmer_runtime::{Mmap, VMFunctionBody};
/// The optimal alignment for functions.
@@ -16,29 +20,22 @@ const ARCH_FUNCTION_ALIGNMENT: usize = 16;
struct CodeMemoryEntry {
mmap: ManuallyDrop<Mmap>,
table: ManuallyDrop<FunctionTable>,
}
impl CodeMemoryEntry {
fn new() -> Self {
Self {
mmap: ManuallyDrop::new(Mmap::new()),
table: ManuallyDrop::new(FunctionTable::new()),
}
let mmap = ManuallyDrop::new(Mmap::new());
Self { mmap }
}
fn with_capacity(cap: usize) -> Result<Self, String> {
Ok(Self {
mmap: ManuallyDrop::new(Mmap::with_at_least(cap)?),
table: ManuallyDrop::new(FunctionTable::new()),
})
let mmap = ManuallyDrop::new(Mmap::with_at_least(cap)?);
Ok(Self { mmap })
}
}
impl Drop for CodeMemoryEntry {
fn drop(&mut self) {
unsafe {
// Table needs to be freed before mmap.
ManuallyDrop::drop(&mut self.table);
ManuallyDrop::drop(&mut self.mmap);
}
}
@@ -48,6 +45,8 @@ impl Drop for CodeMemoryEntry {
pub struct CodeMemory {
current: CodeMemoryEntry,
entries: Vec<CodeMemoryEntry>,
unwind_registries: Vec<Arc<UnwindRegistry>>,
read_sections: Vec<Vec<u8>>,
position: usize,
published: usize,
}
@@ -58,24 +57,56 @@ impl CodeMemory {
Self {
current: CodeMemoryEntry::new(),
entries: Vec::new(),
read_sections: Vec::new(),
unwind_registries: Vec::new(),
position: 0,
published: 0,
}
}
/// Allocate a continuous memory blocks for a single compiled function.
pub fn allocate_functions(
&mut self,
functions: &PrimaryMap<LocalFunctionIndex, FunctionBody>,
) -> Result<PrimaryMap<LocalFunctionIndex, *mut [VMFunctionBody]>, String> {
let fat_ptrs = self.allocate_for_compilation(functions)?;
// Second, create a PrimaryMap from result vector of pointers.
let mut result = PrimaryMap::with_capacity(functions.len());
for i in 0..fat_ptrs.len() {
let fat_ptr: *mut [VMFunctionBody] = fat_ptrs[i];
result.push(fat_ptr);
/// Publish the unwind registry into code memory.
pub(crate) fn publish_unwind_registry(&mut self, unwind_registry: Arc<UnwindRegistry>) {
self.unwind_registries.push(unwind_registry);
}
/// Allocate a continuous memory block for a compilation.
///
/// Allocates memory for both the function bodies as well as function unwind data.
pub fn allocate_functions<K>(
&mut self,
registry: &mut UnwindRegistry,
compilation: &PrimaryMap<K, FunctionBody>,
) -> Result<PrimaryMap<K, *mut [VMFunctionBody]>, String>
where
K: EntityRef,
{
let total_len = compilation.values().fold(0, |acc, func| {
acc + get_align_padding_size(acc, ARCH_FUNCTION_ALIGNMENT)
+ Self::function_allocation_size(func)
});
let (mut buf, start) = self.allocate(total_len, ARCH_FUNCTION_ALIGNMENT)?;
let base_address = buf.as_ptr() as usize - start;
let mut result = PrimaryMap::with_capacity(compilation.len());
let mut start = start as u32;
let mut padding = 0usize;
for func in compilation.values() {
let (next_start, next_buf, vmfunc) = Self::copy_function(
registry,
base_address,
func,
start + padding as u32,
&mut buf[padding..],
);
assert!(vmfunc as *mut _ as *mut u8 as usize % ARCH_FUNCTION_ALIGNMENT == 0);
result.push(vmfunc as *mut [VMFunctionBody]);
padding = get_align_padding_size(next_start as usize, ARCH_FUNCTION_ALIGNMENT);
start = next_start;
buf = next_buf;
}
Ok(result)
}
@@ -84,13 +115,15 @@ impl CodeMemory {
/// mmap region rather than into a Vec that we need to copy in.
pub fn allocate_for_function(
&mut self,
registry: &mut UnwindRegistry,
func: &FunctionBody,
) -> Result<&mut [VMFunctionBody], String> {
let size = Self::function_allocation_size(func);
let (buf, table, start) = self.allocate(size, ARCH_FUNCTION_ALIGNMENT)?;
let (buf, start) = self.allocate(size, ARCH_FUNCTION_ALIGNMENT)?;
let base_address = buf.as_ptr() as usize - start;
let (_, _, _, vmfunc) = Self::copy_function(func, start as u32, buf, table);
let (_, _, vmfunc) = Self::copy_function(registry, base_address, func, start as u32, buf);
assert!(vmfunc as *mut _ as *mut u8 as usize % ARCH_FUNCTION_ALIGNMENT == 0);
Ok(vmfunc)
@@ -102,42 +135,22 @@ impl CodeMemory {
section: &SectionBody,
) -> Result<&mut [u8], String> {
let section = section.as_slice();
let (buf, _, _) = self.allocate(section.len(), ARCH_FUNCTION_ALIGNMENT)?;
let (buf, _) = self.allocate(section.len(), ARCH_FUNCTION_ALIGNMENT)?;
buf.copy_from_slice(section);
Ok(buf)
}
/// Allocate a continuous memory block for a compilation.
///
/// Allocates memory for both the function bodies as well as function unwind data.
pub fn allocate_for_compilation(
/// Allocate a continuous memory block for a readable custom section.
pub fn allocate_for_custom_section(
&mut self,
compilation: &PrimaryMap<LocalFunctionIndex, FunctionBody>,
) -> Result<Box<[&mut [VMFunctionBody]]>, String> {
let total_len = compilation.values().fold(0, |acc, func| {
acc + get_align_padding_size(acc, ARCH_FUNCTION_ALIGNMENT)
+ Self::function_allocation_size(func)
});
let (mut buf, mut table, start) = self.allocate(total_len, ARCH_FUNCTION_ALIGNMENT)?;
let mut result = Vec::with_capacity(compilation.len());
let mut start = start as u32;
let mut padding = 0usize;
for func in compilation.values() {
let (next_start, next_buf, next_table, vmfunc) =
Self::copy_function(func, start + padding as u32, &mut buf[padding..], table);
assert!(vmfunc as *mut _ as *mut u8 as usize % ARCH_FUNCTION_ALIGNMENT == 0);
result.push(vmfunc);
padding = get_align_padding_size(next_start as usize, ARCH_FUNCTION_ALIGNMENT);
start = next_start;
buf = next_buf;
table = next_table;
}
Ok(result.into_boxed_slice())
section: &SectionBody,
) -> Result<&mut [u8], String> {
let section = section.as_slice().to_vec();
self.read_sections.push(section);
Ok(self
.read_sections
.last_mut()
.ok_or("Can't get last section".to_string())?)
}
/// Make all allocated memory executable.
@@ -145,11 +158,7 @@ impl CodeMemory {
self.push_current(0)
.expect("failed to push current memory map");
for CodeMemoryEntry { mmap: m, table: t } in &mut self.entries[self.published..] {
// Remove write access to the pages due to the relocation fixups.
t.publish(m.as_ptr() as u64)
.expect("failed to publish function table");
for CodeMemoryEntry { mmap: m } in &mut self.entries[self.published..] {
if !m.is_empty() {
unsafe {
region::protect(m.as_mut_ptr(), m.len(), region::Protection::READ_EXECUTE)
@@ -171,11 +180,7 @@ impl CodeMemory {
/// * A mutable slice which references the allocated memory
/// * A function table instance where unwind information is registered
/// * The offset within the current mmap that the slice starts at
fn allocate(
&mut self,
size: usize,
alignment: usize,
) -> Result<(&mut [u8], &mut FunctionTable, usize), String> {
fn allocate(&mut self, size: usize, alignment: usize) -> Result<(&mut [u8], usize), String> {
assert!(alignment > 0);
let align_padding = get_align_padding_size(self.position, alignment);
@@ -198,18 +203,20 @@ impl CodeMemory {
Ok((
&mut self.current.mmap.as_mut_slice()[old_position..self.position],
&mut self.current.table,
old_position,
))
}
/// Calculates the allocation size of the given compiled function.
fn function_allocation_size(func: &FunctionBody) -> usize {
if let Some(unwind_info) = &func.unwind_info {
// Account for necessary unwind information alignment padding (32-bit)
((func.body.len() + 3) & !3) + unwind_info.len()
} else {
func.body.len()
match &func.unwind_info {
Some(CompiledFunctionUnwindInfo::WindowsX64(info)) => {
// Windows unwind information is required to be emitted into code memory
// This is because it must be a positive relative offset from the start of the memory
// Account for necessary unwind information alignment padding (32-bit alignment)
((func.body.len() + 3) & !3) + info.len()
}
_ => func.body.len(),
}
}
@@ -217,44 +224,42 @@ impl CodeMemory {
///
/// This will also add the function to the current function table.
fn copy_function<'a>(
registry: &mut UnwindRegistry,
base_address: usize,
func: &FunctionBody,
func_start: u32,
buf: &'a mut [u8],
table: &'a mut FunctionTable,
) -> (
u32,
&'a mut [u8],
&'a mut FunctionTable,
&'a mut [VMFunctionBody],
) {
let func_end = func_start + (func.body.len() as u32);
) -> (u32, &'a mut [u8], &'a mut [VMFunctionBody]) {
assert!((func_start as usize) % ARCH_FUNCTION_ALIGNMENT == 0);
let (body, remainder) = buf.split_at_mut(func.body.len());
let func_len = func.body.len();
let mut func_end = func_start + (func_len as u32);
let (body, mut remainder) = buf.split_at_mut(func_len);
body.copy_from_slice(&func.body);
let vmfunc = Self::view_as_mut_vmfunc_slice(body);
if func.unwind_info.is_none() {
return (func_end, remainder, table, vmfunc);
}
let unwind_info = func.unwind_info.as_ref().unwrap();
if let Some(CompiledFunctionUnwindInfo::WindowsX64(info)) = &func.unwind_info {
// Windows unwind information is written following the function body
// Keep unwind information 32-bit aligned (round up to the nearest 4 byte boundary)
let padding = ((func.body.len() + 3) & !3) - func.body.len();
let (unwind, remainder) = remainder.split_at_mut(padding + unwind_info.len());
let mut relocs = Vec::new();
unwind_info.serialize(&mut unwind[padding..], &mut relocs);
let unwind_start = (func_end + 3) & !3;
let unwind_size = info.len();
let padding = (unwind_start - func_end) as usize;
assert_eq!((func_start as usize + func_len + padding) % 4, 0);
let (slice, r) = remainder.split_at_mut(padding + unwind_size);
slice[padding..].copy_from_slice(&info);
// println!("Info {:?} (func_len: {}, padded: {})", info, func_len, padding);
func_end = unwind_start + (unwind_size as u32);
remainder = r;
}
let unwind_start = func_end + (padding as u32);
let unwind_end = unwind_start + (unwind_info.len() as u32);
if let Some(info) = &func.unwind_info {
registry
.register(base_address, func_start, func_len as u32, info)
.expect("failed to register unwind information");
}
relocs.iter_mut().for_each(move |r| {
r.offset += unwind_start;
r.addend += func_start as i64;
});
table.add_function(func_start, func_end, unwind_start, &relocs);
(unwind_end, remainder, table, vmfunc)
(func_end, remainder, vmfunc)
}
/// Convert mut a slice from u8 to VMFunctionBody.
@@ -264,7 +269,7 @@ impl CodeMemory {
unsafe { &mut *body_ptr }
}
/// Pushes the current Mmap (and function table) and allocates a new Mmap of the given size.
/// Pushes the current Mmap and allocates a new Mmap of the given size.
fn push_current(&mut self, new_size: usize) -> Result<(), String> {
let previous = mem::replace(
&mut self.current,
@@ -277,8 +282,6 @@ impl CodeMemory {
if !previous.mmap.is_empty() {
self.entries.push(previous);
} else {
assert_eq!(previous.table.len(), 0);
}
self.position = 0;

View File

@@ -1,5 +1,6 @@
//! JIT compilation.
use crate::unwind::UnwindRegistry;
use crate::{CodeMemory, JITArtifact};
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
@@ -162,6 +163,7 @@ impl JITEngineInner {
))
}
/// Allocate custom sections into memory
pub(crate) fn allocate_custom_sections(
&mut self,
custom_sections: &PrimaryMap<SectionIndex, CustomSection>,
@@ -169,13 +171,21 @@ impl JITEngineInner {
let mut result = PrimaryMap::with_capacity(custom_sections.len());
for (_, section) in custom_sections.iter() {
let buffer: &[u8] = match section.protection {
CustomSectionProtection::Read => section.bytes.as_slice(),
CustomSectionProtection::Read => self
.code_memory
.allocate_for_custom_section(&section.bytes)
.map_err(|message| {
CompileError::Resource(format!(
"failed to allocate readable memory for custom section: {}",
message
))
})?,
CustomSectionProtection::ReadExecute => self
.code_memory
.allocate_for_executable_custom_section(&section.bytes)
.map_err(|message| {
CompileError::Resource(format!(
"failed to allocate memory for custom section: {}",
"failed to allocate executable memory for custom section: {}",
message
))
})?,
@@ -185,10 +195,11 @@ impl JITEngineInner {
Ok(result)
}
/// Compile the given function bodies.
/// Allocate compiled functions into memory
#[allow(clippy::type_complexity)]
pub(crate) fn allocate(
&mut self,
registry: &mut UnwindRegistry,
module: &ModuleInfo,
functions: &PrimaryMap<LocalFunctionIndex, FunctionBody>,
function_call_trampolines: &PrimaryMap<SignatureIndex, FunctionBody>,
@@ -196,15 +207,16 @@ impl JITEngineInner {
) -> Result<
(
PrimaryMap<LocalFunctionIndex, *mut [VMFunctionBody]>,
PrimaryMap<FunctionIndex, *const VMFunctionBody>,
PrimaryMap<SignatureIndex, *mut [VMFunctionBody]>,
PrimaryMap<FunctionIndex, *mut [VMFunctionBody]>,
),
CompileError,
> {
// Allocate all of the compiled functions into executable memory,
// copying over their contents.
let allocated_functions =
self.code_memory
.allocate_functions(&functions)
let allocated_functions = self
.code_memory
.allocate_functions(registry, &functions)
.map_err(|message| {
CompileError::Resource(format!(
"failed to allocate memory for functions: {}",
@@ -212,26 +224,37 @@ impl JITEngineInner {
))
})?;
let mut alllocated_function_call_trampolines: PrimaryMap<
SignatureIndex,
*mut [VMFunctionBody],
> = PrimaryMap::new();
// let (indices, compiled_functions): (Vec<VMSharedSignatureIndex>, PrimaryMap<FunctionIndex, FunctionBody>) = function_call_trampolines.iter().map(|(sig_index, compiled_function)| {
// let func_type = module.signatures.get(sig_index).unwrap();
// let index = self.signatures.register(&func_type);
// (index, compiled_function)
// }).filter(|(index, _)| {
// !self.function_call_trampolines.contains_key(index)
// }).unzip();
for (sig_index, compiled_function) in function_call_trampolines.iter() {
let func_type = module.signatures.get(sig_index).unwrap();
let index = self.signatures.register(&func_type);
if self.function_call_trampolines.contains_key(&index) {
// We don't need to allocate the trampoline in case
// it's signature is already allocated.
continue;
}
// if self.function_call_trampolines.contains_key(&index) {
// // We don't need to allocate the trampoline in case
// // it's signature is already allocated.
// continue;
// }
let ptr = self
.code_memory
.allocate_for_function(&compiled_function)
.allocate_for_function(registry, &compiled_function)
.map_err(|message| {
CompileError::Resource(format!(
"failed to allocate memory for function call trampolines: {}",
message
))
})?
.as_ptr();
})?;
alllocated_function_call_trampolines.push(ptr);
let trampoline =
unsafe { std::mem::transmute::<*const VMFunctionBody, VMTrampoline>(ptr) };
unsafe { std::mem::transmute::<*const VMFunctionBody, VMTrampoline>(ptr.as_ptr()) };
self.function_call_trampolines.insert(index, trampoline);
}
@@ -240,19 +263,22 @@ impl JITEngineInner {
.map(|compiled_function| {
let ptr = self
.code_memory
.allocate_for_function(&compiled_function)
.allocate_for_function(registry, &compiled_function)
.map_err(|message| {
CompileError::Resource(format!(
"failed to allocate memory for dynamic function trampolines: {}",
message
))
})?
.as_ptr();
Ok(ptr)
})?;
Ok(ptr as _)
})
.collect::<Result<PrimaryMap<FunctionIndex, _>, CompileError>>()?;
Ok((allocated_functions, allocated_dynamic_function_trampolines))
Ok((
allocated_functions,
alllocated_function_call_trampolines,
allocated_dynamic_function_trampolines,
))
}
/// Make memory containing compiled code executable.
@@ -260,6 +286,11 @@ impl JITEngineInner {
self.code_memory.publish();
}
/// Publish the unwind registry into code memory.
pub(crate) fn publish_unwind_registry(&mut self, unwind_registry: Arc<UnwindRegistry>) {
self.code_memory.publish_unwind_registry(unwind_registry);
}
/// Shared signature registry.
pub fn signatures(&self) -> &SignatureRegistry {
&self.signatures

View File

@@ -1,233 +0,0 @@
//! Runtime function table.
//!
//! This module is primarily used to track JIT functions on Windows for stack walking and unwind.
use wasmer_compiler::FunctionTableReloc;
/// Represents a runtime function table.
///
/// This is used to register JIT code with the operating system to enable stack walking and unwinding.
#[cfg(all(target_os = "windows", target_arch = "x86_64"))]
pub struct FunctionTable {
functions: Vec<winapi::um::winnt::RUNTIME_FUNCTION>,
published: bool,
}
#[cfg(all(target_os = "windows", target_arch = "x86_64"))]
impl FunctionTable {
/// Creates a new function table.
pub fn new() -> Self {
Self {
functions: Vec::new(),
published: false,
}
}
/// Returns the number of functions in the table, also referred to as its 'length'.
pub fn len(&self) -> usize {
self.functions.len()
}
/// Returns whether or not the function table is empty.
pub fn is_empty(&self) -> bool {
self.len() == 0
}
/// Adds a function to the table based off of the start offset, end offset, and unwind offset.
///
/// The offsets are from the "module base", which is provided when the table is published.
pub fn add_function(
&mut self,
start: u32,
end: u32,
unwind: u32,
_relocs: &[FunctionTableReloc],
) {
assert_eq!(_relocs.len(), 0);
use winapi::um::winnt;
assert!(!self.published, "table has already been published");
let mut entry = winnt::RUNTIME_FUNCTION::default();
entry.BeginAddress = start;
entry.EndAddress = end;
unsafe {
*entry.u.UnwindInfoAddress_mut() = unwind;
}
self.functions.push(entry);
}
/// Publishes the function table using the given base address.
///
/// A published function table will automatically be deleted when it is dropped.
pub fn publish(&mut self, base_address: u64) -> Result<(), String> {
use winapi::um::winnt;
if self.published {
return Err("function table was already published".into());
}
self.published = true;
if self.functions.is_empty() {
return Ok(());
}
unsafe {
// Windows heap allocations are 32-bit aligned, but assert just in case
assert_eq!(
(self.functions.as_mut_ptr() as u64) % 4,
0,
"function table allocation was not aligned"
);
if winnt::RtlAddFunctionTable(
self.functions.as_mut_ptr(),
self.functions.len() as u32,
base_address,
) == 0
{
return Err("failed to add function table".into());
}
}
Ok(())
}
}
#[cfg(target_os = "windows")]
impl Drop for FunctionTable {
fn drop(&mut self) {
use winapi::um::winnt;
if self.published {
unsafe {
winnt::RtlDeleteFunctionTable(self.functions.as_mut_ptr());
}
}
}
}
/// Represents a runtime function table.
///
/// This is used to register JIT code with the operating system to enable stack walking and unwinding.
#[cfg(unix)]
pub struct FunctionTable {
functions: Vec<u32>,
relocs: Vec<FunctionTableReloc>,
published: Option<Vec<usize>>,
}
#[cfg(unix)]
impl FunctionTable {
/// Creates a new function table.
pub fn new() -> Self {
Self {
functions: Vec::new(),
relocs: Vec::new(),
published: None,
}
}
/// Returns the number of functions in the table, also referred to as its 'length'.
pub fn len(&self) -> usize {
self.functions.len()
}
/// Returns whether or not the function table is empty.
pub fn is_empty(&self) -> bool {
self.len() == 0
}
/// Adds a function to the table based off of the start offset, end offset, and unwind offset.
///
/// The offsets are from the "module base", which is provided when the table is published.
pub fn add_function(
&mut self,
_start: u32,
_end: u32,
unwind: u32,
relocs: &[FunctionTableReloc],
) {
assert!(self.published.is_none(), "table has already been published");
self.functions.push(unwind);
self.relocs.extend_from_slice(relocs);
}
/// Publishes the function table using the given base address.
///
/// A published function table will automatically be deleted when it is dropped.
pub fn publish(&mut self, base_address: u64) -> Result<(), String> {
if self.published.is_some() {
return Err("function table was already published".into());
}
if self.functions.is_empty() {
assert_eq!(self.relocs.len(), 0);
self.published = Some(vec![]);
return Ok(());
}
extern "C" {
// libunwind import
fn __register_frame(fde: *const u8);
}
for reloc in self.relocs.iter() {
let addr = base_address + (reloc.offset as u64);
let target = base_address + (reloc.addend as u64);
unsafe {
std::ptr::write(addr as *mut u64, target);
}
}
let mut fdes = Vec::with_capacity(self.functions.len());
for unwind_offset in self.functions.iter() {
let addr = base_address + (*unwind_offset as u64);
let off = unsafe { std::ptr::read::<u32>(addr as *const u32) } as usize + 4;
let fde = (addr + off as u64) as usize;
unsafe {
__register_frame(fde as *const _);
}
fdes.push(fde);
}
self.published = Some(fdes);
Ok(())
}
}
#[cfg(unix)]
impl Drop for FunctionTable {
fn drop(&mut self) {
extern "C" {
// libunwind import
fn __deregister_frame(fde: *const u8);
}
if let Some(published) = &self.published {
unsafe {
// I'm not really sure why, but it appears to be way faster to
// unregister frames in reverse order rather than in-order. This
// way we're deregistering in LIFO order, and maybe there's some
// vec shifting or something like that in libgcc?
//
// Locally on Ubuntu 18.04 a wasm module with 40k empty
// functions takes 0.1s to compile and drop with reverse
// iteration. With forward iteration it takes 3s to compile and
// drop!
//
// Poking around libgcc sources seems to indicate that some sort
// of linked list is being traversed... We may need to figure
// out something else for backtraces in the future since this
// API may not be long-lived to keep calling.
for fde in published.iter().rev() {
__deregister_frame(*fde as *const _);
}
}
}
}
}

View File

@@ -28,14 +28,13 @@
mod artifact;
mod code_memory;
mod engine;
mod function_table;
mod link;
mod serialize;
mod unwind;
pub use crate::artifact::JITArtifact;
pub use crate::code_memory::CodeMemory;
pub use crate::engine::JITEngine;
pub use crate::function_table::FunctionTable;
pub use crate::link::link_module;
/// Version number of this crate.

View File

@@ -5,11 +5,23 @@ use wasm_common::{
Features, FunctionIndex, LocalFunctionIndex, MemoryIndex, OwnedDataInitializer, SignatureIndex,
TableIndex,
};
use wasmer_compiler::{CustomSection, FunctionBody, JumpTableOffsets, Relocation, SectionIndex};
use wasmer_compiler::{
CustomSection, Dwarf, FunctionBody, JumpTableOffsets, Relocation, SectionIndex,
};
use wasmer_engine::SerializableFunctionFrameInfo;
use wasmer_runtime::ModuleInfo;
use wasmer_runtime::{MemoryPlan, TablePlan};
// /// The serializable function data
// #[derive(Serialize, Deserialize)]
// pub struct SerializableFunction {
// #[serde(with = "serde_bytes")]
// pub body: &[u8],
// /// The unwind info for Windows
// #[serde(with = "serde_bytes")]
// pub windows_unwind_info: &[u8],
// }
/// The compilation related data for a serialized modules
#[derive(Serialize, Deserialize)]
pub struct SerializableCompilation {
@@ -24,6 +36,8 @@ pub struct SerializableCompilation {
pub dynamic_function_trampolines: PrimaryMap<FunctionIndex, FunctionBody>,
pub custom_sections: PrimaryMap<SectionIndex, CustomSection>,
pub custom_section_relocations: PrimaryMap<SectionIndex, Vec<Relocation>>,
// The section indices corresponding to the Dwarf debug info
pub debug: Option<Dwarf>,
}
/// Serializable struct that is able to serialize from and to

View File

@@ -0,0 +1,32 @@
//! Module for Dummy unwind registry.
use wasmer_compiler::CompiledFunctionUnwindInfo;
/// Represents a registry of function unwind information when the host system
/// support any one in specific.
pub struct DummyUnwindRegistry {}
impl DummyUnwindRegistry {
/// Creates a new unwind registry with the given base address.
pub fn new() -> Self {
DummyUnwindRegistry {}
}
/// Registers a function given the start offset, length, and unwind information.
pub fn register(
&mut self,
_base_address: usize,
_func_start: u32,
_func_len: u32,
_info: &CompiledFunctionUnwindInfo,
) -> Result<(), String> {
// Do nothing
Ok(())
}
/// Publishes all registered functions.
pub fn publish(&mut self, eh_frame: Option<&[u8]>) -> Result<(), String> {
// Do nothing
Ok(())
}
}

View File

@@ -0,0 +1,13 @@
cfg_if::cfg_if! {
if #[cfg(all(windows, target_arch = "x86_64"))] {
mod windows_x64;
pub use self::windows_x64::*;
} else if #[cfg(unix)] {
mod systemv;
pub use self::systemv::*;
} else {
// Otherwise, we provide a dummy fallback without unwinding
mod dummy;
pub use self::dummy::DummyUnwindRegistry as UnwindRegistry;
}
}

Some files were not shown because too many files have changed in this diff Show More