@@ -85,16 +85,21 @@ type escape_status =
8585 | Escape_constant (* Escapes but we know the value is not modified *)
8686 | No
8787
88+ type mutable_fields =
89+ | No_field
90+ | Some_fields of IntSet .t
91+ | All_fields
92+
8893type state =
8994 { vars : Var.ISet .t (* Set of all veriables considered *)
9095 ; deps : Var .t list Var.Tbl .t (* Dependency between variables *)
9196 ; defs : def array (* Definition of each variable *)
9297 ; variable_may_escape : escape_status array
9398 (* Any value bound to this variable may escape *)
94- ; variable_possibly_mutable : Var.ISet .t
99+ ; variable_mutable_fields : mutable_fields array
95100 (* Any value bound to this variable may be mutable *)
96101 ; may_escape : escape_status array (* This value may escape *)
97- ; possibly_mutable : Var.ISet .t (* This value may be mutable *)
102+ ; mutable_fields : mutable_fields array (* This value may be mutable *)
98103 ; return_values : Var.Set .t Var.Map .t
99104 (* Set of variables holding return values of each function *)
100105 ; functions_from_returned_value : Var .t list Var.Hashtbl .t
@@ -154,7 +159,14 @@ let cont_deps blocks st ?ignore (pc, args) =
154159
155160let do_escape st level x = st.variable_may_escape.(Var. idx x) < - level
156161
157- let possibly_mutable st x = Var.ISet. add st.variable_possibly_mutable x
162+ let possibly_mutable st x = st.variable_mutable_fields.(Var. idx x) < - All_fields
163+
164+ let field_possibly_mutable st x n =
165+ match st.variable_mutable_fields.(Var. idx x) with
166+ | No_field -> st.variable_mutable_fields.(Var. idx x) < - Some_fields (IntSet. singleton n)
167+ | Some_fields s ->
168+ st.variable_mutable_fields.(Var. idx x) < - Some_fields (IntSet. add n s)
169+ | All_fields -> ()
158170
159171let expr_deps blocks st x e =
160172 match e with
@@ -259,7 +271,10 @@ let program_deps st { start; blocks; _ } =
259271 add_expr_def st x e;
260272 expr_deps blocks st x e
261273 | Assign (x , y ) -> add_assign_def st x y
262- | Set_field (x , _ , _ , y ) | Array_set (x , _ , y ) ->
274+ | Set_field (x , n , _ , y ) ->
275+ field_possibly_mutable st x n;
276+ do_escape st Escape y
277+ | Array_set (x , _ , y ) ->
263278 possibly_mutable st x;
264279 do_escape st Escape y
265280 | Event _ | Offset_ref _ -> () );
@@ -352,7 +367,7 @@ module Domain = struct
352367 Array. iter ~f: (fun y -> variable_escape ~update ~st ~approx s y) a;
353368 match s, mut with
354369 | Escape , Maybe_mutable ->
355- Var.ISet. add st.possibly_mutable x ;
370+ st.mutable_fields.( Var. idx x) < - All_fields ;
356371 update ~children: true x
357372 | (Escape_constant | No ), _ | Escape , Immutable -> () )
358373 | Expr (Closure (params , _ , _ )) ->
@@ -397,18 +412,28 @@ module Domain = struct
397412 s
398413 (if o then others else bot)
399414
400- let mark_mutable ~update ~st a =
415+ let mark_mutable ~update ~st a mutable_fields =
401416 match a with
402417 | Top -> ()
403418 | Values { known; _ } ->
404419 Var.Set. iter
405420 (fun x ->
406421 match st.defs.(Var. idx x) with
407- | Expr (Block (_ , _ , _ , Maybe_mutable)) ->
408- if not (Var.ISet. mem st.possibly_mutable x)
409- then (
410- Var.ISet. add st.possibly_mutable x;
411- update ~children: true x)
422+ | Expr (Block (_ , _ , _ , Maybe_mutable)) -> (
423+ match st.mutable_fields.(Var. idx x), mutable_fields with
424+ | _ , No_field -> ()
425+ | No_field , _ ->
426+ st.mutable_fields.(Var. idx x) < - mutable_fields;
427+ update ~children: true x
428+ | Some_fields s , Some_fields s' ->
429+ if IntSet. exists (fun i -> not (IntSet. mem i s)) s'
430+ then (
431+ st.mutable_fields.(Var. idx x) < - Some_fields (IntSet. union s s');
432+ update ~children: true x)
433+ | Some_fields _ , All_fields ->
434+ st.mutable_fields.(Var. idx x) < - All_fields ;
435+ update ~children: true x
436+ | All_fields , _ -> () )
412437 | Expr (Block (_ , _ , _ , Immutable )) | Expr (Closure _ ) -> ()
413438 | Phi _ | Expr _ -> assert false )
414439 known
@@ -444,7 +469,12 @@ let propagate st ~update approx x =
444469 | Some tags -> List. memq t ~set: tags
445470 | None -> true ->
446471 let t = a.(n) in
447- let m = Var.ISet. mem st.possibly_mutable z in
472+ let m =
473+ match st.mutable_fields.(Var. idx z) with
474+ | No_field -> false
475+ | Some_fields s -> IntSet. mem n s
476+ | All_fields -> true
477+ in
448478 if not m then add_dep st x z;
449479 add_dep st x t;
450480 let a = Var.Tbl. get approx t in
@@ -472,7 +502,11 @@ let propagate st ~update approx x =
472502 (fun z ->
473503 match st.defs.(Var. idx z) with
474504 | Expr (Block (_ , lst , _ , _ )) ->
475- let m = Var.ISet. mem st.possibly_mutable z in
505+ let m =
506+ match st.mutable_fields.(Var. idx z) with
507+ | No_field -> false
508+ | Some_fields _ | All_fields -> true
509+ in
476510 if not m then add_dep st x z;
477511 Array. iter ~f: (fun t -> add_dep st x t) lst;
478512 let a =
@@ -566,8 +600,9 @@ let propagate st ~update approx x =
566600 (match st.variable_may_escape.(Var. idx x) with
567601 | (Escape | Escape_constant ) as s -> Domain. approx_escape ~update ~st ~approx s res
568602 | No -> () );
569- if Var.ISet. mem st.variable_possibly_mutable x
570- then Domain. mark_mutable ~update ~st res;
603+ (match st.variable_mutable_fields.(Var. idx x) with
604+ | No_field -> ()
605+ | (Some_fields _ | All_fields ) as s -> Domain. mark_mutable ~update ~st res s);
571606 res
572607 | Top -> Top
573608
@@ -645,9 +680,9 @@ let f ~fast p =
645680 let deps = Var.Tbl. make () [] in
646681 let defs = Array. make nv undefined in
647682 let variable_may_escape = Array. make nv No in
648- let variable_possibly_mutable = Var.ISet. empty () in
683+ let variable_mutable_fields = Array. make nv No_field in
649684 let may_escape = Array. make nv No in
650- let possibly_mutable = Var.ISet. empty () in
685+ let mutable_fields = Array. make nv No_field in
651686 let functions_from_returned_value = Var.Hashtbl. create 128 in
652687 Var.Map. iter
653688 (fun f s -> Var.Set. iter (fun x -> add_to_list functions_from_returned_value x f) s)
@@ -659,9 +694,9 @@ let f ~fast p =
659694 ; return_values = rets
660695 ; functions_from_returned_value
661696 ; variable_may_escape
662- ; variable_possibly_mutable
697+ ; variable_mutable_fields
663698 ; may_escape
664- ; possibly_mutable
699+ ; mutable_fields
665700 ; known_cases = Var.Hashtbl. create 16
666701 ; applied_functions = Hashtbl. create 16
667702 ; fast
@@ -690,13 +725,28 @@ let f ~fast p =
690725 match a with
691726 | Top -> Format. fprintf f " top"
692727 | Values _ ->
728+ let print_mutable_fields f s =
729+ match s with
730+ | No_field -> Format. fprintf f " no"
731+ | Some_fields s ->
732+ Format. fprintf
733+ f
734+ " {%a}"
735+ (Format. pp_print_list
736+ ~pp_sep: (fun f () -> Format. fprintf f " , " )
737+ (fun f i -> Format. fprintf f " %d" i))
738+ (IntSet. elements s)
739+ | All_fields -> Format. fprintf f " yes"
740+ in
693741 Format. fprintf
694742 f
695- " %a mut:%b vmut:%b vesc:%s esc:%s"
743+ " %a mut:%a vmut:%a vesc:%s esc:%s"
696744 (print_approx st)
697745 a
698- (Var.ISet. mem st.possibly_mutable x)
699- (Var.ISet. mem st.variable_possibly_mutable x)
746+ print_mutable_fields
747+ st.mutable_fields.(Var. idx x)
748+ print_mutable_fields
749+ st.variable_mutable_fields.(Var. idx x)
700750 (match st.variable_may_escape.(Var. idx x) with
701751 | Escape -> " Y"
702752 | Escape_constant -> " y"
0 commit comments