fix: 原型面四方法补不变量并改四入口路由

This commit is contained in:
2026-10-18 12:28:43 +00:00
parent 87cbea9755
commit 71c7aed833
8 changed files with 293 additions and 152 deletions
+54 -23
View File
@@ -1579,7 +1579,7 @@ fn desc_field_bool<H: VmHost>(vm: &mut H, desc: JsValue, prop_si: u32) -> Result
/// [[IsExtensible]](代理感知):代理经 isExtensible trap 路由(实参 target,
/// 结果经 ToBoolean 投影,trap 报告须与 target 实际可扩展状态一致,不一致抛
/// TypeError),trap 缺失落穿 target;普通对象读自身标志。
fn proxy_is_extensible<H: VmHost>(vm: &mut H, obj: &JsObject) -> Result<bool, String> {
pub fn proxy_is_extensible<H: VmHost>(vm: &mut H, obj: &JsObject) -> Result<bool, String> {
if !obj.is_proxy_obj() {
return Ok(obj.is_extensible());
}
@@ -1943,9 +1943,10 @@ fn seal_own_prop_meta(obj: &mut JsObject, store: u32) {
}
/// 代理 [[PreventExtensions]](规范 ProxyPreventExtensions):preventExtensions
/// trap 以(target)调用,结果经 ToBoolean 投影后须与 target 实际可扩展状态
/// 一致(不一致抛 TypeError);trap 缺失落穿 target 的普通 preventExtensions
/// (置不可扩展标志,返 true)。
/// trap 以(target)调用,结果经 ToBoolean 投影;trap 报 true 而 target 可扩展
/// 时抛 TypeError(报 false 无论 target 状态均原样返回);trap 缺失落穿
/// target 的 [[PreventExtensions]](target 自身为代理时递归再路由,普通对象
/// 置不可扩展标志)。
pub fn proxy_prevent_extensions<H: VmHost>(vm: &mut H, obj: &JsObject) -> Result<bool, JsValue> {
let target = crate::proxy::proxy_state_ref(obj).expect("状态盒").target;
// SAFETY: target 由构造器校验为非空对象指针。
@@ -1955,32 +1956,45 @@ pub fn proxy_prevent_extensions<H: VmHost>(vm: &mut H, obj: &JsObject) -> Result
Err(msg) => return Err(own_keys_trap_exc(vm, msg)),
};
let Some(r) = trap_result else {
// OrdinaryPreventExtensions(target):置不可扩展标志。
// 落穿 target 的 [[PreventExtensions]]:target 自身为代理时递归再路由
// (其 trap 与落穿语义对 target 生效);普通对象置不可扩展标志。
if target_obj.is_proxy_obj() {
return proxy_prevent_extensions(vm, target_obj);
}
// SAFETY: target 由构造器校验为非空对象指针。
unsafe { &mut *target.as_js_object_ptr() }.set_extensible(false);
return Ok(true);
};
let result = oxide_runtime_api::to_boolean(r);
let target_extensible =
proxy_is_extensible(vm, target_obj).map_err(|msg| crate::error::create_from_text(vm, &msg))?;
if result != target_extensible {
return Err(crate::error::create_type_error(
vm,
"Proxy preventExtensions trap result is inconsistent with target",
));
if result {
let target_extensible =
proxy_is_extensible(vm, target_obj).map_err(|msg| crate::error::create_from_text(vm, &msg))?;
if target_extensible {
return Err(crate::error::create_type_error(
vm,
"Proxy preventExtensions trap returned true for an extensible target",
));
}
}
Ok(result)
}
/// 代理完整性级别(规范 SetIntegrityLevel):[[PreventExtensions]](代理感知)
/// 后 [[OwnPropertyKeys]](代理感知),逐键 DefinePropertyOrThrow(经
/// defineProperty trap 路由,trap 缺失落穿 target)。seal 仅置 configurable:
/// false;freeze 对数据属性额外置 writable: false(规范步 7b 先读 currentDesc
/// 区分数据/访问器,访问器不写 writable 字段)。
/// 代理完整性级别(规范 SetIntegrityLevel):[[PreventExtensions]](代理感知,
/// 报 false 时按规范抛 TypeError)后 [[OwnPropertyKeys]](代理感知),逐键
/// DefinePropertyOrThrow(经 defineProperty trap 路由,trap 缺失落穿 target)。
/// seal 仅置 configurable: false;freeze 对数据属性额外置 writable: false
/// (规范步 7b 先读 currentDesc 区分数据/访问器,访问器不写 writable 字段)。
fn proxy_set_integrity_level<H: VmHost>(vm: &mut H, obj_ptr: *mut JsObject, frozen: bool) -> Result<(), JsValue> {
// SAFETY: obj_ptr 为存活对象指针。
let obj = unsafe { &*obj_ptr };
proxy_prevent_extensions(vm, obj)?;
// SetIntegrityLevel 步 3:[[PreventExtensions]] 报 false 时完整性级别
// 返回 false,Object.freeze/seal 按规范抛 TypeError。
if !proxy_prevent_extensions(vm, obj)? {
return Err(crate::error::create_type_error(
vm,
"SetIntegrityLevel: [[PreventExtensions]] returned false",
));
}
let (keys, _storage) = own_keys_proxy_aware(vm, obj)?;
let cfg_si = vm.perm_intern("configurable");
let writable_si = vm.perm_intern("writable");
@@ -2138,6 +2152,10 @@ pub fn object_seal<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
}
/// `Object.preventExtensions(obj)`:禁止添加新属性,返回原对象。
///
/// # 边界与前提
/// - 代理经 preventExtensions trap 路由(缺失落穿 target);`[[PreventExtensions]]`
/// 报 false 时按规范抛 TypeError。
pub fn object_prevent_extensions<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
if args.len() < 2 {
return NativeResult::Err(crate::error::create_type_error(vm, "Object.preventExtensions called on non-object"));
@@ -2147,10 +2165,16 @@ pub fn object_prevent_extensions<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeRe
return NativeResult::Ok(val);
}
let obj_ptr = val.as_js_object_ptr();
unsafe {
(*obj_ptr).set_extensible(false);
match vm.prevent_extensions(unsafe { &mut *obj_ptr }) {
Ok(true) => NativeResult::Ok(val),
// [[PreventExtensions]] 报 false:规范 20.1.2.20 步 3 抛 TypeError。
Ok(false) => NativeResult::Err(crate::error::create_type_error(
vm,
"Object.preventExtensions: [[PreventExtensions]] returned false",
)),
// 代理 trap 异常原值传播(ReturnIfAbrupt)。
Err(err) => NativeResult::Err(crate::array::from_engine_error(vm, &err)),
}
NativeResult::Ok(val)
}
/// `Object.isFrozen(obj)`:对象是否冻结(检查 extensible 及全部属性 writable/configurable)。
@@ -2236,6 +2260,10 @@ pub fn object_is_sealed<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
}
/// `Object.isExtensible(obj)`:对象是否可扩展。
///
/// # 边界与前提
/// - 代理经 isExtensible trap 路由(缺失落穿 target,报告与 target 状态
/// 不一致抛 TypeError);普通对象读自身标志。
pub fn object_is_extensible<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
if args.len() < 2 {
return NativeResult::Err(crate::error::create_type_error(vm, "Object.isExtensible called on non-object"));
@@ -2248,8 +2276,11 @@ pub fn object_is_extensible<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult
if obj_ptr.is_null() {
return NativeResult::Ok(JsValue::bool(false));
}
let obj = unsafe { &*obj_ptr };
NativeResult::Ok(JsValue::bool(obj.is_extensible()))
match vm.is_extensible(unsafe { &*obj_ptr }) {
Ok(extensible) => NativeResult::Ok(JsValue::bool(extensible)),
// 代理 trap 异常原值传播(ReturnIfAbrupt)。
Err(err) => NativeResult::Err(crate::array::from_engine_error(vm, &err)),
}
}
/// `Object.getOwnPropertyNames(obj)`:返回全部自身属性名(含不可枚举)。
+8 -47
View File
@@ -70,54 +70,17 @@ fn check_target_and_handler(target: JsValue, handler: JsValue) -> Result<(), &'s
Ok(())
}
/// 不变量检查(规范 10.2.4 步骤 1、4-5):target 可调用时须可扩展,handler
/// 的 isExtensible 与 setPrototypeOf trap 若存在,其布尔值须与 target 实际
/// 状态一致,否则抛 TypeError。
/// 不变量检查(规范 10.5.15 ProxyCreate 步 1-2):target 可调用且不可扩展时
/// 抛 TypeError。构造器不读 handler 的 trap 属性(现代规范无构造期 trap 一致性
/// 检查,不变量在内部方法调用期执行,getter 抛错不得在构造期触发)。
///
/// # 边界与前提
/// - 仅当 handler 自有对应 trap 属性时检查(继承属性不触发)。
/// - trap 读为传播读,getter 抛错原值上抛。
fn proxy_create_invariants<H: VmHost>(
vm: &mut H, target: JsValue, target_obj: &JsObject, handler_obj: &JsObject, handler: JsValue,
) -> Result<(), JsValue> {
/// - 仅当 target 可调用时检查可扩展性。
fn proxy_create_invariants<H: VmHost>(vm: &mut H, target: JsValue, target_obj: &JsObject) -> Result<(), JsValue> {
// target 可调用且不可扩展:函数代理的不变量无法满足,抛 TypeError。
if crate::iterator::is_callable(target) && !target_obj.is_extensible() {
return Err(crate::error::create_type_error(vm, "Proxy target must be extensible if it is callable"));
}
// isExtensible trap:handler 报 true 时 target 须可扩展,报 false 时须不可扩展。
let si_is_extensible = vm.perm_intern("isExtensible");
if vm.get_own_property_slot(handler_obj, si_is_extensible).is_some() {
let trap_val = vm
.ordinary_get(handler_obj, si_is_extensible, handler)
.map_err(|e| crate::iterator::engine_error(vm, &e))?;
let target_extensible = target_obj.is_extensible();
let trap_is_true = trap_val.is_bool() && trap_val.as_bool();
let trap_is_false = trap_val.is_bool() && !trap_val.as_bool();
if (trap_is_true && !target_extensible) || (trap_is_false && target_extensible) {
return Err(crate::error::create_type_error(
vm,
"Proxy invariant: isExtensible trap inconsistent with target",
));
}
}
// setPrototypeOf trap:handler 报 true 时 target 原型须为对象或 null,
// 报 false 时须为其它类型。
let si_set_proto = vm.perm_intern("setPrototypeOf");
if vm.get_own_property_slot(handler_obj, si_set_proto).is_some() {
let trap_val = vm
.ordinary_get(handler_obj, si_set_proto, handler)
.map_err(|e| crate::iterator::engine_error(vm, &e))?;
let target_proto = target_obj.proto();
let target_proto_is_obj_or_null = target_proto.is_object() || target_proto.is_null();
let trap_is_true = trap_val.is_bool() && trap_val.as_bool();
let trap_is_false = trap_val.is_bool() && !trap_val.as_bool();
if (trap_is_true && !target_proto_is_obj_or_null) || (trap_is_false && target_proto_is_obj_or_null) {
return Err(crate::error::create_type_error(
vm,
"Proxy invariant: setPrototypeOf trap inconsistent with target",
));
}
}
Ok(())
}
@@ -146,7 +109,7 @@ fn create_proxy_object<H: VmHost>(vm: &mut H, target: JsValue, handler: JsValue)
/// # 步骤
/// 1. NewTarget 校验:非构造形态调用抛 TypeError。
/// 2. 参数校验:target 与 handler 均须对象。
/// 3. 不变量检查:handler 的 isExtensible / setPrototypeOf trap 与 target 一致性。
/// 3. 不变量检查:target 可调用时须可扩展(构造器不读 handler trap 属性)。
/// 4. 创建代理对象(tag 39 + 状态盒 + Object.prototype 原型链)。
///
/// # 边界与前提
@@ -164,8 +127,7 @@ pub fn proxy_constructor<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
}
// SAFETY: check_target_and_handler 已校验非空对象指针。
let target_obj = unsafe { &*target.as_js_object_ptr() };
let handler_obj = unsafe { &*handler.as_js_object_ptr() };
if let Err(exc) = proxy_create_invariants(vm, target, target_obj, handler_obj, handler) {
if let Err(exc) = proxy_create_invariants(vm, target, target_obj) {
return NativeResult::Err(exc);
}
NativeResult::Ok(create_proxy_object(vm, target, handler))
@@ -191,8 +153,7 @@ pub fn proxy_revocable<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
}
// SAFETY: check_target_and_handler 已校验非空对象指针。
let target_obj = unsafe { &*target.as_js_object_ptr() };
let handler_obj = unsafe { &*handler.as_js_object_ptr() };
if let Err(exc) = proxy_create_invariants(vm, target, target_obj, handler_obj, handler) {
if let Err(exc) = proxy_create_invariants(vm, target, target_obj) {
return NativeResult::Err(exc);
}
let proxy_val = create_proxy_object(vm, target, handler);
+20 -4
View File
@@ -233,12 +233,20 @@ pub fn reflect_has<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
}
/// `Reflect.isExtensible(target)`:对象是否可扩展。
///
/// # 边界与前提
/// - 代理经 isExtensible trap 路由(缺失落穿 target,报告与 target 状态
/// 不一致抛 TypeError);普通对象读自身标志。
pub fn reflect_is_extensible<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
let target_val = arg(vm, args, 1);
let Some(target_ptr) = object_ptr(target_val) else {
return type_error(vm, "Reflect.isExtensible target is not an object");
};
NativeResult::Ok(JsValue::bool(unsafe { &*target_ptr }.is_extensible()))
match vm.is_extensible(unsafe { &*target_ptr }) {
Ok(extensible) => NativeResult::Ok(JsValue::bool(extensible)),
// 代理 trap 异常原值传播(ReturnIfAbrupt)。
Err(msg) => NativeResult::Err(from_engine_error(vm, &msg)),
}
}
/// `Reflect.ownKeys(target)`:返回对象全部自身属性键,字符串键在前、Symbol 键在后。
@@ -297,14 +305,22 @@ pub fn reflect_own_keys<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
NativeResult::Ok(JsValue::from_js_object(arr))
}
/// `Reflect.preventExtensions(target)`:阻止扩展,返回 true。
/// `Reflect.preventExtensions(target)`:阻止扩展,返回 `[[PreventExtensions]]`
/// 的布尔结果。
///
/// # 边界与前提
/// - 代理经 preventExtensions trap 路由(缺失落穿 target);结果按规范
/// 原样返回(非恒 true)。
pub fn reflect_prevent_extensions<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
let target_val = arg(vm, args, 1);
let Some(target_ptr) = object_ptr(target_val) else {
return type_error(vm, "Reflect.preventExtensions target is not an object");
};
unsafe { &mut *target_ptr }.set_extensible(false);
NativeResult::Ok(JsValue::bool(true))
match vm.prevent_extensions(unsafe { &mut *target_ptr }) {
Ok(status) => NativeResult::Ok(JsValue::bool(status)),
// 代理 trap 异常原值传播(ReturnIfAbrupt)。
Err(msg) => NativeResult::Err(from_engine_error(vm, &msg)),
}
}
/// `Reflect.set(target, key, value, receiver)`:按 OrdinarySetWithReceiver 语义写入属性。