perf: member 复合写路径接入 IC 写命中(depth 0)消除每次 DashMap 查询与回写

set_member_prop 增加 ic_set_hit_own(仅接受 depth==0 槽,跳过读侧学习的
原型条目防原型污染)命中直写槽,ext_pc 由 read_member_prop 显式带出消除
隐式 pc 契约;写新属性 miss 分支(IC_SET 分发 + member 写)统一改
CreateDataProperty 快路径(保留原型链 setter/readonly 检查),砍掉
ordinary_set 全链路的重复查询与 shape 转换开销。
This commit is contained in:
2026-08-15 08:16:49 +08:00
parent abeab6f216
commit aa4c28cdf0
7 changed files with 361 additions and 52 deletions
+48
View File
@@ -239,3 +239,51 @@ pub(crate) fn ic_set_hit_poly(obj: &mut JsObject, bytecode: &[Instr], ext_pc: us
}
false
}
/// member 复合写(读改写共用同一扩展字组)的写侧命中判定:顺序遍历 4 槽,只接受
/// depth==0 的数据槽并直写。
///
/// 读侧会把继承属性解析结果以 depth>0 条目写回同一扩展字组;写侧若命中这些条目
/// 会把新值直写原型对象(原型污染,规范要求 shadow 到接收者 own 属性)——因此
/// 原型条目一律跳过,落到慢路径走完整 [[Set]] 语义。
///
/// `pc` 为越过该 IC 指令全部扩展字后的位置(与 [`write_ic_back`] 同一约定),
/// 命中遍历从 `pc - IC_EXT_WORDS` 起的扩展字开始。
#[inline(always)]
pub(crate) fn ic_set_hit_own(obj: &mut JsObject, bytecode: &[Instr], pc: usize, value: JsValue) -> bool {
let base = pc - IC_EXT_WORDS;
let shape_id = bytecode[base] & 0x00FF_FFFF;
if shape_id == 0 {
return false;
}
let proto_depth = (bytecode[base] >> 24) as u8;
let slot_index = bytecode[base + 1];
if proto_depth == 0 && obj.shape_id() == shape_id && slot_index < obj.prop_vec_len() as u32 {
obj.set_prop_shape(slot_index, value);
return true;
}
ic_set_hit_own_poly(obj, bytecode, base, value)
}
/// 写侧多态槽(1..3)遍历,depth==0 only;`inline(never)` 防主循环代码膨胀。
/// `ext_pc` 为扩展字起始位置(首个扩展字处)。
#[inline(never)]
fn ic_set_hit_own_poly(obj: &mut JsObject, bytecode: &[Instr], ext_pc: usize, value: JsValue) -> bool {
for i in 1..IC_SLOTS {
let base = ext_pc + i * 2;
let shape_id = bytecode[base] & 0x00FF_FFFF;
if shape_id == 0 {
break;
}
let proto_depth = (bytecode[base] >> 24) as u8;
if proto_depth != 0 {
continue;
}
let slot_index = bytecode[base + 1];
if obj.shape_id() == shape_id && slot_index < obj.prop_vec_len() as u32 {
obj.set_prop_shape(slot_index, value);
return true;
}
}
false
}