about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEduard-Mihai Burtescu <edy.burt@gmail.com>2019-04-13 23:30:53 +0300
committerEduard-Mihai Burtescu <edy.burt@gmail.com>2019-10-15 18:23:51 +0300
commitcef495028019b5bbb380bfa1d7a10e9e06dbf166 (patch)
tree90d4903ae2df9c398147d8889f0beb206c721327
parent677f0df63b7f39c3b22a84004c1697e85743c470 (diff)
downloadrust-cef495028019b5bbb380bfa1d7a10e9e06dbf166.tar.gz
rust-cef495028019b5bbb380bfa1d7a10e9e06dbf166.zip
rustc_metadata: generalize Table<T> to hold T, not Lazy<T>, elements.
-rw-r--r--src/librustc_metadata/decoder.rs6
-rw-r--r--src/librustc_metadata/encoder.rs10
-rw-r--r--src/librustc_metadata/schema.rs2
-rw-r--r--src/librustc_metadata/table.rs108
4 files changed, 78 insertions, 48 deletions
diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs
index 7ba395a1bd5..f1ae0487529 100644
--- a/src/librustc_metadata/decoder.rs
+++ b/src/librustc_metadata/decoder.rs
@@ -2,7 +2,7 @@
 
 use crate::cstore::{self, CrateMetadata, MetadataBlob};
 use crate::schema::*;
-use crate::table::PerDefTable;
+use crate::table::{FixedSizeEncoding, PerDefTable};
 
 use rustc_index::vec::IndexVec;
 use rustc_data_structures::sync::{Lrc, ReadGuard};
@@ -256,7 +256,7 @@ impl<'a, 'tcx, T: Encodable> SpecializedDecoder<Lazy<[T]>> for DecodeContext<'a,
 }
 
 impl<'a, 'tcx, T> SpecializedDecoder<Lazy<PerDefTable<T>>> for DecodeContext<'a, 'tcx>
-    where T: LazyMeta<Meta = ()>,
+    where Option<T>: FixedSizeEncoding,
 {
     fn specialized_decode(&mut self) -> Result<Lazy<PerDefTable<T>>, Self::Error> {
         let len = self.read_usize()?;
@@ -481,7 +481,7 @@ impl<'a, 'tcx> CrateMetadata {
     }
 
     fn maybe_entry(&self, item_id: DefIndex) -> Option<Lazy<Entry<'tcx>>> {
-        self.root.per_def.entry.lookup(self.blob.raw_bytes(), item_id)
+        self.root.per_def.entry.get(self.blob.raw_bytes(), item_id)
     }
 
     fn entry(&self, item_id: DefIndex) -> Entry<'tcx> {
diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs
index 51634e372a2..c9426aaece9 100644
--- a/src/librustc_metadata/encoder.rs
+++ b/src/librustc_metadata/encoder.rs
@@ -1,5 +1,5 @@
 use crate::schema::*;
-use crate::table::PerDefTable;
+use crate::table::{FixedSizeEncoding, PerDefTable};
 
 use rustc::middle::cstore::{LinkagePreference, NativeLibrary,
                             EncodedMetadata, ForeignModule};
@@ -61,7 +61,7 @@ struct EncodeContext<'tcx> {
 }
 
 struct PerDefTables<'tcx> {
-    entry: PerDefTable<Entry<'tcx>>,
+    entry: PerDefTable<Lazy<Entry<'tcx>>>,
 }
 
 macro_rules! encoder_methods {
@@ -119,7 +119,7 @@ impl<'tcx, T: Encodable> SpecializedEncoder<Lazy<[T]>> for EncodeContext<'tcx> {
 }
 
 impl<'tcx, T> SpecializedEncoder<Lazy<PerDefTable<T>>> for EncodeContext<'tcx>
-    where T: LazyMeta<Meta = ()>,
+    where Option<T>: FixedSizeEncoding,
 {
     fn specialized_encode(&mut self, lazy: &Lazy<PerDefTable<T>>) -> Result<(), Self::Error> {
         self.emit_usize(lazy.meta)?;
@@ -280,14 +280,14 @@ impl<I, T: Encodable> EncodeContentsForLazy<[T]> for I
     }
 }
 
-// Shorthand for `$self.$tables.$table.record($key, $self.lazy($value))`, which would
+// Shorthand for `$self.$tables.$table.set($key, $self.lazy($value))`, which would
 // normally need extra variables to avoid errors about multiple mutable borrows.
 macro_rules! record {
     ($self:ident.$tables:ident.$table:ident[$key:expr] <- $value:expr) => {{
         {
             let value = $value;
             let lazy = $self.lazy(value);
-            $self.$tables.$table.record($key, lazy);
+            $self.$tables.$table.set($key, lazy);
         }
     }}
 }
diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs
index 9d6748732b8..e70ba2532ca 100644
--- a/src/librustc_metadata/schema.rs
+++ b/src/librustc_metadata/schema.rs
@@ -229,7 +229,7 @@ crate struct TraitImpls {
 
 #[derive(RustcEncodable, RustcDecodable)]
 crate struct LazyPerDefTables<'tcx> {
-    pub entry: Lazy!(PerDefTable<Entry<'tcx>>),
+    pub entry: Lazy!(PerDefTable<Lazy<Entry<'tcx>>>),
 }
 
 #[derive(RustcEncodable, RustcDecodable)]
diff --git a/src/librustc_metadata/table.rs b/src/librustc_metadata/table.rs
index c60c8e2cbce..c069ea2830c 100644
--- a/src/librustc_metadata/table.rs
+++ b/src/librustc_metadata/table.rs
@@ -8,7 +8,10 @@ use std::num::NonZeroUsize;
 use log::debug;
 
 /// Helper trait, for encoding to, and decoding from, a fixed number of bytes.
-trait FixedSizeEncoding {
+/// 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,
@@ -38,7 +41,7 @@ macro_rules! fixed_size_encoding_byte_len_and_defaults {
                     b.len() / BYTE_LEN,
                 )
             };
-            Self::from_bytes(&b[i])
+            FixedSizeEncoding::from_bytes(&b[i])
         }
         fn write_to_bytes_at(self, b: &mut [u8], i: usize) {
             const BYTE_LEN: usize = $byte_len;
@@ -69,37 +72,69 @@ impl FixedSizeEncoding for u32 {
     }
 }
 
-/// Random-access position table, allowing encoding in an arbitrary order
-/// (e.g. while visiting the definitions of a crate), and on-demand decoding
-/// of specific indices (e.g. queries for per-definition data).
-/// Similar to `Vec<Lazy<T>>`, but with zero-copy decoding.
-// FIXME(eddyb) newtype `[u8]` here, such that `Box<Table<T>>` would be used
+// 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, similar to `Vec<Option<T>>`, but without requiring
+/// encoding or decoding all the values eagerly and in-order.
+// 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.
 // Sadly, that doesn't work for `DefPerTable`, which is `(Table<T>, Table<T>)`,
 // and so would need two lengths in its metadata, which is not supported yet.
-crate struct Table<T: LazyMeta<Meta = ()>> {
+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: LazyMeta<Meta = ()>> Table<T> {
+impl<T> Table<T> where Option<T>: FixedSizeEncoding {
     crate fn new(len: usize) -> Self {
         Table {
-            bytes: vec![0; len * 4],
+            // FIXME(eddyb) only allocate and encode as many entries as needed.
+            bytes: vec![0; len * <Option<T>>::BYTE_LEN],
             _marker: PhantomData,
         }
     }
 
-    crate fn record(&mut self, i: usize, entry: Lazy<T>) {
-        let position: u32 = entry.position.get().try_into().unwrap();
-
-        assert!(u32::read_from_bytes_at(&self.bytes, i) == 0,
-                "recorded position for index {:?} twice, first at {:?} and now at {:?}",
-                i,
-                u32::read_from_bytes_at(&self.bytes, i),
-                position);
-
-        position.write_to_bytes_at(&mut self.bytes, i)
+    crate fn set(&mut self, i: usize, value: T) {
+        Some(value).write_to_bytes_at(&mut self.bytes, i);
     }
 
     crate fn encode(&self, buf: &mut Encoder) -> Lazy<Self> {
@@ -112,7 +147,7 @@ impl<T: LazyMeta<Meta = ()>> Table<T> {
     }
 }
 
-impl<T: LazyMeta<Meta = ()>> LazyMeta for Table<T> {
+impl<T> LazyMeta for Table<T> where Option<T>: FixedSizeEncoding {
     type Meta = usize;
 
     fn min_size(len: usize) -> usize {
@@ -120,34 +155,29 @@ impl<T: LazyMeta<Meta = ()>> LazyMeta for Table<T> {
     }
 }
 
-impl<T: Encodable> Lazy<Table<T>> {
-    /// Given the metadata, extract out the offset of a particular index (if any).
+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 lookup(&self, bytes: &[u8], i: usize) -> Option<Lazy<T>> {
+    crate fn get(&self, bytes: &[u8], i: usize) -> Option<T> {
         debug!("Table::lookup: index={:?} len={:?}", i, self.meta);
 
-        let bytes = &bytes[self.position.get()..][..self.meta];
-        let position = u32::read_from_bytes_at(bytes, i);
-        debug!("Table::lookup: position={:?}", position);
-
-        NonZeroUsize::new(position as usize).map(Lazy::from_position)
+        <Option<T>>::read_from_bytes_at(&bytes[self.position.get()..][..self.meta], i)
     }
 }
 
-
 /// Per-definition table, similar to `Table` but keyed on `DefIndex`.
 // FIXME(eddyb) replace by making `Table` behave like `IndexVec`,
 // and by using `newtype_index!` to define `DefIndex`.
-crate struct PerDefTable<T: LazyMeta<Meta = ()>>(Table<T>);
+crate struct PerDefTable<T>(Table<T>) where Option<T>: FixedSizeEncoding;
 
-impl<T: LazyMeta<Meta = ()>> PerDefTable<T> {
+impl<T> PerDefTable<T> where Option<T>: FixedSizeEncoding {
     crate fn new(def_index_count: usize) -> Self {
         PerDefTable(Table::new(def_index_count))
     }
 
-    crate fn record(&mut self, def_id: DefId, entry: Lazy<T>) {
+    crate fn set(&mut self, def_id: DefId, value: T) {
         assert!(def_id.is_local());
-        self.0.record(def_id.index.index(), entry);
+        self.0.set(def_id.index.index(), value);
     }
 
     crate fn encode(&self, buf: &mut Encoder) -> Lazy<Self> {
@@ -156,7 +186,7 @@ impl<T: LazyMeta<Meta = ()>> PerDefTable<T> {
     }
 }
 
-impl<T: LazyMeta<Meta = ()>> LazyMeta for PerDefTable<T> {
+impl<T> LazyMeta for PerDefTable<T> where Option<T>: FixedSizeEncoding {
     type Meta = <Table<T> as LazyMeta>::Meta;
 
     fn min_size(meta: Self::Meta) -> usize {
@@ -164,14 +194,14 @@ impl<T: LazyMeta<Meta = ()>> LazyMeta for PerDefTable<T> {
     }
 }
 
-impl<T: Encodable> Lazy<PerDefTable<T>> {
+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 offset of a particular DefIndex (if any).
+    /// Given the metadata, extract out the value at a particular DefIndex (if any).
     #[inline(never)]
-    crate fn lookup(&self, bytes: &[u8], def_index: DefIndex) -> Option<Lazy<T>> {
-        self.as_table().lookup(bytes, def_index.index())
+    crate fn get(&self, bytes: &[u8], def_index: DefIndex) -> Option<T> {
+        self.as_table().get(bytes, def_index.index())
     }
 }