mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-24 02:31:13 +08:00
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:
@@ -320,7 +320,8 @@ fn current_index<H: VmHost>(vm: &mut H, wrapper: &JsObject, index_si: u32) -> us
|
||||
}
|
||||
}
|
||||
|
||||
fn make_iter_result<H: VmHost>(vm: &mut H, value: JsValue, done: bool) -> JsValue {
|
||||
/// 构造迭代器结果对象 `{value, done}`(生成器 next/return 结果复用)。
|
||||
pub fn make_iter_result<H: VmHost>(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()
|
||||
|
||||
@@ -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<UpvalueCapture>,
|
||||
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,
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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)?;
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -50,6 +50,8 @@ pub struct IRFunction {
|
||||
pub is_class_constructor: bool,
|
||||
pub is_derived_constructor: bool,
|
||||
pub needs_home_object: bool,
|
||||
/// 是否为生成器函数体(`function*`)。
|
||||
pub is_generator: bool,
|
||||
pub captured_this_const_idx: u16,
|
||||
pub function_name: Option<String>,
|
||||
/// 函数 `length` 属性值:第一个带默认值/解构默认的形参之前的形参数(rest 不计)。
|
||||
@@ -80,6 +82,7 @@ impl IRFunction {
|
||||
is_class_constructor: false,
|
||||
is_derived_constructor: false,
|
||||
needs_home_object: false,
|
||||
is_generator: false,
|
||||
captured_this_const_idx: 0,
|
||||
function_name: None,
|
||||
function_length: 0,
|
||||
|
||||
@@ -89,6 +89,7 @@ pub fn lower(f: &IRFunction) -> Result<CompiledModule, String> {
|
||||
is_class_constructor: f.is_class_constructor,
|
||||
is_derived_constructor: f.is_derived_constructor,
|
||||
needs_home_object: f.needs_home_object,
|
||||
is_generator: f.is_generator,
|
||||
upvalue_captures: f.upvalue_captures.clone(),
|
||||
cells_needed: f.cells_needed,
|
||||
flat_id: 0,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -401,8 +401,6 @@ fn is_skipped(meta: &TestMeta) -> Option<String> {
|
||||
let excluded_features = [
|
||||
"Proxy",
|
||||
"BigInt",
|
||||
"generators",
|
||||
"generator",
|
||||
"async-functions",
|
||||
"Intl",
|
||||
"Temporal",
|
||||
@@ -418,12 +416,6 @@ fn is_skipped(meta: &TestMeta) -> Option<String> {
|
||||
}
|
||||
}
|
||||
|
||||
// 仅当 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
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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"));
|
||||
}
|
||||
|
||||
@@ -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<JsValue>,
|
||||
/// 首次调用时的方法接收者(`obj.g()` 的 `obj`),压帧时作 `this` 绑定。
|
||||
pub this_value: JsValue,
|
||||
/// 完成后返回值。
|
||||
pub result: JsValue,
|
||||
// ── 挂起时的执行上下文 ──
|
||||
pub regs: Box<[JsValue; 256]>,
|
||||
pub pc: usize,
|
||||
pub bytecode: Vec<opcode::Instr>,
|
||||
/// 生成器模块 flat_id(恢复时重激活 immutables)。
|
||||
pub sub_idx: u32,
|
||||
pub active_reg_limit: u8,
|
||||
pub root_reg_limit: u8,
|
||||
/// 生成器帧(压入时由 push_bytecode_frame 构造,挂起时弹出存此)。
|
||||
pub frame: Option<CallFrame>,
|
||||
pub spill_stack: Vec<JsValue>,
|
||||
pub save_stack: Vec<JsValue>,
|
||||
pub cell_stack: Vec<Vec<*mut Cell>>,
|
||||
pub try_stack: Vec<TryHandler>,
|
||||
pub for_in_iters: Vec<*mut ForInIter<'static>>,
|
||||
pub for_of_iters: Vec<JsValue>,
|
||||
pub last_for_of_result: JsValue,
|
||||
pub saved_bytecode_stack: Vec<Vec<opcode::Instr>>,
|
||||
pub saved_immutables_stack: Vec<*const [JsValue]>,
|
||||
/// 在途异常/完成(throw 穿越 finally 挂起时保留,恢复后继续展开)。
|
||||
pub exception_value: Option<JsValue>,
|
||||
pub pending_exception: Option<JsValue>,
|
||||
pub pending_error_kind: Option<&'static str>,
|
||||
pub pending_completion: Option<crate::vm::Completion>,
|
||||
}
|
||||
|
||||
/// `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<JsValue, String> {
|
||||
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<GeneratorStep, String> {
|
||||
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<Option<JsValue>, 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<GeneratorStep, String>) -> 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<JsValue> {
|
||||
let Some(state) = generator_state_mut(obj) else {
|
||||
return Vec::new();
|
||||
};
|
||||
let mut edges = Vec::new();
|
||||
let push = |v: JsValue, edges: &mut Vec<JsValue>| {
|
||||
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::<GeneratorState>() as u64
|
||||
+ state.bytecode.len() as u64 * std::mem::size_of::<u32>() as u64
|
||||
+ state.spill_stack.capacity() as u64 * std::mem::size_of::<JsValue>() as u64
|
||||
+ state.save_stack.capacity() as u64 * std::mem::size_of::<JsValue>() as u64
|
||||
+ state.for_of_iters.capacity() as u64 * std::mem::size_of::<JsValue>() as u64
|
||||
+ state.args.capacity() as u64 * std::mem::size_of::<JsValue>() as u64
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -239,6 +239,11 @@ pub struct Vm {
|
||||
pub(crate) session: KernelSession,
|
||||
pub epoch: Epoch,
|
||||
pub object_prototype: P<JsObject>,
|
||||
/// `%GeneratorPrototype%`:生成器实例的原型(next/return/throw 方法挂此)。
|
||||
pub generator_proto: P<JsObject>,
|
||||
/// `%GeneratorFunction.prototype%`:生成器函数对象的原型(`constructor` 指向
|
||||
/// `%GeneratorFunction%`,使 `g.constructor.name` 解析为 "GeneratorFunction")。
|
||||
pub generator_function_proto: P<JsObject>,
|
||||
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<JsValue>,
|
||||
/// 生成器体 `dispatch()` 让出时的信号:YIELD 置 Some(让出值),恢复方(
|
||||
/// generator 内嵌 dispatch 循环)取走并判定挂起。None = 正常返回/异常。
|
||||
pub(crate) generator_suspended: Option<JsValue>,
|
||||
/// 当前是否处于生成器内嵌 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"));
|
||||
}
|
||||
|
||||
@@ -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<JsValue> = (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<usize> {
|
||||
pub(crate) fn record_completion(&mut self, c: Completion) -> Option<usize> {
|
||||
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<Option<JsValue>, String> {
|
||||
pub(crate) fn do_return(&mut self, result: JsValue) -> Result<Option<JsValue>, 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);
|
||||
|
||||
@@ -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"));
|
||||
|
||||
@@ -26,6 +26,64 @@ fn place_flat(module: &CompiledModule, out: &mut Vec<Option<CompiledModule>>) {
|
||||
}
|
||||
|
||||
impl Vm {
|
||||
/// 保存当前完整 VM 执行状态到堆上(内联同步调用与生成器恢复共用)。
|
||||
pub(crate) fn save_inline_state(&mut self) -> Box<InlineSyncState> {
|
||||
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<InlineSyncState>) {
|
||||
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<JsValue, String> {
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user