Skip to content

Commit 0ebd4eb

Browse files
committed
fix: implement niches instead of fragmented bits.
1 parent 5f47351 commit 0ebd4eb

File tree

2 files changed

+58
-101
lines changed

2 files changed

+58
-101
lines changed

tasks/ast_codegen/src/layout.rs

Lines changed: 58 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ use lazy_static::lazy_static;
88
use quote::ToTokens;
99
use syn::Type;
1010

11-
use crate::util::{Bits, FromBits, ToBits};
1211
use crate::{
1312
schema::{REnum, RStruct, RType},
1413
util::{NormalizeError, TypeAnalyzeResult, TypeExt, TypeWrapper},
@@ -23,8 +22,8 @@ pub enum Layout {
2322
}
2423

2524
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 })
2827
}
2928

3029
pub fn layout(self) -> Option<KnownLayout> {
@@ -48,9 +47,8 @@ pub struct KnownLayout {
4847
align: usize,
4948
/// padding at the end of type to align it
5049
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,
5452
}
5553

5654
impl KnownLayout {
@@ -73,31 +71,31 @@ impl KnownLayout {
7371
/// number of unused bits scatered throughout layout, this doesn't contain the `trailing_pad`
7472
/// bits.
7573
#[inline]
76-
pub fn fragmented_bits(&self) -> Bits {
77-
self.fragmented_bits
74+
pub fn niches(&self) -> u128 {
75+
self.niches
7876
}
7977

8078
/// Panics
8179
/// 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;
8482
}
8583

8684
/// Panics
8785
/// 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 {
9290
// consume one byte of padding at the end
9391
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;
9694
} else if can_resize {
9795
let align = self.align();
9896
self.size += align;
9997
self.trailing_pad += align;
100-
self.consume_bits(bits, can_be_fragmented, can_resize);
98+
self.consume_niches(n, can_eat_pad, can_resize);
10199
} else {
102100
panic!("`consume_bit` called on a layout without enough space.");
103101
}
@@ -114,43 +112,44 @@ impl Layout {
114112
/// If alignment of `T` is higher than one byte.
115113
const fn of<T>() -> Self {
116114
// 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>>);
125123

126124
let size = size_of::<T>();
127125
let align = align_of::<T>();
128-
let fragmented_bits = if size_of::<Bit1<T>>() > size {
126+
let niches = if size_of::<N1<T>>() > size {
129127
0
130-
} else if size_of::<Bit2<T>>() > size {
128+
} else if size_of::<N2<T>>() > size {
131129
1
132-
} else if size_of::<Bit3<T>>() > size {
130+
} else if size_of::<N3<T>>() > size {
133131
2
134-
} else if size_of::<Bit4<T>>() > size {
132+
} else if size_of::<N4<T>>() > size {
135133
3
136-
} else if size_of::<Bit5<T>>() > size {
134+
} else if size_of::<N5<T>>() > size {
137135
4
138-
} else if size_of::<Bit6<T>>() > size {
136+
} else if size_of::<N6<T>>() > size {
139137
5
140-
} else if size_of::<Bit7<T>>() > size {
138+
} else if size_of::<N7<T>>() > size {
141139
6
142-
} else if size_of::<Bit8<T>>() > size {
140+
} else if size_of::<N8<T>>() > size {
143141
7
144-
} else if size_of::<Bit8<T>>() == size {
142+
} else if size_of::<N8<T>>() == size {
145143
8
146144
} else {
147145
panic!(
148146
"Alignment of `T` is bigger than what this method can calculate the headroom for."
149147
);
150148
};
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
152150
// 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)
154153
}
155154

156155
const fn zero() -> Self {
@@ -336,13 +335,9 @@ fn calc_enum_layout(ty: &mut REnum, ctx: &CodegenCtx) -> Result<PlatformLayout>
336335
// all unit variants?
337336
if ty.item.variants.iter().all(|var| var.fields.is_empty()) {
338337
// 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);
346341
Ok(vec![PlatformLayout(layout, layout)])
347342
} else {
348343
ty.item
@@ -370,17 +365,17 @@ fn calc_enum_layout(ty: &mut REnum, ctx: &CodegenCtx) -> Result<PlatformLayout>
370365
if layout.trailing_pad() < acc.trailing_pad() {
371366
acc.trailing_pad = layout.trailing_pad();
372367
}
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();
376371
}
377372
acc
378373
}
379374

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);
382377
acc
383-
}
378+
};
384379

385380
let layouts = collect_variant_layouts(ty, ctx)?;
386381
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>
391386
.collect::<Option<_>>()
392387
.expect("already checked.");
393388

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+
));
402399
Ok(PlatformLayout(Layout::from(x64), Layout::from(x32)))
403400
}
404401

@@ -424,13 +421,13 @@ fn calc_struct_layout(ty: &mut RStruct, ctx: &CodegenCtx) -> Result<PlatformLayo
424421
// TODO: store `offsets` in the layout
425422
let mut offsets = Vec::new();
426423
let mut output = std::alloc::Layout::from_size_align(0, 1)?;
427-
let mut fragmented_bits = 0;
424+
let mut niches = 0;
428425
for layout in layouts {
429426
let (new_layout, offset) =
430427
output.extend(std::alloc::Layout::from_size_align(layout.size, layout.align)?)?;
431428
output = new_layout;
432429
offsets.push(offset);
433-
fragmented_bits += layout.fragmented_bits();
430+
niches += layout.niches();
434431
}
435432
// TODO: use `std::alloc::Layout::padding_needed_for` when it stabilized
436433
let (pad, output) = {
@@ -442,7 +439,7 @@ fn calc_struct_layout(ty: &mut RStruct, ctx: &CodegenCtx) -> Result<PlatformLayo
442439
size: output.size(),
443440
align: output.align(),
444441
trailing_pad: pad + layouts.last().map(KnownLayout::trailing_pad).unwrap_or_default(),
445-
fragmented_bits,
442+
niches,
446443
})
447444
}
448445

@@ -479,7 +476,7 @@ fn calc_type_layout(ty: &TypeAnalyzeResult, ctx: &CodegenCtx) -> Result<Platform
479476
fn try_fold_option(layout: Layout) -> Layout {
480477
let Layout::Layout(mut known) = layout else { return layout };
481478
// 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);
483480
Layout::Layout(known)
484481
}
485482

tasks/ast_codegen/src/util.rs

Lines changed: 0 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -59,19 +59,6 @@ pub trait StrExt: AsRef<str> {
5959
fn to_plural(self) -> String;
6060
}
6161

62-
pub type Bits = u128;
63-
64-
pub trait ToBits {
65-
/// Returns number of bits in the given bytes, basiaclly `self * 8`
66-
fn to_bits(&self) -> Bits;
67-
}
68-
69-
pub trait FromBits {
70-
/// Returns number of bytes that can be constructed from the given bits and the leftover
71-
/// fragmented bits.
72-
fn from_bits(bits: Bits) -> (usize, /* fragments */ Bits);
73-
}
74-
7562
#[derive(Debug)]
7663
pub enum TypeIdentResult<'a> {
7764
/// We bailed on detecting wrapper
@@ -298,30 +285,3 @@ pub fn write_all_to<S: AsRef<str>>(data: &[u8], path: S) -> std::io::Result<()>
298285
file.write_all(data)?;
299286
Ok(())
300287
}
301-
302-
impl ToBits for usize {
303-
#[inline]
304-
fn to_bits(&self) -> Bits {
305-
bits_from_bytes(*self)
306-
}
307-
}
308-
309-
impl FromBits for usize {
310-
#[inline]
311-
fn from_bits(bits: Bits) -> (Self, Bits) {
312-
bits_to_bytes(bits)
313-
}
314-
}
315-
316-
/// Returns number of bits in the given bytes, basiaclly `bytes * 8`
317-
#[inline]
318-
pub const fn bits_from_bytes(bytes: usize) -> Bits {
319-
bytes as Bits * 8
320-
}
321-
322-
#[inline]
323-
pub fn bits_to_bytes(bits: Bits) -> (usize, /* fragments */ Bits) {
324-
let frag = bits % 8;
325-
let bits = bits - frag;
326-
((bits / 8) as usize, frag)
327-
}

0 commit comments

Comments
 (0)