@samitouri / QOS-React-2 / commits / 3a1124fe14

[hir] Add alias analysis for lvalue aggregates

This adds a field sensitive, flow-insensitive, context-insensitive alias analysis for lvalue aggregates. In the future, InferMutableLifetimes can refine it's analysis using these field sensitive alias sets.

Sathya Gunasekaran committed Dec 5, 2022 at 22:27 UTC 3a1124fe143c067cb1f5c794d01e34e2498ec8fc
5 files changed +92 -57
compiler/forget/src/HIR/BuildAliasSets.ts
+42 -1
@@ -16,6 +16,10 @@ type AbstractPrimitive = {
16 export type AliasSet = Set<Identifier>;
17 class AbstractState {
18 aliases = new DisjointSet<Identifier>();
19 + // NOTE(gsn): Should this be a part of AbstractObject? No, because this has
20 + // nothing to do with values in the object.
21 + objectAliases = new Map<Identifier, Map<string, AliasSet>>();
22 +
23 #values = new Map<Identifier, AbstractValue>();
24
25 read(alias: Place): AbstractValue {
@@ -90,8 +94,45 @@ class AbstractState {
94 }
95
96 alias(lvalue: LValue, alias: Place) {
93 - // TODO(gsn): Handle aliasing for complex lvalue
97 + // Complex lvalue:
98 + // lvalue.memberPath = alias;
99 + // lvalue.memberPath = alias.someMemberPath;
100 if (lvalue.place.memberPath !== null) {
101 + // TODO(gsn): Handle nested memberPaths in lvalue.
102 + if (lvalue.place.memberPath.length > 1) {
103 + return;
104 + }
105 + let memberPath = lvalue.place.memberPath[0];
106 +
107 + // Consider the case of:
108 + // lvalue.memberPath = alias;
109 + // mutate(lvalue); <-- `alias` should be considered mutable
110 + // here.
111 + //
112 + // Similarly for this case,
113 + // mutate(lvalue.memberPath); <-- `alias` should be considered mutable
114 + // here as well.
115 + //
116 + // But what about this case:
117 + // mutate(lvalue.foo); <-- Do we consider `alias` mutable here?
118 + // No!
119 + //
120 + // To distinguish between these different cases, we need to build separate
121 + // alias sets for each memberPath of `lvalue`.
122 + let objectAlias = this.objectAliases.get(lvalue.place.identifier);
123 + if (objectAlias === undefined) {
124 + objectAlias = new Map<string, AliasSet>();
125 + this.objectAliases.set(lvalue.place.identifier, objectAlias);
126 + }
127 +
128 + let memberAlias = objectAlias.get(memberPath);
129 + if (memberAlias === undefined) {
130 + memberAlias = new Set<Identifier>();
131 + objectAlias.set(memberPath, memberAlias);
132 + }
133 +
134 + memberAlias.add(alias.identifier);
135 + this.aliases.union([lvalue.place.identifier, alias.identifier]);
136 return;
137 }
138
compiler/forget/src/__tests__/fixtures/hir/mutable-lifetime-with-aliasing.expect.md
+19 -20
@@ -67,12 +67,12 @@ function mutate$0(x$1, y$2) {}
67 ```
68 bb0:
69 [1] Const mutate a$11_@0 = Object { }
70 - [2] Const mutate b$12_@1 = Array [read a$11_@0]
70 + [2] Const mutate b$12_@1[0:15] = Array [read a$11_@0]
71 [3] Const mutate c$13_@2 = Object { }
72 - [4] Const mutate d$14_@3[0:15] = Object { c: read c$13_@2 }
73 - [5] Const mutate x$15_@3[0:15] = Object { }
74 - [6] Reassign mutate x$15_@3.b[0:15] = read b$12_@1
75 - [7] Const mutate y$16_@3[0:15] = Call mutate mutate$8_@3(mutate x$15_@3, mutate d$14_@3)
72 + [4] Const mutate d$14_@1[0:15] = Object { c: read c$13_@2 }
73 + [5] Const mutate x$15_@1[0:15] = Object { }
74 + [6] Reassign mutate x$15_@1.b[0:15] = read b$12_@1
75 + [7] Const mutate y$16_@1[0:15] = Call mutate mutate$8_@1(mutate x$15_@1, mutate d$14_@1)
76 [8] If (read a$11_@0) then:bb1 else:bb1
77 bb1:
78 predecessor blocks: bb0
@@ -82,17 +82,16 @@ bb3:
82 [10] If (read c$13_@2) then:bb5 else:bb5
83 bb5:
84 predecessor blocks: bb3
85 - [11] If (read d$14_@3) then:bb7 else:bb7
85 + [11] If (read d$14_@1) then:bb7 else:bb7
86 bb7:
87 predecessor blocks: bb5
88 - [12] If (read y$16_@3) then:bb9 else:bb9
88 + [12] If (read y$16_@1) then:bb9 else:bb9
89 bb9:
90 predecessor blocks: bb7
91 - [13] Const mutate $17_@4 = null
92 - [14] Call mutate mutate$8_@3(mutate x$15_@3, read $17_@4)
91 + [13] Const mutate $17_@3 = null
92 + [14] Call mutate mutate$8_@1(mutate x$15_@1, read $17_@3)
93 [15] Return
94 -scope1 [2:3]:
95 - - read a$11_@0
94 +
95 ```
96
97 ### CFG
@@ -103,12 +102,12 @@ flowchart TB
102 subgraph bb0
103 bb0_instrs["
104 [1] Const mutate a$11_@0 = Object { }
106 - [2] Const mutate b$12_@1 = Array [read a$11_@0]
105 + [2] Const mutate b$12_@1[0:15] = Array [read a$11_@0]
106 [3] Const mutate c$13_@2 = Object { }
108 - [4] Const mutate d$14_@3[0:15] = Object { c: read c$13_@2 }
109 - [5] Const mutate x$15_@3[0:15] = Object { }
110 - [6] Reassign mutate x$15_@3.b[0:15] = read b$12_@1
111 - [7] Const mutate y$16_@3[0:15] = Call mutate mutate$8_@3(mutate x$15_@3, mutate d$14_@3)
107 + [4] Const mutate d$14_@1[0:15] = Object { c: read c$13_@2 }
108 + [5] Const mutate x$15_@1[0:15] = Object { }
109 + [6] Reassign mutate x$15_@1.b[0:15] = read b$12_@1
110 + [7] Const mutate y$16_@1[0:15] = Call mutate mutate$8_@1(mutate x$15_@1, mutate d$14_@1)
111 "]
112 bb0_instrs --> bb0_terminal(["If (read a$11_@0)"])
113 end
@@ -119,15 +118,15 @@ flowchart TB
118 bb3_terminal(["If (read c$13_@2)"])
119 end
120 subgraph bb5
122 - bb5_terminal(["If (read d$14_@3)"])
121 + bb5_terminal(["If (read d$14_@1)"])
122 end
123 subgraph bb7
125 - bb7_terminal(["If (read y$16_@3)"])
124 + bb7_terminal(["If (read y$16_@1)"])
125 end
126 subgraph bb9
127 bb9_instrs["
129 - [13] Const mutate $17_@4 = null
130 - [14] Call mutate mutate$8_@3(mutate x$15_@3, read $17_@4)
128 + [13] Const mutate $17_@3 = null
129 + [14] Call mutate mutate$8_@1(mutate x$15_@1, read $17_@3)
130 "]
131 bb9_instrs --> bb9_terminal(["Return"])
132 end
compiler/forget/src/__tests__/fixtures/hir/property-assignment.expect.md
+13 -16
@@ -18,22 +18,19 @@ function Component(props) {
18 ```
19 bb0:
20 [1] Const mutate x$7_@0[1:6] = Object { }
21 - [2] Const mutate y$8_@1 = Array []
22 - [3] Reassign mutate x$7_@0.y[1:6] = read y$8_@1
23 - [4] Const mutate child$9_@2 = JSX <read Component$0 data={freeze y$8_@1} ></read Component$0>
21 + [2] Const mutate y$8_@0[1:6] = Array []
22 + [3] Reassign mutate x$7_@0.y[1:6] = read y$8_@0
23 + [4] Const mutate child$9_@0[1:6] = JSX <read Component$0 data={freeze y$8_@0} ></read Component$0>
24 [5] Call mutate x$7_@0.y.push(read props$6.p0)
25 - [6] Const mutate $10_@3 = JSX <read Component$0 data={freeze x$7_@0} >{read child$9_@2}</read Component$0>
26 - [7] Return read $10_@3
27 -scope1 [2:3]:
28 - - mutate x$7_@0.y
29 -scope2 [4:5]:
25 + [6] Const mutate $10_@1 = JSX <read Component$0 data={freeze x$7_@0} >{read child$9_@0}</read Component$0>
26 + [7] Return read $10_@1
27 +scope0 [1:6]:
28 - read Component$0
31 - - freeze y$8_@1
29 - read props$6.p0
33 -scope3 [6:7]:
30 +scope1 [6:7]:
31 - read Component$0
32 - freeze x$7_@0
36 - - read child$9_@2
33 + - read child$9_@0
34 ```
35
36 ### CFG
@@ -44,13 +41,13 @@ flowchart TB
41 subgraph bb0
42 bb0_instrs["
43 [1] Const mutate x$7_@0[1:6] = Object { }
47 - [2] Const mutate y$8_@1 = Array []
48 - [3] Reassign mutate x$7_@0.y[1:6] = read y$8_@1
49 - [4] Const mutate child$9_@2 = JSX <read Component$0 data={freeze y$8_@1} ></read Component$0>
44 + [2] Const mutate y$8_@0[1:6] = Array []
45 + [3] Reassign mutate x$7_@0.y[1:6] = read y$8_@0
46 + [4] Const mutate child$9_@0[1:6] = JSX <read Component$0 data={freeze y$8_@0} ></read Component$0>
47 [5] Call mutate x$7_@0.y.push(read props$6.p0)
51 - [6] Const mutate $10_@3 = JSX <read Component$0 data={freeze x$7_@0} >{read child$9_@2}</read Component$0>
48 + [6] Const mutate $10_@1 = JSX <read Component$0 data={freeze x$7_@0} >{read child$9_@0}</read Component$0>
49 "]
53 - bb0_instrs --> bb0_terminal(["Return read $10_@3"])
50 + bb0_instrs --> bb0_terminal(["Return read $10_@1"])
51 end
52
53 %% Jumps
compiler/forget/src/__tests__/fixtures/hir/reactive-scope-grouping.expect.md
+9 -10
@@ -19,13 +19,12 @@ function foo() {
19 ```
20 bb0:
21 [1] Let mutate x$4_@0[1:6] = Object { }
22 - [2] Let mutate y$5_@1[2:5] = Array []
23 - [3] Let mutate z$6_@1[2:5] = Object { }
24 - [4] Call mutate y$5_@1.push(mutate z$6_@1)
25 - [5] Reassign mutate x$4_@0.y[1:6] = read y$5_@1
22 + [2] Let mutate y$5_@0[1:6] = Array []
23 + [3] Let mutate z$6_@0[1:6] = Object { }
24 + [4] Call mutate y$5_@0.push(mutate z$6_@0)
25 + [5] Reassign mutate x$4_@0.y[1:6] = read y$5_@0
26 [6] Return freeze x$4_@0
27 -scope1 [2:5]:
28 - - mutate x$4_@0.y
27 +
28 ```
29
30 ### CFG
@@ -36,10 +35,10 @@ flowchart TB
35 subgraph bb0
36 bb0_instrs["
37 [1] Let mutate x$4_@0[1:6] = Object { }
39 - [2] Let mutate y$5_@1[2:5] = Array []
40 - [3] Let mutate z$6_@1[2:5] = Object { }
41 - [4] Call mutate y$5_@1.push(mutate z$6_@1)
42 - [5] Reassign mutate x$4_@0.y[1:6] = read y$5_@1
38 + [2] Let mutate y$5_@0[1:6] = Array []
39 + [3] Let mutate z$6_@0[1:6] = Object { }
40 + [4] Call mutate y$5_@0.push(mutate z$6_@0)
41 + [5] Reassign mutate x$4_@0.y[1:6] = read y$5_@0
42 "]
43 bb0_instrs --> bb0_terminal(["Return freeze x$4_@0"])
44 end
compiler/forget/src/__tests__/fixtures/hir/ssa-property.expect.md
+9 -10
@@ -15,12 +15,11 @@ function foo() {
15
16 ```
17 bb0:
18 - [1] Const mutate x$3_@0 = Array []
19 - [2] Const mutate y$4_@1[2:4] = Object { }
20 - [3] Reassign mutate y$4_@1.x[2:4] = read x$3_@0
21 - [4] Return freeze y$4_@1
22 -scope1 [2:4]:
23 - - read x$3_@0
18 + [1] Const mutate x$3_@0[1:4] = Array []
19 + [2] Const mutate y$4_@0[1:4] = Object { }
20 + [3] Reassign mutate y$4_@0.x[1:4] = read x$3_@0
21 + [4] Return freeze y$4_@0
22 +
23 ```
24
25 ### CFG
@@ -30,11 +29,11 @@ flowchart TB
29 %% Basic Blocks
30 subgraph bb0
31 bb0_instrs["
33 - [1] Const mutate x$3_@0 = Array []
34 - [2] Const mutate y$4_@1[2:4] = Object { }
35 - [3] Reassign mutate y$4_@1.x[2:4] = read x$3_@0
32 + [1] Const mutate x$3_@0[1:4] = Array []
33 + [2] Const mutate y$4_@0[1:4] = Object { }
34 + [3] Reassign mutate y$4_@0.x[1:4] = read x$3_@0
35 "]
37 - bb0_instrs --> bb0_terminal(["Return freeze y$4_@1"])
36 + bb0_instrs --> bb0_terminal(["Return freeze y$4_@0"])
37 end
38
39 %% Jumps