perf: 数组元素访问 dispatch 内联 fast path + length_si 缓存

GET_PROP_DYNAMIC/SET_PROP_DYNAMIC 开头内联数组元素 fast path:整数键 +
真数组 + 无元素 meta + 界内时直读/直写元素区,免 primitive_property_get /
ordinary_get/set 调用链与 __proto__ 每次 RwLock 查询;越界与有 meta
场景回退原路径(CreateDataProperty + length 扩展 / accessor/hole 协议)。
GET 侧 is_object() 快检先于 checked_object_ptr,保持原始值 receiver
不抛错。length_si 缓存为 Vm 字段(builtin 绑定后取 id,稳定非 0),
普通属性路径 5 处 hot spot 改读缓存,消除每次 intern 的共享锁开销。
This commit is contained in:
2026-08-15 04:58:57 +08:00
parent 63d549aec2
commit ee4a12668f
7 changed files with 222 additions and 16 deletions
+9 -4
View File
@@ -21,6 +21,9 @@ impl Vm {
let core = KernelCore::new(KernelConfig::minimal());
let mut session = KernelSession::new(&core);
bindings::init_kernel_builtins(&core, &mut session);
// 在 builtin 绑定之后取 id:绑定过程已 intern "length",此处命中缓存得到
// 非 0 的稳定 id(保持枚举层"id 0 哨兵"的既有约定,见 walk_own_keys)。
let length_si = core.perm_interner().intern("length").0;
let obj_proto = P::clone(&session.builtin_world().object_proto);
let mut vm = Self {
regs: [JsValue::undefined(); 256],
@@ -31,6 +34,7 @@ impl Vm {
frames: smallvec::SmallVec::new(),
kernel_core: core,
session,
length_si,
epoch: Epoch::new(),
object_prototype: obj_proto,
generator_proto: P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null())),
@@ -115,6 +119,9 @@ impl Vm {
pub fn with_kernel_core(core: Arc<KernelCore>) -> Self {
let mut session = KernelSession::new(&core);
bindings::init_kernel_builtins(&core, &mut session);
// 在 builtin 绑定之后取 id:绑定过程已 intern "length",此处命中缓存得到
// 非 0 的稳定 id(保持枚举层"id 0 哨兵"的既有约定,见 walk_own_keys)。
let length_si = core.perm_interner().intern("length").0;
let obj_proto = P::clone(&session.builtin_world().object_proto);
let mut vm = Self {
regs: [JsValue::undefined(); 256],
@@ -125,6 +132,7 @@ impl Vm {
frames: smallvec::SmallVec::new(),
kernel_core: core,
session,
length_si,
epoch: Epoch::new(),
object_prototype: obj_proto,
generator_proto: P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null())),
@@ -637,10 +645,7 @@ mod tests {
// wrapper 是跨重置存活对象,其原型链必须仍能解析出 call/apply/bind:
// 任何一条路径失效都说明 wrapper 原型指向了已释放的旧 Function 原型。
assert_eq!(run_source(&mut vm, "Array.prototype.push.call([1], 2)"), JsValue::int(2));
assert_eq!(
run_source(&mut vm, "Array.prototype.push.apply([], [1, 2, 3])"),
JsValue::int(3)
);
assert_eq!(run_source(&mut vm, "Array.prototype.push.apply([], [1, 2, 3])"), JsValue::int(3));
let replaced = run_source(&mut vm, "String.prototype.replace.call('a', 'a', 'b')");
assert_eq!(vm.lookup_str(replaced).as_deref(), Some("b"));
let has = run_source(&mut vm, "Object.prototype.hasOwnProperty.call({x: 1}, 'x')");