Change translate_module to use FuncTranslator.
This commit is contained in:
committed by
Jakob Stoklund Olesen
parent
95e2566d6f
commit
de27abcb2b
@@ -11,6 +11,6 @@ license = "Apache-2.0"
|
|||||||
name = "cton_wasm"
|
name = "cton_wasm"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
wasmparser = "0.9.4"
|
wasmparser = "0.10.0"
|
||||||
cretonne = { path = "../cretonne" }
|
cretonne = { path = "../cretonne" }
|
||||||
cretonne-frontend = { path = "../frontend" }
|
cretonne-frontend = { path = "../frontend" }
|
||||||
|
|||||||
@@ -21,90 +21,18 @@
|
|||||||
//!
|
//!
|
||||||
//! That is why `translate_function_body` takes an object having the `WasmRuntime` trait as
|
//! That is why `translate_function_body` takes an object having the `WasmRuntime` trait as
|
||||||
//! argument.
|
//! argument.
|
||||||
use cretonne::ir::{self, Function, Signature, Type, InstBuilder, FunctionName, Ebb, MemFlags,
|
use cretonne::ir::{self, InstBuilder, Ebb, MemFlags, JumpTableData};
|
||||||
JumpTableData};
|
|
||||||
use cretonne::ir::types::*;
|
use cretonne::ir::types::*;
|
||||||
use cretonne::ir::immediates::{Ieee32, Ieee64};
|
|
||||||
use cretonne::ir::condcodes::{IntCC, FloatCC};
|
use cretonne::ir::condcodes::{IntCC, FloatCC};
|
||||||
use cton_frontend::{ILBuilder, FunctionBuilder};
|
use cton_frontend::FunctionBuilder;
|
||||||
use wasmparser::{Parser, Operator, WasmDecoder, MemoryImmediate};
|
use wasmparser::{Operator, MemoryImmediate};
|
||||||
use translation_utils::{f32_translation, f64_translation, type_to_type, translate_type, Local};
|
use translation_utils::{f32_translation, f64_translation, type_to_type, translate_type, Local};
|
||||||
use translation_utils::{TableIndex, SignatureIndex, FunctionIndex, MemoryIndex};
|
use translation_utils::{TableIndex, SignatureIndex, FunctionIndex, MemoryIndex};
|
||||||
use state::{TranslationState, ControlStackFrame};
|
use state::{TranslationState, ControlStackFrame};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use runtime::{FuncEnvironment, GlobalValue, WasmRuntime};
|
use runtime::{FuncEnvironment, GlobalValue};
|
||||||
use std::u32;
|
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<HashMap<FunctionIndex, String>>,
|
|
||||||
il_builder: &mut ILBuilder<Local>,
|
|
||||||
runtime: &mut WasmRuntime,
|
|
||||||
) -> Result<Function, String> {
|
|
||||||
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
|
/// Translates wasm operators into Cretonne IL instructions. Returns `true` if it inserted
|
||||||
/// a return.
|
/// a return.
|
||||||
pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
||||||
|
|||||||
@@ -59,10 +59,20 @@ impl FuncTranslator {
|
|||||||
code: &[u8],
|
code: &[u8],
|
||||||
func: &mut ir::Function,
|
func: &mut ir::Function,
|
||||||
environ: &mut FE,
|
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<FE: FuncEnvironment + ?Sized>(
|
||||||
|
&mut self,
|
||||||
|
mut reader: BinaryReader,
|
||||||
|
func: &mut ir::Function,
|
||||||
|
environ: &mut FE,
|
||||||
) -> CtonResult {
|
) -> CtonResult {
|
||||||
dbg!(
|
dbg!(
|
||||||
"translate({} bytes, {}{})",
|
"translate({} bytes, {}{})",
|
||||||
code.len(),
|
reader.bytes_remaining(),
|
||||||
func.name,
|
func.name,
|
||||||
func.signature
|
func.signature
|
||||||
);
|
);
|
||||||
@@ -81,8 +91,7 @@ impl FuncTranslator {
|
|||||||
let exit_block = builder.create_ebb();
|
let exit_block = builder.create_ebb();
|
||||||
self.state.initialize(&builder.func.signature, exit_block);
|
self.state.initialize(&builder.func.signature, exit_block);
|
||||||
|
|
||||||
let reader = &mut BinaryReader::new(code);
|
parse_local_decls(&mut reader, builder, num_args)?;
|
||||||
parse_local_decls(reader, builder, num_args)?;
|
|
||||||
parse_function_body(reader, builder, &mut self.state, environ)
|
parse_function_body(reader, builder, &mut self.state, environ)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -120,12 +129,15 @@ fn parse_local_decls(
|
|||||||
num_args: usize,
|
num_args: usize,
|
||||||
) -> CtonResult {
|
) -> CtonResult {
|
||||||
let mut next_local = num_args;
|
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 {
|
for _ in 0..local_count {
|
||||||
let (count, ty) = reader.read_local_decl().map_err(
|
let (count, ty) = reader.read_local_decl(&mut locals_total).map_err(|_| {
|
||||||
|_| CtonError::InvalidInput,
|
CtonError::InvalidInput
|
||||||
)?;
|
})?;
|
||||||
declare_locals(builder, count, ty, &mut next_local)?;
|
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
|
/// This assumes that the local variable declarations have already been parsed and function
|
||||||
/// arguments and locals are declared in the builder.
|
/// arguments and locals are declared in the builder.
|
||||||
fn parse_function_body<FE: FuncEnvironment + ?Sized>(
|
fn parse_function_body<FE: FuncEnvironment + ?Sized>(
|
||||||
reader: &mut BinaryReader,
|
mut reader: BinaryReader,
|
||||||
builder: &mut FunctionBuilder<Local>,
|
builder: &mut FunctionBuilder<Local>,
|
||||||
state: &mut TranslationState,
|
state: &mut TranslationState,
|
||||||
environ: &mut FE,
|
environ: &mut FE,
|
||||||
@@ -192,10 +204,13 @@ fn parse_function_body<FE: FuncEnvironment + ?Sized>(
|
|||||||
//
|
//
|
||||||
// If the exit block is unreachable, it may not have the correct arguments, so we would
|
// 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.
|
// generate a return instruction that doesn't match the signature.
|
||||||
|
debug_assert!(builder.is_pristine());
|
||||||
if !builder.is_unreachable() {
|
if !builder.is_unreachable() {
|
||||||
builder.ins().return_(state.stack.as_slice());
|
builder.ins().return_(&state.stack);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
debug_assert!(reader.eof());
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,11 +5,11 @@ use sections_translator::{SectionParsingError, parse_function_signatures, parse_
|
|||||||
parse_function_section, parse_export_section, parse_memory_section,
|
parse_function_section, parse_export_section, parse_memory_section,
|
||||||
parse_global_section, parse_table_section, parse_elements_section,
|
parse_global_section, parse_table_section, parse_elements_section,
|
||||||
parse_data_section};
|
parse_data_section};
|
||||||
use translation_utils::{type_to_type, Import, SignatureIndex, FunctionIndex};
|
use translation_utils::{Import, SignatureIndex, FunctionIndex};
|
||||||
use cretonne::ir::{Function, Type};
|
use cretonne::ir::{Function, FunctionName};
|
||||||
use code_translator::translate_function_body;
|
use func_translator::FuncTranslator;
|
||||||
use cton_frontend::ILBuilder;
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::error::Error;
|
||||||
use runtime::WasmRuntime;
|
use runtime::WasmRuntime;
|
||||||
|
|
||||||
/// Output of the [`translate_module`](fn.translate_module.html) function.
|
/// Output of the [`translate_module`](fn.translate_module.html) function.
|
||||||
@@ -198,38 +198,27 @@ pub fn translate_module(
|
|||||||
Some(functions) => functions,
|
Some(functions) => functions,
|
||||||
};
|
};
|
||||||
let mut il_functions: Vec<Function> = Vec::new();
|
let mut il_functions: Vec<Function> = Vec::new();
|
||||||
let mut il_builder = ILBuilder::new();
|
let mut trans = FuncTranslator::new();
|
||||||
runtime.begin_translation();
|
runtime.begin_translation();
|
||||||
loop {
|
loop {
|
||||||
let locals: Vec<(usize, Type)> = match *parser.read() {
|
match *parser.read() {
|
||||||
ParserState::BeginFunctionBody { ref locals, .. } => {
|
ParserState::BeginFunctionBody { .. } => {}
|
||||||
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()
|
|
||||||
}
|
|
||||||
ParserState::EndSection => break,
|
ParserState::EndSection => break,
|
||||||
_ => return Err(String::from("wrong content in code section")),
|
_ => return Err(String::from("wrong content in code section")),
|
||||||
};
|
}
|
||||||
let signature = signatures[functions[function_index]].clone();
|
runtime.next_function();
|
||||||
let il_func = translate_function_body(
|
// First we build the Function object with its name and signature
|
||||||
&mut parser,
|
let mut func = Function::new();
|
||||||
function_index,
|
func.signature = signatures[functions[function_index]].clone();
|
||||||
&signature,
|
if let Some(ref exports) = exports {
|
||||||
&locals,
|
if let Some(name) = exports.get(&function_index) {
|
||||||
&exports,
|
func.name = FunctionName::new(name.clone());
|
||||||
&mut il_builder,
|
}
|
||||||
runtime,
|
}
|
||||||
)?;
|
trans
|
||||||
il_functions.push(il_func);
|
.translate_from_reader(parser.create_binary_reader(), &mut func, runtime)
|
||||||
|
.map_err(|e| String::from(e.description()))?;
|
||||||
|
il_functions.push(func);
|
||||||
function_index += 1;
|
function_index += 1;
|
||||||
}
|
}
|
||||||
loop {
|
loop {
|
||||||
|
|||||||
Reference in New Issue
Block a user