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