fix: 执行期字符串 GC 触发点移到指令边界,消除 builtin 局部活串悬垂

分配点触发会把仅存于 builtin 函数栈上局部 JsValue 与构造中未登记对象的
存活串判死释放(temporal 槽、regexp exec 构造中数组、replace 回调参数
Vec),长会话超阈值即悬垂。触发改在 dispatch 指令边界,此时所有局部值已
落地为执行根;分配点只留账目。水位采用上次收集存活字节加阈值增量,活串
超阈值时不会每指令重复白跑;reset 完整收集仍按阈值直接比较。debug 构建下
收集后断言存活对象字符串边已登记。补低阈值回归:regexp exec 旧行为直接
SIGABRT,temporal 与 replace 结果断言守护。
This commit is contained in:
2026-08-15 13:20:04 +08:00
parent f4c58d5dd9
commit 81f54f280d
5 changed files with 136 additions and 17 deletions
+6
View File
@@ -1320,6 +1320,12 @@ impl Vm {
let mut steps: u64 = 0;
loop {
steps += 1;
// 执行期字符串 GC 安全点:指令边界上无 builtin 局部活值(分配点触发
// 会释放仅存于 Rust 局部/构造中未登记对象的串),此处触发保证回收
// 时所有存活串都已落地为执行根。账目未超水位时仅 2 次字段比较。
if self.gc_state.session_bytes_allocated >= self.gc_state.string_gc_watermark {
self.maybe_collect_session_strings();
}
if let Some(max_steps) = max_steps {
if steps > max_steps {
vm_warn!("dispatch: step limit {} exceeded at pc={}", max_steps, self.pc);