|
|
@ -1,6 +1,8 @@ |
|
|
|
use backend::*; |
|
|
|
use error::Error; |
|
|
|
use wasmparser::{FunctionBody, Operator}; |
|
|
|
use wasmparser::{FunctionBody, Operator, Type}; |
|
|
|
|
|
|
|
// TODO: Use own declared `Type` enum.
|
|
|
|
|
|
|
|
/// Type of a control frame.
|
|
|
|
#[derive(Debug, Copy, Clone, PartialEq)] |
|
|
@ -10,6 +12,7 @@ enum ControlFrameKind { |
|
|
|
/// Can be used for an implicit function block.
|
|
|
|
Block { end_label: Label }, |
|
|
|
/// Loop frame (branching to the beginning of block).
|
|
|
|
#[allow(unused)] |
|
|
|
Loop { header: Label }, |
|
|
|
/// True-subblock of if expression.
|
|
|
|
IfTrue { |
|
|
@ -49,20 +52,34 @@ impl ControlFrameKind { |
|
|
|
struct ControlFrame { |
|
|
|
kind: ControlFrameKind, |
|
|
|
/// Boolean which signals whether value stack became polymorphic. Value stack starts in non-polymorphic state and
|
|
|
|
/// becomes polymorphic only after an instruction that never passes control further is executed,
|
|
|
|
/// i.e. `unreachable`, `br` (but not `br_if`!), etc.
|
|
|
|
/// becomes polymorphic only after an instruction that never passes control further is executed,
|
|
|
|
/// i.e. `unreachable`, `br` (but not `br_if`!), etc.
|
|
|
|
stack_polymorphic: bool, |
|
|
|
// TODO: type, stack height, etc
|
|
|
|
/// Relative stack depth at the beginning of the frame.
|
|
|
|
stack_depth: StackDepth, |
|
|
|
ty: Type, |
|
|
|
} |
|
|
|
|
|
|
|
impl ControlFrame { |
|
|
|
pub fn new(kind: ControlFrameKind) -> ControlFrame { |
|
|
|
pub fn new(kind: ControlFrameKind, stack_depth: StackDepth, ty: Type) -> ControlFrame { |
|
|
|
ControlFrame { |
|
|
|
kind, |
|
|
|
stack_depth, |
|
|
|
ty, |
|
|
|
stack_polymorphic: false, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
pub fn outgoing_stack_depth(&self) -> StackDepth { |
|
|
|
let mut outgoing_stack_depth = self.stack_depth; |
|
|
|
if self.ty != Type::EmptyBlockType { |
|
|
|
// If there a return value then increment expected outgoing stack depth value
|
|
|
|
// to account for the result value.
|
|
|
|
outgoing_stack_depth.increment(); |
|
|
|
} |
|
|
|
outgoing_stack_depth |
|
|
|
} |
|
|
|
|
|
|
|
/// Marks this control frame as reached stack-polymorphic state.
|
|
|
|
pub fn mark_stack_polymorphic(&mut self) { |
|
|
|
self.stack_polymorphic = true; |
|
|
@ -75,6 +92,7 @@ pub fn translate(session: &mut CodeGenSession, body: &FunctionBody) -> Result<() |
|
|
|
// Assume signature is (i32, i32) -> i32 for now.
|
|
|
|
// TODO: Use a real signature
|
|
|
|
const ARG_COUNT: u32 = 2; |
|
|
|
let return_ty = Type::I32; |
|
|
|
|
|
|
|
let mut framesize = ARG_COUNT; |
|
|
|
for local in locals { |
|
|
@ -100,6 +118,8 @@ pub fn translate(session: &mut CodeGenSession, body: &FunctionBody) -> Result<() |
|
|
|
ControlFrameKind::Block { |
|
|
|
end_label: epilogue_label, |
|
|
|
}, |
|
|
|
current_stack_depth(&ctx), |
|
|
|
return_ty, |
|
|
|
)); |
|
|
|
|
|
|
|
for op in operators { |
|
|
@ -114,24 +134,63 @@ pub fn translate(session: &mut CodeGenSession, body: &FunctionBody) -> Result<() |
|
|
|
Operator::If { ty } => { |
|
|
|
let end_label = create_label(&mut ctx); |
|
|
|
let if_not = create_label(&mut ctx); |
|
|
|
|
|
|
|
pop_and_breq(&mut ctx, if_not); |
|
|
|
|
|
|
|
control_frames.push(ControlFrame::new( |
|
|
|
ControlFrameKind::IfTrue { |
|
|
|
end_label, |
|
|
|
if_not, |
|
|
|
}, |
|
|
|
ControlFrameKind::IfTrue { end_label, if_not }, |
|
|
|
current_stack_depth(&ctx), |
|
|
|
ty, |
|
|
|
)); |
|
|
|
|
|
|
|
// TODO: Generate code that pops a value and executes the if_true part if the value
|
|
|
|
// is not equal to zero.
|
|
|
|
} |
|
|
|
Operator::Else => { |
|
|
|
match control_frames.pop() { |
|
|
|
Some(ControlFrame { |
|
|
|
kind: ControlFrameKind::IfTrue { if_not, end_label }, |
|
|
|
ty, |
|
|
|
stack_depth, |
|
|
|
.. |
|
|
|
}) => { |
|
|
|
// Finalize if..else block by jumping to the `end_label`.
|
|
|
|
br(&mut ctx, end_label); |
|
|
|
|
|
|
|
// Define `if_not` label here, so if the corresponding `if` block receives
|
|
|
|
// 0 it will branch here.
|
|
|
|
// After that reset stack depth to the value before entering `if` block.
|
|
|
|
define_label(&mut ctx, if_not); |
|
|
|
restore_stack_depth(&mut ctx, stack_depth); |
|
|
|
|
|
|
|
// Carry over the `end_label`, so it will be resolved when the corresponding `end`
|
|
|
|
// is encountered.
|
|
|
|
//
|
|
|
|
// Also note that we reset `stack_depth` to the value before entering `if` block.
|
|
|
|
let mut frame = ControlFrame::new( |
|
|
|
ControlFrameKind::IfFalse { end_label }, |
|
|
|
stack_depth, |
|
|
|
ty, |
|
|
|
); |
|
|
|
control_frames.push(frame); |
|
|
|
} |
|
|
|
Some(_) => panic!("else expects if block"), |
|
|
|
None => panic!("control stack is never empty"), |
|
|
|
}; |
|
|
|
} |
|
|
|
Operator::End => { |
|
|
|
let control_frame = control_frames.pop().expect("control stack is never empty"); |
|
|
|
|
|
|
|
if !control_frame.kind.is_loop() { |
|
|
|
// Branches to a control frame with block type directs control flow to the header of the loop
|
|
|
|
// Branches to a control frame with block type directs control flow to the header of the loop
|
|
|
|
// and we don't need to resolve it here. Branching to other control frames always lead
|
|
|
|
// control flow to the corresponding `end`.
|
|
|
|
define_label(&mut ctx, control_frame.kind.br_destination()); |
|
|
|
} |
|
|
|
|
|
|
|
if let ControlFrameKind::IfTrue { if_not, .. } = control_frame.kind { |
|
|
|
// this is `if .. end` construction. Define the `if_not` label here.
|
|
|
|
define_label(&mut ctx, if_not); |
|
|
|
} |
|
|
|
|
|
|
|
restore_stack_depth(&mut ctx, control_frame.outgoing_stack_depth()); |
|
|
|
} |
|
|
|
Operator::I32Eq => { |
|
|
|
relop_eq_i32(&mut ctx); |
|
|
|