refactor: 提取 Realm 组合类型,session 与 GC 及原型槽归 realm

This commit is contained in:
2026-10-07 00:10:27 +00:00
parent add910a504
commit 14ef287a75
31 changed files with 598 additions and 567 deletions
+4 -4
View File
@@ -47,9 +47,9 @@ impl Vm {
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);
self.realm.gc.session_object_ptrs.push(ptr);
// 直 session 分配计入堆账目(与 promote 同式:对象头 + 对象堆数据)。
self.gc_state.session_bytes_allocated += std::mem::size_of::<JsObject>()
self.realm.gc.session_bytes_allocated += std::mem::size_of::<JsObject>()
+ crate::session_gc::SessionGc::object_heap_data_bytes(unsafe { &*ptr }) as usize;
ptr
}
@@ -296,7 +296,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.session.global_object().as_ptr() as *mut JsObject)
JsValue::from_js_object(self.realm.session.global_object().as_ptr() as *mut JsObject)
} else if sub_is_strict {
this_value
} else {
@@ -402,7 +402,7 @@ mod tests {
}
fn native_function(vm: &mut Vm, f: crate::native::NativeFn) -> JsValue {
let proto = vm.session.builtin_world().function_proto.as_ptr() as *mut JsObject;
let proto = vm.realm.session.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 存储。
+9 -9
View File
@@ -128,29 +128,29 @@ impl Vm {
// 宿主 `$262.gc()` 置位的强制收集与压力模式收集在此边界消费:
// 完整收集唯一安全点(无在途 dispatch 局部值),与正常触发路径
// 同一入口。压力模式开启后每个顶层边界做一次完整收集。
if self.gc_state.pending_forced_collect || self.gc_state.gc_pressure_mode {
self.gc_state.pending_forced_collect = false;
if self.realm.gc.pending_forced_collect || self.realm.gc.gc_pressure_mode {
self.realm.gc.pending_forced_collect = false;
self.collect_session_gc();
}
// 峰值高水位:同一边界采样 session 堆账目上界
let bytes = self.gc_state.session_bytes_allocated;
if bytes > self.gc_state.session_bytes_peak {
self.gc_state.session_bytes_peak = bytes;
let bytes = self.realm.gc.session_bytes_allocated;
if bytes > self.realm.gc.session_bytes_peak {
self.realm.gc.session_bytes_peak = bytes;
}
// 单 run 分配包络高水位:O(1) 读(手工账目 + BigInt/cell 表长)。
let alloc = self.run_alloc_bytes();
if alloc > self.gc_state.run_alloc_peak {
self.gc_state.run_alloc_peak = alloc;
if alloc > self.realm.gc.run_alloc_peak {
self.realm.gc.run_alloc_peak = alloc;
}
// 压力模式开启时跳过两档水位收集:完整收集已涵盖其全部工作,
// 同边界双触发只会多一轮空转 mark。
if bytes >= self.gc_state.string_gc_watermark && !self.gc_state.gc_pressure_mode {
if bytes >= self.realm.gc.string_gc_watermark && !self.realm.gc.gc_pressure_mode {
self.maybe_collect_session_strings();
}
// 执行期原地 sweep 收集:O(1) 包络超触发水位 → 收集(无门控:
// 迭代器键引用经根收集标活,原地释放不搬移存活对象;
// 边界契约见 maybe_collect_in_run)。
if alloc >= self.gc_state.gc_watermark && !self.gc_state.gc_pressure_mode {
if alloc >= self.realm.gc.gc_watermark && !self.realm.gc.gc_pressure_mode {
self.maybe_collect_in_run();
}
}
+21 -21
View File
@@ -150,7 +150,7 @@ impl Vm {
}
}
}
f(RootGroup::Global, JsValue::from_js_object(self.session.global_object().as_ptr() as *mut JsObject));
f(RootGroup::Global, JsValue::from_js_object(self.realm.session.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.gc_state.session_gc);
let mut session_gc = std::mem::take(&mut self.realm.gc.session_gc);
session_gc.maybe_collect(self);
self.gc_state.session_gc = session_gc;
self.realm.gc.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.gc_state.session_gc);
let mut session_gc = std::mem::take(&mut self.realm.gc.session_gc);
session_gc.maybe_collect_strings_only(self);
self.gc_state.session_gc = session_gc;
self.realm.gc.session_gc = session_gc;
}
/// 执行期原地 sweep 收集的 dispatch 安全点入口:仅在循环顶
@@ -187,35 +187,35 @@ impl Vm {
/// - 无对象可回收时仍跑一轮(mark + 原地清扫),水位同点抬高,
/// 触发间距由包络增量控制。
pub(crate) fn maybe_collect_in_run(&mut self) {
let mut session_gc = std::mem::take(&mut self.gc_state.session_gc);
let mut session_gc = std::mem::take(&mut self.realm.gc.session_gc);
session_gc.collect_in_run(self);
self.gc_state.session_gc = session_gc;
self.realm.gc.session_gc = session_gc;
}
/// 只读访问 session GC 的统计(回收次数、存活/死亡对象数、释放字节等)。
pub fn session_gc_stats(&self) -> &SessionGc {
&self.gc_state.session_gc
&self.realm.gc.session_gc
}
/// 当前 session arena 中存活(已晋升)的对象数量。
pub fn session_object_count(&self) -> usize {
self.gc_state.session_object_ptrs.len()
self.realm.gc.session_object_ptrs.len()
}
/// session 当前分配的字节数(对象 + 存活字符串)。
pub fn session_bytes_allocated(&self) -> usize {
self.gc_state.session_bytes_allocated
self.realm.gc.session_bytes_allocated
}
/// 执行期 session 堆账目的峰值高水位(顶层指令边界采样,全量重置清零)。
pub fn session_bytes_peak(&self) -> usize {
self.gc_state.session_bytes_peak
self.realm.gc.session_bytes_peak
}
/// 本 run 累计分配字节的高水位:`run_alloc_bytes` 的顶层指令边界
/// 采样上界,run 边界(reset/full_reset)重起算。留存内存观测锚。
pub fn run_alloc_peak(&self) -> usize {
self.gc_state.run_alloc_peak
self.realm.gc.run_alloc_peak
}
/// 本 run 累计分配字节:session 手工堆账目(session 对象及其属性向量 +
@@ -228,9 +228,9 @@ impl Vm {
/// 属性区(元素/属性向量扩容)增长对其不可见——上限判定须配合
/// [`Self::run_alloc_bytes_full`] 的深采样层。
pub(crate) fn run_alloc_bytes(&self) -> usize {
self.gc_state.session_bytes_allocated
+ self.gc_state.session_bigint_ptrs.borrow().len() * std::mem::size_of::<num_bigint::BigInt>()
+ self.gc_state.session_cell_ptrs.borrow().len() * std::mem::size_of::<Cell>()
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>()
}
/// 本 run 累计分配字节(O(1) 读)。
@@ -248,7 +248,7 @@ impl Vm {
/// 与 [`Self::run_alloc_bytes`] 的轻层公式逐位相等。
pub(crate) fn run_alloc_bytes_full(&self) -> u64 {
let mut bytes = 0u64;
for &ptr in self.gc_state.session_object_ptrs.iter() {
for &ptr in self.realm.gc.session_object_ptrs.iter() {
if ptr.is_null() {
continue;
}
@@ -256,15 +256,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.gc_state.session_string_ptrs {
for &ptr in &self.realm.gc.session_string_ptrs {
if ptr.is_null() {
continue;
}
// SAFETY: ptr 在字符串表登记,收尾前有效。
bytes += (std::mem::size_of::<JsString>() + unsafe { (*ptr).payload_bytes() }) as u64;
}
bytes += (self.gc_state.session_bigint_ptrs.borrow().len() * std::mem::size_of::<num_bigint::BigInt>()) as u64;
bytes += (self.gc_state.session_cell_ptrs.borrow().len() * std::mem::size_of::<Cell>()) 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
}
@@ -278,9 +278,9 @@ impl Vm {
/// - 须在执行外的安全点调用(无在途 builtin 局部裸指针、dispatch 未重入);
/// 执行期触发仍走水位路径,本入口供事后观测(如基准测 workload 后留存堆)。
pub fn collect_session_gc(&mut self) {
let mut session_gc = std::mem::take(&mut self.gc_state.session_gc);
let mut session_gc = std::mem::take(&mut self.realm.gc.session_gc);
session_gc.collect(self);
self.gc_state.session_gc = session_gc;
self.realm.gc.session_gc = session_gc;
}
/// 当前 epoch 中已分配并跟踪的对象数量。对象分配统一入口 Box 化后
+7 -27
View File
@@ -17,11 +17,11 @@ use smallvec::SmallVec;
/// 初始化一个 session 的内置对象(global 槽位、各构造器与原型、IC 预热)。
pub use crate::bindings::init_kernel_builtins;
use crate::native::NativeFn;
use crate::realm::Realm;
use crate::vm_debug;
use crate::vm_state::{GcState, IterState, ProfilingState, SampleState, SymbolState};
use crate::vm_state::{IterState, ProfilingState, SampleState, SymbolState};
use oxide_kernel::kernel::{KernelCore, KernelSession};
use oxide_types::error::JsErrorKind;
use oxide_types::mem::P;
use oxide_types::object::{Cell, JsObject, JsString, NativeFnPtr};
use oxide_types::private_key::INT_KEY_COUNT;
use oxide_types::value::JsValue;
@@ -175,7 +175,9 @@ pub struct Vm {
pub(crate) active_immutables: *const [JsValue],
pub(crate) frames: SmallVec<[CallFrame; 16]>,
pub(crate) kernel_core: Arc<KernelCore>,
pub(crate) session: KernelSession,
/// 每 VM 的 realm 组合:内核会话(builtin world 与 global 对象)、
/// session GC 簿记与 10 个内建原型槽(见 `realm` 模块)。
pub(crate) realm: Realm,
/// `"length"` 属性键的 intern id 缓存:进程内稳定(PermInterner append-only、
/// KernelCore 不重建),属性 get/set 热路径免每次 intern(hash64 + DashMap +
/// RwLock 读锁)。
@@ -190,26 +192,6 @@ pub struct Vm {
/// f64→string 十六槽 last-value 缓存的值(session 串,经 `for_each_value`
/// 登记为 GC 根;`full_reset` 在 session 串释放前清空)。
pub(crate) number_to_string_cache_vals: [JsValue; 16],
pub object_prototype: P<JsObject>,
/// `%GeneratorPrototype%`:生成器实例的原型(next/return/throw 方法挂此)。
pub generator_proto: P<JsObject>,
/// `%GeneratorFunction.prototype%`:生成器函数对象的原型(`constructor` 指向
/// `%GeneratorFunction%`,使 `g.constructor.name` 解析为 "GeneratorFunction")。
pub generator_function_proto: P<JsObject>,
/// `%Promise%` 构造器(resolve/reject 静态方法挂此,global 的 Promise 槽指向它)。
pub promise_constructor: P<JsObject>,
/// `%Promise.prototype%`:Promise 实例的原型(then/catch/finally 方法挂此)。
pub promise_proto: P<JsObject>,
/// `%AggregateError%` 构造器(Promise.any 拒绝时构造 AggregateError 用)。
pub aggregate_error_constructor: P<JsObject>,
/// `%AggregateError.prototype%`(proto = %Error.prototype%)。
pub aggregate_error_proto: P<JsObject>,
/// `%AsyncFunction.prototype%`:异步函数对象的原型(`constructor` 指向 `%AsyncFunction%`)。
pub async_function_proto: P<JsObject>,
/// `%AsyncGeneratorPrototype%`:异步生成器实例的原型(next/return/throw/@@asyncIterator)。
pub async_generator_proto: P<JsObject>,
/// `%AsyncGeneratorFunction.prototype%`:异步生成器函数对象的原型。
pub async_generator_function_proto: P<JsObject>,
/// 微任务队列(Promise reactions / thenable 委托),`run()` 末尾 FIFO drain。
pub(crate) job_queue: VecDeque<crate::promise::Microtask>,
/// Atomics.waitAsync waiter 表:键 = (缓冲对象指针, 元素字节偏移),值 =
@@ -357,8 +339,6 @@ pub struct Vm {
/// 异步生成器 body `dispatch()` 的 AWAIT 让出信号:置 true 表示挂起在 await,
/// 恢复方(异步生成器内嵌 dispatch 循环)据此快照挂起状态。
pub(crate) async_gen_suspended: bool,
/// 分组保存 session arena / GC 簿记状态。
pub(crate) gc_state: GcState,
/// 分组保存 `Symbol` intern 状态。
pub(crate) symbols: SymbolState,
/// 分组保存活跃的 for-in / for-of 迭代器状态。
@@ -440,12 +420,12 @@ impl Vm {
/// 只读访问当前 session(builtin world 与 global object)。
pub fn session(&self) -> &KernelSession {
&self.session
&self.realm.session
}
/// 判定裸指针是否指向当前 session 的 `%Object.prototype%`。
pub(crate) fn is_object_prototype(&self, ptr: *const JsObject) -> bool {
let proto_ptr = self.session.builtin_world().object_proto.as_ptr();
let proto_ptr = self.realm.session.builtin_world().object_proto.as_ptr();
std::ptr::eq(ptr, proto_ptr)
}
+4 -4
View File
@@ -46,7 +46,7 @@ impl oxide_runtime_api::VmHost for Vm {
self.kernel_core()
}
fn session(&self) -> &KernelSession {
self.session()
&self.realm.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.generator_function_proto.as_ptr())
|| std::ptr::eq(p, self.async_function_proto.as_ptr())
|| std::ptr::eq(p, self.async_generator_function_proto.as_ptr())
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())
}
fn step_rng(&mut self) {
self.step_rng()