@@ -85,16 +85,21 @@ type escape_status =
85
85
| Escape_constant (* Escapes but we know the value is not modified *)
86
86
| No
87
87
88
+ type mutable_fields =
89
+ | No_field
90
+ | Some_fields of IntSet .t
91
+ | All_fields
92
+
88
93
type state =
89
94
{ vars : Var.ISet .t (* Set of all veriables considered *)
90
95
; deps : Var .t list Var.Tbl .t (* Dependency between variables *)
91
96
; defs : def array (* Definition of each variable *)
92
97
; variable_may_escape : escape_status array
93
98
(* Any value bound to this variable may escape *)
94
- ; variable_possibly_mutable : Var.ISet .t
99
+ ; variable_mutable_fields : mutable_fields array
95
100
(* Any value bound to this variable may be mutable *)
96
101
; 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 *)
98
103
; return_values : Var.Set .t Var.Map .t
99
104
(* Set of variables holding return values of each function *)
100
105
; functions_from_returned_value : Var .t list Var.Hashtbl .t
@@ -154,7 +159,14 @@ let cont_deps blocks st ?ignore (pc, args) =
154
159
155
160
let do_escape st level x = st.variable_may_escape.(Var. idx x) < - level
156
161
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 -> ()
158
170
159
171
let expr_deps blocks st x e =
160
172
match e with
@@ -259,7 +271,10 @@ let program_deps st { start; blocks; _ } =
259
271
add_expr_def st x e;
260
272
expr_deps blocks st x e
261
273
| 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 ) ->
263
278
possibly_mutable st x;
264
279
do_escape st Escape y
265
280
| Event _ | Offset_ref _ -> () );
@@ -352,7 +367,7 @@ module Domain = struct
352
367
Array. iter ~f: (fun y -> variable_escape ~update ~st ~approx s y) a;
353
368
match s, mut with
354
369
| Escape , Maybe_mutable ->
355
- Var.ISet. add st.possibly_mutable x ;
370
+ st.mutable_fields.( Var. idx x) < - All_fields ;
356
371
update ~children: true x
357
372
| (Escape_constant | No ), _ | Escape , Immutable -> () )
358
373
| Expr (Closure (params , _ , _ )) ->
@@ -397,18 +412,28 @@ module Domain = struct
397
412
s
398
413
(if o then others else bot)
399
414
400
- let mark_mutable ~update ~st a =
415
+ let mark_mutable ~update ~st a mutable_fields =
401
416
match a with
402
417
| Top -> ()
403
418
| Values { known; _ } ->
404
419
Var.Set. iter
405
420
(fun x ->
406
421
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 , _ -> () )
412
437
| Expr (Block (_ , _ , _ , Immutable )) | Expr (Closure _ ) -> ()
413
438
| Phi _ | Expr _ -> assert false )
414
439
known
@@ -444,7 +469,12 @@ let propagate st ~update approx x =
444
469
| Some tags -> List. memq t ~set: tags
445
470
| None -> true ->
446
471
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
448
478
if not m then add_dep st x z;
449
479
add_dep st x t;
450
480
let a = Var.Tbl. get approx t in
@@ -472,7 +502,11 @@ let propagate st ~update approx x =
472
502
(fun z ->
473
503
match st.defs.(Var. idx z) with
474
504
| 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
476
510
if not m then add_dep st x z;
477
511
Array. iter ~f: (fun t -> add_dep st x t) lst;
478
512
let a =
@@ -566,8 +600,9 @@ let propagate st ~update approx x =
566
600
(match st.variable_may_escape.(Var. idx x) with
567
601
| (Escape | Escape_constant ) as s -> Domain. approx_escape ~update ~st ~approx s res
568
602
| 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);
571
606
res
572
607
| Top -> Top
573
608
@@ -645,9 +680,9 @@ let f ~fast p =
645
680
let deps = Var.Tbl. make () [] in
646
681
let defs = Array. make nv undefined in
647
682
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
649
684
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
651
686
let functions_from_returned_value = Var.Hashtbl. create 128 in
652
687
Var.Map. iter
653
688
(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 =
659
694
; return_values = rets
660
695
; functions_from_returned_value
661
696
; variable_may_escape
662
- ; variable_possibly_mutable
697
+ ; variable_mutable_fields
663
698
; may_escape
664
- ; possibly_mutable
699
+ ; mutable_fields
665
700
; known_cases = Var.Hashtbl. create 16
666
701
; applied_functions = Hashtbl. create 16
667
702
; fast
@@ -690,13 +725,28 @@ let f ~fast p =
690
725
match a with
691
726
| Top -> Format. fprintf f " top"
692
727
| 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
693
741
Format. fprintf
694
742
f
695
- " %a mut:%b vmut:%b vesc:%s esc:%s"
743
+ " %a mut:%a vmut:%a vesc:%s esc:%s"
696
744
(print_approx st)
697
745
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)
700
750
(match st.variable_may_escape.(Var. idx x) with
701
751
| Escape -> " Y"
702
752
| Escape_constant -> " y"
0 commit comments