mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-25 03:01:12 +08:00
feat: String 盒迁移 boxed_value 载荷并物化固有属性面
This commit is contained in:
@@ -139,12 +139,12 @@ pub(crate) fn arraylike_get<H: VmHost>(vm: &mut H, ptr: *mut JsObject, i: usize)
|
||||
|
||||
/// 字符串源的 array-like 单元序列;非字符串源返回 `None`。
|
||||
///
|
||||
/// String exotic 对象的 `length` 与索引属性在引擎内未物化,Array.from /
|
||||
/// %TypedArray%.from 的 array-like 回退按 UTF-16 单元直接读:原始串取自身单元,
|
||||
/// 装箱串取其 `[[StringData]]`(槽 0)。单元长度即 `length`,第 i 个索引为第 i 个码元。
|
||||
/// Array.from / %TypedArray%.from 的 array-like 回退按 UTF-16 单元直接读:
|
||||
/// 原始串取自身单元,装箱串取其 `[[StringData]]`(boxed_value 载荷)。
|
||||
/// 单元长度即 `length`,第 i 个索引为第 i 个码元。
|
||||
///
|
||||
/// # 边界
|
||||
/// 装箱串槽 0 非字符串(异常形态)按非字符串源处理;指针为空返回 `None`。
|
||||
/// 装箱串载荷非字符串(异常形态)按非字符串源处理;指针为空返回 `None`。
|
||||
pub(crate) fn string_arraylike_units<H: VmHost>(vm: &H, value: JsValue) -> Option<Vec<u16>> {
|
||||
let raw = if value.is_string() {
|
||||
value
|
||||
@@ -158,7 +158,7 @@ pub(crate) fn string_arraylike_units<H: VmHost>(vm: &H, value: JsValue) -> Optio
|
||||
if !obj.is_string_obj() {
|
||||
return None;
|
||||
}
|
||||
let data = obj.get_prop_at(0);
|
||||
let data = obj.boxed_value();
|
||||
if !data.is_string() {
|
||||
return None;
|
||||
}
|
||||
|
||||
@@ -1547,10 +1547,10 @@ fn get_iterator<H: VmHost>(vm: &mut H, value: JsValue) -> Result<Option<(JsValue
|
||||
return Err(exc);
|
||||
}
|
||||
};
|
||||
// 码元快速路径的 inner:原始串取 value 本身;装箱串取其内容(槽 0 恒为
|
||||
// 原始串)——wrapper 码元步进按原始串产出,装箱串不直接作 inner。
|
||||
// 码元快速路径的 inner:原始串取 value 本身;装箱串取其 boxed_value
|
||||
// 载荷——wrapper 码元步进按原始串产出,装箱串不直接作 inner。
|
||||
let inner = if value_is_string_box {
|
||||
let raw = unsafe { (&*value.as_js_object_ptr()).get_prop_at(0) };
|
||||
let raw = unsafe { (&*value.as_js_object_ptr()).boxed_value() };
|
||||
if raw.is_string() {
|
||||
raw
|
||||
} else {
|
||||
|
||||
@@ -235,13 +235,7 @@ fn whitelist_element_name<H: VmHost>(vm: &mut H, elem: JsValue) -> Result<Option
|
||||
return Ok(None);
|
||||
}
|
||||
let obj = unsafe { &*ptr };
|
||||
// 装箱 String 的盒值存 prop 槽 0(boxed_value 槽不存)。
|
||||
let boxed = obj.boxed_value();
|
||||
let boxed = if boxed.is_undefined() && obj.is_string_obj() {
|
||||
obj.get_prop_at(0)
|
||||
} else {
|
||||
boxed
|
||||
};
|
||||
if !boxed.is_string() && !boxed.is_int() && !boxed.is_double() {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
@@ -466,7 +466,8 @@ pub fn object_constructor<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
let obj = vm.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::from_js_object(proto)));
|
||||
let obj_ref = unsafe { &mut *obj };
|
||||
obj_ref.type_tag = JsObject::OBJ_TYPE_STRING_OBJ;
|
||||
obj_ref.set_prop_at(0, val);
|
||||
// 构造期物化:boxed_value 载荷与字符索引/length 固有属性同批落地。
|
||||
oxide_runtime_api::materialize_string_box(vm, obj_ref, val);
|
||||
return NativeResult::Ok(JsValue::from_js_object(obj));
|
||||
}
|
||||
if val.is_bool() {
|
||||
@@ -638,10 +639,12 @@ pub fn object_assign<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
|
||||
let mut all_assignments: Vec<(u32, JsValue)> = Vec::new();
|
||||
for &arg_reg in args.iter().skip(2) {
|
||||
let source_val = vm.reg(arg_reg);
|
||||
if !source_val.is_object() {
|
||||
continue;
|
||||
}
|
||||
// null/undefined 源静默跳过(语料口径,非规范 ToObject 抛错);其余
|
||||
// 基元经 ToObject 装箱后走同一 walk(string 源自此获字符属性拷贝)。
|
||||
let source_val = match oxide_runtime_api::to_object(vm.reg(arg_reg), vm) {
|
||||
Ok(v) => v,
|
||||
Err(_) => continue,
|
||||
};
|
||||
let source_ptr = source_val.as_js_object_ptr();
|
||||
if source_ptr.is_null() {
|
||||
continue;
|
||||
@@ -866,8 +869,8 @@ pub(crate) fn define_from_descriptor<H: VmHost>(
|
||||
/// # 边界与前提
|
||||
/// - 仅处理可枚举自身属性;描述符值经 ordinary_get 读取(触发访问器 getter)
|
||||
/// - 描述符值的非对象校验由 define_from_descriptor 承担(ToPropertyDescriptor)
|
||||
/// - String 盒的自身键是字符下标 0..len-1(String exotic,各键值为对应
|
||||
/// 字符),盒存储未落属性枚举面,此处按规范物化
|
||||
/// - String 盒装箱后自身键为物化的字符下标(值为对应字符),走同一
|
||||
/// walk 路径;字符值非对象,ToPropertyDescriptor 按规范抛 TypeError
|
||||
///
|
||||
/// # 副作用
|
||||
/// - 修改 target 的 shape 链、属性表与 generation
|
||||
@@ -878,18 +881,7 @@ fn define_all_from_properties<H: VmHost>(
|
||||
// 前缀恢复后原类型抛出。
|
||||
let props_obj = oxide_runtime_api::to_object(props_val, vm)?;
|
||||
let props_ptr = props_obj.as_js_object_ptr();
|
||||
let descriptors: Vec<(u32, JsValue)> = if unsafe { &*props_ptr }.is_string_obj() {
|
||||
// String 盒:键为字符下标、值为字符本身;空串零键。
|
||||
let props = unsafe { &*props_ptr };
|
||||
let raw = props.boxed_value();
|
||||
let raw = if raw.is_undefined() { props.get_prop_at(0) } else { raw };
|
||||
let units = if raw.is_string() { vm.string_units(raw).to_vec() } else { Vec::new() };
|
||||
units
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, unit)| (make_int_key(i as u32), vm.new_string_units(std::slice::from_ref(unit))))
|
||||
.collect()
|
||||
} else {
|
||||
let descriptors: Vec<(u32, JsValue)> = {
|
||||
let props = unsafe { &*props_ptr };
|
||||
walk_own_keys(vm, props)
|
||||
.into_iter()
|
||||
@@ -1031,15 +1023,14 @@ pub fn object_get_own_property_descriptor<H: VmHost>(vm: &mut H, args: &[u8]) ->
|
||||
///
|
||||
/// # 步骤
|
||||
/// 1. ToObject 装箱接收者(null/undefined 抛 TypeError)
|
||||
/// 2. String 盒:按规范枚举虚拟键(整数下标 0..len-1 + "length"),构造描述符
|
||||
/// 3. 普通对象:按规范三段序枚举自身键(walk_own_keys + walk_own_symbol_keys)
|
||||
/// 4. 逐键取描述符(缺失键跳过),以数据属性定义到结果对象
|
||||
/// 2. 按规范三段序枚举自身键(walk_own_keys + walk_own_symbol_keys);
|
||||
/// String 盒装箱后自身键为物化的字符下标 + length,走同一路径
|
||||
/// 3. 逐键取描述符(缺失键跳过),以数据属性定义到结果对象
|
||||
///
|
||||
/// # 边界与前提
|
||||
/// - 结果对象 proto = %Object.prototype%,各键属性恒 writable/enumerable/
|
||||
/// configurable 全真(fresh 普通对象的 CreateDataPropertyOrThrow 形态)
|
||||
/// - 描述符取值与 gOPD 同核;模块命名空间未初始化导出抛 ReferenceError 原值
|
||||
/// - String 盒虚拟属性:字符下标 enumerable=true,length enumerable=false
|
||||
///
|
||||
/// # 副作用
|
||||
/// - 分配结果对象与每个描述符对象
|
||||
@@ -1049,11 +1040,6 @@ pub fn object_get_own_property_descriptors<H: VmHost>(vm: &mut H, args: &[u8]) -
|
||||
Err(err) => return NativeResult::Err(err),
|
||||
};
|
||||
|
||||
// String 盒:自身键为虚拟属性(从被包字符串值派生),不走 shape 链枚举。
|
||||
if unsafe { &*obj_ptr }.is_string_obj() {
|
||||
return string_exotic_get_own_property_descriptors(vm, obj_ptr);
|
||||
}
|
||||
|
||||
let obj = unsafe { &*obj_ptr };
|
||||
|
||||
// 三段自身键序:字符串/整数键(整键升序在前)后接 Symbol 键插入序。
|
||||
@@ -1080,81 +1066,6 @@ pub fn object_get_own_property_descriptors<H: VmHost>(vm: &mut H, args: &[u8]) -
|
||||
NativeResult::Ok(result_val)
|
||||
}
|
||||
|
||||
/// String 盒的 `getOwnPropertyDescriptors`:枚举虚拟键(字符下标 + length)。
|
||||
///
|
||||
/// # 步骤
|
||||
/// 1. 取被包字符串值(boxed_value 或 hash_props[0] fallback)
|
||||
/// 2. 按 UTF-16 单元枚举:整数下标 0..len-1(enumerable=true)+ "length"(enumerable=false)
|
||||
/// 3. 逐键构造描述符对象并写入结果
|
||||
///
|
||||
/// # 边界与前提
|
||||
/// - 空串:仅返回 length 描述符
|
||||
/// - 非字符串被包值:退化为零键
|
||||
fn string_exotic_get_own_property_descriptors<H: VmHost>(vm: &mut H, obj_ptr: *mut JsObject) -> NativeResult {
|
||||
let obj = unsafe { &*obj_ptr };
|
||||
// 取被包字符串值:优先 boxed_value,回退 hash_props[0]。
|
||||
let raw = obj.boxed_value();
|
||||
let raw = if raw.is_undefined() { obj.get_prop_at(0) } else { raw };
|
||||
let units = if raw.is_string() { vm.string_units(raw).to_vec() } else { Vec::new() };
|
||||
let len = units.len();
|
||||
|
||||
// 结果对象:proto = %Object.prototype%。
|
||||
let desc_proto = vm.session().builtin_world().object_proto.as_ptr() as *mut JsObject;
|
||||
let result = vm.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::from_js_object(desc_proto)));
|
||||
let result_val = JsValue::from_js_object(result);
|
||||
|
||||
// 预计算 interned 键。
|
||||
let intern = vm.kernel_core().perm_interner();
|
||||
let value_si = intern.intern("value").0;
|
||||
let writable_si = intern.intern("writable").0;
|
||||
let enumerable_si = intern.intern("enumerable").0;
|
||||
let configurable_si = intern.intern("configurable").0;
|
||||
let length_si = intern.intern("length").0;
|
||||
|
||||
// 整数下标键 0..len-1:enumerable=true, writable=false, configurable=false。
|
||||
for (i, unit) in units.iter().enumerate() {
|
||||
let si = make_int_key(i as u32);
|
||||
let char_val = vm.new_string_units(std::slice::from_ref(unit));
|
||||
let desc = alloc_desc_object(vm);
|
||||
let desc_obj = unsafe { &mut *desc };
|
||||
let desc_obj_ptr = JsValue::from_js_object(desc);
|
||||
// 构造描述符对象:value + writable/enumerable/configurable。
|
||||
vm.define_data_property(desc_obj, value_si, char_val, PropAttributes::DEFAULT_DATA)
|
||||
.ok();
|
||||
vm.define_data_property(desc_obj, writable_si, JsValue::bool(false), PropAttributes::DEFAULT_DATA)
|
||||
.ok();
|
||||
vm.define_data_property(desc_obj, enumerable_si, JsValue::bool(true), PropAttributes::DEFAULT_DATA)
|
||||
.ok();
|
||||
vm.define_data_property(desc_obj, configurable_si, JsValue::bool(false), PropAttributes::DEFAULT_DATA)
|
||||
.ok();
|
||||
if let Err(err) =
|
||||
vm.define_data_property(unsafe { &mut *result }, si, desc_obj_ptr, PropAttributes::DEFAULT_DATA)
|
||||
{
|
||||
return NativeResult::Err(crate::error::create_type_error(vm, &err));
|
||||
}
|
||||
}
|
||||
|
||||
// "length" 键:enumerable=false, writable=false, configurable=false。
|
||||
let desc = alloc_desc_object(vm);
|
||||
let desc_obj = unsafe { &mut *desc };
|
||||
let desc_obj_ptr = JsValue::from_js_object(desc);
|
||||
vm.define_data_property(desc_obj, value_si, JsValue::int(len as i32), PropAttributes::DEFAULT_DATA)
|
||||
.ok();
|
||||
vm.define_data_property(desc_obj, writable_si, JsValue::bool(false), PropAttributes::DEFAULT_DATA)
|
||||
.ok();
|
||||
vm.define_data_property(desc_obj, enumerable_si, JsValue::bool(false), PropAttributes::DEFAULT_DATA)
|
||||
.ok();
|
||||
vm.define_data_property(desc_obj, configurable_si, JsValue::bool(false), PropAttributes::DEFAULT_DATA)
|
||||
.ok();
|
||||
if let Err(err) =
|
||||
vm.define_data_property(unsafe { &mut *result }, length_si, desc_obj_ptr, PropAttributes::DEFAULT_DATA)
|
||||
{
|
||||
return NativeResult::Err(crate::error::create_type_error(vm, &err));
|
||||
}
|
||||
|
||||
NativeResult::Ok(result_val)
|
||||
}
|
||||
|
||||
/// 按 ToPropertyDescriptor 语义取描述符字段:沿原型链判存在性,存在时经
|
||||
/// ordinary_get 取值(触发 accessor getter,receiver 为描述符对象本身)。
|
||||
fn own_field<H: VmHost>(vm: &mut H, desc: JsValue, prop_si: u32) -> Option<JsValue> {
|
||||
|
||||
@@ -114,7 +114,7 @@ pub fn string_value_of<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
if !ptr.is_null() {
|
||||
let obj = unsafe { &*ptr };
|
||||
if obj.is_string_obj() {
|
||||
return NativeResult::Ok(obj.get_prop_at(0));
|
||||
return NativeResult::Ok(obj.boxed_value());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -172,7 +172,8 @@ pub fn string_constructor<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
|
||||
let obj = unsafe { &mut *this_val.as_js_object_ptr() };
|
||||
obj.type_tag = JsObject::OBJ_TYPE_STRING_OBJ;
|
||||
obj.push_prop(str_val);
|
||||
// 构造期物化:boxed_value 载荷与字符索引/length 固有属性同批落地。
|
||||
oxide_runtime_api::materialize_string_box(vm, obj, str_val);
|
||||
NativeResult::Ok(this_val)
|
||||
}
|
||||
|
||||
@@ -187,7 +188,7 @@ pub fn string_to_string<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
if !ptr.is_null() {
|
||||
let obj = unsafe { &*ptr };
|
||||
if obj.is_string_obj() {
|
||||
return NativeResult::Ok(obj.get_prop_at(0));
|
||||
return NativeResult::Ok(obj.boxed_value());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user