Mirror label_stack.

This commit is contained in:
Sergey Pepyakin 2019-04-05 14:17:15 +02:00
parent 4e2347b4bf
commit 57251eec79
1 changed files with 55 additions and 22 deletions

View File

@ -192,6 +192,9 @@ impl FunctionReader {
&context.value_stack, &context.value_stack,
&mut context.frame_stack, &mut context.frame_stack,
)?; )?;
context
.label_stack
.push(BlockFrameType::Block { end_label });
FunctionReader::read_function_body(&mut context, body.code().elements())?; FunctionReader::read_function_body(&mut context, body.code().elements())?;
assert!(context.frame_stack.is_empty()); assert!(context.frame_stack.is_empty());
@ -648,6 +651,9 @@ struct FunctionValidationContext<'a> {
return_type: BlockType, return_type: BlockType,
/// A sink used to emit optimized code. /// A sink used to emit optimized code.
sink: Sink, sink: Sink,
// TODO: to be moved to the compiler.
label_stack: Vec<BlockFrameType>,
} }
impl<'a> FunctionValidationContext<'a> { impl<'a> FunctionValidationContext<'a> {
@ -667,6 +673,7 @@ impl<'a> FunctionValidationContext<'a> {
frame_stack: StackWithLimit::with_limit(frame_stack_limit), frame_stack: StackWithLimit::with_limit(frame_stack_limit),
return_type: return_type, return_type: return_type,
sink: Sink::with_instruction_capacity(size_estimate), sink: Sink::with_instruction_capacity(size_estimate),
label_stack: Vec::new(),
} }
} }
@ -692,6 +699,7 @@ impl<'a> FunctionValidationContext<'a> {
Block(block_type) => { Block(block_type) => {
let end_label = self.sink.new_label(); let end_label = self.sink.new_label();
push_label( push_label(
StartedWith::Block, StartedWith::Block,
BlockFrameType::Block { end_label }, BlockFrameType::Block { end_label },
@ -700,6 +708,7 @@ impl<'a> FunctionValidationContext<'a> {
&self.value_stack, &self.value_stack,
&mut self.frame_stack, &mut self.frame_stack,
)?; )?;
self.label_stack.push(BlockFrameType::Block { end_label });
} }
Loop(block_type) => { Loop(block_type) => {
// Resolve loop header right away. // Resolve loop header right away.
@ -714,6 +723,7 @@ impl<'a> FunctionValidationContext<'a> {
&self.value_stack, &self.value_stack,
&mut self.frame_stack, &mut self.frame_stack,
)?; )?;
self.label_stack.push(BlockFrameType::Loop { header });
} }
If(block_type) => { If(block_type) => {
// `if_not` will be resolved whenever `End` or `Else` operator will be met. // `if_not` will be resolved whenever `End` or `Else` operator will be met.
@ -734,6 +744,8 @@ impl<'a> FunctionValidationContext<'a> {
&self.value_stack, &self.value_stack,
&mut self.frame_stack, &mut self.frame_stack,
)?; )?;
self.label_stack
.push(BlockFrameType::IfTrue { if_not, end_label });
self.sink.emit_br_eqz(Target { self.sink.emit_br_eqz(Target {
label: if_not, label: if_not,
@ -744,14 +756,24 @@ impl<'a> FunctionValidationContext<'a> {
}); });
} }
Else => { Else => {
let (block_type, if_not, end_label) = { let block_type = {
let top_frame = top_label(&self.frame_stack); let top = top_label(&self.frame_stack);
if top.started_with != StartedWith::If {
return Err(Error("Misplaced else instruction".into()));
}
top.block_type
};
let (if_not, end_label) = match top_frame.frame_type { let (if_not, end_label) = {
// TODO: We will have to place this before validation step to ensure that
// the block type is indeed if_true.
let top_label = self.label_stack.last().unwrap();
let (if_not, end_label) = match *top_label {
BlockFrameType::IfTrue { if_not, end_label } => (if_not, end_label), BlockFrameType::IfTrue { if_not, end_label } => (if_not, end_label),
_ => return Err(Error("Misplaced else instruction".into())), _ => panic!("validation ensures that the top frame is actually if_true"),
}; };
(top_frame.block_type, if_not, end_label) (if_not, end_label)
}; };
// First, we need to finish if-true block: add a jump from the end of the if-true block // First, we need to finish if-true block: add a jump from the end of the if-true block
@ -779,31 +801,41 @@ impl<'a> FunctionValidationContext<'a> {
&self.value_stack, &self.value_stack,
&mut self.frame_stack, &mut self.frame_stack,
)?; )?;
self.label_stack.pop().unwrap();
self.label_stack.push(BlockFrameType::IfFalse { end_label });
} }
End => { End => {
let (started_with, frame_type, block_type) = { let (started_with, block_type) = {
let top = top_label(&self.frame_stack); let top = top_label(&self.frame_stack);
(top.started_with, top.frame_type, top.block_type)
};
if let BlockFrameType::IfTrue { if_not, .. } = frame_type { if top.started_with == StartedWith::If && top.block_type != BlockType::NoResult {
// A `if` without an `else` can't return a result. // A `if` without an `else` can't return a result.
if block_type != BlockType::NoResult {
return Err(Error(format!( return Err(Error(format!(
"If block without else required to have NoResult block type. But it has {:?} type", "If block without else required to have NoResult block type. But it has {:?} type",
block_type top.block_type
))); )));
} }
// Resolve `if_not` label. If the `if's` condition doesn't hold the control will jump (top.started_with, top.block_type)
// to here. };
self.sink.resolve_label(if_not);
}
// Unless it's a loop, resolve the `end_label` position here. {
if started_with != StartedWith::Loop { // TODO: We will have to place this before validation step to ensure that
let end_label = frame_type.end_label(); // the block type is indeed if_true.
self.sink.resolve_label(end_label); let frame_type = self.label_stack.last().unwrap();
if let BlockFrameType::IfTrue { if_not, .. } = *frame_type {
// Resolve `if_not` label. If the `if's` condition doesn't hold the control will jump
// to here.
self.sink.resolve_label(if_not);
}
// Unless it's a loop, resolve the `end_label` position here.
if started_with != StartedWith::Loop {
let end_label = frame_type.end_label();
self.sink.resolve_label(end_label);
}
} }
if self.frame_stack.len() == 1 { if self.frame_stack.len() == 1 {
@ -822,6 +854,7 @@ impl<'a> FunctionValidationContext<'a> {
} }
pop_label(&mut self.value_stack, &mut self.frame_stack)?; pop_label(&mut self.value_stack, &mut self.frame_stack)?;
self.label_stack.pop().unwrap();
// Push the result value. // Push the result value.
if let BlockType::Value(value_type) = block_type { if let BlockType::Value(value_type) = block_type {