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:
bors 2019-10-17 10:45:09 +00:00
commit ea45150837
6 changed files with 855 additions and 874 deletions

View File

@ -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

View File

@ -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))
}
}
}

View File

@ -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;

View File

@ -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)]

View File

@ -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())
}
}