From 8555d51bc7d9d7c546bd4117d13a62f176a4a046 Mon Sep 17 00:00:00 2001 From: Pawel Kozlowski Date: Fri, 15 Nov 2019 16:59:31 +0100 Subject: [PATCH] perf(ivy): extract template's instruction first create pass processing (#33856) This refactorings clearly separates the first and subsequent creation execution of the `template` instruction. This approach has the following benefits: - it is clear what happens during the first vs. subsequent executions; - we can avoid several memory reads and checks after the first creation pass (there is measurable performance improvement on various benchmarks); - the template instructions becomes smaller and should become a candidate for optimisations / inlining faster; PR Close #33856 --- .../src/render3/instructions/container.ts | 75 ++++++++++++------- .../bundling/todo/bundle.golden_symbols.json | 6 +- 2 files changed, 49 insertions(+), 32 deletions(-) diff --git a/packages/core/src/render3/instructions/container.ts b/packages/core/src/render3/instructions/container.ts index 1e152ac266..ef5fa7e63f 100644 --- a/packages/core/src/render3/instructions/container.ts +++ b/packages/core/src/render3/instructions/container.ts @@ -6,14 +6,14 @@ * found in the LICENSE file at https://angular.io/license */ import {assertDataInRange, assertEqual} from '../../util/assert'; -import {assertHasParent} from '../assert'; +import {assertFirstCreatePass, assertHasParent} from '../assert'; import {attachPatchData} from '../context_discovery'; import {executeCheckHooks, executeInitAndCheckHooks, incrementInitPhaseFlags, registerPostOrderHooks} from '../hooks'; import {ACTIVE_INDEX, CONTAINER_HEADER_OFFSET, LContainer} from '../interfaces/container'; import {ComponentTemplate} from '../interfaces/definition'; import {LocalRefExtractor, TAttributes, TContainerNode, TNode, TNodeType, TViewNode} from '../interfaces/node'; import {isDirectiveHost} from '../interfaces/type_checks'; -import {FLAGS, HEADER_OFFSET, InitPhaseState, LView, LViewFlags, RENDERER, TVIEW, TViewType, T_HOST} from '../interfaces/view'; +import {FLAGS, HEADER_OFFSET, InitPhaseState, LView, LViewFlags, RENDERER, TVIEW, TView, TViewType, T_HOST} from '../interfaces/view'; import {assertNodeType} from '../node_assert'; import {appendChild, removeView} from '../node_manipulation'; import {getBindingIndex, getCheckNoChangesMode, getIsParent, getLView, getPreviousOrParentTNode, setIsNotParent, setPreviousOrParentTNode} from '../state'; @@ -44,6 +44,36 @@ export function ɵɵcontainer(index: number): void { setIsNotParent(); } +function templateFirstCreatePass( + index: number, tView: TView, lView: LView, templateFn: ComponentTemplate| null, + decls: number, vars: number, tagName?: string | null, attrsIndex?: number | null, + localRefsIndex?: number | null): TContainerNode { + ngDevMode && assertFirstCreatePass(tView); + ngDevMode && ngDevMode.firstCreatePass++; + const tViewConsts = tView.consts; + // TODO(pk): refactor getOrCreateTNode to have the "create" only version + const tNode = getOrCreateTNode( + tView, lView[T_HOST], index, TNodeType.Container, tagName || null, + getConstant(tViewConsts, attrsIndex)); + + resolveDirectives(tView, lView, tNode, getConstant(tViewConsts, localRefsIndex)); + registerPostOrderHooks(tView, tNode); + + const embeddedTView = tNode.tViews = createTView( + TViewType.Embedded, -1, templateFn, decls, vars, tView.directiveRegistry, tView.pipeRegistry, + null, tView.schemas, tViewConsts); + const embeddedTViewNode = createTNode(tView, null, TNodeType.View, -1, null, null) as TViewNode; + embeddedTViewNode.injectorIndex = tNode.injectorIndex; + embeddedTView.node = embeddedTViewNode; + + if (tView.queries !== null) { + tView.queries.template(tView, tNode); + embeddedTView.queries = tView.queries.embeddedTView(tNode); + } + + return tNode; +} + /** * Creates an LContainer for an ng-template (dynamically-inserted view), e.g. * @@ -69,40 +99,27 @@ export function ɵɵtemplate( localRefExtractor?: LocalRefExtractor) { const lView = getLView(); const tView = lView[TVIEW]; - const tViewConsts = tView.consts; + const adjustedIndex = index + HEADER_OFFSET; - // TODO: consider a separate node type for templates - const tContainerNode = containerInternal( - lView, index, tagName || null, getConstant(tViewConsts, attrsIndex)); + const tNode = tView.firstCreatePass ? + templateFirstCreatePass( + index, tView, lView, templateFn, decls, vars, tagName, attrsIndex, localRefsIndex) : + tView.data[adjustedIndex] as TContainerNode; + setPreviousOrParentTNode(tNode, false); - if (tView.firstCreatePass) { - ngDevMode && ngDevMode.firstCreatePass++; - resolveDirectives( - tView, lView, tContainerNode, getConstant(tViewConsts, localRefsIndex)); - registerPostOrderHooks(tView, tContainerNode); + const comment = lView[RENDERER].createComment(ngDevMode ? 'container' : ''); + appendChild(comment, tNode, lView); + attachPatchData(comment, lView); - const embeddedTView = tContainerNode.tViews = createTView( - TViewType.Embedded, -1, templateFn, decls, vars, tView.directiveRegistry, - tView.pipeRegistry, null, tView.schemas, tViewConsts); - const embeddedTViewNode = createTNode(tView, null, TNodeType.View, -1, null, null) as TViewNode; - embeddedTViewNode.injectorIndex = tContainerNode.injectorIndex; - embeddedTView.node = embeddedTViewNode; + addToViewTree(lView, lView[adjustedIndex] = createLContainer(comment, lView, comment, tNode)); - if (tView.queries !== null) { - tView.queries.template(tView, tContainerNode); - embeddedTView.queries = tView.queries.embeddedTView(tContainerNode); - } + if (isDirectiveHost(tNode)) { + createDirectivesInstances(tView, lView, tNode); } - if (isDirectiveHost(tContainerNode)) { - createDirectivesInstances(tView, lView, tContainerNode); + if (localRefsIndex != null) { + saveResolvedLocalsInData(lView, tNode, localRefExtractor); } - - if (localRefsIndex !== null) { - saveResolvedLocalsInData(lView, tContainerNode, localRefExtractor); - } - - setIsNotParent(); } /** diff --git a/packages/core/test/bundling/todo/bundle.golden_symbols.json b/packages/core/test/bundling/todo/bundle.golden_symbols.json index 23fec5b572..db29b88c6d 100644 --- a/packages/core/test/bundling/todo/bundle.golden_symbols.json +++ b/packages/core/test/bundling/todo/bundle.golden_symbols.json @@ -443,9 +443,6 @@ { "name": "concatString" }, - { - "name": "containerInternal" - }, { "name": "createContainerRef" }, @@ -1301,6 +1298,9 @@ { "name": "syncViewWithBlueprint" }, + { + "name": "templateFirstCreatePass" + }, { "name": "textBindingInternal" },