Files
OxideJS-New/crates/oxide_ir/src/inst.rs
T

527 lines
26 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! IR 指令结构 + 构造 API。
//!
//! `ext` 内部是裸 u32(lowering 直拼字节码扩展字)。扩展字的**数量与语义值编码**
//! 全部由 `inst_*` 构造 API 保证——emit 代码不直接触碰 `ext` 字段。
//! 寄存器 def/use 契约与副作用判定在 `contract` 模块(`impl Inst`,DCE/liveness 共用)。
use oxide_bytecode::opcode::{OpCode, IC_EXT_WORDS};
use smallvec::SmallVec;
use crate::operand::{LabelId, Operand};
/// IR 指令:opcode + 三个操作数槽(rd/a/b)+ 扩展字 `ext`。
/// `ext` 内部是裸 u32,其数量与语义值编码由下方 `inst_*` 构造 API 保证。
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Inst {
pub op: OpCode,
pub rd: Operand,
pub a: Operand,
pub b: Operand,
pub ext: SmallVec<[u32; 4]>,
}
impl Inst {
/// 基础构造:ext 为空。
pub fn new(op: OpCode, rd: Operand, a: Operand, b: Operand) -> Self {
Self {
op,
rd,
a,
b,
ext: SmallVec::new(),
}
}
fn with_ext(op: OpCode, rd: Operand, a: Operand, b: Operand, ext: &[u32]) -> Self {
Self {
op,
rd,
a,
b,
ext: SmallVec::from_slice(ext),
}
}
// ── IC 系:ext = [0; IC_EXT_WORDS](IC_SLOTS 组 shape/slot/proto 占位字,VM 运行时回填)──
/// 内联缓存读属性:结果写入 `dst`,属性键为 `key`。
pub fn ic_get(dst: Operand, key: Operand) -> Self {
Self::with_ext(OpCode::IC_GET_PROP, Operand::None, dst, key, &[0; IC_EXT_WORDS])
}
/// 内联缓存写属性:`obj[key] = value`。
pub fn ic_set(obj: Operand, value: Operand, key: Operand) -> Self {
Self::with_ext(OpCode::IC_SET_PROP, obj, value, key, &[0; IC_EXT_WORDS])
}
/// 成员自增:`obj[key]++`,val 为当前值寄存器。
pub fn member_inc(obj: Operand, val: Operand, key: Operand) -> Self {
Self::with_ext(OpCode::MEMBER_INC, obj, val, key, &[0; IC_EXT_WORDS])
}
/// 成员自减:`obj[key]--`,val 为当前值寄存器。
pub fn member_dec(obj: Operand, val: Operand, key: Operand) -> Self {
Self::with_ext(OpCode::MEMBER_DEC, obj, val, key, &[0; IC_EXT_WORDS])
}
/// 成员复合赋值加法:`obj[key] += val`。
pub fn compound_member_add(obj: Operand, val: Operand, key: Operand) -> Self {
Self::with_ext(OpCode::COMPOUND_MEMBER_ADD, obj, val, key, &[0; IC_EXT_WORDS])
}
/// 成员复合赋值减法:`obj[key] -= val`。
pub fn compound_member_sub(obj: Operand, val: Operand, key: Operand) -> Self {
Self::with_ext(OpCode::COMPOUND_MEMBER_SUB, obj, val, key, &[0; IC_EXT_WORDS])
}
/// 成员复合赋值乘法:`obj[key] *= val`。
pub fn compound_member_mul(obj: Operand, val: Operand, key: Operand) -> Self {
Self::with_ext(OpCode::COMPOUND_MEMBER_MUL, obj, val, key, &[0; IC_EXT_WORDS])
}
/// 成员复合赋值除法:`obj[key] /= val`。
pub fn compound_member_div(obj: Operand, val: Operand, key: Operand) -> Self {
Self::with_ext(OpCode::COMPOUND_MEMBER_DIV, obj, val, key, &[0; IC_EXT_WORDS])
}
/// 成员复合赋值取模:`obj[key] %= val`。
pub fn compound_member_mod(obj: Operand, val: Operand, key: Operand) -> Self {
Self::with_ext(OpCode::COMPOUND_MEMBER_MOD, obj, val, key, &[0; IC_EXT_WORDS])
}
/// 成员复合赋值指数:`obj[key] **= val`。
pub fn compound_member_exp(obj: Operand, val: Operand, key: Operand) -> Self {
Self::with_ext(OpCode::COMPOUND_MEMBER_EXP, obj, val, key, &[0; IC_EXT_WORDS])
}
/// 成员复合赋值按位与:`obj[key] &= val`。
pub fn compound_member_bit_and(obj: Operand, val: Operand, key: Operand) -> Self {
Self::with_ext(OpCode::COMPOUND_MEMBER_BIT_AND, obj, val, key, &[0; IC_EXT_WORDS])
}
/// 成员复合赋值按位或:`obj[key] |= val`。
pub fn compound_member_bit_or(obj: Operand, val: Operand, key: Operand) -> Self {
Self::with_ext(OpCode::COMPOUND_MEMBER_BIT_OR, obj, val, key, &[0; IC_EXT_WORDS])
}
/// 成员复合赋值按位异或:`obj[key] ^= val`。
pub fn compound_member_bit_xor(obj: Operand, val: Operand, key: Operand) -> Self {
Self::with_ext(OpCode::COMPOUND_MEMBER_BIT_XOR, obj, val, key, &[0; IC_EXT_WORDS])
}
/// 成员复合赋值左移:`obj[key] <<= val`。
pub fn compound_member_shl(obj: Operand, val: Operand, key: Operand) -> Self {
Self::with_ext(OpCode::COMPOUND_MEMBER_SHL, obj, val, key, &[0; IC_EXT_WORDS])
}
/// 成员复合赋值右移:`obj[key] >>= val`。
pub fn compound_member_shr(obj: Operand, val: Operand, key: Operand) -> Self {
Self::with_ext(OpCode::COMPOUND_MEMBER_SHR, obj, val, key, &[0; IC_EXT_WORDS])
}
/// 成员复合赋值无符号右移:`obj[key] >>>= val`。
pub fn compound_member_ushr(obj: Operand, val: Operand, key: Operand) -> Self {
Self::with_ext(OpCode::COMPOUND_MEMBER_USHR, obj, val, key, &[0; IC_EXT_WORDS])
}
// ── Call 系:ext = [nargs | (存活上界 << 8)] ──
// 低 8 位 nargs;高 8 位由 RegAlloc 后 `encode_call_window` 回填调用点存活
// 上界(窗口 regs[0..上界],0 = 全量)。emit 构造时高 8 位恒 0。
/// 普通函数调用:rd=callee,a=this,b=首参,ext=[nargs|(上界<<8)]。
/// 参数从 `first_arg` 起连续占 nargs 个寄存器。
pub fn call(callee: Operand, this: Operand, first_arg: Operand, nargs: u8) -> Self {
Self::with_ext(OpCode::CALL, callee, this, first_arg, &[nargs as u32])
}
/// 原生函数调用(内置),不经 JS 调用协议。
pub fn call_native(callee: Operand, this: Operand, first_arg: Operand, nargs: u8) -> Self {
Self::with_ext(OpCode::CALL_NATIVE, callee, this, first_arg, &[nargs as u32])
}
/// `new` 表达式:结果写入 `result`,构造函数为 `constructor`。ext 编码同 `call`。
pub fn new_expression(result: Operand, constructor: Operand, first_arg: Operand, nargs: u8) -> Self {
Self::with_ext(OpCode::NEW_EXPRESSION, result, constructor, first_arg, &[nargs as u32])
}
/// 派生类构造中的 `super(...)`:结果写入 `result`。ext 编码同 `call`。
pub fn super_call(result: Operand, first_arg: Operand, nargs: u8) -> Self {
Self::with_ext(OpCode::SUPER_CALL, result, first_arg, Operand::None, &[nargs as u32])
}
/// spread 实参调用:rd=callee,a=this,b 槽未用。
/// ext=[nstatic|(nspread<<8), 有序实参字…];每个实参字:静态实参为寄存器号,
/// spread 源为 `0x8000_0000 | 寄存器号`(高位标记),按源码求值序排列。
pub fn call_spread(callee: Operand, this: Operand, words: &[u32]) -> Self {
let ext = spread_ext(words);
Self::with_ext(OpCode::CALL_SPREAD, callee, this, Operand::None, &ext)
}
/// spread 实参 `new`:结果写入 `result`,构造函数为 `constructor`。
pub fn new_expression_spread(result: Operand, constructor: Operand, words: &[u32]) -> Self {
let ext = spread_ext(words);
Self::with_ext(OpCode::NEW_EXPRESSION_SPREAD, result, constructor, Operand::None, &ext)
}
/// 派生类构造中的 `super(...spread)`:结果写入 `result`。
pub fn super_call_spread(result: Operand, words: &[u32]) -> Self {
let ext = spread_ext(words);
Self::with_ext(OpCode::SUPER_CALL_SPREAD, result, Operand::None, Operand::None, &ext)
}
// ── 其他带 ext 字 ──
/// 私有成员读取:result=结果,obj=接收者,key=私有名 id。
/// ext = [brand_reg, brand_id]:brand_reg 为当前类 brand 对象寄存器(0 表示跳过
/// brand 检查,instance 字段路径),brand_id 为实例 brand 槽的私有名 id。
pub fn get_private(result: Operand, obj: Operand, key: Operand, brand_reg: u32, brand_id: u32) -> Self {
Self::with_ext(OpCode::GET_PRIVATE, result, obj, key, &[brand_reg, brand_id])
}
/// 私有名 `in` 判定:result=结果,obj=接收者,key=私有名 id。
/// ext = [brand_reg, brand_id]:brand_reg 为当前类 brand 对象寄存器(0 表示跳过
/// brand 检查),brand_id 为实例 brand 槽的私有名 id。判定 own 私有槽(字段)或
/// own brand(方法/访问器,槽在 home)——不跨原型链(PrivateFieldIn)。
pub fn private_brand_in(result: Operand, obj: Operand, key: Operand, brand_reg: u32, brand_id: u32) -> Self {
Self::with_ext(OpCode::PRIVATE_BRAND_IN, result, obj, key, &[brand_reg, brand_id])
}
/// 私有成员写入:obj=接收者,value=新值,key=私有名 id。ext 语义同 `get_private`。
pub fn set_private(obj: Operand, value: Operand, key: Operand, brand_reg: u32, brand_id: u32) -> Self {
Self::with_ext(OpCode::SET_PRIVATE, obj, value, key, &[brand_reg, brand_id])
}
/// 私有成员初始化:target=接收者,value=初值,key=私有名 id。
/// ext = [is_method]:1 表示私有方法槽(不可写),0 表示字段/brand 槽。
pub fn init_private(target: Operand, value: Operand, key: Operand, is_method: bool) -> Self {
Self::with_ext(OpCode::INIT_PRIVATE, target, value, key, &[is_method as u32])
}
/// 定义访问器属性:home 为宿主对象,get/set 为访问器函数寄存器,key_idx 为属性名常量下标。
pub fn define_accessor(home: Operand, get: Operand, set: Operand, key_idx: u32) -> Self {
Self::with_ext(OpCode::DEFINE_ACCESSOR, home, get, set, &[key_idx])
}
/// 定义访问器属性并指定描述符:ext = [key_idx, attrs](attrs 位同 DEFINE_PROP_ATTRS)。
pub fn define_accessor_attrs(home: Operand, get: Operand, set: Operand, key_idx: u32, attrs: u32) -> Self {
Self::with_ext(OpCode::DEFINE_ACCESSOR_ATTRS, home, get, set, &[key_idx, attrs])
}
/// 定义访问器属性(运行时计算键):home 为宿主对象,get/set 为访问器函数寄存器,
/// key_reg 为键值寄存器(编码进 ext[0],高位标记 `0x8000_0000 | key_reg`)。
pub fn define_accessor_dynamic(home: Operand, get: Operand, set: Operand, key_reg: u32) -> Self {
Self::with_ext(OpCode::DEFINE_ACCESSOR_DYNAMIC, home, get, set, &[0x8000_0000 | key_reg])
}
/// define 数据属性:target 为宿主对象,value/key 为寄存器。
/// 不触发原型链 setter,与 SET_PROP 语义不同。
pub fn define_prop(target: Operand, value: Operand, key: Operand) -> Self {
Self::new(OpCode::DEFINE_PROP, target, value, key)
}
/// define 数据属性并指定描述符:ext = [attrs](bit0=writable, bit1=enumerable, bit2=configurable,
/// 与 PropAttributes 位一致);class 方法/constructor/prototype 需要非枚举或不可写描述符。
pub fn define_prop_attrs(target: Operand, value: Operand, key: Operand, attrs: u32) -> Self {
Self::with_ext(OpCode::DEFINE_PROP_ATTRS, target, value, key, &[attrs])
}
/// 定义全局 var 绑定数据属性:target 为全局对象,value/key 为寄存器。
/// 属性可写/可枚举/不可配置(脚本顶层 var/function 声明的属性描述符)。
pub fn define_global_prop(target: Operand, value: Operand, key: Operand) -> Self {
Self::new(OpCode::DEFINE_GLOBAL_PROP, target, value, key)
}
/// 定义隐式全局数据属性:ext = [key_idx](键常量池下标),value 放 a 槽。
/// 全局对象由 VM 运行期从 session 解析(不依赖 this 寄存器),属性可写/可枚举/
/// 可配置(未声明标识符写与 eval 脚本 var/函数声明的属性描述符)。
pub fn define_global_prop_c(value: Operand, key_idx: u16) -> Self {
Self::with_ext(OpCode::DEFINE_GLOBAL_PROP_C, Operand::None, value, Operand::None, &[key_idx as u32])
}
/// 顶层 var 声明的全局属性 define-if-absent:target 为全局对象,value/key 为寄存器。
/// 既有属性零动作;缺失新建可写/可枚举/不可配置(脚本 GDI 序言,CreateGlobalVarBinding
/// 对既有数据描述符零修改)。
pub fn define_global_prop_if_absent(target: Operand, value: Operand, key: Operand) -> Self {
Self::new(OpCode::DEFINE_GLOBAL_PROP_IF_ABSENT, target, value, key)
}
/// eval 脚本顶层 var 声明的全局属性 define-if-absent:ext = [key_idx](键常量池
/// 下标),value 放 a 槽。既有属性零动作;缺失新建可写/可枚举/可配置。
pub fn define_global_prop_c_if_absent(value: Operand, key_idx: u16) -> Self {
Self::with_ext(
OpCode::DEFINE_GLOBAL_PROP_C_IF_ABSENT,
Operand::None,
value,
Operand::None,
&[key_idx as u32],
)
}
/// 顶层函数声明的全局绑定声明检查(GDI step 9):target 为全局对象,key 为
/// 声明名寄存器。运行期按 CanDeclareGlobalFunction 判定——撞既有不可配置
/// 非可写数据属性(或不可扩展上的缺失名)抛 TypeError。
pub fn can_declare_global_func(target: Operand, key: Operand) -> Self {
Self::new(OpCode::CAN_DECLARE_GLOBAL_FUNC, target, Operand::None, key)
}
/// 创建全局函数绑定(CreateGlobalFunctionBinding,脚本面 deletable=false):
/// target 为全局对象,value/key 为寄存器。缺失或既有可配置属性定义可写/可枚举/
/// 不可配置数据属性;既有不可配置可写数据属性仅更新值保描述符。
pub fn define_global_func_bind(target: Operand, value: Operand, key: Operand) -> Self {
Self::new(OpCode::DEFINE_GLOBAL_FUNC_BIND, target, value, key)
}
/// 静态删除属性:obj 同时放 rd/a 槽,const_idx 为属性名常量下标。
pub fn delete_prop_static(obj: Operand, const_idx: u32) -> Self {
Self::with_ext(OpCode::DELETE_PROP_STATIC, obj, obj, Operand::None, &[const_idx])
}
/// 删除全局内置数据属性(delete 标识符):ext = [key_idx](键常量池下标),
/// `result` 放 rd 槽(布尔删除结果),`slot` 放 a 槽(内置镜像槽寄存器,删除
/// 成功时写 undefined;无槽传 None)。全局对象由 VM 运行期从 session 解析。
pub fn delete_global_prop_c(result: Operand, slot: Operand, key_idx: u16) -> Self {
Self::with_ext(OpCode::DELETE_GLOBAL_PROP_C, result, slot, Operand::None, &[key_idx as u32])
}
/// 对象 rest 展开:`{...src, 排除 excluded_idx 常量列出的键}` 存入 `rest`。
/// `excl_arr` 为可选运行时 excluded 键数组寄存器(computed key 求值结果),
/// None 时仅用编译期 excluded_idx 常量。
pub fn rest_object(rest: Operand, src: Operand, excluded_idx: u32, excl_arr: Option<Operand>) -> Self {
Self::with_ext(OpCode::REST_OBJECT, rest, src, excl_arr.unwrap_or(Operand::None), &[excluded_idx])
}
/// 对象字面量 spread 展开:把源 `src` 的可枚举自有属性写入目标对象 `rd`(原地改)。
/// 语义 = CopyDataProperties 的"非 null/undefined 源":null/undefined 合法(空展开),
/// 与 REST_OBJECT(对 null/undefined 抛 TypeError)不同。
pub fn spread_object(target: Operand, src: Operand) -> Self {
Self::new(OpCode::SPREAD_OBJECT, target, src, Operand::None)
}
/// 对象字面量批量构造:`dst` 为新对象,a 槽编码纯静态数据键前缀的属性数(≤255),
/// ext 为每键的常量池下标(`Constant::String`)。运行时按键序链式预建 shape,
/// 后续逐个 `SET_PROP_BATCH` 纯槽写。
pub fn new_object(dst: Operand, nprops: u32, key_idxs: &[u32]) -> Self {
Self::with_ext(OpCode::NEW_OBJECT, dst, Operand::Imm(nprops as u16), Operand::None, key_idxs)
}
/// 对象字面量批量构造的纯槽写:`target[slot] = value`。slot 对应键序预建 shape 的槽位,
/// 不做键解析/形状变更。
pub fn set_prop_batch(target: Operand, value: Operand, slot: u16) -> Self {
Self::new(OpCode::SET_PROP_BATCH, target, value, Operand::Imm(slot))
}
/// 多操作数拼接(连续 `+` 表达式摊平):rd=结果,首操作数放 a 槽,
/// ext=[n, op2..opn](n=操作数总数,ext 字数 = 1+(n-1) = n)。
/// 操作数按源码求值序排列,emit 层保证 ≥3 个(<3 退化 ADD);op 字无高位标记。
pub fn concat_n(dst: Operand, operands: &[u32]) -> Self {
debug_assert!(operands.len() >= 3, "CONCAT_N 仅用于 ≥3 操作数摊平");
let mut ext = SmallVec::with_capacity(operands.len());
ext.push(operands.len() as u32);
ext.extend_from_slice(&operands[1..]);
Self {
op: OpCode::CONCAT_N,
rd: dst,
a: Operand::Reg(operands[0]),
b: Operand::None,
ext,
}
}
/// TEMPLATE_STR:变长 ext。首字打包 `(segment_count<<16) | total_len_hint`,
/// 后续每 quasi 一项 `quasi_const_idx & 0x7FFF_FFFF`,其后若跟表达式再一项 `0x8000_0000 | expr_reg`。
pub fn template_str(dst: Operand, segment_count: u32, total_len_hint: u16, parts: &[u32]) -> Self {
let mut ext = SmallVec::with_capacity(2 + parts.len());
ext.push(((segment_count & 0xFFFF) << 16) | (total_len_hint as u32 & 0xFFFF));
ext.extend_from_slice(parts);
Self {
op: OpCode::TEMPLATE_STR,
rd: dst,
a: Operand::None,
b: Operand::None,
ext,
}
}
/// GET_TEMPLATE_OBJECT:构建/取缓存模板对象(GetTemplateObject 语义)。
///
/// # ext 布局
/// - `ext[0]`:quasis 段数 n;
/// - `ext[1..=2n]`:每段交错两个字——cooked 字(`0x8000_0000` 高位标记
/// cooked 为 None(非法转义 → 元素为 undefined),低 31 位是常量池下标)
/// 与 raw 字(常量池下标);
/// - `ext[2n+1]`:site 序号(编译树内全局唯一,与模块 flat_id 组成缓存键)。
pub fn get_template_object(dst: Operand, site_no: u32, cooked_idx: &[u32], raw_idx: &[u16]) -> Self {
let n = cooked_idx.len();
let mut ext = SmallVec::with_capacity(2 + 2 * n);
ext.push(n as u32);
for i in 0..n {
ext.push(cooked_idx[i]);
ext.push(raw_idx[i] as u32);
}
ext.push(site_no);
Self {
op: OpCode::GET_TEMPLATE_OBJECT,
rd: dst,
a: Operand::None,
b: Operand::None,
ext,
}
}
// ── RegAlloc 辅助指令 ──
/// 寄存器复制 rd = a(RegAlloc 区间拆分时搬值)。
/// 不可用 LOAD_VAR/STORE_VAR 组合模拟——引入变量绑定语义会误触 const guard。
pub fn inst_mov(dst: Operand, src: Operand) -> Self {
Self::with_ext(OpCode::MOV, dst, src, Operand::None, &[])
}
/// 溢出:regs[rd] → spill_stack[frame_base + slot],ext=[slot u16]。
pub fn inst_spill(src: Operand, slot: u16) -> Self {
Self::with_ext(OpCode::SPILL, src, Operand::None, Operand::None, &[slot as u32])
}
/// 恢复:spill_stack[frame_base + slot] → regs[rd],ext=[slot u16]。
pub fn inst_unspill(dst: Operand, slot: u16) -> Self {
Self::with_ext(OpCode::UNSPILL, dst, Operand::None, Operand::None, &[slot as u32])
}
// ── 无 ext:立即数/索引指令(拆字是 lowering 职责)──
/// 加载常量池常量:`dst = constants[idx]`。a 槽 Const 下标由 lowering 拆字。
pub fn load_const(dst: Operand, idx: u16) -> Self {
Self::new(OpCode::LOAD_CONST, dst, Operand::Const(idx), Operand::None)
}
/// 创建闭包:`dst = nested[sub_idx]` 实例化。a 槽 Imm 子函数下标由 lowering 拆字。
pub fn create_closure(dst: Operand, sub_idx: u16) -> Self {
Self::new(OpCode::CREATE_CLOSURE, dst, Operand::Imm(sub_idx), Operand::None)
}
/// 创建 arguments 对象:`dst = 当前帧的实参列表`。运行时从当前帧
/// (CallFrame 或 inline 同步调用)的实参区构建,无寄存器 use。
pub fn create_arguments(dst: Operand) -> Self {
Self::new(OpCode::CREATE_ARGUMENTS, dst, Operand::None, Operand::None)
}
/// 创建 rest 参数数组:`dst = 当前帧实参区中下标 ≥ fixed_count 的实参组成的数组`。
/// `fixed_count` 为 rest 之前的固定形参数,编码进 b 槽(Imm 单字节),运行时
/// 与 CREATE_ARGUMENTS 同源读实参区,无寄存器 use。
pub fn create_rest_array(dst: Operand, fixed_count: u32) -> Self {
Self::new(OpCode::CREATE_REST_ARRAY, dst, Operand::None, Operand::Imm(fixed_count as u16))
}
/// 生成器让出:`rd` 为被让出的值;恢复时 `next(v)` 的 `v` 经 reg 0 交付
/// (与 CALL 同协议,emit 用 `LOAD_VAR(None)` 读取)。
pub fn yield_value(src: Operand) -> Self {
Self::new(OpCode::YIELD, src, Operand::None, Operand::None)
}
/// `yield*` 委托:`rd` 为内层可迭代对象。运行时取迭代器并转发 next/return/throw,
/// 委托完成值(内层 done 的 value)经 reg 0 交付,与 `yield_value` 同协议。
pub fn yield_star(src: Operand) -> Self {
Self::new(OpCode::YIELD_STAR, src, Operand::None, Operand::None)
}
/// 生成器 body 起点标记:调用时参数初始化完成后挂起于此,首次 `next()` 继续。
pub fn suspend_body() -> Self {
Self::new(OpCode::SUSPEND_BODY, Operand::None, Operand::None, Operand::None)
}
/// `await` 让出:`rd` 为被等待的值(运行时 PromiseResolve 包装);异步帧挂起,
/// promise settle 后恢复,值经 reg 0 交付(与 YIELD 同协议)。
pub fn await_expr(src: Operand) -> Self {
Self::new(OpCode::AWAIT, src, Operand::None, Operand::None)
}
// ── 跳转族:label 放 b 槽,offset 计算是 lowering 职责 ──
/// 无条件跳转。label 放 b 槽,offset 由 lowering 回填。
pub fn jmp(label: LabelId) -> Self {
Self::new(OpCode::JMP, Operand::None, Operand::None, Operand::Label(label))
}
/// break 完成:label 指向循环/switch 出口,`crossed` 为逃出的 finally 域数
/// (emit 词法计算,运行时据此逐个穿越 finally;0 表示未逃出,不产生完成语义)。
/// `for_of_count`/`for_in_count` 为逃出的迭代器层数,编码进 ext 字——
/// BREAK/CONTINUE 的 a/b 槽被跳转 offset 占用,无空闲位。
/// 编码:rd 槽放 crossed(≤255),label 放 b 槽,ext[0] 打包两个逃出计数。
pub fn brk(label: LabelId, crossed: u16, for_of_count: usize, for_in_count: usize) -> Self {
Self::with_ext(
OpCode::BREAK,
Operand::Imm(crossed),
Operand::None,
Operand::Label(label),
&[pack_escape_counts(for_of_count, for_in_count)],
)
}
/// continue 完成:同 break,label 指向循环继续目标。
pub fn cont(label: LabelId, crossed: u16, for_of_count: usize, for_in_count: usize) -> Self {
Self::with_ext(
OpCode::CONTINUE,
Operand::Imm(crossed),
Operand::None,
Operand::Label(label),
&[pack_escape_counts(for_of_count, for_in_count)],
)
}
/// return 完成:`src` 为返回值寄存器(None = 隐式 undefined,reg 0)。
/// `for_of_count`/`for_in_count` 为逃出的迭代器层数,编码进 ext 字。
pub fn ret(src: Operand, for_of_count: usize, for_in_count: usize) -> Self {
Self::with_ext(
OpCode::RETURN,
src,
Operand::None,
Operand::None,
&[pack_escape_counts(for_of_count, for_in_count)],
)
}
/// 条件寄存器为 false 时跳转。
pub fn jmp_if_false(cond_reg: u32, label: LabelId) -> Self {
Self::new(OpCode::JMP_IF_FALSE, Operand::Reg(cond_reg), Operand::None, Operand::Label(label))
}
/// 条件寄存器为 true 时跳转。
pub fn jmp_if_true(cond_reg: u32, label: LabelId) -> Self {
Self::new(OpCode::JMP_IF_TRUE, Operand::Reg(cond_reg), Operand::None, Operand::Label(label))
}
/// 条件寄存器为 null/undefined 时跳转(`??` / 可选链短路)。
pub fn jmp_if_nullish(cond_reg: u32, label: LabelId) -> Self {
Self::new(OpCode::JMP_IF_NULLISH, Operand::Reg(cond_reg), Operand::None, Operand::Label(label))
}
/// try 块起始,label 指向对应的 catch/finally 处理入口。
pub fn try_begin(label: LabelId) -> Self {
Self::new(OpCode::TRY_BEGIN, Operand::None, Operand::None, Operand::Label(label))
}
/// try-finally 块起始,label 指向 finally 入口。
pub fn try_finally_begin(label: LabelId) -> Self {
Self::new(OpCode::TRY_FINALLY_BEGIN, Operand::None, Operand::None, Operand::Label(label))
}
/// finally 体入口标记:运行时置位对应 try handler 的 `finally_active`。
pub fn try_finally_enter() -> Self {
Self::new(OpCode::TRY_FINALLY_ENTER, Operand::None, Operand::None, Operand::None)
}
}
/// 把逃出的 for-of / for-in 层数打包进一个 ext 字:低 16 位 for-of,高 16 位 for-in。
/// 层数受寄存器上限约束(每层循环消耗若干 vreg),16 位覆盖远超实际可能。
fn pack_escape_counts(for_of_count: usize, for_in_count: usize) -> u32 {
((for_in_count.min(0xFFFF) as u32) << 16) | (for_of_count.min(0xFFFF) as u32)
}
/// spread 调用系 ext 构造:首字打包 `nstatic | (nspread << 8)`,后续按源码求值序排列
/// 每个实参字(静态实参 = 寄存器号,spread 源 = `0x8000_0000 | 寄存器号`)。
fn spread_ext(words: &[u32]) -> SmallVec<[u32; 4]> {
let nspread = words.iter().filter(|w| *w >> 31 == 1).count() as u32;
let nstatic = (words.len() as u32) - nspread;
let mut ext = SmallVec::with_capacity(1 + words.len());
ext.push(nstatic | (nspread << 8));
ext.extend_from_slice(words);
ext
}