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
open! Stdlib
open Code
let pure_expr pure_funs e =
match e with
| Block _ | Field _ | Closure _ | Constant _ -> true
| Special (Alias_prim _ | Undefined) -> true
| Apply { f; exact; _ } -> exact && Var.Set.mem f pure_funs
| Prim (p, _l) -> (
match p with
| Extern f -> Primitive.is_pure f
| _ -> true)
let pure_instr pure_funs i =
match i with
| Let (_, e) -> pure_expr pure_funs e
| Assign _ -> true
| Set_field _ | Offset_ref _ | Array_set _ -> false
let rec traverse blocks pc visited funs =
try Addr.Map.find pc visited, visited, funs
with Not_found ->
let visited = Addr.Map.add pc false visited in
let pure, visited, funs =
fold_children
blocks
pc
(fun pc (pure, visited, funs) ->
let pure', visited, funs = traverse blocks pc visited funs in
pure && pure', visited, funs)
(true, visited, funs)
in
let pure, visited, funs = block blocks pc pure visited funs in
pure, Addr.Map.add pc pure visited, funs
and block blocks pc pure visited funs =
let b = Addr.Map.find pc blocks in
let pure =
match fst b.branch with
| Raise _ -> false
| _ -> pure
in
List.fold_left
b.body
~init:(pure, visited, funs)
~f:(fun (pure, visited, funs) (i, _loc) ->
let visited, funs =
match i with
| Let (x, Closure (_, (pc, _))) ->
let pure, visited, funs = traverse blocks pc visited funs in
visited, if pure then Var.Set.add x funs else funs
| _ -> visited, funs
in
pure && pure_instr funs i, visited, funs)
let f p =
let _, _, funs = traverse p.blocks p.start Addr.Map.empty Var.Set.empty in
funs