Skip to content

Commit 228071b

Browse files
committed
Function call analysis
1 parent a06177b commit 228071b

File tree

2 files changed

+66
-0
lines changed

2 files changed

+66
-0
lines changed
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
open! Stdlib
2+
open Code
3+
4+
let debug = Debug.find "call-graph"
5+
6+
let get_approx info x =
7+
(* Specialization can add some variables *)
8+
if Var.idx x < Var.Tbl.length info.Global_flow.info_approximation
9+
then Var.Tbl.get info.Global_flow.info_approximation x
10+
else Top
11+
12+
let block_deps ~info ~non_escaping ~ambiguous ~blocks pc =
13+
let block = Addr.Map.find pc blocks in
14+
List.iter block.body ~f:(fun i ->
15+
match i with
16+
| Let (_, Apply { f; _ }) -> (
17+
match get_approx info f with
18+
| Top -> ()
19+
| Values { known; others } ->
20+
if others || Var.Set.cardinal known > 1
21+
then Var.Set.iter (fun x -> Var.Hashtbl.replace ambiguous x ()) known;
22+
if debug ()
23+
then
24+
Format.eprintf "CALL others:%b known:%d@." others (Var.Set.cardinal known)
25+
)
26+
| Let (x, Closure _) -> (
27+
match get_approx info x with
28+
| Top -> ()
29+
| Values { known; others } ->
30+
if Var.Set.cardinal known = 1 && (not others) && Var.Set.mem x known
31+
then (
32+
let may_escape = Var.ISet.mem info.Global_flow.info_may_escape x in
33+
if debug () then Format.eprintf "CLOSURE may-escape:%b@." may_escape;
34+
if not may_escape then Var.Hashtbl.replace non_escaping x ()))
35+
| Let (_, (Prim _ | Block _ | Constant _ | Field _ | Special _))
36+
| Event _ | Assign _ | Set_field _ | Offset_ref _ | Array_set _ -> ())
37+
38+
type t = { unambiguous_non_escaping : unit Var.Hashtbl.t }
39+
40+
let direct_calls_only info f =
41+
Config.Flag.optcall () && Var.Hashtbl.mem info.unambiguous_non_escaping f
42+
43+
let f p info =
44+
let non_escaping = Var.Hashtbl.create 128 in
45+
let ambiguous = Var.Hashtbl.create 128 in
46+
fold_closures
47+
p
48+
(fun _ _ (pc, _) _ () ->
49+
traverse
50+
{ fold = Code.fold_children }
51+
(fun pc () -> block_deps ~info ~non_escaping ~ambiguous ~blocks:p.blocks pc)
52+
pc
53+
p.blocks
54+
())
55+
();
56+
if debug ()
57+
then Format.eprintf "SUMMARY non-escaping:%d" (Var.Hashtbl.length non_escaping);
58+
Var.Hashtbl.iter (fun x () -> Var.Hashtbl.remove non_escaping x) ambiguous;
59+
if debug ()
60+
then Format.eprintf " unambiguous-non-escaping:%d@." (Var.Hashtbl.length non_escaping);
61+
{ unambiguous_non_escaping = non_escaping }
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
type t
2+
3+
val direct_calls_only : t -> Code.Var.t -> bool
4+
5+
val f : Code.program -> Global_flow.info -> t

0 commit comments

Comments
 (0)