mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-23 18:21:13 +08:00
refactor: VM 执行状态类型从 vm.rs 移入 vm 目录
This commit is contained in:
@@ -0,0 +1,198 @@
|
|||||||
|
//! 调用帧与完成值类型:帧续行方式、压帧实参来源、调用帧、for-in 迭代游标、
|
||||||
|
//! try/catch/finally 处理记录,以及 break/continue/return 完成值(含访问器)。
|
||||||
|
|
||||||
|
use oxide_types::value::JsValue;
|
||||||
|
|
||||||
|
/// 调用帧被挂起后,恢复时需要继续的执行方式。
|
||||||
|
///
|
||||||
|
/// `AccessorGet` 表示 accessor getter 返回后需把结果写回 `target_reg`;
|
||||||
|
/// `AccessorSet` 表示 setter 调用完成;`None` 为普通调用返回。
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub enum FrameContinuation {
|
||||||
|
None,
|
||||||
|
AccessorGet { target_reg: u8 },
|
||||||
|
AccessorSet,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 压帧实参来源:已物化切片或寄存器连续区间。
|
||||||
|
///
|
||||||
|
/// `RegRange` 直接引用调用方寄存器文件(CALL/NEW/SUPER_CALL 的实参在寄存器中
|
||||||
|
/// 天然连续排列),免去临时堆 `Vec<JsValue>` 物化,每次调用省 1 次分配/释放。
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub(crate) enum FrameArgs<'a> {
|
||||||
|
/// 已物化实参:spread 展开、TailCall、accessor 与初始执行路径。
|
||||||
|
Slice(&'a [JsValue]),
|
||||||
|
/// 寄存器连续区间 `regs[first .. first+count)`。
|
||||||
|
RegRange { first: u8, count: usize },
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FrameArgs<'_> {
|
||||||
|
/// 实参总数。
|
||||||
|
pub(crate) fn len(&self) -> usize {
|
||||||
|
match self {
|
||||||
|
FrameArgs::Slice(s) => s.len(),
|
||||||
|
FrameArgs::RegRange { count, .. } => *count,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 一次函数调用的调用帧:记录返回地址、调用方寄存器窗口与 `this`/`new.target`。
|
||||||
|
///
|
||||||
|
/// 调用方寄存器窗口在 `save_stack` 中按 `saved_reg_offset` 保存,返回时由
|
||||||
|
/// `restore_frame` 恢复;`continuation` 描述 getter/setter 场景的恢复方式。
|
||||||
|
pub struct CallFrame {
|
||||||
|
pub return_addr: usize,
|
||||||
|
pub function_name: u32,
|
||||||
|
/// 压帧保存的调用方寄存器窗口长度(= save_stack 中本帧段大小)。
|
||||||
|
/// 普通字节码调用按调用点存活上界截断;运行时发起(accessor/内联)为
|
||||||
|
/// 调用方 `active_reg_limit` 全量。
|
||||||
|
pub caller_reg_limit: u8,
|
||||||
|
/// 压帧时刻调用方 `active_reg_limit`(真实值):帧恢复时据此还原,与
|
||||||
|
/// `caller_reg_limit`(可能被存活上界截断的窗口)解耦。
|
||||||
|
pub caller_active_reg_limit: u8,
|
||||||
|
pub saved_reg_offset: u32,
|
||||||
|
/// 记录本帧 spill 栈起始长度,作为 SPILL/UNSPILL 的帧边界基址(push 时快照)。
|
||||||
|
pub spill_offset: u32,
|
||||||
|
/// 本帧完整实参在 spill 栈的起始下标(帧恢复时随 spill 区一起截断丢弃)。
|
||||||
|
pub arguments_base: u32,
|
||||||
|
/// 实际传入的实参个数(可大于形参个数)。
|
||||||
|
pub arguments_count: u16,
|
||||||
|
pub saved_this: JsValue,
|
||||||
|
pub saved_new_target: JsValue,
|
||||||
|
pub callee: JsValue,
|
||||||
|
pub construct_result_reg: Option<u8>,
|
||||||
|
pub constructed_this: Option<JsValue>,
|
||||||
|
pub is_derived_constructor: bool,
|
||||||
|
/// derived 构造帧是否已成功调用 super()(父构造器正常返回后置位)。
|
||||||
|
///
|
||||||
|
/// 置位识别依赖 ABI 不变量:`construct_result_reg == Some(254)` 仅 SUPER_CALL
|
||||||
|
/// 压帧产生(emit 从寄存器 ≥1 分配,254 保留给 this);父构造器抛错走 unwind
|
||||||
|
/// 弹帧不进 do_return,不置位。此标志取代依赖 regs[254] 值判定 super 状态的
|
||||||
|
/// 旧方案——多层继承时中间 derived 帧由 SUPER_CALL 以构造 this 压入,
|
||||||
|
/// regs[254] 恒非 undefined,值判定三重失效。
|
||||||
|
pub super_called: bool,
|
||||||
|
/// 本帧函数的严格模式标志(来源:模块编译产物 `is_strict`)。
|
||||||
|
/// 属性写失败时据此分派:严格模式抛 TypeError,sloppy 静默 no-op。
|
||||||
|
pub strict: bool,
|
||||||
|
pub continuation: FrameContinuation,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 一次 `for-in` 迭代的游标:已收集的 key 列表与当前下标。
|
||||||
|
///
|
||||||
|
/// 每个 key 与它的 intern id 配对保存,使整型下标 key 无需重新 intern 即可排到字符串 key 之前。
|
||||||
|
pub struct ForInIter<'bump> {
|
||||||
|
/// 每个 key 与其字符串 intern id 配对,使 for-in 排序时整型下标 key 无需
|
||||||
|
/// 重新 intern 即可排到字符串 key 之前。
|
||||||
|
pub keys: bumpalo::collections::Vec<'bump, (JsValue, u32)>,
|
||||||
|
pub index: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// try/catch/finally 处理记录,异常展开时用于定位跳转目标与清理范围。
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub struct TryHandler {
|
||||||
|
pub catch_pc: Option<usize>,
|
||||||
|
pub finally_pc: Option<usize>,
|
||||||
|
/// finally 体是否已进入(normal JMP / 异常展开 / 完成穿越都会置位)。
|
||||||
|
/// 用标志而非 pc 范围判定"当前是否执行 finally 体":try 体末指令可能因 DCE
|
||||||
|
/// 紧贴 finally 入口,pc 边界会误判。
|
||||||
|
pub finally_active: bool,
|
||||||
|
pub frame_depth: usize,
|
||||||
|
/// try 入口时 for_of_iters 的长度,界定异常展开时哪些迭代器需要 IteratorClose。
|
||||||
|
pub for_of_depth: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 控制流完成:break/continue/return 逃出 finally 域时暂存的完成目标。
|
||||||
|
///
|
||||||
|
/// 仿 `pending_exception` 的侧通道:finally 执行期间悬挂在此,由 TRY_FINALLY_END
|
||||||
|
/// 逐个恢复(`remaining_finally` 为仍需穿越的 finally 体数,进入一个递减一个)。
|
||||||
|
/// `for_of_count`/`for_in_count` 为逃出时需关闭的迭代器层数:在全部 finally 穿越
|
||||||
|
/// 之后、跳转/返回之前执行(规范 §13.7.5.4 的 IteratorClose 在完成值之后)。
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub enum Completion {
|
||||||
|
Break {
|
||||||
|
target_pc: usize,
|
||||||
|
remaining_finally: usize,
|
||||||
|
for_of_count: usize,
|
||||||
|
for_in_count: usize,
|
||||||
|
},
|
||||||
|
Continue {
|
||||||
|
target_pc: usize,
|
||||||
|
remaining_finally: usize,
|
||||||
|
for_of_count: usize,
|
||||||
|
for_in_count: usize,
|
||||||
|
},
|
||||||
|
Return {
|
||||||
|
value: JsValue,
|
||||||
|
remaining_finally: usize,
|
||||||
|
for_of_count: usize,
|
||||||
|
for_in_count: usize,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Completion {
|
||||||
|
/// 仍需穿越的 finally 体数。
|
||||||
|
pub fn remaining_finally(&self) -> usize {
|
||||||
|
match *self {
|
||||||
|
Completion::Break { remaining_finally, .. }
|
||||||
|
| Completion::Continue { remaining_finally, .. }
|
||||||
|
| Completion::Return { remaining_finally, .. } => remaining_finally,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 逃出时需关闭的 for-of 迭代器层数。
|
||||||
|
pub fn for_of_count(&self) -> usize {
|
||||||
|
match *self {
|
||||||
|
Completion::Break { for_of_count, .. }
|
||||||
|
| Completion::Continue { for_of_count, .. }
|
||||||
|
| Completion::Return { for_of_count, .. } => for_of_count,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 逃出时需弹出的 for-in 迭代器层数。
|
||||||
|
pub fn for_in_count(&self) -> usize {
|
||||||
|
match *self {
|
||||||
|
Completion::Break { for_in_count, .. }
|
||||||
|
| Completion::Continue { for_in_count, .. }
|
||||||
|
| Completion::Return { for_in_count, .. } => for_in_count,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 复制并改写剩余 finally 计数(进入一个 finally 后递减)。
|
||||||
|
pub fn with_remaining(&self, remaining: usize) -> Completion {
|
||||||
|
match *self {
|
||||||
|
Completion::Break {
|
||||||
|
target_pc,
|
||||||
|
for_of_count,
|
||||||
|
for_in_count,
|
||||||
|
..
|
||||||
|
} => Completion::Break {
|
||||||
|
target_pc,
|
||||||
|
remaining_finally: remaining,
|
||||||
|
for_of_count,
|
||||||
|
for_in_count,
|
||||||
|
},
|
||||||
|
Completion::Continue {
|
||||||
|
target_pc,
|
||||||
|
for_of_count,
|
||||||
|
for_in_count,
|
||||||
|
..
|
||||||
|
} => Completion::Continue {
|
||||||
|
target_pc,
|
||||||
|
remaining_finally: remaining,
|
||||||
|
for_of_count,
|
||||||
|
for_in_count,
|
||||||
|
},
|
||||||
|
Completion::Return {
|
||||||
|
value,
|
||||||
|
for_of_count,
|
||||||
|
for_in_count,
|
||||||
|
..
|
||||||
|
} => Completion::Return {
|
||||||
|
value,
|
||||||
|
remaining_finally: remaining,
|
||||||
|
for_of_count,
|
||||||
|
for_in_count,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
//! 内联同步执行核心的堆上快照 `InlineSyncState`;字段登记表宏
|
||||||
|
//! `inline_core_fields!` 在 `vm_runtime` 模块。
|
||||||
|
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use oxide_bytecode::opcode;
|
||||||
|
use oxide_types::object::Cell;
|
||||||
|
use oxide_types::value::JsValue;
|
||||||
|
use smallvec::SmallVec;
|
||||||
|
|
||||||
|
use super::frames::{CallFrame, Completion, ForInIter, TryHandler};
|
||||||
|
use crate::vm_state::ForOfEntry;
|
||||||
|
|
||||||
|
/// `call_bytecode_function_inline` 使用的堆分配快照。
|
||||||
|
/// 放在堆上避免 JS 代码链式同步字节码调用(如 sort 比较器、accessor)时
|
||||||
|
/// 耗尽 Rust 栈。
|
||||||
|
pub(crate) struct InlineSyncState {
|
||||||
|
/// 寄存器窗口副本:`regs[0..len]`,len ≤ 254(含 RegAlloc 最高合法物理槽
|
||||||
|
/// 253)。`regs[254]/[255]` 不在此列,由 `saved_this`/`saved_new_target`
|
||||||
|
/// 单独保存(callee 也会重写这两个槽)。
|
||||||
|
pub(crate) regs: Box<[JsValue]>,
|
||||||
|
pub(crate) saved_this: JsValue,
|
||||||
|
pub(crate) saved_new_target: JsValue,
|
||||||
|
pub(crate) pc: usize,
|
||||||
|
pub(crate) bytecode: Arc<[opcode::Instr]>,
|
||||||
|
pub(crate) active_immutables: *const [JsValue],
|
||||||
|
pub(crate) active_reg_limit: u8,
|
||||||
|
pub(crate) root_reg_limit: u8,
|
||||||
|
pub(crate) try_stack: Vec<TryHandler>,
|
||||||
|
pub(crate) frames: SmallVec<[CallFrame; 16]>,
|
||||||
|
pub(crate) exception_value: Option<JsValue>,
|
||||||
|
pub(crate) pending_exception: Option<JsValue>,
|
||||||
|
pub(crate) pending_error_kind: Option<&'static str>,
|
||||||
|
pub(crate) pending_completion: Option<Completion>,
|
||||||
|
pub(crate) for_in_iters: Vec<*mut ForInIter<'static>>,
|
||||||
|
pub(crate) for_of_iters: Vec<ForOfEntry>,
|
||||||
|
pub(crate) saved_bytecode_stack: Vec<Arc<[opcode::Instr]>>,
|
||||||
|
pub(crate) saved_immutables_stack: Vec<*const [JsValue]>,
|
||||||
|
pub(crate) save_stack: Vec<JsValue>,
|
||||||
|
pub(crate) spill_stack: Vec<JsValue>,
|
||||||
|
pub(crate) cell_stack: Vec<Vec<*mut Cell>>,
|
||||||
|
pub(crate) inline_callee: Option<JsValue>,
|
||||||
|
/// 三个内嵌 dispatch 调度标志(`Vm::generator_dispatch` / `async_dispatch` /
|
||||||
|
/// `construct_dispatch`)的属主快照。save 时记录外层值并清零 VM 侧、restore
|
||||||
|
/// 时写回:嵌套 state-swap 调用不得继承外层调度上下文,否则其内部构造帧
|
||||||
|
/// 弹出后 frames 清空,`do_return` 会把嵌套调用误判为属主内嵌 dispatch 提前
|
||||||
|
/// 交付,跳过被调函数剩余字节码(详见 `do_return` 交付条件注释)。
|
||||||
|
pub(crate) generator_dispatch: bool,
|
||||||
|
pub(crate) async_dispatch: bool,
|
||||||
|
pub(crate) construct_dispatch: bool,
|
||||||
|
/// inline 目标函数的严格模式标志(内联执行期间写路径的 strict/sloppy 判定
|
||||||
|
/// 来源;嵌套内联时随本快照保存/恢复)。
|
||||||
|
pub(crate) inline_strict: bool,
|
||||||
|
/// inline 起始时 `frames.len()` 基线(嵌套内联时随本快照保存/恢复)。
|
||||||
|
pub(crate) inline_frames_base: usize,
|
||||||
|
pub(crate) inline_args_base: u32,
|
||||||
|
pub(crate) inline_args_count: u16,
|
||||||
|
pub(crate) accessor_frame_target_reg: Option<u8>,
|
||||||
|
pub(crate) active_flat_id: u32,
|
||||||
|
pub(crate) active_table_gen: u32,
|
||||||
|
}
|
||||||
@@ -12,7 +12,9 @@ use smallvec::SmallVec;
|
|||||||
pub use crate::bindings::init_kernel_builtins;
|
pub use crate::bindings::init_kernel_builtins;
|
||||||
use crate::native::NativeFn;
|
use crate::native::NativeFn;
|
||||||
use crate::session_gc::SessionGc;
|
use crate::session_gc::SessionGc;
|
||||||
use crate::vm_state::{ForOfEntry, GcState, IterState, ProfilingState, SymbolState};
|
#[cfg(test)]
|
||||||
|
use crate::vm_state::ForOfEntry;
|
||||||
|
use crate::vm_state::{GcState, IterState, ProfilingState, SymbolState};
|
||||||
use crate::{vm_debug, vm_error, vm_trace, vm_warn};
|
use crate::{vm_debug, vm_error, vm_trace, vm_warn};
|
||||||
use oxide_kernel::kernel::{KernelCore, KernelSession};
|
use oxide_kernel::kernel::{KernelCore, KernelSession};
|
||||||
use oxide_runtime_api as coercion;
|
use oxide_runtime_api as coercion;
|
||||||
@@ -25,6 +27,15 @@ use oxide_types::private_key::{
|
|||||||
};
|
};
|
||||||
use oxide_types::value::{JsValue, PTR_MASK};
|
use oxide_types::value::{JsValue, PTR_MASK};
|
||||||
|
|
||||||
|
mod frames;
|
||||||
|
mod inline;
|
||||||
|
mod tables;
|
||||||
|
|
||||||
|
pub(crate) use frames::FrameArgs;
|
||||||
|
pub use frames::{CallFrame, Completion, ForInIter, FrameContinuation, TryHandler};
|
||||||
|
pub(crate) use inline::InlineSyncState;
|
||||||
|
pub(crate) use tables::TableGen;
|
||||||
|
|
||||||
pub(crate) const MAX_PROTO_CHAIN_DEPTH: usize = 1024;
|
pub(crate) const MAX_PROTO_CHAIN_DEPTH: usize = 1024;
|
||||||
|
|
||||||
/// 判定字符串是否为规范数组下标(无前导零的纯数字串),并反解其值。
|
/// 判定字符串是否为规范数组下标(无前导零的纯数字串),并反解其值。
|
||||||
@@ -181,266 +192,6 @@ macro_rules! binary_arith {
|
|||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 调用帧被挂起后,恢复时需要继续的执行方式。
|
|
||||||
///
|
|
||||||
/// `AccessorGet` 表示 accessor getter 返回后需把结果写回 `target_reg`;
|
|
||||||
/// `AccessorSet` 表示 setter 调用完成;`None` 为普通调用返回。
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
pub enum FrameContinuation {
|
|
||||||
None,
|
|
||||||
AccessorGet { target_reg: u8 },
|
|
||||||
AccessorSet,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 压帧实参来源:已物化切片或寄存器连续区间。
|
|
||||||
///
|
|
||||||
/// `RegRange` 直接引用调用方寄存器文件(CALL/NEW/SUPER_CALL 的实参在寄存器中
|
|
||||||
/// 天然连续排列),免去临时堆 `Vec<JsValue>` 物化,每次调用省 1 次分配/释放。
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
pub(crate) enum FrameArgs<'a> {
|
|
||||||
/// 已物化实参:spread 展开、TailCall、accessor 与初始执行路径。
|
|
||||||
Slice(&'a [JsValue]),
|
|
||||||
/// 寄存器连续区间 `regs[first .. first+count)`。
|
|
||||||
RegRange { first: u8, count: usize },
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FrameArgs<'_> {
|
|
||||||
/// 实参总数。
|
|
||||||
pub(crate) fn len(&self) -> usize {
|
|
||||||
match self {
|
|
||||||
FrameArgs::Slice(s) => s.len(),
|
|
||||||
FrameArgs::RegRange { count, .. } => *count,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 一次函数调用的调用帧:记录返回地址、调用方寄存器窗口与 `this`/`new.target`。
|
|
||||||
///
|
|
||||||
/// 调用方寄存器窗口在 `save_stack` 中按 `saved_reg_offset` 保存,返回时由
|
|
||||||
/// `restore_frame` 恢复;`continuation` 描述 getter/setter 场景的恢复方式。
|
|
||||||
pub struct CallFrame {
|
|
||||||
pub return_addr: usize,
|
|
||||||
pub function_name: u32,
|
|
||||||
/// 压帧保存的调用方寄存器窗口长度(= save_stack 中本帧段大小)。
|
|
||||||
/// 普通字节码调用按调用点存活上界截断;运行时发起(accessor/内联)为
|
|
||||||
/// 调用方 `active_reg_limit` 全量。
|
|
||||||
pub caller_reg_limit: u8,
|
|
||||||
/// 压帧时刻调用方 `active_reg_limit`(真实值):帧恢复时据此还原,与
|
|
||||||
/// `caller_reg_limit`(可能被存活上界截断的窗口)解耦。
|
|
||||||
pub caller_active_reg_limit: u8,
|
|
||||||
pub saved_reg_offset: u32,
|
|
||||||
/// 记录本帧 spill 栈起始长度,作为 SPILL/UNSPILL 的帧边界基址(push 时快照)。
|
|
||||||
pub spill_offset: u32,
|
|
||||||
/// 本帧完整实参在 spill 栈的起始下标(帧恢复时随 spill 区一起截断丢弃)。
|
|
||||||
pub arguments_base: u32,
|
|
||||||
/// 实际传入的实参个数(可大于形参个数)。
|
|
||||||
pub arguments_count: u16,
|
|
||||||
pub saved_this: JsValue,
|
|
||||||
pub saved_new_target: JsValue,
|
|
||||||
pub callee: JsValue,
|
|
||||||
pub construct_result_reg: Option<u8>,
|
|
||||||
pub constructed_this: Option<JsValue>,
|
|
||||||
pub is_derived_constructor: bool,
|
|
||||||
/// derived 构造帧是否已成功调用 super()(父构造器正常返回后置位)。
|
|
||||||
///
|
|
||||||
/// 置位识别依赖 ABI 不变量:`construct_result_reg == Some(254)` 仅 SUPER_CALL
|
|
||||||
/// 压帧产生(emit 从寄存器 ≥1 分配,254 保留给 this);父构造器抛错走 unwind
|
|
||||||
/// 弹帧不进 do_return,不置位。此标志取代依赖 regs[254] 值判定 super 状态的
|
|
||||||
/// 旧方案——多层继承时中间 derived 帧由 SUPER_CALL 以构造 this 压入,
|
|
||||||
/// regs[254] 恒非 undefined,值判定三重失效。
|
|
||||||
pub super_called: bool,
|
|
||||||
/// 本帧函数的严格模式标志(来源:模块编译产物 `is_strict`)。
|
|
||||||
/// 属性写失败时据此分派:严格模式抛 TypeError,sloppy 静默 no-op。
|
|
||||||
pub strict: bool,
|
|
||||||
pub continuation: FrameContinuation,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 一次 `for-in` 迭代的游标:已收集的 key 列表与当前下标。
|
|
||||||
///
|
|
||||||
/// 每个 key 与它的 intern id 配对保存,使整型下标 key 无需重新 intern 即可排到字符串 key 之前。
|
|
||||||
pub struct ForInIter<'bump> {
|
|
||||||
/// 每个 key 与其字符串 intern id 配对,使 for-in 排序时整型下标 key 无需
|
|
||||||
/// 重新 intern 即可排到字符串 key 之前。
|
|
||||||
pub keys: bumpalo::collections::Vec<'bump, (JsValue, u32)>,
|
|
||||||
pub index: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// try/catch/finally 处理记录,异常展开时用于定位跳转目标与清理范围。
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
pub struct TryHandler {
|
|
||||||
pub catch_pc: Option<usize>,
|
|
||||||
pub finally_pc: Option<usize>,
|
|
||||||
/// finally 体是否已进入(normal JMP / 异常展开 / 完成穿越都会置位)。
|
|
||||||
/// 用标志而非 pc 范围判定"当前是否执行 finally 体":try 体末指令可能因 DCE
|
|
||||||
/// 紧贴 finally 入口,pc 边界会误判。
|
|
||||||
pub finally_active: bool,
|
|
||||||
pub frame_depth: usize,
|
|
||||||
/// try 入口时 for_of_iters 的长度,界定异常展开时哪些迭代器需要 IteratorClose。
|
|
||||||
pub for_of_depth: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 控制流完成:break/continue/return 逃出 finally 域时暂存的完成目标。
|
|
||||||
///
|
|
||||||
/// 仿 `pending_exception` 的侧通道:finally 执行期间悬挂在此,由 TRY_FINALLY_END
|
|
||||||
/// 逐个恢复(`remaining_finally` 为仍需穿越的 finally 体数,进入一个递减一个)。
|
|
||||||
/// `for_of_count`/`for_in_count` 为逃出时需关闭的迭代器层数:在全部 finally 穿越
|
|
||||||
/// 之后、跳转/返回之前执行(规范 §13.7.5.4 的 IteratorClose 在完成值之后)。
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
pub enum Completion {
|
|
||||||
Break {
|
|
||||||
target_pc: usize,
|
|
||||||
remaining_finally: usize,
|
|
||||||
for_of_count: usize,
|
|
||||||
for_in_count: usize,
|
|
||||||
},
|
|
||||||
Continue {
|
|
||||||
target_pc: usize,
|
|
||||||
remaining_finally: usize,
|
|
||||||
for_of_count: usize,
|
|
||||||
for_in_count: usize,
|
|
||||||
},
|
|
||||||
Return {
|
|
||||||
value: JsValue,
|
|
||||||
remaining_finally: usize,
|
|
||||||
for_of_count: usize,
|
|
||||||
for_in_count: usize,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Completion {
|
|
||||||
/// 仍需穿越的 finally 体数。
|
|
||||||
pub fn remaining_finally(&self) -> usize {
|
|
||||||
match *self {
|
|
||||||
Completion::Break { remaining_finally, .. }
|
|
||||||
| Completion::Continue { remaining_finally, .. }
|
|
||||||
| Completion::Return { remaining_finally, .. } => remaining_finally,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 逃出时需关闭的 for-of 迭代器层数。
|
|
||||||
pub fn for_of_count(&self) -> usize {
|
|
||||||
match *self {
|
|
||||||
Completion::Break { for_of_count, .. }
|
|
||||||
| Completion::Continue { for_of_count, .. }
|
|
||||||
| Completion::Return { for_of_count, .. } => for_of_count,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 逃出时需弹出的 for-in 迭代器层数。
|
|
||||||
pub fn for_in_count(&self) -> usize {
|
|
||||||
match *self {
|
|
||||||
Completion::Break { for_in_count, .. }
|
|
||||||
| Completion::Continue { for_in_count, .. }
|
|
||||||
| Completion::Return { for_in_count, .. } => for_in_count,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 复制并改写剩余 finally 计数(进入一个 finally 后递减)。
|
|
||||||
pub fn with_remaining(&self, remaining: usize) -> Completion {
|
|
||||||
match *self {
|
|
||||||
Completion::Break {
|
|
||||||
target_pc,
|
|
||||||
for_of_count,
|
|
||||||
for_in_count,
|
|
||||||
..
|
|
||||||
} => Completion::Break {
|
|
||||||
target_pc,
|
|
||||||
remaining_finally: remaining,
|
|
||||||
for_of_count,
|
|
||||||
for_in_count,
|
|
||||||
},
|
|
||||||
Completion::Continue {
|
|
||||||
target_pc,
|
|
||||||
for_of_count,
|
|
||||||
for_in_count,
|
|
||||||
..
|
|
||||||
} => Completion::Continue {
|
|
||||||
target_pc,
|
|
||||||
remaining_finally: remaining,
|
|
||||||
for_of_count,
|
|
||||||
for_in_count,
|
|
||||||
},
|
|
||||||
Completion::Return {
|
|
||||||
value,
|
|
||||||
for_of_count,
|
|
||||||
for_in_count,
|
|
||||||
..
|
|
||||||
} => Completion::Return {
|
|
||||||
value,
|
|
||||||
remaining_finally: remaining,
|
|
||||||
for_of_count,
|
|
||||||
for_in_count,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// `call_bytecode_function_inline` 使用的堆分配快照。
|
|
||||||
/// 放在堆上避免 JS 代码链式同步字节码调用(如 sort 比较器、accessor)时
|
|
||||||
/// 耗尽 Rust 栈。
|
|
||||||
pub(crate) struct InlineSyncState {
|
|
||||||
/// 寄存器窗口副本:`regs[0..len]`,len ≤ 254(含 RegAlloc 最高合法物理槽
|
|
||||||
/// 253)。`regs[254]/[255]` 不在此列,由 `saved_this`/`saved_new_target`
|
|
||||||
/// 单独保存(callee 也会重写这两个槽)。
|
|
||||||
pub(crate) regs: Box<[JsValue]>,
|
|
||||||
pub(crate) saved_this: JsValue,
|
|
||||||
pub(crate) saved_new_target: JsValue,
|
|
||||||
pub(crate) pc: usize,
|
|
||||||
pub(crate) bytecode: Arc<[opcode::Instr]>,
|
|
||||||
pub(crate) active_immutables: *const [JsValue],
|
|
||||||
pub(crate) active_reg_limit: u8,
|
|
||||||
pub(crate) root_reg_limit: u8,
|
|
||||||
pub(crate) try_stack: Vec<TryHandler>,
|
|
||||||
pub(crate) frames: SmallVec<[CallFrame; 16]>,
|
|
||||||
pub(crate) exception_value: Option<JsValue>,
|
|
||||||
pub(crate) pending_exception: Option<JsValue>,
|
|
||||||
pub(crate) pending_error_kind: Option<&'static str>,
|
|
||||||
pub(crate) pending_completion: Option<Completion>,
|
|
||||||
pub(crate) for_in_iters: Vec<*mut ForInIter<'static>>,
|
|
||||||
pub(crate) for_of_iters: Vec<ForOfEntry>,
|
|
||||||
pub(crate) saved_bytecode_stack: Vec<Arc<[opcode::Instr]>>,
|
|
||||||
pub(crate) saved_immutables_stack: Vec<*const [JsValue]>,
|
|
||||||
pub(crate) save_stack: Vec<JsValue>,
|
|
||||||
pub(crate) spill_stack: Vec<JsValue>,
|
|
||||||
pub(crate) cell_stack: Vec<Vec<*mut Cell>>,
|
|
||||||
pub(crate) inline_callee: Option<JsValue>,
|
|
||||||
/// 三个内嵌 dispatch 调度标志(`Vm::generator_dispatch` / `async_dispatch` /
|
|
||||||
/// `construct_dispatch`)的属主快照。save 时记录外层值并清零 VM 侧、restore
|
|
||||||
/// 时写回:嵌套 state-swap 调用不得继承外层调度上下文,否则其内部构造帧
|
|
||||||
/// 弹出后 frames 清空,`do_return` 会把嵌套调用误判为属主内嵌 dispatch 提前
|
|
||||||
/// 交付,跳过被调函数剩余字节码(详见 `do_return` 交付条件注释)。
|
|
||||||
pub(crate) generator_dispatch: bool,
|
|
||||||
pub(crate) async_dispatch: bool,
|
|
||||||
pub(crate) construct_dispatch: bool,
|
|
||||||
/// inline 目标函数的严格模式标志(内联执行期间写路径的 strict/sloppy 判定
|
|
||||||
/// 来源;嵌套内联时随本快照保存/恢复)。
|
|
||||||
pub(crate) inline_strict: bool,
|
|
||||||
/// inline 起始时 `frames.len()` 基线(嵌套内联时随本快照保存/恢复)。
|
|
||||||
pub(crate) inline_frames_base: usize,
|
|
||||||
pub(crate) inline_args_base: u32,
|
|
||||||
pub(crate) inline_args_count: u16,
|
|
||||||
pub(crate) accessor_frame_target_reg: Option<u8>,
|
|
||||||
pub(crate) active_flat_id: u32,
|
|
||||||
pub(crate) active_table_gen: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 单代子模块平表:模块平表 + 每模块不可变常量缓存,注册进 `Vm::tables` 按代际管理。
|
|
||||||
///
|
|
||||||
/// 以 `Box` 承载(HashMap 扩容搬 Box 指针不搬被指物):`active_immutables` 与
|
|
||||||
/// `saved_immutables_stack` 是伸入 immutables 内部常量 Vec 的胖指针,表地址须
|
|
||||||
/// 在其整个生命周期内稳定。动态扩表(`create_dynamic_function` /
|
|
||||||
/// `create_dynamic_script`)对 modules 外层 Arc 做 `make_mut`:彼时该 Arc 的
|
|
||||||
/// 强引用唯一持有者是本表(函数对象只持 u32 下标不持 Arc),原地扩展不分叉。
|
|
||||||
pub(crate) struct TableGen {
|
|
||||||
/// 全局扁平模块表:下标 = 模块 `flat_id`(顶层 0,子模块 flatten 后全局唯一)。
|
|
||||||
/// 函数对象 `sub_module_index` 即该平表下标,逃逸函数也能自足解析。
|
|
||||||
pub(crate) modules: Arc<Vec<Arc<CompiledModule>>>,
|
|
||||||
/// 每次 run 转换一次的不可变常量缓存:下标 0 = 顶层模块,sub_idx = modules[sub_idx]。
|
|
||||||
/// 每个 `OnceLock` 保存该模块常量本次运行中只转换一次的 `JsValue` 结果。
|
|
||||||
/// 不可变常量是标量 + perm 字符串,只读,GC 根收集按表代际遍历。
|
|
||||||
pub(crate) immutables: Vec<OnceLock<Vec<JsValue>>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 基于寄存器的 JS 虚拟机:持有执行状态、寄存器文件、调用栈与 session 内存。
|
/// 基于寄存器的 JS 虚拟机:持有执行状态、寄存器文件、调用栈与 session 内存。
|
||||||
///
|
///
|
||||||
/// 执行入口为 [`Vm::run`](见 `vm_runtime` 模块);内存模型为 epoch arena +
|
/// 执行入口为 [`Vm::run`](见 `vm_runtime` 模块);内存模型为 epoch arena +
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
//! 子模块平表代际:`TableGen`(模块平表 + 每模块不可变常量缓存),注册进
|
||||||
|
//! `Vm::tables` 按代际管理。
|
||||||
|
|
||||||
|
use std::sync::{Arc, OnceLock};
|
||||||
|
|
||||||
|
use oxide_bytecode::module::CompiledModule;
|
||||||
|
use oxide_types::value::JsValue;
|
||||||
|
|
||||||
|
/// 单代子模块平表:模块平表 + 每模块不可变常量缓存,注册进 `Vm::tables` 按代际管理。
|
||||||
|
///
|
||||||
|
/// 以 `Box` 承载(HashMap 扩容搬 Box 指针不搬被指物):`active_immutables` 与
|
||||||
|
/// `saved_immutables_stack` 是伸入 immutables 内部常量 Vec 的胖指针,表地址须
|
||||||
|
/// 在其整个生命周期内稳定。动态扩表(`create_dynamic_function` /
|
||||||
|
/// `create_dynamic_script`)对 modules 外层 Arc 做 `make_mut`:彼时该 Arc 的
|
||||||
|
/// 强引用唯一持有者是本表(函数对象只持 u32 下标不持 Arc),原地扩展不分叉。
|
||||||
|
pub(crate) struct TableGen {
|
||||||
|
/// 全局扁平模块表:下标 = 模块 `flat_id`(顶层 0,子模块 flatten 后全局唯一)。
|
||||||
|
/// 函数对象 `sub_module_index` 即该平表下标,逃逸函数也能自足解析。
|
||||||
|
pub(crate) modules: Arc<Vec<Arc<CompiledModule>>>,
|
||||||
|
/// 每次 run 转换一次的不可变常量缓存:下标 0 = 顶层模块,sub_idx = modules[sub_idx]。
|
||||||
|
/// 每个 `OnceLock` 保存该模块常量本次运行中只转换一次的 `JsValue` 结果。
|
||||||
|
/// 不可变常量是标量 + perm 字符串,只读,GC 根收集按表代际遍历。
|
||||||
|
pub(crate) immutables: Vec<OnceLock<Vec<JsValue>>>,
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user