From 02414144f3931648f661a5dd0d1da75f6adac999 Mon Sep 17 00:00:00 2001 From: pjh456 <147148383@qq.com> Date: Mon, 10 Aug 2026 16:13:24 +0800 Subject: [PATCH] =?UTF-8?q?perf:=20JsString=20=E7=BC=93=E5=AD=98=20UTF-16?= =?UTF-8?q?=20length=EF=BC=8C=E5=AD=97=E7=AC=A6=E4=B8=B2=20length=20?= =?UTF-8?q?=E8=AE=BF=E9=97=AE=E6=94=B9=20O(1)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crates/oxide_types/src/object.rs | 26 +++++++++++++++++++++++- crates/oxide_vm/src/dispatch/property.rs | 4 ++-- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/crates/oxide_types/src/object.rs b/crates/oxide_types/src/object.rs index fb98b3b5..4c26bd70 100644 --- a/crates/oxide_types/src/object.rs +++ b/crates/oxide_types/src/object.rs @@ -7,6 +7,7 @@ //! 闭包共享 cell (`Cell`)。 use crate::value::JsValue; +use std::sync::atomic::{AtomicU32, Ordering}; /// 堆分配的 JS 字符串值。 /// @@ -14,12 +15,24 @@ use crate::value::JsValue; #[derive(Debug)] pub struct JsString { 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 { /// 用 UTF-8 数据构造字符串。 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() } + /// 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 { self.data.is_empty() diff --git a/crates/oxide_vm/src/dispatch/property.rs b/crates/oxide_vm/src/dispatch/property.rs index c6d1bea2..a0918617 100644 --- a/crates/oxide_vm/src/dispatch/property.rs +++ b/crates/oxide_vm/src/dispatch/property.rs @@ -47,8 +47,8 @@ impl Vm { if val.is_string() { let length_si = self.kernel_core.perm_interner().intern("length").0; if prop_name_si == length_si { - // SAFETY: val 是字符串值。 - let len = unsafe { (*val.as_string_ptr()).data.encode_utf16().count() }; + // SAFETY: val 是字符串值。utf16_len 构造时缓存,O(1) 读取。 + let len = unsafe { (*val.as_string_ptr()).utf16_len() }; return Ok(Some(JsValue::int(len as i32))); } let proto_ptr = self.session.builtin_world().string_proto.as_ptr() as *mut JsObject;