builtins: reuse the precomputed type hash as the object id of non-concrete datatypes (#62211)
jl_object_id recomputed a structural hash (recursing through hash_svec
over the
type parameters) on every call for a non-concrete datatype, while
concrete
datatypes already returned their precomputed dt->hash directly. dt->hash
is
alpha-invariant and egal-consistent, so it is a valid object id for any
datatype:
return it for non-concrete datatypes too, and fall back to the
structural
computation only when no hash was precomputed (dt->hash == 0).
This makes hashing a non-concrete argument-tuple type cheap, which
matters for
method dispatch on a type-valued argument: the arg tuple (e.g.
Tuple{typeof(f), Type{Int}}) is itself a non-concrete DataType that
previously
got re-hashed structurally on every dynamic call. Such dispatch is
common during
inference, so this is a measurable win for interpreter- and
inference-heavy work
such as compiling the compiler (#62198): a dynamic dispatch on a
type-valued
argument drops from ~60ns to ~45ns.
Note this changes the object-id value of non-concrete datatypes; it
stays
egal-consistent (dt->hash is alpha-invariant and identical for egal
types), and
the system image is regenerated with the new runtime so cached ids
agree.
This change was written with the assistance of generative AI (Claude).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>