mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-24 10:41:11 +08:00
perf: 数组回调字节码调用改寄存器窗口复用减少搬移
This commit is contained in:
@@ -31,36 +31,45 @@ fn place_flat(module: &Arc<CompiledModule>, out: &mut Vec<Option<Arc<CompiledMod
|
||||
}
|
||||
|
||||
/// save 方向的字段取值表达式(字段名由调用方以 ident 位置提供,本宏只产出值)。
|
||||
/// `regs` 取窗口副本:值来自 `save_inline_state` 预填充的 `window_regs` 局部缓冲
|
||||
/// (经宏参数注入,绕开 macro hygiene),从池中取出后即 move 进 `InlineSyncState`。
|
||||
macro_rules! inline_save_field {
|
||||
($recv:ident, regs, boxed_array) => { Box::new($recv.regs) };
|
||||
($recv:ident, pc, copy) => { $recv.pc };
|
||||
($recv:ident, bytecode, move_field) => { std::mem::take(&mut $recv.bytecode) };
|
||||
($recv:ident, active_immutables, copy) => { $recv.active_immutables };
|
||||
($recv:ident, active_reg_limit, copy) => { $recv.active_reg_limit };
|
||||
($recv:ident, root_reg_limit, copy) => { $recv.root_reg_limit };
|
||||
($recv:ident, try_stack, move_field) => { std::mem::take(&mut $recv.try_stack) };
|
||||
($recv:ident, frames, frames_values) => { std::mem::take(&mut $recv.frames) };
|
||||
($recv:ident, exception_value, opt_take) => { $recv.exception_value.take() };
|
||||
($recv:ident, pending_exception, opt_take) => { $recv.pending_exception.take() };
|
||||
($recv:ident, pending_error_kind, opt_take) => { $recv.pending_error_kind.take() };
|
||||
($recv:ident, pending_completion, opt_copy) => { $recv.pending_completion };
|
||||
($recv:ident, for_in_iters, for_in_keys) => { std::mem::take(&mut $recv.iters.for_in_iters) };
|
||||
($recv:ident, for_of_iters, iter_take) => { std::mem::take(&mut $recv.iters.for_of_iters) };
|
||||
($recv:ident, last_for_of_result, iter_copy) => { $recv.iters.last_for_of_result };
|
||||
($recv:ident, saved_bytecode_stack, move_field) => { std::mem::take(&mut $recv.saved_bytecode_stack) };
|
||||
($recv:ident, saved_immutables_stack, move_field) => { std::mem::take(&mut $recv.saved_immutables_stack) };
|
||||
($recv:ident, save_stack, move_field) => { std::mem::take(&mut $recv.save_stack) };
|
||||
($recv:ident, spill_stack, move_field) => { std::mem::take(&mut $recv.spill_stack) };
|
||||
($recv:ident, cell_stack, move_field) => { std::mem::take(&mut $recv.cell_stack) };
|
||||
($recv:ident, inline_callee, opt_copy) => { $recv.inline_callee };
|
||||
($recv:ident, inline_args_base, copy) => { $recv.inline_args_base };
|
||||
($recv:ident, inline_args_count, copy) => { $recv.inline_args_count };
|
||||
($recv:ident, accessor_frame_target_reg, copy) => { $recv.accessor_frame_target_reg };
|
||||
($recv:ident, $window_regs:ident, regs, boxed_window) => { std::mem::take(&mut $window_regs).into_boxed_slice() };
|
||||
($recv:ident, $window_regs:ident, saved_this, copy) => { $recv.regs[254] };
|
||||
($recv:ident, $window_regs:ident, saved_new_target, copy) => { $recv.regs[255] };
|
||||
($recv:ident, $window_regs:ident, pc, copy) => { $recv.pc };
|
||||
($recv:ident, $window_regs:ident, bytecode, move_field) => { std::mem::take(&mut $recv.bytecode) };
|
||||
($recv:ident, $window_regs:ident, active_immutables, copy) => { $recv.active_immutables };
|
||||
($recv:ident, $window_regs:ident, active_reg_limit, copy) => { $recv.active_reg_limit };
|
||||
($recv:ident, $window_regs:ident, root_reg_limit, copy) => { $recv.root_reg_limit };
|
||||
($recv:ident, $window_regs:ident, try_stack, move_field) => { std::mem::take(&mut $recv.try_stack) };
|
||||
($recv:ident, $window_regs:ident, frames, frames_values) => { std::mem::take(&mut $recv.frames) };
|
||||
($recv:ident, $window_regs:ident, exception_value, opt_take) => { $recv.exception_value.take() };
|
||||
($recv:ident, $window_regs:ident, pending_exception, opt_take) => { $recv.pending_exception.take() };
|
||||
($recv:ident, $window_regs:ident, pending_error_kind, opt_take) => { $recv.pending_error_kind.take() };
|
||||
($recv:ident, $window_regs:ident, pending_completion, opt_copy) => { $recv.pending_completion };
|
||||
($recv:ident, $window_regs:ident, for_in_iters, for_in_keys) => { std::mem::take(&mut $recv.iters.for_in_iters) };
|
||||
($recv:ident, $window_regs:ident, for_of_iters, iter_take) => { std::mem::take(&mut $recv.iters.for_of_iters) };
|
||||
($recv:ident, $window_regs:ident, last_for_of_result, iter_copy) => { $recv.iters.last_for_of_result };
|
||||
($recv:ident, $window_regs:ident, saved_bytecode_stack, move_field) => { std::mem::take(&mut $recv.saved_bytecode_stack) };
|
||||
($recv:ident, $window_regs:ident, saved_immutables_stack, move_field) => { std::mem::take(&mut $recv.saved_immutables_stack) };
|
||||
($recv:ident, $window_regs:ident, save_stack, move_field) => { std::mem::take(&mut $recv.save_stack) };
|
||||
($recv:ident, $window_regs:ident, spill_stack, move_field) => { std::mem::take(&mut $recv.spill_stack) };
|
||||
($recv:ident, $window_regs:ident, cell_stack, move_field) => { std::mem::take(&mut $recv.cell_stack) };
|
||||
($recv:ident, $window_regs:ident, inline_callee, opt_copy) => { $recv.inline_callee };
|
||||
($recv:ident, $window_regs:ident, inline_args_base, copy) => { $recv.inline_args_base };
|
||||
($recv:ident, $window_regs:ident, inline_args_count, copy) => { $recv.inline_args_count };
|
||||
($recv:ident, $window_regs:ident, accessor_frame_target_reg, copy) => { $recv.accessor_frame_target_reg };
|
||||
}
|
||||
|
||||
/// restore 方向的字段写回语句。
|
||||
/// restore 方向的字段写回语句。`regs` 只回拷窗口并把缓冲归还池。
|
||||
macro_rules! inline_restore_field {
|
||||
($recv:ident, $saved:ident, regs, boxed_array) => { $recv.regs = *$saved.regs };
|
||||
($recv:ident, $saved:ident, regs, boxed_window) => {
|
||||
$recv.regs[..$saved.regs.len()].copy_from_slice(&$saved.regs);
|
||||
$recv.inline_reg_pool = Some($saved.regs.into_vec());
|
||||
};
|
||||
($recv:ident, $saved:ident, saved_this, copy) => { $recv.regs[254] = $saved.saved_this };
|
||||
($recv:ident, $saved:ident, saved_new_target, copy) => { $recv.regs[255] = $saved.saved_new_target };
|
||||
($recv:ident, $saved:ident, pc, copy) => { $recv.pc = $saved.pc };
|
||||
($recv:ident, $saved:ident, bytecode, move_field) => { $recv.bytecode = $saved.bytecode };
|
||||
($recv:ident, $saved:ident, active_immutables, copy) => { $recv.active_immutables = $saved.active_immutables };
|
||||
@@ -88,10 +97,13 @@ macro_rules! inline_restore_field {
|
||||
|
||||
/// 内联同步调用可搬移执行核心字段的单一登记表。save/restore 双向由本宏展开;
|
||||
/// 新增字段只加一行(字段名, 操作符)。注释 = 该字段语义(M 搬移 / V 含 JsValue)。
|
||||
/// `$window_regs` 只在 save 方向被 `regs` 字段消费。
|
||||
macro_rules! inline_core_fields {
|
||||
($recv:ident, $saved:ident, $ops:ident) => {
|
||||
$ops!($recv, $saved,
|
||||
(regs, boxed_array), // V M
|
||||
($recv:ident, $saved:ident, $ops:ident, $window_regs:ident) => {
|
||||
$ops!($recv, $saved, $window_regs,
|
||||
(regs, boxed_window), // V M
|
||||
(saved_this, copy), // V
|
||||
(saved_new_target, copy), // V
|
||||
(pc, copy), // M
|
||||
(bytecode, move_field), // V M
|
||||
(active_immutables, copy), // M
|
||||
@@ -122,33 +134,48 @@ macro_rules! inline_core_fields {
|
||||
/// 把字段表展开为 `InlineSyncState` 结构体字面量(字段名在 ident 位置,值由
|
||||
/// `inline_save_field` 产出)。
|
||||
macro_rules! inline_save {
|
||||
($recv:ident, $saved:ident, $(($field:ident, $op:ident)),* $(,)?) => {
|
||||
($recv:ident, $saved:ident, $window_regs:ident, $(($field:ident, $op:ident)),* $(,)?) => {
|
||||
InlineSyncState {
|
||||
$($field: inline_save_field!($recv, $field, $op)),*
|
||||
$($field: inline_save_field!($recv, $window_regs, $field, $op)),*
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// 把字段表展开为写回语句序列。
|
||||
macro_rules! inline_restore {
|
||||
($recv:ident, $saved:ident, $(($field:ident, $op:ident)),* $(,)?) => {
|
||||
($recv:ident, $saved:ident, $window_regs:ident, $(($field:ident, $op:ident)),* $(,)?) => {
|
||||
{ $(inline_restore_field!($recv, $saved, $field, $op);)* }
|
||||
};
|
||||
}
|
||||
|
||||
impl Vm {
|
||||
/// 保存当前完整 VM 执行状态到堆上(内联同步调用与生成器恢复共用)。
|
||||
pub(crate) fn save_inline_state(&mut self) -> Box<InlineSyncState> {
|
||||
/// 保存当前 VM 执行状态到堆上(内联同步调用与生成器恢复共用)。
|
||||
///
|
||||
/// 寄存器只保存窗口 `regs[0..min(regs_end, 253)]` 的副本,`regs[254]/[255]`
|
||||
/// 单独存入 `saved_this`/`saved_new_target`。窗口缓冲取自 `inline_reg_pool`
|
||||
/// 复用,热回调循环内零分配;嵌套时池为空则新分配。
|
||||
///
|
||||
/// # 边界与前提
|
||||
/// - `regs_end` ≤ 253 表示窗口化保存;传 256(全量)等价于保存全部寄存器
|
||||
/// (253 个通用槽 + 254/255 单独存)。
|
||||
/// - 调用方保证 `regs_end ≤ 256`;窗口截断到 253 是 callee 写入集上限。
|
||||
pub(crate) fn save_inline_state(&mut self, regs_end: usize) -> Box<InlineSyncState> {
|
||||
vm_trace!("save_inline_state: pc={} depth={}", self.pc, self.frames.len());
|
||||
let window = regs_end.min(253);
|
||||
let mut window_regs = self.inline_reg_pool.take().unwrap_or_default();
|
||||
window_regs.clear();
|
||||
window_regs.extend_from_slice(&self.regs[..window]);
|
||||
let vm = self;
|
||||
Box::new(inline_core_fields!(vm, vm, inline_save))
|
||||
Box::new(inline_core_fields!(vm, vm, inline_save, window_regs))
|
||||
}
|
||||
|
||||
/// 把 [`save_inline_state`] 保存的状态完整恢复回 VM。
|
||||
/// 把 [`save_inline_state`] 保存的状态恢复回 VM。窗口回拷 + `regs[254]/[255]`
|
||||
/// 单回,窗口外寄存器 callee 未触碰无需恢复。
|
||||
pub(crate) fn restore_inline_state(&mut self, saved: Box<InlineSyncState>) {
|
||||
vm_trace!("restore_inline_state: pc={}", saved.pc);
|
||||
let vm = self;
|
||||
inline_core_fields!(vm, saved, inline_restore);
|
||||
let _window_regs: Vec<JsValue> = Vec::new();
|
||||
inline_core_fields!(vm, saved, inline_restore, _window_regs);
|
||||
}
|
||||
|
||||
/// 首次执行的 VM 就绪:清空执行核心(regs/pc/bytecode/各栈段/迭代器/内联态),
|
||||
@@ -223,9 +250,16 @@ impl Vm {
|
||||
let sub = &subs[sub_idx];
|
||||
|
||||
vm_trace!("call_bytecode: saving state pc={} depth={}", self.pc, self.frames.len());
|
||||
let saved = self.save_inline_state();
|
||||
// 窗口 = max(调用方活跃寄存器, callee 寄存器数):restore 只回拷窗口,正好
|
||||
// 覆盖 callee 写入区(regs[0..n_registers] + 254/255)与调用方活动区。
|
||||
let window = self.active_reg_limit.max(sub.n_registers).max(1) as usize;
|
||||
let saved = self.save_inline_state(window);
|
||||
|
||||
self.regs = [JsValue::undefined(); 256];
|
||||
// 只零填 callee 读区 regs[0..n_registers];高位残留调用方旧值无害
|
||||
// (callee 字节码只访问自身 n_registers 内)。
|
||||
for r in 0..sub.n_registers as usize {
|
||||
self.regs[r] = JsValue::undefined();
|
||||
}
|
||||
self.pc = 0;
|
||||
self.bytecode = Arc::clone(&sub.bytecode);
|
||||
self.activate_immutables(sub_idx, &sub.constants);
|
||||
@@ -422,6 +456,8 @@ mod tests {
|
||||
// 构造带哨兵的 VM → save → 恢复 → 断言全部字段逐字往返(含 accessor_frame_target_reg)。
|
||||
let mut vm = Vm::new();
|
||||
vm.regs[3] = JsValue::float(1.0);
|
||||
vm.regs[254] = JsValue::float(254.0);
|
||||
vm.regs[255] = JsValue::float(255.0);
|
||||
vm.pc = 7;
|
||||
vm.active_immutables = std::ptr::slice_from_raw_parts(std::ptr::null(), 0);
|
||||
vm.active_reg_limit = 4;
|
||||
@@ -441,12 +477,14 @@ mod tests {
|
||||
vm.inline_args_count = 3;
|
||||
vm.accessor_frame_target_reg = Some(9);
|
||||
|
||||
let saved = vm.save_inline_state();
|
||||
let saved = vm.save_inline_state(256);
|
||||
vm.regs[3] = JsValue::float(99.0);
|
||||
vm.accessor_frame_target_reg = None;
|
||||
vm.restore_inline_state(saved);
|
||||
|
||||
assert_eq!(vm.regs[3], JsValue::float(1.0));
|
||||
assert_eq!(vm.regs[254], JsValue::float(254.0));
|
||||
assert_eq!(vm.regs[255], JsValue::float(255.0));
|
||||
assert_eq!(vm.pc, 7);
|
||||
assert_eq!(vm.active_reg_limit, 4);
|
||||
assert_eq!(vm.root_reg_limit, 5);
|
||||
|
||||
Reference in New Issue
Block a user