Skip to content

Commit 7ea5161

Browse files
karajasonaden
authored andcommitted
refactor(ivy): merge directives into LViewData (angular#26316)
PR Close angular#26316
1 parent b087904 commit 7ea5161

33 files changed

+464
-328
lines changed

packages/compiler-cli/test/compliance/r3_compiler_compliance_spec.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -588,7 +588,7 @@ describe('compiler compliance', () => {
588588
selectors: [["", "hostBindingDir", ""]],
589589
factory: function HostBindingDir_Factory(t) { return new (t || HostBindingDir)(); },
590590
hostBindings: function HostBindingDir_HostBindings(dirIndex, elIndex) {
591-
$r3$.ɵelementProperty(elIndex, "id", $r3$.ɵbind($r3$.ɵloadDirective(dirIndex).dirId));
591+
$r3$.ɵelementProperty(elIndex, "id", $r3$.ɵbind($r3$.ɵload(dirIndex).dirId));
592592
},
593593
hostVars: 1,
594594
features: [$r3$.ɵPublicFeature]
@@ -632,7 +632,7 @@ describe('compiler compliance', () => {
632632
selectors: [["host-binding-comp"]],
633633
factory: function HostBindingComp_Factory(t) { return new (t || HostBindingComp)(); },
634634
hostBindings: function HostBindingComp_HostBindings(dirIndex, elIndex) {
635-
$r3$.ɵelementProperty(elIndex, "id", $r3$.ɵbind($r3$.ɵpureFunction1(1, $ff$, $r3$.ɵloadDirective(dirIndex).id)));
635+
$r3$.ɵelementProperty(elIndex, "id", $r3$.ɵbind($r3$.ɵpureFunction1(1, $ff$, $r3$.ɵload(dirIndex).id)));
636636
},
637637
hostVars: 3,
638638
features: [$r3$.ɵPublicFeature],
@@ -1343,7 +1343,7 @@ describe('compiler compliance', () => {
13431343
$r3$.ɵregisterContentQuery($r3$.ɵquery(null, SomeDirective, false));
13441344
},
13451345
contentQueriesRefresh: function ContentQueryComponent_ContentQueriesRefresh(dirIndex, queryStartIndex) {
1346-
const instance = $r3$.ɵloadDirective(dirIndex);
1346+
const instance = $r3$.ɵload(dirIndex);
13471347
var $tmp$;
13481348
($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵloadQueryList(queryStartIndex))) && ($instance$.someDir = $tmp$.first));
13491349
($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵloadQueryList((queryStartIndex + 1)))) && ($instance$.someDirList = $tmp$));
@@ -1403,7 +1403,7 @@ describe('compiler compliance', () => {
14031403
$r3$.ɵregisterContentQuery($r3$.ɵquery(null, ["myRef1", "myRef2", "myRef3"], false));
14041404
},
14051405
contentQueriesRefresh: function ContentQueryComponent_ContentQueriesRefresh(dirIndex, queryStartIndex) {
1406-
const instance = $r3$.ɵloadDirective(dirIndex);
1406+
const instance = $r3$.ɵload(dirIndex);
14071407
var $tmp$;
14081408
($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵloadQueryList(queryStartIndex))) && (instance.myRef = $tmp$.first));
14091409
($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵloadQueryList((queryStartIndex + 1)))) && (instance.myRefs = $tmp$));
@@ -1452,7 +1452,7 @@ describe('compiler compliance', () => {
14521452
$r3$.ɵregisterContentQuery($r3$.ɵquery(null, ["myRef1", "myRef2", "myRef3"], false, ElementRef));
14531453
},
14541454
contentQueriesRefresh: function ContentQueryComponent_ContentQueriesRefresh(dirIndex, queryStartIndex) {
1455-
const instance = $r3$.ɵloadDirective(dirIndex);
1455+
const instance = $r3$.ɵload(dirIndex);
14561456
var $tmp$;
14571457
($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵloadQueryList(queryStartIndex))) && (instance.myRef = $tmp$.first));
14581458
($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵloadQueryList((queryStartIndex + 1)))) && (instance.myRefs = $tmp$));

packages/compiler-cli/test/ngtsc/ngtsc_spec.ts

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -463,17 +463,14 @@ describe('ngtsc behavioral tests', () => {
463463
env.driveMain();
464464
const jsContents = env.getContents('test.js');
465465
expect(jsContents)
466-
.toContain(
467-
`i0.ɵelementProperty(elIndex, "attr.hello", i0.ɵbind(i0.ɵloadDirective(dirIndex).foo));`);
466+
.toContain(`i0.ɵelementProperty(elIndex, "attr.hello", i0.ɵbind(i0.ɵload(dirIndex).foo));`);
468467
expect(jsContents)
469-
.toContain(
470-
`i0.ɵelementProperty(elIndex, "prop", i0.ɵbind(i0.ɵloadDirective(dirIndex).bar));`);
468+
.toContain(`i0.ɵelementProperty(elIndex, "prop", i0.ɵbind(i0.ɵload(dirIndex).bar));`);
471469
expect(jsContents)
472470
.toContain(
473-
'i0.ɵelementProperty(elIndex, "class.someclass", i0.ɵbind(i0.ɵloadDirective(dirIndex).someClass))');
474-
expect(jsContents).toContain('i0.ɵloadDirective(dirIndex).onClick($event)');
475-
expect(jsContents)
476-
.toContain('i0.ɵloadDirective(dirIndex).onChange(i0.ɵloadDirective(dirIndex).arg)');
471+
'i0.ɵelementProperty(elIndex, "class.someclass", i0.ɵbind(i0.ɵload(dirIndex).someClass))');
472+
expect(jsContents).toContain('i0.ɵload(dirIndex).onClick($event)');
473+
expect(jsContents).toContain('i0.ɵload(dirIndex).onChange(i0.ɵload(dirIndex).arg)');
477474
});
478475

479476
it('should correctly recognize local symbols', () => {

packages/compiler/src/render3/r3_identifiers.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,6 @@ export class Identifiers {
9696
static pipeBindV: o.ExternalReference = {name: 'ɵpipeBindV', moduleName: CORE};
9797

9898
static load: o.ExternalReference = {name: 'ɵload', moduleName: CORE};
99-
static loadDirective: o.ExternalReference = {name: 'ɵloadDirective', moduleName: CORE};
10099
static loadQueryList: o.ExternalReference = {name: 'ɵloadQueryList', moduleName: CORE};
101100

102101
static pipe: o.ExternalReference = {name: 'ɵpipe', moduleName: CORE};

packages/compiler/src/render3/view/compiler.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -473,10 +473,9 @@ function createContentQueriesRefreshFunction(meta: R3DirectiveMetadata): o.Expre
473473
// var $tmp$: any;
474474
const temporary = temporaryAllocator(statements, TEMPORARY_NAME);
475475

476-
// const $instance$ = $r3$.ɵloadDirective(dirIndex);
477-
statements.push(
478-
directiveInstanceVar.set(o.importExpr(R3.loadDirective).callFn([o.variable('dirIndex')]))
479-
.toDeclStmt(o.INFERRED_TYPE, [o.StmtModifier.Final]));
476+
// const $instance$ = $r3$.ɵload(dirIndex);
477+
statements.push(directiveInstanceVar.set(o.importExpr(R3.load).callFn([o.variable('dirIndex')]))
478+
.toDeclStmt(o.INFERRED_TYPE, [o.StmtModifier.Final]));
480479

481480
meta.queries.forEach((query: R3QueryMetadata, idx: number) => {
482481
const loadQLArg = o.variable('queryStartIndex');
@@ -580,7 +579,7 @@ function createHostBindingsFunction(
580579

581580
// Calculate the host property bindings
582581
const bindings = bindingParser.createBoundHostProperties(directiveSummary, hostBindingSourceSpan);
583-
const bindingContext = o.importExpr(R3.loadDirective).callFn([o.variable('dirIndex')]);
582+
const bindingContext = o.importExpr(R3.load).callFn([o.variable('dirIndex')]);
584583
if (bindings) {
585584
const valueConverter = new ValueConverter(
586585
constantPool,

packages/core/src/core_render3_private_export.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@ export {
4747
embeddedViewStart as ɵembeddedViewStart,
4848
query as ɵquery,
4949
registerContentQuery as ɵregisterContentQuery,
50-
loadDirective as ɵloadDirective,
5150
projection as ɵprojection,
5251
bind as ɵbind,
5352
interpolation1 as ɵinterpolation1,

packages/core/src/render3/VIEW_DATA.md

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -128,8 +128,6 @@ NOTE:
128128

129129
## `EXPANDO`
130130

131-
*TODO*: This section is to be implemented.
132-
133131
`EXPANDO` contains information on data which size is not known at compile time.
134132
Examples include:
135133
- `Component`/`Directives` since we don't know at compile time which directives will match.
@@ -203,7 +201,7 @@ The `EXPANDO` section needs additional information for information stored in `TV
203201

204202
| Index | `TView.expandoInstructions` | Meaning
205203
| ----: | ---------------------------: | -------
206-
| 0 | -10 | Negative numbers signifies pointers to elements. In this case 10 (`<child>`)
204+
| 0 | -10 | Negative numbers signify pointers to elements. In this case 10 (`<child>`)
207205
| 1 | 2 | Injector size. Number of values to skip to get to Host Bindings.
208206
| 2 | Child.ngComponentDef.hostBindings | The function to call. (Only when `hostVars` is not `0`)
209207
| 3 | Child.ngComponentDef.hostVars | Number of host bindings to process. (Only when `hostVars` is not `0`)
@@ -215,9 +213,9 @@ The reason for this layout is to make the host binding update efficient using th
215213
let currentDirectiveIndex = -1;
216214
let currentElementIndex = -1;
217215
// This is global state which is used internally by hostBindings to know where the offset is
218-
let bindingRootIndex = tView.expandoStart;
219-
for(var i = 0; i < tview.expandoInstructions.length; i++) {
220-
let instruction = tview.expandoInstructions[i];
216+
let bindingRootIndex = tView.expandoStartIndex;
217+
for(var i = 0; i < tView.expandoInstructions.length; i++) {
218+
let instruction = tView.expandoInstructions[i];
221219
if (typeof instruction === 'number') {
222220
// Numbers are used to update the indices.
223221
if (instruction < 0) {

packages/core/src/render3/component.ts

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,10 @@ import {assertComponentType, assertDefined} from './assert';
1616
import {getLElementFromComponent, readPatchedLViewData} from './context_discovery';
1717
import {getComponentDef} from './definition';
1818
import {queueInitHooks, queueLifecycleHooks} from './hooks';
19-
import {PlayerHandler} from './interfaces/player';
20-
21-
import {CLEAN_PROMISE, baseDirectiveCreate, createLViewData, createTView, detectChangesInternal, enterView, executeInitAndContentHooks, hostElement, leaveView, locateHostElement, setHostBindings, queueHostBindingForCheck,} from './instructions';
19+
import {CLEAN_PROMISE, baseDirectiveCreate, createLViewData, createTView, detectChangesInternal, enterView, executeInitAndContentHooks, hostElement, leaveView, locateHostElement, prefillHostVars, setHostBindings} from './instructions';
2220
import {ComponentDef, ComponentType} from './interfaces/definition';
23-
import {LElementNode} from './interfaces/node';
21+
import {LElementNode, TNodeFlags} from './interfaces/node';
22+
import {PlayerHandler} from './interfaces/player';
2423
import {RElement, RendererFactory3, domRendererFactory3} from './interfaces/renderer';
2524
import {CONTEXT, INJECTOR, LViewData, LViewFlags, RootContext, RootContextFlags, TVIEW} from './interfaces/view';
2625
import {getRootView, stringify} from './util';
@@ -151,15 +150,16 @@ export function renderComponent<T>(
151150
export function createRootComponent<T>(
152151
elementNode: LElementNode, componentDef: ComponentDef<T>, rootView: LViewData,
153152
rootContext: RootContext, hostFeatures: HostFeature[] | null): any {
154-
// Create directive instance with factory() and store at index 0 in directives array
155-
const component = baseDirectiveCreate(0, componentDef.factory() as T, componentDef, elementNode);
153+
// Create directive instance with factory() and store at next index in viewData
154+
const component =
155+
baseDirectiveCreate(rootView.length, componentDef.factory() as T, componentDef, elementNode);
156156

157-
if (componentDef.hostBindings) queueHostBindingForCheck(0, componentDef.hostVars);
158157
rootContext.components.push(component);
159158
(elementNode.data as LViewData)[CONTEXT] = component;
160159

161160
hostFeatures && hostFeatures.forEach((feature) => feature(component, componentDef));
162-
setHostBindings(rootView[TVIEW].hostBindings);
161+
if (rootView[TVIEW].firstTemplatePass) prefillHostVars(componentDef.hostVars);
162+
setHostBindings();
163163
return component;
164164
}
165165

@@ -190,11 +190,10 @@ export function createRootContext(
190190
*/
191191
export function LifecycleHooksFeature(component: any, def: ComponentDef<any>): void {
192192
const rootTView = readPatchedLViewData(component) ![TVIEW];
193+
const dirIndex = rootTView.data.length - 1;
193194

194-
// Root component is always created at dir index 0
195-
queueInitHooks(0, def.onInit, def.doCheck, rootTView);
196-
// Directive starting index 0, directive count 1 -> directive flags: 1
197-
queueLifecycleHooks(1, rootTView);
195+
queueInitHooks(dirIndex, def.onInit, def.doCheck, rootTView);
196+
queueLifecycleHooks(dirIndex << TNodeFlags.DirectiveStartingIndexShift | 1, rootTView);
198197
}
199198

200199
/**

packages/core/src/render3/component_ref.ts

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -139,13 +139,6 @@ export class ComponentFactory<T> extends viewEngine_ComponentFactory<T> {
139139

140140
// Create element node at index 0 in data array
141141
elementNode = hostElement(componentTag, hostNode, this.componentDef);
142-
143-
// TODO: should LifecycleHooksFeature and other host features be generated by the compiler and
144-
// executed here?
145-
// Angular 5 reference: https://stackblitz.com/edit/lifecycle-hooks-vcref
146-
component = createRootComponent(
147-
elementNode, this.componentDef, rootView, rootContext, [LifecycleHooksFeature]);
148-
149142
tElementNode = getTNode(0) as TElementNode;
150143

151144
// Transform the arrays of native nodes into a LNode structure that can be consumed by the
@@ -168,6 +161,12 @@ export class ComponentFactory<T> extends viewEngine_ComponentFactory<T> {
168161
}
169162
}
170163

164+
// TODO: should LifecycleHooksFeature and other host features be generated by the compiler and
165+
// executed here?
166+
// Angular 5 reference: https://stackblitz.com/edit/lifecycle-hooks-vcref
167+
component = createRootComponent(
168+
elementNode, this.componentDef, rootView, rootContext, [LifecycleHooksFeature]);
169+
171170
// Execute the template in creation mode only, and then turn off the CreationMode flag
172171
const componentView = elementNode.data as LViewData;
173172
renderEmbeddedTemplate(componentView, componentView[TVIEW], component, RenderFlags.Create);

packages/core/src/render3/context_discovery.ts

Lines changed: 17 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import './ng_dev_mode';
1010
import {assertEqual} from './assert';
1111
import {LElementNode, TNode, TNodeFlags} from './interfaces/node';
1212
import {RElement} from './interfaces/renderer';
13-
import {CONTEXT, DIRECTIVES, HEADER_OFFSET, LViewData, TVIEW} from './interfaces/view';
13+
import {CONTEXT, HEADER_OFFSET, LViewData, TVIEW} from './interfaces/view';
1414

1515
/**
1616
* This property will be monkey-patched on elements, components and directives
@@ -306,21 +306,17 @@ function findViaDirective(lViewData: LViewData, directiveInstance: {}): number {
306306
// element bound to the directive being search lives somewhere
307307
// in the view data. We loop through the nodes and check their
308308
// list of directives for the instance.
309-
const directivesAcrossView = lViewData[DIRECTIVES];
310309
let tNode = lViewData[TVIEW].firstChild;
311-
if (directivesAcrossView != null) {
312-
while (tNode) {
313-
const directiveIndexStart = getDirectiveStartIndex(tNode);
314-
const directiveIndexEnd = getDirectiveEndIndex(tNode, directiveIndexStart);
315-
for (let i = directiveIndexStart; i < directiveIndexEnd; i++) {
316-
if (directivesAcrossView[i] === directiveInstance) {
317-
return tNode.index;
318-
}
310+
while (tNode) {
311+
const directiveIndexStart = getDirectiveStartIndex(tNode);
312+
const directiveIndexEnd = getDirectiveEndIndex(tNode, directiveIndexStart);
313+
for (let i = directiveIndexStart; i < directiveIndexEnd; i++) {
314+
if (lViewData[i] === directiveInstance) {
315+
return tNode.index;
319316
}
320-
tNode = traverseNextElement(tNode);
321317
}
318+
tNode = traverseNextElement(tNode);
322319
}
323-
324320
return -1;
325321
}
326322

@@ -341,24 +337,20 @@ function getLNodeFromViewData(lViewData: LViewData, lElementIndex: number): LEle
341337
}
342338

343339
/**
344-
* Returns a list of directives extracted from the given view. Does not contain
345-
* the component.
340+
* Returns a list of directives extracted from the given view based on the
341+
* provided list of directive index values.
346342
*
347-
* @param nodeIndex Index of node to search
343+
* @param nodeIndex The node index
348344
* @param lViewData The target view data
349345
* @param includeComponents Whether or not to include components in returned directives
350346
*/
351347
export function discoverDirectives(
352348
nodeIndex: number, lViewData: LViewData, includeComponents: boolean): any[]|null {
353-
const directivesAcrossView = lViewData[DIRECTIVES];
354-
if (directivesAcrossView != null) {
355-
const tNode = lViewData[TVIEW].data[nodeIndex] as TNode;
356-
let directiveStartIndex = getDirectiveStartIndex(tNode);
357-
const directiveEndIndex = getDirectiveEndIndex(tNode, directiveStartIndex);
358-
if (!includeComponents && tNode.flags & TNodeFlags.isComponent) directiveStartIndex++;
359-
return directivesAcrossView.slice(directiveStartIndex, directiveEndIndex);
360-
}
361-
return null;
349+
const tNode = lViewData[TVIEW].data[nodeIndex] as TNode;
350+
let directiveStartIndex = getDirectiveStartIndex(tNode);
351+
const directiveEndIndex = getDirectiveEndIndex(tNode, directiveStartIndex);
352+
if (!includeComponents && tNode.flags & TNodeFlags.isComponent) directiveStartIndex++;
353+
return lViewData.slice(directiveStartIndex, directiveEndIndex);
362354
}
363355

364356
/**
@@ -375,7 +367,7 @@ export function discoverLocalRefs(lViewData: LViewData, lNodeIndex: number): {[k
375367
const directiveIndex = tNode.localNames[i + 1] as number;
376368
result[localRefName] = directiveIndex === -1 ?
377369
getLNodeFromViewData(lViewData, lNodeIndex) !.native :
378-
lViewData[DIRECTIVES] ![directiveIndex];
370+
lViewData[directiveIndex];
379371
}
380372
return result;
381373
}

packages/core/src/render3/debug.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ class Render3DebugContext implements DebugContext {
7070
// TODO(vicb): add view providers when supported
7171
get providerTokens(): any[] {
7272
// TODO(vicb): why/when
73-
const directiveDefs = this.view[TVIEW].directives;
73+
const directiveDefs = this.view[TVIEW].data;
7474
if (this.nodeIndex === null || directiveDefs == null) {
7575
return [];
7676
}

0 commit comments

Comments
 (0)