Skip to content

Commit 322c33c

Browse files
committed
[wip] Refactor the layout tracker thing.
1 parent 24edc5c commit 322c33c

16 files changed

+102
-177
lines changed

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

+4-5
Original file line numberDiff line numberDiff line change
@@ -363,8 +363,7 @@ impl CodeGenerator for Module {
363363
}
364364

365365
if item.id() == ctx.root_module() {
366-
let saw_union = result.saw_union;
367-
if saw_union && !ctx.options().unstable_rust {
366+
if result.saw_union && !ctx.options().unstable_rust {
368367
utils::prepend_union_types(ctx, &mut *result);
369368
}
370369
if result.saw_incomplete_array {
@@ -2176,8 +2175,8 @@ impl ToRustTy for Type {
21762175
quote_ty!(ctx.ext_cx(), ::$prefix::option::Option<$ty>)
21772176
}
21782177
TypeKind::Array(item, len) => {
2179-
let inner = item.to_rust_ty(ctx);
2180-
aster::ty::TyBuilder::new().array(len).build(inner)
2178+
let ty = item.to_rust_ty(ctx);
2179+
aster::ty::TyBuilder::new().array(len).build(ty)
21812180
}
21822181
TypeKind::Enum(..) => {
21832182
let path = item.namespace_aware_canonical_path(ctx);
@@ -2192,7 +2191,7 @@ impl ToRustTy for Type {
21922191
.map(|arg| arg.to_rust_ty(ctx))
21932192
.collect::<Vec<_>>();
21942193

2195-
path.segments.last_mut().unwrap().parameters = if
2194+
path.segments.last_mut().unwrap().parameters = if
21962195
template_args.is_empty() {
21972196
None
21982197
} else {

src/codegen/struct_layout.rs

+44-51
Original file line numberDiff line numberDiff line change
@@ -123,61 +123,57 @@ impl<'a, 'ctx> StructLayoutTracker<'a, 'ctx> {
123123
self.max_field_align = cmp::max(self.max_field_align, layout.align);
124124
}
125125

126+
/// Add a padding field if necessary for a given new field _before_ adding
127+
/// that field.
126128
pub fn pad_field(&mut self,
127129
field_name: &str,
128130
field_ty: &Type,
129131
field_offset: Option<usize>)
130132
-> Option<ast::StructField> {
131-
field_ty.layout(self.ctx).and_then(|field_layout| {
132-
self.align_to_latest_field();
133+
let field_layout = match field_ty.layout(self.ctx) {
134+
Some(l) => l,
135+
None => return None,
136+
};
133137

134-
let padding_layout = if self.comp.packed() {
135-
None
136-
} else {
137-
let calculated_layout = field_ty.as_comp()
138-
.and_then(|comp| comp.calc_layout(self.ctx))
139-
.unwrap_or(field_layout);
140-
141-
let align = cmp::min(calculated_layout.align, mem::size_of::<*mut ()>());
142-
143-
let (padding_bytes, need_padding) = match field_offset {
144-
Some(offset) if offset / 8 > self.latest_offset => {
145-
(offset / 8 - self.latest_offset, true)
146-
}
147-
_ if field_layout.align != 0 => {
148-
(self.padding_bytes(field_layout), (self.latest_offset % field_layout.align) != 0)
149-
}
150-
_ => {
151-
(0, false)
152-
}
153-
};
154-
155-
self.latest_offset += padding_bytes;
156-
157-
debug!("align field {} to {}/{} with {} padding bytes {:?}, calculated {:?}",
158-
field_name,
159-
self.latest_offset,
160-
field_offset.unwrap_or(0) / 8,
161-
padding_bytes,
162-
field_layout,
163-
calculated_layout);
138+
self.align_to_latest_field();
164139

165-
if need_padding &&
166-
(padding_bytes > calculated_layout.align ||
167-
field_layout.align > mem::size_of::<*mut ()>()) {
168-
Some(Layout::new(padding_bytes, align))
169-
} else {
170-
None
140+
let padding_layout = if self.comp.packed() {
141+
None
142+
} else {
143+
let padding_bytes = match field_offset {
144+
Some(offset) if offset / 8 > self.latest_offset => {
145+
offset / 8 - self.latest_offset
146+
}
147+
_ if field_layout.align == 0 => 0,
148+
_ => {
149+
self.padding_bytes(field_layout)
171150
}
172151
};
173152

174-
self.latest_offset += field_ty.calc_size(self.ctx).unwrap_or(field_layout.size);
153+
// Otherwise the padding is useless.
154+
let need_padding = padding_bytes >= field_layout.align;
155+
156+
self.latest_offset += padding_bytes;
157+
158+
debug!("align field {} to {}/{} with {} padding bytes {:?}",
159+
field_name,
160+
self.latest_offset,
161+
field_offset.unwrap_or(0) / 8,
162+
padding_bytes,
163+
field_layout);
164+
165+
if need_padding && padding_bytes != 0 {
166+
Some(Layout::new(padding_bytes, field_layout.align))
167+
} else {
168+
None
169+
}
170+
};
175171

176-
self.latest_field_layout = Some(field_layout);
177-
self.max_field_align = cmp::max(self.max_field_align, field_layout.align);
172+
self.latest_offset += field_layout.size;
173+
self.latest_field_layout = Some(field_layout);
174+
self.max_field_align = cmp::max(self.max_field_align, field_layout.align);
178175

179-
padding_layout.map(|layout| self.padding_field(layout))
180-
})
176+
padding_layout.map(|layout| self.padding_field(layout))
181177
}
182178

183179
pub fn pad_struct(&mut self, layout: Layout) -> Option<ast::StructField> {
@@ -188,16 +184,13 @@ impl<'a, 'ctx> StructLayoutTracker<'a, 'ctx> {
188184
None
189185
} else {
190186
let padding_bytes = layout.size - self.latest_offset;
191-
let struct_align = cmp::min(layout.align,
192-
mem::size_of::<*mut ()>());
193-
194-
if padding_bytes > struct_align ||
195-
(layout.align > mem::size_of::<*mut ()>() && padding_bytes > 0) {
187+
if padding_bytes > 0 &&
188+
(self.latest_field_layout.map_or(false, |l| padding_bytes > l.align) ||
189+
padding_bytes >= layout.align) {
196190
let padding_align = if self.comp.packed() {
197191
1
198192
} else {
199-
cmp::min(1 << padding_bytes.trailing_zeros(),
200-
mem::size_of::<*mut ()>())
193+
self.latest_field_layout.unwrap().align
201194
};
202195

203196
Some(self.padding_field(Layout::new(padding_bytes, padding_align)))
@@ -240,7 +233,7 @@ impl<'a, 'ctx> StructLayoutTracker<'a, 'ctx> {
240233
fn align_to_latest_field(&mut self) {
241234
if self.comp.packed() {
242235
// skip to align field when packed
243-
} else if let Some(layout) = self.latest_field_layout {
236+
} else if let Some(layout) = self.latest_field_layout.take() {
244237
self.latest_offset += self.padding_bytes(layout);
245238
}
246239
}

src/ir/comp.rs

+12-60
Original file line numberDiff line numberDiff line change
@@ -408,73 +408,25 @@ impl CompInfo {
408408
/// members. This is not ideal, but clang fails to report the size for these
409409
/// kind of unions, see test/headers/template_union.hpp
410410
pub fn layout(&self, ctx: &BindgenContext) -> Option<Layout> {
411+
use std::cmp;
411412
// We can't do better than clang here, sorry.
412413
if self.kind == CompKind::Struct {
413-
None
414-
} else {
415-
self.calc_layout(ctx)
414+
return None
416415
}
417-
}
418-
419-
/// Compute the layout of this type.
420-
pub fn calc_layout(&self, ctx: &BindgenContext) -> Option<Layout> {
421-
use std::cmp;
422-
use std::mem;
423-
424-
if self.kind == CompKind::Struct {
425-
let mut latest_offset_in_bits = 0;
426-
let mut max_align = 0;
427-
428-
if self.needs_explicit_vtable(ctx) {
429-
latest_offset_in_bits += mem::size_of::<*mut ()>() * 8;
430-
max_align = mem::size_of::<*mut ()>();
431-
}
432-
433-
for field in &self.fields {
434-
if let Some(bits) = field.bitfield() {
435-
latest_offset_in_bits += bits as usize;
436-
} else {
437-
let field_ty = ctx.resolve_type(field.ty);
438416

439-
if let Some(field_layout) =
440-
field_ty.as_comp()
441-
.and_then(|comp| comp.calc_layout(ctx))
442-
.or_else(|| field_ty.layout(ctx)) {
417+
let mut max_size = 0;
418+
let mut max_align = 0;
419+
for field in &self.fields {
420+
let field_layout = ctx.resolve_type(field.ty)
421+
.layout(ctx);
443422

444-
let n = (latest_offset_in_bits / 8) %
445-
field_layout.align;
446-
447-
if !self.packed && n != 0 {
448-
latest_offset_in_bits += (field_layout.align - n) *
449-
8;
450-
}
451-
452-
latest_offset_in_bits += field_layout.size * 8;
453-
max_align = cmp::max(max_align, field_layout.align);
454-
}
455-
}
456-
}
457-
458-
if latest_offset_in_bits == 0 && max_align == 0 {
459-
None
460-
} else {
461-
Some(Layout::new((latest_offset_in_bits + 7) / 8, max_align))
462-
}
463-
} else {
464-
let mut max_size = 0;
465-
let mut max_align = 0;
466-
for field in &self.fields {
467-
let field_layout = ctx.resolve_type(field.ty)
468-
.layout(ctx);
469-
470-
if let Some(layout) = field_layout {
471-
max_size = cmp::max(max_size, layout.size);
472-
max_align = cmp::max(max_align, layout.align);
473-
}
423+
if let Some(layout) = field_layout {
424+
max_size = cmp::max(max_size, layout.size);
425+
max_align = cmp::max(max_align, layout.align);
474426
}
475-
476-
Some(Layout::new(max_size, max_align))
477427
}
428+
429+
Some(Layout::new(max_size, max_align))
478430
}
479431

480432
/// Get this type's set of fields.

src/ir/enum_ty.rs

+1-16
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@ use super::item::Item;
55
use super::ty::TypeKind;
66
use clang;
77
use ir::annotations::Annotations;
8-
use ir::int::IntKind;
9-
use ir::layout::Layout;
108
use parse::{ClangItemParser, ParseError};
119

1210
/// An enum representing custom handling that can be given to a variant.
@@ -51,19 +49,6 @@ impl Enum {
5149
&self.variants
5250
}
5351

54-
/// Compute the layout of this type.
55-
pub fn calc_layout(&self, ctx: &BindgenContext) -> Option<Layout> {
56-
self.repr
57-
.map(|repr| ctx.resolve_type(repr))
58-
.and_then(|repr| match *repr.canonical_type(ctx).kind() {
59-
TypeKind::Int(int_kind) => Some(int_kind),
60-
_ => None,
61-
})
62-
.unwrap_or(IntKind::Int)
63-
.known_size()
64-
.map(|size| Layout::new(size, size))
65-
}
66-
6752
/// Construct an enumeration from the given Clang type.
6853
pub fn from_ty(ty: &clang::Type,
6954
ctx: &mut BindgenContext)
@@ -114,7 +99,7 @@ impl Enum {
11499
Annotations::new(&cursor)
115100
.and_then(|anno| if anno.hide() {
116101
Some(EnumVariantCustomBehavior::Hide)
117-
} else if
102+
} else if
118103
anno.constify_enum_variant() {
119104
Some(EnumVariantCustomBehavior::Constify)
120105
} else {

src/ir/layout.rs

+23-2
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33
use super::context::BindgenContext;
44
use super::derive::{CanDeriveCopy, CanDeriveDebug, CanDeriveDefault};
55
use super::ty::RUST_DERIVE_IN_ARRAY_LIMIT;
6-
use std::cmp;
6+
use std::{cmp, mem};
77

88
/// A type that represents the struct layout of a type.
9-
#[derive(Debug, Clone, Copy)]
9+
#[derive(Debug, Clone, Copy, PartialEq)]
1010
pub struct Layout {
1111
/// The size (in bytes) of this layout.
1212
pub size: usize,
@@ -16,6 +16,13 @@ pub struct Layout {
1616
pub packed: bool,
1717
}
1818

19+
#[test]
20+
fn test_layout_for_size() {
21+
let ptr_size = mem::size_of::<*mut ()>();
22+
assert_eq!(Layout::for_size(ptr_size), Layout::new(ptr_size, ptr_size));
23+
assert_eq!(Layout::for_size(3 * ptr_size), Layout::new(3 * ptr_size, ptr_size));
24+
}
25+
1926
impl Layout {
2027
/// Construct a new `Layout` with the given `size` and `align`. It is not
2128
/// packed.
@@ -27,6 +34,20 @@ impl Layout {
2734
}
2835
}
2936

37+
/// Creates a non-packed layout for a given size, trying to use the maximum
38+
/// alignment possible.
39+
pub fn for_size(size: usize) -> Self {
40+
let mut next_align = 2;
41+
while size % next_align == 0 && next_align <= 2 * mem::size_of::<*mut ()>() {
42+
next_align *= 2;
43+
}
44+
Layout {
45+
size: size,
46+
align: next_align / 2,
47+
packed: false,
48+
}
49+
}
50+
3051
/// Is this a zero-sized layout?
3152
pub fn is_zero(&self) -> bool {
3253
self.size == 0 && self.align == 0

src/ir/ty.rs

+1-37
Original file line numberDiff line numberDiff line change
@@ -380,44 +380,8 @@ impl Type {
380380
_ => false,
381381
}
382382
}
383-
384-
/// If this type has a known size, return it (in bytes).
385-
pub fn calc_size(&self, ctx: &BindgenContext) -> Option<usize> {
386-
if let Some(layout) = self.layout {
387-
return Some(layout.size);
388-
}
389-
match self.kind {
390-
TypeKind::Comp(ref ci) => {
391-
ci.calc_layout(ctx).map(|layout| layout.size)
392-
}
393-
TypeKind::Enum(ref enum_ty) => {
394-
enum_ty.calc_layout(ctx).map(|layout| layout.size)
395-
}
396-
TypeKind::Int(int_kind) => int_kind.known_size(),
397-
TypeKind::Float(float_kind) => Some(float_kind.known_size()),
398-
TypeKind::Complex(float_kind) => Some(float_kind.known_size() * 2),
399-
TypeKind::Reference(..) |
400-
TypeKind::NullPtr |
401-
TypeKind::Pointer(..) |
402-
TypeKind::BlockPointer |
403-
TypeKind::Function(..) |
404-
TypeKind::ObjCInterface(..) => Some(mem::size_of::<*mut ()>()),
405-
TypeKind::ResolvedTypeRef(inner) |
406-
TypeKind::Alias(inner) |
407-
TypeKind::TemplateAlias(inner, _) |
408-
TypeKind::TemplateInstantiation(inner, _) => {
409-
ctx.resolve_type(inner).calc_size(ctx)
410-
}
411-
TypeKind::Array(inner, len) => {
412-
ctx.resolve_type(inner)
413-
.layout(ctx)
414-
.map(|layout| layout.size * len)
415-
}
416-
TypeKind::Void | TypeKind::Named => None,
417-
TypeKind::UnresolvedTypeRef(..) => unreachable!(),
418-
}
419-
}
420383
}
384+
421385
#[test]
422386
fn is_invalid_named_type_valid() {
423387
let ty = Type::new(Some("foo".into()), None, TypeKind::Named, false);

0 commit comments

Comments
 (0)