refactor(core): Create `NodeInjectorOffset` type which better describes NodeInjector (#38707)
`NodeInjector` is store in expando as a list of values in an array. The offset constant into the array have been brought together into a single `NodeInjectorOffset` enum with better documentation explaining their usage. PR Close #38707
This commit is contained in:
parent
fc3b3fe39e
commit
494a2f3be4
|
@ -10,7 +10,7 @@ import {assertDefined, assertEqual, assertNumber, throwError} from '../util/asse
|
|||
import {getComponentDef, getNgModuleDef} from './definition';
|
||||
import {LContainer} from './interfaces/container';
|
||||
import {DirectiveDef} from './interfaces/definition';
|
||||
import {PARENT_INJECTOR} from './interfaces/injector';
|
||||
import {NodeInjectorOffset} from './interfaces/injector';
|
||||
import {TNode} from './interfaces/node';
|
||||
import {isLContainer, isLView} from './interfaces/type_checks';
|
||||
import {HEADER_OFFSET, LView, TVIEW, TView} from './interfaces/view';
|
||||
|
@ -136,7 +136,7 @@ export function assertBetween(lower: number, upper: number, index: number) {
|
|||
*/
|
||||
export function assertNodeInjector(lView: LView, injectorIndex: number) {
|
||||
assertIndexInExpandoRange(lView, injectorIndex);
|
||||
assertIndexInExpandoRange(lView, injectorIndex + PARENT_INJECTOR);
|
||||
assertIndexInExpandoRange(lView, injectorIndex + NodeInjectorOffset.PARENT);
|
||||
assertNumber(lView[injectorIndex + 0], 'injectorIndex should point to a bloom filter');
|
||||
assertNumber(lView[injectorIndex + 1], 'injectorIndex should point to a bloom filter');
|
||||
assertNumber(lView[injectorIndex + 2], 'injectorIndex should point to a bloom filter');
|
||||
|
@ -146,6 +146,6 @@ export function assertNodeInjector(lView: LView, injectorIndex: number) {
|
|||
assertNumber(lView[injectorIndex + 6], 'injectorIndex should point to a bloom filter');
|
||||
assertNumber(lView[injectorIndex + 7], 'injectorIndex should point to a bloom filter');
|
||||
assertNumber(
|
||||
lView[injectorIndex + 8 /*PARENT_INJECTOR*/],
|
||||
lView[injectorIndex + NodeInjectorOffset.PARENT],
|
||||
'injectorIndex should point to parent injector');
|
||||
}
|
||||
|
|
|
@ -207,7 +207,7 @@ function traverseNextElement(tNode: TNode): TNode|null {
|
|||
if (tNode.child && tNode.child.parent === tNode) {
|
||||
// FIXME(misko): checking if `tNode.child.parent === tNode` should not be necessary
|
||||
// We have added it here because i18n creates TNode's which are not valid, so this is a work
|
||||
// around. The i18n code is being refactored in #??? and once it lands this extra check can be
|
||||
// around. The i18n code will be refactored in #39003 and once it lands this extra check can be
|
||||
// deleted.
|
||||
return tNode.child;
|
||||
} else if (tNode.next) {
|
||||
|
|
|
@ -21,7 +21,7 @@ import {getFactoryDef} from './definition';
|
|||
import {NG_ELEMENT_ID, NG_FACTORY_DEF} from './fields';
|
||||
import {registerPreOrderHooks} from './hooks';
|
||||
import {DirectiveDef, FactoryFn} from './interfaces/definition';
|
||||
import {isFactory, NO_PARENT_INJECTOR, NodeInjectorFactory, PARENT_INJECTOR, RelativeInjectorLocation, RelativeInjectorLocationFlags, TNODE} from './interfaces/injector';
|
||||
import {isFactory, NO_PARENT_INJECTOR, NodeInjectorFactory, NodeInjectorOffset, RelativeInjectorLocation, RelativeInjectorLocationFlags} from './interfaces/injector';
|
||||
import {AttributeMarker, TContainerNode, TDirectiveHostNode, TElementContainerNode, TElementNode, TNode, TNodeProviderIndexes, TNodeType} from './interfaces/node';
|
||||
import {isComponentDef, isComponentHost} from './interfaces/type_checks';
|
||||
import {DECLARATION_COMPONENT_VIEW, DECLARATION_VIEW, INJECTOR, LView, T_HOST, TData, TVIEW, TView, TViewType} from './interfaces/view';
|
||||
|
@ -170,12 +170,12 @@ export function getOrCreateNodeInjectorForNode(
|
|||
const parentData = parentLView[TVIEW].data as any;
|
||||
// Creates a cumulative bloom filter that merges the parent's bloom filter
|
||||
// and its own cumulative bloom (which contains tokens for all ancestors)
|
||||
for (let i = 0; i < 8; i++) {
|
||||
for (let i = 0; i < NodeInjectorOffset.BLOOM_SIZE; i++) {
|
||||
lView[injectorIndex + i] = parentLView[parentIndex + i] | parentData[parentIndex + i];
|
||||
}
|
||||
}
|
||||
|
||||
lView[injectorIndex + PARENT_INJECTOR] = parentLoc;
|
||||
lView[injectorIndex + NodeInjectorOffset.PARENT] = parentLoc;
|
||||
return injectorIndex;
|
||||
}
|
||||
|
||||
|
@ -191,7 +191,7 @@ export function getInjectorIndex(tNode: TNode, lView: LView): number {
|
|||
(tNode.parent && tNode.parent.injectorIndex === tNode.injectorIndex) ||
|
||||
// After the first template pass, the injector index might exist but the parent values
|
||||
// might not have been calculated yet for this instance
|
||||
lView[tNode.injectorIndex + PARENT_INJECTOR] == null) {
|
||||
lView[tNode.injectorIndex + NodeInjectorOffset.PARENT] === null) {
|
||||
return -1;
|
||||
} else {
|
||||
ngDevMode && assertIndexInRange(lView, tNode.injectorIndex);
|
||||
|
@ -402,7 +402,7 @@ export function getOrCreateInjectable<T>(
|
|||
// searching the parent injector.
|
||||
if (injectorIndex === -1 || flags & InjectFlags.SkipSelf) {
|
||||
parentLocation = injectorIndex === -1 ? getParentInjectorLocation(tNode, lView) :
|
||||
lView[injectorIndex + PARENT_INJECTOR];
|
||||
lView[injectorIndex + NodeInjectorOffset.PARENT];
|
||||
|
||||
if (parentLocation === NO_PARENT_INJECTOR || !shouldSearchParent(flags, false)) {
|
||||
injectorIndex = -1;
|
||||
|
@ -420,7 +420,9 @@ export function getOrCreateInjectable<T>(
|
|||
|
||||
// Check the current injector. If it matches, see if it contains token.
|
||||
const tView = lView[TVIEW];
|
||||
ngDevMode && assertTNodeForLView(tView.data[injectorIndex + TNODE] as TNode, lView);
|
||||
ngDevMode &&
|
||||
assertTNodeForLView(
|
||||
tView.data[injectorIndex + NodeInjectorOffset.TNODE] as TNode, lView);
|
||||
if (bloomHasToken(bloomHash, injectorIndex, tView.data)) {
|
||||
// At this point, we have an injector which *may* contain the token, so we step through
|
||||
// the providers and directives associated with the injector's corresponding node to get
|
||||
|
@ -431,10 +433,11 @@ export function getOrCreateInjectable<T>(
|
|||
return instance;
|
||||
}
|
||||
}
|
||||
parentLocation = lView[injectorIndex + PARENT_INJECTOR];
|
||||
parentLocation = lView[injectorIndex + NodeInjectorOffset.PARENT];
|
||||
if (parentLocation !== NO_PARENT_INJECTOR &&
|
||||
shouldSearchParent(
|
||||
flags, lView[TVIEW].data[injectorIndex + TNODE] === hostTElementNode) &&
|
||||
flags,
|
||||
lView[TVIEW].data[injectorIndex + NodeInjectorOffset.TNODE] === hostTElementNode) &&
|
||||
bloomHasToken(bloomHash, injectorIndex, lView)) {
|
||||
// The def wasn't found anywhere on this node, so it was a false positive.
|
||||
// Traverse up the tree and continue searching.
|
||||
|
@ -485,7 +488,7 @@ function searchTokensOnInjector<T>(
|
|||
injectorIndex: number, lView: LView, token: Type<T>|InjectionToken<T>,
|
||||
previousTView: TView|null, flags: InjectFlags, hostTElementNode: TNode|null) {
|
||||
const currentTView = lView[TVIEW];
|
||||
const tNode = currentTView.data[injectorIndex + TNODE] as TNode;
|
||||
const tNode = currentTView.data[injectorIndex + NodeInjectorOffset.TNODE] as TNode;
|
||||
// First, we need to determine if view providers can be accessed by the starting element.
|
||||
// There are two possibilities
|
||||
const canAccessViewProviders = previousTView == null ?
|
||||
|
|
|
@ -16,7 +16,7 @@ import {assertNodeInjector} from '../assert';
|
|||
import {getInjectorIndex} from '../di';
|
||||
import {CONTAINER_HEADER_OFFSET, HAS_TRANSPLANTED_VIEWS, LContainer, MOVED_VIEWS, NATIVE} from '../interfaces/container';
|
||||
import {ComponentTemplate, DirectiveDef, DirectiveDefList, PipeDefList, ViewQueriesFunction} from '../interfaces/definition';
|
||||
import {NO_PARENT_INJECTOR, PARENT_INJECTOR, TNODE} from '../interfaces/injector';
|
||||
import {NO_PARENT_INJECTOR, NodeInjectorOffset} from '../interfaces/injector';
|
||||
import {AttributeMarker, PropertyAliases, TConstants, TContainerNode, TElementNode, TNode as ITNode, TNodeFlags, TNodeProviderIndexes, TNodeType, TNodeTypeAsString} from '../interfaces/node';
|
||||
import {SelectorFlags} from '../interfaces/projection';
|
||||
import {LQueries, TQueries} from '../interfaces/query';
|
||||
|
@ -218,9 +218,9 @@ class TNode implements ITNode {
|
|||
let injectorIndex = getInjectorIndex(this, lView);
|
||||
ngDevMode && assertNodeInjector(lView, injectorIndex);
|
||||
while (injectorIndex !== -1) {
|
||||
const tNode = lView[TVIEW].data[injectorIndex + TNODE] as TNode;
|
||||
const tNode = lView[TVIEW].data[injectorIndex + NodeInjectorOffset.TNODE] as TNode;
|
||||
path.push(buildDebugNode(tNode, lView));
|
||||
const parentLocation = lView[injectorIndex + PARENT_INJECTOR];
|
||||
const parentLocation = lView[injectorIndex + NodeInjectorOffset.PARENT];
|
||||
if (parentLocation === NO_PARENT_INJECTOR) {
|
||||
injectorIndex = -1;
|
||||
} else {
|
||||
|
|
|
@ -25,7 +25,7 @@ import {throwMultipleComponentError} from '../errors';
|
|||
import {executeCheckHooks, executeInitAndCheckHooks, incrementInitPhaseFlags} from '../hooks';
|
||||
import {CONTAINER_HEADER_OFFSET, HAS_TRANSPLANTED_VIEWS, LContainer, MOVED_VIEWS} from '../interfaces/container';
|
||||
import {ComponentDef, ComponentTemplate, DirectiveDef, DirectiveDefListOrFactory, PipeDefListOrFactory, RenderFlags, ViewQueriesFunction} from '../interfaces/definition';
|
||||
import {INJECTOR_BLOOM_PARENT_SIZE, NodeInjectorFactory} from '../interfaces/injector';
|
||||
import {NodeInjectorFactory, NodeInjectorOffset} from '../interfaces/injector';
|
||||
import {AttributeMarker, InitialInputData, InitialInputs, LocalRefExtractor, PropertyAliases, PropertyAliasValue, TAttributes, TConstantsOrFactory, TContainerNode, TDirectiveHostNode, TElementContainerNode, TElementNode, TIcuContainerNode, TNode, TNodeFlags, TNodeProviderIndexes, TNodeType, TProjectionNode} from '../interfaces/node';
|
||||
import {isProceduralRenderer, RComment, RElement, Renderer3, RendererFactory3, RNode, RText} from '../interfaces/renderer';
|
||||
import {SanitizerFn} from '../interfaces/sanitization';
|
||||
|
@ -88,7 +88,7 @@ export function setHostBindingsByExecutingExpandoInstructions(tView: TView, lVie
|
|||
|
||||
// Injector block and providers are taken into account.
|
||||
const providerCount = (expandoInstructions[++i] as number);
|
||||
bindingRootIndex += INJECTOR_BLOOM_PARENT_SIZE + providerCount;
|
||||
bindingRootIndex += NodeInjectorOffset.SIZE + providerCount;
|
||||
|
||||
currentDirectiveIndex = bindingRootIndex;
|
||||
} else {
|
||||
|
|
|
@ -15,13 +15,49 @@ import {TDirectiveHostNode} from './node';
|
|||
import {LView, TData} from './view';
|
||||
|
||||
/**
|
||||
* Offset from 'injectorIndex' where:
|
||||
* - `TViewData[injectorIndex + TNODE]` => `TNode` associated with the current injector.
|
||||
* - `LView[injectorIndex + TNODE]` => index to the parent injector.
|
||||
* Offsets of the `NodeInjector` data structure in the expando.
|
||||
*
|
||||
* `NodeInjector` is stored in both `LView` as well as `TView.data`. All storage requires 9 words.
|
||||
* First 8 are reserved for bloom filter and the 9th is reserved for the associated `TNode` as well
|
||||
* as parent `NodeInjector` pointer. All indexes are starting with `index` and have an offset as
|
||||
* shown.
|
||||
*
|
||||
* `LView` layout:
|
||||
* ```
|
||||
* index + 0: cumulative bloom filter
|
||||
* index + 1: cumulative bloom filter
|
||||
* index + 2: cumulative bloom filter
|
||||
* index + 3: cumulative bloom filter
|
||||
* index + 4: cumulative bloom filter
|
||||
* index + 5: cumulative bloom filter
|
||||
* index + 6: cumulative bloom filter
|
||||
* index + 7: cumulative bloom filter
|
||||
* index + 8: cumulative bloom filter
|
||||
* index + PARENT: Index to the parent injector. See `RelativeInjectorLocation`
|
||||
* `const parent = lView[index + NodeInjectorOffset.PARENT]`
|
||||
* ```
|
||||
*
|
||||
* `TViewData` layout:
|
||||
* ```
|
||||
* index + 0: cumulative bloom filter
|
||||
* index + 1: cumulative bloom filter
|
||||
* index + 2: cumulative bloom filter
|
||||
* index + 3: cumulative bloom filter
|
||||
* index + 4: cumulative bloom filter
|
||||
* index + 5: cumulative bloom filter
|
||||
* index + 6: cumulative bloom filter
|
||||
* index + 7: cumulative bloom filter
|
||||
* index + 8: cumulative bloom filter
|
||||
* index + TNODE: TNode associated with this `NodeInjector`
|
||||
* `canst tNode = tView.data[index + NodeInjectorOffset.TNODE]`
|
||||
* ```
|
||||
*/
|
||||
export const TNODE = 8;
|
||||
export const PARENT_INJECTOR = 8;
|
||||
export const INJECTOR_BLOOM_PARENT_SIZE = 9;
|
||||
export const enum NodeInjectorOffset {
|
||||
TNODE = 8,
|
||||
PARENT = 8,
|
||||
BLOOM_SIZE = 8,
|
||||
SIZE = 9,
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a relative location of parent injector.
|
||||
|
|
|
@ -22,7 +22,7 @@ import {assertLContainer, assertNodeInjector} from './assert';
|
|||
import {getParentInjectorLocation, NodeInjector} from './di';
|
||||
import {addToViewTree, createLContainer, createLView, renderView} from './instructions/shared';
|
||||
import {CONTAINER_HEADER_OFFSET, LContainer, NATIVE, VIEW_REFS} from './interfaces/container';
|
||||
import {TNODE} from './interfaces/injector';
|
||||
import {NodeInjectorOffset} from './interfaces/injector';
|
||||
import {TContainerNode, TDirectiveHostNode, TElementContainerNode, TElementNode, TNode, TNodeType} from './interfaces/node';
|
||||
import {isProceduralRenderer, RComment, RElement} from './interfaces/renderer';
|
||||
import {isComponentHost, isLContainer, isLView, isRootView} from './interfaces/type_checks';
|
||||
|
@ -190,7 +190,8 @@ export function createContainerRef(
|
|||
const parentView = getParentInjectorView(parentLocation, this._hostView);
|
||||
const injectorIndex = getParentInjectorIndex(parentLocation);
|
||||
ngDevMode && assertNodeInjector(parentView, injectorIndex);
|
||||
const parentTNode = parentView[TVIEW].data[injectorIndex + TNODE] as TElementNode;
|
||||
const parentTNode =
|
||||
parentView[TVIEW].data[injectorIndex + NodeInjectorOffset.TNODE] as TElementNode;
|
||||
return new NodeInjector(parentTNode, parentView);
|
||||
} else {
|
||||
return new NodeInjector(null, this._hostView);
|
||||
|
|
|
@ -9,11 +9,11 @@
|
|||
import {InjectFlags, Optional, Renderer2, Self} from '@angular/core';
|
||||
import {createLView, createTView, getOrCreateTNode} from '@angular/core/src/render3/instructions/shared';
|
||||
import {RenderFlags} from '@angular/core/src/render3/interfaces/definition';
|
||||
import {NodeInjectorOffset} from '@angular/core/src/render3/interfaces/injector';
|
||||
|
||||
import {ɵɵdefineComponent} from '../../src/render3/definition';
|
||||
import {bloomAdd, bloomHashBitOrFactory as bloomHash, bloomHasToken, getOrCreateNodeInjectorForNode} from '../../src/render3/di';
|
||||
import {ɵɵdefineDirective, ɵɵdirectiveInject, ɵɵelement, ɵɵelementEnd, ɵɵelementStart, ɵɵtext} from '../../src/render3/index';
|
||||
import {TNODE} from '../../src/render3/interfaces/injector';
|
||||
import {TNodeType} from '../../src/render3/interfaces/node';
|
||||
import {isProceduralRenderer} from '../../src/render3/interfaces/renderer';
|
||||
import {LViewFlags, TVIEW, TViewType} from '../../src/render3/interfaces/view';
|
||||
|
@ -150,7 +150,7 @@ describe('di', () => {
|
|||
});
|
||||
|
||||
function bloomState() {
|
||||
return mockTView.data.slice(0, TNODE).reverse();
|
||||
return mockTView.data.slice(0, NodeInjectorOffset.TNODE).reverse();
|
||||
}
|
||||
|
||||
class Dir0 {
|
||||
|
|
Loading…
Reference in New Issue