From d4d07233dcbac4228051f3345c72ab3309d0c606 Mon Sep 17 00:00:00 2001 From: Pawel Kozlowski Date: Fri, 11 Oct 2019 16:38:07 +0200 Subject: [PATCH] perf(ivy): guard host binding execution with a TNode flag (#33102) Based on the results of the `directive_instantiate` executing host bindings logic (in creation mode) account for ~23% of time spent in the directive instantiation, even if a directive doesn't have host bindings! This is clearly wastful hence a new flag. PR Close #33102 --- .../src/render3/instructions/lview_debug.ts | 1 + .../core/src/render3/instructions/shared.ts | 9 ++++---- packages/core/src/render3/interfaces/node.ts | 23 ++++++++++++------- 3 files changed, 21 insertions(+), 12 deletions(-) diff --git a/packages/core/src/render3/instructions/lview_debug.ts b/packages/core/src/render3/instructions/lview_debug.ts index 362e678c98..1b99765ad3 100644 --- a/packages/core/src/render3/instructions/lview_debug.ts +++ b/packages/core/src/render3/instructions/lview_debug.ts @@ -164,6 +164,7 @@ export const TNodeConstructor = class TNode implements ITNode { if (this.flags & TNodeFlags.hasContentQuery) flags.push('TNodeFlags.hasContentQuery'); if (this.flags & TNodeFlags.hasStyleInput) flags.push('TNodeFlags.hasStyleInput'); if (this.flags & TNodeFlags.hasInitialStyling) flags.push('TNodeFlags.hasInitialStyling'); + if (this.flags & TNodeFlags.hasHostBindings) flags.push('TNodeFlags.hasHostBindings'); if (this.flags & TNodeFlags.isComponentHost) flags.push('TNodeFlags.isComponentHost'); if (this.flags & TNodeFlags.isDirectiveHost) flags.push('TNodeFlags.isDirectiveHost'); if (this.flags & TNodeFlags.isDetached) flags.push('TNodeFlags.isDetached'); diff --git a/packages/core/src/render3/instructions/shared.ts b/packages/core/src/render3/instructions/shared.ts index 2ca04d1a48..5d21b2ba90 100644 --- a/packages/core/src/render3/instructions/shared.ts +++ b/packages/core/src/render3/instructions/shared.ts @@ -536,7 +536,9 @@ export function createDirectivesInstances( tView: TView, lView: LView, tNode: TElementNode | TContainerNode | TElementContainerNode) { if (!getBindingsEnabled()) return; instantiateAllDirectives(tView, lView, tNode); - invokeDirectivesHostBindings(tView, lView, tNode); + if ((tNode.flags & TNodeFlags.hasHostBindings) === TNodeFlags.hasHostBindings) { + invokeDirectivesHostBindings(tView, lView, tNode); + } setActiveHostElement(null); } @@ -1069,9 +1071,8 @@ export function resolveDirectives( saveNameToExportMap(tView.data !.length - 1, def, exportsMap); - if (def.contentQueries) { - tNode.flags |= TNodeFlags.hasContentQuery; - } + if (def.contentQueries !== null) tNode.flags |= TNodeFlags.hasContentQuery; + if (def.hostBindings !== null) tNode.flags |= TNodeFlags.hasHostBindings; // Init hooks are queued now so ngOnInit is called in host components before // any projected components. diff --git a/packages/core/src/render3/interfaces/node.ts b/packages/core/src/render3/interfaces/node.ts index 688784124c..a598252390 100644 --- a/packages/core/src/render3/interfaces/node.ts +++ b/packages/core/src/render3/interfaces/node.ts @@ -46,30 +46,37 @@ export const enum TNodeType { */ export const enum TNodeFlags { /** This bit is set if the node is a host for any directive (including a component) */ - isDirectiveHost = 0b00000001, + isDirectiveHost = 0b000000001, /** * This bit is set if the node is a host for a component. Setting this bit implies that the * isDirectiveHost bit is set as well. */ - isComponentHost = 0b00000010, + isComponentHost = 0b000000010, /** This bit is set if the node has been projected */ - isProjected = 0b00000100, + isProjected = 0b000000100, /** This bit is set if any directive on this node has content queries */ - hasContentQuery = 0b00001000, + hasContentQuery = 0b000001000, /** This bit is set if the node has any "class" inputs */ - hasClassInput = 0b00010000, + hasClassInput = 0b000010000, /** This bit is set if the node has any "style" inputs */ - hasStyleInput = 0b00100000, + hasStyleInput = 0b000100000, /** This bit is set if the node has initial styling */ - hasInitialStyling = 0b01000000, + hasInitialStyling = 0b001000000, /** This bit is set if the node has been detached by i18n */ - isDetached = 0b10000000, + isDetached = 0b010000000, + + /** + * This bit is set if the node has directives with host bindings. This flags allows us to guard + * host-binding logic and invoke it only on nodes that actually have directives with host + * bindings. + */ + hasHostBindings = 0b100000000, } /**