mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-23 18:21:13 +08:00
feat: 函数代理 apply 与 construct trap 路由落地
This commit is contained in:
@@ -17,6 +17,12 @@ use super::common::{
|
||||
pub fn array_constructor<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
let proto = vm.builtin_proto(ProtoKind::ArrayProto);
|
||||
let proto_val = JsValue::from_js_object(proto);
|
||||
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
|
||||
// 构造形态(newTarget 在场):产物须为 Array exotic 对象(Array.isArray 认)
|
||||
// 且原型取 newTarget.prototype(派生类 / 代理 newTarget 由此拿到子类实例),
|
||||
// 原型已由构造入口预写入 receiver,直接读取复用;普通调用形态自建
|
||||
// Array.prototype 原型的新数组。
|
||||
let in_construct = vm.constructing_native() && this_val.is_object();
|
||||
|
||||
if args.len() == 2 {
|
||||
let val = vm.reg(args[1]);
|
||||
@@ -25,7 +31,13 @@ pub fn array_constructor<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
Ok(n) => n,
|
||||
Err(err) => return NativeResult::Err(err),
|
||||
};
|
||||
let arr = vm.alloc_object(JsObject::new_array(EMPTY_SHAPE_ID, proto_val, n));
|
||||
let arr_proto = if in_construct {
|
||||
// SAFETY: receiver 是构造帧分配的 this(本 session 存活),只读原型。
|
||||
unsafe { &*this_val.as_js_object_ptr() }.proto()
|
||||
} else {
|
||||
proto_val
|
||||
};
|
||||
let arr = vm.alloc_object(JsObject::new_array(EMPTY_SHAPE_ID, arr_proto, n));
|
||||
// 数值长度分支建 n 个空洞而非 present-undefined:`in`、for-in、
|
||||
// Object.keys 按缺失处理,元素 Get 落原型链。物理区以稠密上限
|
||||
// 钳位(越界索引无物理槽,逻辑长度已覆盖)。
|
||||
@@ -39,7 +51,13 @@ pub fn array_constructor<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
}
|
||||
|
||||
let n_elems = if args.len() > 1 { args.len() - 1 } else { 0 };
|
||||
let arr = vm.alloc_object(JsObject::new_array(EMPTY_SHAPE_ID, proto_val, n_elems));
|
||||
let arr_proto = if in_construct {
|
||||
// SAFETY: receiver 是构造帧分配的 this(本 session 存活),只读原型。
|
||||
unsafe { &*this_val.as_js_object_ptr() }.proto()
|
||||
} else {
|
||||
proto_val
|
||||
};
|
||||
let arr = vm.alloc_object(JsObject::new_array(EMPTY_SHAPE_ID, arr_proto, n_elems));
|
||||
for i in 0..n_elems {
|
||||
unsafe {
|
||||
(*arr).set_prop_at(i, vm.reg(args[1 + i]));
|
||||
|
||||
@@ -70,15 +70,23 @@ fn check_target_and_handler(target: JsValue, handler: JsValue) -> Result<(), &'s
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 不变量检查(规范 10.2.4 步骤 4-5):handler 的 isExtensible 与 setPrototypeOf
|
||||
/// trap 若存在,其布尔值须与 target 实际状态一致,否则抛 TypeError。
|
||||
/// 不变量检查(规范 10.2.4 步骤 1、4-5):target 可调用时须可扩展,handler
|
||||
/// 的 isExtensible 与 setPrototypeOf trap 若存在,其布尔值须与 target 实际
|
||||
/// 状态一致,否则抛 TypeError。
|
||||
///
|
||||
/// # 边界与前提
|
||||
/// - 仅当 handler 自有对应 trap 属性时检查(继承属性不触发)。
|
||||
/// - trap 读为传播读,getter 抛错原值上抛。
|
||||
fn proxy_create_invariants<H: VmHost>(
|
||||
vm: &mut H, target_obj: &JsObject, handler_obj: &JsObject, handler: JsValue,
|
||||
vm: &mut H, target: JsValue, target_obj: &JsObject, handler_obj: &JsObject, handler: JsValue,
|
||||
) -> 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() {
|
||||
@@ -160,7 +168,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_obj, handler_obj, handler) {
|
||||
if let Err(exc) = proxy_create_invariants(vm, target, target_obj, handler_obj, handler) {
|
||||
return NativeResult::Err(exc);
|
||||
}
|
||||
NativeResult::Ok(create_proxy_object(vm, target, handler))
|
||||
@@ -187,7 +195,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_obj, handler_obj, handler) {
|
||||
if let Err(exc) = proxy_create_invariants(vm, target, target_obj, handler_obj, handler) {
|
||||
return NativeResult::Err(exc);
|
||||
}
|
||||
let proxy_val = create_proxy_object(vm, target, handler);
|
||||
|
||||
Reference in New Issue
Block a user