Better unreachability handling.

This commit is contained in:
Chris Fallin 2022-11-29 13:22:04 -08:00
parent 35ecc79136
commit 232b34f66b
No known key found for this signature in database
GPG key ID: 31649E4FE65EB465
4 changed files with 227 additions and 165 deletions

View file

@ -238,7 +238,6 @@ impl<'a> WasmFuncBackend<'a> {
ty: sig_index.index() as u32, ty: sig_index.index() as u32,
table: table_index.index() as u32, table: table_index.index() as u32,
}), }),
Operator::Return => Some(wasm_encoder::Instruction::Return),
Operator::Select => Some(wasm_encoder::Instruction::Select), Operator::Select => Some(wasm_encoder::Instruction::Select),
Operator::TypedSelect { ty } => Some(wasm_encoder::Instruction::TypedSelect( Operator::TypedSelect { ty } => Some(wasm_encoder::Instruction::TypedSelect(
wasm_encoder::ValType::from(*ty), wasm_encoder::ValType::from(*ty),

View file

@ -301,7 +301,7 @@ fn parse_body<'a>(
let entry = Block::new(0); let entry = Block::new(0);
builder.body.entry = entry; builder.body.entry = entry;
builder.locals.seal_block_preds(entry, &mut builder.body); builder.locals.seal_block_preds(entry, &mut builder.body);
builder.locals.start_block(entry); builder.locals.start_block(entry, false);
for (arg_idx, &arg_ty) in module.signature(my_sig).params.iter().enumerate() { for (arg_idx, &arg_ty) in module.signature(my_sig).params.iter().enumerate() {
let local_idx = Local::new(arg_idx); let local_idx = Local::new(arg_idx);
@ -321,10 +321,14 @@ fn parse_body<'a>(
let ops = body.get_operators_reader()?; let ops = body.get_operators_reader()?;
for op in ops.into_iter() { for op in ops.into_iter() {
let op = op?; let op = op?;
builder.handle_op(op)?; if builder.reachable {
builder.handle_op(op)?;
} else {
builder.handle_op_unreachable(op)?;
}
} }
if builder.cur_block.is_some() { if builder.reachable {
builder.handle_op(wasmparser::Operator::Return)?; builder.handle_op(wasmparser::Operator::Return)?;
} }
@ -346,7 +350,7 @@ struct LocalTracker {
/// Types of locals, as declared. /// Types of locals, as declared.
types: FxHashMap<Local, Type>, types: FxHashMap<Local, Type>,
/// The current block. /// The current block.
cur_block: Option<Block>, cur_block: Block,
/// Is the given block sealed? /// Is the given block sealed?
block_sealed: FxHashSet<Block>, block_sealed: FxHashSet<Block>,
/// The local-to-value mapping at the start of a block. /// The local-to-value mapping at the start of a block.
@ -363,19 +367,18 @@ impl LocalTracker {
assert!(!was_present); assert!(!was_present);
} }
pub fn start_block(&mut self, block: Block) { pub fn start_block(&mut self, block: Block, was_reachable: bool) {
self.finish_block(); self.finish_block(was_reachable);
log::trace!("start_block: block {}", block); log::trace!("start_block: block {}", block);
self.cur_block = Some(block); self.cur_block = block;
} }
pub fn finish_block(&mut self) { pub fn finish_block(&mut self, reachable: bool) {
log::trace!("finish_block: block {:?}", self.cur_block); log::trace!("finish_block: block {}", self.cur_block);
if let Some(block) = self.cur_block { if reachable {
let mapping = std::mem::take(&mut self.in_cur_block); let mapping = std::mem::take(&mut self.in_cur_block);
self.block_end.insert(block, mapping); self.block_end.insert(self.cur_block, mapping);
} }
self.cur_block = None;
} }
pub fn seal_block_preds(&mut self, block: Block, body: &mut FunctionBody) { pub fn seal_block_preds(&mut self, block: Block, body: &mut FunctionBody) {
@ -404,7 +407,7 @@ impl LocalTracker {
log::trace!("get_in_block: at_block {} local {}", at_block, local); log::trace!("get_in_block: at_block {} local {}", at_block, local);
let ty = body.locals[local]; let ty = body.locals[local];
if self.cur_block == Some(at_block) { if self.cur_block == at_block {
if let Some(&value) = self.in_cur_block.get(&local) { if let Some(&value) = self.in_cur_block.get(&local) {
log::trace!(" -> {:?}", value); log::trace!(" -> {:?}", value);
return value; return value;
@ -462,11 +465,7 @@ impl LocalTracker {
} }
pub fn get(&mut self, body: &mut FunctionBody, local: Local) -> Value { pub fn get(&mut self, body: &mut FunctionBody, local: Local) -> Value {
if let Some(block) = self.cur_block { self.get_in_block(body, self.cur_block, local)
self.get_in_block(body, block, local)
} else {
Value::invalid()
}
} }
fn create_default_value( fn create_default_value(
@ -592,7 +591,8 @@ struct FunctionBodyBuilder<'a, 'b> {
my_sig: Signature, my_sig: Signature,
body: &'b mut FunctionBody, body: &'b mut FunctionBody,
locals: LocalTracker, locals: LocalTracker,
cur_block: Option<Block>, cur_block: Block,
reachable: bool,
ctrl_stack: Vec<Frame>, ctrl_stack: Vec<Frame>,
op_stack: Vec<(Type, Value)>, op_stack: Vec<(Type, Value)>,
} }
@ -604,6 +604,7 @@ enum Frame {
out: Block, out: Block,
params: Vec<Type>, params: Vec<Type>,
results: Vec<Type>, results: Vec<Type>,
out_reachable: bool,
}, },
Loop { Loop {
start_depth: usize, start_depth: usize,
@ -619,12 +620,14 @@ enum Frame {
param_values: Vec<(Type, Value)>, param_values: Vec<(Type, Value)>,
params: Vec<Type>, params: Vec<Type>,
results: Vec<Type>, results: Vec<Type>,
head_reachable: bool,
}, },
Else { Else {
start_depth: usize, start_depth: usize,
out: Block, out: Block,
params: Vec<Type>, params: Vec<Type>,
results: Vec<Type>, results: Vec<Type>,
merge_reachable: bool,
}, },
} }
@ -681,6 +684,13 @@ impl Frame {
| Frame::Else { results, .. } => &results[..], | Frame::Else { results, .. } => &results[..],
} }
} }
fn set_reachable(&mut self) {
match self {
Frame::Block { out_reachable, .. } => *out_reachable = true,
_ => {}
}
}
} }
impl<'a, 'b> FunctionBodyBuilder<'a, 'b> { impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
@ -692,7 +702,8 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
body, body,
ctrl_stack: vec![], ctrl_stack: vec![],
op_stack: vec![], op_stack: vec![],
cur_block: Some(Block::new(0)), cur_block: Block::new(0),
reachable: true,
locals: LocalTracker::default(), locals: LocalTracker::default(),
}; };
@ -705,6 +716,7 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
out, out,
params: vec![], params: vec![],
results, results,
out_reachable: false,
}); });
ret ret
} }
@ -741,13 +753,16 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
trace!("op_stack = {:?}", self.op_stack); trace!("op_stack = {:?}", self.op_stack);
trace!("ctrl_stack = {:?}", self.ctrl_stack); trace!("ctrl_stack = {:?}", self.ctrl_stack);
trace!("locals = {:?}", self.locals); trace!("locals = {:?}", self.locals);
debug_assert!(self.reachable);
if self.handle_ctrl_op(op.clone())? {
return Ok(());
}
match &op { match &op {
wasmparser::Operator::Unreachable => { wasmparser::Operator::Unreachable => {
if let Some(block) = self.cur_block { self.emit_unreachable();
self.body.end_block(block, Terminator::Unreachable);
self.locals.finish_block();
}
self.cur_block = None;
} }
wasmparser::Operator::LocalGet { local_index } => { wasmparser::Operator::LocalGet { local_index } => {
@ -760,17 +775,13 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
wasmparser::Operator::LocalSet { local_index } => { wasmparser::Operator::LocalSet { local_index } => {
let local_index = Local::from(*local_index); let local_index = Local::from(*local_index);
let (_, value) = self.op_stack.pop().unwrap(); let (_, value) = self.op_stack.pop().unwrap();
if self.cur_block.is_some() { self.locals.set(local_index, value);
self.locals.set(local_index, value);
}
} }
wasmparser::Operator::LocalTee { local_index } => { wasmparser::Operator::LocalTee { local_index } => {
let local_index = Local::from(*local_index); let local_index = Local::from(*local_index);
let (_ty, value) = *self.op_stack.last().unwrap(); let (_ty, value) = *self.op_stack.last().unwrap();
if self.cur_block.is_some() { self.locals.set(local_index, value);
self.locals.set(local_index, value);
}
} }
wasmparser::Operator::Call { .. } wasmparser::Operator::Call { .. }
@ -957,11 +968,104 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
let _ = self.pop_1(); let _ = self.pop_1();
} }
wasmparser::Operator::Br { relative_depth }
| wasmparser::Operator::BrIf { relative_depth } => {
let cond = match &op {
wasmparser::Operator::Br { .. } => None,
wasmparser::Operator::BrIf { .. } => Some(self.pop_1()),
_ => unreachable!(),
};
// Get the frame we're branching to.
let frame = self.relative_frame(*relative_depth);
frame.set_reachable();
let frame = frame.clone();
log::trace!("Br/BrIf: dest frame {:?}", frame);
// Finally, generate the branch itself.
match cond {
None => {
// Get the args off the stack unconditionally.
let args = self.pop_n(frame.br_args().len());
self.emit_branch(frame.br_target(), &args[..]);
self.reachable = false;
}
Some(cond) => {
let cont = self.body.add_block();
// Get the args off the stack but leave for the fallthrough.
let args = self.op_stack[self.op_stack.len() - frame.br_args().len()..]
.iter()
.map(|(_ty, value)| *value)
.collect::<Vec<_>>();
self.emit_cond_branch(cond, frame.br_target(), &args[..], cont, &[]);
self.locals.seal_block_preds(cont, &mut self.body);
self.cur_block = cont;
self.locals.start_block(cont, self.reachable);
}
}
}
wasmparser::Operator::BrTable { targets } => {
// Get the selector index.
let index = self.pop_1();
// Get the signature of the default frame; this tells
// us the signature of all frames (since wasmparser
// validates the input for us). Pop that many args.
let default_frame = self.relative_frame(targets.default());
let default_term_target = default_frame.br_target();
let arg_len = default_frame.br_args().len();
let args = self.pop_n(arg_len);
// Generate a branch terminator with the same args for
// every branch target.
let mut term_targets = vec![];
for target in targets.targets() {
let target = target?;
let frame = self.relative_frame(target);
frame.set_reachable();
assert_eq!(frame.br_args().len(), args.len());
let block = frame.br_target();
term_targets.push(block);
}
self.emit_br_table(index, default_term_target, &term_targets[..], &args[..]);
}
wasmparser::Operator::Return => {
let retvals = self.pop_n(self.module.signature(self.my_sig).returns.len());
self.emit_ret(&retvals[..]);
}
_ => bail!(FrontendError::UnsupportedFeature(format!(
"Unsupported operator: {:?}",
op
))),
}
Ok(())
}
fn handle_op_unreachable(&mut self, op: wasmparser::Operator<'a>) -> Result<()> {
trace!("handle_op_unreachable: {:?}", op);
trace!("op_stack = {:?}", self.op_stack);
trace!("ctrl_stack = {:?}", self.ctrl_stack);
debug_assert!(!self.reachable);
self.handle_ctrl_op(op)?;
Ok(())
}
fn handle_ctrl_op(&mut self, op: wasmparser::Operator<'a>) -> Result<bool> {
match &op {
wasmparser::Operator::End => { wasmparser::Operator::End => {
let frame = self.ctrl_stack.pop(); let frame = self.ctrl_stack.pop();
match &frame { match &frame {
None => { None => {
self.emit(Operator::Return)?; if self.reachable {
let retvals =
self.pop_n(self.module.signature(self.my_sig).returns.len());
self.emit_ret(&retvals[..]);
} else {
self.emit_unreachable();
}
} }
Some(Frame::Block { Some(Frame::Block {
start_depth, start_depth,
@ -977,9 +1081,9 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
}) => { }) => {
// Generate a branch to the out-block with // Generate a branch to the out-block with
// blockparams for the results. // blockparams for the results.
if let Some(cur_block) = self.cur_block { if self.reachable {
let result_values = let result_values =
self.block_results(&results[..], *start_depth, cur_block); self.block_results(&results[..], *start_depth, self.cur_block);
self.emit_branch(*out, &result_values[..]); self.emit_branch(*out, &result_values[..]);
} }
self.op_stack.truncate(*start_depth); self.op_stack.truncate(*start_depth);
@ -991,8 +1095,14 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
if let Some(Frame::Loop { header, .. }) = &frame { if let Some(Frame::Loop { header, .. }) = &frame {
self.locals.seal_block_preds(*header, &mut self.body); self.locals.seal_block_preds(*header, &mut self.body);
} }
self.cur_block = Some(*out); // Set `cur_block` only if currently set (otherwise, unreachable!)
self.locals.start_block(*out); self.cur_block = *out;
self.locals.start_block(*out, self.reachable);
self.reachable = self.reachable
|| match &frame {
Some(Frame::Block { out_reachable, .. }) => *out_reachable,
_ => false,
};
self.push_block_params(results.len()); self.push_block_params(results.len());
} }
Some(Frame::If { Some(Frame::If {
@ -1001,51 +1111,59 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
el, el,
ref param_values, ref param_values,
ref results, ref results,
head_reachable,
.. ..
}) => { }) => {
// Generate a branch to the out-block with // Generate a branch to the out-block with
// blockparams for the results. // blockparams for the results.
if let Some(cur_block) = self.cur_block { if self.reachable {
let result_values = let result_values =
self.block_results(&results[..], *start_depth, cur_block); self.block_results(&results[..], *start_depth, self.cur_block);
self.emit_branch(*out, &result_values[..]); self.emit_branch(*out, &result_values[..]);
} }
self.op_stack.truncate(*start_depth); self.op_stack.truncate(*start_depth);
// No `else`, so we need to generate a trivial if *head_reachable {
// branch in the else-block. If the if-block-type // No `else`, so we need to generate a trivial
// has results, they must be exactly the params. // branch in the else-block. If the if-block-type
let else_result_values = param_values; // has results, they must be exactly the params.
assert_eq!(else_result_values.len(), results.len()); let else_result_values = param_values;
let else_result_values = else_result_values assert_eq!(else_result_values.len(), results.len());
.iter() let else_result_values = else_result_values
.map(|(_ty, value)| *value) .iter()
.collect::<Vec<_>>(); .map(|(_ty, value)| *value)
self.locals.start_block(*el); .collect::<Vec<_>>();
self.cur_block = Some(*el); self.locals.start_block(*el, self.reachable);
self.emit_branch(*out, &else_result_values[..]); self.cur_block = *el;
assert_eq!(self.op_stack.len(), *start_depth); self.emit_branch(*out, &else_result_values[..]);
self.cur_block = Some(*out); assert_eq!(self.op_stack.len(), *start_depth);
}
self.cur_block = *out;
let was_reachable = self.reachable;
self.reachable = *head_reachable || self.reachable;
self.locals.seal_block_preds(*out, &mut self.body); self.locals.seal_block_preds(*out, &mut self.body);
self.locals.start_block(*out); self.locals.start_block(*out, was_reachable);
self.push_block_params(results.len()); self.push_block_params(results.len());
} }
Some(Frame::Else { Some(Frame::Else {
out, out,
ref results, ref results,
start_depth, start_depth,
merge_reachable,
.. ..
}) => { }) => {
// Generate a branch to the out-block with // Generate a branch to the out-block with
// blockparams for the results. // blockparams for the results.
if let Some(cur_block) = self.cur_block { if self.reachable {
let result_values = let result_values =
self.block_results(&results[..], *start_depth, cur_block); self.block_results(&results[..], *start_depth, self.cur_block);
self.emit_branch(*out, &result_values[..]); self.emit_branch(*out, &result_values[..]);
} }
self.op_stack.truncate(*start_depth); self.op_stack.truncate(*start_depth);
self.cur_block = Some(*out); self.cur_block = *out;
let was_reachable = self.reachable;
self.reachable = *merge_reachable || self.reachable;
self.locals.seal_block_preds(*out, &mut self.body); self.locals.seal_block_preds(*out, &mut self.body);
self.locals.start_block(*out); self.locals.start_block(*out, was_reachable);
self.push_block_params(results.len()); self.push_block_params(results.len());
} }
} }
@ -1061,6 +1179,7 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
out, out,
params, params,
results, results,
out_reachable: false,
}); });
} }
@ -1071,8 +1190,8 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
let initial_args = self.pop_n(params.len()); let initial_args = self.pop_n(params.len());
let start_depth = self.op_stack.len(); let start_depth = self.op_stack.len();
self.emit_branch(header, &initial_args[..]); self.emit_branch(header, &initial_args[..]);
self.cur_block = Some(header); self.cur_block = header;
self.locals.start_block(header); self.locals.start_block(header, self.reachable);
self.push_block_params(params.len()); self.push_block_params(params.len());
let out = self.body.add_block(); let out = self.body.add_block();
self.add_block_params(out, &results[..]); self.add_block_params(out, &results[..]);
@ -1101,12 +1220,13 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
param_values, param_values,
params, params,
results, results,
head_reachable: self.reachable,
}); });
self.emit_cond_branch(cond, if_true, &[], if_false, &[]); self.emit_cond_branch(cond, if_true, &[], if_false, &[]);
self.locals.seal_block_preds(if_true, &mut self.body); self.locals.seal_block_preds(if_true, &mut self.body);
self.locals.seal_block_preds(if_false, &mut self.body); self.locals.seal_block_preds(if_false, &mut self.body);
self.cur_block = Some(if_true); self.cur_block = if_true;
self.locals.start_block(if_true); self.locals.start_block(if_true, self.reachable);
} }
wasmparser::Operator::Else => { wasmparser::Operator::Else => {
@ -1117,10 +1237,12 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
param_values, param_values,
params, params,
results, results,
head_reachable,
} = self.ctrl_stack.pop().unwrap() } = self.ctrl_stack.pop().unwrap()
{ {
if let Some(cur_block) = self.cur_block { if self.reachable {
let if_results = self.block_results(&results[..], start_depth, cur_block); let if_results =
self.block_results(&results[..], start_depth, self.cur_block);
self.emit_branch(out, &if_results[..]); self.emit_branch(out, &if_results[..]);
} }
self.op_stack.truncate(start_depth); self.op_stack.truncate(start_depth);
@ -1130,9 +1252,11 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
out, out,
params, params,
results, results,
merge_reachable: head_reachable,
}); });
self.cur_block = Some(el); self.cur_block = el;
self.locals.start_block(el); self.locals.start_block(el, self.reachable);
self.reachable = head_reachable;
} else { } else {
bail!(FrontendError::Internal(format!( bail!(FrontendError::Internal(format!(
"Else without If on top of frame stack" "Else without If on top of frame stack"
@ -1140,73 +1264,10 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
} }
} }
wasmparser::Operator::Br { relative_depth } _ => return Ok(false),
| wasmparser::Operator::BrIf { relative_depth } => {
let cond = match &op {
wasmparser::Operator::Br { .. } => None,
wasmparser::Operator::BrIf { .. } => Some(self.pop_1()),
_ => unreachable!(),
};
// Get the frame we're branching to.
let frame = self.relative_frame(*relative_depth).clone();
log::trace!("Br/BrIf: dest frame {:?}", frame);
// Finally, generate the branch itself.
match cond {
None => {
// Get the args off the stack unconditionally.
let args = self.pop_n(frame.br_args().len());
self.emit_branch(frame.br_target(), &args[..]);
}
Some(cond) => {
let cont = self.body.add_block();
// Get the args off the stack but leave for the fallthrough.
let args = self.op_stack[self.op_stack.len() - frame.br_args().len()..]
.iter()
.map(|(_ty, value)| *value)
.collect::<Vec<_>>();
self.emit_cond_branch(cond, frame.br_target(), &args[..], cont, &[]);
self.locals.seal_block_preds(cont, &mut self.body);
self.cur_block = Some(cont);
self.locals.start_block(cont);
}
}
}
wasmparser::Operator::BrTable { targets } => {
// Get the selector index.
let index = self.pop_1();
// Get the signature of the default frame; this tells
// us the signature of all frames (since wasmparser
// validates the input for us). Pop that many args.
let default_frame = self.relative_frame(targets.default());
let default_term_target = default_frame.br_target();
let arg_len = default_frame.br_args().len();
let args = self.pop_n(arg_len);
// Generate a branch terminator with the same args for
// every branch target.
let mut term_targets = vec![];
for target in targets.targets() {
let target = target?;
let frame = self.relative_frame(target);
assert_eq!(frame.br_args().len(), args.len());
let block = frame.br_target();
term_targets.push(block);
}
self.emit_br_table(index, default_term_target, &term_targets[..], &args[..]);
}
wasmparser::Operator::Return => {
let retvals = self.pop_n(self.module.signature(self.my_sig).returns.len());
self.emit_ret(&retvals[..]);
}
_ => bail!(FrontendError::UnsupportedFeature(format!(
"Unsupported operator: {:?}",
op
))),
} }
Ok(()) Ok(true)
} }
fn add_block_params(&mut self, block: Block, tys: &[Type]) { fn add_block_params(&mut self, block: Block, tys: &[Type]) {
@ -1230,8 +1291,9 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
} }
} }
fn relative_frame(&self, relative_depth: u32) -> &Frame { fn relative_frame(&mut self, relative_depth: u32) -> &mut Frame {
&self.ctrl_stack[self.ctrl_stack.len() - 1 - relative_depth as usize] let index = self.ctrl_stack.len() - 1 - relative_depth as usize;
&mut self.ctrl_stack[index]
} }
fn emit_branch(&mut self, target: Block, args: &[Value]) { fn emit_branch(&mut self, target: Block, args: &[Value]) {
@ -1241,15 +1303,16 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
target, target,
args args
); );
if let Some(block) = self.cur_block { if self.reachable {
let args = args.to_vec(); let args = args.to_vec();
let target = BlockTarget { let target = BlockTarget {
block: target, block: target,
args, args,
}; };
self.body.end_block(block, Terminator::Br { target }); self.body
self.cur_block = None; .end_block(self.cur_block, Terminator::Br { target });
self.locals.finish_block(); self.reachable = false;
self.locals.finish_block(true);
} }
} }
@ -1269,11 +1332,11 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
if_false, if_false,
if_false_args if_false_args
); );
if let Some(block) = self.cur_block { if self.reachable {
let if_true_args = if_true_args.to_vec(); let if_true_args = if_true_args.to_vec();
let if_false_args = if_false_args.to_vec(); let if_false_args = if_false_args.to_vec();
self.body.end_block( self.body.end_block(
block, self.cur_block,
Terminator::CondBr { Terminator::CondBr {
cond, cond,
if_true: BlockTarget { if_true: BlockTarget {
@ -1286,8 +1349,8 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
}, },
}, },
); );
self.cur_block = None; self.reachable = false;
self.locals.finish_block(); self.locals.finish_block(true);
} }
} }
@ -1306,7 +1369,7 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
indexed_targets, indexed_targets,
args, args,
); );
if let Some(block) = self.cur_block { if self.reachable {
let args = args.to_vec(); let args = args.to_vec();
let targets = indexed_targets let targets = indexed_targets
.iter() .iter()
@ -1323,24 +1386,33 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
}; };
self.body.end_block( self.body.end_block(
block, self.cur_block,
Terminator::Select { Terminator::Select {
value: index, value: index,
targets, targets,
default, default,
}, },
); );
self.cur_block = None; self.locals.finish_block(true);
self.locals.finish_block(); self.reachable = false;
} }
} }
fn emit_ret(&mut self, values: &[Value]) { fn emit_ret(&mut self, values: &[Value]) {
if let Some(block) = self.cur_block { if self.reachable {
let values = values.to_vec(); let values = values.to_vec();
self.body.end_block(block, Terminator::Return { values }); self.body
self.cur_block = None; .end_block(self.cur_block, Terminator::Return { values });
self.locals.finish_block(); self.reachable = false;
self.locals.finish_block(true);
}
}
fn emit_unreachable(&mut self) {
if self.reachable {
self.body.end_block(self.cur_block, Terminator::Unreachable);
self.reachable = false;
self.locals.finish_block(true);
} }
} }
@ -1350,16 +1422,15 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
self.cur_block, self.cur_block,
num_params num_params
); );
let block = self.cur_block.unwrap();
for i in 0..num_params { for i in 0..num_params {
let (ty, value) = self.body.blocks[block].params[i]; let (ty, value) = self.body.blocks[self.cur_block].params[i];
log::trace!(" -> push {:?} ty {:?}", value, ty); log::trace!(" -> push {:?} ty {:?}", value, ty);
self.op_stack.push((ty, value)); self.op_stack.push((ty, value));
} }
} }
fn emit(&mut self, op: Operator) -> Result<()> { fn emit(&mut self, op: Operator) -> Result<()> {
let inputs = op_inputs(self.module, self.my_sig, &self.op_stack[..], &op)?; let inputs = op_inputs(self.module, &self.op_stack[..], &op)?;
let outputs = op_outputs(self.module, &self.op_stack[..], &op)?; let outputs = op_outputs(self.module, &self.op_stack[..], &op)?;
log::trace!( log::trace!(
@ -1386,8 +1457,8 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
.add_value(ValueDef::Operator(op, input_operands, outputs.to_vec())); .add_value(ValueDef::Operator(op, input_operands, outputs.to_vec()));
log::trace!(" -> value: {:?}", value); log::trace!(" -> value: {:?}", value);
if let Some(block) = self.cur_block { if self.reachable {
self.body.append_to_block(block, value); self.body.append_to_block(self.cur_block, value);
} }
if n_outputs == 1 { if n_outputs == 1 {
@ -1398,8 +1469,8 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
let pick = self let pick = self
.body .body
.add_value(ValueDef::PickOutput(value, i, output_ty)); .add_value(ValueDef::PickOutput(value, i, output_ty));
if let Some(block) = self.cur_block { if self.reachable {
self.body.append_to_block(block, pick); self.body.append_to_block(self.cur_block, pick);
} }
self.op_stack.push((output_ty, pick)); self.op_stack.push((output_ty, pick));
log::trace!(" -> pick {}: {:?} ty {:?}", i, pick, output_ty); log::trace!(" -> pick {}: {:?} ty {:?}", i, pick, output_ty);

View file

@ -1,13 +1,12 @@
//! Metadata on operators. //! Metadata on operators.
use crate::ir::{Module, Signature, Type, Value}; use crate::ir::{Module, Type, Value};
use crate::Operator; use crate::Operator;
use anyhow::Result; use anyhow::Result;
use std::borrow::Cow; use std::borrow::Cow;
pub fn op_inputs( pub fn op_inputs(
module: &Module, module: &Module,
my_sig: Signature,
op_stack: &[(Type, Value)], op_stack: &[(Type, Value)],
op: &Operator, op: &Operator,
) -> Result<Cow<'static, [Type]>> { ) -> Result<Cow<'static, [Type]>> {
@ -23,7 +22,6 @@ pub fn op_inputs(
params.push(Type::I32); params.push(Type::I32);
Ok(params.into()) Ok(params.into())
} }
&Operator::Return => Ok(Vec::from(module.signature(my_sig).returns.clone()).into()),
&Operator::Select => { &Operator::Select => {
let val_ty = op_stack[op_stack.len() - 2].0; let val_ty = op_stack[op_stack.len() - 2].0;
@ -241,7 +239,6 @@ pub fn op_outputs(
&Operator::CallIndirect { sig_index, .. } => { &Operator::CallIndirect { sig_index, .. } => {
Ok(Vec::from(module.signature(sig_index).returns.clone()).into()) Ok(Vec::from(module.signature(sig_index).returns.clone()).into())
} }
&Operator::Return => Ok(Cow::Borrowed(&[])),
&Operator::Select => { &Operator::Select => {
let val_ty = op_stack[op_stack.len() - 2].0; let val_ty = op_stack[op_stack.len() - 2].0;
@ -442,7 +439,6 @@ pub enum SideEffect {
WriteTable, WriteTable,
ReadLocal, ReadLocal,
WriteLocal, WriteLocal,
Return,
All, All,
} }
@ -456,7 +452,6 @@ impl Operator {
&Operator::Call { .. } => &[All], &Operator::Call { .. } => &[All],
&Operator::CallIndirect { .. } => &[All], &Operator::CallIndirect { .. } => &[All],
&Operator::Return => &[Return],
&Operator::Select => &[], &Operator::Select => &[],
&Operator::TypedSelect { .. } => &[], &Operator::TypedSelect { .. } => &[],
@ -659,7 +654,6 @@ impl std::fmt::Display for Operator {
sig_index, sig_index,
table_index, table_index,
} => write!(f, "call_indirect<{}, {}>", sig_index, table_index)?, } => write!(f, "call_indirect<{}, {}>", sig_index, table_index)?,
&Operator::Return => write!(f, "return")?,
&Operator::Select => write!(f, "select")?, &Operator::Select => write!(f, "select")?,
&Operator::TypedSelect { ty } => write!(f, "typed_select<{}>", ty)?, &Operator::TypedSelect { ty } => write!(f, "typed_select<{}>", ty)?,

View file

@ -33,7 +33,6 @@ pub enum Operator {
sig_index: Signature, sig_index: Signature,
table_index: Table, table_index: Table,
}, },
Return,
Select, Select,
TypedSelect { TypedSelect {
ty: Type, ty: Type,
@ -316,7 +315,6 @@ impl<'a, 'b> std::convert::TryFrom<&'b wasmparser::Operator<'a>> for Operator {
sig_index: Signature::from(type_index), sig_index: Signature::from(type_index),
table_index: Table::from(table_index), table_index: Table::from(table_index),
}), }),
&wasmparser::Operator::Return => Ok(Operator::Return),
&wasmparser::Operator::LocalSet { .. } => Err(()), &wasmparser::Operator::LocalSet { .. } => Err(()),
&wasmparser::Operator::LocalTee { .. } => Err(()), &wasmparser::Operator::LocalTee { .. } => Err(()),
&wasmparser::Operator::LocalGet { .. } => Err(()), &wasmparser::Operator::LocalGet { .. } => Err(()),