Fix branching out of loops and improve tracking
This commit is contained in:
parent
a6cf4fdf07
commit
941bb4842b
@ -82,6 +82,24 @@ impl<'a> TypeInfo<'a> {
|
|||||||
self.arity_of(*adjusted)
|
self.arity_of(*adjusted)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn block_arity_of(&self, typ: BlockType) -> Arity {
|
||||||
|
match typ {
|
||||||
|
BlockType::NoResult => Arity {
|
||||||
|
num_param: 0,
|
||||||
|
num_result: 0,
|
||||||
|
},
|
||||||
|
BlockType::Value(_) => Arity {
|
||||||
|
num_param: 0,
|
||||||
|
num_result: 1,
|
||||||
|
},
|
||||||
|
BlockType::TypeIndex(i) => {
|
||||||
|
let id = i.try_into().unwrap();
|
||||||
|
|
||||||
|
self.arity_of(id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn func_of_import(import: &ImportEntry) -> Option<usize> {
|
fn func_of_import(import: &ImportEntry) -> Option<usize> {
|
||||||
if let &External::Function(i) = import.external() {
|
if let &External::Function(i) = import.external() {
|
||||||
Some(i.try_into().unwrap())
|
Some(i.try_into().unwrap())
|
||||||
@ -110,17 +128,35 @@ impl<'a> TypeInfo<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum BlockVariant {
|
||||||
|
Forward,
|
||||||
|
Backward,
|
||||||
|
If,
|
||||||
|
Else,
|
||||||
|
}
|
||||||
|
|
||||||
|
enum BlockData {
|
||||||
|
Forward { num_result: usize },
|
||||||
|
Backward { num_param: usize },
|
||||||
|
If { num_result: usize, typ: BlockType },
|
||||||
|
Else { num_result: usize },
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for BlockData {
|
||||||
|
fn default() -> Self {
|
||||||
|
BlockData::Forward { num_result: 0 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct StatList {
|
struct StatList {
|
||||||
stack: Vec<Expression>,
|
stack: Vec<Expression>,
|
||||||
code: Vec<Statement>,
|
code: Vec<Statement>,
|
||||||
last: Option<Terminator>,
|
last: Option<Terminator>,
|
||||||
|
|
||||||
num_result: usize,
|
block_data: BlockData,
|
||||||
num_param: usize,
|
|
||||||
num_stack: usize,
|
num_stack: usize,
|
||||||
num_previous: usize,
|
num_previous: usize,
|
||||||
is_else: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StatList {
|
impl StatList {
|
||||||
@ -376,26 +412,29 @@ impl<'a> Builder<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_block(&mut self, typ: BlockType, stat: Statement) {
|
fn start_block(&mut self, typ: BlockType, variant: BlockVariant) {
|
||||||
let (num_param, num_result) = match typ {
|
let Arity {
|
||||||
BlockType::NoResult => (0, 0),
|
num_param,
|
||||||
BlockType::Value(_) => (0, 1),
|
num_result,
|
||||||
BlockType::TypeIndex(i) => {
|
} = self.type_info.block_arity_of(typ);
|
||||||
let id = i.try_into().unwrap();
|
|
||||||
let arity = self.type_info.arity_of(id);
|
|
||||||
|
|
||||||
(arity.num_param, arity.num_result)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut old = std::mem::take(&mut self.target);
|
let mut old = std::mem::take(&mut self.target);
|
||||||
|
|
||||||
old.leak_all();
|
old.leak_all();
|
||||||
old.code.push(stat);
|
|
||||||
|
self.target.block_data = match variant {
|
||||||
|
BlockVariant::Forward => BlockData::Forward { num_result },
|
||||||
|
BlockVariant::Backward => BlockData::Backward { num_param },
|
||||||
|
BlockVariant::If => BlockData::If { num_result, typ },
|
||||||
|
BlockVariant::Else => {
|
||||||
|
old.pop_len(num_result);
|
||||||
|
old.push_temporary(num_param);
|
||||||
|
|
||||||
|
BlockData::Else { num_result }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
self.target.stack = old.pop_len(num_param);
|
self.target.stack = old.pop_len(num_param);
|
||||||
self.target.num_result = num_result;
|
|
||||||
self.target.num_param = num_param;
|
|
||||||
self.target.num_previous = old.num_previous + old.stack.len();
|
self.target.num_previous = old.num_previous + old.stack.len();
|
||||||
|
|
||||||
old.push_temporary(num_result);
|
old.push_temporary(num_result);
|
||||||
@ -404,22 +443,15 @@ impl<'a> Builder<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn start_else(&mut self) {
|
fn start_else(&mut self) {
|
||||||
let mut temp = StatList {
|
let typ = if let BlockData::If { typ, .. } = self.target.block_data {
|
||||||
num_result: self.target.num_result,
|
typ
|
||||||
num_param: self.target.num_param,
|
} else {
|
||||||
num_stack: self.target.num_stack,
|
unreachable!()
|
||||||
num_previous: self.target.num_previous,
|
|
||||||
is_else: true,
|
|
||||||
..Default::default()
|
|
||||||
};
|
};
|
||||||
|
|
||||||
temp.push_temporary(temp.num_param);
|
self.target.leak_all();
|
||||||
|
|
||||||
self.end_block();
|
self.end_block();
|
||||||
|
self.start_block(typ, BlockVariant::Else);
|
||||||
let old = std::mem::replace(&mut self.target, temp);
|
|
||||||
|
|
||||||
self.pending.push(old);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn end_block(&mut self) {
|
fn end_block(&mut self) {
|
||||||
@ -428,13 +460,26 @@ impl<'a> Builder<'a> {
|
|||||||
|
|
||||||
self.target.num_stack = now.num_stack;
|
self.target.num_stack = now.num_stack;
|
||||||
|
|
||||||
match self.target.code.last_mut().unwrap() {
|
let stat = match now.block_data {
|
||||||
Statement::Forward(data) => *data = now.into(),
|
BlockData::Forward { .. } => Statement::Forward(now.into()),
|
||||||
Statement::Backward(data) => *data = now.into(),
|
BlockData::Backward { .. } => Statement::Backward(now.into()),
|
||||||
Statement::If(data) if !now.is_else => data.truthy = now.into(),
|
BlockData::If { .. } => Statement::If(If {
|
||||||
Statement::If(data) if now.is_else => data.falsey = Some(now.into()),
|
cond: self.target.pop_required(),
|
||||||
_ => unreachable!(),
|
truthy: now.into(),
|
||||||
}
|
falsey: None,
|
||||||
|
}),
|
||||||
|
BlockData::Else { .. } => {
|
||||||
|
if let Statement::If(v) = self.target.code.last_mut().unwrap() {
|
||||||
|
v.falsey = Some(now.into());
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
self.target.code.push(stat);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_relative_block(&self, index: usize) -> Option<&StatList> {
|
fn get_relative_block(&self, index: usize) -> Option<&StatList> {
|
||||||
@ -447,7 +492,15 @@ impl<'a> Builder<'a> {
|
|||||||
|
|
||||||
fn get_br_terminator(&self, target: usize) -> Br {
|
fn get_br_terminator(&self, target: usize) -> Br {
|
||||||
let (par_start, par_result) = match self.get_relative_block(target) {
|
let (par_start, par_result) = match self.get_relative_block(target) {
|
||||||
Some(v) => (v.num_previous, v.num_result),
|
Some(v) => (
|
||||||
|
v.num_previous,
|
||||||
|
match v.block_data {
|
||||||
|
BlockData::Forward { num_result } => num_result,
|
||||||
|
BlockData::Backward { num_param } => num_param,
|
||||||
|
BlockData::If { num_result, .. } => num_result,
|
||||||
|
BlockData::Else { num_result } => num_result,
|
||||||
|
},
|
||||||
|
),
|
||||||
None => (0, self.num_result),
|
None => (0, self.num_result),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -534,26 +587,18 @@ impl<'a> Builder<'a> {
|
|||||||
}
|
}
|
||||||
Inst::Nop => {}
|
Inst::Nop => {}
|
||||||
Inst::Block(typ) => {
|
Inst::Block(typ) => {
|
||||||
let stat = Statement::Forward(Forward::default());
|
self.start_block(typ, BlockVariant::Forward);
|
||||||
|
|
||||||
self.start_block(typ, stat);
|
|
||||||
}
|
}
|
||||||
Inst::Loop(typ) => {
|
Inst::Loop(typ) => {
|
||||||
let stat = Statement::Backward(Backward::default());
|
self.start_block(typ, BlockVariant::Backward);
|
||||||
|
|
||||||
self.start_block(typ, stat);
|
|
||||||
}
|
}
|
||||||
Inst::If(typ) => {
|
Inst::If(typ) => {
|
||||||
let stat = Statement::If(If {
|
let cond = self.target.pop_required();
|
||||||
cond: self.target.pop_required(),
|
|
||||||
truthy: Forward::default(),
|
|
||||||
falsey: None,
|
|
||||||
});
|
|
||||||
|
|
||||||
self.start_block(typ, stat);
|
self.start_block(typ, BlockVariant::If);
|
||||||
|
self.pending.last_mut().unwrap().stack.push(cond);
|
||||||
}
|
}
|
||||||
Inst::Else => {
|
Inst::Else => {
|
||||||
self.target.leak_all();
|
|
||||||
self.start_else();
|
self.start_else();
|
||||||
}
|
}
|
||||||
Inst::End => {
|
Inst::End => {
|
||||||
@ -726,7 +771,7 @@ impl<'a> Builder<'a> {
|
|||||||
fn build_stat_list(&mut self, list: &[Instruction], num_result: usize) -> StatList {
|
fn build_stat_list(&mut self, list: &[Instruction], num_result: usize) -> StatList {
|
||||||
self.nested_unreachable = 0;
|
self.nested_unreachable = 0;
|
||||||
self.num_result = num_result;
|
self.num_result = num_result;
|
||||||
self.target.num_result = num_result;
|
self.target.block_data = BlockData::Forward { num_result };
|
||||||
|
|
||||||
for inst in list.iter().take(list.len() - 1) {
|
for inst in list.iter().take(list.len() - 1) {
|
||||||
if self.nested_unreachable == 0 {
|
if self.nested_unreachable == 0 {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user