From da0c372fdf67230dea4f5d4df52c55ac6e1938db Mon Sep 17 00:00:00 2001 From: Pawel Kozlowski Date: Wed, 13 Nov 2019 17:06:54 +0100 Subject: [PATCH] perf(ivy): don't store public input names in two places (#33798) Before this change a public name of a directive's input was stored in 2 places: - as a key of an object on TNode.index; - as a value of PropertyAliasValue at the index 1 This PR changes the data structure so the public name is stored only once as a key on TNode.index. This saves one array entry for each and every directive input. PR Close #33798 --- packages/core/src/render3/i18n.ts | 2 +- .../core/src/render3/instructions/element.ts | 8 +++---- .../core/src/render3/instructions/listener.ts | 4 ++-- .../core/src/render3/instructions/shared.ts | 22 +++++++++---------- .../core/src/render3/instructions/styling.ts | 2 +- packages/core/src/render3/interfaces/node.ts | 5 ++--- 6 files changed, 20 insertions(+), 23 deletions(-) diff --git a/packages/core/src/render3/i18n.ts b/packages/core/src/render3/i18n.ts index 29d29b1aee..6244017d64 100644 --- a/packages/core/src/render3/i18n.ts +++ b/packages/core/src/render3/i18n.ts @@ -1021,7 +1021,7 @@ function i18nAttributesFirstPass(lView: LView, tView: TView, index: number, valu // Check if that attribute is a directive input const dataValue = tNode.inputs && tNode.inputs[attrName]; if (dataValue) { - setInputsForProperty(lView, dataValue, value); + setInputsForProperty(lView, dataValue, attrName, value); if (ngDevMode) { const element = getNativeByIndex(previousElementIndex, lView) as RElement | RComment; setNgReflectProperties(lView, element, tNode.type, dataValue, value); diff --git a/packages/core/src/render3/instructions/element.ts b/packages/core/src/render3/instructions/element.ts index 4dda458a90..ba88358a5c 100644 --- a/packages/core/src/render3/instructions/element.ts +++ b/packages/core/src/render3/instructions/element.ts @@ -134,11 +134,11 @@ export function ɵɵelementEnd(): void { if (hasClassInput(tNode)) { const inputName: string = selectClassBasedInputName(tNode.inputs !); - setDirectiveStylingInput(tNode.classes, lView, tNode.inputs ![inputName]); + setDirectiveStylingInput(tNode.classes, lView, tNode.inputs ![inputName], inputName); } if (hasStyleInput(tNode)) { - setDirectiveStylingInput(tNode.styles, lView, tNode.inputs !['style']); + setDirectiveStylingInput(tNode.styles, lView, tNode.inputs !['style'], 'style'); } } @@ -231,7 +231,7 @@ export function ɵɵelementHostAttrs(attrs: TAttributes) { function setDirectiveStylingInput( context: TStylingContext | StylingMapArray | null, lView: LView, - stylingInputs: (string | number)[]) { + stylingInputs: (string | number)[], propName: string) { // older versions of Angular treat the input as `null` in the // event that the value does not exist at all. For this reason // we can't have a styling value be an empty string. @@ -240,7 +240,7 @@ function setDirectiveStylingInput( // Ivy does an extra `[class]` write with a falsy value since the value // is applied during creation mode. This is a deviation from VE and should // be (Jira Issue = FW-1467). - setInputsForProperty(lView, stylingInputs, value); + setInputsForProperty(lView, stylingInputs, propName, value); } function validateElement( diff --git a/packages/core/src/render3/instructions/listener.ts b/packages/core/src/render3/instructions/listener.ts index bb0b02b0d1..c37d28492d 100644 --- a/packages/core/src/render3/instructions/listener.ts +++ b/packages/core/src/render3/instructions/listener.ts @@ -196,10 +196,10 @@ function listenerInternal( const propsLength = props.length; if (propsLength) { const lCleanup = getCleanup(lView); - for (let i = 0; i < propsLength; i += 3) { + for (let i = 0; i < propsLength; i += 2) { const index = props[i] as number; ngDevMode && assertDataInRange(lView, index); - const minifiedName = props[i + 2]; + const minifiedName = props[i + 1]; const directiveInstance = lView[index]; const output = directiveInstance[minifiedName]; diff --git a/packages/core/src/render3/instructions/shared.ts b/packages/core/src/render3/instructions/shared.ts index 85ed47b729..bb3449f376 100644 --- a/packages/core/src/render3/instructions/shared.ts +++ b/packages/core/src/render3/instructions/shared.ts @@ -848,9 +848,9 @@ function generatePropertyAliases( const internalName = inputAliasMap[publicName]; if (propStore.hasOwnProperty(publicName)) { - propStore[publicName].push(directiveDefIdx, publicName, internalName); + propStore[publicName].push(directiveDefIdx, internalName); } else { - (propStore[publicName] = [directiveDefIdx, publicName, internalName]); + (propStore[publicName] = [directiveDefIdx, internalName]); } } } @@ -925,7 +925,7 @@ export function elementPropertyInternal( let inputData = tNode.inputs; let dataValue: PropertyAliasValue|undefined; if (!nativeOnly && inputData != null && (dataValue = inputData[propName])) { - setInputsForProperty(lView, dataValue, value); + setInputsForProperty(lView, dataValue, propName, value); if (isComponentHost(tNode)) markDirtyIfOnPush(lView, index + HEADER_OFFSET); if (ngDevMode) { setNgReflectProperties(lView, element, tNode.type, dataValue, value); @@ -1002,14 +1002,13 @@ export function setNgReflectProperties( /** * dataValue is an array containing runtime input or output names for the directives: * i+0: directive instance index - * i+1: publicName - * i+2: privateName + * i+1: privateName * * e.g. [0, 'change', 'change-minified'] - * we want to set the reflected property with the privateName: dataValue[i+2] + * we want to set the reflected property with the privateName: dataValue[i+1] */ - for (let i = 0; i < dataValue.length; i += 3) { - setNgReflectProperty(lView, element, type, dataValue[i + 2] as string, value); + for (let i = 0; i < dataValue.length; i += 2) { + setNgReflectProperty(lView, element, type, dataValue[i + 1] as string, value); } } } @@ -1864,17 +1863,16 @@ export function handleError(lView: LView, error: any): void { * possibly minified, property names to write to. * @param value Value to set. */ -export function setInputsForProperty(lView: LView, inputs: PropertyAliasValue, value: any): void { +export function setInputsForProperty( + lView: LView, inputs: PropertyAliasValue, publicName: string, value: any): void { const tView = lView[TVIEW]; for (let i = 0; i < inputs.length;) { const index = inputs[i++] as number; - const publicName = inputs[i++] as string; const privateName = inputs[i++] as string; const instance = lView[index]; ngDevMode && assertDataInRange(lView, index); const def = tView.data[index] as DirectiveDef; - const setInput = def.setInput; - if (setInput) { + if (def.setInput !== null) { def.setInput !(instance, value, publicName, privateName); } else { instance[privateName] = value; diff --git a/packages/core/src/render3/instructions/styling.ts b/packages/core/src/render3/instructions/styling.ts index 50a7e05a29..ef3c4b7320 100644 --- a/packages/core/src/render3/instructions/styling.ts +++ b/packages/core/src/render3/instructions/styling.ts @@ -442,7 +442,7 @@ function updateDirectiveInputValue( const inputs = tNode.inputs ![inputName] !; const initialValue = getInitialStylingValue(context); const value = normalizeStylingDirectiveInputValue(initialValue, newValue, isClassBased); - setInputsForProperty(lView, inputs, value); + setInputsForProperty(lView, inputs, inputName, value); setElementExitFn(stylingApply); } setValue(lView, bindingIndex, newValue); diff --git a/packages/core/src/render3/interfaces/node.ts b/packages/core/src/render3/interfaces/node.ts index 316cd3a141..66b2684939 100644 --- a/packages/core/src/render3/interfaces/node.ts +++ b/packages/core/src/render3/interfaces/node.ts @@ -738,10 +738,9 @@ export type PropertyAliases = { * Store the runtime input or output names for all the directives. * * i+0: directive instance index - * i+1: publicName - * i+2: privateName + * i+1: privateName * - * e.g. [0, 'change', 'change-minified'] + * e.g. [0, 'change-minified'] */ export type PropertyAliasValue = (number | string)[];