mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-24 02:31:13 +08:00
999 lines
55 KiB
Rust
999 lines
55 KiB
Rust
//! 字节码操作码表与指令编解码。
|
||
//!
|
||
//! [`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;
|
||
|
||
/// 操作数槽位:指令 rd/a/b 三槽之一。
|
||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||
pub enum Slot {
|
||
/// 目标寄存器槽。
|
||
Rd,
|
||
/// 第一操作数槽。
|
||
A,
|
||
/// 第二操作数槽。
|
||
B,
|
||
}
|
||
|
||
/// 槽位规范:声明指令如何读写寄存器。解析器在 `oxide_ir::contract`。
|
||
///
|
||
/// # 语义约定
|
||
/// - `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)。
|
||
/// - `ExtReg`:ext[0] 是寄存器,高位标记 `0x8000_0000 | vreg`,低 31 位是 vreg。
|
||
#[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,
|
||
/// ext[0] 的寄存器(高位标记,与 SpreadArgs 同款编码)。
|
||
ExtReg,
|
||
}
|
||
|
||
/// 单张语义表行:一个 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<SlotSpec>,
|
||
/// 读取的寄存器(按序,序即 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,
|
||
/// IC 扩展字(= has_ic_ext_words):每条 IC 指令带 IC_EXT_WORDS 个扩展字。
|
||
pub ic_ext: bool,
|
||
}
|
||
|
||
/// IC 每站点的缓存槽数:多态化支持同一访问点最多缓存该数量的 shape。
|
||
pub const IC_SLOTS: usize = 4;
|
||
|
||
/// 每条 IC 指令的扩展字总数(每槽两个字:shape_id|proto_depth 打包字 + slot 字)。
|
||
pub const IC_EXT_WORDS: usize = IC_SLOTS * 2;
|
||
|
||
/// 从单张表生成 [`OpCode`] 枚举、`TryFrom<u8>`、`Display` 与语义访问器。
|
||
///
|
||
/// 每行同时提供枚举判别值、`TryFrom` 分支、`Display` 名称与语义字段
|
||
/// (def/uses/pure/jump/term/ic)七份信息,保证多表永不漂移;新增操作码只需
|
||
/// 加一行。`semantics()` 的 match 无 `_` 臂——漏填语义即编译错误。
|
||
///
|
||
/// # 注意事项
|
||
/// - 分组注释(`// ── 算术 ──`)在宏展开前被词法器剥离,可自由插入行间。
|
||
macro_rules! define_opcodes {
|
||
( $(
|
||
$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 个一组组织便于阅读。已实现的操作码在编译器中有发射支持;
|
||
/// 占位符操作码为后续阶段预留(IC、profiling、并行化)。
|
||
#[repr(u8)]
|
||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||
#[allow(non_camel_case_types)]
|
||
pub enum OpCode {
|
||
$( $name = $val, )+
|
||
}
|
||
|
||
impl TryFrom<u8> for OpCode {
|
||
type Error = ();
|
||
|
||
fn try_from(value: u8) -> Result<Self, Self::Error> {
|
||
match value {
|
||
$( $val => Ok(OpCode::$name), )+
|
||
_ => Err(()),
|
||
}
|
||
}
|
||
}
|
||
|
||
impl fmt::Display for OpCode {
|
||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||
let name = match self {
|
||
$( OpCode::$name => $disp, )+
|
||
};
|
||
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 = false, 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 = false, 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 = false, 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 = false, 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 = false, jump = false, term = false, ic = false,
|
||
NEG = 0x05 => "NEG",
|
||
def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::A)],
|
||
pure = false, 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",
|
||
def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::Rd), SlotSpec::Slot(Slot::A)],
|
||
pure = false, jump = false, term = false, ic = false,
|
||
// 二元幂运算 `a ** b`(三寄存器,与 SUB/MUL 同族;0x00-0x0F 已满,值用空闲槽 0x94)。
|
||
EXP = 0x94 => "EXP",
|
||
def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::A), SlotSpec::Slot(Slot::B)],
|
||
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 = false, 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 = false, 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 = false, 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 = false, 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 = false, 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 = false, 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 = false, 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",
|
||
def = Some(SlotSpec::Slot(Slot::Rd)), uses = [],
|
||
pure = false, jump = false, term = false, ic = false,
|
||
// using/await using 声明登记:rd = 资源值寄存器,a = 释放提示(0 = 同步、1 = 异步)。
|
||
// 无寄存器 def(值压入 VM 释放栈,释放时机由作用域出口点决定);
|
||
// pure = false 防 DCE 删除压栈副作用。
|
||
DISPOSE_REGISTER = 0x2C => "DISPOSE_REGISTER",
|
||
def = None, uses = [SlotSpec::Slot(Slot::Rd)],
|
||
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;TRY_FINALLY_ENTER 用 0x1B 空槽) ──
|
||
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_ENTER = 0x1B => "TRY_FINALLY_ENTER",
|
||
def = None, uses = [],
|
||
pure = false, jump = false, 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 = false, jump = false, term = false, ic = false,
|
||
|
||
// ── 标签模板对象 (0x97) ──
|
||
// GetTemplateObject:按 site 缓存模板对象(同一编译树同 site 恒返回同一对象),
|
||
// 首次构建时冻结 cooked/raw 数组并设置规范描述符。ext 布局见
|
||
// `Inst::get_template_object`;无寄存器 use(quasis 全为常量池下标)。
|
||
GET_TEMPLATE_OBJECT = 0x97 => "GET_TEMPLATE_OBJECT",
|
||
def = Some(SlotSpec::Slot(Slot::Rd)), uses = [],
|
||
pure = false, 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,
|
||
// 未声明/已删标识符读:rd=目标,a/b=常量池 key 下标(imm16,与 LOAD_CONST 同构),
|
||
// 运行期查 global object 属性存在性,缺失抛 ReferenceError(未声明名与已知 builtin
|
||
// 名非局部遮蔽读均命中本指令:delete 后 A 侧缺失须经属性在位判定,镜像槽无法
|
||
// 自区分缺位与在位 undefined)。
|
||
LOAD_GLOBAL = 0x95 => "LOAD_GLOBAL",
|
||
def = Some(SlotSpec::Slot(Slot::Rd)), uses = [],
|
||
pure = false, jump = false, term = false, ic = false,
|
||
// typeof 未声明标识符特判:同 LOAD_GLOBAL 查 global object 属性,但缺失时
|
||
// 求值为 undefined 而非抛 ReferenceError(IsUnresolvableReference 语义)。
|
||
LOAD_GLOBAL_TYPEOF = 0x96 => "LOAD_GLOBAL_TYPEOF",
|
||
def = Some(SlotSpec::Slot(Slot::Rd)), uses = [],
|
||
pure = false, jump = false, term = false, ic = false,
|
||
|
||
// ── 调用 (0x40-0x4F) ──
|
||
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",
|
||
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",
|
||
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", // 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",
|
||
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,
|
||
// a 槽编码纯静态数据键前缀的属性数(≤255),ext 为每键的常量池下标;
|
||
// 运行时按键序链式预建 shape,后续 SET_PROP_BATCH 纯槽写。
|
||
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,
|
||
// 对象字面量批量构造的纯槽写:rd=对象,a=值,b=Imm(slot)。键序预建的 shape 槽,
|
||
// 不做任何键解析/形状变更,仅写数据槽。
|
||
SET_PROP_BATCH = 0x92 => "SET_PROP_BATCH",
|
||
def = None, uses = [SlotSpec::Slot(Slot::Rd), SlotSpec::Slot(Slot::A), SlotSpec::Slot(Slot::B)],
|
||
pure = false, jump = false, term = false, ic = false,
|
||
// 多操作数拼接(连续 `+` 左结合链摊平):rd=结果,a=首操作数,ext=[n, op2..opn],
|
||
// n=操作数总数,ext 字数 = 1+(n-1) = n;op 字无高位标记(纯 vreg,≤255),
|
||
// SpreadArgs 直接解析。含 ToPrimitive 副作用,不可删。
|
||
CONCAT_N = 0x93 => "CONCAT_N",
|
||
def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::A), SlotSpec::SpreadArgs],
|
||
pure = false, jump = false, term = false, ic = false,
|
||
|
||
// ── 成员更新 (0x59-0x62) ──
|
||
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",
|
||
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,
|
||
|
||
// ── using/await using 释放 (0x6A, 0x6B) ──
|
||
// 作用域入口水位:把当前释放栈深度压入水位栈(DISPOSE_REGISTER 的配对出口),
|
||
// 无寄存器 def/use;pure = false 防 DCE 删除水位副作用。
|
||
DISPOSE_MARK = 0x6A => "DISPOSE_MARK",
|
||
def = None, uses = [],
|
||
pure = false, jump = false, term = false, ic = false,
|
||
// 作用域出口:弹出水位,逆序释放水位以上资源并截断释放栈(规范
|
||
// DisposeResources),无寄存器 def/use。
|
||
DISPOSE_POP = 0x6B => "DISPOSE_POP",
|
||
def = None, uses = [],
|
||
pure = false, jump = false, term = false, ic = false,
|
||
// super 属性写:rd=值、a=this(receiver)、b=键。运行期 GetSuperBase 先于
|
||
// ToPropertyKey(与 SUPER_GET_PROP 同步序),基非对象抛 TypeError,写经
|
||
// ordinary_set(strict 由 current_strict 判定,失败抛 TypeError)。
|
||
SUPER_PUT_PROP = 0x6C => "SUPER_PUT_PROP",
|
||
def = None, uses = [SlotSpec::Slot(Slot::Rd), SlotSpec::Slot(Slot::A), SlotSpec::Slot(Slot::B)],
|
||
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,
|
||
|
||
// define 数据/访问器属性并指定描述符:ext 字存放 attrs(bit0=writable, bit1=enumerable, bit2=configurable,与 PropAttributes 位一致)。
|
||
// class 方法/constructor/prototype 需要非枚举或不可写描述符,普通 SET_PROP/DEFINE_PROP 无法表达。
|
||
DEFINE_PROP_ATTRS = 0x90 => "DEFINE_PROP_ATTRS",
|
||
def = None, uses = [SlotSpec::Slot(Slot::Rd), SlotSpec::Slot(Slot::A), SlotSpec::Slot(Slot::B)],
|
||
pure = false, jump = false, term = false, ic = false,
|
||
DEFINE_ACCESSOR_ATTRS = 0x91 => "DEFINE_ACCESSOR_ATTRS",
|
||
def = None, uses = [SlotSpec::Slot(Slot::Rd), SlotSpec::Slot(Slot::A), SlotSpec::Slot(Slot::B)],
|
||
pure = false, jump = false, term = false, ic = false,
|
||
// 隐式全局写:ext 字 = 键常量池下标(u16)、a 槽 = 值寄存器;全局对象由 VM 运行期
|
||
// 从 session 取(不依赖 this——函数体内隐式全局写时 regs[254] 不一定是全局对象)。
|
||
// 数据属性可写/可枚举/可配置(未声明标识符 PutValue 与 eval 脚本声明共用);
|
||
// 全局对象不可扩展时 strict/sloppy 均抛 TypeError。
|
||
DEFINE_GLOBAL_PROP_C = 0x98 => "DEFINE_GLOBAL_PROP_C",
|
||
def = None, uses = [SlotSpec::Slot(Slot::A)],
|
||
pure = false, jump = false, term = false, ic = false,
|
||
// 顶层 var 声明的全局属性 define-if-absent(GDI 序言):rd=目标对象(顶层
|
||
// This=全局对象)、a=值、b=键。既有属性(数据或 accessor)零动作——
|
||
// CreateGlobalVarBinding 对既有数据描述符零修改(可写/不可写/配置位均不更新);
|
||
// 缺失新建可写/可枚举/不可配置数据属性(脚本 var 的 c:false 描述符)。
|
||
DEFINE_GLOBAL_PROP_IF_ABSENT = 0x99 => "DEFINE_GLOBAL_PROP_IF_ABSENT",
|
||
def = None, uses = [SlotSpec::Slot(Slot::Rd), SlotSpec::Slot(Slot::A), SlotSpec::Slot(Slot::B)],
|
||
pure = false, jump = false, term = false, ic = false,
|
||
// eval 脚本顶层 var 声明的全局属性 define-if-absent:ext 字 = 键常量池下标
|
||
// (u16)、a 槽 = 值寄存器;全局对象由 session 解析(不依赖 this)。既有属性
|
||
// 零动作,缺失新建可写/可枚举/可配置(eval 传 deterministic=true)。
|
||
DEFINE_GLOBAL_PROP_C_IF_ABSENT = 0x9A => "DEFINE_GLOBAL_PROP_C_IF_ABSENT",
|
||
def = None, uses = [SlotSpec::Slot(Slot::A)],
|
||
pure = false, jump = false, term = false, ic = false,
|
||
// session 直分普通对象:寿命 session 级(session GC mark/sweep 回收),逃逸写
|
||
// 不触发晋升克隆。类原型等内建形对象要求与构造器 prototype 属性两侧 identity
|
||
// 一致——epoch 分配会在逃逸写晋升时克隆出第二份分裂 identity(同函数
|
||
// prototype 子对象的 session 分配同因)。
|
||
NEW_SESSION_OBJECT = 0x9B => "NEW_SESSION_OBJECT",
|
||
def = Some(SlotSpec::Slot(Slot::Rd)), uses = [],
|
||
pure = true, jump = false, term = false, ic = false,
|
||
// 删除全局内置数据属性(delete 标识符):ext 字 = 键常量池下标(u16)、
|
||
// rd = 布尔结果槽、a 槽 = 内置镜像槽寄存器(删除成功时该槽写 undefined;
|
||
// 0 = 无槽)。全局对象由 VM 运行期从 session 取(不依赖 this 寄存器)。
|
||
DELETE_GLOBAL_PROP_C = 0x9C => "DELETE_GLOBAL_PROP_C",
|
||
def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::A)],
|
||
pure = false, jump = false, term = false, ic = false,
|
||
// 全局函数绑定声明检查(GDI step 9,脚本顶层函数声明):rd=目标对象(顶层
|
||
// This=全局对象)、b=键寄存器。CanDeclareGlobalFunction 三臂:缺失 →
|
||
// IsExtensible、c:true → 过、data{w:true,e:true} → 过,余抛 TypeError。
|
||
// 检查阶段发射于任何绑定创建之前(先于 GDI var 序言),失败即无部分绑定。
|
||
CAN_DECLARE_GLOBAL_FUNC = 0x9D => "CAN_DECLARE_GLOBAL_FUNC",
|
||
def = None, uses = [SlotSpec::Slot(Slot::Rd), SlotSpec::Slot(Slot::B)],
|
||
pure = false, jump = false, term = false, ic = false,
|
||
// 创建全局函数绑定(CreateGlobalFunctionBinding,脚本面 deletable=false):
|
||
// rd=目标对象、a=值、b=键,与 DEFINE_GLOBAL_PROP 同形。缺失或既有 c:true →
|
||
// 定义可写/可枚举/不可配置数据属性;既有 c:false 可写数据 → 仅更新值保描述符。
|
||
DEFINE_GLOBAL_FUNC_BIND = 0x9E => "DEFINE_GLOBAL_FUNC_BIND",
|
||
def = None, uses = [SlotSpec::Slot(Slot::Rd), SlotSpec::Slot(Slot::A), SlotSpec::Slot(Slot::B)],
|
||
pure = false, jump = false, term = false, ic = false,
|
||
// 计算键访问器并指定描述符:同形 DEFINE_ACCESSOR_ATTRS,但 ext[0] 为高位标记
|
||
// 键寄存器(`0x8000_0000 | key_reg`,键值运行期从寄存器读取)、ext[1] = attrs。
|
||
// 发射方仅 class 体计算 get/set(规范 DefineMethod,enumerable=false)。
|
||
DEFINE_ACCESSOR_ATTRS_DYNAMIC = 0x9F => "DEFINE_ACCESSOR_ATTRS_DYNAMIC",
|
||
def = None, uses = [SlotSpec::Slot(Slot::Rd), SlotSpec::Slot(Slot::A), SlotSpec::Slot(Slot::B), SlotSpec::ExtReg],
|
||
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,
|
||
|
||
// ── 私有 (0x72-0x75) ──
|
||
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,
|
||
// 计算键访问器:ext[0]=key 寄存器(`0x8000_0000 | vreg`,低 31 位是 vreg)。
|
||
DEFINE_ACCESSOR_DYNAMIC = 0x7F => "DEFINE_ACCESSOR_DYNAMIC",
|
||
def = None, uses = [SlotSpec::Slot(Slot::Rd), SlotSpec::Slot(Slot::A), SlotSpec::Slot(Slot::B), SlotSpec::ExtReg],
|
||
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 = false, 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 = false, 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 = false, 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 = false, 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 = false, 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 = false, jump = false, term = false, ic = false,
|
||
BIT_NOT = 0x86 => "BIT_NOT",
|
||
def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::A)],
|
||
pure = false, 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", // 保持 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",
|
||
def = Some(SlotSpec::Slot(Slot::Rd)), uses = [],
|
||
pure = true, jump = false, term = false, ic = false,
|
||
}
|
||
|
||
/// 4 字节定长指令。
|
||
///
|
||
/// 布局 `[opcode: u8] [rd: u8] [a: u8] [b: u8]`:
|
||
/// - `rd` — 目标寄存器
|
||
/// - `a` — 第一个源寄存器,或 imm16 低字节
|
||
/// - `b` — 第二个源寄存器,或 imm16 高字节
|
||
pub type Instr = u32;
|
||
|
||
/// 把操作码与三个操作数字节编码为一条 [`Instr`]。
|
||
pub fn encode(op: OpCode, rd: u8, a: u8, b: u8) -> Instr {
|
||
((b as Instr) << 24) | ((a as Instr) << 16) | ((rd as Instr) << 8) | (op as Instr)
|
||
}
|
||
|
||
/// 解码指令的低 8 位操作码;未知字节返回 [`OpCode::NOP`]。
|
||
pub fn opcode(instr: Instr) -> OpCode {
|
||
OpCode::try_from((instr & 0xFF) as u8).unwrap_or(OpCode::NOP)
|
||
}
|
||
|
||
/// 解码目标寄存器(bits 8-15)。
|
||
pub fn rd(instr: Instr) -> u8 {
|
||
((instr >> 8) & 0xFF) as u8
|
||
}
|
||
|
||
/// 解码第一个操作数(bits 16-23)。
|
||
pub fn a(instr: Instr) -> u8 {
|
||
((instr >> 16) & 0xFF) as u8
|
||
}
|
||
|
||
/// 解码第二个操作数(bits 24-31)。
|
||
pub fn b(instr: Instr) -> u8 {
|
||
((instr >> 24) & 0xFF) as u8
|
||
}
|
||
|
||
/// 解码 16 位立即数(bits 16-31,由 a、b 两字节拼成)。
|
||
pub fn imm16(instr: Instr) -> u16 {
|
||
((instr >> 16) & 0xFFFF) as u16
|
||
}
|
||
|
||
/// 解码 16 位有符号跳转偏移(bits 16-31)。
|
||
pub fn offset16(instr: Instr) -> i16 {
|
||
((instr >> 16) & 0xFFFF) as i16
|
||
}
|
||
|
||
/// 计算 `pc` 处指令之后的扩展字个数(按 opcode 语义推进,逐指令字节序一致)。
|
||
///
|
||
/// 定长族返回固定字数;变长族依指令内容:spread 调用从首字读 nstatic|nspread、
|
||
/// TEMPLATE_STR 从首字读 segment_count、GET_TEMPLATE_OBJECT 从首字读 quasis 段数、
|
||
/// CONCAT_N 从首字读操作数总数、NEW_OBJECT 从 a 槽读属性数(键表)。
|
||
/// 反汇编 Display 与 IC 清零扫描共用此表,任何新增变长 ext opcode 必须在此登记。
|
||
pub fn ext_word_count(bytecode: &[Instr], pc: usize) -> usize {
|
||
let op = opcode(bytecode[pc]);
|
||
// IC 系固定 IC_EXT_WORDS 扩展字(多态槽组)。
|
||
if op.has_ic_ext_words() {
|
||
return IC_EXT_WORDS;
|
||
}
|
||
match op {
|
||
OpCode::SPILL
|
||
| OpCode::UNSPILL
|
||
| OpCode::CALL
|
||
| OpCode::CALL_NATIVE
|
||
| OpCode::NEW_EXPRESSION
|
||
| OpCode::SUPER_CALL
|
||
| OpCode::DEFINE_ACCESSOR
|
||
| OpCode::DEFINE_ACCESSOR_DYNAMIC
|
||
| OpCode::DEFINE_PROP_ATTRS
|
||
| OpCode::DEFINE_GLOBAL_PROP_C
|
||
| OpCode::DEFINE_GLOBAL_PROP_C_IF_ABSENT
|
||
| OpCode::DELETE_GLOBAL_PROP_C
|
||
| OpCode::DELETE_PROP_STATIC
|
||
| OpCode::REST_OBJECT
|
||
| OpCode::INIT_PRIVATE => 1,
|
||
OpCode::DEFINE_ACCESSOR_ATTRS
|
||
| OpCode::DEFINE_ACCESSOR_ATTRS_DYNAMIC
|
||
| OpCode::GET_PRIVATE
|
||
| OpCode::SET_PRIVATE
|
||
| OpCode::PRIVATE_BRAND_IN => 2,
|
||
// 逃出计数 ext:BREAK/CONTINUE/RETURN 恒带 2 个字——第一字
|
||
// pack_escape_counts(for-of/for-in 逃出层数打包),第二字 dispose_count
|
||
// (逃出资源条数);lower 对这三条无条件落 ext 字,dispatch 经
|
||
// read_escape_counts 消费,扫描必须同步跳过以免错位。
|
||
OpCode::BREAK | OpCode::CONTINUE | OpCode::RETURN => 2,
|
||
OpCode::CALL_SPREAD | OpCode::NEW_EXPRESSION_SPREAD | OpCode::SUPER_CALL_SPREAD => {
|
||
let header = bytecode.get(pc + 1).copied().unwrap_or(0);
|
||
1 + (header & 0xFF) as usize + ((header >> 8) & 0xFF) as usize
|
||
}
|
||
OpCode::TEMPLATE_STR => {
|
||
let header = bytecode.get(pc + 1).copied().unwrap_or(0);
|
||
1 + ((header >> 16) & 0xFFFF) as usize
|
||
}
|
||
// GET_TEMPLATE_OBJECT:ext[0]=quasis 段数 n,随后 2n 个交错 cooked/raw 字,
|
||
// 末尾 1 个 site 序号——总 ext 字数 = 2+2n,与 dispatch 逐字消费一致。
|
||
OpCode::GET_TEMPLATE_OBJECT => {
|
||
let n = bytecode.get(pc + 1).copied().unwrap_or(0) as usize;
|
||
2 + 2 * n
|
||
}
|
||
// CONCAT_N:ext[0]=n=操作数总数,ext 字数 = 1+(n-1) = n。
|
||
OpCode::CONCAT_N => bytecode.get(pc + 1).copied().unwrap_or(0) as usize,
|
||
OpCode::NEW_OBJECT => a(bytecode[pc]) as usize,
|
||
_ => 0,
|
||
}
|
||
}
|
||
|
||
/// 发射无条件跳转指令(`JMP`,偏移以 16 位补码编码)。
|
||
pub fn encode_jmp(offset: i16) -> Instr {
|
||
let lo = (offset as u16 & 0xFF) as u8;
|
||
let hi = ((offset as u16 >> 8) & 0xFF) as u8;
|
||
encode(OpCode::JMP, 0, lo, hi)
|
||
}
|
||
|
||
/// 发射 `JMP_IF_FALSE`:当 `rd` 寄存器为 falsy 时跳转。
|
||
pub fn encode_jmp_if_false(rd: u8, offset: i16) -> Instr {
|
||
let lo = (offset as u16 & 0xFF) as u8;
|
||
let hi = ((offset as u16 >> 8) & 0xFF) as u8;
|
||
encode(OpCode::JMP_IF_FALSE, rd, lo, hi)
|
||
}
|
||
|
||
/// 发射 `JMP_IF_TRUE`:当 `rd` 寄存器为 truthy 时跳转。
|
||
pub fn encode_jmp_if_true(rd: u8, offset: i16) -> Instr {
|
||
let lo = (offset as u16 & 0xFF) as u8;
|
||
let hi = ((offset as u16 >> 8) & 0xFF) as u8;
|
||
encode(OpCode::JMP_IF_TRUE, rd, lo, hi)
|
||
}
|
||
|
||
/// 发射 `JMP_IF_NULLISH`:当 `rd` 为 `null` / `undefined` 时跳转(`??` 短路)。
|
||
pub fn encode_jmp_if_nullish(rd: u8, offset: i16) -> Instr {
|
||
let lo = (offset as u16 & 0xFF) as u8;
|
||
let hi = ((offset as u16 >> 8) & 0xFF) as u8;
|
||
encode(OpCode::JMP_IF_NULLISH, rd, lo, hi)
|
||
}
|
||
|
||
/// 发射 `TRY_BEGIN`:标记 try 块开始,偏移指向 catch 处理器。
|
||
pub fn encode_try_begin(offset: i16) -> Instr {
|
||
let lo = (offset as u16 & 0xFF) as u8;
|
||
let hi = ((offset as u16 >> 8) & 0xFF) as u8;
|
||
encode(OpCode::TRY_BEGIN, 0, lo, hi)
|
||
}
|
||
|
||
/// 发射 `TRY_FINALLY_BEGIN`:标记 try/finally 块开始,偏移指向 finally 处理器。
|
||
pub fn encode_try_finally_begin(offset: i16) -> Instr {
|
||
let lo = (offset as u16 & 0xFF) as u8;
|
||
let hi = ((offset as u16 >> 8) & 0xFF) as u8;
|
||
encode(OpCode::TRY_FINALLY_BEGIN, 0, lo, hi)
|
||
}
|
||
|
||
#[cfg(test)]
|
||
mod tests {
|
||
use super::*;
|
||
|
||
/// 遍历全部有效 opcode(枚举字节序)。
|
||
fn all_opcodes() -> impl Iterator<Item = OpCode> {
|
||
(0u8..=u8::MAX).filter_map(|b| OpCode::try_from(b).ok())
|
||
}
|
||
|
||
#[test]
|
||
fn opcode_table_is_byte_identical() {
|
||
for byte in 0u8..=u8::MAX {
|
||
if let Ok(op) = OpCode::try_from(byte) {
|
||
assert_eq!(op as u8, byte, "discriminant mismatch for 0x{byte:02X}");
|
||
assert!(!op.to_string().is_empty(), "empty Display for 0x{byte:02X}");
|
||
}
|
||
}
|
||
|
||
assert_eq!(OpCode::ADD as u8, 0x00);
|
||
assert_eq!(OpCode::STRICT_EQ as u8, 0x1A);
|
||
assert_eq!(OpCode::JMP_IF_NULLISH as u8, 0x8F);
|
||
assert_eq!(OpCode::VOID as u8, 0xF3);
|
||
assert_eq!(OpCode::MOV as u8, 0x0C);
|
||
assert_eq!(OpCode::SPILL as u8, 0x0D);
|
||
assert_eq!(OpCode::UNSPILL as u8, 0x0E);
|
||
assert_eq!(OpCode::SPREAD_OBJECT as u8, 0x0F);
|
||
assert_eq!(OpCode::CREATE_ARGUMENTS as u8, 0x63);
|
||
assert_eq!(OpCode::CREATE_REST_ARRAY as u8, 0x6E);
|
||
assert_eq!(OpCode::DEFINE_ACCESSOR_DYNAMIC as u8, 0x7F);
|
||
assert_eq!(OpCode::SET_PROP_BATCH as u8, 0x92);
|
||
assert_eq!(OpCode::CONCAT_N as u8, 0x93);
|
||
assert_eq!(OpCode::DEFINE_ACCESSOR_ATTRS_DYNAMIC as u8, 0x9F);
|
||
assert_eq!(OpCode::ADD.to_string(), "ADD");
|
||
assert_eq!(OpCode::COMPOUND_MEMBER_EXP.to_string(), "COMPOUND_MEMBER_EXP");
|
||
assert_eq!(OpCode::MOV.to_string(), "MOV");
|
||
assert_eq!(OpCode::SPILL.to_string(), "SPILL");
|
||
assert_eq!(OpCode::UNSPILL.to_string(), "UNSPILL");
|
||
assert_eq!(OpCode::SPREAD_OBJECT.to_string(), "SPREAD_OBJECT");
|
||
|
||
assert!(OpCode::try_from(0xFA).is_err());
|
||
assert!(OpCode::try_from(0xFF).is_err());
|
||
}
|
||
|
||
/// 全 opcode 表遍历:jump/terminator/ic 三集合与 lower/cfg/vm 硬编码集合逐字节一致。
|
||
#[test]
|
||
fn semantics_golden_sets() {
|
||
let jump_set: Vec<u8> = 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<u8> = 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<u8> = all_opcodes().filter(|op| op.has_ic_ext_words()).map(|op| op as u8).collect();
|
||
assert_eq!(ic_set.len(), 16, "ic_ext 恰 16 个");
|
||
const _: () = assert!(IC_EXT_WORDS == IC_SLOTS * 2 && IC_SLOTS >= 2);
|
||
}
|
||
|
||
/// 表驱动 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<u8> = all_opcodes().filter(|op| op.has_ic_ext_words()).map(|op| op as u8).collect();
|
||
assert_eq!(tbl, legacy);
|
||
}
|
||
|
||
/// ext 字数表与 dispatch 逐字消费布局对齐(定长族 / 双字族 / 变长族)。
|
||
#[test]
|
||
fn ext_word_count_matches_dispatch_layout() {
|
||
// IC 族固定 8 字。
|
||
let ic = [encode(OpCode::IC_GET_PROP, 0, 0, 0); IC_EXT_WORDS + 1];
|
||
assert_eq!(ext_word_count(&ic, 0), IC_EXT_WORDS);
|
||
// 1 字族。
|
||
assert_eq!(ext_word_count(&[encode(OpCode::CALL, 0, 0, 0), 3], 0), 1);
|
||
// 2 字族(含 BREAK/CONTINUE/RETURN 逃出计数:迭代器打包字 + dispose_count 字)。
|
||
assert_eq!(ext_word_count(&[encode(OpCode::BREAK, 0, 0, 0), 1, 2], 0), 2);
|
||
assert_eq!(ext_word_count(&[encode(OpCode::RETURN, 0, 0, 0), 1, 2], 0), 2);
|
||
assert_eq!(ext_word_count(&[encode(OpCode::GET_PRIVATE, 0, 0, 0), 1, 2], 0), 2);
|
||
// 变长族:spread 首字 nstatic|nspread、TEMPLATE_STR 段数、GET_TEMPLATE_OBJECT 2+2n、
|
||
// CONCAT_N=n、NEW_OBJECT=a 槽属性数。
|
||
assert_eq!(ext_word_count(&[encode(OpCode::CALL_SPREAD, 0, 0, 0), 0x0201, 5, 6, 7], 0), 4);
|
||
assert_eq!(ext_word_count(&[encode(OpCode::TEMPLATE_STR, 0, 0, 0), 0x0002_0000, 1, 2], 0), 3);
|
||
assert_eq!(ext_word_count(&[encode(OpCode::GET_TEMPLATE_OBJECT, 0, 0, 0), 1, 2, 3, 4], 0), 4);
|
||
assert_eq!(ext_word_count(&[encode(OpCode::CONCAT_N, 0, 0, 0), 3, 1, 2], 0), 3);
|
||
assert_eq!(ext_word_count(&[encode(OpCode::NEW_OBJECT, 0, 2, 0), 7, 8], 0), 2);
|
||
// 无 ext 字。
|
||
assert_eq!(ext_word_count(&[encode(OpCode::ADD, 0, 0, 0)], 0), 0);
|
||
}
|
||
}
|