perf(ivy): avoid generating extra parameters for host property bindings (#31550)

Currently we reuse the same instruction both for regular property bindings and property bindings on the `host`. The only difference between the two is that when it's on the host we shouldn't support inputs. We have an optional parameter called `nativeOnly` which is used to differentiate the two, however since `nativeOnly` is preceeded by another optional parameter (`sanitizer`), we have to generate two extra parameters for each host property bindings every time (e.g. `property('someProp', 'someValue', null, true)`).

These changes add a new instruction called `hostProperty` which avoids the need for the two parameters by removing `nativeOnly` which is always set and it allows us to omit `sanitizer` when it isn't being used.

These changes also remove the `nativeOnly` parameter from the `updateSyntheticHostBinding` instruction, because it's only generated for host elements which means that we can assume that its value will always be `true`.

PR Close #31550
This commit is contained in:
crisbeto
2019-07-14 11:11:10 +02:00
committed by Matias Niemelä
parent 46c03bd866
commit 40d785f0a0
14 changed files with 106 additions and 73 deletions

View File

@ -98,6 +98,7 @@ export {
ɵɵcontentQuery,
ɵɵloadContentQuery,
ɵɵelementEnd,
ɵɵhostProperty,
ɵɵproperty,
ɵɵpropertyInterpolate,
ɵɵpropertyInterpolate1,

View File

@ -82,6 +82,7 @@ export {
ɵɵprojection,
ɵɵprojectionDef,
ɵɵhostProperty,
ɵɵproperty,
ɵɵpropertyInterpolate,
ɵɵpropertyInterpolate1,

View File

@ -49,3 +49,4 @@ export * from './text';
export * from './text_interpolation';
export * from './class_map_interpolation';
export * from './style_prop_interpolation';
export * from './host_property';

View File

@ -0,0 +1,73 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {assertNotEqual} from '../../util/assert';
import {SanitizerFn} from '../interfaces/sanitization';
import {getLView, getSelectedIndex} from '../state';
import {NO_CHANGE} from '../tokens';
import {bind} from './property';
import {TsickleIssue1009, elementPropertyInternal, loadComponentRenderer} from './shared';
/**
* Update a property on a host element. Only applies to native node properties, not inputs.
*
* Operates on the element selected by index via the {@link select} instruction.
*
* @param propName Name of property. Because it is going to DOM, this is not subject to
* renaming as part of minification.
* @param value New value to write.
* @param sanitizer An optional function used to sanitize the value.
* @returns This function returns itself so that it may be chained
* (e.g. `property('name', ctx.name)('title', ctx.title)`)
*
* @codeGenApi
*/
export function ɵɵhostProperty<T>(
propName: string, value: T, sanitizer?: SanitizerFn | null): TsickleIssue1009 {
const index = getSelectedIndex();
ngDevMode && assertNotEqual(index, -1, 'selected index cannot be -1');
const lView = getLView();
const bindReconciledValue = bind(lView, value);
if (bindReconciledValue !== NO_CHANGE) {
elementPropertyInternal(index, propName, bindReconciledValue, sanitizer, true);
}
return ɵɵhostProperty;
}
/**
* Updates a synthetic host binding (e.g. `[@foo]`) on a component.
*
* This instruction is for compatibility purposes and is designed to ensure that a
* synthetic host binding (e.g. `@HostBinding('@foo')`) properly gets rendered in
* the component's renderer. Normally all host bindings are evaluated with the parent
* component's renderer, but, in the case of animation @triggers, they need to be
* evaluated with the sub component's renderer (because that's where the animation
* triggers are defined).
*
* Do not use this instruction as a replacement for `elementProperty`. This instruction
* only exists to ensure compatibility with the ViewEngine's host binding behavior.
*
* @param index The index of the element to update in the data array
* @param propName Name of property. Because it is going to DOM, this is not subject to
* renaming as part of minification.
* @param value New value to write.
* @param sanitizer An optional function used to sanitize the value.
*
* @codeGenApi
*/
export function ɵɵupdateSyntheticHostBinding<T>(
propName: string, value: T | NO_CHANGE, sanitizer?: SanitizerFn | null): TsickleIssue1009 {
const index = getSelectedIndex();
const lView = getLView();
// TODO(benlesh): remove bind call here.
const bound = bind(lView, value);
if (bound !== NO_CHANGE) {
elementPropertyInternal(index, propName, bound, sanitizer, true, loadComponentRenderer);
}
return ɵɵupdateSyntheticHostBinding;
}

View File

@ -12,7 +12,7 @@ import {BINDING_INDEX, LView} from '../interfaces/view';
import {getLView, getSelectedIndex} from '../state';
import {NO_CHANGE} from '../tokens';
import {TsickleIssue1009, elementPropertyInternal, loadComponentRenderer, storeBindingMetadata} from './shared';
import {TsickleIssue1009, elementPropertyInternal, storeBindingMetadata} from './shared';
/**
@ -28,22 +28,19 @@ import {TsickleIssue1009, elementPropertyInternal, loadComponentRenderer, storeB
* renaming as part of minification.
* @param value New value to write.
* @param sanitizer An optional function used to sanitize the value.
* @param nativeOnly Whether or not we should only set native properties and skip input check
* (this is necessary for host property bindings)
* @returns This function returns itself so that it may be chained
* (e.g. `property('name', ctx.name)('title', ctx.title)`)
*
* @codeGenApi
*/
export function ɵɵproperty<T>(
propName: string, value: T, sanitizer?: SanitizerFn | null,
nativeOnly?: boolean): TsickleIssue1009 {
propName: string, value: T, sanitizer?: SanitizerFn | null): TsickleIssue1009 {
const index = getSelectedIndex();
ngDevMode && assertNotEqual(index, -1, 'selected index cannot be -1');
const lView = getLView();
const bindReconciledValue = bind(lView, value);
if (bindReconciledValue !== NO_CHANGE) {
elementPropertyInternal(index, propName, bindReconciledValue, sanitizer, nativeOnly);
elementPropertyInternal(index, propName, bindReconciledValue, sanitizer);
}
return ɵɵproperty;
}
@ -59,39 +56,3 @@ export function bind<T>(lView: LView, value: T): T|NO_CHANGE {
storeBindingMetadata(lView);
return bindingUpdated(lView, bindingIndex, value) ? value : NO_CHANGE;
}
/**
* Updates a synthetic host binding (e.g. `[@foo]`) on a component.
*
* This instruction is for compatibility purposes and is designed to ensure that a
* synthetic host binding (e.g. `@HostBinding('@foo')`) properly gets rendered in
* the component's renderer. Normally all host bindings are evaluated with the parent
* component's renderer, but, in the case of animation @triggers, they need to be
* evaluated with the sub component's renderer (because that's where the animation
* triggers are defined).
*
* Do not use this instruction as a replacement for `elementProperty`. This instruction
* only exists to ensure compatibility with the ViewEngine's host binding behavior.
*
* @param index The index of the element to update in the data array
* @param propName Name of property. Because it is going to DOM, this is not subject to
* renaming as part of minification.
* @param value New value to write.
* @param sanitizer An optional function used to sanitize the value.
* @param nativeOnly Whether or not we should only set native properties and skip input check
* (this is necessary for host property bindings)
*
* @codeGenApi
*/
export function ɵɵupdateSyntheticHostBinding<T>(
propName: string, value: T | NO_CHANGE, sanitizer?: SanitizerFn | null,
nativeOnly?: boolean): TsickleIssue1009 {
const index = getSelectedIndex();
const lView = getLView();
// TODO(benlesh): remove bind call here.
const bound = bind(lView, value);
if (bound !== NO_CHANGE) {
elementPropertyInternal(index, propName, bound, sanitizer, nativeOnly, loadComponentRenderer);
}
return ɵɵupdateSyntheticHostBinding;
}

View File

@ -85,6 +85,7 @@ export const angularCoreEnv: {[name: string]: Function} =
'ɵɵpipeBind4': r3.ɵɵpipeBind4,
'ɵɵpipeBindV': r3.ɵɵpipeBindV,
'ɵɵprojectionDef': r3.ɵɵprojectionDef,
'ɵɵhostProperty': r3.ɵɵhostProperty,
'ɵɵproperty': r3.ɵɵproperty,
'ɵɵpropertyInterpolate': r3.ɵɵpropertyInterpolate,
'ɵɵpropertyInterpolate1': r3.ɵɵpropertyInterpolate1,