mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-23 18:21:13 +08:00
feat: String 盒迁移 boxed_value 载荷并物化固有属性面
This commit is contained in:
@@ -87,6 +87,26 @@ pub(crate) fn tag_number_proto(proto: &P<JsObject>) {
|
||||
obj.set_boxed_value(JsValue::int(0));
|
||||
}
|
||||
|
||||
/// 把 String.prototype 标成 String 对象本体:规范 22.7.3 规定其是
|
||||
/// [[StringData]] = 空串的 String object。type_tag 是品牌表判据,boxed 值
|
||||
/// 供 thisStringValue/valueOf 的通用分支读取;length 自身属性按构造期
|
||||
/// 物化约定落地(writable:false / enumerable:false / configurable:false)。
|
||||
pub(crate) fn tag_string_proto(proto: &P<JsObject>, string_forge: &PermInterner, shape_forge: &ShapeForge) {
|
||||
let ptr = proto.as_ptr() as *mut JsObject;
|
||||
// SAFETY: proto 是 make_named_pair 刚建的本进程对象,P 引用与裸指针同址。
|
||||
let obj = unsafe { &mut *ptr };
|
||||
obj.type_tag = JsObject::OBJ_TYPE_STRING_OBJ;
|
||||
obj.set_boxed_value(JsValue::perm_string(crate::string_forge::empty_string_ptr()));
|
||||
let length_si = string_forge.intern("length").0;
|
||||
let shape_id = shape_forge.make_shape(obj.shape_id(), length_si);
|
||||
obj.set_shape_id(shape_id);
|
||||
// push_prop 返回绝对存储下标(尾部槽),meta 按同下标落位,
|
||||
// 避免写死槽号覆盖既有属性(如 constructor)的元数据。
|
||||
let length_pos = obj.push_prop(JsValue::int(0));
|
||||
obj.set_data_meta(length_pos, PropAttributes::new(false, false, false));
|
||||
obj.bump_generation();
|
||||
}
|
||||
|
||||
pub(crate) fn make_error_subtypes(error_proto: &P<JsObject>) -> ErrorSubtypeProtos {
|
||||
let error_proto_val = JsValue::from_js_object(error_proto.as_ptr() as *mut JsObject);
|
||||
ErrorSubtypeProtos {
|
||||
@@ -448,6 +468,7 @@ impl BuiltinWorld {
|
||||
let (array_proto, array_constructor) = make_named_pair(string_forge, shape_forge, labels, "Array");
|
||||
let (function_proto, function_constructor) = make_named_pair(string_forge, shape_forge, labels, "Function");
|
||||
let (string_proto, string_constructor) = make_named_pair(string_forge, shape_forge, labels, "String");
|
||||
tag_string_proto(&string_proto, string_forge, shape_forge);
|
||||
let (number_proto, number_constructor) = make_named_pair(string_forge, shape_forge, labels, "Number");
|
||||
tag_number_proto(&number_proto);
|
||||
let (boolean_proto, boolean_constructor) = make_named_pair(string_forge, shape_forge, labels, "Boolean");
|
||||
|
||||
@@ -7,7 +7,7 @@ use oxide_types::object::JsObject;
|
||||
use oxide_types::value::JsValue;
|
||||
|
||||
use super::construct::{
|
||||
builtin_labels, make_error_subtypes, make_named_pair, make_typed_array_family, tag_number_proto,
|
||||
builtin_labels, make_error_subtypes, make_named_pair, make_typed_array_family, tag_number_proto, tag_string_proto,
|
||||
wire_builtin_world_links, ErrorSubtypeProtos, TypedArrayFamily,
|
||||
};
|
||||
use super::BuiltinWorld;
|
||||
@@ -178,7 +178,11 @@ impl BuiltinWorld {
|
||||
(current.function_proto.clone(), current.function_constructor.clone())
|
||||
};
|
||||
let (string_proto, string_constructor) = if dirty.string {
|
||||
make_named_pair(string_forge, shape_forge, labels, "String")
|
||||
// 脏重建与全量构造同形:原型本体须带 String 对象 tag 与空串包值
|
||||
// (+length 物化),漏此分支 full_reset 后 tag 翻回 "Object"。
|
||||
let (proto, ctor) = make_named_pair(string_forge, shape_forge, labels, "String");
|
||||
tag_string_proto(&proto, string_forge, shape_forge);
|
||||
(proto, ctor)
|
||||
} else {
|
||||
(current.string_proto.clone(), current.string_constructor.clone())
|
||||
};
|
||||
|
||||
@@ -399,6 +399,29 @@ pub fn single_char_ptr(ch: u8) -> *const JsString {
|
||||
}
|
||||
}
|
||||
|
||||
/// 空串永久 `JsString` 指针,首用惰性物化后恒复用同一地址。
|
||||
/// 供 %StringPrototype% 的 `[[StringData]]` 载荷等零分配场景复用。
|
||||
static EMPTY_STRING: OnceLock<StringPtr> = OnceLock::new();
|
||||
|
||||
/// 取空串的永久 `JsString` 指针,惰性物化一次后恒返回同一地址。
|
||||
pub fn empty_string_ptr() -> *const JsString {
|
||||
match EMPTY_STRING.get() {
|
||||
Some(ptr) => ptr.0,
|
||||
None => {
|
||||
let ptr = Box::into_raw(Box::new(JsString::new(String::new())));
|
||||
match EMPTY_STRING.set(StringPtr(ptr)) {
|
||||
Ok(()) => ptr,
|
||||
Err(_) => {
|
||||
let existing = EMPTY_STRING.get().expect("set 失败时槽必已初始化").0;
|
||||
// SAFETY: ptr 来自本线程的 Box::into_raw,无任何外部引用。
|
||||
unsafe { drop(Box::from_raw(ptr)) };
|
||||
existing
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 小整数(0..=99)永久 `JsString` 指针表:`s += j` 等数字叶子拼接的高频命中路径,
|
||||
/// 免每次 `to_string` + 登记 2 次分配。物化面严格有界:100 条目 ≈ 4KB,
|
||||
/// 随进程生命周期有意保留(同 `SINGLE_CHAR_TABLE` 论证)。
|
||||
|
||||
Reference in New Issue
Block a user