mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-23 18:21:13 +08:00
refactor: 退役 session_epoch Bump 字段
This commit is contained in:
@@ -1106,7 +1106,7 @@ fn global_prop_opt(vm: &Vm, name: &str) -> Option<JsValue> {
|
|||||||
vm.resolve_property(global, si)
|
vm.resolve_property(global, si)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 闭包捕获变量跨对象 sweep 存活:reset 触发完整收集(session_epoch 替换)。
|
/// 闭包捕获变量跨对象 sweep 存活:reset 触发完整收集。
|
||||||
/// cell 独立堆分配、地址稳定,原地 sweep 不搬移对象、不触碰 cell 结构——
|
/// cell 独立堆分配、地址稳定,原地 sweep 不搬移对象、不触碰 cell 结构——
|
||||||
/// 跨收集的 cell 指针与值均保留。
|
/// 跨收集的 cell 指针与值均保留。
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -201,7 +201,7 @@ impl SuspendedFrame {
|
|||||||
if p.is_null() {
|
if p.is_null() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// SAFETY: cell 由 session_epoch 分配,本 session 内指针有效。
|
// SAFETY: cell 经 alloc_cell 独立堆分配,本 session 内指针有效。
|
||||||
f(unsafe { &*p }.value);
|
f(unsafe { &*p }.value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -265,7 +265,7 @@ impl SuspendedFrame {
|
|||||||
if p.is_null() {
|
if p.is_null() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// SAFETY: cell 由 session_epoch 分配,本 session 内指针有效。
|
// SAFETY: cell 经 alloc_cell 独立堆分配,本 session 内指针有效。
|
||||||
let cell = unsafe { &mut *p };
|
let cell = unsafe { &mut *p };
|
||||||
cell.value = rewrite(cell.value);
|
cell.value = rewrite(cell.value);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ impl Vm {
|
|||||||
if cell_ptr.is_null() {
|
if cell_ptr.is_null() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// SAFETY: cell 由 session_epoch 分配,本 session 内指针有效。
|
// SAFETY: cell 经 alloc_cell 独立堆分配,本 session 内指针有效。
|
||||||
f(unsafe { &*cell_ptr }.value);
|
f(unsafe { &*cell_ptr }.value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -129,7 +129,7 @@ impl Vm {
|
|||||||
if cell_ptr.is_null() {
|
if cell_ptr.is_null() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// SAFETY: cell 由 session_epoch 分配,本 session 内指针有效。
|
// SAFETY: cell 经 alloc_cell 独立堆分配,本 session 内指针有效。
|
||||||
let cell = unsafe { &mut *cell_ptr };
|
let cell = unsafe { &mut *cell_ptr };
|
||||||
cell.value = rewrite(cell.value);
|
cell.value = rewrite(cell.value);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,13 +18,12 @@ use oxide_types::object::{Cell as UpvalueCell, JsObject, JsString};
|
|||||||
use oxide_types::private_key::WELL_KNOWN_SYMBOL_COUNT;
|
use oxide_types::private_key::WELL_KNOWN_SYMBOL_COUNT;
|
||||||
use oxide_types::value::JsValue;
|
use oxide_types::value::JsValue;
|
||||||
|
|
||||||
/// session arena 与 GC 簿记。
|
/// session 堆与 GC 簿记。
|
||||||
///
|
///
|
||||||
/// 仅做字段分类。mark/sweep/rewrite_vm_roots 驻留在 `Vm` 上:GC 需扫描所有
|
/// 仅做字段分类。mark/sweep/rewrite_vm_roots 驻留在 `Vm` 上:GC 需扫描所有
|
||||||
/// 子结构的根(regs、frames、for_in_iters、for_of_iters、exception_value 等),
|
/// 子结构的根(regs、frames、for_in_iters、for_of_iters、exception_value 等),
|
||||||
/// 无法限制在 GcState 内。
|
/// 无法限制在 GcState 内。
|
||||||
pub(crate) struct GcState {
|
pub(crate) struct GcState {
|
||||||
pub(crate) session_epoch: bumpalo::Bump,
|
|
||||||
pub(crate) session_gc: SessionGc,
|
pub(crate) session_gc: SessionGc,
|
||||||
pub(crate) session_object_ptrs: Vec<*mut JsObject>,
|
pub(crate) session_object_ptrs: Vec<*mut JsObject>,
|
||||||
pub(crate) session_string_ptrs: Vec<*mut JsString>,
|
pub(crate) session_string_ptrs: Vec<*mut JsString>,
|
||||||
|
|||||||
@@ -122,7 +122,6 @@ impl Vm {
|
|||||||
async_gen_dispatch: false,
|
async_gen_dispatch: false,
|
||||||
async_gen_suspended: false,
|
async_gen_suspended: false,
|
||||||
gc_state: GcState {
|
gc_state: GcState {
|
||||||
session_epoch: bumpalo::Bump::new(),
|
|
||||||
session_gc: crate::session_gc::SessionGc::new(),
|
session_gc: crate::session_gc::SessionGc::new(),
|
||||||
session_object_ptrs: Vec::new(),
|
session_object_ptrs: Vec::new(),
|
||||||
session_string_ptrs: Vec::new(),
|
session_string_ptrs: Vec::new(),
|
||||||
@@ -257,7 +256,6 @@ impl Vm {
|
|||||||
async_gen_dispatch: false,
|
async_gen_dispatch: false,
|
||||||
async_gen_suspended: false,
|
async_gen_suspended: false,
|
||||||
gc_state: GcState {
|
gc_state: GcState {
|
||||||
session_epoch: bumpalo::Bump::new(),
|
|
||||||
session_gc: crate::session_gc::SessionGc::new(),
|
session_gc: crate::session_gc::SessionGc::new(),
|
||||||
session_object_ptrs: Vec::new(),
|
session_object_ptrs: Vec::new(),
|
||||||
session_string_ptrs: Vec::new(),
|
session_string_ptrs: Vec::new(),
|
||||||
@@ -397,9 +395,6 @@ impl Vm {
|
|||||||
);
|
);
|
||||||
self.active_immutables = std::ptr::slice_from_raw_parts(std::ptr::null(), 0);
|
self.active_immutables = std::ptr::slice_from_raw_parts(std::ptr::null(), 0);
|
||||||
self.teardown_session_heap_data();
|
self.teardown_session_heap_data();
|
||||||
// 换新 Bump:旧 session arena 全量归还系统分配器(与 sweep 路径同构),
|
|
||||||
// 容量不跨 full_reset 保留。
|
|
||||||
self.gc_state.session_epoch = bumpalo::Bump::new();
|
|
||||||
self.gc_state.session_bytes_allocated = 0;
|
self.gc_state.session_bytes_allocated = 0;
|
||||||
self.gc_state.session_bytes_peak = 0;
|
self.gc_state.session_bytes_peak = 0;
|
||||||
self.gc_state.run_alloc_peak = 0;
|
self.gc_state.run_alloc_peak = 0;
|
||||||
@@ -417,10 +412,8 @@ impl Vm {
|
|||||||
/// + session 串 + BigInt box + upvalue cell box。
|
/// + session 串 + BigInt box + upvalue cell box。
|
||||||
///
|
///
|
||||||
/// 供 `full_reset` 与 `Drop` 共用——统一入口路径上对象本体全部为堆载体
|
/// 供 `full_reset` 与 `Drop` 共用——统一入口路径上对象本体全部为堆载体
|
||||||
/// (`Box::from_raw` 恰好释放一次;晋升族 Bump 克隆仅测试形态,本体随
|
/// (`Box::from_raw` 恰好释放一次),堆数据与 upvalue 列表各恰好释放一次。
|
||||||
/// 换新 Bump 归还),堆数据与 upvalue 列表各恰好释放一次。独占所有权
|
/// 独占所有权免去重:死对象已出表不重复枚举。
|
||||||
/// 免去重:死对象已出表不重复枚举,表内无共享 upvalue Box 的原件-克隆对
|
|
||||||
/// (死对象从不被克隆,生产路径不产克隆)。
|
|
||||||
pub(crate) fn teardown_session_heap_data(&mut self) {
|
pub(crate) fn teardown_session_heap_data(&mut self) {
|
||||||
// 迭代器体是堆上 Box:收尾路径(full_reset 与 Drop 共用)逐条释放,
|
// 迭代器体是堆上 Box:收尾路径(full_reset 与 Drop 共用)逐条释放,
|
||||||
// 防 Vm 直接 drop 时表内残留体泄漏。
|
// 防 Vm 直接 drop 时表内残留体泄漏。
|
||||||
|
|||||||
@@ -423,16 +423,6 @@ fn full_reset_dirty_four_families_cross_family_reads() {
|
|||||||
assert!(!vm.session.is_dirty_since_snapshot());
|
assert!(!vm.session.is_dirty_since_snapshot());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn session_epoch_survives_reset() {
|
|
||||||
let mut vm = Vm::new();
|
|
||||||
let session_ptr = vm.gc_state.session_epoch.alloc(123i32) as *mut i32;
|
|
||||||
|
|
||||||
vm.reset();
|
|
||||||
|
|
||||||
assert!(unsafe { *session_ptr } == 123);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 未捕获异常侧通道是执行期状态:原生错误后可能残留原值,reset/full_reset
|
/// 未捕获异常侧通道是执行期状态:原生错误后可能残留原值,reset/full_reset
|
||||||
/// 边界须随执行状态一并清空——否则其持有的 epoch 对象指针在池回收后悬垂
|
/// 边界须随执行状态一并清空——否则其持有的 epoch 对象指针在池回收后悬垂
|
||||||
/// (后续原生错误经 raise_call_error 消费残留值即 UAF)。
|
/// (后续原生错误经 raise_call_error 消费残留值即 UAF)。
|
||||||
@@ -449,24 +439,6 @@ fn reset_drops_stale_uncaught_value() {
|
|||||||
assert!(vm.last_uncaught_value.is_none(), "full_reset 应清空未捕获异常侧通道");
|
assert!(vm.last_uncaught_value.is_none(), "full_reset 应清空未捕获异常侧通道");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 全量重置后 epoch/session 两 arena 均空:容量不跨 reset 保留。对象
|
|
||||||
/// Box 化后 arena 零分配,此不变量是分配包络公式排除 arena 计数器的前提。
|
|
||||||
#[test]
|
|
||||||
fn full_reset_zeroes_arena_retained() {
|
|
||||||
let mut vm = Vm::new();
|
|
||||||
run_source(
|
|
||||||
&mut vm,
|
|
||||||
"var t = 0; for (var i = 0; i < 20000; i++) { var o = { s: 'ab' + i, a: [i] }; t += o.s.length + o.a.length; } t",
|
|
||||||
);
|
|
||||||
// 统一入口 Box 化后 epoch arena 零分配,水位恒零。
|
|
||||||
assert_eq!(vm.epoch.bump().allocated_bytes(), 0);
|
|
||||||
|
|
||||||
vm.full_reset();
|
|
||||||
|
|
||||||
assert_eq!(vm.epoch.bump().allocated_bytes(), 0);
|
|
||||||
assert_eq!(vm.gc_state.session_epoch.allocated_bytes(), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 直 session 分配站(函数对象 + prototype 子对象)计入 session 堆账目:
|
/// 直 session 分配站(函数对象 + prototype 子对象)计入 session 堆账目:
|
||||||
/// 分配点计数 = 对象头(属性区容量扩张属 promote 同口径的既有盲区,不钉)。
|
/// 分配点计数 = 对象头(属性区容量扩张属 promote 同口径的既有盲区,不钉)。
|
||||||
/// 另含 CREATE_CLOSURE 站将推断函数名物化为 session 串(name 数据属性,
|
/// 另含 CREATE_CLOSURE 站将推断函数名物化为 session 串(name 数据属性,
|
||||||
@@ -617,15 +589,6 @@ fn dynamic_function_rethrows_to_string_exception() {
|
|||||||
assert_eq!(result, JsValue::int(7));
|
assert_eq!(result, JsValue::int(7));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn session_epoch_replacement_is_only_in_full_reset_state_clear() {
|
|
||||||
let src = include_str!("../vm_support.rs");
|
|
||||||
let production = src.split("#[cfg(test)]").next().expect("production source");
|
|
||||||
assert_eq!(production.matches("self.gc_state.session_epoch = bumpalo::Bump::new()").count(), 1);
|
|
||||||
assert!(production.contains("fn clear_full_reset_state(&mut self)"));
|
|
||||||
assert!(production.contains("self.gc_state.session_epoch = bumpalo::Bump::new();"));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn full_reset_refreshes_object_prototype_after_object_dirty() {
|
fn full_reset_refreshes_object_prototype_after_object_dirty() {
|
||||||
let mut vm = Vm::new();
|
let mut vm = Vm::new();
|
||||||
|
|||||||
Reference in New Issue
Block a user