]> git.lizzy.rs Git - rust.git/blob - src/librustc_metadata/index.rs
Auto merge of #57770 - Zoxc:no-hash-query, r=michaelwoerister
[rust.git] / src / librustc_metadata / index.rs
1 use crate::schema::*;
2
3 use rustc::hir::def_id::{DefId, DefIndex, DefIndexAddressSpace};
4 use rustc_serialize::opaque::Encoder;
5 use std::slice;
6 use std::u32;
7 use log::debug;
8
9 /// While we are generating the metadata, we also track the position
10 /// of each DefIndex. It is not required that all definitions appear
11 /// in the metadata, nor that they are serialized in order, and
12 /// therefore we first allocate the vector here and fill it with
13 /// `u32::MAX`. Whenever an index is visited, we fill in the
14 /// appropriate spot by calling `record_position`. We should never
15 /// visit the same index twice.
16 pub struct Index {
17     positions: [Vec<u32>; 2]
18 }
19
20 impl Index {
21     pub fn new((max_index_lo, max_index_hi): (usize, usize)) -> Index {
22         Index {
23             positions: [vec![u32::MAX; max_index_lo],
24                         vec![u32::MAX; max_index_hi]],
25         }
26     }
27
28     pub fn record(&mut self, def_id: DefId, entry: Lazy<Entry<'_>>) {
29         assert!(def_id.is_local());
30         self.record_index(def_id.index, entry);
31     }
32
33     pub fn record_index(&mut self, item: DefIndex, entry: Lazy<Entry<'_>>) {
34         assert!(entry.position < (u32::MAX as usize));
35         let position = entry.position as u32;
36         let space_index = item.address_space().index();
37         let array_index = item.as_array_index();
38
39         assert!(self.positions[space_index][array_index] == u32::MAX,
40                 "recorded position for item {:?} twice, first at {:?} and now at {:?}",
41                 item,
42                 self.positions[space_index][array_index],
43                 position);
44
45         self.positions[space_index][array_index] = position.to_le();
46     }
47
48     pub fn write_index(&self, buf: &mut Encoder) -> LazySeq<Index> {
49         let pos = buf.position();
50
51         // First we write the length of the lower range ...
52         buf.emit_raw_bytes(words_to_bytes(&[(self.positions[0].len() as u32).to_le()]));
53         // ... then the values in the lower range ...
54         buf.emit_raw_bytes(words_to_bytes(&self.positions[0][..]));
55         // ... then the values in the higher range.
56         buf.emit_raw_bytes(words_to_bytes(&self.positions[1][..]));
57         LazySeq::with_position_and_length(pos as usize,
58             self.positions[0].len() + self.positions[1].len() + 1)
59     }
60 }
61
62 impl<'tcx> LazySeq<Index> {
63     /// Given the metadata, extract out the offset of a particular
64     /// DefIndex (if any).
65     #[inline(never)]
66     pub fn lookup(&self, bytes: &[u8], def_index: DefIndex) -> Option<Lazy<Entry<'tcx>>> {
67         let words = &bytes_to_words(&bytes[self.position..])[..self.len];
68
69         debug!("Index::lookup: index={:?} words.len={:?}",
70                def_index,
71                words.len());
72
73         let positions = match def_index.address_space() {
74             DefIndexAddressSpace::Low => &words[1..],
75             DefIndexAddressSpace::High => {
76                 // This is a DefIndex in the higher range, so find out where
77                 // that starts:
78                 let lo_count = u32::from_le(words[0].get()) as usize;
79                 &words[lo_count + 1 .. ]
80             }
81         };
82
83         let array_index = def_index.as_array_index();
84         let position = u32::from_le(positions[array_index].get());
85         if position == u32::MAX {
86             debug!("Index::lookup: position=u32::MAX");
87             None
88         } else {
89             debug!("Index::lookup: position={:?}", position);
90             Some(Lazy::with_position(position as usize))
91         }
92     }
93 }
94
95 #[repr(packed)]
96 #[derive(Copy)]
97 struct Unaligned<T>(T);
98
99 // The derived Clone impl is unsafe for this packed struct since it needs to pass a reference to
100 // the field to `T::clone`, but this reference may not be properly aligned.
101 impl<T: Copy> Clone for Unaligned<T> {
102     fn clone(&self) -> Self {
103         *self
104     }
105 }
106
107 impl<T> Unaligned<T> {
108     fn get(self) -> T { self.0 }
109 }
110
111 fn bytes_to_words(b: &[u8]) -> &[Unaligned<u32>] {
112     unsafe { slice::from_raw_parts(b.as_ptr() as *const Unaligned<u32>, b.len() / 4) }
113 }
114
115 fn words_to_bytes(w: &[u32]) -> &[u8] {
116     unsafe { slice::from_raw_parts(w.as_ptr() as *const u8, w.len() * 4) }
117 }