-
Notifications
You must be signed in to change notification settings - Fork 554
Interning chapter #585
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Interning chapter #585
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
# Memory Management in Rustc | ||
|
||
Rustc tries to be pretty careful how it manages memory. The compiler allocates | ||
_a lot_ of data structures throughout compilation, and if we are not careful, | ||
it will take a lot of time and space to do so. | ||
|
||
One of the main way the compiler manages this is using arenas and interning. | ||
|
||
## Arenas and Interning | ||
|
||
We create a LOT of data structures during compilation. For performance reasons, | ||
we allocate them from a global memory pool; they are each allocated once from a | ||
long-lived *arena*. This is called _arena allocation_. This system reduces | ||
allocations/deallocations of memory. It also allows for easy comparison of | ||
types for equality: for each interned type `X`, we implemented [`PartialEq for | ||
X`][peqimpl], so we can just compare pointers. The [`CtxtInterners`] type | ||
contains a bunch of maps of interned types and the arena itself. | ||
|
||
[peqimpl]: https://github.com/rust-lang/rust/blob/3ee936378662bd2e74be951d6a7011a95a6bd84d/src/librustc/ty/mod.rs#L528-L534 | ||
[`CtxtInterners`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc/ty/struct.CtxtInterners.html#structfield.arena | ||
|
||
### Example: `ty::TyS` | ||
|
||
Taking the example of [`ty::TyS`] which represents a type in the compiler (you | ||
can read more [here](./ty.md)). Each time we want to construct a type, the | ||
compiler doesn’t naively allocate from the buffer. Instead, we check if that | ||
type was already constructed. If it was, we just get the same pointer we had | ||
before, otherwise we make a fresh pointer. With this schema if we want to know | ||
if two types are the same, all we need to do is compare the pointers which is | ||
efficient. `TyS` is carefully setup so you never construct them on the stack. | ||
You always allocate them from this arena and you always intern them so they are | ||
unique. | ||
|
||
At the beginning of the compilation we make a buffer and each time we need to allocate a type we use | ||
some of this memory buffer. If we run out of space we get another one. The lifetime of that buffer | ||
is `'tcx`. Our types are tied to that lifetime, so when compilation finishes all the memory related | ||
to that buffer is freed and our `'tcx` references would be invalid. | ||
|
||
In addition to types, there are a number of other arena-allocated data structures that you can | ||
allocate, and which are found in this module. Here are a few examples: | ||
|
||
- [`Substs`][subst], allocated with `mk_substs` – this will intern a slice of types, often used to | ||
specify the values to be substituted for generics (e.g. `HashMap<i32, u32>` would be represented | ||
as a slice `&'tcx [tcx.types.i32, tcx.types.u32]`). | ||
- [`TraitRef`], typically passed by value – a **trait reference** consists of a reference to a trait | ||
along with its various type parameters (including `Self`), like `i32: Display` (here, the def-id | ||
would reference the `Display` trait, and the substs would contain `i32`). Note that `def-id` is | ||
defined and discussed in depth in the `AdtDef and DefId` section. | ||
- [`Predicate`] defines something the trait system has to prove (see `traits` module). | ||
|
||
[subst]: ./generic_arguments.html#subst | ||
[`TraitRef`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc/ty/struct.TraitRef.html | ||
[`Predicate`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc/ty/enum.Predicate.html | ||
|
||
[`ty::TyS`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc/ty/struct.TyS.html | ||
|
||
## The tcx and how it uses lifetimes | ||
|
||
The `tcx` ("typing context") is the central data structure in the compiler. It is the context that | ||
you use to perform all manner of queries. The struct `TyCtxt` defines a reference to this shared | ||
context: | ||
|
||
```rust,ignore | ||
tcx: TyCtxt<'tcx> | ||
// ---- | ||
// | | ||
// arena lifetime | ||
``` | ||
|
||
As you can see, the `TyCtxt` type takes a lifetime parameter. When you see a reference with a | ||
lifetime like `'tcx`, you know that it refers to arena-allocated data (or data that lives as long as | ||
the arenas, anyhow). | ||
|
||
### A Note On Lifetimes | ||
|
||
The Rust compiler is a fairly large program containing lots of big data | ||
structures (e.g. the AST, HIR, and the type system) and as such, arenas and | ||
references are heavily relied upon to minimize unnecessary memory use. This | ||
manifests itself in the way people can plug into the compiler (i.e. the | ||
[driver](./rustc-driver.md)), preferring a "push"-style API (callbacks) instead | ||
of the more Rust-ic "pull" style (think the `Iterator` trait). | ||
|
||
Thread-local storage and interning are used a lot through the compiler to reduce | ||
duplication while also preventing a lot of the ergonomic issues due to many | ||
pervasive lifetimes. The [`rustc::ty::tls`][tls] module is used to access these | ||
thread-locals, although you should rarely need to touch it. | ||
|
||
[tls]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc/ty/tls/index.html |
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
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
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
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.
Uh oh!
There was an error while loading. Please reload this page.