refactor: 退役内置盒克隆重写族死函数与孤儿辅助

This commit is contained in:
2026-10-02 20:35:48 +00:00
parent 43acaacd08
commit b76f2214f9
8 changed files with 17 additions and 358 deletions
+3 -37
View File
@@ -144,8 +144,8 @@ fn dv_buffer_writable<H: VmHost>(vm: &mut H, view: DataViewData) -> Result<(), J
Ok(())
}
/// JS 调用点后的缓冲重取纪律:重读寄存器再重取载荷(epoch 晋升改写
/// 寄存器,旧 JsValue 滞留 epoch 克隆旧盒);detached → TypeError。
/// JS 调用点后的缓冲重取纪律:重读寄存器并重取载荷,寄存器值为唯一口径;
/// detached → TypeError。
/// 返回(寄存器重读值、live 长、存储上限)。
fn revalidate_buffer<H: VmHost>(vm: &mut H, buf_reg: u8) -> Result<(JsValue, usize, usize), JsValue> {
let buffer = vm.reg(buf_reg);
@@ -246,8 +246,7 @@ fn has_data_view_proto<H: VmHost>(vm: &mut H, this_val: JsValue) -> bool {
/// # 边界与前提
/// - 原型读取在全部初校验之后:越界 RangeError 先于抛错的 prototype getter。
/// - NewTarget 非对象(直调/缺省面)时直接回落默认原型,不抛错。
/// - 每个 JS 调用点后重取缓冲(重读寄存器 + 载荷重取):晋升改写寄存器,
/// 旧值滞留 epoch 克隆旧盒。
/// - 每个 JS 调用点后重取缓冲(重读寄存器 + 载荷重取),寄存器值为唯一口径。
pub fn data_view_constructor<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
if !has_data_view_proto(vm, this_val) {
@@ -357,39 +356,6 @@ pub fn data_view_native_edges(obj: &JsObject) -> Vec<JsValue> {
}
}
/// 克隆 DataView 视图数据到新对象,用 `rewrite` 改写 buffer 引用。
pub fn clone_data_view_native_with_rewrite<F>(old_obj: &JsObject, new_obj: &mut JsObject, mut rewrite: F)
where
F: FnMut(JsValue) -> JsValue,
{
let Some(ptr) = data_view_data_ptr(old_obj) else {
return;
};
if ptr.is_null() {
return;
}
let mut data = unsafe { *ptr };
data.buffer = rewrite(data.buffer);
let cloned = Box::into_raw(Box::new(data));
new_obj.set_native_fn(Some(unsafe { NativeFnPtr::from_raw(cloned as *const ()) }));
}
/// 原地重写 DataView 的 buffer 引用。
pub fn rewrite_data_view_native<F>(obj: &mut JsObject, mut rewrite: F)
where
F: FnMut(JsValue) -> JsValue,
{
let Some(ptr) = data_view_data_ptr(obj) else {
return;
};
if ptr.is_null() {
return;
}
unsafe {
(*ptr).buffer = rewrite((*ptr).buffer);
}
}
/// 只读核算 DataView 视图数据字节(不释放)。
pub fn data_view_native_size(obj: &JsObject) -> u64 {
let Some(ptr) = data_view_data_ptr(obj) else {
+2 -56
View File
@@ -7,8 +7,8 @@
//! `type_tag` 为 `JsObject::OBJ_TYPE_DISPOSABLE_STACK`(同步)或
//! `OBJ_TYPE_ASYNC_DISPOSABLE_STACK`(异步)时区分接收者,`hint` 以 0/1 两值区分
//! 条目释放语义(定义见 `DisposeEntry.hint`),`wrap_sync` 标记 async 栈 use 落回
//! `@@dispose` 的条目(返回值丢弃、异常异步化)。GC 四函数
//! (edges/rewrite/clone/drop)供 session 层跨 epoch 追踪,签名与 Map/Promise
//! `@@dispose` 的条目(返回值丢弃、异常异步化)。GC 三函数
//! (edges/size/drop)接线 mark 边、字节账目与释放,形态与 Map/Promise
//! 状态盒同构。
use oxide_kernel::shape_forge::EMPTY_SHAPE_ID;
@@ -579,60 +579,6 @@ pub fn dispose_edges(obj: &JsObject) -> Vec<JsValue> {
unsafe { (*ptr).entries.iter().flat_map(|entry| [entry.value, entry.method]).collect() }
}
/// 克隆状态盒到新对象,用 `rewrite` 改写其中的对象引用
/// (供跨 epoch 的对象重写/克隆流程使用)。
pub fn clone_dispose_native_with_rewrite<F>(src: &JsObject, dst: &mut JsObject, mut rewrite: F)
where
F: FnMut(JsValue) -> JsValue,
{
if !src.is_disposable_stack_obj() && !src.is_async_disposable_stack_obj() {
return;
}
let ptr = get_capability_ptr(src);
if ptr.is_null() {
dst.set_native_data(std::ptr::null_mut());
return;
}
// SAFETY: 同上,src 状态盒在 GC 移动期间仍存活。
let src_cap = unsafe { &*ptr };
let cloned = DisposeCapability {
state: src_cap.state,
entries: src_cap
.entries
.iter()
.map(|entry| DisposeEntry {
value: if entry.value.is_object() { rewrite(entry.value) } else { entry.value },
method: if entry.method.is_object() { rewrite(entry.method) } else { entry.method },
hint: entry.hint,
arg_style: entry.arg_style,
wrap_sync: entry.wrap_sync,
})
.collect(),
};
dst.set_native_data(Box::into_raw(Box::new(cloned)) as *mut u8);
}
/// 原地重写状态盒,用 `rewrite` 改写其中的对象引用。
pub fn rewrite_dispose_native<F>(obj: &mut JsObject, mut rewrite: F)
where
F: FnMut(JsValue) -> JsValue,
{
if !obj.is_disposable_stack_obj() && !obj.is_async_disposable_stack_obj() {
return;
}
let ptr = get_capability_ptr(obj);
if ptr.is_null() {
return;
}
// SAFETY: 同上,改写发生在 GC 移动/清扫期间,对象仍存活。
unsafe {
for entry in &mut (*ptr).entries {
entry.value = rewrite(entry.value);
entry.method = rewrite(entry.method);
}
}
}
/// 只读核算 DisposableStack 状态盒字节(不释放)。
pub fn disposable_stack_native_size(obj: &JsObject) -> u64 {
if !obj.is_disposable_stack_obj() && !obj.is_async_disposable_stack_obj() {
-55
View File
@@ -41,13 +41,6 @@ impl MapInner {
}
}
pub(crate) fn with_capacity(capacity: usize) -> Self {
Self {
slots: Vec::with_capacity(capacity),
index: HashMap::with_capacity(capacity),
}
}
/// 活表条目数(规范 SetDataSize 口径,空槽不计)。
pub(crate) fn len(&self) -> usize {
self.index.len()
@@ -171,54 +164,6 @@ pub fn map_native_edges(obj: &JsObject) -> Vec<JsValue> {
unsafe { (*inner).iter().flat_map(|(key, value)| [key.0, value]).collect() }
}
/// 克隆 Map 的 native 数据到新对象,用 `rewrite` 改写其中的对象引用
/// (供跨 epoch 的对象重写/克隆流程使用)。
pub fn clone_map_native_with_rewrite<F>(src: &JsObject, dst: &mut JsObject, mut rewrite: F)
where
F: FnMut(JsValue) -> JsValue,
{
if !src.is_map() {
return;
}
let inner = src.native_data() as *const MapInner;
if inner.is_null() {
dst.set_native_data(std::ptr::null_mut());
return;
}
let mut cloned = MapInner::new();
unsafe {
for (key, value) in (*inner).iter() {
let new_key = if key.0.is_object() { SetKey(rewrite(key.0)) } else { key };
let new_value = if value.is_object() { rewrite(value) } else { value };
cloned.insert(new_key, new_value);
}
}
dst.set_native_data(Box::into_raw(Box::new(cloned)) as *mut u8);
}
/// 原地重写 Map 的 native 数据,用 `rewrite` 改写其中的对象引用。
pub fn rewrite_map_native<F>(obj: &mut JsObject, mut rewrite: F)
where
F: FnMut(JsValue) -> JsValue,
{
if !obj.is_map() {
return;
}
let inner = obj.native_data() as *mut MapInner;
if inner.is_null() {
return;
}
unsafe {
let mut rewritten = MapInner::with_capacity((*inner).len());
for (key, value) in (*inner).iter() {
let new_key = if key.0.is_object() { SetKey(rewrite(key.0)) } else { key };
let new_value = if value.is_object() { rewrite(value) } else { value };
rewritten.insert(new_key, new_value);
}
*inner = rewritten;
}
}
/// 只读核算 Map 的 native 数据字节(不释放)。
/// 槽表与辅助索引均按 capacity 核算,与 `drop_map_native` 释放口径一致,
/// 供 GC 账目核算。
-73
View File
@@ -235,79 +235,6 @@ pub fn module_ns_cell_edges(obj: &JsObject) -> Vec<*mut Cell> {
out
}
/// 原地重写条目表内的 JsValue 边(对象搬移/epoch 晋升后的引用重定位)。
///
/// # 副作用
/// - 改写 `Value` 条目的值与共享 cell 内的值;cell 指针本身稳定不变。
pub fn rewrite_module_ns_native<F>(obj: &mut JsObject, mut rewrite: F)
where
F: FnMut(JsValue) -> JsValue,
{
let table = ns_table_ptr(obj);
if table.is_null() {
return;
}
// SAFETY: table 归本 ns 对象持有,原地改写其 JsValue 边。
let table_ref = unsafe { &mut *table };
for entry in table_ref.entries.iter_mut() {
match &mut entry.state {
ModuleNsState::Value { value, .. } => *value = rewrite(*value),
ModuleNsState::Cell(cell) => {
if !cell.is_null() {
// SAFETY: cell 生命周期见 `module_ns_export`;共享 cell 内值一并改写。
let cell_ref = unsafe { &mut **cell };
cell_ref.value = rewrite(cell_ref.value);
}
}
}
}
}
/// 深拷贝条目表到 `dst`,并用 `rewrite` 改写其中的对象引用。
///
/// # 注意事项
/// - `clone_for_session_epoch` 只浅拷贝 `native_data` 指针;本函数必须在新对象上
/// 重建独立 Box,否则原件与克隆共享同一表会在释放时双放。
/// - `Cell` 指针本身跨搬移稳定,只改写其内部值。
pub fn clone_module_ns_native_with_rewrite<F>(src: &JsObject, dst: &mut JsObject, mut rewrite: F)
where
F: FnMut(JsValue) -> JsValue,
{
if !src.is_module_namespace() {
return;
}
let table = src.native_data() as *const ModuleNsTable;
if table.is_null() {
dst.set_native_data(std::ptr::null_mut());
return;
}
// SAFETY: src.native_data 指向 src 持有的 Box<ModuleNsTable>。
let table_ref = unsafe { &*table };
let mut entries = Vec::with_capacity(table_ref.entries.len());
for entry in &table_ref.entries {
let state = match &entry.state {
ModuleNsState::Value { value, initialized } => ModuleNsState::Value {
value: if value.is_object() { rewrite(*value) } else { *value },
initialized: *initialized,
},
ModuleNsState::Cell(cell) => {
if !cell.is_null() {
// SAFETY: cell 生命周期见 `module_ns_export`;晋升/搬移后改写其内值。
let cell_ref = unsafe { &mut **cell };
cell_ref.value = rewrite(cell_ref.value);
}
ModuleNsState::Cell(*cell)
}
};
entries.push(ModuleNsEntry {
name_si: entry.name_si,
origin: entry.origin,
state,
});
}
dst.set_native_data(Box::into_raw(Box::new(ModuleNsTable { entries })) as *mut u8);
}
/// 只读核算条目表的 native 数据字节(不释放),与 `drop_module_ns_native` 的
/// capacity 口径一致,供 GC 账目核算。
pub fn module_ns_native_size(obj: &JsObject) -> u64 {
-45
View File
@@ -141,51 +141,6 @@ pub fn set_native_edges(obj: &JsObject) -> Vec<JsValue> {
unsafe { (*inner).iter().map(|key| key.0).collect() }
}
/// 克隆 Set 的 native 数据到新对象,用 `rewrite` 改写其中的对象引用。
pub fn clone_set_native_with_rewrite<F>(src: &JsObject, dst: &mut JsObject, mut rewrite: F)
where
F: FnMut(JsValue) -> JsValue,
{
if !src.is_set() {
return;
}
let inner = src.native_data() as *const SetInner;
if inner.is_null() {
dst.set_native_data(std::ptr::null_mut());
return;
}
let mut cloned = SetInner::new();
unsafe {
for key in (*inner).iter() {
let new_key = if key.0.is_object() { SetKey(rewrite(key.0)) } else { *key };
cloned.insert(new_key);
}
}
dst.set_native_data(Box::into_raw(Box::new(cloned)) as *mut u8);
}
/// 原地重写 Set 的 native 数据,用 `rewrite` 改写其中的对象引用。
pub fn rewrite_set_native<F>(obj: &mut JsObject, mut rewrite: F)
where
F: FnMut(JsValue) -> JsValue,
{
if !obj.is_set() {
return;
}
let inner = obj.native_data() as *mut SetInner;
if inner.is_null() {
return;
}
unsafe {
let mut rewritten = SetInner::with_capacity((*inner).len());
for key in (*inner).iter() {
let new_key = if key.0.is_object() { SetKey(rewrite(key.0)) } else { *key };
rewritten.insert(new_key);
}
*inner = rewritten;
}
}
/// 只读核算 Set 的 native 数据字节(不释放)。
/// 与 `drop_set_native` 释放口径一致(capacity),供 GC 账目核算。
pub fn set_native_size(obj: &JsObject) -> u64 {
-33
View File
@@ -181,39 +181,6 @@ pub fn typed_array_native_edges(obj: &JsObject) -> Vec<JsValue> {
}
}
/// 克隆 TypedArray 的视图数据到新对象,用 `rewrite` 改写 buffer 引用。
pub fn clone_typed_array_native_with_rewrite<F>(old_obj: &JsObject, new_obj: &mut JsObject, mut rewrite: F)
where
F: FnMut(JsValue) -> JsValue,
{
let Some(ptr) = typed_array_data_ptr(old_obj) else {
return;
};
if ptr.is_null() {
return;
}
let mut data = unsafe { *ptr };
data.buffer = rewrite(data.buffer);
let cloned = Box::into_raw(Box::new(data));
new_obj.set_native_fn(Some(unsafe { NativeFnPtr::from_raw(cloned as *const ()) }));
}
/// 原地重写 TypedArray 的 buffer 引用。
pub fn rewrite_typed_array_native<F>(obj: &mut JsObject, mut rewrite: F)
where
F: FnMut(JsValue) -> JsValue,
{
let Some(ptr) = typed_array_data_ptr(obj) else {
return;
};
if ptr.is_null() {
return;
}
unsafe {
(*ptr).buffer = rewrite((*ptr).buffer);
}
}
/// 只读核算 TypedArray 视图数据字节(不释放)。
pub fn typed_array_native_size(obj: &JsObject) -> u64 {
let Some(ptr) = typed_array_data_ptr(obj) else {
+9 -56
View File
@@ -1,9 +1,10 @@
//! WeakMap 条目表:弱键 → 强值。
//!
//! 键为弱引用(GC mark 不产键边,死键由收集路径按转发表判定后丢条目),
//! 值为强引用(值边进 mark 边扫描与晋升改写)。存储盒经 `Box::into_raw` 挂
//! `JsObject.native_data`,GC 六站点(mark 边 / 移动式 sweep / 晋升克隆 /
//! 原地晋升 / drop / 字节账目)经本模块五函数族接线,口径与 Map/Set 同形。
//! 键为弱引用(GC mark 不产键边,死键由原地 sweep 的 mark 位判定后丢条目),
//! 值为强引用(值边进 mark 边扫描,原地 sweep 弱键定夺相改写,该相值为恒等
//! 改写)。存储盒经 `Box::into_raw` 挂 `JsObject.native_data`,GC 四站点
//! (mark 边 / 原地 sweep 弱键定夺 / drop / 字节账目)经本模块四函数族接线,
//! 口径与 Map/Set 同形。
//! 构造体(iterable 协议)与 set/get/has/delete 四方法的品牌三分枝守卫
//! (set/delete 对非 WeakMap this 抛 TypeError,get/has 静默返 undefined/false)
//! 也在本模块。
@@ -19,7 +20,7 @@ use oxide_types::value::JsValue;
/// (interner 保证同符号同 si)。两臂互斥,不可弱持的值不建键。
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum WeakKey {
/// 对象键:裸指针仅作哈希键与成员查,生命周期由 GC 转发表判定。
/// 对象键:裸指针仅作哈希键与成员查,生命周期由原地 sweep 的 mark 位判定。
Obj(*const JsObject),
/// symbol 键:interned si 值。
Symbol(u32),
@@ -120,34 +121,11 @@ pub fn weak_map_native_edges(obj: &JsObject) -> Vec<JsValue> {
unsafe { (*inner).entries.values().copied().collect() }
}
/// 克隆 WeakMap 条目表到新对象:键原样搬运(生死判定交晋升后的弱键定夺
/// 路径),值经 `rewrite` 改写(强边)。源盒由释放路径单独释放,互不共享。
pub fn clone_weak_map_native_with_rewrite<F>(src: &JsObject, dst: &mut JsObject, mut rewrite: F)
where
F: FnMut(JsValue) -> JsValue,
{
if !src.is_weak_map_obj() {
return;
}
// SAFETY: 源盒指针由构造路径写入,克隆完成 native_data 重指前读取有效。
let inner = weak_map_inner_of(src);
if inner.is_null() {
dst.set_native_data(std::ptr::null_mut());
return;
}
let mut cloned = WeakMapInner::new();
unsafe {
for (key, value) in (*inner).iter() {
let new_value = if value.is_object() { rewrite(value) } else { value };
cloned.entries.insert(key, new_value);
}
}
dst.set_native_data(Box::into_raw(Box::new(cloned)) as *mut u8);
}
/// 原地重写 WeakMap 条目表的键与值:键经 `key_resolve` 判定(返回 `None`
/// 即死键,条目丢弃;`Some` 改指新键),值经 `value_rewrite` 改写(强边)。
/// 按原表整表重建,免条目级原位换键的容量抖动。
/// 键不提前改写,键的生死统一由弱键定夺路径判定(原地 sweep 弱键定夺按
/// mark 位定生死、死键条目丢弃);提前改写键会引入定夺序依赖。按原表
/// 整表重建,免条目级原位换键的容量抖动。
pub fn rewrite_weak_map_native<K, V>(obj: &mut JsObject, mut key_resolve: K, mut value_rewrite: V)
where
K: FnMut(WeakKey) -> Option<WeakKey>,
@@ -174,31 +152,6 @@ where
}
}
/// 原地重写 WeakMap 条目表的值边(强边):键不动,值经 `rewrite` 改写。
/// 供晋升主改写路径使用——键的生死须待转发表收敛后由弱键定夺路径判定,
/// 本路径提前改写键会引入晋升序依赖。
pub fn rewrite_weak_map_native_values<F>(obj: &mut JsObject, mut rewrite: F)
where
F: FnMut(JsValue) -> JsValue,
{
if !obj.is_weak_map_obj() {
return;
}
// native_data 同 rewrite_weak_map_native:构造路径写入的有效 Box 指针。
let inner = obj.native_data() as *mut WeakMapInner;
if inner.is_null() {
return;
}
unsafe {
let mut rewritten = WeakMapInner::with_capacity((*inner).len());
for (key, value) in (*inner).iter() {
let new_value = if value.is_object() { rewrite(value) } else { value };
rewritten.entries.insert(key, new_value);
}
*inner = rewritten;
}
}
/// 只读核算 WeakMap 条目表字节(不释放),供 GC 账目核算;与
/// `drop_weak_map_native` 同口径(盒本体 + 桶容量按条目尺寸计)。
pub fn weak_map_native_size(obj: &JsObject) -> u64 {
+3 -3
View File
@@ -78,9 +78,9 @@ pub struct CallFrame {
pub continuation: FrameContinuation,
/// 被调函数 upvalue cell 表(压帧时从 callee 对象固化,非闭包为 null 空切片)。
///
/// SAFETY 前提:`callee` 是 GC 根(根遍历/重写/深拷贝三处均遍历该字段),
/// 其 `upvalues` Box 创建后不替换(`set_upvalues` 仅 CREATE_CLOSURE 调用一次,
/// 晋升克隆共享同一 Box),故指针跨 GC 恒有效;写路径经 `*mut` 转可变切片
/// SAFETY 前提:`callee` 是 GC 根(根遍历经该字段),其 `upvalues` Box
/// 创建后不替换(`set_upvalues` 仅 CREATE_CLOSURE 调用一次),故指针跨 GC
/// 恒有效;写路径经 `*mut` 转可变切片
/// 与 `upvalues_slice_mut` 同口径(Box 单所有权)。
pub upvalues: *const [*mut Cell],
}