perf: use open-addressing caches in the kernel's expression traversals (#15930)

This PR replaces the `std::unordered_map`/`std::unordered_set` caches of
the kernel's expression traversals (`replace`, `Expr.replace`,
`Expr.instantiateLevelParams`, `expr_eq_fn`, `for_each_fn`,
`instantiateMVars`) with small open-addressing tables. The first 16
slots are stored inline, so traversals that cache only a few subterms
allocate no memory.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
6 files changed