mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-23 18:21:13 +08:00
feat: defer 依赖不发 __moduleEval,构造 deferred 对象并逐名预注册
This commit is contained in:
Generated
+19
-19
@@ -1160,7 +1160,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_builtins"
|
||||
version = "0.8.104"
|
||||
version = "0.8.105"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"fast-float",
|
||||
@@ -1185,7 +1185,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_bytecode"
|
||||
version = "0.8.104"
|
||||
version = "0.8.105"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"oxide_log",
|
||||
@@ -1193,7 +1193,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_cfg"
|
||||
version = "0.8.104"
|
||||
version = "0.8.105"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_emit",
|
||||
@@ -1204,7 +1204,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_cli"
|
||||
version = "0.8.104"
|
||||
version = "0.8.105"
|
||||
dependencies = [
|
||||
"ansi_term",
|
||||
"bumpalo",
|
||||
@@ -1226,7 +1226,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_code_cache"
|
||||
version = "0.8.104"
|
||||
version = "0.8.105"
|
||||
dependencies = [
|
||||
"lru",
|
||||
"oxide_bytecode",
|
||||
@@ -1235,7 +1235,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_compiler"
|
||||
version = "0.8.104"
|
||||
version = "0.8.105"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_cfg",
|
||||
@@ -1255,7 +1255,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_dce"
|
||||
version = "0.8.104"
|
||||
version = "0.8.105"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_cfg",
|
||||
@@ -1269,7 +1269,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_emit"
|
||||
version = "0.8.104"
|
||||
version = "0.8.105"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"oxc_allocator",
|
||||
@@ -1284,7 +1284,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_engine"
|
||||
version = "0.8.104"
|
||||
version = "0.8.105"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_compiler",
|
||||
@@ -1296,7 +1296,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_ir"
|
||||
version = "0.8.104"
|
||||
version = "0.8.105"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_log",
|
||||
@@ -1305,7 +1305,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_kernel"
|
||||
version = "0.8.104"
|
||||
version = "0.8.105"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"dashmap",
|
||||
@@ -1319,7 +1319,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_liveness"
|
||||
version = "0.8.104"
|
||||
version = "0.8.105"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_cfg",
|
||||
@@ -1331,7 +1331,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_log"
|
||||
version = "0.8.104"
|
||||
version = "0.8.105"
|
||||
dependencies = [
|
||||
"tracing",
|
||||
"tracing-appender",
|
||||
@@ -1340,7 +1340,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_parser"
|
||||
version = "0.8.104"
|
||||
version = "0.8.105"
|
||||
dependencies = [
|
||||
"oxc_allocator",
|
||||
"oxc_ast",
|
||||
@@ -1355,7 +1355,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_regalloc"
|
||||
version = "0.8.104"
|
||||
version = "0.8.105"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_cfg",
|
||||
@@ -1371,7 +1371,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_runtime_api"
|
||||
version = "0.8.104"
|
||||
version = "0.8.105"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"num-traits",
|
||||
@@ -1384,7 +1384,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_test262"
|
||||
version = "0.8.104"
|
||||
version = "0.8.105"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_compiler",
|
||||
@@ -1402,7 +1402,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_types"
|
||||
version = "0.8.104"
|
||||
version = "0.8.105"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"dashmap",
|
||||
@@ -1415,7 +1415,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_vm"
|
||||
version = "0.8.104"
|
||||
version = "0.8.105"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"chrono",
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@ members = [
|
||||
]
|
||||
|
||||
[workspace.package]
|
||||
version = "0.8.104"
|
||||
version = "0.8.105"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
rust-version = "1.80"
|
||||
|
||||
@@ -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();
|
||||
if ptr.is_null() || !unsafe { (*ptr).is_function() } {
|
||||
return type_error(vm, "__moduleDeferObject: target is not a function");
|
||||
!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");
|
||||
}
|
||||
// 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]] 边。
|
||||
|
||||
@@ -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
@@ -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。
|
||||
|
||||
@@ -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 模块不得预注册依赖");
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
|
||||
Reference in New Issue
Block a user