feat: run 装载期对共享模块字节码显式复制,COW 深拷贝移出热路径

This commit is contained in:
2026-10-09 09:07:20 +00:00
parent f5766c4679
commit 582475363b
4 changed files with 49 additions and 23 deletions
Generated
+19 -19
View File
@@ -1160,7 +1160,7 @@ dependencies = [
[[package]]
name = "oxide_builtins"
version = "0.8.94"
version = "0.8.95"
dependencies = [
"chrono",
"fast-float",
@@ -1185,7 +1185,7 @@ dependencies = [
[[package]]
name = "oxide_bytecode"
version = "0.8.94"
version = "0.8.95"
dependencies = [
"num-bigint",
"oxide_log",
@@ -1193,7 +1193,7 @@ dependencies = [
[[package]]
name = "oxide_cfg"
version = "0.8.94"
version = "0.8.95"
dependencies = [
"oxide_bytecode",
"oxide_emit",
@@ -1204,7 +1204,7 @@ dependencies = [
[[package]]
name = "oxide_cli"
version = "0.8.94"
version = "0.8.95"
dependencies = [
"ansi_term",
"bumpalo",
@@ -1226,7 +1226,7 @@ dependencies = [
[[package]]
name = "oxide_code_cache"
version = "0.8.94"
version = "0.8.95"
dependencies = [
"lru",
"oxide_bytecode",
@@ -1235,7 +1235,7 @@ dependencies = [
[[package]]
name = "oxide_compiler"
version = "0.8.94"
version = "0.8.95"
dependencies = [
"oxide_bytecode",
"oxide_cfg",
@@ -1255,7 +1255,7 @@ dependencies = [
[[package]]
name = "oxide_dce"
version = "0.8.94"
version = "0.8.95"
dependencies = [
"oxide_bytecode",
"oxide_cfg",
@@ -1269,7 +1269,7 @@ dependencies = [
[[package]]
name = "oxide_emit"
version = "0.8.94"
version = "0.8.95"
dependencies = [
"num-bigint",
"oxc_allocator",
@@ -1284,7 +1284,7 @@ dependencies = [
[[package]]
name = "oxide_engine"
version = "0.8.94"
version = "0.8.95"
dependencies = [
"oxide_bytecode",
"oxide_compiler",
@@ -1296,7 +1296,7 @@ dependencies = [
[[package]]
name = "oxide_ir"
version = "0.8.94"
version = "0.8.95"
dependencies = [
"oxide_bytecode",
"oxide_log",
@@ -1305,7 +1305,7 @@ dependencies = [
[[package]]
name = "oxide_kernel"
version = "0.8.94"
version = "0.8.95"
dependencies = [
"bumpalo",
"dashmap",
@@ -1319,7 +1319,7 @@ dependencies = [
[[package]]
name = "oxide_liveness"
version = "0.8.94"
version = "0.8.95"
dependencies = [
"oxide_bytecode",
"oxide_cfg",
@@ -1331,7 +1331,7 @@ dependencies = [
[[package]]
name = "oxide_log"
version = "0.8.94"
version = "0.8.95"
dependencies = [
"tracing",
"tracing-appender",
@@ -1340,7 +1340,7 @@ dependencies = [
[[package]]
name = "oxide_parser"
version = "0.8.94"
version = "0.8.95"
dependencies = [
"oxc_allocator",
"oxc_ast",
@@ -1355,7 +1355,7 @@ dependencies = [
[[package]]
name = "oxide_regalloc"
version = "0.8.94"
version = "0.8.95"
dependencies = [
"oxide_bytecode",
"oxide_cfg",
@@ -1371,7 +1371,7 @@ dependencies = [
[[package]]
name = "oxide_runtime_api"
version = "0.8.94"
version = "0.8.95"
dependencies = [
"num-bigint",
"num-traits",
@@ -1384,7 +1384,7 @@ dependencies = [
[[package]]
name = "oxide_test262"
version = "0.8.94"
version = "0.8.95"
dependencies = [
"oxide_bytecode",
"oxide_compiler",
@@ -1402,7 +1402,7 @@ dependencies = [
[[package]]
name = "oxide_types"
version = "0.8.94"
version = "0.8.95"
dependencies = [
"bumpalo",
"dashmap",
@@ -1415,7 +1415,7 @@ dependencies = [
[[package]]
name = "oxide_vm"
version = "0.8.94"
version = "0.8.95"
dependencies = [
"bumpalo",
"chrono",
+1 -1
View File
@@ -23,7 +23,7 @@ members = [
]
[workspace.package]
version = "0.8.94"
version = "0.8.95"
edition = "2021"
license = "MIT"
rust-version = "1.80"
+2 -1
View File
@@ -168,7 +168,8 @@ pub struct Vm {
pub(crate) regs: [JsValue; 256],
pub(crate) pc: usize,
/// 当前活动字节码。以 `Arc<[Instr]>` 共享:函数调用经 `Arc::clone` 换帧(O(1)),
/// 不再逐帧深拷贝。与子模块平表源共享同一缓冲,IC 写回经 `bytecode_mut` 的
/// 不再逐帧深拷贝。顶层装载期按引用计数条件复制(共享时显式深拷贝,独占时
/// 零拷贝),子模块平表源保持惰性 COW,IC 写回经 `bytecode_mut` 的
/// `Arc::make_mut` 写时复制,保证独占后才改写(miss 时才深拷贝,频率低)。
pub(crate) bytecode: Arc<[opcode::Instr]>,
/// 当前活动模块已转换不可变常量的只读视图(指向当前表代际的 immutables 内部)。
+27 -2
View File
@@ -664,7 +664,8 @@ impl Vm {
/// 加载并执行一个已编译模块,返回模块顶层执行结果或未捕获异常消息。
///
/// 模块以 `Arc` 与调用方共享(如 CodeForge 缓存条目):平表装载只做
/// Arc::clone,run 期零模块拷贝。内部初始化寄存器/bytecode/immutables 与
/// Arc::clone,顶层字节码按引用计数条件复制(共享时装载期显式深拷贝,
/// 独占时零拷贝)。内部初始化寄存器/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());
@@ -696,7 +697,15 @@ impl Vm {
self.active_table_gen = self.current_gen;
// 顶层脚本严格模式:无帧且无 inline 时写路径的 strict/sloppy 判定来源。
self.top_level_strict = module.is_strict;
self.bytecode = Arc::clone(&module.bytecode);
// 顶层字节码按模块引用计数条件复制:模块被宿主共享(外层 Arc 计数 > 1,
// 如 CodeForge 缓存条目与调用方各持一份)时装载期显式深拷贝,把 COW 深拷贝
// 从 dispatch 主循环热路径挪到 run 装载期(批量、可预测);模块独占(计数 1,
// 如 worker 新编译模块)保持 Arc::clone,无宿主共享缓冲需保护,复制无收益。
if Arc::strong_count(module) > 1 {
self.bytecode = Arc::from(&module.bytecode[..]);
} else {
self.bytecode = Arc::clone(&module.bytecode);
}
self.activate_immutables(self.current_gen, 0, &module.constants);
self.root_reg_limit = module.n_registers.max(1);
self.active_reg_limit = self.root_reg_limit;
@@ -933,6 +942,22 @@ mod tests {
assert_eq!(vm.bytecode.len(), module.bytecode.len());
}
#[test]
fn run_copies_bytecode_when_shared() {
// 顶层字节码装载期显式副本:共享模块(引用计数 > 1)在 run 装载期即深拷贝,
// 即使零 IC miss(无写回触发惰性 COW)Vm.bytecode 也须是私有 Arc 实例。
// 本钉在惰性 COW 行为下必失败(无写回则不拷贝,保持与宿主同一实例)。
let mut vm = Vm::new();
let module = Arc::new(compile("var x = 1; x + 1"));
let shared = Arc::clone(&module); // 双 Arc 计数,模拟宿主缓存共享
vm.run(&shared).expect("run");
assert!(
!Arc::ptr_eq(&module.bytecode, &vm.bytecode),
"共享模块装载期须显式复制,Vm.bytecode 不得与宿主共享同一 Arc"
);
assert_eq!(vm.bytecode.len(), module.bytecode.len());
}
#[test]
fn save_restore_inline_round_trip() {
// 构造带哨兵的 VM → save → 恢复 → 断言全部字段逐字往返(含 accessor_frame_target_reg)。