Skip to content

Commit d19fe68

Browse files
committed
perf(lint): end File's pointer block on a slice, not a bare pointer
Round-2 code review's efficiency angle re-ran fieldalignment after this PR's File reorder settled and found a residual, smaller finding beyond the original 688->640 size fix: "struct with 488 pointer bytes could be 472". RunCache *RunCache sat last among the pointer-bearing fields; a bare pointer's entire width is its GC pointer word, so ending the block there left no free non-pointer tail. Reordering so linkRefs []Reference is the last pointer-bearing field instead lets its 16-byte len/cap tail fall outside ptrdata for free, since a slice only GC-scans its 8-byte data-pointer word. Ref: docs/development/high-performance-go.md#struct-layout
1 parent e3560a2 commit d19fe68

1 file changed

Lines changed: 17 additions & 9 deletions

File tree

internal/lint/file.go

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -149,15 +149,6 @@ type File struct {
149149
// rather than via NewFile; LinkReferences then parses once on
150150
// demand. Released once linkRefs is materialized.
151151
parseCtx parser.Context
152-
linkRefs []Reference
153-
154-
// scratch backs Memo: per-Check rule memoization. A *File is
155-
// built fresh for each Check and discarded after, so values
156-
// cached here never outlive a single Check — no cross-file or
157-
// cross-run staleness, the same scope as the cross-file rule's
158-
// per-Check cache. sync.Map keeps it safe for the concurrent
159-
// readers the LSP may run against one document.
160-
scratch sync.Map
161152

162153
// RunCache is the engine-owned read cache shared by every File
163154
// processed in one engine.Run pass. Catalog and include rules
@@ -175,6 +166,23 @@ type File struct {
175166
// they belong with File anyway. See plan/224.
176167
RunCache *RunCache
177168

169+
// scratch backs Memo: per-Check rule memoization. A *File is
170+
// built fresh for each Check and discarded after, so values
171+
// cached here never outlive a single Check — no cross-file or
172+
// cross-run staleness, the same scope as the cross-file rule's
173+
// per-Check cache. sync.Map keeps it safe for the concurrent
174+
// readers the LSP may run against one document.
175+
scratch sync.Map
176+
177+
// linkRefs is declared last among the pointer-bearing fields on
178+
// purpose: as a slice, only its 8-byte data-pointer word is
179+
// GC-scanned when nothing after it holds a pointer, so its
180+
// trailing len/cap words (16 bytes) fall outside ptrdata for
181+
// free — unlike ending on a bare pointer field (e.g. RunCache),
182+
// whose single word carries no such free tail. See parseCtx's
183+
// comment above for what linkRefs caches.
184+
linkRefs []Reference
185+
178186
// --- lazy-init guards -------------------------------------------
179187
// Every *Done atomic.Bool / *Mu sync.Mutex pair below guards the
180188
// same-named cache field above; see that field's comment for what

0 commit comments

Comments
 (0)