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:
@@ -324,6 +324,150 @@ impl Emitter {
|
||||
}
|
||||
}
|
||||
|
||||
/// 扫描赋值目标中的引用(标识符写名,成员目标扫对象/键,解构目标递归元素)。
|
||||
fn collect_capture_names_assign_target(
|
||||
&self, target: &oxide_parser::AssignmentTarget, ref_set: &HashSet<String>, shadow: &HashSet<String>,
|
||||
out: &mut HashSet<String>,
|
||||
) {
|
||||
match target {
|
||||
oxide_parser::AssignmentTarget::AssignmentTargetIdentifier(ati) => {
|
||||
let name = ati.name.as_str();
|
||||
if ref_set.contains(name) && !shadow.contains(name) {
|
||||
out.insert(ati.name.to_string());
|
||||
}
|
||||
}
|
||||
oxide_parser::AssignmentTarget::StaticMemberExpression(m) => {
|
||||
self.collect_capture_names_expr(&m.object, ref_set, shadow, out);
|
||||
}
|
||||
oxide_parser::AssignmentTarget::ComputedMemberExpression(m) => {
|
||||
self.collect_capture_names_expr(&m.object, ref_set, shadow, out);
|
||||
self.collect_capture_names_expr(&m.expression, ref_set, shadow, out);
|
||||
}
|
||||
oxide_parser::AssignmentTarget::ArrayAssignmentTarget(a) => {
|
||||
for elem in &a.elements {
|
||||
if let Some(e) = elem {
|
||||
self.collect_capture_names_maybe_default_target(e, ref_set, shadow, out);
|
||||
}
|
||||
}
|
||||
if let Some(rest) = &a.rest {
|
||||
self.collect_capture_names_assign_target(&rest.target, ref_set, shadow, out);
|
||||
}
|
||||
}
|
||||
oxide_parser::AssignmentTarget::ObjectAssignmentTarget(o) => {
|
||||
for prop in &o.properties {
|
||||
if let oxide_parser::AssignmentTargetProperty::AssignmentTargetPropertyIdentifier(id) = prop {
|
||||
if ref_set.contains(id.binding.name.as_str()) && !shadow.contains(id.binding.name.as_str()) {
|
||||
out.insert(id.binding.name.to_string());
|
||||
}
|
||||
if let Some(init) = &id.init {
|
||||
self.collect_capture_names_expr(init, ref_set, shadow, out);
|
||||
}
|
||||
} else if let oxide_parser::AssignmentTargetProperty::AssignmentTargetPropertyProperty(p) = prop {
|
||||
if let Some(name_expr) = p.name.as_expression() {
|
||||
self.collect_capture_names_expr(name_expr, ref_set, shadow, out);
|
||||
}
|
||||
self.collect_capture_names_maybe_default_target(&p.binding, ref_set, shadow, out);
|
||||
}
|
||||
}
|
||||
if let Some(rest) = &o.rest {
|
||||
self.collect_capture_names_assign_target(&rest.target, ref_set, shadow, out);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
/// 解构赋值元素可能是 `AssignmentTarget` 或带默认值的包装(后者多一层 `init`)。
|
||||
fn collect_capture_names_maybe_default_target(
|
||||
&self, target: &oxide_parser::AssignmentTargetMaybeDefault, ref_set: &HashSet<String>,
|
||||
shadow: &HashSet<String>, out: &mut HashSet<String>,
|
||||
) {
|
||||
use oxide_parser::AssignmentTargetMaybeDefault as MaybeDefault;
|
||||
match target {
|
||||
MaybeDefault::AssignmentTargetWithDefault(d) => {
|
||||
self.collect_capture_names_expr(&d.init, ref_set, shadow, out);
|
||||
self.collect_capture_names_assign_target(&d.binding, ref_set, shadow, out);
|
||||
}
|
||||
MaybeDefault::AssignmentTargetIdentifier(ati) => {
|
||||
let name = ati.name.as_str();
|
||||
if ref_set.contains(name) && !shadow.contains(name) {
|
||||
out.insert(ati.name.to_string());
|
||||
}
|
||||
}
|
||||
MaybeDefault::StaticMemberExpression(m) => {
|
||||
self.collect_capture_names_expr(&m.object, ref_set, shadow, out);
|
||||
}
|
||||
MaybeDefault::ComputedMemberExpression(m) => {
|
||||
self.collect_capture_names_expr(&m.object, ref_set, shadow, out);
|
||||
self.collect_capture_names_expr(&m.expression, ref_set, shadow, out);
|
||||
}
|
||||
MaybeDefault::ArrayAssignmentTarget(a) => {
|
||||
for elem in &a.elements {
|
||||
if let Some(e) = elem {
|
||||
self.collect_capture_names_maybe_default_target(e, ref_set, shadow, out);
|
||||
}
|
||||
}
|
||||
}
|
||||
MaybeDefault::ObjectAssignmentTarget(o) => {
|
||||
for prop in &o.properties {
|
||||
if let oxide_parser::AssignmentTargetProperty::AssignmentTargetPropertyIdentifier(id) = prop {
|
||||
if ref_set.contains(id.binding.name.as_str()) && !shadow.contains(id.binding.name.as_str()) {
|
||||
out.insert(id.binding.name.to_string());
|
||||
}
|
||||
if let Some(init) = &id.init {
|
||||
self.collect_capture_names_expr(init, ref_set, shadow, out);
|
||||
}
|
||||
} else if let oxide_parser::AssignmentTargetProperty::AssignmentTargetPropertyProperty(p) = prop {
|
||||
if let Some(name_expr) = p.name.as_expression() {
|
||||
self.collect_capture_names_expr(name_expr, ref_set, shadow, out);
|
||||
}
|
||||
self.collect_capture_names_maybe_default_target(&p.binding, ref_set, shadow, out);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
/// 扫描一元更新目标(`++x` / `obj.x++`)中的引用。
|
||||
fn collect_capture_names_simple_target(
|
||||
&self, target: &oxide_parser::SimpleAssignmentTarget, ref_set: &HashSet<String>, shadow: &HashSet<String>,
|
||||
out: &mut HashSet<String>,
|
||||
) {
|
||||
match target {
|
||||
oxide_parser::SimpleAssignmentTarget::AssignmentTargetIdentifier(ati) => {
|
||||
let name = ati.name.as_str();
|
||||
if ref_set.contains(name) && !shadow.contains(name) {
|
||||
out.insert(ati.name.to_string());
|
||||
}
|
||||
}
|
||||
oxide_parser::SimpleAssignmentTarget::StaticMemberExpression(m) => {
|
||||
self.collect_capture_names_expr(&m.object, ref_set, shadow, out);
|
||||
}
|
||||
oxide_parser::SimpleAssignmentTarget::ComputedMemberExpression(m) => {
|
||||
self.collect_capture_names_expr(&m.object, ref_set, shadow, out);
|
||||
self.collect_capture_names_expr(&m.expression, ref_set, shadow, out);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
/// `collect_captured_expr` 侧的赋值目标扫描:父绑定集合即 ref_set,无遮蔽。
|
||||
fn collect_captured_assign_target(
|
||||
&self, target: &oxide_parser::AssignmentTarget, own: &HashSet<String>, out: &mut HashSet<String>,
|
||||
) {
|
||||
let empty = HashSet::new();
|
||||
self.collect_capture_names_assign_target(target, own, &empty, out);
|
||||
}
|
||||
|
||||
/// `collect_captured_expr` 侧的一元更新目标扫描。
|
||||
fn collect_captured_simple_target(
|
||||
&self, target: &oxide_parser::SimpleAssignmentTarget, own: &HashSet<String>, out: &mut HashSet<String>,
|
||||
) {
|
||||
let empty = HashSet::new();
|
||||
self.collect_capture_names_simple_target(target, own, &empty, out);
|
||||
}
|
||||
|
||||
/// 收集函数参数默认值表达式里的引用(子层 upvalue 判定;参数名遮蔽)。
|
||||
fn collect_fn_default_names(
|
||||
&self, params: &oxide_parser::FormalParameters, ref_set: &HashSet<String>, shadow: &HashSet<String>,
|
||||
@@ -349,21 +493,12 @@ impl Emitter {
|
||||
}
|
||||
}
|
||||
Expression::AssignmentExpression(ae) => {
|
||||
if let oxide_parser::AssignmentTarget::AssignmentTargetIdentifier(ati) = &ae.left {
|
||||
let name = ati.name.as_str();
|
||||
if ref_set.contains(name) && !shadow.contains(name) {
|
||||
out.insert(ati.name.to_string());
|
||||
}
|
||||
}
|
||||
// 赋值目标里的引用也须捕获:标识符目标写名,成员/解构目标扫描其对象/元素。
|
||||
self.collect_capture_names_assign_target(&ae.left, ref_set, shadow, out);
|
||||
self.collect_capture_names_expr(&ae.right, ref_set, shadow, out);
|
||||
}
|
||||
Expression::UpdateExpression(ue) => {
|
||||
if let oxide_parser::SimpleAssignmentTarget::AssignmentTargetIdentifier(ati) = &ue.argument {
|
||||
let name = ati.name.as_str();
|
||||
if ref_set.contains(name) && !shadow.contains(name) {
|
||||
out.insert(ati.name.to_string());
|
||||
}
|
||||
}
|
||||
self.collect_capture_names_simple_target(&ue.argument, ref_set, shadow, out);
|
||||
}
|
||||
Expression::FunctionExpression(fe) => {
|
||||
let body: &[Statement] = fe.body.as_ref().map(|b| &b.statements[..]).unwrap_or(&[]);
|
||||
@@ -453,6 +588,13 @@ impl Emitter {
|
||||
}
|
||||
}
|
||||
}
|
||||
// 生成器让出表达式:被让出的值里引用的父变量须纳入捕获,否则生成器体经
|
||||
// LOAD_VAR 读调用方寄存器残留(挂起恢复后寄存器已被覆盖)。
|
||||
Expression::YieldExpression(ye) => {
|
||||
if let Some(a) = &ye.argument {
|
||||
self.collect_capture_names_expr(a, ref_set, shadow, out);
|
||||
}
|
||||
}
|
||||
Expression::ChainExpression(c) => self.collect_capture_names_chain(&c.expression, ref_set, shadow, out),
|
||||
_ => {}
|
||||
}
|
||||
@@ -716,7 +858,11 @@ impl Emitter {
|
||||
self.collect_captured_expr(e, own, out);
|
||||
}
|
||||
}
|
||||
Expression::AssignmentExpression(ae) => self.collect_captured_expr(&ae.right, own, out),
|
||||
Expression::AssignmentExpression(ae) => {
|
||||
self.collect_captured_assign_target(&ae.left, own, out);
|
||||
self.collect_captured_expr(&ae.right, own, out);
|
||||
}
|
||||
Expression::UpdateExpression(ue) => self.collect_captured_simple_target(&ue.argument, own, out),
|
||||
Expression::ArrayExpression(ae) => {
|
||||
for e in &ae.elements {
|
||||
if let Some(e) = e.as_expression() {
|
||||
@@ -755,6 +901,11 @@ impl Emitter {
|
||||
}
|
||||
}
|
||||
Expression::ParenthesizedExpression(p) => self.collect_captured_expr(&p.expression, own, out),
|
||||
Expression::YieldExpression(ye) => {
|
||||
if let Some(a) = &ye.argument {
|
||||
self.collect_captured_expr(a, own, out);
|
||||
}
|
||||
}
|
||||
Expression::ChainExpression(c) => self.collect_captured_chain(&c.expression, own, out),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
@@ -161,6 +161,8 @@ pub struct CompileCtx {
|
||||
pub(crate) in_derived_constructor: bool,
|
||||
pub(crate) in_instance_method: bool,
|
||||
pub(crate) in_static_method: bool,
|
||||
/// 本函数是否为生成器函数体(`function*`),`assemble_ir` 回写到 IR。
|
||||
pub(crate) is_generator: bool,
|
||||
pub(crate) static_block_this_reg: Option<u8>,
|
||||
pub(crate) field_buffer: Option<FieldBuffer>,
|
||||
/// 类构造器模块中 `@@field_keys` upvalue 下标(实例字段 computed key 数组)。
|
||||
@@ -262,6 +264,7 @@ impl CompileCtx {
|
||||
in_derived_constructor: false,
|
||||
in_instance_method: false,
|
||||
in_static_method: false,
|
||||
is_generator: false,
|
||||
static_block_this_reg: None,
|
||||
field_buffer: None,
|
||||
field_keys_uv: None,
|
||||
@@ -603,6 +606,7 @@ impl CompileCtx {
|
||||
is_class_constructor: false,
|
||||
is_derived_constructor: false,
|
||||
needs_home_object: false,
|
||||
is_generator: self.is_generator,
|
||||
captured_this_const_idx: 0,
|
||||
function_name: None,
|
||||
function_length: self.function_length,
|
||||
@@ -700,27 +704,44 @@ impl Emitter {
|
||||
pub(crate) fn compile_function_body<'a>(
|
||||
&self, param_specs: &[ParamSpec<'a>], body_stmts: &[Statement<'a>], parent_ctx: &CompileCtx,
|
||||
is_expression_body: bool, is_arrow: bool,
|
||||
) -> Result<IRFunction, String> {
|
||||
self.compile_function_body_with_flags(param_specs, body_stmts, parent_ctx, is_expression_body, is_arrow, false)
|
||||
}
|
||||
|
||||
/// 编译函数体并显式指定生成器标志(`function*` 走此入口)。
|
||||
pub(crate) fn compile_generator_body<'a>(
|
||||
&self, param_specs: &[ParamSpec<'a>], body_stmts: &[Statement<'a>], parent_ctx: &CompileCtx,
|
||||
) -> Result<IRFunction, String> {
|
||||
self.compile_function_body_with_flags(param_specs, body_stmts, parent_ctx, false, false, true)
|
||||
}
|
||||
|
||||
fn compile_function_body_with_flags<'a>(
|
||||
&self, param_specs: &[ParamSpec<'a>], body_stmts: &[Statement<'a>], parent_ctx: &CompileCtx,
|
||||
is_expression_body: bool, is_arrow: bool, is_generator: bool,
|
||||
) -> Result<IRFunction, String> {
|
||||
let body_context = if is_arrow {
|
||||
FunctionBodyContext::Arrow
|
||||
} else {
|
||||
FunctionBodyContext::Ordinary
|
||||
};
|
||||
self.compile_function_body_with_bindings(
|
||||
self.compile_function_body_with_bindings_gen(
|
||||
param_specs,
|
||||
body_stmts,
|
||||
parent_ctx,
|
||||
is_expression_body,
|
||||
&[],
|
||||
body_context,
|
||||
is_generator,
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn compile_function_body_with_bindings<'a>(
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub(crate) fn compile_function_body_with_bindings_gen<'a>(
|
||||
&self, param_specs: &[ParamSpec<'a>], body_stmts: &[Statement<'a>], parent_ctx: &CompileCtx,
|
||||
is_expression_body: bool, extra_bindings: &[(&str, u32)], body_context: FunctionBodyContext,
|
||||
is_generator: bool,
|
||||
) -> Result<IRFunction, String> {
|
||||
self.compile_function_body_with_field_hooks(
|
||||
self.compile_function_body_with_field_hooks_gen(
|
||||
param_specs,
|
||||
body_stmts,
|
||||
parent_ctx,
|
||||
@@ -731,6 +752,7 @@ impl Emitter {
|
||||
false,
|
||||
&[],
|
||||
&[],
|
||||
is_generator,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -745,13 +767,39 @@ impl Emitter {
|
||||
pub(crate) fn compile_function_body_with_field_hooks<'a, E>(
|
||||
&self, param_specs: &[ParamSpec<'a>], body_stmts: &[Statement<'a>], parent_ctx: &CompileCtx,
|
||||
is_expression_body: bool, extra_bindings: &[(&str, u32)], body_context: FunctionBodyContext,
|
||||
mut emit_fields: Option<E>, fields_after_super: bool, extra_capture_exprs: &[&'a Expression<'a>],
|
||||
emit_fields: Option<E>, fields_after_super: bool, extra_capture_exprs: &[&'a Expression<'a>],
|
||||
extra_upvalue_names: &[(&str, u8)],
|
||||
) -> Result<IRFunction, String>
|
||||
where
|
||||
E: FnMut(&Emitter, &mut CompileCtx) -> Result<(), String>,
|
||||
{
|
||||
self.compile_function_body_with_field_hooks_gen(
|
||||
param_specs,
|
||||
body_stmts,
|
||||
parent_ctx,
|
||||
is_expression_body,
|
||||
extra_bindings,
|
||||
body_context,
|
||||
emit_fields,
|
||||
fields_after_super,
|
||||
extra_capture_exprs,
|
||||
extra_upvalue_names,
|
||||
false,
|
||||
)
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub(crate) fn compile_function_body_with_field_hooks_gen<'a, E>(
|
||||
&self, param_specs: &[ParamSpec<'a>], body_stmts: &[Statement<'a>], parent_ctx: &CompileCtx,
|
||||
is_expression_body: bool, extra_bindings: &[(&str, u32)], body_context: FunctionBodyContext,
|
||||
mut emit_fields: Option<E>, fields_after_super: bool, extra_capture_exprs: &[&'a Expression<'a>],
|
||||
extra_upvalue_names: &[(&str, u8)], is_generator: bool,
|
||||
) -> Result<IRFunction, String>
|
||||
where
|
||||
E: FnMut(&Emitter, &mut CompileCtx) -> Result<(), String>,
|
||||
{
|
||||
let mut ctx = CompileCtx::new();
|
||||
ctx.is_generator = is_generator;
|
||||
|
||||
// length = 第一个带默认值形参之前的形参数(解构默认与标识符默认同规则);
|
||||
// rest 参数不在 param_specs 中(独立字段),天然不计入。
|
||||
@@ -838,6 +886,12 @@ impl Emitter {
|
||||
// 预声明 `var` 名,使首个 sub-pass 中提升的函数声明能解析其闭包引用的外层 var。
|
||||
self.predeclare_var_declarations(body_stmts, &mut ctx);
|
||||
|
||||
// 生成器:body 起点标记——调用时参数初始化(emit_params_prologue)结束后挂起于此,
|
||||
// 参数副作用/异常在 `g()` 调用时刻生效,首次 next() 从这继续执行 body。
|
||||
if is_generator {
|
||||
ctx.inst(Inst::suspend_body());
|
||||
}
|
||||
|
||||
if let Some(emit) = emit_fields.as_mut() {
|
||||
if fields_after_super {
|
||||
let mut parent_insts = Vec::new();
|
||||
@@ -1103,6 +1157,7 @@ impl Emitter {
|
||||
| Expression::ClassExpression(_)
|
||||
| Expression::NewExpression(_) => self.emit_function_domain(expr, ctx),
|
||||
Expression::Identifier(ident) => self.emit_identifier_expression(ident, ctx),
|
||||
Expression::YieldExpression(ye) => self.emit_yield_expression(ye, ctx),
|
||||
Expression::CallExpression(_) => self.emit_call_domain(expr, ctx),
|
||||
Expression::ThisExpression(_) => self.emit_this_expression(ctx),
|
||||
Expression::SequenceExpression(seq) => self.emit_sequence_expression(seq, ctx),
|
||||
|
||||
@@ -76,7 +76,11 @@ impl Emitter {
|
||||
|
||||
let body_stmts: &[Statement] = if let Some(body) = &fe.body { &body.statements } else { &[] };
|
||||
|
||||
let mut sub_module = self.compile_function_body(¶m_names, body_stmts, ctx, false, false)?;
|
||||
let mut sub_module = if fe.generator {
|
||||
self.compile_generator_body(¶m_names, body_stmts, ctx)?
|
||||
} else {
|
||||
self.compile_function_body(¶m_names, body_stmts, ctx, false, false)?
|
||||
};
|
||||
if let Some(id) = &fe.id {
|
||||
sub_module.function_name = Some(id.name.to_string());
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ pub mod operator;
|
||||
pub mod parenthesized;
|
||||
pub mod template;
|
||||
pub mod this;
|
||||
pub mod yield_expr;
|
||||
|
||||
impl Emitter {
|
||||
pub(crate) fn emit_unsupported_expression(&self, expr: &Expression, ctx: &mut CompileCtx) -> Result<u32, String> {
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
//! `yield` 表达式 emit:求值被让出的值后发 `YIELD` 指令,结果经 reg 0 交付。
|
||||
|
||||
use crate::{CompileCtx, Emitter};
|
||||
use oxide_bytecode::module::Constant;
|
||||
use oxide_bytecode::opcode::OpCode;
|
||||
use oxide_ir::inst::Inst;
|
||||
use oxide_ir::operand::Operand;
|
||||
use oxide_parser::YieldExpression;
|
||||
|
||||
impl Emitter {
|
||||
pub(crate) fn emit_yield_expression(&self, ye: &YieldExpression, ctx: &mut CompileCtx) -> Result<u32, String> {
|
||||
// 未支持:`yield*` 委托迭代,后续按 IteratorYield 协议实现。
|
||||
if ye.delegate {
|
||||
return Err("yield* not yet supported".into());
|
||||
}
|
||||
// 求值被让出的值(`yield` 无参数时让出 undefined)。
|
||||
let value_reg = if let Some(arg) = &ye.argument {
|
||||
self.emit_expression(arg, ctx)?
|
||||
} else {
|
||||
let undef_idx = ctx.add_constant(Constant::Undefined);
|
||||
let r = ctx.alloc_reg();
|
||||
ctx.inst(Inst::load_const(Operand::Reg(r), undef_idx));
|
||||
r
|
||||
};
|
||||
ctx.inst(Inst::yield_value(Operand::Reg(value_reg)));
|
||||
// 恢复时 `next(v)` 的 v 经 reg 0 交付(与 CALL 同协议)。
|
||||
let result_reg = ctx.alloc_reg();
|
||||
ctx.inst(Inst::new(OpCode::LOAD_VAR, Operand::Reg(result_reg), Operand::None, Operand::None));
|
||||
Ok(result_reg)
|
||||
}
|
||||
}
|
||||
@@ -33,7 +33,11 @@ impl Emitter {
|
||||
}
|
||||
}
|
||||
let body_stmts: &[Statement] = if let Some(body) = &fd.body { &body.statements } else { &[] };
|
||||
let mut sub_module = self.compile_function_body(¶m_names, body_stmts, ctx, false, false)?;
|
||||
let mut sub_module = if fd.generator {
|
||||
self.compile_generator_body(¶m_names, body_stmts, ctx)?
|
||||
} else {
|
||||
self.compile_function_body(¶m_names, body_stmts, ctx, false, false)?
|
||||
};
|
||||
sub_module.function_name = Some(name.clone());
|
||||
ctx.nested.push(sub_module);
|
||||
let var_reg = ctx.lookup(&name)?;
|
||||
|
||||
Reference in New Issue
Block a user