Fix nondeterminism in br_table translation.

This commit is contained in:
Dan Gohman
2017-11-07 15:33:35 -08:00
parent 15aff899ee
commit 849f090562

View File

@@ -22,7 +22,7 @@
//! //!
//! That is why `translate_function_body` takes an object having the `WasmRuntime` trait as //! That is why `translate_function_body` takes an object having the `WasmRuntime` trait as
//! argument. //! argument.
use cretonne::ir::{self, InstBuilder, Ebb, MemFlags, JumpTableData}; use cretonne::ir::{self, InstBuilder, MemFlags, JumpTableData};
use cretonne::ir::types::*; use cretonne::ir::types::*;
use cretonne::ir::condcodes::{IntCC, FloatCC}; use cretonne::ir::condcodes::{IntCC, FloatCC};
use cton_frontend::FunctionBuilder; use cton_frontend::FunctionBuilder;
@@ -30,7 +30,7 @@ use wasmparser::{Operator, MemoryImmediate};
use translation_utils::{f32_translation, f64_translation, type_to_type, num_return_values, Local}; use translation_utils::{f32_translation, f64_translation, type_to_type, num_return_values, Local};
use translation_utils::{TableIndex, SignatureIndex, FunctionIndex, MemoryIndex}; use translation_utils::{TableIndex, SignatureIndex, FunctionIndex, MemoryIndex};
use state::{TranslationState, ControlStackFrame}; use state::{TranslationState, ControlStackFrame};
use std::collections::HashMap; use std::collections::{HashMap, hash_map};
use environ::{FuncEnvironment, GlobalValue}; use environ::{FuncEnvironment, GlobalValue};
use std::u32; use std::u32;
@@ -297,25 +297,26 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
let val = state.pop1(); let val = state.pop1();
let return_count = 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 mut dest_ebb_sequence = Vec::new();
&depth| { let mut dest_ebb_map = HashMap::new();
if acc.get(&(depth as usize)).is_none() { for depth in depths {
let branch_ebb = builder.create_ebb(); let branch_ebb = match dest_ebb_map.entry(depth as usize) {
data.push_entry(branch_ebb); hash_map::Entry::Occupied(entry) => *entry.get(),
acc.insert(depth as usize, branch_ebb); hash_map::Entry::Vacant(entry) => {
return acc; let ebb = builder.create_ebb();
dest_ebb_sequence.push((depth as usize, ebb));
*entry.insert(ebb)
}
}; };
let branch_ebb = acc[&(depth as usize)];
data.push_entry(branch_ebb); data.push_entry(branch_ebb);
acc }
});
let jt = builder.create_jump_table(data); let jt = builder.create_jump_table(data);
builder.ins().br_table(val, jt); builder.ins().br_table(val, jt);
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.peekn(return_count)); builder.ins().jump(default_ebb, state.peekn(return_count));
for (depth, dest_ebb) in dest_ebbs { for (depth, dest_ebb) in dest_ebb_sequence {
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;