mirror of
https://github.com/mii443/wasmer.git
synced 2025-12-03 03:08:22 +00:00
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:
committed by
Manos Pitsidianakis
parent
b5ae6399ce
commit
a419ccdf52
@@ -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);
|
||||
|
||||
@@ -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! {})?;
|
||||
```
|
||||
|
||||
@@ -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)]);
|
||||
|
||||
@@ -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)]);
|
||||
|
||||
@@ -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)]);
|
||||
|
||||
@@ -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: {}",
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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)]);
|
||||
|
||||
@@ -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)]);
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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));
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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)]);
|
||||
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
|
||||
@@ -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...");
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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(_) => {}
|
||||
|
||||
@@ -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(_) => {}
|
||||
|
||||
@@ -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(_) => {}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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"]
|
||||
|
||||
@@ -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! {};
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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))]
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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())
|
||||
|
||||
193
lib/api/src/js/externals/function.rs
vendored
193
lib/api/src/js/externals/function.rs
vendored
@@ -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
|
||||
}
|
||||
|
||||
|
||||
66
lib/api/src/js/externals/global.rs
vendored
66
lib/api/src/js/externals/global.rs
vendored
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
67
lib/api/src/js/externals/memory.rs
vendored
67
lib/api/src/js/externals/memory.rs
vendored
@@ -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> {
|
||||
|
||||
18
lib/api/src/js/externals/mod.rs
vendored
18
lib/api/src/js/externals/mod.rs
vendored
@@ -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),
|
||||
|
||||
60
lib/api/src/js/externals/table.rs
vendored
60
lib/api/src/js/externals/table.rs
vendored
@@ -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())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
153
lib/api/src/js/function_env.rs
Normal file
153
lib/api/src/js/function_env.rs
Normal 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
|
||||
}
|
||||
}
|
||||
@@ -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.));
|
||||
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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> {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)?;
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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! {};
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
359
lib/api/src/sys/externals/function.rs
vendored
359
lib/api/src/sys/externals/function.rs
vendored
@@ -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!(
|
||||
|
||||
110
lib/api/src/sys/externals/global.rs
vendored
110
lib/api/src/sys/externals/global.rs
vendored
@@ -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 {
|
||||
|
||||
98
lib/api/src/sys/externals/memory.rs
vendored
98
lib/api/src/sys/externals/memory.rs
vendored
@@ -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> {
|
||||
|
||||
16
lib/api/src/sys/externals/mod.rs
vendored
16
lib/api/src/sys/externals/mod.rs
vendored
@@ -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),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
60
lib/api/src/sys/externals/table.rs
vendored
60
lib/api/src/sys/externals/table.rs
vendored
@@ -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 {
|
||||
|
||||
120
lib/api/src/sys/function_env.rs
Normal file
120
lib/api/src/sys/function_env.rs
Normal 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
|
||||
}
|
||||
}
|
||||
@@ -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() {
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
```"#
|
||||
);
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)?;
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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"))
|
||||
}
|
||||
|
||||
@@ -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)))
|
||||
|
||||
@@ -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(())
|
||||
// }
|
||||
}
|
||||
|
||||
@@ -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(())
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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>,
|
||||
) {
|
||||
}
|
||||
196
lib/c-api/src/wasm_c_api/externals/function.rs
vendored
196
lib/c-api/src/wasm_c_api/externals/function.rs
vendored
@@ -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, ¶ms) {
|
||||
match func.extern_.function().call(&mut store_mut, ¶ms) {
|
||||
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()),
|
||||
)))
|
||||
}
|
||||
|
||||
90
lib/c-api/src/wasm_c_api/externals/global.rs
vendored
90
lib/c-api/src/wasm_c_api/externals/global.rs
vendored
@@ -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)))");
|
||||
|
||||
94
lib/c-api/src/wasm_c_api/externals/memory.rs
vendored
94
lib/c-api/src/wasm_c_api/externals/memory.rs
vendored
@@ -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()
|
||||
}
|
||||
|
||||
284
lib/c-api/src/wasm_c_api/externals/mod.rs
vendored
284
lib/c-api/src/wasm_c_api/externals/mod.rs
vendored
@@ -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
Reference in New Issue
Block a user