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