feat: 对象方法 super 门加计算型 super 成员加 VM 步序对齐

This commit is contained in:
2026-10-10 01:09:06 +00:00
parent b6219188e7
commit c38e91a65a
11 changed files with 459 additions and 137 deletions
+49 -18
View File
@@ -202,6 +202,19 @@ impl Vm {
is_derived_constructor,
needs_home_object,
);
// 箭头函数词法继承 super 上下文:home object 从外层函数(当前 callee)
// 继承。类方法由 SET_HOME_OBJECT 显式挂接,不经此路径。
if is_arrow && needs_home_object {
if let Some(callee) = self.current_callee() {
if callee.is_object() {
let home = unsafe { &*callee.as_js_object_ptr() }.home_object();
if home.is_object() {
let func_obj = unsafe { &mut *result.as_js_object_ptr() };
func_obj.set_home_object(home);
}
}
}
}
// 函数名推断:emit 端在变量声明/对象属性赋值点设置 function_name。
let func_obj = unsafe { &mut *result.as_js_object_ptr() };
let length_si = self.length_si;
@@ -642,18 +655,25 @@ impl Vm {
return Ok(true);
}
let super_obj = unsafe { &*super_ctor.as_js_object_ptr() };
if !super_obj.is_function() {
self.raise_error_kind("TypeError", "super constructor is not a function")?;
return Ok(true);
}
if super_obj.native_fn().is_some() {
// 实参先物化再走同步调用收口:native 调用协议把 253/254 槽固定为
// 实参先物化再走 IsConstructor 检查(规范序:ArgumentListEvaluation
// 先于 IsConstructor);native 调用协议把 253/254 槽固定为
// receiver/callee,实参寄存器(颜色 ≤253)占位 253 时裸引用会被覆写
// (与 SUPER_CALL_SPREAD 路径同形)。
let args: Vec<JsValue> = (0..arg_count)
.map(|i| self.regs[first_arg_reg.wrapping_add(i as u8) as usize])
.collect();
if !super_obj.is_function() {
self.raise_error_kind("TypeError", "super constructor is not a function")?;
return Ok(true);
}
// native 函数仅带构造器类型标时可构造(与 NEW 路径同口径):
// 非构造器 proto 的 super 调用在实参求值后抛 TypeError。
if super_obj.type_tag != JsObject::OBJ_TYPE_CONSTRUCTOR {
self.raise_error_kind("TypeError", "super constructor is not a constructor")?;
return Ok(true);
}
// 构造形态标记夹持(SUPER native 臂不写 reg255,new.target 继承
// 外层类构造器帧,形态判定只能靠本标记)。
let saved_constructing = self.constructing_native;
@@ -742,8 +762,6 @@ impl Vm {
pub(crate) fn dispatch_super_get_prop(&mut self, rd: usize, a: usize, b: usize) -> Result<bool, String> {
vm_trace!("SUPER_GET_PROP rd={} a={} b={}", rd, a, b);
let key_val = self.regs[b];
let prop_name_si = self.property_key_si(key_val)?;
let Some(frame) = self.frames.last() else {
self.raise_error_kind("ReferenceError", "super property used outside function")?;
return Ok(true);
@@ -759,15 +777,19 @@ impl Vm {
return Ok(true);
}
let home_obj = unsafe { &*home_object.as_js_object_ptr() };
// 规范步序:GetSuperBase 先于 ToPropertyKey;基非对象可强转时抛
// TypeError(RequireObjectCoercible 面)。
let super_base = home_obj.proto();
if !super_base.is_object() {
self.regs[rd] = JsValue::undefined();
} else {
let super_obj = unsafe { &*super_base.as_js_object_ptr() };
let val = self.ordinary_get_with_target(super_obj, prop_name_si, self.regs[a], rd as u8)?;
if self.accessor_frame_target_reg.take().is_none() {
self.regs[rd] = val;
}
self.raise_type_error("Cannot convert null or undefined to object")?;
return Ok(true);
}
let key_val = self.regs[b];
let prop_name_si = self.property_key_si(key_val)?;
let super_obj = unsafe { &*super_base.as_js_object_ptr() };
let val = self.ordinary_get_with_target(super_obj, prop_name_si, self.regs[a], rd as u8)?;
if self.accessor_frame_target_reg.take().is_none() {
self.regs[rd] = val;
}
Ok(false)
}
@@ -1174,17 +1196,26 @@ impl Vm {
return Ok(true);
}
let super_obj = unsafe { &*super_ctor.as_js_object_ptr() };
if !super_obj.is_function() {
self.raise_error_kind("TypeError", "super constructor is not a function")?;
return Ok(true);
}
let args = match self.materialize_spread_args(&words)? {
Some(args) => args,
None => return Ok(true),
};
// IsConstructor 检查在实参物化之后(规范序:ArgumentListEvaluation
// 先于 IsConstructor)。
if !super_obj.is_function() {
self.raise_error_kind("TypeError", "super constructor is not a function")?;
return Ok(true);
}
if super_obj.native_fn().is_some() {
// native 函数仅带构造器类型标时可构造(与 NEW 路径同口径):
// 非构造器 proto 的 super 调用在实参求值后抛 TypeError。
if super_obj.type_tag != JsObject::OBJ_TYPE_CONSTRUCTOR {
self.raise_error_kind("TypeError", "super constructor is not a constructor")?;
return Ok(true);
}
// 构造形态标记夹持(SUPER native 臂不写 reg255,new.target 继承
// 外层类构造器帧,形态判定只能靠本标记)。
let saved_constructing = self.constructing_native;
@@ -0,0 +1,191 @@
//! super 属性读运行期面:对象字面量方法门、home object 挂接、嵌套箭头继承、
//! null-proto 抛 TypeError、GetSuperBase 先于 ToPropertyKey、super 调用 IsConstructor
//! 后移、派生构造器 this 未初始化键求值面。
use std::sync::Arc;
use oxide_compiler::compiler::Compiler;
use oxide_types::value::JsValue;
use oxide_vm::vm::Vm;
fn eval(vm: &mut Vm, source: &str) -> Result<JsValue, String> {
let allocator = oxide_parser::Allocator::default();
let program = oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?;
let module = Compiler::new().compile(&program).map_err(|e| format!("Compile error: {}", e))?;
vm.run(&Arc::new(module))
}
// 对象方法 super.x 读:proto 链取值,receiver 为方法接收者。
#[test]
fn object_method_super_read_walks_proto_chain() {
let mut vm = Vm::new();
let result = eval(
&mut vm,
"var A = { fromA: 'a', fromB: 'a' }; var B = { fromB: 'b' }; \
Object.setPrototypeOf(B, A); \
var obj = { fromA: 'c', fromB: 'c', method() { return super.fromA + '|' + super.fromB; } }; \
Object.setPrototypeOf(obj, B); obj.method()",
)
.unwrap();
assert_eq!(vm.lookup_str(result).unwrap(), "a|b");
}
// 对象方法内嵌套箭头继承 super 上下文:home object 从外层方法继承。
#[test]
fn object_method_nested_arrow_inherits_super() {
let mut vm = Vm::new();
let result = eval(
&mut vm,
"var A = { fromA: 'a', fromB: 'a' }; var B = { fromB: 'b' }; \
Object.setPrototypeOf(B, A); \
var obj = { method() { return (() => super.fromA + super.fromB)(); } }; \
Object.setPrototypeOf(obj, B); obj.method()",
)
.unwrap();
assert_eq!(vm.lookup_str(result).unwrap(), "ab");
}
// home proto 为 null 时 super 读抛 TypeError(RequireObjectCoercible 面)。
#[test]
fn object_method_super_read_null_proto_throws_type_error() {
let mut vm = Vm::new();
let err = eval(
&mut vm,
"var obj = { method() { return super.x; } }; \
Object.setPrototypeOf(obj, null); \
try { obj.method(); } catch (e) { e.name; }",
)
.unwrap();
assert_eq!(vm.lookup_str(err).unwrap(), "TypeError");
}
// 键对象 toString 副作用换 proto:GetSuperBase 先于 ToPropertyKey,读旧 proto 值。
#[test]
fn object_method_super_read_getsuperbase_before_topropertykey() {
let mut vm = Vm::new();
let result = eval(
&mut vm,
"var proto = { p: 'ok' }; var proto2 = { p: 'bad' }; \
var obj = { __proto__: proto, m() { return super[key]; } }; \
var key = { toString() { Object.setPrototypeOf(obj, proto2); return 'p'; } }; \
obj.m()",
)
.unwrap();
assert_eq!(vm.lookup_str(result).unwrap(), "ok");
}
// super 调用 IsConstructor 检查在实参物化之后:非构造器 proto 时实参副作用先执行。
#[test]
fn super_call_evaluates_args_before_is_constructor() {
let mut vm = Vm::new();
let result = eval(
&mut vm,
"var evaluatedArg = false; var caught; \
class C extends Object { constructor() { \
try { super(evaluatedArg = true); } catch (err) { caught = err; } \
} } \
Object.setPrototypeOf(C, parseInt); \
try { new C(); } catch (_) {} \
evaluatedArg + '|' + (caught ? caught.name : 'none')",
)
.unwrap();
assert_eq!(vm.lookup_str(result).unwrap(), "true|TypeError");
}
// 派生构造器 this 未初始化时 super[键]:GetThisBinding 先于键求值,抛 ReferenceError。
#[test]
fn derived_ctor_super_computed_uninitialized_this_throws_reference_error() {
let mut vm = Vm::new();
let result = eval(
&mut vm,
"class Base { constructor() { throw new Error('base constructor'); } } \
class Derived extends Base { constructor() { return super[super()]; } } \
try { new Derived(); } catch (e) { e.name; }",
)
.unwrap();
assert_eq!(vm.lookup_str(result).unwrap(), "ReferenceError");
}
// 对象 getter 内 super.x(Get/Set 臂 home object 面)。
#[test]
fn object_getter_super_read_uses_home_object() {
let mut vm = Vm::new();
let result = eval(
&mut vm,
"var A = { v: 'a' }; var B = { v: 'b' }; Object.setPrototypeOf(B, A); \
var obj = { get g() { return super.v; } }; \
Object.setPrototypeOf(obj, B); obj.g",
)
.unwrap();
assert_eq!(vm.lookup_str(result).unwrap(), "b");
}
// 对象 setter 内 super.x(Set 臂 home object 面)。
#[test]
fn object_setter_super_read_uses_home_object() {
let mut vm = Vm::new();
let result = eval(
&mut vm,
"var A = { v: 'a' }; var B = { v: 'b' }; Object.setPrototypeOf(B, A); \
var seen; var obj = { set s(x) { seen = super.v; } }; \
Object.setPrototypeOf(obj, B); obj.s = 1; seen",
)
.unwrap();
assert_eq!(vm.lookup_str(result).unwrap(), "b");
}
// 类表达式值不挂外层对象作 home:其方法 super 读以类自身 proto 为基。
#[test]
fn class_expression_value_not_homed_to_outer_object() {
let mut vm = Vm::new();
let result = eval(
&mut vm,
"function Base() {} Base.prototype.q = 'base'; \
var C = class extends Base { m() { return super.q; } }; \
var o = { c: C }; new C().m()",
)
.unwrap();
assert_eq!(vm.lookup_str(result).unwrap(), "base");
}
// 对象方法 super 调用:callee 为 proto 链上的方法,receiver 为方法接收者。
#[test]
fn object_method_super_call_walks_proto_chain() {
let mut vm = Vm::new();
let result = eval(
&mut vm,
"var A = { f() { return 'A:' + this.tag; } }; var B = { f() { return 'B:' + this.tag; } }; \
Object.setPrototypeOf(B, A); \
var obj = { tag: 't', m() { return super.f(); } }; \
Object.setPrototypeOf(obj, B); obj.m()",
)
.unwrap();
assert_eq!(vm.lookup_str(result).unwrap(), "B:t");
}
// 类方法 super 计算成员读:this 未初始化(派生构造器)时抛 ReferenceError。
#[test]
fn class_method_super_computed_uninitialized_this_throws() {
let mut vm = Vm::new();
let result = eval(
&mut vm,
"class Base { constructor() { throw new Error('base'); } } \
class Derived extends Base { constructor() { return super['x']; } } \
try { new Derived(); } catch (e) { e.name; }",
)
.unwrap();
assert_eq!(vm.lookup_str(result).unwrap(), "ReferenceError");
}
// super 调用:native 构造器 proto 正常路径(回归面,IsConstructor 检查后移不破坏)。
#[test]
fn super_call_native_constructor_still_works() {
let mut vm = Vm::new();
let result = eval(
&mut vm,
"class C extends Object { constructor(n) { super(n); } } \
new C(5) instanceof Object",
)
.unwrap();
assert!(result.is_bool() && result.as_bool(), "super() 后实例应为 Object 实例");
}