mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-23 18:21:13 +08:00
fix: 原型链直读改经 get_prototype_of 路由
This commit is contained in:
@@ -146,7 +146,12 @@ pub fn function_symbol_has_instance<H: VmHost>(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<H: VmHost>(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))
|
||||
}
|
||||
|
||||
@@ -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<bool, String>;
|
||||
fn step_rng(&mut self);
|
||||
fn math_rng_value(&self) -> f64;
|
||||
fn sub_module_function_name(&self, gen: u32, sub_idx: u16) -> String;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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<Option<*mut JsObject>, 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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<bool, String> {
|
||||
// 严格函数对象,或 [[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()
|
||||
|
||||
@@ -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 构建键表时逐键走
|
||||
|
||||
@@ -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<PropMetaEntry> {
|
||||
fn inherited_property_meta(
|
||||
&mut self, obj: &JsObject, prop_name_si: u32,
|
||||
) -> Result<Option<PropMetaEntry>, 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。
|
||||
|
||||
Reference in New Issue
Block a user