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