perf: 压帧时固化 callee upvalue 表,热路径免每指令重查

This commit is contained in:
2026-09-28 17:24:10 +00:00
parent 597f11e802
commit b3255faa46
12 changed files with 110 additions and 88 deletions
+7 -3
View File
@@ -4,7 +4,7 @@
use std::sync::Arc;
use oxide_runtime_api::NativeResult;
use oxide_types::object::JsObject;
use oxide_types::object::{Cell, JsObject};
use oxide_types::value::JsValue;
use smallvec::SmallVec;
@@ -301,6 +301,9 @@ impl Vm {
.map(|name| self.kernel_core.perm_interner().intern(name).0)
.unwrap_or(0);
// 压帧时固化 callee 的 upvalue 表(非闭包为 null 空切片):热路径免
// 每指令重查 callee 对象,指针跨 GC 恒有效(callee 是 GC 根)。
let up = obj.upvalues_slice() as *const [*mut Cell];
self.frames.push(CallFrame {
return_addr: self.pc,
function_name,
@@ -319,9 +322,10 @@ impl Vm {
super_called: false,
strict: sub_is_strict,
continuation,
upvalues: up,
});
// 压帧后 callee 换为被调函数:失效 upvalue 切片缓存。
self.upvalue_cache = None;
// 压帧后活动镜像切到被调函数的表(非闭包为 null 空切片)。
self.active_upvalues = up;
self.pc = 0;
self.bytecode = sub_bytecode;
+8
View File
@@ -1,6 +1,7 @@
//! 调用帧与完成值类型:帧续行方式、压帧实参来源、调用帧、for-in 迭代游标、
//! try/catch/finally 处理记录,以及 break/continue/return 完成值(含访问器)。
use oxide_types::object::Cell;
use oxide_types::value::JsValue;
/// 调用帧被挂起后,恢复时需要继续的执行方式。
@@ -75,6 +76,13 @@ pub struct CallFrame {
/// 属性写失败时据此分派:严格模式抛 TypeError,sloppy 静默 no-op。
pub strict: bool,
pub continuation: FrameContinuation,
/// 被调函数 upvalue cell 表(压帧时从 callee 对象固化,非闭包为 null 空切片)。
///
/// SAFETY 前提:`callee` 是 GC 根(根遍历/重写/深拷贝三处均遍历该字段),
/// 其 `upvalues` Box 创建后不替换(`set_upvalues` 仅 CREATE_CLOSURE 调用一次,
/// 晋升克隆共享同一 Box),故指针跨 GC 恒有效;写路径经 `*mut` 转可变切片
/// 与 `upvalues_slice_mut` 同口径(Box 单所有权)。
pub upvalues: *const [*mut Cell],
}
/// 一次 `for-in` 迭代的游标:已收集的 key 列表与当前下标。
+3 -2
View File
@@ -40,8 +40,9 @@ pub(crate) struct InlineSyncState {
pub(crate) spill_stack: Vec<JsValue>,
pub(crate) cell_stack: Vec<Vec<*mut Cell>>,
pub(crate) inline_callee: Option<JsValue>,
/// upvalue 切片指针缓存(与 `inline_callee` 同生命周期,随本快照保存/恢复)。
pub(crate) upvalue_cache: Option<(JsValue, *const [*mut Cell])>,
/// 当前执行函数的 upvalue cell 表镜像(与 `inline_callee` 同生命周期,
/// 随本快照保存/恢复)。
pub(crate) active_upvalues: *const [*mut Cell],
/// 三个内嵌 dispatch 调度标志(`Vm::generator_dispatch` / `async_dispatch` /
/// `construct_dispatch`)的属主快照。save 时记录外层值并清零 VM 侧、restore
/// 时写回:嵌套 state-swap 调用不得继承外层调度上下文,否则其内部构造帧
+5 -5
View File
@@ -270,11 +270,11 @@ pub struct Vm {
/// frames 为空(inline 隔离状态)时由此取闭包 upvalues。嵌套 inline 由
/// InlineSyncState 保存/恢复。
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])>,
/// 当前执行函数的 upvalue cell 表(活动镜像,与 `CallFrame.upvalues` 同型:
/// 胖指针,非闭包为 null 空切片)。压帧/内联/弹帧/挂起恢复四个边界置位,
/// run 边界清零;指针恒有效——callee 对象是 GC 根,`upvalues` Box 创建后不
/// 替换,LOAD/STORE_UPVALUE 热路径直接按下标取 cell。
pub(crate) active_upvalues: *const [*mut Cell],
/// inline 目标函数的严格模式标志(与 `inline_callee` 同生命周期,
/// InlineSyncState 保存/恢复):内联执行期间帧表被隔离,写路径的
/// strict/sloppy 判定取此值而非帧标志。