Skip to content

Commit 32ae421

Browse files
crisbetothePunderWoman
authored andcommitted
refactor(compiler): replace attribute interpolation instructions (angular#61557)
Replaces the attribute interpolation instructions with `attribute` plus the new `interpolateX` instruction. This allows to reduce our overall instruction footprint. PR Close angular#61557
1 parent a7be506 commit 32ae421

9 files changed

Lines changed: 92 additions & 70 deletions

File tree

Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
template: function MyComponent_Template(rf, ctx) {
22
33
if (rf & 2) {
4-
$r3$.ɵɵattributeInterpolate1("tabindex", "prefix-", 0 + 3);
5-
$r3$.ɵɵattributeInterpolate2("aria-label", "hello-", 1 + 3, "-", 2 + 3);
6-
$r3$.ɵɵattribute("title", 1)("id", 2);
4+
$r3$.ɵɵattribute("tabindex", $r3$.ɵɵinterpolate1("prefix-", 0 + 3))("aria-label", $r3$.ɵɵinterpolate2("hello-", 1 + 3, "-", 2 + 3))("title", 1)("id", 2);
75
}
86
}

packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_bindings/attribute_bindings/chain_multiple_bindings_mixed.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
template: function MyComponent_Template(rf, ctx) {
22
33
if (rf & 2) {
4-
$r3$.ɵɵattributeInterpolate1("aria-label", "prefix-", 1 + 3);
4+
$r3$.ɵɵattribute("aria-label", $r3$.ɵɵinterpolate1("prefix-", 1 + 3));
55
$r3$.ɵɵproperty("id", 2);
66
$r3$.ɵɵattribute("title", 1)("tabindex", 3);
77
}
Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
11
if (rf & 2) {
2-
i0.ɵɵattributeInterpolateV("title", ["a", ctx.one, "b", ctx.two, "c", ctx.three, "d", ctx.four, "e", ctx.five, "f", ctx.six, "g", ctx.seven, "h", ctx.eight, "i", ctx.nine, "j"]);
3-
i0.ɵɵadvance();
4-
i0.ɵɵattributeInterpolate8("title", "a", ctx.one, "b", ctx.two, "c", ctx.three, "d", ctx.four, "e", ctx.five, "f", ctx.six, "g", ctx.seven, "h", ctx.eight, "i");
5-
i0.ɵɵadvance();
6-
i0.ɵɵattributeInterpolate7("title", "a", ctx.one, "b", ctx.two, "c", ctx.three, "d", ctx.four, "e", ctx.five, "f", ctx.six, "g", ctx.seven, "h");
7-
i0.ɵɵadvance();
8-
i0.ɵɵattributeInterpolate6("title", "a", ctx.one, "b", ctx.two, "c", ctx.three, "d", ctx.four, "e", ctx.five, "f", ctx.six, "g");
9-
i0.ɵɵadvance();
10-
i0.ɵɵattributeInterpolate5("title", "a", ctx.one, "b", ctx.two, "c", ctx.three, "d", ctx.four, "e", ctx.five, "f");
11-
i0.ɵɵadvance();
12-
i0.ɵɵattributeInterpolate4("title", "a", ctx.one, "b", ctx.two, "c", ctx.three, "d", ctx.four, "e");
13-
i0.ɵɵadvance();
14-
i0.ɵɵattributeInterpolate3("title", "a", ctx.one, "b", ctx.two, "c", ctx.three, "d");
15-
i0.ɵɵadvance();
16-
i0.ɵɵattributeInterpolate2("title", "a", ctx.one, "b", ctx.two, "c");
17-
i0.ɵɵadvance();
18-
i0.ɵɵattributeInterpolate1("title", "a", ctx.one, "b");
19-
i0.ɵɵadvance();
20-
i0.ɵɵattribute("title", ctx.one);
2+
$r3$.ɵɵattribute("title", $r3$.ɵɵinterpolateV(["a", ctx.one, "b", ctx.two, "c", ctx.three, "d", ctx.four, "e", ctx.five, "f", ctx.six, "g", ctx.seven, "h", ctx.eight, "i", ctx.nine, "j"]));
3+
$r3$.ɵɵadvance();
4+
$r3$.ɵɵattribute("title", $r3$.ɵɵinterpolate8("a", ctx.one, "b", ctx.two, "c", ctx.three, "d", ctx.four, "e", ctx.five, "f", ctx.six, "g", ctx.seven, "h", ctx.eight, "i"));
5+
$r3$.ɵɵadvance();
6+
$r3$.ɵɵattribute("title", $r3$.ɵɵinterpolate7("a", ctx.one, "b", ctx.two, "c", ctx.three, "d", ctx.four, "e", ctx.five, "f", ctx.six, "g", ctx.seven, "h"));
7+
$r3$.ɵɵadvance();
8+
$r3$.ɵɵattribute("title", $r3$.ɵɵinterpolate6("a", ctx.one, "b", ctx.two, "c", ctx.three, "d", ctx.four, "e", ctx.five, "f", ctx.six, "g"));
9+
$r3$.ɵɵadvance();
10+
$r3$.ɵɵattribute("title", $r3$.ɵɵinterpolate5("a", ctx.one, "b", ctx.two, "c", ctx.three, "d", ctx.four, "e", ctx.five, "f"));
11+
$r3$.ɵɵadvance();
12+
$r3$.ɵɵattribute("title", $r3$.ɵɵinterpolate4("a", ctx.one, "b", ctx.two, "c", ctx.three, "d", ctx.four, "e"));
13+
$r3$.ɵɵadvance();
14+
$r3$.ɵɵattribute("title", $r3$.ɵɵinterpolate3("a", ctx.one, "b", ctx.two, "c", ctx.three, "d"));
15+
$r3$.ɵɵadvance();
16+
$r3$.ɵɵattribute("title", $r3$.ɵɵinterpolate2("a", ctx.one, "b", ctx.two, "c"));
17+
$r3$.ɵɵadvance();
18+
$r3$.ɵɵattribute("title", $r3$.ɵɵinterpolate1("a", ctx.one, "b"));
19+
$r3$.ɵɵadvance();
20+
$r3$.ɵɵattribute("title", ctx.one);
2121
}
2222

packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_bindings/order_bindings.js

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,33 +2,33 @@ hostAttrs: ["literal1", "foo"]
22
// ...
33
function MyCmp_HostBindings(rf, ctx) {
44
if (rf & 1) {
5-
i0.ɵɵlistener("event1", function MyCmp_event1_HostBindingHandler() { return ctx.foo(); });
5+
$r3$.ɵɵlistener("event1", function MyCmp_event1_HostBindingHandler() { return ctx.foo(); });
66
}
77
if (rf & 2) {
8-
i0.ɵɵdomProperty("prop1", ctx.foo);
9-
i0.ɵɵattribute("attr1", ctx.foo);
10-
i0.ɵɵstyleMap(ctx.foo);
11-
i0.ɵɵclassMap(ctx.foo);
12-
i0.ɵɵstyleProp("style1", true);
13-
i0.ɵɵclassProp("class1", false);
8+
$r3$.ɵɵdomProperty("prop1", ctx.foo);
9+
$r3$.ɵɵattribute("attr1", ctx.foo);
10+
$r3$.ɵɵstyleMap(ctx.foo);
11+
$r3$.ɵɵclassMap(ctx.foo);
12+
$r3$.ɵɵstyleProp("style1", true);
13+
$r3$.ɵɵclassProp("class1", false);
1414
}
1515
}
1616

1717
// ...
1818

1919
function MyCmp_Template(rf, ctx) {
2020
if (rf & 1) {
21-
i0.ɵɵelementStart(0, "some-elem", 0);
22-
i0.ɵɵlistener("event1", function MyCmp_Template_some_elem_event1_0_listener() {
21+
$r3$.ɵɵelementStart(0, "some-elem", 0);
22+
$r3$.ɵɵlistener("event1", function MyCmp_Template_some_elem_event1_0_listener() {
2323
return ctx.foo();
2424
});
25-
i0.ɵɵelementEnd();
25+
$r3$.ɵɵelementEnd();
2626
} if (rf & 2) {
27-
i0.ɵɵstyleProp("style1", ctx.foo);
28-
i0.ɵɵclassProp("class1", ctx.foo);
29-
i0.ɵɵattributeInterpolate1("attrInterp1", "interp ", ctx.foo);
30-
i0.ɵɵpropertyInterpolate1("propInterp1", "interp ", ctx.foo);
31-
i0.ɵɵproperty("prop1", ctx.foo);
32-
i0.ɵɵattribute("attr1", ctx.foo);
27+
$r3$.ɵɵstyleProp("style1", ctx.foo);
28+
$r3$.ɵɵclassProp("class1", ctx.foo);
29+
$r3$.ɵɵattribute("attrInterp1", $r3$.ɵɵinterpolate1("interp ", ctx.foo));
30+
$r3$.ɵɵpropertyInterpolate1("propInterp1", "interp ", ctx.foo);
31+
$r3$.ɵɵproperty("prop1", ctx.foo);
32+
$r3$.ɵɵattribute("attr1", ctx.foo);
3333
}
3434
}
Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
11
template: function MyComponent_Template(rf, ctx) {
22
if (rf & 1) {
3-
i0.ɵɵelement(0, "div", 0)(1, "link", 1)(2, "div")(3, "img", 2)(4, "iframe", 3)(5, "a", 1)(6, "div");
3+
$r3$.ɵɵelement(0, "div", 0)(1, "link", 1)(2, "div")(3, "img", 2)(4, "iframe", 3)(5, "a", 1)(6, "div");
44
}
55
if (rf & 2) {
6-
i0.ɵɵproperty("innerHtml", ctx.evil, i0.ɵɵsanitizeHtml);
7-
i0.ɵɵadvance();
8-
i0.ɵɵproperty("href", ctx.evil, i0.ɵɵsanitizeResourceUrl);
9-
i0.ɵɵadvance();
10-
i0.ɵɵattribute("style", ctx.evil, i0.ɵɵsanitizeStyle);
11-
i0.ɵɵadvance();
12-
i0.ɵɵproperty("src", ctx.evil, i0.ɵɵsanitizeUrl);
13-
i0.ɵɵadvance();
14-
i0.ɵɵproperty("sandbox", ctx.evil, i0.ɵɵvalidateIframeAttribute);
15-
i0.ɵɵadvance();
16-
i0.ɵɵpropertyInterpolate2("href", "", ctx.evil, "", ctx.evil, "", i0.ɵɵsanitizeUrl);
17-
i0.ɵɵadvance();
18-
i0.ɵɵattributeInterpolate2("style", "", ctx.evil, "", ctx.evil, "", i0.ɵɵsanitizeStyle);
6+
$r3$.ɵɵproperty("innerHtml", ctx.evil, $r3$.ɵɵsanitizeHtml);
7+
$r3$.ɵɵadvance();
8+
$r3$.ɵɵproperty("href", ctx.evil, $r3$.ɵɵsanitizeResourceUrl);
9+
$r3$.ɵɵadvance();
10+
$r3$.ɵɵattribute("style", ctx.evil, $r3$.ɵɵsanitizeStyle);
11+
$r3$.ɵɵadvance();
12+
$r3$.ɵɵproperty("src", ctx.evil, $r3$.ɵɵsanitizeUrl);
13+
$r3$.ɵɵadvance();
14+
$r3$.ɵɵproperty("sandbox", ctx.evil, $r3$.ɵɵvalidateIframeAttribute);
15+
$r3$.ɵɵadvance();
16+
$r3$.ɵɵpropertyInterpolate2("href", "", ctx.evil, "", ctx.evil, "", $r3$.ɵɵsanitizeUrl);
17+
$r3$.ɵɵadvance();
18+
$r3$.ɵɵattribute("style", $r3$.ɵɵinterpolate2("", ctx.evil, "", ctx.evil), $r3$.ɵɵsanitizeStyle);
1919
}
2020
}

packages/compiler/src/template/pipeline/src/instruction.ts

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -674,22 +674,18 @@ export function attributeInterpolate(
674674
strings: string[],
675675
expressions: o.Expression[],
676676
sanitizer: o.Expression | null,
677+
namespace: string | null,
677678
sourceSpan: ParseSourceSpan,
678679
): ir.UpdateOp {
679680
const interpolationArgs = collateInterpolationArgs(strings, expressions);
680-
681-
const extraArgs = [];
682-
if (sanitizer !== null) {
683-
extraArgs.push(sanitizer);
684-
}
685-
686-
return callVariadicInstruction(
687-
ATTRIBUTE_INTERPOLATE_CONFIG,
688-
[o.literal(name)],
681+
const value = callVariadicInstructionExpr(
682+
VALUE_INTERPOLATE_CONFIG,
683+
[],
689684
interpolationArgs,
690-
extraArgs,
685+
[],
691686
sourceSpan,
692687
);
688+
return attribute(name, value, sanitizer, namespace);
693689
}
694690

695691
export function stylePropInterpolate(
@@ -894,6 +890,27 @@ const PROPERTY_INTERPOLATE_CONFIG: VariadicInstructionConfig = {
894890
},
895891
};
896892

893+
const VALUE_INTERPOLATE_CONFIG: VariadicInstructionConfig = {
894+
constant: [
895+
Identifiers.interpolate,
896+
Identifiers.interpolate1,
897+
Identifiers.interpolate2,
898+
Identifiers.interpolate3,
899+
Identifiers.interpolate4,
900+
Identifiers.interpolate5,
901+
Identifiers.interpolate6,
902+
Identifiers.interpolate7,
903+
Identifiers.interpolate8,
904+
],
905+
variable: Identifiers.interpolateV,
906+
mapping: (n) => {
907+
if (n % 2 === 0) {
908+
throw new Error(`Expected odd number of arguments`);
909+
}
910+
return (n - 1) / 2;
911+
},
912+
};
913+
897914
/**
898915
* `InterpolationConfig` for the `stylePropInterpolate` instruction.
899916
*/

packages/compiler/src/template/pipeline/src/phases/reify.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -568,6 +568,7 @@ function reifyUpdateOperations(_unit: CompilationUnit, ops: ir.OpList<ir.UpdateO
568568
op.expression.strings,
569569
op.expression.expressions,
570570
op.sanitizer,
571+
op.namespace,
571572
op.sourceSpan,
572573
),
573574
);

packages/core/src/render3/instructions/attribute.ts

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import {bindingUpdated} from '../bindings';
99
import {SanitizerFn} from '../interfaces/sanitization';
1010
import {getLView, getSelectedTNode, getTView, nextBindingIndex} from '../state';
11+
import {NO_CHANGE} from '../tokens';
1112
import {elementAttributeInternal, storePropertyBindingMetadata} from './shared';
1213

1314
/**
@@ -29,13 +30,18 @@ export function ɵɵattribute(
2930
sanitizer?: SanitizerFn | null,
3031
namespace?: string,
3132
): typeof ɵɵattribute {
32-
const lView = getLView();
3333
const bindingIndex = nextBindingIndex();
34-
if (bindingUpdated(lView, bindingIndex, value)) {
35-
const tView = getTView();
36-
const tNode = getSelectedTNode();
37-
elementAttributeInternal(tNode, lView, name, value, sanitizer, namespace);
38-
ngDevMode && storePropertyBindingMetadata(tView.data, tNode, 'attr.' + name, bindingIndex);
34+
35+
// Value can be `NO_CHANGE` in case of an interpolation.
36+
if (value !== NO_CHANGE) {
37+
const lView = getLView();
38+
if (bindingUpdated(lView, bindingIndex, value)) {
39+
const tView = getTView();
40+
const tNode = getSelectedTNode();
41+
elementAttributeInternal(tNode, lView, name, value, sanitizer, namespace);
42+
ngDevMode && storePropertyBindingMetadata(tView.data, tNode, 'attr.' + name, bindingIndex);
43+
}
3944
}
45+
4046
return ɵɵattribute;
4147
}

packages/core/test/acceptance/change_detection_spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1671,7 +1671,7 @@ describe('change detection', () => {
16711671
});
16721672

16731673
it('should include field name in case of attribute interpolation', () => {
1674-
const message = `Previous value for 'attr.id': 'Expressions: a and initial!'. Current value: 'Expressions: a and changed!'`;
1674+
const message = `Expression has changed after it was checked. Previous value: 'initial'. Current value: 'changed'`;
16751675
expect(() =>
16761676
initWithTemplate(
16771677
'<div attr.id="Expressions: {{ a }} and {{ unstableStringExpression }}!"></div>',

0 commit comments

Comments
 (0)