2017-02-09 03:38:52 -08:00

121 lines
4.0 KiB
Rust

// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use schema::*;
use rustc::hir::def_id::{DefId, DefIndex};
use std::io::{Cursor, Write};
use std::slice;
use std::u32;
/// While we are generating the metadata, we also track the position
/// of each DefIndex. It is not required that all definitions appear
/// in the metadata, nor that they are serialized in order, and
/// therefore we first allocate the vector here and fill it with
/// `u32::MAX`. Whenever an index is visited, we fill in the
/// appropriate spot by calling `record_position`. We should never
/// visit the same index twice.
pub struct Index {
positions: Vec<u32>,
}
impl Index {
pub fn new(max_index: usize) -> Index {
Index { positions: vec![u32::MAX; max_index] }
}
pub fn record(&mut self, def_id: DefId, entry: Lazy<Entry>) {
assert!(def_id.is_local());
self.record_index(def_id.index, entry);
}
pub fn record_index(&mut self, item: DefIndex, entry: Lazy<Entry>) {
let item = item.as_usize();
assert!(entry.position < (u32::MAX as usize));
let position = entry.position as u32;
assert!(self.positions[item] == u32::MAX,
"recorded position for item {:?} twice, first at {:?} and now at {:?}",
item,
self.positions[item],
position);
self.positions[item] = position.to_le();
}
pub fn write_index(&self, buf: &mut Cursor<Vec<u8>>) -> LazySeq<Index> {
let pos = buf.position();
buf.write_all(words_to_bytes(&self.positions)).unwrap();
LazySeq::with_position_and_length(pos as usize, self.positions.len())
}
}
impl<'tcx> LazySeq<Index> {
/// Given the metadata, extract out the offset of a particular
/// DefIndex (if any).
#[inline(never)]
pub fn lookup(&self, bytes: &[u8], def_index: DefIndex) -> Option<Lazy<Entry<'tcx>>> {
let words = &bytes_to_words(&bytes[self.position..])[..self.len];
let index = def_index.as_usize();
debug!("Index::lookup: index={:?} words.len={:?}",
index,
words.len());
let position = u32::from_le(words[index].get());
if position == u32::MAX {
debug!("Index::lookup: position=u32::MAX");
None
} else {
debug!("Index::lookup: position={:?}", position);
Some(Lazy::with_position(position as usize))
}
}
pub fn iter_enumerated<'a>(&self,
bytes: &'a [u8])
-> impl Iterator<Item = (DefIndex, Lazy<Entry<'tcx>>)> + 'a {
let words = &bytes_to_words(&bytes[self.position..])[..self.len];
words.iter().map(|word| word.get()).enumerate().filter_map(|(index, position)| {
if position == u32::MAX {
None
} else {
let position = u32::from_le(position) as usize;
Some((DefIndex::new(index), Lazy::with_position(position)))
}
})
}
}
#[repr(packed)]
#[derive(Copy)]
struct Unaligned<T>(T);
// The derived Clone impl is unsafe for this packed struct since it needs to pass a reference to
// the field to `T::clone`, but this reference may not be properly aligned.
impl<T: Copy> Clone for Unaligned<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T> Unaligned<T> {
fn get(self) -> T { self.0 }
}
fn bytes_to_words(b: &[u8]) -> &[Unaligned<u32>] {
unsafe { slice::from_raw_parts(b.as_ptr() as *const Unaligned<u32>, b.len() / 4) }
}
fn words_to_bytes(w: &[u32]) -> &[u8] {
unsafe { slice::from_raw_parts(w.as_ptr() as *const u8, w.len() * 4) }
}