feat: BroadcastChannel 内核接线两 P 字段加 BuiltinId 加脏家族位加注册表字段

This commit is contained in:
2026-10-09 04:26:22 +00:00
parent a84f430739
commit dd373ef3f0
11 changed files with 82 additions and 26 deletions
Generated
+19 -19
View File
@@ -1160,7 +1160,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_builtins" name = "oxide_builtins"
version = "0.8.86" version = "0.8.87"
dependencies = [ dependencies = [
"chrono", "chrono",
"fast-float", "fast-float",
@@ -1185,7 +1185,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_bytecode" name = "oxide_bytecode"
version = "0.8.86" version = "0.8.87"
dependencies = [ dependencies = [
"num-bigint", "num-bigint",
"oxide_log", "oxide_log",
@@ -1193,7 +1193,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_cfg" name = "oxide_cfg"
version = "0.8.86" version = "0.8.87"
dependencies = [ dependencies = [
"oxide_bytecode", "oxide_bytecode",
"oxide_emit", "oxide_emit",
@@ -1204,7 +1204,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_cli" name = "oxide_cli"
version = "0.8.86" version = "0.8.87"
dependencies = [ dependencies = [
"ansi_term", "ansi_term",
"bumpalo", "bumpalo",
@@ -1226,7 +1226,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_code_cache" name = "oxide_code_cache"
version = "0.8.86" version = "0.8.87"
dependencies = [ dependencies = [
"lru", "lru",
"oxide_bytecode", "oxide_bytecode",
@@ -1235,7 +1235,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_compiler" name = "oxide_compiler"
version = "0.8.86" version = "0.8.87"
dependencies = [ dependencies = [
"oxide_bytecode", "oxide_bytecode",
"oxide_cfg", "oxide_cfg",
@@ -1255,7 +1255,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_dce" name = "oxide_dce"
version = "0.8.86" version = "0.8.87"
dependencies = [ dependencies = [
"oxide_bytecode", "oxide_bytecode",
"oxide_cfg", "oxide_cfg",
@@ -1269,7 +1269,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_emit" name = "oxide_emit"
version = "0.8.86" version = "0.8.87"
dependencies = [ dependencies = [
"num-bigint", "num-bigint",
"oxc_allocator", "oxc_allocator",
@@ -1284,7 +1284,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_engine" name = "oxide_engine"
version = "0.8.86" version = "0.8.87"
dependencies = [ dependencies = [
"oxide_bytecode", "oxide_bytecode",
"oxide_compiler", "oxide_compiler",
@@ -1296,7 +1296,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_ir" name = "oxide_ir"
version = "0.8.86" version = "0.8.87"
dependencies = [ dependencies = [
"oxide_bytecode", "oxide_bytecode",
"oxide_log", "oxide_log",
@@ -1305,7 +1305,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_kernel" name = "oxide_kernel"
version = "0.8.86" version = "0.8.87"
dependencies = [ dependencies = [
"bumpalo", "bumpalo",
"dashmap", "dashmap",
@@ -1319,7 +1319,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_liveness" name = "oxide_liveness"
version = "0.8.86" version = "0.8.87"
dependencies = [ dependencies = [
"oxide_bytecode", "oxide_bytecode",
"oxide_cfg", "oxide_cfg",
@@ -1331,7 +1331,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_log" name = "oxide_log"
version = "0.8.86" version = "0.8.87"
dependencies = [ dependencies = [
"tracing", "tracing",
"tracing-appender", "tracing-appender",
@@ -1340,7 +1340,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_parser" name = "oxide_parser"
version = "0.8.86" version = "0.8.87"
dependencies = [ dependencies = [
"oxc_allocator", "oxc_allocator",
"oxc_ast", "oxc_ast",
@@ -1355,7 +1355,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_regalloc" name = "oxide_regalloc"
version = "0.8.86" version = "0.8.87"
dependencies = [ dependencies = [
"oxide_bytecode", "oxide_bytecode",
"oxide_cfg", "oxide_cfg",
@@ -1371,7 +1371,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_runtime_api" name = "oxide_runtime_api"
version = "0.8.86" version = "0.8.87"
dependencies = [ dependencies = [
"num-bigint", "num-bigint",
"num-traits", "num-traits",
@@ -1384,7 +1384,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_test262" name = "oxide_test262"
version = "0.8.86" version = "0.8.87"
dependencies = [ dependencies = [
"oxide_bytecode", "oxide_bytecode",
"oxide_compiler", "oxide_compiler",
@@ -1402,7 +1402,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_types" name = "oxide_types"
version = "0.8.86" version = "0.8.87"
dependencies = [ dependencies = [
"bumpalo", "bumpalo",
"dashmap", "dashmap",
@@ -1415,7 +1415,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_vm" name = "oxide_vm"
version = "0.8.86" version = "0.8.87"
dependencies = [ dependencies = [
"bumpalo", "bumpalo",
"chrono", "chrono",
+1 -1
View File
@@ -23,7 +23,7 @@ members = [
] ]
[workspace.package] [workspace.package]
version = "0.8.86" version = "0.8.87"
edition = "2021" edition = "2021"
license = "MIT" license = "MIT"
rust-version = "1.80" rust-version = "1.80"
@@ -508,6 +508,12 @@ impl BuiltinWorld {
let message_port_proto = P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null())); let message_port_proto = P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null()));
let message_channel_constructor = P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null())); let message_channel_constructor = P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null()));
// BroadcastChannel 原型与构造器的内核接线占位(空对象):真实原型/
// 构造器本体与原型链连线由绑定层后续任务填充,本处只预留槽位使快照/
// 脏检查/收尾枚举覆盖到这两枚 P 字段。
let broadcast_channel_proto = P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null()));
let broadcast_channel_constructor = P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null()));
let (date_proto, date_constructor) = make_named_pair(string_forge, shape_forge, labels, "Date"); let (date_proto, date_constructor) = make_named_pair(string_forge, shape_forge, labels, "Date");
let (set_proto, set_constructor) = make_named_pair(string_forge, shape_forge, labels, "Set"); let (set_proto, set_constructor) = make_named_pair(string_forge, shape_forge, labels, "Set");
let (map_proto, map_constructor) = make_named_pair(string_forge, shape_forge, labels, "Map"); let (map_proto, map_constructor) = make_named_pair(string_forge, shape_forge, labels, "Map");
@@ -657,6 +663,8 @@ impl BuiltinWorld {
console_object, console_object,
message_port_proto, message_port_proto,
message_channel_constructor, message_channel_constructor,
broadcast_channel_proto,
broadcast_channel_constructor,
leaked_objects: std::cell::RefCell::new(Vec::new()), leaked_objects: std::cell::RefCell::new(Vec::new()),
}; };
wire_builtin_world_links(&world); wire_builtin_world_links(&world);
@@ -407,6 +407,20 @@ impl BuiltinWorld {
(current.message_port_proto.clone(), current.message_channel_constructor.clone()) (current.message_port_proto.clone(), current.message_channel_constructor.clone())
}; };
// BroadcastChannel 原型与构造器:脏则换新空对象占位(与全量构造同形),
// 未脏沿用旧指针。
let (broadcast_channel_proto, broadcast_channel_constructor) = if dirty.broadcast_channel {
(
P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null())),
P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null())),
)
} else {
(
current.broadcast_channel_proto.clone(),
current.broadcast_channel_constructor.clone(),
)
};
// 迭代器原型与资源栈原型依赖 Object.prototype(链到其上):object 家族重建时 // 迭代器原型与资源栈原型依赖 Object.prototype(链到其上):object 家族重建时
// 一并重建,否则旧原型链指向已释放的 object_proto。 // 一并重建,否则旧原型链指向已释放的 object_proto。
let ( let (
@@ -559,6 +573,8 @@ impl BuiltinWorld {
console_object, console_object,
message_port_proto, message_port_proto,
message_channel_constructor, message_channel_constructor,
broadcast_channel_proto,
broadcast_channel_constructor,
leaked_objects: std::cell::RefCell::new(Vec::new()), leaked_objects: std::cell::RefCell::new(Vec::new()),
}; };
wire_builtin_world_links(&world); wire_builtin_world_links(&world);
+11 -1
View File
@@ -144,6 +144,12 @@ pub struct BuiltinWorld {
/// `MessageChannel` 构造器槽位:纯内核接线占位(空对象),真实构造器 /// `MessageChannel` 构造器槽位:纯内核接线占位(空对象),真实构造器
/// 本体由绑定层后续任务填充。 /// 本体由绑定层后续任务填充。
pub message_channel_constructor: P<JsObject>, pub message_channel_constructor: P<JsObject>,
/// `BroadcastChannel.prototype` 槽位:纯内核接线占位(空对象),真实
/// 原型本体与构造器对由绑定层后续任务填充;脏家族位为 `broadcast_channel`。
pub broadcast_channel_proto: P<JsObject>,
/// `BroadcastChannel` 构造器槽位:纯内核接线占位(空对象),真实构造器
/// 本体由绑定层后续任务填充。
pub broadcast_channel_constructor: P<JsObject>,
/// 释放登记表(`Box::into_raw` 对象的清单,session 收尾统一释放,非内存泄漏): /// 释放登记表(`Box::into_raw` 对象的清单,session 收尾统一释放,非内存泄漏):
/// 绑定层经 `Box::into_raw` 持有的函数/宿主对象(方法 wrapper、访问器、 /// 绑定层经 `Box::into_raw` 持有的函数/宿主对象(方法 wrapper、访问器、
/// 错误构造器、Reflect/Iterator、内建原型构造器、`$262` 宿主等)。 /// 错误构造器、Reflect/Iterator、内建原型构造器、`$262` 宿主等)。
@@ -374,7 +380,7 @@ impl BuiltinWorld {
/// session 收尾(`teardown_heap_data`)与选择性重建收尾(`retire_replaced`) /// session 收尾(`teardown_heap_data`)与选择性重建收尾(`retire_replaced`)
/// 的 P 字段枚举唯一入口:`BuiltinWorld` 新增 P 字段须在此同步补一行,否则 /// 的 P 字段枚举唯一入口:`BuiltinWorld` 新增 P 字段须在此同步补一行,否则
/// 收尾时该字段属性区无法释放、重建原型槽改写/释放漏掉该字段。 /// 收尾时该字段属性区无法释放、重建原型槽改写/释放漏掉该字段。
pub(crate) fn all_p_fields(&self) -> [&P<JsObject>; 97] { pub(crate) fn all_p_fields(&self) -> [&P<JsObject>; 99] {
[ [
&self.object_proto, &self.object_proto,
&self.array_proto, &self.array_proto,
@@ -473,6 +479,8 @@ impl BuiltinWorld {
&self.console_object, &self.console_object,
&self.message_port_proto, &self.message_port_proto,
&self.message_channel_constructor, &self.message_channel_constructor,
&self.broadcast_channel_proto,
&self.broadcast_channel_constructor,
] ]
} }
@@ -608,6 +616,8 @@ impl BuiltinWorld {
BuiltinId::AsyncIteratorProto => &self.async_iterator_proto, BuiltinId::AsyncIteratorProto => &self.async_iterator_proto,
BuiltinId::MessagePortProto => &self.message_port_proto, BuiltinId::MessagePortProto => &self.message_port_proto,
BuiltinId::MessageChannelCtor => &self.message_channel_constructor, BuiltinId::MessageChannelCtor => &self.message_channel_constructor,
BuiltinId::BroadcastChannelProto => &self.broadcast_channel_proto,
BuiltinId::BroadcastChannelCtor => &self.broadcast_channel_constructor,
} }
} }
} }
+14 -5
View File
@@ -1,4 +1,4 @@
//! 内置对象 id 枚举(`BuiltinId` 87 变体 + `ALL` 顺序钉表)、世代快照 //! 内置对象 id 枚举(`BuiltinId` 89 变体 + `ALL` 顺序钉表)、世代快照
//! (`BuiltinSnapshot`)与按家族划分的脏标记位集(`BuiltinDirtySet`); //! (`BuiltinSnapshot`)与按家族划分的脏标记位集(`BuiltinDirtySet`);
//! `NUM_BUILTINS` 文档承载"新增 BuiltinWorld 字段须同步"四处约束注记。 //! `NUM_BUILTINS` 文档承载"新增 BuiltinWorld 字段须同步"四处约束注记。
@@ -11,7 +11,7 @@ use crate::builtin::BuiltinWorld;
/// 维护注意:每个新增的 `BuiltinWorld` 对象字段都必须加到这里以及 /// 维护注意:每个新增的 `BuiltinWorld` 对象字段都必须加到这里以及
/// `KernelSession::dirty_since_snapshot()`,以便选择性重置重建正确的 /// `KernelSession::dirty_since_snapshot()`,以便选择性重置重建正确的
/// builtin 家族。 /// builtin 家族。
pub const NUM_BUILTINS: usize = 87; pub const NUM_BUILTINS: usize = 89;
/// 内置对象枚举 id,与 `BuiltinWorld` 中的存储槽一一对应。 /// 内置对象枚举 id,与 `BuiltinWorld` 中的存储槽一一对应。
/// ///
@@ -107,6 +107,8 @@ pub enum BuiltinId {
AsyncIteratorProto = 84, AsyncIteratorProto = 84,
MessagePortProto = 85, MessagePortProto = 85,
MessageChannelCtor = 86, MessageChannelCtor = 86,
BroadcastChannelProto = 87,
BroadcastChannelCtor = 88,
} }
impl BuiltinId { impl BuiltinId {
@@ -201,6 +203,8 @@ impl BuiltinId {
BuiltinId::AsyncIteratorProto, BuiltinId::AsyncIteratorProto,
BuiltinId::MessagePortProto, BuiltinId::MessagePortProto,
BuiltinId::MessageChannelCtor, BuiltinId::MessageChannelCtor,
BuiltinId::BroadcastChannelProto,
BuiltinId::BroadcastChannelCtor,
]; ];
} }
@@ -277,6 +281,7 @@ pub struct BuiltinDirtySet {
pub global: bool, pub global: bool,
pub console: bool, pub console: bool,
pub message_channel: bool, pub message_channel: bool,
pub broadcast_channel: bool,
} }
impl BuiltinDirtySet { impl BuiltinDirtySet {
@@ -311,6 +316,7 @@ impl BuiltinDirtySet {
global: true, global: true,
console: true, console: true,
message_channel: true, message_channel: true,
broadcast_channel: true,
} }
} }
@@ -339,6 +345,7 @@ impl BuiltinDirtySet {
|| self.stubs || self.stubs
|| self.console || self.console
|| self.message_channel || self.message_channel
|| self.broadcast_channel
} }
/// 是否存在任何污染(builtin world 或 global object)。 /// 是否存在任何污染(builtin world 或 global object)。
@@ -351,13 +358,13 @@ impl BuiltinDirtySet {
mod tests { mod tests {
use super::*; use super::*;
/// 槽对齐面:ALL 表与判别值 0..86 严格同序,快照数组随 NUM_BUILTINS /// 槽对齐面:ALL 表与判别值 0..88 严格同序,快照数组随 NUM_BUILTINS
/// 自动扩维、逐槽对齐。 /// 自动扩维、逐槽对齐。
#[test] #[test]
fn builtin_snapshot_all_slots_aligned() { fn builtin_snapshot_all_slots_aligned() {
assert_eq!(NUM_BUILTINS, 87); assert_eq!(NUM_BUILTINS, 89);
assert_eq!(BuiltinId::ALL.len(), NUM_BUILTINS); assert_eq!(BuiltinId::ALL.len(), NUM_BUILTINS);
for i in 0..86usize { for i in 0..88usize {
assert_eq!(BuiltinId::ALL[i] as usize, i); assert_eq!(BuiltinId::ALL[i] as usize, i);
} }
assert_eq!(BuiltinId::ALL[81], BuiltinId::SharedArrayBufferProto); assert_eq!(BuiltinId::ALL[81], BuiltinId::SharedArrayBufferProto);
@@ -366,6 +373,8 @@ mod tests {
assert_eq!(BuiltinId::ALL[84], BuiltinId::AsyncIteratorProto); assert_eq!(BuiltinId::ALL[84], BuiltinId::AsyncIteratorProto);
assert_eq!(BuiltinId::ALL[85], BuiltinId::MessagePortProto); assert_eq!(BuiltinId::ALL[85], BuiltinId::MessagePortProto);
assert_eq!(BuiltinId::ALL[86], BuiltinId::MessageChannelCtor); assert_eq!(BuiltinId::ALL[86], BuiltinId::MessageChannelCtor);
assert_eq!(BuiltinId::ALL[87], BuiltinId::BroadcastChannelProto);
assert_eq!(BuiltinId::ALL[88], BuiltinId::BroadcastChannelCtor);
// 快照经 session 全量构造路径采集,generations 数组维度 = 槽数。 // 快照经 session 全量构造路径采集,generations 数组维度 = 槽数。
use crate::kernel::{KernelConfig, KernelCore, KernelSession}; use crate::kernel::{KernelConfig, KernelCore, KernelSession};
@@ -198,6 +198,9 @@ impl KernelSession {
console: gen(BuiltinId::Console) != snap(BuiltinId::Console), console: gen(BuiltinId::Console) != snap(BuiltinId::Console),
message_channel: gen(BuiltinId::MessagePortProto) != snap(BuiltinId::MessagePortProto) message_channel: gen(BuiltinId::MessagePortProto) != snap(BuiltinId::MessagePortProto)
|| gen(BuiltinId::MessageChannelCtor) != snap(BuiltinId::MessageChannelCtor), || gen(BuiltinId::MessageChannelCtor) != snap(BuiltinId::MessageChannelCtor),
broadcast_channel: gen(BuiltinId::BroadcastChannelProto)
!= snap(BuiltinId::BroadcastChannelProto)
|| gen(BuiltinId::BroadcastChannelCtor) != snap(BuiltinId::BroadcastChannelCtor),
}; };
// wrapper 本体被写不落在任何家族位上(写的是 wrapper 自身而非所属 P // wrapper 本体被写不落在任何家族位上(写的是 wrapper 自身而非所属 P
// 对象):收缩为全脏,强制重建全部家族与 global,使被写的可复用 // 对象):收缩为全脏,强制重建全部家族与 global,使被写的可复用
+2
View File
@@ -102,6 +102,8 @@ pub enum ProtoKind {
BigUint64ArrayConstructor, BigUint64ArrayConstructor,
// 消息通道原型 // 消息通道原型
MessagePortProto, MessagePortProto,
// 广播通道原型
BroadcastChannelProto,
} }
/// builtins 依赖的 `Vm` 能力集合。 /// builtins 依赖的 `Vm` 能力集合。
+1
View File
@@ -143,6 +143,7 @@ impl oxide_runtime_api::VmHost for Vm {
ProtoKind::BigInt64ArrayConstructor => &world.bigint64array_constructor, ProtoKind::BigInt64ArrayConstructor => &world.bigint64array_constructor,
ProtoKind::BigUint64ArrayConstructor => &world.biguint64array_constructor, ProtoKind::BigUint64ArrayConstructor => &world.biguint64array_constructor,
ProtoKind::MessagePortProto => &world.message_port_proto, ProtoKind::MessagePortProto => &world.message_port_proto,
ProtoKind::BroadcastChannelProto => &world.broadcast_channel_proto,
}; };
P::as_ptr(p) as *mut JsObject P::as_ptr(p) as *mut JsObject
} }
+5
View File
@@ -61,6 +61,11 @@ pub(crate) struct GcState {
/// 开启后每个顶层指令边界做一次完整收集,与强制收集共用同一安全点入口, /// 开启后每个顶层指令边界做一次完整收集,与强制收集共用同一安全点入口,
/// 同时跳过两个水位触发的档(完整收集已涵盖其全部工作)。 /// 同时跳过两个水位触发的档(完整收集已涵盖其全部工作)。
pub(crate) gc_pressure_mode: bool, pub(crate) gc_pressure_mode: bool,
/// BroadcastChannel per-realm 弱引用注册表:通道名 → 通道对象裸指针列表
/// (弱引用,不保活)。构造器分配后登记、close 注销、GC sweep 按 mark 位
/// 剪枝。当前仅声明,不填不读(登记与剪枝由后续任务接线)。
#[allow(dead_code)]
pub(crate) broadcast_channels: HashMap<String, Vec<*mut JsObject>>,
} }
impl GcState { impl GcState {
+2
View File
@@ -101,6 +101,7 @@ impl Vm {
gc_watermark: gc_threshold, gc_watermark: gc_threshold,
pending_forced_collect: false, pending_forced_collect: false,
gc_pressure_mode: gc_pressure_mode_from_env(), gc_pressure_mode: gc_pressure_mode_from_env(),
broadcast_channels: std::collections::HashMap::new(),
}), }),
symbols: RefCell::new(SymbolState { symbols: RefCell::new(SymbolState {
symbol_descriptions: Vec::new(), symbol_descriptions: Vec::new(),
@@ -257,6 +258,7 @@ impl Vm {
gc_watermark: gc_threshold, gc_watermark: gc_threshold,
pending_forced_collect: false, pending_forced_collect: false,
gc_pressure_mode: gc_pressure_mode_from_env(), gc_pressure_mode: gc_pressure_mode_from_env(),
broadcast_channels: std::collections::HashMap::new(),
}), }),
symbols: RefCell::new(SymbolState { symbols: RefCell::new(SymbolState {
symbol_descriptions: Vec::new(), symbol_descriptions: Vec::new(),