perf(ivy): replace select instruction with advance (#32516)

Replaces the `select` instruction with a new one called `advance`. Instead of the jumping to a specific index, the new instruction goes forward X amount of elements. The advantage of doing this is that it should generate code the compresses better.

PR Close #32516
This commit is contained in:
crisbeto
2019-09-06 23:43:16 +02:00
committed by Matias Niemelä
parent 2230dfaea7
commit 664e0015d4
34 changed files with 280 additions and 304 deletions

View File

@ -148,6 +148,7 @@ export {
ɵɵelementHostAttrs,
ɵɵselect,
ɵɵadvance,
ɵɵtemplate,
ɵɵembeddedViewEnd,
store as ɵstore,

View File

@ -98,9 +98,8 @@ class MyApp {
ɵɵelementEnd();
}
if (rf & RenderFlags.Update) {
ɵɵselect(0);
ɵɵproperty('title', ctx.name);
ɵɵselect(1);
ɵɵadvance(1);
ɵɵtextInterpolate1('Hello ', ctx.name, '!');
}
...

View File

@ -29,7 +29,6 @@ import {DirectiveDef} from '../interfaces/definition';
* ɵɵtext(0);
* }
* if (fs & RenderFlags.Update) {
* ɵɵselect(0);
* ɵɵtextInterpolate(ctx.greeter.greet());
* }
* },

View File

@ -97,7 +97,9 @@ export {
ɵɵreference,
// TODO: remove `select` once we're refactored all of the tests not to use it.
ɵɵselect,
ɵɵadvance,
ɵɵstyleMap,
ɵɵstyleProp,

View File

@ -8,36 +8,46 @@
import {assertDataInRange, assertGreaterThan} from '../../util/assert';
import {executeCheckHooks, executeInitAndCheckHooks} from '../hooks';
import {FLAGS, HEADER_OFFSET, InitPhaseState, LView, LViewFlags, TVIEW} from '../interfaces/view';
import {getCheckNoChangesMode, getLView, setSelectedIndex} from '../state';
import {getCheckNoChangesMode, getLView, getSelectedIndex, setSelectedIndex} from '../state';
/**
* Selects an element for later binding instructions.
* Advances to an element for later binding instructions.
*
* Used in conjunction with instructions like {@link property} to act on elements with specified
* indices, for example those created with {@link element} or {@link elementStart}.
*
* ```ts
* (rf: RenderFlags, ctx: any) => {
* if (rf & 1) {
* element(0, 'div');
* }
* if (rf & 2) {
* select(0); // Select the <div/> created above.
* property('title', 'test');
* }
* }
* ```
* @param index the index of the item to act on with the following instructions
*
* if (rf & 1) {
* text(0, 'Hello');
* text(1, 'Goodbye')
* element(2, 'div');
* }
* if (rf & 2) {
* advance(2); // Advance twice to the <div>.
* property('title', 'test');
* }
* }
* ```
* @param delta Number of elements to advance forwards by.
*
* @codeGenApi
*/
export function ɵɵadvance(delta: number): void {
ngDevMode && assertGreaterThan(delta, 0, 'Can only advance forward');
selectIndexInternal(getLView(), getSelectedIndex() + delta, getCheckNoChangesMode());
}
/**
* Selects an element for later binding instructions.
* @deprecated No longer being generated, but still used in unit tests.
* @codeGenApi
*/
export function ɵɵselect(index: number): void {
selectInternal(getLView(), index, getCheckNoChangesMode());
selectIndexInternal(getLView(), index, getCheckNoChangesMode());
}
export function selectInternal(lView: LView, index: number, checkNoChangesMode: boolean) {
export function selectIndexInternal(lView: LView, index: number, checkNoChangesMode: boolean) {
ngDevMode && assertGreaterThan(index, -1, 'Invalid index');
ngDevMode && assertDataInRange(lView, index + HEADER_OFFSET);
@ -62,6 +72,6 @@ export function selectInternal(lView: LView, index: number, checkNoChangesMode:
// We must set the selected index *after* running the hooks, because hooks may have side-effects
// that cause other template functions to run, thus updating the selected index, which is global
// state. If we run `setSelectedIndex` *before* we run the hooks, in some cases the selected index
// will be altered by the time we leave the `ɵɵselect` instruction.
// will be altered by the time we leave the `ɵɵadvance` instruction.
setSelectedIndex(index);
}

View File

@ -42,7 +42,7 @@ export * from './next_context';
export * from './projection';
export * from './property';
export * from './property_interpolation';
export * from './select';
export * from './advance';
export * from '../styling_next/instructions';
export * from './text';
export * from './text_interpolation';

View File

@ -37,8 +37,8 @@ import {INTERPOLATION_DELIMITER, renderStringify, stringifyForError} from '../ut
import {getLViewParent} from '../util/view_traversal_utils';
import {getComponentViewByIndex, getNativeByIndex, getNativeByTNode, getTNode, isCreationMode, readPatchedLView, resetPreOrderHookFlags, unwrapRNode, viewAttachedToChangeDetector} from '../util/view_utils';
import {selectIndexInternal} from './advance';
import {LCleanup, LViewBlueprint, MatchesArray, TCleanup, TNodeConstructor, TNodeInitialData, TNodeInitialInputs, TNodeLocalNames, TViewComponents, TViewConstructor, attachLContainerDebug, attachLViewDebug, cloneToLView, cloneToTViewData} from './lview_debug';
import {selectInternal} from './select';
@ -494,9 +494,9 @@ function executeTemplate<T>(
try {
setActiveHostElement(null);
if (rf & RenderFlags.Update && lView.length > HEADER_OFFSET) {
// When we're updating, have an inherent ɵɵselect(0) so we don't have to generate that
// instruction for most update blocks
selectInternal(lView, 0, getCheckNoChangesMode());
// When we're updating, inherently select 0 so we don't
// have to generate that instruction for most update blocks.
selectIndexInternal(lView, 0, getCheckNoChangesMode());
}
templateFn(rf, context);
} finally {

View File

@ -132,6 +132,7 @@ export const angularCoreEnv: {[name: string]: Function} =
'ɵɵstylingApply': r3.ɵɵstylingApply,
'ɵɵclassProp': r3.ɵɵclassProp,
'ɵɵselect': r3.ɵɵselect,
'ɵɵadvance': r3.ɵɵadvance,
'ɵɵtemplate': r3.ɵɵtemplate,
'ɵɵtext': r3.ɵɵtext,
'ɵɵtextInterpolate': r3.ɵɵtextInterpolate,