From 09a2bb839fffb8f45bf63433ffd3529a48155b8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mi=C5=A1ko=20Hevery?= Date: Mon, 14 Oct 2019 13:59:17 -0700 Subject: [PATCH] refactor(ivy): Intruduce LFrame to store global instruction information (#33178) `LFrame` stores information specifice to the current `LView` As the code enters and leaves `LView`s we use `enterView()` and `leaveView()` respectively to build a a stack of `LFrame`s. This allows us to easily restore the previous `LView` instruction state. PR Close #33178 --- integration/_payload-limits.json | 4 +- packages/core/src/render3/component.ts | 11 +- packages/core/src/render3/component_ref.ts | 13 +- packages/core/src/render3/di.ts | 24 +- .../src/render3/instructions/embedded_view.ts | 10 +- .../core/src/render3/instructions/listener.ts | 9 +- .../core/src/render3/instructions/shared.ts | 32 +- packages/core/src/render3/state.ts | 341 +++++++++++------- packages/core/test/acceptance/styling_spec.ts | 2 +- .../cyclic_import/bundle.golden_symbols.json | 36 +- .../hello_world/bundle.golden_symbols.json | 36 +- .../bundling/todo/bundle.golden_symbols.json | 33 +- packages/core/test/render3/di_spec.ts | 6 +- .../perf/directive_instantiate/index.ts | 4 - .../render3/perf/element_text_create/index.ts | 4 - .../core/test/render3/perf/listeners/index.ts | 4 - .../perf/noop_change_detection/index.ts | 2 +- packages/core/test/render3/render_util.ts | 7 +- .../test/sanitization/sanatization_spec.ts | 8 +- 19 files changed, 327 insertions(+), 259 deletions(-) diff --git a/integration/_payload-limits.json b/integration/_payload-limits.json index af1c04b6f1bc7..957460e409c72 100644 --- a/integration/_payload-limits.json +++ b/integration/_payload-limits.json @@ -12,7 +12,7 @@ "master": { "uncompressed": { "runtime-es2015": 1485, - "main-es2015": 14440, + "main-es2015": 14678, "polyfills-es2015": 36808 } } @@ -64,4 +64,4 @@ } } } -} +} \ No newline at end of file diff --git a/packages/core/src/render3/component.ts b/packages/core/src/render3/component.ts index 0164b4f670970..7884bbc34cfc9 100644 --- a/packages/core/src/render3/component.ts +++ b/packages/core/src/render3/component.ts @@ -23,7 +23,7 @@ import {TElementNode, TNode, TNodeType} from './interfaces/node'; import {PlayerHandler} from './interfaces/player'; import {RElement, Renderer3, RendererFactory3, domRendererFactory3} from './interfaces/renderer'; import {CONTEXT, HEADER_OFFSET, LView, LViewFlags, RootContext, RootContextFlags, TVIEW} from './interfaces/view'; -import {getPreviousOrParentTNode, incrementActiveDirectiveId, resetComponentState, selectView, setActiveHostElement} from './state'; +import {enterView, getPreviousOrParentTNode, incrementActiveDirectiveId, leaveView, setActiveHostElement} from './state'; import {publishDefaultGlobalUtils} from './util/global_utils'; import {defaultScheduler, stringifyForError} from './util/misc_utils'; import {getRootContext} from './util/view_traversal_utils'; @@ -111,10 +111,6 @@ export function renderComponent( ngDevMode && publishDefaultGlobalUtils(); ngDevMode && assertComponentType(componentType); - // this is preemptively set to avoid having test and debug code accidentally - // read data from a previous application state... - setActiveHostElement(null); - const rendererFactory = opts.rendererFactory || domRendererFactory3; const sanitizer = opts.sanitizer || null; const componentDef = getComponentDef(componentType) !; @@ -133,7 +129,7 @@ export function renderComponent( null, rootTView, rootContext, rootFlags, null, null, rendererFactory, renderer, undefined, opts.injector || null); - const oldView = selectView(rootView, null); + enterView(rootView, null); let component: T; try { @@ -149,7 +145,7 @@ export function renderComponent( refreshView(rootView, rootTView, null, null); } finally { - selectView(oldView, null); + leaveView(); if (rendererFactory.end) rendererFactory.end(); } @@ -170,7 +166,6 @@ export function renderComponent( export function createRootComponentView( rNode: RElement | null, def: ComponentDef, rootView: LView, rendererFactory: RendererFactory3, renderer: Renderer3, sanitizer?: Sanitizer | null): LView { - resetComponentState(); const tView = rootView[TVIEW]; ngDevMode && assertDataInRange(rootView, 0 + HEADER_OFFSET); rootView[0 + HEADER_OFFSET] = rNode; diff --git a/packages/core/src/render3/component_ref.ts b/packages/core/src/render3/component_ref.ts index 7638973919d12..3fdb9fcaa1fdf 100644 --- a/packages/core/src/render3/component_ref.ts +++ b/packages/core/src/render3/component_ref.ts @@ -29,7 +29,7 @@ import {ComponentDef} from './interfaces/definition'; import {TContainerNode, TElementContainerNode, TElementNode} from './interfaces/node'; import {RNode, RendererFactory3, domRendererFactory3, isProceduralRenderer} from './interfaces/renderer'; import {LView, LViewFlags, TVIEW} from './interfaces/view'; -import {namespaceHTMLInternal, selectView} from './state'; +import {enterView, leaveView} from './state'; import {defaultScheduler} from './util/misc_utils'; import {getTNode} from './util/view_utils'; import {createElementRef} from './view_engine_compatibility'; @@ -133,9 +133,6 @@ export class ComponentFactory extends viewEngine_ComponentFactory { rootViewInjector.get(RendererFactory2, domRendererFactory3) as RendererFactory3; const sanitizer = rootViewInjector.get(Sanitizer, null); - // Ensure that the namespace for the root node is correct, - // otherwise the browser might not render out the element properly. - namespaceHTMLInternal(); const hostRNode = rootSelectorOrNode ? locateHostElement(rendererFactory, rootSelectorOrNode) : elementCreate(this.selector, rendererFactory.createRenderer(null, this.componentDef), null); @@ -167,7 +164,11 @@ export class ComponentFactory extends viewEngine_ComponentFactory { rootViewInjector); // rootView is the parent when bootstrapping - const oldLView = selectView(rootLView, null); + // TODO(misko): it looks like we are entering view here but we don't really need to as + // `renderView` does that. However as the code is written it is needed because + // `createRootComponentView` and `createRootComponent` both read global state. Fixing those + // issues would allow us to drop this. + enterView(rootLView, null); let component: T; let tElementNode: TElementNode; @@ -194,7 +195,7 @@ export class ComponentFactory extends viewEngine_ComponentFactory { renderView(rootLView, rootTView, null); } finally { - selectView(oldLView, null); + leaveView(); } const componentRef = new ComponentRef( diff --git a/packages/core/src/render3/di.ts b/packages/core/src/render3/di.ts index e6581f91fa533..8b63e30d0c47a 100644 --- a/packages/core/src/render3/di.ts +++ b/packages/core/src/render3/di.ts @@ -10,7 +10,7 @@ import {isForwardRef, resolveForwardRef} from '../di/forward_ref'; import {InjectionToken} from '../di/injection_token'; import {Injector} from '../di/injector'; import {injectRootLimpMode, setInjectImplementation} from '../di/injector_compatibility'; -import {getInjectableDef, getInjectorDef} from '../di/interface/defs'; +import {getInjectorDef} from '../di/interface/defs'; import {InjectFlags} from '../di/interface/injector'; import {Type} from '../interface/type'; import {assertDefined, assertEqual} from '../util/assert'; @@ -19,11 +19,11 @@ import {getFactoryDef} from './definition'; import {NG_ELEMENT_ID, NG_FACTORY_DEF} from './fields'; import {DirectiveDef, FactoryFn} from './interfaces/definition'; import {NO_PARENT_INJECTOR, NodeInjectorFactory, PARENT_INJECTOR, RelativeInjectorLocation, RelativeInjectorLocationFlags, TNODE, isFactory} from './interfaces/injector'; -import {AttributeMarker, TContainerNode, TElementContainerNode, TElementNode, TNode, TNodeFlags, TNodeProviderIndexes, TNodeType} from './interfaces/node'; +import {AttributeMarker, TContainerNode, TElementContainerNode, TElementNode, TNode, TNodeProviderIndexes, TNodeType} from './interfaces/node'; import {isComponentDef, isComponentHost} from './interfaces/type_checks'; import {DECLARATION_VIEW, INJECTOR, LView, TData, TVIEW, TView, T_HOST} from './interfaces/view'; import {assertNodeOfPossibleTypes} from './node_assert'; -import {getLView, getPreviousOrParentTNode, setTNodeAndViewData} from './state'; +import {enterDI, leaveDI} from './state'; import {isNameOnlyAttributeMarker} from './util/attrs_utils'; import {getParentInjectorIndex, getParentInjectorView, hasParentInjector} from './util/injector_utils'; import {stringifyForError} from './util/misc_utils'; @@ -334,9 +334,7 @@ export function getOrCreateInjectable( // If the ID stored here is a function, this is a special object like ElementRef or TemplateRef // so just call the factory function to create it. if (typeof bloomHash === 'function') { - const savePreviousOrParentTNode = getPreviousOrParentTNode(); - const saveLView = getLView(); - setTNodeAndViewData(tNode, lView); + enterDI(lView, tNode); try { const value = bloomHash(); if (value == null && !(flags & InjectFlags.Optional)) { @@ -345,7 +343,7 @@ export function getOrCreateInjectable( return value; } } finally { - setTNodeAndViewData(savePreviousOrParentTNode, saveLView); + leaveDI(); } } else if (typeof bloomHash == 'number') { if (bloomHash === -1) { @@ -530,8 +528,8 @@ export function locateDirectiveOrProvider( * instantiates the `injectable` and caches the value. */ export function getNodeInjectable( - tData: TData, lData: LView, index: number, tNode: TElementNode): any { - let value = lData[index]; + tData: TData, lView: LView, index: number, tNode: TElementNode): any { + let value = lView[index]; if (isFactory(value)) { const factory: NodeInjectorFactory = value; if (factory.resolving) { @@ -543,16 +541,14 @@ export function getNodeInjectable( if (factory.injectImpl) { previousInjectImplementation = setInjectImplementation(factory.injectImpl); } - const savePreviousOrParentTNode = getPreviousOrParentTNode(); - const saveLView = getLView(); - setTNodeAndViewData(tNode, lData); + enterDI(lView, tNode); try { - value = lData[index] = factory.factory(undefined, tData, lData, tNode); + value = lView[index] = factory.factory(undefined, tData, lView, tNode); } finally { if (factory.injectImpl) setInjectImplementation(previousInjectImplementation); setIncludeViewProviders(previousIncludeViewProviders); factory.resolving = false; - setTNodeAndViewData(savePreviousOrParentTNode, saveLView); + leaveDI(); } } return value; diff --git a/packages/core/src/render3/instructions/embedded_view.ts b/packages/core/src/render3/instructions/embedded_view.ts index 0ceeaf309e975..72bafd6a35980 100644 --- a/packages/core/src/render3/instructions/embedded_view.ts +++ b/packages/core/src/render3/instructions/embedded_view.ts @@ -14,12 +14,12 @@ import {TContainerNode, TNodeType} from '../interfaces/node'; import {CONTEXT, LView, LViewFlags, PARENT, TVIEW, TView, T_HOST} from '../interfaces/view'; import {assertNodeType} from '../node_assert'; import {insertView, removeView} from '../node_manipulation'; -import {getIsParent, getLView, getPreviousOrParentTNode, selectView, setIsParent, setPreviousOrParentTNode} from '../state'; +import {enterView, getIsParent, getLView, getPreviousOrParentTNode, leaveViewProcessExit, setIsParent, setPreviousOrParentTNode} from '../state'; import {isCreationMode} from '../util/view_utils'; - import {assignTViewNodeToLView, createLView, createTView, refreshView, renderView} from './shared'; + /** * Marks the start of an embedded view. * @@ -42,7 +42,7 @@ export function ɵɵembeddedViewStart(viewBlockId: number, decls: number, vars: if (viewToRender) { setIsParent(); - selectView(viewToRender, viewToRender[TVIEW].node); + enterView(viewToRender, viewToRender[TVIEW].node); } else { // When we create a new LView, we always reset the state of the instructions. viewToRender = createLView( @@ -52,7 +52,7 @@ export function ɵɵembeddedViewStart(viewBlockId: number, decls: number, vars: const tParentNode = getIsParent() ? previousOrParentTNode : previousOrParentTNode && previousOrParentTNode.parent; assignTViewNodeToLView(viewToRender[TVIEW], tParentNode, viewBlockId, viewToRender); - selectView(viewToRender, viewToRender[TVIEW].node); + enterView(viewToRender, viewToRender[TVIEW].node); } if (lContainer) { if (isCreationMode(viewToRender)) { @@ -138,6 +138,6 @@ export function ɵɵembeddedViewEnd(): void { const lContainer = lView[PARENT] as LContainer; ngDevMode && assertLContainerOrUndefined(lContainer); - selectView(lContainer[PARENT] !, null); + leaveViewProcessExit(); setPreviousOrParentTNode(viewHost !, false); } diff --git a/packages/core/src/render3/instructions/listener.ts b/packages/core/src/render3/instructions/listener.ts index 5d7bebec504f8..307423c46c09b 100644 --- a/packages/core/src/render3/instructions/listener.ts +++ b/packages/core/src/render3/instructions/listener.ts @@ -17,8 +17,11 @@ import {CLEANUP, FLAGS, LView, LViewFlags, RENDERER, TVIEW} from '../interfaces/ import {assertNodeOfPossibleTypes} from '../node_assert'; import {getLView, getPreviousOrParentTNode} from '../state'; import {getComponentLViewByIndex, getNativeByTNode, unwrapRNode} from '../util/view_utils'; + import {getCleanup, handleError, loadComponentRenderer, markViewDirty} from './shared'; + + /** * Adds an event listener to the current node. * @@ -213,7 +216,7 @@ function listenerInternal( } function executeListenerWithErrorHandling( - lView: LView, listenerFn: (e?: any) => any, e: any): boolean { + lView: LView, tNode: TNode, listenerFn: (e?: any) => any, e: any): boolean { try { // Only explicitly returning false from a listener should preventDefault return listenerFn(e) !== false; @@ -256,13 +259,13 @@ function wrapListener( markViewDirty(startView); } - let result = executeListenerWithErrorHandling(lView, listenerFn, e); + let result = executeListenerWithErrorHandling(lView, tNode, listenerFn, e); // A just-invoked listener function might have coalesced listeners so we need to check for // their presence and invoke as needed. let nextListenerFn = (wrapListenerIn_markDirtyAndPreventDefault).__ngNextListenerFn__; while (nextListenerFn) { // We should prevent default if any of the listeners explicitly return false - result = executeListenerWithErrorHandling(lView, nextListenerFn, e) && result; + result = executeListenerWithErrorHandling(lView, tNode, nextListenerFn, e) && result; nextListenerFn = (nextListenerFn).__ngNextListenerFn__; } diff --git a/packages/core/src/render3/instructions/shared.ts b/packages/core/src/render3/instructions/shared.ts index a28e394246460..0d10dccf31ca7 100644 --- a/packages/core/src/render3/instructions/shared.ts +++ b/packages/core/src/render3/instructions/shared.ts @@ -15,7 +15,7 @@ import {createNamedArrayType} from '../../util/named_array_type'; import {initNgDevMode} from '../../util/ng_dev_mode'; import {normalizeDebugBindingName, normalizeDebugBindingValue} from '../../util/ng_reflect'; import {assertFirstTemplatePass, assertLView} from '../assert'; -import {attachPatchData, getComponentViewByInstance} from '../context_discovery'; +import {attachPatchData} from '../context_discovery'; import {getFactoryDef} from '../definition'; import {diPublicInInjector, getNodeInjectable, getOrCreateNodeInjectorForNode} from '../di'; import {throwMultipleComponentError} from '../errors'; @@ -30,7 +30,7 @@ import {isComponentDef, isComponentHost, isContentQueryHost, isLContainer, isRoo import {BINDING_INDEX, CHILD_HEAD, CHILD_TAIL, CLEANUP, CONTEXT, DECLARATION_VIEW, ExpandoInstructions, FLAGS, HEADER_OFFSET, HOST, INJECTOR, InitPhaseState, LView, LViewFlags, NEXT, PARENT, RENDERER, RENDERER_FACTORY, RootContext, RootContextFlags, SANITIZER, TData, TVIEW, TView, T_HOST} from '../interfaces/view'; import {assertNodeOfPossibleTypes} from '../node_assert'; import {isNodeMatchingSelectorList} from '../node_selector_matcher'; -import {ActiveElementFlags, executeElementExitFn, getBindingsEnabled, getCheckNoChangesMode, getIsParent, getPreviousOrParentTNode, getSelectedIndex, hasActiveElementFlag, incrementActiveDirectiveId, namespaceHTMLInternal, selectView, setActiveHostElement, setBindingRoot, setCheckNoChangesMode, setCurrentDirectiveDef, setCurrentQueryIndex, setPreviousOrParentTNode, setSelectedIndex} from '../state'; +import {ActiveElementFlags, enterView, executeElementExitFn, getBindingsEnabled, getCheckNoChangesMode, getIsParent, getPreviousOrParentTNode, getSelectedIndex, hasActiveElementFlag, incrementActiveDirectiveId, leaveView, leaveViewProcessExit, setActiveHostElement, setBindingRoot, setCheckNoChangesMode, setCurrentDirectiveDef, setCurrentQueryIndex, setPreviousOrParentTNode, setSelectedIndex} from '../state'; import {renderStylingMap} from '../styling/bindings'; import {NO_CHANGE} from '../tokens'; import {isAnimationProp} from '../util/attrs_utils'; @@ -312,7 +312,7 @@ export function allocExpando(view: LView, numSlotsToAlloc: number) { */ export function renderView(lView: LView, tView: TView, context: T): void { ngDevMode && assertEqual(isCreationMode(lView), true, 'Should be run in creation mode'); - const oldView = selectView(lView, lView[T_HOST]); + enterView(lView, lView[T_HOST]); try { const viewQuery = tView.viewQuery; if (viewQuery !== null) { @@ -357,7 +357,7 @@ export function renderView(lView: LView, tView: TView, context: T): void { } finally { lView[FLAGS] &= ~LViewFlags.CreationMode; - selectView(oldView, null); + leaveView(); } } @@ -372,7 +372,7 @@ export function renderView(lView: LView, tView: TView, context: T): void { export function refreshView( lView: LView, tView: TView, templateFn: ComponentTemplate<{}>| null, context: T) { ngDevMode && assertEqual(isCreationMode(lView), false, 'Should be run in update mode'); - const oldView = selectView(lView, lView[T_HOST]); + enterView(lView, lView[T_HOST]); const flags = lView[FLAGS]; try { resetPreOrderHookFlags(lView); @@ -463,7 +463,7 @@ export function refreshView( } finally { lView[FLAGS] &= ~(LViewFlags.Dirty | LViewFlags.FirstLViewPass); - selectView(oldView, null); + leaveViewProcessExit(); } } @@ -472,8 +472,6 @@ export function renderComponentOrTemplate( const rendererFactory = hostView[RENDERER_FACTORY]; const normalExecutionPath = !getCheckNoChangesMode(); const creationModeIsActive = isCreationMode(hostView); - const previousOrParentTNode = getPreviousOrParentTNode(); - const isParent = getIsParent(); try { if (normalExecutionPath && !creationModeIsActive && rendererFactory.begin) { rendererFactory.begin(); @@ -487,13 +485,11 @@ export function renderComponentOrTemplate( if (normalExecutionPath && !creationModeIsActive && rendererFactory.end) { rendererFactory.end(); } - setPreviousOrParentTNode(previousOrParentTNode, isParent); } } function executeTemplate( lView: LView, templateFn: ComponentTemplate, rf: RenderFlags, context: T) { - namespaceHTMLInternal(); const prevSelectedIndex = getSelectedIndex(); try { setActiveHostElement(null); @@ -1659,9 +1655,6 @@ export function tickRootContext(rootContext: RootContext) { export function detectChangesInternal(view: LView, context: T) { const rendererFactory = view[RENDERER_FACTORY]; - const previousOrParentTNode = getPreviousOrParentTNode(); - const isParent = getIsParent(); - if (rendererFactory.begin) rendererFactory.begin(); try { const tView = view[TVIEW]; @@ -1671,7 +1664,6 @@ export function detectChangesInternal(view: LView, context: T) { throw error; } finally { if (rendererFactory.end) rendererFactory.end(); - setPreviousOrParentTNode(previousOrParentTNode, isParent); } } @@ -1684,18 +1676,6 @@ export function detectChangesInRootView(lView: LView): void { tickRootContext(lView[CONTEXT] as RootContext); } - -/** - * Checks the change detector and its children, and throws if any changes are detected. - * - * This is used in development mode to verify that running change detection doesn't - * introduce other changes. - */ -export function checkNoChanges(component: T): void { - const view = getComponentViewByInstance(component); - checkNoChangesInternal(view, component); -} - export function checkNoChangesInternal(view: LView, context: T) { setCheckNoChangesMode(true); try { diff --git a/packages/core/src/render3/state.ts b/packages/core/src/render3/state.ts index a47e8172b3a29..7e81335adcc05 100644 --- a/packages/core/src/render3/state.ts +++ b/packages/core/src/render3/state.ts @@ -11,19 +11,28 @@ import {assertDefined, assertEqual} from '../util/assert'; import {assertLViewOrUndefined} from './assert'; import {ComponentDef, DirectiveDef} from './interfaces/definition'; -import {TElementNode, TNode, TViewNode} from './interfaces/node'; -import {CONTEXT, DECLARATION_VIEW, LView, OpaqueViewState} from './interfaces/view'; +import {TNode} from './interfaces/node'; +import {BINDING_INDEX, CONTEXT, DECLARATION_VIEW, LView, OpaqueViewState, TVIEW} from './interfaces/view'; + /** - * All implicit instruction state is stored here. - * - * It is useful to have a single object where all of the state is stored as a mental model - * (rather it being spread across many different variables.) * - * PERF NOTE: Turns out that writing to a true global variable is slower than - * having an intermediate object with properties. */ -interface InstructionState { +interface LFrame { + /** + * Parent LFrame. + * + * This is needed when `leaveView` is called to restore the previous state. + */ + parent: LFrame; + + /** + * Child LFrame. + * + * This is used to cache existing LFrames to relieve the memory pressure. + */ + child: LFrame|null; + /** * State of the current view being processed. * @@ -61,39 +70,14 @@ interface InstructionState { */ contextLView: LView; - /** - * In this mode, any changes in bindings will throw an ExpressionChangedAfterChecked error. - * - * Necessary to support ChangeDetectorRef.checkNoChanges(). - */ - checkNoChangesMode: boolean; - /** * Store the element depth count. This is used to identify the root elements of the template - * so that we can then attach `LView` to only those elements. + * so that we can then attach patch data `LView` to only those elements. We know that those + * are the only places where the patch data could change, this way we will save on number + * of places where tha patching occurs. */ elementDepthCount: number; - /** - * Stores whether directives should be matched to elements. - * - * When template contains `ngNonBindable` then we need to prevent the runtime form matching - * directives on children of that element. - * - * Example: - * ``` - * - * Should match component / directive. - * - *
- * - * Should not match component / directive because we are in ngNonBindable. - * - *
- * ``` - */ - bindingsEnabled: boolean; - /** * Current namespace to be used when creating elements */ @@ -131,7 +115,51 @@ interface InstructionState { * We iterate over the list of Queries and increment current query index at every step. */ currentQueryIndex: number; +} + +/** + * All implicit instruction state is stored here. + * + * It is useful to have a single object where all of the state is stored as a mental model + * (rather it being spread across many different variables.) + * + * PERF NOTE: Turns out that writing to a true global variable is slower than + * having an intermediate object with properties. + */ +interface InstructionState { + /** + * Current `LFrame` + * + * `null` if we have not called `enterView` + */ + lFrame: LFrame; + + /** + * Stores whether directives should be matched to elements. + * + * When template contains `ngNonBindable` then we need to prevent the runtime from matching + * directives on children of that element. + * + * Example: + * ``` + * + * Should match component / directive. + * + *
+ * + * Should not match component / directive because we are in ngNonBindable. + * + *
+ * ``` + */ + bindingsEnabled: boolean; + /** + * In this mode, any changes in bindings will throw an ExpressionChangedAfterChecked error. + * + * Necessary to support ChangeDetectorRef.checkNoChanges(). + */ + checkNoChangesMode: boolean; /** * Function to be called when the element is exited. @@ -142,49 +170,34 @@ interface InstructionState { } export const instructionState: InstructionState = { - previousOrParentTNode: null !, - isParent: null !, - lView: null !, - // tslint:disable-next-line: no-toplevel-property-access - selectedIndex: -1 << ActiveElementFlags.Size, - contextLView: null !, - checkNoChangesMode: false, - elementDepthCount: 0, + lFrame: createLFrame(null), bindingsEnabled: true, - currentNamespace: null, - currentSanitizer: null, - currentDirectiveDef: null, - activeDirectiveId: 0, - bindingRootIndex: -1, - currentQueryIndex: 0, elementExitFn: null, + checkNoChangesMode: false, }; export function getElementDepthCount() { - // top level variables should not be exported for performance reasons (PERF_NOTES.md) - return instructionState.elementDepthCount; + return instructionState.lFrame.elementDepthCount; } export function increaseElementDepthCount() { - instructionState.elementDepthCount++; + instructionState.lFrame.elementDepthCount++; } export function decreaseElementDepthCount() { - instructionState.elementDepthCount--; + instructionState.lFrame.elementDepthCount--; } export function getCurrentDirectiveDef(): DirectiveDef|ComponentDef|null { - // top level variables should not be exported for performance reasons (PERF_NOTES.md) - return instructionState.currentDirectiveDef; + return instructionState.lFrame.currentDirectiveDef; } export function setCurrentDirectiveDef(def: DirectiveDef| ComponentDef| null): void { - instructionState.currentDirectiveDef = def; + instructionState.lFrame.currentDirectiveDef = def; } export function getBindingsEnabled(): boolean { - // top level variables should not be exported for performance reasons (PERF_NOTES.md) return instructionState.bindingsEnabled; } @@ -235,8 +248,16 @@ export function ɵɵdisableBindings(): void { instructionState.bindingsEnabled = false; } +/** + * Return the current LView. + * + * The return value can be `null` if the method is called outside of template. This can happen if + * directive is instantiated by module injector (rather than by node injector.) + */ export function getLView(): LView { - return instructionState.lView; + // TODO(misko): the return value should be `LView|null` but doing so breaks a lot of code. + const lFrame = instructionState.lFrame; + return lFrame === null ? null ! : lFrame.lView; } /** @@ -259,14 +280,14 @@ export const enum ActiveElementFlags { * Determines whether or not a flag is currently set for the active element. */ export function hasActiveElementFlag(flag: ActiveElementFlags) { - return (instructionState.selectedIndex & flag) === flag; + return (instructionState.lFrame.selectedIndex & flag) === flag; } /** * Sets a flag is for the active element. */ -export function setActiveElementFlag(flag: ActiveElementFlags) { - instructionState.selectedIndex |= flag; +function setActiveElementFlag(flag: ActiveElementFlags) { + instructionState.lFrame.selectedIndex |= flag; } /** @@ -277,20 +298,16 @@ export function setActiveElementFlag(flag: ActiveElementFlags) { * the directive/component instance lives */ export function setActiveHostElement(elementIndex: number | null = null) { - if (getSelectedIndex() !== elementIndex) { - if (hasActiveElementFlag(ActiveElementFlags.RunExitFn)) { - executeElementExitFn(); - } - setSelectedIndex(elementIndex === null ? -1 : elementIndex); - instructionState.activeDirectiveId = 0; + if (hasActiveElementFlag(ActiveElementFlags.RunExitFn)) { + executeElementExitFn(); } + setSelectedIndex(elementIndex === null ? -1 : elementIndex); + instructionState.lFrame.activeDirectiveId = 0; } export function executeElementExitFn() { instructionState.elementExitFn !(); - // TODO (matsko|misko): remove this unassignment once the state management of - // global variables are better managed. - instructionState.selectedIndex &= ~ActiveElementFlags.RunExitFn; + instructionState.lFrame.selectedIndex &= ~ActiveElementFlags.RunExitFn; } /** @@ -331,7 +348,7 @@ export function setElementExitFn(fn: () => void): void { * different set of directives). */ export function getActiveDirectiveId() { - return instructionState.activeDirectiveId; + return instructionState.lFrame.activeDirectiveId; } /** @@ -360,7 +377,7 @@ export function incrementActiveDirectiveId() { // directive uniqueId is not set anywhere--it is just incremented between // each hostBindings call and is useful for helping instruction code // uniquely determine which directive is currently active when executed. - instructionState.activeDirectiveId += 1; + instructionState.lFrame.activeDirectiveId += 1; } /** @@ -375,44 +392,34 @@ export function incrementActiveDirectiveId() { * @codeGenApi */ export function ɵɵrestoreView(viewToRestore: OpaqueViewState) { - instructionState.contextLView = viewToRestore as any as LView; + instructionState.lFrame.contextLView = viewToRestore as any as LView; } export function getPreviousOrParentTNode(): TNode { - // top level variables should not be exported for performance reasons (PERF_NOTES.md) - return instructionState.previousOrParentTNode; + return instructionState.lFrame.previousOrParentTNode; } export function setPreviousOrParentTNode(tNode: TNode, _isParent: boolean) { - instructionState.previousOrParentTNode = tNode; - instructionState.isParent = _isParent; -} - -export function setTNodeAndViewData(tNode: TNode, view: LView) { - ngDevMode && assertLViewOrUndefined(view); - instructionState.previousOrParentTNode = tNode; - instructionState.lView = view; + instructionState.lFrame.previousOrParentTNode = tNode; + instructionState.lFrame.isParent = _isParent; } export function getIsParent(): boolean { - // top level variables should not be exported for performance reasons (PERF_NOTES.md) - return instructionState.isParent; + return instructionState.lFrame.isParent; } export function setIsNotParent(): void { - instructionState.isParent = false; + instructionState.lFrame.isParent = false; } export function setIsParent(): void { - instructionState.isParent = true; + instructionState.lFrame.isParent = true; } export function getContextLView(): LView { - // top level variables should not be exported for performance reasons (PERF_NOTES.md) - return instructionState.contextLView; + return instructionState.lFrame.contextLView; } export function getCheckNoChangesMode(): boolean { - // top level variables should not be exported for performance reasons (PERF_NOTES.md) return instructionState.checkNoChangesMode; } @@ -422,22 +429,63 @@ export function setCheckNoChangesMode(mode: boolean): void { // top level variables should not be exported for performance reasons (PERF_NOTES.md) export function getBindingRoot() { - return instructionState.bindingRootIndex; + const lFrame = instructionState.lFrame; + let index = lFrame.bindingRootIndex; + if (index === -1) { + const lView = lFrame.lView; + index = lFrame.bindingRootIndex = lView[BINDING_INDEX] = lView[TVIEW].bindingStartIndex; + } + return index; } export function setBindingRoot(value: number) { - instructionState.bindingRootIndex = value; + instructionState.lFrame.bindingRootIndex = value; } export function getCurrentQueryIndex(): number { - // top level variables should not be exported for performance reasons (PERF_NOTES.md) - return instructionState.currentQueryIndex; + return instructionState.lFrame.currentQueryIndex; } export function setCurrentQueryIndex(value: number): void { - instructionState.currentQueryIndex = value; + instructionState.lFrame.currentQueryIndex = value; } +/** + * This is a light weight version of the `enterView` which is needed by the DI system. + * @param newView + * @param tNode + */ +export function enterDI(newView: LView, tNode: TNode) { + ngDevMode && assertLViewOrUndefined(newView); + const newLFrame = allocLFrame(); + instructionState.lFrame = newLFrame; + newLFrame.previousOrParentTNode = tNode !; + newLFrame.lView = newView; + if (ngDevMode) { + // resetting for safety in dev mode only. + newLFrame.isParent = DEV_MODE_VALUE; + newLFrame.selectedIndex = DEV_MODE_VALUE; + newLFrame.contextLView = DEV_MODE_VALUE; + newLFrame.elementDepthCount = DEV_MODE_VALUE; + newLFrame.currentNamespace = DEV_MODE_VALUE; + newLFrame.currentSanitizer = DEV_MODE_VALUE; + newLFrame.currentDirectiveDef = DEV_MODE_VALUE; + newLFrame.activeDirectiveId = DEV_MODE_VALUE; + newLFrame.bindingRootIndex = DEV_MODE_VALUE; + newLFrame.currentQueryIndex = DEV_MODE_VALUE; + } +} + +const DEV_MODE_VALUE: any = + 'Value indicating that DI is trying to read value which it should not need to know about.'; + +/** + * This is a light weight version of the `leaveView` which is needed by the DI system. + * + * Because the implementation is same it is only an alias + */ +export const leaveDI = leaveView; + /** * Swap the current lView with a new lView. * @@ -447,27 +495,72 @@ export function setCurrentQueryIndex(value: number): void { * exited the state has to be restored * * @param newView New lView to become active - * @param host Element to which the View is a child of + * @param tNode Element to which the View is a child of * @returns the previously active lView; */ -export function selectView(newView: LView, hostTNode: TElementNode | TViewNode | null): LView { +export function enterView(newView: LView, tNode: TNode | null): void { + ngDevMode && assertLViewOrUndefined(newView); + const newLFrame = allocLFrame(); + instructionState.lFrame = newLFrame; + newLFrame.previousOrParentTNode = tNode !; + newLFrame.isParent = true; + newLFrame.lView = newView; + newLFrame.selectedIndex = 0; + newLFrame.contextLView = newView !; + newLFrame.elementDepthCount = 0; + newLFrame.currentNamespace = null; + newLFrame.currentSanitizer = null; + newLFrame.currentDirectiveDef = null; + newLFrame.activeDirectiveId = 0; + newLFrame.bindingRootIndex = -1; + newLFrame.currentQueryIndex = 0; +} + +/** + * Allocates next free LFrame. This function tries to reuse the `LFrame`s to lower memory pressure. + */ +function allocLFrame() { + const currentLFrame = instructionState.lFrame; + const childLFrame = currentLFrame === null ? null : currentLFrame.child; + const newLFrame = childLFrame === null ? createLFrame(currentLFrame) : childLFrame; + return newLFrame; +} + +function createLFrame(parent: LFrame | null): LFrame { + const lFrame: LFrame = { + previousOrParentTNode: null !, // + isParent: true, // + lView: null !, // + selectedIndex: 0, // + contextLView: null !, // + elementDepthCount: 0, // + currentNamespace: null, // + currentSanitizer: null, // + currentDirectiveDef: null, // + activeDirectiveId: 0, // + bindingRootIndex: -1, // + currentQueryIndex: 0, // + parent: parent !, // + child: null, // + }; + parent !== null && (parent.child = lFrame); // link the new LFrame for reuse. + return lFrame; +} + +export function leaveViewProcessExit() { if (hasActiveElementFlag(ActiveElementFlags.RunExitFn)) { executeElementExitFn(); } + leaveView(); +} - ngDevMode && assertLViewOrUndefined(newView); - const oldView = instructionState.lView; - - instructionState.previousOrParentTNode = hostTNode !; - instructionState.isParent = true; - - instructionState.lView = instructionState.contextLView = newView; - return oldView; +export function leaveView() { + instructionState.lFrame = instructionState.lFrame.parent; } export function nextContextImpl(level: number = 1): T { - instructionState.contextLView = walkUpViews(level, instructionState.contextLView !); - return instructionState.contextLView[CONTEXT] as T; + instructionState.lFrame.contextLView = walkUpViews(level, instructionState.lFrame.contextLView !); + return instructionState.lFrame.contextLView[CONTEXT] as T; } function walkUpViews(nestingLevel: number, currentView: LView): LView { @@ -481,17 +574,6 @@ function walkUpViews(nestingLevel: number, currentView: LView): LView { return currentView; } -/** - * Resets the application state. - */ -export function resetComponentState() { - instructionState.isParent = false; - instructionState.previousOrParentTNode = null !; - instructionState.elementDepthCount = 0; - instructionState.bindingsEnabled = true; - setCurrentStyleSanitizer(null); -} - /** * Gets the most recent index passed to {@link select} * @@ -499,7 +581,7 @@ export function resetComponentState() { * current `LView` to act on. */ export function getSelectedIndex() { - return instructionState.selectedIndex >> ActiveElementFlags.Size; + return instructionState.lFrame.selectedIndex >> ActiveElementFlags.Size; } /** @@ -512,7 +594,7 @@ export function getSelectedIndex() { * run if and when the provided `index` value is different from the current selected index value.) */ export function setSelectedIndex(index: number) { - instructionState.selectedIndex = index << ActiveElementFlags.Size; + instructionState.lFrame.selectedIndex = index << ActiveElementFlags.Size; } @@ -522,7 +604,7 @@ export function setSelectedIndex(index: number) { * @codeGenApi */ export function ɵɵnamespaceSVG() { - instructionState.currentNamespace = 'http://www.w3.org/2000/svg'; + instructionState.lFrame.currentNamespace = 'http://www.w3.org/2000/svg'; } /** @@ -531,7 +613,7 @@ export function ɵɵnamespaceSVG() { * @codeGenApi */ export function ɵɵnamespaceMathML() { - instructionState.currentNamespace = 'http://www.w3.org/1998/MathML/'; + instructionState.lFrame.currentNamespace = 'http://www.w3.org/1998/MathML/'; } /** @@ -549,15 +631,15 @@ export function ɵɵnamespaceHTML() { * `createElement` rather than `createElementNS`. */ export function namespaceHTMLInternal() { - instructionState.currentNamespace = null; + instructionState.lFrame.currentNamespace = null; } export function getNamespace(): string|null { - return instructionState.currentNamespace; + return instructionState.lFrame.currentNamespace; } export function setCurrentStyleSanitizer(sanitizer: StyleSanitizeFn | null) { - instructionState.currentSanitizer = sanitizer; + instructionState.lFrame.currentSanitizer = sanitizer; } export function resetCurrentStyleSanitizer() { @@ -565,5 +647,8 @@ export function resetCurrentStyleSanitizer() { } export function getCurrentStyleSanitizer() { - return instructionState.currentSanitizer; + // TODO(misko): This should throw when there is no LView, but it turns out we can get here from + // `NodeStyleDebug` hence we return `null`. This should be fixed + const lFrame = instructionState.lFrame; + return lFrame === null ? null : lFrame.currentSanitizer; } diff --git a/packages/core/test/acceptance/styling_spec.ts b/packages/core/test/acceptance/styling_spec.ts index 25a4f19a7fa99..c8248228140d1 100644 --- a/packages/core/test/acceptance/styling_spec.ts +++ b/packages/core/test/acceptance/styling_spec.ts @@ -2105,7 +2105,7 @@ describe('styling', () => { expect(readyChild).toBeTruthy(); }); - onlyInIvy('only ivy allows for multiple styles/classes to be balanaced across directives') + onlyInIvy('only ivy allows for multiple styles/classes to be balanced across directives') .it('should allow various duplicate properties to be defined in various styling maps within the template and directive styling bindings', () => { @Component({ diff --git a/packages/core/test/bundling/cyclic_import/bundle.golden_symbols.json b/packages/core/test/bundling/cyclic_import/bundle.golden_symbols.json index 58ce0ef3baecb..3c63b957fd6bb 100644 --- a/packages/core/test/bundling/cyclic_import/bundle.golden_symbols.json +++ b/packages/core/test/bundling/cyclic_import/bundle.golden_symbols.json @@ -155,6 +155,9 @@ { "name": "addToViewTree" }, + { + "name": "allocLFrame" + }, { "name": "allocStylingMapArray" }, @@ -185,6 +188,9 @@ { "name": "createDirectivesInstances" }, + { + "name": "createLFrame" + }, { "name": "createLView" }, @@ -227,6 +233,12 @@ { "name": "elementCreate" }, + { + "name": "enterDI" + }, + { + "name": "enterView" + }, { "name": "executeCheckHooks" }, @@ -479,6 +491,15 @@ { "name": "isStylingValueDefined" }, + { + "name": "leaveDI" + }, + { + "name": "leaveView" + }, + { + "name": "leaveViewProcessExit" + }, { "name": "locateHostElement" }, @@ -488,9 +509,6 @@ { "name": "matchTemplateAttribute" }, - { - "name": "namespaceHTMLInternal" - }, { "name": "nativeAppendChild" }, @@ -560,9 +578,6 @@ { "name": "renderView" }, - { - "name": "resetComponentState" - }, { "name": "resetPreOrderHookFlags" }, @@ -581,9 +596,6 @@ { "name": "selectIndexInternal" }, - { - "name": "selectView" - }, { "name": "setActiveHostElement" }, @@ -599,9 +611,6 @@ { "name": "setCurrentQueryIndex" }, - { - "name": "setCurrentStyleSanitizer" - }, { "name": "setDirectiveStylingInput" }, @@ -635,9 +644,6 @@ { "name": "setStyle" }, - { - "name": "setTNodeAndViewData" - }, { "name": "setUpAttributes" }, diff --git a/packages/core/test/bundling/hello_world/bundle.golden_symbols.json b/packages/core/test/bundling/hello_world/bundle.golden_symbols.json index 7758a17a73f81..2f90cfa8578b7 100644 --- a/packages/core/test/bundling/hello_world/bundle.golden_symbols.json +++ b/packages/core/test/bundling/hello_world/bundle.golden_symbols.json @@ -134,6 +134,9 @@ { "name": "addToViewTree" }, + { + "name": "allocLFrame" + }, { "name": "appendChild" }, @@ -152,6 +155,9 @@ { "name": "callHooks" }, + { + "name": "createLFrame" + }, { "name": "createLView" }, @@ -188,6 +194,12 @@ { "name": "domRendererFactory3" }, + { + "name": "enterDI" + }, + { + "name": "enterView" + }, { "name": "executeCheckHooks" }, @@ -351,13 +363,19 @@ "name": "isRootView" }, { - "name": "locateHostElement" + "name": "leaveDI" }, { - "name": "markAsComponentHost" + "name": "leaveView" + }, + { + "name": "leaveViewProcessExit" }, { - "name": "namespaceHTMLInternal" + "name": "locateHostElement" + }, + { + "name": "markAsComponentHost" }, { "name": "nativeAppendChild" @@ -410,18 +428,12 @@ { "name": "renderView" }, - { - "name": "resetComponentState" - }, { "name": "resetPreOrderHookFlags" }, { "name": "selectIndexInternal" }, - { - "name": "selectView" - }, { "name": "setActiveHostElement" }, @@ -434,9 +446,6 @@ { "name": "setCurrentQueryIndex" }, - { - "name": "setCurrentStyleSanitizer" - }, { "name": "setHostBindings" }, @@ -455,9 +464,6 @@ { "name": "setSelectedIndex" }, - { - "name": "setTNodeAndViewData" - }, { "name": "stringifyForError" }, diff --git a/packages/core/test/bundling/todo/bundle.golden_symbols.json b/packages/core/test/bundling/todo/bundle.golden_symbols.json index 02ba8c6a28b80..b512676080640 100644 --- a/packages/core/test/bundling/todo/bundle.golden_symbols.json +++ b/packages/core/test/bundling/todo/bundle.golden_symbols.json @@ -362,6 +362,9 @@ { "name": "addToViewTree" }, + { + "name": "allocLFrame" + }, { "name": "allocStylingMapArray" }, @@ -461,6 +464,9 @@ { "name": "createLContext" }, + { + "name": "createLFrame" + }, { "name": "createLView" }, @@ -527,6 +533,12 @@ { "name": "elementPropertyInternal" }, + { + "name": "enterDI" + }, + { + "name": "enterView" + }, { "name": "executeCheckHooks" }, @@ -977,6 +989,15 @@ { "name": "iterateListLike" }, + { + "name": "leaveDI" + }, + { + "name": "leaveView" + }, + { + "name": "leaveViewProcessExit" + }, { "name": "listenerInternal" }, @@ -1022,9 +1043,6 @@ { "name": "matchTemplateAttribute" }, - { - "name": "namespaceHTMLInternal" - }, { "name": "nativeAppendChild" }, @@ -1139,9 +1157,6 @@ { "name": "renderView" }, - { - "name": "resetComponentState" - }, { "name": "resetCurrentStyleSanitizer" }, @@ -1175,9 +1190,6 @@ { "name": "selectIndexInternal" }, - { - "name": "selectView" - }, { "name": "setActiveElementFlag" }, @@ -1247,9 +1259,6 @@ { "name": "setStyle" }, - { - "name": "setTNodeAndViewData" - }, { "name": "setUpAttributes" }, diff --git a/packages/core/test/render3/di_spec.ts b/packages/core/test/render3/di_spec.ts index 244e4c31f7aef..ed372f4d84c28 100644 --- a/packages/core/test/render3/di_spec.ts +++ b/packages/core/test/render3/di_spec.ts @@ -17,7 +17,7 @@ import {TNODE} from '../../src/render3/interfaces/injector'; import {TNodeType} from '../../src/render3/interfaces/node'; import {isProceduralRenderer} from '../../src/render3/interfaces/renderer'; import {LViewFlags, TVIEW} from '../../src/render3/interfaces/view'; -import {selectView} from '../../src/render3/state'; +import {enterView, leaveViewProcessExit} from '../../src/render3/state'; import {getRendererFactory2} from './imported_renderer2'; import {ComponentFixture, createComponent, createDirective} from './render_util'; @@ -225,7 +225,7 @@ describe('di', () => { const contentView = createLView( null, createTView(-1, null, 1, 0, null, null, null, null, null), null, LViewFlags.CheckAlways, null, null, {} as any, {} as any); - const oldView = selectView(contentView, null); + enterView(contentView, null); try { const parentTNode = getOrCreateTNode(contentView[TVIEW], null, 0, TNodeType.Element, null, null); @@ -237,7 +237,7 @@ describe('di', () => { const injector = getOrCreateNodeInjectorForNode(parentTNode, contentView); expect(injector).not.toEqual(-1); } finally { - selectView(oldView, null); + leaveViewProcessExit(); } }); }); diff --git a/packages/core/test/render3/perf/directive_instantiate/index.ts b/packages/core/test/render3/perf/directive_instantiate/index.ts index ab60d58241961..572e5c4ddeecd 100644 --- a/packages/core/test/render3/perf/directive_instantiate/index.ts +++ b/packages/core/test/render3/perf/directive_instantiate/index.ts @@ -9,7 +9,6 @@ import {ɵɵdefineDirective, ɵɵelementEnd, ɵɵelementStart, ɵɵtext} from '. import {createTNode, createTView} from '../../../../src/render3/instructions/shared'; import {RenderFlags} from '../../../../src/render3/interfaces/definition'; import {TNodeType, TViewNode} from '../../../../src/render3/interfaces/node'; -import {resetComponentState} from '../../../../src/render3/state'; import {createBenchmark} from '../micro_bench'; import {createAndRenderLView} from '../setup'; @@ -78,9 +77,6 @@ const embeddedTView = createTView( -1, testTemplate, 21, 10, [Tooltip.ɵdir], null, null, null, [['position', 'top', 3, 'tooltip']]); -// initialize global state -resetComponentState(); - // create view once so we don't profile first template pass createAndRenderLView(null, embeddedTView, viewTNode); diff --git a/packages/core/test/render3/perf/element_text_create/index.ts b/packages/core/test/render3/perf/element_text_create/index.ts index 43c2e870a5be5..6555d2a332269 100644 --- a/packages/core/test/render3/perf/element_text_create/index.ts +++ b/packages/core/test/render3/perf/element_text_create/index.ts @@ -10,7 +10,6 @@ import {createTNode, createTView} from '../../../../src/render3/instructions/sha import {ɵɵtext} from '../../../../src/render3/instructions/text'; import {RenderFlags} from '../../../../src/render3/interfaces/definition'; import {TNodeType, TViewNode} from '../../../../src/render3/interfaces/node'; -import {resetComponentState} from '../../../../src/render3/state'; import {createBenchmark} from '../micro_bench'; import {createAndRenderLView} from '../setup'; @@ -69,9 +68,6 @@ const embeddedTView = createTView(-1, testTemplate, 21, 0, null, null, null, nul ['name1', 'value1', 'name2', 'value2', 'name3', 'value3', 'name4', 'value4', 'name5', 'value5'] ]); -// initialize global state -resetComponentState(); - // create view once so we don't profile first template pass createAndRenderLView(null, embeddedTView, viewTNode); diff --git a/packages/core/test/render3/perf/listeners/index.ts b/packages/core/test/render3/perf/listeners/index.ts index 4ea8304c30beb..0edbb091873b7 100644 --- a/packages/core/test/render3/perf/listeners/index.ts +++ b/packages/core/test/render3/perf/listeners/index.ts @@ -10,7 +10,6 @@ import {ɵɵlistener} from '../../../../src/render3/instructions/listener'; import {createTNode, createTView} from '../../../../src/render3/instructions/shared'; import {RenderFlags} from '../../../../src/render3/interfaces/definition'; import {TNodeType, TViewNode} from '../../../../src/render3/interfaces/node'; -import {resetComponentState} from '../../../../src/render3/state'; import {createBenchmark} from '../micro_bench'; import {createAndRenderLView} from '../setup'; @@ -79,9 +78,6 @@ const viewTNode = createTNode(null !, null, TNodeType.View, -1, null, null) as T const embeddedTView = createTView(-1, testTemplate, 11, 0, null, null, null, null, [[3, 'click', 'input']]); -// initialize global state -resetComponentState(); - // create view once so we don't profile first template pass createAndRenderLView(null, embeddedTView, viewTNode); diff --git a/packages/core/test/render3/perf/noop_change_detection/index.ts b/packages/core/test/render3/perf/noop_change_detection/index.ts index 7f454d01c4ec5..b77b373e572a3 100644 --- a/packages/core/test/render3/perf/noop_change_detection/index.ts +++ b/packages/core/test/render3/perf/noop_change_detection/index.ts @@ -18,7 +18,7 @@ const noopChangeDetection = createBenchmark('noop change detection'); const refreshTime = noopChangeDetection('refresh'); // run change detection in the update mode -console.profile('noop_refresh'); +console.profile('noop_change_detection'); while (refreshTime()) { refreshView(rootLView, rootTView, null, null); } diff --git a/packages/core/test/render3/render_util.ts b/packages/core/test/render3/render_util.ts index 554a64ffb6a70..66dd809329c21 100644 --- a/packages/core/test/render3/render_util.ts +++ b/packages/core/test/render3/render_util.ts @@ -14,7 +14,7 @@ import {ViewContainerRef} from '@angular/core/src/linker/view_container_ref'; import {Renderer2} from '@angular/core/src/render/api'; import {createLView, createTView, getOrCreateTNode, getOrCreateTView, renderComponentOrTemplate} from '@angular/core/src/render3/instructions/shared'; import {TAttributes, TNodeType} from '@angular/core/src/render3/interfaces/node'; -import {getLView, resetComponentState, selectView} from '@angular/core/src/render3/state'; +import {enterView, getLView} from '@angular/core/src/render3/state'; import {stringifyElement} from '@angular/platform-browser/testing/src/browser_util'; import {SWITCH_CHANGE_DETECTOR_REF_FACTORY__POST_R3__ as R3_CHANGE_DETECTOR_REF_FACTORY} from '../../src/change_detection/change_detector_ref'; @@ -32,7 +32,7 @@ import {ComponentDef, ComponentTemplate, ComponentType, DirectiveDef, DirectiveT import {DirectiveDefList, DirectiveDefListOrFactory, DirectiveTypesOrFactory, HostBindingsFunction, PipeDef, PipeDefList, PipeDefListOrFactory, PipeTypesOrFactory} from '../../src/render3/interfaces/definition'; import {PlayerHandler} from '../../src/render3/interfaces/player'; import {ProceduralRenderer3, RComment, RElement, RNode, RText, Renderer3, RendererFactory3, RendererStyleFlags3, domRendererFactory3} from '../../src/render3/interfaces/renderer'; -import {HEADER_OFFSET, LView, LViewFlags, TVIEW, T_HOST} from '../../src/render3/interfaces/view'; +import {HEADER_OFFSET, LView, LViewFlags, T_HOST} from '../../src/render3/interfaces/view'; import {destroyLView} from '../../src/render3/node_manipulation'; import {getRootView} from '../../src/render3/util/view_traversal_utils'; import {Sanitizer} from '../../src/sanitization/sanitizer'; @@ -251,7 +251,6 @@ export function renderTemplate( directives?: DirectiveDefListOrFactory | null, pipes?: PipeDefListOrFactory | null, sanitizer?: Sanitizer | null, consts?: TAttributes[]): LView { if (componentView === null) { - resetComponentState(); const renderer = providedRendererFactory.createRenderer(null, null); // We need to create a root view so it's possible to look up the host element through its index @@ -259,7 +258,7 @@ export function renderTemplate( const hostLView = createLView( null, tView, {}, LViewFlags.CheckAlways | LViewFlags.IsRoot, null, null, providedRendererFactory, renderer); - selectView(hostLView, null); // SUSPECT! why do we need to enter the View? + enterView(hostLView, null); const def: ComponentDef = ɵɵdefineComponent({ selectors: [], diff --git a/packages/core/test/sanitization/sanatization_spec.ts b/packages/core/test/sanitization/sanatization_spec.ts index 5d09d2119422f..2c7a8d2650c61 100644 --- a/packages/core/test/sanitization/sanatization_spec.ts +++ b/packages/core/test/sanitization/sanatization_spec.ts @@ -8,8 +8,8 @@ */ import {SECURITY_SCHEMA} from '@angular/compiler/src/schema/dom_security_schema'; -import {HEADER_OFFSET, LView} from '@angular/core/src/render3/interfaces/view'; -import {setTNodeAndViewData} from '@angular/core/src/render3/state'; +import {LView} from '@angular/core/src/render3/interfaces/view'; +import {enterView, leaveView} from '@angular/core/src/render3/state'; import {bypassSanitizationTrustHtml, bypassSanitizationTrustResourceUrl, bypassSanitizationTrustScript, bypassSanitizationTrustStyle, bypassSanitizationTrustUrl} from '../../src/sanitization/bypass'; import {getUrlSanitizer, ɵɵsanitizeHtml, ɵɵsanitizeResourceUrl, ɵɵsanitizeScript, ɵɵsanitizeStyle, ɵɵsanitizeUrl, ɵɵsanitizeUrlOrResourceUrl} from '../../src/sanitization/sanitization'; @@ -20,8 +20,8 @@ function fakeLView(): LView { } describe('sanitization', () => { - beforeEach(() => setTNodeAndViewData(null !, fakeLView())); - afterEach(() => setTNodeAndViewData(null !, null !)); + beforeEach(() => enterView(fakeLView(), null)); + afterEach(() => leaveView()); class Wrap { constructor(private value: string) {} toString() { return this.value; }