mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-25 03:01:12 +08:00
feat: 落地 Proxy 构造器与 revocable 及撤销函数
This commit is contained in:
@@ -11,12 +11,10 @@ use crate::bindings::{bind_global_value, configure_native_constructor};
|
||||
/// 未实现内置的 stub 表:(全局名、native 函数项指针、形参个数、
|
||||
/// 原型 @@toStringTag、是否安装原型对象)。
|
||||
///
|
||||
/// `tag` 为 `None` 的条目(Proxy)原型对象不设 @@toStringTag;弱族 stub
|
||||
/// (WeakSet/WeakRef/FinalizationRegistry)各取族名。
|
||||
/// 规范 25.1 的 %Proxy% 无 prototype 属性(`has_prototype` = false),
|
||||
/// 弱族 stub 各装带 constructor 回指的原型对象。
|
||||
const STUBS: [(&str, *const (), u8, Option<&str>, bool); 4] = [
|
||||
("Proxy", oxide_builtins::stubs::proxy_stub::<crate::vm::Vm> as *const (), 2, None, false),
|
||||
/// 弱族 stub(WeakSet/WeakRef/FinalizationRegistry)各取族名作 @@toStringTag,
|
||||
/// 各装带 constructor 回指的原型对象。Proxy 已落地真构造器(`bind_proxy`),
|
||||
/// 不在此表。
|
||||
const STUBS: [(&str, *const (), u8, Option<&str>, bool); 3] = [
|
||||
(
|
||||
"WeakSet",
|
||||
oxide_builtins::stubs::weakset_stub::<crate::vm::Vm> as *const (),
|
||||
@@ -50,16 +48,16 @@ fn set_data_property(core: &Arc<KernelCore>, obj: &mut JsObject, si: u32, value:
|
||||
obj.bump_generation();
|
||||
}
|
||||
|
||||
/// 把未实现内置(Proxy/WeakSet/WeakRef/FinalizationRegistry)的 stub 构造器
|
||||
/// 绑定到 global,并登记到 `stub_objects` 供快照跟踪。WeakMap 已落地真构造器,
|
||||
/// 走 `bind_weak` 绑定面,不在此表。
|
||||
/// 把未实现内置(WeakSet/WeakRef/FinalizationRegistry)的 stub 构造器
|
||||
/// 绑定到 global,并登记到 `stub_objects` 供快照跟踪。WeakMap 与 Proxy 已落地
|
||||
/// 真构造器,走 `bind_weak` / `bind_proxy` 绑定面,不在此表。
|
||||
///
|
||||
/// # 副作用
|
||||
/// 每个 stub 按规范补装构造器面属性:`length`、`name`(四族全装);弱族 stub
|
||||
/// 每个 stub 按规范补装构造器面属性:`length`、`name`(三族全装);弱族 stub
|
||||
/// 另装 `prototype`(新建 plain 对象,原型链落 Object.prototype,其上带指回
|
||||
/// stub 的 `constructor` 与 @@toStringTag)——规范 25.1 的 %Proxy% 无
|
||||
/// prototype 属性,不装;描述符均不可枚举,`prototype` 另不可写、不可配置。
|
||||
/// 原型对象登记进 world 释放登记表,与 stub 对象同生死,session 收尾统一释放。
|
||||
/// stub 的 `constructor` 与 @@toStringTag);描述符均不可枚举,`prototype`
|
||||
/// 另不可写、不可配置。原型对象登记进 world 释放登记表,与 stub 对象同生死,
|
||||
/// session 收尾统一释放。
|
||||
///
|
||||
/// `realm_id` 是目标所属 realm 的编号:`@@toStringTag` 符号键按 (realm 编号,
|
||||
/// 局部下标) 编码,realm 编号为 0 时与旧编码逐字节一致。
|
||||
@@ -79,7 +77,7 @@ pub fn bind_stubs(core: &Arc<KernelCore>, session: &mut KernelSession, global: &
|
||||
let stub = P::new(stub);
|
||||
let stub_ptr = stub.as_ptr() as *mut JsObject;
|
||||
|
||||
// 构造器面属性:length / name 四族全装;prototype 仅弱族 stub(%Proxy% 无)。
|
||||
// 构造器面属性:length / name 三族全装;prototype 仅弱族 stub。
|
||||
// SAFETY: stub 尚未发布到 global,局部 Arc 为唯一持有者,可变访问无读者冲突。
|
||||
let stub_obj = unsafe { &mut *stub_ptr };
|
||||
if has_prototype {
|
||||
|
||||
@@ -59,7 +59,7 @@ pub mod bind_set;
|
||||
pub mod bind_shared_array_buffer;
|
||||
/// String 构造器与原型的 native 方法绑定。
|
||||
pub mod bind_string;
|
||||
/// 未实现内置(Proxy/BigInt/WeakMap 等)的 stub 构造器绑定。
|
||||
/// 未实现内置(WeakSet/WeakRef/FinalizationRegistry 等)的 stub 构造器绑定。
|
||||
pub mod bind_stubs;
|
||||
/// Symbol 构造器与原型的 native 方法绑定。
|
||||
pub mod bind_symbol;
|
||||
@@ -978,10 +978,9 @@ fn bind_iterator_global(env: BindEnv<'_>, global: &mut JsObject) {
|
||||
}
|
||||
|
||||
fn bind_stub_globals(env: BindEnv<'_>, global: &mut JsObject) {
|
||||
// 索引 4 = WeakMap 真构造器(bind_weak 留存 stub_objects 末位),global
|
||||
// 重建时原位重绑;四 stub 族索引 0-3 紧随其后。
|
||||
// 索引 3 = WeakMap 真构造器、索引 4 = Proxy 真构造器(bind_weak / bind_proxy
|
||||
// 留存 stub_objects 末两位),global 重建时原位重绑;三 stub 族索引 0-2 紧随其后。
|
||||
for (index, (name, native_fn, arg_count)) in [
|
||||
("Proxy", oxide_builtins::stubs::proxy_stub::<crate::vm::Vm> as *const (), 2),
|
||||
("WeakSet", oxide_builtins::stubs::weakset_stub::<crate::vm::Vm> as *const (), 0),
|
||||
("WeakRef", oxide_builtins::stubs::weakref_stub::<crate::vm::Vm> as *const (), 1),
|
||||
(
|
||||
@@ -990,6 +989,7 @@ fn bind_stub_globals(env: BindEnv<'_>, global: &mut JsObject) {
|
||||
1,
|
||||
),
|
||||
("WeakMap", oxide_builtins::weak_map::weak_map_constructor::<crate::vm::Vm> as *const (), 0),
|
||||
("Proxy", oxide_builtins::proxy::proxy_constructor::<crate::vm::Vm> as *const (), 2),
|
||||
]
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
@@ -1001,6 +1001,83 @@ fn bind_stub_globals(env: BindEnv<'_>, global: &mut JsObject) {
|
||||
}
|
||||
}
|
||||
|
||||
/// 把 %Proxy% 真构造器绑定到 global。
|
||||
///
|
||||
/// # 副作用
|
||||
/// - 构造器经 `P` 留存 `stub_objects`(索引 4,紧随 WeakMap 真构造器),global
|
||||
/// 重建时原位重绑;全局 `Proxy` 槽经 `bind_global_value` 安装。
|
||||
/// - 构造器面按规范装 `length`(2)与 `name`("Proxy");规范 25.1 的 %Proxy%
|
||||
/// 无 prototype 属性,不装。
|
||||
/// - `revocable` 静态方法(非构造器函数,length 2、name "revocable",原型链
|
||||
/// Function.prototype)经构造器属性边可达,另登记释放登记表,session 收尾
|
||||
/// 统一释放。
|
||||
fn bind_proxy(core: &Arc<KernelCore>, session: &mut KernelSession, global: &mut JsObject, _realm_id: u32) {
|
||||
let world = Arc::get_mut(&mut session.builtin_world)
|
||||
.expect("BuiltinWorld must be uniquely owned during init_kernel_builtins");
|
||||
let function_proto_ptr = world.function_proto.as_ptr() as *mut JsObject;
|
||||
let si_length = core.perm_interner().intern("length").0;
|
||||
let si_name = core.perm_interner().intern("name").0;
|
||||
|
||||
// 构造器对象:Function 原型链 + native 函数项;length / name 按规范装
|
||||
// (描述符 { f,f,t },length 先于 name 以保 own 属性序)。
|
||||
let mut ctor = JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::from_js_object(function_proto_ptr));
|
||||
ctor.set_function(true);
|
||||
configure_native_constructor(
|
||||
&mut ctor,
|
||||
oxide_builtins::proxy::proxy_constructor::<crate::vm::Vm> as *const (),
|
||||
2,
|
||||
);
|
||||
let length_shape = core.shape_forge().make_shape(ctor.shape_id(), si_length);
|
||||
ctor.set_shape_id(length_shape);
|
||||
ctor.ensure_hash_props().push(JsValue::int(2));
|
||||
let length_pos = ctor.hash_props_vec().map_or(0, |v| v.len() as u32).saturating_sub(1);
|
||||
ctor.set_data_meta(length_pos, PropAttributes::new(false, false, true));
|
||||
let name_shape = core.shape_forge().make_shape(ctor.shape_id(), si_name);
|
||||
ctor.set_shape_id(name_shape);
|
||||
ctor.ensure_hash_props().push(JsValue::perm_string(
|
||||
core.perm_interner().string_ptr(core.perm_interner().intern("Proxy").0),
|
||||
));
|
||||
let name_pos = ctor.hash_props_vec().map_or(0, |v| v.len() as u32).saturating_sub(1);
|
||||
ctor.set_data_meta(name_pos, PropAttributes::new(false, false, true));
|
||||
|
||||
// revocable 静态方法:非构造器函数(不设 CONSTRUCTOR 标签,new 调用按规范
|
||||
// 抛 TypeError),length 2 / name "revocable",原型链 Function.prototype。
|
||||
let mut revocable = JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::from_js_object(function_proto_ptr));
|
||||
revocable.set_function(true);
|
||||
// SAFETY: proxy_revocable 是合法 NativeFn 函数项。
|
||||
revocable.set_native_fn(Some(unsafe {
|
||||
NativeFnPtr::from_raw(oxide_builtins::proxy::proxy_revocable::<crate::vm::Vm> as *const ())
|
||||
}));
|
||||
revocable.set_native_arg_count(2);
|
||||
let rev_length_shape = core.shape_forge().make_shape(revocable.shape_id(), si_length);
|
||||
revocable.set_shape_id(rev_length_shape);
|
||||
revocable.ensure_hash_props().push(JsValue::int(2));
|
||||
let rev_length_pos = revocable.hash_props_vec().map_or(0, |v| v.len() as u32).saturating_sub(1);
|
||||
revocable.set_data_meta(rev_length_pos, PropAttributes::new(false, false, true));
|
||||
let rev_name_shape = core.shape_forge().make_shape(revocable.shape_id(), si_name);
|
||||
revocable.set_shape_id(rev_name_shape);
|
||||
revocable.ensure_hash_props().push(JsValue::perm_string(
|
||||
core.perm_interner().string_ptr(core.perm_interner().intern("revocable").0),
|
||||
));
|
||||
let rev_name_pos = revocable.hash_props_vec().map_or(0, |v| v.len() as u32).saturating_sub(1);
|
||||
revocable.set_data_meta(rev_name_pos, PropAttributes::new(false, false, true));
|
||||
let revocable_ptr = Box::into_raw(Box::new(revocable));
|
||||
world.track_leaked_object(revocable_ptr);
|
||||
|
||||
// 构造器 revocable 属性({ f,f,t }),own 属性序 length、name、revocable。
|
||||
let si_revocable = core.perm_interner().intern("revocable").0;
|
||||
let rev_shape = core.shape_forge().make_shape(ctor.shape_id(), si_revocable);
|
||||
ctor.set_shape_id(rev_shape);
|
||||
ctor.ensure_hash_props().push(JsValue::from_js_object(revocable_ptr));
|
||||
let rev_pos = ctor.hash_props_vec().map_or(0, |v| v.len() as u32).saturating_sub(1);
|
||||
ctor.set_data_meta(rev_pos, PropAttributes::new(false, false, true));
|
||||
|
||||
let stub = P::new(ctor);
|
||||
let ctor_ptr = stub.as_ptr() as *mut JsObject;
|
||||
world.stub_objects.push(stub);
|
||||
bind_global_value(core, global, "Proxy", JsValue::from_js_object(ctor_ptr));
|
||||
}
|
||||
|
||||
/// 把已有 builtin 构造器的 native 实现与 global 槽位一次性装配完整。
|
||||
///
|
||||
/// 在 global 对象重建(dirty reset)后调用:重新配置构造器 native 函数并重绑
|
||||
@@ -1361,6 +1438,9 @@ pub fn rebind_dirty_builtins(
|
||||
// WeakMap 真构造器面与 stub 族同脏位:原型对象经 leaked 登记表迁移,
|
||||
// 重绑时全局槽原位更新,不占 BuiltinWorld 槽。
|
||||
bind_weak::bind_weak_map(core, session, global, realm_id);
|
||||
// Proxy 真构造器面与 WeakMap 同脏位:构造器经 stub_objects 留存,重绑时
|
||||
// 全局槽原位更新,不占 BuiltinWorld 槽。
|
||||
bind_proxy(core, session, global, realm_id);
|
||||
}
|
||||
let env = BindEnv {
|
||||
core,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//! native 载荷家族的单点分类与每家族边函数引用(家族表)。
|
||||
//!
|
||||
//! 分类是复合谓词:header 位(map/set/module_ns)优先于 `type_tag`,
|
||||
//! 两维互斥、一个对象至多归入一个家族。tag 维显式枚举全部 0..=39,
|
||||
//! 两维互斥、一个对象至多归入一个家族。tag 维显式枚举全部 0..=40,
|
||||
//! 未登记 tag panic。
|
||||
//!
|
||||
//! 关键约定:
|
||||
@@ -10,7 +10,9 @@
|
||||
//! - 注册面集中在 `ops_for` 的家族表,mark/size/drop/clone/rewrite 各链
|
||||
//! 由同一张表驱动,新增家族只在此登记。
|
||||
|
||||
use oxide_builtins::{data_view, disposable_stack, event, map, message_channel, module, set, typed_array, weak_map};
|
||||
use oxide_builtins::{
|
||||
data_view, disposable_stack, event, map, message_channel, module, proxy, set, typed_array, weak_map,
|
||||
};
|
||||
use oxide_types::object::{Cell, JsObject, JsString};
|
||||
use oxide_types::value::JsValue;
|
||||
|
||||
@@ -65,6 +67,8 @@ pub(crate) enum NativeBoxFamily {
|
||||
Arguments,
|
||||
/// Proxy 对象(tag 39,target 与 handler 载荷盒存 `native_data`)。
|
||||
Proxy,
|
||||
/// Proxy 撤销函数(tag 40,被撤销代理指针存 `native_data`,GC 边)。
|
||||
ProxyRevoker,
|
||||
}
|
||||
|
||||
/// 一个家族的边操作集(每家族函数引用,单一注册面)。
|
||||
@@ -97,7 +101,7 @@ pub(crate) fn classify(obj: &JsObject) -> NativeBoxFamily {
|
||||
/// 按类型 tag 分类 native 载荷家族。
|
||||
///
|
||||
/// # 边界与前提
|
||||
/// - 0..=39 全 tag 显式枚举;未登记 tag(40 及以上)panic。
|
||||
/// - 0..=40 全 tag 显式枚举;未登记 tag(41 及以上)panic。
|
||||
pub(crate) fn classify_by_tag(tag: u8) -> NativeBoxFamily {
|
||||
match tag {
|
||||
JsObject::OBJ_TYPE_ARRAY_BUFFER => NativeBoxFamily::ArrayBuffer,
|
||||
@@ -141,6 +145,7 @@ pub(crate) fn classify_by_tag(tag: u8) -> NativeBoxFamily {
|
||||
JsObject::OBJ_TYPE_ERROR_EVENT => NativeBoxFamily::ErrorEvent,
|
||||
JsObject::OBJ_TYPE_CUSTOM_EVENT => NativeBoxFamily::CustomEvent,
|
||||
JsObject::OBJ_TYPE_PROXY => NativeBoxFamily::Proxy,
|
||||
JsObject::OBJ_TYPE_PROXY_REVOKER => NativeBoxFamily::ProxyRevoker,
|
||||
_ => panic!("unregistered type tag: {tag}"),
|
||||
}
|
||||
}
|
||||
@@ -278,6 +283,12 @@ pub(crate) fn ops_for(family: NativeBoxFamily) -> NativeBoxOps {
|
||||
string_edges: None,
|
||||
cell_edges: None,
|
||||
},
|
||||
// Proxy 撤销函数:被撤销代理指针一条对象边(保活代理,仅持撤销函数时不回收)。
|
||||
NativeBoxFamily::ProxyRevoker => NativeBoxOps {
|
||||
object_edges: Some(proxy::proxy_revoker_native_edges),
|
||||
string_edges: None,
|
||||
cell_edges: None,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -315,13 +326,14 @@ mod tests {
|
||||
JsObject::OBJ_TYPE_CUSTOM_EVENT => NativeBoxFamily::CustomEvent,
|
||||
JsObject::OBJ_TYPE_ARGUMENTS => NativeBoxFamily::Arguments,
|
||||
JsObject::OBJ_TYPE_PROXY => NativeBoxFamily::Proxy,
|
||||
JsObject::OBJ_TYPE_PROXY_REVOKER => NativeBoxFamily::ProxyRevoker,
|
||||
_ => NativeBoxFamily::None,
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tag_dimension_every_tag_hits_exactly_one_family() {
|
||||
for tag in 0..=39u8 {
|
||||
for tag in 0..=40u8 {
|
||||
let obj = obj_with_tag(tag);
|
||||
let family = classify(&obj);
|
||||
assert_eq!(family, expected_family_for_tag(tag), "tag {tag} 家族不一致");
|
||||
@@ -355,7 +367,7 @@ mod tests {
|
||||
#[test]
|
||||
#[should_panic(expected = "unregistered type tag")]
|
||||
fn unregistered_tag_panics() {
|
||||
let obj = obj_with_tag(40);
|
||||
let obj = obj_with_tag(41);
|
||||
classify(&obj);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,50 +1,16 @@
|
||||
//! Proxy 状态盒:Proxy 对象 `native_data` 槽的载荷盒(target、handler、revoked
|
||||
//! 位)与 session GC 三类接线——值边、字节核算与释放。
|
||||
//! Proxy 状态盒的 session GC 三类接线:值边、字节核算与释放。
|
||||
//!
|
||||
//! 状态盒本体(`ProxyState`)定义在 `oxide_builtins::proxy`(构造器侧分配),
|
||||
//! 本模块只读其布局做 GC 接线;撤销函数(独立 tag)的边函数在
|
||||
//! `oxide_builtins::proxy::proxy_revoker_native_edges`。
|
||||
|
||||
use oxide_builtins::proxy::ProxyState;
|
||||
use oxide_types::object::JsObject;
|
||||
use oxide_types::value::JsValue;
|
||||
|
||||
/// Proxy 状态盒:存于 Proxy 对象 `native_data`,target 与 handler 是 GC 边,
|
||||
/// revoked 位标记已撤销状态(撤销后全部 trap 抛 TypeError)。
|
||||
///
|
||||
/// 生命周期与 Proxy 对象一致:构造期经 `Box::into_raw` 分配,GC drop 链释放,
|
||||
/// 此后不替换。
|
||||
pub(crate) struct ProxyState {
|
||||
/// 目标对象(GC 边)。
|
||||
pub(crate) target: JsValue,
|
||||
/// 处理器对象(GC 边)。
|
||||
pub(crate) handler: JsValue,
|
||||
/// 撤销位:置位后所有 trap 派发抛 TypeError。
|
||||
#[allow(dead_code)] // 读方为 trap 派发路径,随该路径接线启用
|
||||
pub(crate) revoked: bool,
|
||||
}
|
||||
|
||||
/// 读 Proxy 状态盒(盒未建立时 None)。
|
||||
pub(crate) fn proxy_state_ref(obj: &JsObject) -> Option<&ProxyState> {
|
||||
let ptr = obj.native_data() as *const ProxyState;
|
||||
if ptr.is_null() {
|
||||
None
|
||||
} else {
|
||||
// SAFETY: native_data 由 Box::into_raw 分配,生命周期与 Proxy 对象一致。
|
||||
Some(unsafe { &*ptr })
|
||||
}
|
||||
}
|
||||
|
||||
/// 可变访问 Proxy 状态盒(写 revoked 位)。
|
||||
#[allow(dead_code)] // 写方为构造器与 revocable 路径,随该路径接线启用
|
||||
pub(crate) fn proxy_state_mut(obj: &mut JsObject) -> Option<&mut ProxyState> {
|
||||
let ptr = obj.native_data() as *mut ProxyState;
|
||||
if ptr.is_null() {
|
||||
None
|
||||
} else {
|
||||
// SAFETY: native_data 由 Box::into_raw 分配,生命周期与 Proxy 对象一致。
|
||||
Some(unsafe { &mut *ptr })
|
||||
}
|
||||
}
|
||||
|
||||
/// Proxy 状态盒内全部值边(GC mark 边):target 与 handler。
|
||||
pub(crate) fn proxy_native_edges(obj: &JsObject) -> Vec<JsValue> {
|
||||
let Some(state) = proxy_state_ref(obj) else {
|
||||
let Some(state) = oxide_builtins::proxy::proxy_state_ref(obj) else {
|
||||
return Vec::new();
|
||||
};
|
||||
vec![state.target, state.handler]
|
||||
@@ -85,11 +51,7 @@ mod tests {
|
||||
fn proxy_obj(target: JsValue, handler: JsValue) -> JsObject {
|
||||
let mut obj = JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::undefined());
|
||||
obj.type_tag = JsObject::OBJ_TYPE_PROXY;
|
||||
let state = Box::new(ProxyState {
|
||||
target,
|
||||
handler,
|
||||
revoked: false,
|
||||
});
|
||||
let state = Box::new(ProxyState { target, handler, revoked: false });
|
||||
obj.set_native_data(Box::into_raw(state) as *mut u8);
|
||||
obj
|
||||
}
|
||||
@@ -126,10 +88,10 @@ mod tests {
|
||||
#[test]
|
||||
fn proxy_state_revoked_bit_roundtrip() {
|
||||
let mut obj = proxy_obj(plain_obj_value(), plain_obj_value());
|
||||
let state = proxy_state_ref(&obj).expect("状态盒");
|
||||
let state = oxide_builtins::proxy::proxy_state_ref(&obj).expect("状态盒");
|
||||
assert!(!state.revoked);
|
||||
let state = proxy_state_mut(&mut obj).expect("状态盒");
|
||||
let state = oxide_builtins::proxy::proxy_state_mut(&mut obj).expect("状态盒");
|
||||
state.revoked = true;
|
||||
assert!(proxy_state_ref(&obj).expect("状态盒").revoked);
|
||||
assert!(oxide_builtins::proxy::proxy_state_ref(&obj).expect("状态盒").revoked);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,8 +98,8 @@ fn stub_proto_member_read_returns_undefined() {
|
||||
assert!(result.as_bool());
|
||||
}
|
||||
|
||||
/// 构造体不回归钉:四 stub 构造调用仍抛 TypeError(消息含 "… is not
|
||||
/// implemented");WeakMap 已落地真构造器,不在此列。
|
||||
/// 构造体不回归钉:三弱族 stub 构造调用仍抛 TypeError(消息含 "… is not
|
||||
/// implemented");WeakMap 与 Proxy 已落地真构造器,不在此列。
|
||||
#[test]
|
||||
fn stub_ctor_call_still_throws_not_implemented() {
|
||||
let mut vm = Vm::new();
|
||||
@@ -113,8 +113,7 @@ fn stub_ctor_call_still_throws_not_implemented() {
|
||||
} \
|
||||
return probe(WeakSet, [], 'WeakSet') \
|
||||
&& probe(WeakRef, [{}], 'WeakRef') \
|
||||
&& probe(FinalizationRegistry, [function () {}], 'FinalizationRegistry') \
|
||||
&& probe(Proxy, [ {}, {} ], 'Proxy'); })()",
|
||||
&& probe(FinalizationRegistry, [function () {}], 'FinalizationRegistry'); })()",
|
||||
)
|
||||
.unwrap();
|
||||
assert!(result.as_bool());
|
||||
|
||||
Reference in New Issue
Block a user