Skip to main content

runmat_snapshot/
builder.rs

1//! Snapshot builder for creating optimized snapshots of the standard library
2//!
3//! High-performance builder that preloads, analyzes, and optimizes all standard
4//! library components into a single snapshot file.
5
6use runmat_time::Instant;
7use std::collections::{hash_map::Entry, HashMap};
8use std::path::Path;
9use std::sync::Arc;
10use std::time::Duration;
11
12use anyhow::{Context, Result};
13use indicatif::{ProgressBar, ProgressStyle};
14use parking_lot::RwLock;
15
16use crate::compression::{CompressionConfig, CompressionEngine};
17use crate::format::*;
18use crate::validation::SnapshotValidator;
19use crate::*;
20use runmat_hir::LoweringContext;
21
22/// Snapshot builder with progressive enhancement
23pub struct SnapshotBuilder {
24    /// Configuration
25    config: SnapshotConfig,
26
27    /// Compression engine
28    compression: CompressionEngine,
29
30    /// Validation engine
31    #[cfg(feature = "validation")]
32    validator: SnapshotValidator,
33
34    /// Build statistics
35    stats: Arc<RwLock<BuildStats>>,
36
37    /// Progress reporting
38    progress: Option<ProgressBar>,
39}
40
41/// Build statistics
42#[derive(Debug, Default)]
43pub struct BuildStats {
44    /// Start time
45    pub start_time: Option<Instant>,
46
47    /// Phase timings
48    pub phase_times: HashMap<String, Duration>,
49
50    /// Memory usage tracking
51    pub memory_usage: Vec<(String, usize)>,
52
53    /// Items processed
54    pub items_processed: HashMap<String, usize>,
55
56    /// Errors encountered
57    pub errors: Vec<String>,
58
59    /// Warnings
60    pub warnings: Vec<String>,
61}
62
63/// Build phases for progress tracking
64#[derive(Debug, Clone)]
65pub enum BuildPhase {
66    Initialization,
67    BuiltinRegistration,
68    HirCaching,
69    BytecodeCaching,
70    GcPresetCaching,
71    OptimizationAnalysis,
72    Compression,
73    Validation,
74    Serialization,
75    Finalization,
76}
77
78impl BuildPhase {
79    fn name(&self) -> &'static str {
80        match self {
81            BuildPhase::Initialization => "Initialization",
82            BuildPhase::BuiltinRegistration => "Builtin Registration",
83            BuildPhase::HirCaching => "HIR Caching",
84            BuildPhase::BytecodeCaching => "Bytecode Caching",
85            BuildPhase::GcPresetCaching => "GC Preset Caching",
86            BuildPhase::OptimizationAnalysis => "Optimization Analysis",
87            BuildPhase::Compression => "Compression",
88            BuildPhase::Validation => "Validation",
89            BuildPhase::Serialization => "Serialization",
90            BuildPhase::Finalization => "Finalization",
91        }
92    }
93
94    fn weight(&self) -> u64 {
95        match self {
96            BuildPhase::Initialization => 5,
97            BuildPhase::BuiltinRegistration => 15,
98            BuildPhase::HirCaching => 20,
99            BuildPhase::BytecodeCaching => 25,
100            BuildPhase::GcPresetCaching => 5,
101            BuildPhase::OptimizationAnalysis => 10,
102            BuildPhase::Compression => 10,
103            BuildPhase::Validation => 5,
104            BuildPhase::Serialization => 3,
105            BuildPhase::Finalization => 2,
106        }
107    }
108
109    /// Check if this phase requires compression
110    pub fn needs_compression(&self) -> bool {
111        matches!(self, BuildPhase::Compression)
112    }
113
114    /// Check if this phase requires validation  
115    pub fn needs_validation(&self) -> bool {
116        matches!(self, BuildPhase::Validation)
117    }
118
119    /// Check if this phase involves serialization
120    pub fn involves_serialization(&self) -> bool {
121        matches!(self, BuildPhase::Serialization | BuildPhase::Finalization)
122    }
123}
124
125impl SnapshotBuilder {
126    /// Create a new snapshot builder
127    pub fn new(config: SnapshotConfig) -> Self {
128        let compression_config = Self::compression_config_for(&config);
129
130        let compression = CompressionEngine::new(compression_config);
131
132        #[cfg(feature = "validation")]
133        let validator = SnapshotValidator::new();
134
135        let progress = if config.progress_reporting {
136            let pb = ProgressBar::new(100);
137            pb.set_style(
138                ProgressStyle::default_bar()
139                    .template("{spinner:.green} [{elapsed_precise}] [{wide_bar:.cyan/blue}] {pos:>3}/{len:3} {msg}")
140                    .unwrap()
141                    .progress_chars("#>-"),
142            );
143            Some(pb)
144        } else {
145            None
146        };
147
148        Self {
149            config,
150            compression,
151            #[cfg(feature = "validation")]
152            validator,
153            stats: Arc::new(RwLock::new(BuildStats::default())),
154            progress,
155        }
156    }
157
158    fn compression_config_for(config: &SnapshotConfig) -> CompressionConfig {
159        CompressionConfig {
160            default_level: config.compression_level,
161            adaptive_selection: matches!(
162                config.compression_algorithm,
163                crate::CompressionAlgorithm::Auto
164            ),
165            prefer_speed: matches!(
166                config.compression_algorithm,
167                crate::CompressionAlgorithm::Lz4
168            ) || config.compression_level <= 3,
169            ..CompressionConfig::default()
170        }
171    }
172
173    /// Build and save snapshot to file
174    pub fn build_and_save<P: AsRef<Path>>(&self, output_path: P) -> SnapshotResult<()> {
175        let snapshot = self.build()?;
176        self.save_snapshot(&snapshot, output_path)
177    }
178
179    /// Get compression engine for external use
180    pub fn compression_engine(&self) -> &CompressionEngine {
181        &self.compression
182    }
183
184    /// Get validator for external use
185    #[cfg(feature = "validation")]
186    pub fn validator(&self) -> &SnapshotValidator {
187        &self.validator
188    }
189
190    /// Test all build phases for completeness
191    #[cfg(test)]
192    pub fn test_all_phases() -> Vec<BuildPhase> {
193        vec![
194            BuildPhase::Initialization,
195            BuildPhase::BuiltinRegistration,
196            BuildPhase::HirCaching,
197            BuildPhase::BytecodeCaching,
198            BuildPhase::GcPresetCaching,
199            BuildPhase::OptimizationAnalysis,
200            BuildPhase::Compression,
201            BuildPhase::Validation,
202            BuildPhase::Serialization,
203            BuildPhase::Finalization,
204        ]
205    }
206
207    /// Analyze build phase requirements
208    pub fn analyze_phase_requirements(phase: &BuildPhase) -> String {
209        let mut requirements = Vec::new();
210
211        if phase.needs_compression() {
212            requirements.push("compression engine");
213        }
214        if phase.needs_validation() {
215            requirements.push("validation framework");
216        }
217        if phase.involves_serialization() {
218            requirements.push("serialization support");
219        }
220
221        if requirements.is_empty() {
222            "No special requirements".to_string()
223        } else {
224            format!("Requires: {}", requirements.join(", "))
225        }
226    }
227
228    /// Build snapshot in memory
229    pub fn build(&self) -> SnapshotResult<Snapshot> {
230        self.start_build();
231
232        let phases = [
233            BuildPhase::Initialization,
234            BuildPhase::BuiltinRegistration,
235            BuildPhase::HirCaching,
236            BuildPhase::BytecodeCaching,
237            BuildPhase::GcPresetCaching,
238            BuildPhase::OptimizationAnalysis,
239            BuildPhase::Finalization,
240        ];
241
242        let mut current_progress = 0u64;
243        let total_progress: u64 = phases.iter().map(|p| p.weight()).sum();
244
245        // Initialize snapshot
246        let mut snapshot = self.execute_phase(BuildPhase::Initialization, || {
247            Ok(self.create_empty_snapshot())
248        })?;
249        current_progress += BuildPhase::Initialization.weight();
250        self.update_progress(
251            current_progress,
252            total_progress,
253            BuildPhase::Initialization.name(),
254        );
255
256        // Build builtin registry
257        snapshot.builtins = self.execute_phase(BuildPhase::BuiltinRegistration, || {
258            self.build_builtin_registry()
259        })?;
260        current_progress += BuildPhase::BuiltinRegistration.weight();
261        self.update_progress(
262            current_progress,
263            total_progress,
264            BuildPhase::BuiltinRegistration.name(),
265        );
266
267        // Build HIR cache
268        snapshot.hir_cache =
269            self.execute_phase(BuildPhase::HirCaching, || self.build_hir_cache())?;
270        current_progress += BuildPhase::HirCaching.weight();
271        self.update_progress(
272            current_progress,
273            total_progress,
274            BuildPhase::HirCaching.name(),
275        );
276
277        // Build bytecode cache
278        snapshot.bytecode_cache = self.execute_phase(BuildPhase::BytecodeCaching, || {
279            self.build_bytecode_cache(&snapshot.hir_cache)
280        })?;
281        current_progress += BuildPhase::BytecodeCaching.weight();
282        self.update_progress(
283            current_progress,
284            total_progress,
285            BuildPhase::BytecodeCaching.name(),
286        );
287
288        // Build GC presets
289        snapshot.gc_presets =
290            self.execute_phase(BuildPhase::GcPresetCaching, || self.build_gc_presets())?;
291        current_progress += BuildPhase::GcPresetCaching.weight();
292        self.update_progress(
293            current_progress,
294            total_progress,
295            BuildPhase::GcPresetCaching.name(),
296        );
297
298        // Generate optimization hints
299        snapshot.optimization_hints = self
300            .execute_phase(BuildPhase::OptimizationAnalysis, || {
301                self.generate_optimization_hints(&snapshot)
302            })?;
303        current_progress += BuildPhase::OptimizationAnalysis.weight();
304        self.update_progress(
305            current_progress,
306            total_progress,
307            BuildPhase::OptimizationAnalysis.name(),
308        );
309
310        // Finalize snapshot
311        self.execute_phase(BuildPhase::Finalization, || {
312            self.finalize_snapshot(&mut snapshot)
313        })?;
314        current_progress += BuildPhase::Finalization.weight();
315        self.update_progress(
316            current_progress,
317            total_progress,
318            BuildPhase::Finalization.name(),
319        );
320
321        self.finish_build();
322
323        Ok(snapshot)
324    }
325
326    /// Execute a build phase with timing and error handling
327    fn execute_phase<T, F>(&self, phase: BuildPhase, f: F) -> SnapshotResult<T>
328    where
329        F: FnOnce() -> SnapshotResult<T>,
330    {
331        let start = Instant::now();
332        log::info!("Starting build phase: {}", phase.name());
333
334        let result = f().context(format!("Failed in phase: {}", phase.name()));
335
336        let duration = start.elapsed();
337        {
338            let mut stats = self.stats.write();
339            stats.phase_times.insert(phase.name().to_string(), duration);
340
341            match &result {
342                Ok(_) => {
343                    log::info!("Completed build phase: {} in {:?}", phase.name(), duration);
344                }
345                Err(e) => {
346                    let error_msg = format!("Failed in phase {}: {}", phase.name(), e);
347                    log::error!("{error_msg}");
348                    stats.errors.push(error_msg);
349                }
350            }
351        }
352
353        result.map_err(|e| SnapshotError::Configuration {
354            message: e.to_string(),
355        })
356    }
357
358    /// Create empty snapshot structure
359    fn create_empty_snapshot(&self) -> Snapshot {
360        Snapshot {
361            metadata: SnapshotMetadata::current(),
362            builtins: BuiltinRegistry {
363                name_index: HashMap::new(),
364                functions: Vec::new(),
365                dispatch_table: Arc::new(RwLock::new(Vec::new())),
366            },
367            hir_cache: HirCache {
368                functions: HashMap::new(),
369                patterns: Vec::new(),
370                type_cache: HashMap::new(),
371            },
372            bytecode_cache: BytecodeCache {
373                stdlib_bytecode: HashMap::new(),
374                operation_sequences: Vec::new(),
375                hotspots: Vec::new(),
376            },
377            gc_presets: GcPresetCache {
378                presets: HashMap::new(),
379                default_preset: "default".to_string(),
380                performance_profiles: HashMap::new(),
381            },
382            optimization_hints: OptimizationHints {
383                jit_hints: Vec::new(),
384                memory_hints: Vec::new(),
385                execution_hints: Vec::new(),
386            },
387        }
388    }
389
390    /// Build optimized builtin function registry
391    fn build_builtin_registry(&self) -> SnapshotResult<BuiltinRegistry> {
392        log::info!("Building builtin function registry");
393
394        let builtins = runmat_builtins::builtin_functions();
395        let mut name_index = HashMap::new();
396        let mut functions = Vec::new();
397        let mut dispatch_table = Vec::new();
398
399        for (index, builtin) in builtins.iter().enumerate() {
400            match name_index.entry(builtin.name.to_string()) {
401                Entry::Vacant(slot) => {
402                    slot.insert(index);
403                }
404                Entry::Occupied(existing) => {
405                    log::warn!(
406                        "Duplicate builtin '{}' detected while building snapshot (first index {}, duplicate index {})",
407                        builtin.name,
408                        existing.get(),
409                        index
410                    );
411                }
412            }
413
414            // Analyze function characteristics
415            let metadata = self.analyze_builtin_function(builtin)?;
416            functions.push(metadata);
417
418            dispatch_table.push(builtin.implementation);
419
420            {
421                let mut stats = self.stats.write();
422                *stats
423                    .items_processed
424                    .entry("builtins".to_string())
425                    .or_insert(0) += 1;
426            }
427        }
428
429        log::info!("Registered {} builtin functions", functions.len());
430
431        Ok(BuiltinRegistry {
432            name_index,
433            functions,
434            dispatch_table: Arc::new(RwLock::new(dispatch_table)),
435        })
436    }
437
438    /// Analyze builtin function characteristics
439    fn analyze_builtin_function(
440        &self,
441        builtin: &runmat_builtins::BuiltinFunction,
442    ) -> SnapshotResult<BuiltinMetadata> {
443        // Infer characteristics from function name
444        let category = self.infer_builtin_category(builtin.name);
445        let complexity = self.infer_computational_complexity(builtin.name);
446        let optimization_level = self.infer_optimization_level(builtin.name, &category);
447
448        // For now, assume most functions take 1-2 arguments
449        // In a real implementation, this would use reflection or metadata
450        let arity = if builtin.name.ends_with("mul") || builtin.name.contains("dot") {
451            BuiltinArity::Exact(2)
452        } else if builtin.name == "norm"
453            || builtin.name.starts_with("sin")
454            || builtin.name.starts_with("cos")
455        {
456            BuiltinArity::Exact(1)
457        } else {
458            BuiltinArity::Range(1, 3)
459        };
460
461        Ok(BuiltinMetadata {
462            name: builtin.name.to_string(),
463            arity,
464            category,
465            complexity,
466            optimization_level,
467        })
468    }
469
470    /// Infer builtin function category
471    fn infer_builtin_category(&self, name: &str) -> BuiltinCategory {
472        if name.contains("sin")
473            || name.contains("cos")
474            || name.contains("tan")
475            || name.contains("atan")
476            || name.contains("asin")
477            || name.contains("acos")
478        {
479            BuiltinCategory::Trigonometric
480        } else if name.contains("mat")
481            || name.contains("dot")
482            || name.contains("norm")
483            || name.contains("inv")
484            || name.contains("det")
485        {
486            BuiltinCategory::LinearAlgebra
487        } else if name.contains("mean") || name.contains("std") || name.contains("var") {
488            BuiltinCategory::Statistics
489        } else if name.contains("transpose") || name.contains("reshape") || name.contains("size") {
490            BuiltinCategory::MatrixOps
491        } else if name == "max"
492            || name == "min"
493            || name.contains("equal")
494            || name.contains("greater")
495            || name.contains("less")
496        {
497            BuiltinCategory::Comparison
498        } else if name.contains("sqrt")
499            || name.contains("exp")
500            || name.contains("log")
501            || name.contains("abs")
502            || name.contains("pow")
503        {
504            BuiltinCategory::Math
505        } else {
506            BuiltinCategory::Utility
507        }
508    }
509
510    /// Infer computational complexity
511    fn infer_computational_complexity(&self, name: &str) -> ComputationalComplexity {
512        if name.contains("matmul") || name.contains("inv") || name.contains("det") {
513            ComputationalComplexity::Cubic
514        } else if name.contains("mat") && !name.contains("matmul") {
515            ComputationalComplexity::Quadratic
516        } else if name.contains("dot") || name.contains("norm") || name.contains("sum") {
517            ComputationalComplexity::Linear
518        } else {
519            ComputationalComplexity::Constant
520        }
521    }
522
523    /// Infer optimization level
524    fn infer_optimization_level(
525        &self,
526        _name: &str,
527        category: &BuiltinCategory,
528    ) -> OptimizationLevel {
529        let inferred = match category {
530            BuiltinCategory::LinearAlgebra | BuiltinCategory::MatrixOps => {
531                OptimizationLevel::MaxPerformance
532            }
533            BuiltinCategory::Math | BuiltinCategory::Trigonometric => OptimizationLevel::Aggressive,
534            BuiltinCategory::Statistics => OptimizationLevel::Basic,
535            _ => OptimizationLevel::None,
536        };
537
538        cap_optimization_level(inferred, self.config.max_optimization_level)
539    }
540
541    /// Build HIR cache for standard library functions
542    fn build_hir_cache(&self) -> SnapshotResult<HirCache> {
543        log::info!("Building HIR cache");
544
545        let mut functions = HashMap::new();
546        let mut patterns = Vec::new();
547        let mut type_cache = HashMap::new();
548
549        // Cache common standard library functions
550        let stdlib_functions = self.get_stdlib_function_sources();
551
552        for (name, source) in stdlib_functions {
553            match self.compile_to_hir(&source) {
554                Ok(hir) => {
555                    // Extract type information
556                    self.extract_type_info(&hir, &mut type_cache);
557
558                    // Store HIR
559                    functions.insert(name.clone(), hir);
560
561                    {
562                        let mut stats = self.stats.write();
563                        *stats
564                            .items_processed
565                            .entry("hir_functions".to_string())
566                            .or_insert(0) += 1;
567                    }
568                }
569                Err(e) => {
570                    let warning = format!("Failed to compile {name} to HIR: {e}");
571                    log::warn!("{warning}");
572
573                    let mut stats = self.stats.write();
574                    stats.warnings.push(warning);
575                }
576            }
577        }
578
579        // Generate common patterns
580        patterns.extend(self.generate_common_patterns());
581
582        log::info!(
583            "Cached {} HIR functions and {} patterns",
584            functions.len(),
585            patterns.len()
586        );
587
588        Ok(HirCache {
589            functions,
590            patterns,
591            type_cache,
592        })
593    }
594
595    /// Get standard library function sources
596    fn get_stdlib_function_sources(&self) -> Vec<(String, String)> {
597        vec![
598            (
599                "zeros".to_string(),
600                "function z = zeros(m, n); z = zeros(m, n); end".to_string(),
601            ),
602            (
603                "ones".to_string(),
604                "function o = ones(m, n); o = ones(m, n); end".to_string(),
605            ),
606            (
607                "eye".to_string(),
608                "function i = eye(n); i = eye(n); end".to_string(),
609            ),
610            (
611                "sum_vec".to_string(),
612                "function s = sum_vec(v); s = 0; for i = 1:length(v); s = s + v(i); end; end"
613                    .to_string(),
614            ),
615            (
616                "mean_vec".to_string(),
617                "function m = mean_vec(v); m = sum_vec(v) / length(v); end".to_string(),
618            ),
619        ]
620    }
621
622    /// Compile source to semantic HIR
623    fn compile_to_hir(&self, source: &str) -> Result<runmat_hir::HirAssembly> {
624        let ast = runmat_parser::parse(source).map_err(|e| anyhow::anyhow!(e))?;
625        let hir =
626            runmat_hir::lower(&ast, &LoweringContext::empty()).map_err(|e| anyhow::anyhow!(e))?;
627        Ok(hir.assembly)
628    }
629
630    /// Extract type information from HIR
631    fn extract_type_info(
632        &self,
633        _hir: &runmat_hir::HirAssembly,
634        _type_cache: &mut HashMap<String, runmat_hir::Type>,
635    ) {
636        // Type extraction would analyze HIR and populate type cache
637        // For now, this is a placeholder
638    }
639
640    /// Generate common HIR patterns
641    fn generate_common_patterns(&self) -> Vec<HirPattern> {
642        vec![
643            // Common loop patterns
644            HirPattern {
645                name: "simple_for_loop".to_string(),
646                pattern: self.create_pattern_hir("for i = 1:n; x = x + 1; end"),
647                frequency: 1000,
648                optimization_priority: OptimizationLevel::Aggressive,
649            },
650            // Common matrix operations
651            HirPattern {
652                name: "matrix_multiply".to_string(),
653                pattern: self.create_pattern_hir("C = A * B"),
654                frequency: 500,
655                optimization_priority: OptimizationLevel::MaxPerformance,
656            },
657        ]
658    }
659
660    /// Create HIR pattern (simplified)
661    fn create_pattern_hir(&self, source: &str) -> runmat_hir::HirAssembly {
662        self.compile_to_hir(source).unwrap_or_else(|_| {
663            // Fallback to empty program
664            runmat_hir::HirAssembly::default()
665        })
666    }
667
668    /// Build bytecode cache
669    fn build_bytecode_cache(&self, hir_cache: &HirCache) -> SnapshotResult<BytecodeCache> {
670        log::info!("Building bytecode cache");
671
672        let mut stdlib_bytecode = HashMap::new();
673        let mut operation_sequences = Vec::new();
674        let mut hotspots = Vec::new();
675        let stdlib_sources: HashMap<_, _> =
676            self.get_stdlib_function_sources().into_iter().collect();
677
678        // Compile HIR functions to bytecode
679        for (name, hir) in &hir_cache.functions {
680            let compiled = stdlib_sources
681                .get(name)
682                .map(|source| self.compile_source_to_bytecode(source))
683                .unwrap_or_else(|| self.compile_assembly_to_bytecode(hir));
684            match compiled {
685                Ok(bytecode) => {
686                    stdlib_bytecode.insert(name.clone(), bytecode);
687
688                    {
689                        let mut stats = self.stats.write();
690                        *stats
691                            .items_processed
692                            .entry("bytecode_functions".to_string())
693                            .or_insert(0) += 1;
694                    }
695                }
696                Err(e) => {
697                    let warning = format!("Failed to compile {name} to bytecode: {e}");
698                    log::warn!("{warning}");
699
700                    let mut stats = self.stats.write();
701                    stats.warnings.push(warning);
702                }
703            }
704        }
705
706        // Generate common operation sequences
707        operation_sequences.extend(self.generate_operation_sequences());
708
709        // Identify potential hotspots
710        hotspots.extend(self.identify_hotspot_bytecode(&stdlib_bytecode));
711
712        log::info!(
713            "Cached {} bytecode functions, {} sequences, {} hotspots",
714            stdlib_bytecode.len(),
715            operation_sequences.len(),
716            hotspots.len()
717        );
718
719        Ok(BytecodeCache {
720            stdlib_bytecode,
721            operation_sequences,
722            hotspots,
723        })
724    }
725
726    /// Generate common operation sequences
727    fn generate_operation_sequences(&self) -> Vec<BytecodeSequence> {
728        vec![
729            BytecodeSequence {
730                name: "scalar_add".to_string(),
731                bytecode: self.create_sequence_bytecode("x = a + b"),
732                usage_count: 10000,
733                average_execution_time: Duration::from_nanos(100),
734            },
735            BytecodeSequence {
736                name: "scalar_multiply".to_string(),
737                bytecode: self.create_sequence_bytecode("x = a * b"),
738                usage_count: 8000,
739                average_execution_time: Duration::from_nanos(120),
740            },
741        ]
742    }
743
744    /// Create bytecode for sequence
745    fn create_sequence_bytecode(&self, source: &str) -> runmat_vm::Bytecode {
746        self.compile_source_to_bytecode(source)
747            .unwrap_or_else(|_| runmat_vm::Bytecode::empty())
748    }
749
750    fn compile_source_to_bytecode(&self, source: &str) -> Result<runmat_vm::Bytecode> {
751        let ast = runmat_parser::parse(source).map_err(|e| anyhow::anyhow!(e))?;
752        let lowering =
753            runmat_hir::lower(&ast, &LoweringContext::empty()).map_err(|e| anyhow::anyhow!(e))?;
754        self.compile_assembly_to_bytecode(&lowering.assembly)
755    }
756
757    fn compile_assembly_to_bytecode(
758        &self,
759        assembly: &runmat_hir::HirAssembly,
760    ) -> Result<runmat_vm::Bytecode> {
761        let entrypoint = assembly
762            .entrypoints
763            .first()
764            .ok_or_else(|| anyhow::anyhow!("semantic HIR assembly has no entrypoint"))?;
765        let mir = runmat_mir::lowering::lower_assembly(assembly).map_err(|err| {
766            anyhow::anyhow!(format!(
767                "failed to lower semantic HIR assembly to MIR: {err:?}"
768            ))
769        })?;
770        let _analysis = runmat_mir::analysis::analyze_assembly(&mir);
771        runmat_vm::compile(assembly, &mir, entrypoint.id).map_err(Into::into)
772    }
773
774    /// Identify hotspot bytecode for JIT optimization
775    fn identify_hotspot_bytecode(
776        &self,
777        stdlib_bytecode: &HashMap<String, runmat_vm::Bytecode>,
778    ) -> Vec<HotspotBytecode> {
779        let mut hotspots = Vec::new();
780
781        for (name, bytecode) in stdlib_bytecode {
782            if self.is_hotspot_candidate(name, bytecode) {
783                hotspots.push(HotspotBytecode {
784                    name: name.clone(),
785                    bytecode: bytecode.clone(),
786                    execution_frequency: self.estimate_execution_frequency(name),
787                    jit_compilation_threshold: self.determine_jit_threshold(name),
788                    optimization_hints: self.generate_bytecode_optimization_hints(name, bytecode),
789                });
790            }
791        }
792
793        hotspots
794    }
795
796    /// Check if bytecode is a hotspot candidate
797    fn is_hotspot_candidate(&self, name: &str, bytecode: &runmat_vm::Bytecode) -> bool {
798        // Functions with loops or many instructions are good candidates
799        bytecode.instructions.len() > 10
800            || name.contains("loop")
801            || name.contains("mat")
802            || bytecode.instructions.iter().any(|instr| {
803                matches!(
804                    instr,
805                    runmat_vm::Instr::Jump(_) | runmat_vm::Instr::JumpIfFalse(_)
806                )
807            })
808    }
809
810    /// Estimate execution frequency for function
811    fn estimate_execution_frequency(&self, name: &str) -> u64 {
812        // Heuristic based on function type
813        if name.contains("mat") || name.contains("linear") {
814            1000 // High frequency for matrix operations
815        } else if name.contains("loop") {
816            500 // Medium frequency for loops
817        } else {
818            100 // Low frequency for utilities
819        }
820    }
821
822    /// Determine JIT compilation threshold
823    fn determine_jit_threshold(&self, name: &str) -> u32 {
824        if name.contains("mat") {
825            5 // Compile matrix operations quickly
826        } else if name.contains("loop") {
827            10 // Medium threshold for loops
828        } else {
829            20 // Higher threshold for simple functions
830        }
831    }
832
833    /// Generate optimization hints for bytecode
834    fn generate_bytecode_optimization_hints(
835        &self,
836        name: &str,
837        _bytecode: &runmat_vm::Bytecode,
838    ) -> Vec<OptimizationHint> {
839        let mut hints = Vec::new();
840
841        if name.contains("mat") {
842            hints.push(OptimizationHint {
843                hint_type: "vectorization".to_string(),
844                parameters: [("target".to_string(), "simd".to_string())]
845                    .iter()
846                    .cloned()
847                    .collect(),
848                expected_speedup: 4.0,
849            });
850        }
851
852        if name.contains("loop") {
853            hints.push(OptimizationHint {
854                hint_type: "loop_unrolling".to_string(),
855                parameters: [("factor".to_string(), "4".to_string())]
856                    .iter()
857                    .cloned()
858                    .collect(),
859                expected_speedup: 2.0,
860            });
861        }
862
863        hints
864    }
865
866    /// Build GC preset cache
867    fn build_gc_presets(&self) -> SnapshotResult<GcPresetCache> {
868        log::info!("Building GC preset cache");
869
870        let mut presets = HashMap::new();
871        let mut performance_profiles = HashMap::new();
872
873        // Create standard presets
874        presets.insert("default".to_string(), runmat_gc::GcConfig::default());
875        presets.insert(
876            "low-latency".to_string(),
877            runmat_gc::GcConfig::low_latency(),
878        );
879        presets.insert(
880            "high-throughput".to_string(),
881            runmat_gc::GcConfig::high_throughput(),
882        );
883        presets.insert("low-memory".to_string(), runmat_gc::GcConfig::low_memory());
884        presets.insert("debug".to_string(), runmat_gc::GcConfig::debug());
885
886        // Create performance profiles
887        for preset_name in presets.keys() {
888            performance_profiles.insert(
889                preset_name.clone(),
890                self.create_gc_performance_profile(preset_name),
891            );
892        }
893
894        log::info!("Created {} GC presets", presets.len());
895
896        Ok(GcPresetCache {
897            presets,
898            default_preset: "default".to_string(),
899            performance_profiles,
900        })
901    }
902
903    /// Create performance profile for GC preset
904    fn create_gc_performance_profile(&self, preset_name: &str) -> GcPerformanceProfile {
905        // Estimated performance characteristics
906        match preset_name {
907            "low-latency" => GcPerformanceProfile {
908                average_allocation_rate: 1000000.0, // allocations/sec
909                average_collection_time: Duration::from_micros(100),
910                memory_overhead: 0.1,
911                throughput_impact: 0.05,
912            },
913            "high-throughput" => GcPerformanceProfile {
914                average_allocation_rate: 2000000.0,
915                average_collection_time: Duration::from_millis(10),
916                memory_overhead: 0.2,
917                throughput_impact: 0.02,
918            },
919            "low-memory" => GcPerformanceProfile {
920                average_allocation_rate: 500000.0,
921                average_collection_time: Duration::from_millis(5),
922                memory_overhead: 0.05,
923                throughput_impact: 0.1,
924            },
925            _ => GcPerformanceProfile {
926                average_allocation_rate: 800000.0,
927                average_collection_time: Duration::from_millis(2),
928                memory_overhead: 0.15,
929                throughput_impact: 0.08,
930            },
931        }
932    }
933
934    /// Generate optimization hints
935    fn generate_optimization_hints(
936        &self,
937        snapshot: &Snapshot,
938    ) -> SnapshotResult<OptimizationHints> {
939        log::info!("Generating optimization hints");
940
941        let mut jit_hints = Vec::new();
942        let mut memory_hints = Vec::new();
943        let mut execution_hints = Vec::new();
944
945        // Generate JIT hints based on builtins
946        for builtin in &snapshot.builtins.functions {
947            if matches!(
948                builtin.optimization_level,
949                OptimizationLevel::Aggressive | OptimizationLevel::MaxPerformance
950            ) {
951                jit_hints.push(JitHint {
952                    pattern: builtin.name.clone(),
953                    hint_type: self.determine_jit_hint_type(&builtin.category),
954                    priority: builtin.optimization_level,
955                    expected_performance_gain: self
956                        .estimate_jit_performance_gain(&builtin.complexity),
957                });
958            }
959        }
960
961        // Generate memory hints
962        memory_hints.extend(self.generate_memory_hints());
963
964        // Generate execution hints
965        execution_hints.extend(self.generate_execution_hints(&snapshot.bytecode_cache));
966
967        log::info!(
968            "Generated {} JIT hints, {} memory hints, {} execution hints",
969            jit_hints.len(),
970            memory_hints.len(),
971            execution_hints.len()
972        );
973
974        Ok(OptimizationHints {
975            jit_hints,
976            memory_hints,
977            execution_hints,
978        })
979    }
980
981    /// Determine JIT hint type for builtin category
982    fn determine_jit_hint_type(&self, category: &BuiltinCategory) -> JitHintType {
983        match category {
984            BuiltinCategory::LinearAlgebra | BuiltinCategory::MatrixOps => {
985                JitHintType::VectorizeCandidate
986            }
987            BuiltinCategory::Math | BuiltinCategory::Trigonometric => JitHintType::InlineCandidate,
988            _ => JitHintType::ConstantFolding,
989        }
990    }
991
992    /// Estimate JIT performance gain
993    fn estimate_jit_performance_gain(&self, complexity: &ComputationalComplexity) -> f64 {
994        match complexity {
995            ComputationalComplexity::Constant => 1.5,
996            ComputationalComplexity::Linear => 3.0,
997            ComputationalComplexity::Quadratic => 5.0,
998            ComputationalComplexity::Cubic => 8.0,
999            ComputationalComplexity::Exponential => 10.0,
1000        }
1001    }
1002
1003    /// Generate memory optimization hints
1004    fn generate_memory_hints(&self) -> Vec<MemoryHint> {
1005        vec![
1006            MemoryHint {
1007                data_structure: "matrix_data".to_string(),
1008                hint_type: MemoryHintType::AlignmentOptimization,
1009                alignment: 64, // Cache line alignment
1010                prefetch_pattern: PrefetchPattern::Sequential,
1011            },
1012            MemoryHint {
1013                data_structure: "builtin_dispatch".to_string(),
1014                hint_type: MemoryHintType::CacheLocalityOptimization,
1015                alignment: 8,
1016                prefetch_pattern: PrefetchPattern::Random,
1017            },
1018        ]
1019    }
1020
1021    /// Generate execution hints
1022    fn generate_execution_hints(&self, bytecode_cache: &BytecodeCache) -> Vec<ExecutionHint> {
1023        let mut hints = Vec::new();
1024
1025        for hotspot in &bytecode_cache.hotspots {
1026            hints.push(ExecutionHint {
1027                pattern: hotspot.name.clone(),
1028                hint_type: ExecutionHintType::HotPath,
1029                frequency: hotspot.execution_frequency,
1030                optimization_potential: hotspot
1031                    .optimization_hints
1032                    .iter()
1033                    .map(|h| h.expected_speedup)
1034                    .fold(0.0, f64::max),
1035            });
1036        }
1037
1038        hints
1039    }
1040
1041    /// Finalize snapshot with metadata
1042    fn finalize_snapshot(&self, snapshot: &mut Snapshot) -> SnapshotResult<()> {
1043        log::info!("Finalizing snapshot");
1044
1045        // Update performance metrics
1046        let stats = self.stats.read();
1047        snapshot.metadata.performance_metrics = PerformanceMetrics {
1048            creation_time: stats
1049                .start_time
1050                .map_or(Duration::ZERO, |start| start.elapsed()),
1051            builtin_count: snapshot.builtins.functions.len() as u64,
1052            hir_cache_entries: snapshot.hir_cache.functions.len() as u64,
1053            bytecode_cache_entries: snapshot.bytecode_cache.stdlib_bytecode.len() as u64,
1054            uncompressed_size: bincode::serialized_size(snapshot).unwrap_or(0) as u64,
1055            compression_ratio: 1.0, // Will be updated after compression
1056            peak_memory_usage: self.estimate_peak_memory_usage() as u64,
1057        };
1058
1059        Ok(())
1060    }
1061
1062    /// Save snapshot to file
1063    fn save_snapshot<P: AsRef<Path>>(
1064        &self,
1065        snapshot: &Snapshot,
1066        output_path: P,
1067    ) -> SnapshotResult<()> {
1068        log::info!("Saving snapshot to {}", output_path.as_ref().display());
1069
1070        // Serialize snapshot
1071        let serialized = bincode::serialize(snapshot).map_err(SnapshotError::Serialization)?;
1072
1073        // Store original serialized size before compression
1074        let uncompressed_size = serialized.len() as u64;
1075
1076        // Compress if enabled
1077        let (data, compression_info) = self.compress_snapshot_data(&serialized)?;
1078
1079        // Create format
1080        let mut header = SnapshotHeader::new(snapshot.metadata.clone());
1081
1082        // Update data info with actual sizes
1083        header.data_info.compressed_size = data.len() as u64;
1084        header.data_info.uncompressed_size = uncompressed_size;
1085        header.data_info.compression = compression_info;
1086
1087        let mut format = SnapshotFormat::new(header, data);
1088
1089        // Add checksum if validation enabled
1090        #[cfg(feature = "validation")]
1091        if self.config.validation_enabled {
1092            format = format.with_checksum(crate::format::ChecksumAlgorithm::Sha256)?;
1093        }
1094
1095        // Write to file
1096        self.write_snapshot_file(&mut format, output_path)?;
1097
1098        log::info!("Snapshot saved successfully");
1099        Ok(())
1100    }
1101
1102    fn compress_snapshot_data(
1103        &self,
1104        serialized: &[u8],
1105    ) -> SnapshotResult<(Vec<u8>, CompressionInfo)> {
1106        if !self.config.compression_enabled
1107            || matches!(
1108                self.config.compression_algorithm,
1109                crate::CompressionAlgorithm::None
1110            )
1111        {
1112            return Ok((
1113                serialized.to_vec(),
1114                CompressionInfo {
1115                    algorithm: format::CompressionAlgorithm::None,
1116                    level: 0,
1117                    parameters: std::collections::HashMap::new(),
1118                },
1119            ));
1120        }
1121
1122        let mut compression = CompressionEngine::new(Self::compression_config_for(&self.config));
1123        let result = match self.config.compression_algorithm {
1124            crate::CompressionAlgorithm::Auto => compression.compress(serialized)?,
1125            crate::CompressionAlgorithm::Lz4 => compression.compress_with_algorithm(
1126                serialized,
1127                format::CompressionAlgorithm::Lz4 {
1128                    fast: self.config.compression_level <= 3,
1129                },
1130            )?,
1131            crate::CompressionAlgorithm::Zstd => compression.compress_with_algorithm(
1132                serialized,
1133                format::CompressionAlgorithm::Zstd { dictionary: None },
1134            )?,
1135            crate::CompressionAlgorithm::None => unreachable!("handled before compression"),
1136        };
1137
1138        Ok((result.data, result.info))
1139    }
1140
1141    /// Write snapshot format to file
1142    fn write_snapshot_file<P: AsRef<Path>>(
1143        &self,
1144        format: &mut SnapshotFormat,
1145        output_path: P,
1146    ) -> SnapshotResult<()> {
1147        use std::io::Write;
1148
1149        let mut file = std::fs::File::create(output_path)?;
1150
1151        // Serialize header and ensure the data offset reflects the final layout
1152        let (header_data, header_size) = Self::encode_header_with_offset(&mut format.header)?;
1153
1154        // Write header size first (4 bytes, little-endian)
1155        file.write_all(&header_size.to_le_bytes())?;
1156
1157        // Write header
1158        file.write_all(&header_data)?;
1159
1160        // Write data
1161        file.write_all(&format.data)?;
1162
1163        // Write checksum if present
1164        if let Some(checksum) = &format.checksum {
1165            file.write_all(checksum)?;
1166        }
1167
1168        file.sync_all()?;
1169        Ok(())
1170    }
1171
1172    fn encode_header_with_offset(header: &mut SnapshotHeader) -> SnapshotResult<(Vec<u8>, u32)> {
1173        const MAX_ITER: usize = 4;
1174        let mut last_size = None;
1175
1176        for _ in 0..MAX_ITER {
1177            let header_data = bincode::serialize(header)?;
1178            let header_size = header_data.len() as u32;
1179            let desired_offset = 4 + header_size as u64;
1180
1181            if header.data_info.data_offset == desired_offset {
1182                return Ok((header_data, header_size));
1183            }
1184
1185            header.data_info.data_offset = desired_offset;
1186            last_size = Some(header_size);
1187        }
1188
1189        Err(SnapshotError::Configuration {
1190            message: format!(
1191                "Snapshot header failed to stabilize data_offset after {MAX_ITER} attempts (last observed size: {:?})",
1192                last_size
1193            ),
1194        })
1195    }
1196
1197    /// Start build process
1198    fn start_build(&self) {
1199        {
1200            let mut stats = self.stats.write();
1201            stats.start_time = Some(Instant::now());
1202        }
1203
1204        log::info!("Starting snapshot build");
1205
1206        if let Some(ref progress) = self.progress {
1207            progress.set_message("Initializing...");
1208        }
1209    }
1210
1211    /// Finish build process
1212    fn finish_build(&self) {
1213        if let Some(ref progress) = self.progress {
1214            progress.finish_with_message("Snapshot build completed!");
1215        }
1216
1217        let stats = self.stats.read();
1218        if let Some(start_time) = stats.start_time {
1219            let total_time = start_time.elapsed();
1220            log::info!("Snapshot build completed in {total_time:?}");
1221        }
1222    }
1223
1224    /// Update progress
1225    fn update_progress(&self, current: u64, total: u64, message: &str) {
1226        if let Some(ref progress) = self.progress {
1227            progress.set_position((current * 100) / total);
1228            progress.set_message(message.to_string());
1229        }
1230    }
1231
1232    /// Estimate peak memory usage
1233    fn estimate_peak_memory_usage(&self) -> usize {
1234        // Simplified estimation
1235        std::mem::size_of::<Snapshot>() * 2 // Rough estimate
1236    }
1237
1238    /// Get build statistics
1239    pub fn stats(&self) -> BuildStats {
1240        // Clone the data inside the lock
1241        let stats = self.stats.read();
1242        BuildStats {
1243            start_time: stats.start_time,
1244            phase_times: stats.phase_times.clone(),
1245            memory_usage: stats.memory_usage.clone(),
1246            items_processed: stats.items_processed.clone(),
1247            errors: stats.errors.clone(),
1248            warnings: stats.warnings.clone(),
1249        }
1250    }
1251}
1252
1253fn cap_optimization_level(
1254    inferred: OptimizationLevel,
1255    max_level: OptimizationLevel,
1256) -> OptimizationLevel {
1257    if optimization_rank(inferred) > optimization_rank(max_level) {
1258        max_level
1259    } else {
1260        inferred
1261    }
1262}
1263
1264fn optimization_rank(level: OptimizationLevel) -> u8 {
1265    match level {
1266        OptimizationLevel::None => 0,
1267        OptimizationLevel::Basic => 1,
1268        OptimizationLevel::Aggressive => 2,
1269        OptimizationLevel::MaxPerformance => 3,
1270    }
1271}
1272
1273#[cfg(test)]
1274mod tests {
1275    use super::*;
1276
1277    #[test]
1278    fn test_snapshot_builder_creation() {
1279        let config = SnapshotConfig::default();
1280        let builder = SnapshotBuilder::new(config);
1281
1282        let stats = builder.stats();
1283        assert!(stats.start_time.is_none());
1284        assert!(stats.errors.is_empty());
1285    }
1286
1287    #[test]
1288    fn test_builtin_analysis() {
1289        let config = SnapshotConfig::default();
1290        let builder = SnapshotBuilder::new(config);
1291
1292        fn test_builtin(_args: &[runmat_builtins::Value]) -> runmat_builtins::BuiltinFuture {
1293            Box::pin(async { Ok(runmat_builtins::Value::Num(0.0)) })
1294        }
1295
1296        let builtin = runmat_builtins::BuiltinFunction::new(
1297            "matmul",
1298            "Test builtin function",
1299            "Category",
1300            "",
1301            "",
1302            vec![],
1303            runmat_builtins::Type::Num,
1304            None,
1305            test_builtin,
1306            &[],
1307            false,
1308            false,
1309        );
1310
1311        let metadata = builder.analyze_builtin_function(&builtin).unwrap();
1312        assert_eq!(metadata.name, "matmul");
1313        assert!(matches!(metadata.category, BuiltinCategory::LinearAlgebra));
1314        assert!(matches!(
1315            metadata.complexity,
1316            ComputationalComplexity::Cubic
1317        ));
1318    }
1319
1320    #[test]
1321    fn test_category_inference() {
1322        let config = SnapshotConfig::default();
1323        let builder = SnapshotBuilder::new(config);
1324
1325        assert!(matches!(
1326            builder.infer_builtin_category("sin"),
1327            BuiltinCategory::Trigonometric
1328        ));
1329        assert!(matches!(
1330            builder.infer_builtin_category("matmul"),
1331            BuiltinCategory::LinearAlgebra
1332        ));
1333        assert!(matches!(
1334            builder.infer_builtin_category("max"),
1335            BuiltinCategory::Comparison
1336        ));
1337    }
1338
1339    #[test]
1340    fn test_complexity_inference() {
1341        let config = SnapshotConfig::default();
1342        let builder = SnapshotBuilder::new(config);
1343
1344        assert!(matches!(
1345            builder.infer_computational_complexity("matmul"),
1346            ComputationalComplexity::Cubic
1347        ));
1348        assert!(matches!(
1349            builder.infer_computational_complexity("dot"),
1350            ComputationalComplexity::Linear
1351        ));
1352        assert!(matches!(
1353            builder.infer_computational_complexity("abs"),
1354            ComputationalComplexity::Constant
1355        ));
1356    }
1357
1358    #[test]
1359    fn test_optimization_level_respects_config_cap() {
1360        let config = SnapshotConfig {
1361            max_optimization_level: OptimizationLevel::Basic,
1362            ..SnapshotConfig::default()
1363        };
1364        let builder = SnapshotBuilder::new(config);
1365
1366        assert_eq!(
1367            builder.infer_optimization_level("matmul", &BuiltinCategory::LinearAlgebra),
1368            OptimizationLevel::Basic
1369        );
1370        assert_eq!(
1371            builder.infer_optimization_level("sin", &BuiltinCategory::Trigonometric),
1372            OptimizationLevel::Basic
1373        );
1374        assert_eq!(
1375            builder.infer_optimization_level("mean", &BuiltinCategory::Statistics),
1376            OptimizationLevel::Basic
1377        );
1378        assert_eq!(
1379            builder.infer_optimization_level("disp", &BuiltinCategory::Utility),
1380            OptimizationLevel::None
1381        );
1382    }
1383
1384    #[test]
1385    fn test_empty_snapshot_creation() {
1386        let config = SnapshotConfig::default();
1387        let builder = SnapshotBuilder::new(config);
1388
1389        let snapshot = builder.create_empty_snapshot();
1390        assert!(snapshot.builtins.functions.is_empty());
1391        assert!(snapshot.hir_cache.functions.is_empty());
1392        assert!(snapshot.bytecode_cache.stdlib_bytecode.is_empty());
1393    }
1394
1395    #[test]
1396    fn test_gc_performance_profile() {
1397        let config = SnapshotConfig::default();
1398        let builder = SnapshotBuilder::new(config);
1399
1400        let profile = builder.create_gc_performance_profile("low-latency");
1401        assert!(profile.average_collection_time < Duration::from_millis(1));
1402        assert!(profile.memory_overhead < 0.2);
1403    }
1404
1405    #[test]
1406    fn test_build_phases() {
1407        // Test all build phases are properly constructed
1408        let phases = SnapshotBuilder::test_all_phases();
1409        assert_eq!(phases.len(), 10);
1410
1411        // Test phase analysis
1412        for phase in &phases {
1413            let requirements = SnapshotBuilder::analyze_phase_requirements(phase);
1414            assert!(!requirements.is_empty());
1415
1416            // Test specific phase methods
1417            match phase {
1418                BuildPhase::Compression => assert!(phase.needs_compression()),
1419                BuildPhase::Validation => assert!(phase.needs_validation()),
1420                BuildPhase::Serialization => assert!(phase.involves_serialization()),
1421                BuildPhase::Finalization => assert!(phase.involves_serialization()),
1422                _ => {
1423                    assert!(!phase.needs_compression());
1424                    assert!(!phase.needs_validation());
1425                }
1426            }
1427        }
1428    }
1429
1430    #[test]
1431    fn test_compression_engine_access() {
1432        let config = SnapshotConfig::default();
1433        let builder = SnapshotBuilder::new(config);
1434
1435        // Test that we can access the compression engine
1436        let _engine = builder.compression_engine();
1437    }
1438
1439    #[cfg(feature = "validation")]
1440    #[test]
1441    fn test_validator_access() {
1442        let config = SnapshotConfig::default();
1443        let builder = SnapshotBuilder::new(config);
1444
1445        // Test that we can access the validator
1446        let _validator = builder.validator();
1447    }
1448}