mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-23 18:21:13 +08:00
refactor: 退役根重写镜像与对象克隆重写族,保留原地 sweep 弱键定夺
This commit is contained in:
@@ -224,8 +224,6 @@ impl JsObject {
|
||||
pub const SESSION_EPOCH_BIT: u8 = 0x01;
|
||||
/// `is_session_epoch` 字段中的 GC 标记位。
|
||||
pub const GC_MARK_BIT: u8 = 0x02;
|
||||
/// `is_session_epoch` 字段中的 epoch 归属标记位。
|
||||
pub const EPOCH_BIT: u8 = 0x04;
|
||||
/// `is_session_epoch` 字段中的堆载体标记位:对象本体经 `Box::into_raw`
|
||||
/// 分配(统一分配入口),释放点据此 `Box::from_raw` 释放本体;arena
|
||||
/// 载体(移动式 sweep 克隆、晋升族克隆)无此位,本体随 arena 归还。
|
||||
@@ -489,22 +487,6 @@ impl JsObject {
|
||||
}
|
||||
}
|
||||
|
||||
/// 是否为 epoch 分配(非 session)的对象。
|
||||
#[inline]
|
||||
pub fn is_epoch(&self) -> bool {
|
||||
self.is_session_epoch & Self::EPOCH_BIT != 0
|
||||
}
|
||||
|
||||
/// 设置 / 清除 epoch 归属标记。
|
||||
#[inline]
|
||||
pub fn set_is_epoch(&mut self, value: bool) {
|
||||
if value {
|
||||
self.is_session_epoch |= Self::EPOCH_BIT;
|
||||
} else {
|
||||
self.is_session_epoch &= !Self::EPOCH_BIT;
|
||||
}
|
||||
}
|
||||
|
||||
/// 是否堆载体(本体经 `Box::into_raw` 分配,释放点须 `Box::from_raw`)。
|
||||
#[inline]
|
||||
pub fn is_heap_alloc(&self) -> bool {
|
||||
@@ -521,56 +503,6 @@ impl JsObject {
|
||||
}
|
||||
}
|
||||
|
||||
/// 深拷贝本对象到 session epoch:复制属性向量与元数据,标记为新 session 对象。
|
||||
///
|
||||
/// 用于把持久对象快照进当前调用上下文,修改不反向传播到源对象。
|
||||
/// `upvalues` 指针别名共享(非深拷):调用帧固化的 upvalue 表跨 GC 晋升
|
||||
/// 恒有效依赖此不变量。
|
||||
pub fn clone_for_session_epoch(&self) -> Self {
|
||||
let hash_props = self
|
||||
.hash_props_vec()
|
||||
.map(|props| Box::into_raw(Box::new(props.clone())) as *mut u8)
|
||||
.unwrap_or(std::ptr::null_mut());
|
||||
let prop_meta = self
|
||||
.prop_meta_vec()
|
||||
.map(|meta| Box::into_raw(Box::new(meta.clone())) as *mut u8)
|
||||
.unwrap_or(std::ptr::null_mut());
|
||||
let array_elements = self
|
||||
.array_elements_vec()
|
||||
.map(|elems| Box::into_raw(Box::new(elems.clone())) as *mut u8)
|
||||
.unwrap_or(std::ptr::null_mut());
|
||||
let array_elements_meta = self
|
||||
.array_elements_meta_vec()
|
||||
.map(|meta| Box::into_raw(Box::new(meta.clone())) as *mut u8)
|
||||
.unwrap_or(std::ptr::null_mut());
|
||||
|
||||
Self {
|
||||
header: self.header,
|
||||
native_arg_count: self.native_arg_count,
|
||||
type_tag: self.type_tag,
|
||||
is_session_epoch: Self::SESSION_EPOCH_BIT,
|
||||
_pad: self._pad,
|
||||
array_elements,
|
||||
array_elements_meta,
|
||||
hash_props,
|
||||
prop_meta,
|
||||
native_data: self.native_data,
|
||||
proto: self.proto,
|
||||
generation: self.generation,
|
||||
array_prop_count: self.array_prop_count,
|
||||
array_len_override: self.array_len_override,
|
||||
native_fn: self.native_fn,
|
||||
sub_module_index: self.sub_module_index,
|
||||
table_gen: self.table_gen,
|
||||
captured_this: self.captured_this,
|
||||
home_object: self.home_object,
|
||||
boxed_value: self.boxed_value,
|
||||
regexp_source: self.regexp_source,
|
||||
regexp_flags: self.regexp_flags,
|
||||
upvalues: self.upvalues,
|
||||
}
|
||||
}
|
||||
|
||||
/// 命名属性区底层指针(未分配时为空指针)。
|
||||
pub fn hash_props_raw(&self) -> *mut u8 {
|
||||
self.hash_props
|
||||
@@ -596,7 +528,7 @@ impl JsObject {
|
||||
///
|
||||
/// 供 session 收尾调用:对象本体可能仍被 Arc 引用(此后属性区不再被读取),
|
||||
/// 每区至多释放一次、重复调用为 no-op。upvalue 列表不在本函数释放范围内
|
||||
/// (原件与晋升克隆间别名,须收尾时去重统一释放)。
|
||||
/// (与调用帧压帧时固化的 upvalue 表共享同一 Box,单所有权,随帧收尾释放)。
|
||||
pub fn release_raw_heap(&mut self) {
|
||||
// SAFETY: 四个区指针归本对象所有(见字段声明);回收后即刻置空。
|
||||
unsafe {
|
||||
@@ -660,78 +592,6 @@ impl JsObject {
|
||||
self.upvalues = Box::into_raw(v) as *mut u8;
|
||||
}
|
||||
|
||||
/// 用 `rewrite` 改写对象内引用的所有对象值。
|
||||
///
|
||||
/// 用于 GC 移动 / 世代晋升:遍历数组元素区、命名属性区、访问器 getter/setter、
|
||||
/// `proto`、`captured_this`、`home_object` 与 upvalue cell 中的对象值,
|
||||
/// 原地替换为新地址。非对象值保持不变。
|
||||
pub fn rewrite_object_values<F>(&mut self, mut rewrite: F)
|
||||
where
|
||||
F: FnMut(JsValue) -> JsValue,
|
||||
{
|
||||
if let Some(elements) = self.array_elements_vec_mut() {
|
||||
for value in elements {
|
||||
if value.is_object() {
|
||||
*value = rewrite(*value);
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(meta) = self.array_elements_meta_vec_mut() {
|
||||
for entry in meta.iter_mut().flatten() {
|
||||
if entry.get.is_object() {
|
||||
entry.get = rewrite(entry.get);
|
||||
}
|
||||
if entry.set.is_object() {
|
||||
entry.set = rewrite(entry.set);
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(props) = self.hash_props_vec_mut() {
|
||||
for value in props {
|
||||
if value.is_object() {
|
||||
*value = rewrite(*value);
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(meta) = self.prop_meta_vec_mut() {
|
||||
for entry in meta.iter_mut().flatten() {
|
||||
if entry.get.is_object() {
|
||||
entry.get = rewrite(entry.get);
|
||||
}
|
||||
if entry.set.is_object() {
|
||||
entry.set = rewrite(entry.set);
|
||||
}
|
||||
}
|
||||
}
|
||||
if self.proto.is_object() {
|
||||
self.proto = rewrite(self.proto);
|
||||
}
|
||||
if self.captured_this.is_object() {
|
||||
self.captured_this = rewrite(self.captured_this);
|
||||
}
|
||||
if self.home_object.is_object() {
|
||||
self.home_object = rewrite(self.home_object);
|
||||
}
|
||||
if self.boxed_value.is_object() {
|
||||
self.boxed_value = rewrite(self.boxed_value);
|
||||
}
|
||||
if self.regexp_source.is_object() {
|
||||
self.regexp_source = rewrite(self.regexp_source);
|
||||
}
|
||||
if self.regexp_flags.is_object() {
|
||||
self.regexp_flags = rewrite(self.regexp_flags);
|
||||
}
|
||||
if !self.upvalues.is_null() {
|
||||
let cells = unsafe { &mut *(self.upvalues as *mut Vec<*mut Cell>) };
|
||||
for cell_ptr in cells {
|
||||
let cell = unsafe { &mut **cell_ptr };
|
||||
if cell.value.is_object() {
|
||||
cell.value = rewrite(cell.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 当前形状 ID(header 低位 24 位)。
|
||||
pub fn shape_id(&self) -> ShapeId {
|
||||
self.header & 0x00FF_FFFF
|
||||
|
||||
@@ -342,15 +342,6 @@ impl JsObject {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn hash_props_vec_mut(&mut self) -> Option<&mut Vec<JsValue>> {
|
||||
if self.hash_props.is_null() {
|
||||
None
|
||||
} else {
|
||||
// SAFETY: 指针归本对象所有,见字段声明。
|
||||
unsafe { Some(&mut *(self.hash_props as *mut Vec<JsValue>)) }
|
||||
}
|
||||
}
|
||||
|
||||
/// 若数组元素区为空则初始化,并把长度对齐到 `array_prop_count`,返回其可变引用。
|
||||
fn ensure_array_elements(&mut self) -> &mut Vec<JsValue> {
|
||||
if self.array_elements.is_null() {
|
||||
@@ -375,15 +366,6 @@ impl JsObject {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn array_elements_vec_mut(&mut self) -> Option<&mut Vec<JsValue>> {
|
||||
if self.array_elements.is_null() {
|
||||
None
|
||||
} else {
|
||||
// SAFETY: 指针归本对象所有,见字段声明。
|
||||
unsafe { Some(&mut *(self.array_elements as *mut Vec<JsValue>)) }
|
||||
}
|
||||
}
|
||||
|
||||
/// 确保数组元素元数据向量已分配并返回可变引用(长度对齐当前元素数)。
|
||||
pub fn ensure_array_elements_meta(&mut self) -> &mut Vec<Option<PropMetaEntry>> {
|
||||
if self.array_elements_meta.is_null() {
|
||||
|
||||
@@ -61,36 +61,6 @@ fn session_epoch_marker_keeps_object_size_bound() {
|
||||
assert!(sz <= 256, "JsObject grew unexpectedly: {sz}B");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn clone_for_session_epoch_marks_clone_and_does_not_alias_hash_props() {
|
||||
let mut source = JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null());
|
||||
source.set_prop_at(0, JsValue::int(1));
|
||||
|
||||
let mut clone = source.clone_for_session_epoch();
|
||||
assert!(clone.is_session_epoch());
|
||||
clone.set_prop_at(0, JsValue::int(2));
|
||||
|
||||
assert_eq!(source.get_prop_at(0), JsValue::int(1));
|
||||
assert_eq!(clone.get_prop_at(0), JsValue::int(2));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn clone_for_session_epoch_does_not_alias_prop_meta() {
|
||||
let mut source = JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null());
|
||||
source.set_prop_at(0, JsValue::undefined());
|
||||
source.set_accessor_meta(0, JsValue::int(10), JsValue::int(11), PropAttributes::DEFAULT_DATA);
|
||||
|
||||
let mut clone = source.clone_for_session_epoch();
|
||||
clone.set_accessor_meta(0, JsValue::int(20), JsValue::int(21), PropAttributes::DEFAULT_DATA);
|
||||
|
||||
let source_meta = source.prop_meta_at(0).expect("source meta");
|
||||
let clone_meta = clone.prop_meta_at(0).expect("clone meta");
|
||||
assert_eq!(source_meta.get, JsValue::int(10));
|
||||
assert_eq!(source_meta.set, JsValue::int(11));
|
||||
assert_eq!(clone_meta.get, JsValue::int(20));
|
||||
assert_eq!(clone_meta.set, JsValue::int(21));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn shape_id_roundtrip() {
|
||||
let mut obj = JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null());
|
||||
|
||||
@@ -107,33 +107,3 @@ pub(crate) fn for_each_job_value(job: &Microtask, mut f: impl FnMut(JsValue)) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 供外部改写微任务队列中的 JsValue(session GC sweep 用)。
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn rewrite_job_values(job: &mut Microtask, mut rewrite: impl FnMut(JsValue) -> JsValue) {
|
||||
match job {
|
||||
Microtask::Reaction {
|
||||
handler,
|
||||
argument,
|
||||
resolve,
|
||||
reject,
|
||||
..
|
||||
} => {
|
||||
*handler = rewrite(*handler);
|
||||
*argument = rewrite(*argument);
|
||||
*resolve = rewrite(*resolve);
|
||||
*reject = rewrite(*reject);
|
||||
}
|
||||
Microtask::Thenable {
|
||||
thenable,
|
||||
then,
|
||||
resolve,
|
||||
reject,
|
||||
} => {
|
||||
*thenable = rewrite(*thenable);
|
||||
*then = rewrite(*then);
|
||||
*resolve = rewrite(*resolve);
|
||||
*reject = rewrite(*reject);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ mod reactions;
|
||||
mod settlement;
|
||||
|
||||
pub(crate) use gc_edges::{drop_promise_native, promise_native_edges, promise_native_size};
|
||||
pub(crate) use jobs::{for_each_job_value, rewrite_job_values};
|
||||
pub(crate) use jobs::for_each_job_value;
|
||||
pub use reactions::promise_settled_value;
|
||||
|
||||
/// Promise 的 settled 状态。
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::collections::HashSet;
|
||||
use std::mem::size_of;
|
||||
use std::time::Instant;
|
||||
|
||||
@@ -373,8 +373,8 @@ impl SessionGc {
|
||||
/// 对象 DFS 跟踪 session 对象单表(统一入口 Box 化后无 epoch 表);perm
|
||||
/// 对象不置位(其位跨收集残留会令 DFS 短路漏扫),走独立已访集防环。
|
||||
/// 字符串边走 rope 闭包传播(Cons 子节点与扁平化产物),BigInt 边直接入
|
||||
/// 存活集。roots 由 `Vm::for_each_root` 枚举,字段清单与 `rewrite_values`
|
||||
/// 一一对应、须同步。只置位不搬移,调用前须先 `clear_all_marks` 清位。
|
||||
/// 存活集。roots 由 `Vm::for_each_root` 枚举。只置位不搬移,调用前须先
|
||||
/// `clear_all_marks` 清位。
|
||||
pub(crate) fn mark(&mut self, vm: &Vm) {
|
||||
vm_debug!("[GC] mark phase: {} roots", vm.gc_state.session_object_ptrs.len());
|
||||
let mut seeds = Vec::new();
|
||||
@@ -1060,19 +1060,6 @@ impl Default for SessionGc {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn rewrite_forwarded_value(
|
||||
value: JsValue, forwarding: &HashMap<*mut JsObject, *mut JsObject, FxBuildHasher>,
|
||||
) -> JsValue {
|
||||
if !value.is_object() {
|
||||
return value;
|
||||
}
|
||||
forwarding
|
||||
.get(&value.as_js_object_ptr())
|
||||
.map(|&ptr| JsValue::from_js_object(ptr))
|
||||
.unwrap_or(value)
|
||||
}
|
||||
|
||||
/// 原地 sweep 的弱键判定:session 键按 mark 位定生死(已标 = 强可达保留,
|
||||
/// 未标 = 死键丢弃),非 session 键(perm 对象等)不可死、恒保留;symbol
|
||||
/// 键按值恒等、恒保留。
|
||||
@@ -1096,28 +1083,5 @@ pub(crate) fn resolve_weak_key_sweep(key: weak_map::WeakKey) -> Option<weak_map:
|
||||
Some(key)
|
||||
}
|
||||
|
||||
/// 晋升收敛后的弱键定夺:统一入口 Box 化后晋升族在生产路径不产克隆
|
||||
/// (epoch 守卫恒假、无 epoch 对象),转发表恒空、无重指需求;reset 边界
|
||||
/// 的 mark 位已被前序收集清位,不携带本轮可达性信息。故定夺退化为原样
|
||||
/// 保留——弱键生死由原地 sweep 的 mark 位判定单一裁定,本路径不改表项。
|
||||
///
|
||||
/// # 边界与前提
|
||||
/// - 不解引用任何对象本体(无位域读取),无定夺时序面;
|
||||
/// - 晋升族整体为死代码保留面,弱表族本体退役时一并删除。
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn resolve_weak_key_after_promotion(key: weak_map::WeakKey) -> Option<weak_map::WeakKey> {
|
||||
Some(key)
|
||||
}
|
||||
|
||||
/// 按 forwarding 表把全部 VM 根引用重写到搬移后的新地址。与 `for_each_value`
|
||||
/// 共用同一字段清单(经 `rewrite_values` 遍历)且须同步:遗漏字段会在搬移后
|
||||
/// 保留指向旧 arena 的悬垂指针。
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn rewrite_vm_roots(vm: &mut Vm, forwarding: &HashMap<*mut JsObject, *mut JsObject, FxBuildHasher>) {
|
||||
vm_debug!("[GC] rewrite_vm_roots: {} forwarded objects", forwarding.len());
|
||||
// 统一遍历:与 for_each_value 共用同一字段清单。
|
||||
vm.rewrite_values(|value| rewrite_forwarded_value(value, forwarding));
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
@@ -131,53 +131,6 @@ fn gc_roots_contains_registers_frames_and_root_roots() {
|
||||
assert_eq!(vm.exception_value, Some(JsValue::from_js_object(root_session)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rewrite_matches_roots_coverage() {
|
||||
// 指针重写必须覆盖根收集访问的同一组执行核心字段:session→marker 映射后,
|
||||
// 每个持有 session 的字段都应被改写为 marker(与上文基于 for_each 的覆盖
|
||||
// 测试同口径,共同构成孪生清单验证)。
|
||||
let mut vm = Vm::new();
|
||||
let obj = plain_object(&mut vm);
|
||||
let session = obj;
|
||||
let marker = plain_object(&mut vm);
|
||||
let marker_session = marker;
|
||||
vm.regs[0] = JsValue::from_js_object(session);
|
||||
vm.last_uncaught_value = Some(JsValue::from_js_object(session));
|
||||
vm.generator_suspended = Some(JsValue::from_js_object(session));
|
||||
vm.delegated_iterator = Some(JsValue::from_js_object(session));
|
||||
vm.async_context = Some(JsValue::from_js_object(session));
|
||||
vm.async_gen_context = Some(JsValue::from_js_object(session));
|
||||
vm.inline_callee = Some(JsValue::from_js_object(session));
|
||||
vm.pending_completion = Some(crate::vm::Completion::Return {
|
||||
value: JsValue::from_js_object(session),
|
||||
remaining_finally: 0,
|
||||
for_of_count: 0,
|
||||
for_in_count: 0,
|
||||
});
|
||||
|
||||
let mut forwarding = std::collections::HashMap::new();
|
||||
forwarding.insert(session, marker_session);
|
||||
vm.rewrite_values(|v| {
|
||||
if v.is_object() {
|
||||
if let Some(&m) = forwarding.get(&v.as_js_object_ptr()) {
|
||||
return JsValue::from_js_object(m);
|
||||
}
|
||||
}
|
||||
v
|
||||
});
|
||||
assert_eq!(vm.regs[0].as_js_object_ptr(), marker_session);
|
||||
assert_eq!(vm.last_uncaught_value.unwrap().as_js_object_ptr(), marker_session);
|
||||
assert_eq!(vm.generator_suspended.unwrap().as_js_object_ptr(), marker_session);
|
||||
assert_eq!(vm.delegated_iterator.unwrap().as_js_object_ptr(), marker_session);
|
||||
assert_eq!(vm.async_context.unwrap().as_js_object_ptr(), marker_session);
|
||||
assert_eq!(vm.async_gen_context.unwrap().as_js_object_ptr(), marker_session);
|
||||
assert_eq!(vm.inline_callee.unwrap().as_js_object_ptr(), marker_session);
|
||||
match vm.pending_completion.unwrap() {
|
||||
crate::vm::Completion::Return { value, .. } => assert_eq!(value.as_js_object_ptr(), marker_session),
|
||||
_ => panic!("expected Return completion"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mark_phase_reaches_cycles_and_unreachable_are_unmarked() {
|
||||
let mut vm = Vm::new();
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//! GC 根遍历与执行期收集钩子:根统一枚举、搬移后指针重写、执行期两档
|
||||
//! GC 根遍历与执行期收集钩子:根统一枚举、执行期两档
|
||||
//! 收集入口(安全点门控)与 session GC 账目统计访问器。
|
||||
|
||||
use oxide_types::object::{Cell, JsObject, JsString};
|
||||
@@ -9,10 +9,9 @@ use super::Vm;
|
||||
use crate::session_gc::SessionGc;
|
||||
|
||||
impl Vm {
|
||||
/// GC 根收集的统一遍历(对象与字符串都产出)。与 `rewrite_values` 字段一一对应。
|
||||
/// GC 根收集的统一遍历(对象与字符串都产出)。
|
||||
/// 覆盖执行核心的全部 JsValue 持有点:regs/帧/各栈段/cell/在途异常与完成/
|
||||
/// 挂起信号/迭代器/微任务/global。新增执行字段必须同时登记在此与
|
||||
/// `rewrite_values`。
|
||||
/// 挂起信号/迭代器/微任务/global。
|
||||
pub(crate) fn for_each_value(&self, mut f: impl FnMut(JsValue)) {
|
||||
for value in &self.regs {
|
||||
f(*value);
|
||||
@@ -106,118 +105,7 @@ impl Vm {
|
||||
f(JsValue::from_js_object(self.session.global_object().as_ptr() as *mut JsObject));
|
||||
}
|
||||
|
||||
/// GC 指针重写(session 搬移后调用)。与 `for_each_value` 字段一一对应。
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn rewrite_values(&mut self, mut rewrite: impl FnMut(JsValue) -> JsValue) {
|
||||
for value in &mut self.regs {
|
||||
*value = rewrite(*value);
|
||||
}
|
||||
for frame in &mut self.frames {
|
||||
frame.saved_this = rewrite(frame.saved_this);
|
||||
frame.saved_new_target = rewrite(frame.saved_new_target);
|
||||
frame.callee = rewrite(frame.callee);
|
||||
frame.constructed_this = frame.constructed_this.map(&mut rewrite);
|
||||
}
|
||||
for v in &mut self.save_stack {
|
||||
*v = rewrite(*v);
|
||||
}
|
||||
for v in &mut self.spill_stack {
|
||||
*v = rewrite(*v);
|
||||
}
|
||||
for cell_vec in &mut self.cell_stack {
|
||||
for &mut cell_ptr in cell_vec.iter_mut() {
|
||||
if cell_ptr.is_null() {
|
||||
continue;
|
||||
}
|
||||
// SAFETY: cell 经 alloc_cell 独立堆分配,本 session 内指针有效。
|
||||
let cell = unsafe { &mut *cell_ptr };
|
||||
cell.value = rewrite(cell.value);
|
||||
}
|
||||
}
|
||||
self.exception_value = self.exception_value.map(&mut rewrite);
|
||||
self.pending_exception = self.pending_exception.map(&mut rewrite);
|
||||
self.last_uncaught_value = self.last_uncaught_value.map(&mut rewrite);
|
||||
self.pending_length_exception = self.pending_length_exception.map(&mut rewrite);
|
||||
for cached in self.template_objects.values_mut() {
|
||||
*cached = rewrite(*cached);
|
||||
}
|
||||
self.pending_completion = self.pending_completion.map(|completion| match completion {
|
||||
Completion::Return {
|
||||
value,
|
||||
remaining_finally,
|
||||
for_of_count,
|
||||
for_in_count,
|
||||
} => Completion::Return {
|
||||
value: rewrite(value),
|
||||
remaining_finally,
|
||||
for_of_count,
|
||||
for_in_count,
|
||||
},
|
||||
other => other,
|
||||
});
|
||||
self.generator_suspended = self.generator_suspended.map(&mut rewrite);
|
||||
self.delegated_iterator = self.delegated_iterator.map(&mut rewrite);
|
||||
self.async_context = self.async_context.map(&mut rewrite);
|
||||
self.async_gen_context = self.async_gen_context.map(&mut rewrite);
|
||||
// 在途异步逃出的 promise/完成值/剩余迭代器随 sweep 重写(与 mark 段一一对应)。
|
||||
self.pending_async_escape = self.pending_async_escape.as_mut().map(|pend| {
|
||||
let completion = match pend.completion {
|
||||
Completion::Return {
|
||||
value,
|
||||
remaining_finally,
|
||||
for_of_count,
|
||||
for_in_count,
|
||||
} => Completion::Return {
|
||||
value: rewrite(value),
|
||||
remaining_finally,
|
||||
for_of_count,
|
||||
for_in_count,
|
||||
},
|
||||
other => other,
|
||||
};
|
||||
super::PendingAsyncEscape {
|
||||
close_promise: rewrite(pend.close_promise),
|
||||
completion,
|
||||
remaining: pend.remaining.iter().copied().map(&mut rewrite).collect(),
|
||||
}
|
||||
});
|
||||
self.inline_callee = self.inline_callee.map(&mut rewrite);
|
||||
for entry in &mut self.iters.for_of_iters {
|
||||
entry.iterator = rewrite(entry.iterator);
|
||||
entry.last_result = rewrite(entry.last_result);
|
||||
entry.fast_value = rewrite(entry.fast_value);
|
||||
}
|
||||
// 微任务队列中的值随 sweep 重写。
|
||||
for job in &mut self.job_queue {
|
||||
crate::promise::rewrite_job_values(job, &mut rewrite);
|
||||
}
|
||||
// Atomics waiter 表中的 promise 随 sweep 重写(与 mark 段一一对应)。
|
||||
for promises in self.atomics_waiters.values_mut() {
|
||||
for p in promises {
|
||||
*p = rewrite(*p);
|
||||
}
|
||||
}
|
||||
for iter in &mut self.iters.for_in_iters {
|
||||
if iter.is_null() {
|
||||
continue;
|
||||
}
|
||||
// SAFETY: for_in_iters 存放堆上迭代器体,VM 表独占持有。
|
||||
unsafe {
|
||||
for (v, _si) in (*(*iter)).keys.iter_mut() {
|
||||
*v = rewrite(*v);
|
||||
}
|
||||
}
|
||||
}
|
||||
let global_ptr = self.session.global_object().as_ptr() as *mut JsObject;
|
||||
if !global_ptr.is_null() {
|
||||
// SAFETY: KernelSession 在 VM 生命周期内拥有 global_object。
|
||||
unsafe {
|
||||
(*global_ptr).rewrite_object_values(rewrite);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// GC 根统一枚举入口:遍历的字段清单与 `rewrite_values` 一一对应。
|
||||
/// GC 根统一枚举入口:遍历的字段清单与 `for_each_value` 相同。
|
||||
pub(crate) fn for_each_root(&self, f: impl FnMut(JsValue)) {
|
||||
self.for_each_value(f);
|
||||
}
|
||||
|
||||
@@ -359,7 +359,7 @@ pub struct Vm {
|
||||
/// 标签模板对象缓存(GetTemplateObject):键 = (表代际, 模块 flat_id, site 序号)。
|
||||
/// 同一代际同 flat_id 同 site 恒返回同一对象;每次 `run()` 清空(缓存只留
|
||||
/// 本次 run 的条目,规模有界)。键含代际维度后,跨 run 调用旧代模块的
|
||||
/// flat_id 重编号不再误命中。值为 GC 根(for_each_value/rewrite_values 遍历)。
|
||||
/// flat_id 重编号不再误命中。值为 GC 根(for_each_value 遍历)。
|
||||
pub(crate) template_objects: HashMap<(u32, u32, u32), JsValue>,
|
||||
/// 当前活动字节码所属模块的 flat_id(顶层 0;帧切换时随 bytecode 换)。
|
||||
/// GET_TEMPLATE_OBJECT 据其区分不同编译树(eval 每次编译独立 site)。
|
||||
|
||||
@@ -20,7 +20,7 @@ use oxide_types::value::JsValue;
|
||||
|
||||
/// session 堆与 GC 簿记。
|
||||
///
|
||||
/// 仅做字段分类。mark/sweep/rewrite_vm_roots 驻留在 `Vm` 上:GC 需扫描所有
|
||||
/// 仅做字段分类。mark/sweep 驻留在 `Vm` 上:GC 需扫描所有
|
||||
/// 子结构的根(regs、frames、for_in_iters、for_of_iters、exception_value 等),
|
||||
/// 无法限制在 GcState 内。
|
||||
pub(crate) struct GcState {
|
||||
|
||||
Reference in New Issue
Block a user