kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

commit cd997d0fecd8f80e5c141064ec4c1c4b5ff2f26a
parent e665229aefa465755b17d605f20610d6cf4bd52e
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Wed, 10 Jun 2026 22:56:09 -0700

perf(core): hoist table/entries bases out of the intern probe loop

pool_intern_slice runs once per identifier/keyword token (3-7% self-time on
every axis). The probe reloaded p->table and p->entries from the Pool struct on
each iteration (confirmed in disassembly). Both are stable across a probe (a
grow only happens after a miss), so hoist them into locals — one fewer dependent
load per probe step. Byte-identical (Sym identity unchanged); verified
test-parse + test-cg-api green.

Deliberately not done here: word-at-a-time intern hash (measured SLOWER for the
short identifiers real code uses), lower load factor (probe length already 1.3-
1.9), and the inline-prefix cache (negligible) — all refuted by measurement. The
image-id FNV->HW-SHA swap is a real symbol-count win but changes every
executable's LC_UUID/build-id bytes, so it is left as a deliberate, separately
gated change.

Diffstat:
Msrc/core/pool.c | 13++++++++++---
1 file changed, 10 insertions(+), 3 deletions(-)

diff --git a/src/core/pool.c b/src/core/pool.c @@ -111,9 +111,16 @@ Sym pool_intern_slice(Pool* p, Slice in) { h = fnv1a(s, len); mask = p->cap - 1; i = h & mask; - while ((sym = p->table[i]) != 0) { - if (sym_eq(&p->entries[sym], s, len, h)) return sym; - i = (i + 1) & mask; + /* Hoist the table/entries bases: they are stable across the probe (a grow + * only happens after a miss, below), so the compiler need not reload them + * from the Pool each iteration. This is the per-identifier intern probe. */ + { + const Sym* table = p->table; + const PoolEntry* ents = p->entries; + while ((sym = table[i]) != 0) { + if (sym_eq(&ents[sym], s, len, h)) return sym; + i = (i + 1) & mask; + } } /* Not found: allocate a new entry. The stored buffer carries a trailing * NUL so a returned slice's pointer can be handed to a NUL-terminated