diff --git a/packages/core/src/render3/component.ts b/packages/core/src/render3/component.ts index 7682ce0b6c..5fac476310 100644 --- a/packages/core/src/render3/component.ts +++ b/packages/core/src/render3/component.ts @@ -11,6 +11,7 @@ import {Type} from '../core'; import {Injector} from '../di/injector'; import {Sanitizer} from '../sanitization/security'; +import {assertDataInRange, assertEqual} from '../util/assert'; import {assertComponentType} from './assert'; import {getComponentDef} from './definition'; @@ -172,7 +173,9 @@ export function createRootComponentView( rendererFactory: RendererFactory3, renderer: Renderer3, sanitizer?: Sanitizer | null): LView { resetComponentState(); const tView = rootView[TVIEW]; - const tNode: TElementNode = createNodeAtIndex(0, TNodeType.Element, rNode, null, null); + ngDevMode && assertDataInRange(rootView, 0 + HEADER_OFFSET); + rootView[0 + HEADER_OFFSET] = rNode; + const tNode: TElementNode = createNodeAtIndex(0, TNodeType.Element, null, null); const componentView = createLView( rootView, getOrCreateTView(def), null, def.onPush ? LViewFlags.Dirty : LViewFlags.CheckAlways, rootView[HEADER_OFFSET], tNode, rendererFactory, renderer, sanitizer); diff --git a/packages/core/src/render3/i18n.ts b/packages/core/src/render3/i18n.ts index 0d9acf4c1a..940160ce15 100644 --- a/packages/core/src/render3/i18n.ts +++ b/packages/core/src/render3/i18n.ts @@ -12,7 +12,7 @@ import {SRCSET_ATTRS, URI_ATTRS, VALID_ATTRS, VALID_ELEMENTS, getTemplateContent import {InertBodyHelper} from '../sanitization/inert_body'; import {_sanitizeUrl, sanitizeSrcset} from '../sanitization/url_sanitizer'; import {addAllToArray} from '../util/array_utils'; -import {assertDefined, assertEqual, assertGreaterThan} from '../util/assert'; +import {assertDataInRange, assertDefined, assertEqual, assertGreaterThan} from '../util/assert'; import {attachPatchData} from './context_discovery'; import {attachI18nOpCodesDebug} from './debug'; @@ -671,10 +671,12 @@ function i18nEndFirstPass(tView: TView) { * Creates and stores the dynamic TNode, and unhooks it from the tree for now. */ function createDynamicNodeAtIndex( - index: number, type: TNodeType, native: RElement | RText | null, + lView: LView, index: number, type: TNodeType, native: RElement | RText | null, name: string | null): TElementNode|TIcuContainerNode { const previousOrParentTNode = getPreviousOrParentTNode(); - const tNode = createNodeAtIndex(index, type as any, native, name, null); + ngDevMode && assertDataInRange(lView, index + HEADER_OFFSET); + lView[index + HEADER_OFFSET] = native; + const tNode = createNodeAtIndex(index, type as any, name, null); // We are creating a dynamic node, the previous tNode might not be pointing at this node. // We will link ourselves into the tree later with `appendI18nNode`. @@ -699,7 +701,8 @@ function readCreateOpCodes( const textNodeIndex = createOpCodes[++i] as number; ngDevMode && ngDevMode.rendererCreateTextNode++; previousTNode = currentTNode; - currentTNode = createDynamicNodeAtIndex(textNodeIndex, TNodeType.Element, textRNode, null); + currentTNode = + createDynamicNodeAtIndex(viewData, textNodeIndex, TNodeType.Element, textRNode, null); visitedNodes.push(textNodeIndex); setIsNotParent(); } else if (typeof opCode == 'number') { @@ -755,7 +758,7 @@ function readCreateOpCodes( ngDevMode && ngDevMode.rendererCreateComment++; previousTNode = currentTNode; currentTNode = createDynamicNodeAtIndex( - commentNodeIndex, TNodeType.IcuContainer, commentRNode, null); + viewData, commentNodeIndex, TNodeType.IcuContainer, commentRNode, null); visitedNodes.push(commentNodeIndex); attachPatchData(commentRNode, viewData); (currentTNode as TIcuContainerNode).activeCaseIndex = null; @@ -772,7 +775,7 @@ function readCreateOpCodes( ngDevMode && ngDevMode.rendererCreateElement++; previousTNode = currentTNode; currentTNode = createDynamicNodeAtIndex( - elementNodeIndex, TNodeType.Element, elementRNode, tagNameValue); + viewData, elementNodeIndex, TNodeType.Element, elementRNode, tagNameValue); visitedNodes.push(elementNodeIndex); break; default: diff --git a/packages/core/src/render3/instructions/container.ts b/packages/core/src/render3/instructions/container.ts index 5dda4b18ee..f66e488bb7 100644 --- a/packages/core/src/render3/instructions/container.ts +++ b/packages/core/src/render3/instructions/container.ts @@ -5,7 +5,7 @@ * 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 {assertEqual} from '../../util/assert'; +import {assertDataInRange, assertEqual} from '../../util/assert'; import {assertHasParent} from '../assert'; import {attachPatchData} from '../context_discovery'; import {executePreOrderHooks, registerPostOrderHooks} from '../hooks'; @@ -164,9 +164,11 @@ function containerInternal( 'container nodes should be created before any bindings'); const adjustedIndex = index + HEADER_OFFSET; - const comment = lView[RENDERER].createComment(ngDevMode ? 'container' : ''); + ngDevMode && assertDataInRange(lView, index + HEADER_OFFSET); ngDevMode && ngDevMode.rendererCreateComment++; - const tNode = createNodeAtIndex(index, TNodeType.Container, comment, tagName, attrs); + const comment = lView[index + HEADER_OFFSET] = + lView[RENDERER].createComment(ngDevMode ? 'container' : ''); + const tNode = createNodeAtIndex(index, TNodeType.Container, tagName, attrs); const lContainer = lView[adjustedIndex] = createLContainer(lView[adjustedIndex], lView, comment, tNode); diff --git a/packages/core/src/render3/instructions/element.ts b/packages/core/src/render3/instructions/element.ts index ed404dbbf9..a603edca0f 100644 --- a/packages/core/src/render3/instructions/element.ts +++ b/packages/core/src/render3/instructions/element.ts @@ -14,7 +14,7 @@ import {TAttributes, TNodeFlags, TNodeType} from '../interfaces/node'; import {RElement, isProceduralRenderer} from '../interfaces/renderer'; import {SanitizerFn} from '../interfaces/sanitization'; import {StylingContext} from '../interfaces/styling'; -import {BINDING_INDEX, QUERIES, RENDERER, TVIEW} from '../interfaces/view'; +import {BINDING_INDEX, HEADER_OFFSET, QUERIES, RENDERER, TVIEW} from '../interfaces/view'; import {assertNodeType} from '../node_assert'; import {appendChild} from '../node_manipulation'; import {applyOnCreateInstructions} from '../node_util'; @@ -55,13 +55,10 @@ export function ɵɵelementStart( 'elements should be created before any bindings '); ngDevMode && ngDevMode.rendererCreateElement++; - - const native = elementCreate(name); + ngDevMode && assertDataInRange(lView, index + HEADER_OFFSET); + const native = lView[index + HEADER_OFFSET] = elementCreate(name); const renderer = lView[RENDERER]; - - ngDevMode && assertDataInRange(lView, index - 1); - - const tNode = createNodeAtIndex(index, TNodeType.Element, native !, name, attrs || null); + const tNode = createNodeAtIndex(index, TNodeType.Element, name, attrs || null); let initialStylesIndex = 0; let initialClassesIndex = 0; diff --git a/packages/core/src/render3/instructions/element_container.ts b/packages/core/src/render3/instructions/element_container.ts index 58db303b72..dac999f7a1 100644 --- a/packages/core/src/render3/instructions/element_container.ts +++ b/packages/core/src/render3/instructions/element_container.ts @@ -10,7 +10,7 @@ import {assertHasParent} from '../assert'; import {attachPatchData} from '../context_discovery'; import {registerPostOrderHooks} from '../hooks'; import {TAttributes, TNodeType} from '../interfaces/node'; -import {BINDING_INDEX, QUERIES, RENDERER, TVIEW} from '../interfaces/view'; +import {BINDING_INDEX, HEADER_OFFSET, QUERIES, RENDERER, TVIEW} from '../interfaces/view'; import {assertNodeType} from '../node_assert'; import {appendChild} from '../node_manipulation'; import {applyOnCreateInstructions} from '../node_util'; @@ -43,11 +43,11 @@ export function ɵɵelementContainerStart( 'element containers should be created before any bindings'); ngDevMode && ngDevMode.rendererCreateComment++; - const native = renderer.createComment(ngDevMode ? tagName : ''); + ngDevMode && assertDataInRange(lView, index + HEADER_OFFSET); + const native = lView[index + HEADER_OFFSET] = renderer.createComment(ngDevMode ? tagName : ''); ngDevMode && assertDataInRange(lView, index - 1); - const tNode = - createNodeAtIndex(index, TNodeType.ElementContainer, native, tagName, attrs || null); + const tNode = createNodeAtIndex(index, TNodeType.ElementContainer, tagName, attrs || null); if (attrs) { diff --git a/packages/core/src/render3/instructions/projection.ts b/packages/core/src/render3/instructions/projection.ts index e36df3b93e..efe348ee10 100644 --- a/packages/core/src/render3/instructions/projection.ts +++ b/packages/core/src/render3/instructions/projection.ts @@ -5,9 +5,10 @@ * 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 {assertDataInRange} from '../../util/assert'; import {TAttributes, TElementNode, TNode, TNodeType} from '../interfaces/node'; import {CssSelectorList} from '../interfaces/projection'; -import {T_HOST} from '../interfaces/view'; +import {HEADER_OFFSET, T_HOST} from '../interfaces/view'; import {appendProjectedNodes} from '../node_manipulation'; import {matchingProjectionSelectorIndex} from '../node_selector_matcher'; import {getLView, setIsNotParent} from '../state'; @@ -81,8 +82,7 @@ export function ɵɵprojectionDef(selectors?: CssSelectorList[]): void { export function ɵɵprojection( nodeIndex: number, selectorIndex: number = 0, attrs?: TAttributes): void { const lView = getLView(); - const tProjectionNode = - createNodeAtIndex(nodeIndex, TNodeType.Projection, null, null, attrs || null); + const tProjectionNode = createNodeAtIndex(nodeIndex, TNodeType.Projection, null, attrs || null); // We can't use viewData[HOST_NODE] because projection nodes can be nested in embedded views. if (tProjectionNode.projection === null) tProjectionNode.projection = selectorIndex; diff --git a/packages/core/src/render3/instructions/shared.ts b/packages/core/src/render3/instructions/shared.ts index 85c8eb853e..43dfcefe84 100644 --- a/packages/core/src/render3/instructions/shared.ts +++ b/packages/core/src/render3/instructions/shared.ts @@ -233,30 +233,26 @@ export function createLView( * @param attrs Any attrs for the native element, if applicable */ export function createNodeAtIndex( - index: number, type: TNodeType.Element, native: RElement | RText | null, name: string | null, + index: number, type: TNodeType.Element, name: string | null, attrs: TAttributes | null): TElementNode; export function createNodeAtIndex( - index: number, type: TNodeType.Container, native: RComment, name: string | null, + index: number, type: TNodeType.Container, name: string | null, attrs: TAttributes | null): TContainerNode; export function createNodeAtIndex( - index: number, type: TNodeType.Projection, native: null, name: null, + index: number, type: TNodeType.Projection, name: null, attrs: TAttributes | null): TProjectionNode; export function createNodeAtIndex( - index: number, type: TNodeType.ElementContainer, native: RComment, name: string | null, + index: number, type: TNodeType.ElementContainer, name: string | null, attrs: TAttributes | null): TElementContainerNode; export function createNodeAtIndex( - index: number, type: TNodeType.IcuContainer, native: RComment, name: null, + index: number, type: TNodeType.IcuContainer, name: null, attrs: TAttributes | null): TElementContainerNode; export function createNodeAtIndex( - index: number, type: TNodeType, native: RText | RElement | RComment | null, name: string | null, - attrs: TAttributes | null): TElementNode&TContainerNode&TElementContainerNode&TProjectionNode& - TIcuContainerNode { + index: number, type: TNodeType, name: string | null, attrs: TAttributes | null): TElementNode& + TContainerNode&TElementContainerNode&TProjectionNode&TIcuContainerNode { const lView = getLView(); const tView = lView[TVIEW]; const adjustedIndex = index + HEADER_OFFSET; - ngDevMode && - assertLessThan(adjustedIndex, lView.length, `Slot should have been initialized with null`); - lView[adjustedIndex] = native; const previousOrParentTNode = getPreviousOrParentTNode(); let tNode = tView.data[adjustedIndex] as TNode; diff --git a/packages/core/src/render3/instructions/text.ts b/packages/core/src/render3/instructions/text.ts index df0a539473..0833ddf958 100644 --- a/packages/core/src/render3/instructions/text.ts +++ b/packages/core/src/render3/instructions/text.ts @@ -30,8 +30,9 @@ export function ɵɵtext(index: number, value?: any): void { lView[BINDING_INDEX], lView[TVIEW].bindingStartIndex, 'text nodes should be created before any bindings'); ngDevMode && ngDevMode.rendererCreateTextNode++; - const textNative = createTextNode(value, lView[RENDERER]); - const tNode = createNodeAtIndex(index, TNodeType.Element, textNative, null, null); + ngDevMode && assertDataInRange(lView, index + HEADER_OFFSET); + const textNative = lView[index + HEADER_OFFSET] = createTextNode(value, lView[RENDERER]); + const tNode = createNodeAtIndex(index, TNodeType.Element, null, null); // Text nodes are self closing. setIsNotParent(); diff --git a/packages/core/test/render3/di_spec.ts b/packages/core/test/render3/di_spec.ts index 7ad45750f1..d4ac5315ab 100644 --- a/packages/core/test/render3/di_spec.ts +++ b/packages/core/test/render3/di_spec.ts @@ -605,7 +605,7 @@ describe('di', () => { null, null, {} as any, {} as any); const oldView = enterView(contentView, null); try { - const parentTNode = createNodeAtIndex(0, TNodeType.Element, null, null, null); + const parentTNode = createNodeAtIndex(0, TNodeType.Element, null, null); // Simulate the situation where the previous parent is not initialized. // This happens on first bootstrap because we don't init existing values // so that we have smaller HelloWorld.