Use TranslationState's popn/peekn functions. (#151)
This entailed reorganizing surrounding code to minimize the extent of mutable borrows of the control-flow stack.
This commit is contained in:
@@ -224,18 +224,17 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
|||||||
// and push a new control frame with a new ebb for the code after the if/then/else
|
// and push a new control frame with a new ebb for the code after the if/then/else
|
||||||
// At the end of the then clause we jump to the destination
|
// At the end of the then clause we jump to the destination
|
||||||
let i = state.control_stack.len() - 1;
|
let i = state.control_stack.len() - 1;
|
||||||
let (destination, return_values, branch_inst) = match state.control_stack[i] {
|
let (destination, return_count, branch_inst) = match state.control_stack[i] {
|
||||||
ControlStackFrame::If {
|
ControlStackFrame::If {
|
||||||
destination,
|
destination,
|
||||||
ref return_values,
|
ref return_values,
|
||||||
branch_inst,
|
branch_inst,
|
||||||
..
|
..
|
||||||
} => (destination, return_values, branch_inst),
|
} => (destination, return_values.len(), branch_inst),
|
||||||
_ => panic!("should not happen"),
|
_ => panic!("should not happen"),
|
||||||
};
|
};
|
||||||
let cut_index = state.stack.len() - return_values.len();
|
builder.ins().jump(destination, state.peekn(return_count));
|
||||||
builder.ins().jump(destination, &state.stack[cut_index..]);
|
state.popn(return_count);
|
||||||
state.stack.truncate(cut_index);
|
|
||||||
// We change the target of the branch instruction
|
// We change the target of the branch instruction
|
||||||
let else_ebb = builder.create_ebb();
|
let else_ebb = builder.create_ebb();
|
||||||
builder.change_jump_destination(branch_inst, else_ebb);
|
builder.change_jump_destination(branch_inst, else_ebb);
|
||||||
@@ -245,12 +244,12 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
|||||||
Operator::End => {
|
Operator::End => {
|
||||||
let frame = state.control_stack.pop().unwrap();
|
let frame = state.control_stack.pop().unwrap();
|
||||||
if !builder.is_unreachable() || !builder.is_pristine() {
|
if !builder.is_unreachable() || !builder.is_pristine() {
|
||||||
let cut_index = state.stack.len() - frame.return_values().len();
|
let return_count = frame.return_values().len();
|
||||||
builder.ins().jump(
|
builder.ins().jump(
|
||||||
frame.following_code(),
|
frame.following_code(),
|
||||||
&state.stack[cut_index..],
|
state.peekn(return_count),
|
||||||
);
|
);
|
||||||
state.stack.truncate(cut_index);
|
state.popn(return_count);
|
||||||
}
|
}
|
||||||
builder.switch_to_block(frame.following_code(), frame.return_values());
|
builder.switch_to_block(frame.following_code(), frame.return_values());
|
||||||
builder.seal_block(frame.following_code());
|
builder.seal_block(frame.following_code());
|
||||||
@@ -287,40 +286,44 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
|||||||
***********************************************************************************/
|
***********************************************************************************/
|
||||||
Operator::Br { relative_depth } => {
|
Operator::Br { relative_depth } => {
|
||||||
let i = state.control_stack.len() - 1 - (relative_depth as usize);
|
let i = state.control_stack.len() - 1 - (relative_depth as usize);
|
||||||
let frame = &mut state.control_stack[i];
|
let (return_count, br_destination) = {
|
||||||
let cut_index = state.stack.len() -
|
let frame = &mut state.control_stack[i];
|
||||||
if frame.is_loop() {
|
// We signal that all the code that follows until the next End is unreachable
|
||||||
|
frame.set_reachable();
|
||||||
|
let return_count = if frame.is_loop() {
|
||||||
0
|
0
|
||||||
} else {
|
} else {
|
||||||
frame.return_values().len()
|
frame.return_values().len()
|
||||||
};
|
};
|
||||||
|
(return_count, frame.br_destination())
|
||||||
|
};
|
||||||
builder.ins().jump(
|
builder.ins().jump(
|
||||||
frame.br_destination(),
|
br_destination,
|
||||||
&state.stack[cut_index..],
|
state.peekn(return_count),
|
||||||
);
|
);
|
||||||
state.stack.truncate(cut_index);
|
state.popn(return_count);
|
||||||
// We signal that all the code that follows until the next End is unreachable
|
|
||||||
frame.set_reachable();
|
|
||||||
state.real_unreachable_stack_depth = 1 + relative_depth as usize;
|
state.real_unreachable_stack_depth = 1 + relative_depth as usize;
|
||||||
}
|
}
|
||||||
Operator::BrIf { relative_depth } => {
|
Operator::BrIf { relative_depth } => {
|
||||||
let val = state.pop1();
|
let val = state.pop1();
|
||||||
let i = state.control_stack.len() - 1 - (relative_depth as usize);
|
let i = state.control_stack.len() - 1 - (relative_depth as usize);
|
||||||
let frame = &mut state.control_stack[i];
|
let (return_count, br_destination) = {
|
||||||
let cut_index = state.stack.len() -
|
let frame = &mut state.control_stack[i];
|
||||||
if frame.is_loop() {
|
// The values returned by the branch are still available for the reachable
|
||||||
|
// code that comes after it
|
||||||
|
frame.set_reachable();
|
||||||
|
let return_count = if frame.is_loop() {
|
||||||
0
|
0
|
||||||
} else {
|
} else {
|
||||||
frame.return_values().len()
|
frame.return_values().len()
|
||||||
};
|
};
|
||||||
|
(return_count, frame.br_destination())
|
||||||
|
};
|
||||||
builder.ins().brnz(
|
builder.ins().brnz(
|
||||||
val,
|
val,
|
||||||
frame.br_destination(),
|
br_destination,
|
||||||
&state.stack[cut_index..],
|
state.peekn(return_count),
|
||||||
);
|
);
|
||||||
// The values returned by the branch are still available for the reachable
|
|
||||||
// code that comes after it
|
|
||||||
frame.set_reachable();
|
|
||||||
}
|
}
|
||||||
Operator::BrTable { ref table } => {
|
Operator::BrTable { ref table } => {
|
||||||
let (depths, default) = table.read_table();
|
let (depths, default) = table.read_table();
|
||||||
@@ -362,7 +365,7 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
|||||||
// Here we have jump arguments, but Cretonne's br_table doesn't support them
|
// Here we have jump arguments, but Cretonne's br_table doesn't support them
|
||||||
// We then proceed to split the edges going out of the br_table
|
// We then proceed to split the edges going out of the br_table
|
||||||
let val = state.pop1();
|
let val = state.pop1();
|
||||||
let cut_index = state.stack.len() - jump_args_count;
|
let return_count = jump_args_count;
|
||||||
let mut data = JumpTableData::with_capacity(depths.len());
|
let mut data = JumpTableData::with_capacity(depths.len());
|
||||||
let dest_ebbs: HashMap<usize, Ebb> = depths.iter().fold(HashMap::new(), |mut acc,
|
let dest_ebbs: HashMap<usize, Ebb> = depths.iter().fold(HashMap::new(), |mut acc,
|
||||||
&depth| {
|
&depth| {
|
||||||
@@ -381,25 +384,26 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
|||||||
let default_ebb = state.control_stack[state.control_stack.len() - 1 -
|
let default_ebb = state.control_stack[state.control_stack.len() - 1 -
|
||||||
(default as usize)]
|
(default as usize)]
|
||||||
.br_destination();
|
.br_destination();
|
||||||
builder.ins().jump(default_ebb, &state.stack[cut_index..]);
|
builder.ins().jump(default_ebb, state.peekn(return_count));
|
||||||
for (depth, dest_ebb) in dest_ebbs {
|
for (depth, dest_ebb) in dest_ebbs {
|
||||||
builder.switch_to_block(dest_ebb, &[]);
|
builder.switch_to_block(dest_ebb, &[]);
|
||||||
builder.seal_block(dest_ebb);
|
builder.seal_block(dest_ebb);
|
||||||
let i = state.control_stack.len() - 1 - depth;
|
let i = state.control_stack.len() - 1 - depth;
|
||||||
let frame = &mut state.control_stack[i];
|
let real_dest_ebb = {
|
||||||
let real_dest_ebb = frame.br_destination();
|
let frame = &mut state.control_stack[i];
|
||||||
builder.ins().jump(real_dest_ebb, &state.stack[cut_index..]);
|
frame.set_reachable();
|
||||||
frame.set_reachable();
|
frame.br_destination()
|
||||||
|
};
|
||||||
|
builder.ins().jump(real_dest_ebb, state.peekn(return_count));
|
||||||
}
|
}
|
||||||
state.stack.truncate(cut_index);
|
state.popn(return_count);
|
||||||
state.real_unreachable_stack_depth = 1 + min_depth as usize;
|
state.real_unreachable_stack_depth = 1 + min_depth as usize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Operator::Return => {
|
Operator::Return => {
|
||||||
let return_count = state.control_stack[0].return_values().len();
|
let return_count = state.control_stack[0].return_values().len();
|
||||||
let cut_index = state.stack.len() - return_count;
|
builder.ins().return_(state.peekn(return_count));
|
||||||
builder.ins().return_(&state.stack[cut_index..]);
|
state.popn(return_count);
|
||||||
state.stack.truncate(cut_index);
|
|
||||||
state.real_unreachable_stack_depth = 1;
|
state.real_unreachable_stack_depth = 1;
|
||||||
}
|
}
|
||||||
/************************************ Calls ****************************************
|
/************************************ Calls ****************************************
|
||||||
@@ -429,7 +433,7 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
|||||||
index as SignatureIndex,
|
index as SignatureIndex,
|
||||||
sigref,
|
sigref,
|
||||||
callee,
|
callee,
|
||||||
&state.peekn(num_args),
|
state.peekn(num_args),
|
||||||
);
|
);
|
||||||
state.popn(num_args);
|
state.popn(num_args);
|
||||||
state.pushn(builder.func.dfg.inst_results(call));
|
state.pushn(builder.func.dfg.inst_results(call));
|
||||||
|
|||||||
Reference in New Issue
Block a user