perf: 属性键解析移出 IC 命中路径
This commit is contained in:
@@ -308,10 +308,11 @@ impl Vm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let obj = unsafe { &*obj_ptr };
|
let obj = unsafe { &*obj_ptr };
|
||||||
let prop_name_si = self.property_key_si(self.regs[b])?;
|
|
||||||
let (cached_shape_id, cached_slot, cached_depth) = ic_helper::read_ic_entry(&self.bytecode, &mut self.pc);
|
let (cached_shape_id, cached_slot, cached_depth) = ic_helper::read_ic_entry(&self.bytecode, &mut self.pc);
|
||||||
let ic_pc = self.pc;
|
let ic_pc = self.pc;
|
||||||
if obj.has_prop_meta() {
|
if obj.has_prop_meta() {
|
||||||
|
// meta 对象整对象走慢路径,此时才解析键。
|
||||||
|
let prop_name_si = self.property_key_si(self.regs[b])?;
|
||||||
let val = self.ordinary_get_with_target(obj, prop_name_si, val, a as u8)?;
|
let val = self.ordinary_get_with_target(obj, prop_name_si, val, a as u8)?;
|
||||||
if self.accessor_frame_target_reg.take().is_none() {
|
if self.accessor_frame_target_reg.take().is_none() {
|
||||||
self.regs[a] = val;
|
self.regs[a] = val;
|
||||||
@@ -320,66 +321,73 @@ impl Vm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Some(value) = ic_get_hit(obj, cached_shape_id, cached_slot, cached_depth) {
|
if let Some(value) = ic_get_hit(obj, cached_shape_id, cached_slot, cached_depth) {
|
||||||
|
// 命中路径只比对 shape_id,不解析键。
|
||||||
self.regs[a] = value;
|
self.regs[a] = value;
|
||||||
self.profiling.record_ic_hit();
|
self.profiling.record_ic_hit();
|
||||||
ic_trace!("IC_GET hit shape={} slot={} depth={}", cached_shape_id, cached_slot, cached_depth);
|
ic_trace!("IC_GET hit shape={} slot={} depth={}", cached_shape_id, cached_slot, cached_depth);
|
||||||
} else if let Some(template) = self.kernel_core.prop_forge().get_template(obj.shape_id()) {
|
} else {
|
||||||
self.profiling.record_ic_miss();
|
// miss 分支才解析键(IC 站点键恒为编译期字符串常量,延后解析无 ToPrimitive 副作用)。
|
||||||
prop_cache_miss();
|
let prop_name_si = self.property_key_si(self.regs[b])?;
|
||||||
if template.prop_name == prop_name_si {
|
if let Some(template) = self.kernel_core.prop_forge().get_template(obj.shape_id()) {
|
||||||
if template.position < obj.prop_vec_len() as u32 {
|
self.profiling.record_ic_miss();
|
||||||
ic_helper::write_ic_back(self.bytecode_mut(), ic_pc, obj.shape_id(), template.position, 0);
|
prop_cache_miss();
|
||||||
ic_debug!(
|
if template.prop_name == prop_name_si {
|
||||||
"IC_GET propforge hit shape={} prop={} slot={}",
|
if template.position < obj.prop_vec_len() as u32 {
|
||||||
obj.shape_id(),
|
ic_helper::write_ic_back(self.bytecode_mut(), ic_pc, obj.shape_id(), template.position, 0);
|
||||||
prop_name_si,
|
ic_debug!(
|
||||||
template.position
|
"IC_GET propforge hit shape={} prop={} slot={}",
|
||||||
);
|
obj.shape_id(),
|
||||||
self.regs[a] = obj.get_prop_shape(template.position);
|
prop_name_si,
|
||||||
|
template.position
|
||||||
|
);
|
||||||
|
self.regs[a] = obj.get_prop_shape(template.position);
|
||||||
|
} else {
|
||||||
|
ic_debug!("IC_GET miss shape={} prop={}", obj.shape_id(), prop_name_si);
|
||||||
|
self.regs[a] = self.ordinary_get(obj, prop_name_si, val)?;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
ic_debug!("IC_GET miss shape={} prop={}", obj.shape_id(), prop_name_si);
|
ic_debug!("IC_GET miss shape={} prop={}", obj.shape_id(), prop_name_si);
|
||||||
self.regs[a] = self.ordinary_get(obj, prop_name_si, val)?;
|
self.regs[a] = self.ordinary_get(obj, prop_name_si, val)?;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
prop_cache_miss();
|
||||||
ic_debug!("IC_GET miss shape={} prop={}", obj.shape_id(), prop_name_si);
|
ic_debug!("IC_GET miss shape={} prop={}", obj.shape_id(), prop_name_si);
|
||||||
self.regs[a] = self.ordinary_get(obj, prop_name_si, val)?;
|
let resolved = self.ordinary_get(obj, prop_name_si, val)?;
|
||||||
}
|
// 先试自身属性(快路径,depth=0)。
|
||||||
} else {
|
if let Some(pos) = self.kernel_core.shape_forge().lookup_position(obj.shape_id(), prop_name_si) {
|
||||||
prop_cache_miss();
|
if !obj.is_accessor_meta(pos) {
|
||||||
ic_debug!("IC_GET miss shape={} prop={}", obj.shape_id(), prop_name_si);
|
ic_helper::write_ic_back(self.bytecode_mut(), ic_pc, obj.shape_id(), pos, 0);
|
||||||
let resolved = self.ordinary_get(obj, prop_name_si, val)?;
|
ic_debug!("IC_GET write-back own shape={} slot={}", obj.shape_id(), pos);
|
||||||
// 先试自身属性(快路径,depth=0)。
|
}
|
||||||
if let Some(pos) = self.kernel_core.shape_forge().lookup_position(obj.shape_id(), prop_name_si) {
|
} else {
|
||||||
if !obj.is_accessor_meta(pos) {
|
// 沿原型链查找真正拥有该属性的对象。
|
||||||
ic_helper::write_ic_back(self.bytecode_mut(), ic_pc, obj.shape_id(), pos, 0);
|
let mut cursor = obj.proto().as_js_object_ptr();
|
||||||
ic_debug!("IC_GET write-back own shape={} slot={}", obj.shape_id(), pos);
|
let mut depth = 1u8;
|
||||||
}
|
while !cursor.is_null() {
|
||||||
} else {
|
let co_ref = unsafe { &*cursor };
|
||||||
// 沿原型链查找真正拥有该属性的对象。
|
if let Some(pos) =
|
||||||
let mut cursor = obj.proto().as_js_object_ptr();
|
self.kernel_core.shape_forge().lookup_position(co_ref.shape_id(), prop_name_si)
|
||||||
let mut depth = 1u8;
|
{
|
||||||
while !cursor.is_null() {
|
if !co_ref.is_accessor_meta(pos) {
|
||||||
let co_ref = unsafe { &*cursor };
|
ic_helper::write_ic_back(self.bytecode_mut(), ic_pc, co_ref.shape_id(), pos, depth);
|
||||||
if let Some(pos) = self.kernel_core.shape_forge().lookup_position(co_ref.shape_id(), prop_name_si) {
|
ic_debug!(
|
||||||
if !co_ref.is_accessor_meta(pos) {
|
"IC_GET write-back proto shape={} slot={} depth={}",
|
||||||
ic_helper::write_ic_back(self.bytecode_mut(), ic_pc, co_ref.shape_id(), pos, depth);
|
co_ref.shape_id(),
|
||||||
ic_debug!(
|
pos,
|
||||||
"IC_GET write-back proto shape={} slot={} depth={}",
|
depth
|
||||||
co_ref.shape_id(),
|
);
|
||||||
pos,
|
}
|
||||||
depth
|
break;
|
||||||
);
|
|
||||||
}
|
}
|
||||||
break;
|
if !co_ref.proto().is_object() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
cursor = co_ref.proto().as_js_object_ptr();
|
||||||
|
depth += 1;
|
||||||
}
|
}
|
||||||
if !co_ref.proto().is_object() {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
cursor = co_ref.proto().as_js_object_ptr();
|
|
||||||
depth += 1;
|
|
||||||
}
|
}
|
||||||
|
self.regs[a] = resolved;
|
||||||
}
|
}
|
||||||
self.regs[a] = resolved;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -390,34 +398,38 @@ impl Vm {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
};
|
};
|
||||||
|
|
||||||
let prop_name_si = self.property_key_si(self.regs[b])?;
|
// read_ic_entry 先消费 3 扩展字,命中路径无需解析键。
|
||||||
if self.kernel_core.perm_interner().lookup(prop_name_si) == Some("__proto__") {
|
|
||||||
let proto_value = self.promote_if_needed_for_write_ptr(obj_ptr, self.regs[a]);
|
|
||||||
if self.is_object_prototype(obj_ptr) && !proto_value.is_null() {
|
|
||||||
self.raise_type_error("Object.prototype.__proto__ is immutable")?;
|
|
||||||
self.pc += 3;
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
let obj = unsafe { &mut *obj_ptr };
|
|
||||||
obj.set_proto(proto_value).map_err(|e| e.to_string())?;
|
|
||||||
self.pc += 3;
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
|
|
||||||
let (cached_shape_id, cached_slot, cached_depth) = ic_helper::read_ic_entry(&self.bytecode, &mut self.pc);
|
let (cached_shape_id, cached_slot, cached_depth) = ic_helper::read_ic_entry(&self.bytecode, &mut self.pc);
|
||||||
let ic_pc = self.pc;
|
let ic_pc = self.pc;
|
||||||
let value = self.promote_if_needed_for_write_ptr(obj_ptr, self.regs[a]);
|
let value = self.promote_if_needed_for_write_ptr(obj_ptr, self.regs[a]);
|
||||||
let receiver = self.regs[rd];
|
let receiver = self.regs[rd];
|
||||||
let obj = unsafe { &mut *obj_ptr };
|
let obj = unsafe { &mut *obj_ptr };
|
||||||
|
|
||||||
|
// 命中路径零键零拦截:__proto__ 赋值从不写 IC,缓存槽必为数据槽。
|
||||||
|
if !obj.has_prop_meta() && ic_set_hit(obj, cached_shape_id, cached_slot, cached_depth, value) {
|
||||||
|
self.profiling.record_ic_hit();
|
||||||
|
ic_trace!("IC_SET hit shape={} slot={} depth={}", cached_shape_id, cached_slot, cached_depth);
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 慢路径(has_prop_meta / miss)才解析键并拦截 __proto__ 赋值,须先于写槽,
|
||||||
|
// 防 __proto__ 落入数据槽。
|
||||||
|
let prop_name_si = self.property_key_si(self.regs[b])?;
|
||||||
|
if self.kernel_core.perm_interner().lookup(prop_name_si) == Some("__proto__") {
|
||||||
|
if self.is_object_prototype(obj_ptr) && !value.is_null() {
|
||||||
|
self.raise_type_error("Object.prototype.__proto__ is immutable")?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
obj.set_proto(value).map_err(|e| e.to_string())?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
if obj.has_prop_meta() {
|
if obj.has_prop_meta() {
|
||||||
self.ordinary_set_dispatch(obj, prop_name_si, value, receiver)?;
|
self.ordinary_set_dispatch(obj, prop_name_si, value, receiver)?;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
if ic_set_hit(obj, cached_shape_id, cached_slot, cached_depth, value) {
|
if let Some(pos) = self.kernel_core.shape_forge().lookup_position(obj.shape_id(), prop_name_si) {
|
||||||
self.profiling.record_ic_hit();
|
|
||||||
ic_trace!("IC_SET hit shape={} slot={} depth={}", cached_shape_id, cached_slot, cached_depth);
|
|
||||||
} else if let Some(pos) = self.kernel_core.shape_forge().lookup_position(obj.shape_id(), prop_name_si) {
|
|
||||||
self.profiling.record_ic_miss();
|
self.profiling.record_ic_miss();
|
||||||
prop_cache_miss();
|
prop_cache_miss();
|
||||||
obj.set_prop_shape(pos, value);
|
obj.set_prop_shape(pos, value);
|
||||||
|
|||||||
Reference in New Issue
Block a user