From e91d8ecaf2cb6fdb6d45e000a522833849a366c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=88=B1=E7=89=B9=E6=AF=8F=E7=BE=8A=E9=98=9F?= Date: Sat, 8 Aug 2026 01:39:12 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20defineProperty=20=E6=8F=8F=E8=BF=B0?= =?UTF-8?q?=E7=AC=A6=E5=AD=97=E6=AE=B5=E6=8C=89=20ToPropertyDescriptor=20?= =?UTF-8?q?=E8=AF=AD=E4=B9=89=E8=A7=A3=E6=9E=90=EF=BC=88=E5=8E=9F=E5=9E=8B?= =?UTF-8?q?=E9=93=BE=20+=20accessor=20getter=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crates/oxide_builtins/src/object.rs | 32 ++++++++++++---------------- crates/oxide_builtins/src/reflect.rs | 28 +++++++++++++----------- 2 files changed, 29 insertions(+), 31 deletions(-) diff --git a/crates/oxide_builtins/src/object.rs b/crates/oxide_builtins/src/object.rs index 655af79..ebaf0df 100644 --- a/crates/oxide_builtins/src/object.rs +++ b/crates/oxide_builtins/src/object.rs @@ -247,11 +247,10 @@ pub fn object_define_property(vm: &mut H, args: &[u8]) -> NativeResul let enumerable_si = vm.kernel_core().perm_interner().intern("enumerable").0; let configurable_si = vm.kernel_core().perm_interner().intern("configurable").0; - let desc = unsafe { &*desc_ptr }; - let value_field = own_field(vm, desc, value_si); - let get_field = own_field(vm, desc, get_si); - let set_field = own_field(vm, desc, set_si); - let writable_field = own_field(vm, desc, writable_si); + let value_field = own_field(vm, desc_val, value_si); + let get_field = own_field(vm, desc_val, get_si); + let set_field = own_field(vm, desc_val, set_si); + let writable_field = own_field(vm, desc_val, writable_si); let existing_pos = { let obj = unsafe { &*obj_ptr }; @@ -263,10 +262,10 @@ pub fn object_define_property(vm: &mut H, args: &[u8]) -> NativeResul }); // 修改已有属性时缺省字段回填现有值,仅定义新属性时缺省才为 false。 - let enumerable = own_field(vm, desc, enumerable_si) + let enumerable = own_field(vm, desc_val, enumerable_si) .map(oxide_runtime_api::to_boolean) .unwrap_or_else(|| existing_meta.map(|m| m.attributes.enumerable()).unwrap_or(false)); - let configurable = own_field(vm, desc, configurable_si) + let configurable = own_field(vm, desc_val, configurable_si) .map(oxide_runtime_api::to_boolean) .unwrap_or_else(|| existing_meta.map(|m| m.attributes.configurable()).unwrap_or(false)); @@ -419,17 +418,14 @@ pub fn object_get_own_property_descriptor(vm: &mut H, args: &[u8]) -> NativeResult::Ok(JsValue::from_js_object(desc)) } -fn own_field(vm: &H, obj: &JsObject, prop_si: u32) -> Option { - vm.kernel_core() - .shape_forge() - .lookup_position(obj.shape_id(), prop_si) - .and_then(|pos| { - if obj.prop_vec_len() > pos as usize { - Some(obj.get_prop_at(pos)) - } else { - None - } - }) +/// 按 ToPropertyDescriptor 语义取描述符字段:沿原型链判存在性,存在时经 +/// ordinary_get 取值(触发 accessor getter,receiver 为描述符对象本身)。 +fn own_field(vm: &mut H, desc: JsValue, prop_si: u32) -> Option { + // ordinary_get 对缺失属性返回 undefined,无法区分"不存在"与"值为 + // undefined",故先用 resolve_property 沿原型链判 HasProperty。 + let obj = unsafe { &*desc.as_js_object_ptr() }; + vm.resolve_property(obj, prop_si)?; + vm.ordinary_get(obj, prop_si, desc).ok() } fn is_callable(value: JsValue) -> bool { diff --git a/crates/oxide_builtins/src/reflect.rs b/crates/oxide_builtins/src/reflect.rs index 317cc21..72f8a88 100644 --- a/crates/oxide_builtins/src/reflect.rs +++ b/crates/oxide_builtins/src/reflect.rs @@ -75,12 +75,11 @@ pub fn reflect_define_property(vm: &mut H, args: &[u8]) -> NativeResu return type_error(vm, "Reflect.defineProperty target is not an object"); }; let desc_val = arg(vm, args, 3); - let Some(desc_ptr) = object_ptr(desc_val) else { + let Some(_) = object_ptr(desc_val) else { return type_error(vm, "Reflect.defineProperty descriptor is not an object"); }; let key_si = vm.property_key_si(arg(vm, args, 2)); - let desc = unsafe { &*desc_ptr }; let value_si = vm.kernel_core().perm_interner().intern("value").0; let get_si = vm.kernel_core().perm_interner().intern("get").0; let set_si = vm.kernel_core().perm_interner().intern("set").0; @@ -88,14 +87,14 @@ pub fn reflect_define_property(vm: &mut H, args: &[u8]) -> NativeResu let enumerable_si = vm.kernel_core().perm_interner().intern("enumerable").0; let configurable_si = vm.kernel_core().perm_interner().intern("configurable").0; - let value_field = own_field(vm, desc, value_si); - let get_field = own_field(vm, desc, get_si); - let set_field = own_field(vm, desc, set_si); - let writable_field = own_field(vm, desc, writable_si); - let enumerable = own_field(vm, desc, enumerable_si) + let value_field = own_field(vm, desc_val, value_si); + let get_field = own_field(vm, desc_val, get_si); + let set_field = own_field(vm, desc_val, set_si); + let writable_field = own_field(vm, desc_val, writable_si); + let enumerable = own_field(vm, desc_val, enumerable_si) .map(oxide_runtime_api::to_boolean) .unwrap_or(false); - let configurable = own_field(vm, desc, configurable_si) + let configurable = own_field(vm, desc_val, configurable_si) .map(oxide_runtime_api::to_boolean) .unwrap_or(false); @@ -264,11 +263,14 @@ fn array_like_elements(value: JsValue) -> Option> { Some((0..obj.prop_count() as usize).map(|idx| obj.get_prop_at(idx)).collect()) } -fn own_field(vm: &H, obj: &JsObject, prop_si: u32) -> Option { - vm.kernel_core() - .shape_forge() - .lookup_position(obj.shape_id(), prop_si) - .and_then(|pos| (obj.prop_vec_len() > pos as usize).then(|| obj.get_prop_at(pos))) +/// 按 ToPropertyDescriptor 语义取描述符字段:沿原型链判存在性,存在时经 +/// ordinary_get 取值(触发 accessor getter,receiver 为描述符对象本身)。 +fn own_field(vm: &mut H, desc: JsValue, prop_si: u32) -> Option { + // ordinary_get 对缺失属性返回 undefined,无法区分"不存在"与"值为 + // undefined",故先用 resolve_property 沿原型链判 HasProperty。 + let obj = unsafe { &*desc.as_js_object_ptr() }; + vm.resolve_property(obj, prop_si)?; + vm.ordinary_get(obj, prop_si, desc).ok() } fn make_string_array(vm: &mut H, parts: &[String]) -> JsValue {