feat: defer 依赖不发 __moduleEval,构造 deferred 对象并逐名预注册

This commit is contained in:
2026-10-09 13:10:22 +00:00
parent 64c5fcbb1e
commit 7900bb92e6
7 changed files with 389 additions and 74 deletions
Generated
+19 -19
View File
@@ -1160,7 +1160,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_builtins" name = "oxide_builtins"
version = "0.8.104" version = "0.8.105"
dependencies = [ dependencies = [
"chrono", "chrono",
"fast-float", "fast-float",
@@ -1185,7 +1185,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_bytecode" name = "oxide_bytecode"
version = "0.8.104" version = "0.8.105"
dependencies = [ dependencies = [
"num-bigint", "num-bigint",
"oxide_log", "oxide_log",
@@ -1193,7 +1193,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_cfg" name = "oxide_cfg"
version = "0.8.104" version = "0.8.105"
dependencies = [ dependencies = [
"oxide_bytecode", "oxide_bytecode",
"oxide_emit", "oxide_emit",
@@ -1204,7 +1204,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_cli" name = "oxide_cli"
version = "0.8.104" version = "0.8.105"
dependencies = [ dependencies = [
"ansi_term", "ansi_term",
"bumpalo", "bumpalo",
@@ -1226,7 +1226,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_code_cache" name = "oxide_code_cache"
version = "0.8.104" version = "0.8.105"
dependencies = [ dependencies = [
"lru", "lru",
"oxide_bytecode", "oxide_bytecode",
@@ -1235,7 +1235,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_compiler" name = "oxide_compiler"
version = "0.8.104" version = "0.8.105"
dependencies = [ dependencies = [
"oxide_bytecode", "oxide_bytecode",
"oxide_cfg", "oxide_cfg",
@@ -1255,7 +1255,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_dce" name = "oxide_dce"
version = "0.8.104" version = "0.8.105"
dependencies = [ dependencies = [
"oxide_bytecode", "oxide_bytecode",
"oxide_cfg", "oxide_cfg",
@@ -1269,7 +1269,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_emit" name = "oxide_emit"
version = "0.8.104" version = "0.8.105"
dependencies = [ dependencies = [
"num-bigint", "num-bigint",
"oxc_allocator", "oxc_allocator",
@@ -1284,7 +1284,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_engine" name = "oxide_engine"
version = "0.8.104" version = "0.8.105"
dependencies = [ dependencies = [
"oxide_bytecode", "oxide_bytecode",
"oxide_compiler", "oxide_compiler",
@@ -1296,7 +1296,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_ir" name = "oxide_ir"
version = "0.8.104" version = "0.8.105"
dependencies = [ dependencies = [
"oxide_bytecode", "oxide_bytecode",
"oxide_log", "oxide_log",
@@ -1305,7 +1305,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_kernel" name = "oxide_kernel"
version = "0.8.104" version = "0.8.105"
dependencies = [ dependencies = [
"bumpalo", "bumpalo",
"dashmap", "dashmap",
@@ -1319,7 +1319,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_liveness" name = "oxide_liveness"
version = "0.8.104" version = "0.8.105"
dependencies = [ dependencies = [
"oxide_bytecode", "oxide_bytecode",
"oxide_cfg", "oxide_cfg",
@@ -1331,7 +1331,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_log" name = "oxide_log"
version = "0.8.104" version = "0.8.105"
dependencies = [ dependencies = [
"tracing", "tracing",
"tracing-appender", "tracing-appender",
@@ -1340,7 +1340,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_parser" name = "oxide_parser"
version = "0.8.104" version = "0.8.105"
dependencies = [ dependencies = [
"oxc_allocator", "oxc_allocator",
"oxc_ast", "oxc_ast",
@@ -1355,7 +1355,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_regalloc" name = "oxide_regalloc"
version = "0.8.104" version = "0.8.105"
dependencies = [ dependencies = [
"oxide_bytecode", "oxide_bytecode",
"oxide_cfg", "oxide_cfg",
@@ -1371,7 +1371,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_runtime_api" name = "oxide_runtime_api"
version = "0.8.104" version = "0.8.105"
dependencies = [ dependencies = [
"num-bigint", "num-bigint",
"num-traits", "num-traits",
@@ -1384,7 +1384,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_test262" name = "oxide_test262"
version = "0.8.104" version = "0.8.105"
dependencies = [ dependencies = [
"oxide_bytecode", "oxide_bytecode",
"oxide_compiler", "oxide_compiler",
@@ -1402,7 +1402,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_types" name = "oxide_types"
version = "0.8.104" version = "0.8.105"
dependencies = [ dependencies = [
"bumpalo", "bumpalo",
"dashmap", "dashmap",
@@ -1415,7 +1415,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_vm" name = "oxide_vm"
version = "0.8.104" version = "0.8.105"
dependencies = [ dependencies = [
"bumpalo", "bumpalo",
"chrono", "chrono",
+1 -1
View File
@@ -23,7 +23,7 @@ members = [
] ]
[workspace.package] [workspace.package]
version = "0.8.104" version = "0.8.105"
edition = "2021" edition = "2021"
license = "MIT" license = "MIT"
rust-version = "1.80" rust-version = "1.80"
+73 -19
View File
@@ -66,11 +66,14 @@ pub struct ModuleNsEntry {
/// 字段、不建第二个 Box——GC 边、字节核算、释放全部复用 `ModuleNamespace` 家族链, /// 字段、不建第二个 Box——GC 边、字节核算、释放全部复用 `ModuleNamespace` 家族链,
/// 零新增注册点。 /// 零新增注册点。
pub struct DeferredNsState { pub struct DeferredNsState {
/// `[[Module]]`:依赖模块函数(编译期 CREATE_CLOSURE 的闭包对象)。 /// `[[Module]]`:依赖模块函数(编译期 CREATE_CLOSURE 的闭包对象),或
/// undefined(哨兵:自导入/祖先引用,模块函数在导入方 prelude 期不可得)。
pub module: JsValue, pub module: JsValue,
/// `[[Evaluated]]`:依赖模块是否已求值(首次触发成功后置真,不回退)。 /// `[[Evaluated]]`:依赖模块是否已求值(mixed 依赖构造时即为真;
/// 首次触发成功后置真,不回退)。
pub evaluated: bool, pub evaluated: bool,
/// `[[Namespace]]`:求值后返回的命名空间对象(求值前为 undefined)。 /// `[[Namespace]]`:求值后返回的命名空间对象(mixed 依赖构造时即为真实 ns;
/// 求值前为 undefined)。
pub namespace: JsValue, pub namespace: JsValue,
} }
@@ -859,29 +862,38 @@ pub fn module_eval<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
} }
} }
/// `__moduleDeferObject(fn)`:创建 deferred namespace 对象(`import defer * as` 产物)。 /// `__moduleDeferObject(fn, real_ns)`:创建 deferred namespace 对象(`import defer * as` 产物)。
/// ///
/// # 步骤 /// # 步骤
/// 1. 校验 `fn` 为函数对象(依赖模块函数,编译期 CREATE_CLOSURE 的闭包对象)。 /// 1. 校验 `fn` 为函数对象(依赖模块函数,编译期 CREATE_CLOSURE 的闭包对象)
/// 或 undefined(哨兵:自导入/祖先引用,模块函数在导入方 prelude 期不可得);
/// 校验 `real_ns` 为对象(mixed:模块已急切求值)或 undefined。
/// 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]]` = false、 /// 4. 安装条目表并写状态盒:`[[Module]]` = fn、`[[Evaluated]]` = `real_ns` 为对象、
/// `[[Namespace]]` = undefined。 /// `[[Namespace]]` = `real_ns`(或 undefined)。
/// ///
/// # 副作用 /// # 副作用
/// - 新对象创建起即标记 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() < 2 { if args.len() < 3 {
return type_error(vm, "__moduleDeferObject: 1 argument required"); return type_error(vm, "__moduleDeferObject: 2 arguments required");
} }
let fn_val = vm.reg(args[1]); let fn_val = vm.reg(args[1]);
if !fn_val.is_object() { let ns_val = vm.reg(args[2]);
return type_error(vm, "__moduleDeferObject: target is not a function"); // fn 为函数或 undefined(哨兵);其余抛 TypeError。
let fn_is_function = fn_val.is_object()
&& {
let ptr = fn_val.as_js_object_ptr();
!ptr.is_null() && unsafe { (*ptr).is_function() }
};
if !fn_is_function && !fn_val.is_undefined() {
return type_error(vm, "__moduleDeferObject: first argument must be a function or undefined");
} }
let ptr = fn_val.as_js_object_ptr(); // real_ns 为对象(mixed 已求值态)或 undefined;其余抛 TypeError。
if ptr.is_null() || !unsafe { (*ptr).is_function() } { if !ns_val.is_object() && !ns_val.is_undefined() {
return type_error(vm, "__moduleDeferObject: target is not a function"); return type_error(vm, "__moduleDeferObject: second argument must be an object or undefined");
} }
let obj = vm.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null())); let obj = vm.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null()));
let tag_si = encode_symbol_key(vm.realm_id(), TO_STRING_TAG_SYMBOL_ID); let tag_si = encode_symbol_key(vm.realm_id(), TO_STRING_TAG_SYMBOL_ID);
@@ -898,8 +910,8 @@ pub fn module_defer_object<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
unsafe { unsafe {
(*table).deferred = Some(DeferredNsState { (*table).deferred = Some(DeferredNsState {
module: fn_val, module: fn_val,
evaluated: false, evaluated: ns_val.is_object(),
namespace: JsValue::undefined(), namespace: ns_val,
}); });
} }
NativeResult::Ok(JsValue::from_js_object(obj)) NativeResult::Ok(JsValue::from_js_object(obj))
@@ -968,7 +980,8 @@ mod tests {
fn module_defer_object_installs_state_box() { fn module_defer_object_installs_state_box() {
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);
let ns_val = module_defer_object(&mut vm, &[0, 1]).unwrap(); vm.set_reg(2, JsValue::undefined());
let ns_val = module_defer_object(&mut vm, &[0, 1, 2]).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());
@@ -984,14 +997,54 @@ mod tests {
assert_eq!(state.namespace, JsValue::undefined(), "[[Namespace]] 求值前应为 undefined"); assert_eq!(state.namespace, JsValue::undefined(), "[[Namespace]] 求值前应为 undefined");
} }
#[test]
fn module_defer_object_mixed_carries_evaluated_state() {
let (mut vm, fn_val) = vm_with_function();
// 真实 ns 对象(mixed:模块已急切求值)。
let real_ns = vm.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null()));
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 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]] 应存依赖模块函数");
assert!(state.evaluated, "mixed 依赖 [[Evaluated]] 构造时应为 true");
assert_eq!(state.namespace, ns_val, "[[Namespace]] 应存真实 ns");
}
#[test]
fn module_defer_object_sentinel_accepts_undefined_module() {
let (mut vm, _) = vm_with_function();
// 哨兵形态: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 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");
assert!(!state.evaluated, "哨兵 [[Evaluated]] 应为 false");
assert_eq!(state.namespace, JsValue::undefined(), "哨兵 [[Namespace]] 应为 undefined");
}
#[test] #[test]
fn module_defer_object_rejects_non_function() { fn module_defer_object_rejects_non_function() {
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));
let result = module_defer_object(&mut vm, &[0, 1]); vm.set_reg(2, JsValue::undefined());
let result = module_defer_object(&mut vm, &[0, 1, 2]);
assert!(matches!(result, NativeResult::Err(_)), "非函数应抛 TypeError"); assert!(matches!(result, NativeResult::Err(_)), "非函数应抛 TypeError");
} }
#[test]
fn module_defer_object_rejects_non_object_ns() {
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]);
assert!(matches!(result, NativeResult::Err(_)), "非对象 real_ns 应抛 TypeError");
}
#[test] #[test]
fn module_defer_ns_gc_edge_keeps_module_function_alive() { fn module_defer_ns_gc_edge_keeps_module_function_alive() {
let (mut vm, fn_val) = vm_with_function(); let (mut vm, fn_val) = vm_with_function();
@@ -999,7 +1052,8 @@ 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);
let ns_val = module_defer_object(&mut vm, &[0, 1]).unwrap(); vm.set_reg(2, JsValue::undefined());
let ns_val = module_defer_object(&mut vm, &[0, 1, 2]).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]] 边。
+5
View File
@@ -173,6 +173,10 @@ pub struct CompileCtx {
pub(crate) module_local_export_regs: HashMap<u32, Vec<String>>, pub(crate) module_local_export_regs: HashMap<u32, Vec<String>>,
/// 已求值依赖模块的命名空间对象寄存器(按 import/export source 字符串索引)。 /// 已求值依赖模块的命名空间对象寄存器(按 import/export source 字符串索引)。
pub(crate) module_dep_ns_regs: HashMap<String, u32>, pub(crate) module_dep_ns_regs: HashMap<String, u32>,
/// defer 依赖的 deferred namespace 对象寄存器(按 import source 字符串索引):
/// `import defer * as ns` 绑定此对象(`__moduleDeferObject` 产物),eager 命名空间
/// 绑定仍走 `module_dep_ns_regs`。仅含 defer 导入的 spec 登记。
pub(crate) module_defer_ns_regs: HashMap<String, u32>,
/// 依赖模块规范路径(按 import/export source 字符串索引):再导出来源身份用。 /// 依赖模块规范路径(按 import/export source 字符串索引):再导出来源身份用。
pub(crate) module_dep_paths: HashMap<String, String>, pub(crate) module_dep_paths: HashMap<String, String>,
/// 非自导入的导入局部名 → (依赖模块规范路径, 导入名)。命名空间导入的导入名为 /// 非自导入的导入局部名 → (依赖模块规范路径, 导入名)。命名空间导入的导入名为
@@ -287,6 +291,7 @@ impl CompileCtx {
module_ns_reg: None, module_ns_reg: None,
module_local_export_regs: HashMap::new(), module_local_export_regs: HashMap::new(),
module_dep_ns_regs: HashMap::new(), module_dep_ns_regs: HashMap::new(),
module_defer_ns_regs: HashMap::new(),
module_dep_paths: HashMap::new(), module_dep_paths: HashMap::new(),
module_import_origins: HashMap::new(), module_import_origins: HashMap::new(),
module_dep_reassignable: HashMap::new(), module_dep_reassignable: HashMap::new(),
+179 -33
View File
@@ -4,8 +4,11 @@
//! `__moduleGet` 活读,其余退化为快照;被闭包捕获的导出挂共享 cell,闭包内写 //! `__moduleGet` 活读,其余退化为快照;被闭包捕获的导出挂共享 cell,闭包内写
//! 随活读可见。自导入(`import ... from 自身`)的局部名解析为本模块源绑定的活 //! 随活读可见。自导入(`import ... from 自身`)的局部名解析为本模块源绑定的活
//! 别名,TDZ/提升/活值/不可变四语义全部委托源绑定。`export` 语句就地注册导出值。 //! 别名,TDZ/提升/活值/不可变四语义全部委托源绑定。`export` 语句就地注册导出值。
//! 未支持:嵌套闭包内读 import 名(仍为链接期快照)、defer(延迟求值)、 //! defer 导入(`import defer * as ns`)的依赖不求值:编译入子模块树并发
//! source-phase;star 转发与经再导出链的活值仍为快照;循环导入在编译期跳过。 //! `__moduleDeferObject` 构造 deferred namespace 对象(逐名预注册静态导出名),
//! 绑定该对象;自导入/祖先 defer 回边发哨兵形态(不递归、不编译)。
//! 未支持:嵌套闭包内读 import 名(仍为链接期快照)、source-phase;
//! star 转发与经再导出链的活值仍为快照;eager 环导入在编译期跳过。
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use std::path::Path; use std::path::Path;
@@ -21,7 +24,8 @@ use oxide_ir::operand::Operand;
use oxide_ir::{IRFunction, ParamLayout}; use oxide_ir::{IRFunction, ParamLayout};
use oxide_parser::{ use oxide_parser::{
BindingPattern, Declaration, ExportDefaultDeclarationKind, Expression, ImportAttributeKey, BindingPattern, Declaration, ExportDefaultDeclarationKind, Expression, ImportAttributeKey,
ImportDeclarationSpecifier, ModuleExportName, Statement, VariableDeclarationKind, WithClause, ImportDeclarationSpecifier, ImportPhase, ModuleExportName, Statement, VariableDeclarationKind,
WithClause,
}; };
use oxide_types::MODULE_NAMESPACE_BINDING; use oxide_types::MODULE_NAMESPACE_BINDING;
@@ -44,6 +48,16 @@ pub struct ResolvedModule {
pub kind: ModuleKind, pub kind: ModuleKind,
} }
/// 单个依赖 spec 的 phase 跟踪:eager/defer 双标志与首次出现的导入属性。
///
/// `eager` 为真表示该 spec 被任一非 defer 语句(导入或再导出)引用;
/// `defer` 为真表示被任一 `import defer * as` 引用。两标志可并存(mixed 依赖)。
struct DepPhase {
eager: bool,
defer: bool,
attrs: Vec<(String, String)>,
}
/// 模块加载器:由调用方(test262 runner / CLI)提供文件解析。 /// 模块加载器:由调用方(test262 runner / CLI)提供文件解析。
pub trait ModuleSourceLoader { pub trait ModuleSourceLoader {
/// 解析依赖模块:按 `base_dir` 与 `specifier` 定位模块源码,`attributes` 为 /// 解析依赖模块:按 `base_dir` 与 `specifier` 定位模块源码,`attributes` 为
@@ -457,50 +471,84 @@ impl Emitter {
let ns_reg = self.emit_module_call(ctx, "__moduleObject", &[])?; let ns_reg = self.emit_module_call(ctx, "__moduleObject", &[])?;
ctx.module_ns_reg = Some(ns_reg); ctx.module_ns_reg = Some(ns_reg);
// —— 依赖收集(import + re-export/star 的 source,按首次出现去重)—— // —— 依赖收集(import + re-export/star 的 source,按首次出现去重,记 phase)——
// eager_order 为各 spec 首个 eager 语句的出现序(求值序);defer_order 为各 spec
// 首次出现序(defer-only 组发射序)。无 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())
.unwrap_or_default(); .unwrap_or_default();
let mut deps: Vec<(String, Vec<(String, String)>)> = Vec::new(); 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();
for stmt in body { for stmt in body {
let (spec, attrs) = match stmt { let (spec, attrs, is_defer) = match stmt {
Statement::ImportDeclaration(imp) => { Statement::ImportDeclaration(imp) => {
(imp.source.value.to_string(), module_attributes(&imp.with_clause)) let is_defer = imp.phase == Some(ImportPhase::Defer);
(imp.source.value.to_string(), module_attributes(&imp.with_clause), is_defer)
} }
Statement::ExportNamedDeclaration(exp) => { Statement::ExportNamedDeclaration(exp) => {
if let Some(src) = &exp.source { if let Some(src) = &exp.source {
(src.value.to_string(), module_attributes(&exp.with_clause)) (src.value.to_string(), module_attributes(&exp.with_clause), false)
} else { } else {
continue; continue;
} }
} }
Statement::ExportAllDeclaration(exp) => { Statement::ExportAllDeclaration(exp) => {
(exp.source.value.to_string(), module_attributes(&exp.with_clause)) (exp.source.value.to_string(), module_attributes(&exp.with_clause), false)
} }
_ => continue, _ => continue,
}; };
if !deps.iter().any(|(s, _)| *s == spec) { let is_new = !phase_map.contains_key(&spec);
deps.push((spec, attrs)); let entry = phase_map
.entry(spec.clone())
.or_insert_with(|| DepPhase { eager: false, defer: false, attrs });
if is_new {
defer_order.push(spec.clone());
}
if !is_defer && !entry.eager {
entry.eager = true;
eager_order.push(spec.clone());
}
if is_defer {
entry.defer = true;
} }
} }
// —— 编译并求值依赖 —— // 本模块自身导出名与 var 作用域导出名:自导入 mixed 的 defer 预注册复用,
for (spec, attrs) in deps { // 亦供下方绑定循环与 live 预注册消费。
let attr_refs: Vec<(&str, &str)> = attrs.iter().map(|(k, v)| (k.as_str(), v.as_str())).collect(); let own_export_names = module_own_export_names(body);
let var_scoped_export_names = module_var_scoped_export_names(body);
// —— 编译并求值依赖:eager 组先行(按 eager 语句序),defer-only 组随后 ——
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 resolved = loader.resolve(&base_dir, &spec, &attr_refs)?;
let dep_ns_reg = if 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 {
// 自导入:读自身命名空间(依赖即本模块,勿递归)。 // 自导入:读自身命名空间(依赖即本模块,勿递归)。
ns_reg (ns_reg, None, 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) = match resolved.kind { let (dep_ir, dep_reassignable, dep_own_names, dep_var_scoped) = match resolved.kind {
ModuleKind::Js => self.compile_js_dep(&resolved, loader, path_stack)?, ModuleKind::Js => self.compile_js_dep(&resolved, loader, path_stack)?,
ModuleKind::Json => (self.compile_data_dep("json", &resolved.source)?, false), ModuleKind::Json => (
ModuleKind::Text => (self.compile_data_dep("text", &resolved.source)?, false), self.compile_data_dep("json", &resolved.source)?,
false,
HashSet::from([DEFAULT_EXPORT_NAME.to_string()]),
HashSet::from([DEFAULT_EXPORT_NAME.to_string()]),
),
ModuleKind::Text => (
self.compile_data_dep("text", &resolved.source)?,
false,
HashSet::from([DEFAULT_EXPORT_NAME.to_string()]),
HashSet::from([DEFAULT_EXPORT_NAME.to_string()]),
),
ModuleKind::Bytes => return Err("bytes module not supported".into()), ModuleKind::Bytes => return Err("bytes module not supported".into()),
}; };
path_stack.pop(); path_stack.pop();
@@ -508,20 +556,84 @@ 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));
self.emit_module_call(ctx, "__moduleEval", &[fn_reg])? let real_ns = self.emit_module_call(ctx, "__moduleEval", &[fn_reg])?;
(real_ns, Some(fn_reg), dep_own_names, dep_var_scoped)
}; };
ctx.module_dep_ns_regs.insert(spec.clone(), dep_ns_reg); ctx.module_dep_ns_regs.insert(spec.clone(), dep_ns_reg);
ctx.module_dep_paths.insert(spec.clone(), resolved.path.clone()); ctx.module_dep_paths.insert(spec.clone(), resolved.path.clone());
if resolved.path == module_path { if is_self {
// 自导入:绑定走别名语义(源导出在 body 执行中才就绪), // 自导入:绑定走别名语义(源导出在 body 执行中才就绪),
// 不能像普通依赖那样链接期快照。 // 不能像普通依赖那样链接期快照。
ctx.module_self_import_specs.insert(spec.clone()); 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)?;
}
}
// 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 {
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 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());
} else {
path_stack.push(resolved.path.clone());
let (dep_ir, _dep_reassignable, dep_own_names, dep_var_scoped) = match resolved.kind {
ModuleKind::Js => self.compile_js_dep(&resolved, loader, path_stack)?,
ModuleKind::Json => (
self.compile_data_dep("json", &resolved.source)?,
false,
HashSet::from([DEFAULT_EXPORT_NAME.to_string()]),
HashSet::from([DEFAULT_EXPORT_NAME.to_string()]),
),
ModuleKind::Text => (
self.compile_data_dep("text", &resolved.source)?,
false,
HashSet::from([DEFAULT_EXPORT_NAME.to_string()]),
HashSet::from([DEFAULT_EXPORT_NAME.to_string()]),
),
ModuleKind::Bytes => return Err("bytes module not supported".into()),
};
path_stack.pop();
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)?;
}
} }
// —— 导入绑定初始化(普通依赖为链接期快照;命名空间绑定直接引用 ns 对象; // —— 导入绑定初始化(普通依赖为链接期快照;命名空间绑定直接引用 ns 对象;
// 自导入绑定解析为本模块源绑定的活别名)—— // defer 命名空间绑定引用 deferred 对象;自导入绑定解析为本模块源绑定的活别名)——
let own_export_names = module_own_export_names(body);
// 无命名 `export * from 'x'` 会把依赖的全部导出转发给自身;自导入名可能来自 // 无命名 `export * from 'x'` 会把依赖的全部导出转发给自身;自导入名可能来自
// star 再导出,编译期无法静态判定该名是否存在于自身导出,故链接校验放宽。 // star 再导出,编译期无法静态判定该名是否存在于自身导出,故链接校验放宽。
let has_unnamed_star = body let has_unnamed_star = body
@@ -647,19 +759,29 @@ impl Emitter {
} }
} }
ImportDeclarationSpecifier::ImportNamespaceSpecifier(s) => { ImportDeclarationSpecifier::ImportNamespaceSpecifier(s) => {
let is_defer = imp.phase == Some(ImportPhase::Defer);
// 命名空间绑定引用 ns 对象本身:自导入时同一对象, // 命名空间绑定引用 ns 对象本身:自导入时同一对象,
// body 执行后导出自然可见。 // body 执行后导出自然可见;defer 绑定 deferred 对象。
if is_self { // defer 自导入不得激活 live ns(不置 has_self_ns_import)。
if is_self && !is_defer {
has_self_ns_import = true; has_self_ns_import = true;
} else { } else if !is_self {
ctx.module_import_origins.insert( ctx.module_import_origins.insert(
s.local.name.to_string(), s.local.name.to_string(),
(dep_path.clone(), MODULE_NAMESPACE_BINDING.to_string()), (dep_path.clone(), MODULE_NAMESPACE_BINDING.to_string()),
); );
} }
let bind_reg = if is_defer {
*ctx
.module_defer_ns_regs
.get(&dep_spec)
.ok_or_else(|| format!("module dependency missing: {dep_spec}"))?
} else {
dep_ns_reg
};
self.emit_bind_target( self.emit_bind_target(
s.local.name.as_str(), s.local.name.as_str(),
dep_ns_reg, bind_reg,
VariableDeclarationKind::Const, VariableDeclarationKind::Const,
true, true,
false, false,
@@ -698,12 +820,11 @@ impl Emitter {
// var/函数类导出(VarScopedDeclarations)在实例化期即初始化为 undefined, // var/函数类导出(VarScopedDeclarations)在实例化期即初始化为 undefined,
// lexical/class 保持未初始化(TDZ)。 —— // lexical/class 保持未初始化(TDZ)。 ——
if live_active { if live_active {
let var_scoped = module_var_scoped_export_names(body);
let mut export_names: Vec<String> = own_export_names.into_iter().collect(); let mut export_names: Vec<String> = own_export_names.into_iter().collect();
export_names.sort(); export_names.sort();
for name in export_names { for name in export_names {
let name_reg = self.load_string_const(&name, ctx); let name_reg = self.load_string_const(&name, ctx);
let var_like_reg = self.load_bool_const(var_scoped.contains(&name), ctx); let var_like_reg = self.load_bool_const(var_scoped_export_names.contains(&name), ctx);
self.emit_module_call(ctx, "__modulePreRegister", &[ns_reg, name_reg, var_like_reg])?; self.emit_module_call(ctx, "__modulePreRegister", &[ns_reg, name_reg, var_like_reg])?;
} }
} }
@@ -824,17 +945,19 @@ impl Emitter {
Ok(()) Ok(())
} }
/// 编译 JS 依赖模块(递归),回传 IR 与「是否含可重赋导出」标志。 /// 编译 JS 依赖模块(递归),回传 IR、「是否含可重赋导出」标志、
/// 自身静态导出名集与 var 作用域导出名集。
/// ///
/// # 边界与前提 /// # 边界与前提
/// - 标志取自依赖 ctx 的 `module_live_dep`;入口模块不参与,依赖模块恒按 /// - 可重赋标志取自依赖 ctx 的 `module_live_dep`;入口模块不参与,依赖模块恒按
/// `!top_level` 判定,故 const-only 依赖回传 false。 /// `!top_level` 判定,故 const-only 依赖回传 false。
/// - 导出名集在函数内对解析产物就地计算,供导入方 defer 预注册消费。
/// ///
/// # 注意事项 /// # 注意事项
/// - 导入方据标志决定是否登记活读映射;标志不改变本模块 IR。 /// - 导入方据标志决定是否登记活读映射;标志不改变本模块 IR。
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>,
) -> Result<(IRFunction, bool), String> { ) -> Result<(IRFunction, bool, HashSet<String>, HashSet<String>), String> {
let alloc = oxide_parser::Allocator::default(); let alloc = oxide_parser::Allocator::default();
let program = oxide_parser::parse_module(&alloc, &resolved.source).map_err(|errs| { let program = oxide_parser::parse_module(&alloc, &resolved.source).map_err(|errs| {
format!( format!(
@@ -848,7 +971,30 @@ impl Emitter {
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)?;
let reassignable = ctx.module_live_dep; let reassignable = ctx.module_live_dep;
Ok((ctx.assemble_ir(ParamLayout { base: 0, count: 0 }, None), reassignable)) let own_export_names = module_own_export_names(&program.body);
let var_scoped = module_var_scoped_export_names(&program.body);
Ok((
ctx.assemble_ir(ParamLayout { base: 0, count: 0 }, None),
reassignable,
own_export_names,
var_scoped,
))
}
/// 发 defer 预注册:对 deferred namespace 对象逐名 `__modulePreRegister`,
/// 名字按字典序排序保证发射序确定。var 作用域导出名(var/function)
/// 预注册为已初始化(undefined),lexical/class 保持未初始化(TDZ)。
fn emit_defer_pre_register(
&self, ctx: &mut CompileCtx, defer_ns_reg: u32, export_names: &HashSet<String>, var_scoped: &HashSet<String>,
) -> Result<(), String> {
let mut names: Vec<&String> = export_names.iter().collect();
names.sort();
for name in names {
let name_reg = self.load_string_const(name, ctx);
let var_like_reg = self.load_bool_const(var_scoped.contains(name), ctx);
self.emit_module_call(ctx, "__modulePreRegister", &[defer_ns_reg, name_reg, var_like_reg])?;
}
Ok(())
} }
/// 编译数据模块(json/text):body 仅为 __moduleData 调用 + RETURN。 /// 编译数据模块(json/text):body 仅为 __moduleData 调用 + RETURN。
+111 -1
View File
@@ -1,6 +1,7 @@
//! 模块链接面的 IR 级断言:内存版 `ModuleSourceLoader` + //! 模块链接面的 IR 级断言:内存版 `ModuleSourceLoader` +
//! `emit_program_module`,钉死 import prelude / export 就地注册 / star 再导出 / //! `emit_program_module`,钉死 import prelude / export 就地注册 / star 再导出 /
//! 循环导入编译期报错 / 数据模块的现状行为。 //! 循环导入编译期报错 / 数据模块 / defer 依赖(不求值、mixed eager 序、
//! 自导入与祖先回边哨兵)的现状行为。
//! //!
//! 路径口径:加载器 `path` 回填表键原样字符串,与入口 `module_path` 入参逐字符 //! 路径口径:加载器 `path` 回填表键原样字符串,与入口 `module_path` 入参逐字符
//! 一致(虚拟路径 canonicalize 失败保留原路径),自导入身份比较与循环检测依赖 //! 一致(虚拟路径 canonicalize 失败保留原路径),自导入身份比较与循环检测依赖
@@ -366,3 +367,112 @@ fn entry_module_reassignable_export_not_pre_registered() {
assert_eq!(native_calls_to(&ir, "__modulePreRegister"), 0, "入口模块不得预注册"); assert_eq!(native_calls_to(&ir, "__modulePreRegister"), 0, "入口模块不得预注册");
assert_eq!(native_calls_to(&ir, "__moduleSetCell"), 0, "入口模块不得挂 cell"); assert_eq!(native_calls_to(&ir, "__moduleSetCell"), 0, "入口模块不得挂 cell");
} }
/// 面 14:defer-only 依赖不求值——无 `__moduleEval`,发 `__moduleDeferObject`
/// 构造 deferred 对象,逐名 `__modulePreRegister` 预注册静态导出名。
#[test]
fn defer_only_dep_not_evaluated() {
let (ir, _) = emit_module(
"import defer * as ns from \"./dep.js\"; ns;",
"./entry.js",
&[("./dep.js", ModuleKind::Js, "export var a = 1; export const b = 2;")],
)
.expect("defer-only 依赖应编译成功");
assert_eq!(native_calls_to(&ir, "__moduleEval"), 0, "defer-only 依赖不得求值");
assert_eq!(native_calls_to(&ir, "__moduleDeferObject"), 1, "deferred 对象应构造一次");
assert_eq!(native_calls_to(&ir, "__modulePreRegister"), 2, "a 与 b 各预注册一次");
let pool = pool_strings(&ir);
assert!(pool.contains("a") && pool.contains("b"), "导出名应入池: {pool:?}");
assert_eq!(ir.nested.len(), 1, "依赖模块应编入子模块树");
}
/// 面 15:mixed 依赖按 eager 语句序求值,defer 语句不计入求值序。
/// 入口的 eager 序为 [setup, dep-2, dep-1](dep-1 为 mixed);dep-1 内的
/// defer-only dep-1.2 不求值。
#[test]
fn mixed_dep_evaluates_in_eager_order() {
let (ir, _) = emit_module(
"import \"./setup.js\"; import defer * as ns1 from \"./dep-1.js\"; import \"./dep-2.js\"; import \"./dep-1.js\";",
"./entry.js",
&[
("./setup.js", ModuleKind::Js, "globalThis.evaluations = [];"),
(
"./dep-1.js",
ModuleKind::Js,
"import \"./dep-1.1.js\"; import defer * as ns_1_2 from \"./dep-1.2.js\"; globalThis.evaluations.push(1); export { ns_1_2 };",
),
("./dep-2.js", ModuleKind::Js, "globalThis.evaluations.push(2);"),
("./dep-1.1.js", ModuleKind::Js, "globalThis.evaluations.push(1.1);"),
("./dep-1.2.js", ModuleKind::Js, "globalThis.evaluations.push(1.2);"),
],
)
.expect("mixed 依赖应编译成功");
// 入口:3 个 eager 依赖(setup, dep-2, dep-1)各求值一次。
assert_eq!(native_calls_to(&ir, "__moduleEval"), 3, "入口应求值 3 个 eager 依赖");
// 入口:dep-1 为 mixed,deferred 对象构造一次。
assert_eq!(native_calls_to(&ir, "__moduleDeferObject"), 1, "mixed dep-1 应构造 deferred 对象一次");
// dep-1 是第 3 个 nested 模块(eager_order = [setup, dep-2, dep-1])。
let dep1 = &ir.nested[2];
// dep-1:1 个 eager 依赖(dep-1.1)求值,defer-only 依赖(dep-1.2)不求值。
assert_eq!(native_calls_to(dep1, "__moduleEval"), 1, "dep-1 应只求值 dep-1.1");
// dep-1:dep-1.2 为 defer-only,deferred 对象构造一次。
assert_eq!(native_calls_to(dep1, "__moduleDeferObject"), 1, "dep-1.2 应构造 deferred 对象一次");
// dep-1.2 是 dep-1 的第 2 个 nested 模块(eager_order = [dep-1.1], defer_order = [dep-1.1, dep-1.2])。
let dep12 = &dep1.nested[1];
assert_eq!(native_calls_to(dep12, "__moduleEval"), 0, "dep-1.2 不得求值");
}
/// 面 16:自导入 defer 走哨兵分支——不递归、无环检测 Err、发
/// `__moduleDeferObject(undefined, undefined)`。
#[test]
fn self_import_defer_sentinel() {
let (ir, _) = emit_module(
"import defer * as self from \"./self.js\"; self;",
"./self.js",
&[("./self.js", ModuleKind::Js, "export var foo = 1;")],
)
.expect("自导入 defer 应编译成功");
assert_eq!(native_calls_to(&ir, "__moduleEval"), 0, "自导入 defer 不得求值");
assert_eq!(native_calls_to(&ir, "__moduleDeferObject"), 1, "哨兵 deferred 对象应构造一次");
assert_eq!(ir.nested.len(), 0, "自导入 defer 不得递归");
}
/// 面 17:祖先 defer 回边(dep → main)走哨兵分支——编译成功、无环检测 Err、
/// 不递归。main eager 导入 dep,dep defer 导入 main(导入图含环)。
#[test]
fn ancestor_defer_back_edge_sentinel() {
let main_src = "import \"./dep.js\"; globalThis.result = 1;";
let dep_src = "import defer * as main from \"./main.js\"; main.foo;";
let (ir, _) = emit_module(
main_src,
"./main.js",
&[
("./main.js", ModuleKind::Js, main_src),
("./dep.js", ModuleKind::Js, dep_src),
],
)
.expect("祖先 defer 回边应编译成功");
// main:1 个 eager 依赖(dep)求值。
assert_eq!(native_calls_to(&ir, "__moduleEval"), 1, "main 应求值 dep");
// main:无 defer,无 deferred 对象。
assert_eq!(native_calls_to(&ir, "__moduleDeferObject"), 0, "main 不得构造 deferred 对象");
// dep(nested):1 个 defer-only 依赖(main)哨兵,不求值。
let dep = &ir.nested[0];
assert_eq!(native_calls_to(dep, "__moduleEval"), 0, "dep 不得求值 main");
assert_eq!(native_calls_to(dep, "__moduleDeferObject"), 1, "dep 应为 main 构造哨兵 deferred 对象");
// dep:不递归(main 未编入 dep 的 nested)。
assert_eq!(dep.nested.len(), 0, "dep 不得递归进 main");
}
/// 面 18:零 diff 守卫——非 defer 模块无 `__moduleDeferObject`、无依赖预注册。
#[test]
fn no_defer_object_for_non_defer_modules() {
let (ir, _) = emit_module(
"import * as ns from \"./dep.js\"; ns;",
"./entry.js",
&[("./dep.js", ModuleKind::Js, "export var z = 1;")],
)
.expect("非 defer 模块应编译成功");
assert_eq!(native_calls_to(&ir, "__moduleDeferObject"), 0, "非 defer 模块不得构造 deferred 对象");
assert_eq!(native_calls_to(&ir, "__modulePreRegister"), 0, "非 defer 模块不得预注册依赖");
}
+1 -1
View File
@@ -57,7 +57,7 @@ pub fn bind_global(core: &Arc<KernelCore>, session: &KernelSession, global: &mut
( (
"__moduleDeferObject", "__moduleDeferObject",
oxide_builtins::module::module_defer_object::<crate::vm::Vm> as *const (), oxide_builtins::module::module_defer_object::<crate::vm::Vm> as *const (),
1, 2,
), ),
("__moduleData", oxide_builtins::module::module_data::<crate::vm::Vm> as *const (), 2), ("__moduleData", oxide_builtins::module::module_data::<crate::vm::Vm> as *const (), 2),
("eval", oxide_builtins::eval::eval::<crate::vm::Vm> as *const (), 1), ("eval", oxide_builtins::eval::eval::<crate::vm::Vm> as *const (), 1),