@@ -31,6 +31,10 @@ let times = Debug.find "times"
3131
3232open Code
3333
34+ let associated_list h x = try Var.Hashtbl. find h x with Not_found -> []
35+
36+ let add_to_list h x v = Var.Hashtbl. replace h x (v :: associated_list h x)
37+
3438(* ***)
3539
3640(* Compute the list of variables containing the return values of each
@@ -83,7 +87,7 @@ type escape_status =
8387
8488type state =
8589 { vars : Var.ISet .t (* Set of all veriables considered *)
86- ; deps : Var .t Var.Tbl.DataSet .t Var.Tbl .t (* Dependency between variables *)
90+ ; deps : Var .t list Var.Tbl .t (* Dependency between variables *)
8791 ; defs : def array (* Definition of each variable *)
8892 ; variable_may_escape : escape_status array
8993 (* Any value bound to this variable may escape *)
@@ -93,20 +97,24 @@ type state =
9397 ; possibly_mutable : Var.ISet .t (* This value may be mutable *)
9498 ; return_values : Var.Set .t Var.Map .t
9599 (* Set of variables holding return values of each function *)
96- ; known_cases : (Var .t , int list ) Hashtbl .t
100+ ; functions_from_returned_value : Var .t list Var.Hashtbl .t
101+ (* Functions associated to each return value *)
102+ ; known_cases : int list Var.Hashtbl .t
97103 (* Possible tags for a block after a [switch]. This is used to
98104 get a more precise approximation of the effect of a field
99105 access [Field] *)
100106 ; applied_functions : (Var .t * Var .t , unit ) Hashtbl .t
101107 (* Functions that have been already considered at a call site.
102108 This is to avoid repeated computations *)
109+ ; function_call_sites : Var .t list Var.Hashtbl .t
110+ (* Known call sites of each functions *)
103111 ; fast : bool
104112 }
105113
106114let add_var st x = Var.ISet. add st.vars x
107115
108116(* x depends on y *)
109- let add_dep st x y = Var.Tbl. add_set st.deps y x
117+ let add_dep st x y = Var.Tbl. set st.deps y (x :: Var.Tbl. get st.deps y)
110118
111119let add_expr_def st x e =
112120 add_var st x;
@@ -223,10 +231,10 @@ let expr_deps blocks st x e =
223231 match st.defs.(Var. idx f) with
224232 | Expr (Closure (params , _ )) when List. length args = List. length params ->
225233 Hashtbl. add st.applied_functions (x, f) () ;
234+ add_to_list st.function_call_sites f x;
226235 if st.fast
227236 then List. iter ~f: (fun a -> do_escape st Escape a) args
228- else List. iter2 ~f: (fun p a -> add_assign_def st p a) params args;
229- Var.Set. iter (fun y -> add_dep st x y) (Var.Map. find f st.return_values)
237+ else List. iter2 ~f: (fun p a -> add_assign_def st p a) params args
230238 | _ -> () )
231239 | Closure (l , cont ) ->
232240 List. iter l ~f: (fun x -> add_param_def st x);
@@ -285,7 +293,7 @@ let program_deps st { start; blocks; _ } =
285293 ~f: (fun i ->
286294 match i with
287295 | Let (y , Field (x' , _ , _ )) when Var. equal b x' ->
288- Hashtbl. add st.known_cases y tags
296+ Var. Hashtbl. add st.known_cases y tags
289297 | _ -> () )
290298 block.body)
291299 h
@@ -420,7 +428,7 @@ let propagate st ~update approx x =
420428 match Var.Tbl. get approx y with
421429 | Values { known; others } ->
422430 let tags =
423- try Some (Hashtbl. find st.known_cases x) with Not_found -> None
431+ try Some (Var. Hashtbl. find st.known_cases x) with Not_found -> None
424432 in
425433 Domain. join_set
426434 ~others
@@ -506,6 +514,7 @@ let propagate st ~update approx x =
506514 if not (Hashtbl. mem st.applied_functions (x, g))
507515 then (
508516 Hashtbl. add st.applied_functions (x, g) () ;
517+ add_to_list st.function_call_sites g x;
509518 if st.fast
510519 then
511520 List. iter
@@ -518,18 +527,15 @@ let propagate st ~update approx x =
518527 add_assign_def st p a;
519528 update ~children: false p)
520529 params
521- args;
522- Var.Set. iter
523- (fun y -> add_dep st x y)
524- (Var.Map. find g st.return_values));
530+ args);
525531 Domain. join_set
526532 ~update
527533 ~st
528534 ~approx
529535 (fun y -> Var.Tbl. get approx y)
530536 (Var.Map. find g st.return_values)
531537 | Expr (Closure (_ , _ )) ->
532- (* The funciton is partially applied or over applied *)
538+ (* The function is partially applied or over applied *)
533539 List. iter
534540 ~f: (fun y -> Domain. variable_escape ~update ~st ~approx Escape y)
535541 args;
@@ -599,7 +605,11 @@ let solver st =
599605 let g =
600606 { G. domain = st.vars
601607 ; G. iter_children =
602- (fun f x -> Var.Tbl.DataSet. iter (fun k -> f k) (Var.Tbl. get st.deps x))
608+ (fun f x ->
609+ List. iter ~f (Var.Tbl. get st.deps x);
610+ List. iter
611+ ~f: (fun g -> List. iter ~f (associated_list st.function_call_sites g))
612+ (associated_list st.functions_from_returned_value x))
603613 }
604614 in
605615 let res = Solver. f' () g (propagate st) in
@@ -632,24 +642,30 @@ let f ~fast p =
632642 let rets = return_values p in
633643 let nv = Var. count () in
634644 let vars = Var.ISet. empty () in
635- let deps = Var.Tbl. make_set () in
645+ let deps = Var.Tbl. make () [] in
636646 let defs = Array. make nv undefined in
637647 let variable_may_escape = Array. make nv No in
638648 let variable_possibly_mutable = Var.ISet. empty () in
639649 let may_escape = Array. make nv No in
640650 let possibly_mutable = Var.ISet. empty () in
651+ let functions_from_returned_value = Var.Hashtbl. create 128 in
652+ Var.Map. iter
653+ (fun f s -> Var.Set. iter (fun x -> add_to_list functions_from_returned_value x f) s)
654+ rets;
641655 let st =
642656 { vars
643657 ; deps
644658 ; defs
645659 ; return_values = rets
660+ ; functions_from_returned_value
646661 ; variable_may_escape
647662 ; variable_possibly_mutable
648663 ; may_escape
649664 ; possibly_mutable
650- ; known_cases = Hashtbl. create 16
665+ ; known_cases = Var. Hashtbl. create 16
651666 ; applied_functions = Hashtbl. create 16
652667 ; fast
668+ ; function_call_sites = Var.Hashtbl. create 128
653669 }
654670 in
655671 program_deps st p;
0 commit comments