diff --git a/crates/oxide_bytecode/src/opcode.rs b/crates/oxide_bytecode/src/opcode.rs index 17c72ad..5eb5bdb 100644 --- a/crates/oxide_bytecode/src/opcode.rs +++ b/crates/oxide_bytecode/src/opcode.rs @@ -1,20 +1,83 @@ //! 字节码操作码表与指令编解码。 //! -//! [`OpCode`] 由 `define_opcodes!` 宏从单张表生成;[`Instr`] 是 4 字节指令 -//! (opcode + rd + a + b,imm16/offset16 复用 a、b 两字节)。本模块提供 -//! 编译器发射(`encode*`)与 VM 解码(`opcode` / `rd` / `a` / `b` 等)全套函数。 +//! [`OpCode`] 由 `define_opcodes!` 宏从单张表生成(每行含语义字段 +//! def/uses/pure/jump/term/ic);[`Instr`] 是 4 字节指令(opcode + rd + a + b, +//! imm16/offset16 复用 a、b 两字节)。本模块提供编译器发射(`encode*`)与 VM +//! 解码(`opcode` / `rd` / `a` / `b` 等)全套函数。 use std::fmt; -/// 从单张表生成 [`OpCode`] 枚举及其 `TryFrom`、`Display` 实现。 +/// 操作数槽位:指令 rd/a/b 三槽之一。 +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum Slot { + /// 目标寄存器槽。 + Rd, + /// 第一操作数槽。 + A, + /// 第二操作数槽。 + B, +} + +/// 槽位规范:声明指令如何读写寄存器。解析器在 `oxide_ir::contract`。 /// -/// 每行 `VARIANT = 0xXX => "DISPLAY"` 同时提供枚举判别值、`TryFrom` 匹配分支 -/// 与 `Display` 名称三份信息,保证三表永不漂移;新增操作码只需加一行。 +/// # 语义约定 +/// - `Slot(Rd|A|B)`:读/写对应操作数槽;Const/Imm/Label 非寄存器则跳过; +/// None→0、This→254、NewTarget→255 由操作数层 reg_of 映射(不进表)。 +/// - `Reg0`:常量寄存器 0(CALL 隐式写、HALT 隐式读)。 +/// - `Range(Slot)`:从指定槽起连续 nargs 个寄存器,nargs=ext[0](调用实参区)。 +/// - `SpreadArgs`:ext[1..] 每个字 `& 0x7FFF_FFFF` 是实参寄存器(spread 源同低 31 位)。 +/// - `TemplateExprs`:TEMPLATE_STR 的 ext[1..],`seg>>31==1` 时低 8 位是表达式寄存器。 +/// - `BrandReg`:ext[0] 是 brand 对象寄存器,0 表示跳过检查(不产生 use)。 +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum SlotSpec { + /// 读写对应操作数槽。 + Slot(Slot), + /// 常量寄存器 0。 + Reg0, + /// 从指定槽起连续 nargs 个寄存器(nargs=ext[0])。 + Range(Slot), + /// spread 调用系 ext[1..] 的有序实参字。 + SpreadArgs, + /// TEMPLATE_STR 的 ext[1..] 表达式寄存器。 + TemplateExprs, + /// ext[0] 的 brand 对象寄存器(0 跳过检查)。 + BrandReg, +} + +/// 单张语义表行:一个 opcode 的 def/uses/pure/跳转/终结/IC 扩展字声明。 +/// +/// 字段语义与各消费方历史硬编码集合一致:`is_jump` = lower.rs 跳转族(label +/// 回填),`is_terminator` = CFG 块尾终结,`ic_ext` = VM 的 IC 扩展字。`pure` +/// 是静态可删判定,LOAD_VAR 的上下文例外留在 `oxide_ir::contract::is_pure`。 +pub struct OpSemantics { + /// 写入的寄存器(恒为单个,无 Range)。 + pub def: Option, + /// 读取的寄存器(按序,序即 use_regs 输出序)。 + pub uses: &'static [SlotSpec], + /// 静态可删判定(LOAD_VAR 例外在 oxide_ir 侧)。 + pub pure: bool, + /// 带 Label 槽、需偏移回填(= lower.rs is_jump_op)。 + pub is_jump: bool, + /// CFG 块尾终结(= cfg is_terminator)。 + pub is_terminator: bool, + /// 3 个 IC 扩展字(= has_ic_ext_words)。 + pub ic_ext: bool, +} + +/// 从单张表生成 [`OpCode`] 枚举、`TryFrom`、`Display` 与语义访问器。 +/// +/// 每行同时提供枚举判别值、`TryFrom` 分支、`Display` 名称与语义字段 +/// (def/uses/pure/jump/term/ic)七份信息,保证多表永不漂移;新增操作码只需 +/// 加一行。`semantics()` 的 match 无 `_` 臂——漏填语义即编译错误。 /// /// # 注意事项 /// - 分组注释(`// ── 算术 ──`)在宏展开前被词法器剥离,可自由插入行间。 macro_rules! define_opcodes { - ( $( $name:ident = $val:literal => $disp:literal ),+ $(,)? ) => { + ( $( + $name:ident = $val:literal => $disp:literal, + def = $def:expr, uses = [$($u:expr),*], + pure = $pure:literal, jump = $jump:literal, term = $term:literal, ic = $ic:literal + ),+ $(,)? ) => { /// 寄存器字节码虚拟机的操作码。 /// /// 按 16 个一组组织便于阅读。已实现的操作码在编译器中有发射支持; @@ -45,230 +108,532 @@ macro_rules! define_opcodes { write!(f, "{name}") } } + + impl OpCode { + /// 单张语义表访问器。match 无 `_` 臂:新 opcode 漏填语义即编译错误。 + /// + /// # 注意事项 + /// - 返回 `&'static`:match 臂内 `&OpSemantics { .. }` 是常量表达式, + /// 由常量提升保证零运行时开销。 + pub fn semantics(&self) -> &'static OpSemantics { + match self { + $( OpCode::$name => &OpSemantics { + def: $def, + uses: &[$($u),*], + pure: $pure, + is_jump: $jump, + is_terminator: $term, + ic_ext: $ic, + }, )+ + } + } + + /// 便捷访问器:跳转族(label 偏移回填)。 + pub fn is_jump(&self) -> bool { + self.semantics().is_jump + } + + /// 便捷访问器:CFG 块尾终结。 + pub fn is_terminator(&self) -> bool { + self.semantics().is_terminator + } + + /// 便捷访问器:IC 扩展字。 + pub fn has_ic_ext_words(&self) -> bool { + self.semantics().ic_ext + } + } }; } define_opcodes! { // ── Arithmetic (0x00-0x0F) ── ADD = 0x00 => "ADD", + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::A), SlotSpec::Slot(Slot::B)], + pure = true, jump = false, term = false, ic = false, SUB = 0x01 => "SUB", + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::A), SlotSpec::Slot(Slot::B)], + pure = true, jump = false, term = false, ic = false, MUL = 0x02 => "MUL", + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::A), SlotSpec::Slot(Slot::B)], + pure = true, jump = false, term = false, ic = false, DIV = 0x03 => "DIV", + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::A), SlotSpec::Slot(Slot::B)], + pure = true, jump = false, term = false, ic = false, MOD = 0x04 => "MOD", + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::A), SlotSpec::Slot(Slot::B)], + pure = true, jump = false, term = false, ic = false, NEG = 0x05 => "NEG", + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::A)], + pure = true, jump = false, term = false, ic = false, COMPOUND_ADD = 0x06 => "COMPOUND_ADD", + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::Rd), SlotSpec::Slot(Slot::A)], + pure = false, jump = false, term = false, ic = false, COMPOUND_SUB = 0x07 => "COMPOUND_SUB", + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::Rd), SlotSpec::Slot(Slot::A)], + pure = false, jump = false, term = false, ic = false, COMPOUND_MUL = 0x08 => "COMPOUND_MUL", + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::Rd), SlotSpec::Slot(Slot::A)], + pure = false, jump = false, term = false, ic = false, COMPOUND_DIV = 0x09 => "COMPOUND_DIV", + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::Rd), SlotSpec::Slot(Slot::A)], + pure = false, jump = false, term = false, ic = false, COMPOUND_MOD = 0x0A => "COMPOUND_MOD", + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::Rd), SlotSpec::Slot(Slot::A)], + pure = false, jump = false, term = false, ic = false, COMPOUND_EXP = 0x0B => "COMPOUND_EXP", - MOV = 0x0C => "MOV", // rd=dst, a=src(寄存器复制,区间拆分搬值) - SPILL = 0x0D => "SPILL", // rd=src, ext=[slot u16](寄存器值写 VM spill 栈) - UNSPILL = 0x0E => "UNSPILL", // rd=dst, ext=[slot u16](从 VM spill 栈恢复寄存器) + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::Rd), SlotSpec::Slot(Slot::A)], + pure = false, jump = false, term = false, ic = false, + MOV = 0x0C => "MOV", // rd=dst, a=src(寄存器复制,区间拆分搬值) + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::A)], + pure = true, jump = false, term = false, ic = false, + SPILL = 0x0D => "SPILL", // rd=src, ext=[slot u16](寄存器值写 VM spill 栈) + def = None, uses = [SlotSpec::Slot(Slot::Rd)], + pure = false, jump = false, term = false, ic = false, + UNSPILL = 0x0E => "UNSPILL", // rd=dst, ext=[slot u16](从 VM spill 栈恢复寄存器) + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [], + pure = false, jump = false, term = false, ic = false, SPREAD_OBJECT = 0x0F => "SPREAD_OBJECT", // rd=目标对象, a=源(对象字面量 ... 展开,原地写目标) + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::Rd), SlotSpec::Slot(Slot::A)], + pure = false, jump = false, term = false, ic = false, // ── 比较 (0x10-0x1F) ── EQ = 0x10 => "EQ", + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::A), SlotSpec::Slot(Slot::B)], + pure = true, jump = false, term = false, ic = false, NEQ = 0x11 => "NEQ", + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::A), SlotSpec::Slot(Slot::B)], + pure = true, jump = false, term = false, ic = false, LT = 0x12 => "LT", + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::A), SlotSpec::Slot(Slot::B)], + pure = true, jump = false, term = false, ic = false, GT = 0x13 => "GT", + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::A), SlotSpec::Slot(Slot::B)], + pure = true, jump = false, term = false, ic = false, LTE = 0x14 => "LTE", + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::A), SlotSpec::Slot(Slot::B)], + pure = true, jump = false, term = false, ic = false, GTE = 0x15 => "GTE", + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::A), SlotSpec::Slot(Slot::B)], + pure = true, jump = false, term = false, ic = false, IN = 0x16 => "IN", + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::A), SlotSpec::Slot(Slot::B)], + pure = false, jump = false, term = false, ic = false, NOT = 0x17 => "NOT", + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::A)], + pure = true, jump = false, term = false, ic = false, AND = 0x18 => "AND", + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::A), SlotSpec::Slot(Slot::B)], + pure = true, jump = false, term = false, ic = false, OR = 0x19 => "OR", + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::A), SlotSpec::Slot(Slot::B)], + pure = true, jump = false, term = false, ic = false, STRICT_EQ = 0x1A => "STRICT_EQ", + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::A), SlotSpec::Slot(Slot::B)], + pure = true, jump = false, term = false, ic = false, STRICT_NEQ = 0x1C => "STRICT_NEQ", + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::A), SlotSpec::Slot(Slot::B)], + pure = true, jump = false, term = false, ic = false, UNARY_PLUS = 0x1D => "UNARY_PLUS", + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::A)], + pure = true, jump = false, term = false, ic = false, // ── 控制流 (0x1E-0x2F) ── BREAK = 0x1E => "BREAK", + def = None, uses = [], + pure = false, jump = true, term = true, ic = false, CONTINUE = 0x1F => "CONTINUE", + def = None, uses = [], + pure = false, jump = true, term = true, ic = false, JMP = 0x20 => "JMP", + def = None, uses = [], + pure = false, jump = true, term = true, ic = false, JMP_IF_FALSE = 0x21 => "JMP_IF_FALSE", + def = None, uses = [SlotSpec::Slot(Slot::Rd)], + pure = false, jump = true, term = true, ic = false, JMP_IF_TRUE = 0x22 => "JMP_IF_TRUE", + def = None, uses = [SlotSpec::Slot(Slot::Rd)], + pure = false, jump = true, term = true, ic = false, FOR_OF_INIT = 0x23 => "FOR_OF_INIT", + def = None, uses = [SlotSpec::Slot(Slot::A)], + pure = false, jump = false, term = false, ic = false, FOR_OF_NEXT = 0x24 => "FOR_OF_NEXT", + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [], + pure = false, jump = false, term = false, ic = false, // ── 更新 (0x25-0x28) ── INC_PRE = 0x25 => "INC_PRE", + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::Rd)], + pure = false, jump = false, term = false, ic = false, INC_POST = 0x26 => "INC_POST", + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::Rd)], + pure = false, jump = false, term = false, ic = false, DEC_PRE = 0x27 => "DEC_PRE", + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::Rd)], + pure = false, jump = false, term = false, ic = false, DEC_POST = 0x28 => "DEC_POST", + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::Rd)], + pure = false, jump = false, term = false, ic = false, FOR_IN_INIT = 0x29 => "FOR_IN_INIT", + def = None, uses = [SlotSpec::Slot(Slot::A)], + pure = false, jump = false, term = false, ic = false, FOR_IN_NEXT = 0x2A => "FOR_IN_NEXT", + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [], + pure = false, jump = false, term = false, ic = false, FOR_IN_DONE = 0x2B => "FOR_IN_DONE", - SWITCH_TABLE = 0x2C => "SWITCH_TABLE", + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [], + pure = false, jump = false, term = false, ic = false, + SWITCH_TABLE = 0x2C => "SWITCH_TABLE", // 占位:emit 不产,按 catch-all 保守 def + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [], + pure = false, jump = false, term = false, ic = false, FOR_IN_CLEANUP = 0x2D => "FOR_IN_CLEANUP", + def = None, uses = [], + pure = false, jump = false, term = false, ic = false, // ── 异常 (0x2E-0x2F, 0x33-0x35) ── THROW = 0x2E => "THROW", + def = None, uses = [SlotSpec::Slot(Slot::Rd)], + pure = false, jump = false, term = true, ic = false, TRY_BEGIN = 0x2F => "TRY_BEGIN", + def = None, uses = [], + pure = false, jump = true, term = false, ic = false, TRY_END = 0x33 => "TRY_END", + def = None, uses = [], + pure = false, jump = false, term = false, ic = false, TRY_FINALLY_BEGIN = 0x34 => "TRY_FINALLY_BEGIN", + def = None, uses = [], + pure = false, jump = true, term = false, ic = false, TRY_FINALLY_END = 0x35 => "TRY_FINALLY_END", + def = None, uses = [], + pure = false, jump = false, term = false, ic = false, FOR_OF_DONE = 0x36 => "FOR_OF_DONE", + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [], + pure = false, jump = false, term = false, ic = false, FOR_OF_CLOSE = 0x37 => "FOR_OF_CLOSE", + def = None, uses = [], + pure = false, jump = false, term = false, ic = false, // ── 模板字符串 (0x38) ── TEMPLATE_STR = 0x38 => "TEMPLATE_STR", + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::TemplateExprs], + pure = true, jump = false, term = false, ic = false, // ── 小语言特性 (0x39-0x3B) ── DELETE_PROP_STATIC = 0x39 => "DELETE_PROP_STATIC", + def = None, uses = [SlotSpec::Slot(Slot::Rd)], + pure = false, jump = false, term = false, ic = false, DELETE_PROP_DYNAMIC = 0x3A => "DELETE_PROP_DYNAMIC", + def = None, uses = [SlotSpec::Slot(Slot::Rd), SlotSpec::Slot(Slot::B)], + pure = false, jump = false, term = false, ic = false, INSTANCEOF = 0x3B => "INSTANCEOF", + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::A), SlotSpec::Slot(Slot::B)], + pure = false, jump = false, term = false, ic = false, MAKE_CELL = 0x3C => "MAKE_CELL", + def = None, uses = [SlotSpec::Slot(Slot::Rd)], + pure = false, jump = false, term = false, ic = false, CELL_GET = 0x3D => "CELL_GET", + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::A)], + pure = true, jump = false, term = false, ic = false, REST_OBJECT = 0x3E => "REST_OBJECT", + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::A), SlotSpec::Slot(Slot::B)], + pure = false, jump = false, term = false, ic = false, CELL_SET = 0x3F => "CELL_SET", + def = None, uses = [SlotSpec::Slot(Slot::A)], + pure = false, jump = false, term = false, ic = false, // ── 变量 (0x30-0x32) ── LOAD_VAR = 0x30 => "LOAD_VAR", + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::A)], + pure = true, jump = false, term = false, ic = false, STORE_VAR = 0x31 => "STORE_VAR", + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::A)], + pure = false, jump = false, term = false, ic = false, LOAD_CONST = 0x32 => "LOAD_CONST", + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [], + pure = true, jump = false, term = false, ic = false, // ── 调用 (0x40-0x4F) ── - CALL = 0x40 => "CALL", + CALL = 0x40 => "CALL", // 结果隐式写 reg 0;rd=callee, a=this, b=首参, ext[0]=nargs + def = Some(SlotSpec::Reg0), uses = [SlotSpec::Slot(Slot::Rd), SlotSpec::Slot(Slot::A), SlotSpec::Range(Slot::B)], + pure = false, jump = false, term = false, ic = false, RETURN = 0x41 => "RETURN", + def = None, uses = [SlotSpec::Slot(Slot::Rd)], + pure = false, jump = false, term = true, ic = false, CALL_NATIVE = 0x42 => "CALL_NATIVE", - NEW_EXPRESSION = 0x43 => "NEW_EXPRESSION", - SUPER_CALL = 0x44 => "SUPER_CALL", + def = Some(SlotSpec::Reg0), uses = [SlotSpec::Slot(Slot::Rd), SlotSpec::Slot(Slot::A), SlotSpec::Range(Slot::B)], + pure = false, jump = false, term = false, ic = false, + NEW_EXPRESSION = 0x43 => "NEW_EXPRESSION", // a=ctor, b..b+nargs + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::A), SlotSpec::Range(Slot::B)], + pure = false, jump = false, term = false, ic = false, + SUPER_CALL = 0x44 => "SUPER_CALL", // a..a+nargs,无 callee/this 槽 + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Range(Slot::A)], + pure = false, jump = false, term = false, ic = false, SUPER_GET_PROP = 0x45 => "SUPER_GET_PROP", + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::A), SlotSpec::Slot(Slot::B)], + pure = false, jump = false, term = false, ic = false, SUPER_STATIC_GET_PROP = 0x46 => "SUPER_STATIC_GET_PROP", + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::A), SlotSpec::Slot(Slot::B)], + pure = false, jump = false, term = false, ic = false, SET_HOME_OBJECT = 0x47 => "SET_HOME_OBJECT", + def = None, uses = [SlotSpec::Slot(Slot::Rd), SlotSpec::Slot(Slot::A)], + pure = false, jump = false, term = false, ic = false, DEFINE_ACCESSOR = 0x48 => "DEFINE_ACCESSOR", + def = None, uses = [SlotSpec::Slot(Slot::Rd), SlotSpec::Slot(Slot::A), SlotSpec::Slot(Slot::B)], + pure = false, jump = false, term = false, ic = false, LOAD_UPVALUE = 0x49 => "LOAD_UPVALUE", + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [], + pure = true, jump = false, term = false, ic = false, CREATE_CLOSURE = 0x4A => "CREATE_CLOSURE", + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [], + pure = true, jump = false, term = false, ic = false, CREATE_REGEXP = 0x4B => "CREATE_REGEXP", + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::A), SlotSpec::Slot(Slot::B)], + pure = false, jump = false, term = false, ic = false, STORE_UPVALUE = 0x4C => "STORE_UPVALUE", - CALL_SPREAD = 0x4D => "CALL_SPREAD", + def = None, uses = [SlotSpec::Slot(Slot::A)], + pure = false, jump = false, term = false, ic = false, + CALL_SPREAD = 0x4D => "CALL_SPREAD", // 结果经 reg 0;ext[1..] 有序实参字 + def = Some(SlotSpec::Reg0), uses = [SlotSpec::Slot(Slot::Rd), SlotSpec::Slot(Slot::A), SlotSpec::SpreadArgs], + pure = false, jump = false, term = false, ic = false, NEW_EXPRESSION_SPREAD = 0x4E => "NEW_EXPRESSION_SPREAD", + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::A), SlotSpec::SpreadArgs], + pure = false, jump = false, term = false, ic = false, SUPER_CALL_SPREAD = 0x4F => "SUPER_CALL_SPREAD", + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::SpreadArgs], + pure = false, jump = false, term = false, ic = false, // ── Object Property (0x50-0x5F) ── - IC_GET_PROP = 0x50 => "IC_GET_PROP", + IC_GET_PROP = 0x50 => "IC_GET_PROP", // a 槽既是对象 use 又写回结果,rd 忽略 + def = Some(SlotSpec::Slot(Slot::A)), uses = [SlotSpec::Slot(Slot::A), SlotSpec::Slot(Slot::B)], + pure = false, jump = false, term = false, ic = true, IC_SET_PROP = 0x51 => "IC_SET_PROP", - GET_PROP = 0x52 => "GET_PROP", - GET_PROP_DYNAMIC = 0x53 => "GET_PROP_DYNAMIC", + def = None, uses = [SlotSpec::Slot(Slot::Rd), SlotSpec::Slot(Slot::A), SlotSpec::Slot(Slot::B)], + pure = false, jump = false, term = false, ic = true, + GET_PROP = 0x52 => "GET_PROP", // 结果写 a 槽,rd=obj 是 use + def = Some(SlotSpec::Slot(Slot::A)), uses = [SlotSpec::Slot(Slot::Rd), SlotSpec::Slot(Slot::B)], + pure = false, jump = false, term = false, ic = false, + GET_PROP_DYNAMIC = 0x53 => "GET_PROP_DYNAMIC", // 结果写 b 槽 + def = Some(SlotSpec::Slot(Slot::B)), uses = [SlotSpec::Slot(Slot::Rd), SlotSpec::Slot(Slot::A)], + pure = false, jump = false, term = false, ic = false, SET_PROP = 0x54 => "SET_PROP", + def = None, uses = [SlotSpec::Slot(Slot::Rd), SlotSpec::Slot(Slot::A), SlotSpec::Slot(Slot::B)], + pure = false, jump = false, term = false, ic = false, SET_PROP_DYNAMIC = 0x55 => "SET_PROP_DYNAMIC", + def = None, uses = [SlotSpec::Slot(Slot::Rd), SlotSpec::Slot(Slot::A), SlotSpec::Slot(Slot::B)], + pure = false, jump = false, term = false, ic = false, NEW_OBJECT = 0x56 => "NEW_OBJECT", + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [], + pure = true, jump = false, term = false, ic = false, NEW_ARRAY = 0x57 => "NEW_ARRAY", + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [], + pure = true, jump = false, term = false, ic = false, SET_ELEM = 0x58 => "SET_ELEM", + def = None, uses = [SlotSpec::Slot(Slot::Rd), SlotSpec::Slot(Slot::A), SlotSpec::Slot(Slot::B)], + pure = false, jump = false, term = false, ic = false, // ── 成员更新 (0x59-0x62) ── - MEMBER_INC = 0x59 => "MEMBER_INC", + MEMBER_INC = 0x59 => "MEMBER_INC", // 结果写 a 槽(val 槽原地更新) + def = Some(SlotSpec::Slot(Slot::A)), uses = [SlotSpec::Slot(Slot::Rd), SlotSpec::Slot(Slot::B)], + pure = false, jump = false, term = false, ic = true, MEMBER_DEC = 0x5A => "MEMBER_DEC", - DYN_MEMBER_INC = 0x5B => "DYN_MEMBER_INC", + def = Some(SlotSpec::Slot(Slot::A)), uses = [SlotSpec::Slot(Slot::Rd), SlotSpec::Slot(Slot::B)], + pure = false, jump = false, term = false, ic = true, + DYN_MEMBER_INC = 0x5B => "DYN_MEMBER_INC", // 结果写 b 槽 + def = Some(SlotSpec::Slot(Slot::B)), uses = [SlotSpec::Slot(Slot::Rd), SlotSpec::Slot(Slot::A)], + pure = false, jump = false, term = false, ic = false, DYN_MEMBER_DEC = 0x5C => "DYN_MEMBER_DEC", + def = Some(SlotSpec::Slot(Slot::B)), uses = [SlotSpec::Slot(Slot::Rd), SlotSpec::Slot(Slot::A)], + pure = false, jump = false, term = false, ic = false, COMPOUND_MEMBER_ADD = 0x5D => "COMPOUND_MEMBER_ADD", + def = Some(SlotSpec::Slot(Slot::A)), uses = [SlotSpec::Slot(Slot::Rd), SlotSpec::Slot(Slot::A), SlotSpec::Slot(Slot::B)], + pure = false, jump = false, term = false, ic = true, COMPOUND_MEMBER_SUB = 0x5E => "COMPOUND_MEMBER_SUB", + def = Some(SlotSpec::Slot(Slot::A)), uses = [SlotSpec::Slot(Slot::Rd), SlotSpec::Slot(Slot::A), SlotSpec::Slot(Slot::B)], + pure = false, jump = false, term = false, ic = true, COMPOUND_MEMBER_MUL = 0x5F => "COMPOUND_MEMBER_MUL", + def = Some(SlotSpec::Slot(Slot::A)), uses = [SlotSpec::Slot(Slot::Rd), SlotSpec::Slot(Slot::A), SlotSpec::Slot(Slot::B)], + pure = false, jump = false, term = false, ic = true, COMPOUND_MEMBER_DIV = 0x60 => "COMPOUND_MEMBER_DIV", + def = Some(SlotSpec::Slot(Slot::A)), uses = [SlotSpec::Slot(Slot::Rd), SlotSpec::Slot(Slot::A), SlotSpec::Slot(Slot::B)], + pure = false, jump = false, term = false, ic = true, COMPOUND_MEMBER_MOD = 0x61 => "COMPOUND_MEMBER_MOD", + def = Some(SlotSpec::Slot(Slot::A)), uses = [SlotSpec::Slot(Slot::Rd), SlotSpec::Slot(Slot::A), SlotSpec::Slot(Slot::B)], + pure = false, jump = false, term = false, ic = true, COMPOUND_MEMBER_EXP = 0x62 => "COMPOUND_MEMBER_EXP", + def = Some(SlotSpec::Slot(Slot::A)), uses = [SlotSpec::Slot(Slot::Rd), SlotSpec::Slot(Slot::A), SlotSpec::Slot(Slot::B)], + pure = false, jump = false, term = false, ic = true, // ── 对象 (0x63) ── CREATE_ARGUMENTS = 0x63 => "CREATE_ARGUMENTS", + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [], + pure = false, jump = false, term = false, ic = false, // rest 参数数组:rd=目标寄存器,b=固定形参数(rest 之前的形参个数)。 CREATE_REST_ARRAY = 0x6E => "CREATE_REST_ARRAY", + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [], + pure = false, jump = false, term = false, ic = false, // ── define 语义属性写入 (0x6D, 0x6F) ── DEFINE_PROP = 0x6D => "DEFINE_PROP", + def = None, uses = [SlotSpec::Slot(Slot::Rd), SlotSpec::Slot(Slot::A), SlotSpec::Slot(Slot::B)], + pure = false, jump = false, term = false, ic = false, // 全局 var 绑定属性定义:rd=目标对象、a=值、b=键,数据属性可写/可枚举/不可配置 // (脚本顶层 var/function 声明同步到 globalThis 用,属性描述符与规范一致)。 DEFINE_GLOBAL_PROP = 0x6F => "DEFINE_GLOBAL_PROP", + def = None, uses = [SlotSpec::Slot(Slot::Rd), SlotSpec::Slot(Slot::A), SlotSpec::Slot(Slot::B)], + pure = false, jump = false, term = false, ic = false, // ── 成员复合赋值:位/移位 (0x64-0x69) ── COMPOUND_MEMBER_BIT_AND = 0x64 => "COMPOUND_MEMBER_BIT_AND", + def = Some(SlotSpec::Slot(Slot::A)), uses = [SlotSpec::Slot(Slot::Rd), SlotSpec::Slot(Slot::A), SlotSpec::Slot(Slot::B)], + pure = false, jump = false, term = false, ic = true, COMPOUND_MEMBER_BIT_OR = 0x65 => "COMPOUND_MEMBER_BIT_OR", + def = Some(SlotSpec::Slot(Slot::A)), uses = [SlotSpec::Slot(Slot::Rd), SlotSpec::Slot(Slot::A), SlotSpec::Slot(Slot::B)], + pure = false, jump = false, term = false, ic = true, COMPOUND_MEMBER_BIT_XOR = 0x66 => "COMPOUND_MEMBER_BIT_XOR", + def = Some(SlotSpec::Slot(Slot::A)), uses = [SlotSpec::Slot(Slot::Rd), SlotSpec::Slot(Slot::A), SlotSpec::Slot(Slot::B)], + pure = false, jump = false, term = false, ic = true, COMPOUND_MEMBER_SHL = 0x67 => "COMPOUND_MEMBER_SHL", + def = Some(SlotSpec::Slot(Slot::A)), uses = [SlotSpec::Slot(Slot::Rd), SlotSpec::Slot(Slot::A), SlotSpec::Slot(Slot::B)], + pure = false, jump = false, term = false, ic = true, COMPOUND_MEMBER_SHR = 0x68 => "COMPOUND_MEMBER_SHR", + def = Some(SlotSpec::Slot(Slot::A)), uses = [SlotSpec::Slot(Slot::Rd), SlotSpec::Slot(Slot::A), SlotSpec::Slot(Slot::B)], + pure = false, jump = false, term = false, ic = true, COMPOUND_MEMBER_USHR = 0x69 => "COMPOUND_MEMBER_USHR", + def = Some(SlotSpec::Slot(Slot::A)), uses = [SlotSpec::Slot(Slot::Rd), SlotSpec::Slot(Slot::A), SlotSpec::Slot(Slot::B)], + pure = false, jump = false, term = false, ic = true, // ── Profiling — 占位符 (0x6A-0x6F) ── - PROFILE_SHAPE = 0x6A => "PROFILE_SHAPE", + PROFILE_SHAPE = 0x6A => "PROFILE_SHAPE", // 占位:catch-all 保守 def + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [], + pure = false, jump = false, term = false, ic = false, PROFILE_BRANCH = 0x6B => "PROFILE_BRANCH", + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [], + pure = false, jump = false, term = false, ic = false, PROFILE_CALL = 0x6C => "PROFILE_CALL", + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [], + pure = false, jump = false, term = false, ic = false, // ── 并行 — 占位符 (0x70-0x75) ── FORK = 0x70 => "FORK", + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [], + pure = false, jump = false, term = false, ic = false, JOIN = 0x71 => "JOIN", - GET_PRIVATE = 0x72 => "GET_PRIVATE", + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [], + pure = false, jump = false, term = false, ic = false, + GET_PRIVATE = 0x72 => "GET_PRIVATE", // ext[0]=brand_reg,非 0 才产生 use + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::A), SlotSpec::Slot(Slot::B), SlotSpec::BrandReg], + pure = false, jump = false, term = false, ic = false, SET_PRIVATE = 0x73 => "SET_PRIVATE", + def = None, uses = [SlotSpec::Slot(Slot::Rd), SlotSpec::Slot(Slot::A), SlotSpec::Slot(Slot::B), SlotSpec::BrandReg], + pure = false, jump = false, term = false, ic = false, INIT_PRIVATE = 0x74 => "INIT_PRIVATE", + def = None, uses = [SlotSpec::Slot(Slot::Rd), SlotSpec::Slot(Slot::A), SlotSpec::Slot(Slot::B)], + pure = false, jump = false, term = false, ic = false, PRIVATE_BRAND_IN = 0x75 => "PRIVATE_BRAND_IN", + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::A), SlotSpec::Slot(Slot::B)], + pure = false, jump = false, term = false, ic = false, // ── 生成器 (0x76-0x78) ── YIELD = 0x76 => "YIELD", // rd=被让出的值(结果经 reg 0 交付,见 contract.rs) + def = Some(SlotSpec::Reg0), uses = [SlotSpec::Slot(Slot::Rd)], + pure = false, jump = false, term = false, ic = false, // 生成器 body 起点标记:调用时参数初始化完成后挂起于此,首次 next() 从这继续。 SUSPEND_BODY = 0x77 => "SUSPEND_BODY", + def = None, uses = [], + pure = false, jump = false, term = false, ic = false, // `yield*` 委托:rd=内层可迭代对象;委托完成值经 reg 0 交付(与 YIELD 同协议)。 YIELD_STAR = 0x78 => "YIELD_STAR", + def = Some(SlotSpec::Reg0), uses = [SlotSpec::Slot(Slot::Rd)], + pure = false, jump = false, term = false, ic = false, // `await`:rd=被等待的值(PromiseResolve 包装);挂起异步帧,恢复值经 reg 0 交付。 AWAIT = 0x79 => "AWAIT", + def = Some(SlotSpec::Reg0), uses = [SlotSpec::Slot(Slot::Rd)], + pure = false, jump = false, term = false, ic = false, // for-await-of 步进:INIT(a=可迭代值) 取异步迭代器;NEXT 调用迭代器 next(), // 结果写 rd(随后由 AWAIT 等待);DONE 读取 AWAIT 恢复值(a 槽)的 done 写 rd; // CLOSE 执行异步 IteratorClose(return() 结果 await 后继续)。 FOR_AWAIT_OF_INIT = 0x7A => "FOR_AWAIT_OF_INIT", + def = None, uses = [SlotSpec::Slot(Slot::A)], + pure = false, jump = false, term = false, ic = false, FOR_AWAIT_OF_NEXT = 0x7B => "FOR_AWAIT_OF_NEXT", + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [], + pure = false, jump = false, term = false, ic = false, FOR_AWAIT_OF_DONE = 0x7C => "FOR_AWAIT_OF_DONE", + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::A)], + pure = false, jump = false, term = false, ic = false, FOR_AWAIT_OF_CLOSE = 0x7D => "FOR_AWAIT_OF_CLOSE", + def = None, uses = [], + pure = false, jump = false, term = false, ic = false, // 无条件新建 cell 并替换 cell_stack[cell_idx],值为 regs[rd]——循环每迭代绑定 // 把当前值拷入新 cell,本迭代闭包捕获新 cell(旧闭包仍指向旧 cell)。 MAKE_CELL_FRESH = 0x7E => "MAKE_CELL_FRESH", + def = None, uses = [SlotSpec::Slot(Slot::Rd)], + pure = false, jump = false, term = false, ic = false, // ── 位运算 (0x80-0x8F) ── BIT_AND = 0x80 => "BIT_AND", + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::A), SlotSpec::Slot(Slot::B)], + pure = true, jump = false, term = false, ic = false, BIT_OR = 0x81 => "BIT_OR", + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::A), SlotSpec::Slot(Slot::B)], + pure = true, jump = false, term = false, ic = false, BIT_XOR = 0x82 => "BIT_XOR", + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::A), SlotSpec::Slot(Slot::B)], + pure = true, jump = false, term = false, ic = false, SHL = 0x83 => "SHL", + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::A), SlotSpec::Slot(Slot::B)], + pure = true, jump = false, term = false, ic = false, SHR = 0x84 => "SHR", + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::A), SlotSpec::Slot(Slot::B)], + pure = true, jump = false, term = false, ic = false, USHR = 0x85 => "USHR", + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::A), SlotSpec::Slot(Slot::B)], + pure = true, jump = false, term = false, ic = false, BIT_NOT = 0x86 => "BIT_NOT", - TO_OBJECT = 0x87 => "TO_OBJECT", + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::A)], + pure = true, jump = false, term = false, ic = false, + TO_OBJECT = 0x87 => "TO_OBJECT", // rd 原地转换(读且写) + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::Rd)], + pure = false, jump = false, term = false, ic = false, COMPOUND_AND = 0x88 => "COMPOUND_AND", + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::Rd), SlotSpec::Slot(Slot::A)], + pure = false, jump = false, term = false, ic = false, COMPOUND_OR = 0x89 => "COMPOUND_OR", + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::Rd), SlotSpec::Slot(Slot::A)], + pure = false, jump = false, term = false, ic = false, COMPOUND_XOR = 0x8A => "COMPOUND_XOR", + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::Rd), SlotSpec::Slot(Slot::A)], + pure = false, jump = false, term = false, ic = false, COMPOUND_SHL = 0x8B => "COMPOUND_SHL", + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::Rd), SlotSpec::Slot(Slot::A)], + pure = false, jump = false, term = false, ic = false, COMPOUND_SHR = 0x8C => "COMPOUND_SHR", + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::Rd), SlotSpec::Slot(Slot::A)], + pure = false, jump = false, term = false, ic = false, COMPOUND_USHR = 0x8D => "COMPOUND_USHR", + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::Rd), SlotSpec::Slot(Slot::A)], + pure = false, jump = false, term = false, ic = false, NULLISH = 0x8E => "NULLISH", + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::A), SlotSpec::Slot(Slot::B)], + pure = true, jump = false, term = false, ic = false, JMP_IF_NULLISH = 0x8F => "JMP_IF_NULLISH", + def = None, uses = [SlotSpec::Slot(Slot::Rd)], + pure = false, jump = true, term = true, ic = false, // ── 杂项 (0xF0-0xFF) ── - NOP = 0xF0 => "NOP", - HALT = 0xF1 => "HALT", + NOP = 0xF0 => "NOP", // 保持 def=Rd:catch-all 使 NOP(rd=None) 的 def_reg=Some(0) + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [], + pure = true, jump = false, term = false, ic = false, + HALT = 0xF1 => "HALT", // 隐式读 reg 0(顶层返回值) + def = None, uses = [SlotSpec::Reg0], + pure = false, jump = false, term = true, ic = false, TYPEOF = 0xF2 => "TYPEOF", + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::A)], + pure = true, jump = false, term = false, ic = false, VOID = 0xF3 => "VOID", -} - -impl OpCode { - /// 是否需要 IC 扩展字(inline cache 元数据跟随指令之后)。 - pub fn has_ic_ext_words(&self) -> bool { - matches!( - self, - OpCode::IC_GET_PROP - | OpCode::IC_SET_PROP - | OpCode::MEMBER_INC - | OpCode::MEMBER_DEC - | OpCode::COMPOUND_MEMBER_ADD - | OpCode::COMPOUND_MEMBER_SUB - | OpCode::COMPOUND_MEMBER_MUL - | OpCode::COMPOUND_MEMBER_DIV - | OpCode::COMPOUND_MEMBER_MOD - | OpCode::COMPOUND_MEMBER_EXP - | OpCode::COMPOUND_MEMBER_BIT_AND - | OpCode::COMPOUND_MEMBER_BIT_OR - | OpCode::COMPOUND_MEMBER_BIT_XOR - | OpCode::COMPOUND_MEMBER_SHL - | OpCode::COMPOUND_MEMBER_SHR - | OpCode::COMPOUND_MEMBER_USHR - ) - } + def = Some(SlotSpec::Slot(Slot::Rd)), uses = [], + pure = true, jump = false, term = false, ic = false, } /// 4 字节定长指令。 @@ -360,6 +725,11 @@ pub fn encode_try_finally_begin(offset: i16) -> Instr { mod tests { use super::*; + /// 遍历全部有效 opcode(枚举字节序)。 + fn all_opcodes() -> impl Iterator { + (0u8..=u8::MAX).filter_map(|b| OpCode::try_from(b).ok()) + } + #[test] fn opcode_table_is_byte_identical() { for byte in 0u8..=u8::MAX { @@ -388,11 +758,43 @@ mod tests { assert!(OpCode::try_from(0x1B).is_err()); assert!(OpCode::try_from(0xFF).is_err()); + } - let ic_count = (0u8..=u8::MAX) - .filter_map(|b| OpCode::try_from(b).ok()) - .filter(OpCode::has_ic_ext_words) - .count(); - assert_eq!(ic_count, 16); + /// 全 opcode 表遍历:jump/terminator/ic 三集合与 lower/cfg/vm 硬编码集合逐字节一致。 + #[test] + fn semantics_golden_sets() { + let jump_set: Vec = all_opcodes().filter(|op| op.is_jump()).map(|op| op as u8).collect(); + assert_eq!( + jump_set, + [0x1E, 0x1F, 0x20, 0x21, 0x22, 0x2F, 0x34, 0x8F], + "is_jump 集合(8 个跳转族,含 TRY_BEGIN/TRY_FINALLY_BEGIN label 回填)" + ); + + let term_set: Vec = all_opcodes().filter(|op| op.is_terminator()).map(|op| op as u8).collect(); + assert_eq!( + term_set, + [0x1E, 0x1F, 0x20, 0x21, 0x22, 0x2E, 0x41, 0x8F, 0xF1], + "is_terminator 集合(跳转族去 TRY_* 加 RETURN/HALT/THROW)" + ); + + let ic_set: Vec = all_opcodes() + .filter(|op| op.has_ic_ext_words()) + .map(|op| op as u8) + .collect(); + assert_eq!(ic_set.len(), 16, "ic_ext 恰 16 个"); + } + + /// 表驱动 ic_ext 与迁移前硬编码 16 集合逐项相等(旧表并存期的迁移校验)。 + #[test] + fn semantics_ic_ext_matches_legacy_list() { + let legacy = [ + 0x50, 0x51, 0x59, 0x5A, 0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x64, 0x65, 0x66, 0x67, 0x68, + 0x69, + ]; + let tbl: Vec = all_opcodes() + .filter(|op| op.has_ic_ext_words()) + .map(|op| op as u8) + .collect(); + assert_eq!(tbl, legacy); } } diff --git a/crates/oxide_cfg/src/lib.rs b/crates/oxide_cfg/src/lib.rs index 12d130b..f4bd2d8 100644 --- a/crates/oxide_cfg/src/lib.rs +++ b/crates/oxide_cfg/src/lib.rs @@ -68,18 +68,7 @@ impl Default for Cfg { /// 标记**(异常边起点,见 Pass 3),不是控制流终结——抄用 is_jump_op 会导致 try 体 /// 被切块、异常边爆炸。 fn is_terminator(op: OpCode) -> bool { - matches!( - op, - OpCode::JMP - | OpCode::BREAK - | OpCode::CONTINUE - | OpCode::JMP_IF_TRUE - | OpCode::JMP_IF_FALSE - | OpCode::JMP_IF_NULLISH - | OpCode::RETURN - | OpCode::HALT - | OpCode::THROW - ) + op.is_terminator() } /// 构建 CFG:`&IRFunction → Cfg`。纯函数,只读 IR。 diff --git a/crates/oxide_ir/src/contract.rs b/crates/oxide_ir/src/contract.rs index ae71912..1d9a00b 100644 --- a/crates/oxide_ir/src/contract.rs +++ b/crates/oxide_ir/src/contract.rs @@ -5,7 +5,7 @@ //! 寄存器规则与 VM dispatch handler 行为一致: //! CALL 隐式写 reg 0、GET_PROP 结果写 a/b 槽、HALT 隐式读 reg 0、None 槽映射 Reg(0)。 -use oxide_bytecode::opcode::OpCode; +use oxide_bytecode::opcode::{OpCode, Slot, SlotSpec}; use smallvec::SmallVec; use crate::inst::Inst; @@ -15,335 +15,58 @@ use crate::IRFunction; impl Inst { /// 本指令定义的寄存器(None 槽按 Reg(0) 映射;CALL 系含隐式 reg 0)。 /// 无写入返回 None。 + /// + /// # 步骤 + /// 表驱动解析:取语义表 def 槽位 → 解出对应操作数槽寄存器;Reg0 恒为常量 0。 + /// + /// # 边界与前提 + /// - `SlotSpec::Range/SpreadArgs/TemplateExprs/BrandReg` 不可能作 def,返回 None。 pub fn def_reg(&self) -> Option { - match self.op { - // CALL 系:结果隐式写 reg 0,rd 是 callee 的 use - OpCode::CALL | OpCode::CALL_NATIVE | OpCode::CALL_SPREAD => Some(0), - // YIELD/YIELD_STAR:恢复时 next(v) 的 v / 委托完成值经 reg 0 交付(与 CALL 同协议) - OpCode::YIELD | OpCode::YIELD_STAR | OpCode::AWAIT => Some(0), - // GET_PROP 系:结果写 a/b 槽而非 rd - OpCode::GET_PROP | OpCode::IC_GET_PROP => reg_of(&self.a), - OpCode::GET_PROP_DYNAMIC => reg_of(&self.b), - // 成员读写:val 槽原地更新(a 槽 / b 槽) - OpCode::MEMBER_INC | OpCode::MEMBER_DEC => reg_of(&self.a), - OpCode::DYN_MEMBER_INC | OpCode::DYN_MEMBER_DEC => reg_of(&self.b), - OpCode::COMPOUND_MEMBER_ADD - | OpCode::COMPOUND_MEMBER_SUB - | OpCode::COMPOUND_MEMBER_MUL - | OpCode::COMPOUND_MEMBER_DIV - | OpCode::COMPOUND_MEMBER_MOD - | OpCode::COMPOUND_MEMBER_EXP - | OpCode::COMPOUND_MEMBER_BIT_AND - | OpCode::COMPOUND_MEMBER_BIT_OR - | OpCode::COMPOUND_MEMBER_BIT_XOR - | OpCode::COMPOUND_MEMBER_SHL - | OpCode::COMPOUND_MEMBER_SHR - | OpCode::COMPOUND_MEMBER_USHR => reg_of(&self.a), - // 无 def:控制流 / 写共享状态 / 纯写对象 - OpCode::HALT - | OpCode::RETURN - | OpCode::THROW - | OpCode::JMP - | OpCode::BREAK - | OpCode::CONTINUE - | OpCode::JMP_IF_FALSE - | OpCode::JMP_IF_TRUE - | OpCode::JMP_IF_NULLISH - | OpCode::TRY_BEGIN - | OpCode::TRY_END - | OpCode::TRY_FINALLY_BEGIN - | OpCode::TRY_FINALLY_END - | OpCode::MAKE_CELL - | OpCode::MAKE_CELL_FRESH - | OpCode::CELL_SET - | OpCode::STORE_UPVALUE - | OpCode::SET_PROP - | OpCode::SET_PROP_DYNAMIC - | OpCode::IC_SET_PROP - | OpCode::SET_ELEM - | OpCode::SET_PRIVATE - | OpCode::INIT_PRIVATE - | OpCode::DELETE_PROP_STATIC - | OpCode::DELETE_PROP_DYNAMIC - | OpCode::DEFINE_ACCESSOR - | OpCode::DEFINE_PROP - | OpCode::DEFINE_GLOBAL_PROP - | OpCode::SET_HOME_OBJECT - // SPILL 写 VM spill 栈而非寄存器(恢复由 UNSPILL 写 rd) - | OpCode::SPILL - | OpCode::FOR_IN_INIT - | OpCode::FOR_OF_INIT - | OpCode::FOR_AWAIT_OF_INIT - | OpCode::FOR_IN_CLEANUP - | OpCode::FOR_OF_CLOSE - | OpCode::FOR_AWAIT_OF_CLOSE - | OpCode::SUSPEND_BODY => None, - // 其余指令 rd 即 def(算术/比较/位/逻辑/加载族/迭代器 NEXT 等) - _ => reg_of(&self.rd), + match self.op.semantics().def? { + SlotSpec::Slot(slot) => reg_of(slot_operand(slot, self)), + SlotSpec::Reg0 => Some(0), + _ => None, } } /// 本指令读取的寄存器(None 槽按 Reg(0) 映射;HALT 特判 reg 0;TEMPLATE_STR 解析 ext)。 + /// + /// # 步骤 + /// 按语义表 uses 槽位序逐项解析,序即输出序。 + /// + /// # 边界与前提 + /// - `Range`:nargs=ext[0],从指定槽起连续 nargs 个寄存器。 + /// - `SpreadArgs`:ext[1..] 每个字 `& 0x7FFF_FFFF`。 + /// - `TemplateExprs`:ext[1..] 中 `seg>>31==1` 的低 8 位。 + /// - `BrandReg`:ext[0] 非 0 才产生 use。 pub fn use_regs(&self) -> SmallVec<[u32; 4]> { let mut uses = SmallVec::new(); - match self.op { - // CALL 系:rd=callee, a=this, b..b+nargs 参数区间 - OpCode::CALL | OpCode::CALL_NATIVE => { - push_operand(&mut uses, &self.rd); - push_operand(&mut uses, &self.a); - let nargs = self.ext.first().copied().unwrap_or(0); - push_range(&mut uses, reg_of(&self.b), nargs); - } - // NEW_EXPRESSION:a=ctor, b..b+nargs - OpCode::NEW_EXPRESSION => { - push_operand(&mut uses, &self.a); - let nargs = self.ext.first().copied().unwrap_or(0); - push_range(&mut uses, reg_of(&self.b), nargs); - } - // SUPER_CALL:a..a+nargs - OpCode::SUPER_CALL => { - let nargs = self.ext.first().copied().unwrap_or(0); - push_range(&mut uses, reg_of(&self.a), nargs); - } - // spread 调用系:ext 内嵌有序实参字(静态寄存器号 / `0x8000_0000|reg` spread 源) - OpCode::CALL_SPREAD => { - push_operand(&mut uses, &self.rd); - push_operand(&mut uses, &self.a); - for &w in self.ext.iter().skip(1) { - uses.push(w & 0x7FFF_FFFF); + for &spec in self.op.semantics().uses { + match spec { + SlotSpec::Slot(slot) => push_operand(&mut uses, slot_operand(slot, self)), + SlotSpec::Reg0 => uses.push(0), + SlotSpec::Range(slot) => { + let nargs = self.ext.first().copied().unwrap_or(0); + push_range(&mut uses, reg_of(slot_operand(slot, self)), nargs); } - } - OpCode::NEW_EXPRESSION_SPREAD => { - push_operand(&mut uses, &self.a); - for &w in self.ext.iter().skip(1) { - uses.push(w & 0x7FFF_FFFF); - } - } - OpCode::SUPER_CALL_SPREAD => { - for &w in self.ext.iter().skip(1) { - uses.push(w & 0x7FFF_FFFF); - } - } - // GET_PROP 系:结果写 a/b 槽,rd=obj 是 use - OpCode::GET_PROP => { - push_operand(&mut uses, &self.rd); - push_operand(&mut uses, &self.b); - } - OpCode::GET_PROP_DYNAMIC => { - push_operand(&mut uses, &self.rd); - push_operand(&mut uses, &self.a); - } - OpCode::IC_GET_PROP => { - push_operand(&mut uses, &self.a); - push_operand(&mut uses, &self.b); - } - // 成员更新:obj + key 是 use,val 槽是 def - OpCode::MEMBER_INC | OpCode::MEMBER_DEC => { - push_operand(&mut uses, &self.rd); - push_operand(&mut uses, &self.b); - } - OpCode::DYN_MEMBER_INC | OpCode::DYN_MEMBER_DEC => { - push_operand(&mut uses, &self.rd); - push_operand(&mut uses, &self.a); - } - OpCode::COMPOUND_MEMBER_ADD - | OpCode::COMPOUND_MEMBER_SUB - | OpCode::COMPOUND_MEMBER_MUL - | OpCode::COMPOUND_MEMBER_DIV - | OpCode::COMPOUND_MEMBER_MOD - | OpCode::COMPOUND_MEMBER_EXP - | OpCode::COMPOUND_MEMBER_BIT_AND - | OpCode::COMPOUND_MEMBER_BIT_OR - | OpCode::COMPOUND_MEMBER_BIT_XOR - | OpCode::COMPOUND_MEMBER_SHL - | OpCode::COMPOUND_MEMBER_SHR - | OpCode::COMPOUND_MEMBER_USHR => { - push_operand(&mut uses, &self.rd); - push_operand(&mut uses, &self.a); - push_operand(&mut uses, &self.b); - } - // 复合赋值:rd 与 a 都是 use(coerce 读双寄存器) - OpCode::COMPOUND_ADD - | OpCode::COMPOUND_SUB - | OpCode::COMPOUND_MUL - | OpCode::COMPOUND_DIV - | OpCode::COMPOUND_MOD - | OpCode::COMPOUND_EXP - | OpCode::COMPOUND_AND - | OpCode::COMPOUND_OR - | OpCode::COMPOUND_XOR - | OpCode::COMPOUND_SHL - | OpCode::COMPOUND_SHR - | OpCode::COMPOUND_USHR => { - push_operand(&mut uses, &self.rd); - push_operand(&mut uses, &self.a); - } - // 自增/自减:读 rd(写 rd 和 a) - OpCode::INC_PRE | OpCode::INC_POST | OpCode::DEC_PRE | OpCode::DEC_POST => { - push_operand(&mut uses, &self.rd); - } - // 二元运算:a, b - OpCode::ADD - | OpCode::SUB - | OpCode::MUL - | OpCode::DIV - | OpCode::MOD - | OpCode::EQ - | OpCode::NEQ - | OpCode::LT - | OpCode::GT - | OpCode::LTE - | OpCode::GTE - | OpCode::AND - | OpCode::OR - | OpCode::NULLISH - | OpCode::STRICT_EQ - | OpCode::STRICT_NEQ - | OpCode::BIT_AND - | OpCode::BIT_OR - | OpCode::BIT_XOR - | OpCode::SHL - | OpCode::SHR - | OpCode::USHR - | OpCode::INSTANCEOF - | OpCode::IN - | OpCode::CREATE_REGEXP => { - push_operand(&mut uses, &self.a); - push_operand(&mut uses, &self.b); - } - // 一元:a(emit 常 rd==a) - OpCode::NEG | OpCode::NOT | OpCode::UNARY_PLUS | OpCode::BIT_NOT | OpCode::TYPEOF => { - push_operand(&mut uses, &self.a); - } - // 无条件跳转 / try 标记 / 生成器 body 标记:无寄存器 - OpCode::JMP - | OpCode::BREAK - | OpCode::CONTINUE - | OpCode::TRY_BEGIN - | OpCode::TRY_FINALLY_BEGIN - | OpCode::TRY_END - | OpCode::TRY_FINALLY_END - | OpCode::FOR_IN_CLEANUP - | OpCode::FOR_OF_CLOSE - | OpCode::SUSPEND_BODY => {} - // 条件跳转:rd=cond - OpCode::JMP_IF_FALSE | OpCode::JMP_IF_TRUE | OpCode::JMP_IF_NULLISH => { - push_operand(&mut uses, &self.rd); - } - // HALT:隐式读 reg 0(顶层返回值) - OpCode::HALT => uses.push(0), - // RETURN/THROW/YIELD/YIELD_STAR/AWAIT:读 rd(None→0) - OpCode::RETURN | OpCode::THROW | OpCode::YIELD | OpCode::YIELD_STAR | OpCode::AWAIT => { - push_operand(&mut uses, &self.rd) - } - // 加载族:a 槽是 Const/Imm 立即数,无寄存器 use - OpCode::LOAD_CONST - | OpCode::CREATE_CLOSURE - | OpCode::LOAD_UPVALUE - | OpCode::VOID - | OpCode::NEW_OBJECT - | OpCode::NEW_ARRAY - | OpCode::CREATE_ARGUMENTS - | OpCode::CREATE_REST_ARRAY - | OpCode::NOP => {} - // 变量读写:LOAD_VAR/STORE_VAR/CELL_GET 读 a(None→0) - OpCode::LOAD_VAR | OpCode::STORE_VAR | OpCode::CELL_GET => { - push_operand(&mut uses, &self.a); - } - // RegAlloc 辅助:MOV 读 src(a 槽);SPILL 读待溢出寄存器(rd);UNSPILL 仅写 rd 无寄存器读 - OpCode::MOV => push_operand(&mut uses, &self.a), - OpCode::SPILL => push_operand(&mut uses, &self.rd), - OpCode::UNSPILL => {} - // MAKE_CELL:cell 初值读 rd;CELL_SET/STORE_UPVALUE 读 a - OpCode::MAKE_CELL | OpCode::MAKE_CELL_FRESH => push_operand(&mut uses, &self.rd), - OpCode::CELL_SET | OpCode::STORE_UPVALUE => push_operand(&mut uses, &self.a), - // 写对象属性:rd/a/b 全 use - OpCode::SET_PROP - | OpCode::SET_PROP_DYNAMIC - | OpCode::IC_SET_PROP - | OpCode::SET_ELEM - | OpCode::INIT_PRIVATE - | OpCode::DEFINE_ACCESSOR - | OpCode::DEFINE_PROP - | OpCode::DEFINE_GLOBAL_PROP => { - push_operand(&mut uses, &self.rd); - push_operand(&mut uses, &self.a); - push_operand(&mut uses, &self.b); - } - // 私有写:rd=对象、a=值、b=键是 use,额外读 ext[0](brand 对象寄存器) - OpCode::SET_PRIVATE => { - push_operand(&mut uses, &self.rd); - push_operand(&mut uses, &self.a); - push_operand(&mut uses, &self.b); - let brand_reg = self.ext.first().copied().unwrap_or(0); - if brand_reg != 0 { - uses.push(brand_reg); - } - } - // 私有读/品牌检查:a=对象、b=私有键是 use,rd 是结果 def - // GET_PRIVATE 额外读 ext[0](brand 对象寄存器,0 表示跳过检查) - OpCode::GET_PRIVATE => { - push_operand(&mut uses, &self.a); - push_operand(&mut uses, &self.b); - let brand_reg = self.ext.first().copied().unwrap_or(0); - if brand_reg != 0 { - uses.push(brand_reg); - } - } - OpCode::PRIVATE_BRAND_IN => { - push_operand(&mut uses, &self.a); - push_operand(&mut uses, &self.b); - } - // delete:读 obj(+dynamic 读 key) - OpCode::DELETE_PROP_STATIC => push_operand(&mut uses, &self.rd), - OpCode::DELETE_PROP_DYNAMIC => { - push_operand(&mut uses, &self.rd); - push_operand(&mut uses, &self.b); - } - // super 属性读:a=this, b=key - OpCode::SUPER_GET_PROP | OpCode::SUPER_STATIC_GET_PROP => { - push_operand(&mut uses, &self.a); - push_operand(&mut uses, &self.b); - } - // SET_HOME_OBJECT:rd=func, a=home - OpCode::SET_HOME_OBJECT => { - push_operand(&mut uses, &self.rd); - push_operand(&mut uses, &self.a); - } - // for-in/of 迭代器:INIT 读 a;NEXT/DONE 读迭代器栈隐式状态 - OpCode::FOR_IN_INIT | OpCode::FOR_OF_INIT | OpCode::FOR_AWAIT_OF_INIT => push_operand(&mut uses, &self.a), - OpCode::FOR_IN_NEXT | OpCode::FOR_IN_DONE | OpCode::FOR_OF_NEXT | OpCode::FOR_OF_DONE => {} - // for-await-of:NEXT 无寄存器 use;DONE 读取 AWAIT 恢复值(a 槽)的 done - OpCode::FOR_AWAIT_OF_NEXT | OpCode::FOR_AWAIT_OF_CLOSE => {} - OpCode::FOR_AWAIT_OF_DONE => push_operand(&mut uses, &self.a), - // REST_OBJECT:读 a(src)与可选 b(运行时 excluded 数组),ext 是 excluded_idx 常量 - OpCode::REST_OBJECT => { - push_operand(&mut uses, &self.a); - push_operand(&mut uses, &self.b); - } - // SPREAD_OBJECT:原地改目标对象,读目标(rd)与源(a) - OpCode::SPREAD_OBJECT => { - push_operand(&mut uses, &self.rd); - push_operand(&mut uses, &self.a); - } - // TEMPLATE_STR:解析 ext,跳过 ext[0],后续 seg>>31==1 则低 8 位是 expr_reg - OpCode::TEMPLATE_STR => { - for seg in self.ext.iter().skip(1) { - if seg >> 31 == 1 { - uses.push(seg & 0xFF); + SlotSpec::SpreadArgs => { + for &w in self.ext.iter().skip(1) { + uses.push(w & 0x7FFF_FFFF); + } + } + SlotSpec::TemplateExprs => { + for seg in self.ext.iter().skip(1) { + if seg >> 31 == 1 { + uses.push(seg & 0xFF); + } + } + } + SlotSpec::BrandReg => { + let brand_reg = self.ext.first().copied().unwrap_or(0); + if brand_reg != 0 { + uses.push(brand_reg); } } - } - // 占位 opcode(emit 不产):按无 use 保守处理,不影响合法产物 - OpCode::SWITCH_TABLE - | OpCode::PROFILE_SHAPE - | OpCode::PROFILE_BRANCH - | OpCode::PROFILE_CALL - | OpCode::FORK - | OpCode::JOIN => {} - // TO_OBJECT:rd 原地转换(读且写) - OpCode::TO_OBJECT => { - push_operand(&mut uses, &self.rd); } } uses @@ -351,59 +74,19 @@ impl Inst { /// 本指令是否无观察副作用(LOAD_VAR 的 This+derived 特判需要函数元信息)。 /// - /// 纯 = 结果未用时可删。表外 opcode 一律视为有副作用,宁少删不错删。 + /// 纯 = 结果未用时可删。表内 pure 是静态字段,LOAD_VAR 上下文例外在此叠加。 pub fn is_pure(&self, f: &IRFunction) -> bool { - match self.op { - // 算术 / 比较 / 位 / 逻辑:coerce 对象路径有抛错风险,仍按纯处理(运行时等价兜底) - OpCode::ADD - | OpCode::SUB - | OpCode::MUL - | OpCode::DIV - | OpCode::MOD - | OpCode::NEG - | OpCode::UNARY_PLUS - | OpCode::EQ - | OpCode::NEQ - | OpCode::LT - | OpCode::GT - | OpCode::LTE - | OpCode::GTE - | OpCode::STRICT_EQ - | OpCode::STRICT_NEQ - | OpCode::BIT_AND - | OpCode::BIT_OR - | OpCode::BIT_XOR - | OpCode::SHL - | OpCode::SHR - | OpCode::USHR - | OpCode::BIT_NOT - | OpCode::AND - | OpCode::OR - | OpCode::NOT - | OpCode::NULLISH => true, - // 分配 / 常量 / 空操作(a 槽非寄存器) - OpCode::NOP - | OpCode::LOAD_CONST - | OpCode::VOID - | OpCode::TYPEOF - | OpCode::NEW_OBJECT - | OpCode::NEW_ARRAY => true, - // MOV:寄存器复制无副作用,可删无害 - OpCode::MOV => true, - // SPILL/UNSPILL:RegAlloc 插入的指令,删 SPILL 后 UNSPILL 读陈旧值,永不删 - OpCode::SPILL | OpCode::UNSPILL => false, - // 闭包 / cell 读取:无抛错路径 - OpCode::CREATE_CLOSURE | OpCode::LOAD_UPVALUE | OpCode::CELL_GET => true, - // 模板字符串:纯拼接写 rd,无抛错(use 统计覆盖其 ext) - OpCode::TEMPLATE_STR => true, - // LOAD_VAR:仅 a==This 且 derived 构造函数读 this 时可能抛 ReferenceError - OpCode::LOAD_VAR => !(self.a == Operand::This && f.is_derived_constructor), - // STORE_VAR:写变量目标寄存器。脚本顶层/模块作用域的变量是全局可观察状态, - // 删除会改变外部观察结果;函数内局部未用赋值的优化交给精确 DCE。 - OpCode::STORE_VAR => false, - // 其余全部有副作用(getter/调用/控制流/迭代器/复合更新/写共享状态/占位防御) - _ => false, - } + let base = self.op.semantics().pure; + base && !(self.op == OpCode::LOAD_VAR && self.a == Operand::This && f.is_derived_constructor) + } +} + +/// 槽位 → 对应操作数(表解析用;Const/Imm/Label 由 reg_of 过滤)。 +fn slot_operand(slot: Slot, i: &Inst) -> &Operand { + match slot { + Slot::Rd => &i.rd, + Slot::A => &i.a, + Slot::B => &i.b, } } @@ -800,4 +483,310 @@ mod tests { let reg_load = Inst::new(OpCode::LOAD_VAR, Operand::Reg(1), Operand::Reg(2), Operand::None); assert!(reg_load.is_pure(&derived)); } + + // ── 表驱动解析 vs 老 match 的一致性(Phase B1 迁移校验)── + + /// 每个 opcode 构造一条规范指令:rd/a/b 置 Reg(1/2/3),ext 按族填真实布局。 + fn canonical_inst(op: OpCode) -> Inst { + match op { + OpCode::CALL | OpCode::CALL_NATIVE => { + Inst::call(Operand::Reg(1), Operand::Reg(2), Operand::Reg(3), 2) + } + OpCode::NEW_EXPRESSION => { + Inst::new_expression(Operand::Reg(1), Operand::Reg(2), Operand::Reg(3), 2) + } + OpCode::SUPER_CALL => Inst::super_call(Operand::Reg(1), Operand::Reg(2), 2), + OpCode::CALL_SPREAD => { + Inst::call_spread(Operand::Reg(1), Operand::Reg(2), &[5, 0x8000_0000 | 9]) + } + OpCode::NEW_EXPRESSION_SPREAD => { + Inst::new_expression_spread(Operand::Reg(1), Operand::Reg(2), &[5, 0x8000_0000 | 9]) + } + OpCode::SUPER_CALL_SPREAD => { + Inst::super_call_spread(Operand::Reg(1), &[5, 0x8000_0000 | 9]) + } + OpCode::IC_GET_PROP => Inst::ic_get(Operand::Reg(1), Operand::Reg(2)), + OpCode::IC_SET_PROP => Inst::ic_set(Operand::Reg(1), Operand::Reg(2), Operand::Reg(3)), + OpCode::MEMBER_INC => { + Inst::member_inc(Operand::Reg(1), Operand::Reg(2), Operand::Reg(3)) + } + OpCode::MEMBER_DEC => { + Inst::member_dec(Operand::Reg(1), Operand::Reg(2), Operand::Reg(3)) + } + OpCode::COMPOUND_MEMBER_ADD => { + Inst::compound_member_add(Operand::Reg(1), Operand::Reg(2), Operand::Reg(3)) + } + OpCode::COMPOUND_MEMBER_SUB => { + Inst::compound_member_sub(Operand::Reg(1), Operand::Reg(2), Operand::Reg(3)) + } + OpCode::COMPOUND_MEMBER_MUL => { + Inst::compound_member_mul(Operand::Reg(1), Operand::Reg(2), Operand::Reg(3)) + } + OpCode::COMPOUND_MEMBER_DIV => { + Inst::compound_member_div(Operand::Reg(1), Operand::Reg(2), Operand::Reg(3)) + } + OpCode::COMPOUND_MEMBER_MOD => { + Inst::compound_member_mod(Operand::Reg(1), Operand::Reg(2), Operand::Reg(3)) + } + OpCode::COMPOUND_MEMBER_EXP => { + Inst::compound_member_exp(Operand::Reg(1), Operand::Reg(2), Operand::Reg(3)) + } + OpCode::COMPOUND_MEMBER_BIT_AND => { + Inst::compound_member_bit_and(Operand::Reg(1), Operand::Reg(2), Operand::Reg(3)) + } + OpCode::COMPOUND_MEMBER_BIT_OR => { + Inst::compound_member_bit_or(Operand::Reg(1), Operand::Reg(2), Operand::Reg(3)) + } + OpCode::COMPOUND_MEMBER_BIT_XOR => { + Inst::compound_member_bit_xor(Operand::Reg(1), Operand::Reg(2), Operand::Reg(3)) + } + OpCode::COMPOUND_MEMBER_SHL => { + Inst::compound_member_shl(Operand::Reg(1), Operand::Reg(2), Operand::Reg(3)) + } + OpCode::COMPOUND_MEMBER_SHR => { + Inst::compound_member_shr(Operand::Reg(1), Operand::Reg(2), Operand::Reg(3)) + } + OpCode::COMPOUND_MEMBER_USHR => { + Inst::compound_member_ushr(Operand::Reg(1), Operand::Reg(2), Operand::Reg(3)) + } + OpCode::TEMPLATE_STR => Inst::template_str(Operand::Reg(1), 2, 10, &[0x1234, 0x8000_0000 | 5]), + OpCode::GET_PRIVATE => { + Inst::get_private(Operand::Reg(1), Operand::Reg(2), Operand::Reg(3), 7, 99) + } + OpCode::SET_PRIVATE => { + Inst::set_private(Operand::Reg(1), Operand::Reg(2), Operand::Reg(3), 7, 99) + } + OpCode::INIT_PRIVATE => { + Inst::init_private(Operand::Reg(1), Operand::Reg(2), Operand::Reg(3), true) + } + OpCode::PRIVATE_BRAND_IN => { + Inst::private_brand_in(Operand::Reg(1), Operand::Reg(2), Operand::Reg(3), 7, 99) + } + OpCode::SPILL => Inst::inst_spill(Operand::Reg(1), 42), + OpCode::UNSPILL => Inst::inst_unspill(Operand::Reg(1), 42), + OpCode::REST_OBJECT => Inst::rest_object(Operand::Reg(1), Operand::Reg(2), 7, None), + OpCode::DEFINE_ACCESSOR => { + Inst::define_accessor(Operand::Reg(1), Operand::Reg(2), Operand::Reg(3), 42) + } + OpCode::DELETE_PROP_STATIC => Inst::delete_prop_static(Operand::Reg(1), 9), + _ => Inst::new(op, Operand::Reg(1), Operand::Reg(2), Operand::Reg(3)), + } + } + + /// 全 opcode 表遍历断言(golden):def/use/pure 与表逐项一致。 + fn assert_contract(op: OpCode, def: Option, uses: &[u32], pure: bool) { + let inst = canonical_inst(op); + let f = IRFunction::new(); + assert_eq!(inst.def_reg(), def, "{op}: def"); + assert_eq!(inst.use_regs().as_slice(), uses, "{op}: uses"); + assert_eq!(inst.is_pure(&f), pure, "{op}: pure"); + } + + /// 同一规格的多个 opcode 批量断言。 + fn assert_group(ops: &[OpCode], def: Option, uses: &[u32], pure: bool) { + for &op in ops { + assert_contract(op, def, uses, pure); + } + } + + /// 每个 opcode 的 def/use/pure 与现有语义表一致(canonical rd=1, a=2, b=3)。 + #[test] + fn opcode_semantics_golden_table() { + // 二元运算:def=rd, uses=[a,b],纯 + assert_group( + &[ + OpCode::ADD, + OpCode::SUB, + OpCode::MUL, + OpCode::DIV, + OpCode::MOD, + OpCode::EQ, + OpCode::NEQ, + OpCode::LT, + OpCode::GT, + OpCode::LTE, + OpCode::GTE, + OpCode::AND, + OpCode::OR, + OpCode::STRICT_EQ, + OpCode::STRICT_NEQ, + OpCode::BIT_AND, + OpCode::BIT_OR, + OpCode::BIT_XOR, + OpCode::SHL, + OpCode::SHR, + OpCode::USHR, + OpCode::NULLISH, + ], + Some(1), + &[2, 3], + true, + ); + // 二元但不可删:coerce 有观察路径 + assert_group(&[OpCode::IN, OpCode::INSTANCEOF, OpCode::CREATE_REGEXP], Some(1), &[2, 3], false); + // 一元:def=rd, uses=[a] + assert_group( + &[OpCode::NEG, OpCode::NOT, OpCode::UNARY_PLUS, OpCode::BIT_NOT, OpCode::TYPEOF], + Some(1), + &[2], + true, + ); + // 复合赋值:def=rd, uses=[rd,a],不可删 + assert_group( + &[ + OpCode::COMPOUND_ADD, + OpCode::COMPOUND_SUB, + OpCode::COMPOUND_MUL, + OpCode::COMPOUND_DIV, + OpCode::COMPOUND_MOD, + OpCode::COMPOUND_EXP, + OpCode::COMPOUND_AND, + OpCode::COMPOUND_OR, + OpCode::COMPOUND_XOR, + OpCode::COMPOUND_SHL, + OpCode::COMPOUND_SHR, + OpCode::COMPOUND_USHR, + ], + Some(1), + &[1, 2], + false, + ); + // RegAlloc 辅助 + assert_contract(OpCode::MOV, Some(1), &[2], true); + assert_contract(OpCode::SPILL, None, &[1], false); + assert_contract(OpCode::UNSPILL, Some(1), &[], false); + assert_contract(OpCode::SPREAD_OBJECT, Some(1), &[1, 2], false); + // 无条件跳转 / try 标记 / 生成器 body 标记:无 def 无 use + assert_group( + &[ + OpCode::BREAK, + OpCode::CONTINUE, + OpCode::JMP, + OpCode::TRY_BEGIN, + OpCode::TRY_END, + OpCode::TRY_FINALLY_BEGIN, + OpCode::TRY_FINALLY_END, + OpCode::FOR_IN_CLEANUP, + OpCode::FOR_OF_CLOSE, + OpCode::SUSPEND_BODY, + ], + None, + &[], + false, + ); + // 条件跳转:uses=[rd] + assert_group(&[OpCode::JMP_IF_FALSE, OpCode::JMP_IF_TRUE, OpCode::JMP_IF_NULLISH], None, &[1], false); + // 迭代器 INIT 读 a;NEXT/DONE 无 use 写 rd + assert_group(&[OpCode::FOR_OF_INIT, OpCode::FOR_IN_INIT, OpCode::FOR_AWAIT_OF_INIT], None, &[2], false); + assert_group( + &[ + OpCode::FOR_OF_NEXT, + OpCode::FOR_IN_NEXT, + OpCode::FOR_IN_DONE, + OpCode::FOR_OF_DONE, + OpCode::FOR_AWAIT_OF_NEXT, + ], + Some(1), + &[], + false, + ); + assert_contract(OpCode::FOR_AWAIT_OF_DONE, Some(1), &[2], false); + // 自增/自减:def=rd, uses=[rd] + assert_group(&[OpCode::INC_PRE, OpCode::INC_POST, OpCode::DEC_PRE, OpCode::DEC_POST], Some(1), &[1], false); + // 占位 opcode:def=rd 保守,不可删 + assert_group( + &[ + OpCode::SWITCH_TABLE, + OpCode::PROFILE_SHAPE, + OpCode::PROFILE_BRANCH, + OpCode::PROFILE_CALL, + OpCode::FORK, + OpCode::JOIN, + ], + Some(1), + &[], + false, + ); + // 异常 / 返回 / 停机 + assert_contract(OpCode::THROW, None, &[1], false); + assert_contract(OpCode::RETURN, None, &[1], false); + assert_contract(OpCode::HALT, None, &[0], false); + // 模板字符串:表达式寄存器来自 ext + assert_contract(OpCode::TEMPLATE_STR, Some(1), &[5], true); + // 小语言特性 + assert_contract(OpCode::DELETE_PROP_STATIC, None, &[1], false); + assert_contract(OpCode::DELETE_PROP_DYNAMIC, None, &[1, 3], false); + assert_contract(OpCode::MAKE_CELL, None, &[1], false); + assert_contract(OpCode::MAKE_CELL_FRESH, None, &[1], false); + assert_contract(OpCode::CELL_SET, None, &[2], false); + assert_contract(OpCode::CELL_GET, Some(1), &[2], true); + assert_contract(OpCode::REST_OBJECT, Some(1), &[2, 0], false); + // 变量加载族 + assert_contract(OpCode::LOAD_VAR, Some(1), &[2], true); + assert_contract(OpCode::STORE_VAR, Some(1), &[2], false); + assert_contract(OpCode::LOAD_CONST, Some(1), &[], true); + assert_contract(OpCode::LOAD_UPVALUE, Some(1), &[], true); + assert_contract(OpCode::CREATE_CLOSURE, Some(1), &[], true); + assert_contract(OpCode::STORE_UPVALUE, None, &[2], false); + // 调用族:CALL 系隐式写 reg 0 + assert_contract(OpCode::CALL, Some(0), &[1, 2, 3, 4], false); + assert_contract(OpCode::CALL_NATIVE, Some(0), &[1, 2, 3, 4], false); + assert_contract(OpCode::NEW_EXPRESSION, Some(1), &[2, 3, 4], false); + assert_contract(OpCode::SUPER_CALL, Some(1), &[2, 3], false); + assert_contract(OpCode::CALL_SPREAD, Some(0), &[1, 2, 5, 9], false); + assert_contract(OpCode::NEW_EXPRESSION_SPREAD, Some(1), &[2, 5, 9], false); + assert_contract(OpCode::SUPER_CALL_SPREAD, Some(1), &[5, 9], false); + // super 属性读 / home object / accessor + assert_group(&[OpCode::SUPER_GET_PROP, OpCode::SUPER_STATIC_GET_PROP], Some(1), &[2, 3], false); + assert_contract(OpCode::SET_HOME_OBJECT, None, &[1, 2], false); + assert_contract(OpCode::DEFINE_ACCESSOR, None, &[1, 2, 3], false); + // Object Property:GET_PROP 写 a 槽、DYNAMIC 写 b 槽 + assert_contract(OpCode::GET_PROP, Some(2), &[1, 3], false); + assert_contract(OpCode::GET_PROP_DYNAMIC, Some(3), &[1, 2], false); + assert_contract(OpCode::IC_GET_PROP, Some(1), &[1, 2], false); + assert_contract(OpCode::SET_PROP, None, &[1, 2, 3], false); + assert_contract(OpCode::SET_PROP_DYNAMIC, None, &[1, 2, 3], false); + assert_contract(OpCode::IC_SET_PROP, None, &[1, 2, 3], false); + assert_contract(OpCode::SET_ELEM, None, &[1, 2, 3], false); + assert_group(&[OpCode::NEW_OBJECT, OpCode::NEW_ARRAY], Some(1), &[], true); + // define 语义属性写入 / arguments / rest + assert_group(&[OpCode::DEFINE_PROP, OpCode::DEFINE_GLOBAL_PROP], None, &[1, 2, 3], false); + assert_group(&[OpCode::CREATE_ARGUMENTS, OpCode::CREATE_REST_ARRAY], Some(1), &[], false); + // 成员更新:val 槽原地写(a/b 槽) + assert_group(&[OpCode::MEMBER_INC, OpCode::MEMBER_DEC], Some(2), &[1, 3], false); + assert_group(&[OpCode::DYN_MEMBER_INC, OpCode::DYN_MEMBER_DEC], Some(3), &[1, 2], false); + assert_group( + &[ + OpCode::COMPOUND_MEMBER_ADD, + OpCode::COMPOUND_MEMBER_SUB, + OpCode::COMPOUND_MEMBER_MUL, + OpCode::COMPOUND_MEMBER_DIV, + OpCode::COMPOUND_MEMBER_MOD, + OpCode::COMPOUND_MEMBER_EXP, + OpCode::COMPOUND_MEMBER_BIT_AND, + OpCode::COMPOUND_MEMBER_BIT_OR, + OpCode::COMPOUND_MEMBER_BIT_XOR, + OpCode::COMPOUND_MEMBER_SHL, + OpCode::COMPOUND_MEMBER_SHR, + OpCode::COMPOUND_MEMBER_USHR, + ], + Some(2), + &[1, 2, 3], + false, + ); + // 私有成员:brand_reg 非 0 时产生额外 use + assert_contract(OpCode::GET_PRIVATE, Some(1), &[2, 3, 7], false); + assert_contract(OpCode::SET_PRIVATE, None, &[1, 2, 3, 7], false); + assert_contract(OpCode::INIT_PRIVATE, None, &[1, 2, 3], false); + assert_contract(OpCode::PRIVATE_BRAND_IN, Some(1), &[2, 3], false); + // 生成器 / 异步:恢复值经 reg 0 + assert_group(&[OpCode::YIELD, OpCode::YIELD_STAR, OpCode::AWAIT], Some(0), &[1], false); + assert_contract(OpCode::FOR_AWAIT_OF_CLOSE, None, &[], false); + // 位 / 对象 / 杂项 + assert_contract(OpCode::TO_OBJECT, Some(1), &[1], false); + // NOP:rd=None 时 def_reg 仍为 Some(0)(catch-all 语义,表内保持 def=Rd) + assert_eq!(Inst::new(OpCode::NOP, Operand::None, Operand::None, Operand::None).def_reg(), Some(0)); + assert_contract(OpCode::NOP, Some(1), &[], true); + assert_contract(OpCode::VOID, Some(1), &[], true); + } } diff --git a/crates/oxide_ir/src/lower.rs b/crates/oxide_ir/src/lower.rs index 368cee8..332e2dc 100644 --- a/crates/oxide_ir/src/lower.rs +++ b/crates/oxide_ir/src/lower.rs @@ -120,7 +120,7 @@ fn operand_pair_to_u8(a: &Operand, b: &Operand) -> (u8, u8) { } fn encode_inst(inst: &Inst, instrs: &mut Vec, jumps: &mut Vec<(usize, u32)>) -> Result<(), String> { - if is_jump_op(inst.op) { + 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)), @@ -148,17 +148,3 @@ fn encode_inst(inst: &Inst, instrs: &mut Vec, jumps: &mut Vec<(usize, u32)> instrs.extend_from_slice(&inst.ext); Ok(()) } - -fn is_jump_op(op: OpCode) -> bool { - matches!( - op, - OpCode::JMP - | OpCode::BREAK - | OpCode::CONTINUE - | OpCode::JMP_IF_FALSE - | OpCode::JMP_IF_TRUE - | OpCode::JMP_IF_NULLISH - | OpCode::TRY_BEGIN - | OpCode::TRY_FINALLY_BEGIN - ) -} diff --git a/crates/oxide_regalloc/src/rewrite.rs b/crates/oxide_regalloc/src/rewrite.rs index 302ecf2..faba134 100644 --- a/crates/oxide_regalloc/src/rewrite.rs +++ b/crates/oxide_regalloc/src/rewrite.rs @@ -292,18 +292,7 @@ fn remap_ext_reg(r: u32, slot_color: &BTreeMap, map: &AllocMap) -> u32 /// terminator 判定:跳转族 + RETURN/HALT/THROW(def 结果必死,SPILL 跳过)。 fn is_terminator(op: OpCode) -> bool { - matches!( - op, - OpCode::JMP - | OpCode::BREAK - | OpCode::CONTINUE - | OpCode::JMP_IF_TRUE - | OpCode::JMP_IF_FALSE - | OpCode::JMP_IF_NULLISH - | OpCode::RETURN - | OpCode::HALT - | OpCode::THROW - ) + op.is_terminator() } /// spilled builtin:对 builtin_reg_map 中 map[v]=Spill 的项分配确定性自由色 R。