mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-25 03:01:12 +08:00
perf: 对象统一入口 Box 化合并对象表退役晋升档
This commit is contained in:
@@ -13,14 +13,6 @@ use super::{native_fn_ptr_to_fn, Vm};
|
||||
use crate::native::NativeFn;
|
||||
use crate::{vm_debug, vm_trace};
|
||||
|
||||
/// 对象分配统一入口的后端:epoch arena(短命对象,晋升进 session)与
|
||||
/// session arena(长命对象,session GC mark/sweep 回收)二选一。
|
||||
#[derive(Clone, Copy)]
|
||||
enum AllocBackend {
|
||||
Epoch,
|
||||
Session,
|
||||
}
|
||||
|
||||
impl Vm {
|
||||
fn pack_sync_native_call_args(
|
||||
&mut self, receiver: JsValue, callee: JsValue, args: &[JsValue],
|
||||
@@ -48,44 +40,33 @@ impl Vm {
|
||||
unsafe { (*obj_ptr).is_session_epoch() }
|
||||
}
|
||||
|
||||
/// 按指定后端分配对象并登记追踪表与堆账目,返回裸指针。
|
||||
/// 对象分配统一入口:置 session 归属位与堆载体位,本体经 `Box::into_raw`
|
||||
/// 堆分配,登记 session 对象表并计入堆账目,返回裸指针。
|
||||
///
|
||||
/// # 步骤
|
||||
/// 1. Epoch 后端:epoch arena 分配并登记 `epoch_object_ptrs`。
|
||||
/// 2. Session 后端:先置 session 归属位再分配,登记 `session_object_ptrs`,
|
||||
/// 计入堆账目(与晋升同式:对象头 + 对象堆数据,读分配后的 arena 对象)。
|
||||
///
|
||||
/// # 注意事项
|
||||
/// Session 后端先置位后分配,置位与登记顺序在两个后端内固定;
|
||||
/// 换后端只改本函数内的分配原语,调用点不动。
|
||||
fn alloc_with_backend(&mut self, mut obj: JsObject, backend: AllocBackend) -> *mut JsObject {
|
||||
match backend {
|
||||
AllocBackend::Epoch => {
|
||||
let ptr = self.epoch.alloc(obj);
|
||||
self.gc_state.track_epoch_object(ptr);
|
||||
ptr
|
||||
}
|
||||
AllocBackend::Session => {
|
||||
obj.set_session_epoch(true);
|
||||
let ptr = self.gc_state.session_epoch.alloc(obj) as *mut JsObject;
|
||||
self.gc_state.session_object_ptrs.push(ptr);
|
||||
// 直 session 分配计入堆账目(与 promote 同式:对象头 + 对象堆数据)。
|
||||
self.gc_state.session_bytes_allocated += std::mem::size_of::<JsObject>()
|
||||
+ crate::session_gc::SessionGc::object_heap_data_bytes(unsafe { &*ptr }) as usize;
|
||||
ptr
|
||||
}
|
||||
}
|
||||
/// 1. 置 session 归属位与堆载体位(释放点据此 `Box::from_raw` 释放本体)。
|
||||
/// 2. 本体堆分配,登记 `session_object_ptrs`。
|
||||
/// 3. 计入堆账目(对象头 + 对象堆数据,读分配后的对象)。
|
||||
fn alloc_object_box(&mut self, mut obj: JsObject) -> *mut JsObject {
|
||||
obj.set_session_epoch(true);
|
||||
obj.set_heap_alloc(true);
|
||||
let ptr = Box::into_raw(Box::new(obj));
|
||||
self.gc_state.session_object_ptrs.push(ptr);
|
||||
// 直 session 分配计入堆账目(与 promote 同式:对象头 + 对象堆数据)。
|
||||
self.gc_state.session_bytes_allocated += std::mem::size_of::<JsObject>()
|
||||
+ crate::session_gc::SessionGc::object_heap_data_bytes(unsafe { &*ptr }) as usize;
|
||||
ptr
|
||||
}
|
||||
|
||||
/// 在当前 epoch arena 分配对象并登记 GC 追踪表,返回裸指针。
|
||||
/// 分配对象并登记 GC 追踪表,返回裸指针。
|
||||
pub(crate) fn alloc_object(&mut self, obj: JsObject) -> *mut JsObject {
|
||||
self.alloc_with_backend(obj, AllocBackend::Epoch)
|
||||
self.alloc_object_box(obj)
|
||||
}
|
||||
|
||||
/// 在当前 session arena 分配对象:置 session 归属位、登记 session 对象表
|
||||
/// 并计入堆账目,返回裸指针。
|
||||
/// 分配对象:置 session 归属位与堆载体位、登记 session 对象表并计入
|
||||
/// 堆账目,返回裸指针。
|
||||
pub(crate) fn alloc_session_object(&mut self, obj: JsObject) -> *mut JsObject {
|
||||
self.alloc_with_backend(obj, AllocBackend::Session)
|
||||
self.alloc_object_box(obj)
|
||||
}
|
||||
|
||||
/// native / 字节码函数的统一同步调用入口,返回结果或错误文本。
|
||||
|
||||
@@ -246,7 +246,7 @@ impl Vm {
|
||||
/// 挂起帧把迭代器搬入状态盒(`vm.iters` 不可见),故须逐状态盒扫描。
|
||||
///
|
||||
/// # 边界与前提
|
||||
/// - 扫描 epoch + session 两份对象表——挂起状态盒宿主对象可能尚未晋升;
|
||||
/// - 扫描 session 对象表——挂起状态盒宿主对象在表内;
|
||||
/// - 挂起帧的 keys 经状态盒边收为 GC 根(被枚举对象不误释放),迭代器
|
||||
/// 体是堆上 Box,故按指针扫 `for_in_iters`;
|
||||
/// - 保守口径:死对象的状态盒同样计入(持挂起 for-in 的 run 放弃执行期
|
||||
@@ -257,7 +257,7 @@ impl Vm {
|
||||
if ptr.is_null() {
|
||||
return false;
|
||||
}
|
||||
// SAFETY: 对象表登记的指针,arena 存活期内有效。
|
||||
// SAFETY: 对象表登记的指针,存活期内有效。
|
||||
let obj = unsafe { &*ptr };
|
||||
match obj.type_tag {
|
||||
JsObject::OBJ_TYPE_GENERATOR => crate::generator::generator_holds_suspended_for_in(obj),
|
||||
@@ -268,7 +268,7 @@ impl Vm {
|
||||
_ => false,
|
||||
}
|
||||
};
|
||||
self.gc_state.epoch_object_ptrs.iter().any(holds) || self.gc_state.session_object_ptrs.iter().any(holds)
|
||||
self.gc_state.session_object_ptrs.iter().any(holds)
|
||||
}
|
||||
|
||||
/// 执行期两档收集的 dispatch 安全点入口:仅在循环顶
|
||||
@@ -357,12 +357,7 @@ impl Vm {
|
||||
/// 扩容等账目盲区的兜底。
|
||||
pub(crate) fn run_alloc_bytes_full(&self) -> u64 {
|
||||
let mut bytes = (self.epoch.bump().allocated_bytes() + self.gc_state.session_epoch.allocated_bytes()) as u64;
|
||||
for &ptr in self
|
||||
.gc_state
|
||||
.epoch_object_ptrs
|
||||
.iter()
|
||||
.chain(self.gc_state.session_object_ptrs.iter())
|
||||
{
|
||||
for &ptr in self.gc_state.session_object_ptrs.iter() {
|
||||
if ptr.is_null() {
|
||||
continue;
|
||||
}
|
||||
@@ -393,9 +388,10 @@ impl Vm {
|
||||
self.gc_state.session_gc = session_gc;
|
||||
}
|
||||
|
||||
/// 当前 epoch 中已分配并跟踪的对象数量(未晋升到 session 的临时对象)。
|
||||
/// 当前 epoch 中已分配并跟踪的对象数量。对象分配统一入口 Box 化后
|
||||
/// 全部对象入 session 表,epoch 表退役,恒返 0(采集点保留,恒零口径)。
|
||||
pub fn epoch_object_count(&self) -> usize {
|
||||
self.gc_state.epoch_object_ptrs.len()
|
||||
0
|
||||
}
|
||||
|
||||
/// inline cache 命中率(0.0~1.0),用于观测 IC 预热效果。
|
||||
|
||||
Reference in New Issue
Block a user