diff --git a/Cargo.toml b/Cargo.toml index febeeaaca0..e28e3ad577 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,9 +13,10 @@ name = "wasmstandalone" path = "src/main.rs" [dependencies] -cretonne = { git = "https://github.com/stoklund/cretonne.git" } -cretonne-reader = { git = "https://github.com/stoklund/cretonne.git" } -cretonne-wasm = { git = "https://github.com/stoklund/cretonne.git" } +cretonne = { path = "/home/sunfish/rust/cretonne/lib/cretonne" } +cretonne-reader = { path = "/home/sunfish/rust/cretonne/lib/reader" } +cretonne-wasm = { path = "/home/sunfish/rust/cretonne/lib/wasm" } +cretonne-native = { path = "/home/sunfish/rust/cretonne/lib/native" } wasmstandalone = { path = "lib/wasmstandalone" } wasmparser = "0.8.2" wasmtext = { git = "https://github.com/yurydelendik/wasmtext" } diff --git a/lib/wasmstandalone/Cargo.toml b/lib/wasmstandalone/Cargo.toml index d7f8fa1b6f..5d3c4ed339 100644 --- a/lib/wasmstandalone/Cargo.toml +++ b/lib/wasmstandalone/Cargo.toml @@ -8,7 +8,7 @@ repository = "https://github.com/stoklund/cretonne" license = "Apache-2.0" [dependencies] -cretonne = { git = "https://github.com/stoklund/cretonne.git" } -cretonne-frontend = { git = "https://github.com/stoklund/cretonne.git" } -cretonne-wasm = { git = "https://github.com/stoklund/cretonne.git" } +cretonne = { path = "/home/sunfish/rust/cretonne/lib/cretonne" } +cretonne-frontend = { path = "/home/sunfish/rust/cretonne/lib/frontend" } +cretonne-wasm = { path = "/home/sunfish/rust/cretonne/lib/wasm" } region = "0.0.8" diff --git a/lib/wasmstandalone/src/execution.rs b/lib/wasmstandalone/src/execution.rs index e85d1806c2..4692ca2805 100644 --- a/lib/wasmstandalone/src/execution.rs +++ b/lib/wasmstandalone/src/execution.rs @@ -8,13 +8,14 @@ use cretonne::result::CtonError; use cretonne::ir::entities::AnyEntity; use cretonne::ir::{Ebb, FuncRef, JumpTable, Function}; use cretonne::binemit::{RelocSink, Reloc, CodeOffset}; -use cton_wasm::{TranslationResult, FunctionTranslation, ImportMappings, FunctionIndex}; +use cton_wasm::{TranslationResult, FunctionIndex, WasmRuntime}; use std::mem::transmute; use region::Protection; use region::protect; use std::collections::HashMap; use std::ptr::write_unaligned; use std::fmt::Write; +use standalone::StandaloneRuntime; type RelocRef = u16; @@ -26,13 +27,9 @@ struct StandaloneRelocSink { } // Contains all the metadata necessary to perform relocations -enum FunctionMetaData { - Import(), - Local { - relocs: StandaloneRelocSink, - imports: ImportMappings, - il_func: Function, - }, +struct FunctionMetaData { + relocs: StandaloneRelocSink, + il_func: Function, } impl RelocSink for StandaloneRelocSink { @@ -64,7 +61,17 @@ pub struct ExecutableCode { } /// Executes a module that has been translated with the `StandaloneRuntime` runtime implementation. -pub fn compile_module(trans_result: &TranslationResult) -> Result { +pub fn compile_module( + trans_result: &TranslationResult, + isa: &TargetIsa, + runtime: &StandaloneRuntime, +) -> Result { + debug_assert!( + trans_result.start_index.is_none() || + trans_result.start_index.unwrap() >= trans_result.function_imports_count, + "imported start functions not supported yet" + ); + let mut shared_builder = settings::builder(); shared_builder.enable("enable_verifier").expect( "Missing enable_verifier setting", @@ -72,43 +79,14 @@ pub fn compile_module(trans_result: &TranslationResult) -> Result { - panic!() // The target ISA is not available. - } - Ok(mut isa_builder) => { - isa_builder.enable("haswell").expect( - "Missing haswell setting", - ); - isa_builder.finish(settings::Flags::new(&shared_builder)) - } - }; let mut functions_metatada = Vec::new(); let mut functions_code = Vec::new(); for (function_index, function) in trans_result.functions.iter().enumerate() { let mut context = Context::new(); - let (il, imports) = match function { - &FunctionTranslation::Import() => { - if trans_result.start_index.is_some() && - trans_result.start_index.unwrap() == function_index - { - return Err(String::from("start function should not be an import")); - } else { - functions_code.push(Vec::new()); - functions_metatada.push(FunctionMetaData::Import()); - continue; - } - } - &FunctionTranslation::Code { - ref il, - ref imports, - .. - } => (il.clone(), imports.clone()), - }; - verify_function(&il, None).unwrap(); - context.func = il; - let code_size = context.compile(&*isa).map_err(|e| { - pretty_error(&context.func, Some(&*isa), e) + verify_function(&function, isa).unwrap(); + context.func = function.clone(); // TODO: Avoid this clone. + let code_size = context.compile(isa).map_err(|e| { + pretty_error(&context.func, Some(isa), e) })? as usize; if code_size == 0 { return Err(String::from("no code generated by Cretonne")); @@ -116,15 +94,19 @@ pub fn compile_module(trans_result: &TranslationResult) -> Result = Vec::with_capacity(code_size); code_buf.resize(code_size, 0); let mut relocsink = StandaloneRelocSink::new(); - context.emit_to_memory(code_buf.as_mut_ptr(), &mut relocsink, &*isa); - functions_metatada.push(FunctionMetaData::Local { + context.emit_to_memory(code_buf.as_mut_ptr(), &mut relocsink, isa); + functions_metatada.push(FunctionMetaData { relocs: relocsink, - imports: imports, il_func: context.func, }); functions_code.push(code_buf); } - relocate(&functions_metatada, &mut functions_code); + relocate( + trans_result.function_imports_count, + &functions_metatada, + &mut functions_code, + runtime, + ); // After having emmitted the code to memory, we deal with relocations match trans_result.start_index { None => Err(String::from( @@ -192,47 +174,45 @@ pub fn execute(exec: &ExecutableCode) -> Result<(), String> { } /// Performs the relocations inside the function bytecode, provided the necessary metadata -fn relocate(functions_metatada: &[FunctionMetaData], functions_code: &mut Vec>) { +fn relocate( + function_imports_count: usize, + functions_metatada: &[FunctionMetaData], + functions_code: &mut Vec>, + runtime: &StandaloneRuntime, +) { // The relocations are relative to the relocation's address plus four bytes for (func_index, function_in_memory) in functions_metatada.iter().enumerate() { - match *function_in_memory { - FunctionMetaData::Import() => continue, - FunctionMetaData::Local { - ref relocs, - ref imports, - ref il_func, - } => { - for &(func_ref, offset) in relocs.funcs.values() { - let target_func_index = imports.functions[&func_ref]; - let target_func_address: isize = functions_code[target_func_index].as_ptr() as - isize; - unsafe { - let reloc_address: isize = functions_code[func_index] - .as_mut_ptr() - .offset(offset as isize + 4) as - isize; - let reloc_delta_i32: i32 = (target_func_address - reloc_address) as i32; - write_unaligned(reloc_address as *mut i32, reloc_delta_i32); - } - } - for &(ebb, offset) in relocs.ebbs.values() { - unsafe { - let reloc_address: isize = functions_code[func_index] - .as_mut_ptr() - .offset(offset as isize + 4) as - isize; - let target_ebb_address: isize = - functions_code[func_index].as_ptr().offset( - il_func.offsets[ebb] as - isize, - ) as isize; - let reloc_delta_i32: i32 = (target_ebb_address - reloc_address) as i32; - write_unaligned(reloc_address as *mut i32, reloc_delta_i32); - } - } - // TODO: deal with jumptable relocations + let FunctionMetaData { + ref relocs, + ref il_func, + } = *function_in_memory; + for &(func_ref, offset) in relocs.funcs.values() { + let target_func_index = runtime.func_indices[func_ref] - function_imports_count; + let target_func_address: isize = functions_code[target_func_index].as_ptr() as isize; + unsafe { + let reloc_address: isize = functions_code[func_index].as_mut_ptr().offset( + offset as isize + + 4, + ) as isize; + let reloc_delta_i32: i32 = (target_func_address - reloc_address) as i32; + write_unaligned(reloc_address as *mut i32, reloc_delta_i32); } } + for &(ebb, offset) in relocs.ebbs.values() { + unsafe { + let reloc_address: isize = functions_code[func_index].as_mut_ptr().offset( + offset as isize + + 4, + ) as isize; + let target_ebb_address: isize = functions_code[func_index].as_ptr().offset( + il_func.offsets[ebb] as + isize, + ) as isize; + let reloc_delta_i32: i32 = (target_ebb_address - reloc_address) as i32; + write_unaligned(reloc_address as *mut i32, reloc_delta_i32); + } + } + // TODO: deal with jumptable relocations } } diff --git a/lib/wasmstandalone/src/standalone.rs b/lib/wasmstandalone/src/standalone.rs index 06038c008d..c1ed67a696 100644 --- a/lib/wasmstandalone/src/standalone.rs +++ b/lib/wasmstandalone/src/standalone.rs @@ -1,11 +1,16 @@ -use cton_wasm::{Local, FunctionIndex, GlobalIndex, TableIndex, MemoryIndex, RawByte, - MemoryAddress, Global, GlobalInit, Table, Memory, WasmRuntime}; +use cton_wasm::{FunctionIndex, GlobalIndex, TableIndex, MemoryIndex, Global, GlobalInit, Table, + Memory, WasmRuntime, FuncEnvironment, GlobalValue, SignatureIndex}; use cton_frontend::FunctionBuilder; use cretonne::ir::{MemFlags, Value, InstBuilder, SigRef, FuncRef, ExtFuncData, FunctionName, Signature, ArgumentType, CallConv}; use cretonne::ir::types::*; use cretonne::ir::condcodes::IntCC; use cretonne::ir::immediates::Offset32; +use cretonne::cursor::FuncCursor; +use cretonne::packed_option::PackedOption; +use cretonne::ir; +use cretonne::settings; +use cretonne::entity::EntityMap; use std::mem::transmute; use std::ptr::copy_nonoverlapping; use std::ptr::write; @@ -22,18 +27,18 @@ struct GlobalInfo { } struct GlobalsData { - data: Vec, + data: Vec, info: Vec, } struct TableData { - data: Vec, + data: Vec, elements: Vec, info: Table, } struct MemoryData { - data: Vec, + data: Vec, info: Memory, } @@ -42,18 +47,43 @@ const PAGE_SIZE: usize = 65536; /// Object containing the standalone runtime information. To be passed after creation as argument /// to `cton_wasm::translatemodule`. pub struct StandaloneRuntime { + // Compilation setting flags. + flags: settings::Flags, + + // Unprocessed signatures exactly as provided by `declare_signature()`. + signatures: Vec, + // Types of functions, imported and local. + func_types: Vec, + // Names of imported functions. + imported_funcs: Vec, + globals: GlobalsData, tables: Vec, memories: Vec, instantiated: bool, + has_current_memory: Option, has_grow_memory: Option, + + /// Mapping from cretonne FuncRef to wasm FunctionIndex. + pub func_indices: EntityMap, + + the_heap: PackedOption, } impl StandaloneRuntime { - /// Allocates the runtime data structures. - pub fn new() -> StandaloneRuntime { - StandaloneRuntime { + /// 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 { + flags, + signatures: Vec::new(), + func_types: Vec::new(), + imported_funcs: Vec::new(), globals: GlobalsData { data: Vec::new(), info: Vec::new(), @@ -63,145 +93,172 @@ impl StandaloneRuntime { instantiated: false, has_current_memory: None, has_grow_memory: None, + func_indices: EntityMap::new(), + the_heap: PackedOption::default(), } } } +impl FuncEnvironment for StandaloneRuntime { + fn flags(&self) -> &settings::Flags { + &self.flags + } + + fn make_global(&mut self, func: &mut ir::Function, index: GlobalIndex) -> GlobalValue { + // Just create a dummy `vmctx` global. + let offset = ((index * 8) as i32 + 8).into(); + let gv = func.create_global_var(ir::GlobalVarData::VmCtx { offset }); + GlobalValue::Memory { + gv, + ty: self.globals.info[index].global.ty, + } + } + + fn make_heap(&mut self, func: &mut ir::Function, _index: MemoryIndex) -> ir::Heap { + debug_assert!(self.the_heap.is_none(), "multiple heaps not supported yet"); + + let heap = func.create_heap(ir::HeapData { + base: ir::HeapBase::ReservedReg, + min_size: 0.into(), + guard_size: 0x8000_0000.into(), + style: ir::HeapStyle::Static { bound: 0x1_0000_0000.into() }, + }); + + self.the_heap = PackedOption::from(heap); + + heap + } + + 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()) + } + + fn make_direct_func(&mut self, func: &mut ir::Function, index: FunctionIndex) -> ir::FuncRef { + let sigidx = self.func_types[index]; + // 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 = match self.imported_funcs.get(index) { + Some(name) => name.clone(), + None => ir::FunctionName::new(format!("localfunc{}", index)), + }; + + let func_ref = func.import_function(ir::ExtFuncData { name, signature }); + + self.func_indices[func_ref] = index; + + func_ref + } + + fn translate_call_indirect( + &mut self, + mut pos: FuncCursor, + table_index: TableIndex, + _sig_index: SignatureIndex, + sig_ref: ir::SigRef, + callee: ir::Value, + call_args: &[ir::Value], + ) -> ir::Inst { + debug_assert!(table_index == 0, "non-default tables not supported yet"); + pos.ins().call_indirect(sig_ref, callee, call_args) + } + + fn translate_grow_memory( + &mut self, + mut pos: FuncCursor, + index: MemoryIndex, + heap: ir::Heap, + val: ir::Value, + ) -> ir::Value { + debug_assert!(self.instantiated); + debug_assert!(index == 0, "non-default memories not supported yet"); + debug_assert!( + heap == self.the_heap.unwrap(), + "multiple heaps not supported yet" + ); + let grow_mem_func = match self.has_grow_memory { + Some(grow_mem_func) => grow_mem_func, + None => { + let sig_ref = pos.func.import_signature(Signature { + call_conv: CallConv::Native, + argument_bytes: None, + argument_types: vec![ArgumentType::new(I32)], + return_types: vec![ArgumentType::new(I32)], + }); + pos.func.import_function(ExtFuncData { + name: FunctionName::new("grow_memory"), + signature: sig_ref, + }) + } + }; + self.has_grow_memory = Some(grow_mem_func); + let call_inst = pos.ins().call(grow_mem_func, &[val]); + *pos.func.dfg.inst_results(call_inst).first().unwrap() + } + + fn translate_current_memory( + &mut self, + mut pos: FuncCursor, + index: MemoryIndex, + heap: ir::Heap, + ) -> ir::Value { + debug_assert!(self.instantiated); + debug_assert!(index == 0, "non-default memories not supported yet"); + debug_assert!( + heap == self.the_heap.unwrap(), + "multiple heaps not supported yet" + ); + let cur_mem_func = match self.has_current_memory { + Some(cur_mem_func) => cur_mem_func, + None => { + let sig_ref = pos.func.import_signature(Signature { + call_conv: CallConv::Native, + argument_bytes: None, + argument_types: Vec::new(), + return_types: vec![ArgumentType::new(I32)], + }); + pos.func.import_function(ExtFuncData { + name: FunctionName::new("current_memory"), + signature: sig_ref, + }) + } + }; + self.has_current_memory = Some(cur_mem_func); + let call_inst = pos.ins().call(cur_mem_func, &[]); + *pos.func.dfg.inst_results(call_inst).first().unwrap() + } +} + /// This trait is useful for /// `cton_wasm::translatemodule` because it /// tells how to translate runtime-dependent wasm instructions. These functions should not be /// called by the user. impl WasmRuntime for StandaloneRuntime { - fn translate_get_global( - &self, - builder: &mut FunctionBuilder, - global_index: GlobalIndex, - ) -> Value { - debug_assert!(self.instantiated); - let ty = self.globals.info[global_index].global.ty; - let offset = self.globals.info[global_index].offset; - let memflags = MemFlags::new(); - let memoffset = Offset32::new(offset as i32); - let addr: i64 = unsafe { transmute(self.globals.data.as_ptr()) }; - let addr_val = builder.ins().iconst(I64, addr); - builder.ins().load(ty, memflags, addr_val, memoffset) + fn declare_signature(&mut self, sig: &ir::Signature) { + self.signatures.push(sig.clone()); } - fn translate_set_global( - &self, - builder: &mut FunctionBuilder, - global_index: GlobalIndex, - val: Value, - ) { - let offset = self.globals.info[global_index].offset; - let memflags = MemFlags::new(); - let memoffset = Offset32::new(offset as i32); - let addr: i64 = unsafe { transmute(self.globals.data.as_ptr()) }; - let addr_val = builder.ins().iconst(I64, addr); - builder.ins().store(memflags, val, addr_val, memoffset); - } - fn translate_memory_base_address( - &self, - builder: &mut FunctionBuilder, - memory_index: MemoryIndex, - ) -> Value { - let addr: i64 = unsafe { transmute(self.memories[memory_index].data.as_ptr()) }; - builder.ins().iconst(I64, addr) - } - fn translate_grow_memory( - &mut self, - builder: &mut FunctionBuilder, - pages: Value, - ) -> Value { - debug_assert!(self.instantiated); - let grow_mem_func = match self.has_grow_memory { - Some(grow_mem_func) => grow_mem_func, - None => { - let sig_ref = builder.import_signature(Signature { - call_conv: CallConv::Native, - argument_bytes: None, - argument_types: vec![ArgumentType::new(I32)], - return_types: vec![ArgumentType::new(I32)], - }); - builder.import_function(ExtFuncData { - name: FunctionName::new("grow_memory"), - signature: sig_ref, - }) - } - }; - self.has_grow_memory = Some(grow_mem_func); - let call_inst = builder.ins().call(grow_mem_func, &[pages]); - *builder.inst_results(call_inst).first().unwrap() - } - fn translate_current_memory(&mut self, builder: &mut FunctionBuilder) -> Value { - debug_assert!(self.instantiated); - let cur_mem_func = match self.has_current_memory { - Some(cur_mem_func) => cur_mem_func, - None => { - let sig_ref = builder.import_signature(Signature { - call_conv: CallConv::Native, - argument_bytes: None, - argument_types: Vec::new(), - return_types: vec![ArgumentType::new(I32)], - }); - builder.import_function(ExtFuncData { - name: FunctionName::new("current_memory"), - signature: sig_ref, - }) - } - }; - self.has_current_memory = Some(cur_mem_func); - let call_inst = builder.ins().call(cur_mem_func, &[]); - *builder.inst_results(call_inst).first().unwrap() - } - fn translate_call_indirect<'a>( - &self, - builder: &'a mut FunctionBuilder, - sig_ref: SigRef, - index_val: Value, - call_args: &[Value], - ) -> &'a [Value] { - let trap_ebb = builder.create_ebb(); - let continue_ebb = builder.create_ebb(); - let size_val = builder.ins().iconst(I32, self.tables[0].info.size as i64); - let zero_val = builder.ins().iconst(I32, 0); - builder.ins().br_icmp( - IntCC::UnsignedLessThan, - index_val, - zero_val, - trap_ebb, - &[], + + fn declare_func_import(&mut self, sig_index: SignatureIndex, module: &[u8], field: &[u8]) { + debug_assert_eq!( + self.func_types.len(), + self.imported_funcs.len(), + "Imported functions must be declared first" ); - builder.ins().br_icmp( - IntCC::UnsignedGreaterThanOrEqual, - index_val, - size_val, - trap_ebb, - &[], - ); - builder.seal_block(trap_ebb); - let offset_val = builder.ins().imul_imm(index_val, 4); - let base_table_addr: i64 = unsafe { transmute(self.tables[0].data.as_ptr()) }; - let table_addr_val = builder.ins().iconst(I32, base_table_addr); - let table_entry_addr_val = builder.ins().iadd(table_addr_val, offset_val); - let memflags = MemFlags::new(); - let memoffset = Offset32::new(0); - let table_entry_val = builder.ins().load( - I32, - memflags, - table_entry_addr_val, - memoffset, - ); - let call_inst = builder.ins().call_indirect( - sig_ref, - table_entry_val, - call_args, - ); - builder.ins().jump(continue_ebb, &[]); - builder.seal_block(continue_ebb); - builder.switch_to_block(trap_ebb, &[]); - builder.ins().trap(); - builder.switch_to_block(continue_ebb, &[]); - builder.inst_results(call_inst) + self.func_types.push(sig_index); + + // TODO: name_fold and concatenation with '_' are lossy; figure out something better. + let mut name = Vec::new(); + name.extend(module.iter().cloned().map(name_fold)); + name.push(b'_'); + name.extend(field.iter().cloned().map(name_fold)); + self.imported_funcs.push(ir::FunctionName::new(name)); + } + + fn declare_func_type(&mut self, sig_index: SignatureIndex) { + self.func_types.push(sig_index); } fn begin_translation(&mut self) { @@ -270,9 +327,14 @@ impl WasmRuntime for StandaloneRuntime { fn next_function(&mut self) { self.has_current_memory = None; self.has_grow_memory = None; + self.func_indices.clear(); } fn declare_global(&mut self, global: Global) { debug_assert!(!self.instantiated); + debug_assert!( + self.globals.info.is_empty(), + "multiple globals not supported yet" + ); self.globals.info.push(GlobalInfo { global: global, offset: 0, @@ -343,3 +405,12 @@ impl StandaloneRuntime { &self.globals.data[offset..offset + len] } } + +// Generate characters suitable for printable `FuncName`s. +fn name_fold(c: u8) -> u8 { + if (c as char).is_alphanumeric() { + c + } else { + b'_' + } +} diff --git a/src/main.rs b/src/main.rs index 9b1b1d8a3e..d6a6030dac 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,6 +6,7 @@ //! and tables, then emitting the translated code with hardcoded addresses to memory. extern crate cton_wasm; +extern crate cton_native; extern crate wasmstandalone; extern crate wasmparser; extern crate cretonne; @@ -16,8 +17,7 @@ extern crate serde_derive; extern crate term; extern crate tempdir; -use cton_wasm::{translate_module, TranslationResult, FunctionTranslation, DummyRuntime, - WasmRuntime}; +use cton_wasm::{translate_module, TranslationResult}; use wasmstandalone::{StandaloneRuntime, compile_module, execute}; use std::path::PathBuf; use wasmparser::{Parser, ParserState, WasmDecoder, SectionCode}; @@ -31,6 +31,7 @@ use cretonne::ir; use cretonne::ir::entities::AnyEntity; use cretonne::isa::TargetIsa; use cretonne::verifier; +use cretonne::settings; use std::fs::File; use std::error::Error; use std::io; @@ -106,10 +107,14 @@ fn main() { }) .unwrap_or_else(|e| e.exit()); let mut terminal = term::stdout().unwrap(); + let (flag_builder, isa_builder) = cton_native::builders().unwrap_or_else(|_| { + panic!("host machine is not a supported target"); + }); + let isa = isa_builder.finish(settings::Flags::new(&flag_builder)); for filename in &args.arg_file { let path = Path::new(&filename); let name = path.as_os_str().to_string_lossy(); - match handle_module(&args, path.to_path_buf(), &name) { + match handle_module(&args, path.to_path_buf(), &name, &*isa) { Ok(()) => {} Err(message) => { terminal.fg(term::color::RED).unwrap(); @@ -121,7 +126,7 @@ fn main() { } } -fn handle_module(args: &Args, path: PathBuf, name: &str) -> Result<(), String> { +fn handle_module(args: &Args, path: PathBuf, name: &str, isa: &TargetIsa) -> Result<(), String> { let mut terminal = term::stdout().unwrap(); terminal.fg(term::color::YELLOW).unwrap(); vprint!(args.flag_verbose, "Handling: "); @@ -172,15 +177,9 @@ fn handle_module(args: &Args, path: PathBuf, name: &str) -> Result<(), String> { } } }; - let mut dummy_runtime = DummyRuntime::new(); - let mut standalone_runtime = StandaloneRuntime::new(); + let mut runtime = StandaloneRuntime::with_flags(isa.flags().clone()); let translation = { - let runtime: &mut WasmRuntime = if args.flag_execute { - &mut standalone_runtime - } else { - &mut dummy_runtime - }; - match translate_module(&data, runtime) { + match translate_module(&data, &mut runtime) { Ok(x) => x, Err(string) => { return Err(string); @@ -195,14 +194,9 @@ fn handle_module(args: &Args, path: PathBuf, name: &str) -> Result<(), String> { vprint!(args.flag_verbose, "Checking... "); terminal.reset().unwrap(); for func in &translation.functions { - let il = match *func { - FunctionTranslation::Import() => continue, - FunctionTranslation::Code { ref il, .. } => il.clone(), - }; - match verifier::verify_function(&il, None) { - Ok(()) => (), - Err(ref err) => return Err(pretty_verifier_error(&il, None, err)), - } + verifier::verify_function(func, isa).map_err(|err| { + pretty_verifier_error(func, Some(isa), &err) + })?; } terminal.fg(term::color::GREEN).unwrap(); vprintln!(args.flag_verbose, " ok"); @@ -211,7 +205,14 @@ fn handle_module(args: &Args, path: PathBuf, name: &str) -> Result<(), String> { if args.flag_print { let mut writer1 = stdout(); let mut writer2 = stdout(); - match pretty_print_translation(&name, &data, &translation, &mut writer1, &mut writer2) { + match pretty_print_translation( + &name, + &data, + &translation, + &mut writer1, + &mut writer2, + isa, + ) { Err(error) => return Err(String::from(error.description())), Ok(()) => (), } @@ -221,33 +222,29 @@ fn handle_module(args: &Args, path: PathBuf, name: &str) -> Result<(), String> { vprint!(args.flag_verbose, "Optimizing... "); terminal.reset().unwrap(); for func in &translation.functions { - let il = match *func { - FunctionTranslation::Import() => continue, - FunctionTranslation::Code { ref il, .. } => il.clone(), - }; let mut loop_analysis = LoopAnalysis::new(); let mut cfg = ControlFlowGraph::new(); - cfg.compute(&il); + cfg.compute(&func); let mut domtree = DominatorTree::new(); - domtree.compute(&il, &cfg); - loop_analysis.compute(&il, &cfg, &domtree); + domtree.compute(&func, &cfg); + loop_analysis.compute(&func, &cfg, &domtree); let mut context = Context::new(); - context.func = il; + context.func = func.clone(); // TODO: Avoid this clone. context.cfg = cfg; context.domtree = domtree; context.loop_analysis = loop_analysis; - match verifier::verify_context(&context.func, &context.cfg, &context.domtree, None) { + match verifier::verify_context(&context.func, &context.cfg, &context.domtree, isa) { Ok(()) => (), Err(ref err) => { - return Err(pretty_verifier_error(&context.func, None, err)); + return Err(pretty_verifier_error(&context.func, Some(isa), err)); } }; - match context.licm() { + match context.licm(isa) { Ok(())=> (), Err(error) => { match error { CtonError::Verifier(ref err) => { - return Err(pretty_verifier_error(&context.func, None, err)); + return Err(pretty_verifier_error(&context.func, Some(isa), err)); } CtonError::InvalidInput | CtonError::ImplLimitExceeded | @@ -255,9 +252,9 @@ fn handle_module(args: &Args, path: PathBuf, name: &str) -> Result<(), String> { } } }; - match verifier::verify_context(&context.func, &context.cfg, &context.domtree, None) { + match verifier::verify_context(&context.func, &context.cfg, &context.domtree, isa) { Ok(()) => (), - Err(ref err) => return Err(pretty_verifier_error(&context.func, None, err)), + Err(ref err) => return Err(pretty_verifier_error(&context.func, Some(isa), err)), } } terminal.fg(term::color::GREEN).unwrap(); @@ -268,7 +265,7 @@ fn handle_module(args: &Args, path: PathBuf, name: &str) -> Result<(), String> { terminal.fg(term::color::MAGENTA).unwrap(); vprint!(args.flag_verbose, "Compiling... "); terminal.reset().unwrap(); - match compile_module(&translation) { + match compile_module(&translation, isa, &runtime) { Ok(ref exec) => { terminal.fg(term::color::GREEN).unwrap(); vprintln!(args.flag_verbose, "ok"); @@ -314,7 +311,7 @@ fn handle_module(args: &Args, path: PathBuf, name: &str) -> Result<(), String> { if split.len() != 3 { break; } - let memory = standalone_runtime.inspect_memory( + let memory = runtime.inspect_memory( str::parse(split[0]).unwrap(), str::parse(split[1]).unwrap(), str::parse(split[2]).unwrap(), @@ -341,14 +338,12 @@ fn pretty_print_translation( translation: &TranslationResult, writer_wast: &mut Write, writer_cretonne: &mut Write, + isa: &TargetIsa, ) -> Result<(), io::Error> { let mut terminal = term::stdout().unwrap(); let mut parser = Parser::new(data); let mut parser_writer = Writer::new(writer_wast); - let imports_count = translation.functions.iter().fold(0, |acc, f| match f { - &FunctionTranslation::Import() => acc + 1, - &FunctionTranslation::Code { .. } => acc, - }); + let imports_count = translation.function_imports_count; match parser.read() { s @ &ParserState::BeginWasm { .. } => parser_writer.write(s)?, _ => panic!("modules should begin properly"), @@ -401,10 +396,8 @@ fn pretty_print_translation( } let mut function_string = format!( " {}", - match translation.functions[function_index + imports_count] { - FunctionTranslation::Code { ref il, .. } => il, - FunctionTranslation::Import() => panic!("should not happen"), - }.display(None) + translation.functions[function_index + imports_count] + .display(isa) ); function_string.pop(); let function_str = str::replace(function_string.as_str(), "\n", "\n ");