julia
3fa6b8e1 - gf: cache single-dispatch and simple signatures in the call cache

Commit
24 days ago
gf: cache single-dispatch and simple signatures in the call cache Dynamic calls to builtins and intrinsics (from the interpreter and from inference's concrete evaluation) went through a full non-leaf typemap lookup on every call, since their methods have Vararg{Any} signatures that are never eligible for the leaf-only call cache. The same held for widened @nospecialize cache entries such as Tuple{typeof(objectid), Any} or Expr's constructor, which were 82% of the remaining slow-path lookups during bootstrap and 94% in the dict test suite. Generalize the call cache in two ways to cover these. First, add one extra cache slot hashed on the callee value itself, checked before the callsite-hashed slots: most callees dispatch to a single cache entry regardless of callsite ("single dispatch"), so this probe usually hits first, from any callsite - including ones that thrash the callsite-hashed slots, such as the interpreter's few C callsites. Entries whose signature is exactly Tuple{typeof(f), Vararg{Any}} (builtins and intrinsic calls) match every call of f and are accepted with an inline shape test. Second, allow cached entries to be non-leaf simple signatures, re-matched with sig_match_simple via a new jl_typemap_entry_sig_match helper that mirrors the per-entry logic of jl_typemap_entry_assoc_exact. An inline pre-rejection test keeps the cost of probing a foreign entry to a single comparison. Guarded entries are never cached, since a guard rejection must fall through to the rest of the typemap. Cacheable entries are inserted both by callee and by callsite so both probe patterns can find them. Dynamic dispatch of the affected calls becomes 1.3-3.3x cheaper (=== 45ns -> 14ns, add_int 56ns -> 21ns, getfield 63ns -> 23ns, Expr(:call, :f) 159ns -> 57ns, Core.Typeof 31ns -> 21ns), and ordinary leaf dispatch of a monomorphic callee gets slightly faster since it now hits the first probe (+ 14.8ns -> 14.3ns). The one small loser is a callee dispatched with alternating argument types from a single callsite, which pays one extra probe (18.4ns -> 20.5ns). Interpreter- and concrete-eval-heavy work benefits the most: a from-scratch sysimage bootstrap (including stdlib precompilation) goes from 11m26s to 8m47s (-23%) on this machine, and compiling the compiler (#62198) and package precompilation see similar wins. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Author
Committer
Parents
Loading