Last active
May 28, 2026 23:19
-
-
Save KuSh/7af1829312429dd6e638a47de430a86a to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // Microbenchmark: Comment `loc` access patterns with reset cycles | |
| // Simulates oxlint lifecycle: pool init → for each file { reset → access loc ×10 → reset } | |
| import { performance } from "node:perf_hooks"; | |
| // ── helpers ────────────────────────────────────────────────────────────────── | |
| function computeLoc(start, end) { | |
| return { | |
| start: { line: start, column: 0 }, | |
| end: { line: end, column: 0 }, | |
| }; | |
| } | |
| const N = 5000; // pool size | |
| const N_FILES = 100; // file cycles simulated | |
| const INNER = 10; // inner repetitions per file | |
| // ── Variant C: prototype getter (original before PR) ───────────────────────── | |
| class CommentC { | |
| #loc = null; | |
| start = 0; | |
| end = 0; | |
| range = [0, 0]; | |
| type = "Line"; | |
| value = ""; | |
| get loc() { | |
| let loc = this.#loc; | |
| if (loc !== null) return loc; | |
| return (this.#loc = computeLoc(this.start, this.end)); | |
| } | |
| resetLoc() { | |
| this.#loc = null; | |
| } | |
| toJSON() { | |
| return { ...this, loc: this.loc }; | |
| } | |
| } | |
| Object.defineProperty(CommentC.prototype, "loc", { enumerable: true }); | |
| // ── Variant A: Proxy + WeakMap (current PR) ────────────────────────────────── | |
| const commentsLoc = new WeakMap(); | |
| class CommentA { | |
| start = 0; | |
| end = 0; | |
| range = [0, 0]; | |
| type = "Line"; | |
| value = ""; | |
| constructor() { | |
| return new Proxy(this, { | |
| ownKeys(obj) { | |
| return [...Reflect.ownKeys(obj), "loc"]; | |
| }, | |
| getOwnPropertyDescriptor(obj, prop) { | |
| if (prop === "loc") { | |
| return { | |
| configurable: true, | |
| enumerable: true, | |
| get: () => obj.loc, | |
| }; | |
| } | |
| return Reflect.getOwnPropertyDescriptor(obj, prop); | |
| }, | |
| }); | |
| } | |
| get loc() { | |
| let loc = commentsLoc.get(this); | |
| if (loc !== undefined) return loc; | |
| commentsLoc.set(this, (loc = computeLoc(this.start, this.end))); | |
| return loc; | |
| } | |
| resetLoc() { | |
| commentsLoc.delete(this); | |
| } | |
| } | |
| // ── Variant B: own descriptor (module-level variable) ──────────────────────── | |
| let LOC_DESC_B; | |
| class CommentB { | |
| #loc = null; | |
| start = 0; | |
| end = 0; | |
| range = [0, 0]; | |
| type = "Line"; | |
| value = ""; | |
| constructor() { | |
| Object.defineProperty(this, "loc", LOC_DESC_B); | |
| } | |
| resetLoc() { | |
| this.#loc = null; | |
| } | |
| static { | |
| LOC_DESC_B = { | |
| get() { | |
| const loc = this.#loc; | |
| if (loc !== null) return loc; | |
| return (this.#loc = computeLoc(this.start, this.end)); | |
| }, | |
| enumerable: true, | |
| configurable: true, | |
| }; | |
| } | |
| } | |
| // ── Variant E: own descriptor (static #desc) ───────────────────────────────── | |
| class CommentE { | |
| #loc = null; | |
| start = 0; | |
| end = 0; | |
| range = [0, 0]; | |
| type = "Line"; | |
| value = ""; | |
| static #LOC_DESC = { | |
| get() { | |
| const loc = this.#loc; | |
| if (loc !== null) return loc; | |
| return (this.#loc = computeLoc(this.start, this.end)); | |
| }, | |
| enumerable: true, | |
| configurable: true, | |
| }; | |
| constructor() { | |
| Object.defineProperty(this, "loc", CommentE.#LOC_DESC); | |
| } | |
| resetLoc() { | |
| this.#loc = null; | |
| } | |
| } | |
| // ── Variant SR: self-replace accessor ──────────────────────────────────────── | |
| class CommentSR { | |
| start = 0; | |
| end = 0; | |
| range = [0, 0]; | |
| type = "Line"; | |
| value = ""; | |
| static #LOC_DESC = { | |
| get() { | |
| const loc = computeLoc(this.start, this.end); | |
| Object.defineProperty(this, "loc", { | |
| value: loc, | |
| writable: true, | |
| enumerable: true, | |
| configurable: true, | |
| }); | |
| return loc; | |
| }, | |
| enumerable: true, | |
| configurable: true, | |
| }; | |
| constructor() { | |
| Object.defineProperty(this, "loc", CommentSR.#LOC_DESC); | |
| } | |
| resetLoc() { | |
| Object.defineProperty(this, "loc", CommentSR.#LOC_DESC); | |
| } | |
| } | |
| // ── Variant D: #innerLoc delegation ────────────────────────────────────────── | |
| class CommentD { | |
| #loc = null; | |
| start = 0; | |
| end = 0; | |
| range = [0, 0]; | |
| type = "Line"; | |
| value = ""; | |
| get #innerLoc() { | |
| const loc = this.#loc; | |
| if (loc !== null) return loc; | |
| return (this.#loc = computeLoc(this.start, this.end)); | |
| } | |
| static #LOC_DESC = { | |
| get() { | |
| return this.#innerLoc; | |
| }, | |
| enumerable: true, | |
| configurable: true, | |
| }; | |
| constructor() { | |
| Object.defineProperty(this, "loc", CommentD.#LOC_DESC); | |
| } | |
| resetLoc() { | |
| this.#loc = null; | |
| } | |
| } | |
| // ── pool builder ───────────────────────────────────────────────────────────── | |
| function makePool(Cls) { | |
| const pool = []; | |
| for (let i = 0; i < N; i++) { | |
| const c = new Cls(); | |
| c.start = i * 10; | |
| c.end = i * 10 + 5; | |
| c.range = [c.start, c.end]; | |
| c.type = (i & 1) ? "Block" : "Line"; | |
| c.value = `comment ${i}`; | |
| pool.push(c); | |
| } | |
| return pool; | |
| } | |
| // ── tests ──────────────────────────────────────────────────────────────────── | |
| function testDirectAccess(pool) { | |
| let count = 0; | |
| for (let iter = 0; iter < INNER; iter++) { | |
| for (let j = 0; j < pool.length; j++) { | |
| const comment = pool[j]; | |
| const loc = comment.loc; | |
| count += loc.start.line; | |
| count += loc.start.column; | |
| count += loc.end.line; | |
| count += loc.end.column; | |
| count += comment.value.length; | |
| count += comment.type.length; | |
| count += comment.range[0]; | |
| count += comment.range[1]; | |
| } | |
| } | |
| if (count === 0) throw new Error("DCE"); | |
| } | |
| function testSpreadAccess(pool) { | |
| let count = 0; | |
| for (let iter = 0; iter < INNER; iter++) { | |
| for (let j = 0; j < pool.length; j++) { | |
| const comment = pool[j]; | |
| const copy = { ...comment }; | |
| count += copy.value.length; | |
| } | |
| } | |
| if (count === 0) throw new Error("DCE"); | |
| } | |
| // ── benchmark runner (steady state, no reset) ───────────────────────────────── | |
| function benchNoReset(name, pool, accessFn) { | |
| // warmup | |
| for (let i = 0; i < 3; i++) accessFn(pool); | |
| // measure (same N_FILES iterations for consistency) | |
| const start = performance.now(); | |
| for (let f = 0; f < N_FILES; f++) accessFn(pool); | |
| const elapsed = performance.now() - start; | |
| console.log(` ${name.padEnd(10)} ${(elapsed / N_FILES).toFixed(3)} ms/file`); | |
| } | |
| // ── benchmark runner with reset cycles ─────────────────────────────────────── | |
| function benchWithReset(name, pool, accessFn) { | |
| // warmup: 3 file cycles | |
| for (let f = 0; f < 3; f++) { | |
| for (let j = 0; j < pool.length; j++) pool[j].resetLoc(); | |
| accessFn(pool); | |
| } | |
| // measure: N_FILES file cycles | |
| const start = performance.now(); | |
| for (let f = 0; f < N_FILES; f++) { | |
| for (let j = 0; j < pool.length; j++) pool[j].resetLoc(); | |
| accessFn(pool); | |
| } | |
| const elapsed = performance.now() - start; | |
| console.log(` ${name.padEnd(10)} ${(elapsed / N_FILES).toFixed(3)} ms/file`); | |
| } | |
| // ── main ───────────────────────────────────────────────────────────────────── | |
| const VARIANTS = [ | |
| ["C:proto", CommentC], | |
| ["A:proxy", CommentA], | |
| ["B:modvar", CommentB], | |
| ["E:static#", CommentE], | |
| ["SR:selfRp", CommentSR], | |
| ["D:delloc", CommentD], | |
| ]; | |
| console.log(`Pool: ${N}, files: ${N_FILES}, inner: ${INNER}`); | |
| console.log(""); | |
| console.log("── No reset: direct access (steady state) ──"); | |
| for (const [name, Cls] of VARIANTS) { | |
| const pool = makePool(Cls); | |
| benchNoReset(name, pool, testDirectAccess); | |
| } | |
| console.log(""); | |
| console.log("── No reset: spread + access value.length (steady state) ──"); | |
| for (const [name, Cls] of VARIANTS) { | |
| const pool = makePool(Cls); | |
| benchNoReset(name, pool, testSpreadAccess); | |
| } | |
| console.log(""); | |
| console.log("── With reset: direct access (loc + value ×10 per file) ──"); | |
| for (const [name, Cls] of VARIANTS) { | |
| const pool = makePool(Cls); | |
| benchWithReset(name, pool, testDirectAccess); | |
| } | |
| console.log(""); | |
| console.log("── With reset: spread + access value.length (×10 per file) ──"); | |
| for (const [name, Cls] of VARIANTS) { | |
| const pool = makePool(Cls); | |
| benchWithReset(name, pool, testSpreadAccess); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment