@@ -8,7 +8,6 @@ use lazy_static::lazy_static;
8
8
use quote:: ToTokens ;
9
9
use syn:: Type ;
10
10
11
- use crate :: util:: { Bits , FromBits , ToBits } ;
12
11
use crate :: {
13
12
schema:: { REnum , RStruct , RType } ,
14
13
util:: { NormalizeError , TypeAnalyzeResult , TypeExt , TypeWrapper } ,
@@ -23,8 +22,8 @@ pub enum Layout {
23
22
}
24
23
25
24
impl Layout {
26
- const fn known ( size : usize , align : usize , trailing_pad : usize , fragmented_bits : Bits ) -> Self {
27
- Self :: Layout ( KnownLayout { size, align, trailing_pad, fragmented_bits } )
25
+ const fn known ( size : usize , align : usize , trailing_pad : usize , niches : u128 ) -> Self {
26
+ Self :: Layout ( KnownLayout { size, align, trailing_pad, niches } )
28
27
}
29
28
30
29
pub fn layout ( self ) -> Option < KnownLayout > {
@@ -48,9 +47,8 @@ pub struct KnownLayout {
48
47
align : usize ,
49
48
/// padding at the end of type to align it
50
49
trailing_pad : usize ,
51
- /// number of unused bits scatered throughout layout, this doesn't contain the `trailing_pad`
52
- /// bits.
53
- fragmented_bits : Bits ,
50
+ /// number of available niches
51
+ niches : u128 ,
54
52
}
55
53
56
54
impl KnownLayout {
@@ -73,31 +71,31 @@ impl KnownLayout {
73
71
/// number of unused bits scatered throughout layout, this doesn't contain the `trailing_pad`
74
72
/// bits.
75
73
#[ inline]
76
- pub fn fragmented_bits ( & self ) -> Bits {
77
- self . fragmented_bits
74
+ pub fn niches ( & self ) -> u128 {
75
+ self . niches
78
76
}
79
77
80
78
/// Panics
81
79
/// if doesn't have enough viable space and `can_resize` is false
82
- pub fn consume_trailing_pad ( & mut self , size : usize , can_resize : bool ) {
83
- self . consume_bits ( size . to_bits ( ) , false , can_resize ) ;
80
+ pub fn consume_trailing_pad ( & mut self , size : usize ) {
81
+ self . trailing_pad -= size ;
84
82
}
85
83
86
84
/// Panics
87
85
/// if doesn't have enough viable space and `can_resize` is false
88
- pub fn consume_bits ( & mut self , bits : Bits , can_be_fragmented : bool , can_resize : bool ) {
89
- if can_be_fragmented && self . fragmented_bits ( ) >= bits {
90
- self . fragmented_bits -= 1 ;
91
- } else if self . trailing_pad ( ) > 0 {
86
+ pub fn consume_niches ( & mut self , n : u128 , can_eat_pad : bool , can_resize : bool ) {
87
+ if self . niches ( ) >= n {
88
+ self . niches -= 1 ;
89
+ } else if can_eat_pad && self . trailing_pad ( ) > 0 {
92
90
// consume one byte of padding at the end
93
91
self . trailing_pad -= 1 ;
94
- // consume one bit of that byte and add the remaining unused bits as fragmented space .
95
- self . fragmented_bits = 1 . to_bits ( ) - 1 ;
92
+ // consume one and add the remaining values of one byte as niches .
93
+ self . niches = ( u8 :: MAX - 1 ) as u128 ;
96
94
} else if can_resize {
97
95
let align = self . align ( ) ;
98
96
self . size += align;
99
97
self . trailing_pad += align;
100
- self . consume_bits ( bits , can_be_fragmented , can_resize) ;
98
+ self . consume_niches ( n , can_eat_pad , can_resize) ;
101
99
} else {
102
100
panic ! ( "`consume_bit` called on a layout without enough space." ) ;
103
101
}
@@ -114,43 +112,44 @@ impl Layout {
114
112
/// If alignment of `T` is higher than one byte.
115
113
const fn of < T > ( ) -> Self {
116
114
// TODO: find a better way of calculating this.
117
- struct Bit1 < T > ( Option < T > ) ;
118
- struct Bit2 < T > ( Bit1 < Bit1 < T > > ) ;
119
- struct Bit3 < T > ( Bit1 < Bit2 < T > > ) ;
120
- struct Bit4 < T > ( Bit1 < Bit3 < T > > ) ;
121
- struct Bit5 < T > ( Bit1 < Bit4 < T > > ) ;
122
- struct Bit6 < T > ( Bit1 < Bit5 < T > > ) ;
123
- struct Bit7 < T > ( Bit1 < Bit6 < T > > ) ;
124
- struct Bit8 < T > ( Bit1 < Bit7 < T > > ) ;
115
+ struct N1 < T > ( Option < T > ) ;
116
+ struct N2 < T > ( N1 < N1 < T > > ) ;
117
+ struct N3 < T > ( N1 < N2 < T > > ) ;
118
+ struct N4 < T > ( N1 < N3 < T > > ) ;
119
+ struct N5 < T > ( N1 < N4 < T > > ) ;
120
+ struct N6 < T > ( N1 < N5 < T > > ) ;
121
+ struct N7 < T > ( N1 < N6 < T > > ) ;
122
+ struct N8 < T > ( N1 < N7 < T > > ) ;
125
123
126
124
let size = size_of :: < T > ( ) ;
127
125
let align = align_of :: < T > ( ) ;
128
- let fragmented_bits = if size_of :: < Bit1 < T > > ( ) > size {
126
+ let niches = if size_of :: < N1 < T > > ( ) > size {
129
127
0
130
- } else if size_of :: < Bit2 < T > > ( ) > size {
128
+ } else if size_of :: < N2 < T > > ( ) > size {
131
129
1
132
- } else if size_of :: < Bit3 < T > > ( ) > size {
130
+ } else if size_of :: < N3 < T > > ( ) > size {
133
131
2
134
- } else if size_of :: < Bit4 < T > > ( ) > size {
132
+ } else if size_of :: < N4 < T > > ( ) > size {
135
133
3
136
- } else if size_of :: < Bit5 < T > > ( ) > size {
134
+ } else if size_of :: < N5 < T > > ( ) > size {
137
135
4
138
- } else if size_of :: < Bit6 < T > > ( ) > size {
136
+ } else if size_of :: < N6 < T > > ( ) > size {
139
137
5
140
- } else if size_of :: < Bit7 < T > > ( ) > size {
138
+ } else if size_of :: < N7 < T > > ( ) > size {
141
139
6
142
- } else if size_of :: < Bit8 < T > > ( ) > size {
140
+ } else if size_of :: < N8 < T > > ( ) > size {
143
141
7
144
- } else if size_of :: < Bit8 < T > > ( ) == size {
142
+ } else if size_of :: < N8 < T > > ( ) == size {
145
143
8
146
144
} else {
147
145
panic ! (
148
146
"Alignment of `T` is bigger than what this method can calculate the headroom for."
149
147
) ;
150
148
} ;
151
- // NOTE: some or all of `fragmented_bits ` might be `trailing_pad` but we don't need to
149
+ // NOTE: some or all of `niches ` might be `trailing_pad` but we don't need to
152
150
// distinguish between them. This method is only used to get layout info of simple types.
153
- Self :: known ( size, align, 0 , fragmented_bits)
151
+ // most of them are builtin primitives.
152
+ Self :: known ( size, align, 0 , niches)
154
153
}
155
154
156
155
const fn zero ( ) -> Self {
@@ -336,13 +335,9 @@ fn calc_enum_layout(ty: &mut REnum, ctx: &CodegenCtx) -> Result<PlatformLayout>
336
335
// all unit variants?
337
336
if ty. item . variants . iter ( ) . all ( |var| var. fields . is_empty ( ) ) {
338
337
// all AST enums are `repr(C)` so it would have a 4 byte layout/alignment,
339
- const TAG_SIZE : usize = 4 ;
340
- const TAG_ALIGN : usize = 4 ;
341
- let var_len = ty. item . variants . len ( ) ;
342
- // We use one bit per each variant to identify it, The rest are unused bits.
343
- let unused_bits = 4 . to_bits ( ) - var_len as Bits ;
344
- let ( padding_bytes, fragmented_bits) = usize:: from_bits ( unused_bits) ;
345
- let layout = Layout :: known ( TAG_SIZE , TAG_ALIGN , padding_bytes, fragmented_bits) ;
338
+ let mut layout = KnownLayout { size : 0 , align : 4 , trailing_pad : 0 , niches : 0 } ;
339
+ layout. consume_niches ( ty. item . variants . len ( ) as u128 , true , true ) ;
340
+ let layout = Layout :: Layout ( layout) ;
346
341
Ok ( vec ! [ PlatformLayout ( layout, layout) ] )
347
342
} else {
348
343
ty. item
@@ -370,17 +365,17 @@ fn calc_enum_layout(ty: &mut REnum, ctx: &CodegenCtx) -> Result<PlatformLayout>
370
365
if layout. trailing_pad ( ) < acc. trailing_pad ( ) {
371
366
acc. trailing_pad = layout. trailing_pad ( ) ;
372
367
}
373
- // min fragmented_bits
374
- if layout. fragmented_bits ( ) < acc. fragmented_bits ( ) {
375
- acc. fragmented_bits = layout. fragmented_bits ( ) ;
368
+ // min niches
369
+ if layout. niches ( ) < acc. niches ( ) {
370
+ acc. niches = layout. niches ( ) ;
376
371
}
377
372
acc
378
373
}
379
374
380
- fn with_tag ( mut acc : KnownLayout ) -> KnownLayout {
381
- acc. consume_bits ( size_of :: < u8 > ( ) . to_bits ( ) , false , true ) ;
375
+ let with_tag = | mut acc : KnownLayout | -> KnownLayout {
376
+ acc. consume_niches ( ty . item . variants . len ( ) as u128 , true , true ) ;
382
377
acc
383
- }
378
+ } ;
384
379
385
380
let layouts = collect_variant_layouts ( ty, ctx) ?;
386
381
let ( layouts_x64, layouts_x32) : ( Vec < KnownLayout > , Vec < KnownLayout > ) = layouts
@@ -391,14 +386,16 @@ fn calc_enum_layout(ty: &mut REnum, ctx: &CodegenCtx) -> Result<PlatformLayout>
391
386
. collect :: < Option < _ > > ( )
392
387
. expect ( "already checked." ) ;
393
388
394
- let x32 = with_tag ( layouts_x32. into_iter ( ) . fold (
395
- KnownLayout { size : 0 , align : 0 , trailing_pad : usize:: MAX , fragmented_bits : 0 } ,
396
- fold_layout,
397
- ) ) ;
398
- let x64 = with_tag ( layouts_x64. into_iter ( ) . fold (
399
- KnownLayout { size : 0 , align : 0 , trailing_pad : usize:: MAX , fragmented_bits : 0 } ,
400
- fold_layout,
401
- ) ) ;
389
+ let x32 =
390
+ with_tag ( layouts_x32. into_iter ( ) . fold (
391
+ KnownLayout { size : 0 , align : 0 , trailing_pad : usize:: MAX , niches : 0 } ,
392
+ fold_layout,
393
+ ) ) ;
394
+ let x64 =
395
+ with_tag ( layouts_x64. into_iter ( ) . fold (
396
+ KnownLayout { size : 0 , align : 0 , trailing_pad : usize:: MAX , niches : 0 } ,
397
+ fold_layout,
398
+ ) ) ;
402
399
Ok ( PlatformLayout ( Layout :: from ( x64) , Layout :: from ( x32) ) )
403
400
}
404
401
@@ -424,13 +421,13 @@ fn calc_struct_layout(ty: &mut RStruct, ctx: &CodegenCtx) -> Result<PlatformLayo
424
421
// TODO: store `offsets` in the layout
425
422
let mut offsets = Vec :: new ( ) ;
426
423
let mut output = std:: alloc:: Layout :: from_size_align ( 0 , 1 ) ?;
427
- let mut fragmented_bits = 0 ;
424
+ let mut niches = 0 ;
428
425
for layout in layouts {
429
426
let ( new_layout, offset) =
430
427
output. extend ( std:: alloc:: Layout :: from_size_align ( layout. size , layout. align ) ?) ?;
431
428
output = new_layout;
432
429
offsets. push ( offset) ;
433
- fragmented_bits += layout. fragmented_bits ( ) ;
430
+ niches += layout. niches ( ) ;
434
431
}
435
432
// TODO: use `std::alloc::Layout::padding_needed_for` when it stabilized
436
433
let ( pad, output) = {
@@ -442,7 +439,7 @@ fn calc_struct_layout(ty: &mut RStruct, ctx: &CodegenCtx) -> Result<PlatformLayo
442
439
size : output. size ( ) ,
443
440
align : output. align ( ) ,
444
441
trailing_pad : pad + layouts. last ( ) . map ( KnownLayout :: trailing_pad) . unwrap_or_default ( ) ,
445
- fragmented_bits ,
442
+ niches ,
446
443
} )
447
444
}
448
445
@@ -479,7 +476,7 @@ fn calc_type_layout(ty: &TypeAnalyzeResult, ctx: &CodegenCtx) -> Result<Platform
479
476
fn try_fold_option ( layout : Layout ) -> Layout {
480
477
let Layout :: Layout ( mut known) = layout else { return layout } ;
481
478
// option needs only one bit to store its tag and it can be in a fragmented offset
482
- known. consume_bits ( 1 , true , true ) ;
479
+ known. consume_niches ( 1 , true , true ) ;
483
480
Layout :: Layout ( known)
484
481
}
485
482
0 commit comments