Implement RFC 11: Redesigning Wasmtime's APIs (#2897)

Implement Wasmtime's new API as designed by RFC 11. This is quite a large commit which has had lots of discussion externally, so for more information it's best to read the RFC thread and the PR thread.
This commit is contained in:
Alex Crichton
2021-06-03 09:10:53 -05:00
committed by GitHub
parent a5a28b1c5b
commit 7a1b7cdf92
233 changed files with 13349 additions and 11997 deletions

View File

@@ -21,8 +21,8 @@ fn successful_instantiation() -> Result<()> {
let module = Module::new(&engine, r#"(module (memory 1) (table 10 funcref))"#)?;
// Module should instantiate
let store = Store::new(&engine);
Instance::new(&store, &module, &[])?;
let mut store = Store::new(&engine, ());
Instance::new(&mut store, &module, &[])?;
Ok(())
}
@@ -61,30 +61,36 @@ fn memory_limit() -> Result<()> {
// Instantiate the module and grow the memory via the `f` function
{
let store = Store::new(&engine);
let instance = Instance::new(&store, &module, &[])?;
let f = instance.get_typed_func::<(), i32>("f")?;
let mut store = Store::new(&engine, ());
let instance = Instance::new(&mut store, &module, &[])?;
let f = instance.get_typed_func::<(), i32, _>(&mut store, "f")?;
assert_eq!(f.call(()).expect("function should not trap"), 0);
assert_eq!(f.call(()).expect("function should not trap"), 1);
assert_eq!(f.call(()).expect("function should not trap"), 2);
assert_eq!(f.call(()).expect("function should not trap"), -1);
assert_eq!(f.call(()).expect("function should not trap"), -1);
assert_eq!(f.call(&mut store, ()).expect("function should not trap"), 0);
assert_eq!(f.call(&mut store, ()).expect("function should not trap"), 1);
assert_eq!(f.call(&mut store, ()).expect("function should not trap"), 2);
assert_eq!(
f.call(&mut store, ()).expect("function should not trap"),
-1
);
assert_eq!(
f.call(&mut store, ()).expect("function should not trap"),
-1
);
}
// Instantiate the module and grow the memory via the Wasmtime API
let store = Store::new(&engine);
let instance = Instance::new(&store, &module, &[])?;
let mut store = Store::new(&engine, ());
let instance = Instance::new(&mut store, &module, &[])?;
let memory = instance.get_memory("m").unwrap();
assert_eq!(memory.size(), 0);
assert_eq!(memory.grow(1).expect("memory should grow"), 0);
assert_eq!(memory.size(), 1);
assert_eq!(memory.grow(1).expect("memory should grow"), 1);
assert_eq!(memory.size(), 2);
assert_eq!(memory.grow(1).expect("memory should grow"), 2);
assert_eq!(memory.size(), 3);
assert!(memory.grow(1).is_err());
let memory = instance.get_memory(&mut store, "m").unwrap();
assert_eq!(memory.size(&store), 0);
assert_eq!(memory.grow(&mut store, 1).expect("memory should grow"), 0);
assert_eq!(memory.size(&store), 1);
assert_eq!(memory.grow(&mut store, 1).expect("memory should grow"), 1);
assert_eq!(memory.size(&store), 2);
assert_eq!(memory.grow(&mut store, 1).expect("memory should grow"), 2);
assert_eq!(memory.size(&store), 3);
assert!(memory.grow(&mut store, 1).is_err());
Ok(())
}
@@ -112,17 +118,15 @@ fn memory_init() -> Result<()> {
r#"(module (memory (export "m") 2) (data (i32.const 65530) "this data spans multiple pages") (data (i32.const 10) "hello world"))"#,
)?;
let store = Store::new(&engine);
let instance = Instance::new(&store, &module, &[])?;
let memory = instance.get_memory("m").unwrap();
let mut store = Store::new(&engine, ());
let instance = Instance::new(&mut store, &module, &[])?;
let memory = instance.get_memory(&mut store, "m").unwrap();
unsafe {
assert_eq!(
&memory.data_unchecked()[65530..65560],
b"this data spans multiple pages"
);
assert_eq!(&memory.data_unchecked()[10..21], b"hello world");
}
assert_eq!(
&memory.data(&store)[65530..65560],
b"this data spans multiple pages"
);
assert_eq!(&memory.data(&store)[10..21], b"hello world");
Ok(())
}
@@ -152,30 +156,31 @@ fn memory_guard_page_trap() -> Result<()> {
// Instantiate the module and check for out of bounds trap
for _ in 0..10 {
let store = Store::new(&engine);
let instance = Instance::new(&store, &module, &[])?;
let m = instance.get_memory("m").unwrap();
let f = instance.get_typed_func::<i32, ()>("f")?;
let mut store = Store::new(&engine, ());
let instance = Instance::new(&mut store, &module, &[])?;
let m = instance.get_memory(&mut store, "m").unwrap();
let f = instance.get_typed_func::<i32, (), _>(&mut store, "f")?;
let trap = f.call(0).expect_err("function should trap");
let trap = f.call(&mut store, 0).expect_err("function should trap");
assert!(trap.to_string().contains("out of bounds"));
let trap = f.call(1).expect_err("function should trap");
let trap = f.call(&mut store, 1).expect_err("function should trap");
assert!(trap.to_string().contains("out of bounds"));
m.grow(1).expect("memory should grow");
f.call(0).expect("function should not trap");
m.grow(&mut store, 1).expect("memory should grow");
f.call(&mut store, 0).expect("function should not trap");
let trap = f.call(65536).expect_err("function should trap");
let trap = f.call(&mut store, 65536).expect_err("function should trap");
assert!(trap.to_string().contains("out of bounds"));
let trap = f.call(65537).expect_err("function should trap");
let trap = f.call(&mut store, 65537).expect_err("function should trap");
assert!(trap.to_string().contains("out of bounds"));
m.grow(1).expect("memory should grow");
f.call(65536).expect("function should not trap");
m.grow(&mut store, 1).expect("memory should grow");
f.call(&mut store, 65536).expect("function should not trap");
m.grow(1).expect_err("memory should be at the limit");
m.grow(&mut store, 1)
.expect_err("memory should be at the limit");
}
Ok(())
@@ -204,20 +209,20 @@ fn memory_zeroed() -> Result<()> {
// Instantiate the module repeatedly after writing data to the entire memory
for _ in 0..10 {
let store = Store::new(&engine);
let instance = Instance::new(&store, &module, &[])?;
let memory = instance.get_memory("m").unwrap();
let mut store = Store::new(&engine, ());
let instance = Instance::new(&mut store, &module, &[])?;
let memory = instance.get_memory(&mut store, "m").unwrap();
assert_eq!(memory.size(), 1);
assert_eq!(memory.data_size(), 65536);
assert_eq!(memory.size(&store,), 1);
assert_eq!(memory.data_size(&store), 65536);
let ptr = memory.data_ptr();
let ptr = memory.data_mut(&mut store).as_mut_ptr();
unsafe {
for i in 0..8192 {
assert_eq!(*ptr.cast::<u64>().offset(i), 0);
}
std::ptr::write_bytes(ptr, 0xFE, memory.data_size());
std::ptr::write_bytes(ptr, 0xFE, memory.data_size(&store));
}
}
@@ -259,36 +264,45 @@ fn table_limit() -> Result<()> {
// Instantiate the module and grow the table via the `f` function
{
let store = Store::new(&engine);
let instance = Instance::new(&store, &module, &[])?;
let f = instance.get_typed_func::<(), i32>("f")?;
let mut store = Store::new(&engine, ());
let instance = Instance::new(&mut store, &module, &[])?;
let f = instance.get_typed_func::<(), i32, _>(&mut store, "f")?;
for i in 0..TABLE_ELEMENTS {
assert_eq!(f.call(()).expect("function should not trap"), i as i32);
assert_eq!(
f.call(&mut store, ()).expect("function should not trap"),
i as i32
);
}
assert_eq!(f.call(()).expect("function should not trap"), -1);
assert_eq!(f.call(()).expect("function should not trap"), -1);
assert_eq!(
f.call(&mut store, ()).expect("function should not trap"),
-1
);
assert_eq!(
f.call(&mut store, ()).expect("function should not trap"),
-1
);
}
// Instantiate the module and grow the table via the Wasmtime API
let store = Store::new(&engine);
let instance = Instance::new(&store, &module, &[])?;
let mut store = Store::new(&engine, ());
let instance = Instance::new(&mut store, &module, &[])?;
let table = instance.get_table("t").unwrap();
let table = instance.get_table(&mut store, "t").unwrap();
for i in 0..TABLE_ELEMENTS {
assert_eq!(table.size(), i);
assert_eq!(table.size(&store), i);
assert_eq!(
table
.grow(1, Val::FuncRef(None))
.grow(&mut store, 1, Val::FuncRef(None))
.expect("table should grow"),
i
);
}
assert_eq!(table.size(), TABLE_ELEMENTS);
assert!(table.grow(1, Val::FuncRef(None)).is_err());
assert_eq!(table.size(&store), TABLE_ELEMENTS);
assert!(table.grow(&mut store, 1, Val::FuncRef(None)).is_err());
Ok(())
}
@@ -316,22 +330,22 @@ fn table_init() -> Result<()> {
r#"(module (table (export "t") 6 funcref) (elem (i32.const 1) 1 2 3 4) (elem (i32.const 0) 0) (func) (func (param i32)) (func (param i32 i32)) (func (param i32 i32 i32)) (func (param i32 i32 i32 i32)))"#,
)?;
let store = Store::new(&engine);
let instance = Instance::new(&store, &module, &[])?;
let table = instance.get_table("t").unwrap();
let mut store = Store::new(&engine, ());
let instance = Instance::new(&mut store, &module, &[])?;
let table = instance.get_table(&mut store, "t").unwrap();
for i in 0..5 {
let v = table.get(i).expect("table should have entry");
let v = table.get(&mut store, i).expect("table should have entry");
let f = v
.funcref()
.expect("expected funcref")
.expect("expected non-null value");
assert_eq!(f.ty().params().len(), i as usize);
assert_eq!(f.ty(&store).params().len(), i as usize);
}
assert!(
table
.get(5)
.get(&mut store, 5)
.expect("table should have entry")
.funcref()
.expect("expected funcref")
@@ -365,19 +379,21 @@ fn table_zeroed() -> Result<()> {
// Instantiate the module repeatedly after filling table elements
for _ in 0..10 {
let store = Store::new(&engine);
let instance = Instance::new(&store, &module, &[])?;
let table = instance.get_table("t").unwrap();
let f = Func::wrap(&store, || {});
let mut store = Store::new(&engine, ());
let instance = Instance::new(&mut store, &module, &[])?;
let table = instance.get_table(&mut store, "t").unwrap();
let f = Func::wrap(&mut store, || {});
assert_eq!(table.size(), 10);
assert_eq!(table.size(&store), 10);
for i in 0..10 {
match table.get(i).unwrap() {
match table.get(&mut store, i).unwrap() {
Val::FuncRef(r) => assert!(r.is_none()),
_ => panic!("expected a funcref"),
}
table.set(i, Val::FuncRef(Some(f.clone()))).unwrap();
table
.set(&mut store, i, Val::FuncRef(Some(f.clone())))
.unwrap();
}
}
@@ -406,13 +422,13 @@ fn instantiation_limit() -> Result<()> {
// Instantiate to the limit
{
let store = Store::new(&engine);
let mut store = Store::new(&engine, ());
for _ in 0..INSTANCE_LIMIT {
Instance::new(&store, &module, &[])?;
Instance::new(&mut store, &module, &[])?;
}
match Instance::new(&store, &module, &[]) {
match Instance::new(&mut store, &module, &[]) {
Ok(_) => panic!("instantiation should fail"),
Err(e) => assert_eq!(
e.to_string(),
@@ -426,10 +442,10 @@ fn instantiation_limit() -> Result<()> {
// With the above store dropped, ensure instantiations can be made
let store = Store::new(&engine);
let mut store = Store::new(&engine, ());
for _ in 0..INSTANCE_LIMIT {
Instance::new(&store, &module, &[])?;
Instance::new(&mut store, &module, &[])?;
}
Ok(())