1use crate::{
6 AggregateMemoryLocation, CountU16, FrameMemoryAddress, FrameMemoryRegion, FrameMemorySize,
7 InstructionPositionOffset, InstructionRange, MemoryLocation, align_to,
8};
9use fxhash::FxHasher;
10use seq_fmt::comma;
11use std::cmp::{Ordering, max};
12use std::fmt::{Debug, Display, Formatter, Write};
13use std::hash::{Hash, Hasher};
14use std::rc::Rc;
15use swamp_vm_isa::{
16 HEAP_PTR_ON_FRAME_ALIGNMENT, HEAP_PTR_ON_FRAME_SIZE, HeapMemoryAddress, HeapMemoryRegion,
17 InstructionPosition, MAP_HEADER_ALIGNMENT, MAP_HEADER_SIZE, MAP_ITERATOR_ALIGNMENT,
18 MAP_ITERATOR_SIZE, MemoryAlignment, MemoryOffset, MemorySize, ProgramCounterDelta,
19 RANGE_HEADER_ALIGNMENT, RANGE_HEADER_SIZE, RANGE_ITERATOR_ALIGNMENT, RANGE_ITERATOR_SIZE,
20 RegIndex, STRING_PTR_ALIGNMENT, STRING_PTR_SIZE, VEC_HEADER_SIZE, VEC_ITERATOR_ALIGNMENT,
21 VEC_ITERATOR_SIZE, VEC_PTR_ALIGNMENT, VEC_PTR_SIZE,
22};
23use tracing::error;
24use yansi::Paint;
25
26pub type BasicTypeRef = Rc<BasicType>;
27
28#[derive(Clone, Debug)]
29pub struct OffsetMemoryItem {
30 pub offset: MemoryOffset,
31 pub size: MemorySize,
32 pub name: String,
33 pub ty: BasicTypeRef,
34}
35
36impl Display for OffsetMemoryItem {
37 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
38 write!(f, "{}:{}", self.name, self.ty)
39 }
40}
41
42#[derive(Clone, Debug)]
43pub struct StructType {
44 pub name: String,
45 pub fields: Vec<OffsetMemoryItem>,
46 pub total_size: MemorySize,
47 pub max_alignment: MemoryAlignment,
48}
49
50impl Display for StructType {
51 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
52 write!(f, "{}", self.name)?;
53 for field in &self.fields {
54 write!(
55 f,
56 "{:04X}:{:X} {}:{}",
57 field.offset.0, field.size.0, field.name, field.ty
58 )?;
59 }
60 Ok(())
61 }
62}
63
64#[derive(Clone, Debug)]
65pub struct TupleType {
66 pub fields: Vec<OffsetMemoryItem>,
67 pub total_size: MemorySize,
68 pub max_alignment: MemoryAlignment,
69}
70
71impl TupleType {
72 #[must_use]
73 pub fn aligned_size_of_field(&self, field_index: usize) -> MemorySize {
74 let max_alignment: usize = self.max_alignment.into();
75 MemorySize(max(self.fields[field_index].size.0 as usize, max_alignment) as u32)
76 }
77}
78
79impl Display for TupleType {
80 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
81 for field in &self.fields {
82 write!(f, "{:04X}:{:X} {}", field.offset.0, field.size.0, field.ty)?;
83 }
84 Ok(())
85 }
86}
87
88#[derive(Clone, Debug)]
89pub struct TaggedUnionVariant {
90 pub name: String, pub ty: BasicTypeRef, }
93
94impl Display for TaggedUnionVariant {
95 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
96 write!(f, "{}: {}", self.name, self.ty)
97 }
98}
99
100#[derive(Clone, Debug)]
101pub struct TaggedUnion {
102 pub name: String,
103 pub tag_offset: MemoryOffset, pub tag_alignment: MemoryAlignment,
105 pub tag_size: MemorySize,
106 pub payload_max_size: MemorySize,
107 pub max_payload_alignment: MemoryAlignment,
108 pub payload_offset: MemoryOffset,
109 pub variants: Vec<TaggedUnionVariant>,
110 pub total_size: MemorySize,
111 pub max_alignment: MemoryAlignment,
112}
113
114impl Display for TaggedUnion {
115 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
116 write!(f, "union {}:", self.name,)?;
117 for (offset, variant) in self.variants.iter().enumerate() {
118 writeln!(f, " {offset}: {variant}")?;
119 }
120 Ok(())
121 }
122}
123
124impl TaggedUnion {
125 #[must_use]
126 pub fn payload_offset(&self) -> MemoryOffset {
127 align_to(MemoryOffset(self.tag_size.0), self.max_alignment)
128 }
129}
130
131impl TaggedUnion {
132 #[must_use]
133 pub fn get_variant_by_index(&self, index: usize) -> &TaggedUnionVariant {
134 debug_assert!(
135 index < self.variants.len(),
136 "variant out of bounds {index} out of {}",
137 self.variants.len()
138 );
139 &self.variants[index]
140 }
141
142 #[must_use]
143 pub fn get_variant_as_offset_item(&self, index: usize) -> OffsetMemoryItem {
144 let variant = self.get_variant_by_index(index);
145 OffsetMemoryItem {
146 offset: self.payload_offset,
147 size: variant.ty.total_size,
148 name: variant.name.clone(),
149 ty: variant.ty.clone(),
150 }
151 }
152}
153
154#[derive(Debug, Clone)]
155pub struct FrameMemoryAttribute {
156 pub is_temporary: bool,
157}
158
159#[derive(Debug, Clone)]
160pub enum DecoratedOperandAccessKind {
161 WriteRegister(TypedRegister, Option<PathInfo>, FrameMemoryAttribute), ReadRegister(TypedRegister, Option<PathInfo>, FrameMemoryAttribute), ReadIndirectPointer(FrameMemoryAddress), DeltaPc(ProgramCounterDelta), AbsolutePc(InstructionPosition), MemorySize(MemorySize),
167 AbsoluteMemoryPosition(HeapMemoryAddress), WriteFrameMemoryAddress(FrameMemoryAddress), ReadFrameMemoryAddress(FrameMemoryAddress), WriteBaseRegWithOffset(RegIndex, MemoryOffset),
171 ReadBaseRegWithOffset(RegIndex, MemoryOffset),
172 ImmediateU8(u8),
173 ImmediateU16(u16),
174 ImmediateU32(u32),
175 CountU16(u16),
176 CountU8(u8),
177 WriteMask(u8),
178 ReadMask(u8),
179}
180
181pub struct DecoratedOperandOrigin {}
182
183pub struct DecoratedOperand {
184 pub kind: DecoratedOperandAccessKind,
185 pub origin: DecoratedOperandOrigin,
186}
187
188pub struct DecoratedOpcode {
189 pub name: String,
190 pub operands: Vec<DecoratedOperand>,
191}
192
193#[derive(Clone, Debug)]
194pub struct MemoryElement {
195 pub offset: MemoryOffset,
196 pub size: MemorySize,
197 pub alignment: MemoryAlignment,
198}
199
200#[derive(Clone, Debug)]
201pub enum BasicTypeKind {
202 Empty,
203 Pointer,
204 U8,
205 B8,
206 U16,
207 S32,
208 Fixed32,
209 U32,
210 StringView {
211 byte: BasicTypeRef,
212 char: BasicTypeRef,
213 },
214 Struct(StructType),
215 TaggedUnion(TaggedUnion),
216 Tuple(TupleType),
217 Optional(TaggedUnion),
218 InternalRangeHeader,
219
220 InternalVecIterator,
222 InternalStringIterator,
223 InternalMapIterator,
224 InternalSparseIterator,
225 InternalRangeIterator,
226 SliceView(BasicTypeRef),
228
229 FixedCapacityArray(BasicTypeRef, usize),
231 DynamicLengthVecView(BasicTypeRef),
232 VecStorage(BasicTypeRef, usize),
233 StringStorage {
234 element_type: BasicTypeRef,
235 char: BasicTypeRef,
236 capacity: usize,
237 },
238 StackStorage(BasicTypeRef, usize),
239 QueueStorage(BasicTypeRef, usize),
240 MapStorage {
241 key_type: BasicTypeRef,
242 value_type: BasicTypeRef,
243 logical_limit: usize,
244 capacity: CountU16,
245 },
246 SparseView(BasicTypeRef),
247 SparseStorage(BasicTypeRef, usize),
248
249 DynamicLengthMapView(Box<OffsetMemoryItem>, Box<OffsetMemoryItem>),
250 GridView(BasicTypeRef),
252 GridStorage(BasicTypeRef, usize, usize),
253 Any,
254}
255
256impl BasicTypeKind {
257 pub(crate) const fn manifestation(&self) -> Manifestation {
258 if self.is_scalar() {
259 Manifestation::Scalar
260 } else {
261 Manifestation::Aggregate
262 }
263 }
264
265 #[must_use]
266 pub fn element(&self) -> Option<BasicTypeRef> {
267 match &self {
268 Self::StackStorage(inner, _)
269 | Self::GridView(inner)
270 | Self::GridStorage(inner, ..)
271 | Self::SparseStorage(inner, _)
272 | Self::SparseView(inner)
273 | Self::QueueStorage(inner, _)
274 | Self::DynamicLengthVecView(inner)
275 | Self::FixedCapacityArray(inner, _)
276 | Self::VecStorage(inner, _)
277 | Self::SliceView(inner) => Some(inner.clone()),
278
279 Self::StringStorage { char, .. } | Self::StringView { char, .. } => Some(char.clone()),
280
281 _ => None,
282 }
283 }
284}
285
286pub enum Manifestation {
287 Scalar,
288 Aggregate,
289}
290
291impl Manifestation {
292 #[must_use]
293 pub const fn string(&self) -> &str {
294 match self {
295 Self::Scalar => "scalar",
296 Self::Aggregate => "aggregate",
297 }
298 }
299}
300
301impl Display for Manifestation {
302 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
303 write!(f, "{}", self.string())
304 }
305}
306
307impl BasicTypeKind {
308 pub(crate) const fn is_scalar(&self) -> bool {
309 matches!(
310 self,
311 Self::Empty
312 | Self::B8
313 | Self::U8
314 | Self::U16
315 | Self::S32
316 | Self::U32
317 | Self::Fixed32
318 | Self::StringView { .. }
319 )
320 }
321
322 #[must_use]
323 pub const fn is_reg_copy(&self) -> bool {
324 self.is_scalar()
325 }
326
327 #[must_use]
328 pub const fn is_view(&self) -> bool {
329 match self {
330 Self::GridView(_)
331 | Self::DynamicLengthMapView(_, _)
332 | Self::SparseView(_)
333 | Self::DynamicLengthVecView(_)
334 | Self::SliceView(_)
335 | Self::StringView { .. } => true,
336 _ => false,
337 }
338 }
339
340 #[must_use]
341 pub const fn is_aggregate(&self) -> bool {
342 !self.is_scalar()
343 }
344
345 #[must_use]
346 pub const fn is_mutable_reference(&self) -> bool {
347 false }
349
350 pub(crate) const fn is_immutable(&self) -> bool {
351 !self.is_mutable_reference()
352 }
353
354 pub(crate) const fn is_storage(&self) -> bool {
355 !self.is_storage()
356 }
357
358 #[must_use]
359 pub const fn needs_copy_back_when_mutable(&self) -> bool {
360 self.is_scalar()
361 }
362
363 #[must_use]
364 pub fn union_info(&self) -> &TaggedUnion {
365 if let Self::TaggedUnion(union) = self {
366 union
367 } else {
368 panic!("wrong type")
369 }
370 }
371}
372
373impl Display for BasicTypeKind {
374 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
375 match self {
376 Self::Empty => write!(f, "()"),
377 Self::Pointer => write!(f, "Ptr"),
378 Self::Any => write!(f, "Any"),
379 Self::U8 => write!(f, "u8"),
380 Self::B8 => write!(f, "b8"),
381 Self::U16 => write!(f, "u16"),
382 Self::S32 => write!(f, "i32"),
383 Self::Fixed32 => write!(f, "Fixed(i32)"),
384 Self::U32 => write!(f, "u32"),
385 Self::StringView { .. } => write!(f, "String"),
386 Self::InternalRangeHeader => write!(f, "Range"),
387 Self::FixedCapacityArray(item_type, size) => write!(f, "[{item_type}; {size}]"),
388 Self::DynamicLengthVecView(item_type) => write!(f, "Vec<{item_type}>"),
389 Self::VecStorage(item_type, size) => write!(f, "Vec<{item_type}, {size}>"),
390 Self::StringStorage {
391 element_type: byte,
392 capacity,
393 ..
394 } => write!(f, "String<{byte}, {capacity}>"),
395 Self::SparseView(item_type) => write!(f, "Sparse<{item_type}>"),
396 Self::GridView(item_type) => write!(f, "Grid<{item_type}>"),
397 Self::SparseStorage(item_type, size) => write!(f, "SparseStorage<{item_type}, {size}>"),
398 Self::StackStorage(item_type, size) => write!(f, "StackStorage<{item_type}, {size}>"),
399 Self::GridStorage(item_type, width, height) => {
400 write!(f, "GridStorage<{item_type}, ({width},{height})>")
401 }
402 Self::QueueStorage(item_type, size) => write!(f, "QueueStorage<{item_type}, {size}>"),
403 Self::MapStorage {
404 logical_limit: logical_size,
405 capacity,
406 key_type,
407 value_type,
408 ..
409 } => write!(
410 f,
411 "MapStorage<{key_type}, {value_type}, {logical_size} ({capacity})>",
412 ),
413 Self::DynamicLengthMapView(key, value) => write!(f, "Map<{key}, {value}>"),
414 Self::InternalVecIterator => write!(f, "Vec::Iterator"),
415 Self::InternalStringIterator => write!(f, "String::Iterator"),
416 Self::InternalMapIterator => write!(f, "Map::Iterator"),
417 Self::InternalSparseIterator => write!(f, "Sparse::Iterator"),
418 Self::InternalRangeIterator => write!(f, "Range::Iterator"),
419 Self::Struct(struct_type) => write!(f, "{}", struct_type.name),
420 Self::TaggedUnion(union) => write!(f, "enum {}", union.name),
421 Self::Optional(optional) => write!(f, "{}?", optional.get_variant_by_index(1).ty),
422 Self::Tuple(tuple_type) => write!(f, "({})", comma(&tuple_type.fields)),
423 Self::SliceView(a) => write!(f, "slice<{}>", a.kind),
424 }
425 }
426}
427
428#[must_use]
429pub fn pointer_type_again() -> BasicTypeRef {
430 Rc::new(BasicType {
431 id: BasicTypeId::EMPTY,
432 kind: BasicTypeKind::U8, total_size: MemorySize(4),
434 max_alignment: MemoryAlignment::U32,
435 })
436}
437
438#[must_use]
440pub fn string_type() -> BasicTypeRef {
441 Rc::new(BasicType {
442 id: BasicTypeId::EMPTY,
443 kind: BasicTypeKind::U8,
444 total_size: STRING_PTR_SIZE,
445 max_alignment: STRING_PTR_ALIGNMENT,
446 })
447}
448#[must_use]
450pub fn int_type() -> BasicTypeRef {
451 Rc::new(BasicType {
452 id: BasicTypeId::EMPTY,
453 kind: BasicTypeKind::S32,
454 total_size: MemorySize(4),
455 max_alignment: MemoryAlignment::U32,
456 })
457}
458
459#[must_use]
461pub fn float_type() -> BasicTypeRef {
462 Rc::new(BasicType {
463 id: BasicTypeId::EMPTY,
464 kind: BasicTypeKind::Fixed32,
465 total_size: MemorySize(4),
466 max_alignment: MemoryAlignment::U32,
467 })
468}
469
470#[must_use]
472pub fn bytes_type() -> BasicTypeRef {
473 Rc::new(BasicType {
474 id: BasicTypeId::EMPTY,
475 kind: BasicTypeKind::Empty,
476 total_size: MemorySize(0),
477 max_alignment: MemoryAlignment::U32,
478 })
479}
480
481#[must_use]
482pub const fn range_type() -> BasicType {
483 BasicType {
484 id: BasicTypeId::EMPTY,
485 kind: BasicTypeKind::InternalRangeHeader,
486 total_size: RANGE_HEADER_SIZE,
487 max_alignment: RANGE_HEADER_ALIGNMENT,
488 }
489}
490
491#[must_use]
492pub const fn range_iter_type() -> BasicType {
493 BasicType {
494 id: BasicTypeId::EMPTY,
495 kind: BasicTypeKind::InternalRangeIterator,
496 total_size: RANGE_ITERATOR_SIZE,
497 max_alignment: RANGE_ITERATOR_ALIGNMENT,
498 }
499}
500
501#[must_use]
502pub fn slice_type() -> BasicType {
503 BasicType {
504 id: BasicTypeId::EMPTY,
505 kind: BasicTypeKind::SliceView(BasicTypeRef::from(u8_type())), total_size: MAP_HEADER_SIZE,
507 max_alignment: MAP_HEADER_ALIGNMENT,
508 }
509}
510
511#[must_use]
513pub fn unknown_type() -> BasicTypeRef {
514 Rc::new(BasicType {
515 id: BasicTypeId::EMPTY,
516 kind: BasicTypeKind::Empty,
517 total_size: MemorySize(0),
518 max_alignment: MemoryAlignment::U8,
519 })
520}
521
522#[must_use]
523pub fn vec_type() -> BasicType {
524 BasicType {
525 id: BasicTypeId::EMPTY,
526 kind: BasicTypeKind::DynamicLengthVecView(BasicTypeRef::from(unknown_type())),
527 total_size: VEC_PTR_SIZE,
528 max_alignment: VEC_PTR_ALIGNMENT,
529 }
530}
531
532#[must_use]
533pub const fn vec_iter_type() -> BasicType {
534 BasicType {
535 id: BasicTypeId::EMPTY,
536 kind: BasicTypeKind::InternalVecIterator,
537 total_size: VEC_ITERATOR_SIZE,
538 max_alignment: VEC_ITERATOR_ALIGNMENT,
539 }
540}
541
542#[must_use]
543pub fn map_type() -> BasicType {
544 BasicType {
545 id: BasicTypeId::EMPTY,
546 kind: BasicTypeKind::DynamicLengthMapView(
547 Box::from(OffsetMemoryItem {
548 offset: MemoryOffset(0),
549 size: MemorySize(0),
550 name: String::new(),
551 ty: Rc::new(BasicType {
552 id: BasicTypeId::EMPTY,
553 kind: BasicTypeKind::Empty,
554 total_size: MemorySize(0),
555 max_alignment: MemoryAlignment::U8,
556 }),
557 }),
558 Box::from(OffsetMemoryItem {
559 offset: MemoryOffset(0),
560 size: MemorySize(0),
561 name: String::new(),
562 ty: Rc::new(BasicType {
563 id: BasicTypeId::EMPTY,
564 kind: BasicTypeKind::Empty,
565 total_size: MemorySize(0),
566 max_alignment: MemoryAlignment::U8,
567 }),
568 }),
569 ),
570
571 total_size: MAP_HEADER_SIZE,
572 max_alignment: MAP_HEADER_ALIGNMENT,
573 }
574}
575
576#[must_use]
577pub const fn map_iter_type() -> BasicType {
578 BasicType {
579 id: BasicTypeId::EMPTY,
580 kind: BasicTypeKind::InternalMapIterator,
581 total_size: MAP_ITERATOR_SIZE,
582 max_alignment: MAP_ITERATOR_ALIGNMENT,
583 }
584}
585
586#[must_use]
588pub fn u32_type() -> BasicTypeRef {
589 Rc::new(BasicType {
590 id: BasicTypeId::EMPTY,
591 kind: BasicTypeKind::U32,
592 total_size: MemorySize(4),
593 max_alignment: MemoryAlignment::U32,
594 })
595}
596
597#[must_use]
598pub fn u16_type() -> BasicTypeRef {
599 Rc::new(BasicType {
600 id: BasicTypeId::EMPTY,
601 kind: BasicTypeKind::U16,
602 total_size: MemorySize(2),
603 max_alignment: MemoryAlignment::U16,
604 })
605}
606
607#[must_use]
609pub fn u8_type() -> BasicTypeRef {
610 Rc::new(BasicType {
611 id: BasicTypeId::EMPTY,
612 kind: BasicTypeKind::U8,
613 total_size: MemorySize(1),
614 max_alignment: MemoryAlignment::U8,
615 })
616}
617
618#[must_use]
620pub fn b8_type() -> BasicTypeRef {
621 Rc::new(BasicType {
622 id: BasicTypeId::EMPTY,
623 kind: BasicTypeKind::B8,
624 total_size: MemorySize(1),
625 max_alignment: MemoryAlignment::U8,
626 })
627}
628
629#[must_use]
632pub fn pointer_type() -> BasicTypeRef {
633 Rc::new(BasicType {
635 id: BasicTypeId::EMPTY,
636 kind: BasicTypeKind::U8, total_size: HEAP_PTR_ON_FRAME_SIZE,
638 max_alignment: HEAP_PTR_ON_FRAME_ALIGNMENT,
639 })
640}
641
642#[derive(Clone, Debug)]
644pub struct HeapPlacedArray {
645 addr: HeapMemoryAddress,
646 byte_count: u32,
647}
648
649impl HeapPlacedArray {
650 #[must_use]
651 pub const fn new(addr: HeapMemoryAddress, byte_count: u32) -> Self {
652 Self { addr, byte_count }
653 }
654
655 #[must_use]
656 pub const fn addr(&self) -> HeapMemoryAddress {
657 self.addr
658 }
659
660 #[must_use]
661 pub const fn byte_count(&self) -> u32 {
662 self.byte_count
663 }
664}
665
666#[derive(Clone, Debug)]
668pub struct HeapPlacedType {
669 addr: HeapMemoryAddress,
670 ty: BasicTypeRef,
671}
672
673impl HeapPlacedType {
674 #[must_use]
675 pub const fn new(addr: HeapMemoryAddress, ty: BasicTypeRef) -> Self {
676 Self { addr, ty }
677 }
678
679 #[must_use]
680 pub fn region(&self) -> HeapMemoryRegion {
681 HeapMemoryRegion {
682 addr: self.addr,
683 size: self.ty.total_size,
684 }
685 }
686
687 #[must_use]
688 pub const fn addr(&self) -> HeapMemoryAddress {
689 self.addr
690 }
691
692 #[must_use]
693 pub fn size(&self) -> MemorySize {
694 self.ty.total_size
695 }
696
697 #[must_use]
698 pub const fn ty(&self) -> &BasicTypeRef {
699 &self.ty
700 }
701}
702
703#[derive(Clone, Debug)]
705pub enum Place {
706 Discard, Register(TypedRegister),
708 Memory(MemoryLocation),
709}
710
711impl Place {
712 #[must_use]
713 pub const fn vm_type(&self) -> Option<&VmType> {
714 match self {
715 Self::Discard => None,
716 Self::Register(reg) => Some(®.ty),
717 Self::Memory(mem) => Some(&mem.ty),
718 }
719 }
720}
721
722impl Display for Place {
723 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
724 match self {
725 Self::Discard => write!(f, "unit ()"),
726 Self::Register(reg) => write!(f, "reg: {reg}"),
727 Self::Memory(memory_location) => write!(f, "memory_location {memory_location:?}"),
728 }
729 }
730}
731
732impl Place {
733 #[must_use]
734 pub const fn memory_location(&self) -> Option<&MemoryLocation> {
735 match self {
736 Self::Discard => None,
737 Self::Register(_) => None,
738 Self::Memory(memory_location) => Some(memory_location),
739 }
740 }
741}
742
743impl Place {
744 #[must_use]
745 pub fn add_offset(&self, offset: MemoryOffset, vm_type: VmType) -> Self {
746 match self {
747 Self::Discard => {
748 panic!("add_offset")
749 }
750 Self::Register(reg) => {
751 if reg.ty.is_aggregate() {
752 Self::Memory(MemoryLocation {
753 base_ptr_reg: reg.clone(),
754 offset,
755 ty: vm_type,
756 })
757 } else {
758 panic!(
759 "can not add offset to a register since it wasn't an aggregate {}",
760 reg.ty
761 )
762 }
763 }
764 Self::Memory(memory_location) => Self::Memory(MemoryLocation {
765 base_ptr_reg: memory_location.base_ptr_reg.clone(),
766 offset: memory_location.offset + offset,
767 ty: vm_type,
768 }),
769 }
770 }
771 #[must_use]
772 pub const fn new_unit() -> Self {
773 Self::Discard
774 }
775 #[must_use]
776 pub const fn new_reg(register: TypedRegister) -> Self {
777 Self::Register(register)
778 }
779 #[must_use]
780 pub const fn new_location(memory_location: MemoryLocation) -> Self {
781 Self::Memory(memory_location)
782 }
783
784 #[must_use]
785 pub const fn is_unit(&self) -> bool {
786 matches!(self, Self::Discard)
787 }
788 #[must_use]
789 pub const fn is_memory_location(&self) -> bool {
790 matches!(self, Self::Memory(_))
791 }
792
793 #[must_use]
794 pub const fn is_register(&self) -> bool {
795 matches!(self, Self::Register(_))
796 }
797 #[must_use]
798 pub fn ty(&self) -> &BasicTypeRef {
799 match self {
800 Self::Discard => panic!("no type"),
801 Self::Register(reg) => ®.ty.basic_type,
802 Self::Memory(location) => &location.ty.basic_type,
803 }
804 }
805
806 #[must_use]
807 pub const fn register(&self) -> Option<&TypedRegister> {
808 match self {
809 Self::Register(reg) => Some(reg),
810 _ => None,
811 }
812 }
813
814 #[must_use]
815 pub const fn register_involved_in_destination(&self) -> Option<&TypedRegister> {
816 match self {
817 Self::Register(reg) => Some(reg),
818 Self::Memory(memory_location) => Some(memory_location.reg()),
819 Self::Discard => None,
820 }
821 }
822
823 #[must_use]
824 pub fn grab_register(&self) -> &TypedRegister {
825 match self {
826 Self::Register(reg) => reg,
827 Self::Memory(_) => {
828 panic!("assumed it would be a register")
829 }
830 Self::Discard => panic!("assumed it would be a register, but was unit"),
831 }
832 }
833
834 #[must_use]
835 pub fn grab_memory_location(&self) -> &MemoryLocation {
836 match self {
837 Self::Register(_reg) => panic!("assumed it was a memory location"),
838 Self::Memory(location) => location,
839 Self::Discard => {
840 panic!("assumed it would be a memory location, but was unit")
841 }
842 }
843 }
844
845 #[must_use]
848 pub fn memory_location_or_pointer_reg(&self) -> MemoryLocation {
849 match self {
850 Self::Register(reg) => MemoryLocation {
851 base_ptr_reg: reg.clone(),
852 offset: MemoryOffset(0),
853 ty: reg.ty.clone(),
854 },
855 Self::Memory(location) => location.clone(),
856 Self::Discard => {
857 panic!("assumed it would be a memory location, but was unit")
858 }
859 }
860 }
861
862 #[must_use]
863 pub fn grab_aggregate_memory_location_or_pointer_reg(&self) -> AggregateMemoryLocation {
864 AggregateMemoryLocation {
865 location: self.memory_location_or_pointer_reg(),
866 }
867 }
868 #[must_use]
869 pub fn grab_aggregate_memory_location(&self) -> AggregateMemoryLocation {
870 AggregateMemoryLocation {
871 location: self.grab_memory_location().clone(),
872 }
873 }
874}
875
876#[derive(Clone)]
877pub struct TypedRegister {
878 pub index: u8,
879 pub ty: VmType,
880 pub comment: String,
881}
882
883impl PartialEq<Self> for TypedRegister {
884 fn eq(&self, other: &Self) -> bool {
885 self.index == other.index
886 }
887}
888
889impl Eq for TypedRegister {}
890
891impl Ord for TypedRegister {
892 fn cmp(&self, other: &Self) -> Ordering {
893 self.index.cmp(&other.index)
894 }
895}
896impl PartialOrd<Self> for TypedRegister {
897 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
898 self.index.partial_cmp(&other.index)
899 }
900}
901
902impl TypedRegister {
903 #[must_use]
904 pub fn comment(&self) -> &str {
905 &self.comment
906 }
907}
908
909impl TypedRegister {
910 #[must_use]
911 pub fn new_empty_reserved() -> Self {
912 Self {
913 index: 0xff,
914 ty: VmType::new_unknown_placement(BasicTypeRef::from(unknown_type())),
915 comment: String::new(),
916 }
917 }
918}
919
920impl TypedRegister {
921 #[must_use]
922 pub fn final_type(&self) -> BasicTypeRef {
923 self.ty.basic_type.clone()
924 }
925}
926
927impl Debug for TypedRegister {
928 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
929 write!(f, "r{} ({} - {})", self.index, self.ty, self.comment)
930 }
931}
932
933impl Display for TypedRegister {
934 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
935 write!(f, "r{}", self.index)
936 }
937}
938
939impl TypedRegister {
940 #[must_use]
941 pub fn new_frame_placed(index: u8, frame_placed: FramePlacedType) -> Self {
942 Self {
943 index,
944 ty: VmType::new_frame_placed(frame_placed),
945 comment: String::new(),
946 }
947 }
948
949 #[must_use]
950 pub const fn new_vm_type(index: u8, ty: VmType) -> Self {
951 Self {
952 index,
953 ty,
954 comment: String::new(),
955 }
956 }
957
958 pub fn with_comment(&mut self, comment: &str) -> &mut Self {
959 self.comment = comment.to_string();
960 self
961 }
962 #[must_use]
963 pub const fn addressing(&self) -> u8 {
964 self.index
965 }
966
967 #[must_use]
968 pub const fn ty(&self) -> &BasicTypeRef {
969 &self.ty.basic_type
970 }
971
972 #[must_use]
973 pub fn frame_placed(&self) -> FramePlacedType {
974 if let Some(fp) = self.ty.frame_placed_type() {
975 fp
976 } else {
977 panic!("")
978 }
979 }
980
981 #[must_use]
982 pub fn size(&self) -> MemorySize {
983 self.ty.basic_type.total_size
984 }
985
986 #[must_use]
987 pub fn addr(&self) -> FrameMemoryAddress {
988 self.frame_placed().addr
989 }
990
991 #[must_use]
992 pub fn region(&self) -> FrameMemoryRegion {
993 self.frame_placed().region()
994 }
995
996 #[must_use]
997 pub fn underlying(&self) -> BasicTypeRef {
998 self.ty.basic_type.clone()
999 }
1000}
1001
1002#[derive(Clone, Debug)]
1003pub enum VmTypeOrigin {
1004 Unknown,
1005 InsideReg,
1006 Frame(FrameMemoryRegion),
1007 Heap(HeapMemoryRegion), }
1009
1010impl Display for VmTypeOrigin {
1011 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1012 match self {
1013 Self::Unknown => Ok(()),
1014 Self::Frame(region) => write!(f, "frame {region}"),
1015 Self::Heap(region) => write!(f, "heap {region}"),
1016 Self::InsideReg => write!(f, "reg"),
1017 }
1018 }
1019}
1020
1021#[derive(Clone, Debug)]
1022pub struct VmType {
1023 pub basic_type: BasicTypeRef,
1024 pub origin: VmTypeOrigin,
1025}
1026
1027impl VmType {
1028 #[must_use]
1029 pub fn is_collection_like(&self) -> bool {
1030 self.basic_type.is_collection_like()
1031 }
1032}
1033
1034impl VmType {
1035 #[must_use]
1036 pub fn is_mutable_primitive(&self) -> bool {
1037 self.basic_type.is_mutable_reference()
1038 && self
1039 .basic_type
1040 .should_be_copied_back_when_mutable_arg_or_return()
1041 }
1042
1043 #[must_use]
1044 pub fn element_count_always_same_as_capacity(&self) -> bool {
1045 self.basic_type.element_count_always_same_as_capacity()
1046 }
1047}
1048
1049impl Display for VmType {
1050 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1051 write!(
1052 f,
1053 "{} {} {}",
1054 tinter::bright_green(&self.basic_type),
1055 self.origin,
1056 tinter::bright_magenta(self.manifestation())
1057 )
1058 }
1059}
1060
1061impl VmType {
1062 #[must_use]
1063 pub fn new_frame_placed(frame_placed: FramePlacedType) -> Self {
1064 Self {
1065 basic_type: frame_placed.ty.clone(),
1066 origin: VmTypeOrigin::Frame(frame_placed.region()),
1067 }
1068 }
1069 #[must_use]
1070 pub fn is_immutable(&self) -> bool {
1071 self.basic_type.kind.is_immutable()
1072 }
1073
1074 #[must_use]
1075 pub fn manifestation(&self) -> Manifestation {
1076 self.basic_type.manifestation()
1077 }
1078
1079 #[must_use]
1080 pub const fn new_heap_placement(
1081 basic_type: BasicTypeRef,
1082 heap_region: HeapMemoryRegion,
1083 ) -> Self {
1084 Self {
1085 basic_type,
1086 origin: VmTypeOrigin::Heap(heap_region),
1087 }
1088 }
1089
1090 #[must_use]
1091 pub const fn new_contained_in_register(basic_type: BasicTypeRef) -> Self {
1092 Self {
1093 basic_type,
1094 origin: VmTypeOrigin::InsideReg,
1095 }
1096 }
1097
1098 #[must_use]
1099 pub const fn new_unknown_placement(basic_type: BasicTypeRef) -> Self {
1100 Self {
1101 basic_type,
1102 origin: VmTypeOrigin::Unknown,
1103 }
1104 }
1105
1106 #[must_use]
1107 pub const fn new_basic_with_origin(basic_type: BasicTypeRef, origin: VmTypeOrigin) -> Self {
1108 Self { basic_type, origin }
1109 }
1110
1111 #[must_use]
1112 pub fn frame_placed_type(&self) -> Option<FramePlacedType> {
1113 if let VmTypeOrigin::Frame(region) = self.origin {
1114 Some(FramePlacedType {
1115 addr: region.addr,
1116 ty: self.basic_type.clone(),
1117 })
1118 } else {
1119 None
1120 }
1121 }
1122
1123 #[must_use]
1124 pub fn is_mutable_reference_semantic(&self) -> bool {
1125 self.basic_type.is_mutable_reference()
1126 }
1127
1128 #[must_use]
1129 pub fn is_aggregate(&self) -> bool {
1130 self.basic_type.is_aggregate()
1131 }
1132
1133 #[must_use]
1134 pub fn is_scalar(&self) -> bool {
1135 self.basic_type.is_scalar()
1136 }
1137
1138 #[must_use]
1139 pub fn is_reg_copy(&self) -> bool {
1140 self.basic_type.is_reg_copy()
1141 }
1142
1143 #[must_use]
1144 pub fn needs_allocated_space_for_return_in_reg0(&self) -> bool {
1145 self.basic_type.is_aggregate()
1146 }
1147
1148 #[must_use]
1149 pub fn needs_copy_back_for_mutable(&self) -> bool {
1150 !self.basic_type.is_aggregate()
1151 }
1152 #[must_use]
1153 pub const fn basic_type(&self) -> &BasicTypeRef {
1154 &self.basic_type
1155 }
1156}
1157
1158#[derive(Clone, Debug)]
1160pub struct FramePlacedType {
1161 addr: FrameMemoryAddress,
1162 ty: BasicTypeRef,
1163}
1164
1165impl FramePlacedType {
1166 #[must_use]
1167 pub const fn new(addr: FrameMemoryAddress, ty: BasicTypeRef) -> Self {
1168 Self { addr, ty }
1169 }
1170
1171 #[must_use]
1172 pub fn region(&self) -> FrameMemoryRegion {
1173 FrameMemoryRegion {
1174 addr: self.addr,
1175 size: self.ty.total_size,
1176 }
1177 }
1178
1179 #[must_use]
1180 pub const fn addr(&self) -> FrameMemoryAddress {
1181 self.addr
1182 }
1183
1184 #[must_use]
1185 pub fn size(&self) -> MemorySize {
1186 self.ty.total_size
1187 }
1188
1189 #[must_use]
1190 pub fn ty(&self) -> &BasicType {
1191 &self.ty
1192 }
1193
1194 #[must_use]
1195 pub fn final_type(&self) -> BasicTypeRef {
1196 self.ty.clone()
1197 }
1198
1199 #[must_use]
1200 pub fn move_with_offset(&self, offset: MemoryOffset, ty: BasicTypeRef) -> Self {
1201 Self {
1202 addr: self.addr + offset,
1203 ty,
1204 }
1205 }
1206
1207 #[must_use]
1208 pub fn move_to_field(&self, index: usize) -> Self {
1209 let offset_info = self.ty.get_field_offset(index).unwrap();
1210 Self {
1211 addr: self.addr + offset_info.offset,
1212 ty: offset_info.ty.clone(),
1213 }
1214 }
1215
1216 #[must_use]
1217 pub fn move_to_optional_some_payload(&self) -> Self {
1218 self.move_to_optional_payload_variant(1)
1219 }
1220
1221 #[must_use]
1222 pub fn move_to_optional_none_payload(&self) -> Self {
1223 self.move_to_optional_payload_variant(0)
1224 }
1225
1226 #[must_use]
1227 pub fn move_to_optional_payload_variant(&self, index: usize) -> Self {
1228 let optional_info = self.ty.optional_info().unwrap();
1229 Self::new(
1230 self.addr + optional_info.payload_offset,
1231 optional_info.get_variant_by_index(index).ty.clone(),
1232 )
1233 }
1234
1235 #[must_use]
1236 pub fn move_to_optional_tag(&self) -> Self {
1237 let optional_info = self.ty().optional_info().unwrap();
1238
1239 let addr = self.addr() + optional_info.tag_offset;
1240 assert_eq!(optional_info.tag_size.0, 1);
1241
1242 let tag_type = Rc::new(BasicType {
1243 id: BasicTypeId::EMPTY,
1244 kind: BasicTypeKind::B8,
1245 total_size: MemorySize(1),
1246 max_alignment: MemoryAlignment::U8,
1247 });
1248
1249 Self::new(addr, tag_type)
1250 }
1251}
1252
1253pub enum BoundsCheck {
1254 KnownSizeAtCompileTime(u16),
1255 RegisterWithMaxCount(TypedRegister),
1256}
1257
1258#[derive(Clone, Debug)]
1259pub struct BasicTypeId(pub u32);
1260
1261impl BasicTypeId {
1262 pub const EMPTY: Self = Self(0xffff_ffff);
1263}
1264
1265#[derive(Clone, Debug)]
1266pub struct BasicType {
1267 pub id: BasicTypeId,
1268 pub kind: BasicTypeKind,
1269 pub total_size: MemorySize,
1270 pub max_alignment: MemoryAlignment,
1271}
1272
1273impl BasicType {
1274 #[must_use]
1275 pub const fn is_vec_like(&self) -> bool {
1276 matches!(
1277 self.kind,
1278 BasicTypeKind::VecStorage(..)
1279 | BasicTypeKind::DynamicLengthVecView(..)
1280 | BasicTypeKind::StringStorage { .. }
1281 | BasicTypeKind::StringView { .. }
1282 | BasicTypeKind::StackStorage(..)
1283 | BasicTypeKind::QueueStorage(..)
1284 | BasicTypeKind::SliceView(..)
1285 | BasicTypeKind::FixedCapacityArray(..)
1286 )
1287 }
1288
1289 #[must_use]
1290 pub fn element(&self) -> Option<BasicTypeRef> {
1291 self.kind.element()
1292 }
1293
1294 #[must_use]
1295 pub const fn is_collection(&self) -> bool {
1296 matches!(
1297 self.kind,
1298 BasicTypeKind::VecStorage(..)
1299 | BasicTypeKind::StringStorage { .. }
1300 | BasicTypeKind::StringView { .. }
1301 | BasicTypeKind::SliceView(..)
1302 | BasicTypeKind::FixedCapacityArray(..)
1303 | BasicTypeKind::DynamicLengthVecView(..)
1304 | BasicTypeKind::MapStorage { .. }
1305 | BasicTypeKind::DynamicLengthMapView(..)
1306 | BasicTypeKind::GridStorage(..)
1307 | BasicTypeKind::GridView(..)
1308 | BasicTypeKind::SparseStorage(..)
1309 | BasicTypeKind::SparseView(..)
1310 | BasicTypeKind::StackStorage(..)
1311 | BasicTypeKind::QueueStorage(..)
1312 )
1313 }
1314
1315 #[must_use]
1316 pub fn might_contain_collections(&self) -> bool {
1317 match &self.kind {
1318 BasicTypeKind::Struct(struct_type) => struct_type
1319 .fields
1320 .iter()
1321 .any(|field| field.ty.is_collection() || field.ty.might_contain_collections()),
1322 BasicTypeKind::Tuple(tuple_type) => tuple_type
1323 .fields
1324 .iter()
1325 .any(|field| field.ty.is_collection() || field.ty.might_contain_collections()),
1326 BasicTypeKind::TaggedUnion(union_type) => union_type.variants.iter().any(|variant| {
1327 variant.ty.is_collection() || variant.ty.might_contain_collections()
1328 }),
1329 BasicTypeKind::Optional(union_type) => union_type.variants.iter().any(|variant| {
1330 variant.ty.is_collection() || variant.ty.might_contain_collections()
1331 }),
1332 BasicTypeKind::MapStorage { value_type, .. } => {
1333 value_type.is_collection() || value_type.might_contain_collections()
1334 }
1335 _ => false,
1336 }
1337 }
1338
1339 pub(crate) const fn element_count_always_same_as_capacity(&self) -> bool {
1340 matches!(self.kind, BasicTypeKind::FixedCapacityArray(..))
1341 }
1342 #[must_use]
1343 pub const fn is_collection_like(&self) -> bool {
1344 matches!(
1345 self.kind,
1346 BasicTypeKind::FixedCapacityArray(..)
1347 | BasicTypeKind::StringView { .. }
1349 | BasicTypeKind::StringStorage { .. }
1350
1351 | BasicTypeKind::VecStorage(..)
1353 | BasicTypeKind::StackStorage(..)
1354 | BasicTypeKind::DynamicLengthVecView(..)
1355 | BasicTypeKind::MapStorage { ..}
1357 | BasicTypeKind::DynamicLengthMapView(..)
1358 )
1359 }
1360 #[must_use]
1361 pub const fn is_collection_with_capacity(&self) -> bool {
1362 matches!(
1363 self.kind,
1364 BasicTypeKind::FixedCapacityArray(..)
1365 | BasicTypeKind::VecStorage(..)
1367 | BasicTypeKind::StringStorage {..}
1368 | BasicTypeKind::MapStorage { ..}
1370 )
1371 }
1372}
1373
1374impl BasicType {
1375 pub(crate) const fn manifestation(&self) -> Manifestation {
1376 self.kind.manifestation()
1377 }
1378}
1379
1380impl BasicType {
1381 #[must_use]
1382 pub const fn should_be_copied_back_when_mutable_arg_or_return(&self) -> bool {
1383 !self.is_aggregate()
1384 }
1385}
1386
1387impl BasicType {
1388 #[must_use]
1389 pub fn referenced_type(&self) -> &Self {
1390 panic!("referenced_type() is no longer supported - MutablePointer was removed")
1392 }
1393}
1394
1395impl BasicType {
1396 #[must_use]
1397 pub const fn make_pointer(&self) -> Self {
1398 Self {
1400 id: BasicTypeId::EMPTY,
1401 kind: BasicTypeKind::U8,
1402 total_size: HEAP_PTR_ON_FRAME_SIZE,
1403 max_alignment: HEAP_PTR_ON_FRAME_ALIGNMENT,
1404 }
1405 }
1406}
1407
1408impl BasicType {}
1409
1410impl BasicType {
1411 #[must_use]
1412 pub fn get_variant(&self, variant_index: usize) -> &TaggedUnionVariant {
1413 match &self.kind {
1414 BasicTypeKind::TaggedUnion(tagged) | BasicTypeKind::Optional(tagged) => {
1415 tagged.get_variant_by_index(variant_index)
1416 }
1417 _ => panic!("type is not a tagged union"),
1418 }
1419 }
1420}
1421
1422impl BasicType {
1423 #[must_use]
1424 pub const fn is_scalar(&self) -> bool {
1425 self.kind.is_scalar()
1426 }
1427
1428 #[must_use]
1429 pub const fn is_reg_copy(&self) -> bool {
1430 self.kind.is_reg_copy()
1431 }
1432
1433 #[must_use]
1434 pub const fn is_scratch_arena_allocated(&self) -> bool {
1435 matches!(self.kind, BasicTypeKind::StringView { .. })
1436 }
1437
1438 #[must_use]
1439 pub const fn needs_hidden_pointer_as_return(&self) -> bool {
1440 self.kind.is_aggregate() && !self.is_scratch_arena_allocated()
1441 }
1442
1443 #[must_use]
1444 pub const fn is_mutable_reference(&self) -> bool {
1445 self.kind.is_mutable_reference()
1446 }
1447}
1448
1449impl BasicType {
1450 #[must_use]
1451 pub const fn unwrap_info(
1452 &self,
1453 ) -> Option<(MemoryOffset, MemorySize, MemoryOffset, MemorySize)> {
1454 match &self.kind {
1455 BasicTypeKind::TaggedUnion(tagged) | BasicTypeKind::Optional(tagged) => Some((
1456 tagged.tag_offset,
1457 tagged.tag_size,
1458 tagged.payload_offset,
1459 tagged.payload_max_size,
1460 )),
1461 _ => None,
1462 }
1463 }
1464
1465 #[must_use]
1466 pub fn union_info(&self) -> &TaggedUnion {
1467 self.kind.union_info()
1468 }
1469
1470 #[must_use]
1471 pub fn create_mutable_pointer(&self) -> Self {
1472 debug_assert!(!self.is_mutable_reference());
1474
1475 Self {
1476 id: BasicTypeId::EMPTY,
1477 kind: BasicTypeKind::U8,
1478 total_size: HEAP_PTR_ON_FRAME_SIZE,
1479 max_alignment: HEAP_PTR_ON_FRAME_ALIGNMENT,
1480 }
1481 }
1482
1483 #[must_use]
1484 pub const fn is_aggregate(&self) -> bool {
1485 self.kind.is_aggregate()
1486 }
1487
1488 #[must_use]
1489 pub const fn optional_info(&self) -> Option<&TaggedUnion> {
1490 match &self.kind {
1491 BasicTypeKind::Optional(tagged_union) => Some(tagged_union),
1492 _ => None,
1493 }
1494 }
1495
1496 #[must_use]
1497 pub fn get_field_offset(&self, index: usize) -> Option<&OffsetMemoryItem> {
1498 match &self.kind {
1499 BasicTypeKind::Struct(struct_type) => struct_type.fields.get(index),
1500 BasicTypeKind::Tuple(tuple_type) => tuple_type.fields.get(index),
1501 _ => {
1502 error!(?self, "not a type with fields");
1503 None
1504 }
1505 }
1506 }
1507
1508 #[must_use]
1509 pub fn bucket_size_for_vec_like(&self) -> Option<MemorySize> {
1510 match &self.kind {
1511 BasicTypeKind::FixedCapacityArray(inner, _capacity) => Some(inner.total_size),
1512 BasicTypeKind::SliceView(inner) => Some(inner.total_size),
1513 BasicTypeKind::VecStorage(inner, _) => Some(inner.total_size),
1514 BasicTypeKind::StringStorage {
1515 element_type: byte, ..
1516 } => Some(byte.total_size),
1517 BasicTypeKind::DynamicLengthVecView(inner) => Some(inner.total_size),
1518 BasicTypeKind::StringView { .. } => Some(MemorySize(1)), _ => None,
1520 }
1521 }
1522
1523 #[must_use]
1524 pub const fn header_size_for_vec_like(&self) -> Option<MemorySize> {
1525 match &self.kind {
1526 BasicTypeKind::SliceView(_)
1527 | BasicTypeKind::DynamicLengthVecView(_)
1528 | BasicTypeKind::VecStorage(_, _)
1529 | BasicTypeKind::StringStorage { .. }
1530 | BasicTypeKind::StringView { .. } => Some(VEC_HEADER_SIZE),
1531 BasicTypeKind::DynamicLengthMapView(..) => Some(MAP_HEADER_SIZE),
1532 _ => None,
1533 }
1534 }
1535
1536 #[must_use]
1537 pub fn element_pair(&self) -> Option<(&OffsetMemoryItem, &OffsetMemoryItem)> {
1538 match &self.kind {
1539 BasicTypeKind::DynamicLengthMapView(a, b) => Some((a, b)),
1540 _ => None,
1541 }
1542 }
1543
1544 #[must_use]
1545 pub fn is_int(&self) -> bool {
1546 matches!(self.kind, BasicTypeKind::S32)
1547 && self.total_size.0 == 4
1548 && self.max_alignment == MemoryAlignment::U32
1549 }
1550
1551 #[must_use]
1552 pub fn is_codepoint(&self) -> bool {
1553 matches!(self.kind, BasicTypeKind::U32)
1554 && self.total_size.0 == 4
1555 && self.max_alignment == MemoryAlignment::U32
1556 }
1557 #[must_use]
1558 pub fn is_float(&self) -> bool {
1559 matches!(self.kind, BasicTypeKind::Fixed32)
1560 && self.total_size.0 == 4
1561 && self.max_alignment == MemoryAlignment::U32
1562 }
1563
1564 #[must_use]
1565 pub fn is_str(&self) -> bool {
1566 (matches!(self.kind, BasicTypeKind::StringView { .. })
1567 && self.total_size == STRING_PTR_SIZE
1568 && self.max_alignment == STRING_PTR_ALIGNMENT)
1569 || matches!(self.kind, BasicTypeKind::StringStorage { .. })
1570 }
1571
1572 #[must_use]
1573 pub fn is_bool(&self) -> bool {
1574 matches!(self.kind, BasicTypeKind::B8)
1575 && self.total_size.0 == 1
1576 && self.max_alignment == MemoryAlignment::U8
1577 }
1578 #[must_use]
1579 pub fn is_byte(&self) -> bool {
1580 matches!(self.kind, BasicTypeKind::U8)
1581 && self.total_size.0 == 1
1582 && self.max_alignment == MemoryAlignment::U8
1583 }
1584}
1585
1586impl Display for BasicType {
1587 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1588 write!(f, "{}", self.kind)
1589 }
1590}
1591
1592#[derive(Clone, Debug)]
1593pub struct VariableInfo {
1594 pub is_mutable: bool,
1595 pub name: String,
1596}
1597
1598impl Display for VariableInfo {
1599 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1600 let mut_prefix = if self.is_mutable { "mut " } else { "" };
1601
1602 let name = &self.name;
1603 write!(f, "{mut_prefix}{name}")
1604 }
1605}
1606
1607#[derive(Clone, Debug)]
1608pub enum VariableInfoKind {
1609 Variable(VariableInfo),
1610 Parameter(VariableInfo),
1611 Return,
1612}
1613
1614impl Display for VariableInfoKind {
1615 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1616 match self {
1617 Self::Variable(var_info) => {
1618 write!(f, "{} {var_info}", "var:".white())
1619 }
1620 Self::Parameter(var_info) => {
1621 write!(f, "{} {var_info}", "param:".white())
1622 }
1623 Self::Return => {
1624 write!(f, "{}", "return".white())
1625 }
1626 }
1627 }
1628}
1629
1630#[derive(Clone, Debug)]
1631pub struct FrameAddressInfo {
1632 pub kind: VariableInfoKind,
1633 pub frame_placed_type: FramePlacedType,
1634}
1635
1636#[derive(Clone, Debug)]
1637pub struct VariableRegister {
1638 pub unique_id_in_function: usize,
1639 pub variable: VariableInfo,
1640 pub register: TypedRegister,
1641}
1642
1643impl Display for VariableRegister {
1644 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1645 write!(f, "{}: {}", self.register, self.variable)
1646 }
1647}
1648
1649#[derive(Clone, Debug)]
1650pub struct VariableRegisterRange {
1651 pub start: u8,
1652 pub count: u8,
1653}
1654
1655#[derive(Clone, Debug)]
1656pub struct FrameMemoryInfo {
1657 pub infos: Vec<FrameAddressInfo>,
1658 pub total_frame_size: FrameMemorySize,
1659 pub variable_frame_size: FrameMemorySize,
1660 pub variable_registers: Vec<VariableRegister>,
1661 pub frame_size_for_variables_except_temp: FrameMemorySize,
1663}
1664
1665#[derive(Clone)]
1666pub struct FrameRelativeInfo {
1667 pub frame_memory_region: FrameMemoryRegion,
1668 pub kind: FrameAddressInfo,
1669}
1670
1671#[derive(Clone, Debug)]
1672pub struct PathInfo {
1673 pub steps: Vec<PathStep>,
1674}
1675
1676impl PathInfo {
1677 #[must_use]
1678 pub fn convert_to_string(&self) -> String {
1679 let path = &self.steps;
1680
1681 let last = path.last().unwrap();
1682
1683 let names: Vec<_> = path.iter().map(|x| x.item.name.to_string()).collect();
1684
1685 let types: Vec<_> = path.iter().map(|x| format!("{}", x.item.ty.kind)).collect();
1686
1687 let names_path = names.join(".");
1688 let types_path = types.join("->");
1689
1690 format!(
1691 "{:04X}:{:X} {} ({})",
1692 (last.origin + last.item.offset).0.bright_cyan(),
1693 last.item.ty.total_size.0.yellow(),
1694 names_path.bright_blue(),
1695 types_path.yellow(),
1696 )
1697 }
1698}
1699
1700#[derive(Clone, Debug)]
1701pub struct PathStep {
1702 pub item: OffsetMemoryItem,
1703 pub origin: FrameMemoryAddress,
1704}
1705
1706impl PathStep {
1707 #[must_use]
1708 pub const fn absolute_address(&self) -> FrameMemoryAddress {
1709 FrameMemoryAddress(self.origin.0 + self.item.offset.0)
1710 }
1711}
1712
1713impl FrameMemoryInfo {
1714 #[must_use]
1715 pub const fn size(&self) -> FrameMemorySize {
1716 self.total_frame_size
1717 }
1718
1719 #[must_use]
1721 pub fn find_path_to_address_items(&self, target: FrameMemoryAddress) -> Option<PathInfo> {
1722 for info in &self.infos {
1723 let root_item = OffsetMemoryItem {
1725 offset: MemoryOffset(0),
1726 size: info.frame_placed_type.ty.total_size,
1727 name: info.kind.to_string(),
1728 ty: info.frame_placed_type.ty.clone(),
1729 };
1730 let base_addr = info.frame_placed_type.addr;
1731 let mut path = Vec::new();
1732 if find_in_item(&root_item, base_addr, target, &mut path) {
1733 return Some(PathInfo { steps: path });
1734 }
1735 }
1736 None
1737 }
1738}
1739fn find_in_item(
1740 item: &OffsetMemoryItem,
1741 base_addr: FrameMemoryAddress,
1742 target: FrameMemoryAddress,
1743 path: &mut Vec<PathStep>,
1744) -> bool {
1745 let item_addr = FrameMemoryAddress(base_addr.0 + item.offset.0);
1746 path.push(PathStep {
1747 item: item.clone(),
1748 origin: base_addr,
1749 });
1750
1751 if item_addr.0 == target.0 {
1752 return true;
1753 }
1754
1755 match &item.ty.kind {
1756 BasicTypeKind::Struct(st) => {
1757 for field in &st.fields {
1758 if find_in_item(field, item_addr, target, path) {
1759 return true;
1760 }
1761 }
1762 }
1763 BasicTypeKind::Tuple(tt) => {
1764 for field in &tt.fields {
1765 if find_in_item(field, item_addr, target, path) {
1766 return true;
1767 }
1768 }
1769 }
1770 BasicTypeKind::TaggedUnion(tu) => {
1771 for variant in &tu.variants {
1772 let variant_item = OffsetMemoryItem {
1774 offset: MemoryOffset(0),
1775 size: variant.ty.total_size,
1776 name: variant.name.clone(),
1777 ty: variant.ty.clone(),
1778 };
1779 if find_in_item(&variant_item, item_addr, target, path) {
1780 return true;
1781 }
1782 }
1783 }
1784 BasicTypeKind::Optional(tu) => {
1785 for variant in &tu.variants {
1786 let variant_item = OffsetMemoryItem {
1787 offset: MemoryOffset(0),
1788 size: variant.ty.total_size,
1789 name: variant.name.clone(),
1790 ty: variant.ty.clone(),
1791 };
1792 if find_in_item(&variant_item, item_addr, target, path) {
1793 return true;
1794 }
1795 }
1796 }
1797 BasicTypeKind::SliceView(inner) => {
1798 let slice_item = OffsetMemoryItem {
1799 offset: MemoryOffset(0),
1800 size: inner.total_size,
1801 name: "slice".to_string(),
1802 ty: inner.clone(),
1803 };
1804 if find_in_item(&slice_item, item_addr, target, path) {
1805 return true;
1806 }
1807 }
1808 BasicTypeKind::DynamicLengthMapView(a, b) => {
1809 if find_in_item(a, item_addr, target, path) {
1810 return true;
1811 }
1812 if find_in_item(b, item_addr, target, path) {
1813 return true;
1814 }
1815 }
1816 _ => {}
1817 }
1818
1819 path.pop();
1820 false
1821}
1822
1823#[derive(Clone, Debug)]
1824pub enum FunctionInfoKind {
1825 Constant(usize),
1826 Normal(usize),
1827}
1828
1829#[derive(Clone, Debug)]
1830pub struct FunctionInfo {
1831 pub kind: FunctionInfoKind,
1832 pub frame_memory: FrameMemoryInfo,
1833 pub params: Vec<BasicTypeRef>,
1834 pub return_type: VmType,
1835 pub name: String,
1836 pub ip_range: InstructionRange,
1837}
1838
1839#[derive(Clone, Debug)]
1840pub struct CompleteFunctionInfo {
1841 pub ip: InstructionPosition,
1842 pub size: InstructionPositionOffset,
1843 pub info: FunctionInfo,
1844}
1845
1846pub fn new_line_and_tab(f: &mut dyn Write, tabs: usize) -> std::fmt::Result {
1847 let tab_str = " ".repeat(tabs);
1848 writeln!(f)?;
1849 write!(f, "{tab_str}")
1850}
1851
1852pub fn show_memory_offset(
1853 offset: MemoryOffset,
1854 origin: FrameMemoryAddress,
1855 f: &mut dyn Write,
1856 _tabs: usize,
1857) -> std::fmt::Result {
1858 let result = origin + offset;
1859 write!(f, "{}+{:04X}", result, offset.0.yellow())
1860}
1861fn show_memory_size(size: MemorySize, f: &mut dyn Write, _tabs: usize) -> std::fmt::Result {
1862 write!(f, "{} ({})", size.green(), size.0)
1863}
1864
1865pub fn show_offset_item(
1866 offset_item: &OffsetMemoryItem,
1867 origin: FrameMemoryAddress,
1868 f: &mut dyn Write,
1869 tabs: usize,
1870) -> std::fmt::Result {
1871 show_memory_offset(offset_item.offset, origin, f, tabs)?;
1872 write!(f, ":")?;
1873 show_memory_size(offset_item.size, f, tabs)?;
1874 write!(f, " ")?;
1875 write_identifier_and_colon(&offset_item.name, f)?;
1876 let adjusted_origin = origin + offset_item.offset;
1877 write_basic_type(&offset_item.ty, adjusted_origin, f, tabs + 1)
1878}
1879
1880pub fn show_tagged_union(
1881 tagged_union: &TaggedUnion,
1882 origin: FrameMemoryAddress,
1883 f: &mut dyn Write,
1884 tabs: usize,
1885) -> std::fmt::Result {
1886 write!(f, "union tag_size:")?;
1887 show_memory_size(tagged_union.tag_size, f, tabs)?;
1888 write!(f, " max payload:")?;
1889 show_memory_size(tagged_union.payload_max_size, f, tabs)?;
1890
1891 let adjusted_payload_origin = origin + tagged_union.payload_offset;
1892
1893 for (index, union_data) in tagged_union
1894 .variants
1895 .clone()
1896 .into_iter()
1897 .take(4)
1898 .enumerate()
1899 {
1900 new_line_and_tab(f, tabs + 1)?;
1902 write!(f, "{}> ", index.bright_magenta())?;
1903 write_identifier_and_colon(&union_data.name, f)?;
1904 write_basic_type(&union_data.ty, adjusted_payload_origin, f, tabs + 1)?;
1905 }
1906 Ok(())
1907}
1908
1909pub fn show_struct_type(
1910 s: &StructType,
1911 origin: FrameMemoryAddress,
1912 f: &mut dyn Write,
1913 tabs: usize,
1914) -> std::fmt::Result {
1915 write!(f, "{} {{", s.name)?;
1916 for offset_item in &s.fields {
1917 new_line_and_tab(f, tabs + 1)?;
1918 show_offset_item(offset_item, origin, f, tabs + 1)?;
1919 }
1920 write!(f, " }}")
1921}
1922
1923pub fn show_tuple_type(
1924 s: &TupleType,
1925 origin: FrameMemoryAddress,
1926 f: &mut dyn Write,
1927 tabs: usize,
1928) -> std::fmt::Result {
1929 write!(f, "(")?;
1930 for offset_item in &s.fields {
1931 new_line_and_tab(f, tabs + 1)?;
1932 show_offset_item(offset_item, origin, f, tabs + 1)?;
1933 }
1934 write!(f, " )")
1935}
1936
1937pub fn write_identifier_and_colon(identifier: &str, f: &mut dyn Write) -> std::fmt::Result {
1938 write!(f, "{}: ", identifier.blue())
1939}
1940
1941pub fn write_basic_type(
1942 ty: &BasicType,
1943 origin: FrameMemoryAddress,
1944 f: &mut dyn Write,
1945 tabs: usize,
1946) -> std::fmt::Result {
1947 match &ty.kind {
1948 BasicTypeKind::Any => write!(f, "Any"),
1949 BasicTypeKind::Pointer => write!(f, "Ptr"),
1950 BasicTypeKind::Empty => write!(f, "()"),
1951 BasicTypeKind::U8 => write!(f, "{}", "u8".white()),
1952 BasicTypeKind::B8 => write!(f, "{}", "b8".white()),
1953 BasicTypeKind::U16 => write!(f, "{}", "u16".white()),
1954 BasicTypeKind::S32 => write!(f, "{}", "s32".white()),
1955 BasicTypeKind::Fixed32 => write!(f, "{}", "f32".white()),
1956 BasicTypeKind::U32 => write!(f, "{}", "u32".white()),
1957 BasicTypeKind::Struct(s) => show_struct_type(s, origin, f, tabs),
1958 BasicTypeKind::TaggedUnion(tagged_union) => {
1959 show_tagged_union(tagged_union, origin, f, tabs)
1960 }
1961 BasicTypeKind::Optional(tagged_union) => {
1962 write!(f, "Option<{}> ", tagged_union.variants[1].ty)?;
1963 show_tagged_union(tagged_union, origin, f, tabs)
1964 }
1965 BasicTypeKind::Tuple(tuple_type) => show_tuple_type(tuple_type, origin, f, tabs),
1966
1967 BasicTypeKind::SliceView(slice_inner_type) => {
1968 write!(f, "[|")?;
1969 write_basic_type(slice_inner_type, origin, f, tabs + 1)?;
1970 write!(f, "|]")
1971 }
1972 BasicTypeKind::DynamicLengthMapView(key_type, value_type) => {
1973 write!(f, "[|")?;
1974 show_offset_item(key_type, origin, f, tabs + 1)?;
1975 write!(f, ", ")?;
1976 show_offset_item(value_type, origin, f, tabs + 1)?;
1977 write!(f, "|]")
1978 }
1979 BasicTypeKind::StringView { .. } => {
1980 write!(f, "str")
1981 }
1982 BasicTypeKind::InternalRangeHeader => {
1983 write!(f, "range")
1984 }
1985
1986 BasicTypeKind::FixedCapacityArray(element_type, size) => {
1987 write!(f, "[{element_type}, {size}]")
1988 }
1989 BasicTypeKind::DynamicLengthVecView(element_type) => {
1990 write!(f, "Vec<{element_type}>")
1991 }
1992 BasicTypeKind::VecStorage(element_type, size) => {
1993 write!(f, "VecStorage<{element_type}, {size}>")
1994 }
1995 BasicTypeKind::StringStorage {
1996 element_type: byte,
1997 capacity,
1998 ..
1999 } => {
2000 write!(f, "StringStorage<{byte}, {capacity}>")
2001 }
2002 BasicTypeKind::QueueStorage(element_type, size) => {
2003 write!(f, "QueueStorage<{element_type}, {size}>")
2004 }
2005 BasicTypeKind::GridStorage(element_type, width, height) => {
2006 write!(f, "GridStorage<{element_type}, ({width},{height})>")
2007 }
2008 BasicTypeKind::StackStorage(element_type, size) => {
2009 write!(f, "StackStorage<{element_type}, {size}>")
2010 }
2011 BasicTypeKind::SparseView(element_type) => {
2012 write!(f, "Sparse<{element_type}>")
2013 }
2014 BasicTypeKind::GridView(element_type) => {
2015 write!(f, "grid<{element_type}>")
2016 }
2017 BasicTypeKind::SparseStorage(element_type, size) => {
2018 write!(f, "SparseStorage<{element_type}, {size}>")
2019 }
2020 BasicTypeKind::MapStorage {
2021 logical_limit: logical_size,
2022 key_type,
2023 value_type,
2024 ..
2025 } => {
2026 write!(f, "MapStorage<{key_type}, {value_type}, {logical_size}>",)
2027 }
2028 BasicTypeKind::InternalVecIterator => {
2029 write!(f, "vec_iter")
2030 }
2031 BasicTypeKind::InternalStringIterator => {
2032 write!(f, "str_iter")
2033 }
2034 BasicTypeKind::InternalRangeIterator => {
2035 write!(f, "range_iter")
2036 }
2037 BasicTypeKind::InternalMapIterator => {
2038 write!(f, "map_iter")
2039 }
2040 BasicTypeKind::InternalSparseIterator => {
2041 write!(f, "sparse_iter")
2042 }
2043 }
2044}
2045
2046pub fn show_frame_addr(
2047 addr: FrameMemoryAddress,
2048 f: &mut dyn Write,
2049 _tabs: usize,
2050) -> std::fmt::Result {
2051 write!(f, "{:04X}", addr.0.blue())
2052}
2053
2054pub fn show_frame_region(
2055 region: FrameMemoryRegion,
2056 f: &mut dyn Write,
2057 tabs: usize,
2058 use_color: bool,
2059) -> std::fmt::Result {
2060 if use_color {
2061 yansi::enable();
2062 } else {
2063 yansi::disable();
2064 }
2065 show_frame_addr(region.addr, f, tabs)?;
2066 write!(f, ":")?;
2067 show_memory_size(region.size, f, tabs)
2068}
2069
2070pub fn show_frame_memory(
2071 frame_relative_infos: &FrameMemoryInfo,
2072 f: &mut dyn Write,
2073 use_color: bool,
2074) -> std::fmt::Result {
2075 for mem in &frame_relative_infos.infos {
2076 let addr = mem.frame_placed_type.addr;
2077 show_frame_region(mem.frame_placed_type.region(), f, 0, use_color)?;
2078 write!(f, " ")?;
2079 match &mem.kind {
2080 VariableInfoKind::Variable(v) => {
2081 write!(f, "var ")?;
2082 write_identifier_and_colon(&v.name, f)?;
2083 }
2084 VariableInfoKind::Parameter(v) => {
2085 write!(f, "param ")?;
2086 write_identifier_and_colon(&v.name, f)?;
2087 }
2088 VariableInfoKind::Return => {
2089 write!(f, "return:")?;
2090 }
2091 }
2092 write!(f, " ")?;
2093 write_basic_type(&mem.frame_placed_type.ty, addr, f, 0)?;
2094 writeln!(f)?;
2095 }
2096
2097 writeln!(
2098 f,
2099 "frame size for variables: {:0}",
2100 frame_relative_infos.frame_size_for_variables_except_temp
2101 )?;
2102 Ok(())
2103}
2104
2105impl Hash for BasicType {
2106 fn hash<H: Hasher>(&self, state: &mut H) {
2107 self.kind.hash(state);
2110 self.total_size.0.hash(state);
2111 self.max_alignment.hash(state);
2112 }
2113}
2114
2115impl Hash for BasicTypeKind {
2116 fn hash<H: Hasher>(&self, state: &mut H) {
2117 std::mem::discriminant(self).hash(state);
2118
2119 match self {
2120 Self::Any => {}
2121 Self::Pointer => {}
2122 Self::Empty => {}
2123 Self::U8 => {}
2124 Self::B8 => {}
2125 Self::U16 => {}
2126 Self::S32 => {}
2127 Self::Fixed32 => {}
2128 Self::U32 => {}
2129 Self::InternalRangeHeader => {}
2130 Self::InternalVecIterator => {}
2131 Self::InternalStringIterator => {}
2132 Self::InternalMapIterator => {}
2133 Self::InternalSparseIterator => {}
2134 Self::InternalRangeIterator => {}
2135
2136 Self::StringView { byte, char } => {
2137 byte.universal_hash(state);
2138 char.universal_hash(state);
2139 }
2140
2141 Self::Struct(struct_type) => {
2142 struct_type.hash(state);
2143 }
2144
2145 Self::TaggedUnion(union) => {
2146 union.hash(state);
2147 }
2148
2149 Self::Tuple(tuple_type) => {
2150 tuple_type.hash(state);
2151 }
2152
2153 Self::Optional(optional) => {
2154 optional.hash(state);
2155 }
2156
2157 Self::SliceView(inner) => {
2158 inner.universal_hash(state);
2159 }
2160
2161 Self::FixedCapacityArray(inner, size) => {
2162 inner.universal_hash(state);
2163 size.hash(state);
2164 }
2165
2166 Self::DynamicLengthVecView(inner) => {
2167 inner.universal_hash(state);
2168 }
2169
2170 Self::VecStorage(inner, size) => {
2171 inner.universal_hash(state);
2172 size.hash(state);
2173 }
2174
2175 Self::StringStorage {
2176 element_type,
2177 char,
2178 capacity,
2179 } => {
2180 element_type.universal_hash(state);
2181 char.universal_hash(state);
2182 capacity.hash(state);
2183 }
2184
2185 Self::StackStorage(inner, size) => {
2186 inner.universal_hash(state);
2187 size.hash(state);
2188 }
2189
2190 Self::QueueStorage(inner, size) => {
2191 inner.universal_hash(state);
2192 size.hash(state);
2193 }
2194
2195 Self::MapStorage {
2196 key_type,
2197 value_type,
2198 logical_limit,
2199 capacity,
2200 } => {
2201 key_type.universal_hash(state);
2202 value_type.universal_hash(state);
2203 logical_limit.hash(state);
2204 capacity.0.hash(state);
2205 }
2206
2207 Self::SparseView(inner) => {
2208 inner.universal_hash(state);
2209 }
2210
2211 Self::SparseStorage(inner, size) => {
2212 inner.universal_hash(state);
2213 size.hash(state);
2214 }
2215
2216 Self::DynamicLengthMapView(key, value) => {
2217 key.hash(state);
2218 value.hash(state);
2219 }
2220
2221 Self::GridView(inner) => {
2222 inner.universal_hash(state);
2223 }
2224
2225 Self::GridStorage(inner, width, height) => {
2226 inner.universal_hash(state);
2227 width.hash(state);
2228 height.hash(state);
2229 }
2230 }
2231 }
2232}
2233
2234impl Hash for StructType {
2235 fn hash<H: Hasher>(&self, state: &mut H) {
2236 self.name.hash(state);
2237 for field in &self.fields {
2239 field.hash(state);
2240 }
2241 self.total_size.0.hash(state);
2242 self.max_alignment.hash(state);
2243 }
2244}
2245
2246impl Hash for TupleType {
2247 fn hash<H: Hasher>(&self, state: &mut H) {
2248 for field in &self.fields {
2250 field.hash(state);
2251 }
2252 self.total_size.0.hash(state);
2253 self.max_alignment.hash(state);
2254 }
2255}
2256
2257impl Hash for TaggedUnion {
2258 fn hash<H: Hasher>(&self, state: &mut H) {
2259 self.name.hash(state);
2260 self.tag_offset.0.hash(state);
2261 self.tag_alignment.hash(state);
2262 self.tag_size.0.hash(state);
2263 self.payload_max_size.0.hash(state);
2264 self.max_payload_alignment.hash(state);
2265 self.payload_offset.0.hash(state);
2266
2267 for variant in &self.variants {
2269 variant.hash(state);
2270 }
2271
2272 self.total_size.0.hash(state);
2273 self.max_alignment.hash(state);
2274 }
2275}
2276
2277impl Hash for TaggedUnionVariant {
2278 fn hash<H: Hasher>(&self, state: &mut H) {
2279 self.name.hash(state);
2280 self.ty.universal_hash(state);
2281 }
2282}
2283
2284impl Hash for OffsetMemoryItem {
2285 fn hash<H: Hasher>(&self, state: &mut H) {
2286 self.offset.0.hash(state);
2287 self.size.0.hash(state);
2288 self.name.hash(state);
2289 self.ty.universal_hash(state);
2290 }
2291}
2292
2293impl BasicType {
2295 pub fn universal_hash<H: Hasher>(&self, state: &mut H) {
2301 self.hash(state);
2302 }
2303
2304 #[must_use]
2306 pub fn universal_hash_u64(&self) -> u64 {
2307 let mut hasher = FxHasher::default();
2308 self.universal_hash(&mut hasher);
2309 hasher.finish()
2310 }
2311}