Skip to content

Commit 0889896

Browse files
committed
Starting to get in to diminishing returns here
1 parent 250c2f7 commit 0889896

9 files changed

Lines changed: 302 additions & 209 deletions

File tree

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,7 @@
321321
"@ember/enumerable/mutable.js": "ember-source/@ember/enumerable/mutable.js",
322322
"@ember/helper/index.js": "ember-source/@ember/helper/index.js",
323323
"@ember/instrumentation/index.js": "ember-source/@ember/instrumentation/index.js",
324+
"@ember/instrumentation/lib/internal-instrument.js": "ember-source/@ember/instrumentation/lib/internal-instrument.js",
324325
"@ember/modifier/index.js": "ember-source/@ember/modifier/index.js",
325326
"@ember/modifier/on.js": "ember-source/@ember/modifier/on.js",
326327
"@ember/object/-internals.js": "ember-source/@ember/object/-internals.js",

packages/@ember/-internals/glimmer/lib/resolver.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type { InternalFactory, InternalOwner } from '@ember/-internals/owner';
22
import { isFactory } from '@ember/-internals/owner';
33
import { assert } from '@ember/debug';
4-
import { _instrumentStart } from '@ember/instrumentation';
4+
import { _instrumentStart } from '@ember/instrumentation/lib/internal-instrument';
55
import { DEBUG } from '@glimmer/env';
66
import type {
77
ClassicResolver,

packages/@ember/instrumentation/index.ts

Lines changed: 13 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,21 @@
11
/* eslint no-console:off */
22
/* global console */
33

4-
import { ENV } from '@ember/-internals/environment/lib/env';
5-
import { assert } from '@ember/debug';
4+
import {
5+
_instrumentStart,
6+
NOOP,
7+
resetCache,
8+
subscribers,
9+
} from './lib/internal-instrument';
10+
import type { Listener, StructuredProfilePayload, Subscriber } from './lib/internal-instrument';
611

7-
export interface Listener<T> {
8-
before: (name: string, timestamp: number, payload: object) => T;
9-
after: (name: string, timestamp: number, payload: object, beforeValue: T) => void;
10-
}
11-
12-
export interface Subscriber<T> {
13-
pattern: string;
14-
regex: RegExp;
15-
object: Listener<T>;
16-
}
12+
export type { Listener, StructuredProfilePayload, Subscriber };
13+
export { _instrumentStart };
1714

1815
export interface PayloadWithException {
1916
exception?: any;
2017
}
2118

22-
export interface StructuredProfilePayload {
23-
object: string | object;
24-
}
25-
2619
/**
2720
@module @ember/instrumentation
2821
@private
@@ -78,23 +71,7 @@ export interface StructuredProfilePayload {
7871
@static
7972
@private
8073
*/
81-
export let subscribers: Subscriber<any>[] = [];
82-
let cache: { [key: string]: Listener<any>[] } = {};
83-
84-
function populateListeners(name: string) {
85-
let listeners: Listener<any>[] = [];
86-
87-
for (let subscriber of subscribers) {
88-
if (subscriber.regex.test(name)) {
89-
listeners.push(subscriber.object);
90-
}
91-
}
92-
93-
cache[name] = listeners;
94-
return listeners;
95-
}
96-
97-
const time = (): number => performance.now();
74+
export { subscribers };
9875

9976
type InstrumentCallback<Binding, Result> = (this: Binding) => Result;
10077

@@ -196,67 +173,6 @@ function withFinalizer<Binding, Result>(
196173
}
197174
}
198175

199-
function NOOP() {}
200-
201-
// private for now
202-
export function _instrumentStart(name: string, payloadFunc: () => object): () => void;
203-
export function _instrumentStart<Arg>(
204-
name: string,
205-
payloadFunc: (arg: Arg) => object,
206-
payloadArg: Arg
207-
): () => void;
208-
export function _instrumentStart<Arg>(
209-
name: string,
210-
payloadFunc: ((arg: Arg) => object) | (() => object),
211-
payloadArg?: Arg
212-
): () => void {
213-
if (subscribers.length === 0) {
214-
return NOOP;
215-
}
216-
217-
let listeners = cache[name];
218-
219-
if (!listeners) {
220-
listeners = populateListeners(name);
221-
}
222-
223-
if (listeners.length === 0) {
224-
return NOOP;
225-
}
226-
227-
let payload = payloadFunc(payloadArg!);
228-
229-
let STRUCTURED_PROFILE = ENV.STRUCTURED_PROFILE;
230-
let timeName: string;
231-
if (STRUCTURED_PROFILE) {
232-
timeName = `${name}: ${(payload as StructuredProfilePayload).object}`;
233-
console.time(timeName);
234-
}
235-
236-
let beforeValues: any[] = [];
237-
let timestamp = time();
238-
for (let listener of listeners) {
239-
beforeValues.push(listener.before(name, timestamp, payload));
240-
}
241-
242-
const constListeners = listeners;
243-
244-
return function _instrumentEnd(): void {
245-
let timestamp = time();
246-
for (let i = 0; i < constListeners.length; i++) {
247-
let listener = constListeners[i];
248-
assert('has listener', listener); // Iterating over values
249-
if (typeof listener.after === 'function') {
250-
listener.after(name, timestamp, payload, beforeValues[i]);
251-
}
252-
}
253-
254-
if (STRUCTURED_PROFILE) {
255-
console.timeEnd(timeName);
256-
}
257-
};
258-
}
259-
260176
/**
261177
Subscribes to a particular event or instrumented block of code.
262178
@@ -292,7 +208,7 @@ export function subscribe<T>(pattern: string, object: Listener<T>): Subscriber<T
292208
};
293209

294210
subscribers.push(subscriber);
295-
cache = {};
211+
resetCache();
296212

297213
return subscriber;
298214
}
@@ -317,7 +233,7 @@ export function unsubscribe(subscriber: Subscriber<any>): void {
317233
}
318234

319235
subscribers.splice(index, 1);
320-
cache = {};
236+
resetCache();
321237
}
322238

323239
/**
@@ -330,5 +246,5 @@ export function unsubscribe(subscriber: Subscriber<any>): void {
330246
*/
331247
export function reset(): void {
332248
subscribers.length = 0;
333-
cache = {};
249+
resetCache();
334250
}
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
// Hot-path bits of `@ember/instrumentation`, factored out so internal
2+
// callers (the resolver, component managers) don't have to drag in the
3+
// full subscribe/unsubscribe/instrument machinery — most of which is dead
4+
// code unless something actually subscribes (e.g. Ember Inspector).
5+
//
6+
// `subscribers` and `cache` live here; `index.ts` imports and mutates
7+
// them via `subscribe`/`unsubscribe`/`reset`.
8+
9+
import { ENV } from '@ember/-internals/environment/lib/env';
10+
import { assert } from '@ember/debug';
11+
12+
export interface Listener<T> {
13+
before: (name: string, timestamp: number, payload: object) => T;
14+
after: (name: string, timestamp: number, payload: object, beforeValue: T) => void;
15+
}
16+
17+
export interface Subscriber<T> {
18+
pattern: string;
19+
regex: RegExp;
20+
object: Listener<T>;
21+
}
22+
23+
export interface StructuredProfilePayload {
24+
object: string | object;
25+
}
26+
27+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
28+
export const subscribers: Subscriber<any>[] = [];
29+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
30+
export const cache: { [key: string]: Listener<any>[] } = {};
31+
32+
export function resetCache(): void {
33+
for (const key of Object.keys(cache)) {
34+
delete cache[key];
35+
}
36+
}
37+
38+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
39+
function populateListeners(name: string): Listener<any>[] {
40+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
41+
let listeners: Listener<any>[] = [];
42+
43+
for (let subscriber of subscribers) {
44+
if (subscriber.regex.test(name)) {
45+
listeners.push(subscriber.object);
46+
}
47+
}
48+
49+
cache[name] = listeners;
50+
return listeners;
51+
}
52+
53+
const time = (): number => performance.now();
54+
55+
export const NOOP = (): void => {};
56+
57+
export function _instrumentStart(name: string, payloadFunc: () => object): () => void;
58+
export function _instrumentStart<Arg>(
59+
name: string,
60+
payloadFunc: (arg: Arg) => object,
61+
payloadArg: Arg
62+
): () => void;
63+
export function _instrumentStart<Arg>(
64+
name: string,
65+
payloadFunc: ((arg: Arg) => object) | (() => object),
66+
payloadArg?: Arg
67+
): () => void {
68+
if (subscribers.length === 0) {
69+
return NOOP;
70+
}
71+
72+
let listeners = cache[name];
73+
74+
if (!listeners) {
75+
listeners = populateListeners(name);
76+
}
77+
78+
if (listeners.length === 0) {
79+
return NOOP;
80+
}
81+
82+
let payload = payloadFunc(payloadArg!);
83+
84+
let STRUCTURED_PROFILE = ENV.STRUCTURED_PROFILE;
85+
let timeName: string;
86+
if (STRUCTURED_PROFILE) {
87+
timeName = `${name}: ${(payload as StructuredProfilePayload).object}`;
88+
// eslint-disable-next-line no-console
89+
console.time(timeName);
90+
}
91+
92+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
93+
let beforeValues: any[] = [];
94+
let timestamp = time();
95+
for (let listener of listeners) {
96+
beforeValues.push(listener.before(name, timestamp, payload));
97+
}
98+
99+
const constListeners = listeners;
100+
101+
return function _instrumentEnd(): void {
102+
let timestamp = time();
103+
for (let i = 0; i < constListeners.length; i++) {
104+
let listener = constListeners[i];
105+
assert('has listener', listener);
106+
if (typeof listener.after === 'function') {
107+
listener.after(name, timestamp, payload, beforeValues[i]);
108+
}
109+
}
110+
111+
if (STRUCTURED_PROFILE) {
112+
// eslint-disable-next-line no-console
113+
console.timeEnd(timeName);
114+
}
115+
};
116+
}

packages/@glimmer/debug/lib/dism/operands.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ class Disassembler<in out Added extends OperandType> {
6868
}
6969
}
7070

71-
export const OPERANDS = Disassembler.build((d) => {
71+
export const OPERANDS = /*#__PURE__*/ Disassembler.build((d) => {
7272
return d
7373
.add(['imm/u32', 'imm/i32', 'imm/u32{todo}', 'imm/i32{todo}'], ({ value }) => ['number', value])
7474
.add(['const/i32[]'], ({ value, constants }) => [
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Side-effect-only module: registers `DebugRenderTreeImpl` as the factory
2+
// used by `EnvironmentImpl` when `delegate.enableDebugTooling` is true.
3+
//
4+
// Importing this file pulls `./debug-render-tree` into the bundle. Apps
5+
// that don't need render-tree introspection (anything not running the
6+
// Ember Inspector) shouldn't import this module — `EnvironmentImpl`'s
7+
// `debugRenderTree` will silently stay `undefined`, which is the same
8+
// behavior you'd get with `enableDebugTooling: false`.
9+
10+
import DebugRenderTreeImpl from './debug-render-tree';
11+
import { registerDebugRenderTreeFactory } from './environment';
12+
13+
registerDebugRenderTreeFactory(() => new DebugRenderTreeImpl());

packages/@glimmer/runtime/lib/environment.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { DEBUG } from '@glimmer/env';
22
import type {
33
ClassicResolver,
44
ComponentInstanceWithCreate,
5+
DebugRenderTree,
56
Environment,
67
EnvironmentOptions,
78
GlimmerTreeChanges,
@@ -19,10 +20,20 @@ import { ProgramImpl } from '@glimmer/program/lib/program';
1920
import { track } from '@glimmer/validator/lib/tracking';
2021
import { UPDATE_TAG as updateTag } from '@glimmer/validator/lib/validators';
2122

22-
import DebugRenderTree from './debug-render-tree';
2323
import { DOMChangesImpl, DOMTreeConstruction } from './dom/helper';
2424
import { isArgumentError } from './vm/arguments';
2525

26+
// Lazy registration: the DebugRenderTree implementation registers itself
27+
// here on import. Apps that don't need it (e.g. anything that isn't running
28+
// the Ember Inspector) won't pull `./debug-render-tree` into the bundle,
29+
// since this module no longer references it statically.
30+
type DebugRenderTreeFactory = () => DebugRenderTree<object>;
31+
let debugRenderTreeFactory: DebugRenderTreeFactory | null = null;
32+
33+
export function registerDebugRenderTreeFactory(factory: DebugRenderTreeFactory): void {
34+
debugRenderTreeFactory = factory;
35+
}
36+
2637
export const TRANSACTION: TransactionSymbol = Symbol('TRANSACTION') as TransactionSymbol;
2738

2839
class TransactionImpl implements Transaction {
@@ -114,7 +125,10 @@ export class EnvironmentImpl implements Environment {
114125
private delegate: EnvironmentDelegate
115126
) {
116127
this.isInteractive = delegate.isInteractive;
117-
this.debugRenderTree = this.delegate.enableDebugTooling ? new DebugRenderTree() : undefined;
128+
this.debugRenderTree =
129+
this.delegate.enableDebugTooling && debugRenderTreeFactory
130+
? debugRenderTreeFactory()
131+
: undefined;
118132
this.isArgumentCaptureError = this.delegate.enableDebugTooling ? isArgumentError : undefined;
119133
if (options.appendOperations) {
120134
this.appendOperations = options.appendOperations;

0 commit comments

Comments
 (0)