[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