1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
use super::*;
use std::mem;
impl Module {
pub fn ensure_termination(&mut self, default_fuel: u32) -> u32 {
self.inner.ensure_termination(default_fuel)
}
}
impl<C> ConfiguredModule<C>
where
C: Config,
{
pub fn ensure_termination(&mut self, default_fuel: u32) -> u32 {
let fuel_global = self.global_imports() + self.globals.len() as u32;
self.globals.push(Global {
ty: GlobalType {
val_type: ValType::I32,
mutable: true,
},
expr: Instruction::I32Const(default_fuel as i32),
});
for code in &mut self.code {
let check_fuel = |insts: &mut Vec<Instruction>| {
insts.push(Instruction::GlobalGet(fuel_global));
insts.push(Instruction::I32Eqz);
insts.push(Instruction::If(BlockType::Empty));
insts.push(Instruction::Unreachable);
insts.push(Instruction::End);
insts.push(Instruction::GlobalGet(fuel_global));
insts.push(Instruction::I32Const(1));
insts.push(Instruction::I32Sub);
insts.push(Instruction::GlobalSet(fuel_global));
};
let instrs = match &mut code.instructions {
Instructions::Generated(list) => list,
Instructions::Arbitrary(_) => unreachable!(),
};
let mut new_insts = Vec::with_capacity(instrs.len() * 2);
check_fuel(&mut new_insts);
for inst in mem::replace(instrs, vec![]) {
let is_loop = matches!(&inst, Instruction::Loop(_));
new_insts.push(inst);
if is_loop {
check_fuel(&mut new_insts);
}
}
*instrs = new_insts;
}
fuel_global
}
}