From 89255abd1753a14e3d24e5134c56a4e55f0bebff Mon Sep 17 00:00:00 2001 From: pjh456 <147148383@qq.com> Date: Sun, 18 Oct 2026 12:24:10 +0000 Subject: [PATCH] =?UTF-8?q?fix:=20=E5=8E=9F=E5=9E=8B=E9=93=BE=E7=9B=B4?= =?UTF-8?q?=E8=AF=BB=E6=94=B9=E7=BB=8F=20get=5Fprototype=5Fof=20=E8=B7=AF?= =?UTF-8?q?=E7=94=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.lock | 42 ++++++++++++------------ Cargo.toml | 2 +- crates/oxide_builtins/src/function.rs | 12 +++++-- crates/oxide_runtime_api/src/host.rs | 3 +- crates/oxide_vm/src/dispatch/call.rs | 18 +++++++--- crates/oxide_vm/src/dispatch/property.rs | 30 ++++++++++------- crates/oxide_vm/src/ic_helper.rs | 16 +++++++++ crates/oxide_vm/src/vm/props.rs | 9 ++++- crates/oxide_vm/src/vm/vmhost.rs | 15 +++++---- crates/oxide_vm/src/vm_dispatch_misc.rs | 10 ++++-- crates/oxide_vm/src/vm_props.rs | 36 ++++++++++++-------- 11 files changed, 126 insertions(+), 67 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index db264ae4..e5753d93 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1160,7 +1160,7 @@ dependencies = [ [[package]] name = "oxide_builtins" -version = "0.20.13" +version = "0.20.14" dependencies = [ "chrono", "fast-float", @@ -1185,7 +1185,7 @@ dependencies = [ [[package]] name = "oxide_bytecode" -version = "0.20.13" +version = "0.20.14" dependencies = [ "num-bigint", "oxide_log", @@ -1193,7 +1193,7 @@ dependencies = [ [[package]] name = "oxide_cfg" -version = "0.20.13" +version = "0.20.14" dependencies = [ "oxide_bytecode", "oxide_emit", @@ -1204,7 +1204,7 @@ dependencies = [ [[package]] name = "oxide_cli" -version = "0.20.13" +version = "0.20.14" dependencies = [ "ansi_term", "bumpalo", @@ -1228,7 +1228,7 @@ dependencies = [ [[package]] name = "oxide_code_cache" -version = "0.20.13" +version = "0.20.14" dependencies = [ "lru", "oxide_bytecode", @@ -1237,7 +1237,7 @@ dependencies = [ [[package]] name = "oxide_compiler" -version = "0.20.13" +version = "0.20.14" dependencies = [ "oxide_bytecode", "oxide_cfg", @@ -1258,7 +1258,7 @@ dependencies = [ [[package]] name = "oxide_dce" -version = "0.20.13" +version = "0.20.14" dependencies = [ "oxide_bytecode", "oxide_cfg", @@ -1272,7 +1272,7 @@ dependencies = [ [[package]] name = "oxide_emit" -version = "0.20.13" +version = "0.20.14" dependencies = [ "num-bigint", "oxc_allocator", @@ -1288,7 +1288,7 @@ dependencies = [ [[package]] name = "oxide_engine" -version = "0.20.13" +version = "0.20.14" dependencies = [ "oxide_bytecode", "oxide_compiler", @@ -1300,7 +1300,7 @@ dependencies = [ [[package]] name = "oxide_fold" -version = "0.20.13" +version = "0.20.14" dependencies = [ "num-bigint", "oxide_bytecode", @@ -1312,7 +1312,7 @@ dependencies = [ [[package]] name = "oxide_ir" -version = "0.20.13" +version = "0.20.14" dependencies = [ "oxide_bytecode", "oxide_log", @@ -1321,7 +1321,7 @@ dependencies = [ [[package]] name = "oxide_kernel" -version = "0.20.13" +version = "0.20.14" dependencies = [ "bumpalo", "dashmap", @@ -1335,7 +1335,7 @@ dependencies = [ [[package]] name = "oxide_liveness" -version = "0.20.13" +version = "0.20.14" dependencies = [ "oxide_bytecode", "oxide_cfg", @@ -1347,7 +1347,7 @@ dependencies = [ [[package]] name = "oxide_log" -version = "0.20.13" +version = "0.20.14" dependencies = [ "tracing", "tracing-appender", @@ -1356,11 +1356,11 @@ dependencies = [ [[package]] name = "oxide_net" -version = "0.20.13" +version = "0.20.14" [[package]] name = "oxide_parser" -version = "0.20.13" +version = "0.20.14" dependencies = [ "oxc_allocator", "oxc_ast", @@ -1375,7 +1375,7 @@ dependencies = [ [[package]] name = "oxide_regalloc" -version = "0.20.13" +version = "0.20.14" dependencies = [ "oxide_bytecode", "oxide_cfg", @@ -1391,7 +1391,7 @@ dependencies = [ [[package]] name = "oxide_runtime_api" -version = "0.20.13" +version = "0.20.14" dependencies = [ "num-bigint", "num-traits", @@ -1404,7 +1404,7 @@ dependencies = [ [[package]] name = "oxide_test262" -version = "0.20.13" +version = "0.20.14" dependencies = [ "oxide_bytecode", "oxide_compiler", @@ -1424,7 +1424,7 @@ dependencies = [ [[package]] name = "oxide_types" -version = "0.20.13" +version = "0.20.14" dependencies = [ "bumpalo", "dashmap", @@ -1437,7 +1437,7 @@ dependencies = [ [[package]] name = "oxide_vm" -version = "0.20.13" +version = "0.20.14" dependencies = [ "bumpalo", "chrono", diff --git a/Cargo.toml b/Cargo.toml index a9b85d0e..79d4bc0f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,7 +25,7 @@ members = [ ] [workspace.package] -version = "0.20.13" +version = "0.20.14" edition = "2021" license = "MIT" rust-version = "1.80" diff --git a/crates/oxide_builtins/src/function.rs b/crates/oxide_builtins/src/function.rs index ad371452..07bb211c 100644 --- a/crates/oxide_builtins/src/function.rs +++ b/crates/oxide_builtins/src/function.rs @@ -146,7 +146,12 @@ pub fn function_symbol_has_instance(vm: &mut H, args: &[u8]) -> Nativ let proto_ptr = proto_val.as_js_object_ptr(); // 沿 O 原型链与 C.prototype 比对;深度上限防止原型环死循环。 - let mut cur = unsafe { &*o_val.as_js_object_ptr() }.proto(); + // 原型链走查经 [[GetPrototypeOf]] 路由:代理经 getPrototypeOf trap, + // 非代理对象零行为变化。 + let mut cur = match vm.get_prototype_of(unsafe { &*o_val.as_js_object_ptr() }) { + Ok(v) => v, + Err(e) => return NativeResult::Err(to_string_error_value(vm, &e)), + }; for _ in 0..1024 { if !cur.is_object() { return NativeResult::Ok(JsValue::bool(false)); @@ -154,7 +159,10 @@ pub fn function_symbol_has_instance(vm: &mut H, args: &[u8]) -> Nativ if cur.as_js_object_ptr() == proto_ptr { return NativeResult::Ok(JsValue::bool(true)); } - cur = unsafe { &*cur.as_js_object_ptr() }.proto(); + cur = match vm.get_prototype_of(unsafe { &*cur.as_js_object_ptr() }) { + Ok(v) => v, + Err(e) => return NativeResult::Err(to_string_error_value(vm, &e)), + }; } NativeResult::Ok(JsValue::bool(false)) } diff --git a/crates/oxide_runtime_api/src/host.rs b/crates/oxide_runtime_api/src/host.rs index 7de64e8f..709b204e 100644 --- a/crates/oxide_runtime_api/src/host.rs +++ b/crates/oxide_runtime_api/src/host.rs @@ -536,7 +536,8 @@ pub trait VmHost { fn function_is_strict(&self, obj: &JsObject) -> bool; /// caller/arguments 访问是否受限:严格函数对象,或生成器 / 异步 / /// 异步生成器函数对象([[Prototype]] 为三个动态函数原型之一)。 - fn function_is_restricted(&self, obj: &JsObject) -> bool; + /// 原型经 [[GetPrototypeOf]] 路由判定(代理函数对象经 getPrototypeOf trap)。 + fn function_is_restricted(&mut self, obj: &JsObject) -> Result; fn step_rng(&mut self); fn math_rng_value(&self) -> f64; fn sub_module_function_name(&self, gen: u32, sub_idx: u16) -> String; diff --git a/crates/oxide_vm/src/dispatch/call.rs b/crates/oxide_vm/src/dispatch/call.rs index 66295907..5ff644be 100644 --- a/crates/oxide_vm/src/dispatch/call.rs +++ b/crates/oxide_vm/src/dispatch/call.rs @@ -5,7 +5,7 @@ use crate::{vm_debug, vm_trace}; use oxide_builtins::iterator::make_iterator_for_value; use oxide_builtins::{builtins_debug, builtins_trace}; use oxide_bytecode::opcode; -use oxide_runtime_api::{to_boolean, NativeResult}; +use oxide_runtime_api::{to_boolean, NativeResult, VmHost}; use oxide_types::object::{Cell, JsObject, PropAttributes}; use oxide_types::value::JsValue; @@ -653,7 +653,9 @@ impl Vm { return Ok(true); } let callee_obj = unsafe { &*callee.as_js_object_ptr() }; - let super_ctor = callee_obj.proto(); + // super 构造器取当前帧 callee 的 [[GetPrototypeOf]](规范 10.2.11 面): + // 代理函数对象经 getPrototypeOf trap 取基。 + let super_ctor = self.get_prototype_of(callee_obj)?; if !super_ctor.is_object() { self.raise_error_kind("TypeError", "super constructor is not an object")?; return Ok(true); @@ -781,7 +783,9 @@ impl Vm { let home_obj = unsafe { &*home_object.as_js_object_ptr() }; // 规范步序:GetSuperBase 先于 ToPropertyKey;基非对象可强转时抛 // TypeError(RequireObjectCoercible 面)。 - let super_base = home_obj.proto(); + // GetSuperBase 取 home 对象的 [[GetPrototypeOf]](规范 10.2.11 面): + // 代理 home 对象经 getPrototypeOf trap 取基。 + let super_base = self.get_prototype_of(home_obj)?; if !super_base.is_object() { self.raise_type_error("Cannot convert null or undefined to object")?; return Ok(true); @@ -826,7 +830,9 @@ impl Vm { let home_obj = unsafe { &*home_object.as_js_object_ptr() }; // 规范步序:GetSuperBase 先于 ToPropertyKey;基非对象可强转时抛 // TypeError(RequireObjectCoercible 面)。 - let super_base = home_obj.proto(); + // GetSuperBase 取 home 对象的 [[GetPrototypeOf]](规范 10.2.11 面): + // 代理 home 对象经 getPrototypeOf trap 取基。 + let super_base = self.get_prototype_of(home_obj)?; if !super_base.is_object() { self.raise_type_error("Cannot convert null or undefined to object")?; return Ok(true); @@ -1158,7 +1164,9 @@ impl Vm { return Ok(true); } let callee_obj = unsafe { &*callee.as_js_object_ptr() }; - let super_ctor = callee_obj.proto(); + // super 构造器取当前帧 callee 的 [[GetPrototypeOf]](规范 10.2.11 面): + // 代理函数对象经 getPrototypeOf trap 取基。 + let super_ctor = self.get_prototype_of(callee_obj)?; if !super_ctor.is_object() { self.raise_error_kind("TypeError", "super constructor is not an object")?; return Ok(true); diff --git a/crates/oxide_vm/src/dispatch/property.rs b/crates/oxide_vm/src/dispatch/property.rs index f82a76d5..a2154782 100644 --- a/crates/oxide_vm/src/dispatch/property.rs +++ b/crates/oxide_vm/src/dispatch/property.rs @@ -1,6 +1,7 @@ use crate::{ic_debug, ic_trace, vm_trace}; use oxide_bytecode::opcode::{OpCode, IC_EXT_WORDS}; use oxide_runtime_api as coercion; +use oxide_runtime_api::VmHost; use oxide_types::object::JsObject; use oxide_types::private_key::{int_key_value, is_int_key, make_int_key, make_private_name_id}; use oxide_types::value::JsValue; @@ -123,8 +124,10 @@ impl Vm { /// 沿实例→proto 链查找私有方法/访问器槽(存于类的 home=proto)。字段槽不跨原型 /// (PrivateFieldFind 只查 own)——链上遇到字段槽(无 hole meta)即拒绝,防 /// `Object.create(instance)` 穿透读取实例字段。 - fn find_private_method_slot(&self, obj: &JsObject, private_key: u32) -> Option<*mut JsObject> { - let mut proto = obj.proto(); + fn find_private_method_slot( + &mut self, obj: &JsObject, private_key: u32, + ) -> Result, String> { + let mut proto = self.get_prototype_of(obj)?; let mut depth = 0usize; while proto.is_object() && depth < MAX_PROTO_CHAIN_DEPTH { depth += 1; @@ -133,13 +136,13 @@ impl Vm { // 方法/访问器槽有 hole 标记(私有方法)或 is_accessor 标记(私有 getter/setter); // 字段槽(存实例)沿链出现说明接收者并非本类实例 → 拒绝穿透。 if proto_obj.prop_meta_at(pos).is_some_and(|m| m.is_hole() || m.is_accessor) { - return Some(proto_obj as *const JsObject as *mut JsObject); + return Ok(Some(proto_obj as *const JsObject as *mut JsObject)); } - return None; + return Ok(None); } - proto = proto_obj.proto(); + proto = self.get_prototype_of(proto_obj)?; } - None + Ok(None) } /// 私有方法/访问器/静态字段访问的 brand 检查:接收者 own 的 brand 槽(构造时写入 @@ -185,7 +188,7 @@ impl Vm { return Ok(()); } // 方法路径:own 无槽(私有方法/访问器存于 home=proto)→ 沿链找方法槽 + brand 检查。 - let Some(home_ptr) = self.find_private_method_slot(obj, private_key) else { + let Ok(Some(home_ptr)) = self.find_private_method_slot(obj, private_key) else { return self.raise_type_error("private field brand check failed"); }; if brand_reg != 0 { @@ -244,7 +247,7 @@ impl Vm { return Ok(()); } // 方法路径:own 无槽(私有方法/访问器存于 home=proto)→ 沿链找方法槽 + brand 检查。 - let Some(home_ptr) = self.find_private_method_slot(obj, private_key) else { + let Ok(Some(home_ptr)) = self.find_private_method_slot(obj, private_key) else { return self.raise_type_error("private field brand check failed"); }; if brand_reg != 0 { @@ -465,8 +468,10 @@ impl Vm { ic_debug!("IC_GET write-back own shape={} slot={}", obj.shape_id(), pos); } } else { - // 沿原型链查找真正拥有该属性的对象。 - let mut cursor = obj.proto().as_js_object_ptr(); + // 沿原型链查找真正拥有该属性的对象(逐层经 [[GetPrototypeOf]] + // 路由,代理层经 trap 取原型)。 + let proto = self.get_prototype_of(obj)?; + let mut cursor = proto.as_js_object_ptr(); let mut depth = 1u8; while !cursor.is_null() { let co_ref = unsafe { &*cursor }; @@ -484,10 +489,11 @@ impl Vm { } break; } - if !co_ref.proto().is_object() { + let next_proto = self.get_prototype_of(co_ref)?; + if !next_proto.is_object() { break; } - cursor = co_ref.proto().as_js_object_ptr(); + cursor = next_proto.as_js_object_ptr(); depth += 1; } } diff --git a/crates/oxide_vm/src/ic_helper.rs b/crates/oxide_vm/src/ic_helper.rs index 55888ccb..24f42a6a 100644 --- a/crates/oxide_vm/src/ic_helper.rs +++ b/crates/oxide_vm/src/ic_helper.rs @@ -119,6 +119,10 @@ pub(crate) fn ic_get_hit(obj: &JsObject, shape_id: u32, slot_index: u32, proto_d return None; } let target_ref = unsafe { &*target }; + // 链上目标为代理:直读自身槽绕过 get trap,恒 miss,落穿慢路径路由 trap。 + if target_ref.is_proxy_obj() { + return None; + } if target_ref.shape_id() == shape_id && slot_index < target_ref.prop_vec_len() as u32 { Some(target_ref.get_prop_shape(slot_index)) } else { @@ -153,6 +157,10 @@ pub(crate) fn ic_get_hit_poly(obj: &JsObject, bytecode: &[Instr], ext_pc: usize) continue; } let target_ref = unsafe { &*target }; + // 链上目标为代理:恒 miss,落穿慢路径路由 get trap。 + if target_ref.is_proxy_obj() { + continue; + } if target_ref.shape_id() == shape_id && slot_index < target_ref.prop_vec_len() as u32 { return Some(target_ref.get_prop_shape(slot_index)); } @@ -177,6 +185,10 @@ pub(crate) fn ic_set_hit(obj: &mut JsObject, shape_id: u32, slot_index: u32, pro return false; } let target_ref = unsafe { &*target }; + // 链上目标为代理:直写自身槽绕过 set trap,恒 miss,落穿慢路径路由 trap。 + if target_ref.is_proxy_obj() { + return false; + } if target_ref.shape_id() == shape_id && slot_index < target_ref.prop_vec_len() as u32 { unsafe { &mut *(target as *mut JsObject) }.set_prop_shape(slot_index, value); true @@ -209,6 +221,10 @@ pub(crate) fn ic_set_hit_poly(obj: &mut JsObject, bytecode: &[Instr], ext_pc: us continue; } let target_ref = unsafe { &*target }; + // 链上目标为代理:恒 miss,落穿慢路径路由 set trap。 + if target_ref.is_proxy_obj() { + continue; + } if target_ref.shape_id() == shape_id && slot_index < target_ref.prop_vec_len() as u32 { unsafe { &mut *(target as *mut JsObject) }.set_prop_shape(slot_index, value); return true; diff --git a/crates/oxide_vm/src/vm/props.rs b/crates/oxide_vm/src/vm/props.rs index 01ff46e6..52aaa595 100644 --- a/crates/oxide_vm/src/vm/props.rs +++ b/crates/oxide_vm/src/vm/props.rs @@ -191,6 +191,11 @@ impl Vm { while proto.is_object() && depth < MAX_PROTO_CHAIN_DEPTH { depth += 1; let proto_obj = unsafe { &*proto.as_js_object_ptr() }; + // 链上代理层:不可变签名无法同步调 get trap,保守返 None, + // 与顶层代理口径一致(权威路径由可变签名入口承载)。 + if proto_obj.is_proxy_obj() { + return None; + } if let Some(pos) = self .kernel_core .shape_forge() @@ -300,7 +305,9 @@ impl Vm { break; } depth += 1; - let proto = obj.proto(); + // 链上续层经 [[GetPrototypeOf]] 路由:代理层经 trap 取原型, + // 取到的代理层在下一轮循环经入口守卫路由 has trap。 + let proto = self.get_prototype_of(obj)?; current = proto.is_object().then(|| unsafe { &*proto.as_js_object_ptr() }); } Ok(false) diff --git a/crates/oxide_vm/src/vm/vmhost.rs b/crates/oxide_vm/src/vm/vmhost.rs index 251bbaf9..6e2b0b92 100644 --- a/crates/oxide_vm/src/vm/vmhost.rs +++ b/crates/oxide_vm/src/vm/vmhost.rs @@ -571,20 +571,21 @@ impl oxide_runtime_api::VmHost for Vm { // 按严格处理(受限访问器对其抛错)。 self.callee_module(obj).map(|m| m.is_strict).unwrap_or(true) } - fn function_is_restricted(&self, obj: &JsObject) -> bool { + fn function_is_restricted(&mut self, obj: &JsObject) -> Result { // 严格函数对象,或 [[Prototype]] 为三个动态函数原型之一(生成器 / - // 异步 / 异步生成器函数):caller/arguments 访问一律受限。 + // 异步 / 异步生成器函数):caller/arguments 访问一律受限。原型经 + // [[GetPrototypeOf]] 路由取(代理函数对象经 getPrototypeOf trap)。 if self.function_is_strict(obj) { - return true; + return Ok(true); } - let proto = obj.proto(); + let proto = self.get_prototype_of(obj)?; if !proto.is_object() { - return false; + return Ok(false); } let p = proto.as_js_object_ptr() as *const JsObject; - std::ptr::eq(p, self.realm.generator_function_proto.borrow().as_ptr()) + Ok(std::ptr::eq(p, self.realm.generator_function_proto.borrow().as_ptr()) || std::ptr::eq(p, self.realm.async_function_proto.borrow().as_ptr()) - || std::ptr::eq(p, self.realm.async_generator_function_proto.borrow().as_ptr()) + || std::ptr::eq(p, self.realm.async_generator_function_proto.borrow().as_ptr())) } fn step_rng(&mut self) { self.step_rng() diff --git a/crates/oxide_vm/src/vm_dispatch_misc.rs b/crates/oxide_vm/src/vm_dispatch_misc.rs index 497c3dac..e334dadc 100644 --- a/crates/oxide_vm/src/vm_dispatch_misc.rs +++ b/crates/oxide_vm/src/vm_dispatch_misc.rs @@ -498,7 +498,10 @@ impl Vm { } let ctor_proto_ptr = ctor_proto.as_js_object_ptr(); - let mut proto = unsafe { &*lhs_val.as_js_object_ptr() }.proto(); + // 原型链走查经 [[GetPrototypeOf]] 路由:代理经 getPrototypeOf trap, + // 非代理对象零行为变化。 + let lhs_obj = unsafe { &*lhs_val.as_js_object_ptr() }; + let mut proto = self.get_prototype_of(lhs_obj)?; let mut depth = 0usize; loop { if !proto.is_object() { @@ -515,7 +518,7 @@ impl Vm { self.regs[rd] = JsValue::bool(true); break; } - proto = unsafe { &*proto_ptr }.proto(); + proto = self.get_prototype_of(unsafe { &*proto_ptr })?; } Ok(()) } @@ -681,7 +684,8 @@ impl Vm { // shape 链按叶→根遍历(与插入序相反);在接上原型前把本对象的切片 // 翻转为插入序。 keys_vec[obj_start..].reverse(); - current = cur.proto(); + // 链上续层经 [[GetPrototypeOf]] 路由:代理层经 trap 取原型。 + current = self.get_prototype_of(cur)?; } // 模块命名空间 exotic:EnumerateObjectProperties 构建键表时逐键走 diff --git a/crates/oxide_vm/src/vm_props.rs b/crates/oxide_vm/src/vm_props.rs index 03b5bc94..c8b54bab 100644 --- a/crates/oxide_vm/src/vm_props.rs +++ b/crates/oxide_vm/src/vm_props.rs @@ -246,7 +246,9 @@ impl Vm { break; } depth += 1; - let proto = obj.proto(); + // 原型链走查经 [[GetPrototypeOf]] 路由:代理层调 getPrototypeOf + // trap,非代理对象零行为变化。 + let proto = self.get_prototype_of(obj)?; current = proto.is_object().then(|| unsafe { &*proto.as_js_object_ptr() }); if let Some(proto_obj) = current { vm_trace!("ordinary_get proto step: depth={} shape={}", depth, proto_obj.shape_id()); @@ -312,16 +314,18 @@ impl Vm { Ok(true) } - fn inherited_property_meta(&self, obj: &JsObject, prop_name_si: u32) -> Option { + fn inherited_property_meta( + &mut self, obj: &JsObject, prop_name_si: u32, + ) -> Result, String> { vm_trace!("inherited_property_meta: shape={} prop_si={}", obj.shape_id(), prop_name_si); - let mut proto = obj.proto(); + let mut proto = self.get_prototype_of(obj)?; let mut depth = 0usize; while proto.is_object() && depth < MAX_PROTO_CHAIN_DEPTH { depth += 1; let proto_obj = unsafe { &*proto.as_js_object_ptr() }; // 代理层:无 getOwnPropertyDescriptor trap 时 [[GetOwnProperty]] - // 落穿 target 的自身属性,故按 target 的自身槽位判定;链上续层取 - // 代理自身的原型([[GetPrototypeOf]] 同样落穿 target)。 + // 落穿 target 的自身属性,故按 target 的自身槽位判定;链上续层经 + // [[GetPrototypeOf]] 路由取下一层(代理经 trap,非代理零行为变化)。 let effective = if proto_obj.is_proxy_obj() { let target = oxide_builtins::proxy::proxy_state_ref(proto_obj).expect("状态盒").target; // SAFETY: target 由构造器校验为非空对象指针。 @@ -330,11 +334,11 @@ impl Vm { proto_obj }; if let Some(pos) = self.get_own_property_slot(effective, prop_name_si) { - return effective.prop_meta_at(pos); + return Ok(effective.prop_meta_at(pos)); } - proto = proto_obj.proto(); + proto = self.get_prototype_of(proto_obj)?; } - None + Ok(None) } /// 全局 builtin 属性在原始存储侧(全局对象自身属性槽,下文简称 A 侧)写成功后 @@ -705,7 +709,9 @@ impl Vm { // 即 receiver);原型链走完(或深度到界)时 CreateDataProperty(Receiver, // P, V)。 if depth < MAX_PROTO_CHAIN_DEPTH { - let parent = obj.proto(); + // 经 [[GetPrototypeOf]] 路由取父层:代理父层经 trap 取原型, + // 父层自身 [[Set]] 由递归入口判定。 + let parent = self.get_prototype_of(obj)?; if parent.is_object() { // SAFETY: parent 为值携带的非空对象指针,对象在本会话内存活; // 写路径不移动对象。 @@ -1451,8 +1457,9 @@ impl Vm { } return Ok(resolved); } - // 沿原型链查找继承属性。 - let mut cursor = obj.proto().as_js_object_ptr(); + // 沿原型链查找继承属性(逐层经 [[GetPrototypeOf]] 路由,代理层经 trap)。 + let proto = self.get_prototype_of(obj)?; + let mut cursor = proto.as_js_object_ptr(); let mut depth = 1u8; while !cursor.is_null() { let co = unsafe { &*cursor }; @@ -1462,10 +1469,11 @@ impl Vm { } break; } - if !co.proto().is_object() { + let next_proto = self.get_prototype_of(co)?; + if !next_proto.is_object() { break; } - cursor = co.proto().as_js_object_ptr(); + cursor = next_proto.as_js_object_ptr(); depth += 1; } Ok(resolved) @@ -1531,7 +1539,7 @@ impl Vm { let use_frame_push = contract.use_frame_push; // 原型链同名 accessor 须触发 setter、只读 data 须报错(与 ordinary_set 一致), // 命中时不得创建 own 属性(规范 [[Set]] shadow 语义)。 - if let Some(meta) = self.inherited_property_meta(obj, prop_name_si) { + if let Ok(Some(meta)) = self.inherited_property_meta(obj, prop_name_si) { if meta.is_accessor { if meta.set.is_undefined() { // 继承无 setter:严格抛错,sloppy 静默 no-op。