mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-23 18:21:13 +08:00
refactor: for-in 迭代器体脱离 epoch arena 改堆上 Box 独占释放
This commit is contained in:
@@ -703,7 +703,7 @@ fn async_state_mut(obj: &JsObject) -> Option<&mut AsyncState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// 异步挂起帧是否持有 for-in 迭代器:执行期收集门控按指针扫描
|
/// 异步挂起帧是否持有 for-in 迭代器:执行期收集门控按指针扫描
|
||||||
/// (ForInIter body 分配于 epoch arena,换新 Bump 即时失效在表迭代器)。
|
/// (迭代器体是堆上 Box,门控是保守门)。
|
||||||
pub(crate) fn async_holds_suspended_for_in(obj: &JsObject) -> bool {
|
pub(crate) fn async_holds_suspended_for_in(obj: &JsObject) -> bool {
|
||||||
let Some(state) = async_state_mut(obj) else {
|
let Some(state) = async_state_mut(obj) else {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -1677,7 +1677,7 @@ fn async_gen_state_mut(obj: &JsObject) -> Option<&mut AsyncGeneratorState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// 异步生成器挂起帧是否持有 for-in 迭代器:执行期收集门控按指针扫描
|
/// 异步生成器挂起帧是否持有 for-in 迭代器:执行期收集门控按指针扫描
|
||||||
/// (ForInIter body 分配于 epoch arena,换新 Bump 即时失效在表迭代器)。
|
/// (迭代器体是堆上 Box,门控是保守门)。
|
||||||
pub(crate) fn async_generator_holds_suspended_for_in(obj: &JsObject) -> bool {
|
pub(crate) fn async_generator_holds_suspended_for_in(obj: &JsObject) -> bool {
|
||||||
let Some(state) = async_gen_state_mut(obj) else {
|
let Some(state) = async_gen_state_mut(obj) else {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -965,7 +965,7 @@ fn generator_state_mut(obj: &JsObject) -> Option<&mut GeneratorState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// 生成器挂起帧是否持有 for-in 迭代器:执行期收集门控按指针扫描
|
/// 生成器挂起帧是否持有 for-in 迭代器:执行期收集门控按指针扫描
|
||||||
/// (ForInIter body 分配于 epoch arena,换新 Bump 即时失效在表迭代器)。
|
/// (迭代器体是堆上 Box,门控是保守门)。
|
||||||
pub(crate) fn generator_holds_suspended_for_in(obj: &JsObject) -> bool {
|
pub(crate) fn generator_holds_suspended_for_in(obj: &JsObject) -> bool {
|
||||||
let Some(state) = generator_state_mut(obj) else {
|
let Some(state) = generator_state_mut(obj) else {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -1040,8 +1040,8 @@ impl SessionGc {
|
|||||||
/// identity 不分裂。
|
/// identity 不分裂。
|
||||||
///
|
///
|
||||||
/// # 边界与前提
|
/// # 边界与前提
|
||||||
/// - 调用方已完成门控(无活跃/挂起 for-in):ForInIter body 分配于 epoch
|
/// - 调用方已完成门控(无活跃/挂起 for-in):门控是保守门,迭代器体
|
||||||
/// arena,换新 Bump 即时失效在表迭代器;
|
/// 是堆上 Box,收集不搬移迭代器体;
|
||||||
/// - 调用点为 dispatch 安全点(`native_call_depth == 0`),无在途 builtin
|
/// - 调用点为 dispatch 安全点(`native_call_depth == 0`),无在途 builtin
|
||||||
/// 局部裸指针、dispatch 未重入。
|
/// 局部裸指针、dispatch 未重入。
|
||||||
///
|
///
|
||||||
|
|||||||
@@ -1730,18 +1730,18 @@ fn in_run_collection_reclaims_dead_and_keeps_live() {
|
|||||||
|
|
||||||
/// for-in 门控双形钉住:活跃形(迭代器在 `vm.iters` 表内)与挂起形
|
/// for-in 门控双形钉住:活跃形(迭代器在 `vm.iters` 表内)与挂起形
|
||||||
/// (生成器在 for-in 内 yield,迭代器搬入状态盒)都须拦下执行期收集——
|
/// (生成器在 for-in 内 yield,迭代器搬入状态盒)都须拦下执行期收集——
|
||||||
/// 换新 Bump 使 ForInIter body 即时失效;门控开后方可收集。
|
/// 门控是保守门,迭代器体为堆上 Box;门控开后方可收集。
|
||||||
#[test]
|
#[test]
|
||||||
fn active_and_suspended_for_in_block_in_run_collection() {
|
fn active_and_suspended_for_in_block_in_run_collection() {
|
||||||
// 活跃形:迭代器直接压在 vm.iters,O(1) 子句即拦。
|
// 活跃形:迭代器直接压在 vm.iters,O(1) 子句即拦。
|
||||||
let mut vm = vm_with_threshold(65536);
|
let mut vm = vm_with_threshold(65536);
|
||||||
let dead = plain_object(&mut vm);
|
let dead = plain_object(&mut vm);
|
||||||
vm.gc_state.epoch_object_ptrs.push(dead);
|
vm.gc_state.epoch_object_ptrs.push(dead);
|
||||||
let iter = vm.epoch.alloc(crate::vm::ForInIter {
|
let iter = Box::into_raw(Box::new(crate::vm::ForInIter {
|
||||||
keys: bumpalo::collections::Vec::new_in(vm.epoch.bump()),
|
keys: Vec::new(),
|
||||||
index: 0,
|
index: 0,
|
||||||
});
|
}));
|
||||||
vm.iters.push_for_in(iter.cast::<crate::vm::ForInIter<'static>>());
|
vm.iters.push_for_in(iter);
|
||||||
let bump_before = vm.epoch.current_id();
|
let bump_before = vm.epoch.current_id();
|
||||||
|
|
||||||
vm.maybe_collect_in_run();
|
vm.maybe_collect_in_run();
|
||||||
@@ -1750,7 +1750,7 @@ fn active_and_suspended_for_in_block_in_run_collection() {
|
|||||||
assert!(vm.gc_state.epoch_object_ptrs.contains(&dead), "死对象仍在 epoch 表");
|
assert!(vm.gc_state.epoch_object_ptrs.contains(&dead), "死对象仍在 epoch 表");
|
||||||
|
|
||||||
// 迭代器出表后同一调用点即应收集。
|
// 迭代器出表后同一调用点即应收集。
|
||||||
vm.iters.for_in_iters.pop();
|
vm.iters.pop_for_in();
|
||||||
vm.maybe_collect_in_run();
|
vm.maybe_collect_in_run();
|
||||||
assert_eq!(vm.session_gc_stats().total_collections, 1, "门控开:应收集");
|
assert_eq!(vm.session_gc_stats().total_collections, 1, "门控开:应收集");
|
||||||
assert!(vm.epoch.current_id() > bump_before, "收集应换新 epoch Bump");
|
assert!(vm.epoch.current_id() > bump_before, "收集应换新 epoch Bump");
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ pub(crate) struct SuspendedFrame {
|
|||||||
pub save_stack: Vec<JsValue>,
|
pub save_stack: Vec<JsValue>,
|
||||||
pub cell_stack: Vec<Vec<*mut Cell>>,
|
pub cell_stack: Vec<Vec<*mut Cell>>,
|
||||||
pub try_stack: Vec<TryHandler>,
|
pub try_stack: Vec<TryHandler>,
|
||||||
pub for_in_iters: Vec<*mut ForInIter<'static>>,
|
pub for_in_iters: Vec<*mut ForInIter>,
|
||||||
pub for_of_iters: Vec<ForOfEntry>,
|
pub for_of_iters: Vec<ForOfEntry>,
|
||||||
/// `yield*` 委托中的内层迭代器;异步函数恒为 None。
|
/// `yield*` 委托中的内层迭代器;异步函数恒为 None。
|
||||||
pub delegated_iterator: Option<JsValue>,
|
pub delegated_iterator: Option<JsValue>,
|
||||||
@@ -235,7 +235,7 @@ impl SuspendedFrame {
|
|||||||
if iter.is_null() {
|
if iter.is_null() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// SAFETY: for_in_iters 存放由当前 VM epoch 拥有的存活迭代器指针。
|
// SAFETY: for_in_iters 存放堆上迭代器体,状态盒独占持有。
|
||||||
for (v, _si) in unsafe { (*(*iter)).keys.iter() } {
|
for (v, _si) in unsafe { (*(*iter)).keys.iter() } {
|
||||||
f(*v);
|
f(*v);
|
||||||
}
|
}
|
||||||
@@ -316,7 +316,7 @@ impl SuspendedFrame {
|
|||||||
if iter.is_null() {
|
if iter.is_null() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// SAFETY: for_in_iters 存放由当前 VM epoch 拥有的存活迭代器指针。
|
// SAFETY: for_in_iters 存放堆上迭代器体,状态盒独占持有。
|
||||||
for (v, _si) in unsafe { (*(*iter)).keys.iter_mut() } {
|
for (v, _si) in unsafe { (*(*iter)).keys.iter_mut() } {
|
||||||
*v = rewrite(*v);
|
*v = rewrite(*v);
|
||||||
}
|
}
|
||||||
@@ -362,7 +362,18 @@ impl SuspendedFrame {
|
|||||||
save_stack: self.save_stack.iter().copied().map(&mut rewrite).collect(),
|
save_stack: self.save_stack.iter().copied().map(&mut rewrite).collect(),
|
||||||
cell_stack: self.cell_stack.clone(),
|
cell_stack: self.cell_stack.clone(),
|
||||||
try_stack: self.try_stack.clone(),
|
try_stack: self.try_stack.clone(),
|
||||||
for_in_iters: self.for_in_iters.clone(),
|
for_in_iters: self.for_in_iters.iter().map(|&iter| {
|
||||||
|
if iter.is_null() {
|
||||||
|
return iter;
|
||||||
|
}
|
||||||
|
// SAFETY: 指针是堆上迭代器体,原件状态盒独占持有;克隆新建
|
||||||
|
// 独立体,原件与克隆各持自有体,恰好各释放一次。
|
||||||
|
let body = unsafe { &*iter };
|
||||||
|
Box::into_raw(Box::new(ForInIter {
|
||||||
|
keys: body.keys.iter().map(|(v, si)| (rewrite(*v), *si)).collect(),
|
||||||
|
index: body.index,
|
||||||
|
}))
|
||||||
|
}).collect(),
|
||||||
for_of_iters: self
|
for_of_iters: self
|
||||||
.for_of_iters
|
.for_of_iters
|
||||||
.iter()
|
.iter()
|
||||||
@@ -425,6 +436,23 @@ impl SuspendedFrame {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Drop for SuspendedFrame {
|
||||||
|
/// 释放状态盒持有的 for-in 迭代器体:体是堆上 `Box`,每个状态盒独占
|
||||||
|
/// 持有自身体,随状态盒释放逐条释放(null 跳过)。restore 已把向量
|
||||||
|
/// 移出时字段为空,Drop 不再触碰,无双放。
|
||||||
|
fn drop(&mut self) {
|
||||||
|
for iter in self.for_in_iters.drain(..) {
|
||||||
|
if iter.is_null() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// SAFETY: 指针是堆上迭代器体,状态盒独占持有,释放恰好一次。
|
||||||
|
unsafe {
|
||||||
|
drop(Box::from_raw(iter));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|||||||
@@ -87,11 +87,13 @@ pub struct CallFrame {
|
|||||||
|
|
||||||
/// 一次 `for-in` 迭代的游标:已收集的 key 列表与当前下标。
|
/// 一次 `for-in` 迭代的游标:已收集的 key 列表与当前下标。
|
||||||
///
|
///
|
||||||
|
/// 体是堆上 `Box`:迭代器表与挂起状态盒各独占持有体,出表/状态盒释放时
|
||||||
|
/// 逐条释放。
|
||||||
/// 每个 key 与它的 intern id 配对保存,使整型下标 key 无需重新 intern 即可排到字符串 key 之前。
|
/// 每个 key 与它的 intern id 配对保存,使整型下标 key 无需重新 intern 即可排到字符串 key 之前。
|
||||||
pub struct ForInIter<'bump> {
|
pub struct ForInIter {
|
||||||
/// 每个 key 与其字符串 intern id 配对,使 for-in 排序时整型下标 key 无需
|
/// 每个 key 与其字符串 intern id 配对,使 for-in 排序时整型下标 key 无需
|
||||||
/// 重新 intern 即可排到字符串 key 之前。
|
/// 重新 intern 即可排到字符串 key 之前。
|
||||||
pub keys: bumpalo::collections::Vec<'bump, (JsValue, u32)>,
|
pub keys: Vec<(JsValue, u32)>,
|
||||||
pub index: usize,
|
pub index: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ impl Vm {
|
|||||||
if iter.is_null() {
|
if iter.is_null() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// SAFETY: for_in_iters 存放由当前 VM epoch 拥有的存活迭代器指针。
|
// SAFETY: for_in_iters 存放堆上迭代器体,VM 表独占持有。
|
||||||
unsafe {
|
unsafe {
|
||||||
for (v, _si) in (*(*iter)).keys.iter() {
|
for (v, _si) in (*(*iter)).keys.iter() {
|
||||||
f(*v);
|
f(*v);
|
||||||
@@ -200,7 +200,7 @@ impl Vm {
|
|||||||
if iter.is_null() {
|
if iter.is_null() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// SAFETY: for_in_iters 存放由当前 VM epoch 拥有的存活迭代器指针。
|
// SAFETY: for_in_iters 存放堆上迭代器体,VM 表独占持有。
|
||||||
unsafe {
|
unsafe {
|
||||||
for (v, _si) in (*(*iter)).keys.iter_mut() {
|
for (v, _si) in (*(*iter)).keys.iter_mut() {
|
||||||
*v = rewrite(*v);
|
*v = rewrite(*v);
|
||||||
@@ -242,13 +242,13 @@ impl Vm {
|
|||||||
/// 门控子句二:三型状态盒(生成器/异步函数/异步生成器)的
|
/// 门控子句二:三型状态盒(生成器/异步函数/异步生成器)的
|
||||||
/// `suspended.for_in_iters` 是否非空。
|
/// `suspended.for_in_iters` 是否非空。
|
||||||
///
|
///
|
||||||
/// ForInIter body 分配于 epoch arena,收集换新 Bump 即时失效在表迭代器;
|
/// 门控是保守门:for-in 迭代器活跃/挂起期间拦下执行期收集;
|
||||||
/// 挂起帧把迭代器搬入状态盒(`vm.iters` 不可见),故须逐状态盒扫描。
|
/// 挂起帧把迭代器搬入状态盒(`vm.iters` 不可见),故须逐状态盒扫描。
|
||||||
///
|
///
|
||||||
/// # 边界与前提
|
/// # 边界与前提
|
||||||
/// - 扫描 epoch + session 两份对象表——挂起状态盒宿主对象可能尚未晋升;
|
/// - 扫描 epoch + session 两份对象表——挂起状态盒宿主对象可能尚未晋升;
|
||||||
/// - 挂起帧的 keys 经状态盒边收为 GC 根(被枚举对象不误释放),悬的是
|
/// - 挂起帧的 keys 经状态盒边收为 GC 根(被枚举对象不误释放),迭代器
|
||||||
/// 迭代器 body,故按指针扫 `for_in_iters`;
|
/// 体是堆上 Box,故按指针扫 `for_in_iters`;
|
||||||
/// - 保守口径:死对象的状态盒同样计入(持挂起 for-in 的 run 放弃执行期
|
/// - 保守口径:死对象的状态盒同样计入(持挂起 for-in 的 run 放弃执行期
|
||||||
/// 收集),正确性优先于收益;
|
/// 收集),正确性优先于收益;
|
||||||
/// - 新增挂起态持有者须在此登记。
|
/// - 新增挂起态持有者须在此登记。
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ pub(crate) struct InlineSyncState {
|
|||||||
pub(crate) pending_exception: Option<JsValue>,
|
pub(crate) pending_exception: Option<JsValue>,
|
||||||
pub(crate) pending_error_kind: Option<&'static str>,
|
pub(crate) pending_error_kind: Option<&'static str>,
|
||||||
pub(crate) pending_completion: Option<Completion>,
|
pub(crate) pending_completion: Option<Completion>,
|
||||||
pub(crate) for_in_iters: Vec<*mut ForInIter<'static>>,
|
pub(crate) for_in_iters: Vec<*mut ForInIter>,
|
||||||
pub(crate) for_of_iters: Vec<ForOfEntry>,
|
pub(crate) for_of_iters: Vec<ForOfEntry>,
|
||||||
pub(crate) saved_bytecode_stack: Vec<Arc<[opcode::Instr]>>,
|
pub(crate) saved_bytecode_stack: Vec<Arc<[opcode::Instr]>>,
|
||||||
pub(crate) saved_immutables_stack: Vec<*const [JsValue]>,
|
pub(crate) saved_immutables_stack: Vec<*const [JsValue]>,
|
||||||
@@ -62,3 +62,20 @@ pub(crate) struct InlineSyncState {
|
|||||||
pub(crate) active_flat_id: u32,
|
pub(crate) active_flat_id: u32,
|
||||||
pub(crate) active_table_gen: u32,
|
pub(crate) active_table_gen: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Drop for InlineSyncState {
|
||||||
|
/// 释放快照持有的 for-in 迭代器体:体是堆上 `Box`,快照独占持有自身体,
|
||||||
|
/// drop 时逐条释放(null 跳过)。restore 是字段直移,移出后字段为空,
|
||||||
|
/// Drop 不再触碰,无双放。
|
||||||
|
fn drop(&mut self) {
|
||||||
|
for iter in self.for_in_iters.drain(..) {
|
||||||
|
if iter.is_null() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// SAFETY: 指针是堆上迭代器体,快照独占持有,释放恰好一次。
|
||||||
|
unsafe {
|
||||||
|
drop(Box::from_raw(iter));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -464,10 +464,8 @@ impl Vm {
|
|||||||
let mut obj_val = self.regs[a];
|
let mut obj_val = self.regs[a];
|
||||||
if obj_val.is_null() || obj_val.is_undefined() {
|
if obj_val.is_null() || obj_val.is_undefined() {
|
||||||
// null/undefined 枚举不到任何键——是空 for-in,而非 TypeError。
|
// null/undefined 枚举不到任何键——是空 for-in,而非 TypeError。
|
||||||
let keys_vec: bumpalo::collections::Vec<(JsValue, u32)> =
|
let iter = Box::into_raw(Box::new(ForInIter { keys: Vec::new(), index: 0 }));
|
||||||
bumpalo::collections::Vec::new_in(self.epoch.bump());
|
self.iters.push_for_in(iter);
|
||||||
let iter = self.epoch.alloc(ForInIter { keys: keys_vec, index: 0 });
|
|
||||||
self.iters.push_for_in(iter.cast::<ForInIter<'static>>());
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
if !obj_val.is_object() {
|
if !obj_val.is_object() {
|
||||||
@@ -595,12 +593,10 @@ impl Vm {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// std Vec 建完后迁入 bump 区,避免枚举循环期间对 self 的 &mut 借用
|
// std Vec 直接作为迭代器体;体是堆上 Box,生命周期随迭代器表与
|
||||||
// 与 bump 借用冲突。
|
// 挂起状态盒,出表/状态盒释放时逐条释放。
|
||||||
let keys_bump: bumpalo::collections::Vec<(JsValue, u32)> =
|
let iter = Box::into_raw(Box::new(ForInIter { keys: keys_vec, index: 0 }));
|
||||||
bumpalo::collections::Vec::from_iter_in(keys_vec, self.epoch.bump());
|
self.iters.push_for_in(iter);
|
||||||
let iter = self.epoch.alloc(ForInIter { keys: keys_bump, index: 0 });
|
|
||||||
self.iters.push_for_in(iter.cast::<ForInIter<'static>>());
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -146,7 +146,7 @@ macro_rules! inline_save_field {
|
|||||||
macro_rules! inline_restore_field {
|
macro_rules! inline_restore_field {
|
||||||
($recv:ident, $saved:ident, regs, boxed_window) => {
|
($recv:ident, $saved:ident, regs, boxed_window) => {
|
||||||
$recv.regs[..$saved.regs.len()].copy_from_slice(&$saved.regs);
|
$recv.regs[..$saved.regs.len()].copy_from_slice(&$saved.regs);
|
||||||
$recv.inline_reg_pool = Some($saved.regs.into_vec());
|
$recv.inline_reg_pool = Some(std::mem::take(&mut $saved.regs).into_vec());
|
||||||
};
|
};
|
||||||
($recv:ident, $saved:ident, saved_this, copy) => {
|
($recv:ident, $saved:ident, saved_this, copy) => {
|
||||||
$recv.regs[254] = $saved.saved_this
|
$recv.regs[254] = $saved.saved_this
|
||||||
@@ -158,7 +158,7 @@ macro_rules! inline_restore_field {
|
|||||||
$recv.pc = $saved.pc
|
$recv.pc = $saved.pc
|
||||||
};
|
};
|
||||||
($recv:ident, $saved:ident, bytecode, move_field) => {
|
($recv:ident, $saved:ident, bytecode, move_field) => {
|
||||||
$recv.bytecode = $saved.bytecode
|
$recv.bytecode = std::mem::take(&mut $saved.bytecode)
|
||||||
};
|
};
|
||||||
($recv:ident, $saved:ident, active_immutables, copy) => {
|
($recv:ident, $saved:ident, active_immutables, copy) => {
|
||||||
$recv.active_immutables = $saved.active_immutables
|
$recv.active_immutables = $saved.active_immutables
|
||||||
@@ -170,10 +170,10 @@ macro_rules! inline_restore_field {
|
|||||||
$recv.root_reg_limit = $saved.root_reg_limit
|
$recv.root_reg_limit = $saved.root_reg_limit
|
||||||
};
|
};
|
||||||
($recv:ident, $saved:ident, try_stack, move_field) => {
|
($recv:ident, $saved:ident, try_stack, move_field) => {
|
||||||
$recv.try_stack = $saved.try_stack
|
$recv.try_stack = std::mem::take(&mut $saved.try_stack)
|
||||||
};
|
};
|
||||||
($recv:ident, $saved:ident, frames, frames_values) => {
|
($recv:ident, $saved:ident, frames, frames_values) => {
|
||||||
$recv.frames = $saved.frames
|
$recv.frames = std::mem::take(&mut $saved.frames)
|
||||||
};
|
};
|
||||||
($recv:ident, $saved:ident, exception_value, opt_take) => {
|
($recv:ident, $saved:ident, exception_value, opt_take) => {
|
||||||
$recv.exception_value = $saved.exception_value
|
$recv.exception_value = $saved.exception_value
|
||||||
@@ -188,25 +188,25 @@ macro_rules! inline_restore_field {
|
|||||||
$recv.pending_completion = $saved.pending_completion
|
$recv.pending_completion = $saved.pending_completion
|
||||||
};
|
};
|
||||||
($recv:ident, $saved:ident, for_in_iters, for_in_keys) => {
|
($recv:ident, $saved:ident, for_in_iters, for_in_keys) => {
|
||||||
$recv.iters.for_in_iters = $saved.for_in_iters
|
$recv.iters.for_in_iters = std::mem::take(&mut $saved.for_in_iters)
|
||||||
};
|
};
|
||||||
($recv:ident, $saved:ident, for_of_iters, iter_take) => {
|
($recv:ident, $saved:ident, for_of_iters, iter_take) => {
|
||||||
$recv.iters.for_of_iters = $saved.for_of_iters
|
$recv.iters.for_of_iters = std::mem::take(&mut $saved.for_of_iters)
|
||||||
};
|
};
|
||||||
($recv:ident, $saved:ident, saved_bytecode_stack, move_field) => {
|
($recv:ident, $saved:ident, saved_bytecode_stack, move_field) => {
|
||||||
$recv.saved_bytecode_stack = $saved.saved_bytecode_stack
|
$recv.saved_bytecode_stack = std::mem::take(&mut $saved.saved_bytecode_stack)
|
||||||
};
|
};
|
||||||
($recv:ident, $saved:ident, saved_immutables_stack, move_field) => {
|
($recv:ident, $saved:ident, saved_immutables_stack, move_field) => {
|
||||||
$recv.saved_immutables_stack = $saved.saved_immutables_stack
|
$recv.saved_immutables_stack = std::mem::take(&mut $saved.saved_immutables_stack)
|
||||||
};
|
};
|
||||||
($recv:ident, $saved:ident, save_stack, move_field) => {
|
($recv:ident, $saved:ident, save_stack, move_field) => {
|
||||||
$recv.save_stack = $saved.save_stack
|
$recv.save_stack = std::mem::take(&mut $saved.save_stack)
|
||||||
};
|
};
|
||||||
($recv:ident, $saved:ident, spill_stack, move_field) => {
|
($recv:ident, $saved:ident, spill_stack, move_field) => {
|
||||||
$recv.spill_stack = $saved.spill_stack
|
$recv.spill_stack = std::mem::take(&mut $saved.spill_stack)
|
||||||
};
|
};
|
||||||
($recv:ident, $saved:ident, cell_stack, move_field) => {
|
($recv:ident, $saved:ident, cell_stack, move_field) => {
|
||||||
$recv.cell_stack = $saved.cell_stack
|
$recv.cell_stack = std::mem::take(&mut $saved.cell_stack)
|
||||||
};
|
};
|
||||||
($recv:ident, $saved:ident, inline_callee, opt_copy) => {
|
($recv:ident, $saved:ident, inline_callee, opt_copy) => {
|
||||||
$recv.inline_callee = $saved.inline_callee
|
$recv.inline_callee = $saved.inline_callee
|
||||||
@@ -336,7 +336,7 @@ impl Vm {
|
|||||||
|
|
||||||
/// 把 [`save_inline_state`] 保存的状态恢复回 VM。窗口回拷 + `regs[254]/[255]`
|
/// 把 [`save_inline_state`] 保存的状态恢复回 VM。窗口回拷 + `regs[254]/[255]`
|
||||||
/// 单回,窗口外寄存器 callee 未触碰无需恢复。
|
/// 单回,窗口外寄存器 callee 未触碰无需恢复。
|
||||||
pub(crate) fn restore_inline_state(&mut self, saved: Box<InlineSyncState>) {
|
pub(crate) fn restore_inline_state(&mut self, mut saved: Box<InlineSyncState>) {
|
||||||
vm_trace!("restore_inline_state: pc={}", saved.pc);
|
vm_trace!("restore_inline_state: pc={}", saved.pc);
|
||||||
// 固化不变量:内联 state-swap 边界不携带在途异步逃出(与 save 侧同)。
|
// 固化不变量:内联 state-swap 边界不携带在途异步逃出(与 save 侧同)。
|
||||||
debug_assert!(self.pending_async_escape.is_none());
|
debug_assert!(self.pending_async_escape.is_none());
|
||||||
@@ -363,8 +363,7 @@ impl Vm {
|
|||||||
self.active_reg_limit = 1;
|
self.active_reg_limit = 1;
|
||||||
self.root_reg_limit = 1;
|
self.root_reg_limit = 1;
|
||||||
self.try_stack.clear();
|
self.try_stack.clear();
|
||||||
self.iters.for_in_iters.clear();
|
self.iters.reset();
|
||||||
self.iters.for_of_iters.clear();
|
|
||||||
self.spill_stack.clear();
|
self.spill_stack.clear();
|
||||||
self.save_stack.clear();
|
self.save_stack.clear();
|
||||||
self.saved_bytecode_stack.clear();
|
self.saved_bytecode_stack.clear();
|
||||||
|
|||||||
@@ -175,25 +175,41 @@ pub(crate) struct ForOfEntry {
|
|||||||
|
|
||||||
/// for-in / for-of 的活跃迭代器状态。
|
/// for-in / for-of 的活跃迭代器状态。
|
||||||
pub(crate) struct IterState {
|
pub(crate) struct IterState {
|
||||||
pub(crate) for_in_iters: Vec<*mut ForInIter<'static>>,
|
pub(crate) for_in_iters: Vec<*mut ForInIter>,
|
||||||
pub(crate) for_of_iters: Vec<ForOfEntry>,
|
pub(crate) for_of_iters: Vec<ForOfEntry>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IterState {
|
impl IterState {
|
||||||
pub(crate) fn reset(&mut self) {
|
pub(crate) fn reset(&mut self) {
|
||||||
self.for_in_iters.clear();
|
for iter in self.for_in_iters.drain(..) {
|
||||||
|
if iter.is_null() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// SAFETY: 指针是堆上迭代器体,表独占持有,清表释放恰好一次。
|
||||||
|
unsafe {
|
||||||
|
drop(Box::from_raw(iter));
|
||||||
|
}
|
||||||
|
}
|
||||||
self.for_of_iters.clear();
|
self.for_of_iters.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn push_for_in(&mut self, iter: *mut ForInIter<'static>) {
|
pub(crate) fn push_for_in(&mut self, iter: *mut ForInIter) {
|
||||||
self.for_in_iters.push(iter);
|
self.for_in_iters.push(iter);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn pop_for_in(&mut self) {
|
pub(crate) fn pop_for_in(&mut self) {
|
||||||
self.for_in_iters.pop();
|
if let Some(iter) = self.for_in_iters.pop() {
|
||||||
|
if iter.is_null() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// SAFETY: 指针是堆上迭代器体,表独占持有,出表释放恰好一次。
|
||||||
|
unsafe {
|
||||||
|
drop(Box::from_raw(iter));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn last_for_in(&self) -> *mut ForInIter<'static> {
|
pub(crate) fn last_for_in(&self) -> *mut ForInIter {
|
||||||
self.for_in_iters.last().copied().unwrap_or(std::ptr::null_mut())
|
self.for_in_iters.last().copied().unwrap_or(std::ptr::null_mut())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -428,6 +428,9 @@ impl Vm {
|
|||||||
/// 重置,本函数只释放手工管理的 Box 指针(属性向量、各原生盒、串、BigInt、cell)。
|
/// 重置,本函数只释放手工管理的 Box 指针(属性向量、各原生盒、串、BigInt、cell)。
|
||||||
/// 原生盒在 GC 搬移/晋升时已深拷贝为单所有权,此处恰好释放一次。
|
/// 原生盒在 GC 搬移/晋升时已深拷贝为单所有权,此处恰好释放一次。
|
||||||
pub(crate) fn teardown_session_heap_data(&mut self) {
|
pub(crate) fn teardown_session_heap_data(&mut self) {
|
||||||
|
// 迭代器体是堆上 Box:收尾路径(full_reset 与 Drop 共用)逐条释放,
|
||||||
|
// 防 Vm 直接 drop 时表内残留体泄漏。
|
||||||
|
self.iters.reset();
|
||||||
// upvalue 列表先于对象表清空释放:去重枚举依赖两份对象表尚存。
|
// upvalue 列表先于对象表清空释放:去重枚举依赖两份对象表尚存。
|
||||||
self.free_session_upvalues();
|
self.free_session_upvalues();
|
||||||
self.free_epoch_object_heap_data();
|
self.free_epoch_object_heap_data();
|
||||||
|
|||||||
@@ -847,9 +847,10 @@ fn reset_clears_runtime_state_like_rerun() {
|
|||||||
upvalues: std::ptr::slice_from_raw_parts(std::ptr::null(), 0),
|
upvalues: std::ptr::slice_from_raw_parts(std::ptr::null(), 0),
|
||||||
});
|
});
|
||||||
vm.save_stack.push(JsValue::undefined());
|
vm.save_stack.push(JsValue::undefined());
|
||||||
vm.iters
|
vm.iters.for_in_iters.push(Box::into_raw(Box::new(crate::vm::ForInIter {
|
||||||
.for_in_iters
|
keys: Vec::new(),
|
||||||
.push(std::ptr::dangling_mut::<crate::vm::ForInIter<'static>>());
|
index: 0,
|
||||||
|
})));
|
||||||
vm.iters.for_of_iters.push(crate::vm_state::ForOfEntry {
|
vm.iters.for_of_iters.push(crate::vm_state::ForOfEntry {
|
||||||
iterator: JsValue::undefined(),
|
iterator: JsValue::undefined(),
|
||||||
last_result: JsValue::undefined(),
|
last_result: JsValue::undefined(),
|
||||||
|
|||||||
Reference in New Issue
Block a user