From 51da7ed3d95df986df0842e6bae4b39b00aea6f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=88=B1=E7=89=B9=E6=AF=8F=E7=BE=8A=E9=98=9F?= Date: Mon, 10 Aug 2026 23:28:18 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=20DEFINE=5FACCESSOR?= =?UTF-8?q?=5FDYNAMIC=20opcode=20=E6=94=AF=E6=8C=81=E8=AE=A1=E7=AE=97?= =?UTF-8?q?=E9=94=AE=E5=AF=B9=E8=B1=A1=E8=AE=BF=E9=97=AE=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crates/oxide_bytecode/src/opcode.rs | 8 +++ .../src/expr/object/object_literal.rs | 55 +++++++++++++------ crates/oxide_ir/src/contract.rs | 10 ++++ crates/oxide_ir/src/inst.rs | 13 +++++ crates/oxide_regalloc/src/graph.rs | 7 +++ crates/oxide_regalloc/src/rewrite.rs | 10 ++++ crates/oxide_vm/src/vm.rs | 4 ++ crates/oxide_vm/src/vm_dispatch_ctrl.rs | 25 +++++++-- 8 files changed, 110 insertions(+), 22 deletions(-) diff --git a/crates/oxide_bytecode/src/opcode.rs b/crates/oxide_bytecode/src/opcode.rs index 5eb5bdb..3af0eb7 100644 --- a/crates/oxide_bytecode/src/opcode.rs +++ b/crates/oxide_bytecode/src/opcode.rs @@ -28,6 +28,7 @@ pub enum Slot { /// - `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 { /// 读写对应操作数槽。 @@ -42,6 +43,8 @@ pub enum SlotSpec { TemplateExprs, /// ext[0] 的 brand 对象寄存器(0 跳过检查)。 BrandReg, + /// ext[0] 的寄存器(高位标记,与 SpreadArgs 同款编码)。 + ExtReg, } /// 单张语义表行:一个 opcode 的 def/uses/pure/跳转/终结/IC 扩展字声明。 @@ -570,6 +573,10 @@ define_opcodes! { 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", @@ -749,6 +756,7 @@ mod tests { 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::ADD.to_string(), "ADD"); assert_eq!(OpCode::COMPOUND_MEMBER_EXP.to_string(), "COMPOUND_MEMBER_EXP"); assert_eq!(OpCode::MOV.to_string(), "MOV"); diff --git a/crates/oxide_emit/src/expr/object/object_literal.rs b/crates/oxide_emit/src/expr/object/object_literal.rs index 2eb9b70..18c3933 100644 --- a/crates/oxide_emit/src/expr/object/object_literal.rs +++ b/crates/oxide_emit/src/expr/object/object_literal.rs @@ -40,18 +40,25 @@ impl Emitter { }; match p.kind { 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)?; - if let Some(sub_mod) = ctx.nested.last_mut() { - // 访问器函数名带 "get "/"set " 前缀(SetFunctionName 语义)。 - let fn_name = match p.kind { - PropertyKind::Get => format!("get {prop_name}"), - PropertyKind::Set => format!("set {prop_name}"), - _ => prop_name.clone(), - }; - sub_mod.function_name = Some(fn_name); + if !computed { + if let Some(sub_mod) = ctx.nested.last_mut() { + // 访问器函数名带 "get "/"set " 前缀(SetFunctionName 语义)。 + // 计算键的键值运行时才知,静态无法定名,保持匿名。 + let fn_name = match p.kind { + PropertyKind::Get => format!("get {prop_name}"), + PropertyKind::Set => format!("set {prop_name}"), + _ => prop_name.clone(), + }; + sub_mod.function_name = Some(fn_name); + } } let undef_reg = self.emit_undefined(ctx); let (get_reg, set_reg) = if p.kind == PropertyKind::Get { @@ -59,13 +66,25 @@ impl Emitter { } else { (undef_reg, accessor_reg) }; - 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, - )); + match key_reg { + Some(key_reg) => { + ctx.inst(Inst::define_accessor_dynamic( + Operand::Reg(obj_reg), + Operand::Reg(get_reg), + 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 { diff --git a/crates/oxide_ir/src/contract.rs b/crates/oxide_ir/src/contract.rs index 1d9a00b..fdd6d0b 100644 --- a/crates/oxide_ir/src/contract.rs +++ b/crates/oxide_ir/src/contract.rs @@ -39,6 +39,7 @@ impl Inst { /// - `SpreadArgs`:ext[1..] 每个字 `& 0x7FFF_FFFF`。 /// - `TemplateExprs`:ext[1..] 中 `seg>>31==1` 的低 8 位。 /// - `BrandReg`:ext[0] 非 0 才产生 use。 + /// - `ExtReg`:ext[0] `& 0x7FFF_FFFF`(高位标记的寄存器号)。 pub fn use_regs(&self) -> SmallVec<[u32; 4]> { let mut uses = SmallVec::new(); for &spec in self.op.semantics().uses { @@ -67,6 +68,10 @@ impl Inst { uses.push(brand_reg); } } + SlotSpec::ExtReg => { + let w = self.ext.first().copied().unwrap_or(0); + uses.push(w & 0x7FFF_FFFF); + } } } 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::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_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_DYNAMIC, Operand::Reg(0), Operand::None, Operand::Reg(2)).is_pure(&f)); // 调用 / 异常 / 控制流 @@ -568,6 +574,9 @@ mod tests { OpCode::DEFINE_ACCESSOR => { 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), _ => 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_contract(OpCode::SET_HOME_OBJECT, None, &[1, 2], 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 槽 assert_contract(OpCode::GET_PROP, Some(2), &[1, 3], false); assert_contract(OpCode::GET_PROP_DYNAMIC, Some(3), &[1, 2], false); diff --git a/crates/oxide_ir/src/inst.rs b/crates/oxide_ir/src/inst.rs index c0e84b5..c1a981d 100644 --- a/crates/oxide_ir/src/inst.rs +++ b/crates/oxide_ir/src/inst.rs @@ -199,6 +199,12 @@ impl Inst { 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 为寄存器。 /// 不触发原型链 setter,与 SET_PROP 语义不同。 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.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); assert_eq!(rest.ext.as_slice(), &[7]); diff --git a/crates/oxide_regalloc/src/graph.rs b/crates/oxide_regalloc/src/graph.rs index 600e011..3434f07 100644 --- a/crates/oxide_regalloc/src/graph.rs +++ b/crates/oxide_regalloc/src/graph.rs @@ -79,6 +79,13 @@ pub(super) fn collect_real_vregs(f: &IRFunction) -> BTreeSet { } } } + // 计算键访问器: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 } diff --git a/crates/oxide_regalloc/src/rewrite.rs b/crates/oxide_regalloc/src/rewrite.rs index faba134..01a2c5b 100644 --- a/crates/oxide_regalloc/src/rewrite.rs +++ b/crates/oxide_regalloc/src/rewrite.rs @@ -236,6 +236,16 @@ fn rewrite_inst( } 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(), }; // 调用点首参槽改指 arg_window_base(桥接后) diff --git a/crates/oxide_vm/src/vm.rs b/crates/oxide_vm/src/vm.rs index bb655af..3507b80 100644 --- a/crates/oxide_vm/src/vm.rs +++ b/crates/oxide_vm/src/vm.rs @@ -1441,6 +1441,10 @@ impl Vm { self.dispatch_define_accessor(rd, a, b)?; } + OpCode::DEFINE_ACCESSOR_DYNAMIC => { + self.dispatch_define_accessor_dynamic(rd, a, b)?; + } + OpCode::DEFINE_PROP => { self.dispatch_define_prop(rd, a, b)?; } diff --git a/crates/oxide_vm/src/vm_dispatch_ctrl.rs b/crates/oxide_vm/src/vm_dispatch_ctrl.rs index 2175dfb..86b40a5 100644 --- a/crates/oxide_vm/src/vm_dispatch_ctrl.rs +++ b/crates/oxide_vm/src/vm_dispatch_ctrl.rs @@ -126,10 +126,6 @@ impl Vm { if prop_idx >= self.immutables().len() { 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]; // 私有访问器:key 常量编码为 Int(私有名局部 id),映射到私有键高半区; // 普通访问器 key 是字符串常量,走 interner 键。 @@ -138,6 +134,27 @@ impl Vm { } else { 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 setter = self.regs[b]; let obj = unsafe { &mut *obj_val.as_js_object_ptr() };