mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-23 18:21:13 +08:00
feat: MessageEvent 载荷盒加 GC 加构造器加原型加交付整合
This commit is contained in:
@@ -1,9 +1,12 @@
|
||||
//! Event 基类行为面:`Event` 构造器(`new Event(type, init)`)、原型 getter
|
||||
//! (type / target / currentTarget / eventPhase / isTrusted / bubbles /
|
||||
//! cancelable / defaultPrevented / composed)与原型方法(preventDefault /
|
||||
//! stopPropagation / stopImmediatePropagation / composedPath)。
|
||||
//! Event 基类与 MessageEvent 派生类行为面:`Event` 构造器(`new Event(type,
|
||||
//! init)`)、原型 getter(type / target / currentTarget / eventPhase /
|
||||
//! isTrusted / bubbles / cancelable / defaultPrevented / composed)与原型方法
|
||||
//! (preventDefault / stopPropagation / stopImmediatePropagation /
|
||||
//! composedPath);`MessageEvent` 构造器(`new MessageEvent(type, init)`)与
|
||||
//! 原型 getter(data / origin / lastEpoch / source / ports)。
|
||||
//!
|
||||
//! 事件载荷盒(type 串与九项状态位)存于对象 `native_fn` 槽,向 GC 家族表
|
||||
//! 事件载荷盒(type 串与九项状态位,MessageEvent 加 data / origin /
|
||||
//! lastEpoch / source / ports 五字段)存于对象 `native_fn` 槽,向 GC 家族表
|
||||
//! 暴露 edges/size/drop 三自由函数。
|
||||
|
||||
use std::mem;
|
||||
@@ -17,6 +20,10 @@ use oxide_runtime_api::{NativeResult, ProtoKind, VmHost};
|
||||
/// Event 载荷盒:存于对象 `native_fn` 槽(`Box::into_raw`,realm 局部单线程)。
|
||||
/// `r#type` 是事件类型串(GC 字符串边),`target` / `current_target` 是目标
|
||||
/// 对象(GC 对象边,初始 null),其余为简单状态位。
|
||||
///
|
||||
/// `#[repr(C)]` 固定字段按声明序、首字段偏移 0:派生类盒以本结构为首字段嵌入,
|
||||
/// 派发路径把盒指针转基类指针读首字段,依赖该偏移稳定。
|
||||
#[repr(C)]
|
||||
struct EventInner {
|
||||
r#type: JsValue,
|
||||
target: JsValue,
|
||||
@@ -31,6 +38,33 @@ struct EventInner {
|
||||
composed: bool,
|
||||
}
|
||||
|
||||
/// MessageEvent 载荷盒:事件基类字段(`EventInner` 嵌入,位于偏移 0)加消息
|
||||
/// 五字段(data / origin / lastEpoch / source / ports)。存于对象 `native_fn`
|
||||
/// 槽(`Box::into_raw`,realm 局部单线程)。
|
||||
///
|
||||
/// `#[repr(C)]` 固定 `base` 位于偏移 0:派生类盒指针转基类指针读首字段依赖该
|
||||
/// 偏移稳定(与 `EventInner` 同型约束)。
|
||||
#[repr(C)]
|
||||
struct MessageEventInner {
|
||||
base: EventInner,
|
||||
data: JsValue,
|
||||
origin: JsValue,
|
||||
last_epoch: u32,
|
||||
source: JsValue,
|
||||
ports: Vec<JsValue>,
|
||||
}
|
||||
|
||||
/// 是否事件系对象(Event / MessageEvent / ErrorEvent / CustomEvent 四标签)。
|
||||
pub fn is_event_family_obj(obj: &JsObject) -> bool {
|
||||
matches!(
|
||||
obj.type_tag,
|
||||
JsObject::OBJ_TYPE_EVENT
|
||||
| JsObject::OBJ_TYPE_MESSAGE_EVENT
|
||||
| JsObject::OBJ_TYPE_ERROR_EVENT
|
||||
| JsObject::OBJ_TYPE_CUSTOM_EVENT
|
||||
)
|
||||
}
|
||||
|
||||
/// 取载荷盒指针:仅 Event 标签对象返回 `Some`,其余标签返回 `None`。
|
||||
fn event_payload_ptr(obj: &JsObject) -> Option<*mut EventInner> {
|
||||
if !obj.is_event_obj() {
|
||||
@@ -39,6 +73,17 @@ fn event_payload_ptr(obj: &JsObject) -> Option<*mut EventInner> {
|
||||
obj.native_fn().map(|ptr| ptr.as_ptr() as *mut EventInner)
|
||||
}
|
||||
|
||||
/// 取事件系基类字段指针:仅事件系标签对象返回 `Some`,其余标签返回 `None`。
|
||||
///
|
||||
/// 派生类对象的 `native_fn` 槽存 `Box<派生类Inner>`,其首字段是 `EventInner`
|
||||
/// (基类字段位于偏移 0),指针可安全转基类字段指针。
|
||||
fn event_family_base_ptr(obj: &JsObject) -> Option<*mut EventInner> {
|
||||
if !is_event_family_obj(obj) {
|
||||
return None;
|
||||
}
|
||||
obj.native_fn().map(|ptr| ptr.as_ptr() as *mut EventInner)
|
||||
}
|
||||
|
||||
/// 收集 Event 的引用边(type 串边与 target / current_target 对象边)。
|
||||
///
|
||||
/// `target` / `current_target` 空窗口(构造期回填之前)为 null,边函数自守,
|
||||
@@ -86,11 +131,11 @@ pub fn drop_event_native(obj: &mut JsObject) -> u64 {
|
||||
bytes
|
||||
}
|
||||
|
||||
/// 读事件类型串(GC 字符串边)。非 Event 对象或无载荷盒返回 None。
|
||||
/// 读事件类型串(GC 字符串边)。非事件系对象或无载荷盒返回 None。
|
||||
///
|
||||
/// 供派发路径(`dispatchEvent`)取事件类型串、intern 后查监听器。
|
||||
pub fn event_type_value(obj: &JsObject) -> Option<JsValue> {
|
||||
let ptr = event_payload_ptr(obj)?;
|
||||
let ptr = event_family_base_ptr(obj)?;
|
||||
if ptr.is_null() {
|
||||
return None;
|
||||
}
|
||||
@@ -99,11 +144,11 @@ pub fn event_type_value(obj: &JsObject) -> Option<JsValue> {
|
||||
}
|
||||
|
||||
/// 设派发目标与阶段:`target` / `current_target` 置 `target`、`event_phase` 置
|
||||
/// `phase`。非 Event 对象或无载荷盒时 no-op。
|
||||
/// `phase`。非事件系对象或无载荷盒时 no-op。
|
||||
///
|
||||
/// 供派发路径(`dispatchEvent`)在调用监听器前设目标与 AT_TARGET 阶段。
|
||||
pub fn event_set_dispatch(obj: &mut JsObject, target: JsValue, phase: u32) {
|
||||
let Some(ptr) = event_payload_ptr(obj) else {
|
||||
let Some(ptr) = event_family_base_ptr(obj) else {
|
||||
return;
|
||||
};
|
||||
if ptr.is_null() {
|
||||
@@ -116,9 +161,9 @@ pub fn event_set_dispatch(obj: &mut JsObject, target: JsValue, phase: u32) {
|
||||
inner.event_phase = phase;
|
||||
}
|
||||
|
||||
/// 读 `defaultPrevented` 标志。非 Event 对象或无载荷盒返回 None。
|
||||
/// 读 `defaultPrevented` 标志。非事件系对象或无载荷盒返回 None。
|
||||
pub fn event_default_prevented(obj: &JsObject) -> Option<bool> {
|
||||
let ptr = event_payload_ptr(obj)?;
|
||||
let ptr = event_family_base_ptr(obj)?;
|
||||
if ptr.is_null() {
|
||||
return None;
|
||||
}
|
||||
@@ -126,9 +171,9 @@ pub fn event_default_prevented(obj: &JsObject) -> Option<bool> {
|
||||
Some(unsafe { &*ptr }.default_prevented)
|
||||
}
|
||||
|
||||
/// 读 `stopImmediatePropagation` 标志。非 Event 对象或无载荷盒返回 None。
|
||||
/// 读 `stopImmediatePropagation` 标志。非事件系对象或无载荷盒返回 None。
|
||||
pub fn event_immediate_stopped(obj: &JsObject) -> Option<bool> {
|
||||
let ptr = event_payload_ptr(obj)?;
|
||||
let ptr = event_family_base_ptr(obj)?;
|
||||
if ptr.is_null() {
|
||||
return None;
|
||||
}
|
||||
@@ -136,7 +181,7 @@ pub fn event_immediate_stopped(obj: &JsObject) -> Option<bool> {
|
||||
Some(unsafe { &*ptr }.immediate_stopped)
|
||||
}
|
||||
|
||||
/// 解析 this 为 Event 载荷盒共享引用:非 Event 对象或无载荷盒返回 None。
|
||||
/// 解析 this 为事件系基类字段共享引用:非事件系对象或无载荷盒返回 None。
|
||||
///
|
||||
/// # 注意事项
|
||||
/// 返回引用按 `'a` 声称为存活,实际存活至载荷盒被 GC 释放;调用方须在无 GC
|
||||
@@ -151,10 +196,7 @@ fn event_inner_of<'a>(this_val: JsValue) -> Option<&'a EventInner> {
|
||||
}
|
||||
// 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)?;
|
||||
let box_ptr = event_family_base_ptr(obj)?;
|
||||
if box_ptr.is_null() {
|
||||
return None;
|
||||
}
|
||||
@@ -163,7 +205,7 @@ fn event_inner_of<'a>(this_val: JsValue) -> Option<&'a EventInner> {
|
||||
Some(unsafe { &*box_ptr })
|
||||
}
|
||||
|
||||
/// 解析 this 为 Event 载荷盒可变引用:非 Event 对象或无载荷盒返回 None。
|
||||
/// 解析 this 为事件系基类字段可变引用:非事件系对象或无载荷盒返回 None。
|
||||
///
|
||||
/// # 注意事项
|
||||
/// 返回引用按 `'a` 声称为存活,实际存活至载荷盒被 GC 释放;调用方须在无 GC
|
||||
@@ -178,10 +220,7 @@ fn event_inner_of_mut<'a>(this_val: JsValue) -> Option<&'a mut EventInner> {
|
||||
}
|
||||
// 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)?;
|
||||
let box_ptr = event_family_base_ptr(obj)?;
|
||||
if box_ptr.is_null() {
|
||||
return None;
|
||||
}
|
||||
@@ -487,3 +526,359 @@ pub fn event_composed_path<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
}
|
||||
NativeResult::Ok(JsValue::from_js_object(arr))
|
||||
}
|
||||
|
||||
// —— MessageEvent 派生类 ——
|
||||
|
||||
/// 取 MessageEvent 载荷盒指针:仅 MessageEvent 标签对象返回 `Some`,其余标签
|
||||
/// 返回 `None`。
|
||||
fn message_event_payload_ptr(obj: &JsObject) -> Option<*mut MessageEventInner> {
|
||||
if obj.type_tag != JsObject::OBJ_TYPE_MESSAGE_EVENT {
|
||||
return None;
|
||||
}
|
||||
obj.native_fn().map(|ptr| ptr.as_ptr() as *mut MessageEventInner)
|
||||
}
|
||||
|
||||
/// 收集 MessageEvent 的引用边(基类 type / target / current_target 边加
|
||||
/// data / source / ports 边)。
|
||||
///
|
||||
/// `target` / `current_target` 空窗口(构造期回填之前)为 null,边函数自守,
|
||||
/// 语义自含。
|
||||
pub fn message_event_native_edges(obj: &JsObject) -> Vec<JsValue> {
|
||||
let Some(ptr) = message_event_payload_ptr(obj) else {
|
||||
return Vec::new();
|
||||
};
|
||||
if ptr.is_null() {
|
||||
return Vec::new();
|
||||
}
|
||||
// SAFETY: ptr 指向有效载荷盒(槽位仅构造期写入、释放时置空),只读字段。
|
||||
let inner = unsafe { &*ptr };
|
||||
let mut edges = vec![inner.base.r#type, inner.base.target, inner.base.current_target];
|
||||
edges.push(inner.data);
|
||||
edges.push(inner.source);
|
||||
edges.extend(inner.ports.iter().copied());
|
||||
edges
|
||||
}
|
||||
|
||||
/// 只读核算 MessageEvent 载荷盒字节(不释放)。
|
||||
pub fn message_event_native_size(obj: &JsObject) -> u64 {
|
||||
let Some(ptr) = message_event_payload_ptr(obj) else {
|
||||
return 0;
|
||||
};
|
||||
if ptr.is_null() {
|
||||
return 0;
|
||||
}
|
||||
mem::size_of::<MessageEventInner>() as u64
|
||||
}
|
||||
|
||||
/// 释放 MessageEvent 载荷盒(`Box<MessageEventInner>`),返回释放字节数。
|
||||
///
|
||||
/// 盒 drop 时基类字段与 data / origin / source / ports 的 JsValue 边随盒释放
|
||||
/// (GC 已判定死对象);槽置空保证重复调用零释放(幂等)。
|
||||
pub fn drop_message_event_native(obj: &mut JsObject) -> u64 {
|
||||
let bytes = message_event_native_size(obj);
|
||||
if bytes == 0 {
|
||||
return 0;
|
||||
}
|
||||
let Some(ptr) = message_event_payload_ptr(obj) else {
|
||||
return 0;
|
||||
};
|
||||
// SAFETY: ptr 非空(message_event_native_size 已验证),Box::from_raw 恰好
|
||||
// 释放一次。
|
||||
unsafe {
|
||||
drop(Box::from_raw(ptr));
|
||||
}
|
||||
obj.set_native_fn(None);
|
||||
bytes
|
||||
}
|
||||
|
||||
/// 建一个 MessageEvent 载荷盒对象(`type` 串与 `data` 值),返回对象指针。
|
||||
///
|
||||
/// 供交付路径(消息事件)建真实 MessageEvent 盒,使 `dispatchEvent` 品牌守卫
|
||||
/// 通过。盒的 `origin` 为空串、`lastEpoch` 为 0、`source` 为 null、`ports`
|
||||
/// 为空数组;`[[Prototype]]` 指向 `MessageEvent.prototype`
|
||||
/// (`e instanceof MessageEvent` 与 `e instanceof Event` 均成立)。
|
||||
///
|
||||
/// # 副作用
|
||||
/// - 新建一个 MessageEvent 盒对象(经 `alloc_object` 入对象表)。
|
||||
pub fn create_message_event_box<H: VmHost>(vm: &mut H, data: JsValue, type_str: &str) -> *mut JsObject {
|
||||
let type_js = vm.new_string(type_str);
|
||||
let origin_js = vm.new_string("");
|
||||
let inner = Box::into_raw(Box::new(MessageEventInner {
|
||||
base: EventInner {
|
||||
r#type: type_js,
|
||||
target: JsValue::null(),
|
||||
current_target: JsValue::null(),
|
||||
event_phase: 0,
|
||||
is_trusted: false,
|
||||
bubbles: false,
|
||||
cancelable: false,
|
||||
default_prevented: false,
|
||||
propagation_stopped: false,
|
||||
immediate_stopped: false,
|
||||
composed: false,
|
||||
},
|
||||
data,
|
||||
origin: origin_js,
|
||||
last_epoch: 0,
|
||||
source: JsValue::null(),
|
||||
ports: Vec::new(),
|
||||
}));
|
||||
let me_proto = JsValue::from_js_object(vm.builtin_proto(ProtoKind::MessageEventProto));
|
||||
let obj = JsObject::new_empty(EMPTY_SHAPE_ID, me_proto);
|
||||
let ptr = vm.alloc_object(obj);
|
||||
// SAFETY: ptr 是本函数刚 alloc_object 的对象,存活且本段无别名;native_fn 存
|
||||
// 不透明 `Box<MessageEventInner>` 指针,与 ArrayBuffer / RegExp 的类型化
|
||||
// 存储模式一致。
|
||||
let me_obj = unsafe { &mut *ptr };
|
||||
me_obj.type_tag = JsObject::OBJ_TYPE_MESSAGE_EVENT;
|
||||
me_obj.set_native_fn(Some(unsafe { NativeFnPtr::from_raw(inner as *const ()) }));
|
||||
ptr
|
||||
}
|
||||
|
||||
/// MessageEvent 构造器:`new MessageEvent(type, init)`。
|
||||
///
|
||||
/// # 步骤
|
||||
/// 1. 非构造形态(`!constructing_native`)抛 TypeError(HTML 规范只有
|
||||
/// [[Construct]],无 [[Call]])
|
||||
/// 2. type 经完整 ToString 转串;空串抛 SyntaxError
|
||||
/// 3. init 字典读 data / origin / lastEpoch / source / ports(缺省:data 为
|
||||
/// undefined、origin 为空串、lastEpoch 为 0、source 为 null、ports 为空数组)
|
||||
/// 4. 建载荷盒入 receiver 的 `native_fn` 槽,置 type_tag
|
||||
/// 5. 返回 receiver
|
||||
///
|
||||
/// # 边界与前提
|
||||
/// - receiver(`args[0]`)是 VM 按构造器 prototype 新分配的对象,proto 已
|
||||
/// 指向 %MessageEvent.prototype%;
|
||||
/// - init 缺省(undefined)或非对象时对应字段取缺省。
|
||||
///
|
||||
/// # 副作用
|
||||
/// - receiver 的 `native_fn` 槽写入载荷盒、`type_tag` 置 MessageEvent 标签。
|
||||
pub fn message_event_constructor<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
if !vm.constructing_native() {
|
||||
return NativeResult::Err(crate::error::create_type_error(vm, "MessageEvent constructor requires new"));
|
||||
}
|
||||
|
||||
let this_val = vm.reg(args[0]);
|
||||
if !this_val.is_object() {
|
||||
return NativeResult::Err(crate::error::create_type_error(vm, "MessageEvent 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 字典读 data / origin / lastEpoch / source / ports(缺省或非对象
|
||||
// 时取缺省)。
|
||||
let mut data = JsValue::undefined();
|
||||
let mut origin = JsValue::undefined();
|
||||
let mut last_epoch = 0u32;
|
||||
let mut source = JsValue::null();
|
||||
let mut ports: Vec<JsValue> = Vec::new();
|
||||
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 };
|
||||
|
||||
// data / origin / source 直读属性(getter 副作用与异常原值传播)。
|
||||
for (name, slot) in [("data", &mut data), ("origin", &mut origin), ("source", &mut source)] {
|
||||
let si = vm.perm_intern(name);
|
||||
match vm.ordinary_get(init_obj, si, init_val) {
|
||||
Ok(v) => *slot = v,
|
||||
Err(_) => {
|
||||
if let Some(exc) = vm.take_uncaught_value() {
|
||||
return NativeResult::Err(exc);
|
||||
}
|
||||
return NativeResult::Err(crate::error::create_type_error(
|
||||
vm,
|
||||
"MessageEvent init property getter failed",
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// lastEpoch 读数值(非有限非负数归 0)。
|
||||
let si_epoch = vm.perm_intern("lastEpoch");
|
||||
match vm.ordinary_get(init_obj, si_epoch, init_val) {
|
||||
Ok(v) => {
|
||||
let n = oxide_runtime_api::to_number(v);
|
||||
last_epoch = if n.is_finite() && n >= 0.0 { n as u32 } else { 0 };
|
||||
}
|
||||
Err(_) => {
|
||||
if let Some(exc) = vm.take_uncaught_value() {
|
||||
return NativeResult::Err(exc);
|
||||
}
|
||||
return NativeResult::Err(crate::error::create_type_error(
|
||||
vm,
|
||||
"MessageEvent init property getter failed",
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
// ports 读数组属性并复制元素(非数组取空数组)。
|
||||
let si_ports = vm.perm_intern("ports");
|
||||
match vm.ordinary_get(init_obj, si_ports, init_val) {
|
||||
Ok(v) => {
|
||||
if v.is_object() {
|
||||
let ports_ptr = v.as_js_object_ptr();
|
||||
// SAFETY: v 已确认是对象值,借用即时消费。
|
||||
let ports_obj = unsafe { &*ports_ptr };
|
||||
if ports_obj.is_array() {
|
||||
if let Some(elements) = ports_obj.array_elements_vec() {
|
||||
ports = elements.to_vec();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(_) => {
|
||||
if let Some(exc) = vm.take_uncaught_value() {
|
||||
return NativeResult::Err(exc);
|
||||
}
|
||||
return NativeResult::Err(crate::error::create_type_error(
|
||||
vm,
|
||||
"MessageEvent init property getter failed",
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// origin 缺省为空串。
|
||||
if origin.is_undefined() {
|
||||
origin = vm.new_string("");
|
||||
}
|
||||
|
||||
// 建载荷盒入 receiver 的 native_fn 槽,置 MessageEvent 标签。
|
||||
let type_js = vm.new_string(&type_str);
|
||||
let inner = Box::into_raw(Box::new(MessageEventInner {
|
||||
base: EventInner {
|
||||
r#type: type_js,
|
||||
target: JsValue::null(),
|
||||
current_target: JsValue::null(),
|
||||
event_phase: 0,
|
||||
is_trusted: false,
|
||||
bubbles: false,
|
||||
cancelable: false,
|
||||
default_prevented: false,
|
||||
propagation_stopped: false,
|
||||
immediate_stopped: false,
|
||||
composed: false,
|
||||
},
|
||||
data,
|
||||
origin,
|
||||
last_epoch,
|
||||
source,
|
||||
ports,
|
||||
}));
|
||||
// SAFETY: receiver 不可调用,native_fn 存不透明 `Box<MessageEventInner>`
|
||||
// 指针,与 ArrayBuffer / RegExp 的类型化存储模式一致。
|
||||
let obj = unsafe { &mut *this_val.as_js_object_ptr() };
|
||||
obj.type_tag = JsObject::OBJ_TYPE_MESSAGE_EVENT;
|
||||
obj.set_native_fn(Some(unsafe { NativeFnPtr::from_raw(inner as *const ()) }));
|
||||
NativeResult::Ok(this_val)
|
||||
}
|
||||
|
||||
/// 解析 this 为 MessageEvent 载荷盒共享引用:非 MessageEvent 对象或无载荷盒
|
||||
/// 返回 None。
|
||||
///
|
||||
/// # 注意事项
|
||||
/// 返回引用按 `'a` 声称为存活,实际存活至载荷盒被 GC 释放;调用方须在无 GC
|
||||
/// 窗口的单 native 函数内消费,不得跨用户调用窗口持有。
|
||||
fn message_event_inner_of<'a>(this_val: JsValue) -> Option<&'a MessageEventInner> {
|
||||
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 };
|
||||
let box_ptr = message_event_payload_ptr(obj)?;
|
||||
if box_ptr.is_null() {
|
||||
return None;
|
||||
}
|
||||
// SAFETY: box_ptr 指向有效载荷盒(构造期写入、释放时置空);'a 存活由
|
||||
// 调用方「无 GC 窗口内消费」约定保证。
|
||||
Some(unsafe { &*box_ptr })
|
||||
}
|
||||
|
||||
/// `MessageEvent.prototype.data`:返回消息数据。
|
||||
pub fn message_event_data_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) = message_event_inner_of(this_val) else {
|
||||
return NativeResult::Err(crate::error::create_type_error(
|
||||
vm,
|
||||
"MessageEvent.prototype.data getter called on non-MessageEvent object",
|
||||
));
|
||||
};
|
||||
NativeResult::Ok(inner.data)
|
||||
}
|
||||
|
||||
/// `MessageEvent.prototype.origin`:返回消息来源源(缺省为空串)。
|
||||
pub fn message_event_origin_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) = message_event_inner_of(this_val) else {
|
||||
return NativeResult::Err(crate::error::create_type_error(
|
||||
vm,
|
||||
"MessageEvent.prototype.origin getter called on non-MessageEvent object",
|
||||
));
|
||||
};
|
||||
NativeResult::Ok(inner.origin)
|
||||
}
|
||||
|
||||
/// `MessageEvent.prototype.lastEpoch`:返回最后纪元(引擎恒 0)。
|
||||
pub fn message_event_last_epoch_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) = message_event_inner_of(this_val) else {
|
||||
return NativeResult::Err(crate::error::create_type_error(
|
||||
vm,
|
||||
"MessageEvent.prototype.lastEpoch getter called on non-MessageEvent object",
|
||||
));
|
||||
};
|
||||
NativeResult::Ok(JsValue::int(inner.last_epoch as i32))
|
||||
}
|
||||
|
||||
/// `MessageEvent.prototype.source`:返回消息来源对象(首版恒 null)。
|
||||
pub fn message_event_source_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) = message_event_inner_of(this_val) else {
|
||||
return NativeResult::Err(crate::error::create_type_error(
|
||||
vm,
|
||||
"MessageEvent.prototype.source getter called on non-MessageEvent object",
|
||||
));
|
||||
};
|
||||
NativeResult::Ok(inner.source)
|
||||
}
|
||||
|
||||
/// `MessageEvent.prototype.ports`:返回消息端口数组(首版恒空数组)。
|
||||
pub fn message_event_ports_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) = message_event_inner_of(this_val) else {
|
||||
return NativeResult::Err(crate::error::create_type_error(
|
||||
vm,
|
||||
"MessageEvent.prototype.ports getter called on non-MessageEvent object",
|
||||
));
|
||||
};
|
||||
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, inner.ports.len()));
|
||||
// SAFETY: arr 是本函数刚分配的对象,存活且本段无别名。
|
||||
unsafe {
|
||||
for (i, value) in inner.ports.iter().enumerate() {
|
||||
(*arr).set_prop_at(i, *value);
|
||||
}
|
||||
}
|
||||
NativeResult::Ok(JsValue::from_js_object(arr))
|
||||
}
|
||||
|
||||
@@ -174,7 +174,7 @@ pub fn event_target_dispatch_event<H: VmHost>(vm: &mut H, args: &[u8]) -> Native
|
||||
}
|
||||
let this_ptr = this_val.as_js_object_ptr();
|
||||
|
||||
// event 品牌守卫:须为 Event 系对象(首版仅 Event 标签,派生类由后续任务接入)。
|
||||
// event 品牌守卫:须为事件系对象(Event 基类或派生类标签)。
|
||||
let event_val = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() };
|
||||
if !event_val.is_object() {
|
||||
return NativeResult::Err(crate::error::create_type_error(vm, "dispatchEvent requires an Event"));
|
||||
@@ -185,7 +185,7 @@ pub fn event_target_dispatch_event<H: VmHost>(vm: &mut H, args: &[u8]) -> Native
|
||||
}
|
||||
// SAFETY: event_val 已确认是对象值,event_ptr 指向合法 JsObject。
|
||||
let event_obj = unsafe { &*event_ptr };
|
||||
if !event_obj.is_event_obj() {
|
||||
if !event::is_event_family_obj(event_obj) {
|
||||
return NativeResult::Err(crate::error::create_type_error(vm, "dispatchEvent requires an Event"));
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
//! Event 基类绑定:就地填充 `event_constructor` / `event_proto` 两枚 P 字段
|
||||
//! 占位(构造器本体、原型方法、原型 getter 与 Event 常量),并绑全局 `Event`。
|
||||
//! Event 体系绑定:就地填充 `event_constructor` / `event_proto` 两枚 P 字段
|
||||
//! 占位(构造器本体、原型方法、原型 getter 与 Event 常量),并绑全局 `Event`;
|
||||
//! 就地填充 `message_event_constructor` / `message_event_proto` 两枚 P 字段
|
||||
//! 占位(构造器本体与原型 getter),并绑全局 `MessageEvent`。
|
||||
//!
|
||||
//! 九枚 P 字段中其余七枚(MessageEvent / ErrorEvent / CustomEvent 四对加
|
||||
//! EventTarget 原型)由后续子任务就地填充,本函数不读不写。
|
||||
//! 九枚 P 字段中其余四枚(ErrorEvent / CustomEvent 两对)由后续子任务就地
|
||||
//! 填充,本函数不读不写。
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
@@ -12,10 +14,11 @@ use oxide_kernel::kernel::{KernelCore, KernelSession};
|
||||
use oxide_types::object::{JsObject, PropAttributes};
|
||||
use oxide_types::value::JsValue;
|
||||
|
||||
/// 把 Event 构造器与原型方法绑定到 global。
|
||||
/// 把 Event 与 MessageEvent 构造器及原型方法绑定到 global。
|
||||
///
|
||||
/// `event_constructor` / `event_proto` 两枚 P 字段是空对象占位,本函数就地
|
||||
/// 填充(不新建对象——P 字段本身就是槽位,快照/脏检查/收尾枚举已覆盖)。
|
||||
/// `event_constructor` / `event_proto` 与 `message_event_constructor` /
|
||||
/// `message_event_proto` 四枚 P 字段是空对象占位,本函数就地填充(不新建
|
||||
/// 对象——P 字段本身就是槽位,快照/脏检查/收尾枚举已覆盖)。
|
||||
///
|
||||
/// # 幂等
|
||||
/// 本函数从三条路径到达:`init_kernel_builtins`(占位是空对象)、
|
||||
@@ -163,6 +166,79 @@ pub fn bind_event(core: &Arc<KernelCore>, session: &KernelSession, global: &mut
|
||||
}
|
||||
}
|
||||
|
||||
// ---- 填 MessageEvent 构造器与原型占位 ----
|
||||
let me_ctor_ptr = world.message_event_constructor.as_ptr() as *mut JsObject;
|
||||
let me_ctor = unsafe { &mut *me_ctor_ptr };
|
||||
let me_proto_ptr = world.message_event_proto.as_ptr() as *mut JsObject;
|
||||
let me_proto = unsafe { &mut *me_proto_ptr };
|
||||
|
||||
// 构造器:function 标志、prototype 槽、name 槽、[[Prototype]] →
|
||||
// Function.prototype(幂等,裸写槽)。
|
||||
me_ctor.set_function(true);
|
||||
if sh.lookup_position(me_ctor.shape_id(), si_prototype).is_none() {
|
||||
let shape = sh.make_shape(me_ctor.shape_id(), si_prototype);
|
||||
me_ctor.set_shape_id(shape);
|
||||
let pos = me_ctor.push_prop(JsValue::from_js_object(me_proto_ptr));
|
||||
me_ctor.set_data_meta(pos, PropAttributes::new(false, false, false));
|
||||
me_ctor.bump_generation();
|
||||
}
|
||||
if sh.lookup_position(me_ctor.shape_id(), si_name).is_none() {
|
||||
let shape = sh.make_shape(me_ctor.shape_id(), si_name);
|
||||
me_ctor.set_shape_id(shape);
|
||||
me_ctor
|
||||
.ensure_hash_props()
|
||||
.push(JsValue::perm_string(sf.string_ptr(sf.intern("MessageEvent").0)));
|
||||
let pos = me_ctor.hash_props_vec().map_or(0, |v| v.len() as u32).saturating_sub(1);
|
||||
me_ctor.set_data_meta(pos, PropAttributes::new(false, false, true));
|
||||
me_ctor.bump_generation();
|
||||
}
|
||||
let _ = me_ctor.set_proto(fn_proto_val);
|
||||
|
||||
configure_native_constructor(
|
||||
me_ctor,
|
||||
oxide_builtins::event::message_event_constructor::<crate::vm::Vm> as *const (),
|
||||
2,
|
||||
);
|
||||
bind_constructor!(
|
||||
core,
|
||||
global,
|
||||
"MessageEvent",
|
||||
me_ctor_ptr,
|
||||
oxide_builtins::event::message_event_constructor::<crate::vm::Vm>,
|
||||
2,
|
||||
hash: true
|
||||
);
|
||||
|
||||
// 原型:constructor 槽、[[Prototype]] → Event.prototype、五个 getter
|
||||
// (data / origin / lastEpoch / source / ports,每 getter 先 lookup_position
|
||||
// 守卫)。
|
||||
if sh.lookup_position(me_proto.shape_id(), si_constructor).is_none() {
|
||||
let shape = sh.make_shape(me_proto.shape_id(), si_constructor);
|
||||
me_proto.set_shape_id(shape);
|
||||
let pos = me_proto.push_prop(JsValue::from_js_object(me_ctor_ptr));
|
||||
me_proto.set_data_meta(pos, PropAttributes::new(true, false, true));
|
||||
me_proto.bump_generation();
|
||||
}
|
||||
let event_proto_val = JsValue::from_js_object(world.event_proto.as_ptr() as *mut JsObject);
|
||||
let _ = me_proto.set_proto(event_proto_val);
|
||||
|
||||
let me_getter_fns: [(&str, *const ()); 5] = [
|
||||
("data", oxide_builtins::event::message_event_data_getter::<crate::vm::Vm> as *const ()),
|
||||
("origin", oxide_builtins::event::message_event_origin_getter::<crate::vm::Vm> as *const ()),
|
||||
(
|
||||
"lastEpoch",
|
||||
oxide_builtins::event::message_event_last_epoch_getter::<crate::vm::Vm> as *const (),
|
||||
),
|
||||
("source", oxide_builtins::event::message_event_source_getter::<crate::vm::Vm> as *const ()),
|
||||
("ports", oxide_builtins::event::message_event_ports_getter::<crate::vm::Vm> as *const ()),
|
||||
];
|
||||
for (name, fn_ptr) in me_getter_fns {
|
||||
let si = sf.intern(name).0;
|
||||
if sh.lookup_position(me_proto.shape_id(), si).is_none() {
|
||||
bind_accessor_getter(core, session, me_proto, name, fn_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
// ---- 填 EventTarget 原型占位(无构造器,仅暴露原型与三方法)----
|
||||
// 幂等:三方法经 lookup_position 守卫,[[Prototype]] 裸写槽幂等。
|
||||
let et_proto_ptr = world.event_target_proto.as_ptr() as *mut JsObject;
|
||||
|
||||
@@ -241,9 +241,16 @@ pub(crate) fn ops_for(family: NativeBoxFamily) -> NativeBoxOps {
|
||||
string_edges: None,
|
||||
cell_edges: None,
|
||||
},
|
||||
// 事件派生类(MessageEvent / ErrorEvent / CustomEvent)载荷盒由后续子
|
||||
// 任务填充;本臂当前无引用边,仅 size/drop 链消费。
|
||||
NativeBoxFamily::MessageEvent | NativeBoxFamily::ErrorEvent | NativeBoxFamily::CustomEvent => NativeBoxOps {
|
||||
// MessageEvent 派生类载荷盒:基类 type / target / current_target 边加
|
||||
// data / source / ports 边。
|
||||
NativeBoxFamily::MessageEvent => NativeBoxOps {
|
||||
object_edges: Some(event::message_event_native_edges),
|
||||
string_edges: None,
|
||||
cell_edges: None,
|
||||
},
|
||||
// ErrorEvent / CustomEvent 载荷盒由后续子任务填充;本两臂当前无引用
|
||||
// 边,仅 size/drop 链消费。
|
||||
NativeBoxFamily::ErrorEvent | NativeBoxFamily::CustomEvent => NativeBoxOps {
|
||||
object_edges: None,
|
||||
string_edges: None,
|
||||
cell_edges: None,
|
||||
|
||||
@@ -133,6 +133,7 @@ impl SessionGc {
|
||||
bytes += message_channel::message_port_native_size(obj);
|
||||
bytes += broadcast_channel::broadcast_channel_native_size(obj);
|
||||
bytes += event::event_native_size(obj);
|
||||
bytes += event::message_event_native_size(obj);
|
||||
bytes += crate::arguments_gc::arguments_native_size(obj);
|
||||
|
||||
bytes
|
||||
@@ -376,9 +377,16 @@ 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) {
|
||||
// 事件系载荷盒(Event / MessageEvent / ErrorEvent / CustomEvent)字符串
|
||||
// 边标记:按标签取对应边函数;ErrorEvent / CustomEvent 载荷盒由后续子
|
||||
// 任务填充,当前取空边。
|
||||
if event::is_event_family_obj(obj) {
|
||||
let edges = match obj.type_tag {
|
||||
JsObject::OBJ_TYPE_EVENT => event::event_native_edges(obj),
|
||||
JsObject::OBJ_TYPE_MESSAGE_EVENT => event::message_event_native_edges(obj),
|
||||
_ => Vec::new(),
|
||||
};
|
||||
for value in edges {
|
||||
if value.is_string() {
|
||||
Self::mark_string_live(live, value.as_string_ptr_mut());
|
||||
}
|
||||
@@ -584,6 +592,7 @@ impl SessionGc {
|
||||
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 += event::drop_message_event_native(obj);
|
||||
freed_bytes += crate::arguments_gc::drop_arguments_native(obj);
|
||||
|
||||
freed_bytes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//! Worker API 的 concrete `&mut Vm` native 函数:构造器、`postMessage`/`terminate`
|
||||
//! 原型方法、`self` 面(`self.postMessage`/`self.close`/`self.name`/`self.location`)
|
||||
//! 与 `MessageEvent` 构造辅助。
|
||||
//! 与 `MessageEvent` / 错误事件构造辅助。
|
||||
//!
|
||||
//! 关键约定:
|
||||
//! - 函数是 concrete `&mut Vm` 形态(`NativeFn`),不挂 `VmHost` trait(trait 是单
|
||||
@@ -287,30 +287,59 @@ pub(crate) fn self_location(vm: &mut Vm, _args: &[u8]) -> NativeResult {
|
||||
NativeResult::Ok(vm.new_string(""))
|
||||
}
|
||||
|
||||
/// 事件构造辅助:建真实 Event 盒(`type` 字段)加 `data` / `message` 普通属性。
|
||||
/// 消息事件构造辅助:建真实 MessageEvent 盒(`data` + `type`,`ports` 空数组)。
|
||||
///
|
||||
/// 消息事件与错误事件同型,共用本辅助:消息事件 `message` 为 undefined,
|
||||
/// 错误事件 `data` 为 undefined、`message` 为错误串。
|
||||
/// 消息路径(`deliver_worker_messages` / `deliver_self_message`)经本辅助建
|
||||
/// 真实 MessageEvent,`e instanceof MessageEvent` 与 `e instanceof Event` 均
|
||||
/// 成立,`e.data` 经原型 getter 读盒字段。
|
||||
///
|
||||
/// # 步骤
|
||||
/// 1. 经 `create_event_box` 建真实 Event 盒(`type` 取 `type_val` 的字符串形态,
|
||||
/// `[[Prototype]]` → `Event.prototype`),使 `dispatchEvent` 品牌守卫通过。
|
||||
/// 2. define `data` 属性(rehydrate 后的消息值,可枚举;GC 边)。
|
||||
/// 3. `message` 非 undefined 时 define `message` 属性(错误消息串,可枚举)。
|
||||
/// 4. 返回对象。
|
||||
/// 1. 读 `data`(`args[1]`)与 `type`(`args[2]`)。
|
||||
/// 2. 委托 `create_message_event_box` 建真实 MessageEvent 盒(`origin` 空串、
|
||||
/// `lastEpoch` 0、`source` null、`ports` 空数组,`[[Prototype]]` →
|
||||
/// `MessageEvent.prototype`),使 `dispatchEvent` 品牌守卫通过。
|
||||
/// 3. 返回对象。
|
||||
///
|
||||
/// # 边界与前提
|
||||
/// - `data` 是 rehydrate 后的消息值(GC 边,经属性区入 mark)。
|
||||
/// - `type` 是事件类型串(`"message"`/`"error"`/`"messageerror"`)。
|
||||
/// - `message` 是错误消息串(仅错误事件定义,消息事件为 undefined)。
|
||||
/// - Event 盒无 `data` 字段(8.4 的 MessageEvent 才补),`data` 作盒对象普通属性。
|
||||
/// - `data` 是 rehydrate 后的消息值(GC 边,经盒边入 mark)。
|
||||
/// - `type` 是事件类型串(`"message"`)。
|
||||
///
|
||||
/// # 副作用
|
||||
/// - 新建一个 Event 盒对象(经 `alloc_object` 入对象表)。
|
||||
/// - 新建一个 MessageEvent 盒对象(经 `alloc_object` 入对象表)。
|
||||
pub(crate) fn message_event_constructor(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
let data_val = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() };
|
||||
let type_val = if args.len() > 2 { vm.reg(args[2]) } else { JsValue::undefined() };
|
||||
let message_val = if args.len() > 3 { vm.reg(args[3]) } else { JsValue::undefined() };
|
||||
|
||||
// 建真实 MessageEvent 盒(type 取 type_val 的字符串形态)。
|
||||
let type_text = vm.lookup_str(type_val).unwrap_or_default();
|
||||
let ptr = oxide_builtins::event::create_message_event_box(vm, data_val, &type_text);
|
||||
NativeResult::Ok(JsValue::from_js_object(ptr))
|
||||
}
|
||||
|
||||
/// 错误事件构造辅助(临时形态):建真实 Event 盒(`type` 字段)加 `data` /
|
||||
/// `message` 普通属性。
|
||||
///
|
||||
/// 错误路径(`deliver_error_event`)经本辅助建错误事件:`data` 为 undefined、
|
||||
/// `message` 为错误串,供 onerror 处理器读取。
|
||||
///
|
||||
/// # 步骤
|
||||
/// 1. 读 `type`(`args[1]`)与 `message`(`args[2]`)。
|
||||
/// 2. 经 `create_event_box` 建真实 Event 盒(`type` 取 `type_val` 的字符串
|
||||
/// 形态,`[[Prototype]]` → `Event.prototype`),使 `dispatchEvent` 品牌守卫
|
||||
/// 通过。
|
||||
/// 3. define `data` 属性(undefined,可枚举)与 `message` 属性(错误消息串,
|
||||
/// 可枚举)。
|
||||
/// 4. 返回对象。
|
||||
///
|
||||
/// # 边界与前提
|
||||
/// - `type` 是事件类型串(`"error"`/`"messageerror"`)。
|
||||
/// - `message` 是错误消息串。
|
||||
///
|
||||
/// # 副作用
|
||||
/// - 新建一个 Event 盒对象(经 `alloc_object` 入对象表)。
|
||||
pub(crate) fn build_error_event(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
let type_val = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() };
|
||||
let message_val = if args.len() > 2 { vm.reg(args[2]) } else { JsValue::undefined() };
|
||||
|
||||
// 建真实 Event 盒(type 取 type_val 的字符串形态)。
|
||||
let type_text = vm.lookup_str(type_val).unwrap_or_default();
|
||||
@@ -319,11 +348,9 @@ pub(crate) fn message_event_constructor(vm: &mut Vm, args: &[u8]) -> NativeResul
|
||||
let event_obj = unsafe { &mut *ptr };
|
||||
|
||||
let si_data = vm.perm_intern("data");
|
||||
let _ = vm.define_data_property(event_obj, si_data, data_val, PropAttributes::DEFAULT_DATA);
|
||||
if !message_val.is_undefined() {
|
||||
let si_message = vm.perm_intern("message");
|
||||
let _ = vm.define_data_property(event_obj, si_message, message_val, PropAttributes::DEFAULT_DATA);
|
||||
}
|
||||
let _ = vm.define_data_property(event_obj, si_data, JsValue::undefined(), PropAttributes::DEFAULT_DATA);
|
||||
let si_message = vm.perm_intern("message");
|
||||
let _ = vm.define_data_property(event_obj, si_message, message_val, PropAttributes::DEFAULT_DATA);
|
||||
|
||||
NativeResult::Ok(JsValue::from_js_object(ptr))
|
||||
}
|
||||
|
||||
@@ -318,8 +318,8 @@ impl Vm {
|
||||
/// 2. 对每个 worker `poll_worker_messages` 排空通道(数据面 rehydrate 进主 realm)。
|
||||
/// 3. 反查 Worker 对象(GC 根)。
|
||||
/// 4. 错误面逐条交付 `onerror`;消息交付失败面逐条交付 `onmessageerror`。
|
||||
/// 5. 数据面读 `onmessage` 属性,可调用时逐条建 MessageEvent 经
|
||||
/// `execute_task` + `call_function_sync` 触发,后 `drain_microtasks`。
|
||||
/// 5. 数据面逐条建真实 MessageEvent 经 `dispatchEvent` 交付(注册表查
|
||||
/// 监听器),后 `drain_microtasks`。
|
||||
///
|
||||
/// # 返回值
|
||||
/// 本轮是否交付了任何面(false 时调用方 1ms 轮询,避免忙等)。
|
||||
@@ -368,7 +368,7 @@ impl Vm {
|
||||
if self.worker_object(id).is_none() {
|
||||
break;
|
||||
}
|
||||
let event = self.build_message_event(data, "message", None);
|
||||
let event = self.build_message_event(data, "message");
|
||||
self.dispatch_event_on(worker_obj, event);
|
||||
self.drain_microtasks();
|
||||
}
|
||||
@@ -407,35 +407,55 @@ impl Vm {
|
||||
/// # 副作用
|
||||
/// - 触发监听器回调与微任务 drain。
|
||||
fn deliver_error_event(&mut self, worker_obj: JsValue, event_type: &str, message: &str) {
|
||||
let event = self.build_message_event(JsValue::undefined(), event_type, Some(message));
|
||||
let event = self.build_error_event(event_type, message);
|
||||
self.dispatch_event_on(worker_obj, event);
|
||||
self.drain_microtasks();
|
||||
}
|
||||
|
||||
/// 建事件对象(`data` + `type` + `message` 属性),委托 `message_event_constructor`
|
||||
/// 构造辅助。消息事件 `message` 为 `None`(undefined),错误事件 `data` 为
|
||||
/// undefined、`message` 为错误串。
|
||||
/// 消息路径建事件对象:建真实 MessageEvent(`data` + `type`,`ports` 空
|
||||
/// 数组),委托 `message_event_constructor` 构造辅助。
|
||||
///
|
||||
/// # 步骤
|
||||
/// 1. `type` 与 `message` 串物化为 session 串(`message` 为 `None` 时 undefined)。
|
||||
/// 2. `data` / `type` / `message` 写入寄存器 1 / 2 / 3,委托
|
||||
/// `message_event_constructor`(按寄存器下标读取)建对象。
|
||||
/// 1. `type` 串物化为 session 串。
|
||||
/// 2. `data` / `type` 写入寄存器 1 / 2,委托 `message_event_constructor`
|
||||
/// (按寄存器下标读取)建对象。
|
||||
///
|
||||
/// # 返回值
|
||||
/// 新建的事件对象值(构造失败时返回错误对象值)。
|
||||
///
|
||||
/// # 副作用
|
||||
/// - 新建一个事件对象(经 `alloc_object` 入对象表)。
|
||||
fn build_message_event(&mut self, data: JsValue, type_str: &str, message: Option<&str>) -> JsValue {
|
||||
/// - 新建一个 MessageEvent 盒对象(经 `alloc_object` 入对象表)。
|
||||
fn build_message_event(&mut self, data: JsValue, type_str: &str) -> JsValue {
|
||||
let type_val = self.new_string(type_str);
|
||||
let message_val = match message {
|
||||
Some(m) => self.new_string(m),
|
||||
None => JsValue::undefined(),
|
||||
};
|
||||
self.set_reg(1, data);
|
||||
self.set_reg(2, type_val);
|
||||
self.set_reg(3, message_val);
|
||||
match bindings::message_event_constructor(self, &[0, 1, 2, 3]) {
|
||||
match bindings::message_event_constructor(self, &[0, 1, 2]) {
|
||||
NativeResult::Ok(v) => v,
|
||||
NativeResult::Err(e) => e,
|
||||
// 构造辅助只建对象,不产生尾调用(防御臂,不可达)。
|
||||
NativeResult::TailCall { .. } => JsValue::undefined(),
|
||||
}
|
||||
}
|
||||
|
||||
/// 错误路径建事件对象(临时形态):建真实 Event 盒(`type` 字段)加
|
||||
/// `data` / `message` 普通属性,委托 `build_error_event` 构造辅助。
|
||||
///
|
||||
/// # 步骤
|
||||
/// 1. `type` 与 `message` 串物化为 session 串。
|
||||
/// 2. `type` / `message` 写入寄存器 1 / 2,委托 `build_error_event`
|
||||
/// (按寄存器下标读取)建对象。
|
||||
///
|
||||
/// # 返回值
|
||||
/// 新建的事件对象值(构造失败时返回错误对象值)。
|
||||
///
|
||||
/// # 副作用
|
||||
/// - 新建一个 Event 盒对象(经 `alloc_object` 入对象表)。
|
||||
fn build_error_event(&mut self, type_str: &str, message: &str) -> JsValue {
|
||||
let type_val = self.new_string(type_str);
|
||||
let message_val = self.new_string(message);
|
||||
self.set_reg(1, type_val);
|
||||
self.set_reg(2, message_val);
|
||||
match bindings::build_error_event(self, &[0, 1, 2]) {
|
||||
NativeResult::Ok(v) => v,
|
||||
NativeResult::Err(e) => e,
|
||||
// 构造辅助只建对象,不产生尾调用(防御臂,不可达)。
|
||||
@@ -478,7 +498,7 @@ impl Vm {
|
||||
/// - 触发监听器回调与微任务 drain。
|
||||
pub(crate) fn deliver_self_message(&mut self, value: MessageValue) {
|
||||
let data = rehydrate_message(self, &value);
|
||||
let event = self.build_message_event(data, "message", None);
|
||||
let event = self.build_message_event(data, "message");
|
||||
// 取 worker global 对象指针(Ref 守卫在语句块内消费,不跨 &mut 借用长存)。
|
||||
let global_ptr = {
|
||||
let session = self.realm.session.borrow();
|
||||
|
||||
Reference in New Issue
Block a user