From 94e2ae5893328ef2f7c5c2269413f545546ed350 Mon Sep 17 00:00:00 2001 From: Joe Savona Date: Thu, 18 May 2023 16:05:32 -0700 Subject: [PATCH] Dont memoize calls that produce primitive values Teaches InferReactiveScopeVariables that calls can produce primitives that don't need a scope. --- .../src/Inference/InferReferenceEffects.ts | 2 +- .../InferReactiveScopeVariables.ts | 28 ++++++++++++++++--- .../compiler/globals-Boolean.expect.md | 15 +++------- .../compiler/globals-Number.expect.md | 15 +++------- .../compiler/globals-String.expect.md | 15 +++------- 5 files changed, 37 insertions(+), 38 deletions(-) diff --git a/compiler/forget/src/Inference/InferReferenceEffects.ts b/compiler/forget/src/Inference/InferReferenceEffects.ts index 783bd48e48..29771573ad 100644 --- a/compiler/forget/src/Inference/InferReferenceEffects.ts +++ b/compiler/forget/src/Inference/InferReferenceEffects.ts @@ -1013,7 +1013,7 @@ function hasContextRefOperand( return false; } -function getFunctionCallSignature( +export function getFunctionCallSignature( env: Environment, type: Type ): FunctionSignature | null { diff --git a/compiler/forget/src/ReactiveScopes/InferReactiveScopeVariables.ts b/compiler/forget/src/ReactiveScopes/InferReactiveScopeVariables.ts index 6b2eb178e4..1aed7924f1 100644 --- a/compiler/forget/src/ReactiveScopes/InferReactiveScopeVariables.ts +++ b/compiler/forget/src/ReactiveScopes/InferReactiveScopeVariables.ts @@ -5,6 +5,7 @@ * LICENSE file in the root directory of this source tree. */ +import { Environment } from "../HIR"; import { HIRFunction, Identifier, @@ -20,6 +21,7 @@ import { eachInstructionOperand, eachPatternOperand, } from "../HIR/visitors"; +import { getFunctionCallSignature } from "../Inference/InferReferenceEffects"; import DisjointSet from "../Utils/DisjointSet"; import { assertExhaustive } from "../Utils/utils"; @@ -103,7 +105,7 @@ export function inferReactiveScopeVariables(fn: HIRFunction): void { for (const instr of block.instructions) { const operands: Array = []; const range = instr.lvalue.identifier.mutableRange; - if (range.end > range.start + 1 || mayAllocate(instr.value)) { + if (range.end > range.start + 1 || mayAllocate(fn.env, instr.value)) { operands.push(instr.lvalue!.identifier); } if ( @@ -217,7 +219,7 @@ function isMutable({ id }: Instruction, place: Place): boolean { return id >= range.start && id < range.end; } -function mayAllocate(value: InstructionValue): boolean { +function mayAllocate(env: Environment, value: InstructionValue): boolean { switch (value.kind) { case "Destructure": { return doesPatternContainSpreadElement(value.lvalue.pattern); @@ -245,12 +247,30 @@ function mayAllocate(value: InstructionValue): boolean { case "Debugger": { return false; } + case "CallExpression": { + const signature = getFunctionCallSignature( + env, + value.callee.identifier.type + ); + if (signature !== null) { + return signature.returnType.kind !== "Primitive"; + } + return true; + } + case "MethodCall": { + const signature = getFunctionCallSignature( + env, + value.receiver.identifier.type + ); + if (signature !== null) { + return signature.returnType.kind !== "Primitive"; + } + return true; + } case "RegExpLiteral": - case "MethodCall": case "PropertyStore": case "ComputedStore": case "ArrayExpression": - case "CallExpression": case "JsxExpression": case "JsxFragment": case "NewExpression": diff --git a/compiler/forget/src/__tests__/fixtures/compiler/globals-Boolean.expect.md b/compiler/forget/src/__tests__/fixtures/compiler/globals-Boolean.expect.md index 84b9eb6b94..32dceb52d0 100644 --- a/compiler/forget/src/__tests__/fixtures/compiler/globals-Boolean.expect.md +++ b/compiler/forget/src/__tests__/fixtures/compiler/globals-Boolean.expect.md @@ -15,7 +15,7 @@ function Component(props) { ```javascript import { unstable_useMemoCache as useMemoCache } from "react"; function Component(props) { - const $ = useMemoCache(3); + const $ = useMemoCache(2); let t0; if ($[0] === Symbol.for("react.memo_cache_sentinel")) { t0 = {}; @@ -24,22 +24,15 @@ function Component(props) { t0 = $[0]; } const x = t0; + const y = Boolean(x); let t1; if ($[1] === Symbol.for("react.memo_cache_sentinel")) { - t1 = Boolean(x); + t1 = [x, y]; $[1] = t1; } else { t1 = $[1]; } - const y = t1; - let t2; - if ($[2] === Symbol.for("react.memo_cache_sentinel")) { - t2 = [x, y]; - $[2] = t2; - } else { - t2 = $[2]; - } - return t2; + return t1; } ``` diff --git a/compiler/forget/src/__tests__/fixtures/compiler/globals-Number.expect.md b/compiler/forget/src/__tests__/fixtures/compiler/globals-Number.expect.md index 7a29e07de6..a88990e6e0 100644 --- a/compiler/forget/src/__tests__/fixtures/compiler/globals-Number.expect.md +++ b/compiler/forget/src/__tests__/fixtures/compiler/globals-Number.expect.md @@ -15,7 +15,7 @@ function Component(props) { ```javascript import { unstable_useMemoCache as useMemoCache } from "react"; function Component(props) { - const $ = useMemoCache(3); + const $ = useMemoCache(2); let t0; if ($[0] === Symbol.for("react.memo_cache_sentinel")) { t0 = {}; @@ -24,22 +24,15 @@ function Component(props) { t0 = $[0]; } const x = t0; + const y = Number(x); let t1; if ($[1] === Symbol.for("react.memo_cache_sentinel")) { - t1 = Number(x); + t1 = [x, y]; $[1] = t1; } else { t1 = $[1]; } - const y = t1; - let t2; - if ($[2] === Symbol.for("react.memo_cache_sentinel")) { - t2 = [x, y]; - $[2] = t2; - } else { - t2 = $[2]; - } - return t2; + return t1; } ``` diff --git a/compiler/forget/src/__tests__/fixtures/compiler/globals-String.expect.md b/compiler/forget/src/__tests__/fixtures/compiler/globals-String.expect.md index 1efd363393..75b7000e51 100644 --- a/compiler/forget/src/__tests__/fixtures/compiler/globals-String.expect.md +++ b/compiler/forget/src/__tests__/fixtures/compiler/globals-String.expect.md @@ -15,7 +15,7 @@ function Component(props) { ```javascript import { unstable_useMemoCache as useMemoCache } from "react"; function Component(props) { - const $ = useMemoCache(3); + const $ = useMemoCache(2); let t0; if ($[0] === Symbol.for("react.memo_cache_sentinel")) { t0 = {}; @@ -24,22 +24,15 @@ function Component(props) { t0 = $[0]; } const x = t0; + const y = String(x); let t1; if ($[1] === Symbol.for("react.memo_cache_sentinel")) { - t1 = String(x); + t1 = [x, y]; $[1] = t1; } else { t1 = $[1]; } - const y = t1; - let t2; - if ($[2] === Symbol.for("react.memo_cache_sentinel")) { - t2 = [x, y]; - $[2] = t2; - } else { - t2 = $[2]; - } - return t2; + return t1; } ```