perf(compiler): reduce amount of generated code for safe accesses and nullish coalescing (#41563)

This is follow-up from #41437 and it reduces the amount of code we generate for safe property accesses (`a?.b`) and nullish coalescing (`a ?? b`) by:
1. Reusing variables in nested nullish coalescing expressions.
2. Not initializing temporary variables to `null`. The way our code is generated means that the value will always be overwritten before we compare against it so the initializer didn't really matter.

Fixes #41491.

PR Close #41563
This commit is contained in:
Kristiyan Kostadinov 2021-04-12 17:36:31 +02:00 committed by Zach Arend
parent a1b2718b92
commit dde81ba0cd
8 changed files with 22 additions and 27 deletions

View File

@ -1,13 +1,12 @@
hostBindings: function MyApp_HostBindings(rf, ctx) {
if (rf & 1) {
i0.ɵɵlistener("click", function MyApp_click_HostBindingHandler() {
let tmp_b_0 = null;
let tmp_b_1 = null;
return ctx.logLastName((tmp_b_0 = (tmp_b_1 = ctx.lastName) !== null && tmp_b_1 !== undefined ? tmp_b_1 : ctx.lastNameFallback) !== null && tmp_b_0 !== undefined ? tmp_b_0 : "unknown");
let $tmp$;
return ctx.logLastName(($tmp$ = ($tmp$ = ctx.lastName) !== null && $tmp$ !== undefined ? $tmp$ : ctx.lastNameFallback) !== null && $tmp$ !== undefined ? $tmp$ : "unknown");
});
}
if (rf & 2) {
let tmp_b_0 = null;
i0.ɵɵattribute("first-name", "Hello, " + ((tmp_b_0 = ctx.firstName) !== null && tmp_b_0 !== undefined ? tmp_b_0 : "Frodo") + "!");
let $tmp$;
i0.ɵɵattribute("first-name", "Hello, " + (($tmp$ = ctx.firstName) !== null && $tmp$ !== undefined ? $tmp$ : "Frodo") + "!");
}
}

View File

@ -8,12 +8,11 @@ template: function MyApp_Template(rf, ctx) {
i0.ɵɵelementEnd();
}
if (rf & 2) {
let tmp_0_0 = null;
let tmp_1_0 = null;
let tmp_1_1 = null;
let $tmp_0_0$;
let $tmp_1_0$;
i0.ɵɵadvance(1);
i0.ɵɵtextInterpolate1("Hello, ", (tmp_0_0 = ctx.firstName) !== null && tmp_0_0 !== undefined ? tmp_0_0 : "Frodo", "!");
i0.ɵɵtextInterpolate1("Hello, ", ($tmp_0_0$ = ctx.firstName) !== null && $tmp_0_0$ !== undefined ? $tmp_0_0$ : "Frodo", "!");
i0.ɵɵadvance(2);
i0.ɵɵtextInterpolate1("Your last name is ", (tmp_1_0 = (tmp_1_1 = ctx.lastName) !== null && tmp_1_1 !== undefined ? tmp_1_1 : ctx.lastNameFallback) !== null && tmp_1_0 !== undefined ? tmp_1_0 : "unknown", "");
i0.ɵɵtextInterpolate1("Your last name is ", ($tmp_1_0$ = ($tmp_1_0$ = ctx.lastName) !== null && $tmp_1_0$ !== undefined ? $tmp_1_0$ : ctx.lastNameFallback) !== null && $tmp_1_0$ !== undefined ? $tmp_1_0$ : "unknown", "");
}
}

View File

@ -4,11 +4,10 @@ template: function MyApp_Template(rf, ctx) {
i0.ɵɵelement(1, "span", 0);
}
if (rf & 2) {
let tmp_0_0 = null;
let tmp_1_0 = null;
let tmp_1_1 = null;
i0.ɵɵproperty("title", "Hello, " + ((tmp_0_0 = ctx.firstName) !== null && tmp_0_0 !== undefined ? tmp_0_0 : "Frodo") + "!");
let $tmp_0_0$;
let $tmp_1_0$;
i0.ɵɵproperty("title", "Hello, " + (($tmp_0_0$ = ctx.firstName) !== null && $tmp_0_0$ !== undefined ? $tmp_0_0$ : "Frodo") + "!");
i0.ɵɵadvance(1);
i0.ɵɵproperty("title", (tmp_1_0 = (tmp_1_1 = "Your last name is " + ctx.lastName) !== null && tmp_1_1 !== undefined ? tmp_1_1 : ctx.lastNameFallback) !== null && tmp_1_0 !== undefined ? tmp_1_0 : "unknown");
i0.ɵɵproperty("title", ($tmp_1_0$ = ($tmp_1_0$ = "Your last name is " + ctx.lastName) !== null && $tmp_1_0$ !== undefined ? $tmp_1_0$ : ctx.lastNameFallback) !== null && $tmp_1_0$ !== undefined ? $tmp_1_0$ : "unknown");
}
}

View File

@ -5,7 +5,7 @@ HostBindingDir.ɵdir = /*@__PURE__*/ $r3$.ɵɵdefineDirective({
hostVars: 1,
hostBindings: function HostBindingDir_HostBindings(rf, ctx) {
if (rf & 2) {
let $tmp0$ = null;
let $tmp0$;
$r3$.ɵɵhostProperty("id", ($tmp0$ = ctx.getData()) == null ? null : $tmp0$.id);
}
}

View File

@ -1,7 +1,7 @@
template: function MyComponent_Template(rf, ctx) {
if (rf & 2) {
let $tmp0$ = null;
$r3$.ɵɵproperty("title", ctx.myTitle)("id", (tmp_1_0 = i0.ɵɵpipeBind1(1, 3, ctx.auth().identity())) == null ? null : tmp_1_0.id)("tabindex", 1);
let $tmp0$;
$r3$.ɵɵproperty("title", ctx.myTitle)("id", ($tmp0$ = i0.ɵɵpipeBind1(1, 3, ctx.auth().identity())) == null ? null : $tmp0$.id)("tabindex", 1);
}
}

View File

@ -14,7 +14,7 @@ template: function MyComponent_Template(rf, ctx) {
$r3$.ɵɵelementEnd();
}
if (rf & 2) {
let $tmp_0_0$ = null;
let $tmp_0_0$;
$r3$.ɵɵi18nExp(($tmp_0_0$ = ctx.valueA.getRawValue()) == null ? null : $tmp_0_0$.getTitle());
$r3$.ɵɵi18nApply(1);
}

View File

@ -12,7 +12,7 @@ template: function MyComponent_Template(rf, ctx) {
$r3$.ɵɵelementEnd();
}
if (rf & 2) {
let $tmp_2_0$ = null;
let $tmp_2_0$;
$r3$.ɵɵadvance(2);
$r3$.ɵɵi18nExp($r3$.ɵɵpipeBind1(2, 3, ctx.valueA))
(ctx.valueA == null ? null : ctx.valueA.a == null ? null : ctx.valueA.a.b)

View File

@ -259,8 +259,8 @@ function temporaryName(bindingId: string, temporaryNumber: number): string {
return `tmp_${bindingId}_${temporaryNumber}`;
}
export function temporaryDeclaration(bindingId: string, temporaryNumber: number): o.Statement {
return new o.DeclareVarStmt(temporaryName(bindingId, temporaryNumber), o.NULL_EXPR);
function temporaryDeclaration(bindingId: string, temporaryNumber: number): o.Statement {
return new o.DeclareVarStmt(temporaryName(bindingId, temporaryNumber));
}
function prependTemporaryDecls(
@ -728,15 +728,13 @@ class _AstToIrVisitor implements cdAst.AstVisitor {
}
// Produce the conditional
return convertToStatementIfNeeded(mode, condition.conditional(o.literal(null), access));
return convertToStatementIfNeeded(mode, condition.conditional(o.NULL_EXPR, access));
}
private convertNullishCoalesce(ast: cdAst.Binary, mode: _Mode): any {
// Allocate the temporary variable before visiting the LHS and RHS, because they
// may allocate temporary variables too and we don't want them to be reused.
const temporary = this.allocateTemporary();
const left: o.Expression = this._visit(ast.left, _Mode.Expression);
const right: o.Expression = this._visit(ast.right, _Mode.Expression);
const temporary = this.allocateTemporary();
this.releaseTemporary(temporary);
// Generate the following expression. It is identical to how TS