From 74a0d54db2e96ebcedfb5e39e41cb2bbd3acacef Mon Sep 17 00:00:00 2001 From: Joe Savona Date: Thu, 22 Dec 2022 14:00:49 -0800 Subject: [PATCH] Account for stores that can occur in object/array literals --- .../forget/src/HIR/InferAliasForStores.ts | 47 ++++++++++++++----- .../forget/src/HIR/InferReferenceEffects.ts | 5 +- ...-variations-complex-lvalue-array.expect.md | 33 +++++++++++++ ...ignment-variations-complex-lvalue-array.js | 6 +++ ...gnment-variations-complex-lvalue.expect.md | 23 +++------ .../mutable-lifetime-with-aliasing.expect.md | 21 +-------- .../fixtures/hir/ssa-property-call.expect.md | 18 ++----- .../fixtures/hir/store-via-call.expect.md | 33 +++++++++++++ .../__tests__/fixtures/hir/store-via-call.js | 6 +++ .../fixtures/hir/store-via-new.expect.md | 33 +++++++++++++ .../__tests__/fixtures/hir/store-via-new.js | 6 +++ 11 files changed, 167 insertions(+), 64 deletions(-) create mode 100644 compiler/forget/src/__tests__/fixtures/hir/assignment-variations-complex-lvalue-array.expect.md create mode 100644 compiler/forget/src/__tests__/fixtures/hir/assignment-variations-complex-lvalue-array.js create mode 100644 compiler/forget/src/__tests__/fixtures/hir/store-via-call.expect.md create mode 100644 compiler/forget/src/__tests__/fixtures/hir/store-via-call.js create mode 100644 compiler/forget/src/__tests__/fixtures/hir/store-via-new.expect.md create mode 100644 compiler/forget/src/__tests__/fixtures/hir/store-via-new.js diff --git a/compiler/forget/src/HIR/InferAliasForStores.ts b/compiler/forget/src/HIR/InferAliasForStores.ts index d141aedb42..17da0d5a27 100644 --- a/compiler/forget/src/HIR/InferAliasForStores.ts +++ b/compiler/forget/src/HIR/InferAliasForStores.ts @@ -4,9 +4,8 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ -import invariant from "invariant"; import DisjointSet from "../Utils/DisjointSet"; -import { Effect, HIRFunction, Identifier } from "./HIR"; +import { Effect, HIRFunction, Identifier, InstructionId, Place } from "./HIR"; export function inferAliasForStores( func: HIRFunction, @@ -18,18 +17,40 @@ export function inferAliasForStores( if (lvalue === null || lvalue.place.effect !== Effect.Store) { continue; } - - invariant( - value.kind === "Identifier", - "only identifiers can be aliased by stores" - ); - - if ( - lvalue.place.identifier.mutableRange.end > instr.id || - value.identifier.mutableRange.end > instr.id - ) { - aliases.union([lvalue.place.identifier, value.identifier]); + switch (value.kind) { + case "Identifier": { + maybeAlias(aliases, lvalue.place, value, instr.id); + break; + } + case "ArrayExpression": { + for (const item of value.elements) { + maybeAlias(aliases, lvalue.place, item, instr.id); + } + break; + } + case "ObjectExpression": { + if (value.properties !== null) { + for (const [, property] of value.properties) { + maybeAlias(aliases, lvalue.place, property, instr.id); + } + } + break; + } } } } } + +function maybeAlias( + aliases: DisjointSet, + lvalue: Place, + rvalue: Place, + id: InstructionId +): void { + if ( + lvalue.identifier.mutableRange.end > id || + rvalue.identifier.mutableRange.end > id + ) { + aliases.union([lvalue.identifier, rvalue.identifier]); + } +} diff --git a/compiler/forget/src/HIR/InferReferenceEffects.ts b/compiler/forget/src/HIR/InferReferenceEffects.ts index 266eecb590..952fb0818b 100644 --- a/compiler/forget/src/HIR/InferReferenceEffects.ts +++ b/compiler/forget/src/HIR/InferReferenceEffects.ts @@ -516,6 +516,7 @@ function inferBlock(env: Environment, block: BasicBlock) { for (const instr of block.instructions) { const instrValue = instr.value; let effectKind: Effect | null = null; + let lvalueEffect = Effect.Mutate; let valueKind: ValueKind; switch (instrValue.kind) { case "BinaryExpression": { @@ -526,6 +527,7 @@ function inferBlock(env: Environment, block: BasicBlock) { case "ArrayExpression": { valueKind = ValueKind.Mutable; effectKind = Effect.Read; + lvalueEffect = Effect.Store; break; } case "NewExpression": { @@ -547,6 +549,7 @@ function inferBlock(env: Environment, block: BasicBlock) { valueKind = ValueKind.Mutable; // Object construction captures but does not modify the key/property values effectKind = Effect.Read; + lvalueEffect = Effect.Store; break; } case "UnaryExpression": { @@ -645,7 +648,7 @@ function inferBlock(env: Environment, block: BasicBlock) { } else { env.reference(instr.lvalue.place, Effect.Mutate); } - instr.lvalue.place.effect = Effect.Mutate; + instr.lvalue.place.effect = lvalueEffect; } } diff --git a/compiler/forget/src/__tests__/fixtures/hir/assignment-variations-complex-lvalue-array.expect.md b/compiler/forget/src/__tests__/fixtures/hir/assignment-variations-complex-lvalue-array.expect.md new file mode 100644 index 0000000000..dad0b2d4a6 --- /dev/null +++ b/compiler/forget/src/__tests__/fixtures/hir/assignment-variations-complex-lvalue-array.expect.md @@ -0,0 +1,33 @@ + +## Input + +```javascript +function foo() { + const a = [[1]]; + const first = a.at(0); + first.set(0, 2); + return a; +} + +``` + +## Code + +```javascript +function foo() { + const $ = React.useMemoCache(); + let a; + if ($[0] === Symbol.for("react.memo_cache_sentinel")) { + a = [[1]]; + const first = a.at(0); + first.set(0, 2); + $[0] = a; + } else { + a = $[0]; + } + + return a; +} + +``` + \ No newline at end of file diff --git a/compiler/forget/src/__tests__/fixtures/hir/assignment-variations-complex-lvalue-array.js b/compiler/forget/src/__tests__/fixtures/hir/assignment-variations-complex-lvalue-array.js new file mode 100644 index 0000000000..c396f86547 --- /dev/null +++ b/compiler/forget/src/__tests__/fixtures/hir/assignment-variations-complex-lvalue-array.js @@ -0,0 +1,6 @@ +function foo() { + const a = [[1]]; + const first = a.at(0); + first.set(0, 2); + return a; +} diff --git a/compiler/forget/src/__tests__/fixtures/hir/assignment-variations-complex-lvalue.expect.md b/compiler/forget/src/__tests__/fixtures/hir/assignment-variations-complex-lvalue.expect.md index 1c0a599870..a864c3e88c 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/assignment-variations-complex-lvalue.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/assignment-variations-complex-lvalue.expect.md @@ -16,29 +16,18 @@ function g() { ```javascript function g() { const $ = React.useMemoCache(); - let t0; - if ($[0] === Symbol.for("react.memo_cache_sentinel")) { - t0 = { - z: 1, - }; - $[0] = t0; - } else { - t0 = $[0]; - } - - const c_1 = $[1] !== t0; let x; - - if (c_1) { + if ($[0] === Symbol.for("react.memo_cache_sentinel")) { x = { - y: t0, + y: { + z: 1, + }, }; x.z.y = x.y.z + 1; x.z.y = x.y.z * 2; - $[1] = t0; - $[2] = x; + $[0] = x; } else { - x = $[2]; + x = $[0]; } return x; 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 0c4269ebbf..1f692e05ab 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 @@ -45,32 +45,15 @@ function mutate(x, y) {} ```javascript function Component(props) { - const $ = React.useMemoCache(); - let a; - if ($[0] === Symbol.for("react.memo_cache_sentinel")) { - a = {}; - $[0] = a; - } else { - a = $[0]; - } - + const a = {}; const b = [a]; - let c; - - if ($[1] === Symbol.for("react.memo_cache_sentinel")) { - c = {}; - $[1] = c; - } else { - c = $[1]; - } - + const c = {}; const d = { c: c, }; const x = {}; x.b = b; const y = mutate(x, d); - if (a) { } diff --git a/compiler/forget/src/__tests__/fixtures/hir/ssa-property-call.expect.md b/compiler/forget/src/__tests__/fixtures/hir/ssa-property-call.expect.md index 84fc2f512e..cd3a8503a3 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/ssa-property-call.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/ssa-property-call.expect.md @@ -16,26 +16,16 @@ function foo() { ```javascript function foo() { const $ = React.useMemoCache(); - let x; - if ($[0] === Symbol.for("react.memo_cache_sentinel")) { - x = []; - $[0] = x; - } else { - x = $[0]; - } - - const c_1 = $[1] !== x; let y; - - if (c_1) { + if ($[0] === Symbol.for("react.memo_cache_sentinel")) { + const x = []; y = { x: x, }; y.x.push([]); - $[1] = x; - $[2] = y; + $[0] = y; } else { - y = $[2]; + y = $[0]; } return y; diff --git a/compiler/forget/src/__tests__/fixtures/hir/store-via-call.expect.md b/compiler/forget/src/__tests__/fixtures/hir/store-via-call.expect.md new file mode 100644 index 0000000000..21dbeb1062 --- /dev/null +++ b/compiler/forget/src/__tests__/fixtures/hir/store-via-call.expect.md @@ -0,0 +1,33 @@ + +## Input + +```javascript +function foo() { + const x = {}; + const y = foo(x); + y.mutate(); + return x; +} + +``` + +## Code + +```javascript +function foo() { + const $ = React.useMemoCache(); + let x; + if ($[0] === Symbol.for("react.memo_cache_sentinel")) { + x = {}; + const y = foo(x); + y.mutate(); + $[0] = x; + } else { + x = $[0]; + } + + return x; +} + +``` + \ No newline at end of file diff --git a/compiler/forget/src/__tests__/fixtures/hir/store-via-call.js b/compiler/forget/src/__tests__/fixtures/hir/store-via-call.js new file mode 100644 index 0000000000..461e9e1656 --- /dev/null +++ b/compiler/forget/src/__tests__/fixtures/hir/store-via-call.js @@ -0,0 +1,6 @@ +function foo() { + const x = {}; + const y = foo(x); + y.mutate(); + return x; +} diff --git a/compiler/forget/src/__tests__/fixtures/hir/store-via-new.expect.md b/compiler/forget/src/__tests__/fixtures/hir/store-via-new.expect.md new file mode 100644 index 0000000000..82a5b680ec --- /dev/null +++ b/compiler/forget/src/__tests__/fixtures/hir/store-via-new.expect.md @@ -0,0 +1,33 @@ + +## Input + +```javascript +function Foo() { + const x = {}; + const y = new Foo(x); + y.mutate(); + return x; +} + +``` + +## Code + +```javascript +function Foo() { + const $ = React.useMemoCache(); + let x; + if ($[0] === Symbol.for("react.memo_cache_sentinel")) { + x = {}; + const y = new Foo(x); + y.mutate(); + $[0] = x; + } else { + x = $[0]; + } + + return x; +} + +``` + \ No newline at end of file diff --git a/compiler/forget/src/__tests__/fixtures/hir/store-via-new.js b/compiler/forget/src/__tests__/fixtures/hir/store-via-new.js new file mode 100644 index 0000000000..a4032d7e06 --- /dev/null +++ b/compiler/forget/src/__tests__/fixtures/hir/store-via-new.js @@ -0,0 +1,6 @@ +function Foo() { + const x = {}; + const y = new Foo(x); + y.mutate(); + return x; +}