Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ref trace for inspector #1635

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion benchmark/benchmarks/krausest/vite.config.mts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const packagePath = (name: string) => {
export default defineConfig({
plugins: [benchmark()],
resolve: {
extensions: ['.mjs', '.js', '.mts', '.ts', '.jsx', '.tsx', '.json', '.d.ts'],
alias: {
'@glimmer-workspace/benchmark-env': '@glimmer-workspace/benchmark-env/index.ts',
'@glimmer/debug': packagePath('@glimmer/debug'),
Expand All @@ -42,7 +43,7 @@ function benchmark(): Plugin {
if (id === '\0@glimmer/env') {
return `export const DEBUG = false;`;
} else if (id === '\0@glimmer/local-debug-flags') {
return `export const LOCAL_SHOULD_LOG = false;`;
return `export const LOCAL_SHOULD_LOG = false;export const LOCAL_DEBUG=false`;
}
/** @type {string | undefined} */
let result: string | undefined;
Expand Down
1 change: 1 addition & 0 deletions packages/@glimmer/interfaces/lib/references.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export type ReferenceSymbol = typeof REFERENCE;
export interface Reference<T = unknown> {
[REFERENCE]: ReferenceType;
debugLabel?: string | undefined;
debugMeta?: object | undefined;
compute: Nullable<() => T>;
children: null | Map<string | Reference, Reference>;
}
2 changes: 2 additions & 0 deletions packages/@glimmer/reference/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,6 @@ export {
UNDEFINED_REFERENCE,
updateRef,
valueForRef,
setEnableRefTrace,
getRefsTrace
} from './lib/reference';
43 changes: 39 additions & 4 deletions packages/@glimmer/reference/lib/reference.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ class ReferenceImpl<T = unknown> implements Reference<T> {
public update: Nullable<(val: T) => void> = null;

public debugLabel?: string;
public debugMeta?: object;

constructor(type: ReferenceType) {
this[REFERENCE] = type;
Expand All @@ -75,27 +76,29 @@ export const NULL_REFERENCE = createPrimitiveRef(null);
export const TRUE_REFERENCE = createPrimitiveRef(true as const);
export const FALSE_REFERENCE = createPrimitiveRef(false as const);

export function createConstRef<T>(value: T, debugLabel: false | string): Reference<T> {
export function createConstRef<T>(value: T, debugLabel: false | string, meta?: object | undefined): Reference<T> {
const ref = new ReferenceImpl<T>(CONSTANT);

ref.lastValue = value;
ref.tag = CONSTANT_TAG;

if (import.meta.env.DEV) {
ref.debugLabel = debugLabel as string;
ref.debugLabel = String(debugLabel || value);
ref.debugMeta = meta;
}

return ref;
}

export function createUnboundRef<T>(value: T, debugLabel: false | string): Reference<T> {
export function createUnboundRef<T>(value: T, debugLabel: false | string, meta?: object | undefined): Reference<T> {
const ref = new ReferenceImpl<T>(UNBOUND);

ref.lastValue = value;
ref.tag = CONSTANT_TAG;

if (import.meta.env.DEV) {
ref.debugLabel = debugLabel as string;
ref.debugMeta = meta;
}

return ref;
Expand All @@ -104,7 +107,8 @@ export function createUnboundRef<T>(value: T, debugLabel: false | string): Refer
export function createComputeRef<T = unknown>(
compute: () => T,
update: Nullable<(value: T) => void> = null,
debugLabel: false | string = 'unknown'
debugLabel: false | string = 'unknown',
meta?: object | undefined
): Reference<T> {
const ref = new ReferenceImpl<T>(COMPUTE);

Expand All @@ -113,6 +117,7 @@ export function createComputeRef<T = unknown>(

if (import.meta.env.DEV) {
ref.debugLabel = `(result of a \`${debugLabel}\` helper)`;
ref.debugMeta = meta;
}

return ref;
Expand Down Expand Up @@ -151,9 +156,31 @@ export function isUpdatableRef(_ref: Reference) {
return ref.update !== null;
}

const trackedRefs = new WeakMap();
const refStack = [];
let isTraceEnabled = false;

export function setEnableRefTrace(enable: boolean) {
isTraceEnabled = enable;
}

function getCurrentRef() {
return refStack.at(-1);
}

export function getRefsTrace() {
return trackedRefs;
}

export function valueForRef<T>(_ref: Reference<T>): T {
const ref = _ref as ReferenceImpl<T>;

if (import.meta.env.DEV) {
if (refStack.length) {
trackedRefs.get(getCurrentRef()).push(ref);
}
}

let { tag } = ref;

if (tag === CONSTANT_TAG) {
Expand All @@ -164,6 +191,10 @@ export function valueForRef<T>(_ref: Reference<T>): T {
let lastValue;

if (tag === null || !validateTag(tag, lastRevision)) {
if (import.meta.env.DEV) {
refStack.push(ref);
trackedRefs.set(ref, []);
}
const { compute } = ref;

const newTag = track(
Expand All @@ -176,6 +207,10 @@ export function valueForRef<T>(_ref: Reference<T>): T {
tag = ref.tag = newTag;

ref.lastRevision = valueForTag(newTag);

if (import.meta.env.DEV) {
refStack.pop();
}
} else {
lastValue = ref.lastValue;
}
Expand Down
42 changes: 19 additions & 23 deletions packages/@glimmer/reference/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,21 @@
"directory": "packages/@glimmer/reference"
},
"type": "module",
"main": "index.ts",
"types": "index.ts",
"publishConfig": {
"access": "public",
"types": "dist/dev/index.d.ts",
"exports": {
".": {
"types": "./dist/dev/index.d.ts",
"development": {
"require": "./dist/dev/index.cjs",
"import": "./dist/dev/index.js"
},
"access": "public",
"types": "dist/dev/index.d.ts",
"exports": {
".": {
"types": "./dist/dev/index.d.ts",
"development": {
"require": "./dist/dev/index.cjs",
"import": "./dist/prod/index.js"
}
},
"main": null,
"module": "dist/dev/index.js"
"import": "./dist/dev/index.js"
},
"require": "./dist/dev/index.cjs",
"import": "./dist/prod/index.js"
}
},
"main": null,
"module": "dist/dev/index.js",
"files": [
"dist"
],
Expand All @@ -39,14 +35,14 @@
},
"dependencies": {
"@glimmer/env": "^0.1.7",
"@glimmer/global-context": "workspace:*",
"@glimmer/interfaces": "workspace:*",
"@glimmer/util": "workspace:*",
"@glimmer/validator": "workspace:*"
"@glimmer/global-context": "*",
"@glimmer/interfaces": "*",
"@glimmer/util": "*",
"@glimmer/validator": "*"
},
"devDependencies": {
"@glimmer-workspace/build-support": "workspace:*",
"@glimmer/local-debug-flags": "workspace:*",
"@glimmer-workspace/build-support": "*",
"@glimmer/local-debug-flags": "*",
"eslint": "^8.52.0",
"publint": "^0.2.5",
"rollup": "^4.5.1",
Expand Down
16 changes: 13 additions & 3 deletions packages/@glimmer/runtime/lib/compiled/opcodes/expressions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import type {
ScopeBlock,
VM as PublicVM,
} from '@glimmer/interfaces';
import type { Reference } from '@glimmer/reference';
import { createDebugAliasRef, type Reference } from "@glimmer/reference";
import {
check,
CheckBlockSymbolTable,
Expand All @@ -28,7 +28,7 @@ import {
valueForRef,
} from '@glimmer/reference';
import { assert, assign, debugToString, decodeHandle, isObject } from '@glimmer/util';
import { $v0, CurriedTypes, Op } from '@glimmer/vm';
import { $s0, $v0, CurriedTypes, Op } from "@glimmer/vm";

import { isCurriedType, resolveCurriedValue } from '../../curried-value';
import { APPEND_OPCODES } from '../../opcodes';
Expand Down Expand Up @@ -67,7 +67,10 @@ APPEND_OPCODES.add(Op.Curry, (vm, { op1: type, op2: _isStrict }) => {

vm.loadValue(
$v0,
createCurryRef(type as CurriedType, definition, owner, capturedArgs, resolver, isStrict)
addHelper(createCurryRef(type as CurriedType, definition, owner, capturedArgs, resolver, isStrict), {
type,
definition
})
);
});

Expand Down Expand Up @@ -170,6 +173,13 @@ APPEND_OPCODES.add(Op.GetVariable, (vm, { op1: symbol }) => {

APPEND_OPCODES.add(Op.SetVariable, (vm, { op1: symbol }) => {
let expr = check(vm.stack.pop(), CheckReference);
if (import.meta.env.DEV && symbol > 0) {
let state = vm.fetchValue($s0);
let symbols = state.table?.symbols;
if (symbols && symbols.length >= symbol) {
expr = createDebugAliasRef(`${symbols[symbol - 1]} from let`, expr);
}
}
vm.scope().bindSymbol(symbol, expr);
});

Expand Down
2 changes: 1 addition & 1 deletion packages/@glimmer/runtime/lib/compiled/opcodes/vm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ APPEND_OPCODES.add(Op.Constant, (vm, { op1: other }) => {
});

APPEND_OPCODES.add(Op.ConstantReference, (vm, { op1: other }) => {
vm.stack.push(createConstRef(vm[CONSTANTS].getValue(decodeHandle(other)), false));
vm.stack.push(createConstRef(vm[CONSTANTS].getValue(decodeHandle(other))));
});

APPEND_OPCODES.add(Op.Primitive, (vm, { op1: primitive }) => {
Expand Down
2 changes: 1 addition & 1 deletion packages/@glimmer/runtime/lib/debug-render-tree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import type {
} from '@glimmer/interfaces';
import { assign, expect, Stack } from '@glimmer/util';

import { reifyArgsDebug } from './vm/arguments';
import { getArgTags, reifyArgsDebug } from "./vm/arguments";

interface InternalRenderNode<T extends object> extends RenderNode {
bounds: Nullable<Bounds>;
Expand Down
43 changes: 42 additions & 1 deletion packages/@glimmer/runtime/lib/vm/arguments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import type {
import type { Reference } from '@glimmer/reference';
import type { Tag } from '@glimmer/validator';
import { check, CheckBlockSymbolTable, CheckHandle, CheckOption, CheckOr } from '@glimmer/debug';
import { createDebugAliasRef, UNDEFINED_REFERENCE, valueForRef } from '@glimmer/reference';
import { createDebugAliasRef, UNDEFINED_REFERENCE, valueForRef, setEnableRefTrace, getRefsTrace } from '@glimmer/reference';
import { dict, EMPTY_STRING_ARRAY, emptyArray, enumerate, unwrap } from '@glimmer/util';
import { CONSTANT_TAG } from '@glimmer/validator';
import { $sp } from '@glimmer/vm';
Expand Down Expand Up @@ -503,6 +503,7 @@ export function reifyArgs(args: CapturedArguments) {
}

const ARGUMENT_ERROR = Symbol('ARGUMENT_ERROR');
const ARGUMENT_TAG = Symbol('ARGUMENT_TAG');

export function isArgumentError(arg: unknown): arg is ArgumentError {
return (
Expand All @@ -519,6 +520,42 @@ function ArgumentErrorImpl(error: any) {
};
}

export function getArgTags(args: CapturedArguments) {
let named = dict();
for (const [key, value] of Object.entries(args.named)) {
named[key] = value.tag;
}
let positional = args.positional.map(p => p.tag);
return {
named,
positional,
};
}

function buildRefTree(tracedRefs: Map<Reference, Reference[]>, ref: Reference) {
return {
ref: {
label: ref.debugLabel,
value: ref.lastValue,
meta: ref.debugMeta
},
children: tracedRefs.get(ref)?.map(r => buildRefTree(tracedRefs, r)) || []
}
}

export function getArgRefsTree(args: CapturedArguments) {
const tracedRefs = getRefsTrace();
let named = dict();
for (const [key, value] of Object.entries(args.named)) {
named[key] = buildRefTree(tracedRefs, value);
}
let positional = args.positional.map(p => buildRefTree(tracedRefs, p));
return {
named,
positional,
};
}

export function reifyNamedDebug(named: CapturedNamedArguments) {
let reified = dict();
for (const [key, value] of Object.entries(named)) {
Expand All @@ -543,11 +580,15 @@ export function reifyPositionalDebug(positional: CapturedPositionalArguments) {
}

export function reifyArgsDebug(args: CapturedArguments) {
setEnableRefTrace(true);
let named = reifyNamedDebug(args.named);
let positional = reifyPositionalDebug(args.positional);
setEnableRefTrace(false);
return {
named,
positional,
tags: getArgTags(args),
refs: getArgRefsTree(args)
};
}

Expand Down
Loading
Loading