Browse Source

Roughly update for the recent Cretonne API changes.

Everything builds and simple modules run, though there's still lots more
to do.
pull/3/head
Dan Gohman 7 years ago
parent
commit
cdffc1b50a
  1. 7
      Cargo.toml
  2. 6
      lib/wasmstandalone/Cargo.toml
  3. 146
      lib/wasmstandalone/src/execution.rs
  4. 281
      lib/wasmstandalone/src/standalone.rs
  5. 83
      src/main.rs

7
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" }

6
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"

146
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<ExecutableCode, String> {
pub fn compile_module(
trans_result: &TranslationResult,
isa: &TargetIsa,
runtime: &StandaloneRuntime,
) -> Result<ExecutableCode, String> {
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<ExecutableCode
shared_builder.set("is_64bit", "1").expect(
"Missing 64bits setting",
);
let isa = match isa::lookup("intel") {
Err(_) => {
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<ExecutableCode
let mut code_buf: Vec<u8> = 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<Vec<u8>>) {
fn relocate(
function_imports_count: usize,
functions_metatada: &[FunctionMetaData],
functions_code: &mut Vec<Vec<u8>>,
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
}
}

281
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<RawByte>,
data: Vec<u8>,
info: Vec<GlobalInfo>,
}
struct TableData {
data: Vec<MemoryAddress>,
data: Vec<usize>,
elements: Vec<TableElement>,
info: Table,
}
struct MemoryData {
data: Vec<RawByte>,
data: Vec<u8>,
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<ir::Signature>,
// Types of functions, imported and local.
func_types: Vec<SignatureIndex>,
// Names of imported functions.
imported_funcs: Vec<ir::FunctionName>,
globals: GlobalsData,
tables: Vec<TableData>,
memories: Vec<MemoryData>,
instantiated: bool,
has_current_memory: Option<FuncRef>,
has_grow_memory: Option<FuncRef>,
/// Mapping from cretonne FuncRef to wasm FunctionIndex.
pub func_indices: EntityMap<FuncRef, FunctionIndex>,
the_heap: PackedOption<ir::Heap>,
}
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(),
}
}
}
/// 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<Local>,
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)
impl FuncEnvironment for StandaloneRuntime {
fn flags(&self) -> &settings::Flags {
&self.flags
}
fn translate_set_global(
&self,
builder: &mut FunctionBuilder<Local>,
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 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 translate_memory_base_address(
&self,
builder: &mut FunctionBuilder<Local>,
memory_index: MemoryIndex,
) -> Value {
let addr: i64 = unsafe { transmute(self.memories[memory_index].data.as_ptr()) };
builder.ins().iconst(I64, addr)
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,
builder: &mut FunctionBuilder<Local>,
pages: Value,
) -> Value {
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 = builder.import_signature(Signature {
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)],
});
builder.import_function(ExtFuncData {
pos.func.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()
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, builder: &mut FunctionBuilder<Local>) -> Value {
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 = builder.import_signature(Signature {
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)],
});
builder.import_function(ExtFuncData {
pos.func.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()
let call_inst = pos.ins().call(cur_mem_func, &[]);
*pos.func.dfg.inst_results(call_inst).first().unwrap()
}
fn translate_call_indirect<'a>(
&self,
builder: &'a mut FunctionBuilder<Local>,
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,
&[],
);
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,
}
/// 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 declare_signature(&mut self, sig: &ir::Signature) {
self.signatures.push(sig.clone());
}
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().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'_'
}
}

83
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 ");

Loading…
Cancel
Save