From 783e89e4cb1b1b1c3aa0af84d2eaa57663113fe9 Mon Sep 17 00:00:00 2001 From: pjh456 <147148383@qq.com> Date: Sun, 9 Aug 2026 18:02:08 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E7=94=9F=E6=88=90=E5=99=A8=E5=9F=BA?= =?UTF-8?q?=E7=A1=80=E6=94=AF=E6=8C=81=EF=BC=88YIELD=20=E5=B8=A7=E5=BF=AB?= =?UTF-8?q?=E7=85=A7=E6=8C=82=E8=B5=B7/=E6=81=A2=E5=A4=8D=20+=20GeneratorP?= =?UTF-8?q?rototype=20next/return/throw=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 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/赋值目标扫描 --- crates/oxide_builtins/src/iterator.rs | 3 +- crates/oxide_bytecode/src/module.rs | 4 + crates/oxide_bytecode/src/opcode.rs | 7 +- crates/oxide_emit/src/closure.rs | 177 ++++- crates/oxide_emit/src/emit.rs | 63 +- crates/oxide_emit/src/expr/function/mod.rs | 6 +- crates/oxide_emit/src/expr/mod.rs | 1 + crates/oxide_emit/src/expr/yield_expr.rs | 31 + .../src/stmt/declaration/function_decl.rs | 6 +- crates/oxide_ir/src/contract.rs | 21 +- crates/oxide_ir/src/inst.rs | 13 +- crates/oxide_ir/src/lib.rs | 3 + crates/oxide_ir/src/lower.rs | 1 + crates/oxide_ir/tests/lowering_tests.rs | 2 +- crates/oxide_test262/src/main.rs | 8 - crates/oxide_types/src/object.rs | 7 + crates/oxide_vm/src/dispatch/call.rs | 13 + crates/oxide_vm/src/generator.rs | 745 ++++++++++++++++++ crates/oxide_vm/src/lib.rs | 1 + crates/oxide_vm/src/session_arena.rs | 5 + crates/oxide_vm/src/session_gc.rs | 13 + crates/oxide_vm/src/vm.rs | 32 + crates/oxide_vm/src/vm_dispatch_ctrl.rs | 17 +- crates/oxide_vm/src/vm_dispatch_misc.rs | 4 + crates/oxide_vm/src/vm_runtime.rs | 113 +-- crates/oxide_vm/src/vm_support.rs | 76 +- 26 files changed, 1265 insertions(+), 107 deletions(-) create mode 100644 crates/oxide_emit/src/expr/yield_expr.rs create mode 100644 crates/oxide_vm/src/generator.rs diff --git a/crates/oxide_builtins/src/iterator.rs b/crates/oxide_builtins/src/iterator.rs index 77b061cb..6fabba91 100644 --- a/crates/oxide_builtins/src/iterator.rs +++ b/crates/oxide_builtins/src/iterator.rs @@ -320,7 +320,8 @@ fn current_index(vm: &mut H, wrapper: &JsObject, index_si: u32) -> us } } -fn make_iter_result(vm: &mut H, value: JsValue, done: bool) -> JsValue { +/// 构造迭代器结果对象 `{value, done}`(生成器 next/return 结果复用)。 +pub fn make_iter_result(vm: &mut H, value: JsValue, done: bool) -> JsValue { let object_proto = vm.session().builtin_world().object_proto.as_ptr() as *mut JsObject; let obj = vm .epoch() diff --git a/crates/oxide_bytecode/src/module.rs b/crates/oxide_bytecode/src/module.rs index 5a0aaac1..d8084b51 100644 --- a/crates/oxide_bytecode/src/module.rs +++ b/crates/oxide_bytecode/src/module.rs @@ -68,6 +68,8 @@ pub struct CompiledModule { pub is_derived_constructor: bool, /// 原型方法是否需要运行时 home_object。 pub needs_home_object: bool, + /// 是否为生成器函数体(`function*`):调用返回迭代器对象,body 挂起/恢复执行。 + pub is_generator: bool, pub upvalue_captures: Vec, pub cells_needed: u8, /// 全局扁平模块 id:编译末端 flatten 阶段分配(顶层 0,子模块 DFS 递增)。 @@ -93,6 +95,7 @@ impl CompiledModule { is_class_constructor: false, is_derived_constructor: false, needs_home_object: false, + is_generator: false, upvalue_captures: Vec::new(), cells_needed: 0, flat_id: 0, @@ -123,6 +126,7 @@ impl Clone for CompiledModule { is_class_constructor: self.is_class_constructor, is_derived_constructor: self.is_derived_constructor, needs_home_object: self.needs_home_object, + is_generator: self.is_generator, upvalue_captures: self.upvalue_captures.clone(), cells_needed: self.cells_needed, flat_id: self.flat_id, diff --git a/crates/oxide_bytecode/src/opcode.rs b/crates/oxide_bytecode/src/opcode.rs index 3b715dbd..de8847ad 100644 --- a/crates/oxide_bytecode/src/opcode.rs +++ b/crates/oxide_bytecode/src/opcode.rs @@ -189,7 +189,7 @@ define_opcodes! { PROFILE_BRANCH = 0x6B => "PROFILE_BRANCH", PROFILE_CALL = 0x6C => "PROFILE_CALL", - // ── 并行 — 占位符 (0x70-0x7F) ── + // ── 并行 — 占位符 (0x70-0x75) ── FORK = 0x70 => "FORK", JOIN = 0x71 => "JOIN", GET_PRIVATE = 0x72 => "GET_PRIVATE", @@ -197,6 +197,11 @@ define_opcodes! { INIT_PRIVATE = 0x74 => "INIT_PRIVATE", PRIVATE_BRAND_IN = 0x75 => "PRIVATE_BRAND_IN", + // ── 生成器 (0x76-0x77) ── + YIELD = 0x76 => "YIELD", // rd=被让出的值(结果经 reg 0 交付,见 contract.rs) + // 生成器 body 起点标记:调用时参数初始化完成后挂起于此,首次 next() 从这继续。 + SUSPEND_BODY = 0x77 => "SUSPEND_BODY", + // ── 位运算 (0x80-0x8F) ── BIT_AND = 0x80 => "BIT_AND", BIT_OR = 0x81 => "BIT_OR", diff --git a/crates/oxide_emit/src/closure.rs b/crates/oxide_emit/src/closure.rs index 03ed4b2a..c9e8cde6 100644 --- a/crates/oxide_emit/src/closure.rs +++ b/crates/oxide_emit/src/closure.rs @@ -324,6 +324,150 @@ impl Emitter { } } + /// 扫描赋值目标中的引用(标识符写名,成员目标扫对象/键,解构目标递归元素)。 + fn collect_capture_names_assign_target( + &self, target: &oxide_parser::AssignmentTarget, ref_set: &HashSet, shadow: &HashSet, + out: &mut HashSet, + ) { + 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, + shadow: &HashSet, out: &mut HashSet, + ) { + 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, shadow: &HashSet, + out: &mut HashSet, + ) { + 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, out: &mut HashSet, + ) { + 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, out: &mut HashSet, + ) { + 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, shadow: &HashSet, @@ -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), _ => {} } diff --git a/crates/oxide_emit/src/emit.rs b/crates/oxide_emit/src/emit.rs index 92828fe6..dc676000 100644 --- a/crates/oxide_emit/src/emit.rs +++ b/crates/oxide_emit/src/emit.rs @@ -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, pub(crate) field_buffer: Option, /// 类构造器模块中 `@@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 { + 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 { + 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 { 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 { - 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, fields_after_super: bool, extra_capture_exprs: &[&'a Expression<'a>], + emit_fields: Option, fields_after_super: bool, extra_capture_exprs: &[&'a Expression<'a>], extra_upvalue_names: &[(&str, u8)], ) -> Result + 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, fields_after_super: bool, extra_capture_exprs: &[&'a Expression<'a>], + extra_upvalue_names: &[(&str, u8)], is_generator: bool, + ) -> Result 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), diff --git a/crates/oxide_emit/src/expr/function/mod.rs b/crates/oxide_emit/src/expr/function/mod.rs index cac6ea1b..e872cb03 100644 --- a/crates/oxide_emit/src/expr/function/mod.rs +++ b/crates/oxide_emit/src/expr/function/mod.rs @@ -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()); } diff --git a/crates/oxide_emit/src/expr/mod.rs b/crates/oxide_emit/src/expr/mod.rs index 32e43f4b..2d51ccfc 100644 --- a/crates/oxide_emit/src/expr/mod.rs +++ b/crates/oxide_emit/src/expr/mod.rs @@ -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 { diff --git a/crates/oxide_emit/src/expr/yield_expr.rs b/crates/oxide_emit/src/expr/yield_expr.rs new file mode 100644 index 00000000..8f787e4e --- /dev/null +++ b/crates/oxide_emit/src/expr/yield_expr.rs @@ -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 { + // 未支持:`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) + } +} diff --git a/crates/oxide_emit/src/stmt/declaration/function_decl.rs b/crates/oxide_emit/src/stmt/declaration/function_decl.rs index 9ba44726..1d109073 100644 --- a/crates/oxide_emit/src/stmt/declaration/function_decl.rs +++ b/crates/oxide_emit/src/stmt/declaration/function_decl.rs @@ -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)?; diff --git a/crates/oxide_ir/src/contract.rs b/crates/oxide_ir/src/contract.rs index 6d32d401..5bd9e2c6 100644 --- a/crates/oxide_ir/src/contract.rs +++ b/crates/oxide_ir/src/contract.rs @@ -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)); diff --git a/crates/oxide_ir/src/inst.rs b/crates/oxide_ir/src/inst.rs index d514b7aa..07c384d7 100644 --- a/crates/oxide_ir/src/inst.rs +++ b/crates/oxide_ir/src/inst.rs @@ -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)); diff --git a/crates/oxide_ir/src/lib.rs b/crates/oxide_ir/src/lib.rs index c0c9b2e1..5c7bc6dc 100644 --- a/crates/oxide_ir/src/lib.rs +++ b/crates/oxide_ir/src/lib.rs @@ -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, /// 函数 `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, diff --git a/crates/oxide_ir/src/lower.rs b/crates/oxide_ir/src/lower.rs index 583145fb..cb032b0a 100644 --- a/crates/oxide_ir/src/lower.rs +++ b/crates/oxide_ir/src/lower.rs @@ -89,6 +89,7 @@ pub fn lower(f: &IRFunction) -> Result { 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, diff --git a/crates/oxide_ir/tests/lowering_tests.rs b/crates/oxide_ir/tests/lowering_tests.rs index 1255d722..3c627d6c 100644 --- a/crates/oxide_ir/tests/lowering_tests.rs +++ b/crates/oxide_ir/tests/lowering_tests.rs @@ -131,7 +131,7 @@ fn define_accessor_and_rest_object_carry_single_ext_word() { let mut f = base_module(); f.insts .push(Inst::define_accessor(Operand::Reg(0), Operand::Reg(1), Operand::Reg(2), 42)); - f.insts.push(Inst::rest_object(Operand::Reg(3), Operand::Reg(4), 7)); + f.insts.push(Inst::rest_object(Operand::Reg(3), Operand::Reg(4), 7, None)); let m = lower_ok(&f); assert_eq!(m.bytecode.len(), 4); assert_eq!(opcode::opcode(m.bytecode[0]), OpCode::DEFINE_ACCESSOR); diff --git a/crates/oxide_test262/src/main.rs b/crates/oxide_test262/src/main.rs index 52a86f1d..dce34651 100644 --- a/crates/oxide_test262/src/main.rs +++ b/crates/oxide_test262/src/main.rs @@ -401,8 +401,6 @@ fn is_skipped(meta: &TestMeta) -> Option { let excluded_features = [ "Proxy", "BigInt", - "generators", - "generator", "async-functions", "Intl", "Temporal", @@ -418,12 +416,6 @@ fn is_skipped(meta: &TestMeta) -> Option { } } - // 仅当 description 与 features 都表明 generator/async 时才跳过 - // (许多 description 含 "async" 的测试测的是非 async 功能)。 - if meta.description.contains("generator") && meta.features.iter().any(|f| f.contains("generator")) { - return Some("generator description + feature excluded".into()); - } - None } diff --git a/crates/oxide_types/src/object.rs b/crates/oxide_types/src/object.rs index 496d3546..d33cc008 100644 --- a/crates/oxide_types/src/object.rs +++ b/crates/oxide_types/src/object.rs @@ -398,6 +398,8 @@ impl JsObject { pub const OBJ_TYPE_TYPED_ARRAY: u8 = 8; /// native 构造器(Set/Array/Object 等,可 [[Construct]]);区别于不可构造的 native 方法。 pub const OBJ_TYPE_CONSTRUCTOR: u8 = 9; + /// 生成器迭代器对象(`function*` 调用返回):状态快照存于 `native_data`。 + pub const OBJ_TYPE_GENERATOR: u8 = 10; /// `is_session_epoch` 字段中的 session 标记位。 pub const SESSION_EPOCH_BIT: u8 = 0x01; /// `is_session_epoch` 字段中的 GC 标记位。 @@ -443,6 +445,11 @@ impl JsObject { pub fn is_typed_array_obj(&self) -> bool { self.type_tag == Self::OBJ_TYPE_TYPED_ARRAY } + /// 是否生成器迭代器对象。 + #[inline] + pub fn is_generator_obj(&self) -> bool { + self.type_tag == Self::OBJ_TYPE_GENERATOR + } /// 构造无属性、可扩展的空对象(`new Object()` 的基础对象)。 pub fn new_empty(shape_id: ShapeId, proto: JsValue) -> Self { diff --git a/crates/oxide_vm/src/dispatch/call.rs b/crates/oxide_vm/src/dispatch/call.rs index 670a16ea..722c16d4 100644 --- a/crates/oxide_vm/src/dispatch/call.rs +++ b/crates/oxide_vm/src/dispatch/call.rs @@ -741,6 +741,13 @@ impl Vm { } } } else if obj.sub_module_index() > 0 { + let sub_idx = obj.sub_module_index() as usize; + // 生成器函数调用返回迭代器对象,不执行函数体。 + if sub_idx < self.sub_modules.len() && self.sub_modules[sub_idx].is_generator { + let gen = self.create_generator_object(callee, this_value, &args)?; + self.regs[0] = gen; + return Ok(false); + } self.push_bytecode_frame( callee, this_value, @@ -827,6 +834,12 @@ impl Vm { } } } else if ctor_obj.sub_module_index() > 0 { + // 生成器函数不是构造器:`new g()` 抛 TypeError。 + if (ctor_obj.sub_module_index() as usize) < self.sub_modules.len() + && self.sub_modules[ctor_obj.sub_module_index() as usize].is_generator + { + return self.raise_type_error("g is not a constructor").map(|_| true); + } if self.frames.len() >= self.kernel_core.config.max_call_depth { return Err(self.error_message_text("RangeError", "Maximum call stack size exceeded")); } diff --git a/crates/oxide_vm/src/generator.rs b/crates/oxide_vm/src/generator.rs new file mode 100644 index 00000000..0635f975 --- /dev/null +++ b/crates/oxide_vm/src/generator.rs @@ -0,0 +1,745 @@ +//! 生成器运行时:帧快照挂起/恢复 + next/return/throw 方法。 +//! +//! 策略:`function*` 函数调用返回生成器迭代器对象(状态存 `native_data`), +//! body 不立即执行。`next()` 时把生成器执行状态(寄存器窗口、pc、bytecode、 +//! spill/save/try/cell 栈段、for-in/for-of 迭代器)灌回 VM,在内嵌 dispatch +//! 循环中继续执行到下一个 `YIELD` 或 `RETURN`。`YIELD` 通过 +//! `Vm::generator_suspended` 信号让内嵌 dispatch 返回,恢复方据此快照挂起状态。 + +use std::sync::Arc; + +use oxide_builtins::iterator::make_iter_result; +use oxide_bytecode::opcode; +use oxide_kernel::shape_forge::EMPTY_SHAPE_ID; +use oxide_runtime_api::NativeResult; +use oxide_types::mem::P; +use oxide_types::object::{Cell, JsObject, NativeFnPtr}; +use oxide_types::value::JsValue; + +use crate::vm::{CallFrame, ForInIter, FrameContinuation, TryHandler, Vm}; + +/// 生成器执行阶段。 +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub(crate) enum GeneratorPhase { + /// 尚未开始执行(首次 next 前)。 + New, + /// 正在执行(body 运行在嵌套 dispatch 循环中)。 + Running, + /// 已在 `yield` 挂起。 + Suspended, + /// 已正常返回 / 被 `return()` 提前结束。 + Completed, +} + +/// 生成器挂起时的完整执行上下文快照。 +/// +/// 存在生成器对象 `native_data`(`Box`),跨 `next()` 调用存活;其中所有 +/// `JsValue` 由 session GC 经生成器对象边追踪(见 `session_gc`)。 +pub(crate) struct GeneratorState { + pub phase: GeneratorPhase, + /// 生成器函数对象(首次执行时压帧用)。 + pub callee: JsValue, + /// 首次调用实参。 + pub args: Vec, + /// 首次调用时的方法接收者(`obj.g()` 的 `obj`),压帧时作 `this` 绑定。 + pub this_value: JsValue, + /// 完成后返回值。 + pub result: JsValue, + // ── 挂起时的执行上下文 ── + pub regs: Box<[JsValue; 256]>, + pub pc: usize, + pub bytecode: Vec, + /// 生成器模块 flat_id(恢复时重激活 immutables)。 + pub sub_idx: u32, + pub active_reg_limit: u8, + pub root_reg_limit: u8, + /// 生成器帧(压入时由 push_bytecode_frame 构造,挂起时弹出存此)。 + pub frame: Option, + pub spill_stack: Vec, + pub save_stack: Vec, + pub cell_stack: Vec>, + pub try_stack: Vec, + pub for_in_iters: Vec<*mut ForInIter<'static>>, + pub for_of_iters: Vec, + pub last_for_of_result: JsValue, + pub saved_bytecode_stack: Vec>, + pub saved_immutables_stack: Vec<*const [JsValue]>, + /// 在途异常/完成(throw 穿越 finally 挂起时保留,恢复后继续展开)。 + pub exception_value: Option, + pub pending_exception: Option, + pub pending_error_kind: Option<&'static str>, + pub pending_completion: Option, +} + +/// `next()/return()/throw()` 的注入模式。 +#[derive(Debug, Clone, Copy)] +pub(crate) enum GeneratorResumeMode { + /// 普通恢复:`next(v)` 的 v 作为 `yield` 表达式结果(写 reg 0)。 + Next(JsValue), + /// 提前结束:等价于在挂起点执行 `return v`(触发 finally)。 + Return(JsValue), + /// 注入异常:等价于在挂起点抛错(可被 catch/finally 捕获)。 + Throw(JsValue), +} + +/// 一次恢复的结局。 +pub(crate) enum GeneratorStep { + /// 让出:`value` 为 `yield` 的值,生成器仍可继续。 + Suspended { value: JsValue }, + /// 完成:`value` 为返回值。 + Completed { value: JsValue }, + /// 未捕获异常逃逸:`value` 为原异常值,调用方须重新抛出。 + Thrown { value: JsValue }, +} + +impl Vm { + /// 调用生成器函数返回的迭代器对象:创建生成器实例、挂状态并执行调用时参数初始化。 + /// + /// 实例 [[Prototype]] = 调用方 `g.prototype`(为对象时),否则回退 `%GeneratorPrototype%` + /// (GetPrototypeFromConstructor 语义,`default-proto`/`prototype-value` 测试)。 + pub(crate) fn create_generator_object( + &mut self, callee: JsValue, this_value: JsValue, args: &[JsValue], + ) -> Result { + let gen_proto_val = JsValue::from_js_object(self.generator_proto.as_ptr() as *mut JsObject); + let obj = self.epoch.alloc(JsObject::new_empty(EMPTY_SHAPE_ID, gen_proto_val)); + let obj_ref = unsafe { &mut *obj }; + obj_ref.type_tag = JsObject::OBJ_TYPE_GENERATOR; + let state = Box::new(GeneratorState { + phase: GeneratorPhase::New, + callee, + args: args.to_vec(), + this_value, + result: JsValue::undefined(), + regs: Box::new([JsValue::undefined(); 256]), + pc: 0, + bytecode: Vec::new(), + sub_idx: 0, + active_reg_limit: 0, + root_reg_limit: 0, + frame: None, + spill_stack: Vec::new(), + save_stack: Vec::new(), + cell_stack: Vec::new(), + try_stack: Vec::new(), + for_in_iters: Vec::new(), + for_of_iters: Vec::new(), + last_for_of_result: JsValue::undefined(), + saved_bytecode_stack: Vec::new(), + saved_immutables_stack: Vec::new(), + exception_value: None, + pending_exception: None, + pending_error_kind: None, + pending_completion: None, + }); + obj_ref.set_native_data(Box::into_raw(state) as *mut u8); + self.gc_state.track_epoch_object(obj); + let gen_val = JsValue::from_js_object(obj); + // 调用时参数初始化(含默认值/解构/arguments 创建):副作用与异常在 `g()` 时刻生效。 + self.initialize_generator(gen_val)?; + // 实例 [[Prototype]] 在参数初始化之后读取:参数默认值可能改写 `g.prototype` + // (GetPrototypeFromConstructor 语义),为对象则用,否则回退 %GeneratorPrototype%。 + if callee.is_object() { + let proto_si = self.kernel_core.perm_interner().intern("prototype").0; + let callee_obj = unsafe { &*callee.as_js_object_ptr() }; + if let Some(p) = self.resolve_property(callee_obj, proto_si) { + if p.is_object() { + let obj_ref = unsafe { &mut *obj }; + obj_ref.set_proto(p).ok(); + } + } + } + Ok(gen_val) + } + + /// 生成器调用时的参数初始化步:压入生成器帧,执行到 body 起点标记(SUSPEND_BODY)。 + /// + /// 参数初始化抛错时恢复调用方状态并在调用方上下文重新抛(可被外围 try/catch 捕获); + /// 成功则把挂起在 body 起点的状态快照存入生成器对象。 + /// + /// # 副作用 + /// - 生成器对象状态从 `New` 转为 `Suspended`(body 起点)。 + /// - 参数默认值的副作用、`arguments` 创建、解构的迭代副作用在调用时刻完成。 + fn initialize_generator(&mut self, gen_val: JsValue) -> Result<(), String> { + let state_ptr = self.generator_state_ptr(gen_val); + let saved = self.save_inline_state(); + self.generator_suspended = None; + // 嵌套生成器创建(参数默认值里调用其它 generator)会改写 init 标志,须保存恢复。 + let prev_init_step = self.generator_init_step; + let prev_body_started = self.generator_body_started; + self.generator_body_started = false; + self.generator_init_step = true; + self.native_call_depth += 1; + + // 压入生成器帧(New)。 + self.regs = [JsValue::undefined(); 256]; + self.pc = 0; + self.bytecode = Vec::new(); + self.active_reg_limit = 1; + self.root_reg_limit = 1; + self.try_stack.clear(); + self.iters.for_in_iters.clear(); + self.iters.for_of_iters.clear(); + self.iters.last_for_of_result = JsValue::undefined(); + self.spill_stack.clear(); + self.save_stack.clear(); + self.saved_bytecode_stack.clear(); + self.saved_immutables_stack.clear(); + self.cell_stack.clear(); + self.inline_callee = None; + let callee = unsafe { (*state_ptr).callee }; + let this_value = unsafe { (*state_ptr).this_value }; + let args = unsafe { std::mem::take(&mut (*state_ptr).args) }; + let push_res = self.push_bytecode_frame( + callee, + this_value, + &args, + None, + None, + JsValue::undefined(), + FrameContinuation::None, + ); + unsafe { (*state_ptr).args = args }; + if let Err(e) = push_res { + self.restore_inline_state(saved); + self.generator_init_step = false; + self.native_call_depth -= 1; + return Err(e); + } + unsafe { (*state_ptr).phase = GeneratorPhase::Running }; + + let prev_dispatch = self.generator_dispatch; + self.generator_dispatch = true; + let result = self.dispatch(); + self.generator_dispatch = prev_dispatch; + self.generator_init_step = prev_init_step; + let body_started = self.generator_body_started; + self.generator_body_started = prev_body_started; + self.native_call_depth -= 1; + + if body_started { + // 参数初始化完成:快照挂起在 body 起点,首次 next() 从此继续。 + let state = unsafe { &mut *state_ptr }; + self.snapshot_generator(state)?; + self.restore_inline_state(saved); + return Ok(()); + } + + // 参数初始化抛错/异常结束:恢复调用方上下文后重新抛出。 + let exc = self.last_uncaught_value.take().unwrap_or_else(|| match result { + Ok(v) => oxide_builtins::error::create_error(self, &format!("generator initialization failed: {v:?}")), + Err(e) => oxide_builtins::error::create_error(self, &e), + }); + let kind = self.thrown_error_kind(exc); + unsafe { (*state_ptr).phase = GeneratorPhase::Completed }; + self.restore_inline_state(saved); + self.exception_value = Some(exc); + self.pending_error_kind = Some(kind); + self.unwind().map(|_| ()) + } + + /// 取出生成器对象的状态指针(调用方须先校验 `is_generator_obj`)。 + fn generator_state_ptr(&self, gen_val: JsValue) -> *mut GeneratorState { + unsafe { (*gen_val.as_js_object_ptr()).native_data() as *mut GeneratorState } + } + + /// 恢复生成器一步执行:`next(v)` / `return(v)` / `throw(e)`。 + /// + /// # 步骤 + /// 1. 校验生成器对象与阶段(已完成/执行中直接给出对应结局)。 + /// 2. 用 `InlineSyncState` 保存调用方 VM 状态,把生成器挂起快照灌回 VM。 + /// 3. 在嵌套 `dispatch()` 中运行生成器 body 到下一个 `YIELD`/`RETURN`/异常。 + /// 4. 让出则快照新状态;完成/异常则标记阶段;最后恢复调用方状态。 + /// + /// # 副作用 + /// - 修改生成器对象 `native_data` 中的快照。 + /// - 嵌套 dispatch 期间 VM 完全被生成器状态占据。 + pub(crate) fn resume_generator( + &mut self, gen_val: JsValue, mode: GeneratorResumeMode, + ) -> Result { + if !gen_val.is_object() { + let err = oxide_builtins::error::create_type_error(self, "Generator methods called on non-object"); + return Ok(GeneratorStep::Thrown { value: err }); + } + let obj = unsafe { &*gen_val.as_js_object_ptr() }; + if !obj.is_generator_obj() { + let err = + oxide_builtins::error::create_type_error(self, "Generator methods called on incompatible receiver"); + return Ok(GeneratorStep::Thrown { value: err }); + } + let state_ptr = self.generator_state_ptr(gen_val); + + // 已完成:next 返回 {value: undefined, done: true}(完成值仅在完成步交付); + // return(v) 返回 {value: v, done: true};throw 直接传播异常。 + if unsafe { (*state_ptr).phase } == GeneratorPhase::Completed { + return match mode { + GeneratorResumeMode::Next(_) => Ok(GeneratorStep::Completed { value: JsValue::undefined() }), + GeneratorResumeMode::Return(v) => Ok(GeneratorStep::Completed { value: v }), + GeneratorResumeMode::Throw(e) => Ok(GeneratorStep::Thrown { value: e }), + }; + } + if unsafe { (*state_ptr).phase } == GeneratorPhase::Running { + let err = oxide_builtins::error::create_type_error(self, "Generator is already running"); + return Ok(GeneratorStep::Thrown { value: err }); + } + + let was_new = unsafe { (*state_ptr).phase } == GeneratorPhase::New; + // return() 在未开始的生成器上直接完成,不执行 body。 + if was_new { + if let GeneratorResumeMode::Return(v) = mode { + let state = unsafe { &mut *state_ptr }; + state.phase = GeneratorPhase::Completed; + state.result = v; + return Ok(GeneratorStep::Completed { value: v }); + } + if let GeneratorResumeMode::Throw(e) = mode { + unsafe { (*state_ptr).phase = GeneratorPhase::Completed }; + return Ok(GeneratorStep::Thrown { value: e }); + } + } + + // 保存调用方完整 VM 状态。 + let saved = self.save_inline_state(); + self.generator_suspended = None; + self.native_call_depth += 1; + + // 首次执行:压入生成器帧;挂起:恢复快照。 + if was_new { + self.regs = [JsValue::undefined(); 256]; + self.pc = 0; + self.bytecode = Vec::new(); + self.active_reg_limit = 1; + self.root_reg_limit = 1; + self.try_stack.clear(); + self.iters.for_in_iters.clear(); + self.iters.for_of_iters.clear(); + self.iters.last_for_of_result = JsValue::undefined(); + self.spill_stack.clear(); + self.save_stack.clear(); + self.saved_bytecode_stack.clear(); + self.saved_immutables_stack.clear(); + self.cell_stack.clear(); + self.inline_callee = None; + let callee = unsafe { (*state_ptr).callee }; + let args = unsafe { std::mem::take(&mut (*state_ptr).args) }; + let push_res = self.push_bytecode_frame( + callee, + JsValue::undefined(), + &args, + None, + None, + JsValue::undefined(), + FrameContinuation::None, + ); + unsafe { (*state_ptr).args = args }; + if let Err(e) = push_res { + self.restore_inline_state(saved); + return Err(e); + } + unsafe { (*state_ptr).phase = GeneratorPhase::Running }; + } else { + let state = unsafe { &mut *state_ptr }; + self.regs = *state.regs; + self.pc = state.pc; + self.bytecode = std::mem::take(&mut state.bytecode); + let subs = Arc::clone(&self.sub_modules); + if (state.sub_idx as usize) < subs.len() { + self.activate_immutables(state.sub_idx as usize, &subs[state.sub_idx as usize].constants); + } else { + // 挂起状态跨 run:sub_modules 已重建,无法恢复(与动态函数同限制)。 + self.restore_inline_state(saved); + return Err("generator suspended across runs is no longer valid".into()); + } + self.active_reg_limit = state.active_reg_limit; + self.root_reg_limit = state.root_reg_limit; + self.frames.clear(); + if let Some(frame) = state.frame.take() { + self.frames.push(frame); + } + self.spill_stack = std::mem::take(&mut state.spill_stack); + self.save_stack = std::mem::take(&mut state.save_stack); + self.cell_stack = std::mem::take(&mut state.cell_stack); + self.try_stack = std::mem::take(&mut state.try_stack); + self.iters.for_in_iters = std::mem::take(&mut state.for_in_iters); + self.iters.for_of_iters = std::mem::take(&mut state.for_of_iters); + self.iters.last_for_of_result = state.last_for_of_result; + self.saved_bytecode_stack = std::mem::take(&mut state.saved_bytecode_stack); + self.saved_immutables_stack = std::mem::take(&mut state.saved_immutables_stack); + self.exception_value = state.exception_value.take(); + self.pending_exception = state.pending_exception.take(); + self.pending_error_kind = state.pending_error_kind.take(); + self.pending_completion = state.pending_completion.take(); + self.inline_callee = None; + state.phase = GeneratorPhase::Running; + + // 注入模式:next(v) 写 reg 0;throw(e) 恢复异常上下文;return(v) 完成穿越。 + match mode { + GeneratorResumeMode::Next(arg) => { + self.regs[0] = arg; + } + GeneratorResumeMode::Throw(exc) => { + self.exception_value = Some(exc); + self.pending_error_kind = Some(self.thrown_error_kind(exc)); + if self.unwind().is_err() { + self.restore_inline_state(saved); + self.native_call_depth -= 1; + let thrown = self.last_uncaught_value.take().unwrap_or(exc); + unsafe { (*state_ptr).phase = GeneratorPhase::Completed }; + return Ok(GeneratorStep::Thrown { value: thrown }); + } + } + GeneratorResumeMode::Return(value) => { + // 等价于在挂起点执行 return:穿越 finally 或直接交付返回值。 + // 直接交付路径走 do_return(帧弹出后需按内嵌 dispatch 语义返回)。 + let prev_dispatch = self.generator_dispatch; + self.generator_dispatch = true; + let completed = self.complete_generator_return(value); + self.generator_dispatch = prev_dispatch; + if let Some(completed) = completed? { + self.restore_inline_state(saved); + self.native_call_depth -= 1; + let state = unsafe { &mut *state_ptr }; + state.phase = GeneratorPhase::Completed; + state.result = completed; + return Ok(GeneratorStep::Completed { value: completed }); + } + } + } + } + + let prev_dispatch = self.generator_dispatch; + self.generator_dispatch = true; + let result = self.dispatch(); + self.generator_dispatch = prev_dispatch; + self.native_call_depth -= 1; + + // YIELD 让出:快照挂起状态。 + if let Some(value) = self.generator_suspended.take() { + let state = unsafe { &mut *state_ptr }; + self.snapshot_generator(state)?; + self.restore_inline_state(saved); + return Ok(GeneratorStep::Suspended { value }); + } + + // 完成或异常逃逸。 + match result { + Ok(value) => { + let state = unsafe { &mut *state_ptr }; + state.phase = GeneratorPhase::Completed; + state.result = value; + self.restore_inline_state(saved); + Ok(GeneratorStep::Completed { value }) + } + Err(e) => { + let exc = self + .last_uncaught_value + .take() + .unwrap_or_else(|| oxide_builtins::error::create_error(self, &e)); + let state = unsafe { &mut *state_ptr }; + state.phase = GeneratorPhase::Completed; + state.result = JsValue::undefined(); + self.restore_inline_state(saved); + Ok(GeneratorStep::Thrown { value: exc }) + } + } + } + + /// 把当前 VM 执行状态(生成器 body 刚在嵌套 dispatch 中让出)快照进状态盒。 + /// + /// 生成器帧弹出存 `frame`,其余栈段整段搬入(嵌套循环期间这些栈只含生成器数据)。 + fn snapshot_generator(&mut self, state: &mut GeneratorState) -> Result<(), String> { + let frame = self + .frames + .pop() + .ok_or_else(|| "generator frame missing on yield".to_string())?; + state.frame = Some(frame); + state.regs = Box::new(self.regs); + state.pc = self.pc; + state.bytecode = std::mem::take(&mut self.bytecode); + state.sub_idx = if state.callee.is_object() { + unsafe { (*state.callee.as_js_object_ptr()).sub_module_index() } + } else { + 0 + }; + state.active_reg_limit = self.active_reg_limit; + state.root_reg_limit = self.root_reg_limit; + state.spill_stack = std::mem::take(&mut self.spill_stack); + state.save_stack = std::mem::take(&mut self.save_stack); + state.cell_stack = std::mem::take(&mut self.cell_stack); + state.try_stack = std::mem::take(&mut self.try_stack); + state.for_in_iters = std::mem::take(&mut self.iters.for_in_iters); + state.for_of_iters = std::mem::take(&mut self.iters.for_of_iters); + state.last_for_of_result = self.iters.last_for_of_result; + state.saved_bytecode_stack = std::mem::take(&mut self.saved_bytecode_stack); + state.saved_immutables_stack = std::mem::take(&mut self.saved_immutables_stack); + state.exception_value = self.exception_value.take(); + state.pending_exception = self.pending_exception.take(); + state.pending_error_kind = self.pending_error_kind.take(); + state.pending_completion = self.pending_completion.take(); + state.phase = GeneratorPhase::Suspended; + Ok(()) + } + + /// 在生成器挂起点交付 `return v` 完成:穿越 finally 或直接返回。 + /// + /// # 返回值 + /// - `Ok(Some(value))`:直接完成,无需再 dispatch(`value` 为返回值); + /// - `Ok(None)`:进入 finally 穿越,调用方须继续 `dispatch()`。 + fn complete_generator_return(&mut self, value: JsValue) -> Result, String> { + // return 逃出当前帧:弹出纯 catch handler,穿越 finally。 + self.pop_frame_catch_handlers(); + let crossed = self + .try_stack + .iter() + .filter(|h| h.frame_depth == self.frames.len() && h.finally_pc.is_some()) + .count(); + if let Some(finally_pc) = self.record_completion(crate::vm::Completion::Return { + value, + remaining_finally: crossed, + }) { + self.pc = finally_pc; + return Ok(None); + } + // 无 finally:直接交付返回(弹出生成器帧后 frames 为空 → Some(value))。 + self.do_return(value) + } +} + +/// `%GeneratorPrototype%.next`:恢复生成器执行到下一个 yield/return。 +pub(crate) fn generator_next(vm: &mut Vm, args: &[u8]) -> NativeResult { + let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] }); + let arg = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() }; + let step = vm.resume_generator(this_val, GeneratorResumeMode::Next(arg)); + generator_step_result(vm, step) +} + +/// `%GeneratorPrototype%.return`:提前结束生成器(穿越挂起中的 finally)。 +pub(crate) fn generator_return(vm: &mut Vm, args: &[u8]) -> NativeResult { + let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] }); + let arg = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() }; + let step = vm.resume_generator(this_val, GeneratorResumeMode::Return(arg)); + generator_step_result(vm, step) +} + +/// `%GeneratorPrototype%.throw`:向生成器注入异常。 +pub(crate) fn generator_throw(vm: &mut Vm, args: &[u8]) -> NativeResult { + let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] }); + let arg = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() }; + let step = vm.resume_generator(this_val, GeneratorResumeMode::Throw(arg)); + generator_step_result(vm, step) +} + +/// `%GeneratorPrototype%[@@iterator]`:生成器自身即可迭代,返回 `this`。 +pub(crate) fn generator_symbol_iterator(vm: &mut Vm, args: &[u8]) -> NativeResult { + let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] }); + NativeResult::Ok(this_val) +} + +/// 把恢复结局折叠为迭代器结果 `{value, done}` 或传播异常。 +fn generator_step_result(vm: &mut Vm, step: Result) -> NativeResult { + match step { + Ok(GeneratorStep::Suspended { value }) | Ok(GeneratorStep::Completed { value }) => { + let done = matches!(step, Ok(GeneratorStep::Completed { .. })); + NativeResult::Ok(make_iter_result(vm, value, done)) + } + Ok(GeneratorStep::Thrown { value }) => NativeResult::Err(value), + Err(e) => NativeResult::Err(oxide_builtins::error::create_type_error(vm, &e)), + } +} + +/// 初始化生成器内建对象:`%GeneratorPrototype%` 与 `%GeneratorFunction.prototype%`。 +/// +/// 两个原型对象存于 VM 字段(session 生命周期),`full_reset` 后重建。 +pub(crate) fn init_generator_intrinsics(vm: &mut Vm) { + let sf = vm.kernel_core.perm_interner().as_ref(); + let sh = vm.kernel_core.shape_forge().as_ref(); + let fn_proto_val = vm.session.builtin_world().fn_proto_val(); + let object_proto_val = JsValue::from_js_object(vm.session.builtin_world().object_proto.as_ptr() as *mut JsObject); + + // %GeneratorPrototype%:proto = Object.prototype,方法 next/return/throw/@@iterator。 + let mut gen_proto = Box::new(JsObject::new_empty(EMPTY_SHAPE_ID, object_proto_val)); + oxide_kernel::bind_methods_static!( + &mut gen_proto, + sf, + sh, + fn_proto_val, + ("next", generator_next as *const (), 1), + ("return", generator_return as *const (), 1), + ("throw", generator_throw as *const (), 1), + ); + // @@toStringTag(Object.prototype.toString → "[object Generator]")。 + let tag_si = sf.intern("@@toStringTag").0; + let tag_shape = sh.make_shape(gen_proto.shape_id(), tag_si); + gen_proto.set_shape_id(tag_shape); + let tag_pos = gen_proto.push_prop(JsValue::perm_string(sf.string_ptr(sf.intern("Generator").0))); + gen_proto.set_data_meta(tag_pos, oxide_types::object::PropAttributes::new(false, false, true)); + // @@iterator:返回自身(生成器是可迭代对象)。 + let iter_key = oxide_types::private_key::make_well_known_symbol_key(0); + let _ = oxide_kernel::builtin::BuiltinWorld::bind_method_key_static( + &mut gen_proto, + sh, + sf, + iter_key, + "@@iterator", + unsafe { oxide_types::object::NativeFnPtr::from_raw(generator_symbol_iterator as *const ()) }, + 0, + fn_proto_val, + ); + vm.generator_proto = P::new(*gen_proto); + + // %GeneratorFunction.prototype%:proto = Function.prototype,constructor = %GeneratorFunction%。 + let mut gf_ctor = Box::new(JsObject::new_empty(EMPTY_SHAPE_ID, fn_proto_val)); + gf_ctor.set_function(true); + gf_ctor.set_native_arg_count(1); + let mut gf_proto = Box::new(JsObject::new_empty(EMPTY_SHAPE_ID, fn_proto_val)); + // %GeneratorFunction% 构造器:动态生成器函数创建未实现,调用抛 TypeError。 + gf_ctor.set_native_fn(Some(unsafe { NativeFnPtr::from_raw(generator_function_stub as *const ()) })); + // prototype/name 属性(构造器形状 [prototype, name])。 + let proto_si = sf.intern("prototype").0; + let ctor_shape = sh.make_shape(gf_ctor.shape_id(), proto_si); + gf_ctor.set_shape_id(ctor_shape); + let ppos = gf_ctor.push_prop(JsValue::from_js_object(gf_proto.as_mut() as *mut JsObject)); + gf_ctor.set_data_meta(ppos, oxide_types::object::PropAttributes::new(false, false, false)); + let name_si = sf.intern("name").0; + let name_shape = sh.make_shape(gf_ctor.shape_id(), name_si); + gf_ctor.set_shape_id(name_shape); + let npos = gf_ctor.push_prop(JsValue::perm_string(sf.string_ptr(sf.intern("GeneratorFunction").0))); + gf_ctor.set_data_meta(npos, oxide_types::object::PropAttributes::new(false, false, true)); + // gf_proto.constructor = gf_ctor(构造器对象泄漏持有,与 builtin 方法 wrapper 同生命周期)。 + let ctor_si = sf.intern("constructor").0; + let ctor2_shape = sh.make_shape(gf_proto.shape_id(), ctor_si); + gf_proto.set_shape_id(ctor2_shape); + let cpos = gf_proto.push_prop(JsValue::from_js_object(Box::into_raw(gf_ctor))); + gf_proto.set_data_meta(cpos, oxide_types::object::PropAttributes::new(false, false, true)); + // gf_proto.prototype = %GeneratorPrototype%(默认原型,default-proto 测试读取)。 + let proto2_si = sf.intern("prototype").0; + let proto2_shape = sh.make_shape(gf_proto.shape_id(), proto2_si); + gf_proto.set_shape_id(proto2_shape); + let ppos2 = gf_proto.push_prop(JsValue::from_js_object(vm.generator_proto.as_ptr() as *mut JsObject)); + gf_proto.set_data_meta(ppos2, oxide_types::object::PropAttributes::new(false, false, false)); + // gf_proto[Symbol.toStringTag] = "GeneratorFunction"(数据属性,w/e/c = false/false/true)。 + let tag2_key = oxide_types::private_key::make_well_known_symbol_key(0); + let tag2_shape = sh.make_shape(gf_proto.shape_id(), tag2_key); + gf_proto.set_shape_id(tag2_shape); + let tag2_pos = gf_proto.push_prop(JsValue::perm_string(sf.string_ptr(sf.intern("GeneratorFunction").0))); + gf_proto.set_data_meta(tag2_pos, oxide_types::object::PropAttributes::new(false, false, true)); + + vm.generator_function_proto = P::new(*gf_proto); +} + +/// `%GeneratorFunction%` 占位:动态生成器函数创建未实现,调用抛错。 +fn generator_function_stub(vm: &mut Vm, _args: &[u8]) -> NativeResult { + NativeResult::Err(oxide_builtins::error::create_type_error( + vm, + "GeneratorFunction constructor is not supported", + )) +} + +// ── session GC 支撑:状态快照中的 JsValues 作为生成器对象边追踪 ── + +fn generator_state_mut(obj: &JsObject) -> Option<&mut GeneratorState> { + let ptr = obj.native_data() as *mut GeneratorState; + if ptr.is_null() { + None + } else { + // SAFETY: native_data 在 create_generator_object 中由 Box::into_raw 分配, + // 生命周期与生成器对象一致;GC 只在 reset(无执行状态)时运行。 + Some(unsafe { &mut *ptr }) + } +} + +/// 生成器状态内所有对象引用的扁平列表(GC mark 边)。 +pub(crate) fn generator_native_edges(obj: &JsObject) -> Vec { + let Some(state) = generator_state_mut(obj) else { + return Vec::new(); + }; + let mut edges = Vec::new(); + let push = |v: JsValue, edges: &mut Vec| { + if v.is_object() { + edges.push(v); + } + }; + push(state.callee, &mut edges); + edges.extend(state.args.iter().copied().filter(|v| v.is_object())); + push(state.result, &mut edges); + edges.extend(state.regs.iter().copied().filter(|v| v.is_object())); + if let Some(frame) = &state.frame { + push(frame.saved_this, &mut edges); + push(frame.saved_new_target, &mut edges); + push(frame.callee, &mut edges); + if let Some(ct) = frame.constructed_this { + push(ct, &mut edges); + } + } + edges.extend(state.spill_stack.iter().copied().filter(|v| v.is_object())); + edges.extend(state.save_stack.iter().copied().filter(|v| v.is_object())); + for cells in &state.cell_stack { + for &cell_ptr in cells { + if cell_ptr.is_null() { + continue; + } + // SAFETY: cell 由 session_epoch 分配,本 session 内指针有效。 + let cell = unsafe { &*cell_ptr }; + push(cell.value, &mut edges); + } + } + edges.extend(state.for_of_iters.iter().copied().filter(|v| v.is_object())); + push(state.last_for_of_result, &mut edges); + edges +} + +/// 用转发函数重写状态快照中的所有 JsValue(session GC 移动式清扫 / promote 用)。 +pub(crate) fn rewrite_generator_native(obj: &JsObject, mut rewrite: impl FnMut(JsValue) -> JsValue) { + let Some(state) = generator_state_mut(obj) else { + return; + }; + state.callee = rewrite(state.callee); + for v in &mut state.args { + *v = rewrite(*v); + } + state.result = rewrite(state.result); + for v in state.regs.iter_mut() { + *v = rewrite(*v); + } + if let Some(frame) = &mut state.frame { + frame.saved_this = rewrite(frame.saved_this); + frame.saved_new_target = rewrite(frame.saved_new_target); + frame.callee = rewrite(frame.callee); + frame.constructed_this = frame.constructed_this.map(&mut rewrite); + } + for v in &mut state.spill_stack { + *v = rewrite(*v); + } + for v in &mut state.save_stack { + *v = rewrite(*v); + } + for cells in &mut state.cell_stack { + for &mut cell_ptr in cells.iter_mut() { + if cell_ptr.is_null() { + continue; + } + // SAFETY: cell 由 session_epoch 分配,本 session 内指针有效。 + let cell = unsafe { &mut *cell_ptr }; + cell.value = rewrite(cell.value); + } + } + for v in &mut state.for_of_iters { + *v = rewrite(*v); + } + state.last_for_of_result = rewrite(state.last_for_of_result); +} + +/// 释放生成器状态盒(对象被 GC 回收时),返回释放字节数。 +pub(crate) fn drop_generator_native(obj: &JsObject) -> u64 { + let ptr = obj.native_data() as *mut GeneratorState; + if ptr.is_null() { + return 0; + } + // SAFETY: 指针来自 create_generator_object 的 Box::into_raw,只在 GC 回收时释放一次。 + let state = unsafe { Box::from_raw(ptr) }; + std::mem::size_of::() as u64 + + state.bytecode.len() as u64 * std::mem::size_of::() as u64 + + state.spill_stack.capacity() as u64 * std::mem::size_of::() as u64 + + state.save_stack.capacity() as u64 * std::mem::size_of::() as u64 + + state.for_of_iters.capacity() as u64 * std::mem::size_of::() as u64 + + state.args.capacity() as u64 * std::mem::size_of::() as u64 +} diff --git a/crates/oxide_vm/src/lib.rs b/crates/oxide_vm/src/lib.rs index 7268c9f3..c3a7ce30 100644 --- a/crates/oxide_vm/src/lib.rs +++ b/crates/oxide_vm/src/lib.rs @@ -10,6 +10,7 @@ /// 内置对象绑定模块:向 session 的 global 对象安装 Object/Array/... 及各原型。 pub mod bindings; mod dispatch; +mod generator; mod ic_helper; /// native 函数签名类型([`native::NativeFn`]),builtin 绑定与 VM 调用约定依赖它。 pub mod native; diff --git a/crates/oxide_vm/src/session_arena.rs b/crates/oxide_vm/src/session_arena.rs index 50054f55..e6be51cd 100644 --- a/crates/oxide_vm/src/session_arena.rs +++ b/crates/oxide_vm/src/session_arena.rs @@ -65,6 +65,11 @@ impl Vm { data_view::clone_data_view_native_with_rewrite(src_ref, dst_ref, |value| { self.promote_value_if_epoch_object(value, forwarding) }); + } else if src_ref.is_generator_obj() { + // 生成器状态盒为堆分配、promote 后与源共享同一盒:就地改写其 JsValue。 + crate::generator::rewrite_generator_native(dst_ref, |value| { + self.promote_value_if_epoch_object(value, forwarding) + }); } dst } diff --git a/crates/oxide_vm/src/session_gc.rs b/crates/oxide_vm/src/session_gc.rs index 23ae0f77..c39f0a3e 100644 --- a/crates/oxide_vm/src/session_gc.rs +++ b/crates/oxide_vm/src/session_gc.rs @@ -89,6 +89,9 @@ impl SessionGc { if obj.is_data_view_obj() { edges.extend(data_view::data_view_native_edges(obj)); } + if obj.is_generator_obj() { + edges.extend(crate::generator::generator_native_edges(obj)); + } // 遍历 upvalue cell 中的对象引用。 for cell_ptr in obj.upvalues_slice() { if cell_ptr.is_null() { @@ -144,6 +147,13 @@ impl SessionGc { } } } + if obj.is_generator_obj() { + for value in crate::generator::generator_native_edges(obj) { + if value.is_string() { + live.insert(value.as_string_ptr_mut()); + } + } + } } pub(crate) fn mark(&mut self, vm: &Vm) { @@ -253,6 +263,7 @@ impl SessionGc { freed_bytes += regexp::drop_regexp_native(obj); freed_bytes += typed_array::drop_typed_array_native(obj); freed_bytes += data_view::drop_data_view_native(obj); + freed_bytes += crate::generator::drop_generator_native(obj); freed_bytes } @@ -338,6 +349,8 @@ impl SessionGc { typed_array::rewrite_typed_array_native(obj, |value| rewrite_forwarded_value(value, &forwarding)); } else if obj.is_data_view_obj() { data_view::rewrite_data_view_native(obj, |value| rewrite_forwarded_value(value, &forwarding)); + } else if obj.is_generator_obj() { + crate::generator::rewrite_generator_native(obj, |value| rewrite_forwarded_value(value, &forwarding)); } } diff --git a/crates/oxide_vm/src/vm.rs b/crates/oxide_vm/src/vm.rs index 7075bf0f..a03fa172 100644 --- a/crates/oxide_vm/src/vm.rs +++ b/crates/oxide_vm/src/vm.rs @@ -239,6 +239,11 @@ pub struct Vm { pub(crate) session: KernelSession, pub epoch: Epoch, pub object_prototype: P, + /// `%GeneratorPrototype%`:生成器实例的原型(next/return/throw 方法挂此)。 + pub generator_proto: P, + /// `%GeneratorFunction.prototype%`:生成器函数对象的原型(`constructor` 指向 + /// `%GeneratorFunction%`,使 `g.constructor.name` 解析为 "GeneratorFunction")。 + pub generator_function_proto: P, pub math_rng_state: u64, /// 全局扁平模块表:下标 = 模块 `flat_id`(顶层 0,子模块 flatten 后全局唯一)。 /// 闭包 `sub_module_index` 即 flat_id,逃逸闭包也能自足解析。 @@ -277,6 +282,16 @@ pub struct Vm { /// frames 为空(inline 隔离状态)时由此取闭包 upvalues。嵌套 inline 由 /// InlineSyncState 保存/恢复。 pub(crate) inline_callee: Option, + /// 生成器体 `dispatch()` 让出时的信号:YIELD 置 Some(让出值),恢复方( + /// generator 内嵌 dispatch 循环)取走并判定挂起。None = 正常返回/异常。 + pub(crate) generator_suspended: Option, + /// 当前是否处于生成器内嵌 dispatch 循环:生成器帧弹出且 frames 清空时, + /// `do_return` 据此把结果交付给恢复方(而非当作普通顶层返回继续执行)。 + pub(crate) generator_dispatch: bool, + /// 生成器调用时参数初始化步:body 起点标记(SUSPEND_BODY)据此判定"挂起在 body 前"。 + pub(crate) generator_init_step: bool, + /// 参数初始化步中已越过 body 起点标记的信号(`initialize_generator` 消费后复位)。 + pub(crate) generator_body_started: bool, /// 分组保存 session arena / GC 簿记状态。 pub(crate) gc_state: GcState, /// 分组保存 `Symbol` intern 状态。 @@ -1488,6 +1503,23 @@ impl Vm { Err(e) => return Err(e), }, + OpCode::YIELD => { + // 生成器让出:把让出值存入信号,内嵌 dispatch 返回,恢复方快照挂起状态。 + let value = self.regs[rd]; + self.generator_suspended = Some(value); + self.profiling.set_instruction_count(steps); + return Ok(JsValue::undefined()); + } + + OpCode::SUSPEND_BODY => { + // 生成器调用时参数初始化结束:挂起在 body 起点;正常 next() 恢复时直接穿过。 + if self.generator_init_step { + self.generator_body_started = true; + self.profiling.set_instruction_count(steps); + return Ok(JsValue::undefined()); + } + } + _ => { return Err(format!("opcode {op} not yet implemented")); } diff --git a/crates/oxide_vm/src/vm_dispatch_ctrl.rs b/crates/oxide_vm/src/vm_dispatch_ctrl.rs index bc547ef8..e9ac4850 100644 --- a/crates/oxide_vm/src/vm_dispatch_ctrl.rs +++ b/crates/oxide_vm/src/vm_dispatch_ctrl.rs @@ -31,9 +31,16 @@ impl Vm { self.dispatch_native_call(obj, callee, this_reg, first_arg_reg, arg_count)?; return Ok(true); } else if obj.sub_module_index() > 0 { + let sub_idx = obj.sub_module_index() as usize; let args: Vec = (0..arg_count) .map(|i| self.regs[first_arg_reg.wrapping_add(i as u8) as usize]) .collect(); + // 生成器函数调用返回迭代器对象,不执行函数体。 + if sub_idx < self.sub_modules.len() && self.sub_modules[sub_idx].is_generator { + let gen = self.create_generator_object(callee, self.regs[this_reg as usize], &args)?; + self.regs[0] = gen; + return Ok(false); + } self.push_bytecode_frame( callee, self.regs[this_reg as usize], @@ -200,7 +207,7 @@ impl Vm { /// /// # 副作用 /// - 清空 `pending_exception`/`pending_completion`,弹出被逃出的 handler。 - fn record_completion(&mut self, c: Completion) -> Option { + pub(crate) fn record_completion(&mut self, c: Completion) -> Option { self.pending_exception = None; self.pending_error_kind = None; self.pending_completion = None; @@ -273,7 +280,7 @@ impl Vm { /// - 只处理 `frame_depth == frames.len()` 的 handler:return 只逃出本帧, /// 调用者的 handler 必须保留。 /// - 纯 catch 判定为 `finally_pc.is_none()`(不携带 finally 的 TRY_BEGIN)。 - fn pop_frame_catch_handlers(&mut self) { + pub(crate) fn pop_frame_catch_handlers(&mut self) { let depth = self.frames.len(); let mut kept = Vec::with_capacity(self.try_stack.len()); for h in self.try_stack.drain(..) { @@ -287,7 +294,7 @@ impl Vm { /// 实际执行返回:弹出当前帧并交付返回值(供 dispatch_return 与 finally 完成 /// 恢复共用)。 - fn do_return(&mut self, result: JsValue) -> Result, String> { + pub(crate) fn do_return(&mut self, result: JsValue) -> Result, String> { // 兜底:return 完成恢复路径(dispatch_try_finally_end 直达)也可能携带 // 未清理的纯 catch handler,先弹出再弹帧。 self.pop_frame_catch_handlers(); @@ -320,6 +327,10 @@ impl Vm { } } } + // 生成器内嵌 dispatch:帧全部弹出后把结果交付恢复方,而非继续执行。 + if self.frames.is_empty() && self.generator_dispatch { + return Ok(Some(result)); + } Ok(None) } else { vm_trace!("RETURN top-level: regs[0]={:?}", result); diff --git a/crates/oxide_vm/src/vm_dispatch_misc.rs b/crates/oxide_vm/src/vm_dispatch_misc.rs index e3dfb47e..08f701ad 100644 --- a/crates/oxide_vm/src/vm_dispatch_misc.rs +++ b/crates/oxide_vm/src/vm_dispatch_misc.rs @@ -95,6 +95,10 @@ impl Vm { self.sub_modules.len() )); } + // 生成器函数不是构造器:`new g()` 抛 TypeError。 + if self.sub_modules[sub_idx].is_generator { + return self.raise_type_error("g is not a constructor").map(|_| true); + } if self.frames.len() >= self.kernel_core.config.max_call_depth { return Err(self.error_message_text("RangeError", "Maximum call stack size exceeded")); diff --git a/crates/oxide_vm/src/vm_runtime.rs b/crates/oxide_vm/src/vm_runtime.rs index e0327a4a..d078c284 100644 --- a/crates/oxide_vm/src/vm_runtime.rs +++ b/crates/oxide_vm/src/vm_runtime.rs @@ -26,6 +26,64 @@ fn place_flat(module: &CompiledModule, out: &mut Vec>) { } impl Vm { + /// 保存当前完整 VM 执行状态到堆上(内联同步调用与生成器恢复共用)。 + pub(crate) fn save_inline_state(&mut self) -> Box { + vm_trace!("save_inline_state: pc={} depth={}", self.pc, self.frames.len()); + Box::new(InlineSyncState { + regs: Box::new(self.regs), + pc: self.pc, + bytecode: std::mem::take(&mut self.bytecode), + active_immutables: self.active_immutables, + active_reg_limit: self.active_reg_limit, + root_reg_limit: self.root_reg_limit, + try_stack: std::mem::take(&mut self.try_stack), + frames: std::mem::take(&mut self.frames), + exception_value: self.exception_value.take(), + pending_exception: self.pending_exception.take(), + pending_error_kind: self.pending_error_kind.take(), + pending_completion: self.pending_completion, + for_in_iters: std::mem::take(&mut self.iters.for_in_iters), + for_of_iters: std::mem::take(&mut self.iters.for_of_iters), + last_for_of_result: self.iters.last_for_of_result, + saved_bytecode_stack: std::mem::take(&mut self.saved_bytecode_stack), + saved_immutables_stack: std::mem::take(&mut self.saved_immutables_stack), + save_stack: std::mem::take(&mut self.save_stack), + spill_stack: std::mem::take(&mut self.spill_stack), + cell_stack: std::mem::take(&mut self.cell_stack), + inline_callee: self.inline_callee, + inline_args_base: self.inline_args_base, + inline_args_count: self.inline_args_count, + }) + } + + /// 把 [`save_inline_state`] 保存的状态完整恢复回 VM。 + pub(crate) fn restore_inline_state(&mut self, saved: Box) { + vm_trace!("restore_inline_state: pc={}", saved.pc); + self.regs = *saved.regs; + self.pc = saved.pc; + self.bytecode = saved.bytecode; + self.active_immutables = saved.active_immutables; + self.active_reg_limit = saved.active_reg_limit; + self.root_reg_limit = saved.root_reg_limit; + self.try_stack = saved.try_stack; + self.frames = saved.frames; + self.exception_value = saved.exception_value; + self.pending_exception = saved.pending_exception; + self.pending_error_kind = saved.pending_error_kind; + self.pending_completion = saved.pending_completion; + self.iters.for_in_iters = saved.for_in_iters; + self.iters.for_of_iters = saved.for_of_iters; + self.iters.last_for_of_result = saved.last_for_of_result; + self.saved_bytecode_stack = saved.saved_bytecode_stack; + self.saved_immutables_stack = saved.saved_immutables_stack; + self.save_stack = saved.save_stack; + self.spill_stack = saved.spill_stack; + self.cell_stack = saved.cell_stack; + self.inline_callee = saved.inline_callee; + self.inline_args_base = saved.inline_args_base; + self.inline_args_count = saved.inline_args_count; + } + pub(crate) fn call_bytecode_function_inline( &mut self, callee: JsValue, callee_obj: &JsObject, receiver: JsValue, args: &[JsValue], ) -> Result { @@ -54,37 +112,17 @@ impl Vm { self.raise_error_kind("RangeError", "Maximum call stack size exceeded")?; return Ok(JsValue::undefined()); } + // 生成器函数调用返回迭代器对象,不执行函数体。 + if self.sub_modules[sub_idx].is_generator { + return self.create_generator_object(callee, receiver, args); + } self.native_call_depth += 1; let subs = Arc::clone(&self.sub_modules); let sub = &subs[sub_idx]; vm_trace!("call_bytecode: saving state pc={} depth={}", self.pc, self.frames.len()); - let saved = Box::new(InlineSyncState { - regs: Box::new(self.regs), - pc: self.pc, - bytecode: std::mem::take(&mut self.bytecode), - active_immutables: self.active_immutables, - active_reg_limit: self.active_reg_limit, - root_reg_limit: self.root_reg_limit, - try_stack: std::mem::take(&mut self.try_stack), - frames: std::mem::take(&mut self.frames), - exception_value: self.exception_value.take(), - pending_exception: self.pending_exception.take(), - pending_error_kind: self.pending_error_kind.take(), - pending_completion: self.pending_completion, - for_in_iters: std::mem::take(&mut self.iters.for_in_iters), - for_of_iters: std::mem::take(&mut self.iters.for_of_iters), - last_for_of_result: self.iters.last_for_of_result, - saved_bytecode_stack: std::mem::take(&mut self.saved_bytecode_stack), - saved_immutables_stack: std::mem::take(&mut self.saved_immutables_stack), - save_stack: std::mem::take(&mut self.save_stack), - spill_stack: std::mem::take(&mut self.spill_stack), - cell_stack: std::mem::take(&mut self.cell_stack), - inline_callee: self.inline_callee, - inline_args_base: self.inline_args_base, - inline_args_count: self.inline_args_count, - }); + let saved = self.save_inline_state(); self.regs = [JsValue::undefined(); 256]; self.pc = 0; @@ -123,30 +161,7 @@ impl Vm { self.native_call_depth -= 1; vm_trace!("call_bytecode: restoring state pc={} result={:?}", saved.pc, result.as_ref().ok()); - self.regs = *saved.regs; - self.pc = saved.pc; - self.bytecode = saved.bytecode; - self.active_immutables = saved.active_immutables; - self.active_reg_limit = saved.active_reg_limit; - self.root_reg_limit = saved.root_reg_limit; - self.try_stack = saved.try_stack; - self.frames = saved.frames; - self.exception_value = saved.exception_value; - self.pending_exception = saved.pending_exception; - self.pending_error_kind = saved.pending_error_kind; - self.pending_completion = saved.pending_completion; - self.iters.for_in_iters = saved.for_in_iters; - self.iters.for_of_iters = saved.for_of_iters; - self.iters.last_for_of_result = saved.last_for_of_result; - self.saved_bytecode_stack = saved.saved_bytecode_stack; - self.saved_immutables_stack = saved.saved_immutables_stack; - self.save_stack = saved.save_stack; - self.spill_stack = saved.spill_stack; - self.cell_stack = saved.cell_stack; - self.inline_callee = saved.inline_callee; - self.inline_args_base = saved.inline_args_base; - self.inline_args_count = saved.inline_args_count; - + self.restore_inline_state(saved); result } diff --git a/crates/oxide_vm/src/vm_support.rs b/crates/oxide_vm/src/vm_support.rs index c50fa3bc..5c53038e 100644 --- a/crates/oxide_vm/src/vm_support.rs +++ b/crates/oxide_vm/src/vm_support.rs @@ -21,7 +21,7 @@ impl Vm { let mut session = KernelSession::new(&core); bindings::init_kernel_builtins(&core, &mut session); let obj_proto = P::clone(&session.builtin_world().object_proto); - let vm = Self { + let mut vm = Self { regs: [JsValue::undefined(); 256], pc: 0, bytecode: Vec::new(), @@ -32,6 +32,8 @@ impl Vm { session, epoch: Epoch::new(), object_prototype: obj_proto, + generator_proto: P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null())), + generator_function_proto: P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null())), math_rng_state: 0, sub_modules: Arc::new(Vec::new()), saved_bytecode_stack: Vec::new(), @@ -51,6 +53,10 @@ impl Vm { inline_args_count: 0, accessor_frame_target_reg: None, inline_callee: None, + generator_suspended: None, + generator_dispatch: false, + generator_init_step: false, + generator_body_started: false, gc_state: GcState { session_epoch: bumpalo::Bump::new(), session_gc: crate::session_gc::SessionGc::new(), @@ -78,6 +84,7 @@ impl Vm { string_buf: String::new(), cell_stack: Vec::new(), }; + vm.init_generator_intrinsics(); vm_info!("Vm created"); vm } @@ -87,7 +94,7 @@ impl Vm { let mut session = KernelSession::new(&core); bindings::init_kernel_builtins(&core, &mut session); let obj_proto = P::clone(&session.builtin_world().object_proto); - let vm = Self { + let mut vm = Self { regs: [JsValue::undefined(); 256], pc: 0, bytecode: Vec::new(), @@ -98,6 +105,8 @@ impl Vm { session, epoch: Epoch::new(), object_prototype: obj_proto, + generator_proto: P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null())), + generator_function_proto: P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null())), math_rng_state: 0, sub_modules: Arc::new(Vec::new()), saved_bytecode_stack: Vec::new(), @@ -117,6 +126,10 @@ impl Vm { inline_args_count: 0, accessor_frame_target_reg: None, inline_callee: None, + generator_suspended: None, + generator_dispatch: false, + generator_init_step: false, + generator_body_started: false, gc_state: GcState { session_epoch: bumpalo::Bump::new(), session_gc: crate::session_gc::SessionGc::new(), @@ -144,10 +157,19 @@ impl Vm { string_buf: String::new(), cell_stack: Vec::new(), }; + vm.init_generator_intrinsics(); vm_info!("Vm created (pool)"); vm } + /// 初始化/重建生成器内建对象(`%GeneratorPrototype%` 与 `%GeneratorFunction.prototype%`)。 + /// + /// 在 VM 创建与 `full_reset`(session 重建)后调用——原型继承自 session 的 + /// Object/Function 原型,session 重建后须重挂。 + pub(crate) fn init_generator_intrinsics(&mut self) { + crate::generator::init_generator_intrinsics(self); + } + /// 全量隔离重置:仅重建被污染的内置对象与 global,并清空所有执行状态与内存。 /// /// 用于在多次 JS 执行之间达到完全隔离:session 内未被污染的 builtin 保留原指针。 @@ -163,6 +185,7 @@ impl Vm { } self.session.record_snapshot(); self.object_prototype = P::clone(&self.session.builtin_world().object_proto); + self.init_generator_intrinsics(); self.clear_full_reset_state(); vm_info!("full_reset completed"); } @@ -173,6 +196,7 @@ impl Vm { self.session = KernelSession::new(&self.kernel_core); bindings::init_kernel_builtins(&self.kernel_core, &mut self.session); self.object_prototype = P::clone(&self.session.builtin_world().object_proto); + self.init_generator_intrinsics(); self.clear_full_reset_state(); } @@ -226,6 +250,10 @@ impl Vm { self.pending_exception = None; self.pending_error_kind = None; self.pending_completion = None; + self.generator_suspended = None; + self.generator_dispatch = false; + self.generator_init_step = false; + self.generator_body_started = false; self.native_call_depth = 0; } @@ -290,8 +318,14 @@ impl Vm { &mut self, sub_idx: u32, is_arrow: bool, is_class_constructor: bool, is_derived_constructor: bool, needs_home_object: bool, ) -> JsValue { - let func_proto_ptr = self.session.builtin_world().function_proto.as_ptr() as *mut JsObject; - let proto_val = JsValue::from_js_object(func_proto_ptr); + // 生成器函数对象:原型为 %GeneratorFunction.prototype%(constructor 链解析到 + // "GeneratorFunction"),且不像普通函数那样拥有 `prototype` 属性。 + let is_generator = self.sub_modules.get(sub_idx as usize).map(|m| m.is_generator).unwrap_or(false); + let proto_val = if is_generator { + JsValue::from_js_object(self.generator_function_proto.as_ptr() as *mut JsObject) + } else { + JsValue::from_js_object(self.session.builtin_world().function_proto.as_ptr() as *mut JsObject) + }; let mut obj = JsObject::new_empty(EMPTY_SHAPE_ID, proto_val); obj.set_function(true); obj.set_sub_module_index(sub_idx); @@ -306,26 +340,36 @@ impl Vm { let func_val = JsValue::object(obj_ptr as *mut u8); if !is_arrow { - let object_proto_ptr = self.session.builtin_world().object_proto.as_ptr() as *mut JsObject; - let prototype_obj = self - .epoch - .alloc(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::from_js_object(object_proto_ptr))); + // 原型对象自身的 [[Prototype]]:生成器为 %GeneratorPrototype%,普通函数为 Object.prototype。 + let proto_of_proto = if is_generator { + JsValue::from_js_object(self.generator_proto.as_ptr() as *mut JsObject) + } else { + JsValue::from_js_object(self.session.builtin_world().object_proto.as_ptr() as *mut JsObject) + }; + let prototype_obj = self.epoch.alloc(JsObject::new_empty(EMPTY_SHAPE_ID, proto_of_proto)); self.gc_state.track_epoch_object(prototype_obj); let prototype_val = JsValue::from_js_object(prototype_obj); - let constructor_si = self.kernel_core.perm_interner().intern("constructor").0; - let constructor_shape = self.kernel_core.shape_forge().make_shape(EMPTY_SHAPE_ID, constructor_si); - let prototype = unsafe { &mut *prototype_obj }; - prototype.set_shape_id(constructor_shape); - let constructor_pos = prototype.push_prop(func_val); - prototype.set_data_meta(constructor_pos, PropAttributes::new(true, false, true)); - prototype.bump_generation(); + if !is_generator { + // 普通函数:prototype 对象带 constructor 指回函数。 + let constructor_si = self.kernel_core.perm_interner().intern("constructor").0; + let constructor_shape = self.kernel_core.shape_forge().make_shape(EMPTY_SHAPE_ID, constructor_si); + let prototype = unsafe { &mut *prototype_obj }; + prototype.set_shape_id(constructor_shape); + let constructor_pos = prototype.push_prop(func_val); + prototype.set_data_meta(constructor_pos, PropAttributes::new(true, false, true)); + prototype.bump_generation(); + } + // 函数自身 `prototype` 属性:生成器 writable:true / enumerable:false / configurable:false。 let prototype_si = self.kernel_core.perm_interner().intern("prototype").0; let func = unsafe { &mut *obj_ptr }; let prototype_shape = self.kernel_core.shape_forge().make_shape(func.shape_id(), prototype_si); func.set_shape_id(prototype_shape); - func.ensure_hash_props().push(prototype_val); + let prototype_pos = func.push_prop(prototype_val); + if is_generator { + func.set_data_meta(prototype_pos, PropAttributes::new(true, false, false)); + } func.bump_generation(); }