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 seq_fmt::comma;
16use std::cmp::{max, Ordering};
17use std::fmt::{Debug, Display, Formatter, Write};
18use std::hash::{Hash, Hasher};
19use std::rc::Rc;
20use tracing::error;
21use yansi::Paint;
22
23pub type BasicTypeRef = Rc<BasicType>;
24
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 return_type: VmType,
1785 pub name: String,
1786 pub ip_range: InstructionRange,
1787}
1788
1789#[derive(Clone, Debug)]
1790pub struct CompleteFunctionInfo {
1791 pub ip: InstructionPosition,
1792 pub size: InstructionPositionOffset,
1793 pub info: FunctionInfo,
1794}
1795
1796pub fn new_line_and_tab(f: &mut dyn Write, tabs: usize) -> std::fmt::Result {
1797 let tab_str = " ".repeat(tabs);
1798 writeln!(f)?;
1799 write!(f, "{tab_str}")
1800}
1801
1802pub fn show_memory_offset(
1803 offset: MemoryOffset,
1804 origin: FrameMemoryAddress,
1805 f: &mut dyn Write,
1806 _tabs: usize,
1807) -> std::fmt::Result {
1808 let result = origin + offset;
1809 write!(f, "{}+{:04X}", result, offset.0.yellow())
1810}
1811fn show_memory_size(size: MemorySize, f: &mut dyn Write, _tabs: usize) -> std::fmt::Result {
1812 write!(f, "{} ({})", size.green(), size.0)
1813}
1814
1815pub fn show_offset_item(
1816 offset_item: &OffsetMemoryItem,
1817 origin: FrameMemoryAddress,
1818 f: &mut dyn Write,
1819 tabs: usize,
1820) -> std::fmt::Result {
1821 show_memory_offset(offset_item.offset, origin, f, tabs)?;
1822 write!(f, ":")?;
1823 show_memory_size(offset_item.size, f, tabs)?;
1824 write!(f, " ")?;
1825 write_identifier_and_colon(&offset_item.name, f)?;
1826 let adjusted_origin = origin + offset_item.offset;
1827 write_basic_type(&offset_item.ty, adjusted_origin, f, tabs + 1)
1828}
1829
1830pub fn show_tagged_union(
1831 tagged_union: &TaggedUnion,
1832 origin: FrameMemoryAddress,
1833 f: &mut dyn Write,
1834 tabs: usize,
1835) -> std::fmt::Result {
1836 write!(f, "union tag_size:")?;
1837 show_memory_size(tagged_union.tag_size, f, tabs)?;
1838 write!(f, " max payload:")?;
1839 show_memory_size(tagged_union.payload_max_size, f, tabs)?;
1840
1841 let adjusted_payload_origin = origin + tagged_union.payload_offset;
1842
1843 for (index, union_data) in tagged_union
1844 .variants
1845 .clone()
1846 .into_iter()
1847 .take(4)
1848 .enumerate()
1849 {
1850 new_line_and_tab(f, tabs + 1)?;
1852 write!(f, "{}> ", index.bright_magenta())?;
1853 write_identifier_and_colon(&union_data.name, f)?;
1854 write_basic_type(&union_data.ty, adjusted_payload_origin, f, tabs + 1)?;
1855 }
1856 Ok(())
1857}
1858
1859pub fn show_struct_type(
1860 s: &StructType,
1861 origin: FrameMemoryAddress,
1862 f: &mut dyn Write,
1863 tabs: usize,
1864) -> std::fmt::Result {
1865 write!(f, "{} {{", s.name)?;
1866 for offset_item in &s.fields {
1867 new_line_and_tab(f, tabs + 1)?;
1868 show_offset_item(offset_item, origin, f, tabs + 1)?;
1869 }
1870 write!(f, " }}")
1871}
1872
1873pub fn show_tuple_type(
1874 s: &TupleType,
1875 origin: FrameMemoryAddress,
1876 f: &mut dyn Write,
1877 tabs: usize,
1878) -> std::fmt::Result {
1879 write!(f, "(")?;
1880 for offset_item in &s.fields {
1881 new_line_and_tab(f, tabs + 1)?;
1882 show_offset_item(offset_item, origin, f, tabs + 1)?;
1883 }
1884 write!(f, " )")
1885}
1886
1887pub fn write_identifier_and_colon(identifier: &str, f: &mut dyn Write) -> std::fmt::Result {
1888 write!(f, "{}: ", identifier.blue())
1889}
1890
1891pub fn write_basic_type(
1892 ty: &BasicType,
1893 origin: FrameMemoryAddress,
1894 f: &mut dyn Write,
1895 tabs: usize,
1896) -> std::fmt::Result {
1897 match &ty.kind {
1898 BasicTypeKind::Any => write!(f, "Any"),
1899 BasicTypeKind::Empty => write!(f, "()"),
1900 BasicTypeKind::U8 => write!(f, "{}", "u8".white()),
1901 BasicTypeKind::B8 => write!(f, "{}", "b8".white()),
1902 BasicTypeKind::U16 => write!(f, "{}", "u16".white()),
1903 BasicTypeKind::S32 => write!(f, "{}", "s32".white()),
1904 BasicTypeKind::Fixed32 => write!(f, "{}", "f32".white()),
1905 BasicTypeKind::U32 => write!(f, "{}", "u32".white()),
1906 BasicTypeKind::Struct(s) => show_struct_type(s, origin, f, tabs),
1907 BasicTypeKind::TaggedUnion(tagged_union) => {
1908 show_tagged_union(tagged_union, origin, f, tabs)
1909 }
1910 BasicTypeKind::Optional(tagged_union) => {
1911 write!(f, "Option<{}> ", tagged_union.variants[1].ty)?;
1912 show_tagged_union(tagged_union, origin, f, tabs)
1913 }
1914 BasicTypeKind::Tuple(tuple_type) => show_tuple_type(tuple_type, origin, f, tabs),
1915
1916 BasicTypeKind::SliceView(slice_inner_type) => {
1917 write!(f, "[|")?;
1918 write_basic_type(slice_inner_type, origin, f, tabs + 1)?;
1919 write!(f, "|]")
1920 }
1921 BasicTypeKind::DynamicLengthMapView(key_type, value_type) => {
1922 write!(f, "[|")?;
1923 show_offset_item(key_type, origin, f, tabs + 1)?;
1924 write!(f, ", ")?;
1925 show_offset_item(value_type, origin, f, tabs + 1)?;
1926 write!(f, "|]")
1927 }
1928 BasicTypeKind::StringView { .. } => {
1929 write!(f, "str")
1930 }
1931 BasicTypeKind::InternalRangeHeader => {
1932 write!(f, "range")
1933 }
1934
1935 BasicTypeKind::FixedCapacityArray(element_type, size) => {
1936 write!(f, "[{element_type}, {size}]")
1937 }
1938 BasicTypeKind::DynamicLengthVecView(element_type) => {
1939 write!(f, "Vec<{element_type}>")
1940 }
1941 BasicTypeKind::VecStorage(element_type, size) => {
1942 write!(f, "VecStorage<{element_type}, {size}>")
1943 }
1944 BasicTypeKind::StringStorage {
1945 element_type: byte,
1946 capacity,
1947 ..
1948 } => {
1949 write!(f, "StringStorage<{byte}, {capacity}>")
1950 }
1951 BasicTypeKind::QueueStorage(element_type, size) => {
1952 write!(f, "QueueStorage<{element_type}, {size}>")
1953 }
1954 BasicTypeKind::GridStorage(element_type, width, height) => {
1955 write!(f, "GridStorage<{element_type}, ({width},{height})>")
1956 }
1957 BasicTypeKind::StackStorage(element_type, size) => {
1958 write!(f, "StackStorage<{element_type}, {size}>")
1959 }
1960 BasicTypeKind::SparseView(element_type) => {
1961 write!(f, "Sparse<{element_type}>")
1962 }
1963 BasicTypeKind::GridView(element_type) => {
1964 write!(f, "grid<{element_type}>")
1965 }
1966 BasicTypeKind::SparseStorage(element_type, size) => {
1967 write!(f, "SparseStorage<{element_type}, {size}>")
1968 }
1969 BasicTypeKind::MapStorage {
1970 logical_limit: logical_size,
1971 key_type,
1972 value_type,
1973 ..
1974 } => {
1975 write!(f, "MapStorage<{key_type}, {value_type}, {logical_size}>", )
1976 }
1977 BasicTypeKind::InternalVecIterator => {
1978 write!(f, "vec_iter")
1979 }
1980 BasicTypeKind::InternalStringIterator => {
1981 write!(f, "str_iter")
1982 }
1983 BasicTypeKind::InternalRangeIterator => {
1984 write!(f, "range_iter")
1985 }
1986 BasicTypeKind::InternalMapIterator => {
1987 write!(f, "map_iter")
1988 }
1989 BasicTypeKind::InternalSparseIterator => {
1990 write!(f, "sparse_iter")
1991 }
1992 }
1993}
1994
1995pub fn show_frame_addr(
1996 addr: FrameMemoryAddress,
1997 f: &mut dyn Write,
1998 _tabs: usize,
1999) -> std::fmt::Result {
2000 write!(f, "{:04X}", addr.0.blue())
2001}
2002
2003pub fn show_frame_region(
2004 region: FrameMemoryRegion,
2005 f: &mut dyn Write,
2006 tabs: usize,
2007) -> std::fmt::Result {
2008 show_frame_addr(region.addr, f, tabs)?;
2009 write!(f, ":")?;
2010 show_memory_size(region.size, f, tabs)
2011}
2012
2013pub fn show_frame_memory(
2014 frame_relative_infos: &FrameMemoryInfo,
2015 f: &mut dyn Write,
2016) -> std::fmt::Result {
2017 for mem in &frame_relative_infos.infos {
2018 let addr = mem.frame_placed_type.addr;
2019 show_frame_region(mem.frame_placed_type.region(), f, 0)?;
2020 write!(f, " ")?;
2021 match &mem.kind {
2022 VariableInfoKind::Variable(v) => {
2023 write!(f, "var ")?;
2024 write_identifier_and_colon(&v.name, f)?;
2025 }
2026 VariableInfoKind::Parameter(v) => {
2027 write!(f, "param ")?;
2028 write_identifier_and_colon(&v.name, f)?;
2029 }
2030 VariableInfoKind::Return => {
2031 write!(f, "return:")?;
2032 }
2033 }
2034 write!(f, " ")?;
2035 write_basic_type(&mem.frame_placed_type.ty, addr, f, 0)?;
2036 writeln!(f)?;
2037 }
2038
2039 writeln!(
2040 f,
2041 "frame size for variables: {:0}",
2042 frame_relative_infos.frame_size_for_variables_except_temp
2043 )?;
2044 Ok(())
2045}
2046
2047impl Hash for BasicType {
2048 fn hash<H: Hasher>(&self, state: &mut H) {
2049 self.kind.hash(state);
2052 self.total_size.0.hash(state);
2053 self.max_alignment.hash(state);
2054 }
2055}
2056
2057impl Hash for BasicTypeKind {
2058 fn hash<H: Hasher>(&self, state: &mut H) {
2059 std::mem::discriminant(self).hash(state);
2060
2061 match self {
2062 Self::Any => panic!("not allowed to perform hash on any"),
2063 Self::Empty => {}
2064 Self::U8 => {}
2065 Self::B8 => {}
2066 Self::U16 => {}
2067 Self::S32 => {}
2068 Self::Fixed32 => {}
2069 Self::U32 => {}
2070 Self::InternalRangeHeader => {}
2071 Self::InternalVecIterator => {}
2072 Self::InternalStringIterator => {}
2073 Self::InternalMapIterator => {}
2074 Self::InternalSparseIterator => {}
2075 Self::InternalRangeIterator => {}
2076
2077 Self::StringView { byte, char } => {
2078 byte.universal_hash(state);
2079 char.universal_hash(state);
2080 }
2081
2082 Self::Struct(struct_type) => {
2083 struct_type.hash(state);
2084 }
2085
2086 Self::TaggedUnion(union) => {
2087 union.hash(state);
2088 }
2089
2090 Self::Tuple(tuple_type) => {
2091 tuple_type.hash(state);
2092 }
2093
2094 Self::Optional(optional) => {
2095 optional.hash(state);
2096 }
2097
2098 Self::SliceView(inner) => {
2099 inner.universal_hash(state);
2100 }
2101
2102 Self::FixedCapacityArray(inner, size) => {
2103 inner.universal_hash(state);
2104 size.hash(state);
2105 }
2106
2107 Self::DynamicLengthVecView(inner) => {
2108 inner.universal_hash(state);
2109 }
2110
2111 Self::VecStorage(inner, size) => {
2112 inner.universal_hash(state);
2113 size.hash(state);
2114 }
2115
2116 Self::StringStorage { element_type, char, capacity } => {
2117 element_type.universal_hash(state);
2118 char.universal_hash(state);
2119 capacity.hash(state);
2120 }
2121
2122 Self::StackStorage(inner, size) => {
2123 inner.universal_hash(state);
2124 size.hash(state);
2125 }
2126
2127 Self::QueueStorage(inner, size) => {
2128 inner.universal_hash(state);
2129 size.hash(state);
2130 }
2131
2132 Self::MapStorage { key_type, value_type, logical_limit, capacity } => {
2133 key_type.universal_hash(state);
2134 value_type.universal_hash(state);
2135 logical_limit.hash(state);
2136 capacity.0.hash(state);
2137 }
2138
2139 Self::SparseView(inner) => {
2140 inner.universal_hash(state);
2141 }
2142
2143 Self::SparseStorage(inner, size) => {
2144 inner.universal_hash(state);
2145 size.hash(state);
2146 }
2147
2148 Self::DynamicLengthMapView(key, value) => {
2149 key.hash(state);
2150 value.hash(state);
2151 }
2152
2153 Self::GridView(inner) => {
2154 inner.universal_hash(state);
2155 }
2156
2157 Self::GridStorage(inner, width, height) => {
2158 inner.universal_hash(state);
2159 width.hash(state);
2160 height.hash(state);
2161 }
2162 }
2163 }
2164}
2165
2166impl Hash for StructType {
2167 fn hash<H: Hasher>(&self, state: &mut H) {
2168 self.name.hash(state);
2169 for field in &self.fields {
2171 field.hash(state);
2172 }
2173 self.total_size.0.hash(state);
2174 self.max_alignment.hash(state);
2175 }
2176}
2177
2178impl Hash for TupleType {
2179 fn hash<H: Hasher>(&self, state: &mut H) {
2180 for field in &self.fields {
2182 field.hash(state);
2183 }
2184 self.total_size.0.hash(state);
2185 self.max_alignment.hash(state);
2186 }
2187}
2188
2189impl Hash for TaggedUnion {
2190 fn hash<H: Hasher>(&self, state: &mut H) {
2191 self.name.hash(state);
2192 self.tag_offset.0.hash(state);
2193 self.tag_alignment.hash(state);
2194 self.tag_size.0.hash(state);
2195 self.payload_max_size.0.hash(state);
2196 self.max_payload_alignment.hash(state);
2197 self.payload_offset.0.hash(state);
2198
2199 for variant in &self.variants {
2201 variant.hash(state);
2202 }
2203
2204 self.total_size.0.hash(state);
2205 self.max_alignment.hash(state);
2206 }
2207}
2208
2209impl Hash for TaggedUnionVariant {
2210 fn hash<H: Hasher>(&self, state: &mut H) {
2211 self.name.hash(state);
2212 self.ty.universal_hash(state);
2213 }
2214}
2215
2216impl Hash for OffsetMemoryItem {
2217 fn hash<H: Hasher>(&self, state: &mut H) {
2218 self.offset.0.hash(state);
2219 self.size.0.hash(state);
2220 self.name.hash(state);
2221 self.ty.universal_hash(state);
2222 }
2223}
2224
2225impl BasicType {
2227 pub fn universal_hash<H: Hasher>(&self, state: &mut H) {
2233 self.hash(state);
2234 }
2235
2236 #[must_use] pub fn universal_hash_u64(&self) -> u64 {
2238 let mut hasher = std::collections::hash_map::DefaultHasher::new();
2239 self.universal_hash(&mut hasher);
2240 hasher.finish()
2241 }
2242}