perf(ivy): chain multiple `i18nExp` calls (#31258)

Implement function chaining for `i18nExp` to reduce the output size.

FW-1391 #resolve
PR Close #31258
This commit is contained in:
Olivier Combe 2019-06-25 17:14:07 +02:00 committed by Kara Erickson
parent 3846192bde
commit ef9cb6a034
4 changed files with 54 additions and 76 deletions

View File

@ -464,14 +464,10 @@ describe('i18n support in the view compiler', () => {
$r3$.ɵɵelementEnd();
}
if (rf & 2) {
$r3$.ɵɵi18nExp($r3$.ɵɵpipeBind1(1, 6, ctx.valueA));
$r3$.ɵɵi18nExp(ctx.valueB);
$r3$.ɵɵi18nExp($r3$.ɵɵpipeBind1(1, 6, ctx.valueA))(ctx.valueB);
$r3$.ɵɵi18nApply(2);
$r3$.ɵɵselect(3);
$r3$.ɵɵi18nExp(ctx.valueA);
$r3$.ɵɵi18nExp(ctx.valueB);
$r3$.ɵɵi18nExp(ctx.valueA + ctx.valueB);
$r3$.ɵɵi18nExp(ctx.valueC);
$r3$.ɵɵi18nExp(ctx.valueA)(ctx.valueB)(ctx.valueA + ctx.valueB)(ctx.valueC);
$r3$.ɵɵi18nApply(4);
}
}
@ -690,14 +686,10 @@ describe('i18n support in the view compiler', () => {
$r3$.ɵɵelementEnd();
}
if (rf & 2) {
$r3$.ɵɵi18nExp($r3$.ɵɵpipeBind1(1, 6, ctx.valueA));
$r3$.ɵɵi18nExp(ctx.valueB);
$r3$.ɵɵi18nExp($r3$.ɵɵpipeBind1(1, 6, ctx.valueA))(ctx.valueB);
$r3$.ɵɵi18nApply(2);
$r3$.ɵɵselect(3);
$r3$.ɵɵi18nExp(ctx.valueA);
$r3$.ɵɵi18nExp(ctx.valueB);
$r3$.ɵɵi18nExp(ctx.valueA + ctx.valueB);
$r3$.ɵɵi18nExp(ctx.valueC);
$r3$.ɵɵi18nExp(ctx.valueA)(ctx.valueB)(ctx.valueA + ctx.valueB)(ctx.valueC);
$r3$.ɵɵi18nApply(4);
}
}
@ -1054,8 +1046,7 @@ describe('i18n support in the view compiler', () => {
}
if (rf & 2) {
$r3$.ɵɵselect(1);
$r3$.ɵɵi18nExp($r3$.ɵɵpipeBind1(2, 2, ctx.valueA));
$r3$.ɵɵi18nExp(ctx.valueA == null ? null : ctx.valueA.a == null ? null : ctx.valueA.a.b);
$r3$.ɵɵi18nExp($r3$.ɵɵpipeBind1(2, 2, ctx.valueA))(ctx.valueA == null ? null : ctx.valueA.a == null ? null : ctx.valueA.a.b);
$r3$.ɵɵi18nApply(1);
}
}
@ -1224,8 +1215,7 @@ describe('i18n support in the view compiler', () => {
$r3$.ɵɵi18nExp(ctx.one);
$r3$.ɵɵi18nApply(1);
$r3$.ɵɵselect(4);
$r3$.ɵɵi18nExp($r3$.ɵɵpipeBind1(5, 3, ctx.two));
$r3$.ɵɵi18nExp(ctx.nestedInBlockTwo);
$r3$.ɵɵi18nExp($r3$.ɵɵpipeBind1(5, 3, ctx.two))(ctx.nestedInBlockTwo);
$r3$.ɵɵi18nApply(4);
}
}
@ -1335,8 +1325,7 @@ describe('i18n support in the view compiler', () => {
}
if (rf & 2) {
$r3$.ɵɵselect(2);
$r3$.ɵɵi18nExp(ctx.valueB);
$r3$.ɵɵi18nExp(ctx.valueC);
$r3$.ɵɵi18nExp(ctx.valueB)(ctx.valueC);
$r3$.ɵɵi18nApply(3);
$r3$.ɵɵi18nExp(ctx.valueA);
$r3$.ɵɵi18nApply(1);
@ -1402,8 +1391,7 @@ describe('i18n support in the view compiler', () => {
if (rf & 2) {
const $ctx_r0$ = $r3$.ɵɵnextContext();
$r3$.ɵɵselect(2);
$r3$.ɵɵi18nExp($ctx_r0$.valueA);
$r3$.ɵɵi18nExp($r3$.ɵɵpipeBind1(4, 2, $ctx_r0$.valueB));
$r3$.ɵɵi18nExp($ctx_r0$.valueA)($r3$.ɵɵpipeBind1(4, 2, $ctx_r0$.valueB));
$r3$.ɵɵi18nApply(2);
}
}
@ -1527,8 +1515,7 @@ describe('i18n support in the view compiler', () => {
}
if (rf & 2) {
const $ctx_r2$ = $r3$.ɵɵnextContext(2);
$r3$.ɵɵi18nExp($ctx_r2$.valueC);
$r3$.ɵɵi18nExp($ctx_r2$.valueD);
$r3$.ɵɵi18nExp($ctx_r2$.valueC)($ctx_r2$.valueD);
$r3$.ɵɵi18nApply(0);
}
}
@ -1547,8 +1534,7 @@ describe('i18n support in the view compiler', () => {
const $ctx_r0$ = $r3$.ɵɵnextContext();
$r3$.ɵɵselect(4);
$r3$.ɵɵproperty("ngIf", $ctx_r0$.exists);
$r3$.ɵɵi18nExp($ctx_r0$.valueA);
$r3$.ɵɵi18nExp($r3$.ɵɵpipeBind1(3, 3, $ctx_r0$.valueB));
$r3$.ɵɵi18nExp($ctx_r0$.valueA)($r3$.ɵɵpipeBind1(3, 3, $ctx_r0$.valueB));
$r3$.ɵɵi18nApply(0);
}
}
@ -1596,8 +1582,7 @@ describe('i18n support in the view compiler', () => {
}
if (rf & 2) {
const $ctx_r1$ = $r3$.ɵɵnextContext();
$r3$.ɵɵi18nExp($ctx_r1$.valueE + $ctx_r1$.valueF);
$r3$.ɵɵi18nExp($r3$.ɵɵpipeBind1(3, 2, $ctx_r1$.valueG));
$r3$.ɵɵi18nExp($ctx_r1$.valueE + $ctx_r1$.valueF)($r3$.ɵɵpipeBind1(3, 2, $ctx_r1$.valueG));
$r3$.ɵɵi18nApply(0);
}
}
@ -2554,8 +2539,7 @@ describe('i18n support in the view compiler', () => {
if (rf & 2) {
const $ctx_r1$ = $r3$.ɵɵnextContext();
$r3$.ɵɵselect(2);
$r3$.ɵɵi18nExp($ctx_r1$.count);
$r3$.ɵɵi18nExp($ctx_r1$.count);
$r3$.ɵɵi18nExp($ctx_r1$.count)($ctx_r1$.count);
$r3$.ɵɵi18nApply(2);
}
}
@ -2615,8 +2599,7 @@ describe('i18n support in the view compiler', () => {
}
if (rf & 2) {
$r3$.ɵɵselect(1);
$r3$.ɵɵi18nExp(ctx.age);
$r3$.ɵɵi18nExp(ctx.other);
$r3$.ɵɵi18nExp(ctx.age)(ctx.other);
$r3$.ɵɵi18nApply(1);
}
}
@ -2742,8 +2725,7 @@ describe('i18n support in the view compiler', () => {
}
if (rf & 2) {
$r3$.ɵɵselect(1);
$r3$.ɵɵi18nExp(ctx.gender);
$r3$.ɵɵi18nExp(ctx.ageA + ctx.ageB + ctx.ageC);
$r3$.ɵɵi18nExp(ctx.gender)(ctx.ageA + ctx.ageB + ctx.ageC);
$r3$.ɵɵi18nApply(1);
}
}
@ -2808,8 +2790,7 @@ describe('i18n support in the view compiler', () => {
}
if (rf & 2) {
$r3$.ɵɵselect(1);
$r3$.ɵɵi18nExp(ctx.gender);
$r3$.ɵɵi18nExp(ctx.age);
$r3$.ɵɵi18nExp(ctx.gender)(ctx.age);
$r3$.ɵɵi18nApply(1);
}
}
@ -2914,8 +2895,7 @@ describe('i18n support in the view compiler', () => {
if (rf & 2) {
$r3$.ɵɵselect(3);
$r3$.ɵɵproperty("ngIf", ctx.visible);
$r3$.ɵɵi18nExp(ctx.gender);
$r3$.ɵɵi18nExp(ctx.gender);
$r3$.ɵɵi18nExp(ctx.gender)(ctx.gender);
$r3$.ɵɵi18nApply(1);
}
}
@ -2962,8 +2942,7 @@ describe('i18n support in the view compiler', () => {
}
if (rf & 2) {
$r3$.ɵɵselect(1);
$r3$.ɵɵi18nExp(ctx.age);
$r3$.ɵɵi18nExp(ctx.gender);
$r3$.ɵɵi18nExp(ctx.age)(ctx.gender);
$r3$.ɵɵi18nApply(1);
}
}
@ -3132,8 +3111,7 @@ describe('i18n support in the view compiler', () => {
}
if (rf & 2) {
const $ctx_r0$ = $r3$.ɵɵnextContext();
$r3$.ɵɵi18nExp($ctx_r0$.age);
$r3$.ɵɵi18nExp($ctx_r0$.otherAge);
$r3$.ɵɵi18nExp($ctx_r0$.age)($ctx_r0$.otherAge);
$r3$.ɵɵi18nApply(0);
}
}
@ -3151,9 +3129,7 @@ describe('i18n support in the view compiler', () => {
if (rf & 2) {
$r3$.ɵɵselect(2);
$r3$.ɵɵproperty("ngIf", ctx.ageVisible);
$r3$.ɵɵi18nExp(ctx.gender);
$r3$.ɵɵi18nExp(ctx.weight);
$r3$.ɵɵi18nExp(ctx.height);
$r3$.ɵɵi18nExp(ctx.gender)(ctx.weight)(ctx.height);
$r3$.ɵɵi18nApply(1);
}
}
@ -3204,10 +3180,7 @@ describe('i18n support in the view compiler', () => {
}
if (rf & 2) {
$r3$.ɵɵselect(1);
$r3$.ɵɵi18nExp(ctx.gender);
$r3$.ɵɵi18nExp(ctx.weight);
$r3$.ɵɵi18nExp(ctx.height);
$r3$.ɵɵi18nExp(ctx.age);
$r3$.ɵɵi18nExp(ctx.gender)(ctx.weight)(ctx.height)(ctx.age);
$r3$.ɵɵi18nApply(1);
}
}

View File

@ -456,10 +456,14 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
// setup accumulated bindings
const {index, bindings} = this.i18n;
if (bindings.size) {
const chainBindings: ChainableBindingInstruction[] = [];
bindings.forEach(binding => {
this.updateInstruction(
index, span, R3.i18nExp, () => [this.convertPropertyBinding(binding)]);
chainBindings.push({
sourceSpan: span,
value: () => this.convertPropertyBinding(binding)
});
});
this.updateInstructionChain(index, R3.i18nExp, chainBindings);
this.updateInstruction(index, span, R3.i18nApply, [o.literal(index)]);
}
if (!selfClosing) {
@ -641,6 +645,7 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
if (i18nAttrs.length) {
let hasBindings: boolean = false;
const i18nAttrArgs: o.Expression[] = [];
const bindings: ChainableBindingInstruction[] = [];
i18nAttrs.forEach(attr => {
const message = attr.i18n !as i18n.Message;
if (attr instanceof t.TextAttribute) {
@ -654,13 +659,17 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
i18nAttrArgs.push(o.literal(attr.name), this.i18nTranslate(message, params));
converted.expressions.forEach(expression => {
hasBindings = true;
this.updateInstruction(
elementIndex, element.sourceSpan, R3.i18nExp,
() => [this.convertExpressionBinding(expression)]);
bindings.push({
sourceSpan: element.sourceSpan,
value: () => this.convertExpressionBinding(expression)
});
});
}
}
});
if (bindings.length) {
this.updateInstructionChain(elementIndex, R3.i18nExp, bindings);
}
if (i18nAttrArgs.length) {
const index: o.Expression = o.literal(this.allocateDataSlot());
const args = this.constantPool.getConstLiteral(o.literalArr(i18nAttrArgs), true);
@ -733,7 +742,7 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
propertyBindings.push({
name: prepareSyntheticPropertyName(input.name),
input,
sourceSpan: input.sourceSpan,
value: () => hasValue ? this.convertPropertyBinding(value) : emptyValueBindInstruction
});
} else {
@ -771,7 +780,7 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
// [prop]="value"
// Collect all the properties so that we can chain into a single function at the end.
propertyBindings.push(
{name: attrName, input, value: () => this.convertPropertyBinding(value), params});
{name: attrName, sourceSpan: input.sourceSpan, value: () => this.convertPropertyBinding(value), params});
}
} else if (inputType === BindingType.Attribute) {
if (value instanceof Interpolation && getInterpolationArgsLength(value) > 1) {
@ -785,7 +794,7 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
// Collect the attribute bindings so that they can be chained at the end.
attributeBindings.push({
name: attrName,
input,
sourceSpan: input.sourceSpan,
value: () => this.convertPropertyBinding(boundValue), params
});
}
@ -830,18 +839,6 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
}
}
/**
* Adds an update instruction for a bound property or attribute, such as `[prop]="value"` or
* `[attr.title]="value"`
*/
boundUpdateInstruction(
instruction: o.ExternalReference, elementIndex: number, attrName: string,
input: t.BoundAttribute, value: any, params: any[]) {
this.updateInstruction(elementIndex, input.sourceSpan, instruction, () => {
return [o.literal(attrName), this.convertPropertyBinding(value), ...params];
});
}
/**
* Adds an update instruction for an interpolated property or attribute, such as
* `prop="{{value}}"` or `attr.title="{{value}}"`
@ -1042,7 +1039,7 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
if (value !== undefined) {
this.allocateBindingSlots(value);
propertyBindings.push(
{name: input.name, input, value: () => this.convertPropertyBinding(value)});
{name: input.name, sourceSpan: input.sourceSpan, value: () => this.convertPropertyBinding(value)});
}
}
});
@ -1093,12 +1090,17 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
private updateInstructionChain(
nodeIndex: number, reference: o.ExternalReference, bindings: ChainableBindingInstruction[]) {
const span = bindings.length ? bindings[0].input.sourceSpan : null;
const span = bindings.length ? bindings[0].sourceSpan : null;
this.addSelectInstructionIfNecessary(nodeIndex, span);
this._updateCodeFns.push(() => {
const calls = bindings.map(
property => [o.literal(property.name), property.value(), ...(property.params || [])]);
const calls = bindings.map(property => {
const fnParams = [property.value(), ...(property.params || [])];
if (property.name) {
fnParams.unshift(o.literal(property.name));
}
return fnParams;
});
return chainedInstruction(span, reference, calls).toStmt();
});
@ -2027,8 +2029,8 @@ function hasTextChildrenOnly(children: t.Node[]): boolean {
}
interface ChainableBindingInstruction {
name: string;
input: t.BoundAttribute;
name?: string;
sourceSpan: ParseSourceSpan|null;
value: () => o.Expression;
params?: any[];
}

View File

@ -16,7 +16,7 @@ import {assertDataInRange, assertDefined, assertEqual, assertGreaterThan} from '
import {attachPatchData} from './context_discovery';
import {bind, setDelayProjection, ɵɵload} from './instructions/all';
import {attachI18nOpCodesDebug} from './instructions/lview_debug';
import {allocExpando, elementAttributeInternal, elementPropertyInternal, getOrCreateTNode, setInputsForProperty, textBindingInternal} from './instructions/shared';
import {allocExpando, elementAttributeInternal, elementPropertyInternal, getOrCreateTNode, setInputsForProperty, textBindingInternal, TsickleIssue1009} from './instructions/shared';
import {LContainer, NATIVE} from './interfaces/container';
import {COMMENT_MARKER, ELEMENT_MARKER, I18nMutateOpCode, I18nMutateOpCodes, I18nUpdateOpCode, I18nUpdateOpCodes, IcuType, TI18n, TIcu} from './interfaces/i18n';
import {TElementNode, TIcuContainerNode, TNode, TNodeFlags, TNodeType, TProjectionNode} from './interfaces/node';
@ -1012,16 +1012,19 @@ let shiftsCounter = 0;
* update the translated nodes.
*
* @param value The binding's value
* @returns This function returns itself so that it may be chained
* (e.g. `i18nExp(ctx.name)(ctx.title)`)
*
* @codeGenApi
*/
export function ɵɵi18nExp<T>(value: T): void {
export function ɵɵi18nExp<T>(value: T): TsickleIssue1009 {
const lView = getLView();
const expression = bind(lView, value);
if (expression !== NO_CHANGE) {
changeMask = changeMask | (1 << shiftsCounter);
}
shiftsCounter++;
return ɵɵi18nExp;
}
/**

View File

@ -851,7 +851,7 @@ export declare function ɵɵi18nAttributes(index: number, values: string[]): voi
export declare function ɵɵi18nEnd(): void;
export declare function ɵɵi18nExp<T>(value: T): void;
export declare function ɵɵi18nExp<T>(value: T): TsickleIssue1009;
/** @deprecated */
export declare function ɵɵi18nLocalize(input: string, placeholders?: {