Make FuncEnvironment independent from ModuleEnvironment (formerly WasmRuntime).

This renames WasmRuntime to ModuleEnvironment, and makes several changes
to allow for more flexible compilation.

ModuleEnvironment no longer derives from FuncEnvironment, and no longer
has the `begin_translation` and `next_translation` functions, so that
independent `FuncEnvironment` instances can operate within the same
module.

Also, this obviates the rest of TranslationResult, as it moves processing
of function bodies into the environment. The DummyEnvironment implementation
gives an example of decoding the function bodies as they are parsed, however
other implementation strategies are now possible.
This commit is contained in:
Dan Gohman
2017-10-10 15:21:29 -07:00
parent d4c0c5babc
commit 733870aee4
9 changed files with 245 additions and 187 deletions

View File

@@ -4,7 +4,7 @@
//! IL. Can also executes the `start` function of the module by laying out the memories, globals
//! and tables, then emitting the translated code with hardcoded addresses to memory.
use cton_wasm::{translate_module, DummyRuntime, WasmRuntime};
use cton_wasm::{translate_module, DummyEnvironment, ModuleEnvironment};
use std::path::PathBuf;
use cretonne::Context;
use cretonne::settings::FlagsOrIsa;
@@ -98,8 +98,8 @@ fn handle_module(
|err| String::from(err.description()),
)?;
}
let mut dummy_runtime = DummyRuntime::with_flags(fisa.flags.clone());
let translation = translate_module(&data, &mut dummy_runtime)?;
let mut dummy_environ = DummyEnvironment::with_flags(fisa.flags.clone());
translate_module(&data, &mut dummy_environ)?;
terminal.fg(term::color::GREEN).unwrap();
vprintln!(flag_verbose, "ok");
terminal.reset().unwrap();
@@ -113,8 +113,8 @@ fn handle_module(
vprint!(flag_verbose, "Compiling... ");
}
terminal.reset().unwrap();
let num_func_imports = dummy_runtime.get_num_func_imports();
for (def_index, func) in translation.functions.iter().enumerate() {
let num_func_imports = dummy_environ.get_num_func_imports();
for (def_index, func) in dummy_environ.info.function_bodies.iter().enumerate() {
let func_index = num_func_imports + def_index;
let mut context = Context::new();
context.func = func.clone();
@@ -133,12 +133,12 @@ fn handle_module(
}
if flag_print {
vprintln!(flag_verbose, "");
if let Some(start_func) = dummy_runtime.start_func {
if let Some(start_func) = dummy_environ.info.start_func {
if func_index == start_func {
println!("; Selected as wasm start function");
}
}
for export_name in &dummy_runtime.functions[func_index].export_names {
for export_name in &dummy_environ.info.functions[func_index].export_names {
println!("; Exported as \"{}\"", export_name);
}
println!("{}", context.func.display(fisa.isa));

View File

@@ -233,7 +233,7 @@ fn cur_srcloc(reader: &BinaryReader) -> ir::SourceLoc {
mod tests {
use cretonne::{ir, Context};
use cretonne::ir::types::I32;
use runtime::{DummyRuntime, FuncEnvironment};
use runtime::{DummyEnvironment, FuncEnvironment};
use super::FuncTranslator;
#[test]
@@ -252,7 +252,7 @@ mod tests {
];
let mut trans = FuncTranslator::new();
let mut runtime = DummyRuntime::default();
let runtime = DummyEnvironment::default();
let mut ctx = Context::new();
ctx.func.name = ir::FunctionName::new("small1");
@@ -263,9 +263,11 @@ mod tests {
ir::ArgumentType::new(I32),
);
trans.translate(&BODY, &mut ctx.func, &mut runtime).unwrap();
trans
.translate(&BODY, &mut ctx.func, &mut runtime.func_env())
.unwrap();
dbg!("{}", ctx.func.display(None));
ctx.verify(runtime.flags()).unwrap();
ctx.verify(runtime.func_env().flags()).unwrap();
}
#[test]
@@ -285,7 +287,7 @@ mod tests {
];
let mut trans = FuncTranslator::new();
let mut runtime = DummyRuntime::default();
let runtime = DummyEnvironment::default();
let mut ctx = Context::new();
ctx.func.name = ir::FunctionName::new("small2");
@@ -296,9 +298,11 @@ mod tests {
ir::ArgumentType::new(I32),
);
trans.translate(&BODY, &mut ctx.func, &mut runtime).unwrap();
trans
.translate(&BODY, &mut ctx.func, &mut runtime.func_env())
.unwrap();
dbg!("{}", ctx.func.display(None));
ctx.verify(runtime.flags()).unwrap();
ctx.verify(runtime.func_env().flags()).unwrap();
}
#[test]
@@ -327,7 +331,7 @@ mod tests {
];
let mut trans = FuncTranslator::new();
let mut runtime = DummyRuntime::default();
let runtime = DummyEnvironment::default();
let mut ctx = Context::new();
ctx.func.name = ir::FunctionName::new("infloop");
@@ -335,8 +339,10 @@ mod tests {
ir::ArgumentType::new(I32),
);
trans.translate(&BODY, &mut ctx.func, &mut runtime).unwrap();
trans
.translate(&BODY, &mut ctx.func, &mut runtime.func_env())
.unwrap();
dbg!("{}", ctx.func.display(None));
ctx.verify(runtime.flags()).unwrap();
ctx.verify(runtime.func_env().flags()).unwrap();
}
}

View File

@@ -1,12 +1,10 @@
//! Performs the translation from a wasm module in binary format to the in-memory representation
//! of the Cretonne IL. More particularly, it translates the code of all the functions bodies and
//! interacts with a runtime implementing the [`WasmRuntime`](trait.WasmRuntime.html) trait to
//! deal with tables, globals and linear memory.
//! interacts with a runtime implementing the [`ModuleEnvironment`](trait.ModuleEnvironment.html)
//! trait to deal with tables, globals and linear memory.
//!
//! The crate provides a `DummyRuntime` trait that will allow to translate the code of the
//! functions but will fail at execution. You should use
//! [`wasmstandalone::StandaloneRuntime`](../wasmstandalone/struct.StandaloneRuntime.html) to be
//! able to execute the translated code.
//! The crate provides a `DummyEnvironment` struct that will allow to translate the code of the
//! functions but will fail at execution.
//!
//! The main function of this module is [`translate_module`](fn.translate_module.html).
@@ -26,7 +24,7 @@ mod state;
mod translation_utils;
pub use func_translator::FuncTranslator;
pub use module_translator::{translate_module, TranslationResult};
pub use runtime::{FuncEnvironment, WasmRuntime, DummyRuntime, GlobalValue};
pub use module_translator::translate_module;
pub use runtime::{FuncEnvironment, ModuleEnvironment, DummyEnvironment, GlobalValue};
pub use translation_utils::{FunctionIndex, GlobalIndex, TableIndex, MemoryIndex, SignatureIndex,
Global, GlobalInit, Table, Memory};

View File

@@ -5,25 +5,16 @@ use sections_translator::{SectionParsingError, parse_function_signatures, parse_
parse_function_section, parse_export_section, parse_start_section,
parse_memory_section, parse_global_section, parse_table_section,
parse_elements_section, parse_data_section};
use cretonne::ir::Function;
use func_translator::FuncTranslator;
use std::error::Error;
use runtime::WasmRuntime;
/// Output of the [`translate_module`](fn.translate_module.html) function.
pub struct TranslationResult {
/// The translated functions.
pub functions: Vec<Function>,
}
use runtime::ModuleEnvironment;
/// Translate a sequence of bytes forming a valid Wasm binary into a list of valid Cretonne IL
/// [`Function`](../cretonne/ir/function/struct.Function.html).
/// Returns the functions and also the mappings for imported functions and signature between the
/// indexes in the wasm module and the indexes inside each functions.
pub fn translate_module(
data: &[u8],
runtime: &mut WasmRuntime,
) -> Result<TranslationResult, String> {
pub fn translate_module<'data>(
data: &'data [u8],
environ: &mut ModuleEnvironment,
) -> Result<(), String> {
let mut parser = Parser::new(data);
match *parser.read() {
ParserState::BeginWasm { .. } => {}
@@ -36,7 +27,7 @@ pub fn translate_module(
loop {
match *parser.read_with_input(next_input) {
ParserState::BeginSection { code: SectionCode::Type, .. } => {
match parse_function_signatures(&mut parser, runtime) {
match parse_function_signatures(&mut parser, environ) {
Ok(()) => (),
Err(SectionParsingError::WrongSectionContent(s)) => {
return Err(format!("wrong content in the type section: {}", s))
@@ -45,7 +36,7 @@ pub fn translate_module(
next_input = ParserInput::Default;
}
ParserState::BeginSection { code: SectionCode::Import, .. } => {
match parse_import_section(&mut parser, runtime) {
match parse_import_section(&mut parser, environ) {
Ok(()) => {}
Err(SectionParsingError::WrongSectionContent(s)) => {
return Err(format!("wrong content in the import section: {}", s))
@@ -54,7 +45,7 @@ pub fn translate_module(
next_input = ParserInput::Default;
}
ParserState::BeginSection { code: SectionCode::Function, .. } => {
match parse_function_section(&mut parser, runtime) {
match parse_function_section(&mut parser, environ) {
Ok(()) => {}
Err(SectionParsingError::WrongSectionContent(s)) => {
return Err(format!("wrong content in the function section: {}", s))
@@ -63,7 +54,7 @@ pub fn translate_module(
next_input = ParserInput::Default;
}
ParserState::BeginSection { code: SectionCode::Table, .. } => {
match parse_table_section(&mut parser, runtime) {
match parse_table_section(&mut parser, environ) {
Ok(()) => (),
Err(SectionParsingError::WrongSectionContent(s)) => {
return Err(format!("wrong content in the table section: {}", s))
@@ -71,7 +62,7 @@ pub fn translate_module(
}
}
ParserState::BeginSection { code: SectionCode::Memory, .. } => {
match parse_memory_section(&mut parser, runtime) {
match parse_memory_section(&mut parser, environ) {
Ok(()) => {}
Err(SectionParsingError::WrongSectionContent(s)) => {
return Err(format!("wrong content in the memory section: {}", s))
@@ -80,7 +71,7 @@ pub fn translate_module(
next_input = ParserInput::Default;
}
ParserState::BeginSection { code: SectionCode::Global, .. } => {
match parse_global_section(&mut parser, runtime) {
match parse_global_section(&mut parser, environ) {
Ok(()) => {}
Err(SectionParsingError::WrongSectionContent(s)) => {
return Err(format!("wrong content in the global section: {}", s))
@@ -89,7 +80,7 @@ pub fn translate_module(
next_input = ParserInput::Default;
}
ParserState::BeginSection { code: SectionCode::Export, .. } => {
match parse_export_section(&mut parser, runtime) {
match parse_export_section(&mut parser, environ) {
Ok(()) => {}
Err(SectionParsingError::WrongSectionContent(s)) => {
return Err(format!("wrong content in the export section: {}", s))
@@ -98,7 +89,7 @@ pub fn translate_module(
next_input = ParserInput::Default;
}
ParserState::BeginSection { code: SectionCode::Start, .. } => {
match parse_start_section(&mut parser, runtime) {
match parse_start_section(&mut parser, environ) {
Ok(()) => (),
Err(SectionParsingError::WrongSectionContent(s)) => {
return Err(format!("wrong content in the start section: {}", s))
@@ -107,7 +98,7 @@ pub fn translate_module(
next_input = ParserInput::Default;
}
ParserState::BeginSection { code: SectionCode::Element, .. } => {
match parse_elements_section(&mut parser, runtime) {
match parse_elements_section(&mut parser, environ) {
Ok(()) => (),
Err(SectionParsingError::WrongSectionContent(s)) => {
return Err(format!("wrong content in the element section: {}", s))
@@ -122,9 +113,9 @@ pub fn translate_module(
ParserState::EndSection => {
next_input = ParserInput::Default;
}
ParserState::EndWasm => return Ok(TranslationResult { functions: Vec::new() }),
ParserState::EndWasm => return Ok(()),
ParserState::BeginSection { code: SectionCode::Data, .. } => {
match parse_data_section(&mut parser, runtime) {
match parse_data_section(&mut parser, environ) {
Ok(()) => (),
Err(SectionParsingError::WrongSectionContent(s)) => {
return Err(format!("wrong content in the data section: {}", s))
@@ -135,41 +126,33 @@ pub fn translate_module(
};
}
// At this point we've entered the code section
let num_func_imports = runtime.get_num_func_imports();
let mut il_functions: Vec<Function> = Vec::new();
let mut trans = FuncTranslator::new();
runtime.begin_translation();
loop {
match *parser.read() {
ParserState::BeginFunctionBody { .. } => {}
ParserState::EndSection => break,
_ => return Err(String::from("wrong content in code section")),
}
runtime.next_function();
// First we build the Function object with its name and signature
let mut func = Function::new();
let function_index = num_func_imports + il_functions.len();
func.signature = runtime
.get_signature(runtime.get_func_type(function_index))
.clone();
func.name = runtime.get_func_name(function_index);
trans
.translate_from_reader(parser.create_binary_reader(), &mut func, runtime)
.map_err(|e| String::from(e.description()))?;
il_functions.push(func);
let mut reader = parser.create_binary_reader();
let size = reader.bytes_remaining();
environ.define_function_body(
reader.read_bytes(size).map_err(|e| {
format!("at offset {}: {}", e.offset, e.message)
})?,
)?;
}
loop {
match *parser.read() {
ParserState::BeginSection { code: SectionCode::Data, .. } => {
match parse_data_section(&mut parser, runtime) {
match parse_data_section(&mut parser, environ) {
Ok(()) => (),
Err(SectionParsingError::WrongSectionContent(s)) => {
return Err(format!("wrong content in the data section: {}", s))
}
}
}
ParserState::EndWasm => return Ok(TranslationResult { functions: il_functions }),
ParserState::EndWasm => break,
_ => (),
}
}
Ok(())
}

View File

@@ -1,10 +1,18 @@
use runtime::{FuncEnvironment, GlobalValue, WasmRuntime};
use runtime::{FuncEnvironment, GlobalValue, ModuleEnvironment};
use translation_utils::{Global, Memory, Table, GlobalIndex, TableIndex, SignatureIndex,
FunctionIndex, MemoryIndex};
use func_translator::FuncTranslator;
use cretonne::ir::{self, InstBuilder};
use cretonne::ir::types::*;
use cretonne::cursor::FuncCursor;
use cretonne::settings;
use wasmparser;
use std::error::Error;
/// Compute a `ir::FunctionName` for a given wasm function index.
fn get_func_name(func_index: FunctionIndex) -> ir::FunctionName {
ir::FunctionName::new(format!("wasm_0x{:x}", func_index))
}
/// A collection of names under which a given entity is exported.
pub struct Exportable<T> {
@@ -24,10 +32,10 @@ impl<T> Exportable<T> {
}
}
/// This runtime implementation is a "naïve" one, doing essentially nothing and emitting
/// placeholders when forced to. Don't try to execute code translated with this runtime, it is
/// essentially here for translation debug purposes.
pub struct DummyRuntime {
/// The main state belonging to a `DummyEnvironment`. This is split out from
/// `DummyEnvironment` to allow it to be borrowed separately from the
/// `FuncTranslator` field.
pub struct DummyModuleInfo {
/// Compilation setting flags.
pub flags: settings::Flags,
@@ -40,6 +48,9 @@ pub struct DummyRuntime {
/// Functions, imported and local.
pub functions: Vec<Exportable<SignatureIndex>>,
/// Function bodies.
pub function_bodies: Vec<ir::Function>,
/// Tables as provided by `declare_table`.
pub tables: Vec<Exportable<Table>>,
@@ -53,12 +64,7 @@ pub struct DummyRuntime {
pub start_func: Option<FunctionIndex>,
}
impl DummyRuntime {
/// Allocates the runtime data structures with default flags.
pub fn default() -> Self {
Self::with_flags(settings::Flags::new(&settings::builder()))
}
impl DummyModuleInfo {
/// Allocates the runtime data structures with the given flags.
pub fn with_flags(flags: settings::Flags) -> Self {
Self {
@@ -66,6 +72,7 @@ impl DummyRuntime {
signatures: Vec::new(),
imported_funcs: Vec::new(),
functions: Vec::new(),
function_bodies: Vec::new(),
tables: Vec::new(),
memories: Vec::new(),
globals: Vec::new(),
@@ -74,9 +81,52 @@ impl DummyRuntime {
}
}
impl FuncEnvironment for DummyRuntime {
/// This runtime implementation is a "naïve" one, doing essentially nothing and emitting
/// placeholders when forced to. Don't try to execute code translated with this runtime, it is
/// essentially here for translation debug purposes.
pub struct DummyEnvironment {
/// Module information.
pub info: DummyModuleInfo,
/// Function translation.
trans: FuncTranslator,
}
impl DummyEnvironment {
/// Allocates the runtime data structures with default flags.
pub fn default() -> Self {
Self::with_flags(settings::Flags::new(&settings::builder()))
}
/// Allocates the runtime data structures with the given flags.
pub fn with_flags(flags: settings::Flags) -> Self {
Self {
info: DummyModuleInfo::with_flags(flags),
trans: FuncTranslator::new(),
}
}
/// Return a `DummyFuncEnvironment` for translating functions within this
/// `DummyEnvironment`.
pub fn func_env(&self) -> DummyFuncEnvironment {
DummyFuncEnvironment::new(&self.info)
}
}
/// The FuncEnvironment implementation for use by the DummyEnvironment.
pub struct DummyFuncEnvironment<'dummy_environment> {
pub mod_info: &'dummy_environment DummyModuleInfo,
}
impl<'dummy_environment> DummyFuncEnvironment<'dummy_environment> {
pub fn new(mod_info: &'dummy_environment DummyModuleInfo) -> Self {
Self { mod_info }
}
}
impl<'dummy_environment> FuncEnvironment for DummyFuncEnvironment<'dummy_environment> {
fn flags(&self) -> &settings::Flags {
&self.flags
&self.mod_info.flags
}
fn make_global(&mut self, func: &mut ir::Function, index: GlobalIndex) -> GlobalValue {
@@ -85,7 +135,7 @@ impl FuncEnvironment for DummyRuntime {
let gv = func.create_global_var(ir::GlobalVarData::VmCtx { offset });
GlobalValue::Memory {
gv,
ty: self.globals[index].entity.ty,
ty: self.mod_info.globals[index].entity.ty,
}
}
@@ -101,15 +151,15 @@ impl FuncEnvironment for DummyRuntime {
fn make_indirect_sig(&mut self, func: &mut ir::Function, index: SignatureIndex) -> ir::SigRef {
// A real implementation would probably change the calling convention and add `vmctx` and
// signature index arguments.
func.import_signature(self.signatures[index].clone())
func.import_signature(self.mod_info.signatures[index].clone())
}
fn make_direct_func(&mut self, func: &mut ir::Function, index: FunctionIndex) -> ir::FuncRef {
let sigidx = self.functions[index].entity;
let sigidx = self.mod_info.functions[index].entity;
// A real implementation would probably add a `vmctx` argument.
// And maybe attempt some signature de-duplication.
let signature = func.import_signature(self.signatures[sigidx].clone());
let name = self.get_func_name(index);
let signature = func.import_signature(self.mod_info.signatures[sigidx].clone());
let name = get_func_name(index);
func.import_function(ir::ExtFuncData { name, signature })
}
@@ -145,54 +195,59 @@ impl FuncEnvironment for DummyRuntime {
}
}
impl WasmRuntime for DummyRuntime {
impl ModuleEnvironment for DummyEnvironment {
fn get_func_name(&self, func_index: FunctionIndex) -> ir::FunctionName {
ir::FunctionName::new(format!("wasm_0x{:x}", func_index))
get_func_name(func_index)
}
fn declare_signature(&mut self, sig: &ir::Signature) {
self.signatures.push(sig.clone());
self.info.signatures.push(sig.clone());
}
fn get_signature(&self, sig_index: SignatureIndex) -> &ir::Signature {
&self.signatures[sig_index]
&self.info.signatures[sig_index]
}
fn declare_func_import(&mut self, sig_index: SignatureIndex, module: &str, field: &str) {
fn declare_func_import<'data>(
&mut self,
sig_index: SignatureIndex,
module: &'data str,
field: &'data str,
) {
assert_eq!(
self.functions.len(),
self.imported_funcs.len(),
self.info.functions.len(),
self.info.imported_funcs.len(),
"Imported functions must be declared first"
);
self.functions.push(Exportable::new(sig_index));
self.imported_funcs.push((
self.info.functions.push(Exportable::new(sig_index));
self.info.imported_funcs.push((
String::from(module),
String::from(field),
));
}
fn get_num_func_imports(&self) -> usize {
self.imported_funcs.len()
self.info.imported_funcs.len()
}
fn declare_func_type(&mut self, sig_index: SignatureIndex) {
self.functions.push(Exportable::new(sig_index));
self.info.functions.push(Exportable::new(sig_index));
}
fn get_func_type(&self, func_index: FunctionIndex) -> SignatureIndex {
self.functions[func_index].entity
self.info.functions[func_index].entity
}
fn declare_global(&mut self, global: Global) {
self.globals.push(Exportable::new(global));
self.info.globals.push(Exportable::new(global));
}
fn get_global(&self, global_index: GlobalIndex) -> &Global {
&self.globals[global_index].entity
&self.info.globals[global_index].entity
}
fn declare_table(&mut self, table: Table) {
self.tables.push(Exportable::new(table));
self.info.tables.push(Exportable::new(table));
}
fn declare_table_elements(
&mut self,
@@ -204,51 +259,68 @@ impl WasmRuntime for DummyRuntime {
// We do nothing
}
fn declare_memory(&mut self, memory: Memory) {
self.memories.push(Exportable::new(memory));
self.info.memories.push(Exportable::new(memory));
}
fn declare_data_initialization(
fn declare_data_initialization<'data>(
&mut self,
_memory_index: MemoryIndex,
_base: Option<GlobalIndex>,
_offset: usize,
_data: &[u8],
_data: &'data [u8],
) {
// We do nothing
}
fn declare_func_export(&mut self, func_index: FunctionIndex, name: &str) {
self.functions[func_index].export_names.push(
fn declare_func_export<'data>(&mut self, func_index: FunctionIndex, name: &'data str) {
self.info.functions[func_index].export_names.push(
String::from(
name,
),
);
}
fn declare_table_export<'data>(&mut self, table_index: TableIndex, name: &'data str) {
self.info.tables[table_index].export_names.push(
String::from(name),
);
}
fn declare_table_export(&mut self, table_index: TableIndex, name: &str) {
self.tables[table_index].export_names.push(
String::from(name),
fn declare_memory_export<'data>(&mut self, memory_index: MemoryIndex, name: &'data str) {
self.info.memories[memory_index].export_names.push(
String::from(
name,
),
);
}
fn declare_memory_export(&mut self, memory_index: MemoryIndex, name: &str) {
self.memories[memory_index].export_names.push(
String::from(name),
);
}
fn declare_global_export(&mut self, global_index: GlobalIndex, name: &str) {
self.globals[global_index].export_names.push(
String::from(name),
fn declare_global_export<'data>(&mut self, global_index: GlobalIndex, name: &'data str) {
self.info.globals[global_index].export_names.push(
String::from(
name,
),
);
}
fn declare_start_func(&mut self, func_index: FunctionIndex) {
debug_assert!(self.start_func.is_none());
self.start_func = Some(func_index);
debug_assert!(self.info.start_func.is_none());
self.info.start_func = Some(func_index);
}
fn begin_translation(&mut self) {
// We do nothing
/// Provides the contents of a function body.
fn define_function_body<'data>(&mut self, body_bytes: &'data [u8]) -> Result<(), String> {
let function_index = self.get_num_func_imports() + self.info.function_bodies.len();
let name = get_func_name(function_index);
let sig = self.get_signature(self.get_func_type(function_index))
.clone();
let mut func = ir::Function::with_name_signature(name, sig);
{
let mut func_environ = DummyFuncEnvironment::new(&self.info);
let reader = wasmparser::BinaryReader::new(body_bytes);
self.trans
.translate_from_reader(reader, &mut func, &mut func_environ)
.map_err(|e| String::from(e.description()))?;
}
fn next_function(&mut self) {
// We do nothing
self.info.function_bodies.push(func);
Ok(())
}
}

View File

@@ -1,5 +1,5 @@
mod spec;
mod dummy;
pub use runtime::spec::{WasmRuntime, FuncEnvironment, GlobalValue};
pub use runtime::dummy::DummyRuntime;
pub use runtime::spec::{ModuleEnvironment, FuncEnvironment, GlobalValue};
pub use runtime::dummy::DummyEnvironment;

View File

@@ -1,5 +1,5 @@
//! All the runtime support necessary for the wasm to cretonne translation is formalized by the
//! trait `WasmRuntime`.
//! traits `FunctionEnvironment` and `ModuleEnvironment`.
use cretonne::ir::{self, InstBuilder};
use cretonne::cursor::FuncCursor;
use cretonne::settings::Flags;
@@ -146,21 +146,26 @@ pub trait FuncEnvironment {
) -> ir::Value;
}
/// An object satisfyng the `WasmRuntime` trait can be passed as argument to the
/// An object satisfyng the `ModuleEnvironment` trait can be passed as argument to the
/// [`translate_module`](fn.translate_module.html) function. These methods should not be called
/// by the user, they are only for `cretonne-wasm` internal use.
pub trait WasmRuntime: FuncEnvironment {
pub trait ModuleEnvironment {
/// Return the name for the given function index.
fn get_func_name(&self, func_index: FunctionIndex) -> ir::FunctionName;
/// Declares a function signature to the runtime.
/// Declares a function signature to the environment.
fn declare_signature(&mut self, sig: &ir::Signature);
/// Return the signature with the given index.
fn get_signature(&self, sig_index: SignatureIndex) -> &ir::Signature;
/// Declares a function import to the runtime.
fn declare_func_import(&mut self, sig_index: SignatureIndex, module: &str, field: &str);
/// Declares a function import to the environment.
fn declare_func_import<'data>(
&mut self,
sig_index: SignatureIndex,
module: &'data str,
field: &'data str,
);
/// Return the number of imported funcs.
fn get_num_func_imports(&self) -> usize;
@@ -171,13 +176,13 @@ pub trait WasmRuntime: FuncEnvironment {
/// Return the signature index for the given function index.
fn get_func_type(&self, func_index: FunctionIndex) -> SignatureIndex;
/// Declares a global to the runtime.
/// Declares a global to the environment.
fn declare_global(&mut self, global: Global);
/// Return the global for the given global index.
fn get_global(&self, global_index: GlobalIndex) -> &Global;
/// Declares a table to the runtime.
/// Declares a table to the environment.
fn declare_table(&mut self, table: Table);
/// Fills a declared table with references to functions in the module.
fn declare_table_elements(
@@ -187,32 +192,29 @@ pub trait WasmRuntime: FuncEnvironment {
offset: usize,
elements: &[FunctionIndex],
);
/// Declares a memory to the runtime
/// Declares a memory to the environment
fn declare_memory(&mut self, memory: Memory);
/// Fills a declared memory with bytes at module instantiation.
fn declare_data_initialization(
fn declare_data_initialization<'data>(
&mut self,
memory_index: MemoryIndex,
base: Option<GlobalIndex>,
offset: usize,
data: &[u8],
data: &'data [u8],
);
/// Declares a function export to the runtime.
fn declare_func_export(&mut self, func_index: FunctionIndex, name: &str);
/// Declares a table export to the runtime.
fn declare_table_export(&mut self, table_index: TableIndex, name: &str);
/// Declares a memory export to the runtime.
fn declare_memory_export(&mut self, memory_index: MemoryIndex, name: &str);
/// Declares a global export to the runtime.
fn declare_global_export(&mut self, global_index: GlobalIndex, name: &str);
/// Declares a function export to the environment.
fn declare_func_export<'data>(&mut self, func_index: FunctionIndex, name: &'data str);
/// Declares a table export to the environment.
fn declare_table_export<'data>(&mut self, table_index: TableIndex, name: &'data str);
/// Declares a memory export to the environment.
fn declare_memory_export<'data>(&mut self, memory_index: MemoryIndex, name: &'data str);
/// Declares a global export to the environment.
fn declare_global_export<'data>(&mut self, global_index: GlobalIndex, name: &'data str);
/// Declares a start function.
fn declare_start_func(&mut self, index: FunctionIndex);
/// Call this function after having declared all the runtime elements but prior to the
/// function body translation.
fn begin_translation(&mut self);
/// Call this function between each function body translation.
fn next_function(&mut self);
/// Provides the contents of a function body.
fn define_function_body<'data>(&mut self, body_bytes: &'data [u8]) -> Result<(), String>;
}

View File

@@ -15,7 +15,7 @@ use wasmparser::{Parser, ParserState, FuncType, ImportSectionEntryType, External
MemoryType, Operator};
use wasmparser;
use std::str::from_utf8;
use runtime::WasmRuntime;
use runtime::ModuleEnvironment;
pub enum SectionParsingError {
WrongSectionContent(String),
@@ -24,7 +24,7 @@ pub enum SectionParsingError {
/// Reads the Type Section of the wasm module and returns the corresponding function signatures.
pub fn parse_function_signatures(
parser: &mut Parser,
runtime: &mut WasmRuntime,
environ: &mut ModuleEnvironment,
) -> Result<(), SectionParsingError> {
loop {
match *parser.read() {
@@ -47,7 +47,7 @@ pub fn parse_function_signatures(
);
ArgumentType::new(cret_arg)
}));
runtime.declare_signature(&sig);
environ.declare_signature(&sig);
}
ref s => return Err(SectionParsingError::WrongSectionContent(format!("{:?}", s))),
}
@@ -58,7 +58,7 @@ pub fn parse_function_signatures(
/// Retrieves the imports from the imports section of the binary.
pub fn parse_import_section(
parser: &mut Parser,
runtime: &mut WasmRuntime,
environ: &mut ModuleEnvironment,
) -> Result<(), SectionParsingError> {
loop {
match *parser.read() {
@@ -72,12 +72,12 @@ pub fn parse_import_section(
// becomes a concern here.
let module_name = from_utf8(module).unwrap();
let field_name = from_utf8(field).unwrap();
runtime.declare_func_import(sig as SignatureIndex, module_name, field_name);
environ.declare_func_import(sig as SignatureIndex, module_name, field_name);
}
ParserState::ImportSectionEntry {
ty: ImportSectionEntryType::Memory(MemoryType { limits: ref memlimits }), ..
} => {
runtime.declare_memory(Memory {
environ.declare_memory(Memory {
pages_count: memlimits.initial as usize,
maximum: memlimits.maximum.map(|x| x as usize),
});
@@ -85,7 +85,7 @@ pub fn parse_import_section(
ParserState::ImportSectionEntry {
ty: ImportSectionEntryType::Global(ref ty), ..
} => {
runtime.declare_global(Global {
environ.declare_global(Global {
ty: type_to_type(&ty.content_type).unwrap(),
mutability: ty.mutable,
initializer: GlobalInit::Import(),
@@ -94,7 +94,7 @@ pub fn parse_import_section(
ParserState::ImportSectionEntry {
ty: ImportSectionEntryType::Table(ref tab), ..
} => {
runtime.declare_table(Table {
environ.declare_table(Table {
ty: match type_to_type(&tab.element_type) {
Ok(t) => TableElementType::Val(t),
Err(()) => TableElementType::Func(),
@@ -113,12 +113,12 @@ pub fn parse_import_section(
/// Retrieves the correspondances between functions and signatures from the function section
pub fn parse_function_section(
parser: &mut Parser,
runtime: &mut WasmRuntime,
environ: &mut ModuleEnvironment,
) -> Result<(), SectionParsingError> {
loop {
match *parser.read() {
ParserState::FunctionSectionEntry(sigindex) => {
runtime.declare_func_type(sigindex as SignatureIndex);
environ.declare_func_type(sigindex as SignatureIndex);
}
ParserState::EndSection => break,
ref s => return Err(SectionParsingError::WrongSectionContent(format!("{:?}", s))),
@@ -130,7 +130,7 @@ pub fn parse_function_section(
/// Retrieves the names of the functions from the export section
pub fn parse_export_section(
parser: &mut Parser,
runtime: &mut WasmRuntime,
environ: &mut ModuleEnvironment,
) -> Result<(), SectionParsingError> {
loop {
match *parser.read() {
@@ -145,10 +145,10 @@ pub fn parse_export_section(
let name = from_utf8(field).unwrap();
let func_index = index as FunctionIndex;
match *kind {
ExternalKind::Function => runtime.declare_func_export(func_index, name),
ExternalKind::Table => runtime.declare_table_export(func_index, name),
ExternalKind::Memory => runtime.declare_memory_export(func_index, name),
ExternalKind::Global => runtime.declare_global_export(func_index, name),
ExternalKind::Function => environ.declare_func_export(func_index, name),
ExternalKind::Table => environ.declare_table_export(func_index, name),
ExternalKind::Memory => environ.declare_memory_export(func_index, name),
ExternalKind::Global => environ.declare_global_export(func_index, name),
}
}
ParserState::EndSection => break,
@@ -161,12 +161,12 @@ pub fn parse_export_section(
/// Retrieves the start function index from the start section
pub fn parse_start_section(
parser: &mut Parser,
runtime: &mut WasmRuntime,
environ: &mut ModuleEnvironment,
) -> Result<(), SectionParsingError> {
loop {
match *parser.read() {
ParserState::StartSectionEntry(index) => {
runtime.declare_start_func(index as FunctionIndex);
environ.declare_start_func(index as FunctionIndex);
}
ParserState::EndSection => break,
ref s => return Err(SectionParsingError::WrongSectionContent(format!("{:?}", s))),
@@ -178,12 +178,12 @@ pub fn parse_start_section(
/// Retrieves the size and maximum fields of memories from the memory section
pub fn parse_memory_section(
parser: &mut Parser,
runtime: &mut WasmRuntime,
environ: &mut ModuleEnvironment,
) -> Result<(), SectionParsingError> {
loop {
match *parser.read() {
ParserState::MemorySectionEntry(ref ty) => {
runtime.declare_memory(Memory {
environ.declare_memory(Memory {
pages_count: ty.limits.initial as usize,
maximum: ty.limits.maximum.map(|x| x as usize),
});
@@ -198,7 +198,7 @@ pub fn parse_memory_section(
/// Retrieves the size and maximum fields of memories from the memory section
pub fn parse_global_section(
parser: &mut Parser,
runtime: &mut WasmRuntime,
environ: &mut ModuleEnvironment,
) -> Result<(), SectionParsingError> {
loop {
let (content_type, mutability) = match *parser.read() {
@@ -237,7 +237,7 @@ pub fn parse_global_section(
mutability: mutability,
initializer: initializer,
};
runtime.declare_global(global);
environ.declare_global(global);
match *parser.read() {
ParserState::EndGlobalSectionEntry => (),
ref s => return Err(SectionParsingError::WrongSectionContent(format!("{:?}", s))),
@@ -248,7 +248,7 @@ pub fn parse_global_section(
pub fn parse_data_section(
parser: &mut Parser,
runtime: &mut WasmRuntime,
environ: &mut ModuleEnvironment,
) -> Result<(), SectionParsingError> {
loop {
let memory_index = match *parser.read() {
@@ -265,7 +265,7 @@ pub fn parse_data_section(
(None, value as u32 as usize)
}
ParserState::InitExpressionOperator(Operator::GetGlobal { global_index }) => {
match runtime.get_global(global_index as GlobalIndex).initializer {
match environ.get_global(global_index as GlobalIndex).initializer {
GlobalInit::I32Const(value) => (None, value as u32 as usize),
GlobalInit::Import() => (Some(global_index as GlobalIndex), 0),
_ => panic!("should not happen"),
@@ -288,7 +288,7 @@ pub fn parse_data_section(
ParserState::EndDataSectionEntryBody => break,
ref s => return Err(SectionParsingError::WrongSectionContent(format!("{:?}", s))),
};
runtime.declare_data_initialization(
environ.declare_data_initialization(
memory_index as MemoryIndex,
base,
running_offset,
@@ -307,12 +307,12 @@ pub fn parse_data_section(
/// Retrieves the tables from the table section
pub fn parse_table_section(
parser: &mut Parser,
runtime: &mut WasmRuntime,
environ: &mut ModuleEnvironment,
) -> Result<(), SectionParsingError> {
loop {
match *parser.read() {
ParserState::TableSectionEntry(ref table) => {
runtime.declare_table(Table {
environ.declare_table(Table {
ty: match type_to_type(&table.element_type) {
Ok(t) => TableElementType::Val(t),
Err(()) => TableElementType::Func(),
@@ -331,7 +331,7 @@ pub fn parse_table_section(
/// Retrieves the tables from the table section
pub fn parse_elements_section(
parser: &mut Parser,
runtime: &mut WasmRuntime,
environ: &mut ModuleEnvironment,
) -> Result<(), SectionParsingError> {
loop {
let table_index = match *parser.read() {
@@ -348,7 +348,7 @@ pub fn parse_elements_section(
(None, value as u32 as usize)
}
ParserState::InitExpressionOperator(Operator::GetGlobal { global_index }) => {
match runtime.get_global(global_index as GlobalIndex).initializer {
match environ.get_global(global_index as GlobalIndex).initializer {
GlobalInit::I32Const(value) => (None, value as u32 as usize),
GlobalInit::Import() => (Some(global_index as GlobalIndex), 0),
_ => panic!("should not happen"),
@@ -364,7 +364,7 @@ pub fn parse_elements_section(
ParserState::ElementSectionEntryBody(ref elements) => {
let elems: Vec<FunctionIndex> =
elements.iter().map(|&x| x as FunctionIndex).collect();
runtime.declare_table_elements(table_index, base, offset, &elems)
environ.declare_table_elements(table_index, base, offset, &elems)
}
ref s => return Err(SectionParsingError::WrongSectionContent(format!("{:?}", s))),
};

View File

@@ -2,7 +2,7 @@ extern crate cton_wasm;
extern crate cretonne;
extern crate tempdir;
use cton_wasm::{translate_module, DummyRuntime, WasmRuntime};
use cton_wasm::{translate_module, DummyEnvironment};
use std::path::PathBuf;
use std::fs::File;
use std::error::Error;
@@ -92,12 +92,9 @@ fn handle_module(path: PathBuf, flags: &Flags) {
}
}
};
let mut dummy_runtime = DummyRuntime::with_flags(flags.clone());
let translation = {
let runtime: &mut WasmRuntime = &mut dummy_runtime;
translate_module(&data, runtime).unwrap()
};
for func in &translation.functions {
let mut dummy_environ = DummyEnvironment::with_flags(flags.clone());
translate_module(&data, &mut dummy_environ).unwrap();
for func in &dummy_environ.info.function_bodies {
verifier::verify_function(func, flags)
.map_err(|err| panic!(pretty_verifier_error(func, None, err)))
.unwrap();