Browse Source

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
pull/930/head
Alex Crichton 5 years ago
committed by GitHub
parent
commit
9802005061
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 13
      crates/api/src/module.rs
  2. 38
      crates/api/src/runtime.rs
  3. 13
      crates/api/src/values.rs
  4. 64
      crates/interface-types/src/lib.rs
  5. 295
      crates/jit/src/action.rs
  6. 222
      crates/jit/src/context.rs
  7. 6
      crates/jit/src/lib.rs
  8. 46
      crates/jit/src/namespace.rs

13
crates/api/src/module.rs

@ -9,7 +9,7 @@ use std::path::Path;
use std::sync::{Arc, Mutex};
use wasmparser::{
validate, CustomSectionKind, ExternalKind, ImportSectionEntryType, ModuleReader, Name,
OperatorValidatorConfig, SectionCode, ValidatingParserConfig,
SectionCode,
};
use wasmtime_jit::CompiledModule;
@ -244,16 +244,7 @@ impl Module {
///
/// [binary]: https://webassembly.github.io/spec/core/binary/index.html
pub fn validate(store: &Store, binary: &[u8]) -> Result<()> {
let features = store.engine().config().features.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,
},
};
let config = store.engine().config().validating_config.clone();
validate(binary, Some(config)).map_err(Error::new)
}

38
crates/api/src/runtime.rs

@ -4,9 +4,10 @@ use std::fmt;
use std::path::Path;
use std::rc::Rc;
use std::sync::Arc;
use wasmparser::{OperatorValidatorConfig, ValidatingParserConfig};
use wasmtime_environ::settings::{self, Configurable};
use wasmtime_environ::CacheConfig;
use wasmtime_jit::{native, CompilationStrategy, Compiler, Features};
use wasmtime_jit::{native, CompilationStrategy, Compiler};
// Runtime Environment
@ -20,7 +21,7 @@ use wasmtime_jit::{native, CompilationStrategy, Compiler, Features};
#[derive(Clone)]
pub struct Config {
pub(crate) flags: settings::Builder,
pub(crate) features: Features,
pub(crate) validating_config: ValidatingParserConfig,
pub(crate) debug_info: bool,
pub(crate) strategy: CompilationStrategy,
pub(crate) cache_config: CacheConfig,
@ -45,7 +46,15 @@ impl Config {
Config {
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,
strategy: CompilationStrategy::Auto,
cache_config: CacheConfig::new_cache_disabled(),
@ -77,10 +86,10 @@ impl Config {
///
/// [threads]: https://github.com/webassembly/threads
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
if enable {
self.features.bulk_memory = true;
self.wasm_bulk_memory(true);
}
self
}
@ -102,10 +111,12 @@ impl Config {
///
/// [proposal]: https://github.com/webassembly/reference-types
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
if enable {
self.features.bulk_memory = true;
self.wasm_bulk_memory(true);
}
self
}
@ -126,7 +137,7 @@ impl Config {
///
/// [proposal]: https://github.com/webassembly/simd
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" };
self.flags
.set("enable_simd", val)
@ -150,7 +161,7 @@ impl Config {
///
/// [proposal]: https://github.com/webassembly/bulk-memory-operations
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
}
@ -170,7 +181,7 @@ impl Config {
///
/// [proposal]: https://github.com/webassembly/multi-value
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
}
@ -288,10 +299,15 @@ impl Default for Config {
impl fmt::Debug for Config {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let features = &self.validating_config.operator_config;
f.debug_struct("Config")
.field("debug_info", &self.debug_info)
.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(
"flags",
&settings::Flags::new(self.flags.clone()).to_string(),

13
crates/api/src/values.rs

@ -3,7 +3,6 @@ use crate::{Func, Store, ValType};
use anyhow::{bail, Result};
use std::ptr;
use wasmtime_environ::ir;
use wasmtime_jit::RuntimeValue;
/// Possible runtime values that a WebAssembly module can either consume or
/// 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(
val: Val,
store: &Store,

64
crates/interface-types/src/lib.rs

@ -11,8 +11,8 @@ use anyhow::{bail, format_err, Result};
use std::convert::TryFrom;
use std::str;
use wasm_webidl_bindings::ast;
use wasmtime::Val;
use wasmtime_environ::ir;
use wasmtime_jit::RuntimeValue;
use wasmtime_runtime::{Export, InstanceHandle};
mod value;
@ -147,19 +147,7 @@ impl ModuleData {
.into_iter()
.map(|rv| rv.into())
.collect::<Vec<_>>();
let wasm_results = f
.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>>();
let wasm_results = f.call(&wasm_args)?;
translate_outgoing(&mut cx, &outgoing, &wasm_results)
}
@ -358,7 +346,7 @@ fn translate_incoming(
cx: &mut dyn TranslateContext,
bindings: &[ast::IncomingBindingExpression],
args: &[Value],
) -> Result<Vec<RuntimeValue>> {
) -> Result<Vec<Val>> {
let get = |expr: &ast::IncomingBindingExpression| match expr {
ast::IncomingBindingExpression::Get(g) => args
.get(g.idx as usize)
@ -387,31 +375,31 @@ fn translate_incoming(
_ => bail!("expected a string"),
};
let (ptr, len) = copy(&g.alloc_func_name, val.as_bytes())?;
wasm.push(RuntimeValue::I32(ptr));
wasm.push(RuntimeValue::I32(len));
wasm.push(Val::I32(ptr));
wasm.push(Val::I32(len));
}
ast::IncomingBindingExpression::As(g) => {
let val = get(&g.expr)?;
match g.ty {
walrus::ValType::I32 => match val {
Value::I32(i) => wasm.push(RuntimeValue::I32(*i)),
Value::U32(i) => wasm.push(RuntimeValue::I32(*i as i32)),
Value::I32(i) => wasm.push(Val::I32(*i)),
Value::U32(i) => wasm.push(Val::I32(*i as i32)),
_ => bail!("cannot convert {:?} to `i32`", val),
},
walrus::ValType::I64 => match val {
Value::I32(i) => wasm.push(RuntimeValue::I64((*i).into())),
Value::U32(i) => wasm.push(RuntimeValue::I64((*i).into())),
Value::I64(i) => wasm.push(RuntimeValue::I64(*i)),
Value::U64(i) => wasm.push(RuntimeValue::I64(*i as i64)),
Value::I32(i) => wasm.push(Val::I64((*i).into())),
Value::U32(i) => wasm.push(Val::I64((*i).into())),
Value::I64(i) => wasm.push(Val::I64(*i)),
Value::U64(i) => wasm.push(Val::I64(*i as i64)),
_ => bail!("cannot convert {:?} to `i64`", 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),
},
walrus::ValType::F64 => match val {
Value::F32(i) => wasm.push(RuntimeValue::F64((*i as f64).to_bits())),
Value::F64(i) => wasm.push(RuntimeValue::F64(i.to_bits())),
Value::F32(i) => wasm.push(Val::F64((*i as f64).to_bits())),
Value::F64(i) => wasm.push(Val::F64(i.to_bits())),
_ => bail!("cannot convert {:?} to `f64`", val),
},
walrus::ValType::V128 | walrus::ValType::Anyref => {
@ -429,7 +417,7 @@ fn translate_incoming(
fn translate_outgoing(
cx: &mut dyn TranslateContext,
bindings: &[ast::OutgoingBindingExpression],
args: &[RuntimeValue],
args: &[Val],
) -> Result<Vec<Value>> {
let mut values = Vec::new();
@ -445,32 +433,32 @@ fn translate_outgoing(
let arg = get(a.idx)?;
match a.ty {
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),
},
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),
},
ast::WebidlTypeRef::Scalar(ast::WebidlScalarType::LongLong) => match arg {
RuntimeValue::I32(a) => values.push(Value::I64(a as i64)),
RuntimeValue::I64(a) => values.push(Value::I64(a)),
Val::I32(a) => values.push(Value::I64(a as i64)),
Val::I64(a) => values.push(Value::I64(a)),
_ => bail!("can't convert {:?} to long long", arg),
},
ast::WebidlTypeRef::Scalar(ast::WebidlScalarType::UnsignedLongLong) => {
match arg {
RuntimeValue::I32(a) => values.push(Value::U64(a as u64)),
RuntimeValue::I64(a) => values.push(Value::U64(a as u64)),
Val::I32(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),
}
}
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),
},
ast::WebidlTypeRef::Scalar(ast::WebidlScalarType::Double) => match arg {
RuntimeValue::F32(a) => values.push(Value::F64(f32::from_bits(a) as f64)),
RuntimeValue::F64(a) => values.push(Value::F64(f64::from_bits(a))),
Val::F32(a) => values.push(Value::F64(f32::from_bits(a) as f64)),
Val::F64(a) => values.push(Value::F64(f64::from_bits(a))),
_ => bail!("can't convert {:?} to double", arg),
},
_ => bail!("unsupported outgoing binding expr {:?}", expr),
@ -481,11 +469,11 @@ fn translate_outgoing(
bail!("utf-8 strings must go into dom-string")
}
let offset = match get(e.offset)? {
RuntimeValue::I32(a) => a,
Val::I32(a) => a,
_ => bail!("offset must be an i32"),
};
let length = match get(e.length)? {
RuntimeValue::I32(a) => a,
Val::I32(a) => a,
_ => bail!("length must be an i32"),
};
let bytes = unsafe { &cx.get_memory()?[offset as usize..][..length as usize] };

295
crates/jit/src/action.rs

@ -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
)));
}
})
}
}

222
crates/jit/src/context.rs

@ -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)
}
}

6
crates/jit/src/lib.rs

@ -21,28 +21,22 @@
)
)]
mod action;
mod code_memory;
mod compiler;
mod context;
mod function_table;
mod imports;
mod instantiate;
mod link;
mod namespace;
mod resolver;
mod target_tunables;
pub mod native;
pub mod trampoline;
pub use crate::action::{invoke, ActionError, ActionOutcome, RuntimeValue};
pub use crate::code_memory::CodeMemory;
pub use crate::compiler::{CompilationStrategy, Compiler};
pub use crate::context::{Context, ContextError, Features, UnknownInstance};
pub use crate::instantiate::{instantiate, CompiledModule, SetupError};
pub use crate::link::link_module;
pub use crate::namespace::Namespace;
pub use crate::resolver::{NullResolver, Resolver};
pub use crate::target_tunables::target_tunables;

46
crates/jit/src/namespace.rs

@ -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
}
}
}
Loading…
Cancel
Save