mirror of
https://github.com/mii443/wasmer.git
synced 2025-12-16 17:18:57 +00:00
Merge remote-tracking branch 'origin/master' into middleware
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -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
135
Cargo.lock
generated
@@ -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"
|
||||
|
||||
19
Cargo.toml
19
Cargo.toml
@@ -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"
|
||||
|
||||
16
Makefile
16
Makefile
@@ -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
|
||||
|
||||
|
||||
44
lib/api/src/externals/function.rs
vendored
44
lib/api/src/externals/function.rs
vendored
@@ -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,
|
||||
) {
|
||||
|
||||
4
lib/api/src/externals/table.rs
vendored
4
lib/api/src/externals/table.rs
vendored
@@ -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`.
|
||||
|
||||
@@ -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};
|
||||
|
||||
@@ -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(¶ms_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(¶ms_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);
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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(())
|
||||
|
||||
@@ -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"]
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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()),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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"),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
36
lib/cache/src/filesystem.rs
vendored
36
lib/cache/src/filesystem.rs
vendored
@@ -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(())
|
||||
|
||||
@@ -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"]
|
||||
|
||||
@@ -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).
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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>;
|
||||
@@ -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};
|
||||
|
||||
102
lib/compiler-cranelift/src/dwarf.rs
Normal file
102
lib/compiler-cranelift/src/dwarf.rs
Normal 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");
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)),
|
||||
};
|
||||
|
||||
|
||||
@@ -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};
|
||||
|
||||
@@ -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 => {
|
||||
|
||||
@@ -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),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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).
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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>>();
|
||||
|
||||
@@ -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()?;
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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?
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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 }
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"))]
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)),
|
||||
},
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
28
lib/emscripten/src/env/mod.rs
vendored
28
lib/emscripten/src/env/mod.rs
vendored
@@ -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,
|
||||
|
||||
20
lib/emscripten/src/env/unix/mod.rs
vendored
20
lib/emscripten/src/env/unix/mod.rs
vendored
@@ -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>,
|
||||
|
||||
20
lib/emscripten/src/env/windows/mod.rs
vendored
20
lib/emscripten/src/env/windows/mod.rs
vendored
@@ -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>,
|
||||
|
||||
@@ -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!");
|
||||
|
||||
@@ -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!");
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"] }
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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(§ion.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(§ion.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
|
||||
|
||||
@@ -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 _);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
32
lib/engine-jit/src/unwind/dummy.rs
Normal file
32
lib/engine-jit/src/unwind/dummy.rs
Normal 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(())
|
||||
}
|
||||
}
|
||||
13
lib/engine-jit/src/unwind/mod.rs
Normal file
13
lib/engine-jit/src/unwind/mod.rs
Normal 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
Reference in New Issue
Block a user