From 0eb41cb0a3720e7056d52da46e8cb84bb05056fe Mon Sep 17 00:00:00 2001 From: Chris Fallin Date: Sat, 13 Nov 2021 17:47:33 -0800 Subject: [PATCH] Seems to be fuzz-clean in wasm-to-IR step now; complete for Wasm-MVP --- src/frontend.rs | 271 +++++++++++++++++++++++++++-------------------- src/op_traits.rs | 30 ++++-- 2 files changed, 180 insertions(+), 121 deletions(-) diff --git a/src/frontend.rs b/src/frontend.rs index a4bb68f..bafe1bd 100644 --- a/src/frontend.rs +++ b/src/frontend.rs @@ -100,6 +100,11 @@ fn parse_body<'a, 'b>( body: wasmparser::FunctionBody<'a>, ) -> Result> { let mut ret: FunctionBody<'a> = FunctionBody::default(); + + for ¶m in &module.signatures[my_sig].params[..] { + ret.locals.push(param); + } + let mut locals = body.get_locals_reader()?; for _ in 0..locals.get_count() { let (count, ty) = locals.read()?; @@ -197,6 +202,15 @@ impl Frame { Frame::If { out, .. } | Frame::Else { out, .. } => *out, } } + + fn out(&self) -> BlockId { + match self { + Frame::Block { out, .. } + | Frame::Loop { out, .. } + | Frame::If { out, .. } + | Frame::Else { out, .. } => *out, + } + } } impl<'a, 'b> FunctionBodyBuilder<'a, 'b> { @@ -212,13 +226,13 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> { }; // Push initial implicit Block. - let params = module.signatures[my_sig].params.to_vec(); - let results = module.signatures[my_sig].params.to_vec(); + let results = module.signatures[my_sig].returns.to_vec(); let out = ret.create_block(); + ret.add_block_params(out, &results[..]); ret.ctrl_stack.push(Frame::Block { start_depth: 0, out, - params, + params: vec![], results, }); ret @@ -229,11 +243,13 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> { } fn pop_n(&mut self, n: usize) -> Vec { - self.op_stack - .split_off(n) - .into_iter() - .map(|(_ty, value)| value) - .collect() + let new_top = self.op_stack.len() - n; + let ret = self.op_stack[new_top..] + .iter() + .map(|(_ty, value)| *value) + .collect::>(); + self.op_stack.truncate(new_top); + ret } fn pop_1(&mut self) -> ValueId { @@ -242,9 +258,17 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> { fn handle_op(&mut self, op: Operator<'a>) -> Result<()> { trace!("handle_op: {:?}", op); + trace!("op_stack = {:?}", self.op_stack); + trace!("ctrl_stack = {:?}", self.ctrl_stack); match &op { - Operator::Unreachable - | Operator::LocalGet { .. } + Operator::Unreachable => { + if let Some(block) = self.cur_block { + self.body.blocks[block].terminator = Terminator::None; + } + self.cur_block = None; + } + + Operator::LocalGet { .. } | Operator::LocalSet { .. } | Operator::LocalTee { .. } | Operator::Call { .. } @@ -414,6 +438,10 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> { | Operator::I64TruncSatF32U | Operator::I64TruncSatF64S | Operator::I64TruncSatF64U + | Operator::F32ReinterpretI32 + | Operator::F64ReinterpretI64 + | Operator::I32ReinterpretF32 + | Operator::I64ReinterpretF64 | Operator::TableGet { .. } | Operator::TableSet { .. } | Operator::TableGrow { .. } @@ -425,71 +453,88 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> { let _ = self.pop_1(); } - Operator::End => match self.ctrl_stack.pop() { - None => { - self.emit(Operator::Return)?; + Operator::End if self.cur_block.is_none() => { + let frame = self.ctrl_stack.pop().unwrap(); + self.op_stack.truncate(frame.start_depth()); + self.cur_block = Some(frame.out()); + self.push_block_params(); + } + + Operator::End => { + let frame = self.ctrl_stack.pop(); + match frame { + None => { + self.emit(Operator::Return)?; + } + Some(Frame::Block { + start_depth, + out, + results, + .. + }) + | Some(Frame::Loop { + start_depth, + out, + results, + .. + }) => { + // Generate a branch to the out-block with + // blockparams for the results. + if self.cur_block.is_some() { + let result_values = self.pop_n(results.len()); + self.emit_branch(out, &result_values[..]); + } + self.op_stack.truncate(start_depth); + self.cur_block = Some(out); + self.push_block_params(); + } + Some(Frame::If { + start_depth, + out, + el, + param_values, + results, + .. + }) => { + // Generate a branch to the out-block with + // blockparams for the results. + if self.cur_block.is_some() { + let result_values = self.pop_n(results.len()); + self.emit_branch(out, &result_values[..]); + } + self.op_stack.truncate(start_depth); + // No `else`, so we need to generate a trivial + // branch in the else-block. If the if-block-type + // has results, they must be exactly the params. + let else_result_values = param_values; + assert_eq!(else_result_values.len(), results.len()); + let else_result_values = else_result_values + .iter() + .map(|(_ty, value)| *value) + .collect::>(); + self.emit_branch(el, &else_result_values[..]); + assert_eq!(self.op_stack.len(), start_depth); + self.cur_block = Some(out); + self.push_block_params(); + } + Some(Frame::Else { + out, + results, + start_depth, + .. + }) => { + // Generate a branch to the out-block with + // blockparams for the results. + if self.cur_block.is_some() { + let result_values = self.pop_n(results.len()); + self.emit_branch(out, &result_values[..]); + } + self.op_stack.truncate(start_depth); + self.cur_block = Some(out); + self.push_block_params(); + } } - Some(Frame::Block { - start_depth, - out, - results, - .. - }) - | Some(Frame::Loop { - start_depth, - out, - results, - .. - }) => { - // Generate a branch to the out-block with - // blockparams for the results. - let result_values = self.pop_n(results.len()); - self.emit_branch(out, &result_values[..]); - assert_eq!(self.op_stack.len(), start_depth); - self.cur_block = Some(out); - self.push_block_params(&results[..]); - } - Some(Frame::If { - start_depth, - out, - el, - param_values, - results, - .. - }) => { - // Generate a branch to the out-block with - // blockparams for the results. - let result_values = self.pop_n(results.len()); - self.emit_branch(out, &result_values[..]); - // No `else`, so we need to generate a trivial - // branch in the else-block. If the if-block-type - // has results, they must be exactly the params. - let else_result_values = param_values; - assert_eq!(else_result_values.len(), results.len()); - let else_result_values = else_result_values - .iter() - .map(|(_ty, value)| *value) - .collect::>(); - self.emit_branch(el, &else_result_values[..]); - assert_eq!(self.op_stack.len(), start_depth); - self.cur_block = Some(out); - self.push_block_params(&results[..]); - } - Some(Frame::Else { - out, - results, - start_depth, - .. - }) => { - // Generate a branch to the out-block with - // blockparams for the results. - let result_values = self.pop_n(results.len()); - assert_eq!(self.op_stack.len(), start_depth); - self.emit_branch(out, &result_values[..]); - self.cur_block = Some(out); - self.push_block_params(&results[..]); - } - }, + } Operator::Block { ty } => { let (params, results) = self.block_params_and_results(*ty); @@ -512,8 +557,9 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> { let start_depth = self.op_stack.len(); self.emit_branch(header, &initial_args[..]); self.cur_block = Some(header); - self.push_block_params(¶ms[..]); + self.push_block_params(); let out = self.create_block(); + self.add_block_params(out, &results[..]); self.ctrl_stack.push(Frame::Loop { start_depth, header, @@ -531,7 +577,7 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> { self.add_block_params(join, &results[..]); let cond = self.pop_1(); let param_values = self.op_stack[self.op_stack.len() - params.len()..].to_vec(); - let start_depth = self.op_stack.len(); + let start_depth = self.op_stack.len() - params.len(); self.ctrl_stack.push(Frame::If { start_depth, out: join, @@ -554,8 +600,11 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> { results, } = self.ctrl_stack.pop().unwrap() { - let if_results = self.pop_n(results.len()); - self.emit_branch(out, &if_results[..]); + if self.cur_block.is_some() { + let if_results = self.pop_n(results.len()); + self.emit_branch(out, &if_results[..]); + } + self.op_stack.truncate(start_depth); self.op_stack.extend(param_values); self.ctrl_stack.push(Frame::Else { start_depth, @@ -577,16 +626,21 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> { }; // Get the frame we're branching to. let frame = self.relative_frame(*relative_depth).clone(); - // Get the args off the stack. - let args = self.pop_n(frame.br_args().len()); // 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.cur_block = None; } Some(cond) => { let cont = self.create_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::>(); self.emit_cond_branch(cond, frame.br_target(), &args[..], cont, &[]); self.cur_block = Some(cont); } @@ -637,6 +691,7 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> { fn block_params_and_results(&self, ty: TypeOrFuncType) -> (Vec, Vec) { match ty { + TypeOrFuncType::Type(Type::EmptyBlockType) => (vec![], vec![]), TypeOrFuncType::Type(ret_ty) => (vec![], vec![ret_ty]), TypeOrFuncType::FuncType(sig_idx) => { let sig = &self.module.signatures[sig_idx as SignatureId]; @@ -729,8 +784,9 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> { } } - fn push_block_params(&mut self, tys: &[Type]) { - assert_eq!(tys, self.body.blocks[self.cur_block.unwrap()].params); + fn push_block_params(&mut self) { + let tys = &self.body.blocks[self.cur_block.unwrap()].params[..]; + for (i, &ty) in tys.iter().enumerate() { let value_id = self.body.values.len() as ValueId; self.body.values.push(ValueDef { @@ -742,32 +798,30 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> { } fn emit(&mut self, op: Operator<'a>) -> Result<()> { + let inputs = op_inputs( + self.module, + self.my_sig, + &self.body.locals[..], + &self.op_stack[..], + &op, + )?; + let outputs = op_outputs(self.module, &self.body.locals[..], &self.op_stack[..], &op)?; + if let Some(block) = self.cur_block { let inst = self.body.blocks[block].insts.len() as InstId; - let mut inputs = vec![]; - for input in op_inputs( - self.module, - self.my_sig, - &self.body.locals[..], - &self.op_stack[..], - &op, - )? - .into_iter() - .rev() - { + let mut input_operands = vec![]; + for input in inputs.into_iter().rev() { let (stack_top_ty, stack_top) = self.op_stack.pop().unwrap(); assert_eq!(stack_top_ty, input); - inputs.push(Operand::value(stack_top)); + input_operands.push(Operand::value(stack_top)); } - inputs.reverse(); + input_operands.reverse(); - let mut outputs = vec![]; - for output_ty in - op_outputs(self.module, &self.body.locals[..], &self.op_stack[..], &op)?.into_iter() - { + let mut output_operands = vec![]; + for output_ty in outputs.into_iter() { let val = self.body.values.len() as ValueId; - outputs.push(val); + output_operands.push(val); self.body.values.push(ValueDef { kind: ValueKind::Inst(block, inst), ty: output_ty, @@ -777,21 +831,12 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> { self.body.blocks[block].insts.push(Inst { operator: op, - outputs, - inputs, + outputs: output_operands, + inputs: input_operands, }); } else { - let _ = self.pop_n( - op_inputs( - self.module, - self.my_sig, - &self.body.locals[..], - &self.op_stack[..], - &op, - )? - .len(), - ); - for ty in op_outputs(self.module, &self.body.locals[..], &self.op_stack[..], &op)? { + let _ = self.pop_n(inputs.len()); + for ty in outputs { self.op_stack.push((ty, NO_VALUE)); } } diff --git a/src/op_traits.rs b/src/op_traits.rs index e162d65..6b8eb9d 100644 --- a/src/op_traits.rs +++ b/src/op_traits.rs @@ -19,8 +19,8 @@ pub fn op_inputs( Ok(Vec::from(module.signatures[sig].params.clone())) } &Operator::CallIndirect { index, .. } => { - let mut params = vec![Type::I32]; - params.extend_from_slice(&module.signatures[index as usize].params[..]); + let mut params = module.signatures[index as usize].params.to_vec(); + params.push(Type::I32); Ok(params) } &Operator::Return => Ok(Vec::from(module.signatures[my_sig].returns.clone())), @@ -210,10 +210,16 @@ pub fn op_inputs( Operator::I64TruncSatF32U => Ok(vec![Type::F32]), Operator::I64TruncSatF64S => Ok(vec![Type::F64]), Operator::I64TruncSatF64U => Ok(vec![Type::F64]), + Operator::F32ReinterpretI32 => Ok(vec![Type::I32]), + Operator::F64ReinterpretI64 => Ok(vec![Type::I64]), + Operator::I32ReinterpretF32 => Ok(vec![Type::F32]), + Operator::I64ReinterpretF64 => Ok(vec![Type::F64]), Operator::TableGet { .. } => Ok(vec![Type::I32]), Operator::TableSet { table } => Ok(vec![Type::I32, module.tables[*table as usize]]), Operator::TableGrow { .. } => Ok(vec![Type::I32]), Operator::TableSize { .. } => Ok(vec![]), + Operator::MemorySize { .. } => Ok(vec![]), + Operator::MemoryGrow { .. } => Ok(vec![Type::I32]), _ => bail!("Unknown operator in op_inputs(): {:?}", op), } @@ -236,8 +242,10 @@ pub fn op_outputs( Ok(Vec::from(module.signatures[index as usize].returns.clone())) } &Operator::Return => Ok(vec![]), - &Operator::LocalSet { .. } | &Operator::LocalTee { .. } => Ok(vec![]), - &Operator::LocalGet { local_index } => Ok(vec![my_locals[local_index as usize]]), + &Operator::LocalSet { .. } => Ok(vec![]), + &Operator::LocalGet { local_index } | &Operator::LocalTee { local_index } => { + Ok(vec![my_locals[local_index as usize]]) + } &Operator::Select => { let val_ty = op_stack[op_stack.len() - 2].0; @@ -248,19 +256,19 @@ pub fn op_outputs( &Operator::GlobalSet { .. } => Ok(vec![]), Operator::I32Load { .. } - | Operator::I64Load { .. } - | Operator::F32Load { .. } - | Operator::F64Load { .. } | Operator::I32Load8S { .. } | Operator::I32Load8U { .. } | Operator::I32Load16S { .. } | Operator::I32Load16U { .. } => Ok(vec![Type::I32]), - Operator::I64Load8S { .. } + Operator::I64Load { .. } + | Operator::I64Load8S { .. } | Operator::I64Load8U { .. } | Operator::I64Load16S { .. } | Operator::I64Load16U { .. } | Operator::I64Load32S { .. } | Operator::I64Load32U { .. } => Ok(vec![Type::I64]), + Operator::F32Load { .. } => Ok(vec![Type::F32]), + Operator::F64Load { .. } => Ok(vec![Type::F64]), Operator::I32Store { .. } => Ok(vec![]), Operator::I64Store { .. } => Ok(vec![]), @@ -414,10 +422,16 @@ pub fn op_outputs( Operator::I64TruncSatF32U => Ok(vec![Type::I64]), Operator::I64TruncSatF64S => Ok(vec![Type::I64]), Operator::I64TruncSatF64U => Ok(vec![Type::I64]), + Operator::F32ReinterpretI32 => Ok(vec![Type::F32]), + Operator::F64ReinterpretI64 => Ok(vec![Type::F64]), + Operator::I32ReinterpretF32 => Ok(vec![Type::I32]), + Operator::I64ReinterpretF64 => Ok(vec![Type::I64]), Operator::TableGet { table } => Ok(vec![module.tables[*table as usize]]), Operator::TableSet { .. } => Ok(vec![]), Operator::TableGrow { .. } => Ok(vec![]), Operator::TableSize { .. } => Ok(vec![Type::I32]), + Operator::MemorySize { .. } => Ok(vec![Type::I32]), + Operator::MemoryGrow { .. } => Ok(vec![Type::I32]), _ => bail!("Unknown operator in op_outputs(): {:?}", op), }