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

134 lines
6.0 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.
use std::sync::Arc;
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;
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),
(
"WeakSet",
oxide_builtins::stubs::weakset_stub::<crate::vm::Vm> as *const (),
0,
Some("WeakSet"),
true,
),
(
"WeakRef",
oxide_builtins::stubs::weakref_stub::<crate::vm::Vm> as *const (),
1,
Some("WeakRef"),
true,
),
(
"FinalizationRegistry",
oxide_builtins::stubs::finalization_registry_stub::<crate::vm::Vm> as *const (),
1,
Some("FinalizationRegistry"),
true,
),
];
/// 在 `obj` 上按键 `si` 安装数据属性,描述符为 `attributes`:
/// 开 shape 槽,值写入命名属性区并置描述符元数据。
fn set_data_property(core: &Arc<KernelCore>, obj: &mut JsObject, si: u32, value: JsValue, attributes: PropAttributes) {
let shape = core.shape_forge().make_shape(obj.shape_id(), si);
obj.set_shape_id(shape);
let pos = obj.push_prop(value);
obj.set_data_meta(pos, attributes);
obj.bump_generation();
}
/// 把未实现内置(Proxy/WeakSet/WeakRef/FinalizationRegistry)的 stub 构造器
/// 绑定到 global,并登记到 `stub_objects` 供快照跟踪。WeakMap 已落地真构造器,
/// 走 `bind_weak` 绑定面,不在此表。
///
/// # 副作用
/// 每个 stub 按规范补装构造器面属性:`length`、`name`(四族全装);弱族 stub
/// 另装 `prototype`(新建 plain 对象,原型链落 Object.prototype,其上带指回
/// stub 的 `constructor` 与 @@toStringTag)——规范 25.1 的 %Proxy% 无
/// prototype 属性,不装;描述符均不可枚举,`prototype` 另不可写、不可配置。
/// 原型对象登记进 world 释放登记表,与 stub 对象同生死,session 收尾统一释放。
///
/// `realm_id` 是目标所属 realm 的编号:`@@toStringTag` 符号键按 (realm 编号,
/// 局部下标) 编码,realm 编号为 0 时与旧编码逐字节一致。
pub fn bind_stubs(core: &Arc<KernelCore>, session: &mut KernelSession, global: &mut JsObject, realm_id: u32) {
let builtin_world = Arc::get_mut(&mut session.builtin_world)
.expect("BuiltinWorld must be uniquely owned during init_kernel_builtins");
let object_proto_ptr = builtin_world.object_proto.as_ptr() as *mut JsObject;
for (name, native_fn, arg_count, tag, has_prototype) in STUBS {
let mut stub = JsObject::new_empty(
EMPTY_SHAPE_ID,
JsValue::from_js_object(builtin_world.function_proto.as_ptr() as *mut JsObject),
);
stub.set_function(true);
configure_native_constructor(&mut stub, native_fn, arg_count);
let stub = P::new(stub);
let stub_ptr = stub.as_ptr() as *mut JsObject;
// 构造器面属性:length / name 四族全装;prototype 仅弱族 stub(%Proxy% 无)。
// SAFETY: stub 尚未发布到 global,局部 Arc 为唯一持有者,可变访问无读者冲突。
let stub_obj = unsafe { &mut *stub_ptr };
if has_prototype {
// 原型对象:constructor 回指 + @@toStringTag(四弱族);属性装完再
// 登记释放登记表,登记点世代即洁净基线。
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;
set_data_property(
core,
&mut proto,
si_constructor,
JsValue::from_js_object(stub_ptr),
PropAttributes::new(true, false, true),
);
if let Some(tag_name) = tag {
let tag_key = oxide_types::private_key::encode_symbol_key(
realm_id,
oxide_types::private_key::WELL_KNOWN_SYMBOL_TO_STRING_TAG,
);
let tag_val =
JsValue::perm_string(core.perm_interner().string_ptr(core.perm_interner().intern(tag_name).0));
set_data_property(core, &mut proto, tag_key, tag_val, PropAttributes::new(false, false, true));
}
let proto_ptr = Box::into_raw(Box::new(proto));
builtin_world.track_leaked_object(proto_ptr);
let si_prototype = core.perm_interner().intern("prototype").0;
set_data_property(
core,
stub_obj,
si_prototype,
JsValue::from_js_object(proto_ptr),
PropAttributes::new(false, false, false),
);
}
let si_length = core.perm_interner().intern("length").0;
set_data_property(
core,
stub_obj,
si_length,
JsValue::int(arg_count as i32),
PropAttributes::new(false, false, true),
);
let si_name = core.perm_interner().intern("name").0;
let name_val = JsValue::perm_string(core.perm_interner().string_ptr(core.perm_interner().intern(name).0));
set_data_property(core, stub_obj, si_name, name_val, PropAttributes::new(false, false, true));
bind_global_value(core, global, name, JsValue::from_js_object(stub_ptr));
builtin_world.stub_objects.push(stub);
}
}