Skip to content

Commit

Permalink
addresses comments, adds back contextual information/logs
Browse files Browse the repository at this point in the history
  • Loading branch information
Chris Garrett committed Nov 20, 2019
1 parent c1ee6d1 commit c1b614b
Show file tree
Hide file tree
Showing 26 changed files with 615 additions and 145 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,14 @@ import {
WithStaticLayout,
} from '@glimmer/runtime';
import { Destroyable, EMPTY_ARRAY } from '@glimmer/util';
import { BOUNDS, DIRTY_TAG, HAS_BLOCK, IS_DISPATCHING_ATTRS, ROOT_REF } from '../component';
import {
BOUNDS,
DIRTY_TAG,
GLIMMER_ENV,
HAS_BLOCK,
IS_DISPATCHING_ATTRS,
ROOT_REF,
} from '../component';
import Environment from '../environment';
import { DynamicScope } from '../renderer';
import RuntimeResolver from '../resolver';
Expand Down Expand Up @@ -286,6 +293,9 @@ export default class CurlyComponentManager
props.layout = state.template;
}

// Pass the environment for the root reference
props[GLIMMER_ENV] = environment;

// caller:
// <FaIcon @name="bug" />
//
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -323,8 +323,12 @@ export default class CustomComponentManager<ComponentInstance>
delegate.getContext(component);
}

getSelf({ delegate, component }: CustomComponentState<ComponentInstance>): PathReference<Opaque> {
return RootReference.create(delegate.getContext(component));
getSelf({
env,
delegate,
component,
}: CustomComponentState<ComponentInstance>): PathReference<Opaque> {
return RootReference.create(delegate.getContext(component), env);
}

getDestructor(state: CustomComponentState<ComponentInstance>): Option<Destroyable> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,8 @@ export default class InputComponentManager extends InternalComponentManager<Inpu
return state;
}

getSelf({ instance }: InputComponentState): VersionedPathReference {
return new RootReference(instance);
getSelf({ env, instance }: InputComponentState): VersionedPathReference {
return new RootReference(instance, env);
}

getTag() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,12 +106,12 @@ class MountManager extends AbstractManager<EngineState, EngineDefinitionState>

if (modelRef === undefined) {
controller = controllerFactory.create();
self = new RootReference(controller);
self = new RootReference(controller, environment);
bucket = { engine, controller, self, environment };
} else {
let model = modelRef.value();
controller = controllerFactory.create({ model });
self = new RootReference(controller);
self = new RootReference(controller, environment);
bucket = { engine, controller, self, modelRef, environment };
}

Expand Down
3 changes: 2 additions & 1 deletion packages/@ember/-internals/glimmer/lib/component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export const ROOT_REF = symbol('ROOT_REF');
export const IS_DISPATCHING_ATTRS = symbol('IS_DISPATCHING_ATTRS');
export const HAS_BLOCK = symbol('HAS_BLOCK');
export const BOUNDS = symbol('BOUNDS');
export const GLIMMER_ENV = symbol('GLIMMER_ENV');

/**
@module @ember/component
Expand Down Expand Up @@ -722,7 +723,7 @@ const Component = CoreView.extend(
this._super(...arguments);
this[IS_DISPATCHING_ATTRS] = false;
this[DIRTY_TAG] = createTag();
this[ROOT_REF] = new RootReference(this);
this[ROOT_REF] = new RootReference(this, this[GLIMMER_ENV]);
this[BOUNDS] = null;

if (DEBUG && this.renderer._destinedForDOM && this.tagName === '') {
Expand Down
19 changes: 18 additions & 1 deletion packages/@ember/-internals/glimmer/lib/modifiers/custom.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
import { track, untrack } from '@ember/-internals/metal';
import {
clearRenderingContextDesc,
setRenderingContextDesc,
track,
untrack,
} from '@ember/-internals/metal';
import { Factory } from '@ember/-internals/owner';
import { getDebugName } from '@ember/-internals/utils';
import { assert, deprecate } from '@ember/debug';
import { DEBUG } from '@glimmer/env';
import { Dict, Opaque, Simple } from '@glimmer/interfaces';
import { combine, CONSTANT_TAG, createUpdatableTag, Tag, update } from '@glimmer/reference';
import { Arguments, CapturedArguments, ModifierManager } from '@glimmer/runtime';
Expand Down Expand Up @@ -162,9 +169,19 @@ class InteractiveCustomModifierManager<ModifierInstance>
if (capabilities.disableAutoTracking === true) {
untrack(() => delegate.installModifier(modifier, element, args.value()));
} else {
if (DEBUG) {
let debugName = getDebugName!(modifier);
setRenderingContextDesc!(`(instance of a \`${debugName}\` modifier)`);
}

let combinedTrackingTag = track(() =>
delegate.installModifier(modifier, element, args.value())
);

if (DEBUG) {
clearRenderingContextDesc!();
}

update(tag, combinedTrackingTag);
}
}
Expand Down
29 changes: 6 additions & 23 deletions packages/@ember/-internals/glimmer/lib/renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,6 @@ class RootState {
public result: RenderResult | undefined;
public shouldReflush: boolean;
public destroyed: boolean;
public options: {
alwaysRevalidate: boolean;
};
public render: () => void;

constructor(
Expand All @@ -93,10 +90,6 @@ class RootState {
this.shouldReflush = false;
this.destroyed = false;

let options = (this.options = {
alwaysRevalidate: false,
});

this.render = () => {
let layout = template.asLayout();
let handle = layout.compile();
Expand All @@ -116,7 +109,7 @@ class RootState {
let result = (this.result = iteratorResult.value);

// override .render function after initial render
this.render = () => result.rerender(options);
this.render = () => result.rerender({ alwaysRevalidate: false });
};
}

Expand Down Expand Up @@ -397,20 +390,17 @@ export abstract class Renderer {

_renderRoots() {
let { _roots: roots, _env: env, _removedRoots: removedRoots } = this;
let globalShouldReflush = false;
let initialRootsLength: number;
let root: RootState, shouldReflush: boolean;

do {
env.begin();
try {
// ensure that for the first iteration of the loop
// each root is processed
initialRootsLength = roots.length;
globalShouldReflush = false;

for (let i = 0; i < roots.length; i++) {
root = roots[i];
let root = roots[i];

if (root.destroyed) {
// add to the list of roots to be removed
Expand All @@ -421,32 +411,25 @@ export abstract class Renderer {
continue;
}

shouldReflush = root.shouldReflush;

// when processing non-initial reflush loops,
// do not process more roots than needed
if (i >= initialRootsLength && !shouldReflush) {
if (i >= initialRootsLength) {
continue;
}

root.options.alwaysRevalidate = shouldReflush;
// track shouldReflush based on this roots render result
if (DEBUG) {
runInAutotrackingTransaction(() => root.render());
// run in an autotracking transaction to prevent backflow errors
runInAutotrackingTransaction!(root.render.bind(root));
} else {
root.render();
}

// globalShouldReflush should be `true` if *any* of
// the roots need to reflush
globalShouldReflush = globalShouldReflush || shouldReflush;
}

this._lastRevision = value(CURRENT_TAG);
} finally {
env.commit();
}
} while (globalShouldReflush || roots.length > initialRootsLength);
} while (roots.length > initialRootsLength);

// remove any roots that were destroyed during this transaction
while (removedRoots.length) {
Expand Down
33 changes: 27 additions & 6 deletions packages/@ember/-internals/glimmer/lib/syntax/outlet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
import { Dict, dict, Opaque } from '@glimmer/util';
import * as WireFormat from '@glimmer/wire-format';
import { OutletComponentDefinition, OutletDefinitionState } from '../component-managers/outlet';
import Environment from '../environment';
import { DynamicScope } from '../renderer';
import { isTemplateFactory } from '../template';
import { OutletReference, OutletState } from '../utils/outlet';
Expand Down Expand Up @@ -77,7 +78,10 @@ export function outletHelper(vm: VM, args: Arguments) {
} else {
nameRef = args.positional.at<VersionedPathReference<string>>(0);
}
return new OutletComponentReference(new OutletReference(scope.outletState, nameRef));
return new OutletComponentReference(
new OutletReference(scope.outletState, nameRef),
vm.env as Environment
);
}

export function outletMacro(
Expand All @@ -93,8 +97,12 @@ export function outletMacro(

class OutletModelReference implements VersionedPathReference {
public tag: Tag;
private debugStackLog?: string;

constructor(private parent: VersionedPathReference<OutletState | undefined>) {
constructor(
private parent: VersionedPathReference<OutletState | undefined>,
private env: Environment
) {
this.tag = parent.tag;
}

Expand All @@ -116,6 +124,16 @@ class OutletModelReference implements VersionedPathReference {

get(property: string): VersionedPathReference {
if (DEBUG) {
// We capture the log stack now, as accessing `{{@model}}` directly can't
// cause issues (doesn't autotrack) but accessing subproperties can. We
// don't want to capture the log stack when `value` or `debug` are called,
// because the ref might have been passed downward, so we'd have the
// incorrect context.
//
// TODO: This feels messy, side-effect of the fact that this ref is
// created well before the component itself.
this.debugStackLog = this.env.debugRenderTree.logCurrentRenderStack();

// This guarentees that we preserve the `debug()` output below
return new NestedPropertyReference(this, property);
} else {
Expand All @@ -125,8 +143,8 @@ class OutletModelReference implements VersionedPathReference {
}

if (DEBUG) {
OutletModelReference.prototype['debug'] = function debug(): string {
return '@model';
OutletModelReference.prototype['debug'] = function debug(subPath: string): string {
return `${this['debugStackLog']}@mount.${subPath}`;
};
}

Expand All @@ -137,12 +155,15 @@ class OutletComponentReference
private definition: Option<CurriedComponentDefinition> = null;
private lastState: Option<OutletDefinitionState> = null;

constructor(private outletRef: VersionedPathReference<OutletState | undefined>) {
constructor(
private outletRef: VersionedPathReference<OutletState | undefined>,
env: Environment
) {
// The router always dirties the root state.
let tag = (this.tag = outletRef.tag);

if (EMBER_ROUTING_MODEL_ARG) {
let modelRef = new OutletModelReference(outletRef);
let modelRef = new OutletModelReference(outletRef, env);
let map = dict<VersionedPathReference>();
map.model = modelRef;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,25 @@ export class Ref<T extends object> {
}
}

const _repeat =
String.prototype.repeat ||
function(this: string, count: number) {
return new Array(count + 1).join(this);
};

function repeatString(str: string, count: number) {
return _repeat.call(str, count);
}

class StackWithToArray<T> extends Stack<T> {
toArray(): T[] {
// polyfilling feature of modern Glimmer VM
return this['stack'];
}
}

export default class DebugRenderTree<Bucket extends object = object> {
private stack = new Stack<Bucket>();
private stack = new StackWithToArray<Bucket>();

private refs = new WeakMap<Bucket, Ref<Bucket>>();
private roots = new Set<Ref<Bucket>>();
Expand Down Expand Up @@ -116,6 +133,17 @@ export default class DebugRenderTree<Bucket extends object = object> {
return this.captureRefs(this.roots);
}

logCurrentRenderStack(): string {
let nodes = this.stack.toArray().map(bucket => this.nodeFor(bucket));
let message = nodes
.filter(node => node.type !== 'outlet')
.map((node, index) => `${repeatString(' ', index * 2)}${node.name}`);

message.push(`${repeatString(' ', message.length * 2)}`);

return message.join('\n');
}

private reset(): void {
if (this.stack.size !== 0) {
// We probably encountered an error during the rendering loop. This will
Expand Down
Loading

0 comments on commit c1b614b

Please sign in to comment.