diff --git a/compiler/forget/src/HIR/BuildAliasSets.ts b/compiler/forget/src/HIR/BuildAliasSets.ts index 49a9a344b4..db09f9bca8 100644 --- a/compiler/forget/src/HIR/BuildAliasSets.ts +++ b/compiler/forget/src/HIR/BuildAliasSets.ts @@ -16,6 +16,10 @@ type AbstractPrimitive = { export type AliasSet = Set; class AbstractState { aliases = new DisjointSet(); + // NOTE(gsn): Should this be a part of AbstractObject? No, because this has + // nothing to do with values in the object. + objectAliases = new Map>(); + #values = new Map(); 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(); + this.objectAliases.set(lvalue.place.identifier, objectAlias); + } + + let memberAlias = objectAlias.get(memberPath); + if (memberAlias === undefined) { + memberAlias = new Set(); + objectAlias.set(memberPath, memberAlias); + } + + memberAlias.add(alias.identifier); + this.aliases.union([lvalue.place.identifier, alias.identifier]); return; } diff --git a/compiler/forget/src/__tests__/fixtures/hir/mutable-lifetime-with-aliasing.expect.md b/compiler/forget/src/__tests__/fixtures/hir/mutable-lifetime-with-aliasing.expect.md index 0e958759b5..b1dfa768c4 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/mutable-lifetime-with-aliasing.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/mutable-lifetime-with-aliasing.expect.md @@ -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 diff --git a/compiler/forget/src/__tests__/fixtures/hir/property-assignment.expect.md b/compiler/forget/src/__tests__/fixtures/hir/property-assignment.expect.md index 7dbe6246a5..74ea0ae523 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/property-assignment.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/property-assignment.expect.md @@ -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 + [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 [5] Call mutate x$7_@0.y.push(read props$6.p0) - [6] Const mutate $10_@3 = JSX {read child$9_@2} - [7] Return read $10_@3 -scope1 [2:3]: - - mutate x$7_@0.y -scope2 [4:5]: + [6] Const mutate $10_@1 = JSX {read child$9_@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 + [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 [5] Call mutate x$7_@0.y.push(read props$6.p0) - [6] Const mutate $10_@3 = JSX {read child$9_@2} + [6] Const mutate $10_@1 = JSX {read child$9_@0} "] - bb0_instrs --> bb0_terminal(["Return read $10_@3"]) + bb0_instrs --> bb0_terminal(["Return read $10_@1"]) end %% Jumps diff --git a/compiler/forget/src/__tests__/fixtures/hir/reactive-scope-grouping.expect.md b/compiler/forget/src/__tests__/fixtures/hir/reactive-scope-grouping.expect.md index 9e8422b15e..8b413bb7ca 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/reactive-scope-grouping.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/reactive-scope-grouping.expect.md @@ -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 diff --git a/compiler/forget/src/__tests__/fixtures/hir/ssa-property.expect.md b/compiler/forget/src/__tests__/fixtures/hir/ssa-property.expect.md index 3c1022977a..f9e4208798 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/ssa-property.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/ssa-property.expect.md @@ -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