diff --git a/lib/wasm/Cargo.toml b/lib/wasm/Cargo.toml index 9cabdc1b92..3de76671d0 100644 --- a/lib/wasm/Cargo.toml +++ b/lib/wasm/Cargo.toml @@ -11,6 +11,6 @@ license = "Apache-2.0" name = "cton_wasm" [dependencies] -wasmparser = "0.9.4" +wasmparser = "0.10.0" cretonne = { path = "../cretonne" } cretonne-frontend = { path = "../frontend" } diff --git a/lib/wasm/src/code_translator.rs b/lib/wasm/src/code_translator.rs index 8a1b7c4e14..625552232b 100644 --- a/lib/wasm/src/code_translator.rs +++ b/lib/wasm/src/code_translator.rs @@ -21,90 +21,18 @@ //! //! That is why `translate_function_body` takes an object having the `WasmRuntime` trait as //! argument. -use cretonne::ir::{self, Function, Signature, Type, InstBuilder, FunctionName, Ebb, MemFlags, - JumpTableData}; +use cretonne::ir::{self, InstBuilder, Ebb, MemFlags, JumpTableData}; use cretonne::ir::types::*; -use cretonne::ir::immediates::{Ieee32, Ieee64}; use cretonne::ir::condcodes::{IntCC, FloatCC}; -use cton_frontend::{ILBuilder, FunctionBuilder}; -use wasmparser::{Parser, Operator, WasmDecoder, MemoryImmediate}; +use cton_frontend::FunctionBuilder; +use wasmparser::{Operator, MemoryImmediate}; use translation_utils::{f32_translation, f64_translation, type_to_type, translate_type, Local}; use translation_utils::{TableIndex, SignatureIndex, FunctionIndex, MemoryIndex}; use state::{TranslationState, ControlStackFrame}; use std::collections::HashMap; -use runtime::{FuncEnvironment, GlobalValue, WasmRuntime}; +use runtime::{FuncEnvironment, GlobalValue}; use std::u32; -/// Returns a well-formed Cretonne IL function from a wasm function body and a signature. -pub fn translate_function_body( - parser: &mut Parser, - function_index: FunctionIndex, - sig: &Signature, - locals: &[(usize, Type)], - exports: &Option>, - il_builder: &mut ILBuilder, - runtime: &mut WasmRuntime, -) -> Result { - runtime.next_function(); - // First we build the Function object with its name and signature - let mut func = Function::new(); - let args_num: usize = sig.argument_types.len(); - func.signature = sig.clone(); - if let Some(ref exports) = *exports { - if let Some(name) = exports.get(&function_index) { - func.name = FunctionName::new(name.clone()); - } - } - // We introduce an arbitrary scope for the FunctionBuilder object - { - let mut builder = FunctionBuilder::new(&mut func, il_builder); - let first_ebb = builder.create_ebb(); - builder.switch_to_block(first_ebb, &[]); - builder.seal_block(first_ebb); - for (i, arg_type) in sig.argument_types.iter().enumerate() { - // First we declare the function arguments' as non-SSA vars because they will be - // accessed by get_local - let arg_value = builder.arg_value(i); - builder.declare_var(Local(i as u32), arg_type.value_type); - builder.def_var(Local(i as u32), arg_value); - } - // We also declare and initialize to 0 the local variables - let mut local_index = args_num; - for &(loc_count, ty) in locals { - let val = match ty { - I32 => builder.ins().iconst(ty, 0), - I64 => builder.ins().iconst(ty, 0), - F32 => builder.ins().f32const(Ieee32::with_bits(0)), - F64 => builder.ins().f64const(Ieee64::with_bits(0)), - _ => panic!("should not happen"), - }; - for _ in 0..loc_count { - builder.declare_var(Local(local_index as u32), ty); - builder.def_var(Local(local_index as u32), val); - local_index += 1; - } - } - - // We initialize the control stack with the implicit function block - let mut state = TranslationState::new(); - let end_ebb = builder.create_ebb(); - state.initialize(sig, end_ebb); - - // Now the main loop that reads every wasm instruction and translates it - let mut reader = parser.create_binary_reader(); - while let Ok(ref op) = reader.read_operator() { - translate_operator(op, &mut builder, &mut state, runtime) - } - debug_assert!(state.control_stack.is_empty()); - debug_assert!(builder.is_pristine()); - if !builder.is_unreachable() { - debug_assert!(state.stack.len() == sig.return_types.len()); - builder.ins().return_(&state.stack); - } - } - Ok(func) -} - /// Translates wasm operators into Cretonne IL instructions. Returns `true` if it inserted /// a return. pub fn translate_operator( diff --git a/lib/wasm/src/func_translator.rs b/lib/wasm/src/func_translator.rs index 9eba880f32..e2dede8b88 100644 --- a/lib/wasm/src/func_translator.rs +++ b/lib/wasm/src/func_translator.rs @@ -59,10 +59,20 @@ impl FuncTranslator { code: &[u8], func: &mut ir::Function, environ: &mut FE, + ) -> CtonResult { + self.translate_from_reader(BinaryReader::new(code), func, environ) + } + + /// Translate a binary WebAssembly function from a `BinaryReader`. + pub fn translate_from_reader( + &mut self, + mut reader: BinaryReader, + func: &mut ir::Function, + environ: &mut FE, ) -> CtonResult { dbg!( "translate({} bytes, {}{})", - code.len(), + reader.bytes_remaining(), func.name, func.signature ); @@ -81,8 +91,7 @@ impl FuncTranslator { let exit_block = builder.create_ebb(); self.state.initialize(&builder.func.signature, exit_block); - let reader = &mut BinaryReader::new(code); - parse_local_decls(reader, builder, num_args)?; + parse_local_decls(&mut reader, builder, num_args)?; parse_function_body(reader, builder, &mut self.state, environ) } } @@ -120,12 +129,15 @@ fn parse_local_decls( num_args: usize, ) -> CtonResult { let mut next_local = num_args; - let local_count = reader.read_var_u32().map_err(|_| CtonError::InvalidInput)?; + let local_count = reader.read_local_count().map_err( + |_| CtonError::InvalidInput, + )?; + let mut locals_total = 0; for _ in 0..local_count { - let (count, ty) = reader.read_local_decl().map_err( - |_| CtonError::InvalidInput, - )?; + let (count, ty) = reader.read_local_decl(&mut locals_total).map_err(|_| { + CtonError::InvalidInput + })?; declare_locals(builder, count, ty, &mut next_local)?; } @@ -173,7 +185,7 @@ fn declare_locals( /// This assumes that the local variable declarations have already been parsed and function /// arguments and locals are declared in the builder. fn parse_function_body( - reader: &mut BinaryReader, + mut reader: BinaryReader, builder: &mut FunctionBuilder, state: &mut TranslationState, environ: &mut FE, @@ -192,10 +204,13 @@ fn parse_function_body( // // If the exit block is unreachable, it may not have the correct arguments, so we would // generate a return instruction that doesn't match the signature. + debug_assert!(builder.is_pristine()); if !builder.is_unreachable() { - builder.ins().return_(state.stack.as_slice()); + builder.ins().return_(&state.stack); } + debug_assert!(reader.eof()); + Ok(()) } diff --git a/lib/wasm/src/module_translator.rs b/lib/wasm/src/module_translator.rs index 984f5ab78b..b9df83f9fe 100644 --- a/lib/wasm/src/module_translator.rs +++ b/lib/wasm/src/module_translator.rs @@ -5,11 +5,11 @@ use sections_translator::{SectionParsingError, parse_function_signatures, parse_ parse_function_section, parse_export_section, parse_memory_section, parse_global_section, parse_table_section, parse_elements_section, parse_data_section}; -use translation_utils::{type_to_type, Import, SignatureIndex, FunctionIndex}; -use cretonne::ir::{Function, Type}; -use code_translator::translate_function_body; -use cton_frontend::ILBuilder; +use translation_utils::{Import, SignatureIndex, FunctionIndex}; +use cretonne::ir::{Function, FunctionName}; +use func_translator::FuncTranslator; use std::collections::HashMap; +use std::error::Error; use runtime::WasmRuntime; /// Output of the [`translate_module`](fn.translate_module.html) function. @@ -198,38 +198,27 @@ pub fn translate_module( Some(functions) => functions, }; let mut il_functions: Vec = Vec::new(); - let mut il_builder = ILBuilder::new(); + let mut trans = FuncTranslator::new(); runtime.begin_translation(); loop { - let locals: Vec<(usize, Type)> = match *parser.read() { - ParserState::BeginFunctionBody { ref locals, .. } => { - locals - .iter() - .map(|&(index, ref ty)| { - ( - index as usize, - match type_to_type(ty) { - Ok(ty) => ty, - Err(()) => panic!("unsupported type for local variable"), - }, - ) - }) - .collect() - } + match *parser.read() { + ParserState::BeginFunctionBody { .. } => {} ParserState::EndSection => break, _ => return Err(String::from("wrong content in code section")), - }; - let signature = signatures[functions[function_index]].clone(); - let il_func = translate_function_body( - &mut parser, - function_index, - &signature, - &locals, - &exports, - &mut il_builder, - runtime, - )?; - il_functions.push(il_func); + } + runtime.next_function(); + // First we build the Function object with its name and signature + let mut func = Function::new(); + func.signature = signatures[functions[function_index]].clone(); + if let Some(ref exports) = exports { + if let Some(name) = exports.get(&function_index) { + func.name = FunctionName::new(name.clone()); + } + } + trans + .translate_from_reader(parser.create_binary_reader(), &mut func, runtime) + .map_err(|e| String::from(e.description()))?; + il_functions.push(func); function_index += 1; } loop {