From 7bdd0f03cb529f673a632e2a774b6a9de4fec5e4 Mon Sep 17 00:00:00 2001 From: Sathya Gunasekaran Date: Thu, 1 Dec 2022 19:03:50 +0000 Subject: [PATCH] [hir] Perform alias analysis for aggregate rvalues Maintain and use abstract memory to peform more refined aliasing of member expressions. --- compiler/forget/src/HIR/BuildAliasSets.ts | 59 +++++++++++++++++++ .../fixtures/hir/component.expect.md | 52 ++++++++-------- 2 files changed, 85 insertions(+), 26 deletions(-) diff --git a/compiler/forget/src/HIR/BuildAliasSets.ts b/compiler/forget/src/HIR/BuildAliasSets.ts index e5b69b0de7..726f359db7 100644 --- a/compiler/forget/src/HIR/BuildAliasSets.ts +++ b/compiler/forget/src/HIR/BuildAliasSets.ts @@ -37,6 +37,65 @@ class AbstractState { if (value.kind !== "Primitive") { this.aliases.union([lvalue.place.identifier, alias.identifier]); } + return; + } + + // Complex alias: + // lvalue = alias.memberPath; + if (alias.memberPath.length > 1) { + // TODO(gsn): Handle nested member paths + return; + } + + let object = this.#values.get(alias.identifier); + + // Don't know what this, let's default to an Object conservatively. + if (object === undefined) { + object = { kind: "Object", values: new Map() }; + } + + // We're doing a member lookup on a non object. + // + // alias = 1; + // lvalue = alias.memberPath; + if (object.kind !== "Object") { + // Conservatively type the value as object. + // + // NOTE(gsn): Should this be an AbstractUnknown rather than an + // AbstractObject? + this.#values.set(lvalue.place.identifier, { + kind: "Object", + values: new Map(), + }); + this.aliases.union([lvalue.place.identifier, alias.identifier]); + return; + } + + let value = object.values.get(alias.memberPath[0]); + + // We don't have a value for this member path. + // + // alias = {}; + // lvalue = alias.memberPath; + if (value === undefined) { + // Conservatively type the value as object. + this.#values.set(lvalue.place.identifier, { + kind: "Object", + values: new Map(), + }); + this.aliases.union([lvalue.place.identifier, alias.identifier]); + return; + } + + // We have a value for this memberPath! + // + // alias.memberPath = value; + // lvalue = alias.memberPath; + this.#values.set(lvalue.place.identifier, value); + + // No need to alias Primitives. + if (value.kind !== "Primitive") { + this.aliases.union([lvalue.place.identifier, alias.identifier]); } } diff --git a/compiler/forget/src/__tests__/fixtures/hir/component.expect.md b/compiler/forget/src/__tests__/fixtures/hir/component.expect.md index 010aafa6da..1e4074ec71 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/component.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/component.expect.md @@ -37,7 +37,7 @@ function Component(props) { bb0: [1] Const mutate items$27_@0 = read props$26.items [2] Const mutate maxItems$28_@1 = read props$26.maxItems - [3] Const mutate renderedItems$29_@2[3:22] = Array [] + [3] Const mutate renderedItems$29_@2[3:26] = Array [] [4] Const mutate seen$30_@3[0:19] = New mutate Set$6_@3() [5] Const mutate $31_@4 = 0 [6] Const mutate max$32_@5[0:7] = Call mutate Math$8_@5.max(read $31_@4, read maxItems$28_@1) @@ -71,23 +71,23 @@ bb4: [19] Const mutate $43_@7 = "div" [20] Const mutate $44_@8 = JSX {read item$10_@3} [21] Call mutate renderedItems$29_@2.push(read $44_@8) - [22] Const mutate $49_@9 = Binary read renderedItems$29_@2.length >= read max$32_@5 - [23] If (read $49_@9) then:bb2 else:bb10 + [22] Const mutate $49_@2[3:26] = Binary read renderedItems$29_@2.length >= read max$32_@5 + [23] If (read $49_@2) then:bb2 else:bb10 bb10: predecessor blocks: bb4 [24] Goto(Continue) bb1 bb2: predecessor blocks: bb4 bb1 - [25] Const mutate count$52_@10 = read renderedItems$29_@2.length - [26] Const mutate $53_@11 = "div" - [27] Const mutate $54_@12 = "\n " - [28] Const mutate $55_@13 = "h1" - [29] Const mutate $56_@14 = " Items" - [30] Const mutate $57_@15 = JSX {freeze count$52_@10}{read $56_@14} - [31] Const mutate $58_@16 = "\n " - [32] Const mutate $59_@17 = "\n " - [33] Const mutate $60_@18 = JSX {read $54_@12}{read $57_@15}{read $58_@16}{freeze renderedItems$29_@2}{read $59_@17} - [34] Return read $60_@18 + [25] Const mutate count$52_@2[3:26] = read renderedItems$29_@2.length + [26] Const mutate $53_@9 = "div" + [27] Const mutate $54_@10 = "\n " + [28] Const mutate $55_@11 = "h1" + [29] Const mutate $56_@12 = " Items" + [30] Const mutate $57_@13 = JSX {freeze count$52_@2}{read $56_@12} + [31] Const mutate $58_@14 = "\n " + [32] Const mutate $59_@15 = "\n " + [33] Const mutate $60_@16 = JSX {read $54_@10}{read $57_@13}{read $58_@14}{freeze renderedItems$29_@2}{read $59_@15} + [34] Return read $60_@16 scope0 [1:2]: - read props$26.items scope1 [2:3]: @@ -103,7 +103,7 @@ flowchart TB bb0_instrs[" [1] Const mutate items$27_@0 = read props$26.items [2] Const mutate maxItems$28_@1 = read props$26.maxItems - [3] Const mutate renderedItems$29_@2[3:22] = Array [] + [3] Const mutate renderedItems$29_@2[3:26] = Array [] [4] Const mutate seen$30_@3[0:19] = New mutate Set$6_@3() [5] Const mutate $31_@4 = 0 [6] Const mutate max$32_@5[0:7] = Call mutate Math$8_@5.max(read $31_@4, read maxItems$28_@1) @@ -144,26 +144,26 @@ flowchart TB [19] Const mutate $43_@7 = 'div' [20] Const mutate $44_@8 = JSX {read item$10_@3} [21] Call mutate renderedItems$29_@2.push(read $44_@8) - [22] Const mutate $49_@9 = Binary read renderedItems$29_@2.length >= read max$32_@5 + [22] Const mutate $49_@2[3:26] = Binary read renderedItems$29_@2.length >= read max$32_@5 "] - bb4_instrs --> bb4_terminal(["If (read $49_@9)"]) + bb4_instrs --> bb4_terminal(["If (read $49_@2)"]) end subgraph bb10 bb10_terminal(["Goto"]) end subgraph bb2 bb2_instrs[" - [25] Const mutate count$52_@10 = read renderedItems$29_@2.length - [26] Const mutate $53_@11 = 'div' - [27] Const mutate $54_@12 = '\n ' - [28] Const mutate $55_@13 = 'h1' - [29] Const mutate $56_@14 = ' Items' - [30] Const mutate $57_@15 = JSX {freeze count$52_@10}{read $56_@14} - [31] Const mutate $58_@16 = '\n ' - [32] Const mutate $59_@17 = '\n ' - [33] Const mutate $60_@18 = JSX {read $54_@12}{read $57_@15}{read $58_@16}{freeze renderedItems$29_@2}{read $59_@17} + [25] Const mutate count$52_@2[3:26] = read renderedItems$29_@2.length + [26] Const mutate $53_@9 = 'div' + [27] Const mutate $54_@10 = '\n ' + [28] Const mutate $55_@11 = 'h1' + [29] Const mutate $56_@12 = ' Items' + [30] Const mutate $57_@13 = JSX {freeze count$52_@2}{read $56_@12} + [31] Const mutate $58_@14 = '\n ' + [32] Const mutate $59_@15 = '\n ' + [33] Const mutate $60_@16 = JSX {read $54_@10}{read $57_@13}{read $58_@14}{freeze renderedItems$29_@2}{read $59_@15} "] - bb2_instrs --> bb2_terminal(["Return read $60_@18"]) + bb2_instrs --> bb2_terminal(["Return read $60_@16"]) end %% Jumps