feat: MessageChannel 构造器与 MessagePort 方法绑定及全局槽

This commit is contained in:
2026-10-09 04:07:22 +00:00
parent 10628928bc
commit a84f430739
5 changed files with 816 additions and 27 deletions
@@ -0,0 +1,121 @@
use std::sync::Arc;
use crate::bind_constructor;
use crate::bindings::{apply_binding_table, bind_accessor_getter, configure_native_constructor};
use oxide_kernel::kernel::{KernelCore, KernelSession};
use oxide_types::object::{JsObject, PropAttributes};
use oxide_types::value::JsValue;
/// 把 MessageChannel 构造器与 MessagePort 原型方法绑定到 global。
///
/// 935.1.1 的两枚 P 字段(`message_channel_constructor` / `message_port_proto`)
/// 是空对象占位,本函数就地填充(不新建对象——P 字段本身就是槽位,快照/脏检查/
/// 收尾枚举已覆盖)。
///
/// # 幂等
/// 本函数从三条路径到达:`init_kernel_builtins`(占位是空对象)、`rebind_dirty_
/// builtins` 的 `message_channel` 分支(占位是重建后的空对象)、global-dirty
/// 路径(占位可能已填满)。全部槽写经 `lookup_position` 前置守卫,有槽即跳过;
/// `bind_constructor!` 的全局槽臂自带既有槽原位更新,天然幂等。
///
/// `realm_id` 未使用(MessageChannel 无 well-known 符号键),保留签名与其他
/// 绑定函数一致。
pub fn bind_message_channel(core: &Arc<KernelCore>, session: &KernelSession, global: &mut JsObject, _realm_id: u32) {
let world = session.builtin_world();
let ctor_ptr = world.message_channel_constructor.as_ptr() as *mut JsObject;
let ctor = unsafe { &mut *ctor_ptr };
let proto_ptr = world.message_port_proto.as_ptr() as *mut JsObject;
let proto = unsafe { &mut *proto_ptr };
let sf = core.perm_interner().as_ref();
let sh = core.shape_forge().as_ref();
// ---- 填构造器占位 ----
ctor.set_function(true);
// prototype 槽 → 原型对象(描述符 {f,f,f})。
let si_prototype = sf.intern("prototype").0;
if sh.lookup_position(ctor.shape_id(), si_prototype).is_none() {
let shape = sh.make_shape(ctor.shape_id(), si_prototype);
ctor.set_shape_id(shape);
let pos = ctor.push_prop(JsValue::from_js_object(proto_ptr));
ctor.set_data_meta(pos, PropAttributes::new(false, false, false));
ctor.bump_generation();
}
// name 槽 → "MessageChannel"(描述符 {f,f,t})。
let si_name = sf.intern("name").0;
if sh.lookup_position(ctor.shape_id(), si_name).is_none() {
let shape = sh.make_shape(ctor.shape_id(), si_name);
ctor.set_shape_id(shape);
ctor.ensure_hash_props().push(JsValue::perm_string(sf.string_ptr(sf.intern("MessageChannel").0)));
let pos = ctor.hash_props_vec().map_or(0, |v| v.len() as u32).saturating_sub(1);
ctor.set_data_meta(pos, PropAttributes::new(false, false, true));
ctor.bump_generation();
}
// [[Prototype]] → Function.prototype(幂等,裸写槽)。
let fn_proto_val = JsValue::from_js_object(world.function_proto.as_ptr() as *mut JsObject);
let _ = ctor.set_proto(fn_proto_val);
configure_native_constructor(
ctor,
oxide_builtins::message_channel::message_channel_constructor::<crate::vm::Vm> as *const (),
0,
);
bind_constructor!(
core,
global,
"MessageChannel",
ctor_ptr,
oxide_builtins::message_channel::message_channel_constructor::<crate::vm::Vm>,
0,
hash: true
);
// ---- 填原型占位 ----
// constructor 槽 → 构造器对象(描述符 {t,f,t})。
let si_constructor = sf.intern("constructor").0;
if sh.lookup_position(proto.shape_id(), si_constructor).is_none() {
let shape = sh.make_shape(proto.shape_id(), si_constructor);
proto.set_shape_id(shape);
let pos = proto.push_prop(JsValue::from_js_object(ctor_ptr));
proto.set_data_meta(pos, PropAttributes::new(true, false, true));
proto.bump_generation();
}
// [[Prototype]] → Object.prototype(幂等,裸写槽)。
let object_proto_val = JsValue::from_js_object(world.object_proto.as_ptr() as *mut JsObject);
let _ = proto.set_proto(object_proto_val);
// 原型方法:postMessage / close / start(每方法先 lookup_position 守卫)。
let si_post_message = sf.intern("postMessage").0;
if sh.lookup_position(proto.shape_id(), si_post_message).is_none() {
apply_binding_table(
world,
proto,
core,
&[
(
"postMessage",
oxide_builtins::message_channel::message_port_post_message::<crate::vm::Vm> as *const (),
2,
),
("close", oxide_builtins::message_channel::message_port_close::<crate::vm::Vm> as *const (), 0),
("start", oxide_builtins::message_channel::message_port_start::<crate::vm::Vm> as *const (), 0),
],
);
}
// readyState 原型访问器(set 恒 undefined),lookup_position 守卫。
let si_ready_state = sf.intern("readyState").0;
if sh.lookup_position(proto.shape_id(), si_ready_state).is_none() {
bind_accessor_getter(
core,
session,
proto,
"readyState",
oxide_builtins::message_channel::message_port_ready_state::<crate::vm::Vm> as *const (),
);
}
}
+14
View File
@@ -36,6 +36,8 @@ pub mod bind_json;
pub mod bind_map;
/// Math 单例对象及其 native 方法绑定。
pub mod bind_math;
/// MessageChannel 构造器与 MessagePort 原型方法的 native 绑定(就地填充占位)。
pub mod bind_message_channel;
/// Number 构造器与原型的 native 方法绑定(含常量属性)。
pub mod bind_number;
/// Object 构造器与原型的 native 方法绑定。
@@ -1050,6 +1052,11 @@ pub fn bind_global_builtin_slots(
oxide_builtins::symbol::symbol_constructor::<crate::vm::Vm> as *const (),
1,
);
configure_existing_ctor(
&world.message_channel_constructor,
oxide_builtins::message_channel::message_channel_constructor::<crate::vm::Vm> as *const (),
0,
);
for (name, value) in [
("Object", JsValue::from_js_object(world.object_constructor.as_ptr() as *mut JsObject)),
@@ -1073,6 +1080,10 @@ pub fn bind_global_builtin_slots(
("Function", JsValue::from_js_object(world.function_constructor.as_ptr() as *mut JsObject)),
("RegExp", JsValue::from_js_object(world.regexp_constructor.as_ptr() as *mut JsObject)),
("Symbol", JsValue::from_js_object(world.symbol_constructor.as_ptr() as *mut JsObject)),
(
"MessageChannel",
JsValue::from_js_object(world.message_channel_constructor.as_ptr() as *mut JsObject),
),
("Math", JsValue::from_js_object(world.math_object.as_ptr() as *mut JsObject)),
("JSON", JsValue::from_js_object(world.json_object.as_ptr() as *mut JsObject)),
("Temporal", JsValue::from_js_object(world.temporal_object.as_ptr() as *mut JsObject)),
@@ -1312,6 +1323,9 @@ pub fn rebind_dirty_builtins(
if dirty.map_or(true, |d| d.stubs) {
bind_bigint::bind_bigint(core, session, global, realm_id);
}
if dirty.map_or(true, |d| d.message_channel) {
bind_message_channel::bind_message_channel(core, session, global, realm_id);
}
if dirty.map_or(true, |d| d.console) {
bind_console::bind_console(core, session, global);
}