Merge remote-tracking branch 'origin/master' into no_std

This commit is contained in:
Dan Gohman
2018-03-30 15:14:30 -07:00
260 changed files with 4509 additions and 5074 deletions

View File

@@ -1,5 +1,5 @@
//! This module contains the bulk of the interesting code performing the translation between
//! WebAssembly and Cretonne IL.
//! WebAssembly and Cretonne IR.
//!
//! The translation is done in one pass, opcode by opcode. Two main data structures are used during
//! code translations: the value stack and the control stack. The value stack mimics the execution
@@ -22,21 +22,23 @@
//!
//! That is why `translate_function_body` takes an object having the `WasmRuntime` trait as
//! argument.
use cretonne::ir::{self, InstBuilder, MemFlags, JumpTableData};
use cretonne::ir::condcodes::{FloatCC, IntCC};
use cretonne::ir::types::*;
use cretonne::ir::condcodes::{IntCC, FloatCC};
use cretonne::ir::{self, InstBuilder, JumpTableData, MemFlags};
use cretonne::packed_option::ReservedValue;
use cton_frontend::{FunctionBuilder, Variable};
use wasmparser::{Operator, MemoryImmediate};
use translation_utils::{f32_translation, f64_translation, type_to_type, num_return_values};
use translation_utils::{TableIndex, SignatureIndex, FunctionIndex, MemoryIndex};
use state::{TranslationState, ControlStackFrame};
use std::collections::{HashMap, hash_map};
use environ::{FuncEnvironment, GlobalValue};
use std::{i32, u32};
use state::{ControlStackFrame, TranslationState};
use std::collections::{hash_map, HashMap};
use std::vec::Vec;
use std::{i32, u32};
use translation_utils::{FunctionIndex, MemoryIndex, SignatureIndex, TableIndex};
use translation_utils::{num_return_values, type_to_type, f32_translation, f64_translation};
use wasmparser::{MemoryImmediate, Operator};
/// Translates wasm operators into Cretonne IL instructions. Returns `true` if it inserted
// Clippy warns about "flags: _" but its important to document that the flags field is ignored
#[cfg_attr(feature = "cargo-clippy", allow(unneeded_field_pattern))]
/// Translates wasm operators into Cretonne IR instructions. Returns `true` if it inserted
/// a return.
pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
op: Operator,
@@ -45,7 +47,7 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
environ: &mut FE,
) {
if !state.reachable {
return translate_unreachable_operator(op, builder, state);
return translate_unreachable_operator(&op, builder, state);
}
// This big match treats all Wasm code operators.
@@ -73,8 +75,9 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
GlobalValue::Const(val) => val,
GlobalValue::Memory { gv, ty } => {
let addr = builder.ins().global_addr(environ.native_pointer(), gv);
// TODO: It is likely safe to set `aligned notrap` flags on a global load.
let flags = ir::MemFlags::new();
let mut flags = ir::MemFlags::new();
flags.set_notrap();
flags.set_aligned();
builder.ins().load(ty, flags, addr, 0)
}
};
@@ -85,8 +88,9 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
GlobalValue::Const(_) => panic!("global #{} is a constant", global_index),
GlobalValue::Memory { gv, .. } => {
let addr = builder.ins().global_addr(environ.native_pointer(), gv);
// TODO: It is likely safe to set `aligned notrap` flags on a global store.
let flags = ir::MemFlags::new();
let mut flags = ir::MemFlags::new();
flags.set_notrap();
flags.set_aligned();
let val = state.pop1();
builder.ins().store(flags, val, addr, 0);
}
@@ -138,6 +142,7 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
builder.ins().jump(loop_body, &[]);
state.push_loop(loop_body, next, num_return_values(ty));
builder.switch_to_block(loop_body);
environ.translate_loop_header(builder.cursor());
}
Operator::If { ty } => {
let val = state.pop1();
@@ -187,8 +192,8 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
}
Operator::End => {
let frame = state.control_stack.pop().unwrap();
let return_count = frame.num_return_values();
if !builder.is_unreachable() || !builder.is_pristine() {
let return_count = frame.num_return_values();
builder.ins().jump(
frame.following_code(),
state.peekn(return_count),
@@ -197,9 +202,8 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
builder.switch_to_block(frame.following_code());
builder.seal_block(frame.following_code());
// If it is a loop we also have to seal the body loop block
match frame {
ControlStackFrame::Loop { header, .. } => builder.seal_block(header),
_ => {}
if let ControlStackFrame::Loop { header, .. } = frame {
builder.seal_block(header)
}
state.stack.truncate(frame.original_stack_size());
state.stack.extend_from_slice(
@@ -247,27 +251,7 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
state.popn(return_count);
state.reachable = false;
}
Operator::BrIf { relative_depth } => {
let val = state.pop1();
let i = state.control_stack.len() - 1 - (relative_depth as usize);
let (return_count, br_destination) = {
let frame = &mut state.control_stack[i];
// The values returned by the branch are still available for the reachable
// code that comes after it
frame.set_branched_to_exit();
let return_count = if frame.is_loop() {
0
} else {
frame.num_return_values()
};
(return_count, frame.br_destination())
};
builder.ins().brnz(
val,
br_destination,
state.peekn(return_count),
);
}
Operator::BrIf { relative_depth } => translate_br_if(relative_depth, builder, state),
Operator::BrTable { table } => {
let (depths, default) = table.read_table();
let mut min_depth = default;
@@ -765,101 +749,45 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
}
/**************************** Comparison Operators **********************************/
Operator::I32LtS | Operator::I64LtS => {
let (arg1, arg2) = state.pop2();
let val = builder.ins().icmp(IntCC::SignedLessThan, arg1, arg2);
state.push1(builder.ins().bint(I32, val));
translate_icmp(IntCC::SignedLessThan, builder, state)
}
Operator::I32LtU | Operator::I64LtU => {
let (arg1, arg2) = state.pop2();
let val = builder.ins().icmp(IntCC::UnsignedLessThan, arg1, arg2);
state.push1(builder.ins().bint(I32, val));
translate_icmp(IntCC::UnsignedLessThan, builder, state)
}
Operator::I32LeS | Operator::I64LeS => {
let (arg1, arg2) = state.pop2();
let val = builder.ins().icmp(IntCC::SignedLessThanOrEqual, arg1, arg2);
state.push1(builder.ins().bint(I32, val));
translate_icmp(IntCC::SignedLessThanOrEqual, builder, state)
}
Operator::I32LeU | Operator::I64LeU => {
let (arg1, arg2) = state.pop2();
let val = builder.ins().icmp(
IntCC::UnsignedLessThanOrEqual,
arg1,
arg2,
);
state.push1(builder.ins().bint(I32, val));
translate_icmp(IntCC::UnsignedLessThanOrEqual, builder, state)
}
Operator::I32GtS | Operator::I64GtS => {
let (arg1, arg2) = state.pop2();
let val = builder.ins().icmp(IntCC::SignedGreaterThan, arg1, arg2);
state.push1(builder.ins().bint(I32, val));
translate_icmp(IntCC::SignedGreaterThan, builder, state)
}
Operator::I32GtU | Operator::I64GtU => {
let (arg1, arg2) = state.pop2();
let val = builder.ins().icmp(IntCC::UnsignedGreaterThan, arg1, arg2);
state.push1(builder.ins().bint(I32, val));
translate_icmp(IntCC::UnsignedGreaterThan, builder, state)
}
Operator::I32GeS | Operator::I64GeS => {
let (arg1, arg2) = state.pop2();
let val = builder.ins().icmp(
IntCC::SignedGreaterThanOrEqual,
arg1,
arg2,
);
state.push1(builder.ins().bint(I32, val));
translate_icmp(IntCC::SignedGreaterThanOrEqual, builder, state)
}
Operator::I32GeU | Operator::I64GeU => {
let (arg1, arg2) = state.pop2();
let val = builder.ins().icmp(
IntCC::UnsignedGreaterThanOrEqual,
arg1,
arg2,
);
state.push1(builder.ins().bint(I32, val));
translate_icmp(IntCC::UnsignedGreaterThanOrEqual, builder, state)
}
Operator::I32Eqz | Operator::I64Eqz => {
let arg = state.pop1();
let val = builder.ins().icmp_imm(IntCC::Equal, arg, 0);
state.push1(builder.ins().bint(I32, val));
}
Operator::I32Eq | Operator::I64Eq => {
let (arg1, arg2) = state.pop2();
let val = builder.ins().icmp(IntCC::Equal, arg1, arg2);
state.push1(builder.ins().bint(I32, val));
}
Operator::F32Eq | Operator::F64Eq => {
let (arg1, arg2) = state.pop2();
let val = builder.ins().fcmp(FloatCC::Equal, arg1, arg2);
state.push1(builder.ins().bint(I32, val));
}
Operator::I32Ne | Operator::I64Ne => {
let (arg1, arg2) = state.pop2();
let val = builder.ins().icmp(IntCC::NotEqual, arg1, arg2);
state.push1(builder.ins().bint(I32, val));
}
Operator::F32Ne | Operator::F64Ne => {
let (arg1, arg2) = state.pop2();
let val = builder.ins().fcmp(FloatCC::NotEqual, arg1, arg2);
state.push1(builder.ins().bint(I32, val));
}
Operator::F32Gt | Operator::F64Gt => {
let (arg1, arg2) = state.pop2();
let val = builder.ins().fcmp(FloatCC::GreaterThan, arg1, arg2);
state.push1(builder.ins().bint(I32, val));
}
Operator::I32Eq | Operator::I64Eq => translate_icmp(IntCC::Equal, builder, state),
Operator::F32Eq | Operator::F64Eq => translate_fcmp(FloatCC::Equal, builder, state),
Operator::I32Ne | Operator::I64Ne => translate_icmp(IntCC::NotEqual, builder, state),
Operator::F32Ne | Operator::F64Ne => translate_fcmp(FloatCC::NotEqual, builder, state),
Operator::F32Gt | Operator::F64Gt => translate_fcmp(FloatCC::GreaterThan, builder, state),
Operator::F32Ge | Operator::F64Ge => {
let (arg1, arg2) = state.pop2();
let val = builder.ins().fcmp(FloatCC::GreaterThanOrEqual, arg1, arg2);
state.push1(builder.ins().bint(I32, val));
}
Operator::F32Lt | Operator::F64Lt => {
let (arg1, arg2) = state.pop2();
let val = builder.ins().fcmp(FloatCC::LessThan, arg1, arg2);
state.push1(builder.ins().bint(I32, val));
translate_fcmp(FloatCC::GreaterThanOrEqual, builder, state)
}
Operator::F32Lt | Operator::F64Lt => translate_fcmp(FloatCC::LessThan, builder, state),
Operator::F32Le | Operator::F64Le => {
let (arg1, arg2) = state.pop2();
let val = builder.ins().fcmp(FloatCC::LessThanOrEqual, arg1, arg2);
state.push1(builder.ins().bint(I32, val));
translate_fcmp(FloatCC::LessThanOrEqual, builder, state)
}
Operator::Wake { .. } |
Operator::I32Wait { .. } |
@@ -932,15 +860,17 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
}
}
// Clippy warns us of some fields we are deliberately ignoring
#[cfg_attr(feature = "cargo-clippy", allow(unneeded_field_pattern))]
/// Deals with a Wasm instruction located in an unreachable portion of the code. Most of them
/// are dropped but special ones like `End` or `Else` signal the potential end of the unreachable
/// portion so the translation state muts be updated accordingly.
fn translate_unreachable_operator(
op: Operator,
op: &Operator,
builder: &mut FunctionBuilder<Variable>,
state: &mut TranslationState,
) {
match op {
match *op {
Operator::If { ty: _ } => {
// Push a placeholder control stack entry. The if isn't reachable,
// so we don't have any branches anywhere.
@@ -952,27 +882,25 @@ fn translate_unreachable_operator(
}
Operator::Else => {
let i = state.control_stack.len() - 1;
match state.control_stack[i] {
ControlStackFrame::If {
branch_inst,
ref mut reachable_from_top,
..
} => {
if *reachable_from_top {
// We have a branch from the top of the if to the else.
state.reachable = true;
// And because there's an else, there can no longer be a
// branch from the top directly to the end.
*reachable_from_top = false;
if let ControlStackFrame::If {
branch_inst,
ref mut reachable_from_top,
..
} = state.control_stack[i]
{
if *reachable_from_top {
// We have a branch from the top of the if to the else.
state.reachable = true;
// And because there's an else, there can no longer be a
// branch from the top directly to the end.
*reachable_from_top = false;
// We change the target of the branch instruction
let else_ebb = builder.create_ebb();
builder.change_jump_destination(branch_inst, else_ebb);
builder.seal_block(else_ebb);
builder.switch_to_block(else_ebb);
}
// We change the target of the branch instruction
let else_ebb = builder.create_ebb();
builder.change_jump_destination(branch_inst, else_ebb);
builder.seal_block(else_ebb);
builder.switch_to_block(else_ebb);
}
_ => {}
}
}
Operator::End => {
@@ -1016,7 +944,7 @@ fn translate_unreachable_operator(
}
}
// Get the address+offset to use for a heap access.
/// Get the address+offset to use for a heap access.
fn get_heap_addr(
heap: ir::Heap,
addr32: ir::Value,
@@ -1053,7 +981,7 @@ fn get_heap_addr(
}
}
// Translate a load instruction.
/// Translate a load instruction.
fn translate_load<FE: FuncEnvironment + ?Sized>(
offset: u32,
opcode: ir::Opcode,
@@ -1066,6 +994,9 @@ fn translate_load<FE: FuncEnvironment + ?Sized>(
// We don't yet support multiple linear memories.
let heap = state.get_heap(builder.func, 0, environ);
let (base, offset) = get_heap_addr(heap, addr32, offset, environ.native_pointer(), builder);
// Note that we don't set `is_aligned` here, even if the load instruction's
// alignment immediate says it's aligned, because WebAssembly's immediate
// field is just a hint, while Cretonne's aligned flag needs a guarantee.
let flags = MemFlags::new();
let (load, dfg) = builder.ins().Load(
opcode,
@@ -1077,7 +1008,7 @@ fn translate_load<FE: FuncEnvironment + ?Sized>(
state.push1(dfg.first_result(load));
}
// Translate a store instruction.
/// Translate a store instruction.
fn translate_store<FE: FuncEnvironment + ?Sized>(
offset: u32,
opcode: ir::Opcode,
@@ -1091,6 +1022,7 @@ fn translate_store<FE: FuncEnvironment + ?Sized>(
// We don't yet support multiple linear memories.
let heap = state.get_heap(builder.func, 0, environ);
let (base, offset) = get_heap_addr(heap, addr32, offset, environ.native_pointer(), builder);
// See the comments in `translate_load` about the flags.
let flags = MemFlags::new();
builder.ins().Store(
opcode,
@@ -1101,3 +1033,54 @@ fn translate_store<FE: FuncEnvironment + ?Sized>(
base,
);
}
fn translate_icmp(
cc: IntCC,
builder: &mut FunctionBuilder<Variable>,
state: &mut TranslationState,
) {
let (arg0, arg1) = state.pop2();
let val = builder.ins().icmp(cc, arg0, arg1);
state.push1(builder.ins().bint(I32, val));
}
fn translate_fcmp(
cc: FloatCC,
builder: &mut FunctionBuilder<Variable>,
state: &mut TranslationState,
) {
let (arg0, arg1) = state.pop2();
let val = builder.ins().fcmp(cc, arg0, arg1);
state.push1(builder.ins().bint(I32, val));
}
fn translate_br_if(
relative_depth: u32,
builder: &mut FunctionBuilder<Variable>,
state: &mut TranslationState,
) {
let val = state.pop1();
let (br_destination, inputs) = translate_br_if_args(relative_depth, state);
builder.ins().brnz(val, br_destination, inputs);
}
fn translate_br_if_args(
relative_depth: u32,
state: &mut TranslationState,
) -> (ir::Ebb, &[ir::Value]) {
let i = state.control_stack.len() - 1 - (relative_depth as usize);
let (return_count, br_destination) = {
let frame = &mut state.control_stack[i];
// The values returned by the branch are still available for the reachable
// code that comes after it
frame.set_branched_to_exit();
let return_count = if frame.is_loop() {
0
} else {
frame.num_return_values()
};
(return_count, frame.br_destination())
};
let inputs = state.peekn(return_count);
(br_destination, inputs)
}

View File

@@ -1,16 +1,16 @@
//! "Dummy" environment for testing wasm translation.
use environ::{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::ir::types::*;
use cretonne::ir::{self, InstBuilder};
use cretonne::settings;
use wasmparser;
use std::vec::Vec;
use environ::{FuncEnvironment, GlobalValue, ModuleEnvironment};
use func_translator::FuncTranslator;
use std::string::String;
use std::vec::Vec;
use translation_utils::{FunctionIndex, Global, GlobalIndex, Memory, MemoryIndex, SignatureIndex,
Table, TableIndex};
use wasmparser;
/// Compute a `ir::ExternalName` for a given wasm function index.
fn get_func_name(func_index: FunctionIndex) -> ir::ExternalName {
@@ -120,7 +120,7 @@ impl DummyEnvironment {
}
}
/// The FuncEnvironment implementation for use by the `DummyEnvironment`.
/// The `FuncEnvironment` implementation for use by the `DummyEnvironment`.
pub struct DummyFuncEnvironment<'dummy_environment> {
pub mod_info: &'dummy_environment DummyModuleInfo,
}
@@ -208,7 +208,10 @@ impl<'dummy_environment> FuncEnvironment for DummyFuncEnvironment<'dummy_environ
let ext = pos.ins().uextend(I64, callee);
pos.ins().imul_imm(ext, 4)
};
let func_ptr = pos.ins().load(ptr, ir::MemFlags::new(), callee_offset, 0);
let mut mflags = ir::MemFlags::new();
mflags.set_notrap();
mflags.set_aligned();
let func_ptr = pos.ins().load(ptr, mflags, callee_offset, 0);
// Build a value list for the indirect call instruction containing the callee, call_args,
// and the vmctx parameter.

View File

@@ -1,7 +1,7 @@
//! Support for configurable wasm translation.
mod spec;
mod dummy;
mod spec;
pub use environ::spec::{ModuleEnvironment, FuncEnvironment, GlobalValue};
pub use environ::dummy::DummyEnvironment;
pub use environ::spec::{FuncEnvironment, GlobalValue, ModuleEnvironment};

View File

@@ -1,12 +1,12 @@
//! All the runtime support necessary for the wasm to cretonne translation is formalized by the
//! traits `FunctionEnvironment` and `ModuleEnvironment`.
use cretonne::ir::{self, InstBuilder};
use cretonne::cursor::FuncCursor;
use cretonne::ir::{self, InstBuilder};
use cretonne::settings::Flags;
use translation_utils::{SignatureIndex, FunctionIndex, TableIndex, GlobalIndex, MemoryIndex,
Global, Table, Memory};
use std::vec::Vec;
use std::string::String;
use std::vec::Vec;
use translation_utils::{FunctionIndex, Global, GlobalIndex, Memory, MemoryIndex, SignatureIndex,
Table, TableIndex};
/// The value of a WebAssembly global variable.
#[derive(Clone, Copy)]
@@ -26,7 +26,7 @@ pub enum GlobalValue {
/// Environment affecting the translation of a single WebAssembly function.
///
/// A `FuncEnvironment` trait object is required to translate a WebAssembly function to Cretonne
/// IL. The function environment provides information about the WebAssembly module as well as the
/// IR. The function environment provides information about the WebAssembly module as well as the
/// runtime environment.
pub trait FuncEnvironment {
/// Get the flags for the current compilation.
@@ -146,6 +146,14 @@ pub trait FuncEnvironment {
index: MemoryIndex,
heap: ir::Heap,
) -> ir::Value;
/// Emit code at the beginning of every wasm loop.
///
/// This can be used to insert explicit interrupt or safepoint checking at
/// the beginnings of loops.
fn translate_loop_header(&mut self, _pos: FuncCursor) {
// By default, don't emit anything.
}
}
/// An object satisfying the `ModuleEnvironment` trait can be passed as argument to the

View File

@@ -1,26 +1,26 @@
//! Stand-alone WebAssembly to Cretonne IL translator.
//! Stand-alone WebAssembly to Cretonne IR translator.
//!
//! This module defines the `FuncTranslator` type which can translate a single WebAssembly
//! function to Cretonne IL guided by a `FuncEnvironment` which provides information about the
//! function to Cretonne IR guided by a `FuncEnvironment` which provides information about the
//! WebAssembly module and the runtime environment.
use code_translator::translate_operator;
use cretonne::entity::EntityRef;
use cretonne::ir::{self, InstBuilder, Ebb};
use cretonne::result::{CtonResult, CtonError};
use cretonne::ir::{self, Ebb, InstBuilder};
use cretonne::result::{CtonError, CtonResult};
use cretonne::timing;
use cton_frontend::{ILBuilder, FunctionBuilder, Variable};
use cton_frontend::{FunctionBuilder, FunctionBuilderContext, Variable};
use environ::FuncEnvironment;
use state::TranslationState;
use wasmparser::{self, BinaryReader};
/// WebAssembly to Cretonne IL function translator.
/// WebAssembly to Cretonne IR function translator.
///
/// A `FuncTranslator` is used to translate a binary WebAssembly function into Cretonne IL guided
/// A `FuncTranslator` is used to translate a binary WebAssembly function into Cretonne IR guided
/// by a `FuncEnvironment` object. A single translator instance can be reused to translate multiple
/// functions which will reduce heap allocation traffic.
pub struct FuncTranslator {
il_builder: ILBuilder<Variable>,
func_ctx: FunctionBuilderContext<Variable>,
state: TranslationState,
}
@@ -28,7 +28,7 @@ impl FuncTranslator {
/// Create a new translator.
pub fn new() -> Self {
Self {
il_builder: ILBuilder::new(),
func_ctx: FunctionBuilderContext::new(),
state: TranslationState::new(),
}
}
@@ -77,8 +77,8 @@ impl FuncTranslator {
debug_assert_eq!(func.dfg.num_ebbs(), 0, "Function must be empty");
debug_assert_eq!(func.dfg.num_insts(), 0, "Function must be empty");
// This clears the `ILBuilder`.
let mut builder = FunctionBuilder::new(func, &mut self.il_builder);
// This clears the `FunctionBuilderContext`.
let mut builder = FunctionBuilder::new(func, &mut self.func_ctx);
let entry_block = builder.create_ebb();
builder.append_ebb_params_for_function_params(entry_block);
builder.switch_to_block(entry_block); // This also creates values for the arguments.
@@ -232,10 +232,10 @@ fn cur_srcloc(reader: &BinaryReader) -> ir::SourceLoc {
#[cfg(test)]
mod tests {
use cretonne::{ir, Context};
use cretonne::ir::types::I32;
use environ::{DummyEnvironment, FuncEnvironment};
use super::FuncTranslator;
use cretonne::ir::types::I32;
use cretonne::{ir, Context};
use environ::{DummyEnvironment, FuncEnvironment};
#[test]
fn small1() {

View File

@@ -1,5 +1,5 @@
//! 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
//! Performs translation from a wasm module in binary format to the in-memory form
//! of Cretonne IR. More particularly, it translates the code of all the functions bodies and
//! interacts with an environment implementing the
//! [`ModuleEnvironment`](trait.ModuleEnvironment.html)
//! trait to deal with tables, globals and linear memory.
@@ -9,9 +9,9 @@
//!
//! The main function of this module is [`translate_module`](fn.translate_module.html).
#![deny(missing_docs,
trivial_numeric_casts,
unused_extern_crates)]
#![deny(missing_docs, trivial_numeric_casts, unused_extern_crates)]
#![cfg_attr(feature = "clippy", plugin(clippy(conf_file = "../../clippy.toml")))]
#![cfg_attr(feature = "cargo-clippy", allow(new_without_default, redundant_field_names))]
#![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(not(feature = "std"), feature(alloc))]
@@ -24,24 +24,24 @@ extern crate alloc;
#[cfg(not(feature = "std"))]
extern crate hashmap_core;
extern crate wasmparser;
extern crate cton_frontend;
#[macro_use(dbg)]
extern crate cretonne;
extern crate cton_frontend;
extern crate wasmparser;
mod code_translator;
mod environ;
mod func_translator;
mod module_translator;
mod environ;
mod sections_translator;
mod state;
mod translation_utils;
pub use environ::{DummyEnvironment, FuncEnvironment, GlobalValue, ModuleEnvironment};
pub use func_translator::FuncTranslator;
pub use module_translator::translate_module;
pub use environ::{FuncEnvironment, ModuleEnvironment, DummyEnvironment, GlobalValue};
pub use translation_utils::{FunctionIndex, GlobalIndex, TableIndex, MemoryIndex, SignatureIndex,
Global, GlobalInit, Table, Memory};
pub use translation_utils::{FunctionIndex, Global, GlobalIndex, GlobalInit, Memory, MemoryIndex,
SignatureIndex, Table, TableIndex};
#[cfg(not(feature = "std"))]
mod std {

View File

@@ -1,16 +1,16 @@
//! Translation skeleton that traverses the whole WebAssembly module and call helper functions
//! to deal with each part of it.
use cretonne::timing;
use wasmparser::{ParserState, SectionCode, ParserInput, Parser, WasmDecoder, BinaryReaderError};
use sections_translator::{SectionParsingError, parse_function_signatures, parse_import_section,
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 environ::ModuleEnvironment;
use sections_translator::{parse_data_section, parse_elements_section, parse_export_section,
parse_function_section, parse_function_signatures, parse_global_section,
parse_import_section, parse_memory_section, parse_start_section,
parse_table_section, SectionParsingError};
use wasmparser::{BinaryReaderError, Parser, ParserInput, ParserState, SectionCode, WasmDecoder};
use std::string::String;
/// Translate a sequence of bytes forming a valid Wasm binary into a list of valid Cretonne IL
/// Translate a sequence of bytes forming a valid Wasm binary into a list of valid Cretonne IR
/// [`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.

View File

@@ -7,17 +7,17 @@
//! The special case of the initialize expressions for table elements offsets or global variables
//! is handled, according to the semantics of WebAssembly, to only specific expressions that are
//! interpreted on the fly.
use translation_utils::{type_to_type, TableIndex, FunctionIndex, GlobalIndex, SignatureIndex,
MemoryIndex, Global, GlobalInit, Table, TableElementType, Memory};
use cretonne::ir::{Signature, AbiParam, CallConv};
use cretonne;
use wasmparser::{Parser, ParserState, FuncType, ImportSectionEntryType, ExternalKind, WasmDecoder,
MemoryType, Operator};
use wasmparser;
use std::str::from_utf8;
use cretonne::ir::{AbiParam, CallConv, Signature};
use environ::ModuleEnvironment;
use std::vec::Vec;
use std::str::from_utf8;
use std::string::String;
use std::vec::Vec;
use translation_utils::{type_to_type, FunctionIndex, Global, GlobalIndex, GlobalInit, Memory,
MemoryIndex, SignatureIndex, Table, TableElementType, TableIndex};
use wasmparser;
use wasmparser::{ExternalKind, FuncType, ImportSectionEntryType, MemoryType, Operator, Parser,
ParserState, WasmDecoder};
pub enum SectionParsingError {
WrongSectionContent(String),
@@ -36,7 +36,7 @@ pub fn parse_function_signatures(
ref params,
ref returns,
}) => {
let mut sig = Signature::new(CallConv::Native);
let mut sig = Signature::new(CallConv::SystemV);
sig.params.extend(params.iter().map(|ty| {
let cret_arg: cretonne::ir::Type = type_to_type(ty).expect(
"only numeric types are supported in function signatures",

View File

@@ -6,8 +6,8 @@
use cretonne::ir::{self, Ebb, Inst, Value};
use environ::{FuncEnvironment, GlobalValue};
use std::collections::HashMap;
use translation_utils::{GlobalIndex, MemoryIndex, SignatureIndex, FunctionIndex};
use std::vec::Vec;
use translation_utils::{FunctionIndex, GlobalIndex, MemoryIndex, SignatureIndex};
/// A control stack frame can be an `if`, a `block` or a `loop`, each one having the following
/// fields:

View File

@@ -1,7 +1,7 @@
//! Helper functions and structures for the translation.
use wasmparser;
use cretonne;
use std::u32;
use wasmparser;
/// Index of a function (imported or defined) inside the WebAssembly module.
pub type FunctionIndex = usize;