mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-25 03:01:12 +08:00
refactor: realm 与 Vm 生命周期解耦,Vm 持 Arc<Realm>
This commit is contained in:
@@ -47,10 +47,13 @@ impl Vm {
|
||||
obj.set_session_epoch(true);
|
||||
obj.set_heap_alloc(true);
|
||||
let ptr = Box::into_raw(Box::new(obj));
|
||||
self.realm.gc.session_object_ptrs.push(ptr);
|
||||
// 直 session 分配计入堆账目(与 promote 同式:对象头 + 对象堆数据)。
|
||||
self.realm.gc.session_bytes_allocated += std::mem::size_of::<JsObject>()
|
||||
// 直 session 分配计入堆账目(与 promote 同式:对象头 + 对象堆数据):
|
||||
// 表登记与账目更新合并进同一次借用。
|
||||
let bytes = std::mem::size_of::<JsObject>()
|
||||
+ crate::session_gc::SessionGc::object_heap_data_bytes(unsafe { &*ptr }) as usize;
|
||||
let gc = &mut self.realm.gc.borrow_mut();
|
||||
gc.session_object_ptrs.push(ptr);
|
||||
gc.session_bytes_allocated += bytes;
|
||||
ptr
|
||||
}
|
||||
|
||||
@@ -296,7 +299,7 @@ impl Vm {
|
||||
self.regs[254] = if sub_is_arrow {
|
||||
obj.captured_this()
|
||||
} else if !sub_is_strict && this_value.is_nullish() {
|
||||
JsValue::from_js_object(self.realm.session.global_object().as_ptr() as *mut JsObject)
|
||||
JsValue::from_js_object(self.realm.session.borrow().global_object().as_ptr() as *mut JsObject)
|
||||
} else if sub_is_strict {
|
||||
this_value
|
||||
} else {
|
||||
@@ -402,7 +405,7 @@ mod tests {
|
||||
}
|
||||
|
||||
fn native_function(vm: &mut Vm, f: crate::native::NativeFn) -> JsValue {
|
||||
let proto = vm.realm.session.builtin_world().function_proto.as_ptr() as *mut JsObject;
|
||||
let proto = vm.realm.session.borrow().builtin_world().function_proto.as_ptr() as *mut JsObject;
|
||||
let mut obj = JsObject::new_empty(oxide_kernel::shape_forge::EMPTY_SHAPE_ID, JsValue::from_js_object(proto));
|
||||
obj.set_function(true);
|
||||
// SAFETY: f 是 NativeFn 函数项,可作为 NativeFnPtr 存储。
|
||||
|
||||
@@ -128,29 +128,31 @@ impl Vm {
|
||||
// 宿主 `$262.gc()` 置位的强制收集与压力模式收集在此边界消费:
|
||||
// 完整收集唯一安全点(无在途 dispatch 局部值),与正常触发路径
|
||||
// 同一入口。压力模式开启后每个顶层边界做一次完整收集。
|
||||
if self.realm.gc.pending_forced_collect || self.realm.gc.gc_pressure_mode {
|
||||
self.realm.gc.pending_forced_collect = false;
|
||||
// 各字段读入局部变量(临时借用)后释放借用再调收集,
|
||||
// 不跨 collect 调用持借。
|
||||
if self.realm.gc.borrow().pending_forced_collect || self.realm.gc.borrow().gc_pressure_mode {
|
||||
self.realm.gc.borrow_mut().pending_forced_collect = false;
|
||||
self.collect_session_gc();
|
||||
}
|
||||
// 峰值高水位:同一边界采样 session 堆账目上界
|
||||
let bytes = self.realm.gc.session_bytes_allocated;
|
||||
if bytes > self.realm.gc.session_bytes_peak {
|
||||
self.realm.gc.session_bytes_peak = bytes;
|
||||
let bytes = self.realm.gc.borrow().session_bytes_allocated;
|
||||
if bytes > self.realm.gc.borrow().session_bytes_peak {
|
||||
self.realm.gc.borrow_mut().session_bytes_peak = bytes;
|
||||
}
|
||||
// 单 run 分配包络高水位:O(1) 读(手工账目 + BigInt/cell 表长)。
|
||||
let alloc = self.run_alloc_bytes();
|
||||
if alloc > self.realm.gc.run_alloc_peak {
|
||||
self.realm.gc.run_alloc_peak = alloc;
|
||||
if alloc > self.realm.gc.borrow().run_alloc_peak {
|
||||
self.realm.gc.borrow_mut().run_alloc_peak = alloc;
|
||||
}
|
||||
// 压力模式开启时跳过两档水位收集:完整收集已涵盖其全部工作,
|
||||
// 同边界双触发只会多一轮空转 mark。
|
||||
if bytes >= self.realm.gc.string_gc_watermark && !self.realm.gc.gc_pressure_mode {
|
||||
if bytes >= self.realm.gc.borrow().string_gc_watermark && !self.realm.gc.borrow().gc_pressure_mode {
|
||||
self.maybe_collect_session_strings();
|
||||
}
|
||||
// 执行期原地 sweep 收集:O(1) 包络超触发水位 → 收集(无门控:
|
||||
// 迭代器键引用经根收集标活,原地释放不搬移存活对象;
|
||||
// 边界契约见 maybe_collect_in_run)。
|
||||
if alloc >= self.realm.gc.gc_watermark && !self.realm.gc.gc_pressure_mode {
|
||||
if alloc >= self.realm.gc.borrow().gc_watermark && !self.realm.gc.borrow().gc_pressure_mode {
|
||||
self.maybe_collect_in_run();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,7 +150,7 @@ impl Vm {
|
||||
}
|
||||
}
|
||||
}
|
||||
f(RootGroup::Global, JsValue::from_js_object(self.realm.session.global_object().as_ptr() as *mut JsObject));
|
||||
f(RootGroup::Global, JsValue::from_js_object(self.realm.session.borrow().global_object().as_ptr() as *mut JsObject));
|
||||
}
|
||||
|
||||
/// GC 根统一枚举入口:遍历的字段清单与 `for_each_value` 相同。
|
||||
@@ -163,17 +163,17 @@ impl Vm {
|
||||
/// `session_gc` 经 `mem::take` 借出后再放回:收集需要 `&mut Vm`,而
|
||||
/// `SessionGc` 是 `Vm` 的内部字段,借出以避开借用冲突。
|
||||
pub(crate) fn maybe_collect_session_gc(&mut self) {
|
||||
let mut session_gc = std::mem::take(&mut self.realm.gc.session_gc);
|
||||
let mut session_gc = std::mem::take(&mut self.realm.gc.borrow_mut().session_gc);
|
||||
session_gc.maybe_collect(self);
|
||||
self.realm.gc.session_gc = session_gc;
|
||||
self.realm.gc.borrow_mut().session_gc = session_gc;
|
||||
}
|
||||
|
||||
/// 执行期字符串阈值回收:仅回收 session 字符串(跳过对象搬移)。热路径只在
|
||||
/// 超阈值后进入,`mem::take` 不承担每次分配的开销。
|
||||
pub(crate) fn maybe_collect_session_strings(&mut self) {
|
||||
let mut session_gc = std::mem::take(&mut self.realm.gc.session_gc);
|
||||
let mut session_gc = std::mem::take(&mut self.realm.gc.borrow_mut().session_gc);
|
||||
session_gc.maybe_collect_strings_only(self);
|
||||
self.realm.gc.session_gc = session_gc;
|
||||
self.realm.gc.borrow_mut().session_gc = session_gc;
|
||||
}
|
||||
|
||||
/// 执行期原地 sweep 收集的 dispatch 安全点入口:仅在循环顶
|
||||
@@ -187,35 +187,38 @@ impl Vm {
|
||||
/// - 无对象可回收时仍跑一轮(mark + 原地清扫),水位同点抬高,
|
||||
/// 触发间距由包络增量控制。
|
||||
pub(crate) fn maybe_collect_in_run(&mut self) {
|
||||
let mut session_gc = std::mem::take(&mut self.realm.gc.session_gc);
|
||||
let mut session_gc = std::mem::take(&mut self.realm.gc.borrow_mut().session_gc);
|
||||
session_gc.collect_in_run(self);
|
||||
self.realm.gc.session_gc = session_gc;
|
||||
self.realm.gc.borrow_mut().session_gc = session_gc;
|
||||
}
|
||||
|
||||
/// 只读访问 session GC 的统计(回收次数、存活/死亡对象数、释放字节等)。
|
||||
pub fn session_gc_stats(&self) -> &SessionGc {
|
||||
&self.realm.gc.session_gc
|
||||
///
|
||||
/// 返回 `Ref` 守卫(`session_gc` 入 `RefCell` 后无法再给稳定 `&`):
|
||||
/// 调用方在单表达式内消费,不跨 `borrow_mut` 长存。
|
||||
pub fn session_gc_stats(&self) -> std::cell::Ref<'_, SessionGc> {
|
||||
std::cell::Ref::map(self.realm.gc.borrow(), |gc| &gc.session_gc)
|
||||
}
|
||||
|
||||
/// 当前 session arena 中存活(已晋升)的对象数量。
|
||||
pub fn session_object_count(&self) -> usize {
|
||||
self.realm.gc.session_object_ptrs.len()
|
||||
self.realm.gc.borrow().session_object_ptrs.len()
|
||||
}
|
||||
|
||||
/// session 当前分配的字节数(对象 + 存活字符串)。
|
||||
pub fn session_bytes_allocated(&self) -> usize {
|
||||
self.realm.gc.session_bytes_allocated
|
||||
self.realm.gc.borrow().session_bytes_allocated
|
||||
}
|
||||
|
||||
/// 执行期 session 堆账目的峰值高水位(顶层指令边界采样,全量重置清零)。
|
||||
pub fn session_bytes_peak(&self) -> usize {
|
||||
self.realm.gc.session_bytes_peak
|
||||
self.realm.gc.borrow().session_bytes_peak
|
||||
}
|
||||
|
||||
/// 本 run 累计分配字节的高水位:`run_alloc_bytes` 的顶层指令边界
|
||||
/// 采样上界,run 边界(reset/full_reset)重起算。留存内存观测锚。
|
||||
pub fn run_alloc_peak(&self) -> usize {
|
||||
self.realm.gc.run_alloc_peak
|
||||
self.realm.gc.borrow().run_alloc_peak
|
||||
}
|
||||
|
||||
/// 本 run 累计分配字节:session 手工堆账目(session 对象及其属性向量 +
|
||||
@@ -228,9 +231,9 @@ impl Vm {
|
||||
/// 属性区(元素/属性向量扩容)增长对其不可见——上限判定须配合
|
||||
/// [`Self::run_alloc_bytes_full`] 的深采样层。
|
||||
pub(crate) fn run_alloc_bytes(&self) -> usize {
|
||||
self.realm.gc.session_bytes_allocated
|
||||
+ self.realm.gc.session_bigint_ptrs.borrow().len() * std::mem::size_of::<num_bigint::BigInt>()
|
||||
+ self.realm.gc.session_cell_ptrs.borrow().len() * std::mem::size_of::<Cell>()
|
||||
self.realm.gc.borrow().session_bytes_allocated
|
||||
+ self.realm.gc.borrow().session_bigint_ptrs.borrow().len() * std::mem::size_of::<num_bigint::BigInt>()
|
||||
+ self.realm.gc.borrow().session_cell_ptrs.borrow().len() * std::mem::size_of::<Cell>()
|
||||
}
|
||||
|
||||
/// 本 run 累计分配字节(O(1) 读)。
|
||||
@@ -248,7 +251,7 @@ impl Vm {
|
||||
/// 与 [`Self::run_alloc_bytes`] 的轻层公式逐位相等。
|
||||
pub(crate) fn run_alloc_bytes_full(&self) -> u64 {
|
||||
let mut bytes = 0u64;
|
||||
for &ptr in self.realm.gc.session_object_ptrs.iter() {
|
||||
for &ptr in self.realm.gc.borrow().session_object_ptrs.iter() {
|
||||
if ptr.is_null() {
|
||||
continue;
|
||||
}
|
||||
@@ -256,15 +259,15 @@ impl Vm {
|
||||
let obj = unsafe { &*ptr };
|
||||
bytes += std::mem::size_of::<JsObject>() as u64 + SessionGc::object_heap_data_bytes(obj);
|
||||
}
|
||||
for &ptr in &self.realm.gc.session_string_ptrs {
|
||||
for &ptr in &self.realm.gc.borrow().session_string_ptrs {
|
||||
if ptr.is_null() {
|
||||
continue;
|
||||
}
|
||||
// SAFETY: ptr 在字符串表登记,收尾前有效。
|
||||
bytes += (std::mem::size_of::<JsString>() + unsafe { (*ptr).payload_bytes() }) as u64;
|
||||
}
|
||||
bytes += (self.realm.gc.session_bigint_ptrs.borrow().len() * std::mem::size_of::<num_bigint::BigInt>()) as u64;
|
||||
bytes += (self.realm.gc.session_cell_ptrs.borrow().len() * std::mem::size_of::<Cell>()) as u64;
|
||||
bytes += (self.realm.gc.borrow().session_bigint_ptrs.borrow().len() * std::mem::size_of::<num_bigint::BigInt>()) as u64;
|
||||
bytes += (self.realm.gc.borrow().session_cell_ptrs.borrow().len() * std::mem::size_of::<Cell>()) as u64;
|
||||
bytes
|
||||
}
|
||||
|
||||
@@ -278,9 +281,9 @@ impl Vm {
|
||||
/// - 须在执行外的安全点调用(无在途 builtin 局部裸指针、dispatch 未重入);
|
||||
/// 执行期触发仍走水位路径,本入口供事后观测(如基准测 workload 后留存堆)。
|
||||
pub fn collect_session_gc(&mut self) {
|
||||
let mut session_gc = std::mem::take(&mut self.realm.gc.session_gc);
|
||||
let mut session_gc = std::mem::take(&mut self.realm.gc.borrow_mut().session_gc);
|
||||
session_gc.collect(self);
|
||||
self.realm.gc.session_gc = session_gc;
|
||||
self.realm.gc.borrow_mut().session_gc = session_gc;
|
||||
}
|
||||
|
||||
/// 当前 epoch 中已分配并跟踪的对象数量。对象分配统一入口 Box 化后
|
||||
|
||||
@@ -176,8 +176,10 @@ pub struct Vm {
|
||||
pub(crate) frames: SmallVec<[CallFrame; 16]>,
|
||||
pub(crate) kernel_core: Arc<KernelCore>,
|
||||
/// 每 VM 的 realm 组合:内核会话(builtin world 与 global 对象)、
|
||||
/// session GC 簿记与 10 个内建原型槽(见 `realm` 模块)。
|
||||
pub(crate) realm: Realm,
|
||||
/// session GC 簿记与 10 个内建原型槽(见 `realm` 模块)。以 `Arc` 持有:
|
||||
/// 可变组经 `RefCell` 内部可变性在 `&Arc<Realm>` 下改写,teardown 归
|
||||
/// `Drop for Realm`(per-realm 消亡:Arc 计数归零时收尾)。
|
||||
pub(crate) realm: Arc<Realm>,
|
||||
/// `"length"` 属性键的 intern id 缓存:进程内稳定(PermInterner append-only、
|
||||
/// KernelCore 不重建),属性 get/set 热路径免每次 intern(hash64 + DashMap +
|
||||
/// RwLock 读锁)。
|
||||
@@ -382,10 +384,11 @@ impl Drop for Vm {
|
||||
fn drop(&mut self) {
|
||||
// 边界守卫计数:与构造器登记恰好配对(Rust 所有权保证恰好一次)。
|
||||
self.kernel_core.note_vm_ended();
|
||||
// 直接 drop(test262 每测试新建即弃)不经 reset/full_reset 路径:
|
||||
// 统一收尾释放全部 session 堆数据与内建原型属性区,防逐测试累积泄漏。
|
||||
self.teardown_intrinsic_protos();
|
||||
self.teardown_session_heap_data();
|
||||
// 活跃 for-in / for-of 迭代器是 per-VM 执行态:收尾路径逐条释放,
|
||||
// 防 Vm 直接 drop 时表内残留体泄漏。
|
||||
self.iters.reset();
|
||||
// realm 收尾归 `Drop for Realm`(per-realm 消亡:Arc 计数归零时触发,
|
||||
// 直接 drop 时恰好一次)。
|
||||
}
|
||||
}
|
||||
|
||||
@@ -419,13 +422,16 @@ impl Vm {
|
||||
}
|
||||
|
||||
/// 只读访问当前 session(builtin world 与 global object)。
|
||||
pub fn session(&self) -> &KernelSession {
|
||||
&self.realm.session
|
||||
///
|
||||
/// 返回 `Ref` 守卫(session 入 `RefCell` 后无法再给稳定 `&`):调用方
|
||||
/// 在单表达式内消费,不跨 `borrow_mut` 长存。
|
||||
pub fn session(&self) -> std::cell::Ref<'_, KernelSession> {
|
||||
self.realm.session.borrow()
|
||||
}
|
||||
|
||||
/// 判定裸指针是否指向当前 session 的 `%Object.prototype%`。
|
||||
pub(crate) fn is_object_prototype(&self, ptr: *const JsObject) -> bool {
|
||||
let proto_ptr = self.realm.session.builtin_world().object_proto.as_ptr();
|
||||
let proto_ptr = self.realm.session.borrow().builtin_world().object_proto.as_ptr();
|
||||
std::ptr::eq(ptr, proto_ptr)
|
||||
}
|
||||
|
||||
|
||||
@@ -45,8 +45,8 @@ impl oxide_runtime_api::VmHost for Vm {
|
||||
fn kernel_core(&self) -> &Arc<KernelCore> {
|
||||
self.kernel_core()
|
||||
}
|
||||
fn session(&self) -> &KernelSession {
|
||||
&self.realm.session
|
||||
fn session(&self) -> std::cell::Ref<'_, KernelSession> {
|
||||
self.session()
|
||||
}
|
||||
fn pc(&self) -> usize {
|
||||
self.pc
|
||||
@@ -189,9 +189,9 @@ impl oxide_runtime_api::VmHost for Vm {
|
||||
return false;
|
||||
}
|
||||
let p = proto.as_js_object_ptr() as *const JsObject;
|
||||
std::ptr::eq(p, self.realm.generator_function_proto.as_ptr())
|
||||
|| std::ptr::eq(p, self.realm.async_function_proto.as_ptr())
|
||||
|| std::ptr::eq(p, self.realm.async_generator_function_proto.as_ptr())
|
||||
std::ptr::eq(p, self.realm.generator_function_proto.borrow().as_ptr())
|
||||
|| std::ptr::eq(p, self.realm.async_function_proto.borrow().as_ptr())
|
||||
|| std::ptr::eq(p, self.realm.async_generator_function_proto.borrow().as_ptr())
|
||||
}
|
||||
fn step_rng(&mut self) {
|
||||
self.step_rng()
|
||||
|
||||
Reference in New Issue
Block a user