diff --git a/crates/oxide_vm/src/dispatch/call.rs b/crates/oxide_vm/src/dispatch/call.rs index 0247c67f..19c35634 100644 --- a/crates/oxide_vm/src/dispatch/call.rs +++ b/crates/oxide_vm/src/dispatch/call.rs @@ -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")?; diff --git a/crates/oxide_vm/src/dispatch/property.rs b/crates/oxide_vm/src/dispatch/property.rs index d7947638..aae4edaa 100644 --- a/crates/oxide_vm/src/dispatch/property.rs +++ b/crates/oxide_vm/src/dispatch/property.rs @@ -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 检查,防止 diff --git a/crates/oxide_vm/src/vm_dispatch_misc.rs b/crates/oxide_vm/src/vm_dispatch_misc.rs index 4d5a8369..5c752769 100644 --- a/crates/oxide_vm/src/vm_dispatch_misc.rs +++ b/crates/oxide_vm/src/vm_dispatch_misc.rs @@ -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); } } diff --git a/crates/oxide_vm/src/vm_props.rs b/crates/oxide_vm/src/vm_props.rs index bdce5798..30c8b776 100644 --- a/crates/oxide_vm/src/vm_props.rs +++ b/crates/oxide_vm/src/vm_props.rs @@ -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() { diff --git a/crates/oxide_vm/src/vm_support.rs b/crates/oxide_vm/src/vm_support.rs index 82f7046d..26fb4a1d 100644 --- a/crates/oxide_vm/src/vm_support.rs +++ b/crates/oxide_vm/src/vm_support.rs @@ -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);