Add separated runtime crate

This commit is contained in:
Lachlan Sneff
2019-01-08 12:09:47 -05:00
parent 231ed37127
commit 8a73ff71af
18 changed files with 2393 additions and 1 deletions

2
.gitignore vendored
View File

@ -1,4 +1,4 @@
/target
**/target
**/*.rs.bk
/artifacts
.DS_Store

491
lib/runtime/Cargo.lock generated Normal file
View 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
View 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"

View 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
View 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
View 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
View 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)
}

View 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
View 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
View 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
View 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>,
}

View 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)
}

View 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()
}
}

View 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
View 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
View 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
View 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(),
);
}
}

View 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()
}