refactor(core): Move booleans in LContainer to flags slot (#52338)

There are now 2 booleans in the LContainer so this commit moves them to a shared
FLAGS slot like the LView.

PR Close #52338
This commit is contained in:
Andrew Scott
2023-10-23 07:22:30 -07:00
committed by Jessica Janiuk
parent a55c8bb0e0
commit 76aba9ef0e
17 changed files with 67 additions and 110 deletions
@@ -13,7 +13,7 @@ import {assertDefined, assertEqual} from '../../util/assert';
import {assertLContainer} from '../assert';
import {getComponentViewByInstance} from '../context_discovery';
import {executeCheckHooks, executeInitAndCheckHooks, incrementInitPhaseFlags} from '../hooks';
import {CONTAINER_HEADER_OFFSET, HAS_CHILD_VIEWS_TO_REFRESH, HAS_TRANSPLANTED_VIEWS, LContainer, MOVED_VIEWS} from '../interfaces/container';
import {CONTAINER_HEADER_OFFSET, LContainer, LContainerFlags, MOVED_VIEWS} from '../interfaces/container';
import {ComponentTemplate, RenderFlags} from '../interfaces/definition';
import {CONTEXT, EFFECTS_TO_SCHEDULE, ENVIRONMENT, FLAGS, InitPhaseState, LView, LViewFlags, PARENT, REACTIVE_TEMPLATE_CONSUMER, TVIEW, TView, TViewType} from '../interfaces/view';
import {getOrBorrowReactiveLViewConsumer, maybeReturnReactiveLViewConsumer, ReactiveLViewConsumer} from '../reactive_lview_consumer';
@@ -324,7 +324,7 @@ function viewShouldHaveReactiveConsumer(tView: TView) {
function detectChangesInEmbeddedViews(lView: LView, mode: ChangeDetectionMode) {
for (let lContainer = getFirstLContainer(lView); lContainer !== null;
lContainer = getNextLContainer(lContainer)) {
lContainer[HAS_CHILD_VIEWS_TO_REFRESH] = false;
lContainer[FLAGS] &= ~LContainerFlags.HasChildViewsToRefresh;
for (let i = CONTAINER_HEADER_OFFSET; i < lContainer.length; i++) {
const embeddedLView = lContainer[i];
detectChangesInViewIfAttached(embeddedLView, mode);
@@ -340,7 +340,7 @@ function detectChangesInEmbeddedViews(lView: LView, mode: ChangeDetectionMode) {
function markTransplantedViewsForRefresh(lView: LView) {
for (let lContainer = getFirstLContainer(lView); lContainer !== null;
lContainer = getNextLContainer(lContainer)) {
if (!lContainer[HAS_TRANSPLANTED_VIEWS]) continue;
if (!(lContainer[FLAGS] & LContainerFlags.HasTransplantedViews)) continue;
const movedViews = lContainer[MOVED_VIEWS]!;
ngDevMode && assertDefined(movedViews, 'Transplanted View flags set but missing MOVED_VIEWS');
@@ -1387,15 +1387,14 @@ export function createLContainer(
const lContainer: LContainer = [
hostNative, // host native
true, // Boolean `true` in this position signifies that this is an `LContainer`
false, // has transplanted views
0, // flags
currentView, // parent
null, // next
tNode, // t_host
false, // has child views to refresh
null, // dehydrated views
native, // native,
null, // view refs
null, // moved views
null, // dehydrated views
];
ngDevMode &&
assertEqual(
@@ -10,8 +10,7 @@ import {DehydratedContainerView} from '../../hydration/interfaces';
import {TNode} from './node';
import {RComment, RElement} from './renderer_dom';
import {HOST, LView, NEXT, PARENT, T_HOST} from './view';
import {FLAGS, HOST, LView, NEXT, PARENT, T_HOST} from './view';
/**
@@ -27,27 +26,13 @@ export const TYPE = 1;
* Uglify will inline these when minifying so there shouldn't be a cost.
*/
/**
* Flag to signify that this `LContainer` may have transplanted views which need to be change
* detected. (see: `LView[DECLARATION_COMPONENT_VIEW])`.
*
* This flag, once set, is never unset for the `LContainer`. This means that when unset we can skip
* a lot of work in `refreshEmbeddedViews`. But when set we still need to verify
* that the `MOVED_VIEWS` are transplanted and on-push.
*/
export const HAS_TRANSPLANTED_VIEWS = 2;
// PARENT and NEXT are indices 3 and 4
// FLAGS, PARENT, NEXT, and T_HOST are indices 2, 3, 4, and 5
// As we already have these constants in LView, we don't need to re-create them.
// T_HOST is index 5
// We already have this constants in LView, we don't need to re-create it.
export const HAS_CHILD_VIEWS_TO_REFRESH = 6;
export const DEHYDRATED_VIEWS = 6;
export const NATIVE = 7;
export const VIEW_REFS = 8;
export const MOVED_VIEWS = 9;
export const DEHYDRATED_VIEWS = 10;
/**
* Size of LContainer's header. Represents the index after which all views in the
@@ -55,7 +40,7 @@ export const DEHYDRATED_VIEWS = 10;
* which views are already in the DOM (and don't need to be re-added) and so we can
* remove views from the DOM when they are no longer required.
*/
export const CONTAINER_HEADER_OFFSET = 11;
export const CONTAINER_HEADER_OFFSET = 10;
/**
* The state associated with a container.
@@ -80,13 +65,8 @@ export interface LContainer extends Array<any> {
*/
[TYPE]: true;
/**
* Flag to signify that this `LContainer` may have transplanted views which need to be change
* detected. (see: `LView[DECLARATION_COMPONENT_VIEW])`.
*
* This flag, once set, is never unset for the `LContainer`.
*/
[HAS_TRANSPLANTED_VIEWS]: boolean;
/** Flags for this container. See LContainerFlags for more info. */
[FLAGS]: LContainerFlags;
/**
* Access to the parent view is necessary so we can propagate back
@@ -100,12 +80,6 @@ export interface LContainer extends Array<any> {
*/
[NEXT]: LView|LContainer|null;
/**
* Indicates that this LContainer has a view underneath it that needs to be refreshed during
* change detection.
*/
[HAS_CHILD_VIEWS_TO_REFRESH]: boolean;
/**
* A collection of views created based on the underlying `<ng-template>` element but inserted into
* a different `LContainer`. We need to track views created from a given declaration point since
@@ -143,3 +117,20 @@ export interface LContainer extends Array<any> {
*/
[DEHYDRATED_VIEWS]: DehydratedContainerView[]|null;
}
/** Flags associated with an LContainer (saved in LContainer[FLAGS]) */
export enum LContainerFlags {
None = 0,
/**
* Flag to signify that this `LContainer` may have transplanted views which need to be change
* detected. (see: `LView[DECLARATION_COMPONENT_VIEW])`.
*
* This flag, once set, is never unset for the `LContainer`.
*/
HasTransplantedViews = 1 << 1,
/**
* Indicates that this LContainer has a view underneath it that needs to be refreshed during
* change detection.
*/
HasChildViewsToRefresh = 1 << 2,
}
+1 -1
View File
@@ -32,9 +32,9 @@ import {TDeferBlockDetails} from '../../defer/interfaces';
// Uglify will inline these when minifying so there shouldn't be a cost.
export const HOST = 0;
export const TVIEW = 1;
export const FLAGS = 2;
// Shared with LContainer
export const FLAGS = 2;
export const PARENT = 3;
export const NEXT = 4;
export const T_HOST = 5;
@@ -18,7 +18,7 @@ import {escapeCommentText} from '../util/dom';
import {assertLContainer, assertLView, assertParentView, assertProjectionSlots, assertTNodeForLView} from './assert';
import {attachPatchData} from './context_discovery';
import {icuContainerIterate} from './i18n/i18n_tree_shaking';
import {CONTAINER_HEADER_OFFSET, HAS_TRANSPLANTED_VIEWS, LContainer, MOVED_VIEWS, NATIVE} from './interfaces/container';
import {CONTAINER_HEADER_OFFSET, LContainer, LContainerFlags, MOVED_VIEWS, NATIVE} from './interfaces/container';
import {ComponentDef} from './interfaces/definition';
import {NodeInjectorFactory} from './interfaces/injector';
import {unregisterLView} from './interfaces/lview_tracking';
@@ -298,7 +298,7 @@ function trackMovedView(declarationContainer: LContainer, lView: LView) {
// At this point the declaration-component is not same as insertion-component; this means that
// this is a transplanted view. Mark the declared lView as having transplanted views so that
// those views can participate in CD.
declarationContainer[HAS_TRANSPLANTED_VIEWS] = true;
declarationContainer[FLAGS] |= LContainerFlags.HasTransplantedViews;
}
if (movedViews === null) {
declarationContainer[MOVED_VIEWS] = [lView];
+3 -3
View File
@@ -9,7 +9,7 @@
import {RuntimeError, RuntimeErrorCode} from '../../errors';
import {assertDefined, assertGreaterThan, assertGreaterThanOrEqual, assertIndexInRange, assertLessThan} from '../../util/assert';
import {assertTNode, assertTNodeForLView} from '../assert';
import {HAS_CHILD_VIEWS_TO_REFRESH, LContainer, TYPE} from '../interfaces/container';
import {LContainer, LContainerFlags, TYPE} from '../interfaces/container';
import {TConstants, TNode} from '../interfaces/node';
import {RNode} from '../interfaces/renderer_dom';
import {isLContainer, isLView} from '../interfaces/type_checks';
@@ -224,13 +224,13 @@ export function markAncestorsForTraversal(lView: LView) {
while (parent !== null) {
// We stop adding markers to the ancestors once we reach one that already has the marker. This
// is to avoid needlessly traversing all the way to the root when the marker already exists.
if ((isLContainer(parent) && parent[HAS_CHILD_VIEWS_TO_REFRESH] ||
if ((isLContainer(parent) && (parent[FLAGS] & LContainerFlags.HasChildViewsToRefresh) ||
(isLView(parent) && parent[FLAGS] & LViewFlags.HasChildViewsToRefresh))) {
break;
}
if (isLContainer(parent)) {
parent[HAS_CHILD_VIEWS_TO_REFRESH] = true;
parent[FLAGS] |= LContainerFlags.HasChildViewsToRefresh;
} else {
parent[FLAGS] |= LViewFlags.HasChildViewsToRefresh;
if (!viewAttachedToChangeDetector(parent)) {
@@ -233,12 +233,6 @@
{
"name": "GenericBrowserDomAdapter"
},
{
"name": "HAS_CHILD_VIEWS_TO_REFRESH"
},
{
"name": "HAS_TRANSPLANTED_VIEWS"
},
{
"name": "INJECTOR2"
},
@@ -266,6 +260,9 @@
{
"name": "Injector"
},
{
"name": "LContainerFlags"
},
{
"name": "LEAVE_TOKEN_REGEX"
},
@@ -257,12 +257,6 @@
{
"name": "GenericBrowserDomAdapter"
},
{
"name": "HAS_CHILD_VIEWS_TO_REFRESH"
},
{
"name": "HAS_TRANSPLANTED_VIEWS"
},
{
"name": "INJECTOR2"
},
@@ -290,6 +284,9 @@
{
"name": "KeyEventsPlugin"
},
{
"name": "LContainerFlags"
},
{
"name": "LEAVE_TOKEN_REGEX"
},
@@ -164,12 +164,6 @@
{
"name": "GenericBrowserDomAdapter"
},
{
"name": "HAS_CHILD_VIEWS_TO_REFRESH"
},
{
"name": "HAS_TRANSPLANTED_VIEWS"
},
{
"name": "INJECTOR2"
},
@@ -197,6 +191,9 @@
{
"name": "KeyEventsPlugin"
},
{
"name": "LContainerFlags"
},
{
"name": "LOCALE_ID2"
},
@@ -194,12 +194,6 @@
{
"name": "GenericBrowserDomAdapter"
},
{
"name": "HAS_CHILD_VIEWS_TO_REFRESH"
},
{
"name": "HAS_TRANSPLANTED_VIEWS"
},
{
"name": "INJECTOR2"
},
@@ -230,6 +224,9 @@
{
"name": "KeyEventsPlugin"
},
{
"name": "LContainerFlags"
},
{
"name": "LOADING_AFTER_SLOT"
},
@@ -242,12 +242,6 @@
{
"name": "GenericBrowserDomAdapter"
},
{
"name": "HAS_CHILD_VIEWS_TO_REFRESH"
},
{
"name": "HAS_TRANSPLANTED_VIEWS"
},
{
"name": "INJECTOR2"
},
@@ -281,6 +275,9 @@
{
"name": "KeyEventsPlugin"
},
{
"name": "LContainerFlags"
},
{
"name": "LOCALE_ID2"
},
@@ -227,12 +227,6 @@
{
"name": "GenericBrowserDomAdapter"
},
{
"name": "HAS_CHILD_VIEWS_TO_REFRESH"
},
{
"name": "HAS_TRANSPLANTED_VIEWS"
},
{
"name": "INJECTOR2"
},
@@ -266,6 +260,9 @@
{
"name": "KeyEventsPlugin"
},
{
"name": "LContainerFlags"
},
{
"name": "LOCALE_ID2"
},
@@ -104,12 +104,6 @@
{
"name": "GenericBrowserDomAdapter"
},
{
"name": "HAS_CHILD_VIEWS_TO_REFRESH"
},
{
"name": "HAS_TRANSPLANTED_VIEWS"
},
{
"name": "HelloWorldModule"
},
@@ -137,6 +131,9 @@
{
"name": "Injector"
},
{
"name": "LContainerFlags"
},
{
"name": "LOCALE_ID2"
},
@@ -185,12 +185,6 @@
{
"name": "GenericBrowserDomAdapter"
},
{
"name": "HAS_CHILD_VIEWS_TO_REFRESH"
},
{
"name": "HAS_TRANSPLANTED_VIEWS"
},
{
"name": "HEADERS"
},
@@ -239,6 +233,9 @@
{
"name": "Injector"
},
{
"name": "LContainerFlags"
},
{
"name": "LOCALE_ID2"
},
@@ -272,12 +272,6 @@
{
"name": "GuardsCheckStart"
},
{
"name": "HAS_CHILD_VIEWS_TO_REFRESH"
},
{
"name": "HAS_TRANSPLANTED_VIEWS"
},
{
"name": "HistoryStateManager"
},
@@ -323,6 +317,9 @@
{
"name": "ItemComponent"
},
{
"name": "LContainerFlags"
},
{
"name": "LOCALE_ID2"
},
@@ -146,12 +146,6 @@
{
"name": "GenericBrowserDomAdapter"
},
{
"name": "HAS_CHILD_VIEWS_TO_REFRESH"
},
{
"name": "HAS_TRANSPLANTED_VIEWS"
},
{
"name": "INJECTOR2"
},
@@ -179,6 +173,9 @@
{
"name": "Injector"
},
{
"name": "LContainerFlags"
},
{
"name": "LOCALE_ID2"
},
@@ -167,12 +167,6 @@
{
"name": "GenericBrowserDomAdapter"
},
{
"name": "HAS_CHILD_VIEWS_TO_REFRESH"
},
{
"name": "HAS_TRANSPLANTED_VIEWS"
},
{
"name": "INJECTOR2"
},
@@ -206,6 +200,9 @@
{
"name": "KeyEventsPlugin"
},
{
"name": "LContainerFlags"
},
{
"name": "LOCALE_ID2"
},