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