Mirror label_stack.
This commit is contained in:
parent
4e2347b4bf
commit
57251eec79
|
@ -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 {
|
||||||
|
|
Loading…
Reference in New Issue