1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
use crate::abi::AbiVariant;
use crate::{Int, Interface, Record, RecordKind, Type, TypeDef, TypeDefKind, Variant};
#[derive(Default)]
pub struct SizeAlign {
map: Vec<(usize, usize)>,
}
impl SizeAlign {
pub fn fill(&mut self, variant: AbiVariant, iface: &Interface) {
self.map = vec![(0, 0); iface.types.len()];
for ty in iface.topological_types() {
let pair = self.calculate(variant, &iface.types[ty]);
self.map[ty.index()] = pair;
}
}
fn calculate(&self, variant: AbiVariant, ty: &TypeDef) -> (usize, usize) {
match &ty.kind {
TypeDefKind::Type(t) => (self.size(t), self.align(t)),
TypeDefKind::List(_) => (8, 4),
TypeDefKind::Pointer(_) | TypeDefKind::ConstPointer(_) => (4, 4),
TypeDefKind::PushBuffer(_) | TypeDefKind::PullBuffer(_) => match variant {
AbiVariant::GuestImport => (12, 4),
AbiVariant::GuestExport => (4, 4),
},
TypeDefKind::Record(r) => {
if let RecordKind::Flags(repr) = r.kind {
return match repr {
Some(i) => int_size_align(i),
None if r.fields.len() <= 8 => (1, 1),
None if r.fields.len() <= 16 => (2, 2),
None if r.fields.len() <= 32 => (4, 4),
None if r.fields.len() <= 64 => (8, 8),
None => (r.num_i32s() * 4, 4),
};
}
let mut size = 0;
let mut align = 1;
for f in r.fields.iter() {
let field_size = self.size(&f.ty);
let field_align = self.align(&f.ty);
size = align_to(size, field_align) + field_size;
align = align.max(field_align);
}
(align_to(size, align), align)
}
TypeDefKind::Variant(v) => {
let (discrim_size, discrim_align) = int_size_align(v.tag);
let mut size = discrim_size;
let mut align = discrim_align;
for c in v.cases.iter() {
if let Some(ty) = &c.ty {
let case_size = self.size(ty);
let case_align = self.align(ty);
align = align.max(case_align);
size = size.max(align_to(discrim_size, case_align) + case_size);
}
}
(size, align)
}
}
}
pub fn size(&self, ty: &Type) -> usize {
match ty {
Type::U8 | Type::S8 | Type::CChar => 1,
Type::U16 | Type::S16 => 2,
Type::U32 | Type::S32 | Type::F32 | Type::Char | Type::Handle(_) | Type::Usize => 4,
Type::U64 | Type::S64 | Type::F64 => 8,
Type::Id(id) => self.map[id.index()].0,
}
}
pub fn align(&self, ty: &Type) -> usize {
match ty {
Type::U8 | Type::S8 | Type::CChar => 1,
Type::U16 | Type::S16 => 2,
Type::U32 | Type::S32 | Type::F32 | Type::Char | Type::Handle(_) | Type::Usize => 4,
Type::U64 | Type::S64 | Type::F64 => 8,
Type::Id(id) => self.map[id.index()].1,
}
}
pub fn field_offsets(&self, record: &Record) -> Vec<usize> {
let mut cur = 0;
record
.fields
.iter()
.map(|field| {
let ret = align_to(cur, self.align(&field.ty));
cur = ret + self.size(&field.ty);
ret
})
.collect()
}
pub fn payload_offset(&self, variant: &Variant) -> usize {
let mut max_align = 1;
for c in variant.cases.iter() {
if let Some(ty) = &c.ty {
max_align = max_align.max(self.align(ty));
}
}
let tag_size = int_size_align(variant.tag).0;
align_to(tag_size, max_align)
}
}
fn int_size_align(i: Int) -> (usize, usize) {
match i {
Int::U8 => (1, 1),
Int::U16 => (2, 2),
Int::U32 => (4, 4),
Int::U64 => (8, 8),
}
}
fn align_to(val: usize, align: usize) -> usize {
(val + align - 1) & !(align - 1)
}