refactor: mark 边链归一为 native 家族分类器驱动

This commit is contained in:
2026-09-27 02:05:53 +00:00
parent 18737c70ea
commit 00a8e9a2bd
3 changed files with 291 additions and 74 deletions
+2
View File
@@ -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;
+278
View File
@@ -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<fn(&JsObject) -> Vec<JsValue>>,
/// native 字符串边(mark 存活集)。
pub(crate) string_edges: Option<fn(&JsObject) -> Vec<*mut JsString>>,
/// native cell 边(mark 存活集)。
pub(crate) cell_edges: Option<fn(&JsObject) -> 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<JsValue> {
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);
}
}
+11 -74
View File
@@ -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() {