wasm: Remove duplicated parameters when popping an If

Parameters are duplicated when pushing an If block, so they're available
to the Else block without an extra heap allocation. However, when
truncating the stack after popping the If control frame, the stack size
at entry doesn't account for the duplicated parameters. That is
intentional: the Else block uses this value to know what's the stack
size when it is entered, so there's nothing to change there.

This patch makes the wasm translation truncates the value stack to the
right size after an If block, by taking those duplicated parameters into
account.
This commit is contained in:
Benjamin Bouvier
2020-09-11 13:12:48 +02:00
parent ae6693a638
commit 518b7a7e23
2 changed files with 47 additions and 1 deletions

View File

@@ -323,13 +323,33 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
// since we truncate the stack back to the original height
// below.
}
builder.switch_to_block(next_block);
builder.seal_block(next_block);
// If it is a loop we also have to seal the body loop block
if let ControlStackFrame::Loop { header, .. } = frame {
builder.seal_block(header)
}
state.stack.truncate(frame.original_stack_size());
// The "If" frame pushes its parameters twice, so they're available to the else block
// (see also `FuncTranslationState::push_if`).
// Yet, the original_stack_size member accounts for them only once, so that the else
// block can see the same number of parameters as the consequent block. As a matter of
// fact, we need to substract an extra number of parameter values for if blocks.
let num_duplicated_params = if let ControlStackFrame::If {
num_param_values, ..
} = frame
{
debug_assert!(num_param_values <= frame.original_stack_size());
num_param_values
} else {
0
};
state
.stack
.truncate(frame.original_stack_size() - num_duplicated_params);
state
.stack
.extend_from_slice(builder.block_params(next_block));