mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-23 18:21:13 +08:00
feat: 落地 deferred namespace 状态盒与 is_deferred 标志
This commit is contained in:
Generated
+19
-19
@@ -1160,7 +1160,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_builtins"
|
name = "oxide_builtins"
|
||||||
version = "0.8.103"
|
version = "0.8.104"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"fast-float",
|
"fast-float",
|
||||||
@@ -1185,7 +1185,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_bytecode"
|
name = "oxide_bytecode"
|
||||||
version = "0.8.103"
|
version = "0.8.104"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"num-bigint",
|
"num-bigint",
|
||||||
"oxide_log",
|
"oxide_log",
|
||||||
@@ -1193,7 +1193,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_cfg"
|
name = "oxide_cfg"
|
||||||
version = "0.8.103"
|
version = "0.8.104"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"oxide_bytecode",
|
"oxide_bytecode",
|
||||||
"oxide_emit",
|
"oxide_emit",
|
||||||
@@ -1204,7 +1204,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_cli"
|
name = "oxide_cli"
|
||||||
version = "0.8.103"
|
version = "0.8.104"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ansi_term",
|
"ansi_term",
|
||||||
"bumpalo",
|
"bumpalo",
|
||||||
@@ -1226,7 +1226,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_code_cache"
|
name = "oxide_code_cache"
|
||||||
version = "0.8.103"
|
version = "0.8.104"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"lru",
|
"lru",
|
||||||
"oxide_bytecode",
|
"oxide_bytecode",
|
||||||
@@ -1235,7 +1235,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_compiler"
|
name = "oxide_compiler"
|
||||||
version = "0.8.103"
|
version = "0.8.104"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"oxide_bytecode",
|
"oxide_bytecode",
|
||||||
"oxide_cfg",
|
"oxide_cfg",
|
||||||
@@ -1255,7 +1255,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_dce"
|
name = "oxide_dce"
|
||||||
version = "0.8.103"
|
version = "0.8.104"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"oxide_bytecode",
|
"oxide_bytecode",
|
||||||
"oxide_cfg",
|
"oxide_cfg",
|
||||||
@@ -1269,7 +1269,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_emit"
|
name = "oxide_emit"
|
||||||
version = "0.8.103"
|
version = "0.8.104"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"num-bigint",
|
"num-bigint",
|
||||||
"oxc_allocator",
|
"oxc_allocator",
|
||||||
@@ -1284,7 +1284,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_engine"
|
name = "oxide_engine"
|
||||||
version = "0.8.103"
|
version = "0.8.104"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"oxide_bytecode",
|
"oxide_bytecode",
|
||||||
"oxide_compiler",
|
"oxide_compiler",
|
||||||
@@ -1296,7 +1296,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_ir"
|
name = "oxide_ir"
|
||||||
version = "0.8.103"
|
version = "0.8.104"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"oxide_bytecode",
|
"oxide_bytecode",
|
||||||
"oxide_log",
|
"oxide_log",
|
||||||
@@ -1305,7 +1305,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_kernel"
|
name = "oxide_kernel"
|
||||||
version = "0.8.103"
|
version = "0.8.104"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bumpalo",
|
"bumpalo",
|
||||||
"dashmap",
|
"dashmap",
|
||||||
@@ -1319,7 +1319,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_liveness"
|
name = "oxide_liveness"
|
||||||
version = "0.8.103"
|
version = "0.8.104"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"oxide_bytecode",
|
"oxide_bytecode",
|
||||||
"oxide_cfg",
|
"oxide_cfg",
|
||||||
@@ -1331,7 +1331,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_log"
|
name = "oxide_log"
|
||||||
version = "0.8.103"
|
version = "0.8.104"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"tracing",
|
"tracing",
|
||||||
"tracing-appender",
|
"tracing-appender",
|
||||||
@@ -1340,7 +1340,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_parser"
|
name = "oxide_parser"
|
||||||
version = "0.8.103"
|
version = "0.8.104"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"oxc_allocator",
|
"oxc_allocator",
|
||||||
"oxc_ast",
|
"oxc_ast",
|
||||||
@@ -1355,7 +1355,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_regalloc"
|
name = "oxide_regalloc"
|
||||||
version = "0.8.103"
|
version = "0.8.104"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"oxide_bytecode",
|
"oxide_bytecode",
|
||||||
"oxide_cfg",
|
"oxide_cfg",
|
||||||
@@ -1371,7 +1371,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_runtime_api"
|
name = "oxide_runtime_api"
|
||||||
version = "0.8.103"
|
version = "0.8.104"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"num-bigint",
|
"num-bigint",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
@@ -1384,7 +1384,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_test262"
|
name = "oxide_test262"
|
||||||
version = "0.8.103"
|
version = "0.8.104"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"oxide_bytecode",
|
"oxide_bytecode",
|
||||||
"oxide_compiler",
|
"oxide_compiler",
|
||||||
@@ -1402,7 +1402,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_types"
|
name = "oxide_types"
|
||||||
version = "0.8.103"
|
version = "0.8.104"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bumpalo",
|
"bumpalo",
|
||||||
"dashmap",
|
"dashmap",
|
||||||
@@ -1415,7 +1415,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_vm"
|
name = "oxide_vm"
|
||||||
version = "0.8.103"
|
version = "0.8.104"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bumpalo",
|
"bumpalo",
|
||||||
"chrono",
|
"chrono",
|
||||||
|
|||||||
+1
-1
@@ -23,7 +23,7 @@ members = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[workspace.package]
|
[workspace.package]
|
||||||
version = "0.8.103"
|
version = "0.8.104"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
rust-version = "1.80"
|
rust-version = "1.80"
|
||||||
|
|||||||
@@ -60,10 +60,28 @@ pub struct ModuleNsEntry {
|
|||||||
pub state: ModuleNsState,
|
pub state: ModuleNsState,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// deferred namespace 状态盒:`[[Module]]`/`[[Evaluated]]`/`[[Namespace]]` 三内部槽。
|
||||||
|
///
|
||||||
|
/// 以 `Option` 内嵌进 `ModuleNsTable`(`native_data` 的唯一分配),不新建 JsObject
|
||||||
|
/// 字段、不建第二个 Box——GC 边、字节核算、释放全部复用 `ModuleNamespace` 家族链,
|
||||||
|
/// 零新增注册点。
|
||||||
|
pub struct DeferredNsState {
|
||||||
|
/// `[[Module]]`:依赖模块函数(编译期 CREATE_CLOSURE 的闭包对象)。
|
||||||
|
pub module: JsValue,
|
||||||
|
/// `[[Evaluated]]`:依赖模块是否已求值(首次触发成功后置真,不回退)。
|
||||||
|
pub evaluated: bool,
|
||||||
|
/// `[[Namespace]]`:求值后返回的命名空间对象(求值前为 undefined)。
|
||||||
|
pub namespace: JsValue,
|
||||||
|
}
|
||||||
|
|
||||||
/// 模块命名空间条目表:挂在 ns 对象 `native_data` 上,是 exotic [[Get]] 的权威
|
/// 模块命名空间条目表:挂在 ns 对象 `native_data` 上,是 exotic [[Get]] 的权威
|
||||||
/// 状态。键为 `PermInterner` interned 键,线性查找(导出名通常少于 50)。
|
/// 状态。键为 `PermInterner` interned 键,线性查找(导出名通常少于 50)。
|
||||||
|
///
|
||||||
|
/// `deferred` 仅对 deferred namespace 对象为 `Some`(`__moduleDeferObject` 安装),
|
||||||
|
/// 其余 ns 对象恒 `None`;求值触发点(后续轮次)经 `deferred_state` 只读消费。
|
||||||
pub struct ModuleNsTable {
|
pub struct ModuleNsTable {
|
||||||
entries: Vec<ModuleNsEntry>,
|
entries: Vec<ModuleNsEntry>,
|
||||||
|
deferred: Option<DeferredNsState>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 导出名状态查询结果。
|
/// 导出名状态查询结果。
|
||||||
@@ -86,6 +104,24 @@ fn ns_table_ptr(obj: &JsObject) -> *mut ModuleNsTable {
|
|||||||
obj.native_data() as *mut ModuleNsTable
|
obj.native_data() as *mut ModuleNsTable
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 只读访问 deferred namespace 状态盒(`[[Module]]`/`[[Evaluated]]`/`[[Namespace]]`)。
|
||||||
|
///
|
||||||
|
/// # 边界与前提
|
||||||
|
/// - 返回 `None`:非 module namespace / 无条目表 / 非 deferred 对象(`deferred` 为 `None`)。
|
||||||
|
/// - 返回 `Some`:deferred 对象且已安装状态盒,供求值触发点消费三内部槽。
|
||||||
|
///
|
||||||
|
/// # 注意事项
|
||||||
|
/// - 写入点唯一(`module_defer_object` 安装),本访问器只读,不改状态盒。
|
||||||
|
pub fn deferred_state(obj: &JsObject) -> Option<&DeferredNsState> {
|
||||||
|
let table = ns_table_ptr(obj);
|
||||||
|
if table.is_null() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
// SAFETY: table 归本 ns 对象持有,生命周期见 `module_ns_export`。
|
||||||
|
let table_ref = unsafe { &*table };
|
||||||
|
table_ref.deferred.as_ref()
|
||||||
|
}
|
||||||
|
|
||||||
/// 在条目表中按 interned 键定位条目下标。
|
/// 在条目表中按 interned 键定位条目下标。
|
||||||
fn entry_index(table: &ModuleNsTable, key_si: u32) -> Option<usize> {
|
fn entry_index(table: &ModuleNsTable, key_si: u32) -> Option<usize> {
|
||||||
table.entries.iter().position(|e| e.name_si == key_si)
|
table.entries.iter().position(|e| e.name_si == key_si)
|
||||||
@@ -93,7 +129,10 @@ fn entry_index(table: &ModuleNsTable, key_si: u32) -> Option<usize> {
|
|||||||
|
|
||||||
/// 分配空条目表并挂到 ns 对象的 `native_data`。
|
/// 分配空条目表并挂到 ns 对象的 `native_data`。
|
||||||
fn install_ns_table(obj: &mut JsObject) -> *mut ModuleNsTable {
|
fn install_ns_table(obj: &mut JsObject) -> *mut ModuleNsTable {
|
||||||
let table = Box::into_raw(Box::new(ModuleNsTable { entries: Vec::new() }));
|
let table = Box::into_raw(Box::new(ModuleNsTable {
|
||||||
|
entries: Vec::new(),
|
||||||
|
deferred: None,
|
||||||
|
}));
|
||||||
obj.set_native_data(table as *mut u8);
|
obj.set_native_data(table as *mut u8);
|
||||||
table
|
table
|
||||||
}
|
}
|
||||||
@@ -189,6 +228,10 @@ pub fn module_ns_export(obj: &JsObject, key_si: u32) -> Option<ModuleNsQuery> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// 收集条目表持有的 JsValue 边(已初始化 `Value` 与全部 `Cell` 内值),供 GC mark。
|
/// 收集条目表持有的 JsValue 边(已初始化 `Value` 与全部 `Cell` 内值),供 GC mark。
|
||||||
|
///
|
||||||
|
/// deferred namespace 对象额外持有 `[[Module]]` 与 `[[Namespace]]` 两条边:
|
||||||
|
/// 依赖模块函数与求值后命名空间对象须经本单一注册点入 mark,漏登则函数在
|
||||||
|
/// deferred ns 存活期间被回收,触发点解引用悬垂。
|
||||||
pub fn module_ns_native_edges(obj: &JsObject) -> Vec<JsValue> {
|
pub fn module_ns_native_edges(obj: &JsObject) -> Vec<JsValue> {
|
||||||
let table = ns_table_ptr(obj);
|
let table = ns_table_ptr(obj);
|
||||||
if table.is_null() {
|
if table.is_null() {
|
||||||
@@ -212,6 +255,10 @@ pub fn module_ns_native_edges(obj: &JsObject) -> Vec<JsValue> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if let Some(deferred) = &table_ref.deferred {
|
||||||
|
edges.push(deferred.module);
|
||||||
|
edges.push(deferred.namespace);
|
||||||
|
}
|
||||||
edges
|
edges
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -812,6 +859,52 @@ pub fn module_eval<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// `__moduleDeferObject(fn)`:创建 deferred namespace 对象(`import defer * as` 产物)。
|
||||||
|
///
|
||||||
|
/// # 步骤
|
||||||
|
/// 1. 校验 `fn` 为函数对象(依赖模块函数,编译期 CREATE_CLOSURE 的闭包对象)。
|
||||||
|
/// 2. 建 null 原型对象,定义 `@@toStringTag` = "Deferred Module"(不可写不可枚举不可配置)。
|
||||||
|
/// 3. 置 module namespace + deferred 双标志,置 non-extensible。
|
||||||
|
/// 4. 安装条目表并写状态盒:`[[Module]]` = fn、`[[Evaluated]]` = false、
|
||||||
|
/// `[[Namespace]]` = undefined。
|
||||||
|
///
|
||||||
|
/// # 副作用
|
||||||
|
/// - 新对象创建起即标记 module namespace exotic 并置 non-extensible(同 `__moduleObject`);
|
||||||
|
/// 状态盒三内部槽由本入口唯一安装。
|
||||||
|
pub fn module_defer_object<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||||
|
if args.len() < 2 {
|
||||||
|
return type_error(vm, "__moduleDeferObject: 1 argument required");
|
||||||
|
}
|
||||||
|
let fn_val = vm.reg(args[1]);
|
||||||
|
if !fn_val.is_object() {
|
||||||
|
return type_error(vm, "__moduleDeferObject: target is not a function");
|
||||||
|
}
|
||||||
|
let ptr = fn_val.as_js_object_ptr();
|
||||||
|
if ptr.is_null() || !unsafe { (*ptr).is_function() } {
|
||||||
|
return type_error(vm, "__moduleDeferObject: target is not a function");
|
||||||
|
}
|
||||||
|
let obj = vm.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null()));
|
||||||
|
let tag_si = encode_symbol_key(vm.realm_id(), TO_STRING_TAG_SYMBOL_ID);
|
||||||
|
let tag_val = vm.new_string("Deferred Module");
|
||||||
|
let obj_ref = unsafe { &mut *obj };
|
||||||
|
if let Err(e) = vm.define_data_property(obj_ref, tag_si, tag_val, PropAttributes::new(false, false, false)) {
|
||||||
|
return NativeResult::Err(crate::error::create_error(vm, &e));
|
||||||
|
}
|
||||||
|
obj_ref.set_module_namespace(true);
|
||||||
|
obj_ref.set_deferred(true);
|
||||||
|
obj_ref.set_extensible(false);
|
||||||
|
let table = install_ns_table(obj_ref);
|
||||||
|
// SAFETY: table 由 install_ns_table 的 Box::into_raw 分配,本处恰好写入一次。
|
||||||
|
unsafe {
|
||||||
|
(*table).deferred = Some(DeferredNsState {
|
||||||
|
module: fn_val,
|
||||||
|
evaluated: false,
|
||||||
|
namespace: JsValue::undefined(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
NativeResult::Ok(JsValue::from_js_object(obj))
|
||||||
|
}
|
||||||
|
|
||||||
/// `__moduleData(kind, content)`:构造数据模块命名空间(json/text;bytes 未支持)。
|
/// `__moduleData(kind, content)`:构造数据模块命名空间(json/text;bytes 未支持)。
|
||||||
///
|
///
|
||||||
/// # 副作用
|
/// # 副作用
|
||||||
@@ -853,3 +946,73 @@ pub fn module_data<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
|||||||
obj_ref.set_extensible(false);
|
obj_ref.set_extensible(false);
|
||||||
NativeResult::Ok(JsValue::from_js_object(obj))
|
NativeResult::Ok(JsValue::from_js_object(obj))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use oxide_compiler::DefaultCompilerService;
|
||||||
|
use oxide_vm::vm::Vm;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
/// 建一个带编译服务的 VM 与一个依赖模块函数(deferred ns 的 `[[Module]]` 载荷)。
|
||||||
|
fn vm_with_function() -> (Vm, JsValue) {
|
||||||
|
let mut vm = Vm::new();
|
||||||
|
vm.set_compiler_service(Arc::new(DefaultCompilerService));
|
||||||
|
let fn_val = vm
|
||||||
|
.create_dynamic_function(&[], "return 42;", false, false)
|
||||||
|
.expect("create function");
|
||||||
|
(vm, fn_val)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn module_defer_object_installs_state_box() {
|
||||||
|
let (mut vm, fn_val) = vm_with_function();
|
||||||
|
vm.set_reg(1, fn_val);
|
||||||
|
let ns_val = module_defer_object(&mut vm, &[0, 1]).unwrap();
|
||||||
|
assert!(ns_val.is_object());
|
||||||
|
let ns_ptr = ns_val.as_js_object_ptr();
|
||||||
|
assert!(!ns_ptr.is_null());
|
||||||
|
let ns_obj = unsafe { &*ns_ptr };
|
||||||
|
assert!(ns_obj.is_module_namespace(), "deferred ns 应标记 module namespace");
|
||||||
|
assert!(ns_obj.is_deferred(), "deferred ns 应标记 deferred");
|
||||||
|
assert!(!ns_obj.is_extensible(), "deferred ns 应 non-extensible");
|
||||||
|
|
||||||
|
// 状态盒三内部槽安装正确:[[Module]] = fn、[[Evaluated]] = false、[[Namespace]] = undefined。
|
||||||
|
let state = deferred_state(ns_obj).expect("deferred state 应已安装");
|
||||||
|
assert_eq!(state.module, fn_val, "[[Module]] 应存依赖模块函数");
|
||||||
|
assert!(!state.evaluated, "[[Evaluated]] 初始应为 false");
|
||||||
|
assert_eq!(state.namespace, JsValue::undefined(), "[[Namespace]] 求值前应为 undefined");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn module_defer_object_rejects_non_function() {
|
||||||
|
let (mut vm, _) = vm_with_function();
|
||||||
|
vm.set_reg(1, JsValue::int(42));
|
||||||
|
let result = module_defer_object(&mut vm, &[0, 1]);
|
||||||
|
assert!(matches!(result, NativeResult::Err(_)), "非函数应抛 TypeError");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn module_defer_ns_gc_edge_keeps_module_function_alive() {
|
||||||
|
let (mut vm, fn_val) = vm_with_function();
|
||||||
|
let fn_ptr = fn_val.as_js_object_ptr();
|
||||||
|
|
||||||
|
// 创建 deferred ns(持有 fn);fn + ns 两个 session 对象。
|
||||||
|
vm.set_reg(1, fn_val);
|
||||||
|
let ns_val = module_defer_object(&mut vm, &[0, 1]).unwrap();
|
||||||
|
let count_after_ns = vm.session_object_count();
|
||||||
|
|
||||||
|
// 仅 ns 为根:清掉持有 fn 的寄存器,fn 唯一可达路径是 ns 的 [[Module]] 边。
|
||||||
|
vm.set_reg(1, JsValue::undefined());
|
||||||
|
vm.set_reg(0, ns_val);
|
||||||
|
|
||||||
|
// 完整收集:若 [[Module]] 边漏登,fn 被回收、计数回落。
|
||||||
|
vm.collect_session_gc();
|
||||||
|
|
||||||
|
assert_eq!(vm.session_object_count(), count_after_ns, "依赖模块函数应跨收集存活(GC 边已登记)");
|
||||||
|
// 原地 sweep 不搬移:ns 与状态盒原地保留,[[Module]] 指针稳定。
|
||||||
|
let ns_obj = unsafe { &*ns_val.as_js_object_ptr() };
|
||||||
|
let state = deferred_state(ns_obj).expect("deferred state 应存活");
|
||||||
|
assert_eq!(state.module.as_js_object_ptr(), fn_ptr, "[[Module]] 指针应稳定");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -85,8 +85,9 @@ pub const MAX_DENSE_PROPS: usize = 1_000_000;
|
|||||||
/// regexp_source: JsValue (8 字节,RegExp 实例的 source 字符串)
|
/// regexp_source: JsValue (8 字节,RegExp 实例的 source 字符串)
|
||||||
/// regexp_flags: JsValue (8 字节,RegExp 实例的 flags 字符串)
|
/// regexp_flags: JsValue (8 字节,RegExp 实例的 flags 字符串)
|
||||||
/// upvalues: *mut u8 (8 字节,指向闭包的 Box<Vec<*mut Cell>>)
|
/// upvalues: *mut u8 (8 字节,指向闭包的 Box<Vec<*mut Cell>>)
|
||||||
|
/// deferred_flags: u8 (1 字节,bit 0 = is_deferred,deferred namespace 标志)
|
||||||
///
|
///
|
||||||
/// 字段自和:132 字节,另有 4 字节尾部对齐填充
|
/// 字段自和:133 字节,另有 3 字节尾部对齐填充
|
||||||
/// 总计:136 字节
|
/// 总计:136 字节
|
||||||
/// 对齐:8 字节
|
/// 对齐:8 字节
|
||||||
pub struct JsObject {
|
pub struct JsObject {
|
||||||
@@ -138,6 +139,10 @@ pub struct JsObject {
|
|||||||
/// RegExp 实例的 flags 字符串(RegExp.prototype.flags 访问器的数据源)。
|
/// RegExp 实例的 flags 字符串(RegExp.prototype.flags 访问器的数据源)。
|
||||||
regexp_flags: JsValue,
|
regexp_flags: JsValue,
|
||||||
pub upvalues: *mut u8,
|
pub upvalues: *mut u8,
|
||||||
|
/// deferred namespace 标志位:bit 0 = is_deferred。仅对 module namespace
|
||||||
|
/// 对象有语义(deferred ns 同时置 module_namespace 与本位);其余对象恒 0。
|
||||||
|
/// 占尾部对齐填充 1 字节,136B 布局钉不变。
|
||||||
|
deferred_flags: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl JsObject {
|
impl JsObject {
|
||||||
@@ -435,6 +440,7 @@ impl JsObject {
|
|||||||
regexp_source: JsValue::undefined(),
|
regexp_source: JsValue::undefined(),
|
||||||
regexp_flags: JsValue::undefined(),
|
regexp_flags: JsValue::undefined(),
|
||||||
upvalues: std::ptr::null_mut(),
|
upvalues: std::ptr::null_mut(),
|
||||||
|
deferred_flags: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -464,6 +470,7 @@ impl JsObject {
|
|||||||
regexp_source: JsValue::undefined(),
|
regexp_source: JsValue::undefined(),
|
||||||
regexp_flags: JsValue::undefined(),
|
regexp_flags: JsValue::undefined(),
|
||||||
upvalues: std::ptr::null_mut(),
|
upvalues: std::ptr::null_mut(),
|
||||||
|
deferred_flags: 0,
|
||||||
};
|
};
|
||||||
let vec = Box::new(vec![JsValue::undefined(); n_elements.min(MAX_DENSE_PROPS)]);
|
let vec = Box::new(vec![JsValue::undefined(); n_elements.min(MAX_DENSE_PROPS)]);
|
||||||
obj.array_elements = Box::into_raw(vec) as *mut u8;
|
obj.array_elements = Box::into_raw(vec) as *mut u8;
|
||||||
@@ -680,6 +687,25 @@ impl JsObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 是否 deferred namespace 对象(`import defer * as` 产物)。
|
||||||
|
///
|
||||||
|
/// # 边界与前提
|
||||||
|
/// - 仅当 `is_module_namespace()` 为真时有语义;deferred ns 同时置
|
||||||
|
/// module_namespace 位与本位,两维独立。
|
||||||
|
/// - 读 `deferred_flags` bit 0;其余对象恒 0。
|
||||||
|
pub fn is_deferred(&self) -> bool {
|
||||||
|
self.deferred_flags & 1 != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 设置 deferred namespace 标志(写 `deferred_flags` bit 0)。
|
||||||
|
pub fn set_deferred(&mut self, value: bool) {
|
||||||
|
if value {
|
||||||
|
self.deferred_flags |= 1;
|
||||||
|
} else {
|
||||||
|
self.deferred_flags &= !1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// 数组 length 虚拟属性是否可写。
|
/// 数组 length 虚拟属性是否可写。
|
||||||
///
|
///
|
||||||
/// # 边界与前提
|
/// # 边界与前提
|
||||||
|
|||||||
@@ -9,12 +9,22 @@ fn object_size_bounds() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn js_object_exact_size() {
|
fn js_object_exact_size() {
|
||||||
// 精确钉当前布局:字段自和 132 字节 + 4 字节尾部对齐填充。
|
// 精确钉当前布局:字段自和 133 字节 + 3 字节尾部对齐填充。
|
||||||
// 对象头尺寸是 GC 账目与内存基线的锚,静默膨胀须在此显式失败。
|
// 对象头尺寸是 GC 账目与内存基线的锚,静默膨胀须在此显式失败。
|
||||||
let sz = std::mem::size_of::<JsObject>();
|
let sz = std::mem::size_of::<JsObject>();
|
||||||
assert_eq!(sz, 136, "JsObject size drifted: {sz}B");
|
assert_eq!(sz, 136, "JsObject size drifted: {sz}B");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn deferred_flag_roundtrip() {
|
||||||
|
let mut obj = JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null());
|
||||||
|
assert!(!obj.is_deferred());
|
||||||
|
obj.set_deferred(true);
|
||||||
|
assert!(obj.is_deferred());
|
||||||
|
obj.set_deferred(false);
|
||||||
|
assert!(!obj.is_deferred());
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn new_empty_defaults() {
|
fn new_empty_defaults() {
|
||||||
let obj = JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null());
|
let obj = JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null());
|
||||||
|
|||||||
@@ -54,6 +54,11 @@ pub fn bind_global(core: &Arc<KernelCore>, session: &KernelSession, global: &mut
|
|||||||
("__moduleStar", oxide_builtins::module::module_star::<crate::vm::Vm> as *const (), 3),
|
("__moduleStar", oxide_builtins::module::module_star::<crate::vm::Vm> as *const (), 3),
|
||||||
("__moduleSeal", oxide_builtins::module::module_seal::<crate::vm::Vm> as *const (), 1),
|
("__moduleSeal", oxide_builtins::module::module_seal::<crate::vm::Vm> as *const (), 1),
|
||||||
("__moduleEval", oxide_builtins::module::module_eval::<crate::vm::Vm> as *const (), 1),
|
("__moduleEval", oxide_builtins::module::module_eval::<crate::vm::Vm> as *const (), 1),
|
||||||
|
(
|
||||||
|
"__moduleDeferObject",
|
||||||
|
oxide_builtins::module::module_defer_object::<crate::vm::Vm> as *const (),
|
||||||
|
1,
|
||||||
|
),
|
||||||
("__moduleData", oxide_builtins::module::module_data::<crate::vm::Vm> as *const (), 2),
|
("__moduleData", oxide_builtins::module::module_data::<crate::vm::Vm> as *const (), 2),
|
||||||
("eval", oxide_builtins::eval::eval::<crate::vm::Vm> as *const (), 1),
|
("eval", oxide_builtins::eval::eval::<crate::vm::Vm> as *const (), 1),
|
||||||
(
|
(
|
||||||
|
|||||||
Reference in New Issue
Block a user