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 } ;
@@ -85,6 +91,17 @@ impl Layout {
8591 unsafe { Ok ( Layout :: from_size_align_unchecked ( size, align) ) }
8692 }
8793
94+ /// Internal helper constructor to skip revalidating alignment validity.
95+ #[ inline]
96+ const fn from_size_valid_align ( size : usize , align : ValidAlign ) -> Result < Self , LayoutError > {
97+ // See above for the correctness of this check.
98+ if size > isize:: MAX as usize - ( align. as_nonzero ( ) . get ( ) - 1 ) {
99+ return Err ( LayoutError ) ;
100+ }
101+ // SAFTEY: as above, this check is sufficient.
102+ Ok ( Layout { size, align } )
103+ }
104+
88105 /// Creates a layout, bypassing all checks.
89106 ///
90107 /// # Safety
@@ -126,10 +143,9 @@ impl Layout {
126143 #[ inline]
127144 pub const fn new < T > ( ) -> Self {
128145 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.
146+ // SAFETY: if the type is instantiated, rustc already ensures that its
147+ // layout is valid. Use the unchecked constructor to avoid inserting a
148+ // panicking codepath that needs to be optimized out.
133149 unsafe { Layout :: from_size_align_unchecked ( size, align) }
134150 }
135151
@@ -141,7 +157,6 @@ impl Layout {
141157 #[ inline]
142158 pub fn for_value < T : ?Sized > ( t : & T ) -> Self {
143159 let ( size, align) = ( mem:: size_of_val ( t) , mem:: align_of_val ( t) ) ;
144- debug_assert ! ( Layout :: from_size_align( size, align) . is_ok( ) ) ;
145160 // SAFETY: see rationale in `new` for why this is using the unsafe variant
146161 unsafe { Layout :: from_size_align_unchecked ( size, align) }
147162 }
@@ -176,7 +191,6 @@ impl Layout {
176191 pub unsafe fn for_value_raw < T : ?Sized > ( t : * const T ) -> Self {
177192 // SAFETY: we pass along the prerequisites of these functions to the caller
178193 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( ) ) ;
180194 // SAFETY: see rationale in `new` for why this is using the unsafe variant
181195 unsafe { Layout :: from_size_align_unchecked ( size, align) }
182196 }
@@ -280,8 +294,7 @@ impl Layout {
280294 // > less than or equal to `isize::MAX`)
281295 let new_size = self . size ( ) + pad;
282296
283- // SAFETY: self.align is already known to be valid and new_size has been
284- // padded already.
297+ // SAFETY: padded size is guaranteed to not exceed `isize::MAX`.
285298 unsafe { Layout :: from_size_align_unchecked ( new_size, self . align ( ) ) }
286299 }
287300
@@ -304,7 +317,7 @@ impl Layout {
304317 let alloc_size = padded_size. checked_mul ( n) . ok_or ( LayoutError ) ?;
305318
306319 // 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) )
320+ Layout :: from_size_valid_align ( alloc_size, self . align ) . map ( |layout| ( layout, padded_size) )
308321 }
309322
310323 /// Creates a layout describing the record for `self` followed by
@@ -355,14 +368,14 @@ impl Layout {
355368 #[ stable( feature = "alloc_layout_manipulation" , since = "1.44.0" ) ]
356369 #[ inline]
357370 pub fn extend ( & self , next : Self ) -> Result < ( Self , usize ) , LayoutError > {
358- let new_align = cmp:: max ( self . align ( ) , next. align ( ) ) ;
371+ let new_align = cmp:: max ( self . align , next. align ) ;
359372 let pad = self . padding_needed_for ( next. align ( ) ) ;
360373
361374 let offset = self . size ( ) . checked_add ( pad) . ok_or ( LayoutError ) ?;
362375 let new_size = offset. checked_add ( next. size ( ) ) . ok_or ( LayoutError ) ?;
363376
364377 // The safe constructor is called here to enforce the isize size limit.
365- let layout = Layout :: from_size_align ( new_size, new_align) ?;
378+ let layout = Layout :: from_size_valid_align ( new_size, new_align) ?;
366379 Ok ( ( layout, offset) )
367380 }
368381
@@ -383,7 +396,7 @@ impl Layout {
383396 pub fn repeat_packed ( & self , n : usize ) -> Result < Self , LayoutError > {
384397 let size = self . size ( ) . checked_mul ( n) . ok_or ( LayoutError ) ?;
385398 // The safe constructor is called here to enforce the isize size limit.
386- Layout :: from_size_align ( size, self . align ( ) )
399+ Layout :: from_size_valid_align ( size, self . align )
387400 }
388401
389402 /// Creates a layout describing the record for `self` followed by
@@ -397,7 +410,7 @@ impl Layout {
397410 pub fn extend_packed ( & self , next : Self ) -> Result < Self , LayoutError > {
398411 let new_size = self . size ( ) . checked_add ( next. size ( ) ) . ok_or ( LayoutError ) ?;
399412 // The safe constructor is called here to enforce the isize size limit.
400- Layout :: from_size_align ( new_size, self . align ( ) )
413+ Layout :: from_size_valid_align ( new_size, self . align )
401414 }
402415
403416 /// Creates a layout describing the record for a `[T; n]`.
@@ -408,7 +421,7 @@ impl Layout {
408421 pub fn array < T > ( n : usize ) -> Result < Self , LayoutError > {
409422 let array_size = mem:: size_of :: < T > ( ) . checked_mul ( n) . ok_or ( LayoutError ) ?;
410423 // The safe constructor is called here to enforce the isize size limit.
411- Layout :: from_size_align ( array_size, mem :: align_of :: < T > ( ) )
424+ Layout :: from_size_valid_align ( array_size, ValidAlign :: of :: < T > ( ) )
412425 }
413426}
414427
0 commit comments