@samitouri / QOS-React-2 / commits / 94e2ae5893

Dont memoize calls that produce primitive values

Teaches InferReactiveScopeVariables that calls can produce primitives that don't need a scope.

Joe Savona committed May 18, 2023 at 16:05 UTC 94e2ae5893328ef2f7c5c2269413f545546ed350
5 files changed +37 -38
compiler/forget/src/Inference/InferReferenceEffects.ts
+1 -1
@@ -1013,7 +1013,7 @@ function hasContextRefOperand(
1013 return false;
1014 }
1015
1016 -function getFunctionCallSignature(
1016 +export function getFunctionCallSignature(
1017 env: Environment,
1018 type: Type
1019 ): FunctionSignature | null {
compiler/forget/src/ReactiveScopes/InferReactiveScopeVariables.ts
+24 -4
@@ -5,6 +5,7 @@
5 * LICENSE file in the root directory of this source tree.
6 */
7
8 +import { Environment } from "../HIR";
9 import {
10 HIRFunction,
11 Identifier,
@@ -20,6 +21,7 @@ import {
21 eachInstructionOperand,
22 eachPatternOperand,
23 } from "../HIR/visitors";
24 +import { getFunctionCallSignature } from "../Inference/InferReferenceEffects";
25 import DisjointSet from "../Utils/DisjointSet";
26 import { assertExhaustive } from "../Utils/utils";
27
@@ -103,7 +105,7 @@ export function inferReactiveScopeVariables(fn: HIRFunction): void {
105 for (const instr of block.instructions) {
106 const operands: Array<Identifier> = [];
107 const range = instr.lvalue.identifier.mutableRange;
106 - if (range.end > range.start + 1 || mayAllocate(instr.value)) {
108 + if (range.end > range.start + 1 || mayAllocate(fn.env, instr.value)) {
109 operands.push(instr.lvalue!.identifier);
110 }
111 if (
@@ -217,7 +219,7 @@ function isMutable({ id }: Instruction, place: Place): boolean {
219 return id >= range.start && id < range.end;
220 }
221
220 -function mayAllocate(value: InstructionValue): boolean {
222 +function mayAllocate(env: Environment, value: InstructionValue): boolean {
223 switch (value.kind) {
224 case "Destructure": {
225 return doesPatternContainSpreadElement(value.lvalue.pattern);
@@ -245,12 +247,30 @@ function mayAllocate(value: InstructionValue): boolean {
247 case "Debugger": {
248 return false;
249 }
250 + case "CallExpression": {
251 + const signature = getFunctionCallSignature(
252 + env,
253 + value.callee.identifier.type
254 + );
255 + if (signature !== null) {
256 + return signature.returnType.kind !== "Primitive";
257 + }
258 + return true;
259 + }
260 + case "MethodCall": {
261 + const signature = getFunctionCallSignature(
262 + env,
263 + value.receiver.identifier.type
264 + );
265 + if (signature !== null) {
266 + return signature.returnType.kind !== "Primitive";
267 + }
268 + return true;
269 + }
270 case "RegExpLiteral":
249 - case "MethodCall":
271 case "PropertyStore":
272 case "ComputedStore":
273 case "ArrayExpression":
253 - case "CallExpression":
274 case "JsxExpression":
275 case "JsxFragment":
276 case "NewExpression":
compiler/forget/src/__tests__/fixtures/compiler/globals-Boolean.expect.md
+4 -11
@@ -15,7 +15,7 @@ function Component(props) {
15 ```javascript
16 import { unstable_useMemoCache as useMemoCache } from "react";
17 function Component(props) {
18 - const $ = useMemoCache(3);
18 + const $ = useMemoCache(2);
19 let t0;
20 if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
21 t0 = {};
@@ -24,22 +24,15 @@ function Component(props) {
24 t0 = $[0];
25 }
26 const x = t0;
27 + const y = Boolean(x);
28 let t1;
29 if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
29 - t1 = Boolean(x);
30 + t1 = [x, y];
31 $[1] = t1;
32 } else {
33 t1 = $[1];
34 }
34 - const y = t1;
35 - let t2;
36 - if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
37 - t2 = [x, y];
38 - $[2] = t2;
39 - } else {
40 - t2 = $[2];
41 - }
42 - return t2;
35 + return t1;
36 }
37
38 ```
compiler/forget/src/__tests__/fixtures/compiler/globals-Number.expect.md
+4 -11
@@ -15,7 +15,7 @@ function Component(props) {
15 ```javascript
16 import { unstable_useMemoCache as useMemoCache } from "react";
17 function Component(props) {
18 - const $ = useMemoCache(3);
18 + const $ = useMemoCache(2);
19 let t0;
20 if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
21 t0 = {};
@@ -24,22 +24,15 @@ function Component(props) {
24 t0 = $[0];
25 }
26 const x = t0;
27 + const y = Number(x);
28 let t1;
29 if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
29 - t1 = Number(x);
30 + t1 = [x, y];
31 $[1] = t1;
32 } else {
33 t1 = $[1];
34 }
34 - const y = t1;
35 - let t2;
36 - if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
37 - t2 = [x, y];
38 - $[2] = t2;
39 - } else {
40 - t2 = $[2];
41 - }
42 - return t2;
35 + return t1;
36 }
37
38 ```
compiler/forget/src/__tests__/fixtures/compiler/globals-String.expect.md
+4 -11
@@ -15,7 +15,7 @@ function Component(props) {
15 ```javascript
16 import { unstable_useMemoCache as useMemoCache } from "react";
17 function Component(props) {
18 - const $ = useMemoCache(3);
18 + const $ = useMemoCache(2);
19 let t0;
20 if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
21 t0 = {};
@@ -24,22 +24,15 @@ function Component(props) {
24 t0 = $[0];
25 }
26 const x = t0;
27 + const y = String(x);
28 let t1;
29 if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
29 - t1 = String(x);
30 + t1 = [x, y];
31 $[1] = t1;
32 } else {
33 t1 = $[1];
34 }
34 - const y = t1;
35 - let t2;
36 - if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
37 - t2 = [x, y];
38 - $[2] = t2;
39 - } else {
40 - t2 = $[2];
41 - }
42 - return t2;
35 + return t1;
36 }
37
38 ```