Skip to content

Comments

Improve how QueryCache/QueryState/QueryEngine are stored#152835

Open
nnethercote wants to merge 4 commits intorust-lang:mainfrom
nnethercote:fix-query-state-query-cache
Open

Improve how QueryCache/QueryState/QueryEngine are stored#152835
nnethercote wants to merge 4 commits intorust-lang:mainfrom
nnethercote:fix-query-state-query-cache

Conversation

@nnethercote
Copy link
Contributor

@nnethercote nnethercote commented Feb 19, 2026

View all comments

QueryVTable has two fields query_state and query_cache that are byte offsets of fields in other structs. They are used in unsafe combination with byte_add and cast to access said fields. I don't like this at all and this PR replaces them with something sensible.

r? @Zalathar

@rustbot rustbot added A-query-system Area: The rustc query system (https://rustc-dev-guide.rust-lang.org/query.html) S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Feb 19, 2026
@rustbot
Copy link
Collaborator

rustbot commented Feb 19, 2026

Zalathar is not on the review rotation at the moment.
They may take a while to respond.

@Zalathar
Copy link
Member

@bors try @rust-timer queue

@rust-timer

This comment has been minimized.

@rust-bors

This comment has been minimized.

rust-bors bot pushed a commit that referenced this pull request Feb 19, 2026
Improve how `QueryCache`s and `QueryState`s are stored
@rustbot rustbot added the S-waiting-on-perf Status: Waiting on a perf run to be completed. label Feb 19, 2026
@Zalathar
Copy link
Member

Putting the state and cache directly in the vtable is not a possibility I had considered.

It stretches the concept of “vtable” a bit, and it gives up on being able to treat the vtable as mere metadata, but it does have advantages for actually looking up the state/cache given a vtable reference.

Genuinely unsure how to feel about this overall. It doesn’t jump out to me as something obviously-good or obviously-bad; the tradeoffs are more subtle.

@nnethercote
Copy link
Contributor Author

I agree about stretching the meaning of "vtable".

Beyond that I think it's a clear win. The offset code is ridiculous, it screams "something went wrong here".

More generally, it makes more sense to have a struct containing (A, B, C) x 400 than having (A x 400, B x 400, C x 400) when A and B and C are closely related and used together.

@Zalathar
Copy link
Member

This PR also touches on some areas that I haven’t been able to work on because they’re still waiting for #152747 to be merged, so having this PR also interfere with that is starting to feel overwhelming.

@rust-bors
Copy link
Contributor

rust-bors bot commented Feb 19, 2026

☀️ Try build successful (CI)
Build commit: 6efacd9 (6efacd91cd7cd06fc2c44d60f80077051f2fca7d, parent: e0cb264b814526acb82def4b5810e394a2ed294f)

@rust-timer

This comment has been minimized.

@rust-timer
Copy link
Collaborator

Finished benchmarking commit (6efacd9): comparison URL.

Overall result: ✅ improvements - no action needed

Benchmarking this pull request means it may be perf-sensitive – we'll automatically label it not fit for rolling up. You can override this, but we strongly advise not to, due to possible changes in compiler perf.

@bors rollup=never
@rustbot label: -S-waiting-on-perf -perf-regression

Instruction count

Our most reliable metric. Used to determine the overall result above. However, even this metric can be noisy.

mean range count
Regressions ❌
(primary)
- - 0
Regressions ❌
(secondary)
- - 0
Improvements ✅
(primary)
- - 0
Improvements ✅
(secondary)
-0.3% [-0.5%, -0.1%] 10
All ❌✅ (primary) - - 0

Max RSS (memory usage)

Results (secondary -3.2%)

A less reliable metric. May be of interest, but not used to determine the overall result above.

mean range count
Regressions ❌
(primary)
- - 0
Regressions ❌
(secondary)
- - 0
Improvements ✅
(primary)
- - 0
Improvements ✅
(secondary)
-3.2% [-3.2%, -3.2%] 1
All ❌✅ (primary) - - 0

Cycles

Results (primary 2.1%)

A less reliable metric. May be of interest, but not used to determine the overall result above.

mean range count
Regressions ❌
(primary)
2.1% [2.1%, 2.1%] 1
Regressions ❌
(secondary)
- - 0
Improvements ✅
(primary)
- - 0
Improvements ✅
(secondary)
- - 0
All ❌✅ (primary) 2.1% [2.1%, 2.1%] 1

Binary size

This benchmark run did not return any relevant results for this metric.

Bootstrap: 487.064s -> 482.434s (-0.95%)
Artifact size: 397.85 MiB -> 397.80 MiB (-0.01%)

@rustbot rustbot removed the S-waiting-on-perf Status: Waiting on a perf run to be completed. label Feb 19, 2026
@nnethercote
Copy link
Contributor Author

QueryEngine also merges into QueryVTable really nicely. I've added a new commit doing that.

I've been asking you for a lot of reviews; I'm happy to ask a different reviewer if you want a break.

@rust-bors

This comment has been minimized.

@Zalathar
Copy link
Member

I was skeptical of this PR at first, because it was unclear to me whether moving state/cache into the vtable was a good idea overall, and I wasn't convinced by the motivation of wanting to get rid of the unsafe offset fields (even though I don't like the offset fields).

However, after some more consideration, I'm coming around to the idea that putting per-query state/caches in the vtable is a fine idea in its own right. So now I'm pretty happy with the direction of this PR.

I have some remarks to write up, and I'll want to do another pass, but overall this PR looks good to me.

@Zoxc
Copy link
Contributor

Zoxc commented Feb 21, 2026

Pointers to fields can be done safely using say field-offset. I don't see much downside having the cache/state in QueryVTable besides preventing them from being 'static.

@nnethercote
Copy link
Contributor Author

Pointers to fields can be done safely using say field-offset

Even so, that's (a) a new third-party crate, and (b) it's very non-idiomatic and strongly suggests a suboptimal data layout.

@nnethercote nnethercote force-pushed the fix-query-state-query-cache branch from bc792c2 to d13ad56 Compare February 22, 2026 08:37
@rustbot

This comment has been minimized.

@nnethercote
Copy link
Contributor Author

nnethercote commented Feb 22, 2026

I have updated. Thanks for the great suggestions!

@rust-bors

This comment has been minimized.

@nnethercote nnethercote force-pushed the fix-query-state-query-cache branch from d13ad56 to 271ad55 Compare February 23, 2026 00:15
@rustbot

This comment has been minimized.

/// Used when reporting query cycle errors and similar problems.
pub description_fn: fn(TyCtxt<'tcx>, C::Key) -> String,

pub execute_query_fn: fn(TyCtxt<'tcx>, Span, C::Key, QueryMode) -> Option<C::Value>,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remark (pre-existing): This field could really use some docs and maybe a better name, because what it does and doesn't do is fairly subtle. But that's a pre-existing concern, so I don't want to block this PR on it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you want to suggest a comment I can drop it in.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don’t have something prepared, but I’ll add it to my TODO list to come back and look at this for a follow-up PR.

@Zalathar
Copy link
Member

Looking at this PR again, I realised that it's going to need some minor fixups after the dispatcher→vtable changes in #152791, which should combine for some nice little simplifications.

@rust-bors

This comment has been minimized.

@nnethercote nnethercote force-pushed the fix-query-state-query-cache branch from 271ad55 to f362d0e Compare February 24, 2026 00:34
@rustbot
Copy link
Collaborator

rustbot commented Feb 24, 2026

This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed.

Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers.

@nnethercote nnethercote changed the title Improve how QueryCaches and QueryStates are stored Improve how QueryCache/QueryState/QueryEngine are stored Feb 24, 2026
@nnethercote
Copy link
Contributor Author

@Zalathar: I have updated for the #152791 merge. Should be ready for the final review, thanks.

@Zalathar
Copy link
Member

Commit message nit: The first commit no longer needs to mention SemiDynamicQueryDispatcher. 🎉

@Zalathar
Copy link
Member

r=me with commit message nit addressed.

`QuerySystem` has these fields:
```
pub states: QueryStates<'tcx>,
pub caches: QueryCaches<'tcx>,
pub query_vtables: PerQueryVTables<'tcx>,
```
Each one has an entry for each query.

Some methods that take a query-specific `QueryVTable` need to access the
corresponding query-specific states and/or caches. So `QueryVTable`
stores the *byte offset* to the relevant fields within `states` and
`caches`, and uses that to (with `unsafe`) access the fields. This is
bizarre, and I hope it made sense in the past when the code was
structured differently.

This commit moves `QueryState` and `QueryCache` inside `QueryVTable`. As
a result, the query-specific states and/or caches are directly
accessible, and no unsafe offset computations are required. Much simpler
and more normal. Also, `QueryCaches` and `QueryStates` are no longer
needed, which makes `define_callbacks!` a bit simpler.

The commit also rename the fields and their getters to `states` and
`caches`.
Currently type variables that impl `QueryCache` are called either `C` or
`Cache`. I find the former clearer because single char type variables
names are very common and longer type variable names are easy to mistake
for type or trait names -- e.g. I find the trait bound `C: QueryCache`
much easier and faster to read than `Cache: QueryCache`.
`QueryEngine` is a struct with one function pointer per query. This
commit removes it by moving each function pointer into the relevant
query's vtable, which is already a collection of function pointers for
that query. This makes things simpler.
The `Per` isn't really necessary.
@nnethercote nnethercote force-pushed the fix-query-state-query-cache branch from f362d0e to 7df5249 Compare February 24, 2026 02:01
@nnethercote
Copy link
Contributor Author

I fixed the comment.

@bors r=Zalathar

@rust-bors
Copy link
Contributor

rust-bors bot commented Feb 24, 2026

📌 Commit 7df5249 has been approved by Zalathar

It is now in the queue for this repository.

@rust-bors rust-bors bot added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Feb 24, 2026
@bjorn3
Copy link
Member

bjorn3 commented Feb 24, 2026

Pointers to fields can be done safely using say field-offset.

We used to use that crate before #136201, but removed it as it is not compatible with strict provenance.

@rust-bors rust-bors bot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. labels Feb 24, 2026
@rust-bors
Copy link
Contributor

rust-bors bot commented Feb 24, 2026

☔ The latest upstream changes (presumably #153047) made this pull request unmergeable. Please resolve the merge conflicts.

This pull request was unapproved.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-query-system Area: The rustc query system (https://rustc-dev-guide.rust-lang.org/query.html) S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants