Skip to content

Commit 7a43072

Browse files
committed
rustc_metadata: generalize Table<T> to hold T, not Lazy<T>, elements.
1 parent 1e66a28 commit 7a43072

File tree

4 files changed

+102
-57
lines changed

4 files changed

+102
-57
lines changed

src/librustc_metadata/decoder.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
use crate::cstore::{self, CrateMetadata, MetadataBlob, NativeLibrary, ForeignModule};
44
use crate::schema::*;
5-
use crate::table::PerDefTable;
5+
use crate::table::{FixedSizeEncoding, PerDefTable};
66

77
use rustc_data_structures::sync::{Lrc, ReadGuard};
88
use rustc::hir::map::{DefKey, DefPath, DefPathData, DefPathHash, Definitions};
@@ -255,7 +255,7 @@ impl<'a, 'tcx, T: Encodable> SpecializedDecoder<Lazy<[T]>> for DecodeContext<'a,
255255
}
256256

257257
impl<'a, 'tcx, T> SpecializedDecoder<Lazy<PerDefTable<T>>> for DecodeContext<'a, 'tcx>
258-
where T: LazyMeta<Meta = ()>,
258+
where Option<T>: FixedSizeEncoding,
259259
{
260260
fn specialized_decode(&mut self) -> Result<Lazy<PerDefTable<T>>, Self::Error> {
261261
let lo_hi = [
@@ -498,7 +498,7 @@ impl<'a, 'tcx> CrateMetadata {
498498

499499
fn maybe_entry(&self, item_id: DefIndex) -> Option<Lazy<Entry<'tcx>>> {
500500
assert!(!self.is_proc_macro(item_id));
501-
self.root.per_def.entry.lookup(self.blob.raw_bytes(), item_id)
501+
self.root.per_def.entry.get(self.blob.raw_bytes(), item_id)
502502
}
503503

504504
fn entry(&self, item_id: DefIndex) -> Entry<'tcx> {

src/librustc_metadata/encoder.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::schema::*;
2-
use crate::table::PerDefTable;
2+
use crate::table::{FixedSizeEncoding, PerDefTable};
33

44
use rustc::middle::cstore::{LinkagePreference, NativeLibrary,
55
EncodedMetadata, ForeignModule};
@@ -59,7 +59,7 @@ pub struct EncodeContext<'a, 'tcx: 'a> {
5959
}
6060

6161
struct PerDefTables<'tcx> {
62-
entry: PerDefTable<Entry<'tcx>>,
62+
entry: PerDefTable<Lazy<Entry<'tcx>>>,
6363
}
6464

6565
macro_rules! encoder_methods {
@@ -117,7 +117,7 @@ impl<'a, 'tcx, T: Encodable> SpecializedEncoder<Lazy<[T]>> for EncodeContext<'a,
117117
}
118118

119119
impl<'a, 'tcx, T> SpecializedEncoder<Lazy<PerDefTable<T>>> for EncodeContext<'a, 'tcx>
120-
where T: LazyMeta<Meta = ()>,
120+
where Option<T>: FixedSizeEncoding,
121121
{
122122
fn specialized_encode(&mut self, lazy: &Lazy<PerDefTable<T>>) -> Result<(), Self::Error> {
123123
self.emit_usize(lazy.meta[0])?;
@@ -273,14 +273,14 @@ impl<I, T: Encodable> EncodeContentsForLazy<[T]> for I
273273
}
274274
}
275275

276-
// Shorthand for `$self.$tables.$table.record($key, $self.lazy($value))`, which would
276+
// Shorthand for `$self.$tables.$table.set($key, $self.lazy($value))`, which would
277277
// normally need extra variables to avoid errors about multiple mutable borrows.
278278
macro_rules! record {
279279
($self:ident.$tables:ident[$key:expr]: $($table:ident => $value:expr,)+) => {{
280280
$({
281281
let value = $value;
282282
let lazy = $self.lazy(value);
283-
$self.$tables.$table.record($key, lazy);
283+
$self.$tables.$table.set($key, lazy);
284284
})+
285285
}}
286286
}

src/librustc_metadata/schema.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ pub struct TraitImpls {
220220

221221
#[derive(RustcEncodable, RustcDecodable)]
222222
pub struct LazyPerDefTables<'tcx> {
223-
pub entry: Lazy!(PerDefTable<Entry<'tcx>>),
223+
pub entry: Lazy!(PerDefTable<Lazy<Entry<'tcx>>>),
224224
}
225225

226226
#[derive(RustcEncodable, RustcDecodable)]

src/librustc_metadata/table.rs

Lines changed: 93 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -6,39 +6,98 @@ use std::marker::PhantomData;
66
use std::num::NonZeroUsize;
77
use log::debug;
88

9-
/// Random-access position table, allowing encoding in an arbitrary order
10-
/// (e.g. while visiting the definitions of a crate), and on-demand decoding
11-
/// of specific indices (e.g. queries for per-definition data).
12-
/// Similar to `Vec<Lazy<T>>`, but with zero-copy decoding.
13-
// FIXME(eddyb) newtype `[u8]` here, such that `Box<Table<T>>` would be used
9+
/// Helper trait, for encoding to, and decoding from, a fixed number of bytes.
10+
/// Used mainly for Lazy positions and lengths.
11+
/// Unchecked invariant: `Self::default()` should encode as `[0; BYTE_LEN]`,
12+
/// but this has no impact on safety.
13+
pub trait FixedSizeEncoding: Default {
14+
const BYTE_LEN: usize;
15+
16+
// FIXME(eddyb) convert to and from `[u8; Self::BYTE_LEN]` instead,
17+
// once that starts being allowed by the compiler (i.e. lazy normalization).
18+
fn from_bytes(b: &[u8]) -> Self;
19+
fn write_to_bytes(self, b: &mut [u8]);
20+
}
21+
22+
impl FixedSizeEncoding for u32 {
23+
const BYTE_LEN: usize = 4;
24+
25+
fn from_bytes(b: &[u8]) -> Self {
26+
let mut bytes = [0; Self::BYTE_LEN];
27+
bytes.copy_from_slice(&b[..Self::BYTE_LEN]);
28+
Self::from_le_bytes(bytes)
29+
}
30+
31+
fn write_to_bytes(self, b: &mut [u8]) {
32+
b[..Self::BYTE_LEN].copy_from_slice(&self.to_le_bytes());
33+
}
34+
}
35+
36+
// NOTE(eddyb) there could be an impl for `usize`, which would enable a more
37+
// generic `Lazy<T>` impl, but in the general case we might not need / want to
38+
// fit every `usize` in `u32`.
39+
impl<T: Encodable> FixedSizeEncoding for Option<Lazy<T>> {
40+
const BYTE_LEN: usize = u32::BYTE_LEN;
41+
42+
fn from_bytes(b: &[u8]) -> Self {
43+
Some(Lazy::from_position(NonZeroUsize::new(u32::from_bytes(b) as usize)?))
44+
}
45+
46+
fn write_to_bytes(self, b: &mut [u8]) {
47+
let position = self.map_or(0, |lazy| lazy.position.get());
48+
let position_u32 = position as u32;
49+
assert_eq!(position_u32 as usize, position);
50+
51+
position_u32.write_to_bytes(b)
52+
}
53+
}
54+
55+
impl<T: Encodable> FixedSizeEncoding for Option<Lazy<[T]>> {
56+
const BYTE_LEN: usize = u32::BYTE_LEN * 2;
57+
58+
fn from_bytes(b: &[u8]) -> Self {
59+
Some(Lazy::from_position_and_meta(
60+
<Option<Lazy<T>>>::from_bytes(b)?.position,
61+
u32::from_bytes(&b[u32::BYTE_LEN..]) as usize,
62+
))
63+
}
64+
65+
fn write_to_bytes(self, b: &mut [u8]) {
66+
self.map(|lazy| Lazy::<T>::from_position(lazy.position))
67+
.write_to_bytes(b);
68+
69+
let len = self.map_or(0, |lazy| lazy.meta);
70+
let len_u32 = len as u32;
71+
assert_eq!(len_u32 as usize, len);
72+
73+
len_u32.write_to_bytes(&mut b[u32::BYTE_LEN..]);
74+
}
75+
}
76+
77+
/// Random-access table, similar to `Vec<Option<T>>`, but without requiring
78+
/// encoding or decoding all the values eagerly and in-order.
79+
// FIXME(eddyb) replace `Vec` with `[_]` here, such that `Box<Table<T>>` would be used
1480
// when building it, and `Lazy<Table<T>>` or `&Table<T>` when reading it.
1581
// Sadly, that doesn't work for `DefPerTable`, which is `(Table<T>, Table<T>)`,
1682
// and so would need two lengths in its metadata, which is not supported yet.
17-
pub struct Table<T: LazyMeta<Meta = ()>> {
83+
pub struct Table<T> where Option<T>: FixedSizeEncoding {
84+
// FIXME(eddyb) store `[u8; <Option<T>>::BYTE_LEN]` instead of `u8` in `Vec`,
85+
// once that starts being allowed by the compiler (i.e. lazy normalization).
1886
bytes: Vec<u8>,
1987
_marker: PhantomData<T>,
2088
}
2189

22-
impl<T: LazyMeta<Meta = ()>> Table<T> {
90+
impl<T> Table<T> where Option<T>: FixedSizeEncoding {
2391
pub fn new(len: usize) -> Self {
2492
Table {
25-
bytes: vec![0; len * 4],
93+
// FIXME(eddyb) only allocate and encode as many entries as needed.
94+
bytes: vec![0; len * <Option<T>>::BYTE_LEN],
2695
_marker: PhantomData,
2796
}
2897
}
2998

30-
pub fn record(&mut self, i: usize, entry: Lazy<T>) {
31-
let position = entry.position.get() as u32;
32-
assert_eq!(position as usize, entry.position.get());
33-
34-
let bytes = &mut self.bytes[i * 4..];
35-
assert!(read_le_u32(bytes) == 0,
36-
"recorded position for index {:?} twice, first at {:?} and now at {:?}",
37-
i,
38-
read_le_u32(bytes),
39-
position);
40-
41-
write_le_u32(bytes, position);
99+
pub fn set(&mut self, i: usize, value: T) {
100+
Some(value).write_to_bytes(&mut self.bytes[i * <Option<T>>::BYTE_LEN..]);
42101
}
43102

44103
pub fn encode(&self, buf: &mut Encoder) -> Lazy<Self> {
@@ -51,58 +110,45 @@ impl<T: LazyMeta<Meta = ()>> Table<T> {
51110
}
52111
}
53112

54-
impl<T: LazyMeta<Meta = ()>> LazyMeta for Table<T> {
113+
impl<T> LazyMeta for Table<T> where Option<T>: FixedSizeEncoding {
55114
type Meta = usize;
56115

57116
fn min_size(len: usize) -> usize {
58117
len
59118
}
60119
}
61120

62-
impl<T: Encodable> Lazy<Table<T>> {
63-
/// Given the metadata, extract out the offset of a particular index (if any).
121+
impl<T> Lazy<Table<T>> where Option<T>: FixedSizeEncoding {
122+
/// Given the metadata, extract out the value at a particular index (if any).
64123
#[inline(never)]
65-
pub fn lookup(&self, bytes: &[u8], i: usize) -> Option<Lazy<T>> {
124+
pub fn get(&self, bytes: &[u8], i: usize) -> Option<T> {
66125
debug!("Table::lookup: index={:?} len={:?}", i, self.meta);
67126

68127
let bytes = &bytes[self.position.get()..][..self.meta];
69-
let position = read_le_u32(&bytes[i * 4..]);
70-
debug!("Table::lookup: position={:?}", position);
71-
72-
NonZeroUsize::new(position as usize).map(Lazy::from_position)
128+
<Option<T>>::from_bytes(&bytes[i * <Option<T>>::BYTE_LEN..])
73129
}
74130
}
75131

76-
fn read_le_u32(b: &[u8]) -> u32 {
77-
let mut bytes = [0; 4];
78-
bytes.copy_from_slice(&b[..4]);
79-
u32::from_le_bytes(bytes)
80-
}
81-
82-
fn write_le_u32(b: &mut [u8], x: u32) {
83-
b[..4].copy_from_slice(&x.to_le_bytes());
84-
}
85-
86132
/// Per-definition table, similar to `Table` but keyed on `DefIndex`.
87133
/// Needed because of the two `DefIndexAddressSpace`s a `DefIndex` can be in.
88-
pub struct PerDefTable<T: LazyMeta<Meta = ()>> {
134+
pub struct PerDefTable<T> where Option<T>: FixedSizeEncoding {
89135
lo: Table<T>,
90136
hi: Table<T>,
91137
}
92138

93-
impl<T: LazyMeta<Meta = ()>> PerDefTable<T> {
139+
impl<T> PerDefTable<T> where Option<T>: FixedSizeEncoding {
94140
pub fn new((max_index_lo, max_index_hi): (usize, usize)) -> Self {
95141
PerDefTable {
96142
lo: Table::new(max_index_lo),
97143
hi: Table::new(max_index_hi),
98144
}
99145
}
100146

101-
pub fn record(&mut self, def_id: DefId, entry: Lazy<T>) {
147+
pub fn set(&mut self, def_id: DefId, value: T) {
102148
assert!(def_id.is_local());
103149
let space_index = def_id.index.address_space().index();
104150
let array_index = def_id.index.as_array_index();
105-
[&mut self.lo, &mut self.hi][space_index].record(array_index, entry);
151+
[&mut self.lo, &mut self.hi][space_index].set(array_index, value);
106152
}
107153

108154
pub fn encode(&self, buf: &mut Encoder) -> Lazy<Self> {
@@ -117,15 +163,15 @@ impl<T: LazyMeta<Meta = ()>> PerDefTable<T> {
117163
}
118164
}
119165

120-
impl<T: LazyMeta<Meta = ()>> LazyMeta for PerDefTable<T> {
166+
impl<T> LazyMeta for PerDefTable<T> where Option<T>: FixedSizeEncoding {
121167
type Meta = [<Table<T> as LazyMeta>::Meta; 2];
122168

123169
fn min_size([lo, hi]: Self::Meta) -> usize {
124170
Table::<T>::min_size(lo) + Table::<T>::min_size(hi)
125171
}
126172
}
127173

128-
impl<T: Encodable> Lazy<PerDefTable<T>> {
174+
impl<T> Lazy<PerDefTable<T>> where Option<T>: FixedSizeEncoding {
129175
fn table_for_space(&self, space: DefIndexAddressSpace) -> Lazy<Table<T>> {
130176
let space_index = space.index();
131177
let offset = space_index.checked_sub(1).map_or(0, |i| self.meta[i]);
@@ -135,11 +181,10 @@ impl<T: Encodable> Lazy<PerDefTable<T>> {
135181
)
136182
}
137183

138-
/// Given the metadata, extract out the offset of a particular DefIndex (if any).
184+
/// Given the metadata, extract out the value at a particular DefIndex (if any).
139185
#[inline(never)]
140-
pub fn lookup(&self, bytes: &[u8], def_index: DefIndex) -> Option<Lazy<T>> {
186+
pub fn get(&self, bytes: &[u8], def_index: DefIndex) -> Option<T> {
141187
self.table_for_space(def_index.address_space())
142-
.lookup(bytes, def_index.as_array_index())
188+
.get(bytes, def_index.as_array_index())
143189
}
144190
}
145-

0 commit comments

Comments
 (0)