Skip to content

Commit 852db65

Browse files
author
bors-servo
authored
Auto merge of #512 - emilio:bitfields, r=fitzgen
Rework how bitfields are handled. This fixes #111, and unblocks stylo. The problem with this as of right now is that it drops the accessors (though before that this code was buggy so I'm not sure it's a loss). I can probably try to re-implement those (though it'd be more complex). WDYT @fitzgen? Also, note that I changed the max_align_nonce because it was incorrect (we shouldn't generate padding, because `long double` was `128` bits).
2 parents ac49717 + b14adc3 commit 852db65

21 files changed

+516
-953
lines changed

Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ name = "bindgen"
1313
readme = "README.md"
1414
repository = "https://github.com/servo/rust-bindgen"
1515
documentation = "https://docs.rs/bindgen"
16-
version = "0.21.3"
16+
version = "0.22.0"
1717
build = "build.rs"
1818

1919
exclude = ["tests/headers", "tests/expectations", "bindgen-integration", "ci"]

build.rs

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ mod codegen {
1111
quasi_codegen::expand(&src, &dst).unwrap();
1212
println!("cargo:rerun-if-changed=src/codegen/mod.rs");
1313
println!("cargo:rerun-if-changed=src/codegen/helpers.rs");
14+
println!("cargo:rerun-if-changed=src/codegen/struct_layout.rs");
1415
}
1516
}
1617

src/codegen/mod.rs

+86-84
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ mod helpers;
22
mod struct_layout;
33

44
use self::helpers::{BlobTyBuilder, attributes};
5-
use self::struct_layout::StructLayoutTracker;
5+
use self::struct_layout::{align_to, bytes_from_bits};
6+
use self::struct_layout::{bytes_from_bits_pow2, StructLayoutTracker};
67
use aster;
78

89
use ir::annotations::FieldAccessorKind;
@@ -363,8 +364,7 @@ impl CodeGenerator for Module {
363364
}
364365

365366
if item.id() == ctx.root_module() {
366-
let saw_union = result.saw_union;
367-
if saw_union && !ctx.options().unstable_rust {
367+
if result.saw_union && !ctx.options().unstable_rust {
368368
utils::prepend_union_types(ctx, &mut *result);
369369
}
370370
if result.saw_incomplete_array {
@@ -717,12 +717,12 @@ impl<'a> ItemToRustTy for Vtable<'a> {
717717
}
718718

719719
struct Bitfield<'a> {
720-
index: usize,
720+
index: &'a mut usize,
721721
fields: Vec<&'a Field>,
722722
}
723723

724724
impl<'a> Bitfield<'a> {
725-
fn new(index: usize, fields: Vec<&'a Field>) -> Self {
725+
fn new(index: &'a mut usize, fields: Vec<&'a Field>) -> Self {
726726
Bitfield {
727727
index: index,
728728
fields: fields,
@@ -732,89 +732,96 @@ impl<'a> Bitfield<'a> {
732732
fn codegen_fields(self,
733733
ctx: &BindgenContext,
734734
fields: &mut Vec<ast::StructField>,
735-
methods: &mut Vec<ast::ImplItem>)
735+
_methods: &mut Vec<ast::ImplItem>)
736736
-> Layout {
737737
use aster::struct_field::StructFieldBuilder;
738-
let mut total_width = self.fields
739-
.iter()
740-
.fold(0u32, |acc, f| acc + f.bitfield().unwrap());
741-
742-
if !total_width.is_power_of_two() || total_width < 8 {
743-
total_width = cmp::max(8, total_width.next_power_of_two());
744-
}
745-
debug_assert_eq!(total_width % 8, 0);
746-
let total_width_in_bytes = total_width as usize / 8;
747-
748-
let bitfield_layout = Layout::new(total_width_in_bytes,
749-
total_width_in_bytes);
750-
let bitfield_type = BlobTyBuilder::new(bitfield_layout).build();
751-
let field_name = format!("_bitfield_{}", self.index);
752-
let field_ident = ctx.ext_cx().ident_of(&field_name);
753-
let field = StructFieldBuilder::named(&field_name)
754-
.pub_()
755-
.build_ty(bitfield_type.clone());
756-
fields.push(field);
757738

739+
// NOTE: What follows is reverse-engineered from LLVM's
740+
// lib/AST/RecordLayoutBuilder.cpp
741+
//
742+
// FIXME(emilio): There are some differences between Microsoft and the
743+
// Itanium ABI, but we'll ignore those and stick to Itanium for now.
744+
//
745+
// Also, we need to handle packed bitfields and stuff.
746+
// TODO(emilio): Take into account C++'s wide bitfields, and
747+
// packing, sigh.
748+
let mut total_size_in_bits = 0;
749+
let mut max_align = 0;
750+
let mut unfilled_bits_in_last_unit = 0;
751+
let mut field_size_in_bits = 0;
752+
*self.index += 1;
753+
let mut last_field_name = format!("_bitfield_{}", self.index);
754+
let mut last_field_align = 0;
758755

759-
let mut offset = 0;
760756
for field in self.fields {
761757
let width = field.bitfield().unwrap();
762-
let field_name = field.name()
763-
.map(ToOwned::to_owned)
764-
.unwrap_or_else(|| format!("at_offset_{}", offset));
765-
766758
let field_item = ctx.resolve_item(field.ty());
767759
let field_ty_layout = field_item.kind()
768760
.expect_type()
769761
.layout(ctx)
770762
.expect("Bitfield without layout? Gah!");
771763

772-
let field_type = field_item.to_rust_ty(ctx);
773-
let int_type = BlobTyBuilder::new(field_ty_layout).build();
764+
let field_align = field_ty_layout.align;
774765

775-
let getter_name = ctx.rust_ident(&field_name);
776-
let setter_name = ctx.ext_cx()
777-
.ident_of(&format!("set_{}", &field_name));
778-
let mask = ((1usize << width) - 1) << offset;
779-
let prefix = ctx.trait_prefix();
780-
// The transmute is unfortunate, but it's needed for enums in
781-
// bitfields.
782-
let item = quote_item!(ctx.ext_cx(),
783-
impl X {
784-
#[inline]
785-
pub fn $getter_name(&self) -> $field_type {
786-
unsafe {
787-
::$prefix::mem::transmute(
788-
(
789-
(self.$field_ident &
790-
($mask as $bitfield_type))
791-
>> $offset
792-
) as $int_type
793-
)
794-
}
795-
}
766+
if field_size_in_bits != 0 &&
767+
(width == 0 || width as usize > unfilled_bits_in_last_unit) {
768+
field_size_in_bits = align_to(field_size_in_bits, field_align);
769+
// Push the new field.
770+
let ty =
771+
BlobTyBuilder::new(Layout::new(bytes_from_bits_pow2(field_size_in_bits),
772+
bytes_from_bits_pow2(last_field_align)))
773+
.build();
796774

797-
#[inline]
798-
pub fn $setter_name(&mut self, val: $field_type) {
799-
self.$field_ident &= !($mask as $bitfield_type);
800-
self.$field_ident |=
801-
(val as $int_type as $bitfield_type << $offset) &
802-
($mask as $bitfield_type);
803-
}
804-
}
805-
)
806-
.unwrap();
775+
let field = StructFieldBuilder::named(&last_field_name)
776+
.pub_()
777+
.build_ty(ty);
778+
fields.push(field);
807779

808-
let items = match item.unwrap().node {
809-
ast::ItemKind::Impl(_, _, _, _, _, items) => items,
810-
_ => unreachable!(),
811-
};
780+
// TODO(emilio): dedup this.
781+
*self.index += 1;
782+
last_field_name = format!("_bitfield_{}", self.index);
783+
784+
// Now reset the size and the rest of stuff.
785+
// unfilled_bits_in_last_unit = 0;
786+
field_size_in_bits = 0;
787+
last_field_align = 0;
788+
}
789+
790+
// TODO(emilio): Create the accessors. Problem here is that we still
791+
// don't know which one is going to be the final alignment of the
792+
// bitfield, and whether we have to index in it. Thus, we don't know
793+
// which integer type do we need.
794+
//
795+
// We could push them to a Vec or something, but given how buggy
796+
// they where maybe it's not a great idea?
797+
field_size_in_bits += width as usize;
798+
total_size_in_bits += width as usize;
799+
800+
801+
let data_size = align_to(field_size_in_bits, field_align * 8);
802+
803+
max_align = cmp::max(max_align, field_align);
804+
805+
// NB: The width here is completely, absolutely intentional.
806+
last_field_align = cmp::max(last_field_align, width as usize);
807+
808+
unfilled_bits_in_last_unit = data_size - field_size_in_bits;
809+
}
810+
811+
if field_size_in_bits != 0 {
812+
// Push the last field.
813+
let ty =
814+
BlobTyBuilder::new(Layout::new(bytes_from_bits_pow2(field_size_in_bits),
815+
bytes_from_bits_pow2(last_field_align)))
816+
.build();
812817

813-
methods.extend(items.into_iter());
814-
offset += width;
818+
let field = StructFieldBuilder::named(&last_field_name)
819+
.pub_()
820+
.build_ty(ty);
821+
fields.push(field);
815822
}
816823

817-
bitfield_layout
824+
Layout::new(bytes_from_bits(total_size_in_bits), max_align)
818825
}
819826
}
820827

@@ -1062,12 +1069,10 @@ impl CodeGenerator for CompInfo {
10621069
debug_assert!(!current_bitfield_fields.is_empty());
10631070
let bitfield_fields =
10641071
mem::replace(&mut current_bitfield_fields, vec![]);
1065-
bitfield_count += 1;
1066-
let bitfield_layout = Bitfield::new(bitfield_count,
1072+
let bitfield_layout = Bitfield::new(&mut bitfield_count,
10671073
bitfield_fields)
10681074
.codegen_fields(ctx, &mut fields, &mut methods);
1069-
1070-
struct_layout.saw_bitfield(bitfield_layout);
1075+
struct_layout.saw_bitfield_batch(bitfield_layout);
10711076

10721077
current_bitfield_width = None;
10731078
current_bitfield_layout = None;
@@ -1099,8 +1104,7 @@ impl CodeGenerator for CompInfo {
10991104
} else {
11001105
quote_ty!(ctx.ext_cx(), __BindgenUnionField<$ty>)
11011106
}
1102-
} else if let Some(item) =
1103-
field_ty.is_incomplete_array(ctx) {
1107+
} else if let Some(item) = field_ty.is_incomplete_array(ctx) {
11041108
result.saw_incomplete_array();
11051109

11061110
let inner = item.to_rust_ty(ctx);
@@ -1224,12 +1228,10 @@ impl CodeGenerator for CompInfo {
12241228
debug_assert!(!current_bitfield_fields.is_empty());
12251229
let bitfield_fields = mem::replace(&mut current_bitfield_fields,
12261230
vec![]);
1227-
bitfield_count += 1;
1228-
let bitfield_layout = Bitfield::new(bitfield_count,
1231+
let bitfield_layout = Bitfield::new(&mut bitfield_count,
12291232
bitfield_fields)
12301233
.codegen_fields(ctx, &mut fields, &mut methods);
1231-
1232-
struct_layout.saw_bitfield(bitfield_layout);
1234+
struct_layout.saw_bitfield_batch(bitfield_layout);
12331235
}
12341236
debug_assert!(current_bitfield_fields.is_empty());
12351237

@@ -1268,7 +1270,7 @@ impl CodeGenerator for CompInfo {
12681270
}
12691271
} else if !is_union && !self.is_unsized(ctx) {
12701272
if let Some(padding_field) =
1271-
layout.and_then(|layout| struct_layout.pad_struct(layout)) {
1273+
layout.and_then(|layout| struct_layout.pad_struct(&canonical_name, layout)) {
12721274
fields.push(padding_field);
12731275
}
12741276

@@ -2174,8 +2176,8 @@ impl ToRustTy for Type {
21742176
quote_ty!(ctx.ext_cx(), ::$prefix::option::Option<$ty>)
21752177
}
21762178
TypeKind::Array(item, len) => {
2177-
let inner = item.to_rust_ty(ctx);
2178-
aster::ty::TyBuilder::new().array(len).build(inner)
2179+
let ty = item.to_rust_ty(ctx);
2180+
aster::ty::TyBuilder::new().array(len).build(ty)
21792181
}
21802182
TypeKind::Enum(..) => {
21812183
let path = item.namespace_aware_canonical_path(ctx);
@@ -2190,7 +2192,7 @@ impl ToRustTy for Type {
21902192
.map(|arg| arg.to_rust_ty(ctx))
21912193
.collect::<Vec<_>>();
21922194

2193-
path.segments.last_mut().unwrap().parameters = if
2195+
path.segments.last_mut().unwrap().parameters = if
21942196
template_args.is_empty() {
21952197
None
21962198
} else {

0 commit comments

Comments
 (0)