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
This commit is contained in:
parent
b3549e6680
commit
ffc34b3676
|
@ -360,13 +360,14 @@ const parentIndexStack: number[] = [];
|
||||||
* @codeGenApi
|
* @codeGenApi
|
||||||
*/
|
*/
|
||||||
export function ɵɵi18nStart(index: number, message: string, subTemplateIndex?: number): void {
|
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`);
|
ngDevMode && assertDefined(tView, `tView should be defined`);
|
||||||
i18nIndexStack[++i18nIndexStackPointer] = index;
|
i18nIndexStack[++i18nIndexStackPointer] = index;
|
||||||
// We need to delay projections until `i18nEnd`
|
// We need to delay projections until `i18nEnd`
|
||||||
setDelayProjection(true);
|
setDelayProjection(true);
|
||||||
if (tView.firstTemplatePass && tView.data[index + HEADER_OFFSET] === null) {
|
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.
|
* See `i18nStart` above.
|
||||||
*/
|
*/
|
||||||
function i18nStartFirstPass(
|
function i18nStartFirstPass(
|
||||||
tView: TView, index: number, message: string, subTemplateIndex?: number) {
|
lView: LView, tView: TView, index: number, message: string, subTemplateIndex?: number) {
|
||||||
const viewData = getLView();
|
|
||||||
const startIndex = tView.blueprint.length - HEADER_OFFSET;
|
const startIndex = tView.blueprint.length - HEADER_OFFSET;
|
||||||
i18nVarsCount = 0;
|
i18nVarsCount = 0;
|
||||||
const previousOrParentTNode = getPreviousOrParentTNode();
|
const previousOrParentTNode = getPreviousOrParentTNode();
|
||||||
const parentTNode = getIsParent() ? getPreviousOrParentTNode() :
|
const parentTNode =
|
||||||
previousOrParentTNode && previousOrParentTNode.parent;
|
getIsParent() ? previousOrParentTNode : previousOrParentTNode && previousOrParentTNode.parent;
|
||||||
let parentIndex =
|
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;
|
let parentIndexPointer = 0;
|
||||||
parentIndexStack[parentIndexPointer] = parentIndex;
|
parentIndexStack[parentIndexPointer] = parentIndex;
|
||||||
const createOpCodes: I18nMutateOpCodes = [];
|
const createOpCodes: I18nMutateOpCodes = [];
|
||||||
|
@ -471,12 +471,12 @@ function i18nStartFirstPass(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i18nVarsCount > 0) {
|
if (i18nVarsCount > 0) {
|
||||||
allocExpando(viewData, i18nVarsCount);
|
allocExpando(lView, i18nVarsCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
ngDevMode &&
|
ngDevMode &&
|
||||||
attachI18nOpCodesDebug(
|
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`.
|
// NOTE: local var needed to properly assert the type of `TI18n`.
|
||||||
const tI18n: TI18n = {
|
const tI18n: TI18n = {
|
||||||
|
@ -656,9 +656,10 @@ export function ɵɵi18nPostprocess(
|
||||||
* @codeGenApi
|
* @codeGenApi
|
||||||
*/
|
*/
|
||||||
export function ɵɵi18nEnd(): void {
|
export function ɵɵi18nEnd(): void {
|
||||||
const tView = getLView()[TVIEW];
|
const lView = getLView();
|
||||||
|
const tView = lView[TVIEW];
|
||||||
ngDevMode && assertDefined(tView, `tView should be defined`);
|
ngDevMode && assertDefined(tView, `tView should be defined`);
|
||||||
i18nEndFirstPass(tView);
|
i18nEndFirstPass(lView, tView);
|
||||||
// Stop delaying projections
|
// Stop delaying projections
|
||||||
setDelayProjection(false);
|
setDelayProjection(false);
|
||||||
}
|
}
|
||||||
|
@ -666,10 +667,9 @@ export function ɵɵi18nEnd(): void {
|
||||||
/**
|
/**
|
||||||
* See `i18nEnd` above.
|
* See `i18nEnd` above.
|
||||||
*/
|
*/
|
||||||
function i18nEndFirstPass(tView: TView) {
|
function i18nEndFirstPass(lView: LView, tView: TView) {
|
||||||
const viewData = getLView();
|
|
||||||
ngDevMode && assertEqual(
|
ngDevMode && assertEqual(
|
||||||
viewData[BINDING_INDEX], viewData[TVIEW].bindingStartIndex,
|
lView[BINDING_INDEX], tView.bindingStartIndex,
|
||||||
'i18nEnd should be called before any binding');
|
'i18nEnd should be called before any binding');
|
||||||
|
|
||||||
const rootIndex = i18nIndexStack[i18nIndexStackPointer--];
|
const rootIndex = i18nIndexStack[i18nIndexStackPointer--];
|
||||||
|
@ -677,15 +677,15 @@ function i18nEndFirstPass(tView: TView) {
|
||||||
ngDevMode && assertDefined(tI18n, `You should call i18nStart before i18nEnd`);
|
ngDevMode && assertDefined(tI18n, `You should call i18nStart before i18nEnd`);
|
||||||
|
|
||||||
// Find the last node that was added 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
|
// 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
|
// Remove deleted nodes
|
||||||
for (let i = rootIndex + 1; i <= lastCreatedNode.index - HEADER_OFFSET; i++) {
|
for (let i = rootIndex + 1; i <= lastCreatedNode.index - HEADER_OFFSET; i++) {
|
||||||
if (visitedNodes.indexOf(i) === -1) {
|
if (visitedNodes.indexOf(i) === -1) {
|
||||||
removeNode(i, viewData, /* markAsDetached */ true);
|
removeNode(i, lView, /* markAsDetached */ true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -711,9 +711,8 @@ function createDynamicNodeAtIndex(
|
||||||
}
|
}
|
||||||
|
|
||||||
function readCreateOpCodes(
|
function readCreateOpCodes(
|
||||||
index: number, createOpCodes: I18nMutateOpCodes, icus: TIcu[] | null,
|
index: number, createOpCodes: I18nMutateOpCodes, lView: LView): number[] {
|
||||||
viewData: LView): number[] {
|
const renderer = lView[RENDERER];
|
||||||
const renderer = getLView()[RENDERER];
|
|
||||||
let currentTNode: TNode|null = null;
|
let currentTNode: TNode|null = null;
|
||||||
let previousTNode: TNode|null = null;
|
let previousTNode: TNode|null = null;
|
||||||
const visitedNodes: number[] = [];
|
const visitedNodes: number[] = [];
|
||||||
|
@ -725,7 +724,7 @@ function readCreateOpCodes(
|
||||||
ngDevMode && ngDevMode.rendererCreateTextNode++;
|
ngDevMode && ngDevMode.rendererCreateTextNode++;
|
||||||
previousTNode = currentTNode;
|
previousTNode = currentTNode;
|
||||||
currentTNode =
|
currentTNode =
|
||||||
createDynamicNodeAtIndex(viewData, textNodeIndex, TNodeType.Element, textRNode, null);
|
createDynamicNodeAtIndex(lView, textNodeIndex, TNodeType.Element, textRNode, null);
|
||||||
visitedNodes.push(textNodeIndex);
|
visitedNodes.push(textNodeIndex);
|
||||||
setIsNotParent();
|
setIsNotParent();
|
||||||
} else if (typeof opCode == 'number') {
|
} else if (typeof opCode == 'number') {
|
||||||
|
@ -736,28 +735,28 @@ function readCreateOpCodes(
|
||||||
if (destinationNodeIndex === index) {
|
if (destinationNodeIndex === index) {
|
||||||
// If the destination node is `i18nStart`, we don't have a
|
// If the destination node is `i18nStart`, we don't have a
|
||||||
// top-level node and we should use the host node instead
|
// top-level node and we should use the host node instead
|
||||||
destinationTNode = viewData[T_HOST] !;
|
destinationTNode = lView[T_HOST] !;
|
||||||
} else {
|
} else {
|
||||||
destinationTNode = getTNode(destinationNodeIndex, viewData);
|
destinationTNode = getTNode(destinationNodeIndex, lView);
|
||||||
}
|
}
|
||||||
ngDevMode &&
|
ngDevMode &&
|
||||||
assertDefined(
|
assertDefined(
|
||||||
currentTNode !,
|
currentTNode !,
|
||||||
`You need to create or select a node before you can insert it into the DOM`);
|
`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;
|
break;
|
||||||
case I18nMutateOpCode.Select:
|
case I18nMutateOpCode.Select:
|
||||||
const nodeIndex = opCode >>> I18nMutateOpCode.SHIFT_REF;
|
const nodeIndex = opCode >>> I18nMutateOpCode.SHIFT_REF;
|
||||||
visitedNodes.push(nodeIndex);
|
visitedNodes.push(nodeIndex);
|
||||||
previousTNode = currentTNode;
|
previousTNode = currentTNode;
|
||||||
currentTNode = getTNode(nodeIndex, viewData);
|
currentTNode = getTNode(nodeIndex, lView);
|
||||||
if (currentTNode) {
|
if (currentTNode) {
|
||||||
setPreviousOrParentTNode(currentTNode, currentTNode.type === TNodeType.Element);
|
setPreviousOrParentTNode(currentTNode, currentTNode.type === TNodeType.Element);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case I18nMutateOpCode.ElementEnd:
|
case I18nMutateOpCode.ElementEnd:
|
||||||
const elementIndex = opCode >>> I18nMutateOpCode.SHIFT_REF;
|
const elementIndex = opCode >>> I18nMutateOpCode.SHIFT_REF;
|
||||||
previousTNode = currentTNode = getTNode(elementIndex, viewData);
|
previousTNode = currentTNode = getTNode(elementIndex, lView);
|
||||||
setPreviousOrParentTNode(currentTNode, false);
|
setPreviousOrParentTNode(currentTNode, false);
|
||||||
break;
|
break;
|
||||||
case I18nMutateOpCode.Attr:
|
case I18nMutateOpCode.Attr:
|
||||||
|
@ -766,7 +765,7 @@ function readCreateOpCodes(
|
||||||
const attrValue = createOpCodes[++i] as string;
|
const attrValue = createOpCodes[++i] as string;
|
||||||
// This code is used for ICU expressions only, since we don't support
|
// 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
|
// directives/components in ICUs, we don't need to worry about inputs here
|
||||||
elementAttributeInternal(elementNodeIndex, attrName, attrValue, viewData);
|
elementAttributeInternal(elementNodeIndex, attrName, attrValue, lView);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Error(`Unable to determine the type of mutate operation for "${opCode}"`);
|
throw new Error(`Unable to determine the type of mutate operation for "${opCode}"`);
|
||||||
|
@ -783,9 +782,9 @@ function readCreateOpCodes(
|
||||||
ngDevMode && ngDevMode.rendererCreateComment++;
|
ngDevMode && ngDevMode.rendererCreateComment++;
|
||||||
previousTNode = currentTNode;
|
previousTNode = currentTNode;
|
||||||
currentTNode = createDynamicNodeAtIndex(
|
currentTNode = createDynamicNodeAtIndex(
|
||||||
viewData, commentNodeIndex, TNodeType.IcuContainer, commentRNode, null);
|
lView, commentNodeIndex, TNodeType.IcuContainer, commentRNode, null);
|
||||||
visitedNodes.push(commentNodeIndex);
|
visitedNodes.push(commentNodeIndex);
|
||||||
attachPatchData(commentRNode, viewData);
|
attachPatchData(commentRNode, lView);
|
||||||
(currentTNode as TIcuContainerNode).activeCaseIndex = null;
|
(currentTNode as TIcuContainerNode).activeCaseIndex = null;
|
||||||
// We will add the case nodes later, during the update phase
|
// We will add the case nodes later, during the update phase
|
||||||
setIsNotParent();
|
setIsNotParent();
|
||||||
|
@ -800,7 +799,7 @@ function readCreateOpCodes(
|
||||||
ngDevMode && ngDevMode.rendererCreateElement++;
|
ngDevMode && ngDevMode.rendererCreateElement++;
|
||||||
previousTNode = currentTNode;
|
previousTNode = currentTNode;
|
||||||
currentTNode = createDynamicNodeAtIndex(
|
currentTNode = createDynamicNodeAtIndex(
|
||||||
viewData, elementNodeIndex, TNodeType.Element, elementRNode, tagNameValue);
|
lView, elementNodeIndex, TNodeType.Element, elementRNode, tagNameValue);
|
||||||
visitedNodes.push(elementNodeIndex);
|
visitedNodes.push(elementNodeIndex);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -886,7 +885,7 @@ function readUpdateOpCodes(
|
||||||
icuTNode.activeCaseIndex = caseIndex !== -1 ? caseIndex : null;
|
icuTNode.activeCaseIndex = caseIndex !== -1 ? caseIndex : null;
|
||||||
|
|
||||||
// Add the nodes for the new case
|
// Add the nodes for the new case
|
||||||
readCreateOpCodes(-1, tIcu.create[caseIndex], icus, viewData);
|
readCreateOpCodes(-1, tIcu.create[caseIndex], viewData);
|
||||||
caseCreated = true;
|
caseCreated = true;
|
||||||
break;
|
break;
|
||||||
case I18nUpdateOpCode.IcuUpdate:
|
case I18nUpdateOpCode.IcuUpdate:
|
||||||
|
@ -968,15 +967,16 @@ export function ɵɵi18n(index: number, message: string, subTemplateIndex?: numb
|
||||||
* @codeGenApi
|
* @codeGenApi
|
||||||
*/
|
*/
|
||||||
export function ɵɵi18nAttributes(index: number, values: string[]): void {
|
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`);
|
ngDevMode && assertDefined(tView, `tView should be defined`);
|
||||||
i18nAttributesFirstPass(tView, index, values);
|
i18nAttributesFirstPass(lView, tView, index, values);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* See `i18nAttributes` above.
|
* 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 previousElement = getPreviousOrParentTNode();
|
||||||
const previousElementIndex = previousElement.index - HEADER_OFFSET;
|
const previousElementIndex = previousElement.index - HEADER_OFFSET;
|
||||||
const updateOpCodes: I18nUpdateOpCodes = [];
|
const updateOpCodes: I18nUpdateOpCodes = [];
|
||||||
|
@ -1000,7 +1000,6 @@ function i18nAttributesFirstPass(tView: TView, index: number, values: string[])
|
||||||
generateBindingUpdateOpCodes(value, previousElementIndex, attrName), updateOpCodes);
|
generateBindingUpdateOpCodes(value, previousElementIndex, attrName), updateOpCodes);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const lView = getLView();
|
|
||||||
elementAttributeInternal(previousElementIndex, attrName, value, lView);
|
elementAttributeInternal(previousElementIndex, attrName, value, lView);
|
||||||
// Check if that attribute is a directive input
|
// Check if that attribute is a directive input
|
||||||
const tNode = getTNode(previousElementIndex, lView);
|
const tNode = getTNode(previousElementIndex, lView);
|
||||||
|
|
Loading…
Reference in New Issue