mirror of
https://github.com/mii443/wasmer.git
synced 2025-08-22 16:35:33 +00:00
Remove engine-dylib
This commit is contained in:
42
Cargo.lock
generated
42
Cargo.lock
generated
@ -160,7 +160,7 @@ dependencies = [
|
||||
"regex",
|
||||
"rustc-hash",
|
||||
"shlex",
|
||||
"which 3.1.1",
|
||||
"which",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2796,7 +2796,6 @@ dependencies = [
|
||||
"wasmer-compiler-singlepass",
|
||||
"wasmer-derive",
|
||||
"wasmer-engine",
|
||||
"wasmer-engine-dylib",
|
||||
"wasmer-engine-universal",
|
||||
"wasmer-types",
|
||||
"wasmer-vm",
|
||||
@ -2826,7 +2825,6 @@ dependencies = [
|
||||
"wasmer-compiler-cranelift",
|
||||
"wasmer-compiler-llvm",
|
||||
"wasmer-compiler-singlepass",
|
||||
"wasmer-engine-dylib",
|
||||
"wasmer-engine-universal",
|
||||
"wasmer-middlewares",
|
||||
"wasmprinter",
|
||||
@ -2853,7 +2851,6 @@ dependencies = [
|
||||
"wasmer-compiler-singlepass",
|
||||
"wasmer-emscripten",
|
||||
"wasmer-engine",
|
||||
"wasmer-engine-dylib",
|
||||
"wasmer-engine-staticlib",
|
||||
"wasmer-engine-universal",
|
||||
"wasmer-middlewares",
|
||||
@ -2873,7 +2870,6 @@ dependencies = [
|
||||
"thiserror",
|
||||
"wasmer",
|
||||
"wasmer-compiler-singlepass",
|
||||
"wasmer-engine-dylib",
|
||||
"wasmer-engine-universal",
|
||||
]
|
||||
|
||||
@ -2900,7 +2896,6 @@ dependencies = [
|
||||
"wasmer-compiler-singlepass",
|
||||
"wasmer-emscripten",
|
||||
"wasmer-engine",
|
||||
"wasmer-engine-dylib",
|
||||
"wasmer-engine-staticlib",
|
||||
"wasmer-engine-universal",
|
||||
"wasmer-types",
|
||||
@ -3068,29 +3063,6 @@ dependencies = [
|
||||
"wasmer-vm",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasmer-engine-dylib"
|
||||
version = "2.3.0"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"enum-iterator",
|
||||
"enumset",
|
||||
"leb128",
|
||||
"libloading",
|
||||
"object",
|
||||
"rkyv",
|
||||
"serde",
|
||||
"tempfile",
|
||||
"tracing",
|
||||
"wasmer-artifact",
|
||||
"wasmer-compiler",
|
||||
"wasmer-engine",
|
||||
"wasmer-object",
|
||||
"wasmer-types",
|
||||
"wasmer-vm",
|
||||
"which 4.2.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasmer-engine-staticlib"
|
||||
version = "2.3.0"
|
||||
@ -3352,7 +3324,6 @@ dependencies = [
|
||||
"wasmer-emscripten",
|
||||
"wasmer-engine",
|
||||
"wasmer-engine-dummy",
|
||||
"wasmer-engine-dylib",
|
||||
"wasmer-engine-staticlib",
|
||||
"wasmer-engine-universal",
|
||||
"wasmer-middlewares",
|
||||
@ -3514,17 +3485,6 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "which"
|
||||
version = "4.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c4fb54e6113b6a8772ee41c3404fb0301ac79604489467e0a9ce1f3e97c24ae"
|
||||
dependencies = [
|
||||
"either",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
|
17
Cargo.toml
17
Cargo.toml
@ -18,7 +18,6 @@ wasmer-compiler-llvm = { version = "=2.3.0", path = "lib/compiler-llvm", optiona
|
||||
wasmer-emscripten = { version = "=2.3.0", path = "lib/emscripten", optional = true }
|
||||
wasmer-engine = { version = "=2.3.0", path = "lib/engine" }
|
||||
wasmer-engine-universal = { version = "=2.3.0", path = "lib/engine-universal", optional = true }
|
||||
wasmer-engine-dylib = { version = "=2.3.0", path = "lib/engine-dylib", optional = true }
|
||||
wasmer-engine-staticlib = { version = "=2.3.0", path = "lib/engine-staticlib", optional = true }
|
||||
wasmer-wasi = { version = "=2.3.0", path = "lib/wasi", optional = true }
|
||||
wasmer-wast = { version = "=2.3.0", path = "tests/lib/wast", optional = true }
|
||||
@ -43,7 +42,6 @@ members = [
|
||||
"lib/emscripten",
|
||||
"lib/engine",
|
||||
"lib/engine-universal",
|
||||
"lib/engine-dylib",
|
||||
"lib/engine-staticlib",
|
||||
"lib/object",
|
||||
"lib/vfs",
|
||||
@ -91,7 +89,6 @@ default = [
|
||||
"wat",
|
||||
"wast",
|
||||
"universal",
|
||||
"dylib",
|
||||
"staticlib",
|
||||
"cache",
|
||||
"wasi",
|
||||
@ -103,10 +100,6 @@ universal = [
|
||||
"wasmer-engine-universal",
|
||||
"engine",
|
||||
]
|
||||
dylib = [
|
||||
"wasmer-engine-dylib",
|
||||
"engine",
|
||||
]
|
||||
staticlib = [
|
||||
"wasmer-engine-staticlib",
|
||||
"engine",
|
||||
@ -120,7 +113,6 @@ compiler = [
|
||||
"wasmer/compiler",
|
||||
"wasmer-compiler/translator",
|
||||
"wasmer-engine-universal/compiler",
|
||||
"wasmer-engine-dylib/compiler",
|
||||
"wasmer-engine-staticlib/compiler",
|
||||
]
|
||||
singlepass = [
|
||||
@ -148,10 +140,6 @@ test-llvm = [
|
||||
"llvm",
|
||||
]
|
||||
|
||||
test-dylib = [
|
||||
"dylib",
|
||||
"test-generator/test-dylib",
|
||||
]
|
||||
test-universal = [
|
||||
"universal",
|
||||
"test-generator/test-universal",
|
||||
@ -178,11 +166,6 @@ name = "engine-universal"
|
||||
path = "examples/engine_universal.rs"
|
||||
required-features = ["cranelift"]
|
||||
|
||||
[[example]]
|
||||
name = "engine-dylib"
|
||||
path = "examples/engine_dylib.rs"
|
||||
required-features = ["cranelift"]
|
||||
|
||||
[[example]]
|
||||
name = "engine-headless"
|
||||
path = "examples/engine_headless.rs"
|
||||
|
72
Makefile
72
Makefile
@ -13,29 +13,20 @@ SHELL=/usr/bin/env bash
|
||||
# | Compiler ⨯ Engine ⨯ Platform ⨯ Architecture ⨯ libc |
|
||||
# |------------|-----------|----------|--------------|-------|
|
||||
# | Cranelift | Universal | Linux | amd64 | glibc |
|
||||
# | LLVM | Dylib | Darwin | aarch64 | musl |
|
||||
# | Singlepass | Staticlib | Windows | | |
|
||||
# | LLVM | Staticlib | Darwin | aarch64 | musl |
|
||||
# | Singlepass | | Windows | | |
|
||||
# |------------|-----------|----------|--------------|-------|
|
||||
#
|
||||
# Here is what works and what doesn't:
|
||||
#
|
||||
# * Cranelift with the Universal engine works everywhere,
|
||||
#
|
||||
# * Cranelift with the Dylib engine works on Linux+Darwin/`amd64`, but
|
||||
# it doesn't work on */`aarch64` or Windows/*.
|
||||
#
|
||||
# * LLVM with the Universal engine works on Linux+Darwin/`amd64`,
|
||||
# but it doesn't work on */`aarch64` or Windows/*.
|
||||
#
|
||||
# * LLVM with the Dylib engine works on
|
||||
# Linux+Darwin/`amd64`+`aarch64`, but it doesn't work on Windows/*.
|
||||
#
|
||||
# * Singlepass with the Universal engine works on Linux+Darwin/`amd64`, but
|
||||
# it doesn't work on */`aarch64` or Windows/*.
|
||||
#
|
||||
# * Singlepass with the Dylib engine doesn't work because it doesn't
|
||||
# know how to output object files for the moment.
|
||||
#
|
||||
# * Windows isn't tested on `aarch64`, that's why we consider it's not
|
||||
# working, but it might possibly be.
|
||||
|
||||
@ -217,18 +208,6 @@ compilers_engines :=
|
||||
|
||||
ifeq ($(ENABLE_CRANELIFT), 1)
|
||||
compilers_engines += cranelift-universal
|
||||
|
||||
ifneq (, $(filter 1, $(IS_WINDOWS) $(IS_DARWIN) $(IS_LINUX)))
|
||||
ifeq ($(IS_AMD64), 1)
|
||||
ifneq ($(LIBC), musl)
|
||||
compilers_engines += cranelift-dylib
|
||||
endif
|
||||
else ifeq ($(IS_AARCH64), 1)
|
||||
ifneq ($(LIBC), musl)
|
||||
compilers_engines += cranelift-dylib
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
##
|
||||
@ -239,10 +218,8 @@ ifeq ($(ENABLE_LLVM), 1)
|
||||
ifneq (, $(filter 1, $(IS_WINDOWS) $(IS_DARWIN) $(IS_LINUX)))
|
||||
ifeq ($(IS_AMD64), 1)
|
||||
compilers_engines += llvm-universal
|
||||
compilers_engines += llvm-dylib
|
||||
else ifeq ($(IS_AARCH64), 1)
|
||||
compilers_engines += llvm-universal
|
||||
compilers_engines += llvm-dylib
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
@ -284,7 +261,7 @@ capi_compilers_engines_exclude :=
|
||||
# LLVM for the moment because it causes the linker to fail since LLVM is not statically linked.
|
||||
# TODO: Reenable LLVM in C-API
|
||||
capi_compiler_features := --features $(subst $(space),$(comma),$(filter-out llvm, $(compilers)))
|
||||
capi_compilers_engines_exclude += llvm-universal llvm-dylib
|
||||
capi_compilers_engines_exclude += llvm-universal
|
||||
|
||||
# We exclude singlepass-universal because it doesn't support multivalue (required in wasm-c-api tests)
|
||||
capi_compilers_engines_exclude += singlepass-universal
|
||||
@ -444,57 +421,45 @@ build-docs-capi: capi-setup
|
||||
# when generating the documentation, we rename it to its
|
||||
# crate's name. Then we restore the lib's name.
|
||||
sed "$(SEDI)" -e 's/name = "wasmer" # ##lib.name##/name = "wasmer_c_api" # ##lib.name##/' lib/c-api/Cargo.toml
|
||||
RUSTFLAGS="${RUSTFLAGS}" $(CARGO_BINARY) doc $(CARGO_TARGET) --manifest-path lib/c-api/Cargo.toml --no-deps --features wat,universal,staticlib,dylib,cranelift,wasi
|
||||
RUSTFLAGS="${RUSTFLAGS}" $(CARGO_BINARY) doc $(CARGO_TARGET) --manifest-path lib/c-api/Cargo.toml --no-deps --features wat,universal,staticlib,cranelift,wasi
|
||||
sed "$(SEDI)" -e 's/name = "wasmer_c_api" # ##lib.name##/name = "wasmer" # ##lib.name##/' lib/c-api/Cargo.toml
|
||||
|
||||
build-capi: capi-setup
|
||||
RUSTFLAGS="${RUSTFLAGS}" $(CARGO_BINARY) build $(CARGO_TARGET) --manifest-path lib/c-api/Cargo.toml --release \
|
||||
--no-default-features --features wat,universal,dylib,staticlib,wasi,middlewares $(capi_compiler_features)
|
||||
--no-default-features --features wat,universal,staticlib,wasi,middlewares $(capi_compiler_features)
|
||||
|
||||
build-capi-singlepass: capi-setup
|
||||
RUSTFLAGS="${RUSTFLAGS}" $(CARGO_BINARY) build $(CARGO_TARGET) --manifest-path lib/c-api/Cargo.toml --release \
|
||||
--no-default-features --features wat,universal,dylib,staticlib,singlepass,wasi,middlewares
|
||||
--no-default-features --features wat,universal,staticlib,singlepass,wasi,middlewares
|
||||
|
||||
build-capi-singlepass-universal: capi-setup
|
||||
RUSTFLAGS="${RUSTFLAGS}" $(CARGO_BINARY) build $(CARGO_TARGET) --manifest-path lib/c-api/Cargo.toml --release \
|
||||
--no-default-features --features wat,universal,singlepass,wasi,middlewares
|
||||
|
||||
build-capi-singlepass-dylib: capi-setup
|
||||
RUSTFLAGS="${RUSTFLAGS}" $(CARGO_BINARY) build $(CARGO_TARGET) --manifest-path lib/c-api/Cargo.toml --release \
|
||||
--no-default-features --features wat,dylib,singlepass,wasi,middlewares
|
||||
|
||||
build-capi-singlepass-staticlib: capi-setup
|
||||
RUSTFLAGS="${RUSTFLAGS}" $(CARGO_BINARY) build $(CARGO_TARGET) --manifest-path lib/c-api/Cargo.toml --release \
|
||||
--no-default-features --features wat,staticlib,singlepass,wasi,middlewares
|
||||
|
||||
build-capi-cranelift: capi-setup
|
||||
RUSTFLAGS="${RUSTFLAGS}" $(CARGO_BINARY) build $(CARGO_TARGET) --manifest-path lib/c-api/Cargo.toml --release \
|
||||
--no-default-features --features wat,universal,dylib,staticlib,cranelift,wasi,middlewares
|
||||
--no-default-features --features wat,universal,staticlib,cranelift,wasi,middlewares
|
||||
|
||||
build-capi-cranelift-universal: capi-setup
|
||||
RUSTFLAGS="${RUSTFLAGS}" $(CARGO_BINARY) build $(CARGO_TARGET) --manifest-path lib/c-api/Cargo.toml --release \
|
||||
--no-default-features --features wat,universal,cranelift,wasi,middlewares
|
||||
|
||||
build-capi-cranelift-dylib: capi-setup
|
||||
RUSTFLAGS="${RUSTFLAGS}" $(CARGO_BINARY) build $(CARGO_TARGET) --manifest-path lib/c-api/Cargo.toml --release \
|
||||
--no-default-features --features wat,dylib,cranelift,wasi,middlewares
|
||||
|
||||
build-capi-cranelift-staticlib: capi-setup
|
||||
RUSTFLAGS="${RUSTFLAGS}" $(CARGO_BINARY) build $(CARGO_TARGET) --manifest-path lib/c-api/Cargo.toml --release \
|
||||
--no-default-features --features wat,dylib,staticlib,cranelift,wasi,middlewares
|
||||
--no-default-features --features wat,staticlib,cranelift,wasi,middlewares
|
||||
|
||||
build-capi-llvm: capi-setup
|
||||
RUSTFLAGS="${RUSTFLAGS}" $(CARGO_BINARY) build $(CARGO_TARGET) --manifest-path lib/c-api/Cargo.toml --release \
|
||||
--no-default-features --features wat,universal,dylib,staticlib,llvm,wasi,middlewares
|
||||
--no-default-features --features wat,universal,staticlib,llvm,wasi,middlewares
|
||||
|
||||
build-capi-llvm-universal: capi-setup
|
||||
RUSTFLAGS="${RUSTFLAGS}" $(CARGO_BINARY) build $(CARGO_TARGET) --manifest-path lib/c-api/Cargo.toml --release \
|
||||
--no-default-features --features wat,universal,llvm,wasi,middlewares
|
||||
|
||||
build-capi-llvm-dylib: capi-setup
|
||||
RUSTFLAGS="${RUSTFLAGS}" $(CARGO_BINARY) build $(CARGO_TARGET) --manifest-path lib/c-api/Cargo.toml --release \
|
||||
--no-default-features --features wat,dylib,llvm,wasi,middlewares
|
||||
|
||||
build-capi-llvm-staticlib: capi-setup
|
||||
RUSTFLAGS="${RUSTFLAGS}" $(CARGO_BINARY) build $(CARGO_TARGET) --manifest-path lib/c-api/Cargo.toml --release \
|
||||
--no-default-features --features wat,staticlib,llvm,wasi,middlewares
|
||||
@ -505,21 +470,17 @@ build-capi-headless-universal: capi-setup
|
||||
RUSTFLAGS="${RUSTFLAGS}" $(CARGO_BINARY) build $(CARGO_TARGET) --manifest-path lib/c-api/Cargo.toml --release \
|
||||
--no-default-features --features universal,wasi
|
||||
|
||||
build-capi-headless-dylib: capi-setup
|
||||
RUSTFLAGS="${RUSTFLAGS}" $(CARGO_BINARY) build $(CARGO_TARGET) --manifest-path lib/c-api/Cargo.toml --release \
|
||||
--no-default-features --features dylib,wasi
|
||||
|
||||
build-capi-headless-staticlib: capi-setup
|
||||
RUSTFLAGS="${RUSTFLAGS}" $(CARGO_BINARY) build $(CARGO_TARGET) --manifest-path lib/c-api/Cargo.toml --release \
|
||||
--no-default-features --features staticlib,wasi
|
||||
|
||||
build-capi-headless-all: capi-setup
|
||||
RUSTFLAGS="${RUSTFLAGS}" $(CARGO_BINARY) build $(CARGO_TARGET) --manifest-path lib/c-api/Cargo.toml --release \
|
||||
--no-default-features --features universal,dylib,staticlib,wasi
|
||||
--no-default-features --features universal,staticlib,wasi
|
||||
|
||||
build-capi-headless-ios: capi-setup
|
||||
RUSTFLAGS="${RUSTFLAGS}" cargo lipo --manifest-path lib/c-api/Cargo.toml --release \
|
||||
--no-default-features --features dylib,wasi
|
||||
--no-default-features --features wasi
|
||||
|
||||
#####
|
||||
#
|
||||
@ -554,21 +515,12 @@ test-js-wasi:
|
||||
|
||||
test-compilers-compat: $(foreach compiler,$(compilers),test-$(compiler))
|
||||
|
||||
test-singlepass-dylib:
|
||||
$(CARGO_BINARY) test $(CARGO_TARGET) --release --tests $(compiler_features) -- singlepass::dylib
|
||||
|
||||
test-singlepass-universal:
|
||||
$(CARGO_BINARY) test $(CARGO_TARGET) --release --tests $(compiler_features) -- singlepass::universal
|
||||
|
||||
test-cranelift-dylib:
|
||||
$(CARGO_BINARY) test $(CARGO_TARGET) --release --tests $(compiler_features) -- cranelift::dylib
|
||||
|
||||
test-cranelift-universal:
|
||||
$(CARGO_BINARY) test $(CARGO_TARGET) --release --tests $(compiler_features) -- cranelift::universal
|
||||
|
||||
test-llvm-dylib:
|
||||
$(CARGO_BINARY) test $(CARGO_TARGET) --release --tests $(compiler_features) -- llvm::dylib
|
||||
|
||||
test-llvm-universal:
|
||||
$(CARGO_BINARY) test $(CARGO_TARGET) --release --tests $(compiler_features) -- llvm::universal
|
||||
|
||||
@ -584,7 +536,7 @@ test-capi: build-capi package-capi $(foreach compiler_engine,$(capi_compilers_en
|
||||
|
||||
test-capi-crate-%:
|
||||
WASMER_CAPI_CONFIG=$(shell echo $@ | sed -e s/test-capi-crate-//) $(CARGO_BINARY) test $(CARGO_TARGET) --manifest-path lib/c-api/Cargo.toml --release \
|
||||
--no-default-features --features wat,universal,dylib,staticlib,wasi,middlewares $(capi_compiler_features) -- --nocapture
|
||||
--no-default-features --features wat,universal,staticlib,wasi,middlewares $(capi_compiler_features) -- --nocapture
|
||||
|
||||
test-capi-integration-%:
|
||||
# Test the Wasmer C API tests for C
|
||||
|
@ -5,7 +5,6 @@ digraph dependencies {
|
||||
n1 [label="wasmer-compiler", color=orange];
|
||||
n5 [label="wasmer-engine", color=orange];
|
||||
n6 [label="wasmer-engine-universal", color=orange];
|
||||
n7 [label="wasmer-engine-dylib", color=orange];
|
||||
n8 [label="wasmer-types", color=orange];
|
||||
n9 [label="wasmer-vm", color=orange];
|
||||
n10 [label="wasmer-c-api", color=orange];
|
||||
@ -29,7 +28,6 @@ digraph dependencies {
|
||||
color=brown;
|
||||
|
||||
n6 [label="wasmer-engine-universal", color=orange];
|
||||
n7 [label="wasmer-engine-dylib", color=orange];
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -42,18 +42,6 @@
|
||||
<path fill="none" stroke="orange" stroke-dasharray="5,2" d="M488.06,-373.25C467.43,-368.88 440.95,-362.59 418,-355 394.49,-347.23 369.06,-336.52 348.38,-327.2"/>
|
||||
<polygon fill="orange" stroke="orange" points="349.79,-323.99 339.24,-323.02 346.88,-330.36 349.79,-323.99"/>
|
||||
</g>
|
||||
<!-- n7 -->
|
||||
<g id="node5" class="node">
|
||||
<title>n7</title>
|
||||
<ellipse fill="none" stroke="orange" cx="102" cy="-306" rx="85.59" ry="18"/>
|
||||
<text text-anchor="middle" x="102" y="-302.3" font-family="Times,serif" font-size="14.00">wasmer-engine-dylib</text>
|
||||
</g>
|
||||
<!-- n0->n7 -->
|
||||
<g id="edge13" class="edge">
|
||||
<title>n0->n7</title>
|
||||
<path fill="none" stroke="orange" stroke-dasharray="5,2" d="M484.8,-378.93C410.73,-376.56 250.17,-369.84 197,-355 175.78,-349.08 153.72,-338.26 136.21,-328.39"/>
|
||||
<polygon fill="orange" stroke="orange" points="137.9,-325.33 127.49,-323.35 134.39,-331.39 137.9,-325.33"/>
|
||||
</g>
|
||||
<!-- n2 -->
|
||||
<g id="node13" class="node">
|
||||
<title>n2</title>
|
||||
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 11 KiB |
@ -236,24 +236,7 @@ example.
|
||||
|
||||
</details>
|
||||
|
||||
2. [**Dylib engine**][engine-dylib], explains what a Dylib engine
|
||||
is, and how to set it up. The example completes itself with the
|
||||
compilation of the Wasm module, its instantiation, and finally, by
|
||||
calling an exported function.
|
||||
|
||||
_Keywords_: native, engine, shared library, dynamic library,
|
||||
executable code.
|
||||
|
||||
<details>
|
||||
<summary><em>Execute the example</em></summary>
|
||||
|
||||
```shell
|
||||
$ cargo run --example engine-dylib --release --features "cranelift"
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
3. [**Headless engines**][engine-headless], explains what a headless
|
||||
2. [**Headless engines**][engine-headless], explains what a headless
|
||||
engine is, what problem it does solve, and what are the benefits of
|
||||
it. The example completes itself with the instantiation of a
|
||||
pre-compiled Wasm module, and finally, by calling an exported
|
||||
@ -376,7 +359,6 @@ example.
|
||||
|
||||
[hello-world]: ./hello_world.rs
|
||||
[engine-universal]: ./engine_universal.rs
|
||||
[engine-dylib]: ./engine_dylib.rs
|
||||
[engine-headless]: ./engine_headless.rs
|
||||
[compiler-singlepass]: ./compiler_singlepass.rs
|
||||
[compiler-cranelift]: ./compiler_cranelift.rs
|
||||
|
@ -22,7 +22,7 @@ use std::str::FromStr;
|
||||
use wasmer::{wat2wasm, Module, RuntimeError, Store};
|
||||
use wasmer_compiler::{CpuFeature, Target, Triple};
|
||||
use wasmer_compiler_cranelift::Cranelift;
|
||||
use wasmer_engine_dylib::Dylib;
|
||||
use wasmer_engine_universal::Universal;
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
// Let's declare the Wasm module with the text representation.
|
||||
@ -67,13 +67,10 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
|
||||
// Define the engine that will drive everything.
|
||||
//
|
||||
// In this case, the engine is `wasmer_engine_dylib` which means
|
||||
// that a shared object is going to be generated.
|
||||
//
|
||||
// That's where we specify the target for the compiler.
|
||||
//
|
||||
// Use the Dylib engine.
|
||||
let engine = Dylib::new(compiler_config)
|
||||
// Use the Universal engine.
|
||||
let engine = Universal::new(compiler_config)
|
||||
// Here we go.
|
||||
// Pass the target to the engine! The engine will share
|
||||
// this information with the compiler.
|
||||
|
@ -20,67 +20,71 @@
|
||||
|
||||
use wasmer::{imports, wat2wasm, Instance, Module, Store, Value};
|
||||
use wasmer_compiler_cranelift::Cranelift;
|
||||
/*
|
||||
use wasmer_engine_dylib::Dylib;
|
||||
*/
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
// Let's declare the Wasm module with the text representation.
|
||||
let wasm_bytes = wat2wasm(
|
||||
r#"
|
||||
(module
|
||||
(type $sum_t (func (param i32 i32) (result i32)))
|
||||
(func $sum_f (type $sum_t) (param $x i32) (param $y i32) (result i32)
|
||||
local.get $x
|
||||
local.get $y
|
||||
i32.add)
|
||||
(export "sum" (func $sum_f)))
|
||||
"#
|
||||
.as_bytes(),
|
||||
)?;
|
||||
/*
|
||||
// Let's declare the Wasm module with the text representation.
|
||||
let wasm_bytes = wat2wasm(
|
||||
r#"
|
||||
(module
|
||||
(type $sum_t (func (param i32 i32) (result i32)))
|
||||
(func $sum_f (type $sum_t) (param $x i32) (param $y i32) (result i32)
|
||||
local.get $x
|
||||
local.get $y
|
||||
i32.add)
|
||||
(export "sum" (func $sum_f)))
|
||||
"#
|
||||
.as_bytes(),
|
||||
)?;
|
||||
|
||||
// Define a compiler configuration.
|
||||
//
|
||||
// In this situation, the compiler is
|
||||
// `wasmer_compiler_cranelift`. The compiler is responsible to
|
||||
// compile the Wasm module into executable code.
|
||||
let compiler_config = Cranelift::default();
|
||||
// Define a compiler configuration.
|
||||
//
|
||||
// In this situation, the compiler is
|
||||
// `wasmer_compiler_cranelift`. The compiler is responsible to
|
||||
// compile the Wasm module into executable code.
|
||||
let compiler_config = Cranelift::default();
|
||||
|
||||
println!("Creating Dylib engine...");
|
||||
// Define the engine that will drive everything.
|
||||
//
|
||||
// In this case, the engine is `wasmer_engine_dylib` which means
|
||||
// that a shared object is going to be generated.
|
||||
let engine = Dylib::new(compiler_config).engine();
|
||||
println!("Creating Dylib engine...");
|
||||
// Define the engine that will drive everything.
|
||||
//
|
||||
// In this case, the engine is `wasmer_engine_dylib` which means
|
||||
// that a shared object is going to be generated.
|
||||
let engine = Dylib::new(compiler_config).engine();
|
||||
|
||||
// Create a store, that holds the engine.
|
||||
let store = Store::new(&engine);
|
||||
// Create a store, that holds the engine.
|
||||
let store = Store::new(&engine);
|
||||
|
||||
println!("Compiling module...");
|
||||
// Here we go.
|
||||
//
|
||||
// Let's compile the Wasm module. It is at this step that the Wasm
|
||||
// text is transformed into Wasm bytes (if necessary), and then
|
||||
// compiled to executable code by the compiler, which is then
|
||||
// stored into a shared object by the engine.
|
||||
let module = Module::new(&store, wasm_bytes)?;
|
||||
println!("Compiling module...");
|
||||
// Here we go.
|
||||
//
|
||||
// Let's compile the Wasm module. It is at this step that the Wasm
|
||||
// text is transformed into Wasm bytes (if necessary), and then
|
||||
// compiled to executable code by the compiler, which is then
|
||||
// stored into a shared object by the engine.
|
||||
let module = Module::new(&store, wasm_bytes)?;
|
||||
|
||||
// Congrats, the Wasm module is compiled! Now let's execute it for
|
||||
// the sake of having a complete example.
|
||||
// Congrats, the Wasm module is compiled! Now let's execute it for
|
||||
// the sake of having a complete example.
|
||||
|
||||
// Create an import object. Since our Wasm module didn't declare
|
||||
// any imports, it's an empty object.
|
||||
let import_object = imports! {};
|
||||
// Create an import object. Since our Wasm module didn't declare
|
||||
// any imports, it's an empty object.
|
||||
let import_object = imports! {};
|
||||
|
||||
println!("Instantiating module...");
|
||||
// And here we go again. Let's instantiate the Wasm module.
|
||||
let instance = Instance::new(&module, &import_object)?;
|
||||
println!("Instantiating module...");
|
||||
// And here we go again. Let's instantiate the Wasm module.
|
||||
let instance = Instance::new(&module, &import_object)?;
|
||||
|
||||
println!("Calling `sum` function...");
|
||||
// The Wasm module exports a function called `sum`.
|
||||
let sum = instance.exports.get_function("sum")?;
|
||||
let results = sum.call(&[Value::I32(1), Value::I32(2)])?;
|
||||
println!("Calling `sum` function...");
|
||||
// The Wasm module exports a function called `sum`.
|
||||
let sum = instance.exports.get_function("sum")?;
|
||||
let results = sum.call(&[Value::I32(1), Value::I32(2)])?;
|
||||
|
||||
println!("Results: {:?}", results);
|
||||
assert_eq!(results.to_vec(), vec![Value::I32(3)]);
|
||||
println!("Results: {:?}", results);
|
||||
assert_eq!(results.to_vec(), vec![Value::I32(3)]);
|
||||
*/
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -8,10 +8,9 @@
|
||||
//! What problem does it solve, and what does it mean?
|
||||
//!
|
||||
//! Once a Wasm module is compiled into executable code and stored
|
||||
//! somewhere (e.g. in memory with the Universal engine, or in a
|
||||
//! shared object file with the Dylib engine), the module can be
|
||||
//! instantiated and executed. But imagine for a second the following
|
||||
//! scenario:
|
||||
//! somewhere (e.g. in memory with the Universal engine), the module
|
||||
//! can be instantiated and executed. But imagine for a second the
|
||||
//! following scenario:
|
||||
//!
|
||||
//! * Modules are compiled ahead of time, to be instantiated later
|
||||
//! on.
|
||||
@ -53,7 +52,7 @@ use wasmer::Module;
|
||||
use wasmer::Store;
|
||||
use wasmer::Value;
|
||||
use wasmer_compiler_cranelift::Cranelift;
|
||||
use wasmer_engine_dylib::Dylib;
|
||||
use wasmer_engine_universal::Universal;
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
// First step, let's compile the Wasm module and serialize it.
|
||||
@ -80,16 +79,9 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
// compile the Wasm module into executable code.
|
||||
let compiler_config = Cranelift::default();
|
||||
|
||||
println!("Creating Dylib engine...");
|
||||
println!("Creating univesral engine...");
|
||||
// Define the engine that will drive everything.
|
||||
//
|
||||
// In this case, the engine is `wasmer_engine_dylib` which
|
||||
// means that a shared object is going to be generated. So
|
||||
// when we are going to serialize the compiled Wasm module, we
|
||||
// are going to store it in a file with the `.so` extension
|
||||
// for example (or `.dylib`, or `.dll` depending of the
|
||||
// platform).
|
||||
let engine = Dylib::new(compiler_config).engine();
|
||||
let engine = Universal::new(compiler_config).engine();
|
||||
|
||||
// Create a store, that holds the engine.
|
||||
let store = Store::new(&engine);
|
||||
@ -110,9 +102,9 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
// Second step, deserialize the compiled Wasm module, and execute
|
||||
// it, for example with Wasmer without a compiler.
|
||||
{
|
||||
println!("Creating headless Dylib engine...");
|
||||
// We create a headless Dylib engine.
|
||||
let engine = Dylib::headless().engine();
|
||||
println!("Creating headless Universal engine...");
|
||||
// We create a headless Universal engine.
|
||||
let engine = Universal::headless().engine();
|
||||
let store = Store::new(&engine);
|
||||
|
||||
println!("Deserializing module...");
|
||||
|
@ -17,49 +17,53 @@ use std::str::FromStr;
|
||||
use wasmer::{wat2wasm, Module, RuntimeError, Store};
|
||||
use wasmer_compiler::{CpuFeature, Target, Triple};
|
||||
use wasmer_compiler_cranelift::Cranelift;
|
||||
/*
|
||||
use wasmer_engine_dylib::Dylib;
|
||||
*/
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
// Let's declare the Wasm module with the text representation.
|
||||
let wasm_bytes = wat2wasm(
|
||||
r#"
|
||||
(module
|
||||
(type $sum_t (func (param i32 i32) (result i32)))
|
||||
(func $sum_f (type $sum_t) (param $x i32) (param $y i32) (result i32)
|
||||
local.get $x
|
||||
local.get $y
|
||||
i32.add)
|
||||
(export "sum" (func $sum_f)))
|
||||
"#
|
||||
.as_bytes(),
|
||||
)?;
|
||||
/*
|
||||
// Let's declare the Wasm module with the text representation.
|
||||
let wasm_bytes = wat2wasm(
|
||||
r#"
|
||||
(module
|
||||
(type $sum_t (func (param i32 i32) (result i32)))
|
||||
(func $sum_f (type $sum_t) (param $x i32) (param $y i32) (result i32)
|
||||
local.get $x
|
||||
local.get $y
|
||||
i32.add)
|
||||
(export "sum" (func $sum_f)))
|
||||
"#
|
||||
.as_bytes(),
|
||||
)?;
|
||||
|
||||
// Create a compiler for iOS
|
||||
let compiler_config = Cranelift::default();
|
||||
// Change it to `x86_64-apple-ios` if you want to target the iOS simulator
|
||||
let triple = Triple::from_str("aarch64-apple-ios")
|
||||
.map_err(|error| RuntimeError::new(error.to_string()))?;
|
||||
// Create a compiler for iOS
|
||||
let compiler_config = Cranelift::default();
|
||||
// Change it to `x86_64-apple-ios` if you want to target the iOS simulator
|
||||
let triple = Triple::from_str("aarch64-apple-ios")
|
||||
.map_err(|error| RuntimeError::new(error.to_string()))?;
|
||||
|
||||
// Let's build the target.
|
||||
let mut cpu_feature = CpuFeature::set();
|
||||
cpu_feature.insert(CpuFeature::from_str("sse2")?);
|
||||
let target = Target::new(triple, cpu_feature);
|
||||
println!("Chosen target: {:?}", target);
|
||||
// Let's build the target.
|
||||
let mut cpu_feature = CpuFeature::set();
|
||||
cpu_feature.insert(CpuFeature::from_str("sse2")?);
|
||||
let target = Target::new(triple, cpu_feature);
|
||||
println!("Chosen target: {:?}", target);
|
||||
|
||||
println!("Creating Dylib engine...");
|
||||
let engine = Dylib::new(compiler_config).target(target).engine();
|
||||
println!("Creating Dylib engine...");
|
||||
let engine = Dylib::new(compiler_config).target(target).engine();
|
||||
|
||||
// Create a store, that holds the engine.
|
||||
let store = Store::new(&engine);
|
||||
// Create a store, that holds the engine.
|
||||
let store = Store::new(&engine);
|
||||
|
||||
println!("Compiling module...");
|
||||
// Let's compile the Wasm module.
|
||||
let module = Module::new(&store, wasm_bytes)?;
|
||||
// Here we go. Let's serialize the compiled Wasm module in a
|
||||
// file.
|
||||
println!("Serializing module...");
|
||||
let dylib_file = Path::new("./sum.dylib");
|
||||
module.serialize_to_file(dylib_file)?;
|
||||
println!("Compiling module...");
|
||||
// Let's compile the Wasm module.
|
||||
let module = Module::new(&store, wasm_bytes)?;
|
||||
// Here we go. Let's serialize the compiled Wasm module in a
|
||||
// file.
|
||||
println!("Serializing module...");
|
||||
let dylib_file = Path::new("./sum.dylib");
|
||||
module.serialize_to_file(dylib_file)?;
|
||||
*/
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -17,7 +17,6 @@ wasmer-compiler-cranelift = { path = "../lib/compiler-cranelift", optional = tru
|
||||
wasmer-compiler-llvm = { path = "../lib/compiler-llvm", optional = true }
|
||||
wasmer-compiler-singlepass = { path = "../lib/compiler-singlepass", optional = true }
|
||||
wasmer-engine-universal = { path = "../lib/engine-universal", optional = true }
|
||||
wasmer-engine-dylib = { path = "../lib/engine-dylib", optional = true }
|
||||
wasmer-middlewares = { path = "../lib/middlewares" }
|
||||
wasmprinter = "0.2"
|
||||
|
||||
@ -26,7 +25,6 @@ cranelift = [ "wasmer-compiler-cranelift" ]
|
||||
llvm = [ "wasmer-compiler-llvm" ]
|
||||
singlepass = [ "wasmer-compiler-singlepass" ]
|
||||
universal = [ "wasmer-engine-universal" ]
|
||||
dylib = [ "wasmer-engine-dylib" ]
|
||||
|
||||
[[bin]]
|
||||
name = "equivalence_universal"
|
||||
@ -53,12 +51,7 @@ name = "metering"
|
||||
path = "fuzz_targets/metering.rs"
|
||||
required-features = ["universal", "cranelift"]
|
||||
|
||||
[[bin]]
|
||||
name = "dylib_cranelift"
|
||||
path = "fuzz_targets/dylib_cranelift.rs"
|
||||
required-features = ["dylib", "cranelift"]
|
||||
|
||||
[[bin]]
|
||||
name = "deterministic"
|
||||
path = "fuzz_targets/deterministic.rs"
|
||||
required-features = ["universal", "dylib", "cranelift", "llvm", "singlepass"]
|
||||
required-features = ["universal", "cranelift", "llvm", "singlepass"]
|
||||
|
@ -6,7 +6,6 @@ use wasmer::{CompilerConfig, Engine, Module, Store};
|
||||
use wasmer_compiler_cranelift::Cranelift;
|
||||
use wasmer_compiler_llvm::LLVM;
|
||||
use wasmer_compiler_singlepass::Singlepass;
|
||||
use wasmer_engine_dylib::Dylib;
|
||||
use wasmer_engine_universal::Universal;
|
||||
|
||||
#[derive(Arbitrary, Debug, Default, Copy, Clone)]
|
||||
@ -51,11 +50,6 @@ fuzz_target!(|module: ConfiguredModule<NoImportsConfig>| {
|
||||
Universal::new(compiler.clone()).engine(),
|
||||
&wasm_bytes,
|
||||
);
|
||||
//compile_and_compare(
|
||||
// "dylib-cranelift",
|
||||
// Dylib::new(compiler).engine(),
|
||||
// &wasm_bytes,
|
||||
//);
|
||||
|
||||
let mut compiler = LLVM::default();
|
||||
compiler.canonicalize_nans(true);
|
||||
@ -65,7 +59,6 @@ fuzz_target!(|module: ConfiguredModule<NoImportsConfig>| {
|
||||
Universal::new(compiler.clone()).engine(),
|
||||
&wasm_bytes,
|
||||
);
|
||||
//compile_and_compare("dylib-llvm", Dylib::new(compiler).engine(), &wasm_bytes);
|
||||
|
||||
let compiler = Singlepass::default();
|
||||
compile_and_compare(
|
||||
@ -73,9 +66,4 @@ fuzz_target!(|module: ConfiguredModule<NoImportsConfig>| {
|
||||
Universal::new(compiler.clone()).engine(),
|
||||
&wasm_bytes,
|
||||
);
|
||||
//compile_and_compare(
|
||||
// "dylib-singlepass",
|
||||
// Dylib::new(compiler).engine(),
|
||||
// &wasm_bytes,
|
||||
//);
|
||||
});
|
||||
|
@ -1,64 +0,0 @@
|
||||
#![no_main]
|
||||
|
||||
use libfuzzer_sys::{arbitrary, arbitrary::Arbitrary, fuzz_target};
|
||||
use wasm_smith::{Config, ConfiguredModule};
|
||||
use wasmer::{imports, Instance, Module, Store};
|
||||
use wasmer_compiler_cranelift::Cranelift;
|
||||
use wasmer_engine_dylib::Dylib;
|
||||
|
||||
#[derive(Arbitrary, Debug, Default, Copy, Clone)]
|
||||
struct NoImportsConfig;
|
||||
impl Config for NoImportsConfig {
|
||||
fn max_imports(&self) -> usize {
|
||||
0
|
||||
}
|
||||
fn max_memory_pages(&self) -> u32 {
|
||||
// https://github.com/wasmerio/wasmer/issues/2187
|
||||
65535
|
||||
}
|
||||
fn allow_start_export(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
#[derive(Arbitrary)]
|
||||
struct WasmSmithModule(ConfiguredModule<NoImportsConfig>);
|
||||
impl std::fmt::Debug for WasmSmithModule {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str(&wasmprinter::print_bytes(self.0.to_bytes()).unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
fuzz_target!(|module: WasmSmithModule| {
|
||||
let serialized = {
|
||||
let wasm_bytes = module.0.to_bytes();
|
||||
|
||||
if let Ok(path) = std::env::var("DUMP_TESTCASE") {
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
let mut file = File::create(path).unwrap();
|
||||
file.write_all(&wasm_bytes).unwrap();
|
||||
return;
|
||||
}
|
||||
|
||||
let compiler = Cranelift::default();
|
||||
let store = Store::new(&Dylib::new(compiler).engine());
|
||||
let module = Module::new(&store, &wasm_bytes).unwrap();
|
||||
module.serialize().unwrap()
|
||||
};
|
||||
|
||||
let engine = Dylib::headless().engine();
|
||||
let store = Store::new(&engine);
|
||||
let module = unsafe { Module::deserialize(&store, serialized.as_slice()) }.unwrap();
|
||||
match Instance::new(&module, &imports! {}) {
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
let error_message = format!("{}", e);
|
||||
if error_message.starts_with("RuntimeError: ")
|
||||
&& error_message.contains("out of bounds")
|
||||
{
|
||||
return;
|
||||
}
|
||||
panic!("{}", e);
|
||||
}
|
||||
}
|
||||
});
|
@ -34,9 +34,6 @@ composed of a set of crates. We can group them as follows:
|
||||
differ:
|
||||
* `engine-universal` — stores the code in a custom file format, and
|
||||
loads it in memory,
|
||||
* `engine-dylib` — stores Position-Independent Code in a native
|
||||
shared object library (`.dylib`, `.so`, `.dll`) and loads it with
|
||||
Operating System shared library loader (via `dlopen`),
|
||||
* `engine-staticlib` — stores executable code in a native static
|
||||
object library, in addition to emitting a C header file, which
|
||||
both can be linked against a sandboxed WebAssembly runtime
|
||||
|
@ -44,7 +44,6 @@ wasmer-compiler-singlepass = { path = "../compiler-singlepass", version = "=2.3.
|
||||
wasmer-compiler-cranelift = { path = "../compiler-cranelift", version = "=2.3.0", optional = true }
|
||||
wasmer-compiler-llvm = { path = "../compiler-llvm", version = "=2.3.0", optional = true }
|
||||
wasmer-engine-universal = { path = "../engine-universal", version = "=2.3.0", optional = true }
|
||||
wasmer-engine-dylib = { path = "../engine-dylib", version = "=2.3.0", optional = true }
|
||||
# - Mandatory dependencies for `sys` on Windows.
|
||||
[target.'cfg(all(not(target_arch = "wasm32"), target_os = "windows"))'.dependencies]
|
||||
winapi = "0.3"
|
||||
@ -93,7 +92,6 @@ compiler = [
|
||||
"sys",
|
||||
"wasmer-compiler/translator",
|
||||
"wasmer-engine-universal/compiler",
|
||||
"wasmer-engine-dylib/compiler",
|
||||
]
|
||||
singlepass = [
|
||||
"compiler",
|
||||
@ -126,19 +124,11 @@ engine = ["sys"]
|
||||
"engine",
|
||||
"wasmer-engine-universal",
|
||||
]
|
||||
dylib = [
|
||||
"engine",
|
||||
"wasmer-engine-dylib",
|
||||
]
|
||||
default-engine = []
|
||||
default-universal = [
|
||||
"default-engine",
|
||||
"universal",
|
||||
]
|
||||
default-dylib = [
|
||||
"default-engine",
|
||||
"dylib",
|
||||
]
|
||||
# - Experimental / in-development features
|
||||
experimental-reference-types-extern-ref = [
|
||||
"sys",
|
||||
@ -146,7 +136,6 @@ experimental-reference-types-extern-ref = [
|
||||
]
|
||||
# - Deprecated features.
|
||||
jit = ["universal"]
|
||||
native = ["dylib"]
|
||||
|
||||
# Features for `js`.
|
||||
js = []
|
||||
@ -157,4 +146,4 @@ wasm-types-polyfill = ["js", "wasmparser"]
|
||||
js-serializable-module = []
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
features = ["compiler", "core", "cranelift", "default-compiler", "default-dylib", "default-engine", "dylib", "engine", "jit", "native", "singlepass", "sys", "sys-default", "universal"]
|
||||
features = ["compiler", "core", "cranelift", "default-compiler", "default-engine", "engine", "jit", "native", "singlepass", "sys", "sys-default", "universal"]
|
||||
|
@ -49,8 +49,6 @@ Wasmer is not only fast, but also designed to be *highly customizable*:
|
||||
compilation process and to store the generated executable code
|
||||
somewhere, either:
|
||||
* in-memory (with [`wasmer-engine-universal`]),
|
||||
* in a native shared object file (with [`wasmer-engine-dylib`],
|
||||
`.dylib`, `.so`, `.dll`), then load it with `dlopen`,
|
||||
* in a native static object file (with [`wasmer-engine-staticlib`]),
|
||||
in addition to emitting a C header file, which both can be linked
|
||||
against a sandboxed WebAssembly runtime environment for the
|
||||
@ -101,7 +99,6 @@ more](https://wasmerio.github.io/wasmer/crates/doc/wasmer/).
|
||||
Made with ❤️ by the Wasmer team, for the community
|
||||
|
||||
[`wasmer-engine-universal`]: https://github.com/wasmerio/wasmer/tree/master/lib/engine-universal
|
||||
[`wasmer-engine-dylib`]: https://github.com/wasmerio/wasmer/tree/master/lib/engine-dylib
|
||||
[`wasmer-engine-staticlib`]: https://github.com/wasmerio/wasmer/tree/master/lib/engine-staticlib
|
||||
[`wasmer-compiler-singlepass`]: https://github.com/wasmerio/wasmer/tree/master/lib/compiler-singlepass
|
||||
[`wasmer-compiler-cranelift`]: https://github.com/wasmerio/wasmer/tree/master/lib/compiler-cranelift
|
||||
|
@ -77,8 +77,6 @@
|
||||
//! compilation process and to store the generated executable code
|
||||
//! somewhere, either:
|
||||
//! * in-memory (with [`wasmer-engine-universal`]),
|
||||
//! * in a native shared object file (with [`wasmer-engine-dylib`],
|
||||
//! `.dylib`, `.so`, `.dll`), then load it with `dlopen`,
|
||||
//! * in a native static object file (with [`wasmer-engine-staticlib`]),
|
||||
//! in addition to emitting a C header file, which both can be linked
|
||||
//! against a sandboxed WebAssembly runtime environment for the
|
||||
@ -324,11 +322,7 @@
|
||||
//! - `universal`
|
||||
#![cfg_attr(feature = "universal", doc = "(enabled),")]
|
||||
#![cfg_attr(not(feature = "universal"), doc = "(disabled),")]
|
||||
//! enables [the Universal engine][`wasmer-engine-universal`],
|
||||
//! - `dylib`
|
||||
#![cfg_attr(feature = "dylib", doc = "(enabled),")]
|
||||
#![cfg_attr(not(feature = "dylib"), doc = "(disabled),")]
|
||||
//! enables [the Dylib engine][`wasmer-engine-dylib`].
|
||||
//! enables [the Universal engine][`wasmer-engine-universal`].
|
||||
//!
|
||||
//! The features that set defaults come in sets that are mutually exclusive.
|
||||
//!
|
||||
@ -350,11 +344,7 @@
|
||||
//! - `default-universal`
|
||||
#![cfg_attr(feature = "default-universal", doc = "(enabled),")]
|
||||
#![cfg_attr(not(feature = "default-universal"), doc = "(disabled),")]
|
||||
//! set the Universal engine as the default,
|
||||
//! - `default-dylib`
|
||||
#![cfg_attr(feature = "default-dylib", doc = "(enabled),")]
|
||||
#![cfg_attr(not(feature = "default-dylib"), doc = "(disabled),")]
|
||||
//! set the Dylib engine as the default.
|
||||
//! set the Universal engine as the default.
|
||||
//!
|
||||
#![cfg_attr(
|
||||
feature = "js",
|
||||
@ -434,7 +424,6 @@
|
||||
//! [`wasmer-emscripten`]: https://docs.rs/wasmer-emscripten/
|
||||
//! [wasmer-engine]: https://docs.rs/wasmer-engine/
|
||||
//! [`wasmer-engine-universal`]: https://docs.rs/wasmer-engine-universal/
|
||||
//! [`wasmer-engine-dylib`]: https://docs.rs/wasmer-engine-dylib/
|
||||
//! [`wasmer-engine-staticlib`]: https://docs.rs/wasmer-engine-staticlib/
|
||||
//! [`wasmer-compiler-singlepass`]: https://docs.rs/wasmer-compiler-singlepass/
|
||||
//! [`wasmer-compiler-llvm`]: https://docs.rs/wasmer-compiler-llvm/
|
||||
|
@ -112,9 +112,6 @@ pub use wasmer_compiler_llvm::{LLVMOptLevel, LLVM};
|
||||
#[cfg(feature = "universal")]
|
||||
pub use wasmer_engine_universal::{Universal, UniversalArtifact, UniversalEngine};
|
||||
|
||||
#[cfg(feature = "dylib")]
|
||||
pub use wasmer_engine_dylib::{Dylib, DylibArtifact, DylibEngine};
|
||||
|
||||
/// Version number of this crate.
|
||||
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||
|
||||
@ -123,11 +120,6 @@ pub const VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||
#[deprecated(since = "2.0.0", note = "Please use the `universal` feature instead")]
|
||||
pub type JIT = Universal;
|
||||
|
||||
/// The Deprecated Native Engine (please use `Dylib` instead)
|
||||
#[cfg(feature = "native")]
|
||||
#[deprecated(since = "2.0.0", note = "Please use the `native` feature instead")]
|
||||
pub type Native = Dylib;
|
||||
|
||||
/// This type is deprecated, it has been replaced by TypedFunction.
|
||||
#[deprecated(
|
||||
since = "3.0.0",
|
||||
|
@ -121,9 +121,6 @@ impl Default for Store {
|
||||
if #[cfg(feature = "default-universal")] {
|
||||
wasmer_engine_universal::Universal::new(config)
|
||||
.engine()
|
||||
} else if #[cfg(feature = "default-dylib")] {
|
||||
wasmer_engine_dylib::Dylib::new(config)
|
||||
.engine()
|
||||
} else {
|
||||
compile_error!("No default engine chosen")
|
||||
}
|
||||
|
@ -13,7 +13,6 @@ attributions of the project.
|
||||
|
||||
|
||||
[`wasmer-engine-universal`]: https://github.com/wasmerio/wasmer/tree/master/lib/engine-universal
|
||||
[`wasmer-engine-dylib`]: https://github.com/wasmerio/wasmer/tree/master/lib/engine-dylib
|
||||
[`wasmer-engine-staticlib`]: https://github.com/wasmerio/wasmer/tree/master/lib/engine-staticlib
|
||||
[`wasmer-engine-dummy`]: https://github.com/wasmerio/wasmer/tree/master/tests/lib/engine-dummy
|
||||
[`wasmtime-api`]: https://crates.io/crates/wasmtime
|
||||
|
@ -29,7 +29,6 @@ wasmer-compiler-llvm = { version = "=2.3.0", path = "../compiler-llvm", optional
|
||||
wasmer-emscripten = { version = "=2.3.0", path = "../emscripten", optional = true }
|
||||
wasmer-engine = { version = "=2.3.0", path = "../engine" }
|
||||
wasmer-engine-universal = { version = "=2.3.0", path = "../engine-universal", optional = true }
|
||||
wasmer-engine-dylib = { version = "=2.3.0", path = "../engine-dylib", optional = true }
|
||||
wasmer-engine-staticlib = { version = "=2.3.0", path = "../engine-staticlib", optional = true }
|
||||
wasmer-middlewares = { version = "=2.3.0", path = "../middlewares", optional = true }
|
||||
wasmer-wasi = { version = "=2.3.0", path = "../wasi", default-features = false, features = ["host-fs", "sys"], optional = true }
|
||||
@ -66,10 +65,6 @@ universal = [
|
||||
"wasmer-engine-universal",
|
||||
"engine",
|
||||
]
|
||||
dylib = [
|
||||
"wasmer-engine-dylib",
|
||||
"engine",
|
||||
]
|
||||
staticlib = [
|
||||
"wasmer-engine-staticlib",
|
||||
"engine",
|
||||
@ -77,7 +72,6 @@ staticlib = [
|
||||
compiler = [
|
||||
"wasmer-api/compiler",
|
||||
"wasmer-engine-universal/compiler",
|
||||
"wasmer-engine-dylib/compiler",
|
||||
"wasmer-engine-staticlib/compiler"
|
||||
]
|
||||
singlepass = [
|
||||
@ -95,10 +89,9 @@ llvm = [
|
||||
|
||||
# Deprecated features.
|
||||
jit = ["universal"]
|
||||
native = ["dylib"]
|
||||
|
||||
# TODO: Port this feature.
|
||||
#emscripten = ["wasmer-emscripten"]
|
||||
|
||||
[build-dependencies]
|
||||
cbindgen = "0.19"
|
||||
cbindgen = "0.19"
|
||||
|
@ -13,8 +13,6 @@ use crate::error::update_last_error;
|
||||
use cfg_if::cfg_if;
|
||||
use std::sync::Arc;
|
||||
use wasmer_api::Engine;
|
||||
#[cfg(feature = "dylib")]
|
||||
use wasmer_engine_dylib::Dylib;
|
||||
#[cfg(feature = "staticlib")]
|
||||
use wasmer_engine_staticlib::Staticlib;
|
||||
#[cfg(feature = "universal")]
|
||||
@ -70,10 +68,6 @@ pub enum wasmer_engine_t {
|
||||
/// [`wasmer_engine_universal`] Rust crate.
|
||||
UNIVERSAL = 0,
|
||||
|
||||
/// Variant to represent the Dylib engine. See the
|
||||
/// [`wasmer_engine_dylib`] Rust crate.
|
||||
DYLIB = 1,
|
||||
|
||||
/// Variant to represent the Staticlib engine. See the
|
||||
/// [`wasmer_engine_staticlib`] Rust crate.
|
||||
STATICLIB = 2,
|
||||
@ -84,8 +78,6 @@ impl Default for wasmer_engine_t {
|
||||
cfg_if! {
|
||||
if #[cfg(feature = "universal")] {
|
||||
Self::UNIVERSAL
|
||||
} else if #[cfg(feature = "dylib")] {
|
||||
Self::DYLIB
|
||||
} else if #[cfg(feature = "staticlib")] {
|
||||
Self::STATICLIB
|
||||
} else {
|
||||
@ -251,10 +243,6 @@ pub extern "C" fn wasm_config_set_compiler(
|
||||
/// if (wasmer_is_engine_available(UNIVERSAL)) {
|
||||
/// wasm_config_set_engine(config, UNIVERSAL);
|
||||
/// }
|
||||
/// // Or maybe the Dylib engine?
|
||||
/// else if (wasmer_is_engine_available(DYLIB)) {
|
||||
/// wasm_config_set_engine(config, DYLIB);
|
||||
/// }
|
||||
/// // OK, let's do not specify any particular engine.
|
||||
///
|
||||
/// // Create the engine.
|
||||
@ -332,33 +320,6 @@ cfg_if! {
|
||||
let engine: Arc<dyn Engine + Send + Sync> = Arc::new(Universal::headless().engine());
|
||||
Box::new(wasm_engine_t { inner: engine })
|
||||
}
|
||||
} else if #[cfg(all(feature = "dylib", feature = "compiler"))] {
|
||||
/// Creates a new Dylib engine with the default compiler.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// See [`wasm_engine_delete`].
|
||||
///
|
||||
/// cbindgen:ignore
|
||||
#[no_mangle]
|
||||
pub extern "C" fn wasm_engine_new() -> Box<wasm_engine_t> {
|
||||
let compiler_config: Box<dyn CompilerConfig> = get_default_compiler_config();
|
||||
let engine: Arc<dyn Engine + Send + Sync> = Arc::new(Dylib::new(compiler_config).engine());
|
||||
Box::new(wasm_engine_t { inner: engine })
|
||||
}
|
||||
} else if #[cfg(feature = "dylib")] {
|
||||
/// Creates a new headless Dylib engine.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// See [`wasm_engine_delete`].
|
||||
///
|
||||
/// cbindgen:ignore
|
||||
#[no_mangle]
|
||||
pub extern "C" fn wasm_engine_new() -> Box<wasm_engine_t> {
|
||||
let engine: Arc<dyn Engine + Send + Sync> = Arc::new(Dylib::headless().engine());
|
||||
Box::new(wasm_engine_t { inner: engine })
|
||||
}
|
||||
}
|
||||
// There are currently no uses of the Staticlib engine + compiler from the C API.
|
||||
// So if we get here, we default to headless mode regardless of if `compiler` is enabled.
|
||||
@ -502,25 +463,6 @@ pub extern "C" fn wasm_engine_new_with_config(
|
||||
}
|
||||
}
|
||||
},
|
||||
wasmer_engine_t::DYLIB => {
|
||||
cfg_if! {
|
||||
if #[cfg(feature = "dylib")] {
|
||||
let mut builder = Dylib::new(compiler_config);
|
||||
|
||||
if let Some(target) = config.target {
|
||||
builder = builder.target(target.inner);
|
||||
}
|
||||
|
||||
if let Some(features) = config.features {
|
||||
builder = builder.features(features.inner);
|
||||
}
|
||||
|
||||
Arc::new(builder.engine())
|
||||
} else {
|
||||
return return_with_error("Wasmer has not been compiled with the `dylib` feature.");
|
||||
}
|
||||
}
|
||||
},
|
||||
wasmer_engine_t::STATICLIB => {
|
||||
cfg_if! {
|
||||
// There are currently no uses of the Staticlib engine + compiler from the C API.
|
||||
@ -565,25 +507,6 @@ pub extern "C" fn wasm_engine_new_with_config(
|
||||
}
|
||||
}
|
||||
},
|
||||
wasmer_engine_t::DYLIB => {
|
||||
cfg_if! {
|
||||
if #[cfg(feature = "dylib")] {
|
||||
let mut builder = Dylib::headless();
|
||||
|
||||
if let Some(target) = config.target {
|
||||
builder = builder.target(target.inner);
|
||||
}
|
||||
|
||||
if let Some(features) = config.features {
|
||||
builder = builder.features(features.inner);
|
||||
}
|
||||
|
||||
Arc::new(builder.engine())
|
||||
} else {
|
||||
return return_with_error("Wasmer has not been compiled with the `dylib` feature.");
|
||||
}
|
||||
}
|
||||
},
|
||||
wasmer_engine_t::STATICLIB => {
|
||||
cfg_if! {
|
||||
if #[cfg(feature = "staticlib")] {
|
||||
|
@ -163,7 +163,6 @@ pub extern "C" fn wasmer_is_headless() -> bool {
|
||||
pub extern "C" fn wasmer_is_engine_available(engine: wasmer_engine_t) -> bool {
|
||||
match engine {
|
||||
wasmer_engine_t::UNIVERSAL if cfg!(feature = "universal") => true,
|
||||
wasmer_engine_t::DYLIB if cfg!(feature = "dylib") => true,
|
||||
wasmer_engine_t::STATICLIB if cfg!(feature = "staticlib") => true,
|
||||
_ => false,
|
||||
}
|
||||
@ -245,7 +244,6 @@ mod tests {
|
||||
"0"
|
||||
},
|
||||
);
|
||||
set_var("DYLIB", if cfg!(feature = "dylib") { "1" } else { "0" });
|
||||
set_var(
|
||||
"STATICLIB",
|
||||
if cfg!(feature = "staticlib") {
|
||||
@ -261,7 +259,6 @@ mod tests {
|
||||
|
||||
int main() {
|
||||
assert(wasmer_is_engine_available(UNIVERSAL) == (getenv("UNIVERSAL")[0] == '1'));
|
||||
assert(wasmer_is_engine_available(DYLIB) == (getenv("DYLIB")[0] == '1'));
|
||||
assert(wasmer_is_engine_available(STATICLIB) == (getenv("STATICLIB")[0] == '1'));
|
||||
|
||||
return 0;
|
||||
@ -270,7 +267,6 @@ mod tests {
|
||||
.success();
|
||||
|
||||
remove_var("UNIVERSAL");
|
||||
remove_var("DYLIB");
|
||||
remove_var("STATICLIB");
|
||||
}
|
||||
}
|
||||
|
@ -34,9 +34,6 @@ wasm_engine_t *wasm_engine_new() {
|
||||
if (strcmp(wasmer_test_engine, "universal") == 0) {
|
||||
assert(wasmer_is_engine_available(UNIVERSAL));
|
||||
wasm_config_set_engine(config, UNIVERSAL);
|
||||
} else if (strcmp(wasmer_test_engine, "dylib") == 0) {
|
||||
assert(wasmer_is_engine_available(DYLIB));
|
||||
wasm_config_set_engine(config, DYLIB);
|
||||
} else if (wasmer_test_engine) {
|
||||
printf("Engine %s not recognized\n", wasmer_test_engine);
|
||||
abort();
|
||||
|
1
lib/cache/Cargo.toml
vendored
1
lib/cache/Cargo.toml
vendored
@ -22,7 +22,6 @@ tempfile = "3"
|
||||
rand = "0.8.3"
|
||||
wasmer-compiler-singlepass = { path = "../compiler-singlepass", version = "=2.3.0" }
|
||||
wasmer-engine-universal = { path = "../engine-universal", version = "=2.3.0" }
|
||||
wasmer-engine-dylib = { path = "../engine-dylib", version = "=2.3.0" }
|
||||
|
||||
[features]
|
||||
default = ["wasmer/js-serializable-module", "filesystem"]
|
||||
|
1
lib/cache/benches/bench_filesystem_cache.rs
vendored
1
lib/cache/benches/bench_filesystem_cache.rs
vendored
@ -7,7 +7,6 @@ use wasmer::{Module, Store};
|
||||
use wasmer_cache::Cache;
|
||||
use wasmer_cache::{FileSystemCache, Hash};
|
||||
use wasmer_compiler_singlepass::Singlepass;
|
||||
use wasmer_engine_dylib::Dylib;
|
||||
use wasmer_engine_universal::Universal;
|
||||
|
||||
fn random_key() -> Hash {
|
||||
|
@ -33,7 +33,6 @@ wasmer-compiler-llvm = { version = "=2.3.0", path = "../compiler-llvm", optional
|
||||
wasmer-emscripten = { version = "=2.3.0", path = "../emscripten", optional = true }
|
||||
wasmer-engine = { version = "=2.3.0", path = "../engine" }
|
||||
wasmer-engine-universal = { version = "=2.3.0", path = "../engine-universal", optional = true }
|
||||
wasmer-engine-dylib = { version = "=2.3.0", path = "../engine-dylib", optional = true }
|
||||
wasmer-engine-staticlib = { version = "=2.3.0", path = "../engine-staticlib", optional = true }
|
||||
wasmer-vm = { version = "=2.3.0", path = "../vm" }
|
||||
wasmer-wasi = { version = "=2.3.0", path = "../wasi", optional = true }
|
||||
@ -66,7 +65,6 @@ default = [
|
||||
"wat",
|
||||
"wast",
|
||||
"universal",
|
||||
"dylib",
|
||||
"staticlib",
|
||||
"cache",
|
||||
"wasi",
|
||||
@ -77,10 +75,6 @@ universal = [
|
||||
"wasmer-engine-universal",
|
||||
"engine",
|
||||
]
|
||||
dylib = [
|
||||
"wasmer-engine-dylib",
|
||||
"engine",
|
||||
]
|
||||
staticlib = [
|
||||
"wasmer-engine-staticlib",
|
||||
"engine",
|
||||
@ -94,7 +88,6 @@ wat = ["wasmer/wat"]
|
||||
compiler = [
|
||||
"wasmer-compiler/translator",
|
||||
"wasmer-engine-universal/compiler",
|
||||
"wasmer-engine-dylib/compiler",
|
||||
"wasmer-engine-staticlib/compiler",
|
||||
]
|
||||
experimental-io-devices = [
|
||||
@ -116,8 +109,7 @@ llvm = [
|
||||
debug = ["fern", "log", "wasmer-wasi/logging"]
|
||||
disable-all-logging = ["wasmer-wasi/disable-all-logging"]
|
||||
headless = []
|
||||
headless-minimal = ["headless", "disable-all-logging", "wasi", "dylib", "universal"]
|
||||
headless-minimal = ["headless", "disable-all-logging", "wasi", "universal"]
|
||||
|
||||
# Deprecated features.
|
||||
jit = ["universal"]
|
||||
native = ["dylib"]
|
||||
|
@ -26,7 +26,6 @@ The Wasmer supports the following features:
|
||||
* `wat` (default): support for executing WebAssembly text files.
|
||||
* `wast`(default): support for running wast test files.
|
||||
* `universal` (default): support for the [Universal engine].
|
||||
* `dylib` (default): support for the [Dylib engine].
|
||||
* `cache` (default): support or automatically caching compiled artifacts.
|
||||
* `wasi` (default): support for [WASI].
|
||||
* `experimental-io-devices`: support for experimental IO devices in WASI.
|
||||
@ -36,7 +35,6 @@ The Wasmer supports the following features:
|
||||
* `llvm`: support for the [LLVM compiler].
|
||||
|
||||
[Universal engine]: https://github.com/wasmerio/wasmer/tree/master/lib/engine-universal/
|
||||
[Dylib engine]: https://github.com/wasmerio/wasmer/tree/master/lib/engine-dylib/
|
||||
[WASI]: https://github.com/wasmerio/wasmer/tree/master/lib/wasi/
|
||||
[Emscripten]: https://github.com/wasmerio/wasmer/tree/master/lib/emscripten/
|
||||
[Singlepass compiler]: https://github.com/wasmerio/wasmer/tree/master/lib/compiler-singlepass/
|
||||
@ -62,11 +60,11 @@ wasmer run myfile.wasm
|
||||
Compile a WebAssembly file:
|
||||
|
||||
```bash
|
||||
wasmer compile myfile.wasm -o myfile.so --dylib
|
||||
wasmer compile myfile.wasm -o myfile.wasmu --universal
|
||||
```
|
||||
|
||||
Run a compiled WebAssembly file (fastest):
|
||||
|
||||
```bash
|
||||
wasmer run myfile.so
|
||||
wasmer run myfile.wasmu
|
||||
```
|
||||
|
@ -43,10 +43,6 @@ impl Compile {
|
||||
target_triple: &Triple,
|
||||
) -> Result<&'static str> {
|
||||
Ok(match engine_type {
|
||||
#[cfg(feature = "dylib")]
|
||||
EngineType::Dylib => {
|
||||
wasmer_engine_dylib::DylibArtifact::get_default_extension(target_triple)
|
||||
}
|
||||
#[cfg(feature = "universal")]
|
||||
EngineType::Universal => {
|
||||
wasmer_engine_universal::UniversalArtifact::get_default_extension(target_triple)
|
||||
@ -55,7 +51,7 @@ impl Compile {
|
||||
EngineType::Staticlib => {
|
||||
wasmer_engine_staticlib::StaticlibArtifact::get_default_extension(target_triple)
|
||||
}
|
||||
#[cfg(not(all(feature = "dylib", feature = "universal", feature = "staticlib")))]
|
||||
#[cfg(not(all(feature = "universal", feature = "staticlib")))]
|
||||
_ => bail!("selected engine type is not compiled in"),
|
||||
})
|
||||
}
|
||||
|
@ -223,15 +223,6 @@ impl Run {
|
||||
|
||||
fn get_module(&self) -> Result<Module> {
|
||||
let contents = std::fs::read(self.path.clone())?;
|
||||
#[cfg(feature = "dylib")]
|
||||
{
|
||||
if wasmer_engine_dylib::DylibArtifact::is_deserializable(&contents) {
|
||||
let engine = wasmer_engine_dylib::Dylib::headless().engine();
|
||||
let store = Store::new(&engine);
|
||||
let module = unsafe { Module::deserialize_from_file(&store, &self.path)? };
|
||||
return Ok(module);
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "universal")]
|
||||
{
|
||||
if wasmer_engine_universal::UniversalArtifact::is_deserializable(&contents) {
|
||||
@ -314,16 +305,8 @@ impl Run {
|
||||
cache_dir_root.push(compiler_type.to_string());
|
||||
let mut cache = FileSystemCache::new(cache_dir_root)?;
|
||||
|
||||
// Important: Dylib files need to have a `.dll` extension on
|
||||
// Windows, otherwise they will not load, so we just add an
|
||||
// extension always to make it easier to recognize as well.
|
||||
#[allow(unreachable_patterns)]
|
||||
let extension = match *engine_type {
|
||||
#[cfg(feature = "dylib")]
|
||||
EngineType::Dylib => {
|
||||
wasmer_engine_dylib::DylibArtifact::get_default_extension(&Triple::host())
|
||||
.to_string()
|
||||
}
|
||||
#[cfg(feature = "universal")]
|
||||
EngineType::Universal => {
|
||||
wasmer_engine_universal::UniversalArtifact::get_default_extension(&Triple::host())
|
||||
|
@ -23,27 +23,19 @@ pub struct StoreOptions {
|
||||
compiler: CompilerOptions,
|
||||
|
||||
/// Use the Universal Engine.
|
||||
#[structopt(long, conflicts_with_all = &["dylib", "staticlib", "jit", "native", "object_file"])]
|
||||
#[structopt(long, conflicts_with_all = &["staticlib", "jit", "object_file"])]
|
||||
universal: bool,
|
||||
|
||||
/// Use the Dylib Engine.
|
||||
#[structopt(long, conflicts_with_all = &["universal", "staticlib", "jit", "native", "object_file"])]
|
||||
dylib: bool,
|
||||
|
||||
/// Use the Staticlib Engine.
|
||||
#[structopt(long, conflicts_with_all = &["universal", "dylib", "jit", "native", "object_file"])]
|
||||
#[structopt(long, conflicts_with_all = &["universal", "jit", "object_file"])]
|
||||
staticlib: bool,
|
||||
|
||||
/// Use the JIT (Universal) Engine.
|
||||
#[structopt(long, hidden = true, conflicts_with_all = &["universal", "dylib", "staticlib", "native", "object_file"])]
|
||||
#[structopt(long, hidden = true, conflicts_with_all = &["universal", "staticlib", "object_file"])]
|
||||
jit: bool,
|
||||
|
||||
/// Use the Native (Dylib) Engine.
|
||||
#[structopt(long, hidden = true, conflicts_with_all = &["universal", "dylib", "staticlib", "jit", "object_file"])]
|
||||
native: bool,
|
||||
|
||||
/// Use the ObjectFile (Staticlib) Engine.
|
||||
#[structopt(long, hidden = true, conflicts_with_all = &["universal", "dylib", "staticlib", "jit", "native"])]
|
||||
#[structopt(long, hidden = true, conflicts_with_all = &["universal", "staticlib", "jit"])]
|
||||
object_file: bool,
|
||||
}
|
||||
|
||||
@ -150,13 +142,6 @@ impl CompilerOptions {
|
||||
.target(target)
|
||||
.engine(),
|
||||
),
|
||||
#[cfg(feature = "dylib")]
|
||||
EngineType::Dylib => Box::new(
|
||||
wasmer_engine_dylib::Dylib::new(compiler_config)
|
||||
.target(target)
|
||||
.features(features)
|
||||
.engine(),
|
||||
),
|
||||
#[cfg(feature = "staticlib")]
|
||||
EngineType::Staticlib => Box::new(
|
||||
wasmer_engine_staticlib::Staticlib::new(compiler_config)
|
||||
@ -164,7 +149,7 @@ impl CompilerOptions {
|
||||
.features(features)
|
||||
.engine(),
|
||||
),
|
||||
#[cfg(not(all(feature = "universal", feature = "dylib", feature = "staticlib")))]
|
||||
#[cfg(not(all(feature = "universal", feature = "staticlib")))]
|
||||
engine => bail!(
|
||||
"The `{}` engine is not included in this binary.",
|
||||
engine.to_string()
|
||||
@ -356,8 +341,6 @@ impl ToString for CompilerType {
|
||||
pub enum EngineType {
|
||||
/// Universal Engine
|
||||
Universal,
|
||||
/// Dylib Engine
|
||||
Dylib,
|
||||
/// Static Engine
|
||||
Staticlib,
|
||||
}
|
||||
@ -366,7 +349,6 @@ impl ToString for EngineType {
|
||||
fn to_string(&self) -> String {
|
||||
match self {
|
||||
Self::Universal => "universal".to_string(),
|
||||
Self::Dylib => "dylib".to_string(),
|
||||
Self::Staticlib => "staticlib".to_string(),
|
||||
}
|
||||
}
|
||||
@ -410,16 +392,12 @@ impl StoreOptions {
|
||||
fn get_engine(&self) -> Result<EngineType> {
|
||||
if self.universal || self.jit {
|
||||
Ok(EngineType::Universal)
|
||||
} else if self.dylib || self.native {
|
||||
Ok(EngineType::Dylib)
|
||||
} else if self.staticlib || self.object_file {
|
||||
Ok(EngineType::Staticlib)
|
||||
} else {
|
||||
// Auto mode, we choose the best engine for that platform
|
||||
if cfg!(feature = "universal") {
|
||||
Ok(EngineType::Universal)
|
||||
} else if cfg!(feature = "dylib") {
|
||||
Ok(EngineType::Dylib)
|
||||
} else if cfg!(feature = "staticlib") {
|
||||
Ok(EngineType::Staticlib)
|
||||
} else {
|
||||
@ -439,13 +417,11 @@ impl StoreOptions {
|
||||
EngineType::Universal => {
|
||||
Arc::new(wasmer_engine_universal::Universal::headless().engine())
|
||||
}
|
||||
#[cfg(feature = "dylib")]
|
||||
EngineType::Dylib => Arc::new(wasmer_engine_dylib::Dylib::headless().engine()),
|
||||
#[cfg(feature = "staticlib")]
|
||||
EngineType::Staticlib => {
|
||||
Arc::new(wasmer_engine_staticlib::Staticlib::headless().engine())
|
||||
}
|
||||
#[cfg(not(all(feature = "universal", feature = "dylib", feature = "staticlib")))]
|
||||
#[cfg(not(all(feature = "universal", feature = "staticlib")))]
|
||||
engine => bail!(
|
||||
"The `{}` engine is not included in this binary.",
|
||||
engine.to_string()
|
||||
|
@ -135,7 +135,7 @@ impl Cranelift {
|
||||
flags.enable("is_pic").expect("should be a valid flag");
|
||||
}
|
||||
|
||||
// We set up libcall trampolines in engine-dylib and engine-universal.
|
||||
// We set up libcall trampolines in engine-universal.
|
||||
// These trampolines are always reachable through short jumps.
|
||||
flags
|
||||
.enable("use_colocated_libcalls")
|
||||
|
@ -1,38 +0,0 @@
|
||||
[package]
|
||||
name = "wasmer-engine-dylib"
|
||||
version = "2.3.0"
|
||||
description = "Wasmer Dylib Engine"
|
||||
categories = ["wasm"]
|
||||
keywords = ["wasm", "webassembly", "engine", "dylib"]
|
||||
authors = ["Wasmer Engineering Team <engineering@wasmer.io>"]
|
||||
repository = "https://github.com/wasmerio/wasmer"
|
||||
license = "MIT"
|
||||
readme = "README.md"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
wasmer-artifact = { path = "../artifact", version = "=2.3.0" }
|
||||
wasmer-types = { path = "../types", version = "=2.3.0" }
|
||||
wasmer-compiler = { path = "../compiler", version = "=2.3.0" }
|
||||
wasmer-vm = { path = "../vm", version = "=2.3.0" }
|
||||
wasmer-engine = { path = "../engine", version = "=2.3.0" }
|
||||
wasmer-object = { path = "../object", version = "=2.3.0" }
|
||||
serde = { version = "1.0", features = ["derive", "rc"] }
|
||||
cfg-if = "1.0"
|
||||
tracing = { version = "0.1", features = ["log"] }
|
||||
leb128 = "0.2"
|
||||
libloading = "0.7"
|
||||
tempfile = "3.1"
|
||||
which = "4.0"
|
||||
rkyv = { version = "0.7.38", features = ["indexmap"] }
|
||||
enumset = "1.0"
|
||||
enum-iterator = "0.7.0"
|
||||
object = { version = "0.28.3", default-features = false, features = ["write"] }
|
||||
|
||||
[features]
|
||||
# Enable the `compiler` feature if you want the engine to compile
|
||||
# and not be only on headless mode.
|
||||
compiler = ["wasmer-compiler/translator"]
|
||||
|
||||
[badges]
|
||||
maintenance = { status = "actively-developed" }
|
@ -1,60 +0,0 @@
|
||||
# `wasmer-engine-dylib` [](https://github.com/wasmerio/wasmer/actions?query=workflow%3Abuild) [](https://slack.wasmer.io) [](https://github.com/wasmerio/wasmer/blob/master/LICENSE)
|
||||
|
||||
The Wasmer Dylib engine is usable with any compiler implementation
|
||||
based on [`wasmer-compiler`] that is able to emit
|
||||
[Position-Independent Code][PIC] (PIC).
|
||||
|
||||
After the compiler generates the machine code for the functions, the
|
||||
Dylib Engine generates a shared object file and links it via [`dlsym`]
|
||||
so it can be usable by the [`wasmer`] API.
|
||||
|
||||
This allows Wasmer to achieve *blazing fast* **native startup times**.
|
||||
|
||||
*Note: you can find a [full working example using the Dylib engine
|
||||
here][example].*
|
||||
|
||||
### Difference with `wasmer-engine-universal`
|
||||
|
||||
The Dylib Engine and Universal Engine mainly differ on how the Modules
|
||||
are loaded/stored. Using the same compilers, both will have the same
|
||||
runtime speed.
|
||||
|
||||
However, the Dylib Engine uses the Operating System shared library
|
||||
loader (via `dlopen`) and as such is able to achieve a much faster
|
||||
startup time when deserializing a serialized `Module`.
|
||||
|
||||
## Requirements
|
||||
|
||||
The `wasmer-engine-dylib` crate requires a linker available on
|
||||
your system to generate the shared object file.
|
||||
|
||||
We recommend having [`gcc`] or [`clang`] installed.
|
||||
|
||||
> Note: when **cross-compiling** to other targets, `clang` will be the
|
||||
> default command used for compiling.
|
||||
|
||||
You can install LLVM (that provides `clang`) 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][llvm-pre-built].
|
||||
|
||||
|
||||
[`wasmer-compiler`]: https://github.com/wasmerio/wasmer/tree/master/lib/compiler
|
||||
[PIC]: https://en.wikipedia.org/wiki/Position-independent_code
|
||||
[`dlsym`]: https://www.freebsd.org/cgi/man.cgi?query=dlsym
|
||||
[`wasmer`]: https://github.com/wasmerio/wasmer/tree/master/lib/api
|
||||
[example]: https://github.com/wasmerio/wasmer/blob/master/examples/engine_dylib.rs
|
||||
[`gcc`]: https://gcc.gnu.org/
|
||||
[`clang`]: https://clang.llvm.org/
|
||||
[llvm-pre-built]: https://releases.llvm.org/download.html
|
@ -1,897 +0,0 @@
|
||||
//! Define `DylibArtifact` to allow compiling and instantiating
|
||||
//! to be done as separate steps.
|
||||
|
||||
use crate::engine::{DylibEngine, DylibEngineInner};
|
||||
use crate::serialize::ModuleMetadata;
|
||||
use crate::trampoline::{emit_trampolines, fill_trampoline_table, WASMER_TRAMPOLINES_SYMBOL};
|
||||
use enumset::EnumSet;
|
||||
use libloading::{Library, Symbol as LibrarySymbol};
|
||||
use object::{write::CoffExportStyle, BinaryFormat};
|
||||
use std::error::Error;
|
||||
use std::fs::{self, File};
|
||||
use std::io::{Read, Write};
|
||||
use std::path::{Path, PathBuf};
|
||||
#[cfg(feature = "compiler")]
|
||||
use std::process::Command;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use tempfile::NamedTempFile;
|
||||
use tracing::log::error;
|
||||
#[cfg(feature = "compiler")]
|
||||
use tracing::trace;
|
||||
use wasmer_artifact::ArtifactCreate;
|
||||
use wasmer_compiler::{
|
||||
Architecture, CompileError, CompiledFunctionFrameInfo, CpuFeature, Features,
|
||||
FunctionAddressMap, OperatingSystem, Symbol, SymbolRegistry, Triple,
|
||||
};
|
||||
#[cfg(feature = "compiler")]
|
||||
use wasmer_compiler::{
|
||||
CompileModuleInfo, Compiler, FunctionBodyData, ModuleEnvironment, ModuleMiddlewareChain,
|
||||
ModuleTranslationState,
|
||||
};
|
||||
use wasmer_engine::{
|
||||
register_frame_info, Artifact, DeserializeError, FunctionExtent, GlobalFrameInfoRegistration,
|
||||
InstantiationError, MetadataHeader, SerializeError,
|
||||
};
|
||||
#[cfg(feature = "compiler")]
|
||||
use wasmer_engine::{Engine, Tunables};
|
||||
#[cfg(feature = "compiler")]
|
||||
use wasmer_object::{emit_compilation, emit_data, get_object_for_target};
|
||||
use wasmer_types::entity::{BoxedSlice, PrimaryMap};
|
||||
#[cfg(feature = "compiler")]
|
||||
use wasmer_types::DataInitializer;
|
||||
use wasmer_types::{
|
||||
FunctionIndex, LocalFunctionIndex, MemoryIndex, ModuleInfo, OwnedDataInitializer,
|
||||
SignatureIndex, TableIndex,
|
||||
};
|
||||
use wasmer_vm::{
|
||||
FuncDataRegistry, FunctionBodyPtr, MemoryStyle, TableStyle, VMFunctionBody,
|
||||
VMSharedSignatureIndex, VMTrampoline,
|
||||
};
|
||||
|
||||
/// A compiled Wasm module, ready to be instantiated.
|
||||
pub struct DylibArtifact {
|
||||
dylib_path: PathBuf,
|
||||
is_temporary: bool,
|
||||
metadata: ModuleMetadata,
|
||||
finished_functions: BoxedSlice<LocalFunctionIndex, FunctionBodyPtr>,
|
||||
finished_function_call_trampolines: BoxedSlice<SignatureIndex, VMTrampoline>,
|
||||
finished_dynamic_function_trampolines: BoxedSlice<FunctionIndex, FunctionBodyPtr>,
|
||||
func_data_registry: Arc<FuncDataRegistry>,
|
||||
signatures: BoxedSlice<SignatureIndex, VMSharedSignatureIndex>,
|
||||
frame_info_registration: Mutex<Option<GlobalFrameInfoRegistration>>,
|
||||
}
|
||||
|
||||
impl Drop for DylibArtifact {
|
||||
fn drop(&mut self) {
|
||||
if self.is_temporary {
|
||||
if let Err(err) = std::fs::remove_file(&self.dylib_path) {
|
||||
error!("cannot delete the temporary dylib artifact: {}", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn to_compile_error(err: impl Error) -> CompileError {
|
||||
CompileError::Codegen(err.to_string())
|
||||
}
|
||||
|
||||
const WASMER_METADATA_SYMBOL: &[u8] = b"WASMER_METADATA";
|
||||
|
||||
impl DylibArtifact {
|
||||
// Mach-O header in iOS/Mac
|
||||
#[allow(dead_code)]
|
||||
const MAGIC_HEADER_MH_CIGAM_64: &'static [u8] = &[207, 250, 237, 254];
|
||||
|
||||
// ELF Magic header for Linux (32 bit)
|
||||
#[allow(dead_code)]
|
||||
const MAGIC_HEADER_ELF_32: &'static [u8] = &[0x7f, b'E', b'L', b'F', 1];
|
||||
|
||||
// ELF Magic header for Linux (64 bit)
|
||||
#[allow(dead_code)]
|
||||
const MAGIC_HEADER_ELF_64: &'static [u8] = &[0x7f, b'E', b'L', b'F', 2];
|
||||
|
||||
// COFF Magic header for Windows (64 bit)
|
||||
#[allow(dead_code)]
|
||||
const MAGIC_HEADER_COFF_64: &'static [u8] = &[b'M', b'Z'];
|
||||
|
||||
/// Check if the provided bytes look like `DylibArtifact`.
|
||||
///
|
||||
/// This means, if the bytes look like a shared object file in the target
|
||||
/// system.
|
||||
pub fn is_deserializable(bytes: &[u8]) -> bool {
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(all(target_pointer_width = "64", target_vendor="apple"))] {
|
||||
bytes.starts_with(Self::MAGIC_HEADER_MH_CIGAM_64)
|
||||
}
|
||||
else if #[cfg(all(target_pointer_width = "64", target_os="linux"))] {
|
||||
bytes.starts_with(Self::MAGIC_HEADER_ELF_64)
|
||||
}
|
||||
else if #[cfg(all(target_pointer_width = "32", target_os="linux"))] {
|
||||
bytes.starts_with(Self::MAGIC_HEADER_ELF_32)
|
||||
}
|
||||
else if #[cfg(all(target_pointer_width = "64", target_os="windows"))] {
|
||||
bytes.starts_with(Self::MAGIC_HEADER_COFF_64)
|
||||
}
|
||||
else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Generate a compilation
|
||||
#[cfg(feature = "compiler")]
|
||||
#[allow(clippy::type_complexity)]
|
||||
fn generate_metadata<'data>(
|
||||
data: &'data [u8],
|
||||
features: &Features,
|
||||
compiler: &dyn Compiler,
|
||||
tunables: &dyn Tunables,
|
||||
) -> Result<
|
||||
(
|
||||
CompileModuleInfo,
|
||||
PrimaryMap<LocalFunctionIndex, FunctionBodyData<'data>>,
|
||||
Vec<DataInitializer<'data>>,
|
||||
Option<ModuleTranslationState>,
|
||||
),
|
||||
CompileError,
|
||||
> {
|
||||
let environ = ModuleEnvironment::new();
|
||||
let translation = environ.translate(data).map_err(CompileError::Wasm)?;
|
||||
|
||||
// We try to apply the middleware first
|
||||
let mut module = translation.module;
|
||||
let middlewares = compiler.get_middlewares();
|
||||
middlewares.apply_on_module_info(&mut module);
|
||||
|
||||
let memory_styles: PrimaryMap<MemoryIndex, MemoryStyle> = module
|
||||
.memories
|
||||
.values()
|
||||
.map(|memory_type| tunables.memory_style(memory_type))
|
||||
.collect();
|
||||
let table_styles: PrimaryMap<TableIndex, TableStyle> = module
|
||||
.tables
|
||||
.values()
|
||||
.map(|table_type| tunables.table_style(table_type))
|
||||
.collect();
|
||||
|
||||
let compile_info = CompileModuleInfo {
|
||||
module: Arc::new(module),
|
||||
features: features.clone(),
|
||||
memory_styles,
|
||||
table_styles,
|
||||
};
|
||||
Ok((
|
||||
compile_info,
|
||||
translation.function_body_inputs,
|
||||
translation.data_initializers,
|
||||
translation.module_translation_state,
|
||||
))
|
||||
}
|
||||
|
||||
/// Compile a data buffer into a `DylibArtifact`, which may
|
||||
/// then be instantiated.
|
||||
#[cfg(feature = "compiler")]
|
||||
pub fn new(
|
||||
engine: &DylibEngine,
|
||||
data: &[u8],
|
||||
tunables: &dyn Tunables,
|
||||
) -> Result<Self, CompileError> {
|
||||
let mut engine_inner = engine.inner_mut();
|
||||
let target = engine.target();
|
||||
let compiler = engine_inner.compiler()?;
|
||||
let (compile_info, function_body_inputs, data_initializers, module_translation) =
|
||||
Self::generate_metadata(data, engine_inner.features(), compiler, tunables)?;
|
||||
|
||||
let data_initializers = data_initializers
|
||||
.iter()
|
||||
.map(OwnedDataInitializer::new)
|
||||
.collect::<Vec<_>>()
|
||||
.into_boxed_slice();
|
||||
|
||||
let target_triple = target.triple();
|
||||
|
||||
/*
|
||||
// We construct the function body lengths
|
||||
let function_body_lengths = compilation
|
||||
.get_function_bodies()
|
||||
.values()
|
||||
.map(|function_body| function_body.body.len() as u64)
|
||||
.map(|_function_body| 0u64)
|
||||
.collect::<PrimaryMap<LocalFunctionIndex, u64>>();
|
||||
*/
|
||||
|
||||
// TODO: we currently supply all-zero function body lengths.
|
||||
// We don't know the lengths until they're compiled, yet we have to
|
||||
// supply the metadata as an input to the compile.
|
||||
let function_body_lengths = function_body_inputs
|
||||
.keys()
|
||||
.map(|_function_body| 0u64)
|
||||
.collect::<PrimaryMap<LocalFunctionIndex, u64>>();
|
||||
|
||||
let function_frame_info = None;
|
||||
|
||||
let mut metadata = ModuleMetadata {
|
||||
compile_info,
|
||||
function_frame_info,
|
||||
prefix: engine_inner.get_prefix(data),
|
||||
data_initializers,
|
||||
function_body_lengths,
|
||||
cpu_features: target.cpu_features().as_u64(),
|
||||
};
|
||||
|
||||
let serialized_data = metadata.serialize()?;
|
||||
|
||||
let mut metadata_binary = vec![];
|
||||
metadata_binary.extend(MetadataHeader::new(serialized_data.len()).into_bytes());
|
||||
metadata_binary.extend(serialized_data);
|
||||
|
||||
let (compile_info, symbol_registry) = metadata.split();
|
||||
|
||||
let maybe_obj_bytes = compiler.experimental_native_compile_module(
|
||||
target,
|
||||
compile_info,
|
||||
module_translation.as_ref().unwrap(),
|
||||
&function_body_inputs,
|
||||
&symbol_registry,
|
||||
&metadata_binary,
|
||||
);
|
||||
|
||||
let mut extra_filepath = None;
|
||||
let filepath = match maybe_obj_bytes {
|
||||
Some(obj_bytes) => {
|
||||
extra_filepath = {
|
||||
// Create a separate object file with the trampolines.
|
||||
let mut obj = get_object_for_target(target_triple).map_err(to_compile_error)?;
|
||||
emit_trampolines(&mut obj, engine.target());
|
||||
if obj.format() == BinaryFormat::Coff {
|
||||
obj.add_coff_exports(CoffExportStyle::Gnu);
|
||||
}
|
||||
let file = tempfile::Builder::new()
|
||||
.prefix("wasmer_dylib_")
|
||||
.suffix(".o")
|
||||
.tempfile()
|
||||
.map_err(to_compile_error)?;
|
||||
|
||||
// Re-open it.
|
||||
let (mut file, filepath) = file.keep().map_err(to_compile_error)?;
|
||||
let obj_bytes = obj.write().map_err(to_compile_error)?;
|
||||
file.write_all(&obj_bytes).map_err(to_compile_error)?;
|
||||
Some(filepath)
|
||||
};
|
||||
|
||||
// Write the object file generated by the compiler.
|
||||
let obj_bytes = obj_bytes?;
|
||||
let file = tempfile::Builder::new()
|
||||
.prefix("wasmer_dylib_")
|
||||
.suffix(".o")
|
||||
.tempfile()
|
||||
.map_err(to_compile_error)?;
|
||||
|
||||
// Re-open it.
|
||||
let (mut file, filepath) = file.keep().map_err(to_compile_error)?;
|
||||
file.write_all(&obj_bytes).map_err(to_compile_error)?;
|
||||
filepath
|
||||
}
|
||||
None => {
|
||||
let compilation = compiler.compile_module(
|
||||
target,
|
||||
compile_info,
|
||||
module_translation.as_ref().unwrap(),
|
||||
function_body_inputs,
|
||||
)?;
|
||||
let mut obj = get_object_for_target(target_triple).map_err(to_compile_error)?;
|
||||
emit_trampolines(&mut obj, engine.target());
|
||||
emit_data(
|
||||
&mut obj,
|
||||
WASMER_METADATA_SYMBOL,
|
||||
&metadata_binary,
|
||||
MetadataHeader::ALIGN as u64,
|
||||
)
|
||||
.map_err(to_compile_error)?;
|
||||
|
||||
let frame_info = compilation.get_frame_info();
|
||||
|
||||
emit_compilation(&mut obj, compilation, &symbol_registry, target_triple)
|
||||
.map_err(to_compile_error)?;
|
||||
if obj.format() == BinaryFormat::Coff {
|
||||
obj.add_coff_exports(CoffExportStyle::Gnu);
|
||||
}
|
||||
let file = tempfile::Builder::new()
|
||||
.prefix("wasmer_dylib_")
|
||||
.suffix(".o")
|
||||
.tempfile()
|
||||
.map_err(to_compile_error)?;
|
||||
|
||||
metadata.function_frame_info = Some(frame_info);
|
||||
|
||||
// Re-open it.
|
||||
let (mut file, filepath) = file.keep().map_err(to_compile_error)?;
|
||||
let obj_bytes = obj.write().map_err(to_compile_error)?;
|
||||
|
||||
file.write_all(&obj_bytes).map_err(to_compile_error)?;
|
||||
filepath
|
||||
}
|
||||
};
|
||||
|
||||
let output_filepath = {
|
||||
let suffix = format!(".{}", Self::get_default_extension(target_triple));
|
||||
let shared_file = tempfile::Builder::new()
|
||||
.prefix("wasmer_dylib_")
|
||||
.suffix(&suffix)
|
||||
.tempfile()
|
||||
.map_err(to_compile_error)?;
|
||||
shared_file
|
||||
.into_temp_path()
|
||||
.keep()
|
||||
.map_err(to_compile_error)?
|
||||
};
|
||||
|
||||
let is_cross_compiling = engine_inner.is_cross_compiling();
|
||||
let target_triple_str = {
|
||||
let into_str = target_triple.to_string();
|
||||
// We have to adapt the target triple string, because otherwise
|
||||
// Apple's clang will not recognize it.
|
||||
if into_str == "aarch64-apple-darwin" {
|
||||
"arm64-apple-darwin".to_string()
|
||||
} else {
|
||||
into_str
|
||||
}
|
||||
};
|
||||
|
||||
// Set 'isysroot' clang flag if compiling to iOS target
|
||||
let ios_compile_target = target_triple.operating_system == OperatingSystem::Ios;
|
||||
let ios_sdk_flag = {
|
||||
if ios_compile_target {
|
||||
if target_triple.architecture == Architecture::X86_64 {
|
||||
"-isysroot/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk"
|
||||
} else {
|
||||
"-isysroot/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk"
|
||||
}
|
||||
} else {
|
||||
""
|
||||
}
|
||||
};
|
||||
let ios_sdk_lib = {
|
||||
if ios_compile_target {
|
||||
"-lSystem"
|
||||
} else {
|
||||
""
|
||||
}
|
||||
};
|
||||
|
||||
// Get the location of the 'ld' linker for clang
|
||||
let fuse_linker = {
|
||||
let ld_install = which::which("ld");
|
||||
match (ios_compile_target, ld_install) {
|
||||
(true, Ok(ld_install)) => ld_install.into_os_string().into_string().unwrap(),
|
||||
_ => "lld".to_string(),
|
||||
}
|
||||
};
|
||||
|
||||
let cross_compiling_args: Vec<String> = if is_cross_compiling {
|
||||
vec![
|
||||
format!("--target={}", target_triple_str),
|
||||
format!("-fuse-ld={}", fuse_linker),
|
||||
"-nodefaultlibs".to_string(),
|
||||
"-nostdlib".to_string(),
|
||||
ios_sdk_flag.to_string(),
|
||||
ios_sdk_lib.to_string(),
|
||||
]
|
||||
} else {
|
||||
// We are explicit on the target when the host system is
|
||||
// Apple Silicon, otherwise compilation fails.
|
||||
if target_triple_str == "arm64-apple-darwin" {
|
||||
vec![format!("--target={}", target_triple_str)]
|
||||
} else {
|
||||
vec![]
|
||||
}
|
||||
};
|
||||
let target_args = match (target_triple.operating_system, is_cross_compiling) {
|
||||
(OperatingSystem::Windows, true) => vec!["-Wl,/force:unresolved,/noentry"],
|
||||
(OperatingSystem::Windows, false) => vec!["-Wl,-undefined,dynamic_lookup"],
|
||||
_ => vec!["-nostartfiles", "-Wl,-undefined,dynamic_lookup"],
|
||||
};
|
||||
trace!(
|
||||
"Compiling for target {} from host {}",
|
||||
target_triple_str,
|
||||
Triple::host().to_string(),
|
||||
);
|
||||
|
||||
let linker = engine_inner.linker().executable();
|
||||
let output = Command::new(linker)
|
||||
.arg(&filepath)
|
||||
.args(&extra_filepath)
|
||||
.arg("-o")
|
||||
.arg(&output_filepath)
|
||||
.args(&target_args)
|
||||
// .args(&wasmer_symbols)
|
||||
.arg("-shared")
|
||||
.args(&cross_compiling_args)
|
||||
.arg("-v")
|
||||
.output()
|
||||
.map_err(to_compile_error);
|
||||
|
||||
if fs::metadata(&filepath).is_ok() {
|
||||
fs::remove_file(filepath).map_err(to_compile_error)?;
|
||||
}
|
||||
if let Some(filepath) = extra_filepath {
|
||||
if fs::metadata(&filepath).is_ok() {
|
||||
fs::remove_file(filepath).map_err(to_compile_error)?;
|
||||
}
|
||||
}
|
||||
|
||||
let output = output?;
|
||||
|
||||
if !output.status.success() {
|
||||
return Err(CompileError::Codegen(format!(
|
||||
"Shared object file generator failed with:\nstderr:{}\nstdout:{}",
|
||||
String::from_utf8_lossy(&output.stderr).trim_end(),
|
||||
String::from_utf8_lossy(&output.stdout).trim_end()
|
||||
)));
|
||||
}
|
||||
|
||||
trace!("gcc command result {:?}", output);
|
||||
|
||||
let mut artifact = if is_cross_compiling {
|
||||
Self::from_parts_crosscompiled(metadata, output_filepath)
|
||||
} else {
|
||||
let lib = unsafe { Library::new(&output_filepath).map_err(to_compile_error)? };
|
||||
Self::from_parts(&mut engine_inner, metadata, output_filepath, lib)
|
||||
}?;
|
||||
artifact.is_temporary = true;
|
||||
|
||||
Ok(artifact)
|
||||
}
|
||||
|
||||
/// Get the default extension when serializing this artifact
|
||||
pub fn get_default_extension(triple: &Triple) -> &'static str {
|
||||
match triple.operating_system {
|
||||
OperatingSystem::Windows => "dll",
|
||||
OperatingSystem::Darwin | OperatingSystem::Ios | OperatingSystem::MacOSX { .. } => {
|
||||
"dylib"
|
||||
}
|
||||
_ => "so",
|
||||
}
|
||||
}
|
||||
|
||||
/// Construct a `DylibArtifact` from component parts.
|
||||
pub fn from_parts_crosscompiled(
|
||||
metadata: ModuleMetadata,
|
||||
dylib_path: PathBuf,
|
||||
) -> Result<Self, CompileError> {
|
||||
let finished_functions: PrimaryMap<LocalFunctionIndex, FunctionBodyPtr> = PrimaryMap::new();
|
||||
let finished_function_call_trampolines: PrimaryMap<SignatureIndex, VMTrampoline> =
|
||||
PrimaryMap::new();
|
||||
let finished_dynamic_function_trampolines: PrimaryMap<FunctionIndex, FunctionBodyPtr> =
|
||||
PrimaryMap::new();
|
||||
let signatures: PrimaryMap<SignatureIndex, VMSharedSignatureIndex> = PrimaryMap::new();
|
||||
Ok(Self {
|
||||
dylib_path,
|
||||
is_temporary: false,
|
||||
metadata,
|
||||
finished_functions: finished_functions.into_boxed_slice(),
|
||||
finished_function_call_trampolines: finished_function_call_trampolines
|
||||
.into_boxed_slice(),
|
||||
finished_dynamic_function_trampolines: finished_dynamic_function_trampolines
|
||||
.into_boxed_slice(),
|
||||
func_data_registry: Arc::new(FuncDataRegistry::new()),
|
||||
signatures: signatures.into_boxed_slice(),
|
||||
frame_info_registration: Mutex::new(None),
|
||||
})
|
||||
}
|
||||
|
||||
/// Construct a `DylibArtifact` from component parts.
|
||||
pub fn from_parts(
|
||||
engine_inner: &mut DylibEngineInner,
|
||||
metadata: ModuleMetadata,
|
||||
dylib_path: PathBuf,
|
||||
lib: Library,
|
||||
) -> Result<Self, CompileError> {
|
||||
unsafe {
|
||||
let trampolines_symbol: LibrarySymbol<usize> = lib
|
||||
.get(WASMER_TRAMPOLINES_SYMBOL)
|
||||
.expect("missing WASMER_TRAMPOLINES symbol");
|
||||
fill_trampoline_table(trampolines_symbol.into_raw().into_raw() as *mut usize);
|
||||
}
|
||||
|
||||
let mut finished_functions: PrimaryMap<LocalFunctionIndex, FunctionBodyPtr> =
|
||||
PrimaryMap::new();
|
||||
for (function_local_index, _function_len) in metadata.function_body_lengths.iter() {
|
||||
let function_name = metadata
|
||||
.get_symbol_registry()
|
||||
.symbol_to_name(Symbol::LocalFunction(function_local_index));
|
||||
unsafe {
|
||||
// We use a fake function signature `fn()` because we just
|
||||
// want to get the function address.
|
||||
let func: LibrarySymbol<unsafe extern "C" fn()> = lib
|
||||
.get(function_name.as_bytes())
|
||||
.map_err(to_compile_error)?;
|
||||
finished_functions.push(FunctionBodyPtr(
|
||||
func.into_raw().into_raw() as *const VMFunctionBody
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
// Retrieve function call trampolines
|
||||
let mut finished_function_call_trampolines: PrimaryMap<SignatureIndex, VMTrampoline> =
|
||||
PrimaryMap::with_capacity(metadata.compile_info.module.signatures.len());
|
||||
for sig_index in metadata.compile_info.module.signatures.keys() {
|
||||
let function_name = metadata
|
||||
.get_symbol_registry()
|
||||
.symbol_to_name(Symbol::FunctionCallTrampoline(sig_index));
|
||||
unsafe {
|
||||
let trampoline: LibrarySymbol<VMTrampoline> = lib
|
||||
.get(function_name.as_bytes())
|
||||
.map_err(to_compile_error)?;
|
||||
let raw = *trampoline.into_raw();
|
||||
finished_function_call_trampolines.push(raw);
|
||||
}
|
||||
}
|
||||
|
||||
// Retrieve dynamic function trampolines (only for imported functions)
|
||||
let mut finished_dynamic_function_trampolines: PrimaryMap<FunctionIndex, FunctionBodyPtr> =
|
||||
PrimaryMap::with_capacity(metadata.compile_info.module.num_imported_functions);
|
||||
for func_index in metadata
|
||||
.compile_info
|
||||
.module
|
||||
.functions
|
||||
.keys()
|
||||
.take(metadata.compile_info.module.num_imported_functions)
|
||||
{
|
||||
let function_name = metadata
|
||||
.get_symbol_registry()
|
||||
.symbol_to_name(Symbol::DynamicFunctionTrampoline(func_index));
|
||||
unsafe {
|
||||
let trampoline: LibrarySymbol<unsafe extern "C" fn()> = lib
|
||||
.get(function_name.as_bytes())
|
||||
.map_err(to_compile_error)?;
|
||||
finished_dynamic_function_trampolines.push(FunctionBodyPtr(
|
||||
trampoline.into_raw().into_raw() as *const VMFunctionBody,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
// Compute indices into the shared signature table.
|
||||
let signatures = {
|
||||
metadata
|
||||
.compile_info
|
||||
.module
|
||||
.signatures
|
||||
.values()
|
||||
.map(|sig| engine_inner.signatures().register(sig))
|
||||
.collect::<PrimaryMap<_, _>>()
|
||||
};
|
||||
|
||||
engine_inner.add_library(lib);
|
||||
|
||||
Ok(Self {
|
||||
dylib_path,
|
||||
is_temporary: false,
|
||||
metadata,
|
||||
finished_functions: finished_functions.into_boxed_slice(),
|
||||
finished_function_call_trampolines: finished_function_call_trampolines
|
||||
.into_boxed_slice(),
|
||||
finished_dynamic_function_trampolines: finished_dynamic_function_trampolines
|
||||
.into_boxed_slice(),
|
||||
func_data_registry: engine_inner.func_data().clone(),
|
||||
signatures: signatures.into_boxed_slice(),
|
||||
frame_info_registration: Mutex::new(None),
|
||||
})
|
||||
}
|
||||
|
||||
/// Compile a data buffer into a `DylibArtifact`, which may
|
||||
/// then be instantiated.
|
||||
#[cfg(not(feature = "compiler"))]
|
||||
pub fn new(_engine: &DylibEngine, _data: &[u8]) -> Result<Self, CompileError> {
|
||||
Err(CompileError::Codegen(
|
||||
"Compilation is not enabled in the engine".to_string(),
|
||||
))
|
||||
}
|
||||
|
||||
/// Deserialize a `DylibArtifact` from bytes.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The bytes must represent a serialized WebAssembly module.
|
||||
pub unsafe fn deserialize(
|
||||
engine: &DylibEngine,
|
||||
bytes: &[u8],
|
||||
) -> Result<Self, DeserializeError> {
|
||||
if !Self::is_deserializable(bytes) {
|
||||
return Err(DeserializeError::Incompatible(
|
||||
"The provided bytes are not in any native format Wasmer can understand".to_string(),
|
||||
));
|
||||
}
|
||||
// Dump the bytes into a file, so we can read it with our `dlopen`
|
||||
let named_file = NamedTempFile::new()?;
|
||||
let (mut file, path) = named_file.keep().map_err(|e| e.error)?;
|
||||
file.write_all(bytes)?;
|
||||
// We already checked for the header, so we don't need
|
||||
// to check again.
|
||||
let mut artifact = Self::deserialize_from_file_unchecked(engine, &path)?;
|
||||
artifact.is_temporary = true;
|
||||
|
||||
Ok(artifact)
|
||||
}
|
||||
|
||||
/// Deserialize a `DylibArtifact` from a file path.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The file's content must represent a serialized WebAssembly module.
|
||||
pub unsafe fn deserialize_from_file(
|
||||
engine: &DylibEngine,
|
||||
path: &Path,
|
||||
) -> Result<Self, DeserializeError> {
|
||||
let mut file = File::open(&path)?;
|
||||
let mut buffer = [0; 5];
|
||||
// read up to 5 bytes
|
||||
file.read_exact(&mut buffer)?;
|
||||
if !Self::is_deserializable(&buffer) {
|
||||
return Err(DeserializeError::Incompatible(
|
||||
"The provided bytes are not in any native format Wasmer can understand".to_string(),
|
||||
));
|
||||
}
|
||||
Self::deserialize_from_file_unchecked(engine, path)
|
||||
}
|
||||
|
||||
/// Deserialize a `DylibArtifact` from a file path (unchecked).
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The file's content must represent a serialized WebAssembly module.
|
||||
pub unsafe fn deserialize_from_file_unchecked(
|
||||
engine: &DylibEngine,
|
||||
path: &Path,
|
||||
) -> Result<Self, DeserializeError> {
|
||||
let lib = Library::new(&path).map_err(|e| {
|
||||
DeserializeError::CorruptedBinary(format!("Library loading failed: {}", e))
|
||||
})?;
|
||||
let shared_path: PathBuf = PathBuf::from(path);
|
||||
let metadata_symbol: LibrarySymbol<*mut [u8; MetadataHeader::LEN]> =
|
||||
lib.get(WASMER_METADATA_SYMBOL).map_err(|e| {
|
||||
DeserializeError::CorruptedBinary(format!(
|
||||
"The provided object file doesn't seem to be generated by Wasmer: {}",
|
||||
e
|
||||
))
|
||||
})?;
|
||||
use std::slice;
|
||||
|
||||
let metadata = &**metadata_symbol;
|
||||
let metadata_len = MetadataHeader::parse(metadata)?;
|
||||
let metadata_slice: &'static [u8] =
|
||||
slice::from_raw_parts(metadata.as_ptr().add(MetadataHeader::LEN), metadata_len);
|
||||
|
||||
let metadata = ModuleMetadata::deserialize(metadata_slice)?;
|
||||
|
||||
let mut engine_inner = engine.inner_mut();
|
||||
|
||||
Self::from_parts(&mut engine_inner, metadata, shared_path, lib)
|
||||
.map_err(DeserializeError::Compiler)
|
||||
}
|
||||
|
||||
/// Used in test deserialize metadata is correct
|
||||
pub fn metadata(&self) -> &ModuleMetadata {
|
||||
&self.metadata
|
||||
}
|
||||
}
|
||||
|
||||
impl ArtifactCreate for DylibArtifact {
|
||||
fn module(&self) -> Arc<ModuleInfo> {
|
||||
self.metadata.compile_info.module.clone()
|
||||
}
|
||||
|
||||
fn module_ref(&self) -> &ModuleInfo {
|
||||
&self.metadata.compile_info.module
|
||||
}
|
||||
|
||||
fn module_mut(&mut self) -> Option<&mut ModuleInfo> {
|
||||
Arc::get_mut(&mut self.metadata.compile_info.module)
|
||||
}
|
||||
|
||||
fn features(&self) -> &Features {
|
||||
&self.metadata.compile_info.features
|
||||
}
|
||||
|
||||
fn cpu_features(&self) -> enumset::EnumSet<CpuFeature> {
|
||||
EnumSet::from_u64(self.metadata.cpu_features)
|
||||
}
|
||||
|
||||
fn data_initializers(&self) -> &[OwnedDataInitializer] {
|
||||
&*self.metadata.data_initializers
|
||||
}
|
||||
|
||||
fn memory_styles(&self) -> &PrimaryMap<MemoryIndex, MemoryStyle> {
|
||||
&self.metadata.compile_info.memory_styles
|
||||
}
|
||||
|
||||
fn table_styles(&self) -> &PrimaryMap<TableIndex, TableStyle> {
|
||||
&self.metadata.compile_info.table_styles
|
||||
}
|
||||
|
||||
/// Serialize a `DylibArtifact`.
|
||||
fn serialize(&self) -> Result<Vec<u8>, SerializeError> {
|
||||
Ok(std::fs::read(&self.dylib_path)?)
|
||||
}
|
||||
|
||||
/// Serialize a `DylibArtifact` to a portable file
|
||||
#[cfg(feature = "compiler")]
|
||||
fn serialize_to_file(&self, path: &Path) -> Result<(), SerializeError> {
|
||||
let serialized = self.serialize()?;
|
||||
std::fs::write(&path, serialized)?;
|
||||
|
||||
/*
|
||||
When you write the artifact to a new file it still has the 'Mach-O Identifier'
|
||||
of the original file, and so this can causes linker issues when adding
|
||||
the new file to an XCode project.
|
||||
|
||||
The below code renames the ID of the file so that it references itself through
|
||||
an @executable_path prefix. Basically it tells XCode to find this file
|
||||
inside of the projects' list of 'linked executables'.
|
||||
|
||||
You need to be running MacOS for the following to actually work though.
|
||||
*/
|
||||
let has_extension = path.extension().is_some();
|
||||
if has_extension && path.extension().unwrap() == "dylib" {
|
||||
let filename = path.file_name().unwrap().to_str().unwrap();
|
||||
let parent_dir = path.parent().unwrap();
|
||||
let absolute_path = std::fs::canonicalize(&parent_dir)
|
||||
.unwrap()
|
||||
.into_os_string()
|
||||
.into_string()
|
||||
.unwrap();
|
||||
|
||||
Command::new("install_name_tool")
|
||||
.arg("-id")
|
||||
.arg(format!("@executable_path/{}", &filename))
|
||||
.arg(&filename)
|
||||
.current_dir(&absolute_path)
|
||||
.output()?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
impl Artifact for DylibArtifact {
|
||||
fn register_frame_info(&self) {
|
||||
let mut info = self.frame_info_registration.lock().unwrap();
|
||||
|
||||
if info.is_some() {
|
||||
return;
|
||||
}
|
||||
|
||||
// We (reverse) order all the functions by their pointer location.
|
||||
// [f9, f6, f7, f8...] and calculate their potential function body size by
|
||||
// getting the diff in pointers between functions (since they are all located
|
||||
// in the same __text section).
|
||||
|
||||
let min_call_trampolines_pointer = self
|
||||
.finished_function_call_trampolines
|
||||
.values()
|
||||
.map(|t| *t as usize)
|
||||
.min()
|
||||
.unwrap_or(0);
|
||||
let min_dynamic_trampolines_pointer = self
|
||||
.finished_dynamic_function_trampolines
|
||||
.values()
|
||||
.map(|t| **t as usize)
|
||||
.min()
|
||||
.unwrap_or(0);
|
||||
|
||||
let fp = self.finished_functions.clone();
|
||||
let mut function_pointers = fp.into_iter().collect::<Vec<_>>();
|
||||
|
||||
// Sort the keys by the funciton pointer values in reverse order.
|
||||
// This way we can get the maximum function lengths (since functions can't overlap in memory)
|
||||
function_pointers.sort_by(|(_k1, v1), (_k2, v2)| v2.cmp(v1));
|
||||
let mut iter = function_pointers.into_iter();
|
||||
let mut function_pointers = iter
|
||||
.next()
|
||||
.map(|(index, function_pointer)| {
|
||||
let fp = **function_pointer as usize;
|
||||
// In case we are in the first function pointer (the one with the highest pointer)
|
||||
// we try to determine it's bounds (function size) by using the other function trampoline
|
||||
// locations.
|
||||
let current_size_by_ptr = if fp < min_call_trampolines_pointer {
|
||||
if min_call_trampolines_pointer < min_dynamic_trampolines_pointer
|
||||
|| min_dynamic_trampolines_pointer == 0
|
||||
{
|
||||
min_call_trampolines_pointer - fp
|
||||
} else {
|
||||
min_dynamic_trampolines_pointer - fp
|
||||
}
|
||||
} else if fp < min_dynamic_trampolines_pointer {
|
||||
min_dynamic_trampolines_pointer - fp
|
||||
} else {
|
||||
// The trampoline pointers are before the function.
|
||||
// We can safely assume the function will be at least 16 bits of length.
|
||||
// This is a very hacky assumption, but it makes collisions work perfectly
|
||||
// Since DLOpen simlinks will always be > 16 bits of difference between
|
||||
// two different libraries for the same symbol.
|
||||
// Note: the minmum Mach-O file is 0x1000 bytes and the minimum ELF is 0x0060 bytes
|
||||
16
|
||||
};
|
||||
let mut prev_pointer = fp;
|
||||
// We choose the minimum between the function size given the pointer diff
|
||||
// and the emitted size by the address map
|
||||
let ptr = function_pointer;
|
||||
let length = current_size_by_ptr;
|
||||
let first = (index, FunctionExtent { ptr: *ptr, length });
|
||||
std::iter::once(first)
|
||||
.chain(iter.map(|(index, function_pointer)| {
|
||||
let fp = **function_pointer as usize;
|
||||
// This assumes we never lay any functions bodies across the usize::MAX..nullptr
|
||||
// wrapping point.
|
||||
// Which is generally true on most OSes, but certainly doesn't have to be true.
|
||||
//
|
||||
// Further reading: https://lwn.net/Articles/342330/ \
|
||||
// "There is one little problem with that reasoning, though: NULL (zero) can
|
||||
// actually be a valid pointer address."
|
||||
let current_size_by_ptr = prev_pointer - fp;
|
||||
|
||||
prev_pointer = fp;
|
||||
// We choose the minimum between the function size given the pointer diff
|
||||
// and the emitted size by the address map
|
||||
let ptr = function_pointer;
|
||||
let length = current_size_by_ptr;
|
||||
(index, FunctionExtent { ptr: *ptr, length })
|
||||
}))
|
||||
.collect::<Vec<_>>()
|
||||
})
|
||||
.unwrap_or_default();
|
||||
|
||||
// We sort them again, by key this time
|
||||
function_pointers.sort_by(|(k1, _v1), (k2, _v2)| k1.cmp(k2));
|
||||
|
||||
let frame_infos = if self.metadata().function_frame_info.is_some() {
|
||||
self.metadata().function_frame_info.clone().unwrap()
|
||||
} else {
|
||||
function_pointers
|
||||
.iter()
|
||||
.map(|(_, extent)| CompiledFunctionFrameInfo {
|
||||
traps: vec![],
|
||||
address_map: FunctionAddressMap {
|
||||
body_len: extent.length,
|
||||
..Default::default()
|
||||
},
|
||||
})
|
||||
.collect::<PrimaryMap<LocalFunctionIndex, _>>()
|
||||
};
|
||||
|
||||
let finished_function_extents = function_pointers
|
||||
.into_iter()
|
||||
.map(|(_, function_extent)| function_extent)
|
||||
.collect::<PrimaryMap<LocalFunctionIndex, _>>()
|
||||
.into_boxed_slice();
|
||||
|
||||
*info = register_frame_info(
|
||||
self.metadata.compile_info.module.clone(),
|
||||
&finished_function_extents,
|
||||
frame_infos,
|
||||
);
|
||||
}
|
||||
|
||||
fn finished_functions(&self) -> &BoxedSlice<LocalFunctionIndex, FunctionBodyPtr> {
|
||||
&self.finished_functions
|
||||
}
|
||||
|
||||
fn finished_function_call_trampolines(&self) -> &BoxedSlice<SignatureIndex, VMTrampoline> {
|
||||
&self.finished_function_call_trampolines
|
||||
}
|
||||
|
||||
fn finished_dynamic_function_trampolines(&self) -> &BoxedSlice<FunctionIndex, FunctionBodyPtr> {
|
||||
&self.finished_dynamic_function_trampolines
|
||||
}
|
||||
|
||||
fn signatures(&self) -> &BoxedSlice<SignatureIndex, VMSharedSignatureIndex> {
|
||||
&self.signatures
|
||||
}
|
||||
|
||||
fn func_data_registry(&self) -> &FuncDataRegistry {
|
||||
&self.func_data_registry
|
||||
}
|
||||
|
||||
fn preinstantiate(&self) -> Result<(), InstantiationError> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
@ -1,117 +0,0 @@
|
||||
use crate::DylibEngine;
|
||||
use wasmer_compiler::{CompilerConfig, Features, Target};
|
||||
|
||||
/// The Dylib builder
|
||||
pub struct Dylib {
|
||||
compiler_config: Option<Box<dyn CompilerConfig>>,
|
||||
target: Option<Target>,
|
||||
features: Option<Features>,
|
||||
}
|
||||
|
||||
impl Dylib {
|
||||
#[cfg(feature = "compiler")]
|
||||
/// Create a new Dylib builder.
|
||||
pub fn new<T>(compiler_config: T) -> Self
|
||||
where
|
||||
T: Into<Box<dyn CompilerConfig>>,
|
||||
{
|
||||
let mut compiler_config = compiler_config.into();
|
||||
compiler_config.enable_pic();
|
||||
|
||||
Self {
|
||||
compiler_config: Some(compiler_config),
|
||||
target: None,
|
||||
features: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a new headless Dylib builder.
|
||||
pub fn headless() -> Self {
|
||||
Self {
|
||||
compiler_config: None,
|
||||
target: None,
|
||||
features: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the target
|
||||
pub fn target(mut self, target: Target) -> Self {
|
||||
self.target = Some(target);
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the features
|
||||
pub fn features(mut self, features: Features) -> Self {
|
||||
self.features = Some(features);
|
||||
self
|
||||
}
|
||||
|
||||
/// Build the `DylibEngine` for this configuration
|
||||
pub fn engine(self) -> DylibEngine {
|
||||
if let Some(_compiler_config) = self.compiler_config {
|
||||
#[cfg(feature = "compiler")]
|
||||
{
|
||||
let compiler_config = _compiler_config;
|
||||
let target = self.target.unwrap_or_default();
|
||||
let features = self
|
||||
.features
|
||||
.unwrap_or_else(|| compiler_config.default_features_for_target(&target));
|
||||
let compiler = compiler_config.compiler();
|
||||
DylibEngine::new(compiler, target, features)
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "compiler"))]
|
||||
{
|
||||
unreachable!("Cannot call `DylibEngine::new` without the `compiler` feature")
|
||||
}
|
||||
} else {
|
||||
DylibEngine::headless()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
#[cfg(feature = "compiler")]
|
||||
use std::sync::Arc;
|
||||
#[cfg(feature = "compiler")]
|
||||
use wasmer_compiler::{Compiler, ModuleMiddleware};
|
||||
|
||||
#[cfg(feature = "compiler")]
|
||||
#[derive(Default)]
|
||||
pub struct TestCompilerConfig {
|
||||
pub enabled_pic: bool,
|
||||
pub middlewares: Vec<Arc<dyn ModuleMiddleware>>,
|
||||
}
|
||||
|
||||
#[cfg(feature = "compiler")]
|
||||
impl CompilerConfig for TestCompilerConfig {
|
||||
fn enable_pic(&mut self) {
|
||||
self.enabled_pic = true;
|
||||
}
|
||||
|
||||
fn compiler(self: Box<Self>) -> Box<dyn Compiler> {
|
||||
unimplemented!("compiler not implemented");
|
||||
}
|
||||
|
||||
fn push_middleware(&mut self, middleware: Arc<dyn ModuleMiddleware>) {
|
||||
self.middlewares.push(middleware);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "compiler")]
|
||||
#[test]
|
||||
#[should_panic(expected = "compiler not implemented")]
|
||||
fn build_engine() {
|
||||
let compiler_config = TestCompilerConfig::default();
|
||||
let dylib = Dylib::new(compiler_config);
|
||||
let _engine = dylib.engine();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn build_headless_engine() {
|
||||
let dylib = Dylib::headless();
|
||||
let _engine = dylib.engine();
|
||||
}
|
||||
}
|
@ -1,325 +0,0 @@
|
||||
//! Dylib Engine.
|
||||
|
||||
use crate::DylibArtifact;
|
||||
use libloading::Library;
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
use std::sync::Mutex;
|
||||
use wasmer_compiler::{CompileError, Target};
|
||||
#[cfg(feature = "compiler")]
|
||||
use wasmer_compiler::{Compiler, Triple};
|
||||
use wasmer_engine::{Artifact, DeserializeError, Engine, EngineId, Tunables};
|
||||
#[cfg(feature = "compiler")]
|
||||
use wasmer_types::Features;
|
||||
use wasmer_types::FunctionType;
|
||||
use wasmer_vm::{
|
||||
FuncDataRegistry, SignatureRegistry, VMCallerCheckedAnyfunc, VMFuncRef, VMSharedSignatureIndex,
|
||||
};
|
||||
|
||||
/// A WebAssembly `Dylib` Engine.
|
||||
#[derive(Clone)]
|
||||
pub struct DylibEngine {
|
||||
inner: Arc<Mutex<DylibEngineInner>>,
|
||||
/// The target for the compiler
|
||||
target: Arc<Target>,
|
||||
engine_id: EngineId,
|
||||
}
|
||||
|
||||
impl DylibEngine {
|
||||
/// Create a new `DylibEngine` with the given config
|
||||
#[cfg(feature = "compiler")]
|
||||
pub fn new(compiler: Box<dyn Compiler>, target: Target, features: Features) -> Self {
|
||||
let is_cross_compiling = *target.triple() != Triple::host();
|
||||
let linker = Linker::find_linker(is_cross_compiling);
|
||||
|
||||
Self {
|
||||
inner: Arc::new(Mutex::new(DylibEngineInner {
|
||||
compiler: Some(compiler),
|
||||
signatures: SignatureRegistry::new(),
|
||||
func_data: Arc::new(FuncDataRegistry::new()),
|
||||
prefixer: None,
|
||||
features,
|
||||
is_cross_compiling,
|
||||
linker,
|
||||
libraries: vec![],
|
||||
})),
|
||||
target: Arc::new(target),
|
||||
engine_id: EngineId::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a headless `DylibEngine`
|
||||
///
|
||||
/// A headless engine is an engine without any compiler attached.
|
||||
/// This is useful for assuring a minimal runtime for running
|
||||
/// WebAssembly modules.
|
||||
///
|
||||
/// For example, for running in IoT devices where compilers are very
|
||||
/// expensive, or also to optimize startup speed.
|
||||
///
|
||||
/// # Important
|
||||
///
|
||||
/// Headless engines can't compile or validate any modules,
|
||||
/// they just take already processed Modules (via `Module::serialize`).
|
||||
pub fn headless() -> Self {
|
||||
Self {
|
||||
inner: Arc::new(Mutex::new(DylibEngineInner {
|
||||
#[cfg(feature = "compiler")]
|
||||
compiler: None,
|
||||
#[cfg(feature = "compiler")]
|
||||
features: Features::default(),
|
||||
signatures: SignatureRegistry::new(),
|
||||
func_data: Arc::new(FuncDataRegistry::new()),
|
||||
prefixer: None,
|
||||
is_cross_compiling: false,
|
||||
linker: Linker::None,
|
||||
libraries: vec![],
|
||||
})),
|
||||
target: Arc::new(Target::default()),
|
||||
engine_id: EngineId::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets a prefixer for the wasm module, so we can avoid any collisions
|
||||
/// in the exported function names on the generated shared object.
|
||||
///
|
||||
/// This, allows us to rather than have functions named `wasmer_function_1`
|
||||
/// to be named `wasmer_function_PREFIX_1`.
|
||||
///
|
||||
/// # Important
|
||||
///
|
||||
/// This prefixer function should be deterministic, so the compilation
|
||||
/// remains deterministic.
|
||||
pub fn set_deterministic_prefixer<F>(&mut self, prefixer: F)
|
||||
where
|
||||
F: Fn(&[u8]) -> String + Send + 'static,
|
||||
{
|
||||
let mut inner = self.inner_mut();
|
||||
inner.prefixer = Some(Box::new(prefixer));
|
||||
}
|
||||
|
||||
pub(crate) fn inner(&self) -> std::sync::MutexGuard<'_, DylibEngineInner> {
|
||||
self.inner.lock().unwrap()
|
||||
}
|
||||
|
||||
pub(crate) fn inner_mut(&self) -> std::sync::MutexGuard<'_, DylibEngineInner> {
|
||||
self.inner.lock().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl Engine for DylibEngine {
|
||||
/// The target
|
||||
fn target(&self) -> &Target {
|
||||
&self.target
|
||||
}
|
||||
|
||||
/// Register a signature
|
||||
fn register_signature(&self, func_type: &FunctionType) -> VMSharedSignatureIndex {
|
||||
let compiler = self.inner();
|
||||
compiler.signatures().register(func_type)
|
||||
}
|
||||
|
||||
fn register_function_metadata(&self, func_data: VMCallerCheckedAnyfunc) -> VMFuncRef {
|
||||
let compiler = self.inner();
|
||||
compiler.func_data().register(func_data)
|
||||
}
|
||||
|
||||
/// Lookup a signature
|
||||
fn lookup_signature(&self, sig: VMSharedSignatureIndex) -> Option<FunctionType> {
|
||||
let compiler = self.inner();
|
||||
compiler.signatures().lookup(sig)
|
||||
}
|
||||
|
||||
/// Validates a WebAssembly module
|
||||
fn validate(&self, binary: &[u8]) -> Result<(), CompileError> {
|
||||
self.inner().validate(binary)
|
||||
}
|
||||
|
||||
/// Compile a WebAssembly binary
|
||||
#[cfg(feature = "compiler")]
|
||||
fn compile(
|
||||
&self,
|
||||
binary: &[u8],
|
||||
tunables: &dyn Tunables,
|
||||
) -> Result<Arc<dyn Artifact>, CompileError> {
|
||||
Ok(Arc::new(DylibArtifact::new(self, binary, tunables)?))
|
||||
}
|
||||
|
||||
/// Compile a WebAssembly binary (it will fail because the `compiler` flag is disabled).
|
||||
#[cfg(not(feature = "compiler"))]
|
||||
fn compile(
|
||||
&self,
|
||||
_binary: &[u8],
|
||||
_tunables: &dyn Tunables,
|
||||
) -> Result<Arc<dyn Artifact>, CompileError> {
|
||||
Err(CompileError::Codegen(
|
||||
"The `DylibEngine` is operating in headless mode, so it cannot compile a module."
|
||||
.to_string(),
|
||||
))
|
||||
}
|
||||
|
||||
/// Deserializes a WebAssembly module (binary content of a shared object file)
|
||||
unsafe fn deserialize(&self, bytes: &[u8]) -> Result<Arc<dyn Artifact>, DeserializeError> {
|
||||
Ok(Arc::new(DylibArtifact::deserialize(self, bytes)?))
|
||||
}
|
||||
|
||||
/// Deserializes a WebAssembly module from a path
|
||||
/// It should point to a shared object file generated by this engine.
|
||||
unsafe fn deserialize_from_file(
|
||||
&self,
|
||||
file_ref: &Path,
|
||||
) -> Result<Arc<dyn Artifact>, DeserializeError> {
|
||||
Ok(Arc::new(DylibArtifact::deserialize_from_file(
|
||||
self, file_ref,
|
||||
)?))
|
||||
}
|
||||
|
||||
fn id(&self) -> &EngineId {
|
||||
&self.engine_id
|
||||
}
|
||||
|
||||
fn cloned(&self) -> Arc<dyn Engine + Send + Sync> {
|
||||
Arc::new(self.clone())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub(crate) enum Linker {
|
||||
None,
|
||||
Clang11,
|
||||
Clang10,
|
||||
Clang,
|
||||
Gcc,
|
||||
}
|
||||
|
||||
impl Linker {
|
||||
#[cfg(feature = "compiler")]
|
||||
fn find_linker(is_cross_compiling: bool) -> Self {
|
||||
let (possibilities, requirements): (&[_], _) = if is_cross_compiling {
|
||||
(
|
||||
&[Self::Clang11, Self::Clang10, Self::Clang],
|
||||
"at least one of `clang-11`, `clang-10`, or `clang`",
|
||||
)
|
||||
} else {
|
||||
(&[Self::Gcc], "`gcc`")
|
||||
};
|
||||
*possibilities
|
||||
.iter()
|
||||
.find(|linker| which::which(linker.executable()).is_ok())
|
||||
.unwrap_or_else(|| {
|
||||
panic!(
|
||||
"Need {} installed in order to use `DylibEngine` when {}cross-compiling",
|
||||
requirements,
|
||||
if is_cross_compiling { "" } else { "not " }
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn executable(self) -> &'static str {
|
||||
match self {
|
||||
Self::None => "",
|
||||
Self::Clang11 => "clang-11",
|
||||
Self::Clang10 => "clang-10",
|
||||
Self::Clang => "clang",
|
||||
Self::Gcc => "gcc",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The inner contents of `DylibEngine`
|
||||
pub struct DylibEngineInner {
|
||||
/// The compiler
|
||||
#[cfg(feature = "compiler")]
|
||||
compiler: Option<Box<dyn Compiler>>,
|
||||
|
||||
/// The WebAssembly features to use
|
||||
#[cfg(feature = "compiler")]
|
||||
features: Features,
|
||||
|
||||
/// The signature registry is used mainly to operate with trampolines
|
||||
/// performantly.
|
||||
signatures: SignatureRegistry,
|
||||
|
||||
/// The backing storage of `VMFuncRef`s. This centralized store ensures that 2
|
||||
/// functions with the same `VMCallerCheckedAnyfunc` will have the same `VMFuncRef`.
|
||||
/// It also guarantees that the `VMFuncRef`s stay valid until the engine is dropped.
|
||||
func_data: Arc<FuncDataRegistry>,
|
||||
|
||||
/// The prefixer returns the a String to prefix each of
|
||||
/// the functions in the shared object generated by the `DylibEngine`,
|
||||
/// so we can assure no collisions.
|
||||
prefixer: Option<Box<dyn Fn(&[u8]) -> String + Send>>,
|
||||
|
||||
/// Whether the Dylib engine will cross-compile.
|
||||
is_cross_compiling: bool,
|
||||
|
||||
/// The linker to use.
|
||||
linker: Linker,
|
||||
|
||||
/// List of libraries loaded by this engine.
|
||||
libraries: Vec<Library>,
|
||||
}
|
||||
|
||||
impl DylibEngineInner {
|
||||
/// Gets the compiler associated to this engine.
|
||||
#[cfg(feature = "compiler")]
|
||||
pub fn compiler(&self) -> Result<&dyn Compiler, CompileError> {
|
||||
if self.compiler.is_none() {
|
||||
return Err(CompileError::Codegen("The `DylibEngine` is operating in headless mode, so it can only execute already compiled Modules.".to_string()));
|
||||
}
|
||||
Ok(&**self
|
||||
.compiler
|
||||
.as_ref()
|
||||
.expect("Can't get compiler reference"))
|
||||
}
|
||||
|
||||
#[cfg(feature = "compiler")]
|
||||
pub(crate) fn get_prefix(&self, bytes: &[u8]) -> String {
|
||||
if let Some(prefixer) = &self.prefixer {
|
||||
prefixer(bytes)
|
||||
} else {
|
||||
"".to_string()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "compiler")]
|
||||
pub(crate) fn features(&self) -> &Features {
|
||||
&self.features
|
||||
}
|
||||
|
||||
/// Validate the module
|
||||
#[cfg(feature = "compiler")]
|
||||
pub fn validate(&self, data: &[u8]) -> Result<(), CompileError> {
|
||||
self.compiler()?.validate_module(self.features(), data)
|
||||
}
|
||||
|
||||
/// Validate the module
|
||||
#[cfg(not(feature = "compiler"))]
|
||||
pub fn validate<'data>(&self, _data: &'data [u8]) -> Result<(), CompileError> {
|
||||
Err(CompileError::Validate(
|
||||
"The `DylibEngine` is not compiled with compiler support, which is required for validating".to_string(),
|
||||
))
|
||||
}
|
||||
|
||||
/// Shared signature registry.
|
||||
pub fn signatures(&self) -> &SignatureRegistry {
|
||||
&self.signatures
|
||||
}
|
||||
|
||||
/// Shared func metadata registry.
|
||||
pub(crate) fn func_data(&self) -> &Arc<FuncDataRegistry> {
|
||||
&self.func_data
|
||||
}
|
||||
|
||||
pub(crate) fn is_cross_compiling(&self) -> bool {
|
||||
self.is_cross_compiling
|
||||
}
|
||||
|
||||
pub(crate) fn linker(&self) -> Linker {
|
||||
self.linker
|
||||
}
|
||||
|
||||
pub(crate) fn add_library(&mut self, library: Library) {
|
||||
self.libraries.push(library);
|
||||
}
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
//! Dylib Engine for Wasmer compilers.
|
||||
//!
|
||||
//! Given a compiler (such as `CraneliftCompiler` or `LLVMCompiler`)
|
||||
//! it generates a dylib/shared object file (`.so` or `.dylib`
|
||||
//! depending on the target), saves it temporarily to disk and uses it
|
||||
//! natively via `dlopen` and `dlsym` (using the `libloading`
|
||||
//! library).
|
||||
|
||||
#![deny(missing_docs, trivial_numeric_casts, unused_extern_crates)]
|
||||
#![warn(unused_import_braces)]
|
||||
#![cfg_attr(feature = "cargo-clippy", allow(clippy::new_without_default))]
|
||||
#![cfg_attr(
|
||||
feature = "cargo-clippy",
|
||||
warn(
|
||||
clippy::float_arithmetic,
|
||||
clippy::mut_mut,
|
||||
clippy::nonminimal_bool,
|
||||
clippy::map_unwrap_or,
|
||||
clippy::print_stdout,
|
||||
clippy::unicode_not_nfc,
|
||||
clippy::use_self
|
||||
)
|
||||
)]
|
||||
|
||||
mod artifact;
|
||||
mod builder;
|
||||
mod engine;
|
||||
mod serialize;
|
||||
mod trampoline;
|
||||
|
||||
pub use crate::artifact::DylibArtifact;
|
||||
pub use crate::builder::Dylib;
|
||||
pub use crate::engine::DylibEngine;
|
||||
|
||||
/// Version number of this crate.
|
||||
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
|
@ -1,139 +0,0 @@
|
||||
use rkyv::{
|
||||
archived_value, de::deserializers::SharedDeserializeMap, ser::serializers::AllocSerializer,
|
||||
ser::Serializer as RkyvSerializer, Archive, Deserialize as RkyvDeserialize,
|
||||
Serialize as RkyvSerialize,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::error::Error;
|
||||
use wasmer_compiler::{
|
||||
CompileError, CompileModuleInfo, CompiledFunctionFrameInfo, SectionIndex, Symbol,
|
||||
SymbolRegistry,
|
||||
};
|
||||
use wasmer_engine::DeserializeError;
|
||||
use wasmer_types::entity::{EntityRef, PrimaryMap};
|
||||
use wasmer_types::{FunctionIndex, LocalFunctionIndex, OwnedDataInitializer, SignatureIndex};
|
||||
|
||||
fn to_compile_error(err: impl Error) -> CompileError {
|
||||
CompileError::Codegen(format!("{}", err))
|
||||
}
|
||||
|
||||
/// Serializable struct that represents the compiled metadata.
|
||||
#[derive(Serialize, Deserialize, Debug, RkyvSerialize, RkyvDeserialize, Archive, PartialEq, Eq)]
|
||||
pub struct ModuleMetadata {
|
||||
pub compile_info: CompileModuleInfo,
|
||||
pub function_frame_info: Option<PrimaryMap<LocalFunctionIndex, CompiledFunctionFrameInfo>>,
|
||||
pub prefix: String,
|
||||
pub data_initializers: Box<[OwnedDataInitializer]>,
|
||||
// The function body lengths (used to find function by address)
|
||||
pub function_body_lengths: PrimaryMap<LocalFunctionIndex, u64>,
|
||||
pub cpu_features: u64,
|
||||
}
|
||||
|
||||
pub struct ModuleMetadataSymbolRegistry<'a> {
|
||||
pub prefix: &'a String,
|
||||
}
|
||||
|
||||
impl ModuleMetadata {
|
||||
pub fn split(&'_ mut self) -> (&'_ mut CompileModuleInfo, ModuleMetadataSymbolRegistry<'_>) {
|
||||
let compile_info = &mut self.compile_info;
|
||||
let symbol_registry = ModuleMetadataSymbolRegistry {
|
||||
prefix: &self.prefix,
|
||||
};
|
||||
(compile_info, symbol_registry)
|
||||
}
|
||||
|
||||
pub fn get_symbol_registry(&'_ self) -> ModuleMetadataSymbolRegistry<'_> {
|
||||
ModuleMetadataSymbolRegistry {
|
||||
prefix: &self.prefix,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn serialize(&mut self) -> Result<Vec<u8>, CompileError> {
|
||||
let mut serializer = AllocSerializer::<4096>::default();
|
||||
let pos = serializer.serialize_value(self).map_err(to_compile_error)? as u64;
|
||||
let mut serialized_data = serializer.into_serializer().into_inner();
|
||||
serialized_data.extend_from_slice(&pos.to_le_bytes());
|
||||
Ok(serialized_data.to_vec())
|
||||
}
|
||||
|
||||
pub unsafe fn deserialize(metadata_slice: &[u8]) -> Result<Self, DeserializeError> {
|
||||
let archived = Self::archive_from_slice(metadata_slice)?;
|
||||
Self::deserialize_from_archive(archived)
|
||||
}
|
||||
|
||||
unsafe fn archive_from_slice(
|
||||
metadata_slice: &[u8],
|
||||
) -> Result<&ArchivedModuleMetadata, DeserializeError> {
|
||||
let mut pos: [u8; 8] = Default::default();
|
||||
pos.copy_from_slice(&metadata_slice[metadata_slice.len() - 8..metadata_slice.len()]);
|
||||
let pos: u64 = u64::from_le_bytes(pos);
|
||||
Ok(archived_value::<Self>(
|
||||
&metadata_slice[..metadata_slice.len() - 8],
|
||||
pos as usize,
|
||||
))
|
||||
}
|
||||
|
||||
pub fn deserialize_from_archive(
|
||||
archived: &ArchivedModuleMetadata,
|
||||
) -> Result<Self, DeserializeError> {
|
||||
let mut deserializer = SharedDeserializeMap::new();
|
||||
RkyvDeserialize::deserialize(archived, &mut deserializer)
|
||||
.map_err(|e| DeserializeError::CorruptedBinary(format!("{:?}", e)))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> SymbolRegistry for ModuleMetadataSymbolRegistry<'a> {
|
||||
fn symbol_to_name(&self, symbol: Symbol) -> String {
|
||||
match symbol {
|
||||
Symbol::LocalFunction(index) => {
|
||||
format!("wasmer_function_{}_{}", self.prefix, index.index())
|
||||
}
|
||||
Symbol::Section(index) => format!("wasmer_section_{}_{}", self.prefix, index.index()),
|
||||
Symbol::FunctionCallTrampoline(index) => {
|
||||
format!(
|
||||
"wasmer_trampoline_function_call_{}_{}",
|
||||
self.prefix,
|
||||
index.index()
|
||||
)
|
||||
}
|
||||
Symbol::DynamicFunctionTrampoline(index) => {
|
||||
format!(
|
||||
"wasmer_trampoline_dynamic_function_{}_{}",
|
||||
self.prefix,
|
||||
index.index()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn name_to_symbol(&self, name: &str) -> Option<Symbol> {
|
||||
if let Some(index) = name.strip_prefix(&format!("wasmer_function_{}_", self.prefix)) {
|
||||
index
|
||||
.parse::<u32>()
|
||||
.ok()
|
||||
.map(|index| Symbol::LocalFunction(LocalFunctionIndex::from_u32(index)))
|
||||
} else if let Some(index) = name.strip_prefix(&format!("wasmer_section_{}_", self.prefix)) {
|
||||
index
|
||||
.parse::<u32>()
|
||||
.ok()
|
||||
.map(|index| Symbol::Section(SectionIndex::from_u32(index)))
|
||||
} else if let Some(index) =
|
||||
name.strip_prefix(&format!("wasmer_trampoline_function_call_{}_", self.prefix))
|
||||
{
|
||||
index
|
||||
.parse::<u32>()
|
||||
.ok()
|
||||
.map(|index| Symbol::FunctionCallTrampoline(SignatureIndex::from_u32(index)))
|
||||
} else if let Some(index) = name.strip_prefix(&format!(
|
||||
"wasmer_trampoline_dynamic_function_{}_",
|
||||
self.prefix
|
||||
)) {
|
||||
index
|
||||
.parse::<u32>()
|
||||
.ok()
|
||||
.map(|index| Symbol::DynamicFunctionTrampoline(FunctionIndex::from_u32(index)))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
@ -1,166 +0,0 @@
|
||||
//! Trampolines for libcalls.
|
||||
//!
|
||||
//! This is needed because the target of libcall relocations are not reachable
|
||||
//! through normal branch instructions.
|
||||
//!
|
||||
//! There is an additional complexity for dynamic libraries: we can't just
|
||||
//! import the symbol from the host executable because executables don't export
|
||||
//! dynamic symbols (it's possible but requires special linker options).
|
||||
//!
|
||||
//! Instead, we export a table of function pointers in the data section which is
|
||||
//! manually filled in by the runtime after the dylib is loaded.
|
||||
|
||||
use enum_iterator::IntoEnumIterator;
|
||||
use object::{
|
||||
elf, macho,
|
||||
write::{Object, Relocation, SectionId, StandardSection, Symbol, SymbolId, SymbolSection},
|
||||
BinaryFormat, RelocationEncoding, RelocationKind, SymbolFlags, SymbolKind, SymbolScope,
|
||||
};
|
||||
use wasmer_compiler::{Architecture, Target};
|
||||
use wasmer_vm::libcalls::{function_pointer, LibCall};
|
||||
|
||||
/// Symbol exported from the dynamic library which points to the trampoline table.
|
||||
pub const WASMER_TRAMPOLINES_SYMBOL: &[u8] = b"WASMER_TRAMPOLINES";
|
||||
|
||||
// SystemV says that both x16 and x17 are available as intra-procedural scratch
|
||||
// registers but Apple's ABI restricts us to use x17.
|
||||
// ADRP x17, #... 11 00 00 90
|
||||
// LDR x17, [x17, #...] 31 02 40 f9
|
||||
// BR x17 20 02 1f d6
|
||||
const AARCH64_TRAMPOLINE: [u8; 12] = [
|
||||
0x11, 0x00, 0x00, 0x90, 0x31, 0x02, 0x40, 0xf9, 0x20, 0x02, 0x1f, 0xd6,
|
||||
];
|
||||
|
||||
// JMP [RIP + ...] FF 25 00 00 00 00
|
||||
const X86_64_TRAMPOLINE: [u8; 6] = [0xff, 0x25, 0x00, 0x00, 0x00, 0x00];
|
||||
|
||||
fn emit_trampoline(
|
||||
obj: &mut Object,
|
||||
text: SectionId,
|
||||
trampoline_table_symbols: &[SymbolId],
|
||||
libcall: LibCall,
|
||||
target: &Target,
|
||||
) {
|
||||
let function_name = libcall.to_function_name();
|
||||
let libcall_symbol = obj.add_symbol(Symbol {
|
||||
name: function_name.as_bytes().to_vec(),
|
||||
value: 0,
|
||||
size: 0,
|
||||
kind: SymbolKind::Text,
|
||||
scope: SymbolScope::Linkage,
|
||||
weak: false,
|
||||
section: SymbolSection::Section(text),
|
||||
flags: SymbolFlags::None,
|
||||
});
|
||||
|
||||
match target.triple().architecture {
|
||||
Architecture::Aarch64(_) => {
|
||||
let (reloc1, reloc2) = match obj.format() {
|
||||
BinaryFormat::Elf => (
|
||||
RelocationKind::Elf(elf::R_AARCH64_ADR_PREL_PG_HI21),
|
||||
RelocationKind::Elf(elf::R_AARCH64_LDST64_ABS_LO12_NC),
|
||||
),
|
||||
BinaryFormat::MachO => (
|
||||
RelocationKind::MachO {
|
||||
value: macho::ARM64_RELOC_PAGE21,
|
||||
relative: true,
|
||||
},
|
||||
RelocationKind::MachO {
|
||||
value: macho::ARM64_RELOC_PAGEOFF12,
|
||||
relative: false,
|
||||
},
|
||||
),
|
||||
_ => panic!("Unsupported binary format on AArch64"),
|
||||
};
|
||||
let offset = obj.add_symbol_data(libcall_symbol, text, &AARCH64_TRAMPOLINE, 4);
|
||||
obj.add_relocation(
|
||||
text,
|
||||
Relocation {
|
||||
offset,
|
||||
size: 32,
|
||||
kind: reloc1,
|
||||
encoding: RelocationEncoding::Generic,
|
||||
symbol: trampoline_table_symbols[libcall as usize],
|
||||
addend: 0,
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
obj.add_relocation(
|
||||
text,
|
||||
Relocation {
|
||||
offset: offset + 4,
|
||||
size: 32,
|
||||
kind: reloc2,
|
||||
encoding: RelocationEncoding::Generic,
|
||||
symbol: trampoline_table_symbols[libcall as usize],
|
||||
addend: 0,
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
Architecture::X86_64 => {
|
||||
let offset = obj.add_symbol_data(libcall_symbol, text, &X86_64_TRAMPOLINE, 1);
|
||||
obj.add_relocation(
|
||||
text,
|
||||
Relocation {
|
||||
offset: offset + 2,
|
||||
size: 32,
|
||||
kind: RelocationKind::Relative,
|
||||
encoding: RelocationEncoding::Generic,
|
||||
symbol: trampoline_table_symbols[libcall as usize],
|
||||
// -4 because RIP-relative addressing starts from the end of
|
||||
// the instruction.
|
||||
addend: -4,
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
arch => panic!("Unsupported architecture: {}", arch),
|
||||
};
|
||||
}
|
||||
|
||||
/// Emits the libcall trampolines and table to the object file.
|
||||
pub fn emit_trampolines(obj: &mut Object, target: &Target) {
|
||||
let text = obj.section_id(StandardSection::Text);
|
||||
let bss = obj.section_id(StandardSection::UninitializedData);
|
||||
|
||||
let trampoline_table = obj.add_symbol(Symbol {
|
||||
name: WASMER_TRAMPOLINES_SYMBOL.to_vec(),
|
||||
value: 0,
|
||||
size: 0,
|
||||
kind: SymbolKind::Data,
|
||||
scope: SymbolScope::Dynamic,
|
||||
weak: false,
|
||||
section: SymbolSection::Section(bss),
|
||||
flags: SymbolFlags::None,
|
||||
});
|
||||
let table_offset =
|
||||
obj.add_symbol_bss(trampoline_table, bss, LibCall::VARIANT_COUNT as u64 * 8, 8);
|
||||
|
||||
// Create a symbol for each entry in the table. We could avoid this and use
|
||||
// an addend, but this isn't supported in all object formats.
|
||||
let mut trampoline_table_symbols = vec![];
|
||||
for libcall in LibCall::into_enum_iter() {
|
||||
trampoline_table_symbols.push(obj.add_symbol(Symbol {
|
||||
name: format!("__WASMER_TRAMPOLINE{}", libcall as usize).into_bytes(),
|
||||
value: table_offset + libcall as u64 * 8,
|
||||
size: 0,
|
||||
kind: SymbolKind::Data,
|
||||
scope: SymbolScope::Compilation,
|
||||
weak: false,
|
||||
section: SymbolSection::Section(bss),
|
||||
flags: SymbolFlags::None,
|
||||
}));
|
||||
}
|
||||
|
||||
for libcall in LibCall::into_enum_iter() {
|
||||
emit_trampoline(obj, text, &trampoline_table_symbols, libcall, target);
|
||||
}
|
||||
}
|
||||
|
||||
/// Fills in the libcall trampoline table at the given address.
|
||||
pub unsafe fn fill_trampoline_table(table: *mut usize) {
|
||||
for libcall in LibCall::into_enum_iter() {
|
||||
*table.add(libcall as usize) = function_pointer(libcall);
|
||||
}
|
||||
}
|
@ -5,14 +5,13 @@ This crate is the general abstraction for creating Engines in Wasmer.
|
||||
Wasmer Engines are mainly responsible for two things:
|
||||
* Transform the compilation code (from any Wasmer Compiler) to
|
||||
**create** an `Artifact`,
|
||||
* **Load** an`Artifact` so it can be used by the user (normally,
|
||||
* **Load** an `Artifact` so it can be used by the user (normally,
|
||||
pushing the code into executable memory and so on).
|
||||
|
||||
It currently has three implementations:
|
||||
It currently has two implementations:
|
||||
|
||||
1. Universal with [`wasmer-engine-universal`],
|
||||
2. Native with [`wasmer-engine-dylib`],
|
||||
3. Object with [`wasmer-engine-staticlib`].
|
||||
2. Object with [`wasmer-engine-staticlib`].
|
||||
|
||||
## Example Implementation
|
||||
|
||||
@ -29,7 +28,6 @@ attributions of the project.
|
||||
|
||||
|
||||
[`wasmer-engine-universal`]: https://github.com/wasmerio/wasmer/tree/master/lib/engine-universal
|
||||
[`wasmer-engine-dylib`]: https://github.com/wasmerio/wasmer/tree/master/lib/engine-dylib
|
||||
[`wasmer-engine-staticlib`]: https://github.com/wasmerio/wasmer/tree/master/lib/engine-staticlib
|
||||
[`wasmer-engine-dummy`]: https://github.com/wasmerio/wasmer/tree/master/tests/lib/engine-dummy
|
||||
[`wasmtime-api`]: https://crates.io/crates/wasmtime
|
||||
|
@ -13,7 +13,6 @@ attributions of the project.
|
||||
|
||||
|
||||
[`wasmer-engine-universal`]: https://github.com/wasmerio/wasmer/tree/master/lib/engine-universal
|
||||
[`wasmer-engine-dylib`]: https://github.com/wasmerio/wasmer/tree/master/lib/engine-dylib
|
||||
[`wasmer-engine-staticlib`]: https://github.com/wasmerio/wasmer/tree/master/lib/engine-staticlib
|
||||
[`wasmer-engine-dummy`]: https://github.com/wasmerio/wasmer/tree/master/tests/lib/engine-dummy
|
||||
[`wasmtime-api`]: https://crates.io/crates/wasmtime
|
||||
|
@ -59,16 +59,6 @@ dep_graph = {
|
||||
"wasmer-engine",
|
||||
]
|
||||
),
|
||||
"wasmer-engine-dylib": set(
|
||||
[
|
||||
"wasmer-artifact",
|
||||
"wasmer-types",
|
||||
"wasmer-compiler",
|
||||
"wasmer-vm",
|
||||
"wasmer-engine",
|
||||
"wasmer-object",
|
||||
]
|
||||
),
|
||||
"wasmer-engine-staticlib": set(
|
||||
[
|
||||
"wasmer-artifact",
|
||||
@ -91,7 +81,6 @@ dep_graph = {
|
||||
"wasmer-compiler-cranelift",
|
||||
"wasmer-compiler-llvm",
|
||||
"wasmer-engine-universal",
|
||||
"wasmer-engine-dylib",
|
||||
]
|
||||
),
|
||||
"wasmer-vfs": set([]),
|
||||
@ -110,7 +99,6 @@ dep_graph = {
|
||||
"wasmer-emscripten",
|
||||
"wasmer-engine",
|
||||
"wasmer-engine-universal",
|
||||
"wasmer-engine-dylib",
|
||||
"wasmer-engine-staticlib",
|
||||
"wasmer-middlewares",
|
||||
"wasmer-wasi",
|
||||
@ -129,7 +117,6 @@ dep_graph = {
|
||||
"wasmer-emscripten",
|
||||
"wasmer-engine",
|
||||
"wasmer-engine-universal",
|
||||
"wasmer-engine-dylib",
|
||||
"wasmer-engine-staticlib",
|
||||
"wasmer-vm",
|
||||
"wasmer-wasi",
|
||||
@ -159,7 +146,6 @@ location = {
|
||||
"wasmer-compiler-llvm": "compiler-llvm",
|
||||
"wasmer-engine": "engine",
|
||||
"wasmer-engine-universal": "engine-universal",
|
||||
"wasmer-engine-dylib": "engine-dylib",
|
||||
"wasmer-engine-staticlib": "engine-staticlib",
|
||||
"wasmer-cache": "cache",
|
||||
"wasmer": "api",
|
||||
|
@ -10,7 +10,6 @@ pub enum Compiler {
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum Engine {
|
||||
Dylib,
|
||||
Universal,
|
||||
}
|
||||
|
||||
@ -61,14 +60,6 @@ impl Config {
|
||||
#[cfg(not(feature = "engine"))]
|
||||
compile_error!("Plese enable at least one engine via the features");
|
||||
match &self.engine {
|
||||
#[cfg(feature = "dylib")]
|
||||
Engine::Dylib => {
|
||||
let mut engine = wasmer_engine_dylib::Dylib::new(compiler_config);
|
||||
if let Some(ref features) = self.features {
|
||||
engine = engine.features(features.clone())
|
||||
}
|
||||
Box::new(engine.engine())
|
||||
}
|
||||
#[cfg(feature = "universal")]
|
||||
Engine::Universal => {
|
||||
let mut engine = wasmer_engine_universal::Universal::new(compiler_config);
|
||||
@ -87,8 +78,6 @@ impl Config {
|
||||
|
||||
pub fn engine_headless(&self) -> Box<dyn WasmerEngine> {
|
||||
match &self.engine {
|
||||
#[cfg(feature = "dylib")]
|
||||
Engine::Dylib => Box::new(wasmer_engine_dylib::Dylib::headless().engine()),
|
||||
#[cfg(feature = "universal")]
|
||||
Engine::Universal => Box::new(wasmer_engine_universal::Universal::headless().engine()),
|
||||
#[allow(unreachable_patterns)]
|
||||
|
@ -42,6 +42,7 @@ pub fn run_wast(mut config: crate::Config, wast_path: &str) -> anyhow::Result<()
|
||||
wast.allow_trap_message("uninitialized element 2", "uninitialized element");
|
||||
// `liking.wast` has different wording but the same meaning
|
||||
wast.allow_trap_message("out of bounds memory access", "memory out of bounds");
|
||||
/*
|
||||
if config.compiler == crate::Compiler::Cranelift && config.engine == crate::Engine::Dylib {
|
||||
wast.allow_trap_message("call stack exhausted", "out of bounds memory access");
|
||||
wast.allow_trap_message("indirect call type mismatch", "call stack exhausted");
|
||||
@ -52,6 +53,7 @@ pub fn run_wast(mut config: crate::Config, wast_path: &str) -> anyhow::Result<()
|
||||
wast.allow_trap_message("uninitialized element", "call stack exhausted");
|
||||
wast.allow_trap_message("unreachable", "call stack exhausted");
|
||||
}
|
||||
*/
|
||||
if cfg!(feature = "coverage") {
|
||||
wast.disable_assert_and_exhaustion();
|
||||
}
|
||||
|
@ -2,37 +2,27 @@
|
||||
singlepass spec::multi_value # Singlepass has not implemented multivalue (functions that returns "structs"/"tuples")
|
||||
singlepass spec::simd # Singlepass doesn't support yet SIMD (no one asked for this feature)
|
||||
|
||||
windows+dylib * # This might be trivial to fix?
|
||||
musl+dylib * # Dynamic loading not supported in Musl
|
||||
|
||||
# Traps
|
||||
## Traps. Tracing doesn't work properly in Singlepass
|
||||
## Unwinding is not properly implemented in Singlepass
|
||||
# Needs investigation
|
||||
singlepass+aarch64+macos traps::test_trap_trace
|
||||
dylib traps::test_trap_trace
|
||||
cranelift+aarch64 traps::test_trap_trace
|
||||
singlepass+aarch64+macos traps::test_trap_stack_overflow # Need to investigate
|
||||
dylib traps::test_trap_stack_overflow # Need to investigate
|
||||
cranelift+aarch64 traps::test_trap_stack_overflow # Need to investigate
|
||||
singlepass+aarch64+macos traps::trap_display_pretty
|
||||
llvm traps::trap_display_pretty
|
||||
dylib traps::trap_display_pretty
|
||||
cranelift+aarch64 traps::trap_display_pretty
|
||||
singlepass+aarch64+macos traps::trap_display_multi_module
|
||||
llvm traps::trap_display_multi_module
|
||||
dylib traps::trap_display_multi_module
|
||||
cranelift+aarch64 traps::trap_display_multi_module
|
||||
singlepass traps::call_signature_mismatch # Need to investigate, get foo (a[0]:0x33) instead of 0x30 for inderect call
|
||||
llvm traps::call_signature_mismatch
|
||||
dylib traps::call_signature_mismatch
|
||||
macos+aarch64 traps::call_signature_mismatch
|
||||
singlepass+aarch64+macos traps::start_trap_pretty
|
||||
llvm traps::start_trap_pretty
|
||||
dylib traps::start_trap_pretty
|
||||
cranelift+aarch64 traps::start_trap_pretty
|
||||
|
||||
singlepass multi_value_imports::dylib # Singlepass doesn't support multivalue
|
||||
singlepass multi_value_imports::dynamic # Singlepass doesn't support multivalue
|
||||
|
||||
# Also neither LLVM nor Cranelift currently implement stack probing on AArch64.
|
||||
|
@ -22,7 +22,6 @@ impl Compiler {
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum Engine {
|
||||
Universal,
|
||||
Dylib,
|
||||
Staticlib,
|
||||
}
|
||||
|
||||
@ -30,7 +29,6 @@ impl Engine {
|
||||
pub const fn to_flag(self) -> &'static str {
|
||||
match self {
|
||||
Engine::Universal => "--universal",
|
||||
Engine::Dylib => "--dylib",
|
||||
Engine::Staticlib => "--staticlib",
|
||||
}
|
||||
}
|
||||
|
@ -115,7 +115,7 @@ impl Ignores {
|
||||
arch = Some(alias.to_string());
|
||||
}
|
||||
// Engines
|
||||
"universal" | "dylib" => {
|
||||
"universal" => {
|
||||
engine = Some(alias.to_string());
|
||||
}
|
||||
// Compilers
|
||||
|
@ -112,7 +112,6 @@ pub fn compiler_test(attrs: TokenStream, input: TokenStream) -> TokenStream {
|
||||
let mod_name = ::quote::format_ident!("{}", compiler_name.to_lowercase());
|
||||
let universal_engine_test =
|
||||
construct_engine_test(func, compiler_name, "Universal", "universal");
|
||||
let dylib_engine_test = construct_engine_test(func, compiler_name, "Dylib", "dylib");
|
||||
let compiler_name_lowercase = compiler_name.to_lowercase();
|
||||
|
||||
quote! {
|
||||
@ -121,7 +120,6 @@ pub fn compiler_test(attrs: TokenStream, input: TokenStream) -> TokenStream {
|
||||
use super::*;
|
||||
|
||||
#universal_engine_test
|
||||
#dylib_engine_test
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -63,15 +63,6 @@ gen_tests! {
|
||||
crate::Compiler::Singlepass
|
||||
))
|
||||
}
|
||||
#[test_log::test]
|
||||
#[cold]
|
||||
#[cfg(feature = "dylib")]
|
||||
fn dylib() {
|
||||
foo(crate::Config::new(
|
||||
crate::Engine::Dylib,
|
||||
crate::Compiler::Singlepass
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "cranelift")]
|
||||
@ -86,15 +77,6 @@ gen_tests! {
|
||||
crate::Compiler::Cranelift
|
||||
))
|
||||
}
|
||||
#[test_log::test]
|
||||
#[cold]
|
||||
#[cfg(feature = "dylib")]
|
||||
fn dylib() {
|
||||
foo(crate::Config::new(
|
||||
crate::Engine::Dylib,
|
||||
crate::Compiler::Cranelift
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "llvm")]
|
||||
@ -109,15 +91,6 @@ gen_tests! {
|
||||
crate::Compiler::LLVM
|
||||
))
|
||||
}
|
||||
#[test_log::test]
|
||||
#[cold]
|
||||
#[cfg(feature = "dylib")]
|
||||
fn dylib() {
|
||||
foo(crate::Config::new(
|
||||
crate::Engine::Dylib,
|
||||
crate::Compiler::LLVM
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -10,5 +10,4 @@ anyhow = "1.0"
|
||||
target-lexicon = "0.12"
|
||||
|
||||
[features]
|
||||
test-dylib = []
|
||||
test-universal = []
|
||||
|
Reference in New Issue
Block a user