From 9482bce56e9b56b91ec6c6af92eb660961ce8734 Mon Sep 17 00:00:00 2001 From: Austin Hicks Date: Sat, 1 Oct 2016 21:25:40 -0400 Subject: [PATCH] Replace offset_after_field with offsets --- src/librustc/ty/layout.rs | 59 ++++++++++++++++-------------------- src/librustc_lint/types.rs | 2 +- src/librustc_trans/adt.rs | 47 +++++++++++----------------- src/librustc_trans/common.rs | 2 +- src/librustc_trans/glue.rs | 13 +------- 5 files changed, 47 insertions(+), 76 deletions(-) diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index ed945534e1e5f..ec6843eb75d1f 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -511,11 +511,11 @@ pub struct Struct { /// If true, the size is exact, otherwise it's only a lower bound. pub sized: bool, - /// Offsets for the first byte after each field. - /// That is, field_offset(i) = offset_after_field[i - 1] and the - /// whole structure's size is the last offset, excluding padding. - // FIXME(eddyb) use small vector optimization for the common case. - pub offset_after_field: Vec + /// Offsets for the first byte of each field. + /// FIXME(eddyb) use small vector optimization for the common case. + pub offsets: Vec, + + pub min_size: Size, } impl<'a, 'gcx, 'tcx> Struct { @@ -524,7 +524,8 @@ impl<'a, 'gcx, 'tcx> Struct { align: if packed { dl.i8_align } else { dl.aggregate_align }, packed: packed, sized: true, - offset_after_field: vec![] + offsets: vec![], + min_size: Size::from_bytes(0), } } @@ -534,12 +535,14 @@ impl<'a, 'gcx, 'tcx> Struct { scapegoat: Ty<'gcx>) -> Result<(), LayoutError<'gcx>> where I: Iterator>> { - self.offset_after_field.reserve(fields.size_hint().0); + self.offsets.reserve(fields.size_hint().0); + + let mut offset = self.min_size; for field in fields { if !self.sized { bug!("Struct::extend: field #{} of `{}` comes after unsized field", - self.offset_after_field.len(), scapegoat); + self.offsets.len(), scapegoat); } let field = field?; @@ -548,34 +551,29 @@ impl<'a, 'gcx, 'tcx> Struct { } // Invariant: offset < dl.obj_size_bound() <= 1<<61 - let mut offset = if !self.packed { + if !self.packed { let align = field.align(dl); self.align = self.align.max(align); - self.offset_after_field.last_mut().map_or(Size::from_bytes(0), |last| { - *last = last.abi_align(align); - *last - }) - } else { - self.offset_after_field.last().map_or(Size::from_bytes(0), |&last| last) - }; + offset = offset.abi_align(align); + } + + self.offsets.push(offset); + offset = offset.checked_add(field.size(dl), dl) .map_or(Err(LayoutError::SizeOverflow(scapegoat)), Ok)?; - - self.offset_after_field.push(offset); } + self.min_size = offset; + Ok(()) } /// Get the size without trailing alignment padding. - pub fn min_size(&self) -> Size { - self.offset_after_field.last().map_or(Size::from_bytes(0), |&last| last) - } /// Get the size with trailing aligment padding. pub fn stride(&self) -> Size { - self.min_size().abi_align(self.align) + self.min_size.abi_align(self.align) } /// Determine whether a structure would be zero-sized, given its fields. @@ -671,15 +669,6 @@ impl<'a, 'gcx, 'tcx> Struct { } Ok(None) } - - pub fn offset_of_field(&self, index: usize) -> Size { - assert!(index < self.offset_after_field.len()); - if index == 0 { - Size::from_bytes(0) - } else { - self.offset_after_field[index-1] - } - } } /// An untagged union. @@ -1138,7 +1127,7 @@ impl<'a, 'gcx, 'tcx> Layout { }); let mut st = Struct::new(dl, false); st.extend(dl, discr.iter().map(Ok).chain(fields), ty)?; - size = cmp::max(size, st.min_size()); + size = cmp::max(size, st.min_size); align = align.max(st.align); Ok(st) }).collect::, _>>()?; @@ -1171,12 +1160,16 @@ impl<'a, 'gcx, 'tcx> Layout { let old_ity_size = Int(min_ity).size(dl); let new_ity_size = Int(ity).size(dl); for variant in &mut variants { - for offset in &mut variant.offset_after_field { + for offset in &mut variant.offsets[1..] { if *offset > old_ity_size { break; } *offset = new_ity_size; } + // We might be making the struct larger. + if variant.min_size <= old_ity_size { + variant.min_size = new_ity_size; + } } } diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index 1209ced8dd3d7..4caf7a04fe058 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -738,7 +738,7 @@ impl LateLintPass for VariantSizeDifferences { .zip(variants) .map(|(variant, variant_layout)| { // Subtract the size of the enum discriminant - let bytes = variant_layout.min_size().bytes() + let bytes = variant_layout.min_size.bytes() .saturating_sub(discr_size); debug!("- variant `{}` is {} bytes large", variant.node.name, bytes); diff --git a/src/librustc_trans/adt.rs b/src/librustc_trans/adt.rs index 8c6074fdaf9aa..f5cbe138cc5eb 100644 --- a/src/librustc_trans/adt.rs +++ b/src/librustc_trans/adt.rs @@ -632,7 +632,7 @@ fn struct_field_ptr<'blk, 'tcx>(bcx: &BlockAndBuilder<'blk, 'tcx>, let meta = val.meta; - let offset = st.offset_of_field(ix).bytes(); + let offset = st.offsets[ix].bytes(); let unaligned_offset = C_uint(bcx.ccx(), offset); // Get the alignment of the field @@ -695,9 +695,9 @@ pub fn trans_const<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>, discr: D let lldiscr = C_integral(Type::from_integer(ccx, d), discr.0 as u64, true); let mut vals_with_discr = vec![lldiscr]; vals_with_discr.extend_from_slice(vals); - let mut contents = build_const_struct(ccx, &variant.offset_after_field[..], - &vals_with_discr[..], variant.packed); - let needed_padding = l.size(dl).bytes() - variant.min_size().bytes(); + let mut contents = build_const_struct(ccx, &variant, + &vals_with_discr[..]); + let needed_padding = l.size(dl).bytes() - variant.min_size.bytes(); if needed_padding > 0 { contents.push(padding(ccx, needed_padding)); } @@ -711,7 +711,7 @@ pub fn trans_const<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>, discr: D layout::Univariant { ref variant, .. } => { assert_eq!(discr, Disr(0)); let contents = build_const_struct(ccx, - &variant.offset_after_field[..], vals, variant.packed); + &variant, vals); C_struct(ccx, &contents[..], variant.packed) } layout::Vector { .. } => { @@ -728,9 +728,7 @@ pub fn trans_const<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>, discr: D } layout::StructWrappedNullablePointer { ref nonnull, nndiscr, .. } => { if discr.0 == nndiscr { - C_struct(ccx, &build_const_struct(ccx, - &nonnull.offset_after_field[..], - vals, nonnull.packed), + C_struct(ccx, &build_const_struct(ccx, &nonnull, vals), false) } else { let fields = compute_fields(ccx, t, nndiscr as usize, false); @@ -739,10 +737,7 @@ pub fn trans_const<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>, discr: D // field; see #8506. C_null(type_of::sizing_type_of(ccx, ty)) }).collect::>(); - C_struct(ccx, &build_const_struct(ccx, - &nonnull.offset_after_field[..], - &vals[..], - false), + C_struct(ccx, &build_const_struct(ccx, &nonnull, &vals[..]), false) } } @@ -759,11 +754,10 @@ pub fn trans_const<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>, discr: D /// a two-element struct will locate it at offset 4, and accesses to it /// will read the wrong memory. fn build_const_struct<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - offset_after_field: &[layout::Size], - vals: &[ValueRef], - packed: bool) + st: &layout::Struct, + vals: &[ValueRef]) -> Vec { - assert_eq!(vals.len(), offset_after_field.len()); + assert_eq!(vals.len(), st.offsets.len()); if vals.len() == 0 { return Vec::new(); @@ -772,24 +766,19 @@ fn build_const_struct<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // offset of current value let mut offset = 0; let mut cfields = Vec::new(); - let target_offsets = offset_after_field.iter().map(|i| i.bytes()); - for (&val, target_offset) in vals.iter().zip(target_offsets) { - assert!(!is_undef(val)); - cfields.push(val); - offset += machine::llsize_of_alloc(ccx, val_ty(val)); - if !packed { - let val_align = machine::llalign_of_min(ccx, val_ty(val)); - offset = roundup(offset, val_align); - } - if offset != target_offset { + let offsets = st.offsets.iter().map(|i| i.bytes()); + for (&val, target_offset) in vals.iter().zip(offsets) { + if offset < target_offset { cfields.push(padding(ccx, target_offset - offset)); offset = target_offset; } + assert!(!is_undef(val)); + cfields.push(val); + offset += machine::llsize_of_alloc(ccx, val_ty(val)); } - let size = offset_after_field.last().unwrap(); - if offset < size.bytes() { - cfields.push(padding(ccx, size.bytes() - offset)); + if offset < st.min_size.bytes() { + cfields.push(padding(ccx, st.min_size.bytes() - offset)); } cfields diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index 5b1f691af8df7..6ae5fc1657aa7 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -127,7 +127,7 @@ pub fn type_is_imm_pair<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) Layout::FatPointer { .. } => true, Layout::Univariant { ref variant, .. } => { // There must be only 2 fields. - if variant.offset_after_field.len() != 2 { + if variant.offsets.len() != 2 { return false; } diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs index fe76ec05f6ead..64d959d29080c 100644 --- a/src/librustc_trans/glue.rs +++ b/src/librustc_trans/glue.rs @@ -335,20 +335,9 @@ pub fn size_and_align_of_dst<'blk, 'tcx>(bcx: &BlockAndBuilder<'blk, 'tcx>, let layout = ccx.layout_of(t); debug!("DST {} layout: {:?}", t, layout); - // Returns size in bytes of all fields except the last one - // (we will be recursing on the last one). - fn local_prefix_bytes(variant: &ty::layout::Struct) -> u64 { - let fields = variant.offset_after_field.len(); - if fields > 1 { - variant.offset_after_field[fields - 2].bytes() - } else { - 0 - } - } - let (sized_size, sized_align) = match *layout { ty::layout::Layout::Univariant { ref variant, .. } => { - (local_prefix_bytes(variant), variant.align.abi()) + (variant.offsets.last().map_or(0, |o| o.bytes()), variant.align.abi()) } _ => { bug!("size_and_align_of_dst: expcted Univariant for `{}`, found {:#?}",