+
+## Installation
+
+The Wasmtime CLI can be installed on Linux and macOS with a small install
+script:
+
+```sh
+$ curl https://wasmtime.dev/install.sh -sSf | bash
+```
+
+Windows or otherwise interested users can download installers and
+binaries directly from the [GitHub
+Releases](https://github.com/bytecodealliance/wasmtime/releases) page.
+
+## Example
+
+If you've got the [Rust compiler
+installed](https://www.rust-lang.org/tools/install) then you can take some Rust
+source code:
+
+```rust
+fn main() {
+ println!("Hello, world!");
+}
+```
+
+and compile/run it with:
+
+```sh
+$ rustup target add wasm32-wasi
+$ rustc hello.rs --target wasm32-wasi
+$ wasmtime hello.wasm
+Hello, world!
+```
+
+## Features
+
+* **Lightweight**. Wasmtime is a standalone runtime for WebAssembly that scales
+ with your needs. It fits on tiny chips as well as makes use of huge servers.
+ Wasmtime can be embedded into almost any application too.
+
+* **Fast**. Wasmtime is built on the optimizing Cranelift code generator to
+ quickly generate high-quality machine code at runtime.
+
+* **Configurable**. Whether you need to precompile your wasm ahead of time,
+ generate code blazingly fast with Lightbeam, or interpret it at runtime,
+ Wasmtime has you covered for all your wasm-executing needs.
+
+* **WASI**. Wasmtime supports a rich set of APIs for interacting with the host
+ environment through the [WASI standard](https://wasi.dev).
+
+* **Standards Compliant**. Wasmtime passes the [official WebAssembly test
+ suite](https://github.com/WebAssembly/testsuite), implements the [official C
+ API of wasm](https://github.com/WebAssembly/wasm-c-api), and implements
+ [future proposals to WebAssembly](https://github.com/WebAssembly/proposals) as
+ well. Wasmtime developers are intimately engaged with the WebAssembly
+ standards process all along the way too.
+
+## Documentation
+
+[📚 Read the Wasmtime guide here! 📚][guide]
+
+The [wasmtime guide][guide] is the best starting point to learn about what
+Wasmtime can do for you or help answer your questions about Wasmtime. If you're
+curious in contributing to Wasmtime, [it can also help you do
+that][contributing]!.
+
+[contributing]: https://bytecodealliance.github.io/wasmtime/contributing.html
+[guide]: https://bytecodealliance.github.io/wasmtime
+
+---
+
+It's Wasmtime.
diff --git a/RELEASES.md b/RELEASES.md
new file mode 100644
index 0000000000..202f673e51
--- /dev/null
+++ b/RELEASES.md
@@ -0,0 +1,50 @@
+# Wasmtime Releases
+
+--------------------------------------------------------------------------------
+
+## 0.12.0
+
+Released 2020-02-26.
+
+### Added
+
+* Support for the [WebAssembly text annotations proposal][annotations-proposal]
+ has been added.
+ [#998](https://github.com/bytecodealliance/wasmtime/pull/998)
+
+* An initial C API for instantiating WASI modules has been added.
+ [#977](https://github.com/bytecodealliance/wasmtime/pull/977)
+
+* A new suite of `Func::getN` functions have been added to the `wasmtime` API to
+ call statically-known function signatures in a highly optimized fashion.
+ [#955](https://github.com/bytecodealliance/wasmtime/pull/955)
+
+* Initial support for profiling JIT code through perf jitdump has been added.
+ [#360](https://github.com/bytecodealliance/wasmtime/pull/360)
+
+* More CLI flags corresponding to proposed WebAssembly features have been added.
+ [#917](https://github.com/bytecodealliance/wasmtime/pull/917)
+
+[annotations-proposal]: https://github.com/webassembly/annotations
+
+### Changed
+
+* The `wasmtime` CLI as well as embedding API will optimize WebAssembly code by
+ default now.
+ [#973](https://github.com/bytecodealliance/wasmtime/pull/973)
+ [#988](https://github.com/bytecodealliance/wasmtime/pull/988)
+
+* The `verifier` pass in Cranelift is now no longer run by default when using
+ the embedding API.
+ [#882](https://github.com/bytecodealliance/wasmtime/pull/882)
+
+### Fixed
+
+* Code caching now accurately accounts for optimization levels, ensuring that if
+ you ask for optimized code you're not accidentally handed unoptimized code
+ from the cache.
+ [#974](https://github.com/bytecodealliance/wasmtime/pull/974)
+
+* Automated releases for tags should be up and running again, along with
+ automatic publication of the `wasmtime` Python package.
+ [#971](https://github.com/bytecodealliance/wasmtime/pull/971)
diff --git a/SECURITY.md b/SECURITY.md
new file mode 100644
index 0000000000..3513b9cb35
--- /dev/null
+++ b/SECURITY.md
@@ -0,0 +1,29 @@
+# Security Policy
+
+Building secure foundations for software development is at the core of what we do in the Bytecode Alliance. Contributions of external security researchers are a vital part of that.
+
+## Scope
+
+If you believe you've found a security issue in any website, service, or software owned or operated by the Bytecode Alliance, we encourage you to notify us.
+
+## How to Submit a Report
+
+To submit a vulnerability report to the Bytecode Alliance, please contact us at [security@bytecodealliance.org](mailto:security@bytecodealliance.org). Your submission will be reviewed and validated by a member of our security team.
+
+## Safe Harbor
+
+The Bytecode Alliance supports safe harbor for security researchers who:
+
+* Make a good faith effort to avoid privacy violations, destruction of data, and interruption or degradation of our services.
+* Only interact with accounts you own or with explicit permission of the account holder. If you do encounter Personally Identifiable Information (PII) contact us immediately, do not proceed with access, and immediately purge any local information.
+* Provide us with a reasonable amount of time to resolve vulnerabilities prior to any disclosure to the public or a third-party.
+
+We will consider activities conducted consistent with this policy to constitute "authorized" conduct and will not pursue civil action or initiate a complaint to law enforcement. We will help to the extent we can if legal action is initiated by a third party against you.
+
+Please submit a report to us before engaging in conduct that may be inconsistent with or unaddressed by this policy.
+
+## Preferences
+
+* Please provide detailed reports with reproducible steps and a clearly defined impact.
+* Submit one vulnerability per report.
+* Social engineering (e.g. phishing, vishing, smishing) is prohibited.
diff --git a/build.rs b/build.rs
new file mode 100644
index 0000000000..f8a847abe2
--- /dev/null
+++ b/build.rs
@@ -0,0 +1,211 @@
+//! Build program to generate a program which runs all the testsuites.
+//!
+//! By generating a separate `#[test]` test for each file, we allow cargo test
+//! to automatically run the files in parallel.
+
+use anyhow::Context;
+use std::env;
+use std::fmt::Write;
+use std::fs;
+use std::path::{Path, PathBuf};
+use std::process::Command;
+
+fn main() -> anyhow::Result<()> {
+ println!("cargo:rerun-if-changed=build.rs");
+ let out_dir = PathBuf::from(
+ env::var_os("OUT_DIR").expect("The OUT_DIR environment variable must be set"),
+ );
+ let mut out = String::new();
+
+ for strategy in &[
+ "Cranelift",
+ #[cfg(feature = "lightbeam")]
+ "Lightbeam",
+ ] {
+ writeln!(out, "#[cfg(test)]")?;
+ writeln!(out, "#[allow(non_snake_case)]")?;
+ writeln!(out, "mod {} {{", strategy)?;
+
+ with_test_module(&mut out, "misc", |out| {
+ test_directory(out, "tests/misc_testsuite", strategy)?;
+ test_directory_module(out, "tests/misc_testsuite/bulk-memory-operations", strategy)?;
+ test_directory_module(out, "tests/misc_testsuite/reference-types", strategy)?;
+ Ok(())
+ })?;
+
+ with_test_module(&mut out, "spec", |out| {
+ let spec_tests = test_directory(out, "tests/spec_testsuite", strategy)?;
+ // Skip running spec_testsuite tests if the submodule isn't checked
+ // out.
+ if spec_tests > 0 {
+ test_directory_module(out, "tests/spec_testsuite/proposals/simd", strategy)?;
+ test_directory_module(out, "tests/spec_testsuite/proposals/multi-value", strategy)?;
+ test_directory_module(
+ out,
+ "tests/spec_testsuite/proposals/reference-types",
+ strategy,
+ )?;
+ test_directory_module(
+ out,
+ "tests/spec_testsuite/proposals/bulk-memory-operations",
+ strategy,
+ )?;
+ } else {
+ println!(
+ "cargo:warning=The spec testsuite is disabled. To enable, run `git submodule \
+ update --remote`."
+ );
+ }
+ Ok(())
+ })?;
+
+ writeln!(out, "}}")?;
+ }
+
+ // Write out our auto-generated tests and opportunistically format them with
+ // `rustfmt` if it's installed.
+ let output = out_dir.join("wast_testsuite_tests.rs");
+ fs::write(&output, out)?;
+ drop(Command::new("rustfmt").arg(&output).status());
+ Ok(())
+}
+
+fn test_directory_module(
+ out: &mut String,
+ path: impl AsRef,
+ strategy: &str,
+) -> anyhow::Result {
+ let path = path.as_ref();
+ let testsuite = &extract_name(path);
+ with_test_module(out, testsuite, |out| test_directory(out, path, strategy))
+}
+
+fn test_directory(
+ out: &mut String,
+ path: impl AsRef,
+ strategy: &str,
+) -> anyhow::Result {
+ let path = path.as_ref();
+ let mut dir_entries: Vec<_> = path
+ .read_dir()
+ .context(format!("failed to read {:?}", path))?
+ .map(|r| r.expect("reading testsuite directory entry"))
+ .filter_map(|dir_entry| {
+ let p = dir_entry.path();
+ let ext = p.extension()?;
+ // Only look at wast files.
+ if ext != "wast" {
+ return None;
+ }
+ // Ignore files starting with `.`, which could be editor temporary files
+ if p.file_stem()?.to_str()?.starts_with(".") {
+ return None;
+ }
+ Some(p)
+ })
+ .collect();
+
+ dir_entries.sort();
+
+ let testsuite = &extract_name(path);
+ for entry in dir_entries.iter() {
+ write_testsuite_tests(out, entry, testsuite, strategy)?;
+ }
+
+ Ok(dir_entries.len())
+}
+
+/// Extract a valid Rust identifier from the stem of a path.
+fn extract_name(path: impl AsRef) -> String {
+ path.as_ref()
+ .file_stem()
+ .expect("filename should have a stem")
+ .to_str()
+ .expect("filename should be representable as a string")
+ .replace("-", "_")
+ .replace("/", "_")
+}
+
+fn with_test_module(
+ out: &mut String,
+ testsuite: &str,
+ f: impl FnOnce(&mut String) -> anyhow::Result,
+) -> anyhow::Result {
+ out.push_str("mod ");
+ out.push_str(testsuite);
+ out.push_str(" {\n");
+
+ let result = f(out)?;
+
+ out.push_str("}\n");
+ Ok(result)
+}
+
+fn write_testsuite_tests(
+ out: &mut String,
+ path: impl AsRef,
+ testsuite: &str,
+ strategy: &str,
+) -> anyhow::Result<()> {
+ let path = path.as_ref();
+ let testname = extract_name(path);
+
+ writeln!(out, "#[test]")?;
+ if ignore(testsuite, &testname, strategy) {
+ writeln!(out, "#[ignore]")?;
+ }
+ writeln!(out, "fn r#{}() -> anyhow::Result<()> {{", &testname)?;
+ writeln!(
+ out,
+ "crate::run_wast(r#\"{}\"#, crate::Strategy::{})",
+ path.display(),
+ strategy
+ )?;
+ writeln!(out, "}}")?;
+ writeln!(out)?;
+ Ok(())
+}
+
+/// Ignore tests that aren't supported yet.
+fn ignore(testsuite: &str, testname: &str, strategy: &str) -> bool {
+ match strategy {
+ #[cfg(feature = "lightbeam")]
+ "Lightbeam" => match (testsuite, testname) {
+ ("simd", _) => return true,
+ ("multi_value", _) => return true,
+ ("reference_types", _) => return true,
+ ("bulk_memory_operations", _) => return true,
+ // Lightbeam doesn't support float arguments on the stack.
+ ("spec_testsuite", "call") => return true,
+ _ => (),
+ },
+ "Cranelift" => match (testsuite, testname) {
+ ("simd", "simd_bit_shift") => return true, // FIXME Unsupported feature: proposed SIMD operator I8x16Shl
+ ("simd", "simd_conversions") => return true, // FIXME Unsupported feature: proposed SIMD operator I16x8NarrowI32x4S
+ ("simd", "simd_f32x4") => return true, // FIXME expected V128(F32x4([CanonicalNan, CanonicalNan, Value(Float32 { bits: 0 }), Value(Float32 { bits: 0 })])), got V128(18428729675200069632)
+ ("simd", "simd_f64x2") => return true, // FIXME expected V128(F64x2([Value(Float64 { bits: 9221120237041090560 }), Value(Float64 { bits: 0 })])), got V128(0)
+ ("simd", "simd_f64x2_arith") => return true, // FIXME expected V128(F64x2([Value(Float64 { bits: 9221120237041090560 }), Value(Float64 { bits: 13835058055282163712 })])), got V128(255211775190703847615975447847722024960)
+ ("simd", "simd_i64x2_arith") => return true, // FIXME Unsupported feature: proposed SIMD operator I64x2Mul
+ ("simd", "simd_lane") => return true, // FIXME invalid u8 number: constant out of range: (v8x16.shuffle -1 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14...
+ ("simd", "simd_load") => return true, // FIXME Unsupported feature: proposed SIMD operator I8x16Shl
+ ("simd", "simd_load_extend") => return true, // FIXME Unsupported feature: proposed SIMD operator I16x8Load8x8S { memarg: MemoryImmediate { flags: 0, offset: 0 } }
+ ("simd", "simd_load_splat") => return true, // FIXME Unsupported feature: proposed SIMD operator V8x16LoadSplat { memarg: MemoryImmediate { flags: 0, offset: 0 } }
+ ("simd", "simd_splat") => return true, // FIXME Unsupported feature: proposed SIMD operator I8x16ShrS
+
+ // Still working on implementing these. See #929.
+ ("reference_types", "table_copy_on_imported_tables") => return false,
+ ("reference_types", _) => return true,
+
+ // Still working on implementing these. See #928
+ ("bulk_memory_operations", "bulk")
+ | ("bulk_memory_operations", "data")
+ | ("bulk_memory_operations", "memory_init")
+ | ("bulk_memory_operations", "imports") => return true,
+
+ _ => {}
+ },
+ _ => panic!("unrecognized strategy"),
+ }
+
+ false
+}
diff --git a/ci/build-tarballs.sh b/ci/build-tarballs.sh
new file mode 100755
index 0000000000..433450116b
--- /dev/null
+++ b/ci/build-tarballs.sh
@@ -0,0 +1,55 @@
+#!/bin/bash
+
+# A small shell script invoked from CI on the final Linux builder which actually
+# assembles the release artifacts for a particular platform. This will take the
+# binary artifacts of previous builders and create associated tarballs to
+# publish to GitHub.
+#
+# The first argument of this is the "platform" name to put into the tarball, and
+# the second argument is the name of the github actions platform which is where
+# we source binaries from. The final third argument is ".exe" on Windows to
+# handle executable extensions right.
+
+set -ex
+
+platform=$1
+src=$2
+exe=$3
+
+rm -rf tmp
+mkdir tmp
+mkdir -p dist
+
+mktarball() {
+ dir=$1
+ if [ "$exe" = "" ]; then
+ tar cJf dist/$dir.tar.xz -C tmp $dir
+ else
+ (cd tmp && zip -r ../dist/$dir.zip $dir)
+ fi
+}
+
+# Create the main tarball of binaries
+bin_pkgname=wasmtime-$TAG-$platform
+mkdir tmp/$bin_pkgname
+cp LICENSE README.md tmp/$bin_pkgname
+mv bins-$src/{wasmtime,wasm2obj}$exe tmp/$bin_pkgname
+chmod +x tmp/$bin_pkgname/{wasmtime,wasm2obj}$exe
+mktarball $bin_pkgname
+
+if [ "$exe" = ".exe" ]; then
+ mv bins-$src/installer.msi dist/$bin_pkgname.msi
+fi
+
+# Create tarball of API libraries
+api_pkgname=wasmtime-$TAG-$platform-c-api
+mkdir tmp/$api_pkgname
+mkdir tmp/$api_pkgname/lib
+mkdir tmp/$api_pkgname/include
+cp LICENSE README.md tmp/$api_pkgname
+mv bins-$src/* tmp/$api_pkgname/lib
+cp crates/c-api/examples/wasm-c-api/include/wasm.h tmp/$api_pkgname/include
+mktarball $api_pkgname
+
+# Move wheels to dist folder
+mv wheels-$src/* dist
diff --git a/ci/setup_centos6_python3.sh b/ci/setup_centos6_python3.sh
new file mode 100644
index 0000000000..35ab465469
--- /dev/null
+++ b/ci/setup_centos6_python3.sh
@@ -0,0 +1,34 @@
+#!/bin/bash
+set -e
+
+VERSION=${1:-3.7.3}
+
+# Python 3.6 stands in our way -- nuking it
+yum erase -y rh-python36
+rm -rf /opt/rh/rh-python36
+
+yum install -y gcc bzip2-devel libffi-devel zlib-devel
+
+cd /usr/src/
+
+# pip3.7 needs new openssl
+curl -O -L https://github.com/openssl/openssl/archive/OpenSSL_1_1_1c.tar.gz
+tar -zxvf OpenSSL_1_1_1c.tar.gz
+cd openssl-OpenSSL_1_1_1c
+./Configure shared zlib linux-x86_64
+make -sj4
+make install
+cd ..
+rm -rf openssl-OpenSSL_1_1_1c
+
+# Fixing libssl.so.1.1: cannot open shared object file
+echo "/usr/local/lib64" >> /etc/ld.so.conf && ldconfig
+
+curl -O -L https://www.python.org/ftp/python/${VERSION}/Python-${VERSION}.tgz
+tar xzf Python-${VERSION}.tgz
+cd Python-${VERSION}
+./configure
+make -sj4
+make install
+cd ..
+rm -rf Python-${VERSION}
diff --git a/ci/wasmtime.wxs b/ci/wasmtime.wxs
new file mode 100644
index 0000000000..8110932cb9
--- /dev/null
+++ b/ci/wasmtime.wxs
@@ -0,0 +1,89 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/clippy.toml b/clippy.toml
new file mode 100644
index 0000000000..152f137769
--- /dev/null
+++ b/clippy.toml
@@ -0,0 +1 @@
+doc-valid-idents = ["WebAssembly"]
diff --git a/crates/api/Cargo.toml b/crates/api/Cargo.toml
new file mode 100644
index 0000000000..b4adb27975
--- /dev/null
+++ b/crates/api/Cargo.toml
@@ -0,0 +1,52 @@
+[package]
+name = "wasmtime"
+version = "0.12.0"
+authors = ["The Wasmtime Project Developers"]
+description = "High-level API to expose the Wasmtime runtime"
+license = "Apache-2.0 WITH LLVM-exception"
+repository = "https://github.com/bytecodealliance/wasmtime"
+readme = "README.md"
+edition = "2018"
+
+[dependencies]
+wasmtime-runtime = { path = "../runtime", version = "0.12.0" }
+wasmtime-environ = { path = "../environ", version = "0.12.0" }
+wasmtime-jit = { path = "../jit", version = "0.12.0" }
+wasmtime-profiling = { path = "../profiling", version = "0.12.0" }
+wasmparser = "0.51.2"
+target-lexicon = { version = "0.10.0", default-features = false }
+anyhow = "1.0.19"
+region = "2.0.0"
+libc = "0.2"
+cfg-if = "0.1.9"
+backtrace = "0.3.42"
+rustc-demangle = "0.1.16"
+lazy_static = "1.4"
+wat = { version = "1.0.10", optional = true }
+
+[target.'cfg(target_os = "windows")'.dependencies]
+winapi = "0.3.7"
+
+[dev-dependencies]
+# for wasmtime.rs
+wasi-common = { path = "../wasi-common", version = "0.12.0" }
+pretty_env_logger = "0.3.0"
+rayon = "1.2.1"
+file-per-thread-logger = "0.1.1"
+wat = "1.0.10"
+tempfile = "3.1"
+
+[badges]
+maintenance = { status = "actively-developed" }
+
+[features]
+default = ['wat']
+
+# Enables experimental support for the lightbeam codegen backend, an alternative
+# to cranelift. Requires Nightly Rust currently, and this is not enabled by
+# default.
+lightbeam = ["wasmtime-jit/lightbeam"]
+
+[[test]]
+name = "host-segfault"
+harness = false
diff --git a/crates/api/LICENSE b/crates/api/LICENSE
new file mode 100644
index 0000000000..f9d81955f4
--- /dev/null
+++ b/crates/api/LICENSE
@@ -0,0 +1,220 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+
+--- LLVM Exceptions to the Apache 2.0 License ----
+
+As an exception, if, as a result of your compiling your source code, portions
+of this Software are embedded into an Object form of such source code, you
+may redistribute such embedded portions in such Object form without complying
+with the conditions of Sections 4(a), 4(b) and 4(d) of the License.
+
+In addition, if you combine or link compiled forms of this Software with
+software that is licensed under the GPLv2 ("Combined Software") and if a
+court of competent jurisdiction determines that the patent provision (Section
+3), the indemnity provision (Section 9) or other Section of the License
+conflicts with the conditions of the GPLv2, you may retroactively and
+prospectively choose to deem waived or otherwise exclude such Section(s) of
+the License, but only in their entirety and only with respect to the Combined
+Software.
+
diff --git a/crates/api/README.md b/crates/api/README.md
new file mode 100644
index 0000000000..49ca113c15
--- /dev/null
+++ b/crates/api/README.md
@@ -0,0 +1,8 @@
+## Wasmtime Embedding API
+
+The `wasmtime` crate is an embedding API of the `wasmtime` WebAssembly runtime.
+This is intended to be used in Rust projects and provides a high-level API of
+working with WebAssembly modules.
+
+If you're interested in embedding `wasmtime` in other languages, you may wish to
+take a look a the [C embedding API](../c-api) instead!
diff --git a/crates/api/examples/gcd.rs b/crates/api/examples/gcd.rs
new file mode 100644
index 0000000000..5f68b87417
--- /dev/null
+++ b/crates/api/examples/gcd.rs
@@ -0,0 +1,60 @@
+//! Example of instantiating of the WebAssembly module and
+//! invoking its exported function.
+
+use wasmtime::*;
+
+const WAT: &str = r#"
+(module
+ (func $gcd (param i32 i32) (result i32)
+ (local i32)
+ block ;; label = @1
+ block ;; label = @2
+ local.get 0
+ br_if 0 (;@2;)
+ local.get 1
+ local.set 2
+ br 1 (;@1;)
+ end
+ loop ;; label = @2
+ local.get 1
+ local.get 0
+ local.tee 2
+ i32.rem_u
+ local.set 0
+ local.get 2
+ local.set 1
+ local.get 0
+ br_if 0 (;@2;)
+ end
+ end
+ local.get 2
+ )
+ (export "gcd" (func $gcd))
+)
+"#;
+
+fn main() -> anyhow::Result<()> {
+ // Load our WebAssembly (parsed WAT in our case), and then load it into a
+ // `Module` which is attached to a `Store` cache.
+ let store = Store::default();
+ let module = Module::new(&store, WAT)?;
+
+ // Find index of the `gcd` export.
+ let gcd_index = module
+ .exports()
+ .iter()
+ .enumerate()
+ .find(|(_, export)| export.name().to_string() == "gcd")
+ .unwrap()
+ .0;
+
+ // Instantiate the module.
+ let instance = Instance::new(&module, &[])?;
+
+ // Invoke `gcd` export
+ let gcd = instance.exports()[gcd_index].func().expect("gcd");
+ let result = gcd.call(&[Val::from(6i32), Val::from(27i32)])?;
+
+ println!("{:?}", result);
+ Ok(())
+}
diff --git a/crates/api/examples/hello.rs b/crates/api/examples/hello.rs
new file mode 100644
index 0000000000..9a461569ba
--- /dev/null
+++ b/crates/api/examples/hello.rs
@@ -0,0 +1,50 @@
+//! Translation of hello example
+
+use anyhow::{ensure, Context as _, Result};
+use wasmtime::*;
+
+fn main() -> Result<()> {
+ // Configure the initial compilation environment, creating the global
+ // `Store` structure. Note that you can also tweak configuration settings
+ // with a `Config` and an `Engine` if desired.
+ println!("Initializing...");
+ let store = Store::default();
+
+ // Compile the wasm binary into an in-memory instance of a `Module`.
+ println!("Compiling module...");
+ let wat = r#"
+ (module
+ (func $hello (import "" "hello"))
+ (func (export "run") (call $hello))
+ )
+ "#;
+ let module = Module::new(&store, wat).context("> Error compiling module!")?;
+
+ // Here we handle the imports of the module, which in this case is our
+ // `HelloCallback` type and its associated implementation of `Callback.
+ println!("Creating callback...");
+ let hello_func = Func::wrap0(&store, || {
+ println!("Calling back...");
+ println!("> Hello World!");
+ });
+
+ // Once we've got that all set up we can then move to the instantiation
+ // phase, pairing together a compiled module as well as a set of imports.
+ // Note that this is where the wasm `start` function, if any, would run.
+ println!("Instantiating module...");
+ let imports = vec![hello_func.into()];
+ let instance = Instance::new(&module, &imports).context("> Error instantiating module!")?;
+
+ // Next we poke around a bit to extract the `run` function from the module.
+ println!("Extracting export...");
+ let exports = instance.exports();
+ ensure!(!exports.is_empty(), "> Error accessing exports!");
+ let run_func = exports[0].func().context("> Error accessing exports!")?;
+
+ // And last but not least we can call it!
+ println!("Calling export...");
+ run_func.call(&[])?;
+
+ println!("Done.");
+ Ok(())
+}
diff --git a/crates/api/examples/memory.rs b/crates/api/examples/memory.rs
new file mode 100644
index 0000000000..dd2908c005
--- /dev/null
+++ b/crates/api/examples/memory.rs
@@ -0,0 +1,160 @@
+//! Translation of the memory example
+
+use anyhow::{bail, ensure, Context as _, Error};
+use wasmtime::*;
+
+fn get_export_memory(exports: &[Extern], i: usize) -> Result {
+ if exports.len() <= i {
+ bail!("> Error accessing memory export {}!", i);
+ }
+ Ok(exports[i]
+ .memory()
+ .with_context(|| format!("> Error accessing memory export {}!", i))?
+ .clone())
+}
+
+fn get_export_func(exports: &[Extern], i: usize) -> Result {
+ if exports.len() <= i {
+ bail!("> Error accessing function export {}!", i);
+ }
+ Ok(exports[i]
+ .func()
+ .with_context(|| format!("> Error accessing function export {}!", i))?
+ .clone())
+}
+
+macro_rules! check {
+ ($actual:expr, $expected:expr) => {
+ if $actual != $expected {
+ bail!("> Error on result, expected {}, got {}", $expected, $actual);
+ }
+ };
+}
+
+macro_rules! check_ok {
+ ($func:expr, $($p:expr),*) => {
+ if let Err(_) = $func.call(&[$($p.into()),*]) {
+ bail!("> Error on result, expected return");
+ }
+ }
+}
+
+macro_rules! check_trap {
+ ($func:expr, $($p:expr),*) => {
+ if let Ok(_) = $func.call(&[$($p.into()),*]) {
+ bail!("> Error on result, expected trap");
+ }
+ }
+}
+
+macro_rules! call {
+ ($func:expr, $($p:expr),*) => {
+ match $func.call(&[$($p.into()),*]) {
+ Ok(result) => {
+ let result: i32 = result[0].unwrap_i32();
+ result
+ }
+ Err(_) => { bail!("> Error on result, expected return"); }
+ }
+ }
+}
+
+fn main() -> Result<(), Error> {
+ // Initialize.
+ println!("Initializing...");
+ let store = Store::default();
+
+ // Load binary.
+ println!("Loading binary...");
+ let wat = r#"
+ (module
+ (memory (export "memory") 2 3)
+
+ (func (export "size") (result i32) (memory.size))
+ (func (export "load") (param i32) (result i32)
+ (i32.load8_s (local.get 0))
+ )
+ (func (export "store") (param i32 i32)
+ (i32.store8 (local.get 0) (local.get 1))
+ )
+
+ (data (i32.const 0x1000) "\01\02\03\04")
+ )
+ "#;
+
+ // Compile.
+ println!("Compiling module...");
+ let module = Module::new(&store, &wat).context("> Error compiling module!")?;
+
+ // Instantiate.
+ println!("Instantiating module...");
+ let instance = Instance::new(&module, &[]).context("> Error instantiating module!")?;
+
+ // Extract export.
+ println!("Extracting export...");
+ let exports = instance.exports();
+ ensure!(!exports.is_empty(), "> Error accessing exports!");
+ let memory = get_export_memory(&exports, 0)?;
+ let size_func = get_export_func(&exports, 1)?;
+ let load_func = get_export_func(&exports, 2)?;
+ let store_func = get_export_func(&exports, 3)?;
+
+ // Check initial memory.
+ println!("Checking memory...");
+ check!(memory.size(), 2u32);
+ check!(memory.data_size(), 0x20000usize);
+ check!(unsafe { memory.data_unchecked_mut()[0] }, 0);
+ check!(unsafe { memory.data_unchecked_mut()[0x1000] }, 1);
+ check!(unsafe { memory.data_unchecked_mut()[0x1003] }, 4);
+
+ check!(call!(size_func,), 2);
+ check!(call!(load_func, 0), 0);
+ check!(call!(load_func, 0x1000), 1);
+ check!(call!(load_func, 0x1003), 4);
+ check!(call!(load_func, 0x1ffff), 0);
+ check_trap!(load_func, 0x20000);
+
+ // Mutate memory.
+ println!("Mutating memory...");
+ unsafe {
+ memory.data_unchecked_mut()[0x1003] = 5;
+ }
+
+ check_ok!(store_func, 0x1002, 6);
+ check_trap!(store_func, 0x20000, 0);
+
+ check!(unsafe { memory.data_unchecked()[0x1002] }, 6);
+ check!(unsafe { memory.data_unchecked()[0x1003] }, 5);
+ check!(call!(load_func, 0x1002), 6);
+ check!(call!(load_func, 0x1003), 5);
+
+ // Grow memory.
+ println!("Growing memory...");
+ memory.grow(1)?;
+ check!(memory.size(), 3u32);
+ check!(memory.data_size(), 0x30000usize);
+
+ check!(call!(load_func, 0x20000), 0);
+ check_ok!(store_func, 0x20000, 0);
+ check_trap!(load_func, 0x30000);
+ check_trap!(store_func, 0x30000, 0);
+
+ memory.grow(1).unwrap_err();
+ memory.grow(0).unwrap();
+
+ // Create stand-alone memory.
+ // TODO(wasm+): Once Wasm allows multiple memories, turn this into import.
+ println!("Creating stand-alone memory...");
+ let memorytype = MemoryType::new(Limits::new(5, Some(5)));
+ let memory2 = Memory::new(&store, memorytype);
+ check!(memory2.size(), 5u32);
+ memory2.grow(1).unwrap_err();
+ memory2.grow(0).unwrap();
+
+ // Shut down.
+ println!("Shutting down...");
+ drop(store);
+
+ println!("Done.");
+ Ok(())
+}
diff --git a/crates/api/examples/multi.rs b/crates/api/examples/multi.rs
new file mode 100644
index 0000000000..663281eb09
--- /dev/null
+++ b/crates/api/examples/multi.rs
@@ -0,0 +1,129 @@
+//! Translation of multi example
+
+use anyhow::{ensure, format_err, Context as _, Result};
+use std::rc::Rc;
+use wasmtime::*;
+
+struct Callback;
+
+impl Callable for Callback {
+ fn call(&self, args: &[Val], results: &mut [Val]) -> Result<(), Trap> {
+ println!("Calling back...");
+ println!("> {} {}", args[0].unwrap_i32(), args[1].unwrap_i64());
+
+ results[0] = Val::I64(args[1].unwrap_i64() + 1);
+ results[1] = Val::I32(args[0].unwrap_i32() + 1);
+ Ok(())
+ }
+}
+
+const WAT: &str = r#"
+(module
+ (func $f (import "" "f") (param i32 i64) (result i64 i32))
+
+ (func $g (export "g") (param i32 i64) (result i64 i32)
+ (call $f (local.get 0) (local.get 1))
+ )
+
+ (func $round_trip_many
+ (export "round_trip_many")
+ (param i64 i64 i64 i64 i64 i64 i64 i64 i64 i64)
+ (result i64 i64 i64 i64 i64 i64 i64 i64 i64 i64)
+ local.get 0
+ local.get 1
+ local.get 2
+ local.get 3
+ local.get 4
+ local.get 5
+ local.get 6
+ local.get 7
+ local.get 8
+ local.get 9)
+)
+"#;
+
+fn main() -> Result<()> {
+ // Initialize.
+ println!("Initializing...");
+ let engine = Engine::new(Config::new().wasm_multi_value(true));
+ let store = Store::new(&engine);
+
+ // Compile.
+ println!("Compiling module...");
+ let module = Module::new(&store, WAT).context("Error compiling module!")?;
+
+ // Create external print functions.
+ println!("Creating callback...");
+ let callback_type = FuncType::new(
+ Box::new([ValType::I32, ValType::I64]),
+ Box::new([ValType::I64, ValType::I32]),
+ );
+ let callback_func = Func::new(&store, callback_type, Rc::new(Callback));
+
+ // Instantiate.
+ println!("Instantiating module...");
+ let imports = vec![callback_func.into()];
+ let instance =
+ Instance::new(&module, imports.as_slice()).context("Error instantiating module!")?;
+
+ // Extract exports.
+ println!("Extracting export...");
+ let exports = instance.exports();
+ ensure!(!exports.is_empty(), "Error accessing exports!");
+ let g = exports[0].func().context("> Error accessing export $g!")?;
+ let round_trip_many = exports[1]
+ .func()
+ .context("> Error accessing export $round_trip_many")?;
+
+ // Call `$g`.
+ println!("Calling export \"g\"...");
+ let args = vec![Val::I32(1), Val::I64(3)];
+ let results = g
+ .call(&args)
+ .map_err(|e| format_err!("> Error calling g! {:?}", e))?;
+
+ println!("Printing result...");
+ println!("> {} {}", results[0].unwrap_i64(), results[1].unwrap_i32());
+
+ debug_assert_eq!(results[0].unwrap_i64(), 4);
+ debug_assert_eq!(results[1].unwrap_i32(), 2);
+
+ // Call `$round_trip_many`.
+ println!("Calling export \"round_trip_many\"...");
+ let args = vec![
+ Val::I64(0),
+ Val::I64(1),
+ Val::I64(2),
+ Val::I64(3),
+ Val::I64(4),
+ Val::I64(5),
+ Val::I64(6),
+ Val::I64(7),
+ Val::I64(8),
+ Val::I64(9),
+ ];
+ let results = round_trip_many
+ .call(&args)
+ .map_err(|e| format_err!("> Error calling round_trip_many! {:?}", e))?;
+
+ println!("Printing result...");
+ print!(">");
+ for r in results.iter() {
+ print!(" {}", r.unwrap_i64());
+ }
+ println!();
+
+ debug_assert_eq!(results.len(), 10);
+ debug_assert!(args
+ .iter()
+ .zip(results.iter())
+ .all(|(a, r)| a.i64() == r.i64()));
+
+ // Shut down.
+ println!("Shutting down...");
+ drop(store);
+
+ // All done.
+ println!("Done.");
+ Ok(())
+}
diff --git a/crates/api/src/callable.rs b/crates/api/src/callable.rs
new file mode 100644
index 0000000000..c4983df8c8
--- /dev/null
+++ b/crates/api/src/callable.rs
@@ -0,0 +1,225 @@
+use crate::runtime::Store;
+use crate::trampoline::generate_func_export;
+use crate::trap::Trap;
+use crate::types::FuncType;
+use crate::values::Val;
+use std::ptr;
+use std::rc::Rc;
+use wasmtime_environ::ir;
+use wasmtime_runtime::{Export, InstanceHandle};
+
+/// A trait representing a function that can be imported and called from inside
+/// WebAssembly.
+/// # Example
+/// ```
+/// use wasmtime::Val;
+///
+/// struct TimesTwo;
+///
+/// impl wasmtime::Callable for TimesTwo {
+/// fn call(&self, params: &[Val], results: &mut [Val]) -> Result<(), wasmtime::Trap> {
+/// let mut value = params[0].unwrap_i32();
+/// value *= 2;
+/// results[0] = value.into();
+///
+/// Ok(())
+/// }
+/// }
+///
+/// # fn main () -> Result<(), Box> {
+/// // Simple module that imports our host function ("times_two") and re-exports
+/// // it as "run".
+/// let wat = r#"
+/// (module
+/// (func $times_two (import "" "times_two") (param i32) (result i32))
+/// (func
+/// (export "run")
+/// (param i32)
+/// (result i32)
+/// (local.get 0)
+/// (call $times_two))
+/// )
+/// "#;
+///
+/// // Initialise environment and our module.
+/// let store = wasmtime::Store::default();
+/// let module = wasmtime::Module::new(&store, wat)?;
+///
+/// // Define the type of the function we're going to call.
+/// let times_two_type = wasmtime::FuncType::new(
+/// // Parameters
+/// Box::new([wasmtime::ValType::I32]),
+/// // Results
+/// Box::new([wasmtime::ValType::I32])
+/// );
+///
+/// // Build a reference to the "times_two" function that can be used.
+/// let times_two_function =
+/// wasmtime::Func::new(&store, times_two_type, std::rc::Rc::new(TimesTwo));
+///
+/// // Create module instance that imports our function
+/// let instance = wasmtime::Instance::new(
+/// &module,
+/// &[times_two_function.into()]
+/// )?;
+///
+/// // Get "run" function from the exports.
+/// let run_function = instance.exports()[0].func().unwrap();
+///
+/// // Borrow and call "run". Returning any error message from Wasm as a string.
+/// let original = 5i32;
+/// let results = run_function
+/// .call(&[original.into()])
+/// .map_err(|trap| trap.to_string())?;
+///
+/// // Compare that the results returned matches what we expect.
+/// assert_eq!(original * 2, results[0].unwrap_i32());
+/// # Ok(())
+/// # }
+/// ```
+pub trait Callable {
+ /// What is called when the function is invoked in WebAssembly.
+ /// `params` is an immutable list of parameters provided to the function.
+ /// `results` is mutable list of results to be potentially set by your
+ /// function. Produces a `Trap` if the function encounters any errors.
+ fn call(&self, params: &[Val], results: &mut [Val]) -> Result<(), Trap>;
+}
+
+pub(crate) trait WrappedCallable {
+ fn call(&self, params: &[Val], results: &mut [Val]) -> Result<(), Trap>;
+ fn signature(&self) -> &ir::Signature {
+ match self.wasmtime_export() {
+ Export::Function { signature, .. } => signature,
+ _ => panic!("unexpected export type in Callable"),
+ }
+ }
+ fn wasmtime_handle(&self) -> &InstanceHandle;
+ fn wasmtime_export(&self) -> &Export;
+}
+
+pub(crate) struct WasmtimeFn {
+ store: Store,
+ instance: InstanceHandle,
+ export: Export,
+}
+
+impl WasmtimeFn {
+ pub fn new(store: &Store, instance: InstanceHandle, export: Export) -> WasmtimeFn {
+ WasmtimeFn {
+ store: store.clone(),
+ instance,
+ export,
+ }
+ }
+}
+
+impl WrappedCallable for WasmtimeFn {
+ fn call(&self, params: &[Val], results: &mut [Val]) -> Result<(), Trap> {
+ use std::cmp::max;
+ use std::mem;
+
+ let (vmctx, body, signature) = match self.wasmtime_export() {
+ Export::Function {
+ vmctx,
+ address,
+ signature,
+ } => (*vmctx, *address, signature.clone()),
+ _ => panic!("unexpected export type in Callable"),
+ };
+ if signature.params.len() - 2 != params.len() {
+ return Err(Trap::new(format!(
+ "expected {} arguments, got {}",
+ signature.params.len() - 2,
+ params.len()
+ )));
+ }
+ if signature.returns.len() != results.len() {
+ return Err(Trap::new(format!(
+ "expected {} results, got {}",
+ signature.returns.len(),
+ results.len()
+ )));
+ }
+
+ let value_size = mem::size_of::();
+ let mut values_vec = vec![0; max(params.len(), results.len())];
+
+ // Store the argument values into `values_vec`.
+ let param_tys = signature.params.iter().skip(2);
+ for ((arg, slot), ty) in params.iter().zip(&mut values_vec).zip(param_tys) {
+ if arg.ty().get_wasmtime_type() != Some(ty.value_type) {
+ return Err(Trap::new("argument type mismatch"));
+ }
+ unsafe {
+ arg.write_value_to(slot);
+ }
+ }
+
+ // Get the trampoline to call for this function.
+ let exec_code_buf = self
+ .store
+ .compiler_mut()
+ .get_published_trampoline(&signature, value_size)
+ .map_err(|e| Trap::new(format!("trampoline error: {:?}", e)))?;
+
+ // Call the trampoline.
+ if let Err(error) = unsafe {
+ wasmtime_runtime::wasmtime_call_trampoline(
+ vmctx,
+ ptr::null_mut(),
+ exec_code_buf,
+ body,
+ values_vec.as_mut_ptr() as *mut u8,
+ )
+ } {
+ return Err(Trap::from_jit(error));
+ }
+
+ // Load the return values out of `values_vec`.
+ for (index, abi_param) in signature.returns.iter().enumerate() {
+ unsafe {
+ let ptr = values_vec.as_ptr().add(index);
+
+ results[index] = Val::read_value_from(ptr, abi_param.value_type);
+ }
+ }
+
+ Ok(())
+ }
+ fn wasmtime_handle(&self) -> &InstanceHandle {
+ &self.instance
+ }
+ fn wasmtime_export(&self) -> &Export {
+ &self.export
+ }
+}
+
+pub struct NativeCallable {
+ callable: Rc,
+ instance: InstanceHandle,
+ export: Export,
+}
+
+impl NativeCallable {
+ pub(crate) fn new(callable: Rc, ft: &FuncType, store: &Store) -> Self {
+ let (instance, export) =
+ generate_func_export(ft, &callable, store).expect("generated func");
+ NativeCallable {
+ callable,
+ instance,
+ export,
+ }
+ }
+}
+
+impl WrappedCallable for NativeCallable {
+ fn call(&self, params: &[Val], results: &mut [Val]) -> Result<(), Trap> {
+ self.callable.call(params, results)
+ }
+ fn wasmtime_handle(&self) -> &InstanceHandle {
+ &self.instance
+ }
+ fn wasmtime_export(&self) -> &Export {
+ &self.export
+ }
+}
diff --git a/crates/api/src/externals.rs b/crates/api/src/externals.rs
new file mode 100644
index 0000000000..1735c10be6
--- /dev/null
+++ b/crates/api/src/externals.rs
@@ -0,0 +1,643 @@
+use crate::trampoline::{generate_global_export, generate_memory_export, generate_table_export};
+use crate::values::{from_checked_anyfunc, into_checked_anyfunc, Val};
+use crate::Mutability;
+use crate::{ExternType, GlobalType, MemoryType, TableType, ValType};
+use crate::{Func, Store};
+use anyhow::{anyhow, bail, Result};
+use std::slice;
+use wasmtime_environ::{ir, wasm};
+use wasmtime_runtime::{self as runtime, InstanceHandle};
+
+// Externals
+
+/// An external item to a WebAssembly module, or a list of what can possibly be
+/// exported from a wasm module.
+///
+/// This is both returned from [`Instance::exports`](crate::Instance::exports)
+/// as well as required by [`Instance::new`](crate::Instance::new). In other
+/// words, this is the type of extracted values from an instantiated module, and
+/// it's also used to provide imported values when instantiating a module.
+#[derive(Clone)]
+pub enum Extern {
+ /// A WebAssembly `func` which can be called.
+ Func(Func),
+ /// A WebAssembly `global` which acts like a `Cell` of sorts, supporting
+ /// `get` and `set` operations.
+ Global(Global),
+ /// A WebAssembly `table` which is an array of `Val` types.
+ Table(Table),
+ /// A WebAssembly linear memory.
+ Memory(Memory),
+}
+
+impl Extern {
+ /// Returns the underlying `Func`, if this external is a function.
+ ///
+ /// Returns `None` if this is not a function.
+ pub fn func(&self) -> Option<&Func> {
+ match self {
+ Extern::Func(func) => Some(func),
+ _ => None,
+ }
+ }
+
+ /// Returns the underlying `Global`, if this external is a global.
+ ///
+ /// Returns `None` if this is not a global.
+ pub fn global(&self) -> Option<&Global> {
+ match self {
+ Extern::Global(global) => Some(global),
+ _ => None,
+ }
+ }
+
+ /// Returns the underlying `Table`, if this external is a table.
+ ///
+ /// Returns `None` if this is not a table.
+ pub fn table(&self) -> Option<&Table> {
+ match self {
+ Extern::Table(table) => Some(table),
+ _ => None,
+ }
+ }
+
+ /// Returns the underlying `Memory`, if this external is a memory.
+ ///
+ /// Returns `None` if this is not a memory.
+ pub fn memory(&self) -> Option<&Memory> {
+ match self {
+ Extern::Memory(memory) => Some(memory),
+ _ => None,
+ }
+ }
+
+ /// Returns the type associated with this `Extern`.
+ pub fn ty(&self) -> ExternType {
+ match self {
+ Extern::Func(ft) => ExternType::Func(ft.ty().clone()),
+ Extern::Memory(ft) => ExternType::Memory(ft.ty().clone()),
+ Extern::Table(tt) => ExternType::Table(tt.ty().clone()),
+ Extern::Global(gt) => ExternType::Global(gt.ty().clone()),
+ }
+ }
+
+ pub(crate) fn get_wasmtime_export(&self) -> wasmtime_runtime::Export {
+ match self {
+ Extern::Func(f) => f.wasmtime_export().clone(),
+ Extern::Global(g) => g.wasmtime_export().clone(),
+ Extern::Memory(m) => m.wasmtime_export().clone(),
+ Extern::Table(t) => t.wasmtime_export().clone(),
+ }
+ }
+
+ pub(crate) fn from_wasmtime_export(
+ store: &Store,
+ instance_handle: InstanceHandle,
+ export: wasmtime_runtime::Export,
+ ) -> Extern {
+ match export {
+ wasmtime_runtime::Export::Function { .. } => {
+ Extern::Func(Func::from_wasmtime_function(export, store, instance_handle))
+ }
+ wasmtime_runtime::Export::Memory { .. } => {
+ Extern::Memory(Memory::from_wasmtime_memory(export, store, instance_handle))
+ }
+ wasmtime_runtime::Export::Global { .. } => {
+ Extern::Global(Global::from_wasmtime_global(export, store, instance_handle))
+ }
+ wasmtime_runtime::Export::Table { .. } => {
+ Extern::Table(Table::from_wasmtime_table(export, store, instance_handle))
+ }
+ }
+ }
+}
+
+impl From for Extern {
+ fn from(r: Func) -> Self {
+ Extern::Func(r)
+ }
+}
+
+impl From for Extern {
+ fn from(r: Global) -> Self {
+ Extern::Global(r)
+ }
+}
+
+impl From for Extern {
+ fn from(r: Memory) -> Self {
+ Extern::Memory(r)
+ }
+}
+
+impl From
for Extern {
+ fn from(r: Table) -> Self {
+ Extern::Table(r)
+ }
+}
+
+/// A WebAssembly `global` value which can be read and written to.
+///
+/// A `global` in WebAssembly is sort of like a global variable within an
+/// [`Instance`](crate::Instance). The `global.get` and `global.set`
+/// instructions will modify and read global values in a wasm module. Globals
+/// can either be imported or exported from wasm modules.
+///
+/// If you're familiar with Rust already you can think of a `Global` as a sort
+/// of `Rc>`, more or less.
+///
+/// # `Global` and `Clone`
+///
+/// Globals are internally reference counted so you can `clone` a `Global`. The
+/// cloning process only performs a shallow clone, so two cloned `Global`
+/// instances are equivalent in their functionality.
+#[derive(Clone)]
+pub struct Global {
+ _store: Store,
+ ty: GlobalType,
+ wasmtime_export: wasmtime_runtime::Export,
+ wasmtime_handle: InstanceHandle,
+}
+
+impl Global {
+ /// Creates a new WebAssembly `global` value with the provide type `ty` and
+ /// initial value `val`.
+ ///
+ /// The `store` argument provided is used as a general global cache for
+ /// information, and otherwise the `ty` and `val` arguments are used to
+ /// initialize the global.
+ ///
+ /// # Errors
+ ///
+ /// Returns an error if the `ty` provided does not match the type of the
+ /// value `val`.
+ pub fn new(store: &Store, ty: GlobalType, val: Val) -> Result {
+ if val.ty() != *ty.content() {
+ bail!("value provided does not match the type of this global");
+ }
+ let (wasmtime_handle, wasmtime_export) = generate_global_export(store, &ty, val)?;
+ Ok(Global {
+ _store: store.clone(),
+ ty,
+ wasmtime_export,
+ wasmtime_handle,
+ })
+ }
+
+ /// Returns the underlying type of this `global`.
+ pub fn ty(&self) -> &GlobalType {
+ &self.ty
+ }
+
+ fn wasmtime_global_definition(&self) -> *mut wasmtime_runtime::VMGlobalDefinition {
+ match self.wasmtime_export {
+ wasmtime_runtime::Export::Global { definition, .. } => definition,
+ _ => panic!("global definition not found"),
+ }
+ }
+
+ /// Returns the current [`Val`] of this global.
+ pub fn get(&self) -> Val {
+ let definition = unsafe { &mut *self.wasmtime_global_definition() };
+ unsafe {
+ match self.ty().content() {
+ ValType::I32 => Val::from(*definition.as_i32()),
+ ValType::I64 => Val::from(*definition.as_i64()),
+ ValType::F32 => Val::F32(*definition.as_u32()),
+ ValType::F64 => Val::F64(*definition.as_u64()),
+ _ => unimplemented!("Global::get for {:?}", self.ty().content()),
+ }
+ }
+ }
+
+ /// Attempts to set the current value of this global to [`Val`].
+ ///
+ /// # Errors
+ ///
+ /// Returns an error if this global has a different type than `Val`, or if
+ /// it's not a mutable global.
+ pub fn set(&self, val: Val) -> Result<()> {
+ if self.ty().mutability() != Mutability::Var {
+ bail!("immutable global cannot be set");
+ }
+ if val.ty() != *self.ty().content() {
+ bail!(
+ "global of type {:?} cannot be set to {:?}",
+ self.ty().content(),
+ val.ty()
+ );
+ }
+ let definition = unsafe { &mut *self.wasmtime_global_definition() };
+ unsafe {
+ match val {
+ Val::I32(i) => *definition.as_i32_mut() = i,
+ Val::I64(i) => *definition.as_i64_mut() = i,
+ Val::F32(f) => *definition.as_u32_mut() = f,
+ Val::F64(f) => *definition.as_u64_mut() = f,
+ _ => unimplemented!("Global::set for {:?}", val.ty()),
+ }
+ }
+ Ok(())
+ }
+
+ pub(crate) fn wasmtime_export(&self) -> &wasmtime_runtime::Export {
+ &self.wasmtime_export
+ }
+
+ pub(crate) fn from_wasmtime_global(
+ export: wasmtime_runtime::Export,
+ store: &Store,
+ wasmtime_handle: InstanceHandle,
+ ) -> Global {
+ let global = if let wasmtime_runtime::Export::Global { ref global, .. } = export {
+ global
+ } else {
+ panic!("wasmtime export is not global")
+ };
+ // The original export is coming from wasmtime_runtime itself we should
+ // support all the types coming out of it, so assert such here.
+ let ty = GlobalType::from_wasmtime_global(&global)
+ .expect("core wasm global type should be supported");
+ Global {
+ _store: store.clone(),
+ ty: ty,
+ wasmtime_export: export,
+ wasmtime_handle,
+ }
+ }
+}
+
+/// A WebAssembly `table`, or an array of values.
+///
+/// Like [`Memory`] a table is an indexed array of values, but unlike [`Memory`]
+/// it's an array of WebAssembly values rather than bytes. One of the most
+/// common usages of a table is a function table for wasm modules, where each
+/// element has the `Func` type.
+///
+/// Tables, like globals, are not threadsafe and can only be used on one thread.
+/// Tables can be grown in size and each element can be read/written.
+///
+/// # `Table` and `Clone`
+///
+/// Tables are internally reference counted so you can `clone` a `Table`. The
+/// cloning process only performs a shallow clone, so two cloned `Table`
+/// instances are equivalent in their functionality.
+#[derive(Clone)]
+pub struct Table {
+ store: Store,
+ ty: TableType,
+ wasmtime_handle: InstanceHandle,
+ wasmtime_export: wasmtime_runtime::Export,
+}
+
+fn set_table_item(
+ handle: &mut InstanceHandle,
+ table_index: wasm::DefinedTableIndex,
+ item_index: u32,
+ item: wasmtime_runtime::VMCallerCheckedAnyfunc,
+) -> Result<()> {
+ handle
+ .table_set(table_index, item_index, item)
+ .map_err(|()| anyhow!("table element index out of bounds"))
+}
+
+impl Table {
+ /// Creates a new `Table` with the given parameters.
+ ///
+ /// * `store` - a global cache to store information in
+ /// * `ty` - the type of this table, containing both the element type as
+ /// well as the initial size and maximum size, if any.
+ /// * `init` - the initial value to fill all table entries with, if the
+ /// table starts with an initial size.
+ ///
+ /// # Errors
+ ///
+ /// Returns an error if `init` does not match the element type of the table.
+ pub fn new(store: &Store, ty: TableType, init: Val) -> Result
{
+ let item = into_checked_anyfunc(init, store)?;
+ let (mut wasmtime_handle, wasmtime_export) = generate_table_export(store, &ty)?;
+
+ // Initialize entries with the init value.
+ match wasmtime_export {
+ wasmtime_runtime::Export::Table { definition, .. } => {
+ let index = wasmtime_handle.table_index(unsafe { &*definition });
+ let len = unsafe { (*definition).current_elements };
+ for i in 0..len {
+ set_table_item(&mut wasmtime_handle, index, i, item.clone())?;
+ }
+ }
+ _ => unreachable!("export should be a table"),
+ }
+
+ Ok(Table {
+ store: store.clone(),
+ ty,
+ wasmtime_handle,
+ wasmtime_export,
+ })
+ }
+
+ /// Returns the underlying type of this table, including its element type as
+ /// well as the maximum/minimum lower bounds.
+ pub fn ty(&self) -> &TableType {
+ &self.ty
+ }
+
+ fn wasmtime_table_index(&self) -> wasm::DefinedTableIndex {
+ match self.wasmtime_export {
+ wasmtime_runtime::Export::Table { definition, .. } => {
+ self.wasmtime_handle.table_index(unsafe { &*definition })
+ }
+ _ => panic!("global definition not found"),
+ }
+ }
+
+ /// Returns the table element value at `index`.
+ ///
+ /// Returns `None` if `index` is out of bounds.
+ pub fn get(&self, index: u32) -> Option {
+ let table_index = self.wasmtime_table_index();
+ let item = self.wasmtime_handle.table_get(table_index, index)?;
+ Some(from_checked_anyfunc(item, &self.store))
+ }
+
+ /// Writes the `val` provided into `index` within this table.
+ ///
+ /// # Errors
+ ///
+ /// Returns an error if `index` is out of bounds or if `val` does not have
+ /// the right type to be stored in this table.
+ pub fn set(&self, index: u32, val: Val) -> Result<()> {
+ let table_index = self.wasmtime_table_index();
+ let mut wasmtime_handle = self.wasmtime_handle.clone();
+ let item = into_checked_anyfunc(val, &self.store)?;
+ set_table_item(&mut wasmtime_handle, table_index, index, item)
+ }
+
+ /// Returns the current size of this table.
+ pub fn size(&self) -> u32 {
+ match self.wasmtime_export {
+ wasmtime_runtime::Export::Table { definition, .. } => unsafe {
+ (*definition).current_elements
+ },
+ _ => panic!("global definition not found"),
+ }
+ }
+
+ /// Grows the size of this table by `delta` more elements, initialization
+ /// all new elements to `init`.
+ ///
+ /// # Errors
+ ///
+ /// Returns an error if the table cannot be grown by `delta`, for example
+ /// if it would cause the table to exceed its maximum size. Also returns an
+ /// error if `init` is not of the right type.
+ pub fn grow(&self, delta: u32, init: Val) -> Result {
+ let index = self.wasmtime_table_index();
+ let item = into_checked_anyfunc(init, &self.store)?;
+ if let Some(len) = self.wasmtime_handle.clone().table_grow(index, delta) {
+ let mut wasmtime_handle = self.wasmtime_handle.clone();
+ for i in 0..delta {
+ let i = len - (delta - i);
+ set_table_item(&mut wasmtime_handle, index, i, item.clone())?;
+ }
+ Ok(len)
+ } else {
+ bail!("failed to grow table by `{}`", delta)
+ }
+ }
+
+ /// Copy `len` elements from `src_table[src_index..]` into
+ /// `dst_table[dst_index..]`.
+ ///
+ /// # Errors
+ ///
+ /// Returns an error if the range is out of bounds of either the source or
+ /// destination tables.
+ pub fn copy(
+ dst_table: &Table,
+ dst_index: u32,
+ src_table: &Table,
+ src_index: u32,
+ len: u32,
+ ) -> Result<()> {
+ // NB: We must use the `dst_table`'s `wasmtime_handle` for the
+ // `dst_table_index` and vice versa for `src_table` since each table can
+ // come from different modules.
+
+ let dst_table_index = dst_table.wasmtime_table_index();
+ let dst_table = dst_table.wasmtime_handle.get_defined_table(dst_table_index);
+
+ let src_table_index = src_table.wasmtime_table_index();
+ let src_table = src_table.wasmtime_handle.get_defined_table(src_table_index);
+
+ runtime::Table::copy(
+ dst_table,
+ src_table,
+ dst_index,
+ src_index,
+ len,
+ ir::SourceLoc::default(),
+ )?;
+ Ok(())
+ }
+
+ pub(crate) fn wasmtime_export(&self) -> &wasmtime_runtime::Export {
+ &self.wasmtime_export
+ }
+
+ pub(crate) fn from_wasmtime_table(
+ export: wasmtime_runtime::Export,
+ store: &Store,
+ instance_handle: wasmtime_runtime::InstanceHandle,
+ ) -> Table {
+ let table = if let wasmtime_runtime::Export::Table { ref table, .. } = export {
+ table
+ } else {
+ panic!("wasmtime export is not table")
+ };
+ let ty = TableType::from_wasmtime_table(&table.table);
+ Table {
+ store: store.clone(),
+ ty: ty,
+ wasmtime_handle: instance_handle,
+ wasmtime_export: export,
+ }
+ }
+}
+
+/// A WebAssembly linear memory.
+///
+/// WebAssembly memories represent a contiguous array of bytes that have a size
+/// that is always a multiple of the WebAssembly page size, currently 64
+/// kilobytes.
+///
+/// WebAssembly memory is used for global data, statics in C/C++/Rust, shadow
+/// stack memory, etc. Accessing wasm memory is generally quite fast!
+///
+/// # `Memory` and `Clone`
+///
+/// Memories are internally reference counted so you can `clone` a `Memory`. The
+/// cloning process only performs a shallow clone, so two cloned `Memory`
+/// instances are equivalent in their functionality.
+///
+/// # `Memory` and threads
+///
+/// It is intended that `Memory` is safe to share between threads. At this time
+/// this is not implemented in `wasmtime`, however. This is planned to be
+/// implemented though!
+#[derive(Clone)]
+pub struct Memory {
+ _store: Store,
+ ty: MemoryType,
+ wasmtime_handle: InstanceHandle,
+ wasmtime_export: wasmtime_runtime::Export,
+}
+
+impl Memory {
+ /// Creates a new WebAssembly memory given the configuration of `ty`.
+ ///
+ /// The `store` argument is a general location for cache information, and
+ /// otherwise the memory will immediately be allocated according to the
+ /// type's configuration. All WebAssembly memory is initialized to zero.
+ pub fn new(store: &Store, ty: MemoryType) -> Memory {
+ let (wasmtime_handle, wasmtime_export) =
+ generate_memory_export(store, &ty).expect("generated memory");
+ Memory {
+ _store: store.clone(),
+ ty,
+ wasmtime_handle,
+ wasmtime_export,
+ }
+ }
+
+ /// Returns the underlying type of this memory.
+ pub fn ty(&self) -> &MemoryType {
+ &self.ty
+ }
+
+ fn wasmtime_memory_definition(&self) -> *mut wasmtime_runtime::VMMemoryDefinition {
+ match self.wasmtime_export {
+ wasmtime_runtime::Export::Memory { definition, .. } => definition,
+ _ => panic!("memory definition not found"),
+ }
+ }
+
+ /// Returns this memory as a slice view that can be read natively in Rust.
+ ///
+ /// # Safety
+ ///
+ /// This is an unsafe operation because there is no guarantee that the
+ /// following operations do not happen concurrently while the slice is in
+ /// use:
+ ///
+ /// * Data could be modified by calling into a wasm module.
+ /// * Memory could be relocated through growth by calling into a wasm
+ /// module.
+ /// * When threads are supported, non-atomic reads will race with other
+ /// writes.
+ ///
+ /// Extreme care need be taken when the data of a `Memory` is read. The
+ /// above invariants all need to be upheld at a bare minimum, and in
+ /// general you'll need to ensure that while you're looking at slice you're
+ /// the only one who can possibly look at the slice and read/write it.
+ ///
+ /// Be sure to keep in mind that `Memory` is reference counted, meaning
+ /// that there may be other users of this `Memory` instance elsewhere in
+ /// your program. Additionally `Memory` can be shared and used in any number
+ /// of wasm instances, so calling any wasm code should be considered
+ /// dangerous while you're holding a slice of memory.
+ pub unsafe fn data_unchecked(&self) -> &[u8] {
+ self.data_unchecked_mut()
+ }
+
+ /// Returns this memory as a slice view that can be read and written
+ /// natively in Rust.
+ ///
+ /// # Safety
+ ///
+ /// All of the same safety caveats of [`Memory::data_unchecked`] apply
+ /// here, doubly so because this is returning a mutable slice! As a
+ /// double-extra reminder, remember that `Memory` is reference counted, so
+ /// you can very easily acquire two mutable slices by simply calling this
+ /// function twice. Extreme caution should be used when using this method,
+ /// and in general you probably want to result to unsafe accessors and the
+ /// `data` methods below.
+ pub unsafe fn data_unchecked_mut(&self) -> &mut [u8] {
+ let definition = &*self.wasmtime_memory_definition();
+ slice::from_raw_parts_mut(definition.base, definition.current_length)
+ }
+
+ /// Returns the base pointer, in the host's address space, that the memory
+ /// is located at.
+ ///
+ /// When reading and manipulating memory be sure to read up on the caveats
+ /// of [`Memory::data_unchecked`] to make sure that you can safely
+ /// read/write the memory.
+ pub fn data_ptr(&self) -> *mut u8 {
+ unsafe { (*self.wasmtime_memory_definition()).base }
+ }
+
+ /// Returns the byte length of this memory.
+ ///
+ /// The returned value will be a multiple of the wasm page size, 64k.
+ pub fn data_size(&self) -> usize {
+ unsafe { (*self.wasmtime_memory_definition()).current_length }
+ }
+
+ /// Returns the size, in pages, of this wasm memory.
+ pub fn size(&self) -> u32 {
+ (self.data_size() / wasmtime_environ::WASM_PAGE_SIZE as usize) as u32
+ }
+
+ /// Grows this WebAssembly memory by `delta` pages.
+ ///
+ /// This will attempt to add `delta` more pages of memory on to the end of
+ /// this `Memory` instance. If successful this may relocate the memory and
+ /// cause [`Memory::data_ptr`] to return a new value. Additionally previous
+ /// slices into this memory may no longer be valid.
+ ///
+ /// On success returns the number of pages this memory previously had
+ /// before the growth succeeded.
+ ///
+ /// # Errors
+ ///
+ /// Returns an error if memory could not be grown, for example if it exceeds
+ /// the maximum limits of this memory.
+ pub fn grow(&self, delta: u32) -> Result {
+ match self.wasmtime_export {
+ wasmtime_runtime::Export::Memory { definition, .. } => {
+ let definition = unsafe { &(*definition) };
+ let index = self.wasmtime_handle.memory_index(definition);
+ self.wasmtime_handle
+ .clone()
+ .memory_grow(index, delta)
+ .ok_or_else(|| anyhow!("failed to grow memory"))
+ }
+ _ => panic!("memory definition not found"),
+ }
+ }
+
+ pub(crate) fn wasmtime_export(&self) -> &wasmtime_runtime::Export {
+ &self.wasmtime_export
+ }
+
+ pub(crate) fn from_wasmtime_memory(
+ export: wasmtime_runtime::Export,
+ store: &Store,
+ instance_handle: wasmtime_runtime::InstanceHandle,
+ ) -> Memory {
+ let memory = if let wasmtime_runtime::Export::Memory { ref memory, .. } = export {
+ memory
+ } else {
+ panic!("wasmtime export is not memory")
+ };
+ let ty = MemoryType::from_wasmtime_memory(&memory.memory);
+ Memory {
+ _store: store.clone(),
+ ty: ty,
+ wasmtime_handle: instance_handle,
+ wasmtime_export: export,
+ }
+ }
+}
diff --git a/crates/api/src/frame_info.rs b/crates/api/src/frame_info.rs
new file mode 100644
index 0000000000..5e0ea13331
--- /dev/null
+++ b/crates/api/src/frame_info.rs
@@ -0,0 +1,183 @@
+use crate::module::Names;
+use std::collections::BTreeMap;
+use std::sync::{Arc, RwLock};
+use wasmtime_environ::entity::EntityRef;
+use wasmtime_environ::wasm::FuncIndex;
+use wasmtime_jit::CompiledModule;
+
+lazy_static::lazy_static! {
+ /// This is a global cache of backtrace frame information for all active
+ ///
+ /// This global cache is used during `Trap` creation to symbolicate frames.
+ /// This is populated on module compilation, and it is cleared out whenever
+ /// all references to a module are dropped.
+ pub static ref FRAME_INFO: GlobalFrameInfo = GlobalFrameInfo::default();
+}
+
+#[derive(Default)]
+pub struct GlobalFrameInfo {
+ /// An internal map that keeps track of backtrace frame information for
+ /// each module.
+ ///
+ /// This map is morally a map of ranges to a map of information for that
+ /// module. Each module is expected to reside in a disjoint section of
+ /// contiguous memory. No modules can overlap.
+ ///
+ /// The key of this map is the highest address in the module and the value
+ /// is the module's information, which also contains the start address.
+ ranges: RwLock>,
+}
+
+/// An RAII structure used to unregister a module's frame information when the
+/// module is destroyed.
+pub struct GlobalFrameInfoRegistration {
+ /// The key that will be removed from the global `ranges` map when this is
+ /// dropped.
+ key: usize,
+}
+
+struct ModuleFrameInfo {
+ start: usize,
+ functions: BTreeMap,
+ names: Arc,
+}
+
+impl GlobalFrameInfo {
+ /// Registers a new compiled module's frame information.
+ ///
+ /// This function will register the `names` information for all of the
+ /// compiled functions within `module`. If the `module` has no functions
+ /// then `None` will be returned. Otherwise the returned object, when
+ /// dropped, will be used to unregister all name information from this map.
+ pub fn register(
+ &self,
+ names: &Arc,
+ module: &CompiledModule,
+ ) -> Option {
+ let mut min = usize::max_value();
+ let mut max = 0;
+ let mut functions = BTreeMap::new();
+ for (i, allocated) in module.finished_functions() {
+ let (start, end) = unsafe {
+ let ptr = (**allocated).as_ptr();
+ let len = (**allocated).len();
+ (ptr as usize, ptr as usize + len)
+ };
+ if start < min {
+ min = start;
+ }
+ if end > max {
+ max = end;
+ }
+ let func_index = module.module().local.func_index(i);
+ assert!(functions.insert(end, (start, func_index)).is_none());
+ }
+ if functions.len() == 0 {
+ return None;
+ }
+
+ let mut ranges = self.ranges.write().unwrap();
+ // First up assert that our chunk of jit functions doesn't collide with
+ // any other known chunks of jit functions...
+ if let Some((_, prev)) = ranges.range(max..).next() {
+ assert!(prev.start > max);
+ }
+ if let Some((prev_end, _)) = ranges.range(..=min).next_back() {
+ assert!(*prev_end < min);
+ }
+
+ // ... then insert our range and assert nothing was there previously
+ let prev = ranges.insert(
+ max,
+ ModuleFrameInfo {
+ start: min,
+ functions,
+ names: names.clone(),
+ },
+ );
+ assert!(prev.is_none());
+ Some(GlobalFrameInfoRegistration { key: max })
+ }
+
+ /// Fetches information about a program counter in a backtrace.
+ ///
+ /// Returns an object if this `pc` is known to some previously registered
+ /// module, or returns `None` if no information can be found.
+ pub fn lookup(&self, pc: usize) -> Option {
+ let ranges = self.ranges.read().ok()?;
+ let (end, info) = ranges.range(pc..).next()?;
+ if pc < info.start || *end < pc {
+ return None;
+ }
+ let (end, (start, func_index)) = info.functions.range(pc..).next()?;
+ if pc < *start || *end < pc {
+ return None;
+ }
+ Some(FrameInfo {
+ module_name: info.names.module_name.clone(),
+ func_index: func_index.index() as u32,
+ func_name: info.names.module.func_names.get(func_index).cloned(),
+ })
+ }
+}
+
+impl Drop for GlobalFrameInfoRegistration {
+ fn drop(&mut self) {
+ if let Ok(mut map) = FRAME_INFO.ranges.write() {
+ map.remove(&self.key);
+ }
+ }
+}
+
+/// Description of a frame in a backtrace for a [`Trap`].
+///
+/// Whenever a WebAssembly trap occurs an instance of [`Trap`] is created. Each
+/// [`Trap`] has a backtrace of the WebAssembly frames that led to the trap, and
+/// each frame is described by this structure.
+#[derive(Debug)]
+pub struct FrameInfo {
+ module_name: Option,
+ func_index: u32,
+ func_name: Option,
+}
+
+impl FrameInfo {
+ /// Returns the WebAssembly function index for this frame.
+ ///
+ /// This function index is the index in the function index space of the
+ /// WebAssembly module that this frame comes from.
+ pub fn func_index(&self) -> u32 {
+ self.func_index
+ }
+
+ /// Returns the identifer of the module that this frame is for.
+ ///
+ /// Module identifiers are present in the `name` section of a WebAssembly
+ /// binary, but this may not return the exact item in the `name` section.
+ /// Module names can be overwritten at construction time or perhaps inferred
+ /// from file names. The primary purpose of this function is to assist in
+ /// debugging and therefore may be tweaked over time.
+ ///
+ /// This function returns `None` when no name can be found or inferred.
+ pub fn module_name(&self) -> Option<&str> {
+ self.module_name.as_deref()
+ }
+
+ /// Returns a descriptive name of the function for this frame, if one is
+ /// available.
+ ///
+ /// The name of this function may come from the `name` section of the
+ /// WebAssembly binary, or wasmtime may try to infer a better name for it if
+ /// not available, for example the name of the export if it's exported.
+ ///
+ /// This return value is primarily used for debugging and human-readable
+ /// purposes for things like traps. Note that the exact return value may be
+ /// tweaked over time here and isn't guaranteed to be something in
+ /// particular about a wasm module due to its primary purpose of assisting
+ /// in debugging.
+ ///
+ /// This function returns `None` when no name could be inferred.
+ pub fn func_name(&self) -> Option<&str> {
+ self.func_name.as_deref()
+ }
+}
diff --git a/crates/api/src/func.rs b/crates/api/src/func.rs
new file mode 100644
index 0000000000..de0255feff
--- /dev/null
+++ b/crates/api/src/func.rs
@@ -0,0 +1,621 @@
+use crate::callable::{NativeCallable, WasmtimeFn, WrappedCallable};
+use crate::{Callable, FuncType, Store, Trap, Val, ValType};
+use anyhow::{ensure, Context as _};
+use std::fmt;
+use std::mem;
+use std::panic::{self, AssertUnwindSafe};
+use std::ptr;
+use std::rc::Rc;
+use wasmtime_runtime::{InstanceHandle, VMContext, VMFunctionBody};
+
+/// A WebAssembly function which can be called.
+///
+/// This type can represent a number of callable items, such as:
+///
+/// * An exported function from a WebAssembly module.
+/// * A user-defined function used to satisfy an import.
+///
+/// These types of callable items are all wrapped up in this `Func` and can be
+/// used to both instantiate an [`Instance`](crate::Instance) as well as be
+/// extracted from an [`Instance`](crate::Instance).
+///
+/// # `Func` and `Clone`
+///
+/// Functions are internally reference counted so you can `clone` a `Func`. The
+/// cloning process only performs a shallow clone, so two cloned `Func`
+/// instances are equivalent in their functionality.
+#[derive(Clone)]
+pub struct Func {
+ _store: Store,
+ callable: Rc,
+ ty: FuncType,
+}
+
+macro_rules! wrappers {
+ ($(
+ $(#[$doc:meta])*
+ ($name:ident $(,$args:ident)*)
+ )*) => ($(
+ $(#[$doc])*
+ pub fn $name(store: &Store, func: F) -> Func
+ where
+ F: Fn($($args),*) -> R + 'static,
+ $($args: WasmTy,)*
+ R: WasmRet,
+ {
+ #[allow(non_snake_case)]
+ unsafe extern "C" fn shim(
+ vmctx: *mut VMContext,
+ _caller_vmctx: *mut VMContext,
+ $($args: $args::Abi,)*
+ ) -> R::Abi
+ where
+ F: Fn($($args),*) -> R + 'static,
+ $($args: WasmTy,)*
+ R: WasmRet,
+ {
+ let ret = {
+ let instance = InstanceHandle::from_vmctx(vmctx);
+ let func = instance.host_state().downcast_ref::().expect("state");
+ panic::catch_unwind(AssertUnwindSafe(|| {
+ func($($args::from_abi(_caller_vmctx, $args)),*)
+ }))
+ };
+ match ret {
+ Ok(ret) => ret.into_abi(),
+ Err(panic) => wasmtime_runtime::resume_panic(panic),
+ }
+ }
+
+ let mut _args = Vec::new();
+ $($args::push(&mut _args);)*
+ let mut ret = Vec::new();
+ R::push(&mut ret);
+ let ty = FuncType::new(_args.into(), ret.into());
+ unsafe {
+ let (instance, export) = crate::trampoline::generate_raw_func_export(
+ &ty,
+ std::slice::from_raw_parts_mut(
+ shim:: as *mut _,
+ 0,
+ ),
+ store,
+ Box::new(func),
+ )
+ .expect("failed to generate export");
+ let callable = Rc::new(WasmtimeFn::new(store, instance, export));
+ Func::from_wrapped(store, ty, callable)
+ }
+ }
+ )*)
+}
+
+macro_rules! getters {
+ ($(
+ $(#[$doc:meta])*
+ ($name:ident $(,$args:ident)*)
+ )*) => ($(
+ $(#[$doc])*
+ #[allow(non_snake_case)]
+ pub fn $name<$($args,)* R>(&self)
+ -> anyhow::Result Result>
+ where
+ $($args: WasmTy,)*
+ R: WasmTy,
+ {
+ // Verify all the paramers match the expected parameters, and that
+ // there are no extra parameters...
+ let mut params = self.ty().params().iter().cloned();
+ let n = 0;
+ $(
+ let n = n + 1;
+ $args::matches(&mut params)
+ .with_context(|| format!("Type mismatch in argument {}", n))?;
+ )*
+ ensure!(params.next().is_none(), "Type mismatch: too many arguments (expected {})", n);
+
+ // ... then do the same for the results...
+ let mut results = self.ty().results().iter().cloned();
+ R::matches(&mut results)
+ .context("Type mismatch in return type")?;
+ ensure!(results.next().is_none(), "Type mismatch: too many return values (expected 1)");
+
+ // ... and then once we've passed the typechecks we can hand out our
+ // object since our `transmute` below should be safe!
+ let (address, vmctx) = match self.wasmtime_export() {
+ wasmtime_runtime::Export::Function { address, vmctx, signature: _} => {
+ (*address, *vmctx)
+ }
+ _ => panic!("expected function export"),
+ };
+ Ok(move |$($args: $args),*| -> Result {
+ unsafe {
+ let f = mem::transmute::<
+ *const VMFunctionBody,
+ unsafe extern "C" fn(
+ *mut VMContext,
+ *mut VMContext,
+ $($args::Abi,)*
+ ) -> R::Abi,
+ >(address);
+ let mut ret = None;
+ $(let $args = $args.into_abi();)*
+ wasmtime_runtime::catch_traps(vmctx, || {
+ ret = Some(f(vmctx, ptr::null_mut(), $($args,)*));
+ }).map_err(Trap::from_jit)?;
+ Ok(R::from_abi(vmctx, ret.unwrap()))
+ }
+ })
+ }
+ )*)
+}
+
+impl Func {
+ /// Creates a new `Func` with the given arguments, typically to create a
+ /// user-defined function to pass as an import to a module.
+ ///
+ /// * `store` - a cache of data where information is stored, typically
+ /// shared with a [`Module`](crate::Module).
+ ///
+ /// * `ty` - the signature of this function, used to indicate what the
+ /// inputs and outputs are, which must be WebAssembly types.
+ ///
+ /// * `callable` - a type implementing the [`Callable`] trait which
+ /// is the implementation of this `Func` value.
+ ///
+ /// Note that the implementation of `callable` must adhere to the `ty`
+ /// signature given, error or traps may occur if it does not respect the
+ /// `ty` signature.
+ pub fn new(store: &Store, ty: FuncType, callable: Rc) -> Self {
+ let callable = Rc::new(NativeCallable::new(callable, &ty, &store));
+ Func::from_wrapped(store, ty, callable)
+ }
+
+ wrappers! {
+ /// Creates a new `Func` from the given Rust closure, which takes 0
+ /// arguments.
+ ///
+ /// For more information about this function, see [`Func::wrap1`].
+ (wrap0)
+
+ /// Creates a new `Func` from the given Rust closure, which takes 1
+ /// argument.
+ ///
+ /// This function will create a new `Func` which, when called, will
+ /// execute the given Rust closure. Unlike [`Func::new`] the target
+ /// function being called is known statically so the type signature can
+ /// be inferred. Rust types will map to WebAssembly types as follows:
+ ///
+ ///
+ /// | Rust Argument Type | WebAssembly Type |
+ /// |--------------------|------------------|
+ /// | `i32` | `i32` |
+ /// | `i64` | `i64` |
+ /// | `f32` | `f32` |
+ /// | `f64` | `f64` |
+ /// | (not supported) | `v128` |
+ /// | (not supported) | `anyref` |
+ ///
+ /// Any of the Rust types can be returned from the closure as well, in
+ /// addition to some extra types
+ ///
+ /// | Rust Return Type | WebAssembly Return Type | Meaning |
+ /// |-------------------|-------------------------|-------------------|
+ /// | `()` | nothing | no return value |
+ /// | `Result` | `T` | function may trap |
+ ///
+ /// Note that when using this API (and the related `wrap*` family of
+ /// functions), the intention is to create as thin of a layer as
+ /// possible for when WebAssembly calls the function provided. With
+ /// sufficient inlining and optimization the WebAssembly will call
+ /// straight into `func` provided, with no extra fluff entailed.
+ (wrap1, A1)
+
+ /// Creates a new `Func` from the given Rust closure, which takes 2
+ /// arguments.
+ ///
+ /// For more information about this function, see [`Func::wrap1`].
+ (wrap2, A1, A2)
+
+ /// Creates a new `Func` from the given Rust closure, which takes 3
+ /// arguments.
+ ///
+ /// For more information about this function, see [`Func::wrap1`].
+ (wrap3, A1, A2, A3)
+
+ /// Creates a new `Func` from the given Rust closure, which takes 4
+ /// arguments.
+ ///
+ /// For more information about this function, see [`Func::wrap1`].
+ (wrap4, A1, A2, A3, A4)
+
+ /// Creates a new `Func` from the given Rust closure, which takes 5
+ /// arguments.
+ ///
+ /// For more information about this function, see [`Func::wrap1`].
+ (wrap5, A1, A2, A3, A4, A5)
+
+ /// Creates a new `Func` from the given Rust closure, which takes 6
+ /// arguments.
+ ///
+ /// For more information about this function, see [`Func::wrap1`].
+ (wrap6, A1, A2, A3, A4, A5, A6)
+
+ /// Creates a new `Func` from the given Rust closure, which takes 7
+ /// arguments.
+ ///
+ /// For more information about this function, see [`Func::wrap1`].
+ (wrap7, A1, A2, A3, A4, A5, A6, A7)
+
+ /// Creates a new `Func` from the given Rust closure, which takes 8
+ /// arguments.
+ ///
+ /// For more information about this function, see [`Func::wrap1`].
+ (wrap8, A1, A2, A3, A4, A5, A6, A7, A8)
+
+ /// Creates a new `Func` from the given Rust closure, which takes 9
+ /// arguments.
+ ///
+ /// For more information about this function, see [`Func::wrap1`].
+ (wrap9, A1, A2, A3, A4, A5, A6, A7, A8, A9)
+
+ /// Creates a new `Func` from the given Rust closure, which takes 10
+ /// arguments.
+ ///
+ /// For more information about this function, see [`Func::wrap1`].
+ (wrap10, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10)
+ }
+
+ fn from_wrapped(
+ store: &Store,
+ ty: FuncType,
+ callable: Rc,
+ ) -> Func {
+ Func {
+ _store: store.clone(),
+ callable,
+ ty,
+ }
+ }
+
+ /// Returns the underlying wasm type that this `Func` has.
+ pub fn ty(&self) -> &FuncType {
+ &self.ty
+ }
+
+ /// Returns the number of parameters that this function takes.
+ pub fn param_arity(&self) -> usize {
+ self.ty.params().len()
+ }
+
+ /// Returns the number of results this function produces.
+ pub fn result_arity(&self) -> usize {
+ self.ty.results().len()
+ }
+
+ /// Invokes this function with the `params` given, returning the results and
+ /// any trap, if one occurs.
+ ///
+ /// The `params` here must match the type signature of this `Func`, or a
+ /// trap will occur. If a trap occurs while executing this function, then a
+ /// trap will also be returned.
+ ///
+ /// This function should not panic unless the underlying function itself
+ /// initiates a panic.
+ pub fn call(&self, params: &[Val]) -> Result, Trap> {
+ let mut results = vec![Val::null(); self.result_arity()];
+ self.callable.call(params, &mut results)?;
+ Ok(results.into_boxed_slice())
+ }
+
+ pub(crate) fn wasmtime_export(&self) -> &wasmtime_runtime::Export {
+ self.callable.wasmtime_export()
+ }
+
+ pub(crate) fn from_wasmtime_function(
+ export: wasmtime_runtime::Export,
+ store: &Store,
+ instance_handle: InstanceHandle,
+ ) -> Self {
+ // This is only called with `Export::Function`, and since it's coming
+ // from wasmtime_runtime itself we should support all the types coming
+ // out of it, so assert such here.
+ let ty = if let wasmtime_runtime::Export::Function { signature, .. } = &export {
+ FuncType::from_wasmtime_signature(signature.clone())
+ .expect("core wasm signature should be supported")
+ } else {
+ panic!("expected function export")
+ };
+ let callable = WasmtimeFn::new(store, instance_handle, export);
+ Func::from_wrapped(store, ty, Rc::new(callable))
+ }
+
+ getters! {
+ /// Extracts a natively-callable object from this `Func`, if the
+ /// signature matches.
+ ///
+ /// See the [`Func::get1`] method for more documentation.
+ (get0)
+
+ /// Extracts a natively-callable object from this `Func`, if the
+ /// signature matches.
+ ///
+ /// This function serves as an optimized version of the [`Func::call`]
+ /// method if the type signature of a function is statically known to
+ /// the program. This method is faster than `call` on a few metrics:
+ ///
+ /// * Runtime type-checking only happens once, when this method is
+ /// called.
+ /// * The result values, if any, aren't boxed into a vector.
+ /// * Arguments and return values don't go through boxing and unboxing.
+ /// * No trampolines are used to transfer control flow to/from JIT code,
+ /// instead this function jumps directly into JIT code.
+ ///
+ /// For more information about which Rust types match up to which wasm
+ /// types, see the documentation on [`Func::wrap1`].
+ ///
+ /// # Return
+ ///
+ /// This function will return `None` if the type signature asserted
+ /// statically does not match the runtime type signature. `Some`,
+ /// however, will be returned if the underlying function takes one
+ /// parameter of type `A` and returns the parameter `R`. Currently `R`
+ /// can either be `()` (no return values) or one wasm type. At this time
+ /// a multi-value return isn't supported.
+ ///
+ /// The returned closure will always return a `Result` and an
+ /// `Err` is returned if a trap happens while the wasm is executing.
+ (get1, A1)
+
+ /// Extracts a natively-callable object from this `Func`, if the
+ /// signature matches.
+ ///
+ /// See the [`Func::get1`] method for more documentation.
+ (get2, A1, A2)
+
+ /// Extracts a natively-callable object from this `Func`, if the
+ /// signature matches.
+ ///
+ /// See the [`Func::get1`] method for more documentation.
+ (get3, A1, A2, A3)
+
+ /// Extracts a natively-callable object from this `Func`, if the
+ /// signature matches.
+ ///
+ /// See the [`Func::get1`] method for more documentation.
+ (get4, A1, A2, A3, A4)
+
+ /// Extracts a natively-callable object from this `Func`, if the
+ /// signature matches.
+ ///
+ /// See the [`Func::get1`] method for more documentation.
+ (get5, A1, A2, A3, A4, A5)
+
+ /// Extracts a natively-callable object from this `Func`, if the
+ /// signature matches.
+ ///
+ /// See the [`Func::get1`] method for more documentation.
+ (get6, A1, A2, A3, A4, A5, A6)
+
+ /// Extracts a natively-callable object from this `Func`, if the
+ /// signature matches.
+ ///
+ /// See the [`Func::get1`] method for more documentation.
+ (get7, A1, A2, A3, A4, A5, A6, A7)
+
+ /// Extracts a natively-callable object from this `Func`, if the
+ /// signature matches.
+ ///
+ /// See the [`Func::get1`] method for more documentation.
+ (get8, A1, A2, A3, A4, A5, A6, A7, A8)
+
+ /// Extracts a natively-callable object from this `Func`, if the
+ /// signature matches.
+ ///
+ /// See the [`Func::get1`] method for more documentation.
+ (get9, A1, A2, A3, A4, A5, A6, A7, A8, A9)
+
+ /// Extracts a natively-callable object from this `Func`, if the
+ /// signature matches.
+ ///
+ /// See the [`Func::get1`] method for more documentation.
+ (get10, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10)
+ }
+}
+
+impl fmt::Debug for Func {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "Func")
+ }
+}
+
+/// A trait implemented for types which can be arguments to closures passed to
+/// [`Func::wrap1`] and friends.
+///
+/// This trait should not be implemented by user types. This trait may change at
+/// any time internally. The types which implement this trait, however, are
+/// stable over time.
+///
+/// For more information see [`Func::wrap1`]
+pub trait WasmTy {
+ #[doc(hidden)]
+ type Abi: Copy;
+ #[doc(hidden)]
+ fn push(dst: &mut Vec);
+ #[doc(hidden)]
+ fn matches(tys: impl Iterator) -> anyhow::Result<()>;
+ #[doc(hidden)]
+ fn from_abi(vmctx: *mut VMContext, abi: Self::Abi) -> Self;
+ #[doc(hidden)]
+ fn into_abi(self) -> Self::Abi;
+}
+
+impl WasmTy for () {
+ type Abi = ();
+ fn push(_dst: &mut Vec) {}
+ fn matches(_tys: impl Iterator) -> anyhow::Result<()> {
+ Ok(())
+ }
+ #[inline]
+ fn from_abi(_vmctx: *mut VMContext, abi: Self::Abi) -> Self {
+ abi
+ }
+ #[inline]
+ fn into_abi(self) -> Self::Abi {
+ self
+ }
+}
+
+impl WasmTy for i32 {
+ type Abi = Self;
+ fn push(dst: &mut Vec) {
+ dst.push(ValType::I32);
+ }
+ fn matches(mut tys: impl Iterator) -> anyhow::Result<()> {
+ let next = tys.next();
+ ensure!(
+ next == Some(ValType::I32),
+ "Type mismatch, expected i32, got {:?}",
+ next
+ );
+ Ok(())
+ }
+ #[inline]
+ fn from_abi(_vmctx: *mut VMContext, abi: Self::Abi) -> Self {
+ abi
+ }
+ #[inline]
+ fn into_abi(self) -> Self::Abi {
+ self
+ }
+}
+
+impl WasmTy for i64 {
+ type Abi = Self;
+ fn push(dst: &mut Vec) {
+ dst.push(ValType::I64);
+ }
+ fn matches(mut tys: impl Iterator) -> anyhow::Result<()> {
+ let next = tys.next();
+ ensure!(
+ next == Some(ValType::I64),
+ "Type mismatch, expected i64, got {:?}",
+ next
+ );
+ Ok(())
+ }
+ #[inline]
+ fn from_abi(_vmctx: *mut VMContext, abi: Self::Abi) -> Self {
+ abi
+ }
+ #[inline]
+ fn into_abi(self) -> Self::Abi {
+ self
+ }
+}
+
+impl WasmTy for f32 {
+ type Abi = Self;
+ fn push(dst: &mut Vec) {
+ dst.push(ValType::F32);
+ }
+ fn matches(mut tys: impl Iterator) -> anyhow::Result<()> {
+ let next = tys.next();
+ ensure!(
+ next == Some(ValType::F32),
+ "Type mismatch, expected f32, got {:?}",
+ next
+ );
+ Ok(())
+ }
+ #[inline]
+ fn from_abi(_vmctx: *mut VMContext, abi: Self::Abi) -> Self {
+ abi
+ }
+ #[inline]
+ fn into_abi(self) -> Self::Abi {
+ self
+ }
+}
+
+impl WasmTy for f64 {
+ type Abi = Self;
+ fn push(dst: &mut Vec) {
+ dst.push(ValType::F64);
+ }
+ fn matches(mut tys: impl Iterator) -> anyhow::Result<()> {
+ let next = tys.next();
+ ensure!(
+ next == Some(ValType::F64),
+ "Type mismatch, expected f64, got {:?}",
+ next
+ );
+ Ok(())
+ }
+ #[inline]
+ fn from_abi(_vmctx: *mut VMContext, abi: Self::Abi) -> Self {
+ abi
+ }
+ #[inline]
+ fn into_abi(self) -> Self::Abi {
+ self
+ }
+}
+
+/// A trait implemented for types which can be returned from closures passed to
+/// [`Func::wrap1`] and friends.
+///
+/// This trait should not be implemented by user types. This trait may change at
+/// any time internally. The types which implement this trait, however, are
+/// stable over time.
+///
+/// For more information see [`Func::wrap1`]
+pub trait WasmRet {
+ #[doc(hidden)]
+ type Abi;
+ #[doc(hidden)]
+ fn push(dst: &mut Vec);
+ #[doc(hidden)]
+ fn matches(tys: impl Iterator) -> anyhow::Result<()>;
+ #[doc(hidden)]
+ fn into_abi(self) -> Self::Abi;
+}
+
+impl WasmRet for T {
+ type Abi = T::Abi;
+ fn push(dst: &mut Vec) {
+ T::push(dst)
+ }
+
+ fn matches(tys: impl Iterator) -> anyhow::Result<()> {
+ T::matches(tys)
+ }
+
+ #[inline]
+ fn into_abi(self) -> Self::Abi {
+ T::into_abi(self)
+ }
+}
+
+impl WasmRet for Result {
+ type Abi = T::Abi;
+ fn push(dst: &mut Vec) {
+ T::push(dst)
+ }
+
+ fn matches(tys: impl Iterator) -> anyhow::Result<()> {
+ T::matches(tys)
+ }
+
+ #[inline]
+ fn into_abi(self) -> Self::Abi {
+ match self {
+ Ok(val) => return val.into_abi(),
+ Err(trap) => handle_trap(trap),
+ }
+
+ fn handle_trap(trap: Trap) -> ! {
+ unsafe { wasmtime_runtime::raise_user_trap(Box::new(trap)) }
+ }
+ }
+}
diff --git a/crates/api/src/instance.rs b/crates/api/src/instance.rs
new file mode 100644
index 0000000000..7d0b26260a
--- /dev/null
+++ b/crates/api/src/instance.rs
@@ -0,0 +1,186 @@
+use crate::externals::Extern;
+use crate::module::Module;
+use crate::runtime::{Config, Store};
+use crate::trap::Trap;
+use anyhow::{Error, Result};
+use wasmtime_jit::{CompiledModule, Resolver};
+use wasmtime_runtime::{Export, InstanceHandle, InstantiationError};
+
+struct SimpleResolver<'a> {
+ imports: &'a [Extern],
+}
+
+impl Resolver for SimpleResolver<'_> {
+ fn resolve(&mut self, idx: u32, _name: &str, _field: &str) -> Option {
+ self.imports
+ .get(idx as usize)
+ .map(|i| i.get_wasmtime_export())
+ }
+}
+
+fn instantiate(
+ config: &Config,
+ compiled_module: &CompiledModule,
+ imports: &[Extern],
+) -> Result {
+ let mut resolver = SimpleResolver { imports };
+ unsafe {
+ let instance = compiled_module
+ .instantiate(
+ config.validating_config.operator_config.enable_bulk_memory,
+ &mut resolver,
+ )
+ .map_err(|e| -> Error {
+ match e {
+ InstantiationError::StartTrap(trap) | InstantiationError::Trap(trap) => {
+ Trap::from_jit(trap).into()
+ }
+ other => other.into(),
+ }
+ })?;
+ Ok(instance)
+ }
+}
+
+/// An instantiated WebAssembly module.
+///
+/// This type represents the instantiation of a [`Module`]. Once instantiated
+/// you can access the [`exports`](Instance::exports) which are of type
+/// [`Extern`] and provide the ability to call functions, set globals, read
+/// memory, etc. This is where all the fun stuff happens!
+///
+/// An [`Instance`] is created from two inputs, a [`Module`] and a list of
+/// imports, provided as a list of [`Extern`] values. The [`Module`] is the wasm
+/// code that was compiled and we're instantiating, and the [`Extern`] imports
+/// are how we're satisfying the imports of the module provided. On successful
+/// instantiation an [`Instance`] will automatically invoke the wasm `start`
+/// function.
+///
+/// When interacting with any wasm code you'll want to make an [`Instance`] to
+/// call any code or execute anything!
+#[derive(Clone)]
+pub struct Instance {
+ pub(crate) instance_handle: InstanceHandle,
+ module: Module,
+ exports: Box<[Extern]>,
+}
+
+impl Instance {
+ /// Creates a new [`Instance`] from the previously compiled [`Module`] and
+ /// list of `imports` specified.
+ ///
+ /// This method instantiates the `module` provided with the `imports`,
+ /// following the procedure in the [core specification][inst] to
+ /// instantiate. Instantiation can fail for a number of reasons (many
+ /// specified below), but if successful the `start` function will be
+ /// automatically run (if provided) and then the [`Instance`] will be
+ /// returned.
+ ///
+ /// ## Providing Imports
+ ///
+ /// The `imports` array here is a bit tricky. The entries in the list of
+ /// `imports` are intended to correspond 1:1 with the list of imports
+ /// returned by [`Module::imports`]. Before calling [`Instance::new`] you'll
+ /// want to inspect the return value of [`Module::imports`] and, for each
+ /// import type, create an [`Extern`] which corresponds to that type.
+ /// These [`Extern`] values are all then collected into a list and passed to
+ /// this function.
+ ///
+ /// Note that this function is intentionally relatively low level. It is the
+ /// intention that we'll soon provide a [higher level API][issue] which will
+ /// be much more ergonomic for instantiating modules. If you need the full
+ /// power of customization of imports, though, this is the method for you!
+ ///
+ /// ## Errors
+ ///
+ /// This function can fail for a number of reasons, including, but not
+ /// limited to:
+ ///
+ /// * The number of `imports` provided doesn't match the number of imports
+ /// returned by the `module`'s [`Module::imports`] method.
+ /// * The type of any [`Extern`] doesn't match the corresponding
+ /// [`ExternType`] entry that it maps to.
+ /// * The `start` function in the instance, if present, traps.
+ /// * Module/instance resource limits are exceeded.
+ ///
+ /// When instantiation fails it's recommended to inspect the return value to
+ /// see why it failed, or bubble it upwards. If you'd like to specifically
+ /// check for trap errors, you can use `error.downcast::()`.
+ ///
+ /// [inst]: https://webassembly.github.io/spec/core/exec/modules.html#exec-instantiation
+ /// [issue]: https://github.com/bytecodealliance/wasmtime/issues/727
+ pub fn new(module: &Module, imports: &[Extern]) -> Result {
+ let store = module.store();
+ let config = store.engine().config();
+ let instance_handle = instantiate(config, module.compiled_module(), imports)?;
+
+ let exports = {
+ let mut exports = Vec::with_capacity(module.exports().len());
+ for export in module.exports() {
+ let name = export.name().to_string();
+ let export = instance_handle.lookup(&name).expect("export");
+ exports.push(Extern::from_wasmtime_export(
+ store,
+ instance_handle.clone(),
+ export,
+ ));
+ }
+ exports.into_boxed_slice()
+ };
+ module.register_frame_info();
+ Ok(Instance {
+ instance_handle,
+ module: module.clone(),
+ exports,
+ })
+ }
+
+ /// Returns the associated [`Store`] that this `Instance` is compiled into.
+ ///
+ /// This is the [`Store`] that generally serves as a sort of global cache
+ /// for various instance-related things.
+ pub fn store(&self) -> &Store {
+ self.module.store()
+ }
+
+ /// Returns the associated [`Module`] that this `Instance` instantiated.
+ ///
+ /// The corresponding [`Module`] here is a static version of this `Instance`
+ /// which can be used to learn information such as naming information about
+ /// various functions.
+ pub fn module(&self) -> &Module {
+ &self.module
+ }
+
+ /// Returns the list of exported items from this [`Instance`].
+ ///
+ /// Note that the exports here do not have names associated with them,
+ /// they're simply the values that are exported. To learn the value of each
+ /// export you'll need to consult [`Module::exports`]. The list returned
+ /// here maps 1:1 with the list that [`Module::exports`] returns, and
+ /// [`ExportType`] contains the name of each export.
+ pub fn exports(&self) -> &[Extern] {
+ &self.exports
+ }
+
+ /// Looks up an exported [`Extern`] value by name.
+ ///
+ /// This method will search the module for an export named `name` and return
+ /// the value, if found.
+ ///
+ /// Returns `None` if there was no export named `name`.
+ pub fn get_export(&self, name: &str) -> Option<&Extern> {
+ let (i, _) = self
+ .module
+ .exports()
+ .iter()
+ .enumerate()
+ .find(|(_, e)| e.name() == name)?;
+ Some(&self.exports()[i])
+ }
+
+ #[doc(hidden)]
+ pub fn handle(&self) -> &InstanceHandle {
+ &self.instance_handle
+ }
+}
diff --git a/crates/api/src/lib.rs b/crates/api/src/lib.rs
new file mode 100644
index 0000000000..4e5bce5b6c
--- /dev/null
+++ b/crates/api/src/lib.rs
@@ -0,0 +1,44 @@
+//! Wasmtime's embedding API
+//!
+//! This crate contains a high-level API used to interact with WebAssembly
+//! modules. The API here is intended to mirror the proposed [WebAssembly C
+//! API](https://github.com/WebAssembly/wasm-c-api), with small extensions here
+//! and there to implement Rust idioms. This crate also defines the actual C API
+//! itself for consumption from other languages.
+
+#![deny(missing_docs)]
+
+mod callable;
+mod externals;
+mod frame_info;
+mod func;
+mod instance;
+mod module;
+mod r#ref;
+mod runtime;
+mod trampoline;
+mod trap;
+mod types;
+mod values;
+
+pub use crate::callable::Callable;
+pub use crate::externals::*;
+pub use crate::frame_info::FrameInfo;
+pub use crate::func::{Func, WasmRet, WasmTy};
+pub use crate::instance::Instance;
+pub use crate::module::Module;
+pub use crate::r#ref::{AnyRef, HostInfo, HostRef};
+pub use crate::runtime::{Config, Engine, OptLevel, Store, Strategy};
+pub use crate::trap::Trap;
+pub use crate::types::*;
+pub use crate::values::*;
+
+cfg_if::cfg_if! {
+ if #[cfg(unix)] {
+ pub mod unix;
+ } else if #[cfg(windows)] {
+ pub mod windows;
+ } else {
+ // ... unknown os!
+ }
+}
diff --git a/crates/api/src/module.rs b/crates/api/src/module.rs
new file mode 100644
index 0000000000..dd463d2fc5
--- /dev/null
+++ b/crates/api/src/module.rs
@@ -0,0 +1,442 @@
+use crate::frame_info::{GlobalFrameInfoRegistration, FRAME_INFO};
+use crate::runtime::Store;
+use crate::types::{
+ ExportType, ExternType, FuncType, GlobalType, ImportType, Limits, MemoryType, Mutability,
+ TableType, ValType,
+};
+use anyhow::{bail, Error, Result};
+use std::path::Path;
+use std::sync::{Arc, Mutex};
+use wasmparser::{
+ validate, CustomSectionKind, ExternalKind, ImportSectionEntryType, ModuleReader, Name,
+ SectionCode,
+};
+use wasmtime_jit::CompiledModule;
+
+fn into_memory_type(mt: wasmparser::MemoryType) -> Result {
+ if mt.shared {
+ bail!("shared memories are not supported yet");
+ }
+ Ok(MemoryType::new(Limits::new(
+ mt.limits.initial,
+ mt.limits.maximum,
+ )))
+}
+
+fn into_global_type(gt: wasmparser::GlobalType) -> GlobalType {
+ let mutability = if gt.mutable {
+ Mutability::Var
+ } else {
+ Mutability::Const
+ };
+ GlobalType::new(into_valtype(>.content_type), mutability)
+}
+
+// `into_valtype` is used for `map` which requires `&T`.
+#[allow(clippy::trivially_copy_pass_by_ref)]
+fn into_valtype(ty: &wasmparser::Type) -> ValType {
+ use wasmparser::Type::*;
+ match ty {
+ I32 => ValType::I32,
+ I64 => ValType::I64,
+ F32 => ValType::F32,
+ F64 => ValType::F64,
+ V128 => ValType::V128,
+ AnyFunc => ValType::FuncRef,
+ AnyRef => ValType::AnyRef,
+ _ => unimplemented!("types in into_valtype"),
+ }
+}
+
+fn into_func_type(mt: wasmparser::FuncType) -> FuncType {
+ assert_eq!(mt.form, wasmparser::Type::Func);
+ let params = mt.params.iter().map(into_valtype).collect::>();
+ let returns = mt.returns.iter().map(into_valtype).collect::>();
+ FuncType::new(params.into_boxed_slice(), returns.into_boxed_slice())
+}
+
+fn into_table_type(tt: wasmparser::TableType) -> TableType {
+ assert!(
+ tt.element_type == wasmparser::Type::AnyFunc || tt.element_type == wasmparser::Type::AnyRef
+ );
+ let ty = into_valtype(&tt.element_type);
+ let limits = Limits::new(tt.limits.initial, tt.limits.maximum);
+ TableType::new(ty, limits)
+}
+
+/// A compiled WebAssembly module, ready to be instantiated.
+///
+/// A `Module` is a compiled in-memory representation of an input WebAssembly
+/// binary. A `Module` is then used to create an [`Instance`](crate::Instance)
+/// through an instantiation process. You cannot call functions or fetch
+/// globals, for example, on a `Module` because it's purely a code
+/// representation. Instead you'll need to create an
+/// [`Instance`](crate::Instance) to interact with the wasm module.
+///
+/// ## Modules and `Clone`
+///
+/// Using `clone` on a `Module` is a cheap operation. It will not create an
+/// entirely new module, but rather just a new reference to the existing module.
+/// In other words it's a shallow copy, not a deep copy.
+#[derive(Clone)]
+pub struct Module {
+ inner: Arc,
+}
+
+struct ModuleInner {
+ store: Store,
+ imports: Box<[ImportType]>,
+ exports: Box<[ExportType]>,
+ compiled: CompiledModule,
+ frame_info_registration: Mutex