Skip to content

Commit 3575b36

Browse files
NullVoxPopuli-ai-agentclaude
andcommitted
perf(validator): fast path tag [COMPUTE] for subtag-less tags
`MonomorphicTagImpl[COMPUTE]` is called by `validateTag`/`valueForTag` on every reference read. For a tag with no subtag — property tags, cell tags, plain dirtyable/updatable tags, i.e. the overwhelming majority — the result is always just `revision` (kept current by `dirtyTag`). The `lastChecked`/`isUpdating`/cycle-guard/`try-finally` machinery exists only to memoize subtag recursion, so it is pure overhead for these tags. Return `this.revision` directly when `subtag === null`. The combinator path is unchanged (it now reuses the already-read `subtag`). Microbench (1000 subtag-less [COMPUTE]s during a revalidation pass): ~4.71µs -> ~3.90µs (~17%), and no try/finally or field writes on the read. Full browser suite green: 9340 tests, 9323 pass, 17 skip, 0 fail. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 8a4840a commit 3575b36

1 file changed

Lines changed: 27 additions & 17 deletions

File tree

packages/@glimmer/validator/lib/validators.ts

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,18 @@ class MonomorphicTagImpl<T extends MonomorphicTagId = MonomorphicTagId> {
122122
}
123123

124124
[COMPUTE](): Revision {
125+
// Fast path for subtag-less tags (property tags, cell tags, plain
126+
// dirtyable/updatable tags — the overwhelming majority). With no subtags to
127+
// fold in, the value is always just `revision`, which `dirtyTag` keeps
128+
// current, so none of the `lastChecked`/`isUpdating`/cycle machinery below
129+
// (which exists purely to memoize subtag recursion) is needed. This runs on
130+
// every `validateTag`/`valueForTag`, i.e. every reference read.
131+
let { subtag } = this;
132+
133+
if (subtag === null) {
134+
return this.revision;
135+
}
136+
125137
let { lastChecked } = this;
126138

127139
if (this.isUpdating) {
@@ -135,24 +147,22 @@ class MonomorphicTagImpl<T extends MonomorphicTagId = MonomorphicTagId> {
135147
this.lastChecked = $REVISION;
136148

137149
try {
138-
let { subtag, revision } = this;
139-
140-
if (subtag !== null) {
141-
if (Array.isArray(subtag)) {
142-
for (const tag of subtag) {
143-
let value = tag[COMPUTE]();
144-
revision = Math.max(value, revision);
145-
}
150+
let { revision } = this;
151+
152+
if (Array.isArray(subtag)) {
153+
for (const tag of subtag) {
154+
let value = tag[COMPUTE]();
155+
revision = Math.max(value, revision);
156+
}
157+
} else {
158+
let subtagValue = subtag[COMPUTE]();
159+
160+
if (subtagValue === this.subtagBufferCache) {
161+
revision = Math.max(revision, this.lastValue);
146162
} else {
147-
let subtagValue = subtag[COMPUTE]();
148-
149-
if (subtagValue === this.subtagBufferCache) {
150-
revision = Math.max(revision, this.lastValue);
151-
} else {
152-
// Clear the temporary buffer cache
153-
this.subtagBufferCache = null;
154-
revision = Math.max(revision, subtagValue);
155-
}
163+
// Clear the temporary buffer cache
164+
this.subtagBufferCache = null;
165+
revision = Math.max(revision, subtagValue);
156166
}
157167
}
158168

0 commit comments

Comments
 (0)