refactor: 退役逃逸写屏障 vm 侧调用点与固有方法

This commit is contained in:
2026-10-03 01:24:15 +00:00
parent bd7426b23b
commit 3ad2a4dca4
5 changed files with 25 additions and 45 deletions
-1
View File
@@ -717,7 +717,6 @@ impl Vm {
self.raise_error_kind("TypeError", "SET_HOME_OBJECT expects function and object")?;
return Ok(true);
}
let home_val = self.promote_if_needed_for_write_ptr(func_val.as_js_object_ptr(), home_val);
let func_obj = unsafe { &mut *func_val.as_js_object_ptr() };
if !func_obj.is_function() {
self.raise_error_kind("TypeError", "SET_HOME_OBJECT target is not a function")?;
+14 -17
View File
@@ -228,7 +228,7 @@ impl Vm {
return self.raise_type_error("private field has no setter");
}
let setter = meta.set;
let value = self.promote_if_needed_for_write_ptr(obj_ptr, self.regs[a]);
let value = self.regs[a];
return self.call_or_push_setter(setter, obj_val, value, true);
}
// 私有方法槽不可写(init 时打标记)。
@@ -237,7 +237,7 @@ impl Vm {
.raise_type_error("Cannot write private member to an object whose class did not declare it");
}
}
let value = self.promote_if_needed_for_write_ptr(obj_ptr, self.regs[a]);
let value = self.regs[a];
let obj = unsafe { &mut *obj_ptr };
obj.set_prop_shape(pos, value);
return Ok(());
@@ -257,7 +257,7 @@ impl Vm {
return self.raise_type_error("private field has no setter");
}
let setter = meta.set;
let value = self.promote_if_needed_for_write_ptr(obj_ptr, self.regs[a]);
let value = self.regs[a];
return self.call_or_push_setter(setter, obj_val, value, true);
}
// 私有方法槽不可写(init 时打标记)。
@@ -266,7 +266,7 @@ impl Vm {
.raise_type_error("Cannot write private member to an object whose class did not declare it");
}
}
let value = self.promote_if_needed_for_write_ptr(home_ptr, self.regs[a]);
let value = self.regs[a];
let home = unsafe { &mut *home_ptr };
home.set_prop_shape(pos, value);
Ok(())
@@ -281,7 +281,7 @@ impl Vm {
let private_key = self.private_key_from_reg(b);
let is_method = self.bytecode[self.pc] != 0;
self.pc += 1;
let value = self.promote_if_needed_for_write_ptr(obj_ptr, self.regs[a]);
let value = self.regs[a];
let obj = unsafe { &mut *obj_ptr };
if self
.kernel_core
@@ -453,7 +453,7 @@ impl Vm {
// read_ic_slot0 先消费全部扩展字,命中路径无需解析键。
let (cached_shape_id, cached_slot, cached_depth) = ic_helper::read_ic_slot0(&self.bytecode, &mut self.pc);
let ic_pc = self.pc;
let value = self.promote_if_needed_for_write_ptr(obj_ptr, self.regs[a]);
let value = self.regs[a];
let receiver = self.regs[rd];
let obj = unsafe { &mut *obj_ptr };
@@ -534,7 +534,7 @@ impl Vm {
};
let prop_name_si = self.property_key_si(self.regs[b])?;
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]);
let proto_value = self.regs[a];
if self.is_object_prototype(obj_ptr) && !proto_value.is_null() {
self.raise_type_error("Object.prototype.__proto__ is immutable")?;
return Ok(());
@@ -543,25 +543,24 @@ impl Vm {
obj.set_proto(proto_value).map_err(|e| e.to_string())?;
return Ok(());
}
let value = self.promote_if_needed_for_write_ptr(obj_ptr, self.regs[a]);
let value = self.regs[a];
let obj = unsafe { &mut *obj_ptr };
self.ordinary_set_dispatch(obj, prop_name_si, value, self.regs[rd], self.current_strict())?;
Ok(())
}
/// 对象字面量批量构造的纯槽写:把值写入键序预建 shape 的 `slot` 槽。
/// 不做键解析/`__proto__` 拦截/promote 之外的任何形状变更——键与槽位由
/// 不做键解析、`__proto__` 拦截或任何形状变更——键与槽位由
/// NEW_OBJECT 的键常量表一次性建好。
///
/// # 边界与前提
/// - `slot` 必须 < NEW_OBJECT 预分配的槽数(emit 保证 ≤255)。
/// - 值仍需 promote(对象值可能来自 session epoch 且目标是逃逸根)。
fn dispatch_set_prop_batch(&mut self, rd: usize, a: usize, b: usize) -> Result<(), String> {
vm_trace!("SET_PROP_BATCH rd={} slot={}", rd, b);
let Some(obj_ptr) = self.checked_object_ptr(self.regs[rd], "Cannot create property on non-object")? else {
return Ok(());
};
let value = self.promote_if_needed_for_write_ptr(obj_ptr, self.regs[a]);
let value = self.regs[a];
let obj = unsafe { &mut *obj_ptr };
obj.set_prop_storage(b, value);
Ok(())
@@ -619,9 +618,7 @@ impl Vm {
if obj.is_array() && obj.array_elements_meta_vec().is_none() {
let idx = int_key_value(prop_name_si);
if idx < obj.array_prop_count {
// promote 必须保留:obj 是 session 根、写入值可能是 epoch 对象,
// 不 promote 下轮 GC 会悬垂。
let value = self.promote_if_needed_for_write_ptr(obj_ptr, self.regs[b]);
let value = self.regs[b];
let obj = unsafe { &mut *obj_ptr };
obj.set_prop_storage(idx as usize, value);
return Ok(());
@@ -631,7 +628,7 @@ impl Vm {
// 整数键恒不可能等于 "__proto__"(字符串 intern id 远小于整数键区间),
// 短路免去每次 set 的 RwLock 查询。
if !is_int_key(prop_name_si) && 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[b]);
let proto_value = self.regs[b];
if self.is_object_prototype(obj_ptr) && !proto_value.is_null() {
self.raise_type_error("Object.prototype.__proto__ is immutable")?;
return Ok(());
@@ -640,7 +637,7 @@ impl Vm {
obj.set_proto(proto_value).map_err(|e| e.to_string())?;
return Ok(());
}
let value = self.promote_if_needed_for_write_ptr(obj_ptr, self.regs[b]);
let value = self.regs[b];
let obj = unsafe { &mut *obj_ptr };
self.ordinary_set_dispatch(obj, prop_name_si, value, self.regs[rd], self.current_strict())?;
Ok(())
@@ -658,7 +655,7 @@ impl Vm {
} else {
0
};
let value = self.promote_if_needed_for_write_ptr(obj_ptr, self.regs[b]);
let value = self.regs[b];
let obj = unsafe { &mut *obj_ptr };
// 有属性 meta(freeze/seal 逐属性写 meta 后恒 true,含 accessor 元素/描述符
// 元素):回落 ordinary_set 走完整 writable/accessor/extensible 检查,防止
+8 -12
View File
@@ -1080,8 +1080,7 @@ impl Vm {
));
let rest = unsafe { &mut *rest_ptr };
for (si, val) in assignments {
let promoted = self.promote_if_needed_for_write_ptr(rest_ptr, val);
self.set_or_create_prop_value(rest, si, promoted);
self.set_or_create_prop_value(rest, si, val);
}
self.regs[rd] = JsValue::from_js_object(rest_ptr);
Ok(())
@@ -1156,8 +1155,7 @@ impl Vm {
// 提交:覆盖目标已有同名属性(从左到右求值,后展开者胜)。
let target = unsafe { &mut *target_val.as_js_object_ptr() };
for (si, val) in assignments {
let promoted = self.promote_if_needed_for_write_ptr(target, val);
self.set_or_create_prop_value(target, si, promoted);
self.set_or_create_prop_value(target, si, val);
}
Ok(())
}
@@ -1199,9 +1197,9 @@ impl Vm {
let proto_ptr = self.session.builtin_world().array_proto.as_ptr() as *mut JsObject;
let proto_val = JsValue::from_js_object(proto_ptr);
// 模板对象直接分配为 session 对象:跨 epoch 写入(存进 global/数组)时
// 免 promote 搬移——若按 epoch 分配,首次写入 session 根会把对象搬到新
// 地址,缓存中的旧指针与新实例分叉,同一 site 两次取值将返回不同对象。
// 模板对象直接分配为 session 对象:写入 session 根(存进 global/数组)
// 时对象地址稳定,缓存指针不失效——分配档不同则首次写入触发搬移,
// 缓存旧指针与新实例分叉,同一 site 两次取值将返回不同对象。
let mut alloc_session_array = |n: usize| {
let clone = JsObject::new_array(oxide_kernel::shape_forge::EMPTY_SHAPE_ID, proto_val, n, self.epoch.bump());
self.alloc_session_object(clone)
@@ -1215,7 +1213,7 @@ impl Vm {
let elem_attrs = PropAttributes::new(false, true, false);
for i in 0..n {
let (c_val, r_val) = {
// immutables 借用限于本块:promote 需 &mut self,先取值再放行借用。
// immutables 借用限于本块:先取出本段两值,再放行借用。
let imm = self.immutables();
let c_val = if cooked_words[i] & 0x8000_0000 != 0 {
JsValue::undefined()
@@ -1225,13 +1223,11 @@ impl Vm {
let r_val = imm.get(raw_idxs[i] as usize).copied().unwrap_or(JsValue::undefined());
(c_val, r_val)
};
let c_promoted = self.promote_if_needed_for_write_ptr(cooked, c_val);
let r_promoted = self.promote_if_needed_for_write_ptr(raw, r_val);
// SAFETY: cooked/raw 为本函数刚分配的 epoch 对象,借用仅在本循环内消费。
unsafe {
(*cooked).set_prop_at(i, c_promoted);
(*cooked).set_prop_at(i, c_val);
(*cooked).set_data_meta(i, elem_attrs);
(*raw).set_prop_at(i, r_promoted);
(*raw).set_prop_at(i, r_val);
(*raw).set_data_meta(i, elem_attrs);
}
}
+1 -8
View File
@@ -326,7 +326,6 @@ impl Vm {
pub(crate) fn ordinary_set(
&mut self, obj: &mut JsObject, prop_name_si: u32, val: JsValue, receiver: JsValue, strict: bool,
) -> Result<(), String> {
let val = self.promote_if_needed_for_write_ptr(obj as *mut JsObject, val);
self.ordinary_set_inner(obj, prop_name_si, val, receiver, false, strict, false)
}
@@ -336,11 +335,10 @@ impl Vm {
pub(crate) fn ordinary_set_builtin(
&mut self, obj: &mut JsObject, prop_name_si: u32, val: JsValue, receiver: JsValue, strict: bool,
) -> Result<(), String> {
let val = self.promote_if_needed_for_write_ptr(obj as *mut JsObject, val);
self.ordinary_set_inner(obj, prop_name_si, val, receiver, false, strict, true)
}
/// 分发期入口:调用方(dispatch_set_prop 等)已对值做过 promote。
/// 分发期入口:值直接落位。
pub(crate) fn ordinary_set_dispatch(
&mut self, obj: &mut JsObject, prop_name_si: u32, val: JsValue, receiver: JsValue, strict: bool,
) -> Result<(), String> {
@@ -792,7 +790,6 @@ impl Vm {
&mut self, obj: &mut JsObject, prop_name_si: u32, val: JsValue, receiver: JsValue, ext_pc: usize,
) -> Result<(), String> {
ic_trace!("set_member_prop: shape_id={} prop_name_si={}", obj.shape_id(), prop_name_si);
let val = self.promote_if_needed_for_write_ptr(obj as *mut JsObject, val);
// 写方即当前执行函数(赋值语义),strict/sloppy 判定取当前上下文。
let strict = self.current_strict();
if obj.has_prop_meta() {
@@ -1008,7 +1005,6 @@ impl Vm {
&mut self, obj: &mut JsObject, prop_name_si: u32, val: JsValue, attributes: PropAttributes,
) -> Result<(), String> {
vm_trace!("define_data_property: shape={} prop_si={}", obj.shape_id(), prop_name_si);
let val = self.promote_if_needed_for_write_ptr(obj as *mut JsObject, val);
// TypedArray 统一数值键门:界内规范键走元素定义(界内写 buffer);
// 规范越界键(含 detach:live 长 0)拒绝定义;非规范数值串
// ("+1"/"1.0" 等,round-trip 不成)与 symbol 键落命名属性路径。
@@ -1129,9 +1125,6 @@ impl Vm {
&mut self, obj: &mut JsObject, prop_name_si: u32, get: JsValue, set: JsValue, attributes: PropAttributes,
) -> Result<(), String> {
vm_trace!("define_accessor_property: shape={} prop_si={}", obj.shape_id(), prop_name_si);
let target_ptr = obj as *mut JsObject;
let get = self.promote_if_needed_for_write_ptr(target_ptr, get);
let set = self.promote_if_needed_for_write_ptr(target_ptr, set);
// TA 数值索引臂:界内 / 数字无效索引不接受 accessor(false);非规范数字
// 串 / symbol 键落真实 accessor 属性。
if obj.is_typed_array_obj() {
+2 -7
View File
@@ -555,11 +555,6 @@ impl Vm {
self.active_reg_limit = 0;
}
/// 逃逸写屏障:写向全局/session 目标的对象值原样直通,不克隆。
pub(crate) fn promote_if_needed_for_write_ptr(&mut self, _target_ptr: *mut JsObject, value: JsValue) -> JsValue {
value
}
/// 分配一个可被 session GC 回收的字符串 `JsValue`(session-heap 字符串)。
pub fn new_string(&mut self, s: &str) -> JsValue {
self.new_string_owned(s.to_string())
@@ -719,8 +714,8 @@ impl Vm {
obj.set_captured_this(self.regs[254]);
}
// 函数对象直接 session 分配:寿命从调用级延至 session 级(session GC
// mark/sweep 回收)。若按 epoch 分配,写入全局等逃逸根时 promote 屏障会
// 深克隆进 session,全局属性与局部槽指针分裂、严格相等恒 false。
// mark/sweep 回收),写入全局等逃逸根时地址稳定,全局属性与局部槽
// 指向同一对象,严格相等保持。
let obj_ptr = self.alloc_session_object(obj);
let func_val = JsValue::object(obj_ptr as *mut u8);