feat: TLA 模块求值 emit 侧编译为合成异步函数

This commit is contained in:
2026-10-13 17:36:47 +00:00
parent 009a049288
commit 75cece2ad9
7 changed files with 575 additions and 34 deletions
Generated
+21 -21
View File
@@ -1160,7 +1160,7 @@ dependencies = [
[[package]]
name = "oxide_builtins"
version = "0.18.4"
version = "0.18.5"
dependencies = [
"chrono",
"fast-float",
@@ -1185,7 +1185,7 @@ dependencies = [
[[package]]
name = "oxide_bytecode"
version = "0.18.4"
version = "0.18.5"
dependencies = [
"num-bigint",
"oxide_log",
@@ -1193,7 +1193,7 @@ dependencies = [
[[package]]
name = "oxide_cfg"
version = "0.18.4"
version = "0.18.5"
dependencies = [
"oxide_bytecode",
"oxide_emit",
@@ -1204,7 +1204,7 @@ dependencies = [
[[package]]
name = "oxide_cli"
version = "0.18.4"
version = "0.18.5"
dependencies = [
"ansi_term",
"bumpalo",
@@ -1228,7 +1228,7 @@ dependencies = [
[[package]]
name = "oxide_code_cache"
version = "0.18.4"
version = "0.18.5"
dependencies = [
"lru",
"oxide_bytecode",
@@ -1237,7 +1237,7 @@ dependencies = [
[[package]]
name = "oxide_compiler"
version = "0.18.4"
version = "0.18.5"
dependencies = [
"oxide_bytecode",
"oxide_cfg",
@@ -1258,7 +1258,7 @@ dependencies = [
[[package]]
name = "oxide_dce"
version = "0.18.4"
version = "0.18.5"
dependencies = [
"oxide_bytecode",
"oxide_cfg",
@@ -1272,7 +1272,7 @@ dependencies = [
[[package]]
name = "oxide_emit"
version = "0.18.4"
version = "0.18.5"
dependencies = [
"num-bigint",
"oxc_allocator",
@@ -1288,7 +1288,7 @@ dependencies = [
[[package]]
name = "oxide_engine"
version = "0.18.4"
version = "0.18.5"
dependencies = [
"oxide_bytecode",
"oxide_compiler",
@@ -1300,7 +1300,7 @@ dependencies = [
[[package]]
name = "oxide_fold"
version = "0.18.4"
version = "0.18.5"
dependencies = [
"num-bigint",
"oxide_bytecode",
@@ -1312,7 +1312,7 @@ dependencies = [
[[package]]
name = "oxide_ir"
version = "0.18.4"
version = "0.18.5"
dependencies = [
"oxide_bytecode",
"oxide_log",
@@ -1321,7 +1321,7 @@ dependencies = [
[[package]]
name = "oxide_kernel"
version = "0.18.4"
version = "0.18.5"
dependencies = [
"bumpalo",
"dashmap",
@@ -1335,7 +1335,7 @@ dependencies = [
[[package]]
name = "oxide_liveness"
version = "0.18.4"
version = "0.18.5"
dependencies = [
"oxide_bytecode",
"oxide_cfg",
@@ -1347,7 +1347,7 @@ dependencies = [
[[package]]
name = "oxide_log"
version = "0.18.4"
version = "0.18.5"
dependencies = [
"tracing",
"tracing-appender",
@@ -1356,11 +1356,11 @@ dependencies = [
[[package]]
name = "oxide_net"
version = "0.18.4"
version = "0.18.5"
[[package]]
name = "oxide_parser"
version = "0.18.4"
version = "0.18.5"
dependencies = [
"oxc_allocator",
"oxc_ast",
@@ -1375,7 +1375,7 @@ dependencies = [
[[package]]
name = "oxide_regalloc"
version = "0.18.4"
version = "0.18.5"
dependencies = [
"oxide_bytecode",
"oxide_cfg",
@@ -1391,7 +1391,7 @@ dependencies = [
[[package]]
name = "oxide_runtime_api"
version = "0.18.4"
version = "0.18.5"
dependencies = [
"num-bigint",
"num-traits",
@@ -1404,7 +1404,7 @@ dependencies = [
[[package]]
name = "oxide_test262"
version = "0.18.4"
version = "0.18.5"
dependencies = [
"oxide_bytecode",
"oxide_compiler",
@@ -1424,7 +1424,7 @@ dependencies = [
[[package]]
name = "oxide_types"
version = "0.18.4"
version = "0.18.5"
dependencies = [
"bumpalo",
"dashmap",
@@ -1437,7 +1437,7 @@ dependencies = [
[[package]]
name = "oxide_vm"
version = "0.18.4"
version = "0.18.5"
dependencies = [
"bumpalo",
"chrono",
+1 -1
View File
@@ -25,7 +25,7 @@ members = [
]
[workspace.package]
version = "0.18.4"
version = "0.18.5"
edition = "2021"
license = "MIT"
rust-version = "1.80"
+57 -5
View File
@@ -12,13 +12,40 @@ use oxide_bytecode::module::CompiledModule;
use oxide_bytecode::opcode::{self, OpCode};
/// 给整棵子模块树分配扁平 id 并重写 `CREATE_CLOSURE` 操作数。
///
/// TLA 模块(`is_async`)额外做 entry rehome:平表下标 0 是 native 哨兵
/// (`call_bytecode_function_inline` 拒绝 `sub_module_index == 0`),故在 `sub_modules`
/// 头部插一个占位槽(flat_id 0)、entry 落 flat_id 1、其余子模块顺延。
pub fn flatten_submodules(module: &mut CompiledModule) {
let mut next_id = 1u32;
assign_ids(module, &mut next_id);
let rehome = module.is_async;
if rehome {
module.sub_modules.insert(0, Arc::new(CompiledModule::new()));
module.flat_id = 1;
// entry 的 CREATE_CLOSURE 相对下标整体 +1(占位槽占据下标 1)。
for instr in Arc::make_mut(&mut module.bytecode).iter_mut() {
if opcode::opcode(*instr) == OpCode::CREATE_CLOSURE {
let rel = opcode::imm16(*instr) as usize;
let rd = opcode::rd(*instr);
*instr = opcode::encode(
OpCode::CREATE_CLOSURE,
rd,
((rel + 1) & 0xFF) as u8,
(((rel + 1) >> 8) & 0xFF) as u8,
);
}
}
}
let mut next_id = if rehome { 2u32 } else { 1u32 };
assign_ids(module, &mut next_id, rehome);
}
fn assign_ids(module: &mut CompiledModule, next_id: &mut u32) {
for sub in &mut module.sub_modules {
fn assign_ids(module: &mut CompiledModule, next_id: &mut u32, skip_placeholder: bool) {
for (i, sub) in module.sub_modules.iter_mut().enumerate() {
// TLA 模块首个子模块是占位槽(flat_id 0),不参与递增分配。
if skip_placeholder && i == 0 {
Arc::make_mut(sub).flat_id = 0;
continue;
}
// 子模块以 Arc 共享;flatten 在编译末端跑(refcount 1),make_mut 无拷贝。
Arc::make_mut(sub).flat_id = *next_id;
*next_id += 1;
@@ -37,7 +64,7 @@ fn assign_ids(module: &mut CompiledModule, next_id: &mut u32) {
}
}
for sub in &mut module.sub_modules {
assign_ids(Arc::make_mut(sub), next_id);
assign_ids(Arc::make_mut(sub), next_id, false);
}
}
@@ -69,4 +96,29 @@ mod tests {
// mid 的 CREATE_CLOSURE 相对 1 → flat 2
assert_eq!(opcode::imm16(top.sub_modules[0].bytecode[0]), 2);
}
#[test]
fn flatten_rehomes_async_entry_to_index_one() {
// 非 TLA 模块:entry 落 flat_id 0,占位槽不存在。
let mut sync = CompiledModule::new();
sync.bytecode = Arc::from(vec![opcode::encode(OpCode::CREATE_CLOSURE, 1, 1, 0)]);
sync.sub_modules = vec![Arc::new(CompiledModule::new())];
flatten_submodules(&mut sync);
assert_eq!(sync.flat_id, 0);
assert_eq!(sync.sub_modules.len(), 1);
assert_eq!(sync.sub_modules[0].flat_id, 1);
// TLA 模块:占位槽 0、entry 落 1、子模块顺延 2。
let mut tla = CompiledModule::new();
tla.is_async = true;
tla.bytecode = Arc::from(vec![opcode::encode(OpCode::CREATE_CLOSURE, 1, 1, 0)]);
tla.sub_modules = vec![Arc::new(CompiledModule::new())];
flatten_submodules(&mut tla);
assert_eq!(tla.flat_id, 1);
assert_eq!(tla.sub_modules.len(), 2);
assert_eq!(tla.sub_modules[0].flat_id, 0); // 占位槽
assert_eq!(tla.sub_modules[1].flat_id, 2);
// entry 的 CREATE_CLOSURE 相对 1 → 占位槽插入后指向 flat 2
assert_eq!(opcode::imm16(tla.bytecode[0]), 2);
}
}
+354 -7
View File
@@ -23,8 +23,11 @@ use oxide_ir::inst::Inst;
use oxide_ir::operand::Operand;
use oxide_ir::{IRFunction, ParamLayout};
use oxide_parser::{
BindingPattern, Declaration, ExportDefaultDeclarationKind, Expression, ImportAttributeKey,
ImportDeclarationSpecifier, ImportPhase, ModuleExportName, Statement, VariableDeclarationKind, WithClause,
ArrayExpressionElement, AssignmentTarget, AssignmentTargetMaybeDefault, AssignmentTargetProperty,
BindingPattern, ChainElement, Declaration, ExportDefaultDeclarationKind, Expression,
ForStatementInit, ForStatementLeft, ImportAttributeKey, ImportDeclarationSpecifier, ImportPhase,
ModuleExportName, ObjectPropertyKind, SimpleAssignmentTarget, Statement, VariableDeclarationKind,
WithClause,
};
use oxide_types::MODULE_NAMESPACE_BINDING;
@@ -334,6 +337,301 @@ fn is_hoisted_function_decl(stmt: &Statement) -> bool {
}
}
/// 判断模块体是否含顶层 `await`(top-level await,模块自身 `[[HasTLA]]` 标志)。
///
/// # 边界与前提
/// - 递归进入语句与表达式容器;不进入函数体(函数声明、函数表达式、箭头函数、
/// 类方法)——函数体内的 `await` 属函数自身异步语义,不使模块变异步。
/// - `for await…of` 在模块代码使模块异步(规范强制),其 `await` 关键字与
/// 左值、右值、体一并判定。
///
/// # 注意事项
/// - 取向宁假阳勿假阴:漏判会使模块按同步编译、运行期 `AWAIT` 守卫硬拒,红色不静默;
/// 误判仅使模块多走异步编译路径,语义不变。
fn module_has_top_level_await(body: &[Statement]) -> bool {
body.iter().any(|stmt| stmt_has_top_level_await(stmt))
}
/// 语句级顶层 `await` 游走:进入子语句与子表达式,函数/类声明体不进入。
fn stmt_has_top_level_await(stmt: &Statement) -> bool {
match stmt {
Statement::BlockStatement(block) => {
block.body.iter().any(|s| stmt_has_top_level_await(s))
}
Statement::IfStatement(if_stmt) => {
stmt_has_top_level_await(&if_stmt.consequent)
|| if_stmt
.alternate
.as_ref()
.is_some_and(|alt| stmt_has_top_level_await(alt))
}
Statement::ForStatement(for_stmt) => {
for_stmt.init.as_ref().is_some_and(|init| match init {
ForStatementInit::VariableDeclaration(vd) => vd
.declarations
.iter()
.any(|d| d.init.as_ref().is_some_and(|i| expr_has_top_level_await(i))),
_ => init.as_expression().is_some_and(expr_has_top_level_await),
})
|| for_stmt.test.as_ref().is_some_and(|t| expr_has_top_level_await(t))
|| for_stmt.update.as_ref().is_some_and(|u| expr_has_top_level_await(u))
|| stmt_has_top_level_await(&for_stmt.body)
}
Statement::ForInStatement(for_in) => {
for_left_has_top_level_await(&for_in.left)
|| expr_has_top_level_await(&for_in.right)
|| stmt_has_top_level_await(&for_in.body)
}
Statement::ForOfStatement(for_of) => {
// `for await…of` 在模块代码使模块按异步求值(规范强制模块异步;
// `await` 关键字本身非 AwaitExpression,但语句整体触发 [[HasTLA]])。
// 左值、右值与体照常游走。
for_of.r#await
|| for_left_has_top_level_await(&for_of.left)
|| expr_has_top_level_await(&for_of.right)
|| stmt_has_top_level_await(&for_of.body)
}
Statement::WhileStatement(while_stmt) => {
expr_has_top_level_await(&while_stmt.test) || stmt_has_top_level_await(&while_stmt.body)
}
Statement::DoWhileStatement(do_while) => {
expr_has_top_level_await(&do_while.test) || stmt_has_top_level_await(&do_while.body)
}
Statement::SwitchStatement(switch_stmt) => {
expr_has_top_level_await(&switch_stmt.discriminant)
|| switch_stmt.cases.iter().any(|c| {
c.test.as_ref().is_some_and(|t| expr_has_top_level_await(t))
|| c.consequent.iter().any(|s| stmt_has_top_level_await(s))
})
}
Statement::TryStatement(try_stmt) => {
try_stmt.block.body.iter().any(|s| stmt_has_top_level_await(s))
|| try_stmt
.handler
.as_ref()
.is_some_and(|h| h.body.body.iter().any(|s| stmt_has_top_level_await(s)))
|| try_stmt
.finalizer
.as_ref()
.is_some_and(|f| f.body.iter().any(|s| stmt_has_top_level_await(s)))
}
Statement::LabeledStatement(labeled) => stmt_has_top_level_await(&labeled.body),
Statement::WithStatement(with_stmt) => {
expr_has_top_level_await(&with_stmt.object) || stmt_has_top_level_await(&with_stmt.body)
}
Statement::ExpressionStatement(expr_stmt) => expr_has_top_level_await(&expr_stmt.expression),
Statement::ReturnStatement(ret) => ret
.argument
.as_ref()
.is_some_and(|a| expr_has_top_level_await(a)),
Statement::ThrowStatement(throw) => expr_has_top_level_await(&throw.argument),
Statement::VariableDeclaration(vd) => vd
.declarations
.iter()
.any(|d| d.init.as_ref().is_some_and(|i| expr_has_top_level_await(i))),
// 函数/类声明:体不进入(函数体是独立异步语义边界)。
Statement::FunctionDeclaration(_) | Statement::ClassDeclaration(_) => false,
// import/export 与无子表达式的语句(break/continue/debugger/empty)不含顶层 await。
_ => false,
}
}
/// `for-in`/`for-of` 左值顶层 `await` 游走:变量声明形态游走初始化器,
/// 其余形态(绑定目标)经 `target_has_top_level_await` 游走。
fn for_left_has_top_level_await(left: &ForStatementLeft) -> bool {
match left {
ForStatementLeft::VariableDeclaration(vd) => vd
.declarations
.iter()
.any(|d| d.init.as_ref().is_some_and(|i| expr_has_top_level_await(i))),
_ => left.as_assignment_target().is_some_and(target_has_top_level_await),
}
}
/// 赋值目标顶层 `await` 游走:模式目标递归进元素/属性,简单目标(标识符、
/// 成员、TS 包装)经 `simple_target_has_top_level_await` 游走。
fn target_has_top_level_await(target: &AssignmentTarget) -> bool {
match target {
AssignmentTarget::ArrayAssignmentTarget(arr) => arr
.elements
.iter()
.flatten()
.any(|e| target_maybe_default_has_top_level_await(e))
|| arr
.rest
.as_ref()
.is_some_and(|r| target_has_top_level_await(&r.target)),
AssignmentTarget::ObjectAssignmentTarget(obj) => {
obj.properties.iter().any(|p| match p {
AssignmentTargetProperty::AssignmentTargetPropertyIdentifier(id) => id
.init
.as_ref()
.is_some_and(|i| expr_has_top_level_await(i)),
AssignmentTargetProperty::AssignmentTargetPropertyProperty(prop) => {
prop.name
.as_expression()
.is_some_and(expr_has_top_level_await)
|| target_maybe_default_has_top_level_await(&prop.binding)
}
})
|| obj
.rest
.as_ref()
.is_some_and(|r| target_has_top_level_await(&r.target))
}
_ => target
.as_simple_assignment_target()
.is_some_and(simple_target_has_top_level_await),
}
}
/// 简单赋值目标顶层 `await` 游走:计算成员键是可求值子表达式,TS 包装进入内层,
/// 纯标识符无子表达式。
fn simple_target_has_top_level_await(t: &SimpleAssignmentTarget) -> bool {
match t {
SimpleAssignmentTarget::ComputedMemberExpression(m) => {
expr_has_top_level_await(&m.object) || expr_has_top_level_await(&m.expression)
}
SimpleAssignmentTarget::StaticMemberExpression(m) => expr_has_top_level_await(&m.object),
SimpleAssignmentTarget::PrivateFieldExpression(m) => expr_has_top_level_await(&m.object),
SimpleAssignmentTarget::TSAsExpression(e) => expr_has_top_level_await(&e.expression),
SimpleAssignmentTarget::TSSatisfiesExpression(e) => expr_has_top_level_await(&e.expression),
SimpleAssignmentTarget::TSNonNullExpression(e) => expr_has_top_level_await(&e.expression),
SimpleAssignmentTarget::TSTypeAssertion(e) => expr_has_top_level_await(&e.expression),
SimpleAssignmentTarget::AssignmentTargetIdentifier(_) => false,
}
}
/// 带默认值的赋值目标顶层 `await` 游走:默认值是可求值子表达式,
/// 绑定目标本身递归进 `target_has_top_level_await`。
fn target_maybe_default_has_top_level_await(t: &AssignmentTargetMaybeDefault) -> bool {
match t {
AssignmentTargetMaybeDefault::AssignmentTargetWithDefault(d) => {
target_has_top_level_await(&d.binding) || expr_has_top_level_await(&d.init)
}
_ => t.as_assignment_target().is_some_and(target_has_top_level_await),
}
}
/// 表达式级顶层 `await` 游走:命中 `AwaitExpression` 即真;进入子表达式容器,
/// 函数表达式/箭头/类表达式体不进入。
fn expr_has_top_level_await(expr: &Expression) -> bool {
match expr {
Expression::AwaitExpression(_) => true,
Expression::BinaryExpression(bin) => {
expr_has_top_level_await(&bin.left) || expr_has_top_level_await(&bin.right)
}
Expression::LogicalExpression(logic) => {
expr_has_top_level_await(&logic.left) || expr_has_top_level_await(&logic.right)
}
Expression::ConditionalExpression(cond) => {
expr_has_top_level_await(&cond.test)
|| expr_has_top_level_await(&cond.consequent)
|| expr_has_top_level_await(&cond.alternate)
}
Expression::CallExpression(call) => {
expr_has_top_level_await(&call.callee)
|| call
.arguments
.iter()
.any(|a| a.as_expression().is_some_and(expr_has_top_level_await))
}
Expression::NewExpression(new_expr) => {
expr_has_top_level_await(&new_expr.callee)
|| new_expr
.arguments
.iter()
.any(|a| a.as_expression().is_some_and(expr_has_top_level_await))
}
Expression::ComputedMemberExpression(m) => {
expr_has_top_level_await(&m.object) || expr_has_top_level_await(&m.expression)
}
Expression::StaticMemberExpression(m) => expr_has_top_level_await(&m.object),
Expression::PrivateFieldExpression(m) => expr_has_top_level_await(&m.object),
Expression::ChainExpression(chain) => chain_element_has_top_level_await(&chain.expression),
Expression::ArrayExpression(arr) => arr
.elements
.iter()
.any(|e| match e {
ArrayExpressionElement::SpreadElement(spread) => {
expr_has_top_level_await(&spread.argument)
}
_ => e.as_expression().is_some_and(expr_has_top_level_await),
}),
Expression::ObjectExpression(obj) => obj.properties.iter().any(|p| match p {
ObjectPropertyKind::ObjectProperty(prop) => {
(prop.computed
&& prop
.key
.as_expression()
.is_some_and(expr_has_top_level_await))
|| expr_has_top_level_await(&prop.value)
}
ObjectPropertyKind::SpreadProperty(spread) => expr_has_top_level_await(&spread.argument),
}),
Expression::SequenceExpression(seq) => {
seq.expressions.iter().any(|e| expr_has_top_level_await(e))
}
Expression::TemplateLiteral(tmpl) => {
tmpl.expressions.iter().any(|e| expr_has_top_level_await(e))
}
Expression::TaggedTemplateExpression(tagged) => {
expr_has_top_level_await(&tagged.tag)
|| tagged.quasi.expressions.iter().any(|e| expr_has_top_level_await(e))
}
// 赋值左值是绑定目标(计算成员键可含可求值子表达式),右值与左值目标都游走。
Expression::AssignmentExpression(assign) => {
target_has_top_level_await(&assign.left) || expr_has_top_level_await(&assign.right)
}
Expression::UpdateExpression(update) => {
simple_target_has_top_level_await(&update.argument)
}
Expression::UnaryExpression(unary) => expr_has_top_level_await(&unary.argument),
Expression::ParenthesizedExpression(paren) => expr_has_top_level_await(&paren.expression),
Expression::YieldExpression(yield_expr) => yield_expr
.argument
.as_ref()
.is_some_and(|a| expr_has_top_level_await(a)),
Expression::PrivateInExpression(private_in) => expr_has_top_level_await(&private_in.right),
Expression::ImportExpression(import_expr) => {
expr_has_top_level_await(&import_expr.source)
|| import_expr
.options
.as_ref()
.is_some_and(|o| expr_has_top_level_await(o))
}
// 函数体:独立异步语义边界,不进入。
Expression::FunctionExpression(_)
| Expression::ArrowFunctionExpression(_)
| Expression::ClassExpression(_) => false,
// 字面量/标识符/this/super/meta 等无子表达式。
_ => false,
}
}
/// 可选链元素顶层 `await` 游走:链元素是成员/调用/TS 非空形态,逐一进入子表达式。
fn chain_element_has_top_level_await(element: &ChainElement) -> bool {
match element {
ChainElement::CallExpression(call) => {
expr_has_top_level_await(&call.callee)
|| call
.arguments
.iter()
.any(|a| a.as_expression().is_some_and(expr_has_top_level_await))
}
ChainElement::TSNonNullExpression(non_null) => expr_has_top_level_await(&non_null.expression),
ChainElement::ComputedMemberExpression(computed) => {
expr_has_top_level_await(&computed.object) || expr_has_top_level_await(&computed.expression)
}
ChainElement::StaticMemberExpression(static_member) => {
expr_has_top_level_await(&static_member.object)
}
ChainElement::PrivateFieldExpression(private_field) => {
expr_has_top_level_await(&private_field.object)
}
}
}
/// 合成默认导出的源绑定名(匿名 default 函数/类与 default 表达式共用)。
/// 含 `*`,与任何用户标识符都不可能重名。
pub(crate) const SYNTHETIC_DEFAULT_BINDING: &str = "*default*";
@@ -526,6 +824,12 @@ impl Emitter {
let own_export_names = module_own_export_names(body);
let var_scoped_export_names = module_var_scoped_export_names(body);
// 本模块自身顶层 `await` 标志(`[[HasTLA]]`):决定本模块是否按异步求值编译。
let own_tla = module_has_top_level_await(body);
// 异步 eager 依赖的 (spec, `__moduleEval` 返回的 promise 寄存器):prelude
// 聚合 gate 消费。defer-only 依赖不求值、不产生 promise,不入此集。
let mut async_dep_promises: Vec<(String, u32)> = Vec::new();
// —— 编译并求值依赖:eager 组先行(按 eager 语句序),defer-only 组随后 ——
for spec in eager_order {
let phase = &phase_map[&spec];
@@ -540,19 +844,21 @@ impl Emitter {
return Err(format!("circular module import not supported: {}", resolved.path));
}
path_stack.push(resolved.path.clone());
let (dep_ir, dep_reassignable, dep_own_names, dep_var_scoped) = match resolved.kind {
let (dep_ir, dep_reassignable, dep_own_names, dep_var_scoped, dep_eval_async) = match resolved.kind {
ModuleKind::Js => self.compile_js_dep(&resolved, loader, path_stack)?,
ModuleKind::Json => (
self.compile_data_dep("json", &resolved.source)?,
false,
HashSet::from([DEFAULT_EXPORT_NAME.to_string()]),
HashSet::from([DEFAULT_EXPORT_NAME.to_string()]),
false,
),
ModuleKind::Text => (
self.compile_data_dep("text", &resolved.source)?,
false,
HashSet::from([DEFAULT_EXPORT_NAME.to_string()]),
HashSet::from([DEFAULT_EXPORT_NAME.to_string()]),
false,
),
ModuleKind::Bytes => return Err("bytes module not supported".into()),
};
@@ -562,6 +868,11 @@ impl Emitter {
let fn_reg = ctx.alloc_reg();
ctx.inst(Inst::create_closure(Operand::Reg(fn_reg), ctx.nested.len() as u16));
let real_ns = self.emit_module_call(ctx, "__moduleEval", &[fn_reg])?;
// 异步依赖:`__moduleEval` 返回 capability promise(非命名空间),
// 登记进聚合 gate;命名空间在 gate 后从 promise 结算值提取。
if dep_eval_async {
async_dep_promises.push((spec.clone(), real_ns));
}
(real_ns, Some(fn_reg), dep_own_names, dep_var_scoped)
};
ctx.module_dep_ns_regs.insert(spec.clone(), dep_ns_reg);
@@ -586,6 +897,11 @@ impl Emitter {
}
}
// 本模块异步求值标志:自身含顶层 `await`,或任一 eager 依赖按异步求值
// (传递异步经 `dep_eval_async` 递归回传),模块体按合成异步函数编译
// (`assemble_ir` 据此回写 IR 的 `is_async`)。非 TLA 模块恒 false,零 diff。
ctx.is_async = own_tla || !async_dep_promises.is_empty();
// defer-only 组(eager == false 的 spec,按 defer_order):不求值、不发
// __moduleEval。祖先判定(自导入或父链回边)命中时发哨兵形态
// __moduleDeferObject(undefined, undefined)——不递归、不压 path_stack、不编译;
@@ -608,19 +924,21 @@ impl Emitter {
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 {
let (dep_ir, _dep_reassignable, dep_own_names, dep_var_scoped, _dep_eval_async) = match resolved.kind {
ModuleKind::Js => self.compile_js_dep(&resolved, loader, path_stack)?,
ModuleKind::Json => (
self.compile_data_dep("json", &resolved.source)?,
false,
HashSet::from([DEFAULT_EXPORT_NAME.to_string()]),
HashSet::from([DEFAULT_EXPORT_NAME.to_string()]),
false,
),
ModuleKind::Text => (
self.compile_data_dep("text", &resolved.source)?,
false,
HashSet::from([DEFAULT_EXPORT_NAME.to_string()]),
HashSet::from([DEFAULT_EXPORT_NAME.to_string()]),
false,
),
ModuleKind::Bytes => return Err("bytes module not supported".into()),
};
@@ -637,6 +955,30 @@ impl Emitter {
}
}
// —— 聚合 gate:异步依赖的 `__moduleEval` 返回 capability promise(非命名空间),
// 其命名空间在 gate 后从结算值提取。单 AWAIT 挂起模块体直至全部异步依赖结算
// (由 drain 微任务释放),非 TLA 模块此集为空、零 IR 变化。——
if !async_dep_promises.is_empty() {
let promise_regs: Vec<u32> = async_dep_promises.iter().map(|(_, r)| *r).collect();
let gate_reg = self.emit_module_call(ctx, "__moduleWaitAll", &promise_regs)?;
ctx.inst(Inst::await_expr(Operand::Reg(gate_reg)));
// promise settle 后恢复值(结算值数组)经 reg 0 交付(与 YIELD/CALL 同协议)。
let settled_reg = ctx.alloc_reg();
ctx.inst(Inst::new(OpCode::LOAD_VAR, Operand::Reg(settled_reg), Operand::None, Operand::None));
// 逐依赖从结算数组提取命名空间,覆盖链接寄存器(原为 promise)。
for (i, (spec, _)) in async_dep_promises.iter().enumerate() {
let idx_reg = self.load_string_const(&i.to_string(), ctx);
let ns_reg = ctx.alloc_reg();
ctx.inst(Inst::new(
OpCode::GET_PROP_DYNAMIC,
Operand::Reg(settled_reg),
Operand::Reg(idx_reg),
Operand::Reg(ns_reg),
));
ctx.module_dep_ns_regs.insert(spec.clone(), ns_reg);
}
}
// —— 导入绑定初始化(普通依赖为链接期快照;命名空间绑定直接引用 ns 对象;
// defer 命名空间绑定引用 deferred 对象;自导入绑定解析为本模块源绑定的活别名)——
// 无命名 `export * from 'x'` 会把依赖的全部导出转发给自身;自导入名可能来自
@@ -951,18 +1293,21 @@ impl Emitter {
}
/// 编译 JS 依赖模块(递归),回传 IR、「是否含可重赋导出」标志、
/// 自身静态导出名集与 var 作用域导出名集。
/// 自身静态导出名集、var 作用域导出名集与「是否异步求值」标志。
///
/// # 边界与前提
/// - 可重赋标志取自依赖 ctx 的 `module_live_dep`;入口模块不参与,依赖模块恒按
/// `!top_level` 判定,故 const-only 依赖回传 false。
/// - 导出名集在函数内对解析产物就地计算,供导入方 defer 预注册消费。
/// - 异步求值标志取自依赖 ctx 的 `is_async`(依赖自身含顶层 `await` 或含异步
/// 传递依赖时为真),供导入方判定是否需 prelude 聚合 gate。
///
/// # 注意事项
/// - 导入方据标志决定是否登记活读映射;标志不改变本模块 IR。
/// - 导入方据标志决定是否登记活读映射与聚合 gate;标志不改变本模块 IR。
#[allow(clippy::type_complexity)]
fn compile_js_dep(
&self, resolved: &ResolvedModule, loader: &mut dyn ModuleSourceLoader, path_stack: &mut Vec<String>,
) -> Result<(IRFunction, bool, HashSet<String>, HashSet<String>), String> {
) -> Result<(IRFunction, bool, HashSet<String>, HashSet<String>, bool), String> {
// 线程本地分配器:依赖模块递归解析共享同一分配器,
// 重入深度守卫防止嵌套 reset 销毁外层 AST。
oxide_parser::with_parse_allocator(|alloc| {
@@ -978,6 +1323,7 @@ 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;
let eval_async = ctx.is_async;
let own_export_names = module_own_export_names(&program.body);
let var_scoped = module_var_scoped_export_names(&program.body);
Ok((
@@ -985,6 +1331,7 @@ impl Emitter {
reassignable,
own_export_names,
var_scoped,
eval_async,
))
})
}
@@ -473,3 +473,107 @@ fn no_defer_object_for_non_defer_modules() {
assert_eq!(native_calls_to(&ir, "__moduleDeferObject"), 0, "非 defer 模块不得构造 deferred 对象");
assert_eq!(native_calls_to(&ir, "__modulePreRegister"), 0, "非 defer 模块不得预注册依赖");
}
/// 面 19:模块自身顶层 `await` 使 `is_async` 为真,体 await 编译为 AWAIT;
/// 无异步依赖时不发聚合 gate。
#[test]
fn tla_module_compiles_async_without_gate() {
let (ir, _) = emit_module(
"const x = await Promise.resolve(1); export { x };",
"./entry.js",
&[],
)
.expect("TLA 模块应编译成功");
assert!(ir.is_async, "含顶层 await 的模块应标记异步求值");
assert_eq!(
ir.insts.iter().filter(|i| i.op == OpCode::AWAIT).count(),
1,
"顶层 await 应编译为一条 AWAIT"
);
assert_eq!(native_calls_to(&ir, "__moduleWaitAll"), 0, "无异步依赖不得发聚合 gate");
}
/// 面 20:无顶层 `await` 的模块保持同步编译(`is_async` 假、主身零 AWAIT);
/// 异步函数体内的 await 不使模块变异步(await 落在嵌套子模块)。
#[test]
fn non_tla_module_stays_sync() {
let (ir, _) = emit_module(
"async function f() { return await Promise.resolve(1); } export { f };",
"./entry.js",
&[],
)
.expect("非 TLA 模块应编译成功");
assert!(!ir.is_async, "无顶层 await 的模块不得标记异步");
assert_eq!(
ir.insts.iter().filter(|i| i.op == OpCode::AWAIT).count(),
0,
"主身不得含 AWAIT"
);
}
/// 面 21:`for await…of` 在模块代码使模块异步(规范强制模块异步求值,
/// `await` 关键字触发 [[HasTLA]];右值与体照常游走)。
#[test]
fn for_await_of_makes_module_async() {
let (ir, _) = emit_module(
"for await (const x of iter) { globalThis.v = x; }",
"./entry.js",
&[],
)
.expect("for await…of 模块应编译成功");
assert!(ir.is_async, "for await…of 应使模块标记异步");
}
/// 面 22:普通 `for…of`(无 `await`)不使模块异步,主身零 AWAIT。
#[test]
fn for_of_is_not_tla() {
let (ir, _) = emit_module(
"for (const x of iter) { globalThis.v = x; }",
"./entry.js",
&[],
)
.expect("for…of 模块应编译成功");
assert!(!ir.is_async, "普通 for…of 不得使模块标记异步");
assert_eq!(
ir.insts.iter().filter(|i| i.op == OpCode::AWAIT).count(),
0,
"主身不得含 AWAIT"
);
}
/// 面 23:异步 eager 依赖聚合 gate——依赖含顶层 `await` 时 `__moduleEval` 返回
/// capability promise,导入方发 `__moduleWaitAll` 加单 AWAIT 挂起,模块标记异步。
#[test]
fn async_dep_emits_wait_all_gate() {
let (ir, _) = emit_module(
"import { x } from \"./dep.js\"; export { x };",
"./entry.js",
&[("./dep.js", ModuleKind::Js, "const v = await Promise.resolve(1); export const x = v;")],
)
.expect("含异步依赖的模块应编译成功");
assert!(ir.is_async, "含异步依赖的导入方应标记异步求值");
assert_eq!(native_calls_to(&ir, "__moduleWaitAll"), 1, "聚合 gate 应发一次");
assert_eq!(
ir.insts.iter().filter(|i| i.op == OpCode::AWAIT).count(),
1,
"gate 应以单 AWAIT 挂起"
);
}
/// 面 24:同步依赖零 diff 守卫——无 gate、无 AWAIT、模块保持同步。
#[test]
fn sync_dep_no_gate() {
let (ir, _) = emit_module(
"import { x } from \"./dep.js\"; export { x };",
"./entry.js",
&[("./dep.js", ModuleKind::Js, "export const x = 1;")],
)
.expect("含同步依赖的模块应编译成功");
assert!(!ir.is_async, "无顶层 await 且依赖同步的模块不得标记异步");
assert_eq!(native_calls_to(&ir, "__moduleWaitAll"), 0, "同步依赖不得发聚合 gate");
assert_eq!(
ir.insts.iter().filter(|i| i.op == OpCode::AWAIT).count(),
0,
"主身不得含 AWAIT"
);
}
@@ -1,6 +1,13 @@
use oxide_runtime_api::NativeResult;
use oxide_types::object::JsObject;
use crate::bindings::{apply_binding_table, BindEnv};
use crate::vm::Vm;
/// `__moduleWaitAll` 原生入口:委托 `Vm::module_wait_all`(聚合 gate,见 promise 模块)。
fn module_wait_all(vm: &mut Vm, args: &[u8]) -> NativeResult {
vm.module_wait_all(args)
}
/// 把普通全局函数(`isNaN`、`parseInt`、`decodeURIComponent` 等)绑定到 global。
pub fn bind_global(env: BindEnv<'_>, global: &mut JsObject) {
@@ -56,6 +63,7 @@ pub fn bind_global(env: BindEnv<'_>, global: &mut JsObject) {
2,
),
("__moduleData", oxide_builtins::module::module_data::<crate::vm::Vm> as *const (), 2),
("__moduleWaitAll", module_wait_all as *const (), 0),
("eval", oxide_builtins::eval::eval::<crate::vm::Vm> as *const (), 1),
(
"structuredClone",
+30
View File
@@ -163,6 +163,36 @@ impl Vm {
JsValue::from_js_object(ptr)
}
/// `__moduleWaitAll(p1, p2, ...)`:模块求值聚合 gate。等待全部实参 promise
/// 结算后以结算值数组完成新 promise,任一实参拒绝则拒绝。
///
/// # 步骤
/// 1. 按实参序收集各 promise 值(`args[0]` 为实参个数,`args[1..]` 为寄存器下标)。
/// 2. 以实参 promise 建数组,经 `Promise.all` 共享聚合路径(`perform_promise_combine`)
/// 结算:全部完成时以结算值数组完成,任一拒绝时拒绝。
///
/// # 边界与前提
/// - 实参须为 promise(模块依赖的 capability promise);非 promise 由
/// `Promise.all` 的 `C.resolve` 包装为已完成 promise,语义不变。
///
/// # 副作用
/// - 新建聚合 promise 与记录对象;结算反应入微任务队列。
pub fn module_wait_all(&mut self, args: &[u8]) -> NativeResult {
let n = args.len().saturating_sub(1);
let mut promises = Vec::with_capacity(n);
for i in 0..n {
promises.push(self.reg(args[i + 1]));
}
let array = self.make_plain_array(promises);
let ctor = JsValue::from_js_object(
self.realm.promise_constructor.borrow().as_ptr() as *mut JsObject,
);
match perform_promise_combine(self, ctor, array, AggregateKind::All) {
Ok(promise) => NativeResult::Ok(promise),
Err(err) => NativeResult::Err(err),
}
}
/// 建 Promise.try 的包装闭包 W:native 函数对象,executor 与转发实参数组挂
/// 自身属性(GC 边走属性区,免 native_data 接线);W 被构造器以
/// (resolve, reject) 实参调用。