Files
OxideJS-New/crates/oxide_bytecode/src/module.rs
T

445 lines
20 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.
//! 编译产物(compiled module)与常量池 ABI。
//!
//! [`CompiledModule`] 是编译器输出的字节码函数单元:指令序列、常量池、
//! 寄存器布局元信息、子函数(嵌套函数)与 upvalue 捕获描述;随 VM 解释执行
//! 或由其它模块克隆复制。`Display` 输出可读的反汇编文本,供调试用:
//! 扩展字并入其指令行不单独成行,offset 列为字序号(与 VM 的 pc 同单位),
//! 子模块(嵌套函数体)递归渲染。
use std::fmt;
use std::sync::Arc;
use crate::opcode::{self, OpCode};
/// 常量池条目:编译期折叠的不可变值。
///
/// 变体覆盖 ECMAScript 顶层字面量类型;`Display` 未实现,调试输出走 `Debug`。
#[derive(Debug, Clone, PartialEq)]
pub enum Constant {
Number(f64),
Int(i32),
BigInt(num_bigint::BigInt),
String(String),
Boolean(bool),
Null,
Undefined,
}
/// 闭包对上层作用域一个变量的捕获描述。
///
/// `enclosing_reg` 是外层函数中该变量的寄存器位;`cell_idx` 是父函数 own cell
/// 表下标(`parent_uv_idx` 为 None 时)。多级闭包(外层变量本身就是父函数从更
/// 外层捕获的 upvalue)时 `parent_uv_idx` 给出父闭包 `upvalues` 数组下标。
#[derive(Debug, Clone, PartialEq)]
pub struct UpvalueCapture {
pub name: String,
pub enclosing_reg: u32,
pub cell_idx: u8,
/// 链式捕获:None = 父 own cell(cell_idx 索引定义方 cell 表);
/// Some = 父函数自身 upvalue(运行时从父闭包 upvalues[parent_uv_idx] 取 cell)。
pub parent_uv_idx: Option<u8>,
}
/// 一个函数单元(或顶层脚本)的编译产物。
///
/// 字段说明:
/// - `bytecode` / `constants` — 指令序列与常量池;
/// - `n_registers` / `n_args` / `param_base` — 寄存器窗口布局;
/// - `builtin_reg_map` — 内置对象到寄存器的预绑定;
/// - `sub_modules` — 嵌套函数(闭包体)的编译产物(`Arc` 共享,避免每次 run 深拷贝模块树);
/// - `is_arrow` / `captured_this_const_idx` — 箭头函数词法 `this`;
/// - `is_class_constructor` / `is_derived_constructor` / `needs_home_object` — 类相关;
/// - `upvalue_captures` / `cells_needed` — 闭包捕获描述。
///
/// 派生 `PartialEq` 供缓存 debug 重编译校验做整结构比较(递归覆盖子模块树);
/// `Debug` 供校验失败时输出整棵模块树(与 `Display` 反汇编互补)。
#[derive(Debug, PartialEq)]
pub struct CompiledModule {
pub bytecode: Arc<[opcode::Instr]>,
pub constants: Vec<Constant>,
pub n_registers: u8,
pub n_args: u8,
pub param_base: u8,
pub builtin_reg_map: Vec<(String, u32)>,
pub sub_modules: Vec<Arc<CompiledModule>>,
/// 是否为箭头函数体(箭头函数从外围作用域词法捕获 `this`)。
pub is_arrow: bool,
/// 是否为严格模式函数体:VM 帧入口据其判定 sloppy `this` 替换。
pub is_strict: bool,
/// 捕获 `this` 的 JsValue 在常量池中的下标;0 表示未捕获,使用标准 this 绑定。
pub captured_this_const_idx: u16,
/// 由赋值上下文推断的函数名,在变量声明 / 对象属性赋值点设置。
pub function_name: Option<String>,
/// 函数名不可写绑定的寄存器(帧槽写入目标):压帧时把 callee 函数对象写入该槽。
/// `None` 表示无名绑定(匿名函数 / 形参或 var 同名抑制 / arguments 特例)。
pub function_name_reg: Option<u32>,
/// 函数 `length` 属性值:第一个带默认值/解构默认的形参之前的形参数(rest 不计)。
pub function_length: u32,
/// 形参列表是否 simple(全部无初始值标识符且无 rest):arguments 对象
/// callee 形态(数据属性 vs 受限访问器)按 strict ‖ !simple 分流。
pub has_simple_params: bool,
/// 是否为类构造函数(普通 CALL 必须拒绝它,仅 NEW_EXPRESSION 可经它构造)。
pub is_class_constructor: bool,
/// 类构造函数是否有 `extends` 子句(`this` 在 SUPER_CALL 完成前保持未初始化)。
pub is_derived_constructor: bool,
/// 原型方法是否需要运行时 home_object。
pub needs_home_object: bool,
/// 是否为生成器函数体(`function*`):调用返回迭代器对象,body 挂起/恢复执行。
pub is_generator: bool,
/// 是否为异步函数体(`async function` / async 箭头):调用返回 promise,body 挂起/恢复执行。
pub is_async: bool,
pub upvalue_captures: Vec<UpvalueCapture>,
pub cells_needed: u8,
/// own cell 绑定名表:下标 = cell 下标,值 = 绑定名;未覆盖下标(合成
/// cell、块级预声明追加)留空串。与 `cells_needed` 同容量口径,供运行时
/// TDZ 消息取名。
pub cell_names: Vec<String>,
/// 全局扁平模块 id:编译末端 flatten 阶段分配(顶层 0,子模块 DFS 递增)。
/// `CREATE_CLOSURE` 的 imm16 在 flatten 后即此 id,运行时以它为平表下标。
pub flat_id: u32,
/// 是否为 ES module 顶层:VM 据此把顶层 `this` 绑定为 undefined
/// (模块环境记录 GetThisBinding 返回 undefined,区别于脚本全局 this)。
pub is_es_module: bool,
}
impl CompiledModule {
/// 构造空模块:空字节码、空常量池、零寄存器与全部标志默认关闭。
pub fn new() -> Self {
Self {
bytecode: Arc::from(Vec::new()),
constants: Vec::new(),
n_registers: 0,
n_args: 0,
param_base: 0,
builtin_reg_map: Vec::new(),
sub_modules: Vec::new(),
is_arrow: false,
is_strict: false,
captured_this_const_idx: 0,
function_name: None,
function_name_reg: None,
function_length: 0,
has_simple_params: false,
is_class_constructor: false,
is_derived_constructor: false,
needs_home_object: false,
is_generator: false,
is_async: false,
upvalue_captures: Vec::new(),
cells_needed: 0,
cell_names: Vec::new(),
flat_id: 0,
is_es_module: false,
}
}
}
impl Default for CompiledModule {
fn default() -> Self {
Self::new()
}
}
impl Clone for CompiledModule {
fn clone(&self) -> Self {
Self {
bytecode: self.bytecode.clone(),
constants: self.constants.clone(),
n_registers: self.n_registers,
n_args: self.n_args,
param_base: self.param_base,
builtin_reg_map: self.builtin_reg_map.clone(),
sub_modules: self.sub_modules.clone(),
is_arrow: self.is_arrow,
is_strict: self.is_strict,
captured_this_const_idx: self.captured_this_const_idx,
function_name: self.function_name.clone(),
function_name_reg: self.function_name_reg,
function_length: self.function_length,
has_simple_params: self.has_simple_params,
is_class_constructor: self.is_class_constructor,
is_derived_constructor: self.is_derived_constructor,
needs_home_object: self.needs_home_object,
is_generator: self.is_generator,
is_async: self.is_async,
upvalue_captures: self.upvalue_captures.clone(),
cells_needed: self.cells_needed,
cell_names: self.cell_names.clone(),
flat_id: self.flat_id,
is_es_module: self.is_es_module,
}
}
}
impl fmt::Display for CompiledModule {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Self::render(f, self, 0, None)
}
}
impl CompiledModule {
/// 渲染一个模块单元:头部元信息 + 指令行 + 递归子模块。
///
/// `depth` 控制指令行缩进(顶层 0,每层 +2 空格);`sub_index` 为子模块序号
/// (顶层 None)。指令行按 `1 + ext_word_count` 推进 offset,扩展字并入其
/// 指令行,不单独成行;offset 列即字序号(与 VM 的 pc 同单位)。
fn render(
f: &mut fmt::Formatter<'_>, module: &CompiledModule, depth: usize, sub_index: Option<usize>,
) -> fmt::Result {
// 子模块头:序号 + 全局 flat_id + 函数名(嵌套函数体调试入口)。
if let Some(i) = sub_index {
let name = module.function_name.as_deref().unwrap_or("");
writeln!(f, "\n; sub_module[{i}] (flat_id={flat_id}, \"{name}\"):", flat_id = module.flat_id)?;
}
// 头部元信息(顶层 2 空格缩进,子模块 4 空格)。
let p1 = if depth == 0 { "; " } else { "; " };
let p2 = if depth == 0 { "; " } else { "; " };
writeln!(f, "{p1}n_registers = {}", module.n_registers)?;
writeln!(f, "{p1}constants:")?;
for (i, c) in module.constants.iter().enumerate() {
writeln!(f, "{p2}[{i}] = {c:?}")?;
}
writeln!(f)?;
writeln!(f, "{p1}upvalue_captures: {:?}", module.upvalue_captures)?;
writeln!(f)?;
// 指令行:逐指令按 ext 字数推进,扩展字并入本行。
let indent = " ".repeat(depth + 1);
let mut offset = 0usize;
while offset < module.bytecode.len() {
let instr = module.bytecode[offset];
let op = opcode::opcode(instr);
write!(f, "{indent}{offset:04} {op}")?;
render_operands(f, op, instr, &module.bytecode, offset)?;
writeln!(f)?;
offset += 1 + opcode::ext_word_count(&module.bytecode, offset);
}
// 递归渲染子模块(嵌套函数体)。
for (i, sub) in module.sub_modules.iter().enumerate() {
Self::render(f, sub, depth + 1, Some(i))?;
}
Ok(())
}
}
/// 指令操作数渲染:按 opcode 语义把 rd/a/b/imm16/ext 字渲染为可读文本。
///
/// 常量池下标族渲染 `const[N]`,upvalue 下标族 `uv[N]`,闭包模块下标
/// `module[N]`,跳转族渲染相对偏移(单位 = 指令字,含 ext 字);ext 字并入
/// 本行。ext 字越界回退 0(Display 面不 panic)。
fn render_operands(
f: &mut fmt::Formatter<'_>, op: OpCode, instr: opcode::Instr, bytecode: &[opcode::Instr], offset: usize,
) -> fmt::Result {
let rd = opcode::rd(instr);
let a = opcode::a(instr);
let b = opcode::b(instr);
// ext 字安全读取(越界回退 0)。
let ext = |i: usize| bytecode.get(offset + 1 + i).copied().unwrap_or(0);
match op {
// 跳转族:offset16 相对偏移(单位 = 指令字,含 ext 字)。
OpCode::JMP | OpCode::TRY_BEGIN | OpCode::TRY_FINALLY_BEGIN => {
write!(f, " +{} (rel)", opcode::offset16(instr))
}
OpCode::JMP_IF_FALSE | OpCode::JMP_IF_TRUE | OpCode::JMP_IF_NULLISH | OpCode::BREAK | OpCode::CONTINUE => {
write!(f, " r{rd}, +{} (rel)", opcode::offset16(instr))
}
// imm16 常量池/下标族。
OpCode::LOAD_CONST | OpCode::LOAD_GLOBAL | OpCode::LOAD_GLOBAL_TYPEOF => {
write!(f, " r{rd}, const[{}]", opcode::imm16(instr))
}
OpCode::LOAD_UPVALUE => write!(f, " r{rd}, uv[{}]", opcode::imm16(instr)),
OpCode::CREATE_CLOSURE => write!(f, " r{rd}, module[{}]", opcode::imm16(instr)),
OpCode::STORE_UPVALUE => write!(f, " r{a}, uv[{b}]"),
// 单 ext 字族。
OpCode::SPILL | OpCode::UNSPILL => write!(f, " r{rd}, slot[{}]", ext(0)),
OpCode::CALL | OpCode::CALL_NATIVE | OpCode::NEW_EXPRESSION => {
write!(f, " r{rd}, r{a}, r{b}, nargs={}", ext(0) & 0xFF)
}
OpCode::SUPER_CALL => write!(f, " r{rd}, r{a}, nargs={}", ext(0) & 0xFF),
OpCode::DEFINE_ACCESSOR => write!(f, " r{rd}, r{a}, r{b}, const[{}]", ext(0)),
OpCode::DEFINE_ACCESSOR_DYNAMIC => write!(f, " r{rd}, r{a}, r{b}, key=r{}", ext(0) & 0x7FFF_FFFF),
OpCode::DEFINE_PROP_ATTRS => write!(f, " r{rd}, r{a}, r{b}, attrs={:#x}", ext(0)),
OpCode::DEFINE_GLOBAL_PROP_C | OpCode::DEFINE_GLOBAL_PROP_C_IF_ABSENT => {
write!(f, " r{a}, const[{}]", ext(0))
}
OpCode::DELETE_GLOBAL_PROP_C => write!(f, " r{rd}, r{a}, const[{}]", ext(0)),
OpCode::DELETE_PROP_STATIC => write!(f, " r{rd}, r{a}, const[{}]", ext(0)),
OpCode::REST_OBJECT => write!(f, " r{rd}, r{a}, r{b}, excl=const[{}]", ext(0)),
OpCode::INIT_PRIVATE => write!(f, " r{rd}, r{a}, r{b}, method={}", ext(0)),
// 双 ext 字族。
OpCode::DEFINE_ACCESSOR_ATTRS => {
write!(f, " r{rd}, r{a}, r{b}, const[{}], attrs={:#x}", ext(0), ext(1))
}
OpCode::DEFINE_ACCESSOR_ATTRS_DYNAMIC => {
write!(f, " r{rd}, r{a}, r{b}, key=r{}, attrs={:#x}", ext(0) & 0x7FFF_FFFF, ext(1))
}
OpCode::GET_PRIVATE | OpCode::SET_PRIVATE | OpCode::PRIVATE_BRAND_IN => {
write!(f, " r{rd}, r{a}, r{b}, brand=r{}, id={}", ext(0), ext(1))
}
// IC 族:8 个多态槽扩展字。
_ if op.has_ic_ext_words() => write!(f, " r{rd}, r{a}, r{b}, ic x{}", opcode::IC_EXT_WORDS),
// 变长 ext 族。
OpCode::CALL_SPREAD | OpCode::NEW_EXPRESSION_SPREAD | OpCode::SUPER_CALL_SPREAD => {
// 首字 = nstatic | (nspread<<8);实参字:静态 = 寄存器号,spread 源带高位标记。
let header = ext(0);
let n = ((header & 0xFF) + ((header >> 8) & 0xFF)) as usize;
write!(f, " r{rd}, r{a}, r{b}, args=[")?;
for i in 0..n {
if i > 0 {
write!(f, ", ")?;
}
let w = ext(i + 1);
if w & 0x8000_0000 != 0 {
write!(f, "...r{}", w & 0x7FFF_FFFF)?;
} else {
write!(f, "r{}", w)?;
}
}
write!(f, "]")
}
OpCode::TEMPLATE_STR => {
// 首字 = (segment_count<<16) | len_hint;段字:高位标记 = 表达式寄存器,
// 否则常量池下标。
let header = ext(0);
let n = ((header >> 16) & 0xFFFF) as usize;
write!(f, " r{rd}, segs=[")?;
for i in 0..n {
if i > 0 {
write!(f, ", ")?;
}
let w = ext(i + 1);
if w & 0x8000_0000 != 0 {
write!(f, "r{}", w & 0x7FFF_FFFF)?;
} else {
write!(f, "c{}", w & 0x7FFF_FFFF)?;
}
}
write!(f, "]")
}
OpCode::GET_TEMPLATE_OBJECT => {
// ext[0]=quasis 段数 n,随后 2n 个交错 cooked/raw 字,末尾 site 序号。
let n = ext(0) as usize;
write!(f, " r{rd}, {n} quasis, site={}", ext(1 + 2 * n))
}
OpCode::CONCAT_N => {
// ext[0]=n=操作数总数,其余 n-1 字为操作数寄存器。
let n = ext(0) as usize;
write!(f, " r{rd}, r{a}, ops=[")?;
for i in 0..n.saturating_sub(1) {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "r{}", ext(i + 1) & 0x7FFF_FFFF)?;
}
write!(f, "]")
}
OpCode::NEW_OBJECT => {
// a 槽 = 属性数,ext = 每键常量池下标。
let n = a as usize;
write!(f, " r{rd}, {n} keys [")?;
for i in 0..n {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "const[{}]", ext(i))?;
}
write!(f, "]")
}
// 单操作数族。
OpCode::NEG => write!(f, " r{rd}, r{a}"),
OpCode::RETURN | OpCode::HALT | OpCode::NOP => write!(f, " r{rd}"),
_ => write!(f, " r{rd}, r{a}, r{b}"),
}
}
#[cfg(test)]
mod tests {
use super::*;
/// 手工构造反汇编夹具:顶层 5 条指令(NEW_OBJECT 1 字键表、CALL 1 ext 字、
/// IC_GET_PROP 8 ext 字),子模块 1 个(3 条指令,RETURN 带 2 个逃出计数 ext 字)。
fn fixture() -> CompiledModule {
let sub = CompiledModule {
function_name: Some("f".into()),
flat_id: 1,
n_registers: 2,
constants: vec![Constant::Int(42)],
bytecode: Arc::from([
opcode::encode(OpCode::LOAD_CONST, 1, 0, 0),
opcode::encode(OpCode::RETURN, 1, 0, 0),
0, // RETURN 迭代器打包 ext 字
0, // RETURN dispose_count ext 字
opcode::encode(OpCode::HALT, 0, 0, 0),
]),
..Default::default()
};
let mut m = CompiledModule::new();
m.n_registers = 4;
m.constants = vec![Constant::Int(1), Constant::String("a".into())];
m.bytecode = Arc::from([
opcode::encode(OpCode::LOAD_CONST, 1, 0, 0),
opcode::encode(OpCode::NEW_OBJECT, 2, 1, 0),
1, // NEW_OBJECT 键表:const[1]
opcode::encode(OpCode::CALL, 3, 0, 1),
1, // CALL ext:nargs=1
opcode::encode(OpCode::IC_GET_PROP, 0, 2, 3),
0xAAAA_AAAA,
0xBBBB_BBBB,
0xCCCC_CCCC,
0xDDDD_DDDD,
0xEEEE_EEEE,
0xFFFF_FFFF,
0x1111_1111,
0x2222_2222,
opcode::encode(OpCode::HALT, 0, 0, 0),
]);
m.sub_modules = vec![Arc::new(sub)];
m
}
#[test]
fn disassembly_ext_words_merge_into_instruction_lines() {
let text = fixture().to_string();
let lines: Vec<&str> = text.lines().collect();
// 指令行数 = 真实指令数(顶层 5 + 子模块 3),ext 字不单独成行。
let instr_lines = lines
.iter()
.filter(|l| l.trim_start().chars().next().is_some_and(|c| c.is_ascii_digit()));
assert_eq!(instr_lines.count(), 8, "指令行数 = 真实指令数\n{text}");
// 逐行形态:offset 列 = 字序号(与 VM pc 同单位),操作数按语义渲染。
let expected = [
" 0000 LOAD_CONST r1, const[0]",
" 0001 NEW_OBJECT r2, 1 keys [const[1]]",
" 0003 CALL r3, r0, r1, nargs=1",
" 0005 IC_GET_PROP r0, r2, r3, ic x8",
" 0014 HALT r0",
" 0000 LOAD_CONST r1, const[0]",
" 0001 RETURN r1",
" 0004 HALT r0",
];
for line in &expected {
assert!(lines.contains(line), "missing line: {line}\n{text}");
}
// 子模块头:序号 + flat_id + 函数名。
assert!(lines.contains(&"; sub_module[0] (flat_id=1, \"f\"):"));
}
#[test]
fn disassembly_imm16_and_ext_operand_rendering() {
let mut m = CompiledModule::new();
m.constants = vec![Constant::String("x".into())];
m.bytecode = Arc::from([
opcode::encode(OpCode::LOAD_GLOBAL, 1, 0, 0),
opcode::encode(OpCode::CREATE_CLOSURE, 2, 0, 0),
opcode::encode(OpCode::DEFINE_GLOBAL_PROP_C, 0, 1, 0),
3, // ext:键常量池下标
opcode::encode(OpCode::JMP_IF_FALSE, 1, 12, 0),
]);
let text = m.to_string();
let lines: Vec<&str> = text.lines().collect();
assert!(lines.contains(&" 0000 LOAD_GLOBAL r1, const[0]"));
assert!(lines.contains(&" 0001 CREATE_CLOSURE r2, module[0]"));
assert!(lines.contains(&" 0002 DEFINE_GLOBAL_PROP_C r1, const[3]"));
assert!(lines.contains(&" 0004 JMP_IF_FALSE r1, +12 (rel)"));
}
}