mirror of
https://github.com/fluencelabs/wasmer
synced 2025-06-22 13:11:32 +00:00
Add separated runtime crate
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,4 +1,4 @@
|
|||||||
/target
|
**/target
|
||||||
**/*.rs.bk
|
**/*.rs.bk
|
||||||
/artifacts
|
/artifacts
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
491
lib/runtime/Cargo.lock
generated
Normal file
491
lib/runtime/Cargo.lock
generated
Normal file
@ -0,0 +1,491 @@
|
|||||||
|
[[package]]
|
||||||
|
name = "abort_on_panic"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aho-corasick"
|
||||||
|
version = "0.6.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"memchr 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ansi_term"
|
||||||
|
version = "0.11.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "atty"
|
||||||
|
version = "0.2.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bindgen"
|
||||||
|
version = "0.31.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"cexpr 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"clang-sys 0.21.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"peeking_take_while 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"regex 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"which 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bitflags"
|
||||||
|
version = "1.0.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "byteorder"
|
||||||
|
version = "1.2.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cc"
|
||||||
|
version = "1.0.28"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cexpr"
|
||||||
|
version = "0.2.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"nom 3.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-if"
|
||||||
|
version = "0.1.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clang-sys"
|
||||||
|
version = "0.21.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"libloading 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap"
|
||||||
|
version = "2.32.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "env_logger"
|
||||||
|
version = "0.4.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"regex 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "errno"
|
||||||
|
version = "0.2.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"errno-dragonfly 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "errno-dragonfly"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gcc"
|
||||||
|
version = "0.3.55"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "glob"
|
||||||
|
version = "0.2.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hashbrown"
|
||||||
|
version = "0.1.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "kernel32-sys"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lazy_static"
|
||||||
|
version = "0.2.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lazy_static"
|
||||||
|
version = "1.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.46"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libffi"
|
||||||
|
version = "0.6.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"abort_on_panic 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"libffi-sys 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libffi-sys"
|
||||||
|
version = "0.6.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"bindgen 0.31.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"make-cmd 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libloading"
|
||||||
|
version = "0.4.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "log"
|
||||||
|
version = "0.3.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "log"
|
||||||
|
version = "0.4.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "make-cmd"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "memchr"
|
||||||
|
version = "1.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "memchr"
|
||||||
|
version = "2.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nix"
|
||||||
|
version = "0.12.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nom"
|
||||||
|
version = "3.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "page_size"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "peeking_take_while"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pkg-config"
|
||||||
|
version = "0.3.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quote"
|
||||||
|
version = "0.3.15"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "redox_syscall"
|
||||||
|
version = "0.1.50"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "redox_termios"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"redox_syscall 0.1.50 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex"
|
||||||
|
version = "0.2.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"aho-corasick 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"memchr 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"regex-syntax 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-syntax"
|
||||||
|
version = "0.5.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "scopeguard"
|
||||||
|
version = "0.3.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "strsim"
|
||||||
|
version = "0.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "termion"
|
||||||
|
version = "1.5.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"redox_syscall 0.1.50 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "textwrap"
|
||||||
|
version = "0.10.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "thread_local"
|
||||||
|
version = "0.3.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ucd-util"
|
||||||
|
version = "0.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-width"
|
||||||
|
version = "0.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "utf8-ranges"
|
||||||
|
version = "1.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "vec_map"
|
||||||
|
version = "0.8.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "version_check"
|
||||||
|
version = "0.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "void"
|
||||||
|
version = "1.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasmer-runtime"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"errno 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"hashbrown 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"libffi 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"nix 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"page_size 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "which"
|
||||||
|
version = "1.0.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi"
|
||||||
|
version = "0.2.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi"
|
||||||
|
version = "0.3.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-build"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-i686-pc-windows-gnu"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-x86_64-pc-windows-gnu"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
"checksum abort_on_panic 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9fa948f9ec9f095cc955efbe4fd00ac5774ef933cc2442562a8fe5a57c4ef919"
|
||||||
|
"checksum aho-corasick 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "1e9a933f4e58658d7b12defcf96dc5c720f20832deebe3e0a19efd3b6aaeeb9e"
|
||||||
|
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
|
||||||
|
"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652"
|
||||||
|
"checksum bindgen 0.31.3 (registry+https://github.com/rust-lang/crates.io-index)" = "57253399c086f4f29e57ffd3b5cdbc23a806a00292619351aa4cfa39cb49d4ea"
|
||||||
|
"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
|
||||||
|
"checksum byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "94f88df23a25417badc922ab0f5716cc1330e87f71ddd9203b3a3ccd9cedf75d"
|
||||||
|
"checksum cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4a8b715cb4597106ea87c7c84b2f1d452c7492033765df7f32651e66fcf749"
|
||||||
|
"checksum cexpr 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "42aac45e9567d97474a834efdee3081b3c942b2205be932092f53354ce503d6c"
|
||||||
|
"checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4"
|
||||||
|
"checksum clang-sys 0.21.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e414af9726e1d11660801e73ccc7fb81803fb5f49e5903a25b348b2b3b480d2e"
|
||||||
|
"checksum clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e"
|
||||||
|
"checksum env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3ddf21e73e016298f5cb37d6ef8e8da8e39f91f9ec8b0df44b7deb16a9f8cd5b"
|
||||||
|
"checksum errno 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c2a071601ed01b988f896ab14b95e67335d1eeb50190932a1320f7fe3cadc84e"
|
||||||
|
"checksum errno-dragonfly 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "14ca354e36190500e1e1fb267c647932382b54053c50b14970856c0b00a35067"
|
||||||
|
"checksum gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)" = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2"
|
||||||
|
"checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb"
|
||||||
|
"checksum hashbrown 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "64b7d419d0622ae02fe5da6b9a5e1964b610a65bb37923b976aeebb6dbb8f86e"
|
||||||
|
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
|
||||||
|
"checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73"
|
||||||
|
"checksum lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1"
|
||||||
|
"checksum libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)" = "023a4cd09b2ff695f9734c1934145a315594b7986398496841c7031a5a1bbdbd"
|
||||||
|
"checksum libffi 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d8a9dac273181f514d742b6b858be5153570c5b80dd4d6020093c0fa584578b1"
|
||||||
|
"checksum libffi-sys 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4675d5d7fdbba34b66218fae3b0d528c2b29580a64ca2ccc5bbfc5af2324b373"
|
||||||
|
"checksum libloading 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "fd38073de8f7965d0c17d30546d4bb6da311ab428d1c7a3fc71dff7f9d4979b9"
|
||||||
|
"checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b"
|
||||||
|
"checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6"
|
||||||
|
"checksum make-cmd 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a8ca8afbe8af1785e09636acb5a41e08a765f5f0340568716c18a8700ba3c0d3"
|
||||||
|
"checksum memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "148fab2e51b4f1cfc66da2a7c32981d1d3c083a803978268bb11fe4b86925e7a"
|
||||||
|
"checksum memchr 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "db4c41318937f6e76648f42826b1d9ade5c09cafb5aef7e351240a70f39206e9"
|
||||||
|
"checksum nix 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "921f61dc817b379d0834e45d5ec45beaacfae97082090a49c2cf30dcbc30206f"
|
||||||
|
"checksum nom 3.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05aec50c70fd288702bcd93284a8444607f3292dbdf2a30de5ea5dcdbe72287b"
|
||||||
|
"checksum page_size 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f89ef58b3d32420dbd1a43d2f38ae92f6239ef12bb556ab09ca55445f5a67242"
|
||||||
|
"checksum peeking_take_while 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
|
||||||
|
"checksum pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "676e8eb2b1b4c9043511a9b7bea0915320d7e502b0a079fb03f9635a5252b18c"
|
||||||
|
"checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
|
||||||
|
"checksum redox_syscall 0.1.50 (registry+https://github.com/rust-lang/crates.io-index)" = "52ee9a534dc1301776eff45b4fa92d2c39b1d8c3d3357e6eb593e0d795506fc2"
|
||||||
|
"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
|
||||||
|
"checksum regex 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9329abc99e39129fcceabd24cf5d85b4671ef7c29c50e972bc5afe32438ec384"
|
||||||
|
"checksum regex-syntax 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7d707a4fa2637f2dca2ef9fd02225ec7661fe01a53623c1e6515b6916511f7a7"
|
||||||
|
"checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27"
|
||||||
|
"checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550"
|
||||||
|
"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096"
|
||||||
|
"checksum textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "307686869c93e71f94da64286f9a9524c0f308a9e1c87a583de8e9c9039ad3f6"
|
||||||
|
"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b"
|
||||||
|
"checksum ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86"
|
||||||
|
"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526"
|
||||||
|
"checksum utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "796f7e48bef87609f7ade7e06495a87d5cd06c7866e6a5cbfceffc558a243737"
|
||||||
|
"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"
|
||||||
|
"checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd"
|
||||||
|
"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
|
||||||
|
"checksum which 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e84a603e7e0b1ce1aa1ee2b109c7be00155ce52df5081590d1ffb93f4f515cb2"
|
||||||
|
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
|
||||||
|
"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0"
|
||||||
|
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
|
||||||
|
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||||
|
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
12
lib/runtime/Cargo.toml
Normal file
12
lib/runtime/Cargo.toml
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
[package]
|
||||||
|
name = "wasmer-runtime"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Lachlan Sneff <lachlan.sneff@gmail.com>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
hashbrown = "0.1"
|
||||||
|
libffi = "0.6.4"
|
||||||
|
nix = "0.12.0"
|
||||||
|
page_size = "0.4.1"
|
||||||
|
errno = "0.2.4"
|
11
lib/runtime/src/backend.rs
Normal file
11
lib/runtime/src/backend.rs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
use crate::{module::Module, types::FuncIndex, vm};
|
||||||
|
use std::ptr::NonNull;
|
||||||
|
|
||||||
|
pub trait Compiler {
|
||||||
|
/// Compiles a `Module` from WebAssembly binary format
|
||||||
|
fn compile(&self, wasm: &[u8]) -> Result<Module, String>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait FuncResolver {
|
||||||
|
fn get(&self, module: &Module, index: FuncIndex) -> Option<NonNull<vm::Func>>;
|
||||||
|
}
|
326
lib/runtime/src/backing.rs
Normal file
326
lib/runtime/src/backing.rs
Normal file
@ -0,0 +1,326 @@
|
|||||||
|
use crate::{
|
||||||
|
instance::{Import, ImportResolver},
|
||||||
|
memory::LinearMemory,
|
||||||
|
module::{ImportName, Module},
|
||||||
|
table::{TableBacking, TableElements},
|
||||||
|
types::{Initializer, MapIndex, Value},
|
||||||
|
vm,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct LocalBacking {
|
||||||
|
pub memories: Box<[LinearMemory]>,
|
||||||
|
pub tables: Box<[TableBacking]>,
|
||||||
|
|
||||||
|
pub vm_memories: Box<[vm::LocalMemory]>,
|
||||||
|
pub vm_tables: Box<[vm::LocalTable]>,
|
||||||
|
pub vm_globals: Box<[vm::LocalGlobal]>,
|
||||||
|
pub vm_signatures: Box<[vm::SigId]>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LocalBacking {
|
||||||
|
pub fn new(module: &Module, imports: &ImportBacking) -> Self {
|
||||||
|
let mut memories = Self::generate_memories(module);
|
||||||
|
let mut tables = Self::generate_tables(module);
|
||||||
|
let globals = Self::generate_globals(module);
|
||||||
|
|
||||||
|
let vm_memories = Self::finalize_memories(module, &mut memories[..]);
|
||||||
|
let vm_tables = Self::finalize_tables(module, imports, &mut tables[..]);
|
||||||
|
let vm_globals = Self::finalize_globals(module, imports, globals);
|
||||||
|
let vm_signatures = module.sig_registry.into_vm_sigid();
|
||||||
|
|
||||||
|
Self {
|
||||||
|
memories,
|
||||||
|
tables,
|
||||||
|
|
||||||
|
vm_memories,
|
||||||
|
vm_tables,
|
||||||
|
vm_globals,
|
||||||
|
vm_signatures,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_memories(module: &Module) -> Box<[LinearMemory]> {
|
||||||
|
let mut memories = Vec::with_capacity(module.memories.len());
|
||||||
|
|
||||||
|
for (_, mem) in &module.memories {
|
||||||
|
// If we use emscripten, we set a fixed initial and maximum
|
||||||
|
debug!("Instance - init memory ({}, {:?})", mem.min, mem.max);
|
||||||
|
// let memory = if options.abi == InstanceABI::Emscripten {
|
||||||
|
// // We use MAX_PAGES, so at the end the result is:
|
||||||
|
// // (initial * LinearMemory::PAGE_SIZE) == LinearMemory::DEFAULT_HEAP_SIZE
|
||||||
|
// // However, it should be: (initial * LinearMemory::PAGE_SIZE) == 16777216
|
||||||
|
// LinearMemory::new(LinearMemory::MAX_PAGES, None)
|
||||||
|
// } else {
|
||||||
|
// LinearMemory::new(memory.minimum, memory.maximum.map(|m| m as u32))
|
||||||
|
// };
|
||||||
|
let memory = LinearMemory::new(mem);
|
||||||
|
memories.push(memory);
|
||||||
|
}
|
||||||
|
|
||||||
|
memories.into_boxed_slice()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn finalize_memories(module: &Module, memories: &mut [LinearMemory]) -> Box<[vm::LocalMemory]> {
|
||||||
|
for init in &module.data_initializers {
|
||||||
|
assert!(init.base.is_none(), "global base not supported yet");
|
||||||
|
assert!(
|
||||||
|
init.offset + init.data.len() <= memories[init.memory_index.index()].current_size()
|
||||||
|
);
|
||||||
|
let offset = init.offset;
|
||||||
|
let mem: &mut LinearMemory = &mut memories[init.memory_index.index()];
|
||||||
|
// let end_of_init = offset + init.data.len();
|
||||||
|
// if end_of_init > mem.current_size() {
|
||||||
|
// let grow_pages = (end_of_init / LinearMemory::PAGE_SIZE as usize) + 1;
|
||||||
|
// mem.grow(grow_pages as u32)
|
||||||
|
// .expect("failed to grow memory for data initializers");
|
||||||
|
// }
|
||||||
|
let to_init = &mut mem[offset..offset + init.data.len()];
|
||||||
|
to_init.copy_from_slice(&init.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
memories
|
||||||
|
.iter_mut()
|
||||||
|
.map(|mem| mem.into_vm_memory())
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.into_boxed_slice()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_tables(module: &Module) -> Box<[TableBacking]> {
|
||||||
|
let mut tables = Vec::with_capacity(module.tables.len());
|
||||||
|
|
||||||
|
for (_, table) in &module.tables {
|
||||||
|
let table_backing = TableBacking::new(table);
|
||||||
|
tables.push(table_backing);
|
||||||
|
}
|
||||||
|
|
||||||
|
tables.into_boxed_slice()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn finalize_tables(
|
||||||
|
module: &Module,
|
||||||
|
imports: &ImportBacking,
|
||||||
|
tables: &mut [TableBacking],
|
||||||
|
) -> Box<[vm::LocalTable]> {
|
||||||
|
for init in &module.table_initializers {
|
||||||
|
assert!(init.base.is_none(), "global base not supported yet");
|
||||||
|
let table = &mut tables[init.table_index.index()];
|
||||||
|
match table.elements {
|
||||||
|
TableElements::Anyfunc(ref mut elements) => {
|
||||||
|
for (i, &func_index) in init.elements.iter().enumerate() {
|
||||||
|
|
||||||
|
let sig_index = module.func_assoc[func_index];
|
||||||
|
let vm_sig_id = vm::SigId(sig_index.index() as u32);
|
||||||
|
|
||||||
|
let func_data = if module.is_imported_function(func_index) {
|
||||||
|
imports.functions[func_index.index()].clone()
|
||||||
|
} else {
|
||||||
|
vm::ImportedFunc {
|
||||||
|
func: module
|
||||||
|
.func_resolver
|
||||||
|
.get(module, func_index)
|
||||||
|
.unwrap()
|
||||||
|
.as_ptr(),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
elements[init.offset + i] = vm::Anyfunc {
|
||||||
|
func_data,
|
||||||
|
sig_id: vm_sig_id,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tables
|
||||||
|
.iter_mut()
|
||||||
|
.map(|table| table.into_vm_table())
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.into_boxed_slice()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_globals(module: &Module) -> Box<[vm::LocalGlobal]> {
|
||||||
|
let globals = vec![vm::LocalGlobal::null(); module.globals.len()];
|
||||||
|
|
||||||
|
globals.into_boxed_slice()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn finalize_globals(
|
||||||
|
module: &Module,
|
||||||
|
imports: &ImportBacking,
|
||||||
|
mut globals: Box<[vm::LocalGlobal]>,
|
||||||
|
) -> Box<[vm::LocalGlobal]> {
|
||||||
|
for (to, (_, from)) in globals.iter_mut().zip(module.globals.into_iter()) {
|
||||||
|
to.data = match from.init {
|
||||||
|
Initializer::Const(Value::I32(x)) => x as u64,
|
||||||
|
Initializer::Const(Value::I64(x)) => x as u64,
|
||||||
|
Initializer::Const(Value::F32(x)) => x as u64,
|
||||||
|
Initializer::Const(Value::F64(x)) => x,
|
||||||
|
Initializer::GetGlobal(index) => (imports.globals[index.index()].global).data,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
globals
|
||||||
|
}
|
||||||
|
|
||||||
|
// fn generate_tables(module: &Module, _options: &InstanceOptions) -> (Box<[TableBacking]>, Box<[vm::LocalTable]>) {
|
||||||
|
// let mut tables = Vec::new();
|
||||||
|
// // Reserve space for tables
|
||||||
|
// tables.reserve_exact(module.info.tables.len());
|
||||||
|
|
||||||
|
// // Get tables in module
|
||||||
|
// for table in &module.info.tables {
|
||||||
|
// let table: Vec<usize> = match table.import_name.as_ref() {
|
||||||
|
// Some((module_name, field_name)) => {
|
||||||
|
// let imported =
|
||||||
|
// import_object.get(&module_name.as_str(), &field_name.as_str());
|
||||||
|
// match imported {
|
||||||
|
// Some(ImportValue::Table(t)) => t.to_vec(),
|
||||||
|
// None => {
|
||||||
|
// if options.mock_missing_tables {
|
||||||
|
// debug!(
|
||||||
|
// "The Imported table {}.{} is not provided, therefore will be mocked.",
|
||||||
|
// module_name, field_name
|
||||||
|
// );
|
||||||
|
// let len = table.entity.minimum as usize;
|
||||||
|
// let mut v = Vec::with_capacity(len);
|
||||||
|
// v.resize(len, 0);
|
||||||
|
// v
|
||||||
|
// } else {
|
||||||
|
// panic!(
|
||||||
|
// "Imported table value was not provided ({}.{})",
|
||||||
|
// module_name, field_name
|
||||||
|
// )
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// _ => panic!(
|
||||||
|
// "Expected global table, but received {:?} ({}.{})",
|
||||||
|
// imported, module_name, field_name
|
||||||
|
// ),
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// None => {
|
||||||
|
// let len = table.entity.minimum as usize;
|
||||||
|
// let mut v = Vec::with_capacity(len);
|
||||||
|
// v.resize(len, 0);
|
||||||
|
// v
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
// tables.push(table);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // instantiate tables
|
||||||
|
// for table_element in &module.info.table_elements {
|
||||||
|
// let base = match table_element.base {
|
||||||
|
// Some(global_index) => globals_data[global_index.index()] as usize,
|
||||||
|
// None => 0,
|
||||||
|
// };
|
||||||
|
|
||||||
|
// let table = &mut tables[table_element.table_index.index()];
|
||||||
|
// for (i, func_index) in table_element.elements.iter().enumerate() {
|
||||||
|
// // since the table just contains functions in the MVP
|
||||||
|
// // we get the address of the specified function indexes
|
||||||
|
// // to populate the table.
|
||||||
|
|
||||||
|
// // let func_index = *elem_index - module.info.imported_funcs.len() as u32;
|
||||||
|
// // let func_addr = functions[func_index.index()].as_ptr();
|
||||||
|
// let func_addr = get_function_addr(&func_index, &import_functions, &functions);
|
||||||
|
// table[base + table_element.offset + i] = func_addr as _;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ImportBacking {
|
||||||
|
pub functions: Box<[vm::ImportedFunc]>,
|
||||||
|
pub memories: Box<[vm::ImportedMemory]>,
|
||||||
|
pub tables: Box<[vm::ImportedTable]>,
|
||||||
|
pub globals: Box<[vm::ImportedGlobal]>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ImportBacking {
|
||||||
|
pub fn new(module: &Module, imports: &dyn ImportResolver) -> Result<Self, String> {
|
||||||
|
assert!(
|
||||||
|
module.imported_memories.len() == 0,
|
||||||
|
"imported memories not yet supported"
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
module.imported_tables.len() == 0,
|
||||||
|
"imported tables not yet supported"
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut functions = Vec::with_capacity(module.imported_functions.len());
|
||||||
|
for (
|
||||||
|
index,
|
||||||
|
ImportName {
|
||||||
|
module: mod_name,
|
||||||
|
name: item_name,
|
||||||
|
},
|
||||||
|
) in &module.imported_functions
|
||||||
|
{
|
||||||
|
let sig_index = module.func_assoc[index];
|
||||||
|
let expected_sig = module.sig_registry.lookup_func_sig(sig_index);
|
||||||
|
let import = imports.get(mod_name, item_name);
|
||||||
|
if let Some(&Import::Func(func, ref signature)) = import {
|
||||||
|
if expected_sig == signature {
|
||||||
|
functions.push(vm::ImportedFunc {
|
||||||
|
func,
|
||||||
|
// vmctx: ptr::null_mut(),
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return Err(format!(
|
||||||
|
"unexpected signature for {:?}:{:?}",
|
||||||
|
mod_name, item_name
|
||||||
|
));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Err(format!("incorrect type for {:?}:{:?}", mod_name, item_name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut globals = Vec::with_capacity(module.imported_globals.len());
|
||||||
|
for (
|
||||||
|
_,
|
||||||
|
(
|
||||||
|
ImportName {
|
||||||
|
module: mod_name,
|
||||||
|
name: item_name,
|
||||||
|
},
|
||||||
|
global_desc,
|
||||||
|
),
|
||||||
|
) in &module.imported_globals
|
||||||
|
{
|
||||||
|
let import = imports.get(mod_name, item_name);
|
||||||
|
if let Some(&Import::Global(val)) = import {
|
||||||
|
if val.ty() == global_desc.ty {
|
||||||
|
globals.push(vm::ImportedGlobal {
|
||||||
|
global: vm::LocalGlobal {
|
||||||
|
data: match val {
|
||||||
|
Value::I32(n) => n as u64,
|
||||||
|
Value::I64(n) => n as u64,
|
||||||
|
Value::F32(n) => n as u64,
|
||||||
|
Value::F64(n) => n,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return Err(format!(
|
||||||
|
"unexpected global type for {:?}:{:?}",
|
||||||
|
mod_name, item_name
|
||||||
|
));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Err(format!("incorrect type for {:?}:{:?}", mod_name, item_name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(ImportBacking {
|
||||||
|
functions: functions.into_boxed_slice(),
|
||||||
|
memories: vec![].into_boxed_slice(),
|
||||||
|
tables: vec![].into_boxed_slice(),
|
||||||
|
globals: globals.into_boxed_slice(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
174
lib/runtime/src/instance.rs
Normal file
174
lib/runtime/src/instance.rs
Normal file
@ -0,0 +1,174 @@
|
|||||||
|
use crate::recovery::call_protected;
|
||||||
|
use crate::{
|
||||||
|
backing::{ImportBacking, LocalBacking},
|
||||||
|
memory::LinearMemory,
|
||||||
|
module::{Export, Module},
|
||||||
|
table::TableBacking,
|
||||||
|
types::{FuncIndex, FuncSig, Memory, Table, Type, Value},
|
||||||
|
vm,
|
||||||
|
};
|
||||||
|
use hashbrown::HashMap;
|
||||||
|
use libffi::high::{arg as libffi_arg, call as libffi_call, CodePtr};
|
||||||
|
use std::iter;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
pub struct Instance {
|
||||||
|
pub(crate) backing: LocalBacking,
|
||||||
|
import_backing: ImportBacking,
|
||||||
|
pub module: Module,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Instance {
|
||||||
|
pub(crate) fn new(module: Module, imports: &dyn ImportResolver) -> Result<Box<Instance>, String> {
|
||||||
|
let import_backing = ImportBacking::new(&module, imports)?;
|
||||||
|
let backing = LocalBacking::new(&module, &import_backing);
|
||||||
|
|
||||||
|
let start_func = module.start_func;
|
||||||
|
|
||||||
|
let mut instance = Box::new(Instance {
|
||||||
|
backing,
|
||||||
|
import_backing,
|
||||||
|
module,
|
||||||
|
});
|
||||||
|
|
||||||
|
if let Some(start_index) = start_func {
|
||||||
|
instance.call_with_index(start_index, &[])?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(instance)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Call an exported webassembly function given the export name.
|
||||||
|
/// Pass arguments by wrapping each one in the `Val` enum.
|
||||||
|
/// The returned value is also returned in a `Val`.
|
||||||
|
///
|
||||||
|
/// This will eventually return `Result<Option<Vec<Val>>, String>` in
|
||||||
|
/// order to support multi-value returns.
|
||||||
|
pub fn call(&mut self, name: &str, args: &[Value]) -> Result<Option<Value>, String> {
|
||||||
|
let func_index = *self
|
||||||
|
.module
|
||||||
|
.exports
|
||||||
|
.get(name)
|
||||||
|
.ok_or_else(|| "there is no export with that name".to_string())
|
||||||
|
.and_then(|export| match export {
|
||||||
|
Export::Func(func_index) => Ok(func_index),
|
||||||
|
_ => Err("that export is not a function".to_string()),
|
||||||
|
})?;
|
||||||
|
|
||||||
|
self.call_with_index(func_index, args)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn call_with_index(
|
||||||
|
&mut self,
|
||||||
|
func_index: FuncIndex,
|
||||||
|
args: &[Value],
|
||||||
|
) -> Result<Option<Value>, String> {
|
||||||
|
// Check the function signature.
|
||||||
|
let sig_index = *self
|
||||||
|
.module
|
||||||
|
.func_assoc
|
||||||
|
.get(func_index)
|
||||||
|
.expect("broken invariant, incorrect func index");
|
||||||
|
|
||||||
|
{
|
||||||
|
let signature = self.module.sig_registry.lookup_func_sig(sig_index);
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
signature.returns.len() <= 1,
|
||||||
|
"multi-value returns not yet supported"
|
||||||
|
);
|
||||||
|
|
||||||
|
if !signature.check_sig(args) {
|
||||||
|
return Err("incorrect signature".to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// the vmctx will be located at the same place on the stack the entire time that this
|
||||||
|
// wasm function is running.
|
||||||
|
let mut vmctx = vm::Ctx::new(
|
||||||
|
&mut self.backing,
|
||||||
|
&mut self.import_backing,
|
||||||
|
);
|
||||||
|
let vmctx_ptr = &mut vmctx as *mut vm::Ctx;
|
||||||
|
|
||||||
|
let libffi_args: Vec<_> = args
|
||||||
|
.iter()
|
||||||
|
.map(|val| match val {
|
||||||
|
Value::I32(ref x) => libffi_arg(x),
|
||||||
|
Value::I64(ref x) => libffi_arg(x),
|
||||||
|
Value::F32(ref x) => libffi_arg(x),
|
||||||
|
Value::F64(ref x) => libffi_arg(x),
|
||||||
|
})
|
||||||
|
.chain(iter::once(libffi_arg(&vmctx_ptr)))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let func_ptr = CodePtr::from_ptr(
|
||||||
|
self.module
|
||||||
|
.func_resolver
|
||||||
|
.get(&self.module, func_index)
|
||||||
|
.expect("broken invariant, func resolver not synced with module.exports")
|
||||||
|
.cast()
|
||||||
|
.as_ptr(),
|
||||||
|
);
|
||||||
|
|
||||||
|
call_protected(|| {
|
||||||
|
self.module.sig_registry.lookup_func_sig(sig_index)
|
||||||
|
.returns
|
||||||
|
.first()
|
||||||
|
.map(|ty| match ty {
|
||||||
|
Type::I32 => Value::I32(unsafe { libffi_call(func_ptr, &libffi_args) }),
|
||||||
|
Type::I64 => Value::I64(unsafe { libffi_call(func_ptr, &libffi_args) }),
|
||||||
|
Type::F32 => Value::F32(unsafe { libffi_call(func_ptr, &libffi_args) }),
|
||||||
|
Type::F64 => Value::F64(unsafe { libffi_call(func_ptr, &libffi_args) }),
|
||||||
|
})
|
||||||
|
.or_else(|| {
|
||||||
|
// call with no returns
|
||||||
|
unsafe {
|
||||||
|
libffi_call::<()>(func_ptr, &libffi_args);
|
||||||
|
}
|
||||||
|
None
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Import {
|
||||||
|
Func(*const vm::Func, FuncSig),
|
||||||
|
Table(Arc<TableBacking>, Table),
|
||||||
|
Memory(Arc<LinearMemory>, Memory),
|
||||||
|
Global(Value),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Imports {
|
||||||
|
map: HashMap<String, HashMap<String, Import>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Imports {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
map: HashMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add(&mut self, module: String, name: String, import: Import) {
|
||||||
|
self.map
|
||||||
|
.entry(module)
|
||||||
|
.or_insert(HashMap::new())
|
||||||
|
.insert(name, import);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get(&self, module: &str, name: &str) -> Option<&Import> {
|
||||||
|
self.map.get(module).and_then(|m| m.get(name))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ImportResolver for Imports {
|
||||||
|
fn get(&self, module: &str, name: &str) -> Option<&Import> {
|
||||||
|
self.get(module, name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait ImportResolver {
|
||||||
|
fn get(&self, module: &str, name: &str) -> Option<&Import>;
|
||||||
|
}
|
29
lib/runtime/src/lib.rs
Normal file
29
lib/runtime/src/lib.rs
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
#[macro_use]
|
||||||
|
mod macros;
|
||||||
|
mod backend;
|
||||||
|
mod backing;
|
||||||
|
mod instance;
|
||||||
|
mod memory;
|
||||||
|
mod module;
|
||||||
|
mod sig_registry;
|
||||||
|
mod table;
|
||||||
|
mod recovery;
|
||||||
|
mod sighandler;
|
||||||
|
mod mmap;
|
||||||
|
pub mod types;
|
||||||
|
pub mod vm;
|
||||||
|
pub mod vmcalls;
|
||||||
|
|
||||||
|
pub use self::backend::{Compiler, FuncResolver};
|
||||||
|
pub use self::instance::{Import, ImportResolver, Imports, Instance};
|
||||||
|
pub use self::module::Module;
|
||||||
|
pub use self::sig_registry::SigRegistry;
|
||||||
|
pub use self::memory::LinearMemory;
|
||||||
|
|
||||||
|
/// Compile a webassembly module using the provided compiler.
|
||||||
|
pub fn compile(
|
||||||
|
wasm: &[u8],
|
||||||
|
compiler: &dyn Compiler,
|
||||||
|
) -> Result<Module, String> {
|
||||||
|
compiler.compile(wasm)
|
||||||
|
}
|
5
lib/runtime/src/macros.rs
Normal file
5
lib/runtime/src/macros.rs
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
#[macro_export]
|
||||||
|
macro_rules! debug {
|
||||||
|
($fmt:expr) => (if cfg!(any(debug_assertions, feature="debug")) { println!(concat!("wasmer-runtime(:{})::", $fmt), line!()) });
|
||||||
|
($fmt:expr, $($arg:tt)*) => (if cfg!(any(debug_assertions, feature="debug")) { println!(concat!("wasmer-runtime(:{})::", $fmt, "\n"), line!(), $($arg)*) });
|
||||||
|
}
|
225
lib/runtime/src/memory.rs
Normal file
225
lib/runtime/src/memory.rs
Normal file
@ -0,0 +1,225 @@
|
|||||||
|
//! The webassembly::Memory() constructor creates a new Memory object which is
|
||||||
|
//! a structure that holds the raw bytes of memory accessed by a
|
||||||
|
//! webassembly::Instance.
|
||||||
|
//! A memory created by Rust or in WebAssembly code will be accessible and
|
||||||
|
//! mutable from both Rust and WebAssembly.
|
||||||
|
use std::ops::{Deref, DerefMut};
|
||||||
|
|
||||||
|
use crate::{types::Memory, vm::LocalMemory, mmap::{Mmap, Protect}};
|
||||||
|
|
||||||
|
/// A linear memory instance.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct LinearMemory {
|
||||||
|
/// The actual memory allocation.
|
||||||
|
mmap: Mmap,
|
||||||
|
|
||||||
|
/// The current number of wasm pages.
|
||||||
|
current: u32,
|
||||||
|
|
||||||
|
// The maximum size the WebAssembly Memory is allowed to grow
|
||||||
|
// to, in units of WebAssembly pages. When present, the maximum
|
||||||
|
// parameter acts as a hint to the engine to reserve memory up
|
||||||
|
// front. However, the engine may ignore or clamp this reservation
|
||||||
|
// request. In general, most WebAssembly modules shouldn't need
|
||||||
|
// to set a maximum.
|
||||||
|
max: Option<u32>,
|
||||||
|
|
||||||
|
// The size of the extra guard pages after the end.
|
||||||
|
// Is used to optimize loads and stores with constant offsets.
|
||||||
|
offset_guard_size: usize,
|
||||||
|
|
||||||
|
/// Requires exception catching to handle out-of-bounds accesses.
|
||||||
|
requires_signal_catch: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// It holds the raw bytes of memory accessed by a WebAssembly Instance
|
||||||
|
impl LinearMemory {
|
||||||
|
pub const PAGE_SIZE: u32 = 65_536;
|
||||||
|
pub const MAX_PAGES: u32 = 65_536;
|
||||||
|
pub const DEFAULT_HEAP_SIZE: usize = 1 << 32; // 4 GiB
|
||||||
|
pub const DEFAULT_GUARD_SIZE: usize = 1 << 31; // 2 GiB
|
||||||
|
pub const DEFAULT_SIZE: usize = Self::DEFAULT_HEAP_SIZE + Self::DEFAULT_GUARD_SIZE; // 6 GiB
|
||||||
|
|
||||||
|
/// Create a new linear memory instance with specified initial and maximum number of pages.
|
||||||
|
///
|
||||||
|
/// `maximum` cannot be set to more than `65536` pages.
|
||||||
|
pub fn new(mem: &Memory) -> Self {
|
||||||
|
assert!(mem.min <= Self::MAX_PAGES);
|
||||||
|
assert!(mem.max.is_none() || mem.max.unwrap() <= Self::MAX_PAGES);
|
||||||
|
debug!("Instantiate LinearMemory(mem: {:?})", mem);
|
||||||
|
|
||||||
|
let (mmap_size, initial_pages, offset_guard_size, requires_signal_catch) =
|
||||||
|
if mem.is_static_heap() {
|
||||||
|
(Self::DEFAULT_SIZE, mem.min, Self::DEFAULT_GUARD_SIZE, true)
|
||||||
|
// This is a static heap
|
||||||
|
} else {
|
||||||
|
// this is a dynamic heap
|
||||||
|
assert!(!mem.shared, "shared memories must have a maximum size.");
|
||||||
|
|
||||||
|
(
|
||||||
|
mem.min as usize * Self::PAGE_SIZE as usize,
|
||||||
|
mem.min,
|
||||||
|
0,
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut mmap = Mmap::with_size(mmap_size).unwrap();
|
||||||
|
|
||||||
|
// map initial pages as readwrite since the inital mmap is mapped as not accessible.
|
||||||
|
if initial_pages != 0 {
|
||||||
|
unsafe {
|
||||||
|
mmap.protect(0..(initial_pages as usize * Self::PAGE_SIZE as usize), Protect::ReadWrite)
|
||||||
|
.expect("unable to make memory accessible");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Self {
|
||||||
|
mmap,
|
||||||
|
current: initial_pages,
|
||||||
|
max: mem.max,
|
||||||
|
offset_guard_size,
|
||||||
|
requires_signal_catch,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns an base address of this linear memory.
|
||||||
|
pub fn base(&mut self) -> *mut u8 {
|
||||||
|
self.mmap.as_ptr()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a number of allocated wasm pages.
|
||||||
|
pub fn current_size(&self) -> usize {
|
||||||
|
self.current as usize * Self::PAGE_SIZE as usize
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn current_pages(&self) -> u32 {
|
||||||
|
self.current
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the maximum number of wasm pages allowed.
|
||||||
|
pub fn maximum_size(&self) -> u32 {
|
||||||
|
self.max.unwrap_or(Self::MAX_PAGES)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn into_vm_memory(&mut self) -> LocalMemory {
|
||||||
|
LocalMemory {
|
||||||
|
base: self.base(),
|
||||||
|
size: self.current_size(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Grow memory by the specified amount of pages.
|
||||||
|
///
|
||||||
|
/// Returns `None` if memory can't be grown by the specified amount
|
||||||
|
/// of pages.
|
||||||
|
pub fn grow_dynamic(&mut self, add_pages: u32) -> Option<i32> {
|
||||||
|
debug!("grow_memory_dynamic called!");
|
||||||
|
assert!(self.max.is_none());
|
||||||
|
if add_pages == 0 {
|
||||||
|
return Some(self.current as _);
|
||||||
|
}
|
||||||
|
|
||||||
|
let prev_pages = self.current;
|
||||||
|
|
||||||
|
let new_pages = match self.current.checked_add(add_pages) {
|
||||||
|
Some(new_pages) => new_pages,
|
||||||
|
None => return None,
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(val) = self.max {
|
||||||
|
if new_pages > val {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
// Wasm linear memories are never allowed to grow beyond what is
|
||||||
|
// indexable. If the memory has no maximum, enforce the greatest
|
||||||
|
// limit here.
|
||||||
|
} else if new_pages >= Self::MAX_PAGES {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let new_bytes = (new_pages * Self::PAGE_SIZE) as usize;
|
||||||
|
|
||||||
|
if new_bytes > self.mmap.size() - self.offset_guard_size {
|
||||||
|
let mmap_size = new_bytes.checked_add(self.offset_guard_size)?;
|
||||||
|
let mut new_mmap = Mmap::with_size(mmap_size).ok()?;
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
new_mmap.protect(0..new_bytes, Protect::ReadWrite).ok()?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let copy_size = self.mmap.size() - self.offset_guard_size;
|
||||||
|
unsafe {
|
||||||
|
new_mmap.as_slice_mut()[..copy_size]
|
||||||
|
.copy_from_slice(&self.mmap.as_slice()[..copy_size]);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.mmap = new_mmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.current = new_pages;
|
||||||
|
|
||||||
|
Some(prev_pages as i32)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn grow_static(&mut self, add_pages: u32) -> Option<i32> {
|
||||||
|
debug!("grow_memory_static called!");
|
||||||
|
assert!(self.max.is_some());
|
||||||
|
if add_pages == 0 {
|
||||||
|
return Some(self.current as _);
|
||||||
|
}
|
||||||
|
|
||||||
|
let prev_pages = self.current;
|
||||||
|
|
||||||
|
let new_pages = match self.current.checked_add(add_pages) {
|
||||||
|
Some(new_pages) => new_pages,
|
||||||
|
None => return None,
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(val) = self.max {
|
||||||
|
if new_pages > val {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
// Wasm linear memories are never allowed to grow beyond what is
|
||||||
|
// indexable. If the memory has no maximum, enforce the greatest
|
||||||
|
// limit here.
|
||||||
|
} else if new_pages >= Self::MAX_PAGES {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let prev_bytes = (prev_pages * Self::PAGE_SIZE) as usize;
|
||||||
|
let new_bytes = (new_pages * Self::PAGE_SIZE) as usize;
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
self.mmap.protect(prev_bytes..new_bytes, Protect::ReadWrite).ok()?;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.current = new_pages;
|
||||||
|
|
||||||
|
Some(prev_pages as i32)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not comparing based on memory content. That would be inefficient.
|
||||||
|
impl PartialEq for LinearMemory {
|
||||||
|
fn eq(&self, other: &LinearMemory) -> bool {
|
||||||
|
self.current == other.current && self.max == other.max
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for LinearMemory {
|
||||||
|
type Target = [u8];
|
||||||
|
fn deref(&self) -> &[u8] {
|
||||||
|
unsafe {
|
||||||
|
self.mmap.as_slice()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DerefMut for LinearMemory {
|
||||||
|
fn deref_mut(&mut self) -> &mut [u8] {
|
||||||
|
unsafe {
|
||||||
|
self.mmap.as_slice_mut()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
103
lib/runtime/src/mmap.rs
Normal file
103
lib/runtime/src/mmap.rs
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
use std::{slice, ptr};
|
||||||
|
use std::ops::Range;
|
||||||
|
use nix::libc;
|
||||||
|
use page_size;
|
||||||
|
use errno;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Mmap {
|
||||||
|
ptr: *mut u8,
|
||||||
|
size: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Mmap {
|
||||||
|
pub fn with_size(size: usize) -> Result<Self, String> {
|
||||||
|
if size == 0 {
|
||||||
|
return Ok(Self {
|
||||||
|
ptr: ptr::null_mut(),
|
||||||
|
size: 0,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let size = round_up_to_page_size(size, page_size::get());
|
||||||
|
|
||||||
|
let ptr = unsafe {
|
||||||
|
libc::mmap(
|
||||||
|
ptr::null_mut(),
|
||||||
|
size,
|
||||||
|
libc::PROT_NONE,
|
||||||
|
libc::MAP_PRIVATE | libc::MAP_ANON,
|
||||||
|
-1,
|
||||||
|
0,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
if ptr == -1 as _ {
|
||||||
|
Err(errno::errno().to_string())
|
||||||
|
} else {
|
||||||
|
Ok(Self {
|
||||||
|
ptr: ptr as *mut u8,
|
||||||
|
size,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn protect(&mut self, range: Range<usize>, protect: Protect) -> Result<(), String> {
|
||||||
|
let page_size = page_size::get();
|
||||||
|
let start = self.ptr.add(round_down_to_page_size(range.start, page_size));
|
||||||
|
let size = range.end - range.start;
|
||||||
|
|
||||||
|
let success = libc::mprotect(start as _, size, protect as i32);
|
||||||
|
if success == -1 {
|
||||||
|
Err(errno::errno().to_string())
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn size(&self) -> usize {
|
||||||
|
self.size
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn as_slice(&self) -> &[u8] {
|
||||||
|
slice::from_raw_parts(self.ptr, self.size)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn as_slice_mut(&mut self) -> &mut [u8] {
|
||||||
|
slice::from_raw_parts_mut(self.ptr, self.size)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_ptr(&mut self) -> *mut u8 {
|
||||||
|
self.ptr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for Mmap {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
if !self.ptr.is_null() {
|
||||||
|
let success = unsafe { libc::munmap(self.ptr as _, self.size) };
|
||||||
|
assert_eq!(success, 0, "failed to unmap memory: {}", errno::errno());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub enum Protect {
|
||||||
|
None = 0,
|
||||||
|
Read = 1,
|
||||||
|
Write = 2,
|
||||||
|
ReadWrite = 1 | 2,
|
||||||
|
Exec = 4,
|
||||||
|
ReadExec = 1 | 4,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Round `size` up to the nearest multiple of `page_size`.
|
||||||
|
fn round_up_to_page_size(size: usize, page_size: usize) -> usize {
|
||||||
|
(size + (page_size - 1)) & !(page_size - 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Round `size` down to the nearest multiple of `page_size`.
|
||||||
|
fn round_down_to_page_size(size: usize, page_size: usize) -> usize {
|
||||||
|
size & !(page_size-1)
|
||||||
|
}
|
113
lib/runtime/src/module.rs
Normal file
113
lib/runtime/src/module.rs
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
use crate::{
|
||||||
|
backend::FuncResolver,
|
||||||
|
types::{
|
||||||
|
FuncIndex, Global, GlobalDesc, GlobalIndex, Map, MapIndex, Memory, MemoryIndex,
|
||||||
|
SigIndex, Table, TableIndex,
|
||||||
|
},
|
||||||
|
sig_registry::SigRegistry,
|
||||||
|
ImportResolver,
|
||||||
|
Instance,
|
||||||
|
};
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::ops::Deref;
|
||||||
|
use hashbrown::HashMap;
|
||||||
|
|
||||||
|
/// This is used to instantiate a new webassembly module.
|
||||||
|
pub struct ModuleInner {
|
||||||
|
pub func_resolver: Box<dyn FuncResolver>,
|
||||||
|
pub memories: Map<MemoryIndex, Memory>,
|
||||||
|
pub globals: Map<GlobalIndex, Global>,
|
||||||
|
pub tables: Map<TableIndex, Table>,
|
||||||
|
|
||||||
|
pub imported_functions: Map<FuncIndex, ImportName>,
|
||||||
|
pub imported_memories: Map<MemoryIndex, (ImportName, Memory)>,
|
||||||
|
pub imported_tables: Map<TableIndex, (ImportName, Table)>,
|
||||||
|
pub imported_globals: Map<GlobalIndex, (ImportName, GlobalDesc)>,
|
||||||
|
|
||||||
|
pub exports: HashMap<String, Export>,
|
||||||
|
|
||||||
|
pub data_initializers: Vec<DataInitializer>,
|
||||||
|
pub table_initializers: Vec<TableInitializer>,
|
||||||
|
pub start_func: Option<FuncIndex>,
|
||||||
|
|
||||||
|
pub func_assoc: Map<FuncIndex, SigIndex>,
|
||||||
|
pub sig_registry: SigRegistry,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Module(Arc<ModuleInner>);
|
||||||
|
|
||||||
|
impl Module {
|
||||||
|
#[inline]
|
||||||
|
pub fn new(inner: ModuleInner) -> Self {
|
||||||
|
Module(Arc::new(inner))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Instantiate a webassembly module with the provided imports.
|
||||||
|
pub fn instantiate(&self, imports: &dyn ImportResolver) -> Result<Box<Instance>, String> {
|
||||||
|
Instance::new(Module(Arc::clone(&self.0)), imports)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ModuleInner {
|
||||||
|
pub(crate) fn is_imported_function(&self, func_index: FuncIndex) -> bool {
|
||||||
|
func_index.index() < self.imported_functions.len()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for Module {
|
||||||
|
type Target = ModuleInner;
|
||||||
|
|
||||||
|
fn deref(&self) -> &ModuleInner {
|
||||||
|
&*self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct ImportName {
|
||||||
|
pub module: String,
|
||||||
|
pub name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<(String, String)> for ImportName {
|
||||||
|
fn from(n: (String, String)) -> Self {
|
||||||
|
ImportName {
|
||||||
|
module: n.0,
|
||||||
|
name: n.1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub enum Export {
|
||||||
|
Func(FuncIndex),
|
||||||
|
Memory(MemoryIndex),
|
||||||
|
Global(GlobalIndex),
|
||||||
|
Table(TableIndex),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A data initializer for linear memory.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct DataInitializer {
|
||||||
|
/// The index of the memory to initialize.
|
||||||
|
pub memory_index: MemoryIndex,
|
||||||
|
/// Optionally a globalvalue base to initialize at.
|
||||||
|
pub base: Option<GlobalIndex>,
|
||||||
|
/// A constant offset to initialize at.
|
||||||
|
pub offset: usize,
|
||||||
|
/// The initialization data.
|
||||||
|
pub data: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A WebAssembly table initializer.
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct TableInitializer {
|
||||||
|
/// The index of a table to initialize.
|
||||||
|
pub table_index: TableIndex,
|
||||||
|
/// Optionally, a global variable giving a base index.
|
||||||
|
pub base: Option<GlobalIndex>,
|
||||||
|
/// The offset to add to the base.
|
||||||
|
pub offset: usize,
|
||||||
|
/// The values to write into the table elements.
|
||||||
|
pub elements: Vec<FuncIndex>,
|
||||||
|
}
|
72
lib/runtime/src/recovery.rs
Normal file
72
lib/runtime/src/recovery.rs
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
//! When a WebAssembly module triggers any traps, we perform recovery here.
|
||||||
|
//!
|
||||||
|
//! This module uses TLS (thread-local storage) to track recovery information. Since the four signals we're handling
|
||||||
|
//! are very special, the async signal unsafety of Rust's TLS implementation generally does not affect the correctness here
|
||||||
|
//! unless you have memory unsafety elsewhere in your code.
|
||||||
|
|
||||||
|
use crate::sighandler::install_sighandler;
|
||||||
|
use nix::libc::siginfo_t;
|
||||||
|
use nix::sys::signal::{Signal, SIGBUS, SIGFPE, SIGILL, SIGSEGV};
|
||||||
|
use std::cell::{Cell, UnsafeCell};
|
||||||
|
use std::sync::Once;
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
pub fn setjmp(env: *mut ::nix::libc::c_void) -> ::nix::libc::c_int;
|
||||||
|
fn longjmp(env: *mut ::nix::libc::c_void, val: ::nix::libc::c_int) -> !;
|
||||||
|
}
|
||||||
|
|
||||||
|
const SETJMP_BUFFER_LEN: usize = 27;
|
||||||
|
pub static SIGHANDLER_INIT: Once = Once::new();
|
||||||
|
|
||||||
|
thread_local! {
|
||||||
|
pub static SETJMP_BUFFER: UnsafeCell<[::nix::libc::c_int; SETJMP_BUFFER_LEN]> = UnsafeCell::new([0; SETJMP_BUFFER_LEN]);
|
||||||
|
pub static CAUGHT_ADDRESS: Cell<usize> = Cell::new(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn call_protected<T>(f: impl FnOnce() -> T) -> Result<T, String> {
|
||||||
|
unsafe {
|
||||||
|
let jmp_buf = SETJMP_BUFFER.with(|buf| buf.get());
|
||||||
|
let prev_jmp_buf = *jmp_buf;
|
||||||
|
|
||||||
|
SIGHANDLER_INIT.call_once(|| {
|
||||||
|
install_sighandler();
|
||||||
|
});
|
||||||
|
|
||||||
|
let signum = setjmp(jmp_buf as *mut ::nix::libc::c_void);
|
||||||
|
if signum != 0 {
|
||||||
|
*jmp_buf = prev_jmp_buf;
|
||||||
|
let addr = CAUGHT_ADDRESS.with(|cell| cell.get());
|
||||||
|
|
||||||
|
let signal = match Signal::from_c_int(signum) {
|
||||||
|
Ok(SIGFPE) => "floating-point exception",
|
||||||
|
Ok(SIGILL) => "illegal instruction",
|
||||||
|
Ok(SIGSEGV) => "segmentation violation",
|
||||||
|
Ok(SIGBUS) => "bus error",
|
||||||
|
Err(_) => "error while getting the Signal",
|
||||||
|
_ => "unkown trapped signal",
|
||||||
|
};
|
||||||
|
Err(format!("trap at {:#x} - {}", addr, signal))
|
||||||
|
} else {
|
||||||
|
let ret = f(); // TODO: Switch stack?
|
||||||
|
*jmp_buf = prev_jmp_buf;
|
||||||
|
Ok(ret)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Unwinds to last protected_call.
|
||||||
|
pub unsafe fn do_unwind(signum: i32, siginfo: *mut siginfo_t) -> ! {
|
||||||
|
// Since do_unwind is only expected to get called from WebAssembly code which doesn't hold any host resources (locks etc.)
|
||||||
|
// itself, accessing TLS here is safe. In case any other code calls this, it often indicates a memory safety bug and you should
|
||||||
|
// temporarily disable the signal handlers to debug it.
|
||||||
|
|
||||||
|
let jmp_buf = SETJMP_BUFFER.with(|buf| buf.get());
|
||||||
|
if *jmp_buf == [0; SETJMP_BUFFER_LEN] {
|
||||||
|
::std::process::abort();
|
||||||
|
}
|
||||||
|
// We only target macos at the moment as other ones might not have si_addr field
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
CAUGHT_ADDRESS.with(|cell| cell.set((*siginfo).si_addr as _));
|
||||||
|
|
||||||
|
longjmp(jmp_buf as *mut ::nix::libc::c_void, signum)
|
||||||
|
}
|
36
lib/runtime/src/sig_registry.rs
Normal file
36
lib/runtime/src/sig_registry.rs
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
use crate::{
|
||||||
|
types::{FuncSig, Map, SigIndex, MapIndex},
|
||||||
|
vm,
|
||||||
|
};
|
||||||
|
use hashbrown::HashMap;
|
||||||
|
|
||||||
|
pub struct SigRegistry {
|
||||||
|
func_table: HashMap<FuncSig, SigIndex>,
|
||||||
|
sig_assoc: Map<SigIndex, FuncSig>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SigRegistry {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
func_table: HashMap::new(),
|
||||||
|
sig_assoc: Map::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn register(&mut self, func_sig: FuncSig) -> SigIndex {
|
||||||
|
let func_table = &mut self.func_table;
|
||||||
|
let sig_assoc = &mut self.sig_assoc;
|
||||||
|
*func_table.entry(func_sig.clone()).or_insert_with(|| {
|
||||||
|
sig_assoc.push(func_sig)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn lookup_func_sig(&self, sig_index: SigIndex) -> &FuncSig {
|
||||||
|
&self.sig_assoc[sig_index]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn into_vm_sigid(&self) -> Box<[vm::SigId]> {
|
||||||
|
let v: Vec<_> = self.sig_assoc.iter().map(|(sig_index, _)| vm::SigId(sig_index.index() as u32)).collect();
|
||||||
|
v.into_boxed_slice()
|
||||||
|
}
|
||||||
|
}
|
33
lib/runtime/src/sighandler.rs
Normal file
33
lib/runtime/src/sighandler.rs
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
//! We install signal handlers to handle WebAssembly traps within
|
||||||
|
//! our Rust code. Otherwise we will have errors that stop the Rust process
|
||||||
|
//! such as `process didn't exit successfully: ... (signal: 8, SIGFPE: erroneous arithmetic operation)`
|
||||||
|
//!
|
||||||
|
//! Please read more about this here: https://github.com/CraneStation/wasmtime/issues/15
|
||||||
|
//! This code is inspired by: https://github.com/pepyakin/wasmtime/commit/625a2b6c0815b21996e111da51b9664feb174622
|
||||||
|
use crate::recovery;
|
||||||
|
use nix::libc::{c_void, siginfo_t};
|
||||||
|
use nix::sys::signal::{
|
||||||
|
sigaction, SaFlags, SigAction, SigHandler, SigSet, SIGBUS, SIGFPE, SIGILL, SIGSEGV,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub unsafe fn install_sighandler() {
|
||||||
|
let sa = SigAction::new(
|
||||||
|
SigHandler::SigAction(signal_trap_handler),
|
||||||
|
SaFlags::SA_ONSTACK,
|
||||||
|
SigSet::empty(),
|
||||||
|
);
|
||||||
|
sigaction(SIGFPE, &sa).unwrap();
|
||||||
|
sigaction(SIGILL, &sa).unwrap();
|
||||||
|
sigaction(SIGSEGV, &sa).unwrap();
|
||||||
|
sigaction(SIGBUS, &sa).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" fn signal_trap_handler(
|
||||||
|
signum: ::nix::libc::c_int,
|
||||||
|
siginfo: *mut siginfo_t,
|
||||||
|
_ucontext: *mut c_void,
|
||||||
|
) {
|
||||||
|
unsafe {
|
||||||
|
recovery::do_unwind(signum, siginfo);
|
||||||
|
}
|
||||||
|
}
|
36
lib/runtime/src/table.rs
Normal file
36
lib/runtime/src/table.rs
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
use super::vm;
|
||||||
|
use crate::types::{ElementType, Table};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum TableElements {
|
||||||
|
/// This is intended to be a caller-checked Anyfunc.
|
||||||
|
Anyfunc(Box<[vm::Anyfunc]>),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct TableBacking {
|
||||||
|
pub elements: TableElements,
|
||||||
|
pub max: Option<u32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TableBacking {
|
||||||
|
pub fn new(table: &Table) -> Self {
|
||||||
|
match table.ty {
|
||||||
|
ElementType::Anyfunc => Self {
|
||||||
|
elements: TableElements::Anyfunc(
|
||||||
|
vec![vm::Anyfunc::null(); table.min as usize].into_boxed_slice(),
|
||||||
|
),
|
||||||
|
max: table.max,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn into_vm_table(&mut self) -> vm::LocalTable {
|
||||||
|
match self.elements {
|
||||||
|
TableElements::Anyfunc(ref mut funcs) => vm::LocalTable {
|
||||||
|
base: funcs.as_mut_ptr() as *mut u8,
|
||||||
|
current_elements: funcs.len(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
322
lib/runtime/src/types.rs
Normal file
322
lib/runtime/src/types.rs
Normal file
@ -0,0 +1,322 @@
|
|||||||
|
use std::marker::PhantomData;
|
||||||
|
use std::{
|
||||||
|
iter,
|
||||||
|
ops::{Index, IndexMut},
|
||||||
|
slice,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
|
pub enum Type {
|
||||||
|
/// The `i32` type.
|
||||||
|
I32,
|
||||||
|
/// The `i64` type.
|
||||||
|
I64,
|
||||||
|
/// The `f32` type.
|
||||||
|
F32,
|
||||||
|
/// The `f64` type.
|
||||||
|
F64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub enum Value {
|
||||||
|
/// The `i32` type.
|
||||||
|
I32(i32),
|
||||||
|
/// The `i64` type.
|
||||||
|
I64(i64),
|
||||||
|
/// The `f32` type.
|
||||||
|
F32(u32),
|
||||||
|
/// The `f64` type.
|
||||||
|
F64(u64),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Value {
|
||||||
|
pub fn ty(&self) -> Type {
|
||||||
|
match self {
|
||||||
|
Value::I32(_) => Type::I32,
|
||||||
|
Value::I64(_) => Type::I64,
|
||||||
|
Value::F32(_) => Type::F32,
|
||||||
|
Value::F64(_) => Type::F64,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<i32> for Value {
|
||||||
|
fn from(i: i32) -> Self {
|
||||||
|
Value::I32(i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<i64> for Value {
|
||||||
|
fn from(i: i64) -> Self {
|
||||||
|
Value::I64(i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<f32> for Value {
|
||||||
|
fn from(f: f32) -> Self {
|
||||||
|
Value::F32(f as _)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<f64> for Value {
|
||||||
|
fn from(f: f64) -> Self {
|
||||||
|
Value::F64(f as _)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub enum ElementType {
|
||||||
|
/// Any wasm function.
|
||||||
|
Anyfunc,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub struct Table {
|
||||||
|
/// Type of data stored in this table.
|
||||||
|
pub ty: ElementType,
|
||||||
|
/// The minimum number of elements that must be stored in this table.
|
||||||
|
pub min: u32,
|
||||||
|
/// The maximum number of elements in this table.
|
||||||
|
pub max: Option<u32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A global value initializer.
|
||||||
|
/// Overtime, this will be able to represent more and more
|
||||||
|
/// complex expressions.
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub enum Initializer {
|
||||||
|
/// Corresponds to a `const.*` instruction.
|
||||||
|
Const(Value),
|
||||||
|
/// Corresponds to a `get_global` instruction.
|
||||||
|
GetGlobal(GlobalIndex),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub struct GlobalDesc {
|
||||||
|
pub mutable: bool,
|
||||||
|
pub ty: Type,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A wasm global.
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub struct Global {
|
||||||
|
pub desc: GlobalDesc,
|
||||||
|
pub init: Initializer,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A wasm memory.
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub struct Memory {
|
||||||
|
/// The minimum number of allowed pages.
|
||||||
|
pub min: u32,
|
||||||
|
/// The maximum number of allowed pages.
|
||||||
|
pub max: Option<u32>,
|
||||||
|
/// This memory can be shared between wasm threads.
|
||||||
|
pub shared: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Memory {
|
||||||
|
pub fn is_static_heap(&self) -> bool {
|
||||||
|
self.max.is_some()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A wasm func.
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub struct FuncSig {
|
||||||
|
pub params: Vec<Type>,
|
||||||
|
pub returns: Vec<Type>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FuncSig {
|
||||||
|
pub fn check_sig(&self, params: &[Value]) -> bool {
|
||||||
|
self.params.len() == params.len()
|
||||||
|
&& self
|
||||||
|
.params
|
||||||
|
.iter()
|
||||||
|
.zip(params.iter().map(|val| val.ty()))
|
||||||
|
.all(|(t0, ref t1)| t0 == t1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait MapIndex {
|
||||||
|
fn new(index: usize) -> Self;
|
||||||
|
fn index(&self) -> usize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Dense item map
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Map<I, T>
|
||||||
|
where
|
||||||
|
I: MapIndex,
|
||||||
|
{
|
||||||
|
elems: Vec<T>,
|
||||||
|
_marker: PhantomData<I>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I, T> Map<I, T>
|
||||||
|
where
|
||||||
|
I: MapIndex,
|
||||||
|
{
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
elems: Vec::new(),
|
||||||
|
_marker: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_capacity(capacity: usize) -> Self {
|
||||||
|
Self {
|
||||||
|
elems: Vec::with_capacity(capacity),
|
||||||
|
_marker: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get(&self, index: I) -> Option<&T> {
|
||||||
|
self.elems.get(index.index())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
self.elems.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push(&mut self, value: T) -> I {
|
||||||
|
let len = self.len();
|
||||||
|
self.elems.push(value);
|
||||||
|
I::new(len)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_ptr(&self) -> *const T {
|
||||||
|
self.elems.as_ptr()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn reserve_exact(&mut self, size: usize) {
|
||||||
|
self.elems.reserve_exact(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn iter(&self) -> Iter<T, I> {
|
||||||
|
Iter::new(self.elems.iter())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I, T> Index<I> for Map<I, T>
|
||||||
|
where
|
||||||
|
I: MapIndex,
|
||||||
|
{
|
||||||
|
type Output = T;
|
||||||
|
fn index(&self, index: I) -> &T {
|
||||||
|
&self.elems[index.index()]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I, T> IndexMut<I> for Map<I, T>
|
||||||
|
where
|
||||||
|
I: MapIndex,
|
||||||
|
{
|
||||||
|
fn index_mut(&mut self, index: I) -> &mut T {
|
||||||
|
&mut self.elems[index.index()]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, I, T> IntoIterator for &'a Map<I, T>
|
||||||
|
where
|
||||||
|
I: MapIndex,
|
||||||
|
{
|
||||||
|
type Item = (I, &'a T);
|
||||||
|
type IntoIter = Iter<'a, T, I>;
|
||||||
|
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
Iter::new(self.elems.iter())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, I, T> IntoIterator for &'a mut Map<I, T>
|
||||||
|
where
|
||||||
|
I: MapIndex,
|
||||||
|
{
|
||||||
|
type Item = (I, &'a mut T);
|
||||||
|
type IntoIter = IterMut<'a, T, I>;
|
||||||
|
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
IterMut::new(self.elems.iter_mut())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Iter<'a, T: 'a, I: MapIndex> {
|
||||||
|
enumerated: iter::Enumerate<slice::Iter<'a, T>>,
|
||||||
|
_marker: PhantomData<I>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T: 'a, I: MapIndex> Iter<'a, T, I> {
|
||||||
|
fn new(iter: slice::Iter<'a, T>) -> Self {
|
||||||
|
Self {
|
||||||
|
enumerated: iter.enumerate(),
|
||||||
|
_marker: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T: 'a, I: MapIndex> Iterator for Iter<'a, T, I> {
|
||||||
|
type Item = (I, &'a T);
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
self.enumerated.next().map(|(i, v)| (I::new(i), v))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct IterMut<'a, T: 'a, I: MapIndex> {
|
||||||
|
enumerated: iter::Enumerate<slice::IterMut<'a, T>>,
|
||||||
|
_marker: PhantomData<I>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T: 'a, I: MapIndex> IterMut<'a, T, I> {
|
||||||
|
fn new(iter: slice::IterMut<'a, T>) -> Self {
|
||||||
|
Self {
|
||||||
|
enumerated: iter.enumerate(),
|
||||||
|
_marker: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T: 'a, I: MapIndex> Iterator for IterMut<'a, T, I> {
|
||||||
|
type Item = (I, &'a mut T);
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
self.enumerated.next().map(|(i, v)| (I::new(i), v))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! define_map_index {
|
||||||
|
($ty:ident) => {
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||||
|
pub struct $ty (u32);
|
||||||
|
impl MapIndex for $ty {
|
||||||
|
fn new(index: usize) -> Self {
|
||||||
|
$ty (index as _)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn index(&self) -> usize {
|
||||||
|
self.0 as usize
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
($($ty:ident,)*) => {
|
||||||
|
$(
|
||||||
|
define_map_index!($ty);
|
||||||
|
)*
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
define_map_index![FuncIndex, MemoryIndex, TableIndex, SigIndex,];
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||||
|
pub struct GlobalIndex(u32);
|
||||||
|
impl MapIndex for GlobalIndex {
|
||||||
|
fn new(index: usize) -> Self {
|
||||||
|
GlobalIndex(index as _)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn index(&self) -> usize {
|
||||||
|
self.0 as usize
|
||||||
|
}
|
||||||
|
}
|
383
lib/runtime/src/vm.rs
Normal file
383
lib/runtime/src/vm.rs
Normal file
@ -0,0 +1,383 @@
|
|||||||
|
use crate::backing::{ImportBacking, LocalBacking};
|
||||||
|
use std::{mem, ptr};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct Ctx {
|
||||||
|
/// A pointer to an array of locally-defined memories, indexed by `MemoryIndex`.
|
||||||
|
pub memories: *mut LocalMemory,
|
||||||
|
|
||||||
|
/// A pointer to an array of locally-defined tables, indexed by `TableIndex`.
|
||||||
|
pub tables: *mut LocalTable,
|
||||||
|
|
||||||
|
/// A pointer to an array of locally-defined globals, indexed by `GlobalIndex`.
|
||||||
|
pub globals: *mut LocalGlobal,
|
||||||
|
|
||||||
|
/// A pointer to an array of imported memories, indexed by `MemoryIndex,
|
||||||
|
pub imported_memories: *mut ImportedMemory,
|
||||||
|
|
||||||
|
/// A pointer to an array of imported tables, indexed by `TableIndex`.
|
||||||
|
pub imported_tables: *mut ImportedTable,
|
||||||
|
|
||||||
|
/// A pointer to an array of imported globals, indexed by `GlobalIndex`.
|
||||||
|
pub imported_globals: *mut ImportedGlobal,
|
||||||
|
|
||||||
|
/// A pointer to an array of imported functions, indexed by `FuncIndex`.
|
||||||
|
pub imported_funcs: *mut ImportedFunc,
|
||||||
|
|
||||||
|
/// Signature identifiers for signature-checked indirect calls.
|
||||||
|
pub signatures: *const SigId,
|
||||||
|
|
||||||
|
/// The parent instance.
|
||||||
|
pub local_backing: *mut LocalBacking,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ctx {
|
||||||
|
pub fn new(
|
||||||
|
local_backing: &mut LocalBacking,
|
||||||
|
import_backing: &mut ImportBacking,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
memories: local_backing.vm_memories.as_mut_ptr(),
|
||||||
|
tables: local_backing.vm_tables.as_mut_ptr(),
|
||||||
|
globals: local_backing.vm_globals.as_mut_ptr(),
|
||||||
|
|
||||||
|
imported_memories: import_backing.memories.as_mut_ptr(),
|
||||||
|
imported_tables: import_backing.tables.as_mut_ptr(),
|
||||||
|
imported_globals: import_backing.globals.as_mut_ptr(),
|
||||||
|
imported_funcs: import_backing.functions.as_mut_ptr(),
|
||||||
|
|
||||||
|
signatures: local_backing.vm_signatures.as_mut_ptr(),
|
||||||
|
local_backing,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn offset_memories() -> u8 {
|
||||||
|
0 * (mem::size_of::<usize>() as u8)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn offset_tables() -> u8 {
|
||||||
|
1 * (mem::size_of::<usize>() as u8)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn offset_globals() -> u8 {
|
||||||
|
2 * (mem::size_of::<usize>() as u8)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn offset_imported_memories() -> u8 {
|
||||||
|
3 * (mem::size_of::<usize>() as u8)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn offset_imported_tables() -> u8 {
|
||||||
|
4 * (mem::size_of::<usize>() as u8)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn offset_imported_globals() -> u8 {
|
||||||
|
5 * (mem::size_of::<usize>() as u8)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn offset_imported_funcs() -> u8 {
|
||||||
|
6 * (mem::size_of::<usize>() as u8)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn offset_signatures() -> u8 {
|
||||||
|
7 * (mem::size_of::<usize>() as u8)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Used to provide type safety (ish) for passing around function pointers.
|
||||||
|
/// The typesystem ensures this cannot be dereferenced since an
|
||||||
|
/// empty enum cannot actually exist.
|
||||||
|
pub enum Func {}
|
||||||
|
|
||||||
|
/// An imported function, which contains the vmctx that owns this function.
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct ImportedFunc {
|
||||||
|
pub func: *const Func,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ImportedFunc {
|
||||||
|
pub fn offset_func() -> u8 {
|
||||||
|
0 * (mem::size_of::<usize>() as u8)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Definition of a table used by the VM. (obviously)
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct LocalTable {
|
||||||
|
/// pointer to the elements in the table.
|
||||||
|
pub base: *mut u8,
|
||||||
|
/// Number of elements in the table (NOT necessarily the size of the table in bytes!).
|
||||||
|
pub current_elements: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LocalTable {
|
||||||
|
pub fn offset_base() -> u8 {
|
||||||
|
0 * (mem::size_of::<usize>() as u8)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn offset_current_elements() -> u8 {
|
||||||
|
1 * (mem::size_of::<usize>() as u8)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct ImportedTable {
|
||||||
|
/// A pointer to the table definition.
|
||||||
|
pub table: *mut LocalTable,
|
||||||
|
/// A pointer to the vmcontext that owns this table definition.
|
||||||
|
pub vmctx: *mut Ctx,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ImportedTable {
|
||||||
|
pub fn offset_table() -> u8 {
|
||||||
|
0 * (mem::size_of::<usize>() as u8)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn offset_vmctx() -> u8 {
|
||||||
|
1 * (mem::size_of::<usize>() as u8)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Definition of a memory used by the VM.
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct LocalMemory {
|
||||||
|
/// Pointer to the bottom of this linear memory.
|
||||||
|
pub base: *mut u8,
|
||||||
|
/// Current size of this linear memory in bytes.
|
||||||
|
pub size: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LocalMemory {
|
||||||
|
pub fn offset_base() -> u8 {
|
||||||
|
0 * (mem::size_of::<usize>() as u8)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn offset_size() -> u8 {
|
||||||
|
1 * (mem::size_of::<usize>() as u8)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct ImportedMemory {
|
||||||
|
/// A pointer to the memory definition.
|
||||||
|
pub memory: *mut LocalMemory,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ImportedMemory {
|
||||||
|
pub fn offset_memory() -> u8 {
|
||||||
|
0 * (mem::size_of::<usize>() as u8)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Definition of a global used by the VM.
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct LocalGlobal {
|
||||||
|
pub data: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LocalGlobal {
|
||||||
|
pub fn offset_data() -> u8 {
|
||||||
|
0 * (mem::size_of::<usize>() as u8)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn null() -> Self {
|
||||||
|
Self { data: 0 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct ImportedGlobal {
|
||||||
|
pub global: LocalGlobal,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ImportedGlobal {
|
||||||
|
pub fn offset_data() -> u8 {
|
||||||
|
0 * (mem::size_of::<usize>() as u8)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
#[repr(transparent)]
|
||||||
|
pub struct SigId(pub u32);
|
||||||
|
|
||||||
|
/// Caller-checked anyfunc
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct Anyfunc {
|
||||||
|
pub func_data: ImportedFunc,
|
||||||
|
pub sig_id: SigId,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Anyfunc {
|
||||||
|
pub fn null() -> Self {
|
||||||
|
Self {
|
||||||
|
func_data: ImportedFunc { func: ptr::null() },
|
||||||
|
sig_id: SigId(u32::max_value()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn offset_func() -> u8 {
|
||||||
|
0 * (mem::size_of::<usize>() as u8)
|
||||||
|
}
|
||||||
|
|
||||||
|
// pub fn offset_vmctx() -> u8 {
|
||||||
|
// 1 * (mem::size_of::<usize>() as u8)
|
||||||
|
// }
|
||||||
|
|
||||||
|
pub fn offset_sig_id() -> u8 {
|
||||||
|
1 * (mem::size_of::<usize>() as u8)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod vm_offset_tests {
|
||||||
|
use super::{
|
||||||
|
Anyfunc, Ctx, ImportedFunc, ImportedGlobal, ImportedMemory, ImportedTable, LocalGlobal,
|
||||||
|
LocalMemory, LocalTable,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn vmctx() {
|
||||||
|
assert_eq!(
|
||||||
|
Ctx::offset_memories() as usize,
|
||||||
|
offset_of!(Ctx => memories).get_byte_offset(),
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
Ctx::offset_tables() as usize,
|
||||||
|
offset_of!(Ctx => tables).get_byte_offset(),
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
Ctx::offset_globals() as usize,
|
||||||
|
offset_of!(Ctx => globals).get_byte_offset(),
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
Ctx::offset_imported_memories() as usize,
|
||||||
|
offset_of!(Ctx => imported_memories).get_byte_offset(),
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
Ctx::offset_imported_tables() as usize,
|
||||||
|
offset_of!(Ctx => imported_tables).get_byte_offset(),
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
Ctx::offset_imported_globals() as usize,
|
||||||
|
offset_of!(Ctx => imported_globals).get_byte_offset(),
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
Ctx::offset_imported_funcs() as usize,
|
||||||
|
offset_of!(Ctx => imported_funcs).get_byte_offset(),
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
Ctx::offset_signatures() as usize,
|
||||||
|
offset_of!(Ctx => signatures).get_byte_offset(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn imported_func() {
|
||||||
|
assert_eq!(
|
||||||
|
ImportedFunc::offset_func() as usize,
|
||||||
|
offset_of!(ImportedFunc => func).get_byte_offset(),
|
||||||
|
);
|
||||||
|
|
||||||
|
// assert_eq!(
|
||||||
|
// ImportedFunc::offset_vmctx() as usize,
|
||||||
|
// offset_of!(ImportedFunc => vmctx).get_byte_offset(),
|
||||||
|
// );
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn local_table() {
|
||||||
|
assert_eq!(
|
||||||
|
LocalTable::offset_base() as usize,
|
||||||
|
offset_of!(LocalTable => base).get_byte_offset(),
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
LocalTable::offset_current_elements() as usize,
|
||||||
|
offset_of!(LocalTable => current_elements).get_byte_offset(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn imported_table() {
|
||||||
|
assert_eq!(
|
||||||
|
ImportedTable::offset_table() as usize,
|
||||||
|
offset_of!(ImportedTable => table).get_byte_offset(),
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
ImportedTable::offset_vmctx() as usize,
|
||||||
|
offset_of!(ImportedTable => vmctx).get_byte_offset(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn local_memory() {
|
||||||
|
assert_eq!(
|
||||||
|
LocalMemory::offset_base() as usize,
|
||||||
|
offset_of!(LocalMemory => base).get_byte_offset(),
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
LocalMemory::offset_size() as usize,
|
||||||
|
offset_of!(LocalMemory => size).get_byte_offset(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn imported_memory() {
|
||||||
|
assert_eq!(
|
||||||
|
ImportedMemory::offset_memory() as usize,
|
||||||
|
offset_of!(ImportedMemory => memory).get_byte_offset(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn local_global() {
|
||||||
|
assert_eq!(
|
||||||
|
LocalGlobal::offset_data() as usize,
|
||||||
|
offset_of!(LocalGlobal => data).get_byte_offset(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn imported_global() {
|
||||||
|
assert_eq!(
|
||||||
|
ImportedGlobal::offset_data() as usize,
|
||||||
|
offset_of!(ImportedGlobal => global: LocalGlobal => data).get_byte_offset(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn cc_anyfunc() {
|
||||||
|
assert_eq!(
|
||||||
|
Anyfunc::offset_func() as usize,
|
||||||
|
offset_of!(Anyfunc => func_data: ImportedFunc => func).get_byte_offset(),
|
||||||
|
);
|
||||||
|
|
||||||
|
// assert_eq!(
|
||||||
|
// Anyfunc::offset_vmctx() as usize,
|
||||||
|
// offset_of!(Anyfunc => func_data: ImportedFunc => vmctx).get_byte_offset(),
|
||||||
|
// );
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
Anyfunc::offset_sig_id() as usize,
|
||||||
|
offset_of!(Anyfunc => sig_id).get_byte_offset(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
21
lib/runtime/src/vmcalls.rs
Normal file
21
lib/runtime/src/vmcalls.rs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
use crate::{memory::LinearMemory, vm};
|
||||||
|
|
||||||
|
pub unsafe extern "C" fn memory_grow_static(
|
||||||
|
memory_index: u32,
|
||||||
|
by_pages: u32,
|
||||||
|
ctx: *mut vm::Ctx,
|
||||||
|
) -> i32 {
|
||||||
|
if let Some(old) = (*(*ctx).local_backing).memories[memory_index as usize].grow_static(by_pages)
|
||||||
|
{
|
||||||
|
// Store the new size back into the vmctx.
|
||||||
|
(*(*ctx).memories.add(memory_index as usize)).size =
|
||||||
|
(old as usize + by_pages as usize) * LinearMemory::PAGE_SIZE as usize;
|
||||||
|
old
|
||||||
|
} else {
|
||||||
|
-1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe extern "C" fn memory_size(memory_index: u32, ctx: *mut vm::Ctx) -> u32 {
|
||||||
|
(*(*ctx).local_backing).memories[memory_index as usize].current_pages()
|
||||||
|
}
|
Reference in New Issue
Block a user