mirror of
https://github.com/fluencelabs/wasmer
synced 2025-04-24 18:02:13 +00:00
First working version of the interpreter
This commit is contained in:
commit
9bca6940b3
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
/target
|
||||
**/*.rs.bk
|
702
Cargo.lock
generated
Normal file
702
Cargo.lock
generated
Normal file
@ -0,0 +1,702 @@
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "0.6.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"memchr 2.1.0 (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.43 (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 = "backtrace"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"backtrace-sys 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-demangle 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "backtrace-sys"
|
||||
version = "0.1.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.43 (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 = "cc"
|
||||
version = "1.0.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "0.1.5"
|
||||
source = "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 = "cmake"
|
||||
version = "0.1.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-bforest"
|
||||
version = "0.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cranelift-entity 0.20.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-codegen"
|
||||
version = "0.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cranelift-bforest 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cranelift-codegen-meta 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cranelift-entity 0.20.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"failure_derive 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"target-lexicon 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-codegen-meta"
|
||||
version = "0.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-entity"
|
||||
version = "0.20.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-frontend"
|
||||
version = "0.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cranelift-codegen 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-native"
|
||||
version = "0.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cranelift-codegen 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"raw-cpuid 5.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"target-lexicon 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-wasm"
|
||||
version = "0.20.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cranelift-codegen 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cranelift-entity 0.20.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cranelift-frontend 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"failure_derive 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"target-lexicon 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wasmparser 0.17.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "docopt"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"strsim 0.7.0 (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.43 (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.43 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "error-chain"
|
||||
version = "0.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "failure"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"failure_derive 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "failure_derive"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"synstructure 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fuchsia-zircon"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fuchsia-zircon-sys"
|
||||
version = "0.3.3"
|
||||
source = "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 = "itoa"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.43"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mach"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.43 (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 = "memmap"
|
||||
version = "0.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "0.4.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "0.6.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "raw-cpuid"
|
||||
version = "5.0.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.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.1.40"
|
||||
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.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"aho-corasick 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"memchr 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex-syntax 0.6.2 (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.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "region"
|
||||
version = "0.3.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)",
|
||||
"errno 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mach 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "remove_dir_all"
|
||||
version = "0.5.1"
|
||||
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 = "rustc-demangle"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "rustc_version"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "semver-parser"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.79"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.79"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ryu 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.79 (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 = "structopt"
|
||||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"structopt-derive 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "structopt-derive"
|
||||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "0.14.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "0.15.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "synstructure"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "target-lexicon"
|
||||
version = "0.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"failure_derive 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tempdir"
|
||||
version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"remove_dir_all 0.5.1 (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.43 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"redox_syscall 0.1.40 (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.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ucd-util"
|
||||
version = "0.1.1"
|
||||
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 = "unicode-xid"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "utf8-ranges"
|
||||
version = "1.0.1"
|
||||
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 = "wabt"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wabt-sys 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wabt-sys"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cmake 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasmer"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"cranelift-codegen 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cranelift-entity 0.20.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cranelift-native 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cranelift-wasm 0.20.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"docopt 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"region 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"structopt 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"target-lexicon 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wabt 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wasmparser 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasmparser"
|
||||
version = "0.17.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "wasmparser"
|
||||
version = "0.20.0"
|
||||
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-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 aho-corasick 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)" = "68f56c7353e5a9547cbd76ed90f7bb5ffc3ba09d4ea9bd1d8c06c8b1142eeb5a"
|
||||
"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 backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "89a47830402e9981c5c41223151efcced65a0510c13097c769cede7efb34782a"
|
||||
"checksum backtrace-sys 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)" = "c66d56ac8dabd07f6aacdaf633f4b8262f5b3601a810a0dcddffd5c22c69daa0"
|
||||
"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
|
||||
"checksum cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "f159dfd43363c4d08055a07703eb7a3406b0dac4d0584d96965a3262db3c9d16"
|
||||
"checksum cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0c4e7bb64a8ebb0d856483e1e682ea3422f883c5f5615a90d51a2c82fe87fdd3"
|
||||
"checksum clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e"
|
||||
"checksum cmake 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "6ec65ee4f9c9d16f335091d23693457ed4928657ba4982289d7fafee03bc614a"
|
||||
"checksum cranelift-bforest 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1e96851b525021dd220259b9f29bf79d83f65b49e4f12b786d545aa929e4cad2"
|
||||
"checksum cranelift-codegen 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)" = "16f418f1d1e6221812a7d35cff5b9a572dc978c002e33792134bbd50c07cacca"
|
||||
"checksum cranelift-codegen-meta 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1da3daa0109e7a0b7b322cea666cc223fb6a0d5170e83d23b3d5d2deaddca5f3"
|
||||
"checksum cranelift-entity 0.20.1 (registry+https://github.com/rust-lang/crates.io-index)" = "27412f153f2b517125dea9247ee8859a9ea3923d44384d54420e64fab9314752"
|
||||
"checksum cranelift-frontend 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)" = "03c44cc7006b375e60e0c7edb6fc81abfbf20158374c03f5d0da981b373860a3"
|
||||
"checksum cranelift-native 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8b9d87fdf63094bef798edbca95a05d7c396c14858e02dee1ef5481c8c4271c8"
|
||||
"checksum cranelift-wasm 0.20.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2a9d3454bf60ee6c3d1f54d6cf9ed82cfc1a2e7efb9ec1b16666bf2987c88bfa"
|
||||
"checksum docopt 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d60c92df70dfaaabecc14b409fd79f55ba0f247780529db1d73bfa601e1d3ac0"
|
||||
"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 error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "07e791d3be96241c77c43846b665ef1384606da2cd2a48730abe606a12906e02"
|
||||
"checksum failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7efb22686e4a466b1ec1a15c2898f91fa9cb340452496dca654032de20ff95b9"
|
||||
"checksum failure_derive 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "946d0e98a50d9831f5d589038d2ca7f8f455b1c21028c0db0e84116a12696426"
|
||||
"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
|
||||
"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
|
||||
"checksum gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)" = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2"
|
||||
"checksum itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1306f3464951f30e30d12373d31c79fbd52d236e5e896fd92f96ec7babbbe60b"
|
||||
"checksum lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca488b89a5657b0a2ecd45b95609b3e848cf1755da332a0da46e2b2b1cb371a7"
|
||||
"checksum libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)" = "76e3a3ef172f1a0b9a9ff0dd1491ae5e6c948b94479a3021819ba7d860c8645d"
|
||||
"checksum log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d4fcce5fa49cc693c312001daf1d13411c4a5283796bac1084299ea3e567113f"
|
||||
"checksum mach 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2fd13ee2dd61cc82833ba05ade5a30bb3d63f7ced605ef827063c63078302de9"
|
||||
"checksum memchr 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4b3629fe9fdbff6daa6c33b90f7c08355c1aca05a3d01fa8063b822fcf185f3b"
|
||||
"checksum memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2ffa2c986de11a9df78620c01eeaaf27d94d3ff02bf81bfcca953102dd0c6ff"
|
||||
"checksum proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)" = "3d7b7eaaa90b4a90a932a9ea6666c95a389e424eff347f0f793979289429feee"
|
||||
"checksum quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)" = "dd636425967c33af890042c483632d33fa7a18f19ad1d7ea72e8998c6ef8dea5"
|
||||
"checksum rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8356f47b32624fef5b3301c1be97e5944ecdd595409cc5da11d05f211db6cfbd"
|
||||
"checksum raw-cpuid 5.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fe3c460bd35fdb75644e94ab498372bdf29a4849367ce7ba74cf358edce590c4"
|
||||
"checksum redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "c214e91d3ecf43e9a4e41e578973adeb14b474f2bee858742d127af75a0112b1"
|
||||
"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
|
||||
"checksum regex 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "2069749032ea3ec200ca51e4a31df41759190a88edca0d2d86ee8bedf7073341"
|
||||
"checksum regex-syntax 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "747ba3b235651f6e2f67dfa8bcdcd073ddb7c243cb21c442fc12395dfcac212d"
|
||||
"checksum region 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3f9d3f2bb4b7085e6996e2765b56b783bd8f3a8a4ea5b95683063ca13cded993"
|
||||
"checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5"
|
||||
"checksum rustc-demangle 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "bcfe5b13211b4d78e5c2cadfebd7769197d95c639c35a50057eb4c05de811395"
|
||||
"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
|
||||
"checksum ryu 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7153dd96dade874ab973e098cb62fcdbb89a03682e46b144fd09550998d4a4a7"
|
||||
"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
|
||||
"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
|
||||
"checksum serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)" = "84257ccd054dc351472528c8587b4de2dbf0dc0fe2e634030c1a90bfdacebaa9"
|
||||
"checksum serde_derive 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)" = "31569d901045afbff7a9479f793177fe9259819aff10ab4f89ef69bbc5f567fe"
|
||||
"checksum serde_json 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)" = "43344e7ce05d0d8280c5940cabb4964bea626aa58b1ec0e8c73fa2a8512a38ce"
|
||||
"checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550"
|
||||
"checksum structopt 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "ca85f2c9a5a1e2d5ac686fc0be48e40f8ad803f5bbe31f692ff71eb2dd8aad45"
|
||||
"checksum structopt-derive 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "1383e5db585da799a5c4acc496c5c868e18bf82e658c00c75cc91038fa26b55f"
|
||||
"checksum syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)" = "261ae9ecaa397c42b960649561949d69311f08eeaea86a65696e6e46517cf741"
|
||||
"checksum syn 0.15.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b10ee269228fb723234fce98e9aac0eaed2bd5f1ad2f6930e8d5b93f04445a1a"
|
||||
"checksum synstructure 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "85bb9b7550d063ea184027c9b8c20ac167cd36d3e06b3a40bceb9d746dc1a7b7"
|
||||
"checksum target-lexicon 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a34226bd63b5a26fc909f5f0d7ef4dc55d5851077035e49437e4e14bf567247f"
|
||||
"checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8"
|
||||
"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.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd2be2d6639d0f8fe6cdda291ad456e23629558d466e2789d2c3e9892bda285d"
|
||||
"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526"
|
||||
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
|
||||
"checksum utf8-ranges 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd70f467df6810094968e2fce0ee1bd0e87157aceb026a8c083bcf5e25b9efe4"
|
||||
"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 wabt 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0768faf932f2898c0a7545edee648fefa716906a2e143009addf4959d2335a75"
|
||||
"checksum wabt-sys 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4aaa9a8fa0d698315da5611f3e113a1e688fbb8d6fa0dd9510dfa023f665e9dc"
|
||||
"checksum wasmparser 0.17.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0fc6511bad33610d7798f80d48e10495a6eb4f1e39306b0bb340b2de0816c4ca"
|
||||
"checksum wasmparser 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2a75e0c3fe9a4d4fd91901348a5be05ba4791e29dda89e8596bfe87900ba7edc"
|
||||
"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0"
|
||||
"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"
|
24
Cargo.toml
Normal file
24
Cargo.toml
Normal file
@ -0,0 +1,24 @@
|
||||
[package]
|
||||
name = "wasmer"
|
||||
version = "0.1.0"
|
||||
authors = ["Syrus Akbary <me@syrusakbary.com>"]
|
||||
edition = "2018"
|
||||
repository = "https://github.com/wapmio/wasmer"
|
||||
publish = false
|
||||
|
||||
[dependencies]
|
||||
cranelift-codegen = "0.20.0"
|
||||
cranelift-entity = "0.20.1"
|
||||
cranelift-wasm = "0.20.1"
|
||||
cranelift-native = "0.20.0"
|
||||
docopt = "1.0.0"
|
||||
serde = "1.0.55"
|
||||
serde_derive = "1.0.55"
|
||||
tempdir = "*"
|
||||
error-chain = "0.12.0"
|
||||
structopt = "0.2.11"
|
||||
wabt = "0.6.0"
|
||||
wasmparser = "0.20.0"
|
||||
region = "0.3.0"
|
||||
memmap = "0.6.2"
|
||||
target-lexicon = "0.0.3"
|
34
README.md
Normal file
34
README.md
Normal file
@ -0,0 +1,34 @@
|
||||
# wasmer - WebAssembly runtime
|
||||
|
||||
[](https://travis-ci.org/rust-lang-nursery/error-chain)
|
||||
[](https://crates.io/crates/error-chain)
|
||||
[](https://github.com/wapmio/wasmer)
|
||||
|
||||
`wasmer` is a Standalone JIT-style runtime for WebAsssembly code.
|
||||
|
||||
The [Cranelift](https://github.com/CraneStation/cranelift) compiler is used to compile WebAssembly to native machine code. Once compiled, there are no complex interactions between the application and the runtime (unlike jit compilers, like v8) to reduce surface area for vulnerabilities.
|
||||
|
||||
[Documentation (crates.io)](https://docs.rs/wasmer).
|
||||
|
||||
## Usage
|
||||
|
||||
It can load both the standard binary format (`.wasm`), and the text format
|
||||
defined by the WebAssembly reference interpreter (`.wat`).
|
||||
|
||||
## Building & Running
|
||||
|
||||
To build this project you will need Rust and Cargo.
|
||||
|
||||
```sh
|
||||
# checkout code and associated submodules
|
||||
git clone https://github.com/wapmio/wasmer.git
|
||||
cd wasmer
|
||||
|
||||
# install tools
|
||||
# make sure that `python` is accessible.
|
||||
cargo install
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
MIT/Apache-2.0
|
75
src/main.rs
Normal file
75
src/main.rs
Normal file
@ -0,0 +1,75 @@
|
||||
#[macro_use]
|
||||
extern crate error_chain;
|
||||
#[macro_use]
|
||||
extern crate structopt;
|
||||
extern crate wabt;
|
||||
extern crate cranelift_codegen;
|
||||
extern crate cranelift_native;
|
||||
extern crate cranelift_wasm;
|
||||
extern crate cranelift_entity;
|
||||
|
||||
use std::path::PathBuf;
|
||||
use std::fs::File;
|
||||
use std::io;
|
||||
use std::io::Read;
|
||||
use std::process::exit;
|
||||
use std::error::Error;
|
||||
|
||||
use structopt::StructOpt;
|
||||
use wabt::wat2wasm;
|
||||
|
||||
pub mod webassembly;
|
||||
pub mod spec;
|
||||
|
||||
|
||||
/// The options for the wasmer Command Line Interface
|
||||
#[derive(Debug, StructOpt)]
|
||||
#[structopt(name = "wasmer", about = "WASM execution runtime.")]
|
||||
struct Opt {
|
||||
/// Activate debug mode
|
||||
#[structopt(short = "d", long = "debug")]
|
||||
debug: bool,
|
||||
/// Input file
|
||||
#[structopt(parse(from_os_str))]
|
||||
path: PathBuf,
|
||||
}
|
||||
|
||||
/// Read the contents of a file
|
||||
fn read_file_contents(path: PathBuf) -> Result<Vec<u8>, io::Error> {
|
||||
let mut buffer: Vec<u8> = Vec::new();
|
||||
let mut file = File::open(path)?;
|
||||
file.read_to_end(&mut buffer)?;
|
||||
Ok(buffer)
|
||||
}
|
||||
|
||||
/// Execute a WASM/WAT file
|
||||
fn execute_wasm(wasm_path: PathBuf) -> Result<(), String>{
|
||||
let mut wasm_binary: Vec<u8> = read_file_contents(wasm_path).map_err(|err| String::from(err.description()))?;
|
||||
if !webassembly::utils::is_wasm_binary(&wasm_binary) {
|
||||
wasm_binary = wat2wasm(
|
||||
wasm_binary
|
||||
).map_err(|err| String::from(err.description()))?;
|
||||
}
|
||||
|
||||
// let result_object = instantiate
|
||||
// webassembly::
|
||||
// if !webassembly::validate(&wasm_binary) {
|
||||
// return Err("Invalid WASM module".to_string())
|
||||
// };
|
||||
webassembly::compile(wasm_binary);
|
||||
// println!("Data, {:?}", wasm_binary);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
fn main() {
|
||||
let opt = Opt::from_args();
|
||||
match execute_wasm(opt.path.clone()) {
|
||||
Ok(()) => {}
|
||||
Err(message) => {
|
||||
let name = opt.path.as_os_str().to_string_lossy();
|
||||
println!("error while executing {}: {}", name, message);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
662
src/spec/mod.rs
Normal file
662
src/spec/mod.rs
Normal file
@ -0,0 +1,662 @@
|
||||
// Shamelessly copied from greenwasm-spectest:
|
||||
// https://github.com/Kimundi/greenwasm/blob/master/greenwasm-spectest/src/lib.rs
|
||||
|
||||
#![deny(missing_docs)]
|
||||
|
||||
//! A library shim around a mirror of the
|
||||
//! official [webassembly MVP testsuite](https://github.com/WebAssembly/spec/tree/master/test/core).
|
||||
//!
|
||||
//! It can be used as a independent testsuite launcher for other
|
||||
//! webassembly implementations by implementing `ScriptHandler`.
|
||||
//!
|
||||
//! Example:
|
||||
//! ```should_fail
|
||||
/*!
|
||||
use wasmer::spec::*;
|
||||
struct DummyHandler;
|
||||
impl ScriptHandler for DummyHandler {
|
||||
fn reset(&mut self) {}
|
||||
fn action_invoke(&mut self,
|
||||
module: Option<String>,
|
||||
field: String,
|
||||
args: Vec<Value>) -> InvokationResult
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
fn action_get(&mut self,
|
||||
module: Option<String>,
|
||||
field: String) -> Value
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
fn module(&mut self, bytes: Vec<u8>, name: Option<String>) {
|
||||
unimplemented!()
|
||||
}
|
||||
fn assert_malformed(&mut self, bytes: Vec<u8>) {
|
||||
unimplemented!()
|
||||
}
|
||||
fn assert_invalid(&mut self, bytes: Vec<u8>) {
|
||||
unimplemented!()
|
||||
}
|
||||
fn assert_uninstantiable(&mut self, bytes: Vec<u8>) {
|
||||
unimplemented!()
|
||||
}
|
||||
fn assert_exhaustion(&mut self, action: Action) {
|
||||
unimplemented!()
|
||||
}
|
||||
fn register(&mut self, name: Option<String>, as_name: String) {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
run_mvp_spectest(&mut DummyHandler).present();
|
||||
*/
|
||||
//! ```
|
||||
//! This would result in a output like this:
|
||||
//! ```text
|
||||
/*!
|
||||
Executing address.wast ...
|
||||
Executing align.wast ...
|
||||
Executing binary.wast ...
|
||||
Executing block.wast ...
|
||||
Executing br.wast ...
|
||||
[...]
|
||||
wast failures:
|
||||
address.wast:3, not yet implemented
|
||||
address.wast:104, <not attempted>
|
||||
address.wast:105, <not attempted>
|
||||
...
|
||||
wast total: 0 passed; 17955 failed
|
||||
*/
|
||||
//! ```
|
||||
|
||||
pub extern crate wabt;
|
||||
pub use wabt::script::Value;
|
||||
pub use wabt::script::Action;
|
||||
pub use wabt::script::CommandKind;
|
||||
|
||||
use std::path::Path;
|
||||
use wabt::script::*;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
/// Handles the different script commands of the `*.wast` format.
|
||||
pub trait ScriptHandler {
|
||||
/// Reset all state of the handler, specifically
|
||||
/// clearing all loaded modules and assuming a new script file.
|
||||
fn reset(&mut self);
|
||||
|
||||
/// Handles an `invoke` action.
|
||||
///
|
||||
/// Should call a exported function with name `field` and arguments
|
||||
/// `args` from a loaded module.
|
||||
///
|
||||
/// Targets either the last loaded module if `module` is None, or
|
||||
/// the module registered with the given name otherwise.
|
||||
fn action_invoke(&mut self, module: Option<String>, field: String, args: Vec<Value>) -> InvokationResult;
|
||||
|
||||
/// Handles an `get` action.
|
||||
///
|
||||
/// Should get a exported global with name `field` from a loaded module.
|
||||
///
|
||||
/// Targets either the last loaded module if `module` is None, or
|
||||
/// the module registered with the given name otherwise.
|
||||
fn action_get(&mut self, module: Option<String>, field: String) -> Value;
|
||||
|
||||
/// Handles an `action`.
|
||||
///
|
||||
/// The default implementation dispatches to `action_get` or `
|
||||
/// action_invoke`, gathers the result in an vector, and panics
|
||||
/// if a function call trapped or exhausted the stack.
|
||||
fn action(&mut self, action: Action) -> Vec<Value> {
|
||||
match action {
|
||||
Action::Invoke { module, field, args } => {
|
||||
if let InvokationResult::Vals(v) = self.action_invoke(module, field, args) {
|
||||
v
|
||||
} else {
|
||||
panic!("invokation returned Trap or exhausted the stack");
|
||||
}
|
||||
}
|
||||
Action::Get { module, field } => {
|
||||
vec![self.action_get(module, field)]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Handles a module load.
|
||||
///
|
||||
/// The webassembly module is passed in its binary format in
|
||||
/// the `bytes` argument.
|
||||
///
|
||||
/// If `name` is `Some`, it should be registered under that name.
|
||||
/// In any case it should count as the least recently loaded module.
|
||||
fn module(&mut self, bytes: Vec<u8>, name: Option<String>);
|
||||
|
||||
/// Handles an `assert_return`.
|
||||
///
|
||||
/// Per default panics if the result of handling the `action`
|
||||
/// does not result in the `expected` values.
|
||||
///
|
||||
/// Floating point values should, and per default are,
|
||||
/// compared according to their bit-pattern, and not their normal
|
||||
/// `PartialEq` semantic. See the `NanCompare` wrapper type.
|
||||
fn assert_return(&mut self, action: Action, expected: Vec<Value>) {
|
||||
let results = self.action(action);
|
||||
assert_eq!(NanCompare(&expected), NanCompare(&results));
|
||||
}
|
||||
|
||||
/// Handles an `assert_trap`.
|
||||
///
|
||||
/// Per default panics if the result of handling the `action`
|
||||
/// does not trap, or refers to an global.
|
||||
fn assert_trap(&mut self, action: Action) {
|
||||
match action {
|
||||
Action::Invoke { module, field, args } => {
|
||||
if let InvokationResult::Vals(results) = self.action_invoke(module, field, args) {
|
||||
panic!("invokation did not trap, but returned {:?}", results);
|
||||
}
|
||||
}
|
||||
Action::Get { .. } => {
|
||||
panic!("a global access can not trap!")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Handles an `assert_malformed`.
|
||||
///
|
||||
/// The webassembly module is passed in its binary format in
|
||||
/// the `bytes` argument.
|
||||
///
|
||||
/// Should panic if the module can be successfully decoded.
|
||||
fn assert_malformed(&mut self, bytes: Vec<u8>);
|
||||
|
||||
/// Handles an `assert_malformed`.
|
||||
///
|
||||
/// The webassembly module is passed in its binary format in
|
||||
/// the `bytes` argument.
|
||||
///
|
||||
/// Should panic if the module can be successfully decoded.
|
||||
fn assert_invalid(&mut self, bytes: Vec<u8>);
|
||||
|
||||
/// Handles an `assert_unlinkable`.
|
||||
///
|
||||
/// The webassembly module is passed in its binary format in
|
||||
/// the `bytes` argument.
|
||||
///
|
||||
/// Should panic if the module can be successfully linked.
|
||||
///
|
||||
/// This seems to be a legacy script command, and per default
|
||||
/// just invokes `assert_uninstantiable`.
|
||||
fn assert_unlinkable(&mut self, bytes: Vec<u8>) {
|
||||
// TODO: figure out the exact difference
|
||||
// Currently it looks like a link error is any instantiation error except
|
||||
// a runtime error during execution of a start function
|
||||
self.assert_uninstantiable(bytes);
|
||||
}
|
||||
|
||||
/// Handles an `assert_uninstantiable`.
|
||||
///
|
||||
/// The webassembly module is passed in its binary format in
|
||||
/// the `bytes` argument.
|
||||
///
|
||||
/// Should panic if the module can be successfully instantiated.
|
||||
fn assert_uninstantiable(&mut self, bytes: Vec<u8>);
|
||||
|
||||
/// Handles an `assert_trap`.
|
||||
///
|
||||
/// Should panic if the result of handling the `action`
|
||||
/// does not exhaust the stack, or refers to an global.
|
||||
fn assert_exhaustion(&mut self, action: Action);
|
||||
|
||||
/// Handles an `assert_return_canonical_nan`.
|
||||
///
|
||||
/// Per default panics if the result of handling the `action`
|
||||
/// does not result in single canonical NaN floating point value.
|
||||
///
|
||||
/// Any canonical NaN is also a arithmetic NaN.
|
||||
///
|
||||
/// Floating point values should, and per default are,
|
||||
/// compared according to their bit-pattern, and not their normal
|
||||
/// `PartialEq` semantic. See the `NanCompare` wrapper type.
|
||||
fn assert_return_canonical_nan(&mut self, action: Action) {
|
||||
let results = self.action(action);
|
||||
match *results {
|
||||
[Value::F32(v)] if v.is_canonical_nan() => {}
|
||||
[Value::F64(v)] if v.is_canonical_nan() => {}
|
||||
ref x => {
|
||||
panic!("unexpected value {:?}", NanCompare(x));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Handles an `assert_return_arithmetic_nan`.
|
||||
///
|
||||
/// Per default panics if the result of handling the `action`
|
||||
/// does not result in single arithmetic NaN floating point value.
|
||||
///
|
||||
/// Any canonical NaN is also a arithmetic NaN.
|
||||
///
|
||||
/// Floating point values should, and per default are,
|
||||
/// compared according to their bit-pattern, and not their normal
|
||||
/// `PartialEq` semantic. See the `NanCompare` wrapper type.
|
||||
fn assert_return_arithmetic_nan(&mut self, action: Action) {
|
||||
let results = self.action(action);
|
||||
match *results {
|
||||
[Value::F32(v)] if v.is_arithmetic_nan() => {}
|
||||
[Value::F64(v)] if v.is_arithmetic_nan() => {}
|
||||
ref x => {
|
||||
panic!("unexpected value {:?}", NanCompare(x));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Register a loaded module under the name `as_name`.
|
||||
///
|
||||
/// If `name` is `Some`, it should be registered under that name.
|
||||
/// In any case it should count as the least recently loaded module.
|
||||
fn register(&mut self, name: Option<String>, as_name: String);
|
||||
}
|
||||
|
||||
/// Wrapper type that compares a list of `wabt` `Value`s
|
||||
/// according to their bit-pattern if they contain floating point values,
|
||||
/// and according to regular `PartialEq` semantics otherwise.
|
||||
pub struct NanCompare<'a>(pub &'a [Value]);
|
||||
|
||||
impl<'a> ::std::cmp::PartialEq for NanCompare<'a> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
if self.0.len() != other.0.len() {
|
||||
return false;
|
||||
}
|
||||
self.0.iter().zip(other.0.iter()).all(|pair| {
|
||||
match pair {
|
||||
(Value::I32(l), Value::I32(r)) => l == r,
|
||||
(Value::I64(l), Value::I64(r)) => l == r,
|
||||
(Value::F32(l), Value::F32(r)) if l.is_nan() && r.is_nan() => {
|
||||
l.payload() == r.payload()
|
||||
},
|
||||
(Value::F64(l), Value::F64(r)) if l.is_nan() && r.is_nan() => {
|
||||
l.payload() == r.payload()
|
||||
},
|
||||
(Value::F32(l), Value::F32(r)) => l == r,
|
||||
(Value::F64(l), Value::F64(r)) => l == r,
|
||||
_ => false,
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
impl<'a> ::std::fmt::Debug for NanCompare<'a> {
|
||||
fn fmt(&self, formatter: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||
formatter.debug_list().entries(self.0.iter().map(|e| {
|
||||
match e {
|
||||
Value::F32(v) if v.is_nan() => {
|
||||
let p = v.payload();
|
||||
format!("F32(NaN:0x{:x})", p)
|
||||
}
|
||||
Value::F64(v) if v.is_nan() => {
|
||||
let p = v.payload();
|
||||
format!("F64(NaN:0x{:x})", p)
|
||||
}
|
||||
_ => format!("{:?}", e)
|
||||
}
|
||||
})).finish()
|
||||
}
|
||||
}
|
||||
|
||||
/// Result of invoking a function.
|
||||
pub enum InvokationResult {
|
||||
/// The function returned successfully with a number of `Value`s
|
||||
Vals(Vec<Value>),
|
||||
/// The function trapped.
|
||||
Trap,
|
||||
/// The function exhausted the stack.
|
||||
StackExhaustion,
|
||||
}
|
||||
|
||||
/// Extension trait for floating point values.
|
||||
///
|
||||
/// Provides methods for accessing the payload
|
||||
/// of a NaN according to the webassembly spec.
|
||||
///
|
||||
/// According to the spec, any canonical NaN is also an arithmetic one.
|
||||
pub trait NanPayload {
|
||||
/// Returns the payload bits of a NaN value.
|
||||
fn payload(&self) -> u64;
|
||||
/// Returns the number of significant digits in a NaN value.
|
||||
fn signif() -> u32;
|
||||
/// Returns positive infinite.
|
||||
fn infinite() -> Self;
|
||||
/// Returns the payload of a canonical NaN.
|
||||
fn canonical_payload() -> u64;
|
||||
/// Returns an arithmetic NaN with the given payload.
|
||||
fn arithmetic_nan(payload: u64) -> Self;
|
||||
/// Returns a canonical NaN.
|
||||
fn canonical_nan() -> Self;
|
||||
/// Checks if a value is an arithmetic NaN.
|
||||
fn is_arithmetic_nan(&self) -> bool;
|
||||
/// Checks if a value is a canonical NaN.
|
||||
fn is_canonical_nan(&self) -> bool;
|
||||
}
|
||||
impl NanPayload for f32 {
|
||||
fn payload(&self) -> u64 {
|
||||
assert!(self.is_nan());
|
||||
let bits: u32 = self.to_bits();
|
||||
let mask: u32 = (1u32 << 23) - 1;
|
||||
let p = bits & mask;
|
||||
p as u64
|
||||
}
|
||||
fn signif() -> u32 { 23 }
|
||||
fn infinite() -> Self { 1.0 / 0.0 }
|
||||
fn canonical_payload() -> u64 {
|
||||
1u64 << (Self::signif() - 1)
|
||||
}
|
||||
fn arithmetic_nan(payload: u64) -> Self {
|
||||
assert!(payload >= Self::canonical_payload());
|
||||
let bits: u32 = Self::infinite().to_bits();
|
||||
let mask: u32 = (1u32 << Self::signif()) - 1;
|
||||
let bits = bits | (mask & (payload as u32));
|
||||
Self::from_bits(bits)
|
||||
}
|
||||
fn canonical_nan() -> Self {
|
||||
Self::arithmetic_nan(Self::canonical_payload())
|
||||
}
|
||||
fn is_arithmetic_nan(&self) -> bool {
|
||||
self.is_nan()
|
||||
}
|
||||
fn is_canonical_nan(&self) -> bool {
|
||||
self.is_nan() && self.abs().to_bits() == Self::canonical_nan().to_bits()
|
||||
}
|
||||
}
|
||||
impl NanPayload for f64 {
|
||||
fn payload(&self) -> u64 {
|
||||
assert!(self.is_nan());
|
||||
let bits: u64 = self.to_bits();
|
||||
let mask: u64 = (1u64 << 52) - 1;
|
||||
let p = bits & mask;
|
||||
p
|
||||
}
|
||||
fn signif() -> u32 { 52 }
|
||||
fn infinite() -> Self { 1.0 / 0.0 }
|
||||
fn canonical_payload() -> u64 {
|
||||
1u64 << (Self::signif() - 1)
|
||||
}
|
||||
fn arithmetic_nan(payload: u64) -> Self {
|
||||
assert!(payload >= Self::canonical_payload());
|
||||
let bits: u64 = Self::infinite().to_bits();
|
||||
let mask: u64 = (1u64 << Self::signif()) - 1;
|
||||
let bits = bits | (mask & payload);
|
||||
Self::from_bits(bits)
|
||||
}
|
||||
fn canonical_nan() -> Self {
|
||||
Self::arithmetic_nan(Self::canonical_payload())
|
||||
}
|
||||
fn is_arithmetic_nan(&self) -> bool {
|
||||
self.is_nan()
|
||||
}
|
||||
fn is_canonical_nan(&self) -> bool {
|
||||
self.is_nan() && self.abs().to_bits() == Self::canonical_nan().to_bits()
|
||||
}
|
||||
}
|
||||
|
||||
/// Result of running a series of script commands.
|
||||
#[must_use]
|
||||
pub struct SpectestResult {
|
||||
/// List of failed commands consisting of
|
||||
/// (filename, line number, panic message) tuples.
|
||||
pub failures: Vec<(String, u64, String)>,
|
||||
|
||||
/// Number of successful commands.
|
||||
pub successes: usize,
|
||||
}
|
||||
|
||||
impl SpectestResult {
|
||||
/// Displays the results in `Self` in a form similar
|
||||
/// to Rusts testsuite, and raises an panic if any tests failed.
|
||||
///
|
||||
/// This is intended to be called from a `#[test]` function.
|
||||
pub fn present(self) {
|
||||
if self.failures.len() > 0 {
|
||||
println!("wast failures:");
|
||||
for (i, f) in self.failures.iter().enumerate() {
|
||||
println!(" {}:{}, {}", f.0, f.1, f.2);
|
||||
if i > 10 {
|
||||
println!(" ...");
|
||||
break;
|
||||
}
|
||||
}
|
||||
println!("wast total: {} passed; {} failed", self.successes, self.failures.len());
|
||||
panic!("some wast commands failed");
|
||||
} else {
|
||||
println!("wast total: {} passed; {} failed", self.successes, self.failures.len());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Run all scripts of the bundled webassembly testsuite on `handler`.
|
||||
pub fn run_mvp_spectest<T: ScriptHandler>(handler: &mut T) -> SpectestResult {
|
||||
run_all_in_directory(format!("{}/testsuite", env!("CARGO_MANIFEST_DIR")).as_ref(), handler)
|
||||
}
|
||||
|
||||
/// Module that is expected under the name "spectest" by all spectest testcases.
|
||||
///
|
||||
/// This is automatically registered by all `run_` functions in this modules
|
||||
/// that work at file granularity or higher.
|
||||
pub const SPECTEST_MODULE: &[u8] = include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/src/spec/spectest.wasm"));
|
||||
|
||||
/// Run all scripts in a given directory on `handler`.
|
||||
pub fn run_all_in_directory<T: ScriptHandler>(path: &Path, handler: &mut T) -> SpectestResult {
|
||||
use std::fs;
|
||||
let mut res = SpectestResult {
|
||||
failures: vec![],
|
||||
successes: 0,
|
||||
};
|
||||
|
||||
println!("\n\nRunning testsuite at {}:\n", path.display());
|
||||
|
||||
'outer: for dir in fs::read_dir(&path).unwrap() {
|
||||
let dir = dir.unwrap();
|
||||
let path = dir.path();
|
||||
let filename = path.file_name().unwrap().to_str().unwrap();
|
||||
|
||||
if path.metadata().unwrap().file_type().is_file() && filename.ends_with(".wast") {
|
||||
println!("Executing {} ...", filename);
|
||||
let res2 = run_single_file(&path, handler);
|
||||
res.successes += res2.successes;
|
||||
res.failures.extend(res2.failures);
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/// Run `handler` on the single `.wast` script file at `path`.
|
||||
pub fn run_single_file<T: ScriptHandler>(path: &Path, handler: &mut T) -> SpectestResult {
|
||||
use std::fs;
|
||||
|
||||
let mut res = SpectestResult {
|
||||
failures: vec![],
|
||||
successes: 0,
|
||||
};
|
||||
|
||||
let filename = path.file_name().unwrap().to_str().unwrap();
|
||||
let source = fs::read(&path).unwrap();
|
||||
|
||||
let mut script = ScriptParser::<>::from_source_and_name(&source, filename).unwrap();
|
||||
let mut fatal = false;
|
||||
|
||||
handler.reset();
|
||||
{
|
||||
let module = SPECTEST_MODULE.to_vec();
|
||||
let name = Some("spectest".into());
|
||||
|
||||
use std::panic::*;
|
||||
|
||||
let r = if let Err(msg) = catch_unwind(AssertUnwindSafe(|| {
|
||||
handler.module(module, name);
|
||||
})) {
|
||||
let msg = if let Some(msg) = msg.downcast_ref::<String>() {
|
||||
msg.to_string()
|
||||
} else if let Some(msg) = msg.downcast_ref::<&'static str>() {
|
||||
msg.to_string()
|
||||
} else {
|
||||
"<unknown>".to_string()
|
||||
};
|
||||
Err(msg)
|
||||
} else {
|
||||
Ok(())
|
||||
};
|
||||
|
||||
match r {
|
||||
Err(msg) => {
|
||||
res.failures.push(("<internal spectest module>".to_owned(), 0, msg));
|
||||
fatal = true;
|
||||
}
|
||||
Ok(()) => {
|
||||
res.successes += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while let Some(Command { line, kind }) = script.next().unwrap() {
|
||||
if fatal {
|
||||
res.failures.push((filename.to_owned(), line, "<not attempted>".to_string()));
|
||||
continue;
|
||||
}
|
||||
match run_single_command(kind, handler) {
|
||||
Err(msg) => {
|
||||
res.failures.push((filename.to_owned(), line, msg));
|
||||
fatal = true;
|
||||
}
|
||||
Ok(()) => {
|
||||
res.successes += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/// Run `handler` on a single wabt script command, catching any panic that
|
||||
/// might happen in the process.
|
||||
///
|
||||
/// Note that `T` needs to be exception safe, in the sense that any
|
||||
/// panic that happened during a method call should not affect it beyond
|
||||
/// a subsequent `reset()` call.
|
||||
pub fn run_single_command<T: ScriptHandler>(kind: CommandKind, handler: &mut T) -> Result<(), String> {
|
||||
use std::panic::*;
|
||||
|
||||
if let Err(msg) = catch_unwind(AssertUnwindSafe(|| {
|
||||
run_single_command_no_catch(kind, handler);
|
||||
})) {
|
||||
let msg = if let Some(msg) = msg.downcast_ref::<String>() {
|
||||
msg.to_string()
|
||||
} else if let Some(msg) = msg.downcast_ref::<&'static str>() {
|
||||
msg.to_string()
|
||||
} else {
|
||||
"<unknown>".to_string()
|
||||
};
|
||||
Err(msg)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Run `handler` on a single wabt script command.
|
||||
///
|
||||
/// Unlike `run_single_command`, this does not catch a panic.
|
||||
pub fn run_single_command_no_catch<C: ScriptHandler>(cmd: CommandKind, c: &mut C) {
|
||||
// TODO: Figure out if the "message" fields need to actually be handled
|
||||
use wabt::script::CommandKind::*;
|
||||
match cmd {
|
||||
Module { module, name } => {
|
||||
c.module(module.into_vec(), name);
|
||||
}
|
||||
AssertReturn { action, expected } => {
|
||||
c.assert_return(action, expected);
|
||||
}
|
||||
AssertReturnCanonicalNan { action } => {
|
||||
c.assert_return_canonical_nan(action);
|
||||
}
|
||||
AssertReturnArithmeticNan { action } => {
|
||||
c.assert_return_arithmetic_nan(action);
|
||||
}
|
||||
AssertTrap { action, message: _ } => {
|
||||
c.assert_trap(action);
|
||||
}
|
||||
AssertInvalid { module, message: _ } => {
|
||||
c.assert_invalid(module.into_vec());
|
||||
}
|
||||
AssertMalformed { module, message: _ } => {
|
||||
c.assert_malformed(module.into_vec());
|
||||
}
|
||||
AssertUninstantiable { module, message: _ } => {
|
||||
c.assert_uninstantiable(module.into_vec());
|
||||
}
|
||||
AssertExhaustion { action } => {
|
||||
c.assert_exhaustion(action);
|
||||
}
|
||||
AssertUnlinkable { module, message: _ } => {
|
||||
c.assert_unlinkable(module.into_vec());
|
||||
}
|
||||
Register { name, as_name } => {
|
||||
c.register(name, as_name);
|
||||
}
|
||||
PerformAction(action) => {
|
||||
c.action(action);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Spectest module .wat, based on wabt's spectest-interp.cc
|
||||
static void InitEnvironment(Environment* env) {
|
||||
HostModule* host_module = env->AppendHostModule("spectest");
|
||||
host_module->AppendFuncExport("print", {{}, {}}, PrintCallback);
|
||||
host_module->AppendFuncExport("print_i32", {{Type::I32}, {}}, PrintCallback);
|
||||
host_module->AppendFuncExport("print_f32", {{Type::F32}, {}}, PrintCallback);
|
||||
host_module->AppendFuncExport("print_f64", {{Type::F64}, {}}, PrintCallback);
|
||||
host_module->AppendFuncExport("print_i32_f32", {{Type::I32, Type::F32}, {}},
|
||||
PrintCallback);
|
||||
host_module->AppendFuncExport("print_f64_f64", {{Type::F64, Type::F64}, {}},
|
||||
PrintCallback);
|
||||
host_module->AppendTableExport("table", Limits(10, 20));
|
||||
host_module->AppendMemoryExport("memory", Limits(1, 2));
|
||||
host_module->AppendGlobalExport("global_i32", false, uint32_t(666));
|
||||
host_module->AppendGlobalExport("global_i64", false, uint64_t(666));
|
||||
host_module->AppendGlobalExport("global_f32", false, float(666.6f));
|
||||
host_module->AppendGlobalExport("global_f64", false, double(666.6));
|
||||
}
|
||||
=>
|
||||
(module
|
||||
(type (func))
|
||||
(type (func (param i32)))
|
||||
(type (func (param f32)))
|
||||
(type (func (param f64)))
|
||||
(type (func (param i32) (param f32)))
|
||||
(type (func (param f64) (param f64)))
|
||||
(func (type 0))
|
||||
(func (type 1))
|
||||
(func (type 2))
|
||||
(func (type 3))
|
||||
(func (type 4))
|
||||
(func (type 5))
|
||||
(table 10 20 anyfunc)
|
||||
(memory 1 2)
|
||||
(global i32 (i32.const 666))
|
||||
(global i64 (i64.const 666))
|
||||
(global f32 (f32.const 666.6))
|
||||
(global f64 (f64.const 666.6))
|
||||
(export "print" (func 0))
|
||||
(export "print_i32" (func 1))
|
||||
(export "print_f32" (func 2))
|
||||
(export "print_f64" (func 3))
|
||||
(export "print_i32_f32" (func 4))
|
||||
(export "print_f64_f64" (func 5))
|
||||
(export "table" (table 0))
|
||||
(export "memory" (memory 0))
|
||||
(export "global_i32" (global 0))
|
||||
(export "global_i64" (global 1))
|
||||
(export "global_f32" (global 2))
|
||||
(export "global_f64" (global 3))
|
||||
)
|
||||
the file spectest.wasm in the crate root contains a copy of it as a binary module
|
||||
*/
|
BIN
src/spec/spectest.wasm
Normal file
BIN
src/spec/spectest.wasm
Normal file
Binary file not shown.
31
src/spec/spectest.wast
Normal file
31
src/spec/spectest.wast
Normal file
@ -0,0 +1,31 @@
|
||||
(module
|
||||
(type (;0;) (func))
|
||||
(type (;1;) (func (param i32)))
|
||||
(type (;2;) (func (param f32)))
|
||||
(type (;3;) (func (param f64)))
|
||||
(type (;4;) (func (param i32 f32)))
|
||||
(type (;5;) (func (param f64 f64)))
|
||||
(func (;0;) (type 0))
|
||||
(func (;1;) (type 1) (param i32))
|
||||
(func (;2;) (type 2) (param f32))
|
||||
(func (;3;) (type 3) (param f64))
|
||||
(func (;4;) (type 4) (param i32 f32))
|
||||
(func (;5;) (type 5) (param f64 f64))
|
||||
(table (;0;) 10 20 anyfunc)
|
||||
(memory (;0;) 1 2)
|
||||
(global (;0;) i32 (i32.const 666))
|
||||
(global (;1;) i64 (i64.const 666))
|
||||
(global (;2;) f32 (f32.const 0x1.4d4cccp+9 (;=666.6;)))
|
||||
(global (;3;) f64 (f64.const 0x1.4d4cccccccccdp+9 (;=666.6;)))
|
||||
(export "print" (func 0))
|
||||
(export "print_i32" (func 1))
|
||||
(export "print_f32" (func 2))
|
||||
(export "print_f64" (func 3))
|
||||
(export "print_i32_f32" (func 4))
|
||||
(export "print_f64_f64" (func 5))
|
||||
(export "table" (table 0))
|
||||
(export "memory" (memory 0))
|
||||
(export "global_i32" (global 0))
|
||||
(export "global_i64" (global 1))
|
||||
(export "global_f32" (global 2))
|
||||
(export "global_f64" (global 3)))
|
114
src/spec/tests.rs
Normal file
114
src/spec/tests.rs
Normal file
@ -0,0 +1,114 @@
|
||||
use std::path::Path;
|
||||
|
||||
use wabt::script::{Value, Action};
|
||||
use super::{InvokationResult, ScriptHandler, run_single_file};
|
||||
use crate::webassembly::{compile, Error, ErrorKind};
|
||||
|
||||
struct StoreCtrl {
|
||||
}
|
||||
|
||||
impl StoreCtrl {
|
||||
fn new() -> Self {
|
||||
// let (tx, rx) = channel();
|
||||
|
||||
// let _handle = thread::spawn(|| {
|
||||
// let _: FrameWitness = store_thread_frame(
|
||||
// StSt { store: Store::new(), stack: Stack::new(), recv: rx});
|
||||
// });
|
||||
|
||||
StoreCtrl {
|
||||
// tx,
|
||||
// _handle,
|
||||
// modules: HashMap::new(),
|
||||
// last_module: None,
|
||||
}
|
||||
}
|
||||
|
||||
// fn add_module(&mut self, name: Option<String>, module: DummyEnvironment) {
|
||||
// // if let Some(name) = name {
|
||||
// // println!("ADD MODULE {:?}", name);
|
||||
// // self.modules
|
||||
// // .insert(name.unwrap_or("__last_module".to_string()), module);
|
||||
// // }
|
||||
// // self.modules.insert("__last_module".to_string(), module);
|
||||
// // self.last_module = Some(module);
|
||||
// }
|
||||
|
||||
// fn get_module(&self, name: String) -> Option<&DummyEnvironment> {
|
||||
// // return self
|
||||
// // .modules
|
||||
// // .get(&name)
|
||||
// // .or(self.modules.get("__last_module"));
|
||||
// return None;
|
||||
// // return self.modules[&name];
|
||||
// // name.map(|name| self.modules[&name]).or(self.last_module).unwrap()
|
||||
// }
|
||||
}
|
||||
|
||||
impl ScriptHandler for StoreCtrl {
|
||||
fn reset(&mut self) {}
|
||||
fn action_invoke(
|
||||
&mut self,
|
||||
module: Option<String>,
|
||||
field: String,
|
||||
args: Vec<Value>,
|
||||
) -> InvokationResult {
|
||||
unimplemented!()
|
||||
}
|
||||
fn action_get(&mut self, module: Option<String>, field: String) -> Value {
|
||||
unimplemented!()
|
||||
}
|
||||
fn module(&mut self, bytes: Vec<u8>, name: Option<String>) {
|
||||
let module_wrapped = compile(bytes);
|
||||
module_wrapped.expect("Module is invalid");
|
||||
}
|
||||
fn assert_malformed(&mut self, bytes: Vec<u8>) {
|
||||
let module_wrapped = compile(bytes);
|
||||
match module_wrapped {
|
||||
Err(Error(ErrorKind::CompileError(v), _)) => {}
|
||||
_ => panic!("Module compilation should have failed")
|
||||
}
|
||||
}
|
||||
fn assert_invalid(&mut self, bytes: Vec<u8>) {
|
||||
let module_wrapped = compile(bytes);
|
||||
match module_wrapped {
|
||||
Err(Error(ErrorKind::CompileError(v), _)) => {}
|
||||
_ => assert!(false, "Module compilation should have failed")
|
||||
}
|
||||
}
|
||||
fn assert_uninstantiable(&mut self, bytes: Vec<u8>) {
|
||||
// unimplemented!()
|
||||
}
|
||||
fn assert_exhaustion(&mut self, action: Action) {
|
||||
// unimplemented!()
|
||||
}
|
||||
fn register(&mut self, name: Option<String>, as_name: String) {
|
||||
// println!("ADD MODULE {:?} {:?}", name.unwrap(), as_name);
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
fn do_test(test_name: String) {
|
||||
let mut handler = &mut StoreCtrl::new();
|
||||
let test_path_str = format!("{}/src/spec/tests/{}.wast", env!("CARGO_MANIFEST_DIR"), test_name);
|
||||
let test_path = Path::new(&test_path_str);
|
||||
let res = run_single_file(&test_path, handler);
|
||||
res.present()
|
||||
}
|
||||
|
||||
macro_rules! wasm_tests {
|
||||
($($name:ident,)*) => {
|
||||
$(
|
||||
#[test]
|
||||
fn $name() {
|
||||
// let test_filename = $value;
|
||||
// assert_eq!(expected, fib(input));
|
||||
do_test(stringify!($name).to_string());
|
||||
}
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
wasm_tests!{
|
||||
_type,
|
||||
}
|
59
src/spec/tests/_type.wast
Normal file
59
src/spec/tests/_type.wast
Normal file
@ -0,0 +1,59 @@
|
||||
;; Test type definitions
|
||||
|
||||
(module
|
||||
(type (func))
|
||||
(type $t (func))
|
||||
|
||||
(type (func (param i32)))
|
||||
(type (func (param $x i32)))
|
||||
(type (func (result i32)))
|
||||
(type (func (param i32) (result i32)))
|
||||
(type (func (param $x i32) (result i32)))
|
||||
|
||||
(type (func (param f32 f64)))
|
||||
;; (type (func (result i64 f32)))
|
||||
;; (type (func (param i32 i64) (result f32 f64)))
|
||||
|
||||
(type (func (param f32) (param f64)))
|
||||
(type (func (param $x f32) (param f64)))
|
||||
(type (func (param f32) (param $y f64)))
|
||||
(type (func (param $x f32) (param $y f64)))
|
||||
;; (type (func (result i64) (result f32)))
|
||||
;; (type (func (param i32) (param i64) (result f32) (result f64)))
|
||||
;; (type (func (param $x i32) (param $y i64) (result f32) (result f64)))
|
||||
|
||||
(type (func (param f32 f64) (param $x i32) (param f64 i32 i32)))
|
||||
;; (type (func (result i64 i64 f32) (result f32 i32)))
|
||||
;; (type
|
||||
;; (func (param i32 i32) (param i64 i32) (result f32 f64) (result f64 i32))
|
||||
;; )
|
||||
|
||||
(type (func (param) (param $x f32) (param) (param) (param f64 i32) (param)))
|
||||
;; (type
|
||||
;; (func (result) (result) (result i64 i64) (result) (result f32) (result))
|
||||
;; )
|
||||
;; (type
|
||||
;; (func
|
||||
;; (param i32 i32) (param i64 i32) (param) (param $x i32) (param)
|
||||
;; (result) (result f32 f64) (result f64 i32) (result)
|
||||
;; )
|
||||
;; )
|
||||
)
|
||||
|
||||
(assert_malformed
|
||||
(module quote "(type (func (result i32) (param i32)))")
|
||||
"result before parameter"
|
||||
)
|
||||
(assert_malformed
|
||||
(module quote "(type (func (result $x i32)))")
|
||||
"unexpected token"
|
||||
)
|
||||
|
||||
(assert_invalid
|
||||
(module (type (func (result i32 i32))))
|
||||
"invalid result arity"
|
||||
)
|
||||
(assert_invalid
|
||||
(module (type (func (result i32) (result i32))))
|
||||
"invalid result arity"
|
||||
)
|
142
src/webassembly/compilation.rs
Normal file
142
src/webassembly/compilation.rs
Normal file
@ -0,0 +1,142 @@
|
||||
//! A `Compilation` contains the compiled function bodies for a WebAssembly
|
||||
//! module.
|
||||
use cranelift_codegen::binemit;
|
||||
use cranelift_codegen::ir;
|
||||
use cranelift_codegen::ir::ExternalName;
|
||||
use cranelift_codegen::isa;
|
||||
use cranelift_codegen::Context;
|
||||
use cranelift_entity::{EntityRef, PrimaryMap};
|
||||
use cranelift_wasm::{DefinedFuncIndex, FuncIndex, FuncTranslator};
|
||||
|
||||
use super::environ::{get_func_name, ModuleTranslation};
|
||||
|
||||
/// The result of compiling a WebAssemby module's functions.
|
||||
#[derive(Debug)]
|
||||
pub struct Compilation {
|
||||
/// Compiled machine code for the function bodies.
|
||||
pub functions: PrimaryMap<DefinedFuncIndex, Vec<u8>>,
|
||||
}
|
||||
|
||||
impl Compilation {
|
||||
/// Allocates the compilation result with the given function bodies.
|
||||
pub fn new(functions: PrimaryMap<DefinedFuncIndex, Vec<u8>>) -> Self {
|
||||
Self { functions }
|
||||
}
|
||||
}
|
||||
|
||||
/// Implementation of a relocation sink that just saves all the information for later
|
||||
pub struct RelocSink {
|
||||
/// Relocations recorded for the function.
|
||||
pub func_relocs: Vec<Relocation>,
|
||||
}
|
||||
|
||||
impl binemit::RelocSink for RelocSink {
|
||||
fn reloc_ebb(
|
||||
&mut self,
|
||||
_offset: binemit::CodeOffset,
|
||||
_reloc: binemit::Reloc,
|
||||
_ebb_offset: binemit::CodeOffset,
|
||||
) {
|
||||
// This should use the `offsets` field of `ir::Function`.
|
||||
panic!("ebb headers not yet implemented");
|
||||
}
|
||||
fn reloc_external(
|
||||
&mut self,
|
||||
offset: binemit::CodeOffset,
|
||||
reloc: binemit::Reloc,
|
||||
name: &ExternalName,
|
||||
addend: binemit::Addend,
|
||||
) {
|
||||
let reloc_target = if let ExternalName::User { namespace, index } = *name {
|
||||
debug_assert!(namespace == 0);
|
||||
RelocationTarget::UserFunc(FuncIndex::new(index as usize))
|
||||
} else if *name == ExternalName::testcase("grow_memory") {
|
||||
RelocationTarget::GrowMemory
|
||||
} else if *name == ExternalName::testcase("current_memory") {
|
||||
RelocationTarget::CurrentMemory
|
||||
} else {
|
||||
panic!("unrecognized external name")
|
||||
};
|
||||
self.func_relocs.push(Relocation {
|
||||
reloc,
|
||||
reloc_target,
|
||||
offset,
|
||||
addend,
|
||||
});
|
||||
}
|
||||
fn reloc_jt(
|
||||
&mut self,
|
||||
_offset: binemit::CodeOffset,
|
||||
_reloc: binemit::Reloc,
|
||||
_jt: ir::JumpTable,
|
||||
) {
|
||||
panic!("jump tables not yet implemented");
|
||||
}
|
||||
}
|
||||
|
||||
impl RelocSink {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
func_relocs: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A record of a relocation to perform.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Relocation {
|
||||
/// The relocation code.
|
||||
pub reloc: binemit::Reloc,
|
||||
/// Relocation target.
|
||||
pub reloc_target: RelocationTarget,
|
||||
/// The offset where to apply the relocation.
|
||||
pub offset: binemit::CodeOffset,
|
||||
/// The addend to add to the relocation value.
|
||||
pub addend: binemit::Addend,
|
||||
}
|
||||
|
||||
/// Destination function. Can be either user function or some special one, like grow_memory.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum RelocationTarget {
|
||||
/// The user function index.
|
||||
UserFunc(FuncIndex),
|
||||
/// Function for growing the default memory by the specified amount of pages.
|
||||
GrowMemory,
|
||||
/// Function for query current size of the default linear memory.
|
||||
CurrentMemory,
|
||||
}
|
||||
|
||||
/// Relocations to apply to function bodies.
|
||||
pub type Relocations = PrimaryMap<DefinedFuncIndex, Vec<Relocation>>;
|
||||
|
||||
/// Compile the module, producing a compilation result with associated
|
||||
/// relocations.
|
||||
pub fn compile_module<'data, 'module>(
|
||||
translation: &ModuleTranslation<'data, 'module>,
|
||||
isa: &isa::TargetIsa,
|
||||
) -> Result<(Compilation, Relocations), String> {
|
||||
let mut functions = PrimaryMap::new();
|
||||
let mut relocations = PrimaryMap::new();
|
||||
for (i, input) in translation.lazy.function_body_inputs.iter() {
|
||||
let func_index = translation.module.func_index(i);
|
||||
let mut context = Context::new();
|
||||
context.func.name = get_func_name(func_index);
|
||||
context.func.signature =
|
||||
translation.module.signatures[translation.module.functions[func_index]].clone();
|
||||
|
||||
let mut trans = FuncTranslator::new();
|
||||
trans
|
||||
.translate(input, &mut context.func, &mut translation.func_env())
|
||||
.map_err(|e| e.to_string())?;
|
||||
|
||||
let mut code_buf: Vec<u8> = Vec::new();
|
||||
let mut reloc_sink = RelocSink::new();
|
||||
let mut trap_sink = binemit::NullTrapSink {};
|
||||
context
|
||||
.compile_and_emit(isa, &mut code_buf, &mut reloc_sink, &mut trap_sink)
|
||||
.map_err(|e| e.to_string())?;
|
||||
functions.push(code_buf);
|
||||
relocations.push(reloc_sink.func_relocs);
|
||||
}
|
||||
Ok((Compilation::new(functions), relocations))
|
||||
}
|
491
src/webassembly/environ.rs
Normal file
491
src/webassembly/environ.rs
Normal file
@ -0,0 +1,491 @@
|
||||
use cranelift_codegen::cursor::FuncCursor;
|
||||
use cranelift_codegen::ir;
|
||||
use cranelift_codegen::ir::immediates::{Imm64, Offset32};
|
||||
use cranelift_codegen::ir::types::*;
|
||||
use cranelift_codegen::ir::{
|
||||
AbiParam, ArgumentPurpose, ExtFuncData, ExternalName, FuncRef, Function, InstBuilder, Signature,
|
||||
};
|
||||
use cranelift_codegen::isa;
|
||||
use cranelift_codegen::settings;
|
||||
use cranelift_entity::EntityRef;
|
||||
use cranelift_wasm::{
|
||||
self, translate_module, FuncIndex, Global, GlobalIndex, GlobalVariable, Memory, MemoryIndex,
|
||||
SignatureIndex, Table, TableIndex, WasmResult,
|
||||
};
|
||||
use target_lexicon::Triple;
|
||||
|
||||
use super::module::{DataInitializer, Export, LazyContents, Module, TableElements};
|
||||
|
||||
/// Compute a `ir::ExternalName` for a given wasm function index.
|
||||
pub fn get_func_name(func_index: FuncIndex) -> ir::ExternalName {
|
||||
debug_assert!(FuncIndex::new(func_index.index() as u32 as usize) == func_index);
|
||||
ir::ExternalName::user(0, func_index.index() as u32)
|
||||
}
|
||||
|
||||
/// Object containing the standalone environment information. To be passed after creation as
|
||||
/// argument to `compile_module`.
|
||||
pub struct ModuleEnvironment<'data, 'module> {
|
||||
/// Compilation setting flags.
|
||||
pub isa: &'module isa::TargetIsa,
|
||||
|
||||
/// Module information.
|
||||
pub module: &'module mut Module,
|
||||
|
||||
/// References to information to be decoded later.
|
||||
pub lazy: LazyContents<'data>,
|
||||
}
|
||||
|
||||
impl<'data, 'module> ModuleEnvironment<'data, 'module> {
|
||||
/// Allocates the enironment data structures with the given isa.
|
||||
pub fn new(isa: &'module isa::TargetIsa, module: &'module mut Module) -> Self {
|
||||
Self {
|
||||
isa,
|
||||
module,
|
||||
lazy: LazyContents::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn func_env(&self) -> FuncEnvironment {
|
||||
FuncEnvironment::new(self.isa, &self.module)
|
||||
}
|
||||
|
||||
fn pointer_type(&self) -> ir::Type {
|
||||
use cranelift_wasm::FuncEnvironment;
|
||||
self.func_env().pointer_type()
|
||||
}
|
||||
|
||||
/// Translate the given wasm module data using this environment. This consumes the
|
||||
/// `ModuleEnvironment` with its mutable reference to the `Module` and produces a
|
||||
/// `ModuleTranslation` with an immutable reference to the `Module` (which has
|
||||
/// become fully populated).
|
||||
pub fn translate(mut self, data: &'data [u8]) -> WasmResult<ModuleTranslation<'data, 'module>> {
|
||||
translate_module(data, &mut self)?;
|
||||
|
||||
Ok(ModuleTranslation {
|
||||
isa: self.isa,
|
||||
module: self.module,
|
||||
lazy: self.lazy,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// The FuncEnvironment implementation for use by the `ModuleEnvironment`.
|
||||
pub struct FuncEnvironment<'module_environment> {
|
||||
/// Compilation setting flags.
|
||||
isa: &'module_environment isa::TargetIsa,
|
||||
|
||||
/// The module-level environment which this function-level environment belongs to.
|
||||
pub module: &'module_environment Module,
|
||||
|
||||
/// The Cranelift global holding the base address of the memories vector.
|
||||
pub memories_base: Option<ir::GlobalValue>,
|
||||
|
||||
/// The Cranelift global holding the base address of the globals vector.
|
||||
pub globals_base: Option<ir::GlobalValue>,
|
||||
|
||||
/// The external function declaration for implementing wasm's `current_memory`.
|
||||
pub current_memory_extfunc: Option<FuncRef>,
|
||||
|
||||
/// The external function declaration for implementing wasm's `grow_memory`.
|
||||
pub grow_memory_extfunc: Option<FuncRef>,
|
||||
}
|
||||
|
||||
impl<'module_environment> FuncEnvironment<'module_environment> {
|
||||
pub fn new(
|
||||
isa: &'module_environment isa::TargetIsa,
|
||||
module: &'module_environment Module,
|
||||
) -> Self {
|
||||
Self {
|
||||
isa,
|
||||
module,
|
||||
memories_base: None,
|
||||
globals_base: None,
|
||||
current_memory_extfunc: None,
|
||||
grow_memory_extfunc: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Transform the call argument list in preparation for making a call.
|
||||
fn get_real_call_args(func: &Function, call_args: &[ir::Value]) -> Vec<ir::Value> {
|
||||
let mut real_call_args = Vec::with_capacity(call_args.len() + 1);
|
||||
real_call_args.extend_from_slice(call_args);
|
||||
real_call_args.push(func.special_param(ArgumentPurpose::VMContext).unwrap());
|
||||
real_call_args
|
||||
}
|
||||
|
||||
fn pointer_bytes(&self) -> usize {
|
||||
usize::from(self.isa.pointer_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
/// This trait is useful for `translate_module` because it tells how to translate
|
||||
/// enironment-dependent wasm instructions. These functions should not be called by the user.
|
||||
impl<'data, 'module> cranelift_wasm::ModuleEnvironment<'data>
|
||||
for ModuleEnvironment<'data, 'module>
|
||||
{
|
||||
fn get_func_name(&self, func_index: FuncIndex) -> ir::ExternalName {
|
||||
get_func_name(func_index)
|
||||
}
|
||||
|
||||
fn flags(&self) -> &settings::Flags {
|
||||
self.isa.flags()
|
||||
}
|
||||
|
||||
fn declare_signature(&mut self, sig: &ir::Signature) {
|
||||
let mut sig = sig.clone();
|
||||
sig.params.push(AbiParam::special(
|
||||
self.pointer_type(),
|
||||
ArgumentPurpose::VMContext,
|
||||
));
|
||||
// TODO: Deduplicate signatures.
|
||||
self.module.signatures.push(sig);
|
||||
}
|
||||
|
||||
fn get_signature(&self, sig_index: SignatureIndex) -> &ir::Signature {
|
||||
&self.module.signatures[sig_index]
|
||||
}
|
||||
|
||||
fn declare_func_import(&mut self, sig_index: SignatureIndex, module: &str, field: &str) {
|
||||
debug_assert_eq!(
|
||||
self.module.functions.len(),
|
||||
self.module.imported_funcs.len(),
|
||||
"Imported functions must be declared first"
|
||||
);
|
||||
self.module.functions.push(sig_index);
|
||||
|
||||
self.module
|
||||
.imported_funcs
|
||||
.push((String::from(module), String::from(field)));
|
||||
}
|
||||
|
||||
fn get_num_func_imports(&self) -> usize {
|
||||
self.module.imported_funcs.len()
|
||||
}
|
||||
|
||||
fn declare_func_type(&mut self, sig_index: SignatureIndex) {
|
||||
self.module.functions.push(sig_index);
|
||||
}
|
||||
|
||||
fn get_func_type(&self, func_index: FuncIndex) -> SignatureIndex {
|
||||
self.module.functions[func_index]
|
||||
}
|
||||
|
||||
fn declare_global(&mut self, global: Global) {
|
||||
self.module.globals.push(global);
|
||||
}
|
||||
|
||||
fn get_global(&self, global_index: GlobalIndex) -> &Global {
|
||||
&self.module.globals[global_index]
|
||||
}
|
||||
|
||||
fn declare_table(&mut self, table: Table) {
|
||||
self.module.tables.push(table);
|
||||
}
|
||||
|
||||
fn declare_table_elements(
|
||||
&mut self,
|
||||
table_index: TableIndex,
|
||||
base: Option<GlobalIndex>,
|
||||
offset: usize,
|
||||
elements: Vec<FuncIndex>,
|
||||
) {
|
||||
debug_assert!(base.is_none(), "global-value offsets not supported yet");
|
||||
self.module.table_elements.push(TableElements {
|
||||
table_index,
|
||||
base,
|
||||
offset,
|
||||
elements,
|
||||
});
|
||||
}
|
||||
|
||||
fn declare_memory(&mut self, memory: Memory) {
|
||||
self.module.memories.push(memory);
|
||||
}
|
||||
|
||||
fn declare_data_initialization(
|
||||
&mut self,
|
||||
memory_index: MemoryIndex,
|
||||
base: Option<GlobalIndex>,
|
||||
offset: usize,
|
||||
data: &'data [u8],
|
||||
) {
|
||||
debug_assert!(base.is_none(), "global-value offsets not supported yet");
|
||||
self.lazy.data_initializers.push(DataInitializer {
|
||||
memory_index,
|
||||
base,
|
||||
offset,
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
fn declare_func_export(&mut self, func_index: FuncIndex, name: &str) {
|
||||
self.module
|
||||
.exports
|
||||
.insert(String::from(name), Export::Function(func_index));
|
||||
}
|
||||
|
||||
fn declare_table_export(&mut self, table_index: TableIndex, name: &str) {
|
||||
self.module
|
||||
.exports
|
||||
.insert(String::from(name), Export::Table(table_index));
|
||||
}
|
||||
|
||||
fn declare_memory_export(&mut self, memory_index: MemoryIndex, name: &str) {
|
||||
self.module
|
||||
.exports
|
||||
.insert(String::from(name), Export::Memory(memory_index));
|
||||
}
|
||||
|
||||
fn declare_global_export(&mut self, global_index: GlobalIndex, name: &str) {
|
||||
self.module
|
||||
.exports
|
||||
.insert(String::from(name), Export::Global(global_index));
|
||||
}
|
||||
|
||||
fn declare_start_func(&mut self, func_index: FuncIndex) {
|
||||
debug_assert!(self.module.start_func.is_none());
|
||||
self.module.start_func = Some(func_index);
|
||||
}
|
||||
|
||||
fn define_function_body(&mut self, body_bytes: &'data [u8]) -> WasmResult<()> {
|
||||
self.lazy.function_body_inputs.push(body_bytes);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'module_environment> {
|
||||
fn flags(&self) -> &settings::Flags {
|
||||
&self.isa.flags()
|
||||
}
|
||||
|
||||
fn triple(&self) -> &Triple {
|
||||
self.isa.triple()
|
||||
}
|
||||
|
||||
fn make_global(&mut self, func: &mut ir::Function, index: GlobalIndex) -> GlobalVariable {
|
||||
let pointer_bytes = self.pointer_bytes();
|
||||
let globals_base = self.globals_base.unwrap_or_else(|| {
|
||||
let new_base = func.create_global_value(ir::GlobalValueData::VMContext {
|
||||
offset: Offset32::new(0),
|
||||
});
|
||||
self.globals_base = Some(new_base);
|
||||
new_base
|
||||
});
|
||||
let offset = index * pointer_bytes;
|
||||
let offset32 = offset as i32;
|
||||
debug_assert_eq!(offset32 as usize, offset);
|
||||
let gv = func.create_global_value(ir::GlobalValueData::Deref {
|
||||
base: globals_base,
|
||||
offset: Offset32::new(offset32),
|
||||
memory_type: self.pointer_type(),
|
||||
});
|
||||
GlobalVariable::Memory {
|
||||
gv,
|
||||
ty: self.module.globals[index].ty,
|
||||
}
|
||||
}
|
||||
|
||||
fn make_heap(&mut self, func: &mut ir::Function, index: MemoryIndex) -> ir::Heap {
|
||||
let pointer_bytes = self.pointer_bytes();
|
||||
let memories_base = self.memories_base.unwrap_or_else(|| {
|
||||
let new_base = func.create_global_value(ir::GlobalValueData::VMContext {
|
||||
offset: Offset32::new(pointer_bytes as i32),
|
||||
});
|
||||
self.globals_base = Some(new_base);
|
||||
new_base
|
||||
});
|
||||
let offset = index * pointer_bytes;
|
||||
let offset32 = offset as i32;
|
||||
debug_assert_eq!(offset32 as usize, offset);
|
||||
let heap_base_addr = func.create_global_value(ir::GlobalValueData::Deref {
|
||||
base: memories_base,
|
||||
offset: Offset32::new(offset32),
|
||||
memory_type: self.pointer_type(),
|
||||
});
|
||||
let heap_base = func.create_global_value(ir::GlobalValueData::Deref {
|
||||
base: heap_base_addr,
|
||||
offset: Offset32::new(0),
|
||||
memory_type: self.pointer_type(),
|
||||
});
|
||||
func.create_heap(ir::HeapData {
|
||||
base: heap_base,
|
||||
min_size: 0.into(),
|
||||
guard_size: 0x8000_0000.into(),
|
||||
style: ir::HeapStyle::Static {
|
||||
bound: 0x1_0000_0000.into(),
|
||||
},
|
||||
index_type: I32,
|
||||
})
|
||||
}
|
||||
|
||||
fn make_table(&mut self, func: &mut ir::Function, _index: TableIndex) -> ir::Table {
|
||||
let pointer_bytes = self.pointer_bytes();
|
||||
let base_gv_addr = func.create_global_value(ir::GlobalValueData::VMContext {
|
||||
offset: Offset32::new(pointer_bytes as i32 * 2),
|
||||
});
|
||||
let base_gv = func.create_global_value(ir::GlobalValueData::Deref {
|
||||
base: base_gv_addr,
|
||||
offset: 0.into(),
|
||||
memory_type: self.pointer_type(),
|
||||
});
|
||||
let bound_gv_addr = func.create_global_value(ir::GlobalValueData::VMContext {
|
||||
offset: Offset32::new(pointer_bytes as i32 * 3),
|
||||
});
|
||||
let bound_gv = func.create_global_value(ir::GlobalValueData::Deref {
|
||||
base: bound_gv_addr,
|
||||
offset: 0.into(),
|
||||
memory_type: I32,
|
||||
});
|
||||
|
||||
func.create_table(ir::TableData {
|
||||
base_gv,
|
||||
min_size: Imm64::new(0),
|
||||
bound_gv,
|
||||
element_size: Imm64::new(i64::from(self.pointer_bytes() as i64)),
|
||||
index_type: I32,
|
||||
})
|
||||
}
|
||||
|
||||
fn make_indirect_sig(&mut self, func: &mut ir::Function, index: SignatureIndex) -> ir::SigRef {
|
||||
func.import_signature(self.module.signatures[index].clone())
|
||||
}
|
||||
|
||||
fn make_direct_func(&mut self, func: &mut ir::Function, index: FuncIndex) -> ir::FuncRef {
|
||||
let sigidx = self.module.functions[index];
|
||||
let signature = func.import_signature(self.module.signatures[sigidx].clone());
|
||||
let name = get_func_name(index);
|
||||
// We currently allocate all code segments independently, so nothing
|
||||
// is colocated.
|
||||
let colocated = false;
|
||||
func.import_function(ir::ExtFuncData {
|
||||
name,
|
||||
signature,
|
||||
colocated,
|
||||
})
|
||||
}
|
||||
|
||||
fn translate_call_indirect(
|
||||
&mut self,
|
||||
mut pos: FuncCursor,
|
||||
table_index: TableIndex,
|
||||
table: ir::Table,
|
||||
_sig_index: SignatureIndex,
|
||||
sig_ref: ir::SigRef,
|
||||
callee: ir::Value,
|
||||
call_args: &[ir::Value],
|
||||
) -> WasmResult<ir::Inst> {
|
||||
// TODO: Cranelift's call_indirect doesn't implement signature checking,
|
||||
// so we need to implement it ourselves.
|
||||
debug_assert_eq!(table_index, 0, "non-default tables not supported yet");
|
||||
|
||||
let table_entry_addr = pos.ins().table_addr(I64, table, callee, 0);
|
||||
|
||||
// Dereference table_entry_addr to get the function address.
|
||||
let mut mem_flags = ir::MemFlags::new();
|
||||
mem_flags.set_notrap();
|
||||
mem_flags.set_aligned();
|
||||
let func_addr = pos
|
||||
.ins()
|
||||
.load(self.pointer_type(), mem_flags, table_entry_addr, 0);
|
||||
|
||||
let real_call_args = FuncEnvironment::get_real_call_args(pos.func, call_args);
|
||||
Ok(pos.ins().call_indirect(sig_ref, func_addr, &real_call_args))
|
||||
}
|
||||
|
||||
fn translate_call(
|
||||
&mut self,
|
||||
mut pos: FuncCursor,
|
||||
_callee_index: FuncIndex,
|
||||
callee: ir::FuncRef,
|
||||
call_args: &[ir::Value],
|
||||
) -> WasmResult<ir::Inst> {
|
||||
let real_call_args = FuncEnvironment::get_real_call_args(pos.func, call_args);
|
||||
Ok(pos.ins().call(callee, &real_call_args))
|
||||
}
|
||||
|
||||
fn translate_memory_grow(
|
||||
&mut self,
|
||||
mut pos: FuncCursor,
|
||||
index: MemoryIndex,
|
||||
_heap: ir::Heap,
|
||||
val: ir::Value,
|
||||
) -> WasmResult<ir::Value> {
|
||||
let grow_mem_func = self.grow_memory_extfunc.unwrap_or_else(|| {
|
||||
let sig_ref = pos.func.import_signature(Signature {
|
||||
call_conv: self.isa.flags().call_conv(),
|
||||
params: vec![
|
||||
AbiParam::new(I32),
|
||||
AbiParam::new(I32),
|
||||
AbiParam::special(self.pointer_type(), ArgumentPurpose::VMContext),
|
||||
],
|
||||
returns: vec![AbiParam::new(I32)],
|
||||
});
|
||||
// We currently allocate all code segments independently, so nothing
|
||||
// is colocated.
|
||||
let colocated = false;
|
||||
// FIXME: Use a real ExternalName system.
|
||||
pos.func.import_function(ExtFuncData {
|
||||
name: ExternalName::testcase("grow_memory"),
|
||||
signature: sig_ref,
|
||||
colocated,
|
||||
})
|
||||
});
|
||||
self.grow_memory_extfunc = Some(grow_mem_func);
|
||||
let memory_index = pos.ins().iconst(I32, index as i64);
|
||||
let vmctx = pos.func.special_param(ArgumentPurpose::VMContext).unwrap();
|
||||
let call_inst = pos.ins().call(grow_mem_func, &[val, memory_index, vmctx]);
|
||||
Ok(*pos.func.dfg.inst_results(call_inst).first().unwrap())
|
||||
}
|
||||
|
||||
fn translate_memory_size(
|
||||
&mut self,
|
||||
mut pos: FuncCursor,
|
||||
index: MemoryIndex,
|
||||
_heap: ir::Heap,
|
||||
) -> WasmResult<ir::Value> {
|
||||
let cur_mem_func = self.current_memory_extfunc.unwrap_or_else(|| {
|
||||
let sig_ref = pos.func.import_signature(Signature {
|
||||
call_conv: self.isa.flags().call_conv(),
|
||||
params: vec![
|
||||
AbiParam::new(I32),
|
||||
AbiParam::special(self.pointer_type(), ArgumentPurpose::VMContext),
|
||||
],
|
||||
returns: vec![AbiParam::new(I32)],
|
||||
});
|
||||
// We currently allocate all code segments independently, so nothing
|
||||
// is colocated.
|
||||
let colocated = false;
|
||||
// FIXME: Use a real ExternalName system.
|
||||
pos.func.import_function(ExtFuncData {
|
||||
name: ExternalName::testcase("current_memory"),
|
||||
signature: sig_ref,
|
||||
colocated,
|
||||
})
|
||||
});
|
||||
self.current_memory_extfunc = Some(cur_mem_func);
|
||||
let memory_index = pos.ins().iconst(I32, index as i64);
|
||||
let vmctx = pos.func.special_param(ArgumentPurpose::VMContext).unwrap();
|
||||
let call_inst = pos.ins().call(cur_mem_func, &[memory_index, vmctx]);
|
||||
Ok(*pos.func.dfg.inst_results(call_inst).first().unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
/// The result of translating via `ModuleEnvironment`.
|
||||
pub struct ModuleTranslation<'data, 'module> {
|
||||
/// Compilation setting flags.
|
||||
pub isa: &'module isa::TargetIsa,
|
||||
|
||||
/// Module information.
|
||||
pub module: &'module Module,
|
||||
|
||||
/// Pointers into the raw data buffer.
|
||||
pub lazy: LazyContents<'data>,
|
||||
}
|
||||
|
||||
/// Convenience functions for the user to be called after execution for debug purposes.
|
||||
impl<'data, 'module> ModuleTranslation<'data, 'module> {
|
||||
/// Return a new `FuncEnvironment` for translation a function.
|
||||
pub fn func_env(&self) -> FuncEnvironment {
|
||||
FuncEnvironment::new(self.isa, &self.module)
|
||||
}
|
||||
}
|
38
src/webassembly/errors.rs
Normal file
38
src/webassembly/errors.rs
Normal file
@ -0,0 +1,38 @@
|
||||
// WebAssembly.CompileError(message, fileName, lineNumber)
|
||||
|
||||
// The WebAssembly.CompileError() constructor creates a new WebAssembly
|
||||
// CompileError object, which indicates an error during WebAssembly
|
||||
// decoding or validation
|
||||
|
||||
|
||||
// WebAssembly.LinkError(message, fileName, lineNumber)
|
||||
|
||||
// The WebAssembly.LinkError() constructor creates a new WebAssembly
|
||||
// LinkError object, which indicates an error during module instantiation
|
||||
// (besides traps from the start function).
|
||||
|
||||
// new WebAssembly.RuntimeError(message, fileName, lineNumber)
|
||||
|
||||
// The WebAssembly.RuntimeError() constructor creates a new WebAssembly
|
||||
// RuntimeError object — the type that is thrown whenever WebAssembly
|
||||
// specifies a trap.
|
||||
|
||||
|
||||
error_chain! {
|
||||
// Define additional `ErrorKind` variants. Define custom responses with the
|
||||
// `description` and `display` calls.
|
||||
errors {
|
||||
CompileError(reason: String) {
|
||||
description("WebAssembly compilation error")
|
||||
display("Compilation error: '{}'", reason)
|
||||
}
|
||||
LinkError {
|
||||
description("WebAssembly link error")
|
||||
// display("invalid toolchain name: '{}'", t)
|
||||
}
|
||||
RuntimeError {
|
||||
description("WebAssembly runtime error")
|
||||
// display("invalid toolchain name: '{}'", t)
|
||||
}
|
||||
}
|
||||
}
|
117
src/webassembly/instance.rs
Normal file
117
src/webassembly/instance.rs
Normal file
@ -0,0 +1,117 @@
|
||||
//! An `Instance` contains all the runtime state used by execution of a wasm
|
||||
//! module.
|
||||
use cranelift_codegen::ir;
|
||||
use cranelift_wasm::GlobalIndex;
|
||||
|
||||
use super::memory::LinearMemory;
|
||||
use super::module::{DataInitializer, Module, TableElements};
|
||||
use super::compilation::Compilation;
|
||||
|
||||
/// An Instance of a WebAssemby module.
|
||||
#[derive(Debug)]
|
||||
pub struct Instance {
|
||||
/// WebAssembly table data.
|
||||
pub tables: Vec<Vec<usize>>,
|
||||
|
||||
/// WebAssembly linear memory data.
|
||||
pub memories: Vec<LinearMemory>,
|
||||
|
||||
/// WebAssembly global variable data.
|
||||
pub globals: Vec<u8>,
|
||||
}
|
||||
|
||||
impl Instance {
|
||||
/// Create a new `Instance`.
|
||||
pub fn new(
|
||||
module: &Module,
|
||||
compilation: &Compilation,
|
||||
data_initializers: &[DataInitializer],
|
||||
) -> Self {
|
||||
let mut result = Self {
|
||||
tables: Vec::new(),
|
||||
memories: Vec::new(),
|
||||
globals: Vec::new(),
|
||||
};
|
||||
result.instantiate_tables(module, compilation, &module.table_elements);
|
||||
result.instantiate_memories(module, data_initializers);
|
||||
result.instantiate_globals(module);
|
||||
result
|
||||
}
|
||||
|
||||
/// Allocate memory in `self` for just the tables of the current module.
|
||||
fn instantiate_tables(
|
||||
&mut self,
|
||||
module: &Module,
|
||||
compilation: &Compilation,
|
||||
table_initializers: &[TableElements],
|
||||
) {
|
||||
debug_assert!(self.tables.is_empty());
|
||||
self.tables.reserve_exact(module.tables.len());
|
||||
for table in &module.tables {
|
||||
let len = table.size;
|
||||
let mut v = Vec::with_capacity(len);
|
||||
v.resize(len, 0);
|
||||
self.tables.push(v);
|
||||
}
|
||||
for init in table_initializers {
|
||||
debug_assert!(init.base.is_none(), "globalvar base not supported yet");
|
||||
let to_init =
|
||||
&mut self.tables[init.table_index][init.offset..init.offset + init.elements.len()];
|
||||
for (i, func_idx) in init.elements.iter().enumerate() {
|
||||
let code_buf = &compilation.functions[module.defined_func_index(*func_idx).expect(
|
||||
"table element initializer with imported function not supported yet",
|
||||
)];
|
||||
to_init[i] = code_buf.as_ptr() as usize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Allocate memory in `instance` for just the memories of the current module.
|
||||
fn instantiate_memories(&mut self, module: &Module, data_initializers: &[DataInitializer]) {
|
||||
debug_assert!(self.memories.is_empty());
|
||||
// Allocate the underlying memory and initialize it to all zeros.
|
||||
self.memories.reserve_exact(module.memories.len());
|
||||
for memory in &module.memories {
|
||||
let v = LinearMemory::new(memory.pages_count as u32, memory.maximum.map(|m| m as u32));
|
||||
self.memories.push(v);
|
||||
}
|
||||
for init in data_initializers {
|
||||
debug_assert!(init.base.is_none(), "globalvar base not supported yet");
|
||||
let mem_mut = self.memories[init.memory_index].as_mut();
|
||||
let to_init = &mut mem_mut[init.offset..init.offset + init.data.len()];
|
||||
to_init.copy_from_slice(init.data);
|
||||
}
|
||||
}
|
||||
|
||||
/// Allocate memory in `instance` for just the globals of the current module,
|
||||
/// without any initializers applied yet.
|
||||
fn instantiate_globals(&mut self, module: &Module) {
|
||||
debug_assert!(self.globals.is_empty());
|
||||
// Allocate the underlying memory and initialize it to all zeros.
|
||||
let globals_data_size = module.globals.len() * 8;
|
||||
self.globals.resize(globals_data_size, 0);
|
||||
}
|
||||
|
||||
/// Returns a mutable reference to a linear memory under the specified index.
|
||||
pub fn memory_mut(&mut self, memory_index: usize) -> &mut LinearMemory {
|
||||
self.memories
|
||||
.get_mut(memory_index)
|
||||
.unwrap_or_else(|| panic!("no memory for index {}", memory_index))
|
||||
}
|
||||
|
||||
/// Returns a slice of the contents of allocated linear memory.
|
||||
pub fn inspect_memory(&self, memory_index: usize, address: usize, len: usize) -> &[u8] {
|
||||
&self
|
||||
.memories
|
||||
.get(memory_index)
|
||||
.unwrap_or_else(|| panic!("no memory for index {}", memory_index))
|
||||
.as_ref()[address..address + len]
|
||||
}
|
||||
|
||||
/// Shows the value of a global variable.
|
||||
pub fn inspect_global(&self, global_index: GlobalIndex, ty: ir::Type) -> &[u8] {
|
||||
let offset = global_index * 8;
|
||||
let len = ty.bytes() as usize;
|
||||
&self.globals[offset..offset + len]
|
||||
}
|
||||
}
|
113
src/webassembly/memory.rs
Normal file
113
src/webassembly/memory.rs
Normal file
@ -0,0 +1,113 @@
|
||||
use memmap;
|
||||
use std::fmt;
|
||||
|
||||
const PAGE_SIZE: u32 = 65536;
|
||||
const MAX_PAGES: u32 = 65536;
|
||||
|
||||
/// A linear memory instance.
|
||||
///
|
||||
/// This linear memory has a stable base address and at the same time allows
|
||||
/// for dynamical growing.
|
||||
pub struct LinearMemory {
|
||||
mmap: memmap::MmapMut,
|
||||
current: u32,
|
||||
maximum: Option<u32>,
|
||||
}
|
||||
|
||||
impl LinearMemory {
|
||||
/// 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(initial: u32, maximum: Option<u32>) -> Self {
|
||||
assert!(initial <= MAX_PAGES);
|
||||
assert!(maximum.is_none() || maximum.unwrap() <= MAX_PAGES);
|
||||
|
||||
let len = PAGE_SIZE * match maximum {
|
||||
Some(val) => val,
|
||||
None => initial,
|
||||
};
|
||||
let mmap = memmap::MmapMut::map_anon(len as usize).unwrap();
|
||||
Self {
|
||||
mmap,
|
||||
current: initial,
|
||||
maximum,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns an base address of this linear memory.
|
||||
pub fn base_addr(&mut self) -> *mut u8 {
|
||||
self.mmap.as_mut_ptr()
|
||||
}
|
||||
|
||||
/// Returns a number of allocated wasm pages.
|
||||
pub fn current_size(&self) -> u32 {
|
||||
self.current
|
||||
}
|
||||
|
||||
/// 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(&mut self, add_pages: u32) -> Option<u32> {
|
||||
let new_pages = match self.current.checked_add(add_pages) {
|
||||
Some(new_pages) => new_pages,
|
||||
None => return None,
|
||||
};
|
||||
if let Some(val) = self.maximum {
|
||||
if new_pages > val {
|
||||
return None;
|
||||
}
|
||||
} else {
|
||||
// Wasm linear memories are never allowed to grow beyond what is
|
||||
// indexable. If the memory has no maximum, enforce the greatest
|
||||
// limit here.
|
||||
if new_pages >= 65536 {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
let prev_pages = self.current;
|
||||
let new_bytes = (new_pages * PAGE_SIZE) as usize;
|
||||
|
||||
if self.mmap.len() < new_bytes {
|
||||
// If we have no maximum, this is a "dynamic" heap, and it's allowed
|
||||
// to move.
|
||||
assert!(self.maximum.is_none());
|
||||
let mut new_mmap = memmap::MmapMut::map_anon(new_bytes).unwrap();
|
||||
new_mmap.copy_from_slice(&self.mmap);
|
||||
self.mmap = new_mmap;
|
||||
}
|
||||
|
||||
self.current = new_pages;
|
||||
|
||||
// Ensure that newly allocated area is zeroed.
|
||||
let new_start_offset = (prev_pages * PAGE_SIZE) as usize;
|
||||
let new_end_offset = (new_pages * PAGE_SIZE) as usize;
|
||||
for i in new_start_offset..new_end_offset {
|
||||
assert!(self.mmap[i] == 0);
|
||||
}
|
||||
|
||||
Some(prev_pages)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for LinearMemory {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_struct("LinearMemory")
|
||||
.field("current", &self.current)
|
||||
.field("maximum", &self.maximum)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<[u8]> for LinearMemory {
|
||||
fn as_ref(&self) -> &[u8] {
|
||||
&self.mmap
|
||||
}
|
||||
}
|
||||
|
||||
impl AsMut<[u8]> for LinearMemory {
|
||||
fn as_mut(&mut self) -> &mut [u8] {
|
||||
&mut self.mmap
|
||||
}
|
||||
}
|
114
src/webassembly/mod.rs
Normal file
114
src/webassembly/mod.rs
Normal file
@ -0,0 +1,114 @@
|
||||
pub mod module;
|
||||
pub mod compilation;
|
||||
pub mod memory;
|
||||
pub mod environ;
|
||||
pub mod instance;
|
||||
pub mod errors;
|
||||
pub mod utils;
|
||||
|
||||
use cranelift_native;
|
||||
use cranelift_codegen::isa::TargetIsa;
|
||||
use cranelift_codegen::settings;
|
||||
use cranelift_codegen::settings::Configurable;
|
||||
|
||||
pub use self::compilation::compile_module;
|
||||
pub use self::environ::ModuleEnvironment;
|
||||
pub use self::module::Module;
|
||||
pub use self::instance::Instance;
|
||||
pub use self::errors::{Error, ErrorKind};
|
||||
use wasmparser;
|
||||
|
||||
pub struct ResultObject {
|
||||
/// A WebAssembly.Module object representing the compiled WebAssembly module.
|
||||
/// This Module can be instantiated again
|
||||
module: Module,
|
||||
/// A WebAssembly.Instance object that contains all the Exported WebAssembly
|
||||
/// functions.
|
||||
instance: Instance
|
||||
}
|
||||
|
||||
pub struct ImportObject {
|
||||
}
|
||||
|
||||
/// The WebAssembly.instantiate() function allows you to compile and
|
||||
/// instantiate WebAssembly code
|
||||
|
||||
/// Params:
|
||||
/// * `buffer_source`: A `Vec<u8>` containing the
|
||||
/// binary code of the .wasm module you want to compile.
|
||||
|
||||
/// * `import_object`: An object containing the values to be imported
|
||||
/// into the newly-created Instance, such as functions or
|
||||
/// WebAssembly.Memory objects. There must be one matching property
|
||||
/// for each declared import of the compiled module or else a
|
||||
/// WebAssembly.LinkError is thrown.
|
||||
|
||||
/// Errors:
|
||||
/// If the operation fails, the Result rejects with a
|
||||
/// WebAssembly.CompileError, WebAssembly.LinkError, or
|
||||
/// WebAssembly.RuntimeError, depending on the cause of the failure.
|
||||
pub fn instantiate(buffer_source: Vec<u8>, import_object: ImportObject) -> Result<ResultObject, Error> {
|
||||
let module = compile(buffer_source)?;
|
||||
let instance = Instance {
|
||||
tables: Vec::new(),
|
||||
memories: Vec::new(),
|
||||
globals: Vec::new(),
|
||||
};
|
||||
|
||||
Ok(ResultObject {
|
||||
module,
|
||||
instance
|
||||
})
|
||||
}
|
||||
|
||||
/// The WebAssembly.compile() function compiles a WebAssembly.Module
|
||||
/// from WebAssembly binary code. This function is useful if it
|
||||
/// is necessary to a compile a module before it can be instantiated
|
||||
/// (otherwise, the WebAssembly.instantiate() function should be used).
|
||||
|
||||
/// Params:
|
||||
/// * `buffer_source`: A `Vec<u8>` containing the
|
||||
/// binary code of the .wasm module you want to compile.
|
||||
|
||||
/// Errors:
|
||||
/// If the operation fails, the Result rejects with a
|
||||
/// WebAssembly.CompileError.
|
||||
pub fn compile(buffer_source: Vec<u8>) -> Result<Module, Error> {
|
||||
let isa = construct_isa();
|
||||
|
||||
let mut module = Module::new();
|
||||
let environ = ModuleEnvironment::new(&*isa, &mut module);
|
||||
let translation = environ.translate(&buffer_source).map_err(|e| ErrorKind::CompileError(e.to_string()))?;
|
||||
compile_module(&translation, &*isa)?;
|
||||
|
||||
Ok(module)
|
||||
}
|
||||
|
||||
fn construct_isa() -> Box<TargetIsa> {
|
||||
let (mut flag_builder, isa_builder) = cranelift_native::builders().unwrap_or_else(|_| {
|
||||
panic!("host machine is not a supported target");
|
||||
});
|
||||
|
||||
// Enable verifier passes in debug mode.
|
||||
// if cfg!(debug_assertions) {
|
||||
flag_builder.enable("enable_verifier").unwrap();
|
||||
// }
|
||||
|
||||
// Enable optimization if requested.
|
||||
// if args.flag_optimize {
|
||||
flag_builder.set("opt_level", "best").unwrap();
|
||||
// }
|
||||
|
||||
isa_builder.finish(settings::Flags::new(flag_builder))
|
||||
}
|
||||
|
||||
/// The WebAssembly.validate() function validates a given typed
|
||||
/// array of WebAssembly binary code, returning whether the bytes
|
||||
/// form a valid wasm module (true) or not (false).
|
||||
|
||||
/// Params:
|
||||
/// * `buffer_source`: A `Vec<u8>` containing the
|
||||
/// binary code of the .wasm module you want to compile.
|
||||
pub fn validate(buffer_source: &Vec<u8>) -> bool {
|
||||
wasmparser::validate(buffer_source, None)
|
||||
}
|
135
src/webassembly/module.rs
Normal file
135
src/webassembly/module.rs
Normal file
@ -0,0 +1,135 @@
|
||||
/// A WebAssembly.Module object representing the compiled WebAssembly module.
|
||||
extern crate cranelift_codegen;
|
||||
extern crate cranelift_entity;
|
||||
extern crate cranelift_wasm;
|
||||
|
||||
use cranelift_codegen::ir;
|
||||
use cranelift_entity::{EntityRef, PrimaryMap};
|
||||
use cranelift_wasm::{
|
||||
DefinedFuncIndex, FuncIndex, Global, GlobalIndex, Memory, MemoryIndex, SignatureIndex, Table,
|
||||
TableIndex,
|
||||
};
|
||||
use std::collections::HashMap;
|
||||
|
||||
/// A WebAssembly table initializer.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct TableElements {
|
||||
/// 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>,
|
||||
}
|
||||
|
||||
/// An entity to export.
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Export {
|
||||
/// Function export.
|
||||
Function(FuncIndex),
|
||||
/// Table export.
|
||||
Table(TableIndex),
|
||||
/// Memory export.
|
||||
Memory(MemoryIndex),
|
||||
/// Global export.
|
||||
Global(GlobalIndex),
|
||||
}
|
||||
|
||||
/// A translated WebAssembly module, excluding the function bodies and
|
||||
/// memory initializers.
|
||||
#[derive(Debug)]
|
||||
pub struct Module {
|
||||
/// Unprocessed signatures exactly as provided by `declare_signature()`.
|
||||
pub signatures: Vec<ir::Signature>,
|
||||
|
||||
/// Names of imported functions.
|
||||
pub imported_funcs: Vec<(String, String)>,
|
||||
|
||||
/// Types of functions, imported and local.
|
||||
pub functions: PrimaryMap<FuncIndex, SignatureIndex>,
|
||||
|
||||
/// WebAssembly tables.
|
||||
pub tables: Vec<Table>,
|
||||
|
||||
/// WebAssembly linear memories.
|
||||
pub memories: Vec<Memory>,
|
||||
|
||||
/// WebAssembly global variables.
|
||||
pub globals: Vec<Global>,
|
||||
|
||||
/// Exported entities.
|
||||
pub exports: HashMap<String, Export>,
|
||||
|
||||
/// The module "start" function, if present.
|
||||
pub start_func: Option<FuncIndex>,
|
||||
|
||||
/// WebAssembly table initializers.
|
||||
pub table_elements: Vec<TableElements>,
|
||||
}
|
||||
|
||||
impl Module {
|
||||
/// Allocates the module data structures.
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
signatures: Vec::new(),
|
||||
imported_funcs: Vec::new(),
|
||||
functions: PrimaryMap::new(),
|
||||
tables: Vec::new(),
|
||||
memories: Vec::new(),
|
||||
globals: Vec::new(),
|
||||
exports: HashMap::new(),
|
||||
start_func: None,
|
||||
table_elements: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert a `DefinedFuncIndex` into a `FuncIndex`.
|
||||
pub fn func_index(&self, defined_func: DefinedFuncIndex) -> FuncIndex {
|
||||
FuncIndex::new(self.imported_funcs.len() + defined_func.index())
|
||||
}
|
||||
|
||||
/// Convert a `FuncIndex` into a `DefinedFuncIndex`. Returns None if the
|
||||
/// index is an imported function.
|
||||
pub fn defined_func_index(&self, func: FuncIndex) -> Option<DefinedFuncIndex> {
|
||||
if func.index() < self.imported_funcs.len() {
|
||||
None
|
||||
} else {
|
||||
Some(DefinedFuncIndex::new(
|
||||
func.index() - self.imported_funcs.len(),
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A data initializer for linear memory.
|
||||
pub struct DataInitializer<'data> {
|
||||
/// The index of the memory to initialize.
|
||||
pub memory_index: MemoryIndex,
|
||||
/// Optionally a globalvar base to initialize at.
|
||||
pub base: Option<GlobalIndex>,
|
||||
/// A constant offset to initialize at.
|
||||
pub offset: usize,
|
||||
/// The initialization data.
|
||||
pub data: &'data [u8],
|
||||
}
|
||||
|
||||
/// References to the input wasm data buffer to be decoded and processed later,
|
||||
/// separately from the main module translation.
|
||||
pub struct LazyContents<'data> {
|
||||
/// References to the function bodies.
|
||||
pub function_body_inputs: PrimaryMap<DefinedFuncIndex, &'data [u8]>,
|
||||
|
||||
/// References to the data initializers.
|
||||
pub data_initializers: Vec<DataInitializer<'data>>,
|
||||
}
|
||||
|
||||
impl<'data> LazyContents<'data> {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
function_body_inputs: PrimaryMap::new(),
|
||||
data_initializers: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
5
src/webassembly/utils.rs
Normal file
5
src/webassembly/utils.rs
Normal file
@ -0,0 +1,5 @@
|
||||
|
||||
/// Detect if a provided binary is a WASM file
|
||||
pub fn is_wasm_binary(binary: &Vec<u8>) -> bool {
|
||||
binary.starts_with(&[b'\0', b'a', b's', b'm'])
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user