Move Webassembly objects to Store and remove Context

Co-authored-by: ptitSeb <sebastien.chev@gmail.com>
Co-authored-by: Manos Pitsidianakis <manos@wasmer.io>
This commit is contained in:
Syrus Akbary
2022-07-08 15:33:29 -07:00
committed by Manos Pitsidianakis
parent b5ae6399ce
commit a419ccdf52
214 changed files with 5800 additions and 5759 deletions

View File

@ -149,14 +149,14 @@ pub fn run_basic_dynamic_function(store: &Store, compiler_name: &str, c: &mut Cr
fn run_static_benchmarks(_c: &mut Criterion) {
#[cfg(feature = "llvm")]
{
let store =
let mut store =
Store::new_with_engine(&Universal::new(wasmer_compiler_llvm::LLVM::new()).engine());
run_basic_static_function(&store, "llvm", c);
}
#[cfg(feature = "cranelift")]
{
let store = Store::new_with_engine(
let mut store = Store::new_with_engine(
&Universal::new(wasmer_compiler_cranelift::Cranelift::new()).engine(),
);
run_basic_static_function(&store, "cranelift", c);
@ -164,7 +164,7 @@ fn run_static_benchmarks(_c: &mut Criterion) {
#[cfg(feature = "singlepass")]
{
let store = Store::new_with_engine(
let mut store = Store::new_with_engine(
&Universal::new(wasmer_compiler_singlepass::Singlepass::new()).engine(),
);
run_basic_static_function(&store, "singlepass", c);
@ -174,14 +174,14 @@ fn run_static_benchmarks(_c: &mut Criterion) {
fn run_dynamic_benchmarks(_c: &mut Criterion) {
#[cfg(feature = "llvm")]
{
let store =
let mut store =
Store::new_with_engine(&Universal::new(wasmer_compiler_llvm::LLVM::new()).engine());
run_basic_dynamic_function(&store, "llvm", c);
}
#[cfg(feature = "cranelift")]
{
let store = Store::new_with_engine(
let mut store = Store::new_with_engine(
&Universal::new(wasmer_compiler_cranelift::Cranelift::new()).engine(),
);
run_basic_dynamic_function(&store, "cranelift", c);
@ -189,7 +189,7 @@ fn run_dynamic_benchmarks(_c: &mut Criterion) {
#[cfg(feature = "singlepass")]
{
let store = Store::new_with_engine(
let mut store = Store::new_with_engine(
&Universal::new(wasmer_compiler_singlepass::Singlepass::new()).engine(),
);
run_basic_dynamic_function(&store, "singlepass", c);

View File

@ -49,7 +49,7 @@ TODO
You need a Store to create a context. Simple context is created using:
```rust
let ctx = Context::new(&store, ());
let ctx = FunctionEnv::new(&mut store, ());
```
For a Context with a custom Env, it will be similar:
@ -59,7 +59,7 @@ For a Context with a custom Env, it will be similar:
struct Env {
counter: i32,
}
let ctx = Context::new(&store, Env{counter: 0});
let ctx = FunctionEnv::new(&mut store, Env{counter: 0});
```
### Managing imports
@ -72,7 +72,7 @@ let import_object: Imports = imports! {
"host_function" => host_function,
},
};
let instance = Instance::new(&mut ctx, &module, &import_object).expect("Could not instantiate module.");
let instance = Instance::new(&mut store, &module, &import_object).expect("Could not instantiate module.");
```
You can also build the `Imports` object manually:
@ -80,18 +80,17 @@ You can also build the `Imports` object manually:
```rust
let mut import_object: Imports = Imports::new();
import_object.define("env", "host_function", host_function);
let instance = Instance::new(&mut ctx, &module, &import_object).expect("Could not instantiate module.");
let instance = Instance::new(&mut store, &module, &import_object).expect("Could not instantiate module.");
```
For WASI, don't forget to import memory to `WasiEnv`
```rust
let mut wasi_env = WasiState::new("hello").finalize()?;
let mut ctx = Context::new(&store, wasi_env.clone());
let import_object = wasi_env.import_object(&mut ctx.as_context_mut(), &module)?;
let instance = Instance::new(&mut ctx, &module, &import_object).expect("Could not instantiate module.");
let import_object = wasi_env.import_object(&mut store, &module)?;
let instance = Instance::new(&mut store, &module, &import_object).expect("Could not instantiate module.");
let memory = instance.exports.get_memory("memory")?;
ctx.data_mut().set_memory(memory.clone());
wasi_env.data_mut(&mut store).set_memory(memory.clone());
```
#### `ChainableNamedResolver` is removed
@ -122,7 +121,7 @@ let wasm_bytes = wat2wasm(
let compiler_config = Cranelift::default();
let engine = Universal::new(compiler_config).engine();
let store = Store::new(&engine);
let mut store = Store::new(&engine);
let module = Module::new(&store, wasm_bytes)?;
let instance = Instance::new(&module, &imports! {})?;
```
@ -137,7 +136,7 @@ let wasm_bytes = wat2wasm(
)?;
let compiler_config = Cranelift::default();
let store = Store::new(&compiler_config);
let mut store = Store::new(&compiler_config);
let module = Module::new(&store, wasm_bytes)?;
let instance = Instance::new(&module, &imports! {})?;
```

View File

@ -10,7 +10,7 @@
//!
//! Ready?
use wasmer::{imports, wat2wasm, Context, Instance, Module, Store, Value};
use wasmer::{imports, wat2wasm, Instance, Module, Store, Value};
use wasmer_compiler::Universal;
use wasmer_compiler_cranelift::Cranelift;
@ -33,8 +33,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let compiler = Cranelift::default();
// Create the store
let store = Store::new_with_engine(&Universal::new(compiler).engine());
let mut ctx = Context::new(&store, ());
let mut store = Store::new_with_engine(&Universal::new(compiler).engine());
println!("Compiling module...");
// Let's compile the Wasm module.
@ -45,14 +44,14 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("Instantiating module...");
// Let's instantiate the Wasm module.
let instance = Instance::new(&mut ctx, &module, &import_object)?;
let instance = Instance::new(&mut store, &module, &import_object)?;
let sum = instance.exports.get_function("sum")?;
println!("Calling `sum` function...");
// Let's call the `sum` exported function. The parameters are a
// slice of `Value`s. The results are a boxed slice of `Value`s.
let results = sum.call(&mut ctx, &[Value::I32(1), Value::I32(2)])?;
let results = sum.call(&mut store, &[Value::I32(1), Value::I32(2)])?;
println!("Results: {:?}", results);
assert_eq!(results.to_vec(), vec![Value::I32(3)]);

View File

@ -10,7 +10,7 @@
//!
//! Ready?
use wasmer::{imports, wat2wasm, Context, Instance, Module, Store, Value};
use wasmer::{imports, wat2wasm, Instance, Module, Store, Value};
use wasmer_compiler::Universal;
use wasmer_compiler_llvm::LLVM;
@ -33,8 +33,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let compiler = LLVM::default();
// Create the store
let store = Store::new_with_engine(&Universal::new(compiler).engine());
let mut ctx = Context::new(&store, ());
let mut store = Store::new_with_engine(&Universal::new(compiler).engine());
println!("Compiling module...");
// Let's compile the Wasm module.
@ -45,14 +44,14 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("Instantiating module...");
// Let's instantiate the Wasm module.
let instance = Instance::new(&mut ctx, &module, &import_object)?;
let instance = Instance::new(&mut store, &module, &import_object)?;
let sum = instance.exports.get_function("sum")?;
println!("Calling `sum` function...");
// Let's call the `sum` exported function. The parameters are a
// slice of `Value`s. The results are a boxed slice of `Value`s.
let results = sum.call(&mut ctx, &[Value::I32(1), Value::I32(2)])?;
let results = sum.call(&mut store, &[Value::I32(1), Value::I32(2)])?;
println!("Results: {:?}", results);
assert_eq!(results.to_vec(), vec![Value::I32(3)]);

View File

@ -10,7 +10,7 @@
//!
//! Ready?
use wasmer::{imports, wat2wasm, Context, Instance, Module, Store, Value};
use wasmer::{imports, wat2wasm, Instance, Module, Store, Value};
use wasmer_compiler::Universal;
use wasmer_compiler_singlepass::Singlepass;
@ -33,8 +33,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let compiler = Singlepass::default();
// Create the store
let store = Store::new_with_engine(&Universal::new(compiler).engine());
let mut ctx = Context::new(&store, ());
let mut store = Store::new_with_engine(&Universal::new(compiler).engine());
println!("Compiling module...");
// Let's compile the Wasm module.
@ -45,14 +44,14 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("Instantiating module...");
// Let's instantiate the Wasm module.
let instance = Instance::new(&mut ctx, &module, &import_object)?;
let instance = Instance::new(&mut store, &module, &import_object)?;
let sum = instance.exports.get_function("sum")?;
println!("Calling `sum` function...");
// Let's call the `sum` exported function. The parameters are a
// slice of `Value`s. The results are a boxed slice of `Value`s.
let results = sum.call(&mut ctx, &[Value::I32(1), Value::I32(2)])?;
let results = sum.call(&mut store, &[Value::I32(1), Value::I32(2)])?;
println!("Results: {:?}", results);
assert_eq!(results.to_vec(), vec![Value::I32(3)]);

View File

@ -17,7 +17,8 @@
use anyhow::bail;
use std::fmt;
use wasmer::{
imports, wat2wasm, Context, ContextMut, Function, Instance, Module, Store, TypedFunction,
imports, wat2wasm, Function, FunctionEnv, FunctionEnvMut, Instance, Module, Store,
TypedFunction,
};
use wasmer_compiler::Universal;
use wasmer_compiler_cranelift::Cranelift;
@ -57,15 +58,15 @@ fn main() -> anyhow::Result<()> {
// Note that we don't need to specify the engine/compiler if we want to use
// the default provided by Wasmer.
// You can use `Store::default()` for that.
let store = Store::new_with_engine(&Universal::new(Cranelift::default()).engine());
let mut ctx = Context::new(&store, ());
let mut store = Store::new_with_engine(&Universal::new(Cranelift::default()).engine());
let env = FunctionEnv::new(&mut store, ());
println!("Compiling module...");
// Let's compile the Wasm module.
let module = Module::new(&store, wasm_bytes)?;
// We declare the host function that we'll use to terminate execution.
fn early_exit(_ctx: ContextMut<()>) -> Result<(), ExitCode> {
fn early_exit(_ctx: FunctionEnvMut<()>) -> Result<(), ExitCode> {
// This is where it happens.
Err(ExitCode(1))
}
@ -73,23 +74,23 @@ fn main() -> anyhow::Result<()> {
// Create an import object.
let import_object = imports! {
"env" => {
"early_exit" => Function::new_native(&mut ctx, early_exit),
"early_exit" => Function::new_native(&mut store, &env, early_exit),
}
};
println!("Instantiating module...");
// Let's instantiate the Wasm module.
let instance = Instance::new(&mut ctx, &module, &import_object)?;
let instance = Instance::new(&mut store, &module, &import_object)?;
// Here we go.
//
// Get the `run` function which we'll use as our entrypoint.
println!("Calling `run` function...");
let run_func: TypedFunction<(i32, i32), i32> =
instance.exports.get_typed_function(&mut ctx, "run")?;
instance.exports.get_typed_function(&mut store, "run")?;
// When we call a function it can either succeed or fail. We expect it to fail.
match run_func.call(&mut ctx, 1, 7) {
match run_func.call(&mut store, 1, 7) {
Ok(result) => {
bail!(
"Expected early termination with `ExitCode`, found: {}",

View File

@ -79,7 +79,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
.engine();
// Create a store, that holds the engine.
let store = Store::new_with_engine(&engine);
let mut store = Store::new_with_engine(&engine);
println!("Compiling module...");
// Let's compile the Wasm module.

View File

@ -55,7 +55,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let engine = Dylib::new(compiler_config).engine();
// Create a store, that holds the engine.
let store = Store::new_with_engine(&engine);
let mut store = Store::new_with_engine(&engine);
println!("Compiling module...");
// Here we go.

View File

@ -47,7 +47,7 @@
use tempfile::NamedTempFile;
use wasmer::imports;
use wasmer::wat2wasm;
use wasmer::Context;
use wasmer::FunctionEnv;
use wasmer::Instance;
use wasmer::Module;
use wasmer::Store;
@ -85,7 +85,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let engine = Universal::new(compiler_config).engine();
// Create a store, that holds the engine.
let store = Store::new_with_engine(&engine);
let mut store = Store::new_with_engine(&engine);
println!("Compiling module...");
// Let's compile the Wasm module.
@ -106,8 +106,8 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("Creating headless Universal engine...");
// We create a headless Universal engine.
let engine = Universal::headless().engine();
let store = Store::new_with_engine(&engine);
let mut ctx = Context::new(&store, ());
let mut store = Store::new_with_engine(&engine);
let mut env = FunctionEnv::new(&mut store, ());
println!("Deserializing module...");
// Here we go.
@ -127,12 +127,12 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("Instantiating module...");
// Let's instantiate the Wasm module.
let instance = Instance::new(&mut ctx, &module, &import_object)?;
let instance = Instance::new(&mut store, &module, &import_object)?;
println!("Calling `sum` function...");
// The Wasm module exports a function called `sum`.
let sum = instance.exports.get_function("sum")?;
let results = sum.call(&mut ctx, &[Value::I32(1), Value::I32(2)])?;
let results = sum.call(&mut store, &[Value::I32(1), Value::I32(2)])?;
println!("Results: {:?}", results);
assert_eq!(results.to_vec(), vec![Value::I32(3)]);

View File

@ -18,7 +18,7 @@
//!
//! Ready?
use wasmer::{imports, wat2wasm, Context, Instance, Module, Store, Value};
use wasmer::{imports, wat2wasm, Instance, Module, Store, Value};
use wasmer_compiler::Universal;
use wasmer_compiler_cranelift::Cranelift;
@ -52,8 +52,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let engine = Universal::new(compiler_config).engine();
// Create a store, that holds the engine.
let store = Store::new_with_engine(&engine);
let mut ctx = Context::new(&store, ());
let mut store = Store::new_with_engine(&engine);
println!("Compiling module...");
// Here we go.
@ -73,12 +72,12 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("Instantiating module...");
// And here we go again. Let's instantiate the Wasm module.
let instance = Instance::new(&mut ctx, &module, &import_object)?;
let instance = Instance::new(&mut store, &module, &import_object)?;
println!("Calling `sum` function...");
// The Wasm module exports a function called `sum`.
let sum = instance.exports.get_function("sum")?;
let results = sum.call(&mut ctx, &[Value::I32(1), Value::I32(2)])?;
let results = sum.call(&mut store, &[Value::I32(1), Value::I32(2)])?;
println!("Results: {:?}", results);
assert_eq!(results.to_vec(), vec![Value::I32(3)]);

View File

@ -13,7 +13,7 @@
//!
//! Ready?
use wasmer::{imports, wat2wasm, Context, Instance, Module, Store, TypedFunction};
use wasmer::{imports, wat2wasm, FunctionEnv, Instance, Module, Store, TypedFunction};
use wasmer_compiler::Universal;
use wasmer_compiler_cranelift::Cranelift;
@ -39,8 +39,8 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
// Note that we don't need to specify the engine/compiler if we want to use
// the default provided by Wasmer.
// You can use `Store::default()` for that.
let store = Store::new_with_engine(&Universal::new(Cranelift::default()).engine());
let mut ctx = Context::new(&store, ());
let mut store = Store::new_with_engine(&Universal::new(Cranelift::default()).engine());
let mut env = FunctionEnv::new(&mut store, ());
println!("Compiling module...");
// Let's compile the Wasm module.
@ -51,7 +51,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("Instantiating module...");
// Let's instantiate the Wasm module.
let instance = Instance::new(&mut ctx, &module, &import_object)?;
let instance = Instance::new(&mut store, &module, &import_object)?;
// Here we go.
//
@ -63,11 +63,11 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let div_by_zero: TypedFunction<(), i32> = instance
.exports
.get_function("div_by_zero")?
.native(&mut ctx)?;
.native(&mut store)?;
println!("Calling `div_by_zero` function...");
// Let's call the `div_by_zero` exported function.
let result = div_by_zero.call(&mut ctx);
let result = div_by_zero.call(&mut store);
// When we call a function it can either succeed or fail. We expect it to fail.
match result {

View File

@ -17,7 +17,7 @@
//!
//! Ready?
use wasmer::{imports, wat2wasm, Context, Instance, Module, Store, TypedFunction, Value};
use wasmer::{imports, wat2wasm, FunctionEnv, Instance, Module, Store, TypedFunction, Value};
use wasmer_compiler::Universal;
use wasmer_compiler_cranelift::Cranelift;
@ -40,8 +40,8 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
// Note that we don't need to specify the engine/compiler if we want to use
// the default provided by Wasmer.
// You can use `Store::default()` for that.
let store = Store::new_with_engine(&Universal::new(Cranelift::default()).engine());
let mut ctx = Context::new(&store, ());
let mut store = Store::new_with_engine(&Universal::new(Cranelift::default()).engine());
let mut env = FunctionEnv::new(&mut store, ());
println!("Compiling module...");
// Let's compile the Wasm module.
@ -52,7 +52,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("Instantiating module...");
// Let's instantiate the Wasm module.
let instance = Instance::new(&mut ctx, &module, &import_object)?;
let instance = Instance::new(&mut store, &module, &import_object)?;
// Here we go.
//
@ -74,7 +74,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
// Let's call the `sum` exported function. The parameters are a
// slice of `Value`s. The results are a boxed slice of `Value`s.
let args = [Value::I32(1), Value::I32(2)];
let result = sum.call(&mut ctx, &args)?;
let result = sum.call(&mut store, &args)?;
println!("Results: {:?}", result);
assert_eq!(result.to_vec(), vec![Value::I32(3)]);
@ -87,13 +87,13 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
// `Rets`, respectively for the parameters and the results. If
// those values don't match the exported function signature, an
// error will be raised.
let sum_native: TypedFunction<(i32, i32), i32> = sum.native(&mut ctx)?;
let sum_native: TypedFunction<(i32, i32), i32> = sum.native(&mut store)?;
println!("Calling `sum` function (natively)...");
// Let's call the `sum` exported function. The parameters are
// statically typed Rust values of type `i32` and `i32`. The
// result, in this case particular case, in a unit of type `i32`.
let result = sum_native.call(&mut ctx, 3, 4)?;
let result = sum_native.call(&mut store, 3, 4)?;
println!("Results: {:?}", result);
assert_eq!(result, 7);

View File

@ -16,7 +16,7 @@
//! Ready?
use wasmer::{
imports, wat2wasm, Context, Instance, Module, Mutability, Store, Type, TypedFunction, Value,
imports, wat2wasm, FunctionEnv, Instance, Module, Mutability, Store, Type, TypedFunction, Value,
};
use wasmer_compiler::Universal;
use wasmer_compiler_cranelift::Cranelift;
@ -40,8 +40,8 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
// Note that we don't need to specify the engine/compiler if we want to use
// the default provided by Wasmer.
// You can use `Store::default()` for that.
let store = Store::new_with_engine(&Universal::new(Cranelift::default()).engine());
let mut ctx = Context::new(&store, ());
let mut store = Store::new_with_engine(&Universal::new(Cranelift::default()).engine());
let mut env = FunctionEnv::new(&mut store, ());
println!("Compiling module...");
// Let's compile the Wasm module.
@ -52,7 +52,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("Instantiating module...");
// Let's instantiate the Wasm module.
let instance = Instance::new(&mut ctx, &module, &import_object)?;
let instance = Instance::new(&mut store, &module, &import_object)?;
// Here we go.
//
@ -73,8 +73,8 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("Getting globals types information...");
// Let's get the globals types. The results are `GlobalType`s.
let one_type = one.ty(&mut ctx);
let some_type = some.ty(&mut ctx);
let one_type = one.ty(&store);
let some_type = some.ty(&store);
println!("`one` type: {:?} {:?}", one_type.mutability, one_type.ty);
assert_eq!(one_type.mutability, Mutability::Const);
@ -91,11 +91,13 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
//
// We will use an exported function for the `one` global
// and the Global API for `some`.
let get_one: TypedFunction<(), f32> =
instance.exports.get_function("get_one")?.native(&mut ctx)?;
let get_one: TypedFunction<(), f32> = instance
.exports
.get_function("get_one")?
.native(&mut store)?;
let one_value = get_one.call(&mut ctx)?;
let some_value = some.get(&mut ctx);
let one_value = get_one.call(&mut store)?;
let some_value = some.get(&mut store);
println!("`one` value: {:?}", one_value);
assert_eq!(one_value, 1.0);
@ -106,13 +108,13 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("Setting global values...");
// Trying to set the value of a immutable global (`const`)
// will result in a `RuntimeError`.
let result = one.set(&mut ctx, Value::F32(42.0));
let result = one.set(&mut store, Value::F32(42.0));
assert_eq!(
result.expect_err("Expected an error").message(),
"Attempted to set an immutable global"
);
let one_result = one.get(&mut ctx);
let one_result = one.get(&mut store);
println!("`one` value after `set`: {:?}", one_result);
assert_eq!(one_result, Value::F32(1.0));
@ -124,14 +126,14 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let set_some: TypedFunction<f32, ()> = instance
.exports
.get_function("set_some")?
.native(&mut ctx)?;
set_some.call(&mut ctx, 21.0)?;
let some_result = some.get(&mut ctx);
.native(&mut store)?;
set_some.call(&mut store, 21.0)?;
let some_result = some.get(&mut store);
println!("`some` value after `set_some`: {:?}", some_result);
assert_eq!(some_result, Value::F32(21.0));
some.set(&mut ctx, Value::F32(42.0))?;
let some_result = some.get(&mut ctx);
some.set(&mut store, Value::F32(42.0))?;
let some_result = some.get(&mut store);
println!("`some` value after `set`: {:?}", some_result);
assert_eq!(some_result, Value::F32(42.0));

View File

@ -11,7 +11,7 @@
//!
//! Ready?
use wasmer::{imports, wat2wasm, Context, Instance, Module, Store, TypedFunction, WasmPtr};
use wasmer::{imports, wat2wasm, FunctionEnv, Instance, Module, Store, TypedFunction, WasmPtr};
use wasmer_compiler::Universal;
use wasmer_compiler_cranelift::Cranelift;
@ -37,8 +37,8 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
// Note that we don't need to specify the engine/compiler if we want to use
// the default provided by Wasmer.
// You can use `Store::default()` for that.
let store = Store::new_with_engine(&Universal::new(Cranelift::default()).engine());
let mut ctx = Context::new(&store, ());
let mut store = Store::new_with_engine(&Universal::new(Cranelift::default()).engine());
let mut env = FunctionEnv::new(&mut store, ());
println!("Compiling module...");
// Let's compile the Wasm module.
@ -49,10 +49,10 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("Instantiating module...");
// Let's instantiate the Wasm module.
let instance = Instance::new(&mut ctx, &module, &import_object)?;
let instance = Instance::new(&mut store, &module, &import_object)?;
let load: TypedFunction<(), (WasmPtr<u8>, i32)> =
instance.exports.get_typed_function(&mut ctx, "load")?;
instance.exports.get_typed_function(&mut store, "load")?;
// Here we go.
//
@ -64,15 +64,15 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
//
// The first thing we might be intersted in is the size of the memory.
// Let's get it!
println!("Memory size (pages) {:?}", memory.size(&mut ctx));
println!("Memory size (bytes) {:?}", memory.data_size(&mut ctx));
println!("Memory size (pages) {:?}", memory.size(&mut store));
println!("Memory size (bytes) {:?}", memory.data_size(&mut store));
// Oh! Wait, before reading the contents, we need to know
// where to find what we are looking for.
//
// Fortunately, the Wasm module exports a `load` function
// which will tell us the offset and length of the string.
let (ptr, length) = load.call(&mut ctx)?;
let (ptr, length) = load.call(&mut store)?;
println!("String offset: {:?}", ptr.offset());
println!("String length: {:?}", length);
@ -81,7 +81,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
// We will get bytes out of the memory so we need to
// decode them into a string.
let str = ptr
.read_utf8_string(&mut ctx, memory, length as u32)
.read_utf8_string(&mut store, memory, length as u32)
.unwrap();
println!("Memory contents: {:?}", str);
@ -91,7 +91,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
// To do that, we'll make a slice from our pointer and change the content
// of each element.
let new_str = b"Hello, Wasmer!";
let values = ptr.slice(&mut ctx, memory, new_str.len() as u32).unwrap();
let values = ptr.slice(&mut store, memory, new_str.len() as u32).unwrap();
for i in 0..new_str.len() {
values.index(i as u64).write(new_str[i]).unwrap();
}
@ -104,7 +104,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("New string length: {:?}", new_str.len());
let str = ptr
.read_utf8_string(&mut ctx, memory, new_str.len() as u32)
.read_utf8_string(&mut store, memory, new_str.len() as u32)
.unwrap();
println!("New memory contents: {:?}", str);

View File

@ -10,7 +10,7 @@
//!
//! Ready?
use wasmer::{imports, wat2wasm, Context, Features, Instance, Module, Store, Value};
use wasmer::{imports, wat2wasm, Features, FunctionEnv, Instance, Module, Store, Value};
use wasmer_compiler::Universal;
use wasmer_compiler_cranelift::Cranelift;
@ -39,17 +39,17 @@ fn main() -> anyhow::Result<()> {
let engine = Universal::new(compiler).features(features);
// Now, let's define the store, and compile the module.
let store = Store::new_with_engine(&engine.engine());
let mut ctx = Context::new(&store, ());
let mut store = Store::new_with_engine(&engine.engine());
let mut env = FunctionEnv::new(&mut store, ());
let module = Module::new(&store, wasm_bytes)?;
// Finally, let's instantiate the module, and execute something
// :-).
let import_object = imports! {};
let instance = Instance::new(&mut ctx, &module, &import_object)?;
let instance = Instance::new(&mut store, &module, &import_object)?;
let swap = instance.exports.get_function("swap")?;
let results = swap.call(&mut ctx, &[Value::I32(1), Value::I64(2)])?;
let results = swap.call(&mut store, &[Value::I32(1), Value::I64(2)])?;
assert_eq!(results.to_vec(), vec![Value::I64(2), Value::I32(1)]);

View File

@ -7,7 +7,8 @@
//! ```
use wasmer::{
imports, wat2wasm, Context, ContextMut, Function, Instance, Module, Store, TypedFunction,
imports, wat2wasm, Function, FunctionEnv, FunctionEnvMut, Instance, Module, Store,
TypedFunction,
};
use wasmer_compiler::Universal;
use wasmer_compiler_cranelift::Cranelift;
@ -46,19 +47,19 @@ fn main() -> anyhow::Result<()> {
// However for the purposes of showing what's happening, we create a compiler
// (`Cranelift`) and pass it to an engine (`Universal`). We then pass the engine to
// the store and are now ready to compile and run WebAssembly!
let store = Store::new_with_engine(&Universal::new(Cranelift::default()).engine());
let mut store = Store::new_with_engine(&Universal::new(Cranelift::default()).engine());
// We then use our store and Wasm bytes to compile a `Module`.
// A `Module` is a compiled WebAssembly module that isn't ready to execute yet.
let module = Module::new(&store, wasm_bytes)?;
// Next we'll set up our `Module` so that we can execute it. First, create
// a `Context` in which to instantiate our `Module`.
let mut context = Context::new(&store, ());
// a `FunctionEnv` in which to instantiate our `Module`.
let mut context = FunctionEnv::new(&mut store, ());
// We define a function to act as our "env" "say_hello" function imported in the
// Wasm program above.
fn say_hello_world(_ctx: ContextMut<'_, ()>) {
fn say_hello_world(_ctx: FunctionEnvMut<'_, ()>) {
println!("Hello, world!")
}
@ -67,7 +68,7 @@ fn main() -> anyhow::Result<()> {
// We use the default namespace "env".
"env" => {
// And call our function "say_hello".
"say_hello" => Function::new_native(&mut context, say_hello_world),
"say_hello" => Function::new_native(&mut store, &context, say_hello_world),
}
};
@ -75,18 +76,17 @@ fn main() -> anyhow::Result<()> {
//
// An `Instance` is a compiled WebAssembly module that has been set up
// and is ready to execute.
let instance = Instance::new(&mut context, &module, &import_object)?;
let instance = Instance::new(&mut store, &module, &import_object)?;
// We get the `TypedFunction` with no parameters and no results from the instance.
//
// Recall that the Wasm module exported a function named "run", this is getting
// that exported function from the `Instance`.
let run_func: TypedFunction<(), ()> =
instance.exports.get_typed_function(&mut context, "run")?;
let run_func: TypedFunction<(), ()> = instance.exports.get_typed_function(&mut store, "run")?;
// Finally, we call our exported Wasm function which will call our "say_hello"
// function and return.
run_func.call(&mut context)?;
run_func.call(&mut store)?;
Ok(())
}

View File

@ -16,8 +16,8 @@
//! Ready?
use wasmer::{
imports, wat2wasm, Context, Function, FunctionType, Global, Instance, Memory, Module, Store,
Table, Type, Value,
imports, wat2wasm, Function, FunctionEnv, FunctionType, Global, Instance, Memory, Module,
Store, Table, Type, Value,
};
use wasmer_compiler::Universal;
use wasmer_compiler_cranelift::Cranelift;
@ -44,8 +44,8 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
// Note that we don't need to specify the engine/compiler if we want to use
// the default provided by Wasmer.
// You can use `Store::default()` for that.
let store = Store::new_with_engine(&Universal::new(Cranelift::default()).engine());
let mut ctx = Context::new(&store, ());
let mut store = Store::new_with_engine(&Universal::new(Cranelift::default()).engine());
let mut env = FunctionEnv::new(&mut store, ());
println!("Compiling module...");
// Let's compile the Wasm module.
@ -60,12 +60,12 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
// covered in more detail in other examples.
println!("Creating the imported function...");
let host_function_signature = FunctionType::new(vec![], vec![Type::I32]);
let host_function = Function::new(&mut ctx, &host_function_signature, |_ctx, _args| {
let host_function = Function::new(&mut store, &env, &host_function_signature, |_ctx, _args| {
Ok(vec![Value::I32(42)])
});
println!("Creating the imported global...");
let host_global = Global::new(&mut ctx, Value::I32(42));
let host_global = Global::new(&mut store, Value::I32(42));
// Create an import object.
//
@ -90,7 +90,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("Instantiating module...");
// Let's instantiate the Wasm module.
let instance = Instance::new(&mut ctx, &module, &import_object)?;
let instance = Instance::new(&mut store, &module, &import_object)?;
// Here we go.
//
@ -103,19 +103,19 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
// Let's get them.
println!("Getting the exported function...");
let function = instance.exports.get::<Function>("guest_function")?;
println!("Got exported function of type: {:?}", function.ty(&mut ctx));
println!("Got exported function of type: {:?}", function.ty(&store));
println!("Getting the exported global...");
let global = instance.exports.get::<Global>("guest_global")?;
println!("Got exported global of type: {:?}", global.ty(&mut ctx));
println!("Got exported global of type: {:?}", global.ty(&store));
println!("Getting the exported memory...");
let memory = instance.exports.get::<Memory>("guest_memory")?;
println!("Got exported memory of type: {:?}", memory.ty(&mut ctx));
println!("Got exported memory of type: {:?}", memory.ty(&store));
println!("Getting the exported table...");
let table = instance.exports.get::<Table>("guest_table")?;
println!("Got exported table of type: {:?}", table.ty(&mut ctx));
println!("Got exported table of type: {:?}", table.ty(&store));
Ok(())
}

View File

@ -18,8 +18,8 @@
//! Ready?
use wasmer::{
imports, wat2wasm, Context, ContextMut, Function, FunctionType, Instance, Module, Store, Type,
TypedFunction, Value,
imports, wat2wasm, Function, FunctionEnv, FunctionEnvMut, FunctionType, Instance, Module,
Store, Type, TypedFunction, Value,
};
use wasmer_compiler::Universal;
use wasmer_compiler_cranelift::Cranelift;
@ -45,8 +45,10 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
// Note that we don't need to specify the engine/compiler if we want to use
// the default provided by Wasmer.
// You can use `Store::default()` for that.
let store = Store::new_with_engine(&Universal::new(Cranelift::default()).engine());
let mut ctx = Context::new(&store, ());
let mut store = Store::new_with_engine(&Universal::new(Cranelift::default()).engine());
let mut ctx1 = FunctionEnv::new(&mut store, ());
struct MyEnv;
let mut ctx2 = FunctionEnv::new(&mut store, MyEnv {});
println!("Compiling module...");
// Let's compile the Wasm module.
@ -54,17 +56,22 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
// Create the functions
let multiply_dynamic_signature = FunctionType::new(vec![Type::I32], vec![Type::I32]);
let multiply_dynamic = Function::new(&mut ctx, &multiply_dynamic_signature, |_ctx, args| {
println!("Calling `multiply_dynamic`...");
let multiply_dynamic = Function::new(
&mut store,
&ctx1,
&multiply_dynamic_signature,
|_ctx, args| {
println!("Calling `multiply_dynamic`...");
let result = args[0].unwrap_i32() * 2;
let result = args[0].unwrap_i32() * 2;
println!("Result of `multiply_dynamic`: {:?}", result);
println!("Result of `multiply_dynamic`: {:?}", result);
Ok(vec![Value::I32(result)])
});
Ok(vec![Value::I32(result)])
},
);
fn multiply(_ctx: ContextMut<()>, a: i32) -> i32 {
fn multiply(_ctx: FunctionEnvMut<MyEnv>, a: i32) -> i32 {
println!("Calling `multiply_native`...");
let result = a * 3;
@ -72,7 +79,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
result
}
let multiply_native = Function::new_native(&mut ctx, multiply);
let multiply_native = Function::new_native(&mut store, &ctx2, multiply);
// Create an import object.
let import_object = imports! {
@ -84,18 +91,18 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("Instantiating module...");
// Let's instantiate the Wasm module.
let instance = Instance::new(&mut ctx, &module, &import_object)?;
let instance = Instance::new(&mut store, &module, &import_object)?;
// Here we go.
//
// The Wasm module exports a function called `sum`. Let's get it.
let sum: TypedFunction<(i32, i32), i32> =
instance.exports.get_function("sum")?.native(&mut ctx)?;
instance.exports.get_function("sum")?.native(&mut store)?;
println!("Calling `sum` function...");
// Let's call the `sum` exported function. It will call each
// of the imported functions.
let result = sum.call(&mut ctx, 1, 2)?;
let result = sum.call(&mut store, 1, 2)?;
println!("Results of `sum`: {:?}", result);
assert_eq!(result, 8);

View File

@ -21,7 +21,8 @@
use std::sync::{Arc, Mutex};
use wasmer::{
imports, wat2wasm, Context, ContextMut, Function, Instance, Module, Store, TypedFunction,
imports, wat2wasm, Function, FunctionEnv, FunctionEnvMut, Instance, Module, Store,
TypedFunction,
};
use wasmer_compiler::Universal;
use wasmer_compiler_cranelift::Cranelift;
@ -51,7 +52,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
// Note that we don't need to specify the engine/compiler if we want to use
// the default provided by Wasmer.
// You can use `Store::default()` for that.
let store = Store::new_with_engine(&Universal::new(Cranelift::default()).engine());
let mut store = Store::new_with_engine(&Universal::new(Cranelift::default()).engine());
println!("Compiling module...");
// Let's compile the Wasm module.
@ -65,7 +66,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let shared_counter: Arc<Mutex<i32>> = Arc::new(Mutex::new(0));
// Once we have our counter we'll wrap it inside en `Env` which we'll pass
// to our imported functionsvia the Context.
// to our imported functionsvia the FunctionEnv.
//
// This struct may have been anything. The only constraint is it must be
// possible to know the size of the `Env` at compile time (i.e it has to
@ -77,18 +78,18 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
}
// Create the functions
fn get_counter(ctx: ContextMut<Env>) -> i32 {
fn get_counter(ctx: FunctionEnvMut<Env>) -> i32 {
*ctx.data().counter.lock().unwrap()
}
fn add_to_counter(mut ctx: ContextMut<Env>, add: i32) -> i32 {
fn add_to_counter(mut ctx: FunctionEnvMut<Env>, add: i32) -> i32 {
let mut counter_ref = ctx.data_mut().counter.lock().unwrap();
*counter_ref += add;
*counter_ref
}
let mut ctx = Context::new(
&store,
let mut env = FunctionEnv::new(
&mut store,
Env {
counter: shared_counter.clone(),
},
@ -97,14 +98,14 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
// Create an import object.
let import_object = imports! {
"env" => {
"get_counter" => Function::new_native(&mut ctx, get_counter),
"add_to_counter" => Function::new_native(&mut ctx, add_to_counter),
"get_counter" => Function::new_native(&mut store, &env, get_counter),
"add_to_counter" => Function::new_native(&mut store, &env, add_to_counter),
}
};
println!("Instantiating module...");
// Let's instantiate the Wasm module.
let instance = Instance::new(&mut ctx, &module, &import_object)?;
let instance = Instance::new(&mut store, &module, &import_object)?;
// Here we go.
//
@ -112,7 +113,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let increment_counter_loop: TypedFunction<i32, i32> = instance
.exports
.get_function("increment_counter_loop")?
.native(&mut ctx)?;
.native(&mut store)?;
let counter_value: i32 = *shared_counter.lock().unwrap();
println!("Initial ounter value: {:?}", counter_value);
@ -121,7 +122,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
// Let's call the `increment_counter_loop` exported function.
//
// It will loop five times thus incrementing our counter five times.
let result = increment_counter_loop.call(&mut ctx, 5)?;
let result = increment_counter_loop.call(&mut store, 5)?;
let counter_value: i32 = *shared_counter.lock().unwrap();
println!("New counter value (host): {:?}", counter_value);

View File

@ -15,7 +15,9 @@
//!
//! Ready?
use wasmer::{imports, wat2wasm, Context, Global, Instance, Module, Store, TypedFunction, Value};
use wasmer::{
imports, wat2wasm, FunctionEnv, Global, Instance, Module, Store, TypedFunction, Value,
};
use wasmer_compiler::Universal;
use wasmer_compiler_cranelift::Cranelift;
@ -38,16 +40,16 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
// Note that we don't need to specify the engine/compiler if we want to use
// the default provided by Wasmer.
// You can use `Store::default()` for that.
let store = Store::new_with_engine(&Universal::new(Cranelift::default()).engine());
let mut ctx = Context::new(&store, ());
let mut store = Store::new_with_engine(&Universal::new(Cranelift::default()).engine());
let mut env = FunctionEnv::new(&mut store, ());
println!("Compiling module...");
// Let's compile the Wasm module.
let module = Module::new(&store, wasm_bytes)?;
// Create the globals
let some = Global::new(&mut ctx, Value::F32(1.0));
let other = Global::new_mut(&mut ctx, Value::F32(2.0));
let some = Global::new(&mut store, Value::F32(1.0));
let other = Global::new_mut(&mut store, Value::F32(2.0));
// Create an import object.
// We add the two required globals in the `env` namespace.
@ -60,7 +62,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("Instantiating module...");
// Let's instantiate the Wasm module.
let instance = Instance::new(&mut ctx, &module, &import_object)?;
let instance = Instance::new(&mut store, &module, &import_object)?;
// Here we go.
//
@ -69,34 +71,34 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let get_some: TypedFunction<(), f32> = instance
.exports
.get_function("get_some")?
.native(&mut ctx)?;
.native(&mut store)?;
let get_other: TypedFunction<(), f32> = instance
.exports
.get_function("get_other")?
.native(&mut ctx)?;
.native(&mut store)?;
let some_result = get_some.call(&mut ctx)?;
let other_result = get_other.call(&mut ctx)?;
let some_result = get_some.call(&mut store)?;
let other_result = get_other.call(&mut store)?;
println!("some value (via `get_some`): {:?}", some_result);
println!("some value (via Global API): {:?}", some.get(&mut ctx));
println!("some value (via Global API): {:?}", some.get(&mut store));
println!("other value (via `get_other`): {:?}", other_result);
println!("other value (via Global API): {:?}", other.get(&mut ctx));
println!("other value (via Global API): {:?}", other.get(&mut store));
assert_eq!(some_result, some.get(&mut ctx).f32().unwrap());
assert_eq!(other_result, other.get(&mut ctx).f32().unwrap());
assert_eq!(some_result, some.get(&mut store).f32().unwrap());
assert_eq!(other_result, other.get(&mut store).f32().unwrap());
println!("Setting global values...");
// Trying to set the value of a immutable global (`const`)
// will result in a `RuntimeError`.
let result = some.set(&mut ctx, Value::F32(42.0));
let result = some.set(&mut store, Value::F32(42.0));
assert_eq!(
result.expect_err("Expected an error").message(),
"Attempted to set an immutable global"
);
other.set(&mut ctx, Value::F32(21.0))?;
let other_result = other.get(&mut ctx);
other.set(&mut store, Value::F32(21.0))?;
let other_result = other.get(&mut store);
println!("other value after `set`: {:?}", other_result);
assert_eq!(other_result, Value::F32(21.0));
@ -106,11 +108,11 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let set_other: TypedFunction<f32, ()> = instance
.exports
.get_function("set_other")?
.native(&mut ctx)?;
set_other.call(&mut ctx, 42.0)?;
.native(&mut store)?;
set_other.call(&mut store, 42.0)?;
println!("other value (via Global API): {:?}", other.get(&mut ctx));
assert_eq!(other.get(&mut ctx), Value::F32(42.0));
println!("other value (via Global API): {:?}", other.get(&mut store));
assert_eq!(other.get(&mut store), Value::F32(42.0));
Ok(())
}

View File

@ -14,7 +14,7 @@
//!
//! Ready?
use wasmer::{imports, wat2wasm, Context, Instance, Module, Store, TypedFunction};
use wasmer::{imports, wat2wasm, FunctionEnv, Instance, Module, Store, TypedFunction};
use wasmer_compiler::Universal;
use wasmer_compiler_cranelift::Cranelift;
@ -39,8 +39,8 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
// Note that we don't need to specify the engine/compiler if we want to use
// the default provided by Wasmer.
// You can use `Store::default()` for that.
let store = Store::new_with_engine(&Universal::new(Cranelift::default()).engine());
let mut ctx = Context::new(&store, ());
let mut store = Store::new_with_engine(&Universal::new(Cranelift::default()).engine());
let mut env = FunctionEnv::new(&mut store, ());
println!("Compiling module...");
// Let's compile the Wasm module.
@ -51,7 +51,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("Instantiating module...");
// Let's instantiate the Wasm module.
let instance = Instance::new(&mut ctx, &module, &import_object)?;
let instance = Instance::new(&mut store, &module, &import_object)?;
// We now have an instance ready to be used.
//
@ -61,11 +61,13 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
// Here we are retrieving the exported function. We won't go into details here
// as the main focus of this example is to show how to create an instance out
// of a Wasm module and have basic interactions with it.
let add_one: TypedFunction<i32, i32> =
instance.exports.get_function("add_one")?.native(&mut ctx)?;
let add_one: TypedFunction<i32, i32> = instance
.exports
.get_function("add_one")?
.native(&mut store)?;
println!("Calling `add_one` function...");
let result = add_one.call(&mut ctx, 1)?;
let result = add_one.call(&mut store, 1)?;
println!("Results of `add_one`: {:?}", result);
assert_eq!(result, 2);

View File

@ -15,7 +15,9 @@
//! Ready?
use std::mem;
use wasmer::{imports, wat2wasm, Bytes, Context, Instance, Module, Pages, Store, TypedFunction};
use wasmer::{
imports, wat2wasm, Bytes, FunctionEnv, Instance, Module, Pages, Store, TypedFunction,
};
use wasmer_compiler::Universal;
use wasmer_compiler_cranelift::Cranelift;
@ -57,8 +59,8 @@ fn main() -> anyhow::Result<()> {
// Note that we don't need to specify the engine/compiler if we want to use
// the default provided by Wasmer.
// You can use `Store::default()` for that.
let store = Store::new_with_engine(&Universal::new(Cranelift::default()).engine());
let mut ctx = Context::new(&store, ());
let mut store = Store::new_with_engine(&Universal::new(Cranelift::default()).engine());
let mut env = FunctionEnv::new(&mut store, ());
println!("Compiling module...");
// Let's compile the Wasm module.
@ -69,17 +71,18 @@ fn main() -> anyhow::Result<()> {
println!("Instantiating module...");
// Let's instantiate the Wasm module.
let instance = Instance::new(&mut ctx, &module, &import_object)?;
let instance = Instance::new(&mut store, &module, &import_object)?;
// The module exports some utility functions, let's get them.
//
// These function will be used later in this example.
let mem_size: TypedFunction<(), i32> =
instance.exports.get_typed_function(&mut ctx, "mem_size")?;
let mem_size: TypedFunction<(), i32> = instance
.exports
.get_typed_function(&mut store, "mem_size")?;
let get_at: TypedFunction<i32, i32> =
instance.exports.get_typed_function(&mut ctx, "get_at")?;
instance.exports.get_typed_function(&mut store, "get_at")?;
let set_at: TypedFunction<(i32, i32), ()> =
instance.exports.get_typed_function(&mut ctx, "set_at")?;
instance.exports.get_typed_function(&mut store, "set_at")?;
let memory = instance.exports.get_memory("memory")?;
// We now have an instance ready to be used.
@ -93,15 +96,15 @@ fn main() -> anyhow::Result<()> {
// The size in bytes can be found either by querying its pages or by
// querying the memory directly.
println!("Querying memory size...");
assert_eq!(memory.size(&mut ctx), Pages::from(1));
assert_eq!(memory.size(&mut ctx).bytes(), Bytes::from(65536 as usize));
assert_eq!(memory.data_size(&mut ctx), 65536);
assert_eq!(memory.size(&mut store), Pages::from(1));
assert_eq!(memory.size(&mut store).bytes(), Bytes::from(65536 as usize));
assert_eq!(memory.data_size(&mut store), 65536);
// Sometimes, the guest module may also export a function to let you
// query the memory. Here we have a `mem_size` function, let's try it:
let result = mem_size.call(&mut ctx)?;
let result = mem_size.call(&mut store)?;
println!("Memory size: {:?}", result);
assert_eq!(Pages::from(result as u32), memory.size(&mut ctx));
assert_eq!(Pages::from(result as u32), memory.size(&mut store));
// Now that we know the size of our memory, it's time to see how wa
// can change this.
@ -110,9 +113,9 @@ fn main() -> anyhow::Result<()> {
// see how we can do that:
println!("Growing memory...");
// Here we are requesting two more pages for our memory.
memory.grow(&mut ctx, 2)?;
assert_eq!(memory.size(&mut ctx), Pages::from(3));
assert_eq!(memory.data_size(&mut ctx), 65536 * 3);
memory.grow(&mut store, 2)?;
assert_eq!(memory.size(&mut store), Pages::from(3));
assert_eq!(memory.data_size(&mut store), 65536 * 3);
// Now that we know how to query and adjust the size of the memory,
// let's see how wa can write to it or read from it.
@ -122,9 +125,9 @@ fn main() -> anyhow::Result<()> {
// addresses to write and read a value.
let mem_addr = 0x2220;
let val = 0xFEFEFFE;
set_at.call(&mut ctx, mem_addr, val)?;
set_at.call(&mut store, mem_addr, val)?;
let result = get_at.call(&mut ctx, mem_addr)?;
let result = get_at.call(&mut store, mem_addr)?;
println!("Value at {:#x?}: {:?}", mem_addr, result);
assert_eq!(result, val);
@ -133,9 +136,9 @@ fn main() -> anyhow::Result<()> {
let page_size = 0x1_0000;
let mem_addr = (page_size * 2) - mem::size_of_val(&val) as i32;
let val = 0xFEA09;
set_at.call(&mut ctx, mem_addr, val)?;
set_at.call(&mut store, mem_addr, val)?;
let result = get_at.call(&mut ctx, mem_addr)?;
let result = get_at.call(&mut store, mem_addr)?;
println!("Value at {:#x?}: {:?}", mem_addr, result);
assert_eq!(result, val);

View File

@ -18,7 +18,7 @@ use anyhow::bail;
use std::sync::Arc;
use wasmer::wasmparser::Operator;
use wasmer::CompilerConfig;
use wasmer::{imports, wat2wasm, Context, Instance, Module, Store, TypedFunction};
use wasmer::{imports, wat2wasm, FunctionEnv, Instance, Module, Store, TypedFunction};
use wasmer_compiler::Universal;
use wasmer_compiler_cranelift::Cranelift;
use wasmer_middlewares::{
@ -70,8 +70,8 @@ fn main() -> anyhow::Result<()> {
//
// We use our previously create compiler configuration
// with the Universal engine.
let store = Store::new_with_engine(&Universal::new(compiler_config).engine());
let mut ctx = Context::new(&store, ());
let mut store = Store::new_with_engine(&Universal::new(compiler_config).engine());
let mut env = FunctionEnv::new(&mut store, ());
println!("Compiling module...");
// Let's compile the Wasm module.
@ -82,17 +82,19 @@ fn main() -> anyhow::Result<()> {
println!("Instantiating module...");
// Let's instantiate the Wasm module.
let instance = Instance::new(&mut ctx, &module, &import_object)?;
let instance = Instance::new(&mut store, &module, &import_object)?;
// We now have an instance ready to be used.
//
// Our module exports a single `add_one` function. We want to
// measure the cost of executing this function.
let add_one: TypedFunction<i32, i32> =
instance.exports.get_function("add_one")?.native(&mut ctx)?;
let add_one: TypedFunction<i32, i32> = instance
.exports
.get_function("add_one")?
.native(&mut store)?;
println!("Calling `add_one` function once...");
add_one.call(&mut ctx, 1)?;
add_one.call(&mut store, 1)?;
// As you can see here, after the first call we have 6 remaining points.
//
@ -100,7 +102,7 @@ fn main() -> anyhow::Result<()> {
// * `local.get $value` is a `Operator::LocalGet` which costs 1 point;
// * `i32.const` is a `Operator::I32Const` which costs 1 point;
// * `i32.add` is a `Operator::I32Add` which costs 2 points.
let remaining_points_after_first_call = get_remaining_points(&mut ctx, &instance);
let remaining_points_after_first_call = get_remaining_points(&mut store, &instance);
assert_eq!(
remaining_points_after_first_call,
MeteringPoints::Remaining(6)
@ -112,11 +114,11 @@ fn main() -> anyhow::Result<()> {
);
println!("Calling `add_one` function twice...");
add_one.call(&mut ctx, 1)?;
add_one.call(&mut store, 1)?;
// We spent 4 more points with the second call.
// We have 2 remaining points.
let remaining_points_after_second_call = get_remaining_points(&mut ctx, &instance);
let remaining_points_after_second_call = get_remaining_points(&mut store, &instance);
assert_eq!(
remaining_points_after_second_call,
MeteringPoints::Remaining(2)
@ -131,7 +133,7 @@ fn main() -> anyhow::Result<()> {
// calling it a third time will fail: we already consume 8
// points, there are only two remaining.
println!("Calling `add_one` function a third time...");
match add_one.call(&mut ctx, 1) {
match add_one.call(&mut store, 1) {
Ok(result) => {
bail!(
"Expected failure while calling `add_one`, found: {}",
@ -142,7 +144,7 @@ fn main() -> anyhow::Result<()> {
println!("Calling `add_one` failed.");
// Because the last needed more than the remaining points, we should have an error.
let remaining_points = get_remaining_points(&mut ctx, &instance);
let remaining_points = get_remaining_points(&mut store, &instance);
match remaining_points {
MeteringPoints::Remaining(..) => {
@ -156,9 +158,9 @@ fn main() -> anyhow::Result<()> {
// Now let's see how we can set a new limit...
println!("Set new remaining points to 10");
let new_limit = 10;
set_remaining_points(&mut ctx, &instance, new_limit);
set_remaining_points(&mut store, &instance, new_limit);
let remaining_points = get_remaining_points(&mut ctx, &instance);
let remaining_points = get_remaining_points(&mut store, &instance);
assert_eq!(remaining_points, MeteringPoints::Remaining(new_limit));
println!("Remaining points: {:?}", remaining_points);

View File

@ -53,7 +53,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let engine = Dylib::new(compiler_config).target(target).engine();
// Create a store, that holds the engine.
let store = Store::new_with_engine(&engine);
let mut store = Store::new_with_engine(&engine);
println!("Compiling module...");
// Let's compile the Wasm module.

View File

@ -1,12 +1,12 @@
use wasmer::{
imports, wat2wasm, Context, ContextMut, Function, Instance, Module, Store, TableType, Type,
TypedFunction, Value,
imports, wat2wasm, Function, FunctionEnv, FunctionEnvMut, Instance, Module, Store, TableType,
Type, TypedFunction, Value,
};
use wasmer_compiler::Universal;
use wasmer_compiler_cranelift::Cranelift;
/// A function we'll call through a table.
fn host_callback(_ctx: ContextMut<()>, arg1: i32, arg2: i32) -> i32 {
fn host_callback(_ctx: FunctionEnvMut<()>, arg1: i32, arg2: i32) -> i32 {
arg1 + arg2
}
@ -52,23 +52,23 @@ fn main() -> anyhow::Result<()> {
)?;
// We set up our store with an engine and a compiler.
let store = Store::new_with_engine(&Universal::new(Cranelift::default()).engine());
let mut ctx = Context::new(&store, ());
let mut store = Store::new_with_engine(&Universal::new(Cranelift::default()).engine());
let mut env = FunctionEnv::new(&mut store, ());
// Then compile our Wasm.
let module = Module::new(&store, wasm_bytes)?;
let import_object = imports! {};
// And instantiate it with no imports.
let instance = Instance::new(&mut ctx, &module, &import_object)?;
let instance = Instance::new(&mut store, &module, &import_object)?;
// We get our function that calls (i32, i32) -> i32 functions via table.
// The first argument is the table index and the next 2 are the 2 arguments
// to be passed to the function found in the table.
let call_via_table: TypedFunction<(i32, i32, i32), i32> = instance
.exports
.get_typed_function(&mut ctx, "call_callback")?;
.get_typed_function(&mut store, "call_callback")?;
// And then call it with table index 1 and arguments 2 and 7.
let result = call_via_table.call(&mut ctx, 1, 2, 7)?;
let result = call_via_table.call(&mut store, 1, 2, 7)?;
// Because it's the default function, we expect it to double each number and
// then sum it, giving us 18.
assert_eq!(result, 18);
@ -76,9 +76,9 @@ fn main() -> anyhow::Result<()> {
// We then get the table from the instance.
let guest_table = instance.exports.get_table("__indirect_function_table")?;
// And demonstrate that it has the properties that we set in the Wasm.
assert_eq!(guest_table.size(&mut ctx), 3);
assert_eq!(guest_table.size(&mut store), 3);
assert_eq!(
guest_table.ty(&mut ctx),
guest_table.ty(&store),
TableType {
ty: Type::FuncRef,
minimum: 3,
@ -89,30 +89,30 @@ fn main() -> anyhow::Result<()> {
// == Setting elements in a table ==
// We first construct a `Function` over our host_callback.
let func = Function::new_native(&mut ctx, host_callback);
let func = Function::new_native(&mut store, &env, host_callback);
// And set table index 1 of that table to the host_callback `Function`.
guest_table.set(&mut ctx, 1, func.into())?;
guest_table.set(&mut store, 1, func.into())?;
// We then repeat the call from before but this time it will find the host function
// that we put at table index 1.
let result = call_via_table.call(&mut ctx, 1, 2, 7)?;
let result = call_via_table.call(&mut store, 1, 2, 7)?;
// And because our host function simply sums the numbers, we expect 9.
assert_eq!(result, 9);
// == Growing a table ==
// We again construct a `Function` over our host_callback.
let func = Function::new_native(&mut ctx, host_callback);
let func = Function::new_native(&mut store, &env, host_callback);
// And grow the table by 3 elements, filling in our host_callback in all the
// new elements of the table.
let previous_size = guest_table.grow(&mut ctx, 3, func.into())?;
let previous_size = guest_table.grow(&mut store, 3, func.into())?;
assert_eq!(previous_size, 3);
assert_eq!(guest_table.size(&mut ctx), 6);
assert_eq!(guest_table.size(&mut store), 6);
assert_eq!(
guest_table.ty(&mut ctx),
guest_table.ty(&store),
TableType {
ty: Type::FuncRef,
minimum: 3,
@ -121,8 +121,8 @@ fn main() -> anyhow::Result<()> {
);
// Now demonstrate that the function we grew the table with is actually in the table.
for table_index in 3..6 {
if let Value::FuncRef(Some(f)) = guest_table.get(&mut ctx, table_index as _).unwrap() {
let result = f.call(&mut ctx, &[Value::I32(1), Value::I32(9)])?;
if let Value::FuncRef(Some(f)) = guest_table.get(&mut store, table_index as _).unwrap() {
let result = f.call(&mut store, &[Value::I32(1), Value::I32(9)])?;
assert_eq!(result[0], Value::I32(10));
} else {
panic!("expected to find funcref in table!");
@ -130,26 +130,26 @@ fn main() -> anyhow::Result<()> {
}
// Call function at index 0 to show that it's still the same.
let result = call_via_table.call(&mut ctx, 0, 2, 7)?;
let result = call_via_table.call(&mut store, 0, 2, 7)?;
assert_eq!(result, 18);
// Now overwrite index 0 with our host_callback.
let func = Function::new_native(&mut ctx, host_callback);
guest_table.set(&mut ctx, 0, func.into())?;
let func = Function::new_native(&mut store, &env, host_callback);
guest_table.set(&mut store, 0, func.into())?;
// And verify that it does what we expect.
let result = call_via_table.call(&mut ctx, 0, 2, 7)?;
let result = call_via_table.call(&mut store, 0, 2, 7)?;
assert_eq!(result, 9);
// Now demonstrate that the host and guest see the same table and that both
// get the same result.
for table_index in 3..6 {
if let Value::FuncRef(Some(f)) = guest_table.get(&mut ctx, table_index as _).unwrap() {
let result = f.call(&mut ctx, &[Value::I32(1), Value::I32(9)])?;
if let Value::FuncRef(Some(f)) = guest_table.get(&mut store, table_index as _).unwrap() {
let result = f.call(&mut store, &[Value::I32(1), Value::I32(9)])?;
assert_eq!(result[0], Value::I32(10));
} else {
panic!("expected to find funcref in table!");
}
let result = call_via_table.call(&mut ctx, table_index, 1, 9)?;
let result = call_via_table.call(&mut store, table_index, 1, 9)?;
assert_eq!(result, 10);
}

View File

@ -3,8 +3,8 @@ use std::ptr::NonNull;
use wasmer::{
imports,
vm::{self, MemoryError, MemoryStyle, TableStyle, VMMemoryDefinition, VMTableDefinition},
wat2wasm, BaseTunables, Context, Instance, Memory, MemoryType, Module, Pages, Store, TableType,
Target, Tunables,
wat2wasm, BaseTunables, FunctionEnv, Instance, Memory, MemoryType, Module, Pages, Store,
TableType, Target, Tunables,
};
use wasmer_compiler::Universal;
use wasmer_compiler_cranelift::Cranelift;
@ -145,8 +145,8 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let tunables = LimitingTunables::new(base, Pages(24));
// Create a store, that holds the engine and our custom tunables
let store = Store::new_with_tunables(&engine, tunables);
let mut ctx = Context::new(&store, ());
let mut store = Store::new_with_tunables(&engine, tunables);
let mut env = FunctionEnv::new(&mut store, ());
println!("Compiling module...");
let module = Module::new(&store, wasm_bytes)?;
@ -155,7 +155,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let import_object = imports! {};
// Now at this point, our custom tunables are used
let instance = Instance::new(&mut ctx, &module, &import_object)?;
let instance = Instance::new(&mut store, &module, &import_object)?;
// Check what happened
let mut memories: Vec<Memory> = instance
@ -168,7 +168,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let first_memory = memories.pop().unwrap();
println!("Memory of this instance: {:?}", first_memory);
assert_eq!(first_memory.ty(&mut ctx).maximum.unwrap(), Pages(24));
assert_eq!(first_memory.ty(&store).maximum.unwrap(), Pages(24));
Ok(())
}

View File

@ -15,7 +15,7 @@
//!
//! Ready?
use wasmer::{AsContextMut, Context, Instance, Module, Store};
use wasmer::{FunctionEnv, Instance, Module, Store};
use wasmer_compiler::Universal;
use wasmer_compiler_cranelift::Cranelift;
use wasmer_wasi::WasiState;
@ -32,7 +32,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
// Note that we don't need to specify the engine/compiler if we want to use
// the default provided by Wasmer.
// You can use `Store::default()` for that.
let store = Store::new_with_engine(&Universal::new(Cranelift::default()).engine());
let mut store = Store::new_with_engine(&Universal::new(Cranelift::default()).engine());
println!("Compiling module...");
// Let's compile the Wasm module.
@ -43,25 +43,23 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut wasi_env = WasiState::new("hello")
// .args(&["world"])
// .env("KEY", "Value")
.finalize()?;
// And now the context,using the newly created WasiEnv
let mut ctx = Context::new(&store, wasi_env.clone());
.finalize(&mut store)?;
println!("Instantiating module with WASI imports...");
// Then, we get the import object related to our WASI
// and attach it to the Wasm instance.
let import_object = wasi_env.import_object(&mut ctx.as_context_mut(), &module)?;
let instance = Instance::new(&mut ctx, &module, &import_object)?;
let import_object = wasi_env.import_object(&mut store, &module)?;
let instance = Instance::new(&mut store, &module, &import_object)?;
println!("Attach WASI memory...");
// Attach the memory export
let memory = instance.exports.get_memory("memory")?;
ctx.data_mut().set_memory(memory.clone());
wasi_env.data_mut(&mut store).set_memory(memory.clone());
println!("Call WASI `_start` function...");
// And we just call the `_start` function!
let start = instance.exports.get_function("_start")?;
start.call(&mut ctx, &[])?;
start.call(&mut store, &[])?;
Ok(())
}

View File

@ -12,7 +12,7 @@
//! Ready?
use std::io::{Read, Write};
use wasmer::{AsContextMut, Context, Instance, Module, Store};
use wasmer::{FunctionEnv, Instance, Module, Store};
use wasmer_compiler::Universal;
use wasmer_compiler_cranelift::Cranelift;
use wasmer_wasi::{Pipe, WasiState};
@ -29,7 +29,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
// Note that we don't need to specify the engine/compiler if we want to use
// the default provided by Wasmer.
// You can use `Store::default()` for that.
let store = Store::new_with_engine(&Universal::new(Cranelift::default()).engine());
let mut store = Store::new_with_engine(&Universal::new(Cranelift::default()).engine());
println!("Compiling module...");
// Let's compile the Wasm module.
@ -42,19 +42,18 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut wasi_env = WasiState::new("hello")
.stdin(Box::new(input.clone()))
.stdout(Box::new(output.clone()))
.finalize()?;
let mut ctx = Context::new(&store, wasi_env.clone());
.finalize(&mut store)?;
println!("Instantiating module with WASI imports...");
// Then, we get the import object related to our WASI
// and attach it to the Wasm instance.
let import_object = wasi_env.import_object(&mut ctx.as_context_mut(), &module)?;
let instance = Instance::new(&mut ctx, &module, &import_object)?;
let import_object = wasi_env.import_object(&mut store, &module)?;
let instance = Instance::new(&mut store, &module, &import_object)?;
println!("Attach WASI memory...");
// Attach the memory export
let memory = instance.exports.get_memory("memory")?;
ctx.data_mut().set_memory(memory.clone());
wasi_env.data_mut(&mut store).set_memory(memory.clone());
let msg = "racecar go zoom";
println!("Writing \"{}\" to the WASI stdin...", msg);
@ -64,7 +63,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("Call WASI `_start` function...");
// And we just call the `_start` function!
let start = instance.exports.get_function("_start")?;
start.call(&mut ctx, &[])?;
start.call(&mut store, &[])?;
println!("Reading from the WASI stdout...");

View File

@ -24,7 +24,7 @@ impl Config for NoImportsConfig {
}
fn compile_and_compare(name: &str, engine: impl Engine, wasm: &[u8]) {
let store = Store::new_with_engine(&engine);
let mut store = Store::new_with_engine(&engine);
// compile for first time
let module = Module::new(&store, wasm).unwrap();

View File

@ -48,7 +48,7 @@ impl std::fmt::Debug for WasmSmithModule {
#[cfg(feature = "singlepass")]
fn maybe_instantiate_singlepass(wasm_bytes: &[u8]) -> Result<Option<Instance>> {
let compiler = Singlepass::default();
let store = Store::new_with_engine(&Universal::new(compiler).engine());
let mut store = Store::new_with_engine(&Universal::new(compiler).engine());
let module = Module::new(&store, &wasm_bytes);
let module = match module {
Ok(m) => m,
@ -69,7 +69,7 @@ fn maybe_instantiate_cranelift(wasm_bytes: &[u8]) -> Result<Option<Instance>> {
let mut compiler = Cranelift::default();
compiler.canonicalize_nans(true);
compiler.enable_verifier();
let store = Store::new_with_engine(&Universal::new(compiler).engine());
let mut store = Store::new_with_engine(&Universal::new(compiler).engine());
let module = Module::new(&store, &wasm_bytes)?;
let instance = Instance::new(&module, &imports! {})?;
Ok(Some(instance))
@ -80,7 +80,7 @@ fn maybe_instantiate_llvm(wasm_bytes: &[u8]) -> Result<Option<Instance>> {
let mut compiler = LLVM::default();
compiler.canonicalize_nans(true);
compiler.enable_verifier();
let store = Store::new_with_engine(&Universal::new(compiler).engine());
let mut store = Store::new_with_engine(&Universal::new(compiler).engine());
let module = Module::new(&store, &wasm_bytes)?;
let instance = Instance::new(&module, &imports! {})?;
Ok(Some(instance))

View File

@ -56,7 +56,7 @@ fuzz_target!(|module: WasmSmithModule| {
compiler.enable_verifier();
let metering = Arc::new(Metering::new(10, cost));
compiler.push_middleware(metering);
let store = Store::new_with_engine(&Universal::new(compiler).engine());
let mut store = Store::new_with_engine(&Universal::new(compiler).engine());
let module = Module::new(&store, &wasm_bytes).unwrap();
match Instance::new(&module, &imports! {}) {
Ok(_) => {}

View File

@ -42,7 +42,7 @@ fuzz_target!(|module: WasmSmithModule| {
let mut compiler = Cranelift::default();
compiler.canonicalize_nans(true);
compiler.enable_verifier();
let store = Store::new_with_engine(&Universal::new(compiler).engine());
let mut store = Store::new_with_engine(&Universal::new(compiler).engine());
let module = Module::new(&store, &wasm_bytes).unwrap();
match Instance::new(&module, &imports! {}) {
Ok(_) => {}

View File

@ -42,7 +42,7 @@ fuzz_target!(|module: WasmSmithModule| {
let mut compiler = LLVM::default();
compiler.canonicalize_nans(true);
compiler.enable_verifier();
let store = Store::new_with_engine(&Universal::new(compiler).engine());
let mut store = Store::new_with_engine(&Universal::new(compiler).engine());
let module = Module::new(&store, &wasm_bytes).unwrap();
match Instance::new(&module, &imports! {}) {
Ok(_) => {}

View File

@ -40,7 +40,7 @@ fuzz_target!(|module: WasmSmithModule| {
}
let compiler = Singlepass::default();
let store = Store::new_with_engine(&Universal::new(compiler).engine());
let mut store = Store::new_with_engine(&Universal::new(compiler).engine());
let module = Module::new(&store, &wasm_bytes);
let module = match module {
Ok(m) => m,

View File

@ -41,6 +41,10 @@ target-lexicon = { version = "0.12.2", default-features = false }
wasmer-compiler-singlepass = { path = "../compiler-singlepass", version = "=2.3.0", optional = true }
wasmer-compiler-cranelift = { path = "../compiler-cranelift", version = "=2.3.0", optional = true }
wasmer-compiler-llvm = { path = "../compiler-llvm", version = "=2.3.0", optional = true }
wasm-bindgen = { version = "0.2.74", optional = true }
js-sys = { version = "0.3.51", optional = true }
# - Mandatory dependencies for `sys` on Windows.
[target.'cfg(all(not(target_arch = "wasm32"), target_os = "windows"))'.dependencies]
winapi = "0.3"
@ -79,6 +83,7 @@ maintenance = { status = "actively-developed" }
[features]
default = ["sys-default"]
# default = ["js-default"]
std = []
core = ["hashbrown"]
@ -100,7 +105,7 @@ default-llvm = ["default-compiler", "llvm"]
# - Engines.
engine = ["sys"]
universal = [
"engine",
"engine", "wasmer-compiler/universal_engine"
]
default-engine = []
default-universal = [
@ -111,7 +116,7 @@ default-universal = [
jit = ["universal"]
# Features for `js`.
js = []
js = ["wasm-bindgen", "js-sys"]
js-default = ["js", "std", "wasm-types-polyfill"]
wasm-types-polyfill = ["js", "wasmparser"]

View File

@ -25,7 +25,7 @@ fn main() -> anyhow::Result<()> {
i32.add))
"#;
let store = Store::default();
let mut store = Store::default();
let module = Module::new(&store, &module_wat)?;
// The module doesn't import anything, so we create an empty import object.
let import_object = imports! {};

View File

@ -1,449 +0,0 @@
#![allow(dead_code)]
use crate::Store;
/// We require the context to have a fixed memory address for its lifetime since
/// various bits of the VM have raw pointers that point back to it. Hence we
/// wrap the actual context in a box.
pub(crate) struct ContextInner<T> {
pub(crate) objects: ContextObjects,
pub(crate) store: Store,
pub(crate) data: T,
}
/// A context containing a set of WebAssembly instances, along with host state.
///
/// All WebAssembly instances must exist within a context. In the majority of
/// cases each instance will have its own context, but it is possible to have
/// multiple instances in a context when these instances need to interact with
/// each other, for example sharing a memory between instances or calling
/// functions in another instance.
///
/// The lifetimes of run-time WebAssembly objects, notably [`Instance`],
/// [`Memory`], [`Global`], [`Table`] and [`Function`] is tied to a context:
/// the backing memory for these objects is only freed when the context is
/// freed.
///
/// The `T` generic parameter allows arbitrary data to be attached to a context.
/// This data can be accessed using the [`Context::data`] and
/// [`Context::data_mut`] methods. Host functions defined using
/// [`Function::new`] and [`Function::new_native`] receive
/// a reference to the context when they are called.
pub struct Context<T> {
pub(crate) inner: Box<ContextInner<T>>,
}
impl<T> Context<T> {
/// Creates a new context with the given host state.
// TODO: Eliminate the Store type and move its functionality into Engine.
pub fn new(store: &Store, data: T) -> Self {
Self {
inner: Box::new(ContextInner {
objects: Default::default(),
store: store.clone(),
data,
}),
}
}
/// Returns a reference to the host state in this context.
pub fn data(&self) -> &T {
&self.inner.data
}
/// Returns a mutable- reference to the host state in this context.
pub fn data_mut(&mut self) -> &mut T {
&mut self.inner.data
}
/// Drops the context and returns the host state that was stored in it.
pub fn into_data(self) -> T {
self.inner.data
}
/// Returns a reference to the `Store` of this context.
pub fn store(&self) -> &Store {
&self.inner.store
}
}
/// A temporary handle to a [`Context`].
pub struct ContextRef<'a, T: 'a> {
inner: &'a ContextInner<T>,
}
impl<'a, T> ContextRef<'a, T> {
/// Returns a reference to the host state in this context.
pub fn data(&self) -> &'a T {
&self.inner.data
}
/// Returns a reference to the `Store` of this context.
pub fn store(&self) -> &Store {
&self.inner.store
}
pub(crate) fn objects(&self) -> &'a ContextObjects {
&self.inner.objects
}
}
/// A temporary handle to a [`Context`].
pub struct ContextMut<'a, T: 'a> {
inner: &'a mut ContextInner<T>,
}
impl<T> ContextMut<'_, T> {
/// Returns a reference to the host state in this context.
pub fn data(&self) -> &T {
&self.inner.data
}
/// Returns a mutable- reference to the host state in this context.
pub fn data_mut(&mut self) -> &mut T {
&mut self.inner.data
}
pub(crate) fn objects_mut(&mut self) -> &mut ContextObjects {
&mut self.inner.objects
}
/// Returns a reference to the `Store` of this context.
pub fn store(&self) -> &Store {
&self.inner.store
}
/// Returns the raw pointer of the context
pub(crate) fn as_raw(&self) -> *mut ContextInner<T> {
self.inner as *const ContextInner<T> as *mut ContextInner<T>
}
/// Constructs the context from the raw pointer
pub(crate) unsafe fn from_raw(raw: *mut ContextInner<T>) -> Self {
Self { inner: &mut *raw }
}
}
/// Helper trait for a value that is convertible to a [`ContextRef`].
pub trait AsContextRef {
/// Host state associated with the [`Context`].
type Data;
/// Returns a `ContextRef` pointing to the underlying context.
fn as_context_ref(&self) -> ContextRef<'_, Self::Data>;
}
/// Helper trait for a value that is convertible to a [`ContextMut`].
pub trait AsContextMut: AsContextRef {
/// Returns a `ContextMut` pointing to the underlying context.
fn as_context_mut(&mut self) -> ContextMut<'_, Self::Data>;
}
impl<T> AsContextRef for Context<T> {
type Data = T;
fn as_context_ref(&self) -> ContextRef<'_, Self::Data> {
ContextRef { inner: &self.inner }
}
}
impl<T> AsContextMut for Context<T> {
fn as_context_mut(&mut self) -> ContextMut<'_, Self::Data> {
ContextMut {
inner: &mut self.inner,
}
}
}
impl<T> AsContextRef for ContextRef<'_, T> {
type Data = T;
fn as_context_ref(&self) -> ContextRef<'_, Self::Data> {
ContextRef { inner: self.inner }
}
}
impl<T> AsContextRef for ContextMut<'_, T> {
type Data = T;
fn as_context_ref(&self) -> ContextRef<'_, Self::Data> {
ContextRef { inner: self.inner }
}
}
impl<T> AsContextMut for ContextMut<'_, T> {
fn as_context_mut(&mut self) -> ContextMut<'_, Self::Data> {
ContextMut { inner: self.inner }
}
}
impl<T: AsContextRef> AsContextRef for &'_ T {
type Data = T::Data;
fn as_context_ref(&self) -> ContextRef<'_, Self::Data> {
T::as_context_ref(*self)
}
}
impl<T: AsContextRef> AsContextRef for &'_ mut T {
type Data = T::Data;
fn as_context_ref(&self) -> ContextRef<'_, Self::Data> {
T::as_context_ref(*self)
}
}
impl<T: AsContextMut> AsContextMut for &'_ mut T {
fn as_context_mut(&mut self) -> ContextMut<'_, Self::Data> {
T::as_context_mut(*self)
}
}
pub use objects::*;
mod objects {
use crate::js::export::{VMFunction, VMGlobal, VMMemory, VMTable};
use std::{
cell::UnsafeCell,
fmt,
marker::PhantomData,
num::{NonZeroU64, NonZeroUsize},
ptr::NonNull,
sync::atomic::{AtomicU64, Ordering},
};
/// Unique ID to identify a context.
///
/// Every handle to an object managed by a context also contains the ID of the
/// context. This is used to check that a handle is always used with the
/// correct context.
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub struct ContextId(NonZeroU64);
impl Default for ContextId {
// Allocates a unique ID for a new context.
fn default() -> Self {
// No overflow checking is needed here: overflowing this would take
// thousands of years.
static NEXT_ID: AtomicU64 = AtomicU64::new(1);
Self(NonZeroU64::new(NEXT_ID.fetch_add(1, Ordering::Relaxed)).unwrap())
}
}
/// Trait to represent an object managed by a context. This is implemented on
/// the VM types managed by the context.
pub trait ContextObject: Sized {
fn list(ctx: &ContextObjects) -> &Vec<Self>;
fn list_mut(ctx: &mut ContextObjects) -> &mut Vec<Self>;
}
macro_rules! impl_context_object {
($($field:ident => $ty:ty,)*) => {
$(
impl ContextObject for $ty {
fn list(ctx: &ContextObjects) -> &Vec<Self> {
&ctx.$field
}
fn list_mut(ctx: &mut ContextObjects) -> &mut Vec<Self> {
&mut ctx.$field
}
}
)*
};
}
impl_context_object! {
functions => VMFunction,
tables => VMTable,
globals => VMGlobal,
memories => VMMemory,
instances => js_sys::WebAssembly::Instance,
}
/// Set of objects managed by a context.
#[derive(Default)]
pub struct ContextObjects {
id: ContextId,
memories: Vec<VMMemory>,
tables: Vec<VMTable>,
globals: Vec<VMGlobal>,
functions: Vec<VMFunction>,
instances: Vec<js_sys::WebAssembly::Instance>,
}
impl ContextObjects {
/// Returns the ID of this context.
pub fn id(&self) -> ContextId {
self.id
}
/// Returns a pair of mutable references from two handles.
///
/// Panics if both handles point to the same object.
pub fn get_2_mut<T: ContextObject>(
&mut self,
a: InternalContextHandle<T>,
b: InternalContextHandle<T>,
) -> (&mut T, &mut T) {
assert_ne!(a.index(), b.index());
let list = T::list_mut(self);
if a.index() < b.index() {
let (low, high) = list.split_at_mut(b.index());
(&mut low[a.index()], &mut high[0])
} else {
let (low, high) = list.split_at_mut(a.index());
(&mut high[0], &mut low[a.index()])
}
}
}
/// Handle to an object managed by a context.
///
/// Internally this is just an integer index into a context. A reference to the
/// context must be passed in separately to access the actual object.
pub struct ContextHandle<T> {
id: ContextId,
internal: InternalContextHandle<T>,
}
impl<T> core::cmp::PartialEq for ContextHandle<T> {
fn eq(&self, other: &Self) -> bool {
self.id == other.id
}
}
impl<T> Clone for ContextHandle<T> {
fn clone(&self) -> Self {
Self {
id: self.id,
internal: self.internal,
}
}
}
impl<T: ContextObject> fmt::Debug for ContextHandle<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ContextHandle")
.field("id", &self.id)
.field("internal", &self.internal.index())
.finish()
}
}
impl<T: ContextObject> ContextHandle<T> {
/// Moves the given object into a context and returns a handle to it.
pub fn new(ctx: &mut ContextObjects, val: T) -> Self {
Self {
id: ctx.id,
internal: InternalContextHandle::new(ctx, val),
}
}
/// Returns a reference to the object that this handle points to.
pub fn get<'a>(&self, ctx: &'a ContextObjects) -> &'a T {
assert_eq!(self.id, ctx.id, "object used with the wrong context");
self.internal.get(ctx)
}
/// Returns a mutable reference to the object that this handle points to.
pub fn get_mut<'a>(&self, ctx: &'a mut ContextObjects) -> &'a mut T {
assert_eq!(self.id, ctx.id, "object used with the wrong context");
self.internal.get_mut(ctx)
}
/// Returns the internal handle contains within this handle.
pub fn internal_handle(&self) -> InternalContextHandle<T> {
self.internal
}
/// Returns the ID of the context associated with the handle.
pub fn context_id(&self) -> ContextId {
self.id
}
/// Constructs a `ContextHandle` from a `ContextId` and an `InternalContextHandle`.
///
/// # Safety
/// Handling `InternalContextHandle` values is unsafe because they do not track context ID.
pub unsafe fn from_internal(id: ContextId, internal: InternalContextHandle<T>) -> Self {
Self { id, internal }
}
}
/// Internal handle to an object owned by the current context.
///
/// Unlike `ContextHandle` this does not track the context ID: it is only
/// intended to be used within objects already owned by a context.
#[repr(transparent)]
pub struct InternalContextHandle<T> {
// Use a NonZero here to reduce the size of Option<InternalContextHandle>.
idx: NonZeroUsize,
marker: PhantomData<fn() -> T>,
}
impl<T> Clone for InternalContextHandle<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T> Copy for InternalContextHandle<T> {}
impl<T> fmt::Debug for InternalContextHandle<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("InternalContextHandle")
.field("idx", &self.idx)
.finish()
}
}
impl<T> PartialEq for InternalContextHandle<T> {
fn eq(&self, other: &Self) -> bool {
self.idx == other.idx
}
}
impl<T> Eq for InternalContextHandle<T> {}
impl<T: ContextObject> InternalContextHandle<T> {
/// Moves the given object into a context and returns a handle to it.
pub fn new(ctx: &mut ContextObjects, val: T) -> Self {
let list = T::list_mut(ctx);
let idx = NonZeroUsize::new(list.len() + 1).unwrap();
list.push(val);
Self {
idx,
marker: PhantomData,
}
}
/// Returns a reference to the object that this handle points to.
pub fn get<'a>(&self, ctx: &'a ContextObjects) -> &'a T {
&T::list(ctx)[self.idx.get() - 1]
}
/// Returns a mutable reference to the object that this handle points to.
pub fn get_mut<'a>(&self, ctx: &'a mut ContextObjects) -> &'a mut T {
&mut T::list_mut(ctx)[self.idx.get() - 1]
}
pub(crate) fn index(&self) -> usize {
self.idx.get()
}
pub(crate) fn from_index(idx: usize) -> Option<Self> {
NonZeroUsize::new(idx).map(|idx| Self {
idx,
marker: PhantomData,
})
}
}
/// Data used by the generated code is generally located inline within the
/// `VMContext` for items defined in an instance. Host-defined objects are
/// allocated separately and owned directly by the context.
pub enum MaybeInstanceOwned<T> {
/// The data is owned here.
Host(Box<UnsafeCell<T>>),
/// The data is stored inline in the `VMContext` of an instance.
Instance(NonNull<T>),
}
impl<T> MaybeInstanceOwned<T> {
/// Returns underlying pointer to the VM data.
pub fn as_ptr(&self) -> NonNull<T> {
match self {
MaybeInstanceOwned::Host(p) => unsafe { NonNull::new_unchecked(p.get()) },
MaybeInstanceOwned::Instance(p) => *p,
}
}
}
}

View File

@ -163,10 +163,10 @@ pub enum InstantiationError {
#[cfg_attr(feature = "std", error(transparent))]
Start(RuntimeError),
/// Import from a different [`Context`].
/// This error occurs when an import from a different context is used.
#[cfg_attr(feature = "std", error("cannot mix imports from different contexts"))]
BadContext,
/// Import from a different [`Store`].
/// This error occurs when an import from a different store is used.
#[cfg_attr(feature = "std", error("cannot mix imports from different stores"))]
DifferentStores,
/// A generic error occured while invoking API functions
#[cfg_attr(feature = "std", error(transparent))]

View File

@ -1,5 +1,5 @@
use crate::js::context::{AsContextMut, AsContextRef, InternalContextHandle};
use crate::js::error::WasmError;
use crate::js::store::{AsStoreMut, AsStoreRef, InternalStoreHandle};
use crate::js::wasm_bindgen_polyfill::Global;
use js_sys::Function;
use js_sys::WebAssembly::{Memory, Table};
@ -85,36 +85,33 @@ impl fmt::Debug for VMFunction {
#[derive(Debug, Clone)]
pub enum Export {
/// A function export value.
Function(InternalContextHandle<VMFunction>),
Function(InternalStoreHandle<VMFunction>),
/// A table export value.
Table(InternalContextHandle<VMTable>),
Table(InternalStoreHandle<VMTable>),
/// A memory export value.
Memory(InternalContextHandle<VMMemory>),
Memory(InternalStoreHandle<VMMemory>),
/// A global export value.
Global(InternalContextHandle<VMGlobal>),
Global(InternalStoreHandle<VMGlobal>),
}
impl Export {
/// Return the export as a `JSValue`.
pub fn as_jsvalue<'context>(&self, ctx: &'context impl AsContextRef) -> &'context JsValue {
pub fn as_jsvalue<'context>(&self, ctx: &'context impl AsStoreRef) -> &'context JsValue {
match self {
Self::Memory(js_wasm_memory) => js_wasm_memory
.get(ctx.as_context_ref().objects())
.get(ctx.as_store_ref().objects())
.memory
.as_ref(),
Self::Function(js_func) => js_func
.get(ctx.as_context_ref().objects())
.function
.as_ref(),
Self::Function(js_func) => js_func.get(ctx.as_store_ref().objects()).function.as_ref(),
Self::Table(js_wasm_table) => js_wasm_table
.get(ctx.as_context_ref().objects())
.get(ctx.as_store_ref().objects())
.table
.as_ref(),
Self::Global(js_wasm_global) => js_wasm_global
.get(ctx.as_context_ref().objects())
.get(ctx.as_store_ref().objects())
.global
.as_ref(),
}
@ -123,14 +120,14 @@ impl Export {
/// Convert a `JsValue` into an `Export` within a given `Context`.
pub fn from_js_value(
val: JsValue,
ctx: &mut impl AsContextMut,
ctx: &mut impl AsStoreMut,
extern_type: ExternType,
) -> Result<Self, WasmError> {
match extern_type {
ExternType::Memory(memory_type) => {
if val.is_instance_of::<Memory>() {
Ok(Self::Memory(InternalContextHandle::new(
&mut ctx.as_context_mut().objects_mut(),
Ok(Self::Memory(InternalStoreHandle::new(
&mut ctx.objects_mut(),
VMMemory::new(val.unchecked_into::<Memory>(), memory_type),
)))
} else {
@ -145,8 +142,8 @@ impl Export {
}
ExternType::Global(global_type) => {
if val.is_instance_of::<Global>() {
Ok(Self::Global(InternalContextHandle::new(
&mut ctx.as_context_mut().objects_mut(),
Ok(Self::Global(InternalStoreHandle::new(
&mut ctx.objects_mut(),
VMGlobal::new(val.unchecked_into::<Global>(), global_type),
)))
} else {
@ -155,8 +152,8 @@ impl Export {
}
ExternType::Function(function_type) => {
if val.is_instance_of::<Function>() {
Ok(Self::Function(InternalContextHandle::new(
&mut ctx.as_context_mut().objects_mut(),
Ok(Self::Function(InternalStoreHandle::new(
&mut ctx.objects_mut(),
VMFunction::new(val.unchecked_into::<Function>(), function_type),
)))
} else {
@ -165,8 +162,8 @@ impl Export {
}
ExternType::Table(table_type) => {
if val.is_instance_of::<Table>() {
Ok(Self::Table(InternalContextHandle::new(
&mut ctx.as_context_mut().objects_mut(),
Ok(Self::Table(InternalStoreHandle::new(
&mut ctx.objects_mut(),
VMTable::new(val.unchecked_into::<Table>(), table_type),
)))
} else {

View File

@ -1,6 +1,6 @@
use crate::js::context::AsContextRef;
use crate::js::externals::{Extern, Function, Global, Memory, Table};
use crate::js::native::TypedFunction;
use crate::js::store::AsStoreRef;
use crate::js::WasmTypeList;
use indexmap::IndexMap;
use std::fmt;
@ -18,7 +18,7 @@ use thiserror::Error;
///
/// ```should_panic
/// # use wasmer::{imports, wat2wasm, Function, Instance, Module, Store, Type, Value, ExportError};
/// # let store = Store::default();
/// # let mut store = Store::default();
/// # let wasm_bytes = wat2wasm(r#"
/// # (module
/// # (global $one (export "glob") f32 (f32.const 1)))
@ -35,7 +35,7 @@ use thiserror::Error;
///
/// ```should_panic
/// # use wasmer::{imports, wat2wasm, Function, Instance, Module, Store, Type, Value, ExportError};
/// # let store = Store::default();
/// # let mut store = Store::default();
/// # let wasm_bytes = wat2wasm("(module)".as_bytes()).unwrap();
/// # let module = Module::new(&store, wasm_bytes).unwrap();
/// # let import_object = imports! {};
@ -141,7 +141,7 @@ impl Exports {
/// Get an export as a `TypedFunction`.
pub fn get_native_function<Args, Rets>(
&self,
ctx: &impl AsContextRef,
ctx: &impl AsStoreRef,
name: &str,
) -> Result<TypedFunction<Args, Rets>, ExportError>
where
@ -154,7 +154,7 @@ impl Exports {
/// Get an export as a `TypedFunction`.
pub fn get_typed_function<Args, Rets>(
&self,
ctx: &impl AsContextRef,
store: &impl AsStoreRef,
name: &str,
) -> Result<TypedFunction<Args, Rets>, ExportError>
where
@ -162,14 +162,14 @@ impl Exports {
Rets: WasmTypeList,
{
self.get_function(name)?
.native(ctx)
.native(store)
.map_err(|_| ExportError::IncompatibleType)
}
/// Hack to get this working with nativefunc too
pub fn get_with_generics<'a, T, Args, Rets>(
&'a self,
ctx: &impl AsContextRef,
ctx: &impl AsStoreRef,
name: &str,
) -> Result<T, ExportError>
where
@ -187,7 +187,7 @@ impl Exports {
/// This is useful for passing data into Context data, for example.
pub fn get_with_generics_weak<'a, T, Args, Rets>(
&'a self,
ctx: &impl AsContextRef,
ctx: &impl AsStoreRef,
name: &str,
) -> Result<T, ExportError>
where
@ -334,7 +334,7 @@ pub trait Exportable<'a>: Sized {
pub trait ExportableWithGenerics<'a, Args: WasmTypeList, Rets: WasmTypeList>: Sized {
/// Get an export with the given generics.
fn get_self_from_extern_with_generics(
ctx: &impl AsContextRef,
ctx: &impl AsStoreRef,
_extern: &'a Extern,
) -> Result<Self, ExportError>;
}
@ -343,7 +343,7 @@ pub trait ExportableWithGenerics<'a, Args: WasmTypeList, Rets: WasmTypeList>: Si
/// with empty `Args` and `Rets`.
impl<'a, T: Exportable<'a> + Clone + 'static> ExportableWithGenerics<'a, (), ()> for T {
fn get_self_from_extern_with_generics(
_ctx: &impl AsContextRef,
_ctx: &impl AsStoreRef,
_extern: &'a Extern,
) -> Result<Self, ExportError> {
T::get_self_from_extern(_extern).map(|i| i.clone())

View File

@ -1,14 +1,13 @@
pub use self::inner::{FromToNativeWasmType, HostFunction, WasmTypeList};
use crate::js::context::{
AsContextMut, AsContextRef, ContextHandle, ContextMut, InternalContextHandle,
};
use crate::js::exports::{ExportError, Exportable};
use crate::js::externals::Extern;
use crate::js::function_env::FunctionEnvMut;
use crate::js::store::{AsStoreMut, AsStoreRef, InternalStoreHandle, StoreHandle, StoreMut};
use crate::js::types::{param_from_js, AsJs}; /* ValFuncRef */
use crate::js::FunctionType;
use crate::js::RuntimeError;
use crate::js::TypedFunction;
use crate::js::Value;
use crate::js::{FunctionEnv, FunctionType};
use js_sys::{Array, Function as JSFunction};
use std::iter::FromIterator;
use wasm_bindgen::prelude::*;
@ -58,7 +57,7 @@ fn results_to_js_array(values: &[Value]) -> Array {
/// [Closures as host functions tracking issue](https://github.com/wasmerio/wasmer/issues/1840)
#[derive(Clone, PartialEq)]
pub struct Function {
pub(crate) handle: ContextHandle<VMFunction>,
pub(crate) handle: StoreHandle<VMFunction>,
}
impl Function {
@ -71,7 +70,7 @@ impl Function {
///
/// ```
/// # use wasmer::{Function, FunctionType, Type, Store, Value};
/// # let store = Store::default();
/// # let mut store = Store::default();
/// #
/// let signature = FunctionType::new(vec![Type::I32, Type::I32], vec![Type::I32]);
///
@ -85,7 +84,7 @@ impl Function {
///
/// ```
/// # use wasmer::{Function, FunctionType, Type, Store, Value};
/// # let store = Store::default();
/// # let mut store = Store::default();
/// #
/// const I32_I32_TO_I32: ([Type; 2], [Type; 1]) = ([Type::I32, Type::I32], [Type::I32]);
///
@ -95,55 +94,63 @@ impl Function {
/// });
/// ```
#[allow(clippy::cast_ptr_alignment)]
pub fn new<FT, F, T>(ctx: &mut impl AsContextMut<Data = T>, ty: FT, func: F) -> Self
pub fn new<FT, F, T: Send + 'static>(
store: &mut impl AsStoreMut,
ctx: &FunctionEnv<T>,
ty: FT,
func: F,
) -> Self
where
FT: Into<FunctionType>,
F: Fn(ContextMut<'_, T>, &[Value]) -> Result<Vec<Value>, RuntimeError>
F: Fn(FunctionEnvMut<'_, T>, &[Value]) -> Result<Vec<Value>, RuntimeError>
+ 'static
+ Send
+ Sync,
{
let mut ctx = ctx.as_context_mut();
let mut store = store.as_store_mut();
let function_type = ty.into();
let func_ty = function_type.clone();
let raw_ctx = ctx.as_raw() as *mut u8;
let raw_store = store.as_raw() as *mut u8;
let raw_ctx = ctx.clone();
let wrapped_func: JsValue = match function_type.results().len() {
0 => Closure::wrap(Box::new(move |args: &Array| {
let mut ctx: ContextMut<T> = unsafe { ContextMut::from_raw(raw_ctx as _) };
let mut store: StoreMut = unsafe { StoreMut::from_raw(raw_store as _) };
let mut ctx: FunctionEnvMut<T> = raw_ctx.clone().into_mut(&mut store);
let wasm_arguments = function_type
.params()
.iter()
.enumerate()
.map(|(i, param)| param_from_js(param, &args.get(i as u32)))
.collect::<Vec<_>>();
let _results = func(ctx.as_context_mut(), &wasm_arguments)?;
let _results = func(ctx, &wasm_arguments)?;
Ok(())
})
as Box<dyn FnMut(&Array) -> Result<(), JsValue>>)
.into_js_value(),
1 => Closure::wrap(Box::new(move |args: &Array| {
let mut ctx: ContextMut<T> = unsafe { ContextMut::from_raw(raw_ctx as _) };
let mut store: StoreMut = unsafe { StoreMut::from_raw(raw_store as _) };
let mut ctx: FunctionEnvMut<T> = raw_ctx.clone().into_mut(&mut store);
let wasm_arguments = function_type
.params()
.iter()
.enumerate()
.map(|(i, param)| param_from_js(param, &args.get(i as u32)))
.collect::<Vec<_>>();
let results = func(ctx.as_context_mut(), &wasm_arguments)?;
let results = func(ctx, &wasm_arguments)?;
return Ok(result_to_js(&results[0]));
})
as Box<dyn FnMut(&Array) -> Result<JsValue, JsValue>>)
.into_js_value(),
_n => Closure::wrap(Box::new(move |args: &Array| {
let mut ctx: ContextMut<T> = unsafe { ContextMut::from_raw(raw_ctx as _) };
let mut store: StoreMut = unsafe { StoreMut::from_raw(raw_store as _) };
let mut ctx: FunctionEnvMut<T> = raw_ctx.clone().into_mut(&mut store);
let wasm_arguments = function_type
.params()
.iter()
.enumerate()
.map(|(i, param)| param_from_js(param, &args.get(i as u32)))
.collect::<Vec<_>>();
let results = func(ctx.as_context_mut(), &wasm_arguments)?;
let results = func(ctx, &wasm_arguments)?;
return Ok(results_to_js_array(&results));
})
as Box<dyn FnMut(&Array) -> Result<Array, JsValue>>)
@ -154,7 +161,7 @@ impl Function {
JSFunction::new_with_args("f", "return f(Array.prototype.slice.call(arguments, 1))");
let binded_func = dyn_func.bind1(&JsValue::UNDEFINED, &wrapped_func);
let vm_function = VMFunction::new(binded_func, func_ty);
Self::from_vm_export(&mut ctx, vm_function)
Self::from_vm_export(&mut store, vm_function)
}
/// Creates a new host `Function` from a native function.
@ -166,7 +173,7 @@ impl Function {
///
/// ```
/// # use wasmer::{Store, Function};
/// # let store = Store::default();
/// # let mut store = Store::default();
/// #
/// fn sum(a: i32, b: i32) -> i32 {
/// a + b
@ -174,13 +181,17 @@ impl Function {
///
/// let f = Function::new_native(&store, sum);
/// ```
pub fn new_native<T, F, Args, Rets>(ctx: &mut impl AsContextMut<Data = T>, func: F) -> Self
pub fn new_native<T, F, Args, Rets>(
store: &mut impl AsStoreMut,
env: &FunctionEnv<T>,
func: F,
) -> Self
where
F: HostFunction<T, Args, Rets>,
Args: WasmTypeList,
Rets: WasmTypeList,
{
let mut ctx = ctx.as_context_mut();
let mut store = store.as_store_mut();
if std::mem::size_of::<F>() != 0 {
Self::closures_unsupported_panic();
}
@ -191,14 +202,15 @@ impl Function {
let as_table = ft.unchecked_ref::<js_sys::WebAssembly::Table>();
let func = as_table.get(address).unwrap();
let binded_func = func.bind1(
let binded_func = func.bind2(
&JsValue::UNDEFINED,
&JsValue::from_f64(ctx.as_raw() as *mut u8 as usize as f64),
&JsValue::from_f64(store.as_raw() as *mut u8 as usize as f64),
&JsValue::from_f64(env.handle.internal_handle().index() as f64),
);
let ty = function.ty();
let vm_function = VMFunction::new(binded_func, ty);
Self {
handle: ContextHandle::new(ctx.as_context_mut().objects_mut(), vm_function),
handle: StoreHandle::new(store.objects_mut(), vm_function),
}
}
@ -208,7 +220,7 @@ impl Function {
///
/// ```
/// # use wasmer::{Function, Store, Type};
/// # let store = Store::default();
/// # let mut store = Store::default();
/// #
/// fn sum(a: i32, b: i32) -> i32 {
/// a + b
@ -219,8 +231,8 @@ impl Function {
/// assert_eq!(f.ty().params(), vec![Type::I32, Type::I32]);
/// assert_eq!(f.ty().results(), vec![Type::I32]);
/// ```
pub fn ty<'context>(&self, ctx: &'context impl AsContextRef) -> &'context FunctionType {
&self.handle.get(ctx.as_context_ref().objects()).ty
pub fn ty<'context>(&self, ctx: &'context impl AsStoreRef) -> &'context FunctionType {
&self.handle.get(ctx.as_store_ref().objects()).ty
}
/// Returns the number of parameters that this function takes.
@ -228,18 +240,19 @@ impl Function {
/// # Example
///
/// ```
/// # use wasmer::{Function, Store, Type};
/// # let store = Store::default();
/// # use wasmer::{Function, FunctionEnv, FunctionEnvMut, Store, Type};
/// # let mut store = Store::default();
/// # let env = FunctionEnv::new(&mut store, ());
/// #
/// fn sum(a: i32, b: i32) -> i32 {
/// fn sum(_ctx: FunctionEnvMut<()>, a: i32, b: i32) -> i32 {
/// a + b
/// }
///
/// let f = Function::new_native(&store, sum);
/// let f = Function::new_native(&store, &env, sum);
///
/// assert_eq!(f.param_arity(), 2);
/// assert_eq!(f.param_arity(&store), 2);
/// ```
pub fn param_arity(&self, ctx: &impl AsContextRef) -> usize {
pub fn param_arity(&self, ctx: &impl AsStoreRef) -> usize {
self.ty(ctx).params().len()
}
@ -248,18 +261,19 @@ impl Function {
/// # Example
///
/// ```
/// # use wasmer::{Function, Store, Type};
/// # let store = Store::default();
/// # use wasmer::{Function, FunctionEnv, FunctionEnvMut, Store, Type};
/// # let mut store = Store::default();
/// # let env = FunctionEnv::new(&mut store, ());
/// #
/// fn sum(a: i32, b: i32) -> i32 {
/// fn sum(_ctx: FunctionEnvMut<()>, a: i32, b: i32) -> i32 {
/// a + b
/// }
///
/// let f = Function::new_native(&store, sum);
/// let f = Function::new_native(&store, &env, sum);
///
/// assert_eq!(f.result_arity(), 1);
/// assert_eq!(f.result_arity(&store), 1);
/// ```
pub fn result_arity(&self, ctx: &impl AsContextRef) -> usize {
pub fn result_arity(&self, ctx: &impl AsStoreRef) -> usize {
self.ty(ctx).results().len()
}
@ -275,7 +289,7 @@ impl Function {
///
/// ```
/// # use wasmer::{imports, wat2wasm, Function, Instance, Module, Store, Type, Value};
/// # let store = Store::default();
/// # let mut store = Store::default();
/// # let wasm_bytes = wat2wasm(r#"
/// # (module
/// # (func (export "sum") (param $x i32) (param $y i32) (result i32)
@ -292,27 +306,27 @@ impl Function {
///
/// assert_eq!(sum.call(&[Value::I32(1), Value::I32(2)]).unwrap().to_vec(), vec![Value::I32(3)]);
/// ```
pub fn call<T>(
pub fn call(
&self,
ctx: &mut impl AsContextMut<Data = T>,
store: &mut impl AsStoreMut,
params: &[Value],
) -> Result<Box<[Value]>, RuntimeError> {
let arr = js_sys::Array::new_with_length(params.len() as u32);
// let raw_ctx = ctx.as_context_mut().as_raw() as *mut u8;
// let mut ctx = unsafe { ContextMut::from_raw(raw_ctx as *mut ContextInner<()>) };
// let raw_ctx = ctx.as_raw() as *mut u8;
// let mut env = unsafe { FunctionEnvMut::from_raw(raw_ctx as *mut StoreInner<()>) };
for (i, param) in params.iter().enumerate() {
let js_value = param.as_jsvalue(&ctx.as_context_ref());
let js_value = param.as_jsvalue(&store.as_store_ref());
arr.set(i as u32, js_value);
}
let result = js_sys::Reflect::apply(
&self.handle.get(ctx.as_context_ref().objects()).function,
&self.handle.get(store.as_store_ref().objects()).function,
&wasm_bindgen::JsValue::NULL,
&arr,
)?;
let result_types = self.handle.get(ctx.as_context_ref().objects()).ty.results();
let result_types = self.handle.get(store.as_store_ref().objects()).ty.results();
match result_types.len() {
0 => Ok(Box::new([])),
1 => {
@ -331,19 +345,19 @@ impl Function {
}
}
pub(crate) fn from_vm_export(ctx: &mut impl AsContextMut, vm_function: VMFunction) -> Self {
pub(crate) fn from_vm_export(ctx: &mut impl AsStoreMut, vm_function: VMFunction) -> Self {
Self {
handle: ContextHandle::new(ctx.as_context_mut().objects_mut(), vm_function),
handle: StoreHandle::new(ctx.objects_mut(), vm_function),
}
}
pub(crate) fn from_vm_extern(
ctx: &mut impl AsContextMut,
internal: InternalContextHandle<VMFunction>,
ctx: &mut impl AsStoreMut,
internal: InternalStoreHandle<VMFunction>,
) -> Self {
Self {
handle: unsafe {
ContextHandle::from_internal(ctx.as_context_ref().objects().id(), internal)
StoreHandle::from_internal(ctx.as_store_ref().objects().id(), internal)
},
}
}
@ -355,7 +369,7 @@ impl Function {
///
/// ```
/// # use wasmer::{imports, wat2wasm, Function, Instance, Module, Store, Type, Value};
/// # let store = Store::default();
/// # let mut store = Store::default();
/// # let wasm_bytes = wat2wasm(r#"
/// # (module
/// # (func (export "sum") (param $x i32) (param $y i32) (result i32)
@ -371,7 +385,7 @@ impl Function {
/// let sum = instance.exports.get_function("sum").unwrap();
/// let sum_native = sum.native::<(i32, i32), i32>().unwrap();
///
/// assert_eq!(sum_native.call(1, 2).unwrap(), 3);
/// assert_eq!(sum_native.call(&mut store, 1, 2).unwrap(), 3);
/// ```
///
/// # Errors
@ -381,7 +395,7 @@ impl Function {
///
/// ```should_panic
/// # use wasmer::{imports, wat2wasm, Function, Instance, Module, Store, Type, Value};
/// # let store = Store::default();
/// # let mut store = Store::default();
/// # let wasm_bytes = wat2wasm(r#"
/// # (module
/// # (func (export "sum") (param $x i32) (param $y i32) (result i32)
@ -397,7 +411,7 @@ impl Function {
/// let sum = instance.exports.get_function("sum").unwrap();
///
/// // This results in an error: `RuntimeError`
/// let sum_native = sum.native::<(i64, i64), i32>().unwrap();
/// let sum_native = sum.native::<(i64, i64), i32>(&mut store).unwrap();
/// ```
///
/// If the `Rets` generic parameter does not match the exported function
@ -405,7 +419,7 @@ impl Function {
///
/// ```should_panic
/// # use wasmer::{imports, wat2wasm, Function, Instance, Module, Store, Type, Value};
/// # let store = Store::default();
/// # let mut store = Store::default();
/// # let wasm_bytes = wat2wasm(r#"
/// # (module
/// # (func (export "sum") (param $x i32) (param $y i32) (result i32)
@ -421,17 +435,17 @@ impl Function {
/// let sum = instance.exports.get_function("sum").unwrap();
///
/// // This results in an error: `RuntimeError`
/// let sum_native = sum.native::<(i32, i32), i64>().unwrap();
/// let sum_native = sum.native::<(i32, i32), i64>(&mut store).unwrap();
/// ```
pub fn native<Args, Rets>(
&self,
ctx: &impl AsContextRef,
ctx: &impl AsStoreRef,
) -> Result<TypedFunction<Args, Rets>, RuntimeError>
where
Args: WasmTypeList,
Rets: WasmTypeList,
{
let vm_function = self.handle.get(ctx.as_context_ref().objects());
let vm_function = self.handle.get(ctx.as_store_ref().objects());
// type check
{
@ -470,8 +484,8 @@ impl Function {
}
/// Checks whether this `Function` can be used with the given context.
pub fn is_from_context(&self, ctx: &impl AsContextRef) -> bool {
self.handle.context_id() == ctx.as_context_ref().objects().id()
pub fn is_from_store(&self, ctx: &impl AsStoreRef) -> bool {
self.handle.store_id() == ctx.as_store_ref().objects().id()
}
}
@ -495,7 +509,9 @@ impl fmt::Debug for Function {
mod inner {
use super::RuntimeError;
use super::VMFunctionBody;
use crate::js::context::{AsContextMut, ContextInner, ContextMut};
use crate::js::function_env::{FunctionEnvMut, VMFunctionEnvironment};
use crate::js::store::{AsStoreMut, InternalStoreHandle, StoreHandle, StoreInner, StoreMut};
use crate::js::FunctionEnv;
use crate::js::NativeWasmTypeInto;
use std::array::TryFromSliceError;
use std::convert::{Infallible, TryInto};
@ -641,7 +657,7 @@ mod inner {
/// Constructs `Self` based on an array of values.
///
/// # Safety
unsafe fn from_array(ctx: &mut impl AsContextMut, array: Self::Array) -> Self;
unsafe fn from_array(ctx: &mut impl AsStoreMut, array: Self::Array) -> Self;
/// Constructs `Self` based on a slice of values.
///
@ -652,7 +668,7 @@ mod inner {
///
/// # Safety
unsafe fn from_slice(
ctx: &mut impl AsContextMut,
ctx: &mut impl AsStoreMut,
slice: &[f64],
) -> Result<Self, TryFromSliceError>;
@ -660,7 +676,7 @@ mod inner {
/// (list) of values.
///
/// # Safety
unsafe fn into_array(self, ctx: &mut impl AsContextMut) -> Self::Array;
unsafe fn into_array(self, ctx: &mut impl AsStoreMut) -> Self::Array;
/// Allocates and return an empty array of type `Array` that
/// will hold a tuple (list) of values, usually to hold the
@ -671,13 +687,13 @@ mod inner {
/// `CStruct`.
///
/// # Safety
unsafe fn from_c_struct(ctx: &mut impl AsContextMut, c_struct: Self::CStruct) -> Self;
unsafe fn from_c_struct(ctx: &mut impl AsStoreMut, c_struct: Self::CStruct) -> Self;
/// Builds and returns a C struct of type `CStruct` from a
/// tuple (list) of values.
///
/// # Safety
unsafe fn into_c_struct(self, ctx: &mut impl AsContextMut) -> Self::CStruct;
unsafe fn into_c_struct(self, ctx: &mut impl AsStoreMut) -> Self::CStruct;
/// Writes the contents of a C struct to an array of `f64`.
///
@ -863,7 +879,7 @@ mod inner {
#[allow(unused_mut)]
#[allow(clippy::unused_unit)]
#[allow(clippy::missing_safety_doc)]
unsafe fn from_array(mut _ctx: &mut impl AsContextMut, array: Self::Array) -> Self {
unsafe fn from_array(mut _ctx: &mut impl AsStoreMut, array: Self::Array) -> Self {
// Unpack items of the array.
#[allow(non_snake_case)]
let [ $( $x ),* ] = array;
@ -877,13 +893,13 @@ mod inner {
}
#[allow(clippy::missing_safety_doc)]
unsafe fn from_slice(ctx: &mut impl AsContextMut, slice: &[f64]) -> Result<Self, TryFromSliceError> {
unsafe fn from_slice(ctx: &mut impl AsStoreMut, slice: &[f64]) -> Result<Self, TryFromSliceError> {
Ok(Self::from_array(ctx, slice.try_into()?))
}
#[allow(unused_mut)]
#[allow(clippy::missing_safety_doc)]
unsafe fn into_array(self, mut _ctx: &mut impl AsContextMut) -> Self::Array {
unsafe fn into_array(self, mut _ctx: &mut impl AsStoreMut) -> Self::Array {
// Unpack items of the tuple.
#[allow(non_snake_case)]
let ( $( $x ),* ) = self;
@ -904,7 +920,7 @@ mod inner {
#[allow(unused_mut)]
#[allow(clippy::unused_unit)]
#[allow(clippy::missing_safety_doc)]
unsafe fn from_c_struct(mut _ctx: &mut impl AsContextMut, c_struct: Self::CStruct) -> Self {
unsafe fn from_c_struct(mut _ctx: &mut impl AsStoreMut, c_struct: Self::CStruct) -> Self {
// Unpack items of the C structure.
#[allow(non_snake_case)]
let $c_struct_name( $( $x ),* ) = c_struct;
@ -918,7 +934,7 @@ mod inner {
#[allow(unused_parens, non_snake_case, unused_mut)]
#[allow(clippy::missing_safety_doc)]
unsafe fn into_c_struct(self, mut _ctx: &mut impl AsContextMut) -> Self::CStruct {
unsafe fn into_c_struct(self, mut _ctx: &mut impl AsStoreMut) -> Self::CStruct {
// Unpack items of the tuple.
let ( $( $x ),* ) = self;
@ -961,30 +977,35 @@ mod inner {
$( $x: FromToNativeWasmType, )*
Rets: WasmTypeList,
RetsAsResult: IntoResult<Rets>,
Func: Fn(ContextMut<'_, T>, $( $x , )*) -> RetsAsResult + 'static,
T: Send + 'static,
Func: Fn(FunctionEnvMut<'_, T>, $( $x , )*) -> RetsAsResult + 'static,
{
#[allow(non_snake_case)]
fn function_body_ptr(self) -> *const VMFunctionBody {
/// This is a function that wraps the real host
/// function. Its address will be used inside the
/// runtime.
unsafe extern "C" fn func_wrapper<T, $( $x, )* Rets, RetsAsResult, Func>( ctx_ptr: usize, $( $x: <$x::Native as NativeWasmType>::Abi, )* ) -> Rets::CStruct
unsafe extern "C" fn func_wrapper<T, $( $x, )* Rets, RetsAsResult, Func>( store_ptr: usize, handle_index: usize, $( $x: <$x::Native as NativeWasmType>::Abi, )* ) -> Rets::CStruct
where
$( $x: FromToNativeWasmType, )*
Rets: WasmTypeList,
RetsAsResult: IntoResult<Rets>,
Func: Fn(ContextMut<'_, T>, $( $x , )*) -> RetsAsResult + 'static,
T: Send + 'static,
Func: Fn(FunctionEnvMut<'_, T>, $( $x , )*) -> RetsAsResult + 'static,
{
// let env: &Env = unsafe { &*(ptr as *const u8 as *const Env) };
let func: &Func = &*(&() as *const () as *const Func);
let mut ctx = ContextMut::from_raw(ctx_ptr as *mut ContextInner<T>);
let mut ctx2 = ContextMut::from_raw(ctx_ptr as *mut ContextInner<T>);
let mut store = StoreMut::from_raw(store_ptr as *mut _);
let mut store2 = StoreMut::from_raw(store_ptr as *mut _);
let result = panic::catch_unwind(AssertUnwindSafe(|| {
func(ctx2.as_context_mut(), $( FromToNativeWasmType::from_native(NativeWasmTypeInto::from_abi(&mut ctx, $x)) ),* ).into_result()
let handle: StoreHandle<VMFunctionEnvironment> = StoreHandle::from_internal(store2.objects_mut().id(), InternalStoreHandle::from_index(handle_index).unwrap());
let ctx: FunctionEnvMut<T> = FunctionEnv::from_handle(handle).into_mut(&mut store2);
func(ctx, $( FromToNativeWasmType::from_native(NativeWasmTypeInto::from_abi(&mut store, $x)) ),* ).into_result()
}));
match result {
Ok(Ok(result)) => return result.into_c_struct(&mut ctx),
Ok(Ok(result)) => return result.into_c_struct(&mut store),
#[allow(deprecated)]
Ok(Err(trap)) => RuntimeError::raise(Box::new(trap)),
Err(_panic) => unimplemented!(),
@ -1051,18 +1072,18 @@ mod inner {
0
}
unsafe fn from_array(_: &mut impl AsContextMut, _: Self::Array) -> Self {
unsafe fn from_array(_: &mut impl AsStoreMut, _: Self::Array) -> Self {
unreachable!()
}
unsafe fn from_slice(
_: &mut impl AsContextMut,
_: &mut impl AsStoreMut,
_: &[f64],
) -> Result<Self, TryFromSliceError> {
unreachable!()
}
unsafe fn into_array(self, _: &mut impl AsContextMut) -> Self::Array {
unsafe fn into_array(self, _: &mut impl AsStoreMut) -> Self::Array {
[]
}
@ -1070,11 +1091,11 @@ mod inner {
[]
}
unsafe fn from_c_struct(_: &mut impl AsContextMut, self_: Self::CStruct) -> Self {
unsafe fn from_c_struct(_: &mut impl AsStoreMut, self_: Self::CStruct) -> Self {
self_
}
unsafe fn into_c_struct(self, _: &mut impl AsContextMut) -> Self::CStruct {
unsafe fn into_c_struct(self, _: &mut impl AsStoreMut) -> Self::CStruct {
self
}

View File

@ -1,7 +1,7 @@
use crate::js::context::{AsContextMut, AsContextRef, ContextHandle, InternalContextHandle};
use crate::js::export::VMGlobal;
use crate::js::exports::{ExportError, Exportable};
use crate::js::externals::Extern;
use crate::js::store::{AsStoreMut, AsStoreRef, InternalStoreHandle, StoreHandle};
use crate::js::value::Value;
use crate::js::wasm_bindgen_polyfill::Global as JSGlobal;
use crate::js::GlobalType;
@ -17,7 +17,7 @@ use wasm_bindgen::JsValue;
/// Spec: <https://webassembly.github.io/spec/core/exec/runtime.html#global-instances>
#[derive(Debug, Clone, PartialEq)]
pub struct Global {
pub(crate) handle: ContextHandle<VMGlobal>,
pub(crate) handle: StoreHandle<VMGlobal>,
}
impl Global {
@ -27,14 +27,14 @@ impl Global {
///
/// ```
/// # use wasmer::{Global, Mutability, Store, Value};
/// # let store = Store::default();
/// # let mut store = Store::default();
/// #
/// let g = Global::new(&store, Value::I32(1));
///
/// assert_eq!(g.get(), Value::I32(1));
/// assert_eq!(g.ty().mutability, Mutability::Const);
/// ```
pub fn new(ctx: &mut impl AsContextMut, val: Value) -> Self {
pub fn new(ctx: &mut impl AsStoreMut, val: Value) -> Self {
Self::from_value(ctx, val, Mutability::Const).unwrap()
}
@ -44,26 +44,26 @@ impl Global {
///
/// ```
/// # use wasmer::{Global, Mutability, Store, Value};
/// # let store = Store::default();
/// # let mut store = Store::default();
/// #
/// let g = Global::new_mut(&store, Value::I32(1));
///
/// assert_eq!(g.get(), Value::I32(1));
/// assert_eq!(g.ty().mutability, Mutability::Var);
/// ```
pub fn new_mut(ctx: &mut impl AsContextMut, val: Value) -> Self {
pub fn new_mut(ctx: &mut impl AsStoreMut, val: Value) -> Self {
Self::from_value(ctx, val, Mutability::Var).unwrap()
}
/// Create a `Global` with the initial value [`Value`] and the provided [`Mutability`].
fn from_value(
ctx: &mut impl AsContextMut,
ctx: &mut impl AsStoreMut,
val: Value,
mutability: Mutability,
) -> Result<Self, RuntimeError> {
if !val.is_from_context(ctx) {
if !val.is_from_store(ctx) {
return Err(RuntimeError::new(
"cross-`Context` values are not supported",
"cross-`WasmerEnv` values are not supported",
));
}
let global_ty = GlobalType {
@ -99,7 +99,7 @@ impl Global {
///
/// ```
/// # use wasmer::{Global, Mutability, Store, Type, Value, GlobalType};
/// # let store = Store::default();
/// # let mut store = Store::default();
/// #
/// let c = Global::new(&store, Value::I32(1));
/// let v = Global::new_mut(&store, Value::I64(1));
@ -107,8 +107,8 @@ impl Global {
/// assert_eq!(c.ty(), &GlobalType::new(Type::I32, Mutability::Const));
/// assert_eq!(v.ty(), &GlobalType::new(Type::I64, Mutability::Var));
/// ```
pub fn ty(&self, ctx: &impl AsContextRef) -> GlobalType {
self.handle.get(ctx.as_context_ref().objects()).ty
pub fn ty(&self, store: &impl AsStoreRef) -> GlobalType {
self.handle.get(store.as_store_ref().objects()).ty
}
/// Retrieves the current value [`Value`] that the Global has.
@ -117,23 +117,23 @@ impl Global {
///
/// ```
/// # use wasmer::{Global, Store, Value};
/// # let store = Store::default();
/// # let mut store = Store::default();
/// #
/// let g = Global::new(&store, Value::I32(1));
///
/// assert_eq!(g.get(), Value::I32(1));
/// ```
pub fn get(&self, ctx: &impl AsContextRef) -> Value {
pub fn get(&self, store: &impl AsStoreRef) -> Value {
unsafe {
let raw = self
.handle
.get(ctx.as_context_ref().objects())
.get(store.as_store_ref().objects())
.global
.value()
.as_f64()
.unwrap();
let ty = self.handle.get(ctx.as_context_ref().objects()).ty;
Value::from_raw(ctx, ty.ty, raw)
let ty = self.handle.get(store.as_store_ref().objects()).ty;
Value::from_raw(store, ty.ty, raw)
}
/*
match self.vm_global.ty.ty {
@ -152,7 +152,7 @@ impl Global {
///
/// ```
/// # use wasmer::{Global, Store, Value};
/// # let store = Store::default();
/// # let mut store = Store::default();
/// #
/// let g = Global::new_mut(&store, Value::I32(1));
///
@ -169,7 +169,7 @@ impl Global {
///
/// ```should_panic
/// # use wasmer::{Global, Store, Value};
/// # let store = Store::default();
/// # let mut store = Store::default();
/// #
/// let g = Global::new(&store, Value::I32(1));
///
@ -180,20 +180,20 @@ impl Global {
///
/// ```should_panic
/// # use wasmer::{Global, Store, Value};
/// # let store = Store::default();
/// # let mut store = Store::default();
/// #
/// let g = Global::new(&store, Value::I32(1));
///
/// // This results in an error: `RuntimeError`.
/// g.set(Value::I64(2)).unwrap();
/// ```
pub fn set(&self, ctx: &mut impl AsContextMut, val: Value) -> Result<(), RuntimeError> {
if !val.is_from_context(ctx) {
pub fn set(&self, store: &mut impl AsStoreMut, val: Value) -> Result<(), RuntimeError> {
if !val.is_from_store(store) {
return Err(RuntimeError::new(
"cross-`Context` values are not supported",
"cross-`WasmerEnv` values are not supported",
));
}
let global_ty = self.ty(&ctx);
let global_ty = self.ty(&store);
if global_ty.mutability == Mutability::Const {
return Err(RuntimeError::new("The global is immutable".to_owned()));
}
@ -212,32 +212,32 @@ impl Global {
}
};
self.handle
.get_mut(ctx.as_context_mut().objects_mut())
.get_mut(store.objects_mut())
.global
.set_value(&new_value);
Ok(())
}
pub(crate) fn from_vm_export(ctx: &mut impl AsContextMut, vm_global: VMGlobal) -> Self {
pub(crate) fn from_vm_export(store: &mut impl AsStoreMut, vm_global: VMGlobal) -> Self {
Self {
handle: ContextHandle::new(ctx.as_context_mut().objects_mut(), vm_global),
handle: StoreHandle::new(store.objects_mut(), vm_global),
}
}
pub(crate) fn from_vm_extern(
ctx: &mut impl AsContextMut,
internal: InternalContextHandle<VMGlobal>,
store: &mut impl AsStoreMut,
internal: InternalStoreHandle<VMGlobal>,
) -> Self {
Self {
handle: unsafe {
ContextHandle::from_internal(ctx.as_context_ref().objects().id(), internal)
StoreHandle::from_internal(store.as_store_ref().objects().id(), internal)
},
}
}
/// Checks whether this `Global` can be used with the given context.
pub fn is_from_context(&self, ctx: &impl AsContextRef) -> bool {
self.handle.context_id() == ctx.as_context_ref().objects().id()
/// Checks whether this `Global` can be used with the given store.
pub fn is_from_store(&self, store: &impl AsStoreRef) -> bool {
self.handle.store_id() == store.as_store_ref().objects().id()
}
}

View File

@ -1,9 +1,7 @@
use crate::js::context::{
AsContextMut, AsContextRef, ContextHandle, ContextObjects, InternalContextHandle,
};
use crate::js::export::VMMemory;
use crate::js::exports::{ExportError, Exportable};
use crate::js::externals::Extern;
use crate::js::store::{AsStoreMut, AsStoreRef, InternalStoreHandle, StoreHandle, StoreObjects};
use crate::js::{MemoryAccessError, MemoryType};
use std::convert::TryInto;
use std::marker::PhantomData;
@ -80,7 +78,7 @@ extern "C" {
/// Spec: <https://webassembly.github.io/spec/core/exec/runtime.html#memory-instances>
#[derive(Debug, Clone)]
pub struct Memory {
pub(crate) handle: ContextHandle<VMMemory>,
pub(crate) handle: StoreHandle<VMMemory>,
#[allow(dead_code)]
view: js_sys::Uint8Array,
}
@ -98,11 +96,11 @@ impl Memory {
///
/// ```
/// # use wasmer::{Memory, MemoryType, Pages, Store, Type, Value};
/// # let store = Store::default();
/// # let mut store = Store::default();
/// #
/// let m = Memory::new(&store, MemoryType::new(1, None, false)).unwrap();
/// ```
pub fn new(ctx: &mut impl AsContextMut, ty: MemoryType) -> Result<Self, MemoryError> {
pub fn new(ctx: &mut impl AsStoreMut, ty: MemoryType) -> Result<Self, MemoryError> {
let descriptor = js_sys::Object::new();
js_sys::Reflect::set(&descriptor, &"initial".into(), &ty.minimum.0.into()).unwrap();
if let Some(max) = ty.maximum {
@ -123,15 +121,15 @@ impl Memory {
///
/// ```
/// # use wasmer::{Memory, MemoryType, Pages, Store, Type, Value};
/// # let store = Store::default();
/// # let mut store = Store::default();
/// #
/// let mt = MemoryType::new(1, None, false);
/// let m = Memory::new(&store, mt).unwrap();
///
/// assert_eq!(m.ty(), mt);
/// ```
pub fn ty(&self, ctx: &impl AsContextRef) -> MemoryType {
self.handle.get(ctx.as_context_ref().objects()).ty
pub fn ty(&self, ctx: &impl AsStoreRef) -> MemoryType {
self.handle.get(ctx.as_store_ref().objects()).ty
}
/// Returns the pointer to the raw bytes of the `Memory`.
@ -141,11 +139,11 @@ impl Memory {
}
/// Returns the size (in bytes) of the `Memory`.
pub fn data_size(&self, ctx: &impl AsContextRef) -> u64 {
pub fn data_size(&self, ctx: &impl AsStoreRef) -> u64 {
js_sys::Reflect::get(
&self
.handle
.get(ctx.as_context_ref().objects())
.get(ctx.as_store_ref().objects())
.memory
.buffer(),
&"byteLength".into(),
@ -161,17 +159,17 @@ impl Memory {
///
/// ```
/// # use wasmer::{Memory, MemoryType, Pages, Store, Type, Value};
/// # let store = Store::default();
/// # let mut store = Store::default();
/// #
/// let m = Memory::new(&store, MemoryType::new(1, None, false)).unwrap();
///
/// assert_eq!(m.size(), Pages(1));
/// ```
pub fn size(&self, ctx: &impl AsContextRef) -> Pages {
pub fn size(&self, ctx: &impl AsStoreRef) -> Pages {
let bytes = js_sys::Reflect::get(
&self
.handle
.get(ctx.as_context_ref().objects())
.get(ctx.as_store_ref().objects())
.memory
.buffer(),
&"byteLength".into(),
@ -189,7 +187,7 @@ impl Memory {
///
/// ```
/// # use wasmer::{Memory, MemoryType, Pages, Store, Type, Value, WASM_MAX_PAGES};
/// # let store = Store::default();
/// # let mut store = Store::default();
/// #
/// let m = Memory::new(&store, MemoryType::new(1, Some(3), false)).unwrap();
/// let p = m.grow(2).unwrap();
@ -205,7 +203,7 @@ impl Memory {
///
/// ```should_panic
/// # use wasmer::{Memory, MemoryType, Pages, Store, Type, Value, WASM_MAX_PAGES};
/// # let store = Store::default();
/// # let mut store = Store::default();
/// #
/// let m = Memory::new(&store, MemoryType::new(1, Some(1), false)).unwrap();
///
@ -214,20 +212,19 @@ impl Memory {
/// ```
pub fn grow<IntoPages>(
&self,
ctx: &mut impl AsContextMut,
store: &mut impl AsStoreMut,
delta: IntoPages,
) -> Result<Pages, MemoryError>
where
IntoPages: Into<Pages>,
{
let pages = delta.into();
let mut ctx_mut = ctx.as_context_mut();
let js_memory = &self.handle.get_mut(ctx_mut.objects_mut()).memory;
let js_memory = &self.handle.get_mut(store.objects_mut()).memory;
let our_js_memory: &JSMemory = JsCast::unchecked_from_js_ref(js_memory);
let new_pages = our_js_memory.grow(pages.0).map_err(|err| {
if err.is_instance_of::<js_sys::RangeError>() {
MemoryError::CouldNotGrow {
current: self.size(&ctx.as_context_ref()),
current: self.size(&store.as_store_ref()),
attempted_delta: pages,
}
} else {
@ -239,40 +236,40 @@ impl Memory {
/// Used by tests
#[doc(hidden)]
pub fn uint8view(&self, ctx: &impl AsContextRef) -> js_sys::Uint8Array {
pub fn uint8view(&self, ctx: &impl AsStoreRef) -> js_sys::Uint8Array {
js_sys::Uint8Array::new(
&self
.handle
.get(ctx.as_context_ref().objects())
.get(ctx.as_store_ref().objects())
.memory
.buffer(),
)
}
pub(crate) fn buffer<'a>(&'a self, _ctx: &'a impl AsContextRef) -> MemoryBuffer<'a> {
pub(crate) fn buffer<'a>(&'a self, _ctx: &'a impl AsStoreRef) -> MemoryBuffer<'a> {
MemoryBuffer {
base: &self.view as *const _ as *mut _,
marker: PhantomData,
}
}
pub(crate) fn from_vm_export(ctx: &mut impl AsContextMut, vm_memory: VMMemory) -> Self {
pub(crate) fn from_vm_export(ctx: &mut impl AsStoreMut, vm_memory: VMMemory) -> Self {
let view = js_sys::Uint8Array::new(&vm_memory.memory.buffer());
Self {
handle: ContextHandle::new(ctx.as_context_mut().objects_mut(), vm_memory),
handle: StoreHandle::new(ctx.objects_mut(), vm_memory),
view,
}
}
pub(crate) fn from_vm_extern(
ctx: &mut impl AsContextMut,
internal: InternalContextHandle<VMMemory>,
ctx: &mut impl AsStoreMut,
internal: InternalStoreHandle<VMMemory>,
) -> Self {
let view =
js_sys::Uint8Array::new(&internal.get(ctx.as_context_ref().objects()).memory.buffer());
js_sys::Uint8Array::new(&internal.get(ctx.as_store_ref().objects()).memory.buffer());
Self {
handle: unsafe {
ContextHandle::from_internal(ctx.as_context_ref().objects().id(), internal)
StoreHandle::from_internal(ctx.as_store_ref().objects().id(), internal)
},
view,
}
@ -287,7 +284,7 @@ impl Memory {
/// concurrent writes.
pub fn read(
&self,
_ctx: &impl AsContextRef,
_ctx: &impl AsStoreRef,
offset: u64,
data: &mut [u8],
) -> Result<(), MemoryAccessError> {
@ -317,7 +314,7 @@ impl Memory {
/// concurrent writes.
pub fn read_uninit<'a>(
&self,
_ctx: &impl AsContextRef,
_ctx: &impl AsStoreRef,
offset: u64,
buf: &'a mut [MaybeUninit<u8>],
) -> Result<&'a mut [u8], MemoryAccessError> {
@ -352,7 +349,7 @@ impl Memory {
/// concurrent reads/writes.
pub fn write(
&self,
_ctx: &mut impl AsContextMut,
_ctx: &mut impl AsStoreMut,
offset: u64,
data: &[u8],
) -> Result<(), MemoryAccessError> {
@ -371,8 +368,8 @@ impl Memory {
}
/// Checks whether this `Global` can be used with the given context.
pub fn is_from_context(&self, ctx: &impl AsContextRef) -> bool {
self.handle.context_id() == ctx.as_context_ref().objects().id()
pub fn is_from_store(&self, ctx: &impl AsStoreRef) -> bool {
self.handle.store_id() == ctx.as_store_ref().objects().id()
}
}
@ -389,7 +386,7 @@ impl<'a> Exportable<'a> for Memory {
#[derive(Copy, Clone)]
pub(crate) struct MemoryBuffer<'a> {
base: *mut js_sys::Uint8Array,
marker: PhantomData<(&'a Memory, &'a ContextObjects)>,
marker: PhantomData<(&'a Memory, &'a StoreObjects)>,
}
impl<'a> MemoryBuffer<'a> {

View File

@ -8,10 +8,10 @@ pub use self::global::Global;
pub use self::memory::{Memory, MemoryError};
pub use self::table::Table;
use crate::js::context::{AsContextMut, AsContextRef};
use crate::js::export::Export;
use crate::js::exports::{ExportError, Exportable};
use crate::js::store::StoreObject;
use crate::js::store::{AsStoreMut, AsStoreRef};
use crate::js::types::AsJs;
use crate::js::ExternType;
use std::fmt;
@ -34,7 +34,7 @@ pub enum Extern {
impl Extern {
/// Return the underlying type of the inner `Extern`.
pub fn ty(&self, ctx: &impl AsContextRef) -> ExternType {
pub fn ty(&self, ctx: &impl AsStoreRef) -> ExternType {
match self {
Self::Function(ft) => ExternType::Function(ft.ty(ctx).clone()),
Self::Memory(ft) => ExternType::Memory(ft.ty(ctx)),
@ -44,7 +44,7 @@ impl Extern {
}
/// Create an `Extern` from an `wasmer_compiler::Export`.
pub fn from_vm_export(ctx: &mut impl AsContextMut, export: Export) -> Self {
pub fn from_vm_export(ctx: &mut impl AsStoreMut, export: Export) -> Self {
match export {
Export::Function(f) => Self::Function(Function::from_vm_extern(ctx, f)),
Export::Memory(m) => Self::Memory(Memory::from_vm_extern(ctx, m)),
@ -54,12 +54,12 @@ impl Extern {
}
/// Checks whether this `Extern` can be used with the given context.
pub fn is_from_context(&self, ctx: &impl AsContextRef) -> bool {
pub fn is_from_store(&self, ctx: &impl AsStoreRef) -> bool {
match self {
Self::Function(val) => val.is_from_context(ctx),
Self::Memory(val) => val.is_from_context(ctx),
Self::Global(val) => val.is_from_context(ctx),
Self::Table(val) => val.is_from_context(ctx),
Self::Function(val) => val.is_from_store(ctx),
Self::Memory(val) => val.is_from_store(ctx),
Self::Global(val) => val.is_from_store(ctx),
Self::Table(val) => val.is_from_store(ctx),
}
}
@ -74,7 +74,7 @@ impl Extern {
}
impl AsJs for Extern {
fn as_jsvalue(&self, ctx: &impl AsContextRef) -> wasm_bindgen::JsValue {
fn as_jsvalue(&self, ctx: &impl AsStoreRef) -> wasm_bindgen::JsValue {
match self {
Self::Function(_) => self.to_export().as_jsvalue(ctx),
Self::Global(_) => self.to_export().as_jsvalue(ctx),

View File

@ -1,7 +1,7 @@
use crate::js::context::{AsContextMut, AsContextRef, ContextHandle, InternalContextHandle};
use crate::js::export::{VMFunction, VMTable};
use crate::js::exports::{ExportError, Exportable};
use crate::js::externals::Extern;
use crate::js::store::{AsStoreMut, AsStoreRef, InternalStoreHandle, StoreHandle};
use crate::js::value::Value;
use crate::js::RuntimeError;
use crate::js::{FunctionType, TableType};
@ -18,21 +18,21 @@ use js_sys::Function;
/// Spec: <https://webassembly.github.io/spec/core/exec/runtime.html#table-instances>
#[derive(Debug, Clone, PartialEq)]
pub struct Table {
pub(crate) handle: ContextHandle<VMTable>,
pub(crate) handle: StoreHandle<VMTable>,
}
fn set_table_item(table: &VMTable, item_index: u32, item: &Function) -> Result<(), RuntimeError> {
table.table.set(item_index, item).map_err(|e| e.into())
}
fn get_function(ctx: &mut impl AsContextMut, val: Value) -> Result<Function, RuntimeError> {
if !val.is_from_context(ctx) {
fn get_function(ctx: &mut impl AsStoreMut, val: Value) -> Result<Function, RuntimeError> {
if !val.is_from_store(ctx) {
return Err(RuntimeError::new("cannot pass Value across contexts"));
}
match val {
Value::FuncRef(Some(ref func)) => Ok(func
.handle
.get(&ctx.as_context_ref().objects())
.get(&ctx.as_store_ref().objects())
.function
.clone()
.into()),
@ -49,11 +49,11 @@ impl Table {
/// This function will construct the `Table` using the store
/// [`BaseTunables`][crate::js::tunables::BaseTunables].
pub fn new(
ctx: &mut impl AsContextMut,
ctx: &mut impl AsStoreMut,
ty: TableType,
init: Value,
) -> Result<Self, RuntimeError> {
let mut ctx = ctx.as_context_mut();
let mut ctx = ctx;
let descriptor = js_sys::Object::new();
js_sys::Reflect::set(&descriptor, &"initial".into(), &ty.minimum.into())?;
if let Some(max) = ty.maximum {
@ -71,20 +71,20 @@ impl Table {
}
Ok(Self {
handle: ContextHandle::new(ctx.objects_mut(), table),
handle: StoreHandle::new(ctx.objects_mut(), table),
})
}
/// Returns the [`TableType`] of the `Table`.
pub fn ty(&self, ctx: &impl AsContextRef) -> TableType {
self.handle.get(ctx.as_context_ref().objects()).ty
pub fn ty(&self, ctx: &impl AsStoreRef) -> TableType {
self.handle.get(ctx.as_store_ref().objects()).ty
}
/// Retrieves an element of the table at the provided `index`.
pub fn get(&self, ctx: &mut impl AsContextMut, index: u32) -> Option<Value> {
pub fn get(&self, ctx: &mut impl AsStoreMut, index: u32) -> Option<Value> {
if let Some(func) = self
.handle
.get(ctx.as_context_ref().objects())
.get(ctx.as_store_ref().objects())
.table
.get(index)
.ok()
@ -101,24 +101,17 @@ impl Table {
/// Sets an element `val` in the Table at the provided `index`.
pub fn set(
&self,
ctx: &mut impl AsContextMut,
ctx: &mut impl AsStoreMut,
index: u32,
val: Value,
) -> Result<(), RuntimeError> {
let item = get_function(ctx, val)?;
set_table_item(
self.handle.get_mut(ctx.as_context_mut().objects_mut()),
index,
&item,
)
set_table_item(self.handle.get_mut(ctx.objects_mut()), index, &item)
}
/// Retrieves the size of the `Table` (in elements)
pub fn size(&self, ctx: &impl AsContextRef) -> u32 {
self.handle
.get(ctx.as_context_ref().objects())
.table
.length()
pub fn size(&self, ctx: &impl AsStoreRef) -> u32 {
self.handle.get(ctx.as_store_ref().objects()).table.length()
}
/// Grows the size of the `Table` by `delta`, initializating
@ -130,7 +123,12 @@ impl Table {
/// # Errors
///
/// Returns an error if the `delta` is out of bounds for the table.
pub fn grow(&self, _delta: u32, _init: Value) -> Result<u32, RuntimeError> {
pub fn grow(
&self,
store: &mut AsStoreMut,
_delta: u32,
_init: Value,
) -> Result<u32, RuntimeError> {
unimplemented!();
}
@ -152,19 +150,19 @@ impl Table {
}
pub(crate) fn from_vm_extern(
ctx: &mut impl AsContextMut,
internal: InternalContextHandle<VMTable>,
ctx: &mut impl AsStoreMut,
internal: InternalStoreHandle<VMTable>,
) -> Self {
Self {
handle: unsafe {
ContextHandle::from_internal(ctx.as_context_ref().objects().id(), internal)
StoreHandle::from_internal(ctx.as_store_ref().objects().id(), internal)
},
}
}
/// Checks whether this `Table` can be used with the given context.
pub fn is_from_context(&self, ctx: &impl AsContextRef) -> bool {
self.handle.context_id() == ctx.as_context_ref().objects().id()
pub fn is_from_store(&self, ctx: &impl AsStoreRef) -> bool {
self.handle.store_id() == ctx.as_store_ref().objects().id()
}
/// Get access to the backing VM value for this extern. This function is for
@ -177,9 +175,9 @@ impl Table {
#[doc(hidden)]
pub unsafe fn get_vm_table<'context>(
&self,
ctx: &'context impl AsContextRef,
ctx: &'context impl AsStoreRef,
) -> &'context VMTable {
self.handle.get(ctx.as_context_ref().objects())
self.handle.get(ctx.as_store_ref().objects())
}
}

View File

@ -0,0 +1,153 @@
use std::{any::Any, marker::PhantomData};
use crate::js::{StoreHandle, StoreObjects};
use crate::js::{AsStoreMut, AsStoreRef, StoreMut, StoreRef};
#[derive(Debug)]
#[repr(transparent)]
/// An opaque reference to a function environment.
/// The function environment data is owned by the `Store`.
pub struct FunctionEnv<T> {
pub(crate) handle: StoreHandle<VMFunctionEnvironment>,
_phantom: PhantomData<T>,
}
impl<T> FunctionEnv<T> {
/// Make a new extern reference
pub fn new(store: &mut impl AsStoreMut, value: T) -> Self
where
T: Any + Send + 'static + Sized,
{
Self {
handle: StoreHandle::new(
store.as_store_mut().objects_mut(),
VMFunctionEnvironment::new(value),
),
_phantom: PhantomData,
}
}
pub(crate) fn from_handle(handle: StoreHandle<VMFunctionEnvironment>) -> Self {
Self {
handle,
_phantom: PhantomData,
}
}
/// Get the data as reference
pub fn as_ref<'a>(&self, store: &'a impl AsStoreMut) -> &'a T
where
T: Any + Send + 'static + Sized,
{
self.handle
.get(store.as_store_ref().objects())
.as_ref()
.downcast_ref::<T>()
.unwrap()
}
/// Get the data as mutable
pub fn as_mut<'a>(&self, store: &'a mut impl AsStoreMut) -> &'a mut T
where
T: Any + Send + 'static + Sized,
{
self.handle
.get_mut(store.objects_mut())
.as_mut()
.downcast_mut::<T>()
.unwrap()
}
/// Convert it into a `FunctionEnvMut`
pub fn into_mut(self, store: &mut impl AsStoreMut) -> FunctionEnvMut<T>
where
T: Any + Send + 'static + Sized,
{
FunctionEnvMut {
store_mut: store.as_store_mut(),
func_env: self,
}
}
}
impl<T> Clone for FunctionEnv<T> {
fn clone(&self) -> Self {
Self {
handle: self.handle.clone(),
_phantom: self._phantom,
}
}
}
/// A temporary handle to a [`Context`].
pub struct FunctionEnvMut<'a, T: 'a> {
pub(crate) store_mut: StoreMut<'a>,
pub(crate) func_env: FunctionEnv<T>,
}
impl<T: Send + 'static> FunctionEnvMut<'_, T> {
/// Returns a reference to the host state in this context.
pub fn data(&self) -> &T {
self.func_env.as_ref(&self.store_mut)
}
/// Returns a mutable- reference to the host state in this context.
pub fn data_mut<'a>(&'a mut self) -> &'a mut T {
self.func_env.as_mut(&mut self.store_mut)
}
/// Borrows a new mutable reference
pub fn as_mut<'a>(&'a mut self) -> FunctionEnvMut<'a, T> {
FunctionEnvMut {
store_mut: self.store_mut.as_store_mut(),
func_env: self.func_env.clone(),
}
}
}
impl<T> AsStoreRef for FunctionEnvMut<'_, T> {
fn as_store_ref(&self) -> StoreRef<'_> {
StoreRef {
inner: self.store_mut.inner,
}
}
}
impl<T> AsStoreMut for FunctionEnvMut<'_, T> {
fn as_store_mut(&mut self) -> StoreMut<'_> {
StoreMut {
inner: self.store_mut.inner,
}
}
#[inline]
fn objects_mut(&mut self) -> &mut StoreObjects {
&mut self.store_mut.inner.objects
}
}
/// Underlying FunctionEnvironment used by a `VMFunction`.
pub struct VMFunctionEnvironment {
contents: Box<dyn Any + Send + 'static>,
}
impl VMFunctionEnvironment {
/// Wraps the given value to expose it to Wasm code as a function context.
pub fn new(val: impl Any + Send + 'static) -> Self {
Self {
contents: Box::new(val),
}
}
#[allow(clippy::should_implement_trait)]
/// Returns a reference to the underlying value.
pub fn as_ref(&self) -> &(dyn Any + Send + 'static) {
&*self.contents
}
#[allow(clippy::should_implement_trait)]
/// Returns a mutable reference to the underlying value.
pub fn as_mut(&mut self) -> &mut (dyn Any + Send + 'static) {
&mut *self.contents
}
}

View File

@ -1,10 +1,10 @@
//! The import module contains the implementation data structures and helper functions used to
//! manipulate and access a wasm module's imports including memories, tables, globals, and
//! functions.
use crate::js::context::AsContextRef;
use crate::js::error::InstantiationError;
use crate::js::exports::Exports;
use crate::js::module::Module;
use crate::js::store::AsStoreRef;
use crate::js::types::AsJs;
use crate::Extern;
use std::collections::HashMap;
@ -97,7 +97,7 @@ impl Imports {
///
/// # Usage
/// ```no_run
/// # let store = Default::default();
/// # let mut store = Default::default();
/// use wasmer::{Imports, Function};
/// fn foo(n: i32) -> i32 {
/// n
@ -151,7 +151,7 @@ impl Imports {
}
/// Returns the `Imports` as a Javascript `Object`
pub fn as_jsobject(&self, ctx: &impl AsContextRef) -> js_sys::Object {
pub fn as_jsobject(&self, ctx: &impl AsStoreRef) -> js_sys::Object {
let imports = js_sys::Object::new();
let namespaces: HashMap<&str, Vec<(&str, &Extern)>> =
self.map
@ -235,7 +235,7 @@ impl fmt::Debug for Imports {
///
/// ```
/// # use wasmer::{Function, Store};
/// # let store = Store::default();
/// # let mut store = Store::default();
/// use wasmer::imports;
///
/// let import_object = imports! {
@ -300,7 +300,7 @@ mod test {
use crate::js::export::Export;
use wasm_bindgen_test::*;
fn namespace() {
let store = Store::default();
let mut store = Store::default();
let g1 = Global::new(&store, Val::I32(0));
let namespace = namespace! {
"happy" => g1
@ -323,7 +323,7 @@ mod test {
fn imports_macro_allows_trailing_comma_and_none() {
use crate::js::Function;
let store = Default::default();
let mut store = Default::default();
fn func(arg: i32) -> i32 {
arg + 1
@ -372,7 +372,7 @@ mod test {
}
fn chaining_works() {
let store = Store::default();
let mut store = Store::default();
let g = Global::new(&store, Val::I32(0));
let mut imports1 = imports! {
@ -402,7 +402,7 @@ mod test {
}
fn extending_conflict_overwrites() {
let store = Store::default();
let mut store = Store::default();
let g1 = Global::new(&store, Val::I32(0));
let g2 = Global::new(&store, Val::F32(0.));
@ -430,7 +430,7 @@ mod test {
);
// now test it in reverse
let store = Store::default();
let mut store = Store::default();
let g1 = Global::new(&store, Val::I32(0));
let g2 = Global::new(&store, Val::F32(0.));

View File

@ -1,10 +1,10 @@
use crate::js::context::{AsContextMut, AsContextRef, ContextHandle};
use crate::js::error::InstantiationError;
use crate::js::export::Export;
use crate::js::exports::Exports;
use crate::js::externals::Extern;
use crate::js::imports::Imports;
use crate::js::module::Module;
use crate::js::store::{AsStoreMut, AsStoreRef, StoreHandle};
use js_sys::WebAssembly;
use std::fmt;
@ -18,7 +18,7 @@ use std::fmt;
/// Spec: <https://webassembly.github.io/spec/core/exec/runtime.html#module-instances>
#[derive(Clone)]
pub struct Instance {
_handle: ContextHandle<WebAssembly::Instance>,
_handle: StoreHandle<WebAssembly::Instance>,
module: Module,
#[allow(dead_code)]
imports: Imports,
@ -41,7 +41,7 @@ impl Instance {
/// ```
/// # use wasmer::{imports, Store, Module, Global, Value, Instance};
/// # fn main() -> anyhow::Result<()> {
/// let store = Store::default();
/// let mut store = Store::default();
/// let module = Module::new(&store, "(module)")?;
/// let imports = imports!{
/// "host" => {
@ -61,13 +61,13 @@ impl Instance {
/// * Link errors that happen when plugging the imports into the instance
/// * Runtime errors that happen when running the module `start` function.
pub fn new(
ctx: &mut impl AsContextMut,
mut ctx: &mut impl AsStoreMut,
module: &Module,
imports: &Imports,
) -> Result<Self, InstantiationError> {
let import_copy = imports.clone();
let (instance, _imports): (ContextHandle<WebAssembly::Instance>, Vec<Extern>) = module
.instantiate(&mut ctx.as_context_mut(), imports)
let (instance, _imports): (StoreHandle<WebAssembly::Instance>, Vec<Extern>) = module
.instantiate(&mut ctx, imports)
.map_err(|e| InstantiationError::Start(e))?;
let self_instance = Self::from_module_and_instance(ctx, module, instance, import_copy)?;
@ -85,12 +85,12 @@ impl Instance {
///
/// *This method is only available when targeting JS environments*
pub fn from_module_and_instance(
ctx: &mut impl AsContextMut,
mut ctx: &mut impl AsStoreMut,
module: &Module,
instance: ContextHandle<WebAssembly::Instance>,
instance: StoreHandle<WebAssembly::Instance>,
imports: Imports,
) -> Result<Self, InstantiationError> {
let instance_exports = instance.get(ctx.as_context_ref().objects()).exports();
let instance_exports = instance.get(ctx.as_store_ref().objects()).exports();
let exports = module
.exports()
.map(|export_type| {
@ -104,9 +104,8 @@ impl Instance {
))
})?;
let export: Export =
Export::from_js_value(js_export, &mut ctx.as_context_mut(), extern_type)?
.into();
let extern_ = Extern::from_vm_export(&mut ctx.as_context_mut(), export);
Export::from_js_value(js_export, &mut ctx, extern_type)?.into();
let extern_ = Extern::from_vm_export(&mut ctx, export);
Ok((name.to_string(), extern_))
})
.collect::<Result<Exports, InstantiationError>>()?;
@ -126,11 +125,8 @@ impl Instance {
/// Returns the inner WebAssembly Instance
#[doc(hidden)]
pub fn raw<'context>(
&self,
ctx: &'context impl AsContextRef,
) -> &'context WebAssembly::Instance {
&self._handle.get(ctx.as_context_ref().objects())
pub fn raw<'context>(&self, ctx: &'context impl AsStoreRef) -> &'context WebAssembly::Instance {
&self._handle.get(ctx.as_store_ref().objects())
}
}

View File

@ -1,5 +1,5 @@
use crate::js::context::AsContextMut;
use crate::js::error::WasmError;
use crate::js::store::AsStoreMut;
use crate::js::{Export, ExternType, Module};
use std::collections::HashMap;
@ -53,7 +53,7 @@ impl JsImportObject {
/// ```
pub fn get_export(
&self,
ctx: &mut impl AsContextMut,
ctx: &mut impl AsStoreMut,
module: &str,
name: &str,
) -> Result<Export, WasmError> {

View File

@ -1,7 +1,7 @@
use crate::js::context::AsContextRef;
use crate::js::externals::memory::MemoryBuffer;
use crate::RuntimeError;
use crate::{Memory, Memory32, Memory64, WasmPtr};
use crate::js::store::AsStoreRef;
use crate::js::RuntimeError;
use crate::js::{Memory, Memory32, Memory64, WasmPtr};
use std::{
convert::TryInto,
fmt,
@ -61,7 +61,7 @@ pub struct WasmRef<'a, T: ValueType> {
impl<'a, T: ValueType> WasmRef<'a, T> {
/// Creates a new `WasmRef` at the given offset in a memory.
#[inline]
pub fn new(ctx: &'a impl AsContextRef, memory: &'a Memory, offset: u64) -> Self {
pub fn new(ctx: &'a impl AsStoreRef, memory: &'a Memory, offset: u64) -> Self {
Self {
buffer: memory.buffer(ctx),
offset,
@ -160,7 +160,7 @@ impl<'a, T: ValueType> WasmSlice<'a, T> {
/// Returns a `MemoryAccessError` if the slice length overflows.
#[inline]
pub fn new(
ctx: &'a impl AsContextRef,
ctx: &'a impl AsStoreRef,
memory: &'a Memory,
offset: u64,
len: u64,

View File

@ -23,11 +23,11 @@ mod lib {
}
}
mod context;
mod error;
mod export;
mod exports;
mod externals;
mod function_env;
mod imports;
mod instance;
mod js_import_object;
@ -44,7 +44,6 @@ mod types;
mod value;
mod wasm_bindgen_polyfill;
pub use crate::js::context::{AsContextMut, AsContextRef, Context, ContextMut, ContextRef};
pub use crate::js::error::{DeserializeError, InstantiationError, SerializeError};
pub use crate::js::export::Export;
pub use crate::js::exports::{ExportError, Exportable, Exports, ExportsIterator};
@ -52,6 +51,7 @@ pub use crate::js::externals::{
Extern, FromToNativeWasmType, Function, Global, HostFunction, Memory, MemoryError, Table,
WasmTypeList,
};
pub use crate::js::function_env::{FunctionEnv, FunctionEnvMut};
pub use crate::js::imports::Imports;
pub use crate::js::instance::Instance;
pub use crate::js::js_import_object::JsImportObject;
@ -62,7 +62,9 @@ pub use crate::js::native_type::NativeWasmTypeInto;
pub use crate::js::ptr::{Memory32, Memory64, MemorySize, WasmPtr, WasmPtr64};
pub use crate::js::trap::RuntimeError;
pub use crate::js::store::{Store, StoreObject};
pub use crate::js::store::{
AsStoreMut, AsStoreRef, Store, StoreHandle, StoreMut, StoreObject, StoreObjects, StoreRef,
};
pub use crate::js::types::ValType as Type;
pub use crate::js::types::{
ExportType, ExternType, FunctionType, GlobalType, ImportType, MemoryType, Mutability,

View File

@ -1,4 +1,3 @@
use crate::js::context::{AsContextMut, ContextHandle};
#[cfg(feature = "wat")]
use crate::js::error::WasmError;
use crate::js::error::{CompileError, InstantiationError};
@ -7,8 +6,10 @@ use crate::js::error::{DeserializeError, SerializeError};
use crate::js::externals::Extern;
use crate::js::imports::Imports;
use crate::js::store::Store;
use crate::js::store::{AsStoreMut, StoreHandle};
use crate::js::types::{AsJs, ExportType, ImportType};
use crate::js::RuntimeError;
use crate::AsStoreRef;
use js_sys::{Reflect, Uint8Array, WebAssembly};
use std::fmt;
use std::io;
@ -59,7 +60,6 @@ pub struct ModuleTypeHints {
/// contents rather than a deep copy.
#[derive(Clone)]
pub struct Module {
store: Store,
module: WebAssembly::Module,
name: Option<String>,
// WebAssembly type hints
@ -95,7 +95,7 @@ impl Module {
/// ```
/// use wasmer::*;
/// # fn main() -> anyhow::Result<()> {
/// # let store = Store::default();
/// # let mut store = Store::default();
/// let wat = "(module)";
/// let module = Module::new(&store, wat)?;
/// # Ok(())
@ -107,7 +107,7 @@ impl Module {
/// ```
/// use wasmer::*;
/// # fn main() -> anyhow::Result<()> {
/// # let store = Store::default();
/// # let mut store = Store::default();
/// // The following is the same as:
/// // (module
/// // (type $t0 (func (param i32) (result i32)))
@ -129,7 +129,7 @@ impl Module {
/// # }
/// ```
#[allow(unreachable_code)]
pub fn new(store: &Store, bytes: impl AsRef<[u8]>) -> Result<Self, CompileError> {
pub fn new(_store: &impl AsStoreRef, bytes: impl AsRef<[u8]>) -> Result<Self, CompileError> {
#[cfg(feature = "wat")]
let bytes = wat::parse_bytes(bytes.as_ref()).map_err(|e| {
CompileError::Wasm(WasmError::Generic(format!(
@ -137,11 +137,14 @@ impl Module {
e
)))
})?;
Self::from_binary(store, bytes.as_ref())
Self::from_binary(_store, bytes.as_ref())
}
/// Creates a new WebAssembly module from a file path.
pub fn from_file(_store: &Store, _file: impl AsRef<Path>) -> Result<Self, IoCompileError> {
pub fn from_file(
_store: &impl AsStoreRef,
_file: impl AsRef<Path>,
) -> Result<Self, IoCompileError> {
unimplemented!();
}
@ -150,10 +153,10 @@ impl Module {
/// Opposed to [`Module::new`], this function is not compatible with
/// the WebAssembly text format (if the "wat" feature is enabled for
/// this crate).
pub fn from_binary(store: &Store, binary: &[u8]) -> Result<Self, CompileError> {
pub fn from_binary(_store: &impl AsStoreRef, binary: &[u8]) -> Result<Self, CompileError> {
//
// Self::validate(store, binary)?;
unsafe { Self::from_binary_unchecked(store, binary) }
unsafe { Self::from_binary_unchecked(_store, binary) }
}
/// Creates a new WebAssembly module skipping any kind of validation.
@ -163,7 +166,7 @@ impl Module {
/// This is safe since the JS vm should be safe already.
/// We maintain the `unsafe` to preserve the same API as Wasmer
pub unsafe fn from_binary_unchecked(
store: &Store,
_store: &impl AsStoreRef,
binary: &[u8],
) -> Result<Self, CompileError> {
let js_bytes = Uint8Array::view(binary);
@ -194,7 +197,6 @@ impl Module {
let (type_hints, name) = (None, None);
Ok(Self {
store: store.clone(),
module,
type_hints,
name,
@ -209,7 +211,7 @@ impl Module {
/// This validation is normally pretty fast and checks the enabled
/// WebAssembly features in the Store Engine to assure deterministic
/// validation of the Module.
pub fn validate(_store: &Store, binary: &[u8]) -> Result<(), CompileError> {
pub fn validate(_store: &impl AsStoreRef, binary: &[u8]) -> Result<(), CompileError> {
let js_bytes = unsafe { Uint8Array::view(binary) };
match WebAssembly::validate(&js_bytes.into()) {
Ok(true) => Ok(()),
@ -219,16 +221,17 @@ impl Module {
pub(crate) fn instantiate(
&self,
ctx: &mut impl AsContextMut,
store: &mut impl AsStoreMut,
imports: &Imports,
) -> Result<(ContextHandle<WebAssembly::Instance>, Vec<Extern>), RuntimeError> {
// Ensure all imports come from the same context.
) -> Result<(StoreHandle<WebAssembly::Instance>, Vec<Extern>), RuntimeError> {
// Ensure all imports come from the same store.
if imports
.into_iter()
.any(|(_, import)| !import.is_from_context(ctx))
.any(|(_, import)| !import.is_from_store(store))
{
// FIXME is RuntimeError::User appropriate?
return Err(RuntimeError::user(Box::new(InstantiationError::BadContext)));
return Err(RuntimeError::user(Box::new(
InstantiationError::DifferentStores,
)));
}
let imports_object = js_sys::Object::new();
let mut import_externs: Vec<Extern> = vec![];
@ -241,7 +244,7 @@ impl Module {
js_sys::Reflect::set(
&val,
&import_type.name().into(),
&import.as_jsvalue(&ctx.as_context_ref()),
&import.as_jsvalue(&store.as_store_ref()),
)?;
} else {
// If the namespace doesn't exist
@ -249,7 +252,7 @@ impl Module {
js_sys::Reflect::set(
&import_namespace,
&import_type.name().into(),
&import.as_jsvalue(&ctx.as_context_ref()),
&import.as_jsvalue(&store.as_store_ref()),
)?;
js_sys::Reflect::set(
&imports_object,
@ -263,8 +266,8 @@ impl Module {
// the error for us, so we don't need to handle it
}
Ok((
ContextHandle::new(
ctx.as_context_mut().objects_mut(),
StoreHandle::new(
store.as_store_mut().objects_mut(),
WebAssembly::Instance::new(&self.module, &imports_object)
.map_err(|e: JsValue| -> RuntimeError { e.into() })?,
),
@ -282,7 +285,7 @@ impl Module {
/// ```
/// # use wasmer::*;
/// # fn main() -> anyhow::Result<()> {
/// # let store = Store::default();
/// # let mut store = Store::default();
/// let wat = "(module $moduleName)";
/// let module = Module::new(&store, wat)?;
/// assert_eq!(module.name(), Some("moduleName"));
@ -309,8 +312,11 @@ impl Module {
/// This is safe since deserialization under `js` is essentially same as reconstructing `Module`.
/// We maintain the `unsafe` to preserve the same API as Wasmer
#[cfg(feature = "js-serializable-module")]
pub unsafe fn deserialize(store: &Store, bytes: &[u8]) -> Result<Self, DeserializeError> {
Self::new(store, bytes).map_err(|e| DeserializeError::Compiler(e))
pub unsafe fn deserialize(
_store: &impl AsStoreRef,
bytes: &[u8],
) -> Result<Self, DeserializeError> {
Self::new(_store, bytes).map_err(|e| DeserializeError::Compiler(e))
}
/// Sets the name of the current module.
@ -325,7 +331,7 @@ impl Module {
/// ```
/// # use wasmer::*;
/// # fn main() -> anyhow::Result<()> {
/// # let store = Store::default();
/// # let mut store = Store::default();
/// let wat = "(module)";
/// let mut module = Module::new(&store, wat)?;
/// assert_eq!(module.name(), None);
@ -360,7 +366,7 @@ impl Module {
/// ```
/// # use wasmer::*;
/// # fn main() -> anyhow::Result<()> {
/// # let store = Store::default();
/// # let mut store = Store::default();
/// let wat = r#"(module
/// (import "host" "func1" (func))
/// (import "host" "func2" (func))
@ -458,7 +464,7 @@ impl Module {
/// ```
/// # use wasmer::*;
/// # fn main() -> anyhow::Result<()> {
/// # let store = Store::default();
/// # let mut store = Store::default();
/// let wat = r#"(module
/// (func (export "namedfunc"))
/// (memory (export "namedmemory") 1)
@ -530,11 +536,6 @@ impl Module {
// pub fn custom_sections<'a>(&'a self, name: &'a str) -> impl Iterator<Item = Arc<[u8]>> + 'a {
// unimplemented!();
// }
/// Returns the [`Store`] where the `Instance` belongs.
pub fn store(&self) -> &Store {
&self.store
}
}
impl fmt::Debug for Module {
@ -548,7 +549,6 @@ impl fmt::Debug for Module {
impl From<WebAssembly::Module> for Module {
fn from(module: WebAssembly::Module) -> Module {
Module {
store: Store::default(),
module,
name: None,
type_hints: None,

View File

@ -9,8 +9,9 @@
//! ```
use std::marker::PhantomData;
use crate::js::context::{AsContextMut, AsContextRef, ContextHandle};
use crate::js::externals::Function;
use crate::js::store::{AsStoreMut, AsStoreRef, StoreHandle};
use crate::js::FunctionEnv;
use crate::js::{FromToNativeWasmType, RuntimeError, WasmTypeList};
// use std::panic::{catch_unwind, AssertUnwindSafe};
use crate::js::export::VMFunction;
@ -23,7 +24,7 @@ use wasm_bindgen::JsValue;
/// (using the Native ABI).
#[derive(Clone)]
pub struct TypedFunction<Args = (), Rets = ()> {
pub(crate) handle: ContextHandle<VMFunction>,
pub(crate) handle: StoreHandle<VMFunction>,
_phantom: PhantomData<(Args, Rets)>,
}
@ -36,9 +37,13 @@ where
Rets: WasmTypeList,
{
#[allow(dead_code)]
pub(crate) fn new<T>(ctx: &mut impl AsContextMut<Data = T>, vm_function: VMFunction) -> Self {
pub(crate) fn new<T>(
store: &mut impl AsStoreMut,
env: &FunctionEnv<T>,
vm_function: VMFunction,
) -> Self {
Self {
handle: ContextHandle::new(ctx.as_context_mut().objects_mut(), vm_function),
handle: StoreHandle::new(store.as_store_mut().objects_mut(), vm_function),
_phantom: PhantomData,
}
}
@ -61,11 +66,11 @@ macro_rules! impl_native_traits {
{
/// Call the typed func and return results.
#[allow(clippy::too_many_arguments)]
pub fn call(&self, ctx: &mut impl AsContextMut, $( $x: $x, )* ) -> Result<Rets, RuntimeError> where
pub fn call(&self, mut ctx: &mut impl AsStoreMut, $( $x: $x, )* ) -> Result<Rets, RuntimeError> where
$( $x: FromToNativeWasmType + crate::js::NativeWasmTypeInto, )*
{
let params_list: Vec<JsValue> = vec![ $( JsValue::from_f64($x.into_raw(ctx))),* ];
let results = self.handle.get(ctx.as_context_ref().objects()).function.apply(
let params_list: Vec<JsValue> = vec![ $( JsValue::from_f64($x.into_raw(&mut ctx))),* ];
let results = self.handle.get(ctx.as_store_ref().objects()).function.apply(
&JsValue::UNDEFINED,
&Array::from_iter(params_list.iter())
)?;
@ -76,7 +81,7 @@ macro_rules! impl_native_traits {
1 => unsafe {
let ty = Rets::wasm_types()[0];
let val = param_from_js(&ty, &results);
*mut_rets = val.as_raw(&mut ctx.as_context_mut());
*mut_rets = val.as_raw(&mut ctx);
}
_n => {
let results: Array = results.into();
@ -85,7 +90,7 @@ macro_rules! impl_native_traits {
unsafe {
let val = param_from_js(&ret_type, &ret);
let slot = mut_rets.add(i);
*slot = val.as_raw(&mut ctx.as_context_mut());
*slot = val.as_raw(&mut ctx);
}
}
}
@ -101,7 +106,7 @@ macro_rules! impl_native_traits {
$( $x: FromToNativeWasmType, )*
Rets: WasmTypeList,
{
fn get_self_from_extern_with_generics(ctx: &impl AsContextRef, _extern: &crate::js::externals::Extern) -> Result<Self, crate::js::exports::ExportError> {
fn get_self_from_extern_with_generics(ctx: &impl AsStoreRef, _extern: &crate::js::externals::Extern) -> Result<Self, crate::js::exports::ExportError> {
use crate::js::exports::Exportable;
crate::js::Function::get_self_from_extern(_extern)?.native(ctx).map_err(|_| crate::js::exports::ExportError::IncompatibleType)
}

View File

@ -3,113 +3,113 @@
use wasmer_types::{NativeWasmType, Type};
use crate::Function;
use crate::js::Function;
use super::context::AsContextMut;
use super::store::AsStoreMut;
/// `NativeWasmTypeInto` performs conversions from and into `NativeWasmType`
/// types with a context.
pub trait NativeWasmTypeInto: NativeWasmType + Sized {
#[doc(hidden)]
fn into_abi(self, ctx: &mut impl AsContextMut) -> Self::Abi;
fn into_abi(self, ctx: &mut impl AsStoreMut) -> Self::Abi;
#[doc(hidden)]
unsafe fn from_abi(ctx: &mut impl AsContextMut, abi: Self::Abi) -> Self;
unsafe fn from_abi(ctx: &mut impl AsStoreMut, abi: Self::Abi) -> Self;
/// Convert self to raw value representation.
fn into_raw(self, ctx: &mut impl AsContextMut) -> f64;
fn into_raw(self, ctx: &mut impl AsStoreMut) -> f64;
/// Convert to self from raw value representation.
///
/// # Safety
///
unsafe fn from_raw(ctx: &mut impl AsContextMut, raw: f64) -> Self;
unsafe fn from_raw(ctx: &mut impl AsStoreMut, raw: f64) -> Self;
}
impl NativeWasmTypeInto for i32 {
#[inline]
unsafe fn from_abi(_ctx: &mut impl AsContextMut, abi: Self::Abi) -> Self {
unsafe fn from_abi(_ctx: &mut impl AsStoreMut, abi: Self::Abi) -> Self {
abi
}
#[inline]
fn into_abi(self, _ctx: &mut impl AsContextMut) -> Self::Abi {
fn into_abi(self, _ctx: &mut impl AsStoreMut) -> Self::Abi {
self
}
#[inline]
fn into_raw(self, _ctx: &mut impl AsContextMut) -> f64 {
fn into_raw(self, _ctx: &mut impl AsStoreMut) -> f64 {
self.into()
}
#[inline]
unsafe fn from_raw(_ctx: &mut impl AsContextMut, raw: f64) -> Self {
unsafe fn from_raw(_ctx: &mut impl AsStoreMut, raw: f64) -> Self {
raw as _
}
}
impl NativeWasmTypeInto for i64 {
#[inline]
unsafe fn from_abi(_ctx: &mut impl AsContextMut, abi: Self::Abi) -> Self {
unsafe fn from_abi(_ctx: &mut impl AsStoreMut, abi: Self::Abi) -> Self {
abi
}
#[inline]
fn into_abi(self, _ctx: &mut impl AsContextMut) -> Self::Abi {
fn into_abi(self, _ctx: &mut impl AsStoreMut) -> Self::Abi {
self
}
#[inline]
fn into_raw(self, _ctx: &mut impl AsContextMut) -> f64 {
fn into_raw(self, _ctx: &mut impl AsStoreMut) -> f64 {
self as _
}
#[inline]
unsafe fn from_raw(_ctx: &mut impl AsContextMut, raw: f64) -> Self {
unsafe fn from_raw(_ctx: &mut impl AsStoreMut, raw: f64) -> Self {
raw as _
}
}
impl NativeWasmTypeInto for f32 {
#[inline]
unsafe fn from_abi(_ctx: &mut impl AsContextMut, abi: Self::Abi) -> Self {
unsafe fn from_abi(_ctx: &mut impl AsStoreMut, abi: Self::Abi) -> Self {
abi
}
#[inline]
fn into_abi(self, _ctx: &mut impl AsContextMut) -> Self::Abi {
fn into_abi(self, _ctx: &mut impl AsStoreMut) -> Self::Abi {
self
}
#[inline]
fn into_raw(self, _ctx: &mut impl AsContextMut) -> f64 {
fn into_raw(self, _ctx: &mut impl AsStoreMut) -> f64 {
self as _
}
#[inline]
unsafe fn from_raw(_ctx: &mut impl AsContextMut, raw: f64) -> Self {
unsafe fn from_raw(_ctx: &mut impl AsStoreMut, raw: f64) -> Self {
raw as _
}
}
impl NativeWasmTypeInto for f64 {
#[inline]
unsafe fn from_abi(_ctx: &mut impl AsContextMut, abi: Self::Abi) -> Self {
unsafe fn from_abi(_ctx: &mut impl AsStoreMut, abi: Self::Abi) -> Self {
abi
}
#[inline]
fn into_abi(self, _ctx: &mut impl AsContextMut) -> Self::Abi {
fn into_abi(self, _ctx: &mut impl AsStoreMut) -> Self::Abi {
self
}
#[inline]
fn into_raw(self, _ctx: &mut impl AsContextMut) -> f64 {
fn into_raw(self, _ctx: &mut impl AsStoreMut) -> f64 {
self
}
#[inline]
unsafe fn from_raw(_ctx: &mut impl AsContextMut, raw: f64) -> Self {
unsafe fn from_raw(_ctx: &mut impl AsStoreMut, raw: f64) -> Self {
raw
}
}

View File

@ -1,7 +1,7 @@
use crate::js::context::AsContextRef;
use crate::js::store::AsStoreRef;
use crate::js::NativeWasmTypeInto;
use crate::js::{externals::Memory, FromToNativeWasmType};
use crate::{MemoryAccessError, WasmRef, WasmSlice};
use crate::js::{MemoryAccessError, WasmRef, WasmSlice};
use std::convert::TryFrom;
use std::{fmt, marker::PhantomData, mem};
pub use wasmer_types::Memory32;
@ -138,13 +138,13 @@ impl<T: ValueType, M: MemorySize> WasmPtr<T, M> {
/// Creates a `WasmRef` from this `WasmPtr` which allows reading and
/// mutating of the value being pointed to.
#[inline]
pub fn deref<'a>(self, ctx: &'a impl AsContextRef, memory: &'a Memory) -> WasmRef<'a, T> {
pub fn deref<'a>(self, ctx: &'a impl AsStoreRef, memory: &'a Memory) -> WasmRef<'a, T> {
WasmRef::new(ctx, memory, self.offset.into())
}
/// Reads the address pointed to by this `WasmPtr` in a memory.
#[inline]
pub fn read(self, ctx: &impl AsContextRef, memory: &Memory) -> Result<T, MemoryAccessError> {
pub fn read(self, ctx: &impl AsStoreRef, memory: &Memory) -> Result<T, MemoryAccessError> {
self.deref(ctx, memory).read()
}
@ -152,7 +152,7 @@ impl<T: ValueType, M: MemorySize> WasmPtr<T, M> {
#[inline]
pub fn write(
self,
ctx: &impl AsContextRef,
ctx: &impl AsStoreRef,
memory: &Memory,
val: T,
) -> Result<(), MemoryAccessError> {
@ -167,7 +167,7 @@ impl<T: ValueType, M: MemorySize> WasmPtr<T, M> {
#[inline]
pub fn slice<'a>(
self,
ctx: &'a impl AsContextRef,
ctx: &'a impl AsStoreRef,
memory: &'a Memory,
len: M::Offset,
) -> Result<WasmSlice<'a, T>, MemoryAccessError> {
@ -181,7 +181,7 @@ impl<T: ValueType, M: MemorySize> WasmPtr<T, M> {
#[inline]
pub fn read_until<'a>(
self,
ctx: &'a impl AsContextRef,
ctx: &'a impl AsStoreRef,
memory: &'a Memory,
mut end: impl FnMut(&T) -> bool,
) -> Result<Vec<T>, MemoryAccessError> {
@ -206,7 +206,7 @@ impl<M: MemorySize> WasmPtr<u8, M> {
#[inline]
pub fn read_utf8_string<'a>(
self,
ctx: &'a impl AsContextRef,
ctx: &'a impl AsStoreRef,
memory: &'a Memory,
len: M::Offset,
) -> Result<String, MemoryAccessError> {
@ -221,7 +221,7 @@ impl<M: MemorySize> WasmPtr<u8, M> {
#[inline]
pub fn read_utf8_string_with_nul<'a>(
self,
ctx: &'a impl AsContextRef,
ctx: &'a impl AsStoreRef,
memory: &'a Memory,
) -> Result<String, MemoryAccessError> {
let vec = self.read_until(ctx, memory, |&byte| byte == 0)?;

View File

@ -1,5 +1,12 @@
use std::fmt;
/// We require the context to have a fixed memory address for its lifetime since
/// various bits of the VM have raw pointers that point back to it. Hence we
/// wrap the actual context in a box.
pub(crate) struct StoreInner {
pub(crate) objects: StoreObjects,
}
/// The store represents all global state that can be manipulated by
/// WebAssembly programs. It consists of the runtime representation
/// of all instances of functions, tables, memories, and globals that
@ -10,13 +17,18 @@ use std::fmt;
/// [`Tunables`] (that are used to create the memories, tables and globals).
///
/// Spec: <https://webassembly.github.io/spec/core/exec/runtime.html#store>
#[derive(Clone)]
pub struct Store;
pub struct Store {
pub(crate) inner: Box<StoreInner>,
}
impl Store {
/// Creates a new `Store`.
pub fn new() -> Self {
Self
Self {
inner: Box::new(StoreInner {
objects: Default::default(),
}),
}
}
/// Checks whether two stores are identical. A store is considered
@ -57,3 +69,377 @@ pub trait StoreObject {
true
}
}
impl AsStoreRef for Store {
fn as_store_ref(&self) -> StoreRef<'_> {
StoreRef { inner: &self.inner }
}
}
impl AsStoreMut for Store {
fn as_store_mut(&mut self) -> StoreMut<'_> {
StoreMut {
inner: &mut self.inner,
}
}
fn objects_mut(&mut self) -> &mut StoreObjects {
&mut self.inner.objects
}
}
/// A temporary handle to a [`Context`].
pub struct StoreRef<'a> {
pub(crate) inner: &'a StoreInner,
}
impl<'a> StoreRef<'a> {
pub(crate) fn objects(&self) -> &'a StoreObjects {
&self.inner.objects
}
/// Checks whether two stores are identical. A store is considered
/// equal to another store if both have the same engine. The
/// tunables are excluded from the logic.
pub fn same(a: &Self, b: &Self) -> bool {
a.inner.objects.id() == b.inner.objects.id()
}
}
/// A temporary handle to a [`Context`].
pub struct StoreMut<'a> {
pub(crate) inner: &'a mut StoreInner,
}
impl<'a> StoreMut<'a> {
/// Checks whether two stores are identical. A store is considered
/// equal to another store if both have the same engine. The
/// tunables are excluded from the logic.
pub fn same(a: &Self, b: &Self) -> bool {
a.inner.objects.id() == b.inner.objects.id()
}
pub(crate) fn as_raw(&self) -> *mut StoreInner {
self.inner as *const StoreInner as *mut StoreInner
}
pub(crate) unsafe fn from_raw(raw: *mut StoreInner) -> Self {
Self { inner: &mut *raw }
}
}
/// Helper trait for a value that is convertible to a [`StoreRef`].
pub trait AsStoreRef {
/// Returns a `StoreRef` pointing to the underlying context.
fn as_store_ref(&self) -> StoreRef<'_>;
}
/// Helper trait for a value that is convertible to a [`StoreMut`].
pub trait AsStoreMut: AsStoreRef {
/// Returns a `StoreMut` pointing to the underlying context.
fn as_store_mut(&mut self) -> StoreMut<'_>;
/// Returns the ObjectMutable
fn objects_mut(&mut self) -> &mut StoreObjects;
}
impl AsStoreRef for StoreRef<'_> {
fn as_store_ref(&self) -> StoreRef<'_> {
StoreRef { inner: self.inner }
}
}
impl AsStoreRef for StoreMut<'_> {
fn as_store_ref(&self) -> StoreRef<'_> {
StoreRef { inner: self.inner }
}
}
impl AsStoreMut for StoreMut<'_> {
fn as_store_mut(&mut self) -> StoreMut<'_> {
StoreMut { inner: self.inner }
}
fn objects_mut(&mut self) -> &mut StoreObjects {
&mut self.inner.objects
}
}
impl<T: AsStoreRef> AsStoreRef for &'_ T {
fn as_store_ref(&self) -> StoreRef<'_> {
T::as_store_ref(*self)
}
}
impl<T: AsStoreRef> AsStoreRef for &'_ mut T {
fn as_store_ref(&self) -> StoreRef<'_> {
T::as_store_ref(*self)
}
}
impl<T: AsStoreMut> AsStoreMut for &'_ mut T {
fn as_store_mut(&mut self) -> StoreMut<'_> {
T::as_store_mut(*self)
}
fn objects_mut(&mut self) -> &mut StoreObjects {
T::objects_mut(*self)
}
}
pub use objects::*;
use crate::js::FunctionEnv;
mod objects {
use crate::js::{
export::{VMFunction, VMGlobal, VMMemory, VMTable},
function_env::VMFunctionEnvironment,
};
use std::{
cell::UnsafeCell,
fmt,
marker::PhantomData,
num::{NonZeroU64, NonZeroUsize},
ptr::NonNull,
sync::atomic::{AtomicU64, Ordering},
};
/// Unique ID to identify a context.
///
/// Every handle to an object managed by a context also contains the ID of the
/// context. This is used to check that a handle is always used with the
/// correct context.
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub struct StoreId(NonZeroU64);
impl Default for StoreId {
// Allocates a unique ID for a new context.
fn default() -> Self {
// No overflow checking is needed here: overflowing this would take
// thousands of years.
static NEXT_ID: AtomicU64 = AtomicU64::new(1);
Self(NonZeroU64::new(NEXT_ID.fetch_add(1, Ordering::Relaxed)).unwrap())
}
}
/// Trait to represent an object managed by a context. This is implemented on
/// the VM types managed by the context.
pub trait StoreObject: Sized {
fn list(ctx: &StoreObjects) -> &Vec<Self>;
fn list_mut(ctx: &mut StoreObjects) -> &mut Vec<Self>;
}
macro_rules! impl_store_object {
($($field:ident => $ty:ty,)*) => {
$(
impl StoreObject for $ty {
fn list(ctx: &StoreObjects) -> &Vec<Self> {
&ctx.$field
}
fn list_mut(ctx: &mut StoreObjects) -> &mut Vec<Self> {
&mut ctx.$field
}
}
)*
};
}
impl_store_object! {
functions => VMFunction,
tables => VMTable,
globals => VMGlobal,
memories => VMMemory,
instances => js_sys::WebAssembly::Instance,
function_environments => VMFunctionEnvironment,
}
/// Set of objects managed by a context.
#[derive(Default)]
pub struct StoreObjects {
id: StoreId,
memories: Vec<VMMemory>,
tables: Vec<VMTable>,
globals: Vec<VMGlobal>,
functions: Vec<VMFunction>,
instances: Vec<js_sys::WebAssembly::Instance>,
function_environments: Vec<VMFunctionEnvironment>,
}
impl StoreObjects {
/// Returns the ID of this context.
pub fn id(&self) -> StoreId {
self.id
}
/// Returns a pair of mutable references from two handles.
///
/// Panics if both handles point to the same object.
pub fn get_2_mut<T: StoreObject>(
&mut self,
a: InternalStoreHandle<T>,
b: InternalStoreHandle<T>,
) -> (&mut T, &mut T) {
assert_ne!(a.index(), b.index());
let list = T::list_mut(self);
if a.index() < b.index() {
let (low, high) = list.split_at_mut(b.index());
(&mut low[a.index()], &mut high[0])
} else {
let (low, high) = list.split_at_mut(a.index());
(&mut high[0], &mut low[a.index()])
}
}
}
/// Handle to an object managed by a context.
///
/// Internally this is just an integer index into a context. A reference to the
/// context must be passed in separately to access the actual object.
pub struct StoreHandle<T> {
id: StoreId,
internal: InternalStoreHandle<T>,
}
impl<T> core::cmp::PartialEq for StoreHandle<T> {
fn eq(&self, other: &Self) -> bool {
self.id == other.id
}
}
impl<T> Clone for StoreHandle<T> {
fn clone(&self) -> Self {
Self {
id: self.id,
internal: self.internal,
}
}
}
impl<T: StoreObject> fmt::Debug for StoreHandle<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("StoreHandle")
.field("id", &self.id)
.field("internal", &self.internal.index())
.finish()
}
}
impl<T: StoreObject> StoreHandle<T> {
/// Moves the given object into a context and returns a handle to it.
pub fn new(ctx: &mut StoreObjects, val: T) -> Self {
Self {
id: ctx.id,
internal: InternalStoreHandle::new(ctx, val),
}
}
/// Returns a reference to the object that this handle points to.
pub fn get<'a>(&self, ctx: &'a StoreObjects) -> &'a T {
assert_eq!(self.id, ctx.id, "object used with the wrong context");
self.internal.get(ctx)
}
/// Returns a mutable reference to the object that this handle points to.
pub fn get_mut<'a>(&self, ctx: &'a mut StoreObjects) -> &'a mut T {
assert_eq!(self.id, ctx.id, "object used with the wrong context");
self.internal.get_mut(ctx)
}
/// Returns the internal handle contains within this handle.
pub fn internal_handle(&self) -> InternalStoreHandle<T> {
self.internal
}
/// Returns the ID of the context associated with the handle.
pub fn store_id(&self) -> StoreId {
self.id
}
/// Constructs a `StoreHandle` from a `StoreId` and an `InternalStoreHandle`.
///
/// # Safety
/// Handling `InternalStoreHandle` values is unsafe because they do not track context ID.
pub unsafe fn from_internal(id: StoreId, internal: InternalStoreHandle<T>) -> Self {
Self { id, internal }
}
}
/// Internal handle to an object owned by the current context.
///
/// Unlike `StoreHandle` this does not track the context ID: it is only
/// intended to be used within objects already owned by a context.
#[repr(transparent)]
pub struct InternalStoreHandle<T> {
// Use a NonZero here to reduce the size of Option<InternalStoreHandle>.
idx: NonZeroUsize,
marker: PhantomData<fn() -> T>,
}
impl<T> Clone for InternalStoreHandle<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T> Copy for InternalStoreHandle<T> {}
impl<T> fmt::Debug for InternalStoreHandle<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("InternalStoreHandle")
.field("idx", &self.idx)
.finish()
}
}
impl<T> PartialEq for InternalStoreHandle<T> {
fn eq(&self, other: &Self) -> bool {
self.idx == other.idx
}
}
impl<T> Eq for InternalStoreHandle<T> {}
impl<T: StoreObject> InternalStoreHandle<T> {
/// Moves the given object into a context and returns a handle to it.
pub fn new(ctx: &mut StoreObjects, val: T) -> Self {
let list = T::list_mut(ctx);
let idx = NonZeroUsize::new(list.len() + 1).unwrap();
list.push(val);
Self {
idx,
marker: PhantomData,
}
}
/// Returns a reference to the object that this handle points to.
pub fn get<'a>(&self, ctx: &'a StoreObjects) -> &'a T {
&T::list(ctx)[self.idx.get() - 1]
}
/// Returns a mutable reference to the object that this handle points to.
pub fn get_mut<'a>(&self, ctx: &'a mut StoreObjects) -> &'a mut T {
&mut T::list_mut(ctx)[self.idx.get() - 1]
}
pub(crate) fn index(&self) -> usize {
self.idx.get()
}
pub(crate) fn from_index(idx: usize) -> Option<Self> {
NonZeroUsize::new(idx).map(|idx| Self {
idx,
marker: PhantomData,
})
}
}
/// Data used by the generated code is generally located inline within the
/// `VMContext` for items defined in an instance. Host-defined objects are
/// allocated separately and owned directly by the context.
pub enum MaybeInstanceOwned<T> {
/// The data is owned here.
Host(Box<UnsafeCell<T>>),
/// The data is stored inline in the `VMContext` of an instance.
Instance(NonNull<T>),
}
impl<T> MaybeInstanceOwned<T> {
/// Returns underlying pointer to the VM data.
pub fn as_ptr(&self) -> NonNull<T> {
match self {
MaybeInstanceOwned::Host(p) => unsafe { NonNull::new_unchecked(p.get()) },
MaybeInstanceOwned::Instance(p) => *p,
}
}
}
}

View File

@ -1,7 +1,7 @@
//use crate::js::externals::Function;
// use crate::js::store::{Store, StoreObject};
// use crate::js::RuntimeError;
use crate::js::context::AsContextRef;
use crate::js::store::AsStoreRef;
use crate::js::value::Value;
use wasm_bindgen::JsValue;
pub use wasmer_types::{
@ -19,7 +19,7 @@ pub use wasmer_types::{
//pub type Value = Value<Function>;
pub trait AsJs {
fn as_jsvalue(&self, ctx: &impl AsContextRef) -> JsValue;
fn as_jsvalue(&self, ctx: &impl AsStoreRef) -> JsValue;
}
#[inline]
@ -37,7 +37,7 @@ pub fn param_from_js(ty: &ValType, js_val: &JsValue) -> Value {
}
impl AsJs for Value {
fn as_jsvalue(&self, ctx: &impl AsContextRef) -> JsValue {
fn as_jsvalue(&self, ctx: &impl AsStoreRef) -> JsValue {
match self {
Self::I32(i) => JsValue::from_f64(*i as f64),
Self::I64(i) => JsValue::from_f64(*i as f64),
@ -45,7 +45,7 @@ impl AsJs for Value {
Self::F64(f) => JsValue::from_f64(*f),
Self::FuncRef(Some(func)) => func
.handle
.get(ctx.as_context_ref().objects())
.get(ctx.as_store_ref().objects())
.function
.clone()
.into(),

View File

@ -7,7 +7,7 @@ use wasmer_types::Type;
//use crate::ExternRef;
use crate::js::externals::function::Function;
use super::context::AsContextRef;
use super::store::AsStoreRef;
/// WebAssembly computations manipulate values of basic value types:
/// * Integers (32 or 64 bit width)
@ -82,7 +82,7 @@ impl Value {
}
/// Converts the `Value` into a `f64`.
pub fn as_raw(&self, ctx: &impl AsContextRef) -> f64 {
pub fn as_raw(&self, ctx: &impl AsStoreRef) -> f64 {
match *self {
Self::I32(v) => v as f64,
Self::I64(v) => v as f64,
@ -90,7 +90,7 @@ impl Value {
Self::F64(v) => v,
Self::FuncRef(Some(ref f)) => f
.handle
.get(ctx.as_context_ref().objects())
.get(ctx.as_store_ref().objects())
.function
.as_f64()
.unwrap_or(0_f64), //TODO is this correct?
@ -105,7 +105,7 @@ impl Value {
///
/// # Safety
///
pub unsafe fn from_raw(_ctx: &impl AsContextRef, ty: Type, raw: f64) -> Self {
pub unsafe fn from_raw(_ctx: &impl AsStoreRef, ty: Type, raw: f64) -> Self {
match ty {
Type::I32 => Self::I32(raw as i32),
Type::I64 => Self::I64(raw as i64),
@ -128,7 +128,7 @@ impl Value {
///
/// Externref and funcref values are tied to a context and can only be used
/// with that context.
pub fn is_from_context(&self, ctx: &impl AsContextRef) -> bool {
pub fn is_from_store(&self, ctx: &impl AsStoreRef) -> bool {
match self {
Self::I32(_)
| Self::I64(_)
@ -136,8 +136,8 @@ impl Value {
| Self::F64(_)
//| Self::ExternRef(None)
| Self::FuncRef(None) => true,
//Self::ExternRef(Some(e)) => e.is_from_context(ctx),
Self::FuncRef(Some(f)) => f.is_from_context(ctx),
//Self::ExternRef(Some(e)) => e.is_from_store(ctx),
Self::FuncRef(Some(f)) => f.is_from_store(ctx),
}
}

View File

@ -41,7 +41,7 @@
//!
//! ```rust
//! use wasmer::{Store, Module, Instance, Value, imports};
//! use wasmer::Context as WasmerContext;
//! use wasmer::FunctionEnv;
//!
//! fn main() -> anyhow::Result<()> {
//! let module_wat = r#"
@ -53,15 +53,15 @@
//! i32.add))
//! "#;
//!
//! let store = Store::default();
//! let mut ctx = WasmerContext::new(&store, ());
//! let mut store = Store::default();
//! let env = FunctionEnv::new(&mut store, ());
//! let module = Module::new(&store, &module_wat)?;
//! // The module doesn't import anything, so we create an empty import object.
//! let import_object = imports! {};
//! let instance = Instance::new(&mut ctx, &module, &import_object)?;
//! let instance = Instance::new(&mut store, &module, &import_object)?;
//!
//! let add_one = instance.exports.get_function("add_one")?;
//! let result = add_one.call(&mut ctx, &[Value::I32(42)])?;
//! let result = add_one.call(&mut store, &[Value::I32(42)])?;
//! assert_eq!(result[0], Value::I32(43));
//!
//! Ok(())
@ -151,13 +151,12 @@
//! [`imports`] macro:
//!
//! ```
//! # use wasmer::{imports, Function, Memory, MemoryType, Store, Imports};
//! # use wasmer::ContextMut;
//! # fn imports_example(mut ctx: ContextMut<()>, store: &Store) -> Imports {
//! let memory = Memory::new(&mut ctx, MemoryType::new(1, None, false)).unwrap();
//! # use wasmer::{imports, Function, FunctionEnv, FunctionEnvMut, Memory, MemoryType, Store, Imports};
//! # fn imports_example(mut ctx: FunctionEnv<()>, mut store: &mut Store) -> Imports {
//! let memory = Memory::new(&mut store, MemoryType::new(1, None, false)).unwrap();
//! imports! {
//! "env" => {
//! "my_function" => Function::new_native(&mut ctx, |_ctx: ContextMut<()>| println!("Hello")),
//! "my_function" => Function::new_native(&mut store, &ctx, |_ctx: FunctionEnvMut<()>| println!("Hello")),
//! "memory" => memory,
//! }
//! }
@ -168,12 +167,12 @@
//! from any instance via `instance.exports`:
//!
//! ```
//! # use wasmer::{imports, Instance, Function, Memory, TypedFunction, ContextMut};
//! # fn exports_example(mut ctx: ContextMut<()>, instance: &Instance) -> anyhow::Result<()> {
//! # use wasmer::{imports, Instance, FunctionEnv, Memory, TypedFunction, Store};
//! # fn exports_example(mut ctx: FunctionEnv<()>, mut store: &mut Store, instance: &Instance) -> anyhow::Result<()> {
//! let memory = instance.exports.get_memory("memory")?;
//! let memory: &Memory = instance.exports.get("some_other_memory")?;
//! let add: TypedFunction<(i32, i32), i32> = instance.exports.get_typed_function(&mut ctx, "add")?;
//! let result = add.call(&mut ctx, 5, 37)?;
//! let add: TypedFunction<(i32, i32), i32> = instance.exports.get_typed_function(&mut store, "add")?;
//! let result = add.call(&mut store, 5, 37)?;
//! assert_eq!(result, 42);
//! # Ok(())
//! # }
@ -395,7 +394,7 @@
//! i32.const 1
//! i32.add))
//! "#;
//! let store = Store::default();
//! let mut store = Store::default();
//! let module = Module::new(&store, &module_wat).unwrap();
//! // The module doesn't import anything, so we create an empty import object.
//! let import_object = imports! {};

View File

@ -1,199 +0,0 @@
use wasmer_vm::ContextObjects;
use crate::Store;
/// We require the context to have a fixed memory address for its lifetime since
/// various bits of the VM have raw pointers that point back to it. Hence we
/// wrap the actual context in a box.
pub(crate) struct ContextInner<T> {
pub(crate) objects: ContextObjects,
pub(crate) store: Store,
pub(crate) data: T,
}
/// A context containing a set of WebAssembly instances, along with host state.
///
/// All WebAssembly instances must exist within a context. In the majority of
/// cases each instance will have its own context, but it is possible to have
/// multiple instances in a context when these instances need to interact with
/// each other, for example sharing a memory between instances or calling
/// functions in another instance.
///
/// The lifetimes of run-time WebAssembly objects, notably [`Instance`],
/// [`Memory`], [`Global`], [`Table`] and [`Function`] is tied to a context:
/// the backing memory for these objects is only freed when the context is
/// freed.
///
/// The `T` generic parameter allows arbitrary data to be attached to a context.
/// This data can be accessed using the [`Context::data`] and
/// [`Context::data_mut`] methods. Host functions defined using
/// [`Function::new`] and [`Function::new_native`] receive
/// a reference to the context when they are called.
pub struct Context<T> {
pub(crate) inner: Box<ContextInner<T>>,
}
impl<T> Context<T> {
/// Creates a new context with the given host state.
// TODO: Eliminate the Store type and move its functionality into Engine.
pub fn new(store: &Store, data: T) -> Self {
Self {
inner: Box::new(ContextInner {
objects: Default::default(),
store: store.clone(),
data,
}),
}
}
/// Returns a reference to the host state in this context.
pub fn data(&self) -> &T {
&self.inner.data
}
/// Returns a mutable- reference to the host state in this context.
pub fn data_mut(&mut self) -> &mut T {
&mut self.inner.data
}
/// Drops the context and returns the host state that was stored in it.
pub fn into_data(self) -> T {
self.inner.data
}
/// Returns a reference to the `Store` of this context.
pub fn store(&self) -> &Store {
&self.inner.store
}
/// For use with the C API
/// # Safety
///
/// This is unsafe.
pub unsafe fn transmute_data<U>(&mut self) -> &mut Context<U> {
core::mem::transmute::<&mut Self, &mut Context<U>>(self)
}
}
/// A temporary handle to a [`Context`].
pub struct ContextRef<'a, T: 'a> {
inner: &'a ContextInner<T>,
}
impl<'a, T> ContextRef<'a, T> {
/// Returns a reference to the host state in this context.
pub fn data(&self) -> &'a T {
&self.inner.data
}
/// Returns a reference to the `Store` of this context.
pub fn store(&self) -> &Store {
&self.inner.store
}
pub(crate) fn objects(&self) -> &'a ContextObjects {
&self.inner.objects
}
}
/// A temporary handle to a [`Context`].
pub struct ContextMut<'a, T: 'a> {
inner: &'a mut ContextInner<T>,
}
impl<T> ContextMut<'_, T> {
/// Returns a reference to the host state in this context.
pub fn data(&self) -> &T {
&self.inner.data
}
/// Returns a mutable- reference to the host state in this context.
pub fn data_mut(&mut self) -> &mut T {
&mut self.inner.data
}
pub(crate) fn objects_mut(&mut self) -> &mut ContextObjects {
&mut self.inner.objects
}
/// Returns a reference to the `Store` of this context.
pub fn store(&self) -> &Store {
&self.inner.store
}
pub(crate) fn as_raw(&self) -> *mut ContextInner<T> {
self.inner as *const ContextInner<T> as *mut ContextInner<T>
}
pub(crate) unsafe fn from_raw(raw: *mut ContextInner<T>) -> Self {
Self { inner: &mut *raw }
}
}
/// Helper trait for a value that is convertible to a [`ContextRef`].
pub trait AsContextRef {
/// Host state associated with the [`Context`].
type Data;
/// Returns a `ContextRef` pointing to the underlying context.
fn as_context_ref(&self) -> ContextRef<'_, Self::Data>;
}
/// Helper trait for a value that is convertible to a [`ContextMut`].
pub trait AsContextMut: AsContextRef {
/// Returns a `ContextMut` pointing to the underlying context.
fn as_context_mut(&mut self) -> ContextMut<'_, Self::Data>;
}
impl<T> AsContextRef for Context<T> {
type Data = T;
fn as_context_ref(&self) -> ContextRef<'_, Self::Data> {
ContextRef { inner: &self.inner }
}
}
impl<T> AsContextMut for Context<T> {
fn as_context_mut(&mut self) -> ContextMut<'_, Self::Data> {
ContextMut {
inner: &mut self.inner,
}
}
}
impl<T> AsContextRef for ContextRef<'_, T> {
type Data = T;
fn as_context_ref(&self) -> ContextRef<'_, Self::Data> {
ContextRef { inner: self.inner }
}
}
impl<T> AsContextRef for ContextMut<'_, T> {
type Data = T;
fn as_context_ref(&self) -> ContextRef<'_, Self::Data> {
ContextRef { inner: self.inner }
}
}
impl<T> AsContextMut for ContextMut<'_, T> {
fn as_context_mut(&mut self) -> ContextMut<'_, Self::Data> {
ContextMut { inner: self.inner }
}
}
impl<T: AsContextRef> AsContextRef for &'_ T {
type Data = T::Data;
fn as_context_ref(&self) -> ContextRef<'_, Self::Data> {
T::as_context_ref(*self)
}
}
impl<T: AsContextRef> AsContextRef for &'_ mut T {
type Data = T::Data;
fn as_context_ref(&self) -> ContextRef<'_, Self::Data> {
T::as_context_ref(*self)
}
}
impl<T: AsContextMut> AsContextMut for &'_ mut T {
fn as_context_mut(&mut self) -> ContextMut<'_, Self::Data> {
T::as_context_mut(*self)
}
}

View File

@ -1,4 +1,4 @@
use super::context::AsContextRef;
use super::store::AsStoreRef;
use crate::sys::externals::{Extern, Function, Global, Memory, Table};
use crate::sys::native::TypedFunction;
use crate::sys::WasmTypeList;
@ -18,16 +18,16 @@ use thiserror::Error;
///
/// ```should_panic
/// # use wasmer::{imports, wat2wasm, Function, Instance, Module, Store, Type, Value, ExportError};
/// # use wasmer::Context as WasmerContext;
/// # let store = Store::default();
/// # let mut ctx = WasmerContext::new(&store, ());
/// # use wasmer::FunctionEnv;
/// # let mut store = Store::default();
/// # let env = FunctionEnv::new(&mut store, ());
/// # let wasm_bytes = wat2wasm(r#"
/// # (module
/// # (global $one (export "glob") f32 (f32.const 1)))
/// # "#.as_bytes()).unwrap();
/// # let module = Module::new(&store, wasm_bytes).unwrap();
/// # let import_object = imports! {};
/// # let instance = Instance::new(&mut ctx, &module, &import_object).unwrap();
/// # let instance = Instance::new(&mut store, &module, &import_object).unwrap();
/// #
/// // This results with an error: `ExportError::IncompatibleType`.
/// let export = instance.exports.get_function("glob").unwrap();
@ -37,13 +37,13 @@ use thiserror::Error;
///
/// ```should_panic
/// # use wasmer::{imports, wat2wasm, Function, Instance, Module, Store, Type, Value, ExportError};
/// # use wasmer::Context as WasmerContext;
/// # let store = Store::default();
/// # let mut ctx = WasmerContext::new(&store, ());
/// # use wasmer::FunctionEnv;
/// # let mut store = Store::default();
/// # let env = FunctionEnv::new(&mut store, ());
/// # let wasm_bytes = wat2wasm("(module)".as_bytes()).unwrap();
/// # let module = Module::new(&store, wasm_bytes).unwrap();
/// # let import_object = imports! {};
/// # let instance = Instance::new(&mut ctx, &module, &import_object).unwrap();
/// # let instance = Instance::new(&mut store, &module, &import_object).unwrap();
/// #
/// // This results with an error: `ExportError::Missing`.
/// let export = instance.exports.get_function("unknown").unwrap();
@ -145,7 +145,7 @@ impl Exports {
/// Get an export as a `TypedFunction`.
pub fn get_native_function<Args, Rets>(
&self,
ctx: &impl AsContextRef,
ctx: &impl AsStoreRef,
name: &str,
) -> Result<TypedFunction<Args, Rets>, ExportError>
where
@ -158,7 +158,7 @@ impl Exports {
/// Get an export as a `TypedFunction`.
pub fn get_typed_function<Args, Rets>(
&self,
ctx: &impl AsContextRef,
ctx: &impl AsStoreRef,
name: &str,
) -> Result<TypedFunction<Args, Rets>, ExportError>
where

View File

@ -1,34 +1,34 @@
use std::any::Any;
use wasmer_vm::{ContextHandle, VMExternObj, VMExternRef};
use wasmer_vm::{StoreHandle, VMExternObj, VMExternRef};
use super::context::{AsContextMut, AsContextRef};
use super::store::{AsStoreMut, AsStoreRef};
#[derive(Debug, Clone)]
#[repr(transparent)]
/// An opaque reference to some data. This reference can be passed through Wasm.
pub struct ExternRef {
handle: ContextHandle<VMExternObj>,
handle: StoreHandle<VMExternObj>,
}
impl ExternRef {
/// Make a new extern reference
pub fn new<T>(ctx: &mut impl AsContextMut, value: T) -> Self
pub fn new<T>(ctx: &mut impl AsStoreMut, value: T) -> Self
where
T: Any + Send + Sync + 'static + Sized,
{
Self {
handle: ContextHandle::new(ctx.as_context_mut().objects_mut(), VMExternObj::new(value)),
handle: StoreHandle::new(ctx.objects_mut(), VMExternObj::new(value)),
}
}
/// Try to downcast to the given value.
pub fn downcast<'a, T>(&self, ctx: &'a impl AsContextRef) -> Option<&'a T>
pub fn downcast<'a, T>(&self, ctx: &'a impl AsStoreRef) -> Option<&'a T>
where
T: Any + Send + Sync + 'static + Sized,
{
self.handle
.get(ctx.as_context_ref().objects())
.get(ctx.as_store_ref().objects())
.as_ref()
.downcast_ref::<T>()
}
@ -38,14 +38,11 @@ impl ExternRef {
}
pub(crate) unsafe fn from_vm_externref(
ctx: &mut impl AsContextMut,
ctx: &mut impl AsStoreMut,
vm_externref: VMExternRef,
) -> Self {
Self {
handle: ContextHandle::from_internal(
ctx.as_context_mut().objects_mut().id(),
vm_externref.0,
),
handle: StoreHandle::from_internal(ctx.objects_mut().id(), vm_externref.0),
}
}
@ -56,7 +53,7 @@ impl ExternRef {
///
/// Externref and funcref values are tied to a context and can only be used
/// with that context.
pub fn is_from_context(&self, ctx: &impl AsContextRef) -> bool {
self.handle.context_id() == ctx.as_context_ref().objects().id()
pub fn is_from_store(&self, ctx: &impl AsStoreRef) -> bool {
self.handle.store_id() == ctx.as_store_ref().objects().id()
}
}

View File

@ -1,11 +1,11 @@
use crate::sys::context::{AsContextMut, AsContextRef, ContextInner, ContextMut};
use crate::sys::exports::{ExportError, Exportable};
use crate::sys::externals::Extern;
use crate::sys::store::{AsStoreMut, AsStoreRef, StoreInner, StoreMut};
use crate::sys::FunctionType;
use crate::sys::RuntimeError;
use crate::sys::TypedFunction;
use crate::Value;
use crate::{FunctionEnv, FunctionEnvMut, Value};
use inner::StaticFunction;
pub use inner::{FromToNativeWasmType, HostFunction, WasmTypeList};
use std::cell::UnsafeCell;
@ -13,10 +13,10 @@ use std::cmp::max;
use std::ffi::c_void;
use wasmer_types::RawValue;
use wasmer_vm::{
on_host_stack, raise_user_trap, resume_panic, wasmer_call_trampoline, ContextHandle,
InternalContextHandle, MaybeInstanceOwned, VMCallerCheckedAnyfunc, VMContext,
VMDynamicFunctionContext, VMExtern, VMFuncRef, VMFunction, VMFunctionBody,
VMFunctionEnvironment, VMFunctionKind, VMTrampoline,
on_host_stack, raise_user_trap, resume_panic, wasmer_call_trampoline, InternalStoreHandle,
MaybeInstanceOwned, StoreHandle, VMCallerCheckedAnyfunc, VMContext, VMDynamicFunctionContext,
VMExtern, VMFuncRef, VMFunction, VMFunctionBody, VMFunctionContext, VMFunctionKind,
VMTrampoline,
};
/// A WebAssembly `function` instance.
@ -38,7 +38,7 @@ use wasmer_vm::{
/// [Closures as host functions tracking issue](https://github.com/wasmerio/wasmer/issues/1840)
#[derive(Debug, Clone)]
pub struct Function {
pub(crate) handle: ContextHandle<VMFunction>,
pub(crate) handle: StoreHandle<VMFunction>,
}
impl Function {
@ -50,14 +50,13 @@ impl Function {
/// # Examples
///
/// ```
/// # use wasmer::{Function, FunctionType, Type, Store, Value};
/// # use wasmer::Context as WasmerContext;
/// # let store = Store::default();
/// # let mut ctx = WasmerContext::new(&store, ());
/// # use wasmer::{Function, FunctionEnv, FunctionType, Type, Store, Value};
/// # let mut store = Store::default();
/// # let env = FunctionEnv::new(&mut store, ());
/// #
/// let signature = FunctionType::new(vec![Type::I32, Type::I32], vec![Type::I32]);
///
/// let f = Function::new(&mut ctx, &signature, |_ctx, args| {
/// let f = Function::new(&mut store, &env, &signature, |_ctx, args| {
/// let sum = args[0].unwrap_i32() + args[1].unwrap_i32();
/// Ok(vec![Value::I32(sum)])
/// });
@ -66,38 +65,47 @@ impl Function {
/// With constant signature:
///
/// ```
/// # use wasmer::{Function, FunctionType, Type, Store, Value};
/// # use wasmer::Context as WasmerContext;
/// # let store = Store::default();
/// # let mut ctx = WasmerContext::new(&store, ());
/// # use wasmer::{Function, FunctionEnv, FunctionType, Type, Store, Value};
/// # let mut store = Store::default();
/// # let env = FunctionEnv::new(&mut store, ());
/// #
/// const I32_I32_TO_I32: ([Type; 2], [Type; 1]) = ([Type::I32, Type::I32], [Type::I32]);
///
/// let f = Function::new(&mut ctx, I32_I32_TO_I32, |_ctx, args| {
/// let f = Function::new(&mut store, &env, I32_I32_TO_I32, |_ctx, args| {
/// let sum = args[0].unwrap_i32() + args[1].unwrap_i32();
/// Ok(vec![Value::I32(sum)])
/// });
/// ```
pub fn new<FT, F, T>(ctx: &mut impl AsContextMut<Data = T>, ty: FT, func: F) -> Self
pub fn new<FT, F, T: Send + 'static>(
store: &mut impl AsStoreMut,
env: &FunctionEnv<T>,
ty: FT,
func: F,
) -> Self
where
FT: Into<FunctionType>,
F: Fn(ContextMut<'_, T>, &[Value]) -> Result<Vec<Value>, RuntimeError>
F: Fn(FunctionEnvMut<T>, &[Value]) -> Result<Vec<Value>, RuntimeError>
+ 'static
+ Send
+ Sync,
{
let mut ctx = ctx.as_context_mut();
let function_type = ty.into();
let func_ty = function_type.clone();
let raw_ctx = ctx.as_raw() as *mut u8;
let func_env = env.clone();
let raw_store = store.as_store_mut().as_raw() as *mut u8;
let wrapper = move |values_vec: *mut RawValue| -> Result<(), RuntimeError> {
unsafe {
let mut ctx = ContextMut::from_raw(raw_ctx as *mut ContextInner<T>);
let mut store = StoreMut::from_raw(raw_store as *mut StoreInner);
let mut args = Vec::with_capacity(func_ty.params().len());
for (i, ty) in func_ty.params().iter().enumerate() {
args.push(Value::from_raw(&mut ctx, *ty, *values_vec.add(i)));
args.push(Value::from_raw(&mut store, *ty, *values_vec.add(i)));
}
let returns = func(ctx.as_context_mut(), &args)?;
let store_mut = StoreMut::from_raw(raw_store as *mut StoreInner);
let env = FunctionEnvMut {
store_mut,
func_env: func_env.clone(),
};
let returns = func(env, &args)?;
// We need to dynamically check that the returns
// match the expected types, as well as expected length.
@ -110,7 +118,7 @@ impl Function {
)));
}
for (i, ret) in returns.iter().enumerate() {
*values_vec.add(i) = ret.as_raw(&ctx);
*values_vec.add(i) = ret.as_raw(&store);
}
}
Ok(())
@ -125,8 +133,11 @@ impl Function {
// The engine linker will replace the address with one pointing to a
// generated dynamic trampoline.
let func_ptr = std::ptr::null() as *const VMFunctionBody;
let type_index = ctx.store().engine().register_signature(&function_type);
let vmctx = VMFunctionEnvironment {
let type_index = store
.as_store_mut()
.engine()
.register_signature(&function_type);
let vmctx = VMFunctionContext {
host_env: host_data.as_ref() as *const _ as *mut c_void,
};
let call_trampoline = host_data.ctx.call_trampoline_address();
@ -144,7 +155,7 @@ impl Function {
host_data,
};
Self {
handle: ContextHandle::new(ctx.objects_mut(), vm_function),
handle: StoreHandle::new(store.as_store_mut().objects_mut(), vm_function),
}
}
@ -156,33 +167,41 @@ impl Function {
/// # Example
///
/// ```
/// # use wasmer::{ContextMut, Store, Function};
/// # use wasmer::Context as WasmerContext;
/// # let store = Store::default();
/// # let mut ctx = WasmerContext::new(&store, ());
/// # use wasmer::{Store, Function, FunctionEnv, FunctionEnvMut};
/// # let mut store = Store::default();
/// # let env = FunctionEnv::new(&mut store, ());
/// #
/// fn sum(_ctx: ContextMut<()>, a: i32, b: i32) -> i32 {
/// fn sum(_ctx: FunctionEnvMut<()>, a: i32, b: i32) -> i32 {
/// a + b
/// }
///
/// let f = Function::new_native(&mut ctx, sum);
/// let f = Function::new_native(&mut store, &env, sum);
/// ```
pub fn new_native<T, F, Args, Rets>(ctx: &mut impl AsContextMut<Data = T>, func: F) -> Self
pub fn new_native<T: Send + 'static, F, Args, Rets>(
store: &mut impl AsStoreMut,
env: &FunctionEnv<T>,
func: F,
) -> Self
where
F: HostFunction<T, Args, Rets> + 'static + Send + Sync,
Args: WasmTypeList,
Rets: WasmTypeList,
{
let mut ctx = ctx.as_context_mut();
// println!("new native {:p}", &new_ctx);
let host_data = Box::new(StaticFunction {
raw_ctx: ctx.as_raw() as *mut u8,
raw_store: store.as_store_mut().as_raw() as *mut u8,
env: env.clone(),
func,
});
let function_type = FunctionType::new(Args::wasm_types(), Rets::wasm_types());
let func_ptr = <F as HostFunction<T, Args, Rets>>::function_body_ptr();
let type_index = ctx.store().engine().register_signature(&function_type);
let vmctx = VMFunctionEnvironment {
let type_index = store
.as_store_mut()
.engine()
.register_signature(&function_type);
let vmctx = VMFunctionContext {
host_env: host_data.as_ref() as *const _ as *mut c_void,
};
let call_trampoline = <F as HostFunction<T, Args, Rets>>::call_trampoline_address();
@ -200,7 +219,7 @@ impl Function {
host_data,
};
Self {
handle: ContextHandle::new(ctx.objects_mut(), vm_function),
handle: StoreHandle::new(store.as_store_mut().objects_mut(), vm_function),
}
}
@ -209,30 +228,29 @@ impl Function {
/// # Example
///
/// ```
/// # use wasmer::{ContextMut, Function, Store, Type};
/// # use wasmer::Context as WasmerContext;
/// # let store = Store::default();
/// # let mut ctx = WasmerContext::new(&store, ());
/// # use wasmer::{Function, FunctionEnv, FunctionEnvMut, Store, Type};
/// # let mut store = Store::default();
/// # let env = FunctionEnv::new(&mut store, ());
/// #
/// fn sum(_ctx: ContextMut<()>, a: i32, b: i32) -> i32 {
/// fn sum(_ctx: FunctionEnvMut<()>, a: i32, b: i32) -> i32 {
/// a + b
/// }
///
/// let f = Function::new_native(&mut ctx, sum);
/// let f = Function::new_native(&mut store, &env, sum);
///
/// assert_eq!(f.ty(&mut ctx).params(), vec![Type::I32, Type::I32]);
/// assert_eq!(f.ty(&mut ctx).results(), vec![Type::I32]);
/// assert_eq!(f.ty(&mut store).params(), vec![Type::I32, Type::I32]);
/// assert_eq!(f.ty(&mut store).results(), vec![Type::I32]);
/// ```
pub fn ty(&self, ctx: &impl AsContextRef) -> FunctionType {
pub fn ty(&self, store: &impl AsStoreRef) -> FunctionType {
self.handle
.get(ctx.as_context_ref().objects())
.get(store.as_store_ref().objects())
.signature
.clone()
}
fn call_wasm(
&self,
ctx: &mut impl AsContextMut,
store: &mut impl AsStoreMut,
trampoline: VMTrampoline,
params: &[Value],
results: &mut [Value],
@ -245,7 +263,7 @@ impl Function {
.join(", ")
};
// TODO: Avoid cloning the signature here, it's expensive.
let signature = self.ty(ctx);
let signature = self.ty(store);
if signature.params().len() != params.len() {
return Err(RuntimeError::new(format!(
"Parameters of type [{}] did not match signature {}",
@ -273,19 +291,19 @@ impl Function {
param_types, &signature,
)));
}
if !arg.is_from_context(ctx) {
if !arg.is_from_store(store) {
return Err(RuntimeError::new(
"cross-`Context` values are not supported",
));
}
*slot = arg.as_raw(ctx);
*slot = arg.as_raw(store);
}
// Call the trampoline.
let vm_function = self.handle.get(ctx.as_context_ref().objects());
let vm_function = self.handle.get(store.as_store_ref().objects());
if let Err(error) = unsafe {
wasmer_call_trampoline(
ctx.as_context_ref().store(),
store.as_store_ref().signal_handler(),
vm_function.anyfunc.as_ptr().as_ref().vmctx,
trampoline,
vm_function.anyfunc.as_ptr().as_ref().func_ptr,
@ -298,7 +316,7 @@ impl Function {
// Load the return values out of `values_vec`.
for (index, &value_type) in signature.results().iter().enumerate() {
unsafe {
results[index] = Value::from_raw(ctx, value_type, values_vec[index]);
results[index] = Value::from_raw(store, value_type, values_vec[index]);
}
}
@ -310,21 +328,20 @@ impl Function {
/// # Example
///
/// ```
/// # use wasmer::{ContextMut, Function, Store, Type};
/// # use wasmer::Context as WasmerContext;
/// # let store = Store::default();
/// # let mut ctx = WasmerContext::new(&store, ());
/// # use wasmer::{Function, FunctionEnv, FunctionEnvMut, Store, Type};
/// # let mut store = Store::default();
/// # let env = FunctionEnv::new(&mut store, ());
/// #
/// fn sum(_ctx: ContextMut<()>, a: i32, b: i32) -> i32 {
/// fn sum(_ctx: FunctionEnvMut<()>, a: i32, b: i32) -> i32 {
/// a + b
/// }
///
/// let f = Function::new_native(&mut ctx, sum);
/// let f = Function::new_native(&mut store, &env, sum);
///
/// assert_eq!(f.param_arity(&mut ctx), 2);
/// assert_eq!(f.param_arity(&mut store), 2);
/// ```
pub fn param_arity(&self, ctx: &impl AsContextRef) -> usize {
self.ty(ctx).params().len()
pub fn param_arity(&self, store: &impl AsStoreRef) -> usize {
self.ty(store).params().len()
}
/// Returns the number of results this function produces.
@ -332,21 +349,20 @@ impl Function {
/// # Example
///
/// ```
/// # use wasmer::{ContextMut, Function, Store, Type};
/// # use wasmer::Context as WasmerContext;
/// # let store = Store::default();
/// # let mut ctx = WasmerContext::new(&store, ());
/// # use wasmer::{Function, FunctionEnv, FunctionEnvMut, Store, Type};
/// # let mut store = Store::default();
/// # let env = FunctionEnv::new(&mut store, ());
/// #
/// fn sum(_ctx: ContextMut<()>, a: i32, b: i32) -> i32 {
/// fn sum(_ctx: FunctionEnvMut<()>, a: i32, b: i32) -> i32 {
/// a + b
/// }
///
/// let f = Function::new_native(&mut ctx, sum);
/// let f = Function::new_native(&mut store, &env, sum);
///
/// assert_eq!(f.result_arity(&mut ctx), 1);
/// assert_eq!(f.result_arity(&mut store), 1);
/// ```
pub fn result_arity(&self, ctx: &impl AsContextRef) -> usize {
self.ty(ctx).results().len()
pub fn result_arity(&self, store: &impl AsStoreRef) -> usize {
self.ty(store).results().len()
}
/// Call the `Function` function.
@ -361,9 +377,9 @@ impl Function {
///
/// ```
/// # use wasmer::{imports, wat2wasm, Function, Instance, Module, Store, Type, Value};
/// # use wasmer::Context as WasmerContext;
/// # let store = Store::default();
/// # let mut ctx = WasmerContext::new(&store, ());
/// # use wasmer::FunctionEnv;
/// # let mut store = Store::default();
/// # let env = FunctionEnv::new(&mut store, ());
/// # let wasm_bytes = wat2wasm(r#"
/// # (module
/// # (func (export "sum") (param $x i32) (param $y i32) (result i32)
@ -374,42 +390,41 @@ impl Function {
/// # "#.as_bytes()).unwrap();
/// # let module = Module::new(&store, wasm_bytes).unwrap();
/// # let import_object = imports! {};
/// # let instance = Instance::new(&mut ctx, &module, &import_object).unwrap();
/// # let instance = Instance::new(&mut store, &module, &import_object).unwrap();
/// #
/// let sum = instance.exports.get_function("sum").unwrap();
///
/// assert_eq!(sum.call(&mut ctx, &[Value::I32(1), Value::I32(2)]).unwrap().to_vec(), vec![Value::I32(3)]);
/// assert_eq!(sum.call(&mut store, &[Value::I32(1), Value::I32(2)]).unwrap().to_vec(), vec![Value::I32(3)]);
/// ```
pub fn call(
&self,
ctx: &mut impl AsContextMut,
store: &mut impl AsStoreMut,
params: &[Value],
) -> Result<Box<[Value]>, RuntimeError> {
let trampoline = unsafe {
self.handle
.get(ctx.as_context_ref().objects())
.get(store.as_store_ref().objects())
.anyfunc
.as_ptr()
.as_ref()
.call_trampoline
};
let mut results = vec![Value::null(); self.result_arity(ctx)];
self.call_wasm(ctx, trampoline, params, &mut results)?;
let mut results = vec![Value::null(); self.result_arity(store)];
self.call_wasm(store, trampoline, params, &mut results)?;
Ok(results.into_boxed_slice())
}
pub(crate) fn vm_funcref(&self, ctx: &impl AsContextRef) -> VMFuncRef {
let vm_function = self.handle.get(ctx.as_context_ref().objects());
pub(crate) fn vm_funcref(&self, store: &impl AsStoreRef) -> VMFuncRef {
let vm_function = self.handle.get(store.as_store_ref().objects());
if vm_function.kind == VMFunctionKind::Dynamic {
panic!("dynamic functions cannot be used in tables or as funcrefs");
}
VMFuncRef(vm_function.anyfunc.as_ptr())
}
pub(crate) unsafe fn from_vm_funcref(ctx: &mut impl AsContextMut, funcref: VMFuncRef) -> Self {
let signature = ctx
.as_context_mut()
.store()
pub(crate) unsafe fn from_vm_funcref(store: &mut impl AsStoreMut, funcref: VMFuncRef) -> Self {
let signature = store
.as_store_ref()
.engine()
.lookup_signature(funcref.0.as_ref().type_index)
.expect("Signature not found in store");
@ -422,7 +437,7 @@ impl Function {
host_data: Box::new(()),
};
Self {
handle: ContextHandle::new(ctx.as_context_mut().objects_mut(), vm_function),
handle: StoreHandle::new(store.as_store_mut().objects_mut(), vm_function),
}
}
@ -433,9 +448,9 @@ impl Function {
///
/// ```
/// # use wasmer::{imports, wat2wasm, Function, Instance, Module, Store, Type, TypedFunction, Value};
/// # use wasmer::Context as WasmerContext;
/// # let store = Store::default();
/// # let mut ctx = WasmerContext::new(&store, ());
/// # use wasmer::FunctionEnv;
/// # let mut store = Store::default();
/// # let env = FunctionEnv::new(&mut store, ());
/// # let wasm_bytes = wat2wasm(r#"
/// # (module
/// # (func (export "sum") (param $x i32) (param $y i32) (result i32)
@ -446,12 +461,12 @@ impl Function {
/// # "#.as_bytes()).unwrap();
/// # let module = Module::new(&store, wasm_bytes).unwrap();
/// # let import_object = imports! {};
/// # let instance = Instance::new(&mut ctx, &module, &import_object).unwrap();
/// # let instance = Instance::new(&mut store, &module, &import_object).unwrap();
/// #
/// let sum = instance.exports.get_function("sum").unwrap();
/// let sum_native: TypedFunction<(i32, i32), i32> = sum.native(&mut ctx).unwrap();
/// let sum_native: TypedFunction<(i32, i32), i32> = sum.native(&mut store).unwrap();
///
/// assert_eq!(sum_native.call(&mut ctx, 1, 2).unwrap(), 3);
/// assert_eq!(sum_native.call(&mut store, 1, 2).unwrap(), 3);
/// ```
///
/// # Errors
@ -461,9 +476,9 @@ impl Function {
///
/// ```should_panic
/// # use wasmer::{imports, wat2wasm, Function, Instance, Module, Store, Type, TypedFunction, Value};
/// # use wasmer::Context as WasmerContext;
/// # let store = Store::default();
/// # let mut ctx = WasmerContext::new(&store, ());
/// # use wasmer::FunctionEnv;
/// # let mut store = Store::default();
/// # let env = FunctionEnv::new(&mut store, ());
/// # let wasm_bytes = wat2wasm(r#"
/// # (module
/// # (func (export "sum") (param $x i32) (param $y i32) (result i32)
@ -474,12 +489,12 @@ impl Function {
/// # "#.as_bytes()).unwrap();
/// # let module = Module::new(&store, wasm_bytes).unwrap();
/// # let import_object = imports! {};
/// # let instance = Instance::new(&mut ctx, &module, &import_object).unwrap();
/// # let instance = Instance::new(&mut store, &module, &import_object).unwrap();
/// #
/// let sum = instance.exports.get_function("sum").unwrap();
///
/// // This results in an error: `RuntimeError`
/// let sum_native : TypedFunction<(i64, i64), i32> = sum.native(&mut ctx).unwrap();
/// let sum_native : TypedFunction<(i64, i64), i32> = sum.native(&mut store).unwrap();
/// ```
///
/// If the `Rets` generic parameter does not match the exported function
@ -487,9 +502,9 @@ impl Function {
///
/// ```should_panic
/// # use wasmer::{imports, wat2wasm, Function, Instance, Module, Store, Type, TypedFunction, Value};
/// # use wasmer::Context as WasmerContext;
/// # let store = Store::default();
/// # let mut ctx = WasmerContext::new(&store, ());
/// # use wasmer::FunctionEnv;
/// # let mut store = Store::default();
/// # let env = FunctionEnv::new(&mut store, ());
/// # let wasm_bytes = wat2wasm(r#"
/// # (module
/// # (func (export "sum") (param $x i32) (param $y i32) (result i32)
@ -500,22 +515,22 @@ impl Function {
/// # "#.as_bytes()).unwrap();
/// # let module = Module::new(&store, wasm_bytes).unwrap();
/// # let import_object = imports! {};
/// # let instance = Instance::new(&mut ctx, &module, &import_object).unwrap();
/// # let instance = Instance::new(&mut store, &module, &import_object).unwrap();
/// #
/// let sum = instance.exports.get_function("sum").unwrap();
///
/// // This results in an error: `RuntimeError`
/// let sum_native: TypedFunction<(i32, i32), i64> = sum.native(&mut ctx).unwrap();
/// let sum_native: TypedFunction<(i32, i32), i64> = sum.native(&mut store).unwrap();
/// ```
pub fn native<Args, Rets>(
&self,
ctx: &impl AsContextRef,
store: &impl AsStoreRef,
) -> Result<TypedFunction<Args, Rets>, RuntimeError>
where
Args: WasmTypeList,
Rets: WasmTypeList,
{
let vm_function = self.handle.get(ctx.as_context_ref().objects());
let vm_function = self.handle.get(store.as_store_ref().objects());
// type check
{
@ -549,19 +564,19 @@ impl Function {
}
pub(crate) fn from_vm_extern(
ctx: &mut impl AsContextMut,
internal: InternalContextHandle<VMFunction>,
store: &mut impl AsStoreMut,
internal: InternalStoreHandle<VMFunction>,
) -> Self {
Self {
handle: unsafe {
ContextHandle::from_internal(ctx.as_context_ref().objects().id(), internal)
StoreHandle::from_internal(store.as_store_ref().objects().id(), internal)
},
}
}
/// Checks whether this `Function` can be used with the given context.
pub fn is_from_context(&self, ctx: &impl AsContextRef) -> bool {
self.handle.context_id() == ctx.as_context_ref().objects().id()
/// Checks whether this `Function` can be used with the given store.
pub fn is_from_store(&self, store: &impl AsStoreRef) -> bool {
self.handle.store_id() == store.as_store_ref().objects().id()
}
pub(crate) fn to_vm_extern(&self) -> VMExtern {
@ -590,10 +605,11 @@ where
// This function wraps our func, to make it compatible with the
// reverse trampoline signature
unsafe extern "C" fn func_wrapper(
this: &VMDynamicFunctionContext<Self>,
this: &mut VMDynamicFunctionContext<Self>,
values_vec: *mut RawValue,
) {
use std::panic::{self, AssertUnwindSafe};
let result =
on_host_stack(|| panic::catch_unwind(AssertUnwindSafe(|| (this.ctx.func)(values_vec))));
@ -633,12 +649,12 @@ mod inner {
use std::panic::{self, AssertUnwindSafe};
use wasmer_vm::{on_host_stack, VMContext, VMTrampoline};
use crate::sys::function_env::FunctionEnvMut;
use wasmer_types::{NativeWasmType, RawValue, Type};
use wasmer_vm::{raise_user_trap, resume_panic, VMFunctionBody};
use crate::sys::context::{ContextInner, ContextMut};
use crate::sys::NativeWasmTypeInto;
use crate::{AsContextMut, AsContextRef, ExternRef, Function};
use crate::{AsStoreMut, AsStoreRef, ExternRef, Function, FunctionEnv, StoreMut};
/// A trait to convert a Rust value to a `WasmNativeType` value,
/// or to convert `WasmNativeType` value to a Rust value.
@ -674,11 +690,11 @@ mod inner {
/// `Self::Native` type.
fn to_native(self) -> Self::Native;
/// Returns whether the given value is from the given context.
/// Returns whether the given value is from the given store.
///
/// This always returns true for primitive types that can be used with
/// any context.
fn is_from_context(&self, _ctx: &impl AsContextRef) -> bool {
fn is_from_store(&self, _ctx: &impl AsStoreRef) -> bool {
true
}
}
@ -750,8 +766,8 @@ mod inner {
fn from_native(n: Self::Native) -> Self {
n
}
fn is_from_context(&self, ctx: &impl AsContextRef) -> bool {
self.as_ref().map_or(true, |e| e.is_from_context(ctx))
fn is_from_store(&self, store: &impl AsStoreRef) -> bool {
self.as_ref().map_or(true, |e| e.is_from_store(store))
}
}
@ -764,8 +780,8 @@ mod inner {
fn from_native(n: Self::Native) -> Self {
n
}
fn is_from_context(&self, ctx: &impl AsContextRef) -> bool {
self.as_ref().map_or(true, |f| f.is_from_context(ctx))
fn is_from_store(&self, store: &impl AsStoreRef) -> bool {
self.as_ref().map_or(true, |f| f.is_from_store(store))
}
}
@ -812,7 +828,7 @@ mod inner {
/// Constructs `Self` based on an array of values.
///
/// # Safety
unsafe fn from_array(ctx: &mut impl AsContextMut, array: Self::Array) -> Self;
unsafe fn from_array(ctx: &mut impl AsStoreMut, array: Self::Array) -> Self;
/// Constructs `Self` based on a slice of values.
///
@ -823,7 +839,7 @@ mod inner {
///
/// # Safety
unsafe fn from_slice(
ctx: &mut impl AsContextMut,
ctx: &mut impl AsStoreMut,
slice: &[RawValue],
) -> Result<Self, TryFromSliceError>;
@ -831,7 +847,7 @@ mod inner {
/// (list) of values.
///
/// # Safety
unsafe fn into_array(self, ctx: &mut impl AsContextMut) -> Self::Array;
unsafe fn into_array(self, store: &mut impl AsStoreMut) -> Self::Array;
/// Allocates and return an empty array of type `Array` that
/// will hold a tuple (list) of values, usually to hold the
@ -842,13 +858,13 @@ mod inner {
/// `CStruct`.
///
/// # Safety
unsafe fn from_c_struct(ctx: &mut impl AsContextMut, c_struct: Self::CStruct) -> Self;
unsafe fn from_c_struct(store: &mut impl AsStoreMut, c_struct: Self::CStruct) -> Self;
/// Builds and returns a C struct of type `CStruct` from a
/// tuple (list) of values.
///
/// # Safety
unsafe fn into_c_struct(self, ctx: &mut impl AsContextMut) -> Self::CStruct;
unsafe fn into_c_struct(self, store: &mut impl AsStoreMut) -> Self::CStruct;
/// Writes the contents of a C struct to an array of `RawValue`.
///
@ -963,8 +979,9 @@ mod inner {
/// Represents a low-level Wasm static host function. See
/// `super::Function::new_native` to learn more.
pub(crate) struct StaticFunction<F> {
pub(crate) raw_ctx: *mut u8,
pub(crate) struct StaticFunction<F, T> {
pub(crate) raw_store: *mut u8,
pub(crate) env: FunctionEnv<T>,
pub(crate) func: F,
}
@ -996,7 +1013,7 @@ mod inner {
#[allow(unused_mut)]
#[allow(clippy::unused_unit)]
#[allow(clippy::missing_safety_doc)]
unsafe fn from_array(mut _ctx: &mut impl AsContextMut, array: Self::Array) -> Self {
unsafe fn from_array(mut _store: &mut impl AsStoreMut, array: Self::Array) -> Self {
// Unpack items of the array.
#[allow(non_snake_case)]
let [ $( $x ),* ] = array;
@ -1004,19 +1021,19 @@ mod inner {
// Build the tuple.
(
$(
FromToNativeWasmType::from_native(NativeWasmTypeInto::from_raw(_ctx, $x))
FromToNativeWasmType::from_native(NativeWasmTypeInto::from_raw(_store, $x))
),*
)
}
#[allow(clippy::missing_safety_doc)]
unsafe fn from_slice(ctx: &mut impl AsContextMut, slice: &[RawValue]) -> Result<Self, TryFromSliceError> {
Ok(Self::from_array(ctx, slice.try_into()?))
unsafe fn from_slice(store: &mut impl AsStoreMut, slice: &[RawValue]) -> Result<Self, TryFromSliceError> {
Ok(Self::from_array(store, slice.try_into()?))
}
#[allow(unused_mut)]
#[allow(clippy::missing_safety_doc)]
unsafe fn into_array(self, mut _ctx: &mut impl AsContextMut) -> Self::Array {
unsafe fn into_array(self, mut _store: &mut impl AsStoreMut) -> Self::Array {
// Unpack items of the tuple.
#[allow(non_snake_case)]
let ( $( $x ),* ) = self;
@ -1024,7 +1041,7 @@ mod inner {
// Build the array.
[
$(
FromToNativeWasmType::to_native($x).into_raw(_ctx)
FromToNativeWasmType::to_native($x).into_raw(_store)
),*
]
}
@ -1037,28 +1054,28 @@ mod inner {
#[allow(unused_mut)]
#[allow(clippy::unused_unit)]
#[allow(clippy::missing_safety_doc)]
unsafe fn from_c_struct(mut _ctx: &mut impl AsContextMut, c_struct: Self::CStruct) -> Self {
unsafe fn from_c_struct(mut _store: &mut impl AsStoreMut, c_struct: Self::CStruct) -> Self {
// Unpack items of the C structure.
#[allow(non_snake_case)]
let $c_struct_name( $( $x ),* ) = c_struct;
(
$(
FromToNativeWasmType::from_native(NativeWasmTypeInto::from_abi(_ctx, $x))
FromToNativeWasmType::from_native(NativeWasmTypeInto::from_abi(_store, $x))
),*
)
}
#[allow(unused_parens, non_snake_case, unused_mut)]
#[allow(clippy::missing_safety_doc)]
unsafe fn into_c_struct(self, mut _ctx: &mut impl AsContextMut) -> Self::CStruct {
unsafe fn into_c_struct(self, mut _store: &mut impl AsStoreMut) -> Self::CStruct {
// Unpack items of the tuple.
let ( $( $x ),* ) = self;
// Build the C structure.
$c_struct_name(
$(
FromToNativeWasmType::to_native($x).into_abi(_ctx)
FromToNativeWasmType::to_native($x).into_abi(_store)
),*
)
}
@ -1086,7 +1103,7 @@ mod inner {
// Implement `HostFunction` for a function that has the same arity than the tuple.
#[allow(unused_parens)]
impl< $( $x, )* Rets, RetsAsResult, T, Func >
impl< $( $x, )* Rets, RetsAsResult, T: Send + 'static, Func >
HostFunction<T, ( $( $x ),* ), Rets>
for
Func
@ -1094,33 +1111,41 @@ mod inner {
$( $x: FromToNativeWasmType, )*
Rets: WasmTypeList,
RetsAsResult: IntoResult<Rets>,
Func: Fn(ContextMut<'_, T>, $( $x , )*) -> RetsAsResult + 'static,
Func: Fn(FunctionEnvMut<T>, $( $x , )*) -> RetsAsResult + 'static,
{
#[allow(non_snake_case)]
fn function_body_ptr() -> *const VMFunctionBody {
/// This is a function that wraps the real host
/// function. Its address will be used inside the
/// runtime.
unsafe extern "C" fn func_wrapper<T, $( $x, )* Rets, RetsAsResult, Func>( env: &StaticFunction<Func>, $( $x: <$x::Native as NativeWasmType>::Abi, )* ) -> Rets::CStruct
unsafe extern "C" fn func_wrapper<T: Send + 'static, $( $x, )* Rets, RetsAsResult, Func>( env: &StaticFunction<Func, T>, $( $x: <$x::Native as NativeWasmType>::Abi, )* ) -> Rets::CStruct
where
$( $x: FromToNativeWasmType, )*
Rets: WasmTypeList,
RetsAsResult: IntoResult<Rets>,
Func: Fn(ContextMut<'_, T>, $( $x , )*) -> RetsAsResult + 'static,
Func: Fn(FunctionEnvMut<T>, $( $x , )*) -> RetsAsResult + 'static,
{
let mut ctx = ContextMut::from_raw(env.raw_ctx as *mut ContextInner<T>);
// println!("func wrapper");
let mut store = StoreMut::from_raw(env.raw_store as *mut _);
let result = on_host_stack(|| {
// println!("func wrapper1");
panic::catch_unwind(AssertUnwindSafe(|| {
$(
let $x = FromToNativeWasmType::from_native(NativeWasmTypeInto::from_abi(&mut ctx, $x));
let $x = FromToNativeWasmType::from_native(NativeWasmTypeInto::from_abi(&mut store, $x));
)*
(env.func)(ctx.as_context_mut(), $($x),* ).into_result()
// println!("func wrapper2 {:p}", *env.raw_ctx);
let store_mut = StoreMut::from_raw(env.raw_store as *mut _);
let f_env = FunctionEnvMut {
store_mut,
func_env: env.env.clone(),
};
// println!("func wrapper3");
(env.func)(f_env, $($x),* ).into_result()
}))
});
match result {
Ok(Ok(result)) => return result.into_c_struct(&mut ctx),
Ok(Ok(result)) => return result.into_c_struct(&mut store),
Ok(Err(trap)) => raise_user_trap(Box::new(trap)),
Err(panic) => resume_panic(panic) ,
}
@ -1212,18 +1237,18 @@ mod inner {
type CStruct = Self;
type Array = [RawValue; 0];
unsafe fn from_array(_: &mut impl AsContextMut, _: Self::Array) -> Self {
unsafe fn from_array(_: &mut impl AsStoreMut, _: Self::Array) -> Self {
unreachable!()
}
unsafe fn from_slice(
_: &mut impl AsContextMut,
_: &mut impl AsStoreMut,
_: &[RawValue],
) -> Result<Self, TryFromSliceError> {
unreachable!()
}
unsafe fn into_array(self, _: &mut impl AsContextMut) -> Self::Array {
unsafe fn into_array(self, _: &mut impl AsStoreMut) -> Self::Array {
[]
}
@ -1231,11 +1256,11 @@ mod inner {
[]
}
unsafe fn from_c_struct(_: &mut impl AsContextMut, self_: Self::CStruct) -> Self {
unsafe fn from_c_struct(_: &mut impl AsStoreMut, self_: Self::CStruct) -> Self {
self_
}
unsafe fn into_c_struct(self, _: &mut impl AsContextMut) -> Self::CStruct {
unsafe fn into_c_struct(self, _: &mut impl AsStoreMut) -> Self::CStruct {
self
}
@ -1249,14 +1274,12 @@ mod inner {
#[cfg(test)]
mod test_wasm_type_list {
use super::*;
use crate::Context as WasmerContext;
use crate::Store;
use wasmer_types::Type;
/*
#[test]
fn test_from_array() {
let store = Store::default();
let mut ctx = WasmerContext::new(&store, ());
let mut store = Store::default();
let env = FunctionEnv::new(&mut store, ());
assert_eq!(<()>::from_array(&mut ctx, []), ());
assert_eq!(<i32>::from_array(&mut ctx, [RawValue{i32: 1}]), (1i32));
assert_eq!(<(i32, i64)>::from_array(&mut ctx, [RawValue{i32:1}, RawValue{i64:2}]), (1i32, 2i64));
@ -1273,8 +1296,8 @@ mod inner {
#[test]
fn test_into_array() {
let store = Store::default();
let mut ctx = WasmerContext::new(&store, ());
let mut store = Store::default();
let env = FunctionEnv::new(&mut store, ());
assert_eq!(().into_array(&mut ctx), [0i128; 0]);
assert_eq!((1i32).into_array(&mut ctx), [1i32]);
assert_eq!((1i32, 2i64).into_array(&mut ctx), [RawValue{i32: 1}, RawValue{i64: 2}]);
@ -1293,8 +1316,8 @@ mod inner {
/*
#[test]
fn test_from_c_struct() {
let store = Store::default();
let mut ctx = WasmerContext::new(&store, ());
let mut store = Store::default();
let env = FunctionEnv::new(&mut store, ());
assert_eq!(<()>::from_c_struct(&mut ctx, S0()), ());
assert_eq!(<i32>::from_c_struct(&mut ctx, S1(1)), (1i32));
assert_eq!(<(i32, i64)>::from_c_struct(&mut ctx, S2(1, 2)), (1i32, 2i64));
@ -1331,7 +1354,7 @@ mod inner {
mod test_function {
use super::*;
use crate::Store;
use crate::Context as WasmerContext;
use crate::FunctionEnv;
use wasmer_types::Type;
fn func() {}
@ -1354,15 +1377,15 @@ mod inner {
#[test]
fn test_function_types() {
let store = Store::default();
let mut ctx = WasmerContext::new(&store, ());
let mut store = Store::default();
let env = FunctionEnv::new(&mut store, ());
use wasmer_types::FunctionType;
assert_eq!(
StaticFunction::new(func).ty(&mut ctx),
StaticFunction::new(func).ty(&mut store),
FunctionType::new(vec![], vec![])
);
assert_eq!(
StaticFunction::new(func__i32).ty(&mut ctx),
StaticFunction::new(func__i32).ty(&mut store),
FunctionType::new(vec![], vec![Type::I32])
);
assert_eq!(

View File

@ -1,11 +1,11 @@
use crate::sys::context::{AsContextMut, AsContextRef};
use crate::sys::exports::{ExportError, Exportable};
use crate::sys::externals::Extern;
use crate::sys::store::{AsStoreMut, AsStoreRef};
use crate::sys::value::Value;
use crate::sys::GlobalType;
use crate::sys::Mutability;
use crate::sys::RuntimeError;
use wasmer_vm::{ContextHandle, InternalContextHandle, VMExtern, VMGlobal};
use wasmer_vm::{InternalStoreHandle, StoreHandle, VMExtern, VMGlobal};
/// A WebAssembly `global` instance.
///
@ -15,7 +15,7 @@ use wasmer_vm::{ContextHandle, InternalContextHandle, VMExtern, VMGlobal};
/// Spec: <https://webassembly.github.io/spec/core/exec/runtime.html#global-instances>
#[derive(Debug, Clone)]
pub struct Global {
handle: ContextHandle<VMGlobal>,
handle: StoreHandle<VMGlobal>,
}
impl Global {
@ -25,16 +25,14 @@ impl Global {
///
/// ```
/// # use wasmer::{Global, Mutability, Store, Value};
/// # use wasmer::Context as WasmerContext;
/// # let store = Store::default();
/// # let mut ctx = WasmerContext::new(&store, ());
/// # let mut store = Store::default();
/// #
/// let g = Global::new(&mut ctx, Value::I32(1));
/// let g = Global::new(&mut store, Value::I32(1));
///
/// assert_eq!(g.get(&mut ctx), Value::I32(1));
/// assert_eq!(g.ty(&mut ctx).mutability, Mutability::Const);
/// assert_eq!(g.get(&mut store), Value::I32(1));
/// assert_eq!(g.ty(&mut store).mutability, Mutability::Const);
/// ```
pub fn new(ctx: &mut impl AsContextMut, val: Value) -> Self {
pub fn new(ctx: &mut impl AsStoreMut, val: Value) -> Self {
Self::from_value(ctx, val, Mutability::Const).unwrap()
}
@ -44,26 +42,24 @@ impl Global {
///
/// ```
/// # use wasmer::{Global, Mutability, Store, Value};
/// # use wasmer::Context as WasmerContext;
/// # let store = Store::default();
/// # let mut ctx = WasmerContext::new(&store, ());
/// # let mut store = Store::default();
/// #
/// let g = Global::new_mut(&mut ctx, Value::I32(1));
/// let g = Global::new_mut(&mut store, Value::I32(1));
///
/// assert_eq!(g.get(&mut ctx), Value::I32(1));
/// assert_eq!(g.ty(&mut ctx).mutability, Mutability::Var);
/// assert_eq!(g.get(&mut store), Value::I32(1));
/// assert_eq!(g.ty(&mut store).mutability, Mutability::Var);
/// ```
pub fn new_mut(ctx: &mut impl AsContextMut, val: Value) -> Self {
pub fn new_mut(ctx: &mut impl AsStoreMut, val: Value) -> Self {
Self::from_value(ctx, val, Mutability::Var).unwrap()
}
/// Create a `Global` with the initial value [`Val`] and the provided [`Mutability`].
fn from_value(
ctx: &mut impl AsContextMut,
ctx: &mut impl AsStoreMut,
val: Value,
mutability: Mutability,
) -> Result<Self, RuntimeError> {
if !val.is_from_context(ctx) {
if !val.is_from_store(ctx) {
return Err(RuntimeError::new(
"cross-`Context` values are not supported",
));
@ -77,7 +73,7 @@ impl Global {
}
Ok(Self {
handle: ContextHandle::new(ctx.as_context_mut().objects_mut(), global),
handle: StoreHandle::new(ctx.objects_mut(), global),
})
}
@ -87,18 +83,16 @@ impl Global {
///
/// ```
/// # use wasmer::{Global, Mutability, Store, Type, Value, GlobalType};
/// # use wasmer::Context as WasmerContext;
/// # let store = Store::default();
/// # let mut ctx = WasmerContext::new(&store, ());
/// # let mut store = Store::default();
/// #
/// let c = Global::new(&mut ctx, Value::I32(1));
/// let v = Global::new_mut(&mut ctx, Value::I64(1));
/// let c = Global::new(&mut store, Value::I32(1));
/// let v = Global::new_mut(&mut store, Value::I64(1));
///
/// assert_eq!(c.ty(&mut ctx), GlobalType::new(Type::I32, Mutability::Const));
/// assert_eq!(v.ty(&mut ctx), GlobalType::new(Type::I64, Mutability::Var));
/// assert_eq!(c.ty(&mut store), GlobalType::new(Type::I32, Mutability::Const));
/// assert_eq!(v.ty(&mut store), GlobalType::new(Type::I64, Mutability::Var));
/// ```
pub fn ty(&self, ctx: &impl AsContextRef) -> GlobalType {
*self.handle.get(ctx.as_context_ref().objects()).ty()
pub fn ty(&self, ctx: &impl AsStoreRef) -> GlobalType {
*self.handle.get(ctx.as_store_ref().objects()).ty()
}
/// Retrieves the current value [`Val`] that the Global has.
@ -107,23 +101,21 @@ impl Global {
///
/// ```
/// # use wasmer::{Global, Store, Value};
/// # use wasmer::Context as WasmerContext;
/// # let store = Store::default();
/// # let mut ctx = WasmerContext::new(&store, ());
/// # let mut store = Store::default();
/// #
/// let g = Global::new(&mut ctx, Value::I32(1));
/// let g = Global::new(&mut store, Value::I32(1));
///
/// assert_eq!(g.get(&mut ctx), Value::I32(1));
/// assert_eq!(g.get(&mut store), Value::I32(1));
/// ```
pub fn get(&self, ctx: &mut impl AsContextMut) -> Value {
pub fn get(&self, ctx: &mut impl AsStoreMut) -> Value {
unsafe {
let raw = self
.handle
.get(ctx.as_context_ref().objects())
.get(ctx.as_store_ref().objects())
.vmglobal()
.as_ref()
.val;
let ty = self.handle.get(ctx.as_context_ref().objects()).ty().ty;
let ty = self.handle.get(ctx.as_store_ref().objects()).ty().ty;
Value::from_raw(ctx, ty, raw)
}
}
@ -134,17 +126,15 @@ impl Global {
///
/// ```
/// # use wasmer::{Global, Store, Value};
/// # use wasmer::Context as WasmerContext;
/// # let store = Store::default();
/// # let mut ctx = WasmerContext::new(&store, ());
/// # let mut store = Store::default();
/// #
/// let g = Global::new_mut(&mut ctx, Value::I32(1));
/// let g = Global::new_mut(&mut store, Value::I32(1));
///
/// assert_eq!(g.get(&mut ctx), Value::I32(1));
/// assert_eq!(g.get(&mut store), Value::I32(1));
///
/// g.set(&mut ctx, Value::I32(2));
/// g.set(&mut store, Value::I32(2));
///
/// assert_eq!(g.get(&mut ctx), Value::I32(2));
/// assert_eq!(g.get(&mut store), Value::I32(2));
/// ```
///
/// # Errors
@ -153,30 +143,26 @@ impl Global {
///
/// ```should_panic
/// # use wasmer::{Global, Store, Value};
/// # use wasmer::Context as WasmerContext;
/// # let store = Store::default();
/// # let mut ctx = WasmerContext::new(&store, ());
/// # let mut store = Store::default();
/// #
/// let g = Global::new(&mut ctx, Value::I32(1));
/// let g = Global::new(&mut store, Value::I32(1));
///
/// g.set(&mut ctx, Value::I32(2)).unwrap();
/// g.set(&mut store, Value::I32(2)).unwrap();
/// ```
///
/// Trying to set a value of a incompatible type will raise an error:
///
/// ```should_panic
/// # use wasmer::{Global, Store, Value};
/// # use wasmer::Context as WasmerContext;
/// # let store = Store::default();
/// # let mut ctx = WasmerContext::new(&store, ());
/// # let mut store = Store::default();
/// #
/// let g = Global::new(&mut ctx, Value::I32(1));
/// let g = Global::new(&mut store, Value::I32(1));
///
/// // This results in an error: `RuntimeError`.
/// g.set(&mut ctx, Value::I64(2)).unwrap();
/// g.set(&mut store, Value::I64(2)).unwrap();
/// ```
pub fn set(&self, ctx: &mut impl AsContextMut, val: Value) -> Result<(), RuntimeError> {
if !val.is_from_context(ctx) {
pub fn set(&self, ctx: &mut impl AsStoreMut, val: Value) -> Result<(), RuntimeError> {
if !val.is_from_store(ctx) {
return Err(RuntimeError::new(
"cross-`Context` values are not supported",
));
@ -193,7 +179,7 @@ impl Global {
}
unsafe {
self.handle
.get_mut(ctx.as_context_mut().objects_mut())
.get_mut(ctx.objects_mut())
.vmglobal()
.as_mut()
.val = val.as_raw(ctx);
@ -202,19 +188,19 @@ impl Global {
}
pub(crate) fn from_vm_extern(
ctx: &mut impl AsContextMut,
internal: InternalContextHandle<VMGlobal>,
ctx: &mut impl AsStoreMut,
internal: InternalStoreHandle<VMGlobal>,
) -> Self {
Self {
handle: unsafe {
ContextHandle::from_internal(ctx.as_context_ref().objects().id(), internal)
StoreHandle::from_internal(ctx.as_store_ref().objects().id(), internal)
},
}
}
/// Checks whether this `Global` can be used with the given context.
pub fn is_from_context(&self, ctx: &impl AsContextRef) -> bool {
self.handle.context_id() == ctx.as_context_ref().objects().id()
pub fn is_from_store(&self, ctx: &impl AsStoreRef) -> bool {
self.handle.store_id() == ctx.as_store_ref().objects().id()
}
pub(crate) fn to_vm_extern(&self) -> VMExtern {

View File

@ -1,6 +1,6 @@
use crate::sys::context::{AsContextMut, AsContextRef};
use crate::sys::exports::{ExportError, Exportable};
use crate::sys::externals::Extern;
use crate::sys::store::{AsStoreMut, AsStoreRef};
use crate::sys::MemoryType;
use crate::MemoryAccessError;
use std::convert::TryInto;
@ -9,9 +9,7 @@ use std::mem;
use std::mem::MaybeUninit;
use std::slice;
use wasmer_types::Pages;
use wasmer_vm::{
ContextHandle, ContextObjects, InternalContextHandle, MemoryError, VMExtern, VMMemory,
};
use wasmer_vm::{InternalStoreHandle, MemoryError, StoreHandle, StoreObjects, VMExtern, VMMemory};
/// A WebAssembly `memory` instance.
///
@ -29,7 +27,7 @@ use wasmer_vm::{
/// Spec: <https://webassembly.github.io/spec/core/exec/runtime.html#memory-instances>
#[derive(Debug, Clone)]
pub struct Memory {
handle: ContextHandle<VMMemory>,
handle: StoreHandle<VMMemory>,
}
impl Memory {
@ -42,20 +40,18 @@ impl Memory {
///
/// ```
/// # use wasmer::{Memory, MemoryType, Pages, Store, Type, Value};
/// # use wasmer::Context as WasmerContext;
/// # let store = Store::default();
/// # let mut ctx = WasmerContext::new(&store, ());
/// # let mut store = Store::default();
/// #
/// let m = Memory::new(&mut ctx, MemoryType::new(1, None, false)).unwrap();
/// let m = Memory::new(&mut store, MemoryType::new(1, None, false)).unwrap();
/// ```
pub fn new(ctx: &mut impl AsContextMut, ty: MemoryType) -> Result<Self, MemoryError> {
let mut ctx = ctx.as_context_mut();
let tunables = ctx.store().tunables();
pub fn new(ctx: &mut impl AsStoreMut, ty: MemoryType) -> Result<Self, MemoryError> {
let mut ctx = ctx.as_store_mut();
let tunables = ctx.tunables();
let style = tunables.memory_style(&ty);
let memory = tunables.create_host_memory(&ty, &style)?;
Ok(Self {
handle: ContextHandle::new(ctx.objects_mut(), memory),
handle: StoreHandle::new(ctx.objects_mut(), memory),
})
}
@ -65,17 +61,15 @@ impl Memory {
///
/// ```
/// # use wasmer::{Memory, MemoryType, Pages, Store, Type, Value};
/// # use wasmer::Context as WasmerContext;
/// # let store = Store::default();
/// # let mut ctx = WasmerContext::new(&store, ());
/// # let mut store = Store::default();
/// #
/// let mt = MemoryType::new(1, None, false);
/// let m = Memory::new(&mut ctx, mt).unwrap();
/// let m = Memory::new(&mut store, mt).unwrap();
///
/// assert_eq!(m.ty(&mut ctx), mt);
/// assert_eq!(m.ty(&mut store), mt);
/// ```
pub fn ty(&self, ctx: &impl AsContextRef) -> MemoryType {
self.handle.get(ctx.as_context_ref().objects()).ty()
pub fn ty(&self, ctx: &impl AsStoreRef) -> MemoryType {
self.handle.get(ctx.as_store_ref().objects()).ty()
}
/// Returns the pointer to the raw bytes of the `Memory`.
@ -83,12 +77,12 @@ impl Memory {
// This used by wasmer-emscripten and wasmer-c-api, but should be treated
// as deprecated and not used in future code.
#[doc(hidden)]
pub fn data_ptr(&self, ctx: &impl AsContextRef) -> *mut u8 {
pub fn data_ptr(&self, ctx: &impl AsStoreRef) -> *mut u8 {
self.buffer(ctx).base
}
/// Returns the size (in bytes) of the `Memory`.
pub fn data_size(&self, ctx: &impl AsContextRef) -> u64 {
pub fn data_size(&self, ctx: &impl AsStoreRef) -> u64 {
self.buffer(ctx).len.try_into().unwrap()
}
@ -98,16 +92,14 @@ impl Memory {
///
/// ```
/// # use wasmer::{Memory, MemoryType, Pages, Store, Type, Value};
/// # use wasmer::Context as WasmerContext;
/// # let store = Store::default();
/// # let mut ctx = WasmerContext::new(&store, ());
/// # let mut store = Store::default();
/// #
/// let m = Memory::new(&mut ctx, MemoryType::new(1, None, false)).unwrap();
/// let m = Memory::new(&mut store, MemoryType::new(1, None, false)).unwrap();
///
/// assert_eq!(m.size(&mut ctx), Pages(1));
/// assert_eq!(m.size(&mut store), Pages(1));
/// ```
pub fn size(&self, ctx: &impl AsContextRef) -> Pages {
self.handle.get(ctx.as_context_ref().objects()).size()
pub fn size(&self, ctx: &impl AsStoreRef) -> Pages {
self.handle.get(ctx.as_store_ref().objects()).size()
}
/// Grow memory by the specified amount of WebAssembly [`Pages`] and return
@ -117,15 +109,13 @@ impl Memory {
///
/// ```
/// # use wasmer::{Memory, MemoryType, Pages, Store, Type, Value, WASM_MAX_PAGES};
/// # use wasmer::Context as WasmerContext;
/// # let store = Store::default();
/// # let mut ctx = WasmerContext::new(&store, ());
/// # let mut store = Store::default();
/// #
/// let m = Memory::new(&mut ctx, MemoryType::new(1, Some(3), false)).unwrap();
/// let p = m.grow(&mut ctx, 2).unwrap();
/// let m = Memory::new(&mut store, MemoryType::new(1, Some(3), false)).unwrap();
/// let p = m.grow(&mut store, 2).unwrap();
///
/// assert_eq!(p, Pages(1));
/// assert_eq!(m.size(&mut ctx), Pages(3));
/// assert_eq!(m.size(&mut store), Pages(3));
/// ```
///
/// # Errors
@ -135,26 +125,24 @@ impl Memory {
///
/// ```should_panic
/// # use wasmer::{Memory, MemoryType, Pages, Store, Type, Value, WASM_MAX_PAGES};
/// # use wasmer::Context as WasmerContext;
/// # let store = Store::default();
/// # let mut ctx = WasmerContext::new(&store, ());
/// # use wasmer::FunctionEnv;
/// # let mut store = Store::default();
/// # let env = FunctionEnv::new(&mut store, ());
/// #
/// let m = Memory::new(&mut ctx, MemoryType::new(1, Some(1), false)).unwrap();
/// let m = Memory::new(&mut store, MemoryType::new(1, Some(1), false)).unwrap();
///
/// // This results in an error: `MemoryError::CouldNotGrow`.
/// let s = m.grow(&mut ctx, 1).unwrap();
/// let s = m.grow(&mut store, 1).unwrap();
/// ```
pub fn grow<IntoPages>(
&self,
ctx: &mut impl AsContextMut,
ctx: &mut impl AsStoreMut,
delta: IntoPages,
) -> Result<Pages, MemoryError>
where
IntoPages: Into<Pages>,
{
self.handle
.get_mut(ctx.as_context_mut().objects_mut())
.grow(delta.into())
self.handle.get_mut(ctx.objects_mut()).grow(delta.into())
}
/// Safely reads bytes from the memory at the given offset.
@ -166,7 +154,7 @@ impl Memory {
/// concurrent writes.
pub fn read(
&self,
ctx: &impl AsContextRef,
ctx: &impl AsStoreRef,
offset: u64,
buf: &mut [u8],
) -> Result<(), MemoryAccessError> {
@ -185,7 +173,7 @@ impl Memory {
/// concurrent writes.
pub fn read_uninit<'a>(
&self,
ctx: &impl AsContextRef,
ctx: &impl AsStoreRef,
offset: u64,
buf: &'a mut [MaybeUninit<u8>],
) -> Result<&'a mut [u8], MemoryAccessError> {
@ -201,15 +189,15 @@ impl Memory {
/// concurrent reads/writes.
pub fn write(
&self,
ctx: &impl AsContextRef,
ctx: &impl AsStoreRef,
offset: u64,
data: &[u8],
) -> Result<(), MemoryAccessError> {
self.buffer(ctx).write(offset, data)
}
pub(crate) fn buffer<'a>(&'a self, ctx: &'a impl AsContextRef) -> MemoryBuffer<'a> {
let definition = self.handle.get(ctx.as_context_ref().objects()).vmmemory();
pub(crate) fn buffer<'a>(&'a self, ctx: &'a impl AsStoreRef) -> MemoryBuffer<'a> {
let definition = self.handle.get(ctx.as_store_ref().objects()).vmmemory();
let def = unsafe { definition.as_ref() };
MemoryBuffer {
base: def.base,
@ -219,19 +207,19 @@ impl Memory {
}
pub(crate) fn from_vm_extern(
ctx: &impl AsContextRef,
internal: InternalContextHandle<VMMemory>,
ctx: &impl AsStoreRef,
internal: InternalStoreHandle<VMMemory>,
) -> Self {
Self {
handle: unsafe {
ContextHandle::from_internal(ctx.as_context_ref().objects().id(), internal)
StoreHandle::from_internal(ctx.as_store_ref().objects().id(), internal)
},
}
}
/// Checks whether this `Memory` can be used with the given context.
pub fn is_from_context(&self, ctx: &impl AsContextRef) -> bool {
self.handle.context_id() == ctx.as_context_ref().objects().id()
pub fn is_from_store(&self, ctx: &impl AsStoreRef) -> bool {
self.handle.store_id() == ctx.as_store_ref().objects().id()
}
pub(crate) fn to_vm_extern(&self) -> VMExtern {
@ -261,7 +249,7 @@ impl<'a> Exportable<'a> for Memory {
pub(crate) struct MemoryBuffer<'a> {
base: *mut u8,
len: usize,
marker: PhantomData<(&'a Memory, &'a ContextObjects)>,
marker: PhantomData<(&'a Memory, &'a StoreObjects)>,
}
impl<'a> MemoryBuffer<'a> {

View File

@ -14,7 +14,7 @@ use crate::sys::ExternType;
use std::fmt;
use wasmer_vm::VMExtern;
use super::context::{AsContextMut, AsContextRef};
use super::store::{AsStoreMut, AsStoreRef};
/// An `Extern` is the runtime representation of an entity that
/// can be imported or exported.
@ -34,7 +34,7 @@ pub enum Extern {
impl Extern {
/// Return the underlying type of the inner `Extern`.
pub fn ty(&self, ctx: &impl AsContextRef) -> ExternType {
pub fn ty(&self, ctx: &impl AsStoreRef) -> ExternType {
match self {
Self::Function(ft) => ExternType::Function(ft.ty(ctx)),
Self::Memory(ft) => ExternType::Memory(ft.ty(ctx)),
@ -44,7 +44,7 @@ impl Extern {
}
/// Create an `Extern` from an `wasmer_engine::Export`.
pub fn from_vm_extern(ctx: &mut impl AsContextMut, vm_extern: VMExtern) -> Self {
pub fn from_vm_extern(ctx: &mut impl AsStoreMut, vm_extern: VMExtern) -> Self {
match vm_extern {
VMExtern::Function(f) => Self::Function(Function::from_vm_extern(ctx, f)),
VMExtern::Memory(m) => Self::Memory(Memory::from_vm_extern(ctx, m)),
@ -54,12 +54,12 @@ impl Extern {
}
/// Checks whether this `Extern` can be used with the given context.
pub fn is_from_context(&self, ctx: &impl AsContextRef) -> bool {
pub fn is_from_store(&self, ctx: &impl AsStoreRef) -> bool {
match self {
Self::Function(f) => f.is_from_context(ctx),
Self::Global(g) => g.is_from_context(ctx),
Self::Memory(m) => m.is_from_context(ctx),
Self::Table(t) => t.is_from_context(ctx),
Self::Function(f) => f.is_from_store(ctx),
Self::Global(g) => g.is_from_store(ctx),
Self::Memory(m) => m.is_from_store(ctx),
Self::Table(t) => t.is_from_store(ctx),
}
}

View File

@ -1,10 +1,10 @@
use crate::sys::context::{AsContextMut, AsContextRef};
use crate::sys::exports::{ExportError, Exportable};
use crate::sys::externals::Extern;
use crate::sys::store::{AsStoreMut, AsStoreRef};
use crate::sys::RuntimeError;
use crate::sys::TableType;
use crate::{ExternRef, Function, Value};
use wasmer_vm::{ContextHandle, InternalContextHandle, TableElement, VMExtern, VMTable};
use wasmer_vm::{InternalStoreHandle, StoreHandle, TableElement, VMExtern, VMTable};
/// A WebAssembly `table` instance.
///
@ -17,7 +17,7 @@ use wasmer_vm::{ContextHandle, InternalContextHandle, TableElement, VMExtern, VM
/// Spec: <https://webassembly.github.io/spec/core/exec/runtime.html#table-instances>
#[derive(Debug, Clone)]
pub struct Table {
handle: ContextHandle<VMTable>,
handle: StoreHandle<VMTable>,
}
fn set_table_item(
@ -29,10 +29,10 @@ fn set_table_item(
}
fn value_to_table_element(
ctx: &mut impl AsContextMut,
ctx: &mut impl AsStoreMut,
val: Value,
) -> Result<wasmer_vm::TableElement, RuntimeError> {
if !val.is_from_context(ctx) {
if !val.is_from_store(ctx) {
return Err(RuntimeError::new("cannot pass Value across contexts"));
}
Ok(match val {
@ -46,7 +46,7 @@ fn value_to_table_element(
})
}
fn value_from_table_element(ctx: &mut impl AsContextMut, item: wasmer_vm::TableElement) -> Value {
fn value_from_table_element(ctx: &mut impl AsStoreMut, item: wasmer_vm::TableElement) -> Value {
match item {
wasmer_vm::TableElement::FuncRef(funcref) => {
Value::FuncRef(funcref.map(|f| unsafe { Function::from_vm_funcref(ctx, f) }))
@ -65,13 +65,13 @@ impl Table {
/// This function will construct the `Table` using the store
/// [`BaseTunables`][crate::sys::BaseTunables].
pub fn new(
ctx: &mut impl AsContextMut,
mut ctx: &mut impl AsStoreMut,
ty: TableType,
init: Value,
) -> Result<Self, RuntimeError> {
let mut ctx = ctx.as_context_mut();
let item = value_to_table_element(&mut ctx, init)?;
let tunables = ctx.store().tunables();
let mut ctx = ctx.as_store_mut();
let tunables = ctx.tunables();
let style = tunables.table_style(&ty);
let mut table = tunables
.create_host_table(&ty, &style)
@ -83,39 +83,35 @@ impl Table {
}
Ok(Self {
handle: ContextHandle::new(ctx.objects_mut(), table),
handle: StoreHandle::new(ctx.objects_mut(), table),
})
}
/// Returns the [`TableType`] of the `Table`.
pub fn ty(&self, ctx: &impl AsContextRef) -> TableType {
*self.handle.get(ctx.as_context_ref().objects()).ty()
pub fn ty(&self, ctx: &impl AsStoreRef) -> TableType {
*self.handle.get(ctx.as_store_ref().objects()).ty()
}
/// Retrieves an element of the table at the provided `index`.
pub fn get(&self, ctx: &mut impl AsContextMut, index: u32) -> Option<Value> {
let item = self.handle.get(ctx.as_context_ref().objects()).get(index)?;
pub fn get(&self, ctx: &mut impl AsStoreMut, index: u32) -> Option<Value> {
let item = self.handle.get(ctx.as_store_ref().objects()).get(index)?;
Some(value_from_table_element(ctx, item))
}
/// Sets an element `val` in the Table at the provided `index`.
pub fn set(
&self,
ctx: &mut impl AsContextMut,
ctx: &mut impl AsStoreMut,
index: u32,
val: Value,
) -> Result<(), RuntimeError> {
let item = value_to_table_element(ctx, val)?;
set_table_item(
self.handle.get_mut(ctx.as_context_mut().objects_mut()),
index,
item,
)
set_table_item(self.handle.get_mut(ctx.objects_mut()), index, item)
}
/// Retrieves the size of the `Table` (in elements)
pub fn size(&self, ctx: &impl AsContextRef) -> u32 {
self.handle.get(ctx.as_context_ref().objects()).size()
pub fn size(&self, ctx: &impl AsStoreRef) -> u32 {
self.handle.get(ctx.as_store_ref().objects()).size()
}
/// Grows the size of the `Table` by `delta`, initializating
@ -129,13 +125,13 @@ impl Table {
/// Returns an error if the `delta` is out of bounds for the table.
pub fn grow(
&self,
ctx: &mut impl AsContextMut,
ctx: &mut impl AsStoreMut,
delta: u32,
init: Value,
) -> Result<u32, RuntimeError> {
let item = value_to_table_element(ctx, init)?;
self.handle
.get_mut(ctx.as_context_mut().objects_mut())
.get_mut(ctx.objects_mut())
.grow(delta, item)
.ok_or_else(|| RuntimeError::new(format!("failed to grow table by `{}`", delta)))
}
@ -148,19 +144,19 @@ impl Table {
/// Returns an error if the range is out of bounds of either the source or
/// destination tables.
pub fn copy(
ctx: &mut impl AsContextMut,
ctx: &mut impl AsStoreMut,
dst_table: &Self,
dst_index: u32,
src_table: &Self,
src_index: u32,
len: u32,
) -> Result<(), RuntimeError> {
if dst_table.handle.context_id() != src_table.handle.context_id() {
if dst_table.handle.store_id() != src_table.handle.store_id() {
return Err(RuntimeError::new(
"cross-`Context` table copies are not supported",
));
}
let mut ctx = ctx.as_context_mut();
let ctx = ctx;
if dst_table.handle.internal_handle() == src_table.handle.internal_handle() {
let table = dst_table.handle.get_mut(ctx.objects_mut());
table.copy_within(dst_index, src_index, len)
@ -176,19 +172,19 @@ impl Table {
}
pub(crate) fn from_vm_extern(
ctx: &mut impl AsContextMut,
internal: InternalContextHandle<VMTable>,
ctx: &mut impl AsStoreMut,
internal: InternalStoreHandle<VMTable>,
) -> Self {
Self {
handle: unsafe {
ContextHandle::from_internal(ctx.as_context_ref().objects().id(), internal)
StoreHandle::from_internal(ctx.as_store_ref().objects().id(), internal)
},
}
}
/// Checks whether this `Table` can be used with the given context.
pub fn is_from_context(&self, ctx: &impl AsContextRef) -> bool {
self.handle.context_id() == ctx.as_context_ref().objects().id()
pub fn is_from_store(&self, ctx: &impl AsStoreRef) -> bool {
self.handle.store_id() == ctx.as_store_ref().objects().id()
}
pub(crate) fn to_vm_extern(&self) -> VMExtern {

View File

@ -0,0 +1,120 @@
use std::{any::Any, marker::PhantomData};
use wasmer_vm::{StoreHandle, StoreObjects, VMFunctionEnvironment};
use crate::{AsStoreMut, AsStoreRef, StoreMut, StoreRef};
#[derive(Debug)]
#[repr(transparent)]
/// An opaque reference to a function environment.
/// The function environment data is owned by the `Store`.
pub struct FunctionEnv<T> {
pub(crate) handle: StoreHandle<VMFunctionEnvironment>,
_phantom: PhantomData<T>,
}
impl<T> FunctionEnv<T> {
/// Make a new extern reference
pub fn new(store: &mut impl AsStoreMut, value: T) -> Self
where
T: Any + Send + 'static + Sized,
{
Self {
handle: StoreHandle::new(
store.as_store_mut().objects_mut(),
VMFunctionEnvironment::new(value),
),
_phantom: PhantomData,
}
}
/// Get the data as reference
pub fn as_ref<'a>(&self, store: &'a impl AsStoreMut) -> &'a T
where
T: Any + Send + 'static + Sized,
{
self.handle
.get(store.as_store_ref().objects())
.as_ref()
.downcast_ref::<T>()
.unwrap()
}
/// Get the data as mutable
pub fn as_mut<'a>(&self, store: &'a mut impl AsStoreMut) -> &'a mut T
where
T: Any + Send + 'static + Sized,
{
self.handle
.get_mut(store.objects_mut())
.as_mut()
.downcast_mut::<T>()
.unwrap()
}
/// Convert it into a `FunctionEnvMut`
pub fn into_mut(self, store: &mut impl AsStoreMut) -> FunctionEnvMut<T>
where
T: Any + Send + 'static + Sized,
{
FunctionEnvMut {
store_mut: store.as_store_mut(),
func_env: self,
}
}
}
impl<T> Clone for FunctionEnv<T> {
fn clone(&self) -> Self {
Self {
handle: self.handle.clone(),
_phantom: self._phantom,
}
}
}
/// A temporary handle to a [`Context`].
pub struct FunctionEnvMut<'a, T: 'a> {
pub(crate) store_mut: StoreMut<'a>,
pub(crate) func_env: FunctionEnv<T>,
}
impl<T: Send + 'static> FunctionEnvMut<'_, T> {
/// Returns a reference to the host state in this context.
pub fn data(&self) -> &T {
self.func_env.as_ref(&self.store_mut)
}
/// Returns a mutable- reference to the host state in this context.
pub fn data_mut(&mut self) -> &mut T {
self.func_env.as_mut(&mut self.store_mut)
}
/// Borrows a new mutable reference
pub fn as_mut(&mut self) -> FunctionEnvMut<'_, T> {
FunctionEnvMut {
store_mut: self.store_mut.as_store_mut(),
func_env: self.func_env.clone(),
}
}
}
impl<T> AsStoreRef for FunctionEnvMut<'_, T> {
fn as_store_ref(&self) -> StoreRef<'_> {
StoreRef {
inner: self.store_mut.inner,
}
}
}
impl<T> AsStoreMut for FunctionEnvMut<'_, T> {
fn as_store_mut(&mut self) -> StoreMut<'_> {
StoreMut {
inner: self.store_mut.inner,
}
}
#[inline]
fn objects_mut(&mut self) -> &mut StoreObjects {
&mut self.store_mut.inner.objects
}
}

View File

@ -16,19 +16,19 @@ use wasmer_types::ImportError;
///
/// # Usage:
/// ```no_run
/// use wasmer::{ContextMut, Exports, Module, Instance, imports, Imports, Function};
/// # fn foo_test(mut ctx: ContextMut<()>, module: Module) {
/// use wasmer::{Store, Exports, Module, Instance, imports, Imports, Function, FunctionEnv, FunctionEnvMut};
/// # fn foo_test(mut env: FunctionEnv<()>, mut store: &mut Store, module: Module) {
///
/// let host_fn = Function::new_native(&mut ctx, foo);
/// let host_fn = Function::new_native(&mut store, &env, foo);
/// let import_object: Imports = imports! {
/// "env" => {
/// "foo" => host_fn,
/// },
/// };
///
/// let instance = Instance::new(&mut ctx, &module, &import_object).expect("Could not instantiate module.");
/// let instance = Instance::new(&mut store, &module, &import_object).expect("Could not instantiate module.");
///
/// fn foo(_ctx: ContextMut<()>, n: i32) -> i32 {
/// fn foo(_ctx: FunctionEnvMut<()>, n: i32) -> i32 {
/// n
/// }
///
@ -97,15 +97,15 @@ impl Imports {
///
/// # Usage
/// ```no_run
/// # use wasmer::Context as WasmerContext;
/// # let store = Default::default();
/// # let mut ctx = WasmerContext::new(&store, ());
/// use wasmer::{ContextMut, Imports, Function};
/// fn foo(_ctx: ContextMut<()>, n: i32) -> i32 {
/// # use wasmer::{FunctionEnv, Store};
/// # let mut store: Store = Default::default();
/// # let env = FunctionEnv::new(&mut store, ());
/// use wasmer::{StoreMut, Imports, Function, FunctionEnvMut};
/// fn foo(_ctx: FunctionEnvMut<()>, n: i32) -> i32 {
/// n
/// }
/// let mut import_object = Imports::new();
/// import_object.define("env", "foo", Function::new_native(&mut ctx, foo));
/// import_object.define("env", "foo", Function::new_native(&mut store, &env, foo));
/// ```
pub fn define(&mut self, ns: &str, name: &str, val: impl Into<Extern>) {
self.map
@ -210,19 +210,18 @@ impl fmt::Debug for Imports {
/// # Usage
///
/// ```
/// # use wasmer::{ContextMut, Function, Store};
/// # use wasmer::Context as WasmerContext;
/// # let store = Store::default();
/// # let mut ctx = WasmerContext::new(&store, ());
/// # use wasmer::{StoreMut, Function, Store, FunctionEnv, FunctionEnvMut};
/// # let mut store = Store::default();
/// # let env = FunctionEnv::new(&mut store, ());
/// use wasmer::imports;
///
/// let import_object = imports! {
/// "env" => {
/// "foo" => Function::new_native(&mut ctx, foo)
/// "foo" => Function::new_native(&mut store, &env, foo)
/// },
/// };
///
/// fn foo(_ctx: ContextMut<()>, n: i32) -> i32 {
/// fn foo(_env: FunctionEnvMut<()>, n: i32) -> i32 {
/// n
/// }
/// ```
@ -271,18 +270,15 @@ macro_rules! import_namespace {
#[cfg(test)]
mod test {
use crate::sys::exports::Exportable;
use crate::sys::Context as WasmerContext;
use crate::sys::Exports;
use crate::sys::{Global, Store, Value};
use crate::sys::FunctionEnv;
use crate::sys::{AsStoreMut, Global, Store, Value};
use wasmer_types::Type;
use wasmer_vm::VMExtern;
/*
#[test]
fn namespace() {
let store = Store::default();
let mut ctx = WasmerContext::new(&store, ());
let g1 = Global::new(&mut ctx, Value::I32(0));
let mut store = Store::default();
let g1 = Global::new(&mut store, Value::I32(0));
let namespace = namespace! {
"happy" => g1
};
@ -294,73 +290,72 @@ mod test {
assert!(
if let VMExtern::Global(happy_dog_global) = happy_dog_entry.to_vm_extern() {
happy_dog_global.get(&mut ctx).ty == Type::I32
(*happy_dog_global.get(store.objects_mut()).ty()).ty == Type::I32
} else {
false
}
);
}
*/
#[test]
fn imports_macro_allows_trailing_comma_and_none() {
use crate::sys::ContextMut;
use crate::sys::Function;
use crate::sys::FunctionEnvMut;
let store = Default::default();
let mut ctx = WasmerContext::new(&store, ());
let mut store: Store = Default::default();
let env = FunctionEnv::new(&mut store, ());
fn func(_ctx: ContextMut<()>, arg: i32) -> i32 {
fn func(_ctx: FunctionEnvMut<()>, arg: i32) -> i32 {
arg + 1
}
let _ = imports! {
"env" => {
"func" => Function::new_native(&mut ctx, func),
"func" => Function::new_native(&mut store, &env, func),
},
};
let _ = imports! {
"env" => {
"func" => Function::new_native(&mut ctx, func),
"func" => Function::new_native(&mut store, &env, func),
}
};
let _ = imports! {
"env" => {
"func" => Function::new_native(&mut ctx, func),
"func" => Function::new_native(&mut store, &env, func),
},
"abc" => {
"def" => Function::new_native(&mut ctx, func),
"def" => Function::new_native(&mut store, &env, func),
}
};
let _ = imports! {
"env" => {
"func" => Function::new_native(&mut ctx, func)
"func" => Function::new_native(&mut store, &env, func)
},
};
let _ = imports! {
"env" => {
"func" => Function::new_native(&mut ctx, func)
"func" => Function::new_native(&mut store, &env, func)
}
};
let _ = imports! {
"env" => {
"func1" => Function::new_native(&mut ctx, func),
"func2" => Function::new_native(&mut ctx, func)
"func1" => Function::new_native(&mut store, &env, func),
"func2" => Function::new_native(&mut store, &env, func)
}
};
let _ = imports! {
"env" => {
"func1" => Function::new_native(&mut ctx, func),
"func2" => Function::new_native(&mut ctx, func),
"func1" => Function::new_native(&mut store, &env, func),
"func2" => Function::new_native(&mut store, &env, func),
}
};
}
#[test]
fn chaining_works() {
let store = Store::default();
let mut ctx = WasmerContext::new(&store, ());
let mut store = Store::default();
let g = Global::new(&mut ctx, Value::I32(0));
let g = Global::new(&mut store, Value::I32(0));
let mut imports1 = imports! {
"dog" => {
@ -390,10 +385,9 @@ mod test {
#[test]
fn extending_conflict_overwrites() {
let store = Store::default();
let mut ctx = WasmerContext::new(&store, ());
let g1 = Global::new(&mut ctx, Value::I32(0));
let g2 = Global::new(&mut ctx, Value::I64(0));
let mut store = Store::default();
let g1 = Global::new(&mut store, Value::I32(0));
let g2 = Global::new(&mut store, Value::I64(0));
let mut imports1 = imports! {
"dog" => {
@ -408,7 +402,7 @@ mod test {
};
imports1.extend(&imports2);
let happy_dog_entry = imports1.get_export("dog", "happy").unwrap();
let _happy_dog_entry = imports1.get_export("dog", "happy").unwrap();
/*
assert!(
if let Exports::Global(happy_dog_global) = happy_dog_entry.to_vm_extern() {
@ -419,10 +413,9 @@ mod test {
);
*/
// now test it in reverse
let store = Store::default();
let mut ctx = WasmerContext::new(&store, ());
let g1 = Global::new(&mut ctx, Value::I32(0));
let g2 = Global::new(&mut ctx, Value::I64(0));
let mut store = Store::default();
let g1 = Global::new(&mut store, Value::I32(0));
let g2 = Global::new(&mut store, Value::I64(0));
let imports1 = imports! {
"dog" => {
@ -437,7 +430,7 @@ mod test {
};
imports2.extend(&imports1);
let happy_dog_entry = imports2.get_export("dog", "happy").unwrap();
let _happy_dog_entry = imports2.get_export("dog", "happy").unwrap();
/*
assert!(
if let Exports::Global(happy_dog_global) = happy_dog_entry.to_vm_extern() {

View File

@ -5,9 +5,9 @@ use crate::sys::module::Module;
use crate::sys::{LinkError, RuntimeError};
use std::fmt;
use thiserror::Error;
use wasmer_vm::{ContextHandle, InstanceHandle};
use wasmer_vm::{InstanceHandle, StoreHandle};
use super::context::AsContextMut;
use super::store::AsStoreMut;
/// A WebAssembly Instance is a stateful, executable
/// instance of a WebAssembly [`Module`].
@ -19,7 +19,7 @@ use super::context::AsContextMut;
/// Spec: <https://webassembly.github.io/spec/core/exec/runtime.html#module-instances>
#[derive(Clone)]
pub struct Instance {
_handle: ContextHandle<InstanceHandle>,
_handle: StoreHandle<InstanceHandle>,
module: Module,
/// The exports for an instance.
pub exports: Exports,
@ -59,13 +59,13 @@ pub enum InstantiationError {
/// The module was compiled with a CPU feature that is not available on
/// the current host.
#[error("missing requires CPU features: {0:?}")]
#[error("missing required CPU features: {0:?}")]
CpuFeature(String),
/// Import from a different [`Context`].
/// This error occurs when an import from a different context is used.
#[error("cannot mix imports from different contexts")]
BadContext,
/// Import from a different [`Store`].
/// This error occurs when an import from a different store is used.
#[error("cannot mix imports from different stores")]
DifferentStores,
}
impl From<wasmer_compiler::InstantiationError> for InstantiationError {
@ -87,17 +87,17 @@ impl Instance {
///
/// ```
/// # use wasmer::{imports, Store, Module, Global, Value, Instance};
/// # use wasmer::Context as WasmerContext;
/// # use wasmer::FunctionEnv;
/// # fn main() -> anyhow::Result<()> {
/// let store = Store::default();
/// let mut ctx = WasmerContext::new(&store, ());
/// let mut store = Store::default();
/// let env = FunctionEnv::new(&mut store, ());
/// let module = Module::new(&store, "(module)")?;
/// let imports = imports!{
/// "host" => {
/// "var" => Global::new(&mut ctx, Value::I32(2))
/// "var" => Global::new(&mut store, Value::I32(2))
/// }
/// };
/// let instance = Instance::new(&mut ctx, &module, &imports)?;
/// let instance = Instance::new(&mut store, &module, &imports)?;
/// # Ok(())
/// # }
/// ```
@ -110,7 +110,7 @@ impl Instance {
/// * Link errors that happen when plugging the imports into the instance
/// * Runtime errors that happen when running the module `start` function.
pub fn new(
ctx: &mut impl AsContextMut,
ctx: &mut impl AsStoreMut,
module: &Module,
imports: &Imports,
) -> Result<Self, InstantiationError> {
@ -129,7 +129,7 @@ impl Instance {
.collect::<Exports>();
let instance = Self {
_handle: ContextHandle::new(ctx.as_context_mut().objects_mut(), handle),
_handle: StoreHandle::new(ctx.objects_mut(), handle),
module: module.clone(),
exports,
};
@ -148,7 +148,7 @@ impl Instance {
/// * Link errors that happen when plugging the imports into the instance
/// * Runtime errors that happen when running the module `start` function.
pub fn new_by_index(
ctx: &mut impl AsContextMut,
ctx: &mut impl AsStoreMut,
module: &Module,
externs: &[Extern],
) -> Result<Self, InstantiationError> {
@ -165,7 +165,7 @@ impl Instance {
.collect::<Exports>();
let instance = Self {
_handle: ContextHandle::new(ctx.as_context_mut().objects_mut(), handle),
_handle: StoreHandle::new(ctx.objects_mut(), handle),
module: module.clone(),
exports,
};

View File

@ -12,8 +12,8 @@ use std::{
use thiserror::Error;
use wasmer_types::ValueType;
use super::context::AsContextRef;
use super::externals::memory::MemoryBuffer;
use super::store::AsStoreRef;
/// Error for invalid [`Memory`] access.
#[derive(Clone, Copy, Debug, Error)]
@ -62,7 +62,7 @@ pub struct WasmRef<'a, T: ValueType> {
impl<'a, T: ValueType> WasmRef<'a, T> {
/// Creates a new `WasmRef` at the given offset in a memory.
#[inline]
pub fn new(ctx: &'a impl AsContextRef, memory: &'a Memory, offset: u64) -> Self {
pub fn new(ctx: &'a impl AsStoreRef, memory: &'a Memory, offset: u64) -> Self {
Self {
buffer: memory.buffer(ctx),
offset,
@ -161,7 +161,7 @@ impl<'a, T: ValueType> WasmSlice<'a, T> {
/// Returns a `MemoryAccessError` if the slice length overflows.
#[inline]
pub fn new(
ctx: &'a impl AsContextRef,
ctx: &'a impl AsStoreRef,
memory: &'a Memory,
offset: u64,
len: u64,

View File

@ -1,7 +1,7 @@
mod context;
mod exports;
mod extern_ref;
mod externals;
mod function_env;
mod imports;
mod instance;
mod mem_access;
@ -13,18 +13,19 @@ mod store;
mod tunables;
mod value;
pub use crate::sys::context::{AsContextMut, AsContextRef, Context, ContextMut, ContextRef};
pub use crate::sys::exports::{ExportError, Exportable, Exports, ExportsIterator};
pub use crate::sys::extern_ref::ExternRef;
pub use crate::sys::externals::{
Extern, FromToNativeWasmType, Function, Global, HostFunction, Memory, Table, WasmTypeList,
};
pub use crate::sys::function_env::{FunctionEnv, FunctionEnvMut};
pub use crate::sys::imports::Imports;
pub use crate::sys::instance::{Instance, InstantiationError};
pub use crate::sys::mem_access::{MemoryAccessError, WasmRef, WasmSlice, WasmSliceIter};
pub use crate::sys::module::Module;
pub use crate::sys::native::TypedFunction;
pub use crate::sys::native_type::NativeWasmTypeInto;
pub use crate::sys::store::{AsStoreMut, AsStoreRef, StoreMut, StoreRef};
pub use crate::sys::ptr::{Memory32, Memory64, MemorySize, WasmPtr, WasmPtr64};
pub use crate::sys::store::Store;
@ -81,7 +82,7 @@ If you wish to use more than one compiler, you can simply create the own store.
use wasmer::{Store, Universal, Singlepass};
let engine = Universal::new(Singlepass::default()).engine();
let store = Store::new_with_engine(&engine);
let mut store = Store::new_with_engine(&engine);
```"#
);

View File

@ -1,5 +1,6 @@
use crate::sys::store::Store;
use crate::sys::InstantiationError;
use crate::AsStoreMut;
use crate::AsStoreRef;
use std::fmt;
use std::io;
use std::path::Path;
@ -14,8 +15,6 @@ use wasmer_types::{
use wasmer_types::{ExportType, ImportType};
use wasmer_vm::InstanceHandle;
use super::context::AsContextMut;
#[derive(Error, Debug)]
pub enum IoCompileError {
/// An IO error
@ -51,7 +50,6 @@ pub struct Module {
// In the future, this code should be refactored to properly describe the
// ownership of the code and its metadata.
artifact: Arc<dyn Artifact>,
store: Store,
}
impl Module {
@ -81,7 +79,7 @@ impl Module {
/// ```
/// use wasmer::*;
/// # fn main() -> anyhow::Result<()> {
/// # let store = Store::default();
/// # let mut store = Store::default();
/// let wat = "(module)";
/// let module = Module::new(&store, wat)?;
/// # Ok(())
@ -93,7 +91,7 @@ impl Module {
/// ```
/// use wasmer::*;
/// # fn main() -> anyhow::Result<()> {
/// # let store = Store::default();
/// # let mut store = Store::default();
/// // The following is the same as:
/// // (module
/// // (type $t0 (func (param i32) (result i32)))
@ -115,7 +113,7 @@ impl Module {
/// # }
/// ```
#[allow(unreachable_code)]
pub fn new(store: &Store, bytes: impl AsRef<[u8]>) -> Result<Self, CompileError> {
pub fn new(store: &impl AsStoreRef, bytes: impl AsRef<[u8]>) -> Result<Self, CompileError> {
#[cfg(feature = "wat")]
let bytes = wat::parse_bytes(bytes.as_ref()).map_err(|e| {
CompileError::Wasm(WasmError::Generic(format!(
@ -128,7 +126,10 @@ impl Module {
}
/// Creates a new WebAssembly module from a file path.
pub fn from_file(store: &Store, file: impl AsRef<Path>) -> Result<Self, IoCompileError> {
pub fn from_file(
store: &impl AsStoreRef,
file: impl AsRef<Path>,
) -> Result<Self, IoCompileError> {
let file_ref = file.as_ref();
let canonical = file_ref.canonicalize()?;
let wasm_bytes = std::fs::read(file_ref)?;
@ -145,7 +146,7 @@ impl Module {
/// Opposed to [`Module::new`], this function is not compatible with
/// the WebAssembly text format (if the "wat" feature is enabled for
/// this crate).
pub fn from_binary(store: &Store, binary: &[u8]) -> Result<Self, CompileError> {
pub fn from_binary(store: &impl AsStoreRef, binary: &[u8]) -> Result<Self, CompileError> {
Self::validate(store, binary)?;
unsafe { Self::from_binary_unchecked(store, binary) }
}
@ -158,7 +159,7 @@ impl Module {
/// in environments where the WebAssembly modules are trusted and validated
/// beforehand.
pub unsafe fn from_binary_unchecked(
store: &Store,
store: &impl AsStoreRef,
binary: &[u8],
) -> Result<Self, CompileError> {
let module = Self::compile(store, binary)?;
@ -171,13 +172,16 @@ impl Module {
/// This validation is normally pretty fast and checks the enabled
/// WebAssembly features in the Store Engine to assure deterministic
/// validation of the Module.
pub fn validate(store: &Store, binary: &[u8]) -> Result<(), CompileError> {
store.engine().validate(binary)
pub fn validate(store: &impl AsStoreRef, binary: &[u8]) -> Result<(), CompileError> {
store.as_store_ref().engine().validate(binary)
}
fn compile(store: &Store, binary: &[u8]) -> Result<Self, CompileError> {
let artifact = store.engine().compile(binary, store.tunables())?;
Ok(Self::from_artifact(store, artifact))
fn compile(store: &impl AsStoreRef, binary: &[u8]) -> Result<Self, CompileError> {
let artifact = store
.as_store_ref()
.engine()
.compile(binary, store.as_store_ref().tunables())?;
Ok(Self::from_artifact(artifact))
}
/// Serializes a module into a binary representation that the `Engine`
@ -188,7 +192,7 @@ impl Module {
/// ```ignore
/// # use wasmer::*;
/// # fn main() -> anyhow::Result<()> {
/// # let store = Store::default();
/// # let mut store = Store::default();
/// # let module = Module::from_file(&store, "path/to/foo.wasm")?;
/// let serialized = module.serialize()?;
/// # Ok(())
@ -206,7 +210,7 @@ impl Module {
/// ```ignore
/// # use wasmer::*;
/// # fn main() -> anyhow::Result<()> {
/// # let store = Store::default();
/// # let mut store = Store::default();
/// # let module = Module::from_file(&store, "path/to/foo.wasm")?;
/// module.serialize_to_file("path/to/foo.so")?;
/// # Ok(())
@ -234,14 +238,17 @@ impl Module {
/// ```ignore
/// # use wasmer::*;
/// # fn main() -> anyhow::Result<()> {
/// # let store = Store::default();
/// # let mut store = Store::default();
/// let module = Module::deserialize(&store, serialized_data)?;
/// # Ok(())
/// # }
/// ```
pub unsafe fn deserialize(store: &Store, bytes: &[u8]) -> Result<Self, DeserializeError> {
let artifact = store.engine().deserialize(bytes)?;
Ok(Self::from_artifact(store, artifact))
pub unsafe fn deserialize(
store: &impl AsStoreRef,
bytes: &[u8],
) -> Result<Self, DeserializeError> {
let artifact = store.as_store_ref().engine().deserialize(bytes)?;
Ok(Self::from_artifact(artifact))
}
/// Deserializes a a serialized Module located in a `Path` into a `Module`.
@ -255,47 +262,48 @@ impl Module {
///
/// ```ignore
/// # use wasmer::*;
/// # let store = Store::default();
/// # let mut store = Store::default();
/// # fn main() -> anyhow::Result<()> {
/// let module = Module::deserialize_from_file(&store, path)?;
/// # Ok(())
/// # }
/// ```
pub unsafe fn deserialize_from_file(
store: &Store,
store: &impl AsStoreRef,
path: impl AsRef<Path>,
) -> Result<Self, DeserializeError> {
let artifact = store.engine().deserialize_from_file(path.as_ref())?;
Ok(Self::from_artifact(store, artifact))
let artifact = store
.as_store_ref()
.engine()
.deserialize_from_file(path.as_ref())?;
Ok(Self::from_artifact(artifact))
}
fn from_artifact(store: &Store, artifact: Arc<dyn Artifact>) -> Self {
Self {
store: store.clone(),
artifact,
}
fn from_artifact(artifact: Arc<dyn Artifact>) -> Self {
Self { artifact }
}
pub(crate) fn instantiate(
&self,
ctx: &mut impl AsContextMut,
store: &mut impl AsStoreMut,
imports: &[crate::Extern],
) -> Result<InstanceHandle, InstantiationError> {
// Ensure all imports come from the same context.
for import in imports {
if !import.is_from_context(ctx) {
return Err(InstantiationError::BadContext);
if !import.is_from_store(store) {
return Err(InstantiationError::DifferentStores);
}
}
let mut store_mut = store.as_store_mut();
let (tunables, objects) = store_mut.tunables_and_objects_mut();
unsafe {
let mut instance_handle = self.artifact.instantiate(
self.store.tunables(),
tunables,
&imports
.iter()
.map(crate::Extern::to_vm_extern)
.collect::<Vec<_>>(),
ctx.as_context_mut().objects_mut(),
objects,
)?;
// After the instance handle is created, we need to initialize
@ -303,8 +311,10 @@ impl Module {
// of this steps traps, we still need to keep the instance alive
// as some of the Instance elements may have placed in other
// instance tables.
self.artifact
.finish_instantiation(&self.store, &mut instance_handle)?;
self.artifact.finish_instantiation(
store.as_store_ref().signal_handler(),
&mut instance_handle,
)?;
Ok(instance_handle)
}
@ -320,7 +330,7 @@ impl Module {
/// ```
/// # use wasmer::*;
/// # fn main() -> anyhow::Result<()> {
/// # let store = Store::default();
/// # let mut store = Store::default();
/// let wat = "(module $moduleName)";
/// let module = Module::new(&store, wat)?;
/// assert_eq!(module.name(), Some("moduleName"));
@ -343,7 +353,7 @@ impl Module {
/// ```
/// # use wasmer::*;
/// # fn main() -> anyhow::Result<()> {
/// # let store = Store::default();
/// # let mut store = Store::default();
/// let wat = "(module)";
/// let mut module = Module::new(&store, wat)?;
/// assert_eq!(module.name(), None);
@ -371,7 +381,7 @@ impl Module {
/// ```
/// # use wasmer::*;
/// # fn main() -> anyhow::Result<()> {
/// # let store = Store::default();
/// # let mut store = Store::default();
/// let wat = r#"(module
/// (import "host" "func1" (func))
/// (import "host" "func2" (func))
@ -399,7 +409,7 @@ impl Module {
/// ```
/// # use wasmer::*;
/// # fn main() -> anyhow::Result<()> {
/// # let store = Store::default();
/// # let mut store = Store::default();
/// let wat = r#"(module
/// (func (export "namedfunc"))
/// (memory (export "namedmemory") 1)
@ -427,11 +437,6 @@ impl Module {
self.artifact.module_ref().custom_sections(name)
}
/// Returns the [`Store`] where the `Instance` belongs.
pub fn store(&self) -> &Store {
&self.store
}
/// The ABI of the ModuleInfo is very unstable, we refactor it very often.
/// This function is public because in some cases it can be useful to get some
/// extra information from the module.

View File

@ -10,7 +10,7 @@
use std::marker::PhantomData;
use crate::sys::{
AsContextMut, FromToNativeWasmType, Function, NativeWasmTypeInto, RuntimeError, WasmTypeList,
AsStoreMut, FromToNativeWasmType, Function, NativeWasmTypeInto, RuntimeError, WasmTypeList,
};
use wasmer_types::RawValue;
@ -66,17 +66,17 @@ macro_rules! impl_native_traits {
/// Call the typed func and return results.
#[allow(unused_mut)]
#[allow(clippy::too_many_arguments)]
pub fn call(&self, ctx: &mut impl AsContextMut, $( $x: $x, )* ) -> Result<Rets, RuntimeError> {
pub fn call(&self, ctx: &mut impl AsStoreMut, $( $x: $x, )* ) -> Result<Rets, RuntimeError> {
let anyfunc = unsafe {
*self.func
.handle
.get(ctx.as_context_ref().objects())
.get(ctx.as_store_ref().objects())
.anyfunc
.as_ptr()
.as_ref()
};
// Ensure all parameters come from the same context.
if $(!FromToNativeWasmType::is_from_context(&$x, ctx) ||)* false {
if $(!FromToNativeWasmType::is_from_store(&$x, ctx) ||)* false {
return Err(RuntimeError::new(
"cross-`Context` values are not supported",
));
@ -99,7 +99,7 @@ macro_rules! impl_native_traits {
};
unsafe {
wasmer_vm::wasmer_call_trampoline(
ctx.as_context_ref().store(),
ctx.as_store_ref().signal_handler(),
anyfunc.vmctx,
anyfunc.call_trampoline,
anyfunc.func_ptr,

View File

@ -6,133 +6,133 @@ use wasmer_vm::{VMExternRef, VMFuncRef};
use crate::{ExternRef, Function};
use super::context::AsContextMut;
use super::store::AsStoreMut;
/// `NativeWasmTypeInto` performs conversions from and into `NativeWasmType`
/// types with a context.
pub trait NativeWasmTypeInto: NativeWasmType + Sized {
#[doc(hidden)]
fn into_abi(self, ctx: &mut impl AsContextMut) -> Self::Abi;
fn into_abi(self, ctx: &mut impl AsStoreMut) -> Self::Abi;
#[doc(hidden)]
unsafe fn from_abi(ctx: &mut impl AsContextMut, abi: Self::Abi) -> Self;
unsafe fn from_abi(ctx: &mut impl AsStoreMut, abi: Self::Abi) -> Self;
/// Convert self to raw value representation.
fn into_raw(self, ctx: &mut impl AsContextMut) -> RawValue;
fn into_raw(self, ctx: &mut impl AsStoreMut) -> RawValue;
/// Convert to self from raw value representation.
///
/// # Safety
///
unsafe fn from_raw(ctx: &mut impl AsContextMut, raw: RawValue) -> Self;
unsafe fn from_raw(ctx: &mut impl AsStoreMut, raw: RawValue) -> Self;
}
impl NativeWasmTypeInto for i32 {
#[inline]
unsafe fn from_abi(_ctx: &mut impl AsContextMut, abi: Self::Abi) -> Self {
unsafe fn from_abi(_ctx: &mut impl AsStoreMut, abi: Self::Abi) -> Self {
abi
}
#[inline]
fn into_abi(self, _ctx: &mut impl AsContextMut) -> Self::Abi {
fn into_abi(self, _ctx: &mut impl AsStoreMut) -> Self::Abi {
self
}
#[inline]
fn into_raw(self, _ctx: &mut impl AsContextMut) -> RawValue {
fn into_raw(self, _ctx: &mut impl AsStoreMut) -> RawValue {
RawValue { i32: self }
}
#[inline]
unsafe fn from_raw(_ctx: &mut impl AsContextMut, raw: RawValue) -> Self {
unsafe fn from_raw(_ctx: &mut impl AsStoreMut, raw: RawValue) -> Self {
raw.i32
}
}
impl NativeWasmTypeInto for i64 {
#[inline]
unsafe fn from_abi(_ctx: &mut impl AsContextMut, abi: Self::Abi) -> Self {
unsafe fn from_abi(_ctx: &mut impl AsStoreMut, abi: Self::Abi) -> Self {
abi
}
#[inline]
fn into_abi(self, _ctx: &mut impl AsContextMut) -> Self::Abi {
fn into_abi(self, _ctx: &mut impl AsStoreMut) -> Self::Abi {
self
}
#[inline]
fn into_raw(self, _ctx: &mut impl AsContextMut) -> RawValue {
fn into_raw(self, _ctx: &mut impl AsStoreMut) -> RawValue {
RawValue { i64: self }
}
#[inline]
unsafe fn from_raw(_ctx: &mut impl AsContextMut, raw: RawValue) -> Self {
unsafe fn from_raw(_ctx: &mut impl AsStoreMut, raw: RawValue) -> Self {
raw.i64
}
}
impl NativeWasmTypeInto for f32 {
#[inline]
unsafe fn from_abi(_ctx: &mut impl AsContextMut, abi: Self::Abi) -> Self {
unsafe fn from_abi(_ctx: &mut impl AsStoreMut, abi: Self::Abi) -> Self {
abi
}
#[inline]
fn into_abi(self, _ctx: &mut impl AsContextMut) -> Self::Abi {
fn into_abi(self, _ctx: &mut impl AsStoreMut) -> Self::Abi {
self
}
#[inline]
fn into_raw(self, _ctx: &mut impl AsContextMut) -> RawValue {
fn into_raw(self, _ctx: &mut impl AsStoreMut) -> RawValue {
RawValue { f32: self }
}
#[inline]
unsafe fn from_raw(_ctx: &mut impl AsContextMut, raw: RawValue) -> Self {
unsafe fn from_raw(_ctx: &mut impl AsStoreMut, raw: RawValue) -> Self {
raw.f32
}
}
impl NativeWasmTypeInto for f64 {
#[inline]
unsafe fn from_abi(_ctx: &mut impl AsContextMut, abi: Self::Abi) -> Self {
unsafe fn from_abi(_ctx: &mut impl AsStoreMut, abi: Self::Abi) -> Self {
abi
}
#[inline]
fn into_abi(self, _ctx: &mut impl AsContextMut) -> Self::Abi {
fn into_abi(self, _ctx: &mut impl AsStoreMut) -> Self::Abi {
self
}
#[inline]
fn into_raw(self, _ctx: &mut impl AsContextMut) -> RawValue {
fn into_raw(self, _ctx: &mut impl AsStoreMut) -> RawValue {
RawValue { f64: self }
}
#[inline]
unsafe fn from_raw(_ctx: &mut impl AsContextMut, raw: RawValue) -> Self {
unsafe fn from_raw(_ctx: &mut impl AsStoreMut, raw: RawValue) -> Self {
raw.f64
}
}
impl NativeWasmTypeInto for u128 {
#[inline]
unsafe fn from_abi(_ctx: &mut impl AsContextMut, abi: Self::Abi) -> Self {
unsafe fn from_abi(_ctx: &mut impl AsStoreMut, abi: Self::Abi) -> Self {
abi
}
#[inline]
fn into_abi(self, _ctx: &mut impl AsContextMut) -> Self::Abi {
fn into_abi(self, _ctx: &mut impl AsStoreMut) -> Self::Abi {
self
}
#[inline]
fn into_raw(self, _ctx: &mut impl AsContextMut) -> RawValue {
fn into_raw(self, _ctx: &mut impl AsStoreMut) -> RawValue {
RawValue { u128: self }
}
#[inline]
unsafe fn from_raw(_ctx: &mut impl AsContextMut, raw: RawValue) -> Self {
unsafe fn from_raw(_ctx: &mut impl AsStoreMut, raw: RawValue) -> Self {
raw.u128
}
}
@ -144,23 +144,23 @@ impl NativeWasmType for ExternRef {
impl NativeWasmTypeInto for Option<ExternRef> {
#[inline]
unsafe fn from_abi(ctx: &mut impl AsContextMut, abi: Self::Abi) -> Self {
unsafe fn from_abi(ctx: &mut impl AsStoreMut, abi: Self::Abi) -> Self {
VMExternRef::from_raw(RawValue { externref: abi })
.map(|e| ExternRef::from_vm_externref(ctx, e))
}
#[inline]
fn into_abi(self, _ctx: &mut impl AsContextMut) -> Self::Abi {
fn into_abi(self, _ctx: &mut impl AsStoreMut) -> Self::Abi {
self.map_or(0, |e| unsafe { e.vm_externref().into_raw().externref })
}
#[inline]
fn into_raw(self, _ctx: &mut impl AsContextMut) -> RawValue {
fn into_raw(self, _ctx: &mut impl AsStoreMut) -> RawValue {
self.map_or(RawValue { externref: 0 }, |e| e.vm_externref().into_raw())
}
#[inline]
unsafe fn from_raw(ctx: &mut impl AsContextMut, raw: RawValue) -> Self {
unsafe fn from_raw(ctx: &mut impl AsStoreMut, raw: RawValue) -> Self {
VMExternRef::from_raw(raw).map(|e| ExternRef::from_vm_externref(ctx, e))
}
}
@ -172,22 +172,22 @@ impl NativeWasmType for Function {
impl NativeWasmTypeInto for Option<Function> {
#[inline]
unsafe fn from_abi(ctx: &mut impl AsContextMut, abi: Self::Abi) -> Self {
unsafe fn from_abi(ctx: &mut impl AsStoreMut, abi: Self::Abi) -> Self {
VMFuncRef::from_raw(RawValue { funcref: abi }).map(|f| Function::from_vm_funcref(ctx, f))
}
#[inline]
fn into_abi(self, ctx: &mut impl AsContextMut) -> Self::Abi {
fn into_abi(self, ctx: &mut impl AsStoreMut) -> Self::Abi {
self.map_or(0, |f| unsafe { f.vm_funcref(ctx).into_raw().externref })
}
#[inline]
fn into_raw(self, ctx: &mut impl AsContextMut) -> RawValue {
fn into_raw(self, ctx: &mut impl AsStoreMut) -> RawValue {
self.map_or(RawValue { externref: 0 }, |e| e.vm_funcref(ctx).into_raw())
}
#[inline]
unsafe fn from_raw(ctx: &mut impl AsContextMut, raw: RawValue) -> Self {
unsafe fn from_raw(ctx: &mut impl AsStoreMut, raw: RawValue) -> Self {
VMFuncRef::from_raw(raw).map(|f| Function::from_vm_funcref(ctx, f))
}
}

View File

@ -5,13 +5,11 @@ use std::convert::TryFrom;
use std::{fmt, marker::PhantomData, mem};
use wasmer_types::ValueType;
use super::context::AsContextRef;
pub use wasmer_types::MemorySize;
use super::store::AsStoreRef;
pub use wasmer_types::Memory32;
pub use wasmer_types::Memory64;
pub use wasmer_types::MemorySize;
/// Alias for `WasmPtr<T, Memory64>.
pub type WasmPtr64<T> = WasmPtr<T, Memory64>;
@ -23,8 +21,8 @@ pub type WasmPtr64<T> = WasmPtr<T, Memory64>;
/// ```
/// # use wasmer::Memory;
/// # use wasmer::WasmPtr;
/// # use wasmer::ContextMut;
/// pub fn host_import(mut ctx: ContextMut<()>, memory: Memory, ptr: WasmPtr<u32>) {
/// # use wasmer::FunctionEnvMut;
/// pub fn host_import(mut ctx: FunctionEnvMut<()>, memory: Memory, ptr: WasmPtr<u32>) {
/// let derefed_ptr = ptr.deref(&mut ctx, &memory);
/// let inner_val: u32 = derefed_ptr.read().expect("pointer in bounds");
/// println!("Got {} from Wasm memory address 0x{:X}", inner_val, ptr.offset());
@ -39,7 +37,7 @@ pub type WasmPtr64<T> = WasmPtr<T, Memory64>;
/// # use wasmer::Memory;
/// # use wasmer::WasmPtr;
/// # use wasmer::ValueType;
/// # use wasmer::ContextMut;
/// # use wasmer::FunctionEnvMut;
///
/// // This is safe as the 12 bytes represented by this struct
/// // are valid for all bit combinations.
@ -51,7 +49,7 @@ pub type WasmPtr64<T> = WasmPtr<T, Memory64>;
/// z: f32
/// }
///
/// fn update_vector_3(mut ctx: ContextMut<()>, memory: Memory, ptr: WasmPtr<V3>) {
/// fn update_vector_3(mut ctx: FunctionEnvMut<()>, memory: Memory, ptr: WasmPtr<V3>) {
/// let derefed_ptr = ptr.deref(&mut ctx, &memory);
/// let mut inner_val: V3 = derefed_ptr.read().expect("pointer in bounds");
/// println!("Got {:?} from Wasm memory address 0x{:X}", inner_val, ptr.offset());
@ -144,13 +142,13 @@ impl<T: ValueType, M: MemorySize> WasmPtr<T, M> {
/// Creates a `WasmRef` from this `WasmPtr` which allows reading and
/// mutating of the value being pointed to.
#[inline]
pub fn deref<'a>(self, ctx: &'a impl AsContextRef, memory: &'a Memory) -> WasmRef<'a, T> {
pub fn deref<'a>(self, ctx: &'a impl AsStoreRef, memory: &'a Memory) -> WasmRef<'a, T> {
WasmRef::new(ctx, memory, self.offset.into())
}
/// Reads the address pointed to by this `WasmPtr` in a memory.
#[inline]
pub fn read(self, ctx: &impl AsContextRef, memory: &Memory) -> Result<T, MemoryAccessError> {
pub fn read(self, ctx: &impl AsStoreRef, memory: &Memory) -> Result<T, MemoryAccessError> {
self.deref(&ctx, memory).read()
}
@ -158,7 +156,7 @@ impl<T: ValueType, M: MemorySize> WasmPtr<T, M> {
#[inline]
pub fn write(
self,
ctx: &impl AsContextRef,
ctx: &impl AsStoreRef,
memory: &Memory,
val: T,
) -> Result<(), MemoryAccessError> {
@ -173,7 +171,7 @@ impl<T: ValueType, M: MemorySize> WasmPtr<T, M> {
#[inline]
pub fn slice<'a>(
self,
ctx: &'a impl AsContextRef,
ctx: &'a impl AsStoreRef,
memory: &'a Memory,
len: M::Offset,
) -> Result<WasmSlice<'a, T>, MemoryAccessError> {
@ -187,7 +185,7 @@ impl<T: ValueType, M: MemorySize> WasmPtr<T, M> {
#[inline]
pub fn read_until(
self,
ctx: &impl AsContextRef,
ctx: &impl AsStoreRef,
memory: &Memory,
mut end: impl FnMut(&T) -> bool,
) -> Result<Vec<T>, MemoryAccessError> {
@ -212,7 +210,7 @@ impl<M: MemorySize> WasmPtr<u8, M> {
#[inline]
pub fn read_utf8_string(
self,
ctx: &impl AsContextRef,
ctx: &impl AsStoreRef,
memory: &Memory,
len: M::Offset,
) -> Result<String, MemoryAccessError> {
@ -227,7 +225,7 @@ impl<M: MemorySize> WasmPtr<u8, M> {
#[inline]
pub fn read_utf8_string_with_nul(
self,
ctx: &impl AsContextRef,
ctx: &impl AsStoreRef,
memory: &Memory,
) -> Result<String, MemoryAccessError> {
let vec = self.read_until(ctx, memory, |&byte| byte == 0)?;

View File

@ -1,9 +1,21 @@
use crate::sys::tunables::BaseTunables;
use std::fmt;
use std::sync::{Arc, RwLock};
use std::sync::Arc;
use wasmer_compiler::CompilerConfig;
use wasmer_compiler::{Engine, Tunables, Universal};
use wasmer_vm::{init_traps, TrapHandler, TrapHandlerFn};
use wasmer_vm::{init_traps, TrapHandlerFn};
use wasmer_vm::StoreObjects;
/// We require the context to have a fixed memory address for its lifetime since
/// various bits of the VM have raw pointers that point back to it. Hence we
/// wrap the actual context in a box.
pub(crate) struct StoreInner {
pub(crate) objects: StoreObjects,
pub(crate) engine: Arc<dyn Engine + Send + Sync>,
pub(crate) tunables: Box<dyn Tunables + Send + Sync>,
pub(crate) trap_handler: Option<Box<TrapHandlerFn<'static>>>,
}
/// The store represents all global state that can be manipulated by
/// WebAssembly programs. It consists of the runtime representation
@ -15,11 +27,8 @@ use wasmer_vm::{init_traps, TrapHandler, TrapHandlerFn};
/// [`Tunables`] (that are used to create the memories, tables and globals).
///
/// Spec: <https://webassembly.github.io/spec/core/exec/runtime.html#store>
#[derive(Clone)]
pub struct Store {
engine: Arc<dyn Engine + Send + Sync>,
tunables: Arc<dyn Tunables + Send + Sync>,
trap_handler: Arc<RwLock<Option<Box<TrapHandlerFn>>>>,
pub(crate) inner: Box<StoreInner>,
}
impl Store {
@ -38,9 +47,8 @@ impl Store {
}
/// Set the trap handler in this store.
pub fn set_trap_handler(&self, handler: Option<Box<TrapHandlerFn>>) {
let mut m = self.trap_handler.write().unwrap();
*m = handler;
pub fn set_trap_handler(&mut self, handler: Option<Box<TrapHandlerFn<'static>>>) {
self.inner.trap_handler = handler;
}
/// Creates a new `Store` with a specific [`Engine`] and [`Tunables`].
@ -53,46 +61,22 @@ impl Store {
init_traps();
Self {
engine: engine.cloned(),
tunables: Arc::new(tunables),
trap_handler: Arc::new(RwLock::new(None)),
}
}
/// Returns the [`Tunables`].
pub fn tunables(&self) -> &dyn Tunables {
self.tunables.as_ref()
}
/// Returns the [`Engine`].
pub fn engine(&self) -> &Arc<dyn Engine + Send + Sync> {
&self.engine
}
/// Checks whether two stores are identical. A store is considered
/// equal to another store if both have the same engine. The
/// tunables are excluded from the logic.
pub fn same(a: &Self, b: &Self) -> bool {
a.engine.id() == b.engine.id()
}
}
impl PartialEq for Store {
fn eq(&self, other: &Self) -> bool {
Self::same(self, other)
}
}
unsafe impl TrapHandler for Store {
fn custom_trap_handler(&self, call: &dyn Fn(&TrapHandlerFn) -> bool) -> bool {
if let Some(handler) = self.trap_handler.read().unwrap().as_ref() {
call(handler)
} else {
false
inner: Box::new(StoreInner {
objects: Default::default(),
engine: engine.cloned(),
tunables: Box::new(tunables),
trap_handler: None,
}),
}
}
}
// impl PartialEq for Store {
// fn eq(&self, other: &Self) -> bool {
// Self::same(self, other)
// }
// }
// This is required to be able to set the trap_handler in the
// Store.
unsafe impl Send for Store {}
@ -139,8 +123,151 @@ impl Default for Store {
}
}
impl AsStoreRef for Store {
fn as_store_ref(&self) -> StoreRef<'_> {
StoreRef { inner: &self.inner }
}
}
impl AsStoreMut for Store {
fn as_store_mut(&mut self) -> StoreMut<'_> {
StoreMut {
inner: &mut self.inner,
}
}
fn objects_mut(&mut self) -> &mut StoreObjects {
&mut self.inner.objects
}
}
impl fmt::Debug for Store {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Store").finish()
}
}
/// A temporary handle to a [`Context`].
pub struct StoreRef<'a> {
pub(crate) inner: &'a StoreInner,
}
impl<'a> StoreRef<'a> {
pub(crate) fn objects(&self) -> &'a StoreObjects {
&self.inner.objects
}
/// Returns the [`Tunables`].
pub fn tunables(&self) -> &dyn Tunables {
self.inner.tunables.as_ref()
}
/// Returns the [`Engine`].
pub fn engine(&self) -> &Arc<dyn Engine + Send + Sync> {
&self.inner.engine
}
/// Checks whether two stores are identical. A store is considered
/// equal to another store if both have the same engine. The
/// tunables are excluded from the logic.
pub fn same(a: &Self, b: &Self) -> bool {
a.inner.engine.id() == b.inner.engine.id()
}
/// The signal handler
#[inline]
pub fn signal_handler(&self) -> Option<*const TrapHandlerFn<'static>> {
self.inner
.trap_handler
.as_ref()
.map(|handler| &*handler as *const _)
}
}
/// A temporary handle to a [`Context`].
pub struct StoreMut<'a> {
pub(crate) inner: &'a mut StoreInner,
}
impl<'a> StoreMut<'a> {
/// Returns the [`Tunables`].
pub fn tunables(&self) -> &dyn Tunables {
self.inner.tunables.as_ref()
}
/// Returns the [`Engine`].
pub fn engine(&self) -> &Arc<dyn Engine + Send + Sync> {
&self.inner.engine
}
/// Checks whether two stores are identical. A store is considered
/// equal to another store if both have the same engine. The
/// tunables are excluded from the logic.
pub fn same(a: &Self, b: &Self) -> bool {
a.inner.engine.id() == b.inner.engine.id()
}
pub(crate) fn tunables_and_objects_mut(&mut self) -> (&dyn Tunables, &mut StoreObjects) {
(self.inner.tunables.as_ref(), &mut self.inner.objects)
}
pub(crate) fn as_raw(&self) -> *mut StoreInner {
self.inner as *const StoreInner as *mut StoreInner
}
pub(crate) unsafe fn from_raw(raw: *mut StoreInner) -> Self {
Self { inner: &mut *raw }
}
}
/// Helper trait for a value that is convertible to a [`StoreRef`].
pub trait AsStoreRef {
/// Returns a `StoreRef` pointing to the underlying context.
fn as_store_ref(&self) -> StoreRef<'_>;
}
/// Helper trait for a value that is convertible to a [`StoreMut`].
pub trait AsStoreMut: AsStoreRef {
/// Returns a `StoreMut` pointing to the underlying context.
fn as_store_mut(&mut self) -> StoreMut<'_>;
/// Returns the ObjectMutable
fn objects_mut(&mut self) -> &mut StoreObjects;
}
impl AsStoreRef for StoreRef<'_> {
fn as_store_ref(&self) -> StoreRef<'_> {
StoreRef { inner: self.inner }
}
}
impl AsStoreRef for StoreMut<'_> {
fn as_store_ref(&self) -> StoreRef<'_> {
StoreRef { inner: self.inner }
}
}
impl AsStoreMut for StoreMut<'_> {
fn as_store_mut(&mut self) -> StoreMut<'_> {
StoreMut { inner: self.inner }
}
fn objects_mut(&mut self) -> &mut StoreObjects {
&mut self.inner.objects
}
}
impl<T: AsStoreRef> AsStoreRef for &'_ T {
fn as_store_ref(&self) -> StoreRef<'_> {
T::as_store_ref(*self)
}
}
impl<T: AsStoreRef> AsStoreRef for &'_ mut T {
fn as_store_ref(&self) -> StoreRef<'_> {
T::as_store_ref(*self)
}
}
impl<T: AsStoreMut> AsStoreMut for &'_ mut T {
fn as_store_mut(&mut self) -> StoreMut<'_> {
T::as_store_mut(*self)
}
fn objects_mut(&mut self) -> &mut StoreObjects {
T::objects_mut(*self)
}
}

View File

@ -9,8 +9,7 @@ use wasmer_vm::VMFuncRef;
use crate::ExternRef;
use crate::Function;
use super::context::AsContextMut;
use super::context::AsContextRef;
use super::store::{AsStoreMut, AsStoreRef};
pub use wasmer_types::RawValue;
@ -92,7 +91,7 @@ impl Value {
}
/// Converts the `Value` into a `RawValue`.
pub fn as_raw(&self, ctx: &impl AsContextRef) -> RawValue {
pub fn as_raw(&self, ctx: &impl AsStoreRef) -> RawValue {
match *self {
Self::I32(i32) => RawValue { i32 },
Self::I64(i64) => RawValue { i64 },
@ -111,7 +110,7 @@ impl Value {
///
/// # Safety
///
pub unsafe fn from_raw(ctx: &mut impl AsContextMut, ty: Type, raw: RawValue) -> Self {
pub unsafe fn from_raw(ctx: &mut impl AsStoreMut, ty: Type, raw: RawValue) -> Self {
match ty {
Type::I32 => Self::I32(raw.i32),
Type::I64 => Self::I64(raw.i64),
@ -134,7 +133,7 @@ impl Value {
///
/// Externref and funcref values are tied to a context and can only be used
/// with that context.
pub fn is_from_context(&self, ctx: &impl AsContextRef) -> bool {
pub fn is_from_store(&self, ctx: &impl AsStoreRef) -> bool {
match self {
Self::I32(_)
| Self::I64(_)
@ -143,8 +142,8 @@ impl Value {
| Self::V128(_)
| Self::ExternRef(None)
| Self::FuncRef(None) => true,
Self::ExternRef(Some(e)) => e.is_from_context(ctx),
Self::FuncRef(Some(f)) => f.is_from_context(ctx),
Self::ExternRef(Some(e)) => e.is_from_store(ctx),
Self::FuncRef(Some(f)) => f.is_from_store(ctx),
}
}

View File

@ -5,20 +5,20 @@ mod js {
#[wasm_bindgen_test]
fn global_new() {
let store = Store::default();
let mut ctx = Context::new(&store, ());
let global = Global::new(&mut ctx, Value::I32(10));
let mut store = Store::default();
let mut env = FunctionEnv::new(&mut store, ());
let global = Global::new(&mut store, Value::I32(10));
assert_eq!(
global.ty(&ctx),
global.ty(&store),
GlobalType {
ty: Type::I32,
mutability: Mutability::Const
}
);
let global_mut = Global::new_mut(&mut ctx, Value::I32(10));
let global_mut = Global::new_mut(&mut store, Value::I32(10));
assert_eq!(
global_mut.ty(&ctx),
global_mut.ty(&store),
GlobalType {
ty: Type::I32,
mutability: Mutability::Var
@ -28,50 +28,50 @@ mod js {
#[wasm_bindgen_test]
fn global_get() {
let store = Store::default();
let mut ctx = Context::new(&store, ());
let global_i32 = Global::new(&mut ctx, Value::I32(10));
assert_eq!(global_i32.get(&ctx), Value::I32(10));
let mut store = Store::default();
let mut env = FunctionEnv::new(&mut store, ());
let global_i32 = Global::new(&mut store, Value::I32(10));
assert_eq!(global_i32.get(&store), Value::I32(10));
// 64-bit values are not yet fully supported in some versions of Node
// Commenting this tests for now:
// let global_i64 = Global::new(&store, Value::I64(20));
// assert_eq!(global_i64.get(), Value::I64(20));
let global_f32 = Global::new(&mut ctx, Value::F32(10.0));
assert_eq!(global_f32.get(&ctx), Value::F32(10.0));
let global_f32 = Global::new(&mut store, Value::F32(10.0));
assert_eq!(global_f32.get(&store), Value::F32(10.0));
// let global_f64 = Global::new(&store, Value::F64(20.0));
// assert_eq!(global_f64.get(), Value::F64(20.0));
}
#[wasm_bindgen_test]
fn global_set() {
let store = Store::default();
let mut ctx = Context::new(&store, ());
let global_i32 = Global::new(&mut ctx, Value::I32(10));
let mut store = Store::default();
let mut env = FunctionEnv::new(&mut store, ());
let global_i32 = Global::new(&mut store, Value::I32(10));
// Set on a constant should error
assert!(global_i32.set(&mut ctx, Value::I32(20)).is_err());
assert!(global_i32.set(&mut store, Value::I32(20)).is_err());
let global_i32_mut = Global::new_mut(&mut ctx, Value::I32(10));
let global_i32_mut = Global::new_mut(&mut store, Value::I32(10));
// Set on different type should error
assert!(global_i32_mut.set(&mut ctx, Value::I64(20)).is_err());
assert!(global_i32_mut.set(&mut store, Value::I64(20)).is_err());
// Set on same type should succeed
global_i32_mut.set(&mut ctx, Value::I32(20)).unwrap();
assert_eq!(global_i32_mut.get(&ctx), Value::I32(20));
global_i32_mut.set(&mut store, Value::I32(20)).unwrap();
assert_eq!(global_i32_mut.get(&store), Value::I32(20));
}
#[wasm_bindgen_test]
fn table_new() {
let store = Store::default();
let mut ctx = Context::new(&store, ());
let mut store = Store::default();
let mut env = FunctionEnv::new(&mut store, ());
let table_type = TableType {
ty: Type::FuncRef,
minimum: 0,
maximum: None,
};
let f = Function::new_native(&mut ctx, |_: ContextMut<'_, ()>| {});
let table = Table::new(&mut ctx, table_type, Value::FuncRef(Some(f))).unwrap();
assert_eq!(table.ty(&ctx), table_type);
let f = Function::new_native(&mut store, &env, |_: FunctionEnvMut<'_, ()>| {});
let table = Table::new(&mut store, table_type, Value::FuncRef(Some(f))).unwrap();
assert_eq!(table.ty(&store), table_type);
// table.get()
// Anyrefs not yet supported
@ -81,7 +81,7 @@ mod js {
// maximum: None,
// };
// let table = Table::new(&store, table_type, Value::ExternRef(ExternRef::Null))?;
// assert_eq!(*table.ty(&ctx), table_type);
// assert_eq!(*table.ty(&store), table_type);
}
// Tables are not yet fully supported in Wasm
@ -90,16 +90,16 @@ mod js {
// #[test]
// #[ignore]
// fn table_get() -> Result<()> {
// let store = Store::default();
// let mut ctx = Context::new(&store, ());
// let mut store = Store::default();
// let mut env = FunctionEnv::new(&mut store, ());
// let table_type = TableType {
// ty: Type::FuncRef,
// minimum: 0,
// maximum: Some(1),
// };
// let f = Function::new(&mut ctx, |num: i32| num + 1);
// let f = Function::new(&mut store, &env, |num: i32| num + 1);
// let table = Table::new(&store, table_type, Value::FuncRef(Some(f.clone())))?;
// assert_eq!(*table.ty(&ctx), table_type);
// assert_eq!(*table.ty(&store), table_type);
// let _elem = table.get(0).unwrap();
// // assert_eq!(elem.funcref().unwrap(), f);
// Ok(())
@ -114,14 +114,14 @@ mod js {
// #[test]
// fn table_grow() -> Result<()> {
// let store = Store::default();
// let mut ctx = Context::new(&store, ());
// let mut store = Store::default();
// let mut env = FunctionEnv::new(&mut store, ());
// let table_type = TableType {
// ty: Type::FuncRef,
// minimum: 0,
// maximum: Some(10),
// };
// let f = Function::new(&mut ctx, |num: i32| num + 1);
// let f = Function::new(&mut store, &env, |num: i32| num + 1);
// let table = Table::new(&store, table_type, Value::FuncRef(Some(f.clone())))?;
// // Growing to a bigger maximum should return None
// let old_len = table.grow(12, Value::FuncRef(Some(f.clone())));
@ -143,32 +143,32 @@ mod js {
#[wasm_bindgen_test]
fn memory_new() {
let store = Store::default();
let mut ctx = Context::new(&store, ());
let mut store = Store::default();
let mut env = FunctionEnv::new(&mut store, ());
let memory_type = MemoryType {
shared: false,
minimum: Pages(0),
maximum: Some(Pages(10)),
};
let memory = Memory::new(&mut ctx, memory_type).unwrap();
assert_eq!(memory.size(&ctx), Pages(0));
assert_eq!(memory.ty(&ctx), memory_type);
let memory = Memory::new(&mut store, memory_type).unwrap();
assert_eq!(memory.size(&store), Pages(0));
assert_eq!(memory.ty(&store), memory_type);
}
#[wasm_bindgen_test]
fn memory_grow() {
let store = Store::default();
let mut ctx = Context::new(&store, ());
let mut store = Store::default();
let mut env = FunctionEnv::new(&mut store, ());
let desc = MemoryType::new(Pages(10), Some(Pages(16)), false);
let memory = Memory::new(&mut ctx, desc).unwrap();
assert_eq!(memory.size(&ctx), Pages(10));
let memory = Memory::new(&mut store, desc).unwrap();
assert_eq!(memory.size(&store), Pages(10));
let result = memory.grow(&mut ctx, Pages(2)).unwrap();
let result = memory.grow(&mut store, Pages(2)).unwrap();
assert_eq!(result, Pages(10));
assert_eq!(memory.size(&ctx), Pages(12));
assert_eq!(memory.size(&store), Pages(12));
let result = memory.grow(&mut ctx, Pages(10));
let result = memory.grow(&mut store, Pages(10));
assert!(result.is_err());
assert_eq!(
result,
@ -181,235 +181,270 @@ mod js {
#[wasm_bindgen_test]
fn function_new() {
let store = Store::default();
let mut ctx = Context::new(&store, ());
let function = Function::new_native(&mut ctx, |_ctx: ContextMut<'_, ()>| {});
assert_eq!(function.ty(&ctx).clone(), FunctionType::new(vec![], vec![]));
let function = Function::new_native(&mut ctx, |_ctx: ContextMut<'_, ()>, _a: i32| {});
let mut store = Store::default();
let mut env = FunctionEnv::new(&mut store, ());
let function = Function::new_native(&mut store, &env, |_ctx: FunctionEnvMut<'_, ()>| {});
assert_eq!(
function.ty(&ctx).clone(),
function.ty(&store).clone(),
FunctionType::new(vec![], vec![])
);
let function =
Function::new_native(&mut store, &env, |_ctx: FunctionEnvMut<'_, ()>, _a: i32| {});
assert_eq!(
function.ty(&store).clone(),
FunctionType::new(vec![Type::I32], vec![])
);
let function = Function::new_native(
&mut ctx,
|_ctx: ContextMut<'_, ()>, _a: i32, _b: i64, _c: f32, _d: f64| {},
&mut store,
&env,
|_ctx: FunctionEnvMut<'_, ()>, _a: i32, _b: i64, _c: f32, _d: f64| {},
);
assert_eq!(
function.ty(&ctx).clone(),
function.ty(&store).clone(),
FunctionType::new(vec![Type::I32, Type::I64, Type::F32, Type::F64], vec![])
);
let function = Function::new_native(&mut ctx, |_ctx: ContextMut<'_, ()>| -> i32 { 1 });
let function =
Function::new_native(&mut store, &env, |_ctx: FunctionEnvMut<'_, ()>| -> i32 {
1
});
assert_eq!(
function.ty(&ctx).clone(),
function.ty(&store).clone(),
FunctionType::new(vec![], vec![Type::I32])
);
let function = Function::new_native(
&mut ctx,
|_ctx: ContextMut<'_, ()>| -> (i32, i64, f32, f64) { (1, 2, 3.0, 4.0) },
&mut store,
&env,
|_ctx: FunctionEnvMut<'_, ()>| -> (i32, i64, f32, f64) { (1, 2, 3.0, 4.0) },
);
assert_eq!(
function.ty(&ctx).clone(),
function.ty(&store).clone(),
FunctionType::new(vec![], vec![Type::I32, Type::I64, Type::F32, Type::F64])
);
}
#[wasm_bindgen_test]
fn function_new_env() {
let store = Store::default();
let mut store = Store::default();
#[derive(Clone)]
struct MyEnv {}
let my_env = MyEnv {};
let mut ctx = Context::new(&store, my_env);
let mut env = FunctionEnv::new(&mut store, my_env);
let function = Function::new_native(&mut ctx, |_: ContextMut<'_, MyEnv>| {});
assert_eq!(function.ty(&ctx).clone(), FunctionType::new(vec![], vec![]));
let function = Function::new_native(&mut ctx, |_: ContextMut<'_, MyEnv>, _a: i32| {});
let function = Function::new_native(&mut store, &env, |_: FunctionEnvMut<'_, MyEnv>| {});
assert_eq!(
function.ty(&ctx).clone(),
function.ty(&store).clone(),
FunctionType::new(vec![], vec![])
);
let function =
Function::new_native(&mut store, &env, |_: FunctionEnvMut<'_, MyEnv>, _a: i32| {});
assert_eq!(
function.ty(&store).clone(),
FunctionType::new(vec![Type::I32], vec![])
);
let function = Function::new_native(
&mut ctx,
|_: ContextMut<'_, MyEnv>, _a: i32, _b: i64, _c: f32, _d: f64| {},
&mut store,
&env,
|_: FunctionEnvMut<'_, MyEnv>, _a: i32, _b: i64, _c: f32, _d: f64| {},
);
assert_eq!(
function.ty(&ctx).clone(),
function.ty(&store).clone(),
FunctionType::new(vec![Type::I32, Type::I64, Type::F32, Type::F64], vec![])
);
let function = Function::new_native(&mut ctx, |_: ContextMut<'_, MyEnv>| -> i32 { 1 });
let function =
Function::new_native(&mut store, &env, |_: FunctionEnvMut<'_, MyEnv>| -> i32 {
1
});
assert_eq!(
function.ty(&ctx).clone(),
function.ty(&store).clone(),
FunctionType::new(vec![], vec![Type::I32])
);
let function = Function::new_native(
&mut ctx,
|_: ContextMut<'_, MyEnv>| -> (i32, i64, f32, f64) { (1, 2, 3.0, 4.0) },
&mut store,
&env,
|_: FunctionEnvMut<'_, MyEnv>| -> (i32, i64, f32, f64) { (1, 2, 3.0, 4.0) },
);
assert_eq!(
function.ty(&ctx).clone(),
function.ty(&store).clone(),
FunctionType::new(vec![], vec![Type::I32, Type::I64, Type::F32, Type::F64])
);
}
#[wasm_bindgen_test]
fn function_new_dynamic() {
let store = Store::default();
let mut ctx = Context::new(&store, ());
let mut store = Store::default();
let mut env = FunctionEnv::new(&mut store, ());
// Using &FunctionType signature
let function_type = FunctionType::new(vec![], vec![]);
let function = Function::new(
&mut ctx,
&mut store,
&env,
&function_type,
|_ctx: ContextMut<'_, ()>, _values: &[Value]| unimplemented!(),
|_ctx: FunctionEnvMut<'_, ()>, _values: &[Value]| unimplemented!(),
);
assert_eq!(function.ty(&ctx).clone(), function_type);
assert_eq!(function.ty(&store).clone(), function_type);
let function_type = FunctionType::new(vec![Type::I32], vec![]);
let function = Function::new(
&mut ctx,
&mut store,
&env,
&function_type,
|_ctx: ContextMut<'_, ()>, _values: &[Value]| unimplemented!(),
|_ctx: FunctionEnvMut<'_, ()>, _values: &[Value]| unimplemented!(),
);
assert_eq!(function.ty(&ctx).clone(), function_type);
assert_eq!(function.ty(&store).clone(), function_type);
let function_type =
FunctionType::new(vec![Type::I32, Type::I64, Type::F32, Type::F64], vec![]);
let function = Function::new(
&mut ctx,
&mut store,
&env,
&function_type,
|_ctx: ContextMut<'_, ()>, _values: &[Value]| unimplemented!(),
|_ctx: FunctionEnvMut<'_, ()>, _values: &[Value]| unimplemented!(),
);
assert_eq!(function.ty(&ctx).clone(), function_type);
assert_eq!(function.ty(&store).clone(), function_type);
let function_type = FunctionType::new(vec![], vec![Type::I32]);
let function = Function::new(
&mut ctx,
&mut store,
&env,
&function_type,
|_ctx: ContextMut<'_, ()>, _values: &[Value]| unimplemented!(),
|_ctx: FunctionEnvMut<'_, ()>, _values: &[Value]| unimplemented!(),
);
assert_eq!(function.ty(&ctx).clone(), function_type);
assert_eq!(function.ty(&store).clone(), function_type);
let function_type =
FunctionType::new(vec![], vec![Type::I32, Type::I64, Type::F32, Type::F64]);
let function = Function::new(
&mut ctx,
&mut store,
&env,
&function_type,
|_ctx: ContextMut<'_, ()>, _values: &[Value]| unimplemented!(),
|_ctx: FunctionEnvMut<'_, ()>, _values: &[Value]| unimplemented!(),
);
assert_eq!(function.ty(&ctx).clone(), function_type);
assert_eq!(function.ty(&store).clone(), function_type);
// Using array signature
let function_type = ([Type::V128], [Type::I32, Type::F32, Type::F64]);
let function = Function::new(
&mut ctx,
&mut store,
&env,
function_type,
|_ctx: ContextMut<'_, ()>, _values: &[Value]| unimplemented!(),
|_ctx: FunctionEnvMut<'_, ()>, _values: &[Value]| unimplemented!(),
);
assert_eq!(function.ty(&ctx).params(), [Type::V128]);
assert_eq!(function.ty(&store).params(), [Type::V128]);
assert_eq!(
function.ty(&ctx).results(),
function.ty(&store).results(),
[Type::I32, Type::F32, Type::F64]
);
}
#[wasm_bindgen_test]
fn function_new_dynamic_env() {
let store = Store::default();
let mut store = Store::default();
#[derive(Clone)]
struct MyEnv {}
let my_env = MyEnv {};
let mut ctx = Context::new(&store, my_env);
let mut env = FunctionEnv::new(&mut store, my_env);
// Using &FunctionType signature
let function_type = FunctionType::new(vec![], vec![]);
let function = Function::new(
&mut ctx,
&mut store,
&env,
&function_type,
|_ctx: ContextMut<'_, MyEnv>, _values: &[Value]| unimplemented!(),
|_ctx: FunctionEnvMut<'_, MyEnv>, _values: &[Value]| unimplemented!(),
);
assert_eq!(function.ty(&ctx).clone(), function_type);
assert_eq!(function.ty(&store).clone(), function_type);
let function_type = FunctionType::new(vec![Type::I32], vec![]);
let function = Function::new(
&mut ctx,
&mut store,
&env,
&function_type,
|_ctx: ContextMut<'_, MyEnv>, _values: &[Value]| unimplemented!(),
|_ctx: FunctionEnvMut<'_, MyEnv>, _values: &[Value]| unimplemented!(),
);
assert_eq!(function.ty(&ctx).clone(), function_type);
assert_eq!(function.ty(&store).clone(), function_type);
let function_type =
FunctionType::new(vec![Type::I32, Type::I64, Type::F32, Type::F64], vec![]);
let function = Function::new(
&mut ctx,
&mut store,
&env,
&function_type,
|_ctx: ContextMut<'_, MyEnv>, _values: &[Value]| unimplemented!(),
|_ctx: FunctionEnvMut<'_, MyEnv>, _values: &[Value]| unimplemented!(),
);
assert_eq!(function.ty(&ctx).clone(), function_type);
assert_eq!(function.ty(&store).clone(), function_type);
let function_type = FunctionType::new(vec![], vec![Type::I32]);
let function = Function::new(
&mut ctx,
&mut store,
&env,
&function_type,
|_ctx: ContextMut<'_, MyEnv>, _values: &[Value]| unimplemented!(),
|_ctx: FunctionEnvMut<'_, MyEnv>, _values: &[Value]| unimplemented!(),
);
assert_eq!(function.ty(&ctx).clone(), function_type);
assert_eq!(function.ty(&store).clone(), function_type);
let function_type =
FunctionType::new(vec![], vec![Type::I32, Type::I64, Type::F32, Type::F64]);
let function = Function::new(
&mut ctx,
&mut store,
&env,
&function_type,
|_ctx: ContextMut<'_, MyEnv>, _values: &[Value]| unimplemented!(),
|_ctx: FunctionEnvMut<'_, MyEnv>, _values: &[Value]| unimplemented!(),
);
assert_eq!(function.ty(&ctx).clone(), function_type);
assert_eq!(function.ty(&store).clone(), function_type);
// Using array signature
let function_type = ([Type::V128], [Type::I32, Type::F32, Type::F64]);
let function = Function::new(
&mut ctx,
&mut store,
&env,
function_type,
|_ctx: ContextMut<'_, MyEnv>, _values: &[Value]| unimplemented!(),
|_ctx: FunctionEnvMut<'_, MyEnv>, _values: &[Value]| unimplemented!(),
);
assert_eq!(function.ty(&ctx).params(), [Type::V128]);
assert_eq!(function.ty(&store).params(), [Type::V128]);
assert_eq!(
function.ty(&ctx).results(),
function.ty(&store).results(),
[Type::I32, Type::F32, Type::F64]
);
}
#[wasm_bindgen_test]
fn native_function_works() {
let store = Store::default();
let mut ctx = Context::new(&store, ());
let function = Function::new_native(&mut ctx, |_: ContextMut<'_, ()>| {});
let typed_function: TypedFunction<(), ()> = function.native(&mut ctx).unwrap();
let result = typed_function.call(&mut ctx);
let mut store = Store::default();
let mut env = FunctionEnv::new(&mut store, ());
let function = Function::new_native(&mut store, &env, |_: FunctionEnvMut<'_, ()>| {});
let typed_function: TypedFunction<(), ()> = function.native(&mut store).unwrap();
let result = typed_function.call(&mut store);
assert!(result.is_ok());
let function =
Function::new_native(&mut ctx, |_: ContextMut<'_, ()>, a: i32| -> i32 { a + 1 });
let typed_function: TypedFunction<i32, i32> = function.native(&mut ctx).unwrap();
assert_eq!(typed_function.call(&mut ctx, 3).unwrap(), 4);
let function = Function::new_native(
&mut store,
&env,
|_: FunctionEnvMut<'_, ()>, a: i32| -> i32 { a + 1 },
);
let typed_function: TypedFunction<i32, i32> = function.native(&mut store).unwrap();
assert_eq!(typed_function.call(&mut store, 3).unwrap(), 4);
// fn rust_abi(a: i32, b: i64, c: f32, d: f64) -> u64 {
// (a as u64 * 1000) + (b as u64 * 100) + (c as u64 * 10) + (d as u64)
// }
// let function = Function::new(&mut ctx, rust_abi);
// let typed_function: TypedFunction<(i32, i64, f32, f64), u64> = function.native(&mut ctx).unwrap();
// let function = Function::new(&mut store, &env, rust_abi);
// let typed_function: TypedFunction<(i32, i64, f32, f64), u64> = function.native(&mut store).unwrap();
// assert_eq!(typed_function.call(8, 4, 1.5, 5.).unwrap(), 8415);
let function = Function::new_native(&mut ctx, |_: ContextMut<'_, ()>| -> i32 { 1 });
let typed_function: TypedFunction<(), i32> = function.native(&mut ctx).unwrap();
assert_eq!(typed_function.call(&mut ctx).unwrap(), 1);
let function =
Function::new_native(&mut store, &env, |_: FunctionEnvMut<'_, ()>| -> i32 { 1 });
let typed_function: TypedFunction<(), i32> = function.native(&mut store).unwrap();
assert_eq!(typed_function.call(&mut store).unwrap(), 1);
let function = Function::new_native(&mut ctx, |_: ContextMut<'_, ()>, _a: i32| {});
let typed_function: TypedFunction<i32, ()> = function.native(&mut ctx).unwrap();
assert!(typed_function.call(&mut ctx, 4).is_ok());
let function =
Function::new_native(&mut store, &env, |_: FunctionEnvMut<'_, ()>, _a: i32| {});
let typed_function: TypedFunction<i32, ()> = function.native(&mut store).unwrap();
assert!(typed_function.call(&mut store, 4).is_ok());
// let function = Function::new(&mut ctx, || -> (i32, i64, f32, f64) { (1, 2, 3.0, 4.0) });
// let typed_function: TypedFunction<(), (i32, i64, f32, f64)> = function.native(&mut ctx).unwrap();
// let function = Function::new(&mut store, &env, || -> (i32, i64, f32, f64) { (1, 2, 3.0, 4.0) });
// let typed_function: TypedFunction<(), (i32, i64, f32, f64)> = function.native(&mut store).unwrap();
// assert_eq!(typed_function.call().unwrap(), (1, 2, 3.0, 4.0));
}
#[wasm_bindgen_test]
fn function_outlives_instance() {
let store = Store::default();
let mut ctx = Context::new(&store, ());
let mut store = Store::default();
let mut env = FunctionEnv::new(&mut store, ());
let wat = r#"(module
(type $sum_t (func (param i32 i32) (result i32)))
(func $sum_f (type $sum_t) (param $x i32) (param $y i32) (result i32)
@ -421,18 +456,18 @@ mod js {
let f = {
let module = Module::new(&store, wat).unwrap();
let instance = Instance::new(&mut ctx, &module, &imports! {}).unwrap();
let instance = Instance::new(&mut store, &module, &imports! {}).unwrap();
let f = instance.exports.get_function("sum").unwrap();
assert_eq!(
f.call(&mut ctx, &[Val::I32(4), Val::I32(5)]).unwrap(),
f.call(&mut store, &[Val::I32(4), Val::I32(5)]).unwrap(),
vec![Val::I32(9)].into_boxed_slice()
);
f.clone()
};
assert_eq!(
f.call(&mut ctx, &[Val::I32(4), Val::I32(5)]).unwrap(),
f.call(&mut store, &[Val::I32(4), Val::I32(5)]).unwrap(),
vec![Val::I32(9)].into_boxed_slice()
);
}

View File

@ -23,7 +23,7 @@ mod js {
#[wasm_bindgen_test]
fn test_exported_memory() {
let store = Store::default();
let mut store = Store::default();
let mut module = Module::new(
&store,
br#"
@ -41,24 +41,24 @@ mod js {
.unwrap();
let import_object = imports! {};
let mut ctx = Context::new(&store, ());
let instance = Instance::new(&mut ctx, &module, &import_object).unwrap();
let mut env = FunctionEnv::new(&mut store, ());
let instance = Instance::new(&mut store, &module, &import_object).unwrap();
let memory = instance.exports.get_memory("mem").unwrap();
assert!(memory.is_from_context(&ctx));
assert_eq!(memory.ty(&ctx), MemoryType::new(Pages(1), None, false));
assert_eq!(memory.size(&ctx), Pages(1));
assert_eq!(memory.data_size(&ctx), 65536);
assert!(memory.is_from_store(&store));
assert_eq!(memory.ty(&store), MemoryType::new(Pages(1), None, false));
assert_eq!(memory.size(&store), Pages(1));
assert_eq!(memory.data_size(&store), 65536);
memory.grow(&mut ctx, Pages(1)).unwrap();
assert_eq!(memory.ty(&ctx), MemoryType::new(Pages(1), None, false));
assert_eq!(memory.size(&ctx), Pages(2));
assert_eq!(memory.data_size(&ctx), 65536 * 2);
memory.grow(&mut store, Pages(1)).unwrap();
assert_eq!(memory.ty(&store), MemoryType::new(Pages(1), None, false));
assert_eq!(memory.size(&store), Pages(2));
assert_eq!(memory.data_size(&store), 65536 * 2);
}
#[wasm_bindgen_test]
fn test_exported_function() {
let store = Store::default();
let mut store = Store::default();
let mut module = Module::new(
&store,
br#"
@ -81,22 +81,22 @@ mod js {
.unwrap();
let import_object = imports! {};
let mut ctx = Context::new(&store, ());
let instance = Instance::new(&mut ctx, &module, &import_object).unwrap();
let mut env = FunctionEnv::new(&mut store, ());
let instance = Instance::new(&mut store, &module, &import_object).unwrap();
let get_magic = instance.exports.get_function("get_magic").unwrap();
assert_eq!(
get_magic.ty(&ctx).clone(),
get_magic.ty(&store).clone(),
FunctionType::new(vec![], vec![Type::I32])
);
let expected = vec![Val::I32(42)].into_boxed_slice();
assert_eq!(get_magic.call(&mut ctx, &[]).unwrap(), expected);
assert_eq!(get_magic.call(&mut store, &[]).unwrap(), expected);
}
#[wasm_bindgen_test]
fn test_imported_function_dynamic() {
let store = Store::default();
let mut store = Store::default();
let mut module = Module::new(
&store,
br#"
@ -121,11 +121,11 @@ mod js {
))],
})
.unwrap();
let mut ctx = Context::new(&store, ());
let mut env = FunctionEnv::new(&mut store, ());
let imported_signature = FunctionType::new(vec![Type::I32], vec![Type::I32]);
let imported = Function::new(&mut ctx, imported_signature, |_env, args| {
let imported = Function::new(&mut store, &env, imported_signature, |_env, args| {
log!("Calling `imported`...");
let result = args[0].unwrap_i32() * 2;
log!("Result of `imported`: {:?}", result);
@ -137,19 +137,19 @@ mod js {
"imported" => imported,
}
};
let instance = Instance::new(&mut ctx, &module, &import_object).unwrap();
let instance = Instance::new(&mut store, &module, &import_object).unwrap();
let exported = instance.exports.get_function("exported").unwrap();
let expected = vec![Val::I32(6)].into_boxed_slice();
assert_eq!(exported.call(&mut ctx, &[Val::I32(3)]).unwrap(), expected);
assert_eq!(exported.call(&mut store, &[Val::I32(3)]).unwrap(), expected);
}
// We comment it for now because in old versions of Node, only single return values are supported
// #[wasm_bindgen_test]
// fn test_imported_function_dynamic_multivalue() {
// let store = Store::default();
// let mut store = Store::default();
// let mut module = Module::new(
// &store,
// br#"
@ -207,7 +207,7 @@ mod js {
#[wasm_bindgen_test]
fn test_imported_function_dynamic_with_env() {
let store = Store::default();
let mut store = Store::default();
let mut module = Module::new(
&store,
br#"
@ -238,10 +238,10 @@ mod js {
multiplier: i32,
}
let mut ctx = Context::new(&store, Env { multiplier: 3 });
let mut env = FunctionEnv::new(&mut store, Env { multiplier: 3 });
let imported_signature = FunctionType::new(vec![Type::I32], vec![Type::I32]);
let imported = Function::new(&mut ctx, &imported_signature, |ctx, args| {
let imported = Function::new(&mut store, &env, &imported_signature, |ctx, args| {
log!("Calling `imported`...");
let result = args[0].unwrap_i32() * ctx.data().multiplier;
log!("Result of `imported`: {:?}", result);
@ -253,17 +253,17 @@ mod js {
"imported" => imported,
}
};
let instance = Instance::new(&mut ctx, &module, &import_object).unwrap();
let instance = Instance::new(&mut store, &module, &import_object).unwrap();
let exported = instance.exports.get_function("exported").unwrap();
let expected = vec![Val::I32(9)].into_boxed_slice();
assert_eq!(exported.call(&mut ctx, &[Val::I32(3)]), Ok(expected));
assert_eq!(exported.call(&mut store, &[Val::I32(3)]), Ok(expected));
}
#[wasm_bindgen_test]
fn test_imported_function_native() {
let store = Store::default();
let mut store = Store::default();
let mut module = Module::new(
&store,
br#"
@ -289,29 +289,29 @@ mod js {
})
.unwrap();
fn imported_fn(_: ContextMut<'_, ()>, arg: u32) -> u32 {
fn imported_fn(_: FunctionEnvMut<'_, ()>, arg: u32) -> u32 {
return arg + 1;
}
let mut ctx = Context::new(&store, ());
let imported = Function::new_native(&mut ctx, imported_fn);
let mut env = FunctionEnv::new(&mut store, ());
let imported = Function::new_native(&mut store, &env, imported_fn);
let import_object = imports! {
"env" => {
"imported" => imported,
}
};
let instance = Instance::new(&mut ctx, &module, &import_object).unwrap();
let instance = Instance::new(&mut store, &module, &import_object).unwrap();
let exported = instance.exports.get_function("exported").unwrap();
let expected = vec![Val::I32(5)].into_boxed_slice();
assert_eq!(exported.call(&mut ctx, &[Val::I32(4)]), Ok(expected));
assert_eq!(exported.call(&mut store, &[Val::I32(4)]), Ok(expected));
}
#[wasm_bindgen_test]
fn test_imported_function_native_with_env() {
let store = Store::default();
let mut store = Store::default();
let mut module = Module::new(
&store,
br#"
@ -342,33 +342,33 @@ mod js {
multiplier: u32,
}
fn imported_fn(ctx: ContextMut<'_, Env>, arg: u32) -> u32 {
fn imported_fn(ctx: FunctionEnvMut<'_, Env>, arg: u32) -> u32 {
log!("inside imported_fn: ctx.data is {:?}", ctx.data());
// log!("inside call id is {:?}", ctx.as_context_ref().objects().id);
// log!("inside call id is {:?}", ctx.as_store_ref().objects().id);
return ctx.data().multiplier * arg;
}
let mut ctx = Context::new(&store, Env { multiplier: 3 });
let mut env = FunctionEnv::new(&mut store, Env { multiplier: 3 });
let imported = Function::new_native(&mut ctx, imported_fn);
let imported = Function::new_native(&mut store, &env, imported_fn);
let import_object = imports! {
"env" => {
"imported" => imported,
}
};
let instance = Instance::new(&mut ctx, &module, &import_object).unwrap();
let instance = Instance::new(&mut store, &module, &import_object).unwrap();
let exported = instance.exports.get_function("exported").unwrap();
let expected = vec![Val::I32(12)].into_boxed_slice();
ctx.data_mut().multiplier = 3;
assert_eq!(exported.call(&mut ctx, &[Val::I32(4)]), Ok(expected));
env.as_mut(&mut store).multiplier = 3;
assert_eq!(exported.call(&mut store, &[Val::I32(4)]), Ok(expected));
}
#[wasm_bindgen_test]
fn test_imported_function_native_with_wasmer_env() {
let store = Store::default();
let mut store = Store::default();
let mut module = Module::new(
&store,
br#"
@ -401,76 +401,79 @@ mod js {
memory: Option<Memory>,
}
fn imported_fn(ctx: ContextMut<'_, Env>, arg: u32) -> u32 {
fn imported_fn(ctx: FunctionEnvMut<'_, Env>, arg: u32) -> u32 {
let memory: &Memory = ctx.data().memory.as_ref().unwrap();
let memory_val = memory.uint8view(&ctx).get_index(0);
return (memory_val as u32) * ctx.data().multiplier * arg;
}
let mut ctx = Context::new(
&store,
let mut env = FunctionEnv::new(
&mut store,
Env {
multiplier: 3,
memory: None,
},
);
let imported = Function::new_native(&mut ctx, imported_fn);
let imported = Function::new_native(&mut store, &env, imported_fn);
let import_object = imports! {
"env" => {
"imported" => imported,
}
};
let instance = Instance::new(&mut ctx, &module, &import_object).unwrap();
let instance = Instance::new(&mut store, &module, &import_object).unwrap();
let memory = instance.exports.get_memory("memory").unwrap();
assert_eq!(memory.data_size(&ctx), 65536);
let memory_val = memory.uint8view(&ctx).get_index(0);
assert_eq!(memory.data_size(&store), 65536);
let memory_val = memory.uint8view(&store).get_index(0);
assert_eq!(memory_val, 0);
memory.uint8view(&ctx).set_index(0, 2);
let memory_val = memory.uint8view(&ctx).get_index(0);
memory.uint8view(&store).set_index(0, 2);
let memory_val = memory.uint8view(&store).get_index(0);
assert_eq!(memory_val, 2);
ctx.data_mut().memory = Some(memory.clone());
env.as_mut(&mut store).memory = Some(memory.clone());
let exported = instance.exports.get_function("exported").unwrap();
// It works with the provided memory
let expected = vec![Val::I32(24)].into_boxed_slice();
assert_eq!(exported.call(&mut ctx, &[Val::I32(4)]), Ok(expected));
assert_eq!(exported.call(&mut store, &[Val::I32(4)]), Ok(expected));
// It works if we update the memory
memory.uint8view(&ctx).set_index(0, 3);
memory.uint8view(&store).set_index(0, 3);
let expected = vec![Val::I32(36)].into_boxed_slice();
assert_eq!(exported.call(&mut ctx, &[Val::I32(4)]), Ok(expected));
assert_eq!(exported.call(&mut store, &[Val::I32(4)]), Ok(expected));
}
#[wasm_bindgen_test]
fn test_unit_native_function_env() {
let store = Store::default();
let mut store = Store::default();
#[derive(Clone)]
struct Env {
multiplier: u32,
}
let mut ctx = Context::new(&store, Env { multiplier: 3 });
let mut env = FunctionEnv::new(&mut store, Env { multiplier: 3 });
fn imported_fn(ctx: ContextMut<'_, Env>, args: &[Val]) -> Result<Vec<Val>, RuntimeError> {
fn imported_fn(
ctx: FunctionEnvMut<'_, Env>,
args: &[Val],
) -> Result<Vec<Val>, RuntimeError> {
let value = ctx.data().multiplier * args[0].unwrap_i32() as u32;
return Ok(vec![Val::I32(value as _)]);
}
let imported_signature = FunctionType::new(vec![Type::I32], vec![Type::I32]);
let imported = Function::new(&mut ctx, imported_signature, imported_fn);
let imported = Function::new(&mut store, &env, imported_signature, imported_fn);
let expected = vec![Val::I32(12)].into_boxed_slice();
assert_eq!(imported.call(&mut ctx, &[Val::I32(4)]), Ok(expected));
assert_eq!(imported.call(&mut store, &[Val::I32(4)]), Ok(expected));
}
#[wasm_bindgen_test]
fn test_imported_function_with_wasmer_env() {
let store = Store::default();
let mut store = Store::default();
let mut module = Module::new(
&store,
br#"
@ -503,15 +506,18 @@ mod js {
memory: Option<Memory>,
}
fn imported_fn(ctx: ContextMut<'_, Env>, args: &[Val]) -> Result<Vec<Val>, RuntimeError> {
fn imported_fn(
ctx: FunctionEnvMut<'_, Env>,
args: &[Val],
) -> Result<Vec<Val>, RuntimeError> {
let memory: &Memory = ctx.data().memory.as_ref().unwrap();
let memory_val = memory.uint8view(&ctx).get_index(0);
let value = (memory_val as u32) * ctx.data().multiplier * args[0].unwrap_i32() as u32;
return Ok(vec![Val::I32(value as _)]);
}
let mut ctx = Context::new(
&store,
let mut env = FunctionEnv::new(
&mut store,
Env {
multiplier: 3,
memory: None,
@ -519,41 +525,41 @@ mod js {
);
let imported_signature = FunctionType::new(vec![Type::I32], vec![Type::I32]);
let imported = Function::new(&mut ctx, imported_signature, imported_fn);
let imported = Function::new(&mut store, &env, imported_signature, imported_fn);
let import_object = imports! {
"env" => {
"imported" => imported,
}
};
let instance = Instance::new(&mut ctx, &module, &import_object).unwrap();
let instance = Instance::new(&mut store, &module, &import_object).unwrap();
let memory = instance.exports.get_memory("memory").unwrap();
assert_eq!(memory.data_size(&ctx), 65536);
let memory_val = memory.uint8view(&ctx).get_index(0);
assert_eq!(memory.data_size(&store), 65536);
let memory_val = memory.uint8view(&store).get_index(0);
assert_eq!(memory_val, 0);
memory.uint8view(&ctx).set_index(0, 2);
let memory_val = memory.uint8view(&ctx).get_index(0);
memory.uint8view(&store).set_index(0, 2);
let memory_val = memory.uint8view(&store).get_index(0);
assert_eq!(memory_val, 2);
ctx.data_mut().memory = Some(memory.clone());
env.as_mut(&mut store).memory = Some(memory.clone());
let exported = instance.exports.get_function("exported").unwrap();
// It works with the provided memory
let expected = vec![Val::I32(24)].into_boxed_slice();
assert_eq!(exported.call(&mut ctx, &[Val::I32(4)]), Ok(expected));
assert_eq!(exported.call(&mut store, &[Val::I32(4)]), Ok(expected));
// It works if we update the memory
memory.uint8view(&ctx).set_index(0, 3);
memory.uint8view(&store).set_index(0, 3);
let expected = vec![Val::I32(36)].into_boxed_slice();
assert_eq!(exported.call(&mut ctx, &[Val::I32(4)]), Ok(expected));
assert_eq!(exported.call(&mut store, &[Val::I32(4)]), Ok(expected));
}
#[wasm_bindgen_test]
fn test_imported_exported_global() {
let store = Store::default();
let mut store = Store::default();
let mut module = Module::new(
&store,
br#"
@ -579,39 +585,39 @@ mod js {
],
})
.unwrap();
let mut ctx = Context::new(&store, ());
let global = Global::new_mut(&mut ctx, Value::I32(0));
let mut env = FunctionEnv::new(&mut store, ());
let global = Global::new_mut(&mut store, Value::I32(0));
let import_object = imports! {
"" => {
"global" => global.clone()
}
};
let instance = Instance::new(&mut ctx, &module, &import_object).unwrap();
let instance = Instance::new(&mut store, &module, &import_object).unwrap();
let get_global = instance.exports.get_function("getGlobal").unwrap();
assert_eq!(
get_global.call(&mut ctx, &[]),
get_global.call(&mut store, &[]),
Ok(vec![Val::I32(0)].into_boxed_slice())
);
global.set(&mut ctx, Value::I32(42)).unwrap();
global.set(&mut store, Value::I32(42)).unwrap();
assert_eq!(
get_global.call(&mut ctx, &[]),
get_global.call(&mut store, &[]),
Ok(vec![Val::I32(42)].into_boxed_slice())
);
let inc_global = instance.exports.get_function("incGlobal").unwrap();
inc_global.call(&mut ctx, &[]).unwrap();
inc_global.call(&mut store, &[]).unwrap();
assert_eq!(
get_global.call(&mut ctx, &[]),
get_global.call(&mut store, &[]),
Ok(vec![Val::I32(43)].into_boxed_slice())
);
assert_eq!(global.get(&ctx), Val::I32(43));
assert_eq!(global.get(&store), Val::I32(43));
}
#[wasm_bindgen_test]
fn test_native_function() {
let store = Store::default();
let mut store = Store::default();
let module = Module::new(
&store,
br#"(module
@ -623,30 +629,30 @@ mod js {
)
.unwrap();
fn sum(_: ContextMut<'_, ()>, a: i32, b: i32) -> i32 {
fn sum(_: FunctionEnvMut<'_, ()>, a: i32, b: i32) -> i32 {
a + b
}
let mut ctx = Context::new(&store, ());
let mut env = FunctionEnv::new(&mut store, ());
let import_object = imports! {
"env" => {
"sum" => Function::new_native(&mut ctx, sum),
"sum" => Function::new_native(&mut store, &env, sum),
}
};
let instance = Instance::new(&mut ctx, &module, &import_object).unwrap();
let instance = Instance::new(&mut store, &module, &import_object).unwrap();
let add_one: TypedFunction<i32, i32> = instance
.exports
.get_typed_function(&ctx, "add_one")
.get_typed_function(&mut store, "add_one")
.unwrap();
assert_eq!(add_one.call(&mut ctx, 1), Ok(2));
assert_eq!(add_one.call(&mut store, 1), Ok(2));
}
#[wasm_bindgen_test]
fn test_panic() {
let store = Store::default();
let mut store = Store::default();
let module = Module::new(
&store,
br#"
@ -664,30 +670,32 @@ mod js {
)
.unwrap();
fn early_exit(_: ContextMut<'_, ()>) {
fn early_exit(_: FunctionEnvMut<'_, ()>) {
panic!("Do panic")
}
let mut ctx = Context::new(&store, ());
let mut env = FunctionEnv::new(&mut store, ());
let import_object = imports! {
"env" => {
"early_exit" => Function::new_native(&mut ctx, early_exit),
"early_exit" => Function::new_native(&mut store, &env, early_exit),
}
};
let instance = Instance::new(&mut ctx, &module, &import_object).unwrap();
let instance = Instance::new(&mut store, &module, &import_object).unwrap();
let run_func: TypedFunction<(i32, i32), i32> =
instance.exports.get_typed_function(&ctx, "run").unwrap();
let run_func: TypedFunction<(i32, i32), i32> = instance
.exports
.get_typed_function(&mut store, "run")
.unwrap();
assert!(
run_func.call(&mut ctx, 1, 7).is_err(),
run_func.call(&mut store, 1, 7).is_err(),
"Expected early termination",
);
let run_func = instance.exports.get_function("run").unwrap();
assert!(
run_func
.call(&mut ctx, &[Val::I32(1), Val::I32(7)])
.call(&mut store, &[Val::I32(1), Val::I32(7)])
.is_err(),
"Expected early termination",
);
@ -695,7 +703,7 @@ mod js {
#[wasm_bindgen_test]
fn test_custom_error() {
let store = Store::default();
let mut store = Store::default();
let module = Module::new(
&store,
br#"
@ -713,7 +721,7 @@ mod js {
)
.unwrap();
let mut ctx = Context::new(&store, ());
let mut env = FunctionEnv::new(&mut store, ());
use std::fmt;
@ -728,17 +736,17 @@ mod js {
impl std::error::Error for ExitCode {}
fn early_exit(_: ContextMut<'_, ()>) -> Result<(), ExitCode> {
fn early_exit(_: FunctionEnvMut<'_, ()>) -> Result<(), ExitCode> {
Err(ExitCode(1))
}
let import_object = imports! {
"env" => {
"early_exit" => Function::new_native(&mut ctx, early_exit),
"early_exit" => Function::new_native(&mut store, &env, early_exit),
}
};
let instance = Instance::new(&mut ctx, &module, &import_object).unwrap();
let instance = Instance::new(&mut store, &module, &import_object).unwrap();
fn test_result<T: core::fmt::Debug>(result: Result<T, RuntimeError>) {
match result {
@ -763,17 +771,19 @@ mod js {
}
}
let run_func: TypedFunction<(i32, i32), i32> =
instance.exports.get_typed_function(&ctx, "run").unwrap();
test_result(run_func.call(&mut ctx, 1, 7));
let run_func: TypedFunction<(i32, i32), i32> = instance
.exports
.get_typed_function(&mut store, "run")
.unwrap();
test_result(run_func.call(&mut store, 1, 7));
let run_func = instance.exports.get_function("run").unwrap();
test_result(run_func.call(&mut ctx, &[Val::I32(1), Val::I32(7)]));
test_result(run_func.call(&mut store, &[Val::I32(1), Val::I32(7)]));
}
#[wasm_bindgen_test]
fn test_start_function_fails() {
let store = Store::default();
let mut store = Store::default();
let module = Module::new(
&store,
br#"
@ -792,8 +802,8 @@ mod js {
.unwrap();
let import_object = imports! {};
let mut ctx = Context::new(&store, ());
let result = Instance::new(&mut ctx, &module, &import_object);
let mut env = FunctionEnv::new(&mut store, ());
let result = Instance::new(&mut store, &module, &import_object);
let err = result.unwrap_err();
assert!(format!("{:?}", err).contains("zero"))
}

View File

@ -6,7 +6,7 @@ mod js {
#[wasm_bindgen_test]
fn module_get_name() {
let store = Store::default();
let mut store = Store::default();
let wat = r#"(module)"#;
let module = Module::new(&store, wat).unwrap();
assert_eq!(module.name(), None);
@ -14,7 +14,7 @@ mod js {
#[wasm_bindgen_test]
fn module_set_name() {
let store = Store::default();
let mut store = Store::default();
let wat = r#"(module $name)"#;
let mut module = Module::new(&store, wat).unwrap();
@ -32,12 +32,11 @@ mod js {
let js_bytes = unsafe { Uint8Array::view(&binary) };
let js_module = WebAssembly::Module::new(&js_bytes.into()).unwrap();
let module: Module = js_module.into();
assert_eq!(module.store(), &Store::default());
}
#[wasm_bindgen_test]
fn imports() {
let store = Store::default();
let mut store = Store::default();
let wat = r#"(module
(import "host" "func" (func))
(import "host" "memory" (memory 1))
@ -108,7 +107,7 @@ mod js {
#[wasm_bindgen_test]
fn exports() {
let store = Store::default();
let mut store = Store::default();
let wat = r#"(module
(func (export "func") nop)
(memory (export "memory") 2)
@ -182,7 +181,7 @@ mod js {
// #[wasm_bindgen_test]
// fn calling_host_functions_with_negative_values_works() {
// let store = Store::default();
// let mut store = Store::default();
// let wat = r#"(module
// (import "host" "host_func1" (func (param i64)))
// (import "host" "host_func2" (func (param i32)))

View File

@ -1,25 +1,24 @@
#[cfg(feature = "sys")]
mod sys {
use anyhow::Result;
use wasmer::Context as WasmerContext;
use wasmer::FunctionEnv;
use wasmer::*;
#[test]
fn global_new() -> Result<()> {
let store = Store::default();
let mut ctx = WasmerContext::new(&store, ());
let global = Global::new(&mut ctx, Value::I32(10));
let mut store = Store::default();
let global = Global::new(&mut store, Value::I32(10));
assert_eq!(
global.ty(&mut ctx),
global.ty(&mut store),
GlobalType {
ty: Type::I32,
mutability: Mutability::Const
}
);
let global_mut = Global::new_mut(&mut ctx, Value::I32(10));
let global_mut = Global::new_mut(&mut store, Value::I32(10));
assert_eq!(
global_mut.ty(&mut ctx),
global_mut.ty(&mut store),
GlobalType {
ty: Type::I32,
mutability: Mutability::Var
@ -31,51 +30,49 @@ mod sys {
#[test]
fn global_get() -> Result<()> {
let store = Store::default();
let mut ctx = WasmerContext::new(&store, ());
let global_i32 = Global::new(&mut ctx, Value::I32(10));
assert_eq!(global_i32.get(&mut ctx), Value::I32(10));
let global_i64 = Global::new(&mut ctx, Value::I64(20));
assert_eq!(global_i64.get(&mut ctx), Value::I64(20));
let global_f32 = Global::new(&mut ctx, Value::F32(10.0));
assert_eq!(global_f32.get(&mut ctx), Value::F32(10.0));
let global_f64 = Global::new(&mut ctx, Value::F64(20.0));
assert_eq!(global_f64.get(&mut ctx), Value::F64(20.0));
let mut store = Store::default();
let global_i32 = Global::new(&mut store, Value::I32(10));
assert_eq!(global_i32.get(&mut store), Value::I32(10));
let global_i64 = Global::new(&mut store, Value::I64(20));
assert_eq!(global_i64.get(&mut store), Value::I64(20));
let global_f32 = Global::new(&mut store, Value::F32(10.0));
assert_eq!(global_f32.get(&mut store), Value::F32(10.0));
let global_f64 = Global::new(&mut store, Value::F64(20.0));
assert_eq!(global_f64.get(&mut store), Value::F64(20.0));
Ok(())
}
#[test]
fn global_set() -> Result<()> {
let store = Store::default();
let mut ctx = WasmerContext::new(&store, ());
let global_i32 = Global::new(&mut ctx, Value::I32(10));
let mut store = Store::default();
let global_i32 = Global::new(&mut store, Value::I32(10));
// Set on a constant should error
assert!(global_i32.set(&mut ctx, Value::I32(20)).is_err());
assert!(global_i32.set(&mut store, Value::I32(20)).is_err());
let global_i32_mut = Global::new_mut(&mut ctx, Value::I32(10));
let global_i32_mut = Global::new_mut(&mut store, Value::I32(10));
// Set on different type should error
assert!(global_i32_mut.set(&mut ctx, Value::I64(20)).is_err());
assert!(global_i32_mut.set(&mut store, Value::I64(20)).is_err());
// Set on same type should succeed
global_i32_mut.set(&mut ctx, Value::I32(20))?;
assert_eq!(global_i32_mut.get(&mut ctx), Value::I32(20));
global_i32_mut.set(&mut store, Value::I32(20))?;
assert_eq!(global_i32_mut.get(&mut store), Value::I32(20));
Ok(())
}
#[test]
fn table_new() -> Result<()> {
let store = Store::default();
let mut ctx = WasmerContext::new(&store, ());
let mut store = Store::default();
let table_type = TableType {
ty: Type::FuncRef,
minimum: 0,
maximum: None,
};
let f = Function::new_native(&mut ctx, |_ctx: ContextMut<()>| {});
let table = Table::new(&mut ctx, table_type, Value::FuncRef(Some(f)))?;
assert_eq!(table.ty(&mut ctx), table_type);
let env = FunctionEnv::new(&mut store, ());
let f = Function::new_native(&mut store, &env, |_ctx: FunctionEnvMut<()>| {});
let table = Table::new(&mut store, table_type, Value::FuncRef(Some(f)))?;
assert_eq!(table.ty(&mut store), table_type);
// Anyrefs not yet supported
// let table_type = TableType {
@ -92,17 +89,19 @@ mod sys {
#[test]
#[ignore]
fn table_get() -> Result<()> {
let store = Store::default();
let mut ctx = WasmerContext::new(&store, ());
let mut store = Store::default();
let env = FunctionEnv::new(&mut store, ());
let table_type = TableType {
ty: Type::FuncRef,
minimum: 0,
maximum: Some(1),
};
let f = Function::new_native(&mut ctx, |_ctx: ContextMut<()>, num: i32| num + 1);
let table = Table::new(&mut ctx, table_type, Value::FuncRef(Some(f)))?;
assert_eq!(table.ty(&mut ctx), table_type);
let _elem = table.get(&mut ctx, 0).unwrap();
let f = Function::new_native(&mut store, &env, |_ctx: FunctionEnvMut<()>, num: i32| {
num + 1
});
let table = Table::new(&mut store, table_type, Value::FuncRef(Some(f)))?;
assert_eq!(table.ty(&mut store), table_type);
let _elem = table.get(&mut store, 0).unwrap();
// assert_eq!(elem.funcref().unwrap(), f);
Ok(())
}
@ -116,21 +115,23 @@ mod sys {
#[test]
fn table_grow() -> Result<()> {
let store = Store::default();
let mut ctx = WasmerContext::new(&store, ());
let mut store = Store::default();
let env = FunctionEnv::new(&mut store, ());
let table_type = TableType {
ty: Type::FuncRef,
minimum: 0,
maximum: Some(10),
};
let f = Function::new_native(&mut ctx, |_ctx: ContextMut<()>, num: i32| num + 1);
let table = Table::new(&mut ctx, table_type, Value::FuncRef(Some(f.clone())))?;
let f = Function::new_native(&mut store, &env, |_ctx: FunctionEnvMut<()>, num: i32| {
num + 1
});
let table = Table::new(&mut store, table_type, Value::FuncRef(Some(f.clone())))?;
// Growing to a bigger maximum should return None
let old_len = table.grow(&mut ctx, 12, Value::FuncRef(Some(f.clone())));
let old_len = table.grow(&mut store, 12, Value::FuncRef(Some(f.clone())));
assert!(old_len.is_err());
// Growing to a bigger maximum should return None
let old_len = table.grow(&mut ctx, 5, Value::FuncRef(Some(f)))?;
let old_len = table.grow(&mut store, 5, Value::FuncRef(Some(f)))?;
assert_eq!(old_len, 0);
Ok(())
@ -145,32 +146,30 @@ mod sys {
#[test]
fn memory_new() -> Result<()> {
let store = Store::default();
let mut ctx = WasmerContext::new(&store, ());
let mut store = Store::default();
let memory_type = MemoryType {
shared: false,
minimum: Pages(0),
maximum: Some(Pages(10)),
};
let memory = Memory::new(&mut ctx, memory_type)?;
assert_eq!(memory.size(&mut ctx), Pages(0));
assert_eq!(memory.ty(&mut ctx), memory_type);
let memory = Memory::new(&mut store, memory_type)?;
assert_eq!(memory.size(&mut store), Pages(0));
assert_eq!(memory.ty(&mut store), memory_type);
Ok(())
}
#[test]
fn memory_grow() -> Result<()> {
let store = Store::default();
let mut ctx = WasmerContext::new(&store, ());
let mut store = Store::default();
let desc = MemoryType::new(Pages(10), Some(Pages(16)), false);
let memory = Memory::new(&mut ctx, desc)?;
assert_eq!(memory.size(&mut ctx), Pages(10));
let memory = Memory::new(&mut store, desc)?;
assert_eq!(memory.size(&mut store), Pages(10));
let result = memory.grow(&mut ctx, Pages(2)).unwrap();
let result = memory.grow(&mut store, Pages(2)).unwrap();
assert_eq!(result, Pages(10));
assert_eq!(memory.size(&mut ctx), Pages(12));
assert_eq!(memory.size(&mut store), Pages(12));
let result = memory.grow(&mut ctx, Pages(10));
let result = memory.grow(&mut store, Pages(10));
assert_eq!(
result,
Err(MemoryError::CouldNotGrow {
@ -180,7 +179,7 @@ mod sys {
);
let bad_desc = MemoryType::new(Pages(15), Some(Pages(10)), false);
let bad_result = Memory::new(&mut ctx, bad_desc);
let bad_result = Memory::new(&mut store, bad_desc);
assert!(matches!(bad_result, Err(MemoryError::InvalidMemory { .. })));
@ -189,37 +188,41 @@ mod sys {
#[test]
fn function_new() -> Result<()> {
let store = Store::default();
let mut ctx = WasmerContext::new(&store, ());
let function = Function::new_native(&mut ctx, |_ctx: ContextMut<_>| {});
let mut store = Store::default();
let env = FunctionEnv::new(&mut store, ());
let function = Function::new_native(&mut store, &env, |_ctx: FunctionEnvMut<()>| {});
assert_eq!(
function.ty(&mut ctx).clone(),
function.ty(&mut store).clone(),
FunctionType::new(vec![], vec![])
);
let function = Function::new_native(&mut ctx, |_ctx: ContextMut<_>, _a: i32| {});
let function =
Function::new_native(&mut store, &env, |_ctx: FunctionEnvMut<()>, _a: i32| {});
assert_eq!(
function.ty(&mut ctx).clone(),
function.ty(&mut store).clone(),
FunctionType::new(vec![Type::I32], vec![])
);
let function = Function::new_native(
&mut ctx,
|_ctx: ContextMut<_>, _a: i32, _b: i64, _c: f32, _d: f64| {},
&mut store,
&env,
|_ctx: FunctionEnvMut<()>, _a: i32, _b: i64, _c: f32, _d: f64| {},
);
assert_eq!(
function.ty(&mut ctx).clone(),
function.ty(&mut store).clone(),
FunctionType::new(vec![Type::I32, Type::I64, Type::F32, Type::F64], vec![])
);
let function = Function::new_native(&mut ctx, |_ctx: ContextMut<_>| -> i32 { 1 });
let function =
Function::new_native(&mut store, &env, |_ctx: FunctionEnvMut<()>| -> i32 { 1 });
assert_eq!(
function.ty(&mut ctx).clone(),
function.ty(&mut store).clone(),
FunctionType::new(vec![], vec![Type::I32])
);
let function =
Function::new_native(&mut ctx, |_ctx: ContextMut<_>| -> (i32, i64, f32, f64) {
(1, 2, 3.0, 4.0)
});
let function = Function::new_native(
&mut store,
&env,
|_ctx: FunctionEnvMut<()>| -> (i32, i64, f32, f64) { (1, 2, 3.0, 4.0) },
);
assert_eq!(
function.ty(&mut ctx).clone(),
function.ty(&mut store).clone(),
FunctionType::new(vec![], vec![Type::I32, Type::I64, Type::F32, Type::F64])
);
Ok(())
@ -227,41 +230,45 @@ mod sys {
#[test]
fn function_new_env() -> Result<()> {
let store = Store::default();
let mut store = Store::default();
#[derive(Clone)]
struct MyEnv {}
let my_env = MyEnv {};
let mut ctx = WasmerContext::new(&store, my_env);
let function = Function::new_native(&mut ctx, |_ctx: ContextMut<MyEnv>| {});
let env = FunctionEnv::new(&mut store, my_env);
let function = Function::new_native(&mut store, &env, |_ctx: FunctionEnvMut<MyEnv>| {});
assert_eq!(
function.ty(&mut ctx).clone(),
function.ty(&mut store).clone(),
FunctionType::new(vec![], vec![])
);
let function = Function::new_native(&mut ctx, |_ctx: ContextMut<MyEnv>, _a: i32| {});
let function =
Function::new_native(&mut store, &env, |_ctx: FunctionEnvMut<MyEnv>, _a: i32| {});
assert_eq!(
function.ty(&mut ctx).clone(),
function.ty(&mut store).clone(),
FunctionType::new(vec![Type::I32], vec![])
);
let function = Function::new_native(
&mut ctx,
|_ctx: ContextMut<MyEnv>, _a: i32, _b: i64, _c: f32, _d: f64| {},
&mut store,
&env,
|_ctx: FunctionEnvMut<MyEnv>, _a: i32, _b: i64, _c: f32, _d: f64| {},
);
assert_eq!(
function.ty(&mut ctx).clone(),
function.ty(&mut store).clone(),
FunctionType::new(vec![Type::I32, Type::I64, Type::F32, Type::F64], vec![])
);
let function = Function::new_native(&mut ctx, |_ctx: ContextMut<MyEnv>| -> i32 { 1 });
let function =
Function::new_native(&mut store, &env, |_ctx: FunctionEnvMut<MyEnv>| -> i32 { 1 });
assert_eq!(
function.ty(&mut ctx).clone(),
function.ty(&mut store).clone(),
FunctionType::new(vec![], vec![Type::I32])
);
let function = Function::new_native(
&mut ctx,
|_ctx: ContextMut<MyEnv>| -> (i32, i64, f32, f64) { (1, 2, 3.0, 4.0) },
&mut store,
&env,
|_ctx: FunctionEnvMut<MyEnv>| -> (i32, i64, f32, f64) { (1, 2, 3.0, 4.0) },
);
assert_eq!(
function.ty(&mut ctx).clone(),
function.ty(&mut store).clone(),
FunctionType::new(vec![], vec![Type::I32, Type::I64, Type::F32, Type::F64])
);
Ok(())
@ -269,58 +276,64 @@ mod sys {
#[test]
fn function_new_dynamic() -> Result<()> {
let store = Store::default();
let mut ctx = WasmerContext::new(&store, ());
let mut store = Store::default();
let env = FunctionEnv::new(&mut store, ());
// Using &FunctionType signature
let function_type = FunctionType::new(vec![], vec![]);
let function = Function::new(
&mut ctx,
&mut store,
&env,
&function_type,
|_ctx: ContextMut<()>, _values: &[Value]| unimplemented!(),
|_ctx: FunctionEnvMut<()>, _values: &[Value]| unimplemented!(),
);
assert_eq!(function.ty(&mut ctx).clone(), function_type);
assert_eq!(function.ty(&mut store).clone(), function_type);
let function_type = FunctionType::new(vec![Type::I32], vec![]);
let function = Function::new(
&mut ctx,
&mut store,
&env,
&function_type,
|_ctx: ContextMut<()>, _values: &[Value]| unimplemented!(),
|_ctx: FunctionEnvMut<()>, _values: &[Value]| unimplemented!(),
);
assert_eq!(function.ty(&mut ctx).clone(), function_type);
assert_eq!(function.ty(&mut store).clone(), function_type);
let function_type =
FunctionType::new(vec![Type::I32, Type::I64, Type::F32, Type::F64], vec![]);
let function = Function::new(
&mut ctx,
&mut store,
&env,
&function_type,
|_ctx: ContextMut<()>, _values: &[Value]| unimplemented!(),
|_ctx: FunctionEnvMut<()>, _values: &[Value]| unimplemented!(),
);
assert_eq!(function.ty(&mut ctx).clone(), function_type);
assert_eq!(function.ty(&mut store).clone(), function_type);
let function_type = FunctionType::new(vec![], vec![Type::I32]);
let function = Function::new(
&mut ctx,
&mut store,
&env,
&function_type,
|_ctx: ContextMut<()>, _values: &[Value]| unimplemented!(),
|_ctx: FunctionEnvMut<()>, _values: &[Value]| unimplemented!(),
);
assert_eq!(function.ty(&mut ctx).clone(), function_type);
assert_eq!(function.ty(&mut store).clone(), function_type);
let function_type =
FunctionType::new(vec![], vec![Type::I32, Type::I64, Type::F32, Type::F64]);
let function = Function::new(
&mut ctx,
&mut store,
&env,
&function_type,
|_ctx: ContextMut<()>, _values: &[Value]| unimplemented!(),
|_ctx: FunctionEnvMut<()>, _values: &[Value]| unimplemented!(),
);
assert_eq!(function.ty(&mut ctx).clone(), function_type);
assert_eq!(function.ty(&mut store).clone(), function_type);
// Using array signature
let function_type = ([Type::V128], [Type::I32, Type::F32, Type::F64]);
let function = Function::new(
&mut ctx,
&mut store,
&env,
function_type,
|_ctx: ContextMut<()>, _values: &[Value]| unimplemented!(),
|_ctx: FunctionEnvMut<()>, _values: &[Value]| unimplemented!(),
);
assert_eq!(function.ty(&mut ctx).params(), [Type::V128]);
assert_eq!(function.ty(&mut store).params(), [Type::V128]);
assert_eq!(
function.ty(&mut ctx).results(),
function.ty(&mut store).results(),
[Type::I32, Type::F32, Type::F64]
);
@ -329,193 +342,199 @@ mod sys {
#[test]
fn function_new_dynamic_env() -> Result<()> {
let store = Store::default();
let mut store = Store::default();
#[derive(Clone)]
struct MyEnv {}
let my_env = MyEnv {};
let mut ctx = WasmerContext::new(&store, my_env);
let env = FunctionEnv::new(&mut store, my_env);
// Using &FunctionType signature
let function_type = FunctionType::new(vec![], vec![]);
let function = Function::new(
&mut ctx,
&mut store,
&env,
&function_type,
|_ctx: ContextMut<MyEnv>, _values: &[Value]| unimplemented!(),
|_ctx: FunctionEnvMut<MyEnv>, _values: &[Value]| unimplemented!(),
);
assert_eq!(function.ty(&mut ctx).clone(), function_type);
assert_eq!(function.ty(&mut store).clone(), function_type);
let function_type = FunctionType::new(vec![Type::I32], vec![]);
let function = Function::new(
&mut ctx,
&mut store,
&env,
&function_type,
|_ctx: ContextMut<MyEnv>, _values: &[Value]| unimplemented!(),
|_ctx: FunctionEnvMut<MyEnv>, _values: &[Value]| unimplemented!(),
);
assert_eq!(function.ty(&mut ctx).clone(), function_type);
assert_eq!(function.ty(&mut store).clone(), function_type);
let function_type =
FunctionType::new(vec![Type::I32, Type::I64, Type::F32, Type::F64], vec![]);
let function = Function::new(
&mut ctx,
&mut store,
&env,
&function_type,
|_ctx: ContextMut<MyEnv>, _values: &[Value]| unimplemented!(),
|_ctx: FunctionEnvMut<MyEnv>, _values: &[Value]| unimplemented!(),
);
assert_eq!(function.ty(&mut ctx).clone(), function_type);
assert_eq!(function.ty(&mut store).clone(), function_type);
let function_type = FunctionType::new(vec![], vec![Type::I32]);
let function = Function::new(
&mut ctx,
&mut store,
&env,
&function_type,
|_ctx: ContextMut<MyEnv>, _values: &[Value]| unimplemented!(),
|_ctx: FunctionEnvMut<MyEnv>, _values: &[Value]| unimplemented!(),
);
assert_eq!(function.ty(&mut ctx).clone(), function_type);
assert_eq!(function.ty(&mut store).clone(), function_type);
let function_type =
FunctionType::new(vec![], vec![Type::I32, Type::I64, Type::F32, Type::F64]);
let function = Function::new(
&mut ctx,
&mut store,
&env,
&function_type,
|_ctx: ContextMut<MyEnv>, _values: &[Value]| unimplemented!(),
|_ctx: FunctionEnvMut<MyEnv>, _values: &[Value]| unimplemented!(),
);
assert_eq!(function.ty(&mut ctx).clone(), function_type);
assert_eq!(function.ty(&mut store).clone(), function_type);
// Using array signature
let function_type = ([Type::V128], [Type::I32, Type::F32, Type::F64]);
let function = Function::new(
&mut ctx,
&mut store,
&env,
function_type,
|_ctx: ContextMut<MyEnv>, _values: &[Value]| unimplemented!(),
|_ctx: FunctionEnvMut<MyEnv>, _values: &[Value]| unimplemented!(),
);
assert_eq!(function.ty(&mut ctx).params(), [Type::V128]);
assert_eq!(function.ty(&mut store).params(), [Type::V128]);
assert_eq!(
function.ty(&mut ctx).results(),
function.ty(&mut store).results(),
[Type::I32, Type::F32, Type::F64]
);
Ok(())
}
#[test]
fn native_function_works() -> Result<()> {
let store = Store::default();
let mut ctx = WasmerContext::new(&store, ());
let function = Function::new_native(&mut ctx, |_ctx: ContextMut<()>| {});
let native_function: TypedFunction<(), ()> = function.native(&mut ctx).unwrap();
let result = native_function.call(&mut ctx);
assert!(result.is_ok());
// #[test]
// fn native_function_works() -> Result<()> {
// let mut store = Store::default();
// let env = FunctionEnv::new(&mut store, ());
// let function = Function::new_native(&mut store, &env, |_ctx: FunctionEnvMut<()>| {});
// let native_function: TypedFunction<(), ()> = function.native(&mut store).unwrap();
// let result = native_function.call(&mut store);
// assert!(result.is_ok());
let function =
Function::new_native(&mut ctx, |_ctx: ContextMut<()>, a: i32| -> i32 { a + 1 });
let native_function: TypedFunction<i32, i32> = function.native(&mut ctx).unwrap();
assert_eq!(native_function.call(&mut ctx, 3).unwrap(), 4);
// let function =
// Function::new_native(&mut store, &env, |_ctx: FunctionEnvMut<()>, a: i32| -> i32 { a + 1 });
// let native_function: TypedFunction<i32, i32> = function.native(&mut store).unwrap();
// assert_eq!(native_function.call(&mut store, 3).unwrap(), 4);
fn rust_abi(_ctx: ContextMut<()>, a: i32, b: i64, c: f32, d: f64) -> u64 {
(a as u64 * 1000) + (b as u64 * 100) + (c as u64 * 10) + (d as u64)
}
let function = Function::new_native(&mut ctx, rust_abi);
let native_function: TypedFunction<(i32, i64, f32, f64), u64> =
function.native(&mut ctx).unwrap();
assert_eq!(native_function.call(&mut ctx, 8, 4, 1.5, 5.).unwrap(), 8415);
// fn rust_abi(_ctx: FunctionEnvMut<()>, a: i32, b: i64, c: f32, d: f64) -> u64 {
// (a as u64 * 1000) + (b as u64 * 100) + (c as u64 * 10) + (d as u64)
// }
// let function = Function::new_native(&mut store, &env, rust_abi);
// let native_function: TypedFunction<(i32, i64, f32, f64), u64> =
// function.native(&mut store).unwrap();
// assert_eq!(native_function.call(&mut store, 8, 4, 1.5, 5.).unwrap(), 8415);
let function = Function::new_native(&mut ctx, |_ctx: ContextMut<()>| -> i32 { 1 });
let native_function: TypedFunction<(), i32> = function.native(&mut ctx).unwrap();
assert_eq!(native_function.call(&mut ctx).unwrap(), 1);
// let function = Function::new_native(&mut store, &env, |_ctx: FunctionEnvMut<()>| -> i32 { 1 });
// let native_function: TypedFunction<(), i32> = function.native(&mut store).unwrap();
// assert_eq!(native_function.call(&mut store).unwrap(), 1);
let function = Function::new_native(&mut ctx, |_ctx: ContextMut<()>, _a: i32| {});
let native_function: TypedFunction<i32, ()> = function.native(&mut ctx).unwrap();
assert!(native_function.call(&mut ctx, 4).is_ok());
// let function = Function::new_native(&mut store, &env, |_ctx: FunctionEnvMut<()>, _a: i32| {});
// let native_function: TypedFunction<i32, ()> = function.native(&mut store).unwrap();
// assert!(native_function.call(&mut store, 4).is_ok());
let function =
Function::new_native(&mut ctx, |_ctx: ContextMut<()>| -> (i32, i64, f32, f64) {
(1, 2, 3.0, 4.0)
});
let native_function: TypedFunction<(), (i32, i64, f32, f64)> =
function.native(&mut ctx).unwrap();
assert_eq!(native_function.call(&mut ctx).unwrap(), (1, 2, 3.0, 4.0));
// let function =
// Function::new_native(&mut store, &env, |_ctx: FunctionEnvMut<()>| -> (i32, i64, f32, f64) {
// (1, 2, 3.0, 4.0)
// });
// let native_function: TypedFunction<(), (i32, i64, f32, f64)> =
// function.native(&mut store).unwrap();
// assert_eq!(native_function.call(&mut store).unwrap(), (1, 2, 3.0, 4.0));
Ok(())
}
// Ok(())
// }
#[test]
fn function_outlives_instance() -> Result<()> {
let store = Store::default();
let mut ctx = WasmerContext::new(&store, ());
let wat = r#"(module
(type $sum_t (func (param i32 i32) (result i32)))
(func $sum_f (type $sum_t) (param $x i32) (param $y i32) (result i32)
local.get $x
local.get $y
i32.add)
(export "sum" (func $sum_f)))
"#;
// #[test]
// fn function_outlives_instance() -> Result<()> {
// let mut store = Store::default();
// let env = FunctionEnv::new(&mut store, ());
// let wat = r#"(module
// (type $sum_t (func (param i32 i32) (result i32)))
// (func $sum_f (type $sum_t) (param $x i32) (param $y i32) (result i32)
// local.get $x
// local.get $y
// i32.add)
// (export "sum" (func $sum_f)))
// "#;
let f = {
let module = Module::new(&store, wat)?;
let instance = Instance::new(&mut ctx, &module, &imports! {})?;
let f: TypedFunction<(i32, i32), i32> =
instance.exports.get_typed_function(&mut ctx, "sum")?;
// let f = {
// let module = Module::new(&store, wat)?;
// let instance = Instance::new(&mut store, &module, &imports! {})?;
// let f: TypedFunction<(i32, i32), i32> =
// instance.exports.get_typed_function(&mut store, "sum")?;
assert_eq!(f.call(&mut ctx, 4, 5)?, 9);
f
};
// assert_eq!(f.call(&mut store, 4, 5)?, 9);
// f
// };
assert_eq!(f.call(&mut ctx, 4, 5)?, 9);
// assert_eq!(f.call(&mut store, 4, 5)?, 9);
Ok(())
}
/*
#[test]
fn weak_instance_ref_externs_after_instance() -> Result<()> {
let store = Store::default();
let mut ctx = WasmerContext::new(&store, ());
let wat = r#"(module
(memory (export "mem") 1)
(type $sum_t (func (param i32 i32) (result i32)))
(func $sum_f (type $sum_t) (param $x i32) (param $y i32) (result i32)
local.get $x
local.get $y
i32.add)
(export "sum" (func $sum_f)))
"#;
// Ok(())
// }
// /*
// #[test]
// fn weak_instance_ref_externs_after_instance() -> Result<()> {
// let mut store = Store::default();
// let env = FunctionEnv::new(&mut store, ());
// let wat = r#"(module
// (memory (export "mem") 1)
// (type $sum_t (func (param i32 i32) (result i32)))
// (func $sum_f (type $sum_t) (param $x i32) (param $y i32) (result i32)
// local.get $x
// local.get $y
// i32.add)
// (export "sum" (func $sum_f)))
// "#;
let f = {
let module = Module::new(&store, wat)?;
let instance = Instance::new(&mut ctx, &module, &imports! {})?;
let f: TypedFunction<(i32, i32), i32> =
instance.exports.get_with_generics_weak("sum")?;
// let f = {
// let module = Module::new(&store, wat)?;
// let instance = Instance::new(&mut store, &module, &imports! {})?;
// let f: TypedFunction<(i32, i32), i32> =
// instance.exports.get_with_generics_weak("sum")?;
assert_eq!(f.call(&mut ctx, 4, 5)?, 9);
f
};
// assert_eq!(f.call(&mut store, 4, 5)?, 9);
// f
// };
assert_eq!(f.call(&mut ctx, 4, 5)?, 9);
// assert_eq!(f.call(&mut store, 4, 5)?, 9);
Ok(())
}
*/
#[test]
fn manually_generate_wasmer_env() -> Result<()> {
let store = Store::default();
#[derive(Clone)]
struct MyEnv {
val: u32,
memory: Option<Memory>,
}
// Ok(())
// }
// */
// #[test]
// fn manually_generate_wasmer_env() -> Result<()> {
// let mut store = Store::default();
// #[derive(Clone)]
// struct MyEnv {
// val: u32,
// memory: Option<Memory>,
// }
fn host_function(ctx: ContextMut<MyEnv>, arg1: u32, arg2: u32) -> u32 {
ctx.data().val + arg1 + arg2
}
// fn host_function(ctx: FunctionEnvMut<MyEnv>, arg1: u32, arg2: u32) -> u32 {
// ctx.data().val + arg1 + arg2
// }
let mut env = MyEnv {
val: 5,
memory: None,
};
let mut ctx = WasmerContext::new(&store, env);
// let mut env = MyEnv {
// val: 5,
// memory: None,
// };
// let env = FunctionEnv::new(&mut store, env);
let result = host_function(ctx.as_context_mut(), 7, 9);
assert_eq!(result, 21);
// let result = host_function(ctx.as_context_mut(), 7, 9);
// assert_eq!(result, 21);
let memory = Memory::new(&mut ctx, MemoryType::new(0, None, false))?;
ctx.data_mut().memory = Some(memory);
// let memory = Memory::new(&mut store, MemoryType::new(0, None, false))?;
// ctx.as_mut(&mut store).memory = Some(memory);
let result = host_function(ctx.as_context_mut(), 1, 2);
assert_eq!(result, 8);
// let result = host_function(ctx.as_context_mut(), 1, 2);
// assert_eq!(result, 8);
Ok(())
}
// Ok(())
// }
}

View File

@ -1,13 +1,12 @@
#[cfg(feature = "sys")]
mod sys {
use anyhow::Result;
use wasmer::Context as WasmerContext;
use wasmer::FunctionEnv;
use wasmer::*;
#[test]
fn exports_work_after_multiple_instances_have_been_freed() -> Result<()> {
let store = Store::default();
let mut ctx = WasmerContext::new(&store, ());
let mut store = Store::default();
let module = Module::new(
&store,
"
@ -22,7 +21,7 @@ mod sys {
)?;
let imports = Imports::new();
let instance = Instance::new(&mut ctx, &module, &imports)?;
let instance = Instance::new(&mut store, &module, &imports)?;
let instance2 = instance.clone();
let instance3 = instance.clone();
@ -35,7 +34,7 @@ mod sys {
// All instances have been dropped, but `sum` continues to work!
assert_eq!(
sum.call(&mut ctx, &[Value::I32(1), Value::I32(2)])?
sum.call(&mut store, &[Value::I32(1), Value::I32(2)])?
.into_vec(),
vec![Value::I32(3)],
);
@ -45,24 +44,31 @@ mod sys {
#[test]
fn unit_native_function_env() -> Result<()> {
let store = Store::default();
let mut store = Store::default();
#[derive(Clone)]
struct Env {
multiplier: u32,
}
fn imported_fn(ctx: ContextMut<Env>, args: &[Value]) -> Result<Vec<Value>, RuntimeError> {
fn imported_fn(
ctx: FunctionEnvMut<Env>,
args: &[Value],
) -> Result<Vec<Value>, RuntimeError> {
let value = ctx.data().multiplier * args[0].unwrap_i32() as u32;
Ok(vec![Value::I32(value as _)])
}
// We create the environment
let env = Env { multiplier: 3 };
let mut ctx = WasmerContext::new(&store, env);
// We move the environment to the store, so it can be used by the `Function`
let env = FunctionEnv::new(&mut store, env);
let imported_signature = FunctionType::new(vec![Type::I32], vec![Type::I32]);
let imported = Function::new(&mut ctx, imported_signature, imported_fn);
let imported = Function::new(&mut store, &env, imported_signature, imported_fn);
let expected = vec![Value::I32(12)].into_boxed_slice();
let result = imported.call(&mut ctx, &[Value::I32(4)])?;
let result = imported.call(&mut store, &[Value::I32(4)])?;
assert_eq!(result, expected);
Ok(())

View File

@ -1,7 +1,7 @@
#[cfg(feature = "sys")]
mod sys {
use anyhow::Result;
use wasmer::Context as WasmerContext;
use wasmer::FunctionEnv;
use wasmer::*;
#[test]
@ -162,7 +162,7 @@ mod sys {
#[test]
fn calling_host_functions_with_negative_values_works() -> Result<()> {
let store = Store::default();
let mut store = Store::default();
let wat = r#"(module
(import "host" "host_func1" (func (param i64)))
(import "host" "host_func2" (func (param i32)))
@ -191,78 +191,78 @@ mod sys {
(call 7 (i32.const -1)))
)"#;
let module = Module::new(&store, wat)?;
let mut ctx = WasmerContext::new(&store, ());
let env = FunctionEnv::new(&mut store, ());
let imports = imports! {
"host" => {
"host_func1" => Function::new_native(&mut ctx, |_ctx: ContextMut<()>, p: u64| {
"host_func1" => Function::new_native(&mut store, &env,|_ctx: FunctionEnvMut<()>, p: u64| {
println!("host_func1: Found number {}", p);
assert_eq!(p, u64::max_value());
}),
"host_func2" => Function::new_native(&mut ctx, |_ctx: ContextMut<()>, p: u32| {
"host_func2" => Function::new_native(&mut store, &env,|_ctx: FunctionEnvMut<()>, p: u32| {
println!("host_func2: Found number {}", p);
assert_eq!(p, u32::max_value());
}),
"host_func3" => Function::new_native(&mut ctx, |_ctx: ContextMut<()>, p: i64| {
"host_func3" => Function::new_native(&mut store, &env,|_ctx: FunctionEnvMut<()>, p: i64| {
println!("host_func3: Found number {}", p);
assert_eq!(p, -1);
}),
"host_func4" => Function::new_native(&mut ctx, |_ctx: ContextMut<()>, p: i32| {
"host_func4" => Function::new_native(&mut store, &env,|_ctx: FunctionEnvMut<()>, p: i32| {
println!("host_func4: Found number {}", p);
assert_eq!(p, -1);
}),
"host_func5" => Function::new_native(&mut ctx, |_ctx: ContextMut<()>, p: i16| {
"host_func5" => Function::new_native(&mut store, &env,|_ctx: FunctionEnvMut<()>, p: i16| {
println!("host_func5: Found number {}", p);
assert_eq!(p, -1);
}),
"host_func6" => Function::new_native(&mut ctx, |_ctx: ContextMut<()>, p: u16| {
"host_func6" => Function::new_native(&mut store, &env,|_ctx: FunctionEnvMut<()>, p: u16| {
println!("host_func6: Found number {}", p);
assert_eq!(p, u16::max_value());
}),
"host_func7" => Function::new_native(&mut ctx, |_ctx: ContextMut<()>, p: i8| {
"host_func7" => Function::new_native(&mut store, &env,|_ctx: FunctionEnvMut<()>, p: i8| {
println!("host_func7: Found number {}", p);
assert_eq!(p, -1);
}),
"host_func8" => Function::new_native(&mut ctx, |_ctx: ContextMut<()>, p: u8| {
"host_func8" => Function::new_native(&mut store, &env,|_ctx: FunctionEnvMut<()>, p: u8| {
println!("host_func8: Found number {}", p);
assert_eq!(p, u8::max_value());
}),
}
};
let instance = Instance::new(&mut ctx, &module, &imports)?;
let instance = Instance::new(&mut store, &module, &imports)?;
let f1: TypedFunction<(), ()> = instance
.exports
.get_typed_function(&mut ctx, "call_host_func1")?;
.get_typed_function(&mut store, "call_host_func1")?;
let f2: TypedFunction<(), ()> = instance
.exports
.get_typed_function(&mut ctx, "call_host_func2")?;
.get_typed_function(&mut store, "call_host_func2")?;
let f3: TypedFunction<(), ()> = instance
.exports
.get_typed_function(&mut ctx, "call_host_func3")?;
.get_typed_function(&mut store, "call_host_func3")?;
let f4: TypedFunction<(), ()> = instance
.exports
.get_typed_function(&mut ctx, "call_host_func4")?;
.get_typed_function(&mut store, "call_host_func4")?;
let f5: TypedFunction<(), ()> = instance
.exports
.get_typed_function(&mut ctx, "call_host_func5")?;
.get_typed_function(&mut store, "call_host_func5")?;
let f6: TypedFunction<(), ()> = instance
.exports
.get_typed_function(&mut ctx, "call_host_func6")?;
.get_typed_function(&mut store, "call_host_func6")?;
let f7: TypedFunction<(), ()> = instance
.exports
.get_typed_function(&mut ctx, "call_host_func7")?;
.get_typed_function(&mut store, "call_host_func7")?;
let f8: TypedFunction<(), ()> = instance
.exports
.get_typed_function(&mut ctx, "call_host_func8")?;
.get_typed_function(&mut store, "call_host_func8")?;
f1.call(&mut ctx)?;
f2.call(&mut ctx)?;
f3.call(&mut ctx)?;
f4.call(&mut ctx)?;
f5.call(&mut ctx)?;
f6.call(&mut ctx)?;
f7.call(&mut ctx)?;
f8.call(&mut ctx)?;
f1.call(&mut store)?;
f2.call(&mut store)?;
f3.call(&mut store)?;
f4.call(&mut store)?;
f5.call(&mut store)?;
f6.call(&mut store)?;
f7.call(&mut store)?;
f8.call(&mut store)?;
Ok(())
}

View File

@ -1,15 +1,14 @@
#[cfg(feature = "sys")]
mod sys {
use anyhow::Result;
use std::collections::HashMap;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use wasmer::Context as WasmerContext;
use wasmer::FunctionEnv;
use wasmer::*;
#[test]
fn func_ref_passed_and_returned() -> Result<()> {
let store = Store::default();
let mut store = Store::default();
let wat = r#"(module
(import "env" "func_ref_identity" (func (param funcref) (result funcref)))
(type $ret_i32_ty (func (result i32)))
@ -25,33 +24,37 @@ mod sys {
#[derive(Clone, Debug)]
pub struct Env(Arc<AtomicBool>);
let env = Env(Arc::new(AtomicBool::new(false)));
let mut ctx = WasmerContext::new(&store, env);
let env = FunctionEnv::new(&mut store, env);
let imports = imports! {
"env" => {
"func_ref_identity" => Function::new(&mut ctx, FunctionType::new([Type::FuncRef], [Type::FuncRef]), |_ctx: ContextMut<Env>, values: &[Value]| -> Result<Vec<_>, _> {
"func_ref_identity" => Function::new(&mut store, &env, FunctionType::new([Type::FuncRef], [Type::FuncRef]), |_ctx: FunctionEnvMut<Env>, values: &[Value]| -> Result<Vec<_>, _> {
Ok(vec![values[0].clone()])
})
},
};
let instance = Instance::new(&mut ctx, &module, &imports)?;
let instance = Instance::new(&mut store, &module, &imports)?;
let f: &Function = instance.exports.get_function("run")?;
let results = f.call(&mut ctx, &[]).unwrap();
let results = f.call(&mut store, &[]).unwrap();
if let Value::FuncRef(fr) = &results[0] {
assert!(fr.is_none());
} else {
panic!("funcref not found!");
}
let func_to_call = Function::new_native(&mut ctx, |mut ctx: ContextMut<Env>| -> i32 {
ctx.data_mut().0.store(true, Ordering::SeqCst);
343
});
let func_to_call =
Function::new_native(&mut store, &env, |mut ctx: FunctionEnvMut<Env>| -> i32 {
ctx.data_mut().0.store(true, Ordering::SeqCst);
343
});
let call_set_value: &Function = instance.exports.get_function("call_set_value")?;
let results: Box<[Value]> =
call_set_value.call(&mut ctx, &[Value::FuncRef(Some(func_to_call))])?;
assert!(ctx.data().0.load(Ordering::SeqCst));
call_set_value.call(&mut store, &[Value::FuncRef(Some(func_to_call))])?;
assert!(env
.as_mut(&mut store.as_store_mut())
.0
.load(Ordering::SeqCst));
assert_eq!(&*results, &[Value::I32(343)]);
Ok(())
@ -59,7 +62,7 @@ mod sys {
#[test]
fn func_ref_passed_and_called() -> Result<()> {
let store = Store::default();
let mut store = Store::default();
let wat = r#"(module
(func $func_ref_call (import "env" "func_ref_call") (param funcref) (result i32))
(type $ret_i32_ty (func (result i32)))
@ -78,9 +81,9 @@ mod sys {
(call $func_ref_call (ref.func $product)))
)"#;
let module = Module::new(&store, wat)?;
let mut ctx = WasmerContext::new(&store, ());
let env = FunctionEnv::new(&mut store, ());
fn func_ref_call(
mut ctx: ContextMut<()>,
mut ctx: FunctionEnvMut<()>,
values: &[Value],
) -> Result<Vec<Value>, RuntimeError> {
// TODO: look into `Box<[Value]>` being returned breakage
@ -92,47 +95,46 @@ mod sys {
let imports = imports! {
"env" => {
"func_ref_call" => Function::new(
&mut ctx,
&mut store,
&env,
FunctionType::new([Type::FuncRef], [Type::I32]),
func_ref_call
),
// TODO(reftypes): this should work
/*
"func_ref_call_native" => Function::new_native(&store, |f: Function| -> Result<i32, RuntimeError> {
let f: TypedFunction::<(i32, i32), i32> = f.native()?;
f.call(7, 9)
})
*/
// "func_ref_call_native" => Function::new_native(&mut store, &env, |_ctx: FunctionEnvMut<()>, f: Function| -> Result<i32, RuntimeError> {
// let f: TypedFunction::<(i32, i32), i32> = f.native(&mut store)?;
// f.call(&mut store, 7, 9)
// })
},
};
let instance = Instance::new(&mut ctx, &module, &imports)?;
let instance = Instance::new(&mut store, &module, &imports)?;
{
fn sum(_ctx: ContextMut<()>, a: i32, b: i32) -> i32 {
fn sum(_ctx: FunctionEnvMut<()>, a: i32, b: i32) -> i32 {
a + b
}
let sum_func = Function::new_native(&mut ctx, sum);
let sum_func = Function::new_native(&mut store, &env, sum);
let call_func: &Function = instance.exports.get_function("call_func")?;
let result = call_func.call(&mut ctx, &[Value::FuncRef(Some(sum_func))])?;
let result = call_func.call(&mut store, &[Value::FuncRef(Some(sum_func))])?;
assert_eq!(result[0].unwrap_i32(), 16);
}
{
let f: TypedFunction<(), i32> = instance
.exports
.get_typed_function(&mut ctx, "call_host_func_with_wasm_func")?;
let result = f.call(&mut ctx)?;
.get_typed_function(&mut store, "call_host_func_with_wasm_func")?;
let result = f.call(&mut store)?;
assert_eq!(result, 63);
}
Ok(())
}
/*
#[test]
fn extern_ref_passed_and_returned() -> Result<()> {
let store = Store::default();
let mut ctx = WasmerContext::new(&store, ());
let mut store = Store::default();
let env = FunctionEnv::new(&mut store, ());
let wat = r#"(module
(func $extern_ref_identity (import "env" "extern_ref_identity") (param externref) (result externref))
(func $extern_ref_identity_native (import "env" "extern_ref_identity_native") (param externref) (result externref))
@ -149,15 +151,16 @@ mod sys {
(call $get_new_extern_ref_native))
)"#;
let module = Module::new(&store, wat)?;
let env = FunctionEnv::new(&mut store, ());
let imports = imports! {
"env" => {
"extern_ref_identity" => Function::new(&mut ctx, FunctionType::new([Type::ExternRef], [Type::ExternRef]), |_ctx, values| -> Result<Vec<_>, _> {
"extern_ref_identity" => Function::new(&mut store, &env, FunctionType::new([Type::ExternRef], [Type::ExternRef]), |_ctx, values| -> Result<Vec<_>, _> {
Ok(vec![values[0].clone()])
}),
"extern_ref_identity_native" => Function::new_native(&mut ctx, |_ctx: ContextMut<()>, er: ExternRef| -> ExternRef {
"extern_ref_identity_native" => Function::new_native(&mut store, &env, |_ctx: FunctionEnvMut<()>, er: ExternRef| -> ExternRef {
er
}),
"get_new_extern_ref" => Function::new(&mut ctx, FunctionType::new([], [Type::ExternRef]), |_ctx, _| -> Result<Vec<_>, _> {
"get_new_extern_ref" => Function::new(&mut store, &env, FunctionType::new([], [Type::ExternRef]), |_ctx, _| -> Result<Vec<_>, _> {
let inner =
[("hello".to_string(), "world".to_string()),
("color".to_string(), "orange".to_string())]
@ -167,7 +170,7 @@ mod sys {
let new_extern_ref = ExternRef::new(&mut ctx, inner);
Ok(vec![Value::ExternRef(new_extern_ref)])
}),
"get_new_extern_ref_native" => Function::new_native(&mut ctx, |_ctx| -> ExternRef {
"get_new_extern_ref_native" => Function::new_native(&mut store, &env,|_ctx| -> ExternRef {
let inner =
[("hello".to_string(), "world".to_string()),
("color".to_string(), "orange".to_string())]
@ -217,11 +220,11 @@ mod sys {
Ok(())
}
#[test]
#[test]
// TODO(reftypes): reenable this test
#[ignore]
fn extern_ref_ref_counting_basic() -> Result<()> {
let store = Store::default();
let mut store = Store::default();
let wat = r#"(module
(func (export "drop") (param $er externref) (result)
(drop (local.get $er)))
@ -241,7 +244,7 @@ mod sys {
#[test]
fn refs_in_globals() -> Result<()> {
let store = Store::default();
let mut store = Store::default();
let wat = r#"(module
(global $er_global (export "er_global") (mut externref) (ref.null extern))
(global $fr_global (export "fr_global") (mut funcref) (ref.null func))
@ -306,7 +309,7 @@ mod sys {
#[test]
fn extern_ref_ref_counting_table_basic() -> Result<()> {
let store = Store::default();
let mut store = Store::default();
let wat = r#"(module
(global $global (export "global") (mut externref) (ref.null extern))
(table $table (export "table") 4 4 externref)
@ -348,7 +351,7 @@ mod sys {
// TODO(reftypes): reenable this test
#[ignore]
fn extern_ref_ref_counting_global_basic() -> Result<()> {
let store = Store::default();
let mut store = Store::default();
let wat = r#"(module
(global $global (export "global") (mut externref) (ref.null extern))
(func $get_from_global (export "get_from_global") (result externref)
@ -379,7 +382,7 @@ mod sys {
// TODO(reftypes): reenable this test
#[ignore]
fn extern_ref_ref_counting_traps() -> Result<()> {
let store = Store::default();
let mut store = Store::default();
let wat = r#"(module
(func $pass_er (export "pass_extern_ref") (param externref)
(local.get 0)
@ -403,7 +406,7 @@ mod sys {
#[test]
fn extern_ref_ref_counting_table_instructions() -> Result<()> {
let store = Store::default();
let mut store = Store::default();
let wat = r#"(module
(table $table1 (export "table1") 2 12 externref)
(table $table2 (export "table2") 6 12 externref)

View File

@ -21,8 +21,6 @@ int main(int argc, const char *argv[]) {
printf("Initializing...\n");
own wasm_engine_t* engine = wasm_engine_new();
own wasm_store_t* store = wasm_store_new(engine);
wasm_context_t* ctx = wasm_context_new(store, 0);
wasm_store_context_set(store, ctx);
// =====================
wasm_limits_t limits1 = {

View File

@ -29,7 +29,7 @@ void print_frame(wasm_frame_t* frame) {
wasm_store_t *store = NULL;
own wasm_trap_t* early_exit(wasm_context_ref_mut_t* ctx_mut, const wasm_val_vec_t* args, wasm_val_vec_t* results) {
own wasm_trap_t* early_exit(const wasm_val_vec_t* args, wasm_val_vec_t* results) {
own wasm_message_t trap_message;
wasm_name_new_from_string_nt(&trap_message, "trapping from a host import");
own wasm_trap_t *trap = wasm_trap_new(store, &trap_message);
@ -42,8 +42,6 @@ int main(int argc, const char *argv[]) {
printf("Initializing...\n");
wasm_engine_t *engine = wasm_engine_new();
store = wasm_store_new(engine);
wasm_context_t* ctx = wasm_context_new(store, 0);
wasm_store_context_set(store, ctx);
// Load binary.
printf("Loading binary...\n");

View File

@ -20,8 +20,6 @@ int main(int argc, const char* argv[]) {
printf("Creating the store...\n");
wasm_engine_t* engine = wasm_engine_new();
wasm_store_t* store = wasm_store_new(engine);
wasm_context_t* ctx = wasm_context_new(store, 0);
wasm_store_context_set(store, ctx);
printf("Compiling module...\n");
wasm_module_t* module = wasm_module_new(store, &wasm_bytes);

View File

@ -19,8 +19,6 @@ int main(int argc, const char* argv[]) {
printf("Creating the store...\n");
wasm_engine_t* engine = wasm_engine_new();
wasm_store_t* store = wasm_store_new(engine);
wasm_context_t* ctx = wasm_context_new(store, 0);
wasm_store_context_set(store, ctx);
printf("Compiling module...\n");
wasm_module_t* module = wasm_module_new(store, &wasm_bytes);

View File

@ -26,8 +26,6 @@ int main(int argc, const char* argv[]) {
printf("Creating the store...\n");
wasm_engine_t* engine = wasm_engine_new_with_config(config);
wasm_store_t* store = wasm_store_new(engine);
wasm_context_t* ctx = wasm_context_new(store, 0);
wasm_store_context_set(store, ctx);
printf("Compiling module...\n");
wasm_module_t* module = wasm_module_new(store, &wasm_bytes);

View File

@ -1,7 +1,7 @@
#include <stdio.h>
#include "wasmer.h"
wasm_trap_t* host_func_callback(wasm_context_ref_mut_t* ctx_mut, const wasm_val_vec_t* args, wasm_val_vec_t* results) {
wasm_trap_t* host_func_callback(const wasm_val_vec_t* args, wasm_val_vec_t* results) {
printf("Calling back...\n> ");
wasm_val_t val = WASM_I32_VAL(42);
@ -31,8 +31,6 @@ int main(int argc, const char* argv[]) {
printf("Creating the store...\n");
wasm_engine_t* engine = wasm_engine_new();
wasm_store_t* store = wasm_store_new(engine);
wasm_context_t* ctx = wasm_context_new(store, 0);
wasm_store_context_set(store, ctx);
printf("Compiling module...\n");
wasm_module_t* module = wasm_module_new(store, &wasm_bytes);

View File

@ -20,8 +20,6 @@ int main(int argc, const char* argv[]) {
printf("Creating the store...\n");
wasm_engine_t* engine = wasm_engine_new();
wasm_store_t* store = wasm_store_new(engine);
wasm_context_t* ctx = wasm_context_new(store, 0);
wasm_store_context_set(store, ctx);
printf("Compiling module...\n");
wasm_module_t* module = wasm_module_new(store, &wasm_bytes);

View File

@ -28,8 +28,6 @@ int main(int argc, const char* argv[]) {
printf("Creating the store...\n");
wasm_engine_t* engine = wasm_engine_new();
wasm_store_t* store = wasm_store_new(engine);
wasm_context_t* ctx = wasm_context_new(store, 0);
wasm_store_context_set(store, ctx);
printf("Compiling module...\n");
wasm_module_t* module = wasm_module_new(store, &wasm_bytes);

View File

@ -20,8 +20,6 @@ int main(int argc, const char *argv[]) {
printf("Initializing...\n");
own wasm_engine_t* engine = wasm_engine_new();
own wasm_store_t* store = wasm_store_new(engine);
wasm_context_t* ctx = wasm_context_new(store, 0);
wasm_store_context_set(store, ctx);
// =====================
wasm_limits_t limits1 = {

View File

@ -36,16 +36,6 @@ int main(int argc, const char* argv[]) {
wasi_config_arg(config, js_string);
wasi_config_capture_stdout(config);
wasi_env_t* wasi_env = wasi_env_new(config);
if (!wasi_env) {
printf("> Error building WASI env!\n");
print_wasmer_error();
return 1;
}
wasm_context_t* ctx = wasm_context_new(store, wasi_env);
wasm_store_context_set(store, ctx);
// Load binary.
printf("Loading binary...\n");
FILE* file = fopen("assets/qjs.wasm", "r");
@ -73,10 +63,27 @@ int main(int argc, const char* argv[]) {
}
wasm_byte_vec_delete(&binary);
printf("Setting up WASI...\n");
config = wasi_config_new("example_program");
// TODO: error checking
js_string = "function greet(name) { return JSON.stringify('Hello, ' + name); }; print(greet('World'));";
wasi_config_arg(config, "--eval");
wasi_config_arg(config, js_string);
wasi_config_capture_stdout(config);
wasi_env_t* wasi_env = wasi_env_new(store, config);
if (!wasi_env) {
printf("> Error building WASI env!\n");
print_wasmer_error();
return 1;
}
// Instantiate.
printf("Instantiating module...\n");
wasm_extern_vec_t imports;
bool get_imports_result = wasi_get_imports(store, module, &imports);
bool get_imports_result = wasi_get_imports(store, wasi_env,module,&imports);
if (!get_imports_result) {
printf("> Error getting WASI imports!\n");
@ -93,6 +100,12 @@ int main(int argc, const char* argv[]) {
return 1;
}
if (!wasi_env_initialize_instance(wasi_env, store, instance)) {
printf("> Error initializing wasi env memory!\n");
print_wasmer_error();
return 1;
}
// Extract export.
printf("Extracting export...\n");
@ -111,9 +124,6 @@ int main(int argc, const char* argv[]) {
return 1;
}
wasm_module_delete(module);
wasm_instance_delete(instance);
// Call.
printf("Calling export...\n");
printf("Evaluating \"%s\"\n", js_string);
@ -170,6 +180,8 @@ int main(int argc, const char* argv[]) {
printf("Shutting down...\n");
wasm_func_delete(run_func);
wasi_env_delete(wasi_env);
wasm_module_delete(module);
wasm_instance_delete(instance);
wasm_store_delete(store);
wasm_engine_delete(engine);

View File

@ -1,73 +0,0 @@
use crate::wasm_c_api::store::wasm_store_t;
use libc::c_void;
use wasmer_api::{Context, ContextMut};
/// Opaque type representing a WebAssembly context.
#[allow(non_camel_case_types)]
pub struct wasm_context_t {
pub(crate) inner: Context<*mut c_void>,
}
impl core::fmt::Debug for wasm_context_t {
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(fmt, "wasm_context_t")
}
}
/// Creates a new WebAssembly Context given a specific [engine][super::engine].
///
/// # Example
///
/// See the module's documentation.
#[no_mangle]
pub unsafe extern "C" fn wasm_context_new(
store: Option<&wasm_store_t>,
data: *mut c_void,
) -> Option<Box<wasm_context_t>> {
let store = store?;
Some(Box::new(wasm_context_t {
inner: Context::new(&store.inner, data),
}))
}
/// Deletes a WebAssembly context.
///
/// # Example
///
/// See the module's documentation.
#[no_mangle]
pub unsafe extern "C" fn wasm_context_delete(_context: Option<Box<wasm_context_t>>) {}
/// Opaque type representing a mut ref of a WebAssembly context.
#[allow(non_camel_case_types)]
pub struct wasm_context_ref_mut_t<'a> {
pub(crate) inner: ContextMut<'a, *mut c_void>,
}
/// Get the value of `wasm_context_ref_mut_t` data.
#[no_mangle]
pub unsafe extern "C" fn wasm_context_ref_mut_get(ctx: &wasm_context_ref_mut_t) -> *mut c_void {
*ctx.inner.data()
}
/// Set the value of [`ContextMut`] data.
///
#[no_mangle]
pub unsafe extern "C" fn wasm_context_ref_mut_set(
ctx: &mut wasm_context_ref_mut_t,
new_val: *mut c_void,
) {
*ctx.inner.data_mut() = new_val;
}
/// Deletes a WebAssembly context.
///
/// # Example
///
/// See the module's documentation.
#[no_mangle]
pub unsafe extern "C" fn wasm_context_ref_mut_delete(
_context: Option<&mut wasm_context_ref_mut_t>,
) {
}

View File

@ -1,59 +1,61 @@
use super::super::context::{wasm_context_ref_mut_t, wasm_context_t};
use super::super::store::wasm_store_t;
use super::super::trap::wasm_trap_t;
use super::super::types::{wasm_functype_t, wasm_valkind_enum};
use super::super::value::{wasm_val_inner, wasm_val_t, wasm_val_vec_t};
use super::CApiExternTag;
use std::cell::RefCell;
use super::wasm_extern_t;
use crate::wasm_c_api::function_env::FunctionCEnv;
use libc::c_void;
use std::convert::TryInto;
use std::ffi::c_void;
use std::mem::MaybeUninit;
use std::rc::Rc;
use wasmer_api::{Function, RuntimeError, Value};
use std::sync::{Arc, Mutex};
use wasmer_api::{Extern, Function, FunctionEnv, FunctionEnvMut, RuntimeError, Value};
#[derive(Debug, Clone)]
#[derive(Clone)]
#[allow(non_camel_case_types)]
#[repr(C)]
pub struct wasm_func_t {
pub(crate) tag: CApiExternTag,
pub(crate) inner: Box<Function>,
pub(crate) context: Option<Rc<RefCell<wasm_context_t>>>,
pub(crate) extern_: wasm_extern_t,
}
impl wasm_func_t {
pub(crate) fn new(function: Function) -> Self {
Self {
tag: CApiExternTag::Function,
inner: Box::new(function),
context: None,
pub(crate) fn try_from(e: &wasm_extern_t) -> Option<&wasm_func_t> {
match &e.inner {
Extern::Function(_) => Some(unsafe { &*(e as *const _ as *const _) }),
_ => None,
}
}
}
#[allow(non_camel_case_types)]
pub type wasm_func_callback_t = unsafe extern "C" fn(
context: &mut wasm_context_ref_mut_t,
args: &wasm_val_vec_t,
results: &mut wasm_val_vec_t,
) -> Option<Box<wasm_trap_t>>;
#[allow(non_camel_case_types)]
pub type wasm_func_callback_with_env_t = unsafe extern "C" fn(
env: *mut c_void,
args: &wasm_val_vec_t,
results: &mut wasm_val_vec_t,
) -> Option<Box<wasm_trap_t>>;
#[allow(non_camel_case_types)]
pub type wasm_env_finalizer_t = unsafe extern "C" fn(*mut c_void);
#[no_mangle]
pub unsafe extern "C" fn wasm_func_new(
store: Option<&wasm_store_t>,
store: Option<&mut wasm_store_t>,
function_type: Option<&wasm_functype_t>,
callback: Option<wasm_func_callback_t>,
) -> Option<Box<wasm_func_t>> {
let function_type = function_type?;
let callback = callback?;
let store = store?;
if store.context.is_none() {
crate::error::update_last_error(wasm_store_t::CTX_ERR_STR);
}
let mut ctx = store.context.as_ref()?.borrow_mut();
let mut store_mut = store.inner.store_mut();
let func_sig = &function_type.inner().function_type;
let num_rets = func_sig.results().len();
let inner_callback = move |ctx: wasmer_api::ContextMut<'_, *mut c_void>,
let inner_callback = move |mut _ctx: FunctionEnvMut<'_, FunctionCEnv>,
args: &[Value]|
-> Result<Vec<Value>, RuntimeError> {
let processed_args: wasm_val_vec_t = args
@ -72,11 +74,7 @@ pub unsafe extern "C" fn wasm_func_new(
]
.into();
let trap = callback(
&mut wasm_context_ref_mut_t { inner: ctx },
&processed_args,
&mut results,
);
let trap = callback(&processed_args, &mut results);
if let Some(trap) = trap {
return Err(trap.inner);
@ -91,12 +89,100 @@ pub unsafe extern "C" fn wasm_func_new(
Ok(processed_results)
};
let function = Function::new(&mut ctx.inner, func_sig, inner_callback);
drop(ctx);
let mut retval = Box::new(wasm_func_t::new(function));
retval.context = store.context.clone();
let env = FunctionEnv::new(&mut store_mut, FunctionCEnv::default());
let function = Function::new(&mut store_mut, &env, func_sig, inner_callback);
Some(Box::new(wasm_func_t {
extern_: wasm_extern_t::new(store.inner.clone(), function.into()),
}))
}
Some(retval)
#[no_mangle]
pub unsafe extern "C" fn wasm_func_new_with_env(
store: Option<&mut wasm_store_t>,
function_type: Option<&wasm_functype_t>,
callback: Option<wasm_func_callback_with_env_t>,
env: *mut c_void,
env_finalizer: Option<wasm_env_finalizer_t>,
) -> Option<Box<wasm_func_t>> {
let function_type = function_type?;
let callback = callback?;
let store = store?;
let mut store_mut = store.inner.store_mut();
let func_sig = &function_type.inner().function_type;
let num_rets = func_sig.results().len();
#[derive(Clone)]
#[repr(C)]
struct WrapperEnv {
env: FunctionCEnv,
env_finalizer: Arc<Mutex<Option<wasm_env_finalizer_t>>>,
}
// Only relevant when using multiple threads in the C API;
// Synchronization will be done via the C API / on the C side.
unsafe impl Send for WrapperEnv {}
unsafe impl Sync for WrapperEnv {}
impl Drop for WrapperEnv {
fn drop(&mut self) {
if let Ok(mut guard) = self.env_finalizer.lock() {
if Arc::strong_count(&self.env_finalizer) == 1 {
if let Some(env_finalizer) = guard.take() {
unsafe { (env_finalizer)(self.env.as_ptr()) };
}
}
}
}
}
let inner_callback = move |env: FunctionEnvMut<'_, WrapperEnv>,
args: &[Value]|
-> Result<Vec<Value>, RuntimeError> {
let processed_args: wasm_val_vec_t = args
.iter()
.map(TryInto::try_into)
.collect::<Result<Vec<wasm_val_t>, _>>()
.expect("Argument conversion failed")
.into();
let mut results: wasm_val_vec_t = vec![
wasm_val_t {
kind: wasm_valkind_enum::WASM_I64 as _,
of: wasm_val_inner { int64_t: 0 },
};
num_rets
]
.into();
let trap = callback(env.data().env.as_ptr(), &processed_args, &mut results);
if let Some(trap) = trap {
return Err(trap.inner);
}
let processed_results = results
.take()
.into_iter()
.map(TryInto::try_into)
.collect::<Result<Vec<Value>, _>>()
.expect("Result conversion failed");
Ok(processed_results)
};
let env = FunctionEnv::new(
&mut store_mut,
WrapperEnv {
env: FunctionCEnv::new(c_try!(
std::ptr::NonNull::new(env),
"Function environment cannot be a null pointer."
)),
env_finalizer: Arc::new(Mutex::new(env_finalizer)),
},
);
let function = Function::new(&mut store_mut, &env, func_sig, inner_callback);
Some(Box::new(wasm_func_t {
extern_: wasm_extern_t::new(store.inner.clone(), function.into()),
}))
}
#[no_mangle]
@ -109,17 +195,14 @@ pub unsafe extern "C" fn wasm_func_delete(_func: Option<Box<wasm_func_t>>) {}
#[no_mangle]
pub unsafe extern "C" fn wasm_func_call(
func: Option<&wasm_func_t>,
func: Option<&mut wasm_func_t>,
args: Option<&wasm_val_vec_t>,
results: &mut wasm_val_vec_t,
) -> Option<Box<wasm_trap_t>> {
let func = func?;
let args = args?;
if func.context.is_none() {
crate::error::update_last_error(wasm_store_t::CTX_ERR_STR);
}
let mut ctx = func.context.as_ref()?.borrow_mut();
let mut store = func.extern_.store.clone();
let mut store_mut = store.store_mut();
let params = args
.as_slice()
.iter()
@ -128,7 +211,7 @@ pub unsafe extern "C" fn wasm_func_call(
.collect::<Result<Vec<Value>, _>>()
.expect("Arguments conversion failed");
match func.inner.call(&mut ctx.inner, &params) {
match func.extern_.function().call(&mut store_mut, &params) {
Ok(wasm_results) => {
for (slot, val) in results
.as_uninit_slice()
@ -146,31 +229,28 @@ pub unsafe extern "C" fn wasm_func_call(
#[no_mangle]
pub unsafe extern "C" fn wasm_func_param_arity(func: &wasm_func_t) -> usize {
let ctx = func
.context
.as_ref()
.expect(wasm_store_t::CTX_ERR_STR)
.borrow();
func.inner.ty(&ctx.inner).params().len()
func.extern_
.function()
.ty(&func.extern_.store.store())
.params()
.len()
}
#[no_mangle]
pub unsafe extern "C" fn wasm_func_result_arity(func: &wasm_func_t) -> usize {
let ctx = func
.context
.as_ref()
.expect(wasm_store_t::CTX_ERR_STR)
.borrow();
func.inner.ty(&ctx.inner).results().len()
func.extern_
.function()
.ty(&func.extern_.store.store())
.results()
.len()
}
#[no_mangle]
pub extern "C" fn wasm_func_type(func: Option<&wasm_func_t>) -> Option<Box<wasm_functype_t>> {
pub unsafe extern "C" fn wasm_func_type(
func: Option<&wasm_func_t>,
) -> Option<Box<wasm_functype_t>> {
let func = func?;
if func.context.is_none() {
crate::error::update_last_error(wasm_store_t::CTX_ERR_STR);
}
let ctx = func.context.as_ref()?.borrow();
Some(Box::new(wasm_functype_t::new(func.inner.ty(&ctx.inner))))
Some(Box::new(wasm_functype_t::new(
func.extern_.function().ty(&func.extern_.store.store()),
)))
}

View File

@ -1,58 +1,47 @@
use super::super::context::wasm_context_t;
use super::super::store::wasm_store_t;
use super::super::types::wasm_globaltype_t;
use super::super::value::wasm_val_t;
use super::CApiExternTag;
use crate::error::update_last_error;
use std::cell::RefCell;
use super::wasm_extern_t;
use std::convert::TryInto;
use std::rc::Rc;
use wasmer_api::{Global, Value};
use wasmer_api::{Extern, Global, Value};
#[allow(non_camel_case_types)]
#[repr(C)]
#[derive(Clone, Debug)]
#[derive(Clone)]
pub struct wasm_global_t {
pub(crate) tag: CApiExternTag,
pub(crate) inner: Box<Global>,
pub(crate) context: Option<Rc<RefCell<wasm_context_t>>>,
pub(crate) extern_: wasm_extern_t,
}
impl wasm_global_t {
pub(crate) fn new(global: Global) -> Self {
Self {
tag: CApiExternTag::Global,
inner: Box::new(global),
context: None,
pub(crate) fn try_from(e: &wasm_extern_t) -> Option<&wasm_global_t> {
match &e.inner {
Extern::Global(_) => Some(unsafe { &*(e as *const _ as *const _) }),
_ => None,
}
}
}
#[no_mangle]
pub unsafe extern "C" fn wasm_global_new(
store: Option<&wasm_store_t>,
store: Option<&mut wasm_store_t>,
global_type: Option<&wasm_globaltype_t>,
val: Option<&wasm_val_t>,
) -> Option<Box<wasm_global_t>> {
let global_type = global_type?;
let store = store?;
if store.context.is_none() {
crate::error::update_last_error(wasm_store_t::CTX_ERR_STR);
}
let mut ctx = store.context.as_ref()?.borrow_mut();
let mut store_mut = store.inner.store_mut();
let val = val?;
let global_type = &global_type.inner().global_type;
let wasm_val = val.try_into().ok()?;
let global = if global_type.mutability.is_mutable() {
Global::new_mut(&mut ctx.inner, wasm_val)
Global::new_mut(&mut store_mut, wasm_val)
} else {
Global::new(&mut ctx.inner, wasm_val)
Global::new(&mut store_mut, wasm_val)
};
let mut retval = Box::new(wasm_global_t::new(global));
retval.context = store.context.clone();
Some(retval)
Some(Box::new(wasm_global_t {
extern_: wasm_extern_t::new(store.inner.clone(), global.into()),
}))
}
#[no_mangle]
@ -61,42 +50,31 @@ pub unsafe extern "C" fn wasm_global_delete(_global: Option<Box<wasm_global_t>>)
#[no_mangle]
pub unsafe extern "C" fn wasm_global_copy(global: &wasm_global_t) -> Box<wasm_global_t> {
// do shallow copy
Box::new(wasm_global_t::new((&*global.inner).clone()))
Box::new(global.clone())
}
#[no_mangle]
pub unsafe extern "C" fn wasm_global_get(
global: &wasm_global_t,
global: &mut wasm_global_t,
// own
out: &mut wasm_val_t,
) {
match global.context.as_ref() {
Some(ctx) => {
let value = global.inner.get(&mut ctx.borrow_mut().inner);
*out = value.try_into().unwrap();
}
None => {
crate::error::update_last_error(wasm_store_t::CTX_ERR_STR);
}
}
let value = global
.extern_
.global()
.get(&mut global.extern_.store.store_mut());
*out = value.try_into().unwrap();
}
/// Note: This function returns nothing by design but it can raise an
/// error if setting a new value fails.
#[no_mangle]
pub unsafe extern "C" fn wasm_global_set(global: &mut wasm_global_t, val: &wasm_val_t) {
match global.context.as_ref() {
Some(ctx) => {
let value: Value = val.try_into().unwrap();
if let Err(e) = global.inner.set(&mut ctx.borrow_mut().inner, value) {
update_last_error(e);
}
}
None => {
crate::error::update_last_error(wasm_store_t::CTX_ERR_STR);
}
}
let value: Value = val.try_into().unwrap();
c_try!(global
.extern_
.global()
.set(&mut global.extern_.store.store_mut(), value); otherwise ());
}
#[no_mangle]
@ -104,20 +82,16 @@ pub unsafe extern "C" fn wasm_global_same(
wasm_global1: &wasm_global_t,
wasm_global2: &wasm_global_t,
) -> bool {
wasm_global1.inner == wasm_global2.inner
wasm_global1.extern_.global() == wasm_global2.extern_.global()
}
#[no_mangle]
pub extern "C" fn wasm_global_type(
pub unsafe extern "C" fn wasm_global_type(
global: Option<&wasm_global_t>,
) -> Option<Box<wasm_globaltype_t>> {
let global = global?;
if global.context.is_none() {
crate::error::update_last_error(wasm_store_t::CTX_ERR_STR);
}
let ctx = global.context.as_ref()?.borrow();
Some(Box::new(wasm_globaltype_t::new(
global.inner.ty(&ctx.inner),
global.extern_.global().ty(&global.extern_.store.store()),
)))
}
@ -133,8 +107,6 @@ mod tests {
int main() {
wasm_engine_t* engine = wasm_engine_new();
wasm_store_t* store = wasm_store_new(engine);
wasm_context_t* ctx = wasm_context_new(store, 0);
wasm_store_context_set(store, ctx);
wasm_val_t forty_two = WASM_F32_VAL(42);
wasm_val_t forty_three = WASM_F32_VAL(43);
@ -167,8 +139,6 @@ mod tests {
int main() {
wasm_engine_t* engine = wasm_engine_new();
wasm_store_t* store = wasm_store_new(engine);
wasm_context_t* ctx = wasm_context_new(store, 0);
wasm_store_context_set(store, ctx);
wasm_byte_vec_t wat;
wasmer_byte_vec_new_from_string(&wat, "(module (global $global (export \"global\") f32 (f32.const 1)))");

View File

@ -1,47 +1,36 @@
use super::super::context::wasm_context_t;
use super::super::store::wasm_store_t;
use super::super::types::wasm_memorytype_t;
use super::CApiExternTag;
use std::cell::RefCell;
use std::rc::Rc;
use wasmer_api::{Memory, Pages};
use super::{super::store::wasm_store_t, wasm_extern_t};
use wasmer_api::{Extern, Memory, Pages};
#[allow(non_camel_case_types)]
#[repr(C)]
#[derive(Clone, Debug)]
#[derive(Clone)]
pub struct wasm_memory_t {
pub(crate) tag: CApiExternTag,
pub(crate) inner: Box<Memory>,
pub(crate) context: Option<Rc<RefCell<wasm_context_t>>>,
pub(crate) extern_: wasm_extern_t,
}
impl wasm_memory_t {
pub(crate) fn new(memory: Memory) -> Self {
Self {
tag: CApiExternTag::Memory,
inner: Box::new(memory),
context: None,
pub(crate) fn try_from(e: &wasm_extern_t) -> Option<&wasm_memory_t> {
match &e.inner {
Extern::Memory(_) => Some(unsafe { &*(e as *const _ as *const _) }),
_ => None,
}
}
}
#[no_mangle]
pub unsafe extern "C" fn wasm_memory_new(
store: Option<&wasm_store_t>,
store: Option<&mut wasm_store_t>,
memory_type: Option<&wasm_memorytype_t>,
) -> Option<Box<wasm_memory_t>> {
let memory_type = memory_type?;
let store = store?;
if store.context.is_none() {
crate::error::update_last_error(wasm_store_t::CTX_ERR_STR);
}
let mut ctx = store.context.as_ref()?.borrow_mut();
let mut store_mut = store.inner.store_mut();
let memory_type = memory_type.inner().memory_type;
let memory = c_try!(Memory::new(&mut ctx.inner, memory_type));
let mut retval = Box::new(wasm_memory_t::new(memory));
retval.context = store.context.clone();
Some(retval)
let memory = c_try!(Memory::new(&mut store_mut, memory_type));
Some(Box::new(wasm_memory_t {
extern_: wasm_extern_t::new(store.inner.clone(), memory.into()),
}))
}
#[no_mangle]
@ -50,7 +39,7 @@ pub unsafe extern "C" fn wasm_memory_delete(_memory: Option<Box<wasm_memory_t>>)
#[no_mangle]
pub unsafe extern "C" fn wasm_memory_copy(memory: &wasm_memory_t) -> Box<wasm_memory_t> {
// do shallow copy
Box::new(wasm_memory_t::new((&*memory.inner).clone()))
Box::new(memory.clone())
}
#[no_mangle]
@ -58,7 +47,7 @@ pub unsafe extern "C" fn wasm_memory_same(
wasm_memory1: &wasm_memory_t,
wasm_memory2: &wasm_memory_t,
) -> bool {
wasm_memory1.inner == wasm_memory2.inner
wasm_memory1.extern_.memory() == wasm_memory2.extern_.memory()
}
#[no_mangle]
@ -66,56 +55,47 @@ pub unsafe extern "C" fn wasm_memory_type(
memory: Option<&wasm_memory_t>,
) -> Option<Box<wasm_memorytype_t>> {
let memory = memory?;
if memory.context.is_none() {
crate::error::update_last_error(wasm_store_t::CTX_ERR_STR);
}
let ctx = memory.context.as_ref()?.borrow();
Some(Box::new(wasm_memorytype_t::new(
memory.inner.ty(&ctx.inner),
memory.extern_.memory().ty(&memory.extern_.store.store()),
)))
}
// get a raw pointer into bytes
#[no_mangle]
pub unsafe extern "C" fn wasm_memory_data(memory: &mut wasm_memory_t) -> *mut u8 {
let ctx = memory
.context
.as_ref()
.expect(wasm_store_t::CTX_ERR_STR)
.borrow();
memory.inner.data_ptr(&ctx.inner)
memory
.extern_
.memory()
.data_ptr(&memory.extern_.store.store())
}
// size in bytes
#[no_mangle]
pub unsafe extern "C" fn wasm_memory_data_size(memory: &wasm_memory_t) -> usize {
let ctx = memory
.context
.as_ref()
.expect(wasm_store_t::CTX_ERR_STR)
.borrow();
memory.inner.size(&ctx.inner).bytes().0
memory
.extern_
.memory()
.size(&memory.extern_.store.store())
.bytes()
.0
}
// size in pages
#[no_mangle]
pub unsafe extern "C" fn wasm_memory_size(memory: &wasm_memory_t) -> u32 {
let ctx = memory
.context
.as_ref()
.expect(wasm_store_t::CTX_ERR_STR)
.borrow();
memory.inner.size(&ctx.inner).0 as _
memory
.extern_
.memory()
.size(&memory.extern_.store.store())
.0 as _
}
// delta is in pages
#[no_mangle]
pub unsafe extern "C" fn wasm_memory_grow(memory: &mut wasm_memory_t, delta: u32) -> bool {
let mut ctx = memory
.context
.as_ref()
.expect(wasm_store_t::CTX_ERR_STR)
.borrow_mut();
memory.inner.grow(&mut ctx.inner, Pages(delta)).is_ok()
memory
.extern_
.memory()
.grow(&mut memory.extern_.store.store_mut(), Pages(delta))
.is_ok()
}

View File

@ -3,231 +3,77 @@ mod global;
mod memory;
mod table;
use super::context::wasm_context_t;
use super::store::wasm_store_t;
use super::store::StoreRef;
// use super::types::{wasm_externkind_enum, wasm_externkind_t};
pub use function::*;
pub use global::*;
pub use memory::*;
use std::cell::RefCell;
use std::mem::{self, ManuallyDrop};
use std::rc::Rc;
pub use table::*;
use wasmer_api::{Extern, ExternType};
use wasmer_api::{Extern, ExternType, Function, Global, Memory, Table};
#[allow(non_camel_case_types)]
#[repr(transparent)]
#[derive(Clone)]
pub struct wasm_extern_t {
pub(crate) inner: wasm_extern_inner,
}
/// All elements in this union must be `repr(C)` and have a
/// `CApiExternTag` as their first element.
#[allow(non_camel_case_types)]
pub(crate) union wasm_extern_inner {
function: mem::ManuallyDrop<wasm_func_t>,
memory: mem::ManuallyDrop<wasm_memory_t>,
global: mem::ManuallyDrop<wasm_global_t>,
table: mem::ManuallyDrop<wasm_table_t>,
}
#[cfg(test)]
mod extern_tests {
use super::*;
#[test]
fn externs_are_the_same_size() {
use std::mem::{align_of, size_of};
assert_eq!(size_of::<wasm_extern_t>(), size_of::<wasm_func_t>());
assert_eq!(size_of::<wasm_extern_t>(), size_of::<wasm_memory_t>());
assert_eq!(size_of::<wasm_extern_t>(), size_of::<wasm_global_t>());
assert_eq!(size_of::<wasm_extern_t>(), size_of::<wasm_table_t>());
assert_eq!(align_of::<wasm_extern_t>(), align_of::<wasm_func_t>());
assert_eq!(align_of::<wasm_extern_t>(), align_of::<wasm_memory_t>());
assert_eq!(align_of::<wasm_extern_t>(), align_of::<wasm_global_t>());
assert_eq!(align_of::<wasm_extern_t>(), align_of::<wasm_table_t>());
}
#[test]
fn tags_are_the_same_offset_away() {
use field_offset::offset_of;
let func_tag_offset = offset_of!(wasm_func_t => tag).get_byte_offset();
let memory_tag_offset = offset_of!(wasm_memory_t => tag).get_byte_offset();
let global_tag_offset = offset_of!(wasm_global_t => tag).get_byte_offset();
let table_tag_offset = offset_of!(wasm_table_t => tag).get_byte_offset();
assert_eq!(func_tag_offset, memory_tag_offset);
assert_eq!(global_tag_offset, table_tag_offset);
assert_eq!(func_tag_offset, global_tag_offset);
}
}
impl Drop for wasm_extern_inner {
fn drop(&mut self) {
unsafe {
match self.function.tag {
CApiExternTag::Function => mem::ManuallyDrop::drop(&mut self.function),
CApiExternTag::Global => mem::ManuallyDrop::drop(&mut self.global),
CApiExternTag::Table => mem::ManuallyDrop::drop(&mut self.table),
CApiExternTag::Memory => mem::ManuallyDrop::drop(&mut self.memory),
}
}
}
pub(crate) inner: Extern,
pub(crate) store: StoreRef,
}
impl wasm_extern_t {
pub(crate) fn get_tag(&self) -> CApiExternTag {
unsafe { self.inner.function.tag }
pub(crate) fn new(store: StoreRef, inner: Extern) -> Self {
Self { inner, store }
}
pub(crate) fn ty(&self) -> ExternType {
match self.get_tag() {
CApiExternTag::Function => unsafe {
let ctx = self
.inner
.function
.context
.as_ref()
.expect(wasm_store_t::CTX_ERR_STR)
.borrow();
ExternType::Function(self.inner.function.inner.ty(&ctx.inner))
},
CApiExternTag::Memory => unsafe {
let ctx = self
.inner
.memory
.context
.as_ref()
.expect(wasm_store_t::CTX_ERR_STR)
.borrow();
ExternType::Memory(self.inner.memory.inner.ty(&ctx.inner))
},
CApiExternTag::Global => unsafe {
let ctx = self
.inner
.global
.context
.as_ref()
.expect(wasm_store_t::CTX_ERR_STR)
.borrow();
ExternType::Global(self.inner.global.inner.ty(&ctx.inner))
},
CApiExternTag::Table => unsafe {
let ctx = self
.inner
.table
.context
.as_ref()
.expect(wasm_store_t::CTX_ERR_STR)
.borrow();
ExternType::Table(self.inner.table.inner.ty(&ctx.inner))
},
pub(crate) fn global(&self) -> Global {
match &self.inner {
Extern::Global(g) => g.clone(),
_ => unsafe { std::hint::unreachable_unchecked() },
}
}
pub(crate) fn set_context(&mut self, new_val: Option<Rc<RefCell<wasm_context_t>>>) {
match self.get_tag() {
CApiExternTag::Function => unsafe {
(*self.inner.function).context = new_val;
},
CApiExternTag::Memory => unsafe {
(*self.inner.memory).context = new_val;
},
CApiExternTag::Global => unsafe {
(*self.inner.global).context = new_val;
},
CApiExternTag::Table => unsafe {
(*self.inner.table).context = new_val;
},
pub(crate) fn function(&self) -> Function {
match &self.inner {
Extern::Function(f) => f.clone(),
_ => unsafe { std::hint::unreachable_unchecked() },
}
}
pub(crate) fn table(&self) -> Table {
match &self.inner {
Extern::Table(t) => t.clone(),
_ => unsafe { std::hint::unreachable_unchecked() },
}
}
pub(crate) fn memory(&self) -> Memory {
match &self.inner {
Extern::Memory(m) => m.clone(),
_ => unsafe { std::hint::unreachable_unchecked() },
}
}
}
impl Clone for wasm_extern_t {
fn clone(&self) -> Self {
match self.get_tag() {
CApiExternTag::Function => Self {
inner: wasm_extern_inner {
function: unsafe { self.inner.function.clone() },
},
},
CApiExternTag::Memory => Self {
inner: wasm_extern_inner {
memory: unsafe { self.inner.memory.clone() },
},
},
CApiExternTag::Global => Self {
inner: wasm_extern_inner {
global: unsafe { self.inner.global.clone() },
},
},
CApiExternTag::Table => Self {
inner: wasm_extern_inner {
table: unsafe { self.inner.table.clone() },
},
},
}
}
}
// #[no_mangle]
// pub extern "C" fn wasm_extern_kind(e: &wasm_extern_t) -> wasm_externkind_t {
// (match e.inner {
// Extern::Function(_) => wasm_externkind_enum::WASM_EXTERN_FUNC,
// Extern::Table(_) => wasm_externkind_enum::WASM_EXTERN_TABLE,
// Extern::Global(_) => wasm_externkind_enum::WASM_EXTERN_GLOBAL,
// Extern::Memory(_) => wasm_externkind_enum::WASM_EXTERN_MEMORY,
// }) as wasm_externkind_t
// }
impl From<Extern> for wasm_extern_t {
fn from(other: Extern) -> Self {
match other {
Extern::Function(function) => Self {
inner: wasm_extern_inner {
function: mem::ManuallyDrop::new(wasm_func_t::new(function)),
},
},
Extern::Memory(memory) => Self {
inner: wasm_extern_inner {
memory: mem::ManuallyDrop::new(wasm_memory_t::new(memory)),
},
},
Extern::Table(table) => Self {
inner: wasm_extern_inner {
table: mem::ManuallyDrop::new(wasm_table_t::new(table)),
},
},
Extern::Global(global) => Self {
inner: wasm_extern_inner {
global: mem::ManuallyDrop::new(wasm_global_t::new(global)),
},
},
}
impl wasm_extern_t {
pub(crate) unsafe fn ty(&self) -> ExternType {
self.inner.ty(&self.store.store())
}
}
impl From<wasm_extern_t> for Extern {
fn from(mut other: wasm_extern_t) -> Self {
let out = match other.get_tag() {
CApiExternTag::Function => unsafe {
(*ManuallyDrop::take(&mut other.inner.function).inner).into()
},
CApiExternTag::Memory => unsafe {
(*ManuallyDrop::take(&mut other.inner.memory).inner).into()
},
CApiExternTag::Table => unsafe {
(*ManuallyDrop::take(&mut other.inner.table).inner).into()
},
CApiExternTag::Global => unsafe {
(*ManuallyDrop::take(&mut other.inner.global).inner).into()
},
};
mem::forget(other);
out
fn from(other: wasm_extern_t) -> Self {
other.inner
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[repr(C)]
pub(crate) enum CApiExternTag {
Function,
Global,
Table,
Memory,
}
wasm_declare_boxed_vec!(extern);
/// Copy a `wasm_extern_t`.
@ -242,70 +88,46 @@ pub unsafe extern "C" fn wasm_extern_delete(_extern: Option<Box<wasm_extern_t>>)
#[no_mangle]
pub extern "C" fn wasm_func_as_extern(func: Option<&wasm_func_t>) -> Option<&wasm_extern_t> {
unsafe { mem::transmute::<Option<&wasm_func_t>, Option<&wasm_extern_t>>(func) }
Some(&func?.extern_)
}
#[no_mangle]
pub extern "C" fn wasm_global_as_extern(global: Option<&wasm_global_t>) -> Option<&wasm_extern_t> {
unsafe { mem::transmute::<Option<&wasm_global_t>, Option<&wasm_extern_t>>(global) }
Some(&global?.extern_)
}
#[no_mangle]
pub extern "C" fn wasm_memory_as_extern(memory: Option<&wasm_memory_t>) -> Option<&wasm_extern_t> {
unsafe { mem::transmute::<Option<&wasm_memory_t>, Option<&wasm_extern_t>>(memory) }
Some(&memory?.extern_)
}
#[no_mangle]
pub extern "C" fn wasm_table_as_extern(table: Option<&wasm_table_t>) -> Option<&wasm_extern_t> {
unsafe { mem::transmute::<Option<&wasm_table_t>, Option<&wasm_extern_t>>(table) }
Some(&table?.extern_)
}
#[no_mangle]
pub extern "C" fn wasm_extern_as_func(r#extern: Option<&wasm_extern_t>) -> Option<&wasm_func_t> {
let r#extern = r#extern?;
if r#extern.get_tag() == CApiExternTag::Function {
Some(unsafe { mem::transmute::<&wasm_extern_t, &wasm_func_t>(r#extern) })
} else {
None
}
wasm_func_t::try_from(r#extern?)
}
#[no_mangle]
pub extern "C" fn wasm_extern_as_global(
r#extern: Option<&wasm_extern_t>,
) -> Option<&wasm_global_t> {
let r#extern = r#extern?;
if r#extern.get_tag() == CApiExternTag::Global {
Some(unsafe { mem::transmute::<&wasm_extern_t, &wasm_global_t>(r#extern) })
} else {
None
}
wasm_global_t::try_from(r#extern?)
}
#[no_mangle]
pub extern "C" fn wasm_extern_as_memory(
r#extern: Option<&wasm_extern_t>,
) -> Option<&wasm_memory_t> {
let r#extern = r#extern?;
if r#extern.get_tag() == CApiExternTag::Memory {
Some(unsafe { mem::transmute::<&wasm_extern_t, &wasm_memory_t>(r#extern) })
} else {
None
}
wasm_memory_t::try_from(r#extern?)
}
#[no_mangle]
pub extern "C" fn wasm_extern_as_table(r#extern: Option<&wasm_extern_t>) -> Option<&wasm_table_t> {
let r#extern = r#extern?;
if r#extern.get_tag() == CApiExternTag::Table {
Some(unsafe { mem::transmute::<&wasm_extern_t, &wasm_table_t>(r#extern) })
} else {
None
}
wasm_table_t::try_from(r#extern?)
}
#[cfg(test)]
@ -320,8 +142,6 @@ mod tests {
int main() {
wasm_engine_t* engine = wasm_engine_new();
wasm_store_t* store = wasm_store_new(engine);
wasm_context_t* ctx = wasm_context_new(store, 0);
wasm_store_context_set(store, ctx);
wasm_byte_vec_t wat;
wasmer_byte_vec_new_from_string(

Some files were not shown because too many files have changed in this diff Show More