mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-23 18:21:13 +08:00
feat: 新增 Event 基类载荷盒、GC 接线、构造器与原型绑定
This commit is contained in:
Generated
+19
-19
@@ -1160,7 +1160,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_builtins"
|
||||
version = "0.14.7"
|
||||
version = "0.14.8"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"fast-float",
|
||||
@@ -1185,7 +1185,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_bytecode"
|
||||
version = "0.14.7"
|
||||
version = "0.14.8"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"oxide_log",
|
||||
@@ -1193,7 +1193,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_cfg"
|
||||
version = "0.14.7"
|
||||
version = "0.14.8"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_emit",
|
||||
@@ -1204,7 +1204,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_cli"
|
||||
version = "0.14.7"
|
||||
version = "0.14.8"
|
||||
dependencies = [
|
||||
"ansi_term",
|
||||
"bumpalo",
|
||||
@@ -1226,7 +1226,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_code_cache"
|
||||
version = "0.14.7"
|
||||
version = "0.14.8"
|
||||
dependencies = [
|
||||
"lru",
|
||||
"oxide_bytecode",
|
||||
@@ -1235,7 +1235,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_compiler"
|
||||
version = "0.14.7"
|
||||
version = "0.14.8"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_cfg",
|
||||
@@ -1255,7 +1255,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_dce"
|
||||
version = "0.14.7"
|
||||
version = "0.14.8"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_cfg",
|
||||
@@ -1269,7 +1269,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_emit"
|
||||
version = "0.14.7"
|
||||
version = "0.14.8"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"oxc_allocator",
|
||||
@@ -1284,7 +1284,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_engine"
|
||||
version = "0.14.7"
|
||||
version = "0.14.8"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_compiler",
|
||||
@@ -1296,7 +1296,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_ir"
|
||||
version = "0.14.7"
|
||||
version = "0.14.8"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_log",
|
||||
@@ -1305,7 +1305,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_kernel"
|
||||
version = "0.14.7"
|
||||
version = "0.14.8"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"dashmap",
|
||||
@@ -1319,7 +1319,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_liveness"
|
||||
version = "0.14.7"
|
||||
version = "0.14.8"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_cfg",
|
||||
@@ -1331,7 +1331,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_log"
|
||||
version = "0.14.7"
|
||||
version = "0.14.8"
|
||||
dependencies = [
|
||||
"tracing",
|
||||
"tracing-appender",
|
||||
@@ -1340,7 +1340,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_parser"
|
||||
version = "0.14.7"
|
||||
version = "0.14.8"
|
||||
dependencies = [
|
||||
"oxc_allocator",
|
||||
"oxc_ast",
|
||||
@@ -1355,7 +1355,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_regalloc"
|
||||
version = "0.14.7"
|
||||
version = "0.14.8"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_cfg",
|
||||
@@ -1371,7 +1371,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_runtime_api"
|
||||
version = "0.14.7"
|
||||
version = "0.14.8"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"num-traits",
|
||||
@@ -1384,7 +1384,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_test262"
|
||||
version = "0.14.7"
|
||||
version = "0.14.8"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_compiler",
|
||||
@@ -1402,7 +1402,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_types"
|
||||
version = "0.14.7"
|
||||
version = "0.14.8"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"dashmap",
|
||||
@@ -1415,7 +1415,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_vm"
|
||||
version = "0.14.7"
|
||||
version = "0.14.8"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"chrono",
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@ members = [
|
||||
]
|
||||
|
||||
[workspace.package]
|
||||
version = "0.14.7"
|
||||
version = "0.14.8"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
rust-version = "1.80"
|
||||
|
||||
@@ -0,0 +1,405 @@
|
||||
//! Event 基类行为面:`Event` 构造器(`new Event(type, init)`)、原型 getter
|
||||
//! (type / target / currentTarget / eventPhase / isTrusted / bubbles /
|
||||
//! cancelable / defaultPrevented / composed)与原型方法(preventDefault /
|
||||
//! stopPropagation / stopImmediatePropagation / composedPath)。
|
||||
//!
|
||||
//! 事件载荷盒(type 串与九项状态位)存于对象 `native_fn` 槽,向 GC 家族表
|
||||
//! 暴露 edges/size/drop 三自由函数。
|
||||
|
||||
use std::mem;
|
||||
|
||||
use oxide_kernel::shape_forge::EMPTY_SHAPE_ID;
|
||||
use oxide_types::object::{JsObject, NativeFnPtr};
|
||||
use oxide_types::value::JsValue;
|
||||
|
||||
use oxide_runtime_api::{NativeResult, ProtoKind, VmHost};
|
||||
|
||||
/// Event 载荷盒:存于对象 `native_fn` 槽(`Box::into_raw`,realm 局部单线程)。
|
||||
/// `r#type` 是事件类型串(GC 字符串边),`target` / `current_target` 是目标
|
||||
/// 对象(GC 对象边,初始 null),其余为简单状态位。
|
||||
struct EventInner {
|
||||
r#type: JsValue,
|
||||
target: JsValue,
|
||||
current_target: JsValue,
|
||||
event_phase: u32,
|
||||
is_trusted: bool,
|
||||
bubbles: bool,
|
||||
cancelable: bool,
|
||||
default_prevented: bool,
|
||||
propagation_stopped: bool,
|
||||
immediate_stopped: bool,
|
||||
composed: bool,
|
||||
}
|
||||
|
||||
/// 取载荷盒指针:仅 Event 标签对象返回 `Some`,其余标签返回 `None`。
|
||||
fn event_payload_ptr(obj: &JsObject) -> Option<*mut EventInner> {
|
||||
if !obj.is_event_obj() {
|
||||
return None;
|
||||
}
|
||||
obj.native_fn().map(|ptr| ptr.as_ptr() as *mut EventInner)
|
||||
}
|
||||
|
||||
/// 收集 Event 的引用边(type 串边与 target / current_target 对象边)。
|
||||
///
|
||||
/// `target` / `current_target` 空窗口(构造期回填之前)为 null,边函数自守,
|
||||
/// 语义自含。
|
||||
pub fn event_native_edges(obj: &JsObject) -> Vec<JsValue> {
|
||||
let Some(ptr) = event_payload_ptr(obj) else {
|
||||
return Vec::new();
|
||||
};
|
||||
if ptr.is_null() {
|
||||
return Vec::new();
|
||||
}
|
||||
// SAFETY: ptr 指向有效载荷盒(槽位仅构造期写入、释放时置空),只读字段。
|
||||
let inner = unsafe { &*ptr };
|
||||
vec![inner.r#type, inner.target, inner.current_target]
|
||||
}
|
||||
|
||||
/// 只读核算 Event 载荷盒字节(不释放)。
|
||||
pub fn event_native_size(obj: &JsObject) -> u64 {
|
||||
let Some(ptr) = event_payload_ptr(obj) else {
|
||||
return 0;
|
||||
};
|
||||
if ptr.is_null() {
|
||||
return 0;
|
||||
}
|
||||
mem::size_of::<EventInner>() as u64
|
||||
}
|
||||
|
||||
/// 释放 Event 载荷盒(`Box<EventInner>`),返回释放字节数。
|
||||
///
|
||||
/// 盒 drop 时 type / target / current_target 的 JsValue 边随盒释放(GC 已
|
||||
/// 判定死对象);槽置空保证重复调用零释放(幂等)。
|
||||
pub fn drop_event_native(obj: &mut JsObject) -> u64 {
|
||||
let bytes = event_native_size(obj);
|
||||
if bytes == 0 {
|
||||
return 0;
|
||||
}
|
||||
let Some(ptr) = event_payload_ptr(obj) else {
|
||||
return 0;
|
||||
};
|
||||
// SAFETY: ptr 非空(event_native_size 已验证),Box::from_raw 恰好释放一次。
|
||||
unsafe {
|
||||
drop(Box::from_raw(ptr));
|
||||
}
|
||||
obj.set_native_fn(None);
|
||||
bytes
|
||||
}
|
||||
|
||||
/// 解析 this 为 Event 载荷盒共享引用:非 Event 对象或无载荷盒返回 None。
|
||||
///
|
||||
/// # 注意事项
|
||||
/// 返回引用按 `'a` 声称为存活,实际存活至载荷盒被 GC 释放;调用方须在无 GC
|
||||
/// 窗口的单 native 函数内消费,不得跨用户调用窗口持有。
|
||||
fn event_inner_of<'a>(this_val: JsValue) -> Option<&'a EventInner> {
|
||||
if !this_val.is_object() {
|
||||
return None;
|
||||
}
|
||||
let obj_ptr = this_val.as_js_object_ptr();
|
||||
if obj_ptr.is_null() {
|
||||
return None;
|
||||
}
|
||||
// SAFETY: this_val 已确认是对象值,obj_ptr 指向合法 JsObject。
|
||||
let obj = unsafe { &*obj_ptr };
|
||||
if !obj.is_event_obj() {
|
||||
return None;
|
||||
}
|
||||
let box_ptr = event_payload_ptr(obj)?;
|
||||
if box_ptr.is_null() {
|
||||
return None;
|
||||
}
|
||||
// SAFETY: box_ptr 指向有效载荷盒(构造期写入、释放时置空);'a 存活由
|
||||
// 调用方「无 GC 窗口内消费」约定保证。
|
||||
Some(unsafe { &*box_ptr })
|
||||
}
|
||||
|
||||
/// 解析 this 为 Event 载荷盒可变引用:非 Event 对象或无载荷盒返回 None。
|
||||
///
|
||||
/// # 注意事项
|
||||
/// 返回引用按 `'a` 声称为存活,实际存活至载荷盒被 GC 释放;调用方须在无 GC
|
||||
/// 窗口的单 native 函数内消费,不得跨用户调用窗口持有。
|
||||
fn event_inner_of_mut<'a>(this_val: JsValue) -> Option<&'a mut EventInner> {
|
||||
if !this_val.is_object() {
|
||||
return None;
|
||||
}
|
||||
let obj_ptr = this_val.as_js_object_ptr();
|
||||
if obj_ptr.is_null() {
|
||||
return None;
|
||||
}
|
||||
// SAFETY: this_val 已确认是对象值,obj_ptr 指向合法 JsObject。
|
||||
let obj = unsafe { &mut *obj_ptr };
|
||||
if !obj.is_event_obj() {
|
||||
return None;
|
||||
}
|
||||
let box_ptr = event_payload_ptr(obj)?;
|
||||
if box_ptr.is_null() {
|
||||
return None;
|
||||
}
|
||||
// SAFETY: box_ptr 指向有效载荷盒(构造期写入、释放时置空);'a 存活由
|
||||
// 调用方「无 GC 窗口内消费」约定保证。
|
||||
Some(unsafe { &mut *box_ptr })
|
||||
}
|
||||
|
||||
/// Event 构造器:`new Event(type, init)`。
|
||||
///
|
||||
/// # 步骤
|
||||
/// 1. 非构造形态(`!constructing_native`)抛 TypeError(HTML 规范只有
|
||||
/// [[Construct]],无 [[Call]])
|
||||
/// 2. type 经完整 ToString 转串;空串抛 SyntaxError
|
||||
/// 3. init 字典读 bubbles / cancelable / composed(缺省 false)
|
||||
/// 4. 建载荷盒入 receiver 的 `native_fn` 槽,置 type_tag
|
||||
/// 5. 返回 receiver
|
||||
///
|
||||
/// # 边界与前提
|
||||
/// - receiver(`args[0]`)是 VM 按构造器 prototype 新分配的对象,proto 已
|
||||
/// 指向 %Event.prototype%;
|
||||
/// - init 缺省(undefined)或非对象时对应标志取 false。
|
||||
///
|
||||
/// # 副作用
|
||||
/// - receiver 的 `native_fn` 槽写入载荷盒、`type_tag` 置 Event 标签。
|
||||
pub fn event_constructor<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
if !vm.constructing_native() {
|
||||
return NativeResult::Err(crate::error::create_type_error(vm, "Event constructor requires new"));
|
||||
}
|
||||
|
||||
let this_val = vm.reg(args[0]);
|
||||
if !this_val.is_object() {
|
||||
return NativeResult::Err(crate::error::create_type_error(vm, "Event constructor requires new"));
|
||||
}
|
||||
|
||||
// type 经完整 ToString 转串(对象经 ToPrimitive,Symbol 抛 TypeError)。
|
||||
let type_val = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() };
|
||||
let type_str = match oxide_runtime_api::to_string_full(type_val, vm) {
|
||||
Ok(s) => s,
|
||||
Err(_) => {
|
||||
if let Some(exc) = vm.take_uncaught_value() {
|
||||
return NativeResult::Err(exc);
|
||||
}
|
||||
return NativeResult::Err(crate::error::create_type_error(vm, "Cannot convert value to a string"));
|
||||
}
|
||||
};
|
||||
if type_str.is_empty() {
|
||||
return NativeResult::Err(crate::error::create_syntax_error(vm, "The provided type is empty"));
|
||||
}
|
||||
|
||||
// init 字典读 bubbles / cancelable / composed(缺省或非对象时取 false)。
|
||||
let mut bubbles = false;
|
||||
let mut cancelable = false;
|
||||
let mut composed = false;
|
||||
if args.len() > 2 {
|
||||
let init_val = vm.reg(args[2]);
|
||||
if init_val.is_object() {
|
||||
let init_ptr = init_val.as_js_object_ptr();
|
||||
// SAFETY: init_val 已确认是对象值,借用即时消费。
|
||||
let init_obj = unsafe { &*init_ptr };
|
||||
for (name, slot) in
|
||||
[("bubbles", &mut bubbles), ("cancelable", &mut cancelable), ("composed", &mut composed)]
|
||||
{
|
||||
let si = vm.perm_intern(name);
|
||||
match vm.ordinary_get(init_obj, si, init_val) {
|
||||
Ok(v) => *slot = oxide_runtime_api::to_boolean(v),
|
||||
Err(_) => {
|
||||
if let Some(exc) = vm.take_uncaught_value() {
|
||||
return NativeResult::Err(exc);
|
||||
}
|
||||
return NativeResult::Err(crate::error::create_type_error(
|
||||
vm,
|
||||
"Event init property getter failed",
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 建载荷盒入 receiver 的 native_fn 槽,置 Event 标签。
|
||||
let type_js = vm.new_string(&type_str);
|
||||
let inner = Box::into_raw(Box::new(EventInner {
|
||||
r#type: type_js,
|
||||
target: JsValue::null(),
|
||||
current_target: JsValue::null(),
|
||||
event_phase: 0,
|
||||
is_trusted: false,
|
||||
bubbles,
|
||||
cancelable,
|
||||
default_prevented: false,
|
||||
propagation_stopped: false,
|
||||
immediate_stopped: false,
|
||||
composed,
|
||||
}));
|
||||
// SAFETY: receiver 不可调用,native_fn 存不透明 `Box<EventInner>` 指针,
|
||||
// 与 ArrayBuffer / RegExp 的类型化存储模式一致。
|
||||
let obj = unsafe { &mut *this_val.as_js_object_ptr() };
|
||||
obj.type_tag = JsObject::OBJ_TYPE_EVENT;
|
||||
obj.set_native_fn(Some(unsafe { NativeFnPtr::from_raw(inner as *const ()) }));
|
||||
NativeResult::Ok(this_val)
|
||||
}
|
||||
|
||||
/// `Event.prototype.type`:返回事件类型串。
|
||||
pub fn event_type_getter<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
|
||||
let Some(inner) = event_inner_of(this_val) else {
|
||||
return NativeResult::Err(crate::error::create_type_error(
|
||||
vm,
|
||||
"Event.prototype.type getter called on non-Event object",
|
||||
));
|
||||
};
|
||||
NativeResult::Ok(inner.r#type)
|
||||
}
|
||||
|
||||
/// `Event.prototype.target`:返回事件目标对象(未派发时 null)。
|
||||
pub fn event_target_getter<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
|
||||
let Some(inner) = event_inner_of(this_val) else {
|
||||
return NativeResult::Err(crate::error::create_type_error(
|
||||
vm,
|
||||
"Event.prototype.target getter called on non-Event object",
|
||||
));
|
||||
};
|
||||
NativeResult::Ok(inner.target)
|
||||
}
|
||||
|
||||
/// `Event.prototype.currentTarget`:返回当前派发目标(未派发时 null)。
|
||||
pub fn event_current_target_getter<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
|
||||
let Some(inner) = event_inner_of(this_val) else {
|
||||
return NativeResult::Err(crate::error::create_type_error(
|
||||
vm,
|
||||
"Event.prototype.currentTarget getter called on non-Event object",
|
||||
));
|
||||
};
|
||||
NativeResult::Ok(inner.current_target)
|
||||
}
|
||||
|
||||
/// `Event.prototype.eventPhase`:返回派发阶段(0 未派发 / 1 捕获 / 2 目标 / 3 冒泡)。
|
||||
pub fn event_phase_getter<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
|
||||
let Some(inner) = event_inner_of(this_val) else {
|
||||
return NativeResult::Err(crate::error::create_type_error(
|
||||
vm,
|
||||
"Event.prototype.eventPhase getter called on non-Event object",
|
||||
));
|
||||
};
|
||||
NativeResult::Ok(JsValue::int(inner.event_phase as i32))
|
||||
}
|
||||
|
||||
/// `Event.prototype.isTrusted`:返回是否由用户操作产生(引擎恒 false)。
|
||||
pub fn event_is_trusted_getter<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
|
||||
let Some(inner) = event_inner_of(this_val) else {
|
||||
return NativeResult::Err(crate::error::create_type_error(
|
||||
vm,
|
||||
"Event.prototype.isTrusted getter called on non-Event object",
|
||||
));
|
||||
};
|
||||
NativeResult::Ok(JsValue::bool(inner.is_trusted))
|
||||
}
|
||||
|
||||
/// `Event.prototype.bubbles`:返回是否冒泡。
|
||||
pub fn event_bubbles_getter<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
|
||||
let Some(inner) = event_inner_of(this_val) else {
|
||||
return NativeResult::Err(crate::error::create_type_error(
|
||||
vm,
|
||||
"Event.prototype.bubbles getter called on non-Event object",
|
||||
));
|
||||
};
|
||||
NativeResult::Ok(JsValue::bool(inner.bubbles))
|
||||
}
|
||||
|
||||
/// `Event.prototype.cancelable`:返回是否可取消。
|
||||
pub fn event_cancelable_getter<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
|
||||
let Some(inner) = event_inner_of(this_val) else {
|
||||
return NativeResult::Err(crate::error::create_type_error(
|
||||
vm,
|
||||
"Event.prototype.cancelable getter called on non-Event object",
|
||||
));
|
||||
};
|
||||
NativeResult::Ok(JsValue::bool(inner.cancelable))
|
||||
}
|
||||
|
||||
/// `Event.prototype.defaultPrevented`:返回默认行为是否已被阻止。
|
||||
pub fn event_default_prevented_getter<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
|
||||
let Some(inner) = event_inner_of(this_val) else {
|
||||
return NativeResult::Err(crate::error::create_type_error(
|
||||
vm,
|
||||
"Event.prototype.defaultPrevented getter called on non-Event object",
|
||||
));
|
||||
};
|
||||
NativeResult::Ok(JsValue::bool(inner.default_prevented))
|
||||
}
|
||||
|
||||
/// `Event.prototype.composed`:返回是否跨 Shadow DOM 边界。
|
||||
pub fn event_composed_getter<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
|
||||
let Some(inner) = event_inner_of(this_val) else {
|
||||
return NativeResult::Err(crate::error::create_type_error(
|
||||
vm,
|
||||
"Event.prototype.composed getter called on non-Event object",
|
||||
));
|
||||
};
|
||||
NativeResult::Ok(JsValue::bool(inner.composed))
|
||||
}
|
||||
|
||||
/// `Event.prototype.preventDefault`:cancelable 时置 defaultPrevented。
|
||||
pub fn event_prevent_default<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
|
||||
let Some(inner) = event_inner_of_mut(this_val) else {
|
||||
return NativeResult::Err(crate::error::create_type_error(
|
||||
vm,
|
||||
"Event.prototype.preventDefault called on non-Event object",
|
||||
));
|
||||
};
|
||||
if inner.cancelable {
|
||||
inner.default_prevented = true;
|
||||
}
|
||||
NativeResult::Ok(JsValue::undefined())
|
||||
}
|
||||
|
||||
/// `Event.prototype.stopPropagation`:置传播停止标志。
|
||||
pub fn event_stop_propagation<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
|
||||
let Some(inner) = event_inner_of_mut(this_val) else {
|
||||
return NativeResult::Err(crate::error::create_type_error(
|
||||
vm,
|
||||
"Event.prototype.stopPropagation called on non-Event object",
|
||||
));
|
||||
};
|
||||
inner.propagation_stopped = true;
|
||||
NativeResult::Ok(JsValue::undefined())
|
||||
}
|
||||
|
||||
/// `Event.prototype.stopImmediatePropagation`:置传播停止与立即停止双标志。
|
||||
pub fn event_stop_immediate_propagation<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
|
||||
let Some(inner) = event_inner_of_mut(this_val) else {
|
||||
return NativeResult::Err(crate::error::create_type_error(
|
||||
vm,
|
||||
"Event.prototype.stopImmediatePropagation called on non-Event object",
|
||||
));
|
||||
};
|
||||
inner.propagation_stopped = true;
|
||||
inner.immediate_stopped = true;
|
||||
NativeResult::Ok(JsValue::undefined())
|
||||
}
|
||||
|
||||
/// `Event.prototype.composedPath`:返回事件传播路径(首版仅含 this 自身)。
|
||||
pub fn event_composed_path<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
|
||||
let Some(_) = event_inner_of(this_val) else {
|
||||
return NativeResult::Err(crate::error::create_type_error(
|
||||
vm,
|
||||
"Event.prototype.composedPath called on non-Event object",
|
||||
));
|
||||
};
|
||||
// 首版:路径仅含 this 自身(完整传播路径由事件派发任务补全)。
|
||||
let array_proto = JsValue::from_js_object(vm.builtin_proto(ProtoKind::ArrayProto));
|
||||
let arr = vm.alloc_object(JsObject::new_array(EMPTY_SHAPE_ID, array_proto, 1));
|
||||
// SAFETY: arr 是本函数刚分配的对象,存活且本段无别名。
|
||||
unsafe {
|
||||
(*arr).set_prop_at(0, this_val);
|
||||
}
|
||||
NativeResult::Ok(JsValue::from_js_object(arr))
|
||||
}
|
||||
@@ -34,6 +34,8 @@ pub mod disposable_stack;
|
||||
pub mod error;
|
||||
/// eval 全局函数实现(动态编译执行脚本/表达式)。
|
||||
pub mod eval;
|
||||
/// Event 基类实现(构造器、原型 getter 与传播方法,载荷盒与 GC 三自由函数族)。
|
||||
pub mod event;
|
||||
/// Function 内置对象实现(call/apply/bind/toString)。
|
||||
pub mod function;
|
||||
/// 全局函数模块(URI 编解码与 Annex B 的 escape/unescape)。
|
||||
|
||||
@@ -232,6 +232,14 @@ impl JsObject {
|
||||
/// 载荷盒(`BroadcastChannelInner`),无对象边(mpsc 非 GC 边、通道名为
|
||||
/// Rust `String`)。
|
||||
pub const OBJ_TYPE_BROADCAST_CHANNEL: u8 = 34;
|
||||
/// Event 对象:事件基类载荷盒(type 串与九项状态位)存于 `native_fn` 槽。
|
||||
pub const OBJ_TYPE_EVENT: u8 = 35;
|
||||
/// MessageEvent 对象:事件派生类载荷盒(data 与 ports 边)存于 `native_fn` 槽。
|
||||
pub const OBJ_TYPE_MESSAGE_EVENT: u8 = 36;
|
||||
/// ErrorEvent 对象:事件派生类载荷盒(message 与 error 边)存于 `native_fn` 槽。
|
||||
pub const OBJ_TYPE_ERROR_EVENT: u8 = 37;
|
||||
/// CustomEvent 对象:事件派生类载荷盒(detail 边)存于 `native_fn` 槽。
|
||||
pub const OBJ_TYPE_CUSTOM_EVENT: u8 = 38;
|
||||
/// `is_session_epoch` 字段中的 session 标记位。
|
||||
pub const SESSION_EPOCH_BIT: u8 = 0x01;
|
||||
/// `is_session_epoch` 字段中的 GC 标记位。
|
||||
@@ -319,6 +327,11 @@ impl JsObject {
|
||||
pub fn is_broadcast_channel(&self) -> bool {
|
||||
self.type_tag == Self::OBJ_TYPE_BROADCAST_CHANNEL
|
||||
}
|
||||
/// 是否 Event 对象(`native_fn` 槽存事件基类载荷盒)。
|
||||
#[inline]
|
||||
pub fn is_event_obj(&self) -> bool {
|
||||
self.type_tag == Self::OBJ_TYPE_EVENT
|
||||
}
|
||||
/// 是否 DataView 对象。
|
||||
#[inline]
|
||||
pub fn is_data_view_obj(&self) -> bool {
|
||||
|
||||
@@ -1,28 +1,165 @@
|
||||
//! Event 体系绑定:本文件是内核接线占位(零行为变化)。九枚 P 字段
|
||||
//! (Event / MessageEvent / ErrorEvent / CustomEvent 四枚原型与构造器对加
|
||||
//! EventTarget 原型)当前是空对象,本函数为它们的绑定入口预留,真实构造器 /
|
||||
//! 原型方法 / 原型链连线由后续任务就地填充(不新建对象——P 字段本身就是槽位,
|
||||
//! 快照 / 脏检查 / 收尾枚举已覆盖)。
|
||||
//! Event 基类绑定:就地填充 `event_constructor` / `event_proto` 两枚 P 字段
|
||||
//! 占位(构造器本体、原型方法、原型 getter 与 Event 常量),并绑全局 `Event`。
|
||||
//!
|
||||
//! 九枚 P 字段中其余七枚(MessageEvent / ErrorEvent / CustomEvent 四对加
|
||||
//! EventTarget 原型)由后续子任务就地填充,本函数不读不写。
|
||||
|
||||
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;
|
||||
use oxide_types::object::{JsObject, PropAttributes};
|
||||
use oxide_types::value::JsValue;
|
||||
|
||||
/// Event 体系绑定入口(当前为空占位)。
|
||||
/// 把 Event 构造器与原型方法绑定到 global。
|
||||
///
|
||||
/// `event_constructor` / `event_proto` 两枚 P 字段是空对象占位,本函数就地
|
||||
/// 填充(不新建对象——P 字段本身就是槽位,快照/脏检查/收尾枚举已覆盖)。
|
||||
///
|
||||
/// # 幂等
|
||||
/// 本函数从三条路径到达:`init_kernel_builtins`(占位是空对象)、
|
||||
/// `rebind_dirty_builtins` 的 `event` 分支(占位是重建后的空对象)、
|
||||
/// global-dirty 路径(占位可能已填满)。本函数当前不写任何槽位,空操作天然
|
||||
/// 幂等;后续任务就地填充时,各槽写须沿用 `lookup_position` 前置守卫
|
||||
/// (有槽即跳过),保持与 `bind_broadcast_channel` 同型的幂等契约。
|
||||
/// `rebind_dirty_builtins` 的 `event` 分支(占位是重建后的空对象)、global-dirty
|
||||
/// 路径(占位可能已填满)。全部槽写经 `lookup_position` 前置守卫,有槽即跳过;
|
||||
/// `bind_constructor!` 的全局槽臂自带既有槽原位更新,天然幂等。
|
||||
///
|
||||
/// # 边界
|
||||
/// 九枚 P 字段是空对象占位,本函数不读不写,行为与未调用一致;
|
||||
/// EventTarget 原型不占 ProtoKind(builtins 不读它),绑定层后续直接访问
|
||||
/// `world.event_target_proto` 槽。
|
||||
///
|
||||
/// `core` / `session` / `global` / `realm_id` 当前未使用,保留签名与其他
|
||||
/// 绑定函数一致,供后续任务就地填充时直接取用。
|
||||
pub fn bind_event(_core: &Arc<KernelCore>, _session: &KernelSession, _global: &mut JsObject, _realm_id: u32) {}
|
||||
/// `realm_id` 未使用(Event 无 well-known 符号键),保留签名与其他绑定函数一致。
|
||||
pub fn bind_event(core: &Arc<KernelCore>, session: &KernelSession, global: &mut JsObject, _realm_id: u32) {
|
||||
let world = session.builtin_world();
|
||||
let ctor_ptr = world.event_constructor.as_ptr() as *mut JsObject;
|
||||
let ctor = unsafe { &mut *ctor_ptr };
|
||||
let proto_ptr = world.event_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 槽 → "Event"(描述符 {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("Event").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::event::event_constructor::<crate::vm::Vm> as *const (), 2);
|
||||
bind_constructor!(
|
||||
core,
|
||||
global,
|
||||
"Event",
|
||||
ctor_ptr,
|
||||
oxide_builtins::event::event_constructor::<crate::vm::Vm>,
|
||||
2,
|
||||
hash: true
|
||||
);
|
||||
|
||||
// Event 常量:CAPTURING_PHASE / AT_TARGET / BUBBLING_PHASE(绑构造器,
|
||||
// 描述符 {t,f,t})。
|
||||
let constants: [(&str, i32); 3] = [("CAPTURING_PHASE", 1), ("AT_TARGET", 2), ("BUBBLING_PHASE", 3)];
|
||||
for (name, value) in constants {
|
||||
let si = sf.intern(name).0;
|
||||
if sh.lookup_position(ctor.shape_id(), si).is_none() {
|
||||
let shape = sh.make_shape(ctor.shape_id(), si);
|
||||
ctor.set_shape_id(shape);
|
||||
let pos = ctor.push_prop(JsValue::int(value));
|
||||
ctor.set_data_meta(pos, PropAttributes::new(true, false, true));
|
||||
ctor.bump_generation();
|
||||
}
|
||||
}
|
||||
|
||||
// ---- 填原型占位 ----
|
||||
// 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);
|
||||
|
||||
// 原型方法:preventDefault / stopPropagation / stopImmediatePropagation /
|
||||
// composedPath(每方法先 lookup_position 守卫)。
|
||||
let si_prevent_default = sf.intern("preventDefault").0;
|
||||
if sh.lookup_position(proto.shape_id(), si_prevent_default).is_none() {
|
||||
apply_binding_table(
|
||||
world,
|
||||
proto,
|
||||
core,
|
||||
&[
|
||||
(
|
||||
"preventDefault",
|
||||
oxide_builtins::event::event_prevent_default::<crate::vm::Vm> as *const (),
|
||||
0,
|
||||
),
|
||||
(
|
||||
"stopPropagation",
|
||||
oxide_builtins::event::event_stop_propagation::<crate::vm::Vm> as *const (),
|
||||
0,
|
||||
),
|
||||
(
|
||||
"stopImmediatePropagation",
|
||||
oxide_builtins::event::event_stop_immediate_propagation::<crate::vm::Vm> as *const (),
|
||||
0,
|
||||
),
|
||||
(
|
||||
"composedPath",
|
||||
oxide_builtins::event::event_composed_path::<crate::vm::Vm> as *const (),
|
||||
0,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
// 原型 getter:type / target / currentTarget / eventPhase / isTrusted /
|
||||
// bubbles / cancelable / defaultPrevented / composed(每 getter 先
|
||||
// lookup_position 守卫)。
|
||||
let getter_fns: [(&str, *const ()); 9] = [
|
||||
("type", oxide_builtins::event::event_type_getter::<crate::vm::Vm> as *const ()),
|
||||
("target", oxide_builtins::event::event_target_getter::<crate::vm::Vm> as *const ()),
|
||||
(
|
||||
"currentTarget",
|
||||
oxide_builtins::event::event_current_target_getter::<crate::vm::Vm> as *const (),
|
||||
),
|
||||
("eventPhase", oxide_builtins::event::event_phase_getter::<crate::vm::Vm> as *const ()),
|
||||
("isTrusted", oxide_builtins::event::event_is_trusted_getter::<crate::vm::Vm> as *const ()),
|
||||
("bubbles", oxide_builtins::event::event_bubbles_getter::<crate::vm::Vm> as *const ()),
|
||||
("cancelable", oxide_builtins::event::event_cancelable_getter::<crate::vm::Vm> as *const ()),
|
||||
(
|
||||
"defaultPrevented",
|
||||
oxide_builtins::event::event_default_prevented_getter::<crate::vm::Vm> as *const (),
|
||||
),
|
||||
("composed", oxide_builtins::event::event_composed_getter::<crate::vm::Vm> as *const ()),
|
||||
];
|
||||
for (name, fn_ptr) in getter_fns {
|
||||
let si = sf.intern(name).0;
|
||||
if sh.lookup_position(proto.shape_id(), si).is_none() {
|
||||
bind_accessor_getter(core, session, proto, name, fn_ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//! native 载荷家族的单点分类与每家族边函数引用(家族表)。
|
||||
//!
|
||||
//! 分类是复合谓词:header 位(map/set/module_ns)优先于 `type_tag`,
|
||||
//! 两维互斥、一个对象至多归入一个家族。tag 维显式枚举全部 0..=34,
|
||||
//! 两维互斥、一个对象至多归入一个家族。tag 维显式枚举全部 0..=38,
|
||||
//! 未登记 tag panic。
|
||||
//!
|
||||
//! 关键约定:
|
||||
@@ -10,13 +10,13 @@
|
||||
//! - 注册面集中在 `ops_for` 的家族表,mark/size/drop/clone/rewrite 各链
|
||||
//! 由同一张表驱动,新增家族只在此登记。
|
||||
|
||||
use oxide_builtins::{data_view, disposable_stack, map, message_channel, module, set, typed_array, weak_map};
|
||||
use oxide_builtins::{data_view, disposable_stack, event, map, message_channel, module, set, typed_array, weak_map};
|
||||
use oxide_types::object::{Cell, JsObject, JsString};
|
||||
use oxide_types::value::JsValue;
|
||||
|
||||
/// native 载荷家族。
|
||||
///
|
||||
/// 15 个 native 家族 + 空家族;空家族是无 native 盒类型的显式归类结果。
|
||||
/// 21 个 native 家族 + 空家族;空家族是无 native 盒类型的显式归类结果。
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub(crate) enum NativeBoxFamily {
|
||||
/// 无 native 载荷盒。
|
||||
@@ -53,6 +53,14 @@ pub(crate) enum NativeBoxFamily {
|
||||
MessagePort,
|
||||
/// BroadcastChannel 通道对象(tag 34,mpsc 发送/接收对与通道名,无对象边)。
|
||||
BroadcastChannel,
|
||||
/// Event 事件基类对象(tag 35,type 串与九项状态位载荷盒)。
|
||||
Event,
|
||||
/// MessageEvent 事件派生类对象(tag 36,data 与 ports 边)。
|
||||
MessageEvent,
|
||||
/// ErrorEvent 事件派生类对象(tag 37,message 与 error 边)。
|
||||
ErrorEvent,
|
||||
/// CustomEvent 事件派生类对象(tag 38,detail 边)。
|
||||
CustomEvent,
|
||||
/// mapped arguments 对象(tag 20,同步状态盒存 `native_data`,无引用边)。
|
||||
Arguments,
|
||||
}
|
||||
@@ -87,7 +95,7 @@ pub(crate) fn classify(obj: &JsObject) -> NativeBoxFamily {
|
||||
/// 按类型 tag 分类 native 载荷家族。
|
||||
///
|
||||
/// # 边界与前提
|
||||
/// - 0..=34 全 tag 显式枚举;未登记 tag(35 及以上)panic。
|
||||
/// - 0..=38 全 tag 显式枚举;未登记 tag(39 及以上)panic。
|
||||
pub(crate) fn classify_by_tag(tag: u8) -> NativeBoxFamily {
|
||||
match tag {
|
||||
JsObject::OBJ_TYPE_ARRAY_BUFFER => NativeBoxFamily::ArrayBuffer,
|
||||
@@ -126,6 +134,10 @@ pub(crate) fn classify_by_tag(tag: u8) -> NativeBoxFamily {
|
||||
JsObject::OBJ_TYPE_RAW_JSON => NativeBoxFamily::None,
|
||||
JsObject::OBJ_TYPE_MESSAGE_PORT => NativeBoxFamily::MessagePort,
|
||||
JsObject::OBJ_TYPE_BROADCAST_CHANNEL => NativeBoxFamily::BroadcastChannel,
|
||||
JsObject::OBJ_TYPE_EVENT => NativeBoxFamily::Event,
|
||||
JsObject::OBJ_TYPE_MESSAGE_EVENT => NativeBoxFamily::MessageEvent,
|
||||
JsObject::OBJ_TYPE_ERROR_EVENT => NativeBoxFamily::ErrorEvent,
|
||||
JsObject::OBJ_TYPE_CUSTOM_EVENT => NativeBoxFamily::CustomEvent,
|
||||
_ => panic!("unregistered type tag: {tag}"),
|
||||
}
|
||||
}
|
||||
@@ -223,6 +235,19 @@ pub(crate) fn ops_for(family: NativeBoxFamily) -> NativeBoxOps {
|
||||
string_edges: None,
|
||||
cell_edges: None,
|
||||
},
|
||||
// Event 基类载荷盒:type 串边与 target / current_target 对象边。
|
||||
NativeBoxFamily::Event => NativeBoxOps {
|
||||
object_edges: Some(event::event_native_edges),
|
||||
string_edges: None,
|
||||
cell_edges: None,
|
||||
},
|
||||
// 事件派生类(MessageEvent / ErrorEvent / CustomEvent)载荷盒由后续子
|
||||
// 任务填充;本臂当前无引用边,仅 size/drop 链消费。
|
||||
NativeBoxFamily::MessageEvent | NativeBoxFamily::ErrorEvent | NativeBoxFamily::CustomEvent => NativeBoxOps {
|
||||
object_edges: None,
|
||||
string_edges: None,
|
||||
cell_edges: None,
|
||||
},
|
||||
// mapped arguments 同步状态盒:无引用边(位图与帧身份均为原始值),
|
||||
// 三边函数全空,仅 size/drop 链消费。
|
||||
NativeBoxFamily::Arguments => NativeBoxOps {
|
||||
@@ -261,6 +286,10 @@ mod tests {
|
||||
JsObject::OBJ_TYPE_REGEXP | JsObject::OBJ_TYPE_REGEX_STUB => NativeBoxFamily::RegExp,
|
||||
JsObject::OBJ_TYPE_MESSAGE_PORT => NativeBoxFamily::MessagePort,
|
||||
JsObject::OBJ_TYPE_BROADCAST_CHANNEL => NativeBoxFamily::BroadcastChannel,
|
||||
JsObject::OBJ_TYPE_EVENT => NativeBoxFamily::Event,
|
||||
JsObject::OBJ_TYPE_MESSAGE_EVENT => NativeBoxFamily::MessageEvent,
|
||||
JsObject::OBJ_TYPE_ERROR_EVENT => NativeBoxFamily::ErrorEvent,
|
||||
JsObject::OBJ_TYPE_CUSTOM_EVENT => NativeBoxFamily::CustomEvent,
|
||||
JsObject::OBJ_TYPE_ARGUMENTS => NativeBoxFamily::Arguments,
|
||||
_ => NativeBoxFamily::None,
|
||||
}
|
||||
@@ -268,7 +297,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn tag_dimension_every_tag_hits_exactly_one_family() {
|
||||
for tag in 0..=34u8 {
|
||||
for tag in 0..=38u8 {
|
||||
let obj = obj_with_tag(tag);
|
||||
let family = classify(&obj);
|
||||
assert_eq!(family, expected_family_for_tag(tag), "tag {tag} 家族不一致");
|
||||
@@ -302,7 +331,7 @@ mod tests {
|
||||
#[test]
|
||||
#[should_panic(expected = "unregistered type tag")]
|
||||
fn unregistered_tag_panics() {
|
||||
let obj = obj_with_tag(35);
|
||||
let obj = obj_with_tag(39);
|
||||
classify(&obj);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ use crate::native_box_dispatch;
|
||||
use crate::vm::RootGroup;
|
||||
use crate::vm::Vm;
|
||||
use oxide_builtins::{
|
||||
array_buffer, broadcast_channel, data_view, disposable_stack, map, message_channel, module, regexp, set,
|
||||
array_buffer, broadcast_channel, data_view, disposable_stack, event, map, message_channel, module, regexp, set,
|
||||
typed_array, weak_map,
|
||||
};
|
||||
|
||||
@@ -132,6 +132,7 @@ impl SessionGc {
|
||||
bytes += weak_map::weak_map_native_size(obj);
|
||||
bytes += message_channel::message_port_native_size(obj);
|
||||
bytes += broadcast_channel::broadcast_channel_native_size(obj);
|
||||
bytes += event::event_native_size(obj);
|
||||
bytes += crate::arguments_gc::arguments_native_size(obj);
|
||||
|
||||
bytes
|
||||
@@ -375,6 +376,14 @@ impl SessionGc {
|
||||
Self::mark_string_live(live, obj.get_regexp_flags().as_string_ptr_mut());
|
||||
}
|
||||
}
|
||||
// Event 载荷盒 type 字段持有字符串边。
|
||||
if obj.is_event_obj() {
|
||||
for value in event::event_native_edges(obj) {
|
||||
if value.is_string() {
|
||||
Self::mark_string_live(live, value.as_string_ptr_mut());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 从 VM roots 标记存活 session 对象、字符串与 BigInt,供 `sweep` 判定。
|
||||
@@ -574,6 +583,7 @@ impl SessionGc {
|
||||
freed_bytes += weak_map::drop_weak_map_native(obj);
|
||||
freed_bytes += message_channel::drop_message_port_native(obj);
|
||||
freed_bytes += broadcast_channel::drop_broadcast_channel_native(obj);
|
||||
freed_bytes += event::drop_event_native(obj);
|
||||
freed_bytes += crate::arguments_gc::drop_arguments_native(obj);
|
||||
|
||||
freed_bytes
|
||||
|
||||
Reference in New Issue
Block a user