Compute LLVM-agnostic type layouts in rustc.

# Conflicts:
#	src/librustc/ty/layout.rs
This commit is contained in:
Eduard Burtescu 2016-04-19 09:11:46 +03:00
parent efd0ea5b20
commit fe48a4af84
5 changed files with 1006 additions and 37 deletions

View File

@ -31,7 +31,7 @@ use hir::FreevarMap;
use ty::{BareFnTy, InferTy, ParamTy, ProjectionTy, TraitTy};
use ty::{TyVar, TyVid, IntVar, IntVid, FloatVar, FloatVid};
use ty::TypeVariants::*;
use ty::layout::TargetDataLayout;
use ty::layout::{Layout, TargetDataLayout};
use ty::maps;
use util::common::MemoizationMap;
use util::nodemap::{NodeMap, NodeSet, DefIdMap, DefIdSet};
@ -56,6 +56,7 @@ pub struct CtxtArenas<'tcx> {
bare_fn: TypedArena<BareFnTy<'tcx>>,
region: TypedArena<Region>,
stability: TypedArena<attr::Stability>,
layout: TypedArena<Layout>,
// references
trait_defs: TypedArena<ty::TraitDef<'tcx>>,
@ -70,6 +71,7 @@ impl<'tcx> CtxtArenas<'tcx> {
bare_fn: TypedArena::new(),
region: TypedArena::new(),
stability: TypedArena::new(),
layout: TypedArena::new(),
trait_defs: TypedArena::new(),
adt_defs: TypedArena::new()
@ -230,6 +232,7 @@ pub struct TyCtxt<'tcx> {
bare_fn_interner: RefCell<FnvHashMap<&'tcx BareFnTy<'tcx>, &'tcx BareFnTy<'tcx>>>,
region_interner: RefCell<FnvHashMap<&'tcx Region, &'tcx Region>>,
stability_interner: RefCell<FnvHashMap<&'tcx attr::Stability, &'tcx attr::Stability>>,
layout_interner: RefCell<FnvHashMap<&'tcx Layout, &'tcx Layout>>,
pub dep_graph: DepGraph,
@ -423,6 +426,9 @@ pub struct TyCtxt<'tcx> {
/// Data layout specification for the current target.
pub data_layout: TargetDataLayout,
/// Cache for layouts computed from types.
pub layout_cache: RefCell<FnvHashMap<Ty<'tcx>, &'tcx Layout>>,
}
impl<'tcx> TyCtxt<'tcx> {
@ -504,6 +510,20 @@ impl<'tcx> TyCtxt<'tcx> {
interned
}
pub fn intern_layout(&self, layout: Layout) -> &'tcx Layout {
if let Some(layout) = self.layout_interner.borrow().get(&layout) {
return layout;
}
let interned = self.arenas.layout.alloc(layout);
if let Some(prev) = self.layout_interner
.borrow_mut()
.insert(interned, interned) {
bug!("Tried to overwrite interned Layout: {:?}", prev)
}
interned
}
pub fn store_free_region_map(&self, id: NodeId, map: FreeRegionMap) {
if self.free_region_maps.borrow_mut().insert(id, map).is_some() {
bug!("Tried to overwrite interned FreeRegionMap for NodeId {:?}", id)
@ -547,6 +567,7 @@ impl<'tcx> TyCtxt<'tcx> {
bare_fn_interner: RefCell::new(FnvHashMap()),
region_interner: RefCell::new(FnvHashMap()),
stability_interner: RefCell::new(FnvHashMap()),
layout_interner: RefCell::new(FnvHashMap()),
dep_graph: dep_graph.clone(),
types: common_types,
named_region_map: named_region_map,
@ -595,6 +616,7 @@ impl<'tcx> TyCtxt<'tcx> {
fragment_infos: RefCell::new(DefIdMap()),
crate_name: token::intern_and_get_ident(crate_name),
data_layout: data_layout,
layout_cache: RefCell::new(FnvHashMap()),
}, f)
}
}
@ -768,6 +790,7 @@ impl<'tcx> TyCtxt<'tcx> {
println!("BareFnTy interner: #{}", self.bare_fn_interner.borrow().len());
println!("Region interner: #{}", self.region_interner.borrow().len());
println!("Stability interner: #{}", self.stability_interner.borrow().len());
println!("Layout interner: #{}", self.layout_interner.borrow().len());
}
}

File diff suppressed because it is too large Load Diff

View File

@ -18,6 +18,7 @@ use hir::pat_util;
use traits::{self, ProjectionMode};
use ty::{self, Ty, TyCtxt, TypeAndMut, TypeFlags, TypeFoldable};
use ty::{Disr, ParameterEnvironment};
use ty::layout::{Layout, LayoutError};
use ty::TypeVariants::*;
use rustc_const_math::{ConstInt, ConstIsize, ConstUsize};
@ -597,6 +598,24 @@ impl<'tcx> ty::TyS<'tcx> {
result
}
#[inline]
pub fn layout<'a>(&'tcx self, infcx: &infer::InferCtxt<'a, 'tcx>)
-> Result<&'tcx Layout, LayoutError<'tcx>> {
let can_cache = !self.has_param_types() && !self.has_self_ty();
if can_cache {
if let Some(&cached) = infcx.tcx.layout_cache.borrow().get(&self) {
return Ok(cached);
}
}
let layout = Layout::compute_uncached(self, infcx)?;
let layout = infcx.tcx.intern_layout(layout);
if can_cache {
infcx.tcx.layout_cache.borrow_mut().insert(self, layout);
}
Ok(layout)
}
/// Check whether a type is representable. This means it cannot contain unboxed
/// structural recursion. This check is needed for structs and enums.

View File

@ -32,18 +32,7 @@ use rustc::ty::{self, Ty};
use libc::c_uint;
pub use syntax::abi::Abi;
/// The first half of a fat pointer.
/// - For a closure, this is the code address.
/// - For an object or trait instance, this is the address of the box.
/// - For a slice, this is the base address.
pub const FAT_PTR_ADDR: usize = 0;
/// The second half of a fat pointer.
/// - For a closure, this is the address of the environment.
/// - For an object or trait instance, this is the address of the vtable.
/// - For a slice, this is the length.
pub const FAT_PTR_EXTRA: usize = 1;
pub use rustc::ty::layout::{FAT_PTR_ADDR, FAT_PTR_EXTRA};
#[derive(Clone, Copy, PartialEq, Debug)]
enum ArgKind {

View File

@ -784,23 +784,8 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
&self.local.trait_cache
}
/// Return exclusive upper bound on object size.
///
/// The theoretical maximum object size is defined as the maximum positive `int` value. This
/// ensures that the `offset` semantics remain well-defined by allowing it to correctly index
/// every address within an object along with one byte past the end, along with allowing `int`
/// to store the difference between any two pointers into an object.
///
/// The upper bound on 64-bit currently needs to be lower because LLVM uses a 64-bit integer to
/// represent object size in bits. It would need to be 1 << 61 to account for this, but is
/// currently conservatively bounded to 1 << 47 as that is enough to cover the current usable
/// address space on 64-bit ARMv8 and x86_64.
pub fn obj_size_bound(&self) -> u64 {
match &self.sess().target.target.target_pointer_width[..] {
"32" => 1 << 31,
"64" => 1 << 47,
_ => bug!() // error handled by config::build_target_config
}
self.tcx().data_layout.obj_size_bound()
}
pub fn report_overbig_object(&self, obj: Ty<'tcx>) -> ! {