mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-23 18:21:13 +08:00
perf: upvalue 读取缓存 callee 切片指针省解引用链
This commit is contained in:
@@ -384,37 +384,51 @@ impl Vm {
|
|||||||
/// 读取当前闭包的 upvalue:命中 cell 判初始化后取值,未命中委托惰性建 cell。
|
/// 读取当前闭包的 upvalue:命中 cell 判初始化后取值,未命中委托惰性建 cell。
|
||||||
///
|
///
|
||||||
/// # 步骤
|
/// # 步骤
|
||||||
/// 1. 取 imm16 为 upvalue 下标,从当前 callee 的 `upvalues` 命中 cell。
|
/// 1. 取 imm16 为 upvalue 下标;缓存命中(键 = 当前 callee 位级相等)直接
|
||||||
|
/// 解引用缓存切片指针,未命中从 callee 重算并填缓存。
|
||||||
/// 2. 命中且非空:未初始化(TDZ)抛 ReferenceError,否则值写入 `regs[rd]`。
|
/// 2. 命中且非空:未初始化(TDZ)抛 ReferenceError,否则值写入 `regs[rd]`。
|
||||||
/// 3. 未命中/空槽(`CREATE_CLOSURE` 早于 `MAKE_CELL`):委托
|
/// 3. 未命中/空槽(`CREATE_CLOSURE` 早于 `MAKE_CELL`):委托
|
||||||
/// `lazy_create_upvalue_cell` 建 cell。
|
/// `lazy_create_upvalue_cell` 建 cell。
|
||||||
///
|
///
|
||||||
/// # 边界与前提
|
/// # 边界与前提
|
||||||
/// - `uv_idx` 越界或当前无 callee 时同样走惰性路径,最终回退 undefined。
|
/// - `uv_idx` 越界或当前无 callee 时同样走惰性路径,最终回退 undefined。
|
||||||
///
|
/// - 缓存指针在键匹配期间恒有效:callee 对象是 GC 根,`upvalues` Box
|
||||||
/// # 注意事项
|
/// 创建后不替换。
|
||||||
/// - 手写 IR 保留指令(同 `dispatch_make_cell`)。
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub(crate) fn dispatch_load_upvalue(&mut self, rd: usize, instr: u32) -> Result<(), String> {
|
pub(crate) fn dispatch_load_upvalue(&mut self, rd: usize, instr: u32) -> Result<(), String> {
|
||||||
let uv_idx = opcode::imm16(instr) as usize;
|
let uv_idx = opcode::imm16(instr) as usize;
|
||||||
if let Some(callee) = self.current_callee() {
|
let callee = self.current_callee();
|
||||||
|
// 命中:键位级相等保证缓存切片指针对应当前 callee 对象(对象为 GC 根、
|
||||||
|
// Box 创建后不替换),直接解引用安全。
|
||||||
|
let mut upvals: Option<&[*mut Cell]> = None;
|
||||||
|
if let Some((key, ptr)) = self.upvalue_cache {
|
||||||
|
if callee == Some(key) {
|
||||||
|
upvals = Some(unsafe { &*ptr });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 未命中:重算切片指针并填缓存(含空切片,免每次 null 判定)。
|
||||||
|
if upvals.is_none() {
|
||||||
|
if let Some(callee) = callee {
|
||||||
if callee.is_object() {
|
if callee.is_object() {
|
||||||
let obj = unsafe { &*callee.as_js_object_ptr() };
|
let obj = unsafe { &*callee.as_js_object_ptr() };
|
||||||
let upvals = obj.upvalues_slice();
|
let slice = obj.upvalues_slice();
|
||||||
|
self.upvalue_cache = Some((callee, slice as *const [*mut Cell]));
|
||||||
|
upvals = Some(slice);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(upvals) = upvals {
|
||||||
if uv_idx < upvals.len() {
|
if uv_idx < upvals.len() {
|
||||||
let cell = upvals[uv_idx];
|
let cell = upvals[uv_idx];
|
||||||
if !cell.is_null() {
|
if !cell.is_null() {
|
||||||
let c = unsafe { &*cell };
|
let c = unsafe { &*cell };
|
||||||
if !c.is_initialized() {
|
if !c.is_initialized() {
|
||||||
return self
|
return self.raise_error_kind("ReferenceError", "Cannot access variable before initialization");
|
||||||
.raise_error_kind("ReferenceError", "Cannot access variable before initialization");
|
|
||||||
}
|
}
|
||||||
self.regs[rd] = c.value;
|
self.regs[rd] = c.value;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
// cell 尚未创建(hoisting 顺序:CREATE_CLOSURE 先于 MAKE_CELL),
|
// cell 尚未创建(hoisting 顺序:CREATE_CLOSURE 先于 MAKE_CELL),
|
||||||
// 用调用方寄存器值惰性创建 cell。
|
// 用调用方寄存器值惰性创建 cell。
|
||||||
self.lazy_create_upvalue_cell(rd, uv_idx)
|
self.lazy_create_upvalue_cell(rd, uv_idx)
|
||||||
|
|||||||
@@ -80,6 +80,9 @@ impl SuspendedFrame {
|
|||||||
pub fn save_from(&mut self, vm: &mut Vm, callee: JsValue) -> Result<(), String> {
|
pub fn save_from(&mut self, vm: &mut Vm, callee: JsValue) -> Result<(), String> {
|
||||||
let frame = vm.frames.pop().ok_or_else(|| "frame missing on suspend".to_string())?;
|
let frame = vm.frames.pop().ok_or_else(|| "frame missing on suspend".to_string())?;
|
||||||
self.frame = Some(frame);
|
self.frame = Some(frame);
|
||||||
|
// 挂起弹帧不经 restore_frame:失效 upvalue 切片缓存(值相等键已自愈,
|
||||||
|
// 此为双保险)。
|
||||||
|
vm.upvalue_cache = None;
|
||||||
*self.regs = vm.regs;
|
*self.regs = vm.regs;
|
||||||
self.pc = vm.pc;
|
self.pc = vm.pc;
|
||||||
self.bytecode = std::mem::take(&mut vm.bytecode);
|
self.bytecode = std::mem::take(&mut vm.bytecode);
|
||||||
|
|||||||
@@ -317,6 +317,8 @@ impl Vm {
|
|||||||
strict: sub_is_strict,
|
strict: sub_is_strict,
|
||||||
continuation,
|
continuation,
|
||||||
});
|
});
|
||||||
|
// 压帧后 callee 换为被调函数:失效 upvalue 切片缓存。
|
||||||
|
self.upvalue_cache = None;
|
||||||
|
|
||||||
self.pc = 0;
|
self.pc = 0;
|
||||||
self.bytecode = sub_bytecode;
|
self.bytecode = sub_bytecode;
|
||||||
|
|||||||
@@ -40,6 +40,8 @@ pub(crate) struct InlineSyncState {
|
|||||||
pub(crate) spill_stack: Vec<JsValue>,
|
pub(crate) spill_stack: Vec<JsValue>,
|
||||||
pub(crate) cell_stack: Vec<Vec<*mut Cell>>,
|
pub(crate) cell_stack: Vec<Vec<*mut Cell>>,
|
||||||
pub(crate) inline_callee: Option<JsValue>,
|
pub(crate) inline_callee: Option<JsValue>,
|
||||||
|
/// upvalue 切片指针缓存(与 `inline_callee` 同生命周期,随本快照保存/恢复)。
|
||||||
|
pub(crate) upvalue_cache: Option<(JsValue, *const [*mut Cell])>,
|
||||||
/// 三个内嵌 dispatch 调度标志(`Vm::generator_dispatch` / `async_dispatch` /
|
/// 三个内嵌 dispatch 调度标志(`Vm::generator_dispatch` / `async_dispatch` /
|
||||||
/// `construct_dispatch`)的属主快照。save 时记录外层值并清零 VM 侧、restore
|
/// `construct_dispatch`)的属主快照。save 时记录外层值并清零 VM 侧、restore
|
||||||
/// 时写回:嵌套 state-swap 调用不得继承外层调度上下文,否则其内部构造帧
|
/// 时写回:嵌套 state-swap 调用不得继承外层调度上下文,否则其内部构造帧
|
||||||
|
|||||||
@@ -255,6 +255,11 @@ pub struct Vm {
|
|||||||
/// frames 为空(inline 隔离状态)时由此取闭包 upvalues。嵌套 inline 由
|
/// frames 为空(inline 隔离状态)时由此取闭包 upvalues。嵌套 inline 由
|
||||||
/// InlineSyncState 保存/恢复。
|
/// InlineSyncState 保存/恢复。
|
||||||
pub(crate) inline_callee: Option<JsValue>,
|
pub(crate) inline_callee: Option<JsValue>,
|
||||||
|
/// upvalue 切片指针缓存:键 = 当前 callee 值(位级相等),值 = 该 callee 的
|
||||||
|
/// `upvalues` 切片指针(含空切片情形)。LOAD_UPVALUE 命中时省 `is_object` +
|
||||||
|
/// 对象解引用 + 切片解引用。压帧/弹帧/挂起/run 边界失效;键匹配期间指针恒
|
||||||
|
/// 有效——callee 对象是 GC 根,`upvalues` Box 创建后不替换。
|
||||||
|
pub(crate) upvalue_cache: Option<(JsValue, *const [*mut Cell])>,
|
||||||
/// inline 目标函数的严格模式标志(与 `inline_callee` 同生命周期,
|
/// inline 目标函数的严格模式标志(与 `inline_callee` 同生命周期,
|
||||||
/// InlineSyncState 保存/恢复):内联执行期间帧表被隔离,写路径的
|
/// InlineSyncState 保存/恢复):内联执行期间帧表被隔离,写路径的
|
||||||
/// strict/sloppy 判定取此值而非帧标志。
|
/// strict/sloppy 判定取此值而非帧标志。
|
||||||
|
|||||||
@@ -101,6 +101,9 @@ macro_rules! inline_save_field {
|
|||||||
($recv:ident, $window_regs:ident, inline_callee, opt_copy) => {
|
($recv:ident, $window_regs:ident, inline_callee, opt_copy) => {
|
||||||
$recv.inline_callee
|
$recv.inline_callee
|
||||||
};
|
};
|
||||||
|
($recv:ident, $window_regs:ident, upvalue_cache, copy) => {
|
||||||
|
$recv.upvalue_cache
|
||||||
|
};
|
||||||
($recv:ident, $window_regs:ident, generator_dispatch, flag_zero) => {{
|
($recv:ident, $window_regs:ident, generator_dispatch, flag_zero) => {{
|
||||||
let prev = $recv.generator_dispatch;
|
let prev = $recv.generator_dispatch;
|
||||||
$recv.generator_dispatch = false;
|
$recv.generator_dispatch = false;
|
||||||
@@ -208,6 +211,9 @@ macro_rules! inline_restore_field {
|
|||||||
($recv:ident, $saved:ident, inline_callee, opt_copy) => {
|
($recv:ident, $saved:ident, inline_callee, opt_copy) => {
|
||||||
$recv.inline_callee = $saved.inline_callee
|
$recv.inline_callee = $saved.inline_callee
|
||||||
};
|
};
|
||||||
|
($recv:ident, $saved:ident, upvalue_cache, copy) => {
|
||||||
|
$recv.upvalue_cache = $saved.upvalue_cache
|
||||||
|
};
|
||||||
($recv:ident, $saved:ident, generator_dispatch, flag_zero) => {
|
($recv:ident, $saved:ident, generator_dispatch, flag_zero) => {
|
||||||
$recv.generator_dispatch = $saved.generator_dispatch
|
$recv.generator_dispatch = $saved.generator_dispatch
|
||||||
};
|
};
|
||||||
@@ -271,6 +277,7 @@ macro_rules! inline_core_fields {
|
|||||||
(spill_stack, move_field), // V M
|
(spill_stack, move_field), // V M
|
||||||
(cell_stack, move_field), // V M
|
(cell_stack, move_field), // V M
|
||||||
(inline_callee, opt_copy), // V M
|
(inline_callee, opt_copy), // V M
|
||||||
|
(upvalue_cache, copy), // V
|
||||||
(generator_dispatch, flag_zero), // M 调度标志:快照属主值,嵌套期间清零
|
(generator_dispatch, flag_zero), // M 调度标志:快照属主值,嵌套期间清零
|
||||||
(async_dispatch, flag_zero), // M 调度标志:快照属主值,嵌套期间清零
|
(async_dispatch, flag_zero), // M 调度标志:快照属主值,嵌套期间清零
|
||||||
(construct_dispatch, flag_zero), // M 调度标志:快照属主值,嵌套期间清零
|
(construct_dispatch, flag_zero), // M 调度标志:快照属主值,嵌套期间清零
|
||||||
@@ -523,6 +530,8 @@ impl Vm {
|
|||||||
frame.return_addr,
|
frame.return_addr,
|
||||||
frame.caller_reg_limit
|
frame.caller_reg_limit
|
||||||
);
|
);
|
||||||
|
// 弹帧后 callee 换回调用方:失效 upvalue 切片缓存。
|
||||||
|
self.upvalue_cache = None;
|
||||||
if let Some(saved_bc) = self.saved_bytecode_stack.pop() {
|
if let Some(saved_bc) = self.saved_bytecode_stack.pop() {
|
||||||
self.bytecode = saved_bc;
|
self.bytecode = saved_bc;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -100,6 +100,7 @@ impl Vm {
|
|||||||
inline_args_count: 0,
|
inline_args_count: 0,
|
||||||
accessor_frame_target_reg: None,
|
accessor_frame_target_reg: None,
|
||||||
inline_callee: None,
|
inline_callee: None,
|
||||||
|
upvalue_cache: None,
|
||||||
inline_strict: false,
|
inline_strict: false,
|
||||||
inline_frames_base: 0,
|
inline_frames_base: 0,
|
||||||
top_level_strict: false,
|
top_level_strict: false,
|
||||||
@@ -236,6 +237,7 @@ impl Vm {
|
|||||||
inline_args_count: 0,
|
inline_args_count: 0,
|
||||||
accessor_frame_target_reg: None,
|
accessor_frame_target_reg: None,
|
||||||
inline_callee: None,
|
inline_callee: None,
|
||||||
|
upvalue_cache: None,
|
||||||
inline_strict: false,
|
inline_strict: false,
|
||||||
inline_frames_base: 0,
|
inline_frames_base: 0,
|
||||||
top_level_strict: false,
|
top_level_strict: false,
|
||||||
@@ -550,6 +552,9 @@ impl Vm {
|
|||||||
self.reentry_hops = 0;
|
self.reentry_hops = 0;
|
||||||
// inline 窗口缓冲池内容为已废弃快照,跨 run/reset 不保留。
|
// inline 窗口缓冲池内容为已废弃快照,跨 run/reset 不保留。
|
||||||
self.inline_reg_pool = None;
|
self.inline_reg_pool = None;
|
||||||
|
// upvalue 切片缓存是执行期状态:键为 callee 值,跨 run/reset 后缓存的
|
||||||
|
// 切片指针失效(callee 对象可能已回收)。
|
||||||
|
self.upvalue_cache = None;
|
||||||
// 微任务队列是执行期状态:跨 run 不保留。
|
// 微任务队列是执行期状态:跨 run 不保留。
|
||||||
self.job_queue.clear();
|
self.job_queue.clear();
|
||||||
// Atomics waiter 表同属执行期状态:未结算 promise 清位后无强根。
|
// Atomics waiter 表同属执行期状态:未结算 promise 清位后无强根。
|
||||||
|
|||||||
Reference in New Issue
Block a user