1 use crate::codegen::ir::{ArgumentExtension, ArgumentPurpose, ValueList}; 2 use crate::config::Config; 3 use anyhow::Result; 4 use arbitrary::{Arbitrary, Unstructured}; 5 use cranelift::codegen::ir::types::*; 6 use cranelift::codegen::ir::{ 7 AbiParam, Block, ExternalName, Function, JumpTable, Opcode, Signature, StackSlot, Type, Value, 8 }; 9 use cranelift::codegen::isa::CallConv; 10 use cranelift::frontend::{FunctionBuilder, FunctionBuilderContext, Switch, Variable}; 11 use cranelift::prelude::{ 12 EntityRef, InstBuilder, IntCC, JumpTableData, StackSlotData, StackSlotKind, 13 }; 14 use std::collections::HashMap; 15 use std::ops::RangeInclusive; 16 17 type BlockSignature = Vec<Type>; 18 19 fn insert_opcode( 20 fgen: &mut FunctionGenerator, 21 builder: &mut FunctionBuilder, 22 opcode: Opcode, 23 args: &'static [Type], 24 rets: &'static [Type], 25 ) -> Result<()> { 26 let mut arg_vals = ValueList::new(); 27 for &arg in args.into_iter() { 28 let var = fgen.get_variable_of_type(arg)?; 29 let val = builder.use_var(var); 30 arg_vals.push(val, &mut builder.func.dfg.value_lists); 31 } 32 33 let typevar = rets.first().copied().unwrap_or(INVALID); 34 let (inst, dfg) = builder.ins().MultiAry(opcode, typevar, arg_vals); 35 let results = dfg.inst_results(inst).to_vec(); 36 37 for (val, &ty) in results.into_iter().zip(rets) { 38 let var = fgen.get_variable_of_type(ty)?; 39 builder.def_var(var, val); 40 } 41 Ok(()) 42 } 43 44 fn insert_stack_load( 45 fgen: &mut FunctionGenerator, 46 builder: &mut FunctionBuilder, 47 _opcode: Opcode, 48 _args: &'static [Type], 49 rets: &'static [Type], 50 ) -> Result<()> { 51 let typevar = rets[0]; 52 let slot = fgen.stack_slot_with_size(builder, typevar.bytes())?; 53 let slot_size = builder.func.sized_stack_slots[slot].size; 54 let type_size = typevar.bytes(); 55 let offset = fgen.u.int_in_range(0..=(slot_size - type_size))? as i32; 56 57 let val = builder.ins().stack_load(typevar, slot, offset); 58 let var = fgen.get_variable_of_type(typevar)?; 59 builder.def_var(var, val); 60 61 Ok(()) 62 } 63 64 fn insert_stack_store( 65 fgen: &mut FunctionGenerator, 66 builder: &mut FunctionBuilder, 67 _opcode: Opcode, 68 args: &'static [Type], 69 _rets: &'static [Type], 70 ) -> Result<()> { 71 let typevar = args[0]; 72 let slot = fgen.stack_slot_with_size(builder, typevar.bytes())?; 73 let slot_size = builder.func.sized_stack_slots[slot].size; 74 let type_size = typevar.bytes(); 75 let offset = fgen.u.int_in_range(0..=(slot_size - type_size))? as i32; 76 77 let arg0 = fgen.get_variable_of_type(typevar)?; 78 let arg0 = builder.use_var(arg0); 79 80 builder.ins().stack_store(arg0, slot, offset); 81 Ok(()) 82 } 83 84 fn insert_const( 85 fgen: &mut FunctionGenerator, 86 builder: &mut FunctionBuilder, 87 _opcode: Opcode, 88 _args: &'static [Type], 89 rets: &'static [Type], 90 ) -> Result<()> { 91 let typevar = rets[0]; 92 let var = fgen.get_variable_of_type(typevar)?; 93 let val = fgen.generate_const(builder, typevar)?; 94 builder.def_var(var, val); 95 Ok(()) 96 } 97 98 type OpcodeInserter = fn( 99 fgen: &mut FunctionGenerator, 100 builder: &mut FunctionBuilder, 101 Opcode, 102 &'static [Type], 103 &'static [Type], 104 ) -> Result<()>; 105 106 // TODO: Derive this from the `cranelift-meta` generator. 107 const OPCODE_SIGNATURES: &'static [( 108 Opcode, 109 &'static [Type], // Args 110 &'static [Type], // Rets 111 OpcodeInserter, 112 )] = &[ 113 (Opcode::Nop, &[], &[], insert_opcode), 114 // Iadd 115 (Opcode::Iadd, &[I8, I8], &[I8], insert_opcode), 116 (Opcode::Iadd, &[I16, I16], &[I16], insert_opcode), 117 (Opcode::Iadd, &[I32, I32], &[I32], insert_opcode), 118 (Opcode::Iadd, &[I64, I64], &[I64], insert_opcode), 119 (Opcode::Iadd, &[I128, I128], &[I128], insert_opcode), 120 // Isub 121 (Opcode::Isub, &[I8, I8], &[I8], insert_opcode), 122 (Opcode::Isub, &[I16, I16], &[I16], insert_opcode), 123 (Opcode::Isub, &[I32, I32], &[I32], insert_opcode), 124 (Opcode::Isub, &[I64, I64], &[I64], insert_opcode), 125 (Opcode::Isub, &[I128, I128], &[I128], insert_opcode), 126 // Imul 127 (Opcode::Imul, &[I8, I8], &[I8], insert_opcode), 128 (Opcode::Imul, &[I16, I16], &[I16], insert_opcode), 129 (Opcode::Imul, &[I32, I32], &[I32], insert_opcode), 130 (Opcode::Imul, &[I64, I64], &[I64], insert_opcode), 131 (Opcode::Imul, &[I128, I128], &[I128], insert_opcode), 132 // Udiv 133 (Opcode::Udiv, &[I8, I8], &[I8], insert_opcode), 134 (Opcode::Udiv, &[I16, I16], &[I16], insert_opcode), 135 (Opcode::Udiv, &[I32, I32], &[I32], insert_opcode), 136 (Opcode::Udiv, &[I64, I64], &[I64], insert_opcode), 137 (Opcode::Udiv, &[I128, I128], &[I128], insert_opcode), 138 // Sdiv 139 (Opcode::Sdiv, &[I8, I8], &[I8], insert_opcode), 140 (Opcode::Sdiv, &[I16, I16], &[I16], insert_opcode), 141 (Opcode::Sdiv, &[I32, I32], &[I32], insert_opcode), 142 (Opcode::Sdiv, &[I64, I64], &[I64], insert_opcode), 143 (Opcode::Sdiv, &[I128, I128], &[I128], insert_opcode), 144 // Fadd 145 (Opcode::Fadd, &[F32, F32], &[F32], insert_opcode), 146 (Opcode::Fadd, &[F64, F64], &[F64], insert_opcode), 147 // Fmul 148 (Opcode::Fmul, &[F32, F32], &[F32], insert_opcode), 149 (Opcode::Fmul, &[F64, F64], &[F64], insert_opcode), 150 // Fsub 151 (Opcode::Fsub, &[F32, F32], &[F32], insert_opcode), 152 (Opcode::Fsub, &[F64, F64], &[F64], insert_opcode), 153 // Fdiv 154 (Opcode::Fdiv, &[F32, F32], &[F32], insert_opcode), 155 (Opcode::Fdiv, &[F64, F64], &[F64], insert_opcode), 156 // Fmin 157 (Opcode::Fmin, &[F32, F32], &[F32], insert_opcode), 158 (Opcode::Fmin, &[F64, F64], &[F64], insert_opcode), 159 // Fmax 160 (Opcode::Fmax, &[F32, F32], &[F32], insert_opcode), 161 (Opcode::Fmax, &[F64, F64], &[F64], insert_opcode), 162 // FminPseudo 163 (Opcode::FminPseudo, &[F32, F32], &[F32], insert_opcode), 164 (Opcode::FminPseudo, &[F64, F64], &[F64], insert_opcode), 165 // FmaxPseudo 166 (Opcode::FmaxPseudo, &[F32, F32], &[F32], insert_opcode), 167 (Opcode::FmaxPseudo, &[F64, F64], &[F64], insert_opcode), 168 // Fcopysign 169 (Opcode::Fcopysign, &[F32, F32], &[F32], insert_opcode), 170 (Opcode::Fcopysign, &[F64, F64], &[F64], insert_opcode), 171 // Fma 172 (Opcode::Fma, &[F32, F32, F32], &[F32], insert_opcode), 173 (Opcode::Fma, &[F64, F64, F64], &[F64], insert_opcode), 174 // Fabs 175 (Opcode::Fabs, &[F32], &[F32], insert_opcode), 176 (Opcode::Fabs, &[F64], &[F64], insert_opcode), 177 // Fneg 178 (Opcode::Fneg, &[F32], &[F32], insert_opcode), 179 (Opcode::Fneg, &[F64], &[F64], insert_opcode), 180 // Sqrt 181 (Opcode::Sqrt, &[F32], &[F32], insert_opcode), 182 (Opcode::Sqrt, &[F64], &[F64], insert_opcode), 183 // Ceil 184 (Opcode::Ceil, &[F32], &[F32], insert_opcode), 185 (Opcode::Ceil, &[F64], &[F64], insert_opcode), 186 // Floor 187 (Opcode::Floor, &[F32], &[F32], insert_opcode), 188 (Opcode::Floor, &[F64], &[F64], insert_opcode), 189 // Trunc 190 (Opcode::Trunc, &[F32], &[F32], insert_opcode), 191 (Opcode::Trunc, &[F64], &[F64], insert_opcode), 192 // Nearest 193 (Opcode::Nearest, &[F32], &[F32], insert_opcode), 194 (Opcode::Nearest, &[F64], &[F64], insert_opcode), 195 // Stack Access 196 (Opcode::StackStore, &[I8], &[], insert_stack_store), 197 (Opcode::StackStore, &[I16], &[], insert_stack_store), 198 (Opcode::StackStore, &[I32], &[], insert_stack_store), 199 (Opcode::StackStore, &[I64], &[], insert_stack_store), 200 (Opcode::StackStore, &[I128], &[], insert_stack_store), 201 (Opcode::StackLoad, &[], &[I8], insert_stack_load), 202 (Opcode::StackLoad, &[], &[I16], insert_stack_load), 203 (Opcode::StackLoad, &[], &[I32], insert_stack_load), 204 (Opcode::StackLoad, &[], &[I64], insert_stack_load), 205 (Opcode::StackLoad, &[], &[I128], insert_stack_load), 206 // Integer Consts 207 (Opcode::Iconst, &[], &[I8], insert_const), 208 (Opcode::Iconst, &[], &[I16], insert_const), 209 (Opcode::Iconst, &[], &[I32], insert_const), 210 (Opcode::Iconst, &[], &[I64], insert_const), 211 (Opcode::Iconst, &[], &[I128], insert_const), 212 // Float Consts 213 (Opcode::F32const, &[], &[F32], insert_const), 214 (Opcode::F64const, &[], &[F64], insert_const), 215 // Bool Consts 216 (Opcode::Bconst, &[], &[B1], insert_const), 217 ]; 218 219 pub struct FunctionGenerator<'r, 'data> 220 where 221 'data: 'r, 222 { 223 u: &'r mut Unstructured<'data>, 224 config: &'r Config, 225 vars: Vec<(Type, Variable)>, 226 blocks: Vec<(Block, BlockSignature)>, 227 jump_tables: Vec<JumpTable>, 228 static_stack_slots: Vec<StackSlot>, 229 } 230 231 impl<'r, 'data> FunctionGenerator<'r, 'data> 232 where 233 'data: 'r, 234 { 235 pub fn new(u: &'r mut Unstructured<'data>, config: &'r Config) -> Self { 236 Self { 237 u, 238 config, 239 vars: vec![], 240 blocks: vec![], 241 jump_tables: vec![], 242 static_stack_slots: vec![], 243 } 244 } 245 246 /// Generates a random value for config `param` 247 fn param(&mut self, param: &RangeInclusive<usize>) -> Result<usize> { 248 Ok(self.u.int_in_range(param.clone())?) 249 } 250 251 fn generate_callconv(&mut self) -> Result<CallConv> { 252 // TODO: Generate random CallConvs per target 253 Ok(CallConv::SystemV) 254 } 255 256 fn generate_intcc(&mut self) -> Result<IntCC> { 257 Ok(*self.u.choose( 258 &[ 259 IntCC::Equal, 260 IntCC::NotEqual, 261 IntCC::SignedLessThan, 262 IntCC::SignedGreaterThanOrEqual, 263 IntCC::SignedGreaterThan, 264 IntCC::SignedLessThanOrEqual, 265 IntCC::UnsignedLessThan, 266 IntCC::UnsignedGreaterThanOrEqual, 267 IntCC::UnsignedGreaterThan, 268 IntCC::UnsignedLessThanOrEqual, 269 IntCC::Overflow, 270 IntCC::NotOverflow, 271 ][..], 272 )?) 273 } 274 275 fn generate_type(&mut self) -> Result<Type> { 276 // TODO: It would be nice if we could get these directly from cranelift 277 let scalars = [ 278 // IFLAGS, FFLAGS, 279 B1, // B8, B16, B32, B64, B128, 280 I8, I16, I32, I64, I128, F32, F64, 281 // R32, R64, 282 ]; 283 // TODO: vector types 284 285 let ty = self.u.choose(&scalars[..])?; 286 Ok(*ty) 287 } 288 289 fn generate_abi_param(&mut self) -> Result<AbiParam> { 290 let value_type = self.generate_type()?; 291 // TODO: There are more argument purposes to be explored... 292 let purpose = ArgumentPurpose::Normal; 293 let extension = match self.u.int_in_range(0..=2)? { 294 2 => ArgumentExtension::Sext, 295 1 => ArgumentExtension::Uext, 296 _ => ArgumentExtension::None, 297 }; 298 299 Ok(AbiParam { 300 value_type, 301 purpose, 302 extension, 303 }) 304 } 305 306 fn generate_signature(&mut self) -> Result<Signature> { 307 let callconv = self.generate_callconv()?; 308 let mut sig = Signature::new(callconv); 309 310 for _ in 0..self.param(&self.config.signature_params)? { 311 sig.params.push(self.generate_abi_param()?); 312 } 313 314 for _ in 0..self.param(&self.config.signature_rets)? { 315 sig.returns.push(self.generate_abi_param()?); 316 } 317 318 Ok(sig) 319 } 320 321 /// Finds a stack slot with size of at least n bytes 322 fn stack_slot_with_size(&mut self, builder: &mut FunctionBuilder, n: u32) -> Result<StackSlot> { 323 let opts: Vec<_> = self 324 .static_stack_slots 325 .iter() 326 .filter(|ss| builder.func.sized_stack_slots[**ss].size >= n) 327 .map(|ss| *ss) 328 .collect(); 329 330 Ok(*self.u.choose(&opts[..])?) 331 } 332 333 /// Creates a new var 334 fn create_var(&mut self, builder: &mut FunctionBuilder, ty: Type) -> Result<Variable> { 335 let id = self.vars.len(); 336 let var = Variable::new(id); 337 builder.declare_var(var, ty); 338 self.vars.push((ty, var)); 339 Ok(var) 340 } 341 342 fn vars_of_type(&self, ty: Type) -> Vec<Variable> { 343 self.vars 344 .iter() 345 .filter(|(var_ty, _)| *var_ty == ty) 346 .map(|(_, v)| *v) 347 .collect() 348 } 349 350 /// Get a variable of type `ty` from the current function 351 fn get_variable_of_type(&mut self, ty: Type) -> Result<Variable> { 352 let opts = self.vars_of_type(ty); 353 let var = self.u.choose(&opts[..])?; 354 Ok(*var) 355 } 356 357 /// Generates an instruction(`iconst`/`fconst`/etc...) to introduce a constant value 358 fn generate_const(&mut self, builder: &mut FunctionBuilder, ty: Type) -> Result<Value> { 359 Ok(match ty { 360 I128 => { 361 // See: https://github.com/bytecodealliance/wasmtime/issues/2906 362 let hi = builder.ins().iconst(I64, self.u.arbitrary::<i64>()?); 363 let lo = builder.ins().iconst(I64, self.u.arbitrary::<i64>()?); 364 builder.ins().iconcat(lo, hi) 365 } 366 ty if ty.is_int() => { 367 let imm64 = match ty { 368 I8 => self.u.arbitrary::<i8>()? as i64, 369 I16 => self.u.arbitrary::<i16>()? as i64, 370 I32 => self.u.arbitrary::<i32>()? as i64, 371 I64 => self.u.arbitrary::<i64>()?, 372 _ => unreachable!(), 373 }; 374 builder.ins().iconst(ty, imm64) 375 } 376 ty if ty.is_bool() => builder.ins().bconst(ty, bool::arbitrary(self.u)?), 377 // f{32,64}::arbitrary does not generate a bunch of important values 378 // such as Signaling NaN's / NaN's with payload, so generate floats from integers. 379 F32 => builder 380 .ins() 381 .f32const(f32::from_bits(u32::arbitrary(self.u)?)), 382 F64 => builder 383 .ins() 384 .f64const(f64::from_bits(u64::arbitrary(self.u)?)), 385 _ => unimplemented!(), 386 }) 387 } 388 389 /// Chooses a random block which can be targeted by a jump / branch. 390 /// This means any block that is not the first block. 391 /// 392 /// For convenience we also generate values that match the block's signature 393 fn generate_target_block( 394 &mut self, 395 builder: &mut FunctionBuilder, 396 ) -> Result<(Block, Vec<Value>)> { 397 let block_targets = &self.blocks[1..]; 398 let (block, signature) = self.u.choose(block_targets)?.clone(); 399 let args = self.generate_values_for_signature(builder, signature.into_iter())?; 400 Ok((block, args)) 401 } 402 403 /// Valid blocks for jump tables have to have no parameters in the signature, and must also 404 /// not be the first block. 405 fn generate_valid_jumptable_target_blocks(&mut self) -> Vec<Block> { 406 self.blocks[1..] 407 .iter() 408 .filter(|(_, sig)| sig.len() == 0) 409 .map(|(b, _)| *b) 410 .collect() 411 } 412 413 fn generate_values_for_signature<I: Iterator<Item = Type>>( 414 &mut self, 415 builder: &mut FunctionBuilder, 416 signature: I, 417 ) -> Result<Vec<Value>> { 418 signature 419 .map(|ty| { 420 let var = self.get_variable_of_type(ty)?; 421 let val = builder.use_var(var); 422 Ok(val) 423 }) 424 .collect() 425 } 426 427 fn generate_return(&mut self, builder: &mut FunctionBuilder) -> Result<()> { 428 let types: Vec<Type> = { 429 let rets = &builder.func.signature.returns; 430 rets.iter().map(|p| p.value_type).collect() 431 }; 432 let vals = self.generate_values_for_signature(builder, types.into_iter())?; 433 434 builder.ins().return_(&vals[..]); 435 Ok(()) 436 } 437 438 fn generate_jump(&mut self, builder: &mut FunctionBuilder) -> Result<()> { 439 let (block, args) = self.generate_target_block(builder)?; 440 builder.ins().jump(block, &args[..]); 441 Ok(()) 442 } 443 444 /// Generates a br_table into a random block 445 fn generate_br_table(&mut self, builder: &mut FunctionBuilder) -> Result<()> { 446 let var = self.get_variable_of_type(I32)?; // br_table only supports I32 447 let val = builder.use_var(var); 448 449 let valid_blocks = self.generate_valid_jumptable_target_blocks(); 450 let default_block = *self.u.choose(&valid_blocks[..])?; 451 452 let jt = *self.u.choose(&self.jump_tables[..])?; 453 builder.ins().br_table(val, default_block, jt); 454 Ok(()) 455 } 456 457 /// Generates a brz/brnz into a random block 458 fn generate_br(&mut self, builder: &mut FunctionBuilder) -> Result<()> { 459 let (block, args) = self.generate_target_block(builder)?; 460 461 let condbr_types = [I8, I16, I32, I64, I128, B1]; 462 let _type = *self.u.choose(&condbr_types[..])?; 463 let var = self.get_variable_of_type(_type)?; 464 let val = builder.use_var(var); 465 466 if bool::arbitrary(self.u)? { 467 builder.ins().brz(val, block, &args[..]); 468 } else { 469 builder.ins().brnz(val, block, &args[..]); 470 } 471 472 // After brz/brnz we must generate a jump 473 self.generate_jump(builder)?; 474 Ok(()) 475 } 476 477 fn generate_bricmp(&mut self, builder: &mut FunctionBuilder) -> Result<()> { 478 let (block, args) = self.generate_target_block(builder)?; 479 let cond = self.generate_intcc()?; 480 481 let bricmp_types = [ 482 I8, I16, I32, 483 I64, 484 // I128 - TODO: https://github.com/bytecodealliance/wasmtime/issues/4406 485 ]; 486 let _type = *self.u.choose(&bricmp_types[..])?; 487 488 let lhs_var = self.get_variable_of_type(_type)?; 489 let lhs_val = builder.use_var(lhs_var); 490 491 let rhs_var = self.get_variable_of_type(_type)?; 492 let rhs_val = builder.use_var(rhs_var); 493 494 builder 495 .ins() 496 .br_icmp(cond, lhs_val, rhs_val, block, &args[..]); 497 498 // After bricmp's we must generate a jump 499 self.generate_jump(builder)?; 500 Ok(()) 501 } 502 503 fn generate_switch(&mut self, builder: &mut FunctionBuilder) -> Result<()> { 504 let _type = *self.u.choose(&[I8, I16, I32, I64, I128][..])?; 505 let switch_var = self.get_variable_of_type(_type)?; 506 let switch_val = builder.use_var(switch_var); 507 508 let valid_blocks = self.generate_valid_jumptable_target_blocks(); 509 let default_block = *self.u.choose(&valid_blocks[..])?; 510 511 // Build this into a HashMap since we cannot have duplicate entries. 512 let mut entries = HashMap::new(); 513 for _ in 0..self.param(&self.config.switch_cases)? { 514 // The Switch API only allows for entries that are addressable by the index type 515 // so we need to limit the range of values that we generate. 516 let (ty_min, ty_max) = _type.bounds(false); 517 let range_start = self.u.int_in_range(ty_min..=ty_max)?; 518 519 // We can either insert a contiguous range of blocks or a individual block 520 // This is done because the Switch API specializes contiguous ranges. 521 let range_size = if bool::arbitrary(self.u)? { 522 1 523 } else { 524 self.param(&self.config.switch_max_range_size)? 525 } as u128; 526 527 // Build the switch entries 528 for i in 0..range_size { 529 let index = range_start.wrapping_add(i) % ty_max; 530 let block = *self.u.choose(&valid_blocks[..])?; 531 entries.insert(index, block); 532 } 533 } 534 535 let mut switch = Switch::new(); 536 for (entry, block) in entries.into_iter() { 537 switch.set_entry(entry, block); 538 } 539 switch.emit(builder, switch_val, default_block); 540 541 Ok(()) 542 } 543 544 /// We always need to exit safely out of a block. 545 /// This either means a jump into another block or a return. 546 fn finalize_block(&mut self, builder: &mut FunctionBuilder) -> Result<()> { 547 let gen = self.u.choose( 548 &[ 549 Self::generate_bricmp, 550 Self::generate_br, 551 Self::generate_br_table, 552 Self::generate_jump, 553 Self::generate_return, 554 Self::generate_switch, 555 ][..], 556 )?; 557 558 gen(self, builder) 559 } 560 561 /// Fills the current block with random instructions 562 fn generate_instructions(&mut self, builder: &mut FunctionBuilder) -> Result<()> { 563 for _ in 0..self.param(&self.config.instructions_per_block)? { 564 let (op, args, rets, inserter) = *self.u.choose(OPCODE_SIGNATURES)?; 565 inserter(self, builder, op, args, rets)?; 566 } 567 568 Ok(()) 569 } 570 571 fn generate_jumptables(&mut self, builder: &mut FunctionBuilder) -> Result<()> { 572 let valid_blocks = self.generate_valid_jumptable_target_blocks(); 573 574 for _ in 0..self.param(&self.config.jump_tables_per_function)? { 575 let mut jt_data = JumpTableData::new(); 576 577 for _ in 0..self.param(&self.config.jump_table_entries)? { 578 let block = *self.u.choose(&valid_blocks[..])?; 579 jt_data.push_entry(block); 580 } 581 582 self.jump_tables.push(builder.create_jump_table(jt_data)); 583 } 584 Ok(()) 585 } 586 587 fn generate_stack_slots(&mut self, builder: &mut FunctionBuilder) -> Result<()> { 588 for _ in 0..self.param(&self.config.static_stack_slots_per_function)? { 589 let bytes = self.param(&self.config.static_stack_slot_size)? as u32; 590 let ss_data = StackSlotData::new(StackSlotKind::ExplicitSlot, bytes); 591 let slot = builder.create_sized_stack_slot(ss_data); 592 593 self.static_stack_slots.push(slot); 594 } 595 Ok(()) 596 } 597 598 /// Zero initializes the stack slot by inserting `stack_store`'s. 599 fn initialize_stack_slots(&mut self, builder: &mut FunctionBuilder) -> Result<()> { 600 let i128_zero = builder.ins().iconst(I128, 0); 601 let i64_zero = builder.ins().iconst(I64, 0); 602 let i32_zero = builder.ins().iconst(I32, 0); 603 let i16_zero = builder.ins().iconst(I16, 0); 604 let i8_zero = builder.ins().iconst(I8, 0); 605 606 for &slot in self.static_stack_slots.iter() { 607 let init_size = builder.func.sized_stack_slots[slot].size; 608 let mut size = init_size; 609 610 // Insert the largest available store for the remaining size. 611 while size != 0 { 612 let offset = (init_size - size) as i32; 613 let (val, filled) = match size { 614 sz if sz / 16 > 0 => (i128_zero, 16), 615 sz if sz / 8 > 0 => (i64_zero, 8), 616 sz if sz / 4 > 0 => (i32_zero, 4), 617 sz if sz / 2 > 0 => (i16_zero, 2), 618 _ => (i8_zero, 1), 619 }; 620 builder.ins().stack_store(val, slot, offset); 621 size -= filled; 622 } 623 } 624 Ok(()) 625 } 626 627 /// Creates a random amount of blocks in this function 628 fn generate_blocks( 629 &mut self, 630 builder: &mut FunctionBuilder, 631 sig: &Signature, 632 ) -> Result<Vec<(Block, BlockSignature)>> { 633 let extra_block_count = self.param(&self.config.blocks_per_function)?; 634 635 // We must always have at least one block, so we generate the "extra" blocks and add 1 for 636 // the entry block. 637 let block_count = 1 + extra_block_count; 638 639 let blocks = (0..block_count) 640 .map(|i| { 641 let is_entry = i == 0; 642 let block = builder.create_block(); 643 644 // Optionally mark blocks that are not the entry block as cold 645 if !is_entry { 646 if bool::arbitrary(self.u)? { 647 builder.set_cold_block(block); 648 } 649 } 650 651 // The first block has to have the function signature, but for the rest of them we generate 652 // a random signature; 653 if is_entry { 654 builder.append_block_params_for_function_params(block); 655 Ok((block, sig.params.iter().map(|a| a.value_type).collect())) 656 } else { 657 let sig = self.generate_block_signature()?; 658 sig.iter().for_each(|ty| { 659 builder.append_block_param(block, *ty); 660 }); 661 Ok((block, sig)) 662 } 663 }) 664 .collect::<Result<Vec<_>>>()?; 665 666 Ok(blocks) 667 } 668 669 fn generate_block_signature(&mut self) -> Result<BlockSignature> { 670 let param_count = self.param(&self.config.block_signature_params)?; 671 672 let mut params = Vec::with_capacity(param_count); 673 for _ in 0..param_count { 674 params.push(self.generate_type()?); 675 } 676 Ok(params) 677 } 678 679 fn build_variable_pool(&mut self, builder: &mut FunctionBuilder) -> Result<()> { 680 let block = builder.current_block().unwrap(); 681 let func_params = builder.func.signature.params.clone(); 682 683 // Define variables for the function signature 684 for (i, param) in func_params.iter().enumerate() { 685 let var = self.create_var(builder, param.value_type)?; 686 let block_param = builder.block_params(block)[i]; 687 builder.def_var(var, block_param); 688 } 689 690 // Create a pool of vars that are going to be used in this function 691 for _ in 0..self.param(&self.config.vars_per_function)? { 692 let ty = self.generate_type()?; 693 let var = self.create_var(builder, ty)?; 694 let value = self.generate_const(builder, ty)?; 695 builder.def_var(var, value); 696 } 697 698 Ok(()) 699 } 700 701 /// We generate a function in multiple stages: 702 /// 703 /// * First we generate a random number of empty blocks 704 /// * Then we generate a random pool of variables to be used throughout the function 705 /// * We then visit each block and generate random instructions 706 /// 707 /// Because we generate all blocks and variables up front we already know everything that 708 /// we need when generating instructions (i.e. jump targets / variables) 709 pub fn generate(mut self) -> Result<Function> { 710 let sig = self.generate_signature()?; 711 712 let mut fn_builder_ctx = FunctionBuilderContext::new(); 713 let mut func = Function::with_name_signature(ExternalName::user(0, 1), sig.clone()); 714 715 let mut builder = FunctionBuilder::new(&mut func, &mut fn_builder_ctx); 716 717 self.blocks = self.generate_blocks(&mut builder, &sig)?; 718 719 // Function preamble 720 self.generate_jumptables(&mut builder)?; 721 self.generate_stack_slots(&mut builder)?; 722 723 // Main instruction generation loop 724 for (i, (block, block_sig)) in self.blocks.clone().iter().enumerate() { 725 let is_block0 = i == 0; 726 builder.switch_to_block(*block); 727 728 if is_block0 { 729 // The first block is special because we must create variables both for the 730 // block signature and for the variable pool. Additionally, we must also define 731 // initial values for all variables that are not the function signature. 732 self.build_variable_pool(&mut builder)?; 733 734 // Stack slots have random bytes at the beginning of the function 735 // initialize them to a constant value so that execution stays predictable. 736 self.initialize_stack_slots(&mut builder)?; 737 } else { 738 // Define variables for the block params 739 for (i, ty) in block_sig.iter().enumerate() { 740 let var = self.get_variable_of_type(*ty)?; 741 let block_param = builder.block_params(*block)[i]; 742 builder.def_var(var, block_param); 743 } 744 } 745 746 // Generate block instructions 747 self.generate_instructions(&mut builder)?; 748 749 self.finalize_block(&mut builder)?; 750 } 751 752 builder.seal_all_blocks(); 753 builder.finalize(); 754 755 Ok(func) 756 } 757 } 758