24
getHookKind,
25
isMutableEffect,
26
} from "../HIR";
27
+import { getFunctionCallSignature } from "../Inference/InferReferenceEffects";
28
import { log } from "../Utils/logger";
29
import { assertExhaustive } from "../Utils/utils";
30
import { getPlaceScope } from "./BuildReactiveBlocks";
120
for (const param of fn.params) {
121
state.declare(param.identifier.id);
122
}
122
- visitReactiveFunction(fn, new CollectDependenciesVisitor(options), state);
123
+ visitReactiveFunction(
124
+ fn,
125
+ new CollectDependenciesVisitor(fn.env, options),
126
+ state
127
+ );
128
129
log(() => prettyFormat(state));
130
348
* - level: the level of memoization to apply to this value
349
*/
350
function computeMemoizationInputs(
351
+ env: Environment,
352
value: ReactiveValue,
353
lvalue: Place | null,
354
options: MemoizationOptions
367
: [],
368
rvalues: [
369
// Conditionals do not alias their test value.
364
- ...computeMemoizationInputs(value.consequent, null, options).rvalues,
365
- ...computeMemoizationInputs(value.alternate, null, options).rvalues,
370
+ ...computeMemoizationInputs(env, value.consequent, null, options)
371
+ .rvalues,
372
+ ...computeMemoizationInputs(env, value.alternate, null, options)
373
+ .rvalues,
374
],
375
};
376
}
382
? [{ place: lvalue, level: MemoizationLevel.Conditional }]
383
: [],
384
rvalues: [
377
- ...computeMemoizationInputs(value.left, null, options).rvalues,
378
- ...computeMemoizationInputs(value.right, null, options).rvalues,
385
+ ...computeMemoizationInputs(env, value.left, null, options).rvalues,
386
+ ...computeMemoizationInputs(env, value.right, null, options).rvalues,
387
],
388
};
389
}
397
// Only the final value of the sequence is a true rvalue:
398
// values from the sequence's instructions are evaluated
399
// as separate nodes
392
- rvalues: computeMemoizationInputs(value.value, null, options).rvalues,
400
+ rvalues: computeMemoizationInputs(env, value.value, null, options)
401
+ .rvalues,
402
};
403
}
404
case "JsxExpression": {
604
return {
605
lvalues: lvalues,
606
rvalues: [
598
- ...computeMemoizationInputs(value.value, null, options).rvalues,
607
+ ...computeMemoizationInputs(env, value.value, null, options).rvalues,
608
],
609
};
610
}
611
+ case "MethodCall": {
612
+ const signature = env.enableNoAliasOptimizations
613
+ ? getFunctionCallSignature(env, value.property.identifier.type)
614
+ : null;
615
+ const operands = [...eachReactiveValueOperand(value)];
616
+ let lvalues = [];
617
+ if (lvalue !== null) {
618
+ lvalues.push({ place: lvalue, level: MemoizationLevel.Memoized });
619
+ }
620
+ if (signature?.noAlias === true) {
621
+ return {
622
+ lvalues,
623
+ rvalues: [],
624
+ };
625
+ }
626
+ lvalues.push(
627
+ ...operands
628
+ .filter((operand) => isMutableEffect(operand.effect, operand.loc))
629
+ .map((place) => ({ place, level: MemoizationLevel.Memoized }))
630
+ );
631
+ return {
632
+ lvalues,
633
+ rvalues: operands,
634
+ };
635
+ }
636
case "RegExpLiteral":
637
case "FunctionExpression":
638
case "TaggedTemplateExpression":
605
- case "CallExpression":
639
case "ArrayExpression":
640
case "NewExpression":
641
case "ObjectExpression":
609
- case "MethodCall":
642
+ case "CallExpression":
643
case "PropertyStore": {
644
// All of these instructions may produce new values which must be memoized if
645
// reachable from a return value. Any mutable rvalue may alias any other rvalue
713
* identifier's and scope's dependencies.
714
*/
715
class CollectDependenciesVisitor extends ReactiveFunctionVisitor<State> {
716
+ env: Environment;
717
options: MemoizationOptions;
718
685
- constructor(options: MemoizationOptions) {
719
+ constructor(env: Environment, options: MemoizationOptions) {
720
super();
721
+ this.env = env;
722
this.options = options;
723
}
724
730
731
// Determe the level of memoization for this value and the lvalues/rvalues
732
const aliasing = computeMemoizationInputs(
733
+ this.env,
734
instruction.value,
735
instruction.lvalue,
736
this.options