feat: String 盒迁移 boxed_value 载荷并物化固有属性面

This commit is contained in:
2026-09-22 16:40:01 +00:00
parent 1be90d90aa
commit 2252ed7bbc
13 changed files with 432 additions and 149 deletions
+49 -5
View File
@@ -8,7 +8,8 @@ use std::cmp::Ordering;
use num_traits::{ToPrimitive, Zero};
use oxide_types::mem::P;
use oxide_types::object::JsObject;
use oxide_types::object::{JsObject, PropAttributes};
use oxide_types::private_key::make_int_key;
use oxide_types::shape::EMPTY_SHAPE_ID;
use oxide_types::value::{JsType, JsValue};
@@ -744,11 +745,55 @@ pub fn strict_equality(lhs: JsValue, rhs: JsValue) -> bool {
}
}
/// 把 String 盒的规范固有属性面物化为普通 shape 属性:被包串写入
/// `boxed_value` 载荷,字符索引 0..len-1(writable:false / enumerable:true /
/// configurable:false)与 `length`(writable:false / enumerable:false /
/// configurable:false)逐键 shape 转换后落属性区。
///
/// 物化后 String exotic 的 [[Get]]/[[Has]]/[[Set]]/[[DefineOwnProperty]]/
/// [[Delete]]/枚举语义由既有属性机制承担:写失败静默(sloppy)/抛错
/// (strict)、同值重定义放行与异值重定义抛 TypeError、delete 返 false,
/// 与 exotic 定义逐条同值,VM 属性派发面零特判。
///
/// # 步骤
/// 1. 整串单元序列落地(借用结束),`boxed_value` 记被包串
/// 2. 逐单元:整数键 shape 转换 → 单单元串落槽 → 索引属性 meta
/// 3. `length` 键 shape 转换 → 单元数落槽 → length 属性 meta
///
/// # 边界与前提
/// - 调用时对象须为刚分配的空盒(EMPTY_SHAPE_ID、无属性),构造点唯一入口
/// - 长串构造成本与单元数线性(每键一次 shape 转换 + 单单元串),
/// ASCII 单元命中 perm 静态表免 session 分配
///
/// # 副作用
/// - 修改对象 shape 链、属性区与 generation;单单元串/整串进 session 字符串区
pub fn materialize_string_box<H: VmHost>(host: &mut H, obj: &mut JsObject, str_val: JsValue) {
let units = host.string_units(str_val).into_owned();
let len = units.len();
obj.set_boxed_value(str_val);
for (i, &unit) in units.iter().enumerate() {
let shape_id = host
.kernel_core()
.shape_forge()
.make_shape(obj.shape_id(), make_int_key(i as u32));
obj.set_shape_id(shape_id);
let ch = host.single_unit(unit).unwrap_or_else(|| host.new_string_units(&[unit]));
obj.push_prop(ch);
obj.set_data_meta(i as u32, PropAttributes::new(false, true, false));
}
let length_si = host.kernel_core().perm_interner().intern("length").0;
let shape_id = host.kernel_core().shape_forge().make_shape(obj.shape_id(), length_si);
obj.set_shape_id(shape_id);
obj.push_prop(JsValue::int(len as i32));
obj.set_data_meta(len as u32, PropAttributes::new(false, false, false));
obj.bump_generation();
}
/// ToObject(ECMA-262 §7.1.13):null/undefined 抛 TypeError,其余原始值包装为对应包装对象。
///
/// 包装对象按类型选择原型(String/Number/Boolean 原型或默认 Object 原型);
/// 被包基元写入对象专属载荷字段,不占命名属性区。字符串盒暂仍预存属性区
/// 槽 0——其消费面(解盒读原始串)与规范固有属性面同批切换,两端不可分拆。
/// 被包基元写入对象专属载荷字段,不占命名属性区。字符串盒经
/// [`materialize_string_box`] 同步物化字符索引与 length 固有属性面。
pub fn to_object<H: VmHost>(val: JsValue, host: &mut H) -> Result<JsValue, String> {
if val.is_object() {
return Ok(val);
@@ -776,8 +821,7 @@ pub fn to_object<H: VmHost>(val: JsValue, host: &mut H) -> Result<JsValue, Strin
let obj_ref = unsafe { &mut *obj };
obj_ref.type_tag = type_tag;
if val.is_string() {
obj_ref.ensure_hash_props().push(val);
obj_ref.set_prop_count(1);
materialize_string_box(host, obj_ref, val);
} else {
obj_ref.set_boxed_value(val);
}
+5 -5
View File
@@ -20,11 +20,11 @@ mod runtime_api_log;
pub use coercion::{
abstract_eq, bigint_data, bigint_to_f64, bigint_to_string, format_error_message, js_number_to_string,
push_to_string, push_units_to, relational_compare, same_value, same_value_zero, strict_equality, string_concat,
string_value_eq, to_bigint_full, to_boolean, to_int32, to_integer_or_infinity, to_length, to_number,
to_number_full, to_object, to_primitive, to_string, to_string_for_string_constructor, to_string_full,
to_string_value_full, to_uint32, to_units_full, well_known_symbol_id, well_known_symbol_name, write_number_into,
ToPrimitiveHint,
materialize_string_box, push_to_string, push_units_to, relational_compare, same_value, same_value_zero,
strict_equality, string_concat, string_value_eq, to_bigint_full, to_boolean, to_int32, to_integer_or_infinity,
to_length, to_number, to_number_full, to_object, to_primitive, to_string, to_string_for_string_constructor,
to_string_full, to_string_value_full, to_uint32, to_units_full, well_known_symbol_id, well_known_symbol_name,
write_number_into, ToPrimitiveHint,
};
pub use host::VmHost;
pub use native_result::NativeResult;