Intern no-ns keywords without per-call allocation
(keyword #f name) built a fresh combined-key string (string-append) on every call just to do the intern-table lookup — ~80 bytes of garbage per (:kw x), map literal, keyword arg, etc. A no-ns keyword now interns in a table keyed by the name string directly, so a lookup of an already-interned keyword is one hashtable-ref with no allocation. The ns table keeps the combined key; both share the keyword-t khash (equal-hash of the combined key) so hash values are unchanged. Small time win on its own (the field-read dispatch dominates hot record code — see jolt-unx4) but removes per-call keyword allocation everywhere. Runtime .ss, no re-mint; identity/=/hash unchanged, make test green.
This commit is contained in:
parent
63a8cb1cb2
commit
8ad4e1cf31
1 changed files with 16 additions and 5 deletions
|
|
@ -23,15 +23,26 @@
|
|||
;; --- keywords: interned so identity works; optional namespace ----------------
|
||||
(define-record-type keyword-t (fields ns name khash) (nongenerative keyword-v1))
|
||||
(define keyword-table (make-hashtable string-hash string=?))
|
||||
;; The common no-ns keyword is interned in a table keyed by NAME directly, so a
|
||||
;; lookup of an already-interned :kw (the hot case — every (:kw x), map literal,
|
||||
;; keyword arg) is one hashtable-ref with NO allocation. The ns table keeps the
|
||||
;; combined key. Both share the keyword-t khash (equal-hash of the combined key),
|
||||
;; so hash values are unchanged.
|
||||
(define keyword-table-bare (make-hashtable string-hash string=?))
|
||||
;; NUL separator can't occur in a keyword ns/name, so the intern key is
|
||||
;; unambiguous (a "/" separator would collide ns="a" name="b/c" with ns="a/b").
|
||||
(define (keyword-intern-key ns name) (string-append (or ns "") "\x0;" name))
|
||||
(define (keyword ns name)
|
||||
(let ((k (keyword-intern-key ns name)))
|
||||
(or (hashtable-ref keyword-table k #f)
|
||||
(let ((kw (make-keyword-t ns name (equal-hash k))))
|
||||
(hashtable-set! keyword-table k kw)
|
||||
kw))))
|
||||
(if ns
|
||||
(let ((k (keyword-intern-key ns name)))
|
||||
(or (hashtable-ref keyword-table k #f)
|
||||
(let ((kw (make-keyword-t ns name (equal-hash k))))
|
||||
(hashtable-set! keyword-table k kw)
|
||||
kw)))
|
||||
(or (hashtable-ref keyword-table-bare name #f)
|
||||
(let ((kw (make-keyword-t #f name (equal-hash (keyword-intern-key #f name)))))
|
||||
(hashtable-set! keyword-table-bare name kw)
|
||||
kw))))
|
||||
(define (keyword? x) (keyword-t? x))
|
||||
|
||||
;; --- symbols: ns + name + meta; NOT interned (meta varies), = by ns/name ------
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue