@@ -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+
96101type 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
163168let 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
167179let 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