<commit_before>//! This module contains the bulk of the interesting code performing the translation between
//! WebAssembly and Cretonne IL.
//!
//! 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
//! of the WebAssembly stack machine: each instruction result is pushed onto the stack and
//! instruction arguments are popped off the stack. Similarly, when encountering a control flow
//! block, it is pushed onto the control stack and popped off when encountering the corresponding
//! `End`.
//!
//! Another data structure, the translation state, records information concerning unreachable code
//! status and about if inserting a return at the end of the function is necessary.
//!
//! Some of the WebAssembly instructions need information about the runtime to be translated:
//!
//! - the loads and stores need the memory base address;
//! - the `get_global` et `set_global` instructions depends on how the globals are implemented;
//! - `current_memory` and `grow_memory` are runtime functions;
//! - `call_indirect` has to translate the function index into the address of where this
//!    is;
//!
//! That is why `translate_function_body` takes an object having the `WasmRuntime` trait as
//! argument.
use cretonne::ir::{self, Function, Signature, Type, InstBuilder, FunctionName, Ebb, MemFlags,
                   JumpTableData};
use cretonne::ir::types::*;
use cretonne::ir::immediates::{Ieee32, Ieee64};
use cretonne::ir::condcodes::{IntCC, FloatCC};
use cton_frontend::{ILBuilder, FunctionBuilder};
use wasmparser::{Parser, ParserState, Operator, WasmDecoder, MemoryImmediate};
use translation_utils::{f32_translation, f64_translation, type_to_type, translate_type, Local};
use translation_utils::{TableIndex, SignatureIndex, FunctionIndex, MemoryIndex};
use state::{TranslationState, ControlStackFrame};
use std::collections::HashMap;
use runtime::{FuncEnvironment, GlobalValue, WasmRuntime};
use 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
        loop {
            let parser_state = parser.read();
            match *parser_state {
                ParserState::CodeOperator(ref op) => {
                    translate_operator(op, &mut builder, &mut state, runtime)
                }

                ParserState::EndFunctionBody => break,
                _ => return Err(String::from("wrong content in function body")),
            }
        }
        // In WebAssembly, the final return instruction is implicit so we need to build it
        // explicitely in Cretonne IL.
        if !builder.is_filled() && (!builder.is_unreachable() || !builder.is_pristine()) {
            let cut_index = state.stack.len() - sig.return_types.len();
            builder.ins().return_(&state.stack[cut_index..]);
            state.stack.truncate(cut_index);
        }
        // Because the function has an implicit block as body, we need to explicitely close it.
        let frame = state.control_stack.pop().unwrap();
        builder.switch_to_block(frame.following_code(), frame.return_values());
        builder.seal_block(frame.following_code());
        // If the block is reachable we also have to include a return instruction in it.
        if !builder.is_unreachable() {
            state.stack.truncate(frame.original_stack_size());
            state.stack.extend_from_slice(
                builder.ebb_args(frame.following_code()),
            );
            let cut_index = state.stack.len() - sig.return_types.len();
            builder.ins().return_(&state.stack[cut_index..]);
            state.stack.truncate(cut_index);
        }
    }
    Ok(func)
}

/// Translates wasm operators into Cretonne IL instructions. Returns `true` if it inserted
/// a return.
pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
    op: &Operator,
    builder: &mut FunctionBuilder<Local>,
    state: &mut TranslationState,
    environ: &mut FE,
) {
    if state.in_unreachable_code() {
        return translate_unreachable_operator(op, builder, state);
    }

    // This big match treats all Wasm code operators.
    match *op {
        /********************************** Locals ****************************************
         *  `get_local` and `set_local` are treated as non-SSA variables and will completely
         *  diseappear in the Cretonne Code
         ***********************************************************************************/
        Operator::GetLocal { local_index } => state.push1(builder.use_var(Local(local_index))),
        Operator::SetLocal { local_index } => {
            let val = state.pop1();<commit_msg>Switch to wasmparser's create_binary_reader() API for reading function bodies.<commit_after>//! This module contains the bulk of the interesting code performing the translation between
//! WebAssembly and Cretonne IL.
//!
//! 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
//! of the WebAssembly stack machine: each instruction result is pushed onto the stack and
//! instruction arguments are popped off the stack. Similarly, when encountering a control flow
//! block, it is pushed onto the control stack and popped off when encountering the corresponding
//! `End`.
//!
//! Another data structure, the translation state, records information concerning unreachable code
//! status and about if inserting a return at the end of the function is necessary.
//!
//! Some of the WebAssembly instructions need information about the runtime to be translated:
//!
//! - the loads and stores need the memory base address;
//! - the `get_global` et `set_global` instructions depends on how the globals are implemented;
//! - `current_memory` and `grow_memory` are runtime functions;
//! - `call_indirect` has to translate the function index into the address of where this
//!    is;
//!
//! That is why `translate_function_body` takes an object having the `WasmRuntime` trait as
//! argument.
use cretonne::ir::{self, Function, Signature, Type, InstBuilder, FunctionName, Ebb, MemFlags,
                   JumpTableData};
use cretonne::ir::types::*;
use cretonne::ir::immediates::{Ieee32, Ieee64};
use cretonne::ir::condcodes::{IntCC, FloatCC};
use cton_frontend::{ILBuilder, FunctionBuilder};
use wasmparser::{Parser, Operator, WasmDecoder, MemoryImmediate};
use translation_utils::{f32_translation, f64_translation, type_to_type, translate_type, Local};
use translation_utils::{TableIndex, SignatureIndex, FunctionIndex, MemoryIndex};
use state::{TranslationState, ControlStackFrame};
use std::collections::HashMap;
use runtime::{FuncEnvironment, GlobalValue, WasmRuntime};
use 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
/// a return.
pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
    op: &Operator,
    builder: &mut FunctionBuilder<Local>,
    state: &mut TranslationState,
    environ: &mut FE,
) {
    if state.in_unreachable_code() {
        return translate_unreachable_operator(op, builder, state);
    }

    // This big match treats all Wasm code operators.
    match *op {
        /********************************** Locals ****************************************
         *  `get_local` and `set_local` are treated as non-SSA variables and will completely
         *  diseappear in the Cretonne Code
         ***********************************************************************************/
        Operator::GetLocal { local_index } => state.push1(builder.use_var(Local(local_index))),
        Operator::SetLocal { local_index } => {
            let val = state.pop1();
{'fraction_non_alphanumeric': 0.128684290489213, 'fraction_numerical': 0.006532968702522029, 'mean_word_length': 2.9737398128584362, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 34, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1760973', 'n_tokens_mistral': 3646, 'n_tokens_neox': 3509, 'n_words': 1145}