From 00a8e9a2bd1af1c2aed60a9f738c85efc12c38ff Mon Sep 17 00:00:00 2001 From: pjh456 <147148383@qq.com> Date: Sun, 27 Sep 2026 02:05:53 +0000 Subject: [PATCH] =?UTF-8?q?refactor:=20mark=20=E8=BE=B9=E9=93=BE=E5=BD=92?= =?UTF-8?q?=E4=B8=80=E4=B8=BA=20native=20=E5=AE=B6=E6=97=8F=E5=88=86?= =?UTF-8?q?=E7=B1=BB=E5=99=A8=E9=A9=B1=E5=8A=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crates/oxide_vm/src/lib.rs | 2 + crates/oxide_vm/src/native_box_dispatch.rs | 278 +++++++++++++++++++++ crates/oxide_vm/src/session_gc.rs | 85 +------ 3 files changed, 291 insertions(+), 74 deletions(-) create mode 100644 crates/oxide_vm/src/native_box_dispatch.rs diff --git a/crates/oxide_vm/src/lib.rs b/crates/oxide_vm/src/lib.rs index 70f2d1a5..9ec6a1b9 100644 --- a/crates/oxide_vm/src/lib.rs +++ b/crates/oxide_vm/src/lib.rs @@ -19,6 +19,8 @@ mod generator; mod ic_helper; /// native 函数签名类型([`native::NativeFn`]),builtin 绑定与 VM 调用约定依赖它。 pub mod native; +/// native 载荷家族单点分类与每家族边函数引用(家族表,GC 各链注册面)。 +mod native_box_dispatch; /// Promise 运行时(状态盒 + 微任务队列 + 构造器/方法实现)。 pub mod promise; mod session_arena; diff --git a/crates/oxide_vm/src/native_box_dispatch.rs b/crates/oxide_vm/src/native_box_dispatch.rs new file mode 100644 index 00000000..f7f5a81b --- /dev/null +++ b/crates/oxide_vm/src/native_box_dispatch.rs @@ -0,0 +1,278 @@ +//! native 载荷家族的单点分类与每家族边函数引用(家族表)。 +//! +//! 分类是复合谓词:header 位(map/set/module_ns)优先于 `type_tag`, +//! 两维互斥、一个对象至多归入一个家族。tag 维显式枚举全部 0..=32, +//! 未登记 tag panic。 +//! +//! 关键约定: +//! - 每家族对 object/string/cell 三类边至多各持一个函数引用;无 native +//! 盒的类型显式归空家族。 +//! - 注册面集中在 `ops_for` 的家族表,mark/size/drop/clone/rewrite 各链 +//! 由同一张表驱动,新增家族只在此登记。 + +use oxide_builtins::{data_view, disposable_stack, map, module, set, typed_array, weak_map}; +use oxide_types::object::{Cell, JsObject, JsString}; +use oxide_types::value::JsValue; + +/// native 载荷家族。 +/// +/// 14 个 native 家族 + 空家族;空家族是无 native 盒类型的显式归类结果。 +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub(crate) enum NativeBoxFamily { + /// 无 native 载荷盒。 + None, + /// Map 实例(header bit 25)。 + Map, + /// Set 实例(header bit 24)。 + Set, + /// 模块命名空间 exotic 对象(`_pad` bit 2)。 + ModuleNamespace, + /// WeakMap(tag 31,条目表)。 + WeakMap, + /// DisposableStack / AsyncDisposableStack(tag 24/25)。 + DisposableStack, + /// TypedArray(tag 8)。 + TypedArray, + /// DataView(tag 7)。 + DataView, + /// ArrayBuffer(tag 6,字节载荷、无引用边)。 + ArrayBuffer, + /// SharedArrayBuffer(tag 30,字节载荷、无引用边)。 + SharedArrayBuffer, + /// 生成器迭代器(tag 10)。 + Generator, + /// Promise(tag 11)。 + Promise, + /// 异步函数执行上下文(tag 12)。 + Async, + /// 异步生成器迭代器(tag 13)。 + AsyncGenerator, + /// RegExp 与 matchAll 载体(tag 2/28,`native_fn` 槽持编译正则)。 + RegExp, +} + +/// 一个家族的边操作集(每家族函数引用,单一注册面)。 +pub(crate) struct NativeBoxOps { + /// 对象强边(mark 栈 / sweep 改写)。 + pub(crate) object_edges: Option Vec>, + /// native 字符串边(mark 存活集)。 + pub(crate) string_edges: Option Vec<*mut JsString>>, + /// native cell 边(mark 存活集)。 + pub(crate) cell_edges: Option Vec<*mut Cell>>, +} + +/// 分类对象的 native 载荷家族。 +/// +/// header 位优先:map/set/module_ns 经 header 位判定,与 tag 维正交; +/// 其余按 `type_tag` 分类。 +pub(crate) fn classify(obj: &JsObject) -> NativeBoxFamily { + if obj.is_map() { + return NativeBoxFamily::Map; + } + if obj.is_set() { + return NativeBoxFamily::Set; + } + if obj.is_module_namespace() { + return NativeBoxFamily::ModuleNamespace; + } + classify_by_tag(obj.type_tag) +} + +/// 按类型 tag 分类 native 载荷家族。 +/// +/// # 边界与前提 +/// - 0..=32 全 tag 显式枚举;未登记 tag(33 及以上)panic。 +pub(crate) fn classify_by_tag(tag: u8) -> NativeBoxFamily { + match tag { + JsObject::OBJ_TYPE_ARRAY_BUFFER => NativeBoxFamily::ArrayBuffer, + JsObject::OBJ_TYPE_DATA_VIEW => NativeBoxFamily::DataView, + JsObject::OBJ_TYPE_TYPED_ARRAY => NativeBoxFamily::TypedArray, + JsObject::OBJ_TYPE_GENERATOR => NativeBoxFamily::Generator, + JsObject::OBJ_TYPE_PROMISE => NativeBoxFamily::Promise, + JsObject::OBJ_TYPE_ASYNC => NativeBoxFamily::Async, + JsObject::OBJ_TYPE_ASYNC_GENERATOR => NativeBoxFamily::AsyncGenerator, + JsObject::OBJ_TYPE_DISPOSABLE_STACK | JsObject::OBJ_TYPE_ASYNC_DISPOSABLE_STACK => { + NativeBoxFamily::DisposableStack + } + JsObject::OBJ_TYPE_WEAK_MAP => NativeBoxFamily::WeakMap, + JsObject::OBJ_TYPE_SHARED_ARRAY_BUFFER => NativeBoxFamily::SharedArrayBuffer, + JsObject::OBJ_TYPE_REGEXP | JsObject::OBJ_TYPE_REGEX_STUB => NativeBoxFamily::RegExp, + // 以下 tag 无 native 载荷盒,显式归空家族。 + JsObject::OBJ_TYPE_PLAIN => NativeBoxFamily::None, + JsObject::OBJ_TYPE_DATE => NativeBoxFamily::None, + JsObject::OBJ_TYPE_BOOLEAN_OBJ => NativeBoxFamily::None, + JsObject::OBJ_TYPE_NUMBER_OBJ => NativeBoxFamily::None, + JsObject::OBJ_TYPE_STRING_OBJ => NativeBoxFamily::None, + JsObject::OBJ_TYPE_CONSTRUCTOR => NativeBoxFamily::None, + JsObject::OBJ_TYPE_INSTANT => NativeBoxFamily::None, + JsObject::OBJ_TYPE_PLAIN_DATE => NativeBoxFamily::None, + JsObject::OBJ_TYPE_PLAIN_TIME => NativeBoxFamily::None, + JsObject::OBJ_TYPE_DURATION => NativeBoxFamily::None, + JsObject::OBJ_TYPE_ZONED_DATE_TIME => NativeBoxFamily::None, + JsObject::OBJ_TYPE_PLAIN_DATE_TIME => NativeBoxFamily::None, + JsObject::OBJ_TYPE_ARGUMENTS => NativeBoxFamily::None, + JsObject::OBJ_TYPE_SYMBOL_OBJ => NativeBoxFamily::None, + JsObject::OBJ_TYPE_ERROR => NativeBoxFamily::None, + JsObject::OBJ_TYPE_BOUND => NativeBoxFamily::None, + JsObject::OBJ_TYPE_PLAIN_MONTH_DAY => NativeBoxFamily::None, + JsObject::OBJ_TYPE_PLAIN_YEAR_MONTH => NativeBoxFamily::None, + JsObject::OBJ_TYPE_HTML_DDA => NativeBoxFamily::None, + JsObject::OBJ_TYPE_RAW_JSON => NativeBoxFamily::None, + _ => panic!("unregistered type tag: {tag}"), + } +} + +/// RegExp 家族的对象边:source/flags 字段(matchAll 载体无可信属性面, +/// 两字段恒 undefined,边自然为空)。 +fn regexp_object_edges(obj: &JsObject) -> Vec { + vec![obj.get_regexp_source(), obj.get_regexp_flags()] +} + +/// 查家族的边操作集(家族表,单一注册面)。 +pub(crate) fn ops_for(family: NativeBoxFamily) -> NativeBoxOps { + match family { + NativeBoxFamily::None => NativeBoxOps { + object_edges: None, + string_edges: None, + cell_edges: None, + }, + NativeBoxFamily::Map => NativeBoxOps { + object_edges: Some(map::map_native_edges), + string_edges: None, + cell_edges: None, + }, + NativeBoxFamily::Set => NativeBoxOps { + object_edges: Some(set::set_native_edges), + string_edges: None, + cell_edges: None, + }, + NativeBoxFamily::ModuleNamespace => NativeBoxOps { + object_edges: Some(module::module_ns_native_edges), + string_edges: None, + cell_edges: Some(module::module_ns_cell_edges), + }, + // WeakMap 仅值边进 mark(强边);键为弱边,不入栈不置位。 + NativeBoxFamily::WeakMap => NativeBoxOps { + object_edges: Some(weak_map::weak_map_native_edges), + string_edges: None, + cell_edges: None, + }, + NativeBoxFamily::DisposableStack => NativeBoxOps { + object_edges: Some(disposable_stack::dispose_edges), + string_edges: None, + cell_edges: None, + }, + NativeBoxFamily::TypedArray => NativeBoxOps { + object_edges: Some(typed_array::typed_array_native_edges), + string_edges: None, + cell_edges: None, + }, + NativeBoxFamily::DataView => NativeBoxOps { + object_edges: Some(data_view::data_view_native_edges), + string_edges: None, + cell_edges: None, + }, + // 字节载荷盒:无引用边,仅 size/drop 链消费。 + NativeBoxFamily::ArrayBuffer | NativeBoxFamily::SharedArrayBuffer => NativeBoxOps { + object_edges: None, + string_edges: None, + cell_edges: None, + }, + NativeBoxFamily::Generator => NativeBoxOps { + object_edges: Some(crate::generator::generator_native_edges), + string_edges: Some(crate::generator::generator_native_string_edges), + cell_edges: Some(crate::generator::generator_native_cell_edges), + }, + NativeBoxFamily::Promise => NativeBoxOps { + object_edges: Some(crate::promise::promise_native_edges), + string_edges: None, + cell_edges: None, + }, + NativeBoxFamily::Async => NativeBoxOps { + object_edges: Some(crate::async_func::async_native_edges), + string_edges: Some(crate::async_func::async_native_string_edges), + cell_edges: Some(crate::async_func::async_native_cell_edges), + }, + NativeBoxFamily::AsyncGenerator => NativeBoxOps { + object_edges: Some(crate::async_generator::async_generator_native_edges), + string_edges: Some(crate::async_generator::async_generator_native_string_edges), + cell_edges: Some(crate::async_generator::async_generator_native_cell_edges), + }, + NativeBoxFamily::RegExp => NativeBoxOps { + object_edges: Some(regexp_object_edges), + string_edges: None, + cell_edges: None, + }, + } +} + +#[cfg(test)] +mod tests { + use super::*; + + fn obj_with_tag(tag: u8) -> JsObject { + let mut obj = JsObject::new_empty(1, JsValue::undefined()); + obj.type_tag = tag; + obj + } + + /// tag 维期望家族(测试侧口径,与分类器镜像对照)。 + fn expected_family_for_tag(tag: u8) -> NativeBoxFamily { + match tag { + JsObject::OBJ_TYPE_ARRAY_BUFFER => NativeBoxFamily::ArrayBuffer, + JsObject::OBJ_TYPE_DATA_VIEW => NativeBoxFamily::DataView, + JsObject::OBJ_TYPE_TYPED_ARRAY => NativeBoxFamily::TypedArray, + JsObject::OBJ_TYPE_GENERATOR => NativeBoxFamily::Generator, + JsObject::OBJ_TYPE_PROMISE => NativeBoxFamily::Promise, + JsObject::OBJ_TYPE_ASYNC => NativeBoxFamily::Async, + JsObject::OBJ_TYPE_ASYNC_GENERATOR => NativeBoxFamily::AsyncGenerator, + JsObject::OBJ_TYPE_DISPOSABLE_STACK | JsObject::OBJ_TYPE_ASYNC_DISPOSABLE_STACK => { + NativeBoxFamily::DisposableStack + } + JsObject::OBJ_TYPE_WEAK_MAP => NativeBoxFamily::WeakMap, + JsObject::OBJ_TYPE_SHARED_ARRAY_BUFFER => NativeBoxFamily::SharedArrayBuffer, + JsObject::OBJ_TYPE_REGEXP | JsObject::OBJ_TYPE_REGEX_STUB => NativeBoxFamily::RegExp, + _ => NativeBoxFamily::None, + } + } + + #[test] + fn tag_dimension_every_tag_hits_exactly_one_family() { + for tag in 0..=32u8 { + let obj = obj_with_tag(tag); + let family = classify(&obj); + assert_eq!(family, expected_family_for_tag(tag), "tag {tag} 家族不一致"); + } + } + + #[test] + fn header_bit_families_are_independent_dimension() { + // map/set/module_ns 经 header 位判定,tag 为 PLAIN,与 tag 维正交。 + let mut map_obj = obj_with_tag(JsObject::OBJ_TYPE_PLAIN); + map_obj.set_map(true); + assert_eq!(classify(&map_obj), NativeBoxFamily::Map); + + let mut set_obj = obj_with_tag(JsObject::OBJ_TYPE_PLAIN); + set_obj.set_set(true); + assert_eq!(classify(&set_obj), NativeBoxFamily::Set); + + let mut ns_obj = obj_with_tag(JsObject::OBJ_TYPE_PLAIN); + ns_obj.set_module_namespace(true); + assert_eq!(classify(&ns_obj), NativeBoxFamily::ModuleNamespace); + } + + #[test] + fn header_bits_take_priority_over_tag() { + // header 位优先于 tag:同置两维时按 header 位归类。 + let mut obj = obj_with_tag(JsObject::OBJ_TYPE_ARRAY_BUFFER); + obj.set_map(true); + assert_eq!(classify(&obj), NativeBoxFamily::Map); + } + + #[test] + #[should_panic(expected = "unregistered type tag")] + fn unregistered_tag_panics() { + let obj = obj_with_tag(33); + classify(&obj); + } +} diff --git a/crates/oxide_vm/src/session_gc.rs b/crates/oxide_vm/src/session_gc.rs index 5c953004..ef094c88 100644 --- a/crates/oxide_vm/src/session_gc.rs +++ b/crates/oxide_vm/src/session_gc.rs @@ -7,6 +7,7 @@ use oxide_types::object::{Cell, JsObject, JsString, PropMetaEntry}; use oxide_types::value::JsValue; use rustc_hash::FxBuildHasher; +use crate::native_box_dispatch; use crate::vm::Vm; use oxide_builtins::{array_buffer, data_view, disposable_stack, map, module, regexp, set, typed_array, weak_map}; @@ -177,88 +178,24 @@ impl SessionGc { Self::process_edge(obj.captured_this(), vm, stack, live_strings, live_bigints); Self::process_edge(obj.home_object(), vm, stack, live_strings, live_bigints); Self::process_edge(obj.boxed_value(), vm, stack, live_strings, live_bigints); - if obj.is_map() { - for value in map::map_native_edges(obj) { + // native 载荷家族边:单点分类 + 家族表函数引用驱动, + // 替代逐族 is_* 谓词链(各家族边函数引用见 native_box_dispatch)。 + let ops = native_box_dispatch::ops_for(native_box_dispatch::classify(obj)); + if let Some(object_edges) = ops.object_edges { + for value in object_edges(obj) { Self::process_edge(value, vm, stack, live_strings, live_bigints); } } - if obj.is_set() { - for value in set::set_native_edges(obj) { - Self::process_edge(value, vm, stack, live_strings, live_bigints); - } - } - if obj.is_weak_map_obj() { - // 仅值边进 mark(强边);键为弱边,不入栈不置位。 - for value in weak_map::weak_map_native_edges(obj) { - Self::process_edge(value, vm, stack, live_strings, live_bigints); - } - } - if obj.is_disposable_stack_obj() || obj.is_async_disposable_stack_obj() { - for value in disposable_stack::dispose_edges(obj) { - Self::process_edge(value, vm, stack, live_strings, live_bigints); - } - } - if obj.is_typed_array_obj() { - for value in typed_array::typed_array_native_edges(obj) { - Self::process_edge(value, vm, stack, live_strings, live_bigints); - } - } - if obj.is_data_view_obj() { - for value in data_view::data_view_native_edges(obj) { - Self::process_edge(value, vm, stack, live_strings, live_bigints); - } - } - if obj.is_module_namespace() { - for value in module::module_ns_native_edges(obj) { - Self::process_edge(value, vm, stack, live_strings, live_bigints); - } - for ptr in module::module_ns_cell_edges(obj) { - live_cells.insert(ptr); - } - } - if obj.is_generator_obj() { - for value in crate::generator::generator_native_edges(obj) { - Self::process_edge(value, vm, stack, live_strings, live_bigints); - } - for ptr in crate::generator::generator_native_string_edges(obj) { + if let Some(string_edges) = ops.string_edges { + for ptr in string_edges(obj) { Self::mark_string_live(live_strings, ptr); } - for ptr in crate::generator::generator_native_cell_edges(obj) { + } + if let Some(cell_edges) = ops.cell_edges { + for ptr in cell_edges(obj) { live_cells.insert(ptr); } } - if obj.is_promise_obj() { - for value in crate::promise::promise_native_edges(obj) { - Self::process_edge(value, vm, stack, live_strings, live_bigints); - } - } - if obj.is_async_obj() { - for value in crate::async_func::async_native_edges(obj) { - Self::process_edge(value, vm, stack, live_strings, live_bigints); - } - for ptr in crate::async_func::async_native_string_edges(obj) { - Self::mark_string_live(live_strings, ptr); - } - for ptr in crate::async_func::async_native_cell_edges(obj) { - live_cells.insert(ptr); - } - } - if obj.is_async_generator_obj() { - for value in crate::async_generator::async_generator_native_edges(obj) { - Self::process_edge(value, vm, stack, live_strings, live_bigints); - } - for ptr in crate::async_generator::async_generator_native_string_edges(obj) { - Self::mark_string_live(live_strings, ptr); - } - for ptr in crate::async_generator::async_generator_native_cell_edges(obj) { - live_cells.insert(ptr); - } - } - // RegExp 实例 source/flags 字段持有字符串边。 - if obj.is_regexp_obj() { - Self::process_edge(obj.get_regexp_source(), vm, stack, live_strings, live_bigints); - Self::process_edge(obj.get_regexp_flags(), vm, stack, live_strings, live_bigints); - } // 遍历 upvalue cell 中的引用:cell 指针本身入存活集(对象 upvalues 边 // 是 cell 的根面),值边照常走 process_edge。 for cell_ptr in obj.upvalues_slice() {