Skip to content

Commit

Permalink
refactor(core): Consistent use of HEADER_OFFSET (in ɵɵ* instructi…
Browse files Browse the repository at this point in the history
…ons only) (#39233)

IMPORTANT: `HEADER_OFFSET` should only be refereed to the in the `ɵɵ*` instructions to translate
instruction index into `LView` index. All other indexes should be in the `LView` index space and
there should be no need to refer to `HEADER_OFFSET` anywhere else.

PR Close #39233
  • Loading branch information
mhevery authored and alxhub committed Oct 22, 2020
1 parent f2fea8c commit 61e98f8
Show file tree
Hide file tree
Showing 34 changed files with 308 additions and 319 deletions.
2 changes: 1 addition & 1 deletion goldens/size-tracking/integration-payloads.json
Expand Up @@ -21,7 +21,7 @@
"master": {
"uncompressed": {
"runtime-es2015": 1485,
"main-es2015": 147242,
"main-es2015": 146698,
"polyfills-es2015": 36571
}
}
Expand Down
15 changes: 7 additions & 8 deletions packages/core/src/render3/component.ts
Expand Up @@ -12,7 +12,6 @@ import {Type} from '../core';
import {Injector} from '../di/injector';
import {Sanitizer} from '../sanitization/sanitizer';
import {assertDefined, assertIndexInRange} from '../util/assert';

import {assertComponentType} from './assert';
import {getComponentDef} from './definition';
import {diPublicInInjector, getOrCreateNodeInjectorForNode} from './di';
Expand Down Expand Up @@ -173,12 +172,13 @@ export function createRootComponentView(
rNode: RElement|null, def: ComponentDef<any>, rootView: LView,
rendererFactory: RendererFactory3, hostRenderer: Renderer3, sanitizer?: Sanitizer|null): LView {
const tView = rootView[TVIEW];
ngDevMode && assertIndexInRange(rootView, 0 + HEADER_OFFSET);
rootView[0 + HEADER_OFFSET] = rNode;
const index = HEADER_OFFSET;
ngDevMode && assertIndexInRange(rootView, index);
rootView[index] = rNode;
// '#host' is added here as we don't know the real host DOM name (we don't want to read it) and at
// the same time we want to communicate the the debug `TNode` that this is a special `TNode`
// representing a host element.
const tNode = getOrCreateTNode(tView, 0, TNodeType.Element, '#host', null);
const tNode: TElementNode = getOrCreateTNode(tView, index, TNodeType.Element, '#host', null);
const mergedAttrs = tNode.mergedAttrs = def.hostAttrs;
if (mergedAttrs !== null) {
computeStaticStyling(tNode, mergedAttrs, true);
Expand All @@ -196,7 +196,7 @@ export function createRootComponentView(
const viewRenderer = rendererFactory.createRenderer(rNode, def);
const componentView = createLView(
rootView, getOrCreateTComponentView(def), null,
def.onPush ? LViewFlags.Dirty : LViewFlags.CheckAlways, rootView[HEADER_OFFSET], tNode,
def.onPush ? LViewFlags.Dirty : LViewFlags.CheckAlways, rootView[index], tNode,
rendererFactory, viewRenderer, sanitizer || null, null);

if (tView.firstCreatePass) {
Expand All @@ -208,7 +208,7 @@ export function createRootComponentView(
addToViewTree(rootView, componentView);

// Store component view at node index, with node as the HOST
return rootView[HEADER_OFFSET] = componentView;
return rootView[index] = componentView;
}

/**
Expand Down Expand Up @@ -237,8 +237,7 @@ export function createRootComponent<T>(
ngDevMode && assertDefined(rootTNode, 'tNode should have been already created');
if (tView.firstCreatePass &&
(componentDef.hostBindings !== null || componentDef.hostAttrs !== null)) {
const elementIndex = rootTNode.index - HEADER_OFFSET;
setSelectedIndex(elementIndex);
setSelectedIndex(rootTNode.index);

const rootTView = rootLView[TVIEW];
addHostBindingsToExpandoInstructions(rootTView, componentDef);
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/render3/component_ref.ts
Expand Up @@ -27,7 +27,7 @@ import {createLView, createTView, locateHostElement, renderView} from './instruc
import {ComponentDef} from './interfaces/definition';
import {TContainerNode, TElementContainerNode, TElementNode, TNode} from './interfaces/node';
import {domRendererFactory3, RendererFactory3, RNode} from './interfaces/renderer';
import {LView, LViewFlags, TViewType} from './interfaces/view';
import {HEADER_OFFSET, LView, LViewFlags, TViewType} from './interfaces/view';
import {MATH_ML_NAMESPACE, SVG_NAMESPACE} from './namespaces';
import {createElementNode, writeDirectClass} from './node_manipulation';
import {extractAttrsAndClassesFromSelector, stringifyCSSSelectorList} from './node_selector_matcher';
Expand Down Expand Up @@ -192,7 +192,7 @@ export class ComponentFactory<T> extends viewEngine_ComponentFactory<T> {
}
}

tElementNode = getTNode(rootTView, 0) as TElementNode;
tElementNode = getTNode(rootTView, HEADER_OFFSET) as TElementNode;

if (projectableNodes !== undefined) {
const projection: (TNode|RNode[]|null)[] = tElementNode.projection = [];
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/render3/context_discovery.ts
Expand Up @@ -14,7 +14,7 @@ import {LContext, MONKEY_PATCH_KEY_NAME} from './interfaces/context';
import {TNode, TNodeFlags} from './interfaces/node';
import {RElement, RNode} from './interfaces/renderer';
import {CONTEXT, HEADER_OFFSET, HOST, LView, TVIEW} from './interfaces/view';
import {getComponentLViewByIndex, getNativeByTNodeOrNull, readPatchedData, unwrapRNode} from './util/view_utils';
import {getComponentLViewByIndex, readPatchedData, unwrapRNode} from './util/view_utils';



Expand Down
8 changes: 4 additions & 4 deletions packages/core/src/render3/i18n/i18n_apply.ts
Expand Up @@ -65,7 +65,7 @@ export function setMaskBit(hasChange: boolean) {
export function applyI18n(tView: TView, lView: LView, index: number) {
if (changeMaskCounter > 0) {
ngDevMode && assertDefined(tView, `tView should be defined`);
const tI18n = tView.data[index + HEADER_OFFSET] as TI18n | I18nUpdateOpCodes;
const tI18n = tView.data[index] as TI18n | I18nUpdateOpCodes;
// When `index` points to an `ɵɵi18nAttributes` then we have an array otherwise `TI18n`
const updateOpCodes: I18nUpdateOpCodes =
Array.isArray(tI18n) ? tI18n as I18nUpdateOpCodes : (tI18n as TI18n).update;
Expand Down Expand Up @@ -195,8 +195,8 @@ export function applyMutableOpCodes(
// This code is used for ICU expressions only, since we don't support
// directives/components in ICUs, we don't need to worry about inputs here
setElementAttribute(
renderer, getNativeByIndex(elementNodeIndex - HEADER_OFFSET, lView) as RElement, null,
null, attrName, attrValue, null);
renderer, getNativeByIndex(elementNodeIndex, lView) as RElement, null, null, attrName,
attrValue, null);
break;
default:
throw new Error(`Unable to determine the type of mutate operation for "${opCode}"`);
Expand Down Expand Up @@ -281,7 +281,7 @@ export function applyUpdateOpCodes(
const propName = updateOpCodes[++j] as string;
const sanitizeFn = updateOpCodes[++j] as SanitizerFn | null;
const tNodeOrTagName = tView.data[nodeIndex] as TNode | string;
ngDevMode && assertDefined(tNodeOrTagName, 'Expecting TNode or string');
ngDevMode && assertDefined(tNodeOrTagName, 'Experting TNode or string');
if (typeof tNodeOrTagName === 'string') {
// IF we don't have a `TNode`, then we are an element in ICU (as ICU content does
// not have TNode), in which case we know that there are no directives, and hence
Expand Down
33 changes: 6 additions & 27 deletions packages/core/src/render3/i18n/i18n_parse.ts
Expand Up @@ -132,7 +132,7 @@ export function i18nStartFirstCreatePass(
}
}

tView.data[index + HEADER_OFFSET] = <TI18n>{
tView.data[index] = <TI18n>{
create: createOpCodes,
update: updateOpCodes,
};
Expand Down Expand Up @@ -247,11 +247,11 @@ export function i18nAttributesFirstPass(
// Even indexes are text (including bindings)
const hasBinding = !!value.match(BINDING_REGEXP);
if (hasBinding) {
if (tView.firstCreatePass && tView.data[index + HEADER_OFFSET] === null) {
if (tView.firstCreatePass && tView.data[index] === null) {
generateBindingUpdateOpCodes(updateOpCodes, value, previousElementIndex, attrName);
}
} else {
const tNode = getTNode(tView, previousElementIndex - HEADER_OFFSET);
const tNode = getTNode(tView, previousElementIndex);
// Set attributes for Elements only, for other types (like ElementContainer),
// only set inputs below
if (tNode.type & TNodeType.AnyRNode) {
Expand All @@ -262,9 +262,7 @@ export function i18nAttributesFirstPass(
if (dataValue) {
setInputsForProperty(tView, lView, dataValue, attrName, value);
if (ngDevMode) {
const element =
getNativeByIndex(previousElementIndex - HEADER_OFFSET, lView) as RElement |
RComment;
const element = getNativeByIndex(previousElementIndex, lView) as RElement | RComment;
setNgReflectProperties(lView, element, tNode.type, dataValue, value);
}
}
Expand All @@ -273,8 +271,8 @@ export function i18nAttributesFirstPass(
}
}

if (tView.firstCreatePass && tView.data[index + HEADER_OFFSET] === null) {
tView.data[index + HEADER_OFFSET] = updateOpCodes;
if (tView.firstCreatePass && tView.data[index] === null) {
tView.data[index] = updateOpCodes;
}
}

Expand Down Expand Up @@ -329,25 +327,6 @@ export function generateBindingUpdateOpCodes(
return mask;
}

function getBindingMask(icuExpression: IcuExpression, mask = 0): number {
mask = mask | toMaskBit(icuExpression.mainBinding);
let match;
for (let i = 0; i < icuExpression.values.length; i++) {
const valueArr = icuExpression.values[i];
for (let j = 0; j < valueArr.length; j++) {
const value = valueArr[j];
if (typeof value === 'string') {
while (match = BINDING_REGEXP.exec(value)) {
mask = mask | toMaskBit(parseInt(match[1], 10));
}
} else {
mask = getBindingMask(value as IcuExpression, mask);
}
}
}
return mask;
}


/**
* Convert binding index to mask bit.
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/render3/instructions/advance.ts
Expand Up @@ -8,7 +8,7 @@
import {assertGreaterThan} from '../../util/assert';
import {assertIndexInDeclRange} from '../assert';
import {executeCheckHooks, executeInitAndCheckHooks} from '../hooks';
import {FLAGS, HEADER_OFFSET, InitPhaseState, LView, LViewFlags, TView} from '../interfaces/view';
import {FLAGS, InitPhaseState, LView, LViewFlags, TView} from '../interfaces/view';
import {getLView, getSelectedIndex, getTView, isInCheckNoChangesMode, setSelectedIndex} from '../state';


Expand Down Expand Up @@ -42,7 +42,7 @@ export function ɵɵadvance(delta: number): void {

export function selectIndexInternal(
tView: TView, lView: LView, index: number, checkNoChangesMode: boolean) {
ngDevMode && assertIndexInDeclRange(lView, index + HEADER_OFFSET);
ngDevMode && assertIndexInDeclRange(lView, index);

// Flush the initial hooks for elements in the view that have been added up to this point.
// PERF WARNING: do NOT extract this to a separate function without running benchmarks
Expand Down
3 changes: 2 additions & 1 deletion packages/core/src/render3/instructions/element.ts
Expand Up @@ -83,7 +83,8 @@ export function ɵɵelementStart(
const renderer = lView[RENDERER];
const native = lView[adjustedIndex] = createElementNode(renderer, name, getNamespace());
const tNode = tView.firstCreatePass ?
elementStartFirstCreatePass(index, tView, lView, native, name, attrsIndex, localRefsIndex) :
elementStartFirstCreatePass(
adjustedIndex, tView, lView, native, name, attrsIndex, localRefsIndex) :
tView.data[adjustedIndex] as TElementNode;
setCurrentTNode(tNode, true);

Expand Down
3 changes: 2 additions & 1 deletion packages/core/src/render3/instructions/element_container.ts
Expand Up @@ -72,7 +72,8 @@ export function ɵɵelementContainerStart(
'element containers should be created before any bindings');

const tNode = tView.firstCreatePass ?
elementContainerStartFirstCreatePass(index, tView, lView, attrsIndex, localRefsIndex) :
elementContainerStartFirstCreatePass(
adjustedIndex, tView, lView, attrsIndex, localRefsIndex) :
tView.data[adjustedIndex] as TElementContainerNode;
setCurrentTNode(tNode, true);

Expand Down
9 changes: 5 additions & 4 deletions packages/core/src/render3/instructions/i18n.ts
Expand Up @@ -49,15 +49,16 @@ export function ɵɵi18nStart(
index: number, messageIndex: number, subTemplateIndex: number = -1): void {
const tView = getTView();
const lView = getLView();
const adjustedIndex = HEADER_OFFSET + index;
ngDevMode && assertDefined(tView, `tView should be defined`);
const message = getConstant<string>(tView.consts, messageIndex)!;
const parentTNode = getCurrentParentTNode() as TElementNode | null;
if (tView.firstCreatePass) {
i18nStartFirstCreatePass(
tView, parentTNode === null ? 0 : parentTNode.index, lView, index, message,
tView, parentTNode === null ? 0 : parentTNode.index, lView, adjustedIndex, message,
subTemplateIndex);
}
const tI18n = tView.data[HEADER_OFFSET + index] as TI18n;
const tI18n = tView.data[adjustedIndex] as TI18n;
const sameViewParentTNode = parentTNode === lView[T_HOST] ? null : parentTNode;
const parentRNode = getClosestRElement(tView, sameViewParentTNode, lView);
// If `parentTNode` is an `ElementContainer` than it has `<!--ng-container--->`.
Expand Down Expand Up @@ -125,7 +126,7 @@ export function ɵɵi18nAttributes(index: number, attrsIndex: number): void {
const tView = getTView();
ngDevMode && assertDefined(tView, `tView should be defined`);
const attrs = getConstant<string[]>(tView.consts, attrsIndex)!;
i18nAttributesFirstPass(lView, tView, index, attrs);
i18nAttributesFirstPass(lView, tView, index + HEADER_OFFSET, attrs);
}


Expand Down Expand Up @@ -154,7 +155,7 @@ export function ɵɵi18nExp<T>(value: T): typeof ɵɵi18nExp {
* @codeGenApi
*/
export function ɵɵi18nApply(index: number) {
applyI18n(getTView(), getLView(), index);
applyI18n(getTView(), getLView(), index + HEADER_OFFSET);
}

/**
Expand Down
15 changes: 0 additions & 15 deletions packages/core/src/render3/instructions/lview_debug.ts
Expand Up @@ -676,18 +676,3 @@ export class LContainerDebug implements ILContainerDebug {
return toDebug(this._raw_lContainer[NEXT]);
}
}

/**
* Return an `LView` value if found.
*
* @param value `LView` if any
*/
export function readLViewValue(value: any): LView|null {
while (Array.isArray(value)) {
// This check is not quite right, as it does not take into account `StylingContext`
// This is why it is in debug, not in util.ts
if (value.length >= HEADER_OFFSET - 1) return value as LView;
value = value[HOST];
}
return null;
}
4 changes: 2 additions & 2 deletions packages/core/src/render3/instructions/projection.ts
Expand Up @@ -8,7 +8,7 @@
import {newArray} from '../../util/array_utils';
import {TAttributes, TElementNode, TNode, TNodeFlags, TNodeType} from '../interfaces/node';
import {ProjectionSlots} from '../interfaces/projection';
import {DECLARATION_COMPONENT_VIEW, T_HOST} from '../interfaces/view';
import {DECLARATION_COMPONENT_VIEW, HEADER_OFFSET, T_HOST} from '../interfaces/view';
import {applyProjection} from '../node_manipulation';
import {getProjectAsAttrValue, isNodeMatchingSelectorList, isSelectorInSelectorList} from '../node_selector_matcher';
import {getLView, getTView, setCurrentTNodeAsNotParent} from '../state';
Expand Down Expand Up @@ -120,7 +120,7 @@ export function ɵɵprojection(
const lView = getLView();
const tView = getTView();
const tProjectionNode =
getOrCreateTNode(tView, nodeIndex, TNodeType.Projection, null, attrs || null);
getOrCreateTNode(tView, HEADER_OFFSET + 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;
Expand Down

0 comments on commit 61e98f8

Please sign in to comment.