diff --git a/cranelift/src/wasm.rs b/cranelift/src/wasm.rs index f632a2162f..8833dc81b9 100644 --- a/cranelift/src/wasm.rs +++ b/cranelift/src/wasm.rs @@ -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)); diff --git a/lib/wasm/src/func_translator.rs b/lib/wasm/src/func_translator.rs index a5abdf382c..b93c3a368f 100644 --- a/lib/wasm/src/func_translator.rs +++ b/lib/wasm/src/func_translator.rs @@ -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(); } } diff --git a/lib/wasm/src/lib.rs b/lib/wasm/src/lib.rs index 9d1ad548bc..5aaee81d25 100644 --- a/lib/wasm/src/lib.rs +++ b/lib/wasm/src/lib.rs @@ -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}; diff --git a/lib/wasm/src/module_translator.rs b/lib/wasm/src/module_translator.rs index 3cbb11de6d..4aed1e9851 100644 --- a/lib/wasm/src/module_translator.rs +++ b/lib/wasm/src/module_translator.rs @@ -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, -} +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 { +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 = 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(()) } diff --git a/lib/wasm/src/runtime/dummy.rs b/lib/wasm/src/runtime/dummy.rs index 5dd39d1871..e3828d6e67 100644 --- a/lib/wasm/src/runtime/dummy.rs +++ b/lib/wasm/src/runtime/dummy.rs @@ -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 { @@ -24,10 +32,10 @@ impl Exportable { } } -/// 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>, + /// Function bodies. + pub function_bodies: Vec, + /// Tables as provided by `declare_table`. pub tables: Vec>, @@ -53,12 +64,7 @@ pub struct DummyRuntime { pub start_func: Option, } -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, _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 - } - fn next_function(&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()))?; + } + self.info.function_bodies.push(func); + Ok(()) } } diff --git a/lib/wasm/src/runtime/mod.rs b/lib/wasm/src/runtime/mod.rs index 548ad6bb6b..abee71b3f8 100644 --- a/lib/wasm/src/runtime/mod.rs +++ b/lib/wasm/src/runtime/mod.rs @@ -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; diff --git a/lib/wasm/src/runtime/spec.rs b/lib/wasm/src/runtime/spec.rs index 35c25d3807..bd38c8c316 100644 --- a/lib/wasm/src/runtime/spec.rs +++ b/lib/wasm/src/runtime/spec.rs @@ -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, 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>; } diff --git a/lib/wasm/src/sections_translator.rs b/lib/wasm/src/sections_translator.rs index 5641312440..b76734101d 100644 --- a/lib/wasm/src/sections_translator.rs +++ b/lib/wasm/src/sections_translator.rs @@ -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 = 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))), }; diff --git a/lib/wasm/tests/testsuite.rs b/lib/wasm/tests/testsuite.rs index d992de753e..687aa7c938 100644 --- a/lib/wasm/tests/testsuite.rs +++ b/lib/wasm/tests/testsuite.rs @@ -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();