refactor(ivy): use generated consts value to set binding index (#25533)
PR Close #25533
This commit is contained in:

committed by
Jason Aden

parent
4708cb91ef
commit
f2aa9c6a7f
@ -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 {
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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++) {
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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++) {
|
||||
|
Reference in New Issue
Block a user