From 32e8dce0035ad98262e46bf8c5cb4a375e726a28 Mon Sep 17 00:00:00 2001 From: pjh456 <147148383@qq.com> Date: Tue, 22 Sep 2026 21:56:48 +0000 Subject: [PATCH] =?UTF-8?q?fix:=20=E7=BB=91=E5=AE=9A=E5=87=BD=E6=95=B0?= =?UTF-8?q?=E7=8A=B6=E6=80=81=E7=A7=BB=E5=85=A5=E7=8A=B6=E6=80=81=E5=AF=B9?= =?UTF-8?q?=E8=B1=A1=E9=98=B2=E5=93=88=E5=B8=8C=E6=A7=BD=E5=86=B2=E7=AA=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crates/oxide_builtins/src/function.rs | 51 +++++++++++++++++-------- crates/oxide_vm/src/vm_dispatch_misc.rs | 13 ++++--- 2 files changed, 43 insertions(+), 21 deletions(-) diff --git a/crates/oxide_builtins/src/function.rs b/crates/oxide_builtins/src/function.rs index 793d0c4f..b7949ff8 100644 --- a/crates/oxide_builtins/src/function.rs +++ b/crates/oxide_builtins/src/function.rs @@ -88,8 +88,7 @@ pub fn function_symbol_has_instance(vm: &mut H, args: &[u8]) -> Nativ // bound 包装:[[BoundTargetFunction]] 递归到最内层 target 判定 // (InstanceofOperator 语义,target 链上的 @@hasInstance 解析到本函数)。 while c_obj.type_tag == oxide_types::object::JsObject::OBJ_TYPE_BOUND { - let props = c_obj.hash_props_vec().cloned().unwrap_or_default(); - let target = props.get(4).copied().unwrap_or(JsValue::undefined()); + let target = bound_state_values(c_obj).first().copied().unwrap_or(JsValue::undefined()); if !target.is_object() || target.as_js_object_ptr().is_null() || !unsafe { &*target.as_js_object_ptr() }.is_function() @@ -138,16 +137,14 @@ pub fn function_symbol_has_instance(vm: &mut H, args: &[u8]) -> Nativ fn bind_dispatcher(vm: &mut H, args: &[u8]) -> NativeResult { let wrapper_val = vm.reg(254); let wrapper = unsafe { &*wrapper_val.as_js_object_ptr() }; - // dense 布局:[length, name, caller, arguments, target, thisArg, ...boundArgs]—— - // 前 4 槽是 shape 属性(length/name 数据 + caller/arguments 访问器占位), - // 绑定状态从槽位 4 起(shape 槽位与 dense 下标对齐)。 - let props = wrapper.hash_props_vec().cloned().unwrap_or_default(); - let bound_target = props.get(4).copied().unwrap_or(JsValue::undefined()); - let bound_this = props.get(5).copied().unwrap_or(JsValue::undefined()); + // 绑定状态对象布局 [target, thisArg, ...boundArgs](见 bound_state_values)。 + let state = bound_state_values(wrapper); + let bound_target = state.first().copied().unwrap_or(JsValue::undefined()); + let bound_this = state.get(1).copied().unwrap_or(JsValue::undefined()); - // 拼接调用实参:绑定实参(props[6..])在前,本次调用实参(跳过 args[0] + // 拼接调用实参:绑定实参(存储槽 2+)在前,本次调用实参(跳过 args[0] // 即绑定包装器的 receiver)在后,与规范的"绑定实参先于调用实参"一致。 - let mut call_args: Vec = props.iter().skip(6).copied().collect(); + let mut call_args: Vec = state.iter().skip(2).copied().collect(); for &r in args.iter().skip(1) { call_args.push(vm.reg(r)); } @@ -238,8 +235,9 @@ pub fn function_bind(vm: &mut H, args: &[u8]) -> NativeResult { (*wrapper).set_native_arg_count(bound_arg_count as u8); } - // length/name 先定义占 dense 槽位 0/1(shape 属性),绑定状态 [target, thisArg, - // ...boundArgs] 随后从槽位 2 起存放,保证 shape 槽位与 dense 下标对齐。 + // length/name/caller/arguments 先定义占 shape 槽位 0..3(length/name 数据 + + // caller/arguments 访问器占位);绑定状态随后以独立状态对象存为第 4 号 shape + // 属性(保留键),不与用户 own 属性共享下标空间。 let length_si = vm.kernel_core().perm_interner().intern("length").0; let name_si = vm.kernel_core().perm_interner().intern("name").0; let caller_si = vm.kernel_core().perm_interner().intern("caller").0; @@ -293,18 +291,39 @@ pub fn function_bind(vm: &mut H, args: &[u8]) -> NativeResult { return NativeResult::Err(crate::error::create_type_error(vm, &e)); } } + // 绑定状态([target, thisArg, ...boundArgs])存独立状态对象:命名属性存储与 + // shape 槽位共享下标,状态值若直接裸推包装器存储槽 4+,用户新增 own 属性时 + // shape 槽位与存储下标错位(读写互串)。状态对象内部存储不占 shape 槽位, + // 经保留键作为包装器固定第 4 号 shape 属性暴露,用户代码不可见。 + let object_proto = vm.session().builtin_world().object_proto.as_ptr() as *mut JsObject; + let state = vm.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::from_js_object(object_proto))); unsafe { - let props = (*wrapper).ensure_hash_props(); - props.push(target_val); - props.push(bound_this); + let state_props = (*state).ensure_hash_props(); + state_props.push(target_val); + state_props.push(bound_this); for &r in args.iter().skip(2) { - props.push(vm.reg(r)); + state_props.push(vm.reg(r)); } } + let state_si = vm.kernel_core().perm_interner().intern("\u{0}bound-state").0; + if let Err(e) = vm.define_data_property(unsafe { &mut *wrapper }, state_si, JsValue::from_js_object(state), attrs) { + return NativeResult::Err(crate::error::create_type_error(vm, &e)); + } NativeResult::Ok(JsValue::from_js_object(wrapper)) } +/// 读 bound 包装器固定第 4 号 shape 属性处的状态对象,返回其存储 +/// [target, thisArg, ...boundArgs](缺位时返回空 vec)。 +pub fn bound_state_values(wrapper: &JsObject) -> Vec { + wrapper + .hash_props_vec() + .and_then(|props| props.get(4).copied()) + .filter(|v| v.is_object() && !v.as_js_object_ptr().is_null()) + .and_then(|sv| unsafe { &*sv.as_js_object_ptr() }.hash_props_vec().cloned()) + .unwrap_or_default() +} + /// bound 函数 caller/arguments 的受限访问器:任何访问(get/set)都抛 TypeError。 fn bound_restricted_thrower(vm: &mut H, _args: &[u8]) -> NativeResult { NativeResult::Err(crate::error::create_type_error( diff --git a/crates/oxide_vm/src/vm_dispatch_misc.rs b/crates/oxide_vm/src/vm_dispatch_misc.rs index 7cabbb24..3a931d0a 100644 --- a/crates/oxide_vm/src/vm_dispatch_misc.rs +++ b/crates/oxide_vm/src/vm_dispatch_misc.rs @@ -170,8 +170,9 @@ impl Vm { /// bound 函数构造分支:按 bound [[Construct]] 语义解包链后转发到最内层 target。 /// /// # 步骤 - /// 1. 逐层解包 [[BoundTargetFunction]]:每层绑定实参(dense 槽 6+)拼到调用 - /// 实参之前(外层先解包 → 最终顺序为内层绑定实参先、外层后、调用实参尾) + /// 1. 逐层解包 [[BoundTargetFunction]]:每层绑定实参(状态对象存储槽 2+) + /// 拼到调用实参之前(外层先解包 → 最终顺序为内层绑定实参先、外层后、 + /// 调用实参尾) /// 2. 校验最内层 target 可构造(native 须 CONSTRUCTOR 标记;字节码须非 /// arrow/async/generator),否则抛 TypeError /// 3. 新对象原型取 target.prototype(new 表达式路径 newTarget 恒等于构造器, @@ -190,9 +191,11 @@ impl Vm { let mut target_val = wrapper_val; loop { let wrapper_obj = unsafe { &*target_val.as_js_object_ptr() }; - let props = wrapper_obj.hash_props_vec().cloned().unwrap_or_default(); - let target = props.get(4).copied().unwrap_or(JsValue::undefined()); - let mut combined: Vec = props.iter().skip(6).copied().collect(); + // 绑定状态对象 [target, thisArg, ...boundArgs](oxide_builtins::function + // 固定第 4 号 shape 属性):target 取存储槽 0,绑定实参取存储槽 2+。 + let state = oxide_builtins::function::bound_state_values(wrapper_obj); + let target = state.first().copied().unwrap_or(JsValue::undefined()); + let mut combined: Vec = state.iter().skip(2).copied().collect(); combined.extend_from_slice(&call_args); call_args = combined; let is_bound = target.is_object()