Skip to main content

memscope_rs/variable_registry/
inference.rs

1//! Size-based type inference for system allocations.
2//!
3//! Split out of `variable_registry.rs` to keep that file within the project line
4//! budget. The results are heuristics: they are labelled as inferred data and must
5//! never be presented as observed types.
6
7use super::*;
8
9impl VariableRegistry {
10    /// Smart inference with caching for better performance
11    pub fn infer_allocation_info_cached(
12        alloc: &crate::capture::types::allocation::AllocationInfo,
13    ) -> (String, String) {
14        // Use a simple cache for common sizes to avoid repeated string formatting
15        static COMMON_TYPES: &[(usize, &str, &str)] = &[
16            (1, "box_u8", "Box<u8>"),
17            (2, "box_u16", "Box<u16>"),
18            (4, "box_u32", "Box<u32>"),
19            (8, "box_u64", "Box<u64>"),
20            (16, "small_alloc_16b", "SmallAlloc"),
21            (24, "string_alloc", "String"),
22            (32, "string_alloc", "String"),
23        ];
24
25        // Fast lookup for common sizes
26        for &(size, var_prefix, type_name) in COMMON_TYPES {
27            if alloc.size == size {
28                return (
29                    format!("{var_prefix}_{:x}", alloc.ptr),
30                    type_name.to_string(),
31                );
32            }
33        }
34
35        // Fallback to original logic for uncommon sizes
36        Self::infer_allocation_info(alloc)
37    }
38
39    /// Smart inference for system allocations based on size patterns and common allocations
40    pub fn infer_allocation_info(
41        alloc: &crate::capture::types::allocation::AllocationInfo,
42    ) -> (String, String) {
43        let size = alloc.size;
44
45        // Common allocation size patterns for type inference
46        let (var_name, type_name) = match size {
47            // String allocations (common sizes)
48            8..=32 if size.is_power_of_two() => (
49                format!("string_alloc_{:x}", alloc.ptr),
50                "String".to_string(),
51            ),
52            // Vec allocations (multiples of common element sizes)
53            s if s % 8 == 0 && s >= 16 => {
54                let elements = s / 8;
55                (
56                    format!("vec_i64_{elements}elem_{:x}", alloc.ptr),
57                    "Vec<i64>".to_string(),
58                )
59            }
60            s if s % 4 == 0 && s >= 8 => {
61                let elements = s / 4;
62                (
63                    format!("vec_i32_{elements}elem_{:x}", alloc.ptr),
64                    "Vec<i32>".to_string(),
65                )
66            }
67            // Box allocations (single element sizes)
68            1 => (format!("box_u8_{:x}", alloc.ptr), "Box<u8>".to_string()),
69            2 => (format!("box_u16_{:x}", alloc.ptr), "Box<u16>".to_string()),
70            4 => (format!("box_u32_{:x}", alloc.ptr), "Box<u32>".to_string()),
71            8 => (format!("box_u64_{:x}", alloc.ptr), "Box<u64>".to_string()),
72            // HashMap/BTreeMap allocations (typically larger, irregular sizes)
73            s if s >= 64 && s % 16 == 0 => (
74                format!("hashmap_alloc_{:x}", alloc.ptr),
75                "HashMap<K,V>".to_string(),
76            ),
77            // Large allocations (likely buffers or large collections)
78            s if s >= 1024 => {
79                let kb = s / 1024;
80                (
81                    format!("large_buffer_{}kb_{:x}", kb, alloc.ptr),
82                    "LargeBuffer".to_string(),
83                )
84            }
85            // Small system allocations
86            s if s <= 16 => (
87                format!("small_alloc_{s}b_{:x}", alloc.ptr),
88                "SmallAlloc".to_string(),
89            ),
90            // Default case with size hint
91            _ => (
92                format!("system_alloc_{size}b_{:x}", alloc.ptr),
93                "SystemAlloc".to_string(),
94            ),
95        };
96
97        (var_name, type_name)
98    }
99}