feat: 生成器基础支持(YIELD 帧快照挂起/恢复 + GeneratorPrototype next/return/throw)

- 新增 YIELD/SUSPEND_BODY opcode;function* 识别与 yield emit
- GeneratorState 全量快照 VM 执行上下文(regs/pc/bytecode/spill/save/try/cell 栈段/迭代器)
- 调用时参数初始化(默认值/解构副作用与异常在 g() 时刻生效)
- %GeneratorPrototype%/%GeneratorFunction.prototype% 内建对象与 next/return/throw
- session GC trace 生成器状态 JsValues;闭包捕获分析补 yield/赋值目标扫描
This commit is contained in:
爱特每羊队
2026-08-09 18:02:08 +08:00
parent 7c2e9ec1ff
commit 6f80c12ac9
26 changed files with 1265 additions and 107 deletions
+13 -8
View File
@@ -19,6 +19,8 @@ impl Inst {
match self.op {
// CALL 系:结果隐式写 reg 0,rd 是 callee 的 use
OpCode::CALL | OpCode::CALL_NATIVE | OpCode::CALL_SPREAD => Some(0),
// YIELD:恢复时 next(v) 的 v 经 reg 0 交付(与 CALL 同协议)
OpCode::YIELD => Some(0),
// GET_PROP 系:结果写 a/b 槽而非 rd
OpCode::GET_PROP | OpCode::IC_GET_PROP => reg_of(&self.a),
OpCode::GET_PROP_DYNAMIC => reg_of(&self.b),
@@ -70,7 +72,8 @@ impl Inst {
| OpCode::FOR_IN_INIT
| OpCode::FOR_OF_INIT
| OpCode::FOR_IN_CLEANUP
| OpCode::FOR_OF_CLOSE => None,
| OpCode::FOR_OF_CLOSE
| OpCode::SUSPEND_BODY => None,
// 其余指令 rd 即 def(算术/比较/位/逻辑/加载族/迭代器 NEXT 等)
_ => reg_of(&self.rd),
}
@@ -208,7 +211,7 @@ impl Inst {
OpCode::NEG | OpCode::NOT | OpCode::UNARY_PLUS | OpCode::BIT_NOT | OpCode::TYPEOF => {
push_operand(&mut uses, &self.a);
}
// 无条件跳转 / try 标记:b 是 Label,无寄存器
// 无条件跳转 / try 标记 / 生成器 body 标记:无寄存器
OpCode::JMP
| OpCode::BREAK
| OpCode::CONTINUE
@@ -217,15 +220,16 @@ impl Inst {
| OpCode::TRY_END
| OpCode::TRY_FINALLY_END
| OpCode::FOR_IN_CLEANUP
| OpCode::FOR_OF_CLOSE => {}
| OpCode::FOR_OF_CLOSE
| OpCode::SUSPEND_BODY => {}
// 条件跳转:rd=cond
OpCode::JMP_IF_FALSE | OpCode::JMP_IF_TRUE | OpCode::JMP_IF_NULLISH => {
push_operand(&mut uses, &self.rd);
}
// HALT:隐式读 reg 0(顶层返回值)
OpCode::HALT => uses.push(0),
// RETURN/THROW:读 rd(None→0)
OpCode::RETURN | OpCode::THROW => push_operand(&mut uses, &self.rd),
// RETURN/THROW/YIELD:读 rd(None→0)
OpCode::RETURN | OpCode::THROW | OpCode::YIELD => push_operand(&mut uses, &self.rd),
// 加载族:a 槽是 Const/Imm 立即数,无寄存器 use
OpCode::LOAD_CONST
| OpCode::CREATE_CLOSURE
@@ -611,9 +615,10 @@ mod tests {
#[test]
fn rest_object_uses_a() {
let inst = Inst::rest_object(Operand::Reg(0), Operand::Reg(1), 7);
let inst = Inst::rest_object(Operand::Reg(0), Operand::Reg(1), 7, None);
assert_eq!(inst.def_reg(), Some(0));
assert_eq!(inst.use_regs().as_slice(), &[1]);
// b 槽 None 映射 reg 0(excl_arr 缺省),REST_OBJECT 运行时同时读源与排除键。
assert_eq!(inst.use_regs().as_slice(), &[1, 0]);
}
#[test]
@@ -744,7 +749,7 @@ mod tests {
assert!(!Inst::new(OpCode::COMPOUND_ADD, Operand::Reg(0), Operand::Reg(1), Operand::None).is_pure(&f));
assert!(!Inst::new(OpCode::MEMBER_INC, Operand::Reg(0), Operand::Reg(1), Operand::Reg(2)).is_pure(&f));
assert!(!Inst::new(OpCode::COMPOUND_MEMBER_ADD, Operand::Reg(0), Operand::Reg(1), Operand::Reg(2)).is_pure(&f));
assert!(!Inst::rest_object(Operand::Reg(0), Operand::Reg(1), 7).is_pure(&f));
assert!(!Inst::rest_object(Operand::Reg(0), Operand::Reg(1), 7, None).is_pure(&f));
assert!(!Inst::new(OpCode::INSTANCEOF, Operand::Reg(0), Operand::Reg(1), Operand::Reg(2)).is_pure(&f));
assert!(!Inst::new(OpCode::IN, Operand::Reg(0), Operand::Reg(1), Operand::Reg(2)).is_pure(&f));
assert!(!Inst::new(OpCode::GET_PRIVATE, Operand::Reg(0), Operand::Reg(1), Operand::Reg(2)).is_pure(&f));
+12 -1
View File
@@ -267,6 +267,17 @@ impl Inst {
Self::new(OpCode::CREATE_ARGUMENTS, dst, Operand::None, Operand::None)
}
/// 生成器让出:`rd` 为被让出的值;恢复时 `next(v)` 的 `v` 经 reg 0 交付
/// (与 CALL 同协议,emit 用 `LOAD_VAR(None)` 读取)。
pub fn yield_value(src: Operand) -> Self {
Self::new(OpCode::YIELD, src, Operand::None, Operand::None)
}
/// 生成器 body 起点标记:调用时参数初始化完成后挂起于此,首次 `next()` 继续。
pub fn suspend_body() -> Self {
Self::new(OpCode::SUSPEND_BODY, Operand::None, Operand::None, Operand::None)
}
// ── 跳转族:label 放 b 槽,offset 计算是 lowering 职责 ──
/// 无条件跳转。label 放 b 槽,offset 由 lowering 回填。
@@ -384,7 +395,7 @@ mod tests {
assert_eq!(accessor.a, Operand::Reg(1));
assert_eq!(accessor.b, Operand::Reg(2));
let rest = Inst::rest_object(Operand::Reg(0), Operand::Reg(1), 7);
let rest = Inst::rest_object(Operand::Reg(0), Operand::Reg(1), 7, None);
assert_eq!(rest.ext.as_slice(), &[7]);
let spread = Inst::spread_object(Operand::Reg(0), Operand::Reg(1));
+3
View File
@@ -50,6 +50,8 @@ pub struct IRFunction {
pub is_class_constructor: bool,
pub is_derived_constructor: bool,
pub needs_home_object: bool,
/// 是否为生成器函数体(`function*`)。
pub is_generator: bool,
pub captured_this_const_idx: u16,
pub function_name: Option<String>,
/// 函数 `length` 属性值:第一个带默认值/解构默认的形参之前的形参数(rest 不计)。
@@ -80,6 +82,7 @@ impl IRFunction {
is_class_constructor: false,
is_derived_constructor: false,
needs_home_object: false,
is_generator: false,
captured_this_const_idx: 0,
function_name: None,
function_length: 0,
+1
View File
@@ -89,6 +89,7 @@ pub fn lower(f: &IRFunction) -> Result<CompiledModule, String> {
is_class_constructor: f.is_class_constructor,
is_derived_constructor: f.is_derived_constructor,
needs_home_object: f.needs_home_object,
is_generator: f.is_generator,
upvalue_captures: f.upvalue_captures.clone(),
cells_needed: f.cells_needed,
flat_id: 0,