1+ // Seemingly inconsequential code changes to this file can lead to measurable
2+ // performance impact on compilation times, due at least in part to the fact
3+ // that the layout code gets called from many instantiations of the various
4+ // collections, resulting in having to optimize down excess IR multiple times.
5+ // Your performance intuition is useless. Run perf.
6+
17use crate :: cmp;
28use crate :: fmt;
39use crate :: mem:: { self , ValidAlign } ;
@@ -62,6 +68,13 @@ impl Layout {
6268 return Err ( LayoutError ) ;
6369 }
6470
71+ // SAFETY: just checked that align is a power of two.
72+ Layout :: from_size_valid_align ( size, unsafe { ValidAlign :: new_unchecked ( align) } )
73+ }
74+
75+ /// Internal helper constructor to skip revalidating alignment validity.
76+ #[ inline]
77+ const fn from_size_valid_align ( size : usize , align : ValidAlign ) -> Result < Self , LayoutError > {
6578 // (power-of-two implies align != 0.)
6679
6780 // Rounded up size is:
@@ -76,13 +89,12 @@ impl Layout {
7689 //
7790 // Above implies that checking for summation overflow is both
7891 // necessary and sufficient.
79- if size > isize:: MAX as usize - ( align - 1 ) {
92+ if size > isize:: MAX as usize - ( align. as_nonzero ( ) . get ( ) - 1 ) {
8093 return Err ( LayoutError ) ;
8194 }
8295
83- // SAFETY: the conditions for `from_size_align_unchecked` have been
84- // checked above.
85- unsafe { Ok ( Layout :: from_size_align_unchecked ( size, align) ) }
96+ // SAFETY: Layout::size invariants checked above.
97+ Ok ( Layout { size, align } )
8698 }
8799
88100 /// Creates a layout, bypassing all checks.
@@ -96,8 +108,8 @@ impl Layout {
96108 #[ must_use]
97109 #[ inline]
98110 pub const unsafe fn from_size_align_unchecked ( size : usize , align : usize ) -> Self {
99- // SAFETY: the caller must ensure that `align` is a power of two .
100- Layout { size, align : unsafe { ValidAlign :: new_unchecked ( align) } }
111+ // SAFETY: the caller is required to uphold the preconditions .
112+ unsafe { Layout { size, align : ValidAlign :: new_unchecked ( align) } }
101113 }
102114
103115 /// The minimum size in bytes for a memory block of this layout.
@@ -126,10 +138,9 @@ impl Layout {
126138 #[ inline]
127139 pub const fn new < T > ( ) -> Self {
128140 let ( size, align) = size_align :: < T > ( ) ;
129- // SAFETY: the align is guaranteed by Rust to be a power of two and
130- // the size+align combo is guaranteed to fit in our address space. As a
131- // result use the unchecked constructor here to avoid inserting code
132- // that panics if it isn't optimized well enough.
141+ // SAFETY: if the type is instantiated, rustc already ensures that its
142+ // layout is valid. Use the unchecked constructor to avoid inserting a
143+ // panicking codepath that needs to be optimized out.
133144 unsafe { Layout :: from_size_align_unchecked ( size, align) }
134145 }
135146
@@ -141,7 +152,6 @@ impl Layout {
141152 #[ inline]
142153 pub fn for_value < T : ?Sized > ( t : & T ) -> Self {
143154 let ( size, align) = ( mem:: size_of_val ( t) , mem:: align_of_val ( t) ) ;
144- debug_assert ! ( Layout :: from_size_align( size, align) . is_ok( ) ) ;
145155 // SAFETY: see rationale in `new` for why this is using the unsafe variant
146156 unsafe { Layout :: from_size_align_unchecked ( size, align) }
147157 }
@@ -176,7 +186,6 @@ impl Layout {
176186 pub unsafe fn for_value_raw < T : ?Sized > ( t : * const T ) -> Self {
177187 // SAFETY: we pass along the prerequisites of these functions to the caller
178188 let ( size, align) = unsafe { ( mem:: size_of_val_raw ( t) , mem:: align_of_val_raw ( t) ) } ;
179- debug_assert ! ( Layout :: from_size_align( size, align) . is_ok( ) ) ;
180189 // SAFETY: see rationale in `new` for why this is using the unsafe variant
181190 unsafe { Layout :: from_size_align_unchecked ( size, align) }
182191 }
@@ -280,8 +289,7 @@ impl Layout {
280289 // > less than or equal to `isize::MAX`)
281290 let new_size = self . size ( ) + pad;
282291
283- // SAFETY: self.align is already known to be valid and new_size has been
284- // padded already.
292+ // SAFETY: padded size is guaranteed to not exceed `isize::MAX`.
285293 unsafe { Layout :: from_size_align_unchecked ( new_size, self . align ( ) ) }
286294 }
287295
@@ -304,7 +312,7 @@ impl Layout {
304312 let alloc_size = padded_size. checked_mul ( n) . ok_or ( LayoutError ) ?;
305313
306314 // The safe constructor is called here to enforce the isize size limit.
307- Layout :: from_size_align ( alloc_size, self . align ( ) ) . map ( |layout| ( layout, padded_size) )
315+ Layout :: from_size_valid_align ( alloc_size, self . align ) . map ( |layout| ( layout, padded_size) )
308316 }
309317
310318 /// Creates a layout describing the record for `self` followed by
@@ -355,14 +363,14 @@ impl Layout {
355363 #[ stable( feature = "alloc_layout_manipulation" , since = "1.44.0" ) ]
356364 #[ inline]
357365 pub fn extend ( & self , next : Self ) -> Result < ( Self , usize ) , LayoutError > {
358- let new_align = cmp:: max ( self . align ( ) , next. align ( ) ) ;
366+ let new_align = cmp:: max ( self . align , next. align ) ;
359367 let pad = self . padding_needed_for ( next. align ( ) ) ;
360368
361369 let offset = self . size ( ) . checked_add ( pad) . ok_or ( LayoutError ) ?;
362370 let new_size = offset. checked_add ( next. size ( ) ) . ok_or ( LayoutError ) ?;
363371
364372 // The safe constructor is called here to enforce the isize size limit.
365- let layout = Layout :: from_size_align ( new_size, new_align) ?;
373+ let layout = Layout :: from_size_valid_align ( new_size, new_align) ?;
366374 Ok ( ( layout, offset) )
367375 }
368376
@@ -383,7 +391,7 @@ impl Layout {
383391 pub fn repeat_packed ( & self , n : usize ) -> Result < Self , LayoutError > {
384392 let size = self . size ( ) . checked_mul ( n) . ok_or ( LayoutError ) ?;
385393 // The safe constructor is called here to enforce the isize size limit.
386- Layout :: from_size_align ( size, self . align ( ) )
394+ Layout :: from_size_valid_align ( size, self . align )
387395 }
388396
389397 /// Creates a layout describing the record for `self` followed by
@@ -397,7 +405,7 @@ impl Layout {
397405 pub fn extend_packed ( & self , next : Self ) -> Result < Self , LayoutError > {
398406 let new_size = self . size ( ) . checked_add ( next. size ( ) ) . ok_or ( LayoutError ) ?;
399407 // The safe constructor is called here to enforce the isize size limit.
400- Layout :: from_size_align ( new_size, self . align ( ) )
408+ Layout :: from_size_valid_align ( new_size, self . align )
401409 }
402410
403411 /// Creates a layout describing the record for a `[T; n]`.
@@ -408,7 +416,7 @@ impl Layout {
408416 pub fn array < T > ( n : usize ) -> Result < Self , LayoutError > {
409417 let array_size = mem:: size_of :: < T > ( ) . checked_mul ( n) . ok_or ( LayoutError ) ?;
410418 // The safe constructor is called here to enforce the isize size limit.
411- Layout :: from_size_align ( array_size, mem :: align_of :: < T > ( ) )
419+ Layout :: from_size_valid_align ( array_size, ValidAlign :: of :: < T > ( ) )
412420 }
413421}
414422
0 commit comments