feat: mapped arguments defineProperty 后参数与 arguments 再同步

This commit is contained in:
2026-10-09 23:27:18 +00:00
parent 6ba2043599
commit 2b18c4d264
21 changed files with 346 additions and 25 deletions
+60
View File
@@ -1,5 +1,6 @@
use oxide_kernel::shape_forge::{ShapeForge, EMPTY_SHAPE_ID};
use oxide_kernel::string_forge::PermInterner;
use oxide_types::arguments_map::ArgumentsMapState;
use oxide_types::object::{JsObject, PropAttributes, PropMetaEntry};
use oxide_types::private_key::{
decode_symbol_key, encode_symbol_key, int_key_value, is_int_key, is_private_name_key, is_symbol_key, make_int_key,
@@ -365,6 +366,33 @@ pub fn delete_own_property_outcome<H: VmHost>(
}
}
// mapped arguments exotic [[Delete]]:整数索引且映射存活时,属性不可配置返回
// NonConfigurable(严格抛 TypeError、sloppy 返回 false);可配置时移除映射并
// 落穿普通删除路径。accessor 属性不移除映射(无参数寄存器同步)。
if obj.is_arguments_obj() {
let state_ptr = obj.native_data() as *mut ArgumentsMapState;
if !state_ptr.is_null() {
// SAFETY: native_data 由创建期 Box::into_raw 分配,生命周期与对象一致。
let state = unsafe { &mut *state_ptr };
if vm.arguments_mapping_alive(state) {
if let Some(index) = array_index_of(vm, key_si) {
if (index as u16) < state.param_count && state.is_mapped(index as u16) {
let pos = vm.get_own_property_slot(obj, key_si);
let meta = pos.and_then(|p| obj.prop_meta_at(p));
let is_accessor = meta.is_some_and(|m| m.is_accessor);
let configurable = meta.map(|m| m.attributes.configurable()).unwrap_or(true);
if !configurable {
return Ok(DeleteOutcome::NonConfigurable);
}
if !is_accessor {
state.unmap(index as u16);
}
}
}
}
}
}
// 数组下标元素在元素区,不参与 shape 链,单独删除(保持 length 不变)。
if obj.is_array() {
if let Some(index) = array_index_of(vm, key_si) {
@@ -955,6 +983,38 @@ pub(crate) fn define_from_descriptor<H: VmHost>(
}
}
// mapped arguments exotic [[DefineOwnProperty]]:整数索引且映射存活时,旧描述符
// 可写且新描述符不可写则移除映射,新描述符含 value 则写参数寄存器;随后落穿
// 普通 define 路径(描述符收窄校验由 define_data_property 承担)。
if unsafe { &*obj_ptr }.is_arguments_obj() {
let state_ptr = unsafe { &*obj_ptr }.native_data() as *mut ArgumentsMapState;
if !state_ptr.is_null() {
// SAFETY: native_data 由创建期 Box::into_raw 分配,生命周期与对象一致。
let state = unsafe { &mut *state_ptr };
if vm.arguments_mapping_alive(state) {
if let Some(index) = array_index_of(vm, key_si) {
if (index as u16) < state.param_count && state.is_mapped(index as u16) {
let old_writable = existing_meta.map(|m| m.attributes.writable()).unwrap_or(true);
let new_writable = if has_existing {
writable_field
.map(oxide_runtime_api::to_boolean)
.unwrap_or_else(|| existing_meta.map(|m| m.attributes.writable()).unwrap_or(false))
} else {
writable_field.map(oxide_runtime_api::to_boolean).unwrap_or(false)
};
if old_writable && !new_writable {
state.unmap(index as u16);
}
if let Some(v) = value_field {
let reg = (state.param_base as u16 + index as u16) as u8;
vm.set_reg(reg, v);
}
}
}
}
}
}
let obj = unsafe { &mut *obj_ptr };
if has_accessor {
vm.define_accessor_property(obj, key_si, get, set, PropAttributes::new(false, enumerable, configurable))