mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-23 18:21:13 +08:00
perf: 字符串 +/+= 二元拼接改 Cons rope 惰性扁平化消除 O(n²)
JsString 拆 Flat/Cons 变体:Cons 经独立 ConsNode 保存左右子节点 + O(1) 字节长 + 惰性扁平化产物缓存(OnceLock 原子发布,产物挂节点生命周期)。 concat_strings 接线:总长 ≤ 128B 的小链急切扁平(与 rope 前同款,拼接即 消费场景零开销),大链 O(1) 链接——大段重复拼接从 O(n²) 拷贝降为 O(n) 链接,文本在消费点(.length/==/string_ref/方法族)首次扁平化后缓存。 GC 兼容:mark 收口 mark_string_live 传播 Cons 子节点与产物闭包(显式栈 防深链爆栈);sweep/full_reset 共用 drop 辅助连带释放产物;节点字节记账 用 O(1) byte_len。rope 节点登记 session 字符串表,与执行期字符串 GC (指令边界触发)天然兼容。JsString 结构 32B 与 rope 前同 bin,小串路径 零结构回退;unsafe impl Send/Sync 论证同 StringPtr(perm 恒 Flat)。
This commit is contained in:
@@ -78,22 +78,57 @@ impl Vm {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 字符串拼接热路径:一次预分配写齐两个操作数的 ToString 文本。
|
||||
/// 字符串拼接接线点(二元 `+`/`+=` 共用):O(1) 链接为 Cons(rope)节点,
|
||||
/// 消除逐次整串重拷贝。文本在消费时(`.length`/`==`/string_ref 等)惰性扁平化。
|
||||
///
|
||||
/// # 步骤
|
||||
/// 1. 按字符串操作数字节长预分配容量(余量覆盖数字/布尔等格式化文本)。
|
||||
/// 2. 两个操作数依次走 push_to_string(BigInt 输出十进制,Symbol 由调用方先行拒绝)。
|
||||
/// 3. 生成会话字符串写入目标寄存器。
|
||||
/// 1. 非字符串操作数先转成叶子字符串(`push_to_string` 同文本语义;小整数走
|
||||
/// 永久缓存零分配,其余 `to_string` + owned)。
|
||||
/// 2. 两个字符串经 `new_cons_string` 链接(每链接 1 次节点分配,对比原 O(n)
|
||||
/// 拷贝 + 结果串分配)。
|
||||
///
|
||||
/// # 副作用
|
||||
/// 新建一个会话字符串,登记到 session 生命周期。
|
||||
/// - 新建 Cons 节点 + 可能的数字叶子,登记到 session 生命周期。回收点仅在
|
||||
/// dispatch 指令边界(结果已写寄存器后检查),链接期子节点天然安全,
|
||||
/// 无需在途保护。
|
||||
fn concat_strings(&mut self, lhs: JsValue, rhs: JsValue) -> JsValue {
|
||||
// 小链急切扁平(与 rope 前同款实现):总字节长 ≤ 阈值时单次预分配
|
||||
// 写齐,零叶子转换 / Cons 节点 / 惰性扁平化开销——拼接即消费的小串
|
||||
// 场景与基线逐字节等价(该场景 rope 的 O(1) 链接收益低于其固定开销)。
|
||||
let lbytes = if lhs.is_string() { unsafe { (*lhs.as_string_ptr()).len() } } else { 0 };
|
||||
let rbytes = if rhs.is_string() { unsafe { (*rhs.as_string_ptr()).len() } } else { 0 };
|
||||
let mut buf = String::with_capacity(lbytes + rbytes + 32);
|
||||
coercion::push_to_string(lhs, &mut buf);
|
||||
coercion::push_to_string(rhs, &mut buf);
|
||||
self.new_string_owned(buf)
|
||||
if lbytes + rbytes <= Self::CONS_FLATTEN_BYTES {
|
||||
let mut buf = String::with_capacity(lbytes + rbytes + 32);
|
||||
coercion::push_to_string(lhs, &mut buf);
|
||||
coercion::push_to_string(rhs, &mut buf);
|
||||
return self.new_string_owned(buf);
|
||||
}
|
||||
// 大链走 Cons rope:非字符串操作数先转叶子,再 O(1) 链接(文本惰性扁平化)。
|
||||
let lv = if lhs.is_string() {
|
||||
lhs
|
||||
} else {
|
||||
self.string_leaf(lhs)
|
||||
};
|
||||
let rv = if rhs.is_string() {
|
||||
rhs
|
||||
} else {
|
||||
self.string_leaf(rhs)
|
||||
};
|
||||
self.new_cons_string(lv, rv)
|
||||
}
|
||||
|
||||
/// 把非字符串原语转为叶子字符串:0..=99 小整数命中永久缓存(零分配),
|
||||
/// 其余走 `to_string` + `new_string_owned`(语义与 `push_to_string` 一致)。
|
||||
fn string_leaf(&mut self, v: JsValue) -> JsValue {
|
||||
if v.is_int() {
|
||||
let n = v.as_int();
|
||||
if n >= 0 {
|
||||
if let Some(ptr) = oxide_kernel::string_forge::small_int_ptr(n as u32) {
|
||||
return JsValue::string(ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
self.new_string_owned(coercion::to_string(v))
|
||||
}
|
||||
|
||||
/// CONCAT_N:多操作数拼接(连续 `+` 左结合链摊平)的两阶段 dispatch。
|
||||
|
||||
Reference in New Issue
Block a user