1
Fork 0

rustc_metadata: Refactor lazy table reading/writing

Change wording from "nullable" to "default".
Introduce a trait `IsDefault` for detecting values that are encoded as zeros or not encoded at all.
Add panics to impossible cases.
Some other minor cleanups.
This commit is contained in:
Vadim Petrochenkov 2023-01-26 18:23:14 +04:00
parent 7f97aeaf73
commit 8cc5aa561c
3 changed files with 127 additions and 90 deletions

View file

@ -365,26 +365,26 @@ impl<'a, 'tcx> TyEncoder for EncodeContext<'a, 'tcx> {
} }
} }
// Shorthand for `$self.$tables.$table.set($def_id.index, $self.lazy_value($value))`, which would // Shorthand for `$self.$tables.$table.set_some($def_id.index, $self.lazy_value($value))`, which would
// normally need extra variables to avoid errors about multiple mutable borrows. // normally need extra variables to avoid errors about multiple mutable borrows.
macro_rules! record { macro_rules! record {
($self:ident.$tables:ident.$table:ident[$def_id:expr] <- $value:expr) => {{ ($self:ident.$tables:ident.$table:ident[$def_id:expr] <- $value:expr) => {{
{ {
let value = $value; let value = $value;
let lazy = $self.lazy(value); let lazy = $self.lazy(value);
$self.$tables.$table.set($def_id.index, lazy); $self.$tables.$table.set_some($def_id.index, lazy);
} }
}}; }};
} }
// Shorthand for `$self.$tables.$table.set($def_id.index, $self.lazy_value($value))`, which would // Shorthand for `$self.$tables.$table.set_some($def_id.index, $self.lazy_value($value))`, which would
// normally need extra variables to avoid errors about multiple mutable borrows. // normally need extra variables to avoid errors about multiple mutable borrows.
macro_rules! record_array { macro_rules! record_array {
($self:ident.$tables:ident.$table:ident[$def_id:expr] <- $value:expr) => {{ ($self:ident.$tables:ident.$table:ident[$def_id:expr] <- $value:expr) => {{
{ {
let value = $value; let value = $value;
let lazy = $self.lazy_array(value); let lazy = $self.lazy_array(value);
$self.$tables.$table.set($def_id.index, lazy); $self.$tables.$table.set_some($def_id.index, lazy);
} }
}}; }};
} }
@ -467,14 +467,14 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
{ {
let def_key = self.lazy(table.def_key(def_index)); let def_key = self.lazy(table.def_key(def_index));
let def_path_hash = table.def_path_hash(def_index); let def_path_hash = table.def_path_hash(def_index);
self.tables.def_keys.set(def_index, def_key); self.tables.def_keys.set_some(def_index, def_key);
self.tables.def_path_hashes.set(def_index, def_path_hash); self.tables.def_path_hashes.set_some(def_index, def_path_hash);
} }
} else { } else {
for (def_index, def_key, def_path_hash) in table.enumerated_keys_and_path_hashes() { for (def_index, def_key, def_path_hash) in table.enumerated_keys_and_path_hashes() {
let def_key = self.lazy(def_key); let def_key = self.lazy(def_key);
self.tables.def_keys.set(def_index, def_key); self.tables.def_keys.set_some(def_index, def_key);
self.tables.def_path_hashes.set(def_index, *def_path_hash); self.tables.def_path_hashes.set_some(def_index, *def_path_hash);
} }
} }
} }
@ -548,7 +548,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
let on_disk_index: u32 = let on_disk_index: u32 =
on_disk_index.try_into().expect("cannot export more than U32_MAX files"); on_disk_index.try_into().expect("cannot export more than U32_MAX files");
adapted.set(on_disk_index, self.lazy(source_file)); adapted.set_some(on_disk_index, self.lazy(source_file));
} }
adapted.encode(&mut self.opaque) adapted.encode(&mut self.opaque)
@ -1147,9 +1147,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
if state.is_doc_hidden { if state.is_doc_hidden {
attr_flags |= AttrFlags::IS_DOC_HIDDEN; attr_flags |= AttrFlags::IS_DOC_HIDDEN;
} }
if !attr_flags.is_empty() { self.tables.attr_flags.set(def_id.local_def_index, attr_flags);
self.tables.attr_flags.set_nullable(def_id.local_def_index, attr_flags);
}
} }
fn encode_def_ids(&mut self) { fn encode_def_ids(&mut self) {
@ -1161,7 +1159,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
let def_id = local_id.to_def_id(); let def_id = local_id.to_def_id();
let def_kind = tcx.opt_def_kind(local_id); let def_kind = tcx.opt_def_kind(local_id);
let Some(def_kind) = def_kind else { continue }; let Some(def_kind) = def_kind else { continue };
self.tables.opt_def_kind.set(def_id.index, def_kind); self.tables.opt_def_kind.set_some(def_id.index, def_kind);
let def_span = tcx.def_span(local_id); let def_span = tcx.def_span(local_id);
record!(self.tables.def_span[def_id] <- def_span); record!(self.tables.def_span[def_id] <- def_span);
self.encode_attrs(local_id); self.encode_attrs(local_id);
@ -1264,14 +1262,14 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
}; };
record!(self.tables.variant_data[variant.def_id] <- data); record!(self.tables.variant_data[variant.def_id] <- data);
self.tables.constness.set(variant.def_id.index, hir::Constness::Const); self.tables.constness.set_some(variant.def_id.index, hir::Constness::Const);
record_array!(self.tables.children[variant.def_id] <- variant.fields.iter().map(|f| { record_array!(self.tables.children[variant.def_id] <- variant.fields.iter().map(|f| {
assert!(f.did.is_local()); assert!(f.did.is_local());
f.did.index f.did.index
})); }));
if let Some((CtorKind::Fn, ctor_def_id)) = variant.ctor { if let Some((CtorKind::Fn, ctor_def_id)) = variant.ctor {
self.tables.constness.set(ctor_def_id.index, hir::Constness::Const); self.tables.constness.set_some(ctor_def_id.index, hir::Constness::Const);
let fn_sig = tcx.fn_sig(ctor_def_id); let fn_sig = tcx.fn_sig(ctor_def_id);
record!(self.tables.fn_sig[ctor_def_id] <- fn_sig); record!(self.tables.fn_sig[ctor_def_id] <- fn_sig);
// FIXME only encode signature for ctor_def_id // FIXME only encode signature for ctor_def_id
@ -1342,16 +1340,16 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
let tcx = self.tcx; let tcx = self.tcx;
let impl_defaultness = tcx.impl_defaultness(def_id.expect_local()); let impl_defaultness = tcx.impl_defaultness(def_id.expect_local());
self.tables.impl_defaultness.set(def_id.index, impl_defaultness); self.tables.impl_defaultness.set_some(def_id.index, impl_defaultness);
let trait_item = tcx.associated_item(def_id); let trait_item = tcx.associated_item(def_id);
self.tables.assoc_container.set(def_id.index, trait_item.container); self.tables.assoc_container.set_some(def_id.index, trait_item.container);
match trait_item.kind { match trait_item.kind {
ty::AssocKind::Const => {} ty::AssocKind::Const => {}
ty::AssocKind::Fn => { ty::AssocKind::Fn => {
record_array!(self.tables.fn_arg_names[def_id] <- tcx.fn_arg_names(def_id)); record_array!(self.tables.fn_arg_names[def_id] <- tcx.fn_arg_names(def_id));
self.tables.asyncness.set(def_id.index, tcx.asyncness(def_id)); self.tables.asyncness.set_some(def_id.index, tcx.asyncness(def_id));
self.tables.constness.set(def_id.index, hir::Constness::NotConst); self.tables.constness.set_some(def_id.index, hir::Constness::NotConst);
} }
ty::AssocKind::Type => { ty::AssocKind::Type => {
self.encode_explicit_item_bounds(def_id); self.encode_explicit_item_bounds(def_id);
@ -1367,14 +1365,14 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
let tcx = self.tcx; let tcx = self.tcx;
let ast_item = self.tcx.hir().expect_impl_item(def_id.expect_local()); let ast_item = self.tcx.hir().expect_impl_item(def_id.expect_local());
self.tables.impl_defaultness.set(def_id.index, ast_item.defaultness); self.tables.impl_defaultness.set_some(def_id.index, ast_item.defaultness);
let impl_item = self.tcx.associated_item(def_id); let impl_item = self.tcx.associated_item(def_id);
self.tables.assoc_container.set(def_id.index, impl_item.container); self.tables.assoc_container.set_some(def_id.index, impl_item.container);
match impl_item.kind { match impl_item.kind {
ty::AssocKind::Fn => { ty::AssocKind::Fn => {
let hir::ImplItemKind::Fn(ref sig, body) = ast_item.kind else { bug!() }; let hir::ImplItemKind::Fn(ref sig, body) = ast_item.kind else { bug!() };
self.tables.asyncness.set(def_id.index, sig.header.asyncness); self.tables.asyncness.set_some(def_id.index, sig.header.asyncness);
record_array!(self.tables.fn_arg_names[def_id] <- self.tcx.hir().body_param_names(body)); record_array!(self.tables.fn_arg_names[def_id] <- self.tcx.hir().body_param_names(body));
// Can be inside `impl const Trait`, so using sig.header.constness is not reliable // Can be inside `impl const Trait`, so using sig.header.constness is not reliable
let constness = if self.tcx.is_const_fn_raw(def_id) { let constness = if self.tcx.is_const_fn_raw(def_id) {
@ -1382,18 +1380,16 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
} else { } else {
hir::Constness::NotConst hir::Constness::NotConst
}; };
self.tables.constness.set(def_id.index, constness); self.tables.constness.set_some(def_id.index, constness);
} }
ty::AssocKind::Const | ty::AssocKind::Type => {} ty::AssocKind::Const | ty::AssocKind::Type => {}
} }
if let Some(trait_item_def_id) = impl_item.trait_item_def_id { if let Some(trait_item_def_id) = impl_item.trait_item_def_id {
self.tables.trait_item_def_id.set(def_id.index, trait_item_def_id.into()); self.tables.trait_item_def_id.set_some(def_id.index, trait_item_def_id.into());
} }
if impl_item.kind == ty::AssocKind::Fn { if impl_item.kind == ty::AssocKind::Fn {
record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id)); record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id));
if tcx.is_intrinsic(def_id) { self.tables.is_intrinsic.set(def_id.index, tcx.is_intrinsic(def_id));
self.tables.is_intrinsic.set_nullable(def_id.index, true);
}
} }
} }
@ -1522,14 +1518,12 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
match item.kind { match item.kind {
hir::ItemKind::Fn(ref sig, .., body) => { hir::ItemKind::Fn(ref sig, .., body) => {
self.tables.asyncness.set(def_id.index, sig.header.asyncness); self.tables.asyncness.set_some(def_id.index, sig.header.asyncness);
record_array!(self.tables.fn_arg_names[def_id] <- self.tcx.hir().body_param_names(body)); record_array!(self.tables.fn_arg_names[def_id] <- self.tcx.hir().body_param_names(body));
self.tables.constness.set(def_id.index, sig.header.constness); self.tables.constness.set_some(def_id.index, sig.header.constness);
} }
hir::ItemKind::Macro(ref macro_def, _) => { hir::ItemKind::Macro(ref macro_def, _) => {
if macro_def.macro_rules { self.tables.is_macro_rules.set(def_id.index, macro_def.macro_rules);
self.tables.is_macro_rules.set_nullable(def_id.index, true);
}
record!(self.tables.macro_definition[def_id] <- &*macro_def.body); record!(self.tables.macro_definition[def_id] <- &*macro_def.body);
} }
hir::ItemKind::Mod(ref m) => { hir::ItemKind::Mod(ref m) => {
@ -1537,20 +1531,20 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
} }
hir::ItemKind::OpaqueTy(ref opaque) => { hir::ItemKind::OpaqueTy(ref opaque) => {
self.encode_explicit_item_bounds(def_id); self.encode_explicit_item_bounds(def_id);
if matches!(opaque.origin, hir::OpaqueTyOrigin::TyAlias) { self.tables
self.tables.is_type_alias_impl_trait.set_nullable(def_id.index, true); .is_type_alias_impl_trait
} .set(def_id.index, matches!(opaque.origin, hir::OpaqueTyOrigin::TyAlias));
} }
hir::ItemKind::Impl(hir::Impl { defaultness, constness, .. }) => { hir::ItemKind::Impl(hir::Impl { defaultness, constness, .. }) => {
self.tables.impl_defaultness.set(def_id.index, *defaultness); self.tables.impl_defaultness.set_some(def_id.index, *defaultness);
self.tables.constness.set(def_id.index, *constness); self.tables.constness.set_some(def_id.index, *constness);
let trait_ref = self.tcx.impl_trait_ref(def_id).map(ty::EarlyBinder::skip_binder); let trait_ref = self.tcx.impl_trait_ref(def_id).map(ty::EarlyBinder::skip_binder);
if let Some(trait_ref) = trait_ref { if let Some(trait_ref) = trait_ref {
let trait_def = self.tcx.trait_def(trait_ref.def_id); let trait_def = self.tcx.trait_def(trait_ref.def_id);
if let Ok(mut an) = trait_def.ancestors(self.tcx, def_id) { if let Ok(mut an) = trait_def.ancestors(self.tcx, def_id) {
if let Some(specialization_graph::Node::Impl(parent)) = an.nth(1) { if let Some(specialization_graph::Node::Impl(parent)) = an.nth(1) {
self.tables.impl_parent.set(def_id.index, parent.into()); self.tables.impl_parent.set_some(def_id.index, parent.into());
} }
} }
@ -1564,7 +1558,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
} }
let polarity = self.tcx.impl_polarity(def_id); let polarity = self.tcx.impl_polarity(def_id);
self.tables.impl_polarity.set(def_id.index, polarity); self.tables.impl_polarity.set_some(def_id.index, polarity);
} }
hir::ItemKind::Trait(..) => { hir::ItemKind::Trait(..) => {
let trait_def = self.tcx.trait_def(def_id); let trait_def = self.tcx.trait_def(def_id);
@ -1601,9 +1595,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
} }
if let hir::ItemKind::Fn(..) = item.kind { if let hir::ItemKind::Fn(..) = item.kind {
record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id)); record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id));
if tcx.is_intrinsic(def_id) { self.tables.is_intrinsic.set(def_id.index, tcx.is_intrinsic(def_id));
self.tables.is_intrinsic.set_nullable(def_id.index, true);
}
} }
if let hir::ItemKind::Impl { .. } = item.kind { if let hir::ItemKind::Impl { .. } = item.kind {
if let Some(trait_ref) = self.tcx.impl_trait_ref(def_id) { if let Some(trait_ref) = self.tcx.impl_trait_ref(def_id) {
@ -1650,7 +1642,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
ty::Closure(_, substs) => { ty::Closure(_, substs) => {
let constness = self.tcx.constness(def_id.to_def_id()); let constness = self.tcx.constness(def_id.to_def_id());
self.tables.constness.set(def_id.to_def_id().index, constness); self.tables.constness.set_some(def_id.to_def_id().index, constness);
record!(self.tables.fn_sig[def_id.to_def_id()] <- ty::EarlyBinder(substs.as_closure().sig())); record!(self.tables.fn_sig[def_id.to_def_id()] <- ty::EarlyBinder(substs.as_closure().sig()));
} }
@ -1678,12 +1670,12 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
self.hygiene_ctxt.encode( self.hygiene_ctxt.encode(
&mut (&mut *self, &mut syntax_contexts, &mut expn_data_table, &mut expn_hash_table), &mut (&mut *self, &mut syntax_contexts, &mut expn_data_table, &mut expn_hash_table),
|(this, syntax_contexts, _, _), index, ctxt_data| { |(this, syntax_contexts, _, _), index, ctxt_data| {
syntax_contexts.set(index, this.lazy(ctxt_data)); syntax_contexts.set_some(index, this.lazy(ctxt_data));
}, },
|(this, _, expn_data_table, expn_hash_table), index, expn_data, hash| { |(this, _, expn_data_table, expn_hash_table), index, expn_data, hash| {
if let Some(index) = index.as_local() { if let Some(index) = index.as_local() {
expn_data_table.set(index.as_raw(), this.lazy(expn_data)); expn_data_table.set_some(index.as_raw(), this.lazy(expn_data));
expn_hash_table.set(index.as_raw(), this.lazy(hash)); expn_hash_table.set_some(index.as_raw(), this.lazy(hash));
} }
}, },
); );
@ -1708,10 +1700,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
let spans = self.tcx.sess.parse_sess.proc_macro_quoted_spans(); let spans = self.tcx.sess.parse_sess.proc_macro_quoted_spans();
for (i, span) in spans.into_iter().enumerate() { for (i, span) in spans.into_iter().enumerate() {
let span = self.lazy(span); let span = self.lazy(span);
self.tables.proc_macro_quoted_spans.set(i, span); self.tables.proc_macro_quoted_spans.set_some(i, span);
} }
self.tables.opt_def_kind.set(LOCAL_CRATE.as_def_id().index, DefKind::Mod); self.tables.opt_def_kind.set_some(LOCAL_CRATE.as_def_id().index, DefKind::Mod);
record!(self.tables.def_span[LOCAL_CRATE.as_def_id()] <- tcx.def_span(LOCAL_CRATE.as_def_id())); record!(self.tables.def_span[LOCAL_CRATE.as_def_id()] <- tcx.def_span(LOCAL_CRATE.as_def_id()));
self.encode_attrs(LOCAL_CRATE.as_def_id().expect_local()); self.encode_attrs(LOCAL_CRATE.as_def_id().expect_local());
let vis = tcx.local_visibility(CRATE_DEF_ID).map_id(|def_id| def_id.local_def_index); let vis = tcx.local_visibility(CRATE_DEF_ID).map_id(|def_id| def_id.local_def_index);
@ -1753,8 +1745,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
def_key.disambiguated_data.data = DefPathData::MacroNs(name); def_key.disambiguated_data.data = DefPathData::MacroNs(name);
let def_id = id.to_def_id(); let def_id = id.to_def_id();
self.tables.opt_def_kind.set(def_id.index, DefKind::Macro(macro_kind)); self.tables.opt_def_kind.set_some(def_id.index, DefKind::Macro(macro_kind));
self.tables.proc_macro.set(def_id.index, macro_kind); self.tables.proc_macro.set_some(def_id.index, macro_kind);
self.encode_attrs(id); self.encode_attrs(id);
record!(self.tables.def_keys[def_id] <- def_key); record!(self.tables.def_keys[def_id] <- def_key);
record!(self.tables.def_ident_span[def_id] <- span); record!(self.tables.def_ident_span[def_id] <- span);
@ -1979,22 +1971,20 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
match nitem.kind { match nitem.kind {
hir::ForeignItemKind::Fn(_, ref names, _) => { hir::ForeignItemKind::Fn(_, ref names, _) => {
self.tables.asyncness.set(def_id.index, hir::IsAsync::NotAsync); self.tables.asyncness.set_some(def_id.index, hir::IsAsync::NotAsync);
record_array!(self.tables.fn_arg_names[def_id] <- *names); record_array!(self.tables.fn_arg_names[def_id] <- *names);
let constness = if self.tcx.is_const_fn_raw(def_id) { let constness = if self.tcx.is_const_fn_raw(def_id) {
hir::Constness::Const hir::Constness::Const
} else { } else {
hir::Constness::NotConst hir::Constness::NotConst
}; };
self.tables.constness.set(def_id.index, constness); self.tables.constness.set_some(def_id.index, constness);
record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id)); record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id));
} }
hir::ForeignItemKind::Static(..) | hir::ForeignItemKind::Type => {} hir::ForeignItemKind::Static(..) | hir::ForeignItemKind::Type => {}
} }
if let hir::ForeignItemKind::Fn(..) = nitem.kind { if let hir::ForeignItemKind::Fn(..) = nitem.kind {
if tcx.is_intrinsic(def_id) { self.tables.is_intrinsic.set(def_id.index, tcx.is_intrinsic(def_id));
self.tables.is_intrinsic.set_nullable(def_id.index, true);
}
} }
} }
} }

View file

@ -316,7 +316,7 @@ pub(crate) struct IncoherentImpls {
/// Define `LazyTables` and `TableBuilders` at the same time. /// Define `LazyTables` and `TableBuilders` at the same time.
macro_rules! define_tables { macro_rules! define_tables {
( (
- nullable: $($name1:ident: Table<$IDX1:ty, $T1:ty>,)+ - defaulted: $($name1:ident: Table<$IDX1:ty, $T1:ty>,)+
- optional: $($name2:ident: Table<$IDX2:ty, $T2:ty>,)+ - optional: $($name2:ident: Table<$IDX2:ty, $T2:ty>,)+
) => { ) => {
#[derive(MetadataEncodable, MetadataDecodable)] #[derive(MetadataEncodable, MetadataDecodable)]
@ -343,7 +343,7 @@ macro_rules! define_tables {
} }
define_tables! { define_tables! {
- nullable: - defaulted:
is_intrinsic: Table<DefIndex, bool>, is_intrinsic: Table<DefIndex, bool>,
is_macro_rules: Table<DefIndex, bool>, is_macro_rules: Table<DefIndex, bool>,
is_type_alias_impl_trait: Table<DefIndex, bool>, is_type_alias_impl_trait: Table<DefIndex, bool>,

View file

@ -10,11 +10,39 @@ use rustc_span::hygiene::MacroKind;
use std::marker::PhantomData; use std::marker::PhantomData;
use std::num::NonZeroUsize; use std::num::NonZeroUsize;
pub(super) trait IsDefault: Default {
fn is_default(&self) -> bool;
}
impl<T> IsDefault for Option<T> {
fn is_default(&self) -> bool {
self.is_none()
}
}
impl IsDefault for AttrFlags {
fn is_default(&self) -> bool {
self.is_empty()
}
}
impl IsDefault for bool {
fn is_default(&self) -> bool {
!self
}
}
impl IsDefault for u32 {
fn is_default(&self) -> bool {
*self == 0
}
}
/// Helper trait, for encoding to, and decoding from, a fixed number of bytes. /// Helper trait, for encoding to, and decoding from, a fixed number of bytes.
/// Used mainly for Lazy positions and lengths. /// Used mainly for Lazy positions and lengths.
/// Unchecked invariant: `Self::default()` should encode as `[0; BYTE_LEN]`, /// Unchecked invariant: `Self::default()` should encode as `[0; BYTE_LEN]`,
/// but this has no impact on safety. /// but this has no impact on safety.
pub(super) trait FixedSizeEncoding: Default { pub(super) trait FixedSizeEncoding: IsDefault {
/// This should be `[u8; BYTE_LEN]`; /// This should be `[u8; BYTE_LEN]`;
/// Cannot use an associated `const BYTE_LEN: usize` instead due to const eval limitations. /// Cannot use an associated `const BYTE_LEN: usize` instead due to const eval limitations.
type ByteArray; type ByteArray;
@ -23,6 +51,8 @@ pub(super) trait FixedSizeEncoding: Default {
fn write_to_bytes(self, b: &mut Self::ByteArray); fn write_to_bytes(self, b: &mut Self::ByteArray);
} }
/// This implementation is not used generically, but for reading/writing
/// concrete `u32` fields in `Lazy*` structures, which may be zero.
impl FixedSizeEncoding for u32 { impl FixedSizeEncoding for u32 {
type ByteArray = [u8; 4]; type ByteArray = [u8; 4];
@ -58,7 +88,7 @@ macro_rules! fixed_size_enum {
fn write_to_bytes(self, b: &mut [u8;1]) { fn write_to_bytes(self, b: &mut [u8;1]) {
use $ty::*; use $ty::*;
b[0] = match self { b[0] = match self {
None => 0, None => unreachable!(),
$(Some($($pat)*) => 1 + ${index()},)* $(Some($($pat)*) => 1 + ${index()},)*
} }
} }
@ -160,15 +190,16 @@ impl FixedSizeEncoding for Option<DefPathHash> {
#[inline] #[inline]
fn from_bytes(b: &[u8; 16]) -> Self { fn from_bytes(b: &[u8; 16]) -> Self {
// NOTE: There's a collision between `None` and `Some(0)`.
Some(DefPathHash(Fingerprint::from_le_bytes(*b))) Some(DefPathHash(Fingerprint::from_le_bytes(*b)))
} }
#[inline] #[inline]
fn write_to_bytes(self, b: &mut [u8; 16]) { fn write_to_bytes(self, b: &mut [u8; 16]) {
let Some(DefPathHash(fingerprint)) = self else { match self {
panic!("Trying to encode absent DefPathHash.") None => unreachable!(),
}; Some(DefPathHash(fingerprint)) => *b = fingerprint.to_le_bytes(),
*b = fingerprint.to_le_bytes(); }
} }
} }
@ -179,17 +210,17 @@ impl FixedSizeEncoding for Option<RawDefId> {
#[inline] #[inline]
fn from_bytes(b: &[u8; 8]) -> Self { fn from_bytes(b: &[u8; 8]) -> Self {
let krate = u32::from_le_bytes(b[0..4].try_into().unwrap()); let krate = u32::from_le_bytes(b[0..4].try_into().unwrap());
let index = u32::from_le_bytes(b[4..8].try_into().unwrap());
if krate == 0 { if krate == 0 {
return None; return None;
} }
let index = u32::from_le_bytes(b[4..8].try_into().unwrap());
Some(RawDefId { krate: krate - 1, index }) Some(RawDefId { krate: krate - 1, index })
} }
#[inline] #[inline]
fn write_to_bytes(self, b: &mut [u8; 8]) { fn write_to_bytes(self, b: &mut [u8; 8]) {
match self { match self {
None => *b = [0; 8], None => unreachable!(),
Some(RawDefId { krate, index }) => { Some(RawDefId { krate, index }) => {
// CrateNum is less than `CrateNum::MAX_AS_U32`. // CrateNum is less than `CrateNum::MAX_AS_U32`.
debug_assert!(krate < u32::MAX); debug_assert!(krate < u32::MAX);
@ -210,6 +241,7 @@ impl FixedSizeEncoding for AttrFlags {
#[inline] #[inline]
fn write_to_bytes(self, b: &mut [u8; 1]) { fn write_to_bytes(self, b: &mut [u8; 1]) {
debug_assert!(!self.is_default());
b[0] = self.bits(); b[0] = self.bits();
} }
} }
@ -224,6 +256,7 @@ impl FixedSizeEncoding for bool {
#[inline] #[inline]
fn write_to_bytes(self, b: &mut [u8; 1]) { fn write_to_bytes(self, b: &mut [u8; 1]) {
debug_assert!(!self.is_default());
b[0] = self as u8 b[0] = self as u8
} }
} }
@ -242,9 +275,14 @@ impl<T> FixedSizeEncoding for Option<LazyValue<T>> {
#[inline] #[inline]
fn write_to_bytes(self, b: &mut [u8; 4]) { fn write_to_bytes(self, b: &mut [u8; 4]) {
let position = self.map_or(0, |lazy| lazy.position.get()); match self {
let position: u32 = position.try_into().unwrap(); None => unreachable!(),
position.write_to_bytes(b) Some(lazy) => {
let position = lazy.position.get();
let position: u32 = position.try_into().unwrap();
position.write_to_bytes(b)
}
}
} }
} }
@ -253,7 +291,7 @@ impl<T> FixedSizeEncoding for Option<LazyArray<T>> {
#[inline] #[inline]
fn from_bytes(b: &[u8; 8]) -> Self { fn from_bytes(b: &[u8; 8]) -> Self {
let ([ref position_bytes, ref meta_bytes],[])= b.as_chunks::<4>() else { panic!() }; let ([position_bytes, meta_bytes],[])= b.as_chunks::<4>() else { panic!() };
let position = NonZeroUsize::new(u32::from_bytes(position_bytes) as usize)?; let position = NonZeroUsize::new(u32::from_bytes(position_bytes) as usize)?;
let len = u32::from_bytes(meta_bytes) as usize; let len = u32::from_bytes(meta_bytes) as usize;
Some(LazyArray::from_position_and_num_elems(position, len)) Some(LazyArray::from_position_and_num_elems(position, len))
@ -261,15 +299,20 @@ impl<T> FixedSizeEncoding for Option<LazyArray<T>> {
#[inline] #[inline]
fn write_to_bytes(self, b: &mut [u8; 8]) { fn write_to_bytes(self, b: &mut [u8; 8]) {
let ([ref mut position_bytes, ref mut meta_bytes],[])= b.as_chunks_mut::<4>() else { panic!() }; match self {
None => unreachable!(),
Some(lazy) => {
let ([position_bytes, meta_bytes],[])= b.as_chunks_mut::<4>() else { panic!() };
let position = self.map_or(0, |lazy| lazy.position.get()); let position = lazy.position.get();
let position: u32 = position.try_into().unwrap(); let position: u32 = position.try_into().unwrap();
position.write_to_bytes(position_bytes); position.write_to_bytes(position_bytes);
let len = self.map_or(0, |lazy| lazy.num_elems); let len = lazy.num_elems;
let len: u32 = len.try_into().unwrap(); let len: u32 = len.try_into().unwrap();
len.write_to_bytes(meta_bytes); len.write_to_bytes(meta_bytes);
}
}
} }
} }
@ -289,20 +332,27 @@ impl<I: Idx, const N: usize, T> TableBuilder<I, Option<T>>
where where
Option<T>: FixedSizeEncoding<ByteArray = [u8; N]>, Option<T>: FixedSizeEncoding<ByteArray = [u8; N]>,
{ {
pub(crate) fn set(&mut self, i: I, value: T) { pub(crate) fn set_some(&mut self, i: I, value: T) {
self.set_nullable(i, Some(value)) self.set(i, Some(value))
} }
} }
impl<I: Idx, const N: usize, T: FixedSizeEncoding<ByteArray = [u8; N]>> TableBuilder<I, T> { impl<I: Idx, const N: usize, T: FixedSizeEncoding<ByteArray = [u8; N]>> TableBuilder<I, T> {
pub(crate) fn set_nullable(&mut self, i: I, value: T) { /// Sets the table value if it is not default.
// FIXME(eddyb) investigate more compact encodings for sparse tables. /// ATTENTION: For optimization default values are simply ignored by this function, because
// On the PR @michaelwoerister mentioned: /// right now metadata tables never need to reset non-default values to default. If such need
// > Space requirements could perhaps be optimized by using the HAMT `popcnt` /// arises in the future then a new method (e.g. `clear` or `reset`) will need to be introduced
// > trick (i.e. divide things into buckets of 32 or 64 items and then /// for doing that explicitly.
// > store bit-masks of which item in each bucket is actually serialized). pub(crate) fn set(&mut self, i: I, value: T) {
self.blocks.ensure_contains_elem(i, || [0; N]); if !value.is_default() {
value.write_to_bytes(&mut self.blocks[i]); // 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).
self.blocks.ensure_contains_elem(i, || [0; N]);
value.write_to_bytes(&mut self.blocks[i]);
}
} }
pub(crate) fn encode(&self, buf: &mut FileEncoder) -> LazyTable<I, T> { pub(crate) fn encode(&self, buf: &mut FileEncoder) -> LazyTable<I, T> {
@ -331,10 +381,7 @@ where
let start = self.position.get(); let start = self.position.get();
let bytes = &metadata.blob()[start..start + self.encoded_size]; let bytes = &metadata.blob()[start..start + self.encoded_size];
let (bytes, []) = bytes.as_chunks::<N>() else { panic!() }; let (bytes, []) = bytes.as_chunks::<N>() else { panic!() };
match bytes.get(i.index()) { bytes.get(i.index()).map_or_else(Default::default, FixedSizeEncoding::from_bytes)
Some(bytes) => FixedSizeEncoding::from_bytes(bytes),
None => FixedSizeEncoding::from_bytes(&[0; N]),
}
} }
/// Size of the table in entries, including possible gaps. /// Size of the table in entries, including possible gaps.