From 98020050612e812030e6ce3ebe9b984580e54723 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 7 Feb 2020 13:22:07 -0600 Subject: [PATCH] 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 --- crates/api/src/module.rs | 13 +- crates/api/src/runtime.rs | 38 ++-- crates/api/src/values.rs | 13 -- crates/interface-types/src/lib.rs | 64 +++---- crates/jit/src/action.rs | 295 ------------------------------ crates/jit/src/context.rs | 222 ---------------------- crates/jit/src/lib.rs | 6 - crates/jit/src/namespace.rs | 46 ----- 8 files changed, 55 insertions(+), 642 deletions(-) delete mode 100644 crates/jit/src/action.rs delete mode 100644 crates/jit/src/context.rs delete mode 100644 crates/jit/src/namespace.rs diff --git a/crates/api/src/module.rs b/crates/api/src/module.rs index 7719600907..c8f159e551 100644 --- a/crates/api/src/module.rs +++ b/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) } diff --git a/crates/api/src/runtime.rs b/crates/api/src/runtime.rs index 89a4b2bf2b..7054918079 100644 --- a/crates/api/src/runtime.rs +++ b/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(), diff --git a/crates/api/src/values.rs b/crates/api/src/values.rs index b61f11124f..de071d312b 100644 --- a/crates/api/src/values.rs +++ b/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 for Val { } } -impl From 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, diff --git a/crates/interface-types/src/lib.rs b/crates/interface-types/src/lib.rs index e730696c78..4e650b13c0 100644 --- a/crates/interface-types/src/lib.rs +++ b/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::>(); - 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::>(); + 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> { +) -> Result> { 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> { 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] }; diff --git a/crates/jit/src/action.rs b/crates/jit/src/action.rs deleted file mode 100644 index 6d9b9b9bb4..0000000000 --- a/crates/jit/src/action.rs +++ /dev/null @@ -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, - }, - - /// 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 { - 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::(); - let mut values_vec: Vec = - 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 { - 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 - ))); - } - }) - } -} diff --git a/crates/jit/src/context.rs b/crates/jit/src/context.rs deleted file mode 100644 index 1d3edec1e1..0000000000 --- a/crates/jit/src/context.rs +++ /dev/null @@ -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 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, - debug_info: bool, - features: Features, -} - -impl Context { - /// Construct a new instance of `Context`. - pub fn new(compiler: Box) -> 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 { - 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, - data: &[u8], - ) -> Result { - 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 { - 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, 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 { - 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 { - 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 { - 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 { - 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) - } -} diff --git a/crates/jit/src/lib.rs b/crates/jit/src/lib.rs index 30cf311991..3d7bba2785 100644 --- a/crates/jit/src/lib.rs +++ b/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; diff --git a/crates/jit/src/namespace.rs b/crates/jit/src/namespace.rs deleted file mode 100644 index a8f5449c6f..0000000000 --- a/crates/jit/src/namespace.rs +++ /dev/null @@ -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, -} - -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 { - if let Some(instance) = self.names.get_mut(name) { - instance.lookup(field) - } else { - None - } - } -}