refactor(ivy): use generated consts value to set binding index (#25533)

PR Close #25533
This commit is contained in:
Kara Erickson
2018-08-16 18:53:21 -07:00
committed by Jason Aden
parent 4708cb91ef
commit f2aa9c6a7f
52 changed files with 2296 additions and 1767 deletions

View File

@ -18,7 +18,7 @@ import {CLEAN_PROMISE, ROOT_DIRECTIVE_INDICES, _getComponentHostLElementNode, ba
import {ComponentDef, ComponentDefInternal, ComponentType} from './interfaces/definition';
import {LElementNode} from './interfaces/node';
import {RElement, RendererFactory3, domRendererFactory3} from './interfaces/renderer';
import {LViewData, LViewFlags, RootContext, INJECTOR, CONTEXT, TVIEW} from './interfaces/view';
import {LViewData, LViewFlags, RootContext, BINDING_INDEX, INJECTOR, CONTEXT, TVIEW} from './interfaces/view';
import {stringify} from './util';
@ -107,11 +107,12 @@ export function renderComponent<T>(
const rootView: LViewData = createLViewData(
rendererFactory.createRenderer(hostNode, componentDef),
createTView(-1, null, null, null, null), rootContext,
createTView(-1, null, 1, null, null, null), rootContext,
componentDef.onPush ? LViewFlags.Dirty : LViewFlags.CheckAlways);
rootView[INJECTOR] = opts.injector || null;
const oldView = enterView(rootView, null !);
rootView[BINDING_INDEX] = rootView[TVIEW].bindingStartIndex;
let elementNode: LElementNode;
let component: T;
try {

View File

@ -22,7 +22,7 @@ import {baseDirectiveCreate, createLNode, createLViewData, createTView, elementC
import {ComponentDefInternal, ComponentType, RenderFlags} from './interfaces/definition';
import {LElementNode, TNode, TNodeType} from './interfaces/node';
import {RElement, RendererFactory3, domRendererFactory3} from './interfaces/renderer';
import {CONTEXT, FLAGS, INJECTOR, LViewData, LViewFlags, RootContext, TVIEW} from './interfaces/view';
import {BINDING_INDEX, CONTEXT, FLAGS, INJECTOR, LViewData, LViewFlags, RootContext, TVIEW} from './interfaces/view';
import {RootViewRef, ViewRef} from './view_ref';
export class ComponentFactoryResolver extends viewEngine_ComponentFactoryResolver {
@ -121,12 +121,13 @@ export class ComponentFactory<T> extends viewEngine_ComponentFactory<T> {
// Create the root view. Uses empty TView and ContentTemplate.
const rootView: LViewData = createLViewData(
rendererFactory.createRenderer(hostNode, this.componentDef),
createTView(-1, null, null, null, null), rootContext,
createTView(-1, null, 1, null, null, null), rootContext,
this.componentDef.onPush ? LViewFlags.Dirty : LViewFlags.CheckAlways);
rootView[INJECTOR] = ngModule && ngModule.injector || null;
// rootView is the parent when bootstrapping
const oldView = enterView(rootView, null !);
rootView[BINDING_INDEX] = rootView[TVIEW].bindingStartIndex;
let component: T;
let elementNode: LElementNode;

View File

@ -53,6 +53,15 @@ export function defineComponent<T>(componentDefinition: {
*/
factory: () => T;
/**
* The number of nodes, local refs, and pipes in this component template.
*
* Used to calculate the length of the component's LViewData array, so we
* can pre-fill the array and set the binding start index.
*/
// TODO(kara): remove queries from this count
consts: number;
/**
* Static attributes to set on host element.
*
@ -245,6 +254,7 @@ export function defineComponent<T>(componentDefinition: {
const def: ComponentDefInternal<any> = {
type: type,
diPublic: null,
consts: componentDefinition.consts,
factory: componentDefinition.factory,
template: componentDefinition.template || null !,
hostBindings: componentDefinition.hostBindings || null,

View File

@ -7,7 +7,7 @@
*/
import {assertEqual, assertLessThan} from './assert';
import {NO_CHANGE, _getViewData, bindingUpdated, bindingUpdated2, bindingUpdated3, bindingUpdated4, createLNode, getPreviousOrParentNode, getRenderer, initBindings, load, resetApplicationState} from './instructions';
import {NO_CHANGE, _getViewData, bindingUpdated, bindingUpdated2, bindingUpdated3, bindingUpdated4, createLNode, getPreviousOrParentNode, getRenderer, load, resetApplicationState} from './instructions';
import {RENDER_PARENT} from './interfaces/container';
import {LContainerNode, LNode, TContainerNode, TElementNode, TNodeType} from './interfaces/node';
import {BINDING_INDEX, HEADER_OFFSET, TVIEW} from './interfaces/view';
@ -293,7 +293,9 @@ function appendI18nNode(node: LNode, parentNode: LNode, previousNode: LNode) {
export function i18nApply(startIndex: number, instructions: I18nInstruction[]): void {
const viewData = _getViewData();
if (ngDevMode) {
assertEqual(viewData[BINDING_INDEX], -1, 'i18nApply should be called before any binding');
assertEqual(
viewData[BINDING_INDEX], viewData[TVIEW].bindingStartIndex,
'i18nApply should be called before any binding');
}
if (!instructions) {
@ -383,7 +385,6 @@ export function i18nExpMapping(
* @returns The concatenated string when any of the arguments changes, `NO_CHANGE` otherwise.
*/
export function i18nInterpolation1(instructions: I18nExpInstruction[], v0: any): string|NO_CHANGE {
initBindings();
const different = bindingUpdated(_getViewData()[BINDING_INDEX]++, v0);
if (!different) {
@ -415,7 +416,6 @@ export function i18nInterpolation1(instructions: I18nExpInstruction[], v0: any):
*/
export function i18nInterpolation2(instructions: I18nExpInstruction[], v0: any, v1: any): string|
NO_CHANGE {
initBindings();
const viewData = _getViewData();
const different = bindingUpdated2(viewData[BINDING_INDEX], v0, v1);
viewData[BINDING_INDEX] += 2;
@ -456,7 +456,6 @@ export function i18nInterpolation2(instructions: I18nExpInstruction[], v0: any,
*/
export function i18nInterpolation3(
instructions: I18nExpInstruction[], v0: any, v1: any, v2: any): string|NO_CHANGE {
initBindings();
const viewData = _getViewData();
const different = bindingUpdated3(viewData[BINDING_INDEX], v0, v1, v2);
viewData[BINDING_INDEX] += 3;
@ -499,7 +498,6 @@ export function i18nInterpolation3(
*/
export function i18nInterpolation4(
instructions: I18nExpInstruction[], v0: any, v1: any, v2: any, v3: any): string|NO_CHANGE {
initBindings();
const viewData = _getViewData();
const different = bindingUpdated4(viewData[BINDING_INDEX], v0, v1, v2, v3);
viewData[BINDING_INDEX] += 4;
@ -544,7 +542,6 @@ export function i18nInterpolation4(
export function i18nInterpolation5(
instructions: I18nExpInstruction[], v0: any, v1: any, v2: any, v3: any, v4: any): string|
NO_CHANGE {
initBindings();
const viewData = _getViewData();
let different = bindingUpdated4(viewData[BINDING_INDEX], v0, v1, v2, v3);
different = bindingUpdated(viewData[BINDING_INDEX] + 4, v4) || different;
@ -592,7 +589,6 @@ export function i18nInterpolation5(
i18nInterpolation6(
instructions: I18nExpInstruction[], v0: any, v1: any, v2: any, v3: any, v4: any, v5: any):
string|NO_CHANGE {
initBindings();
const viewData = _getViewData();
let different = bindingUpdated4(viewData[BINDING_INDEX], v0, v1, v2, v3);
different = bindingUpdated2(viewData[BINDING_INDEX] + 4, v4, v5) || different;
@ -641,7 +637,6 @@ i18nInterpolation6(
export function i18nInterpolation7(
instructions: I18nExpInstruction[], v0: any, v1: any, v2: any, v3: any, v4: any, v5: any,
v6: any): string|NO_CHANGE {
initBindings();
const viewData = _getViewData();
let different = bindingUpdated4(viewData[BINDING_INDEX], v0, v1, v2, v3);
different = bindingUpdated3(viewData[BINDING_INDEX] + 4, v4, v5, v6) || different;
@ -691,7 +686,6 @@ export function i18nInterpolation7(
export function i18nInterpolation8(
instructions: I18nExpInstruction[], v0: any, v1: any, v2: any, v3: any, v4: any, v5: any,
v6: any, v7: any): string|NO_CHANGE {
initBindings();
const viewData = _getViewData();
let different = bindingUpdated4(viewData[BINDING_INDEX], v0, v1, v2, v3);
different = bindingUpdated4(viewData[BINDING_INDEX] + 4, v4, v5, v6, v7) || different;
@ -733,7 +727,6 @@ export function i18nInterpolation8(
*/
export function i18nInterpolationV(instructions: I18nExpInstruction[], values: any[]): string|
NO_CHANGE {
initBindings();
const viewData = _getViewData();
let different = false;
for (let i = 0; i < values.length; i++) {

View File

@ -518,6 +518,7 @@ export function resetApplicationState() {
*
* @param hostNode Existing node to render into.
* @param templateFn Template function with the instructions.
* @param consts The number of nodes, local refs, and pipes in this template
* @param context to pass into the template.
* @param providedRendererFactory renderer factory to use
* @param host The host element node to use
@ -525,14 +526,14 @@ export function resetApplicationState() {
* @param pipes Pipe defs that should be used for matching
*/
export function renderTemplate<T>(
hostNode: RElement, templateFn: ComponentTemplate<T>, context: T,
hostNode: RElement, templateFn: ComponentTemplate<T>, consts: number, context: T,
providedRendererFactory: RendererFactory3, host: LElementNode | null,
directives?: DirectiveDefListOrFactory | null, pipes?: PipeDefListOrFactory | null,
sanitizer?: Sanitizer | null): LElementNode {
if (host == null) {
resetApplicationState();
rendererFactory = providedRendererFactory;
const tView = getOrCreateTView(templateFn, directives || null, pipes || null, null);
const tView = getOrCreateTView(templateFn, consts, directives || null, pipes || null, null);
host = createLNode(
-1, TNodeType.Element, hostNode, null, null,
createLViewData(
@ -598,6 +599,7 @@ export function renderEmbeddedTemplate<T>(
oldView = enterView(viewNode.data !, viewNode);
namespaceHTML();
viewData[BINDING_INDEX] = tView.bindingStartIndex;
tView.template !(rf, context);
if (rf & RenderFlags.Update) {
refreshDescendantViews();
@ -641,6 +643,7 @@ export function renderComponentOrTemplate<T>(
}
if (templateFn) {
namespaceHTML();
viewData[BINDING_INDEX] = tView.bindingStartIndex;
templateFn(getRenderFlags(hostView), componentOrContext !);
refreshDescendantViews();
} else {
@ -723,8 +726,9 @@ export function element(
*/
export function elementContainerStart(
index: number, attrs?: TAttributes | null, localRefs?: string[] | null): void {
ngDevMode &&
assertEqual(viewData[BINDING_INDEX], -1, 'elements should be created before any bindings');
ngDevMode && assertEqual(
viewData[BINDING_INDEX], tView.bindingStartIndex,
'element containers should be created before any bindings');
ngDevMode && ngDevMode.rendererCreateComment++;
const native = renderer.createComment(ngDevMode ? 'ng-container' : '');
@ -768,8 +772,9 @@ export function elementContainerEnd(): void {
*/
export function elementStart(
index: number, name: string, attrs?: TAttributes | null, localRefs?: string[] | null): void {
ngDevMode &&
assertEqual(viewData[BINDING_INDEX], -1, 'elements should be created before any bindings');
ngDevMode && assertEqual(
viewData[BINDING_INDEX], tView.bindingStartIndex,
'elements should be created before any bindings ');
ngDevMode && ngDevMode.rendererCreateElement++;
@ -1005,8 +1010,9 @@ function saveResolvedLocalsInData(
* @returns TView
*/
function getOrCreateTView(
templateFn: ComponentTemplate<any>, directives: DirectiveDefListOrFactory | null,
pipes: PipeDefListOrFactory | null, viewQuery: ComponentQuery<any>| null): TView {
templateFn: ComponentTemplate<any>, consts: number,
directives: DirectiveDefListOrFactory | null, pipes: PipeDefListOrFactory | null,
viewQuery: ComponentQuery<any>| null): TView {
// TODO(misko): reading `ngPrivateData` here is problematic for two reasons
// 1. It is a megamorphic call on each invocation.
// 2. For nested embedded views (ngFor inside ngFor) the template instance is per
@ -1014,19 +1020,22 @@ function getOrCreateTView(
// Correct solution is to only put `ngPrivateData` on the Component template
// and not on embedded templates.
return templateFn.ngPrivateData || (templateFn.ngPrivateData = createTView(
-1, templateFn, directives, pipes, viewQuery) as never);
return templateFn.ngPrivateData ||
(templateFn.ngPrivateData =
createTView(-1, templateFn, consts, directives, pipes, viewQuery) as never);
}
/**
* Creates a TView instance
*
* @param viewIndex The viewBlockId for inline views, or -1 if it's a component/dynamic
* @param templateFn Template function
* @param consts The number of nodes, local refs, and pipes in this template
* @param directives Registry of directives for this view
* @param pipes Registry of pipes for this view
*/
export function createTView(
viewIndex: number, templateFn: ComponentTemplate<any>| null,
viewIndex: number, templateFn: ComponentTemplate<any>| null, consts: number,
directives: DirectiveDefListOrFactory | null, pipes: PipeDefListOrFactory | null,
viewQuery: ComponentQuery<any>| null): TView {
ngDevMode && ngDevMode.tView++;
@ -1037,7 +1046,7 @@ export function createTView(
node: null !,
data: HEADER_FILLER.slice(), // Fill in to match HEADER_OFFSET in LViewData
childIndex: -1, // Children set in addToViewTree(), if any
bindingStartIndex: -1, // Set in initBindings()
bindingStartIndex: HEADER_OFFSET + consts,
directives: null,
firstTemplatePass: true,
initHooks: null,
@ -1137,7 +1146,8 @@ export function hostElement(
const node = createLNode(
0, TNodeType.Element, rNode, null, null,
createLViewData(
renderer, getOrCreateTView(def.template, def.directiveDefs, def.pipeDefs, def.viewQuery),
renderer, getOrCreateTView(
def.template, def.consts, def.directiveDefs, def.pipeDefs, def.viewQuery),
null, def.onPush ? LViewFlags.Dirty : LViewFlags.CheckAlways, sanitizer));
if (firstTemplatePass) {
@ -1590,8 +1600,9 @@ export function elementStylingMap<T>(
* @param value Value to write. This value will be stringified.
*/
export function text(index: number, value?: any): void {
ngDevMode &&
assertEqual(viewData[BINDING_INDEX], -1, 'text nodes should be created before bindings');
ngDevMode && assertEqual(
viewData[BINDING_INDEX], tView.bindingStartIndex,
'text nodes should be created before any bindings');
ngDevMode && ngDevMode.rendererCreateTextNode++;
const textNode = createTextNode(value, renderer);
const node = createLNode(index, TNodeType.Element, textNode, null, null);
@ -1667,7 +1678,8 @@ export function directiveCreate<T>(
function addComponentLogic<T>(
directiveIndex: number, instance: T, def: ComponentDefInternal<T>): void {
const tView = getOrCreateTView(def.template, def.directiveDefs, def.pipeDefs, def.viewQuery);
const tView =
getOrCreateTView(def.template, def.consts, def.directiveDefs, def.pipeDefs, def.viewQuery);
// Only component views should be added to the view tree directly. Embedded views are
// accessed through their containers because they may be removed / re-added later.
@ -1696,8 +1708,9 @@ function addComponentLogic<T>(
export function baseDirectiveCreate<T>(
index: number, directive: T,
directiveDef: DirectiveDefInternal<T>| ComponentDefInternal<T>): T {
ngDevMode &&
assertEqual(viewData[BINDING_INDEX], -1, 'directives should be created before any bindings');
ngDevMode && assertEqual(
viewData[BINDING_INDEX], tView.bindingStartIndex,
'directives should be created before any bindings');
ngDevMode && assertPreviousIsParent();
Object.defineProperty(
@ -1843,6 +1856,7 @@ export function createLContainer(
*
* @param index The index of the container in the data array
* @param templateFn Inline template
* @param consts The number of nodes, local refs, and pipes for this template
* @param tagName The name of the container element, if applicable
* @param attrs The attrs attached to the container, if applicable
* @param localRefs A set of local reference bindings on the element.
@ -1850,14 +1864,15 @@ export function createLContainer(
* Defaults to the current element associated with the local-ref.
*/
export function template(
index: number, templateFn: ComponentTemplate<any>| null, tagName?: string | null,
attrs?: TAttributes | null, localRefs?: string[] | null,
index: number, templateFn: ComponentTemplate<any>| null, consts: number,
tagName?: string | null, attrs?: TAttributes | null, localRefs?: string[] | null,
localRefExtractor?: LocalRefExtractor) {
// TODO: consider a separate node type for templates
const node = containerInternal(index, tagName || null, attrs || null, localRefs || null);
if (firstTemplatePass) {
node.tNode.tViews =
createTView(-1, templateFn, tView.directiveRegistry, tView.pipeRegistry, null);
createTView(-1, templateFn, consts, tView.directiveRegistry, tView.pipeRegistry, null);
}
createDirectivesAndLocals(node, localRefs, localRefExtractor);
@ -1884,9 +1899,9 @@ export function container(index: number): void {
function containerInternal(
index: number, tagName: string | null, attrs: TAttributes | null,
localRefs: string[] | null): LContainerNode {
ngDevMode &&
assertEqual(
viewData[BINDING_INDEX], -1, 'container nodes should be created before any bindings');
ngDevMode && assertEqual(
viewData[BINDING_INDEX], tView.bindingStartIndex,
'container nodes should be created before any bindings');
const currentParent = isParent ? previousOrParentNode : getParentLNode(previousOrParentNode) !;
const lContainer = createLContainer(currentParent, viewData);
@ -2010,7 +2025,7 @@ function scanForView(
* @param viewBlockId The ID of this view
* @return boolean Whether or not this view is in creation mode
*/
export function embeddedViewStart(viewBlockId: number): RenderFlags {
export function embeddedViewStart(viewBlockId: number, consts: number): RenderFlags {
const container =
(isParent ? previousOrParentNode : getParentLNode(previousOrParentNode)) as LContainerNode;
ngDevMode && assertNodeType(container, TNodeType.Container);
@ -2025,8 +2040,8 @@ export function embeddedViewStart(viewBlockId: number): RenderFlags {
} else {
// When we create a new LView, we always reset the state of the instructions.
const newView = createLViewData(
renderer, getOrCreateEmbeddedTView(viewBlockId, container), null, LViewFlags.CheckAlways,
getCurrentSanitizer());
renderer, getOrCreateEmbeddedTView(viewBlockId, consts, container), null,
LViewFlags.CheckAlways, getCurrentSanitizer());
if (lContainer[QUERIES]) {
newView[QUERIES] = lContainer[QUERIES] !.createView();
@ -2042,6 +2057,7 @@ export function embeddedViewStart(viewBlockId: number): RenderFlags {
}
lContainer[ACTIVE_INDEX] !++;
}
viewData[BINDING_INDEX] = tView.bindingStartIndex;
return getRenderFlags(viewNode.data);
}
@ -2053,17 +2069,19 @@ export function embeddedViewStart(viewBlockId: number): RenderFlags {
* it with the same index (since it's in the same template).
*
* @param viewIndex The index of the TView in TNode.tViews
* @param consts The number of nodes, local refs, and pipes in this template
* @param parent The parent container in which to look for the view's static data
* @returns TView
*/
function getOrCreateEmbeddedTView(viewIndex: number, parent: LContainerNode): TView {
function getOrCreateEmbeddedTView(
viewIndex: number, consts: number, parent: LContainerNode): TView {
ngDevMode && assertNodeType(parent, TNodeType.Container);
const containerTViews = (parent !.tNode as TContainerNode).tViews as TView[];
ngDevMode && assertDefined(containerTViews, 'TView expected');
ngDevMode && assertEqual(Array.isArray(containerTViews), true, 'TViews should be in an array');
if (viewIndex >= containerTViews.length || containerTViews[viewIndex] == null) {
containerTViews[viewIndex] =
createTView(viewIndex, null, tView.directiveRegistry, tView.pipeRegistry, null);
createTView(viewIndex, null, consts, tView.directiveRegistry, tView.pipeRegistry, null);
}
return containerTViews[viewIndex];
}
@ -2443,6 +2461,7 @@ export function detectChangesInternal<T>(
const hostTView = hostView[TVIEW];
const templateFn = hostTView.template !;
const viewQuery = hostTView.viewQuery;
viewData[BINDING_INDEX] = tView.bindingStartIndex;
try {
namespaceHTML();
@ -2501,43 +2520,17 @@ export interface NO_CHANGE {
/** A special value which designates that a value has not changed. */
export const NO_CHANGE = {} as NO_CHANGE;
/**
* Initializes the binding start index. Will get inlined.
*
* This function must be called before any binding related function is called
* (ie `bind()`, `interpolationX()`, `pureFunctionX()`)
*/
export function initBindings() {
// TODO(kara): remove this check when we have pre-filled array
if (tView.bindingStartIndex === -1) {
tView.bindingStartIndex = viewData.length;
}
if (viewData[BINDING_INDEX] === -1) {
viewData[BINDING_INDEX] = tView.bindingStartIndex;
}
}
/**
* Creates a single value binding.
*
* @param value Value to diff
*/
export function bind<T>(value: T): T|NO_CHANGE {
initBindings();
return bindingUpdated(viewData[BINDING_INDEX]++, value) ? value : NO_CHANGE;
}
// TODO(kara): Remove this when updating the compiler (cannot remove without breaking JIT test)
export function reserveSlots(numSlots: number) {
// Init the slots with a unique `NO_CHANGE` value so that the first change is always detected
// whether it happens or not during the first change detection pass - pure functions checks
// might be skipped when short-circuited.
viewData.length += numSlots;
viewData.fill(NO_CHANGE, -numSlots);
// We need to initialize the binding in case a `pureFunctionX` kind of binding instruction is
// called first in the update section.
initBindings();
}
export function reserveSlots(numSlots: number) {}
/**
* Create interpolation bindings with a variable number of expressions.
@ -2554,7 +2547,6 @@ export function reserveSlots(numSlots: number) {
export function interpolationV(values: any[]): string|NO_CHANGE {
ngDevMode && assertLessThan(2, values.length, 'should have at least 3 values');
ngDevMode && assertEqual(values.length % 2, 1, 'should have an odd number of values');
initBindings();
let different = false;
for (let i = 1; i < values.length; i += 2) {
@ -2583,7 +2575,6 @@ export function interpolationV(values: any[]): string|NO_CHANGE {
* @param suffix static value used for concatenation only.
*/
export function interpolation1(prefix: string, v0: any, suffix: string): string|NO_CHANGE {
initBindings();
const different = bindingUpdated(viewData[BINDING_INDEX]++, v0);
return different ? prefix + stringify(v0) + suffix : NO_CHANGE;
}
@ -2591,7 +2582,6 @@ export function interpolation1(prefix: string, v0: any, suffix: string): string|
/** Creates an interpolation binding with 2 expressions. */
export function interpolation2(
prefix: string, v0: any, i0: string, v1: any, suffix: string): string|NO_CHANGE {
initBindings();
const different = bindingUpdated2(viewData[BINDING_INDEX], v0, v1);
viewData[BINDING_INDEX] += 2;
@ -2602,7 +2592,6 @@ export function interpolation2(
export function interpolation3(
prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, suffix: string): string|
NO_CHANGE {
initBindings();
const different = bindingUpdated3(viewData[BINDING_INDEX], v0, v1, v2);
viewData[BINDING_INDEX] += 3;
@ -2614,7 +2603,6 @@ export function interpolation3(
export function interpolation4(
prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string, v3: any,
suffix: string): string|NO_CHANGE {
initBindings();
const different = bindingUpdated4(viewData[BINDING_INDEX], v0, v1, v2, v3);
viewData[BINDING_INDEX] += 4;
@ -2628,7 +2616,6 @@ export function interpolation4(
export function interpolation5(
prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string, v3: any,
i3: string, v4: any, suffix: string): string|NO_CHANGE {
initBindings();
let different = bindingUpdated4(viewData[BINDING_INDEX], v0, v1, v2, v3);
different = bindingUpdated(viewData[BINDING_INDEX] + 4, v4) || different;
viewData[BINDING_INDEX] += 5;
@ -2643,7 +2630,6 @@ export function interpolation5(
export function interpolation6(
prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string, v3: any,
i3: string, v4: any, i4: string, v5: any, suffix: string): string|NO_CHANGE {
initBindings();
let different = bindingUpdated4(viewData[BINDING_INDEX], v0, v1, v2, v3);
different = bindingUpdated2(viewData[BINDING_INDEX] + 4, v4, v5) || different;
viewData[BINDING_INDEX] += 6;
@ -2659,7 +2645,6 @@ export function interpolation7(
prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string, v3: any,
i3: string, v4: any, i4: string, v5: any, i5: string, v6: any, suffix: string): string|
NO_CHANGE {
initBindings();
let different = bindingUpdated4(viewData[BINDING_INDEX], v0, v1, v2, v3);
different = bindingUpdated3(viewData[BINDING_INDEX] + 4, v4, v5, v6) || different;
viewData[BINDING_INDEX] += 7;
@ -2675,7 +2660,6 @@ export function interpolation8(
prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string, v3: any,
i3: string, v4: any, i4: string, v5: any, i5: string, v6: any, i6: string, v7: any,
suffix: string): string|NO_CHANGE {
initBindings();
let different = bindingUpdated4(viewData[BINDING_INDEX], v0, v1, v2, v3);
different = bindingUpdated4(viewData[BINDING_INDEX] + 4, v4, v5, v6, v7) || different;
viewData[BINDING_INDEX] += 8;

View File

@ -201,6 +201,15 @@ export interface ComponentDef<T, Selector extends string> extends DirectiveDef<T
*/
readonly styles: string[];
/**
* The number of nodes, local refs, and pipes in this component template.
*
* Used to calculate the length of the component's LViewData array, so we
* can pre-fill the array and set the binding start index.
*/
// TODO(kara): remove queries from this count
consts: number;
/**
* Query-related instructions for a component.
*/

View File

@ -6,16 +6,16 @@
* found in the LICENSE file at https://angular.io/license
*/
import {bindingUpdated, bindingUpdated2, bindingUpdated4, updateBinding, getBinding, getCreationMode, getTView, initBindings, bindingUpdated3,} from './instructions';
import {bindingUpdated, bindingUpdated2, bindingUpdated4, updateBinding, getBinding, getCreationMode, getTView, bindingUpdated3,} from './instructions';
/**
* Bindings for pure functions are stored after regular bindings.
*
* ----------------------------------------------------------------------------
* | LNodes ... | regular bindings / interpolations | pure function bindings
* | LNodes / local refs / pipes ... | regular bindings / interpolations | pure function bindings
* ----------------------------------------------------------------------------
* ^
* TView.bindingStartIndex
* ^
* TView.bindingStartIndex
*
* Pure function instructions are given an offset from TView.bindingStartIndex.
* Adding the offset to TView.bindingStartIndex gives the first index where the bindings
@ -32,7 +32,7 @@ import {bindingUpdated, bindingUpdated2, bindingUpdated4, updateBinding, getBind
* @returns value
*/
export function pureFunction0<T>(slotOffset: number, pureFn: () => T, thisArg?: any): T {
initBindings(); // TODO(kara): remove this check when we have pre-filled array
// TODO(kara): use bindingRoot instead of bindingStartIndex when implementing host bindings
const bindingIndex = getTView().bindingStartIndex + slotOffset;
return getCreationMode() ?
updateBinding(bindingIndex, thisArg ? pureFn.call(thisArg) : pureFn()) :
@ -51,7 +51,7 @@ export function pureFunction0<T>(slotOffset: number, pureFn: () => T, thisArg?:
*/
export function pureFunction1(
slotOffset: number, pureFn: (v: any) => any, exp: any, thisArg?: any): any {
initBindings(); // TODO(kara): remove this check when we have pre-filled array
// TODO(kara): use bindingRoot instead of bindingStartIndex when implementing host bindings
const bindingIndex = getTView().bindingStartIndex + slotOffset;
return bindingUpdated(bindingIndex, exp) ?
updateBinding(bindingIndex + 1, thisArg ? pureFn.call(thisArg, exp) : pureFn(exp)) :
@ -72,7 +72,7 @@ export function pureFunction1(
export function pureFunction2(
slotOffset: number, pureFn: (v1: any, v2: any) => any, exp1: any, exp2: any,
thisArg?: any): any {
initBindings(); // TODO(kara): remove this check when we have pre-filled array
// TODO(kara): use bindingRoot instead of bindingStartIndex when implementing host bindings
const bindingIndex = getTView().bindingStartIndex + slotOffset;
return bindingUpdated2(bindingIndex, exp1, exp2) ?
updateBinding(
@ -95,7 +95,7 @@ export function pureFunction2(
export function pureFunction3(
slotOffset: number, pureFn: (v1: any, v2: any, v3: any) => any, exp1: any, exp2: any, exp3: any,
thisArg?: any): any {
initBindings(); // TODO(kara): remove this check when we have pre-filled array
// TODO(kara): use bindingRoot instead of bindingStartIndex when implementing host bindings
const bindingIndex = getTView().bindingStartIndex + slotOffset;
return bindingUpdated3(bindingIndex, exp1, exp2, exp3) ?
updateBinding(
@ -120,7 +120,7 @@ export function pureFunction3(
export function pureFunction4(
slotOffset: number, pureFn: (v1: any, v2: any, v3: any, v4: any) => any, exp1: any, exp2: any,
exp3: any, exp4: any, thisArg?: any): any {
initBindings(); // TODO(kara): remove this check when we have pre-filled array
// TODO(kara): use bindingRoot instead of bindingStartIndex when implementing host bindings
const bindingIndex = getTView().bindingStartIndex + slotOffset;
return bindingUpdated4(bindingIndex, exp1, exp2, exp3, exp4) ?
updateBinding(
@ -146,7 +146,7 @@ export function pureFunction4(
export function pureFunction5(
slotOffset: number, pureFn: (v1: any, v2: any, v3: any, v4: any, v5: any) => any, exp1: any,
exp2: any, exp3: any, exp4: any, exp5: any, thisArg?: any): any {
initBindings(); // TODO(kara): remove this check when we have pre-filled array
// TODO(kara): use bindingRoot instead of bindingStartIndex when implementing host bindings
const bindingIndex = getTView().bindingStartIndex + slotOffset;
const different = bindingUpdated4(bindingIndex, exp1, exp2, exp3, exp4);
return bindingUpdated(bindingIndex + 4, exp5) || different ?
@ -174,7 +174,7 @@ export function pureFunction5(
export function pureFunction6(
slotOffset: number, pureFn: (v1: any, v2: any, v3: any, v4: any, v5: any, v6: any) => any,
exp1: any, exp2: any, exp3: any, exp4: any, exp5: any, exp6: any, thisArg?: any): any {
initBindings(); // TODO(kara): remove this check when we have pre-filled array
// TODO(kara): use bindingRoot instead of bindingStartIndex when implementing host bindings
const bindingIndex = getTView().bindingStartIndex + slotOffset;
const different = bindingUpdated4(bindingIndex, exp1, exp2, exp3, exp4);
return bindingUpdated2(bindingIndex + 4, exp5, exp6) || different ?
@ -204,7 +204,7 @@ export function pureFunction7(
slotOffset: number,
pureFn: (v1: any, v2: any, v3: any, v4: any, v5: any, v6: any, v7: any) => any, exp1: any,
exp2: any, exp3: any, exp4: any, exp5: any, exp6: any, exp7: any, thisArg?: any): any {
initBindings(); // TODO(kara): remove this check when we have pre-filled array
// TODO(kara): use bindingRoot instead of bindingStartIndex when implementing host bindings
const bindingIndex = getTView().bindingStartIndex + slotOffset;
let different = bindingUpdated4(bindingIndex, exp1, exp2, exp3, exp4);
return bindingUpdated3(bindingIndex + 4, exp5, exp6, exp7) || different ?
@ -237,7 +237,7 @@ export function pureFunction8(
pureFn: (v1: any, v2: any, v3: any, v4: any, v5: any, v6: any, v7: any, v8: any) => any,
exp1: any, exp2: any, exp3: any, exp4: any, exp5: any, exp6: any, exp7: any, exp8: any,
thisArg?: any): any {
initBindings(); // TODO(kara): remove this check when we have pre-filled array
// TODO(kara): use bindingRoot instead of bindingStartIndex when implementing host bindings
const bindingIndex = getTView().bindingStartIndex + slotOffset;
const different = bindingUpdated4(bindingIndex, exp1, exp2, exp3, exp4);
return bindingUpdated4(bindingIndex + 4, exp5, exp6, exp7, exp8) || different ?
@ -263,7 +263,7 @@ export function pureFunction8(
*/
export function pureFunctionV(
slotOffset: number, pureFn: (...v: any[]) => any, exps: any[], thisArg?: any): any {
initBindings(); // TODO(kara): remove this check when we have pre-filled array
// TODO(kara): use bindingRoot instead of bindingStartIndex when implementing host bindings
let bindingIndex = getTView().bindingStartIndex + slotOffset;
let different = false;
for (let i = 0; i < exps.length; i++) {