mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-25 03:01:12 +08:00
perf: run 签名改 &Arc<CompiledModule>,顶层模块跨 run 共享——collect_flat_modules 顶层改 Arc::clone 消除逐 run 常量池深拷贝,全调用点 Arc 包装迁移
This commit is contained in:
@@ -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 应正常分配与读取");
|
||||
}
|
||||
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
|
||||
@@ -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 复用会
|
||||
|
||||
@@ -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}");
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user