mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-23 18:21:13 +08:00
perf: 原生函数指针改 NonNull 使对象头缩至 136 字节
This commit is contained in:
@@ -14,8 +14,8 @@
|
||||
//! `JsObject` / `ShapeId` / `MAX_DENSE_PROPS`),显式名单防 `pub` 面无声扩大。
|
||||
//!
|
||||
//! 布局说明块位于 `JsObject` 定义上方(随结构体,不在模块头文档);
|
||||
//! 尺寸守护为 `object_size_bounds` 测试的 256B 上界,与布局块字段总字节数
|
||||
//! 并存、不统一。
|
||||
//! 尺寸守护为 `js_object_exact_size` 测试的精确字节钉,与 `object_size_bounds`
|
||||
//! 的 256B 上界并存。
|
||||
|
||||
use crate::value::JsValue;
|
||||
|
||||
@@ -75,18 +75,19 @@ pub const MAX_DENSE_PROPS: usize = 1_000_000;
|
||||
/// generation: u32 (4 字节)
|
||||
/// array_prop_count: u32 (4 字节,数组元素数,普通对象恒 0)
|
||||
/// array_len_override: u32 (4 字节,逻辑长度覆盖,length 超 dense 上限时非 0)
|
||||
/// native_fn: Option\<NativeFnPtr\> (16 字节 — 裸 `*const ()` 无法利用 Option\<NonNull\>
|
||||
/// 优化;因 repr(Rust) 布局规则存为包装 8 字节指针的 Option,带 8 字节
|
||||
/// 判别式填充)
|
||||
/// native_fn: Option\<NativeFnPtr\> (8 字节 — NativeFnPtr 是 NonNull 指针,
|
||||
/// Option 借 null niche 缩为单指针)
|
||||
/// sub_module_index: u32 (4 字节,子模块平表下标,与 table_gen 配对解析)
|
||||
/// table_gen: u32 (4 字节,创建期所属子模块平表的表代际)
|
||||
/// captured_this: JsValue (8 字节,箭头函数的词法 this)
|
||||
/// home_object: JsValue (8 字节,\[\[HomeObject\]\],供 super 查找)
|
||||
/// boxed_value: JsValue (8 字节,装箱对象的被包基元载荷,见字段注释)
|
||||
/// regexp_source: JsValue (8 字节,RegExp 实例的 source 字符串)
|
||||
/// regexp_flags: JsValue (8 字节,RegExp 实例的 flags 字符串)
|
||||
/// upvalues: *mut u8 (8 字节,指向闭包的 Box<Vec<*mut Cell>>)
|
||||
///
|
||||
/// 字段自和:124 字节,另有 4 字节对齐填充(native_fn 之前)
|
||||
/// 总计:128 字节
|
||||
/// 字段自和:132 字节,另有 4 字节尾部对齐填充
|
||||
/// 总计:136 字节
|
||||
/// 对齐:8 字节
|
||||
pub struct JsObject {
|
||||
header: u32,
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
//! 原生函数指针的类型安全不透明包装。
|
||||
//!
|
||||
//! 以 `*const ()` 存储而非具体 `fn` 类型,使本 crate 无需依赖 `oxide_vm`;
|
||||
//! 以 `NonNull<()>` 存储而非具体 `fn` 类型,使本 crate 无需依赖 `oxide_vm`;
|
||||
//! 指针必须由合法的 `NativeFn` 函数项创建且永不为空,`Send + Sync` 依赖
|
||||
//! 函数项指针天然线程安全。
|
||||
|
||||
use std::ptr::NonNull;
|
||||
|
||||
/// 原生函数指针的类型安全不透明包装。
|
||||
///
|
||||
/// 以 `*const ()` 存储而非具体 `fn` 类型,使 `oxide_types` 无需依赖
|
||||
/// `oxide_vm::Vm`。`oxide_vm` 中的调用方经 `NativeFnPtr::call_with` 转回
|
||||
/// `NativeFn`——transmute 被限制在单个泛型辅助函数中。
|
||||
/// 以 `NonNull<()>` 存储而非具体 `fn` 类型,使 `oxide_types` 无需依赖
|
||||
/// `oxide_vm::Vm`。`oxide_vm` 中的调用方经 `native_fn_ptr_to_fn` 转回
|
||||
/// `NativeFn`——transmute 被限制在单个辅助函数中。
|
||||
///
|
||||
/// # Safety 不变量
|
||||
///
|
||||
@@ -17,7 +19,7 @@
|
||||
/// 函数项指针天然线程安全(不含数据)。
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
#[repr(transparent)]
|
||||
pub struct NativeFnPtr(pub *const ());
|
||||
pub struct NativeFnPtr(pub NonNull<()>);
|
||||
|
||||
impl NativeFnPtr {
|
||||
/// 包装裸函数指针。指针必须指向合法的 `NativeFn` 函数项。
|
||||
@@ -28,13 +30,15 @@ impl NativeFnPtr {
|
||||
#[inline(always)]
|
||||
pub unsafe fn from_raw(ptr: *const ()) -> Self {
|
||||
debug_assert!(!ptr.is_null(), "NativeFnPtr must not be null");
|
||||
Self(ptr)
|
||||
// SAFETY: 非空性由调用方契约保证,debug 断言兜底;const→mut 仅为
|
||||
// NonNull 构造所需的类型形态,不改变所指。
|
||||
Self(unsafe { NonNull::new_unchecked(ptr as *mut ()) })
|
||||
}
|
||||
|
||||
/// 返回底层裸指针。
|
||||
#[inline(always)]
|
||||
pub fn as_ptr(self) -> *const () {
|
||||
self.0
|
||||
self.0.as_ptr()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,14 @@ fn object_size_bounds() {
|
||||
assert!(sz <= 256, "JsObject grew unexpectedly: {sz}B");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn js_object_exact_size() {
|
||||
// 精确钉当前布局:字段自和 132 字节 + 4 字节尾部对齐填充。
|
||||
// 对象头尺寸是 GC 账目与内存基线的锚,静默膨胀须在此显式失败。
|
||||
let sz = std::mem::size_of::<JsObject>();
|
||||
assert_eq!(sz, 136, "JsObject size drifted: {sz}B");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn new_empty_defaults() {
|
||||
let obj = JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null());
|
||||
|
||||
Reference in New Issue
Block a user