Skip to content

Commit 0ffba92

Browse files
committed
Global flow analysis: keep track of which fields are mutable
1 parent cd67924 commit 0ffba92

File tree

1 file changed

+72
-22
lines changed

1 file changed

+72
-22
lines changed

compiler/lib/global_flow.ml

Lines changed: 72 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -93,16 +93,21 @@ type escape_status =
9393
| Escape_constant (* Escapes but we know the value is not modified *)
9494
| No
9595

96+
type mutable_fields =
97+
| No_field
98+
| Some_fields of IntSet.t
99+
| All_fields
100+
96101
type state =
97102
{ vars : Var.ISet.t (* Set of all veriables considered *)
98103
; deps : Var.t list Var.Tbl.t (* Dependency between variables *)
99104
; defs : def array (* Definition of each variable *)
100105
; variable_may_escape : escape_status array
101106
(* Any value bound to this variable may escape *)
102-
; variable_possibly_mutable : Var.ISet.t
107+
; variable_mutable_fields : mutable_fields array
103108
(* Any value bound to this variable may be mutable *)
104109
; may_escape : escape_status array (* This value may escape *)
105-
; possibly_mutable : Var.ISet.t (* This value may be mutable *)
110+
; mutable_fields : mutable_fields array (* This value may be mutable *)
106111
; return_values : Var.Set.t Var.Map.t
107112
(* Set of variables holding return values of each function *)
108113
; functions_from_returned_value : Var.t list Var.Hashtbl.t
@@ -162,7 +167,14 @@ let cont_deps blocks st ?ignore (pc, args) =
162167

163168
let do_escape st level x = st.variable_may_escape.(Var.idx x) <- level
164169

165-
let possibly_mutable st x = Var.ISet.add st.variable_possibly_mutable x
170+
let possibly_mutable st x = st.variable_mutable_fields.(Var.idx x) <- All_fields
171+
172+
let field_possibly_mutable st x n =
173+
match st.variable_mutable_fields.(Var.idx x) with
174+
| No_field -> st.variable_mutable_fields.(Var.idx x) <- Some_fields (IntSet.singleton n)
175+
| Some_fields s ->
176+
st.variable_mutable_fields.(Var.idx x) <- Some_fields (IntSet.add n s)
177+
| All_fields -> ()
166178

167179
let expr_deps blocks st x e =
168180
match e with
@@ -267,7 +279,10 @@ let program_deps st { start; blocks; _ } =
267279
add_expr_def st x e;
268280
expr_deps blocks st x e
269281
| Assign (x, y) -> add_assign_def st x y
270-
| Set_field (x, _, _, y) | Array_set (x, _, y) ->
282+
| Set_field (x, n, _, y) ->
283+
field_possibly_mutable st x n;
284+
do_escape st Escape y
285+
| Array_set (x, _, y) ->
271286
possibly_mutable st x;
272287
do_escape st Escape y
273288
| Event _ | Offset_ref _ -> ());
@@ -360,7 +375,7 @@ module Domain = struct
360375
Array.iter ~f:(fun y -> variable_escape ~update ~st ~approx s y) a;
361376
match s, mut with
362377
| Escape, Maybe_mutable ->
363-
Var.ISet.add st.possibly_mutable x;
378+
st.mutable_fields.(Var.idx x) <- All_fields;
364379
update ~children:true x
365380
| (Escape_constant | No), _ | Escape, Immutable -> ())
366381
| Expr (Closure (params, _, _)) ->
@@ -405,18 +420,28 @@ module Domain = struct
405420
s
406421
(if o then others else bot)
407422

408-
let mark_mutable ~update ~st a =
423+
let mark_mutable ~update ~st a mutable_fields =
409424
match a with
410425
| Top -> ()
411426
| Values { known; _ } ->
412427
Var.Set.iter
413428
(fun x ->
414429
match st.defs.(Var.idx x) with
415-
| Expr (Block (_, _, _, Maybe_mutable)) ->
416-
if not (Var.ISet.mem st.possibly_mutable x)
417-
then (
418-
Var.ISet.add st.possibly_mutable x;
419-
update ~children:true x)
430+
| Expr (Block (_, _, _, Maybe_mutable)) -> (
431+
match st.mutable_fields.(Var.idx x), mutable_fields with
432+
| _, No_field -> ()
433+
| No_field, _ ->
434+
st.mutable_fields.(Var.idx x) <- mutable_fields;
435+
update ~children:true x
436+
| Some_fields s, Some_fields s' ->
437+
if IntSet.exists (fun i -> not (IntSet.mem i s)) s'
438+
then (
439+
st.mutable_fields.(Var.idx x) <- Some_fields (IntSet.union s s');
440+
update ~children:true x)
441+
| Some_fields _, All_fields ->
442+
st.mutable_fields.(Var.idx x) <- All_fields;
443+
update ~children:true x
444+
| All_fields, _ -> ())
420445
| Expr (Block (_, _, _, Immutable)) | Expr (Closure _) -> ()
421446
| Phi _ | Expr _ -> assert false)
422447
known
@@ -452,7 +477,12 @@ let propagate st ~update approx x =
452477
| Some tags -> List.mem ~eq:Int.equal t tags
453478
| None -> true ->
454479
let t = a.(n) in
455-
let m = Var.ISet.mem st.possibly_mutable z in
480+
let m =
481+
match st.mutable_fields.(Var.idx z) with
482+
| No_field -> false
483+
| Some_fields s -> IntSet.mem n s
484+
| All_fields -> true
485+
in
456486
if not m then add_dep st x z;
457487
add_dep st x t;
458488
let a = Var.Tbl.get approx t in
@@ -480,7 +510,11 @@ let propagate st ~update approx x =
480510
(fun z ->
481511
match st.defs.(Var.idx z) with
482512
| Expr (Block (_, lst, _, _)) ->
483-
let m = Var.ISet.mem st.possibly_mutable z in
513+
let m =
514+
match st.mutable_fields.(Var.idx z) with
515+
| No_field -> false
516+
| Some_fields _ | All_fields -> true
517+
in
484518
if not m then add_dep st x z;
485519
Array.iter ~f:(fun t -> add_dep st x t) lst;
486520
let a =
@@ -574,8 +608,9 @@ let propagate st ~update approx x =
574608
(match st.variable_may_escape.(Var.idx x) with
575609
| (Escape | Escape_constant) as s -> Domain.approx_escape ~update ~st ~approx s res
576610
| No -> ());
577-
if Var.ISet.mem st.variable_possibly_mutable x
578-
then Domain.mark_mutable ~update ~st res;
611+
(match st.variable_mutable_fields.(Var.idx x) with
612+
| No_field -> ()
613+
| (Some_fields _ | All_fields) as s -> Domain.mark_mutable ~update ~st res s);
579614
res
580615
| Top -> Top
581616

@@ -653,9 +688,9 @@ let f ~fast p =
653688
let deps = Var.Tbl.make () [] in
654689
let defs = Array.make nv undefined in
655690
let variable_may_escape = Array.make nv No in
656-
let variable_possibly_mutable = Var.ISet.empty () in
691+
let variable_mutable_fields = Array.make nv No_field in
657692
let may_escape = Array.make nv No in
658-
let possibly_mutable = Var.ISet.empty () in
693+
let mutable_fields = Array.make nv No_field in
659694
let functions_from_returned_value = Var.Hashtbl.create 128 in
660695
Var.Map.iter
661696
(fun f s -> Var.Set.iter (fun x -> add_to_list functions_from_returned_value x f) s)
@@ -667,9 +702,9 @@ let f ~fast p =
667702
; return_values = rets
668703
; functions_from_returned_value
669704
; variable_may_escape
670-
; variable_possibly_mutable
705+
; variable_mutable_fields
671706
; may_escape
672-
; possibly_mutable
707+
; mutable_fields
673708
; known_cases = Var.Hashtbl.create 16
674709
; applied_functions = VarPairTbl.create 16
675710
; fast
@@ -698,13 +733,28 @@ let f ~fast p =
698733
match a with
699734
| Top -> Format.fprintf f "top"
700735
| Values _ ->
736+
let print_mutable_fields f s =
737+
match s with
738+
| No_field -> Format.fprintf f "no"
739+
| Some_fields s ->
740+
Format.fprintf
741+
f
742+
"{%a}"
743+
(Format.pp_print_list
744+
~pp_sep:(fun f () -> Format.fprintf f ", ")
745+
(fun f i -> Format.fprintf f "%d" i))
746+
(IntSet.elements s)
747+
| All_fields -> Format.fprintf f "yes"
748+
in
701749
Format.fprintf
702750
f
703-
"%a mut:%b vmut:%b vesc:%s esc:%s"
751+
"%a mut:%a vmut:%a vesc:%s esc:%s"
704752
(print_approx st)
705753
a
706-
(Var.ISet.mem st.possibly_mutable x)
707-
(Var.ISet.mem st.variable_possibly_mutable x)
754+
print_mutable_fields
755+
st.mutable_fields.(Var.idx x)
756+
print_mutable_fields
757+
st.variable_mutable_fields.(Var.idx x)
708758
(match st.variable_may_escape.(Var.idx x) with
709759
| Escape -> "Y"
710760
| Escape_constant -> "y"

0 commit comments

Comments
 (0)