Remove the action and context modules from wasmtime_jit (#924)
* Remove the `action` and `context` modules from `wasmtime_jit` These modules are now no longer necessary with the `wasmtime` crate fleshed out, and they're entirely subsumed by the `wasmtime` API as well. * Remove some more modules
This commit is contained in:
@@ -9,7 +9,7 @@ use std::path::Path;
|
|||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use wasmparser::{
|
use wasmparser::{
|
||||||
validate, CustomSectionKind, ExternalKind, ImportSectionEntryType, ModuleReader, Name,
|
validate, CustomSectionKind, ExternalKind, ImportSectionEntryType, ModuleReader, Name,
|
||||||
OperatorValidatorConfig, SectionCode, ValidatingParserConfig,
|
SectionCode,
|
||||||
};
|
};
|
||||||
use wasmtime_jit::CompiledModule;
|
use wasmtime_jit::CompiledModule;
|
||||||
|
|
||||||
@@ -244,16 +244,7 @@ impl Module {
|
|||||||
///
|
///
|
||||||
/// [binary]: https://webassembly.github.io/spec/core/binary/index.html
|
/// [binary]: https://webassembly.github.io/spec/core/binary/index.html
|
||||||
pub fn validate(store: &Store, binary: &[u8]) -> Result<()> {
|
pub fn validate(store: &Store, binary: &[u8]) -> Result<()> {
|
||||||
let features = store.engine().config().features.clone();
|
let config = store.engine().config().validating_config.clone();
|
||||||
let config = ValidatingParserConfig {
|
|
||||||
operator_config: OperatorValidatorConfig {
|
|
||||||
enable_threads: features.threads,
|
|
||||||
enable_reference_types: features.reference_types,
|
|
||||||
enable_bulk_memory: features.bulk_memory,
|
|
||||||
enable_simd: features.simd,
|
|
||||||
enable_multi_value: features.multi_value,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
validate(binary, Some(config)).map_err(Error::new)
|
validate(binary, Some(config)).map_err(Error::new)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,9 +4,10 @@ use std::fmt;
|
|||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use wasmparser::{OperatorValidatorConfig, ValidatingParserConfig};
|
||||||
use wasmtime_environ::settings::{self, Configurable};
|
use wasmtime_environ::settings::{self, Configurable};
|
||||||
use wasmtime_environ::CacheConfig;
|
use wasmtime_environ::CacheConfig;
|
||||||
use wasmtime_jit::{native, CompilationStrategy, Compiler, Features};
|
use wasmtime_jit::{native, CompilationStrategy, Compiler};
|
||||||
|
|
||||||
// Runtime Environment
|
// Runtime Environment
|
||||||
|
|
||||||
@@ -20,7 +21,7 @@ use wasmtime_jit::{native, CompilationStrategy, Compiler, Features};
|
|||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
pub(crate) flags: settings::Builder,
|
pub(crate) flags: settings::Builder,
|
||||||
pub(crate) features: Features,
|
pub(crate) validating_config: ValidatingParserConfig,
|
||||||
pub(crate) debug_info: bool,
|
pub(crate) debug_info: bool,
|
||||||
pub(crate) strategy: CompilationStrategy,
|
pub(crate) strategy: CompilationStrategy,
|
||||||
pub(crate) cache_config: CacheConfig,
|
pub(crate) cache_config: CacheConfig,
|
||||||
@@ -45,7 +46,15 @@ impl Config {
|
|||||||
|
|
||||||
Config {
|
Config {
|
||||||
debug_info: false,
|
debug_info: false,
|
||||||
features: Default::default(),
|
validating_config: ValidatingParserConfig {
|
||||||
|
operator_config: OperatorValidatorConfig {
|
||||||
|
enable_threads: false,
|
||||||
|
enable_reference_types: false,
|
||||||
|
enable_bulk_memory: false,
|
||||||
|
enable_simd: false,
|
||||||
|
enable_multi_value: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
flags,
|
flags,
|
||||||
strategy: CompilationStrategy::Auto,
|
strategy: CompilationStrategy::Auto,
|
||||||
cache_config: CacheConfig::new_cache_disabled(),
|
cache_config: CacheConfig::new_cache_disabled(),
|
||||||
@@ -77,10 +86,10 @@ impl Config {
|
|||||||
///
|
///
|
||||||
/// [threads]: https://github.com/webassembly/threads
|
/// [threads]: https://github.com/webassembly/threads
|
||||||
pub fn wasm_threads(&mut self, enable: bool) -> &mut Self {
|
pub fn wasm_threads(&mut self, enable: bool) -> &mut Self {
|
||||||
self.features.threads = enable;
|
self.validating_config.operator_config.enable_threads = enable;
|
||||||
// The threads proposal depends on the bulk memory proposal
|
// The threads proposal depends on the bulk memory proposal
|
||||||
if enable {
|
if enable {
|
||||||
self.features.bulk_memory = true;
|
self.wasm_bulk_memory(true);
|
||||||
}
|
}
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
@@ -102,10 +111,12 @@ impl Config {
|
|||||||
///
|
///
|
||||||
/// [proposal]: https://github.com/webassembly/reference-types
|
/// [proposal]: https://github.com/webassembly/reference-types
|
||||||
pub fn wasm_reference_types(&mut self, enable: bool) -> &mut Self {
|
pub fn wasm_reference_types(&mut self, enable: bool) -> &mut Self {
|
||||||
self.features.reference_types = enable;
|
self.validating_config
|
||||||
|
.operator_config
|
||||||
|
.enable_reference_types = enable;
|
||||||
// The reference types proposal depends on the bulk memory proposal
|
// The reference types proposal depends on the bulk memory proposal
|
||||||
if enable {
|
if enable {
|
||||||
self.features.bulk_memory = true;
|
self.wasm_bulk_memory(true);
|
||||||
}
|
}
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
@@ -126,7 +137,7 @@ impl Config {
|
|||||||
///
|
///
|
||||||
/// [proposal]: https://github.com/webassembly/simd
|
/// [proposal]: https://github.com/webassembly/simd
|
||||||
pub fn wasm_simd(&mut self, enable: bool) -> &mut Self {
|
pub fn wasm_simd(&mut self, enable: bool) -> &mut Self {
|
||||||
self.features.simd = enable;
|
self.validating_config.operator_config.enable_simd = enable;
|
||||||
let val = if enable { "true" } else { "false" };
|
let val = if enable { "true" } else { "false" };
|
||||||
self.flags
|
self.flags
|
||||||
.set("enable_simd", val)
|
.set("enable_simd", val)
|
||||||
@@ -150,7 +161,7 @@ impl Config {
|
|||||||
///
|
///
|
||||||
/// [proposal]: https://github.com/webassembly/bulk-memory-operations
|
/// [proposal]: https://github.com/webassembly/bulk-memory-operations
|
||||||
pub fn wasm_bulk_memory(&mut self, enable: bool) -> &mut Self {
|
pub fn wasm_bulk_memory(&mut self, enable: bool) -> &mut Self {
|
||||||
self.features.bulk_memory = enable;
|
self.validating_config.operator_config.enable_bulk_memory = enable;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,7 +181,7 @@ impl Config {
|
|||||||
///
|
///
|
||||||
/// [proposal]: https://github.com/webassembly/multi-value
|
/// [proposal]: https://github.com/webassembly/multi-value
|
||||||
pub fn wasm_multi_value(&mut self, enable: bool) -> &mut Self {
|
pub fn wasm_multi_value(&mut self, enable: bool) -> &mut Self {
|
||||||
self.features.multi_value = enable;
|
self.validating_config.operator_config.enable_multi_value = enable;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -288,10 +299,15 @@ impl Default for Config {
|
|||||||
|
|
||||||
impl fmt::Debug for Config {
|
impl fmt::Debug for Config {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
let features = &self.validating_config.operator_config;
|
||||||
f.debug_struct("Config")
|
f.debug_struct("Config")
|
||||||
.field("debug_info", &self.debug_info)
|
.field("debug_info", &self.debug_info)
|
||||||
.field("strategy", &self.strategy)
|
.field("strategy", &self.strategy)
|
||||||
.field("features", &self.features)
|
.field("wasm_threads", &features.enable_threads)
|
||||||
|
.field("wasm_reference_types", &features.enable_reference_types)
|
||||||
|
.field("wasm_bulk_memory", &features.enable_bulk_memory)
|
||||||
|
.field("wasm_simd", &features.enable_simd)
|
||||||
|
.field("wasm_multi_value", &features.enable_multi_value)
|
||||||
.field(
|
.field(
|
||||||
"flags",
|
"flags",
|
||||||
&settings::Flags::new(self.flags.clone()).to_string(),
|
&settings::Flags::new(self.flags.clone()).to_string(),
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ use crate::{Func, Store, ValType};
|
|||||||
use anyhow::{bail, Result};
|
use anyhow::{bail, Result};
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use wasmtime_environ::ir;
|
use wasmtime_environ::ir;
|
||||||
use wasmtime_jit::RuntimeValue;
|
|
||||||
|
|
||||||
/// Possible runtime values that a WebAssembly module can either consume or
|
/// Possible runtime values that a WebAssembly module can either consume or
|
||||||
/// produce.
|
/// produce.
|
||||||
@@ -172,18 +171,6 @@ impl From<Func> for Val {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<RuntimeValue> for Val {
|
|
||||||
fn from(rv: RuntimeValue) -> Self {
|
|
||||||
match rv {
|
|
||||||
RuntimeValue::I32(i) => Val::I32(i),
|
|
||||||
RuntimeValue::I64(i) => Val::I64(i),
|
|
||||||
RuntimeValue::F32(u) => Val::F32(u),
|
|
||||||
RuntimeValue::F64(u) => Val::F64(u),
|
|
||||||
RuntimeValue::V128(u) => Val::V128(u128::from_le_bytes(u)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn into_checked_anyfunc(
|
pub(crate) fn into_checked_anyfunc(
|
||||||
val: Val,
|
val: Val,
|
||||||
store: &Store,
|
store: &Store,
|
||||||
|
|||||||
@@ -11,8 +11,8 @@ use anyhow::{bail, format_err, Result};
|
|||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::str;
|
use std::str;
|
||||||
use wasm_webidl_bindings::ast;
|
use wasm_webidl_bindings::ast;
|
||||||
|
use wasmtime::Val;
|
||||||
use wasmtime_environ::ir;
|
use wasmtime_environ::ir;
|
||||||
use wasmtime_jit::RuntimeValue;
|
|
||||||
use wasmtime_runtime::{Export, InstanceHandle};
|
use wasmtime_runtime::{Export, InstanceHandle};
|
||||||
|
|
||||||
mod value;
|
mod value;
|
||||||
@@ -147,19 +147,7 @@ impl ModuleData {
|
|||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|rv| rv.into())
|
.map(|rv| rv.into())
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
let wasm_results = f
|
let wasm_results = f.call(&wasm_args)?;
|
||||||
.call(&wasm_args)?
|
|
||||||
.to_vec()
|
|
||||||
.into_iter()
|
|
||||||
.map(|v: wasmtime::Val| match v {
|
|
||||||
wasmtime::Val::I32(i) => RuntimeValue::I32(i),
|
|
||||||
wasmtime::Val::I64(i) => RuntimeValue::I64(i),
|
|
||||||
wasmtime::Val::F32(i) => RuntimeValue::F32(i),
|
|
||||||
wasmtime::Val::F64(i) => RuntimeValue::F64(i),
|
|
||||||
wasmtime::Val::V128(i) => RuntimeValue::V128(i.to_le_bytes()),
|
|
||||||
_ => panic!("unsupported value {:?}", v),
|
|
||||||
})
|
|
||||||
.collect::<Vec<RuntimeValue>>();
|
|
||||||
translate_outgoing(&mut cx, &outgoing, &wasm_results)
|
translate_outgoing(&mut cx, &outgoing, &wasm_results)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -358,7 +346,7 @@ fn translate_incoming(
|
|||||||
cx: &mut dyn TranslateContext,
|
cx: &mut dyn TranslateContext,
|
||||||
bindings: &[ast::IncomingBindingExpression],
|
bindings: &[ast::IncomingBindingExpression],
|
||||||
args: &[Value],
|
args: &[Value],
|
||||||
) -> Result<Vec<RuntimeValue>> {
|
) -> Result<Vec<Val>> {
|
||||||
let get = |expr: &ast::IncomingBindingExpression| match expr {
|
let get = |expr: &ast::IncomingBindingExpression| match expr {
|
||||||
ast::IncomingBindingExpression::Get(g) => args
|
ast::IncomingBindingExpression::Get(g) => args
|
||||||
.get(g.idx as usize)
|
.get(g.idx as usize)
|
||||||
@@ -387,31 +375,31 @@ fn translate_incoming(
|
|||||||
_ => bail!("expected a string"),
|
_ => bail!("expected a string"),
|
||||||
};
|
};
|
||||||
let (ptr, len) = copy(&g.alloc_func_name, val.as_bytes())?;
|
let (ptr, len) = copy(&g.alloc_func_name, val.as_bytes())?;
|
||||||
wasm.push(RuntimeValue::I32(ptr));
|
wasm.push(Val::I32(ptr));
|
||||||
wasm.push(RuntimeValue::I32(len));
|
wasm.push(Val::I32(len));
|
||||||
}
|
}
|
||||||
ast::IncomingBindingExpression::As(g) => {
|
ast::IncomingBindingExpression::As(g) => {
|
||||||
let val = get(&g.expr)?;
|
let val = get(&g.expr)?;
|
||||||
match g.ty {
|
match g.ty {
|
||||||
walrus::ValType::I32 => match val {
|
walrus::ValType::I32 => match val {
|
||||||
Value::I32(i) => wasm.push(RuntimeValue::I32(*i)),
|
Value::I32(i) => wasm.push(Val::I32(*i)),
|
||||||
Value::U32(i) => wasm.push(RuntimeValue::I32(*i as i32)),
|
Value::U32(i) => wasm.push(Val::I32(*i as i32)),
|
||||||
_ => bail!("cannot convert {:?} to `i32`", val),
|
_ => bail!("cannot convert {:?} to `i32`", val),
|
||||||
},
|
},
|
||||||
walrus::ValType::I64 => match val {
|
walrus::ValType::I64 => match val {
|
||||||
Value::I32(i) => wasm.push(RuntimeValue::I64((*i).into())),
|
Value::I32(i) => wasm.push(Val::I64((*i).into())),
|
||||||
Value::U32(i) => wasm.push(RuntimeValue::I64((*i).into())),
|
Value::U32(i) => wasm.push(Val::I64((*i).into())),
|
||||||
Value::I64(i) => wasm.push(RuntimeValue::I64(*i)),
|
Value::I64(i) => wasm.push(Val::I64(*i)),
|
||||||
Value::U64(i) => wasm.push(RuntimeValue::I64(*i as i64)),
|
Value::U64(i) => wasm.push(Val::I64(*i as i64)),
|
||||||
_ => bail!("cannot convert {:?} to `i64`", val),
|
_ => bail!("cannot convert {:?} to `i64`", val),
|
||||||
},
|
},
|
||||||
walrus::ValType::F32 => match val {
|
walrus::ValType::F32 => match val {
|
||||||
Value::F32(i) => wasm.push(RuntimeValue::F32(i.to_bits())),
|
Value::F32(i) => wasm.push(Val::F32(i.to_bits())),
|
||||||
_ => bail!("cannot convert {:?} to `f32`", val),
|
_ => bail!("cannot convert {:?} to `f32`", val),
|
||||||
},
|
},
|
||||||
walrus::ValType::F64 => match val {
|
walrus::ValType::F64 => match val {
|
||||||
Value::F32(i) => wasm.push(RuntimeValue::F64((*i as f64).to_bits())),
|
Value::F32(i) => wasm.push(Val::F64((*i as f64).to_bits())),
|
||||||
Value::F64(i) => wasm.push(RuntimeValue::F64(i.to_bits())),
|
Value::F64(i) => wasm.push(Val::F64(i.to_bits())),
|
||||||
_ => bail!("cannot convert {:?} to `f64`", val),
|
_ => bail!("cannot convert {:?} to `f64`", val),
|
||||||
},
|
},
|
||||||
walrus::ValType::V128 | walrus::ValType::Anyref => {
|
walrus::ValType::V128 | walrus::ValType::Anyref => {
|
||||||
@@ -429,7 +417,7 @@ fn translate_incoming(
|
|||||||
fn translate_outgoing(
|
fn translate_outgoing(
|
||||||
cx: &mut dyn TranslateContext,
|
cx: &mut dyn TranslateContext,
|
||||||
bindings: &[ast::OutgoingBindingExpression],
|
bindings: &[ast::OutgoingBindingExpression],
|
||||||
args: &[RuntimeValue],
|
args: &[Val],
|
||||||
) -> Result<Vec<Value>> {
|
) -> Result<Vec<Value>> {
|
||||||
let mut values = Vec::new();
|
let mut values = Vec::new();
|
||||||
|
|
||||||
@@ -445,32 +433,32 @@ fn translate_outgoing(
|
|||||||
let arg = get(a.idx)?;
|
let arg = get(a.idx)?;
|
||||||
match a.ty {
|
match a.ty {
|
||||||
ast::WebidlTypeRef::Scalar(ast::WebidlScalarType::UnsignedLong) => match arg {
|
ast::WebidlTypeRef::Scalar(ast::WebidlScalarType::UnsignedLong) => match arg {
|
||||||
RuntimeValue::I32(a) => values.push(Value::U32(a as u32)),
|
Val::I32(a) => values.push(Value::U32(a as u32)),
|
||||||
_ => bail!("can't convert {:?} to unsigned long", arg),
|
_ => bail!("can't convert {:?} to unsigned long", arg),
|
||||||
},
|
},
|
||||||
ast::WebidlTypeRef::Scalar(ast::WebidlScalarType::Long) => match arg {
|
ast::WebidlTypeRef::Scalar(ast::WebidlScalarType::Long) => match arg {
|
||||||
RuntimeValue::I32(a) => values.push(Value::I32(a)),
|
Val::I32(a) => values.push(Value::I32(a)),
|
||||||
_ => bail!("can't convert {:?} to long", arg),
|
_ => bail!("can't convert {:?} to long", arg),
|
||||||
},
|
},
|
||||||
ast::WebidlTypeRef::Scalar(ast::WebidlScalarType::LongLong) => match arg {
|
ast::WebidlTypeRef::Scalar(ast::WebidlScalarType::LongLong) => match arg {
|
||||||
RuntimeValue::I32(a) => values.push(Value::I64(a as i64)),
|
Val::I32(a) => values.push(Value::I64(a as i64)),
|
||||||
RuntimeValue::I64(a) => values.push(Value::I64(a)),
|
Val::I64(a) => values.push(Value::I64(a)),
|
||||||
_ => bail!("can't convert {:?} to long long", arg),
|
_ => bail!("can't convert {:?} to long long", arg),
|
||||||
},
|
},
|
||||||
ast::WebidlTypeRef::Scalar(ast::WebidlScalarType::UnsignedLongLong) => {
|
ast::WebidlTypeRef::Scalar(ast::WebidlScalarType::UnsignedLongLong) => {
|
||||||
match arg {
|
match arg {
|
||||||
RuntimeValue::I32(a) => values.push(Value::U64(a as u64)),
|
Val::I32(a) => values.push(Value::U64(a as u64)),
|
||||||
RuntimeValue::I64(a) => values.push(Value::U64(a as u64)),
|
Val::I64(a) => values.push(Value::U64(a as u64)),
|
||||||
_ => bail!("can't convert {:?} to unsigned long long", arg),
|
_ => bail!("can't convert {:?} to unsigned long long", arg),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ast::WebidlTypeRef::Scalar(ast::WebidlScalarType::Float) => match arg {
|
ast::WebidlTypeRef::Scalar(ast::WebidlScalarType::Float) => match arg {
|
||||||
RuntimeValue::F32(a) => values.push(Value::F32(f32::from_bits(a))),
|
Val::F32(a) => values.push(Value::F32(f32::from_bits(a))),
|
||||||
_ => bail!("can't convert {:?} to float", arg),
|
_ => bail!("can't convert {:?} to float", arg),
|
||||||
},
|
},
|
||||||
ast::WebidlTypeRef::Scalar(ast::WebidlScalarType::Double) => match arg {
|
ast::WebidlTypeRef::Scalar(ast::WebidlScalarType::Double) => match arg {
|
||||||
RuntimeValue::F32(a) => values.push(Value::F64(f32::from_bits(a) as f64)),
|
Val::F32(a) => values.push(Value::F64(f32::from_bits(a) as f64)),
|
||||||
RuntimeValue::F64(a) => values.push(Value::F64(f64::from_bits(a))),
|
Val::F64(a) => values.push(Value::F64(f64::from_bits(a))),
|
||||||
_ => bail!("can't convert {:?} to double", arg),
|
_ => bail!("can't convert {:?} to double", arg),
|
||||||
},
|
},
|
||||||
_ => bail!("unsupported outgoing binding expr {:?}", expr),
|
_ => bail!("unsupported outgoing binding expr {:?}", expr),
|
||||||
@@ -481,11 +469,11 @@ fn translate_outgoing(
|
|||||||
bail!("utf-8 strings must go into dom-string")
|
bail!("utf-8 strings must go into dom-string")
|
||||||
}
|
}
|
||||||
let offset = match get(e.offset)? {
|
let offset = match get(e.offset)? {
|
||||||
RuntimeValue::I32(a) => a,
|
Val::I32(a) => a,
|
||||||
_ => bail!("offset must be an i32"),
|
_ => bail!("offset must be an i32"),
|
||||||
};
|
};
|
||||||
let length = match get(e.length)? {
|
let length = match get(e.length)? {
|
||||||
RuntimeValue::I32(a) => a,
|
Val::I32(a) => a,
|
||||||
_ => bail!("length must be an i32"),
|
_ => bail!("length must be an i32"),
|
||||||
};
|
};
|
||||||
let bytes = unsafe { &cx.get_memory()?[offset as usize..][..length as usize] };
|
let bytes = unsafe { &cx.get_memory()?[offset as usize..][..length as usize] };
|
||||||
|
|||||||
@@ -1,295 +0,0 @@
|
|||||||
//! Support for performing actions with a wasm module from the outside.
|
|
||||||
|
|
||||||
use crate::compiler::Compiler;
|
|
||||||
use crate::instantiate::SetupError;
|
|
||||||
use std::cmp::max;
|
|
||||||
use std::{fmt, mem, ptr, slice};
|
|
||||||
use thiserror::Error;
|
|
||||||
use wasmtime_environ::ir;
|
|
||||||
use wasmtime_runtime::{wasmtime_call_trampoline, Export, InstanceHandle, Trap, VMInvokeArgument};
|
|
||||||
|
|
||||||
/// A runtime value.
|
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
|
||||||
pub enum RuntimeValue {
|
|
||||||
/// A runtime value with type i32.
|
|
||||||
I32(i32),
|
|
||||||
/// A runtime value with type i64.
|
|
||||||
I64(i64),
|
|
||||||
/// A runtime value with type f32.
|
|
||||||
F32(u32),
|
|
||||||
/// A runtime value with type f64.
|
|
||||||
F64(u64),
|
|
||||||
/// A runtime value with type v128
|
|
||||||
V128([u8; 16]),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RuntimeValue {
|
|
||||||
/// Return the type of this `RuntimeValue`.
|
|
||||||
pub fn value_type(self) -> ir::Type {
|
|
||||||
match self {
|
|
||||||
Self::I32(_) => ir::types::I32,
|
|
||||||
Self::I64(_) => ir::types::I64,
|
|
||||||
Self::F32(_) => ir::types::F32,
|
|
||||||
Self::F64(_) => ir::types::F64,
|
|
||||||
Self::V128(_) => ir::types::I8X16,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Assuming this `RuntimeValue` holds an `i32`, return that value.
|
|
||||||
pub fn unwrap_i32(self) -> i32 {
|
|
||||||
match self {
|
|
||||||
Self::I32(x) => x,
|
|
||||||
_ => panic!("unwrapping value of type {} as i32", self.value_type()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Assuming this `RuntimeValue` holds an `i64`, return that value.
|
|
||||||
pub fn unwrap_i64(self) -> i64 {
|
|
||||||
match self {
|
|
||||||
Self::I64(x) => x,
|
|
||||||
_ => panic!("unwrapping value of type {} as i64", self.value_type()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Assuming this `RuntimeValue` holds an `f32`, return that value.
|
|
||||||
pub fn unwrap_f32(self) -> f32 {
|
|
||||||
f32::from_bits(self.unwrap_f32_bits())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Assuming this `RuntimeValue` holds an `f32`, return the bits of that value as a `u32`.
|
|
||||||
pub fn unwrap_f32_bits(self) -> u32 {
|
|
||||||
match self {
|
|
||||||
Self::F32(x) => x,
|
|
||||||
_ => panic!("unwrapping value of type {} as f32", self.value_type()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Assuming this `RuntimeValue` holds an `f64`, return that value.
|
|
||||||
pub fn unwrap_f64(self) -> f64 {
|
|
||||||
f64::from_bits(self.unwrap_f64_bits())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Assuming this `RuntimeValue` holds an `f64`, return the bits of that value as a `u64`.
|
|
||||||
pub fn unwrap_f64_bits(self) -> u64 {
|
|
||||||
match self {
|
|
||||||
Self::F64(x) => x,
|
|
||||||
_ => panic!("unwrapping value of type {} as f64", self.value_type()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for RuntimeValue {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
Self::I32(x) => write!(f, "{}: i32", x),
|
|
||||||
Self::I64(x) => write!(f, "{}: i64", x),
|
|
||||||
Self::F32(x) => write!(f, "{}: f32", x),
|
|
||||||
Self::F64(x) => write!(f, "{}: f64", x),
|
|
||||||
Self::V128(x) => write!(f, "{:?}: v128", x.to_vec()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The result of invoking a wasm function or reading a wasm global.
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum ActionOutcome {
|
|
||||||
/// The action returned normally. Its return values are provided.
|
|
||||||
Returned {
|
|
||||||
/// The return values.
|
|
||||||
values: Vec<RuntimeValue>,
|
|
||||||
},
|
|
||||||
|
|
||||||
/// A trap occurred while the action was executing.
|
|
||||||
Trapped(Trap),
|
|
||||||
}
|
|
||||||
|
|
||||||
/// An error detected while invoking a wasm function or reading a wasm global.
|
|
||||||
/// Note that at this level, traps are not reported errors, but are rather
|
|
||||||
/// returned through `ActionOutcome`.
|
|
||||||
#[derive(Error, Debug)]
|
|
||||||
pub enum ActionError {
|
|
||||||
/// An internal implementation error occurred.
|
|
||||||
#[error("Failed to setup a module")]
|
|
||||||
Setup(#[from] SetupError),
|
|
||||||
|
|
||||||
/// No field with the specified name was present.
|
|
||||||
#[error("Unknown field: {0}")]
|
|
||||||
Field(String),
|
|
||||||
|
|
||||||
/// The field was present but was the wrong kind (eg. function, table, global, or memory).
|
|
||||||
#[error("Kind error: {0}")]
|
|
||||||
Kind(String),
|
|
||||||
|
|
||||||
/// The field was present but was the wrong type (eg. i32, i64, f32, or f64).
|
|
||||||
#[error("Type error: {0}")]
|
|
||||||
Type(String),
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Invoke a function through an `InstanceHandle` identified by an export name.
|
|
||||||
pub fn invoke(
|
|
||||||
compiler: &mut Compiler,
|
|
||||||
instance: &mut InstanceHandle,
|
|
||||||
function_name: &str,
|
|
||||||
args: &[RuntimeValue],
|
|
||||||
) -> Result<ActionOutcome, ActionError> {
|
|
||||||
let (address, signature, callee_vmctx) = match instance.lookup(function_name) {
|
|
||||||
Some(Export::Function {
|
|
||||||
address,
|
|
||||||
signature,
|
|
||||||
vmctx,
|
|
||||||
}) => (address, signature, vmctx),
|
|
||||||
Some(_) => {
|
|
||||||
return Err(ActionError::Kind(format!(
|
|
||||||
"exported item \"{}\" is not a function",
|
|
||||||
function_name
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
return Err(ActionError::Field(format!(
|
|
||||||
"no export named \"{}\"",
|
|
||||||
function_name
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
for (index, value) in args.iter().enumerate() {
|
|
||||||
// Add one to account for the leading vmctx argument.
|
|
||||||
assert_eq!(value.value_type(), signature.params[index + 1].value_type);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Support values larger than v128. And pack the values into memory
|
|
||||||
// instead of just using fixed-sized slots.
|
|
||||||
// Subtract one because we don't pass the vmctx argument in `values_vec`.
|
|
||||||
let value_size = mem::size_of::<VMInvokeArgument>();
|
|
||||||
let mut values_vec: Vec<VMInvokeArgument> =
|
|
||||||
vec![VMInvokeArgument::new(); max(signature.params.len() - 1, signature.returns.len())];
|
|
||||||
|
|
||||||
// Store the argument values into `values_vec`.
|
|
||||||
for (index, arg) in args.iter().enumerate() {
|
|
||||||
unsafe {
|
|
||||||
let ptr = values_vec.as_mut_ptr().add(index);
|
|
||||||
|
|
||||||
match arg {
|
|
||||||
RuntimeValue::I32(x) => ptr::write(ptr as *mut i32, *x),
|
|
||||||
RuntimeValue::I64(x) => ptr::write(ptr as *mut i64, *x),
|
|
||||||
RuntimeValue::F32(x) => ptr::write(ptr as *mut u32, *x),
|
|
||||||
RuntimeValue::F64(x) => ptr::write(ptr as *mut u64, *x),
|
|
||||||
RuntimeValue::V128(x) => ptr::write(ptr as *mut [u8; 16], *x),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the trampoline to call for this function.
|
|
||||||
let exec_code_buf = compiler
|
|
||||||
.get_trampoline(address, &signature, value_size)
|
|
||||||
.map_err(ActionError::Setup)?;
|
|
||||||
|
|
||||||
// Make all JIT code produced thus far executable.
|
|
||||||
compiler.publish_compiled_code();
|
|
||||||
|
|
||||||
// Call the trampoline. Pass a null `caller_vmctx` argument as `invoke` is
|
|
||||||
// all about calling from the outside world rather than from an instance.
|
|
||||||
if let Err(trap) = unsafe {
|
|
||||||
wasmtime_call_trampoline(
|
|
||||||
callee_vmctx,
|
|
||||||
ptr::null_mut(),
|
|
||||||
exec_code_buf,
|
|
||||||
values_vec.as_mut_ptr() as *mut u8,
|
|
||||||
)
|
|
||||||
} {
|
|
||||||
return Ok(ActionOutcome::Trapped(trap));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load the return values out of `values_vec`.
|
|
||||||
let values = signature
|
|
||||||
.returns
|
|
||||||
.iter()
|
|
||||||
.enumerate()
|
|
||||||
.map(|(index, abi_param)| unsafe {
|
|
||||||
let ptr = values_vec.as_ptr().add(index);
|
|
||||||
|
|
||||||
match abi_param.value_type {
|
|
||||||
ir::types::I32 => RuntimeValue::I32(ptr::read(ptr as *const i32)),
|
|
||||||
ir::types::I64 => RuntimeValue::I64(ptr::read(ptr as *const i64)),
|
|
||||||
ir::types::F32 => RuntimeValue::F32(ptr::read(ptr as *const u32)),
|
|
||||||
ir::types::F64 => RuntimeValue::F64(ptr::read(ptr as *const u64)),
|
|
||||||
ir::types::I8X16 => RuntimeValue::V128(ptr::read(ptr as *const [u8; 16])),
|
|
||||||
other => panic!("unsupported value type {:?}", other),
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
Ok(ActionOutcome::Returned { values })
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns a slice of the contents of allocated linear memory.
|
|
||||||
pub fn inspect_memory<'instance>(
|
|
||||||
instance: &'instance InstanceHandle,
|
|
||||||
memory_name: &str,
|
|
||||||
start: usize,
|
|
||||||
len: usize,
|
|
||||||
) -> Result<&'instance [u8], ActionError> {
|
|
||||||
let definition = match instance.lookup(memory_name) {
|
|
||||||
Some(Export::Memory {
|
|
||||||
definition,
|
|
||||||
memory: _memory,
|
|
||||||
vmctx: _vmctx,
|
|
||||||
}) => definition,
|
|
||||||
Some(_) => {
|
|
||||||
return Err(ActionError::Kind(format!(
|
|
||||||
"exported item \"{}\" is not a linear memory",
|
|
||||||
memory_name
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
return Err(ActionError::Field(format!(
|
|
||||||
"no export named \"{}\"",
|
|
||||||
memory_name
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(unsafe {
|
|
||||||
let memory_def = &*definition;
|
|
||||||
&slice::from_raw_parts(memory_def.base, memory_def.current_length)[start..start + len]
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Read a global in the given instance identified by an export name.
|
|
||||||
pub fn get(instance: &InstanceHandle, global_name: &str) -> Result<RuntimeValue, ActionError> {
|
|
||||||
let (definition, global) = match instance.lookup(global_name) {
|
|
||||||
Some(Export::Global {
|
|
||||||
definition,
|
|
||||||
vmctx: _,
|
|
||||||
global,
|
|
||||||
}) => (definition, global),
|
|
||||||
Some(_) => {
|
|
||||||
return Err(ActionError::Kind(format!(
|
|
||||||
"exported item \"{}\" is not a global variable",
|
|
||||||
global_name
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
return Err(ActionError::Field(format!(
|
|
||||||
"no export named \"{}\"",
|
|
||||||
global_name
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
let global_def = &*definition;
|
|
||||||
Ok(match global.ty {
|
|
||||||
ir::types::I32 => RuntimeValue::I32(*global_def.as_i32()),
|
|
||||||
ir::types::I64 => RuntimeValue::I64(*global_def.as_i64()),
|
|
||||||
ir::types::F32 => RuntimeValue::F32(*global_def.as_f32_bits()),
|
|
||||||
ir::types::F64 => RuntimeValue::F64(*global_def.as_f64_bits()),
|
|
||||||
other => {
|
|
||||||
return Err(ActionError::Type(format!(
|
|
||||||
"global with type {} not supported",
|
|
||||||
other
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,222 +0,0 @@
|
|||||||
use crate::action::{get, inspect_memory, invoke};
|
|
||||||
use crate::{
|
|
||||||
instantiate, ActionError, ActionOutcome, CompiledModule, Compiler, InstanceHandle, Namespace,
|
|
||||||
RuntimeValue, SetupError,
|
|
||||||
};
|
|
||||||
use thiserror::Error;
|
|
||||||
use wasmparser::{validate, OperatorValidatorConfig, ValidatingParserConfig};
|
|
||||||
|
|
||||||
/// Indicates an unknown instance was specified.
|
|
||||||
#[derive(Error, Debug)]
|
|
||||||
#[error("no instance {instance_name} present")]
|
|
||||||
pub struct UnknownInstance {
|
|
||||||
instance_name: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Error message used by `WastContext`.
|
|
||||||
#[derive(Error, Debug)]
|
|
||||||
pub enum ContextError {
|
|
||||||
/// An unknown instance name was used.
|
|
||||||
#[error("An error occured due to an unknown instance being specified")]
|
|
||||||
Instance(#[from] UnknownInstance),
|
|
||||||
/// An error occured while performing an action.
|
|
||||||
#[error("An error occurred while performing an action")]
|
|
||||||
Action(#[from] ActionError),
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The collection of features configurable during compilation
|
|
||||||
#[derive(Clone, Default, Debug)]
|
|
||||||
pub struct Features {
|
|
||||||
/// marks whether the proposed thread feature is enabled or disabled
|
|
||||||
pub threads: bool,
|
|
||||||
/// marks whether the proposed reference type feature is enabled or disabled
|
|
||||||
pub reference_types: bool,
|
|
||||||
/// marks whether the proposed SIMD feature is enabled or disabled
|
|
||||||
pub simd: bool,
|
|
||||||
/// marks whether the proposed bulk memory feature is enabled or disabled
|
|
||||||
pub bulk_memory: bool,
|
|
||||||
/// marks whether the proposed multi-value feature is enabled or disabled
|
|
||||||
pub multi_value: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Into<ValidatingParserConfig> for Features {
|
|
||||||
fn into(self) -> ValidatingParserConfig {
|
|
||||||
ValidatingParserConfig {
|
|
||||||
operator_config: OperatorValidatorConfig {
|
|
||||||
enable_threads: self.threads,
|
|
||||||
enable_reference_types: self.reference_types,
|
|
||||||
enable_bulk_memory: self.bulk_memory,
|
|
||||||
enable_simd: self.simd,
|
|
||||||
enable_multi_value: self.multi_value,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A convenient context for compiling and executing WebAssembly instances.
|
|
||||||
pub struct Context {
|
|
||||||
namespace: Namespace,
|
|
||||||
compiler: Box<Compiler>,
|
|
||||||
debug_info: bool,
|
|
||||||
features: Features,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Context {
|
|
||||||
/// Construct a new instance of `Context`.
|
|
||||||
pub fn new(compiler: Box<Compiler>) -> Self {
|
|
||||||
Self {
|
|
||||||
namespace: Namespace::new(),
|
|
||||||
compiler,
|
|
||||||
debug_info: false,
|
|
||||||
features: Default::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get debug_info settings.
|
|
||||||
pub fn debug_info(&self) -> bool {
|
|
||||||
self.debug_info
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set debug_info settings.
|
|
||||||
pub fn set_debug_info(&mut self, value: bool) {
|
|
||||||
self.debug_info = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Retrieve the context features
|
|
||||||
pub fn features(&self) -> &Features {
|
|
||||||
&self.features
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Construct a new instance with the given features from the current `Context`
|
|
||||||
pub fn with_features(self, features: Features) -> Self {
|
|
||||||
Self { features, ..self }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn validate(&mut self, data: &[u8]) -> Result<(), String> {
|
|
||||||
// TODO: Fix Cranelift to be able to perform validation itself, rather
|
|
||||||
// than calling into wasmparser ourselves here.
|
|
||||||
validate(data, Some(self.features.clone().into()))
|
|
||||||
.map_err(|e| format!("module did not validate: {}", e.to_string()))
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn instantiate(&mut self, data: &[u8]) -> Result<InstanceHandle, SetupError> {
|
|
||||||
self.validate(&data).map_err(SetupError::Validate)?;
|
|
||||||
let debug_info = self.debug_info();
|
|
||||||
|
|
||||||
instantiate(&mut *self.compiler, &data, &mut self.namespace, debug_info)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return the instance associated with the given name.
|
|
||||||
pub fn get_instance(
|
|
||||||
&mut self,
|
|
||||||
instance_name: &str,
|
|
||||||
) -> Result<&mut InstanceHandle, UnknownInstance> {
|
|
||||||
self.namespace
|
|
||||||
.get_instance(instance_name)
|
|
||||||
.ok_or_else(|| UnknownInstance {
|
|
||||||
instance_name: instance_name.to_string(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Instantiate a module instance and register the instance.
|
|
||||||
///
|
|
||||||
/// # Unsafety
|
|
||||||
///
|
|
||||||
/// See `InstanceHandle::new`
|
|
||||||
pub unsafe fn instantiate_module(
|
|
||||||
&mut self,
|
|
||||||
instance_name: Option<String>,
|
|
||||||
data: &[u8],
|
|
||||||
) -> Result<InstanceHandle, ActionError> {
|
|
||||||
let instance = self.instantiate(data).map_err(ActionError::Setup)?;
|
|
||||||
self.optionally_name_instance(instance_name, instance.clone());
|
|
||||||
Ok(instance)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Compile a module.
|
|
||||||
pub fn compile_module(&mut self, data: &[u8]) -> Result<CompiledModule, SetupError> {
|
|
||||||
self.validate(&data).map_err(SetupError::Validate)?;
|
|
||||||
let debug_info = self.debug_info();
|
|
||||||
|
|
||||||
CompiledModule::new(&mut *self.compiler, data, debug_info)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// If `name` isn't None, register it for the given instance.
|
|
||||||
pub fn optionally_name_instance(&mut self, name: Option<String>, instance: InstanceHandle) {
|
|
||||||
if let Some(name) = name {
|
|
||||||
self.namespace.name_instance(name, instance);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Register a name for the given instance.
|
|
||||||
pub fn name_instance(&mut self, name: String, instance: InstanceHandle) {
|
|
||||||
self.namespace.name_instance(name, instance);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Register an additional name for an existing registered instance.
|
|
||||||
pub fn alias(&mut self, name: &str, as_name: String) -> Result<(), UnknownInstance> {
|
|
||||||
let instance = self.get_instance(&name)?.clone();
|
|
||||||
self.name_instance(as_name, instance);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Invoke an exported function from a named instance.
|
|
||||||
pub fn invoke_named(
|
|
||||||
&mut self,
|
|
||||||
instance_name: &str,
|
|
||||||
field: &str,
|
|
||||||
args: &[RuntimeValue],
|
|
||||||
) -> Result<ActionOutcome, ContextError> {
|
|
||||||
let mut instance = self
|
|
||||||
.get_instance(&instance_name)
|
|
||||||
.map_err(ContextError::Instance)?
|
|
||||||
.clone();
|
|
||||||
self.invoke(&mut instance, field, args)
|
|
||||||
.map_err(ContextError::Action)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Invoke an exported function from an instance.
|
|
||||||
pub fn invoke(
|
|
||||||
&mut self,
|
|
||||||
instance: &mut InstanceHandle,
|
|
||||||
field: &str,
|
|
||||||
args: &[RuntimeValue],
|
|
||||||
) -> Result<ActionOutcome, ActionError> {
|
|
||||||
invoke(&mut *self.compiler, instance, field, &args)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the value of an exported global variable from an instance.
|
|
||||||
pub fn get_named(
|
|
||||||
&mut self,
|
|
||||||
instance_name: &str,
|
|
||||||
field: &str,
|
|
||||||
) -> Result<ActionOutcome, ContextError> {
|
|
||||||
let instance = self
|
|
||||||
.get_instance(&instance_name)
|
|
||||||
.map_err(ContextError::Instance)?
|
|
||||||
.clone();
|
|
||||||
self.get(&instance, field).map_err(ContextError::Action)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the value of an exported global variable from an instance.
|
|
||||||
pub fn get(
|
|
||||||
&mut self,
|
|
||||||
instance: &InstanceHandle,
|
|
||||||
field: &str,
|
|
||||||
) -> Result<ActionOutcome, ActionError> {
|
|
||||||
get(instance, field).map(|value| ActionOutcome::Returned {
|
|
||||||
values: vec![value],
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get a slice of memory from an instance.
|
|
||||||
pub fn inspect_memory<'instance>(
|
|
||||||
&self,
|
|
||||||
instance: &'instance InstanceHandle,
|
|
||||||
field_name: &str,
|
|
||||||
start: usize,
|
|
||||||
len: usize,
|
|
||||||
) -> Result<&'instance [u8], ActionError> {
|
|
||||||
inspect_memory(instance, field_name, start, len)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -21,28 +21,22 @@
|
|||||||
)
|
)
|
||||||
)]
|
)]
|
||||||
|
|
||||||
mod action;
|
|
||||||
mod code_memory;
|
mod code_memory;
|
||||||
mod compiler;
|
mod compiler;
|
||||||
mod context;
|
|
||||||
mod function_table;
|
mod function_table;
|
||||||
mod imports;
|
mod imports;
|
||||||
mod instantiate;
|
mod instantiate;
|
||||||
mod link;
|
mod link;
|
||||||
mod namespace;
|
|
||||||
mod resolver;
|
mod resolver;
|
||||||
mod target_tunables;
|
mod target_tunables;
|
||||||
|
|
||||||
pub mod native;
|
pub mod native;
|
||||||
pub mod trampoline;
|
pub mod trampoline;
|
||||||
|
|
||||||
pub use crate::action::{invoke, ActionError, ActionOutcome, RuntimeValue};
|
|
||||||
pub use crate::code_memory::CodeMemory;
|
pub use crate::code_memory::CodeMemory;
|
||||||
pub use crate::compiler::{CompilationStrategy, Compiler};
|
pub use crate::compiler::{CompilationStrategy, Compiler};
|
||||||
pub use crate::context::{Context, ContextError, Features, UnknownInstance};
|
|
||||||
pub use crate::instantiate::{instantiate, CompiledModule, SetupError};
|
pub use crate::instantiate::{instantiate, CompiledModule, SetupError};
|
||||||
pub use crate::link::link_module;
|
pub use crate::link::link_module;
|
||||||
pub use crate::namespace::Namespace;
|
|
||||||
pub use crate::resolver::{NullResolver, Resolver};
|
pub use crate::resolver::{NullResolver, Resolver};
|
||||||
pub use crate::target_tunables::target_tunables;
|
pub use crate::target_tunables::target_tunables;
|
||||||
|
|
||||||
|
|||||||
@@ -1,46 +0,0 @@
|
|||||||
//! The core WebAssembly spec does not specify how imports are to be resolved
|
|
||||||
//! to exports. This file provides one possible way to manage multiple instances
|
|
||||||
//! and resolve imports to exports among them.
|
|
||||||
|
|
||||||
use crate::resolver::Resolver;
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use wasmtime_runtime::{Export, InstanceHandle};
|
|
||||||
|
|
||||||
/// A namespace containing instances keyed by name.
|
|
||||||
///
|
|
||||||
/// Note that `Namespace` implements the `Resolver` trait, so it can resolve
|
|
||||||
/// imports using defined exports.
|
|
||||||
pub struct Namespace {
|
|
||||||
/// Mapping from identifiers to indices in `self.instances`.
|
|
||||||
names: HashMap<String, InstanceHandle>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Namespace {
|
|
||||||
/// Construct a new `Namespace`.
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
names: HashMap::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Install a new `InstanceHandle` in this `Namespace`, optionally with the
|
|
||||||
/// given name.
|
|
||||||
pub fn name_instance(&mut self, name: String, instance: InstanceHandle) {
|
|
||||||
self.names.insert(name, instance);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the instance registered with the given `instance_name`.
|
|
||||||
pub fn get_instance(&mut self, name: &str) -> Option<&mut InstanceHandle> {
|
|
||||||
self.names.get_mut(name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Resolver for Namespace {
|
|
||||||
fn resolve(&mut self, _idx: u32, name: &str, field: &str) -> Option<Export> {
|
|
||||||
if let Some(instance) = self.names.get_mut(name) {
|
|
||||||
instance.lookup(field)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user