From ffc34b367693bf7a9a8b445e77105d280890bf40 Mon Sep 17 00:00:00 2001 From: crisbeto Date: Mon, 30 Sep 2019 19:31:52 +0200 Subject: [PATCH] perf(ivy): avoid repeat global state accesses in i18n instructions (#32916) Removes repeat global state accesses from the i18n instructions in the cases where we have the information available already. PR Close #32916 --- packages/core/src/render3/i18n.ts | 69 +++++++++++++++---------------- 1 file changed, 34 insertions(+), 35 deletions(-) diff --git a/packages/core/src/render3/i18n.ts b/packages/core/src/render3/i18n.ts index fcf5461bd6..1fcea56815 100644 --- a/packages/core/src/render3/i18n.ts +++ b/packages/core/src/render3/i18n.ts @@ -360,13 +360,14 @@ const parentIndexStack: number[] = []; * @codeGenApi */ export function ɵɵi18nStart(index: number, message: string, subTemplateIndex?: number): void { - const tView = getLView()[TVIEW]; + const lView = getLView(); + const tView = lView[TVIEW]; ngDevMode && assertDefined(tView, `tView should be defined`); i18nIndexStack[++i18nIndexStackPointer] = index; // We need to delay projections until `i18nEnd` setDelayProjection(true); if (tView.firstTemplatePass && tView.data[index + HEADER_OFFSET] === null) { - i18nStartFirstPass(tView, index, message, subTemplateIndex); + i18nStartFirstPass(lView, tView, index, message, subTemplateIndex); } } @@ -379,15 +380,14 @@ let i18nVarsCount: number; * See `i18nStart` above. */ function i18nStartFirstPass( - tView: TView, index: number, message: string, subTemplateIndex?: number) { - const viewData = getLView(); + lView: LView, tView: TView, index: number, message: string, subTemplateIndex?: number) { const startIndex = tView.blueprint.length - HEADER_OFFSET; i18nVarsCount = 0; const previousOrParentTNode = getPreviousOrParentTNode(); - const parentTNode = getIsParent() ? getPreviousOrParentTNode() : - previousOrParentTNode && previousOrParentTNode.parent; + const parentTNode = + getIsParent() ? previousOrParentTNode : previousOrParentTNode && previousOrParentTNode.parent; let parentIndex = - parentTNode && parentTNode !== viewData[T_HOST] ? parentTNode.index - HEADER_OFFSET : index; + parentTNode && parentTNode !== lView[T_HOST] ? parentTNode.index - HEADER_OFFSET : index; let parentIndexPointer = 0; parentIndexStack[parentIndexPointer] = parentIndex; const createOpCodes: I18nMutateOpCodes = []; @@ -471,12 +471,12 @@ function i18nStartFirstPass( } if (i18nVarsCount > 0) { - allocExpando(viewData, i18nVarsCount); + allocExpando(lView, i18nVarsCount); } ngDevMode && attachI18nOpCodesDebug( - createOpCodes, updateOpCodes, icuExpressions.length ? icuExpressions : null, viewData); + createOpCodes, updateOpCodes, icuExpressions.length ? icuExpressions : null, lView); // NOTE: local var needed to properly assert the type of `TI18n`. const tI18n: TI18n = { @@ -656,9 +656,10 @@ export function ɵɵi18nPostprocess( * @codeGenApi */ export function ɵɵi18nEnd(): void { - const tView = getLView()[TVIEW]; + const lView = getLView(); + const tView = lView[TVIEW]; ngDevMode && assertDefined(tView, `tView should be defined`); - i18nEndFirstPass(tView); + i18nEndFirstPass(lView, tView); // Stop delaying projections setDelayProjection(false); } @@ -666,10 +667,9 @@ export function ɵɵi18nEnd(): void { /** * See `i18nEnd` above. */ -function i18nEndFirstPass(tView: TView) { - const viewData = getLView(); +function i18nEndFirstPass(lView: LView, tView: TView) { ngDevMode && assertEqual( - viewData[BINDING_INDEX], viewData[TVIEW].bindingStartIndex, + lView[BINDING_INDEX], tView.bindingStartIndex, 'i18nEnd should be called before any binding'); const rootIndex = i18nIndexStack[i18nIndexStackPointer--]; @@ -677,15 +677,15 @@ function i18nEndFirstPass(tView: TView) { ngDevMode && assertDefined(tI18n, `You should call i18nStart before i18nEnd`); // Find the last node that was added before `i18nEnd` - let lastCreatedNode = getPreviousOrParentTNode(); + const lastCreatedNode = getPreviousOrParentTNode(); // Read the instructions to insert/move/remove DOM elements - const visitedNodes = readCreateOpCodes(rootIndex, tI18n.create, tI18n.icus, viewData); + const visitedNodes = readCreateOpCodes(rootIndex, tI18n.create, lView); // Remove deleted nodes for (let i = rootIndex + 1; i <= lastCreatedNode.index - HEADER_OFFSET; i++) { if (visitedNodes.indexOf(i) === -1) { - removeNode(i, viewData, /* markAsDetached */ true); + removeNode(i, lView, /* markAsDetached */ true); } } } @@ -711,9 +711,8 @@ function createDynamicNodeAtIndex( } function readCreateOpCodes( - index: number, createOpCodes: I18nMutateOpCodes, icus: TIcu[] | null, - viewData: LView): number[] { - const renderer = getLView()[RENDERER]; + index: number, createOpCodes: I18nMutateOpCodes, lView: LView): number[] { + const renderer = lView[RENDERER]; let currentTNode: TNode|null = null; let previousTNode: TNode|null = null; const visitedNodes: number[] = []; @@ -725,7 +724,7 @@ function readCreateOpCodes( ngDevMode && ngDevMode.rendererCreateTextNode++; previousTNode = currentTNode; currentTNode = - createDynamicNodeAtIndex(viewData, textNodeIndex, TNodeType.Element, textRNode, null); + createDynamicNodeAtIndex(lView, textNodeIndex, TNodeType.Element, textRNode, null); visitedNodes.push(textNodeIndex); setIsNotParent(); } else if (typeof opCode == 'number') { @@ -736,28 +735,28 @@ function readCreateOpCodes( if (destinationNodeIndex === index) { // If the destination node is `i18nStart`, we don't have a // top-level node and we should use the host node instead - destinationTNode = viewData[T_HOST] !; + destinationTNode = lView[T_HOST] !; } else { - destinationTNode = getTNode(destinationNodeIndex, viewData); + destinationTNode = getTNode(destinationNodeIndex, lView); } ngDevMode && assertDefined( currentTNode !, `You need to create or select a node before you can insert it into the DOM`); - previousTNode = appendI18nNode(currentTNode !, destinationTNode, previousTNode, viewData); + previousTNode = appendI18nNode(currentTNode !, destinationTNode, previousTNode, lView); break; case I18nMutateOpCode.Select: const nodeIndex = opCode >>> I18nMutateOpCode.SHIFT_REF; visitedNodes.push(nodeIndex); previousTNode = currentTNode; - currentTNode = getTNode(nodeIndex, viewData); + currentTNode = getTNode(nodeIndex, lView); if (currentTNode) { setPreviousOrParentTNode(currentTNode, currentTNode.type === TNodeType.Element); } break; case I18nMutateOpCode.ElementEnd: const elementIndex = opCode >>> I18nMutateOpCode.SHIFT_REF; - previousTNode = currentTNode = getTNode(elementIndex, viewData); + previousTNode = currentTNode = getTNode(elementIndex, lView); setPreviousOrParentTNode(currentTNode, false); break; case I18nMutateOpCode.Attr: @@ -766,7 +765,7 @@ function readCreateOpCodes( const attrValue = createOpCodes[++i] as string; // This code is used for ICU expressions only, since we don't support // directives/components in ICUs, we don't need to worry about inputs here - elementAttributeInternal(elementNodeIndex, attrName, attrValue, viewData); + elementAttributeInternal(elementNodeIndex, attrName, attrValue, lView); break; default: throw new Error(`Unable to determine the type of mutate operation for "${opCode}"`); @@ -783,9 +782,9 @@ function readCreateOpCodes( ngDevMode && ngDevMode.rendererCreateComment++; previousTNode = currentTNode; currentTNode = createDynamicNodeAtIndex( - viewData, commentNodeIndex, TNodeType.IcuContainer, commentRNode, null); + lView, commentNodeIndex, TNodeType.IcuContainer, commentRNode, null); visitedNodes.push(commentNodeIndex); - attachPatchData(commentRNode, viewData); + attachPatchData(commentRNode, lView); (currentTNode as TIcuContainerNode).activeCaseIndex = null; // We will add the case nodes later, during the update phase setIsNotParent(); @@ -800,7 +799,7 @@ function readCreateOpCodes( ngDevMode && ngDevMode.rendererCreateElement++; previousTNode = currentTNode; currentTNode = createDynamicNodeAtIndex( - viewData, elementNodeIndex, TNodeType.Element, elementRNode, tagNameValue); + lView, elementNodeIndex, TNodeType.Element, elementRNode, tagNameValue); visitedNodes.push(elementNodeIndex); break; default: @@ -886,7 +885,7 @@ function readUpdateOpCodes( icuTNode.activeCaseIndex = caseIndex !== -1 ? caseIndex : null; // Add the nodes for the new case - readCreateOpCodes(-1, tIcu.create[caseIndex], icus, viewData); + readCreateOpCodes(-1, tIcu.create[caseIndex], viewData); caseCreated = true; break; case I18nUpdateOpCode.IcuUpdate: @@ -968,15 +967,16 @@ export function ɵɵi18n(index: number, message: string, subTemplateIndex?: numb * @codeGenApi */ export function ɵɵi18nAttributes(index: number, values: string[]): void { - const tView = getLView()[TVIEW]; + const lView = getLView(); + const tView = lView[TVIEW]; ngDevMode && assertDefined(tView, `tView should be defined`); - i18nAttributesFirstPass(tView, index, values); + i18nAttributesFirstPass(lView, tView, index, values); } /** * See `i18nAttributes` above. */ -function i18nAttributesFirstPass(tView: TView, index: number, values: string[]) { +function i18nAttributesFirstPass(lView: LView, tView: TView, index: number, values: string[]) { const previousElement = getPreviousOrParentTNode(); const previousElementIndex = previousElement.index - HEADER_OFFSET; const updateOpCodes: I18nUpdateOpCodes = []; @@ -1000,7 +1000,6 @@ function i18nAttributesFirstPass(tView: TView, index: number, values: string[]) generateBindingUpdateOpCodes(value, previousElementIndex, attrName), updateOpCodes); } } else { - const lView = getLView(); elementAttributeInternal(previousElementIndex, attrName, value, lView); // Check if that attribute is a directive input const tNode = getTNode(previousElementIndex, lView);