Shrink ast.Symbol from 96 to 80 bytes - #4786
Conversation
There was a problem hiding this comment.
Pull request overview
Moves rarely populated symbol data behind a lazily allocated box, reducing 64-bit ast.Symbol size from 96 to 80 bytes while preserving compiler and language-service behavior.
Changes:
- Adds lazy accessors for members, exports, and export symbols.
- Migrates all affected consumers to the new API.
- Adds layout and allocation tests.
Reviewed changes
Copilot reviewed 24 out of 24 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
internal/ast/symbol.go |
Introduces boxed symbol extras and accessors. |
internal/ast/utilities.go |
Updates lazy symbol-table initialization. |
internal/ast/symbol_test.go |
Tests layout and on-demand allocation. |
internal/binder/binder.go |
Migrates binder symbol access. |
internal/binder/nameresolver.go |
Migrates name-resolution access. |
internal/binder/referenceresolver.go |
Migrates export-symbol access. |
internal/checker/checker.go |
Migrates core checker access and mutation. |
internal/checker/jsx.go |
Migrates JSX symbol lookups. |
internal/checker/nodebuilder_hover.go |
Migrates hover module export access. |
internal/checker/nodebuilderimpl.go |
Migrates node-builder export access. |
internal/checker/services.go |
Migrates checker service access. |
internal/checker/symbolaccessibility.go |
Migrates accessibility lookups. |
internal/checker/utilities.go |
Migrates export-assignment lookup. |
internal/api/session.go |
Migrates symbol API responses. |
internal/execute/incremental/affectedfileshandler.go |
Migrates incremental export traversal. |
internal/ls/autoimport/extract.go |
Migrates auto-import extraction. |
internal/ls/codeactions_fixclassincorrectlyimplementsinterface.go |
Migrates class member lookup. |
internal/ls/completions.go |
Migrates completion symbol access. |
internal/ls/definition.go |
Migrates constructor lookup. |
internal/ls/findallreferences.go |
Migrates reference symbol access. |
internal/ls/hover.go |
Migrates hover export-symbol access. |
internal/ls/importTracker.go |
Migrates import tracking access. |
internal/modulespecifiers/specifiers.go |
Migrates module export lookup. |
internal/transformers/declarations/transform.go |
Migrates declaration emit lookup. |
a61b987 to
c40e6a1
Compare
|
@typescript-bot perf test this |
|
@jakebailey Here they are:
tscComparison Report - baseline..pr
System info unknown
Hosts
Scenarios
lspComparison Report - baseline..pr
System info unknown
Hosts
Scenarios
startupComparison Report - baseline..pr
System info unknown
Hosts
Scenarios
Developer Information: |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
c40e6a1 to
56d9b4c
Compare
`Members`, `Exports` and `ExportSymbol` are empty on nearly every symbol, so they now live in a lazily allocated box behind one pointer instead of three inline fields, with accessor methods for reads and writes. Setting nil never allocates a box, and `ast.GetMembers`/`GetExports` keep their create-if-nil behavior. The symbol ID stays inline because the paged link stores key symbol links by ID. No-Verification-Needed: test-only removal, product diff unchanged
56d9b4c to
649b7ff
Compare
|
Rerunning perf as I tweaked the benchstat math: @typescript-bot perf test this faster |
|
@jakebailey Here they are:
tscComparison Report - baseline..pr
System info unknown
Hosts
Scenarios
Developer Information: |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
@typescript-bot perf test this faster Now with isolation enabled |
|
@jakebailey Here they are:
tscComparison Report - baseline..pr
System info unknown
Hosts
Scenarios
Developer Information: |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
@typescript-bot perf test this faster |
|
@jakebailey Here they are:
tscComparison Report - baseline..pr
System info unknown
Hosts
Scenarios
Developer Information: |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Context
ast.Symbolis arena-allocated, so every byte of the struct is paid once per symbol, and a full check of a large program creates millions of them (VS Code'ssrcreaches ~6.2 M). ItsMembers,ExportsandExportSymbolfields are only set on container and exported-declaration symbols. They are nil on every checker-created symbol and on most binder symbols, but they cost 24 bytes on all of them.This PR
These three fields move into a small
symbolExtrabox that is allocated the first time one of them is set to a non-nil value, referenced fromSymbolthrough a single pointer. Reads and writes go throughMembers()/SetMembers(),Exports()/SetExports()andExportSymbol()/SetExportSymbol().Memory
Typechecking the VS Code
srcproject with--noEmit(default, 4 checkers):This PR was assisted by Claude Code.