Skip to content

Commit

Permalink
Merge pull request #19093 from emberjs/refactor/convert-to-autotracking
Browse files Browse the repository at this point in the history
[REFACTOR] Converts VM to use tracking internally
  • Loading branch information
rwjblue committed Aug 19, 2020
2 parents bfcd426 + ba16712 commit 93fb765
Show file tree
Hide file tree
Showing 37 changed files with 502 additions and 746 deletions.
16 changes: 8 additions & 8 deletions package.json
Expand Up @@ -74,15 +74,15 @@
},
"devDependencies": {
"@babel/preset-env": "^7.9.5",
"@glimmer/compiler": "^0.56.1",
"@glimmer/compiler": "^0.57.2",
"@glimmer/env": "^0.1.7",
"@glimmer/interfaces": "^0.56.1",
"@glimmer/node": "^0.56.1",
"@glimmer/opcode-compiler": "^0.56.1",
"@glimmer/program": "^0.56.1",
"@glimmer/reference": "^0.56.1",
"@glimmer/runtime": "^0.56.1",
"@glimmer/validator": "^0.56.1",
"@glimmer/interfaces": "^0.57.2",
"@glimmer/node": "^0.57.2",
"@glimmer/opcode-compiler": "^0.57.2",
"@glimmer/program": "^0.57.2",
"@glimmer/reference": "^0.57.2",
"@glimmer/runtime": "^0.57.2",
"@glimmer/validator": "^0.57.2",
"@simple-dom/document": "^1.4.0",
"@types/qunit": "^2.9.1",
"@types/rsvp": "^4.0.3",
Expand Down
Expand Up @@ -9,8 +9,7 @@ import {
PreparedArguments,
VMArguments,
} from '@glimmer/interfaces';
import { VersionedPathReference } from '@glimmer/reference';
import { Tag } from '@glimmer/validator';
import { PathReference } from '@glimmer/reference';
import { SimpleElement } from '@simple-dom/interface';
import { EmberVMEnvironment } from '../environment';

Expand All @@ -23,16 +22,18 @@ export default abstract class AbstractManager<T, U> implements ComponentManager<
return null;
}

abstract getDebugName(state: U): string;

abstract create(
env: EmberVMEnvironment,
definition: U,
args: VMArguments,
dynamicScope: DynamicScope,
caller: VersionedPathReference<void | {}>,
caller: PathReference<void | {}>,
hasDefaultBlock: boolean
): T;

abstract getSelf(component: T): VersionedPathReference<unknown>;
abstract getSelf(component: T): PathReference<unknown>;
abstract getCapabilities(state: U): ComponentCapabilities;

didCreateElement(_component: T, _element: SimpleElement, _operations: ElementOperations): void {
Expand All @@ -47,8 +48,6 @@ export default abstract class AbstractManager<T, U> implements ComponentManager<
// noop
}

abstract getTag(_bucket: T): Tag;

update(_bucket: T, _dynamicScope: DynamicScope): void {
// noop
}
Expand Down
65 changes: 46 additions & 19 deletions packages/@ember/-internals/glimmer/lib/component-managers/curly.ts
Expand Up @@ -21,10 +21,18 @@ import {
WithJitDynamicLayout,
WithJitStaticLayout,
} from '@glimmer/interfaces';
import { RootReference, VersionedPathReference } from '@glimmer/reference';
import { PathReference, RootReference } from '@glimmer/reference';
import { PrimitiveReference, registerDestructor } from '@glimmer/runtime';
import { EMPTY_ARRAY, unwrapTemplate } from '@glimmer/util';
import { combine, Tag, validateTag, valueForTag } from '@glimmer/validator';
import {
beginTrackFrame,
beginUntrackFrame,
consumeTag,
endTrackFrame,
endUntrackFrame,
validateTag,
valueForTag,
} from '@glimmer/validator';
import { SimpleElement } from '@simple-dom/interface';
import { BOUNDS, DIRTY_TAG, HAS_BLOCK, IS_DISPATCHING_ATTRS } from '../component';
import { EmberVMEnvironment } from '../environment';
Expand Down Expand Up @@ -62,8 +70,7 @@ function applyAttributeBindings(
attributeBindings: Array<string>,
component: Component,
rootRef: RootReference<Component>,
operations: ElementOperations,
environment: EmberVMEnvironment
operations: ElementOperations
) {
let seen: string[] = [];
let i = attributeBindings.length - 1;
Expand All @@ -75,7 +82,7 @@ function applyAttributeBindings(

if (seen.indexOf(attribute) === -1) {
seen.push(attribute);
AttributeBinding.install(component, rootRef, parsed, operations, environment);
AttributeBinding.install(component, rootRef, parsed, operations);
}

i--;
Expand All @@ -91,12 +98,12 @@ function applyAttributeBindings(
installIsVisibleBinding !== undefined &&
seen.indexOf('style') === -1
) {
installIsVisibleBinding(rootRef, operations, environment);
installIsVisibleBinding(rootRef, operations);
}
}

const DEFAULT_LAYOUT = P`template:components/-default`;
const EMPTY_POSITIONAL_ARGS: VersionedPathReference[] = [];
const EMPTY_POSITIONAL_ARGS: PathReference[] = [];

debugFreeze(EMPTY_POSITIONAL_ARGS);

Expand Down Expand Up @@ -167,7 +174,7 @@ export default class CurlyComponentManager
positional: EMPTY_POSITIONAL_ARGS,
named: {
...rest,
...(__ARGS__.value() as { [key: string]: VersionedPathReference<unknown> }),
...(__ARGS__.value() as { [key: string]: PathReference<unknown> }),
},
};

Expand Down Expand Up @@ -227,7 +234,7 @@ export default class CurlyComponentManager
state: DefinitionState,
args: VMArguments,
dynamicScope: DynamicScope,
callerSelfRef: VersionedPathReference,
callerSelfRef: PathReference,
hasBlock: boolean
): ComponentStateBucket {
// Get the nearest concrete component instance from the scope. "Virtual"
Expand All @@ -240,7 +247,10 @@ export default class CurlyComponentManager
// Capture the arguments, which tells Glimmer to give us our own, stable
// copy of the Arguments object that is safe to hold on to between renders.
let capturedArgs = args.named.capture();

beginTrackFrame();
let props = processComponentArgs(capturedArgs);
let argsTag = endTrackFrame();

// Alias `id` argument to `elementId` property on the component instance.
aliasIdToElementId(args, props);
Expand Down Expand Up @@ -271,6 +281,7 @@ export default class CurlyComponentManager

// Now that we've built up all of the properties to set on the component instance,
// actually create it.
beginUntrackFrame();
let component = factory.create(props);

let finalizer = _instrumentStart('render.component', initialRenderInstrumentDetails, component);
Expand Down Expand Up @@ -308,6 +319,7 @@ export default class CurlyComponentManager
environment,
component,
capturedArgs,
argsTag,
finalizer,
hasWrappedElement
);
Expand All @@ -324,6 +336,8 @@ export default class CurlyComponentManager
component.trigger('willRender');
}

endUntrackFrame();

if (ENV._DEBUG_RENDER_TREE) {
environment.extra.debugRenderTree.create(bucket, {
type: 'component',
Expand All @@ -338,10 +352,18 @@ export default class CurlyComponentManager
});
}

// consume every argument so we always run again
consumeTag(bucket.argsTag);
consumeTag(component[DIRTY_TAG]);

return bucket;
}

getSelf({ rootRef }: ComponentStateBucket): VersionedPathReference {
getDebugName({ name }: DefinitionState) {
return name;
}

getSelf({ rootRef }: ComponentStateBucket): PathReference {
return rootRef;
}

Expand All @@ -356,12 +378,12 @@ export default class CurlyComponentManager
let { attributeBindings, classNames, classNameBindings } = component;

if (attributeBindings && attributeBindings.length) {
applyAttributeBindings(attributeBindings, component, rootRef, operations, environment);
applyAttributeBindings(attributeBindings, component, rootRef, operations);
} else {
let id = component.elementId ? component.elementId : guidFor(component);
operations.setAttribute('id', PrimitiveReference.create(id), false, null);
if (EMBER_COMPONENT_IS_VISIBLE) {
installIsVisibleBinding!(rootRef, operations, environment);
installIsVisibleBinding!(rootRef, operations);
}
}

Expand Down Expand Up @@ -403,10 +425,6 @@ export default class CurlyComponentManager
}
}

getTag({ args, component }: ComponentStateBucket): Tag {
return args ? combine([args.tag, component[DIRTY_TAG]]) : component[DIRTY_TAG];
}

didCreate({ component, environment }: ComponentStateBucket): void {
if (environment.isInteractive) {
component._transitionTo('inDOM');
Expand All @@ -416,18 +434,22 @@ export default class CurlyComponentManager
}

update(bucket: ComponentStateBucket): void {
let { component, args, argsRevision, environment } = bucket;
let { component, args, argsTag, argsRevision, environment } = bucket;

if (ENV._DEBUG_RENDER_TREE) {
environment.extra.debugRenderTree.update(bucket);
}

bucket.finalizer = _instrumentStart('render.component', rerenderInstrumentDetails, component);

if (args && !validateTag(args.tag, argsRevision)) {
beginUntrackFrame();

if (args !== null && !validateTag(argsTag, argsRevision)) {
beginTrackFrame();
let props = processComponentArgs(args!);
argsTag = bucket.argsTag = endTrackFrame();

bucket.argsRevision = valueForTag(args!.tag);
bucket.argsRevision = valueForTag(argsTag);

component[IS_DISPATCHING_ATTRS] = true;
component.setProperties(props);
Expand All @@ -441,6 +463,11 @@ export default class CurlyComponentManager
component.trigger('willUpdate');
component.trigger('willRender');
}

endUntrackFrame();

consumeTag(argsTag);
consumeTag(component[DIRTY_TAG]);
}

didUpdateLayout(bucket: ComponentStateBucket, bounds: Bounds): void {
Expand Down
Expand Up @@ -19,7 +19,7 @@ import {
import { ComponentRootReference, PathReference } from '@glimmer/reference';
import { registerDestructor } from '@glimmer/runtime';
import { unwrapTemplate } from '@glimmer/util';
import { consumeTag, createTag, isConstTagged, Tag } from '@glimmer/validator';
import { track } from '@glimmer/validator';
import { EmberVMEnvironment } from '../environment';
import RuntimeResolver from '../resolver';
import { OwnedTemplate } from '../template';
Expand Down Expand Up @@ -194,17 +194,14 @@ export default class CustomComponentManager<ComponentInstance>

if (EMBER_CUSTOM_COMPONENT_ARG_PROXY) {
let getTag = (key: string) => {
return namedArgs.get(key).tag;
return track(() => namedArgs.get(key).value());
};

if (HAS_NATIVE_PROXY) {
let handler: ProxyHandler<{}> = {
get(_target, prop) {
if (namedArgs.has(prop as string)) {
let ref = namedArgs.get(prop as string);
consumeTag(ref.tag);

return ref.value();
return namedArgs.get(prop as string).value();
} else if (prop === CUSTOM_TAG_FOR) {
return getTag;
}
Expand Down Expand Up @@ -256,10 +253,7 @@ export default class CustomComponentManager<ComponentInstance>
enumerable: true,
configurable: true,
get() {
let ref = namedArgs.get(name);
consumeTag(ref.tag);

return ref.value();
return namedArgs.get(name).value();
},
});
});
Expand Down Expand Up @@ -294,6 +288,10 @@ export default class CustomComponentManager<ComponentInstance>
return bucket;
}

getDebugName({ name }: CustomComponentDefinitionState<ComponentInstance>) {
return name;
}

update(bucket: CustomComponentState<ComponentInstance>) {
if (ENV._DEBUG_RENDER_TREE) {
bucket.env.extra.debugRenderTree.update(bucket);
Expand Down Expand Up @@ -353,15 +351,6 @@ export default class CustomComponentManager<ComponentInstance>
});
}

getTag({ args }: CustomComponentState<ComponentInstance>): Tag {
if (isConstTagged(args)) {
// returning a const tag skips the update hook (VM BUG?)
return createTag();
} else {
return args.tag;
}
}

didRenderLayout(bucket: CustomComponentState<ComponentInstance>, bounds: Bounds) {
if (ENV._DEBUG_RENDER_TREE) {
bucket.env.extra.debugRenderTree.didRender(bucket, bounds);
Expand Down
27 changes: 10 additions & 17 deletions packages/@ember/-internals/glimmer/lib/component-managers/input.ts
Expand Up @@ -11,9 +11,8 @@ import {
PreparedArguments,
VMArguments,
} from '@glimmer/interfaces';
import { ComponentRootReference, ConstReference, VersionedPathReference } from '@glimmer/reference';
import { ComponentRootReference, ConstReference, PathReference } from '@glimmer/reference';
import { registerDestructor } from '@glimmer/runtime';
import { CONSTANT_TAG, createTag, isConstTagged } from '@glimmer/validator';
import { EmberVMEnvironment } from '../environment';
import InternalComponentManager, { InternalDefinitionState } from './internal';

Expand All @@ -34,11 +33,11 @@ const CAPABILITIES: ComponentCapabilities = {

export interface InputComponentState {
env: EmberVMEnvironment;
type: VersionedPathReference;
type: PathReference;
instance: Destroyable;
}

const EMPTY_POSITIONAL_ARGS: VersionedPathReference[] = [];
const EMPTY_POSITIONAL_ARGS: PathReference[] = [];

debugFreeze(EMPTY_POSITIONAL_ARGS);

Expand All @@ -53,7 +52,7 @@ export default class InputComponentManager extends InternalComponentManager<Inpu
args.positional.length === 0
);

let __ARGS__: Dict<VersionedPathReference> = args.named.capture().map;
let __ARGS__: Dict<PathReference> = args.named.capture().map;

return {
positional: EMPTY_POSITIONAL_ARGS,
Expand All @@ -69,9 +68,9 @@ export default class InputComponentManager extends InternalComponentManager<Inpu
{ ComponentClass, layout }: InternalDefinitionState,
args: VMArguments,
_dynamicScope: DynamicScope,
caller: VersionedPathReference
caller: PathReference
): InputComponentState {
assert('caller must be const', isConstTagged(caller));
assert('caller must be const', caller.isConst());

let type = args.named.get('type');

Expand All @@ -97,18 +96,12 @@ export default class InputComponentManager extends InternalComponentManager<Inpu
return state;
}

getSelf({ env, instance }: InputComponentState): VersionedPathReference {
return new ComponentRootReference(instance, env);
getDebugName() {
return 'input';
}

getTag() {
if (ENV._DEBUG_RENDER_TREE) {
// returning a const tag skips the update hook (VM BUG?)
return createTag();
} else {
// an outlet has no hooks
return CONSTANT_TAG;
}
getSelf({ env, instance }: InputComponentState): PathReference {
return new ComponentRootReference(instance, env);
}

didRenderLayout(state: InputComponentState, bounds: Bounds): void {
Expand Down

0 comments on commit 93fb765

Please sign in to comment.