Wasm control stack entries only need the number of return types.

This eliminates heap-allocated vectors which stored the actual types.
This commit is contained in:
Dan Gohman
2017-09-25 12:48:31 -07:00
parent 55e48ce7aa
commit 36585ddc4f
4 changed files with 44 additions and 46 deletions

View File

@@ -26,7 +26,7 @@ use cretonne::ir::types::*;
use cretonne::ir::condcodes::{IntCC, FloatCC};
use cton_frontend::FunctionBuilder;
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, num_return_values, Local};
use translation_utils::{TableIndex, SignatureIndex, FunctionIndex, MemoryIndex};
use state::{TranslationState, ControlStackFrame};
use std::collections::HashMap;
@@ -122,7 +122,7 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
if let Ok(ty_cre) = type_to_type(&ty) {
builder.append_ebb_arg(next, ty_cre);
}
state.push_block(next, translate_type(ty));
state.push_block(next, num_return_values(ty));
}
Operator::Loop { ty } => {
let loop_body = builder.create_ebb();
@@ -131,7 +131,7 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
builder.append_ebb_arg(next, ty_cre);
}
builder.ins().jump(loop_body, &[]);
state.push_loop(loop_body, next, translate_type(ty));
state.push_loop(loop_body, next, num_return_values(ty));
builder.switch_to_block(loop_body, &[]);
}
Operator::If { ty } => {
@@ -147,7 +147,7 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
if let Ok(ty_cre) = type_to_type(&ty) {
builder.append_ebb_arg(if_not, ty_cre);
}
state.push_if(jump_inst, if_not, translate_type(ty));
state.push_if(jump_inst, if_not, num_return_values(ty));
}
Operator::Else => {
// We take the control frame pushed by the if, use its ebb as the else body
@@ -157,10 +157,10 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
let (destination, return_count, branch_inst) = match state.control_stack[i] {
ControlStackFrame::If {
destination,
ref return_values,
num_return_values,
branch_inst,
..
} => (destination, return_values.len(), branch_inst),
} => (destination, num_return_values, branch_inst),
_ => panic!("should not happen"),
};
builder.ins().jump(destination, state.peekn(return_count));
@@ -173,15 +173,14 @@ 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.return_values().len();
builder.ins().jump(
frame.following_code(),
state.peekn(return_count),
);
state.popn(return_count);
}
builder.switch_to_block(frame.following_code(), frame.return_values());
builder.switch_to_block(frame.following_code(), state.peekn(return_count));
builder.seal_block(frame.following_code());
// If it is a loop we also have to seal the body loop block
match frame {
@@ -223,7 +222,7 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
let return_count = if frame.is_loop() {
0
} else {
frame.return_values().len()
frame.num_return_values()
};
(return_count, frame.br_destination())
};
@@ -245,7 +244,7 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
let return_count = if frame.is_loop() {
0
} else {
frame.return_values().len()
frame.num_return_values()
};
(return_count, frame.br_destination())
};
@@ -269,7 +268,7 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
if min_depth_frame.is_loop() {
0
} else {
min_depth_frame.return_values().len()
min_depth_frame.num_return_values()
}
};
if jump_args_count == 0 {
@@ -334,7 +333,7 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
let (return_count, br_destination) = {
let frame = &mut state.control_stack[0];
frame.set_reachable();
let return_count = frame.return_values().len();
let return_count = frame.num_return_values();
(return_count, frame.br_destination())
};
{

View File

@@ -3,7 +3,7 @@
//! The `TranslationState` struct defined in this module is used to keep track of the WebAssembly
//! value and control stacks during the translation of a single function.
use cretonne::ir::{self, Ebb, Inst, Type, Value};
use cretonne::ir::{self, Ebb, Inst, Value};
use runtime::{FuncEnvironment, GlobalValue};
use std::collections::HashMap;
use translation_utils::{GlobalIndex, MemoryIndex, SignatureIndex, FunctionIndex};
@@ -12,7 +12,7 @@ use translation_utils::{GlobalIndex, MemoryIndex, SignatureIndex, FunctionIndex}
/// fields:
///
/// - `destination`: reference to the `Ebb` that will hold the code after the control block;
/// - `return_values`: types of the values returned by the control block;
/// - `num_return_values`: number of values returned by the control block;
/// - `original_stack_size`: size of the value stack at the beginning of the control block.
///
/// Moreover, the `if` frame has the `branch_inst` field that points to the `brz` instruction
@@ -23,20 +23,20 @@ pub enum ControlStackFrame {
If {
destination: Ebb,
branch_inst: Inst,
return_values: Vec<Type>,
num_return_values: usize,
original_stack_size: usize,
reachable: bool,
},
Block {
destination: Ebb,
return_values: Vec<Type>,
num_return_values: usize,
original_stack_size: usize,
reachable: bool,
},
Loop {
destination: Ebb,
header: Ebb,
return_values: Vec<Type>,
num_return_values: usize,
original_stack_size: usize,
reachable: bool,
},
@@ -44,11 +44,11 @@ pub enum ControlStackFrame {
/// Helper methods for the control stack objects.
impl ControlStackFrame {
pub fn return_values(&self) -> &[Type] {
pub fn num_return_values(&self) -> usize {
match *self {
ControlStackFrame::If { ref return_values, .. } |
ControlStackFrame::Block { ref return_values, .. } |
ControlStackFrame::Loop { ref return_values, .. } => &return_values,
ControlStackFrame::If { num_return_values, .. } |
ControlStackFrame::Block { num_return_values, .. } |
ControlStackFrame::Loop { num_return_values, .. } => num_return_values,
}
}
pub fn following_code(&self) -> Ebb {
@@ -161,8 +161,7 @@ impl TranslationState {
sig.return_types
.iter()
.filter(|arg| arg.purpose == ir::ArgumentPurpose::Normal)
.map(|argty| argty.value_type)
.collect(),
.count(),
);
}
@@ -215,33 +214,33 @@ impl TranslationState {
}
// Push a block on the control stack.
pub fn push_block(&mut self, following_code: Ebb, result_types: Vec<Type>) {
pub fn push_block(&mut self, following_code: Ebb, num_result_types: usize) {
self.control_stack.push(ControlStackFrame::Block {
destination: following_code,
original_stack_size: self.stack.len(),
return_values: result_types,
num_return_values: num_result_types,
reachable: false,
});
}
// Push a loop on the control stack.
pub fn push_loop(&mut self, header: Ebb, following_code: Ebb, result_types: Vec<Type>) {
pub fn push_loop(&mut self, header: Ebb, following_code: Ebb, num_result_types: usize) {
self.control_stack.push(ControlStackFrame::Loop {
header,
destination: following_code,
original_stack_size: self.stack.len(),
return_values: result_types,
num_return_values: num_result_types,
reachable: false,
});
}
// Push an if on the control stack.
pub fn push_if(&mut self, branch_inst: Inst, following_code: Ebb, result_types: Vec<Type>) {
pub fn push_if(&mut self, branch_inst: Inst, following_code: Ebb, num_result_types: usize) {
self.control_stack.push(ControlStackFrame::If {
branch_inst,
destination: following_code,
original_stack_size: self.stack.len(),
return_values: result_types,
num_return_values: num_result_types,
reachable: false,
});
}

View File

@@ -119,13 +119,13 @@ pub fn f64_translation(x: wasmparser::Ieee64) -> cretonne::ir::immediates::Ieee6
}
/// Translate a `wasmparser` type into its `Cretonne` equivalent, when possible
pub fn translate_type(ty: wasmparser::Type) -> Vec<cretonne::ir::Type> {
pub fn num_return_values(ty: wasmparser::Type) -> usize {
match ty {
wasmparser::Type::EmptyBlockType => Vec::new(),
wasmparser::Type::I32 => vec![cretonne::ir::types::I32],
wasmparser::Type::F32 => vec![cretonne::ir::types::F32],
wasmparser::Type::I64 => vec![cretonne::ir::types::I64],
wasmparser::Type::F64 => vec![cretonne::ir::types::F64],
wasmparser::Type::EmptyBlockType => 0,
wasmparser::Type::I32 |
wasmparser::Type::F32 |
wasmparser::Type::I64 |
wasmparser::Type::F64 => 1,
_ => panic!("unsupported return value type"),
}
}