feat: 事件目标弱引用注册表加三方法加原型链

This commit is contained in:
2026-10-10 09:06:08 +00:00
parent 8a8c3e9b9c
commit 6ecd3aed89
20 changed files with 890 additions and 123 deletions
+10 -1
View File
@@ -42,11 +42,12 @@ pub(crate) enum RootGroup {
Global,
WorkerObjects,
DisposeStack,
EventTargets,
}
impl RootGroup {
/// 根组总数(与变体数同源,绑定逐组计数数组的长度)。
pub const COUNT: usize = 27;
pub const COUNT: usize = 28;
}
impl Vm {
@@ -180,6 +181,14 @@ impl Vm {
for &worker_obj in self.worker_objects.values() {
f(RootGroup::WorkerObjects, worker_obj);
}
// EventTarget 监听器注册表:监听器回调是 GC 根(存活目标的回调随目标存活,
// 漏根 → 回调被 sweep 释放 → 派发解引用悬垂)。弱键剪枝见 sweep;此处
// 无条件标活全部回调(死目标的回调多活一轮收集,非泄漏,sweep 已剪其条目)。
for state in self.realm.gc.borrow().event_targets.values() {
for entry in &state.listeners {
f(RootGroup::EventTargets, entry.callback);
}
}
}
/// GC 根统一枚举入口:遍历的字段清单与 `for_each_value` 相同。
+24 -1
View File
@@ -4,7 +4,7 @@ use std::ffi::c_void;
use std::sync::Arc;
use oxide_kernel::KernelCore;
use oxide_runtime_api::{ProtoKind, ShapeNode};
use oxide_runtime_api::{ListenerEntry, ProtoKind, ShapeNode};
use oxide_types::mem::P;
use oxide_types::object::{Cell, JsObject, PropAttributes};
use oxide_types::value::JsValue;
@@ -449,4 +449,27 @@ impl oxide_runtime_api::VmHost for Vm {
fn bc_lookup(&self, name: &str) -> Vec<*mut JsObject> {
self.realm.gc.borrow().broadcast_channels.get(name).cloned().unwrap_or_default()
}
fn et_register(&self, target: *mut JsObject, entry: ListenerEntry) {
self.realm
.gc
.borrow_mut()
.event_targets
.entry(target)
.or_default()
.listeners
.push(entry);
}
fn et_unregister(&self, target: *mut JsObject, type_si: u32, callback: JsValue, capture: bool) {
let mut gc = self.realm.gc.borrow_mut();
let should_remove = gc.event_targets.get_mut(&target).is_some_and(|state| {
state.listeners.retain(|e| !(e.type_si == type_si && e.capture == capture && e.callback == callback));
state.listeners.is_empty()
});
if should_remove {
gc.event_targets.remove(&target);
}
}
fn et_lookup(&self, target: *mut JsObject) -> Vec<ListenerEntry> {
self.realm.gc.borrow().event_targets.get(&target).map(|s| s.listeners.clone()).unwrap_or_default()
}
}