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
This commit is contained in:
Pawel Kozlowski 2019-10-11 16:38:07 +02:00 committed by Miško Hevery
parent dcca80bb1e
commit d4d07233dc
3 changed files with 21 additions and 12 deletions

View File

@ -164,6 +164,7 @@ export const TNodeConstructor = class TNode implements ITNode {
if (this.flags & TNodeFlags.hasContentQuery) flags.push('TNodeFlags.hasContentQuery'); if (this.flags & TNodeFlags.hasContentQuery) flags.push('TNodeFlags.hasContentQuery');
if (this.flags & TNodeFlags.hasStyleInput) flags.push('TNodeFlags.hasStyleInput'); if (this.flags & TNodeFlags.hasStyleInput) flags.push('TNodeFlags.hasStyleInput');
if (this.flags & TNodeFlags.hasInitialStyling) flags.push('TNodeFlags.hasInitialStyling'); 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.isComponentHost) flags.push('TNodeFlags.isComponentHost');
if (this.flags & TNodeFlags.isDirectiveHost) flags.push('TNodeFlags.isDirectiveHost'); if (this.flags & TNodeFlags.isDirectiveHost) flags.push('TNodeFlags.isDirectiveHost');
if (this.flags & TNodeFlags.isDetached) flags.push('TNodeFlags.isDetached'); if (this.flags & TNodeFlags.isDetached) flags.push('TNodeFlags.isDetached');

View File

@ -536,7 +536,9 @@ export function createDirectivesInstances(
tView: TView, lView: LView, tNode: TElementNode | TContainerNode | TElementContainerNode) { tView: TView, lView: LView, tNode: TElementNode | TContainerNode | TElementContainerNode) {
if (!getBindingsEnabled()) return; if (!getBindingsEnabled()) return;
instantiateAllDirectives(tView, lView, tNode); instantiateAllDirectives(tView, lView, tNode);
if ((tNode.flags & TNodeFlags.hasHostBindings) === TNodeFlags.hasHostBindings) {
invokeDirectivesHostBindings(tView, lView, tNode); invokeDirectivesHostBindings(tView, lView, tNode);
}
setActiveHostElement(null); setActiveHostElement(null);
} }
@ -1069,9 +1071,8 @@ export function resolveDirectives(
saveNameToExportMap(tView.data !.length - 1, def, exportsMap); saveNameToExportMap(tView.data !.length - 1, def, exportsMap);
if (def.contentQueries) { if (def.contentQueries !== null) tNode.flags |= TNodeFlags.hasContentQuery;
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 // Init hooks are queued now so ngOnInit is called in host components before
// any projected components. // any projected components.

View File

@ -46,30 +46,37 @@ export const enum TNodeType {
*/ */
export const enum TNodeFlags { export const enum TNodeFlags {
/** This bit is set if the node is a host for any directive (including a component) */ /** 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 * 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. */ * isDirectiveHost bit is set as well. */
isComponentHost = 0b00000010, isComponentHost = 0b000000010,
/** This bit is set if the node has been projected */ /** 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 */ /** 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 */ /** 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 */ /** 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 */ /** 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 */ /** 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,
} }
/** /**