Factor WasmNamespace out of lib/wast and into lib/execute as Namespace.
This makes it usable for things other than just wast tests.
This commit is contained in:
@@ -25,6 +25,7 @@
|
|||||||
#![cfg_attr(not(feature = "std"), feature(alloc))]
|
#![cfg_attr(not(feature = "std"), feature(alloc))]
|
||||||
|
|
||||||
extern crate cranelift_codegen;
|
extern crate cranelift_codegen;
|
||||||
|
#[macro_use]
|
||||||
extern crate cranelift_entity;
|
extern crate cranelift_entity;
|
||||||
extern crate cranelift_frontend;
|
extern crate cranelift_frontend;
|
||||||
extern crate cranelift_wasm;
|
extern crate cranelift_wasm;
|
||||||
@@ -43,6 +44,7 @@ mod action;
|
|||||||
mod instance_plus;
|
mod instance_plus;
|
||||||
mod jit_code;
|
mod jit_code;
|
||||||
mod link;
|
mod link;
|
||||||
|
mod namespace;
|
||||||
mod resolver;
|
mod resolver;
|
||||||
mod target_tunables;
|
mod target_tunables;
|
||||||
mod trampoline_park;
|
mod trampoline_park;
|
||||||
@@ -51,6 +53,7 @@ pub use action::{ActionError, ActionOutcome, RuntimeValue};
|
|||||||
pub use instance_plus::InstancePlus;
|
pub use instance_plus::InstancePlus;
|
||||||
pub use jit_code::JITCode;
|
pub use jit_code::JITCode;
|
||||||
pub use link::link_module;
|
pub use link::link_module;
|
||||||
|
pub use namespace::{InstancePlusIndex, Namespace};
|
||||||
pub use resolver::{NullResolver, Resolver};
|
pub use resolver::{NullResolver, Resolver};
|
||||||
pub use target_tunables::target_tunables;
|
pub use target_tunables::target_tunables;
|
||||||
|
|
||||||
|
|||||||
94
lib/execute/src/namespace.rs
Normal file
94
lib/execute/src/namespace.rs
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
//! 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 action::{ActionError, ActionOutcome, RuntimeValue};
|
||||||
|
use cranelift_codegen::isa;
|
||||||
|
use cranelift_entity::PrimaryMap;
|
||||||
|
use instance_plus::InstancePlus;
|
||||||
|
use jit_code::JITCode;
|
||||||
|
use resolver::Resolver;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use wasmtime_runtime::Export;
|
||||||
|
|
||||||
|
/// An opaque reference to an `InstancePlus`.
|
||||||
|
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||||
|
pub struct InstancePlusIndex(u32);
|
||||||
|
entity_impl!(InstancePlusIndex, "instance");
|
||||||
|
|
||||||
|
/// 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, InstancePlusIndex>,
|
||||||
|
|
||||||
|
/// The instances, available by index.
|
||||||
|
instances: PrimaryMap<InstancePlusIndex, InstancePlus>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Namespace {
|
||||||
|
/// Construct a new `Namespace`.
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
names: HashMap::new(),
|
||||||
|
instances: PrimaryMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Install a new `InstancePlus` in this `Namespace`, optionally with the
|
||||||
|
/// given name, and return its index.
|
||||||
|
pub fn instance(
|
||||||
|
&mut self,
|
||||||
|
instance_name: Option<&str>,
|
||||||
|
instance: InstancePlus,
|
||||||
|
) -> InstancePlusIndex {
|
||||||
|
let index = self.instances.push(instance);
|
||||||
|
if let Some(instance_name) = instance_name {
|
||||||
|
self.names.insert(instance_name.into(), index);
|
||||||
|
}
|
||||||
|
index
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the instance index registered with the given `instance_name`.
|
||||||
|
pub fn get_instance_index(&mut self, instance_name: &str) -> Option<&mut InstancePlusIndex> {
|
||||||
|
self.names.get_mut(instance_name)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Register an instance with a given name.
|
||||||
|
pub fn register(&mut self, name: String, index: InstancePlusIndex) {
|
||||||
|
self.names.insert(name, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Invoke an exported function from an instance.
|
||||||
|
pub fn invoke(
|
||||||
|
&mut self,
|
||||||
|
jit_code: &mut JITCode,
|
||||||
|
isa: &isa::TargetIsa,
|
||||||
|
index: InstancePlusIndex,
|
||||||
|
field_name: &str,
|
||||||
|
args: &[RuntimeValue],
|
||||||
|
) -> Result<ActionOutcome, ActionError> {
|
||||||
|
self.instances[index].invoke(jit_code, isa, &field_name, &args)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the value of an exported global from an instance.
|
||||||
|
pub fn get(
|
||||||
|
&mut self,
|
||||||
|
index: InstancePlusIndex,
|
||||||
|
field_name: &str,
|
||||||
|
) -> Result<RuntimeValue, ActionError> {
|
||||||
|
self.instances[index].get(&field_name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Resolver for Namespace {
|
||||||
|
fn resolve(&mut self, instance: &str, field: &str) -> Option<Export> {
|
||||||
|
if let Some(index) = self.names.get(instance) {
|
||||||
|
self.instances[*index].instance.lookup(field)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -23,9 +23,8 @@
|
|||||||
)]
|
)]
|
||||||
|
|
||||||
extern crate cranelift_codegen;
|
extern crate cranelift_codegen;
|
||||||
extern crate cranelift_wasm;
|
|
||||||
#[macro_use]
|
|
||||||
extern crate cranelift_entity;
|
extern crate cranelift_entity;
|
||||||
|
extern crate cranelift_wasm;
|
||||||
extern crate failure;
|
extern crate failure;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate failure_derive;
|
extern crate failure_derive;
|
||||||
@@ -39,4 +38,5 @@ extern crate wasmtime_runtime;
|
|||||||
mod spectest;
|
mod spectest;
|
||||||
mod wast;
|
mod wast;
|
||||||
|
|
||||||
|
pub use spectest::instantiate_spectest;
|
||||||
pub use wast::{WastContext, WastError};
|
pub use wast::{WastContext, WastError};
|
||||||
|
|||||||
@@ -1,14 +1,13 @@
|
|||||||
use cranelift_codegen::isa;
|
use cranelift_codegen::isa;
|
||||||
use cranelift_entity::PrimaryMap;
|
|
||||||
use spectest::instantiate_spectest;
|
use spectest::instantiate_spectest;
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::{fmt, fs, io, str};
|
use std::{fmt, fs, io, str};
|
||||||
use wabt::script::{Action, Command, CommandKind, ModuleBinary, ScriptParser, Value};
|
use wabt::script::{Action, Command, CommandKind, ModuleBinary, ScriptParser, Value};
|
||||||
use wasmparser::{validate, OperatorValidatorConfig, ValidatingParserConfig};
|
use wasmparser::{validate, OperatorValidatorConfig, ValidatingParserConfig};
|
||||||
use wasmtime_execute::{ActionError, ActionOutcome, InstancePlus, JITCode, Resolver, RuntimeValue};
|
use wasmtime_execute::{
|
||||||
use wasmtime_runtime::Export;
|
ActionError, ActionOutcome, InstancePlus, InstancePlusIndex, JITCode, Namespace, RuntimeValue,
|
||||||
|
};
|
||||||
|
|
||||||
/// Translate from a script::Value to a RuntimeValue.
|
/// Translate from a script::Value to a RuntimeValue.
|
||||||
fn runtime_value(v: Value) -> RuntimeValue {
|
fn runtime_value(v: Value) -> RuntimeValue {
|
||||||
@@ -20,17 +19,17 @@ fn runtime_value(v: Value) -> RuntimeValue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Indicates an unknown module was specified.
|
/// Indicates an unknown instance was specified.
|
||||||
#[derive(Fail, Debug)]
|
#[derive(Fail, Debug)]
|
||||||
pub struct UnknownModule {
|
pub struct UnknownInstance {
|
||||||
module: Option<String>,
|
instance: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for UnknownModule {
|
impl fmt::Display for UnknownInstance {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match self.module {
|
match self.instance {
|
||||||
None => write!(f, "no default module present"),
|
None => write!(f, "no default instance present"),
|
||||||
Some(ref name) => write!(f, "no module {} present", name),
|
Some(ref name) => write!(f, "no instance {} present", name),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -40,8 +39,8 @@ impl fmt::Display for UnknownModule {
|
|||||||
pub enum WastError {
|
pub enum WastError {
|
||||||
/// An assert command was not satisfied.
|
/// An assert command was not satisfied.
|
||||||
Assert(String),
|
Assert(String),
|
||||||
/// An unknown module name was used.
|
/// An unknown instance name was used.
|
||||||
Module(UnknownModule),
|
Instance(UnknownInstance),
|
||||||
/// An error occured while performing an action.
|
/// An error occured while performing an action.
|
||||||
Action(ActionError),
|
Action(ActionError),
|
||||||
/// An action trapped.
|
/// An action trapped.
|
||||||
@@ -56,7 +55,7 @@ impl fmt::Display for WastError {
|
|||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match *self {
|
match *self {
|
||||||
WastError::Assert(ref message) => write!(f, "Assert command failed: {}", message),
|
WastError::Assert(ref message) => write!(f, "Assert command failed: {}", message),
|
||||||
WastError::Module(ref error) => error.fmt(f),
|
WastError::Instance(ref error) => error.fmt(f),
|
||||||
WastError::Action(ref error) => error.fmt(f),
|
WastError::Action(ref error) => error.fmt(f),
|
||||||
WastError::Trap(ref message) => write!(f, "trap: {}", message),
|
WastError::Trap(ref message) => write!(f, "trap: {}", message),
|
||||||
WastError::Type(ref message) => write!(f, "type error: {}", message),
|
WastError::Type(ref message) => write!(f, "type error: {}", message),
|
||||||
@@ -74,41 +73,12 @@ pub struct WastFileError {
|
|||||||
error: WastError,
|
error: WastError,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An opaque reference to an `InstancePlus`.
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
|
||||||
pub struct InstancePlusIndex(u32);
|
|
||||||
entity_impl!(InstancePlusIndex, "instance");
|
|
||||||
|
|
||||||
struct WasmNamespace {
|
|
||||||
names: HashMap<String, InstancePlusIndex>,
|
|
||||||
instances: PrimaryMap<InstancePlusIndex, InstancePlus>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WasmNamespace {
|
|
||||||
fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
names: HashMap::new(),
|
|
||||||
instances: PrimaryMap::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Resolver for WasmNamespace {
|
|
||||||
fn resolve(&mut self, module: &str, field: &str) -> Option<Export> {
|
|
||||||
if let Some(index) = self.names.get(module) {
|
|
||||||
self.instances[*index].instance.lookup(field)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The wast test script language allows modules to be defined and actions
|
/// The wast test script language allows modules to be defined and actions
|
||||||
/// to be performed on them.
|
/// to be performed on them.
|
||||||
pub struct WastContext {
|
pub struct WastContext {
|
||||||
/// A namespace of wasm modules, keyed by an optional name.
|
/// A namespace of wasm modules, keyed by an optional name.
|
||||||
current: Option<InstancePlusIndex>,
|
current: Option<InstancePlusIndex>,
|
||||||
namespace: WasmNamespace,
|
namespace: Namespace,
|
||||||
jit_code: JITCode,
|
jit_code: JITCode,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,7 +87,7 @@ impl WastContext {
|
|||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
current: None,
|
current: None,
|
||||||
namespace: WasmNamespace::new(),
|
namespace: Namespace::new(),
|
||||||
jit_code: JITCode::new(),
|
jit_code: JITCode::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -153,17 +123,22 @@ impl WastContext {
|
|||||||
InstancePlus::new(&mut self.jit_code, isa, &data, &mut self.namespace)
|
InstancePlus::new(&mut self.jit_code, isa, &data, &mut self.namespace)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_instance(&mut self, module: &Option<String>) -> Result<InstancePlusIndex, WastError> {
|
fn get_index(
|
||||||
let index = *if let Some(name) = module {
|
&mut self,
|
||||||
self.namespace.names.get_mut(name).ok_or_else(|| {
|
instance_name: &Option<String>,
|
||||||
WastError::Module(UnknownModule {
|
) -> Result<InstancePlusIndex, WastError> {
|
||||||
module: Some(name.to_owned()),
|
let index = *if let Some(instance_name) = instance_name {
|
||||||
|
self.namespace
|
||||||
|
.get_instance_index(instance_name)
|
||||||
|
.ok_or_else(|| {
|
||||||
|
WastError::Instance(UnknownInstance {
|
||||||
|
instance: Some(instance_name.to_string()),
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
|
||||||
} else {
|
} else {
|
||||||
self.current
|
self.current
|
||||||
.as_mut()
|
.as_mut()
|
||||||
.ok_or_else(|| WastError::Module(UnknownModule { module: None }))
|
.ok_or_else(|| WastError::Instance(UnknownInstance { instance: None }))
|
||||||
}?;
|
}?;
|
||||||
|
|
||||||
Ok(index)
|
Ok(index)
|
||||||
@@ -172,58 +147,11 @@ impl WastContext {
|
|||||||
/// Register "spectest" which is used by the spec testsuite.
|
/// Register "spectest" which is used by the spec testsuite.
|
||||||
pub fn register_spectest(&mut self) -> Result<(), ActionError> {
|
pub fn register_spectest(&mut self) -> Result<(), ActionError> {
|
||||||
let instance = instantiate_spectest()?;
|
let instance = instantiate_spectest()?;
|
||||||
let index = self.namespace.instances.push(instance);
|
self.namespace.instance(Some("spectest"), instance);
|
||||||
self.register("spectest".to_owned(), index);
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Define a module and register it.
|
/// Perform the action portion of a command.
|
||||||
pub fn module(
|
|
||||||
&mut self,
|
|
||||||
isa: &isa::TargetIsa,
|
|
||||||
name: Option<String>,
|
|
||||||
module: ModuleBinary,
|
|
||||||
) -> Result<(), ActionError> {
|
|
||||||
let instance = self.instantiate(isa, module)?;
|
|
||||||
let index = self.namespace.instances.push(instance);
|
|
||||||
if let Some(name) = name {
|
|
||||||
self.register(name, index);
|
|
||||||
}
|
|
||||||
self.current = Some(index);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Register a module to make it available for performing actions.
|
|
||||||
pub fn register(&mut self, name: String, index: InstancePlusIndex) {
|
|
||||||
self.namespace.names.insert(name, index);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Invoke an exported function from a defined module.
|
|
||||||
pub fn invoke(
|
|
||||||
&mut self,
|
|
||||||
isa: &isa::TargetIsa,
|
|
||||||
module: Option<String>,
|
|
||||||
field: &str,
|
|
||||||
args: &[Value],
|
|
||||||
) -> Result<ActionOutcome, WastError> {
|
|
||||||
let mut value_args = Vec::with_capacity(args.len());
|
|
||||||
for arg in args {
|
|
||||||
value_args.push(runtime_value(*arg));
|
|
||||||
}
|
|
||||||
let index = self.get_instance(&module)?;
|
|
||||||
self.namespace.instances[index]
|
|
||||||
.invoke(&mut self.jit_code, isa, &field, &value_args)
|
|
||||||
.map_err(WastError::Action)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the value of an exported global from a defined module.
|
|
||||||
pub fn get(&mut self, module: Option<String>, field: &str) -> Result<RuntimeValue, WastError> {
|
|
||||||
let index = self.get_instance(&module)?;
|
|
||||||
self.namespace.instances[index]
|
|
||||||
.get(&field)
|
|
||||||
.map_err(WastError::Action)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn perform_action(
|
fn perform_action(
|
||||||
&mut self,
|
&mut self,
|
||||||
isa: &isa::TargetIsa,
|
isa: &isa::TargetIsa,
|
||||||
@@ -231,16 +159,82 @@ impl WastContext {
|
|||||||
) -> Result<ActionOutcome, WastError> {
|
) -> Result<ActionOutcome, WastError> {
|
||||||
match action {
|
match action {
|
||||||
Action::Invoke {
|
Action::Invoke {
|
||||||
module,
|
module: instance_name,
|
||||||
field,
|
field,
|
||||||
args,
|
args,
|
||||||
} => self.invoke(isa, module, &field, &args),
|
} => self.invoke(isa, instance_name, &field, &args),
|
||||||
Action::Get { module, field } => {
|
Action::Get {
|
||||||
let value = self.get(module, &field)?;
|
module: instance_name,
|
||||||
Ok(ActionOutcome::Returned {
|
field,
|
||||||
values: vec![value],
|
} => self.get(instance_name, &field),
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Define a module and register it.
|
||||||
|
fn module(
|
||||||
|
&mut self,
|
||||||
|
isa: &isa::TargetIsa,
|
||||||
|
instance_name: Option<String>,
|
||||||
|
module: ModuleBinary,
|
||||||
|
) -> Result<(), ActionError> {
|
||||||
|
let instance = self.instantiate(isa, module)?;
|
||||||
|
let index = self
|
||||||
|
.namespace
|
||||||
|
.instance(instance_name.as_ref().map(String::as_str), instance);
|
||||||
|
self.current = Some(index);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Register an instance to make it available for performing actions.
|
||||||
|
fn register(&mut self, name: Option<String>, as_name: String) -> Result<(), WastError> {
|
||||||
|
let index = self.get_index(&name)?;
|
||||||
|
self.namespace.register(as_name, index);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Invoke an exported function from an instance.
|
||||||
|
fn invoke(
|
||||||
|
&mut self,
|
||||||
|
isa: &isa::TargetIsa,
|
||||||
|
instance_name: Option<String>,
|
||||||
|
field: &str,
|
||||||
|
args: &[Value],
|
||||||
|
) -> Result<ActionOutcome, WastError> {
|
||||||
|
let value_args = args
|
||||||
|
.iter()
|
||||||
|
.map(|arg| runtime_value(*arg))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
let index = self.get_index(&instance_name)?;
|
||||||
|
self.namespace
|
||||||
|
.invoke(&mut self.jit_code, isa, index, &field, &value_args)
|
||||||
|
.map_err(WastError::Action)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the value of an exported global from an instance.
|
||||||
|
fn get(
|
||||||
|
&mut self,
|
||||||
|
instance_name: Option<String>,
|
||||||
|
field: &str,
|
||||||
|
) -> Result<ActionOutcome, WastError> {
|
||||||
|
let index = self.get_index(&instance_name)?;
|
||||||
|
let value = self
|
||||||
|
.namespace
|
||||||
|
.get(index, field)
|
||||||
|
.map_err(WastError::Action)?;
|
||||||
|
Ok(ActionOutcome::Returned {
|
||||||
|
values: vec![value],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Perform the action of a `PerformAction`.
|
||||||
|
fn perform_action_command(
|
||||||
|
&mut self,
|
||||||
|
isa: &isa::TargetIsa,
|
||||||
|
action: Action,
|
||||||
|
) -> Result<(), WastError> {
|
||||||
|
match self.perform_action(isa, action)? {
|
||||||
|
ActionOutcome::Returned { .. } => Ok(()),
|
||||||
|
ActionOutcome::Trapped { message } => Err(WastError::Trap(message)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -255,8 +249,11 @@ impl WastContext {
|
|||||||
|
|
||||||
while let Some(Command { kind, line }) = parser.next().expect("parser") {
|
while let Some(Command { kind, line }) = parser.next().expect("parser") {
|
||||||
match kind {
|
match kind {
|
||||||
CommandKind::Module { module, name } => {
|
CommandKind::Module {
|
||||||
self.module(isa, name, module)
|
module: instance_name,
|
||||||
|
name,
|
||||||
|
} => {
|
||||||
|
self.module(isa, name, instance_name)
|
||||||
.map_err(|error| WastFileError {
|
.map_err(|error| WastFileError {
|
||||||
filename: filename.to_string(),
|
filename: filename.to_string(),
|
||||||
line,
|
line,
|
||||||
@@ -264,29 +261,21 @@ impl WastContext {
|
|||||||
})?;
|
})?;
|
||||||
}
|
}
|
||||||
CommandKind::Register { name, as_name } => {
|
CommandKind::Register { name, as_name } => {
|
||||||
let index = self.get_instance(&name).map_err(|error| WastFileError {
|
self.register(name, as_name)
|
||||||
filename: filename.to_string(),
|
.map_err(|error| WastFileError {
|
||||||
line,
|
|
||||||
error,
|
|
||||||
})?;
|
|
||||||
self.register(as_name, index);
|
|
||||||
}
|
|
||||||
CommandKind::PerformAction(action) => match self
|
|
||||||
.perform_action(isa, action)
|
|
||||||
.map_err(|error| WastFileError {
|
|
||||||
filename: filename.to_string(),
|
|
||||||
line,
|
|
||||||
error,
|
|
||||||
})? {
|
|
||||||
ActionOutcome::Returned { .. } => {}
|
|
||||||
ActionOutcome::Trapped { message } => {
|
|
||||||
return Err(WastFileError {
|
|
||||||
filename: filename.to_string(),
|
filename: filename.to_string(),
|
||||||
line,
|
line,
|
||||||
error: WastError::Trap(message),
|
error,
|
||||||
});
|
})?;
|
||||||
}
|
}
|
||||||
},
|
CommandKind::PerformAction(action) => {
|
||||||
|
self.perform_action_command(isa, action)
|
||||||
|
.map_err(|error| WastFileError {
|
||||||
|
filename: filename.to_string(),
|
||||||
|
line,
|
||||||
|
error,
|
||||||
|
})?;
|
||||||
|
}
|
||||||
CommandKind::AssertReturn { action, expected } => {
|
CommandKind::AssertReturn { action, expected } => {
|
||||||
match self
|
match self
|
||||||
.perform_action(isa, action)
|
.perform_action(isa, action)
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ extern crate cranelift_codegen;
|
|||||||
extern crate cranelift_native;
|
extern crate cranelift_native;
|
||||||
extern crate docopt;
|
extern crate docopt;
|
||||||
extern crate wasmtime_execute;
|
extern crate wasmtime_execute;
|
||||||
|
extern crate wasmtime_wast;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate serde_derive;
|
extern crate serde_derive;
|
||||||
extern crate file_per_thread_logger;
|
extern crate file_per_thread_logger;
|
||||||
@@ -51,7 +52,8 @@ use std::io::prelude::*;
|
|||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::process::exit;
|
use std::process::exit;
|
||||||
use wasmtime_execute::{ActionOutcome, InstancePlus, JITCode, NullResolver};
|
use wasmtime_execute::{ActionOutcome, InstancePlus, JITCode, Namespace};
|
||||||
|
use wasmtime_wast::instantiate_spectest;
|
||||||
|
|
||||||
static LOG_FILENAME_PREFIX: &str = "cranelift.dbg.";
|
static LOG_FILENAME_PREFIX: &str = "cranelift.dbg.";
|
||||||
|
|
||||||
@@ -122,9 +124,19 @@ fn main() {
|
|||||||
|
|
||||||
let isa = isa_builder.finish(settings::Flags::new(flag_builder));
|
let isa = isa_builder.finish(settings::Flags::new(flag_builder));
|
||||||
|
|
||||||
|
let mut namespace = Namespace::new();
|
||||||
|
|
||||||
|
// Make spectest available by default.
|
||||||
|
namespace.instance(
|
||||||
|
Some("spectest"),
|
||||||
|
instantiate_spectest().expect("instantiating spectest"),
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut jit_code = JITCode::new();
|
||||||
|
|
||||||
for filename in &args.arg_file {
|
for filename in &args.arg_file {
|
||||||
let path = Path::new(&filename);
|
let path = Path::new(&filename);
|
||||||
match handle_module(&args, path, &*isa) {
|
match handle_module(&mut jit_code, &mut namespace, &args, path, &*isa) {
|
||||||
Ok(()) => {}
|
Ok(()) => {}
|
||||||
Err(message) => {
|
Err(message) => {
|
||||||
let name = path.as_os_str().to_string_lossy();
|
let name = path.as_os_str().to_string_lossy();
|
||||||
@@ -135,21 +147,32 @@ fn main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_module(args: &Args, path: &Path, isa: &TargetIsa) -> Result<(), String> {
|
fn handle_module(
|
||||||
|
jit_code: &mut JITCode,
|
||||||
|
namespace: &mut Namespace,
|
||||||
|
args: &Args,
|
||||||
|
path: &Path,
|
||||||
|
isa: &TargetIsa,
|
||||||
|
) -> Result<(), String> {
|
||||||
let mut data =
|
let mut data =
|
||||||
read_to_end(path.to_path_buf()).map_err(|err| String::from(err.description()))?;
|
read_to_end(path.to_path_buf()).map_err(|err| String::from(err.description()))?;
|
||||||
// if data is using wat-format, first convert data to wasm
|
|
||||||
|
// If data is using wat-format, first convert data to wasm.
|
||||||
if !data.starts_with(&[b'\0', b'a', b's', b'm']) {
|
if !data.starts_with(&[b'\0', b'a', b's', b'm']) {
|
||||||
data = wabt::wat2wasm(data).map_err(|err| String::from(err.description()))?;
|
data = wabt::wat2wasm(data).map_err(|err| String::from(err.description()))?;
|
||||||
}
|
}
|
||||||
let mut resolver = NullResolver {};
|
|
||||||
let mut jit_code = JITCode::new();
|
|
||||||
let mut instance_plus =
|
|
||||||
InstancePlus::new(&mut jit_code, isa, &data, &mut resolver).map_err(|e| e.to_string())?;
|
|
||||||
|
|
||||||
|
// Create a new `InstancePlus` by compiling and instantiating a wasm module.
|
||||||
|
let instance_plus =
|
||||||
|
InstancePlus::new(jit_code, isa, &data, namespace).map_err(|e| e.to_string())?;
|
||||||
|
|
||||||
|
// Register it in the namespace.
|
||||||
|
let index = namespace.instance(None, instance_plus);
|
||||||
|
|
||||||
|
// If a function to invoke was given, invoke it.
|
||||||
if let Some(ref f) = args.flag_invoke {
|
if let Some(ref f) = args.flag_invoke {
|
||||||
match instance_plus
|
match namespace
|
||||||
.invoke(&mut jit_code, isa, &f, &[])
|
.invoke(jit_code, isa, index, &f, &[])
|
||||||
.map_err(|e| e.to_string())?
|
.map_err(|e| e.to_string())?
|
||||||
{
|
{
|
||||||
ActionOutcome::Returned { .. } => {}
|
ActionOutcome::Returned { .. } => {}
|
||||||
|
|||||||
Reference in New Issue
Block a user