lamina 0.0.10

High-performance compiler backend for Lamina Intermediate Representation
Documentation
//! Runtime compiler
//!
//! Compiles MIR modules to executable memory using ras.

use crate::error::LaminaError;
use crate::mir::Module as MirModule;
use crate::mir_codegen::validate_module_call_parameters;
use lamina_platform::{TargetArchitecture, TargetOperatingSystem};
use ras::RasRuntime;
use std::collections::HashMap;

/// Runtime compiler for JIT compilation
pub struct RuntimeCompiler {
    target_arch: TargetArchitecture,
    #[allow(dead_code)] // Used when encoder feature is enabled
    runtime: RasRuntime,
    code_cache: HashMap<String, ras::ExecutableMemory>,
}

impl RuntimeCompiler {
    /// Create a new runtime compiler
    pub fn new(target_arch: TargetArchitecture, target_os: TargetOperatingSystem) -> Self {
        Self {
            target_arch,
            runtime: RasRuntime::new(target_arch, target_os),
            code_cache: HashMap::new(),
        }
    }

    /// Compile a MIR module to executable memory
    ///
    /// Note: Caching is not yet implemented as ExecutableMemory may not be Clone.
    /// Future implementation will use reference counting or other strategies.
    pub fn compile(
        &mut self,
        _module: &MirModule,
        _function_name: Option<&str>,
    ) -> Result<ras::ExecutableMemory, LaminaError> {
        // TODO: Implement caching when ExecutableMemory supports it
        // For now, always compile fresh

        // Compile using ras runtime
        #[cfg(feature = "encoder")]
        {
            validate_module_call_parameters(_module, self.target_arch)?;
            self.runtime.compile_to_memory(_module).map_err(|e| {
                let error_msg = format!("{}", e);
                if error_msg.contains("not yet implemented")
                    || error_msg.contains("Unsupported target")
                {
                    LaminaError::ValidationError(format!(
                        "JIT compilation is not supported for this target (or the MIR uses an unsupported construct).\n\
                             Error: {}\n\
                             JIT machine code is emitted only for x86_64 and AArch64.\n\
                             Consider AOT compilation instead (run without --jit).",
                        error_msg
                    ))
                } else {
                    LaminaError::ValidationError(format!("Runtime compilation failed: {}", e))
                }
            })
        }
        #[cfg(not(feature = "encoder"))]
        {
            Err(LaminaError::ValidationError(
                "Runtime compilation requires the 'encoder' feature to be enabled in ras"
                    .to_string(),
            ))
        }
    }

    /// Compile and get function pointer
    ///
    /// Returns an unsafe function pointer.
    ///
    /// # Safety
    ///
    /// The caller must ensure:
    /// 1. The signature `T` matches the actual function signature in the compiled module.
    /// 2. The returned `ExecutableMemory` (and the `RuntimeCompiler` that owns it) outlives
    ///    every invocation of the returned function pointer.
    pub unsafe fn compile_function<T>(
        &mut self,
        module: &MirModule,
        function_name: &str,
    ) -> Result<unsafe extern "C" fn() -> T, LaminaError> {
        let memory = self.compile(module, Some(function_name))?;
        unsafe {
            let ptr = memory.code_start();
            if ptr.is_null() {
                return Err(LaminaError::ValidationError(
                    "ExecutableMemory has null ptr".to_string(),
                ));
            }
            let f: unsafe extern "C" fn() -> T = std::mem::transmute(ptr);
            Ok(f)
        }
    }

    /// Invalidate cached code
    pub fn invalidate(&mut self, function_name: &str) {
        self.code_cache.remove(function_name);
    }

    /// Clear all cached code
    pub fn clear_cache(&mut self) {
        self.code_cache.clear();
    }
}