@samitouri / QOS-React-2 / commits / 77bb9ff765

ReactiveFunction and codegen for optional calls

Implements HIR->ReactiveFunction conversion and Codegen for optional calls. We add a new OptionalCall variant of ReactiveValue, which is a SequenceExpression that describes the evaluation of the args and the call itself. This is then straightforward to codgen.

Joe Savona committed Mar 24, 2023 at 14:22 UTC 77bb9ff765af43a59c96f5f558c3a5df46445c48
11 files changed +104 -21
compiler/forget/src/HIR/BuildHIR.ts
+1 -1
@@ -941,7 +941,7 @@ function lowerExpression(
941 }
942 case "OptionalCallExpression": {
943 const expr = exprPath as NodePath<t.OptionalCallExpression>;
944 - const optional = expr.get("optional");
944 + const optional = expr.node.optional;
945 const calleePath = expr.get("callee");
946 if (
947 calleePath.isMemberExpression() ||
compiler/forget/src/HIR/HIR.ts
+10 -1
@@ -90,7 +90,8 @@ export type ReactiveValue =
90 | InstructionValue
91 | ReactiveLogicalValue
92 | ReactiveSequenceValue
93 - | ReactiveTernaryValue;
93 + | ReactiveTernaryValue
94 + | ReactiveOptionalCallValue;
95
96 export type ReactiveLogicalValue = {
97 kind: "LogicalExpression";
@@ -116,6 +117,14 @@ export type ReactiveSequenceValue = {
117 loc: SourceLocation;
118 };
119
120 +export type ReactiveOptionalCallValue = {
121 + kind: "OptionalCall";
122 + id: InstructionId;
123 + call: ReactiveValue;
124 + optional: boolean;
125 + loc: SourceLocation;
126 +};
127 +
128 export type ReactiveTerminal =
129 | ReactiveBreakTerminal
130 | ReactiveContinueTerminal
compiler/forget/src/HIR/PrintHIR.ts
+4
@@ -440,6 +440,10 @@ export function printInstructionValue(instrValue: ReactiveValue): string {
440 value = `Global ${instrValue.name}`;
441 break;
442 }
443 + case "OptionalCall": {
444 + value = `OptionalCall ${printInstructionValue(instrValue.call)}`;
445 + break;
446 + }
447 default: {
448 assertExhaustive(
449 instrValue,
compiler/forget/src/ReactiveScopes/BuildReactiveFunction.ts
+26 -4
@@ -29,7 +29,6 @@ import {
29 ReactiveValue,
30 Terminal,
31 } from "../HIR/HIR";
32 -import todo from "../Utils/todo";
32 import { assertExhaustive } from "../Utils/utils";
33
34 /**
@@ -457,6 +456,7 @@ class Driver {
456
457 break;
458 }
459 + case "optional-call":
460 case "ternary":
461 case "logical": {
462 const fallthroughId = terminal.fallthrough;
@@ -482,9 +482,6 @@ class Driver {
482 this.visitBlock(this.cx.ir.blocks.get(fallthroughId)!, blockValue);
483 break;
484 }
485 - case "optional-call": {
486 - todo("BuildReactiveFunction: support optional-call terminal");
487 - }
485 case "goto": {
486 switch (terminal.variant) {
487 case GotoVariant.Break: {
@@ -655,6 +652,31 @@ class Driver {
652 id: InstructionId;
653 } {
654 switch (terminal.kind) {
655 + case "optional-call": {
656 + const test = this.visitValueBlock(terminal.test, terminal.loc);
657 + const testBlock = this.cx.ir.blocks.get(test.block)!;
658 + invariant(
659 + testBlock.terminal.kind === "branch",
660 + "Unexpected terminal kind '%s' for optional call test block",
661 + testBlock.terminal.kind
662 + );
663 + const consequent = this.visitValueBlock(
664 + testBlock.terminal.consequent,
665 + terminal.loc
666 + );
667 + return {
668 + place: { ...consequent.place },
669 + value: {
670 + kind: "OptionalCall",
671 + optional: terminal.optional,
672 + call: consequent.value,
673 + id: terminal.id,
674 + loc: terminal.loc,
675 + },
676 + fallthrough: terminal.fallthrough,
677 + id: terminal.id,
678 + };
679 + }
680 case "logical": {
681 const test = this.visitValueBlock(terminal.test, terminal.loc);
682 const testBlock = this.cx.ir.blocks.get(test.block)!;
compiler/forget/src/ReactiveScopes/CodegenReactiveFunction.ts
+14
@@ -589,6 +589,20 @@ function codegenInstructionValue(
589 value = createCallExpression(instrValue.loc, callee, args);
590 break;
591 }
592 + case "OptionalCall": {
593 + const call = codegenInstructionValue(cx, instrValue.call);
594 + invariant(call.type === "CallExpression", "Expected a call expression");
595 + invariant(
596 + t.isExpression(call.callee),
597 + "v8 intrinsics are validated during lowering"
598 + );
599 + value = t.optionalCallExpression(
600 + call.callee,
601 + call.arguments,
602 + instrValue.optional
603 + );
604 + break;
605 + }
606 case "MethodCall": {
607 const memberExpr = codegenPlace(cx, instrValue.property);
608 invariant(
compiler/forget/src/ReactiveScopes/MergeOverlappingReactiveScopes.ts
+2 -1
@@ -124,7 +124,8 @@ class Visitor extends ReactiveFunctionVisitor<Context> {
124 ): void {
125 if (
126 instruction.value.kind === "ConditionalExpression" ||
127 - instruction.value.kind === "LogicalExpression"
127 + instruction.value.kind === "LogicalExpression" ||
128 + instruction.value.kind === "OptionalCall"
129 ) {
130 state.enter(() => {
131 super.visitInstruction(instruction, state);
compiler/forget/src/ReactiveScopes/PropagateScopeDependencies.ts
+6
@@ -444,6 +444,12 @@ function visitReactiveValue(
444 value: ReactiveValue
445 ): void {
446 switch (value.kind) {
447 + case "OptionalCall": {
448 + context.enterConditional(() => {
449 + visitReactiveValue(context, id, value.call);
450 + });
451 + break;
452 + }
453 case "LogicalExpression": {
454 visitReactiveValue(context, id, value.left);
455 context.enterConditional(() => {
compiler/forget/src/ReactiveScopes/PruneNonEscapingScopes.ts
+1
@@ -508,6 +508,7 @@ function computeMemoizationInputs(
508 rvalues: [value.value],
509 };
510 }
511 + case "OptionalCall":
512 case "FunctionExpression":
513 case "TaggedTemplateExpression":
514 case "CallExpression":
compiler/forget/src/ReactiveScopes/visitors.ts
+8
@@ -41,6 +41,10 @@ export class ReactiveFunctionVisitor<TState = void> {
41 }
42 traverseValue(id: InstructionId, value: ReactiveValue, state: TState): void {
43 switch (value.kind) {
44 + case "OptionalCall": {
45 + this.visitValue(id, value.call, state);
46 + break;
47 + }
48 case "LogicalExpression": {
49 this.visitValue(id, value.left, state);
50 this.visitValue(id, value.right, state);
@@ -277,6 +281,10 @@ export function* eachReactiveValueOperand(
281 instrValue: ReactiveValue
282 ): Iterable<Place> {
283 switch (instrValue.kind) {
284 + case "OptionalCall": {
285 + yield* eachReactiveValueOperand(instrValue.call);
286 + break;
287 + }
288 case "LogicalExpression": {
289 yield* eachReactiveValueOperand(instrValue.left);
290 yield* eachReactiveValueOperand(instrValue.right);
compiler/forget/src/SSA/LeaveSSA.ts
+5 -1
@@ -336,7 +336,11 @@ export function leaveSSA(fn: HIRFunction): void {
336 const update = fn.body.blocks.get(terminal.update)!;
337 pushPhis(update);
338 }
339 - if (terminal.kind === "logical" || terminal.kind === "ternary") {
339 + if (
340 + terminal.kind === "logical" ||
341 + terminal.kind === "ternary" ||
342 + terminal.kind === "optional-call"
343 + ) {
344 const fallthrough = fn.body.blocks.get(terminal.fallthrough)!;
345 pushPhis(fallthrough);
346 }
compiler/forget/yarn.lock
+27 -13
@@ -83,12 +83,12 @@
83 "@jridgewell/gen-mapping" "^0.3.2"
84 jsesc "^2.5.1"
85
86 -"@babel/generator@^7.21.1":
87 - version "7.21.1"
88 - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.21.1.tgz#951cc626057bc0af2c35cd23e9c64d384dea83dd"
89 - integrity sha512-1lT45bAYlQhFn/BHivJs43AiW2rg3/UbLyShGfF3C0KmHvO5fSghWd5kBJy30kpRRucGzXStvnnCFniCR2kXAA==
86 +"@babel/generator@^7.21.3":
87 + version "7.21.3"
88 + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.21.3.tgz#232359d0874b392df04045d72ce2fd9bb5045fce"
89 + integrity sha512-QS3iR1GYC/YGUnW7IdggFeN5c1poPUurnGttOV/bZgPGV+izC/D8HnD6DLwod0fsatNyVn1G3EVWMYIF0nHbeA==
90 dependencies:
91 - "@babel/types" "^7.21.0"
91 + "@babel/types" "^7.21.3"
92 "@jridgewell/gen-mapping" "^0.3.2"
93 "@jridgewell/trace-mapping" "^0.3.17"
94 jsesc "^2.5.1"
@@ -269,11 +269,16 @@
269 resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.19.3.tgz#8dd36d17c53ff347f9e55c328710321b49479a9a"
270 integrity sha512-pJ9xOlNWHiy9+FuFP09DEAFbAn4JskgRsVcc169w2xRBC3FRGuQEwjeIMMND9L2zc0iEhO/tGv4Zq+km+hxNpQ==
271
272 -"@babel/parser@^7.20.7", "@babel/parser@^7.21.2":
272 +"@babel/parser@^7.20.7":
273 version "7.21.2"
274 resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.21.2.tgz#dacafadfc6d7654c3051a66d6fe55b6cb2f2a0b3"
275 integrity sha512-URpaIJQwEkEC2T9Kn+Ai6Xe/02iNaVCuT/PtoRz3GPVJVDpPd7mLo+VddTbhCRU9TXqW5mSrQfXZyi8kDKOVpQ==
276
277 +"@babel/parser@^7.21.3":
278 + version "7.21.3"
279 + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.21.3.tgz#1d285d67a19162ff9daa358d4cb41d50c06220b3"
280 + integrity sha512-lobG0d7aOfQRXh8AyklEAgZGvA4FShxo6xQbUrrT/cNBPUdIDojlokwJsQyCC/eKia7ifqM0yP+2DRZ4WKw2RQ==
281 +
282 "@babel/plugin-syntax-async-generators@^7.8.4":
283 version "7.8.4"
284 resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d"
@@ -502,18 +507,18 @@
507 lodash "^4.17.10"
508
509 "@babel/traverse@^7.19.1":
505 - version "7.21.2"
506 - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.21.2.tgz#ac7e1f27658750892e815e60ae90f382a46d8e75"
507 - integrity sha512-ts5FFU/dSUPS13tv8XiEObDu9K+iagEKME9kAbaP7r0Y9KtZJZ+NGndDvWoRAYNpeWafbpFeki3q9QoMD6gxyw==
510 + version "7.21.3"
511 + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.21.3.tgz#4747c5e7903d224be71f90788b06798331896f67"
512 + integrity sha512-XLyopNeaTancVitYZe2MlUEvgKb6YVVPXzofHgqHijCImG33b/uTurMS488ht/Hbsb2XK3U2BnSTxKVNGV3nGQ==
513 dependencies:
514 "@babel/code-frame" "^7.18.6"
510 - "@babel/generator" "^7.21.1"
515 + "@babel/generator" "^7.21.3"
516 "@babel/helper-environment-visitor" "^7.18.9"
517 "@babel/helper-function-name" "^7.21.0"
518 "@babel/helper-hoist-variables" "^7.18.6"
519 "@babel/helper-split-export-declaration" "^7.18.6"
515 - "@babel/parser" "^7.21.2"
516 - "@babel/types" "^7.21.2"
520 + "@babel/parser" "^7.21.3"
521 + "@babel/types" "^7.21.3"
522 debug "^4.1.0"
523 globals "^11.1.0"
524
@@ -561,7 +566,7 @@
566 "@babel/helper-validator-identifier" "^7.19.1"
567 to-fast-properties "^2.0.0"
568
564 -"@babel/types@^7.21.0", "@babel/types@^7.21.2":
569 +"@babel/types@^7.21.0":
570 version "7.21.2"
571 resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.21.2.tgz#92246f6e00f91755893c2876ad653db70c8310d1"
572 integrity sha512-3wRZSs7jiFaB8AjxiiD+VqN5DTG2iRvJGQ+qYFrs/654lg6kGTQWIOFjlBo5RaXuAZjBmP3+OQH4dmhqiiyYxw==
@@ -570,6 +575,15 @@
575 "@babel/helper-validator-identifier" "^7.19.1"
576 to-fast-properties "^2.0.0"
577
578 +"@babel/types@^7.21.3":
579 + version "7.21.3"
580 + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.21.3.tgz#4865a5357ce40f64e3400b0f3b737dc6d4f64d05"
581 + integrity sha512-sBGdETxC+/M4o/zKC0sl6sjWv62WFR/uzxrJ6uYyMLZOUlPnwzw0tKgVHOXxaAd5l2g8pEDM5RZ495GPQI77kg==
582 + dependencies:
583 + "@babel/helper-string-parser" "^7.19.4"
584 + "@babel/helper-validator-identifier" "^7.19.1"
585 + to-fast-properties "^2.0.0"
586 +
587 "@bcoe/v8-coverage@^0.2.3":
588 version "0.2.3"
589 resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"