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