Skip to content

Commit

Permalink
perf(ivy): move local references into consts array
Browse files Browse the repository at this point in the history
Follow-up from angular#32798. Moves the local references array into the component def's `consts` in order to make it compress better.

Before:
```
const _c0 = ['foo', ''];

SomeComp.ngComponentDef = defineComponent({
  template: function() {
    element(0, 'div', null, _c0);
  }
});
```

After:
```
SomeComp.ngComponentDef = defineComponent({
  consts: [['foo', '']],
  template: function() {
    element(0, 'div', null, 0);
  }
});
```
  • Loading branch information
crisbeto committed Oct 13, 2019
1 parent c88305d commit 3adb337
Show file tree
Hide file tree
Showing 19 changed files with 222 additions and 194 deletions.
Expand Up @@ -797,7 +797,6 @@ describe('compiler compliance', () => {
`IfDirective.ngFactoryDef = function IfDirective_Factory(t) { return new (t || IfDirective)($r3$.ɵɵdirectiveInject($i$.TemplateRef)); };`;

const MyComponentDefinition = `
const $c1$ = ["foo", ""];
function MyComponent_li_2_Template(rf, ctx) {
if (rf & 1) {
$r3$.ɵɵelementStart(0, "li");
Expand All @@ -817,16 +816,16 @@ describe('compiler compliance', () => {
selectors: [["my-component"]],
decls: 3,
vars: 0,
consts: [[${AttributeMarker.Template}, "if"]],
consts: [["foo", ""], [${AttributeMarker.Template}, "if"]],
template: function MyComponent_Template(rf, ctx) {
if (rf & 1) {
$r3$.ɵɵelementStart(0, "ul", null, $c1$);
$r3$.ɵɵtemplate(2, MyComponent_li_2_Template, 2, 2, "li", 0);
$r3$.ɵɵelementStart(0, "ul", null, 0);
$r3$.ɵɵtemplate(2, MyComponent_li_2_Template, 2, 2, "li", 1);
$r3$.ɵɵelementEnd();
}
},
directives:[IfDirective],
encapsulation: 2
directives: [IfDirective],
encapsulation: 2
});`;

const MyComponentFactory =
Expand Down Expand Up @@ -2232,16 +2231,16 @@ describe('compiler compliance', () => {
};

const MyComponentDefinition = `
const $c1$ = ["user", ""];
MyComponent.ɵcmp = $r3$.ɵɵdefineComponent({
type: MyComponent,
selectors: [["my-component"]],
decls: 3,
vars: 1,
consts: [["user", ""]],
template: function MyComponent_Template(rf, ctx) {
if (rf & 1) {
$r3$.ɵɵelement(0, "input", null, $c1$);
$r3$.ɵɵelement(0, "input", null, 0);
$r3$.ɵɵtext(2);
}
if (rf & 2) {
Expand Down Expand Up @@ -2293,9 +2292,6 @@ describe('compiler compliance', () => {
};

const MyComponentDefinition = `
const $c1$ = ["foo", ""];
const $c3$ = ["baz", ""];
const $c4$ = ["bar", ""];
function MyComponent_div_3_span_2_Template(rf, ctx) {
if (rf & 1) {
$r3$.ɵɵelementStart(0, "span");
Expand All @@ -2316,8 +2312,8 @@ describe('compiler compliance', () => {
if (rf & 1) {
$r3$.ɵɵelementStart(0, "div");
$r3$.ɵɵtext(1);
$r3$.ɵɵtemplate(2, MyComponent_div_3_span_2_Template, 2, 3, "span", 0);
$r3$.ɵɵelement(3, "span", null, $c4$);
$r3$.ɵɵtemplate(2, MyComponent_div_3_span_2_Template, 2, 3, "span", 1);
$r3$.ɵɵelement(3, "span", null, 3);
$r3$.ɵɵelementEnd();
}
if (rf & 2) {
Expand All @@ -2334,13 +2330,13 @@ describe('compiler compliance', () => {
selectors: [["my-component"]],
decls: 6,
vars: 1,
consts: [[${AttributeMarker.Template}, "if"]],
consts: [["foo", ""], [${AttributeMarker.Template}, "if"], ["baz", ""], ["bar", ""]],
template: function MyComponent_Template(rf, ctx) {
if (rf & 1) {
$r3$.ɵɵelement(0, "div", null, $c1$);
$r3$.ɵɵelement(0, "div", null, 0);
$r3$.ɵɵtext(2);
$r3$.ɵɵtemplate(3, MyComponent_div_3_Template, 5, 2, "div", 0);
$r3$.ɵɵelement(4, "div", null, $c3$);
$r3$.ɵɵtemplate(3, MyComponent_div_3_Template, 5, 2, "div", 1);
$r3$.ɵɵelement(4, "div", null, 2);
}
if (rf & 2) {
const $foo$ = $r3$.ɵɵreference(1);
Expand Down Expand Up @@ -2382,8 +2378,6 @@ describe('compiler compliance', () => {
};

const template = `
const $c1$ = ["foo", ""];
function MyComponent_div_0_span_3_Template(rf, ctx) {
if (rf & 1) {
$i0$.ɵɵelementStart(0, "span");
Expand All @@ -2401,8 +2395,8 @@ describe('compiler compliance', () => {
function MyComponent_div_0_Template(rf, ctx) {
if (rf & 1) {
$i0$.ɵɵelementStart(0, "div");
$i0$.ɵɵelement(1, "div", null, $c1$);
$i0$.ɵɵtemplate(3, MyComponent_div_0_span_3_Template, 2, 2, "span", 1);
$i0$.ɵɵelement(1, "div", null, 1);
$i0$.ɵɵtemplate(3, MyComponent_div_0_span_3_Template, 2, 2, "span", 2);
$i0$.ɵɵelementEnd();
}
if (rf & 2) {
Expand All @@ -2413,7 +2407,7 @@ describe('compiler compliance', () => {
}
// ...
consts: [[${AttributeMarker.Template}, "ngFor", "ngForOf"], [${AttributeMarker.Template}, "ngIf"]],
consts: [[${AttributeMarker.Template}, "ngFor", "ngForOf"], ["foo", ""], [${AttributeMarker.Template}, "ngIf"]],
template:function MyComponent_Template(rf, ctx){
if (rf & 1) {
$i0$.ɵɵtemplate(0, MyComponent_div_0_Template, 4, 1, "div", 0);
Expand Down
Expand Up @@ -1251,12 +1251,11 @@ describe('compiler compliance: bindings', () => {
`);

const template = `
const $_c1$ = ["myRef", ""];
consts: [["id", "my-id"]],
consts: [["id", "my-id"], ["myRef", ""]],
template:function MyComponent_Template(rf, $ctx$){
if (rf & 1) {
$i0$.ɵɵelementStart(0, "b", 0, $_c1$);
$i0$.ɵɵelementStart(0, "b", 0, 1);
$i0$.ɵɵdisableBindings();
$i0$.ɵɵelementStart(2, "i");
$i0$.ɵɵtext(3, "Hello {{ name }}!");
Expand Down
Expand Up @@ -193,14 +193,13 @@ describe('compiler compliance: listen()', () => {
};

const MyComponentDefinition = `
const $e2_refs$ = ["user", ""];
MyComponent.ɵcmp = $r3$.ɵɵdefineComponent({
type: MyComponent,
selectors: [["my-component"]],
decls: 4,
vars: 0,
consts: [[${AttributeMarker.Bindings}, "click"]],
consts: [[${AttributeMarker.Bindings}, "click"], ["user", ""]],
template: function MyComponent_Template(rf, ctx) {
if (rf & 1) {
const $s$ = $r3$.ɵɵgetCurrentView();
Expand All @@ -212,7 +211,7 @@ describe('compiler compliance: listen()', () => {
});
$r3$.ɵɵtext(1, "Save");
$r3$.ɵɵelementEnd();
$r3$.ɵɵelement(2, "input", null, $e2_refs$);
$r3$.ɵɵelement(2, "input", null, 1);
}
},
encapsulation: 2
Expand Down
Expand Up @@ -491,19 +491,17 @@ describe('compiler compliance: template', () => {
};

const template = `
const $t0_refs$ = ["foo", ""];
function MyComponent_ng_template_0_Template(rf, ctx) {
if (rf & 1) {
$i0$.ɵɵtext(0, "some-content");
}
}
// ...
consts: [["foo", ""]],
template: function MyComponent_Template(rf, ctx) {
if (rf & 1) {
$i0$.ɵɵtemplate(0, MyComponent_ng_template_0_Template, 1, 0, "ng-template", null, $t0_refs$, $i0$.ɵɵtemplateRefExtractor);
$i0$.ɵɵtemplate(0, MyComponent_ng_template_0_Template, 1, 0, "ng-template", null, 0, $i0$.ɵɵtemplateRefExtractor);
}
}`;

Expand Down
38 changes: 21 additions & 17 deletions packages/compiler/src/render3/view/template.ts
Expand Up @@ -606,10 +606,11 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
// add attributes for directive and projection matching purposes
attributes.push(...this.prepareNonRenderAttrs(
allOtherInputs, element.outputs, stylingBuilder, [], i18nAttrs, ngProjectAsAttr));
parameters.push(this.addConstants(attributes));
parameters.push(this.addAttrsToConsts(attributes));

// local refs (ex.: <div #foo #bar="baz">)
parameters.push(this.prepareRefsParameter(element.references));
const refs = this.prepareRefsArray(element.references);
parameters.push(this.addToConsts(refs));

const wasInNamespace = this._namespace;
const currentNamespace = this.getNamespaceInstruction(namespaceKey);
Expand Down Expand Up @@ -869,11 +870,12 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
(a: t.TextAttribute) => { attrsExprs.push(asLiteral(a.name), asLiteral(a.value)); });
attrsExprs.push(...this.prepareNonRenderAttrs(
template.inputs, template.outputs, undefined, template.templateAttrs));
parameters.push(this.addConstants(attrsExprs));
parameters.push(this.addAttrsToConsts(attrsExprs));

// local refs (ex.: <ng-template #foo>)
if (template.references && template.references.length) {
parameters.push(this.prepareRefsParameter(template.references));
const refs = this.prepareRefsArray(template.references);
parameters.push(this.addToConsts(refs));
parameters.push(o.importExpr(R3.templateRefExtractor));
}

Expand Down Expand Up @@ -1294,24 +1296,26 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
return attrExprs;
}

private addConstants(constExprs: o.Expression[]): o.LiteralExpr {
if (constExprs.length > 0) {
const literal = o.literalArr(constExprs);
private addToConsts(expression: o.Expression): o.LiteralExpr {
if (o.isNull(expression)) {
return o.TYPED_NULL_EXPR;
}

// Try to reuse a literal that's already in the array, if possible.
for (let i = 0; i < this._constants.length; i++) {
if (this._constants[i].isEquivalent(literal)) {
return o.literal(i);
}
// Try to reuse a literal that's already in the array, if possible.
for (let i = 0; i < this._constants.length; i++) {
if (this._constants[i].isEquivalent(expression)) {
return o.literal(i);
}

return o.literal(this._constants.push(literal) - 1);
}

return o.TYPED_NULL_EXPR;
return o.literal(this._constants.push(expression) - 1);
}

private addAttrsToConsts(attrs: o.Expression[]): o.LiteralExpr {
return attrs.length > 0 ? this.addToConsts(o.literalArr(attrs)) : o.TYPED_NULL_EXPR;
}

private prepareRefsParameter(references: t.Reference[]): o.Expression {
private prepareRefsArray(references: t.Reference[]): o.Expression {
if (!references || references.length === 0) {
return o.TYPED_NULL_EXPR;
}
Expand All @@ -1336,7 +1340,7 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
return [reference.name, reference.value];
}));

return this.constantPool.getConstLiteral(asLiteral(refsParam), true);
return asLiteral(refsParam);
}

private prepareListenerParameter(tagName: string, outputAst: t.BoundEvent, index: number):
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/render3/definition.ts
Expand Up @@ -173,7 +173,7 @@ export function ɵɵdefineComponent<T>(componentDefinition: {
template: ComponentTemplate<T>;

/** Constants for the nodes in the component's view. */
consts?: TAttributes[];
consts?: (TAttributes | string)[];

/**
* An array of `ngContent[selector]` values that were found in the template.
Expand Down
11 changes: 7 additions & 4 deletions packages/core/src/render3/instructions/container.ts
Expand Up @@ -57,15 +57,15 @@ export function ɵɵcontainer(index: number): void {
* @param vars The number of bindings for this template
* @param tagName The name of the container element, if applicable
* @param constsIndex Index of template in the `consts` array.
* @param localRefs A set of local reference bindings on the element.
* @param localRefs Index of the local refenreces in the `consts` array.
* @param localRefExtractor A function which extracts local-refs values from the template.
* Defaults to the current element associated with the local-ref.
*
* @codeGenApi
*/
export function ɵɵtemplate(
index: number, templateFn: ComponentTemplate<any>| null, decls: number, vars: number,
tagName?: string | null, constsIndex?: number | null, localRefs?: string[] | null,
tagName?: string | null, constsIndex?: number | null, localRefsIndex?: number | null,
localRefExtractor?: LocalRefExtractor) {
const lView = getLView();
const tView = lView[TVIEW];
Expand All @@ -74,10 +74,13 @@ export function ɵɵtemplate(
// TODO: consider a separate node type for templates
const tContainerNode = containerInternal(
lView, index, tagName || null,
tViewConsts === null || constsIndex == null ? null : tViewConsts[constsIndex]);
tViewConsts === null || constsIndex == null ? null : tViewConsts[constsIndex] as TAttributes);
const localRefs = tViewConsts === null || localRefsIndex == null ?
null :
tViewConsts[localRefsIndex] as string[];
if (tView.firstTemplatePass) {
ngDevMode && ngDevMode.firstTemplatePass++;
resolveDirectives(tView, lView, tContainerNode, localRefs || null);
resolveDirectives(tView, lView, tContainerNode, localRefs);
registerPostOrderHooks(tView, tContainerNode);

const embeddedTView = tContainerNode.tViews = createTView(
Expand Down
43 changes: 24 additions & 19 deletions packages/core/src/render3/instructions/element.ts
Expand Up @@ -32,8 +32,8 @@ import {registerInitialStylingOnTNode} from './styling';
*
* @param index Index of the element in the LView array
* @param name Name of the DOM Node
* @param constsIndex Index of the element in the `consts` array.
* @param localRefs A set of local reference bindings on the element.
* @param attrsIndex Index of the element's attributes in the `consts` array.
* @param localRefsIndex Index of the element's local references in the `consts` array.
*
* Attributes and localRefs are passed as an array of strings where elements with an even index
* hold an attribute name and elements with an odd index hold an attribute value, ex.:
Expand All @@ -42,25 +42,30 @@ import {registerInitialStylingOnTNode} from './styling';
* @codeGenApi
*/
export function ɵɵelementStart(
index: number, name: string, constsIndex?: number | null, localRefs?: string[] | null): void {
index: number, name: string, attrsIndex?: number | null, localRefsIndex?: number): void {
const lView = getLView();
const tView = lView[TVIEW];
const tViewConsts = tView.consts;
const consts = tViewConsts === null || constsIndex == null ? null : tViewConsts[constsIndex];
ngDevMode && assertEqual(
lView[BINDING_INDEX], tView.bindingStartIndex,
'elements should be created before any bindings');

ngDevMode && ngDevMode.rendererCreateElement++;
ngDevMode && assertDataInRange(lView, index + HEADER_OFFSET);
const attrs =
tViewConsts === null || attrsIndex == null ? null : tViewConsts[attrsIndex] as TAttributes;
const localRefs = tViewConsts === null || localRefsIndex === undefined ?
null :
tViewConsts[localRefsIndex] as string[];
if (ngDevMode) {
assertEqual(
lView[BINDING_INDEX], tView.bindingStartIndex,
'elements should be created before any bindings');
ngDevMode.rendererCreateElement++;
assertDataInRange(lView, index + HEADER_OFFSET);
}
const renderer = lView[RENDERER];
const native = lView[index + HEADER_OFFSET] = elementCreate(name, renderer, getNamespace());
const tNode = getOrCreateTNode(tView, lView[T_HOST], index, TNodeType.Element, name, consts);
const tNode = getOrCreateTNode(tView, lView[T_HOST], index, TNodeType.Element, name, attrs);

if (consts != null) {
const lastAttrIndex = setUpAttributes(renderer, native, consts);
if (attrs != null) {
const lastAttrIndex = setUpAttributes(renderer, native, attrs);
if (tView.firstTemplatePass) {
registerInitialStylingOnTNode(tNode, consts, lastAttrIndex);
registerInitialStylingOnTNode(tNode, attrs, lastAttrIndex);
}
}

Expand All @@ -84,7 +89,7 @@ export function ɵɵelementStart(
// and `[class]` bindings work for multiple directives.)
if (tView.firstTemplatePass) {
ngDevMode && ngDevMode.firstTemplatePass++;
resolveDirectives(tView, lView, tNode, localRefs || null);
resolveDirectives(tView, lView, tNode, localRefs);

if (tView.queries !== null) {
tView.queries.elementStart(tView, tNode);
Expand Down Expand Up @@ -146,14 +151,14 @@ export function ɵɵelementEnd(): void {
*
* @param index Index of the element in the data array
* @param name Name of the DOM Node
* @param constsIndex Index of the element in the `consts` array.
* @param localRefs A set of local reference bindings on the element.
* @param attrsIndex Index of the element's attributes in the `consts` array.
* @param localRefsIndex Index of the element's local references in the `consts` array.
*
* @codeGenApi
*/
export function ɵɵelement(
index: number, name: string, constsIndex?: number | null, localRefs?: string[] | null): void {
ɵɵelementStart(index, name, constsIndex, localRefs);
index: number, name: string, attrsIndex?: number | null, localRefsIndex?: number): void {
ɵɵelementStart(index, name, attrsIndex, localRefsIndex);
ɵɵelementEnd();
}

Expand Down

0 comments on commit 3adb337

Please sign in to comment.