Skip to content

Commit 68e0e58

Browse files
committed
Auto merge of #50612 - Zoxc:thin-slice, r=michaelwoerister
Make &Slice a thin pointer Split out from #50395 r? @michaelwoerister
2 parents d0456c6 + fb4e3b6 commit 68e0e58

File tree

5 files changed

+133
-49
lines changed

5 files changed

+133
-49
lines changed

src/libarena/lib.rs

+34-25
Original file line numberDiff line numberDiff line change
@@ -314,17 +314,15 @@ impl DroplessArena {
314314
false
315315
}
316316

317-
fn align_for<T>(&self) {
318-
let align = mem::align_of::<T>();
317+
fn align(&self, align: usize) {
319318
let final_address = ((self.ptr.get() as usize) + align - 1) & !(align - 1);
320319
self.ptr.set(final_address as *mut u8);
321320
assert!(self.ptr <= self.end);
322321
}
323322

324323
#[inline(never)]
325324
#[cold]
326-
fn grow<T>(&self, n: usize) {
327-
let needed_bytes = n * mem::size_of::<T>();
325+
fn grow(&self, needed_bytes: usize) {
328326
unsafe {
329327
let mut chunks = self.chunks.borrow_mut();
330328
let (chunk, mut new_capacity);
@@ -356,25 +354,38 @@ impl DroplessArena {
356354
}
357355

358356
#[inline]
359-
pub fn alloc<T>(&self, object: T) -> &mut T {
357+
pub fn alloc_raw(&self, bytes: usize, align: usize) -> &mut [u8] {
360358
unsafe {
361-
assert!(!mem::needs_drop::<T>());
362-
assert!(mem::size_of::<T>() != 0);
359+
assert!(bytes != 0);
360+
361+
self.align(align);
363362

364-
self.align_for::<T>();
365-
let future_end = intrinsics::arith_offset(self.ptr.get(), mem::size_of::<T>() as isize);
363+
let future_end = intrinsics::arith_offset(self.ptr.get(), bytes as isize);
366364
if (future_end as *mut u8) >= self.end.get() {
367-
self.grow::<T>(1)
365+
self.grow(bytes);
368366
}
369367

370368
let ptr = self.ptr.get();
371369
// Set the pointer past ourselves
372370
self.ptr.set(
373-
intrinsics::arith_offset(self.ptr.get(), mem::size_of::<T>() as isize) as *mut u8,
371+
intrinsics::arith_offset(self.ptr.get(), bytes as isize) as *mut u8,
374372
);
373+
slice::from_raw_parts_mut(ptr, bytes)
374+
}
375+
}
376+
377+
#[inline]
378+
pub fn alloc<T>(&self, object: T) -> &mut T {
379+
assert!(!mem::needs_drop::<T>());
380+
381+
let mem = self.alloc_raw(
382+
mem::size_of::<T>(),
383+
mem::align_of::<T>()) as *mut _ as *mut T;
384+
385+
unsafe {
375386
// Write into uninitialized memory.
376-
ptr::write(ptr as *mut T, object);
377-
&mut *(ptr as *mut T)
387+
ptr::write(mem, object);
388+
&mut *mem
378389
}
379390
}
380391

@@ -393,21 +404,13 @@ impl DroplessArena {
393404
assert!(!mem::needs_drop::<T>());
394405
assert!(mem::size_of::<T>() != 0);
395406
assert!(slice.len() != 0);
396-
self.align_for::<T>();
397407

398-
let future_end = unsafe {
399-
intrinsics::arith_offset(self.ptr.get(), (slice.len() * mem::size_of::<T>()) as isize)
400-
};
401-
if (future_end as *mut u8) >= self.end.get() {
402-
self.grow::<T>(slice.len());
403-
}
408+
let mem = self.alloc_raw(
409+
slice.len() * mem::size_of::<T>(),
410+
mem::align_of::<T>()) as *mut _ as *mut T;
404411

405412
unsafe {
406-
let arena_slice = slice::from_raw_parts_mut(self.ptr.get() as *mut T, slice.len());
407-
self.ptr.set(intrinsics::arith_offset(
408-
self.ptr.get(),
409-
(slice.len() * mem::size_of::<T>()) as isize,
410-
) as *mut u8);
413+
let arena_slice = slice::from_raw_parts_mut(mem, slice.len());
411414
arena_slice.copy_from_slice(slice);
412415
arena_slice
413416
}
@@ -464,6 +467,12 @@ impl SyncDroplessArena {
464467
self.lock.lock().in_arena(ptr)
465468
}
466469

470+
#[inline(always)]
471+
pub fn alloc_raw(&self, bytes: usize, align: usize) -> &mut [u8] {
472+
// Extend the lifetime of the result since it's limited to the lock guard
473+
unsafe { &mut *(self.lock.lock().alloc_raw(bytes, align) as *mut [u8]) }
474+
}
475+
467476
#[inline(always)]
468477
pub fn alloc<T>(&self, object: T) -> &mut T {
469478
// Extend the lifetime of the result since it's limited to the lock guard

src/librustc/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
#![feature(macro_vis_matcher)]
5555
#![feature(never_type)]
5656
#![feature(exhaustive_patterns)]
57+
#![feature(extern_types)]
5758
#![feature(non_exhaustive)]
5859
#![feature(proc_macro_internals)]
5960
#![feature(quote)]

src/librustc/ty/context.rs

+21-12
Original file line numberDiff line numberDiff line change
@@ -794,6 +794,12 @@ impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for TypeckTables<'gcx> {
794794

795795
impl<'tcx> CommonTypes<'tcx> {
796796
fn new(interners: &CtxtInterners<'tcx>) -> CommonTypes<'tcx> {
797+
// Ensure our type representation does not grow
798+
#[cfg(target_pointer_width = "64")]
799+
assert!(mem::size_of::<ty::TypeVariants>() <= 24);
800+
#[cfg(target_pointer_width = "64")]
801+
assert!(mem::size_of::<ty::TyS>() <= 32);
802+
797803
let mk = |sty| CtxtInterners::intern_ty(interners, interners, sty);
798804
let mk_region = |r| {
799805
if let Some(r) = interners.region.borrow().get(&r) {
@@ -2056,9 +2062,8 @@ for Interned<'tcx, Slice<Goal<'tcx>>> {
20562062

20572063
macro_rules! intern_method {
20582064
($lt_tcx:tt, $name:ident: $method:ident($alloc:ty,
2059-
$alloc_method:ident,
2065+
$alloc_method:expr,
20602066
$alloc_to_key:expr,
2061-
$alloc_to_ret:expr,
20622067
$keep_in_local_tcx:expr) -> $ty:ty) => {
20632068
impl<'a, 'gcx, $lt_tcx> TyCtxt<'a, 'gcx, $lt_tcx> {
20642069
pub fn $method(self, v: $alloc) -> &$lt_tcx $ty {
@@ -2081,7 +2086,7 @@ macro_rules! intern_method {
20812086
v);
20822087
}
20832088

2084-
let i = ($alloc_to_ret)(self.interners.arena.$alloc_method(v));
2089+
let i = $alloc_method(&self.interners.arena, v);
20852090
interner.insert(Interned(i));
20862091
i
20872092
} else {
@@ -2094,7 +2099,9 @@ macro_rules! intern_method {
20942099
let v = unsafe {
20952100
mem::transmute(v)
20962101
};
2097-
let i = ($alloc_to_ret)(self.global_interners.arena.$alloc_method(v));
2102+
let i: &$lt_tcx $ty = $alloc_method(&self.global_interners.arena, v);
2103+
// Cast to 'gcx
2104+
let i = unsafe { mem::transmute(i) };
20982105
interner.insert(Interned(i));
20992106
i
21002107
}
@@ -2121,8 +2128,10 @@ macro_rules! direct_interners {
21212128

21222129
intern_method!(
21232130
$lt_tcx,
2124-
$name: $method($ty, alloc, |x| x, |x| x, $keep_in_local_tcx) -> $ty
2125-
);)+
2131+
$name: $method($ty,
2132+
|a: &$lt_tcx SyncDroplessArena, v| -> &$lt_tcx $ty { a.alloc(v) },
2133+
|x| x,
2134+
$keep_in_local_tcx) -> $ty);)+
21262135
}
21272136
}
21282137

@@ -2137,10 +2146,11 @@ direct_interners!('tcx,
21372146

21382147
macro_rules! slice_interners {
21392148
($($field:ident: $method:ident($ty:ident)),+) => (
2140-
$(intern_method!('tcx, $field: $method(&[$ty<'tcx>], alloc_slice, Deref::deref,
2141-
|xs: &[$ty]| -> &Slice<$ty> {
2142-
unsafe { mem::transmute(xs) }
2143-
}, |xs: &[$ty]| xs.iter().any(keep_local)) -> Slice<$ty<'tcx>>);)+
2149+
$(intern_method!( 'tcx, $field: $method(
2150+
&[$ty<'tcx>],
2151+
|a, v| Slice::from_arena(a, v),
2152+
Deref::deref,
2153+
|xs: &[$ty]| xs.iter().any(keep_local)) -> Slice<$ty<'tcx>>);)+
21442154
)
21452155
}
21462156

@@ -2162,9 +2172,8 @@ intern_method! {
21622172
'tcx,
21632173
canonical_var_infos: _intern_canonical_var_infos(
21642174
&[CanonicalVarInfo],
2165-
alloc_slice,
2175+
|a, v| Slice::from_arena(a, v),
21662176
Deref::deref,
2167-
|xs: &[CanonicalVarInfo]| -> &Slice<CanonicalVarInfo> { unsafe { mem::transmute(xs) } },
21682177
|_xs: &[CanonicalVarInfo]| -> bool { false }
21692178
) -> Slice<CanonicalVarInfo>
21702179
}

src/librustc/ty/mod.rs

+76-11
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ use ty::util::{IntTypeExt, Discr};
3636
use ty::walk::TypeWalker;
3737
use util::captures::Captures;
3838
use util::nodemap::{NodeSet, DefIdMap, FxHashMap};
39+
use arena::SyncDroplessArena;
3940

4041
use serialize::{self, Encodable, Encoder};
4142
use std::cell::RefCell;
@@ -582,54 +583,113 @@ impl <'gcx: 'tcx, 'tcx> Canonicalize<'gcx, 'tcx> for Ty<'tcx> {
582583
}
583584
}
584585

586+
extern {
587+
/// A dummy type used to force Slice to by unsized without requiring fat pointers
588+
type OpaqueSliceContents;
589+
}
590+
585591
/// A wrapper for slices with the additional invariant
586592
/// that the slice is interned and no other slice with
587593
/// the same contents can exist in the same context.
588-
/// This means we can use pointer + length for both
594+
/// This means we can use pointer for both
589595
/// equality comparisons and hashing.
590-
#[derive(Debug, RustcEncodable)]
591-
pub struct Slice<T>([T]);
596+
#[repr(C)]
597+
pub struct Slice<T> {
598+
len: usize,
599+
data: [T; 0],
600+
opaque: OpaqueSliceContents,
601+
}
602+
603+
impl<T: Copy> Slice<T> {
604+
#[inline]
605+
fn from_arena<'tcx>(arena: &'tcx SyncDroplessArena, slice: &[T]) -> &'tcx Slice<T> {
606+
assert!(!mem::needs_drop::<T>());
607+
assert!(mem::size_of::<T>() != 0);
608+
assert!(slice.len() != 0);
609+
610+
// Align up the size of the len (usize) field
611+
let align = mem::align_of::<T>();
612+
let align_mask = align - 1;
613+
let offset = mem::size_of::<usize>();
614+
let offset = (offset + align_mask) & !align_mask;
615+
616+
let size = offset + slice.len() * mem::size_of::<T>();
617+
618+
let mem = arena.alloc_raw(
619+
size,
620+
cmp::max(mem::align_of::<T>(), mem::align_of::<usize>()));
621+
unsafe {
622+
let result = &mut *(mem.as_mut_ptr() as *mut Slice<T>);
623+
// Write the length
624+
result.len = slice.len();
625+
626+
// Write the elements
627+
let arena_slice = slice::from_raw_parts_mut(result.data.as_mut_ptr(), result.len);
628+
arena_slice.copy_from_slice(slice);
629+
630+
result
631+
}
632+
}
633+
}
634+
635+
impl<T: fmt::Debug> fmt::Debug for Slice<T> {
636+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
637+
(**self).fmt(f)
638+
}
639+
}
640+
641+
impl<T: Encodable> Encodable for Slice<T> {
642+
#[inline]
643+
fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
644+
(**self).encode(s)
645+
}
646+
}
592647

593648
impl<T> Ord for Slice<T> where T: Ord {
594649
fn cmp(&self, other: &Slice<T>) -> Ordering {
595650
if self == other { Ordering::Equal } else {
596-
<[T] as Ord>::cmp(&self.0, &other.0)
651+
<[T] as Ord>::cmp(&**self, &**other)
597652
}
598653
}
599654
}
600655

601656
impl<T> PartialOrd for Slice<T> where T: PartialOrd {
602657
fn partial_cmp(&self, other: &Slice<T>) -> Option<Ordering> {
603658
if self == other { Some(Ordering::Equal) } else {
604-
<[T] as PartialOrd>::partial_cmp(&self.0, &other.0)
659+
<[T] as PartialOrd>::partial_cmp(&**self, &**other)
605660
}
606661
}
607662
}
608663

609-
impl<T> PartialEq for Slice<T> {
664+
impl<T: PartialEq> PartialEq for Slice<T> {
610665
#[inline]
611666
fn eq(&self, other: &Slice<T>) -> bool {
612-
(&self.0 as *const [T]) == (&other.0 as *const [T])
667+
(self as *const _) == (other as *const _)
613668
}
614669
}
615-
impl<T> Eq for Slice<T> {}
670+
impl<T: Eq> Eq for Slice<T> {}
616671

617672
impl<T> Hash for Slice<T> {
673+
#[inline]
618674
fn hash<H: Hasher>(&self, s: &mut H) {
619-
(self.as_ptr(), self.len()).hash(s)
675+
(self as *const Slice<T>).hash(s)
620676
}
621677
}
622678

623679
impl<T> Deref for Slice<T> {
624680
type Target = [T];
681+
#[inline(always)]
625682
fn deref(&self) -> &[T] {
626-
&self.0
683+
unsafe {
684+
slice::from_raw_parts(self.data.as_ptr(), self.len)
685+
}
627686
}
628687
}
629688

630689
impl<'a, T> IntoIterator for &'a Slice<T> {
631690
type Item = &'a T;
632691
type IntoIter = <&'a [T] as IntoIterator>::IntoIter;
692+
#[inline(always)]
633693
fn into_iter(self) -> Self::IntoIter {
634694
self[..].iter()
635695
}
@@ -638,9 +698,14 @@ impl<'a, T> IntoIterator for &'a Slice<T> {
638698
impl<'tcx> serialize::UseSpecializedDecodable for &'tcx Slice<Ty<'tcx>> {}
639699

640700
impl<T> Slice<T> {
701+
#[inline(always)]
641702
pub fn empty<'a>() -> &'a Slice<T> {
703+
#[repr(align(64), C)]
704+
struct EmptySlice([u8; 64]);
705+
static EMPTY_SLICE: EmptySlice = EmptySlice([0; 64]);
706+
assert!(mem::align_of::<T>() <= 64);
642707
unsafe {
643-
mem::transmute(slice::from_raw_parts(0x1 as *const T, 0))
708+
&*(&EMPTY_SLICE as *const _ as *const Slice<T>)
644709
}
645710
}
646711
}

src/test/mir-opt/basic_assignment.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ fn main() {
4848
// _2 = move _3;
4949
// StorageDead(_3);
5050
// StorageLive(_4);
51-
// UserAssertTy(Canonical { variables: Slice([]), value: std::option::Option<std::boxed::Box<u32>> }, _4);
51+
// UserAssertTy(Canonical { variables: [], value: std::option::Option<std::boxed::Box<u32>> }, _4);
5252
// _4 = std::option::Option<std::boxed::Box<u32>>::None;
5353
// StorageLive(_5);
5454
// StorageLive(_6);

0 commit comments

Comments
 (0)