perf: 子模块树改 Arc 共享,run() 免深拷贝模块树

This commit is contained in:
爱特每羊队
2026-08-10 16:26:57 +08:00
parent cd96fa6fcb
commit c90c610e15
6 changed files with 25 additions and 17 deletions
+1 -1
View File
@@ -112,7 +112,7 @@ impl SuspendedFrame {
/// # 边界
/// `sub_idx >= sub_modules.len()`(挂起状态跨 run)返回 Err,调用方须按各自
/// 路径回滚并报错(保持现有三处行为)。
pub fn restore_into(&mut self, vm: &mut Vm, sub_modules: &Arc<Vec<CompiledModule>>) -> Result<(), String> {
pub fn restore_into(&mut self, vm: &mut Vm, sub_modules: &Arc<Vec<Arc<CompiledModule>>>) -> Result<(), String> {
vm.regs = *self.regs;
vm.pc = self.pc;
vm.bytecode = std::mem::take(&mut self.bytecode);
+5 -3
View File
@@ -269,7 +269,9 @@ pub struct Vm {
pub math_rng_state: u64,
/// 全局扁平模块表:下标 = 模块 `flat_id`(顶层 0,子模块 flatten 后全局唯一)。
/// 闭包 `sub_module_index` 即 flat_id,逃逸闭包也能自足解析。
pub(crate) sub_modules: Arc<Vec<CompiledModule>>,
/// 条目为 `Arc<CompiledModule>`,与调用方模块树共享(`run()` 只做 Arc::clone,
/// 不再每次深拷贝整棵子树)。
pub(crate) sub_modules: Arc<Vec<Arc<CompiledModule>>>,
/// 帧切换时暂存调用方字节码的 Arc 栈(与 `bytecode` 同共享语义)。
pub(crate) saved_bytecode_stack: Vec<Arc<[opcode::Instr]>>,
pub(crate) saved_immutables_stack: Vec<*const [JsValue]>,
@@ -1911,7 +1913,7 @@ impl Vm {
/// 把 flatten 后的子模块子树重编号到平表偏移 `base`:DFS 前序拷贝进 `out`,
/// 新 flat_id = base + (old - 1),子树内每条 `CREATE_CLOSURE` 的 imm16 同步重写。
/// 原子树 flat_id 自 1 连续,因此拷贝顺序即新 id 顺序,`out` 下标对齐平表槽位。
fn rehome_subtree(module: &CompiledModule, base: u32, out: &mut Vec<CompiledModule>) {
fn rehome_subtree(module: &CompiledModule, base: u32, out: &mut Vec<Arc<CompiledModule>>) {
let new_id = base + module.flat_id - 1;
let mut bytecode = module.bytecode.to_vec();
for instr in &mut bytecode {
@@ -1929,7 +1931,7 @@ fn rehome_subtree(module: &CompiledModule, base: u32, out: &mut Vec<CompiledModu
let mut rehomed = module.clone();
rehomed.bytecode = Arc::from(bytecode);
rehomed.flat_id = new_id;
out.push(rehomed);
out.push(Arc::new(rehomed));
for sub in &module.sub_modules {
rehome_subtree(sub, base, out);
}
+10 -5
View File
@@ -8,18 +8,23 @@ use oxide_types::object::JsObject;
use oxide_types::value::JsValue;
/// 按 `flat_id` 下标收集整棵子模块树为平表,供 `run()` 装载。
fn collect_flat_modules(module: &CompiledModule) -> Vec<CompiledModule> {
let mut out: Vec<Option<CompiledModule>> = Vec::new();
place_flat(module, &mut out);
///
/// 子模块节点以 `Arc` 与调用方模块树共享:只做 Arc::clone(O(1) 引用计数),
/// 不再深拷贝 constants/upvalue_captures 等。顶层模块本身以浅拷贝包 Arc——
/// 其自有 constants 仍逐 run 复制,但整棵子树零深拷贝。
fn collect_flat_modules(module: &CompiledModule) -> Vec<Arc<CompiledModule>> {
let mut out: Vec<Option<Arc<CompiledModule>>> = Vec::new();
let top = Arc::new(module.clone());
place_flat(&top, &mut out);
out.into_iter().map(|m| m.expect("flat_id slot must be filled")).collect()
}
fn place_flat(module: &CompiledModule, out: &mut Vec<Option<CompiledModule>>) {
fn place_flat(module: &Arc<CompiledModule>, out: &mut Vec<Option<Arc<CompiledModule>>>) {
let idx = module.flat_id as usize;
if idx >= out.len() {
out.resize(idx + 1, None);
}
out[idx] = Some(module.clone());
out[idx] = Some(Arc::clone(module));
for sub in &module.sub_modules {
place_flat(sub, out);
}