Files
OxideJS-New/crates/oxide_compiler/src/compiler.rs
T

135 lines
6.0 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! 编译入口:`Compiler::compile` 串联 emit 与 lowering。
use oxide_bytecode::module::CompiledModule;
use oxide_emit::Emitter;
use oxide_ir::lower::lower;
/// 结构哈希 / 编译模块哈希 re-export(供编译缓存作键)。
pub use crate::hash::{compiled_module_hash, structural_hash};
/// 编译入口:状态 = DCE 开关 + RegAlloc 开关 + REPL 持久开关 + eval 脚本标记,编译其余状态在 emit/lower 内部。
pub struct Compiler {
/// 是否在 emit 与 lower 之间运行死代码消除(默认开启)。
enable_dce: bool,
/// 是否在保守 DCE 后运行 liveness→精确 DCE→RegAlloc 链(默认开启)。
/// 关闭时虚拟寄存器不分配物理号,直接当作物理号进入 lower 的低层降级路径;
/// 数量超过 253 时由 lower 报 RangeError。
enable_regalloc: bool,
/// 是否为 REPL 持久模式:脚本顶层 let/const 也写全局对象属性。
repl_persist: bool,
/// 是否为 eval 脚本:顶层 var/function 声明落全局属性 configurable:true。
is_eval_script: bool,
/// 源码是否为 `source_escape` 产物(动态编译入口:eval / Function 构造器)。
is_source_encoded: bool,
}
impl Compiler {
/// 构造 `Compiler`:默认开启 DCE 与 RegAlloc,不开启 REPL 持久与 eval 脚本标记。
pub fn new() -> Self {
Self {
enable_dce: true,
enable_regalloc: true,
repl_persist: false,
is_eval_script: false,
is_source_encoded: false,
}
}
/// 显式设置 DCE 开关(`with_dce(false)` 关闭死代码消除)。
pub fn with_dce(self, enable: bool) -> Self {
Self { enable_dce: enable, ..self }
}
/// 显式设置 RegAlloc 开关(`with_regalloc(false)` 关闭 liveness/精确 DCE/RegAlloc 链)。
pub fn with_regalloc(self, enable: bool) -> Self {
Self {
enable_regalloc: enable,
..self
}
}
/// 启用 REPL 持久模式(脚本顶层 let/const 也写全局对象)。
pub fn with_repl_persist(self, enable: bool) -> Self {
Self { repl_persist: enable, ..self }
}
/// 标记为 eval 脚本(顶层 var/function 声明落全局属性 configurable:true)。
pub fn with_eval_script(self, enable: bool) -> Self {
Self { is_eval_script: enable, ..self }
}
/// 标记源码为 `source_escape` 产物(动态编译入口:eval / Function 构造器)。
pub fn with_source_encoded(self, enable: bool) -> Self {
Self {
is_source_encoded: enable,
..self
}
}
/// 编译整个 script program:AST → IR(`Emitter::emit_program`)→ 统一 IR 管线。
pub fn compile(&self, program: &oxide_parser::Program) -> Result<CompiledModule, String> {
crate::compiler_debug!("compile: starting...");
let ir = Emitter::new().with_source_encoded(self.is_source_encoded).emit_program(
program,
self.repl_persist,
self.is_eval_script,
)?;
self.compile_ir(ir)
}
/// 编译 ES module:AST → IR(`Emitter::emit_program_module`,含依赖模块链接)→ 统一 IR 管线。
/// `module_path` 为模块文件的规范路径(依赖解析基准 = 其父目录),依赖加载经
/// `loader` 解析。
pub fn compile_module(
&self, program: &oxide_parser::Program, module_path: &str,
loader: &mut dyn oxide_emit::module::ModuleSourceLoader,
) -> Result<CompiledModule, String> {
crate::compiler_debug!("compile_module: starting...");
let ir = Emitter::new().emit_program_module(program, module_path, loader)?;
let mut module = self.compile_ir(ir)?;
module.is_es_module = true;
Ok(module)
}
/// 统一 IR 后处理管线:(可选 DCE)→(可选 liveness/精确 DCE/RegAlloc)→
/// bytecode(`lower`)→ 子模块拍平。
fn compile_ir(&self, mut ir: oxide_ir::IRFunction) -> Result<CompiledModule, String> {
crate::compiler_debug!("compile_ir: after emit {} insts", ir.insts.len());
if self.enable_dce {
oxide_dce::dce(&mut ir); // 顶层函数;nested 不递归
crate::compiler_debug!("compile: after DCE {} insts", ir.insts.len());
}
if self.enable_regalloc && !ir.const_overflow {
// 优化管线:liveness → 精确 DCE → 重算 liveness → RegAlloc → 调用窗口编码
// const_overflow 时跳过:程序已知无效(lower 报 "too many constants"),
// 且超大常量池伴生的海量虚拟寄存器会使 liveness 稠密 bitset 爆内存。
let cfg = oxide_cfg::build_cfg(&ir);
let live = oxide_liveness::liveness(&ir, &cfg);
// 精确 DCE 以第一轮 liveness 的指令级活集为输入,删除死指令
oxide_dce::dce_precise(&mut ir, &live);
// 删指令后 inst 下标位移,旧 CFG 失效,按新程序重建
let cfg2 = oxide_cfg::build_cfg(&ir);
// 指令集已变,旧活集失效,须重算
let live2 = oxide_liveness::liveness(&ir, &cfg2);
// 无可行染色 → RangeError 上抛
oxide_regalloc::alloc(&mut ir, &live2)?;
// RegAlloc 改写指令(虚拟寄存器→物理号并插入 spill)后旧活集失效,
// 须重算第三轮,为调用点存活上界提供物理级活集
let cfg3 = oxide_cfg::build_cfg(&ir);
let live3 = oxide_liveness::liveness(&ir, &cfg3);
oxide_regalloc::encode_call_window(&mut ir, &live3);
crate::compiler_debug!("compile: after regalloc {} insts", ir.insts.len());
}
crate::compiler_debug!("compile: done, {} instructions", ir.insts.len());
let mut module = lower(&ir)?;
crate::flatten::flatten_submodules(&mut module);
Ok(module)
}
}
impl Default for Compiler {
fn default() -> Self {
Self::new()
}
}