perf: 子模块树改 Arc 共享,run() 免深拷贝模块树
This commit is contained in:
@@ -43,7 +43,7 @@ pub struct UpvalueCapture {
|
|||||||
/// - `bytecode` / `constants` — 指令序列与常量池;
|
/// - `bytecode` / `constants` — 指令序列与常量池;
|
||||||
/// - `n_registers` / `n_args` / `param_base` — 寄存器窗口布局;
|
/// - `n_registers` / `n_args` / `param_base` — 寄存器窗口布局;
|
||||||
/// - `builtin_reg_map` — 内置对象到寄存器的预绑定;
|
/// - `builtin_reg_map` — 内置对象到寄存器的预绑定;
|
||||||
/// - `sub_modules` — 嵌套函数(闭包体)的编译产物;
|
/// - `sub_modules` — 嵌套函数(闭包体)的编译产物(`Arc` 共享,避免每次 run 深拷贝模块树);
|
||||||
/// - `is_arrow` / `captured_this_const_idx` — 箭头函数词法 `this`;
|
/// - `is_arrow` / `captured_this_const_idx` — 箭头函数词法 `this`;
|
||||||
/// - `is_class_constructor` / `is_derived_constructor` / `needs_home_object` — 类相关;
|
/// - `is_class_constructor` / `is_derived_constructor` / `needs_home_object` — 类相关;
|
||||||
/// - `upvalue_captures` / `cells_needed` — 闭包捕获描述。
|
/// - `upvalue_captures` / `cells_needed` — 闭包捕获描述。
|
||||||
@@ -54,7 +54,7 @@ pub struct CompiledModule {
|
|||||||
pub n_args: u8,
|
pub n_args: u8,
|
||||||
pub param_base: u8,
|
pub param_base: u8,
|
||||||
pub builtin_reg_map: Vec<(String, u32)>,
|
pub builtin_reg_map: Vec<(String, u32)>,
|
||||||
pub sub_modules: Vec<CompiledModule>,
|
pub sub_modules: Vec<Arc<CompiledModule>>,
|
||||||
/// 是否为箭头函数体(箭头函数从外围作用域词法捕获 `this`)。
|
/// 是否为箭头函数体(箭头函数从外围作用域词法捕获 `this`)。
|
||||||
pub is_arrow: bool,
|
pub is_arrow: bool,
|
||||||
/// 捕获 `this` 的 JsValue 在常量池中的下标;0 表示未捕获,使用标准 this 绑定。
|
/// 捕获 `this` 的 JsValue 在常量池中的下标;0 表示未捕获,使用标准 this 绑定。
|
||||||
|
|||||||
@@ -19,7 +19,8 @@ pub fn flatten_submodules(module: &mut CompiledModule) {
|
|||||||
|
|
||||||
fn assign_ids(module: &mut CompiledModule, next_id: &mut u32) {
|
fn assign_ids(module: &mut CompiledModule, next_id: &mut u32) {
|
||||||
for sub in &mut module.sub_modules {
|
for sub in &mut module.sub_modules {
|
||||||
sub.flat_id = *next_id;
|
// 子模块以 Arc 共享;flatten 在编译末端跑(refcount 1),make_mut 无拷贝。
|
||||||
|
Arc::make_mut(sub).flat_id = *next_id;
|
||||||
*next_id += 1;
|
*next_id += 1;
|
||||||
}
|
}
|
||||||
for instr in Arc::make_mut(&mut module.bytecode).iter_mut() {
|
for instr in Arc::make_mut(&mut module.bytecode).iter_mut() {
|
||||||
@@ -36,7 +37,7 @@ fn assign_ids(module: &mut CompiledModule, next_id: &mut u32) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
for sub in &mut module.sub_modules {
|
for sub in &mut module.sub_modules {
|
||||||
assign_ids(sub, next_id);
|
assign_ids(Arc::make_mut(sub), next_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,7 +45,7 @@ fn assign_ids(module: &mut CompiledModule, next_id: &mut u32) {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
fn module_with_closure(nested: Vec<CompiledModule>) -> CompiledModule {
|
fn module_with_closure(nested: Vec<Arc<CompiledModule>>) -> CompiledModule {
|
||||||
let mut m = CompiledModule::new();
|
let mut m = CompiledModule::new();
|
||||||
m.sub_modules = nested;
|
m.sub_modules = nested;
|
||||||
m
|
m
|
||||||
@@ -55,9 +56,9 @@ mod tests {
|
|||||||
let mut leaf = CompiledModule::new();
|
let mut leaf = CompiledModule::new();
|
||||||
leaf.bytecode = Arc::from(vec![opcode::encode(OpCode::CREATE_CLOSURE, 1, 1, 0)]);
|
leaf.bytecode = Arc::from(vec![opcode::encode(OpCode::CREATE_CLOSURE, 1, 1, 0)]);
|
||||||
let mut mid = CompiledModule::new();
|
let mut mid = CompiledModule::new();
|
||||||
mid.sub_modules = vec![leaf];
|
mid.sub_modules = vec![Arc::new(leaf)];
|
||||||
mid.bytecode = Arc::from(vec![opcode::encode(OpCode::CREATE_CLOSURE, 2, 1, 0)]);
|
mid.bytecode = Arc::from(vec![opcode::encode(OpCode::CREATE_CLOSURE, 2, 1, 0)]);
|
||||||
let mut top = module_with_closure(vec![mid]);
|
let mut top = module_with_closure(vec![Arc::new(mid)]);
|
||||||
|
|
||||||
flatten_submodules(&mut top);
|
flatten_submodules(&mut top);
|
||||||
|
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ pub fn lower(f: &IRFunction) -> Result<CompiledModule, String> {
|
|||||||
|
|
||||||
let mut sub_modules = Vec::with_capacity(f.nested.len());
|
let mut sub_modules = Vec::with_capacity(f.nested.len());
|
||||||
for nested in &f.nested {
|
for nested in &f.nested {
|
||||||
sub_modules.push(lower(nested)?);
|
sub_modules.push(Arc::new(lower(nested)?));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(CompiledModule {
|
Ok(CompiledModule {
|
||||||
|
|||||||
@@ -112,7 +112,7 @@ impl SuspendedFrame {
|
|||||||
/// # 边界
|
/// # 边界
|
||||||
/// `sub_idx >= sub_modules.len()`(挂起状态跨 run)返回 Err,调用方须按各自
|
/// `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.regs = *self.regs;
|
||||||
vm.pc = self.pc;
|
vm.pc = self.pc;
|
||||||
vm.bytecode = std::mem::take(&mut self.bytecode);
|
vm.bytecode = std::mem::take(&mut self.bytecode);
|
||||||
|
|||||||
@@ -269,7 +269,9 @@ pub struct Vm {
|
|||||||
pub math_rng_state: u64,
|
pub math_rng_state: u64,
|
||||||
/// 全局扁平模块表:下标 = 模块 `flat_id`(顶层 0,子模块 flatten 后全局唯一)。
|
/// 全局扁平模块表:下标 = 模块 `flat_id`(顶层 0,子模块 flatten 后全局唯一)。
|
||||||
/// 闭包 `sub_module_index` 即 flat_id,逃逸闭包也能自足解析。
|
/// 闭包 `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` 同共享语义)。
|
/// 帧切换时暂存调用方字节码的 Arc 栈(与 `bytecode` 同共享语义)。
|
||||||
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]>,
|
||||||
@@ -1911,7 +1913,7 @@ impl Vm {
|
|||||||
/// 把 flatten 后的子模块子树重编号到平表偏移 `base`:DFS 前序拷贝进 `out`,
|
/// 把 flatten 后的子模块子树重编号到平表偏移 `base`:DFS 前序拷贝进 `out`,
|
||||||
/// 新 flat_id = base + (old - 1),子树内每条 `CREATE_CLOSURE` 的 imm16 同步重写。
|
/// 新 flat_id = base + (old - 1),子树内每条 `CREATE_CLOSURE` 的 imm16 同步重写。
|
||||||
/// 原子树 flat_id 自 1 连续,因此拷贝顺序即新 id 顺序,`out` 下标对齐平表槽位。
|
/// 原子树 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 new_id = base + module.flat_id - 1;
|
||||||
let mut bytecode = module.bytecode.to_vec();
|
let mut bytecode = module.bytecode.to_vec();
|
||||||
for instr in &mut bytecode {
|
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();
|
let mut rehomed = module.clone();
|
||||||
rehomed.bytecode = Arc::from(bytecode);
|
rehomed.bytecode = Arc::from(bytecode);
|
||||||
rehomed.flat_id = new_id;
|
rehomed.flat_id = new_id;
|
||||||
out.push(rehomed);
|
out.push(Arc::new(rehomed));
|
||||||
for sub in &module.sub_modules {
|
for sub in &module.sub_modules {
|
||||||
rehome_subtree(sub, base, out);
|
rehome_subtree(sub, base, out);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,18 +8,23 @@ use oxide_types::object::JsObject;
|
|||||||
use oxide_types::value::JsValue;
|
use oxide_types::value::JsValue;
|
||||||
|
|
||||||
/// 按 `flat_id` 下标收集整棵子模块树为平表,供 `run()` 装载。
|
/// 按 `flat_id` 下标收集整棵子模块树为平表,供 `run()` 装载。
|
||||||
fn collect_flat_modules(module: &CompiledModule) -> Vec<CompiledModule> {
|
///
|
||||||
let mut out: Vec<Option<CompiledModule>> = Vec::new();
|
/// 子模块节点以 `Arc` 与调用方模块树共享:只做 Arc::clone(O(1) 引用计数),
|
||||||
place_flat(module, &mut out);
|
/// 不再深拷贝 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()
|
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;
|
let idx = module.flat_id as usize;
|
||||||
if idx >= out.len() {
|
if idx >= out.len() {
|
||||||
out.resize(idx + 1, None);
|
out.resize(idx + 1, None);
|
||||||
}
|
}
|
||||||
out[idx] = Some(module.clone());
|
out[idx] = Some(Arc::clone(module));
|
||||||
for sub in &module.sub_modules {
|
for sub in &module.sub_modules {
|
||||||
place_flat(sub, out);
|
place_flat(sub, out);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user