fix: upvalue cell 改独立堆分配消除 GC sweep 后悬垂
upvalue cell 原先分配于 session_epoch bump arena,对象 sweep 替换 arena 后旧 Bump drop,全部闭包 cell 悬垂:后续分配复用其内存导致 upvalue 值 被覆盖(私有字段 brand 检查跨语句误报、release 下可致 SIGSEGV)。 cell 改为 Box::into_raw 独立堆分配并登记进 session_cell_ptrs 追踪表, 与 arena 生命周期解耦:sweep 搬移对象时 cell 指针稳定,只重写 cell.value 中的对象引用;full_reset 统一释放,无 double-free。
This commit is contained in:
@@ -15,7 +15,7 @@ use rustc_hash::FxBuildHasher;
|
||||
|
||||
use crate::session_gc::SessionGc;
|
||||
use crate::vm::ForInIter;
|
||||
use oxide_types::object::{JsObject, JsString};
|
||||
use oxide_types::object::{Cell as UpvalueCell, JsObject, JsString};
|
||||
use oxide_types::value::JsValue;
|
||||
|
||||
/// session arena 与 GC 簿记。
|
||||
@@ -33,6 +33,10 @@ pub(crate) struct GcState {
|
||||
/// `convert_immutables` 也能登记新 box。与字符串不同,BigInt 不参与
|
||||
/// mark/sweep 回收(值量少),只在 full_reset 统一释放。
|
||||
pub(crate) session_bigint_ptrs: RefCell<Vec<*mut num_bigint::BigInt>>,
|
||||
/// upvalue cell(`Box<Cell>`)追踪表。`RefCell` 使 `&self` 的分配入口也能
|
||||
/// 登记新 box。cell 独立堆分配、地址稳定,不参与对象搬移(sweep 只重写
|
||||
/// `cell.value` 中的对象引用),只在 full_reset 统一释放。
|
||||
pub(crate) session_cell_ptrs: RefCell<Vec<*mut UpvalueCell>>,
|
||||
pub(crate) session_bytes_allocated: usize,
|
||||
/// 执行期字符串 GC 的触发水位:本次收集后的存活字节 + 阈值增量。
|
||||
/// 仅当账目超过水位才在指令边界触发回收——活串超阈值时不会每指令重复
|
||||
@@ -45,6 +49,29 @@ impl GcState {
|
||||
pub(crate) fn track_epoch_object(&mut self, ptr: *mut JsObject) {
|
||||
self.epoch_object_ptrs.push(ptr);
|
||||
}
|
||||
|
||||
/// 分配一个 upvalue cell:独立堆分配并返回裸指针,脱离 session arena 生命周期。
|
||||
///
|
||||
/// cell 指针登记进 `session_cell_ptrs`,在 `full_reset` 统一释放。对象 sweep
|
||||
/// 搬移不触碰 cell 结构体(地址稳定),只重写 `cell.value` 中的对象引用。
|
||||
/// `&self` 使调用方可与 `cell_stack` 等其它字段的借用并存(分字段借用)。
|
||||
pub(crate) fn alloc_cell(&self, value: JsValue, initialized: bool) -> *mut UpvalueCell {
|
||||
let ptr = Box::into_raw(Box::new(UpvalueCell::new(value, initialized)));
|
||||
self.session_cell_ptrs.borrow_mut().push(ptr);
|
||||
ptr
|
||||
}
|
||||
|
||||
/// 释放全部 session 堆 upvalue cell box。仅在完全隔离重置(`full_reset`)时调用,
|
||||
/// 此时没有存活的 cell_stack / 函数对象 upvalues 会引用它们。
|
||||
pub(crate) fn free_cells(&mut self) {
|
||||
for ptr in self.session_cell_ptrs.borrow_mut().drain(..) {
|
||||
// SAFETY: 每个指针来自 alloc_cell 的 Box::into_raw(Box::new(Cell)),
|
||||
// 且只在这里恰好释放一次。
|
||||
unsafe {
|
||||
drop(Box::from_raw(ptr));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Symbol 的 intern 状态。
|
||||
|
||||
Reference in New Issue
Block a user