alduin 0.0.1

WIP: A toy compiler backend
Documentation
use std::{
    collections::HashMap,
    sync::{Arc, Mutex},
};

use crate::{
    backend::ISA,
    compiler::compiled_code::CompiledCode,
    compiler::graph::{cfg, Graph},
};

type Isa = crate::backend::x64::X64;

use super::{
    code_space::{CodeBuffer, CodeSpace},
    compiled_code::Symbol,
};

pub struct Compiler {
    pub(crate) code: CodeSpace,
    functions: Mutex<HashMap<Symbol, Box<Graph>>>,
    compiled_functions: Mutex<HashMap<Symbol, Arc<dyn CompiledCode>>>,
    pub(crate) lazy_compilation_trampoline: CodeBuffer,
}

impl Compiler {
    pub fn new() -> Self {
        crate::init_logger();
        let code = CodeSpace::new(128 << 20);
        let lazy_compilation_trampoline =
            code.alloc_code_buffer::<Isa>(&Isa::gen_lazy_compilation_trampoline());
        Self {
            code,
            functions: Mutex::new(HashMap::default()),
            compiled_functions: Mutex::new(HashMap::default()),
            lazy_compilation_trampoline,
        }
    }

    pub fn compile(&self, name: Symbol, graph: Box<Graph>) {
        let mut cfg = cfg::schedule::<Isa>(graph);
        let compiled_code = {
            // compile to machine code
            let compiled_code = Isa::codegen(self, name.clone(), &mut cfg);
            compiled_code
        };
        self.compiled_functions
            .lock()
            .unwrap()
            .insert(name.clone(), compiled_code);
        self.functions.lock().unwrap().insert(name, cfg.g);
    }

    pub fn contains(&self, name: &Symbol) -> bool {
        self.functions.lock().unwrap().contains_key(name)
    }

    /// Resolve and link all functions in memory, for single-pass JIT
    pub fn finalize<Isa: ISA>(&mut self) {
        // link
        let mut symbol_addrs: HashMap<Symbol, *const u8> = HashMap::new();
        let mut compiled_functions = self.compiled_functions.lock().unwrap();
        for (func, code) in &*compiled_functions {
            symbol_addrs.insert(func.clone(), code.entry());
        }
        for (_, code) in &mut *compiled_functions {
            code.link(&symbol_addrs);
        }
    }

    pub fn get(&self, name: &Symbol) -> Arc<dyn CompiledCode> {
        let funcs = self.compiled_functions.lock().unwrap();
        funcs[name].clone()
    }
}