Support parsing the text format in wasmtime crate (#813)

* Support parsing the text format in `wasmtime` crate

This commit adds support to the `wasmtime::Module` type to parse the
text format. This is often quite convenient to support in testing or
tinkering with the runtime. Additionally the `wat` parser is pretty
lightweight and easy to add to builds, so it's relatively easy for us to
support as well!

The exact manner that this is now supported comes with a few updates to
the existing API:

* A new optional feature of the `wasmtime` crate, `wat`, has been added.
  This is enabled by default.
* The `Module::new` API now takes `impl AsRef<[u8]>` instead of just
  `&[u8]`, and when the `wat` feature is enabled it will attempt to
  interpret it either as a wasm binary or as the text format. Note that
  this check is quite cheap since you just check the first byte.
* A `Module::from_file` API was added as a convenience to parse a file
  from disk, allowing error messages for `*.wat` files on disk to be a
  bit nicer.
* APIs like `Module::new_unchecked` and `Module::validate` remain
  unchanged, they require the binary format to be called.

The intention here is to make this as convenient as possible for new
developers of the `wasmtime` crate. By changing the default behavior
though this has ramifications such as, for example, supporting the text
format implicitly through the C API now.

* Handle review comments

* Update more tests to avoid usage of `wat` crate

* Go back to unchecked for now in wasm_module_new

Looks like C# tests rely on this?
This commit is contained in:
Alex Crichton
2020-01-24 14:20:51 -06:00
committed by GitHub
parent 47d6db0be8
commit 16804673a2
15 changed files with 185 additions and 168 deletions

View File

@@ -38,8 +38,7 @@ fn same_import_names_still_distinct() -> anyhow::Result<()> {
}
let store = Store::default();
let wasm = wat::parse_str(WAT)?;
let module = Module::new(&store, &wasm)?;
let module = Module::new(&store, WAT)?;
let imports = [
Func::new(

View File

@@ -32,8 +32,7 @@ fn test_import_calling_export() {
}
let store = Store::default();
let wasm = wat::parse_str(WAT).unwrap();
let module = Module::new(&store, &wasm).expect("failed to create module");
let module = Module::new(&store, WAT).expect("failed to create module");
let callback = Rc::new(Callback {
other: RefCell::new(None),

View File

@@ -5,17 +5,15 @@ use wasmtime::*;
fn test_invoke_func_via_table() -> Result<()> {
let store = Store::default();
let binary = wat::parse_str(
r#"
(module
(func $f (result i64) (i64.const 42))
let wat = r#"
(module
(func $f (result i64) (i64.const 42))
(table (export "table") 1 1 anyfunc)
(elem (i32.const 0) $f)
)
"#,
)?;
let module = Module::new(&store, &binary).context("> Error compiling module!")?;
(table (export "table") 1 1 anyfunc)
(elem (i32.const 0) $f)
)
"#;
let module = Module::new(&store, wat).context("> Error compiling module!")?;
let instance = Instance::new(&module, &[]).context("> Error instantiating module!")?;
let f = instance

View File

@@ -3,15 +3,13 @@ use wasmtime::*;
#[test]
fn test_module_no_name() -> anyhow::Result<()> {
let store = Store::default();
let binary = wat::parse_str(
r#"
(module
(func (export "run") (nop))
)
"#,
)?;
let wat = r#"
(module
(func (export "run") (nop))
)
"#;
let module = Module::new(&store, &binary)?;
let module = Module::new(&store, wat)?;
assert_eq!(module.name(), None);
Ok(())
@@ -20,18 +18,16 @@ fn test_module_no_name() -> anyhow::Result<()> {
#[test]
fn test_module_name() -> anyhow::Result<()> {
let store = Store::default();
let binary = wat::parse_str(
r#"
(module $from_name_section
(func (export "run") (nop))
)
"#,
)?;
let wat = r#"
(module $from_name_section
(func (export "run") (nop))
)
"#;
let module = Module::new(&store, &binary)?;
let module = Module::new(&store, wat)?;
assert_eq!(module.name(), Some("from_name_section"));
let module = Module::new_with_name(&store, &binary, "override")?;
let module = Module::new_with_name(&store, wat, "override")?;
assert_eq!(module.name(), Some("override"));
Ok(())

View File

@@ -13,16 +13,14 @@ fn test_trap_return() -> Result<()> {
}
let store = Store::default();
let binary = wat::parse_str(
r#"
(module
(func $hello (import "" "hello"))
(func (export "run") (call $hello))
)
"#,
)?;
let wat = r#"
(module
(func $hello (import "" "hello"))
(func (export "run") (call $hello))
)
"#;
let module = Module::new(&store, &binary)?;
let module = Module::new(&store, wat)?;
let hello_type = FuncType::new(Box::new([]), Box::new([]));
let hello_func = Func::new(&store, hello_type, Rc::new(HelloCallback));
@@ -41,16 +39,14 @@ fn test_trap_return() -> Result<()> {
#[test]
fn test_trap_trace() -> Result<()> {
let store = Store::default();
let binary = wat::parse_str(
r#"
(module $hello_mod
(func (export "run") (call $hello))
(func $hello (unreachable))
)
"#,
)?;
let wat = r#"
(module $hello_mod
(func (export "run") (call $hello))
(func $hello (unreachable))
)
"#;
let module = Module::new(&store, &binary)?;
let module = Module::new(&store, wat)?;
let instance = Instance::new(&module, &[])?;
let run_func = instance.exports()[0]
.func()
@@ -82,20 +78,18 @@ fn test_trap_trace_cb() -> Result<()> {
}
let store = Store::default();
let binary = wat::parse_str(
r#"
(module $hello_mod
(import "" "throw" (func $throw))
(func (export "run") (call $hello))
(func $hello (call $throw))
)
"#,
)?;
let wat = r#"
(module $hello_mod
(import "" "throw" (func $throw))
(func (export "run") (call $hello))
(func $hello (call $throw))
)
"#;
let fn_type = FuncType::new(Box::new([]), Box::new([]));
let fn_func = Func::new(&store, fn_type, Rc::new(ThrowCallback));
let module = Module::new(&store, &binary)?;
let module = Module::new(&store, wat)?;
let instance = Instance::new(&module, &[fn_func.into()])?;
let run_func = instance.exports()[0]
.func()
@@ -117,15 +111,13 @@ fn test_trap_trace_cb() -> Result<()> {
#[test]
fn test_trap_stack_overflow() -> Result<()> {
let store = Store::default();
let binary = wat::parse_str(
r#"
(module $rec_mod
(func $run (export "run") (call $run))
)
"#,
)?;
let wat = r#"
(module $rec_mod
(func $run (export "run") (call $run))
)
"#;
let module = Module::new(&store, &binary)?;
let module = Module::new(&store, wat)?;
let instance = Instance::new(&module, &[])?;
let run_func = instance.exports()[0]
.func()
@@ -148,18 +140,16 @@ fn test_trap_stack_overflow() -> Result<()> {
#[test]
fn trap_display_pretty() -> Result<()> {
let store = Store::default();
let binary = wat::parse_str(
r#"
(module $m
(func $die unreachable)
(func call $die)
(func $foo call 1)
(func (export "bar") call $foo)
)
"#,
)?;
let wat = r#"
(module $m
(func $die unreachable)
(func call $die)
(func $foo call 1)
(func (export "bar") call $foo)
)
"#;
let module = Module::new(&store, &binary)?;
let module = Module::new(&store, wat)?;
let instance = Instance::new(&module, &[])?;
let run_func = instance.exports()[0]
.func()
@@ -183,31 +173,27 @@ wasm backtrace:
#[test]
fn trap_display_multi_module() -> Result<()> {
let store = Store::default();
let binary = wat::parse_str(
r#"
(module $a
(func $die unreachable)
(func call $die)
(func $foo call 1)
(func (export "bar") call $foo)
)
"#,
)?;
let wat = r#"
(module $a
(func $die unreachable)
(func call $die)
(func $foo call 1)
(func (export "bar") call $foo)
)
"#;
let module = Module::new(&store, &binary)?;
let module = Module::new(&store, wat)?;
let instance = Instance::new(&module, &[])?;
let bar = instance.exports()[0].clone();
let binary = wat::parse_str(
r#"
(module $b
(import "" "" (func $bar))
(func $middle call $bar)
(func (export "bar2") call $middle)
)
"#,
)?;
let module = Module::new(&store, &binary)?;
let wat = r#"
(module $b
(import "" "" (func $bar))
(func $middle call $bar)
(func (export "bar2") call $middle)
)
"#;
let module = Module::new(&store, wat)?;
let instance = Instance::new(&module, &[bar])?;
let bar2 = instance.exports()[0]
.func()