Skip to content

Commit 7cce75f

Browse files
committed
librustc: Apply null pointer optimization to slices, closures and trait
objects.
1 parent 5d5c206 commit 7cce75f

File tree

2 files changed

+100
-43
lines changed

2 files changed

+100
-43
lines changed

src/librustc/middle/trans/adt.rs

Lines changed: 99 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ pub enum Repr {
111111
StructWrappedNullablePointer {
112112
pub nonnull: Struct,
113113
pub nndiscr: Disr,
114-
pub ptrfield: uint,
114+
pub ptrfield: PointerField,
115115
pub nullfields: Vec<ty::t>,
116116
}
117117
}
@@ -211,24 +211,21 @@ fn represent_type_uncached(cx: &CrateContext, t: ty::t) -> Repr {
211211
let mut discr = 0;
212212
while discr < 2 {
213213
if cases.get(1 - discr).is_zerolen(cx) {
214+
let st = mk_struct(cx, cases.get(discr).tys.as_slice(), false);
214215
match cases.get(discr).find_ptr() {
216+
Some(ThinPointer(_)) if st.fields.len() == 1 => {
217+
return RawNullablePointer {
218+
nndiscr: discr as Disr,
219+
nnty: *st.fields.get(0),
220+
nullfields: cases.get(1 - discr).tys.clone()
221+
};
222+
}
215223
Some(ptrfield) => {
216-
let st = mk_struct(cx, cases.get(discr).tys.as_slice(),
217-
false);
218-
219-
return if st.fields.len() == 1 {
220-
RawNullablePointer {
221-
nndiscr: discr as Disr,
222-
nnty: *st.fields.get(0),
223-
nullfields: cases.get(1 - discr).tys.clone()
224-
}
225-
} else {
226-
StructWrappedNullablePointer {
227-
nndiscr: discr as Disr,
228-
nonnull: st,
229-
ptrfield: ptrfield,
230-
nullfields: cases.get(1 - discr).tys.clone()
231-
}
224+
return StructWrappedNullablePointer {
225+
nndiscr: discr as Disr,
226+
nonnull: st,
227+
ptrfield: ptrfield,
228+
nullfields: cases.get(1 - discr).tys.clone()
232229
};
233230
}
234231
None => { }
@@ -283,23 +280,67 @@ pub fn is_ffi_safe(tcx: &ty::ctxt, def_id: ast::DefId) -> bool {
283280
}
284281

285282
// this should probably all be in ty
286-
struct Case { discr: Disr, tys: Vec<ty::t> }
283+
struct Case {
284+
discr: Disr,
285+
tys: Vec<ty::t>
286+
}
287+
288+
289+
#[deriving(Show)]
290+
pub enum PointerField {
291+
ThinPointer(uint),
292+
FatPointer(uint, uint)
293+
}
294+
287295
impl Case {
288296
fn is_zerolen(&self, cx: &CrateContext) -> bool {
289297
mk_struct(cx, self.tys.as_slice(), false).size == 0
290298
}
291-
fn find_ptr(&self) -> Option<uint> {
292-
self.tys.iter().position(|&ty| {
299+
fn find_ptr(&self) -> Option<PointerField> {
300+
use back::abi::{fn_field_code, slice_elt_base, trt_field_box};
301+
302+
for (i, &ty) in self.tys.iter().enumerate() {
293303
match ty::get(ty).sty {
294-
ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ty, ..}) => match ty::get(ty).sty {
295-
ty::ty_vec(_, None) | ty::ty_str| ty::ty_trait(..) => false,
296-
_ => true,
304+
// &T/&mut T could either be a thin or fat pointer depending on T
305+
ty::ty_rptr(_, ty::mt { ty, .. }) => match ty::get(ty).sty {
306+
// &[T] and &str are a pointer and length pair
307+
ty::ty_vec(_, None) | ty::ty_str => return Some(FatPointer(i, slice_elt_base)),
308+
309+
// &Trait/&mut Trait are a pair of pointers: the actual object and a vtable
310+
ty::ty_trait(..) => return Some(FatPointer(i, trt_field_box)),
311+
312+
// Any other &T/&mut T is just a pointer
313+
_ => return Some(ThinPointer(i))
314+
},
315+
316+
// Box<T> could either be a thin or fat pointer depending on T
317+
ty::ty_uniq(t) => match ty::get(t).sty {
318+
// Box<[T]>/Box<str> might be FatPointer in a post DST world
319+
ty::ty_vec(_, None) | ty::ty_str => continue,
320+
321+
// Box<Trait> is a pair of pointers: the actual object and a vtable
322+
ty::ty_trait(..) => return Some(FatPointer(i, trt_field_box)),
323+
324+
// Any other Box<T> is just a pointer
325+
_ => return Some(ThinPointer(i))
297326
},
298-
ty::ty_box(..) | ty::ty_bare_fn(..) => true,
299-
// Is that everything? Would closures or slices qualify?
300-
_ => false
327+
328+
// Gc<T> is just a pointer
329+
ty::ty_box(..) => return Some(ThinPointer(i)),
330+
331+
// Functions are just pointers
332+
ty::ty_bare_fn(..) => return Some(ThinPointer(i)),
333+
334+
// Closures are a pair of pointers: the code and environment
335+
ty::ty_closure(..) => return Some(FatPointer(i, fn_field_code)),
336+
337+
// Anything else is not a pointer
338+
_ => continue
339+
301340
}
302-
})
341+
}
342+
343+
None
303344
}
304345
}
305346

@@ -552,8 +593,8 @@ pub fn trans_get_discr(bcx: &Block, r: &Repr, scrutinee: ValueRef, cast_to: Opti
552593
val = ICmp(bcx, cmp, Load(bcx, scrutinee), C_null(llptrty));
553594
signed = false;
554595
}
555-
StructWrappedNullablePointer { nonnull: ref nonnull, nndiscr, ptrfield, .. } => {
556-
val = struct_wrapped_nullable_bitdiscr(bcx, nonnull, nndiscr, ptrfield, scrutinee);
596+
StructWrappedNullablePointer { nndiscr, ptrfield, .. } => {
597+
val = struct_wrapped_nullable_bitdiscr(bcx, nndiscr, ptrfield, scrutinee);
557598
signed = false;
558599
}
559600
}
@@ -563,12 +604,15 @@ pub fn trans_get_discr(bcx: &Block, r: &Repr, scrutinee: ValueRef, cast_to: Opti
563604
}
564605
}
565606

566-
fn struct_wrapped_nullable_bitdiscr(bcx: &Block, nonnull: &Struct, nndiscr: Disr, ptrfield: uint,
607+
fn struct_wrapped_nullable_bitdiscr(bcx: &Block, nndiscr: Disr, ptrfield: PointerField,
567608
scrutinee: ValueRef) -> ValueRef {
568-
let llptr = Load(bcx, GEPi(bcx, scrutinee, [0, ptrfield]));
609+
let llptrptr = match ptrfield {
610+
ThinPointer(field) => GEPi(bcx, scrutinee, [0, field]),
611+
FatPointer(field, pair) => GEPi(bcx, scrutinee, [0, field, pair])
612+
};
613+
let llptr = Load(bcx, llptrptr);
569614
let cmp = if nndiscr == 0 { IntEQ } else { IntNE };
570-
let llptrty = type_of::type_of(bcx.ccx(), *nonnull.fields.get(ptrfield));
571-
ICmp(bcx, cmp, llptr, C_null(llptrty))
615+
ICmp(bcx, cmp, llptr, C_null(val_ty(llptr)))
572616
}
573617

574618
/// Helper for cases where the discriminant is simply loaded.
@@ -655,9 +699,15 @@ pub fn trans_start_init(bcx: &Block, r: &Repr, val: ValueRef, discr: Disr) {
655699
}
656700
StructWrappedNullablePointer { nonnull: ref nonnull, nndiscr, ptrfield, .. } => {
657701
if discr != nndiscr {
658-
let llptrptr = GEPi(bcx, val, [0, ptrfield]);
659-
let llptrty = type_of::type_of(bcx.ccx(),
660-
*nonnull.fields.get(ptrfield));
702+
let (llptrptr, llptrty) = match ptrfield {
703+
ThinPointer(field) =>
704+
(GEPi(bcx, val, [0, field]),
705+
type_of::type_of(bcx.ccx(), *nonnull.fields.get(field))),
706+
FatPointer(field, pair) => {
707+
let v = GEPi(bcx, val, [0, field, pair]);
708+
(v, val_ty(v).element_type())
709+
}
710+
};
661711
Store(bcx, C_null(llptrty), llptrptr)
662712
}
663713
}
@@ -925,7 +975,11 @@ pub fn const_get_discrim(ccx: &CrateContext, r: &Repr, val: ValueRef)
925975
}
926976
}
927977
StructWrappedNullablePointer { nndiscr, ptrfield, .. } => {
928-
if is_null(const_struct_field(ccx, val, ptrfield)) {
978+
let (idx, sub_idx) = match ptrfield {
979+
ThinPointer(field) => (field, None),
980+
FatPointer(field, pair) => (field, Some(pair))
981+
};
982+
if is_null(const_struct_field(ccx, val, idx, sub_idx)) {
929983
/* subtraction as uint is ok because nndiscr is either 0 or 1 */
930984
(1 - nndiscr) as Disr
931985
} else {
@@ -946,26 +1000,29 @@ pub fn const_get_field(ccx: &CrateContext, r: &Repr, val: ValueRef,
9461000
_discr: Disr, ix: uint) -> ValueRef {
9471001
match *r {
9481002
CEnum(..) => ccx.sess().bug("element access in C-like enum const"),
949-
Univariant(..) => const_struct_field(ccx, val, ix),
950-
General(..) => const_struct_field(ccx, val, ix + 1),
1003+
Univariant(..) => const_struct_field(ccx, val, ix, None),
1004+
General(..) => const_struct_field(ccx, val, ix + 1, None),
9511005
RawNullablePointer { .. } => {
9521006
assert_eq!(ix, 0);
9531007
val
9541008
}
955-
StructWrappedNullablePointer{ .. } => const_struct_field(ccx, val, ix)
1009+
StructWrappedNullablePointer{ .. } => const_struct_field(ccx, val, ix, None)
9561010
}
9571011
}
9581012

9591013
/// Extract field of struct-like const, skipping our alignment padding.
960-
fn const_struct_field(ccx: &CrateContext, val: ValueRef, ix: uint)
1014+
fn const_struct_field(ccx: &CrateContext, val: ValueRef, ix: uint, sub_idx: Option<uint>)
9611015
-> ValueRef {
9621016
// Get the ix-th non-undef element of the struct.
9631017
let mut real_ix = 0; // actual position in the struct
9641018
let mut ix = ix; // logical index relative to real_ix
9651019
let mut field;
9661020
loop {
9671021
loop {
968-
field = const_get_elt(ccx, val, [real_ix]);
1022+
field = match sub_idx {
1023+
Some(si) => const_get_elt(ccx, val, [real_ix, si as u32]),
1024+
None => const_get_elt(ccx, val, [real_ix])
1025+
};
9691026
if !is_undef(field) {
9701027
break;
9711028
}

src/librustc/middle/trans/debuginfo.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2196,7 +2196,7 @@ impl VariantMemberDescriptionFactory {
21962196

21972197
enum EnumDiscriminantInfo {
21982198
RegularDiscriminant(DIType),
2199-
OptimizedDiscriminant(uint),
2199+
OptimizedDiscriminant(adt::PointerField),
22002200
NoDiscriminant
22012201
}
22022202

0 commit comments

Comments
 (0)