feat: 新增 DEFINE_ACCESSOR_DYNAMIC opcode 支持计算键对象访问器

This commit is contained in:
爱特每羊队
2026-08-10 23:28:18 +08:00
parent 7e3d7b43b5
commit 51da7ed3d9
8 changed files with 110 additions and 22 deletions
+8
View File
@@ -28,6 +28,7 @@ pub enum Slot {
/// - `SpreadArgs`:ext[1..] 每个字 `& 0x7FFF_FFFF` 是实参寄存器(spread 源同低 31 位)。 /// - `SpreadArgs`:ext[1..] 每个字 `& 0x7FFF_FFFF` 是实参寄存器(spread 源同低 31 位)。
/// - `TemplateExprs`:TEMPLATE_STR 的 ext[1..],`seg>>31==1` 时低 8 位是表达式寄存器。 /// - `TemplateExprs`:TEMPLATE_STR 的 ext[1..],`seg>>31==1` 时低 8 位是表达式寄存器。
/// - `BrandReg`:ext[0] 是 brand 对象寄存器,0 表示跳过检查(不产生 use)。 /// - `BrandReg`:ext[0] 是 brand 对象寄存器,0 表示跳过检查(不产生 use)。
/// - `ExtReg`:ext[0] 是寄存器,高位标记 `0x8000_0000 | vreg`,低 31 位是 vreg。
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SlotSpec { pub enum SlotSpec {
/// 读写对应操作数槽。 /// 读写对应操作数槽。
@@ -42,6 +43,8 @@ pub enum SlotSpec {
TemplateExprs, TemplateExprs,
/// ext[0] 的 brand 对象寄存器(0 跳过检查)。 /// ext[0] 的 brand 对象寄存器(0 跳过检查)。
BrandReg, BrandReg,
/// ext[0] 的寄存器(高位标记,与 SpreadArgs 同款编码)。
ExtReg,
} }
/// 单张语义表行:一个 opcode 的 def/uses/pure/跳转/终结/IC 扩展字声明。 /// 单张语义表行:一个 opcode 的 def/uses/pure/跳转/终结/IC 扩展字声明。
@@ -570,6 +573,10 @@ define_opcodes! {
MAKE_CELL_FRESH = 0x7E => "MAKE_CELL_FRESH", MAKE_CELL_FRESH = 0x7E => "MAKE_CELL_FRESH",
def = None, uses = [SlotSpec::Slot(Slot::Rd)], def = None, uses = [SlotSpec::Slot(Slot::Rd)],
pure = false, jump = false, term = false, ic = false, 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) ── // ── 位运算 (0x80-0x8F) ──
BIT_AND = 0x80 => "BIT_AND", BIT_AND = 0x80 => "BIT_AND",
@@ -749,6 +756,7 @@ mod tests {
assert_eq!(OpCode::SPREAD_OBJECT as u8, 0x0F); assert_eq!(OpCode::SPREAD_OBJECT as u8, 0x0F);
assert_eq!(OpCode::CREATE_ARGUMENTS as u8, 0x63); assert_eq!(OpCode::CREATE_ARGUMENTS as u8, 0x63);
assert_eq!(OpCode::CREATE_REST_ARRAY as u8, 0x6E); assert_eq!(OpCode::CREATE_REST_ARRAY as u8, 0x6E);
assert_eq!(OpCode::DEFINE_ACCESSOR_DYNAMIC as u8, 0x7F);
assert_eq!(OpCode::ADD.to_string(), "ADD"); assert_eq!(OpCode::ADD.to_string(), "ADD");
assert_eq!(OpCode::COMPOUND_MEMBER_EXP.to_string(), "COMPOUND_MEMBER_EXP"); assert_eq!(OpCode::COMPOUND_MEMBER_EXP.to_string(), "COMPOUND_MEMBER_EXP");
assert_eq!(OpCode::MOV.to_string(), "MOV"); assert_eq!(OpCode::MOV.to_string(), "MOV");
@@ -40,18 +40,25 @@ impl Emitter {
}; };
match p.kind { match p.kind {
PropertyKind::Get | PropertyKind::Set => { PropertyKind::Get | PropertyKind::Set => {
if computed { // 计算键:键表达式先于访问器函数求值(规范求值序),键值运行时
return Err("computed object accessors not yet supported".into()); // 由 DEFINE_ACCESSOR_DYNAMIC 从 key_reg 读取。
} let key_reg = if computed {
Some(self.emit_expression(p.key.to_expression(), ctx)?)
} else {
None
};
let accessor_reg = self.emit_expression(&p.value, ctx)?; let accessor_reg = self.emit_expression(&p.value, ctx)?;
if let Some(sub_mod) = ctx.nested.last_mut() { if !computed {
// 访问器函数名带 "get "/"set " 前缀(SetFunctionName 语义)。 if let Some(sub_mod) = ctx.nested.last_mut() {
let fn_name = match p.kind { // 访问器函数名带 "get "/"set " 前缀(SetFunctionName 语义)。
PropertyKind::Get => format!("get {prop_name}"), // 计算键的键值运行时才知,静态无法定名,保持匿名。
PropertyKind::Set => format!("set {prop_name}"), let fn_name = match p.kind {
_ => prop_name.clone(), PropertyKind::Get => format!("get {prop_name}"),
}; PropertyKind::Set => format!("set {prop_name}"),
sub_mod.function_name = Some(fn_name); _ => prop_name.clone(),
};
sub_mod.function_name = Some(fn_name);
}
} }
let undef_reg = self.emit_undefined(ctx); let undef_reg = self.emit_undefined(ctx);
let (get_reg, set_reg) = if p.kind == PropertyKind::Get { let (get_reg, set_reg) = if p.kind == PropertyKind::Get {
@@ -59,13 +66,25 @@ impl Emitter {
} else { } else {
(undef_reg, accessor_reg) (undef_reg, accessor_reg)
}; };
let idx = ctx.add_constant(Constant::String(prop_name.to_string())); match key_reg {
ctx.inst(Inst::define_accessor( Some(key_reg) => {
Operand::Reg(obj_reg), ctx.inst(Inst::define_accessor_dynamic(
Operand::Reg(get_reg), Operand::Reg(obj_reg),
Operand::Reg(set_reg), Operand::Reg(get_reg),
idx as u32, Operand::Reg(set_reg),
)); key_reg,
));
}
None => {
let idx = ctx.add_constant(Constant::String(prop_name.to_string()));
ctx.inst(Inst::define_accessor(
Operand::Reg(obj_reg),
Operand::Reg(get_reg),
Operand::Reg(set_reg),
idx as u32,
));
}
}
} }
_ => { _ => {
let key_reg = if computed { let key_reg = if computed {
+10
View File
@@ -39,6 +39,7 @@ impl Inst {
/// - `SpreadArgs`:ext[1..] 每个字 `& 0x7FFF_FFFF`。 /// - `SpreadArgs`:ext[1..] 每个字 `& 0x7FFF_FFFF`。
/// - `TemplateExprs`:ext[1..] 中 `seg>>31==1` 的低 8 位。 /// - `TemplateExprs`:ext[1..] 中 `seg>>31==1` 的低 8 位。
/// - `BrandReg`:ext[0] 非 0 才产生 use。 /// - `BrandReg`:ext[0] 非 0 才产生 use。
/// - `ExtReg`:ext[0] `& 0x7FFF_FFFF`(高位标记的寄存器号)。
pub fn use_regs(&self) -> SmallVec<[u32; 4]> { pub fn use_regs(&self) -> SmallVec<[u32; 4]> {
let mut uses = SmallVec::new(); let mut uses = SmallVec::new();
for &spec in self.op.semantics().uses { for &spec in self.op.semantics().uses {
@@ -67,6 +68,10 @@ impl Inst {
uses.push(brand_reg); uses.push(brand_reg);
} }
} }
SlotSpec::ExtReg => {
let w = self.ext.first().copied().unwrap_or(0);
uses.push(w & 0x7FFF_FFFF);
}
} }
} }
uses uses
@@ -418,6 +423,7 @@ mod tests {
assert!(!Inst::new(OpCode::SET_PROP, Operand::Reg(0), Operand::Reg(1), Operand::Reg(2)).is_pure(&f)); assert!(!Inst::new(OpCode::SET_PROP, Operand::Reg(0), Operand::Reg(1), Operand::Reg(2)).is_pure(&f));
assert!(!Inst::new(OpCode::SUPER_GET_PROP, Operand::Reg(0), Operand::Reg(1), Operand::Reg(2)).is_pure(&f)); assert!(!Inst::new(OpCode::SUPER_GET_PROP, Operand::Reg(0), Operand::Reg(1), Operand::Reg(2)).is_pure(&f));
assert!(!Inst::new(OpCode::DEFINE_ACCESSOR, Operand::Reg(0), Operand::Reg(1), Operand::Reg(2)).is_pure(&f)); assert!(!Inst::new(OpCode::DEFINE_ACCESSOR, Operand::Reg(0), Operand::Reg(1), Operand::Reg(2)).is_pure(&f));
assert!(!Inst::new(OpCode::DEFINE_ACCESSOR_DYNAMIC, Operand::Reg(0), Operand::Reg(1), Operand::Reg(2)).is_pure(&f));
assert!(!Inst::new(OpCode::DELETE_PROP_STATIC, Operand::Reg(0), Operand::Reg(0), Operand::None).is_pure(&f)); assert!(!Inst::new(OpCode::DELETE_PROP_STATIC, Operand::Reg(0), Operand::Reg(0), Operand::None).is_pure(&f));
assert!(!Inst::new(OpCode::DELETE_PROP_DYNAMIC, Operand::Reg(0), Operand::None, Operand::Reg(2)).is_pure(&f)); assert!(!Inst::new(OpCode::DELETE_PROP_DYNAMIC, Operand::Reg(0), Operand::None, Operand::Reg(2)).is_pure(&f));
// 调用 / 异常 / 控制流 // 调用 / 异常 / 控制流
@@ -568,6 +574,9 @@ mod tests {
OpCode::DEFINE_ACCESSOR => { OpCode::DEFINE_ACCESSOR => {
Inst::define_accessor(Operand::Reg(1), Operand::Reg(2), Operand::Reg(3), 42) Inst::define_accessor(Operand::Reg(1), Operand::Reg(2), Operand::Reg(3), 42)
} }
OpCode::DEFINE_ACCESSOR_DYNAMIC => {
Inst::define_accessor_dynamic(Operand::Reg(1), Operand::Reg(2), Operand::Reg(3), 7)
}
OpCode::DELETE_PROP_STATIC => Inst::delete_prop_static(Operand::Reg(1), 9), OpCode::DELETE_PROP_STATIC => Inst::delete_prop_static(Operand::Reg(1), 9),
_ => Inst::new(op, Operand::Reg(1), Operand::Reg(2), Operand::Reg(3)), _ => Inst::new(op, Operand::Reg(1), Operand::Reg(2), Operand::Reg(3)),
} }
@@ -740,6 +749,7 @@ mod tests {
assert_group(&[OpCode::SUPER_GET_PROP, OpCode::SUPER_STATIC_GET_PROP], Some(1), &[2, 3], false); 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::SET_HOME_OBJECT, None, &[1, 2], false);
assert_contract(OpCode::DEFINE_ACCESSOR, None, &[1, 2, 3], false); assert_contract(OpCode::DEFINE_ACCESSOR, None, &[1, 2, 3], false);
assert_contract(OpCode::DEFINE_ACCESSOR_DYNAMIC, None, &[1, 2, 3, 7], false);
// Object Property:GET_PROP 写 a 槽、DYNAMIC 写 b 槽 // Object Property:GET_PROP 写 a 槽、DYNAMIC 写 b 槽
assert_contract(OpCode::GET_PROP, Some(2), &[1, 3], false); assert_contract(OpCode::GET_PROP, Some(2), &[1, 3], false);
assert_contract(OpCode::GET_PROP_DYNAMIC, Some(3), &[1, 2], false); assert_contract(OpCode::GET_PROP_DYNAMIC, Some(3), &[1, 2], false);
+13
View File
@@ -199,6 +199,12 @@ impl Inst {
Self::with_ext(OpCode::DEFINE_ACCESSOR, home, get, set, &[key_idx]) Self::with_ext(OpCode::DEFINE_ACCESSOR, home, get, set, &[key_idx])
} }
/// 定义访问器属性(运行时计算键):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 为寄存器。 /// define 数据属性:target 为宿主对象,value/key 为寄存器。
/// 不触发原型链 setter,与 SET_PROP 语义不同。 /// 不触发原型链 setter,与 SET_PROP 语义不同。
pub fn define_prop(target: Operand, value: Operand, key: Operand) -> Self { pub fn define_prop(target: Operand, value: Operand, key: Operand) -> Self {
@@ -428,6 +434,13 @@ mod tests {
assert_eq!(accessor.a, Operand::Reg(1)); assert_eq!(accessor.a, Operand::Reg(1));
assert_eq!(accessor.b, Operand::Reg(2)); assert_eq!(accessor.b, Operand::Reg(2));
let dyn_accessor = Inst::define_accessor_dynamic(Operand::Reg(0), Operand::Reg(1), Operand::Reg(2), 7);
assert_eq!(dyn_accessor.op, OpCode::DEFINE_ACCESSOR_DYNAMIC);
assert_eq!(dyn_accessor.ext.as_slice(), &[0x8000_0000 | 7]);
assert_eq!(dyn_accessor.rd, Operand::Reg(0));
assert_eq!(dyn_accessor.a, Operand::Reg(1));
assert_eq!(dyn_accessor.b, Operand::Reg(2));
let rest = Inst::rest_object(Operand::Reg(0), Operand::Reg(1), 7, None); let rest = Inst::rest_object(Operand::Reg(0), Operand::Reg(1), 7, None);
assert_eq!(rest.ext.as_slice(), &[7]); assert_eq!(rest.ext.as_slice(), &[7]);
+7
View File
@@ -79,6 +79,13 @@ pub(super) fn collect_real_vregs(f: &IRFunction) -> BTreeSet<u32> {
} }
} }
} }
// 计算键访问器:ext[0] 是 key 寄存器(高位标记 `0x8000_0000 | vreg`)。
if inst.op == OpCode::DEFINE_ACCESSOR_DYNAMIC {
let r = inst.ext.first().copied().unwrap_or(0) & 0x7FFF_FFFF;
if r != 0 {
real.insert(r);
}
}
} }
real real
} }
+10
View File
@@ -236,6 +236,16 @@ fn rewrite_inst(
} }
ext ext
} }
// DEFINE_ACCESSOR_DYNAMIC:ext[0] 是 key 寄存器(高位标记 `0x8000_0000 | vreg`),
// 低 31 位重映射后保留高位标记。
OpCode::DEFINE_ACCESSOR_DYNAMIC => {
let mut ext = inst.ext.clone();
if let Some(word) = ext.first_mut() {
let nr = remap_ext_reg(*word & 0x7FFF_FFFF, slot_color, map);
*word = 0x8000_0000 | nr;
}
ext
}
_ => inst.ext.clone(), _ => inst.ext.clone(),
}; };
// 调用点首参槽改指 arg_window_base(桥接后) // 调用点首参槽改指 arg_window_base(桥接后)
+4
View File
@@ -1441,6 +1441,10 @@ impl Vm {
self.dispatch_define_accessor(rd, a, b)?; self.dispatch_define_accessor(rd, a, b)?;
} }
OpCode::DEFINE_ACCESSOR_DYNAMIC => {
self.dispatch_define_accessor_dynamic(rd, a, b)?;
}
OpCode::DEFINE_PROP => { OpCode::DEFINE_PROP => {
self.dispatch_define_prop(rd, a, b)?; self.dispatch_define_prop(rd, a, b)?;
} }
+21 -4
View File
@@ -126,10 +126,6 @@ impl Vm {
if prop_idx >= self.immutables().len() { if prop_idx >= self.immutables().len() {
return self.raise_type_error("DEFINE_ACCESSOR constant index out of bounds"); return self.raise_type_error("DEFINE_ACCESSOR constant index out of bounds");
} }
let obj_val = self.regs[rd];
if !obj_val.is_object() {
return self.raise_type_error("DEFINE_ACCESSOR target is not object");
}
let key_val = self.immutables()[prop_idx]; let key_val = self.immutables()[prop_idx];
// 私有访问器:key 常量编码为 Int(私有名局部 id),映射到私有键高半区; // 私有访问器:key 常量编码为 Int(私有名局部 id),映射到私有键高半区;
// 普通访问器 key 是字符串常量,走 interner 键。 // 普通访问器 key 是字符串常量,走 interner 键。
@@ -138,6 +134,27 @@ impl Vm {
} else { } else {
self.property_key_si(key_val) self.property_key_si(key_val)
}; };
self.dispatch_define_accessor_common(rd, a, b, prop_name_si)
}
/// 计算键访问器:ext[0] 高位标记 `0x8000_0000 | key_reg`,键值运行时从寄存器读取。
pub(crate) fn dispatch_define_accessor_dynamic(&mut self, rd: usize, a: usize, b: usize) -> Result<(), String> {
vm_trace!("DEFINE_ACCESSOR_DYNAMIC rd={} getter={} setter={}", rd, a, b);
let key_word = self.bytecode[self.pc];
self.pc += 1;
let key_reg = (key_word & 0x7FFF_FFFF) as usize;
let prop_name_si = self.property_key_si(self.regs[key_reg]);
self.dispatch_define_accessor_common(rd, a, b, prop_name_si)
}
/// 访问器定义公共路径:读 get/set 槽、合并已有访问器、写属性。
fn dispatch_define_accessor_common(
&mut self, rd: usize, a: usize, b: usize, prop_name_si: u32,
) -> Result<(), String> {
let obj_val = self.regs[rd];
if !obj_val.is_object() {
return self.raise_type_error("DEFINE_ACCESSOR target is not object");
}
let getter = self.regs[a]; let getter = self.regs[a];
let setter = self.regs[b]; let setter = self.regs[b];
let obj = unsafe { &mut *obj_val.as_js_object_ptr() }; let obj = unsafe { &mut *obj_val.as_js_object_ptr() };