//! DisposableStack(同步资源栈)与 AsyncDisposableStack(异步资源栈)内置对象实现。 //! //! 状态盒 `DisposeCapability` 以 `Box::into_raw` 存入对象 `native_data`:`state` //! 记录栈状态,`entries` 按入栈序存待释放资源。同步栈 dispose 只用 //! Pending/Disposed 两态;Disposing 为异步资源栈 disposeAsync 执行期标记 //! (当前状态机只置 Disposed,变体语义预留)。两栈共用本模块:方法按 //! `type_tag` 为 `JsObject::OBJ_TYPE_DISPOSABLE_STACK`(同步)或 //! `OBJ_TYPE_ASYNC_DISPOSABLE_STACK`(异步)时区分接收者,`hint` 以 0/1 两值区分 //! 条目释放语义(定义见 `DisposeEntry.hint`),`wrap_sync` 标记 async 栈 use 落回 //! `@@dispose` 的条目(返回值丢弃、异常异步化)。GC 三函数 //! (edges/size/drop)接线 mark 边、字节账目与释放,形态与 Map/Promise //! 状态盒同构。 use oxide_kernel::shape_forge::EMPTY_SHAPE_ID; use oxide_types::object::JsObject; use oxide_types::private_key::encode_symbol_key; use oxide_types::value::JsValue; use oxide_runtime_api::{NativeResult, ProtoKind, VmHost}; /// 分配空状态盒并存入新资源栈对象(proto 与 type_tag 按栈类型传入)。 fn alloc_disposable_stack(vm: &mut H, proto_val: JsValue, type_tag: u8) -> *mut JsObject { let mut obj = JsObject::new_empty(EMPTY_SHAPE_ID, proto_val); obj.type_tag = type_tag; obj.set_native_data(Box::into_raw(Box::new(DisposeCapability { state: DisposeState::Pending, entries: Vec::new(), })) as *mut u8); vm.alloc_object(obj) } macro_rules! native_try { ($expr:expr) => { match $expr { Ok(value) => value, Err(err) => return NativeResult::Err(err), } }; } /// 取出栈对象 native-data 槽中的 `DisposeCapability` 可变指针。 /// /// # 边界与前提 /// - this 非对象 → TypeError; /// - type_tag 非 24/25 → TypeError(无槽对象); /// - native_data 为空 → TypeError(防御,正常构造路径不会出现)。 pub fn require_dispose_capability( vm: &mut H, this_val: JsValue, type_tag: u8, ) -> Result<*mut DisposeCapability, JsValue> { if !this_val.is_object() { return Err(crate::error::create_type_error(vm, "called on non-DisposableStack object")); } let obj_ptr = this_val.as_js_object_ptr(); if obj_ptr.is_null() { return Err(crate::error::create_type_error(vm, "DisposableStack internal state invalid")); } // SAFETY: obj_ptr 是 JsObject 的非空、对齐指针;对象在 native 执行期间 // 被根保持、不被回收,指针在本调用内有效。 let obj = unsafe { &*obj_ptr }; if obj.type_tag != type_tag { return Err(crate::error::create_type_error( vm, "DisposableStack.prototype method called on incompatible receiver", )); } let cap_ptr = get_capability_ptr(obj); if cap_ptr.is_null() { return Err(crate::error::create_type_error(vm, "DisposableStack internal state invalid")); } Ok(cap_ptr) } fn disposed_reference_error(vm: &mut H) -> JsValue { crate::error::create_reference_error(vm, "DisposableStack has been disposed") } /// 接收者原型链是否命中对应栈类型内建原型(上限 16 层,普通调用接收者不命中)。 fn receiver_intrinsic_proto(this_val: JsValue, stack_proto_val: JsValue) -> bool { if !this_val.is_object() { return false; } let this_ptr = this_val.as_js_object_ptr(); if this_ptr.is_null() { return false; } let stack_proto = stack_proto_val.as_js_object_ptr(); // SAFETY: this_ptr 是 is_object 校验过的当前 session 存活对象指针。 let mut proto = unsafe { &*this_ptr }.proto(); for _ in 0..16 { if !proto.is_object() { return false; } let proto_ptr = proto.as_js_object_ptr(); if proto_ptr.is_null() { return false; } if std::ptr::eq(proto_ptr, stack_proto) { return true; } // SAFETY: 同上,proto 链指针本 session 存活。 proto = unsafe { &*proto_ptr }.proto(); } false } /// 资源栈构造器公共实现:构造形态校验后经 GpFC 推导原型,建带空状态盒的栈对象。 /// /// # 步骤 /// 1. 非构造形态 → TypeError。构造形态标记由 NEW/SUPER/construct_with 三入口置位、 /// 普通调用入口清零;标记未置位的直接 native 调用形态以接收者原型链命中 /// 对应内建原型视同构造形态。 /// 2. GetPrototypeFromConstructor:传播式读 new.target 的 "prototype"(访问器 /// 副作用与异常原值传播);非对象结果回落本栈类型内建原型。 /// 3. 建空状态盒对象,proto 与 type_tag 按栈类型传入。 fn stack_constructor_impl(vm: &mut H, args: &[u8], proto_val: JsValue, type_tag: u8) -> NativeResult { let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] }); if !vm.constructing_native() && !receiver_intrinsic_proto(this_val, proto_val) { return NativeResult::Err(crate::error::create_type_error(vm, "DisposableStack must be called with new")); } let new_target = vm.reg(255); let gpf_proto = if new_target.is_object() { let nt_ptr = new_target.as_js_object_ptr(); // SAFETY: is_object 保证指针非空且对象本 session 存活。 let nt_obj = unsafe { &*nt_ptr }; let proto_si = vm.perm_intern("prototype"); let proto = match vm.ordinary_get(nt_obj, proto_si, new_target) { Ok(v) => v, Err(err) => return NativeResult::Err(crate::iterator::engine_error(vm, &err)), }; if proto.is_object() { proto } else { proto_val } } else { proto_val }; let stack = alloc_disposable_stack(vm, gpf_proto, type_tag); NativeResult::Ok(JsValue::from_js_object(stack)) } /// `DisposableStack` 构造函数:创建带空状态盒的 DisposableStack 对象。 pub fn disposable_stack_constructor(vm: &mut H, args: &[u8]) -> NativeResult { let proto_val = JsValue::from_js_object(vm.builtin_proto(ProtoKind::DisposableStackProto)); stack_constructor_impl(vm, args, proto_val, JsObject::OBJ_TYPE_DISPOSABLE_STACK) } /// `AsyncDisposableStack` 构造函数:创建带空状态盒的 AsyncDisposableStack 对象。 pub fn async_disposable_stack_constructor(vm: &mut H, args: &[u8]) -> NativeResult { let proto_val = JsValue::from_js_object(vm.builtin_proto(ProtoKind::AsyncDisposableStackProto)); stack_constructor_impl(vm, args, proto_val, JsObject::OBJ_TYPE_ASYNC_DISPOSABLE_STACK) } /// `DisposableStack.prototype.use(value)`:把资源的 `value[@@dispose]` 方法入栈。 /// /// # 步骤 /// 1. 校验栈对象与状态;Disposed 抛 ReferenceError。 /// 2. value 为 null/undefined → 直接返回 value 不入栈。 /// 3. value 非对象 → TypeError。 /// 4. 读 `value[@@dispose]`(只读一次,getter 抛错透传原值);缺/null/undefined/ /// 非 callable → TypeError。 /// 5. 入栈 `{value, method, sync, receiver 模式}`,返回 value。 pub fn disposable_stack_use(vm: &mut H, args: &[u8]) -> NativeResult { let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] }); let cap = native_try!(require_dispose_capability(vm, this_val, JsObject::OBJ_TYPE_DISPOSABLE_STACK)); // SAFETY: cap 由 require 校验,native 执行期间对象存活。 let cap_ref = unsafe { &mut *cap }; if cap_ref.state != DisposeState::Pending { return NativeResult::Err(disposed_reference_error(vm)); } let value = vm.reg(if args.len() > 1 { args[1] } else { 0 }); if value.is_null() || value.is_undefined() { return NativeResult::Ok(value); } if !value.is_object() { return NativeResult::Err(crate::error::create_type_error(vm, "value is not an Object")); } let value_obj = unsafe { &*value.as_js_object_ptr() }; let dispose_key = oxide_types::private_key::encode_symbol_key(vm.realm_id(), 12); let method = match vm.ordinary_get(value_obj, dispose_key, value) { Ok(m) => m, Err(err) => return NativeResult::Err(crate::iterator::engine_error(vm, &err)), }; if method.is_null() || method.is_undefined() || !crate::iterator::is_callable(method) { return NativeResult::Err(crate::error::create_type_error(vm, "value[Symbol.dispose] is not callable")); } cap_ref.entries.push(DisposeEntry { value, method, hint: 0, arg_style: false, wrap_sync: false, }); NativeResult::Ok(value) } /// `DisposableStack.prototype.adopt(value, onDispose)`:把 value 与其释放回调入栈。 /// /// # 步骤 /// 1. 校验栈对象与状态;Disposed 抛 ReferenceError。 /// 2. onDispose 非 callable → TypeError。 /// 3. 入栈 `{value, onDispose, sync, arg-style}`(dispose 时 `Call(onDispose, undefined, «value»)`), /// 返回 value。 pub fn disposable_stack_adopt(vm: &mut H, args: &[u8]) -> NativeResult { let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] }); let cap = native_try!(require_dispose_capability(vm, this_val, JsObject::OBJ_TYPE_DISPOSABLE_STACK)); // SAFETY: cap 由 require 校验,native 执行期间对象存活。 let cap_ref = unsafe { &mut *cap }; if cap_ref.state != DisposeState::Pending { return NativeResult::Err(disposed_reference_error(vm)); } let value = vm.reg(if args.len() > 1 { args[1] } else { 0 }); let on_dispose = vm.reg(if args.len() > 2 { args[2] } else { 0 }); if !crate::iterator::is_callable(on_dispose) { return NativeResult::Err(crate::error::create_type_error(vm, "onDispose is not callable")); } cap_ref.entries.push(DisposeEntry { value, method: on_dispose, hint: 0, arg_style: true, wrap_sync: false, }); NativeResult::Ok(value) } /// `AsyncDisposableStack.prototype.use(value)`:把资源的 `value[@@asyncDispose]` /// 方法入栈(缺失时回落 `@@dispose`)。 /// /// # 步骤 /// 1. 校验栈对象(type_tag=25)与状态;Disposed 抛 ReferenceError。 /// 2. value 为 null/undefined → 入栈 method=undefined 的 async 条目并返回原值 /// (与同步栈相反:须记录资源求值,保证 disposeAsync 仍执行 Await)。 /// 3. value 非对象 → TypeError。 /// 4. 读 `value[@@asyncDispose]`(键 11,getter 抛错透传原值);结果缺失 /// (null/undefined)→ 回落读 `value[@@dispose]`(键 12);两者均缺 → /// TypeError;任一读取结果非 callable → TypeError(不回落)。 /// 5. 键 11 得 callable → 入栈 `{value, method, async, receiver 模式, wrap_sync=false}`; /// 键 12 得 callable → 入栈 `{value, method, async, receiver 模式, wrap_sync=true}` /// (同步方法返回值丢弃、异常异步化)。返回 value。 pub fn async_disposable_stack_use(vm: &mut H, args: &[u8]) -> NativeResult { let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] }); let cap = native_try!(require_dispose_capability(vm, this_val, JsObject::OBJ_TYPE_ASYNC_DISPOSABLE_STACK)); // SAFETY: cap 由 require 校验,native 执行期间对象存活。 let cap_ref = unsafe { &mut *cap }; if cap_ref.state != DisposeState::Pending { return NativeResult::Err(disposed_reference_error(vm)); } let value = vm.reg(if args.len() > 1 { args[1] } else { 0 }); if value.is_null() || value.is_undefined() { cap_ref.entries.push(DisposeEntry { value, method: JsValue::undefined(), hint: 1, arg_style: false, wrap_sync: false, }); return NativeResult::Ok(value); } if !value.is_object() { return NativeResult::Err(crate::error::create_type_error(vm, "value is not an Object")); } let value_obj = unsafe { &*value.as_js_object_ptr() }; let async_dispose_key = encode_symbol_key(vm.realm_id(), 11); let method = match vm.ordinary_get(value_obj, async_dispose_key, value) { Ok(m) => m, Err(err) => return NativeResult::Err(crate::iterator::engine_error(vm, &err)), }; if method.is_null() || method.is_undefined() { // 键 11 缺失:回落读 @@dispose(读取顺序测试断言键 11 先、键 12 后)。 let dispose_key = encode_symbol_key(vm.realm_id(), 12); let sync_method = match vm.ordinary_get(value_obj, dispose_key, value) { Ok(m) => m, Err(err) => return NativeResult::Err(crate::iterator::engine_error(vm, &err)), }; if sync_method.is_null() || sync_method.is_undefined() { return NativeResult::Err(crate::error::create_type_error( vm, "value has no callable Symbol.asyncDispose or Symbol.dispose method", )); } if !crate::iterator::is_callable(sync_method) { return NativeResult::Err(crate::error::create_type_error(vm, "value[Symbol.dispose] is not callable")); } cap_ref.entries.push(DisposeEntry { value, method: sync_method, hint: 1, arg_style: false, wrap_sync: true, }); return NativeResult::Ok(value); } if !crate::iterator::is_callable(method) { return NativeResult::Err(crate::error::create_type_error(vm, "value[Symbol.asyncDispose] is not callable")); } cap_ref.entries.push(DisposeEntry { value, method, hint: 1, arg_style: false, wrap_sync: false, }); NativeResult::Ok(value) } /// `AsyncDisposableStack.prototype.adopt(value, onDisposeAsync)`:把 value 与其 /// 异步释放回调入栈。 /// /// # 步骤 /// 1. 校验栈对象(type_tag=25)与状态;Disposed 抛 ReferenceError。 /// 2. onDisposeAsync 非 callable → TypeError。 /// 3. 入栈 `{value, onDisposeAsync, async, arg-style}`(dispose 时 /// `Call(onDisposeAsync, undefined, «value»)`),返回 value。 pub fn async_disposable_stack_adopt(vm: &mut H, args: &[u8]) -> NativeResult { let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] }); let cap = native_try!(require_dispose_capability(vm, this_val, JsObject::OBJ_TYPE_ASYNC_DISPOSABLE_STACK)); // SAFETY: cap 由 require 校验,native 执行期间对象存活。 let cap_ref = unsafe { &mut *cap }; if cap_ref.state != DisposeState::Pending { return NativeResult::Err(disposed_reference_error(vm)); } let value = vm.reg(if args.len() > 1 { args[1] } else { 0 }); let on_dispose = vm.reg(if args.len() > 2 { args[2] } else { 0 }); if !crate::iterator::is_callable(on_dispose) { return NativeResult::Err(crate::error::create_type_error(vm, "onDisposeAsync is not callable")); } cap_ref.entries.push(DisposeEntry { value, method: on_dispose, hint: 1, arg_style: true, wrap_sync: false, }); NativeResult::Ok(value) } /// `AsyncDisposableStack.prototype.defer(onDisposeAsync)`:把无参数异步释放回调入栈。 /// /// # 步骤 /// 1. 校验栈对象(type_tag=25)与状态;Disposed 抛 ReferenceError。 /// 2. onDisposeAsync 非 callable → TypeError。 /// 3. 入栈 `{undefined, onDisposeAsync, async, receiver 模式}`(dispose 时 /// `Call(onDisposeAsync, undefined, «»)`),返回 undefined。 pub fn async_disposable_stack_defer(vm: &mut H, args: &[u8]) -> NativeResult { let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] }); let cap = native_try!(require_dispose_capability(vm, this_val, JsObject::OBJ_TYPE_ASYNC_DISPOSABLE_STACK)); // SAFETY: cap 由 require 校验,native 执行期间对象存活。 let cap_ref = unsafe { &mut *cap }; if cap_ref.state != DisposeState::Pending { return NativeResult::Err(disposed_reference_error(vm)); } let on_dispose = vm.reg(if args.len() > 1 { args[1] } else { 0 }); if !crate::iterator::is_callable(on_dispose) { return NativeResult::Err(crate::error::create_type_error(vm, "onDisposeAsync is not callable")); } cap_ref.entries.push(DisposeEntry { value: JsValue::undefined(), method: on_dispose, hint: 1, arg_style: false, wrap_sync: false, }); NativeResult::Ok(JsValue::undefined()) } /// `DisposableStack.prototype.defer(onDispose)`:把无参数释放回调入栈。 /// /// # 步骤 /// 1. 校验栈对象与状态;Disposed 抛 ReferenceError。 /// 2. onDispose 非 callable → TypeError。 /// 3. 入栈 `{undefined, onDispose, sync, receiver 模式}`(dispose 时 `Call(onDispose, undefined, «»)`), /// 返回 undefined。 pub fn disposable_stack_defer(vm: &mut H, args: &[u8]) -> NativeResult { let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] }); let cap = native_try!(require_dispose_capability(vm, this_val, JsObject::OBJ_TYPE_DISPOSABLE_STACK)); // SAFETY: cap 由 require 校验,native 执行期间对象存活。 let cap_ref = unsafe { &mut *cap }; if cap_ref.state != DisposeState::Pending { return NativeResult::Err(disposed_reference_error(vm)); } let on_dispose = vm.reg(if args.len() > 1 { args[1] } else { 0 }); if !crate::iterator::is_callable(on_dispose) { return NativeResult::Err(crate::error::create_type_error(vm, "onDispose is not callable")); } cap_ref.entries.push(DisposeEntry { value: JsValue::undefined(), method: on_dispose, hint: 0, arg_style: false, wrap_sync: false, }); NativeResult::Ok(JsValue::undefined()) } /// `DisposableStack.prototype.dispose()`:逆序执行全部释放回调并置栈为 Disposed。 /// /// # 步骤 /// 1. 校验栈对象;state 非 Pending → 直接返回 undefined(幂等,Disposing/Disposed 同返)。 /// 2. 先置 state=Disposed 再执行(防执行中 use/adopt 重入入栈)。 /// 3. 逆序逐条调用:arg-style 走 `Call(method, undefined, «value»)`,否则 /// `Call(method, value, «»)`;method 为 undefined 时跳过(防御)。 /// 4. 单错原样抛;多错用 SuppressedError 链式合并(error=后抛、suppressed=前值), /// 循环不因错误中断,剩余条目继续执行。 /// /// # 边界与前提 /// - 回调抛原始值(含 primitive)经 take_uncaught_value 恢复并存入 SuppressedError; /// - 无 uncaught 时回退按错误文本建普通 Error。 pub fn disposable_stack_dispose(vm: &mut H, args: &[u8]) -> NativeResult { let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] }); let cap = native_try!(require_dispose_capability(vm, this_val, JsObject::OBJ_TYPE_DISPOSABLE_STACK)); // SAFETY: cap 由 require 校验,native 执行期间对象存活。 let cap_ref = unsafe { &mut *cap }; if cap_ref.state != DisposeState::Pending { return NativeResult::Ok(JsValue::undefined()); } // 先置位再执行:执行中调用 use/adopt/defer 一律命中 Disposed 分支。 cap_ref.state = DisposeState::Disposed; let mut completion: Option = None; for entry in cap_ref.entries.iter().rev() { if entry.method.is_undefined() { continue; } if let Err(err_val) = call_entry_method(vm, entry) { completion = merge_dispose_error(vm, completion, err_val); } } // 条目逐条执行完毕,清空释放引用(规范 DisposeResources 逐条移除)。 cap_ref.entries.clear(); match completion { Some(err_val) => NativeResult::Err(err_val), None => NativeResult::Ok(JsValue::undefined()), } } /// move 公共实现:把全部 entries 转移到新资源栈。 /// /// # 步骤 /// 1. 校验栈对象;state 非 Pending → ReferenceError。 /// 2. `mem::take` 转移 entries;建新栈(proto 固定为栈类型原型,非子类原型) /// 并装入转移的 entries。 /// 3. 源栈置 Disposed(不再执行任何释放)。 fn stack_move_impl(vm: &mut H, this_val: JsValue, proto_val: JsValue, type_tag: u8) -> NativeResult { let cap = native_try!(require_dispose_capability(vm, this_val, type_tag)); // SAFETY: cap 由 require 校验,native 执行期间对象存活。 let cap_ref = unsafe { &mut *cap }; if cap_ref.state != DisposeState::Pending { return NativeResult::Err(disposed_reference_error(vm)); } let taken = std::mem::take(&mut cap_ref.entries); let new_stack = alloc_disposable_stack(vm, proto_val, type_tag); // SAFETY: alloc_disposable_stack 刚分配的对象,native_data 为新建空状态盒。 unsafe { let new_obj = &mut *new_stack; let new_cap = new_obj.native_data() as *mut DisposeCapability; (*new_cap).entries = taken; } cap_ref.state = DisposeState::Disposed; NativeResult::Ok(JsValue::from_js_object(new_stack)) } /// `DisposableStack.prototype.move()`:把全部 entries 转移到新 DisposableStack。 pub fn disposable_stack_move(vm: &mut H, args: &[u8]) -> NativeResult { let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] }); let proto_val = JsValue::from_js_object(vm.builtin_proto(ProtoKind::DisposableStackProto)); stack_move_impl(vm, this_val, proto_val, JsObject::OBJ_TYPE_DISPOSABLE_STACK) } /// `AsyncDisposableStack.prototype.move()`:把全部 entries 转移到新 /// AsyncDisposableStack(proto 固定为 AsyncDisposableStack.prototype,非子类)。 pub fn async_disposable_stack_move(vm: &mut H, args: &[u8]) -> NativeResult { let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] }); let proto_val = JsValue::from_js_object(vm.builtin_proto(ProtoKind::AsyncDisposableStackProto)); stack_move_impl(vm, this_val, proto_val, JsObject::OBJ_TYPE_ASYNC_DISPOSABLE_STACK) } /// `get DisposableStack.prototype.disposed`:栈是否已 dispose/move。 pub fn disposable_stack_disposed_getter(vm: &mut H, args: &[u8]) -> NativeResult { let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] }); let cap = native_try!(require_dispose_capability(vm, this_val, JsObject::OBJ_TYPE_DISPOSABLE_STACK)); // SAFETY: cap 由 require 校验,native 执行期间对象存活。 let state = unsafe { (*cap).state }; NativeResult::Ok(JsValue::bool(state != DisposeState::Pending)) } /// `get AsyncDisposableStack.prototype.disposed`:栈是否已 disposeAsync/move。 pub fn async_disposable_stack_disposed_getter(vm: &mut H, args: &[u8]) -> NativeResult { let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] }); let cap = native_try!(require_dispose_capability(vm, this_val, JsObject::OBJ_TYPE_ASYNC_DISPOSABLE_STACK)); // SAFETY: cap 由 require 校验,native 执行期间对象存活。 let state = unsafe { (*cap).state }; NativeResult::Ok(JsValue::bool(state != DisposeState::Pending)) } /// 按条目调用约定执行释放回调,失败时恢复本次回调抛出的原始异常值。 /// /// # 边界与前提 /// - `arg_style` 走 `Call(method, undefined, «value»)`,否则 `Call(method, value, «»)`; /// - 无 uncaught 时回退按错误文本建普通 Error。 pub fn call_entry_method(vm: &mut H, entry: &DisposeEntry) -> Result { let call_result = if entry.arg_style { vm.call_function_sync(entry.method, JsValue::undefined(), &[entry.value]) } else { vm.call_function_sync(entry.method, entry.value, &[]) }; call_result.map_err(|err| { vm.take_uncaught_value() .unwrap_or_else(|| crate::error::create_kind_error(vm, "Error", &err)) }) } /// 把本次释放错误合并进完成记录:空 → 原样;已有错误 → SuppressedError 链 /// (error=后抛、suppressed=前值,逆序处理中后处理者=更早入栈者)。 pub fn merge_dispose_error(vm: &mut H, completion: Option, err: JsValue) -> Option { Some(match completion { None => err, Some(prev) => crate::error::create_suppressed_error(vm, err, prev), }) } /// 栈生命周期状态:Pending 可入栈,Disposed 后所有操作抛 ReferenceError; /// Disposing 为异步资源栈 disposeAsync 执行期标记(当前状态机只置 Disposed, /// 变体语义预留)。 #[derive(Clone, Copy, PartialEq, Eq, Debug)] pub enum DisposeState { Pending, #[allow(dead_code)] Disposing, Disposed, } /// 单条待释放资源:dispose 时按 `arg_style` 选择调用约定,按 `hint`/`wrap_sync` /// 决定异步语义(disposeAsync 状态机消费)。 #[derive(Clone, Copy)] pub struct DisposeEntry { /// use() 的资源值(dispose 时作 receiver);adopt() 的资源值(作参数);defer() 恒 undefined。 pub value: JsValue, /// 释放方法:use() 为 @@asyncDispose/@@dispose 函数;adopt()/defer() 为用户回调。 pub method: JsValue, /// 0=sync-dispose,1=async-dispose(异步资源栈用)。 pub hint: u8, /// true=adopt 闭包语义(`Call(method, undefined, «value»)`); /// false=use/defer(`Call(method, value, «»)`)。 pub arg_style: bool, /// true=方法取自 @@dispose(async 栈 use 回落):返回值丢弃、异常异步化。 pub wrap_sync: bool, } /// 状态盒:栈状态 + 按入栈序的资源条目。 pub struct DisposeCapability { pub state: DisposeState, pub entries: Vec, } /// 取对象 `native_data` 中存放的状态盒指针。 /// /// # 注意事项 /// - 仅在对象存活期内调用(GC 边收集与绑定层);指针由分配入口 /// `alloc_disposable_stack` 保证有效。 pub fn get_capability_ptr(obj: &JsObject) -> *mut DisposeCapability { obj.native_data() as *mut DisposeCapability } /// 收集栈内全部 value/method 边(GC mark 边):对象/字符串/BigInt 均产出, /// 消费侧按值类型分发到对象栈与存活集。 pub fn dispose_edges(obj: &JsObject) -> Vec { if !obj.is_disposable_stack_obj() && !obj.is_async_disposable_stack_obj() { return Vec::new(); } let ptr = get_capability_ptr(obj); if ptr.is_null() { return Vec::new(); } // SAFETY: native_data 持有 `alloc_capability` 写入的有效 Box 指针,本函数 // 只在对象存活期间被 GC/绑定层调用。 unsafe { (*ptr).entries.iter().flat_map(|entry| [entry.value, entry.method]).collect() } } /// 只读核算 DisposableStack 状态盒字节(不释放)。 pub fn disposable_stack_native_size(obj: &JsObject) -> u64 { if !obj.is_disposable_stack_obj() && !obj.is_async_disposable_stack_obj() { return 0; } let ptr = get_capability_ptr(obj); if ptr.is_null() { return 0; } unsafe { (std::mem::size_of::() + (*ptr).entries.capacity() * std::mem::size_of::()) as u64 } } /// 释放状态盒(对象被回收时),返回释放的字节数供泄漏统计。 pub fn drop_dispose_native(obj: &mut JsObject) -> u64 { let bytes = disposable_stack_native_size(obj); if bytes == 0 { return 0; } let ptr = get_capability_ptr(obj); // SAFETY: ptr 非空(disposable_stack_native_size 已验证),Box::from_raw 恰好释放一次。 unsafe { let cap = Box::from_raw(ptr); drop(cap); obj.set_native_data(std::ptr::null_mut()); } bytes }