perf: store the fulfillment engine inline in ObligationCtxt - #47
Closed
xmakro wants to merge 1 commit into
Closed
Conversation
Every ObligationCtxt heap-allocated its fulfillment engine as a Box<dyn TraitEngine>, making it the single largest allocation site in the compiler (161k allocations on a syn check build, created per candidate probe in method resolution among others). The solver choice is a per-session constant and both engine types are small, so store them inline in a two-variant enum with static dispatch. The enum's TraitEngine impl needs both FromSolverError bounds, which ripples to the generic impl blocks and two generic users; the concrete error types used everywhere implement both. The boxed engine remains for the per-body typeck root fulfillment context.
xmakro
force-pushed
the
perf/obligation-ctxt-inline-engine
branch
from
July 31, 2026 09:27
bcdadb6 to
aa264ca
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Every
ObligationCtxtallocated its fulfillment engine on the heap as aBox<dyn TraitEngine>. This was the single largest allocation site in the compiler: 161k allocations on asyncheck build (measured with DHAT).ObligationCtxts are created in hot paths, for example once per candidate probe during method resolution.The allocation is easy to avoid. Which solver is used never changes during a compilation session, and both engine types are small (the obligation forest allocates its own storage separately). So this PR stores the engine directly inside
ObligationCtxt, in a two-variant enum. Calls now go through a match on that enum instead of virtual dispatch.The enum's
TraitEngineimpl needs bothFromSolverErrorbounds, so a few generic impl blocks and two generic users now need both bounds as well. The concrete error types used in practice already implement both, so nothing else changes for callers. The typeck root fulfillment context keeps the boxed engine; it is created once per function body, so the allocation does not matter there.