-
-
Notifications
You must be signed in to change notification settings - Fork 17
/
Copy pathtail_call_transformer.rs
50 lines (44 loc) · 1.38 KB
/
tail_call_transformer.rs
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
use tarnik_ast::{WatFunction, WatInstruction, WatModule};
pub struct TailCallTransformer {
module: WatModule,
}
impl TailCallTransformer {
pub fn new(module: WatModule) -> Self {
Self { module }
}
pub fn transform(mut self) -> WatModule {
self._transform();
// consume self and return the modified module
std::mem::take(&mut self.module)
}
fn _transform(&mut self) {
for function in self.module.functions_mut().into_iter() {
transform_function(function);
}
}
}
// TODO: at the moment it's a very simplistic check for tail calls, in the future it
// would be nice to handle more complex cases, like
//
// function foo(n) {
// let ret = foo(n - 1);
// return ret;
// }
fn transform_function(function: &mut WatFunction) {
if !function.has_results() {
return;
}
let mut i = 0;
let mut body = function.body.borrow_mut();
while i < body.len() {
if body[i].is_return() && i > 0 && body[i - 1].is_call() {
// replace the call instruction with nop
let call = std::mem::replace(&mut body[i - 1], WatInstruction::Nop);
if let WatInstruction::Call(name) = call {
// replace return with return_call
let _ = std::mem::replace(&mut body[i], WatInstruction::r#return_call(name));
}
}
i += 1;
}
}