/src/wasm-tools/crates/wit-parser/src/sizealign.rs
Line | Count | Source |
1 | | use std::{ |
2 | | cmp::Ordering, |
3 | | num::NonZeroUsize, |
4 | | ops::{Add, AddAssign}, |
5 | | }; |
6 | | |
7 | | use crate::{FlagsRepr, Int, Resolve, Type, TypeDef, TypeDefKind}; |
8 | | |
9 | | /// Architecture specific alignment |
10 | | #[derive(Eq, PartialEq, Clone, Copy)] |
11 | | pub enum Alignment { |
12 | | /// This represents 4 byte alignment on 32bit and 8 byte alignment on 64bit architectures |
13 | | Pointer, |
14 | | /// This alignment is architecture independent (derived from integer or float types) |
15 | | Bytes(NonZeroUsize), |
16 | | } |
17 | | |
18 | | impl Default for Alignment { |
19 | 5.06k | fn default() -> Self { |
20 | 5.06k | Alignment::Bytes(NonZeroUsize::new(1).unwrap()) |
21 | 5.06k | } |
22 | | } |
23 | | |
24 | | impl std::fmt::Debug for Alignment { |
25 | 0 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
26 | 0 | match self { |
27 | 0 | Alignment::Pointer => f.write_str("ptr"), |
28 | 0 | Alignment::Bytes(b) => f.write_fmt(format_args!("{}", b.get())), |
29 | | } |
30 | 0 | } |
31 | | } |
32 | | |
33 | | impl PartialOrd for Alignment { |
34 | 13.2k | fn partial_cmp(&self, other: &Self) -> Option<Ordering> { |
35 | 13.2k | Some(self.cmp(other)) |
36 | 13.2k | } |
37 | | } |
38 | | |
39 | | impl Ord for Alignment { |
40 | | /// Needed for determining the max alignment of an object from its parts. |
41 | | /// The ordering is: Bytes(1) < Bytes(2) < Bytes(4) < Pointer < Bytes(8) |
42 | | /// as a Pointer is either four or eight byte aligned, depending on the architecture |
43 | 13.2k | fn cmp(&self, other: &Self) -> Ordering { |
44 | 13.2k | match (self, other) { |
45 | 26 | (Alignment::Pointer, Alignment::Pointer) => std::cmp::Ordering::Equal, |
46 | 174 | (Alignment::Pointer, Alignment::Bytes(b)) => { |
47 | 174 | if b.get() > 4 { |
48 | 29 | std::cmp::Ordering::Less |
49 | | } else { |
50 | 145 | std::cmp::Ordering::Greater |
51 | | } |
52 | | } |
53 | 77 | (Alignment::Bytes(b), Alignment::Pointer) => { |
54 | 77 | if b.get() > 4 { |
55 | 7 | std::cmp::Ordering::Greater |
56 | | } else { |
57 | 70 | std::cmp::Ordering::Less |
58 | | } |
59 | | } |
60 | 12.9k | (Alignment::Bytes(a), Alignment::Bytes(b)) => a.cmp(b), |
61 | | } |
62 | 13.2k | } |
63 | | } |
64 | | |
65 | | impl Alignment { |
66 | | /// for easy migration this gives you the value for wasm32 |
67 | 7.63k | pub fn align_wasm32(&self) -> usize { |
68 | 7.63k | match self { |
69 | 289 | Alignment::Pointer => 4, |
70 | 7.34k | Alignment::Bytes(bytes) => bytes.get(), |
71 | | } |
72 | 7.63k | } |
73 | | |
74 | 7.63k | pub fn align_wasm64(&self) -> usize { |
75 | 7.63k | match self { |
76 | 289 | Alignment::Pointer => 8, |
77 | 7.34k | Alignment::Bytes(bytes) => bytes.get(), |
78 | | } |
79 | 7.63k | } |
80 | | |
81 | 0 | pub fn format(&self, ptrsize_expr: &str) -> String { |
82 | 0 | match self { |
83 | 0 | Alignment::Pointer => ptrsize_expr.into(), |
84 | 0 | Alignment::Bytes(bytes) => format!("{}", bytes.get()), |
85 | | } |
86 | 0 | } |
87 | | } |
88 | | |
89 | | /// Architecture specific measurement of position, |
90 | | /// the combined amount in bytes is |
91 | | /// `bytes + pointers * core::mem::size_of::<*const u8>()` |
92 | | #[derive(Default, Clone, Copy, Eq, PartialEq)] |
93 | | pub struct ArchitectureSize { |
94 | | /// architecture independent bytes |
95 | | pub bytes: usize, |
96 | | /// amount of pointer sized units to add |
97 | | pub pointers: usize, |
98 | | } |
99 | | |
100 | | impl Add<ArchitectureSize> for ArchitectureSize { |
101 | | type Output = ArchitectureSize; |
102 | | |
103 | 10.1k | fn add(self, rhs: ArchitectureSize) -> Self::Output { |
104 | 10.1k | ArchitectureSize::new(self.bytes + rhs.bytes, self.pointers + rhs.pointers) |
105 | 10.1k | } |
106 | | } |
107 | | |
108 | | impl AddAssign<ArchitectureSize> for ArchitectureSize { |
109 | 0 | fn add_assign(&mut self, rhs: ArchitectureSize) { |
110 | 0 | self.bytes += rhs.bytes; |
111 | 0 | self.pointers += rhs.pointers; |
112 | 0 | } |
113 | | } |
114 | | |
115 | | impl From<Alignment> for ArchitectureSize { |
116 | 4.35k | fn from(align: Alignment) -> Self { |
117 | 4.35k | match align { |
118 | 4.35k | Alignment::Bytes(bytes) => ArchitectureSize::new(bytes.get(), 0), |
119 | 0 | Alignment::Pointer => ArchitectureSize::new(0, 1), |
120 | | } |
121 | 4.35k | } |
122 | | } |
123 | | |
124 | | impl std::fmt::Debug for ArchitectureSize { |
125 | 0 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
126 | 0 | f.write_str(&self.format("ptrsz")) |
127 | 0 | } |
128 | | } |
129 | | |
130 | | impl ArchitectureSize { |
131 | 38.9k | pub fn new(bytes: usize, pointers: usize) -> Self { |
132 | 38.9k | Self { bytes, pointers } |
133 | 38.9k | } |
134 | | |
135 | 4.14k | pub fn max<B: std::borrow::Borrow<Self>>(&self, other: B) -> Self { |
136 | 4.14k | let other = other.borrow(); |
137 | 4.14k | let self32 = self.size_wasm32(); |
138 | 4.14k | let self64 = self.size_wasm64(); |
139 | 4.14k | let other32 = other.size_wasm32(); |
140 | 4.14k | let other64 = other.size_wasm64(); |
141 | 4.14k | if self32 >= other32 && self64 >= other64 { |
142 | 2.14k | *self |
143 | 2.00k | } else if self32 <= other32 && self64 <= other64 { |
144 | 2.00k | *other |
145 | | } else { |
146 | | // we can assume a combination of bytes and pointers, so align to at least pointer size |
147 | 2 | let new32 = align_to(self32.max(other32), 4); |
148 | 2 | let new64 = align_to(self64.max(other64), 8); |
149 | 2 | ArchitectureSize::new(new32 + new32 - new64, (new64 - new32) / 4) |
150 | | } |
151 | 4.14k | } |
152 | | |
153 | 0 | pub fn add_bytes(&self, b: usize) -> Self { |
154 | 0 | Self::new(self.bytes + b, self.pointers) |
155 | 0 | } |
156 | | |
157 | | /// The effective offset/size is |
158 | | /// `constant_bytes() + core::mem::size_of::<*const u8>() * pointers_to_add()` |
159 | 0 | pub fn constant_bytes(&self) -> usize { |
160 | 0 | self.bytes |
161 | 0 | } |
162 | | |
163 | 0 | pub fn pointers_to_add(&self) -> usize { |
164 | 0 | self.pointers |
165 | 0 | } |
166 | | |
167 | | /// Shortcut for compatibility with previous versions |
168 | 20.0k | pub fn size_wasm32(&self) -> usize { |
169 | 20.0k | self.bytes + self.pointers * 4 |
170 | 20.0k | } |
171 | | |
172 | 20.0k | pub fn size_wasm64(&self) -> usize { |
173 | 20.0k | self.bytes + self.pointers * 8 |
174 | 20.0k | } |
175 | | |
176 | | /// prefer this over >0 |
177 | 0 | pub fn is_empty(&self) -> bool { |
178 | 0 | self.bytes == 0 && self.pointers == 0 |
179 | 0 | } |
180 | | |
181 | | // create a suitable expression in bytes from a pointer size argument |
182 | 0 | pub fn format(&self, ptrsize_expr: &str) -> String { |
183 | 0 | self.format_term(ptrsize_expr, false) |
184 | 0 | } |
185 | | |
186 | | // create a suitable expression in bytes from a pointer size argument, |
187 | | // extended API with optional brackets around the sum |
188 | 0 | pub fn format_term(&self, ptrsize_expr: &str, suppress_brackets: bool) -> String { |
189 | 0 | if self.pointers != 0 { |
190 | 0 | if self.bytes > 0 { |
191 | | // both |
192 | 0 | if suppress_brackets { |
193 | 0 | format!( |
194 | 0 | "{}+{}*{ptrsize_expr}", |
195 | 0 | self.constant_bytes(), |
196 | 0 | self.pointers_to_add() |
197 | | ) |
198 | | } else { |
199 | 0 | format!( |
200 | 0 | "({}+{}*{ptrsize_expr})", |
201 | 0 | self.constant_bytes(), |
202 | 0 | self.pointers_to_add() |
203 | | ) |
204 | | } |
205 | 0 | } else if self.pointers == 1 { |
206 | | // one pointer |
207 | 0 | ptrsize_expr.into() |
208 | | } else { |
209 | | // only pointer |
210 | 0 | if suppress_brackets { |
211 | 0 | format!("{}*{ptrsize_expr}", self.pointers_to_add()) |
212 | | } else { |
213 | 0 | format!("({}*{ptrsize_expr})", self.pointers_to_add()) |
214 | | } |
215 | | } |
216 | | } else { |
217 | | // only bytes |
218 | 0 | format!("{}", self.constant_bytes()) |
219 | | } |
220 | 0 | } |
221 | | } |
222 | | |
223 | | /// Information per structure element |
224 | | #[derive(Default)] |
225 | | pub struct ElementInfo { |
226 | | pub size: ArchitectureSize, |
227 | | pub align: Alignment, |
228 | | } |
229 | | |
230 | | impl From<Alignment> for ElementInfo { |
231 | 4.35k | fn from(align: Alignment) -> Self { |
232 | 4.35k | ElementInfo { |
233 | 4.35k | size: align.into(), |
234 | 4.35k | align, |
235 | 4.35k | } |
236 | 4.35k | } |
237 | | } |
238 | | |
239 | | impl ElementInfo { |
240 | 7.32k | fn new(size: ArchitectureSize, align: Alignment) -> Self { |
241 | 7.32k | Self { size, align } |
242 | 7.32k | } |
243 | | } |
244 | | |
245 | | /// Collect size and alignment for sub-elements of a structure |
246 | | #[derive(Default)] |
247 | | pub struct SizeAlign { |
248 | | map: Vec<ElementInfo>, |
249 | | } |
250 | | |
251 | | impl SizeAlign { |
252 | 1.26k | pub fn fill(&mut self, resolve: &Resolve) { |
253 | 1.26k | self.map = Vec::new(); |
254 | 7.63k | for (_, ty) in resolve.types.iter() { |
255 | 7.63k | let pair = self.calculate(ty); |
256 | 7.63k | self.map.push(pair); |
257 | 7.63k | } |
258 | 1.26k | } |
259 | | |
260 | 7.63k | fn calculate(&self, ty: &TypeDef) -> ElementInfo { |
261 | 7.63k | match &ty.kind { |
262 | 2.60k | TypeDefKind::Type(t) => ElementInfo::new(self.size(t), self.align(t)), |
263 | 0 | TypeDefKind::FixedSizeList(t, size) => { |
264 | 0 | let field_align = self.align(t); |
265 | 0 | let field_size = self.size(t); |
266 | 0 | ElementInfo::new( |
267 | 0 | ArchitectureSize::new( |
268 | 0 | field_size.bytes.checked_mul(*size as usize).unwrap(), |
269 | 0 | field_size.pointers.checked_mul(*size as usize).unwrap(), |
270 | | ), |
271 | 0 | field_align, |
272 | | ) |
273 | | } |
274 | | TypeDefKind::List(_) => { |
275 | 203 | ElementInfo::new(ArchitectureSize::new(0, 2), Alignment::Pointer) |
276 | | } |
277 | 470 | TypeDefKind::Record(r) => self.record(r.fields.iter().map(|f| &f.ty)), |
278 | 555 | TypeDefKind::Tuple(t) => self.record(t.types.iter()), |
279 | 263 | TypeDefKind::Flags(f) => match f.repr() { |
280 | 242 | FlagsRepr::U8 => int_size_align(Int::U8), |
281 | 21 | FlagsRepr::U16 => int_size_align(Int::U16), |
282 | 0 | FlagsRepr::U32(n) => ElementInfo::new( |
283 | 0 | ArchitectureSize::new(n * 4, 0), |
284 | 0 | Alignment::Bytes(NonZeroUsize::new(4).unwrap()), |
285 | | ), |
286 | | }, |
287 | 2.98k | TypeDefKind::Variant(v) => self.variant(v.tag(), v.cases.iter().map(|c| c.ty.as_ref())), |
288 | 1.37k | TypeDefKind::Enum(e) => self.variant(e.tag(), []), |
289 | 261 | TypeDefKind::Option(t) => self.variant(Int::U8, [Some(t)]), |
290 | 917 | TypeDefKind::Result(r) => self.variant(Int::U8, [r.ok.as_ref(), r.err.as_ref()]), |
291 | | // A resource is represented as an index. |
292 | | // A future is represented as an index. |
293 | | // A stream is represented as an index. |
294 | | // An error is represented as an index. |
295 | | TypeDefKind::Handle(_) | TypeDefKind::Future(_) | TypeDefKind::Stream(_) => { |
296 | 48 | int_size_align(Int::U32) |
297 | | } |
298 | | // This shouldn't be used for anything since raw resources aren't part of the ABI -- just handles to |
299 | | // them. |
300 | 199 | TypeDefKind::Resource => ElementInfo::new( |
301 | 199 | ArchitectureSize::new(usize::MAX, 0), |
302 | 199 | Alignment::Bytes(NonZeroUsize::new(usize::MAX).unwrap()), |
303 | | ), |
304 | 0 | TypeDefKind::Unknown => unreachable!(), |
305 | | } |
306 | 7.63k | } |
307 | | |
308 | 21.2k | pub fn size(&self, ty: &Type) -> ArchitectureSize { |
309 | 21.2k | match ty { |
310 | 5.00k | Type::Bool | Type::U8 | Type::S8 => ArchitectureSize::new(1, 0), |
311 | 209 | Type::U16 | Type::S16 => ArchitectureSize::new(2, 0), |
312 | | Type::U32 | Type::S32 | Type::F32 | Type::Char | Type::ErrorContext => { |
313 | 1.53k | ArchitectureSize::new(4, 0) |
314 | | } |
315 | 2.01k | Type::U64 | Type::S64 | Type::F64 => ArchitectureSize::new(8, 0), |
316 | 84 | Type::String => ArchitectureSize::new(0, 2), |
317 | 12.3k | Type::Id(id) => self.map[id.index()].size, |
318 | | } |
319 | 21.2k | } |
320 | | |
321 | 23.5k | pub fn align(&self, ty: &Type) -> Alignment { |
322 | 23.5k | match ty { |
323 | 5.21k | Type::Bool | Type::U8 | Type::S8 => Alignment::Bytes(NonZeroUsize::new(1).unwrap()), |
324 | 260 | Type::U16 | Type::S16 => Alignment::Bytes(NonZeroUsize::new(2).unwrap()), |
325 | | Type::U32 | Type::S32 | Type::F32 | Type::Char | Type::ErrorContext => { |
326 | 2.01k | Alignment::Bytes(NonZeroUsize::new(4).unwrap()) |
327 | | } |
328 | 3.59k | Type::U64 | Type::S64 | Type::F64 => Alignment::Bytes(NonZeroUsize::new(8).unwrap()), |
329 | 94 | Type::String => Alignment::Pointer, |
330 | 12.4k | Type::Id(id) => self.map[id.index()].align, |
331 | | } |
332 | 23.5k | } |
333 | | |
334 | 1.02k | pub fn field_offsets<'a>( |
335 | 1.02k | &self, |
336 | 1.02k | types: impl IntoIterator<Item = &'a Type>, |
337 | 1.02k | ) -> Vec<(ArchitectureSize, &'a Type)> { |
338 | 1.02k | let mut cur = ArchitectureSize::default(); |
339 | 1.02k | types |
340 | 1.02k | .into_iter() |
341 | 3.42k | .map(|ty| { |
342 | 3.42k | let ret = align_to_arch(cur, self.align(ty)); |
343 | 3.42k | cur = ret + self.size(ty); |
344 | 3.42k | (ret, ty) |
345 | 3.42k | }) <wit_parser::sizealign::SizeAlign>::field_offsets::<core::slice::iter::Iter<wit_parser::Type>>::{closure#0}Line | Count | Source | 341 | 2.20k | .map(|ty| { | 342 | 2.20k | let ret = align_to_arch(cur, self.align(ty)); | 343 | 2.20k | cur = ret + self.size(ty); | 344 | 2.20k | (ret, ty) | 345 | 2.20k | }) |
<wit_parser::sizealign::SizeAlign>::field_offsets::<core::iter::adapters::map::Map<core::slice::iter::Iter<wit_parser::Field>, wasm_tools_fuzz::wit64::run::{closure#3}>>::{closure#0}Line | Count | Source | 341 | 1.21k | .map(|ty| { | 342 | 1.21k | let ret = align_to_arch(cur, self.align(ty)); | 343 | 1.21k | cur = ret + self.size(ty); | 344 | 1.21k | (ret, ty) | 345 | 1.21k | }) |
|
346 | 1.02k | .collect() |
347 | 1.02k | } <wit_parser::sizealign::SizeAlign>::field_offsets::<core::slice::iter::Iter<wit_parser::Type>> Line | Count | Source | 334 | 555 | pub fn field_offsets<'a>( | 335 | 555 | &self, | 336 | 555 | types: impl IntoIterator<Item = &'a Type>, | 337 | 555 | ) -> Vec<(ArchitectureSize, &'a Type)> { | 338 | 555 | let mut cur = ArchitectureSize::default(); | 339 | 555 | types | 340 | 555 | .into_iter() | 341 | 555 | .map(|ty| { | 342 | | let ret = align_to_arch(cur, self.align(ty)); | 343 | | cur = ret + self.size(ty); | 344 | | (ret, ty) | 345 | | }) | 346 | 555 | .collect() | 347 | 555 | } |
<wit_parser::sizealign::SizeAlign>::field_offsets::<core::iter::adapters::map::Map<core::slice::iter::Iter<wit_parser::Field>, wasm_tools_fuzz::wit64::run::{closure#3}>>Line | Count | Source | 334 | 470 | pub fn field_offsets<'a>( | 335 | 470 | &self, | 336 | 470 | types: impl IntoIterator<Item = &'a Type>, | 337 | 470 | ) -> Vec<(ArchitectureSize, &'a Type)> { | 338 | 470 | let mut cur = ArchitectureSize::default(); | 339 | 470 | types | 340 | 470 | .into_iter() | 341 | 470 | .map(|ty| { | 342 | | let ret = align_to_arch(cur, self.align(ty)); | 343 | | cur = ret + self.size(ty); | 344 | | (ret, ty) | 345 | | }) | 346 | 470 | .collect() | 347 | 470 | } |
|
348 | | |
349 | 745 | pub fn payload_offset<'a>( |
350 | 745 | &self, |
351 | 745 | tag: Int, |
352 | 745 | cases: impl IntoIterator<Item = Option<&'a Type>>, |
353 | 745 | ) -> ArchitectureSize { |
354 | 745 | let mut max_align = Alignment::default(); |
355 | 3.72k | for ty in cases { |
356 | 2.98k | if let Some(ty) = ty { |
357 | 2.36k | max_align = max_align.max(self.align(ty)); |
358 | 2.36k | } |
359 | | } |
360 | 745 | let tag_size = int_size_align(tag).size; |
361 | 745 | align_to_arch(tag_size, max_align) |
362 | 745 | } |
363 | | |
364 | 1.02k | pub fn record<'a>(&self, types: impl IntoIterator<Item = &'a Type>) -> ElementInfo { |
365 | 1.02k | let mut size = ArchitectureSize::default(); |
366 | 1.02k | let mut align = Alignment::default(); |
367 | 4.44k | for ty in types { |
368 | 3.42k | let field_size = self.size(ty); |
369 | 3.42k | let field_align = self.align(ty); |
370 | 3.42k | size = align_to_arch(size, field_align) + field_size; |
371 | 3.42k | align = align.max(field_align); |
372 | 3.42k | } |
373 | 1.02k | ElementInfo::new(align_to_arch(size, align), align) |
374 | 1.02k | } <wit_parser::sizealign::SizeAlign>::record::<core::slice::iter::Iter<wit_parser::Type>> Line | Count | Source | 364 | 555 | pub fn record<'a>(&self, types: impl IntoIterator<Item = &'a Type>) -> ElementInfo { | 365 | 555 | let mut size = ArchitectureSize::default(); | 366 | 555 | let mut align = Alignment::default(); | 367 | 2.76k | for ty in types { | 368 | 2.20k | let field_size = self.size(ty); | 369 | 2.20k | let field_align = self.align(ty); | 370 | 2.20k | size = align_to_arch(size, field_align) + field_size; | 371 | 2.20k | align = align.max(field_align); | 372 | 2.20k | } | 373 | 555 | ElementInfo::new(align_to_arch(size, align), align) | 374 | 555 | } |
<wit_parser::sizealign::SizeAlign>::record::<core::iter::adapters::map::Map<core::slice::iter::Iter<wit_parser::Field>, <wit_parser::sizealign::SizeAlign>::calculate::{closure#0}>>Line | Count | Source | 364 | 470 | pub fn record<'a>(&self, types: impl IntoIterator<Item = &'a Type>) -> ElementInfo { | 365 | 470 | let mut size = ArchitectureSize::default(); | 366 | 470 | let mut align = Alignment::default(); | 367 | 1.68k | for ty in types { | 368 | 1.21k | let field_size = self.size(ty); | 369 | 1.21k | let field_align = self.align(ty); | 370 | 1.21k | size = align_to_arch(size, field_align) + field_size; | 371 | 1.21k | align = align.max(field_align); | 372 | 1.21k | } | 373 | 470 | ElementInfo::new(align_to_arch(size, align), align) | 374 | 470 | } |
|
375 | | |
376 | | pub fn params<'a>(&self, types: impl IntoIterator<Item = &'a Type>) -> ElementInfo { |
377 | | self.record(types.into_iter()) |
378 | | } |
379 | | |
380 | 3.29k | fn variant<'a>( |
381 | 3.29k | &self, |
382 | 3.29k | tag: Int, |
383 | 3.29k | types: impl IntoIterator<Item = Option<&'a Type>>, |
384 | 3.29k | ) -> ElementInfo { |
385 | | let ElementInfo { |
386 | 3.29k | size: discrim_size, |
387 | 3.29k | align: discrim_align, |
388 | 3.29k | } = int_size_align(tag); |
389 | 3.29k | let mut case_size = ArchitectureSize::default(); |
390 | 3.29k | let mut case_align = Alignment::default(); |
391 | 8.37k | for ty in types { |
392 | 5.07k | if let Some(ty) = ty { |
393 | 4.14k | case_size = case_size.max(&self.size(ty)); |
394 | 4.14k | case_align = case_align.max(self.align(ty)); |
395 | 4.14k | } |
396 | | } |
397 | 3.29k | let align = discrim_align.max(case_align); |
398 | 3.29k | let discrim_aligned = align_to_arch(discrim_size, case_align); |
399 | 3.29k | let size_sum = discrim_aligned + case_size; |
400 | 3.29k | ElementInfo::new(align_to_arch(size_sum, align), align) |
401 | 3.29k | } <wit_parser::sizealign::SizeAlign>::variant::<[core::option::Option<&wit_parser::Type>; 0]> Line | Count | Source | 380 | 1.37k | fn variant<'a>( | 381 | 1.37k | &self, | 382 | 1.37k | tag: Int, | 383 | 1.37k | types: impl IntoIterator<Item = Option<&'a Type>>, | 384 | 1.37k | ) -> ElementInfo { | 385 | | let ElementInfo { | 386 | 1.37k | size: discrim_size, | 387 | 1.37k | align: discrim_align, | 388 | 1.37k | } = int_size_align(tag); | 389 | 1.37k | let mut case_size = ArchitectureSize::default(); | 390 | 1.37k | let mut case_align = Alignment::default(); | 391 | 1.37k | for ty in types { | 392 | 0 | if let Some(ty) = ty { | 393 | 0 | case_size = case_size.max(&self.size(ty)); | 394 | 0 | case_align = case_align.max(self.align(ty)); | 395 | 0 | } | 396 | | } | 397 | 1.37k | let align = discrim_align.max(case_align); | 398 | 1.37k | let discrim_aligned = align_to_arch(discrim_size, case_align); | 399 | 1.37k | let size_sum = discrim_aligned + case_size; | 400 | 1.37k | ElementInfo::new(align_to_arch(size_sum, align), align) | 401 | 1.37k | } |
<wit_parser::sizealign::SizeAlign>::variant::<[core::option::Option<&wit_parser::Type>; 1]> Line | Count | Source | 380 | 261 | fn variant<'a>( | 381 | 261 | &self, | 382 | 261 | tag: Int, | 383 | 261 | types: impl IntoIterator<Item = Option<&'a Type>>, | 384 | 261 | ) -> ElementInfo { | 385 | | let ElementInfo { | 386 | 261 | size: discrim_size, | 387 | 261 | align: discrim_align, | 388 | 261 | } = int_size_align(tag); | 389 | 261 | let mut case_size = ArchitectureSize::default(); | 390 | 261 | let mut case_align = Alignment::default(); | 391 | 522 | for ty in types { | 392 | 261 | if let Some(ty) = ty { | 393 | 261 | case_size = case_size.max(&self.size(ty)); | 394 | 261 | case_align = case_align.max(self.align(ty)); | 395 | 261 | } | 396 | | } | 397 | 261 | let align = discrim_align.max(case_align); | 398 | 261 | let discrim_aligned = align_to_arch(discrim_size, case_align); | 399 | 261 | let size_sum = discrim_aligned + case_size; | 400 | 261 | ElementInfo::new(align_to_arch(size_sum, align), align) | 401 | 261 | } |
<wit_parser::sizealign::SizeAlign>::variant::<[core::option::Option<&wit_parser::Type>; 2]> Line | Count | Source | 380 | 917 | fn variant<'a>( | 381 | 917 | &self, | 382 | 917 | tag: Int, | 383 | 917 | types: impl IntoIterator<Item = Option<&'a Type>>, | 384 | 917 | ) -> ElementInfo { | 385 | | let ElementInfo { | 386 | 917 | size: discrim_size, | 387 | 917 | align: discrim_align, | 388 | 917 | } = int_size_align(tag); | 389 | 917 | let mut case_size = ArchitectureSize::default(); | 390 | 917 | let mut case_align = Alignment::default(); | 391 | 2.75k | for ty in types { | 392 | 1.83k | if let Some(ty) = ty { | 393 | 1.52k | case_size = case_size.max(&self.size(ty)); | 394 | 1.52k | case_align = case_align.max(self.align(ty)); | 395 | 1.52k | } | 396 | | } | 397 | 917 | let align = discrim_align.max(case_align); | 398 | 917 | let discrim_aligned = align_to_arch(discrim_size, case_align); | 399 | 917 | let size_sum = discrim_aligned + case_size; | 400 | 917 | ElementInfo::new(align_to_arch(size_sum, align), align) | 401 | 917 | } |
<wit_parser::sizealign::SizeAlign>::variant::<core::iter::adapters::map::Map<core::slice::iter::Iter<wit_parser::Case>, <wit_parser::sizealign::SizeAlign>::calculate::{closure#1}>>Line | Count | Source | 380 | 745 | fn variant<'a>( | 381 | 745 | &self, | 382 | 745 | tag: Int, | 383 | 745 | types: impl IntoIterator<Item = Option<&'a Type>>, | 384 | 745 | ) -> ElementInfo { | 385 | | let ElementInfo { | 386 | 745 | size: discrim_size, | 387 | 745 | align: discrim_align, | 388 | 745 | } = int_size_align(tag); | 389 | 745 | let mut case_size = ArchitectureSize::default(); | 390 | 745 | let mut case_align = Alignment::default(); | 391 | 3.72k | for ty in types { | 392 | 2.98k | if let Some(ty) = ty { | 393 | 2.36k | case_size = case_size.max(&self.size(ty)); | 394 | 2.36k | case_align = case_align.max(self.align(ty)); | 395 | 2.36k | } | 396 | | } | 397 | 745 | let align = discrim_align.max(case_align); | 398 | 745 | let discrim_aligned = align_to_arch(discrim_size, case_align); | 399 | 745 | let size_sum = discrim_aligned + case_size; | 400 | 745 | ElementInfo::new(align_to_arch(size_sum, align), align) | 401 | 745 | } |
|
402 | | } |
403 | | |
404 | 4.35k | fn int_size_align(i: Int) -> ElementInfo { |
405 | 4.35k | match i { |
406 | 4.28k | Int::U8 => Alignment::Bytes(NonZeroUsize::new(1).unwrap()), |
407 | 21 | Int::U16 => Alignment::Bytes(NonZeroUsize::new(2).unwrap()), |
408 | 48 | Int::U32 => Alignment::Bytes(NonZeroUsize::new(4).unwrap()), |
409 | 0 | Int::U64 => Alignment::Bytes(NonZeroUsize::new(8).unwrap()), |
410 | | } |
411 | 4.35k | .into() |
412 | 4.35k | } |
413 | | |
414 | | /// Increase `val` to a multiple of `align`; |
415 | | /// `align` must be a power of two |
416 | 15.4k | pub(crate) fn align_to(val: usize, align: usize) -> usize { |
417 | 15.4k | (val + align - 1) & !(align - 1) |
418 | 15.4k | } |
419 | | |
420 | | /// Increase `val` to a multiple of `align`, with special handling for pointers; |
421 | | /// `align` must be a power of two or `Alignment::Pointer` |
422 | 15.2k | pub fn align_to_arch(val: ArchitectureSize, align: Alignment) -> ArchitectureSize { |
423 | 15.2k | match align { |
424 | | Alignment::Pointer => { |
425 | 234 | let new32 = align_to(val.bytes, 4); |
426 | 234 | if new32 != align_to(new32, 8) { |
427 | 94 | ArchitectureSize::new(new32 - 4, val.pointers + 1) |
428 | | } else { |
429 | 140 | ArchitectureSize::new(new32, val.pointers) |
430 | | } |
431 | | } |
432 | 14.9k | Alignment::Bytes(align_bytes) => { |
433 | 14.9k | let align_bytes = align_bytes.get(); |
434 | 14.9k | if align_bytes > 4 && (val.pointers & 1) != 0 { |
435 | 13 | let new_bytes = align_to(val.bytes, align_bytes); |
436 | 13 | if (new_bytes - val.bytes) >= 4 { |
437 | | // up to four extra bytes fit together with a the extra 32 bit pointer |
438 | | // and the 64 bit pointer is always 8 bytes (so no change in value) |
439 | 4 | ArchitectureSize::new(new_bytes - 8, val.pointers + 1) |
440 | | } else { |
441 | | // there is no room to combine, so the odd pointer aligns to 8 bytes |
442 | 9 | ArchitectureSize::new(new_bytes + 8, val.pointers - 1) |
443 | | } |
444 | | } else { |
445 | 14.9k | ArchitectureSize::new(align_to(val.bytes, align_bytes), val.pointers) |
446 | | } |
447 | | } |
448 | | } |
449 | 15.2k | } |
450 | | |
451 | | #[cfg(test)] |
452 | | mod test { |
453 | | use super::*; |
454 | | |
455 | | #[test] |
456 | | fn align() { |
457 | | // u8 + ptr |
458 | | assert_eq!( |
459 | | align_to_arch(ArchitectureSize::new(1, 0), Alignment::Pointer), |
460 | | ArchitectureSize::new(0, 1) |
461 | | ); |
462 | | // u8 + u64 |
463 | | assert_eq!( |
464 | | align_to_arch( |
465 | | ArchitectureSize::new(1, 0), |
466 | | Alignment::Bytes(NonZeroUsize::new(8).unwrap()) |
467 | | ), |
468 | | ArchitectureSize::new(8, 0) |
469 | | ); |
470 | | // u8 + u32 |
471 | | assert_eq!( |
472 | | align_to_arch( |
473 | | ArchitectureSize::new(1, 0), |
474 | | Alignment::Bytes(NonZeroUsize::new(4).unwrap()) |
475 | | ), |
476 | | ArchitectureSize::new(4, 0) |
477 | | ); |
478 | | // ptr + u64 |
479 | | assert_eq!( |
480 | | align_to_arch( |
481 | | ArchitectureSize::new(0, 1), |
482 | | Alignment::Bytes(NonZeroUsize::new(8).unwrap()) |
483 | | ), |
484 | | ArchitectureSize::new(8, 0) |
485 | | ); |
486 | | // u32 + ptr |
487 | | assert_eq!( |
488 | | align_to_arch(ArchitectureSize::new(4, 0), Alignment::Pointer), |
489 | | ArchitectureSize::new(0, 1) |
490 | | ); |
491 | | // u32, ptr + u64 |
492 | | assert_eq!( |
493 | | align_to_arch( |
494 | | ArchitectureSize::new(0, 2), |
495 | | Alignment::Bytes(NonZeroUsize::new(8).unwrap()) |
496 | | ), |
497 | | ArchitectureSize::new(0, 2) |
498 | | ); |
499 | | // ptr, u8 + u64 |
500 | | assert_eq!( |
501 | | align_to_arch( |
502 | | ArchitectureSize::new(1, 1), |
503 | | Alignment::Bytes(NonZeroUsize::new(8).unwrap()) |
504 | | ), |
505 | | ArchitectureSize::new(0, 2) |
506 | | ); |
507 | | // ptr, u8 + ptr |
508 | | assert_eq!( |
509 | | align_to_arch(ArchitectureSize::new(1, 1), Alignment::Pointer), |
510 | | ArchitectureSize::new(0, 2) |
511 | | ); |
512 | | // ptr, ptr, u8 + u64 |
513 | | assert_eq!( |
514 | | align_to_arch( |
515 | | ArchitectureSize::new(1, 2), |
516 | | Alignment::Bytes(NonZeroUsize::new(8).unwrap()) |
517 | | ), |
518 | | ArchitectureSize::new(8, 2) |
519 | | ); |
520 | | assert_eq!( |
521 | | align_to_arch( |
522 | | ArchitectureSize::new(30, 3), |
523 | | Alignment::Bytes(NonZeroUsize::new(8).unwrap()) |
524 | | ), |
525 | | ArchitectureSize::new(40, 2) |
526 | | ); |
527 | | |
528 | | assert_eq!( |
529 | | ArchitectureSize::new(12, 0).max(&ArchitectureSize::new(0, 2)), |
530 | | ArchitectureSize::new(8, 1) |
531 | | ); |
532 | | assert_eq!( |
533 | | ArchitectureSize::new(10, 0).max(&ArchitectureSize::new(0, 2)), |
534 | | ArchitectureSize::new(8, 1) |
535 | | ); |
536 | | |
537 | | assert_eq!( |
538 | | align_to_arch( |
539 | | ArchitectureSize::new(2, 0), |
540 | | Alignment::Bytes(NonZeroUsize::new(8).unwrap()) |
541 | | ), |
542 | | ArchitectureSize::new(8, 0) |
543 | | ); |
544 | | assert_eq!( |
545 | | align_to_arch(ArchitectureSize::new(2, 0), Alignment::Pointer), |
546 | | ArchitectureSize::new(0, 1) |
547 | | ); |
548 | | } |
549 | | |
550 | | #[test] |
551 | | fn resource_size() { |
552 | | // keep it identical to the old behavior |
553 | | let obj = SizeAlign::default(); |
554 | | let elem = obj.calculate(&TypeDef { |
555 | | name: None, |
556 | | kind: TypeDefKind::Resource, |
557 | | owner: crate::TypeOwner::None, |
558 | | docs: Default::default(), |
559 | | stability: Default::default(), |
560 | | }); |
561 | | assert_eq!(elem.size, ArchitectureSize::new(usize::MAX, 0)); |
562 | | assert_eq!( |
563 | | elem.align, |
564 | | Alignment::Bytes(NonZeroUsize::new(usize::MAX).unwrap()) |
565 | | ); |
566 | | } |
567 | | #[test] |
568 | | fn result_ptr_10() { |
569 | | let mut obj = SizeAlign::default(); |
570 | | let mut resolve = Resolve::default(); |
571 | | let tuple = crate::Tuple { |
572 | | types: vec![Type::U16, Type::U16, Type::U16, Type::U16, Type::U16], |
573 | | }; |
574 | | let id = resolve.types.alloc(TypeDef { |
575 | | name: None, |
576 | | kind: TypeDefKind::Tuple(tuple), |
577 | | owner: crate::TypeOwner::None, |
578 | | docs: Default::default(), |
579 | | stability: Default::default(), |
580 | | }); |
581 | | obj.fill(&resolve); |
582 | | let my_result = crate::Result_ { |
583 | | ok: Some(Type::String), |
584 | | err: Some(Type::Id(id)), |
585 | | }; |
586 | | let elem = obj.calculate(&TypeDef { |
587 | | name: None, |
588 | | kind: TypeDefKind::Result(my_result), |
589 | | owner: crate::TypeOwner::None, |
590 | | docs: Default::default(), |
591 | | stability: Default::default(), |
592 | | }); |
593 | | assert_eq!(elem.size, ArchitectureSize::new(8, 2)); |
594 | | assert_eq!(elem.align, Alignment::Pointer); |
595 | | } |
596 | | #[test] |
597 | | fn result_ptr_64bit() { |
598 | | let obj = SizeAlign::default(); |
599 | | let my_record = crate::Record { |
600 | | fields: vec![ |
601 | | crate::Field { |
602 | | name: String::new(), |
603 | | ty: Type::String, |
604 | | docs: Default::default(), |
605 | | }, |
606 | | crate::Field { |
607 | | name: String::new(), |
608 | | ty: Type::U64, |
609 | | docs: Default::default(), |
610 | | }, |
611 | | ], |
612 | | }; |
613 | | let elem = obj.calculate(&TypeDef { |
614 | | name: None, |
615 | | kind: TypeDefKind::Record(my_record), |
616 | | owner: crate::TypeOwner::None, |
617 | | docs: Default::default(), |
618 | | stability: Default::default(), |
619 | | }); |
620 | | assert_eq!(elem.size, ArchitectureSize::new(8, 2)); |
621 | | assert_eq!(elem.align, Alignment::Bytes(NonZeroUsize::new(8).unwrap())); |
622 | | } |
623 | | } |