refactor(ivy): flatten LInjector into LViewData (#26220)
PR Close #26220
This commit is contained in:
parent
cb59d87489
commit
730679964f
|
@ -47,10 +47,7 @@ class Render3DebugContext implements DebugContext {
|
|||
get injector(): Injector {
|
||||
if (this.nodeIndex !== null) {
|
||||
const tNode = this.view[TVIEW].data[this.nodeIndex];
|
||||
const nodeInjector = di.getInjector(tNode, this.view);
|
||||
if (nodeInjector) {
|
||||
return new di.NodeInjector(nodeInjector);
|
||||
}
|
||||
return new di.NodeInjector(tNode, this.view);
|
||||
}
|
||||
return Injector.NULL;
|
||||
}
|
||||
|
|
|
@ -20,10 +20,10 @@ import {getComponentDef, getDirectiveDef, getPipeDef} from './definition';
|
|||
import {NG_ELEMENT_ID} from './fields';
|
||||
import {_getViewData, assertPreviousIsParent, getPreviousOrParentTNode, resolveDirective, setEnvironment} from './instructions';
|
||||
import {DirectiveDefInternal} from './interfaces/definition';
|
||||
import {LInjector} from './interfaces/injector';
|
||||
import {INJECTOR_SIZE, InjectorLocationFlags, PARENT_INJECTOR, TNODE,} from './interfaces/injector';
|
||||
import {AttributeMarker, TContainerNode, TElementContainerNode, TElementNode, TNode, TNodeFlags, TNodeType} from './interfaces/node';
|
||||
import {isProceduralRenderer} from './interfaces/renderer';
|
||||
import {DECLARATION_VIEW, DIRECTIVES, HOST_NODE, INJECTOR, LViewData, RENDERER, TVIEW, TView} from './interfaces/view';
|
||||
import {DECLARATION_VIEW, DIRECTIVES, HOST_NODE, INJECTOR, LViewData, PARENT, RENDERER, TData, TVIEW, TView} from './interfaces/view';
|
||||
import {assertNodeOfPossibleTypes} from './node_assert';
|
||||
|
||||
/**
|
||||
|
@ -41,43 +41,47 @@ let nextNgElementId = 0;
|
|||
* Registers this directive as present in its node's injector by flipping the directive's
|
||||
* corresponding bit in the injector's bloom filter.
|
||||
*
|
||||
* @param injector The node injector in which the directive should be registered
|
||||
* @param type The directive to register
|
||||
* @param injectorIndex The index of the node injector where this token should be registered
|
||||
* @param tView The TView for the injector's bloom filters
|
||||
* @param type The directive token to register
|
||||
*/
|
||||
export function bloomAdd(injector: LInjector, type: Type<any>): void {
|
||||
let id: number|undefined = (type as any)[NG_ELEMENT_ID];
|
||||
export function bloomAdd(injectorIndex: number, tView: TView, type: Type<any>): void {
|
||||
if (tView.firstTemplatePass) {
|
||||
let id: number|undefined = (type as any)[NG_ELEMENT_ID];
|
||||
|
||||
// Set a unique ID on the directive type, so if something tries to inject the directive,
|
||||
// we can easily retrieve the ID and hash it into the bloom bit that should be checked.
|
||||
if (id == null) {
|
||||
id = (type as any)[NG_ELEMENT_ID] = nextNgElementId++;
|
||||
}
|
||||
// Set a unique ID on the directive type, so if something tries to inject the directive,
|
||||
// we can easily retrieve the ID and hash it into the bloom bit that should be checked.
|
||||
if (id == null) {
|
||||
id = (type as any)[NG_ELEMENT_ID] = nextNgElementId++;
|
||||
}
|
||||
|
||||
// We only have BLOOM_SIZE (256) slots in our bloom filter (8 buckets * 32 bits each),
|
||||
// so all unique IDs must be modulo-ed into a number from 0 - 255 to fit into the filter.
|
||||
const bloomBit = id & BLOOM_MASK;
|
||||
// We only have BLOOM_SIZE (256) slots in our bloom filter (8 buckets * 32 bits each),
|
||||
// so all unique IDs must be modulo-ed into a number from 0 - 255 to fit into the filter.
|
||||
const bloomBit = id & BLOOM_MASK;
|
||||
|
||||
// Create a mask that targets the specific bit associated with the directive.
|
||||
// JS bit operations are 32 bits, so this will be a number between 2^0 and 2^31, corresponding
|
||||
// to bit positions 0 - 31 in a 32 bit integer.
|
||||
const mask = 1 << bloomBit;
|
||||
// Create a mask that targets the specific bit associated with the directive.
|
||||
// JS bit operations are 32 bits, so this will be a number between 2^0 and 2^31, corresponding
|
||||
// to bit positions 0 - 31 in a 32 bit integer.
|
||||
const mask = 1 << bloomBit;
|
||||
|
||||
// Use the raw bloomBit number to determine which bloom filter bucket we should check
|
||||
// e.g: bf0 = [0 - 31], bf1 = [32 - 63], bf2 = [64 - 95], bf3 = [96 - 127], etc
|
||||
const b7 = bloomBit & 0x80;
|
||||
const b6 = bloomBit & 0x40;
|
||||
const b5 = bloomBit & 0x20;
|
||||
// Use the raw bloomBit number to determine which bloom filter bucket we should check
|
||||
// e.g: bf0 = [0 - 31], bf1 = [32 - 63], bf2 = [64 - 95], bf3 = [96 - 127], etc
|
||||
const b7 = bloomBit & 0x80;
|
||||
const b6 = bloomBit & 0x40;
|
||||
const b5 = bloomBit & 0x20;
|
||||
const tData = tView.data as number[];
|
||||
|
||||
if (b7) {
|
||||
b6 ? (b5 ? (injector.bf7 |= mask) : (injector.bf6 |= mask)) :
|
||||
(b5 ? (injector.bf5 |= mask) : (injector.bf4 |= mask));
|
||||
} else {
|
||||
b6 ? (b5 ? (injector.bf3 |= mask) : (injector.bf2 |= mask)) :
|
||||
(b5 ? (injector.bf1 |= mask) : (injector.bf0 |= mask));
|
||||
if (b7) {
|
||||
b6 ? (b5 ? (tData[injectorIndex + 7] |= mask) : (tData[injectorIndex + 6] |= mask)) :
|
||||
(b5 ? (tData[injectorIndex + 5] |= mask) : (tData[injectorIndex + 4] |= mask));
|
||||
} else {
|
||||
b6 ? (b5 ? (tData[injectorIndex + 3] |= mask) : (tData[injectorIndex + 2] |= mask)) :
|
||||
(b5 ? (tData[injectorIndex + 1] |= mask) : (tData[injectorIndex] |= mask));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function getOrCreateNodeInjector(): LInjector {
|
||||
export function getOrCreateNodeInjector(): number {
|
||||
ngDevMode && assertPreviousIsParent();
|
||||
return getOrCreateNodeInjectorForNode(
|
||||
getPreviousOrParentTNode() as TElementNode | TElementContainerNode | TContainerNode,
|
||||
|
@ -92,67 +96,97 @@ export function getOrCreateNodeInjector(): LInjector {
|
|||
* @returns Node injector
|
||||
*/
|
||||
export function getOrCreateNodeInjectorForNode(
|
||||
tNode: TElementNode | TContainerNode | TElementContainerNode, hostView: LViewData): LInjector {
|
||||
const injector = getInjector(tNode, hostView);
|
||||
if (injector) return injector;
|
||||
tNode: TElementNode | TContainerNode | TElementContainerNode, hostView: LViewData): number {
|
||||
const existingInjectorIndex = getInjectorIndex(tNode, hostView);
|
||||
if (existingInjectorIndex !== -1) {
|
||||
return existingInjectorIndex;
|
||||
}
|
||||
|
||||
const tView = hostView[TVIEW];
|
||||
if (tView.firstTemplatePass) {
|
||||
// TODO(kara): Store node injector with host bindings for that node (see VIEW_DATA.md)
|
||||
tNode.injectorIndex = hostView.length;
|
||||
tView.blueprint.push(null);
|
||||
tView.hostBindingStartIndex++;
|
||||
tView.blueprint.push(0, 0, 0, 0, 0, 0, 0, 0, null); // foundation for cumulative bloom
|
||||
tView.data.push(0, 0, 0, 0, 0, 0, 0, 0, tNode); // foundation for node bloom
|
||||
tView.hostBindingStartIndex += INJECTOR_SIZE;
|
||||
}
|
||||
|
||||
const parentInjector = getParentInjector(tNode, hostView);
|
||||
return hostView[tNode.injectorIndex] = {
|
||||
parent: parentInjector,
|
||||
tNode: tNode,
|
||||
view: hostView,
|
||||
bf0: 0,
|
||||
bf1: 0,
|
||||
bf2: 0,
|
||||
bf3: 0,
|
||||
bf4: 0,
|
||||
bf5: 0,
|
||||
bf6: 0,
|
||||
bf7: 0,
|
||||
cbf0: parentInjector == null ? 0 : parentInjector.cbf0 | parentInjector.bf0,
|
||||
cbf1: parentInjector == null ? 0 : parentInjector.cbf1 | parentInjector.bf1,
|
||||
cbf2: parentInjector == null ? 0 : parentInjector.cbf2 | parentInjector.bf2,
|
||||
cbf3: parentInjector == null ? 0 : parentInjector.cbf3 | parentInjector.bf3,
|
||||
cbf4: parentInjector == null ? 0 : parentInjector.cbf4 | parentInjector.bf4,
|
||||
cbf5: parentInjector == null ? 0 : parentInjector.cbf5 | parentInjector.bf5,
|
||||
cbf6: parentInjector == null ? 0 : parentInjector.cbf6 | parentInjector.bf6,
|
||||
cbf7: parentInjector == null ? 0 : parentInjector.cbf7 | parentInjector.bf7,
|
||||
};
|
||||
const parentLoc = getParentInjectorLocation(tNode, hostView);
|
||||
const parentIndex = parentLoc & InjectorLocationFlags.InjectorIndexMask;
|
||||
const parentView: LViewData = getParentInjectorView(parentLoc, hostView);
|
||||
|
||||
const parentData = parentView[TVIEW].data as any;
|
||||
const injectorIndex = tNode.injectorIndex;
|
||||
|
||||
for (let i = 0; i < PARENT_INJECTOR; i++) {
|
||||
const bloomIndex = parentIndex + i;
|
||||
hostView[injectorIndex + i] =
|
||||
parentLoc === -1 ? 0 : parentView[bloomIndex] | parentData[bloomIndex];
|
||||
}
|
||||
|
||||
hostView[injectorIndex + PARENT_INJECTOR] = parentLoc;
|
||||
return injectorIndex;
|
||||
}
|
||||
|
||||
export function getInjector(tNode: TNode, view: LViewData): LInjector|null {
|
||||
// If the injector index is the same as its parent's injector index, then the index has been
|
||||
// copied down from the parent node. No injector has been created yet on this node.
|
||||
export function getInjectorIndex(tNode: TNode, hostView: LViewData): number {
|
||||
if (tNode.injectorIndex === -1 ||
|
||||
tNode.parent && tNode.parent.injectorIndex === tNode.injectorIndex) {
|
||||
return null;
|
||||
// If the injector index is the same as its parent's injector index, then the index has been
|
||||
// copied down from the parent node. No injector has been created yet on this node.
|
||||
(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
|
||||
hostView[tNode.injectorIndex + PARENT_INJECTOR] == null) {
|
||||
return -1;
|
||||
} else {
|
||||
return view[tNode.injectorIndex];
|
||||
return tNode.injectorIndex;
|
||||
}
|
||||
}
|
||||
|
||||
export function getParentInjector(tNode: TNode, view: LViewData): LInjector {
|
||||
/**
|
||||
* Finds the index of the parent injector, with a view offset if applicable. Used to set the
|
||||
* parent injector initially.
|
||||
*/
|
||||
export function getParentInjectorLocation(tNode: TNode, view: LViewData): number {
|
||||
if (tNode.parent && tNode.parent.injectorIndex !== -1) {
|
||||
return view[tNode.parent.injectorIndex];
|
||||
return tNode.parent.injectorIndex; // view offset is 0
|
||||
}
|
||||
|
||||
// For most cases, the parent injector index can be found on the host node (e.g. for component
|
||||
// or container), so this loop will be skipped, but we must keep the loop here to support
|
||||
// the rarer case of deeply nested <ng-template> tags.
|
||||
// the rarer case of deeply nested <ng-template> tags or inline views.
|
||||
let hostTNode = view[HOST_NODE];
|
||||
let viewOffset = 1;
|
||||
while (hostTNode && hostTNode.injectorIndex === -1) {
|
||||
view = view[DECLARATION_VIEW] !;
|
||||
hostTNode = view[HOST_NODE] !;
|
||||
viewOffset++;
|
||||
}
|
||||
return hostTNode ? view[DECLARATION_VIEW] ![hostTNode.injectorIndex] : null;
|
||||
return hostTNode ?
|
||||
hostTNode.injectorIndex | (viewOffset << InjectorLocationFlags.ViewOffsetShift) :
|
||||
-1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unwraps a parent injector location number to find the view offset from the current injector,
|
||||
* then walks up the declaration view tree until the view is found that contains the parent
|
||||
* injector.
|
||||
*
|
||||
* @param location The location of the parent injector, which contains the view offset
|
||||
* @param startView The LViewData instance from which to start walking up the view tree
|
||||
* @returns The LViewData instance that contains the parent injector
|
||||
*/
|
||||
export function getParentInjectorView(location: number, startView: LViewData): LViewData {
|
||||
let viewOffset = location >> InjectorLocationFlags.ViewOffsetShift;
|
||||
let parentView = startView;
|
||||
// For most cases, the parent injector can be found on the host node (e.g. for component
|
||||
// or container), but we must keep the loop here to support the rarer case of deeply nested
|
||||
// <ng-template> tags or inline views, where the parent injector might live many views
|
||||
// above the child injector.
|
||||
while (viewOffset > 0) {
|
||||
parentView = parentView[DECLARATION_VIEW] !;
|
||||
viewOffset--;
|
||||
}
|
||||
return parentView;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -161,8 +195,9 @@ export function getParentInjector(tNode: TNode, view: LViewData): LInjector {
|
|||
* @param di The node injector in which a directive will be added
|
||||
* @param def The definition of the directive to be made public
|
||||
*/
|
||||
export function diPublicInInjector(di: LInjector, def: DirectiveDefInternal<any>): void {
|
||||
bloomAdd(di, def.type);
|
||||
export function diPublicInInjector(
|
||||
injectorIndex: number, view: LViewData, def: DirectiveDefInternal<any>): void {
|
||||
bloomAdd(injectorIndex, view[TVIEW], def.type);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -171,7 +206,7 @@ export function diPublicInInjector(di: LInjector, def: DirectiveDefInternal<any>
|
|||
* @param def The definition of the directive to be made public
|
||||
*/
|
||||
export function diPublic(def: DirectiveDefInternal<any>): void {
|
||||
diPublicInInjector(getOrCreateNodeInjector(), def);
|
||||
diPublicInInjector(getOrCreateNodeInjector(), _getViewData(), def);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -199,11 +234,11 @@ export function directiveInject<T>(token: Type<T>| InjectionToken<T>): T;
|
|||
export function directiveInject<T>(token: Type<T>| InjectionToken<T>, flags: InjectFlags): T;
|
||||
export function directiveInject<T>(
|
||||
token: Type<T>| InjectionToken<T>, flags = InjectFlags.Default): T|null {
|
||||
return getOrCreateInjectable<T>(getOrCreateNodeInjector(), token, flags);
|
||||
return getOrCreateInjectable<T>(getOrCreateNodeInjector(), _getViewData(), token, flags);
|
||||
}
|
||||
|
||||
export function injectRenderer2(): Renderer2 {
|
||||
return getOrCreateRenderer2(getOrCreateNodeInjector());
|
||||
return getOrCreateRenderer2(_getViewData());
|
||||
}
|
||||
/**
|
||||
* Inject static attribute value into directive constructor.
|
||||
|
@ -254,8 +289,8 @@ export function injectAttribute(attrNameToInject: string): string|undefined {
|
|||
return undefined;
|
||||
}
|
||||
|
||||
function getOrCreateRenderer2(di: LInjector): Renderer2 {
|
||||
const renderer = di.view[RENDERER];
|
||||
function getOrCreateRenderer2(view: LViewData): Renderer2 {
|
||||
const renderer = view[RENDERER];
|
||||
if (isProceduralRenderer(renderer)) {
|
||||
return renderer as Renderer2;
|
||||
} else {
|
||||
|
@ -275,7 +310,7 @@ function getOrCreateRenderer2(di: LInjector): Renderer2 {
|
|||
* @returns the value from the injector or `null` when not found
|
||||
*/
|
||||
export function getOrCreateInjectable<T>(
|
||||
nodeInjector: LInjector, token: Type<T>| InjectionToken<T>,
|
||||
startInjectorIndex: number, hostView: LViewData, token: Type<T>| InjectionToken<T>,
|
||||
flags: InjectFlags = InjectFlags.Default): T|null {
|
||||
const bloomHash = bloomHashBitOrFactory(token);
|
||||
// If the ID stored here is a function, this is a special object like ElementRef or TemplateRef
|
||||
|
@ -285,60 +320,73 @@ export function getOrCreateInjectable<T>(
|
|||
// If the token has a bloom hash, then it is a directive that is public to the injection system
|
||||
// (diPublic) otherwise fall back to the module injector.
|
||||
if (bloomHash != null) {
|
||||
let injector: LInjector|null = nodeInjector;
|
||||
let injectorIndex = startInjectorIndex;
|
||||
let injectorView = hostView;
|
||||
|
||||
while (injector) {
|
||||
// Get the closest potential matching injector (upwards in the injector tree) that
|
||||
// *potentially* has the token.
|
||||
injector = bloomFindPossibleInjector(injector, bloomHash, flags);
|
||||
if (flags & InjectFlags.SkipSelf) {
|
||||
const parentLocation = injectorView[injectorIndex + PARENT_INJECTOR];
|
||||
injectorIndex = parentLocation & InjectorLocationFlags.InjectorIndexMask;
|
||||
injectorView = getParentInjectorView(parentLocation, injectorView);
|
||||
}
|
||||
|
||||
while (injectorIndex !== -1) {
|
||||
// Traverse up the injector tree until we find a potential match or until we know there
|
||||
// *isn't* a match. Outer loop is necessary in case we get a false positive injector.
|
||||
while (injectorIndex !== -1) {
|
||||
// Check the current injector. If it matches, stop searching for an injector.
|
||||
if (injectorHasToken(bloomHash, injectorIndex, injectorView[TVIEW].data)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (flags & InjectFlags.Self ||
|
||||
flags & InjectFlags.Host &&
|
||||
!sameHostView(injectorView[injectorIndex + PARENT_INJECTOR])) {
|
||||
injectorIndex = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
// If the ancestor bloom filter value has the bit corresponding to the directive, traverse
|
||||
// up to find the specific injector. If the ancestor bloom filter does not have the bit, we
|
||||
// can abort.
|
||||
if (injectorHasToken(bloomHash, injectorIndex, injectorView)) {
|
||||
const parentLocation = injectorView[injectorIndex + PARENT_INJECTOR];
|
||||
injectorIndex = parentLocation & InjectorLocationFlags.InjectorIndexMask;
|
||||
injectorView = getParentInjectorView(parentLocation, injectorView);
|
||||
} else {
|
||||
injectorIndex = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If no injector is found, we *know* that there is no ancestor injector that contains the
|
||||
// token, so we abort.
|
||||
if (!injector) {
|
||||
if (injectorIndex === -1) {
|
||||
break;
|
||||
}
|
||||
|
||||
// At this point, we have an injector which *may* contain the token, so we step through the
|
||||
// directives associated with the injector's corresponding node to get the directive instance.
|
||||
const tNode = injector.tNode;
|
||||
const injectorView = injector.view;
|
||||
const nodeFlags = tNode.flags;
|
||||
const count = nodeFlags & TNodeFlags.DirectiveCountMask;
|
||||
|
||||
if (count !== 0) {
|
||||
const start = nodeFlags >> TNodeFlags.DirectiveStartingIndexShift;
|
||||
const end = start + count;
|
||||
const defs = injectorView[TVIEW].directives !;
|
||||
|
||||
for (let i = start; i < end; i++) {
|
||||
// Get the definition for the directive at this index and, if it is injectable (diPublic),
|
||||
// and matches the given token, return the directive instance.
|
||||
const directiveDef = defs[i] as DirectiveDefInternal<any>;
|
||||
if (directiveDef.type === token && directiveDef.diPublic) {
|
||||
return injectorView[DIRECTIVES] ![i];
|
||||
}
|
||||
}
|
||||
let instance: T|null;
|
||||
if (instance = searchDirectivesOnInjector<T>(injectorIndex, injectorView, token)) {
|
||||
return instance;
|
||||
}
|
||||
|
||||
// If we *didn't* find the directive for the token and we are searching the current node's
|
||||
// injector, it's possible the directive is on this node and hasn't been created yet.
|
||||
let instance: T|null;
|
||||
if (injector === nodeInjector &&
|
||||
if (injectorIndex === startInjectorIndex && hostView === injectorView &&
|
||||
(instance = searchMatchesQueuedForCreation<T>(token, injectorView[TVIEW]))) {
|
||||
return instance;
|
||||
}
|
||||
|
||||
// The def wasn't found anywhere on this node, so it was a false positive.
|
||||
// If flags permit, traverse up the tree and continue searching.
|
||||
if (flags & InjectFlags.Self || flags & InjectFlags.Host && !sameHostView(injector)) {
|
||||
injector = null;
|
||||
} else {
|
||||
injector = injector.parent;
|
||||
}
|
||||
// Traverse up the tree and continue searching.
|
||||
const parentLocation = injectorView[injectorIndex + PARENT_INJECTOR];
|
||||
injectorIndex = parentLocation & InjectorLocationFlags.InjectorIndexMask;
|
||||
injectorView = getParentInjectorView(parentLocation, injectorView);
|
||||
}
|
||||
}
|
||||
|
||||
const moduleInjector = nodeInjector.view[INJECTOR];
|
||||
const moduleInjector = hostView[INJECTOR];
|
||||
const formerInjector = setCurrentInjector(moduleInjector);
|
||||
try {
|
||||
return inject(token, flags);
|
||||
|
@ -360,6 +408,29 @@ function searchMatchesQueuedForCreation<T>(token: any, hostTView: TView): T|null
|
|||
return null;
|
||||
}
|
||||
|
||||
function searchDirectivesOnInjector<T>(
|
||||
injectorIndex: number, injectorView: LViewData, token: Type<T>| InjectionToken<T>) {
|
||||
const tNode = injectorView[TVIEW].data[injectorIndex + TNODE] as TNode;
|
||||
const nodeFlags = tNode.flags;
|
||||
const count = nodeFlags & TNodeFlags.DirectiveCountMask;
|
||||
|
||||
if (count !== 0) {
|
||||
const start = nodeFlags >> TNodeFlags.DirectiveStartingIndexShift;
|
||||
const end = start + count;
|
||||
const defs = injectorView[TVIEW].directives !;
|
||||
|
||||
for (let i = start; i < end; i++) {
|
||||
// Get the definition for the directive at this index and, if it is injectable (diPublic),
|
||||
// and matches the given token, return the directive instance.
|
||||
const directiveDef = defs[i] as DirectiveDefInternal<any>;
|
||||
if (directiveDef.type === token && directiveDef.diPublic) {
|
||||
return injectorView[DIRECTIVES] ![i];
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the bit in an injector's bloom filter that should be used to determine whether or not
|
||||
* the directive might be provided by the injector.
|
||||
|
@ -371,108 +442,67 @@ function searchMatchesQueuedForCreation<T>(token: any, hostTView: TView): T|null
|
|||
* @param token the injection token
|
||||
* @returns the matching bit to check in the bloom filter or `null` if the token is not known.
|
||||
*/
|
||||
function bloomHashBitOrFactory(token: Type<any>| InjectionToken<any>): number|Function|undefined {
|
||||
const tokenId: number|undefined = (token as any)[NG_ELEMENT_ID] || null;
|
||||
export function bloomHashBitOrFactory(token: Type<any>| InjectionToken<any>): number|Function|
|
||||
undefined {
|
||||
const tokenId: number|undefined = (token as any)[NG_ELEMENT_ID];
|
||||
return typeof tokenId === 'number' ? tokenId & BLOOM_MASK : tokenId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the closest injector that might have a certain directive.
|
||||
*
|
||||
* Each directive corresponds to a bit in an injector's bloom filter. Given the bloom bit to
|
||||
* check and a starting injector, this function traverses up injectors until it finds an
|
||||
* injector that contains a 1 for that bit in its bloom filter. A 1 indicates that the
|
||||
* injector may have that directive. It only *may* have the directive because directives begin
|
||||
* to share bloom filter bits after the BLOOM_SIZE is reached, and it could correspond to a
|
||||
* different directive sharing the bit.
|
||||
*
|
||||
* Note: We can skip checking further injectors up the tree if an injector's cbf structure
|
||||
* has a 0 for that bloom bit. Since cbf contains the merged value of all the parent
|
||||
* injectors, a 0 in the bloom bit indicates that the parents definitely do not contain
|
||||
* the directive and do not need to be checked.
|
||||
*
|
||||
* @param injector The starting node injector to check
|
||||
* @param bloomBit The bit to check in each injector's bloom filter
|
||||
* @param flags The injection flags for this injection site (e.g. Optional or SkipSelf)
|
||||
* @returns An injector that might have the directive
|
||||
*/
|
||||
export function bloomFindPossibleInjector(
|
||||
startInjector: LInjector, bloomBit: number, flags: InjectFlags): LInjector|null {
|
||||
export function injectorHasToken(
|
||||
bloomHash: number, injectorIndex: number, injectorView: LViewData | TData) {
|
||||
// Create a mask that targets the specific bit associated with the directive we're looking for.
|
||||
// JS bit operations are 32 bits, so this will be a number between 2^0 and 2^31, corresponding
|
||||
// to bit positions 0 - 31 in a 32 bit integer.
|
||||
const mask = 1 << bloomBit;
|
||||
const b7 = bloomBit & 0x80;
|
||||
const b6 = bloomBit & 0x40;
|
||||
const b5 = bloomBit & 0x20;
|
||||
const mask = 1 << bloomHash;
|
||||
const b7 = bloomHash & 0x80;
|
||||
const b6 = bloomHash & 0x40;
|
||||
const b5 = bloomHash & 0x20;
|
||||
|
||||
// Traverse up the injector tree until we find a potential match or until we know there *isn't* a
|
||||
// match.
|
||||
let injector: LInjector|null =
|
||||
flags & InjectFlags.SkipSelf ? startInjector.parent : startInjector;
|
||||
// Our bloom filter size is 256 bits, which is eight 32-bit bloom filter buckets:
|
||||
// bf0 = [0 - 31], bf1 = [32 - 63], bf2 = [64 - 95], bf3 = [96 - 127], etc.
|
||||
// Get the bloom filter value from the appropriate bucket based on the directive's bloomBit.
|
||||
let value: number;
|
||||
|
||||
while (injector) {
|
||||
// Our bloom filter size is 256 bits, which is eight 32-bit bloom filter buckets:
|
||||
// bf0 = [0 - 31], bf1 = [32 - 63], bf2 = [64 - 95], bf3 = [96 - 127], etc.
|
||||
// Get the bloom filter value from the appropriate bucket based on the directive's bloomBit.
|
||||
let value: number;
|
||||
|
||||
if (b7) {
|
||||
value = b6 ? (b5 ? injector.bf7 : injector.bf6) : (b5 ? injector.bf5 : injector.bf4);
|
||||
} else {
|
||||
value = b6 ? (b5 ? injector.bf3 : injector.bf2) : (b5 ? injector.bf1 : injector.bf0);
|
||||
}
|
||||
|
||||
// If the bloom filter value has the bit corresponding to the directive's bloomBit flipped on,
|
||||
// this injector is a potential match.
|
||||
if (value & mask) {
|
||||
return injector;
|
||||
}
|
||||
|
||||
if (flags & InjectFlags.Self || flags & InjectFlags.Host && !sameHostView(injector)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// If the current injector does not have the directive, check the bloom filters for the ancestor
|
||||
// injectors (cbf0 - cbf7). These filters capture *all* ancestor injectors.
|
||||
if (b7) {
|
||||
value = b6 ? (b5 ? injector.cbf7 : injector.cbf6) : (b5 ? injector.cbf5 : injector.cbf4);
|
||||
} else {
|
||||
value = b6 ? (b5 ? injector.cbf3 : injector.cbf2) : (b5 ? injector.cbf1 : injector.cbf0);
|
||||
}
|
||||
|
||||
// If the ancestor bloom filter value has the bit corresponding to the directive, traverse up to
|
||||
// find the specific injector. If the ancestor bloom filter does not have the bit, we can abort.
|
||||
if (value & mask) {
|
||||
injector = injector.parent;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
if (b7) {
|
||||
value = b6 ? (b5 ? injectorView[injectorIndex + 7] : injectorView[injectorIndex + 6]) :
|
||||
(b5 ? injectorView[injectorIndex + 5] : injectorView[injectorIndex + 4]);
|
||||
} else {
|
||||
value = b6 ? (b5 ? injectorView[injectorIndex + 3] : injectorView[injectorIndex + 2]) :
|
||||
(b5 ? injectorView[injectorIndex + 1] : injectorView[injectorIndex]);
|
||||
}
|
||||
|
||||
return null;
|
||||
// If the bloom filter value has the bit corresponding to the directive's bloomBit flipped on,
|
||||
// this injector is a potential match.
|
||||
return !!(value & mask);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks whether the current injector and its parent are in the same host view.
|
||||
*
|
||||
* This is necessary to support @Host() decorators. If @Host() is set, we should stop searching once
|
||||
* the injector and its parent view don't match because it means we'd cross the view boundary.
|
||||
*/
|
||||
function sameHostView(injector: LInjector): boolean {
|
||||
return !!injector.parent && injector.parent.view === injector.view;
|
||||
function sameHostView(parentLocation: number): boolean {
|
||||
return !!parentLocation && (parentLocation >> InjectorLocationFlags.ViewOffsetShift) === 0;
|
||||
}
|
||||
|
||||
export class NodeInjector implements Injector {
|
||||
constructor(private _lInjector: LInjector) {}
|
||||
private _injectorIndex: number;
|
||||
|
||||
constructor(
|
||||
private _tNode: TElementNode|TContainerNode|TElementContainerNode,
|
||||
private _hostView: LViewData) {
|
||||
this._injectorIndex = getOrCreateNodeInjectorForNode(_tNode, _hostView);
|
||||
}
|
||||
|
||||
get(token: any): any {
|
||||
if (token === Renderer2) {
|
||||
return getOrCreateRenderer2(this._lInjector);
|
||||
return getOrCreateRenderer2(this._hostView);
|
||||
}
|
||||
|
||||
setEnvironment(this._lInjector.tNode, this._lInjector.view);
|
||||
return getOrCreateInjectable(this._lInjector, token);
|
||||
setEnvironment(this._tNode, this._hostView);
|
||||
return getOrCreateInjectable(this._injectorIndex, this._hostView, token);
|
||||
}
|
||||
}
|
||||
export function getFactoryOf<T>(type: Type<any>): ((type?: Type<T>) => T)|null {
|
||||
|
|
|
@ -19,7 +19,6 @@ import {throwCyclicDependencyError, throwErrorIfNoChangesMode, throwMultipleComp
|
|||
import {executeHooks, executeInitHooks, queueInitHooks, queueLifecycleHooks} from './hooks';
|
||||
import {ACTIVE_INDEX, LContainer, RENDER_PARENT, VIEWS} from './interfaces/container';
|
||||
import {ComponentDefInternal, ComponentQuery, ComponentTemplate, DirectiveDefInternal, DirectiveDefListOrFactory, InitialStylingFlags, PipeDefListOrFactory, RenderFlags} from './interfaces/definition';
|
||||
import {LInjector} from './interfaces/injector';
|
||||
import {AttributeMarker, InitialInputData, InitialInputs, LContainerNode, LElementContainerNode, LElementNode, LNode, LProjectionNode, LTextNode, LViewNode, LocalRefExtractor, PropertyAliasValue, PropertyAliases, TAttributes, TContainerNode, TElementContainerNode, TElementNode, TNode, TNodeFlags, TNodeType, TProjectionNode, TViewNode} from './interfaces/node';
|
||||
import {CssSelectorList, NG_PROJECT_AS_ATTR_NAME} from './interfaces/projection';
|
||||
import {LQueries} from './interfaces/query';
|
||||
|
@ -1106,8 +1105,8 @@ export function createTView(
|
|||
template: templateFn,
|
||||
viewQuery: viewQuery,
|
||||
node: null !,
|
||||
data: HEADER_FILLER.slice(), // Fill in to match HEADER_OFFSET in LViewData
|
||||
childIndex: -1, // Children set in addToViewTree(), if any
|
||||
data: blueprint.slice(), // Fill in to match HEADER_OFFSET in LViewData
|
||||
childIndex: -1, // Children set in addToViewTree(), if any
|
||||
bindingStartIndex: bindingStartIndex,
|
||||
hostBindingStartIndex: initialViewLength,
|
||||
directives: null,
|
||||
|
|
|
@ -7,71 +7,97 @@
|
|||
*/
|
||||
|
||||
|
||||
import {ChangeDetectorRef} from '../../change_detection/change_detector_ref';
|
||||
import {ElementRef} from '../../linker/element_ref';
|
||||
import {TemplateRef} from '../../linker/template_ref';
|
||||
import {ViewContainerRef} from '../../linker/view_container_ref';
|
||||
|
||||
import {TContainerNode, TElementContainerNode, TElementNode,} from './node';
|
||||
import {LViewData} from './view';
|
||||
|
||||
export interface LInjector {
|
||||
/**
|
||||
* We need to store a reference to the injector's parent so DI can keep looking up
|
||||
* the injector tree until it finds the dependency it's looking for.
|
||||
*/
|
||||
readonly parent: LInjector|null;
|
||||
export const TNODE = 8;
|
||||
export const PARENT_INJECTOR = 8;
|
||||
export const INJECTOR_SIZE = 9;
|
||||
|
||||
/** Necessary to find directive indices for a particular node and look up the LNode. */
|
||||
readonly tNode: TElementNode|TElementContainerNode|TContainerNode;
|
||||
|
||||
/**
|
||||
* The view where the node is stored. Necessary because as we traverse up the injector
|
||||
* tree the view where we search directives may change.
|
||||
*/
|
||||
readonly view: LViewData;
|
||||
|
||||
/**
|
||||
* The following bloom filter determines whether a directive is available
|
||||
* on the associated node or not. This prevents us from searching the directives
|
||||
* array at this level unless it's probable the directive is in it.
|
||||
*
|
||||
* - bf0: Check directive IDs 0-31 (IDs are % 128)
|
||||
* - bf1: Check directive IDs 32-63
|
||||
* - bf2: Check directive IDs 64-95
|
||||
* - bf3: Check directive IDs 96-127
|
||||
* - bf4: Check directive IDs 128-159
|
||||
* - bf5: Check directive IDs 160 - 191
|
||||
* - bf6: Check directive IDs 192 - 223
|
||||
* - bf7: Check directive IDs 224 - 255
|
||||
*
|
||||
* See: https://en.wikipedia.org/wiki/Bloom_filter for more about bloom filters.
|
||||
*/
|
||||
bf0: number;
|
||||
bf1: number;
|
||||
bf2: number;
|
||||
bf3: number;
|
||||
bf4: number;
|
||||
bf5: number;
|
||||
bf6: number;
|
||||
bf7: number;
|
||||
|
||||
/**
|
||||
* cbf0 - cbf7 properties determine whether a directive is available through a
|
||||
* parent injector. They refer to the merged values of parent bloom filters. This
|
||||
* allows us to skip looking up the chain unless it's probable that directive exists
|
||||
* up the chain.
|
||||
*/
|
||||
cbf0: number;
|
||||
cbf1: number;
|
||||
cbf2: number;
|
||||
cbf3: number;
|
||||
cbf4: number;
|
||||
cbf5: number;
|
||||
cbf6: number;
|
||||
cbf7: number;
|
||||
export const enum InjectorLocationFlags {
|
||||
InjectorIndexMask = 0b111111111111111,
|
||||
ViewOffsetShift = 15
|
||||
}
|
||||
|
||||
/**
|
||||
* Each injector is saved in 9 contiguous slots in `LViewData` and 9 contiguous slots in
|
||||
* `TView.data`. This allows us to store information about the current node's tokens (which
|
||||
* can be shared in `TView`) as well as the tokens of its ancestor nodes (which cannot be
|
||||
* shared, so they live in `LViewData`).
|
||||
*
|
||||
* Each of these slots (aside from the last slot) contains a bloom filter. This bloom filter
|
||||
* determines whether a directive is available on the associated node or not. This prevents us
|
||||
* from searching the directives array at this level unless it's probable the directive is in it.
|
||||
*
|
||||
* See: https://en.wikipedia.org/wiki/Bloom_filter for more about bloom filters.
|
||||
*
|
||||
* Because all injectors have been flattened into `LViewData` and `TViewData`, they cannot typed
|
||||
* using interfaces as they were previously. The start index of each `LInjector` and `TInjector`
|
||||
* will differ based on where it is flattened into the main array, so it's not possible to know
|
||||
* the indices ahead of time and save their types here. The interfaces are still included here
|
||||
* for documentation purposes.
|
||||
*
|
||||
* export interface LInjector extends Array<any> {
|
||||
*
|
||||
* // Cumulative bloom for directive IDs 0-31 (IDs are % BLOOM_SIZE)
|
||||
* [0]: number;
|
||||
*
|
||||
* // Cumulative bloom for directive IDs 32-63
|
||||
* [1]: number;
|
||||
*
|
||||
* // Cumulative bloom for directive IDs 64-95
|
||||
* [2]: number;
|
||||
*
|
||||
* // Cumulative bloom for directive IDs 96-127
|
||||
* [3]: number;
|
||||
*
|
||||
* // Cumulative bloom for directive IDs 128-159
|
||||
* [4]: number;
|
||||
*
|
||||
* // Cumulative bloom for directive IDs 160 - 191
|
||||
* [5]: number;
|
||||
*
|
||||
* // Cumulative bloom for directive IDs 192 - 223
|
||||
* [6]: number;
|
||||
*
|
||||
* // Cumulative bloom for directive IDs 224 - 255
|
||||
* [7]: number;
|
||||
*
|
||||
* // We need to store a reference to the injector's parent so DI can keep looking up
|
||||
* // the injector tree until it finds the dependency it's looking for.
|
||||
* [PARENT_INJECTOR]: number;
|
||||
* }
|
||||
*
|
||||
* export interface TInjector extends Array<any> {
|
||||
*
|
||||
* // Shared node bloom for directive IDs 0-31 (IDs are % BLOOM_SIZE)
|
||||
* [0]: number;
|
||||
*
|
||||
* // Shared node bloom for directive IDs 32-63
|
||||
* [1]: number;
|
||||
*
|
||||
* // Shared node bloom for directive IDs 64-95
|
||||
* [2]: number;
|
||||
*
|
||||
* // Shared node bloom for directive IDs 96-127
|
||||
* [3]: number;
|
||||
*
|
||||
* // Shared node bloom for directive IDs 128-159
|
||||
* [4]: number;
|
||||
*
|
||||
* // Shared node bloom for directive IDs 160 - 191
|
||||
* [5]: number;
|
||||
*
|
||||
* // Shared node bloom for directive IDs 192 - 223
|
||||
* [6]: number;
|
||||
*
|
||||
* // Shared node bloom for directive IDs 224 - 255
|
||||
* [7]: number;
|
||||
*
|
||||
* // Necessary to find directive indices for a particular node.
|
||||
* [TNODE]: TElementNode|TElementContainerNode|TContainerNode;
|
||||
* }
|
||||
*/
|
||||
|
||||
// Note: This hack is necessary so we don't erroneously get a circular dependency
|
||||
// failure based on types.
|
||||
export const unusedValueExportToPlacateAjd = 1;
|
||||
|
|
|
@ -7,8 +7,6 @@
|
|||
*/
|
||||
|
||||
import {LContainer} from './container';
|
||||
import {LInjector} from './injector';
|
||||
import {LQueries} from './query';
|
||||
import {RComment, RElement, RText} from './renderer';
|
||||
import {StylingContext} from './styling';
|
||||
import {LViewData, TView} from './view';
|
||||
|
|
|
@ -550,11 +550,15 @@ export type HookData = (number | (() => void))[];
|
|||
* Static data that corresponds to the instance-specific data array on an LView.
|
||||
*
|
||||
* Each node's static data is stored in tData at the same index that it's stored
|
||||
* in the data array. Each pipe's definition is stored here at the same index
|
||||
* as its pipe instance in the data array. Any nodes that do not have static
|
||||
* data store a null value in tData to avoid a sparse array.
|
||||
* in the data array. Any nodes that do not have static data store a null value in
|
||||
* tData to avoid a sparse array.
|
||||
*
|
||||
* Each pipe's definition is stored here at the same index as its pipe instance in
|
||||
* the data array.
|
||||
*
|
||||
* Injector bloom filters are also stored here.
|
||||
*/
|
||||
export type TData = (TNode | PipeDefInternal<any>| null)[];
|
||||
export type TData = (TNode | PipeDefInternal<any>| number | null)[];
|
||||
|
||||
/** Type for TView.currentMatches */
|
||||
export type CurrentMatchesList = [DirectiveDefInternal<any>, (string | number | null)];
|
||||
|
|
|
@ -14,7 +14,6 @@ import {EventEmitter} from '../event_emitter';
|
|||
import {ElementRef as ViewEngine_ElementRef} from '../linker/element_ref';
|
||||
import {QueryList as viewEngine_QueryList} from '../linker/query_list';
|
||||
import {TemplateRef as ViewEngine_TemplateRef} from '../linker/template_ref';
|
||||
import {ViewContainerRef as ViewEngine_ViewContainerRef} from '../linker/view_container_ref';
|
||||
import {Type} from '../type';
|
||||
import {getSymbolIterator} from '../util';
|
||||
|
||||
|
@ -485,4 +484,4 @@ export function queryRefresh(queryList: QueryList<any>): boolean {
|
|||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,16 +16,17 @@ import {ViewContainerRef as ViewEngine_ViewContainerRef} from '../linker/view_co
|
|||
import {EmbeddedViewRef as viewEngine_EmbeddedViewRef, ViewRef as viewEngine_ViewRef} from '../linker/view_ref';
|
||||
|
||||
import {assertDefined, assertGreaterThan, assertLessThan} from './assert';
|
||||
import {NodeInjector, getInjector, getOrCreateNodeInjectorForNode, getParentInjector} from './di';
|
||||
import {NodeInjector, getParentInjectorLocation, getParentInjectorView} from './di';
|
||||
import {_getViewData, addToViewTree, createEmbeddedViewAndNode, createLContainer, createLNodeObject, createTNode, getPreviousOrParentTNode, getRenderer, renderEmbeddedTemplate} from './instructions';
|
||||
import {LContainer, RENDER_PARENT, VIEWS} from './interfaces/container';
|
||||
import {RenderFlags} from './interfaces/definition';
|
||||
import {InjectorLocationFlags} from './interfaces/injector';
|
||||
import {LContainerNode, TContainerNode, TElementContainerNode, TElementNode, TNode, TNodeFlags, TNodeType, TViewNode} from './interfaces/node';
|
||||
import {LQueries} from './interfaces/query';
|
||||
import {RComment, RElement, Renderer3} from './interfaces/renderer';
|
||||
import {CONTEXT, HOST_NODE, LViewData, QUERIES, RENDERER, TView} from './interfaces/view';
|
||||
import {CONTEXT, HOST_NODE, LViewData, QUERIES, RENDERER, TVIEW, TView} from './interfaces/view';
|
||||
import {assertNodeOfPossibleTypes, assertNodeType} from './node_assert';
|
||||
import {addRemoveViewFromContainer, appendChild, detachView, findComponentView, getBeforeNodeForView, getParentLNode, getRenderParent, insertView, removeView} from './node_manipulation';
|
||||
import {addRemoveViewFromContainer, appendChild, detachView, findComponentView, getBeforeNodeForView, getRenderParent, insertView, removeView} from './node_manipulation';
|
||||
import {getLNode, isComponent} from './util';
|
||||
import {ViewRef} from './view_ref';
|
||||
|
||||
|
@ -180,15 +181,17 @@ export function createContainerRef(
|
|||
return createElementRef(ElementRefToken, this._hostTNode, this._hostView);
|
||||
}
|
||||
|
||||
get injector(): Injector {
|
||||
const nodeInjector = getOrCreateNodeInjectorForNode(this._hostTNode, this._hostView);
|
||||
return new NodeInjector(nodeInjector);
|
||||
}
|
||||
get injector(): Injector { return new NodeInjector(this._hostTNode, this._hostView); }
|
||||
|
||||
/** @deprecated No replacement */
|
||||
get parentInjector(): Injector {
|
||||
const parentLInjector = getParentInjector(this._hostTNode, this._hostView);
|
||||
return parentLInjector ? new NodeInjector(parentLInjector) : new NullInjector();
|
||||
const parentLocation = getParentInjectorLocation(this._hostTNode, this._hostView);
|
||||
const parentView = getParentInjectorView(parentLocation, this._hostView);
|
||||
const parentIndex = parentLocation & InjectorLocationFlags.InjectorIndexMask;
|
||||
const parentTNode = parentView[TVIEW].data[parentIndex] as TElementNode | TContainerNode;
|
||||
|
||||
return parentLocation === -1 ? new NullInjector() :
|
||||
new NodeInjector(parentTNode, parentView);
|
||||
}
|
||||
|
||||
clear(): void {
|
||||
|
|
|
@ -68,9 +68,6 @@
|
|||
{
|
||||
"name": "FLAGS"
|
||||
},
|
||||
{
|
||||
"name": "HEADER_FILLER"
|
||||
},
|
||||
{
|
||||
"name": "HEADER_OFFSET"
|
||||
},
|
||||
|
@ -80,6 +77,9 @@
|
|||
{
|
||||
"name": "INJECTOR$1"
|
||||
},
|
||||
{
|
||||
"name": "INJECTOR_SIZE"
|
||||
},
|
||||
{
|
||||
"name": "IterableChangeRecord_"
|
||||
},
|
||||
|
@ -140,6 +140,9 @@
|
|||
{
|
||||
"name": "PARENT"
|
||||
},
|
||||
{
|
||||
"name": "PARENT_INJECTOR"
|
||||
},
|
||||
{
|
||||
"name": "PublicFeature"
|
||||
},
|
||||
|
@ -182,6 +185,9 @@
|
|||
{
|
||||
"name": "TAIL"
|
||||
},
|
||||
{
|
||||
"name": "TNODE"
|
||||
},
|
||||
{
|
||||
"name": "TVIEW"
|
||||
},
|
||||
|
@ -302,9 +308,6 @@
|
|||
{
|
||||
"name": "bloomAdd"
|
||||
},
|
||||
{
|
||||
"name": "bloomFindPossibleInjector"
|
||||
},
|
||||
{
|
||||
"name": "bloomHashBitOrFactory"
|
||||
},
|
||||
|
@ -582,7 +585,7 @@
|
|||
"name": "getInjectableDef"
|
||||
},
|
||||
{
|
||||
"name": "getInjector$1"
|
||||
"name": "getInjectorIndex"
|
||||
},
|
||||
{
|
||||
"name": "getLElementFromComponent"
|
||||
|
@ -621,7 +624,10 @@
|
|||
"name": "getOrCreateTView"
|
||||
},
|
||||
{
|
||||
"name": "getParentInjector"
|
||||
"name": "getParentInjectorLocation"
|
||||
},
|
||||
{
|
||||
"name": "getParentInjectorView"
|
||||
},
|
||||
{
|
||||
"name": "getParentLNode"
|
||||
|
@ -707,6 +713,9 @@
|
|||
{
|
||||
"name": "injectViewContainerRef"
|
||||
},
|
||||
{
|
||||
"name": "injectorHasToken"
|
||||
},
|
||||
{
|
||||
"name": "insertNewMultiProperty"
|
||||
},
|
||||
|
@ -911,6 +920,9 @@
|
|||
{
|
||||
"name": "scheduleTick"
|
||||
},
|
||||
{
|
||||
"name": "searchDirectivesOnInjector"
|
||||
},
|
||||
{
|
||||
"name": "searchMatchesQueuedForCreation"
|
||||
},
|
||||
|
|
|
@ -38,9 +38,6 @@
|
|||
{
|
||||
"name": "FLAGS"
|
||||
},
|
||||
{
|
||||
"name": "HEADER_FILLER"
|
||||
},
|
||||
{
|
||||
"name": "HEADER_OFFSET"
|
||||
},
|
||||
|
@ -50,6 +47,9 @@
|
|||
{
|
||||
"name": "INJECTOR$1"
|
||||
},
|
||||
{
|
||||
"name": "INJECTOR_SIZE"
|
||||
},
|
||||
{
|
||||
"name": "MONKEY_PATCH_KEY_NAME"
|
||||
},
|
||||
|
@ -80,6 +80,9 @@
|
|||
{
|
||||
"name": "PARENT"
|
||||
},
|
||||
{
|
||||
"name": "PARENT_INJECTOR"
|
||||
},
|
||||
{
|
||||
"name": "PublicFeature"
|
||||
},
|
||||
|
@ -107,9 +110,6 @@
|
|||
{
|
||||
"name": "ViewEncapsulation$1"
|
||||
},
|
||||
{
|
||||
"name": "_CLEAN_PROMISE"
|
||||
},
|
||||
{
|
||||
"name": "_getViewData"
|
||||
},
|
||||
|
@ -240,7 +240,7 @@
|
|||
"name": "getHostElementNode"
|
||||
},
|
||||
{
|
||||
"name": "getInjector$1"
|
||||
"name": "getInjectorIndex"
|
||||
},
|
||||
{
|
||||
"name": "getLNode"
|
||||
|
@ -258,7 +258,10 @@
|
|||
"name": "getOrCreateTView"
|
||||
},
|
||||
{
|
||||
"name": "getParentInjector"
|
||||
"name": "getParentInjectorLocation"
|
||||
},
|
||||
{
|
||||
"name": "getParentInjectorView"
|
||||
},
|
||||
{
|
||||
"name": "getParentLNode"
|
||||
|
|
|
@ -53,9 +53,6 @@
|
|||
{
|
||||
"name": "FLAGS"
|
||||
},
|
||||
{
|
||||
"name": "HEADER_FILLER"
|
||||
},
|
||||
{
|
||||
"name": "HEADER_OFFSET"
|
||||
},
|
||||
|
@ -65,6 +62,9 @@
|
|||
{
|
||||
"name": "INJECTOR$1"
|
||||
},
|
||||
{
|
||||
"name": "INJECTOR_SIZE"
|
||||
},
|
||||
{
|
||||
"name": "IterableChangeRecord_"
|
||||
},
|
||||
|
@ -131,6 +131,9 @@
|
|||
{
|
||||
"name": "PARENT"
|
||||
},
|
||||
{
|
||||
"name": "PARENT_INJECTOR"
|
||||
},
|
||||
{
|
||||
"name": "PublicFeature"
|
||||
},
|
||||
|
@ -170,6 +173,9 @@
|
|||
{
|
||||
"name": "TAIL"
|
||||
},
|
||||
{
|
||||
"name": "TNODE"
|
||||
},
|
||||
{
|
||||
"name": "TVIEW"
|
||||
},
|
||||
|
@ -368,9 +374,6 @@
|
|||
{
|
||||
"name": "bloomAdd"
|
||||
},
|
||||
{
|
||||
"name": "bloomFindPossibleInjector"
|
||||
},
|
||||
{
|
||||
"name": "bloomHashBitOrFactory"
|
||||
},
|
||||
|
@ -624,7 +627,7 @@
|
|||
"name": "getInjectableDef"
|
||||
},
|
||||
{
|
||||
"name": "getInjector$1"
|
||||
"name": "getInjectorIndex"
|
||||
},
|
||||
{
|
||||
"name": "getLElementFromComponent"
|
||||
|
@ -657,7 +660,10 @@
|
|||
"name": "getOrCreateTView"
|
||||
},
|
||||
{
|
||||
"name": "getParentInjector"
|
||||
"name": "getParentInjectorLocation"
|
||||
},
|
||||
{
|
||||
"name": "getParentInjectorView"
|
||||
},
|
||||
{
|
||||
"name": "getParentLNode"
|
||||
|
@ -737,6 +743,9 @@
|
|||
{
|
||||
"name": "injectViewContainerRef"
|
||||
},
|
||||
{
|
||||
"name": "injectorHasToken"
|
||||
},
|
||||
{
|
||||
"name": "insertView"
|
||||
},
|
||||
|
@ -935,6 +944,9 @@
|
|||
{
|
||||
"name": "scheduleTick"
|
||||
},
|
||||
{
|
||||
"name": "searchDirectivesOnInjector"
|
||||
},
|
||||
{
|
||||
"name": "searchMatchesQueuedForCreation"
|
||||
},
|
||||
|
|
|
@ -320,9 +320,6 @@
|
|||
{
|
||||
"name": "HAMMER_LOADER"
|
||||
},
|
||||
{
|
||||
"name": "HEADER_FILLER"
|
||||
},
|
||||
{
|
||||
"name": "HEADER_OFFSET"
|
||||
},
|
||||
|
@ -353,6 +350,9 @@
|
|||
{
|
||||
"name": "INJECTOR$1"
|
||||
},
|
||||
{
|
||||
"name": "INJECTOR_SIZE"
|
||||
},
|
||||
{
|
||||
"name": "INSPECT_GLOBAL_NAME"
|
||||
},
|
||||
|
@ -623,6 +623,9 @@
|
|||
{
|
||||
"name": "PARENT"
|
||||
},
|
||||
{
|
||||
"name": "PARENT_INJECTOR"
|
||||
},
|
||||
{
|
||||
"name": "PATTERN_SEP"
|
||||
},
|
||||
|
@ -815,6 +818,9 @@
|
|||
{
|
||||
"name": "THURSDAY"
|
||||
},
|
||||
{
|
||||
"name": "TNODE"
|
||||
},
|
||||
{
|
||||
"name": "TRANSITION_ID"
|
||||
},
|
||||
|
@ -1202,9 +1208,6 @@
|
|||
{
|
||||
"name": "bloomAdd"
|
||||
},
|
||||
{
|
||||
"name": "bloomFindPossibleInjector"
|
||||
},
|
||||
{
|
||||
"name": "bloomHashBitOrFactory"
|
||||
},
|
||||
|
@ -1653,10 +1656,10 @@
|
|||
"name": "getInjectableDef"
|
||||
},
|
||||
{
|
||||
"name": "getInjector$1"
|
||||
"name": "getInjectorDef"
|
||||
},
|
||||
{
|
||||
"name": "getInjectorDef"
|
||||
"name": "getInjectorIndex"
|
||||
},
|
||||
{
|
||||
"name": "getLElementFromComponent"
|
||||
|
@ -1752,7 +1755,10 @@
|
|||
"name": "getOriginalError"
|
||||
},
|
||||
{
|
||||
"name": "getParentInjector"
|
||||
"name": "getParentInjectorLocation"
|
||||
},
|
||||
{
|
||||
"name": "getParentInjectorView"
|
||||
},
|
||||
{
|
||||
"name": "getParentLNode"
|
||||
|
@ -1886,6 +1892,9 @@
|
|||
{
|
||||
"name": "injectableDefRecord"
|
||||
},
|
||||
{
|
||||
"name": "injectorHasToken"
|
||||
},
|
||||
{
|
||||
"name": "insertView"
|
||||
},
|
||||
|
@ -2282,6 +2291,9 @@
|
|||
{
|
||||
"name": "scheduleTick"
|
||||
},
|
||||
{
|
||||
"name": "searchDirectivesOnInjector"
|
||||
},
|
||||
{
|
||||
"name": "searchMatchesQueuedForCreation"
|
||||
},
|
||||
|
|
|
@ -10,20 +10,20 @@ import {Attribute, ChangeDetectorRef, ElementRef, Host, InjectFlags, Injector, O
|
|||
import {RenderFlags} from '@angular/core/src/render3/interfaces/definition';
|
||||
|
||||
import {defineComponent} from '../../src/render3/definition';
|
||||
import {bloomAdd, bloomFindPossibleInjector, getInjector, getOrCreateNodeInjector, injectAttribute} from '../../src/render3/di';
|
||||
import {PublicFeature, defineDirective, directiveInject, elementProperty, getCurrentView, getRenderedText, injectRenderer2, load, templateRefExtractor} from '../../src/render3/index';
|
||||
import {bloomAdd, bloomHashBitOrFactory as bloomHash, getOrCreateInjectable, getOrCreateNodeInjector, injectAttribute, injectorHasToken} from '../../src/render3/di';
|
||||
import {PublicFeature, defineDirective, directiveInject, elementProperty, injectRenderer2, load, templateRefExtractor} from '../../src/render3/index';
|
||||
|
||||
import {bind, container, containerRefreshEnd, containerRefreshStart, createNodeAtIndex, createLViewData, createTView, element, elementEnd, elementStart, embeddedViewEnd, embeddedViewStart, enterView, interpolation2, leaveView, projection, projectionDef, reference, template, text, textBinding, loadDirective, elementContainerStart, elementContainerEnd, _getViewData, getTNode} from '../../src/render3/instructions';
|
||||
import {LInjector} from '../../src/render3/interfaces/injector';
|
||||
import {isProceduralRenderer} from '../../src/render3/interfaces/renderer';
|
||||
import {AttributeMarker, LContainerNode, LElementNode, TNodeType} from '../../src/render3/interfaces/node';
|
||||
|
||||
import {HEADER_OFFSET, LViewData, LViewFlags, TVIEW, TView} from '../../src/render3/interfaces/view';
|
||||
import {LViewFlags} from '../../src/render3/interfaces/view';
|
||||
import {ViewRef} from '../../src/render3/view_ref';
|
||||
|
||||
import {getRendererFactory2} from './imported_renderer2';
|
||||
import {ComponentFixture, createComponent, createDirective, renderComponent, toHtml} from './render_util';
|
||||
import {NgIf} from './common_with_def';
|
||||
import {TNODE} from '../../src/render3/interfaces/injector';
|
||||
|
||||
describe('di', () => {
|
||||
describe('no dependencies', () => {
|
||||
|
@ -1680,72 +1680,79 @@ describe('di', () => {
|
|||
|
||||
describe('inject', () => {
|
||||
describe('bloom filter', () => {
|
||||
let di: LInjector;
|
||||
let mockTView: any;
|
||||
beforeEach(() => {
|
||||
di = {} as any;
|
||||
di.bf0 = 0;
|
||||
di.bf1 = 0;
|
||||
di.bf2 = 0;
|
||||
di.bf3 = 0;
|
||||
di.bf4 = 0;
|
||||
di.bf5 = 0;
|
||||
di.bf6 = 0;
|
||||
di.bf7 = 0;
|
||||
di.bf3 = 0;
|
||||
di.cbf0 = 0;
|
||||
di.cbf1 = 0;
|
||||
di.cbf2 = 0;
|
||||
di.cbf3 = 0;
|
||||
di.cbf4 = 0;
|
||||
di.cbf5 = 0;
|
||||
di.cbf6 = 0;
|
||||
di.cbf7 = 0;
|
||||
mockTView = {data: [0, 0, 0, 0, 0, 0, 0, 0, null], firstTemplatePass: true};
|
||||
});
|
||||
|
||||
function bloomState() {
|
||||
return [di.bf7, di.bf6, di.bf5, di.bf4, di.bf3, di.bf2, di.bf1, di.bf0];
|
||||
function bloomState() { return mockTView.data.slice(0, TNODE).reverse(); }
|
||||
|
||||
class Dir0 {
|
||||
/** @internal */ static __NG_ELEMENT_ID__ = 0;
|
||||
}
|
||||
class Dir1 {
|
||||
/** @internal */ static __NG_ELEMENT_ID__ = 1;
|
||||
}
|
||||
class Dir33 {
|
||||
/** @internal */ static __NG_ELEMENT_ID__ = 33;
|
||||
}
|
||||
class Dir66 {
|
||||
/** @internal */ static __NG_ELEMENT_ID__ = 66;
|
||||
}
|
||||
class Dir99 {
|
||||
/** @internal */ static __NG_ELEMENT_ID__ = 99;
|
||||
}
|
||||
class Dir132 {
|
||||
/** @internal */ static __NG_ELEMENT_ID__ = 132;
|
||||
}
|
||||
class Dir165 {
|
||||
/** @internal */ static __NG_ELEMENT_ID__ = 165;
|
||||
}
|
||||
class Dir198 {
|
||||
/** @internal */ static __NG_ELEMENT_ID__ = 198;
|
||||
}
|
||||
class Dir231 {
|
||||
/** @internal */ static __NG_ELEMENT_ID__ = 231;
|
||||
}
|
||||
|
||||
it('should add values', () => {
|
||||
bloomAdd(di, { __NG_ELEMENT_ID__: 0 } as any);
|
||||
bloomAdd(0, mockTView, Dir0);
|
||||
expect(bloomState()).toEqual([0, 0, 0, 0, 0, 0, 0, 1]);
|
||||
bloomAdd(di, { __NG_ELEMENT_ID__: 32 + 1 } as any);
|
||||
bloomAdd(0, mockTView, Dir33);
|
||||
expect(bloomState()).toEqual([0, 0, 0, 0, 0, 0, 2, 1]);
|
||||
bloomAdd(di, { __NG_ELEMENT_ID__: 64 + 2 } as any);
|
||||
bloomAdd(0, mockTView, Dir66);
|
||||
expect(bloomState()).toEqual([0, 0, 0, 0, 0, 4, 2, 1]);
|
||||
bloomAdd(di, { __NG_ELEMENT_ID__: 96 + 3 } as any);
|
||||
bloomAdd(0, mockTView, Dir99);
|
||||
expect(bloomState()).toEqual([0, 0, 0, 0, 8, 4, 2, 1]);
|
||||
bloomAdd(di, { __NG_ELEMENT_ID__: 128 + 4 } as any);
|
||||
bloomAdd(0, mockTView, Dir132);
|
||||
expect(bloomState()).toEqual([0, 0, 0, 16, 8, 4, 2, 1]);
|
||||
bloomAdd(di, { __NG_ELEMENT_ID__: 160 + 5 } as any);
|
||||
bloomAdd(0, mockTView, Dir165);
|
||||
expect(bloomState()).toEqual([0, 0, 32, 16, 8, 4, 2, 1]);
|
||||
bloomAdd(di, { __NG_ELEMENT_ID__: 192 + 6 } as any);
|
||||
bloomAdd(0, mockTView, Dir198);
|
||||
expect(bloomState()).toEqual([0, 64, 32, 16, 8, 4, 2, 1]);
|
||||
bloomAdd(di, { __NG_ELEMENT_ID__: 224 + 7 } as any);
|
||||
bloomAdd(0, mockTView, Dir231);
|
||||
expect(bloomState()).toEqual([128, 64, 32, 16, 8, 4, 2, 1]);
|
||||
});
|
||||
|
||||
it('should query values', () => {
|
||||
bloomAdd(di, { __NG_ELEMENT_ID__: 0 } as any);
|
||||
bloomAdd(di, { __NG_ELEMENT_ID__: 32 } as any);
|
||||
bloomAdd(di, { __NG_ELEMENT_ID__: 64 } as any);
|
||||
bloomAdd(di, { __NG_ELEMENT_ID__: 96 } as any);
|
||||
bloomAdd(di, { __NG_ELEMENT_ID__: 127 } as any);
|
||||
bloomAdd(di, { __NG_ELEMENT_ID__: 161 } as any);
|
||||
bloomAdd(di, { __NG_ELEMENT_ID__: 188 } as any);
|
||||
bloomAdd(di, { __NG_ELEMENT_ID__: 223 } as any);
|
||||
bloomAdd(di, { __NG_ELEMENT_ID__: 255 } as any);
|
||||
bloomAdd(0, mockTView, Dir0);
|
||||
bloomAdd(0, mockTView, Dir33);
|
||||
bloomAdd(0, mockTView, Dir66);
|
||||
bloomAdd(0, mockTView, Dir99);
|
||||
bloomAdd(0, mockTView, Dir132);
|
||||
bloomAdd(0, mockTView, Dir165);
|
||||
bloomAdd(0, mockTView, Dir198);
|
||||
bloomAdd(0, mockTView, Dir231);
|
||||
|
||||
expect(bloomFindPossibleInjector(di, 0, InjectFlags.Default)).toEqual(di);
|
||||
expect(bloomFindPossibleInjector(di, 1, InjectFlags.Default)).toEqual(null);
|
||||
expect(bloomFindPossibleInjector(di, 32, InjectFlags.Default)).toEqual(di);
|
||||
expect(bloomFindPossibleInjector(di, 64, InjectFlags.Default)).toEqual(di);
|
||||
expect(bloomFindPossibleInjector(di, 96, InjectFlags.Default)).toEqual(di);
|
||||
expect(bloomFindPossibleInjector(di, 127, InjectFlags.Default)).toEqual(di);
|
||||
expect(bloomFindPossibleInjector(di, 161, InjectFlags.Default)).toEqual(di);
|
||||
expect(bloomFindPossibleInjector(di, 188, InjectFlags.Default)).toEqual(di);
|
||||
expect(bloomFindPossibleInjector(di, 223, InjectFlags.Default)).toEqual(di);
|
||||
expect(bloomFindPossibleInjector(di, 255, InjectFlags.Default)).toEqual(di);
|
||||
expect(injectorHasToken(bloomHash(Dir0) as number, 0, mockTView.data)).toEqual(true);
|
||||
expect(injectorHasToken(bloomHash(Dir1) as number, 0, mockTView.data)).toEqual(false);
|
||||
expect(injectorHasToken(bloomHash(Dir33) as number, 0, mockTView.data)).toEqual(true);
|
||||
expect(injectorHasToken(bloomHash(Dir66) as number, 0, mockTView.data)).toEqual(true);
|
||||
expect(injectorHasToken(bloomHash(Dir99) as number, 0, mockTView.data)).toEqual(true);
|
||||
expect(injectorHasToken(bloomHash(Dir132) as number, 0, mockTView.data)).toEqual(true);
|
||||
expect(injectorHasToken(bloomHash(Dir165) as number, 0, mockTView.data)).toEqual(true);
|
||||
expect(injectorHasToken(bloomHash(Dir198) as number, 0, mockTView.data)).toEqual(true);
|
||||
expect(injectorHasToken(bloomHash(Dir231) as number, 0, mockTView.data)).toEqual(true);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -1778,9 +1785,11 @@ describe('di', () => {
|
|||
|
||||
/**
|
||||
* <div parentDir>
|
||||
* % if (...) {
|
||||
* <span childDir child2Dir #child1="childDir" #child2="child2Dir">
|
||||
* {{ child1.value }} - {{ child2.value }}
|
||||
* </span>
|
||||
* % }
|
||||
* </div>
|
||||
*/
|
||||
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
|
||||
|
|
Loading…
Reference in New Issue