perf(ivy): replace select instruction with advance (#32516)
Replaces the `select` instruction with a new one called `advance`. Instead of the jumping to a specific index, the new instruction goes forward X amount of elements. The advantage of doing this is that it should generate code the compresses better. PR Close #32516
This commit is contained in:
@ -92,7 +92,7 @@ GreetComponent.ngComponentDef = i0.ɵɵdefineComponent({
|
||||
i0.ɵɵelementEnd();
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
i0.ɵɵselect(1);
|
||||
i0.ɵɵadvance(1);
|
||||
i0.ɵɵtextInterpolate1('Hello ', ctx.name, '!');
|
||||
}
|
||||
}
|
||||
|
@ -30,6 +30,7 @@ export class Identifiers {
|
||||
static elementEnd: o.ExternalReference = {name: 'ɵɵelementEnd', moduleName: CORE};
|
||||
|
||||
static select: o.ExternalReference = {name: 'ɵɵselect', moduleName: CORE};
|
||||
static advance: o.ExternalReference = {name: 'ɵɵadvance', moduleName: CORE};
|
||||
|
||||
static updateSyntheticHostBinding:
|
||||
o.ExternalReference = {name: 'ɵɵupdateSyntheticHostBinding', moduleName: CORE};
|
||||
|
@ -114,12 +114,10 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
|
||||
* all local refs and context variables are available for matching.
|
||||
*/
|
||||
private _updateCodeFns: (() => o.Statement)[] = [];
|
||||
/**
|
||||
* Memorizes the last node index for which a select instruction has been generated.
|
||||
* We're initializing this to -1 to ensure the `select(0)` instruction is generated before any
|
||||
* relevant update instructions.
|
||||
*/
|
||||
private _lastNodeIndexWithFlush: number = -1;
|
||||
|
||||
/** Index of the currently-selected node. */
|
||||
private _currentIndex: number = 0;
|
||||
|
||||
/** Temporary variable declarations generated from visiting pipes, literals, etc. */
|
||||
private _tempVariables: o.Statement[] = [];
|
||||
/**
|
||||
@ -457,8 +455,8 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
|
||||
bindings.forEach(binding => {
|
||||
chainBindings.push({sourceSpan: span, value: () => this.convertPropertyBinding(binding)});
|
||||
});
|
||||
this.updateInstructionChain(index, R3.i18nExp, chainBindings);
|
||||
this.updateInstruction(index, span, R3.i18nApply, [o.literal(index)]);
|
||||
this.updateInstructionChain(R3.i18nExp, chainBindings);
|
||||
this.updateInstruction(span, R3.i18nApply, [o.literal(index)]);
|
||||
}
|
||||
if (!selfClosing) {
|
||||
this.creationInstruction(span, R3.i18nEnd);
|
||||
@ -489,7 +487,7 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
|
||||
private interpolatedUpdateInstruction(
|
||||
instruction: o.ExternalReference, elementIndex: number, attrName: string,
|
||||
input: t.BoundAttribute, value: any, params: any[]) {
|
||||
this.updateInstruction(
|
||||
this.updateInstructionWithAdvance(
|
||||
elementIndex, input.sourceSpan, instruction,
|
||||
() => [o.literal(attrName), ...this.getUpdateInstructionArguments(value), ...params]);
|
||||
}
|
||||
@ -671,14 +669,14 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
|
||||
}
|
||||
});
|
||||
if (bindings.length) {
|
||||
this.updateInstructionChain(elementIndex, R3.i18nExp, bindings);
|
||||
this.updateInstructionChain(R3.i18nExp, bindings);
|
||||
}
|
||||
if (i18nAttrArgs.length) {
|
||||
const index: o.Expression = o.literal(this.allocateDataSlot());
|
||||
const args = this.constantPool.getConstLiteral(o.literalArr(i18nAttrArgs), true);
|
||||
this.creationInstruction(element.sourceSpan, R3.i18nAttributes, [index, args]);
|
||||
if (hasBindings) {
|
||||
this.updateInstruction(elementIndex, element.sourceSpan, R3.i18nApply, [index]);
|
||||
this.updateInstruction(element.sourceSpan, R3.i18nApply, [index]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -806,7 +804,7 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
|
||||
}
|
||||
} else {
|
||||
// class prop
|
||||
this.updateInstruction(elementIndex, input.sourceSpan, R3.classProp, () => {
|
||||
this.updateInstructionWithAdvance(elementIndex, input.sourceSpan, R3.classProp, () => {
|
||||
return [
|
||||
o.literal(elementIndex), o.literal(attrName), this.convertPropertyBinding(value),
|
||||
...params
|
||||
@ -818,11 +816,11 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
|
||||
});
|
||||
|
||||
if (propertyBindings.length > 0) {
|
||||
this.updateInstructionChain(elementIndex, R3.property, propertyBindings);
|
||||
this.updateInstructionChainWithAdvance(elementIndex, R3.property, propertyBindings);
|
||||
}
|
||||
|
||||
if (attributeBindings.length > 0) {
|
||||
this.updateInstructionChain(elementIndex, R3.attribute, attributeBindings);
|
||||
this.updateInstructionChainWithAdvance(elementIndex, R3.attribute, attributeBindings);
|
||||
}
|
||||
|
||||
// Traverse element child nodes
|
||||
@ -954,7 +952,7 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
|
||||
this.allocateBindingSlots(value);
|
||||
|
||||
if (value instanceof Interpolation) {
|
||||
this.updateInstruction(
|
||||
this.updateInstructionWithAdvance(
|
||||
nodeIndex, text.sourceSpan, getTextInterpolationExpression(value),
|
||||
() => this.getUpdateInstructionArguments(value));
|
||||
} else {
|
||||
@ -1054,7 +1052,7 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
|
||||
});
|
||||
|
||||
if (propertyBindings.length > 0) {
|
||||
this.updateInstructionChain(templateIndex, R3.property, propertyBindings);
|
||||
this.updateInstructionChainWithAdvance(templateIndex, R3.property, propertyBindings);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1079,14 +1077,15 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
|
||||
return instruction.params(value => this.convertPropertyBinding(value)) as o.Expression[];
|
||||
});
|
||||
} else {
|
||||
this.updateInstruction(elementIndex, instruction.sourceSpan, instruction.reference, () => {
|
||||
return instruction
|
||||
.params(value => {
|
||||
return (instruction.supportsInterpolation && value instanceof Interpolation) ?
|
||||
this.getUpdateInstructionArguments(value) :
|
||||
this.convertPropertyBinding(value);
|
||||
}) as o.Expression[];
|
||||
});
|
||||
this.updateInstructionWithAdvance(
|
||||
elementIndex, instruction.sourceSpan, instruction.reference, () => {
|
||||
return instruction
|
||||
.params(value => {
|
||||
return (instruction.supportsInterpolation && value instanceof Interpolation) ?
|
||||
this.getUpdateInstructionArguments(value) :
|
||||
this.convertPropertyBinding(value);
|
||||
}) as o.Expression[];
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1097,18 +1096,23 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
|
||||
this.instructionFn(this._creationCodeFns, span, reference, paramsOrFn || [], prepend);
|
||||
}
|
||||
|
||||
private updateInstruction(
|
||||
private updateInstructionWithAdvance(
|
||||
nodeIndex: number, span: ParseSourceSpan|null, reference: o.ExternalReference,
|
||||
paramsOrFn?: o.Expression[]|(() => o.Expression[])) {
|
||||
this.addSelectInstructionIfNecessary(nodeIndex, span);
|
||||
this.addAdvanceInstructionIfNecessary(nodeIndex, span);
|
||||
this.updateInstruction(span, reference, paramsOrFn);
|
||||
}
|
||||
|
||||
private updateInstruction(
|
||||
span: ParseSourceSpan|null, reference: o.ExternalReference,
|
||||
paramsOrFn?: o.Expression[]|(() => o.Expression[])) {
|
||||
this.instructionFn(this._updateCodeFns, span, reference, paramsOrFn || []);
|
||||
}
|
||||
|
||||
private updateInstructionChain(
|
||||
nodeIndex: number, reference: o.ExternalReference, bindings: ChainableBindingInstruction[]) {
|
||||
reference: o.ExternalReference, bindings: ChainableBindingInstruction[]) {
|
||||
const span = bindings.length ? bindings[0].sourceSpan : null;
|
||||
|
||||
this.addSelectInstructionIfNecessary(nodeIndex, span);
|
||||
this._updateCodeFns.push(() => {
|
||||
const calls = bindings.map(property => {
|
||||
const fnParams = [property.value(), ...(property.params || [])];
|
||||
@ -1122,12 +1126,23 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
|
||||
});
|
||||
}
|
||||
|
||||
private addSelectInstructionIfNecessary(nodeIndex: number, span: ParseSourceSpan|null) {
|
||||
if (this._lastNodeIndexWithFlush < nodeIndex) {
|
||||
if (nodeIndex > 0) {
|
||||
this.instructionFn(this._updateCodeFns, span, R3.select, [o.literal(nodeIndex)]);
|
||||
private updateInstructionChainWithAdvance(
|
||||
nodeIndex: number, reference: o.ExternalReference, bindings: ChainableBindingInstruction[]) {
|
||||
this.addAdvanceInstructionIfNecessary(
|
||||
nodeIndex, bindings.length ? bindings[0].sourceSpan : null);
|
||||
this.updateInstructionChain(reference, bindings);
|
||||
}
|
||||
|
||||
private addAdvanceInstructionIfNecessary(nodeIndex: number, span: ParseSourceSpan|null) {
|
||||
if (nodeIndex !== this._currentIndex) {
|
||||
const delta = nodeIndex - this._currentIndex;
|
||||
|
||||
if (delta < 1) {
|
||||
throw new Error('advance instruction can only go forwards');
|
||||
}
|
||||
this._lastNodeIndexWithFlush = nodeIndex;
|
||||
|
||||
this.instructionFn(this._updateCodeFns, span, R3.advance, [o.literal(delta)]);
|
||||
this._currentIndex = nodeIndex;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2037,4 +2052,4 @@ export function getTranslationDeclStmts(
|
||||
}
|
||||
|
||||
return statements;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user