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 122 123 124
use crate::abi::CallMode; 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, mode: CallMode, iface: &Interface) { self.map = vec![(0, 0); iface.types.len()]; for ty in iface.topological_types() { let pair = self.calculate(mode, &iface.types[ty]); self.map[ty.index()] = pair; } } fn calculate(&self, mode: CallMode, 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(_) => { if mode.import() { (12, 4) } else { (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) }