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