This repository has been archived on 2026-09-15. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
OxideJS/crates/oxide_ir/src/lower.rs
T
爱特每羊队 4303462d19 feat: compiler/test262 runner 接线 + 模块顶层 this 绑定
- Compiler::compile_module:Emitter::emit_program_module → 统一 IR 管线(DCE/regalloc/lower/flatten)
- CompiledModule.is_es_module:VM run 时模块顶层 this=undefined(脚本仍为全局对象)
- 全局注册 __moduleLinkGet
- test262 runner:Test262ModuleLoader(相对路径解析 + import attributes 判定 json/text/bytes),is_module 走 compile_module
2026-08-12 17:37:33 +08:00

155 lines
6.3 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.
//! IRFunction → CompiledModule 等价转换。
//!
//! 字节码格式(4 字节 u32 + 扩展字)逐指令一致。
//! label 用前缀和:`label_pos` 记 Inst 下标,平铺时维护 inst→instr 映射,
//! 跳转 offset 以 Instr(含 ext 字)为单位。
use std::sync::Arc;
use oxide_bytecode::module::CompiledModule;
use oxide_bytecode::opcode::{self, OpCode};
use crate::inst::Inst;
use crate::operand::Operand;
use crate::IRFunction;
/// IRFunction → CompiledModule 等价转换。溢出/标签错误消息为既有格式,逐字保持一致。
pub fn lower(f: &IRFunction) -> Result<CompiledModule, String> {
crate::ir_debug!("lower: {} insts", f.insts.len());
// 溢出检查 1:常量池(先于寄存器——超大常量池伴生的海量 vreg 会使后续检查的
// 稠密 bitset 表示爆内存;常量池超限是更基础的失效,先报它)
if f.const_overflow || f.constants.len() > u16::MAX as usize {
return Err("RangeError: too many constants".into());
}
// 溢出检查 2:寄存器(仅 Operand::Reg 变体;This/NewTarget 是语义操作数,映射 254/255 合法)
for inst in &f.insts {
for o in [&inst.rd, &inst.a, &inst.b] {
if let Operand::Reg(r) = o {
if *r > 253 {
return Err("RangeError: function body uses too many registers (max 253)".into());
}
}
}
}
// 溢出检查 2b:n_registers(u32 → CompiledModule u8 前的显式截断检查)。
// n_registers = max_regs = 最高分配号 + 1,合法上限 254(reg 0..253)。
// 纯参数/空体函数可能无指令引用最高号寄存器,逐指令检查漏掉,计数检查兜底防 u8 静默截断。
if f.n_registers > 254 {
return Err("RangeError: function body uses too many registers (max 253)".into());
}
let mut instrs: Vec<u32> = Vec::new();
let mut inst_to_instr: Vec<usize> = Vec::with_capacity(f.insts.len());
// (当前指令的起始 Instr index, label id)
let mut jumps: Vec<(usize, u32)> = Vec::new();
for inst in &f.insts {
inst_to_instr.push(instrs.len());
encode_inst(inst, &mut instrs, &mut jumps)?;
}
// 跳转回填:offset = 目标 Instr - 当前 Instr(前缀和)
for (instr_idx, label) in jumps {
let target_inst = f
.label_pos
.get(label as usize)
.and_then(|p| *p)
.ok_or_else(|| format!("Label {label} not found in bytecode map"))?;
if target_inst >= inst_to_instr.len() {
return Err(format!("Label {label} not found in bytecode map"));
}
let target_instr = inst_to_instr[target_inst];
let offset = target_instr as isize - instr_idx as isize;
if offset < i16::MIN as isize || offset > i16::MAX as isize {
return Err("RangeError: jump offset out of range".into());
}
let offset = offset as i16;
let existing = instrs[instr_idx];
let op = opcode::opcode(existing);
let rd = opcode::rd(existing);
instrs[instr_idx] = opcode::encode(op, rd, (offset as u16 & 0xFF) as u8, ((offset as u16 >> 8) & 0xFF) as u8);
}
let mut sub_modules = Vec::with_capacity(f.nested.len());
for nested in &f.nested {
sub_modules.push(Arc::new(lower(nested)?));
}
Ok(CompiledModule {
bytecode: Arc::from(instrs),
constants: f.constants.clone(),
n_registers: f.n_registers as u8,
n_args: f.param_layout.count as u8,
param_base: f.param_layout.base as u8,
builtin_reg_map: f.builtin_reg_map.clone(),
sub_modules,
is_arrow: f.is_arrow,
captured_this_const_idx: f.captured_this_const_idx,
function_name: f.function_name.clone(),
function_length: f.function_length,
is_class_constructor: f.is_class_constructor,
is_derived_constructor: f.is_derived_constructor,
needs_home_object: f.needs_home_object,
is_generator: f.is_generator,
is_async: f.is_async,
upvalue_captures: f.upvalue_captures.clone(),
cells_needed: f.cells_needed,
flat_id: 0,
is_es_module: false,
})
}
/// Operand → u8 槽位。Const/Imm 在 a 槽走拆字(operand_pair_to_u8);
/// 出现在 b/rd 槽时按低字节直写(const_flag、cell_idx、uv_idx 等一字节立即数)。
fn operand_to_u8(o: &Operand) -> u8 {
match o {
Operand::Reg(r) => *r as u8,
Operand::This => 254,
Operand::NewTarget => 255,
Operand::Imm(v) => (v & 0xFF) as u8,
Operand::Const(v) => (v & 0xFF) as u8,
Operand::Label(_) | Operand::None => 0,
}
}
/// 普通指令的 a/b 槽:a 槽的 Const/Imm 拆 lo/hi(对应 LOAD_CONST/CREATE_CLOSURE 布局)。
fn operand_pair_to_u8(a: &Operand, b: &Operand) -> (u8, u8) {
match a {
Operand::Const(idx) => ((idx & 0xFF) as u8, (idx >> 8) as u8),
Operand::Imm(v) => ((v & 0xFF) as u8, (v >> 8) as u8),
_ => (operand_to_u8(a), operand_to_u8(b)),
}
}
fn encode_inst(inst: &Inst, instrs: &mut Vec<u32>, jumps: &mut Vec<(usize, u32)>) -> Result<(), String> {
if inst.op.is_jump() {
let label = match inst.b {
Operand::Label(id) => id,
_ => return Err(format!("jump op {:?} requires Label operand in b slot", inst.op)),
};
let cond = operand_to_u8(&inst.rd);
let start = instrs.len();
let instr = match inst.op {
OpCode::JMP => opcode::encode_jmp(0),
OpCode::BREAK | OpCode::CONTINUE => opcode::encode(inst.op, cond, 0, 0),
OpCode::JMP_IF_FALSE => opcode::encode_jmp_if_false(cond, 0),
OpCode::JMP_IF_TRUE => opcode::encode_jmp_if_true(cond, 0),
OpCode::JMP_IF_NULLISH => opcode::encode_jmp_if_nullish(cond, 0),
OpCode::TRY_BEGIN => opcode::encode_try_begin(0),
OpCode::TRY_FINALLY_BEGIN => opcode::encode_try_finally_begin(0),
_ => unreachable!("is_jump_op mismatch"),
};
instrs.push(instr);
jumps.push((start, label));
return Ok(());
}
let rd = operand_to_u8(&inst.rd);
let (a, b) = operand_pair_to_u8(&inst.a, &inst.b);
instrs.push(opcode::encode(inst.op, rd, a, b));
instrs.extend_from_slice(&inst.ext);
Ok(())
}