mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-23 18:21:13 +08:00
feat: import defer 的 TLA 传递依赖按规范序提升求值
This commit is contained in:
Generated
+21
-21
@@ -1160,7 +1160,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_builtins"
|
name = "oxide_builtins"
|
||||||
version = "0.18.9"
|
version = "0.19.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"fast-float",
|
"fast-float",
|
||||||
@@ -1185,7 +1185,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_bytecode"
|
name = "oxide_bytecode"
|
||||||
version = "0.18.9"
|
version = "0.19.1"
|
||||||
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.18.9"
|
version = "0.19.1"
|
||||||
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.18.9"
|
version = "0.19.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ansi_term",
|
"ansi_term",
|
||||||
"bumpalo",
|
"bumpalo",
|
||||||
@@ -1228,7 +1228,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_code_cache"
|
name = "oxide_code_cache"
|
||||||
version = "0.18.9"
|
version = "0.19.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"lru",
|
"lru",
|
||||||
"oxide_bytecode",
|
"oxide_bytecode",
|
||||||
@@ -1237,7 +1237,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_compiler"
|
name = "oxide_compiler"
|
||||||
version = "0.18.9"
|
version = "0.19.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"oxide_bytecode",
|
"oxide_bytecode",
|
||||||
"oxide_cfg",
|
"oxide_cfg",
|
||||||
@@ -1258,7 +1258,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_dce"
|
name = "oxide_dce"
|
||||||
version = "0.18.9"
|
version = "0.19.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"oxide_bytecode",
|
"oxide_bytecode",
|
||||||
"oxide_cfg",
|
"oxide_cfg",
|
||||||
@@ -1272,7 +1272,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_emit"
|
name = "oxide_emit"
|
||||||
version = "0.18.9"
|
version = "0.19.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"num-bigint",
|
"num-bigint",
|
||||||
"oxc_allocator",
|
"oxc_allocator",
|
||||||
@@ -1288,7 +1288,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_engine"
|
name = "oxide_engine"
|
||||||
version = "0.18.9"
|
version = "0.19.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"oxide_bytecode",
|
"oxide_bytecode",
|
||||||
"oxide_compiler",
|
"oxide_compiler",
|
||||||
@@ -1300,7 +1300,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_fold"
|
name = "oxide_fold"
|
||||||
version = "0.18.9"
|
version = "0.19.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"num-bigint",
|
"num-bigint",
|
||||||
"oxide_bytecode",
|
"oxide_bytecode",
|
||||||
@@ -1312,7 +1312,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_ir"
|
name = "oxide_ir"
|
||||||
version = "0.18.9"
|
version = "0.19.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"oxide_bytecode",
|
"oxide_bytecode",
|
||||||
"oxide_log",
|
"oxide_log",
|
||||||
@@ -1321,7 +1321,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_kernel"
|
name = "oxide_kernel"
|
||||||
version = "0.18.9"
|
version = "0.19.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bumpalo",
|
"bumpalo",
|
||||||
"dashmap",
|
"dashmap",
|
||||||
@@ -1335,7 +1335,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_liveness"
|
name = "oxide_liveness"
|
||||||
version = "0.18.9"
|
version = "0.19.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"oxide_bytecode",
|
"oxide_bytecode",
|
||||||
"oxide_cfg",
|
"oxide_cfg",
|
||||||
@@ -1347,7 +1347,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_log"
|
name = "oxide_log"
|
||||||
version = "0.18.9"
|
version = "0.19.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"tracing",
|
"tracing",
|
||||||
"tracing-appender",
|
"tracing-appender",
|
||||||
@@ -1356,11 +1356,11 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_net"
|
name = "oxide_net"
|
||||||
version = "0.18.9"
|
version = "0.19.1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_parser"
|
name = "oxide_parser"
|
||||||
version = "0.18.9"
|
version = "0.19.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"oxc_allocator",
|
"oxc_allocator",
|
||||||
"oxc_ast",
|
"oxc_ast",
|
||||||
@@ -1375,7 +1375,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_regalloc"
|
name = "oxide_regalloc"
|
||||||
version = "0.18.9"
|
version = "0.19.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"oxide_bytecode",
|
"oxide_bytecode",
|
||||||
"oxide_cfg",
|
"oxide_cfg",
|
||||||
@@ -1391,7 +1391,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_runtime_api"
|
name = "oxide_runtime_api"
|
||||||
version = "0.18.9"
|
version = "0.19.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"num-bigint",
|
"num-bigint",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
@@ -1404,7 +1404,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_test262"
|
name = "oxide_test262"
|
||||||
version = "0.18.9"
|
version = "0.19.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"oxide_bytecode",
|
"oxide_bytecode",
|
||||||
"oxide_compiler",
|
"oxide_compiler",
|
||||||
@@ -1424,7 +1424,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_types"
|
name = "oxide_types"
|
||||||
version = "0.18.9"
|
version = "0.19.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bumpalo",
|
"bumpalo",
|
||||||
"dashmap",
|
"dashmap",
|
||||||
@@ -1437,7 +1437,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_vm"
|
name = "oxide_vm"
|
||||||
version = "0.18.9"
|
version = "0.19.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bumpalo",
|
"bumpalo",
|
||||||
"chrono",
|
"chrono",
|
||||||
|
|||||||
+1
-1
@@ -25,7 +25,7 @@ members = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[workspace.package]
|
[workspace.package]
|
||||||
version = "0.19.0"
|
version = "0.19.1"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
rust-version = "1.80"
|
rust-version = "1.80"
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
//! source-phase / defer 语义留待后续轮次。
|
//! source-phase / defer 语义留待后续轮次。
|
||||||
|
|
||||||
use oxide_kernel::shape_forge::EMPTY_SHAPE_ID;
|
use oxide_kernel::shape_forge::EMPTY_SHAPE_ID;
|
||||||
use oxide_runtime_api::{NativeResult, VmHost};
|
use oxide_runtime_api::{to_string, NativeResult, VmHost};
|
||||||
use oxide_types::object::{Cell, JsObject, PropAttributes, PropMetaEntry};
|
use oxide_types::object::{Cell, JsObject, PropAttributes, PropMetaEntry};
|
||||||
use oxide_types::private_key::encode_symbol_key;
|
use oxide_types::private_key::encode_symbol_key;
|
||||||
use oxide_types::value::JsValue;
|
use oxide_types::value::JsValue;
|
||||||
@@ -78,6 +78,9 @@ pub struct DeferredNsState {
|
|||||||
/// 求值失败时缓存的原始错误值(再读再抛同一错误对象,保身份);
|
/// 求值失败时缓存的原始错误值(再读再抛同一错误对象,保身份);
|
||||||
/// 成功求值与求值前恒 `None`。
|
/// 成功求值与求值前恒 `None`。
|
||||||
pub error: Option<JsValue>,
|
pub error: Option<JsValue>,
|
||||||
|
/// 依赖模块规范路径:求值触发点据此查 per-module 状态(提升求值过的 TLA
|
||||||
|
/// 模块已结算,直接取缓存命名空间,防双求值)。
|
||||||
|
pub path: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 模块命名空间条目表:挂在 ns 对象 `native_data` 上,是 exotic [[Get]] 的权威
|
/// 模块命名空间条目表:挂在 ns 对象 `native_data` 上,是 exotic [[Get]] 的权威
|
||||||
@@ -897,16 +900,26 @@ pub fn module_seal<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
|||||||
NativeResult::Ok(ns_val)
|
NativeResult::Ok(ns_val)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `__moduleEval(fn)`:同步执行依赖模块(fn 为编译期 CREATE_CLOSURE 的函数对象),返回其命名空间。
|
/// `__moduleEval(fn, path)`:求值依赖模块(fn 为编译期 CREATE_CLOSURE 的函数对象,
|
||||||
|
/// path 为模块规范路径),返回其命名空间。有状态:per-module 状态按 path 键防双求值。
|
||||||
|
///
|
||||||
|
/// # 步骤
|
||||||
|
/// 1. 查 per-module 状态(按 path 键):已求值返缓存命名空间(no-op);
|
||||||
|
/// 启动中(capability promise)已结算取结算值返命名空间,未结算返 promise
|
||||||
|
/// 本体(调用方聚合 gate 据 async 标志 await 之,不重跑、不抛错)。
|
||||||
|
/// 2. 未求值:启动模块(`call_function_sync`,TLA 模块挂起返 promise、同步模块
|
||||||
|
/// 返命名空间),置状态(pending 载 promise / evaluated 载命名空间),返返值。
|
||||||
///
|
///
|
||||||
/// # 副作用
|
/// # 副作用
|
||||||
/// - 调用前置「正在求值模块」标记为 `Some(fn)`、返回后还原(save/restore,嵌套
|
/// - 调用前置「正在求值模块」标记为 `Some(fn)`、返回后还原(save/restore,嵌套
|
||||||
/// `__moduleEval` 安全):deferred namespace 求值触发的 cyclic 守卫据此判自求值。
|
/// `__moduleEval` 安全):deferred namespace 求值触发的 cyclic 守卫据此判自求值。
|
||||||
|
/// - 写 per-module 状态(键 = path)。
|
||||||
pub fn module_eval<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
pub fn module_eval<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||||
if args.len() < 2 {
|
if args.len() < 3 {
|
||||||
return type_error(vm, "__moduleEval: 1 argument required");
|
return type_error(vm, "__moduleEval: 2 arguments required");
|
||||||
}
|
}
|
||||||
let fn_val = vm.reg(args[1]);
|
let fn_val = vm.reg(args[1]);
|
||||||
|
let path_val = vm.reg(args[2]);
|
||||||
if !fn_val.is_object() {
|
if !fn_val.is_object() {
|
||||||
return type_error(vm, "__moduleEval: target is not a function");
|
return type_error(vm, "__moduleEval: target is not a function");
|
||||||
}
|
}
|
||||||
@@ -914,18 +927,50 @@ pub fn module_eval<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
|||||||
if ptr.is_null() || !unsafe { (*ptr).is_function() } {
|
if ptr.is_null() || !unsafe { (*ptr).is_function() } {
|
||||||
return type_error(vm, "__moduleEval: target is not a function");
|
return type_error(vm, "__moduleEval: target is not a function");
|
||||||
}
|
}
|
||||||
|
let path = to_string(path_val);
|
||||||
|
// 已求值:直接返缓存命名空间(no-op,防 hoisted TLA 模块与 deferred 模块
|
||||||
|
// prelude 的双求值)。
|
||||||
|
if let Some(state) = vm.get_module_eval_state(&path) {
|
||||||
|
if state.evaluated {
|
||||||
|
return NativeResult::Ok(state.namespace);
|
||||||
|
}
|
||||||
|
// 启动中:capability promise 已结算(调用方在聚合 gate 之后),取结算值;
|
||||||
|
// 未结算(提升 TLA 模块互为依赖,先启动者尚未被外层 gate 排空)返 promise
|
||||||
|
// 本体,调用方聚合 gate 据 async 标志 await 之——不重跑、不抛错。
|
||||||
|
let promise = state.namespace;
|
||||||
|
return match vm.promise_settled_value(promise) {
|
||||||
|
Some((true, value)) => {
|
||||||
|
vm.set_module_eval_state(&path, true, value);
|
||||||
|
NativeResult::Ok(value)
|
||||||
|
}
|
||||||
|
Some((false, reason)) => {
|
||||||
|
let text = to_string(reason);
|
||||||
|
NativeResult::Err(crate::error::create_from_text(vm, &text))
|
||||||
|
}
|
||||||
|
None => NativeResult::Ok(promise),
|
||||||
|
};
|
||||||
|
}
|
||||||
// 置位标记,调用返回后无条件还原(异常展开亦不残留)。
|
// 置位标记,调用返回后无条件还原(异常展开亦不残留)。
|
||||||
let saved = vm.evaluating_module();
|
let saved = vm.evaluating_module();
|
||||||
vm.set_evaluating_module(Some(fn_val));
|
vm.set_evaluating_module(Some(fn_val));
|
||||||
let result = match vm.call_function_sync(fn_val, JsValue::undefined(), &[]) {
|
let result = match vm.call_function_sync(fn_val, JsValue::undefined(), &[]) {
|
||||||
Ok(v) => NativeResult::Ok(v),
|
Ok(v) => {
|
||||||
|
// TLA 模块返 capability promise(挂起未结算),同步模块返命名空间。
|
||||||
|
if vm.is_promise_value(v) {
|
||||||
|
vm.set_module_eval_state(&path, false, v);
|
||||||
|
} else {
|
||||||
|
vm.set_module_eval_state(&path, true, v);
|
||||||
|
}
|
||||||
|
NativeResult::Ok(v)
|
||||||
|
}
|
||||||
Err(e) => NativeResult::Err(crate::error::create_error(vm, &e)),
|
Err(e) => NativeResult::Err(crate::error::create_error(vm, &e)),
|
||||||
};
|
};
|
||||||
vm.set_evaluating_module(saved);
|
vm.set_evaluating_module(saved);
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `__moduleDeferObject(fn, real_ns)`:创建 deferred namespace 对象(`import defer * as` 产物)。
|
/// `__moduleDeferObject(fn, real_ns, path)`:创建 deferred namespace 对象
|
||||||
|
/// (`import defer * as` 产物)。
|
||||||
///
|
///
|
||||||
/// # 步骤
|
/// # 步骤
|
||||||
/// 1. 校验 `fn` 为函数对象(依赖模块函数,编译期 CREATE_CLOSURE 的闭包对象)
|
/// 1. 校验 `fn` 为函数对象(依赖模块函数,编译期 CREATE_CLOSURE 的闭包对象)
|
||||||
@@ -934,17 +979,19 @@ pub fn module_eval<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
|||||||
/// 2. 建 null 原型对象,定义 `@@toStringTag` = "Deferred Module"(不可写不可枚举不可配置)。
|
/// 2. 建 null 原型对象,定义 `@@toStringTag` = "Deferred Module"(不可写不可枚举不可配置)。
|
||||||
/// 3. 置 module namespace + deferred 双标志,置 non-extensible。
|
/// 3. 置 module namespace + deferred 双标志,置 non-extensible。
|
||||||
/// 4. 安装条目表并写状态盒:`[[Module]]` = fn、`[[Evaluated]]` = `real_ns` 为对象、
|
/// 4. 安装条目表并写状态盒:`[[Module]]` = fn、`[[Evaluated]]` = `real_ns` 为对象、
|
||||||
/// `[[Namespace]]` = `real_ns`(或 undefined)、失败错误缓存恒 `None`。
|
/// `[[Namespace]]` = `real_ns`(或 undefined)、失败错误缓存恒 `None`、
|
||||||
|
/// `path` = 依赖模块规范路径(求值触发点查 per-module 状态防双求值)。
|
||||||
///
|
///
|
||||||
/// # 副作用
|
/// # 副作用
|
||||||
/// - 新对象创建起即标记 module namespace exotic 并置 non-extensible(同 `__moduleObject`);
|
/// - 新对象创建起即标记 module namespace exotic 并置 non-extensible(同 `__moduleObject`);
|
||||||
/// 状态盒三内部槽由本入口唯一安装。
|
/// 状态盒内部槽由本入口唯一安装。
|
||||||
pub fn module_defer_object<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
pub fn module_defer_object<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||||
if args.len() < 3 {
|
if args.len() < 4 {
|
||||||
return type_error(vm, "__moduleDeferObject: 2 arguments required");
|
return type_error(vm, "__moduleDeferObject: 3 arguments required");
|
||||||
}
|
}
|
||||||
let fn_val = vm.reg(args[1]);
|
let fn_val = vm.reg(args[1]);
|
||||||
let ns_val = vm.reg(args[2]);
|
let ns_val = vm.reg(args[2]);
|
||||||
|
let path = to_string(vm.reg(args[3]));
|
||||||
// fn 为函数或 undefined(哨兵);其余抛 TypeError。
|
// fn 为函数或 undefined(哨兵);其余抛 TypeError。
|
||||||
let fn_is_function = fn_val.is_object() && {
|
let fn_is_function = fn_val.is_object() && {
|
||||||
let ptr = fn_val.as_js_object_ptr();
|
let ptr = fn_val.as_js_object_ptr();
|
||||||
@@ -975,6 +1022,7 @@ pub fn module_defer_object<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
|||||||
evaluated: ns_val.is_object(),
|
evaluated: ns_val.is_object(),
|
||||||
namespace: ns_val,
|
namespace: ns_val,
|
||||||
error: None,
|
error: None,
|
||||||
|
path,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
NativeResult::Ok(JsValue::from_js_object(obj))
|
NativeResult::Ok(JsValue::from_js_object(obj))
|
||||||
@@ -1044,7 +1092,9 @@ mod tests {
|
|||||||
let (mut vm, fn_val) = vm_with_function();
|
let (mut vm, fn_val) = vm_with_function();
|
||||||
vm.set_reg(1, fn_val);
|
vm.set_reg(1, fn_val);
|
||||||
vm.set_reg(2, JsValue::undefined());
|
vm.set_reg(2, JsValue::undefined());
|
||||||
let ns_val = module_defer_object(&mut vm, &[0, 1, 2]).unwrap();
|
let path_str = vm.new_string("p");
|
||||||
|
vm.set_reg(3, path_str);
|
||||||
|
let ns_val = module_defer_object(&mut vm, &[0, 1, 2, 3]).unwrap();
|
||||||
assert!(ns_val.is_object());
|
assert!(ns_val.is_object());
|
||||||
let ns_ptr = ns_val.as_js_object_ptr();
|
let ns_ptr = ns_val.as_js_object_ptr();
|
||||||
assert!(!ns_ptr.is_null());
|
assert!(!ns_ptr.is_null());
|
||||||
@@ -1068,7 +1118,9 @@ mod tests {
|
|||||||
let ns_val = JsValue::from_js_object(real_ns);
|
let ns_val = JsValue::from_js_object(real_ns);
|
||||||
vm.set_reg(1, fn_val);
|
vm.set_reg(1, fn_val);
|
||||||
vm.set_reg(2, ns_val);
|
vm.set_reg(2, ns_val);
|
||||||
let defer_ns = module_defer_object(&mut vm, &[0, 1, 2]).unwrap();
|
let path_str = vm.new_string("p");
|
||||||
|
vm.set_reg(3, path_str);
|
||||||
|
let defer_ns = module_defer_object(&mut vm, &[0, 1, 2, 3]).unwrap();
|
||||||
let ns_obj = unsafe { &*defer_ns.as_js_object_ptr() };
|
let ns_obj = unsafe { &*defer_ns.as_js_object_ptr() };
|
||||||
let state = deferred_state(ns_obj).expect("deferred state 应已安装");
|
let state = deferred_state(ns_obj).expect("deferred state 应已安装");
|
||||||
assert_eq!(state.module, fn_val, "[[Module]] 应存依赖模块函数");
|
assert_eq!(state.module, fn_val, "[[Module]] 应存依赖模块函数");
|
||||||
@@ -1082,7 +1134,9 @@ mod tests {
|
|||||||
// 哨兵形态:fn 与 real_ns 均为 undefined(自导入/祖先 defer)。
|
// 哨兵形态:fn 与 real_ns 均为 undefined(自导入/祖先 defer)。
|
||||||
vm.set_reg(1, JsValue::undefined());
|
vm.set_reg(1, JsValue::undefined());
|
||||||
vm.set_reg(2, JsValue::undefined());
|
vm.set_reg(2, JsValue::undefined());
|
||||||
let ns_val = module_defer_object(&mut vm, &[0, 1, 2]).unwrap();
|
let path_str = vm.new_string("p");
|
||||||
|
vm.set_reg(3, path_str);
|
||||||
|
let ns_val = module_defer_object(&mut vm, &[0, 1, 2, 3]).unwrap();
|
||||||
let ns_obj = unsafe { &*ns_val.as_js_object_ptr() };
|
let ns_obj = unsafe { &*ns_val.as_js_object_ptr() };
|
||||||
let state = deferred_state(ns_obj).expect("deferred state 应已安装");
|
let state = deferred_state(ns_obj).expect("deferred state 应已安装");
|
||||||
assert_eq!(state.module, JsValue::undefined(), "哨兵 [[Module]] 应为 undefined");
|
assert_eq!(state.module, JsValue::undefined(), "哨兵 [[Module]] 应为 undefined");
|
||||||
@@ -1095,7 +1149,9 @@ mod tests {
|
|||||||
let (mut vm, _) = vm_with_function();
|
let (mut vm, _) = vm_with_function();
|
||||||
vm.set_reg(1, JsValue::int(42));
|
vm.set_reg(1, JsValue::int(42));
|
||||||
vm.set_reg(2, JsValue::undefined());
|
vm.set_reg(2, JsValue::undefined());
|
||||||
let result = module_defer_object(&mut vm, &[0, 1, 2]);
|
let path_str = vm.new_string("p");
|
||||||
|
vm.set_reg(3, path_str);
|
||||||
|
let result = module_defer_object(&mut vm, &[0, 1, 2, 3]);
|
||||||
assert!(matches!(result, NativeResult::Err(_)), "非函数应抛 TypeError");
|
assert!(matches!(result, NativeResult::Err(_)), "非函数应抛 TypeError");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1104,7 +1160,9 @@ mod tests {
|
|||||||
let (mut vm, fn_val) = vm_with_function();
|
let (mut vm, fn_val) = vm_with_function();
|
||||||
vm.set_reg(1, fn_val);
|
vm.set_reg(1, fn_val);
|
||||||
vm.set_reg(2, JsValue::int(42));
|
vm.set_reg(2, JsValue::int(42));
|
||||||
let result = module_defer_object(&mut vm, &[0, 1, 2]);
|
let path_str = vm.new_string("p");
|
||||||
|
vm.set_reg(3, path_str);
|
||||||
|
let result = module_defer_object(&mut vm, &[0, 1, 2, 3]);
|
||||||
assert!(matches!(result, NativeResult::Err(_)), "非对象 real_ns 应抛 TypeError");
|
assert!(matches!(result, NativeResult::Err(_)), "非对象 real_ns 应抛 TypeError");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1116,7 +1174,9 @@ mod tests {
|
|||||||
// 创建 deferred ns(持有 fn);fn + ns 两个 session 对象。
|
// 创建 deferred ns(持有 fn);fn + ns 两个 session 对象。
|
||||||
vm.set_reg(1, fn_val);
|
vm.set_reg(1, fn_val);
|
||||||
vm.set_reg(2, JsValue::undefined());
|
vm.set_reg(2, JsValue::undefined());
|
||||||
let ns_val = module_defer_object(&mut vm, &[0, 1, 2]).unwrap();
|
let path_str = vm.new_string("p");
|
||||||
|
vm.set_reg(3, path_str);
|
||||||
|
let ns_val = module_defer_object(&mut vm, &[0, 1, 2, 3]).unwrap();
|
||||||
let count_after_ns = vm.session_object_count();
|
let count_after_ns = vm.session_object_count();
|
||||||
|
|
||||||
// 仅 ns 为根:清掉持有 fn 的寄存器,fn 唯一可达路径是 ns 的 [[Module]] 边。
|
// 仅 ns 为根:清掉持有 fn 的寄存器,fn 唯一可达路径是 ns 的 [[Module]] 边。
|
||||||
@@ -1143,7 +1203,9 @@ mod tests {
|
|||||||
// 创建 deferred ns(哨兵形态)。
|
// 创建 deferred ns(哨兵形态)。
|
||||||
vm.set_reg(1, JsValue::undefined());
|
vm.set_reg(1, JsValue::undefined());
|
||||||
vm.set_reg(2, JsValue::undefined());
|
vm.set_reg(2, JsValue::undefined());
|
||||||
let ns_val = module_defer_object(&mut vm, &[0, 1, 2]).unwrap();
|
let path_str = vm.new_string("p");
|
||||||
|
vm.set_reg(3, path_str);
|
||||||
|
let ns_val = module_defer_object(&mut vm, &[0, 1, 2, 3]).unwrap();
|
||||||
|
|
||||||
// 直接写入 error 字段(模拟失败缓存),置已求值。
|
// 直接写入 error 字段(模拟失败缓存),置已求值。
|
||||||
{
|
{
|
||||||
@@ -1177,7 +1239,9 @@ mod tests {
|
|||||||
// 模块函数返回非对象(42):求值成功后 [[Namespace]] 为非对象值。
|
// 模块函数返回非对象(42):求值成功后 [[Namespace]] 为非对象值。
|
||||||
vm.set_reg(1, fn_val);
|
vm.set_reg(1, fn_val);
|
||||||
vm.set_reg(2, JsValue::undefined());
|
vm.set_reg(2, JsValue::undefined());
|
||||||
let ns_val = module_defer_object(&mut vm, &[0, 1, 2]).unwrap();
|
let path_str = vm.new_string("p");
|
||||||
|
vm.set_reg(3, path_str);
|
||||||
|
let ns_val = module_defer_object(&mut vm, &[0, 1, 2, 3]).unwrap();
|
||||||
let ns_ptr = ns_val.as_js_object_ptr();
|
let ns_ptr = ns_val.as_js_object_ptr();
|
||||||
|
|
||||||
// 模拟求值完成:[[Evaluated]] 置真、[[Namespace]] 为非对象值 42。
|
// 模拟求值完成:[[Evaluated]] 置真、[[Namespace]] 为非对象值 42。
|
||||||
@@ -1205,7 +1269,9 @@ mod tests {
|
|||||||
let real_ns_val = JsValue::from_js_object(real_ns);
|
let real_ns_val = JsValue::from_js_object(real_ns);
|
||||||
vm.set_reg(1, fn_val);
|
vm.set_reg(1, fn_val);
|
||||||
vm.set_reg(2, real_ns_val);
|
vm.set_reg(2, real_ns_val);
|
||||||
let ns_val = module_defer_object(&mut vm, &[0, 1, 2]).unwrap();
|
let path_str = vm.new_string("p");
|
||||||
|
vm.set_reg(3, path_str);
|
||||||
|
let ns_val = module_defer_object(&mut vm, &[0, 1, 2, 3]).unwrap();
|
||||||
let ns_ptr = ns_val.as_js_object_ptr();
|
let ns_ptr = ns_val.as_js_object_ptr();
|
||||||
|
|
||||||
// 权威读目标返回真实 ns(活值与真实槽位在真实 ns 条目表)。
|
// 权威读目标返回真实 ns(活值与真实槽位在真实 ns 条目表)。
|
||||||
|
|||||||
+285
-69
@@ -59,6 +59,74 @@ struct DepPhase {
|
|||||||
attrs: Vec<(String, String)>,
|
attrs: Vec<(String, String)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 依赖图节点:模块的依赖路径集(源序)、自身 TLA 标志、提升求值用 IR 副本。
|
||||||
|
///
|
||||||
|
/// `ir` 仅对含顶层 `await` 的模块(TLA 边界)回填其完整 `IRFunction`:提升求值时
|
||||||
|
/// 入口模块须在自己的 `ctx.nested` 持有该模块 IR 才能发 `CREATE_CLOSURE`——传递
|
||||||
|
/// TLA 依赖编译在中间模块的 `ctx.nested`,入口侧无直接引用,故按 path 键缓存 IR。
|
||||||
|
struct DepNode {
|
||||||
|
deps: Vec<String>,
|
||||||
|
has_tla: bool,
|
||||||
|
ir: Option<IRFunction>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 编译期依赖图:`GatherAsynchronousTransitiveDependencies` 的 DFS 游走载体。
|
||||||
|
///
|
||||||
|
/// 键 = 模块规范路径(与加载器 `resolve` 回填口径一致),值 = 依赖路径集
|
||||||
|
/// (源序)+ 自身 TLA 标志 + 嵌套 IR 下标。递归编译期间逐模块登记,defer 依赖
|
||||||
|
/// 的 TLA 传递依赖据此按发现序收集并提升求值。
|
||||||
|
struct ModuleDepGraph {
|
||||||
|
nodes: HashMap<String, DepNode>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ModuleDepGraph {
|
||||||
|
fn new() -> Self {
|
||||||
|
Self { nodes: HashMap::new() }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 登记模块节点:依赖路径集按源序、`has_tla` 为模块自身顶层 `await` 标志。
|
||||||
|
fn record_module(&mut self, path: &str, deps: Vec<String>, has_tla: bool) {
|
||||||
|
self.nodes.insert(path.to_string(), DepNode { deps, has_tla, ir: None });
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 回填 TLA 模块的完整 IR(`compile_js_dep` 组装 IR 后调用,仅 `has_tla` 模块)。
|
||||||
|
fn set_ir(&mut self, path: &str, ir: IRFunction) {
|
||||||
|
if let Some(node) = self.nodes.get_mut(path) {
|
||||||
|
node.ir = Some(ir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 取 TLA 模块的完整 IR(非 TLA 或未登记时为 `None`)。
|
||||||
|
fn ir(&self, path: &str) -> Option<IRFunction> {
|
||||||
|
self.nodes.get(path).and_then(|n| n.ir.clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// `GatherAsynchronousTransitiveDependencies` 编译期等价:DFS 游走依赖图,
|
||||||
|
/// 按发现序收集 TLA 边界模块(自身含顶层 `await` 的模块;命中即停,不递归)。
|
||||||
|
fn gather_tla(&self, root: &str) -> Vec<String> {
|
||||||
|
let mut seen = HashSet::new();
|
||||||
|
let mut result = Vec::new();
|
||||||
|
self.gather_dfs(root, &mut seen, &mut result);
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gather_dfs(&self, path: &str, seen: &mut HashSet<String>, result: &mut Vec<String>) {
|
||||||
|
if !seen.insert(path.to_string()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let Some(node) = self.nodes.get(path) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
if node.has_tla {
|
||||||
|
result.push(path.to_string());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for dep in &node.deps {
|
||||||
|
self.gather_dfs(dep, seen, result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// 模块加载器:由调用方(test262 runner / CLI)提供文件解析。
|
/// 模块加载器:由调用方(test262 runner / CLI)提供文件解析。
|
||||||
pub trait ModuleSourceLoader {
|
pub trait ModuleSourceLoader {
|
||||||
/// 解析依赖模块:按 `base_dir` 与 `specifier` 定位模块源码,`attributes` 为
|
/// 解析依赖模块:按 `base_dir` 与 `specifier` 定位模块源码,`attributes` 为
|
||||||
@@ -716,7 +784,8 @@ impl Emitter {
|
|||||||
// ES module 顶层恒严格模式(模块代码是严格模式代码,嵌套函数经父 ctx 继承)。
|
// ES module 顶层恒严格模式(模块代码是严格模式代码,嵌套函数经父 ctx 继承)。
|
||||||
ctx.is_strict = true;
|
ctx.is_strict = true;
|
||||||
let mut path_stack = vec![module_path.to_string()];
|
let mut path_stack = vec![module_path.to_string()];
|
||||||
self.emit_module_into_ctx(program, module_path, loader, &mut path_stack, &mut ctx, true)?;
|
let mut graph = ModuleDepGraph::new();
|
||||||
|
self.emit_module_into_ctx(program, module_path, loader, &mut path_stack, &mut ctx, true, &mut graph)?;
|
||||||
Ok(ctx.assemble_ir(ParamLayout { base: 0, count: 0 }, None))
|
Ok(ctx.assemble_ir(ParamLayout { base: 0, count: 0 }, None))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -727,7 +796,7 @@ impl Emitter {
|
|||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
fn emit_module_into_ctx(
|
fn emit_module_into_ctx(
|
||||||
&self, program: &oxide_parser::Program, module_path: &str, loader: &mut dyn ModuleSourceLoader,
|
&self, program: &oxide_parser::Program, module_path: &str, loader: &mut dyn ModuleSourceLoader,
|
||||||
path_stack: &mut Vec<String>, ctx: &mut CompileCtx, top_level: bool,
|
path_stack: &mut Vec<String>, ctx: &mut CompileCtx, top_level: bool, graph: &mut ModuleDepGraph,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
let body = &program.body;
|
let body = &program.body;
|
||||||
|
|
||||||
@@ -755,9 +824,9 @@ impl Emitter {
|
|||||||
ctx.module_ns_reg = Some(ns_reg);
|
ctx.module_ns_reg = Some(ns_reg);
|
||||||
|
|
||||||
// —— 依赖收集(import + re-export/star 的 source,按首次出现去重,记 phase)——
|
// —— 依赖收集(import + re-export/star 的 source,按首次出现去重,记 phase)——
|
||||||
// eager_order 为各 spec 首个 eager 语句的出现序(求值序);defer_order 为各 spec
|
// eager_order 为各 spec 首个 eager 语句的出现序(编译序);defer_order 为各
|
||||||
// 首次出现序(defer-only 组发射序)。无 defer 的模块两序与首次出现序恒等,
|
// spec 首次出现序(求值发射序,evaluationList 序)。无 defer 的模块两序与
|
||||||
// 发射产物与现态逐字节一致。
|
// 首次出现序恒等,发射产物与现态逐字节一致。
|
||||||
let base_dir = Path::new(module_path)
|
let base_dir = Path::new(module_path)
|
||||||
.parent()
|
.parent()
|
||||||
.map(|p| p.to_string_lossy().to_string())
|
.map(|p| p.to_string_lossy().to_string())
|
||||||
@@ -765,6 +834,10 @@ impl Emitter {
|
|||||||
let mut phase_map: HashMap<String, DepPhase> = HashMap::new();
|
let mut phase_map: HashMap<String, DepPhase> = HashMap::new();
|
||||||
let mut eager_order: Vec<String> = Vec::new();
|
let mut eager_order: Vec<String> = Vec::new();
|
||||||
let mut defer_order: Vec<String> = Vec::new();
|
let mut defer_order: Vec<String> = Vec::new();
|
||||||
|
// 语句源序(spec, 是否 defer):evaluationList 求值发射序的权威口径——
|
||||||
|
// 每条语句按源位贡献(defer 语句贡献其 TLA 传递依赖、eager 语句贡献模块
|
||||||
|
// 本体),mixed 依赖的求值点落在其 eager 语句位(非首次出现位)。
|
||||||
|
let mut stmt_order: Vec<(String, bool)> = Vec::new();
|
||||||
for stmt in body {
|
for stmt in body {
|
||||||
let (spec, attrs, is_defer) = match stmt {
|
let (spec, attrs, is_defer) = match stmt {
|
||||||
Statement::ImportDeclaration(imp) => {
|
Statement::ImportDeclaration(imp) => {
|
||||||
@@ -783,6 +856,7 @@ impl Emitter {
|
|||||||
}
|
}
|
||||||
_ => continue,
|
_ => continue,
|
||||||
};
|
};
|
||||||
|
stmt_order.push((spec.clone(), is_defer));
|
||||||
let is_new = !phase_map.contains_key(&spec);
|
let is_new = !phase_map.contains_key(&spec);
|
||||||
let entry = phase_map.entry(spec.clone()).or_insert_with(|| DepPhase {
|
let entry = phase_map.entry(spec.clone()).or_insert_with(|| DepPhase {
|
||||||
eager: false,
|
eager: false,
|
||||||
@@ -811,23 +885,39 @@ impl Emitter {
|
|||||||
// 异步 eager 依赖的 (spec, `__moduleEval` 返回的 promise 寄存器):prelude
|
// 异步 eager 依赖的 (spec, `__moduleEval` 返回的 promise 寄存器):prelude
|
||||||
// 聚合 gate 消费。defer-only 依赖不求值、不产生 promise,不入此集。
|
// 聚合 gate 消费。defer-only 依赖不求值、不产生 promise,不入此集。
|
||||||
let mut async_dep_promises: Vec<(String, u32)> = Vec::new();
|
let mut async_dep_promises: Vec<(String, u32)> = Vec::new();
|
||||||
|
let mut hoisted_tla_promises: Vec<u32> = Vec::new();
|
||||||
|
|
||||||
// —— 编译并求值依赖:eager 组先行(按 eager 语句序),defer-only 组随后 ——
|
// 逐依赖发射数据:编译期(旧序)记录闭包寄存器与求值信息,求值期
|
||||||
|
// (evaluationList 序)消费。
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct DepEmitData {
|
||||||
|
fn_reg: Option<u32>,
|
||||||
|
own_names: HashSet<String>,
|
||||||
|
var_scoped: HashSet<String>,
|
||||||
|
eval_async: bool,
|
||||||
|
path: String,
|
||||||
|
is_self: bool,
|
||||||
|
is_defer: bool,
|
||||||
|
}
|
||||||
|
let mut dep_data: HashMap<String, DepEmitData> = HashMap::new();
|
||||||
|
|
||||||
|
// —— 阶段一:编译依赖(旧序:eager 组按 eager 语句序、defer-only 组随后),
|
||||||
|
// 发 CREATE_CLOSURE 并登记子模块树;求值发射推迟到阶段二(evaluationList 序)。——
|
||||||
for spec in eager_order {
|
for spec in eager_order {
|
||||||
let phase = &phase_map[&spec];
|
let phase = &phase_map[&spec];
|
||||||
let attr_refs: Vec<(&str, &str)> = phase.attrs.iter().map(|(k, v)| (k.as_str(), v.as_str())).collect();
|
let attr_refs: Vec<(&str, &str)> = phase.attrs.iter().map(|(k, v)| (k.as_str(), v.as_str())).collect();
|
||||||
let resolved = loader.resolve(&base_dir, &spec, &attr_refs)?;
|
let resolved = loader.resolve(&base_dir, &spec, &attr_refs)?;
|
||||||
let is_self = resolved.path == module_path;
|
let is_self = resolved.path == module_path;
|
||||||
let (dep_ns_reg, fn_reg, dep_own_names, dep_var_scoped) = if is_self {
|
let (fn_reg, dep_eval_async, dep_own_names, dep_var_scoped) = if is_self {
|
||||||
// 自导入:读自身命名空间(依赖即本模块,勿递归)。
|
// 自导入:读自身命名空间(依赖即本模块,勿递归)。
|
||||||
(ns_reg, None, own_export_names.clone(), var_scoped_export_names.clone())
|
(None, false, own_export_names.clone(), var_scoped_export_names.clone())
|
||||||
} else {
|
} else {
|
||||||
if path_stack.contains(&resolved.path) {
|
if path_stack.contains(&resolved.path) {
|
||||||
return Err(format!("circular module import not supported: {}", resolved.path));
|
return Err(format!("circular module import not supported: {}", resolved.path));
|
||||||
}
|
}
|
||||||
path_stack.push(resolved.path.clone());
|
path_stack.push(resolved.path.clone());
|
||||||
let (dep_ir, dep_reassignable, dep_own_names, dep_var_scoped, dep_eval_async) = match resolved.kind {
|
let (dep_ir, dep_reassignable, dep_own_names, dep_var_scoped, dep_eval_async) = match resolved.kind {
|
||||||
ModuleKind::Js => self.compile_js_dep(&resolved, loader, path_stack)?,
|
ModuleKind::Js => self.compile_js_dep(&resolved, loader, path_stack, graph)?,
|
||||||
ModuleKind::Json => (
|
ModuleKind::Json => (
|
||||||
self.compile_data_dep("json", &resolved.source)?,
|
self.compile_data_dep("json", &resolved.source)?,
|
||||||
false,
|
false,
|
||||||
@@ -849,65 +939,51 @@ impl Emitter {
|
|||||||
ctx.module_dep_reassignable.insert(spec.clone(), dep_reassignable);
|
ctx.module_dep_reassignable.insert(spec.clone(), dep_reassignable);
|
||||||
let fn_reg = ctx.alloc_reg();
|
let fn_reg = ctx.alloc_reg();
|
||||||
ctx.inst(Inst::create_closure(Operand::Reg(fn_reg), ctx.nested.len() as u16));
|
ctx.inst(Inst::create_closure(Operand::Reg(fn_reg), ctx.nested.len() as u16));
|
||||||
let real_ns = self.emit_module_call(ctx, "__moduleEval", &[fn_reg])?;
|
(Some(fn_reg), dep_eval_async, dep_own_names, dep_var_scoped)
|
||||||
// 异步依赖:`__moduleEval` 返回 capability promise(非命名空间),
|
|
||||||
// 登记进聚合 gate;命名空间在 gate 后从 promise 结算值提取。
|
|
||||||
if dep_eval_async {
|
|
||||||
async_dep_promises.push((spec.clone(), real_ns));
|
|
||||||
}
|
|
||||||
(real_ns, Some(fn_reg), dep_own_names, dep_var_scoped)
|
|
||||||
};
|
};
|
||||||
ctx.module_dep_ns_regs.insert(spec.clone(), dep_ns_reg);
|
dep_data.insert(
|
||||||
ctx.module_dep_paths.insert(spec.clone(), resolved.path.clone());
|
spec.clone(),
|
||||||
if is_self {
|
DepEmitData {
|
||||||
// 自导入:绑定走别名语义(源导出在 body 执行中才就绪),
|
fn_reg,
|
||||||
// 不能像普通依赖那样链接期快照。
|
own_names: dep_own_names,
|
||||||
ctx.module_self_import_specs.insert(spec.clone());
|
var_scoped: dep_var_scoped,
|
||||||
}
|
eval_async: dep_eval_async,
|
||||||
if phase.defer {
|
path: resolved.path,
|
||||||
// mixed 依赖:模块已急切求值,deferred 对象承载已求值态
|
is_self,
|
||||||
// ([[Evaluated]]=true、[[Namespace]]=真实 ns)。
|
is_defer: phase.defer,
|
||||||
let fn_or_sentinel = if is_self {
|
},
|
||||||
// 自导入 mixed:模块函数在导入方 prelude 期不可得,发哨兵形态。
|
);
|
||||||
self.emit_undefined(ctx)
|
|
||||||
} else {
|
|
||||||
fn_reg.expect("非自导入 eager 依赖必有闭包寄存器")
|
|
||||||
};
|
|
||||||
let defer_ns = self.emit_module_call(ctx, "__moduleDeferObject", &[fn_or_sentinel, dep_ns_reg])?;
|
|
||||||
ctx.module_defer_ns_regs.insert(spec.clone(), defer_ns);
|
|
||||||
self.emit_defer_pre_register(ctx, defer_ns, &dep_own_names, &dep_var_scoped)?;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 本模块异步求值标志:自身含顶层 `await`,或任一 eager 依赖按异步求值
|
// defer-only 组(eager == false 的 spec,按 defer_order):编译入子模块树、
|
||||||
// (传递异步经 `dep_eval_async` 递归回传),模块体按合成异步函数编译
|
// 发 CREATE_CLOSURE,求值发射推迟到阶段二。
|
||||||
// (`assemble_ir` 据此回写 IR 的 `is_async`)。非 TLA 模块恒 false,零 diff。
|
for spec in &defer_order {
|
||||||
ctx.is_async = own_tla || !async_dep_promises.is_empty();
|
let phase = &phase_map[spec];
|
||||||
|
|
||||||
// defer-only 组(eager == false 的 spec,按 defer_order):不求值、不发
|
|
||||||
// __moduleEval。祖先判定(自导入或父链回边)命中时发哨兵形态
|
|
||||||
// __moduleDeferObject(undefined, undefined)——不递归、不压 path_stack、不编译;
|
|
||||||
// 否则正常编译并发 __moduleDeferObject(fn, undefined) + 逐名预注册。
|
|
||||||
for spec in defer_order {
|
|
||||||
let phase = &phase_map[&spec];
|
|
||||||
if phase.eager {
|
if phase.eager {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let attr_refs: Vec<(&str, &str)> = phase.attrs.iter().map(|(k, v)| (k.as_str(), v.as_str())).collect();
|
let attr_refs: Vec<(&str, &str)> = phase.attrs.iter().map(|(k, v)| (k.as_str(), v.as_str())).collect();
|
||||||
let resolved = loader.resolve(&base_dir, &spec, &attr_refs)?;
|
let resolved = loader.resolve(&base_dir, spec, &attr_refs)?;
|
||||||
let is_ancestor = resolved.path == module_path || path_stack.contains(&resolved.path);
|
let is_ancestor = resolved.path == module_path || path_stack.contains(&resolved.path);
|
||||||
if is_ancestor {
|
if is_ancestor {
|
||||||
// 哨兵:模块函数在导入方 prelude 期不可得(自导入是自身、祖先是
|
// 哨兵:模块函数在导入方 prelude 期不可得(自导入是自身、祖先是
|
||||||
// 父链),defer 回边在导入图上成环,编译期不得报循环。
|
// 父链),defer 回边在导入图上成环,编译期不得报循环。
|
||||||
let undef = self.emit_undefined(ctx);
|
dep_data.insert(
|
||||||
let defer_ns = self.emit_module_call(ctx, "__moduleDeferObject", &[undef, undef])?;
|
spec.clone(),
|
||||||
ctx.module_dep_ns_regs.insert(spec.clone(), defer_ns);
|
DepEmitData {
|
||||||
ctx.module_defer_ns_regs.insert(spec.clone(), defer_ns);
|
fn_reg: None,
|
||||||
ctx.module_dep_paths.insert(spec.clone(), resolved.path.clone());
|
own_names: HashSet::new(),
|
||||||
|
var_scoped: HashSet::new(),
|
||||||
|
eval_async: false,
|
||||||
|
path: resolved.path,
|
||||||
|
is_self: true,
|
||||||
|
is_defer: true,
|
||||||
|
},
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
path_stack.push(resolved.path.clone());
|
path_stack.push(resolved.path.clone());
|
||||||
let (dep_ir, _dep_reassignable, dep_own_names, dep_var_scoped, _dep_eval_async) = match resolved.kind {
|
let (dep_ir, _dep_reassignable, dep_own_names, dep_var_scoped, _dep_eval_async) = match resolved.kind {
|
||||||
ModuleKind::Js => self.compile_js_dep(&resolved, loader, path_stack)?,
|
ModuleKind::Js => self.compile_js_dep(&resolved, loader, path_stack, graph)?,
|
||||||
ModuleKind::Json => (
|
ModuleKind::Json => (
|
||||||
self.compile_data_dep("json", &resolved.source)?,
|
self.compile_data_dep("json", &resolved.source)?,
|
||||||
false,
|
false,
|
||||||
@@ -928,26 +1004,159 @@ impl Emitter {
|
|||||||
ctx.nested.push(dep_ir);
|
ctx.nested.push(dep_ir);
|
||||||
let fn_reg = ctx.alloc_reg();
|
let fn_reg = ctx.alloc_reg();
|
||||||
ctx.inst(Inst::create_closure(Operand::Reg(fn_reg), ctx.nested.len() as u16));
|
ctx.inst(Inst::create_closure(Operand::Reg(fn_reg), ctx.nested.len() as u16));
|
||||||
let undef = self.emit_undefined(ctx);
|
dep_data.insert(
|
||||||
let defer_ns = self.emit_module_call(ctx, "__moduleDeferObject", &[fn_reg, undef])?;
|
spec.clone(),
|
||||||
ctx.module_dep_ns_regs.insert(spec.clone(), defer_ns);
|
DepEmitData {
|
||||||
ctx.module_defer_ns_regs.insert(spec.clone(), defer_ns);
|
fn_reg: Some(fn_reg),
|
||||||
ctx.module_dep_paths.insert(spec.clone(), resolved.path.clone());
|
own_names: dep_own_names,
|
||||||
self.emit_defer_pre_register(ctx, defer_ns, &dep_own_names, &dep_var_scoped)?;
|
var_scoped: dep_var_scoped,
|
||||||
|
eval_async: false,
|
||||||
|
path: resolved.path,
|
||||||
|
is_self: false,
|
||||||
|
is_defer: true,
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// —— 聚合 gate:异步依赖的 `__moduleEval` 返回 capability promise(非命名空间),
|
// —— 阶段二:按 evaluationList 序(语句源位交错)发射求值——每条语句按源位
|
||||||
// 其命名空间在 gate 后从结算值提取。单 AWAIT 挂起模块体直至全部异步依赖结算
|
// 贡献:defer 语句提升其 TLA 传递依赖、eager 语句求值模块本体(去重,mixed
|
||||||
// (由 drain 微任务释放),非 TLA 模块此集为空、零 IR 变化。——
|
// 依赖的求值点落在其 eager 语句位而非首次出现位)。——
|
||||||
if !async_dep_promises.is_empty() {
|
let mut evaluated_specs: HashSet<String> = HashSet::new();
|
||||||
let promise_regs: Vec<u32> = async_dep_promises.iter().map(|(_, r)| *r).collect();
|
let mut hoisted_tla: HashSet<String> = HashSet::new();
|
||||||
let gate_reg = self.emit_module_call(ctx, "__moduleWaitAll", &promise_regs)?;
|
for (spec, is_defer) in &stmt_order {
|
||||||
|
let phase = &phase_map[spec];
|
||||||
|
let data = dep_data.get(spec).cloned().unwrap_or_else(|| {
|
||||||
|
DepEmitData {
|
||||||
|
fn_reg: None,
|
||||||
|
own_names: HashSet::new(),
|
||||||
|
var_scoped: HashSet::new(),
|
||||||
|
eval_async: false,
|
||||||
|
path: String::new(),
|
||||||
|
is_self: false,
|
||||||
|
is_defer: false,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if *is_defer {
|
||||||
|
// defer 语句:提升本模块的 TLA 传递依赖(去重,已提升者不重发)。
|
||||||
|
// 提升模块在导入方 prelude 期启动(TLA 模块挂起返 promise),其
|
||||||
|
// promise 登记进聚合 gate;deferred 模块 prelude 再求值时经
|
||||||
|
// per-module 状态取缓存命名空间,防双求值。
|
||||||
|
//
|
||||||
|
// 传递 TLA 依赖编译在中间模块的 `ctx.nested`,入口侧无直接引用:
|
||||||
|
// 按 path 取图缓存的完整 IR,push 进入口自己的 `ctx.nested` 再发
|
||||||
|
// `CREATE_CLOSURE`(下标为 push 后的 `ctx.nested.len()`)。
|
||||||
|
let tla_modules = graph.gather_tla(&data.path);
|
||||||
|
for tla_path in tla_modules {
|
||||||
|
if !hoisted_tla.insert(tla_path.clone()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let Some(tla_ir) = graph.ir(&tla_path) else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
ctx.nested.push(tla_ir);
|
||||||
|
let tla_fn_reg = ctx.alloc_reg();
|
||||||
|
ctx.inst(Inst::create_closure(Operand::Reg(tla_fn_reg), ctx.nested.len() as u16));
|
||||||
|
let tla_path_reg = self.load_string_const(&tla_path, ctx);
|
||||||
|
let tla_promise = self.emit_module_call(ctx, "__moduleEval", &[tla_fn_reg, tla_path_reg])?;
|
||||||
|
hoisted_tla_promises.push(tla_promise);
|
||||||
|
}
|
||||||
|
if !phase.eager {
|
||||||
|
// defer-only:deferred 模块本身不求值,发 deferred 对象。
|
||||||
|
// path 槽供求值触发点查 per-module 状态(防提升求值后的双求值)。
|
||||||
|
if data.is_self {
|
||||||
|
// 哨兵:模块函数在导入方 prelude 期不可得。
|
||||||
|
let undef = self.emit_undefined(ctx);
|
||||||
|
let path_reg = self.load_string_const(&data.path, ctx);
|
||||||
|
let defer_ns =
|
||||||
|
self.emit_module_call(ctx, "__moduleDeferObject", &[undef, undef, path_reg])?;
|
||||||
|
ctx.module_dep_ns_regs.insert(spec.clone(), defer_ns);
|
||||||
|
ctx.module_defer_ns_regs.insert(spec.clone(), defer_ns);
|
||||||
|
ctx.module_dep_paths.insert(spec.clone(), data.path.clone());
|
||||||
|
} else {
|
||||||
|
let fn_reg = data.fn_reg.expect("非祖先 defer-only 依赖必有闭包寄存器");
|
||||||
|
let undef = self.emit_undefined(ctx);
|
||||||
|
let path_reg = self.load_string_const(&data.path, ctx);
|
||||||
|
let defer_ns =
|
||||||
|
self.emit_module_call(ctx, "__moduleDeferObject", &[fn_reg, undef, path_reg])?;
|
||||||
|
ctx.module_dep_ns_regs.insert(spec.clone(), defer_ns);
|
||||||
|
ctx.module_defer_ns_regs.insert(spec.clone(), defer_ns);
|
||||||
|
ctx.module_dep_paths.insert(spec.clone(), data.path.clone());
|
||||||
|
self.emit_defer_pre_register(ctx, defer_ns, &data.own_names, &data.var_scoped)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// mixed defer 语句:模块本体在其 eager 语句位求值、deferred 对象亦在
|
||||||
|
// eager 语句位发(承载已求值态),此处仅提升 TLA 传递依赖。
|
||||||
|
} else {
|
||||||
|
// eager 语句:求值模块本体(去重,mixed 依赖仅在其 eager 语句位求值一次)。
|
||||||
|
if !evaluated_specs.contains(spec) {
|
||||||
|
let (dep_ns_reg, fn_reg) = if data.is_self {
|
||||||
|
// 自导入:读自身命名空间(依赖即本模块,勿递归)。
|
||||||
|
(ns_reg, None)
|
||||||
|
} else {
|
||||||
|
let fn_reg = data.fn_reg.expect("非自导入 eager 依赖必有闭包寄存器");
|
||||||
|
let path_reg = self.load_string_const(&data.path, ctx);
|
||||||
|
let real_ns = self.emit_module_call(ctx, "__moduleEval", &[fn_reg, path_reg])?;
|
||||||
|
// 异步依赖:`__moduleEval` 返回 capability promise(非命名空间),
|
||||||
|
// 登记进聚合 gate;命名空间在 gate 后从 promise 结算值提取。
|
||||||
|
if data.eval_async {
|
||||||
|
async_dep_promises.push((spec.clone(), real_ns));
|
||||||
|
}
|
||||||
|
(real_ns, Some(fn_reg))
|
||||||
|
};
|
||||||
|
ctx.module_dep_ns_regs.insert(spec.clone(), dep_ns_reg);
|
||||||
|
ctx.module_dep_paths.insert(spec.clone(), data.path.clone());
|
||||||
|
if data.is_self {
|
||||||
|
// 自导入:绑定走别名语义(源导出在 body 执行中才就绪),
|
||||||
|
// 不能像普通依赖那样链接期快照。
|
||||||
|
ctx.module_self_import_specs.insert(spec.clone());
|
||||||
|
}
|
||||||
|
evaluated_specs.insert(spec.clone());
|
||||||
|
if data.is_defer {
|
||||||
|
// mixed 依赖:模块已急切求值,deferred 对象承载已求值态
|
||||||
|
// ([[Evaluated]]=true、[[Namespace]]=真实 ns)。
|
||||||
|
let fn_or_sentinel = if data.is_self {
|
||||||
|
// 自导入 mixed:模块函数在导入方 prelude 期不可得,发哨兵形态。
|
||||||
|
self.emit_undefined(ctx)
|
||||||
|
} else {
|
||||||
|
fn_reg.expect("非自导入 eager 依赖必有闭包寄存器")
|
||||||
|
};
|
||||||
|
let path_reg = self.load_string_const(&data.path, ctx);
|
||||||
|
let defer_ns =
|
||||||
|
self.emit_module_call(ctx, "__moduleDeferObject", &[fn_or_sentinel, dep_ns_reg, path_reg])?;
|
||||||
|
ctx.module_defer_ns_regs.insert(spec.clone(), defer_ns);
|
||||||
|
self.emit_defer_pre_register(ctx, defer_ns, &data.own_names, &data.var_scoped)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 登记本模块图节点:依赖路径集按源序(defer_order)、has_tla 为自身顶层
|
||||||
|
// `await` 标志。
|
||||||
|
let dep_paths_in_source_order: Vec<String> =
|
||||||
|
defer_order.iter().filter_map(|s| dep_data.get(s).map(|d| d.path.clone())).collect();
|
||||||
|
graph.record_module(module_path, dep_paths_in_source_order, own_tla);
|
||||||
|
|
||||||
|
// 本模块异步求值标志:自身含顶层 `await`,或任一 eager 依赖按异步求值
|
||||||
|
// (传递异步经 `dep_eval_async` 递归回传),或存在提升的 TLA 传递依赖
|
||||||
|
// (其 promise 须由聚合 gate 等待)。模块体按合成异步函数编译
|
||||||
|
// (`assemble_ir` 据此回写 IR 的 `is_async`)。非 TLA 模块恒 false,零 diff。
|
||||||
|
ctx.is_async = own_tla || !async_dep_promises.is_empty() || !hoisted_tla_promises.is_empty();
|
||||||
|
|
||||||
|
// —— 聚合 gate:异步依赖与提升 TLA 模块的 `__moduleEval` 返回 capability
|
||||||
|
// promise(非命名空间),其命名空间在 gate 后从结算值提取(仅直接依赖)。
|
||||||
|
// 单 AWAIT 挂起模块体直至全部 promise 结算(由 drain 微任务释放),
|
||||||
|
// 非 TLA 模块此集为空、零 IR 变化。——
|
||||||
|
let all_promises: Vec<u32> =
|
||||||
|
async_dep_promises.iter().map(|(_, r)| *r).chain(hoisted_tla_promises.iter().copied()).collect();
|
||||||
|
if !all_promises.is_empty() {
|
||||||
|
let gate_reg = self.emit_module_call(ctx, "__moduleWaitAll", &all_promises)?;
|
||||||
ctx.inst(Inst::await_expr(Operand::Reg(gate_reg)));
|
ctx.inst(Inst::await_expr(Operand::Reg(gate_reg)));
|
||||||
// promise settle 后恢复值(结算值数组)经 reg 0 交付(与 YIELD/CALL 同协议)。
|
// promise settle 后恢复值(结算值数组)经 reg 0 交付(与 YIELD/CALL 同协议)。
|
||||||
let settled_reg = ctx.alloc_reg();
|
let settled_reg = ctx.alloc_reg();
|
||||||
ctx.inst(Inst::new(OpCode::LOAD_VAR, Operand::Reg(settled_reg), Operand::None, Operand::None));
|
ctx.inst(Inst::new(OpCode::LOAD_VAR, Operand::Reg(settled_reg), Operand::None, Operand::None));
|
||||||
// 逐依赖从结算数组提取命名空间,覆盖链接寄存器(原为 promise)。
|
// 逐直接依赖从结算数组提取命名空间,覆盖链接寄存器(原为 promise);
|
||||||
|
// 提升 TLA 模块非直接依赖,不提取(其命名空间由 per-module 状态承载)。
|
||||||
for (i, (spec, _)) in async_dep_promises.iter().enumerate() {
|
for (i, (spec, _)) in async_dep_promises.iter().enumerate() {
|
||||||
let idx_reg = self.load_string_const(&i.to_string(), ctx);
|
let idx_reg = self.load_string_const(&i.to_string(), ctx);
|
||||||
let ns_reg = ctx.alloc_reg();
|
let ns_reg = ctx.alloc_reg();
|
||||||
@@ -1289,6 +1498,7 @@ impl Emitter {
|
|||||||
#[allow(clippy::type_complexity)]
|
#[allow(clippy::type_complexity)]
|
||||||
fn compile_js_dep(
|
fn compile_js_dep(
|
||||||
&self, resolved: &ResolvedModule, loader: &mut dyn ModuleSourceLoader, path_stack: &mut Vec<String>,
|
&self, resolved: &ResolvedModule, loader: &mut dyn ModuleSourceLoader, path_stack: &mut Vec<String>,
|
||||||
|
graph: &mut ModuleDepGraph,
|
||||||
) -> Result<(IRFunction, bool, HashSet<String>, HashSet<String>, bool), String> {
|
) -> Result<(IRFunction, bool, HashSet<String>, HashSet<String>, bool), String> {
|
||||||
// 线程本地分配器:依赖模块递归解析共享同一分配器,
|
// 线程本地分配器:依赖模块递归解析共享同一分配器,
|
||||||
// 重入深度守卫防止嵌套 reset 销毁外层 AST。
|
// 重入深度守卫防止嵌套 reset 销毁外层 AST。
|
||||||
@@ -1303,13 +1513,19 @@ impl Emitter {
|
|||||||
ctx.is_global_scope = false;
|
ctx.is_global_scope = false;
|
||||||
// 依赖模块经 parse_module 解析,顶层恒严格模式。
|
// 依赖模块经 parse_module 解析,顶层恒严格模式。
|
||||||
ctx.is_strict = true;
|
ctx.is_strict = true;
|
||||||
self.emit_module_into_ctx(&program, &resolved.path, loader, path_stack, &mut ctx, false)?;
|
self.emit_module_into_ctx(&program, &resolved.path, loader, path_stack, &mut ctx, false, graph)?;
|
||||||
let reassignable = ctx.module_live_dep;
|
let reassignable = ctx.module_live_dep;
|
||||||
let eval_async = ctx.is_async;
|
let eval_async = ctx.is_async;
|
||||||
let own_export_names = module_own_export_names(&program.body);
|
let own_export_names = module_own_export_names(&program.body);
|
||||||
let var_scoped = module_var_scoped_export_names(&program.body);
|
let var_scoped = module_var_scoped_export_names(&program.body);
|
||||||
|
let ir = ctx.assemble_ir(ParamLayout { base: 0, count: 0 }, None);
|
||||||
|
// TLA 模块:缓存完整 IR 供导入方提升求值(入口侧 `ctx.nested` 无直接
|
||||||
|
// 引用,须按 path 键取副本)。非 TLA 模块不缓存,零额外开销。
|
||||||
|
if module_has_top_level_await(&program.body) {
|
||||||
|
graph.set_ir(&resolved.path, ir.clone());
|
||||||
|
}
|
||||||
Ok((
|
Ok((
|
||||||
ctx.assemble_ir(ParamLayout { base: 0, count: 0 }, None),
|
ir,
|
||||||
reassignable,
|
reassignable,
|
||||||
own_export_names,
|
own_export_names,
|
||||||
var_scoped,
|
var_scoped,
|
||||||
|
|||||||
@@ -612,3 +612,54 @@ fn extends_await_makes_module_async() {
|
|||||||
"顶层 await 应编译为一条 AWAIT"
|
"顶层 await 应编译为一条 AWAIT"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 面 30:defer-only 依赖含 TLA——TLA 传递依赖提升求值(导入方 prelude 发
|
||||||
|
/// `__moduleEval`),deferred 模块本身不求值;导入方标记异步、发聚合 gate。
|
||||||
|
#[test]
|
||||||
|
fn defer_only_dep_with_tla_hoists_tla_module() {
|
||||||
|
let (ir, _) = emit_module(
|
||||||
|
"import defer * as ns from \"./dep.js\"; ns;",
|
||||||
|
"./entry.js",
|
||||||
|
&[
|
||||||
|
("./dep.js", ModuleKind::Js, "import \"./tla.js\"; export const x = 1;"),
|
||||||
|
("./tla.js", ModuleKind::Js, "const v = await Promise.resolve(1); export { v };"),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
.expect("defer-only 依赖含 TLA 应编译成功");
|
||||||
|
// 入口:1 个提升 TLA 模块(tla)求值一次;deferred 模块(dep)不求值。
|
||||||
|
assert_eq!(native_calls_to(&ir, "__moduleEval"), 1, "提升 TLA 模块应求值一次");
|
||||||
|
assert_eq!(native_calls_to(&ir, "__moduleDeferObject"), 1, "deferred 对象应构造一次");
|
||||||
|
assert!(ir.is_async, "含提升 TLA 模块的导入方应标记异步求值");
|
||||||
|
assert_eq!(native_calls_to(&ir, "__moduleWaitAll"), 1, "聚合 gate 应发一次");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 面 31:defer-only 依赖的传递 TLA——DFS 序收集 TLA 边界模块,提升求值一次。
|
||||||
|
#[test]
|
||||||
|
fn defer_only_dep_with_transitive_tla_hoists_in_dfs_order() {
|
||||||
|
let (ir, _) = emit_module(
|
||||||
|
"import defer * as ns from \"./dep.js\"; ns;",
|
||||||
|
"./entry.js",
|
||||||
|
&[
|
||||||
|
("./dep.js", ModuleKind::Js, "import \"./mid.js\"; export const x = 1;"),
|
||||||
|
("./mid.js", ModuleKind::Js, "import \"./tla.js\"; export const y = 2;"),
|
||||||
|
("./tla.js", ModuleKind::Js, "const v = await Promise.resolve(1); export { v };"),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
.expect("defer-only 依赖含传递 TLA 应编译成功");
|
||||||
|
assert_eq!(native_calls_to(&ir, "__moduleEval"), 1, "传递 TLA 模块应提升求值一次");
|
||||||
|
assert!(ir.is_async, "含传递 TLA 模块的导入方应标记异步求值");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 面 32:defer-only 依赖无 TLA——零提升、零 gate、导入方保持同步(零 diff 守卫)。
|
||||||
|
#[test]
|
||||||
|
fn defer_only_dep_without_tla_no_hoisting() {
|
||||||
|
let (ir, _) = emit_module(
|
||||||
|
"import defer * as ns from \"./dep.js\"; ns;",
|
||||||
|
"./entry.js",
|
||||||
|
&[("./dep.js", ModuleKind::Js, "export const x = 1;")],
|
||||||
|
)
|
||||||
|
.expect("defer-only 依赖无 TLA 应编译成功");
|
||||||
|
assert_eq!(native_calls_to(&ir, "__moduleEval"), 0, "无 TLA 的 defer-only 依赖不得求值");
|
||||||
|
assert_eq!(native_calls_to(&ir, "__moduleWaitAll"), 0, "无 TLA 模块不得发聚合 gate");
|
||||||
|
assert!(!ir.is_async, "无 TLA 模块的导入方不得标记异步");
|
||||||
|
}
|
||||||
|
|||||||
@@ -23,6 +23,16 @@ pub struct ShapeNode {
|
|||||||
pub depth: u32,
|
pub depth: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 模块求值状态(per-module 防双求值):键 = 模块规范路径。
|
||||||
|
///
|
||||||
|
/// `evaluated` 为真时 `namespace` 为已求值命名空间;为假时 `namespace` 承载
|
||||||
|
/// 启动中的 capability promise(TLA 模块挂起未结算),调用方据结算值取命名空间。
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct ModuleEvalState {
|
||||||
|
pub evaluated: bool,
|
||||||
|
pub namespace: JsValue,
|
||||||
|
}
|
||||||
|
|
||||||
/// 内建对象种类:session builtin world 中 builtins 读取的原型与构造器槽位。
|
/// 内建对象种类:session builtin world 中 builtins 读取的原型与构造器槽位。
|
||||||
///
|
///
|
||||||
/// 变体与 builtin world 字段一一对应,仅覆盖 builtins 实际读取的槽位;
|
/// 变体与 builtin world 字段一一对应,仅覆盖 builtins 实际读取的槽位;
|
||||||
@@ -306,6 +316,30 @@ pub trait VmHost {
|
|||||||
|
|
||||||
// 调用基础设施
|
// 调用基础设施
|
||||||
fn call_function_sync(&mut self, callee: JsValue, receiver: JsValue, args: &[JsValue]) -> Result<JsValue, String>;
|
fn call_function_sync(&mut self, callee: JsValue, receiver: JsValue, args: &[JsValue]) -> Result<JsValue, String>;
|
||||||
|
/// 异步模块求值驱动:同步执行模块函数到静止并取结算命名空间。
|
||||||
|
///
|
||||||
|
/// # 步骤
|
||||||
|
/// 1. `call_function_sync(callee)`:TLA 模块返 capability promise(body 同步
|
||||||
|
/// 执行到首个 AWAIT),同步模块返命名空间。
|
||||||
|
/// 2. 返值为 promise 时单次 `drain_microtasks` 排空到静止,取结算值;
|
||||||
|
/// 返值为命名空间时原样返回。
|
||||||
|
///
|
||||||
|
/// # 边界与前提
|
||||||
|
/// - 返值为 promise 且 drain 后仍 pending(宏任务挂起)时返该 promise
|
||||||
|
/// (不阻塞);rejected 时取拒绝原因经 `Err` 上交。
|
||||||
|
///
|
||||||
|
/// # 副作用
|
||||||
|
/// - 可能执行用户模块代码(含分配与 GC);drain 排空微任务队列。
|
||||||
|
fn evaluate_module_async(&mut self, callee: JsValue) -> Result<JsValue, String>;
|
||||||
|
/// 是否原生 Promise 对象(capability promise 判定)。
|
||||||
|
fn is_promise_value(&self, v: JsValue) -> bool;
|
||||||
|
/// 取 promise 结算值:`Some((is_fulfilled, value))`,pending 返 `None`。
|
||||||
|
fn promise_settled_value(&self, promise: JsValue) -> Option<(bool, JsValue)>;
|
||||||
|
/// 读 per-module 求值状态(键 = 模块规范路径):`None` 未求值。
|
||||||
|
fn get_module_eval_state(&self, path: &str) -> Option<ModuleEvalState>;
|
||||||
|
/// 置 per-module 求值状态(键 = 模块规范路径):`evaluated` 为真时
|
||||||
|
/// `namespace` 为命名空间,为假时 `namespace` 承载 capability promise。
|
||||||
|
fn set_module_eval_state(&mut self, path: &str, evaluated: bool, namespace: JsValue);
|
||||||
/// deferred namespace 求值触发(`EnsureDeferredNamespaceEvaluation`):
|
/// deferred namespace 求值触发(`EnsureDeferredNamespaceEvaluation`):
|
||||||
/// 对 deferred 且未求值的 module namespace 同步执行依赖模块函数,缓存结果
|
/// 对 deferred 且未求值的 module namespace 同步执行依赖模块函数,缓存结果
|
||||||
/// 命名空间或失败错误对象。
|
/// 命名空间或失败错误对象。
|
||||||
|
|||||||
@@ -32,5 +32,5 @@ pub use coercion::{
|
|||||||
};
|
};
|
||||||
pub use compiler_service::CompilerService;
|
pub use compiler_service::CompilerService;
|
||||||
pub use event_target::{EventTargetState, ListenerEntry};
|
pub use event_target::{EventTargetState, ListenerEntry};
|
||||||
pub use host::{ProtoKind, ShapeNode, VmHost};
|
pub use host::{ModuleEvalState, ProtoKind, ShapeNode, VmHost};
|
||||||
pub use native_result::NativeResult;
|
pub use native_result::NativeResult;
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ use crate::realm::Realm;
|
|||||||
use crate::vm_debug;
|
use crate::vm_debug;
|
||||||
use crate::vm_state::{IterState, ProfilingState, SampleState};
|
use crate::vm_state::{IterState, ProfilingState, SampleState};
|
||||||
use oxide_kernel::kernel::{KernelCore, KernelSession};
|
use oxide_kernel::kernel::{KernelCore, KernelSession};
|
||||||
|
use oxide_runtime_api::ModuleEvalState;
|
||||||
use oxide_types::error::JsErrorKind;
|
use oxide_types::error::JsErrorKind;
|
||||||
use oxide_types::object::{Cell, JsObject, JsString, NativeFnPtr};
|
use oxide_types::object::{Cell, JsObject, JsString, NativeFnPtr};
|
||||||
use oxide_types::private_key::INT_KEY_COUNT;
|
use oxide_types::private_key::INT_KEY_COUNT;
|
||||||
@@ -314,6 +315,11 @@ pub struct Vm {
|
|||||||
/// 在 `call_function_sync` 前置 `Some(fn)`,两者均 save/restore(嵌套安全)。
|
/// 在 `call_function_sync` 前置 `Some(fn)`,两者均 save/restore(嵌套安全)。
|
||||||
/// 触发点据此判自求值/祖先求值中的 cyclic 并抛 TypeError。
|
/// 触发点据此判自求值/祖先求值中的 cyclic 并抛 TypeError。
|
||||||
pub(crate) evaluating_module: Option<JsValue>,
|
pub(crate) evaluating_module: Option<JsValue>,
|
||||||
|
/// per-module 求值状态(键 = 模块规范路径):防 hoisted TLA 模块与
|
||||||
|
/// deferred 模块 prelude 的双求值。`evaluated` 为真时 `namespace` 为
|
||||||
|
/// 已求值命名空间,为假时 `namespace` 承载启动中的 capability promise。
|
||||||
|
/// 生命周期与 Vm 同消亡:`full_reset` 清空。
|
||||||
|
pub(crate) module_eval_states: std::collections::HashMap<String, ModuleEvalState>,
|
||||||
/// 数组 length define 强转期用户代码抛出的原始异常:与 `last_uncaught_value`
|
/// 数组 length define 强转期用户代码抛出的原始异常:与 `last_uncaught_value`
|
||||||
/// 分离,避免入口误取其它操作忽略调用残留的值。仅 `define_array_length` 写入,
|
/// 分离,避免入口误取其它操作忽略调用残留的值。仅 `define_array_length` 写入,
|
||||||
/// 由 Object/Reflect define 入口消费。
|
/// 由 Object/Reflect define 入口消费。
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ use std::ffi::c_void;
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use oxide_kernel::KernelCore;
|
use oxide_kernel::KernelCore;
|
||||||
use oxide_runtime_api::{ListenerEntry, ProtoKind, ShapeNode};
|
use oxide_runtime_api::{ListenerEntry, ModuleEvalState, ProtoKind, ShapeNode};
|
||||||
use oxide_types::mem::P;
|
use oxide_types::mem::P;
|
||||||
use oxide_types::object::{Cell, JsObject, PropAttributes};
|
use oxide_types::object::{Cell, JsObject, PropAttributes};
|
||||||
use oxide_types::value::JsValue;
|
use oxide_types::value::JsValue;
|
||||||
@@ -262,6 +262,44 @@ impl oxide_runtime_api::VmHost for Vm {
|
|||||||
fn call_function_sync(&mut self, callee: JsValue, receiver: JsValue, args: &[JsValue]) -> Result<JsValue, String> {
|
fn call_function_sync(&mut self, callee: JsValue, receiver: JsValue, args: &[JsValue]) -> Result<JsValue, String> {
|
||||||
self.call_function_sync(callee, receiver, args)
|
self.call_function_sync(callee, receiver, args)
|
||||||
}
|
}
|
||||||
|
fn evaluate_module_async(&mut self, callee: JsValue) -> Result<JsValue, String> {
|
||||||
|
// 同步执行模块函数到首个挂起点:TLA 模块返 capability promise,同步模块返命名空间。
|
||||||
|
let result = self.call_function_sync(callee, JsValue::undefined(), &[])?;
|
||||||
|
// 返值为 promise(TLA 模块):单次 drain 排空到静止,取结算值。
|
||||||
|
if self.is_promise_value(result) {
|
||||||
|
self.drain_microtasks();
|
||||||
|
let obj = unsafe { &*result.as_js_object_ptr() };
|
||||||
|
return match crate::promise::promise_settled_value(obj) {
|
||||||
|
Some((true, value)) => Ok(value),
|
||||||
|
Some((false, reason)) => Err(self.error_text(reason)),
|
||||||
|
// 宏任务挂起(drain 后仍 pending):返 capability promise,不阻塞。
|
||||||
|
None => Ok(result),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// 同步模块:命名空间原样返回。
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
fn is_promise_value(&self, v: JsValue) -> bool {
|
||||||
|
self.is_promise_value(v)
|
||||||
|
}
|
||||||
|
fn promise_settled_value(&self, promise: JsValue) -> Option<(bool, JsValue)> {
|
||||||
|
if !promise.is_object() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let ptr = promise.as_js_object_ptr();
|
||||||
|
if ptr.is_null() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let obj = unsafe { &*ptr };
|
||||||
|
crate::promise::promise_settled_value(obj)
|
||||||
|
}
|
||||||
|
fn get_module_eval_state(&self, path: &str) -> Option<ModuleEvalState> {
|
||||||
|
self.module_eval_states.get(path).cloned()
|
||||||
|
}
|
||||||
|
fn set_module_eval_state(&mut self, path: &str, evaluated: bool, namespace: JsValue) {
|
||||||
|
self.module_eval_states
|
||||||
|
.insert(path.to_string(), ModuleEvalState { evaluated, namespace });
|
||||||
|
}
|
||||||
fn ensure_deferred_ns_evaluation(&mut self, obj: &JsObject, key_si: Option<u32>) -> Result<(), String> {
|
fn ensure_deferred_ns_evaluation(&mut self, obj: &JsObject, key_si: Option<u32>) -> Result<(), String> {
|
||||||
// 非 deferred module namespace 直接 no-op(热路径零成本)。
|
// 非 deferred module namespace 直接 no-op(热路径零成本)。
|
||||||
if !obj.is_module_namespace() || !obj.is_deferred() {
|
if !obj.is_module_namespace() || !obj.is_deferred() {
|
||||||
@@ -303,8 +341,24 @@ impl oxide_runtime_api::VmHost for Vm {
|
|||||||
if self.evaluating_module == Some(state.module) {
|
if self.evaluating_module == Some(state.module) {
|
||||||
return Err(self.error_message_text("TypeError", "cyclic module evaluation"));
|
return Err(self.error_message_text("TypeError", "cyclic module evaluation"));
|
||||||
}
|
}
|
||||||
// EvaluateSync:调依赖模块函数,缓存结果命名空间或失败错误。
|
// 提升求值过的 TLA 模块:per-module 状态已结算(或结算中),直接取缓存
|
||||||
match self.call_function_sync(state.module, JsValue::undefined(), &[]) {
|
// 命名空间,防 `evaluate_module_async` 重跑模块函数(双求值)。
|
||||||
|
if let Some(ms) = self.get_module_eval_state(&state.path) {
|
||||||
|
if ms.evaluated {
|
||||||
|
state.namespace = ms.namespace;
|
||||||
|
state.evaluated = true;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
if let Some((true, value)) = self.promise_settled_value(ms.namespace) {
|
||||||
|
self.set_module_eval_state(&state.path, true, value);
|
||||||
|
state.namespace = value;
|
||||||
|
state.evaluated = true;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
// pending 且未结算:落入下方正常求值(聚合 gate 后不应发生,兜底)。
|
||||||
|
}
|
||||||
|
// EvaluateSync:调依赖模块函数(异步驱动到静止),缓存结果命名空间或失败错误。
|
||||||
|
match self.evaluate_module_async(state.module) {
|
||||||
Ok(ns) => {
|
Ok(ns) => {
|
||||||
state.namespace = ns;
|
state.namespace = ns;
|
||||||
state.evaluated = true;
|
state.evaluated = true;
|
||||||
|
|||||||
@@ -2049,7 +2049,9 @@ mod tests {
|
|||||||
fn make_deferred_ns(vm: &mut Vm, fn_val: JsValue) -> JsValue {
|
fn make_deferred_ns(vm: &mut Vm, fn_val: JsValue) -> JsValue {
|
||||||
vm.set_reg(1, fn_val);
|
vm.set_reg(1, fn_val);
|
||||||
vm.set_reg(2, JsValue::undefined());
|
vm.set_reg(2, JsValue::undefined());
|
||||||
oxide_builtins::module::module_defer_object(vm, &[0, 1, 2]).unwrap()
|
let path_str = vm.new_string("p");
|
||||||
|
vm.set_reg(3, path_str);
|
||||||
|
oxide_builtins::module::module_defer_object(vm, &[0, 1, 2, 3]).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -2077,7 +2079,9 @@ mod tests {
|
|||||||
// 哨兵形态:[[Module]] = undefined(自导入/祖先 defer)。
|
// 哨兵形态:[[Module]] = undefined(自导入/祖先 defer)。
|
||||||
vm.set_reg(1, JsValue::undefined());
|
vm.set_reg(1, JsValue::undefined());
|
||||||
vm.set_reg(2, JsValue::undefined());
|
vm.set_reg(2, JsValue::undefined());
|
||||||
let ns_val = oxide_builtins::module::module_defer_object(&mut vm, &[0, 1, 2]).unwrap();
|
let path_str = vm.new_string("p");
|
||||||
|
vm.set_reg(3, path_str);
|
||||||
|
let ns_val = oxide_builtins::module::module_defer_object(&mut vm, &[0, 1, 2, 3]).unwrap();
|
||||||
let ns_ptr = ns_val.as_js_object_ptr();
|
let ns_ptr = ns_val.as_js_object_ptr();
|
||||||
|
|
||||||
// 模拟「正在求值模块」:置 cyclic 守卫标记。
|
// 模拟「正在求值模块」:置 cyclic 守卫标记。
|
||||||
@@ -2099,7 +2103,9 @@ mod tests {
|
|||||||
.expect("create function");
|
.expect("create function");
|
||||||
vm.set_reg(1, throwing_fn);
|
vm.set_reg(1, throwing_fn);
|
||||||
vm.set_reg(2, JsValue::undefined());
|
vm.set_reg(2, JsValue::undefined());
|
||||||
let ns_val = oxide_builtins::module::module_defer_object(&mut vm, &[0, 1, 2]).unwrap();
|
let path_str = vm.new_string("p");
|
||||||
|
vm.set_reg(3, path_str);
|
||||||
|
let ns_val = oxide_builtins::module::module_defer_object(&mut vm, &[0, 1, 2, 3]).unwrap();
|
||||||
let ns_ptr = ns_val.as_js_object_ptr();
|
let ns_ptr = ns_val.as_js_object_ptr();
|
||||||
let x_si = vm.kernel_core.perm_interner().intern("x").0;
|
let x_si = vm.kernel_core.perm_interner().intern("x").0;
|
||||||
|
|
||||||
|
|||||||
@@ -195,6 +195,7 @@ impl Vm {
|
|||||||
exception_value: None,
|
exception_value: None,
|
||||||
last_uncaught_value: None,
|
last_uncaught_value: None,
|
||||||
evaluating_module: None,
|
evaluating_module: None,
|
||||||
|
module_eval_states: std::collections::HashMap::new(),
|
||||||
pending_length_exception: None,
|
pending_length_exception: None,
|
||||||
pending_exception: None,
|
pending_exception: None,
|
||||||
pending_error_kind: None,
|
pending_error_kind: None,
|
||||||
@@ -363,6 +364,7 @@ impl Vm {
|
|||||||
exception_value: None,
|
exception_value: None,
|
||||||
last_uncaught_value: None,
|
last_uncaught_value: None,
|
||||||
evaluating_module: None,
|
evaluating_module: None,
|
||||||
|
module_eval_states: std::collections::HashMap::new(),
|
||||||
pending_length_exception: None,
|
pending_length_exception: None,
|
||||||
pending_exception: None,
|
pending_exception: None,
|
||||||
pending_error_kind: None,
|
pending_error_kind: None,
|
||||||
@@ -605,6 +607,9 @@ impl Vm {
|
|||||||
// 池回收后残留将悬垂。
|
// 池回收后残留将悬垂。
|
||||||
self.last_uncaught_value = None;
|
self.last_uncaught_value = None;
|
||||||
self.pending_length_exception = None;
|
self.pending_length_exception = None;
|
||||||
|
// per-module 求值状态持 session 对象指针(命名空间/promise):执行期状态,
|
||||||
|
// 跨 run/reset 不保留,残留将悬垂。
|
||||||
|
self.module_eval_states.clear();
|
||||||
self.pending_exception = None;
|
self.pending_exception = None;
|
||||||
self.pending_error_kind = None;
|
self.pending_error_kind = None;
|
||||||
self.pending_completion = None;
|
self.pending_completion = None;
|
||||||
|
|||||||
Reference in New Issue
Block a user