perf: run 签名改 &Arc<CompiledModule>,顶层模块跨 run 共享——collect_flat_modules 顶层改 Arc::clone 消除逐 run 常量池深拷贝,全调用点 Arc 包装迁移

This commit is contained in:
2026-09-11 22:19:13 +00:00
parent 542236a15a
commit 3169e8f2f9
106 changed files with 391 additions and 189 deletions
+12 -6
View File
@@ -959,6 +959,8 @@ mod tests {
use oxide_types::object::JsObject;
use oxide_types::value::JsValue;
use std::sync::Arc;
use super::*;
use crate::vm::{CallFrame, FrameContinuation};
use oxide_builtins::{array_buffer, data_view, map, set, typed_array};
@@ -1612,8 +1614,10 @@ mod tests {
#[test]
fn closure_cell_survives_object_sweep() {
let mut vm = vm_with_threshold(1);
vm.run(&compile("var counter = 0; function inc() { return ++counter; } globalThis.inc = inc; 0"))
.expect("run1");
vm.run(&Arc::new(compile(
"var counter = 0; function inc() { return ++counter; } globalThis.inc = inc; 0",
)))
.expect("run1");
assert!(!vm.gc_state.session_cell_ptrs.borrow().is_empty(), "run1 应分配 upvalue cell");
// reset 触发对象 sweep:存活对象搬到新 arena,旧 arena 释放。
@@ -1636,10 +1640,10 @@ mod tests {
#[test]
fn private_brand_cell_survives_object_sweep() {
let mut vm = vm_with_threshold(1);
vm.run(&compile(
vm.run(&Arc::new(compile(
"class C { #x = 0; set(v){ this.#x = v; } get(){ return this.#x; } } \
globalThis.c = new C(); globalThis.c.set(4); 0",
))
)))
.expect("run1");
vm.reset();
@@ -1664,14 +1668,16 @@ mod tests {
#[test]
fn cells_freed_by_full_reset_and_reallocatable() {
let mut vm = Vm::new();
vm.run(&compile("var x = 1; function f() { return x; } globalThis.f = f; f()"))
vm.run(&Arc::new(compile("var x = 1; function f() { return x; } globalThis.f = f; f()")))
.expect("run1");
assert!(!vm.gc_state.session_cell_ptrs.borrow().is_empty());
vm.full_reset();
assert!(vm.gc_state.session_cell_ptrs.borrow().is_empty(), "full_reset 应释放全部 cell");
let result = vm.run(&compile("var y = 2; function g() { return y; } g()")).expect("run2");
let result = vm
.run(&Arc::new(compile("var y = 2; function g() { return y; } g()")))
.expect("run2");
assert_eq!(format!("{result}"), "2", "重置后新 cell 应正常分配与读取");
}
+7 -4
View File
@@ -446,8 +446,8 @@ pub struct Vm {
pub math_rng_state: u64,
/// 全局扁平模块表:下标 = 模块 `flat_id`(顶层 0,子模块 flatten 后全局唯一)。
/// 闭包 `sub_module_index` 即 flat_id,逃逸闭包也能自足解析。
/// 条目为 `Arc<CompiledModule>`,与调用方模块树共享(`run()` 只做 Arc::clone,
/// 不再每次深拷贝整棵子树)。
/// 条目为 `Arc<CompiledModule>`,与调用方模块树共享:顶层条目即调用方模块
/// Arc 同一实例,`run()` 全程只做 Arc::clone,无深拷贝。
pub(crate) sub_modules: Arc<Vec<Arc<CompiledModule>>>,
/// 帧切换时暂存调用方字节码的 Arc 栈(与 `bytecode` 同共享语义)。
pub(crate) saved_bytecode_stack: Vec<Arc<[opcode::Instr]>>,
@@ -2801,7 +2801,8 @@ mod tests {
is_async: false,
});
vm.run(&module).expect("FOR_OF_CLOSE should tolerate non-object sentinel");
vm.run(&Arc::new(module))
.expect("FOR_OF_CLOSE should tolerate non-object sentinel");
assert!(vm.iters.for_of_iters.is_empty());
}
@@ -2854,7 +2855,9 @@ mod tests {
..CompiledModule::new()
};
let mut vm = Vm::new();
let err = vm.run(&module).expect_err("unimplemented opcode should fail explicitly");
let err = vm
.run(&Arc::new(module))
.expect_err("unimplemented opcode should fail explicitly");
assert_eq!(err, "opcode PROFILE_SHAPE not yet implemented");
}
+10 -8
View File
@@ -9,12 +9,13 @@ use oxide_types::value::JsValue;
/// 按 `flat_id` 下标收集整棵子模块树为平表,供 `run()` 装载。
///
/// 子模块节点以 `Arc` 与调用方模块树共享:只做 Arc::clone(O(1) 引用计数),
/// 不再深拷贝 constants/upvalue_captures 等。顶层模块本身以浅拷贝包 Arc——
/// 其自有 constants 仍逐 run 复制,但整棵子树零深拷贝。
fn collect_flat_modules(module: &CompiledModule) -> Vec<Arc<CompiledModule>> {
/// 顶层与子模块一律 `Arc` 共享:只做 Arc::clone(O(1) 引用计数),run 期
/// 零模块拷贝。唯一可写面 = bytecode 缓冲,经 `bytecode_mut` 的 COW 写时
/// 复制——dispatch 期平表与 `Vm.bytecode` 双持(refcount ≥ 2),写必落在
/// 私有拷贝上,宿主侧共享缓冲永不被写。
fn collect_flat_modules(module: &Arc<CompiledModule>) -> Vec<Arc<CompiledModule>> {
let mut out: Vec<Option<Arc<CompiledModule>>> = Vec::new();
let top = Arc::new(module.clone());
let top = Arc::clone(module);
place_flat(&top, &mut out);
out.into_iter().map(|m| m.expect("flat_id slot must be filled")).collect()
}
@@ -518,9 +519,10 @@ impl Vm {
/// 加载并执行一个已编译模块,返回模块顶层执行结果或未捕获异常消息。
///
/// 内部初始化寄存器/bytecode/immutables 与 builtin 寄存器预绑定,然后进入
/// dispatch 主循环;执行完成或异常展开后返回。
pub fn run(&mut self, module: &CompiledModule) -> Result<JsValue, String> {
/// 模块以 `Arc` 与调用方共享(如 CodeForge 缓存条目):平表装载只做
/// Arc::clone,run 期零模块拷贝。内部初始化寄存器/bytecode/immutables 与
/// builtin 寄存器预绑定,然后进入 dispatch 主循环;执行完成或异常展开后返回。
pub fn run(&mut self, module: &Arc<CompiledModule>) -> Result<JsValue, String> {
vm_debug!("run: starting bytecode execution, {} instructions", module.bytecode.len());
self.clear_execution_state();
// 模板对象缓存按 run 清空:flat_id 每次 run 从 0 重新分配,跨 run 复用会
+5 -3
View File
@@ -821,7 +821,7 @@ mod tests {
let module = oxide_compiler::compiler::Compiler::new()
.compile(&program)
.expect("compile failed");
vm.run(&module).expect("vm run failed")
vm.run(&Arc::new(module)).expect("vm run failed")
}
/// 计数往返:两条构造路径(独立核/共享核)的登记与 Drop 注销恰好配对,
@@ -981,7 +981,9 @@ mod tests {
let module = oxide_compiler::compiler::Compiler::new()
.compile(&program)
.expect("compile failed");
let err = vm.run(&module).expect_err("runaway allocation must hit the alloc cap");
let err = vm
.run(&Arc::new(module))
.expect_err("runaway allocation must hit the alloc cap");
assert!(err.contains("memory limit"), "unexpected error: {err}");
assert!(!err.contains("step limit"), "cap 应先于步数上限生效: {err}");
}
@@ -1015,7 +1017,7 @@ mod tests {
let module = oxide_compiler::compiler::Compiler::new()
.compile(&program)
.expect("compile failed");
let err = vm.run(&module).expect_err("reentry pump must hit the alloc cap");
let err = vm.run(&Arc::new(module)).expect_err("reentry pump must hit the alloc cap");
assert!(err.contains("memory limit"), "unexpected error: {err}");
}