feat: import defer 的 TLA 传递依赖按规范序提升求值

This commit is contained in:
2026-10-14 05:16:34 +00:00
parent 2e0197486c
commit 43f15ad2ee
11 changed files with 555 additions and 117 deletions
Generated
+21 -21
View File
@@ -1160,7 +1160,7 @@ dependencies = [
[[package]]
name = "oxide_builtins"
version = "0.18.9"
version = "0.19.1"
dependencies = [
"chrono",
"fast-float",
@@ -1185,7 +1185,7 @@ dependencies = [
[[package]]
name = "oxide_bytecode"
version = "0.18.9"
version = "0.19.1"
dependencies = [
"num-bigint",
"oxide_log",
@@ -1193,7 +1193,7 @@ dependencies = [
[[package]]
name = "oxide_cfg"
version = "0.18.9"
version = "0.19.1"
dependencies = [
"oxide_bytecode",
"oxide_emit",
@@ -1204,7 +1204,7 @@ dependencies = [
[[package]]
name = "oxide_cli"
version = "0.18.9"
version = "0.19.1"
dependencies = [
"ansi_term",
"bumpalo",
@@ -1228,7 +1228,7 @@ dependencies = [
[[package]]
name = "oxide_code_cache"
version = "0.18.9"
version = "0.19.1"
dependencies = [
"lru",
"oxide_bytecode",
@@ -1237,7 +1237,7 @@ dependencies = [
[[package]]
name = "oxide_compiler"
version = "0.18.9"
version = "0.19.1"
dependencies = [
"oxide_bytecode",
"oxide_cfg",
@@ -1258,7 +1258,7 @@ dependencies = [
[[package]]
name = "oxide_dce"
version = "0.18.9"
version = "0.19.1"
dependencies = [
"oxide_bytecode",
"oxide_cfg",
@@ -1272,7 +1272,7 @@ dependencies = [
[[package]]
name = "oxide_emit"
version = "0.18.9"
version = "0.19.1"
dependencies = [
"num-bigint",
"oxc_allocator",
@@ -1288,7 +1288,7 @@ dependencies = [
[[package]]
name = "oxide_engine"
version = "0.18.9"
version = "0.19.1"
dependencies = [
"oxide_bytecode",
"oxide_compiler",
@@ -1300,7 +1300,7 @@ dependencies = [
[[package]]
name = "oxide_fold"
version = "0.18.9"
version = "0.19.1"
dependencies = [
"num-bigint",
"oxide_bytecode",
@@ -1312,7 +1312,7 @@ dependencies = [
[[package]]
name = "oxide_ir"
version = "0.18.9"
version = "0.19.1"
dependencies = [
"oxide_bytecode",
"oxide_log",
@@ -1321,7 +1321,7 @@ dependencies = [
[[package]]
name = "oxide_kernel"
version = "0.18.9"
version = "0.19.1"
dependencies = [
"bumpalo",
"dashmap",
@@ -1335,7 +1335,7 @@ dependencies = [
[[package]]
name = "oxide_liveness"
version = "0.18.9"
version = "0.19.1"
dependencies = [
"oxide_bytecode",
"oxide_cfg",
@@ -1347,7 +1347,7 @@ dependencies = [
[[package]]
name = "oxide_log"
version = "0.18.9"
version = "0.19.1"
dependencies = [
"tracing",
"tracing-appender",
@@ -1356,11 +1356,11 @@ dependencies = [
[[package]]
name = "oxide_net"
version = "0.18.9"
version = "0.19.1"
[[package]]
name = "oxide_parser"
version = "0.18.9"
version = "0.19.1"
dependencies = [
"oxc_allocator",
"oxc_ast",
@@ -1375,7 +1375,7 @@ dependencies = [
[[package]]
name = "oxide_regalloc"
version = "0.18.9"
version = "0.19.1"
dependencies = [
"oxide_bytecode",
"oxide_cfg",
@@ -1391,7 +1391,7 @@ dependencies = [
[[package]]
name = "oxide_runtime_api"
version = "0.18.9"
version = "0.19.1"
dependencies = [
"num-bigint",
"num-traits",
@@ -1404,7 +1404,7 @@ dependencies = [
[[package]]
name = "oxide_test262"
version = "0.18.9"
version = "0.19.1"
dependencies = [
"oxide_bytecode",
"oxide_compiler",
@@ -1424,7 +1424,7 @@ dependencies = [
[[package]]
name = "oxide_types"
version = "0.18.9"
version = "0.19.1"
dependencies = [
"bumpalo",
"dashmap",
@@ -1437,7 +1437,7 @@ dependencies = [
[[package]]
name = "oxide_vm"
version = "0.18.9"
version = "0.19.1"
dependencies = [
"bumpalo",
"chrono",
+1 -1
View File
@@ -25,7 +25,7 @@ members = [
]
[workspace.package]
version = "0.19.0"
version = "0.19.1"
edition = "2021"
license = "MIT"
rust-version = "1.80"
+85 -19
View File
@@ -7,7 +7,7 @@
//! source-phase / defer 语义留待后续轮次。
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::private_key::encode_symbol_key;
use oxide_types::value::JsValue;
@@ -78,6 +78,9 @@ pub struct DeferredNsState {
/// 求值失败时缓存的原始错误值(再读再抛同一错误对象,保身份);
/// 成功求值与求值前恒 `None`。
pub error: Option<JsValue>,
/// 依赖模块规范路径:求值触发点据此查 per-module 状态(提升求值过的 TLA
/// 模块已结算,直接取缓存命名空间,防双求值)。
pub path: String,
}
/// 模块命名空间条目表:挂在 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)
}
/// `__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,嵌套
/// `__moduleEval` 安全):deferred namespace 求值触发的 cyclic 守卫据此判自求值。
/// - 写 per-module 状态(键 = path)。
pub fn module_eval<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
if args.len() < 2 {
return type_error(vm, "__moduleEval: 1 argument required");
if args.len() < 3 {
return type_error(vm, "__moduleEval: 2 arguments required");
}
let fn_val = vm.reg(args[1]);
let path_val = vm.reg(args[2]);
if !fn_val.is_object() {
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() } {
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();
vm.set_evaluating_module(Some(fn_val));
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)),
};
vm.set_evaluating_module(saved);
result
}
/// `__moduleDeferObject(fn, real_ns)`:创建 deferred namespace 对象(`import defer * as` 产物)。
/// `__moduleDeferObject(fn, real_ns, path)`:创建 deferred namespace 对象
/// (`import defer * as` 产物)。
///
/// # 步骤
/// 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"(不可写不可枚举不可配置)。
/// 3. 置 module namespace + deferred 双标志,置 non-extensible。
/// 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`);
/// 状态盒三内部槽由本入口唯一安装。
/// 状态盒内部槽由本入口唯一安装。
pub fn module_defer_object<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
if args.len() < 3 {
return type_error(vm, "__moduleDeferObject: 2 arguments required");
if args.len() < 4 {
return type_error(vm, "__moduleDeferObject: 3 arguments required");
}
let fn_val = vm.reg(args[1]);
let ns_val = vm.reg(args[2]);
let path = to_string(vm.reg(args[3]));
// fn 为函数或 undefined(哨兵);其余抛 TypeError。
let fn_is_function = fn_val.is_object() && {
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(),
namespace: ns_val,
error: None,
path,
});
}
NativeResult::Ok(JsValue::from_js_object(obj))
@@ -1044,7 +1092,9 @@ mod tests {
let (mut vm, fn_val) = vm_with_function();
vm.set_reg(1, fn_val);
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());
let ns_ptr = ns_val.as_js_object_ptr();
assert!(!ns_ptr.is_null());
@@ -1068,7 +1118,9 @@ mod tests {
let ns_val = JsValue::from_js_object(real_ns);
vm.set_reg(1, fn_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 state = deferred_state(ns_obj).expect("deferred state 应已安装");
assert_eq!(state.module, fn_val, "[[Module]] 应存依赖模块函数");
@@ -1082,7 +1134,9 @@ mod tests {
// 哨兵形态:fn 与 real_ns 均为 undefined(自导入/祖先 defer)。
vm.set_reg(1, 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 state = deferred_state(ns_obj).expect("deferred state 应已安装");
assert_eq!(state.module, JsValue::undefined(), "哨兵 [[Module]] 应为 undefined");
@@ -1095,7 +1149,9 @@ mod tests {
let (mut vm, _) = vm_with_function();
vm.set_reg(1, JsValue::int(42));
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");
}
@@ -1104,7 +1160,9 @@ mod tests {
let (mut vm, fn_val) = vm_with_function();
vm.set_reg(1, fn_val);
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");
}
@@ -1116,7 +1174,9 @@ mod tests {
// 创建 deferred ns(持有 fn);fn + ns 两个 session 对象。
vm.set_reg(1, fn_val);
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();
// 仅 ns 为根:清掉持有 fn 的寄存器,fn 唯一可达路径是 ns 的 [[Module]] 边。
@@ -1143,7 +1203,9 @@ mod tests {
// 创建 deferred ns(哨兵形态)。
vm.set_reg(1, 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 字段(模拟失败缓存),置已求值。
{
@@ -1177,7 +1239,9 @@ mod tests {
// 模块函数返回非对象(42):求值成功后 [[Namespace]] 为非对象值。
vm.set_reg(1, fn_val);
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();
// 模拟求值完成:[[Evaluated]] 置真、[[Namespace]] 为非对象值 42。
@@ -1205,7 +1269,9 @@ mod tests {
let real_ns_val = JsValue::from_js_object(real_ns);
vm.set_reg(1, fn_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();
// 权威读目标返回真实 ns(活值与真实槽位在真实 ns 条目表)。
+285 -69
View File
@@ -59,6 +59,74 @@ struct DepPhase {
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)提供文件解析。
pub trait ModuleSourceLoader {
/// 解析依赖模块:按 `base_dir` 与 `specifier` 定位模块源码,`attributes` 为
@@ -716,7 +784,8 @@ impl Emitter {
// ES module 顶层恒严格模式(模块代码是严格模式代码,嵌套函数经父 ctx 继承)。
ctx.is_strict = true;
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))
}
@@ -727,7 +796,7 @@ impl Emitter {
#[allow(clippy::too_many_arguments)]
fn emit_module_into_ctx(
&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> {
let body = &program.body;
@@ -755,9 +824,9 @@ impl Emitter {
ctx.module_ns_reg = Some(ns_reg);
// —— 依赖收集(import + re-export/star 的 source,按首次出现去重,记 phase)——
// eager_order 为各 spec 首个 eager 语句的出现序(求值序);defer_order 为各 spec
// 首次出现序(defer-only 组发射序)。无 defer 的模块两序与首次出现序恒等,
// 发射产物与现态逐字节一致。
// eager_order 为各 spec 首个 eager 语句的出现序(编译序);defer_order 为各
// spec 首次出现序(求值发射序,evaluationList 序)。无 defer 的模块两序与
// 首次出现序恒等,发射产物与现态逐字节一致。
let base_dir = Path::new(module_path)
.parent()
.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 eager_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 {
let (spec, attrs, is_defer) = match stmt {
Statement::ImportDeclaration(imp) => {
@@ -783,6 +856,7 @@ impl Emitter {
}
_ => continue,
};
stmt_order.push((spec.clone(), is_defer));
let is_new = !phase_map.contains_key(&spec);
let entry = phase_map.entry(spec.clone()).or_insert_with(|| DepPhase {
eager: false,
@@ -811,23 +885,39 @@ impl Emitter {
// 异步 eager 依赖的 (spec, `__moduleEval` 返回的 promise 寄存器):prelude
// 聚合 gate 消费。defer-only 依赖不求值、不产生 promise,不入此集。
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 {
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 resolved = loader.resolve(&base_dir, &spec, &attr_refs)?;
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 {
if path_stack.contains(&resolved.path) {
return Err(format!("circular module import not supported: {}", resolved.path));
}
path_stack.push(resolved.path.clone());
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 => (
self.compile_data_dep("json", &resolved.source)?,
false,
@@ -849,65 +939,51 @@ impl Emitter {
ctx.module_dep_reassignable.insert(spec.clone(), dep_reassignable);
let fn_reg = ctx.alloc_reg();
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])?;
// 异步依赖:`__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)
(Some(fn_reg), dep_eval_async, dep_own_names, dep_var_scoped)
};
ctx.module_dep_ns_regs.insert(spec.clone(), dep_ns_reg);
ctx.module_dep_paths.insert(spec.clone(), resolved.path.clone());
if is_self {
// 自导入:绑定走别名语义(源导出在 body 执行中才就绪),
// 不能像普通依赖那样链接期快照。
ctx.module_self_import_specs.insert(spec.clone());
}
if phase.defer {
// mixed 依赖:模块已急切求值,deferred 对象承载已求值态
// ([[Evaluated]]=true、[[Namespace]]=真实 ns)。
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)?;
}
dep_data.insert(
spec.clone(),
DepEmitData {
fn_reg,
own_names: dep_own_names,
var_scoped: dep_var_scoped,
eval_async: dep_eval_async,
path: resolved.path,
is_self,
is_defer: phase.defer,
},
);
}
// 本模块异步求值标志:自身含顶层 `await`,或任一 eager 依赖按异步求值
// (传递异步经 `dep_eval_async` 递归回传),模块体按合成异步函数编译
// (`assemble_ir` 据此回写 IR 的 `is_async`)。非 TLA 模块恒 false,零 diff。
ctx.is_async = own_tla || !async_dep_promises.is_empty();
// 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];
// defer-only 组(eager == false 的 spec,按 defer_order):编译入子模块树、
// 发 CREATE_CLOSURE,求值发射推迟到阶段二。
for spec in &defer_order {
let phase = &phase_map[spec];
if phase.eager {
continue;
}
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);
if is_ancestor {
// 哨兵:模块函数在导入方 prelude 期不可得(自导入是自身、祖先是
// 父链),defer 回边在导入图上成环,编译期不得报循环。
let undef = self.emit_undefined(ctx);
let defer_ns = self.emit_module_call(ctx, "__moduleDeferObject", &[undef, undef])?;
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(), resolved.path.clone());
dep_data.insert(
spec.clone(),
DepEmitData {
fn_reg: None,
own_names: HashSet::new(),
var_scoped: HashSet::new(),
eval_async: false,
path: resolved.path,
is_self: true,
is_defer: true,
},
);
} else {
path_stack.push(resolved.path.clone());
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 => (
self.compile_data_dep("json", &resolved.source)?,
false,
@@ -928,26 +1004,159 @@ impl Emitter {
ctx.nested.push(dep_ir);
let fn_reg = ctx.alloc_reg();
ctx.inst(Inst::create_closure(Operand::Reg(fn_reg), ctx.nested.len() as u16));
let undef = self.emit_undefined(ctx);
let defer_ns = self.emit_module_call(ctx, "__moduleDeferObject", &[fn_reg, undef])?;
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(), resolved.path.clone());
self.emit_defer_pre_register(ctx, defer_ns, &dep_own_names, &dep_var_scoped)?;
dep_data.insert(
spec.clone(),
DepEmitData {
fn_reg: Some(fn_reg),
own_names: dep_own_names,
var_scoped: dep_var_scoped,
eval_async: false,
path: resolved.path,
is_self: false,
is_defer: true,
},
);
}
}
// —— 聚合 gate:异步依赖的 `__moduleEval` 返回 capability promise(非命名空间),
// 其命名空间在 gate 后从结算值提取。单 AWAIT 挂起模块体直至全部异步依赖结算
// (由 drain 微任务释放),非 TLA 模块此集为空、零 IR 变化。——
if !async_dep_promises.is_empty() {
let promise_regs: Vec<u32> = async_dep_promises.iter().map(|(_, r)| *r).collect();
let gate_reg = self.emit_module_call(ctx, "__moduleWaitAll", &promise_regs)?;
// —— 阶段二:按 evaluationList 序(语句源位交错)发射求值——每条语句按源位
// 贡献:defer 语句提升其 TLA 传递依赖、eager 语句求值模块本体(去重,mixed
// 依赖的求值点落在其 eager 语句位而非首次出现位)。——
let mut evaluated_specs: HashSet<String> = HashSet::new();
let mut hoisted_tla: HashSet<String> = HashSet::new();
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)));
// promise settle 后恢复值(结算值数组)经 reg 0 交付(与 YIELD/CALL 同协议)。
let settled_reg = ctx.alloc_reg();
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() {
let idx_reg = self.load_string_const(&i.to_string(), ctx);
let ns_reg = ctx.alloc_reg();
@@ -1289,6 +1498,7 @@ impl Emitter {
#[allow(clippy::type_complexity)]
fn compile_js_dep(
&self, resolved: &ResolvedModule, loader: &mut dyn ModuleSourceLoader, path_stack: &mut Vec<String>,
graph: &mut ModuleDepGraph,
) -> Result<(IRFunction, bool, HashSet<String>, HashSet<String>, bool), String> {
// 线程本地分配器:依赖模块递归解析共享同一分配器,
// 重入深度守卫防止嵌套 reset 销毁外层 AST。
@@ -1303,13 +1513,19 @@ impl Emitter {
ctx.is_global_scope = false;
// 依赖模块经 parse_module 解析,顶层恒严格模式。
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 eval_async = ctx.is_async;
let own_export_names = module_own_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((
ctx.assemble_ir(ParamLayout { base: 0, count: 0 }, None),
ir,
reassignable,
own_export_names,
var_scoped,
@@ -612,3 +612,54 @@ fn extends_await_makes_module_async() {
"顶层 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 模块的导入方不得标记异步");
}
+34
View File
@@ -23,6 +23,16 @@ pub struct ShapeNode {
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 读取的原型与构造器槽位。
///
/// 变体与 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>;
/// 异步模块求值驱动:同步执行模块函数到静止并取结算命名空间。
///
/// # 步骤
/// 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 且未求值的 module namespace 同步执行依赖模块函数,缓存结果
/// 命名空间或失败错误对象。
+1 -1
View File
@@ -32,5 +32,5 @@ pub use coercion::{
};
pub use compiler_service::CompilerService;
pub use event_target::{EventTargetState, ListenerEntry};
pub use host::{ProtoKind, ShapeNode, VmHost};
pub use host::{ModuleEvalState, ProtoKind, ShapeNode, VmHost};
pub use native_result::NativeResult;
+6
View File
@@ -20,6 +20,7 @@ use crate::realm::Realm;
use crate::vm_debug;
use crate::vm_state::{IterState, ProfilingState, SampleState};
use oxide_kernel::kernel::{KernelCore, KernelSession};
use oxide_runtime_api::ModuleEvalState;
use oxide_types::error::JsErrorKind;
use oxide_types::object::{Cell, JsObject, JsString, NativeFnPtr};
use oxide_types::private_key::INT_KEY_COUNT;
@@ -314,6 +315,11 @@ pub struct Vm {
/// 在 `call_function_sync` 前置 `Some(fn)`,两者均 save/restore(嵌套安全)。
/// 触发点据此判自求值/祖先求值中的 cyclic 并抛 TypeError。
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`
/// 分离,避免入口误取其它操作忽略调用残留的值。仅 `define_array_length` 写入,
/// 由 Object/Reflect define 入口消费。
+57 -3
View File
@@ -4,7 +4,7 @@ use std::ffi::c_void;
use std::sync::Arc;
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::object::{Cell, JsObject, PropAttributes};
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> {
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> {
// 非 deferred module namespace 直接 no-op(热路径零成本)。
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) {
return Err(self.error_message_text("TypeError", "cyclic module evaluation"));
}
// EvaluateSync:调依赖模块函数,缓存结果命名空间或失败错误。
match self.call_function_sync(state.module, JsValue::undefined(), &[]) {
// 提升求值过的 TLA 模块:per-module 状态已结算(或结算中),直接取缓存
// 命名空间,防 `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) => {
state.namespace = ns;
state.evaluated = true;
+9 -3
View File
@@ -2049,7 +2049,9 @@ mod tests {
fn make_deferred_ns(vm: &mut Vm, fn_val: JsValue) -> JsValue {
vm.set_reg(1, fn_val);
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]
@@ -2077,7 +2079,9 @@ mod tests {
// 哨兵形态:[[Module]] = undefined(自导入/祖先 defer)。
vm.set_reg(1, 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();
// 模拟「正在求值模块」:置 cyclic 守卫标记。
@@ -2099,7 +2103,9 @@ mod tests {
.expect("create function");
vm.set_reg(1, throwing_fn);
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 x_si = vm.kernel_core.perm_interner().intern("x").0;
+5
View File
@@ -195,6 +195,7 @@ impl Vm {
exception_value: None,
last_uncaught_value: None,
evaluating_module: None,
module_eval_states: std::collections::HashMap::new(),
pending_length_exception: None,
pending_exception: None,
pending_error_kind: None,
@@ -363,6 +364,7 @@ impl Vm {
exception_value: None,
last_uncaught_value: None,
evaluating_module: None,
module_eval_states: std::collections::HashMap::new(),
pending_length_exception: None,
pending_exception: None,
pending_error_kind: None,
@@ -605,6 +607,9 @@ impl Vm {
// 池回收后残留将悬垂。
self.last_uncaught_value = None;
self.pending_length_exception = None;
// per-module 求值状态持 session 对象指针(命名空间/promise):执行期状态,
// 跨 run/reset 不保留,残留将悬垂。
self.module_eval_states.clear();
self.pending_exception = None;
self.pending_error_kind = None;
self.pending_completion = None;