Refactor the compilation and instantiation pipeline.

wasmtime-execute is now wasmtime-jit. Move `JITCode` and the TargetIsa
into a new `Compiler` type. `InstancePlus` is no more, with trampoline
functionality now handled by `Compiler`.
This commit is contained in:
Dan Gohman
2019-01-03 06:59:46 -08:00
parent 450a279e18
commit 7592c99f3b
46 changed files with 1225 additions and 1073 deletions

View File

@@ -32,7 +32,7 @@ extern crate target_lexicon;
extern crate wabt;
extern crate wasmparser;
extern crate wasmtime_environ;
extern crate wasmtime_execute;
extern crate wasmtime_jit;
extern crate wasmtime_runtime;
mod spectest;

View File

@@ -2,13 +2,12 @@ use cranelift_codegen::ir::types;
use cranelift_codegen::{ir, isa};
use cranelift_entity::PrimaryMap;
use cranelift_wasm::{DefinedFuncIndex, Global, GlobalInit, Memory, Table, TableElementType};
use std::rc::Rc;
use target_lexicon::HOST;
use wasmtime_environ::{
translate_signature, Export, MemoryPlan, MemoryStyle, Module, TablePlan, TableStyle,
};
use wasmtime_execute::{target_tunables, ActionError, InstancePlus};
use wasmtime_runtime::{Imports, VMFunctionBody};
use wasmtime_jit::{target_tunables, CompiledModule};
use wasmtime_runtime::{Imports, Instance, InstantiationError, VMFunctionBody};
extern "C" fn spectest_print() {}
@@ -46,7 +45,7 @@ extern "C" fn spectest_print_f64_f64(x: f64, y: f64) {
/// Return an instance implementing the "spectest" interface used in the
/// spec testsuite.
pub fn instantiate_spectest() -> Result<InstancePlus, ActionError> {
pub fn instantiate_spectest() -> Result<Box<Instance>, InstantiationError> {
let call_conv = isa::CallConv::triple_default(&HOST);
let pointer_type = types::Type::triple_pointer_type(&HOST);
let mut module = Module::new();
@@ -218,10 +217,11 @@ pub fn instantiate_spectest() -> Result<InstancePlus, ActionError> {
let imports = Imports::none();
let data_initializers = Vec::new();
InstancePlus::with_parts(
Rc::new(module),
CompiledModule::from_parts(
module,
finished_functions.into_boxed_slice(),
imports,
data_initializers,
data_initializers.into_boxed_slice(),
)
.instantiate()
}

View File

@@ -1,12 +1,12 @@
use cranelift_codegen::isa;
use spectest::instantiate_spectest;
use std::io::Read;
use std::path::Path;
use std::{fmt, fs, io, str};
use wabt::script::{Action, Command, CommandKind, ModuleBinary, ScriptParser, Value};
use wasmparser::{validate, OperatorValidatorConfig, ValidatingParserConfig};
use wasmtime_execute::{
ActionError, ActionOutcome, InstancePlus, InstancePlusIndex, JITCode, Namespace, RuntimeValue,
use wasmtime_jit::{
instantiate, ActionError, ActionOutcome, Compiler, Instance, InstanceIndex, InstantiationError,
Namespace, RuntimeValue, SetupError,
};
/// Translate from a script::Value to a RuntimeValue.
@@ -77,22 +77,22 @@ pub struct WastFileError {
/// to be performed on them.
pub struct WastContext {
/// A namespace of wasm modules, keyed by an optional name.
current: Option<InstancePlusIndex>,
current: Option<InstanceIndex>,
namespace: Namespace,
jit_code: JITCode,
compiler: Box<Compiler>,
}
impl WastContext {
/// Construct a new instance of `WastContext`.
pub fn new() -> Self {
pub fn new(compiler: Box<Compiler>) -> Self {
Self {
current: None,
namespace: Namespace::new(),
jit_code: JITCode::new(),
compiler,
}
}
fn validate(&mut self, data: &[u8]) -> Result<(), ActionError> {
fn validate(&mut self, data: &[u8]) -> Result<(), String> {
let config = ValidatingParserConfig {
operator_config: OperatorValidatorConfig {
enable_threads: false,
@@ -107,26 +107,19 @@ impl WastContext {
Ok(())
} else {
// TODO: Work with wasmparser to get better error messages.
Err(ActionError::Validate("module did not validate".to_owned()))
Err("module did not validate".to_owned())
}
}
fn instantiate(
&mut self,
isa: &isa::TargetIsa,
module: ModuleBinary,
) -> Result<InstancePlus, ActionError> {
fn instantiate(&mut self, module: ModuleBinary) -> Result<Box<Instance>, SetupError> {
let data = module.into_vec();
self.validate(&data)?;
self.validate(&data).map_err(SetupError::Validate)?;
InstancePlus::new(&mut self.jit_code, isa, &data, &mut self.namespace)
instantiate(&mut *self.compiler, &data, &mut self.namespace)
}
fn get_index(
&mut self,
instance_name: &Option<String>,
) -> Result<InstancePlusIndex, WastError> {
fn get_index(&mut self, instance_name: &Option<String>) -> Result<InstanceIndex, WastError> {
let index = *if let Some(instance_name) = instance_name {
self.namespace
.get_instance_index(instance_name)
@@ -145,24 +138,20 @@ impl WastContext {
}
/// Register "spectest" which is used by the spec testsuite.
pub fn register_spectest(&mut self) -> Result<(), ActionError> {
pub fn register_spectest(&mut self) -> Result<(), InstantiationError> {
let instance = instantiate_spectest()?;
self.namespace.instance(Some("spectest"), instance);
Ok(())
}
/// Perform the action portion of a command.
fn perform_action(
&mut self,
isa: &isa::TargetIsa,
action: Action,
) -> Result<ActionOutcome, WastError> {
fn perform_action(&mut self, action: Action) -> Result<ActionOutcome, WastError> {
match action {
Action::Invoke {
module: instance_name,
field,
args,
} => self.invoke(isa, instance_name, &field, &args),
} => self.invoke(instance_name, &field, &args),
Action::Get {
module: instance_name,
field,
@@ -173,11 +162,10 @@ impl WastContext {
/// 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 instance = self.instantiate(module).map_err(ActionError::Setup)?;
let index = self
.namespace
.instance(instance_name.as_ref().map(String::as_str), instance);
@@ -195,7 +183,6 @@ impl WastContext {
/// Invoke an exported function from an instance.
fn invoke(
&mut self,
isa: &isa::TargetIsa,
instance_name: Option<String>,
field: &str,
args: &[Value],
@@ -206,7 +193,7 @@ impl WastContext {
.collect::<Vec<_>>();
let index = self.get_index(&instance_name)?;
self.namespace
.invoke(&mut self.jit_code, isa, index, &field, &value_args)
.invoke(&mut *self.compiler, index, &field, &value_args)
.map_err(WastError::Action)
}
@@ -227,24 +214,15 @@ impl WastContext {
}
/// 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)? {
fn perform_action_command(&mut self, action: Action) -> Result<(), WastError> {
match self.perform_action(action)? {
ActionOutcome::Returned { .. } => Ok(()),
ActionOutcome::Trapped { message } => Err(WastError::Trap(message)),
}
}
/// Run a wast script from a byte buffer.
pub fn run_buffer(
&mut self,
isa: &isa::TargetIsa,
filename: &str,
wast: &[u8],
) -> Result<(), WastFileError> {
pub fn run_buffer(&mut self, filename: &str, wast: &[u8]) -> Result<(), WastFileError> {
let mut parser = ScriptParser::from_str(str::from_utf8(wast).unwrap()).unwrap();
while let Some(Command { kind, line }) = parser.next().expect("parser") {
@@ -253,7 +231,7 @@ impl WastContext {
module: instance_name,
name,
} => {
self.module(isa, name, instance_name)
self.module(name, instance_name)
.map_err(|error| WastFileError {
filename: filename.to_string(),
line,
@@ -269,7 +247,7 @@ impl WastContext {
})?;
}
CommandKind::PerformAction(action) => {
self.perform_action_command(isa, action)
self.perform_action_command(action)
.map_err(|error| WastFileError {
filename: filename.to_string(),
line,
@@ -277,13 +255,11 @@ impl WastContext {
})?;
}
CommandKind::AssertReturn { action, expected } => {
match self
.perform_action(isa, action)
.map_err(|error| WastFileError {
filename: filename.to_string(),
line,
error,
})? {
match self.perform_action(action).map_err(|error| WastFileError {
filename: filename.to_string(),
line,
error,
})? {
ActionOutcome::Returned { values } => {
for (v, e) in values
.iter()
@@ -312,13 +288,11 @@ impl WastContext {
}
}
CommandKind::AssertTrap { action, message } => {
match self
.perform_action(isa, action)
.map_err(|error| WastFileError {
filename: filename.to_string(),
line,
error,
})? {
match self.perform_action(action).map_err(|error| WastFileError {
filename: filename.to_string(),
line,
error,
})? {
ActionOutcome::Returned { values } => {
return Err(WastFileError {
filename: filename.to_string(),
@@ -340,13 +314,11 @@ impl WastContext {
}
}
CommandKind::AssertExhaustion { action } => {
match self
.perform_action(isa, action)
.map_err(|error| WastFileError {
filename: filename.to_string(),
line,
error,
})? {
match self.perform_action(action).map_err(|error| WastFileError {
filename: filename.to_string(),
line,
error,
})? {
ActionOutcome::Returned { values } => {
return Err(WastFileError {
filename: filename.to_string(),
@@ -366,13 +338,11 @@ impl WastContext {
}
}
CommandKind::AssertReturnCanonicalNan { action } => {
match self
.perform_action(isa, action)
.map_err(|error| WastFileError {
filename: filename.to_string(),
line,
error,
})? {
match self.perform_action(action).map_err(|error| WastFileError {
filename: filename.to_string(),
line,
error,
})? {
ActionOutcome::Returned { values } => {
for v in values.iter() {
match v {
@@ -420,13 +390,11 @@ impl WastContext {
}
}
CommandKind::AssertReturnArithmeticNan { action } => {
match self
.perform_action(isa, action)
.map_err(|error| WastFileError {
filename: filename.to_string(),
line,
error,
})? {
match self.perform_action(action).map_err(|error| WastFileError {
filename: filename.to_string(),
line,
error,
})? {
ActionOutcome::Returned { values } => {
for v in values.iter() {
match v {
@@ -474,7 +442,7 @@ impl WastContext {
}
}
CommandKind::AssertInvalid { module, message } => {
self.module(isa, None, module).expect_err(&format!(
self.module(None, module).expect_err(&format!(
"{}:{}: invalid module was successfully instantiated",
filename, line
));
@@ -484,7 +452,7 @@ impl WastContext {
);
}
CommandKind::AssertMalformed { module, message } => {
self.module(isa, None, module).expect_err(&format!(
self.module(None, module).expect_err(&format!(
"{}:{}: malformed module was successfully instantiated",
filename, line
));
@@ -494,7 +462,7 @@ impl WastContext {
);
}
CommandKind::AssertUninstantiable { module, message } => {
let _err = self.module(isa, None, module).expect_err(&format!(
let _err = self.module(None, module).expect_err(&format!(
"{}:{}: uninstantiable module was successfully instantiated",
filename, line
));
@@ -504,7 +472,7 @@ impl WastContext {
);
}
CommandKind::AssertUnlinkable { module, message } => {
let _err = self.module(isa, None, module).expect_err(&format!(
let _err = self.module(None, module).expect_err(&format!(
"{}:{}: unlinkable module was successfully linked",
filename, line
));
@@ -520,14 +488,14 @@ impl WastContext {
}
/// Run a wast script from a file.
pub fn run_file(&mut self, isa: &isa::TargetIsa, path: &Path) -> Result<(), WastFileError> {
pub fn run_file(&mut self, path: &Path) -> Result<(), WastFileError> {
let filename = path.display().to_string();
let buffer = read_to_end(path).map_err(|e| WastFileError {
filename,
line: 0,
error: WastError::IO(e),
})?;
self.run_buffer(isa, &path.display().to_string(), &buffer)
self.run_buffer(&path.display().to_string(), &buffer)
}
}