461
): void {
462
const cacheStoreStatements: Array<t.Statement> = [];
463
const cacheLoadStatements: Array<t.Statement> = [];
464
+ const cacheLoads: Array<{
465
+ name: t.Identifier;
466
+ index: number;
467
+ value: t.Expression;
468
+ }> = [];
469
const changeExpressions: Array<t.Expression> = [];
470
const changeExpressionComments: Array<string> = [];
471
const outputComments: Array<string> = [];
493
} else {
494
changeExpressions.push(comparison);
495
}
496
+ /*
497
+ * Adding directly to cacheStoreStatements rather than cacheLoads, because there
498
+ * is no corresponding cacheLoadStatement for dependencies
499
+ */
500
cacheStoreStatements.push(
501
t.expressionStatement(
502
t.assignmentExpression(
532
t.variableDeclaration("let", [t.variableDeclarator(name)])
533
);
534
}
526
- cacheStoreStatements.push(
527
- t.expressionStatement(
528
- t.assignmentExpression(
529
- "=",
530
- t.memberExpression(
531
- t.identifier(cx.synthesizeName("$")),
532
- t.numericLiteral(index),
533
- true
534
- ),
535
- wrapCacheDep(cx, name)
536
- )
537
- )
538
- );
539
- cacheLoadStatements.push(
540
- t.expressionStatement(
541
- t.assignmentExpression(
542
- "=",
543
- name,
544
- t.memberExpression(
545
- t.identifier(cx.synthesizeName("$")),
546
- t.numericLiteral(index),
547
- true
548
- )
549
- )
550
- )
551
- );
535
+ cacheLoads.push({ name, index, value: wrapCacheDep(cx, name) });
536
cx.declare(identifier);
537
}
538
for (const reassignment of scope.reassignments) {
542
}
543
const name = convertIdentifier(reassignment);
544
outputComments.push(name.name);
561
-
562
- cacheStoreStatements.push(
563
- t.expressionStatement(
564
- t.assignmentExpression(
565
- "=",
566
- t.memberExpression(
567
- t.identifier(cx.synthesizeName("$")),
568
- t.numericLiteral(index),
569
- true
570
- ),
571
- wrapCacheDep(cx, name)
572
- )
573
- )
574
- );
575
- cacheLoadStatements.push(
576
- t.expressionStatement(
577
- t.assignmentExpression(
578
- "=",
579
- name,
580
- t.memberExpression(
581
- t.identifier(cx.synthesizeName("$")),
582
- t.numericLiteral(index),
583
- true
584
- )
585
- )
586
- )
587
- );
545
+ cacheLoads.push({ name, index, value: wrapCacheDep(cx, name) });
546
}
547
+
548
let testCondition = (changeExpressions as Array<t.Expression>).reduce(
549
(acc: t.Expression | null, ident: t.Expression) => {
550
if (acc == null) {
591
);
592
}
593
let computationBlock = codegenBlock(cx, block);
594
+
595
let memoStatement;
636
- const memoBlock = t.blockStatement(cacheLoadStatements);
596
if (
597
cx.env.config.enableChangeDetectionForDebugging != null &&
598
changeExpressions.length > 0
599
) {
600
const detectionFunction =
601
cx.env.config.enableChangeDetectionForDebugging.importSpecifierName;
602
+ const cacheLoadOldValueStatements: Array<t.Statement> = [];
603
const changeDetectionStatements: Array<t.Statement> = [];
644
- const oldVarDeclarationStatements: Array<t.Statement> = [];
645
- memoBlock.body.forEach((stmt) => {
646
- if (
647
- stmt.type === "ExpressionStatement" &&
648
- stmt.expression.type === "AssignmentExpression" &&
649
- stmt.expression.left.type === "Identifier"
650
- ) {
651
- const name = stmt.expression.left.name;
652
- const loadName = cx.synthesizeName(`old$${name}`);
653
- oldVarDeclarationStatements.push(
654
- t.variableDeclaration("let", [
655
- t.variableDeclarator(t.identifier(loadName)),
604
+ const idempotenceDetectionStatements: Array<t.Statement> = [];
605
+
606
+ for (const { name, index, value } of cacheLoads) {
607
+ const loadName = cx.synthesizeName(`old$${name.name}`);
608
+ const slot = t.memberExpression(
609
+ t.identifier(cx.synthesizeName("$")),
610
+ t.numericLiteral(index),
611
+ true
612
+ );
613
+ cacheStoreStatements.push(
614
+ t.expressionStatement(t.assignmentExpression("=", slot, value))
615
+ );
616
+ cacheLoadOldValueStatements.push(
617
+ t.variableDeclaration("let", [
618
+ t.variableDeclarator(t.identifier(loadName), slot),
619
+ ])
620
+ );
621
+ changeDetectionStatements.push(
622
+ t.expressionStatement(
623
+ t.callExpression(t.identifier(detectionFunction), [
624
+ t.identifier(loadName),
625
+ name,
626
+ t.stringLiteral(name.name),
627
+ t.stringLiteral(cx.fnName),
628
+ t.stringLiteral("cached"),
629
])
657
- );
658
- stmt.expression.left = t.identifier(loadName);
659
- changeDetectionStatements.push(
660
- t.expressionStatement(
661
- t.callExpression(t.identifier(detectionFunction), [
662
- t.identifier(loadName),
663
- t.identifier(name),
664
- t.stringLiteral(name),
665
- t.stringLiteral(cx.fnName),
666
- ])
667
- )
668
- );
669
- changeDetectionStatements.push(
670
- t.expressionStatement(
671
- t.assignmentExpression(
672
- "=",
673
- t.identifier(name),
674
- t.identifier(loadName)
675
- )
676
- )
677
- );
678
- }
679
- });
630
+ )
631
+ );
632
+ idempotenceDetectionStatements.push(
633
+ t.expressionStatement(
634
+ t.callExpression(t.identifier(detectionFunction), [
635
+ slot,
636
+ name,
637
+ t.stringLiteral(name.name),
638
+ t.stringLiteral(cx.fnName),
639
+ t.stringLiteral("recomputed"),
640
+ ])
641
+ )
642
+ );
643
+ idempotenceDetectionStatements.push(
644
+ t.expressionStatement(t.assignmentExpression("=", name, slot))
645
+ );
646
+ }
647
+ const condition = cx.synthesizeName("condition");
648
memoStatement = t.blockStatement([
649
...computationBlock.body,
650
+ t.variableDeclaration("let", [
651
+ t.variableDeclarator(t.identifier(condition), testCondition),
652
+ ]),
653
t.ifStatement(
683
- t.unaryExpression("!", testCondition),
654
+ t.unaryExpression("!", t.identifier(condition)),
655
t.blockStatement([
685
- ...oldVarDeclarationStatements,
686
- ...memoBlock.body,
656
+ ...cacheLoadOldValueStatements,
657
...changeDetectionStatements,
658
])
659
),
660
...cacheStoreStatements,
661
+ t.ifStatement(
662
+ t.identifier(condition),
663
+ t.blockStatement([
664
+ ...computationBlock.body,
665
+ ...idempotenceDetectionStatements,
666
+ ])
667
+ ),
668
]);
669
} else {
670
+ for (const { name, index, value } of cacheLoads) {
671
+ cacheStoreStatements.push(
672
+ t.expressionStatement(
673
+ t.assignmentExpression(
674
+ "=",
675
+ t.memberExpression(
676
+ t.identifier(cx.synthesizeName("$")),
677
+ t.numericLiteral(index),
678
+ true
679
+ ),
680
+ value
681
+ )
682
+ )
683
+ );
684
+ cacheLoadStatements.push(
685
+ t.expressionStatement(
686
+ t.assignmentExpression(
687
+ "=",
688
+ name,
689
+ t.memberExpression(
690
+ t.identifier(cx.synthesizeName("$")),
691
+ t.numericLiteral(index),
692
+ true
693
+ )
694
+ )
695
+ )
696
+ );
697
+ }
698
computationBlock.body.push(...cacheStoreStatements);
694
-
695
- memoStatement = t.ifStatement(testCondition, computationBlock, memoBlock);
699
+ memoStatement = t.ifStatement(
700
+ testCondition,
701
+ computationBlock,
702
+ t.blockStatement(cacheLoadStatements)
703
+ );
704
}
705
706
if (cx.env.config.enableMemoizationComments) {
742
true
743
);
744
}
737
- if (memoBlock.body.length > 0) {
745
+ if (cacheLoadStatements.length > 0) {
746
t.addComment(
739
- memoBlock.body[0]!,
747
+ cacheLoadStatements[0]!,
748
"leading",
749
` Inputs did not change, use cached value`,
750
true