Files
OxideJS-New/crates/oxide_vm/src/bindings/bind_weak.rs
T

164 lines
7.1 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! Weak 族绑定:WeakMap 构造器 + 原型四方法(set/get/has/delete)安装。
//!
//! 弱族不占 BuiltinWorld 槽:构造器经 `P` 留存 `stub_objects`(global
//! 重建路径原位重绑,索引 4 紧随 stub 族四条目),原型对象经
//! `Box::into_raw` 登记 world 释放登记表(属性装完再登记,登记点世代即
//! 洁净基线),恒存活至 session 收尾统一释放;选择性重建经
//! `inherit_leaked_objects` 迁移登记表、`retire_replaced` 重指原型链,
//! 重绑时全局槽原位更新不追加。
use std::sync::Arc;
use crate::bind_constructor;
use crate::bindings::configure_native_constructor;
use oxide_kernel::kernel::{KernelCore, KernelSession};
use oxide_kernel::shape_forge::EMPTY_SHAPE_ID;
use oxide_types::mem::P;
use oxide_types::object::{JsObject, PropAttributes};
use oxide_types::value::JsValue;
/// 在原型上安装一条 native 方法,站点标签 = 族名 perm 键:非 P 原型目标
/// 全部落 family-0,无标签时 WeakMap 与后续弱族同名方法槽(has/delete)
/// 在 FnWrapperKey 复用键上撞键,重绑会迁移到错误家族的 wrapper。
fn bind_labeled_method(
world: &oxide_kernel::builtin::BuiltinWorld, proto: &mut JsObject, core: &Arc<KernelCore>, label: u32, name: &str,
func: *const (), nargs: u8,
) {
let shape_forge = core.shape_forge().as_ref();
let string_forge = core.perm_interner().as_ref();
// SAFETY: func 是转成 *const () 的 NativeFn 函数项指针。
let fn_ptr = unsafe { oxide_types::object::NativeFnPtr::from_raw(func) };
let _ = oxide_kernel::builtin::BuiltinWorld::bind_method_labeled_static(
proto,
shape_forge,
string_forge,
name,
fn_ptr,
nargs,
world,
label,
);
}
/// 把 WeakMap 构造器与原型四方法绑定到 global。
///
/// # 副作用
/// - 构造器经 `P` 留存 `stub_objects`(索引 4,紧随 stub 族四条目);
/// 原型对象经释放登记表登记,恒存活至 session 收尾;全局 `WeakMap` 槽
/// 经 `bind_constructor!` 原位安装(既有槽更新槽值,不追加新槽)。
/// - 方法 wrapper 带族名站点标签登记复用键,选择性重建时按键迁移,
/// 登记表跨重建不增长。
///
/// `realm_id` 是目标所属 realm 的编号:`@@toStringTag` 符号键按 (realm 编号,
/// 局部下标) 编码,realm 编号为 0 时与旧编码逐字节一致。
pub fn bind_weak_map(core: &Arc<KernelCore>, session: &mut KernelSession, global: &mut JsObject, realm_id: u32) {
// world 唯一属主期:全程走可变引用(stub_objects 留存 + 释放登记同表)。
let world = Arc::get_mut(&mut session.builtin_world)
.expect("BuiltinWorld must be uniquely owned during init_kernel_builtins");
let object_proto_ptr = world.object_proto.as_ptr() as *mut JsObject;
let function_proto_ptr = world.function_proto.as_ptr() as *mut JsObject;
let label = core.perm_interner().intern("WeakMap").0;
let si_name = core.perm_interner().intern("name").0;
// 构造器对象:Function 原型链 + native 函数项;name 由本函数安装
// (bind_constructor! 只补 length),描述符 { f,f,t }。
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::weak_map::weak_map_constructor::<crate::vm::Vm> as *const (),
0,
);
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("WeakMap").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));
let stub = P::new(ctor);
let ctor_ptr = stub.as_ptr() as *mut JsObject;
// 原型对象:constructor 回指({ w,f,t })+ @@toStringTag({ f,f,t }),
// 四方法 { w,f,t } 经站点标签绑定;属性装完再登记释放登记表。
let mut proto = JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::from_js_object(object_proto_ptr));
let si_constructor = core.perm_interner().intern("constructor").0;
let ctor_shape = core.shape_forge().make_shape(proto.shape_id(), si_constructor);
proto.set_shape_id(ctor_shape);
proto.ensure_hash_props().push(JsValue::from_js_object(ctor_ptr));
let ctor_pos = proto.hash_props_vec().map_or(0, |v| v.len() as u32).saturating_sub(1);
proto.set_data_meta(ctor_pos, PropAttributes::new(true, false, true));
let tag_key = oxide_types::private_key::encode_symbol_key(
realm_id,
oxide_types::private_key::WELL_KNOWN_SYMBOL_TO_STRING_TAG,
);
let tag_shape = core.shape_forge().make_shape(proto.shape_id(), tag_key);
proto.set_shape_id(tag_shape);
proto.ensure_hash_props().push(JsValue::perm_string(
core.perm_interner().string_ptr(core.perm_interner().intern("WeakMap").0),
));
let tag_pos = proto.hash_props_vec().map_or(0, |v| v.len() as u32).saturating_sub(1);
proto.set_data_meta(tag_pos, PropAttributes::new(false, false, true));
bind_labeled_method(
world,
&mut proto,
core,
label,
"set",
oxide_builtins::weak_map::weak_map_set::<crate::vm::Vm> as *const (),
2,
);
bind_labeled_method(
world,
&mut proto,
core,
label,
"get",
oxide_builtins::weak_map::weak_map_get::<crate::vm::Vm> as *const (),
1,
);
bind_labeled_method(
world,
&mut proto,
core,
label,
"has",
oxide_builtins::weak_map::weak_map_has::<crate::vm::Vm> as *const (),
1,
);
bind_labeled_method(
world,
&mut proto,
core,
label,
"delete",
oxide_builtins::weak_map::weak_map_delete::<crate::vm::Vm> as *const (),
1,
);
let proto_ptr = Box::into_raw(Box::new(proto));
world.track_leaked_object(proto_ptr);
// 构造器 prototype 槽({ f,f,f }):P 留存 stub_objects(global 重建
// 原位重绑依赖索引 4)后,经 bind_constructor! 安装全局槽。
// SAFETY: ctor 尚未发布到 global,局部 P 为唯一持有者,可变访问无读者冲突。
let ctor = unsafe { &mut *ctor_ptr };
let si_prototype = core.perm_interner().intern("prototype").0;
let proto_shape = core.shape_forge().make_shape(ctor.shape_id(), si_prototype);
ctor.set_shape_id(proto_shape);
ctor.ensure_hash_props().push(JsValue::from_js_object(proto_ptr));
let proto_pos = ctor.hash_props_vec().map_or(0, |v| v.len() as u32).saturating_sub(1);
ctor.set_data_meta(proto_pos, PropAttributes::new(false, false, false));
world.stub_objects.push(stub);
bind_constructor!(
core,
global,
"WeakMap",
ctor_ptr,
oxide_builtins::weak_map::weak_map_constructor::<crate::vm::Vm>,
0,
hash: true
);
}