[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.
This commit is contained in:
Sathya Gunasekaran
2022-12-05 22:27:01 +00:00
parent a855e76494
commit 3a1124fe14
5 changed files with 92 additions and 57 deletions
+42 -1
View File
@@ -16,6 +16,10 @@ type AbstractPrimitive = {
export type AliasSet = Set<Identifier>;
class AbstractState {
aliases = new DisjointSet<Identifier>();
// NOTE(gsn): Should this be a part of AbstractObject? No, because this has
// nothing to do with values in the object.
objectAliases = new Map<Identifier, Map<string, AliasSet>>();
#values = new Map<Identifier, AbstractValue>();
read(alias: Place): AbstractValue {
@@ -90,8 +94,45 @@ class AbstractState {
}
alias(lvalue: LValue, alias: Place) {
// TODO(gsn): Handle aliasing for complex lvalue
// Complex lvalue:
// lvalue.memberPath = alias;
// lvalue.memberPath = alias.someMemberPath;
if (lvalue.place.memberPath !== null) {
// TODO(gsn): Handle nested memberPaths in lvalue.
if (lvalue.place.memberPath.length > 1) {
return;
}
let memberPath = lvalue.place.memberPath[0];
// Consider the case of:
// lvalue.memberPath = alias;
// mutate(lvalue); <-- `alias` should be considered mutable
// here.
//
// Similarly for this case,
// mutate(lvalue.memberPath); <-- `alias` should be considered mutable
// here as well.
//
// But what about this case:
// mutate(lvalue.foo); <-- Do we consider `alias` mutable here?
// No!
//
// To distinguish between these different cases, we need to build separate
// alias sets for each memberPath of `lvalue`.
let objectAlias = this.objectAliases.get(lvalue.place.identifier);
if (objectAlias === undefined) {
objectAlias = new Map<string, AliasSet>();
this.objectAliases.set(lvalue.place.identifier, objectAlias);
}
let memberAlias = objectAlias.get(memberPath);
if (memberAlias === undefined) {
memberAlias = new Set<Identifier>();
objectAlias.set(memberPath, memberAlias);
}
memberAlias.add(alias.identifier);
this.aliases.union([lvalue.place.identifier, alias.identifier]);
return;
}
@@ -67,12 +67,12 @@ function mutate$0(x$1, y$2) {}
```
bb0:
[1] Const mutate a$11_@0 = Object { }
[2] Const mutate b$12_@1 = Array [read a$11_@0]
[2] Const mutate b$12_@1[0:15] = Array [read a$11_@0]
[3] Const mutate c$13_@2 = Object { }
[4] Const mutate d$14_@3[0:15] = Object { c: read c$13_@2 }
[5] Const mutate x$15_@3[0:15] = Object { }
[6] Reassign mutate x$15_@3.b[0:15] = read b$12_@1
[7] Const mutate y$16_@3[0:15] = Call mutate mutate$8_@3(mutate x$15_@3, mutate d$14_@3)
[4] Const mutate d$14_@1[0:15] = Object { c: read c$13_@2 }
[5] Const mutate x$15_@1[0:15] = Object { }
[6] Reassign mutate x$15_@1.b[0:15] = read b$12_@1
[7] Const mutate y$16_@1[0:15] = Call mutate mutate$8_@1(mutate x$15_@1, mutate d$14_@1)
[8] If (read a$11_@0) then:bb1 else:bb1
bb1:
predecessor blocks: bb0
@@ -82,17 +82,16 @@ bb3:
[10] If (read c$13_@2) then:bb5 else:bb5
bb5:
predecessor blocks: bb3
[11] If (read d$14_@3) then:bb7 else:bb7
[11] If (read d$14_@1) then:bb7 else:bb7
bb7:
predecessor blocks: bb5
[12] If (read y$16_@3) then:bb9 else:bb9
[12] If (read y$16_@1) then:bb9 else:bb9
bb9:
predecessor blocks: bb7
[13] Const mutate $17_@4 = null
[14] Call mutate mutate$8_@3(mutate x$15_@3, read $17_@4)
[13] Const mutate $17_@3 = null
[14] Call mutate mutate$8_@1(mutate x$15_@1, read $17_@3)
[15] Return
scope1 [2:3]:
- read a$11_@0
```
### CFG
@@ -103,12 +102,12 @@ flowchart TB
subgraph bb0
bb0_instrs["
[1] Const mutate a$11_@0 = Object { }
[2] Const mutate b$12_@1 = Array [read a$11_@0]
[2] Const mutate b$12_@1[0:15] = Array [read a$11_@0]
[3] Const mutate c$13_@2 = Object { }
[4] Const mutate d$14_@3[0:15] = Object { c: read c$13_@2 }
[5] Const mutate x$15_@3[0:15] = Object { }
[6] Reassign mutate x$15_@3.b[0:15] = read b$12_@1
[7] Const mutate y$16_@3[0:15] = Call mutate mutate$8_@3(mutate x$15_@3, mutate d$14_@3)
[4] Const mutate d$14_@1[0:15] = Object { c: read c$13_@2 }
[5] Const mutate x$15_@1[0:15] = Object { }
[6] Reassign mutate x$15_@1.b[0:15] = read b$12_@1
[7] Const mutate y$16_@1[0:15] = Call mutate mutate$8_@1(mutate x$15_@1, mutate d$14_@1)
"]
bb0_instrs --> bb0_terminal(["If (read a$11_@0)"])
end
@@ -119,15 +118,15 @@ flowchart TB
bb3_terminal(["If (read c$13_@2)"])
end
subgraph bb5
bb5_terminal(["If (read d$14_@3)"])
bb5_terminal(["If (read d$14_@1)"])
end
subgraph bb7
bb7_terminal(["If (read y$16_@3)"])
bb7_terminal(["If (read y$16_@1)"])
end
subgraph bb9
bb9_instrs["
[13] Const mutate $17_@4 = null
[14] Call mutate mutate$8_@3(mutate x$15_@3, read $17_@4)
[13] Const mutate $17_@3 = null
[14] Call mutate mutate$8_@1(mutate x$15_@1, read $17_@3)
"]
bb9_instrs --> bb9_terminal(["Return"])
end
@@ -18,22 +18,19 @@ function Component(props) {
```
bb0:
[1] Const mutate x$7_@0[1:6] = Object { }
[2] Const mutate y$8_@1 = Array []
[3] Reassign mutate x$7_@0.y[1:6] = read y$8_@1
[4] Const mutate child$9_@2 = JSX <read Component$0 data={freeze y$8_@1} ></read Component$0>
[2] Const mutate y$8_@0[1:6] = Array []
[3] Reassign mutate x$7_@0.y[1:6] = read y$8_@0
[4] Const mutate child$9_@0[1:6] = JSX <read Component$0 data={freeze y$8_@0} ></read Component$0>
[5] Call mutate x$7_@0.y.push(read props$6.p0)
[6] Const mutate $10_@3 = JSX <read Component$0 data={freeze x$7_@0} >{read child$9_@2}</read Component$0>
[7] Return read $10_@3
scope1 [2:3]:
- mutate x$7_@0.y
scope2 [4:5]:
[6] Const mutate $10_@1 = JSX <read Component$0 data={freeze x$7_@0} >{read child$9_@0}</read Component$0>
[7] Return read $10_@1
scope0 [1:6]:
- read Component$0
- freeze y$8_@1
- read props$6.p0
scope3 [6:7]:
scope1 [6:7]:
- read Component$0
- freeze x$7_@0
- read child$9_@2
- read child$9_@0
```
### CFG
@@ -44,13 +41,13 @@ flowchart TB
subgraph bb0
bb0_instrs["
[1] Const mutate x$7_@0[1:6] = Object { }
[2] Const mutate y$8_@1 = Array []
[3] Reassign mutate x$7_@0.y[1:6] = read y$8_@1
[4] Const mutate child$9_@2 = JSX <read Component$0 data={freeze y$8_@1} ></read Component$0>
[2] Const mutate y$8_@0[1:6] = Array []
[3] Reassign mutate x$7_@0.y[1:6] = read y$8_@0
[4] Const mutate child$9_@0[1:6] = JSX <read Component$0 data={freeze y$8_@0} ></read Component$0>
[5] Call mutate x$7_@0.y.push(read props$6.p0)
[6] Const mutate $10_@3 = JSX <read Component$0 data={freeze x$7_@0} >{read child$9_@2}</read Component$0>
[6] Const mutate $10_@1 = JSX <read Component$0 data={freeze x$7_@0} >{read child$9_@0}</read Component$0>
"]
bb0_instrs --> bb0_terminal(["Return read $10_@3"])
bb0_instrs --> bb0_terminal(["Return read $10_@1"])
end
%% Jumps
@@ -19,13 +19,12 @@ function foo() {
```
bb0:
[1] Let mutate x$4_@0[1:6] = Object { }
[2] Let mutate y$5_@1[2:5] = Array []
[3] Let mutate z$6_@1[2:5] = Object { }
[4] Call mutate y$5_@1.push(mutate z$6_@1)
[5] Reassign mutate x$4_@0.y[1:6] = read y$5_@1
[2] Let mutate y$5_@0[1:6] = Array []
[3] Let mutate z$6_@0[1:6] = Object { }
[4] Call mutate y$5_@0.push(mutate z$6_@0)
[5] Reassign mutate x$4_@0.y[1:6] = read y$5_@0
[6] Return freeze x$4_@0
scope1 [2:5]:
- mutate x$4_@0.y
```
### CFG
@@ -36,10 +35,10 @@ flowchart TB
subgraph bb0
bb0_instrs["
[1] Let mutate x$4_@0[1:6] = Object { }
[2] Let mutate y$5_@1[2:5] = Array []
[3] Let mutate z$6_@1[2:5] = Object { }
[4] Call mutate y$5_@1.push(mutate z$6_@1)
[5] Reassign mutate x$4_@0.y[1:6] = read y$5_@1
[2] Let mutate y$5_@0[1:6] = Array []
[3] Let mutate z$6_@0[1:6] = Object { }
[4] Call mutate y$5_@0.push(mutate z$6_@0)
[5] Reassign mutate x$4_@0.y[1:6] = read y$5_@0
"]
bb0_instrs --> bb0_terminal(["Return freeze x$4_@0"])
end
@@ -15,12 +15,11 @@ function foo() {
```
bb0:
[1] Const mutate x$3_@0 = Array []
[2] Const mutate y$4_@1[2:4] = Object { }
[3] Reassign mutate y$4_@1.x[2:4] = read x$3_@0
[4] Return freeze y$4_@1
scope1 [2:4]:
- read x$3_@0
[1] Const mutate x$3_@0[1:4] = Array []
[2] Const mutate y$4_@0[1:4] = Object { }
[3] Reassign mutate y$4_@0.x[1:4] = read x$3_@0
[4] Return freeze y$4_@0
```
### CFG
@@ -30,11 +29,11 @@ flowchart TB
%% Basic Blocks
subgraph bb0
bb0_instrs["
[1] Const mutate x$3_@0 = Array []
[2] Const mutate y$4_@1[2:4] = Object { }
[3] Reassign mutate y$4_@1.x[2:4] = read x$3_@0
[1] Const mutate x$3_@0[1:4] = Array []
[2] Const mutate y$4_@0[1:4] = Object { }
[3] Reassign mutate y$4_@0.x[1:4] = read x$3_@0
"]
bb0_instrs --> bb0_terminal(["Return freeze y$4_@1"])
bb0_instrs --> bb0_terminal(["Return freeze y$4_@0"])
end
%% Jumps