]>
Commit | Line | Data |
---|---|---|
e9174d1e SL |
1 | // Copyright 2015 The Rust Project Developers. See the COPYRIGHT |
2 | // file at the top-level directory of this distribution and at | |
3 | // http://rust-lang.org/COPYRIGHT. | |
4 | // | |
5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | |
6 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | |
7 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | |
8 | // option. This file may not be copied, modified, or distributed | |
9 | // except according to those terms. | |
10 | ||
9e0c209e SL |
11 | use schema::*; |
12 | ||
cc61c64b | 13 | use rustc::hir::def_id::{DefId, DefIndex, DefIndexAddressSpace}; |
e9174d1e SL |
14 | use std::io::{Cursor, Write}; |
15 | use std::slice; | |
16 | use std::u32; | |
e9174d1e | 17 | |
b039eaaf SL |
18 | /// While we are generating the metadata, we also track the position |
19 | /// of each DefIndex. It is not required that all definitions appear | |
20 | /// in the metadata, nor that they are serialized in order, and | |
21 | /// therefore we first allocate the vector here and fill it with | |
22 | /// `u32::MAX`. Whenever an index is visited, we fill in the | |
23 | /// appropriate spot by calling `record_position`. We should never | |
24 | /// visit the same index twice. | |
9e0c209e | 25 | pub struct Index { |
cc61c64b | 26 | positions: [Vec<u32>; 2] |
e9174d1e SL |
27 | } |
28 | ||
9e0c209e | 29 | impl Index { |
cc61c64b XL |
30 | pub fn new((max_index_lo, max_index_hi): (usize, usize)) -> Index { |
31 | Index { | |
32 | positions: [vec![u32::MAX; max_index_lo], | |
33 | vec![u32::MAX; max_index_hi]], | |
34 | } | |
b039eaaf SL |
35 | } |
36 | ||
9e0c209e | 37 | pub fn record(&mut self, def_id: DefId, entry: Lazy<Entry>) { |
b039eaaf | 38 | assert!(def_id.is_local()); |
9e0c209e | 39 | self.record_index(def_id.index, entry); |
b039eaaf SL |
40 | } |
41 | ||
9e0c209e | 42 | pub fn record_index(&mut self, item: DefIndex, entry: Lazy<Entry>) { |
9e0c209e SL |
43 | assert!(entry.position < (u32::MAX as usize)); |
44 | let position = entry.position as u32; | |
cc61c64b XL |
45 | let space_index = item.address_space().index(); |
46 | let array_index = item.as_array_index(); | |
e9174d1e | 47 | |
cc61c64b | 48 | assert!(self.positions[space_index][array_index] == u32::MAX, |
b039eaaf | 49 | "recorded position for item {:?} twice, first at {:?} and now at {:?}", |
c30ab7b3 | 50 | item, |
cc61c64b | 51 | self.positions[space_index][array_index], |
c30ab7b3 | 52 | position); |
e9174d1e | 53 | |
cc61c64b | 54 | self.positions[space_index][array_index] = position.to_le(); |
e9174d1e SL |
55 | } |
56 | ||
9e0c209e SL |
57 | pub fn write_index(&self, buf: &mut Cursor<Vec<u8>>) -> LazySeq<Index> { |
58 | let pos = buf.position(); | |
cc61c64b XL |
59 | |
60 | // First we write the length of the lower range ... | |
61 | buf.write_all(words_to_bytes(&[(self.positions[0].len() as u32).to_le()])).unwrap(); | |
62 | // ... then the values in the lower range ... | |
63 | buf.write_all(words_to_bytes(&self.positions[0][..])).unwrap(); | |
64 | // ... then the values in the higher range. | |
65 | buf.write_all(words_to_bytes(&self.positions[1][..])).unwrap(); | |
66 | LazySeq::with_position_and_length(pos as usize, | |
67 | self.positions[0].len() + self.positions[1].len() + 1) | |
e9174d1e | 68 | } |
b039eaaf | 69 | } |
e9174d1e | 70 | |
9e0c209e SL |
71 | impl<'tcx> LazySeq<Index> { |
72 | /// Given the metadata, extract out the offset of a particular | |
73 | /// DefIndex (if any). | |
74 | #[inline(never)] | |
75 | pub fn lookup(&self, bytes: &[u8], def_index: DefIndex) -> Option<Lazy<Entry<'tcx>>> { | |
76 | let words = &bytes_to_words(&bytes[self.position..])[..self.len]; | |
e9174d1e | 77 | |
9e0c209e | 78 | debug!("Index::lookup: index={:?} words.len={:?}", |
2c00a5a8 | 79 | def_index, |
c30ab7b3 | 80 | words.len()); |
9e0c209e | 81 | |
cc61c64b XL |
82 | let positions = match def_index.address_space() { |
83 | DefIndexAddressSpace::Low => &words[1..], | |
84 | DefIndexAddressSpace::High => { | |
85 | // This is a DefIndex in the higher range, so find out where | |
86 | // that starts: | |
87 | let lo_count = u32::from_le(words[0].get()) as usize; | |
88 | &words[lo_count + 1 .. ] | |
89 | } | |
90 | }; | |
91 | ||
92 | let array_index = def_index.as_array_index(); | |
93 | let position = u32::from_le(positions[array_index].get()); | |
9e0c209e SL |
94 | if position == u32::MAX { |
95 | debug!("Index::lookup: position=u32::MAX"); | |
96 | None | |
97 | } else { | |
98 | debug!("Index::lookup: position={:?}", position); | |
99 | Some(Lazy::with_position(position as usize)) | |
e9174d1e SL |
100 | } |
101 | } | |
e9174d1e SL |
102 | } |
103 | ||
476ff2be | 104 | #[repr(packed)] |
8bb4bdeb | 105 | #[derive(Copy)] |
476ff2be SL |
106 | struct Unaligned<T>(T); |
107 | ||
8bb4bdeb XL |
108 | // The derived Clone impl is unsafe for this packed struct since it needs to pass a reference to |
109 | // the field to `T::clone`, but this reference may not be properly aligned. | |
110 | impl<T: Copy> Clone for Unaligned<T> { | |
111 | fn clone(&self) -> Self { | |
112 | *self | |
113 | } | |
114 | } | |
115 | ||
476ff2be SL |
116 | impl<T> Unaligned<T> { |
117 | fn get(self) -> T { self.0 } | |
118 | } | |
119 | ||
120 | fn bytes_to_words(b: &[u8]) -> &[Unaligned<u32>] { | |
121 | unsafe { slice::from_raw_parts(b.as_ptr() as *const Unaligned<u32>, b.len() / 4) } | |
e9174d1e SL |
122 | } |
123 | ||
9e0c209e SL |
124 | fn words_to_bytes(w: &[u32]) -> &[u8] { |
125 | unsafe { slice::from_raw_parts(w.as_ptr() as *const u8, w.len() * 4) } | |
e9174d1e | 126 | } |