fix: class 方法/访问器/constructor/prototype 属性描述符(非枚举/只读),新增 DEFINE_PROP_ATTRS/DEFINE_ACCESSOR_ATTRS
- opcode.rs/inst.rs/contract.rs/vm.rs/vm_dispatch_ctrl.rs:新增两个带 attrs 扩展字的 define 指令 (attrs bit0=writable, bit1=enumerable, bit2=configurable,与 PropAttributes 一致) - class/method.rs:方法与非计算访问器改按规范非枚举安装(DefineMethod 语义) - class/prototype.rs:proto.constructor 非枚举;ctor.prototype 三标志全 false(MakeConstructor) - 效果:language/statements/class 1782 pass/948 fail -> 1910 pass/716 fail(+128/-232)
This commit is contained in:
@@ -486,6 +486,15 @@ define_opcodes! {
|
||||
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,
|
||||
|
||||
// ── 成员复合赋值:位/移位 (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)],
|
||||
|
||||
@@ -8,6 +8,9 @@ use oxide_ir::inst::Inst;
|
||||
use oxide_ir::operand::Operand;
|
||||
use oxide_parser::{ClassElement, MethodDefinitionKind, PropertyKey};
|
||||
|
||||
/// class 方法/访问器属性描述符:writable + configurable,enumerable = false(规范 DefineMethod)。
|
||||
const CLASS_METHOD_ATTRS: u32 = 0b101;
|
||||
|
||||
impl Emitter {
|
||||
pub(crate) fn emit_class_methods(
|
||||
&self, elements: &[ClassElement], ctor_reg: u32, proto_reg: u32, self_binding: &[(&str, u32)],
|
||||
@@ -39,21 +42,13 @@ impl Emitter {
|
||||
self.emit_class_method_function(method, &method_name, Operand::Reg(home_reg), ctx, self_binding)?;
|
||||
match method.kind {
|
||||
MethodDefinitionKind::Method => {
|
||||
if method.computed {
|
||||
ctx.inst(Inst::new(
|
||||
OpCode::SET_PROP_DYNAMIC,
|
||||
Operand::Reg(home_reg),
|
||||
Operand::Reg(key_reg),
|
||||
Operand::Reg(accessor_reg),
|
||||
));
|
||||
} else {
|
||||
ctx.inst(Inst::new(
|
||||
OpCode::SET_PROP,
|
||||
Operand::Reg(home_reg),
|
||||
Operand::Reg(accessor_reg),
|
||||
Operand::Reg(key_reg),
|
||||
));
|
||||
}
|
||||
// class 方法按规范为非枚举数据属性(DefineMethod:writable/configurable,enumerable=false)。
|
||||
ctx.inst(Inst::define_prop_attrs(
|
||||
Operand::Reg(home_reg),
|
||||
Operand::Reg(accessor_reg),
|
||||
Operand::Reg(key_reg),
|
||||
CLASS_METHOD_ATTRS,
|
||||
));
|
||||
}
|
||||
MethodDefinitionKind::Get | MethodDefinitionKind::Set => {
|
||||
if method.computed {
|
||||
@@ -67,11 +62,12 @@ impl Emitter {
|
||||
};
|
||||
let key_name = self.class_property_name(&method.key)?;
|
||||
let key_idx = ctx.add_constant(Constant::String(key_name));
|
||||
ctx.inst(Inst::define_accessor(
|
||||
ctx.inst(Inst::define_accessor_attrs(
|
||||
Operand::Reg(home_reg),
|
||||
Operand::Reg(get_reg),
|
||||
Operand::Reg(set_reg),
|
||||
key_idx as u32,
|
||||
CLASS_METHOD_ATTRS,
|
||||
));
|
||||
}
|
||||
MethodDefinitionKind::Constructor => continue,
|
||||
|
||||
@@ -42,20 +42,22 @@ impl Emitter {
|
||||
let ctor_key_idx = ctx.add_constant(Constant::String("constructor".to_string()));
|
||||
let ctor_key_reg = ctx.alloc_reg();
|
||||
ctx.inst(Inst::load_const(Operand::Reg(ctor_key_reg), ctor_key_idx));
|
||||
ctx.inst(Inst::new(
|
||||
OpCode::SET_PROP,
|
||||
// Class.prototype.constructor:writable/configurable,enumerable = false。
|
||||
ctx.inst(Inst::define_prop_attrs(
|
||||
Operand::Reg(proto_reg),
|
||||
Operand::Reg(ctor_reg),
|
||||
Operand::Reg(ctor_key_reg),
|
||||
0b101,
|
||||
));
|
||||
let proto_key_idx = ctx.add_constant(Constant::String("prototype".to_string()));
|
||||
let proto_key_reg = ctx.alloc_reg();
|
||||
ctx.inst(Inst::load_const(Operand::Reg(proto_key_reg), proto_key_idx));
|
||||
ctx.inst(Inst::new(
|
||||
OpCode::SET_PROP,
|
||||
// 类构造器 .prototype 属性:writable/enumerable/configurable 全 false(MakeConstructor)。
|
||||
ctx.inst(Inst::define_prop_attrs(
|
||||
Operand::Reg(ctor_reg),
|
||||
Operand::Reg(proto_reg),
|
||||
Operand::Reg(proto_key_reg),
|
||||
0b000,
|
||||
));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -761,6 +761,8 @@ mod tests {
|
||||
assert_group(&[OpCode::NEW_OBJECT, OpCode::NEW_ARRAY], Some(1), &[], true);
|
||||
// define 语义属性写入 / arguments / rest
|
||||
assert_group(&[OpCode::DEFINE_PROP, OpCode::DEFINE_GLOBAL_PROP], None, &[1, 2, 3], false);
|
||||
assert_contract(OpCode::DEFINE_PROP_ATTRS, None, &[1, 2, 3], false);
|
||||
assert_contract(OpCode::DEFINE_ACCESSOR_ATTRS, None, &[1, 2, 3], false);
|
||||
assert_group(&[OpCode::CREATE_ARGUMENTS, OpCode::CREATE_REST_ARRAY], Some(1), &[], false);
|
||||
// 成员更新:val 槽原地写(a/b 槽)
|
||||
assert_group(&[OpCode::MEMBER_INC, OpCode::MEMBER_DEC], Some(2), &[1, 3], false);
|
||||
|
||||
@@ -199,6 +199,11 @@ impl Inst {
|
||||
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 {
|
||||
@@ -211,6 +216,12 @@ impl Inst {
|
||||
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 {
|
||||
|
||||
@@ -1459,6 +1459,20 @@ impl Vm {
|
||||
self.dispatch_define_global_prop(rd, a, b)?;
|
||||
}
|
||||
|
||||
|
||||
OpCode::DEFINE_PROP_ATTRS => {
|
||||
let attrs = self.bytecode[self.pc] as u8;
|
||||
self.pc += 1;
|
||||
self.dispatch_define_prop_attrs(rd, a, b, attrs)?;
|
||||
}
|
||||
|
||||
OpCode::DEFINE_ACCESSOR_ATTRS => {
|
||||
let key_word = self.bytecode[self.pc];
|
||||
let attrs = self.bytecode[self.pc + 1] as u8;
|
||||
self.pc += 2;
|
||||
self.dispatch_define_accessor_attrs(rd, a, b, key_word, attrs)?;
|
||||
}
|
||||
|
||||
OpCode::RETURN => match self.dispatch_return(rd) {
|
||||
Ok(Some(result)) => return Ok(result),
|
||||
Ok(None) => {}
|
||||
|
||||
@@ -195,6 +195,50 @@ impl Vm {
|
||||
}
|
||||
}
|
||||
|
||||
/// define 数据属性并指定描述符:ext 字为 attrs(bit0=writable, bit1=enumerable, bit2=configurable,与 PropAttributes 位一致)。
|
||||
pub(crate) fn dispatch_define_prop_attrs(&mut self, rd: usize, a: usize, b: usize, attrs: u8) -> Result<(), String> {
|
||||
vm_trace!("DEFINE_PROP_ATTRS rd={} value={} key={} attrs={:#04b}", rd, a, b, attrs);
|
||||
let obj_val = self.regs[rd];
|
||||
if !obj_val.is_object() {
|
||||
return self.raise_type_error("DEFINE_PROP_ATTRS target is not object");
|
||||
}
|
||||
let prop_name_si = self.property_key_si(self.regs[b])?;
|
||||
let value = self.regs[a];
|
||||
let obj = unsafe { &mut *obj_val.as_js_object_ptr() };
|
||||
match self.define_data_property(obj, prop_name_si, value, PropAttributes(attrs)) {
|
||||
Ok(()) => Ok(()),
|
||||
Err(msg) => self.raise_error_kind("TypeError", &msg),
|
||||
}
|
||||
}
|
||||
|
||||
/// 定义访问器属性并指定描述符:ext = [key 常量下标, attrs],key 编码同 DEFINE_ACCESSOR。
|
||||
pub(crate) fn dispatch_define_accessor_attrs(
|
||||
&mut self, rd: usize, a: usize, b: usize, key_word: u32, attrs: u8,
|
||||
) -> Result<(), String> {
|
||||
vm_trace!("DEFINE_ACCESSOR_ATTRS rd={} getter={} setter={} attrs={:#04b}", rd, a, b, attrs);
|
||||
let prop_idx = key_word as usize;
|
||||
if prop_idx >= self.immutables().len() {
|
||||
return self.raise_type_error("DEFINE_ACCESSOR_ATTRS constant index out of bounds");
|
||||
}
|
||||
let key_val = self.immutables()[prop_idx];
|
||||
let prop_name_si = if key_val.is_int() {
|
||||
make_private_name_id(key_val.as_int().max(0) as u32)
|
||||
} else {
|
||||
self.property_key_si(key_val)?
|
||||
};
|
||||
let obj_val = self.regs[rd];
|
||||
if !obj_val.is_object() {
|
||||
return self.raise_type_error("DEFINE_ACCESSOR_ATTRS target is not object");
|
||||
}
|
||||
let getter = self.regs[a];
|
||||
let setter = self.regs[b];
|
||||
let obj = unsafe { &mut *obj_val.as_js_object_ptr() };
|
||||
match self.define_accessor_property(obj, prop_name_si, getter, setter, PropAttributes(attrs)) {
|
||||
Ok(()) => Ok(()),
|
||||
Err(msg) => self.raise_error_kind("TypeError", &msg),
|
||||
}
|
||||
}
|
||||
|
||||
/// 定义全局 var 绑定数据属性:rd=全局对象,a=值,b=键。
|
||||
/// 属性可写/可枚举/不可配置(CreateGlobalVarBinding 的属性描述符)。
|
||||
///
|
||||
|
||||
Reference in New Issue
Block a user