mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-23 18:21:13 +08:00
perf: JsString 缓存 UTF-16 length,字符串 length 访问改 O(1)
This commit is contained in:
@@ -7,6 +7,7 @@
|
|||||||
//! 闭包共享 cell (`Cell`)。
|
//! 闭包共享 cell (`Cell`)。
|
||||||
|
|
||||||
use crate::value::JsValue;
|
use crate::value::JsValue;
|
||||||
|
use std::sync::atomic::{AtomicU32, Ordering};
|
||||||
|
|
||||||
/// 堆分配的 JS 字符串值。
|
/// 堆分配的 JS 字符串值。
|
||||||
///
|
///
|
||||||
@@ -14,12 +15,24 @@ use crate::value::JsValue;
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct JsString {
|
pub struct JsString {
|
||||||
pub data: String,
|
pub data: String,
|
||||||
|
/// JS 语义的字符串长度(UTF-16 code unit 数)懒缓存。
|
||||||
|
///
|
||||||
|
/// 构造是热路径(拼接/格式化),长度查询少见,故不预付 O(n) 扫描;首次
|
||||||
|
/// `utf16_len()` 访问时计算一次。以 sentinel + `AtomicU32` 实现:perm 字符串
|
||||||
|
/// 可被多线程 VM 共享读,计算幂等,relaxed 序即可。
|
||||||
|
utf16_len: AtomicU32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// `utf16_len` 未计算的哨兵值(有效长度不可能为 u32::MAX)。
|
||||||
|
const UTF16_LEN_UNSET: u32 = u32::MAX;
|
||||||
|
|
||||||
impl JsString {
|
impl JsString {
|
||||||
/// 用 UTF-8 数据构造字符串。
|
/// 用 UTF-8 数据构造字符串。
|
||||||
pub fn new(data: String) -> Self {
|
pub fn new(data: String) -> Self {
|
||||||
Self { data }
|
Self {
|
||||||
|
data,
|
||||||
|
utf16_len: AtomicU32::new(UTF16_LEN_UNSET),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 字符串的字节长度(非字符数)。
|
/// 字符串的字节长度(非字符数)。
|
||||||
@@ -27,6 +40,17 @@ impl JsString {
|
|||||||
self.data.len()
|
self.data.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// JS 字符串长度(UTF-16 code unit 数)。首次访问计算并缓存,此后 O(1)。
|
||||||
|
pub fn utf16_len(&self) -> u32 {
|
||||||
|
let cached = self.utf16_len.load(Ordering::Relaxed);
|
||||||
|
if cached != UTF16_LEN_UNSET {
|
||||||
|
return cached;
|
||||||
|
}
|
||||||
|
let len = self.data.encode_utf16().count() as u32;
|
||||||
|
self.utf16_len.store(len, Ordering::Relaxed);
|
||||||
|
len
|
||||||
|
}
|
||||||
|
|
||||||
/// 是否为空字符串。
|
/// 是否为空字符串。
|
||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool {
|
||||||
self.data.is_empty()
|
self.data.is_empty()
|
||||||
|
|||||||
@@ -47,8 +47,8 @@ impl Vm {
|
|||||||
if val.is_string() {
|
if val.is_string() {
|
||||||
let length_si = self.kernel_core.perm_interner().intern("length").0;
|
let length_si = self.kernel_core.perm_interner().intern("length").0;
|
||||||
if prop_name_si == length_si {
|
if prop_name_si == length_si {
|
||||||
// SAFETY: val 是字符串值。
|
// SAFETY: val 是字符串值。utf16_len 构造时缓存,O(1) 读取。
|
||||||
let len = unsafe { (*val.as_string_ptr()).data.encode_utf16().count() };
|
let len = unsafe { (*val.as_string_ptr()).utf16_len() };
|
||||||
return Ok(Some(JsValue::int(len as i32)));
|
return Ok(Some(JsValue::int(len as i32)));
|
||||||
}
|
}
|
||||||
let proto_ptr = self.session.builtin_world().string_proto.as_ptr() as *mut JsObject;
|
let proto_ptr = self.session.builtin_world().string_proto.as_ptr() as *mut JsObject;
|
||||||
|
|||||||
Reference in New Issue
Block a user