Skip to content

Cache a protocol member's parsed requirement; Fix #363 - #365

Merged
arnog merged 1 commit into
cortex-js:mainfrom
enumeratio:protocol-requirement-cache
Sep 30, 2026
Merged

arnog merged 1 commit into
cortex-js:mainfrom
enumeratio:protocol-requirement-cache

Conversation

@enumeratio

Copy link
Copy Markdown
Contributor

Fix #363

requirementShape and requirementAt re-parsed the member's signature on every dispatched call. A signature naming Self never enters parseType's shared cache, and its resolver-less first attempt throws before the resolver-aware parse runs. The parsed requirement is now kept per protocol record (a WeakMap), keyed by member and the receiver's Self spelling, and the entry is dropped when ce._cacheGeneration() moves, so a redeclared type re-parses. A read-only engine view without a generation parses as before.

Measured on 3,000 scalar-receiver calls: 421 ms → 41 ms, against 32 ms for an equivalent plain function.

@enumeratio
enumeratio force-pushed the protocol-requirement-cache branch from 87a9964 to 85558a2 Compare September 29, 2026 04:34
… receiver type, keyed on the engine's any version and bounded per protocol, so a dispatched call no longer re-parses its Self-bearing signature; add regression tests. Fix cortex-js#363
@enumeratio
enumeratio force-pushed the protocol-requirement-cache branch from 85558a2 to fef0b12 Compare September 29, 2026 21:19
@enumeratio

Copy link
Copy Markdown
Contributor Author

Pushed a review pass:

  • The cache is keyed on the engine's any version rather than _cacheGeneration(). The low bit of _cacheGeneration() flips while assumptions are hidden, which would empty the entry on every toggle, and what a requirement parses to doesn't depend on assumptions.
  • It's bounded per protocol (REQUIREMENT_CACHE_LIMIT). A generic conformance meets a new Self for every list length it's called with, so an unbounded entry grows with the calls rather than the declarations.
  • Added regression tests (item-363-protocol-requirement-cache.test.ts):
    • repeated calls over interleaved receiver types answer what a fresh parse answers, rejections included;
    • a conformance added after a call serves the next call;
    • 300 distinct receiver types keep answering past the bound.

Member calls on the benchmark from #363 stay about 11× faster than on main. The PR also merges cleanly with #366 (CHANGELOG aside), and the combined result is just as fast.

@arnog
arnog merged commit c1c3729 into cortex-js:main Sep 30, 2026
2 of 5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

A protocol member call re-parses its signature on every call (~10× a plain function)

2 participants