fix: for-of/for-in 提前退出时按规范顺序完成 IteratorClose
return/break/continue 逃出 for-of 时此前完全不执行 IteratorClose: BREAK/CONTINUE/RETURN 指令现在经 ext 字携带词法逃出的迭代器层数 (for-of + for-in 各 16 位),运行时在全部 finally 穿越之后、真正 跳转/返回之前按 LIFO 关闭——与规范 §13.7.5.4(循环体完成值已含 内部 try-finally 处理,IteratorClose 在后)顺序一致。 - emit 词法:LabelCtx 增加 for-of/for-in 深度计数,loop/switch/label 打开时快照,break/continue/return 按当前深度减目标深度计算逃出层数 (switch 内 break 以 switch 打开点为基准,目标循环自身不计入) - 指令编码:brk/cont/ret 三参构造,lower 跳转路径补发 ext 字 - 运行时:dispatch_break/continue/return 读取逃出计数,无 finally 时 直接关闭后跳转/返回,有 finally 时随 Completion 悬挂由 TRY_FINALLY_END 在穿越完成后消费;生成器 .return()/.throw() 注入经 complete_generator_return 全关快照栈迭代器;return() 抛错经 unwind 替代完成值并关闭剩余迭代器 - 顺带:for-in 逃出残留(无 return() 语义,仅弹栈);for-await-of 的 异步迭代器不做同步关闭(return() promise 须 await,走异步机制) - 新增 15 项回归测试:return/labeled break/continue/switch/while/finally 顺序/抛错优先/生成器注入/for-in/for-await-of 嵌套
This commit is contained in:
@@ -368,14 +368,40 @@ impl Inst {
|
||||
|
||||
/// break 完成:label 指向循环/switch 出口,`crossed` 为逃出的 finally 域数
|
||||
/// (emit 词法计算,运行时据此逐个穿越 finally;0 表示未逃出,不产生完成语义)。
|
||||
/// 编码:rd 槽放 crossed(≤255),label 放 b 槽。
|
||||
pub fn brk(label: LabelId, crossed: u16) -> Self {
|
||||
Self::new(OpCode::BREAK, Operand::Imm(crossed), Operand::None, Operand::Label(label))
|
||||
/// `for_of_count`/`for_in_count` 为逃出的迭代器层数,编码进 ext 字——
|
||||
/// BREAK/CONTINUE 的 a/b 槽被跳转 offset 占用,无空闲位。
|
||||
/// 编码:rd 槽放 crossed(≤255),label 放 b 槽,ext[0] 打包两个逃出计数。
|
||||
pub fn brk(label: LabelId, crossed: u16, for_of_count: usize, for_in_count: usize) -> Self {
|
||||
Self::with_ext(
|
||||
OpCode::BREAK,
|
||||
Operand::Imm(crossed),
|
||||
Operand::None,
|
||||
Operand::Label(label),
|
||||
&[pack_escape_counts(for_of_count, for_in_count)],
|
||||
)
|
||||
}
|
||||
|
||||
/// continue 完成:同 break,label 指向循环继续目标。
|
||||
pub fn cont(label: LabelId, crossed: u16) -> Self {
|
||||
Self::new(OpCode::CONTINUE, Operand::Imm(crossed), Operand::None, Operand::Label(label))
|
||||
pub fn cont(label: LabelId, crossed: u16, for_of_count: usize, for_in_count: usize) -> Self {
|
||||
Self::with_ext(
|
||||
OpCode::CONTINUE,
|
||||
Operand::Imm(crossed),
|
||||
Operand::None,
|
||||
Operand::Label(label),
|
||||
&[pack_escape_counts(for_of_count, for_in_count)],
|
||||
)
|
||||
}
|
||||
|
||||
/// return 完成:`src` 为返回值寄存器(None = 隐式 undefined,reg 0)。
|
||||
/// `for_of_count`/`for_in_count` 为逃出的迭代器层数,编码进 ext 字。
|
||||
pub fn ret(src: Operand, for_of_count: usize, for_in_count: usize) -> Self {
|
||||
Self::with_ext(
|
||||
OpCode::RETURN,
|
||||
src,
|
||||
Operand::None,
|
||||
Operand::None,
|
||||
&[pack_escape_counts(for_of_count, for_in_count)],
|
||||
)
|
||||
}
|
||||
|
||||
/// 条件寄存器为 false 时跳转。
|
||||
@@ -409,6 +435,12 @@ impl Inst {
|
||||
}
|
||||
}
|
||||
|
||||
/// 把逃出的 for-of / for-in 层数打包进一个 ext 字:低 16 位 for-of,高 16 位 for-in。
|
||||
/// 层数受寄存器上限约束(每层循环消耗若干 vreg),16 位覆盖远超实际可能。
|
||||
fn pack_escape_counts(for_of_count: usize, for_in_count: usize) -> u32 {
|
||||
((for_in_count.min(0xFFFF) as u32) << 16) | (for_of_count.min(0xFFFF) as u32)
|
||||
}
|
||||
|
||||
/// spread 调用系 ext 构造:首字打包 `nstatic | (nspread << 8)`,后续按源码求值序排列
|
||||
/// 每个实参字(静态实参 = 寄存器号,spread 源 = `0x8000_0000 | 寄存器号`)。
|
||||
fn spread_ext(words: &[u32]) -> SmallVec<[u32; 4]> {
|
||||
|
||||
@@ -142,6 +142,9 @@ fn encode_inst(inst: &Inst, instrs: &mut Vec<u32>, jumps: &mut Vec<(usize, u32)>
|
||||
_ => unreachable!("is_jump_op mismatch"),
|
||||
};
|
||||
instrs.push(instr);
|
||||
// BREAK/CONTINUE 携带逃出迭代器层数的 ext 字;offset 回填只改写首条指令,
|
||||
// ext 字随指令长度计入后续偏移(inst_to_instr 已含 ext)。
|
||||
instrs.extend_from_slice(&inst.ext);
|
||||
jumps.push((start, label));
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user