mirror of https://github.com/rust-lang/rust.git
Auto merge of #59953 - eddyb:soa-metadata, r=michaelwoerister
rustc_metadata: replace Entry table with one table for each of its fields (AoS -> SoA). In https://github.com/rust-lang/rust/pull/59789#issuecomment-481958212 I noticed that for many cross-crate queries (e.g. `predicates_of(def_id)`), we were deserializing the `rustc_metadata::schema::Entry` for `def_id` *only* to read one field (i.e. `predicates`). But there are several such queries, and `Entry` is not particularly small (in terms of number of fields, the encoding itself is quite compact), so there is a large (and unnecessary) constant factor. This PR replaces the (random-access) array¹ of `Entry` structures ("AoS"), with many separate arrays¹, one for each field that used to be in `Entry` ("SoA"), resulting in the ability to read individual fields separately, with negligible time overhead (in thoery), and some size overhead (as these arrays are not sparse). In a way, the new approach is closer to incremental on-disk caches, which store each query's cached results separately, but it would take significantly more work to unify the two. For stage1 `libcore`'s metadata blob, the size overhead is `8.44%`, and I have another commit (~~not initially included because I want to do perf runs with both~~ **EDIT**: added it now) that brings it down to `5.88%`. ¹(in the source, these arrays are called "tables", but perhaps they could use a better name)
This commit is contained in:
commit
ea45150837
|
@ -2,6 +2,7 @@
|
|||
|
||||
use crate::cstore::{self, CrateMetadata, MetadataBlob};
|
||||
use crate::schema::*;
|
||||
use crate::table::{FixedSizeEncoding, PerDefTable};
|
||||
|
||||
use rustc_index::vec::IndexVec;
|
||||
use rustc_data_structures::sync::{Lrc, ReadGuard};
|
||||
|
@ -25,9 +26,10 @@ use rustc::util::captures::Captures;
|
|||
|
||||
use std::io;
|
||||
use std::mem;
|
||||
use std::num::NonZeroUsize;
|
||||
use std::u32;
|
||||
|
||||
use rustc_serialize::{Decodable, Decoder, SpecializedDecoder, opaque};
|
||||
use rustc_serialize::{Decodable, Decoder, Encodable, SpecializedDecoder, opaque};
|
||||
use syntax::attr;
|
||||
use syntax::ast::{self, Ident};
|
||||
use syntax::source_map::{self, respan, Spanned};
|
||||
|
@ -129,20 +131,20 @@ impl<'a, 'tcx> Metadata<'a, 'tcx> for (&'a CrateMetadata, TyCtxt<'tcx>) {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx, T: Decodable> Lazy<T> {
|
||||
crate fn decode<M: Metadata<'a, 'tcx>>(self, meta: M) -> T {
|
||||
let mut dcx = meta.decoder(self.position);
|
||||
impl<'a, 'tcx, T: Encodable + Decodable> Lazy<T> {
|
||||
crate fn decode<M: Metadata<'a, 'tcx>>(self, metadata: M) -> T {
|
||||
let mut dcx = metadata.decoder(self.position.get());
|
||||
dcx.lazy_state = LazyState::NodeStart(self.position);
|
||||
T::decode(&mut dcx).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a: 'x, 'tcx: 'x, 'x, T: Decodable> Lazy<[T]> {
|
||||
impl<'a: 'x, 'tcx: 'x, 'x, T: Encodable + Decodable> Lazy<[T]> {
|
||||
crate fn decode<M: Metadata<'a, 'tcx>>(
|
||||
self,
|
||||
meta: M,
|
||||
metadata: M,
|
||||
) -> impl ExactSizeIterator<Item = T> + Captures<'a> + Captures<'tcx> + 'x {
|
||||
let mut dcx = meta.decoder(self.position);
|
||||
let mut dcx = metadata.decoder(self.position.get());
|
||||
dcx.lazy_state = LazyState::NodeStart(self.position);
|
||||
(0..self.meta).map(move |_| T::decode(&mut dcx).unwrap())
|
||||
}
|
||||
|
@ -166,13 +168,14 @@ impl<'a, 'tcx> DecodeContext<'a, 'tcx> {
|
|||
let position = match self.lazy_state {
|
||||
LazyState::NoNode => bug!("read_lazy_with_meta: outside of a metadata node"),
|
||||
LazyState::NodeStart(start) => {
|
||||
let start = start.get();
|
||||
assert!(distance + min_size <= start);
|
||||
start - distance - min_size
|
||||
}
|
||||
LazyState::Previous(last_min_end) => last_min_end + distance,
|
||||
LazyState::Previous(last_min_end) => last_min_end.get() + distance,
|
||||
};
|
||||
self.lazy_state = LazyState::Previous(position + min_size);
|
||||
Ok(Lazy::from_position_and_meta(position, meta))
|
||||
self.lazy_state = LazyState::Previous(NonZeroUsize::new(position + min_size).unwrap());
|
||||
Ok(Lazy::from_position_and_meta(NonZeroUsize::new(position).unwrap(), meta))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -235,13 +238,13 @@ impl<'a, 'tcx> TyDecoder<'tcx> for DecodeContext<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx, T> SpecializedDecoder<Lazy<T>> for DecodeContext<'a, 'tcx> {
|
||||
impl<'a, 'tcx, T: Encodable> SpecializedDecoder<Lazy<T>> for DecodeContext<'a, 'tcx> {
|
||||
fn specialized_decode(&mut self) -> Result<Lazy<T>, Self::Error> {
|
||||
self.read_lazy_with_meta(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx, T> SpecializedDecoder<Lazy<[T]>> for DecodeContext<'a, 'tcx> {
|
||||
impl<'a, 'tcx, T: Encodable> SpecializedDecoder<Lazy<[T]>> for DecodeContext<'a, 'tcx> {
|
||||
fn specialized_decode(&mut self) -> Result<Lazy<[T]>, Self::Error> {
|
||||
let len = self.read_usize()?;
|
||||
if len == 0 {
|
||||
|
@ -252,6 +255,14 @@ impl<'a, 'tcx, T> SpecializedDecoder<Lazy<[T]>> for DecodeContext<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx, T> SpecializedDecoder<Lazy<PerDefTable<T>>> for DecodeContext<'a, 'tcx>
|
||||
where Option<T>: FixedSizeEncoding,
|
||||
{
|
||||
fn specialized_decode(&mut self) -> Result<Lazy<PerDefTable<T>>, Self::Error> {
|
||||
let len = self.read_usize()?;
|
||||
self.read_lazy_with_meta(len)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> SpecializedDecoder<DefId> for DecodeContext<'a, 'tcx> {
|
||||
#[inline]
|
||||
|
@ -384,7 +395,9 @@ impl<'tcx> MetadataBlob {
|
|||
}
|
||||
|
||||
crate fn get_rustc_version(&self) -> String {
|
||||
Lazy::<String>::from_position(METADATA_HEADER.len() + 4).decode(self)
|
||||
Lazy::<String>::from_position(
|
||||
NonZeroUsize::new(METADATA_HEADER.len() + 4).unwrap(),
|
||||
).decode(self)
|
||||
}
|
||||
|
||||
crate fn get_root(&self) -> CrateRoot<'tcx> {
|
||||
|
@ -393,7 +406,9 @@ impl<'tcx> MetadataBlob {
|
|||
let pos = (((slice[offset + 0] as u32) << 24) | ((slice[offset + 1] as u32) << 16) |
|
||||
((slice[offset + 2] as u32) << 8) |
|
||||
((slice[offset + 3] as u32) << 0)) as usize;
|
||||
Lazy::<CrateRoot<'tcx>>::from_position(pos).decode(self)
|
||||
Lazy::<CrateRoot<'tcx>>::from_position(
|
||||
NonZeroUsize::new(pos).unwrap(),
|
||||
).decode(self)
|
||||
}
|
||||
|
||||
crate fn list_crate_metadata(&self,
|
||||
|
@ -458,27 +473,20 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
self.root.proc_macro_data.unwrap().decode(self).find(|x| *x == id).is_some()
|
||||
}
|
||||
|
||||
fn entry_unless_proc_macro(&self, id: DefIndex) -> Option<Entry<'tcx>> {
|
||||
match self.is_proc_macro(id) {
|
||||
true => None,
|
||||
false => Some(self.entry(id)),
|
||||
}
|
||||
fn maybe_kind(&self, item_id: DefIndex) -> Option<EntryKind<'tcx>> {
|
||||
self.root.per_def.kind.get(self, item_id).map(|k| k.decode(self))
|
||||
}
|
||||
|
||||
fn maybe_entry(&self, item_id: DefIndex) -> Option<Lazy<Entry<'tcx>>> {
|
||||
self.root.entries_index.lookup(self.blob.raw_bytes(), item_id)
|
||||
}
|
||||
|
||||
fn entry(&self, item_id: DefIndex) -> Entry<'tcx> {
|
||||
match self.maybe_entry(item_id) {
|
||||
None => {
|
||||
bug!("entry: id not found: {:?} in crate {:?} with number {}",
|
||||
item_id,
|
||||
self.root.name,
|
||||
self.cnum)
|
||||
}
|
||||
Some(d) => d.decode(self),
|
||||
}
|
||||
fn kind(&self, item_id: DefIndex) -> EntryKind<'tcx> {
|
||||
assert!(!self.is_proc_macro(item_id));
|
||||
self.maybe_kind(item_id).unwrap_or_else(|| {
|
||||
bug!(
|
||||
"CrateMetadata::kind({:?}): id not found, in crate {:?} with number {}",
|
||||
item_id,
|
||||
self.root.name,
|
||||
self.cnum,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
fn local_def_id(&self, index: DefIndex) -> DefId {
|
||||
|
@ -514,7 +522,7 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
|
||||
crate fn def_kind(&self, index: DefIndex) -> Option<DefKind> {
|
||||
if !self.is_proc_macro(index) {
|
||||
self.entry(index).kind.def_kind()
|
||||
self.kind(index).def_kind()
|
||||
} else {
|
||||
Some(DefKind::Macro(
|
||||
macro_kind(self.raw_proc_macro(index))
|
||||
|
@ -523,7 +531,7 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
}
|
||||
|
||||
crate fn get_span(&self, index: DefIndex, sess: &Session) -> Span {
|
||||
self.entry(index).span.decode((self, sess))
|
||||
self.root.per_def.span.get(self, index).unwrap().decode((self, sess))
|
||||
}
|
||||
|
||||
crate fn load_proc_macro(&self, id: DefIndex, sess: &Session) -> SyntaxExtension {
|
||||
|
@ -552,12 +560,12 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
helper_attrs,
|
||||
self.root.edition,
|
||||
Symbol::intern(name),
|
||||
&self.get_attributes(&self.entry(id), sess),
|
||||
&self.get_item_attrs(id, sess),
|
||||
)
|
||||
}
|
||||
|
||||
crate fn get_trait_def(&self, item_id: DefIndex, sess: &Session) -> ty::TraitDef {
|
||||
match self.entry(item_id).kind {
|
||||
match self.kind(item_id) {
|
||||
EntryKind::Trait(data) => {
|
||||
let data = data.decode((self, sess));
|
||||
ty::TraitDef::new(self.local_def_id(item_id),
|
||||
|
@ -582,18 +590,24 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
fn get_variant(
|
||||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
item: &Entry<'_>,
|
||||
kind: &EntryKind<'_>,
|
||||
index: DefIndex,
|
||||
parent_did: DefId,
|
||||
adt_kind: ty::AdtKind,
|
||||
) -> ty::VariantDef {
|
||||
let data = match item.kind {
|
||||
let data = match kind {
|
||||
EntryKind::Variant(data) |
|
||||
EntryKind::Struct(data, _) |
|
||||
EntryKind::Union(data, _) => data.decode(self),
|
||||
_ => bug!(),
|
||||
};
|
||||
|
||||
let adt_kind = match kind {
|
||||
EntryKind::Variant(_) => ty::AdtKind::Enum,
|
||||
EntryKind::Struct(..) => ty::AdtKind::Struct,
|
||||
EntryKind::Union(..) => ty::AdtKind::Union,
|
||||
_ => bug!(),
|
||||
};
|
||||
|
||||
let variant_did = if adt_kind == ty::AdtKind::Enum {
|
||||
Some(self.local_def_id(index))
|
||||
} else {
|
||||
|
@ -607,14 +621,12 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
variant_did,
|
||||
ctor_did,
|
||||
data.discr,
|
||||
item.children.decode(self).map(|index| {
|
||||
let f = self.entry(index);
|
||||
ty::FieldDef {
|
||||
self.root.per_def.children.get(self, index).unwrap_or(Lazy::empty())
|
||||
.decode(self).map(|index| ty::FieldDef {
|
||||
did: self.local_def_id(index),
|
||||
ident: Ident::with_dummy_span(self.item_name(index)),
|
||||
vis: f.visibility.decode(self)
|
||||
}
|
||||
}).collect(),
|
||||
vis: self.get_visibility(index),
|
||||
}).collect(),
|
||||
data.ctor_kind,
|
||||
adt_kind,
|
||||
parent_did,
|
||||
|
@ -623,28 +635,28 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
}
|
||||
|
||||
crate fn get_adt_def(&self, item_id: DefIndex, tcx: TyCtxt<'tcx>) -> &'tcx ty::AdtDef {
|
||||
let item = self.entry(item_id);
|
||||
let kind = self.kind(item_id);
|
||||
let did = self.local_def_id(item_id);
|
||||
|
||||
let (kind, repr) = match item.kind {
|
||||
let (adt_kind, repr) = match kind {
|
||||
EntryKind::Enum(repr) => (ty::AdtKind::Enum, repr),
|
||||
EntryKind::Struct(_, repr) => (ty::AdtKind::Struct, repr),
|
||||
EntryKind::Union(_, repr) => (ty::AdtKind::Union, repr),
|
||||
_ => bug!("get_adt_def called on a non-ADT {:?}", did),
|
||||
};
|
||||
|
||||
let variants = if let ty::AdtKind::Enum = kind {
|
||||
item.children
|
||||
let variants = if let ty::AdtKind::Enum = adt_kind {
|
||||
self.root.per_def.children.get(self, item_id).unwrap_or(Lazy::empty())
|
||||
.decode(self)
|
||||
.map(|index| {
|
||||
self.get_variant(tcx, &self.entry(index), index, did, kind)
|
||||
self.get_variant(tcx, &self.kind(index), index, did)
|
||||
})
|
||||
.collect()
|
||||
} else {
|
||||
std::iter::once(self.get_variant(tcx, &item, item_id, did, kind)).collect()
|
||||
std::iter::once(self.get_variant(tcx, &kind, item_id, did)).collect()
|
||||
};
|
||||
|
||||
tcx.alloc_adt_def(did, kind, variants, repr)
|
||||
tcx.alloc_adt_def(did, adt_kind, variants, repr)
|
||||
}
|
||||
|
||||
crate fn get_predicates(
|
||||
|
@ -652,7 +664,7 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
item_id: DefIndex,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
) -> ty::GenericPredicates<'tcx> {
|
||||
self.entry(item_id).predicates.unwrap().decode((self, tcx))
|
||||
self.root.per_def.predicates.get(self, item_id).unwrap().decode((self, tcx))
|
||||
}
|
||||
|
||||
crate fn get_predicates_defined_on(
|
||||
|
@ -660,7 +672,7 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
item_id: DefIndex,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
) -> ty::GenericPredicates<'tcx> {
|
||||
self.entry(item_id).predicates_defined_on.unwrap().decode((self, tcx))
|
||||
self.root.per_def.predicates_defined_on.get(self, item_id).unwrap().decode((self, tcx))
|
||||
}
|
||||
|
||||
crate fn get_super_predicates(
|
||||
|
@ -668,7 +680,7 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
item_id: DefIndex,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
) -> ty::GenericPredicates<'tcx> {
|
||||
let super_predicates = match self.entry(item_id).kind {
|
||||
let super_predicates = match self.kind(item_id) {
|
||||
EntryKind::Trait(data) => data.decode(self).super_predicates,
|
||||
EntryKind::TraitAlias(data) => data.decode(self).super_predicates,
|
||||
_ => bug!("def-index does not refer to trait or trait alias"),
|
||||
|
@ -678,34 +690,35 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
}
|
||||
|
||||
crate fn get_generics(&self, item_id: DefIndex, sess: &Session) -> ty::Generics {
|
||||
self.entry(item_id).generics.unwrap().decode((self, sess))
|
||||
self.root.per_def.generics.get(self, item_id).unwrap().decode((self, sess))
|
||||
}
|
||||
|
||||
crate fn get_type(&self, id: DefIndex, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
|
||||
self.entry(id).ty.unwrap().decode((self, tcx))
|
||||
self.root.per_def.ty.get(self, id).unwrap().decode((self, tcx))
|
||||
}
|
||||
|
||||
crate fn get_stability(&self, id: DefIndex) -> Option<attr::Stability> {
|
||||
match self.is_proc_macro(id) {
|
||||
true => self.root.proc_macro_stability.clone(),
|
||||
false => self.entry(id).stability.map(|stab| stab.decode(self)),
|
||||
false => self.root.per_def.stability.get(self, id).map(|stab| stab.decode(self)),
|
||||
}
|
||||
}
|
||||
|
||||
crate fn get_deprecation(&self, id: DefIndex) -> Option<attr::Deprecation> {
|
||||
self.entry_unless_proc_macro(id)
|
||||
.and_then(|entry| entry.deprecation.map(|depr| depr.decode(self)))
|
||||
self.root.per_def.deprecation.get(self, id)
|
||||
.filter(|_| !self.is_proc_macro(id))
|
||||
.map(|depr| depr.decode(self))
|
||||
}
|
||||
|
||||
crate fn get_visibility(&self, id: DefIndex) -> ty::Visibility {
|
||||
match self.is_proc_macro(id) {
|
||||
true => ty::Visibility::Public,
|
||||
false => self.entry(id).visibility.decode(self),
|
||||
false => self.root.per_def.visibility.get(self, id).unwrap().decode(self),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_impl_data(&self, id: DefIndex) -> ImplData<'tcx> {
|
||||
match self.entry(id).kind {
|
||||
match self.kind(id) {
|
||||
EntryKind::Impl(data) => data.decode(self),
|
||||
_ => bug!(),
|
||||
}
|
||||
|
@ -801,38 +814,42 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
}
|
||||
|
||||
// Find the item.
|
||||
let item = match self.maybe_entry(id) {
|
||||
let kind = match self.maybe_kind(id) {
|
||||
None => return,
|
||||
Some(item) => item.decode((self, sess)),
|
||||
Some(kind) => kind,
|
||||
};
|
||||
|
||||
// Iterate over all children.
|
||||
let macros_only = self.dep_kind.lock().macros_only();
|
||||
for child_index in item.children.decode((self, sess)) {
|
||||
let children = self.root.per_def.children.get(self, id).unwrap_or(Lazy::empty());
|
||||
for child_index in children.decode((self, sess)) {
|
||||
if macros_only {
|
||||
continue
|
||||
}
|
||||
|
||||
// Get the item.
|
||||
if let Some(child) = self.maybe_entry(child_index) {
|
||||
let child = child.decode((self, sess));
|
||||
match child.kind {
|
||||
if let Some(child_kind) = self.maybe_kind(child_index) {
|
||||
match child_kind {
|
||||
EntryKind::MacroDef(..) => {}
|
||||
_ if macros_only => continue,
|
||||
_ => {}
|
||||
}
|
||||
|
||||
// Hand off the item to the callback.
|
||||
match child.kind {
|
||||
match child_kind {
|
||||
// FIXME(eddyb) Don't encode these in children.
|
||||
EntryKind::ForeignMod => {
|
||||
for child_index in child.children.decode((self, sess)) {
|
||||
let child_children =
|
||||
self.root.per_def.children.get(self, child_index)
|
||||
.unwrap_or(Lazy::empty());
|
||||
for child_index in child_children.decode((self, sess)) {
|
||||
if let Some(kind) = self.def_kind(child_index) {
|
||||
callback(def::Export {
|
||||
res: Res::Def(kind, self.local_def_id(child_index)),
|
||||
ident: Ident::with_dummy_span(self.item_name(child_index)),
|
||||
vis: self.get_visibility(child_index),
|
||||
span: self.entry(child_index).span.decode((self, sess)),
|
||||
span: self.root.per_def.span.get(self, child_index).unwrap()
|
||||
.decode((self, sess)),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -844,7 +861,7 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
}
|
||||
|
||||
let def_key = self.def_key(child_index);
|
||||
let span = child.span.decode((self, sess));
|
||||
let span = self.get_span(child_index, sess);
|
||||
if let (Some(kind), Some(name)) =
|
||||
(self.def_kind(child_index), def_key.disambiguated_data.data.get_opt_name()) {
|
||||
let ident = Ident::from_interned_str(name);
|
||||
|
@ -897,7 +914,7 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
}
|
||||
}
|
||||
|
||||
if let EntryKind::Mod(data) = item.kind {
|
||||
if let EntryKind::Mod(data) = kind {
|
||||
for exp in data.decode((self, sess)).reexports.decode((self, sess)) {
|
||||
match exp.res {
|
||||
Res::Def(DefKind::Macro(..), _) => {}
|
||||
|
@ -911,15 +928,16 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
|
||||
crate fn is_item_mir_available(&self, id: DefIndex) -> bool {
|
||||
!self.is_proc_macro(id) &&
|
||||
self.maybe_entry(id).and_then(|item| item.decode(self).mir).is_some()
|
||||
self.root.per_def.mir.get(self, id).is_some()
|
||||
}
|
||||
|
||||
crate fn get_optimized_mir(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> Body<'tcx> {
|
||||
self.entry_unless_proc_macro(id)
|
||||
.and_then(|entry| entry.mir.map(|mir| mir.decode((self, tcx))))
|
||||
self.root.per_def.mir.get(self, id)
|
||||
.filter(|_| !self.is_proc_macro(id))
|
||||
.unwrap_or_else(|| {
|
||||
bug!("get_optimized_mir: missing MIR for `{:?}`", self.local_def_id(id))
|
||||
})
|
||||
.decode((self, tcx))
|
||||
}
|
||||
|
||||
crate fn get_promoted_mir(
|
||||
|
@ -927,15 +945,16 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
tcx: TyCtxt<'tcx>,
|
||||
id: DefIndex,
|
||||
) -> IndexVec<Promoted, Body<'tcx>> {
|
||||
self.entry_unless_proc_macro(id)
|
||||
.and_then(|entry| entry.promoted_mir.map(|promoted| promoted.decode((self, tcx))))
|
||||
self.root.per_def.promoted_mir.get(self, id)
|
||||
.filter(|_| !self.is_proc_macro(id))
|
||||
.unwrap_or_else(|| {
|
||||
bug!("get_promoted_mir: missing MIR for `{:?}`", self.local_def_id(id))
|
||||
})
|
||||
.decode((self, tcx))
|
||||
}
|
||||
|
||||
crate fn mir_const_qualif(&self, id: DefIndex) -> u8 {
|
||||
match self.entry(id).kind {
|
||||
match self.kind(id) {
|
||||
EntryKind::Const(qualif, _) |
|
||||
EntryKind::AssocConst(AssocContainer::ImplDefault, qualif, _) |
|
||||
EntryKind::AssocConst(AssocContainer::ImplFinal, qualif, _) => {
|
||||
|
@ -946,12 +965,11 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
}
|
||||
|
||||
crate fn get_associated_item(&self, id: DefIndex) -> ty::AssocItem {
|
||||
let item = self.entry(id);
|
||||
let def_key = self.def_key(id);
|
||||
let parent = self.local_def_id(def_key.parent.unwrap());
|
||||
let name = def_key.disambiguated_data.data.get_opt_name().unwrap();
|
||||
|
||||
let (kind, container, has_self) = match item.kind {
|
||||
let (kind, container, has_self) = match self.kind(id) {
|
||||
EntryKind::AssocConst(container, _, _) => {
|
||||
(ty::AssocKind::Const, container, false)
|
||||
}
|
||||
|
@ -971,7 +989,7 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
ty::AssocItem {
|
||||
ident: Ident::from_interned_str(name),
|
||||
kind,
|
||||
vis: item.visibility.decode(self),
|
||||
vis: self.get_visibility(id),
|
||||
defaultness: container.defaultness(),
|
||||
def_id: self.local_def_id(id),
|
||||
container: container.with_def_id(parent),
|
||||
|
@ -980,11 +998,12 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
}
|
||||
|
||||
crate fn get_item_variances(&self, id: DefIndex) -> Vec<ty::Variance> {
|
||||
self.entry(id).variances.decode(self).collect()
|
||||
self.root.per_def.variances.get(self, id).unwrap_or(Lazy::empty())
|
||||
.decode(self).collect()
|
||||
}
|
||||
|
||||
crate fn get_ctor_kind(&self, node_id: DefIndex) -> CtorKind {
|
||||
match self.entry(node_id).kind {
|
||||
match self.kind(node_id) {
|
||||
EntryKind::Struct(data, _) |
|
||||
EntryKind::Union(data, _) |
|
||||
EntryKind::Variant(data) => data.decode(self).ctor_kind,
|
||||
|
@ -993,7 +1012,7 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
}
|
||||
|
||||
crate fn get_ctor_def_id(&self, node_id: DefIndex) -> Option<DefId> {
|
||||
match self.entry(node_id).kind {
|
||||
match self.kind(node_id) {
|
||||
EntryKind::Struct(data, _) => {
|
||||
data.decode(self).ctor.map(|index| self.local_def_id(index))
|
||||
}
|
||||
|
@ -1015,8 +1034,9 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
node_id
|
||||
};
|
||||
|
||||
let item = self.entry(item_id);
|
||||
Lrc::from(self.get_attributes(&item, sess))
|
||||
Lrc::from(self.root.per_def.attributes.get(self, item_id).unwrap_or(Lazy::empty())
|
||||
.decode((self, sess))
|
||||
.collect::<Vec<_>>())
|
||||
}
|
||||
|
||||
crate fn get_struct_field_names(
|
||||
|
@ -1024,17 +1044,12 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
id: DefIndex,
|
||||
sess: &Session,
|
||||
) -> Vec<Spanned<ast::Name>> {
|
||||
self.entry(id)
|
||||
.children
|
||||
self.root.per_def.children.get(self, id).unwrap_or(Lazy::empty())
|
||||
.decode(self)
|
||||
.map(|index| respan(self.get_span(index, sess), self.item_name(index)))
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn get_attributes(&self, item: &Entry<'tcx>, sess: &Session) -> Vec<ast::Attribute> {
|
||||
item.attributes.decode((self, sess)).collect()
|
||||
}
|
||||
|
||||
// Translate a DefId from the current compilation environment to a DefId
|
||||
// for an external crate.
|
||||
fn reverse_translate_def_id(&self, did: DefId) -> Option<DefId> {
|
||||
|
@ -1055,10 +1070,11 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
tcx: TyCtxt<'tcx>,
|
||||
id: DefIndex,
|
||||
) -> &'tcx [DefId] {
|
||||
tcx.arena.alloc_from_iter(self.entry(id)
|
||||
.inherent_impls
|
||||
.decode(self)
|
||||
.map(|index| self.local_def_id(index)))
|
||||
tcx.arena.alloc_from_iter(
|
||||
self.root.per_def.inherent_impls.get(self, id).unwrap_or(Lazy::empty())
|
||||
.decode(self)
|
||||
.map(|index| self.local_def_id(index))
|
||||
)
|
||||
}
|
||||
|
||||
crate fn get_implementations_for_trait(
|
||||
|
@ -1100,7 +1116,7 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
_ => return None,
|
||||
}
|
||||
def_key.parent.and_then(|parent_index| {
|
||||
match self.entry(parent_index).kind {
|
||||
match self.kind(parent_index) {
|
||||
EntryKind::Trait(_) |
|
||||
EntryKind::TraitAlias(_) => Some(self.local_def_id(parent_index)),
|
||||
_ => None,
|
||||
|
@ -1153,7 +1169,7 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
}
|
||||
|
||||
crate fn get_fn_param_names(&self, id: DefIndex) -> Vec<ast::Name> {
|
||||
let param_names = match self.entry(id).kind {
|
||||
let param_names = match self.kind(id) {
|
||||
EntryKind::Fn(data) |
|
||||
EntryKind::ForeignFn(data) => data.decode(self).param_names,
|
||||
EntryKind::Method(data) => data.decode(self).fn_data.param_names,
|
||||
|
@ -1176,7 +1192,7 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
}
|
||||
|
||||
crate fn get_rendered_const(&self, id: DefIndex) -> String {
|
||||
match self.entry(id).kind {
|
||||
match self.kind(id) {
|
||||
EntryKind::Const(_, data) |
|
||||
EntryKind::AssocConst(_, _, data) => data.decode(self).0,
|
||||
_ => bug!(),
|
||||
|
@ -1184,15 +1200,14 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
}
|
||||
|
||||
crate fn get_macro(&self, id: DefIndex) -> MacroDef {
|
||||
let entry = self.entry(id);
|
||||
match entry.kind {
|
||||
match self.kind(id) {
|
||||
EntryKind::MacroDef(macro_def) => macro_def.decode(self),
|
||||
_ => bug!(),
|
||||
}
|
||||
}
|
||||
|
||||
crate fn is_const_fn_raw(&self, id: DefIndex) -> bool {
|
||||
let constness = match self.entry(id).kind {
|
||||
let constness = match self.kind(id) {
|
||||
EntryKind::Method(data) => data.decode(self).fn_data.constness,
|
||||
EntryKind::Fn(data) => data.decode(self).constness,
|
||||
EntryKind::Variant(..) | EntryKind::Struct(..) => hir::Constness::Const,
|
||||
|
@ -1202,16 +1217,16 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
}
|
||||
|
||||
crate fn asyncness(&self, id: DefIndex) -> hir::IsAsync {
|
||||
match self.entry(id).kind {
|
||||
match self.kind(id) {
|
||||
EntryKind::Fn(data) => data.decode(self).asyncness,
|
||||
EntryKind::Method(data) => data.decode(self).fn_data.asyncness,
|
||||
EntryKind::ForeignFn(data) => data.decode(self).asyncness,
|
||||
_ => bug!("asyncness: expect functions entry."),
|
||||
_ => bug!("asyncness: expected function kind"),
|
||||
}
|
||||
}
|
||||
|
||||
crate fn is_foreign_item(&self, id: DefIndex) -> bool {
|
||||
match self.entry(id).kind {
|
||||
match self.kind(id) {
|
||||
EntryKind::ForeignImmStatic |
|
||||
EntryKind::ForeignMutStatic |
|
||||
EntryKind::ForeignFn(_) => true,
|
||||
|
@ -1220,7 +1235,7 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
}
|
||||
|
||||
crate fn static_mutability(&self, id: DefIndex) -> Option<hir::Mutability> {
|
||||
match self.entry(id).kind {
|
||||
match self.kind(id) {
|
||||
EntryKind::ImmStatic |
|
||||
EntryKind::ForeignImmStatic => Some(hir::MutImmutable),
|
||||
EntryKind::MutStatic |
|
||||
|
@ -1230,7 +1245,7 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
}
|
||||
|
||||
crate fn fn_sig(&self, id: DefIndex, tcx: TyCtxt<'tcx>) -> ty::PolyFnSig<'tcx> {
|
||||
let sig = match self.entry(id).kind {
|
||||
let sig = match self.kind(id) {
|
||||
EntryKind::Fn(data) |
|
||||
EntryKind::ForeignFn(data) => data.decode(self).sig,
|
||||
EntryKind::Method(data) => data.decode(self).fn_data.sig,
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,141 +0,0 @@
|
|||
use crate::schema::*;
|
||||
|
||||
use rustc::hir::def_id::{DefId, DefIndex};
|
||||
use rustc_serialize::opaque::Encoder;
|
||||
use std::marker::PhantomData;
|
||||
use std::u32;
|
||||
use log::debug;
|
||||
|
||||
/// Helper trait, for encoding to, and decoding from, a fixed number of bytes.
|
||||
trait FixedSizeEncoding {
|
||||
const BYTE_LEN: usize;
|
||||
|
||||
// FIXME(eddyb) convert to and from `[u8; Self::BYTE_LEN]` instead,
|
||||
// once that starts being allowed by the compiler (i.e. lazy normalization).
|
||||
fn from_bytes(b: &[u8]) -> Self;
|
||||
fn write_to_bytes(self, b: &mut [u8]);
|
||||
|
||||
// FIXME(eddyb) make these generic functions, or at least defaults here.
|
||||
// (same problem as above, needs `[u8; Self::BYTE_LEN]`)
|
||||
// For now, a macro (`fixed_size_encoding_byte_len_and_defaults`) is used.
|
||||
fn read_from_bytes_at(b: &[u8], i: usize) -> Self;
|
||||
fn write_to_bytes_at(self, b: &mut [u8], i: usize);
|
||||
}
|
||||
|
||||
// HACK(eddyb) this shouldn't be needed (see comments on the methods above).
|
||||
macro_rules! fixed_size_encoding_byte_len_and_defaults {
|
||||
($byte_len:expr) => {
|
||||
const BYTE_LEN: usize = $byte_len;
|
||||
fn read_from_bytes_at(b: &[u8], i: usize) -> Self {
|
||||
const BYTE_LEN: usize = $byte_len;
|
||||
// HACK(eddyb) ideally this would be done with fully safe code,
|
||||
// but slicing `[u8]` with `i * N..` is optimized worse, due to the
|
||||
// possibility of `i * N` overflowing, than indexing `[[u8; N]]`.
|
||||
let b = unsafe {
|
||||
std::slice::from_raw_parts(
|
||||
b.as_ptr() as *const [u8; BYTE_LEN],
|
||||
b.len() / BYTE_LEN,
|
||||
)
|
||||
};
|
||||
Self::from_bytes(&b[i])
|
||||
}
|
||||
fn write_to_bytes_at(self, b: &mut [u8], i: usize) {
|
||||
const BYTE_LEN: usize = $byte_len;
|
||||
// HACK(eddyb) ideally this would be done with fully safe code,
|
||||
// see similar comment in `read_from_bytes_at` for why it can't yet.
|
||||
let b = unsafe {
|
||||
std::slice::from_raw_parts_mut(
|
||||
b.as_mut_ptr() as *mut [u8; BYTE_LEN],
|
||||
b.len() / BYTE_LEN,
|
||||
)
|
||||
};
|
||||
self.write_to_bytes(&mut b[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FixedSizeEncoding for u32 {
|
||||
fixed_size_encoding_byte_len_and_defaults!(4);
|
||||
|
||||
fn from_bytes(b: &[u8]) -> Self {
|
||||
let mut bytes = [0; Self::BYTE_LEN];
|
||||
bytes.copy_from_slice(&b[..Self::BYTE_LEN]);
|
||||
Self::from_le_bytes(bytes)
|
||||
}
|
||||
|
||||
fn write_to_bytes(self, b: &mut [u8]) {
|
||||
b[..Self::BYTE_LEN].copy_from_slice(&self.to_le_bytes());
|
||||
}
|
||||
}
|
||||
|
||||
/// While we are generating the metadata, we also track the position
|
||||
/// of each DefIndex. It is not required that all definitions appear
|
||||
/// in the metadata, nor that they are serialized in order, and
|
||||
/// therefore we first allocate the vector here and fill it with
|
||||
/// `u32::MAX`. Whenever an index is visited, we fill in the
|
||||
/// appropriate spot by calling `record_position`. We should never
|
||||
/// visit the same index twice.
|
||||
crate struct Index<'tcx> {
|
||||
positions: Vec<u8>,
|
||||
_marker: PhantomData<&'tcx ()>,
|
||||
}
|
||||
|
||||
impl Index<'tcx> {
|
||||
crate fn new(max_index: usize) -> Self {
|
||||
Index {
|
||||
positions: vec![0xff; max_index * 4],
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
crate fn record(&mut self, def_id: DefId, entry: Lazy<Entry<'tcx>>) {
|
||||
assert!(def_id.is_local());
|
||||
self.record_index(def_id.index, entry);
|
||||
}
|
||||
|
||||
fn record_index(&mut self, item: DefIndex, entry: Lazy<Entry<'tcx>>) {
|
||||
assert!(entry.position < (u32::MAX as usize));
|
||||
let position = entry.position as u32;
|
||||
let array_index = item.index();
|
||||
|
||||
let positions = &mut self.positions;
|
||||
assert!(u32::read_from_bytes_at(positions, array_index) == u32::MAX,
|
||||
"recorded position for item {:?} twice, first at {:?} and now at {:?}",
|
||||
item,
|
||||
u32::read_from_bytes_at(positions, array_index),
|
||||
position);
|
||||
|
||||
position.write_to_bytes_at(positions, array_index)
|
||||
}
|
||||
|
||||
crate fn write_index(&self, buf: &mut Encoder) -> Lazy<[Self]> {
|
||||
let pos = buf.position();
|
||||
|
||||
// First we write the length of the lower range ...
|
||||
buf.emit_raw_bytes(&(self.positions.len() as u32 / 4).to_le_bytes());
|
||||
// ... then the values.
|
||||
buf.emit_raw_bytes(&self.positions);
|
||||
Lazy::from_position_and_meta(pos as usize, self.positions.len() / 4 + 1)
|
||||
}
|
||||
}
|
||||
|
||||
impl Lazy<[Index<'tcx>]> {
|
||||
/// Given the metadata, extract out the offset of a particular
|
||||
/// DefIndex (if any).
|
||||
#[inline(never)]
|
||||
crate fn lookup(&self, bytes: &[u8], def_index: DefIndex) -> Option<Lazy<Entry<'tcx>>> {
|
||||
let bytes = &bytes[self.position..];
|
||||
debug!("Index::lookup: index={:?} len={:?}",
|
||||
def_index,
|
||||
self.meta);
|
||||
|
||||
let position = u32::read_from_bytes_at(bytes, 1 + def_index.index());
|
||||
if position == u32::MAX {
|
||||
debug!("Index::lookup: position=u32::MAX");
|
||||
None
|
||||
} else {
|
||||
debug!("Index::lookup: position={:?}", position);
|
||||
Some(Lazy::from_position(position as usize))
|
||||
}
|
||||
}
|
||||
}
|
|
@ -26,15 +26,15 @@ extern crate rustc_data_structures;
|
|||
|
||||
pub mod error_codes;
|
||||
|
||||
mod index;
|
||||
mod encoder;
|
||||
mod decoder;
|
||||
mod cstore_impl;
|
||||
mod schema;
|
||||
mod native_libs;
|
||||
mod link_args;
|
||||
mod foreign_modules;
|
||||
mod dependency_format;
|
||||
mod cstore_impl;
|
||||
mod foreign_modules;
|
||||
mod link_args;
|
||||
mod native_libs;
|
||||
mod schema;
|
||||
mod table;
|
||||
|
||||
pub mod creader;
|
||||
pub mod cstore;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::index;
|
||||
use crate::table::PerDefTable;
|
||||
|
||||
use rustc::hir;
|
||||
use rustc::hir::def::{self, CtorKind};
|
||||
|
@ -14,12 +14,14 @@ use rustc_target::spec::{PanicStrategy, TargetTriple};
|
|||
use rustc_index::vec::IndexVec;
|
||||
use rustc_data_structures::svh::Svh;
|
||||
|
||||
use rustc_serialize::Encodable;
|
||||
use syntax::{ast, attr};
|
||||
use syntax::edition::Edition;
|
||||
use syntax::symbol::Symbol;
|
||||
use syntax_pos::{self, Span};
|
||||
|
||||
use std::marker::PhantomData;
|
||||
use std::num::NonZeroUsize;
|
||||
|
||||
crate fn rustc_version() -> String {
|
||||
format!("rustc {}",
|
||||
|
@ -52,7 +54,7 @@ crate trait LazyMeta {
|
|||
fn min_size(meta: Self::Meta) -> usize;
|
||||
}
|
||||
|
||||
impl<T> LazyMeta for T {
|
||||
impl<T: Encodable> LazyMeta for T {
|
||||
type Meta = ();
|
||||
|
||||
fn min_size(_: ()) -> usize {
|
||||
|
@ -61,7 +63,7 @@ impl<T> LazyMeta for T {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T> LazyMeta for [T] {
|
||||
impl<T: Encodable> LazyMeta for [T] {
|
||||
type Meta = usize;
|
||||
|
||||
fn min_size(len: usize) -> usize {
|
||||
|
@ -102,13 +104,13 @@ crate struct Lazy<T, Meta = <T as LazyMeta>::Meta>
|
|||
where T: ?Sized + LazyMeta<Meta = Meta>,
|
||||
Meta: 'static + Copy,
|
||||
{
|
||||
pub position: usize,
|
||||
pub position: NonZeroUsize,
|
||||
pub meta: Meta,
|
||||
_marker: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T: ?Sized + LazyMeta> Lazy<T> {
|
||||
crate fn from_position_and_meta(position: usize, meta: T::Meta) -> Lazy<T> {
|
||||
crate fn from_position_and_meta(position: NonZeroUsize, meta: T::Meta) -> Lazy<T> {
|
||||
Lazy {
|
||||
position,
|
||||
meta,
|
||||
|
@ -117,15 +119,15 @@ impl<T: ?Sized + LazyMeta> Lazy<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T> Lazy<T> {
|
||||
crate fn from_position(position: usize) -> Lazy<T> {
|
||||
impl<T: Encodable> Lazy<T> {
|
||||
crate fn from_position(position: NonZeroUsize) -> Lazy<T> {
|
||||
Lazy::from_position_and_meta(position, ())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Lazy<[T]> {
|
||||
impl<T: Encodable> Lazy<[T]> {
|
||||
crate fn empty() -> Lazy<[T]> {
|
||||
Lazy::from_position_and_meta(0, 0)
|
||||
Lazy::from_position_and_meta(NonZeroUsize::new(1).unwrap(), 0)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -147,12 +149,22 @@ crate enum LazyState {
|
|||
|
||||
/// Inside a metadata node, and before any `Lazy`.
|
||||
/// The position is that of the node itself.
|
||||
NodeStart(usize),
|
||||
NodeStart(NonZeroUsize),
|
||||
|
||||
/// Inside a metadata node, with a previous `Lazy`.
|
||||
/// The position is a conservative estimate of where that
|
||||
/// previous `Lazy` would end (see their comments).
|
||||
Previous(usize),
|
||||
Previous(NonZeroUsize),
|
||||
}
|
||||
|
||||
// FIXME(#59875) `Lazy!(T)` replaces `Lazy<T>`, passing the `Meta` parameter
|
||||
// manually, instead of relying on the default, to get the correct variance.
|
||||
// Only needed when `T` itself contains a parameter (e.g. `'tcx`).
|
||||
macro_rules! Lazy {
|
||||
(Table<$T:ty>) => {Lazy<Table<$T>, usize>};
|
||||
(PerDefTable<$T:ty>) => {Lazy<PerDefTable<$T>, usize>};
|
||||
([$T:ty]) => {Lazy<[$T], usize>};
|
||||
($T:ty) => {Lazy<$T, ()>};
|
||||
}
|
||||
|
||||
#[derive(RustcEncodable, RustcDecodable)]
|
||||
|
@ -182,10 +194,10 @@ crate struct CrateRoot<'tcx> {
|
|||
pub source_map: Lazy<[syntax_pos::SourceFile]>,
|
||||
pub def_path_table: Lazy<hir::map::definitions::DefPathTable>,
|
||||
pub impls: Lazy<[TraitImpls]>,
|
||||
pub exported_symbols: Lazy<[(ExportedSymbol<'tcx>, SymbolExportLevel)]>,
|
||||
pub exported_symbols: Lazy!([(ExportedSymbol<'tcx>, SymbolExportLevel)]),
|
||||
pub interpret_alloc_index: Lazy<[u32]>,
|
||||
|
||||
pub entries_index: Lazy<[index::Index<'tcx>]>,
|
||||
pub per_def: LazyPerDefTables<'tcx>,
|
||||
|
||||
/// The DefIndex's of any proc macros delcared by
|
||||
/// this crate
|
||||
|
@ -216,24 +228,24 @@ crate struct TraitImpls {
|
|||
}
|
||||
|
||||
#[derive(RustcEncodable, RustcDecodable)]
|
||||
crate struct Entry<'tcx> {
|
||||
pub kind: EntryKind<'tcx>,
|
||||
pub visibility: Lazy<ty::Visibility>,
|
||||
pub span: Lazy<Span>,
|
||||
pub attributes: Lazy<[ast::Attribute]>,
|
||||
pub children: Lazy<[DefIndex]>,
|
||||
pub stability: Option<Lazy<attr::Stability>>,
|
||||
pub deprecation: Option<Lazy<attr::Deprecation>>,
|
||||
crate struct LazyPerDefTables<'tcx> {
|
||||
pub kind: Lazy!(PerDefTable<Lazy!(EntryKind<'tcx>)>),
|
||||
pub visibility: Lazy!(PerDefTable<Lazy<ty::Visibility>>),
|
||||
pub span: Lazy!(PerDefTable<Lazy<Span>>),
|
||||
pub attributes: Lazy!(PerDefTable<Lazy<[ast::Attribute]>>),
|
||||
pub children: Lazy!(PerDefTable<Lazy<[DefIndex]>>),
|
||||
pub stability: Lazy!(PerDefTable<Lazy<attr::Stability>>),
|
||||
pub deprecation: Lazy!(PerDefTable<Lazy<attr::Deprecation>>),
|
||||
|
||||
pub ty: Option<Lazy<Ty<'tcx>>>,
|
||||
pub inherent_impls: Lazy<[DefIndex]>,
|
||||
pub variances: Lazy<[ty::Variance]>,
|
||||
pub generics: Option<Lazy<ty::Generics>>,
|
||||
pub predicates: Option<Lazy<ty::GenericPredicates<'tcx>>>,
|
||||
pub predicates_defined_on: Option<Lazy<ty::GenericPredicates<'tcx>>>,
|
||||
pub ty: Lazy!(PerDefTable<Lazy!(Ty<'tcx>)>),
|
||||
pub inherent_impls: Lazy!(PerDefTable<Lazy<[DefIndex]>>),
|
||||
pub variances: Lazy!(PerDefTable<Lazy<[ty::Variance]>>),
|
||||
pub generics: Lazy!(PerDefTable<Lazy<ty::Generics>>),
|
||||
pub predicates: Lazy!(PerDefTable<Lazy!(ty::GenericPredicates<'tcx>)>),
|
||||
pub predicates_defined_on: Lazy!(PerDefTable<Lazy!(ty::GenericPredicates<'tcx>)>),
|
||||
|
||||
pub mir: Option<Lazy<mir::Body<'tcx>>>,
|
||||
pub promoted_mir: Option<Lazy<IndexVec<mir::Promoted, mir::Body<'tcx>>>>,
|
||||
pub mir: Lazy!(PerDefTable<Lazy!(mir::Body<'tcx>)>),
|
||||
pub promoted_mir: Lazy!(PerDefTable<Lazy!(IndexVec<mir::Promoted, mir::Body<'tcx>>)>),
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, RustcEncodable, RustcDecodable)]
|
||||
|
@ -252,22 +264,22 @@ crate enum EntryKind<'tcx> {
|
|||
OpaqueTy,
|
||||
Enum(ReprOptions),
|
||||
Field,
|
||||
Variant(Lazy<VariantData<'tcx>>),
|
||||
Struct(Lazy<VariantData<'tcx>>, ReprOptions),
|
||||
Union(Lazy<VariantData<'tcx>>, ReprOptions),
|
||||
Fn(Lazy<FnData<'tcx>>),
|
||||
ForeignFn(Lazy<FnData<'tcx>>),
|
||||
Variant(Lazy!(VariantData<'tcx>)),
|
||||
Struct(Lazy!(VariantData<'tcx>), ReprOptions),
|
||||
Union(Lazy!(VariantData<'tcx>), ReprOptions),
|
||||
Fn(Lazy!(FnData<'tcx>)),
|
||||
ForeignFn(Lazy!(FnData<'tcx>)),
|
||||
Mod(Lazy<ModData>),
|
||||
MacroDef(Lazy<MacroDef>),
|
||||
Closure(Lazy<ClosureData<'tcx>>),
|
||||
Generator(Lazy<GeneratorData<'tcx>>),
|
||||
Trait(Lazy<TraitData<'tcx>>),
|
||||
Impl(Lazy<ImplData<'tcx>>),
|
||||
Method(Lazy<MethodData<'tcx>>),
|
||||
Closure(Lazy!(ClosureData<'tcx>)),
|
||||
Generator(Lazy!(GeneratorData<'tcx>)),
|
||||
Trait(Lazy!(TraitData<'tcx>)),
|
||||
Impl(Lazy!(ImplData<'tcx>)),
|
||||
Method(Lazy!(MethodData<'tcx>)),
|
||||
AssocType(AssocContainer),
|
||||
AssocOpaqueTy(AssocContainer),
|
||||
AssocConst(AssocContainer, ConstQualif, Lazy<RenderedConst>),
|
||||
TraitAlias(Lazy<TraitAliasData<'tcx>>),
|
||||
TraitAlias(Lazy!(TraitAliasData<'tcx>)),
|
||||
}
|
||||
|
||||
/// Additional data for EntryKind::Const and EntryKind::AssocConst
|
||||
|
@ -297,7 +309,7 @@ crate struct FnData<'tcx> {
|
|||
pub asyncness: hir::IsAsync,
|
||||
pub constness: hir::Constness,
|
||||
pub param_names: Lazy<[ast::Name]>,
|
||||
pub sig: Lazy<ty::PolyFnSig<'tcx>>,
|
||||
pub sig: Lazy!(ty::PolyFnSig<'tcx>),
|
||||
}
|
||||
|
||||
#[derive(RustcEncodable, RustcDecodable)]
|
||||
|
@ -308,7 +320,7 @@ crate struct VariantData<'tcx> {
|
|||
pub ctor: Option<DefIndex>,
|
||||
/// If this is a tuple struct or variant
|
||||
/// ctor, this is its "function" signature.
|
||||
pub ctor_sig: Option<Lazy<ty::PolyFnSig<'tcx>>>,
|
||||
pub ctor_sig: Option<Lazy!(ty::PolyFnSig<'tcx>)>,
|
||||
}
|
||||
|
||||
#[derive(RustcEncodable, RustcDecodable)]
|
||||
|
@ -317,12 +329,12 @@ crate struct TraitData<'tcx> {
|
|||
pub paren_sugar: bool,
|
||||
pub has_auto_impl: bool,
|
||||
pub is_marker: bool,
|
||||
pub super_predicates: Lazy<ty::GenericPredicates<'tcx>>,
|
||||
pub super_predicates: Lazy!(ty::GenericPredicates<'tcx>),
|
||||
}
|
||||
|
||||
#[derive(RustcEncodable, RustcDecodable)]
|
||||
crate struct TraitAliasData<'tcx> {
|
||||
pub super_predicates: Lazy<ty::GenericPredicates<'tcx>>,
|
||||
pub super_predicates: Lazy!(ty::GenericPredicates<'tcx>),
|
||||
}
|
||||
|
||||
#[derive(RustcEncodable, RustcDecodable)]
|
||||
|
@ -333,7 +345,7 @@ crate struct ImplData<'tcx> {
|
|||
|
||||
/// This is `Some` only for impls of `CoerceUnsized`.
|
||||
pub coerce_unsized_info: Option<ty::adjustment::CoerceUnsizedInfo>,
|
||||
pub trait_ref: Option<Lazy<ty::TraitRef<'tcx>>>,
|
||||
pub trait_ref: Option<Lazy!(ty::TraitRef<'tcx>)>,
|
||||
}
|
||||
|
||||
|
||||
|
@ -384,7 +396,7 @@ crate struct MethodData<'tcx> {
|
|||
|
||||
#[derive(RustcEncodable, RustcDecodable)]
|
||||
crate struct ClosureData<'tcx> {
|
||||
pub sig: Lazy<ty::PolyFnSig<'tcx>>,
|
||||
pub sig: Lazy!(ty::PolyFnSig<'tcx>),
|
||||
}
|
||||
|
||||
#[derive(RustcEncodable, RustcDecodable)]
|
||||
|
|
|
@ -0,0 +1,239 @@
|
|||
use crate::decoder::Metadata;
|
||||
use crate::schema::*;
|
||||
|
||||
use rustc::hir::def_id::{DefId, DefIndex};
|
||||
use rustc_serialize::{Encodable, opaque::Encoder};
|
||||
use std::convert::TryInto;
|
||||
use std::marker::PhantomData;
|
||||
use std::num::NonZeroUsize;
|
||||
use log::debug;
|
||||
|
||||
/// Helper trait, for encoding to, and decoding from, a fixed number of bytes.
|
||||
/// Used mainly for Lazy positions and lengths.
|
||||
/// Unchecked invariant: `Self::default()` should encode as `[0; BYTE_LEN]`,
|
||||
/// but this has no impact on safety.
|
||||
crate trait FixedSizeEncoding: Default {
|
||||
const BYTE_LEN: usize;
|
||||
|
||||
// FIXME(eddyb) convert to and from `[u8; Self::BYTE_LEN]` instead,
|
||||
// once that starts being allowed by the compiler (i.e. lazy normalization).
|
||||
fn from_bytes(b: &[u8]) -> Self;
|
||||
fn write_to_bytes(self, b: &mut [u8]);
|
||||
|
||||
// FIXME(eddyb) make these generic functions, or at least defaults here.
|
||||
// (same problem as above, needs `[u8; Self::BYTE_LEN]`)
|
||||
// For now, a macro (`fixed_size_encoding_byte_len_and_defaults`) is used.
|
||||
|
||||
/// Read a `Self` value (encoded as `Self::BYTE_LEN` bytes),
|
||||
/// from `&b[i * Self::BYTE_LEN..]`, returning `None` if `i`
|
||||
/// is not in bounds, or `Some(Self::from_bytes(...))` otherwise.
|
||||
fn maybe_read_from_bytes_at(b: &[u8], i: usize) -> Option<Self>;
|
||||
/// Write a `Self` value (encoded as `Self::BYTE_LEN` bytes),
|
||||
/// at `&mut b[i * Self::BYTE_LEN..]`, using `Self::write_to_bytes`.
|
||||
fn write_to_bytes_at(self, b: &mut [u8], i: usize);
|
||||
}
|
||||
|
||||
// HACK(eddyb) this shouldn't be needed (see comments on the methods above).
|
||||
macro_rules! fixed_size_encoding_byte_len_and_defaults {
|
||||
($byte_len:expr) => {
|
||||
const BYTE_LEN: usize = $byte_len;
|
||||
fn maybe_read_from_bytes_at(b: &[u8], i: usize) -> Option<Self> {
|
||||
const BYTE_LEN: usize = $byte_len;
|
||||
// HACK(eddyb) ideally this would be done with fully safe code,
|
||||
// but slicing `[u8]` with `i * N..` is optimized worse, due to the
|
||||
// possibility of `i * N` overflowing, than indexing `[[u8; N]]`.
|
||||
let b = unsafe {
|
||||
std::slice::from_raw_parts(
|
||||
b.as_ptr() as *const [u8; BYTE_LEN],
|
||||
b.len() / BYTE_LEN,
|
||||
)
|
||||
};
|
||||
b.get(i).map(|b| FixedSizeEncoding::from_bytes(b))
|
||||
}
|
||||
fn write_to_bytes_at(self, b: &mut [u8], i: usize) {
|
||||
const BYTE_LEN: usize = $byte_len;
|
||||
// HACK(eddyb) ideally this would be done with fully safe code,
|
||||
// see similar comment in `read_from_bytes_at` for why it can't yet.
|
||||
let b = unsafe {
|
||||
std::slice::from_raw_parts_mut(
|
||||
b.as_mut_ptr() as *mut [u8; BYTE_LEN],
|
||||
b.len() / BYTE_LEN,
|
||||
)
|
||||
};
|
||||
self.write_to_bytes(&mut b[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FixedSizeEncoding for u32 {
|
||||
fixed_size_encoding_byte_len_and_defaults!(4);
|
||||
|
||||
fn from_bytes(b: &[u8]) -> Self {
|
||||
let mut bytes = [0; Self::BYTE_LEN];
|
||||
bytes.copy_from_slice(&b[..Self::BYTE_LEN]);
|
||||
Self::from_le_bytes(bytes)
|
||||
}
|
||||
|
||||
fn write_to_bytes(self, b: &mut [u8]) {
|
||||
b[..Self::BYTE_LEN].copy_from_slice(&self.to_le_bytes());
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE(eddyb) there could be an impl for `usize`, which would enable a more
|
||||
// generic `Lazy<T>` impl, but in the general case we might not need / want to
|
||||
// fit every `usize` in `u32`.
|
||||
impl<T: Encodable> FixedSizeEncoding for Option<Lazy<T>> {
|
||||
fixed_size_encoding_byte_len_and_defaults!(u32::BYTE_LEN);
|
||||
|
||||
fn from_bytes(b: &[u8]) -> Self {
|
||||
Some(Lazy::from_position(NonZeroUsize::new(u32::from_bytes(b) as usize)?))
|
||||
}
|
||||
|
||||
fn write_to_bytes(self, b: &mut [u8]) {
|
||||
let position = self.map_or(0, |lazy| lazy.position.get());
|
||||
let position: u32 = position.try_into().unwrap();
|
||||
|
||||
position.write_to_bytes(b)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Encodable> FixedSizeEncoding for Option<Lazy<[T]>> {
|
||||
fixed_size_encoding_byte_len_and_defaults!(u32::BYTE_LEN * 2);
|
||||
|
||||
fn from_bytes(b: &[u8]) -> Self {
|
||||
Some(Lazy::from_position_and_meta(
|
||||
<Option<Lazy<T>>>::from_bytes(b)?.position,
|
||||
u32::from_bytes(&b[u32::BYTE_LEN..]) as usize,
|
||||
))
|
||||
}
|
||||
|
||||
fn write_to_bytes(self, b: &mut [u8]) {
|
||||
self.map(|lazy| Lazy::<T>::from_position(lazy.position))
|
||||
.write_to_bytes(b);
|
||||
|
||||
let len = self.map_or(0, |lazy| lazy.meta);
|
||||
let len: u32 = len.try_into().unwrap();
|
||||
|
||||
len.write_to_bytes(&mut b[u32::BYTE_LEN..]);
|
||||
}
|
||||
}
|
||||
|
||||
/// Random-access table (i.e. offeringconstant-time `get`/`set`), similar to
|
||||
/// `Vec<Option<T>>`, but without requiring encoding or decoding all the values
|
||||
/// eagerly and in-order.
|
||||
/// A total of `(max_idx + 1) * <Option<T> as FixedSizeEncoding>::BYTE_LEN` bytes
|
||||
/// are used for a table, where `max_idx` is the largest index passed to `set`.
|
||||
// FIXME(eddyb) replace `Vec` with `[_]` here, such that `Box<Table<T>>` would be used
|
||||
// when building it, and `Lazy<Table<T>>` or `&Table<T>` when reading it.
|
||||
// (not sure if that is possible given that the `Vec` is being resized now)
|
||||
crate struct Table<T> where Option<T>: FixedSizeEncoding {
|
||||
// FIXME(eddyb) store `[u8; <Option<T>>::BYTE_LEN]` instead of `u8` in `Vec`,
|
||||
// once that starts being allowed by the compiler (i.e. lazy normalization).
|
||||
bytes: Vec<u8>,
|
||||
_marker: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T> Default for Table<T> where Option<T>: FixedSizeEncoding {
|
||||
fn default() -> Self {
|
||||
Table {
|
||||
bytes: vec![],
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Table<T> where Option<T>: FixedSizeEncoding {
|
||||
crate fn set(&mut self, i: usize, value: T) {
|
||||
// FIXME(eddyb) investigate more compact encodings for sparse tables.
|
||||
// On the PR @michaelwoerister mentioned:
|
||||
// > Space requirements could perhaps be optimized by using the HAMT `popcnt`
|
||||
// > trick (i.e. divide things into buckets of 32 or 64 items and then
|
||||
// > store bit-masks of which item in each bucket is actually serialized).
|
||||
let needed = (i + 1) * <Option<T>>::BYTE_LEN;
|
||||
if self.bytes.len() < needed {
|
||||
self.bytes.resize(needed, 0);
|
||||
}
|
||||
|
||||
Some(value).write_to_bytes_at(&mut self.bytes, i);
|
||||
}
|
||||
|
||||
crate fn encode(&self, buf: &mut Encoder) -> Lazy<Self> {
|
||||
let pos = buf.position();
|
||||
buf.emit_raw_bytes(&self.bytes);
|
||||
Lazy::from_position_and_meta(
|
||||
NonZeroUsize::new(pos as usize).unwrap(),
|
||||
self.bytes.len(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> LazyMeta for Table<T> where Option<T>: FixedSizeEncoding {
|
||||
type Meta = usize;
|
||||
|
||||
fn min_size(len: usize) -> usize {
|
||||
len
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Lazy<Table<T>> where Option<T>: FixedSizeEncoding {
|
||||
/// Given the metadata, extract out the value at a particular index (if any).
|
||||
#[inline(never)]
|
||||
crate fn get<'a, 'tcx, M: Metadata<'a, 'tcx>>(
|
||||
&self,
|
||||
metadata: M,
|
||||
i: usize,
|
||||
) -> Option<T> {
|
||||
debug!("Table::lookup: index={:?} len={:?}", i, self.meta);
|
||||
|
||||
let start = self.position.get();
|
||||
let bytes = &metadata.raw_bytes()[start..start + self.meta];
|
||||
<Option<T>>::maybe_read_from_bytes_at(bytes, i)?
|
||||
}
|
||||
}
|
||||
|
||||
/// Like a `Table` but using `DefIndex` instead of `usize` as keys.
|
||||
// FIXME(eddyb) replace by making `Table` behave like `IndexVec`,
|
||||
// and by using `newtype_index!` to define `DefIndex`.
|
||||
crate struct PerDefTable<T>(Table<T>) where Option<T>: FixedSizeEncoding;
|
||||
|
||||
impl<T> Default for PerDefTable<T> where Option<T>: FixedSizeEncoding {
|
||||
fn default() -> Self {
|
||||
PerDefTable(Table::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> PerDefTable<T> where Option<T>: FixedSizeEncoding {
|
||||
crate fn set(&mut self, def_id: DefId, value: T) {
|
||||
assert!(def_id.is_local());
|
||||
self.0.set(def_id.index.index(), value);
|
||||
}
|
||||
|
||||
crate fn encode(&self, buf: &mut Encoder) -> Lazy<Self> {
|
||||
let lazy = self.0.encode(buf);
|
||||
Lazy::from_position_and_meta(lazy.position, lazy.meta)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> LazyMeta for PerDefTable<T> where Option<T>: FixedSizeEncoding {
|
||||
type Meta = <Table<T> as LazyMeta>::Meta;
|
||||
|
||||
fn min_size(meta: Self::Meta) -> usize {
|
||||
Table::<T>::min_size(meta)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Lazy<PerDefTable<T>> where Option<T>: FixedSizeEncoding {
|
||||
fn as_table(&self) -> Lazy<Table<T>> {
|
||||
Lazy::from_position_and_meta(self.position, self.meta)
|
||||
}
|
||||
|
||||
/// Given the metadata, extract out the value at a particular DefIndex (if any).
|
||||
#[inline(never)]
|
||||
crate fn get<'a, 'tcx, M: Metadata<'a, 'tcx>>(
|
||||
&self,
|
||||
metadata: M,
|
||||
def_index: DefIndex,
|
||||
) -> Option<T> {
|
||||
self.as_table().get(metadata, def_index.index())
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue