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
+73 -19
View File
@@ -66,11 +66,14 @@ pub struct ModuleNsEntry {
/// 字段、不建第二个 Box——GC 边、字节核算、释放全部复用 `ModuleNamespace` 家族链,
/// 零新增注册点。
pub struct DeferredNsState {
/// `[[Module]]`:依赖模块函数(编译期 CREATE_CLOSURE 的闭包对象)。
/// `[[Module]]`:依赖模块函数(编译期 CREATE_CLOSURE 的闭包对象),或
/// undefined(哨兵:自导入/祖先引用,模块函数在导入方 prelude 期不可得)。
pub module: JsValue,
/// `[[Evaluated]]`:依赖模块是否已求值(首次触发成功后置真,不回退)。
/// `[[Evaluated]]`:依赖模块是否已求值(mixed 依赖构造时即为真;
/// 首次触发成功后置真,不回退)。
pub evaluated: bool,
/// `[[Namespace]]`:求值后返回的命名空间对象(求值前为 undefined)。
/// `[[Namespace]]`:求值后返回的命名空间对象(mixed 依赖构造时即为真实 ns;
/// 求值前为 undefined)。
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"(不可写不可枚举不可配置)。
/// 3. 置 module namespace + deferred 双标志,置 non-extensible。
/// 4. 安装条目表并写状态盒:`[[Module]]` = fn、`[[Evaluated]]` = false、
/// `[[Namespace]]` = undefined。
/// 4. 安装条目表并写状态盒:`[[Module]]` = fn、`[[Evaluated]]` = `real_ns` 为对象、
/// `[[Namespace]]` = `real_ns`(或 undefined)。
///
/// # 副作用
/// - 新对象创建起即标记 module namespace exotic 并置 non-extensible(同 `__moduleObject`);
/// 状态盒三内部槽由本入口唯一安装。
pub fn module_defer_object<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
if args.len() < 2 {
return type_error(vm, "__moduleDeferObject: 1 argument required");
if args.len() < 3 {
return type_error(vm, "__moduleDeferObject: 2 arguments required");
}
let fn_val = vm.reg(args[1]);
if !fn_val.is_object() {
return type_error(vm, "__moduleDeferObject: target is not a function");
let ns_val = vm.reg(args[2]);
// 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();
if ptr.is_null() || !unsafe { (*ptr).is_function() } {
return type_error(vm, "__moduleDeferObject: target is not a function");
// real_ns 为对象(mixed 已求值态)或 undefined;其余抛 TypeError。
if !ns_val.is_object() && !ns_val.is_undefined() {
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 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 {
(*table).deferred = Some(DeferredNsState {
module: fn_val,
evaluated: false,
namespace: JsValue::undefined(),
evaluated: ns_val.is_object(),
namespace: ns_val,
});
}
NativeResult::Ok(JsValue::from_js_object(obj))
@@ -968,7 +980,8 @@ mod tests {
fn module_defer_object_installs_state_box() {
let (mut vm, fn_val) = vm_with_function();
vm.set_reg(1, fn_val);
let ns_val = module_defer_object(&mut vm, &[0, 1]).unwrap();
vm.set_reg(2, JsValue::undefined());
let ns_val = module_defer_object(&mut vm, &[0, 1, 2]).unwrap();
assert!(ns_val.is_object());
let ns_ptr = ns_val.as_js_object_ptr();
assert!(!ns_ptr.is_null());
@@ -984,14 +997,54 @@ mod tests {
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]
fn module_defer_object_rejects_non_function() {
let (mut vm, _) = vm_with_function();
vm.set_reg(1, JsValue::int(42));
let result = module_defer_object(&mut vm, &[0, 1]);
vm.set_reg(2, JsValue::undefined());
let result = module_defer_object(&mut vm, &[0, 1, 2]);
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]
fn module_defer_ns_gc_edge_keeps_module_function_alive() {
let (mut vm, fn_val) = vm_with_function();
@@ -999,7 +1052,8 @@ mod tests {
// 创建 deferred ns(持有 fn);fn + ns 两个 session 对象。
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();
// 仅 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>>,
/// 已求值依赖模块的命名空间对象寄存器(按 import/export source 字符串索引)。
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 字符串索引):再导出来源身份用。
pub(crate) module_dep_paths: HashMap<String, String>,
/// 非自导入的导入局部名 → (依赖模块规范路径, 导入名)。命名空间导入的导入名为
@@ -287,6 +291,7 @@ impl CompileCtx {
module_ns_reg: None,
module_local_export_regs: HashMap::new(),
module_dep_ns_regs: HashMap::new(),
module_defer_ns_regs: HashMap::new(),
module_dep_paths: HashMap::new(),
module_import_origins: HashMap::new(),
module_dep_reassignable: HashMap::new(),
+179 -33
View File
@@ -4,8 +4,11 @@
//! `__moduleGet` 活读,其余退化为快照;被闭包捕获的导出挂共享 cell,闭包内写
//! 随活读可见。自导入(`import ... from 自身`)的局部名解析为本模块源绑定的活
//! 别名,TDZ/提升/活值/不可变四语义全部委托源绑定。`export` 语句就地注册导出值。
//! 未支持:嵌套闭包内读 import 名(仍为链接期快照)、defer(延迟求值)、
//! source-phase;star 转发与经再导出链的活值仍为快照;循环导入在编译期跳过。
//! defer 导入(`import defer * as ns`)的依赖不求值:编译入子模块树并发
//! `__moduleDeferObject` 构造 deferred namespace 对象(逐名预注册静态导出名),
//! 绑定该对象;自导入/祖先 defer 回边发哨兵形态(不递归、不编译)。
//! 未支持:嵌套闭包内读 import 名(仍为链接期快照)、source-phase;
//! star 转发与经再导出链的活值仍为快照;eager 环导入在编译期跳过。
use std::collections::{HashMap, HashSet};
use std::path::Path;
@@ -21,7 +24,8 @@ use oxide_ir::operand::Operand;
use oxide_ir::{IRFunction, ParamLayout};
use oxide_parser::{
BindingPattern, Declaration, ExportDefaultDeclarationKind, Expression, ImportAttributeKey,
ImportDeclarationSpecifier, ModuleExportName, Statement, VariableDeclarationKind, WithClause,
ImportDeclarationSpecifier, ImportPhase, ModuleExportName, Statement, VariableDeclarationKind,
WithClause,
};
use oxide_types::MODULE_NAMESPACE_BINDING;
@@ -44,6 +48,16 @@ pub struct ResolvedModule {
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)提供文件解析。
pub trait ModuleSourceLoader {
/// 解析依赖模块:按 `base_dir` 与 `specifier` 定位模块源码,`attributes` 为
@@ -457,50 +471,84 @@ impl Emitter {
let ns_reg = self.emit_module_call(ctx, "__moduleObject", &[])?;
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)
.parent()
.map(|p| p.to_string_lossy().to_string())
.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 {
let (spec, attrs) = match stmt {
let (spec, attrs, is_defer) = match stmt {
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) => {
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 {
continue;
}
}
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,
};
if !deps.iter().any(|(s, _)| *s == spec) {
deps.push((spec, attrs));
let is_new = !phase_map.contains_key(&spec);
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;
}
}
// —— 编译并求值依赖 ——
for (spec, attrs) in deps {
let attr_refs: Vec<(&str, &str)> = attrs.iter().map(|(k, v)| (k.as_str(), v.as_str())).collect();
// 本模块自身导出名与 var 作用域导出名:自导入 mixed 的 defer 预注册复用,
// 亦供下方绑定循环与 live 预注册消费。
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 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 {
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) = 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::Json => (self.compile_data_dep("json", &resolved.source)?, false),
ModuleKind::Text => (self.compile_data_dep("text", &resolved.source)?, false),
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();
@@ -508,20 +556,84 @@ 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));
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_paths.insert(spec.clone(), resolved.path.clone());
if resolved.path == module_path {
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)?;
}
}
// 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 对象;
// 自导入绑定解析为本模块源绑定的活别名)——
let own_export_names = module_own_export_names(body);
// defer 命名空间绑定引用 deferred 对象;自导入绑定解析为本模块源绑定的活别名)——
// 无命名 `export * from 'x'` 会把依赖的全部导出转发给自身;自导入名可能来自
// star 再导出,编译期无法静态判定该名是否存在于自身导出,故链接校验放宽。
let has_unnamed_star = body
@@ -647,19 +759,29 @@ impl Emitter {
}
}
ImportDeclarationSpecifier::ImportNamespaceSpecifier(s) => {
let is_defer = imp.phase == Some(ImportPhase::Defer);
// 命名空间绑定引用 ns 对象本身:自导入时同一对象,
// body 执行后导出自然可见。
if is_self {
// body 执行后导出自然可见;defer 绑定 deferred 对象。
// defer 自导入不得激活 live ns(不置 has_self_ns_import)。
if is_self && !is_defer {
has_self_ns_import = true;
} else {
} else if !is_self {
ctx.module_import_origins.insert(
s.local.name.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(
s.local.name.as_str(),
dep_ns_reg,
bind_reg,
VariableDeclarationKind::Const,
true,
false,
@@ -698,12 +820,11 @@ impl Emitter {
// var/函数类导出(VarScopedDeclarations)在实例化期即初始化为 undefined,
// lexical/class 保持未初始化(TDZ)。 ——
if live_active {
let var_scoped = module_var_scoped_export_names(body);
let mut export_names: Vec<String> = own_export_names.into_iter().collect();
export_names.sort();
for name in export_names {
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])?;
}
}
@@ -824,17 +945,19 @@ impl Emitter {
Ok(())
}
/// 编译 JS 依赖模块(递归),回传 IR 与「是否含可重赋导出」标志。
/// 编译 JS 依赖模块(递归),回传 IR、「是否含可重赋导出」标志、
/// 自身静态导出名集与 var 作用域导出名集。
///
/// # 边界与前提
/// - 标志取自依赖 ctx 的 `module_live_dep`;入口模块不参与,依赖模块恒按
/// - 可重赋标志取自依赖 ctx 的 `module_live_dep`;入口模块不参与,依赖模块恒按
/// `!top_level` 判定,故 const-only 依赖回传 false。
/// - 导出名集在函数内对解析产物就地计算,供导入方 defer 预注册消费。
///
/// # 注意事项
/// - 导入方据标志决定是否登记活读映射;标志不改变本模块 IR。
fn compile_js_dep(
&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 program = oxide_parser::parse_module(&alloc, &resolved.source).map_err(|errs| {
format!(
@@ -848,7 +971,30 @@ impl Emitter {
ctx.is_strict = true;
self.emit_module_into_ctx(&program, &resolved.path, loader, path_stack, &mut ctx, false)?;
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。
+111 -1
View File
@@ -1,6 +1,7 @@
//! 模块链接面的 IR 级断言:内存版 `ModuleSourceLoader` +
//! `emit_program_module`,钉死 import prelude / export 就地注册 / star 再导出 /
//! 循环导入编译期报错 / 数据模块的现状行为。
//! 循环导入编译期报错 / 数据模块 / defer 依赖(不求值、mixed eager 序、
//! 自导入与祖先回边哨兵)的现状行为。
//!
//! 路径口径:加载器 `path` 回填表键原样字符串,与入口 `module_path` 入参逐字符
//! 一致(虚拟路径 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, "__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",
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),
("eval", oxide_builtins::eval::eval::<crate::vm::Vm> as *const (), 1),