From 35227049a1024cd6984f6da83e9ae01b92e2cfcc Mon Sep 17 00:00:00 2001 From: Alex Rickabaugh Date: Tue, 2 May 2023 11:04:51 -0700 Subject: [PATCH] refactor(compiler): purify literal arrays and maps in template pipeline (#50118) This commit transforms literal arrays and maps within expressions in the template pipeline into `ir.PureFunctionExpr` expressions, in order to memoize the allocation of objects and arrays inside the update pass of change detection. PR Close #50118 --- .../src/template/pipeline/src/emit.ts | 2 + .../src/phases/pure_literal_structures.ts | 65 +++++++++++++++++++ 2 files changed, 67 insertions(+) create mode 100644 packages/compiler/src/template/pipeline/src/phases/pure_literal_structures.ts diff --git a/packages/compiler/src/template/pipeline/src/emit.ts b/packages/compiler/src/template/pipeline/src/emit.ts index 26ce6eab52e..1817cab70ef 100644 --- a/packages/compiler/src/template/pipeline/src/emit.ts +++ b/packages/compiler/src/template/pipeline/src/emit.ts @@ -29,12 +29,14 @@ import {phaseMergeNextContext} from './phases/next_context_merging'; import {phaseNgContainer} from './phases/ng_container'; import {phaseSaveRestoreView} from './phases/save_restore_view'; import {phasePureFunctionExtraction} from './phases/pure_function_extraction'; +import {phasePureLiteralStructures} from './phases/pure_literal_structures'; /** * Run all transformation phases in the correct order against a `ComponentCompilation`. After this * processing, the compilation should be in a state where it can be emitted via `emitTemplateFn`.s */ export function transformTemplate(cpl: ComponentCompilation): void { + phasePureLiteralStructures(cpl); phaseGenerateVariables(cpl); phaseSaveRestoreView(cpl); phaseResolveNames(cpl); diff --git a/packages/compiler/src/template/pipeline/src/phases/pure_literal_structures.ts b/packages/compiler/src/template/pipeline/src/phases/pure_literal_structures.ts new file mode 100644 index 00000000000..a77f65713f2 --- /dev/null +++ b/packages/compiler/src/template/pipeline/src/phases/pure_literal_structures.ts @@ -0,0 +1,65 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import * as o from '../../../../output/output_ast'; +import * as ir from '../../ir'; +import type {ComponentCompilation} from '../compilation'; + +export function phasePureLiteralStructures(cpl: ComponentCompilation): void { + for (const view of cpl.views.values()) { + for (const op of view.update) { + ir.transformExpressionsInOp(op, (expr, flags) => { + if (flags & ir.VisitorContextFlag.InChildOperation) { + return expr; + } + + if (expr instanceof o.LiteralArrayExpr) { + return transformLiteralArray(expr); + } else if (expr instanceof o.LiteralMapExpr) { + return transformLiteralMap(expr); + } + + return expr; + }, ir.VisitorContextFlag.None); + } + } +} + +function transformLiteralArray(expr: o.LiteralArrayExpr): o.Expression { + const derivedEntries: o.Expression[] = []; + const nonConstantArgs: o.Expression[] = []; + for (const entry of expr.entries) { + if (entry.isConstant()) { + derivedEntries.push(entry); + } else { + const idx = nonConstantArgs.length; + nonConstantArgs.push(entry); + derivedEntries.push(new ir.PureFunctionParameterExpr(idx)); + } + } + return new ir.PureFunctionExpr(o.literalArr(derivedEntries), nonConstantArgs); +} + +function transformLiteralMap(expr: o.LiteralMapExpr): o.Expression { + let derivedEntries: o.LiteralMapEntry[] = []; + const nonConstantArgs: o.Expression[] = []; + for (const entry of expr.entries) { + if (entry.value.isConstant()) { + derivedEntries.push(entry); + } else { + const idx = nonConstantArgs.length; + nonConstantArgs.push(entry.value); + derivedEntries.push(new o.LiteralMapEntry( + entry.key, + new ir.PureFunctionParameterExpr(idx), + entry.quoted, + )); + } + } + return new ir.PureFunctionExpr(o.literalMap(derivedEntries), nonConstantArgs); +}